@cobwds/mcp-server 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.
Files changed (35) hide show
  1. package/README.md +6 -15
  2. package/data/cem/custom-elements.json +10058 -6738
  3. package/data/frameworks.json +14 -0
  4. package/data/guides/form-validation.md +1 -1
  5. package/data/guides/frameworks/angular.md +184 -26
  6. package/data/guides/frameworks/react-additions.md +69 -0
  7. package/data/guides/frameworks/react.md +209 -27
  8. package/data/guides/frameworks/vue.md +356 -0
  9. package/data/tokens/tokens.css +2 -2
  10. package/data/tokens/tokens.json +3 -3
  11. package/dist/lib/cem-parser.d.ts +12 -0
  12. package/dist/lib/cem-parser.d.ts.map +1 -1
  13. package/dist/lib/framework-snippets.d.ts +36 -0
  14. package/dist/lib/framework-snippets.d.ts.map +1 -0
  15. package/dist/lib/framework-snippets.js +55 -0
  16. package/dist/lib/framework-usage.d.ts +20 -0
  17. package/dist/lib/framework-usage.d.ts.map +1 -0
  18. package/dist/lib/framework-usage.js +50 -0
  19. package/dist/lib/frameworks-data.d.ts +19 -0
  20. package/dist/lib/frameworks-data.d.ts.map +1 -0
  21. package/dist/lib/frameworks-data.js +40 -0
  22. package/dist/resources/frameworks.d.ts +15 -0
  23. package/dist/resources/frameworks.d.ts.map +1 -0
  24. package/dist/resources/frameworks.js +104 -0
  25. package/dist/resources/guides.d.ts.map +1 -1
  26. package/dist/resources/guides.js +12 -1
  27. package/dist/resources/index.d.ts.map +1 -1
  28. package/dist/resources/index.js +2 -0
  29. package/dist/tools/component-tools.d.ts.map +1 -1
  30. package/dist/tools/component-tools.js +20 -5
  31. package/dist/tools/guide-tools.js +1 -1
  32. package/dist/tools/utility-tools.d.ts +48 -0
  33. package/dist/tools/utility-tools.d.ts.map +1 -1
  34. package/dist/tools/utility-tools.js +236 -71
  35. package/package.json +6 -4
@@ -0,0 +1,14 @@
1
+ {
2
+ "react": {
3
+ "packageName": "@cobwds/react",
4
+ "version": "1.23.1"
5
+ },
6
+ "vue": {
7
+ "packageName": "@cobwds/vue",
8
+ "version": "1.23.1"
9
+ },
10
+ "angular": {
11
+ "packageName": "@cobwds/angular",
12
+ "version": "1.23.1"
13
+ }
14
+ }
@@ -165,5 +165,5 @@ The following COBWDS components support `showError` and `errorMessage`:
165
165
 
166
166
  1. **Error summary links**: Include anchor links to fields for keyboard navigation
167
167
  2. **Focus management**: Move focus to error summary or first error field on validation failure
168
- 3. **ARIA attributes**: COBWDS components automatically set `aria-invalid` and `aria-describedby`
168
+ 3. **ARIA attributes**: COBWDS form components automatically set `aria-invalid` on the control and associate the error message via `aria-errormessage`, and associate the visible `<cob-label>` with the control via `aria-labelledby` — no manual wiring needed
169
169
  4. **Clear error messages**: Use specific, actionable error text
@@ -1,16 +1,32 @@
1
- # COBWDS with Angular
1
+ <!--
2
+ GENERATED FILE. Do not edit directly.
3
+ Source: packages/angular/README.md
4
+ Regenerate with: npm run sync:guides -w @cobwds/mcp-server
5
+ -->
6
+ # @cobwds/angular
2
7
 
3
- > **Note:** Angular integration is currently untested. The guidance below is based on standard web component usage patterns and may require adjustments.
8
+ Angular components for the City of Boston Web Design System (COBWDS). Generated from the COBWDS web components library, with full support for template-driven forms, Reactive Forms, and Signal Forms.
4
9
 
