Skip to content

Commit

Permalink
[Darkside] ReadMore CSS update (#3372)
Browse files Browse the repository at this point in the history
* ✨ Added brandvolume support in theme-component

* 📝 Added brandvolume story to readmore

* ✨ Added large size to readmore

* ✨ Added darkmode support for Readmore

* :refactor: Updated CSS syntax

* 🐛 Fixed brandvolume stories

* ✨ Implemented brandvolume in ReadMore

* ✨ Added large-variant of readmore to OG readmore

* :refactor: Use tokens and calc to handle volume

* 🐛 Added text-accent-strong on hover to high brandvolume

* 🐛 Avoid adjusting readmore body when size is large

* 📝 CHangeset

* Update @navikt/core/react/src/provider/theme/AkselTheme.tsx

Co-authored-by: Halvor Haugan <[email protected]>

* Update @navikt/core/react/src/provider/theme/AkselTheme.tsx

Co-authored-by: Halvor Haugan <[email protected]>

---------

Co-authored-by: Halvor Haugan <[email protected]>
  • Loading branch information
KenAJoh and HalvorHaugan authored Nov 25, 2024
1 parent 0f98344 commit 641276b
Show file tree
Hide file tree
Showing 6 changed files with 160 additions and 62 deletions.
6 changes: 6 additions & 0 deletions .changeset/shy-panthers-hide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@navikt/ds-react": minor
"@navikt/ds-css": minor
---

ReadMore: Added size 'large'.
125 changes: 68 additions & 57 deletions @navikt/core/css/darkside/read-more.darkside.css
Original file line number Diff line number Diff line change
@@ -1,91 +1,102 @@
.navds-read-more {
--__axc-read-more-icon-size: 1.5rem;
--__axc-read-more-pi-start: 0px;
--__axc-read-more-pi-end: var(--ax-spacing-1);
--__axc-read-more-pb: var(--ax-spacing-1);
}

/* ----------------------------- ReadMore Button ---------------------------- */
.navds-read-more__button {
cursor: pointer;
margin: 0;
border: none;
background: none;
display: flex;
align-items: flex-start;
gap: var(--a-spacing-05);
color: var(--ac-read-more-text, var(--a-text-action));
border-radius: var(--a-border-radius-small);
padding: var(--a-spacing-1) var(--a-spacing-2) var(--a-spacing-1) var(--a-spacing-05);
gap: var(--ax-spacing-1);
color: var(--ax-text-accent);
padding-inline: var(--__axc-read-more-pi-start) var(--__axc-read-more-pi-end);
padding-block: var(--__axc-read-more-pb);
text-align: start;
}

.navds-read-more--small .navds-read-more__button {
padding: var(--a-spacing-05) var(--a-spacing-1-alt) var(--a-spacing-05) var(--a-spacing-05);
}

@media (forced-colors: active) {
.navds-read-more__button {
background-color: ButtonFace;
border: solid 1px ButtonText;
color: ButtonText;
&:focus-visible {
outline: 2px solid var(--ax-border-focus);
outline-offset: 2px;
}

.navds-read-more__button.navds-read-more__button:focus-visible {
box-shadow: none;
outline: 2px solid highlight;
outline-offset: 2px;
&[data-state="open"] .navds-read-more__expand-icon {
transform: rotateX(-180deg);
}
}

.navds-read-more__button:hover {
background-color: var(--ac-read-more-hover-bg, var(--a-surface-hover));
color: var(--ac-read-more-hover-text, var(--a-text-action-hover));
}
.navds-read-more:is([data-volume="low"], :not([data-volume])) {
& .navds-read-more__button {
border-radius: var(--ax-border-radius-medium);

.navds-read-more__button:active {
background-color: var(--ac-read-more-active-bg, var(--a-surface-active));
&:hover {
background-color: var(--ax-bg-neutral-hoverA);
color: var(--ax-text-accent-strong);
}
}
}

.navds-read-more__button:focus-visible {
outline: none;
box-shadow: var(--a-shadow-focus);
}
.navds-read-more[data-volume="high"] {
& .navds-read-more__button {
background-color: var(--ax-bg-accent-moderate);
border-radius: var(--ax-border-radius-full);

@supports not selector(:focus-visible) {
.navds-read-more__button:focus {
outline: none;
box-shadow: var(--a-shadow-focus);
&:hover {
background-color: var(--ax-bg-accent-moderate-hoverA);
color: var(--ax-text-accent-strong);
}
}
}

.navds-read-more__content {
margin-top: var(--a-spacing-1);
border-left: 2px solid var(--ac-read-more-line, var(--a-border-divider));
margin-left: 0.8125rem;
padding-left: 0.8125rem;
color: var(--a-text-default);
}
&.navds-read-more--large {
--__axc-read-more-pi-start: var(--ax-spacing-3);
--__axc-read-more-pi-end: var(--ax-spacing-6);
}

.navds-read-more--small .navds-read-more__content {
margin-left: 0.6875rem;
padding-left: 0.6875rem;
&.navds-read-more--small,
&.navds-read-more--medium {
--__axc-read-more-pi-start: var(--ax-spacing-2);
--__axc-read-more-pi-end: var(--ax-spacing-4);
}
}

.navds-read-more__content--closed {
display: none;
/* ---------------------------- ReadMore Content ---------------------------- */
.navds-read-more__content {
margin-top: var(--ax-spacing-2);
border-left: 2px solid var(--ax-border-neutral-subtleA);
color: var(--ax-text-default);
margin-left: calc(var(--__axc-read-more-pi-start) + var(--__axc-read-more-icon-size) / 2 - 1px);
padding-left: calc(var(--__axc-read-more-icon-size) / 2 - 1px + var(--ax-spacing-1));

&[data-state="closed"] {
display: none;
}
}

.navds-read-more__expand-icon {
font-size: 1.5rem;
font-size: var(--__axc-read-more-icon-size);
flex-shrink: 0;
transition: transform 100ms cubic-bezier(0.2, 0, 0, 1);
}

.navds-read-more--small .navds-read-more__expand-icon {
font-size: 1.25rem;
/* ----------------------------- ReadMore Sizes ----------------------------- */
.navds-read-more--large {
--__axc-read-more-pb: var(--ax-spacing-3);
}

.navds-read-more__button:hover > .navds-read-more__expand-icon {
position: relative;
top: 1px;
.navds-read-more--small {
--__axc-read-more-icon-size: 1.25rem;
--__axc-read-more-pb: var(--ax-spacing-05);
}

.navds-read-more--open > .navds-read-more__button > .navds-read-more__expand-icon {
transform: rotate(-180deg);
}

.navds-read-more--open > .navds-read-more__button:hover > .navds-read-more__expand-icon {
top: -1px;
/* ------------------------- ReadMore high-contrast ------------------------- */
@media (forced-colors: active) {
.navds-read-more__button {
background-color: ButtonFace;
border: solid 1px ButtonText;
color: ButtonText;
}
}
4 changes: 4 additions & 0 deletions @navikt/core/css/read-more.css
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
padding: var(--a-spacing-05) var(--a-spacing-1-alt) var(--a-spacing-05) var(--a-spacing-05);
}

.navds-read-more--large .navds-read-more__button {
padding: var(--a-spacing-3) var(--a-spacing-1-alt) var(--a-spacing-3) var(--a-spacing-05);
}

@media (forced-colors: active) {
.navds-read-more__button {
background-color: ButtonFace;
Expand Down
16 changes: 14 additions & 2 deletions @navikt/core/react/src/provider/theme/AkselTheme.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,17 @@ import { Slot } from "../../slot/Slot";
import { createContext } from "../../util/create-context";

type AkselThemeContext = {
theme: "light" | "dark";
/**
* Color theme
* @default "light"
*/
theme?: "light" | "dark";
/**
* Brand volume
* @default "low"
* This is experimental and subject to changes
*/
volume?: "high" | "low";
};

const [ThemeProvider, useAkselTheme] = createContext<AkselThemeContext>({
Expand All @@ -31,6 +41,7 @@ const AkselTheme = forwardRef<HTMLDivElement, AkselThemeProps>(
className,
asChild = false,
theme = context?.theme ?? "light",
volume = context?.volume ?? "low",
hasBackground: hasBackgroundProp = true,
} = props;

Expand All @@ -42,11 +53,12 @@ const AkselTheme = forwardRef<HTMLDivElement, AkselThemeProps>(
const SlotElement = asChild ? Slot : "div";

return (
<ThemeProvider theme={theme}>
<ThemeProvider theme={theme} volume={volume}>
<SlotElement
ref={ref}
className={cl("navds-theme", className, theme)}
data-background={hasBackground}
data-volume={volume}
>
{children}
</SlotElement>
Expand Down
12 changes: 10 additions & 2 deletions @navikt/core/react/src/read-more/ReadMore.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import cl from "clsx";
import React, { forwardRef } from "react";
import { ChevronDownIcon } from "@navikt/aksel-icons";
import { UNSAFE_useAkselTheme } from "../provider";
import { BodyLong } from "../typography";
import { composeEventHandlers } from "../util/composeEventHandlers";
import { useControllableState } from "../util/hooks/useControllableState";
Expand Down Expand Up @@ -33,7 +34,7 @@ export interface ReadMoreProps
* Changes fontsize for content.
* @default "medium"
*/
size?: "medium" | "small";
size?: "large" | "medium" | "small";
}

/**
Expand Down Expand Up @@ -74,6 +75,10 @@ export const ReadMore = forwardRef<HTMLButtonElement, ReadMoreProps>(
onChange: onOpenChange,
});

const themeContext = UNSAFE_useAkselTheme(false);

const typoSize = size === "small" ? "small" : "medium";

return (
<div
className={cl(
Expand All @@ -82,6 +87,7 @@ export const ReadMore = forwardRef<HTMLButtonElement, ReadMoreProps>(
className,
{ "navds-read-more--open": _open },
)}
data-volume={themeContext?.volume}
>
<button
{...rest}
Expand All @@ -92,6 +98,7 @@ export const ReadMore = forwardRef<HTMLButtonElement, ReadMoreProps>(
})}
onClick={composeEventHandlers(onClick, () => _setOpen((x) => !x))}
aria-expanded={_open}
data-state={_open ? "open" : "closed"}
>
<ChevronDownIcon
className="navds-read-more__expand-icon"
Expand All @@ -106,7 +113,8 @@ export const ReadMore = forwardRef<HTMLButtonElement, ReadMoreProps>(
className={cl("navds-read-more__content", {
"navds-read-more__content--closed": !_open,
})}
size={size}
size={typoSize}
data-state={_open ? "open" : "closed"}
>
{children}
</BodyLong>
Expand Down
59 changes: 58 additions & 1 deletion @navikt/core/react/src/read-more/readmore.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { fn } from "@storybook/test";
import React from "react";
import { ReadMore } from ".";
import { VStack } from "../layout/stack";
import { UNSAFE_AkselTheme } from "../provider";

export default {
title: "ds-react/ReadMore",
Expand Down Expand Up @@ -37,6 +38,13 @@ export const Default: Story = {
},
};

export const Large: Story = {
args: {
...Default.args,
size: "large",
},
};

export const Small: Story = {
args: {
...Default.args,
Expand All @@ -58,8 +66,44 @@ export const Open: Story = {
},
};

export const BrandVolumeLow: Story = {
render: () => (
<UNSAFE_AkselTheme volume="low">
<VStack gap="4">
<ReadMore size="large" header={Default.args?.header}>
{Content}
</ReadMore>
<ReadMore header={Default.args?.header}>{Content}</ReadMore>
<ReadMore size="small" header={Default.args?.header}>
{Content}
</ReadMore>
</VStack>
</UNSAFE_AkselTheme>
),
args: {
...Default.args,
open: true,
},
};

export const BrandVolumeHigh: Story = {
render: () => (
<UNSAFE_AkselTheme volume="high">
<VStack gap="4">
<ReadMore size="large" header={Default.args?.header}>
{Content}
</ReadMore>
<ReadMore header={Default.args?.header}>{Content}</ReadMore>
<ReadMore size="small" header={Default.args?.header}>
{Content}
</ReadMore>
</VStack>
</UNSAFE_AkselTheme>
),
};

export const Chromatic: Story = {
render: () => {
render: (...props) => {
return (
<VStack gap="4">
<div>
Expand All @@ -72,6 +116,11 @@ export const Chromatic: Story = {
{/* @ts-expect-error Args are partial, leading to required prop mismatch */}
<ReadMore {...Small.args} />
</div>
<div>
<h2>Large</h2>
{/* @ts-expect-error Args are partial, leading to required prop mismatch */}
<ReadMore {...Large.args} />
</div>
<div>
<h2>DefaultOpen</h2>
{/* @ts-expect-error Args are partial, leading to required prop mismatch */}
Expand All @@ -82,6 +131,14 @@ export const Chromatic: Story = {
{/* @ts-expect-error Args are partial, leading to required prop mismatch */}
<ReadMore {...Open.args} />
</div>
<div>
<h2>BrandVolumeLow</h2>
{BrandVolumeLow?.render?.(...props)}
</div>
<div>
<h2>BrandVolumeHigh</h2>
{BrandVolumeHigh?.render?.(...props)}
</div>
</VStack>
);
},
Expand Down

0 comments on commit 641276b

Please sign in to comment.