@grampro/kit 2.6.2 → 2.7.0
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/.gbs/skills/gbs-components/SKILL.md +5 -4
- package/.gbs/skills/gbs-components/references/install.md +17 -14
- package/CHANGELOG.md +201 -18
- package/README.md +24 -6
- package/index.cjs +59 -59
- package/package.json +2 -2
- package/schema/passport-overlay-v1.schema.json +67 -0
- package/source/components/accordion/passport.json +45 -8
- package/source/components/accordion/passport.manual.json +46 -0
- package/source/components/alert/passport.json +41 -8
- package/source/components/alert/passport.manual.json +42 -0
- package/source/components/avatar/passport.json +40 -7
- package/source/components/avatar/passport.manual.json +43 -0
- package/source/components/badge/passport.json +43 -7
- package/source/components/badge/passport.manual.json +46 -0
- package/source/components/breadcrumb/passport.json +36 -7
- package/source/components/breadcrumb/passport.manual.json +39 -0
- package/source/components/button/passport.json +1 -1
- package/source/components/button/passport.manual.json +1 -1
- package/source/components/card/passport.json +45 -8
- package/source/components/card/passport.manual.json +47 -0
- package/source/components/checkbox/core/agent.ts +33 -0
- package/source/components/checkbox/core/index.ts +2 -0
- package/source/components/checkbox/passport.json +83 -10
- package/source/components/checkbox/passport.manual.json +82 -0
- package/source/components/combobox/core/agent.ts +38 -0
- package/source/components/combobox/core/index.ts +2 -0
- package/source/components/combobox/passport.json +103 -11
- package/source/components/combobox/passport.manual.json +101 -0
- package/source/components/combobox/react/props.ts +14 -0
- package/source/components/combobox/react/useCombobox.ts +7 -1
- package/source/components/data-grid/export/xlsx.ts +9 -2
- package/source/components/data-grid/passport.json +2 -2
- package/source/components/data-grid/passport.manual.json +1 -1
- package/source/components/date-picker/core/agent.ts +42 -0
- package/source/components/date-picker/core/index.ts +2 -0
- package/source/components/date-picker/passport.json +102 -11
- package/source/components/date-picker/passport.manual.json +100 -0
- package/source/components/date-picker/react/DatePicker.tsx +6 -0
- package/source/components/date-picker/react/DateRangePicker.tsx +4 -0
- package/source/components/date-picker/react/props.ts +17 -0
- package/source/components/dialog/passport.json +54 -9
- package/source/components/dialog/passport.manual.json +54 -0
- package/source/components/file-uploader/passport.json +65 -10
- package/source/components/file-uploader/passport.manual.json +64 -0
- package/source/components/input/core/agent.ts +36 -0
- package/source/components/input/core/index.ts +2 -0
- package/source/components/input/passport.json +89 -12
- package/source/components/input/passport.manual.json +86 -0
- package/source/components/menu/passport.json +64 -9
- package/source/components/menu/passport.manual.json +64 -0
- package/source/components/modal/passport.json +52 -9
- package/source/components/modal/passport.manual.json +52 -0
- package/source/components/number-input/core/agent.ts +38 -0
- package/source/components/number-input/core/index.ts +2 -0
- package/source/components/number-input/passport.json +92 -11
- package/source/components/number-input/passport.manual.json +90 -0
- package/source/components/popover/passport.json +47 -8
- package/source/components/popover/passport.manual.json +48 -0
- package/source/components/progress/passport.json +37 -8
- package/source/components/progress/passport.manual.json +39 -0
- package/source/components/radio-group/core/agent.ts +34 -0
- package/source/components/radio-group/core/index.ts +2 -0
- package/source/components/radio-group/passport.json +77 -10
- package/source/components/radio-group/passport.manual.json +76 -0
- package/source/components/shared/core/agent/field-agent.ts +101 -0
- package/source/components/shared/core/agent/field-executors.ts +137 -0
- package/source/components/shared/core/agent/field.ts +649 -0
- package/source/components/shared/core/agent/index.ts +30 -0
- package/source/components/shared/core/agent/write.ts +58 -0
- package/source/components/shared/react/useFieldAgent.ts +88 -0
- package/source/components/skeleton/passport.json +37 -6
- package/source/components/skeleton/passport.manual.json +39 -0
- package/source/components/spinner/passport.json +34 -7
- package/source/components/spinner/passport.manual.json +37 -0
- package/source/components/switch/core/agent.ts +31 -0
- package/source/components/switch/core/index.ts +2 -0
- package/source/components/switch/passport.json +68 -10
- package/source/components/switch/passport.manual.json +67 -0
- package/source/components/tabs/passport.json +50 -9
- package/source/components/tabs/passport.manual.json +50 -0
- package/source/components/textarea/core/agent.ts +34 -0
- package/source/components/textarea/core/index.ts +2 -0
- package/source/components/textarea/passport.json +83 -10
- package/source/components/textarea/passport.manual.json +82 -0
- package/source/components/toaster/passport.json +41 -8
- package/source/components/toaster/passport.manual.json +42 -0
- package/source/components/tooltip/passport.json +39 -6
- package/source/components/tooltip/passport.manual.json +41 -0
- package/tools/mcp/README.md +9 -1
- package/tools/mcp/design.cjs +6 -1
- package/tools/mcp/figma.cjs +49 -9
- package/tools/mcp/install.cjs +6 -1
- package/tools/mcp/server.cjs +14 -2
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
]
|
|
13
13
|
},
|
|
14
14
|
"source": {
|
|
15
|
-
"libraryVersion": "2.
|
|
15
|
+
"libraryVersion": "2.7.0",
|
|
16
16
|
"files": [
|
|
17
17
|
"core/index.ts",
|
|
18
18
|
"core/navigation.ts",
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
],
|
|
24
24
|
"sourceHash": "sha256:3d8e29857c59101e547f234c45735db68cc87ee143cc87d841372ec612e2c663"
|
|
25
25
|
},
|
|
26
|
+
"purpose": "Tabs in underline, pill or segmented styles, horizontal or vertical, with panels that can stay mounted when hidden.",
|
|
26
27
|
"props": [
|
|
27
28
|
{
|
|
28
29
|
"name": "activation",
|
|
@@ -36,7 +37,8 @@
|
|
|
36
37
|
"default": "automatic",
|
|
37
38
|
"origin": "derived",
|
|
38
39
|
"description": "Default `automatic`: arrow keys select as they move.",
|
|
39
|
-
"descriptionOrigin": "jsdoc"
|
|
40
|
+
"descriptionOrigin": "jsdoc",
|
|
41
|
+
"note": "`automatic` selects as focus moves; `manual` waits for Enter or Space."
|
|
40
42
|
},
|
|
41
43
|
{
|
|
42
44
|
"name": "aria-describedby",
|
|
@@ -143,7 +145,8 @@
|
|
|
143
145
|
"default": false,
|
|
144
146
|
"origin": "derived",
|
|
145
147
|
"description": "Overrides `keepMounted` on `Tabs` for this panel.",
|
|
146
|
-
"descriptionOrigin": "jsdoc"
|
|
148
|
+
"descriptionOrigin": "jsdoc",
|
|
149
|
+
"note": "Keeps hidden panels in the DOM, so form state and scroll position survive a switch. Costs the render."
|
|
147
150
|
},
|
|
148
151
|
{
|
|
149
152
|
"name": "name",
|
|
@@ -300,20 +303,58 @@
|
|
|
300
303
|
}
|
|
301
304
|
],
|
|
302
305
|
"accessibility": {
|
|
303
|
-
"supplied": [
|
|
304
|
-
|
|
306
|
+
"supplied": [
|
|
307
|
+
"the tabs pattern: role=tablist with one tab stop, arrow keys between tabs, Home and End to the ends",
|
|
308
|
+
"each tab is linked to its panel by aria-controls and aria-labelledby",
|
|
309
|
+
"`activation` chooses whether moving focus selects, or whether Enter is needed"
|
|
310
|
+
],
|
|
311
|
+
"required": [
|
|
312
|
+
"tab labels that make sense read out of context, since that is how they are announced",
|
|
313
|
+
"manual `activation` when switching a tab is expensive, so arrowing past one does not load it"
|
|
314
|
+
]
|
|
315
|
+
},
|
|
316
|
+
"composition": {
|
|
317
|
+
"allowedChildren": [
|
|
318
|
+
"TabList",
|
|
319
|
+
"Tab",
|
|
320
|
+
"TabPanel"
|
|
321
|
+
],
|
|
322
|
+
"notes": "Every Tab needs a TabPanel with the matching value. Tabs are not a substitute for navigation between URLs."
|
|
305
323
|
},
|
|
306
|
-
"composition": {},
|
|
307
324
|
"operations": {},
|
|
308
|
-
"intentDomains": [
|
|
309
|
-
|
|
325
|
+
"intentDomains": [
|
|
326
|
+
"ActionIntent"
|
|
327
|
+
],
|
|
328
|
+
"safeMutations": {
|
|
329
|
+
"allowed": [
|
|
330
|
+
"variant",
|
|
331
|
+
"size",
|
|
332
|
+
"orientation",
|
|
333
|
+
"icon",
|
|
334
|
+
"badge",
|
|
335
|
+
"keepMounted",
|
|
336
|
+
"activation"
|
|
337
|
+
],
|
|
338
|
+
"forbidden": [
|
|
339
|
+
"value",
|
|
340
|
+
"defaultValue",
|
|
341
|
+
"onValueChange",
|
|
342
|
+
"name",
|
|
343
|
+
"disabled"
|
|
344
|
+
],
|
|
345
|
+
"rationale": "Styling and layout are safe. The selected tab is application state."
|
|
346
|
+
},
|
|
310
347
|
"examples": [],
|
|
311
348
|
"coverage": {
|
|
312
349
|
"propsTotal": 11,
|
|
313
350
|
"propsDescribed": 9,
|
|
314
351
|
"describedPct": 82,
|
|
315
352
|
"authoredSections": [
|
|
316
|
-
"accessibility"
|
|
353
|
+
"accessibility",
|
|
354
|
+
"composition",
|
|
355
|
+
"intentDomains",
|
|
356
|
+
"purpose",
|
|
357
|
+
"safeMutations"
|
|
317
358
|
]
|
|
318
359
|
}
|
|
319
360
|
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../../../schema/passport-overlay-v1.schema.json",
|
|
3
|
+
"component": "Tabs",
|
|
4
|
+
"purpose": "Tabs in underline, pill or segmented styles, horizontal or vertical, with panels that can stay mounted when hidden.",
|
|
5
|
+
"intentDomains": [
|
|
6
|
+
"ActionIntent"
|
|
7
|
+
],
|
|
8
|
+
"accessibility": {
|
|
9
|
+
"supplied": [
|
|
10
|
+
"the tabs pattern: role=tablist with one tab stop, arrow keys between tabs, Home and End to the ends",
|
|
11
|
+
"each tab is linked to its panel by aria-controls and aria-labelledby",
|
|
12
|
+
"`activation` chooses whether moving focus selects, or whether Enter is needed"
|
|
13
|
+
],
|
|
14
|
+
"required": [
|
|
15
|
+
"tab labels that make sense read out of context, since that is how they are announced",
|
|
16
|
+
"manual `activation` when switching a tab is expensive, so arrowing past one does not load it"
|
|
17
|
+
]
|
|
18
|
+
},
|
|
19
|
+
"composition": {
|
|
20
|
+
"allowedChildren": [
|
|
21
|
+
"TabList",
|
|
22
|
+
"Tab",
|
|
23
|
+
"TabPanel"
|
|
24
|
+
],
|
|
25
|
+
"notes": "Every Tab needs a TabPanel with the matching value. Tabs are not a substitute for navigation between URLs."
|
|
26
|
+
},
|
|
27
|
+
"safeMutations": {
|
|
28
|
+
"allowed": [
|
|
29
|
+
"variant",
|
|
30
|
+
"size",
|
|
31
|
+
"orientation",
|
|
32
|
+
"icon",
|
|
33
|
+
"badge",
|
|
34
|
+
"keepMounted",
|
|
35
|
+
"activation"
|
|
36
|
+
],
|
|
37
|
+
"forbidden": [
|
|
38
|
+
"value",
|
|
39
|
+
"defaultValue",
|
|
40
|
+
"onValueChange",
|
|
41
|
+
"name",
|
|
42
|
+
"disabled"
|
|
43
|
+
],
|
|
44
|
+
"rationale": "Styling and layout are safe. The selected tab is application state."
|
|
45
|
+
},
|
|
46
|
+
"propNotes": {
|
|
47
|
+
"keepMounted": "Keeps hidden panels in the DOM, so form state and scroll position survive a switch. Costs the render.",
|
|
48
|
+
"activation": "`automatic` selects as focus moves; `manual` waits for Enter or Space."
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Textarea's agent contract.
|
|
3
|
+
*
|
|
4
|
+
* Identical to Input but for the element behind it, which is why both go
|
|
5
|
+
* through the same executor.
|
|
6
|
+
*
|
|
7
|
+
* Pure: no React, no DOM. The contract is what this instance will accept, and
|
|
8
|
+
* the validator in shared/core/agent decides everything from it. Build it from
|
|
9
|
+
* props on every render so that a field which has just become read-only stops
|
|
10
|
+
* accepting writes immediately.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import type { FieldContract } from "../../shared/core/agent";
|
|
14
|
+
|
|
15
|
+
export interface TextareaAgentProps {
|
|
16
|
+
label?: string;
|
|
17
|
+
disabled?: boolean;
|
|
18
|
+
readOnly?: boolean;
|
|
19
|
+
required?: boolean;
|
|
20
|
+
maxLength?: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function textareaContract(props: TextareaAgentProps = {}): FieldContract {
|
|
24
|
+
return {
|
|
25
|
+
component: "Textarea",
|
|
26
|
+
kind: "text",
|
|
27
|
+
operations: ["setValue", "clear", "focus"],
|
|
28
|
+
label: props.label,
|
|
29
|
+
disabled: props.disabled,
|
|
30
|
+
readOnly: props.readOnly,
|
|
31
|
+
required: props.required,
|
|
32
|
+
maxLength: props.maxLength,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
@@ -8,8 +8,9 @@
|
|
|
8
8
|
]
|
|
9
9
|
},
|
|
10
10
|
"source": {
|
|
11
|
-
"libraryVersion": "2.
|
|
11
|
+
"libraryVersion": "2.7.0",
|
|
12
12
|
"files": [
|
|
13
|
+
"core/agent.ts",
|
|
13
14
|
"core/count.ts",
|
|
14
15
|
"core/index.ts",
|
|
15
16
|
"core/size.ts",
|
|
@@ -19,8 +20,9 @@
|
|
|
19
20
|
"react/locale.ts",
|
|
20
21
|
"react/props.ts"
|
|
21
22
|
],
|
|
22
|
-
"sourceHash": "sha256:
|
|
23
|
+
"sourceHash": "sha256:161bed57c97bbdede609bde754dcbae8452083825fea7749ee035ce1ace510dc"
|
|
23
24
|
},
|
|
25
|
+
"purpose": "A multi-line text field that can grow with its content, with the same label, hint, error and counter wiring as Input.",
|
|
24
26
|
"props": [
|
|
25
27
|
{
|
|
26
28
|
"name": "aria-describedby",
|
|
@@ -58,7 +60,8 @@
|
|
|
58
60
|
"default": false,
|
|
59
61
|
"origin": "derived",
|
|
60
62
|
"description": "Grow and shrink with the text, between `minRows` and `maxRows`. Default false.",
|
|
61
|
-
"descriptionOrigin": "jsdoc"
|
|
63
|
+
"descriptionOrigin": "jsdoc",
|
|
64
|
+
"note": "Grows the field to its content between `minRows` and `maxRows`. Ignored when `resize` lets the user drag."
|
|
62
65
|
},
|
|
63
66
|
{
|
|
64
67
|
"name": "className",
|
|
@@ -369,20 +372,90 @@
|
|
|
369
372
|
}
|
|
370
373
|
],
|
|
371
374
|
"accessibility": {
|
|
372
|
-
"supplied": [
|
|
373
|
-
|
|
375
|
+
"supplied": [
|
|
376
|
+
"the label is a real <label> bound to the textarea",
|
|
377
|
+
"description and error are linked by aria-describedby",
|
|
378
|
+
"aria-invalid while `error` is set",
|
|
379
|
+
"the character counter is announced as a live region when `showCount` is on"
|
|
380
|
+
],
|
|
381
|
+
"required": [
|
|
382
|
+
"a `label`, or `aria-label` when the field is visually unlabelled",
|
|
383
|
+
"a `maxLength` that matches whatever the server enforces, so the counter does not promise room that does not exist"
|
|
384
|
+
]
|
|
385
|
+
},
|
|
386
|
+
"composition": {
|
|
387
|
+
"mustNotContain": [
|
|
388
|
+
"label",
|
|
389
|
+
"textarea"
|
|
390
|
+
],
|
|
391
|
+
"notes": "It renders its own <label> and <textarea>; wrapping it in a second label misbinds the text."
|
|
392
|
+
},
|
|
393
|
+
"operations": {
|
|
394
|
+
"setValue": {
|
|
395
|
+
"summary": "Write a value into the field, as though a person had entered it.",
|
|
396
|
+
"effects": [
|
|
397
|
+
"replaces the field's current value",
|
|
398
|
+
"fires the host's change handler"
|
|
399
|
+
],
|
|
400
|
+
"reversible": true
|
|
401
|
+
},
|
|
402
|
+
"clear": {
|
|
403
|
+
"summary": "Empty the field.",
|
|
404
|
+
"effects": [
|
|
405
|
+
"discards the field's current value",
|
|
406
|
+
"fires the host's change handler"
|
|
407
|
+
],
|
|
408
|
+
"reversible": true
|
|
409
|
+
},
|
|
410
|
+
"focus": {
|
|
411
|
+
"summary": "Move keyboard focus to the field.",
|
|
412
|
+
"effects": [
|
|
413
|
+
"moves focus"
|
|
414
|
+
],
|
|
415
|
+
"reversible": false
|
|
416
|
+
}
|
|
417
|
+
},
|
|
418
|
+
"intentDomains": [
|
|
419
|
+
"ActionIntent",
|
|
420
|
+
"Summarization"
|
|
421
|
+
],
|
|
422
|
+
"safeMutations": {
|
|
423
|
+
"allowed": [
|
|
424
|
+
"size",
|
|
425
|
+
"placeholder",
|
|
426
|
+
"description",
|
|
427
|
+
"rows",
|
|
428
|
+
"minRows",
|
|
429
|
+
"maxRows",
|
|
430
|
+
"autoResize",
|
|
431
|
+
"resize",
|
|
432
|
+
"showCount"
|
|
433
|
+
],
|
|
434
|
+
"forbidden": [
|
|
435
|
+
"value",
|
|
436
|
+
"defaultValue",
|
|
437
|
+
"name",
|
|
438
|
+
"required",
|
|
439
|
+
"disabled",
|
|
440
|
+
"readOnly",
|
|
441
|
+
"maxLength",
|
|
442
|
+
"onValueChange",
|
|
443
|
+
"error"
|
|
444
|
+
],
|
|
445
|
+
"rationale": "Height and hints are presentation. `maxLength` is a contract with the server, and `error` is the host's validation result."
|
|
374
446
|
},
|
|
375
|
-
"composition": {},
|
|
376
|
-
"operations": {},
|
|
377
|
-
"intentDomains": [],
|
|
378
|
-
"safeMutations": {},
|
|
379
447
|
"examples": [],
|
|
380
448
|
"coverage": {
|
|
381
449
|
"propsTotal": 12,
|
|
382
450
|
"propsDescribed": 10,
|
|
383
451
|
"describedPct": 83,
|
|
384
452
|
"authoredSections": [
|
|
385
|
-
"accessibility"
|
|
453
|
+
"accessibility",
|
|
454
|
+
"composition",
|
|
455
|
+
"intentDomains",
|
|
456
|
+
"operations",
|
|
457
|
+
"purpose",
|
|
458
|
+
"safeMutations"
|
|
386
459
|
]
|
|
387
460
|
}
|
|
388
461
|
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../../../schema/passport-overlay-v1.schema.json",
|
|
3
|
+
"component": "Textarea",
|
|
4
|
+
"purpose": "A multi-line text field that can grow with its content, with the same label, hint, error and counter wiring as Input.",
|
|
5
|
+
"intentDomains": [
|
|
6
|
+
"ActionIntent",
|
|
7
|
+
"Summarization"
|
|
8
|
+
],
|
|
9
|
+
"$operationsNote": "Mirrors shared/core/agent/field.ts, which is what the runtime dispatches on. source/components/shared/core/agent/__tests__/field-passport.test.ts fails if the two drift. No `apiMethod`: a field is written through its ref — the element for most of these, a handle for Combobox and DatePicker — and that is a normal case, not a gap.",
|
|
10
|
+
"operations": {
|
|
11
|
+
"setValue": {
|
|
12
|
+
"summary": "Write a value into the field, as though a person had entered it.",
|
|
13
|
+
"effects": [
|
|
14
|
+
"replaces the field's current value",
|
|
15
|
+
"fires the host's change handler"
|
|
16
|
+
],
|
|
17
|
+
"reversible": true
|
|
18
|
+
},
|
|
19
|
+
"clear": {
|
|
20
|
+
"summary": "Empty the field.",
|
|
21
|
+
"effects": [
|
|
22
|
+
"discards the field's current value",
|
|
23
|
+
"fires the host's change handler"
|
|
24
|
+
],
|
|
25
|
+
"reversible": true
|
|
26
|
+
},
|
|
27
|
+
"focus": {
|
|
28
|
+
"summary": "Move keyboard focus to the field.",
|
|
29
|
+
"effects": [
|
|
30
|
+
"moves focus"
|
|
31
|
+
],
|
|
32
|
+
"reversible": false
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"accessibility": {
|
|
36
|
+
"supplied": [
|
|
37
|
+
"the label is a real <label> bound to the textarea",
|
|
38
|
+
"description and error are linked by aria-describedby",
|
|
39
|
+
"aria-invalid while `error` is set",
|
|
40
|
+
"the character counter is announced as a live region when `showCount` is on"
|
|
41
|
+
],
|
|
42
|
+
"required": [
|
|
43
|
+
"a `label`, or `aria-label` when the field is visually unlabelled",
|
|
44
|
+
"a `maxLength` that matches whatever the server enforces, so the counter does not promise room that does not exist"
|
|
45
|
+
]
|
|
46
|
+
},
|
|
47
|
+
"composition": {
|
|
48
|
+
"mustNotContain": [
|
|
49
|
+
"label",
|
|
50
|
+
"textarea"
|
|
51
|
+
],
|
|
52
|
+
"notes": "It renders its own <label> and <textarea>; wrapping it in a second label misbinds the text."
|
|
53
|
+
},
|
|
54
|
+
"safeMutations": {
|
|
55
|
+
"allowed": [
|
|
56
|
+
"size",
|
|
57
|
+
"placeholder",
|
|
58
|
+
"description",
|
|
59
|
+
"rows",
|
|
60
|
+
"minRows",
|
|
61
|
+
"maxRows",
|
|
62
|
+
"autoResize",
|
|
63
|
+
"resize",
|
|
64
|
+
"showCount"
|
|
65
|
+
],
|
|
66
|
+
"forbidden": [
|
|
67
|
+
"value",
|
|
68
|
+
"defaultValue",
|
|
69
|
+
"name",
|
|
70
|
+
"required",
|
|
71
|
+
"disabled",
|
|
72
|
+
"readOnly",
|
|
73
|
+
"maxLength",
|
|
74
|
+
"onValueChange",
|
|
75
|
+
"error"
|
|
76
|
+
],
|
|
77
|
+
"rationale": "Height and hints are presentation. `maxLength` is a contract with the server, and `error` is the host's validation result."
|
|
78
|
+
},
|
|
79
|
+
"propNotes": {
|
|
80
|
+
"autoResize": "Grows the field to its content between `minRows` and `maxRows`. Ignored when `resize` lets the user drag."
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
]
|
|
12
12
|
},
|
|
13
13
|
"source": {
|
|
14
|
-
"libraryVersion": "2.
|
|
14
|
+
"libraryVersion": "2.7.0",
|
|
15
15
|
"files": [
|
|
16
16
|
"core/api.ts",
|
|
17
17
|
"core/index.ts",
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
],
|
|
29
29
|
"sourceHash": "sha256:976553d5d606c12b441caba76badad73812eea6dde400b51eb3ee17d05db7871"
|
|
30
30
|
},
|
|
31
|
+
"purpose": "Short notifications you mount once and call from anywhere, with no hook, context or provider. For things that happened, not things that must be decided.",
|
|
31
32
|
"props": [
|
|
32
33
|
{
|
|
33
34
|
"name": "className",
|
|
@@ -102,7 +103,8 @@
|
|
|
102
103
|
"required": false,
|
|
103
104
|
"origin": "derived",
|
|
104
105
|
"description": "Open toasts on screen at once; the rest wait their turn. Default 3.",
|
|
105
|
-
"descriptionOrigin": "jsdoc"
|
|
106
|
+
"descriptionOrigin": "jsdoc",
|
|
107
|
+
"note": "How many are visible at once; the rest queue rather than being dropped."
|
|
106
108
|
},
|
|
107
109
|
{
|
|
108
110
|
"name": "localeText",
|
|
@@ -204,20 +206,51 @@
|
|
|
204
206
|
}
|
|
205
207
|
],
|
|
206
208
|
"accessibility": {
|
|
207
|
-
"supplied": [
|
|
208
|
-
|
|
209
|
+
"supplied": [
|
|
210
|
+
"a live region that announces new toasts without moving focus",
|
|
211
|
+
"a hotkey to jump to the toast region, for keyboard users who heard one arrive",
|
|
212
|
+
"the close button is reachable and labelled",
|
|
213
|
+
"timers pause on hover and on focus, so a toast cannot expire while it is being read"
|
|
214
|
+
],
|
|
215
|
+
"required": [
|
|
216
|
+
"never put the only copy of something important in a toast — it leaves",
|
|
217
|
+
"a `duration` long enough to read the message, or none at all when it carries an action"
|
|
218
|
+
]
|
|
219
|
+
},
|
|
220
|
+
"composition": {
|
|
221
|
+
"notes": "Mount one Toaster near the root. A second one gives two live regions and duplicate announcements; the store is module-level, so one is all that is needed."
|
|
209
222
|
},
|
|
210
|
-
"composition": {},
|
|
211
223
|
"operations": {},
|
|
212
|
-
"intentDomains": [
|
|
213
|
-
|
|
224
|
+
"intentDomains": [
|
|
225
|
+
"Summarization",
|
|
226
|
+
"ActionIntent"
|
|
227
|
+
],
|
|
228
|
+
"safeMutations": {
|
|
229
|
+
"allowed": [
|
|
230
|
+
"position",
|
|
231
|
+
"duration",
|
|
232
|
+
"closeButton",
|
|
233
|
+
"icons",
|
|
234
|
+
"limit",
|
|
235
|
+
"dir"
|
|
236
|
+
],
|
|
237
|
+
"forbidden": [
|
|
238
|
+
"store",
|
|
239
|
+
"hotkey"
|
|
240
|
+
],
|
|
241
|
+
"rationale": "Placement and timing are presentation. `store` is the module-level queue; replacing it detaches every existing `toast()` call from the thing on screen."
|
|
242
|
+
},
|
|
214
243
|
"examples": [],
|
|
215
244
|
"coverage": {
|
|
216
245
|
"propsTotal": 8,
|
|
217
246
|
"propsDescribed": 8,
|
|
218
247
|
"describedPct": 100,
|
|
219
248
|
"authoredSections": [
|
|
220
|
-
"accessibility"
|
|
249
|
+
"accessibility",
|
|
250
|
+
"composition",
|
|
251
|
+
"intentDomains",
|
|
252
|
+
"purpose",
|
|
253
|
+
"safeMutations"
|
|
221
254
|
]
|
|
222
255
|
}
|
|
223
256
|
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../../../schema/passport-overlay-v1.schema.json",
|
|
3
|
+
"component": "Toaster",
|
|
4
|
+
"purpose": "Short notifications you mount once and call from anywhere, with no hook, context or provider. For things that happened, not things that must be decided.",
|
|
5
|
+
"intentDomains": [
|
|
6
|
+
"Summarization",
|
|
7
|
+
"ActionIntent"
|
|
8
|
+
],
|
|
9
|
+
"accessibility": {
|
|
10
|
+
"supplied": [
|
|
11
|
+
"a live region that announces new toasts without moving focus",
|
|
12
|
+
"a hotkey to jump to the toast region, for keyboard users who heard one arrive",
|
|
13
|
+
"the close button is reachable and labelled",
|
|
14
|
+
"timers pause on hover and on focus, so a toast cannot expire while it is being read"
|
|
15
|
+
],
|
|
16
|
+
"required": [
|
|
17
|
+
"never put the only copy of something important in a toast — it leaves",
|
|
18
|
+
"a `duration` long enough to read the message, or none at all when it carries an action"
|
|
19
|
+
]
|
|
20
|
+
},
|
|
21
|
+
"composition": {
|
|
22
|
+
"notes": "Mount one Toaster near the root. A second one gives two live regions and duplicate announcements; the store is module-level, so one is all that is needed."
|
|
23
|
+
},
|
|
24
|
+
"safeMutations": {
|
|
25
|
+
"allowed": [
|
|
26
|
+
"position",
|
|
27
|
+
"duration",
|
|
28
|
+
"closeButton",
|
|
29
|
+
"icons",
|
|
30
|
+
"limit",
|
|
31
|
+
"dir"
|
|
32
|
+
],
|
|
33
|
+
"forbidden": [
|
|
34
|
+
"store",
|
|
35
|
+
"hotkey"
|
|
36
|
+
],
|
|
37
|
+
"rationale": "Placement and timing are presentation. `store` is the module-level queue; replacing it detaches every existing `toast()` call from the thing on screen."
|
|
38
|
+
},
|
|
39
|
+
"propNotes": {
|
|
40
|
+
"limit": "How many are visible at once; the rest queue rather than being dropped."
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
]
|
|
9
9
|
},
|
|
10
10
|
"source": {
|
|
11
|
-
"libraryVersion": "2.
|
|
11
|
+
"libraryVersion": "2.7.0",
|
|
12
12
|
"files": [
|
|
13
13
|
"core/index.ts",
|
|
14
14
|
"core/types.ts",
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
],
|
|
20
20
|
"sourceHash": "sha256:b7a7aefbc8fcb4c9f4063dd0bc312ca2316ac848946c3055c8e69a8fe8780916"
|
|
21
21
|
},
|
|
22
|
+
"purpose": "A short label on hover or keyboard focus, with a delay, Escape to dismiss, and the accessibility wiring that makes it readable rather than decorative.",
|
|
22
23
|
"props": [
|
|
23
24
|
{
|
|
24
25
|
"name": "align",
|
|
@@ -151,20 +152,52 @@
|
|
|
151
152
|
}
|
|
152
153
|
],
|
|
153
154
|
"accessibility": {
|
|
154
|
-
"supplied": [
|
|
155
|
-
|
|
155
|
+
"supplied": [
|
|
156
|
+
"the trigger is described by the tooltip, so it is announced with the control rather than as stray text",
|
|
157
|
+
"it opens on keyboard focus, not only on hover",
|
|
158
|
+
"Escape dismisses it without moving focus",
|
|
159
|
+
"a delay before opening, so moving the pointer across a toolbar does not flash every label"
|
|
160
|
+
],
|
|
161
|
+
"required": [
|
|
162
|
+
"never put essential information only in a tooltip — it is unreachable on touch and gone on blur",
|
|
163
|
+
"an interactive trigger. A tooltip on a non-focusable element cannot be reached by keyboard"
|
|
164
|
+
]
|
|
165
|
+
},
|
|
166
|
+
"composition": {
|
|
167
|
+
"mustNotContain": [
|
|
168
|
+
"button",
|
|
169
|
+
"a",
|
|
170
|
+
"input"
|
|
171
|
+
],
|
|
172
|
+
"notes": "Tooltip content must not be interactive: it disappears on blur, so nothing inside it can be reached. Use a Popover when the panel has controls."
|
|
156
173
|
},
|
|
157
|
-
"composition": {},
|
|
158
174
|
"operations": {},
|
|
159
175
|
"intentDomains": [],
|
|
160
|
-
"safeMutations": {
|
|
176
|
+
"safeMutations": {
|
|
177
|
+
"allowed": [
|
|
178
|
+
"side",
|
|
179
|
+
"align",
|
|
180
|
+
"gap",
|
|
181
|
+
"delay",
|
|
182
|
+
"closeDelay"
|
|
183
|
+
],
|
|
184
|
+
"forbidden": [
|
|
185
|
+
"content",
|
|
186
|
+
"disabled",
|
|
187
|
+
"children"
|
|
188
|
+
],
|
|
189
|
+
"rationale": "Placement and timing are presentation. The content is the message."
|
|
190
|
+
},
|
|
161
191
|
"examples": [],
|
|
162
192
|
"coverage": {
|
|
163
193
|
"propsTotal": 9,
|
|
164
194
|
"propsDescribed": 7,
|
|
165
195
|
"describedPct": 78,
|
|
166
196
|
"authoredSections": [
|
|
167
|
-
"accessibility"
|
|
197
|
+
"accessibility",
|
|
198
|
+
"composition",
|
|
199
|
+
"purpose",
|
|
200
|
+
"safeMutations"
|
|
168
201
|
]
|
|
169
202
|
}
|
|
170
203
|
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../../../schema/passport-overlay-v1.schema.json",
|
|
3
|
+
"component": "Tooltip",
|
|
4
|
+
"purpose": "A short label on hover or keyboard focus, with a delay, Escape to dismiss, and the accessibility wiring that makes it readable rather than decorative.",
|
|
5
|
+
"intentDomains": [],
|
|
6
|
+
"accessibility": {
|
|
7
|
+
"supplied": [
|
|
8
|
+
"the trigger is described by the tooltip, so it is announced with the control rather than as stray text",
|
|
9
|
+
"it opens on keyboard focus, not only on hover",
|
|
10
|
+
"Escape dismisses it without moving focus",
|
|
11
|
+
"a delay before opening, so moving the pointer across a toolbar does not flash every label"
|
|
12
|
+
],
|
|
13
|
+
"required": [
|
|
14
|
+
"never put essential information only in a tooltip — it is unreachable on touch and gone on blur",
|
|
15
|
+
"an interactive trigger. A tooltip on a non-focusable element cannot be reached by keyboard"
|
|
16
|
+
]
|
|
17
|
+
},
|
|
18
|
+
"composition": {
|
|
19
|
+
"mustNotContain": [
|
|
20
|
+
"button",
|
|
21
|
+
"a",
|
|
22
|
+
"input"
|
|
23
|
+
],
|
|
24
|
+
"notes": "Tooltip content must not be interactive: it disappears on blur, so nothing inside it can be reached. Use a Popover when the panel has controls."
|
|
25
|
+
},
|
|
26
|
+
"safeMutations": {
|
|
27
|
+
"allowed": [
|
|
28
|
+
"side",
|
|
29
|
+
"align",
|
|
30
|
+
"gap",
|
|
31
|
+
"delay",
|
|
32
|
+
"closeDelay"
|
|
33
|
+
],
|
|
34
|
+
"forbidden": [
|
|
35
|
+
"content",
|
|
36
|
+
"disabled",
|
|
37
|
+
"children"
|
|
38
|
+
],
|
|
39
|
+
"rationale": "Placement and timing are presentation. The content is the message."
|
|
40
|
+
}
|
|
41
|
+
}
|
package/tools/mcp/README.md
CHANGED
|
@@ -127,7 +127,15 @@ invention, and this catches it:
|
|
|
127
127
|
|
|
128
128
|
## A whole design at once
|
|
129
129
|
|
|
130
|
-
Install [Grampro Kit from the Figma Community](https://www.figma.com/community/plugin/1692828324805361551).
|
|
130
|
+
Install [Grampro Kit from the Figma Community](https://www.figma.com/community/plugin/1692828324805361551).
|
|
131
|
+
|
|
132
|
+
> The listing is in review, which Figma is quoting at a few weeks. Until it
|
|
133
|
+
> clears: clone the repository and, in the Figma **desktop** app, use
|
|
134
|
+
> **Plugins → Development → Import plugin from manifest...** on
|
|
135
|
+
> `figma-plugin/manifest.json`. The build is committed, so there is nothing
|
|
136
|
+
> to compile.
|
|
137
|
+
|
|
138
|
+
Then
|
|
131
139
|
**Grampro Kit → Export all screens for an agent** walks every
|
|
132
140
|
page and exports each top-level frame, with one set of theme values read
|
|
133
141
|
across the whole design rather than guessed per frame. Save it, then:
|
package/tools/mcp/design.cjs
CHANGED
|
@@ -67,7 +67,12 @@ function splitDesign(file, dest) {
|
|
|
67
67
|
try {
|
|
68
68
|
design = JSON.parse(fs.readFileSync(source, "utf8").replace(/^/, ""));
|
|
69
69
|
} catch (error) {
|
|
70
|
-
|
|
70
|
+
// The parse error carries a slice of the file; name the file instead.
|
|
71
|
+
return {
|
|
72
|
+
error:
|
|
73
|
+
`${source} is not JSON. Expected the Figma plugin's export — ` +
|
|
74
|
+
"run Grampro Kit -> Export all screens for an agent and save that.",
|
|
75
|
+
};
|
|
71
76
|
}
|
|
72
77
|
|
|
73
78
|
/*
|