5
- ## Installation
10
+ ## Install
11
+
12
+ ### Setup a new Angular project
13
+
14
+ ```bash
15
+ npm install -g @angular/cli
16
+ ng new my-angular-app
17
+ ```
18
+
19
+ ### Install NYS Design System
6
20
 
7
21
  ```bash
8
- npm install @cobwds/components @cobwds/styles
22
+ npm install @cobwds/angular @cobwds/styles
9
23
  ```
10
24
 
25
+ Peer dependencies: Angular `>=20.0.0` (core, common, forms).
26
+
11
27
  ## Load styles
12
28
 
13
- Add the COBWDS stylesheet to `angular.json`:
29
+ Add COBWDS styles to your `angular.json`:
14
30
 
15
31
  ```json
16
32
  {
@@ -20,8 +36,7 @@ Add the COBWDS stylesheet to `angular.json`:
20
36
  "build": {
21
37
  "options": {
22
38
  "styles": [
23
- "node_modules/@cobwds/styles/dist/cobwds-full.min.css",
24
- "src/styles.css"
39
+ "node_modules/@cobwds/styles/cobwds-full.min.css"
25
40
  ]
26
41
  }
27
42
  }
@@ -31,41 +46,184 @@ Add the COBWDS stylesheet to `angular.json`:
31
46
  }
32
47
  ```
33
48
 
34
- Use `cobwds-full.min.css` for new projects (includes reset, typography, and utilities) or `cobwds.min.css` for existing projects (CSS variables only).
49
+ ## First component
50
+
51
+ Import standalone components directly into your component:
35
52
 
36
- ## Configuration
53
+ ```typescript
54
+ import { Component, signal } from '@angular/core';
55
+ import { RouterOutlet } from '@angular/router';
56
+ import { CobButtonComponent } from '@cobwds/angular';
57
+ @Component({
58
+ imports: [RouterOutlet, CobButtonComponent],
59
+ selector: 'app-root',
60
+ styleUrl: './app.css',
61
+ templateUrl: './app.html',
62
+ })
63
+ export class App {
64
+ protected readonly title = signal('my-angular-app');
65
+ handleSubmit() {
66
+ console.log('Button clicked!');
67
+ }
68
+ }
69
+ ```
70
+
71
+ ## NgModule support has been deprecated
72
+
73
+ Use "Standalone Components" instead.
74
+
75
+ ## Inputs, outputs, and two-way binding
76
+
77
+ All properties are typed inputs; events are typed outputs. No `CUSTOM_ELEMENTS_SCHEMA` needed:
78
+
79
+ ```html
80
+ <cob-textinput
81
+ [label]="'Email'"
82
+ [required]="true"
83
+ (nysChange)="onEmailChange($event)"
84
+ ></cob-textinput>
85
+ ```
37
86
 
38
- Add `CUSTOM_ELEMENTS_SCHEMA` to your module so Angular allows custom element tags:
87
+ Event detail is typed:
39
88
 
40
89
  ```typescript
41
- import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
90
+ onEmailChange(event: CobTextinputChangeEvent) {
91
+ console.log(event.detail.value); // autocompletes
92
+ }
93
+ ```
42
94
 
43
- @NgModule({
44
- schemas: [CUSTOM_ELEMENTS_SCHEMA]
45
- })
46
- export class AppModule {}
95
+ ## Signal Forms Known Limitations
96
+
97
+ When using Angular's Signal Forms with `[formField]`, be aware of these constraints:
98
+
99
+ - **name property overwrite**: The `[formField]` binding overwrites the `name` attribute. This is an Angular Signal Forms limitation; there is no workaround on the component side. Use a different approach for form arrays that require distinct names.
100
+ - **pattern validation on empty array**: Angular's Signal Forms passes an empty array for unset pattern metadata. The component defensively ignores these writes; no action needed on your side.
101
+
102
+ ## Forms
103
+
104
+ ### Template-driven forms
105
+
106
+ Use `[(ngModel)]` with form components:
107
+
108
+ ```html
109
+ <form>
110
+ <cob-textinput [(ngModel)]="email" name="email"></cob-textinput>
111
+ <cob-checkbox [(ngModel)]="agreed" name="agreed"></cob-checkbox>
112
+ </form>
47
113
  ```
