@nysds/components 1.18.0 → 1.18.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,15 +9,6 @@
9
9
  * - Alias references become var() expressions
10
10
  * - Layer prefixes (primitive, applied) are stripped
11
11
  */
12
- /**
13
- * Legacy interface for backward compatibility
14
- */
15
- export interface DesignToken {
16
- name: string;
17
- value: string;
18
- category: string;
19
- description?: string;
20
- }
21
12
  /**
22
13
  * CSS-centric token info aligned with tokens.css output
23
14
  */
@@ -47,10 +38,6 @@ export interface TokenGraphNode {
47
38
  referencesVariable?: string;
48
39
  usedBy: string[];
49
40
  }
50
- export interface TokenGroup {
51
- category: string;
52
- tokens: DesignToken[];
53
- }
54
41
  /**
55
42
  * Get the path to tokens.json file
56
43
  * Uses ESM-compatible path resolution with fallbacks for different contexts
@@ -94,14 +81,6 @@ export declare function getCSSTokens(): CSSTokenInfo[];
94
81
  * Get CSS tokens filtered by category
95
82
  */
96
83
  export declare function getCSSTokensByCategory(category: string): CSSTokenInfo[];
97
- /**
98
- * Get CSS tokens filtered by layer
99
- */
100
- export declare function getCSSTokensByLayer(layer: string): CSSTokenInfo[];
101
- /**
102
- * Search CSS tokens by variable name, value, or description
103
- */
104
- export declare function searchCSSTokens(query: string): CSSTokenInfo[];
105
84
  /**
106
85
  * Get a single token by CSS variable name
107
86
  */
