@grampro/kit 2.6.3 → 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 +164 -0
- package/README.md +19 -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/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
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../../../schema/passport-overlay-v1.schema.json",
|
|
3
|
+
"component": "Alert",
|
|
4
|
+
"purpose": "A message that stays in the page — neither interrupting like a dialog nor leaving like a toast. For conditions the user needs to keep seeing.",
|
|
5
|
+
"intentDomains": [
|
|
6
|
+
"Summarization"
|
|
7
|
+
],
|
|
8
|
+
"accessibility": {
|
|
9
|
+
"supplied": [
|
|
10
|
+
"role=alert on the error and warning variants, so they are announced when they appear",
|
|
11
|
+
"the variant is carried in text and icon, not by colour alone",
|
|
12
|
+
"the dismiss control is a real button with an accessible name"
|
|
13
|
+
],
|
|
14
|
+
"required": [
|
|
15
|
+
"a message that says what to do, not only what went wrong",
|
|
16
|
+
"do not use `onDismiss` for something the user must act on — a dismissible error can be dismissed unread"
|
|
17
|
+
]
|
|
18
|
+
},
|
|
19
|
+
"composition": {
|
|
20
|
+
"mustNotContain": [
|
|
21
|
+
"Alert"
|
|
22
|
+
],
|
|
23
|
+
"notes": "Actions belong in `actions`, which keeps them in the alert's landmark rather than loose in the body."
|
|
24
|
+
},
|
|
25
|
+
"safeMutations": {
|
|
26
|
+
"allowed": [
|
|
27
|
+
"size",
|
|
28
|
+
"icon",
|
|
29
|
+
"description"
|
|
30
|
+
],
|
|
31
|
+
"forbidden": [
|
|
32
|
+
"variant",
|
|
33
|
+
"children",
|
|
34
|
+
"actions",
|
|
35
|
+
"onDismiss"
|
|
36
|
+
],
|
|
37
|
+
"rationale": "`variant` is the severity. Downgrading an error to info changes what the page is telling the user, and it changes whether it is announced at all."
|
|
38
|
+
},
|
|
39
|
+
"propNotes": {
|
|
40
|
+
"variant": "Decides the role: error and warning are announced, info and success are not."
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
]
|
|
10
10
|
},
|
|
11
11
|
"source": {
|
|
12
|
-
"libraryVersion": "2.
|
|
12
|
+
"libraryVersion": "2.7.0",
|
|
13
13
|
"files": [
|
|
14
14
|
"core/identity.ts",
|
|
15
15
|
"core/index.ts",
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
],
|
|
23
23
|
"sourceHash": "sha256:541aa6ca5c99e64fba414881c07cc3c29244e03c09b665a4934690d633cc20e1"
|
|
24
24
|
},
|
|
25
|
+
"purpose": "A person as a picture or their initials, on a colour derived from their name, with a presence dot and an overflow count for groups.",
|
|
25
26
|
"props": [
|
|
26
27
|
{
|
|
27
28
|
"name": "aria-describedby",
|
|
@@ -75,7 +76,8 @@
|
|
|
75
76
|
"default": false,
|
|
76
77
|
"origin": "derived",
|
|
77
78
|
"description": "Marks the avatar as decoration, for a name printed next to it.",
|
|
78
|
-
"descriptionOrigin": "jsdoc"
|
|
79
|
+
"descriptionOrigin": "jsdoc",
|
|
80
|
+
"note": "Hides it from assistive technology. Correct when the name is already adjacent in text."
|
|
79
81
|
},
|
|
80
82
|
{
|
|
81
83
|
"name": "hidden",
|
|
@@ -277,20 +279,51 @@
|
|
|
277
279
|
}
|
|
278
280
|
],
|
|
279
281
|
"accessibility": {
|
|
280
|
-
"supplied": [
|
|
281
|
-
|
|
282
|
+
"supplied": [
|
|
283
|
+
"the image falls back to initials, and initials to a generic icon, so there is never a broken image",
|
|
284
|
+
"the colour is derived from the name, which makes it stable rather than meaningful — it is never the only signal",
|
|
285
|
+
"a decorative avatar is hidden from assistive technology instead of announcing a name twice",
|
|
286
|
+
"the presence status is given as text, not only as a coloured dot"
|
|
287
|
+
],
|
|
288
|
+
"required": [
|
|
289
|
+
"`name` for the accessible label, or `decorative` when the name is already beside it",
|
|
290
|
+
"`alt`-worthy `label` text where the avatar stands alone as a link to a person"
|
|
291
|
+
]
|
|
292
|
+
},
|
|
293
|
+
"composition": {
|
|
294
|
+
"allowedChildren": [
|
|
295
|
+
"Avatar"
|
|
296
|
+
],
|
|
297
|
+
"notes": "AvatarGroup takes Avatar children and collapses the overflow past `max`."
|
|
282
298
|
},
|
|
283
|
-
"composition": {},
|
|
284
299
|
"operations": {},
|
|
285
300
|
"intentDomains": [],
|
|
286
|
-
"safeMutations": {
|
|
301
|
+
"safeMutations": {
|
|
302
|
+
"allowed": [
|
|
303
|
+
"size",
|
|
304
|
+
"shape",
|
|
305
|
+
"max",
|
|
306
|
+
"decorative"
|
|
307
|
+
],
|
|
308
|
+
"forbidden": [
|
|
309
|
+
"name",
|
|
310
|
+
"src",
|
|
311
|
+
"initials",
|
|
312
|
+
"status",
|
|
313
|
+
"label"
|
|
314
|
+
],
|
|
315
|
+
"rationale": "Shape and size are presentation; the person and their presence are data."
|
|
316
|
+
},
|
|
287
317
|
"examples": [],
|
|
288
318
|
"coverage": {
|
|
289
319
|
"propsTotal": 10,
|
|
290
320
|
"propsDescribed": 10,
|
|
291
321
|
"describedPct": 100,
|
|
292
322
|
"authoredSections": [
|
|
293
|
-
"accessibility"
|
|
323
|
+
"accessibility",
|
|
324
|
+
"composition",
|
|
325
|
+
"purpose",
|
|
326
|
+
"safeMutations"
|
|
294
327
|
]
|
|
295
328
|
}
|
|
296
329
|
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../../../schema/passport-overlay-v1.schema.json",
|
|
3
|
+
"component": "Avatar",
|
|
4
|
+
"purpose": "A person as a picture or their initials, on a colour derived from their name, with a presence dot and an overflow count for groups.",
|
|
5
|
+
"intentDomains": [],
|
|
6
|
+
"accessibility": {
|
|
7
|
+
"supplied": [
|
|
8
|
+
"the image falls back to initials, and initials to a generic icon, so there is never a broken image",
|
|
9
|
+
"the colour is derived from the name, which makes it stable rather than meaningful — it is never the only signal",
|
|
10
|
+
"a decorative avatar is hidden from assistive technology instead of announcing a name twice",
|
|
11
|
+
"the presence status is given as text, not only as a coloured dot"
|
|
12
|
+
],
|
|
13
|
+
"required": [
|
|
14
|
+
"`name` for the accessible label, or `decorative` when the name is already beside it",
|
|
15
|
+
"`alt`-worthy `label` text where the avatar stands alone as a link to a person"
|
|
16
|
+
]
|
|
17
|
+
},
|
|
18
|
+
"composition": {
|
|
19
|
+
"allowedChildren": [
|
|
20
|
+
"Avatar"
|
|
21
|
+
],
|
|
22
|
+
"notes": "AvatarGroup takes Avatar children and collapses the overflow past `max`."
|
|
23
|
+
},
|
|
24
|
+
"safeMutations": {
|
|
25
|
+
"allowed": [
|
|
26
|
+
"size",
|
|
27
|
+
"shape",
|
|
28
|
+
"max",
|
|
29
|
+
"decorative"
|
|
30
|
+
],
|
|
31
|
+
"forbidden": [
|
|
32
|
+
"name",
|
|
33
|
+
"src",
|
|
34
|
+
"initials",
|
|
35
|
+
"status",
|
|
36
|
+
"label"
|
|
37
|
+
],
|
|
38
|
+
"rationale": "Shape and size are presentation; the person and their presence are data."
|
|
39
|
+
},
|
|
40
|
+
"propNotes": {
|
|
41
|
+
"decorative": "Hides it from assistive technology. Correct when the name is already adjacent in text."
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
]
|
|
10
10
|
},
|
|
11
11
|
"source": {
|
|
12
|
-
"libraryVersion": "2.
|
|
12
|
+
"libraryVersion": "2.7.0",
|
|
13
13
|
"files": [
|
|
14
14
|
"core/count.ts",
|
|
15
15
|
"core/index.ts",
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
],
|
|
23
23
|
"sourceHash": "sha256:16f626a94da3bac9b1a105718010edd7e1ce5a6118823ed8a53c97d658d89a3e"
|
|
24
24
|
},
|
|
25
|
+
"purpose": "Short labels: a status, a category, a count that stops at 99+, and chips the user can take off.",
|
|
25
26
|
"props": [
|
|
26
27
|
{
|
|
27
28
|
"name": "appearance",
|
|
@@ -163,7 +164,8 @@
|
|
|
163
164
|
"default": 99,
|
|
164
165
|
"origin": "derived",
|
|
165
166
|
"description": "Where the count stops. Default 99.",
|
|
166
|
-
"descriptionOrigin": "jsdoc"
|
|
167
|
+
"descriptionOrigin": "jsdoc",
|
|
168
|
+
"note": "Counts above this render as `max`+. Default 99."
|
|
167
169
|
},
|
|
168
170
|
{
|
|
169
171
|
"name": "onRemove",
|
|
@@ -315,20 +317,54 @@
|
|
|
315
317
|
}
|
|
316
318
|
],
|
|
317
319
|
"accessibility": {
|
|
318
|
-
"supplied": [
|
|
319
|
-
|
|
320
|
+
"supplied": [
|
|
321
|
+
"a count is announced with its meaning rather than as a bare number",
|
|
322
|
+
"the remove control on a chip is a real button with an accessible name",
|
|
323
|
+
"a dot badge is marked decorative, since a dot alone says nothing"
|
|
324
|
+
],
|
|
325
|
+
"required": [
|
|
326
|
+
"text alongside a status badge — colour is not a label",
|
|
327
|
+
"an accessible name on a dot or icon-only badge, or mark it decorative and say it elsewhere"
|
|
328
|
+
]
|
|
329
|
+
},
|
|
330
|
+
"composition": {
|
|
331
|
+
"mustNotContain": [
|
|
332
|
+
"button",
|
|
333
|
+
"a"
|
|
334
|
+
],
|
|
335
|
+
"notes": "Use `onRemove` for a chip rather than nesting a button inside the badge."
|
|
320
336
|
},
|
|
321
|
-
"composition": {},
|
|
322
337
|
"operations": {},
|
|
323
338
|
"intentDomains": [],
|
|
324
|
-
"safeMutations": {
|
|
339
|
+
"safeMutations": {
|
|
340
|
+
"allowed": [
|
|
341
|
+
"variant",
|
|
342
|
+
"appearance",
|
|
343
|
+
"size",
|
|
344
|
+
"icon",
|
|
345
|
+
"dot",
|
|
346
|
+
"max",
|
|
347
|
+
"showZero",
|
|
348
|
+
"formatValue"
|
|
349
|
+
],
|
|
350
|
+
"forbidden": [
|
|
351
|
+
"count",
|
|
352
|
+
"label",
|
|
353
|
+
"children",
|
|
354
|
+
"onRemove"
|
|
355
|
+
],
|
|
356
|
+
"rationale": "Appearance is safe. The count and the label are the data."
|
|
357
|
+
},
|
|
325
358
|
"examples": [],
|
|
326
359
|
"coverage": {
|
|
327
360
|
"propsTotal": 13,
|
|
328
361
|
"propsDescribed": 11,
|
|
329
362
|
"describedPct": 85,
|
|
330
363
|
"authoredSections": [
|
|
331
|
-
"accessibility"
|
|
364
|
+
"accessibility",
|
|
365
|
+
"composition",
|
|
366
|
+
"purpose",
|
|
367
|
+
"safeMutations"
|
|
332
368
|
]
|
|
333
369
|
}
|
|
334
370
|
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../../../schema/passport-overlay-v1.schema.json",
|
|
3
|
+
"component": "Badge",
|
|
4
|
+
"purpose": "Short labels: a status, a category, a count that stops at 99+, and chips the user can take off.",
|
|
5
|
+
"intentDomains": [],
|
|
6
|
+
"accessibility": {
|
|
7
|
+
"supplied": [
|
|
8
|
+
"a count is announced with its meaning rather than as a bare number",
|
|
9
|
+
"the remove control on a chip is a real button with an accessible name",
|
|
10
|
+
"a dot badge is marked decorative, since a dot alone says nothing"
|
|
11
|
+
],
|
|
12
|
+
"required": [
|
|
13
|
+
"text alongside a status badge — colour is not a label",
|
|
14
|
+
"an accessible name on a dot or icon-only badge, or mark it decorative and say it elsewhere"
|
|
15
|
+
]
|
|
16
|
+
},
|
|
17
|
+
"composition": {
|
|
18
|
+
"mustNotContain": [
|
|
19
|
+
"button",
|
|
20
|
+
"a"
|
|
21
|
+
],
|
|
22
|
+
"notes": "Use `onRemove` for a chip rather than nesting a button inside the badge."
|
|
23
|
+
},
|
|
24
|
+
"safeMutations": {
|
|
25
|
+
"allowed": [
|
|
26
|
+
"variant",
|
|
27
|
+
"appearance",
|
|
28
|
+
"size",
|
|
29
|
+
"icon",
|
|
30
|
+
"dot",
|
|
31
|
+
"max",
|
|
32
|
+
"showZero",
|
|
33
|
+
"formatValue"
|
|
34
|
+
],
|
|
35
|
+
"forbidden": [
|
|
36
|
+
"count",
|
|
37
|
+
"label",
|
|
38
|
+
"children",
|
|
39
|
+
"onRemove"
|
|
40
|
+
],
|
|
41
|
+
"rationale": "Appearance is safe. The count and the label are the data."
|
|
42
|
+
},
|
|
43
|
+
"propNotes": {
|
|
44
|
+
"max": "Counts above this render as `max`+. Default 99."
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -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/trail.ts",
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
],
|
|
21
21
|
"sourceHash": "sha256:3b7fef8f48d1a1290c25a263d2e92ef5dcb706b1a06899ffe5a4df1cdab663e1"
|
|
22
22
|
},
|
|
23
|
+
"purpose": "Where a page sits in the app: a trail that collapses in the middle when it is long, renders through your router's link, and can emit schema.org JSON-LD.",
|
|
23
24
|
"props": [
|
|
24
25
|
{
|
|
25
26
|
"name": "aria-describedby",
|
|
@@ -163,7 +164,8 @@
|
|
|
163
164
|
"default": false,
|
|
164
165
|
"origin": "derived",
|
|
165
166
|
"description": "Add schema.org `BreadcrumbList` JSON-LD for search engines. Pass\n`{ baseUrl }` so relative links become absolute, as search engines require.",
|
|
166
|
-
"descriptionOrigin": "jsdoc"
|
|
167
|
+
"descriptionOrigin": "jsdoc",
|
|
168
|
+
"note": "Emits a schema.org BreadcrumbList as JSON-LD. It must describe real, reachable URLs."
|
|
167
169
|
},
|
|
168
170
|
{
|
|
169
171
|
"name": "style",
|
|
@@ -226,20 +228,47 @@
|
|
|
226
228
|
}
|
|
227
229
|
],
|
|
228
230
|
"accessibility": {
|
|
229
|
-
"supplied": [
|
|
230
|
-
|
|
231
|
+
"supplied": [
|
|
232
|
+
"a nav landmark with an accessible name",
|
|
233
|
+
"the current page is marked aria-current and is not a link",
|
|
234
|
+
"the collapsed middle is a real button that expands, not an inert ellipsis",
|
|
235
|
+
"separators are decorative and hidden from assistive technology"
|
|
236
|
+
],
|
|
237
|
+
"required": [
|
|
238
|
+
"`renderLink` to use your router, so a breadcrumb does not full-page-reload the app",
|
|
239
|
+
"a trail that matches the page's actual position — a wrong one is worse than none"
|
|
240
|
+
]
|
|
241
|
+
},
|
|
242
|
+
"composition": {
|
|
243
|
+
"notes": "Items come from the `items` array. The last item is the current page and is rendered as text."
|
|
231
244
|
},
|
|
232
|
-
"composition": {},
|
|
233
245
|
"operations": {},
|
|
234
246
|
"intentDomains": [],
|
|
235
|
-
"safeMutations": {
|
|
247
|
+
"safeMutations": {
|
|
248
|
+
"allowed": [
|
|
249
|
+
"size",
|
|
250
|
+
"separator",
|
|
251
|
+
"maxItems",
|
|
252
|
+
"itemsBeforeCollapse",
|
|
253
|
+
"itemsAfterCollapse"
|
|
254
|
+
],
|
|
255
|
+
"forbidden": [
|
|
256
|
+
"items",
|
|
257
|
+
"renderLink",
|
|
258
|
+
"structuredData"
|
|
259
|
+
],
|
|
260
|
+
"rationale": "Collapsing and the separator are presentation. `items` is the page's position, `renderLink` is the router binding, and `structuredData` emits markup search engines consume."
|
|
261
|
+
},
|
|
236
262
|
"examples": [],
|
|
237
263
|
"coverage": {
|
|
238
264
|
"propsTotal": 8,
|
|
239
265
|
"propsDescribed": 8,
|
|
240
266
|
"describedPct": 100,
|
|
241
267
|
"authoredSections": [
|
|
242
|
-
"accessibility"
|
|
268
|
+
"accessibility",
|
|
269
|
+
"composition",
|
|
270
|
+
"purpose",
|
|
271
|
+
"safeMutations"
|
|
243
272
|
]
|
|
244
273
|
}
|
|
245
274
|
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../../../schema/passport-overlay-v1.schema.json",
|
|
3
|
+
"component": "Breadcrumb",
|
|
4
|
+
"purpose": "Where a page sits in the app: a trail that collapses in the middle when it is long, renders through your router's link, and can emit schema.org JSON-LD.",
|
|
5
|
+
"intentDomains": [],
|
|
6
|
+
"accessibility": {
|
|
7
|
+
"supplied": [
|
|
8
|
+
"a nav landmark with an accessible name",
|
|
9
|
+
"the current page is marked aria-current and is not a link",
|
|
10
|
+
"the collapsed middle is a real button that expands, not an inert ellipsis",
|
|
11
|
+
"separators are decorative and hidden from assistive technology"
|
|
12
|
+
],
|
|
13
|
+
"required": [
|
|
14
|
+
"`renderLink` to use your router, so a breadcrumb does not full-page-reload the app",
|
|
15
|
+
"a trail that matches the page's actual position — a wrong one is worse than none"
|
|
16
|
+
]
|
|
17
|
+
},
|
|
18
|
+
"composition": {
|
|
19
|
+
"notes": "Items come from the `items` array. The last item is the current page and is rendered as text."
|
|
20
|
+
},
|
|
21
|
+
"safeMutations": {
|
|
22
|
+
"allowed": [
|
|
23
|
+
"size",
|
|
24
|
+
"separator",
|
|
25
|
+
"maxItems",
|
|
26
|
+
"itemsBeforeCollapse",
|
|
27
|
+
"itemsAfterCollapse"
|
|
28
|
+
],
|
|
29
|
+
"forbidden": [
|
|
30
|
+
"items",
|
|
31
|
+
"renderLink",
|
|
32
|
+
"structuredData"
|
|
33
|
+
],
|
|
34
|
+
"rationale": "Collapsing and the separator are presentation. `items` is the page's position, `renderLink` is the router binding, and `structuredData` emits markup search engines consume."
|
|
35
|
+
},
|
|
36
|
+
"propNotes": {
|
|
37
|
+
"structuredData": "Emits a schema.org BreadcrumbList as JSON-LD. It must describe real, reachable URLs."
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$schema": "../../../schema/passport-v1.schema.json",
|
|
2
|
+
"$schema": "../../../schema/passport-overlay-v1.schema.json",
|
|
3
3
|
"component": "Button",
|
|
4
4
|
"purpose": "Trigger an action. Not for navigation unless `render` supplies a link element.",
|
|
5
5
|
"intentDomains": ["ActionIntent"],
|
|
@@ -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/trend.ts",
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
],
|
|
25
25
|
"sourceHash": "sha256:5b40d5a873d8c4bd0ea3423f5a9b0ca06f2515aa1ea45149d36be3b2b4aa63e1"
|
|
26
26
|
},
|
|
27
|
+
"purpose": "A surface that groups related content, with header, body and footer, plus Stat for a single figure and its trend.",
|
|
27
28
|
"props": [
|
|
28
29
|
{
|
|
29
30
|
"name": "actions",
|
|
@@ -134,7 +135,8 @@
|
|
|
134
135
|
"default": false,
|
|
135
136
|
"origin": "derived",
|
|
136
137
|
"description": "Lifts the card on hover, for a card that is clickable by other means.",
|
|
137
|
-
"descriptionOrigin": "jsdoc"
|
|
138
|
+
"descriptionOrigin": "jsdoc",
|
|
139
|
+
"note": "Makes the whole surface a button. Do not combine with controls inside it."
|
|
138
140
|
},
|
|
139
141
|
{
|
|
140
142
|
"name": "label",
|
|
@@ -233,7 +235,8 @@
|
|
|
233
235
|
"required": false,
|
|
234
236
|
"origin": "derived",
|
|
235
237
|
"description": "The change beside the figure: direction, a formatted label, and\nwhether down is the good outcome. Left out, no arrow is shown.",
|
|
236
|
-
"descriptionOrigin": "jsdoc"
|
|
238
|
+
"descriptionOrigin": "jsdoc",
|
|
239
|
+
"note": "Stat only. The direction is also stated in text, so it survives being read aloud."
|
|
237
240
|
},
|
|
238
241
|
{
|
|
239
242
|
"name": "value",
|
|
@@ -326,20 +329,54 @@
|
|
|
326
329
|
}
|
|
327
330
|
],
|
|
328
331
|
"accessibility": {
|
|
329
|
-
"supplied": [
|
|
330
|
-
|
|
332
|
+
"supplied": [
|
|
333
|
+
"an interactive card is a real button or link, not a div with a click handler",
|
|
334
|
+
"the trend on Stat is given as text as well as a direction and colour",
|
|
335
|
+
"the loading state renders placeholder bars announced as loading"
|
|
336
|
+
],
|
|
337
|
+
"required": [
|
|
338
|
+
"`href` or `interactive`, never a bare onClick on the surface — otherwise it is unreachable by keyboard",
|
|
339
|
+
"a heading that names the group, where the card is a section of a page"
|
|
340
|
+
]
|
|
341
|
+
},
|
|
342
|
+
"composition": {
|
|
343
|
+
"mustNotContain": [
|
|
344
|
+
"Card"
|
|
345
|
+
],
|
|
346
|
+
"notes": "An interactive card must not contain its own buttons or links: a control inside a clickable surface is a nested interactive element, and neither target is predictable."
|
|
331
347
|
},
|
|
332
|
-
"composition": {},
|
|
333
348
|
"operations": {},
|
|
334
349
|
"intentDomains": [],
|
|
335
|
-
"safeMutations": {
|
|
350
|
+
"safeMutations": {
|
|
351
|
+
"allowed": [
|
|
352
|
+
"variant",
|
|
353
|
+
"padding",
|
|
354
|
+
"icon",
|
|
355
|
+
"description",
|
|
356
|
+
"help"
|
|
357
|
+
],
|
|
358
|
+
"forbidden": [
|
|
359
|
+
"href",
|
|
360
|
+
"target",
|
|
361
|
+
"rel",
|
|
362
|
+
"interactive",
|
|
363
|
+
"value",
|
|
364
|
+
"trend",
|
|
365
|
+
"loading",
|
|
366
|
+
"actions"
|
|
367
|
+
],
|
|
368
|
+
"rationale": "Surface styling is safe. `href` and `interactive` decide what the card *is*, and `value` and `trend` are the figure it reports."
|
|
369
|
+
},
|
|
336
370
|
"examples": [],
|
|
337
371
|
"coverage": {
|
|
338
372
|
"propsTotal": 16,
|
|
339
373
|
"propsDescribed": 14,
|
|
340
374
|
"describedPct": 88,
|
|
341
375
|
"authoredSections": [
|
|
342
|
-
"accessibility"
|
|
376
|
+
"accessibility",
|
|
377
|
+
"composition",
|
|
378
|
+
"purpose",
|
|
379
|
+
"safeMutations"
|
|
343
380
|
]
|
|
344
381
|
}
|
|
345
382
|
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../../../schema/passport-overlay-v1.schema.json",
|
|
3
|
+
"component": "Card",
|
|
4
|
+
"purpose": "A surface that groups related content, with header, body and footer, plus Stat for a single figure and its trend.",
|
|
5
|
+
"intentDomains": [],
|
|
6
|
+
"accessibility": {
|
|
7
|
+
"supplied": [
|
|
8
|
+
"an interactive card is a real button or link, not a div with a click handler",
|
|
9
|
+
"the trend on Stat is given as text as well as a direction and colour",
|
|
10
|
+
"the loading state renders placeholder bars announced as loading"
|
|
11
|
+
],
|
|
12
|
+
"required": [
|
|
13
|
+
"`href` or `interactive`, never a bare onClick on the surface — otherwise it is unreachable by keyboard",
|
|
14
|
+
"a heading that names the group, where the card is a section of a page"
|
|
15
|
+
]
|
|
16
|
+
},
|
|
17
|
+
"composition": {
|
|
18
|
+
"mustNotContain": [
|
|
19
|
+
"Card"
|
|
20
|
+
],
|
|
21
|
+
"notes": "An interactive card must not contain its own buttons or links: a control inside a clickable surface is a nested interactive element, and neither target is predictable."
|
|
22
|
+
},
|
|
23
|
+
"safeMutations": {
|
|
24
|
+
"allowed": [
|
|
25
|
+
"variant",
|
|
26
|
+
"padding",
|
|
27
|
+
"icon",
|
|
28
|
+
"description",
|
|
29
|
+
"help"
|
|
30
|
+
],
|
|
31
|
+
"forbidden": [
|
|
32
|
+
"href",
|
|
33
|
+
"target",
|
|
34
|
+
"rel",
|
|
35
|
+
"interactive",
|
|
36
|
+
"value",
|
|
37
|
+
"trend",
|
|
38
|
+
"loading",
|
|
39
|
+
"actions"
|
|
40
|
+
],
|
|
41
|
+
"rationale": "Surface styling is safe. `href` and `interactive` decide what the card *is*, and `value` and `trend` are the figure it reports."
|
|
42
|
+
},
|
|
43
|
+
"propNotes": {
|
|
44
|
+
"interactive": "Makes the whole surface a button. Do not combine with controls inside it.",
|
|
45
|
+
"trend": "Stat only. The direction is also stated in text, so it survives being read aloud."
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Checkbox's agent contract.
|
|
3
|
+
*
|
|
4
|
+
* A boolean field, so the write sets `checked` rather than `value`. The
|
|
5
|
+
* indeterminate state is not settable by an agent: it means "some of the group",
|
|
6
|
+
* which is a conclusion about other checkboxes rather than a value of this one.
|
|
7
|
+
*
|
|
8
|
+
* Pure: no React, no DOM. The contract is what this instance will accept, and
|
|
9
|
+
* the validator in shared/core/agent decides everything from it. Build it from
|
|
10
|
+
* props on every render so that a field which has just become read-only stops
|
|
11
|
+
* accepting writes immediately.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import type { FieldContract } from "../../shared/core/agent";
|
|
15
|
+
|
|
16
|
+
export interface CheckboxAgentProps {
|
|
17
|
+
label?: string;
|
|
18
|
+
disabled?: boolean;
|
|
19
|
+
readOnly?: boolean;
|
|
20
|
+
required?: boolean;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function checkboxContract(props: CheckboxAgentProps = {}): FieldContract {
|
|
24
|
+
return {
|
|
25
|
+
component: "Checkbox",
|
|
26
|
+
kind: "boolean",
|
|
27
|
+
operations: ["setValue", "clear", "focus"],
|
|
28
|
+
label: props.label,
|
|
29
|
+
disabled: props.disabled,
|
|
30
|
+
readOnly: props.readOnly,
|
|
31
|
+
required: props.required,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
// Framework-free: selection rules for checkbox groups.
|
|
2
2
|
export { groupState, toggleAll, toggleValue } from "./group";
|
|
3
3
|
export type * from "./types";
|
|
4
|
+
// The agent contract: what a model may ask this field to do.
|
|
5
|
+
export { checkboxContract, type CheckboxAgentProps } from "./agent";
|