48
114
 
49
- For standalone components:
115
+ ### Reactive Forms
116
+
117
+ Use `formControl` or `formControlName`:
50
118
 
51
119
  ```typescript
52
- import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
120
+ form = this.fb.group({
121
+ email: ["", [Validators.required, Validators.email]],
122
+ agreed: [false, Validators.required],
123
+ });
124
+ ```
53
125
 
54
- @Component({
55
- schemas: [CUSTOM_ELEMENTS_SCHEMA],
56
- template: `<cob-button label="Click me"></cob-button>`
57
- })
58
- export class MyComponent {}
126
+ ```html
127
+ <form [formGroup]="form">
128
+ <cob-textinput formControlName="email"></cob-textinput>
129
+ <cob-checkbox formControlName="agreed"></cob-checkbox>
130
+ </form>
131
+ ```
132
+
133
+ ### Signal Forms (Angular 21+)
134
+
135
+ Use `[formField]` with a form field definition:
136
+
137
+ ```typescript
138
+ email = signal<string>("");
139
+ emailControl = new FormControl<string>("", Validators.required);
140
+ ```
141
+
142
+ ```html
143
+ <cob-textinput [formField]="emailControl"></cob-textinput>
144
+ ```
145
+
146
+ ### Group controls
147
+
148
+ `cob-checkboxgroup` and `cob-radiogroup` bind at group level:
149
+
150
+ ```typescript
151
+ form = this.fb.group({
152
+ languages: [["en"], Validators.required],
153
+ });
154
+ ```
155
+
156
+ ```html
157
+ <cob-checkboxgroup formControlName="languages">
158
+ <cob-checkbox value="en">English</cob-checkbox>
159
+ <cob-checkbox value="es">Spanish</cob-checkbox>
160
+ </cob-checkboxgroup>
161
+ ```
162
+
163
+ ### Validation
164
+
165
+ By default, the component owns validation. Its `required` and `pattern` attributes drive ElementInternals validation, shown on blur.
166
+
167
+ To let Angular own validation instead, add the `nysControlErrors` directive:
168
+
169
+ ```html
170
+ <cob-textinput
171
+ formControlName="email"
172
+ nysControlErrors
173
+ ></cob-textinput>
59
174
  ```
60
175
 
61
- ## Usage
176
+ The directive subscribes to `control.errors` and sets the component's `showError` and `errorMessage`. Override the default messages:
62
177
 
63
- Import components in the component or module where they're used:
178
+ ```typescript
179
+ providers: [
180
+ {
181
+ provide: NYS_ERROR_MESSAGES,
182
+ useValue: {
183
+ required: () => "Please fill in this field",
184
+ email: () => "Enter a valid email",
185
+ },
186
+ },
187
+ ]
188
+ ```
189
+
190
+ ### Disabled state
191
+
192
+ `FormControl({ disabled: true })` disables the component:
64
193
 
65
194
  ```typescript
66
- import '@cobwds/cob-button';
195
+ control = new FormControl({ value: "", disabled: true });
196
+ ```
197
+
198
+ ```html
199
+ <cob-textinput [formControl]="control"></cob-textinput>
67
200
  ```
68
201
 
202
+ ## Server-side rendering
203
+
204
+ The components render client-side. For SSR, wrap containers in `ngSkipHydration`:
205
+
69
206
  ```html
70
- <cob-button label="Click me"></cob-button>
207
+ <div ngSkipHydration>
208
+ <cob-textinput></cob-textinput>
209
+ </div>
71
210
  ```
