ionbase-ui 0.22.0 → 0.25.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/dist/components/AgentActivity.d.ts +41 -0
- package/dist/components/AgentActivity.d.ts.map +1 -0
- package/dist/components/AgentActivity.js +84 -0
- package/dist/components/AgentActivity.js.map +1 -0
- package/dist/components/AgentStop.d.ts +58 -0
- package/dist/components/AgentStop.d.ts.map +1 -0
- package/dist/components/AgentStop.js +82 -0
- package/dist/components/AgentStop.js.map +1 -0
- package/dist/components/ApprovalGate.d.ts +72 -0
- package/dist/components/ApprovalGate.d.ts.map +1 -0
- package/dist/components/ApprovalGate.js +68 -0
- package/dist/components/ApprovalGate.js.map +1 -0
- package/dist/components/Citation.d.ts +51 -0
- package/dist/components/Citation.d.ts.map +1 -0
- package/dist/components/Citation.js +41 -0
- package/dist/components/Citation.js.map +1 -0
- package/dist/components/ConfidenceIndicator.d.ts +37 -0
- package/dist/components/ConfidenceIndicator.d.ts.map +1 -0
- package/dist/components/ConfidenceIndicator.js +41 -0
- package/dist/components/ConfidenceIndicator.js.map +1 -0
- package/dist/components/StreamingText.d.ts +47 -0
- package/dist/components/StreamingText.d.ts.map +1 -0
- package/dist/components/StreamingText.js +44 -0
- package/dist/components/StreamingText.js.map +1 -0
- package/dist/components/index.d.ts +12 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +6 -0
- package/dist/components/index.js.map +1 -1
- package/dist/figma-descriptions.json +147 -0
- package/dist/figma-map.json +3 -1
- package/dist/meta/AgentActivity.json +103 -0
- package/dist/meta/AgentActivityStep.json +117 -0
- package/dist/meta/AgentStop.json +164 -0
- package/dist/meta/ApprovalGate.json +255 -0
- package/dist/meta/Avatar.json +2 -2
- package/dist/meta/AvatarGroup.json +2 -2
- package/dist/meta/Citation.json +101 -0
- package/dist/meta/CitationList.json +94 -0
- package/dist/meta/CitationListItem.json +88 -0
- package/dist/meta/ConfidenceIndicator.json +115 -0
- package/dist/meta/Input.json +2 -2
- package/dist/meta/PhoneInput.json +38 -38
- package/dist/meta/StreamingText.json +99 -0
- package/dist/meta/components.json +2125 -989
- package/dist/meta/contrast.json +1086 -32
- package/dist/meta/index.json +100 -5
- package/dist/meta/patterns/index.json +1 -1
- package/dist/styles/agent-activity.css +95 -0
- package/dist/styles/agent-stop.css +109 -0
- package/dist/styles/approval-gate.css +181 -0
- package/dist/styles/citation.css +93 -0
- package/dist/styles/confidence-indicator.css +97 -0
- package/dist/styles/index.css +34 -0
- package/dist/styles/streaming-text.css +56 -0
- package/llms.txt +2 -2
- package/package.json +4 -3
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "CitationListItem",
|
|
3
|
+
"source": "src/components/Citation.tsx",
|
|
4
|
+
"propsType": "CitationListItemProps",
|
|
5
|
+
"import": "import { CitationListItem } from 'ionbase-ui';",
|
|
6
|
+
"status": "stable",
|
|
7
|
+
"summary": "One source row: its number, what it is, and the passage it supports.",
|
|
8
|
+
"useWhen": [
|
|
9
|
+
"a child of CitationList"
|
|
10
|
+
],
|
|
11
|
+
"useInstead": [
|
|
12
|
+
{
|
|
13
|
+
"when": "it is the inline marker in the prose",
|
|
14
|
+
"use": "Citation"
|
|
15
|
+
}
|
|
16
|
+
],
|
|
17
|
+
"slots": {
|
|
18
|
+
"children": {
|
|
19
|
+
"accepts": "text",
|
|
20
|
+
"note": "the quoted or summarised passage this source supports"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"a11y": {
|
|
24
|
+
"guarantees": [
|
|
25
|
+
"the visible number is `aria-hidden`; the row is named by its source text, which is what a reader needs to hear",
|
|
26
|
+
"without `href` the source renders as text rather than a dead link"
|
|
27
|
+
],
|
|
28
|
+
"requires": [
|
|
29
|
+
"`source` naming what is being cited"
|
|
30
|
+
]
|
|
31
|
+
},
|
|
32
|
+
"antiPatterns": [
|
|
33
|
+
{
|
|
34
|
+
"dont": "a bare URL as the `source`",
|
|
35
|
+
"why": "a screen reader spells it out character by character, and it names nothing"
|
|
36
|
+
}
|
|
37
|
+
],
|
|
38
|
+
"stylesheet": "src/styles/citation.css",
|
|
39
|
+
"tokens": [
|
|
40
|
+
"--border-focus",
|
|
41
|
+
"--border-width-thick",
|
|
42
|
+
"--font-family-sans",
|
|
43
|
+
"--font-weight-medium",
|
|
44
|
+
"--font-weight-semibold",
|
|
45
|
+
"--radius-xs",
|
|
46
|
+
"--spacing-16",
|
|
47
|
+
"--spacing-2",
|
|
48
|
+
"--spacing-4",
|
|
49
|
+
"--spacing-8",
|
|
50
|
+
"--surface-primary-subtle",
|
|
51
|
+
"--surface-primary-subtle-hover",
|
|
52
|
+
"--text-link",
|
|
53
|
+
"--text-tertiary",
|
|
54
|
+
"--type-body-sm",
|
|
55
|
+
"--type-body-sm-line-height",
|
|
56
|
+
"--type-caption",
|
|
57
|
+
"--type-caption-line-height"
|
|
58
|
+
],
|
|
59
|
+
"props": {
|
|
60
|
+
"index": {
|
|
61
|
+
"type": "string | number",
|
|
62
|
+
"required": true,
|
|
63
|
+
"origin": "own"
|
|
64
|
+
},
|
|
65
|
+
"source": {
|
|
66
|
+
"type": "string",
|
|
67
|
+
"required": true,
|
|
68
|
+
"origin": "own"
|
|
69
|
+
},
|
|
70
|
+
"href": {
|
|
71
|
+
"type": "string | undefined",
|
|
72
|
+
"required": false,
|
|
73
|
+
"origin": "own"
|
|
74
|
+
},
|
|
75
|
+
"children": {
|
|
76
|
+
"type": "React.ReactNode",
|
|
77
|
+
"required": false,
|
|
78
|
+
"origin": "own",
|
|
79
|
+
"description": "The quoted or summarised passage this citation supports."
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
"propCounts": {
|
|
83
|
+
"own": 4,
|
|
84
|
+
"aria": 0,
|
|
85
|
+
"dom": 278,
|
|
86
|
+
"other": 0
|
|
87
|
+
}
|
|
88
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ConfidenceIndicator",
|
|
3
|
+
"source": "src/components/ConfidenceIndicator.tsx",
|
|
4
|
+
"propsType": "ConfidenceIndicatorProps",
|
|
5
|
+
"description": "ConfidenceIndicator — how much to trust the thing next to it.\n\nTHERE IS NO PERCENTAGE PROP, AND THERE WILL NOT BE ONE\n\n\"87% confident\" reads as a measurement. Almost nowhere is it one: it is\nusually a softmax score, a heuristic, or a number a model produced about\nitself — none of which are calibrated probabilities, and all of which invite\na reader to treat two digits of precision as real. Three levels cannot\noverclaim in that way.\n\n`basis` IS REQUIRED FOR THE SAME REASON. A level with nothing behind it is\ndecoration that changes behaviour: people act on \"high confidence\" whether or\nnot anything justifies it. Making the justification a required prop is the\nonly enforcement available here, and it is a type error rather than a policy\n— which is the strongest kind this system can offer.\n\nIt renders as text plus a three-bar meter, never the meter alone. The bars\ndiffer in filled COUNT, not only in colour, so the reading survives greyscale\nand forced-colours mode.",
|
|
6
|
+
"import": "import { ConfidenceIndicator } from 'ionbase-ui';",
|
|
7
|
+
"status": "stable",
|
|
8
|
+
"summary": "How much to trust the thing next to it — three levels with a required basis, never a percentage.",
|
|
9
|
+
"useWhen": [
|
|
10
|
+
"a generated answer varies in reliability and the reader should weigh it",
|
|
11
|
+
"you can say what the confidence rests on"
|
|
12
|
+
],
|
|
13
|
+
"useInstead": [
|
|
14
|
+
{
|
|
15
|
+
"when": "the answer is wrong or missing rather than uncertain",
|
|
16
|
+
"use": "Alert"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"when": "you want to show where the claim came from",
|
|
20
|
+
"use": "Citation",
|
|
21
|
+
"why": "a source is stronger than a confidence level, and often what the reader actually wanted"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"when": "it is a status rather than a reliability",
|
|
25
|
+
"use": "Badge"
|
|
26
|
+
}
|
|
27
|
+
],
|
|
28
|
+
"variants": {
|
|
29
|
+
"level": {
|
|
30
|
+
"low": {
|
|
31
|
+
"use": "thin or conflicting evidence. One bar, warning colour"
|
|
32
|
+
},
|
|
33
|
+
"medium": {
|
|
34
|
+
"use": "reasonable support with real gaps. Two bars"
|
|
35
|
+
},
|
|
36
|
+
"high": {
|
|
37
|
+
"use": "corroborated, and you can say by what. Three bars"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"a11y": {
|
|
42
|
+
"guarantees": [
|
|
43
|
+
"the level is spelled out in text, so it never depends on the meter",
|
|
44
|
+
"the meter differs in filled COUNT rather than only in colour, and in forced-colours mode filled bars are solid while empty ones are outlined"
|
|
45
|
+
],
|
|
46
|
+
"requires": [
|
|
47
|
+
"`basis` — a type error if omitted, and the reason this component exists rather than a coloured dot"
|
|
48
|
+
]
|
|
49
|
+
},
|
|
50
|
+
"antiPatterns": [
|
|
51
|
+
{
|
|
52
|
+
"dont": "asking for a percentage prop",
|
|
53
|
+
"why": "\"87% confident\" reads as a measurement and almost never is one — usually a softmax score or a model's claim about itself, neither of which is a calibrated probability. Three levels cannot overclaim that way"
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"dont": "a vague basis like \"model output\"",
|
|
57
|
+
"why": "it satisfies the type and defeats the purpose — say \"3 of 4 sources agree\" or \"single unverified source\""
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"dont": "high confidence on every response",
|
|
61
|
+
"why": "an indicator that never varies is decoration that still changes behaviour"
|
|
62
|
+
}
|
|
63
|
+
],
|
|
64
|
+
"stylesheet": "src/styles/confidence-indicator.css",
|
|
65
|
+
"tokens": [
|
|
66
|
+
"--border-width-default",
|
|
67
|
+
"--font-family-sans",
|
|
68
|
+
"--font-weight-medium",
|
|
69
|
+
"--icon-information",
|
|
70
|
+
"--icon-success",
|
|
71
|
+
"--icon-tertiary",
|
|
72
|
+
"--icon-warning",
|
|
73
|
+
"--radius-2xs",
|
|
74
|
+
"--spacing-12",
|
|
75
|
+
"--spacing-16",
|
|
76
|
+
"--spacing-2",
|
|
77
|
+
"--spacing-4",
|
|
78
|
+
"--spacing-8",
|
|
79
|
+
"--text-default",
|
|
80
|
+
"--text-secondary",
|
|
81
|
+
"--text-tertiary",
|
|
82
|
+
"--type-caption",
|
|
83
|
+
"--type-caption-line-height"
|
|
84
|
+
],
|
|
85
|
+
"props": {
|
|
86
|
+
"level": {
|
|
87
|
+
"type": "ConfidenceLevel",
|
|
88
|
+
"required": true,
|
|
89
|
+
"origin": "own",
|
|
90
|
+
"values": [
|
|
91
|
+
"low",
|
|
92
|
+
"medium",
|
|
93
|
+
"high"
|
|
94
|
+
]
|
|
95
|
+
},
|
|
96
|
+
"basis": {
|
|
97
|
+
"type": "string",
|
|
98
|
+
"required": true,
|
|
99
|
+
"origin": "own",
|
|
100
|
+
"description": "What the level is based on. REQUIRED, and the reason this component exists\nrather than a coloured dot: a confidence with no stated basis is a number\nthe reader has no way to weigh. \"3 of 4 sources agree\", \"no matching\nrecords found\", \"single unverified source\"."
|
|
101
|
+
},
|
|
102
|
+
"label": {
|
|
103
|
+
"type": "string | undefined",
|
|
104
|
+
"required": false,
|
|
105
|
+
"origin": "own",
|
|
106
|
+
"description": "Override the level's word. Keep it a word, not a percentage."
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
"propCounts": {
|
|
110
|
+
"own": 3,
|
|
111
|
+
"aria": 0,
|
|
112
|
+
"dom": 277,
|
|
113
|
+
"other": 0
|
|
114
|
+
}
|
|
115
|
+
}
|
package/dist/meta/Input.json
CHANGED
|
@@ -232,13 +232,13 @@
|
|
|
232
232
|
"description": "Identifies the element (or elements) whose contents or presence are controlled by the current\nelement."
|
|
233
233
|
},
|
|
234
234
|
"enterKeyHint": {
|
|
235
|
-
"type": "\"
|
|
235
|
+
"type": "\"done\" | \"enter\" | \"go\" | \"next\" | \"previous\" | \"search\" | \"send\" | undefined",
|
|
236
236
|
"required": false,
|
|
237
237
|
"origin": "aria",
|
|
238
238
|
"description": "An enumerated attribute that defines what action label or icon to preset for the enter key on\nvirtual keyboards. See\n[MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/enterkeyhint).",
|
|
239
239
|
"values": [
|
|
240
|
-
"enter",
|
|
241
240
|
"done",
|
|
241
|
+
"enter",
|
|
242
242
|
"go",
|
|
243
243
|
"next",
|
|
244
244
|
"previous",
|
|
@@ -122,6 +122,42 @@
|
|
|
122
122
|
"origin": "own",
|
|
123
123
|
"description": "Spread onto the dial-code `<button>`. This is how a country picker gets\nattached — see the note on scope below."
|
|
124
124
|
},
|
|
125
|
+
"type": {
|
|
126
|
+
"type": "(string & {}) | \"search\" | \"text\" | \"url\" | \"tel\" | \"email\" | \"password\" | undefined",
|
|
127
|
+
"required": false,
|
|
128
|
+
"origin": "aria",
|
|
129
|
+
"description": "The type of input to render. See\n[MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#htmlattrdeftype).",
|
|
130
|
+
"tags": {
|
|
131
|
+
"default": "'text'"
|
|
132
|
+
},
|
|
133
|
+
"default": "tel"
|
|
134
|
+
},
|
|
135
|
+
"disabled": {
|
|
136
|
+
"type": "boolean | undefined",
|
|
137
|
+
"required": false,
|
|
138
|
+
"origin": "own",
|
|
139
|
+
"tags": {
|
|
140
|
+
"deprecated": "Use `isDisabled`. Accepted as an alias for one minor version."
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
"form": {
|
|
144
|
+
"type": "string | undefined",
|
|
145
|
+
"required": false,
|
|
146
|
+
"origin": "aria",
|
|
147
|
+
"description": "The `<form>` element to associate the input with.\nThe value of this attribute must be the id of a `<form>` in the same document.\nSee [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input#form)."
|
|
148
|
+
},
|
|
149
|
+
"name": {
|
|
150
|
+
"type": "string | undefined",
|
|
151
|
+
"required": false,
|
|
152
|
+
"origin": "aria",
|
|
153
|
+
"description": "The name of the input element, used when submitting an HTML form. See\n[MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#htmlattrdefname)."
|
|
154
|
+
},
|
|
155
|
+
"value": {
|
|
156
|
+
"type": "string | undefined",
|
|
157
|
+
"required": false,
|
|
158
|
+
"origin": "aria",
|
|
159
|
+
"description": "The current value (controlled)."
|
|
160
|
+
},
|
|
125
161
|
"defaultValue": {
|
|
126
162
|
"type": "string | undefined",
|
|
127
163
|
"required": false,
|
|
@@ -155,13 +191,13 @@
|
|
|
155
191
|
"description": "Class names for the control box (`.ion-input`). Always lands here —\nnever on the form-field wrapper. Use `wrapperClassName` for that."
|
|
156
192
|
},
|
|
157
193
|
"enterKeyHint": {
|
|
158
|
-
"type": "\"
|
|
194
|
+
"type": "\"done\" | \"enter\" | \"go\" | \"next\" | \"previous\" | \"search\" | \"send\" | undefined",
|
|
159
195
|
"required": false,
|
|
160
196
|
"origin": "aria",
|
|
161
197
|
"description": "An enumerated attribute that defines what action label or icon to preset for the enter key on\nvirtual keyboards. See\n[MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/enterkeyhint).",
|
|
162
198
|
"values": [
|
|
163
|
-
"enter",
|
|
164
199
|
"done",
|
|
200
|
+
"enter",
|
|
165
201
|
"go",
|
|
166
202
|
"next",
|
|
167
203
|
"previous",
|
|
@@ -359,36 +395,12 @@
|
|
|
359
395
|
],
|
|
360
396
|
"default": "md"
|
|
361
397
|
},
|
|
362
|
-
"type": {
|
|
363
|
-
"type": "(string & {}) | \"search\" | \"text\" | \"url\" | \"tel\" | \"email\" | \"password\" | undefined",
|
|
364
|
-
"required": false,
|
|
365
|
-
"origin": "aria",
|
|
366
|
-
"description": "The type of input to render. See\n[MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#htmlattrdeftype).",
|
|
367
|
-
"tags": {
|
|
368
|
-
"default": "'text'"
|
|
369
|
-
},
|
|
370
|
-
"default": "tel"
|
|
371
|
-
},
|
|
372
398
|
"autoComplete": {
|
|
373
399
|
"type": "string | undefined",
|
|
374
400
|
"required": false,
|
|
375
401
|
"origin": "aria",
|
|
376
402
|
"description": "Describes the type of autocomplete functionality the input should provide if any. See\n[MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#htmlattrdefautocomplete)."
|
|
377
403
|
},
|
|
378
|
-
"disabled": {
|
|
379
|
-
"type": "boolean | undefined",
|
|
380
|
-
"required": false,
|
|
381
|
-
"origin": "own",
|
|
382
|
-
"tags": {
|
|
383
|
-
"deprecated": "Use `isDisabled`. Accepted as an alias for one minor version."
|
|
384
|
-
}
|
|
385
|
-
},
|
|
386
|
-
"form": {
|
|
387
|
-
"type": "string | undefined",
|
|
388
|
-
"required": false,
|
|
389
|
-
"origin": "aria",
|
|
390
|
-
"description": "The `<form>` element to associate the input with.\nThe value of this attribute must be the id of a `<form>` in the same document.\nSee [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input#form)."
|
|
391
|
-
},
|
|
392
404
|
"maxLength": {
|
|
393
405
|
"type": "number | undefined",
|
|
394
406
|
"required": false,
|
|
@@ -401,12 +413,6 @@
|
|
|
401
413
|
"origin": "aria",
|
|
402
414
|
"description": "The minimum number of characters required by the input. See\n[MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#htmlattrdefminlength)."
|
|
403
415
|
},
|
|
404
|
-
"name": {
|
|
405
|
-
"type": "string | undefined",
|
|
406
|
-
"required": false,
|
|
407
|
-
"origin": "aria",
|
|
408
|
-
"description": "The name of the input element, used when submitting an HTML form. See\n[MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#htmlattrdefname)."
|
|
409
|
-
},
|
|
410
416
|
"pattern": {
|
|
411
417
|
"type": "string | undefined",
|
|
412
418
|
"required": false,
|
|
@@ -419,12 +425,6 @@
|
|
|
419
425
|
"origin": "aria",
|
|
420
426
|
"description": "Temporary text that occupies the text input when it is empty."
|
|
421
427
|
},
|
|
422
|
-
"value": {
|
|
423
|
-
"type": "string | undefined",
|
|
424
|
-
"required": false,
|
|
425
|
-
"origin": "aria",
|
|
426
|
-
"description": "The current value (controlled)."
|
|
427
|
-
},
|
|
428
428
|
"isDisabled": {
|
|
429
429
|
"type": "boolean | undefined",
|
|
430
430
|
"required": false,
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "StreamingText",
|
|
3
|
+
"source": "src/components/StreamingText.tsx",
|
|
4
|
+
"propsType": "StreamingTextProps",
|
|
5
|
+
"description": "StreamingText — model output arriving a token at a time.\n\nIT IS NOT A LIVE REGION, AND THAT IS THE WHOLE DESIGN\n\nThe obvious implementation — `aria-live=\"polite\"` on the container — is the\none that makes a screen reader unusable. Every token mutation queues an\nannouncement, so the user hears the answer re-read, stuttered, dozens of\ntimes, and cannot get ahead of it. `aria-live=\"off\"` is not an oversight\nhere; it is the accessible choice.\n\nWhat it does instead: `aria-busy` while streaming, so assistive tech knows\nthe region is unsettled and can wait. The text is ordinary readable content\nthroughout — a screen-reader user navigates into it whenever they want,\nexactly like sighted users reading ahead of the cursor.\n\nANNOUNCING COMPLETION IS THE CALLER'S CALL, not this component's. Some\nsurfaces want \"response complete\"; a chat with ten turns on screen does not\nwant ten of them. Render your own `role=\"status\"` when you want it.\n\nTHE HEIGHT IS RESERVED, NOT ANIMATED. `minLines` holds space in `lh` units so\nthe content below stays still. A container that grows token by token drags\nthe whole page, which is worse for someone using magnification than the wait.\n\nThe cursor is CSS and `aria-hidden`. It stops blinking under\n`prefers-reduced-motion` — a blinking element is a WCAG 2.3.1 concern and a\ngenuine problem for some vestibular and attention conditions.",
|
|
6
|
+
"import": "import { StreamingText } from 'ionbase-ui';",
|
|
7
|
+
"status": "stable",
|
|
8
|
+
"summary": "Model output arriving a token at a time, in a container that does not move. Deliberately not a live region.",
|
|
9
|
+
"useWhen": [
|
|
10
|
+
"rendering a response that streams in rather than arriving whole",
|
|
11
|
+
"the reader should be able to start reading before generation finishes"
|
|
12
|
+
],
|
|
13
|
+
"useInstead": [
|
|
14
|
+
{
|
|
15
|
+
"when": "the text is already complete",
|
|
16
|
+
"use": "Alert",
|
|
17
|
+
"why": "nothing about this component helps once there is nothing left to arrive"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"when": "you are showing progress through steps rather than producing text",
|
|
21
|
+
"use": "AgentActivity"
|
|
22
|
+
}
|
|
23
|
+
],
|
|
24
|
+
"a11y": {
|
|
25
|
+
"role": "region when `label` is set, none otherwise",
|
|
26
|
+
"guarantees": [
|
|
27
|
+
"`aria-live=\"off\"`, deliberately — a polite live region re-announces the whole answer on every token, which makes a streaming response unusable with a screen reader",
|
|
28
|
+
"`aria-busy` while streaming, so assistive tech knows the region is unsettled",
|
|
29
|
+
"the text stays ordinary readable content throughout, so a screen-reader user can read ahead exactly as a sighted user does",
|
|
30
|
+
"the cursor is `aria-hidden`, is a styled box rather than a text character, and stops blinking under `prefers-reduced-motion` (WCAG 2.3.1)"
|
|
31
|
+
],
|
|
32
|
+
"requires": [
|
|
33
|
+
"announcing completion yourself, with your own `role=\"status\"`, if the surface wants it — a chat with ten turns on screen does not want ten announcements",
|
|
34
|
+
"`label` when the region needs a name of its own"
|
|
35
|
+
]
|
|
36
|
+
},
|
|
37
|
+
"antiPatterns": [
|
|
38
|
+
{
|
|
39
|
+
"dont": "wrapping it in `aria-live=\"polite\"`",
|
|
40
|
+
"why": "every token queues an announcement; the user hears the answer stuttered dozens of times and cannot get ahead of it"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"dont": "letting the container grow token by token with no reserved height",
|
|
44
|
+
"do": "`minLines`",
|
|
45
|
+
"why": "the content below climbs the screen while someone is reading it, which is worse under magnification than the wait"
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"dont": "a text-character cursor like ▌",
|
|
49
|
+
"why": "some screen readers read it aloud even inside an aria-hidden span"
|
|
50
|
+
}
|
|
51
|
+
],
|
|
52
|
+
"stylesheet": "src/styles/streaming-text.css",
|
|
53
|
+
"tokens": [
|
|
54
|
+
"--font-family-sans",
|
|
55
|
+
"--ion-streaming-min-lines",
|
|
56
|
+
"--text-default",
|
|
57
|
+
"--text-tertiary",
|
|
58
|
+
"--type-body",
|
|
59
|
+
"--type-body-line-height"
|
|
60
|
+
],
|
|
61
|
+
"props": {
|
|
62
|
+
"children": {
|
|
63
|
+
"type": "React.ReactNode",
|
|
64
|
+
"required": false,
|
|
65
|
+
"origin": "own",
|
|
66
|
+
"description": "The text so far. Re-render with more of it; this component appends nothing."
|
|
67
|
+
},
|
|
68
|
+
"isStreaming": {
|
|
69
|
+
"type": "boolean | undefined",
|
|
70
|
+
"required": false,
|
|
71
|
+
"origin": "own",
|
|
72
|
+
"description": "More is still arriving. Shows the cursor and marks the region busy."
|
|
73
|
+
},
|
|
74
|
+
"minLines": {
|
|
75
|
+
"type": "number | undefined",
|
|
76
|
+
"required": false,
|
|
77
|
+
"origin": "own",
|
|
78
|
+
"description": "Rows of height to hold while the text is short, so the page below does not\nclimb the screen as tokens arrive. Costs blank space at the start and buys\na layout that does not move under a reader."
|
|
79
|
+
},
|
|
80
|
+
"label": {
|
|
81
|
+
"type": "string | undefined",
|
|
82
|
+
"required": false,
|
|
83
|
+
"origin": "own",
|
|
84
|
+
"description": "Accessible name for the region."
|
|
85
|
+
},
|
|
86
|
+
"hideCursor": {
|
|
87
|
+
"type": "boolean | undefined",
|
|
88
|
+
"required": false,
|
|
89
|
+
"origin": "own",
|
|
90
|
+
"description": "Hide the trailing cursor. The text still marks itself busy."
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
"propCounts": {
|
|
94
|
+
"own": 5,
|
|
95
|
+
"aria": 0,
|
|
96
|
+
"dom": 277,
|
|
97
|
+
"other": 0
|
|
98
|
+
}
|
|
99
|
+
}
|