@pithyjs/pidl-catalog 0.1.0-beta.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/LICENSE +21 -0
- package/dist/specs/atoms/actions/button.pidl.json +289 -0
- package/dist/specs/atoms/actions/icon-group.pidl.json +141 -0
- package/dist/specs/atoms/actions/segmented-control.pidl.json +137 -0
- package/dist/specs/atoms/content/action-tile.pidl.json +135 -0
- package/dist/specs/atoms/content/badge.pidl.json +189 -0
- package/dist/specs/atoms/content/callout.pidl.json +170 -0
- package/dist/specs/atoms/content/code-block.pidl.json +170 -0
- package/dist/specs/atoms/content/heading.pidl.json +175 -0
- package/dist/specs/atoms/content/icon.pidl.json +127 -0
- package/dist/specs/atoms/content/image.pidl.json +227 -0
- package/dist/specs/atoms/content/prose.pidl.json +183 -0
- package/dist/specs/atoms/content/stat.pidl.json +158 -0
- package/dist/specs/atoms/content/tabs.pidl.json +207 -0
- package/dist/specs/atoms/content/text.pidl.json +212 -0
- package/dist/specs/atoms/content/tile.pidl.json +156 -0
- package/dist/specs/atoms/data/donut.pidl.json +352 -0
- package/dist/specs/atoms/data/gauge.pidl.json +274 -0
- package/dist/specs/atoms/forms/checkbox-group.pidl.json +170 -0
- package/dist/specs/atoms/forms/checkbox.pidl.json +323 -0
- package/dist/specs/atoms/forms/file-picker.pidl.json +161 -0
- package/dist/specs/atoms/forms/form-field.pidl.json +106 -0
- package/dist/specs/atoms/forms/input.pidl.json +466 -0
- package/dist/specs/atoms/forms/radio-group.pidl.json +174 -0
- package/dist/specs/atoms/forms/radio.pidl.json +312 -0
- package/dist/specs/atoms/forms/search-input.pidl.json +265 -0
- package/dist/specs/atoms/forms/select.pidl.json +420 -0
- package/dist/specs/atoms/forms/textarea.pidl.json +422 -0
- package/dist/specs/atoms/forms/toggle.pidl.json +314 -0
- package/dist/specs/layout/grid-item.pidl.json +120 -0
- package/dist/specs/layout/grid.pidl.json +157 -0
- package/dist/specs/layout/page-section.pidl.json +105 -0
- package/dist/specs/layout/smart-container.pidl.json +148 -0
- package/dist/specs/layout/stack.pidl.json +144 -0
- package/dist/specs/organisms/content/accordion.pidl.json +196 -0
- package/dist/specs/organisms/content/card.pidl.json +283 -0
- package/dist/specs/organisms/feedback/alert-dialog.pidl.json +158 -0
- package/dist/specs/organisms/feedback/modal.pidl.json +133 -0
- package/dist/specs/organisms/feedback/toast.pidl.json +150 -0
- package/dist/specs/organisms/forms/dynamic-form.pidl.json +314 -0
- package/dist/specs/organisms/forms/form.pidl.json +135 -0
- package/dist/specs/organisms/forms/subscribe-form.pidl.json +188 -0
- package/dist/specs/organisms/navigation/command-palette.pidl.json +263 -0
- package/dist/specs/organisms/navigation/docs-sidebar.pidl.json +264 -0
- package/dist/specs/organisms/navigation/navbar.pidl.json +356 -0
- package/dist/specs/organisms/navigation/table-of-contents.pidl.json +197 -0
- package/dist/specs/sections/contact-section.pidl.json +183 -0
- package/dist/specs/sections/cta-section.pidl.json +168 -0
- package/dist/specs/sections/faq-section.pidl.json +202 -0
- package/dist/specs/sections/features-section.pidl.json +214 -0
- package/dist/specs/sections/footer-section.pidl.json +187 -0
- package/dist/specs/sections/hero-section.pidl.json +202 -0
- package/dist/src/borders-psychology.d.ts +17 -0
- package/dist/src/borders-psychology.d.ts.map +1 -0
- package/dist/src/borders-psychology.js +42 -0
- package/dist/src/borders-psychology.js.map +1 -0
- package/dist/src/color-psychology.d.ts +20 -0
- package/dist/src/color-psychology.d.ts.map +1 -0
- package/dist/src/color-psychology.js +57 -0
- package/dist/src/color-psychology.js.map +1 -0
- package/dist/src/design-intelligence.d.ts +13 -0
- package/dist/src/design-intelligence.d.ts.map +1 -0
- package/dist/src/design-intelligence.js +36 -0
- package/dist/src/design-intelligence.js.map +1 -0
- package/dist/src/index.d.ts +6238 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +105 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/motion-psychology.d.ts +19 -0
- package/dist/src/motion-psychology.d.ts.map +1 -0
- package/dist/src/motion-psychology.js +47 -0
- package/dist/src/motion-psychology.js.map +1 -0
- package/dist/src/mutation-vocabulary.d.ts +13 -0
- package/dist/src/mutation-vocabulary.d.ts.map +1 -0
- package/dist/src/mutation-vocabulary.js +67 -0
- package/dist/src/mutation-vocabulary.js.map +1 -0
- package/dist/src/radius-psychology.d.ts +17 -0
- package/dist/src/radius-psychology.d.ts.map +1 -0
- package/dist/src/radius-psychology.js +42 -0
- package/dist/src/radius-psychology.js.map +1 -0
- package/dist/src/shadows-psychology.d.ts +17 -0
- package/dist/src/shadows-psychology.d.ts.map +1 -0
- package/dist/src/shadows-psychology.js +44 -0
- package/dist/src/shadows-psychology.js.map +1 -0
- package/dist/src/spacing-psychology.d.ts +22 -0
- package/dist/src/spacing-psychology.d.ts.map +1 -0
- package/dist/src/spacing-psychology.js +59 -0
- package/dist/src/spacing-psychology.js.map +1 -0
- package/dist/src/typography-psychology.d.ts +22 -0
- package/dist/src/typography-psychology.d.ts.map +1 -0
- package/dist/src/typography-psychology.js +68 -0
- package/dist/src/typography-psychology.js.map +1 -0
- package/package.json +64 -0
|
@@ -0,0 +1,422 @@
|
|
|
1
|
+
{
|
|
2
|
+
"kind": "component",
|
|
3
|
+
"id": "ui.textarea",
|
|
4
|
+
"name": "Textarea",
|
|
5
|
+
"displayName": "Textarea",
|
|
6
|
+
"version": "0.1.0",
|
|
7
|
+
"level": "atom",
|
|
8
|
+
"domain": "forms",
|
|
9
|
+
"bidi": true,
|
|
10
|
+
"description": "Textarea atom with auto-resize (CSS field-sizing with JS fallback), floating label, success/error states with shake animation and state icons, helper text, error message with aria-describedby, character counter, clear button, and loading spinner. No validation logic — states driven externally.",
|
|
11
|
+
"props": [
|
|
12
|
+
{
|
|
13
|
+
"name": "id",
|
|
14
|
+
"label": "ID",
|
|
15
|
+
"editor": { "tab": "settings" },
|
|
16
|
+
"type": "string",
|
|
17
|
+
"description": "Explicit textarea ID — overrides auto-generated ID. Used by FormField for label association."
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"name": "name",
|
|
21
|
+
"label": "Name",
|
|
22
|
+
"editor": { "tab": "settings" },
|
|
23
|
+
"type": "string",
|
|
24
|
+
"description": "Textarea name attribute for form submission"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"name": "value",
|
|
28
|
+
"reactive": true,
|
|
29
|
+
"label": "Value",
|
|
30
|
+
"type": "string | Signal<string>",
|
|
31
|
+
"description": "Textarea value — static string or signal accessor for controlled textarea"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"name": "placeholder",
|
|
35
|
+
"label": "Placeholder",
|
|
36
|
+
"type": "string",
|
|
37
|
+
"description": "Placeholder text shown when textarea is empty"
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"name": "disabled",
|
|
41
|
+
"label": "Disabled",
|
|
42
|
+
"editor": { "tab": "settings" },
|
|
43
|
+
"type": "boolean | Signal<boolean>",
|
|
44
|
+
"default": false,
|
|
45
|
+
"description": "Disabled state — uses native disabled attribute. Accepts signal accessor."
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"name": "readonly",
|
|
49
|
+
"label": "Read-only",
|
|
50
|
+
"editor": { "tab": "settings" },
|
|
51
|
+
"type": "boolean | Signal<boolean>",
|
|
52
|
+
"default": false,
|
|
53
|
+
"description": "Readonly state — textarea is not editable but remains focusable. Accepts signal accessor."
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"name": "required",
|
|
57
|
+
"label": "Required",
|
|
58
|
+
"type": "boolean",
|
|
59
|
+
"default": false,
|
|
60
|
+
"description": "Sets aria-required on the textarea"
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"name": "error",
|
|
64
|
+
"label": "Error",
|
|
65
|
+
"editor": { "tab": "settings" },
|
|
66
|
+
"type": "boolean | Signal<boolean>",
|
|
67
|
+
"default": false,
|
|
68
|
+
"description": "Visual error state — sets aria-invalid, shows red border + alert icon, shakes on transition. No validation logic."
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"name": "errorMessage",
|
|
72
|
+
"label": "Error message",
|
|
73
|
+
"editor": { "tab": "settings" },
|
|
74
|
+
"type": "string | Signal<string>",
|
|
75
|
+
"description": "Error message shown below textarea when error is truthy. Linked via aria-describedby with role='alert'. Replaces helper text when visible."
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"name": "helperText",
|
|
79
|
+
"label": "Helper text",
|
|
80
|
+
"type": "string",
|
|
81
|
+
"description": "Persistent hint text below textarea. Hidden when error message is visible. Linked via aria-describedby."
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"name": "success",
|
|
85
|
+
"label": "Success",
|
|
86
|
+
"editor": { "tab": "settings" },
|
|
87
|
+
"type": "boolean | Signal<boolean>",
|
|
88
|
+
"default": false,
|
|
89
|
+
"description": "Visual success state — shows green border + checkmark icon. Error takes precedence when both are true."
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"name": "size",
|
|
93
|
+
"label": "Size",
|
|
94
|
+
"type": "enum",
|
|
95
|
+
"enum": ["sm", "md", "lg"],
|
|
96
|
+
"default": "md",
|
|
97
|
+
"description": "Control size — maps to u-control-* utilities (padding, min-height, gap)"
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
"name": "label",
|
|
101
|
+
"label": "Label",
|
|
102
|
+
"type": "string",
|
|
103
|
+
"required": true,
|
|
104
|
+
"placeholder": "Message",
|
|
105
|
+
"description": "Accessible label — used as aria-label or as floating label text when floatingLabel is true"
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
"name": "floatingLabel",
|
|
109
|
+
"label": "Floating label",
|
|
110
|
+
"type": "boolean",
|
|
111
|
+
"default": false,
|
|
112
|
+
"description": "Enable floating label — label starts inside the textarea, floats to top-inside on focus/fill."
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
"name": "autocomplete",
|
|
116
|
+
"label": "Autocomplete",
|
|
117
|
+
"editor": { "tab": "settings" },
|
|
118
|
+
"type": "string",
|
|
119
|
+
"description": "Autocomplete hint (e.g., 'off')"
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
"name": "maxLength",
|
|
123
|
+
"label": "Max length",
|
|
124
|
+
"type": "number",
|
|
125
|
+
"description": "Maximum character length — also enables character counter display with tabular-nums"
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
"name": "rows",
|
|
129
|
+
"label": "Rows",
|
|
130
|
+
"editor": { "tab": "layout" },
|
|
131
|
+
"type": "number",
|
|
132
|
+
"default": 3,
|
|
133
|
+
"description": "Initial visible rows. Ignored when autoResize is true and field-sizing is supported."
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
"name": "autoResize",
|
|
137
|
+
"label": "Auto resize",
|
|
138
|
+
"editor": { "tab": "layout" },
|
|
139
|
+
"type": "boolean",
|
|
140
|
+
"default": true,
|
|
141
|
+
"description": "Enable auto-resize — uses CSS field-sizing: content with JS fallback for Firefox"
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
"name": "maxBlockSize",
|
|
145
|
+
"label": "Max block size",
|
|
146
|
+
"editor": { "tab": "layout" },
|
|
147
|
+
"type": "string",
|
|
148
|
+
"description": "Maximum block-size for auto-resize (CSS value, e.g. '200px', '15rem'). No limit when omitted."
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
"name": "minBlockSize",
|
|
152
|
+
"label": "Min block size",
|
|
153
|
+
"editor": { "tab": "layout" },
|
|
154
|
+
"type": "string",
|
|
155
|
+
"description": "Minimum block-size (CSS value, e.g. '80px', '5rem'). Falls back to rows-based height when omitted."
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
"name": "clearable",
|
|
159
|
+
"label": "Clearable",
|
|
160
|
+
"type": "boolean",
|
|
161
|
+
"default": false,
|
|
162
|
+
"description": "Show clear button when textarea has value. Hidden when disabled, readonly, or loading."
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
"name": "loading",
|
|
166
|
+
"label": "Loading",
|
|
167
|
+
"editor": { "tab": "settings" },
|
|
168
|
+
"type": "boolean | Signal<boolean>",
|
|
169
|
+
"default": false,
|
|
170
|
+
"description": "Loading state — shows spinner, sets aria-busy, hides clear button."
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
"name": "onInput",
|
|
174
|
+
"type": "(value: string, e: InputEvent) => void",
|
|
175
|
+
"description": "Fires on every keystroke with current value and native InputEvent"
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
"name": "onChange",
|
|
179
|
+
"type": "(value: string, e: Event) => void",
|
|
180
|
+
"description": "Fires on commit (blur) with current value and native Event"
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
"name": "onBlur",
|
|
184
|
+
"type": "(e: FocusEvent) => void",
|
|
185
|
+
"description": "Fires when textarea loses focus"
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
"name": "onFocus",
|
|
189
|
+
"type": "(e: FocusEvent) => void",
|
|
190
|
+
"description": "Fires when textarea gains focus"
|
|
191
|
+
}
|
|
192
|
+
],
|
|
193
|
+
"events": ["input", "change", "blur", "focus"],
|
|
194
|
+
"slots": [],
|
|
195
|
+
"tokens": {
|
|
196
|
+
"border.default": "border(control) — stable width, color-only changes",
|
|
197
|
+
"border.hover": "--color-primary (border-color) + --color-surface-bright (bg tint)",
|
|
198
|
+
"border.focus": "--color-focus-ring + ring() box-shadow (--ring-offset: 0px)",
|
|
199
|
+
"border.error": "--color-danger + shake animation on transition",
|
|
200
|
+
"border.success": "--color-success + --ring-color: --color-success",
|
|
201
|
+
"border.disabled": "opacity via --state-disabled-opacity",
|
|
202
|
+
"bg.default": "--color-surface (via --_scroll-bg)",
|
|
203
|
+
"bg.hover": "--color-surface-bright (via --_scroll-bg)",
|
|
204
|
+
"bg.focus": "--color-surface-bright (via --_scroll-bg)",
|
|
205
|
+
"bg.readonly": "--color-surface-variant (via --_scroll-bg)",
|
|
206
|
+
"bg.error": "color-mix(--color-danger 3%, --color-surface) — faint danger wash",
|
|
207
|
+
"text.placeholder": "--color-text-muted",
|
|
208
|
+
"text.counter": "--color-text-muted -> --color-warning -> --color-danger",
|
|
209
|
+
"text.helper": "--color-text-muted (--font-size-xs)",
|
|
210
|
+
"text.error-message": "--color-danger (--font-size-xs)",
|
|
211
|
+
"text.label-resting": "--color-text-muted",
|
|
212
|
+
"text.label-floating": "--color-primary (focus) / --color-text-muted (filled)",
|
|
213
|
+
"text.label-error": "--color-danger",
|
|
214
|
+
"text.label-success": "--color-success",
|
|
215
|
+
"radius": "--radius-md (via u-radius-md)",
|
|
216
|
+
"focus.ring": "ring() with --ring-offset: 0px",
|
|
217
|
+
"disabled.opacity": "--state-disabled-opacity",
|
|
218
|
+
"font-size.sm": "--font-size-xs",
|
|
219
|
+
"font-size.md": "--font-size-sm",
|
|
220
|
+
"font-size.lg": "--font-size-body",
|
|
221
|
+
"font-size.label-floating": "--font-size-xs",
|
|
222
|
+
"font-size.counter": "--font-size-xs (tabular-nums)",
|
|
223
|
+
"icon.size": "--_textarea-icon-size mapped per size",
|
|
224
|
+
"icon.state-success": "--color-success (checkmark)",
|
|
225
|
+
"icon.state-error": "--color-danger (triangle alert)",
|
|
226
|
+
"gap.actions": "--space-xs",
|
|
227
|
+
"gap.sub-text": "--space-xs (helper/error to wrapper)",
|
|
228
|
+
"caret.default": "--color-primary",
|
|
229
|
+
"caret.error": "--color-danger",
|
|
230
|
+
"caret.success": "--color-success",
|
|
231
|
+
"selection.default": "color-mix(--color-primary, --state-selected-opacity)",
|
|
232
|
+
"selection.error": "color-mix(--color-danger, --state-selected-opacity)",
|
|
233
|
+
"selection.success": "color-mix(--color-success, --state-selected-opacity)",
|
|
234
|
+
"spinner.adaptive": "--color-text-muted default, --color-danger on error, --color-success on success",
|
|
235
|
+
"required.indicator": "--color-danger asterisk on floating label via [data-required]",
|
|
236
|
+
"shake.animation": "ui-form-shake with --motion-distance-subtle",
|
|
237
|
+
"success-pop.animation": "--motion-animation-fade-scale-in on false->true transition"
|
|
238
|
+
},
|
|
239
|
+
"spacing": {
|
|
240
|
+
"internal": {
|
|
241
|
+
"textarea-to-actions": { "relationship": "lovers", "token": "xs" },
|
|
242
|
+
"icon-to-counter": { "relationship": "lovers", "token": "xs" }
|
|
243
|
+
},
|
|
244
|
+
"external": {
|
|
245
|
+
"wrapper-to-helper": { "relationship": "lovers", "token": "xs" },
|
|
246
|
+
"wrapper-to-error": { "relationship": "lovers", "token": "xs" },
|
|
247
|
+
"label-to-textarea": { "relationship": "close_friends", "token": "sm" },
|
|
248
|
+
"field-to-field": { "relationship": "friends", "token": "md" }
|
|
249
|
+
}
|
|
250
|
+
},
|
|
251
|
+
"constraints": [
|
|
252
|
+
"Never use raw hex colors — use design system tokens",
|
|
253
|
+
"Use logical CSS properties only (margin-inline-start, not margin-left)",
|
|
254
|
+
"All transitions wrapped in @include a11y.motion-safe",
|
|
255
|
+
"Must handle forced-colors mode — add visible border for ButtonText",
|
|
256
|
+
"No validation logic — error/success props are visual only",
|
|
257
|
+
"Label prop is required — used as aria-label or floating label text",
|
|
258
|
+
"Uses native disabled (not aria-disabled)",
|
|
259
|
+
"Error takes precedence over success visually",
|
|
260
|
+
"Error shake skips initial render (firstRun guard)",
|
|
261
|
+
"Character counter is included in aria-describedby for screen reader access, styled with tabular-nums",
|
|
262
|
+
"Clear button is a tabbable type='button' — keyboard-accessible",
|
|
263
|
+
"Loading hides clear button with aria-busy",
|
|
264
|
+
"Readonly suppresses focus styling — label always floated",
|
|
265
|
+
"TextareaProps extends FormControlBaseProps",
|
|
266
|
+
"Auto-resize uses CSS field-sizing: content as progressive enhancement with JS scrollHeight fallback",
|
|
267
|
+
"Helper text hidden when error message is visible"
|
|
268
|
+
],
|
|
269
|
+
"a11y": [
|
|
270
|
+
"aria-label from required label prop — set when floatingLabel is false",
|
|
271
|
+
"Visible <label for='...'> when floatingLabel is true",
|
|
272
|
+
"aria-invalid='true' when error prop is truthy",
|
|
273
|
+
"aria-describedby dynamically updated — references error ID when error is active, helper ID when present, counter ID when maxLength is set",
|
|
274
|
+
"Error message has role='alert' for screen reader announcement",
|
|
275
|
+
"aria-required='true' when required prop is true",
|
|
276
|
+
"aria-busy='true' when loading is true",
|
|
277
|
+
"Native disabled attribute — removes from tab order",
|
|
278
|
+
"Focus ring via box-shadow ring() on wrapper :focus-within",
|
|
279
|
+
"Forced-colors: visible border, GrayText for disabled, Highlight outline on focus",
|
|
280
|
+
"Auto-generated id on <textarea> — enables FormField <label for='...'> association",
|
|
281
|
+
"Clicking wrapper focuses the inner textarea",
|
|
282
|
+
"Clear button has aria-label='Clear', type='button', and :focus-visible ring",
|
|
283
|
+
"Character counter linked via aria-describedby — screen readers announce count on focus",
|
|
284
|
+
"State icons have aria-hidden='true'",
|
|
285
|
+
"Error shake respects prefers-reduced-motion"
|
|
286
|
+
],
|
|
287
|
+
"ai": {
|
|
288
|
+
"synonyms": [
|
|
289
|
+
"text area",
|
|
290
|
+
"multiline input",
|
|
291
|
+
"comment box",
|
|
292
|
+
"message field",
|
|
293
|
+
"multi-line text",
|
|
294
|
+
"rich text input"
|
|
295
|
+
],
|
|
296
|
+
"avoid": [
|
|
297
|
+
"div with contentEditable — use <Textarea> component",
|
|
298
|
+
"hardcoded border colors — use design tokens",
|
|
299
|
+
"built-in validation — validation belongs in Form/DynamicForm",
|
|
300
|
+
"visible label in Textarea without floatingLabel — use FormField molecule",
|
|
301
|
+
"outline: none without alternative — focus ring handled by ring()"
|
|
302
|
+
],
|
|
303
|
+
"patterns": [
|
|
304
|
+
"Basic: <Textarea label=\"'Bio'\" placeholder=\"'Tell us about yourself'\" />",
|
|
305
|
+
"Floating label: <Textarea label=\"'Message'\" floatingLabel=\"true\" />",
|
|
306
|
+
"Character counter: <Textarea label=\"'Bio'\" maxLength=\"500\" />",
|
|
307
|
+
"Fixed rows: <Textarea label=\"'Notes'\" autoResize=\"false\" rows=\"6\" />",
|
|
308
|
+
"Max height: <Textarea label=\"'Comment'\" maxBlockSize=\"'200px'\" />",
|
|
309
|
+
"Clearable: <Textarea label=\"'Search'\" clearable=\"true\" />",
|
|
310
|
+
"Loading: <Textarea label=\"'Content'\" loading=\"isSaving\" />",
|
|
311
|
+
"Error: <Textarea label=\"'Message'\" error=\"hasError\" errorMessage=\"'Message is required'\" />",
|
|
312
|
+
"Helper text: <Textarea label=\"'Bio'\" helperText=\"'Max 500 characters'\" maxLength=\"500\" />",
|
|
313
|
+
"Success: <Textarea label=\"'Bio'\" success=\"isValid\" />"
|
|
314
|
+
]
|
|
315
|
+
},
|
|
316
|
+
"examples": [
|
|
317
|
+
{
|
|
318
|
+
"id": "basic",
|
|
319
|
+
"title": "Basic textarea",
|
|
320
|
+
"pithy": "<Textarea label=\"'Bio'\" placeholder=\"'Tell us about yourself'\" />",
|
|
321
|
+
"assertions": [
|
|
322
|
+
"auto-resizes on input",
|
|
323
|
+
"aria-label set",
|
|
324
|
+
"no violations in axe-core"
|
|
325
|
+
]
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
"id": "floating-label",
|
|
329
|
+
"title": "Floating label textarea",
|
|
330
|
+
"pithy": "<Textarea label=\"'Message'\" floatingLabel=\"true\" />",
|
|
331
|
+
"assertions": [
|
|
332
|
+
"visible <label>",
|
|
333
|
+
"no aria-label",
|
|
334
|
+
"label floats on focus"
|
|
335
|
+
]
|
|
336
|
+
},
|
|
337
|
+
{
|
|
338
|
+
"id": "character-counter",
|
|
339
|
+
"title": "Textarea with character counter",
|
|
340
|
+
"pithy": "<Textarea label=\"'Bio'\" maxLength=\"500\" />",
|
|
341
|
+
"assertions": [
|
|
342
|
+
"counter shows 0/500",
|
|
343
|
+
"warn color at 80%",
|
|
344
|
+
"danger at limit",
|
|
345
|
+
"tabular-nums"
|
|
346
|
+
]
|
|
347
|
+
},
|
|
348
|
+
{
|
|
349
|
+
"id": "fixed-rows",
|
|
350
|
+
"title": "Fixed rows without auto-resize",
|
|
351
|
+
"pithy": "<Textarea label=\"'Notes'\" autoResize=\"false\" rows=\"6\" />",
|
|
352
|
+
"assertions": ["resize: vertical", "no field-sizing", "6 rows visible"]
|
|
353
|
+
},
|
|
354
|
+
{
|
|
355
|
+
"id": "error-shake",
|
|
356
|
+
"title": "Error with shake animation",
|
|
357
|
+
"pithy": "<Textarea label=\"'Message'\" error=\"hasError\" />",
|
|
358
|
+
"assertions": [
|
|
359
|
+
"aria-invalid on error",
|
|
360
|
+
"shake animation on transition",
|
|
361
|
+
"no shake on initial render"
|
|
362
|
+
]
|
|
363
|
+
},
|
|
364
|
+
{
|
|
365
|
+
"id": "clearable",
|
|
366
|
+
"title": "Clearable textarea",
|
|
367
|
+
"pithy": "<Textarea label=\"'Comment'\" clearable=\"true\" />",
|
|
368
|
+
"assertions": [
|
|
369
|
+
"clear button hidden when empty",
|
|
370
|
+
"clear button visible with value",
|
|
371
|
+
"clears on click"
|
|
372
|
+
]
|
|
373
|
+
},
|
|
374
|
+
{
|
|
375
|
+
"id": "readonly",
|
|
376
|
+
"title": "Readonly textarea",
|
|
377
|
+
"pithy": "<Textarea label=\"'Terms'\" readonly=\"true\" value=\"'Non-editable content'\" />",
|
|
378
|
+
"assertions": [
|
|
379
|
+
"textarea is not editable",
|
|
380
|
+
"data-readonly on wrapper",
|
|
381
|
+
"remains focusable"
|
|
382
|
+
]
|
|
383
|
+
},
|
|
384
|
+
{
|
|
385
|
+
"id": "loading",
|
|
386
|
+
"title": "Loading textarea",
|
|
387
|
+
"pithy": "<Textarea label=\"'Content'\" loading=\"isSaving\" />",
|
|
388
|
+
"assertions": [
|
|
389
|
+
"spinner visible",
|
|
390
|
+
"aria-busy='true'",
|
|
391
|
+
"clear button hidden"
|
|
392
|
+
]
|
|
393
|
+
},
|
|
394
|
+
{
|
|
395
|
+
"id": "success",
|
|
396
|
+
"title": "Success textarea",
|
|
397
|
+
"pithy": "<Textarea label=\"'Bio'\" success=\"isValid\" />",
|
|
398
|
+
"assertions": [
|
|
399
|
+
"data-success on wrapper",
|
|
400
|
+
"checkmark icon visible",
|
|
401
|
+
"green border"
|
|
402
|
+
]
|
|
403
|
+
},
|
|
404
|
+
{
|
|
405
|
+
"id": "helper-text",
|
|
406
|
+
"title": "Textarea with helper text",
|
|
407
|
+
"pithy": "<Textarea label=\"'Bio'\" helperText=\"'Max 500 characters'\" maxLength=\"500\" />",
|
|
408
|
+
"assertions": [
|
|
409
|
+
"helper text visible below",
|
|
410
|
+
"linked via aria-describedby",
|
|
411
|
+
"hidden when error active"
|
|
412
|
+
]
|
|
413
|
+
}
|
|
414
|
+
],
|
|
415
|
+
"designGuidance": {
|
|
416
|
+
"surface": "Transparent inner textarea on --color-surface wrapper. Hover brightens to --color-surface-bright. Focus also uses --color-surface-bright. Readonly uses --color-surface-variant.",
|
|
417
|
+
"depth": "No shadow by default. Focus ring via box-shadow ring() with --ring-offset: 0px.",
|
|
418
|
+
"borders": "Stable border width — only border-color changes across states.",
|
|
419
|
+
"interactivity": "Hover changes border color + subtle bg tint. Focus shows ring + bg tint. Error shakes on transition + shows alert icon. Success shows checkmark icon with pop-in. Auto-resize grows textarea as user types. Clear button appears as an absolutely positioned control inside the wrapper when value present.",
|
|
420
|
+
"bestPractices": "Use autoResize (default) for most cases. Set maxBlockSize to cap growth. Use fixed rows for code/log fields. Combine maxLength with helperText for best UX. Use loading for async save feedback."
|
|
421
|
+
}
|
|
422
|
+
}
|