@@ -118,21 +97,30 @@ export declare function getCSSTokenCategories(): {
118
97
  */
119
98
  export declare function getTokensCSS(): string | null;
120
99
  /**
121
- * Load all design tokens (legacy format)
122
- */
123
- export declare function getAllTokens(): DesignToken[];
124
- /**
125
- * Get tokens filtered by category (legacy format)
100
+ * Get recommended tokens for everyday use.
101
+ *
102
+ * Excludes color primitive tokens (the ~150 palette ramps like neutral-*, red-*,
103
+ * blue-*) which are low-level raw values. For font tokens, applied aliases
104
+ * (body-*, h*, ui-*) are sorted before primitives so the most useful tokens
105
+ * appear first.
126
106
  */
127
- export declare function getTokensByCategory(category: string): DesignToken[];
107
+ export declare function getRecommendedTokens(): CSSTokenInfo[];
128
108
  /**
129
- * Search tokens by name or value (legacy format)
109
+ * Get only primitive (raw value) tokens across all categories.
130
110
  */
131
- export declare function searchTokens(query: string): DesignToken[];
111
+ export declare function getPrimitiveTokens(): CSSTokenInfo[];
132
112
  /**
133
- * Get available token categories (legacy format)
113
+ * Get alternative tokens in the same category that share the same name prefix.
114
+ *
115
+ * First looks for child variants (tokens starting with this token's name + "-"):
116
+ * --nys-color-text → finds --nys-color-text-weak, --nys-color-text-reverse, etc.
117
+ *
118
+ * If no children exist, looks for siblings (tokens sharing the same parent prefix):
119
+ * --nys-color-text-weak → parent: --nys-color-text → finds text, text-weaker, etc.
120
+ *
121
+ * Returns an array of cssVariable strings (empty if none found).
134
122
  */
135
- export declare function getTokenCategories(): string[];
123
+ export declare function getAlternativeTokens(token: CSSTokenInfo): string[];
136
124
  /**
137
125
  * Clear all cached tokens (useful for testing)
138
126
  */
@@ -4,9 +4,8 @@
4
4
  * MCP tools for working with NYSDS design tokens.
5
5
  *
6
6
  * Tools:
7
- * - get_tokens: Get tokens, categories, or themes
8
- * - find_tokens: Search tokens by CSS variable, value, or description
9
- * - get_token_info: Get detailed token info with optional context validation
7
+ * - find_tokens: Search or browse tokens (discovery)
8
+ * - get_token: Get full details for a specific token (deep dive)
10
9
  * - get_token_graph: Get token dependency graph
11
10
  */
12
11
  import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
@@ -51,6 +51,8 @@ export declare class NysAvatar extends LitElement {
51
51
  * Functions
52
52
  * --------------------------------------------------------------------------
53
53
  */
54
+ private get _cleanAriaLabel();
55
+ private _colorStyle;
54
56
  /**
55
57
  * Computes the appropriate foreground color (icon or initials)
56
58
  * based on the avatar's background color for sufficient contrast.
@@ -9,9 +9,9 @@ import { LitElement } from "lit";
9
9
  * If no footer exists, place at the bottom of the body tag (after main content). Floating
10
10
  * positioning allows it to overlay content without taking up layout space.
11
11
  *
12
- * **Focus Management:** When clicked, after scrolling to the top, focus is automatically moved
13
- * to the `<main>` element (if present), the first heading (`<h1>` or `<h2>`), or the document element.
14
- * This ensures keyboard navigation continues naturally from the top of the page.
12
+ * **Focus Management:** When clicked, after scrolling to the top, focus is moved to `<body>`.
13
+ * This places the user before the skip-navigation link so they can re-use it to jump directly
14
+ * back to main content and works regardless of whether the page uses `<main>` or heading landmarks.
15
15
  *
16
16
  * @summary Floating back-to-top button with auto-show behavior, smooth scroll, and focus management.
17
17
  * @element nys-backtotop
@@ -181,6 +181,7 @@ export declare class NysButton extends LitElement {
181
181
  private _handleBlur;
182
182
  private _handleClick;
183
183
  private _handleKeydown;
184
+ private _handleKeyup;
184
185
  /**
185
186
  * A Solution to the Vanilla JS & Native HTML keydown:
186
187
  *
@@ -75,6 +75,7 @@ export declare class NysCheckbox extends LitElement {
75
75
  size: "sm" | "md";
76
76
  other: boolean;
77
77
  showOtherError: boolean;
78
+ private _mobileQuery;
78
79
  private isMobile;
79
80
  private _hasUserInteracted;
80
81
  getInputElement(): Promise<HTMLInputElement | null>;
@@ -105,11 +106,11 @@ export declare class NysCheckbox extends LitElement {
105
106
  private _handleInvalid;
106
107
  private _manageLabelClick;
107
108
  get _hasDescription(): boolean;
108
- private _handleResize;
109
109
  /**
110
110
  * Event Handlers
111
111
  * --------------------------------------------------------------------------
112
112
  */
113
+ private _handleMobileQuery;
113
114
  private _emitChangeEvent;
114
115
  private _emitOtherInputEvent;
115
116
  private _handleChange;
@@ -40,6 +40,7 @@ export declare class NysDropdownMenu extends LitElement {
40
40
  private _ariaTarget;
41
41
  private _lastFocusedIndex;
42
42
  private readonly GAP;
43
+ private _resizeObserver;
43
44
  /**
44
45
  * Lifecycle Methods
45
46
  * --------------------------------------------------------------------------
@@ -105,7 +106,6 @@ export declare class NysDropdownMenu extends LitElement {
105
106
  private _handleMenuClick;
106
107
  private _handleTriggerKeydown;
107
108
  private _handleMenuKeydown;
108
- private _handleWindowResize;
109
109
  private _handleWindowScroll;
110
110
  render(): import("lit-html").TemplateResult<1>;
111
111
  }
@@ -36,6 +36,7 @@ export declare class NysGlobalHeader extends LitElement {
36
36
  * --------------------------------------------------------------------------
37
37
  */
38
38
  firstUpdated(): void;
39
+ disconnectedCallback(): void;
39
40
  /**
40
41
  * Functions
41
42
  * --------------------------------------------------------------------------
@@ -47,5 +48,7 @@ export declare class NysGlobalHeader extends LitElement {
47
48
  private _listenLinkClicks;
48
49
  private _renderBrandMark;
49
50
  private _getNysLogo;
51
+ private _boundClickOutside;
52
+ private _boundKeyDown;
50
53
  render(): import("lit-html").TemplateResult<1>;
51
54
  }
@@ -45,6 +45,7 @@ export declare class NysModal extends LitElement {
45
45
  private _actionButtonSlot;
46
46
  private _prevFocusedElement;
47
47
  private _originalBodyOverflow;
48
+ private _mobileMedia;
48
49
  private hasBodySlots;
49
50
  private hasActionSlots;
50
51
  /**
@@ -2,27 +2,55 @@ import { LitElement } from "lit";
2
2
  /**
3
3
  * A single step within `nys-stepper`. Represents one stage in a multi-step process.
4
4
  *
5
- * Mark as `current` to indicate active progress point. Previous steps become clickable for navigation.
6
- * Set `href` for page-based navigation or listen to `nys-step-click` for SPA routing.
5
+ * Mark as `current` to indicate the active progress point. Previous steps become clickable for navigation.
6
+ * Set `href` for page-based navigation, or omit it and listen to `nys-step-click` for SPA/framework routing.
7
7
  *
8
- * ## Step States
8
+ * ## Step states
9
9
  *
10
- * Understanding the three step states is critical for proper stepper usage:
10
+ * Three boolean attributes control step appearance and behavior:
11
11
  *
12
- * - **`selected`** - Which step is currently being displayed/viewed. This controls which step's
13
- * content is shown. Defaults to `current` if not set. Cannot be set on a step after `current`.
14
- * Users can click previous steps to change `selected` without changing `current`.
12
+ * - **`current`** The furthest step the user has reached (the progress boundary). Only one step should
13
+ * have `current` at a time; if multiple are set the parent stepper keeps the first and removes the rest.
14
+ * Steps after `current` are not navigable and do not fire `nys-step-click`. Update `current` in your
15
+ * application state when the user advances.
15
16
  *
16
- * - **`current`** - The furthest step the user has reached. This is the progress boundary.
17
- * Update this as the user completes steps and advances. Steps after `current` are not navigable.
18
- * Only one step should have `current` at a time.
17
+ * - **`selected`** Which step's content is currently displayed. Defaults to the `current` step if not
18
+ * explicitly set. If `selected` is placed on a step after `current`, the stepper silently corrects it
19
+ * to match `current`. When managing state from a framework, always set `selected` explicitly without
20
+ * it the stepper's fallback will reset in-sidebar navigation on every state update.
19
21
  *
20
- * - **`previous`** - Auto-applied by the stepper to all steps before `current`. Do not set manually.
21
- * Steps with `previous` are clickable and allow the user to navigate back.
22
+ * - **`previous`** Auto-applied by the parent stepper to every step before `current`. Do not set this
23
+ * manually. Steps with `previous` are clickable and fire `nys-step-click`.
22
24
  *
23
- * ## Common Patterns
25
+ * ## `nys-step-click` firing conditions
24
26
  *
25
- * **Initial state:** Set `current` on the first step. `selected` will default to it.
27
+ * The event fires only when ALL of the following are true:
28
+ * 1. The step has `previous` or `current` (i.e. it is navigable).
29
+ * 2. The step does NOT already have `selected` (clicking the already-viewed step is a no-op).
30
+ *
31
+ * Steps that are neither `previous` nor `current` (future steps) never fire the event.
32
+ *
33
+ * ## `href` and navigation
34
+ *
35
+ * If `href` is set, the stepper calls `window.location.href = href` after dispatching `nys-step-click`
36
+ * — but only if the event was **not canceled**. To handle navigation yourself (SPA routing, fetch, etc.),
37
+ * always call `e.preventDefault()` in your listener. Omitting `href` entirely is simpler for SPAs.
38
+ *
39
+ * ## `onClick` vs `nys-step-click`
40
+ *
41
+ * The `onClick` property (a function reference, not a DOM attribute) is called **before** the
42
+ * `nys-step-click` event is dispatched. Use it for imperative pre-navigation logic. In React, pass it
43
+ * as the `onClick` prop on `NysStep`.
44
+ *
45
+ * ## Accessibility
46
+ * - The step label renders with `role="button"` and is keyboard-focusable (`tabindex="0"`) for navigable
47
+ * steps (`current`, `previous`). Future steps get `tabindex="-1"` and are not reachable by keyboard.
48
+ * - Enter and Space activate the step (same as click).
49
+ * - `aria-label` is set to `"{label} Step"` for screen reader announcement.
50
+ *
51
+ * ## Common patterns
52
+ *
53
+ * **Initial state:** Set `current` on the first step. `selected` defaults to it.
26
54
  * ```html
27
55
  * <nys-step label="Step 1" current></nys-step>
28
56
  * <nys-step label="Step 2"></nys-step>
@@ -34,7 +62,7 @@ import { LitElement } from "lit";
34
62
  * <nys-step label="Step 2" current></nys-step>
35
63
  * ```
36
64
  *
37
- * **User went back to review step 1 (but progress is still at step 2):**
65
+ * **User went back to review step 1 (progress still at step 2):**
38
66
  * ```html
39
67
  * <nys-step label="Step 1" selected></nys-step>
40
68
  * <nys-step label="Step 2" current></nys-step>
@@ -43,28 +71,52 @@ import { LitElement } from "lit";
43
71
  * @summary Individual step for use within nys-stepper with navigation support.
44
72
  * @element nys-step
45
73
  *
46
- * @fires nys-step-click - Fired when a navigable step is clicked. Detail: `{href, label}`. Cancelable.
74
+ * @fires nys-step-click - Fired when a navigable (`previous` or `current`) non-selected step is clicked
75
+ * or activated by keyboard. Detail: `{ href: string, label: string }`. Cancelable — call
76
+ * `e.preventDefault()` to suppress `window.location.href` navigation.
47
77
  *
48
- * @example Step with navigation
78
+ * @example Step with page navigation
49
79
  * ```html
50
80
  * <nys-step label="Personal Info" href="/step-1"></nys-step>
51
81
  * ```
82
+ *
83
+ * @example Step with SPA navigation (no href)
84
+ * ```js
85
+ * step.addEventListener('nys-step-click', (e) => {
86
+ * e.preventDefault(); // no href set, but good practice
87
+ * showStepContent(e.detail.label);
88
+ * });
89
+ * ```
52
90
  */
53
91
  export declare class NysStep extends LitElement {
54
92
  static styles: import("lit").CSSResult;
55
- /** Whether this step is currently being viewed. Set by parent stepper. */
93
+ /**
94
+ * Which step is currently being displayed. If not set, defaults to the `current` step.
95
+ * Setting this on a step after `current` is silently corrected to match `current`.
96
+ * When controlling state from a framework, always set this explicitly.
97
+ */
56
98
  selected: boolean;
57
- /** Marks the furthest reached step. Steps before this are navigable. */
99
+ /** The furthest step the user has reached (progress boundary). Steps before this are navigable. */
58
100
  current: boolean;
59
101
  /** Step label text displayed alongside the step number. */
60
102
  label: string;
61
- /** URL for page navigation when step is clicked. Optional for SPA routing. */
103
+ /**
104
+ * URL navigated to when the step is activated, via `window.location.href`.
105
+ * Navigation is suppressed if the `nys-step-click` listener calls `e.preventDefault()`.
106
+ * Omit for SPA/framework routing and handle navigation in the event listener instead.
107
+ */
62
108
  href: string;
63
- /** Internal: Whether parent stepper's compact view is expanded. */
109
+ /**
110
+ * @internal Auto-applied by `nys-stepper` to every step that comes before `current`.
111
+ * Marks the step as navigable and clickable. Do not set this manually — the parent stepper
112
+ * adds and removes it on every render based on which step has `current`.
113
+ */
114
+ previous: boolean;
115
+ /** @internal Propagated by the parent stepper. Do not set manually. */
64
116
  isCompactExpanded: boolean;
65
- /** Custom click handler. Called before `nys-step-click` event. */
117
+ /** Optional function called before `nys-step-click` is dispatched. Use for pre-navigation logic. */
66
118
  onClick?: (e: Event) => void;
67
- /** Step number (1-indexed). Auto-assigned by parent stepper. */
119
+ /** @internal 1-indexed position. Auto-assigned by the parent stepper on first render. Do not set manually. */
68
120
  stepNumber: number;
69
121
  private _handleActivate;
70
122
  private _handleKeydown;
@@ -3,15 +3,50 @@ import "./nys-step";
3
3
  /**
4
4
  * A multi-step progress indicator for forms or wizards. Manages `nys-step` children with selection and navigation.
5
5
  *
6
- * Add `nys-step` elements as children. Mark one step as `current` to indicate progress; previous steps become
7
- * navigable. Compact view on mobile expands to show all steps. Use `actions` slot for navigation buttons.
8
- * Do not place the stepper inside a form element.
6
+ * Add `nys-step` elements as children. Mark one step as `current` to indicate the progress boundary; all steps
7
+ * before it become navigable. Compact view on mobile expands to show all steps. Use the `actions` slot for
8
+ * persistent navigation buttons (e.g., Save & Exit). Do not place the stepper inside a `<form>` element
9
+ * put form fields in the main content area alongside it.
10
+ *
11
+ * ## When to use
12
+ * - Linear, ordered forms or wizards with more than 2 sections.
13
+ *
14
+ * ## When not to use
15
+ * - Forms with only 1 or 2 sections — use a simpler layout.
16
+ * - Non-linear forms where sections can be completed in any order.
17
+ *
18
+ * ## Compact mode (mobile)
19
+ * On small screens the stepper collapses to a compact view: step labels are hidden and progress
20
+ * is shown as a bar indicator with a "Step x of y" counter. Clicking or pressing Enter/Space on
21
+ * the counter expands the full step list (counter text changes to "Back to Form"). Collapsing
22
+ * again returns the user to the form view.
23
+ *
24
+ * ## actions slot constraints
25
+ * The `actions` slot must contain exactly one `<div>` as its direct child. That `<div>` may only
26
+ * contain `<nys-button>` elements — any other element is removed with a console warning.
27
+ * The stepper automatically forces `size="sm"` on every button in the slot. Buttons with the
28
+ * `fullWidth` attribute get `flex: 1 1 0` injected so they share available width equally.
29
+ *
30
+ * ## Multiple `current` conflict
31
+ * If more than one `nys-step` has the `current` attribute, only the first one is kept; the rest
32
+ * are silently removed. Always mark exactly one step as `current`.
33
+ *
34
+ * ## id auto-generation
35
+ * If no `id` is provided, a unique id is generated automatically in the form
36
+ * `nys-stepper-{n}-{timestamp}`.
37
+ *
38
+ * ## Accessibility
39
+ * - The compact counter is rendered as a `role="button"` with `aria-expanded` and a descriptive
40
+ * `aria-label` that announces the current step (e.g., "Expand step navigation. You are on Step 2 of 4").
41
+ * - Keyboard: Enter or Space toggles the compact view.
42
+ * - Each `nys-step` label is keyboard-focusable and activatable for navigable steps.
43
+ * - Visual focus indicators are provided on all interactive elements.
9
44
  *
10
45
  * @summary Multi-step progress indicator with navigation and mobile-friendly compact view.
11
46
  * @element nys-stepper
12
47
  *
13
- * @slot - Default slot for `nys-step` elements.
14
- * @slot actions - Navigation buttons (e.g., Back, Continue). Must be wrapped in a `<div>`.
48
+ * @slot - Default slot for `nys-step` elements. Only `nys-step` children are accepted; others are removed.
49
+ * @slot actions - Persistent navigation buttons. Must contain exactly one `<div>` wrapping only `<nys-button>` elements.
15
50
  *
16
51
  * @example Basic stepper
17
52
  * ```html
@@ -58,18 +93,55 @@ import "./nys-step";
58
93
  * </div>
59
94
  * </nys-stepper>
60
95
  * ```
96
+ *
97
+ * @example SPA / programmatic navigation
98
+ * Two state variables drive the stepper in any framework or vanilla JS:
99
+ * - `currentStep` (progress boundary) → set `current` on the matching step
100
+ * - `viewingStep` (displayed content) → set `selected` on the matching step
101
+ *
102
+ * Always set both explicitly. Always call `e.preventDefault()` in the
103
+ * `nys-step-click` listener to suppress href navigation. Do NOT nest inside a
104
+ * `<form>` element.
105
+ * ```js
106
+ * let currentStep = 0; // furthest reached
107
+ * let viewingStep = 0; // currently displayed
108
+ *
109
+ * function updateStepper(steps) {
110
+ * steps.forEach((step, i) => {
111
+ * step.toggleAttribute('current', i === currentStep);
112
+ * step.toggleAttribute('selected', i === viewingStep);
113
+ * });
114
+ * }
115
+ *
116
+ * document.querySelector('nys-stepper').addEventListener('nys-step-click', (e) => {
117
+ * e.preventDefault();
118
+ * const steps = Array.from(document.querySelectorAll('nys-step'));
119
+ * const clicked = e.composedPath().find(el => el.tagName?.toLowerCase() === 'nys-step');
120
+ * const index = steps.indexOf(clicked);
121
+ * if (index !== -1) { viewingStep = index; updateStepper(steps); }
122
+ * });
123
+ *
124
+ * // Advance to next step (call on form submit / "Continue" click)
125
+ * function advance(steps) {
126
+ * if (currentStep < steps.length - 1) {
127
+ * currentStep++;
128
+ * viewingStep = currentStep;
129
+ * updateStepper(steps);
130
+ * }
131
+ * }
132
+ * ```
61
133
  */
62
134
  export declare class NysStepper extends LitElement {
63
135
  static styles: import("lit").CSSResult;
64
- /** Unique identifier. */
136
+ /** Unique identifier. Auto-generated as `nys-stepper-{n}-{timestamp}` if not provided. */
65
137
  id: string;
66
138
  /** Name attribute for form association. */
67
139
  name: string;
68
- /** Title displayed above the step counter. */
140
+ /** Title displayed above the step list and compact counter. */
69
141
  label: string;
70
- /** Progress text (e.g., "Step 2 of 5"). Auto-updated based on selection. */
142
+ /** Progress text displayed in compact mode (e.g., "Step 2 of 5"). Auto-managed do not set manually. */
71
143
  counterText: string;
72
- /** Whether compact mobile view is expanded to show all steps. */
144
+ /** Whether compact mobile view is expanded to show all steps. Toggled by clicking the counter. */
73
145
  isCompactExpanded: boolean;
74
146
  private _stepsNumbered;
75
147
  constructor();
@@ -101,6 +101,7 @@ export declare class NysTabgroup extends LitElement {
101
101
  * is resized.
102
102
  */
103
103
  firstUpdated(): void;
104
+ disconnectedCallback(): void;
104
105
  /**
105
106
  * Reads the current scroll state of `_tabsEl` and toggles the `is-visible`
106
107
  * class on the left and right shadow overlays accordingly.
@@ -153,9 +154,11 @@ export declare class NysTabgroup extends LitElement {
153
154
  *
154
155
  * Iterates over all assigned elements and moves each `<nys-tab>` into
155
156
  * `.nys-tabgroup__tabs` and each `<nys-tabpanel>` into
156
- * `.nys-tabgroup__panels`, preserving relative order. After sorting,
157
- * calls `_applySelection` using the first element that already has a
158
- * `selected` attribute, or index `0` if none is found.
157
+ * `.nys-tabgroup__panels`. If a panel has an `aria-labelledby` attribute,
158
+ * it is explicitly paired with the tab it references; otherwise panels are
159
+ * paired with tabs by index order. After sorting, calls `_applySelection`
160
+ * using the first element that already has a `selected` attribute, or
161
+ * index `0` if none is found.
159
162
  *
160
163
  * @param e - The `Event` fired by the `<slot>` element on slot change.
161
164
  * @returns void
@@ -36,6 +36,7 @@ export declare class NysTooltip extends LitElement {
36
36
  private _internallyUpdatingPosition;
37
37
  private _hideTimeout;
38
38
  private _position;
39
+ private _resizeObserver;
39
40
  /**
40
41
  * Preferred position relative to trigger. Auto-adjusts if space is insufficient.
41
42
  * @default null (auto-positioned based on available space)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nysds/components",
3
- "version": "1.18.0",
3
+ "version": "1.18.3",
4
4
  "description": "New York State's design system and code component library.",
5
5
  "type": "module",
6
6
  "workspaces": [
@@ -46,6 +46,8 @@
46
46
  "release:zip": "npm run build:all && node src/scripts/create-release-zip.js",
47
47
  "test": "npx playwright install && wtr --node-resolve",
48
48
  "test:build": "npm run build:all && npm run test",
49
+ "test:compact": "export NYSDS_TEST_OUTPUT=compact && npx playwright install && wtr --node-resolve",
50
+ "test:ai": "export NYSDS_TEST_OUTPUT=ai && npx playwright install && wtr --node-resolve",
49
51
  "storybook": "cross-env NODE_ENV=production storybook dev -p 6006",
50
52
  "storybook:build:all": "cross-env NODE_ENV=production npm run build:all && npm run storybook",
51
53
  "build-storybook": "npm run build:packages && storybook build",
@@ -18,24 +18,22 @@ export interface NysStepProps extends Pick<
18
18
  | "onFocus"
19
19
  | "onBlur"
20
20
  > {
21
- /** Whether this step is currently being viewed. Set by parent stepper. */
21
+ /** Which step is currently being displayed. If not set, defaults to the `current` step.
22
+ Setting this on a step after `current` is silently corrected to match `current`.
23
+ When controlling state from a framework, always set this explicitly. */
22
24
  selected?: boolean;
23
25
 
24
- /** Marks the furthest reached step. Steps before this are navigable. */
26
+ /** The furthest step the user has reached (progress boundary). Steps before this are navigable. */
25
27
  current?: boolean;
26
28
 
27
- /** Internal: Whether parent stepper's compact view is expanded. */
28
- isCompactExpanded?: boolean;
29
-
30
29
  /** Step label text displayed alongside the step number. */
31
30
  label?: NysStepElement["label"];
32
31
 
33
- /** URL for page navigation when step is clicked. Optional for SPA routing. */
32
+ /** URL navigated to when the step is activated, via `window.location.href`.
33
+ Navigation is suppressed if the `nys-step-click` listener calls `e.preventDefault()`.
34
+ Omit for SPA/framework routing and handle navigation in the event listener instead. */
34
35
  href?: NysStepElement["href"];
35
36
 
36
- /** Step number (1-indexed). Auto-assigned by parent stepper. */
37
- stepNumber?: NysStepElement["stepNumber"];
38
-
39
37
  /** A space-separated list of the classes of the element. Classes allows CSS and JavaScript to select and access specific elements via the class selectors or functions like the method `Document.getElementsByClassName()`. */
40
38
  className?: string;
41
39
 
@@ -57,10 +55,10 @@ export interface NysStepProps extends Pick<
57
55
  /** Allows developers to make HTML elements focusable, allow or prevent them from being sequentially focusable (usually with the `Tab` key, hence the name) and determine their relative ordering for sequential focus navigation. */
58
56
  tabIndex?: number;
59
57
 
60
- /** Custom click handler. Called before `nys-step-click` event. */
58
+ /** Optional function called before `nys-step-click` is dispatched. Use for pre-navigation logic. */
61
59
  onClick?: NysStepElement["onClick"];
62
60
 
63
- /** Fired when a navigable step is clicked. Detail: `{href, label}`. Cancelable. */
61
+ /** Fired when a navigable (`previous` or `current`) non-selected step is clicked or activated by keyboard. Detail: `{ href: string, label: string }`. Cancelable — call `e.preventDefault()` to suppress `window.location.href` navigation. */
64
62
  onNysStepClick?: (event: CustomEvent) => void;
65
63
  }
66
64
 
@@ -70,6 +68,6 @@ export interface NysStepProps extends Pick<
70
68
  *
71
69
  *
72
70
  * ### **Events:**
73
- * - **nys-step-click** - Fired when a navigable step is clicked. Detail: `{href, label}`. Cancelable.
71
+ * - **nys-step-click** - Fired when a navigable (`previous` or `current`) non-selected step is clicked or activated by keyboard. Detail: `{ href: string, label: string }`. Cancelable — call `e.preventDefault()` to suppress `window.location.href` navigation.
74
72
  */
75
73
  export const NysStep: React.ForwardRefExoticComponent<NysStepProps>;
@@ -4,16 +4,7 @@ import { useEventListener, useProperties } from "./react-utils.js";
4
4
 
5
5
  export const NysStep = forwardRef((props, forwardedRef) => {
6
6
  const ref = useRef(null);
7
- const {
8
- selected,
9
- current,
10
- isCompactExpanded,
11
- label,
12
- href,
13
- stepNumber,
14
- onClick,
15
- ...filteredProps
16
- } = props;
7
+ const { selected, current, label, href, onClick, ...filteredProps } = props;
17
8
 
18
9
  /** Event listeners - run once */
19
10
  useEventListener(ref, "nys-step-click", props.onNysStepClick);
@@ -35,7 +26,6 @@ export const NysStep = forwardRef((props, forwardedRef) => {
35
26
  ...filteredProps,
36
27
  label: props.label,
37
28
  href: props.href,
38
- stepNumber: props.stepNumber,
39
29
  class: props.className,
40
30
  exportparts: props.exportparts,
41
31
  for: props.htmlFor,
@@ -43,7 +33,6 @@ export const NysStep = forwardRef((props, forwardedRef) => {
43
33
  tabindex: props.tabIndex,
44
34
  selected: props.selected ? true : undefined,
45
35
  current: props.current ? true : undefined,
46
- isCompactExpanded: props.isCompactExpanded ? true : undefined,
47
36
  style: { ...props.style },
48
37
  },
49
38
  props.children,
@@ -18,19 +18,19 @@ export interface NysStepperProps extends Pick<
18
18
  | "onFocus"
19
19
  | "onBlur"
20
20
  > {
21
- /** Whether compact mobile view is expanded to show all steps. */
21
+ /** Whether compact mobile view is expanded to show all steps. Toggled by clicking the counter. */
22
22
  isCompactExpanded?: boolean;
23
23
 
24
- /** Unique identifier. */
24
+ /** Unique identifier. Auto-generated as `nys-stepper-{n}-{timestamp}` if not provided. */
25
25
  id?: NysStepperElement["id"];
26
26
 
27
27
  /** Name attribute for form association. */
28
28
  name?: NysStepperElement["name"];
29
29
 
30
- /** Title displayed above the step counter. */
30
+ /** Title displayed above the step list and compact counter. */
31
31
  label?: NysStepperElement["label"];
32
32
 
33
- /** Progress text (e.g., "Step 2 of 5"). Auto-updated based on selection. */
33
+ /** Progress text displayed in compact mode (e.g., "Step 2 of 5"). Auto-managed do not set manually. */
34
34
  counterText?: NysStepperElement["counterText"];
35
35
 
36
36
  /** A space-separated list of the classes of the element. Classes allows CSS and JavaScript to select and access specific elements via the class selectors or functions like the method `Document.getElementsByClassName()`. */
@@ -61,7 +61,7 @@ export interface NysStepperProps extends Pick<
61
61
  *
62
62
  *
63
63
  * ### **Slots:**
64
- * - _default_ - Default slot for `nys-step` elements.
65
- * - **actions** - Navigation buttons (e.g., Back, Continue). Must be wrapped in a `<div>`.
64
+ * - _default_ - Default slot for `nys-step` elements. Only `nys-step` children are accepted; others are removed.
65
+ * - **actions** - Persistent navigation buttons. Must contain exactly one `<div>` wrapping only `<nys-button>` elements.
66
66
  */
67
67
  export const NysStepper: React.ForwardRefExoticComponent<NysStepperProps>;