From 320b61386fc53e6b58f730676f6116e53320ff5a Mon Sep 17 00:00:00 2001 From: rajsite <1588923+rajsite@users.noreply.github.com> Date: Tue, 31 Mar 2026 18:31:33 -0500 Subject: [PATCH 01/10] Readonly impl and matrix tests --- .../src/anchor-step/index.ts | 10 +++++++++ .../src/anchor-step/template.ts | 1 + packages/nimble-components/src/step/index.ts | 10 +++++++++ .../nimble-components/src/step/template.ts | 1 + .../anchor-step/anchor-step-matrix.stories.ts | 22 ++++++++++++------- .../src/nimble/step/step-matrix.stories.ts | 22 ++++++++++++------- .../src/nimble/stepper/stepper.stories.ts | 17 +++++++++++++- .../storybook/src/nimble/stepper/types.ts | 15 +++++++++++++ 8 files changed, 81 insertions(+), 17 deletions(-) diff --git a/packages/nimble-components/src/anchor-step/index.ts b/packages/nimble-components/src/anchor-step/index.ts index b411caa756..e32ceaacd3 100644 --- a/packages/nimble-components/src/anchor-step/index.ts +++ b/packages/nimble-components/src/anchor-step/index.ts @@ -62,6 +62,16 @@ export class AnchorStep extends mixinSeverityPattern(AnchorBase) implements Step * @internal */ public readonly stepInternals = new StepInternals(); + + /** + * @internal + */ + public onClick(e: Event): void { + if (this.readOnly) { + e.preventDefault(); + e.stopImmediatePropagation(); + } + } } const nimbleAnchorStep = AnchorStep.compose({ diff --git a/packages/nimble-components/src/anchor-step/template.ts b/packages/nimble-components/src/anchor-step/template.ts index d9fe127d76..f6ec15cee1 100644 --- a/packages/nimble-components/src/anchor-step/template.ts +++ b/packages/nimble-components/src/anchor-step/template.ts @@ -51,6 +51,7 @@ AnchorOptions aria-owns="${x => x.ariaOwns}" aria-relevant="${x => x.ariaRelevant}" aria-roledescription="${x => x.ariaRoledescription}" + @click="${(x, c) => x.onClick(c.event)}" ${ref('control')} >
diff --git a/packages/nimble-components/src/step/index.ts b/packages/nimble-components/src/step/index.ts index fd8994796b..ec7d97b2e5 100644 --- a/packages/nimble-components/src/step/index.ts +++ b/packages/nimble-components/src/step/index.ts @@ -57,6 +57,16 @@ export class Step extends mixinSeverityPattern(FoundationButton) implements Step * @internal */ public readonly stepInternals = new StepInternals(); + + /** + * @internal + */ + public onClick(e: Event): void { + if (this.readOnly) { + e.preventDefault(); + e.stopImmediatePropagation(); + } + } } const nimbleStep = Step.compose({ diff --git a/packages/nimble-components/src/step/template.ts b/packages/nimble-components/src/step/template.ts index aceaab2380..ecc7b6ce7e 100644 --- a/packages/nimble-components/src/step/template.ts +++ b/packages/nimble-components/src/step/template.ts @@ -55,6 +55,7 @@ ButtonOptions aria-pressed="${x => x.ariaPressed}" aria-relevant="${x => x.ariaRelevant}" aria-roledescription="${x => x.ariaRoledescription}" + @click="${(x, c) => x.onClick(c.event)}" ${ref('control')} >
diff --git a/packages/storybook/src/nimble/anchor-step/anchor-step-matrix.stories.ts b/packages/storybook/src/nimble/anchor-step/anchor-step-matrix.stories.ts index a20b3a5c2b..5ee93edfc2 100644 --- a/packages/storybook/src/nimble/anchor-step/anchor-step-matrix.stories.ts +++ b/packages/storybook/src/nimble/anchor-step/anchor-step-matrix.stories.ts @@ -12,8 +12,14 @@ import { } from '../../utilities/matrix'; import { createFixedThemeStory, createStory } from '../../utilities/storybook'; import { hiddenWrapper } from '../../utilities/hidden'; -import { selectedStates, severityStates, stepContentStateShort, stepContentStateStepIndicator, stepContentStates, stepLayoutStates, type SelectedState, type SeverityStates, type StepContentStates, type StepLayoutStates } from '../stepper/types'; -import { backgroundStates, disabledStates, type DisabledState } from '../../utilities/states'; +import { + selectedStates, type SelectedState, + severityStates, type SeverityStates, + stepContentStates, stepContentStateShort, stepContentStateStepIndicator, type StepContentStates, + stepLayoutStates, type StepLayoutStates, + stepManipulationStates, type StepManipulationState +} from '../stepper/types'; +import { backgroundStates } from '../../utilities/states'; const metadata: Meta = { title: 'Tests/Anchor Step', @@ -36,18 +42,18 @@ if (remaining.length > 0) { export default metadata; const component = ( - [disabledName, disabled]: DisabledState, + [manipulationName, readonly, disabled]: StepManipulationState, [layoutName, isLast, orientation]: StepLayoutStates, [selectedName, selected]: SelectedState, [severityName, severity]: SeverityStates, [contentName, titleContent, subtitleContent, severityTextContent, stepIndicatorVisible]: StepContentStates, ): ViewTemplate => html`
-
${disabledName} ${selectedName} Severity(${severityName}) Layout(${layoutName}) Content(${contentName})
+
${manipulationName} ${selectedName} Severity(${severityName}) Layout(${layoutName}) Content(${contentName})
<${stepperTag} style="padding-bottom: 16px; width: 200px; height: 80px;" orientation="${() => orientation}"> ${repeat(() => [isLast, !isLast], html` <${anchorStepTag} href="#" target="_self" - ?disabled=${() => disabled} ?selected=${() => selected} severity-text="${() => severityTextContent}" severity="${() => severity}" + ?disabled=${() => disabled} ?readonly=${() => readonly} ?selected=${() => selected} severity-text="${() => severityTextContent}" severity="${() => severity}" style="${currentIsLast => (currentIsLast ? 'display:none;' : '')}"> ${when(() => titleContent !== undefined, html`${() => titleContent}`)} ${when(() => subtitleContent !== undefined, html`${() => subtitleContent}`)} @@ -67,7 +73,7 @@ const matrixTemplate = html` width: 1200px; "> ${createMatrix(component, [ - disabledStates, + stepManipulationStates, stepLayoutStates, selectedStates, severityStates, @@ -81,7 +87,7 @@ export const matrix$DarkTheme: StoryFn = createFixedThemeStory(matrixTemplate, d export const matrix$ColorTheme: StoryFn = createFixedThemeStory(matrixTemplate, colorThemeDarkGreenBackground); const interactionStatesHover = cartesianProduct([ - disabledStates, + stepManipulationStates, stepLayoutStates, selectedStates, severityStates, @@ -89,7 +95,7 @@ const interactionStatesHover = cartesianProduct([ ] as const); const interactionStates = cartesianProduct([ - disabledStates, + stepManipulationStates, stepLayoutStates, selectedStates, severityStates, diff --git a/packages/storybook/src/nimble/step/step-matrix.stories.ts b/packages/storybook/src/nimble/step/step-matrix.stories.ts index d78900dcf0..a34f2f830f 100644 --- a/packages/storybook/src/nimble/step/step-matrix.stories.ts +++ b/packages/storybook/src/nimble/step/step-matrix.stories.ts @@ -12,8 +12,14 @@ import { } from '../../utilities/matrix'; import { createFixedThemeStory, createStory } from '../../utilities/storybook'; import { hiddenWrapper } from '../../utilities/hidden'; -import { selectedStates, severityStates, stepContentStates, stepContentStateShort, stepContentStateStepIndicator, stepLayoutStates, type SelectedState, type SeverityStates, type StepContentStates, type StepLayoutStates } from '../stepper/types'; -import { disabledStates, type DisabledState, backgroundStates } from '../../utilities/states'; +import { + selectedStates, type SelectedState, + severityStates, type SeverityStates, + stepContentStates, stepContentStateShort, stepContentStateStepIndicator, type StepContentStates, + stepLayoutStates, type StepLayoutStates, + stepManipulationStates, type StepManipulationState +} from '../stepper/types'; +import { backgroundStates } from '../../utilities/states'; const metadata: Meta = { title: 'Tests/Step', @@ -36,18 +42,18 @@ if (remaining.length > 0) { export default metadata; const component = ( - [disabledName, disabled]: DisabledState, + [manipulationName, readonly, disabled]: StepManipulationState, [layoutName, isLast, orientation]: StepLayoutStates, [selectedName, selected]: SelectedState, [severityName, severity]: SeverityStates, [contentName, titleContent, subtitleContent, severityTextContent, stepIndicatorVisible]: StepContentStates, ): ViewTemplate => html`
-
${disabledName} ${selectedName} Severity(${severityName}) Layout(${layoutName}) Content(${contentName})
+
${manipulationName} ${selectedName} Severity(${severityName}) Layout(${layoutName}) Content(${contentName})
<${stepperTag} style="padding-bottom: 16px; width: 200px; height: 80px;" orientation="${() => orientation}"> ${repeat(() => [isLast, !isLast], html` <${stepTag} - ?disabled=${() => disabled} ?selected=${() => selected} severity-text="${() => severityTextContent}" severity="${() => severity}" + ?disabled=${() => disabled} ?readonly=${() => readonly} ?selected=${() => selected} severity-text="${() => severityTextContent}" severity="${() => severity}" style="${currentIsLast => (currentIsLast ? 'display:none;' : '')}"> ${when(() => titleContent !== undefined, html`${() => titleContent}`)} ${when(() => subtitleContent !== undefined, html`${() => subtitleContent}`)} @@ -67,7 +73,7 @@ const matrixTemplate = html` width: 1200px; "> ${createMatrix(component, [ - disabledStates, + stepManipulationStates, stepLayoutStates, selectedStates, severityStates, @@ -81,7 +87,7 @@ export const matrix$DarkTheme: StoryFn = createFixedThemeStory(matrixTemplate, d export const matrix$ColorTheme: StoryFn = createFixedThemeStory(matrixTemplate, colorThemeDarkGreenBackground); const interactionStatesHover = cartesianProduct([ - disabledStates, + stepManipulationStates, stepLayoutStates, selectedStates, severityStates, @@ -89,7 +95,7 @@ const interactionStatesHover = cartesianProduct([ ] as const); const interactionStates = cartesianProduct([ - disabledStates, + stepManipulationStates, stepLayoutStates, selectedStates, severityStates, diff --git a/packages/storybook/src/nimble/stepper/stepper.stories.ts b/packages/storybook/src/nimble/stepper/stepper.stories.ts index caa7ee896e..929caaee31 100644 --- a/packages/storybook/src/nimble/stepper/stepper.stories.ts +++ b/packages/storybook/src/nimble/stepper/stepper.stories.ts @@ -11,7 +11,8 @@ import { apiCategory, createUserSelectedThemeStory, disabledDescription, - incubatingWarning + incubatingWarning, + readonlyDescription } from '../../utilities/storybook'; import { ExampleStepType } from './types'; import { hrefDescription } from '../patterns/anchor/anchor-docs'; @@ -26,6 +27,7 @@ const severityTextDescription = 'A message explaining the state of the step. Onl interface AnchorStepArgs { href: string; disabled: boolean; + readonly: boolean; severity: keyof typeof AnchorStepSeverity; severityText: string; title: string; @@ -38,6 +40,7 @@ export const anchorStep: StoryObj = { <${stepperTag} class="code-hide-top-container"> <${anchorStepTag} ?disabled="${x => x.disabled}" + ?readonly="${x => x.readonly}" severity="${x => AnchorStepSeverity[x.severity]}" severity-text="${x => x.severityText}" ?selected="${x => x.selected}" @@ -63,6 +66,10 @@ export const anchorStep: StoryObj = { }), table: { category: apiCategory.attributes } }, + readonly: { + description: readonlyDescription({ componentName: 'anchor step' }), + table: { category: apiCategory.attributes } + }, severity: { options: Object.keys(AnchorStepSeverity), control: { type: 'radio' }, @@ -96,6 +103,7 @@ export const anchorStep: StoryObj = { args: { href: '#', disabled: false, + readonly: false, severity: 'default', severityText: 'Helper message', title: 'Title', @@ -106,6 +114,7 @@ export const anchorStep: StoryObj = { interface StepArgs { disabled: boolean; + readonly: boolean; severity: keyof typeof StepSeverity; severityText: string; title: string; @@ -119,6 +128,7 @@ export const step: StoryObj = { <${stepperTag} class="code-hide-top-container"> <${stepTag} ?disabled="${x => x.disabled}" + ?readonly="${x => x.readonly}" severity="${x => StepSeverity[x.severity]}" severity-text="${x => x.severityText}" ?selected="${x => x.selected}" @@ -138,6 +148,10 @@ export const step: StoryObj = { }), table: { category: apiCategory.attributes } }, + readonly: { + description: readonlyDescription({ componentName: 'anchor step' }), + table: { category: apiCategory.attributes } + }, severity: { options: Object.keys(StepSeverity), control: { type: 'radio' }, @@ -176,6 +190,7 @@ export const step: StoryObj = { }, args: { disabled: false, + readonly: false, severity: 'default', severityText: 'Helper message', title: 'Title', diff --git a/packages/storybook/src/nimble/stepper/types.ts b/packages/storybook/src/nimble/stepper/types.ts index f259b25103..a9b8c37e1e 100644 --- a/packages/storybook/src/nimble/stepper/types.ts +++ b/packages/storybook/src/nimble/stepper/types.ts @@ -47,3 +47,18 @@ export const stepLayoutStates = [ ['Last Vertical', true, 'vertical'], ] as const; export type StepLayoutStates = (typeof stepLayoutStates)[number]; + +export const stepManipulationStates = [ + ['', false, false], + ['Disabled', false, true], + ['Read-Only', true, false], + ['Read-Only Disabled', true, true], +] as const; +export type StepManipulationState = (typeof stepManipulationStates)[number]; + +export const stepManipulationState = { + none: stepManipulationStates[0], + disabled: stepManipulationStates[1], + readOnly: stepManipulationStates[2], + readOnlyDisabled: stepManipulationStates[3], +} as const; From 97f42f8119b7dbd8a19a37b0dd3320ea31de706a Mon Sep 17 00:00:00 2001 From: rajsite <1588923+rajsite@users.noreply.github.com> Date: Tue, 31 Mar 2026 18:32:05 -0500 Subject: [PATCH 02/10] Change files --- ...le-components-91d2c055-93d0-4d1d-96c1-f1c8366cdc9f.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 change/@ni-nimble-components-91d2c055-93d0-4d1d-96c1-f1c8366cdc9f.json diff --git a/change/@ni-nimble-components-91d2c055-93d0-4d1d-96c1-f1c8366cdc9f.json b/change/@ni-nimble-components-91d2c055-93d0-4d1d-96c1-f1c8366cdc9f.json new file mode 100644 index 0000000000..41f242f6d7 --- /dev/null +++ b/change/@ni-nimble-components-91d2c055-93d0-4d1d-96c1-f1c8366cdc9f.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "Readonly state behavior", + "packageName": "@ni/nimble-components", + "email": "1588923+rajsite@users.noreply.github.com", + "dependentChangeType": "patch" +} From bf795a9274bf58bd5db5dfbb3bc9136f851036c1 Mon Sep 17 00:00:00 2001 From: rajsite <1588923+rajsite@users.noreply.github.com> Date: Tue, 31 Mar 2026 20:52:05 -0500 Subject: [PATCH 03/10] =?UTF-8?q?Decompose=20matrices=20on=20interactions?= =?UTF-8?q?=20=F0=9F=98=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../anchor-step/anchor-step-matrix.stories.ts | 207 ++++++++++++++++-- .../src/nimble/step/step-matrix.stories.ts | 207 ++++++++++++++++-- 2 files changed, 370 insertions(+), 44 deletions(-) diff --git a/packages/storybook/src/nimble/anchor-step/anchor-step-matrix.stories.ts b/packages/storybook/src/nimble/anchor-step/anchor-step-matrix.stories.ts index 5ee93edfc2..0c7c3b2c7d 100644 --- a/packages/storybook/src/nimble/anchor-step/anchor-step-matrix.stories.ts +++ b/packages/storybook/src/nimble/anchor-step/anchor-step-matrix.stories.ts @@ -17,7 +17,7 @@ import { severityStates, type SeverityStates, stepContentStates, stepContentStateShort, stepContentStateStepIndicator, type StepContentStates, stepLayoutStates, type StepLayoutStates, - stepManipulationStates, type StepManipulationState + stepManipulationState, type StepManipulationState, } from '../stepper/types'; import { backgroundStates } from '../../utilities/states'; @@ -64,7 +64,7 @@ const component = (
`; -const matrixTemplate = html` +const matrixTemplate = (template: ViewTemplate): ViewTemplate => html`
- ${createMatrix(component, [ - stepManipulationStates, + ${template} +
+`; + +export const matrix$LightTheme$ReadOnlyAbsent$DisabledAbsent: StoryFn = createFixedThemeStory( + matrixTemplate(createMatrix(component, [ + [stepManipulationState.none], stepLayoutStates, selectedStates, severityStates, stepContentStates, - ])} -
-`; + ])), + lightThemeWhiteBackground +); + +export const matrix$LightTheme$ReadOnlyAbsent$Disabled: StoryFn = createFixedThemeStory( + matrixTemplate(createMatrix(component, [ + [stepManipulationState.disabled], + stepLayoutStates, + selectedStates, + severityStates, + stepContentStates, + ])), + lightThemeWhiteBackground +); + +export const matrix$LightTheme$ReadOnly$DisabledAbsent: StoryFn = createFixedThemeStory( + matrixTemplate(createMatrix(component, [ + [stepManipulationState.readOnly], + stepLayoutStates, + selectedStates, + severityStates, + stepContentStates, + ])), + lightThemeWhiteBackground +); + +export const matrix$LightTheme$ReadOnly$Disabled: StoryFn = createFixedThemeStory( + matrixTemplate(createMatrix(component, [ + [stepManipulationState.readOnlyDisabled], + stepLayoutStates, + selectedStates, + severityStates, + stepContentStates, + ])), + lightThemeWhiteBackground +); + +export const matrix$DarkTheme$ReadOnlyAbsent$DisabledAbsent: StoryFn = createFixedThemeStory( + matrixTemplate(createMatrix(component, [ + [stepManipulationState.none], + stepLayoutStates, + selectedStates, + severityStates, + stepContentStates, + ])), + darkThemeBlackBackground +); + +export const matrix$DarkTheme$ReadOnlyAbsent$Disabled: StoryFn = createFixedThemeStory( + matrixTemplate(createMatrix(component, [ + [stepManipulationState.disabled], + stepLayoutStates, + selectedStates, + severityStates, + stepContentStates, + ])), + darkThemeBlackBackground +); + +export const matrix$DarkTheme$ReadOnly$DisabledAbsent: StoryFn = createFixedThemeStory( + matrixTemplate(createMatrix(component, [ + [stepManipulationState.readOnly], + stepLayoutStates, + selectedStates, + severityStates, + stepContentStates, + ])), + darkThemeBlackBackground +); -export const matrix$LightTheme: StoryFn = createFixedThemeStory(matrixTemplate, lightThemeWhiteBackground); -export const matrix$DarkTheme: StoryFn = createFixedThemeStory(matrixTemplate, darkThemeBlackBackground); -export const matrix$ColorTheme: StoryFn = createFixedThemeStory(matrixTemplate, colorThemeDarkGreenBackground); +export const matrix$DarkTheme$ReadOnly$Disabled: StoryFn = createFixedThemeStory( + matrixTemplate(createMatrix(component, [ + [stepManipulationState.readOnlyDisabled], + stepLayoutStates, + selectedStates, + severityStates, + stepContentStates, + ])), + darkThemeBlackBackground +); + +export const matrix$ColorTheme$ReadOnlyAbsent$DisabledAbsent: StoryFn = createFixedThemeStory( + matrixTemplate(createMatrix(component, [ + [stepManipulationState.none], + stepLayoutStates, + selectedStates, + severityStates, + stepContentStates, + ])), + colorThemeDarkGreenBackground +); + +export const matrix$ColorTheme$ReadOnlyAbsent$Disabled: StoryFn = createFixedThemeStory( + matrixTemplate(createMatrix(component, [ + [stepManipulationState.disabled], + stepLayoutStates, + selectedStates, + severityStates, + stepContentStates, + ])), + colorThemeDarkGreenBackground +); + +export const matrix$ColorTheme$ReadOnly$DisabledAbsent: StoryFn = createFixedThemeStory( + matrixTemplate(createMatrix(component, [ + [stepManipulationState.readOnly], + stepLayoutStates, + selectedStates, + severityStates, + stepContentStates, + ])), + colorThemeDarkGreenBackground +); -const interactionStatesHover = cartesianProduct([ - stepManipulationStates, +export const matrix$ColorTheme$ReadOnly$Disabled: StoryFn = createFixedThemeStory( + matrixTemplate(createMatrix(component, [ + [stepManipulationState.readOnlyDisabled], + stepLayoutStates, + selectedStates, + severityStates, + stepContentStates, + ])), + colorThemeDarkGreenBackground +); + +const interactionStates$ReadOnlyAbsent$DisabledAbsent = cartesianProduct([ + [stepManipulationState.none], stepLayoutStates, selectedStates, severityStates, [stepContentStateShort, stepContentStateStepIndicator], ] as const); +const interactionsTemplate$ReadOnlyAbsent$DisabledAbsent = createMatrixInteractionsFromStates(component, { + hover: interactionStates$ReadOnlyAbsent$DisabledAbsent, + hoverActive: interactionStates$ReadOnlyAbsent$DisabledAbsent, + active: interactionStates$ReadOnlyAbsent$DisabledAbsent, + focus: interactionStates$ReadOnlyAbsent$DisabledAbsent +}); +export const interactions$LightTheme$ReadOnlyAbsent$DisabledAbsent: StoryFn = createFixedThemeStory(interactionsTemplate$ReadOnlyAbsent$DisabledAbsent, lightThemeWhiteBackground); +export const interactions$DarkTheme$ReadOnlyAbsent$DisabledAbsent: StoryFn = createFixedThemeStory(interactionsTemplate$ReadOnlyAbsent$DisabledAbsent, darkThemeBlackBackground); +export const interactions$ColorTheme$ReadOnlyAbsent$DisabledAbsent: StoryFn = createFixedThemeStory(interactionsTemplate$ReadOnlyAbsent$DisabledAbsent, colorThemeDarkGreenBackground); -const interactionStates = cartesianProduct([ - stepManipulationStates, +const interactionStates$ReadOnlyAbsent$Disabled = cartesianProduct([ + [stepManipulationState.disabled], stepLayoutStates, selectedStates, severityStates, [stepContentStateShort, stepContentStateStepIndicator], ] as const); +const interactionsTemplate$ReadOnlyAbsent$Disabled = createMatrixInteractionsFromStates(component, { + hover: interactionStates$ReadOnlyAbsent$Disabled, + hoverActive: interactionStates$ReadOnlyAbsent$Disabled, + active: interactionStates$ReadOnlyAbsent$Disabled, + focus: interactionStates$ReadOnlyAbsent$Disabled +}); +export const interactions$LightTheme$ReadOnlyAbsent$Disabled: StoryFn = createFixedThemeStory(interactionsTemplate$ReadOnlyAbsent$Disabled, lightThemeWhiteBackground); +export const interactions$DarkTheme$ReadOnlyAbsent$Disabled: StoryFn = createFixedThemeStory(interactionsTemplate$ReadOnlyAbsent$Disabled, darkThemeBlackBackground); +export const interactions$ColorTheme$ReadOnlyAbsent$Disabled: StoryFn = createFixedThemeStory(interactionsTemplate$ReadOnlyAbsent$Disabled, colorThemeDarkGreenBackground); -const interactionsTemplate = createMatrixInteractionsFromStates(component, { - hover: interactionStatesHover, - hoverActive: interactionStates, - active: interactionStates, - focus: interactionStates +const interactionStates$ReadOnly$DisabledAbsent = cartesianProduct([ + [stepManipulationState.readOnly], + stepLayoutStates, + selectedStates, + severityStates, + [stepContentStateShort, stepContentStateStepIndicator], +] as const); +const interactionsTemplate$ReadOnly$DisabledAbsent = createMatrixInteractionsFromStates(component, { + hover: interactionStates$ReadOnly$DisabledAbsent, + hoverActive: interactionStates$ReadOnly$DisabledAbsent, + active: interactionStates$ReadOnly$DisabledAbsent, + focus: interactionStates$ReadOnly$DisabledAbsent }); +export const interactions$LightTheme$ReadOnly$DisabledAbsent: StoryFn = createFixedThemeStory(interactionsTemplate$ReadOnly$DisabledAbsent, lightThemeWhiteBackground); +export const interactions$DarkTheme$ReadOnly$DisabledAbsent: StoryFn = createFixedThemeStory(interactionsTemplate$ReadOnly$DisabledAbsent, darkThemeBlackBackground); +export const interactions$ColorTheme$ReadOnly$DisabledAbsent: StoryFn = createFixedThemeStory(interactionsTemplate$ReadOnly$DisabledAbsent, colorThemeDarkGreenBackground); -export const interactions$LightTheme: StoryFn = createFixedThemeStory(interactionsTemplate, lightThemeWhiteBackground); -export const interactions$DarkTheme: StoryFn = createFixedThemeStory(interactionsTemplate, darkThemeBlackBackground); -export const interactions$ColorTheme: StoryFn = createFixedThemeStory(interactionsTemplate, colorThemeDarkGreenBackground); +const interactionStates$ReadOnly$Disabled = cartesianProduct([ + [stepManipulationState.readOnlyDisabled], + stepLayoutStates, + selectedStates, + severityStates, + [stepContentStateShort, stepContentStateStepIndicator], +] as const); +const interactionsTemplate$ReadOnly$Disabled = createMatrixInteractionsFromStates(component, { + hover: interactionStates$ReadOnly$Disabled, + hoverActive: interactionStates$ReadOnly$Disabled, + active: interactionStates$ReadOnly$Disabled, + focus: interactionStates$ReadOnly$Disabled +}); +export const interactions$LightTheme$ReadOnly$Disabled: StoryFn = createFixedThemeStory(interactionsTemplate$ReadOnly$Disabled, lightThemeWhiteBackground); +export const interactions$DarkTheme$ReadOnly$Disabled: StoryFn = createFixedThemeStory(interactionsTemplate$ReadOnly$Disabled, darkThemeBlackBackground); +export const interactions$ColorTheme$ReadOnly$Disabled: StoryFn = createFixedThemeStory(interactionsTemplate$ReadOnly$Disabled, colorThemeDarkGreenBackground); export const hidden: StoryFn = createStory( hiddenWrapper( diff --git a/packages/storybook/src/nimble/step/step-matrix.stories.ts b/packages/storybook/src/nimble/step/step-matrix.stories.ts index a34f2f830f..eed7fc5d0e 100644 --- a/packages/storybook/src/nimble/step/step-matrix.stories.ts +++ b/packages/storybook/src/nimble/step/step-matrix.stories.ts @@ -17,7 +17,7 @@ import { severityStates, type SeverityStates, stepContentStates, stepContentStateShort, stepContentStateStepIndicator, type StepContentStates, stepLayoutStates, type StepLayoutStates, - stepManipulationStates, type StepManipulationState + stepManipulationState, type StepManipulationState, } from '../stepper/types'; import { backgroundStates } from '../../utilities/states'; @@ -64,7 +64,7 @@ const component = ( `; -const matrixTemplate = html` +const matrixTemplate = (template: ViewTemplate): ViewTemplate => html`
- ${createMatrix(component, [ - stepManipulationStates, + ${template} +
+`; + +export const matrix$LightTheme$ReadOnlyAbsent$DisabledAbsent: StoryFn = createFixedThemeStory( + matrixTemplate(createMatrix(component, [ + [stepManipulationState.none], stepLayoutStates, selectedStates, severityStates, stepContentStates, - ])} - -`; + ])), + lightThemeWhiteBackground +); + +export const matrix$LightTheme$ReadOnlyAbsent$Disabled: StoryFn = createFixedThemeStory( + matrixTemplate(createMatrix(component, [ + [stepManipulationState.disabled], + stepLayoutStates, + selectedStates, + severityStates, + stepContentStates, + ])), + lightThemeWhiteBackground +); + +export const matrix$LightTheme$ReadOnly$DisabledAbsent: StoryFn = createFixedThemeStory( + matrixTemplate(createMatrix(component, [ + [stepManipulationState.readOnly], + stepLayoutStates, + selectedStates, + severityStates, + stepContentStates, + ])), + lightThemeWhiteBackground +); + +export const matrix$LightTheme$ReadOnly$Disabled: StoryFn = createFixedThemeStory( + matrixTemplate(createMatrix(component, [ + [stepManipulationState.readOnlyDisabled], + stepLayoutStates, + selectedStates, + severityStates, + stepContentStates, + ])), + lightThemeWhiteBackground +); + +export const matrix$DarkTheme$ReadOnlyAbsent$DisabledAbsent: StoryFn = createFixedThemeStory( + matrixTemplate(createMatrix(component, [ + [stepManipulationState.none], + stepLayoutStates, + selectedStates, + severityStates, + stepContentStates, + ])), + darkThemeBlackBackground +); + +export const matrix$DarkTheme$ReadOnlyAbsent$Disabled: StoryFn = createFixedThemeStory( + matrixTemplate(createMatrix(component, [ + [stepManipulationState.disabled], + stepLayoutStates, + selectedStates, + severityStates, + stepContentStates, + ])), + darkThemeBlackBackground +); + +export const matrix$DarkTheme$ReadOnly$DisabledAbsent: StoryFn = createFixedThemeStory( + matrixTemplate(createMatrix(component, [ + [stepManipulationState.readOnly], + stepLayoutStates, + selectedStates, + severityStates, + stepContentStates, + ])), + darkThemeBlackBackground +); -export const matrix$LightTheme: StoryFn = createFixedThemeStory(matrixTemplate, lightThemeWhiteBackground); -export const matrix$DarkTheme: StoryFn = createFixedThemeStory(matrixTemplate, darkThemeBlackBackground); -export const matrix$ColorTheme: StoryFn = createFixedThemeStory(matrixTemplate, colorThemeDarkGreenBackground); +export const matrix$DarkTheme$ReadOnly$Disabled: StoryFn = createFixedThemeStory( + matrixTemplate(createMatrix(component, [ + [stepManipulationState.readOnlyDisabled], + stepLayoutStates, + selectedStates, + severityStates, + stepContentStates, + ])), + darkThemeBlackBackground +); + +export const matrix$ColorTheme$ReadOnlyAbsent$DisabledAbsent: StoryFn = createFixedThemeStory( + matrixTemplate(createMatrix(component, [ + [stepManipulationState.none], + stepLayoutStates, + selectedStates, + severityStates, + stepContentStates, + ])), + colorThemeDarkGreenBackground +); + +export const matrix$ColorTheme$ReadOnlyAbsent$Disabled: StoryFn = createFixedThemeStory( + matrixTemplate(createMatrix(component, [ + [stepManipulationState.disabled], + stepLayoutStates, + selectedStates, + severityStates, + stepContentStates, + ])), + colorThemeDarkGreenBackground +); + +export const matrix$ColorTheme$ReadOnly$DisabledAbsent: StoryFn = createFixedThemeStory( + matrixTemplate(createMatrix(component, [ + [stepManipulationState.readOnly], + stepLayoutStates, + selectedStates, + severityStates, + stepContentStates, + ])), + colorThemeDarkGreenBackground +); -const interactionStatesHover = cartesianProduct([ - stepManipulationStates, +export const matrix$ColorTheme$ReadOnly$Disabled: StoryFn = createFixedThemeStory( + matrixTemplate(createMatrix(component, [ + [stepManipulationState.readOnlyDisabled], + stepLayoutStates, + selectedStates, + severityStates, + stepContentStates, + ])), + colorThemeDarkGreenBackground +); + +const interactionStates$ReadOnlyAbsent$DisabledAbsent = cartesianProduct([ + [stepManipulationState.none], stepLayoutStates, selectedStates, severityStates, [stepContentStateShort, stepContentStateStepIndicator], ] as const); +const interactionsTemplate$ReadOnlyAbsent$DisabledAbsent = createMatrixInteractionsFromStates(component, { + hover: interactionStates$ReadOnlyAbsent$DisabledAbsent, + hoverActive: interactionStates$ReadOnlyAbsent$DisabledAbsent, + active: interactionStates$ReadOnlyAbsent$DisabledAbsent, + focus: interactionStates$ReadOnlyAbsent$DisabledAbsent +}); +export const interactions$LightTheme$ReadOnlyAbsent$DisabledAbsent: StoryFn = createFixedThemeStory(interactionsTemplate$ReadOnlyAbsent$DisabledAbsent, lightThemeWhiteBackground); +export const interactions$DarkTheme$ReadOnlyAbsent$DisabledAbsent: StoryFn = createFixedThemeStory(interactionsTemplate$ReadOnlyAbsent$DisabledAbsent, darkThemeBlackBackground); +export const interactions$ColorTheme$ReadOnlyAbsent$DisabledAbsent: StoryFn = createFixedThemeStory(interactionsTemplate$ReadOnlyAbsent$DisabledAbsent, colorThemeDarkGreenBackground); -const interactionStates = cartesianProduct([ - stepManipulationStates, +const interactionStates$ReadOnlyAbsent$Disabled = cartesianProduct([ + [stepManipulationState.disabled], stepLayoutStates, selectedStates, severityStates, [stepContentStateShort, stepContentStateStepIndicator], ] as const); +const interactionsTemplate$ReadOnlyAbsent$Disabled = createMatrixInteractionsFromStates(component, { + hover: interactionStates$ReadOnlyAbsent$Disabled, + hoverActive: interactionStates$ReadOnlyAbsent$Disabled, + active: interactionStates$ReadOnlyAbsent$Disabled, + focus: interactionStates$ReadOnlyAbsent$Disabled +}); +export const interactions$LightTheme$ReadOnlyAbsent$Disabled: StoryFn = createFixedThemeStory(interactionsTemplate$ReadOnlyAbsent$Disabled, lightThemeWhiteBackground); +export const interactions$DarkTheme$ReadOnlyAbsent$Disabled: StoryFn = createFixedThemeStory(interactionsTemplate$ReadOnlyAbsent$Disabled, darkThemeBlackBackground); +export const interactions$ColorTheme$ReadOnlyAbsent$Disabled: StoryFn = createFixedThemeStory(interactionsTemplate$ReadOnlyAbsent$Disabled, colorThemeDarkGreenBackground); -const interactionsTemplate = createMatrixInteractionsFromStates(component, { - hover: interactionStatesHover, - hoverActive: interactionStates, - active: interactionStates, - focus: interactionStates +const interactionStates$ReadOnly$DisabledAbsent = cartesianProduct([ + [stepManipulationState.readOnly], + stepLayoutStates, + selectedStates, + severityStates, + [stepContentStateShort, stepContentStateStepIndicator], +] as const); +const interactionsTemplate$ReadOnly$DisabledAbsent = createMatrixInteractionsFromStates(component, { + hover: interactionStates$ReadOnly$DisabledAbsent, + hoverActive: interactionStates$ReadOnly$DisabledAbsent, + active: interactionStates$ReadOnly$DisabledAbsent, + focus: interactionStates$ReadOnly$DisabledAbsent }); +export const interactions$LightTheme$ReadOnly$DisabledAbsent: StoryFn = createFixedThemeStory(interactionsTemplate$ReadOnly$DisabledAbsent, lightThemeWhiteBackground); +export const interactions$DarkTheme$ReadOnly$DisabledAbsent: StoryFn = createFixedThemeStory(interactionsTemplate$ReadOnly$DisabledAbsent, darkThemeBlackBackground); +export const interactions$ColorTheme$ReadOnly$DisabledAbsent: StoryFn = createFixedThemeStory(interactionsTemplate$ReadOnly$DisabledAbsent, colorThemeDarkGreenBackground); -export const interactions$LightTheme: StoryFn = createFixedThemeStory(interactionsTemplate, lightThemeWhiteBackground); -export const interactions$DarkTheme: StoryFn = createFixedThemeStory(interactionsTemplate, darkThemeBlackBackground); -export const interactions$ColorTheme: StoryFn = createFixedThemeStory(interactionsTemplate, colorThemeDarkGreenBackground); +const interactionStates$ReadOnly$Disabled = cartesianProduct([ + [stepManipulationState.readOnlyDisabled], + stepLayoutStates, + selectedStates, + severityStates, + [stepContentStateShort, stepContentStateStepIndicator], +] as const); +const interactionsTemplate$ReadOnly$Disabled = createMatrixInteractionsFromStates(component, { + hover: interactionStates$ReadOnly$Disabled, + hoverActive: interactionStates$ReadOnly$Disabled, + active: interactionStates$ReadOnly$Disabled, + focus: interactionStates$ReadOnly$Disabled +}); +export const interactions$LightTheme$ReadOnly$Disabled: StoryFn = createFixedThemeStory(interactionsTemplate$ReadOnly$Disabled, lightThemeWhiteBackground); +export const interactions$DarkTheme$ReadOnly$Disabled: StoryFn = createFixedThemeStory(interactionsTemplate$ReadOnly$Disabled, darkThemeBlackBackground); +export const interactions$ColorTheme$ReadOnly$Disabled: StoryFn = createFixedThemeStory(interactionsTemplate$ReadOnly$Disabled, colorThemeDarkGreenBackground); export const hidden: StoryFn = createStory( hiddenWrapper( From 157391b0507a344dd07d4982373c4b5e56adfa4b Mon Sep 17 00:00:00 2001 From: rajsite <1588923+rajsite@users.noreply.github.com> Date: Wed, 1 Apr 2026 16:58:44 -0500 Subject: [PATCH 04/10] Readonly styles --- .../src/patterns/step/styles.ts | 47 ++++++++++++++----- 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/packages/nimble-components/src/patterns/step/styles.ts b/packages/nimble-components/src/patterns/step/styles.ts index 2fd100c8c9..5ba6d05e29 100644 --- a/packages/nimble-components/src/patterns/step/styles.ts +++ b/packages/nimble-components/src/patterns/step/styles.ts @@ -184,6 +184,7 @@ export const styles = css` :host([selected]) .control { --ni-private-step-icon-color: ${borderHoverColor}; --ni-private-step-icon-border-color: ${borderHoverColor}; + --ni-private-step-icon-border-width: 2px; --ni-private-step-icon-background-color: rgb(from ${borderHoverColor} r g b / 30%); --ni-private-step-icon-background-size: var(--ni-private-step-icon-background-none-size); --ni-private-step-line-color: ${borderHoverColor}; @@ -223,10 +224,6 @@ export const styles = css` box-shadow ${smallDelay} ease-in-out; } - :host([selected]) .icon { - --ni-private-step-icon-border-width: 2px; - } - .icon::before { content: ''; position: absolute; @@ -360,6 +357,7 @@ export const styles = css` @layer hover { .control:hover { --ni-private-step-icon-border-color: ${borderHoverColor}; + --ni-private-step-icon-border-width: 2px; --ni-private-step-icon-background-size: var(--ni-private-step-icon-background-inset-size); --ni-private-step-line-color: ${borderHoverColor}; } @@ -390,8 +388,12 @@ export const styles = css` --ni-private-step-line-color: ${borderHoverColor}; } - .control:hover .icon { - --ni-private-step-icon-border-width: 2px; + :host([readonly]) .control:hover { + --ni-private-step-icon-color: revert-layer; + --ni-private-step-icon-border-color: revert-layer; + --ni-private-step-icon-border-width: revert-layer; + --ni-private-step-icon-background-size: revert-layer; + --ni-private-step-line-color: revert-layer; } .control:hover .line { @@ -401,11 +403,16 @@ export const styles = css` .container.vertical .control:hover .line { transform: scale(2, 1); } + + :host([readonly]) .container .control:hover .line { + transform: revert-layer; + } } @layer focusVisible { .control${focusVisible} { --ni-private-step-icon-border-color: ${borderHoverColor}; + --ni-private-step-icon-border-width: 2px; --ni-private-step-icon-outline-inset-color: ${borderHoverColor}; --ni-private-step-icon-background-size: var(--ni-private-step-icon-background-inset-size); --ni-private-step-line-color: ${borderHoverColor}; @@ -441,10 +448,6 @@ export const styles = css` --ni-private-step-line-color: ${borderHoverColor}; } - .control${focusVisible} .icon { - --ni-private-step-icon-border-width: 2px; - } - .control${focusVisible} .icon::before { outline-width: ${borderWidth}; ${'' /* -1px control to outline edge -2px focus border -1px inset gap */} @@ -463,6 +466,7 @@ export const styles = css` @layer active { .control:active { --ni-private-step-icon-border-color: ${borderHoverColor}; + --ni-private-step-icon-border-width: 2px; --ni-private-step-icon-background-color: ${fillSelectedColor}; --ni-private-step-icon-background-size: var(--ni-private-step-icon-background-full-size); --ni-private-step-line-color: ${borderHoverColor}; @@ -494,8 +498,13 @@ export const styles = css` --ni-private-step-line-color: ${borderHoverColor}; } - .control:active .icon { - --ni-private-step-icon-border-width: 2px; + :host([readonly]) .control:active { + --ni-private-step-icon-color: revert-layer; + --ni-private-step-icon-border-color: revert-layer; + --ni-private-step-icon-border-width: revert-layer; + --ni-private-step-icon-background-color: revert-layer; + --ni-private-step-icon-background-size: revert-layer; + --ni-private-step-line-color: revert-layer; } .control:active .icon::before { @@ -503,17 +512,31 @@ export const styles = css` outline-offset: 0px; } + :host([readonly]) .control:active .icon::before { + outline-width: revert-layer; + outline-offset: revert-layer; + } + .control:active .line { transform: scale(1, 1); } + + :host([readonly]) .control:active .line { + transform: revert-layer; + } } @layer disabled { + :host([readonly]) .control { + cursor: default; + } + :host([disabled]) .control { cursor: default; color: ${buttonLabelDisabledFontColor}; --ni-private-step-icon-color: rgb(from ${buttonLabelFontColor} r g b / 30%); --ni-private-step-icon-border-color: transparent; + --ni-private-step-icon-border-width: 1px; --ni-private-step-icon-background-color: rgba(${borderRgbPartialColor}, 0.1); --ni-private-step-icon-background-size: var(--ni-private-step-icon-background-full-size); --ni-private-step-icon-outline-inset-color: transparent; From fa8f8cf42c8578e4a00daf3e6b1542f8d610504b Mon Sep 17 00:00:00 2001 From: rajsite <1588923+rajsite@users.noreply.github.com> Date: Wed, 1 Apr 2026 18:29:06 -0500 Subject: [PATCH 05/10] Readonly behavior tests --- .../src/anchor-step/index.ts | 2 +- .../src/anchor-step/tests/anchor-step.spec.ts | 34 +++++++++++ .../step/testing/step-base.pageobject.ts | 4 ++ .../src/patterns/step/types.ts | 6 ++ packages/nimble-components/src/step/index.ts | 2 +- .../src/step/tests/step.spec.ts | 61 +++++++++++++++---- 6 files changed, 96 insertions(+), 13 deletions(-) diff --git a/packages/nimble-components/src/anchor-step/index.ts b/packages/nimble-components/src/anchor-step/index.ts index e32ceaacd3..2db909f08c 100644 --- a/packages/nimble-components/src/anchor-step/index.ts +++ b/packages/nimble-components/src/anchor-step/index.ts @@ -67,7 +67,7 @@ export class AnchorStep extends mixinSeverityPattern(AnchorBase) implements Step * @internal */ public onClick(e: Event): void { - if (this.readOnly) { + if (this.disabled || this.readOnly) { e.preventDefault(); e.stopImmediatePropagation(); } diff --git a/packages/nimble-components/src/anchor-step/tests/anchor-step.spec.ts b/packages/nimble-components/src/anchor-step/tests/anchor-step.spec.ts index f29307f6f6..d7e529aef7 100644 --- a/packages/nimble-components/src/anchor-step/tests/anchor-step.spec.ts +++ b/packages/nimble-components/src/anchor-step/tests/anchor-step.spec.ts @@ -3,6 +3,7 @@ import { parameterizeSpec } from '@ni/jasmine-parameterized'; import { AnchorStep, anchorStepTag } from '..'; import { waitForUpdatesAsync } from '../../testing/async-helpers'; import { fixture, type Fixture } from '../../utilities/tests/fixture'; +import { AnchorStepPageObject } from '../testing/anchor-step.pageobject'; async function setup(): Promise> { return await fixture( @@ -14,9 +15,11 @@ describe('AnchorStep', () => { let element: AnchorStep; let connect: () => Promise; let disconnect: () => Promise; + let pageObject: AnchorStepPageObject; beforeEach(async () => { ({ element, connect, disconnect } = await setup()); + pageObject = new AnchorStepPageObject(element); }); afterEach(async () => { @@ -110,4 +113,35 @@ describe('AnchorStep', () => { expect(element.control!.hasAttribute('tabindex')).toBeFalse(); }); + + describe('click event', () => { + it('should fire when clicked', async () => { + const stepClicked = jasmine.createSpy(); + element.addEventListener('click', stepClicked); + await connect(); + + pageObject.click(); + expect(stepClicked.calls.count()).toEqual(1); + }); + + it('should not fire when disabled', async () => { + const stepClicked = jasmine.createSpy(); + element.addEventListener('click', stepClicked); + element.disabled = true; + await connect(); + + pageObject.click(); + expect(stepClicked.calls.count()).toEqual(0); + }); + + it('should not fire when readonly', async () => { + const stepClicked = jasmine.createSpy(); + element.addEventListener('click', stepClicked); + element.readOnly = true; + await connect(); + + pageObject.click(); + expect(stepClicked.calls.count()).toEqual(0); + }); + }); }); diff --git a/packages/nimble-components/src/patterns/step/testing/step-base.pageobject.ts b/packages/nimble-components/src/patterns/step/testing/step-base.pageobject.ts index 3ab719d3e7..8588afe417 100644 --- a/packages/nimble-components/src/patterns/step/testing/step-base.pageobject.ts +++ b/packages/nimble-components/src/patterns/step/testing/step-base.pageobject.ts @@ -42,4 +42,8 @@ export abstract class StepBasePageObject { } return label; } + + public click(): void { + this.element.control!.click(); + } } diff --git a/packages/nimble-components/src/patterns/step/types.ts b/packages/nimble-components/src/patterns/step/types.ts index bd85dc76c1..7a2d195050 100644 --- a/packages/nimble-components/src/patterns/step/types.ts +++ b/packages/nimble-components/src/patterns/step/types.ts @@ -22,4 +22,10 @@ export interface StepPattern extends SeverityPattern, HTMLElement { * @internal */ stepInternals: StepInternals; + + /** + * Primary control for interactions + * @internal + */ + control?: HTMLElement; } diff --git a/packages/nimble-components/src/step/index.ts b/packages/nimble-components/src/step/index.ts index ec7d97b2e5..c438574f22 100644 --- a/packages/nimble-components/src/step/index.ts +++ b/packages/nimble-components/src/step/index.ts @@ -62,7 +62,7 @@ export class Step extends mixinSeverityPattern(FoundationButton) implements Step * @internal */ public onClick(e: Event): void { - if (this.readOnly) { + if (this.disabled || this.readOnly) { e.preventDefault(); e.stopImmediatePropagation(); } diff --git a/packages/nimble-components/src/step/tests/step.spec.ts b/packages/nimble-components/src/step/tests/step.spec.ts index 612a0dc8c0..51b6ec7f36 100644 --- a/packages/nimble-components/src/step/tests/step.spec.ts +++ b/packages/nimble-components/src/step/tests/step.spec.ts @@ -2,41 +2,51 @@ import { html } from '@ni/fast-element'; import { Step, stepTag } from '..'; import { fixture, type Fixture } from '../../utilities/tests/fixture'; import { waitForUpdatesAsync } from '../../testing/async-helpers'; +import { StepPageObject } from '../testing/step.pageobject'; + +async function setup(): Promise> { + return await fixture( + html`<${stepTag}>` + ); +} describe('Step', () => { - async function setup(): Promise> { - return await fixture(html`<${stepTag}>`); - } + let element: Step; + let connect: () => Promise; + let disconnect: () => Promise; + let pageObject: StepPageObject; + + beforeEach(async () => { + ({ element, connect, disconnect } = await setup()); + pageObject = new StepPageObject(element); + }); + + afterEach(async () => { + await disconnect(); + }); it('can construct an element instance', () => { expect(document.createElement(stepTag)).toBeInstanceOf(Step); }); it('should default tabIndex on the internal button to 0', async () => { - const { element, connect, disconnect } = await setup(); await connect(); const innerStep = element.shadowRoot!.querySelector('button')!; expect(innerStep.getAttribute('tabindex')).toBeNull(); expect(innerStep.tabIndex).toEqual(0); - - await disconnect(); }); it('should set the `tabindex` attribute on the internal button when provided', async () => { - const { element, connect, disconnect } = await setup(); element.setAttribute('tabindex', '-1'); await connect(); const innerStep = element.shadowRoot!.querySelector('button')!; expect(innerStep.getAttribute('tabindex')).toEqual('-1'); expect(innerStep.tabIndex).toEqual(-1); - - await disconnect(); }); it('should clear the `tabindex` attribute on the internal button when cleared from the host', async () => { - const { element, connect, disconnect } = await setup(); element.setAttribute('tabindex', '-1'); await connect(); @@ -46,7 +56,36 @@ describe('Step', () => { const innerStep = element.shadowRoot!.querySelector('button')!; expect(innerStep.getAttribute('tabindex')).toBeNull(); expect(innerStep.tabIndex).toEqual(0); + }); - await disconnect(); + describe('click event', () => { + it('should fire when clicked', async () => { + const stepClicked = jasmine.createSpy(); + element.addEventListener('click', stepClicked); + await connect(); + + pageObject.click(); + expect(stepClicked.calls.count()).toEqual(1); + }); + + it('should not fire when disabled', async () => { + const stepClicked = jasmine.createSpy(); + element.addEventListener('click', stepClicked); + element.disabled = true; + await connect(); + + pageObject.click(); + expect(stepClicked.calls.count()).toEqual(0); + }); + + it('should not fire when readonly', async () => { + const stepClicked = jasmine.createSpy(); + element.addEventListener('click', stepClicked); + element.readOnly = true; + await connect(); + + pageObject.click(); + expect(stepClicked.calls.count()).toEqual(0); + }); }); }); From 55a619108847dd995d49d9716219cb248c781979 Mon Sep 17 00:00:00 2001 From: rajsite <1588923+rajsite@users.noreply.github.com> Date: Wed, 1 Apr 2026 18:30:43 -0500 Subject: [PATCH 06/10] Change file description --- ...-nimble-components-91d2c055-93d0-4d1d-96c1-f1c8366cdc9f.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/change/@ni-nimble-components-91d2c055-93d0-4d1d-96c1-f1c8366cdc9f.json b/change/@ni-nimble-components-91d2c055-93d0-4d1d-96c1-f1c8366cdc9f.json index 41f242f6d7..226cba2816 100644 --- a/change/@ni-nimble-components-91d2c055-93d0-4d1d-96c1-f1c8366cdc9f.json +++ b/change/@ni-nimble-components-91d2c055-93d0-4d1d-96c1-f1c8366cdc9f.json @@ -1,6 +1,6 @@ { "type": "patch", - "comment": "Readonly state behavior", + "comment": "Add readonly behavior to step and anchor step", "packageName": "@ni/nimble-components", "email": "1588923+rajsite@users.noreply.github.com", "dependentChangeType": "patch" From 8e3048314bcc0d186850998fd8fc8db4bbb4b71c Mon Sep 17 00:00:00 2001 From: rajsite <1588923+rajsite@users.noreply.github.com> Date: Wed, 1 Apr 2026 19:09:05 -0500 Subject: [PATCH 07/10] Add helper for interaction matrix with common states --- .../anchor-step/anchor-step-matrix.stories.ts | 195 ++++++++++++------ .../src/nimble/step/step-matrix.stories.ts | 195 ++++++++++++------ packages/storybook/src/utilities/matrix.ts | 13 ++ 3 files changed, 271 insertions(+), 132 deletions(-) diff --git a/packages/storybook/src/nimble/anchor-step/anchor-step-matrix.stories.ts b/packages/storybook/src/nimble/anchor-step/anchor-step-matrix.stories.ts index 0c7c3b2c7d..d0a3040303 100644 --- a/packages/storybook/src/nimble/anchor-step/anchor-step-matrix.stories.ts +++ b/packages/storybook/src/nimble/anchor-step/anchor-step-matrix.stories.ts @@ -7,8 +7,7 @@ import { iconCogTag } from '@ni/nimble-components/dist/esm/icons/cog'; import { createMatrix, sharedMatrixParameters, - cartesianProduct, - createMatrixInteractionsFromStates + createMatrixInteractions } from '../../utilities/matrix'; import { createFixedThemeStory, createStory } from '../../utilities/storybook'; import { hiddenWrapper } from '../../utilities/hidden'; @@ -208,73 +207,137 @@ export const matrix$ColorTheme$ReadOnly$Disabled: StoryFn = createFixedThemeStor colorThemeDarkGreenBackground ); -const interactionStates$ReadOnlyAbsent$DisabledAbsent = cartesianProduct([ - [stepManipulationState.none], - stepLayoutStates, - selectedStates, - severityStates, - [stepContentStateShort, stepContentStateStepIndicator], -] as const); -const interactionsTemplate$ReadOnlyAbsent$DisabledAbsent = createMatrixInteractionsFromStates(component, { - hover: interactionStates$ReadOnlyAbsent$DisabledAbsent, - hoverActive: interactionStates$ReadOnlyAbsent$DisabledAbsent, - active: interactionStates$ReadOnlyAbsent$DisabledAbsent, - focus: interactionStates$ReadOnlyAbsent$DisabledAbsent -}); -export const interactions$LightTheme$ReadOnlyAbsent$DisabledAbsent: StoryFn = createFixedThemeStory(interactionsTemplate$ReadOnlyAbsent$DisabledAbsent, lightThemeWhiteBackground); -export const interactions$DarkTheme$ReadOnlyAbsent$DisabledAbsent: StoryFn = createFixedThemeStory(interactionsTemplate$ReadOnlyAbsent$DisabledAbsent, darkThemeBlackBackground); -export const interactions$ColorTheme$ReadOnlyAbsent$DisabledAbsent: StoryFn = createFixedThemeStory(interactionsTemplate$ReadOnlyAbsent$DisabledAbsent, colorThemeDarkGreenBackground); +export const interactions$LightTheme$ReadOnlyAbsent$DisabledAbsent: StoryFn = createFixedThemeStory( + createMatrixInteractions(component, [ + [stepManipulationState.none], + stepLayoutStates, + selectedStates, + severityStates, + [stepContentStateShort, stepContentStateStepIndicator], + ]), + lightThemeWhiteBackground +); + +export const interactions$LightTheme$ReadOnlyAbsent$Disabled: StoryFn = createFixedThemeStory( + createMatrixInteractions(component, [ + [stepManipulationState.disabled], + stepLayoutStates, + selectedStates, + severityStates, + [stepContentStateShort, stepContentStateStepIndicator], + ]), + lightThemeWhiteBackground +); + +export const interactions$LightTheme$ReadOnly$DisabledAbsent: StoryFn = createFixedThemeStory( + createMatrixInteractions(component, [ + [stepManipulationState.readOnly], + stepLayoutStates, + selectedStates, + severityStates, + [stepContentStateShort, stepContentStateStepIndicator], + ]), + lightThemeWhiteBackground +); + +export const interactions$LightTheme$ReadOnly$Disabled: StoryFn = createFixedThemeStory( + createMatrixInteractions(component, [ + [stepManipulationState.readOnlyDisabled], + stepLayoutStates, + selectedStates, + severityStates, + [stepContentStateShort, stepContentStateStepIndicator], + ]), + lightThemeWhiteBackground +); + +export const interactions$DarkTheme$ReadOnlyAbsent$DisabledAbsent: StoryFn = createFixedThemeStory( + createMatrixInteractions(component, [ + [stepManipulationState.none], + stepLayoutStates, + selectedStates, + severityStates, + [stepContentStateShort, stepContentStateStepIndicator], + ]), + darkThemeBlackBackground +); + +export const interactions$DarkTheme$ReadOnlyAbsent$Disabled: StoryFn = createFixedThemeStory( + createMatrixInteractions(component, [ + [stepManipulationState.disabled], + stepLayoutStates, + selectedStates, + severityStates, + [stepContentStateShort, stepContentStateStepIndicator], + ]), + darkThemeBlackBackground +); + +export const interactions$DarkTheme$ReadOnly$DisabledAbsent: StoryFn = createFixedThemeStory( + createMatrixInteractions(component, [ + [stepManipulationState.readOnly], + stepLayoutStates, + selectedStates, + severityStates, + [stepContentStateShort, stepContentStateStepIndicator], + ]), + darkThemeBlackBackground +); + +export const interactions$DarkTheme$ReadOnly$Disabled: StoryFn = createFixedThemeStory( + createMatrixInteractions(component, [ + [stepManipulationState.readOnlyDisabled], + stepLayoutStates, + selectedStates, + severityStates, + [stepContentStateShort, stepContentStateStepIndicator], + ]), + darkThemeBlackBackground +); + +export const interactions$ColorTheme$ReadOnlyAbsent$DisabledAbsent: StoryFn = createFixedThemeStory( + createMatrixInteractions(component, [ + [stepManipulationState.none], + stepLayoutStates, + selectedStates, + severityStates, + [stepContentStateShort, stepContentStateStepIndicator], + ]), + colorThemeDarkGreenBackground +); -const interactionStates$ReadOnlyAbsent$Disabled = cartesianProduct([ - [stepManipulationState.disabled], - stepLayoutStates, - selectedStates, - severityStates, - [stepContentStateShort, stepContentStateStepIndicator], -] as const); -const interactionsTemplate$ReadOnlyAbsent$Disabled = createMatrixInteractionsFromStates(component, { - hover: interactionStates$ReadOnlyAbsent$Disabled, - hoverActive: interactionStates$ReadOnlyAbsent$Disabled, - active: interactionStates$ReadOnlyAbsent$Disabled, - focus: interactionStates$ReadOnlyAbsent$Disabled -}); -export const interactions$LightTheme$ReadOnlyAbsent$Disabled: StoryFn = createFixedThemeStory(interactionsTemplate$ReadOnlyAbsent$Disabled, lightThemeWhiteBackground); -export const interactions$DarkTheme$ReadOnlyAbsent$Disabled: StoryFn = createFixedThemeStory(interactionsTemplate$ReadOnlyAbsent$Disabled, darkThemeBlackBackground); -export const interactions$ColorTheme$ReadOnlyAbsent$Disabled: StoryFn = createFixedThemeStory(interactionsTemplate$ReadOnlyAbsent$Disabled, colorThemeDarkGreenBackground); +export const interactions$ColorTheme$ReadOnlyAbsent$Disabled: StoryFn = createFixedThemeStory( + createMatrixInteractions(component, [ + [stepManipulationState.disabled], + stepLayoutStates, + selectedStates, + severityStates, + [stepContentStateShort, stepContentStateStepIndicator], + ]), + colorThemeDarkGreenBackground +); -const interactionStates$ReadOnly$DisabledAbsent = cartesianProduct([ - [stepManipulationState.readOnly], - stepLayoutStates, - selectedStates, - severityStates, - [stepContentStateShort, stepContentStateStepIndicator], -] as const); -const interactionsTemplate$ReadOnly$DisabledAbsent = createMatrixInteractionsFromStates(component, { - hover: interactionStates$ReadOnly$DisabledAbsent, - hoverActive: interactionStates$ReadOnly$DisabledAbsent, - active: interactionStates$ReadOnly$DisabledAbsent, - focus: interactionStates$ReadOnly$DisabledAbsent -}); -export const interactions$LightTheme$ReadOnly$DisabledAbsent: StoryFn = createFixedThemeStory(interactionsTemplate$ReadOnly$DisabledAbsent, lightThemeWhiteBackground); -export const interactions$DarkTheme$ReadOnly$DisabledAbsent: StoryFn = createFixedThemeStory(interactionsTemplate$ReadOnly$DisabledAbsent, darkThemeBlackBackground); -export const interactions$ColorTheme$ReadOnly$DisabledAbsent: StoryFn = createFixedThemeStory(interactionsTemplate$ReadOnly$DisabledAbsent, colorThemeDarkGreenBackground); +export const interactions$ColorTheme$ReadOnly$DisabledAbsent: StoryFn = createFixedThemeStory( + createMatrixInteractions(component, [ + [stepManipulationState.readOnly], + stepLayoutStates, + selectedStates, + severityStates, + [stepContentStateShort, stepContentStateStepIndicator], + ]), + colorThemeDarkGreenBackground +); -const interactionStates$ReadOnly$Disabled = cartesianProduct([ - [stepManipulationState.readOnlyDisabled], - stepLayoutStates, - selectedStates, - severityStates, - [stepContentStateShort, stepContentStateStepIndicator], -] as const); -const interactionsTemplate$ReadOnly$Disabled = createMatrixInteractionsFromStates(component, { - hover: interactionStates$ReadOnly$Disabled, - hoverActive: interactionStates$ReadOnly$Disabled, - active: interactionStates$ReadOnly$Disabled, - focus: interactionStates$ReadOnly$Disabled -}); -export const interactions$LightTheme$ReadOnly$Disabled: StoryFn = createFixedThemeStory(interactionsTemplate$ReadOnly$Disabled, lightThemeWhiteBackground); -export const interactions$DarkTheme$ReadOnly$Disabled: StoryFn = createFixedThemeStory(interactionsTemplate$ReadOnly$Disabled, darkThemeBlackBackground); -export const interactions$ColorTheme$ReadOnly$Disabled: StoryFn = createFixedThemeStory(interactionsTemplate$ReadOnly$Disabled, colorThemeDarkGreenBackground); +export const interactions$ColorTheme$ReadOnly$Disabled: StoryFn = createFixedThemeStory( + createMatrixInteractions(component, [ + [stepManipulationState.readOnlyDisabled], + stepLayoutStates, + selectedStates, + severityStates, + [stepContentStateShort, stepContentStateStepIndicator], + ]), + colorThemeDarkGreenBackground +); export const hidden: StoryFn = createStory( hiddenWrapper( diff --git a/packages/storybook/src/nimble/step/step-matrix.stories.ts b/packages/storybook/src/nimble/step/step-matrix.stories.ts index eed7fc5d0e..2e84d42bc8 100644 --- a/packages/storybook/src/nimble/step/step-matrix.stories.ts +++ b/packages/storybook/src/nimble/step/step-matrix.stories.ts @@ -7,8 +7,7 @@ import { bodyFont, bodyFontColor } from '@ni/nimble-components/dist/esm/theme-pr import { createMatrix, sharedMatrixParameters, - cartesianProduct, - createMatrixInteractionsFromStates + createMatrixInteractions } from '../../utilities/matrix'; import { createFixedThemeStory, createStory } from '../../utilities/storybook'; import { hiddenWrapper } from '../../utilities/hidden'; @@ -208,73 +207,137 @@ export const matrix$ColorTheme$ReadOnly$Disabled: StoryFn = createFixedThemeStor colorThemeDarkGreenBackground ); -const interactionStates$ReadOnlyAbsent$DisabledAbsent = cartesianProduct([ - [stepManipulationState.none], - stepLayoutStates, - selectedStates, - severityStates, - [stepContentStateShort, stepContentStateStepIndicator], -] as const); -const interactionsTemplate$ReadOnlyAbsent$DisabledAbsent = createMatrixInteractionsFromStates(component, { - hover: interactionStates$ReadOnlyAbsent$DisabledAbsent, - hoverActive: interactionStates$ReadOnlyAbsent$DisabledAbsent, - active: interactionStates$ReadOnlyAbsent$DisabledAbsent, - focus: interactionStates$ReadOnlyAbsent$DisabledAbsent -}); -export const interactions$LightTheme$ReadOnlyAbsent$DisabledAbsent: StoryFn = createFixedThemeStory(interactionsTemplate$ReadOnlyAbsent$DisabledAbsent, lightThemeWhiteBackground); -export const interactions$DarkTheme$ReadOnlyAbsent$DisabledAbsent: StoryFn = createFixedThemeStory(interactionsTemplate$ReadOnlyAbsent$DisabledAbsent, darkThemeBlackBackground); -export const interactions$ColorTheme$ReadOnlyAbsent$DisabledAbsent: StoryFn = createFixedThemeStory(interactionsTemplate$ReadOnlyAbsent$DisabledAbsent, colorThemeDarkGreenBackground); +export const interactions$LightTheme$ReadOnlyAbsent$DisabledAbsent: StoryFn = createFixedThemeStory( + createMatrixInteractions(component, [ + [stepManipulationState.none], + stepLayoutStates, + selectedStates, + severityStates, + [stepContentStateShort, stepContentStateStepIndicator], + ]), + lightThemeWhiteBackground +); + +export const interactions$LightTheme$ReadOnlyAbsent$Disabled: StoryFn = createFixedThemeStory( + createMatrixInteractions(component, [ + [stepManipulationState.disabled], + stepLayoutStates, + selectedStates, + severityStates, + [stepContentStateShort, stepContentStateStepIndicator], + ]), + lightThemeWhiteBackground +); + +export const interactions$LightTheme$ReadOnly$DisabledAbsent: StoryFn = createFixedThemeStory( + createMatrixInteractions(component, [ + [stepManipulationState.readOnly], + stepLayoutStates, + selectedStates, + severityStates, + [stepContentStateShort, stepContentStateStepIndicator], + ]), + lightThemeWhiteBackground +); + +export const interactions$LightTheme$ReadOnly$Disabled: StoryFn = createFixedThemeStory( + createMatrixInteractions(component, [ + [stepManipulationState.readOnlyDisabled], + stepLayoutStates, + selectedStates, + severityStates, + [stepContentStateShort, stepContentStateStepIndicator], + ]), + lightThemeWhiteBackground +); + +export const interactions$DarkTheme$ReadOnlyAbsent$DisabledAbsent: StoryFn = createFixedThemeStory( + createMatrixInteractions(component, [ + [stepManipulationState.none], + stepLayoutStates, + selectedStates, + severityStates, + [stepContentStateShort, stepContentStateStepIndicator], + ]), + darkThemeBlackBackground +); + +export const interactions$DarkTheme$ReadOnlyAbsent$Disabled: StoryFn = createFixedThemeStory( + createMatrixInteractions(component, [ + [stepManipulationState.disabled], + stepLayoutStates, + selectedStates, + severityStates, + [stepContentStateShort, stepContentStateStepIndicator], + ]), + darkThemeBlackBackground +); + +export const interactions$DarkTheme$ReadOnly$DisabledAbsent: StoryFn = createFixedThemeStory( + createMatrixInteractions(component, [ + [stepManipulationState.readOnly], + stepLayoutStates, + selectedStates, + severityStates, + [stepContentStateShort, stepContentStateStepIndicator], + ]), + darkThemeBlackBackground +); + +export const interactions$DarkTheme$ReadOnly$Disabled: StoryFn = createFixedThemeStory( + createMatrixInteractions(component, [ + [stepManipulationState.readOnlyDisabled], + stepLayoutStates, + selectedStates, + severityStates, + [stepContentStateShort, stepContentStateStepIndicator], + ]), + darkThemeBlackBackground +); + +export const interactions$ColorTheme$ReadOnlyAbsent$DisabledAbsent: StoryFn = createFixedThemeStory( + createMatrixInteractions(component, [ + [stepManipulationState.none], + stepLayoutStates, + selectedStates, + severityStates, + [stepContentStateShort, stepContentStateStepIndicator], + ]), + colorThemeDarkGreenBackground +); -const interactionStates$ReadOnlyAbsent$Disabled = cartesianProduct([ - [stepManipulationState.disabled], - stepLayoutStates, - selectedStates, - severityStates, - [stepContentStateShort, stepContentStateStepIndicator], -] as const); -const interactionsTemplate$ReadOnlyAbsent$Disabled = createMatrixInteractionsFromStates(component, { - hover: interactionStates$ReadOnlyAbsent$Disabled, - hoverActive: interactionStates$ReadOnlyAbsent$Disabled, - active: interactionStates$ReadOnlyAbsent$Disabled, - focus: interactionStates$ReadOnlyAbsent$Disabled -}); -export const interactions$LightTheme$ReadOnlyAbsent$Disabled: StoryFn = createFixedThemeStory(interactionsTemplate$ReadOnlyAbsent$Disabled, lightThemeWhiteBackground); -export const interactions$DarkTheme$ReadOnlyAbsent$Disabled: StoryFn = createFixedThemeStory(interactionsTemplate$ReadOnlyAbsent$Disabled, darkThemeBlackBackground); -export const interactions$ColorTheme$ReadOnlyAbsent$Disabled: StoryFn = createFixedThemeStory(interactionsTemplate$ReadOnlyAbsent$Disabled, colorThemeDarkGreenBackground); +export const interactions$ColorTheme$ReadOnlyAbsent$Disabled: StoryFn = createFixedThemeStory( + createMatrixInteractions(component, [ + [stepManipulationState.disabled], + stepLayoutStates, + selectedStates, + severityStates, + [stepContentStateShort, stepContentStateStepIndicator], + ]), + colorThemeDarkGreenBackground +); -const interactionStates$ReadOnly$DisabledAbsent = cartesianProduct([ - [stepManipulationState.readOnly], - stepLayoutStates, - selectedStates, - severityStates, - [stepContentStateShort, stepContentStateStepIndicator], -] as const); -const interactionsTemplate$ReadOnly$DisabledAbsent = createMatrixInteractionsFromStates(component, { - hover: interactionStates$ReadOnly$DisabledAbsent, - hoverActive: interactionStates$ReadOnly$DisabledAbsent, - active: interactionStates$ReadOnly$DisabledAbsent, - focus: interactionStates$ReadOnly$DisabledAbsent -}); -export const interactions$LightTheme$ReadOnly$DisabledAbsent: StoryFn = createFixedThemeStory(interactionsTemplate$ReadOnly$DisabledAbsent, lightThemeWhiteBackground); -export const interactions$DarkTheme$ReadOnly$DisabledAbsent: StoryFn = createFixedThemeStory(interactionsTemplate$ReadOnly$DisabledAbsent, darkThemeBlackBackground); -export const interactions$ColorTheme$ReadOnly$DisabledAbsent: StoryFn = createFixedThemeStory(interactionsTemplate$ReadOnly$DisabledAbsent, colorThemeDarkGreenBackground); +export const interactions$ColorTheme$ReadOnly$DisabledAbsent: StoryFn = createFixedThemeStory( + createMatrixInteractions(component, [ + [stepManipulationState.readOnly], + stepLayoutStates, + selectedStates, + severityStates, + [stepContentStateShort, stepContentStateStepIndicator], + ]), + colorThemeDarkGreenBackground +); -const interactionStates$ReadOnly$Disabled = cartesianProduct([ - [stepManipulationState.readOnlyDisabled], - stepLayoutStates, - selectedStates, - severityStates, - [stepContentStateShort, stepContentStateStepIndicator], -] as const); -const interactionsTemplate$ReadOnly$Disabled = createMatrixInteractionsFromStates(component, { - hover: interactionStates$ReadOnly$Disabled, - hoverActive: interactionStates$ReadOnly$Disabled, - active: interactionStates$ReadOnly$Disabled, - focus: interactionStates$ReadOnly$Disabled -}); -export const interactions$LightTheme$ReadOnly$Disabled: StoryFn = createFixedThemeStory(interactionsTemplate$ReadOnly$Disabled, lightThemeWhiteBackground); -export const interactions$DarkTheme$ReadOnly$Disabled: StoryFn = createFixedThemeStory(interactionsTemplate$ReadOnly$Disabled, darkThemeBlackBackground); -export const interactions$ColorTheme$ReadOnly$Disabled: StoryFn = createFixedThemeStory(interactionsTemplate$ReadOnly$Disabled, colorThemeDarkGreenBackground); +export const interactions$ColorTheme$ReadOnly$Disabled: StoryFn = createFixedThemeStory( + createMatrixInteractions(component, [ + [stepManipulationState.readOnlyDisabled], + stepLayoutStates, + selectedStates, + severityStates, + [stepContentStateShort, stepContentStateStepIndicator], + ]), + colorThemeDarkGreenBackground +); export const hidden: StoryFn = createStory( hiddenWrapper( diff --git a/packages/storybook/src/utilities/matrix.ts b/packages/storybook/src/utilities/matrix.ts index 6ed26806b1..e800f0ef8d 100644 --- a/packages/storybook/src/utilities/matrix.ts +++ b/packages/storybook/src/utilities/matrix.ts @@ -105,6 +105,19 @@ export const createMatrixThemeStory = ( }; }; +export function createMatrixInteractions( + component: (...states: T) => ViewTemplate, + dimensions?: MakeTupleEntriesArrays +): ViewTemplate { + const states = cartesianProduct(dimensions); + return createMatrixInteractionsFromStates(component, { + hover: states, + hoverActive: states, + active: states, + focus: states + }); +} + export function createMatrixInteractionsFromStates< THover extends readonly unknown[], THoverActive extends readonly unknown[], From 4d8bbd61032232a0a5396fbc271d18a5b660f27c Mon Sep 17 00:00:00 2001 From: rajsite <1588923+rajsite@users.noreply.github.com> Date: Thu, 2 Apr 2026 13:19:25 -0500 Subject: [PATCH 08/10] Prevent outline offset animation flicker --- packages/nimble-components/src/patterns/step/styles.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/nimble-components/src/patterns/step/styles.ts b/packages/nimble-components/src/patterns/step/styles.ts index 5ba6d05e29..240f074cb4 100644 --- a/packages/nimble-components/src/patterns/step/styles.ts +++ b/packages/nimble-components/src/patterns/step/styles.ts @@ -233,7 +233,8 @@ export const styles = css` outline-color: var(--ni-private-step-icon-outline-inset-color); outline-style: solid; outline-width: 0px; - outline-offset: 0px; + ${'' /* outline-offset should always be <=-1 to always render inset */} + outline-offset: -1px; border: none; border-radius: 100%; color: transparent; @@ -509,7 +510,7 @@ export const styles = css` .control:active .icon::before { outline-width: 0px; - outline-offset: 0px; + outline-offset: -1px; } :host([readonly]) .control:active .icon::before { From d619c5f5206fac07883f3bb072de888eb169581e Mon Sep 17 00:00:00 2001 From: rajsite <1588923+rajsite@users.noreply.github.com> Date: Thu, 2 Apr 2026 15:20:54 -0500 Subject: [PATCH 09/10] tweak ordering --- packages/nimble-components/src/patterns/step/styles.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/nimble-components/src/patterns/step/styles.ts b/packages/nimble-components/src/patterns/step/styles.ts index 240f074cb4..9660196afb 100644 --- a/packages/nimble-components/src/patterns/step/styles.ts +++ b/packages/nimble-components/src/patterns/step/styles.ts @@ -312,9 +312,9 @@ export const styles = css` min-width: ${standardPadding}; height: 1px; min-height: 1px; + transform: scale(1, 1); background: var(--ni-private-step-line-color); background-clip: content-box; - transform: scale(1, 1); transition: background-color ${smallDelay} ease-in-out, transform ${smallDelay} ease-in-out; @@ -328,8 +328,8 @@ export const styles = css` width: 1px; min-width: 1px; height: 100%; - padding-top: ${smallPadding}; min-height: ${standardPadding}; + padding-top: ${smallPadding}; } .subtitle { From f3d72e4e0685abea2ff5e14512569e5e7a55c223 Mon Sep 17 00:00:00 2001 From: rajsite <1588923+rajsite@users.noreply.github.com> Date: Thu, 2 Apr 2026 16:01:10 -0500 Subject: [PATCH 10/10] Update readonly description --- packages/storybook/src/utilities/storybook.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/storybook/src/utilities/storybook.ts b/packages/storybook/src/utilities/storybook.ts index df60115070..59d2bb0e19 100644 --- a/packages/storybook/src/utilities/storybook.ts +++ b/packages/storybook/src/utilities/storybook.ts @@ -191,10 +191,10 @@ export const fullBleedDescription = (options: { export const iconDescription = 'Set `slot="start"` to include an icon before the text content.'; export const disabledDescription = (options: { componentName: string -}): string => `Styles the ${options.componentName} as disabled and prevents focus and user interaction.`; +}): string => `Styles the ${options.componentName} as disabled and prevents focus and user interactions.`; export const readonlyDescription = (options: { componentName: string -}): string => `Styles the ${options.componentName} as readonly and prevents the user from changing the value.`; +}): string => `Styles the ${options.componentName} as readonly and allows focus but prevents other interactions.`; export const appearanceReadOnlyDescription = (options: { componentName: string }): string => `Styles the ${options.componentName} as readonly when the component is disabled. This is useful for applications that use a forms library that sets \`disabled\` on components but don't want those components to have a disabled appearance. This property has no impact on the control when it is not disabled.`;