211
+
212
+ Or use `provideClientHydration` if registering components client-only.
213
+
214
+ ## Zoneless
215
+
216
+ The component outputs use Angular's `output()` function, which integrates with zoneless change detection. Zoneless apps work without extra configuration.
217
+
218
+ ## Subpath imports
219
+
220
+ Import individual components:
221
+
222
+ ```typescript
223
+ import { CobTextinputComponent } from "@cobwds/angular/textinput";
224
+ import { CobCheckboxComponent } from "@cobwds/angular/checkbox";
225
+ ```
226
+
227
+ ## License
228
+
229
+ MIT
@@ -0,0 +1,69 @@
1
+ ## Using the stepper in React (multi-page pattern)
2
+
3
+ `cob-stepper` requires careful state management in React. Two state variables are needed:
4
+
5
+ - `currentStep` — the furthest step the user has reached (progress boundary). Maps to the `current` prop on `CobStep`.
6
+ - `viewingStep` — which step's content is currently displayed. Maps to the `selected` prop on `CobStep`.
7
+
8
+ **Always pass both `current` and `selected` explicitly from React state.** Without explicit `selected`, the stepper's internal fallback will override the user's sidebar navigation on every React re-render.
9
+
10
+ **Event listening:** Use `onCobStepClick` on each `CobStep` (not on `CobStepper`). Always call `e.preventDefault()` to suppress `href`-based page navigation.
11
+
12
+ **Do not use `href` for SPA routing.** Omit `href` and handle step changes entirely in React state.
13
+
14
+ **Do not place `<CobStepper>` inside a `<form>` element.**
15
+
16
+ ```tsx
17
+ import { useState } from 'react';
18
+ import { CobStepper, CobStep, CobButton } from '@cobwds/react';
19
+
20
+ const STEPS = [
21
+ { label: 'Personal Info', content: <PersonalInfoForm /> },
22
+ { label: 'Contact Details', content: <ContactForm /> },
23
+ { label: 'Review', content: <ReviewForm /> },
24
+ ];
25
+
26
+ export function MultiStepForm() {
27
+ const [currentStep, setCurrentStep] = useState(0);
28
+ const [viewingStep, setViewingStep] = useState(0);
29
+
30
+ function handleContinue() {
31
+ if (viewingStep < STEPS.length - 1) {
32
+ setCurrentStep(viewingStep + 1);
33
+ setViewingStep(viewingStep + 1);
34
+ }
35
+ }
36
+
37
+ return (
38
+ <div className="cob-grid-row">
39
+ <CobStepper label="Application" className="cob-grid-col-12 cob-desktop:cob-grid-col-3">
40
+ {STEPS.map((step, i) => (
41
+ <CobStep
42
+ key={i}
43
+ label={step.label}
44
+ current={i === currentStep}
45
+ selected={i === viewingStep}
46
+ onCobStepClick={(e) => { e.preventDefault(); setViewingStep(i); }}
47
+ />
48
+ ))}
49
+ <div slot="actions">
50
+ <CobButton label="Save & Exit" variant="outline" fullWidth />
51
+ </div>
52
+ </CobStepper>
53
+
54
+ <main className="cob-grid-col-12 cob-desktop:cob-grid-col-9">
55
+ {STEPS[viewingStep].content}
56
+ <div style={{ display: 'flex', gap: '8px', marginTop: '16px' }}>
57
+ {viewingStep > 0 && (
58
+ <CobButton label="Back" variant="outline"
59
+ onCobClick={() => setViewingStep((v) => v - 1)} />
60
+ )}
61
+ {viewingStep === currentStep && currentStep < STEPS.length - 1 && (
62
+ <CobButton label="Continue" onCobClick={handleContinue} />
63
+ )}
64
+ </div>
65
+ </main>
66
+ </div>
67
+ );
68
+ }
69
+ ```
@@ -1,48 +1,230 @@
1
- # COBWDS with React
1
+ <!--
2
+ GENERATED FILE. Do not edit directly.
3
+ Source: packages/react/README.md + data/guides/frameworks/react-additions.md
4
+ Regenerate with: npm run sync:guides -w @cobwds/mcp-server
5
+ -->
6
+ # @cobwds/react
2
7
 
