@cobwds/cob-stepper 1.19.4 → 1.23.1
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.
- package/dist/cob-step.d.ts +137 -0
- package/dist/cob-stepper.d.ts +217 -0
- package/dist/cob-stepper.figma.d.ts +1 -0
- package/dist/cob-stepper.js +150 -101
- package/dist/cob-stepper.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/package.json +5 -4
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { CobElement } from "@cobwds/internals";
|
|
2
|
+
/** Detail payload for the `cob-step-click` event fired by `cob-step`. */
|
|
3
|
+
export interface CobStepClickDetail {
|
|
4
|
+
href: string;
|
|
5
|
+
label: string;
|
|
6
|
+
}
|
|
7
|
+
/** The `cob-step-click` event fired by `cob-step`. */
|
|
8
|
+
export type CobStepClickEvent = CustomEvent<CobStepClickDetail>;
|
|
9
|
+
/**
|
|
10
|
+
* A single step within `cob-stepper`. Represents one stage in a multi-step process.
|
|
11
|
+
*
|
|
12
|
+
* Mark as `current` to indicate the active progress point. Previous steps become clickable for navigation.
|
|
13
|
+
* Set `href` for page-based navigation, or omit it and listen to `cob-step-click` for SPA/framework routing.
|
|
14
|
+
*
|
|
15
|
+
* ## Step states
|
|
16
|
+
*
|
|
17
|
+
* Three boolean attributes control step appearance and behavior:
|
|
18
|
+
*
|
|
19
|
+
* - **`current`** — The furthest step the user has reached (the progress boundary). Only one step should
|
|
20
|
+
* have `current` at a time; if multiple are set the parent stepper keeps the first and removes the rest.
|
|
21
|
+
* Steps after `current` are not navigable and do not fire `cob-step-click`. Update `current` in your
|
|
22
|
+
* application state when the user advances.
|
|
23
|
+
*
|
|
24
|
+
* - **`selected`** — Which step's content is currently displayed. Defaults to the `current` step if not
|
|
25
|
+
* explicitly set. If `selected` is placed on a step after `current`, the stepper silently corrects it
|
|
26
|
+
* to match `current`. When managing state from a framework, always set `selected` explicitly — without
|
|
27
|
+
* it the stepper's fallback will reset in-sidebar navigation on every state update.
|
|
28
|
+
*
|
|
29
|
+
* - **`previous`** — Auto-applied by the parent stepper to every step before `current`. Do not set this
|
|
30
|
+
* manually. Steps with `previous` are clickable and fire `cob-step-click`.
|
|
31
|
+
*
|
|
32
|
+
* ## `cob-step-click` firing conditions
|
|
33
|
+
*
|
|
34
|
+
* The event fires only when ALL of the following are true:
|
|
35
|
+
* 1. The step has `previous` or `current` (i.e. it is navigable).
|
|
36
|
+
* 2. The step does NOT already have `selected` (clicking the already-viewed step is a no-op).
|
|
37
|
+
*
|
|
38
|
+
* Steps that are neither `previous` nor `current` (future steps) never fire the event.
|
|
39
|
+
*
|
|
40
|
+
* ## `href` and navigation
|
|
41
|
+
*
|
|
42
|
+
* If `href` is set, the stepper calls `window.location.href = href` after dispatching `cob-step-click`
|
|
43
|
+
* — but only if the event was **not canceled**. To handle navigation yourself (SPA routing, fetch, etc.),
|
|
44
|
+
* always call `e.preventDefault()` in your listener. Omitting `href` entirely is simpler for SPAs.
|
|
45
|
+
*
|
|
46
|
+
* ## `onClick` vs `cob-step-click`
|
|
47
|
+
*
|
|
48
|
+
* The `onClick` property (a function reference, not a DOM attribute) is called **before** the
|
|
49
|
+
* `cob-step-click` event is dispatched. Use it for imperative pre-navigation logic. In React, pass it
|
|
50
|
+
* as the `onClick` prop on `CobStep`.
|
|
51
|
+
*
|
|
52
|
+
* ## Accessibility
|
|
53
|
+
* - The host carries `role="listitem"` so the parent stepper's `<ol>` and its slotted
|
|
54
|
+
* `<cob-step>` children form a real list — assistive technology announces each step's
|
|
55
|
+
* position and count (e.g. "2 of 4") automatically.
|
|
56
|
+
* - Navigable steps (`current`, `previous`, `selected`) render a real `<button>` for their
|
|
57
|
+
* row, giving native keyboard activation (Enter/Space), focus handling, and semantics for
|
|
58
|
+
* free — no manual `tabindex`/`keydown` scaffolding required.
|
|
59
|
+
* - Future (non-navigable) steps render the row as a plain, non-interactive `<div>` — not a
|
|
60
|
+
* disabled button. They are not focusable and carry no `role`, `tabindex`, or `aria-disabled`.
|
|
61
|
+
* - `aria-label` announces the step name and 1-indexed position, e.g. `"Personal Info, step 1"`.
|
|
62
|
+
* - The `current` step (progress boundary) is marked with `aria-current="step"` on the
|
|
63
|
+
* `<button>` itself so assistive technology announces the user's current position.
|
|
64
|
+
* - The visual step number is `aria-hidden` (its meaning is folded into the row's accessible name).
|
|
65
|
+
*
|
|
66
|
+
* ## Common patterns
|
|
67
|
+
*
|
|
68
|
+
* **Initial state:** Set `current` on the first step. `selected` defaults to it.
|
|
69
|
+
* ```html
|
|
70
|
+
* <cob-step label="Step 1" current></cob-step>
|
|
71
|
+
* <cob-step label="Step 2"></cob-step>
|
|
72
|
+
* ```
|
|
73
|
+
*
|
|
74
|
+
* **User completed step 1, now on step 2:**
|
|
75
|
+
* ```html
|
|
76
|
+
* <cob-step label="Step 1"></cob-step>
|
|
77
|
+
* <cob-step label="Step 2" current></cob-step>
|
|
78
|
+
* ```
|
|
79
|
+
*
|
|
80
|
+
* **User went back to review step 1 (progress still at step 2):**
|
|
81
|
+
* ```html
|
|
82
|
+
* <cob-step label="Step 1" selected></cob-step>
|
|
83
|
+
* <cob-step label="Step 2" current></cob-step>
|
|
84
|
+
* ```
|
|
85
|
+
*
|
|
86
|
+
* @summary Individual step for use within cob-stepper with navigation support.
|
|
87
|
+
* @element cob-step
|
|
88
|
+
*
|
|
89
|
+
* @fires {CobStepClickEvent} cob-step-click - Fired when a navigable (`previous` or `current`) non-selected step is clicked
|
|
90
|
+
* or activated by keyboard. Detail: `{ href: string, label: string }`. Cancelable — call
|
|
91
|
+
* `e.preventDefault()` to suppress `window.location.href` navigation.
|
|
92
|
+
*/
|
|
93
|
+
export declare class CobStep extends CobElement {
|
|
94
|
+
static styles: import("lit").CSSResult;
|
|
95
|
+
/**
|
|
96
|
+
* Which step is currently being displayed. If not set, defaults to the `current` step.
|
|
97
|
+
* Setting this on a step after `current` is silently corrected to match `current`.
|
|
98
|
+
* When controlling state from a framework, always set this explicitly.
|
|
99
|
+
*/
|
|
100
|
+
selected: boolean;
|
|
101
|
+
/** The furthest step the user has reached (progress boundary). Steps before this are navigable. */
|
|
102
|
+
current: boolean;
|
|
103
|
+
/** Step label text displayed alongside the step number. */
|
|
104
|
+
label: string;
|
|
105
|
+
/**
|
|
106
|
+
* URL navigated to when the step is activated, via `window.location.href`.
|
|
107
|
+
* Navigation is suppressed if the `cob-step-click` listener calls `e.preventDefault()`.
|
|
108
|
+
* Omit for SPA/framework routing and handle navigation in the event listener instead.
|
|
109
|
+
*/
|
|
110
|
+
href: string;
|
|
111
|
+
/**
|
|
112
|
+
* @internal Auto-applied by `cob-stepper` to every step that comes before `current`.
|
|
113
|
+
* Marks the step as navigable and clickable. Do not set this manually — the parent stepper
|
|
114
|
+
* adds and removes it on every render based on which step has `current`.
|
|
115
|
+
*/
|
|
116
|
+
previous: boolean;
|
|
117
|
+
/** @internal Propagated by the parent stepper. Do not set manually. */
|
|
118
|
+
isCompactExpanded: boolean;
|
|
119
|
+
/** Optional function called before `cob-step-click` is dispatched. Use for pre-navigation logic. */
|
|
120
|
+
onClick?: (e: Event) => void;
|
|
121
|
+
/** @internal 1-indexed position. Auto-assigned by the parent stepper on first render. Do not set manually. */
|
|
122
|
+
stepNumber: number;
|
|
123
|
+
/** A step is navigable (focusable + activatable) when it is the displayed,
|
|
124
|
+
* current, or a previously-reached step. Future steps are inert. */
|
|
125
|
+
private get _navigable();
|
|
126
|
+
/**
|
|
127
|
+
* Sets `role="listitem"` on the host so the parent stepper's `<ol>` (which
|
|
128
|
+
* only ever slots `<cob-step>` elements, never real `<li>`s) still forms a
|
|
129
|
+
* valid ARIA list. This is what lets assistive technology announce each
|
|
130
|
+
* step's position and count. Uses a plain attribute (not ElementInternals)
|
|
131
|
+
* so `getAttribute("role")` keeps working for existing consumers/tests,
|
|
132
|
+
* matching the convention used by `<cob-tab>`.
|
|
133
|
+
*/
|
|
134
|
+
connectedCallback(): void;
|
|
135
|
+
private _handleActivate;
|
|
136
|
+
render(): import("lit-html").TemplateResult<1>;
|
|
137
|
+
}
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import { CobElement } from "@cobwds/internals";
|
|
2
|
+
import "./cob-step";
|
|
3
|
+
/**
|
|
4
|
+
* A multi-step progress indicator for forms or wizards. Manages `cob-step` children with selection and navigation.
|
|
5
|
+
*
|
|
6
|
+
* Add `cob-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 `<cob-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 `cob-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
|
+
* `cob-stepper-{timestamp}-{n}`.
|
|
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
|
+
* - Steps are rendered inside an `<ol>` so assistive technology announces each step's position
|
|
43
|
+
* and count (e.g. "2 of 4"). Each slotted `<cob-step>` carries `role="listitem"` since it
|
|
44
|
+
* can't itself be a real `<li>`.
|
|
45
|
+
* - Navigable steps render as real `<button>` elements — keyboard-focusable and activatable
|
|
46
|
+
* (Enter/Space) natively. Future (non-navigable) steps render as plain, non-interactive rows.
|
|
47
|
+
* - Visual focus indicators are provided on all interactive elements.
|
|
48
|
+
*
|
|
49
|
+
* @summary Multi-step progress indicator with navigation and mobile-friendly compact view.
|
|
50
|
+
* @element cob-stepper
|
|
51
|
+
*
|
|
52
|
+
* @slot - Default slot for `cob-step` elements. Only `cob-step` children are accepted; others are removed.
|
|
53
|
+
* @slot actions - Persistent navigation buttons. Must contain exactly one `<div>` wrapping only `<cob-button>` elements.
|
|
54
|
+
*
|
|
55
|
+
* @usage
|
|
56
|
+
* - Use for linear, ordered forms with more than 2 sections to show progress through a multi-step process.
|
|
57
|
+
* - Ensure users can navigate back to previous steps to review or change information.
|
|
58
|
+
* - Don't use when a form has only 1 or 2 sections.
|
|
59
|
+
* - Don't use for forms that are nonlinear and can be completed in any order.
|
|
60
|
+
*
|
|
61
|
+
* @example Basic
|
|
62
|
+
* ```html
|
|
63
|
+
* <div class="cob-grid-row">
|
|
64
|
+
* <cob-stepper
|
|
65
|
+
* id="stepper"
|
|
66
|
+
* name="stepper"
|
|
67
|
+
* label="Register for Web Design System Office Hours"
|
|
68
|
+
* class="cob-desktop:cob-grid-col-3"
|
|
69
|
+
* >
|
|
70
|
+
* <cob-step label="Personal Details" href="/cob-stepper/personal.html"></cob-step>
|
|
71
|
+
* <cob-step label="Team Info" selected href="/cob-stepper/team.html"></cob-step>
|
|
72
|
+
* <cob-step label="Usage Survey" current href="/cob-stepper/survey.html"></cob-step>
|
|
73
|
+
* <cob-step label="Newsletter Opt-In" href="/cob-stepper/newsletter.html"></cob-step>
|
|
74
|
+
* <div slot="actions">
|
|
75
|
+
* <cob-button variant="outline" label="Save & Exit" fullWidth></cob-button>
|
|
76
|
+
* </div>
|
|
77
|
+
* </cob-stepper>
|
|
78
|
+
* <div class="cob-desktop:cob-grid-col-9" id="cob-stepper-content">
|
|
79
|
+
* Loading...
|
|
80
|
+
* </div>
|
|
81
|
+
* </div>
|
|
82
|
+
* ```
|
|
83
|
+
* @render Basic
|
|
84
|
+
* ```html
|
|
85
|
+
* <div class="cob-grid-row">
|
|
86
|
+
* <cob-stepper
|
|
87
|
+
* id="stepper"
|
|
88
|
+
* name="stepper"
|
|
89
|
+
* label="Register for Web Design System Office Hours"
|
|
90
|
+
* class="cob-desktop:cob-grid-col-3"
|
|
91
|
+
* >
|
|
92
|
+
* <cob-step label="Personal Details" href="/cob-stepper/personal.html"></cob-step>
|
|
93
|
+
* <cob-step label="Team Info" selected href="/cob-stepper/team.html"></cob-step>
|
|
94
|
+
* <cob-step label="Usage Survey" current href="/cob-stepper/survey.html"></cob-step>
|
|
95
|
+
* <cob-step label="Newsletter Opt-In" href="/cob-stepper/newsletter.html"></cob-step>
|
|
96
|
+
* </cob-stepper>
|
|
97
|
+
* <div class="cob-desktop:cob-grid-col-9" id="cob-stepper-content">
|
|
98
|
+
* Loading...
|
|
99
|
+
* </div>
|
|
100
|
+
* </div>
|
|
101
|
+
* <script>
|
|
102
|
+
* document.addEventListener("DOMContentLoaded", async () => {
|
|
103
|
+
* const stepper = document.querySelector("cob-stepper");
|
|
104
|
+
* if (stepper?.updateComplete) await stepper.updateComplete;
|
|
105
|
+
* const selectedStep = document.querySelector("cob-step[selected]");
|
|
106
|
+
* const href = selectedStep?.getAttribute("href");
|
|
107
|
+
* if (!href) return;
|
|
108
|
+
* const res = await fetch(href);
|
|
109
|
+
* if (!res.ok) return;
|
|
110
|
+
* const container = document.querySelector("#cob-stepper-content");
|
|
111
|
+
* if (container) container.innerHTML = await res.text();
|
|
112
|
+
* });
|
|
113
|
+
*
|
|
114
|
+
* document.addEventListener("cob-step-click", async (e) => {
|
|
115
|
+
* const href = e.detail?.href;
|
|
116
|
+
* if (!href) return;
|
|
117
|
+
* e.preventDefault();
|
|
118
|
+
* const res = await fetch(href);
|
|
119
|
+
* if (!res.ok) return;
|
|
120
|
+
* const container = document.querySelector("#cob-stepper-content");
|
|
121
|
+
* if (container) container.innerHTML = await res.text();
|
|
122
|
+
* });
|
|
123
|
+
* </script>
|
|
124
|
+
* ```
|
|
125
|
+
*
|
|
126
|
+
* @example Actions slot
|
|
127
|
+
* ```html
|
|
128
|
+
* <div class="cob-grid-row">
|
|
129
|
+
* <cob-stepper
|
|
130
|
+
* id="stepper"
|
|
131
|
+
* name="stepper"
|
|
132
|
+
* label="Register for Web Design System Office Hours"
|
|
133
|
+
* class="cob-desktop:cob-grid-col-3"
|
|
134
|
+
* >
|
|
135
|
+
* <cob-step label="Personal Details" href="/cob-stepper/personal.html"></cob-step>
|
|
136
|
+
* <cob-step label="Team Info" selected href="/cob-stepper/team.html"></cob-step>
|
|
137
|
+
* <cob-step label="Usage Survey" current href="/cob-stepper/survey.html"></cob-step>
|
|
138
|
+
* <cob-step label="Newsletter Opt-In" href="/cob-stepper/newsletter.html"></cob-step>
|
|
139
|
+
* <div slot="actions">
|
|
140
|
+
* <cob-button variant="outline" label="Save & Exit" fullWidth></cob-button>
|
|
141
|
+
* </div>
|
|
142
|
+
* </cob-stepper>
|
|
143
|
+
* <div class="cob-desktop:cob-grid-col-9" id="cob-stepper-content">
|
|
144
|
+
* Loading...
|
|
145
|
+
* </div>
|
|
146
|
+
* </div>
|
|
147
|
+
* ```
|
|
148
|
+
* @render Actions slot
|
|
149
|
+
* ```html
|
|
150
|
+
* <div class="cob-grid-row">
|
|
151
|
+
* <cob-stepper
|
|
152
|
+
* id="stepper"
|
|
153
|
+
* name="stepper"
|
|
154
|
+
* label="Register for Web Design System Office Hours"
|
|
155
|
+
* class="cob-desktop:cob-grid-col-3"
|
|
156
|
+
* >
|
|
157
|
+
* <cob-step label="Personal Details" href="/cob-stepper/personal.html"></cob-step>
|
|
158
|
+
* <cob-step label="Team Info" selected href="/cob-stepper/team.html"></cob-step>
|
|
159
|
+
* <cob-step label="Usage Survey" current href="/cob-stepper/survey.html"></cob-step>
|
|
160
|
+
* <cob-step label="Newsletter Opt-In" href="/cob-stepper/newsletter.html"></cob-step>
|
|
161
|
+
* <div slot="actions">
|
|
162
|
+
* <cob-button variant="outline" label="Save & Exit" fullWidth></cob-button>
|
|
163
|
+
* </div>
|
|
164
|
+
* </cob-stepper>
|
|
165
|
+
* <div class="cob-desktop:cob-grid-col-9" id="cob-stepper-content">
|
|
166
|
+
* Loading...
|
|
167
|
+
* </div>
|
|
168
|
+
* </div>
|
|
169
|
+
* <script>
|
|
170
|
+
* document.addEventListener("DOMContentLoaded", async () => {
|
|
171
|
+
* const stepper = document.querySelector("cob-stepper");
|
|
172
|
+
* if (stepper?.updateComplete) await stepper.updateComplete;
|
|
173
|
+
* const selectedStep = document.querySelector("cob-step[selected]");
|
|
174
|
+
* const href = selectedStep?.getAttribute("href");
|
|
175
|
+
* if (!href) return;
|
|
176
|
+
* const res = await fetch(href);
|
|
177
|
+
* if (!res.ok) return;
|
|
178
|
+
* const container = document.querySelector("#cob-stepper-content");
|
|
179
|
+
* if (container) container.innerHTML = await res.text();
|
|
180
|
+
* });
|
|
181
|
+
*
|
|
182
|
+
* document.addEventListener("cob-step-click", async (e) => {
|
|
183
|
+
* const href = e.detail?.href;
|
|
184
|
+
* if (!href) return;
|
|
185
|
+
* e.preventDefault();
|
|
186
|
+
* const res = await fetch(href);
|
|
187
|
+
* if (!res.ok) return;
|
|
188
|
+
* const container = document.querySelector("#cob-stepper-content");
|
|
189
|
+
* if (container) container.innerHTML = await res.text();
|
|
190
|
+
* });
|
|
191
|
+
* </script>
|
|
192
|
+
* ```
|
|
193
|
+
*/
|
|
194
|
+
export declare class CobStepper extends CobElement {
|
|
195
|
+
static styles: import("lit").CSSResult;
|
|
196
|
+
/** Unique identifier. Auto-generated as `cob-stepper-{timestamp}-{n}` if not provided. */
|
|
197
|
+
id: string;
|
|
198
|
+
/** Name attribute for form association. */
|
|
199
|
+
name: string;
|
|
200
|
+
/** Title displayed above the step list and compact counter. */
|
|
201
|
+
label: string;
|
|
202
|
+
/** Progress text displayed in compact mode (e.g., "Step 2 of 5"). Auto-managed — do not set manually. */
|
|
203
|
+
counterText: string;
|
|
204
|
+
/** Whether compact mobile view is expanded to show all steps. Toggled by clicking the counter. */
|
|
205
|
+
isCompactExpanded: boolean;
|
|
206
|
+
private _stepsNumbered;
|
|
207
|
+
connectedCallback(): void;
|
|
208
|
+
disconnectedCallback(): void;
|
|
209
|
+
private _validateSteps;
|
|
210
|
+
private _validateButtonSlot;
|
|
211
|
+
private _onStepClick;
|
|
212
|
+
private _updateCounter;
|
|
213
|
+
willUpdate(): void;
|
|
214
|
+
private _toggleCompact;
|
|
215
|
+
private _handleCounterKeydown;
|
|
216
|
+
render(): import("lit-html").TemplateResult<1>;
|
|
217
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/cob-stepper.js
CHANGED
|
@@ -1,125 +1,167 @@
|
|
|
1
|
-
import { LitElement as
|
|
2
|
-
import { property as
|
|
1
|
+
import { LitElement as x, unsafeCSS as u, html as d } from "lit";
|
|
2
|
+
import { property as a } from "lit/decorators.js";
|
|
3
|
+
import { ifDefined as _ } from "lit/directives/if-defined.js";
|
|
3
4
|
/*!
|
|
4
5
|
* █▄ █ █ █ █▀▀▀█ █▀▀▄ █▀▀▀█
|
|
5
6
|
* █ █ █ █▄▄▄█ ▀▀▀▄▄ █ █ ▀▀▀▄▄
|
|
6
7
|
* █ ▀█ █ █▄▄▄█ █▄▄▀ █▄▄▄█
|
|
7
8
|
*
|
|
8
|
-
* Stepper Component v1.
|
|
9
|
+
* Stepper Component v1.23.1
|
|
9
10
|
* Part of the City of Boston Web Design System
|
|
10
|
-
* Repository: https://github.com/
|
|
11
|
+
* Repository: https://github.com/its-hcd/cobwds
|
|
11
12
|
* License: MIT
|
|
12
13
|
*/
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
/*!
|
|
15
|
+
* City of Boston Web Design System v1.23.1
|
|
16
|
+
* Description: A web design system for the City of Boston's digital products.
|
|
17
|
+
* Repository: https://github.com/CityOfBoston/nywds-poc
|
|
18
|
+
* License: MIT
|
|
19
|
+
*/
|
|
20
|
+
let g = 0;
|
|
21
|
+
function y(n) {
|
|
22
|
+
return `${n}-${Date.now()}-${g++}`;
|
|
23
|
+
}
|
|
24
|
+
const w = (n) => {
|
|
25
|
+
class e extends n {
|
|
26
|
+
get idPrefix() {
|
|
27
|
+
return this.localName || "cob-element";
|
|
28
|
+
}
|
|
29
|
+
ensureId() {
|
|
30
|
+
this.id || (this.id = y(this.idPrefix));
|
|
31
|
+
}
|
|
32
|
+
connectedCallback() {
|
|
33
|
+
super.connectedCallback(), this.ensureId();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return e;
|
|
37
|
+
}, v = /* @__PURE__ */ w(x), m = ':host{--_cob-stepper-font-size: var(--cob-font-size-ui-md, 16px);--_cob-stepper-font-weight: var(--cob-font-weight-semibold, 600);--_cob-stepper-line-height: var(--cob-font-lineheight-ui-md, 24px);--_cob-stepper-font-family: var( --cob-font-family-ui, var(--cob-font-family-serif, "Lora", "Georgia", "Times New Roman", serif) );--_cob-step-color: var(--cob-color-text, #1b1b1b);--_cob-stepper-background-color: var(--cob-color-surface-raised, #f6f6f6)}.cob-stepper{font-family:var(--_cob-stepper-font-family);font-size:var(--_cob-stepper-font-size);font-weight:var(--_cob-stepper-font-weight);line-height:var(--_cob-stepper-line-height);display:flex;flex-direction:column;counter-reset:step;background-color:var(--_cob-stepper-background-color);max-width:100%;height:100%}.cob-stepper__header{display:flex;flex-direction:column;padding:var(--cob-space-400, 32px) var(--cob-space-400, 32px) var(--cob-space-150, 12px)}::slotted(div[slot=actions]){display:flex;flex-wrap:wrap;justify-content:flex-start;gap:var(--cob-space-100, 8px);margin-bottom:var(--cob-space-300, 24px)}.cob-stepper__counter{display:none;text-decoration:underline;text-decoration-style:solid;text-decoration-skip-ink:auto;text-decoration-thickness:7%;text-underline-offset:auto;text-underline-position:from-font;color:var(--cob-color-text, #1b1b1b);text-overflow:ellipsis;font-family:var(--cob-font-family-ui, "Montserrat");font-size:var(--cob-font-size-ui-md, 16px);font-style:normal;font-weight:400;line-height:var(--cob-font-size-ui-md, 16px);cursor:pointer;width:fit-content}.cob-stepper__steps{list-style:none;margin:0;display:flex;flex-direction:column;padding:var(--cob-space-150, 12px) var(--cob-space-400, 32px) var(--cob-space-400, 32px);overflow-y:scroll;height:fit-content;height:-moz-available;scrollbar-width:none;background:linear-gradient(var(--cob-color-surface-raised, #f6f6f6) 30%,rgba(255,255,255,0)) center top,linear-gradient(rgba(255,255,255,0),var(--cob-color-surface-raised, #f6f6f6) 70%) center bottom,linear-gradient(to bottom,#63636333,#0000) top,linear-gradient(to top,#63636333,#0000) bottom;background-repeat:no-repeat;background-size:100% 40px,100% 40px,100% 14px,100% 14px;background-attachment:local,local,scroll,scroll;background-color:var(--cob-color-surface-raised, #f6f6f6)}.cob-step{position:relative;counter-increment:step;display:flex;flex-direction:column}.cob-step__contentwrapper{appearance:none;-webkit-appearance:none;background:none;border:none;margin:0;padding:0;font:inherit;color:inherit;text-align:inherit;display:flex;flex-direction:row;align-items:center;gap:var(--cob-space-150, 12px);cursor:default;width:fit-content}.cob-step__contentwrapper:focus-visible{outline:solid var(--cob-color-focus, #004dd1) var(--cob-border-width-md, 2px);outline-offset:var(--cob-space-2px, 2px);border-radius:var(--cob-radius-md, 4px)}.cob-step__linewrapper{width:24px;display:flex;justify-content:center}.cob-step__line{width:var(--cob-size-1px, 1px);height:var(--cob-size-300, 24px);border-radius:var(--cob-radius-round, 1776px);background:var(--cob-color-black-transparent-200, rgba(27, 27, 27, .2));margin:var(--cob-space-100, 8px) 0}.cob-step__number{border-radius:var(--cob-radius-round, 1776px);border:var(--cob-size-1px, 1px) solid var(--cob-color-neutral-400, #909395);background:var(--cob-color-white-transparent-900, rgba(255, 255, 255, .9));width:var(--cob-size-300, 24px);min-width:var(--cob-size-300, 24px);max-width:var(--cob-size-300, 24px);height:var(--cob-size-300, 24px);min-height:var(--cob-size-300, 24px);max-height:var(--cob-size-300, 24px);display:flex;align-items:center;justify-content:center;text-align:center;color:var(--cob-color-text, #1b1b1b)}:host([previous]) .cob-step__number,:host([previous]) .cob-step__line,:host([current]) .cob-step__number,:host([current]) .cob-step__line{background-color:var(--cob-color-theme-stronger, #091f2f);color:var(--cob-color-text-reverse, #ffffff);border-color:var(--cob-color-theme-stronger, #091f2f)}:host([selected]) .cob-step__number{background-color:var(--cob-color-theme, #1871bd);color:var(--cob-color-text-reverse, #ffffff);border-color:var(--cob-color-theme, #1871bd);outline:var(--cob-size-50, 4px) solid var(--cob-color-theme-weak, #cddde9)}:host([first]) .cob-step__linewrapper{display:none!important}.cob-step__content{display:flex;flex-direction:column;gap:var(--cob-space-100, 8px)}.cob-step__label{color:var(--_cob-step-color);font-family:var(--_cob-stepper-font-family);font-size:var(--_cob-stepper-font-size);font-weight:var(--_cob-stepper-font-weight);line-height:var(--_cob-stepper-line-height);line-height:var(--cob-font-size-ui-md, 16px);letter-spacing:var(--cob-font-letterspacing-ui-md, .044px);text-decoration-style:solid;text-decoration-skip-ink:auto;text-decoration-thickness:var(7%, 1.12px);text-underline-offset:auto}:host([current]) .cob-step__label,:host([previous]) .cob-step__label{text-decoration-line:underline}:host([current]) .cob-step__contentwrapper,:host([previous]) .cob-step__contentwrapper{cursor:pointer}:host([selected]) .cob-step__label{font-weight:700;text-decoration-line:none}:host([selected]) .cob-step__contentwrapper{cursor:default}:host([selected]) .cob-step__contentwrapper:focus-visible{outline-offset:6px}@media(max-width:1023px){.cob-stepper{max-width:1023px;width:100%}.cob-stepper__header{flex-direction:row-reverse;justify-content:space-between;padding:var(--cob-space-150, 12px);gap:var(--cob-space-200, 16px)}.cob-stepper__headertext{flex:1 1 0;min-width:0}::slotted(div[slot=actions]){margin-bottom:0;min-width:0;justify-content:end}.cob-stepper__counter{display:block}.cob-stepper__steps{flex-direction:row;gap:var(--cob-space-2px, 2px);padding:0}.cob-stepper__steps slot::slotted(*){flex:1}.cob-step__number{border-radius:0;border:none;background-color:var(--cob-color-neutral-200, #bec0c1);height:var(--cob-size-100, 8px);min-height:var(--cob-size-100, 8px);max-height:var(--cob-size-100, 8px);width:100%;min-width:100%;max-width:100%;color:transparent}:host([previous]) .cob-step__number,:host([current]) .cob-step__number{background-color:var(--cob-color-neutral-900, #1b1b1b);color:transparent}:host([selected]) .cob-step__number{background-color:var(--cob-color-theme-mid, #457aa5);outline:none}.cob-step__content,.cob-step__linewrapper{display:none}.cob-step__contentwrapper{cursor:default;pointer-events:none;width:auto}:host([isCompactExpanded]) .cob-step__content,:host([isCompactExpanded]) .cob-step__linewrapper{display:flex}:host([isCompactExpanded]) .cob-stepper__header{padding-bottom:var(--cob-space-250, 20px)}:host([isCompactExpanded]) .cob-stepper__steps{width:-webkit-fill-available;width:-moz-available;z-index:9999;overflow-y:auto;flex-direction:column;gap:0;padding:var(--cob-space-150, 12px) var(--cob-space-400, 32px) var(--cob-space-400, 32px)}:host([isCompactExpanded]) .cob-stepper__steps slot::slotted(*){flex:none}:host([isCompactExpanded]) .cob-step__number{border-radius:var(--cob-radius-round, 1776px);border:1px solid var(--cob-color-neutral-400, #909395);background:var(--cob-color-white-transparent-900, rgba(255, 255, 255, .9));width:var(--cob-space-300, 24px);min-width:var(--cob-space-300, 24px);max-width:var(--cob-space-300, 24px);height:var(--cob-space-300, 24px);min-height:var(--cob-space-300, 24px);max-height:var(--cob-space-300, 24px);color:var(--cob-color-text, #1b1b1b)}:host([isCompactExpanded][previous]) .cob-step__number,:host([isCompactExpanded][previous]) .cob-step__line,:host([isCompactExpanded][current]) .cob-step__number,:host([isCompactExpanded][current]) .cob-step__line{background:var(--cob-color-theme-stronger, #091f2f);color:var(--cob-color-text-reverse, #ffffff);border-color:var(--cob-color-theme-stronger, #091f2f)}:host([isCompactExpanded][selected]) .cob-step__number{background:var(--cob-color-theme, #1871bd);color:var(--cob-color-text-reverse, #ffffff);border-color:var(--cob-color-theme, #1871bd);outline:4px solid var(--cob-color-theme-weak, #cddde9)}:host([isCompactExpanded]) .cob-step__contentwrapper{pointer-events:all}}';
|
|
38
|
+
var C = Object.defineProperty, p = (n, e, o, s) => {
|
|
39
|
+
for (var r = void 0, t = n.length - 1, i; t >= 0; t--)
|
|
40
|
+
(i = n[t]) && (r = i(e, o, r) || r);
|
|
41
|
+
return r && C(e, o, r), r;
|
|
18
42
|
};
|
|
19
|
-
const
|
|
43
|
+
const f = class f extends v {
|
|
20
44
|
constructor() {
|
|
21
45
|
super(...arguments), this.selected = !1, this.current = !1, this.label = "", this.href = "", this.previous = !1, this.isCompactExpanded = !1, this.stepNumber = 0;
|
|
22
46
|
}
|
|
47
|
+
/** A step is navigable (focusable + activatable) when it is the displayed,
|
|
48
|
+
* current, or a previously-reached step. Future steps are inert. */
|
|
49
|
+
get _navigable() {
|
|
50
|
+
return this.selected || this.current || this.hasAttribute("previous");
|
|
51
|
+
}
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
// Lifecycle
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
/**
|
|
56
|
+
* Sets `role="listitem"` on the host so the parent stepper's `<ol>` (which
|
|
57
|
+
* only ever slots `<cob-step>` elements, never real `<li>`s) still forms a
|
|
58
|
+
* valid ARIA list. This is what lets assistive technology announce each
|
|
59
|
+
* step's position and count. Uses a plain attribute (not ElementInternals)
|
|
60
|
+
* so `getAttribute("role")` keeps working for existing consumers/tests,
|
|
61
|
+
* matching the convention used by `<cob-tab>`.
|
|
62
|
+
*/
|
|
63
|
+
connectedCallback() {
|
|
64
|
+
super.connectedCallback(), this.setAttribute("role", "listitem");
|
|
65
|
+
}
|
|
23
66
|
_handleActivate(e) {
|
|
24
67
|
typeof this.onClick == "function" && this.onClick(e);
|
|
25
|
-
const
|
|
68
|
+
const o = new CustomEvent("cob-step-click", {
|
|
26
69
|
bubbles: !0,
|
|
27
70
|
composed: !0,
|
|
28
71
|
cancelable: !0,
|
|
29
72
|
detail: { href: this.href, label: this.label }
|
|
30
73
|
});
|
|
31
|
-
(this.hasAttribute("previous") || this.current) && !this.selected && (this.dispatchEvent(
|
|
32
|
-
}
|
|
33
|
-
_handleKeydown(e) {
|
|
34
|
-
(e.key === "Enter" || e.key === " ") && (e.preventDefault(), this._handleActivate(e));
|
|
74
|
+
(this.hasAttribute("previous") || this.current) && !this.selected && (this.dispatchEvent(o), !o.defaultPrevented && this.href && (window.location.href = this.href));
|
|
35
75
|
}
|
|
36
76
|
render() {
|
|
37
|
-
|
|
77
|
+
const e = this._navigable, o = this.stepNumber ? `${this.label}, step ${this.stepNumber}` : `${this.label} Step`, s = d`
|
|
78
|
+
<div class="cob-step__number" aria-hidden="true">${this.stepNumber}</div>
|
|
79
|
+
<div class="cob-step__content">
|
|
80
|
+
<div class="cob-step__label">${this.label}</div>
|
|
81
|
+
</div>
|
|
82
|
+
`;
|
|
83
|
+
return d`
|
|
38
84
|
<div class="cob-step">
|
|
39
85
|
<div class="cob-step__linewrapper">
|
|
40
86
|
<div class="cob-step__line"></div>
|
|
41
87
|
</div>
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
</div>
|
|
61
|
-
</div>
|
|
62
|
-
</div>
|
|
88
|
+
${e ? d`
|
|
89
|
+
<button
|
|
90
|
+
type="button"
|
|
91
|
+
class="cob-step__contentwrapper"
|
|
92
|
+
@click=${this._handleActivate}
|
|
93
|
+
aria-label=${o}
|
|
94
|
+
aria-current=${_(this.current ? "step" : void 0)}
|
|
95
|
+
>
|
|
96
|
+
${s}
|
|
97
|
+
</button>
|
|
98
|
+
` : d`
|
|
99
|
+
<div
|
|
100
|
+
class="cob-step__contentwrapper"
|
|
101
|
+
aria-label=${o}
|
|
102
|
+
>
|
|
103
|
+
${s}
|
|
104
|
+
</div>
|
|
105
|
+
`}
|
|
63
106
|
</div>
|
|
64
107
|
`;
|
|
65
108
|
}
|
|
66
109
|
};
|
|
67
|
-
|
|
68
|
-
let
|
|
110
|
+
f.styles = u(m);
|
|
111
|
+
let c = f;
|
|
69
112
|
p([
|
|
70
|
-
|
|
71
|
-
],
|
|
113
|
+
a({ type: Boolean, reflect: !0 })
|
|
114
|
+
], c.prototype, "selected");
|
|
72
115
|
p([
|
|
73
|
-
|
|
74
|
-
],
|
|
116
|
+
a({ type: Boolean, reflect: !0 })
|
|
117
|
+
], c.prototype, "current");
|
|
75
118
|
p([
|
|
76
|
-
|
|
77
|
-
],
|
|
119
|
+
a({ type: String })
|
|
120
|
+
], c.prototype, "label");
|
|
78
121
|
p([
|
|
79
|
-
|
|
80
|
-
],
|
|
122
|
+
a({ type: String })
|
|
123
|
+
], c.prototype, "href");
|
|
81
124
|
p([
|
|
82
|
-
|
|
83
|
-
],
|
|
125
|
+
a({ type: Boolean, reflect: !0 })
|
|
126
|
+
], c.prototype, "previous");
|
|
84
127
|
p([
|
|
85
|
-
|
|
86
|
-
],
|
|
128
|
+
a({ type: Boolean })
|
|
129
|
+
], c.prototype, "isCompactExpanded");
|
|
87
130
|
p([
|
|
88
|
-
|
|
89
|
-
],
|
|
131
|
+
a({ attribute: !1 })
|
|
132
|
+
], c.prototype, "onClick");
|
|
90
133
|
p([
|
|
91
|
-
|
|
92
|
-
],
|
|
93
|
-
customElements.get("cob-step") || customElements.define("cob-step",
|
|
94
|
-
var
|
|
95
|
-
for (var
|
|
96
|
-
(i =
|
|
97
|
-
return
|
|
134
|
+
a({ type: Number })
|
|
135
|
+
], c.prototype, "stepNumber");
|
|
136
|
+
customElements.get("cob-step") || customElements.define("cob-step", c);
|
|
137
|
+
var k = Object.defineProperty, b = (n, e, o, s) => {
|
|
138
|
+
for (var r = void 0, t = n.length - 1, i; t >= 0; t--)
|
|
139
|
+
(i = n[t]) && (r = i(e, o, r) || r);
|
|
140
|
+
return r && k(e, o, r), r;
|
|
98
141
|
};
|
|
99
|
-
|
|
100
|
-
const f = class f extends h {
|
|
142
|
+
const h = class h extends v {
|
|
101
143
|
constructor() {
|
|
102
|
-
super(), this.id = "", this.name = "", this.label = "", this.counterText = "initial", this.isCompactExpanded = !1, this._stepsNumbered = !1, this._onStepClick = async (e) => {
|
|
103
|
-
const
|
|
144
|
+
super(...arguments), this.id = "", this.name = "", this.label = "", this.counterText = "initial", this.isCompactExpanded = !1, this._stepsNumbered = !1, this._onStepClick = async (e) => {
|
|
145
|
+
const o = e.composedPath().find(
|
|
104
146
|
(i) => i instanceof HTMLElement && i.tagName.toLowerCase() === "cob-step"
|
|
105
147
|
);
|
|
106
|
-
if (!
|
|
107
|
-
const s = Array.from(this.querySelectorAll("cob-step")),
|
|
148
|
+
if (!o) return;
|
|
149
|
+
const s = Array.from(this.querySelectorAll("cob-step")), r = s.findIndex(
|
|
108
150
|
(i) => i.hasAttribute("current")
|
|
109
|
-
), t = s.indexOf(
|
|
110
|
-
|
|
151
|
+
), t = s.indexOf(o);
|
|
152
|
+
r !== -1 && t > r || o.hasAttribute("selected") || (s.forEach((i) => i.removeAttribute("selected")), o.setAttribute("selected", ""), this._updateCounter(), this.isCompactExpanded = !1);
|
|
111
153
|
};
|
|
112
154
|
}
|
|
113
155
|
connectedCallback() {
|
|
114
|
-
super.connectedCallback(), this.addEventListener("cob-step-click", this._onStepClick), requestAnimationFrame(() => this._validateSteps())
|
|
156
|
+
super.connectedCallback(), this.addEventListener("cob-step-click", this._onStepClick), requestAnimationFrame(() => this._validateSteps());
|
|
115
157
|
}
|
|
116
158
|
disconnectedCallback() {
|
|
117
159
|
this.removeEventListener("cob-step-click", this._onStepClick), super.disconnectedCallback();
|
|
118
160
|
}
|
|
119
161
|
_validateSteps() {
|
|
120
162
|
Array.from(this.children).forEach((e) => {
|
|
121
|
-
const
|
|
122
|
-
!
|
|
163
|
+
const o = e instanceof HTMLElement && e.tagName.toLowerCase() === "cob-step", s = e instanceof HTMLElement && e.hasAttribute("slot") && e.getAttribute("slot") === "actions";
|
|
164
|
+
!o && !s && (console.warn(
|
|
123
165
|
"Only <cob-step> elements or the <div slot='actions'> container are allowed as direct children of <cob-stepper>. Removing:",
|
|
124
166
|
e
|
|
125
167
|
), e.remove());
|
|
@@ -133,8 +175,8 @@ const f = class f extends h {
|
|
|
133
175
|
);
|
|
134
176
|
return;
|
|
135
177
|
}
|
|
136
|
-
const
|
|
137
|
-
Array.from(
|
|
178
|
+
const r = s[0];
|
|
179
|
+
Array.from(r.children).forEach((t) => {
|
|
138
180
|
t instanceof HTMLElement && t.tagName.toLowerCase() === "cob-button" ? (t.setAttribute("size", "sm"), t.hasAttribute("fullWidth") && (t.style.flex = "1 1 0")) : (console.warn(
|
|
139
181
|
"The <div> inside 'actions' slot only accepts <cob-button> elements. Removing invalid node:",
|
|
140
182
|
t
|
|
@@ -147,10 +189,10 @@ const f = class f extends h {
|
|
|
147
189
|
e = "Back to Form", this.style.height = "-webkit-fit-content", this.style.height = "-moz-fit-content", this.style.height = "fit-content";
|
|
148
190
|
else {
|
|
149
191
|
this.style.height = "auto";
|
|
150
|
-
const
|
|
192
|
+
const o = this.querySelectorAll("cob-step"), s = Array.from(o).findIndex(
|
|
151
193
|
(t) => t.hasAttribute("selected")
|
|
152
|
-
),
|
|
153
|
-
e = s >= 0 ? `Step ${s + 1} of ${
|
|
194
|
+
), r = o.length;
|
|
195
|
+
e = s >= 0 ? `Step ${s + 1} of ${r}` : `Step 1 of ${r}`;
|
|
154
196
|
}
|
|
155
197
|
e !== this.counterText && (this.counterText = e);
|
|
156
198
|
}
|
|
@@ -159,10 +201,10 @@ const f = class f extends h {
|
|
|
159
201
|
this._stepsNumbered || (e.forEach((t, i) => {
|
|
160
202
|
t.stepNumber = i + 1;
|
|
161
203
|
}), this._stepsNumbered = !0);
|
|
162
|
-
let
|
|
204
|
+
let o = !1, s = !1, r = !1;
|
|
163
205
|
e.forEach((t, i) => {
|
|
164
|
-
t.current && (
|
|
165
|
-
}), s || (
|
|
206
|
+
t.current && (r ? t.current = !1 : r = !0), i === 0 ? t.setAttribute("first", "") : t.removeAttribute("first"), t.current ? (o = !0, t.previous = !1) : o ? t.previous = !1 : t.previous = !0, t.selected && (o || s ? t.selected = !1 : s = !0), this.isCompactExpanded ? t.setAttribute("isCompactExpanded", "") : t.removeAttribute("isCompactExpanded");
|
|
207
|
+
}), s || (r ? e.forEach((t) => {
|
|
166
208
|
t.current && !s && (t.setAttribute("selected", ""), s = !0);
|
|
167
209
|
}) : e.length > 0 && (e[0].setAttribute("current", ""), e[0].setAttribute("selected", ""))), this._updateCounter();
|
|
168
210
|
}
|
|
@@ -173,7 +215,7 @@ const f = class f extends h {
|
|
|
173
215
|
(e.key === " " || e.key === "Enter") && (e.preventDefault(), this._toggleCompact());
|
|
174
216
|
}
|
|
175
217
|
render() {
|
|
176
|
-
return
|
|
218
|
+
return d`
|
|
177
219
|
<div class="cob-stepper" name=${this.name}>
|
|
178
220
|
<div class="cob-stepper__header">
|
|
179
221
|
<slot name="actions" @slotchange=${this._validateButtonSlot}></slot>
|
|
@@ -192,31 +234,38 @@ const f = class f extends h {
|
|
|
192
234
|
</div>
|
|
193
235
|
</div>
|
|
194
236
|
</div>
|
|
195
|
-
<
|
|
237
|
+
<nav
|
|
238
|
+
class="cob-stepper__nav"
|
|
239
|
+
aria-label=${this.label?.trim() ? `${this.label} progress` : "Progress"}
|
|
240
|
+
>
|
|
241
|
+
<ol class="cob-stepper__steps" role="list">
|
|
242
|
+
<slot></slot>
|
|
243
|
+
</ol>
|
|
244
|
+
</nav>
|
|
196
245
|
</div>
|
|
197
246
|
`;
|
|
198
247
|
}
|
|
199
248
|
};
|
|
200
|
-
|
|
201
|
-
let
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
],
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
],
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
],
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
],
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
],
|
|
217
|
-
customElements.get("cob-stepper") || customElements.define("cob-stepper",
|
|
249
|
+
h.styles = u(m);
|
|
250
|
+
let l = h;
|
|
251
|
+
b([
|
|
252
|
+
a({ type: String, reflect: !0 })
|
|
253
|
+
], l.prototype, "id");
|
|
254
|
+
b([
|
|
255
|
+
a({ type: String, reflect: !0 })
|
|
256
|
+
], l.prototype, "name");
|
|
257
|
+
b([
|
|
258
|
+
a({ type: String })
|
|
259
|
+
], l.prototype, "label");
|
|
260
|
+
b([
|
|
261
|
+
a({ type: String })
|
|
262
|
+
], l.prototype, "counterText");
|
|
263
|
+
b([
|
|
264
|
+
a({ type: Boolean, reflect: !0 })
|
|
265
|
+
], l.prototype, "isCompactExpanded");
|
|
266
|
+
customElements.get("cob-stepper") || customElements.define("cob-stepper", l);
|
|
218
267
|
export {
|
|
219
|
-
|
|
220
|
-
|
|
268
|
+
c as CobStep,
|
|
269
|
+
l as CobStepper
|
|
221
270
|
};
|
|
222
271
|
//# sourceMappingURL=cob-stepper.js.map
|
package/dist/cob-stepper.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cob-stepper.js","sources":["../src/cob-step.ts","../src/cob-stepper.ts"],"sourcesContent":["import { LitElement, html, unsafeCSS } from \"lit\";\nimport { property } from \"lit/decorators.js\";\n// @ts-ignore: SCSS module imported via bundler as inline\nimport styles from \"./cob-stepper.scss?inline\";\n\n/**\n * A single step within `cob-stepper`. Represents one stage in a multi-step process.\n *\n * Mark as `current` to indicate the active progress point. Previous steps become clickable for navigation.\n * Set `href` for page-based navigation, or omit it and listen to `cob-step-click` for SPA/framework routing.\n *\n * ## Step states\n *\n * Three boolean attributes control step appearance and behavior:\n *\n * - **`current`** — The furthest step the user has reached (the progress boundary). Only one step should\n * have `current` at a time; if multiple are set the parent stepper keeps the first and removes the rest.\n * Steps after `current` are not navigable and do not fire `cob-step-click`. Update `current` in your\n * application state when the user advances.\n *\n * - **`selected`** — Which step's content is currently displayed. Defaults to the `current` step if not\n * explicitly set. If `selected` is placed on a step after `current`, the stepper silently corrects it\n * to match `current`. When managing state from a framework, always set `selected` explicitly — without\n * it the stepper's fallback will reset in-sidebar navigation on every state update.\n *\n * - **`previous`** — Auto-applied by the parent stepper to every step before `current`. Do not set this\n * manually. Steps with `previous` are clickable and fire `cob-step-click`.\n *\n * ## `cob-step-click` firing conditions\n *\n * The event fires only when ALL of the following are true:\n * 1. The step has `previous` or `current` (i.e. it is navigable).\n * 2. The step does NOT already have `selected` (clicking the already-viewed step is a no-op).\n *\n * Steps that are neither `previous` nor `current` (future steps) never fire the event.\n *\n * ## `href` and navigation\n *\n * If `href` is set, the stepper calls `window.location.href = href` after dispatching `cob-step-click`\n * — but only if the event was **not canceled**. To handle navigation yourself (SPA routing, fetch, etc.),\n * always call `e.preventDefault()` in your listener. Omitting `href` entirely is simpler for SPAs.\n *\n * ## `onClick` vs `cob-step-click`\n *\n * The `onClick` property (a function reference, not a DOM attribute) is called **before** the\n * `cob-step-click` event is dispatched. Use it for imperative pre-navigation logic. In React, pass it\n * as the `onClick` prop on `CobStep`.\n *\n * ## Accessibility\n * - The step label renders with `role=\"button\"` and is keyboard-focusable (`tabindex=\"0\"`) for navigable\n * steps (`current`, `previous`). Future steps get `tabindex=\"-1\"` and are not reachable by keyboard.\n * - Enter and Space activate the step (same as click).\n * - `aria-label` is set to `\"{label} Step\"` for screen reader announcement.\n *\n * ## Common patterns\n *\n * **Initial state:** Set `current` on the first step. `selected` defaults to it.\n * ```html\n * <cob-step label=\"Step 1\" current></cob-step>\n * <cob-step label=\"Step 2\"></cob-step>\n * ```\n *\n * **User completed step 1, now on step 2:**\n * ```html\n * <cob-step label=\"Step 1\"></cob-step>\n * <cob-step label=\"Step 2\" current></cob-step>\n * ```\n *\n * **User went back to review step 1 (progress still at step 2):**\n * ```html\n * <cob-step label=\"Step 1\" selected></cob-step>\n * <cob-step label=\"Step 2\" current></cob-step>\n * ```\n *\n * @summary Individual step for use within cob-stepper with navigation support.\n * @element cob-step\n *\n * @fires cob-step-click - Fired when a navigable (`previous` or `current`) non-selected step is clicked\n * or activated by keyboard. Detail: `{ href: string, label: string }`. Cancelable — call\n * `e.preventDefault()` to suppress `window.location.href` navigation.\n */\nexport class CobStep extends LitElement {\n static styles = unsafeCSS(styles);\n\n /**\n * Which step is currently being displayed. If not set, defaults to the `current` step.\n * Setting this on a step after `current` is silently corrected to match `current`.\n * When controlling state from a framework, always set this explicitly.\n */\n @property({ type: Boolean, reflect: true }) selected = false;\n\n /** The furthest step the user has reached (progress boundary). Steps before this are navigable. */\n @property({ type: Boolean, reflect: true }) current = false;\n\n /** Step label text displayed alongside the step number. */\n @property({ type: String }) label = \"\";\n\n /**\n * URL navigated to when the step is activated, via `window.location.href`.\n * Navigation is suppressed if the `cob-step-click` listener calls `e.preventDefault()`.\n * Omit for SPA/framework routing and handle navigation in the event listener instead.\n */\n @property({ type: String }) href = \"\";\n\n /**\n * @internal Auto-applied by `cob-stepper` to every step that comes before `current`.\n * Marks the step as navigable and clickable. Do not set this manually — the parent stepper\n * adds and removes it on every render based on which step has `current`.\n */\n @property({ type: Boolean, reflect: true }) previous = false;\n\n /** @internal Propagated by the parent stepper. Do not set manually. */\n @property({ type: Boolean }) isCompactExpanded = false;\n\n /** Optional function called before `cob-step-click` is dispatched. Use for pre-navigation logic. */\n @property({ attribute: false }) onClick?: (e: Event) => void;\n\n /** @internal 1-indexed position. Auto-assigned by the parent stepper on first render. Do not set manually. */\n @property({ type: Number }) stepNumber = 0;\n\n private _handleActivate(e: Event) {\n // Run user-supplied onClick first (if present)\n if (typeof this.onClick === \"function\") {\n this.onClick(e);\n }\n\n // Dispatch event as cancelable so user can prevent navigation\n const event = new CustomEvent(\"cob-step-click\", {\n bubbles: true,\n composed: true,\n cancelable: true,\n detail: { href: this.href, label: this.label },\n });\n\n if ((this.hasAttribute(\"previous\") || this.current) && !this.selected) {\n this.dispatchEvent(event);\n\n // Only navigate if event was not canceled\n if (!event.defaultPrevented && this.href) {\n window.location.href = this.href;\n }\n }\n }\n\n private _handleKeydown(e: KeyboardEvent) {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n this._handleActivate(e);\n }\n }\n\n render() {\n return html`\n <div class=\"cob-step\">\n <div class=\"cob-step__linewrapper\">\n <div class=\"cob-step__line\"></div>\n </div>\n <div\n class=\"cob-step__contentwrapper\"\n @click=${this._handleActivate}\n @keydown=${this._handleKeydown}\n ?disabled=${!(\n this.selected ||\n this.current ||\n this.hasAttribute(\"previous\")\n )}\n >\n <div class=\"cob-step__number\" tabindex=\"-1\" aria-hidden=\"true\">\n ${this.stepNumber}\n </div>\n <div class=\"cob-step__content\" tabindex=\"-1\" aria-hidden=\"true\">\n <div\n class=\"cob-step__label\"\n role=\"button\"\n aria-label=\"${this.label} Step\"\n tabindex=${!(\n this.selected ||\n this.current ||\n this.hasAttribute(\"previous\")\n )\n ? \"-1\"\n : \"0\"}\n aria-hidden=\"true\"\n >\n ${this.label}\n </div>\n </div>\n </div>\n </div>\n `;\n }\n}\n\nif (!customElements.get(\"cob-step\")) {\n customElements.define(\"cob-step\", CobStep);\n}\n","import { LitElement, html, unsafeCSS } from \"lit\";\nimport { property } from \"lit/decorators.js\";\nimport \"./cob-step\";\n// @ts-ignore: SCSS module imported via bundler as inline\nimport styles from \"./cob-stepper.scss?inline\";\n\nlet stepperIdCounter = 0;\n\n/**\n * A multi-step progress indicator for forms or wizards. Manages `cob-step` children with selection and navigation.\n *\n * Add `cob-step` elements as children. Mark one step as `current` to indicate the progress boundary; all steps\n * before it become navigable. Compact view on mobile expands to show all steps. Use the `actions` slot for\n * persistent navigation buttons (e.g., Save & Exit). Do not place the stepper inside a `<form>` element —\n * put form fields in the main content area alongside it.\n *\n * ## When to use\n * - Linear, ordered forms or wizards with more than 2 sections.\n *\n * ## When not to use\n * - Forms with only 1 or 2 sections — use a simpler layout.\n * - Non-linear forms where sections can be completed in any order.\n *\n * ## Compact mode (mobile)\n * On small screens the stepper collapses to a compact view: step labels are hidden and progress\n * is shown as a bar indicator with a \"Step x of y\" counter. Clicking or pressing Enter/Space on\n * the counter expands the full step list (counter text changes to \"Back to Form\"). Collapsing\n * again returns the user to the form view.\n *\n * ## actions slot constraints\n * The `actions` slot must contain exactly one `<div>` as its direct child. That `<div>` may only\n * contain `<cob-button>` elements — any other element is removed with a console warning.\n * The stepper automatically forces `size=\"sm\"` on every button in the slot. Buttons with the\n * `fullWidth` attribute get `flex: 1 1 0` injected so they share available width equally.\n *\n * ## Multiple `current` conflict\n * If more than one `cob-step` has the `current` attribute, only the first one is kept; the rest\n * are silently removed. Always mark exactly one step as `current`.\n *\n * ## id auto-generation\n * If no `id` is provided, a unique id is generated automatically in the form\n * `cob-stepper-{n}-{timestamp}`.\n *\n * ## Accessibility\n * - The compact counter is rendered as a `role=\"button\"` with `aria-expanded` and a descriptive\n * `aria-label` that announces the current step (e.g., \"Expand step navigation. You are on Step 2 of 4\").\n * - Keyboard: Enter or Space toggles the compact view.\n * - Each `cob-step` label is keyboard-focusable and activatable for navigable steps.\n * - Visual focus indicators are provided on all interactive elements.\n *\n * @summary Multi-step progress indicator with navigation and mobile-friendly compact view.\n * @element cob-stepper\n *\n * @slot - Default slot for `cob-step` elements. Only `cob-step` children are accepted; others are removed.\n * @slot actions - Persistent navigation buttons. Must contain exactly one `<div>` wrapping only `<cob-button>` elements.\n *\n * @example Basic\n * ```html\n * <div class=\"cob-grid-row\">\n * <cob-stepper\n * id=\"stepper\"\n * name=\"stepper\"\n * label=\"Register for Web Design System Office Hours\"\n * class=\"cob-desktop:cob-grid-col-3\"\n * >\n * <cob-step label=\"Personal Details\" href=\"/cob-stepper/personal.html\"></cob-step>\n * <cob-step label=\"Team Info\" selected href=\"/cob-stepper/team.html\"></cob-step>\n * <cob-step label=\"Usage Survey\" current href=\"/cob-stepper/survey.html\"></cob-step>\n * <cob-step label=\"Newsletter Opt-In\" href=\"/cob-stepper/newsletter.html\"></cob-step>\n * <div slot=\"actions\">\n * <cob-button variant=\"outline\" label=\"Save & Exit\" fullWidth></cob-button>\n * </div>\n * </cob-stepper>\n * <div class=\"cob-desktop:cob-grid-col-9\" id=\"cob-stepper-content\">\n * Loading...\n * </div>\n * </div>\n * ```\n * @render Basic\n * ```html\n * <div class=\"cob-grid-row\">\n * <cob-stepper\n * id=\"stepper\"\n * name=\"stepper\"\n * label=\"Register for Web Design System Office Hours\"\n * class=\"cob-desktop:cob-grid-col-3\"\n * >\n * <cob-step label=\"Personal Details\" href=\"/cob-stepper/personal.html\"></cob-step>\n * <cob-step label=\"Team Info\" selected href=\"/cob-stepper/team.html\"></cob-step>\n * <cob-step label=\"Usage Survey\" current href=\"/cob-stepper/survey.html\"></cob-step>\n * <cob-step label=\"Newsletter Opt-In\" href=\"/cob-stepper/newsletter.html\"></cob-step>\n * </cob-stepper>\n * <div class=\"cob-desktop:cob-grid-col-9\" id=\"cob-stepper-content\">\n * Loading...\n * </div>\n * </div>\n * <script>\n * document.addEventListener(\"DOMContentLoaded\", async () => {\n * const stepper = document.querySelector(\"cob-stepper\");\n * if (stepper?.updateComplete) await stepper.updateComplete;\n * const selectedStep = document.querySelector(\"cob-step[selected]\");\n * const href = selectedStep?.getAttribute(\"href\");\n * if (!href) return;\n * const res = await fetch(href);\n * if (!res.ok) return;\n * const container = document.querySelector(\"#cob-stepper-content\");\n * if (container) container.innerHTML = await res.text();\n * });\n *\n * document.addEventListener(\"cob-step-click\", async (e) => {\n * const href = e.detail?.href;\n * if (!href) return;\n * e.preventDefault();\n * const res = await fetch(href);\n * if (!res.ok) return;\n * const container = document.querySelector(\"#cob-stepper-content\");\n * if (container) container.innerHTML = await res.text();\n * });\n * </script>\n * ```\n *\n * @example Actions slot\n * ```html\n * <div class=\"cob-grid-row\">\n * <cob-stepper\n * id=\"stepper\"\n * name=\"stepper\"\n * label=\"Register for Web Design System Office Hours\"\n * class=\"cob-desktop:cob-grid-col-3\"\n * >\n * <cob-step label=\"Personal Details\" href=\"/cob-stepper/personal.html\"></cob-step>\n * <cob-step label=\"Team Info\" selected href=\"/cob-stepper/team.html\"></cob-step>\n * <cob-step label=\"Usage Survey\" current href=\"/cob-stepper/survey.html\"></cob-step>\n * <cob-step label=\"Newsletter Opt-In\" href=\"/cob-stepper/newsletter.html\"></cob-step>\n * <div slot=\"actions\">\n * <cob-button variant=\"outline\" label=\"Save & Exit\" fullWidth></cob-button>\n * </div>\n * </cob-stepper>\n * <div class=\"cob-desktop:cob-grid-col-9\" id=\"cob-stepper-content\">\n * Loading...\n * </div>\n * </div>\n * ```\n * @render Actions slot\n * ```html\n * <div class=\"cob-grid-row\">\n * <cob-stepper\n * id=\"stepper\"\n * name=\"stepper\"\n * label=\"Register for Web Design System Office Hours\"\n * class=\"cob-desktop:cob-grid-col-3\"\n * >\n * <cob-step label=\"Personal Details\" href=\"/cob-stepper/personal.html\"></cob-step>\n * <cob-step label=\"Team Info\" selected href=\"/cob-stepper/team.html\"></cob-step>\n * <cob-step label=\"Usage Survey\" current href=\"/cob-stepper/survey.html\"></cob-step>\n * <cob-step label=\"Newsletter Opt-In\" href=\"/cob-stepper/newsletter.html\"></cob-step>\n * <div slot=\"actions\">\n * <cob-button variant=\"outline\" label=\"Save & Exit\" fullWidth></cob-button>\n * </div>\n * </cob-stepper>\n * <div class=\"cob-desktop:cob-grid-col-9\" id=\"cob-stepper-content\">\n * Loading...\n * </div>\n * </div>\n * <script>\n * document.addEventListener(\"DOMContentLoaded\", async () => {\n * const stepper = document.querySelector(\"cob-stepper\");\n * if (stepper?.updateComplete) await stepper.updateComplete;\n * const selectedStep = document.querySelector(\"cob-step[selected]\");\n * const href = selectedStep?.getAttribute(\"href\");\n * if (!href) return;\n * const res = await fetch(href);\n * if (!res.ok) return;\n * const container = document.querySelector(\"#cob-stepper-content\");\n * if (container) container.innerHTML = await res.text();\n * });\n *\n * document.addEventListener(\"cob-step-click\", async (e) => {\n * const href = e.detail?.href;\n * if (!href) return;\n * e.preventDefault();\n * const res = await fetch(href);\n * if (!res.ok) return;\n * const container = document.querySelector(\"#cob-stepper-content\");\n * if (container) container.innerHTML = await res.text();\n * });\n * </script>\n * ```\n */\n\nexport class CobStepper extends LitElement {\n static styles = unsafeCSS(styles);\n\n /** Unique identifier. Auto-generated as `cob-stepper-{n}-{timestamp}` if not provided. */\n @property({ type: String, reflect: true }) id = \"\";\n\n /** Name attribute for form association. */\n @property({ type: String, reflect: true }) name = \"\";\n\n /** Title displayed above the step list and compact counter. */\n @property({ type: String }) label = \"\";\n\n /** Progress text displayed in compact mode (e.g., \"Step 2 of 5\"). Auto-managed — do not set manually. */\n @property({ type: String }) counterText = \"initial\";\n\n /** Whether compact mobile view is expanded to show all steps. Toggled by clicking the counter. */\n @property({ type: Boolean, reflect: true })\n isCompactExpanded = false;\n\n private _stepsNumbered = false;\n\n constructor() {\n super();\n }\n\n connectedCallback() {\n super.connectedCallback();\n this.addEventListener(\"cob-step-click\", this._onStepClick);\n // Defer step validation to next tick to ensure children are upgraded\n requestAnimationFrame(() => this._validateSteps());\n\n // Generate unique id if not provided\n if (!this.id) {\n this.id = `cob-stepper-${++stepperIdCounter}-${Date.now()}`;\n }\n }\n\n disconnectedCallback() {\n this.removeEventListener(\"cob-step-click\", this._onStepClick);\n super.disconnectedCallback();\n }\n\n private _validateSteps() {\n Array.from(this.children).forEach((child) => {\n const isStep =\n child instanceof HTMLElement &&\n child.tagName.toLowerCase() === \"cob-step\";\n const isSlotActionsContainer =\n child instanceof HTMLElement &&\n child.hasAttribute(\"slot\") &&\n child.getAttribute(\"slot\") === \"actions\";\n\n if (!isStep && !isSlotActionsContainer) {\n console.warn(\n \"Only <cob-step> elements or the <div slot='actions'> container are allowed as direct children of <cob-stepper>. Removing:\",\n child,\n );\n child.remove();\n }\n });\n }\n\n private _validateButtonSlot(event: Event) {\n const slot = event.target as HTMLSlotElement;\n const assignedElements = slot.assignedElements();\n\n // Ensure exactly one direct node in the slot, and it must be a div\n if (\n assignedElements.length !== 1 ||\n assignedElements[0].tagName.toLowerCase() !== \"div\"\n ) {\n console.warn(\n \"The 'actions' slot must have exactly one <div> as a direct child.\",\n );\n return;\n }\n\n const div = assignedElements[0] as HTMLElement;\n\n // Iterate through all buttons and validate\n Array.from(div.children).forEach((button) => {\n const isNysButton =\n button instanceof HTMLElement &&\n button.tagName.toLowerCase() === \"cob-button\";\n\n if (!isNysButton) {\n console.warn(\n \"The <div> inside 'actions' slot only accepts <cob-button> elements. Removing invalid node:\",\n button,\n );\n button.remove();\n } else {\n // Ensure cob-button has correct styles\n button.setAttribute(\"size\", \"sm\");\n if (button.hasAttribute(\"fullWidth\")) {\n button.style.flex = \"1 1 0\";\n }\n }\n });\n }\n\n private _onStepClick = async (event: Event) => {\n const clickedStep = event\n .composedPath()\n .find(\n (el) =>\n el instanceof HTMLElement && el.tagName.toLowerCase() === \"cob-step\",\n ) as HTMLElement | undefined;\n\n if (!clickedStep) return;\n\n const steps = Array.from(this.querySelectorAll(\"cob-step\"));\n const currentIndex = steps.findIndex((step) =>\n step.hasAttribute(\"current\"),\n );\n const clickedIndex = steps.indexOf(clickedStep);\n\n // Can't select past current\n if (currentIndex !== -1 && clickedIndex > currentIndex) return;\n\n // Can't select already selected\n if (clickedStep.hasAttribute(\"selected\")) return;\n\n // Remove selected from previous and move to new selected\n steps.forEach((step) => step.removeAttribute(\"selected\"));\n clickedStep.setAttribute(\"selected\", \"\");\n\n // Update counter immediately\n this._updateCounter();\n\n // Close expanded if it was open\n this.isCompactExpanded = false;\n };\n\n private _updateCounter() {\n let newCounterText: string;\n\n if (this.isCompactExpanded) {\n newCounterText = \"Back to Form\";\n this.style.height = \"-webkit-fit-content\";\n this.style.height = \"-moz-fit-content\";\n this.style.height = \"fit-content\";\n } else {\n this.style.height = \"auto\";\n\n const steps = this.querySelectorAll<HTMLElement>(\"cob-step\");\n const selectedIndex = Array.from(steps).findIndex((step) =>\n step.hasAttribute(\"selected\"),\n );\n const totalSteps = steps.length;\n\n newCounterText =\n selectedIndex >= 0\n ? `Step ${selectedIndex + 1} of ${totalSteps}`\n : `Step 1 of ${totalSteps}`;\n }\n\n if (newCounterText !== this.counterText) {\n this.counterText = newCounterText;\n }\n }\n\n willUpdate() {\n const steps = this.querySelectorAll<any>(\"cob-step\");\n\n if (!this._stepsNumbered) {\n steps.forEach((step, index) => {\n step.stepNumber = index + 1;\n });\n this._stepsNumbered = true;\n }\n\n let foundCurrent = false;\n let selectedAssigned = false;\n let currentAssigned = false;\n\n steps.forEach((step, i) => {\n // Check if multiple \"current\" exist, respect the first instance.\n // Read the Lit property (set synchronously by frameworks) rather than the\n // DOM attribute (which Lit reflects asynchronously) so this works in React.\n if (step.current) {\n if (!currentAssigned) {\n currentAssigned = true;\n } else {\n step.current = false;\n }\n }\n\n // Set first\n if (i === 0) {\n step.setAttribute(\"first\", \"\");\n } else {\n step.removeAttribute(\"first\");\n }\n\n // Set previous\n if (step.current) {\n foundCurrent = true;\n step.previous = false;\n } else if (!foundCurrent) {\n step.previous = true;\n } else {\n step.previous = false;\n }\n\n // Handle selected, respect first instance\n if (step.selected) {\n if (foundCurrent || selectedAssigned) {\n step.selected = false;\n } else {\n selectedAssigned = true;\n }\n }\n\n // Handle compact expanded\n if (this.isCompactExpanded) {\n step.setAttribute(\"isCompactExpanded\", \"\");\n } else {\n step.removeAttribute(\"isCompactExpanded\");\n }\n });\n\n // Selected fallback\n if (!selectedAssigned) {\n if (currentAssigned) {\n steps.forEach((step) => {\n if (step.current && !selectedAssigned) {\n step.setAttribute(\"selected\", \"\");\n selectedAssigned = true;\n }\n });\n } else if (steps.length > 0) {\n // If no current or selected, mark first as both current and selected\n steps[0].setAttribute(\"current\", \"\");\n steps[0].setAttribute(\"selected\", \"\");\n }\n }\n\n // Always update counter\n this._updateCounter();\n }\n\n private _toggleCompact() {\n this.isCompactExpanded = !this.isCompactExpanded;\n }\n\n private _handleCounterKeydown(event: KeyboardEvent) {\n if (event.key === \" \" || event.key === \"Enter\") {\n event.preventDefault();\n this._toggleCompact();\n }\n }\n\n render() {\n return html`\n <div class=\"cob-stepper\" name=${this.name}>\n <div class=\"cob-stepper__header\">\n <slot name=\"actions\" @slotchange=${this._validateButtonSlot}></slot>\n <div class=\"cob-stepper__headertext\">\n <div class=\"cob-stepper__label\">${this.label}</div>\n <div\n class=\"cob-stepper__counter\"\n @click=${this._toggleCompact}\n @keydown=${this._handleCounterKeydown}\n role=\"button\"\n tabindex=\"0\"\n aria-label=${this.isCompactExpanded\n ? \"Collapse step navigation to view the form\"\n : `Expand step navigation. You are on ${this.counterText}`}\n aria-expanded=${this.isCompactExpanded ? \"true\" : \"false\"}\n >\n ${this.counterText}\n </div>\n </div>\n </div>\n <slot class=\"cob-stepper__steps\"></slot>\n </div>\n `;\n }\n}\n\nif (!customElements.get(\"cob-stepper\")) {\n customElements.define(\"cob-stepper\", CobStepper);\n}\n"],"names":["_CobStep","LitElement","event","html","unsafeCSS","styles","CobStep","__decorateClass","property","stepperIdCounter","_CobStepper","clickedStep","el","steps","currentIndex","step","clickedIndex","child","isStep","isSlotActionsContainer","assignedElements","div","button","newCounterText","selectedIndex","totalSteps","index","foundCurrent","selectedAssigned","currentAssigned","CobStepper"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cob-stepper.js","sources":["../../internals/dist/index.js","../src/cob-step.ts","../src/cob-stepper.ts"],"sourcesContent":["import { LitElement as u } from \"lit\";\n/*!\n * City of Boston Web Design System v1.23.1\n * Description: A web design system for the City of Boston's digital products.\n * Repository: https://github.com/CityOfBoston/nywds-poc\n * License: MIT\n */\nlet p = 0;\nfunction f(e) {\n return `${e}-${Date.now()}-${p++}`;\n}\nfunction I(e, t, n) {\n e.dispatchEvent(\n new CustomEvent(t, { detail: n, bubbles: !0, composed: !0 })\n );\n}\nfunction w(e, t) {\n e.dispatchEvent(\n new Event(`cob-${t}`, { bubbles: !0, composed: !0 })\n );\n}\nconst g = {\n labelledby: \"ariaLabelledByElements\",\n describedby: \"ariaDescribedByElements\"\n}, _ = {\n labelledby: \"ariaLabel\",\n describedby: \"ariaDescription\"\n};\nfunction y(e) {\n return \"ariaDescribedByElements\" in e;\n}\nfunction E(e) {\n return e === \"errormessage\" ? \"aria-errormessage\" : `aria-${e}`;\n}\nfunction d(e) {\n return e.filter((t) => !!t);\n}\nfunction A(e) {\n return e.map((t) => (t.id || (t.id = f(\"cob-ref\")), t.id));\n}\nfunction x(e, t, n) {\n const r = d(n), i = E(t);\n r.length ? e.setAttribute(i, A(r).join(\" \")) : e.removeAttribute(i);\n}\nfunction L(e, t, n, r, i) {\n const s = d(r), a = g[n], l = t;\n if (a && y(t)) {\n l[a] = s.length ? s : null;\n return;\n }\n const o = _[n];\n if (!o) return;\n const c = i ?? (s.length ? s.map((m) => m.textContent?.trim() ?? \"\").filter(Boolean).join(\" \") : \"\");\n o in l ? l[o] = c || null : c ? e.setAttribute(\n n === \"labelledby\" ? \"aria-label\" : \"aria-description\",\n c\n ) : e.removeAttribute(\n n === \"labelledby\" ? \"aria-label\" : \"aria-description\"\n );\n}\nconst R = {\n labelledby: \"ariaLabelledByElements\",\n describedby: \"ariaDescribedByElements\"\n}, C = {\n labelledby: \"aria-label\",\n describedby: \"aria-description\"\n};\nfunction P(e, t, n) {\n const r = d(n), i = R[t], s = C[t], a = e;\n if (i && i in e && (a[i] = r.length ? r : null), !s) return;\n const l = r.map((o) => o.textContent?.trim() ?? \"\").filter(Boolean).join(\" \");\n l ? e.setAttribute(s, l) : e.removeAttribute(s);\n}\nconst b = (e) => {\n class t extends e {\n get idPrefix() {\n return this.localName || \"cob-element\";\n }\n ensureId() {\n this.id || (this.id = f(this.idPrefix));\n }\n connectedCallback() {\n super.connectedCallback(), this.ensureId();\n }\n }\n return t;\n}, T = /* @__PURE__ */ b(u), h = (e) => {\n class t extends b(e) {\n constructor() {\n super(...arguments), this.__internals = null;\n }\n get internals() {\n if (this.__internals) return this.__internals;\n if (typeof this.attachInternals == \"function\")\n try {\n this.__internals = this.attachInternals();\n } catch {\n this.__internals = null;\n }\n return this.__internals;\n }\n get defaultRole() {\n return null;\n }\n setHostAria(r, i) {\n const s = this.internals;\n if (s && r in s) {\n s[r] = i;\n return;\n }\n const a = V(r);\n i === null ? this.removeAttribute(a) : this.setAttribute(a, i);\n }\n reflectDefaultSemantics() {\n const r = this.defaultRole;\n r && this.setHostAria(\"role\", r);\n }\n connectedCallback() {\n super.connectedCallback(), this.reflectDefaultSemantics();\n }\n }\n return t;\n};\nfunction V(e) {\n if (e === \"role\") return \"role\";\n const t = e.replace(/^aria/, \"\");\n return \"aria-\" + t.charAt(0).toLowerCase() + t.slice(1);\n}\nconst O = /* @__PURE__ */ h(u), v = (e) => {\n const n = class n extends h(e) {\n constructor() {\n super(...arguments), this.__internalValidationMessage = \"\";\n }\n get internalValidationMessage() {\n return this.__internalValidationMessage;\n }\n set internalValidationMessage(i) {\n i !== this.__internalValidationMessage && (this.__internalValidationMessage = i, this.requestUpdate(\"internalValidationMessage\"));\n }\n resolvedErrorMessage() {\n return this.errorMessage || this.internalValidationMessage;\n }\n setFormValue(i) {\n this.internals?.setFormValue(i ?? null);\n }\n setValidityFromState(i, s, a) {\n const l = this.internals;\n if (!l) return;\n const o = Object.values(i).some(Boolean);\n o ? l.setValidity(i, s ?? \"Invalid value\", a) : l.setValidity({}), this.setHostAria(\"ariaInvalid\", o ? \"true\" : \"false\");\n }\n clearValidity() {\n this.internals?.setValidity({}), this.setHostAria(\"ariaInvalid\", \"false\");\n }\n checkValidity() {\n return this.internals?.checkValidity() ?? !0;\n }\n reportValidity() {\n return this.internals?.reportValidity() ?? !0;\n }\n formResetCallback() {\n this.internalValidationMessage = \"\", this.clearValidity();\n }\n };\n n.formAssociated = !0;\n let t = n;\n return t;\n}, B = /* @__PURE__ */ v(u);\nfunction N(e) {\n const t = e.tagName.toLowerCase(), n = /* @__PURE__ */ new Set(), r = (i) => {\n i.querySelectorAll(\"*\").forEach((s) => {\n const a = s.tagName.toLowerCase();\n a.startsWith(\"cob-\") && a !== t && !customElements.get(a) && n.add(a), s.shadowRoot && r(s.shadowRoot);\n });\n };\n return e.shadowRoot && r(e.shadowRoot), r(e), [...n].sort();\n}\nexport {\n T as CobElement,\n B as CobFormControlElement,\n O as CobReflectsAriaElement,\n v as FormControlMixin,\n b as IdentifiedMixin,\n h as ReflectsAriaMixin,\n x as associateControl,\n P as associateControlRefs,\n L as associateHost,\n I as dispatchCobEvent,\n w as dispatchCobFocusBlur,\n N as findUnregisteredChildren,\n f as generateId,\n y as supportsElementRefs\n};\n//# sourceMappingURL=index.js.map\n","import { html, unsafeCSS } from \"lit\";\nimport { property } from \"lit/decorators.js\";\nimport { ifDefined } from \"lit/directives/if-defined.js\";\nimport { CobElement } from \"@cobwds/internals\";\n// @ts-ignore: SCSS module imported via bundler as inline\nimport styles from \"./cob-stepper.scss?inline\";\n\n/** Detail payload for the `cob-step-click` event fired by `cob-step`. */\nexport interface CobStepClickDetail {\n href: string;\n label: string;\n}\n\n/** The `cob-step-click` event fired by `cob-step`. */\nexport type CobStepClickEvent = CustomEvent<CobStepClickDetail>;\n\n/**\n * A single step within `cob-stepper`. Represents one stage in a multi-step process.\n *\n * Mark as `current` to indicate the active progress point. Previous steps become clickable for navigation.\n * Set `href` for page-based navigation, or omit it and listen to `cob-step-click` for SPA/framework routing.\n *\n * ## Step states\n *\n * Three boolean attributes control step appearance and behavior:\n *\n * - **`current`** — The furthest step the user has reached (the progress boundary). Only one step should\n * have `current` at a time; if multiple are set the parent stepper keeps the first and removes the rest.\n * Steps after `current` are not navigable and do not fire `cob-step-click`. Update `current` in your\n * application state when the user advances.\n *\n * - **`selected`** — Which step's content is currently displayed. Defaults to the `current` step if not\n * explicitly set. If `selected` is placed on a step after `current`, the stepper silently corrects it\n * to match `current`. When managing state from a framework, always set `selected` explicitly — without\n * it the stepper's fallback will reset in-sidebar navigation on every state update.\n *\n * - **`previous`** — Auto-applied by the parent stepper to every step before `current`. Do not set this\n * manually. Steps with `previous` are clickable and fire `cob-step-click`.\n *\n * ## `cob-step-click` firing conditions\n *\n * The event fires only when ALL of the following are true:\n * 1. The step has `previous` or `current` (i.e. it is navigable).\n * 2. The step does NOT already have `selected` (clicking the already-viewed step is a no-op).\n *\n * Steps that are neither `previous` nor `current` (future steps) never fire the event.\n *\n * ## `href` and navigation\n *\n * If `href` is set, the stepper calls `window.location.href = href` after dispatching `cob-step-click`\n * — but only if the event was **not canceled**. To handle navigation yourself (SPA routing, fetch, etc.),\n * always call `e.preventDefault()` in your listener. Omitting `href` entirely is simpler for SPAs.\n *\n * ## `onClick` vs `cob-step-click`\n *\n * The `onClick` property (a function reference, not a DOM attribute) is called **before** the\n * `cob-step-click` event is dispatched. Use it for imperative pre-navigation logic. In React, pass it\n * as the `onClick` prop on `CobStep`.\n *\n * ## Accessibility\n * - The host carries `role=\"listitem\"` so the parent stepper's `<ol>` and its slotted\n * `<cob-step>` children form a real list — assistive technology announces each step's\n * position and count (e.g. \"2 of 4\") automatically.\n * - Navigable steps (`current`, `previous`, `selected`) render a real `<button>` for their\n * row, giving native keyboard activation (Enter/Space), focus handling, and semantics for\n * free — no manual `tabindex`/`keydown` scaffolding required.\n * - Future (non-navigable) steps render the row as a plain, non-interactive `<div>` — not a\n * disabled button. They are not focusable and carry no `role`, `tabindex`, or `aria-disabled`.\n * - `aria-label` announces the step name and 1-indexed position, e.g. `\"Personal Info, step 1\"`.\n * - The `current` step (progress boundary) is marked with `aria-current=\"step\"` on the\n * `<button>` itself so assistive technology announces the user's current position.\n * - The visual step number is `aria-hidden` (its meaning is folded into the row's accessible name).\n *\n * ## Common patterns\n *\n * **Initial state:** Set `current` on the first step. `selected` defaults to it.\n * ```html\n * <cob-step label=\"Step 1\" current></cob-step>\n * <cob-step label=\"Step 2\"></cob-step>\n * ```\n *\n * **User completed step 1, now on step 2:**\n * ```html\n * <cob-step label=\"Step 1\"></cob-step>\n * <cob-step label=\"Step 2\" current></cob-step>\n * ```\n *\n * **User went back to review step 1 (progress still at step 2):**\n * ```html\n * <cob-step label=\"Step 1\" selected></cob-step>\n * <cob-step label=\"Step 2\" current></cob-step>\n * ```\n *\n * @summary Individual step for use within cob-stepper with navigation support.\n * @element cob-step\n *\n * @fires {CobStepClickEvent} cob-step-click - Fired when a navigable (`previous` or `current`) non-selected step is clicked\n * or activated by keyboard. Detail: `{ href: string, label: string }`. Cancelable — call\n * `e.preventDefault()` to suppress `window.location.href` navigation.\n */\nexport class CobStep extends CobElement {\n static styles = unsafeCSS(styles);\n\n /**\n * Which step is currently being displayed. If not set, defaults to the `current` step.\n * Setting this on a step after `current` is silently corrected to match `current`.\n * When controlling state from a framework, always set this explicitly.\n */\n @property({ type: Boolean, reflect: true }) selected = false;\n\n /** The furthest step the user has reached (progress boundary). Steps before this are navigable. */\n @property({ type: Boolean, reflect: true }) current = false;\n\n /** Step label text displayed alongside the step number. */\n @property({ type: String }) label = \"\";\n\n /**\n * URL navigated to when the step is activated, via `window.location.href`.\n * Navigation is suppressed if the `cob-step-click` listener calls `e.preventDefault()`.\n * Omit for SPA/framework routing and handle navigation in the event listener instead.\n */\n @property({ type: String }) href = \"\";\n\n /**\n * @internal Auto-applied by `cob-stepper` to every step that comes before `current`.\n * Marks the step as navigable and clickable. Do not set this manually — the parent stepper\n * adds and removes it on every render based on which step has `current`.\n */\n @property({ type: Boolean, reflect: true }) previous = false;\n\n /** @internal Propagated by the parent stepper. Do not set manually. */\n @property({ type: Boolean }) isCompactExpanded = false;\n\n /** Optional function called before `cob-step-click` is dispatched. Use for pre-navigation logic. */\n @property({ attribute: false }) onClick?: (e: Event) => void;\n\n /** @internal 1-indexed position. Auto-assigned by the parent stepper on first render. Do not set manually. */\n @property({ type: Number }) stepNumber = 0;\n\n /** A step is navigable (focusable + activatable) when it is the displayed,\n * current, or a previously-reached step. Future steps are inert. */\n private get _navigable(): boolean {\n return this.selected || this.current || this.hasAttribute(\"previous\");\n }\n\n // ---------------------------------------------------------------------------\n // Lifecycle\n // ---------------------------------------------------------------------------\n\n /**\n * Sets `role=\"listitem\"` on the host so the parent stepper's `<ol>` (which\n * only ever slots `<cob-step>` elements, never real `<li>`s) still forms a\n * valid ARIA list. This is what lets assistive technology announce each\n * step's position and count. Uses a plain attribute (not ElementInternals)\n * so `getAttribute(\"role\")` keeps working for existing consumers/tests,\n * matching the convention used by `<cob-tab>`.\n */\n connectedCallback() {\n super.connectedCallback();\n this.setAttribute(\"role\", \"listitem\");\n }\n\n private _handleActivate(e: Event) {\n // Run user-supplied onClick first (if present)\n if (typeof this.onClick === \"function\") {\n this.onClick(e);\n }\n\n // Dispatch event as cancelable so user can prevent navigation\n const event = new CustomEvent(\"cob-step-click\", {\n bubbles: true,\n composed: true,\n cancelable: true,\n detail: { href: this.href, label: this.label },\n });\n\n if ((this.hasAttribute(\"previous\") || this.current) && !this.selected) {\n this.dispatchEvent(event);\n\n // Only navigate if event was not canceled\n if (!event.defaultPrevented && this.href) {\n window.location.href = this.href;\n }\n }\n }\n\n render() {\n const navigable = this._navigable;\n const accessibleName = this.stepNumber\n ? `${this.label}, step ${this.stepNumber}`\n : `${this.label} Step`;\n\n const rowContent = html`\n <div class=\"cob-step__number\" aria-hidden=\"true\">${this.stepNumber}</div>\n <div class=\"cob-step__content\">\n <div class=\"cob-step__label\">${this.label}</div>\n </div>\n `;\n\n return html`\n <div class=\"cob-step\">\n <div class=\"cob-step__linewrapper\">\n <div class=\"cob-step__line\"></div>\n </div>\n ${navigable\n ? html`\n <button\n type=\"button\"\n class=\"cob-step__contentwrapper\"\n @click=${this._handleActivate}\n aria-label=${accessibleName}\n aria-current=${ifDefined(this.current ? \"step\" : undefined)}\n >\n ${rowContent}\n </button>\n `\n : html`\n <div\n class=\"cob-step__contentwrapper\"\n aria-label=${accessibleName}\n >\n ${rowContent}\n </div>\n `}\n </div>\n `;\n }\n}\n\nif (!customElements.get(\"cob-step\")) {\n customElements.define(\"cob-step\", CobStep);\n}\n","import { html, unsafeCSS } from \"lit\";\nimport { property } from \"lit/decorators.js\";\nimport { CobElement } from \"@cobwds/internals\";\nimport \"./cob-step\";\n// @ts-ignore: SCSS module imported via bundler as inline\nimport styles from \"./cob-stepper.scss?inline\";\n\n/**\n * A multi-step progress indicator for forms or wizards. Manages `cob-step` children with selection and navigation.\n *\n * Add `cob-step` elements as children. Mark one step as `current` to indicate the progress boundary; all steps\n * before it become navigable. Compact view on mobile expands to show all steps. Use the `actions` slot for\n * persistent navigation buttons (e.g., Save & Exit). Do not place the stepper inside a `<form>` element —\n * put form fields in the main content area alongside it.\n *\n * ## When to use\n * - Linear, ordered forms or wizards with more than 2 sections.\n *\n * ## When not to use\n * - Forms with only 1 or 2 sections — use a simpler layout.\n * - Non-linear forms where sections can be completed in any order.\n *\n * ## Compact mode (mobile)\n * On small screens the stepper collapses to a compact view: step labels are hidden and progress\n * is shown as a bar indicator with a \"Step x of y\" counter. Clicking or pressing Enter/Space on\n * the counter expands the full step list (counter text changes to \"Back to Form\"). Collapsing\n * again returns the user to the form view.\n *\n * ## actions slot constraints\n * The `actions` slot must contain exactly one `<div>` as its direct child. That `<div>` may only\n * contain `<cob-button>` elements — any other element is removed with a console warning.\n * The stepper automatically forces `size=\"sm\"` on every button in the slot. Buttons with the\n * `fullWidth` attribute get `flex: 1 1 0` injected so they share available width equally.\n *\n * ## Multiple `current` conflict\n * If more than one `cob-step` has the `current` attribute, only the first one is kept; the rest\n * are silently removed. Always mark exactly one step as `current`.\n *\n * ## id auto-generation\n * If no `id` is provided, a unique id is generated automatically in the form\n * `cob-stepper-{timestamp}-{n}`.\n *\n * ## Accessibility\n * - The compact counter is rendered as a `role=\"button\"` with `aria-expanded` and a descriptive\n * `aria-label` that announces the current step (e.g., \"Expand step navigation. You are on Step 2 of 4\").\n * - Keyboard: Enter or Space toggles the compact view.\n * - Steps are rendered inside an `<ol>` so assistive technology announces each step's position\n * and count (e.g. \"2 of 4\"). Each slotted `<cob-step>` carries `role=\"listitem\"` since it\n * can't itself be a real `<li>`.\n * - Navigable steps render as real `<button>` elements — keyboard-focusable and activatable\n * (Enter/Space) natively. Future (non-navigable) steps render as plain, non-interactive rows.\n * - Visual focus indicators are provided on all interactive elements.\n *\n * @summary Multi-step progress indicator with navigation and mobile-friendly compact view.\n * @element cob-stepper\n *\n * @slot - Default slot for `cob-step` elements. Only `cob-step` children are accepted; others are removed.\n * @slot actions - Persistent navigation buttons. Must contain exactly one `<div>` wrapping only `<cob-button>` elements.\n *\n * @usage\n * - Use for linear, ordered forms with more than 2 sections to show progress through a multi-step process.\n * - Ensure users can navigate back to previous steps to review or change information.\n * - Don't use when a form has only 1 or 2 sections.\n * - Don't use for forms that are nonlinear and can be completed in any order.\n *\n * @example Basic\n * ```html\n * <div class=\"cob-grid-row\">\n * <cob-stepper\n * id=\"stepper\"\n * name=\"stepper\"\n * label=\"Register for Web Design System Office Hours\"\n * class=\"cob-desktop:cob-grid-col-3\"\n * >\n * <cob-step label=\"Personal Details\" href=\"/cob-stepper/personal.html\"></cob-step>\n * <cob-step label=\"Team Info\" selected href=\"/cob-stepper/team.html\"></cob-step>\n * <cob-step label=\"Usage Survey\" current href=\"/cob-stepper/survey.html\"></cob-step>\n * <cob-step label=\"Newsletter Opt-In\" href=\"/cob-stepper/newsletter.html\"></cob-step>\n * <div slot=\"actions\">\n * <cob-button variant=\"outline\" label=\"Save & Exit\" fullWidth></cob-button>\n * </div>\n * </cob-stepper>\n * <div class=\"cob-desktop:cob-grid-col-9\" id=\"cob-stepper-content\">\n * Loading...\n * </div>\n * </div>\n * ```\n * @render Basic\n * ```html\n * <div class=\"cob-grid-row\">\n * <cob-stepper\n * id=\"stepper\"\n * name=\"stepper\"\n * label=\"Register for Web Design System Office Hours\"\n * class=\"cob-desktop:cob-grid-col-3\"\n * >\n * <cob-step label=\"Personal Details\" href=\"/cob-stepper/personal.html\"></cob-step>\n * <cob-step label=\"Team Info\" selected href=\"/cob-stepper/team.html\"></cob-step>\n * <cob-step label=\"Usage Survey\" current href=\"/cob-stepper/survey.html\"></cob-step>\n * <cob-step label=\"Newsletter Opt-In\" href=\"/cob-stepper/newsletter.html\"></cob-step>\n * </cob-stepper>\n * <div class=\"cob-desktop:cob-grid-col-9\" id=\"cob-stepper-content\">\n * Loading...\n * </div>\n * </div>\n * <script>\n * document.addEventListener(\"DOMContentLoaded\", async () => {\n * const stepper = document.querySelector(\"cob-stepper\");\n * if (stepper?.updateComplete) await stepper.updateComplete;\n * const selectedStep = document.querySelector(\"cob-step[selected]\");\n * const href = selectedStep?.getAttribute(\"href\");\n * if (!href) return;\n * const res = await fetch(href);\n * if (!res.ok) return;\n * const container = document.querySelector(\"#cob-stepper-content\");\n * if (container) container.innerHTML = await res.text();\n * });\n *\n * document.addEventListener(\"cob-step-click\", async (e) => {\n * const href = e.detail?.href;\n * if (!href) return;\n * e.preventDefault();\n * const res = await fetch(href);\n * if (!res.ok) return;\n * const container = document.querySelector(\"#cob-stepper-content\");\n * if (container) container.innerHTML = await res.text();\n * });\n * </script>\n * ```\n *\n * @example Actions slot\n * ```html\n * <div class=\"cob-grid-row\">\n * <cob-stepper\n * id=\"stepper\"\n * name=\"stepper\"\n * label=\"Register for Web Design System Office Hours\"\n * class=\"cob-desktop:cob-grid-col-3\"\n * >\n * <cob-step label=\"Personal Details\" href=\"/cob-stepper/personal.html\"></cob-step>\n * <cob-step label=\"Team Info\" selected href=\"/cob-stepper/team.html\"></cob-step>\n * <cob-step label=\"Usage Survey\" current href=\"/cob-stepper/survey.html\"></cob-step>\n * <cob-step label=\"Newsletter Opt-In\" href=\"/cob-stepper/newsletter.html\"></cob-step>\n * <div slot=\"actions\">\n * <cob-button variant=\"outline\" label=\"Save & Exit\" fullWidth></cob-button>\n * </div>\n * </cob-stepper>\n * <div class=\"cob-desktop:cob-grid-col-9\" id=\"cob-stepper-content\">\n * Loading...\n * </div>\n * </div>\n * ```\n * @render Actions slot\n * ```html\n * <div class=\"cob-grid-row\">\n * <cob-stepper\n * id=\"stepper\"\n * name=\"stepper\"\n * label=\"Register for Web Design System Office Hours\"\n * class=\"cob-desktop:cob-grid-col-3\"\n * >\n * <cob-step label=\"Personal Details\" href=\"/cob-stepper/personal.html\"></cob-step>\n * <cob-step label=\"Team Info\" selected href=\"/cob-stepper/team.html\"></cob-step>\n * <cob-step label=\"Usage Survey\" current href=\"/cob-stepper/survey.html\"></cob-step>\n * <cob-step label=\"Newsletter Opt-In\" href=\"/cob-stepper/newsletter.html\"></cob-step>\n * <div slot=\"actions\">\n * <cob-button variant=\"outline\" label=\"Save & Exit\" fullWidth></cob-button>\n * </div>\n * </cob-stepper>\n * <div class=\"cob-desktop:cob-grid-col-9\" id=\"cob-stepper-content\">\n * Loading...\n * </div>\n * </div>\n * <script>\n * document.addEventListener(\"DOMContentLoaded\", async () => {\n * const stepper = document.querySelector(\"cob-stepper\");\n * if (stepper?.updateComplete) await stepper.updateComplete;\n * const selectedStep = document.querySelector(\"cob-step[selected]\");\n * const href = selectedStep?.getAttribute(\"href\");\n * if (!href) return;\n * const res = await fetch(href);\n * if (!res.ok) return;\n * const container = document.querySelector(\"#cob-stepper-content\");\n * if (container) container.innerHTML = await res.text();\n * });\n *\n * document.addEventListener(\"cob-step-click\", async (e) => {\n * const href = e.detail?.href;\n * if (!href) return;\n * e.preventDefault();\n * const res = await fetch(href);\n * if (!res.ok) return;\n * const container = document.querySelector(\"#cob-stepper-content\");\n * if (container) container.innerHTML = await res.text();\n * });\n * </script>\n * ```\n */\n\nexport class CobStepper extends CobElement {\n static styles = unsafeCSS(styles);\n\n /** Unique identifier. Auto-generated as `cob-stepper-{timestamp}-{n}` if not provided. */\n @property({ type: String, reflect: true }) id = \"\";\n\n /** Name attribute for form association. */\n @property({ type: String, reflect: true }) name = \"\";\n\n /** Title displayed above the step list and compact counter. */\n @property({ type: String }) label = \"\";\n\n /** Progress text displayed in compact mode (e.g., \"Step 2 of 5\"). Auto-managed — do not set manually. */\n @property({ type: String }) counterText = \"initial\";\n\n /** Whether compact mobile view is expanded to show all steps. Toggled by clicking the counter. */\n @property({ type: Boolean, reflect: true })\n isCompactExpanded = false;\n\n private _stepsNumbered = false;\n\n connectedCallback() {\n // super.connectedCallback() (CobElement) assigns an auto id when\n // one is not provided, preserving the `cob-stepper-<ts>-<n>` shape. The\n // landmark/navigation role lives on the inner <nav> element (so it groups the\n // slotted steps), so this component keeps defaultRole = null and does not move\n // a role onto the host.\n super.connectedCallback();\n this.addEventListener(\"cob-step-click\", this._onStepClick);\n // Defer step validation to next tick to ensure children are upgraded\n requestAnimationFrame(() => this._validateSteps());\n }\n\n disconnectedCallback() {\n this.removeEventListener(\"cob-step-click\", this._onStepClick);\n super.disconnectedCallback();\n }\n\n private _validateSteps() {\n Array.from(this.children).forEach((child) => {\n const isStep =\n child instanceof HTMLElement &&\n child.tagName.toLowerCase() === \"cob-step\";\n const isSlotActionsContainer =\n child instanceof HTMLElement &&\n child.hasAttribute(\"slot\") &&\n child.getAttribute(\"slot\") === \"actions\";\n\n if (!isStep && !isSlotActionsContainer) {\n console.warn(\n \"Only <cob-step> elements or the <div slot='actions'> container are allowed as direct children of <cob-stepper>. Removing:\",\n child,\n );\n child.remove();\n }\n });\n }\n\n private _validateButtonSlot(event: Event) {\n const slot = event.target as HTMLSlotElement;\n const assignedElements = slot.assignedElements();\n\n // Ensure exactly one direct node in the slot, and it must be a div\n if (\n assignedElements.length !== 1 ||\n assignedElements[0].tagName.toLowerCase() !== \"div\"\n ) {\n console.warn(\n \"The 'actions' slot must have exactly one <div> as a direct child.\",\n );\n return;\n }\n\n const div = assignedElements[0] as HTMLElement;\n\n // Iterate through all buttons and validate\n Array.from(div.children).forEach((button) => {\n const isCobButton =\n button instanceof HTMLElement &&\n button.tagName.toLowerCase() === \"cob-button\";\n\n if (!isCobButton) {\n console.warn(\n \"The <div> inside 'actions' slot only accepts <cob-button> elements. Removing invalid node:\",\n button,\n );\n button.remove();\n } else {\n // Ensure cob-button has correct styles\n button.setAttribute(\"size\", \"sm\");\n if (button.hasAttribute(\"fullWidth\")) {\n button.style.flex = \"1 1 0\";\n }\n }\n });\n }\n\n private _onStepClick = async (event: Event) => {\n const clickedStep = event\n .composedPath()\n .find(\n (el) =>\n el instanceof HTMLElement && el.tagName.toLowerCase() === \"cob-step\",\n ) as HTMLElement | undefined;\n\n if (!clickedStep) return;\n\n const steps = Array.from(this.querySelectorAll(\"cob-step\"));\n const currentIndex = steps.findIndex((step) =>\n step.hasAttribute(\"current\"),\n );\n const clickedIndex = steps.indexOf(clickedStep);\n\n // Can't select past current\n if (currentIndex !== -1 && clickedIndex > currentIndex) return;\n\n // Can't select already selected\n if (clickedStep.hasAttribute(\"selected\")) return;\n\n // Remove selected from previous and move to new selected\n steps.forEach((step) => step.removeAttribute(\"selected\"));\n clickedStep.setAttribute(\"selected\", \"\");\n\n // Update counter immediately\n this._updateCounter();\n\n // Close expanded if it was open\n this.isCompactExpanded = false;\n };\n\n private _updateCounter() {\n let newCounterText: string;\n\n if (this.isCompactExpanded) {\n newCounterText = \"Back to Form\";\n this.style.height = \"-webkit-fit-content\";\n this.style.height = \"-moz-fit-content\";\n this.style.height = \"fit-content\";\n } else {\n this.style.height = \"auto\";\n\n const steps = this.querySelectorAll<HTMLElement>(\"cob-step\");\n const selectedIndex = Array.from(steps).findIndex((step) =>\n step.hasAttribute(\"selected\"),\n );\n const totalSteps = steps.length;\n\n newCounterText =\n selectedIndex >= 0\n ? `Step ${selectedIndex + 1} of ${totalSteps}`\n : `Step 1 of ${totalSteps}`;\n }\n\n if (newCounterText !== this.counterText) {\n this.counterText = newCounterText;\n }\n }\n\n willUpdate() {\n const steps = this.querySelectorAll<any>(\"cob-step\");\n\n if (!this._stepsNumbered) {\n steps.forEach((step, index) => {\n step.stepNumber = index + 1;\n });\n this._stepsNumbered = true;\n }\n\n let foundCurrent = false;\n let selectedAssigned = false;\n let currentAssigned = false;\n\n steps.forEach((step, i) => {\n // Check if multiple \"current\" exist, respect the first instance.\n // Read the Lit property (set synchronously by frameworks) rather than the\n // DOM attribute (which Lit reflects asynchronously) so this works in React.\n if (step.current) {\n if (!currentAssigned) {\n currentAssigned = true;\n } else {\n step.current = false;\n }\n }\n\n // Set first\n if (i === 0) {\n step.setAttribute(\"first\", \"\");\n } else {\n step.removeAttribute(\"first\");\n }\n\n // Set previous\n if (step.current) {\n foundCurrent = true;\n step.previous = false;\n } else if (!foundCurrent) {\n step.previous = true;\n } else {\n step.previous = false;\n }\n\n // Handle selected, respect first instance\n if (step.selected) {\n if (foundCurrent || selectedAssigned) {\n step.selected = false;\n } else {\n selectedAssigned = true;\n }\n }\n\n // Handle compact expanded\n if (this.isCompactExpanded) {\n step.setAttribute(\"isCompactExpanded\", \"\");\n } else {\n step.removeAttribute(\"isCompactExpanded\");\n }\n });\n\n // Selected fallback\n if (!selectedAssigned) {\n if (currentAssigned) {\n steps.forEach((step) => {\n if (step.current && !selectedAssigned) {\n step.setAttribute(\"selected\", \"\");\n selectedAssigned = true;\n }\n });\n } else if (steps.length > 0) {\n // If no current or selected, mark first as both current and selected\n steps[0].setAttribute(\"current\", \"\");\n steps[0].setAttribute(\"selected\", \"\");\n }\n }\n\n // Always update counter\n this._updateCounter();\n }\n\n private _toggleCompact() {\n this.isCompactExpanded = !this.isCompactExpanded;\n }\n\n private _handleCounterKeydown(event: KeyboardEvent) {\n if (event.key === \" \" || event.key === \"Enter\") {\n event.preventDefault();\n this._toggleCompact();\n }\n }\n\n render() {\n return html`\n <div class=\"cob-stepper\" name=${this.name}>\n <div class=\"cob-stepper__header\">\n <slot name=\"actions\" @slotchange=${this._validateButtonSlot}></slot>\n <div class=\"cob-stepper__headertext\">\n <div class=\"cob-stepper__label\">${this.label}</div>\n <div\n class=\"cob-stepper__counter\"\n @click=${this._toggleCompact}\n @keydown=${this._handleCounterKeydown}\n role=\"button\"\n tabindex=\"0\"\n aria-label=${this.isCompactExpanded\n ? \"Collapse step navigation to view the form\"\n : `Expand step navigation. You are on ${this.counterText}`}\n aria-expanded=${this.isCompactExpanded ? \"true\" : \"false\"}\n >\n ${this.counterText}\n </div>\n </div>\n </div>\n <nav\n class=\"cob-stepper__nav\"\n aria-label=${this.label?.trim()\n ? `${this.label} progress`\n : \"Progress\"}\n >\n <ol class=\"cob-stepper__steps\" role=\"list\">\n <slot></slot>\n </ol>\n </nav>\n </div>\n `;\n }\n}\n\nif (!customElements.get(\"cob-stepper\")) {\n customElements.define(\"cob-stepper\", CobStepper);\n}\n"],"names":["LitElement","unsafeCSS","html","property","ifDefined","p","f","e","b","t","T","u","_CobStep","CobElement","event","navigable","accessibleName","rowContent","styles","CobStep","__decorateClass","_CobStepper","clickedStep","el","steps","currentIndex","step","clickedIndex","child","isStep","isSlotActionsContainer","assignedElements","div","button","newCounterText","selectedIndex","totalSteps","index","foundCurrent","selectedAssigned","currentAssigned","CobStepper"],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cobwds/cob-stepper",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.23.1",
|
|
4
4
|
"description": "The Stepper component from the City of Boston Web Design System.",
|
|
5
5
|
"module": "dist/cob-stepper.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"exports": {
|
|
8
8
|
".": {
|
|
9
|
-
"
|
|
10
|
-
"
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"import": "./dist/cob-stepper.js"
|
|
11
11
|
}
|
|
12
12
|
},
|
|
13
13
|
"type": "module",
|
|
@@ -23,9 +23,10 @@
|
|
|
23
23
|
"lit-analyze": "lit-analyzer '**/*.ts'"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@cobwds/cob-button": "^1.
|
|
26
|
+
"@cobwds/cob-button": "^1.23.1"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
|
+
"@cobwds/internals": "^1.23.1",
|
|
29
30
|
"lit": "^3.3.1",
|
|
30
31
|
"typescript": "^5.9.3",
|
|
31
32
|
"vite": "^7.3.1"
|