@nysds/mcp-server 1.21.1 → 1.22.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.
@@ -0,0 +1,356 @@
1
+ <!--
2
+ GENERATED FILE. Do not edit directly.
3
+ Source: packages/vue/README.md
4
+ Regenerate with: npm run sync:guides -w @nysds/mcp-server
5
+ -->
6
+ # @nysds/vue
7
+
8
+ Vue 3 components for the New York State Design System (NYSDS). Generated from the NYSDS web components library.
9
+
10
+ You get two ways to use the design system, and can mix them freely:
11
+
12
+ - **Wrapper components** (`<NysTextinput>`) — real Vue components with
13
+ typed props, `@nys-*` events, `<template #slot>` slots, and `v-model`
14
+ on form controls.
15
+ - **Raw `<nys-*>` tags** — the custom elements themselves, typed in
16
+ templates and TSX.
17
+
18
+ Requires Vue 3.4 or later (tested on 3.4 and 3.5).
19
+
20
+ ## Install
21
+
22
+ ### Setup a new React project
23
+
24
+ ```bash
25
+ npm create vue@latest
26
+ ```
27
+
28
+ ### Install NYS Design System
29
+ ```bash
30
+ npm install @nysds/vue @nysds/styles
31
+ ```
32
+
33
+ ## Load styles
34
+
35
+ Import the design system stylesheet once, in your app's main.ts:
36
+
37
+ ```tsx
38
+ import "@nysds/styles/full";
39
+ ```
40
+
41
+ Vue's default TypeScript config rejects side-effect imports it can't
42
+ resolve, and a stylesheet isn't a module. If `npm run build` fails with
43
+ `TS2882: Cannot find module or type declarations for side-effect import of
44
+ '@nysds/styles/full'`, declare the stylesheets once in `env.d.ts`:
45
+
46
+ ```ts
47
+ // env.d.ts
48
+ declare module "@nysds/styles/*";
49
+ ```
50
+
51
+ Optional agency theme: `<html data-theme="health">`. Themes: `admin`,
52
+ `business`, `environment`, `health`, `local`, `safety`, `transportation`.
53
+ Fonts aren't bundled. Load them the way your agency normally does.
54
+
55
+ ### 4. Use a component
56
+
57
+ ```vue
58
+ <script setup lang="ts">
59
+ import { NysAlert, NysButton } from "@nysds/vue";
60
+
61
+ const start = () => console.log("started");
62
+
63
+ </script>
64
+
65
+ <template>
66
+ <NysAlert type="info" heading="Welcome" />
67
+ <NysButton label="Start" @nys-click="start" />
68
+ </template>
69
+ ```
70
+
71
+ Importing a wrapper registers its custom element as a side effect — no
72
+ `app.use()` call or global registration. Run `npm run dev`; you should see
73
+ a styled alert and button.
74
+
75
+ That's the whole setup. No compiler options are needed for wrapper
76
+ components. If you'd rather write raw `<nys-*>` tags, see
77
+ [Raw tags](#raw-tags).
78
+
79
+ ## Props, events, slots, and refs
80
+
81
+ **Props** are typed from the underlying element class and set as DOM
82
+ properties. Use camelCase or kebab-case in templates, whichever you
83
+ prefer (`appName` and `app-name` are the same prop). Bind numbers and
84
+ booleans with `:` so they keep their type:
85
+
86
+ ```vue
87
+ <NysPagination :total-pages="5" :current-page="1" />
88
+ <NysTextinput label="Name" required :disabled="locked" />
89
+ ```
90
+
91
+ A prop you don't pass is left alone, so the element keeps its own
92
+ default.
93
+
94
+ **Events** keep their full NYSDS names. Listen with `@nys-change`,
95
+ `@nys-input`, and so on. The handler parameter is the typed event, so
96
+ `e.detail` autocompletes:
97
+
98
+ ```vue
99
+ <NysTextinput
100
+ label="First name"
101
+ @nys-input="(e) => console.log(e.detail.value)"
102
+ />
103
+ ```
104
+
105
+ Use the `nys-*` events rather than native `@input` and `@change`: they
106
+ are NYSDS's public event contract, they carry typed details, and they cover
107
+ cases native events don't (a combobox selection, a date picked from the
108
+ calendar).
109
+
110
+ **Slots** work with `<template #name>`. The default slot renders as direct
111
+ children:
112
+
113
+ ```vue
114
+ <NysTextinput label="Email">
115
+ <template #description>We'll never share it.</template>
116
+ </NysTextinput>
117
+
118
+ <NysTooltip text="Tooltip text">
119
+ <NysButton label="Hover me" />
120
+ </NysTooltip>
121
+ ```
122
+
123
+ Named slot content is wrapped in a `<span slot="…" style="display:
124
+ contents">` so any content (text, components, fragments) can fill it. You
125
+ can also put a plain `slot="name"` attribute on your own child element.
126
+
127
+ **Refs** on a wrapper resolve to the Vue component instance. The element
128
+ itself is `$el`, typed as the element class:
129
+
130
+ ```vue
131
+ <script setup lang="ts">
132
+ import { ref } from "vue";
133
+ import { NysTextinput } from "@nysds/vue";
134
+
135
+ const name = ref<InstanceType<typeof NysTextinput> | null>(null);
136
+ const check = () => name.value?.$el.checkValidity();
137
+ </script>
138
+
139
+ <template>
140
+ <NysTextinput ref="name" label="Name" />
141
+ </template>
142
+ ```
143
+
144
+ ## Forms
145
+
146
+ ### `v-model`
147
+
148
+ Every form control supports `v-model`. It binds the property the
149
+ component's form contract defines:
150
+
151
+ | Component | `v-model` value |
152
+ | --- | --- |
153
+ | `NysTextinput`, `NysTextarea`, `NysSelect`, `NysCombobox`, `NysDatepicker`, `NysRadiogroup` | `string` |
154
+ | `NysCheckboxgroup` | `string[]` |
155
+ | `NysCheckbox`, `NysToggle` | `boolean` |
156
+
157
+ ```vue
158
+ <script setup lang="ts">
159
+ import { reactive } from "vue";
160
+ import {
161
+ NysCheckbox,
162
+ NysCheckboxgroup,
163
+ NysRadiobutton,
164
+ NysRadiogroup,
165
+ NysTextinput,
166
+ } from "@nysds/vue";
167
+
168
+ const model = reactive({
169
+ firstName: "",
170
+ agree: false,
171
+ languages: [] as string[],
172
+ contact: "",
173
+ });
174
+ </script>
175
+
176
+ <template>
177
+ <NysTextinput v-model="model.firstName" label="First name" required />
178
+ <NysCheckbox v-model="model.agree" label="I agree to the terms" />
179
+
180
+ <NysCheckboxgroup v-model="model.languages" label="Languages">
181
+ <NysCheckbox label="English" value="en" />
182
+ <NysCheckbox label="Spanish" value="es" />
183
+ </NysCheckboxgroup>
184
+
185
+ <NysRadiogroup v-model="model.contact" label="Preferred contact" name="contact">
186
+ <NysRadiobutton label="Email" name="contact" value="email" />
187
+ <NysRadiobutton label="Phone" name="contact" value="phone" />
188
+ </NysRadiogroup>
189
+ </template>
190
+ ```
191
+
192
+ - Bind checkbox and radio groups on `NysCheckboxgroup` and
193
+ `NysRadiogroup`, not on each child.
194
+ - The model updates on the component's `nys-input` and `nys-change`
195
+ events. Add `.lazy` (`v-model.lazy`) to update on `nys-change` alone, as
196
+ on a native input.
197
+ - **File input** has no `v-model`. Listen for the change event and read
198
+ the files from its detail:
199
+
200
+ ```vue
201
+ <NysFileinput
202
+ label="Resume"
203
+ @nys-change="(e) => (model.resume = e.detail.files[0]?.name ?? '')"
204
+ />
205
+ ```
206
+
207
+ ### Submit and validate with a native form
208
+
209
+ NYSDS form components are form-associated custom elements: they submit
210
+ with a plain `<form>` like native inputs, and `required`, `pattern`, and
211
+ the rest drive the component's own validation and error display.
212
+
213
+ ```vue
214
+ <form @submit.prevent="onSubmit">
215
+ <NysTextinput v-model="model.firstName" label="First name" required />
216
+ <NysButton type="submit" label="Submit" />
217
+ </form>
218
+ ```
219
+
220
+ `nys-button type="submit"` submits through `form.requestSubmit()`, so an
221
+ invalid form blocks `@submit` and the component shows its error.
222
+
223
+ To drive errors from your own validation library instead, set the
224
+ component's error props:
225
+
226
+ ```vue
227
+ <NysTextinput
228
+ v-model="model.firstName"
229
+ label="First name"
230
+ :show-error="!!errors.firstName"
231
+ :error-message="errors.firstName"
232
+ />
233
+ ```
234
+
235
+ ### Reset
236
+
237
+ Setting the model back to its initial values resets every control. The
238
+ file input has no bound value, so also call `reset()` on the form:
239
+
240
+ ```ts
241
+ const form = ref<HTMLFormElement | null>(null);
242
+
243
+ function reset() {
244
+ Object.assign(model, initialModel());
245
+ form.value?.reset();
246
+ }
247
+ ```
248
+
249
+ ## Raw tags
250
+
251
+ If you prefer the custom elements directly, import the package once for
252
+ its side effects and types, then tell Vue's compiler that `nys-*` tags are
253
+ custom elements so it doesn't try to resolve them as components:
254
+
255
+ ```ts
256
+ // vite.config.ts
257
+ import vue from "@vitejs/plugin-vue";
258
+
259
+ export default {
260
+ plugins: [
261
+ vue({
262
+ template: {
263
+ compilerOptions: { isCustomElement: (tag) => tag.startsWith("nys-") },
264
+ },
265
+ }),
266
+ ],
267
+ };
268
+ ```
269
+
270
+ ```vue
271
+ <script setup lang="ts">
272
+ import { reactive } from "vue";
273
+ import "@nysds/vue"; // registers every element and adds the tag types
274
+
275
+ const model = reactive({ firstName: "" });
276
+ </script>
277
+
278
+ <template>
279
+ <nys-textinput
280
+ label="First name"
281
+ :value="model.firstName"
282
+ @nys-input="(e) => (model.firstName = e.detail.value)"
283
+ />
284
+ </template>
285
+ ```
286
+
287
+ Raw tags are typed in `.vue` templates (checked by `vue-tsc`) and in TSX.
288
+ Bind properties with `:` and update your state from the `@nys-*`
289
+ listener.
290
+
291
+ **Raw tags have no working `v-model`.** Vue's built-in `v-model` listens for
292
+ native `input` events instead of the `nys-*` events that make up NYSDS's
293
+ contract, so it misses updates (a combobox selection, a calendar pick, a
294
+ checkbox). Use a wrapper component, or bind `:value` and `@nys-input`
295
+ yourself as above.
296
+
297
+ ## TypeScript
298
+
299
+ - `NysTextinputProps` is the full prop type, including the `on*` event
300
+ handlers and, for form controls, `modelValue`.
301
+ - `NysTextinputElement` is the element class type.
302
+ - `NysTextinputSlots` and `NysTextinputSlotName` describe the slots.
303
+ - Event detail types come from the component packages:
304
+ `import type { NysTextinputInputEvent } from "@nysds/nys-textinput"`.
305
+ - Run `vue-tsc --noEmit` in your build to type-check templates. Unknown
306
+ props on a wrapper are compile errors; slot names are checked in `.vue`
307
+ files but not in TSX.
308
+
309
+ ## SSR and Nuxt
310
+
311
+ The package is safe to import in Node, and a wrapper renders its bare
312
+ element on the server. Components upgrade and become interactive in the
313
+ browser; there is no declarative shadow DOM rendering in this release, and
314
+ hydration has not been verified. For SSR frameworks such as Nuxt, render
315
+ NYSDS components inside client-only boundaries (`<ClientOnly>`) until you
316
+ have tested hydration in your app.
317
+
318
+ ## Troubleshooting
319
+
320
+ **The element renders but has no styling or behavior.** The custom
321
+ element didn't upgrade. Import the component from `@nysds/vue` (the import
322
+ registers it) and check the browser console for load errors. If you use
323
+ raw `<nys-*>` tags, add `import "@nysds/vue"` yourself.
324
+
325
+ **Everything renders unstyled.** Import `@nysds/styles/full` once at your
326
+ entry file.
327
+
328
+ **`Failed to resolve component: nys-…`.** You used a raw tag without the
329
+ `isCustomElement` compiler option. Add it (see [Raw tags](#raw-tags)) or
330
+ use the wrapper component instead.
331
+
332
+ **`v-model` on a raw `<nys-*>` tag doesn't update.** See
333
+ [Raw tags](#raw-tags): use a wrapper, or bind `:value` and `@nys-input`.
334
+
335
+ **A prop change doesn't reach the element.** Bind numbers and booleans
336
+ with `:` (`:total-pages="5"`), not as plain attributes, so Vue passes the
337
+ typed value.
338
+
339
+ **Slot content has an extra wrapper.** Named slot content sits inside a
340
+ `display: contents` span. To avoid it, put a `slot="name"` attribute on
341
+ your own child element instead of using `<template #name>`.
342
+
343
+ **`app.use(router)` or the `<nys-*>` types break with two Vue versions.**
344
+ Two copies of Vue in `node_modules` give TypeScript two sets of types. Run
345
+ `npm ls vue` and dedupe. In a monorepo where you pin a different Vue in one
346
+ workspace, map `vue` in that app's `tsconfig.json`:
347
+
348
+ ```json
349
+ { "compilerOptions": { "baseUrl": ".", "paths": { "vue": ["./node_modules/vue"] } } }
350
+ ```
351
+
352
+ ## How this package is built
353
+
354
+ `src/generated/` is written by the `@nysds/codegen` CEM plugin on every
355
+ `npm run cem` and is not committed. The one hand-written file is
356
+ `src/runtime.ts`, which builds each wrapper from the generated metadata.
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * New York State Design System v1.21.1
2
+ * New York State Design System v1.22.1
3
3
  * Description: A design system for New York State's digital products.
4
4
  * Repository: https://github.com/its-hcd/nysds
5
5
  * License: MIT
@@ -48,6 +48,17 @@ export interface CEMExample {
48
48
  code: string;
49
49
  lang?: string;
50
50
  }
51
+ /**
52
+ * `@formControl <kind> <changeEvent> [inputEvent]` metadata, written by WS1
53
+ * on every form-control component's class JSDoc and parsed into the
54
+ * manifest by the CEM plugin. Drives the Angular `ControlValueAccessor`
55
+ * base class choice and the React/Angular snippet transformer's forms mode.
56
+ */
57
+ export interface CEMFormControl {
58
+ kind: "value" | "checked" | "files";
59
+ changeEvent: string;
60
+ inputEvent?: string;
61
+ }
51
62
  export interface CEMDeclaration {
52
63
  kind: "class";
53
64
  name: string;
@@ -65,6 +76,7 @@ export interface CEMDeclaration {
65
76
  package?: string;
66
77
  };
67
78
  examples?: CEMExample[];
79
+ formControl?: CEMFormControl;
68
80
  }
69
81
  export interface CEMModule {
70
82
  kind: "javascript-module";
@@ -1 +1 @@
1
- {"version":3,"file":"cem-parser.d.ts","sourceRoot":"","sources":["../../src/lib/cem-parser.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cem-parser.d.ts","sourceRoot":"","sources":["../../src/lib/cem-parser.ts"],"names":[],"mappings":"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"}
@@ -2,7 +2,7 @@
2
2
  * Framework package index
3
3
  *
4
4
  * Reads `data/frameworks.json`, written by `scripts/sync-guides.mjs` from
5
- * `packages/react/package.json` and `packages/angular/package.json`. Gives
5
+ * the `package.json` of each framework package (react, vue, angular). Gives
6
6
  * tools and resources the published package name and version without
7
7
  * hand-maintaining either.
8
8
  */
@@ -12,6 +12,7 @@ export interface FrameworkPackageInfo {
12
12
  }
13
13
  export interface FrameworksIndex {
14
14
  react: FrameworkPackageInfo;
15
+ vue: FrameworkPackageInfo;
15
16
  angular: FrameworkPackageInfo;
16
17
  }
17
18
  export declare function getFrameworksIndex(): FrameworksIndex;
@@ -1 +1 @@
1
- {"version":3,"file":"frameworks-data.d.ts","sourceRoot":"","sources":["../../src/lib/frameworks-data.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAQH,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,oBAAoB,CAAC;IAC5B,OAAO,EAAE,oBAAoB,CAAC;CAC/B;AAiBD,wBAAgB,kBAAkB,IAAI,eAAe,CAcpD"}
1
+ {"version":3,"file":"frameworks-data.d.ts","sourceRoot":"","sources":["../../src/lib/frameworks-data.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAQH,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,oBAAoB,CAAC;IAC5B,GAAG,EAAE,oBAAoB,CAAC;IAC1B,OAAO,EAAE,oBAAoB,CAAC;CAC/B;AAiBD,wBAAgB,kBAAkB,IAAI,eAAe,CAepD"}
@@ -2,7 +2,7 @@
2
2
  * Framework package index
3
3
  *
4
4
  * Reads `data/frameworks.json`, written by `scripts/sync-guides.mjs` from
5
- * `packages/react/package.json` and `packages/angular/package.json`. Gives
5
+ * the `package.json` of each framework package (react, vue, angular). Gives
6
6
  * tools and resources the published package name and version without
7
7
  * hand-maintaining either.
8
8
  */
@@ -32,6 +32,7 @@ export function getFrameworksIndex() {
32
32
  console.error("Warning: Could not load data/frameworks.json:", error);
33
33
  cached = {
34
34
  react: { packageName: "@nysds/react", version: "unknown" },
35
+ vue: { packageName: "@nysds/vue", version: "unknown" },
35
36
  angular: { packageName: "@nysds/angular", version: "unknown" },
36
37
  };
37
38
  }
@@ -1,11 +1,13 @@
1
1
  /**
2
2
  * Framework Resources
3
3
  *
4
- * MCP resources for NYSDS framework packages (@nysds/react, @nysds/angular).
4
+ * MCP resources for NYSDS framework packages (@nysds/react, @nysds/vue,
5
+ * @nysds/angular).
5
6
  *
6
7
  * Resources:
7
8
  * - nysds://frameworks - Index of framework packages with version and guide URI
8
9
  * - nysds://frameworks/react - @nysds/react guide (synced from its README)
10
+ * - nysds://frameworks/vue - @nysds/vue guide (synced from its README)
9
11
  * - nysds://frameworks/angular - @nysds/angular guide (synced from its README)
10
12
  */
11
13
  import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
@@ -1 +1 @@
1
- {"version":3,"file":"frameworks.d.ts","sourceRoot":"","sources":["../../src/resources/frameworks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAezE,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA8ElE"}
1
+ {"version":3,"file":"frameworks.d.ts","sourceRoot":"","sources":["../../src/resources/frameworks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAKH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAezE,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAwGlE"}
@@ -1,11 +1,13 @@
1
1
  /**
2
2
  * Framework Resources
3
3
  *
4
- * MCP resources for NYSDS framework packages (@nysds/react, @nysds/angular).
4
+ * MCP resources for NYSDS framework packages (@nysds/react, @nysds/vue,
5
+ * @nysds/angular).
5
6
  *
6
7
  * Resources:
7
8
  * - nysds://frameworks - Index of framework packages with version and guide URI
8
9
  * - nysds://frameworks/react - @nysds/react guide (synced from its README)
10
+ * - nysds://frameworks/vue - @nysds/vue guide (synced from its README)
9
11
  * - nysds://frameworks/angular - @nysds/angular guide (synced from its README)
10
12
  */
11
13
  import { readFileSync } from "node:fs";
@@ -26,7 +28,7 @@ function loadFrameworkGuide(framework) {
26
28
  export function registerFrameworkResources(server) {
27
29
  // nysds://frameworks - Index of framework packages
28
30
  server.resource("frameworks", "nysds://frameworks", {
29
- description: "Index of NYSDS framework packages (@nysds/react, @nysds/angular) with their published version and guide resource URI",
31
+ description: "Index of NYSDS framework packages (@nysds/react, @nysds/vue, @nysds/angular) with their published version and guide resource URI",
30
32
  mimeType: "application/json",
31
33
  }, async () => {
32
34
  const index = getFrameworksIndex();
@@ -37,6 +39,12 @@ export function registerFrameworkResources(server) {
37
39
  version: index.react.version,
38
40
  guideUri: "nysds://frameworks/react",
39
41
  },
42
+ {
43
+ id: "vue",
44
+ packageName: index.vue.packageName,
45
+ version: index.vue.version,
46
+ guideUri: "nysds://frameworks/vue",
47
+ },
40
48
  {
41
49
  id: "angular",
42
50
  packageName: index.angular.packageName,
@@ -67,6 +75,19 @@ export function registerFrameworkResources(server) {
67
75
  },
68
76
  ],
69
77
  }));
78
+ // nysds://frameworks/vue - @nysds/vue guide
79
+ server.resource("frameworks-vue", "nysds://frameworks/vue", {
80
+ description: "@nysds/vue install, usage, v-model forms, SSR, and troubleshooting guide",
81
+ mimeType: "text/markdown",
82
+ }, async () => ({
83
+ contents: [
84
+ {
85
+ uri: "nysds://frameworks/vue",
86
+ mimeType: "text/markdown",
87
+ text: loadFrameworkGuide("vue"),
88
+ },
89
+ ],
90
+ }));
70
91
  // nysds://frameworks/angular - @nysds/angular guide
71
92
  server.resource("frameworks-angular", "nysds://frameworks/angular", {
72
93
  description: "@nysds/angular install, usage, forms, SSR, and troubleshooting guide",
@@ -1 +1 @@
1
- {"version":3,"file":"guides.d.ts","sourceRoot":"","sources":["../../src/resources/guides.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAyE9D"}
1
+ {"version":3,"file":"guides.d.ts","sourceRoot":"","sources":["../../src/resources/guides.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAoF9D"}
@@ -56,7 +56,18 @@ Then use them in HTML:
56
56
 
57
57
  ## Framework Integration
58
58
 
59
- For framework-specific setup, use the \`get_guide\` tool with \`topic: "framework"\` and a \`framework\` parameter (angular, react, dotnet, drupal, or vanilla).
59
+ For framework-specific setup, use the \`get_guide\` tool with a \`topic\` and a \`framework\` parameter (angular, react, vue, dotnet, drupal, or vanilla).
60
+
61
+ React, Vue, and Angular are first-class packages, not wrapper snippets:
62
+ \`@nysds/react\` (\`npm install @nysds/react\`), \`@nysds/vue\`
63
+ (\`npm install @nysds/vue\`), and \`@nysds/angular\`
64
+ (\`npm install @nysds/angular @nysds/components\`) generate typed
65
+ components, props, and events directly from this design system's
66
+ manifest. See the \`nysds://frameworks\` resource for their current
67
+ published versions, \`nysds://frameworks/react\`, \`nysds://frameworks/vue\`, and
68
+ \`nysds://frameworks/angular\` for their full guides, and pass
69
+ \`framework: "react"\` or \`"angular"\` to \`get_component\` for
70
+ per-component import lines and framework-specific code examples.
60
71
 
61
72
  ## Resources
62
73
 
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/resources/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAKzE,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAIzD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/resources/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAMzE,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAKzD"}
@@ -6,8 +6,10 @@
6
6
  import { registerComponentResources } from "./components.js";
7
7
  import { registerTokenResources } from "./tokens.js";
8
8
  import { registerGuideResources } from "./guides.js";
9
+ import { registerFrameworkResources } from "./frameworks.js";
9
10
  export function registerResources(server) {
10
11
  registerComponentResources(server);
11
12
  registerTokenResources(server);
12
13
  registerGuideResources(server);
14
+ registerFrameworkResources(server);
13
15
  }
@@ -1 +1 @@
1
- {"version":3,"file":"component-tools.d.ts","sourceRoot":"","sources":["../../src/tools/component-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIzE,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA+G9D"}
1
+ {"version":3,"file":"component-tools.d.ts","sourceRoot":"","sources":["../../src/tools/component-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAYzE,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA2I9D"}
@@ -10,6 +10,8 @@
10
10
  import { z } from "zod";
11
11
  import { getComponent, getAllComponents } from "../lib/cem-parser.js";
12
12
  import { searchComponents } from "../lib/search.js";
13
+ import { buildExampleSnippets, } from "../lib/framework-snippets.js";
14
+ import { buildAngularUsageNotes, buildReactUsageNotes, } from "../lib/framework-usage.js";
13
15
  export function registerComponentTools(server) {
14
16
  // find_components - Search or list all components
15
17
  server.tool("find_components", "Search for NYSDS components by name or description. Omit query to list all components.", {
@@ -51,15 +53,19 @@ export function registerComponentTools(server) {
51
53
  };
52
54
  });
53
55
  // get_component - Full documentation for a specific component
54
- server.tool("get_component", "Get full documentation for a specific NYSDS component including properties, events, slots, and CSS custom properties", {
56
+ server.tool("get_component", "Get full documentation for a specific NYSDS component including properties, events, slots, and CSS custom properties. Set framework to 'react' or 'angular' to get that framework's import line, event-prop naming, and forms guidance alongside HTML/React/Angular code examples.", {
55
57
  tagName: z
56
58
  .string()
57
59
  .describe("The tag name of the component (e.g., 'nys-button')"),
58
60
  includeExamples: z
59
61
  .boolean()
60
62
  .default(false)
61
- .describe("Include HTML code examples from component JSDoc. Set to true when you need usage patterns."),
62
- }, async ({ tagName, includeExamples }) => {
63
+ .describe("Include code examples from component JSDoc. Set to true when you need usage patterns. Each example carries html, react, and angular snippets."),
64
+ framework: z
65
+ .enum(["html", "react", "angular"])
66
+ .default("html")
67
+ .describe("Which framework to optimize the response for. 'html' (default) returns plain custom-element usage. 'react' and 'angular' add framework-specific usage notes (import line, event-prop naming, forms binding) and, for a form-control component, transform that framework's example snippets into its idiomatic controlled/reactive-forms pattern."),
68
+ }, async ({ tagName, includeExamples, framework }) => {
63
69
  const component = getComponent(tagName);
64
70
  if (!component) {
65
71
  return {
@@ -76,16 +82,25 @@ export function registerComponentTools(server) {
76
82
  // Attributes contains the HTML API, members duplicates this plus private methods
77
83
  const {
78
84
  // members: _members,
79
- examples, ...componentWithoutMembers } = component;
85
+ examples, formControl, ...componentWithoutMembers } = component;
86
+ const usage = {};
87
+ if (framework === "react") {
88
+ usage.react = buildReactUsageNotes(tagName, component.name, formControl);
89
+ }
90
+ else if (framework === "angular") {
91
+ usage.angular = buildAngularUsageNotes(tagName, component.name, formControl);
92
+ }
80
93
  return {
81
94
  content: [
82
95
  {
83
96
  type: "text",
84
97
  text: JSON.stringify({
85
98
  ...componentWithoutMembers,
99
+ formControl,
86
100
  examples: includeExamples && examples && examples.length > 0
87
- ? examples
101
+ ? buildExampleSnippets(examples, framework, formControl)
88
102
  : undefined,
103
+ usage: Object.keys(usage).length > 0 ? usage : undefined,
89
104
  resourceUri: `nysds://component/${tagName}`,
90
105
  }, null, 2),
91
106
  },
@@ -56,7 +56,7 @@ export function registerGuideTools(server) {
56
56
  ])
57
57
  .describe("The guide topic to retrieve"),
58
58
  framework: z
59
- .enum(["angular", "react", "dotnet", "drupal", "vanilla"])
59
+ .enum(["angular", "react", "vue", "dotnet", "drupal", "vanilla"])
60
60
  .optional()
61
61
  .describe("When provided, returns framework-specific setup guide instead of the topic guide. Use with topic 'installation' to get framework install instructions."),
62
62
  }, async ({ topic, framework }) => {