3
- > **Note:** React integration is currently untested. The guidance below is based on standard web component usage patterns and may require adjustments.
8
+ React components for the City of Boston Web Design System (COBWDS). Generated from the COBWDS web components library.
4
9
 
5
- ## Installation
10
+ Works with React 18 and React 19, including Next.js App Router.
11
+
12
+ ## Install
13
+
14
+ ### Setup a new React project
6
15
 
7
16
  ```bash
8
- npm install @cobwds/components @cobwds/styles
17
+ npm create vite@latest my-app -- --template react-ts
18
+ ```
19
+
20
+ ### Install City of Boston Web Design System
21
+ ```sh
22
+ npm install @cobwds/react @cobwds/styles
9
23
  ```
10
24
 
11
25
  ## Load styles
12
26
 
13
- Import the COBWDS stylesheet in your app entry point (e.g., `index.tsx` or `App.tsx`):
27
+ Import the design system stylesheet once, in your app's main.tsx:
28
+
29
+ ```tsx
30
+ import "@cobwds/styles/full";
31
+ ```
32
+
33
+ Without it, components render unstyled. `@cobwds/styles` ships the
34
+ design tokens and global styles; component-level styles live in each
35
+ component's shadow DOM and need no extra setup.
36
+
37
+ ## First component
38
+
39
+ Edit your App.tsx file to import COBWDS components
40
+
41
+ ```tsx
42
+ import { CobButton } from "@cobwds/react/button";
43
+ <CobButton label="Submit" variant="filled" />
44
+ ```
45
+
46
+ ## Props, events, refs
47
+
48
+ **Props** are typed from the underlying element class and set as DOM
49
+ properties, not attributes. Use the camelCase property names
50
+ (`showError`, `errorMessage`), not the kebab-case attribute names.
51
+
52
+ **Events** keep their full COBWDS names, mapped to `onCob*` props:
53
+ `cob-change` becomes `onCobChange`, `cob-input` becomes `onCobInput`.
54
+ The handler parameter is the typed event, so `e.detail` autocompletes:
14
55
 
15
56
  ```tsx
16
- // New project: includes reset, typography, and utility classes
17
- import '@cobwds/styles/dist/cobwds-full.min.css';
57
+ <CobTextinput
58
+ label="First name"
59
+ onCobInput={(e) => console.log(e.detail.value)}
60
+ />
61
+ ```
62
+
63
+ There is no synthetic `onChange`. React's `onChange` prop attaches a
64
+ native `change` listener, which COBWDS components don't dispatch — use
65
+ `onCobChange`.
66
+
67
+ **Refs** resolve to the element instance:
18
68
 
19
- // Existing project: CSS variables only (styles components, nothing else)
20
- // import '@cobwds/styles/dist/cobwds.min.css';
69
+ ```tsx
70
+ const ref = React.useRef<CobTextinputElement>(null);
71
+ <CobTextinput ref={ref} label="Name" />;
72
+ // ref.current?.checkValidity()
21
73
  ```
22
74
 
23
- ## Usage
75
+ ## Forms
76
+
77
+ ### Controlled
24
78
 
25
- Import components and use them in JSX:
79
+ Bind `value` and update state from `onCobInput`:
26
80
 
27
81
  ```tsx
28
- import '@cobwds/cob-button';
29
- import '@cobwds/cob-alert';
82
+ const [name, setName] = React.useState("");
83
+
84
+ <CobTextinput
85
+ label="Name"
86
+ value={name}
87
+ onCobInput={(e) => setName(e.detail.value)}
88
+ />;
89
+ ```
30
90
 
