@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,420 @@
|
|
|
1
|
+
{
|
|
2
|
+
"kind": "component",
|
|
3
|
+
"id": "ui.select",
|
|
4
|
+
"name": "Select",
|
|
5
|
+
"displayName": "Select",
|
|
6
|
+
"version": "0.1.0",
|
|
7
|
+
"level": "atom",
|
|
8
|
+
"domain": "forms",
|
|
9
|
+
"bidi": true,
|
|
10
|
+
"description": "Custom select dropdown atom with searchable options, keyboard navigation, success/error states with shake animation and state icons, helper text, error message with aria-describedby, clear button, and loading spinner. No validation logic — states driven externally.",
|
|
11
|
+
"props": [
|
|
12
|
+
{
|
|
13
|
+
"name": "options",
|
|
14
|
+
"reactive": true,
|
|
15
|
+
"label": "Options",
|
|
16
|
+
"type": "SelectOption[] | Signal<SelectOption[]>",
|
|
17
|
+
"required": true,
|
|
18
|
+
"placeholder": [
|
|
19
|
+
{ "value": "us", "label": "United States" },
|
|
20
|
+
{ "value": "ca", "label": "Canada" },
|
|
21
|
+
{ "value": "uk", "label": "United Kingdom" }
|
|
22
|
+
],
|
|
23
|
+
"description": "Options to display in the dropdown. Each option has value, label, and optional disabled flag.",
|
|
24
|
+
"itemSchema": {
|
|
25
|
+
"value": { "type": "string", "required": true },
|
|
26
|
+
"label": { "type": "string", "required": true },
|
|
27
|
+
"disabled": { "type": "boolean" }
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"name": "id",
|
|
32
|
+
"label": "ID",
|
|
33
|
+
"editor": { "tab": "settings" },
|
|
34
|
+
"type": "string",
|
|
35
|
+
"description": "Explicit trigger ID — overrides auto-generated ID. Used by FormField for label association."
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"name": "name",
|
|
39
|
+
"label": "Name",
|
|
40
|
+
"editor": { "tab": "settings" },
|
|
41
|
+
"type": "string",
|
|
42
|
+
"description": "Select name attribute for form submission via hidden native <select>"
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"name": "value",
|
|
46
|
+
"reactive": true,
|
|
47
|
+
"label": "Value",
|
|
48
|
+
"type": "string | Signal<string>",
|
|
49
|
+
"description": "Selected value — static string or signal accessor for controlled select"
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"name": "placeholder",
|
|
53
|
+
"label": "Placeholder",
|
|
54
|
+
"type": "string",
|
|
55
|
+
"description": "Placeholder text shown when no option is selected"
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"name": "disabled",
|
|
59
|
+
"label": "Disabled",
|
|
60
|
+
"editor": { "tab": "settings" },
|
|
61
|
+
"type": "boolean | Signal<boolean>",
|
|
62
|
+
"default": false,
|
|
63
|
+
"description": "Disabled state — prevents opening and interaction. Accepts signal accessor."
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"name": "readonly",
|
|
67
|
+
"label": "Read-only",
|
|
68
|
+
"editor": { "tab": "settings" },
|
|
69
|
+
"type": "boolean | Signal<boolean>",
|
|
70
|
+
"default": false,
|
|
71
|
+
"description": "Readonly state — trigger is not interactive but remains focusable. Accepts signal accessor."
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"name": "required",
|
|
75
|
+
"label": "Required",
|
|
76
|
+
"type": "boolean",
|
|
77
|
+
"default": false,
|
|
78
|
+
"description": "Sets aria-required on trigger + red asterisk on placeholder via data-required"
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"name": "error",
|
|
82
|
+
"label": "Error",
|
|
83
|
+
"editor": { "tab": "settings" },
|
|
84
|
+
"type": "boolean | Signal<boolean>",
|
|
85
|
+
"default": false,
|
|
86
|
+
"description": "Visual error state — sets aria-invalid, shows red border + alert icon, shakes on transition. No validation logic."
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
"name": "errorMessage",
|
|
90
|
+
"label": "Error message",
|
|
91
|
+
"editor": { "tab": "settings" },
|
|
92
|
+
"type": "string | Signal<string>",
|
|
93
|
+
"description": "Error message shown below select when error is truthy. Linked via aria-describedby with role='alert'. Replaces helper text when visible."
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
"name": "helperText",
|
|
97
|
+
"label": "Helper text",
|
|
98
|
+
"type": "string",
|
|
99
|
+
"description": "Persistent hint text below select. Hidden when error message is visible. Linked via aria-describedby."
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"name": "success",
|
|
103
|
+
"label": "Success",
|
|
104
|
+
"editor": { "tab": "settings" },
|
|
105
|
+
"type": "boolean | Signal<boolean>",
|
|
106
|
+
"default": false,
|
|
107
|
+
"description": "Visual success state — shows green border + checkmark icon. Error takes precedence when both are true."
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
"name": "size",
|
|
111
|
+
"label": "Size",
|
|
112
|
+
"type": "enum",
|
|
113
|
+
"enum": ["sm", "md", "lg"],
|
|
114
|
+
"default": "md",
|
|
115
|
+
"description": "Control size — maps to u-control-* utilities (padding, min-height, gap)"
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"name": "label",
|
|
119
|
+
"label": "Label",
|
|
120
|
+
"type": "string",
|
|
121
|
+
"required": true,
|
|
122
|
+
"placeholder": "Country",
|
|
123
|
+
"description": "Accessible label — used as aria-label on the trigger button"
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
"name": "searchable",
|
|
127
|
+
"label": "Searchable",
|
|
128
|
+
"type": "boolean",
|
|
129
|
+
"default": false,
|
|
130
|
+
"description": "Enable search/filter input in the dropdown. Filters options by label as user types."
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
"name": "clearable",
|
|
134
|
+
"label": "Clearable",
|
|
135
|
+
"type": "boolean",
|
|
136
|
+
"default": false,
|
|
137
|
+
"description": "Show clear button when a value is selected. Hidden when disabled, readonly, or loading."
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
"name": "loading",
|
|
141
|
+
"label": "Loading",
|
|
142
|
+
"editor": { "tab": "settings" },
|
|
143
|
+
"type": "boolean | Signal<boolean>",
|
|
144
|
+
"default": false,
|
|
145
|
+
"description": "Loading state — shows spinner, sets aria-busy, hides chevron and clear button."
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
"name": "onChange",
|
|
149
|
+
"type": "(value: string, option: SelectOption | undefined) => void",
|
|
150
|
+
"description": "Fires when the selected value changes, with the value and matching option object"
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
"name": "onBlur",
|
|
154
|
+
"type": "(e: FocusEvent) => void",
|
|
155
|
+
"description": "Fires when select loses focus (entire component, not just trigger)"
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
"name": "onFocus",
|
|
159
|
+
"type": "(e: FocusEvent) => void",
|
|
160
|
+
"description": "Fires when trigger gains focus"
|
|
161
|
+
}
|
|
162
|
+
],
|
|
163
|
+
"events": ["change", "blur", "focus"],
|
|
164
|
+
"slots": [],
|
|
165
|
+
"tokens": {
|
|
166
|
+
"border.default": "border(control) — stable width, color-only changes",
|
|
167
|
+
"border.hover": "--color-primary (border-color) + --color-surface-bright (bg tint)",
|
|
168
|
+
"border.focus": "--color-focus-ring + ring() box-shadow (--ring-offset: 0px)",
|
|
169
|
+
"border.open": "Same as focus — ring persists while dropdown is visible",
|
|
170
|
+
"border.error": "--color-danger + shake animation on transition",
|
|
171
|
+
"border.success": "--color-success + --ring-color: --color-success",
|
|
172
|
+
"border.disabled": "opacity via --state-disabled-opacity",
|
|
173
|
+
"bg.default": "--color-surface",
|
|
174
|
+
"bg.hover": "--color-surface-bright",
|
|
175
|
+
"bg.focus": "--color-surface-bright",
|
|
176
|
+
"bg.readonly": "--color-surface-variant",
|
|
177
|
+
"bg.dropdown": "--color-surface with --shadow-lg",
|
|
178
|
+
"bg.option-hover": "state-background(hover) mixin with --color-primary",
|
|
179
|
+
"bg.option-pressed": "state-background(pressed) mixin with --color-primary",
|
|
180
|
+
"bg.option-selected": "color-mix --color-primary at --state-selected-opacity",
|
|
181
|
+
"text.placeholder": "--color-text-muted at opacity 0.65",
|
|
182
|
+
"text.option": "--color-text",
|
|
183
|
+
"text.option-selected": "--color-primary + --font-weight-medium",
|
|
184
|
+
"text.empty": "--color-text-muted (centered)",
|
|
185
|
+
"text.helper": "--color-text-muted (--font-size-xs)",
|
|
186
|
+
"text.error-message": "--color-danger (--font-size-xs)",
|
|
187
|
+
"radius": "--radius-md (via u-radius-md)",
|
|
188
|
+
"radius.dropdown": "--radius-md",
|
|
189
|
+
"radius.search": "--radius-sm",
|
|
190
|
+
"radius.option": "--radius-sm (pill-like hover with margin-inline: xs)",
|
|
191
|
+
"scrollbar": "thin scrollbar-width with --color-border thumb",
|
|
192
|
+
"search.highlight": "<mark> wraps matched text with --color-primary + --font-weight-semibold",
|
|
193
|
+
"focus.ring": "ring() with --ring-offset: 0px",
|
|
194
|
+
"disabled.opacity": "--state-disabled-opacity",
|
|
195
|
+
"font-size.sm": "--font-size-xs",
|
|
196
|
+
"font-size.md": "--font-size-sm",
|
|
197
|
+
"font-size.lg": "--font-size-body",
|
|
198
|
+
"icon.chevron": "--_select-icon-size mapped per size, rotates 180deg when open, darkens to --color-text on hover/open",
|
|
199
|
+
"icon.check": "--icon-size-sm (selected option checkmark, --color-primary)",
|
|
200
|
+
"icon.state-success": "--color-success (checkmark)",
|
|
201
|
+
"icon.state-error": "--color-danger (triangle alert)",
|
|
202
|
+
"icon.clear": "--_select-icon-size (× button)",
|
|
203
|
+
"gap.trigger": "--space-xs (between value, icons, chevron)",
|
|
204
|
+
"gap.option": "--space-xs (label to check)",
|
|
205
|
+
"gap.sub-text": "--space-xs (helper/error to trigger)",
|
|
206
|
+
"dropdown.z-index": "var(--_select-dropdown-z) default 100",
|
|
207
|
+
"dropdown.max-height": "var(--_select-dropdown-max-block) default 15rem",
|
|
208
|
+
"dropdown.animation.open": "--motion-animation-slide-up (entrance), --motion-animation-slide-down when flipped to top",
|
|
209
|
+
"dropdown.animation.close": "--motion-animation-fade-out with exit easing",
|
|
210
|
+
"dropdown.flip": "Auto-flips to top (data-placement='top') when insufficient viewport space below",
|
|
211
|
+
"shake.animation": "ui-form-shake (shared form keyframe)",
|
|
212
|
+
"success-pop.animation": "--motion-animation-fade-scale-in on false→true transition",
|
|
213
|
+
"spinner.animation": "--motion-animation-spin",
|
|
214
|
+
"spinner.adaptive": "--color-text-muted default, --color-danger on error, --color-success on success",
|
|
215
|
+
"listbox.scroll-shadows": "background-attachment:local fade indicators using --_scroll-bg, --state-hover-opacity, --space-lg/sm",
|
|
216
|
+
"search.focus-ring": "var(--ring-color) inherited from wrapper — adapts to error/success state"
|
|
217
|
+
},
|
|
218
|
+
"spacing": {
|
|
219
|
+
"internal": {
|
|
220
|
+
"trigger-gap": { "relationship": "lovers", "token": "xs" },
|
|
221
|
+
"option-padding-inline": { "relationship": "friends", "token": "md" },
|
|
222
|
+
"option-padding-block": {
|
|
223
|
+
"relationship": "close_friends",
|
|
224
|
+
"token": "sm"
|
|
225
|
+
},
|
|
226
|
+
"search-padding": { "relationship": "lovers", "token": "xs" },
|
|
227
|
+
"listbox-padding-block": { "relationship": "lovers", "token": "xs" }
|
|
228
|
+
},
|
|
229
|
+
"external": {
|
|
230
|
+
"trigger-to-dropdown": { "relationship": "lovers", "token": "xs" },
|
|
231
|
+
"select-to-helper": { "relationship": "lovers", "token": "xs" },
|
|
232
|
+
"select-to-error": { "relationship": "lovers", "token": "xs" },
|
|
233
|
+
"label-to-select": { "relationship": "close_friends", "token": "sm" },
|
|
234
|
+
"field-to-field": { "relationship": "friends", "token": "md" }
|
|
235
|
+
}
|
|
236
|
+
},
|
|
237
|
+
"constraints": [
|
|
238
|
+
"Never use raw hex colors — use design system tokens",
|
|
239
|
+
"Use logical CSS properties only (margin-inline-start, not margin-left)",
|
|
240
|
+
"All transitions wrapped in @include a11y.motion-safe",
|
|
241
|
+
"Must handle forced-colors mode — add visible border for ButtonText",
|
|
242
|
+
"No validation logic — error/success props are visual only",
|
|
243
|
+
"Label prop is required — used as aria-label on the combobox trigger",
|
|
244
|
+
"Error takes precedence over success visually (CSS source order + state icon priority)",
|
|
245
|
+
"Error shake skips initial render (firstRun guard)",
|
|
246
|
+
"Error shake uses shared ui-form-shake keyframe from _form-animations.scss",
|
|
247
|
+
"Dropdown animation uses design system --motion-animation-slide-down",
|
|
248
|
+
"Loading hides chevron and clear button with aria-busy",
|
|
249
|
+
"Readonly prevents dropdown from opening — trigger shows variant background",
|
|
250
|
+
"SelectProps extends FormControlBaseProps — shared form control interface",
|
|
251
|
+
"Helper text hidden when error message is visible (error replaces helper)",
|
|
252
|
+
"State icons auto-injected: checkmark for success (pop-in animation), triangle alert for error",
|
|
253
|
+
"Hidden native <select> for form submission (aria-hidden, tabindex=-1)",
|
|
254
|
+
"Dropdown closes on outside click, Escape, Tab, focusout, and ancestor scroll",
|
|
255
|
+
"Search input filters options by label (case-insensitive) with matching text highlighted via <mark>",
|
|
256
|
+
"Keyboard navigation skips disabled options",
|
|
257
|
+
"Type-ahead: typing characters on closed trigger jumps to matching option (500ms buffer)",
|
|
258
|
+
"Escape in search clears query first, second Escape closes dropdown",
|
|
259
|
+
"Trigger is <div role=combobox> not <button> — allows nested clear <button> (valid HTML)",
|
|
260
|
+
"Trigger has user-select: none to prevent text selection on drag",
|
|
261
|
+
"Required shows red asterisk on placeholder via CSS ::after"
|
|
262
|
+
],
|
|
263
|
+
"a11y": [
|
|
264
|
+
"role='combobox' on trigger button — standard ARIA combobox pattern",
|
|
265
|
+
"aria-haspopup='listbox' — indicates dropdown type",
|
|
266
|
+
"aria-expanded toggles with dropdown open/close state",
|
|
267
|
+
"aria-controls links trigger to listbox element",
|
|
268
|
+
"aria-activedescendant tracks keyboard-highlighted option",
|
|
269
|
+
"aria-label from required label prop on trigger",
|
|
270
|
+
"aria-invalid='true' when error prop is truthy",
|
|
271
|
+
"aria-describedby links to error message and/or helper text",
|
|
272
|
+
"Error message has role='alert' (assertive live region)",
|
|
273
|
+
"aria-required='true' when required prop is true",
|
|
274
|
+
"aria-busy='true' when loading is true",
|
|
275
|
+
"role='listbox' on dropdown option list",
|
|
276
|
+
"role='option' on each option with aria-selected",
|
|
277
|
+
"aria-disabled='true' on disabled options",
|
|
278
|
+
"role='searchbox' on search input with aria-autocomplete='list'",
|
|
279
|
+
"Search input has aria-label='Search {label}' and aria-controls to listbox",
|
|
280
|
+
"Auto-generated id on trigger — enables FormField <label for> association",
|
|
281
|
+
"Keyboard nav: ArrowDown/Up, Enter/Space to select, Escape to close, Home/End, PageUp/PageDown (5 options)",
|
|
282
|
+
"aria-live='polite' region announces filtered option count for screen readers",
|
|
283
|
+
"State icon has aria-hidden='true' — decorative, not announced",
|
|
284
|
+
"Escape stopPropagation prevents closing parent modals",
|
|
285
|
+
"Focus ring via box-shadow ring() on trigger :focus-visible",
|
|
286
|
+
"Forced-colors: visible borders, Highlight for active/selected, GrayText for disabled",
|
|
287
|
+
"Clear button has aria-label='Clear selection' and type='button'",
|
|
288
|
+
"Empty state has role='presentation' (not interactive)"
|
|
289
|
+
],
|
|
290
|
+
"ai": {
|
|
291
|
+
"synonyms": [
|
|
292
|
+
"dropdown",
|
|
293
|
+
"select box",
|
|
294
|
+
"picker",
|
|
295
|
+
"combo box",
|
|
296
|
+
"select input",
|
|
297
|
+
"option list"
|
|
298
|
+
],
|
|
299
|
+
"avoid": [
|
|
300
|
+
"native <select> element — use <Select> component for consistent styling",
|
|
301
|
+
"hardcoded border colors — use design tokens",
|
|
302
|
+
"built-in validation — validation belongs in Form/DynamicForm",
|
|
303
|
+
"visible label in Select — use FormField molecule for external label",
|
|
304
|
+
"outline: none without alternative — focus ring handled by ring()"
|
|
305
|
+
],
|
|
306
|
+
"patterns": [
|
|
307
|
+
"Basic: <Select label=\"'Country'\" options=\"countries\" />",
|
|
308
|
+
"Placeholder: <Select label=\"'Status'\" options=\"statuses\" placeholder=\"'Choose...'\" />",
|
|
309
|
+
"Searchable: <Select label=\"'Country'\" options=\"countries\" searchable=\"true\" />",
|
|
310
|
+
"Clearable: <Select label=\"'Priority'\" options=\"priorities\" clearable=\"true\" />",
|
|
311
|
+
"Controlled: <Select label=\"'Role'\" options=\"roles\" value=\"selectedRole\" onChange=\"handleChange\" />",
|
|
312
|
+
"Error state: <Select label=\"'Category'\" options=\"categories\" error=\"hasError\" errorMessage=\"'Required field'\" />",
|
|
313
|
+
"Helper text: <Select label=\"'Region'\" options=\"regions\" helperText=\"'Choose your nearest region'\" />",
|
|
314
|
+
"Loading: <Select label=\"'Team'\" options=\"teams\" loading=\"isLoading\" />",
|
|
315
|
+
"With FormField: <FormField label=\"'Country'\" required=\"true\"><Select label=\"'Country'\" options=\"countries\" required=\"true\" /></FormField>"
|
|
316
|
+
]
|
|
317
|
+
},
|
|
318
|
+
"itemSchema": {
|
|
319
|
+
"SelectOption": {
|
|
320
|
+
"value": {
|
|
321
|
+
"type": "string",
|
|
322
|
+
"required": true,
|
|
323
|
+
"description": "Option value used as selected value"
|
|
324
|
+
},
|
|
325
|
+
"label": {
|
|
326
|
+
"type": "string",
|
|
327
|
+
"required": true,
|
|
328
|
+
"description": "Display label shown in dropdown and trigger"
|
|
329
|
+
},
|
|
330
|
+
"disabled": {
|
|
331
|
+
"type": "boolean",
|
|
332
|
+
"description": "Whether this option is disabled"
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
},
|
|
336
|
+
"examples": [
|
|
337
|
+
{
|
|
338
|
+
"id": "basic",
|
|
339
|
+
"title": "Basic select with options",
|
|
340
|
+
"pithy": "<Select label=\"'Country'\" options=\"countries\" placeholder=\"'Select a country'\" />",
|
|
341
|
+
"assertions": [
|
|
342
|
+
"renders trigger button",
|
|
343
|
+
"shows placeholder",
|
|
344
|
+
"opens dropdown on click",
|
|
345
|
+
"no violations in axe-core"
|
|
346
|
+
]
|
|
347
|
+
},
|
|
348
|
+
{
|
|
349
|
+
"id": "searchable",
|
|
350
|
+
"title": "Searchable select",
|
|
351
|
+
"pithy": "<Select label=\"'Country'\" options=\"countries\" searchable=\"true\" />",
|
|
352
|
+
"assertions": [
|
|
353
|
+
"search input in dropdown",
|
|
354
|
+
"filters options by label",
|
|
355
|
+
"keyboard nav works in search"
|
|
356
|
+
]
|
|
357
|
+
},
|
|
358
|
+
{
|
|
359
|
+
"id": "clearable",
|
|
360
|
+
"title": "Clearable select",
|
|
361
|
+
"pithy": "<Select label=\"'Priority'\" options=\"priorities\" clearable=\"true\" value=\"selectedPriority\" />",
|
|
362
|
+
"assertions": [
|
|
363
|
+
"clear button hidden when empty",
|
|
364
|
+
"clear button visible with value",
|
|
365
|
+
"clears on click"
|
|
366
|
+
]
|
|
367
|
+
},
|
|
368
|
+
{
|
|
369
|
+
"id": "error",
|
|
370
|
+
"title": "Error state with message",
|
|
371
|
+
"pithy": "<Select label=\"'Category'\" options=\"categories\" error=\"hasError\" errorMessage=\"'Please select a category'\" />",
|
|
372
|
+
"assertions": [
|
|
373
|
+
"aria-invalid on error",
|
|
374
|
+
"shake animation on transition",
|
|
375
|
+
"error message visible",
|
|
376
|
+
"role='alert'"
|
|
377
|
+
]
|
|
378
|
+
},
|
|
379
|
+
{
|
|
380
|
+
"id": "success",
|
|
381
|
+
"title": "Success state",
|
|
382
|
+
"pithy": "<Select label=\"'Status'\" options=\"statuses\" success=\"true\" value=\"'active'\" />",
|
|
383
|
+
"assertions": [
|
|
384
|
+
"data-success on wrapper",
|
|
385
|
+
"green border",
|
|
386
|
+
"checkmark icon visible"
|
|
387
|
+
]
|
|
388
|
+
},
|
|
389
|
+
{
|
|
390
|
+
"id": "loading",
|
|
391
|
+
"title": "Loading state",
|
|
392
|
+
"pithy": "<Select label=\"'Team'\" options=\"teams\" loading=\"isLoading\" />",
|
|
393
|
+
"assertions": [
|
|
394
|
+
"spinner visible",
|
|
395
|
+
"aria-busy='true'",
|
|
396
|
+
"chevron hidden",
|
|
397
|
+
"dropdown blocked"
|
|
398
|
+
]
|
|
399
|
+
},
|
|
400
|
+
{
|
|
401
|
+
"id": "keyboard-nav",
|
|
402
|
+
"title": "Full keyboard navigation",
|
|
403
|
+
"pithy": "<Select label=\"'Role'\" options=\"roles\" />",
|
|
404
|
+
"assertions": [
|
|
405
|
+
"Enter/Space opens",
|
|
406
|
+
"ArrowDown/Up navigates",
|
|
407
|
+
"Enter selects",
|
|
408
|
+
"Escape closes",
|
|
409
|
+
"Home/End jump"
|
|
410
|
+
]
|
|
411
|
+
}
|
|
412
|
+
],
|
|
413
|
+
"designGuidance": {
|
|
414
|
+
"surface": "Trigger on --color-surface, hover brightens to --color-surface-bright. Dropdown on --color-surface with --shadow-lg. Readonly trigger uses --color-surface-variant. Selected options have faint primary bg tint.",
|
|
415
|
+
"depth": "No shadow on trigger by default. Focus ring via box-shadow ring(). Dropdown has --shadow-lg for elevated depth. Options have rounded corners with inline margin for pill-like hover.",
|
|
416
|
+
"borders": "Stable border width — only border-color changes across states. Dropdown has card border. Search input has control border.",
|
|
417
|
+
"interactivity": "Hover changes border color + subtle bg tint. Focus shows ring. Open state keeps ring active. Chevron rotates 180deg + darkens on hover/open. Options highlight on hover/keyboard with pressed state on click. Error shakes on transition. Success shows checkmark pop-in. Dropdown slides up on open, fades out on close. Auto-flips to top when near viewport bottom. Search highlights matching text. Type-ahead on closed trigger.",
|
|
418
|
+
"bestPractices": "Use searchable for long option lists (>7 items). Use clearable when selection is optional. Use placeholder to hint expected selection. Combine with FormField for visible label. Error/success are mutually exclusive (error wins). Loading blocks interaction."
|
|
419
|
+
}
|
|
420
|
+
}
|