@handamade/psi-mcp 0.4.0 → 0.4.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/index-builder.d.ts +7 -0
- package/dist/index-builder.js +17 -1
- package/dist/init.js +1 -1
- package/dist/psi-index.json +99 -24
- package/dist/store.js +4 -1
- package/package.json +3 -3
package/dist/index-builder.d.ts
CHANGED
|
@@ -12,4 +12,11 @@ export declare const GETTING_STARTED: {
|
|
|
12
12
|
themeAttribute: string;
|
|
13
13
|
rules: string;
|
|
14
14
|
};
|
|
15
|
+
/** Theme mechanics; travels with the index (spec: topics). */
|
|
16
|
+
export declare const THEMES_TOPIC: {
|
|
17
|
+
themes: string[];
|
|
18
|
+
attribute: string;
|
|
19
|
+
switching: string;
|
|
20
|
+
customerThemes: string;
|
|
21
|
+
};
|
|
15
22
|
export declare function buildIndex(inputs: BuildInputs): Promise<PsiIndex>;
|
package/dist/index-builder.js
CHANGED
|
@@ -9,6 +9,8 @@ export const GETTING_STARTED = {
|
|
|
9
9
|
"@handamade/psi-tokens/<theme>.css — one per theme you use (light|dark|acme|ember)",
|
|
10
10
|
"@handamade/psi-tokens/components.css",
|
|
11
11
|
"@handamade/psi-tokens/utilities.css — REQUIRED: .psi-container + reduced-motion zeroing",
|
|
12
|
+
"@handamade/psi-react/styles — REQUIRED: component CSS. Separate export; the JS never " +
|
|
13
|
+
"imports it for you. Without it every component renders unstyled (HAN-17 finding).",
|
|
12
14
|
],
|
|
13
15
|
themeAttribute: 'Set data-psi-theme="light|dark|acme|ember" on <html> or a subtree root.',
|
|
14
16
|
rules: "Sizes are px numbers (24 | 32 | 40 | 48), never S/M/L. Variants are flat " +
|
|
@@ -16,6 +18,15 @@ export const GETTING_STARTED = {
|
|
|
16
18
|
"one accent per visual group (Tags exempt, D40); danger only for destructive actions. " +
|
|
17
19
|
"Never hardcode colors — bind var(--psi-*).",
|
|
18
20
|
};
|
|
21
|
+
/** Theme mechanics; travels with the index (spec: topics). */
|
|
22
|
+
export const THEMES_TOPIC = {
|
|
23
|
+
themes: [...THEMES],
|
|
24
|
+
attribute: 'Set data-psi-theme="light|dark|acme|ember" on <html> or a subtree root.',
|
|
25
|
+
switching: "Theme CSS files are scoped under [data-psi-theme] and co-import safely — " +
|
|
26
|
+
"import every theme you switch between at runtime.",
|
|
27
|
+
customerThemes: "light/dark are the core pair; acme and ember are customer brand themes " +
|
|
28
|
+
"(OKLCH formula overrides, same semantic token names).",
|
|
29
|
+
};
|
|
19
30
|
async function readJson(path) {
|
|
20
31
|
return JSON.parse(await readFile(path, "utf8"));
|
|
21
32
|
}
|
|
@@ -50,6 +61,11 @@ export async function buildIndex(inputs) {
|
|
|
50
61
|
components,
|
|
51
62
|
tokens,
|
|
52
63
|
scales: light.scales,
|
|
53
|
-
topics: {
|
|
64
|
+
topics: {
|
|
65
|
+
...guidance,
|
|
66
|
+
"getting-started": GETTING_STARTED,
|
|
67
|
+
themes: THEMES_TOPIC,
|
|
68
|
+
scales: light.scales,
|
|
69
|
+
},
|
|
54
70
|
};
|
|
55
71
|
}
|
package/dist/init.js
CHANGED
|
@@ -26,7 +26,7 @@ export function renderAgentsBlock(index) {
|
|
|
26
26
|
"- Sizes are px numbers (24 | 32 | 40 | 48), never S/M/L.",
|
|
27
27
|
"- Variants are flat: accent | accent-subtle | neutral | neutral-subtle | ghost | danger | danger-subtle | outline. One accent per visual group (Tags exempt, D40); danger only for destructive actions.",
|
|
28
28
|
"- Never hardcode colors — bind var(--psi-*) custom properties.",
|
|
29
|
-
"- Import all four token CSS files: base.css, one theme css, components.css, utilities.css (utilities is REQUIRED — .psi-container + reduced-motion zeroing).",
|
|
29
|
+
"- Import all four token CSS files: base.css, one theme css, components.css, utilities.css (utilities is REQUIRED — .psi-container + reduced-motion zeroing) — PLUS @handamade/psi-react/styles (component CSS; separate export, never auto-imported).",
|
|
30
30
|
`- Themes: ${index.themes.join(" | ")} — set data-psi-theme on <html> or a subtree root.`,
|
|
31
31
|
"",
|
|
32
32
|
`## Components (${index.components.length})`,
|
package/dist/psi-index.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.4.
|
|
2
|
+
"version": "0.4.1",
|
|
3
3
|
"themes": [
|
|
4
4
|
"light",
|
|
5
5
|
"dark",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"components": [
|
|
10
10
|
{
|
|
11
11
|
"name": "Button",
|
|
12
|
-
"description": "",
|
|
12
|
+
"description": "Action trigger. With `href` renders an anchor with identical styling (D33); `disabled` then maps to `aria-disabled`.",
|
|
13
13
|
"props": [
|
|
14
14
|
{
|
|
15
15
|
"name": "variant",
|
|
@@ -61,11 +61,11 @@
|
|
|
61
61
|
"description": "Additional CSS class name(s) merged onto the component's root element."
|
|
62
62
|
}
|
|
63
63
|
],
|
|
64
|
-
"doc": "<!-- Generated by emit-docs.ts — do not edit. -->\n# Button\n\n\n
|
|
64
|
+
"doc": "<!-- Generated by emit-docs.ts — do not edit. -->\n# Button\n\nAction trigger. With `href` renders an anchor with identical styling (D33); `disabled` then maps to `aria-disabled`.\n\n## Props\n\n| Prop | Type | Default | Required | Description |\n|---|---|---|---|---|\n| `variant` | `\"accent\" \\| \"accent-subtle\" \\| \"neutral\" \\| \"neutral-subtle\" \\| \"ghost\" \\| \"danger\" \\| \"danger-subtle\" \\| \"outline\"` | neutral | no | Visual variant. |\n| `size` | `24 \\| 32 \\| 40 \\| 48` | 32 | no | Height in px (24 \\| 32 \\| 40 \\| 48). |\n| `href` | `string` | — | no | Render as an anchor with this href (D33). disabled → aria-disabled, no href attribute, pointer-events: none. |\n| `target` | `string` | — | no | Anchor target; only used with href. |\n| `rel` | `string` | — | no | Anchor rel; only used with href. |\n| `ref` | `Ref<HTMLButtonElement \\| HTMLAnchorElement>` | — | no | Forwarded ref to the underlying element. |\n| `className` | `string` | — | no | Additional CSS class name(s) merged onto the component's root element. |\n\n## Keyboard & assistive tech\n\n| Keys | Behavior |\n|---|---|\n| Enter / Space | Activates the button. |\n| Tab | Focusable; visible focus ring via :focus-visible. |\n\nWith href it renders an <a>; disabled anchors get aria-disabled, lose the href attribute, and suppress activation (D33).\n\n## Theming\n\nOverride `--psi-button-*` custom properties at any scope; interactive states derive automatically (L - 0.04 hover, L - 0.08 active).\n\n## Variant guidance\n\n- **accent** — Primary action, draws attention. Submit, CTA, main action in a group.\n- **accent-subtle** — Accent tone, lower visual weight. Selected state, active filter, soft CTA.\n- **neutral** — Default, structurally present. Secondary actions, toolbar buttons.\n- **neutral-subtle** — Minimal chrome. Inline actions, table row actions.\n- **ghost** — No visible container until hover. Icon-only triggers, compact toolbars.\n- **outline** — Bordered ghost — visible structure, no fill until hover. Marketing CTA, download button; hover fills accent.\n- **danger** — Destructive action. Delete, remove, disconnect.\n- **danger-subtle** — Destructive context, low urgency. Warning badges, soft destructive hints.\n- **success | warning** — Status communication (Tag only). Status badges, labels.\n\n## Rules\n\n- One accent per visual group; everything else neutral or ghost.\n- danger only for actions with real consequences.\n- Sizes are px numbers (24|32|40|48), never S/M/L.\n- Typography tokens are --psi-text-{size}-{lineHeight}-{weight}.\n- Override component tokens (--psi-{component}-*), not semantic tokens, for one-off theming.\n- --psi-button-font overrides button typography across all sizes (documented D34 override; ember → mono).\n"
|
|
65
65
|
},
|
|
66
66
|
{
|
|
67
67
|
"name": "IconButton",
|
|
68
|
-
"description": "",
|
|
68
|
+
"description": "Square icon-only button; same variant/size/href contract as Button. Give it an accessible name (`aria-label`).",
|
|
69
69
|
"props": [
|
|
70
70
|
{
|
|
71
71
|
"name": "variant",
|
|
@@ -117,11 +117,11 @@
|
|
|
117
117
|
"description": "Additional CSS class name(s) merged onto the component's root element."
|
|
118
118
|
}
|
|
119
119
|
],
|
|
120
|
-
"doc": "<!-- Generated by emit-docs.ts — do not edit. -->\n# IconButton\n\n\n
|
|
120
|
+
"doc": "<!-- Generated by emit-docs.ts — do not edit. -->\n# IconButton\n\nSquare icon-only button; same variant/size/href contract as Button. Give it an accessible name (`aria-label`).\n\n## Props\n\n| Prop | Type | Default | Required | Description |\n|---|---|---|---|---|\n| `variant` | `\"accent\" \\| \"neutral\" \\| \"ghost\" \\| \"danger\"` | neutral | no | Visual variant. |\n| `size` | `24 \\| 32 \\| 40 \\| 48` | 32 | no | Square size in px (24 \\| 32 \\| 40 \\| 48). |\n| `href` | `string` | — | no | Render as an anchor with this href (D33). disabled → aria-disabled, no href attribute, pointer-events: none. |\n| `target` | `string` | — | no | Anchor target; only used with href. |\n| `rel` | `string` | — | no | Anchor rel; only used with href. |\n| `ref` | `Ref<HTMLButtonElement \\| HTMLAnchorElement>` | — | no | Forwarded ref to the underlying element. |\n| `className` | `string` | — | no | Additional CSS class name(s) merged onto the component's root element. |\n\n## Keyboard & assistive tech\n\n| Keys | Behavior |\n|---|---|\n| Enter / Space | Activates. |\n\nRequires an accessible name — pass aria-label. IconButton does not hide its icon for you; mark the icon aria-hidden yourself.\n\n## Theming\n\nOverride `--psi-button-*` custom properties at any scope; interactive states derive automatically (L - 0.04 hover, L - 0.08 active).\n\n## Variant guidance\n\n- **accent** — Primary action, draws attention. Submit, CTA, main action in a group.\n- **accent-subtle** — Accent tone, lower visual weight. Selected state, active filter, soft CTA.\n- **neutral** — Default, structurally present. Secondary actions, toolbar buttons.\n- **neutral-subtle** — Minimal chrome. Inline actions, table row actions.\n- **ghost** — No visible container until hover. Icon-only triggers, compact toolbars.\n- **outline** — Bordered ghost — visible structure, no fill until hover. Marketing CTA, download button; hover fills accent.\n- **danger** — Destructive action. Delete, remove, disconnect.\n- **danger-subtle** — Destructive context, low urgency. Warning badges, soft destructive hints.\n- **success | warning** — Status communication (Tag only). Status badges, labels.\n\n## Rules\n\n- One accent per visual group; everything else neutral or ghost.\n- danger only for actions with real consequences.\n- Sizes are px numbers (24|32|40|48), never S/M/L.\n- Typography tokens are --psi-text-{size}-{lineHeight}-{weight}.\n- Override component tokens (--psi-{component}-*), not semantic tokens, for one-off theming.\n- --psi-button-font overrides button typography across all sizes (documented D34 override; ember → mono).\n"
|
|
121
121
|
},
|
|
122
122
|
{
|
|
123
123
|
"name": "Card",
|
|
124
|
-
"description": "",
|
|
124
|
+
"description": "Content container with an optional edge-to-edge media slot; `stacked` (media above body) or `featured` (media beside body) layout.",
|
|
125
125
|
"props": [
|
|
126
126
|
{
|
|
127
127
|
"name": "variant",
|
|
@@ -159,11 +159,11 @@
|
|
|
159
159
|
"description": "Additional CSS class name(s) merged onto the component's root element."
|
|
160
160
|
}
|
|
161
161
|
],
|
|
162
|
-
"doc": "<!-- Generated by emit-docs.ts — do not edit. -->\n# Card\n\n\n
|
|
162
|
+
"doc": "<!-- Generated by emit-docs.ts — do not edit. -->\n# Card\n\nContent container with an optional edge-to-edge media slot; `stacked` (media above body) or `featured` (media beside body) layout.\n\n## Props\n\n| Prop | Type | Default | Required | Description |\n|---|---|---|---|---|\n| `variant` | `\"stacked\" \\| \"featured\"` | stacked | no | stacked = media above body; featured = media beside body (~1.6fr/1fr), stacks under md. |\n| `media` | `ReactNode` | — | no | Media slot rendered edge-to-edge (img, AspectRatio, …). |\n| `hoverLift` | `boolean` | false | no | Lift on hover: translateY(-6px) over --psi-duration-350. |\n| `ref` | `Ref<HTMLDivElement>` | — | no | Forwarded ref to the root element. |\n| `className` | `string` | — | no | Additional CSS class name(s) merged onto the component's root element. |\n\n## Theming\n\nOverride `--psi-card-*` custom properties at any scope; interactive states derive automatically (L - 0.04 hover, L - 0.08 active).\n\n## Variant guidance\n\n- **accent** — Primary action, draws attention. Submit, CTA, main action in a group.\n- **accent-subtle** — Accent tone, lower visual weight. Selected state, active filter, soft CTA.\n- **neutral** — Default, structurally present. Secondary actions, toolbar buttons.\n- **neutral-subtle** — Minimal chrome. Inline actions, table row actions.\n- **ghost** — No visible container until hover. Icon-only triggers, compact toolbars.\n- **outline** — Bordered ghost — visible structure, no fill until hover. Marketing CTA, download button; hover fills accent.\n- **danger** — Destructive action. Delete, remove, disconnect.\n- **danger-subtle** — Destructive context, low urgency. Warning badges, soft destructive hints.\n- **success | warning** — Status communication (Tag only). Status badges, labels.\n\n## Rules\n\n- One accent per visual group; everything else neutral or ghost.\n- danger only for actions with real consequences.\n- Sizes are px numbers (24|32|40|48), never S/M/L.\n- Typography tokens are --psi-text-{size}-{lineHeight}-{weight}.\n- Override component tokens (--psi-{component}-*), not semantic tokens, for one-off theming.\n- --psi-button-font overrides button typography across all sizes (documented D34 override; ember → mono).\n"
|
|
163
163
|
},
|
|
164
164
|
{
|
|
165
165
|
"name": "Input",
|
|
166
|
-
"description": "",
|
|
166
|
+
"description": "Single-line text input with pixel-true heights (24–48) and an error state.",
|
|
167
167
|
"props": [
|
|
168
168
|
{
|
|
169
169
|
"name": "size",
|
|
@@ -194,11 +194,11 @@
|
|
|
194
194
|
"description": "Additional CSS class name(s) merged onto the component's root element."
|
|
195
195
|
}
|
|
196
196
|
],
|
|
197
|
-
"doc": "<!-- Generated by emit-docs.ts — do not edit. -->\n# Input\n\n\n
|
|
197
|
+
"doc": "<!-- Generated by emit-docs.ts — do not edit. -->\n# Input\n\nSingle-line text input with pixel-true heights (24–48) and an error state.\n\n## Props\n\n| Prop | Type | Default | Required | Description |\n|---|---|---|---|---|\n| `size` | `24 \\| 32 \\| 40 \\| 48` | 32 | no | Height in px (24 \\| 32 \\| 40 \\| 48). |\n| `error` | `boolean` | false | no | Show error styling. |\n| `ref` | `Ref<HTMLInputElement>` | — | no | Forwarded ref to the underlying `<input>` element. |\n| `className` | `string` | — | no | Additional CSS class name(s) merged onto the component's root element. |\n\n## Keyboard & assistive tech\n\n| Keys | Behavior |\n|---|---|\n| Tab | Focuses the native <input>; focus ring on the field. |\n\nerror sets a red border only — pair with aria-invalid and aria-describedby pointing at your error text.\n\n## Theming\n\nOverride `--psi-input-*` custom properties at any scope; interactive states derive automatically (L - 0.04 hover, L - 0.08 active).\n\n\n\n## Rules\n\n- One accent per visual group; everything else neutral or ghost.\n- danger only for actions with real consequences.\n- Sizes are px numbers (24|32|40|48), never S/M/L.\n- Typography tokens are --psi-text-{size}-{lineHeight}-{weight}.\n- Override component tokens (--psi-{component}-*), not semantic tokens, for one-off theming.\n- --psi-button-font overrides button typography across all sizes (documented D34 override; ember → mono).\n"
|
|
198
198
|
},
|
|
199
199
|
{
|
|
200
200
|
"name": "Select",
|
|
201
|
-
"description": "",
|
|
201
|
+
"description": "Styled native `<select>` with pixel-true heights (24–48) and an error state.",
|
|
202
202
|
"props": [
|
|
203
203
|
{
|
|
204
204
|
"name": "size",
|
|
@@ -229,11 +229,11 @@
|
|
|
229
229
|
"description": "Additional CSS class name(s) merged onto the component's root element."
|
|
230
230
|
}
|
|
231
231
|
],
|
|
232
|
-
"doc": "<!-- Generated by emit-docs.ts — do not edit. -->\n# Select\n\n\n
|
|
232
|
+
"doc": "<!-- Generated by emit-docs.ts — do not edit. -->\n# Select\n\nStyled native `<select>` with pixel-true heights (24–48) and an error state.\n\n## Props\n\n| Prop | Type | Default | Required | Description |\n|---|---|---|---|---|\n| `size` | `24 \\| 32 \\| 40 \\| 48` | 32 | no | Height in px (24 \\| 32 \\| 40 \\| 48). Replaces the native `size` attribute (which sets the visible option-row count on a listbox-style `<select>`) with the design system's control height in pixels. |\n| `error` | `boolean` | false | no | Show error styling. |\n| `ref` | `Ref<HTMLSelectElement>` | — | no | Forwarded ref to the underlying `<select>` element. |\n| `className` | `string` | — | no | Additional CSS class name(s) merged onto the component's root element. |\n\n## Keyboard & assistive tech\n\n| Keys | Behavior |\n|---|---|\n| Tab | Focuses the native <select>. |\n| Arrow keys / typeahead | Native option navigation. |\n\nerror: same contract as Input.\n\n## Theming\n\nOverride `--psi-select-*` custom properties at any scope; interactive states derive automatically (L - 0.04 hover, L - 0.08 active).\n\n\n\n## Rules\n\n- One accent per visual group; everything else neutral or ghost.\n- danger only for actions with real consequences.\n- Sizes are px numbers (24|32|40|48), never S/M/L.\n- Typography tokens are --psi-text-{size}-{lineHeight}-{weight}.\n- Override component tokens (--psi-{component}-*), not semantic tokens, for one-off theming.\n- --psi-button-font overrides button typography across all sizes (documented D34 override; ember → mono).\n"
|
|
233
233
|
},
|
|
234
234
|
{
|
|
235
235
|
"name": "Checkbox",
|
|
236
|
-
"description": "",
|
|
236
|
+
"description": "Native checkbox with a built-in label; for independent binary choices.",
|
|
237
237
|
"props": [
|
|
238
238
|
{
|
|
239
239
|
"name": "children",
|
|
@@ -257,11 +257,11 @@
|
|
|
257
257
|
"description": "Additional CSS class name(s) merged onto the component's root element."
|
|
258
258
|
}
|
|
259
259
|
],
|
|
260
|
-
"doc": "<!-- Generated by emit-docs.ts — do not edit. -->\n# Checkbox\n\n\n
|
|
260
|
+
"doc": "<!-- Generated by emit-docs.ts — do not edit. -->\n# Checkbox\n\nNative checkbox with a built-in label; for independent binary choices.\n\n## Props\n\n| Prop | Type | Default | Required | Description |\n|---|---|---|---|---|\n| `children` | `ReactNode` | — | no | Label text. |\n| `ref` | `Ref<HTMLInputElement>` | — | no | Forwarded ref to the underlying `<input type=\"checkbox\">` element. |\n| `className` | `string` | — | no | Additional CSS class name(s) merged onto the component's root element. |\n\n## Keyboard & assistive tech\n\n| Keys | Behavior |\n|---|---|\n| Space | Toggles. Native <input type=checkbox> underneath (visually hidden). |\n\n\n## Theming\n\nOverride `--psi-checkbox-*` custom properties at any scope; interactive states derive automatically (L - 0.04 hover, L - 0.08 active).\n\n\n\n## Rules\n\n- One accent per visual group; everything else neutral or ghost.\n- danger only for actions with real consequences.\n- Sizes are px numbers (24|32|40|48), never S/M/L.\n- Typography tokens are --psi-text-{size}-{lineHeight}-{weight}.\n- Override component tokens (--psi-{component}-*), not semantic tokens, for one-off theming.\n- --psi-button-font overrides button typography across all sizes (documented D34 override; ember → mono).\n"
|
|
261
261
|
},
|
|
262
262
|
{
|
|
263
263
|
"name": "Switch",
|
|
264
|
-
"description": "",
|
|
264
|
+
"description": "On/off toggle (`role=\"switch\"`) with a built-in label; for settings that take effect immediately.",
|
|
265
265
|
"props": [
|
|
266
266
|
{
|
|
267
267
|
"name": "children",
|
|
@@ -285,11 +285,11 @@
|
|
|
285
285
|
"description": "Additional CSS class name(s) merged onto the component's root element."
|
|
286
286
|
}
|
|
287
287
|
],
|
|
288
|
-
"doc": "<!-- Generated by emit-docs.ts — do not edit. -->\n# Switch\n\
|
|
288
|
+
"doc": "<!-- Generated by emit-docs.ts — do not edit. -->\n# Switch\n\nOn/off toggle (`role=\"switch\"`) with a built-in label; for settings that take effect immediately.\n\n## Props\n\n| Prop | Type | Default | Required | Description |\n|---|---|---|---|---|\n| `children` | `ReactNode` | — | no | Label text. |\n| `ref` | `Ref<HTMLInputElement>` | — | no | Forwarded ref to the underlying `<input type=\"checkbox\" role=\"switch\">` element. |\n| `className` | `string` | — | no | Additional CSS class name(s) merged onto the component's root element. |\n\n## Keyboard & assistive tech\n\n| Keys | Behavior |\n|---|---|\n| Space | Toggles. Native checkbox input with role=\"switch\"; announced as a switch, not a checkbox. |\n\n\n## Theming\n\nOverride `--psi-switch-*` custom properties at any scope; interactive states derive automatically (L - 0.04 hover, L - 0.08 active).\n\n\n\n## Rules\n\n- One accent per visual group; everything else neutral or ghost.\n- danger only for actions with real consequences.\n- Sizes are px numbers (24|32|40|48), never S/M/L.\n- Typography tokens are --psi-text-{size}-{lineHeight}-{weight}.\n- Override component tokens (--psi-{component}-*), not semantic tokens, for one-off theming.\n- --psi-button-font overrides button typography across all sizes (documented D34 override; ember → mono).\n"
|
|
289
289
|
},
|
|
290
290
|
{
|
|
291
291
|
"name": "Tag",
|
|
292
|
-
"description": "",
|
|
292
|
+
"description": "Compact label for status or category; semantic variants, optional subtle tint and dismiss button.",
|
|
293
293
|
"props": [
|
|
294
294
|
{
|
|
295
295
|
"name": "variant",
|
|
@@ -327,11 +327,11 @@
|
|
|
327
327
|
"description": "Additional CSS class name(s) merged onto the component's root element."
|
|
328
328
|
}
|
|
329
329
|
],
|
|
330
|
-
"doc": "<!-- Generated by emit-docs.ts — do not edit. -->\n# Tag\n\n\n
|
|
330
|
+
"doc": "<!-- Generated by emit-docs.ts — do not edit. -->\n# Tag\n\nCompact label for status or category; semantic variants, optional subtle tint and dismiss button.\n\n## Props\n\n| Prop | Type | Default | Required | Description |\n|---|---|---|---|---|\n| `variant` | `\"neutral\" \\| \"accent\" \\| \"success\" \\| \"warning\" \\| \"danger\"` | neutral | no | Semantic color variant. |\n| `subtle` | `boolean` | false | no | Use tinted background with semantic foreground. |\n| `onDismiss` | `(() => void)` | — | no | When provided, renders a dismiss button that calls this handler. |\n| `ref` | `Ref<HTMLSpanElement>` | — | no | Forwarded ref to the underlying `<span>` element. |\n| `className` | `string` | — | no | Additional CSS class name(s) merged onto the component's root element. |\n\n## Keyboard & assistive tech\n\n| Keys | Behavior |\n|---|---|\n| Enter / Space (dismiss button) | onDismiss renders a real <button>; keyboard-dismissible. |\n\nPassive label otherwise; not in the tab order without onDismiss.\n\n## Theming\n\nOverride `--psi-tag-*` custom properties at any scope; interactive states derive automatically (L - 0.04 hover, L - 0.08 active).\n\n## Variant guidance\n\n- **accent** — Primary action, draws attention. Submit, CTA, main action in a group.\n- **accent-subtle** — Accent tone, lower visual weight. Selected state, active filter, soft CTA.\n- **neutral** — Default, structurally present. Secondary actions, toolbar buttons.\n- **neutral-subtle** — Minimal chrome. Inline actions, table row actions.\n- **ghost** — No visible container until hover. Icon-only triggers, compact toolbars.\n- **outline** — Bordered ghost — visible structure, no fill until hover. Marketing CTA, download button; hover fills accent.\n- **danger** — Destructive action. Delete, remove, disconnect.\n- **danger-subtle** — Destructive context, low urgency. Warning badges, soft destructive hints.\n- **success | warning** — Status communication (Tag only). Status badges, labels.\n\n## Rules\n\n- One accent per visual group; everything else neutral or ghost.\n- danger only for actions with real consequences.\n- Sizes are px numbers (24|32|40|48), never S/M/L.\n- Typography tokens are --psi-text-{size}-{lineHeight}-{weight}.\n- Override component tokens (--psi-{component}-*), not semantic tokens, for one-off theming.\n- --psi-button-font overrides button typography across all sizes (documented D34 override; ember → mono).\n"
|
|
331
331
|
},
|
|
332
332
|
{
|
|
333
333
|
"name": "Tooltip",
|
|
334
|
-
"description": "",
|
|
334
|
+
"description": "Short hover/focus hint attached to a single trigger element.",
|
|
335
335
|
"props": [
|
|
336
336
|
{
|
|
337
337
|
"name": "content",
|
|
@@ -355,11 +355,11 @@
|
|
|
355
355
|
"description": "Preferred placement."
|
|
356
356
|
}
|
|
357
357
|
],
|
|
358
|
-
"doc": "<!-- Generated by emit-docs.ts — do not edit. -->\n# Tooltip\n\n\n
|
|
358
|
+
"doc": "<!-- Generated by emit-docs.ts — do not edit. -->\n# Tooltip\n\nShort hover/focus hint attached to a single trigger element.\n\n## Props\n\n| Prop | Type | Default | Required | Description |\n|---|---|---|---|---|\n| `content` | `ReactNode` | — | yes | Tooltip content. |\n| `children` | `ReactElement<Record<string, unknown>, string \\| JSXElementConstructor<any>>` | — | yes | The trigger element (must accept ref, onMouseEnter/Leave, onFocus/Blur). |\n| `placement` | `\"top\" \\| \"bottom\" \\| \"left\" \\| \"right\"` | top | no | Preferred placement. |\n\n## Keyboard & assistive tech\n\n| Keys | Behavior |\n|---|---|\n| Tab (focus trigger) | Shows immediately on focus (no delay). |\n| Escape | Dismisses while visible (WCAG 1.4.13). |\n\nHover opens after a short delay; content is linked via aria-describedby while visible. Trigger must accept onMouseEnter/Leave and onFocus/Blur props (cloned in automatically) — no ref forwarding required.\n\n## Theming\n\nOverride `--psi-tooltip-*` custom properties at any scope; interactive states derive automatically (L - 0.04 hover, L - 0.08 active).\n\n\n\n## Rules\n\n- One accent per visual group; everything else neutral or ghost.\n- danger only for actions with real consequences.\n- Sizes are px numbers (24|32|40|48), never S/M/L.\n- Typography tokens are --psi-text-{size}-{lineHeight}-{weight}.\n- Override component tokens (--psi-{component}-*), not semantic tokens, for one-off theming.\n- --psi-button-font overrides button typography across all sizes (documented D34 override; ember → mono).\n"
|
|
359
359
|
},
|
|
360
360
|
{
|
|
361
361
|
"name": "NavBar",
|
|
362
|
-
"description": "",
|
|
362
|
+
"description": "Top navigation bar with brand, nav-link, and trailing-action slots.",
|
|
363
363
|
"props": [
|
|
364
364
|
{
|
|
365
365
|
"name": "brand",
|
|
@@ -397,11 +397,11 @@
|
|
|
397
397
|
"description": "Additional CSS class name(s) merged onto the component's root element."
|
|
398
398
|
}
|
|
399
399
|
],
|
|
400
|
-
"doc": "<!-- Generated by emit-docs.ts — do not edit. -->\n# NavBar\n\n\n
|
|
400
|
+
"doc": "<!-- Generated by emit-docs.ts — do not edit. -->\n# NavBar\n\nTop navigation bar with brand, nav-link, and trailing-action slots.\n\n## Props\n\n| Prop | Type | Default | Required | Description |\n|---|---|---|---|---|\n| `brand` | `ReactNode` | — | no | Brand slot (wordmark / logo link), leading edge. |\n| `actions` | `ReactNode` | — | no | Trailing actions slot (theme switch, CTA). |\n| `children` | `ReactNode` | — | no | Nav links. |\n| `ref` | `Ref<HTMLElement>` | — | no | Forwarded ref to the header element. |\n| `className` | `string` | — | no | Additional CSS class name(s) merged onto the component's root element. |\n\n## Theming\n\nOverride `--psi-navbar-*` custom properties at any scope; interactive states derive automatically (L - 0.04 hover, L - 0.08 active).\n\n\n\n## Rules\n\n- One accent per visual group; everything else neutral or ghost.\n- danger only for actions with real consequences.\n- Sizes are px numbers (24|32|40|48), never S/M/L.\n- Typography tokens are --psi-text-{size}-{lineHeight}-{weight}.\n- Override component tokens (--psi-{component}-*), not semantic tokens, for one-off theming.\n- --psi-button-font overrides button typography across all sizes (documented D34 override; ember → mono).\n"
|
|
401
401
|
},
|
|
402
402
|
{
|
|
403
403
|
"name": "AspectRatio",
|
|
404
|
-
"description": "",
|
|
404
|
+
"description": "Fixed-aspect-ratio box that sizes its child media.",
|
|
405
405
|
"props": [
|
|
406
406
|
{
|
|
407
407
|
"name": "ratio",
|
|
@@ -425,7 +425,7 @@
|
|
|
425
425
|
"description": "Additional CSS class name(s) merged onto the component's root element."
|
|
426
426
|
}
|
|
427
427
|
],
|
|
428
|
-
"doc": "<!-- Generated by emit-docs.ts — do not edit. -->\n# AspectRatio\n\n\n
|
|
428
|
+
"doc": "<!-- Generated by emit-docs.ts — do not edit. -->\n# AspectRatio\n\nFixed-aspect-ratio box that sizes its child media.\n\n## Props\n\n| Prop | Type | Default | Required | Description |\n|---|---|---|---|---|\n| `ratio` | `number` | — | yes | Width/height ratio, e.g. 16/10 or 4/5. |\n| `ref` | `Ref<HTMLDivElement>` | — | no | Forwarded ref to the frame element. |\n| `className` | `string` | — | no | Additional CSS class name(s) merged onto the component's root element. |\n\n## Theming\n\nOverride `--psi-aspect-ratio-*` custom properties at any scope; interactive states derive automatically (L - 0.04 hover, L - 0.08 active).\n\n\n\n## Rules\n\n- One accent per visual group; everything else neutral or ghost.\n- danger only for actions with real consequences.\n- Sizes are px numbers (24|32|40|48), never S/M/L.\n- Typography tokens are --psi-text-{size}-{lineHeight}-{weight}.\n- Override component tokens (--psi-{component}-*), not semantic tokens, for one-off theming.\n- --psi-button-font overrides button typography across all sizes (documented D34 override; ember → mono).\n"
|
|
429
429
|
}
|
|
430
430
|
],
|
|
431
431
|
"tokens": [
|
|
@@ -2009,10 +2009,85 @@
|
|
|
2009
2009
|
"@handamade/psi-tokens/base.css",
|
|
2010
2010
|
"@handamade/psi-tokens/<theme>.css — one per theme you use (light|dark|acme|ember)",
|
|
2011
2011
|
"@handamade/psi-tokens/components.css",
|
|
2012
|
-
"@handamade/psi-tokens/utilities.css — REQUIRED: .psi-container + reduced-motion zeroing"
|
|
2012
|
+
"@handamade/psi-tokens/utilities.css — REQUIRED: .psi-container + reduced-motion zeroing",
|
|
2013
|
+
"@handamade/psi-react/styles — REQUIRED: component CSS. Separate export; the JS never imports it for you. Without it every component renders unstyled (HAN-17 finding)."
|
|
2013
2014
|
],
|
|
2014
2015
|
"themeAttribute": "Set data-psi-theme=\"light|dark|acme|ember\" on <html> or a subtree root.",
|
|
2015
2016
|
"rules": "Sizes are px numbers (24 | 32 | 40 | 48), never S/M/L. Variants are flat (accent, accent-subtle, neutral, neutral-subtle, ghost, danger, danger-subtle, outline); one accent per visual group (Tags exempt, D40); danger only for destructive actions. Never hardcode colors — bind var(--psi-*)."
|
|
2017
|
+
},
|
|
2018
|
+
"themes": {
|
|
2019
|
+
"themes": [
|
|
2020
|
+
"light",
|
|
2021
|
+
"dark",
|
|
2022
|
+
"acme",
|
|
2023
|
+
"ember"
|
|
2024
|
+
],
|
|
2025
|
+
"attribute": "Set data-psi-theme=\"light|dark|acme|ember\" on <html> or a subtree root.",
|
|
2026
|
+
"switching": "Theme CSS files are scoped under [data-psi-theme] and co-import safely — import every theme you switch between at runtime.",
|
|
2027
|
+
"customerThemes": "light/dark are the core pair; acme and ember are customer brand themes (OKLCH formula overrides, same semantic token names)."
|
|
2028
|
+
},
|
|
2029
|
+
"scales": {
|
|
2030
|
+
"space": [
|
|
2031
|
+
0,
|
|
2032
|
+
2,
|
|
2033
|
+
4,
|
|
2034
|
+
6,
|
|
2035
|
+
8,
|
|
2036
|
+
12,
|
|
2037
|
+
16,
|
|
2038
|
+
20,
|
|
2039
|
+
24,
|
|
2040
|
+
32,
|
|
2041
|
+
40,
|
|
2042
|
+
48,
|
|
2043
|
+
64,
|
|
2044
|
+
80,
|
|
2045
|
+
96,
|
|
2046
|
+
120,
|
|
2047
|
+
144
|
|
2048
|
+
],
|
|
2049
|
+
"size": [
|
|
2050
|
+
24,
|
|
2051
|
+
32,
|
|
2052
|
+
40,
|
|
2053
|
+
48
|
|
2054
|
+
],
|
|
2055
|
+
"radius": [
|
|
2056
|
+
4,
|
|
2057
|
+
6,
|
|
2058
|
+
8,
|
|
2059
|
+
12
|
|
2060
|
+
],
|
|
2061
|
+
"motion": {
|
|
2062
|
+
"durations": [
|
|
2063
|
+
150,
|
|
2064
|
+
200,
|
|
2065
|
+
350,
|
|
2066
|
+
450,
|
|
2067
|
+
600
|
|
2068
|
+
],
|
|
2069
|
+
"easings": {
|
|
2070
|
+
"standard": "ease",
|
|
2071
|
+
"in-out": "ease-in-out",
|
|
2072
|
+
"soft": "cubic-bezier(0.2, 0.6, 0.2, 1)"
|
|
2073
|
+
}
|
|
2074
|
+
},
|
|
2075
|
+
"layout": {
|
|
2076
|
+
"breakpoints": {
|
|
2077
|
+
"sm": 560,
|
|
2078
|
+
"md": 960
|
|
2079
|
+
},
|
|
2080
|
+
"container": {
|
|
2081
|
+
"max": 1312,
|
|
2082
|
+
"gutter": 40,
|
|
2083
|
+
"gutterNarrow": 24
|
|
2084
|
+
},
|
|
2085
|
+
"zIndex": {
|
|
2086
|
+
"nav": 100,
|
|
2087
|
+
"overlay": 1000,
|
|
2088
|
+
"tooltip": 1100
|
|
2089
|
+
}
|
|
2090
|
+
}
|
|
2016
2091
|
}
|
|
2017
2092
|
}
|
|
2018
2093
|
}
|
package/dist/store.js
CHANGED
|
@@ -9,7 +9,10 @@ const TOPIC_SUMMARIES = {
|
|
|
9
9
|
layout: "Breakpoints, container, z-index",
|
|
10
10
|
recipes: "Composition recipes (mediaTint, sectionHeader)",
|
|
11
11
|
tags: "Tag/badge rules incl. the accent exemption (D40)",
|
|
12
|
-
"getting-started": "Install, the
|
|
12
|
+
"getting-started": "Install, the five required CSS imports, theme attribute, core rules",
|
|
13
|
+
themes: "Theme list (light|dark|acme|ember), data-psi-theme mechanics, customer themes",
|
|
14
|
+
scales: "Pixel scales — space, size, radius, motion, layout — the values behind " +
|
|
15
|
+
"--psi-space-* / --psi-radius-* / --psi-duration-*",
|
|
13
16
|
};
|
|
14
17
|
function componentSummary(c) {
|
|
15
18
|
const axis = (name) => c.props.find((p) => p.name === name)?.type;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@handamade/psi-mcp",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "MCP server and agent-context generator for the Psi (Ψ) design system",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -32,8 +32,8 @@
|
|
|
32
32
|
"tsx": "^4.22.4",
|
|
33
33
|
"typescript": "^5.7.0",
|
|
34
34
|
"vitest": "^3.2.6",
|
|
35
|
-
"@handamade/psi-react": "0.4.
|
|
36
|
-
"@handamade/psi-tokens": "0.4.
|
|
35
|
+
"@handamade/psi-react": "0.4.1",
|
|
36
|
+
"@handamade/psi-tokens": "0.4.1"
|
|
37
37
|
},
|
|
38
38
|
"scripts": {
|
|
39
39
|
"build": "tsx scripts/build-index.ts && tsc -p tsconfig.build.json"
|