31
- function App() {
91
+ The wrapper re-sets properties on every commit, so re-rendering with
92
+ the same value snaps the element back to your state.
93
+
94
+ ### Uncontrolled with a native form
95
+
96
+ COBWDS form components are form-associated custom elements: they submit
97
+ with a plain `<form>` like native inputs.
98
+
99
+ ```tsx
100
+ function ContactForm() {
32
101
  return (
33
- <div>
34
- <cob-button label="Click me"></cob-button>
35
- <cob-alert type="info">This is an alert.</cob-alert>
36
- </div>
102
+ <form
103
+ onSubmit={(e) => {
104
+ e.preventDefault();
105
+ const data = new FormData(e.currentTarget);
106
+ console.log(data.get("email"));
107
+ }}
108
+ >
109
+ <CobTextinput label="Email" name="email" type="email" />
110
+ <CobButton type="submit" label="Send" />
111
+ </form>
37
112
  );
38
113
  }
39
114
  ```
40
115
 
41
- ## Notes on web components in React
116
+ ### React Hook Form
117
+
118
+ Use `Controller` and wire the field through the event detail:
119
+
120
+ ```tsx
121
+ <Controller
122
+ name="firstName"
123
+ control={control}
124
+ render={({ field }) => (
125
+ <CobTextinput
126
+ label="First name"
127
+ value={field.value}
128
+ onCobInput={(e) => field.onChange(e.detail.value)}
129
+ onCobBlur={field.onBlur}
130
+ />
131
+ )}
132
+ />
133
+ ```
134
+
135
+ The `useCobField` helper collapses that to a prop bag. Pass the kind of
136
+ form control: `"value"` (default), `"checked"`, or `"files"`.
137
+
138
+ ```tsx
139
+ <Controller
140
+ name="subscribed"
141
+ control={control}
142
+ render={({ field }) => (
143
+ <CobCheckbox label="Subscribe" {...useCobField(field, "checked")} />
144
+ )}
145
+ />
146
+ ```
147
+
148
+ To surface validation errors through the component's own error slot:
149
+
150
+ ```tsx
151
+ <CobTextinput
152
+ label="Name"
153
+ showError={!!errors.name}
154
+ errorMessage={errors.name?.message}
155
+ {...useCobField(field)}
156
+ />
157
+ ```
158
+
159
+ ## SSR and Next.js
160
+
161
+ Every wrapper carries a `"use client"` directive, so the App Router
162
+ works with a normal import — no `"use client"` needed in your own files
163
+ unless they hold state:
164
+
165
+ ```tsx
166
+ // app/page.tsx (server component)
167
+ import { Signup } from "./signup"; // a client component that renders COBWDS wrappers
168
+ ```
169
+
170
+ - **App Router:** import wrappers from any client component. A server
171
+ component can't render a wrapper directly; pass it through a client
172
+ boundary like the `Signup` example.
173
+ - **Pages Router:** import and use anywhere.
174
+ - Components render client side. There is no declarative shadow DOM
175
+ server rendering in this release.
176
+
177
+ ## TypeScript tips
178
+
179
+ - `CobTextinputProps` is the full prop type:
180
+ `React.ComponentProps<typeof CobTextinput>`.
181
+ - `CobTextinputElement` is the element class type — use it for refs and
182
+ `e.target` casts.
183
+ - Event detail types come from the component packages:
184
+ `import type { CobTextinputInputEvent } from "@cobwds/cob-textinput"`.
185
+ - Unknown props are compile errors. If a prop is missing, check the
186
+ component's documented API — the wrapper exposes every public
187
+ property.
188
+
189
+ ## Troubleshooting
190
+
191
+ **The element renders but has no styling or behavior.** The custom
192
+ element didn't upgrade. Import the component from `@cobwds/react` (the
193
+ import registers it); check the browser console for load errors. If you
194
+ render raw `<cob-*>` tags instead of wrappers, import the
195
+ `@cobwds/cob-*` package yourself.
196
+
197
+ **Everything renders unstyled.** Import `@cobwds/styles` once at the app
198
+ entry (see Load styles).
199
+
200
+ **Hooks error or "Invalid hook call".** Usually a duplicate React.
201
+ Check `npm ls react` and dedupe; `@cobwds/react` declares React as a
202
+ peer dependency, so a single copy must win.
203
+
204
+ **`onChange` never fires.** COBWDS components dispatch `cob-*` events.
205
+ Use `onCobChange` / `onCobInput`, not React's `onChange`.
206
+
207
+ **Rejecting user input from a handler.** If your handler sets state to
208
+ a value React considers unchanged, React skips the re-render and the
209
+ element keeps the user's text. Force a commit (state that always
210
+ changes) or write the property directly in the handler:
211
+
212
+ ```tsx
213
+ onCobInput={(e) => {
214
+ const next = sanitize(e.detail.value);
215
+ setValue(next);
216
+ (e.target as CobTextinputElement).value = next;
217
+ }}
218
+ ```
219
+
220
+ ## How this package is built
221
+
222
+ `src/generated/` is written by the `@cobwds/codegen` CEM plugin on every
223
+ `npm run cem` and is not committed. Hand-written wrappers in
224
+ `src/overrides/` replace a generated file by class name. See
225
+ `src/overrides/README.md`.
42
226
 
