From e5794891035cec97ad8be358d047c27d3089c555 Mon Sep 17 00:00:00 2001 From: Ken Date: Wed, 20 Nov 2024 14:32:31 +0100 Subject: [PATCH 1/4] :refactor: Added darkmode-support to Stepper --- .../core/css/darkside/stepper.darkside.css | 233 ++++++++---------- @navikt/core/react/src/stepper/Step.tsx | 3 + @navikt/core/react/src/stepper/Stepper.tsx | 7 +- 3 files changed, 106 insertions(+), 137 deletions(-) diff --git a/@navikt/core/css/darkside/stepper.darkside.css b/@navikt/core/css/darkside/stepper.darkside.css index a7f3907965..57bc1daebd 100644 --- a/@navikt/core/css/darkside/stepper.darkside.css +++ b/@navikt/core/css/darkside/stepper.darkside.css @@ -3,8 +3,8 @@ --navds-stepper-border-width: 2px; --navds-stepper-line-length: 1rem; - color: var(--ac-stepper-text, var(--a-surface-action)); - font-weight: 600; + color: var(--ax-text-accent); + font-weight: var(--ax-font-weight-bold); line-height: 1; list-style: none; padding-left: 0; @@ -28,20 +28,16 @@ } .navds-stepper__line { - background-color: var(--ac-stepper-line, var(--a-border-default)); + background-color: var(--ax-border-accent); width: var(--navds-stepper-border-width); height: 100%; min-height: var(--navds-stepper-line-length); justify-self: center; grid-column: 1; -} - -.navds-stepper__step--behind.navds-stepper__step--completed + .navds-stepper__line { - background-color: var(--ac-stepper-line-completed, var(--a-border-selected)); -} -.navds-stepper__item--behind.navds-stepper__item--completed + .navds-stepper__item > .navds-stepper__line--1 { - background-color: var(--ac-stepper-line-completed, var(--a-border-selected)); + .navds-stepper__item--non-interactive & { + background-color: var(--ax-border-neutral); + } } .navds-stepper__line--1 { @@ -51,10 +47,10 @@ .navds-stepper__line--2 { grid-row: line-2; -} -:where(.navds-stepper__item:last-of-type) .navds-stepper__line--2 { - display: none; + .navds-stepper__item:last-of-type & { + display: none; + } } .navds-stepper__step { @@ -62,16 +58,39 @@ grid-column: 1 / -1; display: grid; grid-template-columns: [circle] var(--navds-stepper-circle-size) [content] auto; - gap: var(--a-spacing-2); + gap: var(--ax-spacing-2); justify-content: flex-start; text-decoration: none; cursor: pointer; padding: var(--navds-stepper-border-width); margin: calc(var(--navds-stepper-border-width) * -1) calc(var(--navds-stepper-border-width) * -1) 1.75rem; -} -.navds-stepper__item:last-child .navds-stepper__step { - margin-bottom: 0; + &:focus-visible { + outline: 2px solid var(--ax-border-focus); + outline-offset: 2px; + } + + &[data-interactive="true"] { + color: var(--ax-text-accent); + } + + &[data-interactive="false"] { + color: var(--ax-text-neutral); + cursor: default; + } + + &:is(button) { + appearance: none; + border: none; + background-color: transparent; + font: inherit; + color: inherit; + text-align: inherit; + } + + .navds-stepper__item:last-child & { + margin-bottom: 0; + } } @media (forced-colors: active) { @@ -109,52 +128,81 @@ } } -button.navds-stepper__step { - appearance: none; - border: none; - background-color: transparent; - font: inherit; - color: inherit; - text-align: inherit; -} - -.navds-stepper__step--non-interactive { - color: var(--ac-stepper-non-interactive, var(--a-text-subtle)); - cursor: default; -} - -:where(.navds-stepper__step):focus-visible { - outline: none; - box-shadow: var(--a-shadow-focus); - isolation: isolate; -} - -@supports not selector(:focus-visible) { - .navds-stepper__step:focus { - outline: none; - box-shadow: var(--a-shadow-focus); - isolation: isolate; - } -} - .navds-stepper__circle { grid-column: circle; display: inline-grid; place-items: center; - flex-shrink: 0; width: var(--navds-stepper-circle-size); height: var(--navds-stepper-circle-size); border: var(--navds-stepper-border-width) solid currentColor; - border-radius: var(--a-border-radius-full); + border-radius: var(--ax-border-radius-full); line-height: 1; } .navds-stepper__circle--success { - border: none; background: none; font-size: 1.75rem; - color: var(--a-text-on-action); - background-color: var(--ac-stepper-text, var(--a-surface-action)); +} + +/* stylelint-disable-next-line no-duplicate-selectors */ +.navds-stepper__step[data-interactive="true"] { + & .navds-stepper__circle { + color: var(--ax-text-accent); + border-color: var(--ax-border-accent); + } + + &[data-active="true"] { + & .navds-stepper__content { + color: var(--ax-text-accent-strong); + } + + & .navds-stepper__circle { + color: var(--ax-text-accent-contrast); + background-color: var(--ax-bg-accent-strong-pressed); + border-color: var(--ax-bg-accent-strong-pressed); + } + } + + &[data-active="false"] { + &:hover { + & .navds-stepper__circle { + background-color: var(--ax-bg-accent-moderate-hover); + border-color: var(--ax-border-accent-strong); + } + } + } + + &:hover { + color: var(--ax-text-accent-strong); + + & .navds-stepper__circle { + color: var(--ax-text-accent-strong); + } + + & .navds-stepper__content { + text-decoration: underline; + } + } +} + +/* stylelint-disable-next-line no-duplicate-selectors */ +.navds-stepper__step[data-interactive="false"] { + & .navds-stepper__circle { + color: var(--ax-text-neutral); + border-color: var(--ax-border-default); + } + + &[data-active="true"] { + & .navds-stepper__content { + color: var(--ax-text-neutral-strong); + } + + & .navds-stepper__circle { + color: var(--ax-text-neutral-contrast); + background-color: var(--ax-bg-neutral-strong-pressed); + border-color: var(--ax-bg-neutral-strong-pressed); + } + } } .navds-stepper__content { @@ -218,91 +266,6 @@ button.navds-stepper__step { max-width: 24ch; } -/* Active step */ -:where(.navds-stepper__step--active) .navds-stepper__content { - color: var(--ac-stepper-active, var(--a-text-action-selected)); -} - -.navds-stepper__step:hover:where(:not(.navds-stepper__step--non-interactive)) { - color: var(--ac-stepper-hover-active, var(--a-text-action-hover)); -} - -:where(.navds-stepper__step:hover) .navds-stepper__content { - text-decoration: underline; -} - -:where(.navds-stepper__step--non-interactive:hover, .navds-stepper__step--active:hover) .navds-stepper__content { - text-decoration: none; -} - -:where(.navds-stepper__step--active) .navds-stepper__circle { - background-color: var(--ac-stepper-active-bg, var(--a-surface-action-selected)); - border-color: var(--ac-stepper-active-border, var(--a-border-action-selected)); - color: var(--ac-stepper-active-text, var(--a-text-on-action)); -} - -:where(.navds-stepper__step:not(.navds-stepper__step--active):hover) .navds-stepper__circle { - background-color: var(--ac-stepper-hover-bg, var(--a-surface-action-subtle-hover)); -} - -:where(.navds-stepper__step:not(.navds-stepper__step--active):hover) .navds-stepper__circle--success { - background-color: var(--ac-stepper-text, var(--a-surface-action-hover)); -} - -/* Non-interactive */ -:where(.navds-stepper__step--non-interactive.navds-stepper__step--active) .navds-stepper__content { - color: var(--ac-stepper-non-interactive-active, var(--a-text-default)); -} - -.navds-stepper__step--non-interactive.navds-stepper__step--behind.navds-stepper__step--completed + .navds-stepper__line { - background-color: var(--ac-stepper-non-interactive-line-completed, var(--a-border-strong)); -} - -.navds-stepper__item--non-interactive.navds-stepper__item--behind.navds-stepper__item--completed - + .navds-stepper__item - > .navds-stepper__line--1 { - background-color: var(--ac-stepper-non-interactive-line-completed, var(--a-border-strong)); -} - -:where(.navds-stepper__step--non-interactive.navds-stepper__step--active) .navds-stepper__circle { - background-color: var(--ac-stepper-non-interactive-active-bg, var(--a-surface-inverted)); - border-color: var(--ac-stepper-non-interactive-active-border, var(--a-surface-inverted)); - color: var(--ac-stepper-non-interactive-active-text, var(--a-text-on-inverted)); -} - :where(.navds-stepper__step--non-interactive:hover) .navds-stepper__circle { background-color: transparent; } - -:where(.navds-stepper__step--non-interactive.navds-stepper__step--active:hover) .navds-stepper__circle { - background-color: var(--ac-stepper-non-interactive-active-bg, var(--a-surface-inverted)); -} - -:where(.navds-stepper__step--completed.navds-stepper__step--active) .navds-stepper__circle { - background-color: inherit; - color: var(--ac-stepper-active-completed, var(--a-text-action-selected)); -} - -:where(.navds-stepper__step--completed.navds-stepper__step--active) .navds-stepper__circle--success { - color: var(--a-text-on-action); - background-color: var(--ac-stepper-active-completed, var(--a-surface-action-selected)); -} - -:where(.navds-stepper__step--non-interactive, .navds-stepper__step--non-interactive:hover) .navds-stepper__circle--success { - color: var(--a-text-on-inverted); - background-color: var(--ac-stepper-non-interactive-completed-bg, var(--a-surface-neutral)); -} - -:where(.navds-stepper__step--non-interactive.navds-stepper__step--active) .navds-stepper__circle--success { - color: var(--a-text-on-inverted); - background-color: var(--ac-stepper-non-interactive-active-completed, var(--a-surface-inverted)); -} - -:where(.navds-stepper__step--completed.navds-stepper__step--active.navds-stepper__step--non-interactive) .navds-stepper__circle { - color: var(--ac-stepper-non-interactive-active-completed, var(--a-text-default)); -} - -:where(.navds-stepper__step--completed.navds-stepper__step--active.navds-stepper__step--non-interactive) - .navds-stepper__circle--success { - color: var(--ac-stepper-non-interactive-active-completed, var(--a-text-on-inverted)); -} diff --git a/@navikt/core/react/src/stepper/Step.tsx b/@navikt/core/react/src/stepper/Step.tsx index d32539ac1a..86f5079c34 100644 --- a/@navikt/core/react/src/stepper/Step.tsx +++ b/@navikt/core/react/src/stepper/Step.tsx @@ -60,6 +60,9 @@ export const Step: OverridableComponent = "navds-stepper__step--non-interactive": !isInteractive, "navds-stepper__step--completed": completed, })} + data-active={activeStep === context.index} + data-completed={completed} + data-interactive={isInteractive} onClick={composeEventHandlers(onClick, handleStepClick)} > {completed ? ( diff --git a/@navikt/core/react/src/stepper/Stepper.tsx b/@navikt/core/react/src/stepper/Stepper.tsx index 33f473b12a..29046118d3 100644 --- a/@navikt/core/react/src/stepper/Stepper.tsx +++ b/@navikt/core/react/src/stepper/Stepper.tsx @@ -93,6 +93,7 @@ export const Stepper: StepperComponent = forwardRef< orientation === "horizontal" ? "navds-stepper--horizontal" : "", className, )} + data-orientation={orientation} > {React.Children.map(children, (step, index) => { const stepProps: Partial = @@ -101,10 +102,12 @@ export const Stepper: StepperComponent = forwardRef< return (
  • index, "navds-stepper__item--completed": stepProps.completed, - "navds-stepper__item--non-interactive": - stepProps.interactive ?? interactive, + "navds-stepper__item--non-interactive": !( + stepProps.interactive ?? interactive + ), })} key={index + (children?.toString?.() ?? "")} > From 6bbfd232f52de8c436b691364a741b0c1ff24a5b Mon Sep 17 00:00:00 2001 From: Ken Date: Wed, 20 Nov 2024 15:40:12 +0100 Subject: [PATCH 2/4] :refactor: Restructure Stepper to support darkmode and nesting --- .../core/css/darkside/stepper.darkside.css | 247 +++++++++--------- 1 file changed, 119 insertions(+), 128 deletions(-) diff --git a/@navikt/core/css/darkside/stepper.darkside.css b/@navikt/core/css/darkside/stepper.darkside.css index 57bc1daebd..8ef3170b7a 100644 --- a/@navikt/core/css/darkside/stepper.darkside.css +++ b/@navikt/core/css/darkside/stepper.darkside.css @@ -1,7 +1,7 @@ .navds-stepper { - --navds-stepper-circle-size: 1.75rem; - --navds-stepper-border-width: 2px; - --navds-stepper-line-length: 1rem; + --__axc-stepper-circle-size: 1.75rem; + --__axc-stepper-border-width: 2px; + --__axc-stepper-line-length: 1rem; color: var(--ax-text-accent); font-weight: var(--ax-font-weight-bold); @@ -11,27 +11,21 @@ margin: 0; } -.navds-stepper--horizontal { - display: flex; - align-items: flex-start; - text-align: center; -} - .navds-stepper__item { display: grid; grid-template-rows: - [line-1] auto [step-start] var(--navds-stepper-circle-size) + [line-1] auto [step-start] var(--__axc-stepper-circle-size) [line-2 step-end] auto; - grid-template-columns: var(--navds-stepper-circle-size) auto; + grid-template-columns: var(--__axc-stepper-circle-size) auto; justify-items: flex-start; - gap: 0.5rem; + gap: var(--ax-spacing-2); } .navds-stepper__line { background-color: var(--ax-border-accent); - width: var(--navds-stepper-border-width); + width: var(--__axc-stepper-border-width); height: 100%; - min-height: var(--navds-stepper-line-length); + min-height: var(--__axc-stepper-line-length); justify-self: center; grid-column: 1; @@ -48,6 +42,7 @@ .navds-stepper__line--2 { grid-row: line-2; + /* Hide last line under item */ .navds-stepper__item:last-of-type & { display: none; } @@ -57,26 +52,25 @@ grid-row: 2 / -1; grid-column: 1 / -1; display: grid; - grid-template-columns: [circle] var(--navds-stepper-circle-size) [content] auto; + grid-template-columns: [circle] var(--__axc-stepper-circle-size) [content] auto; gap: var(--ax-spacing-2); justify-content: flex-start; - text-decoration: none; cursor: pointer; - padding: var(--navds-stepper-border-width); - margin: calc(var(--navds-stepper-border-width) * -1) calc(var(--navds-stepper-border-width) * -1) 1.75rem; + padding: var(--__axc-stepper-border-width); + margin: calc(var(--__axc-stepper-border-width) * -1) calc(var(--__axc-stepper-border-width) * -1) + var(--__axc-stepper-circle-size); &:focus-visible { outline: 2px solid var(--ax-border-focus); - outline-offset: 2px; - } + outline-offset: 4px; - &[data-interactive="true"] { - color: var(--ax-text-accent); + /* Isolate item to make outline show above line--2 */ + isolation: isolate; } - &[data-interactive="false"] { - color: var(--ax-text-neutral); - cursor: default; + /* Remove last item bottom margin */ + .navds-stepper__item:last-child & { + margin-bottom: 0; } &:is(button) { @@ -87,65 +81,50 @@ color: inherit; text-align: inherit; } - - .navds-stepper__item:last-child & { - margin-bottom: 0; - } -} - -@media (forced-colors: active) { - .navds-stepper__step { - background-color: ButtonFace; - color: ButtonText; - } - - .navds-stepper__circle.navds-stepper__circle { - border: 0; - } - - .navds-stepper__step .navds-stepper__circle { - forced-color-adjust: none; - background-color: ButtonText; - border-color: ButtonText; - color: ButtonFace; - } - - .navds-stepper__step.navds-stepper__step:focus-visible { - box-shadow: none; - outline: 2px solid highlight; - outline-offset: 2px; - } - - .navds-stepper__step.navds-stepper__step--active .navds-stepper__circle { - forced-color-adjust: none; - background-color: highlight; - border-color: highlighttext; - color: highlighttext; - } - - .navds-stepper__line { - background-color: ButtonText; - } } .navds-stepper__circle { grid-column: circle; display: inline-grid; place-items: center; - width: var(--navds-stepper-circle-size); - height: var(--navds-stepper-circle-size); - border: var(--navds-stepper-border-width) solid currentColor; + width: var(--__axc-stepper-circle-size); + height: var(--__axc-stepper-circle-size); + border: var(--__axc-stepper-border-width) solid currentColor; border-radius: var(--ax-border-radius-full); line-height: 1; } .navds-stepper__circle--success { background: none; - font-size: 1.75rem; + font-size: var(--__axc-stepper-circle-size); } -/* stylelint-disable-next-line no-duplicate-selectors */ .navds-stepper__step[data-interactive="true"] { + color: var(--ax-text-accent); + border-radius: var(--ax-border-radius-medium); + text-decoration: none; + + &:hover, + &:active { + & .navds-stepper__content { + text-decoration-thickness: 0.111em; + } + } + + &:not([data-active="true"]) .navds-stepper__content { + text-decoration: underline; + text-underline-offset: 0.1em; + text-decoration-thickness: 0.05em; + } + + &:hover { + color: var(--ax-text-accent-strong); + + & .navds-stepper__circle { + color: var(--ax-text-accent-strong); + } + } + & .navds-stepper__circle { color: var(--ax-text-accent); border-color: var(--ax-border-accent); @@ -171,22 +150,12 @@ } } } - - &:hover { - color: var(--ax-text-accent-strong); - - & .navds-stepper__circle { - color: var(--ax-text-accent-strong); - } - - & .navds-stepper__content { - text-decoration: underline; - } - } } -/* stylelint-disable-next-line no-duplicate-selectors */ .navds-stepper__step[data-interactive="false"] { + color: var(--ax-text-neutral); + cursor: default; + & .navds-stepper__circle { color: var(--ax-text-neutral); border-color: var(--ax-border-default); @@ -213,59 +182,81 @@ } /* Horizontal */ -:where(.navds-stepper--horizontal) .navds-stepper__item { - flex: 1 1 100%; - grid-template-columns: - [line-1-start] 1fr [step-start] auto [line-1-end] var(--navds-stepper-circle-size) - [line-2-start] auto [step-end] 1fr [line-2-end]; - grid-template-rows: var(--navds-stepper-circle-size) auto; -} +.navds-stepper[data-orientation="horizontal"] { + display: flex; + align-items: flex-start; + text-align: center; -:where(.navds-stepper--horizontal) .navds-stepper__line { - height: var(--navds-stepper-border-width); - width: 100%; - min-height: auto; - grid-row: 1; - display: block; - align-self: center; -} + & .navds-stepper__line { + height: var(--__axc-stepper-border-width); + width: 100%; + min-height: auto; + grid-row: 1; + display: block; + align-self: center; + } -:where(.navds-stepper--horizontal) .navds-stepper__line--1 { - grid-column: line-1; -} + & .navds-stepper__line--1 { + grid-column: line-1; + } -:where(.navds-stepper--horizontal) .navds-stepper__line--2 { - grid-column: line-2; -} + & .navds-stepper__line--2 { + grid-column: line-2; + } -:where(.navds-stepper--horizontal .navds-stepper__item:first-of-type) .navds-stepper__line--1, -:where(.navds-stepper--horizontal .navds-stepper__item:last-of-type) .navds-stepper__line--2 { - visibility: hidden; -} + & .navds-stepper__item { + flex: 1 1 100%; + grid-template-columns: + [line-1-start] 1fr [step-start] auto [line-1-end] var(--__axc-stepper-circle-size) + [line-2-start] auto [step-end] 1fr [line-2-end]; + grid-template-rows: var(--__axc-stepper-circle-size) auto; -:where(.navds-stepper--horizontal) .navds-stepper__step { - grid-row: 1 / -1; - grid-column: step; - display: grid; - grid-template-rows: [circle] var(--navds-stepper-circle-size) [content] auto; - grid-template-columns: - [content-start] auto [circle] var(--navds-stepper-circle-size) - [content-end] auto; - place-items: center center; - margin-bottom: 0; -} + &:first-of-type .navds-stepper__line--1, + &:last-of-type .navds-stepper__line--2 { + visibility: hidden; + } + } -:where(.navds-stepper--horizontal) .navds-stepper__circle { - grid-row: circle; - grid-column: 2; -} + & .navds-stepper__step { + grid-row: 1 / -1; + grid-column: step; + display: grid; + grid-template-rows: [circle] var(--__axc-stepper-circle-size) [content] auto; + grid-template-columns: + [content-start] auto [circle] var(--__axc-stepper-circle-size) + [content-end] auto; + place-items: center center; + margin-bottom: 0; + } -:where(.navds-stepper--horizontal) .navds-stepper__content { - grid-row: content; - grid-column: 1 / -1; - max-width: 24ch; + & .navds-stepper__circle { + grid-row: circle; + grid-column: 2; + } + + & .navds-stepper__content { + grid-row: content; + grid-column: 1 / -1; + max-width: 24ch; + } } -:where(.navds-stepper__step--non-interactive:hover) .navds-stepper__circle { - background-color: transparent; +@media (forced-colors: active) { + .navds-stepper__circle.navds-stepper__circle { + border: 0; + outline: 2px solid ButtonText; + outline-offset: 2px; + } + + .navds-stepper__line.navds-stepper__line { + background-color: ButtonText; + } + + .navds-stepper__step[data-active="true"][data-interactive] { + .navds-stepper__circle { + forced-color-adjust: none; + background-color: highlight; + color: highlighttext; + } + } } From f9e0f0461546640ed4f4de087d51288a4807384a Mon Sep 17 00:00:00 2001 From: Ken Date: Mon, 25 Nov 2024 11:50:32 +0100 Subject: [PATCH 3/4] :bug: text-decoration now changes on hover --- @navikt/core/css/darkside/stepper.darkside.css | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/@navikt/core/css/darkside/stepper.darkside.css b/@navikt/core/css/darkside/stepper.darkside.css index 8ef3170b7a..9ec66dd6ef 100644 --- a/@navikt/core/css/darkside/stepper.darkside.css +++ b/@navikt/core/css/darkside/stepper.darkside.css @@ -104,6 +104,12 @@ border-radius: var(--ax-border-radius-medium); text-decoration: none; + & .navds-stepper__content { + text-decoration: underline; + text-underline-offset: 0.1em; + text-decoration-thickness: 0.05em; + } + &:hover, &:active { & .navds-stepper__content { @@ -111,12 +117,6 @@ } } - &:not([data-active="true"]) .navds-stepper__content { - text-decoration: underline; - text-underline-offset: 0.1em; - text-decoration-thickness: 0.05em; - } - &:hover { color: var(--ax-text-accent-strong); @@ -133,6 +133,7 @@ &[data-active="true"] { & .navds-stepper__content { color: var(--ax-text-accent-strong); + text-decoration: none; } & .navds-stepper__circle { From fc31481f761efaf405a5853381af45e0fde3f08e Mon Sep 17 00:00:00 2001 From: Ken Date: Mon, 25 Nov 2024 11:57:30 +0100 Subject: [PATCH 4/4] :refactor: Line before non-interactive step now has border-neutral --- @navikt/core/css/darkside/stepper.darkside.css | 7 +++++++ @navikt/core/react/src/stepper/stepper.stories.tsx | 4 +++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/@navikt/core/css/darkside/stepper.darkside.css b/@navikt/core/css/darkside/stepper.darkside.css index 9ec66dd6ef..b82584b28d 100644 --- a/@navikt/core/css/darkside/stepper.darkside.css +++ b/@navikt/core/css/darkside/stepper.darkside.css @@ -34,6 +34,13 @@ } } +/* Line before non-interactive step */ +.navds-stepper__item:has(+ .navds-stepper__item > .navds-stepper__step[data-interactive="false"]) { + .navds-stepper__line--2 { + background-color: var(--ax-border-neutral); + } +} + .navds-stepper__line--1 { grid-row: line-1; display: none; diff --git a/@navikt/core/react/src/stepper/stepper.stories.tsx b/@navikt/core/react/src/stepper/stepper.stories.tsx index 3f1a27ec42..180fe7361d 100644 --- a/@navikt/core/react/src/stepper/stepper.stories.tsx +++ b/@navikt/core/react/src/stepper/stepper.stories.tsx @@ -180,7 +180,9 @@ export const CompletedSteps: StoryFn = () => { = 4}> Søknadstekst for en veldig spesifikk prosess i NAV som har lang tekst - 5}>Vedlegg + 5} interactive={false}> + Vedlegg + 6}>Oppsummering 7}>Innsending