43
- - String attributes work normally: `<cob-button label="Click me" />`
44
- - For event listeners, use `ref` and `addEventListener` — React's synthetic event system doesn't forward to custom elements
45
- - Boolean attributes should be set explicitly: `<cob-button disabled={true} />`
227
+ ## MCP guide additions
46
228
 
47
229
  ## Using the stepper in React (multi-page pattern)
48
230
 
@@ -53,7 +235,7 @@ function App() {
53
235
 
54
236
  **Always pass both `current` and `selected` explicitly from React state.** Without explicit `selected`, the stepper's internal fallback will override the user's sidebar navigation on every React re-render.
55
237
 
56
- **Event listening:** Use `onNysStepClick` on each `CobStep` (not on `CobStepper`). Always call `e.preventDefault()` to suppress `href`-based page navigation.
238
+ **Event listening:** Use `onCobStepClick` on each `CobStep` (not on `CobStepper`). Always call `e.preventDefault()` to suppress `href`-based page navigation.
57
239
 
58
240
  **Do not use `href` for SPA routing.** Omit `href` and handle step changes entirely in React state.
59
241
 
@@ -61,7 +243,7 @@ function App() {
61
243
 
62
244
  ```tsx
63
245
  import { useState } from 'react';
64
- import { CobStepper, CobStep, CobButton } from '@cobwds/components/react';
246
+ import { CobStepper, CobStep, CobButton } from '@cobwds/react';
65
247
 
66
248
  const STEPS = [
67
249
  { label: 'Personal Info', content: <PersonalInfoForm /> },
@@ -89,7 +271,7 @@ export function MultiStepForm() {
89
271
  label={step.label}
90
272
  current={i === currentStep}
91
273
  selected={i === viewingStep}
92
- onNysStepClick={(e) => { e.preventDefault(); setViewingStep(i); }}
274
+ onCobStepClick={(e) => { e.preventDefault(); setViewingStep(i); }}
93
275
  />
94
276
  ))}
95
277
  <div slot="actions">
@@ -102,10 +284,10 @@ export function MultiStepForm() {
102
284
  <div style={{ display: 'flex', gap: '8px', marginTop: '16px' }}>
103
285
  {viewingStep > 0 && (
104
286
  <CobButton label="Back" variant="outline"
105
- onNysClick={() => setViewingStep((v) => v - 1)} />
287
+ onCobClick={() => setViewingStep((v) => v - 1)} />
106
288
  )}
107
289
  {viewingStep === currentStep && currentStep < STEPS.length - 1 && (
108
- <CobButton label="Continue" onNysClick={handleContinue} />
290
+ <CobButton label="Continue" onCobClick={handleContinue} />
109
291
  )}
110
292
  </div>
111
293
  </main>