@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,314 @@
|
|
|
1
|
+
{
|
|
2
|
+
"kind": "component",
|
|
3
|
+
"id": "ui.toggle",
|
|
4
|
+
"name": "Toggle",
|
|
5
|
+
"displayName": "Toggle",
|
|
6
|
+
"version": "0.1.0",
|
|
7
|
+
"level": "atom",
|
|
8
|
+
"domain": "forms",
|
|
9
|
+
"bidi": true,
|
|
10
|
+
"description": "Accessible toggle / switch atom with a pill-shaped track and sliding thumb knob, role='switch' with aria-checked, error/success states with shake animation, helper/error text, loading spinner, and full a11y wiring. 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 input ID — overrides auto-generated ID."
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"name": "name",
|
|
21
|
+
"label": "Name",
|
|
22
|
+
"editor": { "tab": "settings" },
|
|
23
|
+
"type": "string",
|
|
24
|
+
"description": "Input name attribute for form submission."
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"name": "value",
|
|
28
|
+
"label": "Value",
|
|
29
|
+
"editor": { "tab": "settings" },
|
|
30
|
+
"type": "string",
|
|
31
|
+
"default": "on",
|
|
32
|
+
"description": "Submitted value when the toggle is on."
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"name": "checked",
|
|
36
|
+
"label": "Checked",
|
|
37
|
+
"editor": { "tab": "settings" },
|
|
38
|
+
"type": "boolean | Signal<boolean>",
|
|
39
|
+
"default": false,
|
|
40
|
+
"description": "Checked (on) state — static or signal accessor for controlled toggle."
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"name": "disabled",
|
|
44
|
+
"label": "Disabled",
|
|
45
|
+
"editor": { "tab": "settings" },
|
|
46
|
+
"type": "boolean | Signal<boolean>",
|
|
47
|
+
"default": false,
|
|
48
|
+
"description": "Disabled state — uses native disabled attribute."
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"name": "readonly",
|
|
52
|
+
"label": "Read-only",
|
|
53
|
+
"editor": { "tab": "settings" },
|
|
54
|
+
"type": "boolean | Signal<boolean>",
|
|
55
|
+
"default": false,
|
|
56
|
+
"description": "Readonly state — focusable but not toggleable. Native input ignores readonly, so toggling is intercepted via click preventDefault, Space keydown preventDefault, and a change-event rollback."
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"name": "required",
|
|
60
|
+
"label": "Required",
|
|
61
|
+
"type": "boolean",
|
|
62
|
+
"default": false,
|
|
63
|
+
"description": "Sets aria-required and adds a visual asterisk to the label."
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"name": "error",
|
|
67
|
+
"label": "Error",
|
|
68
|
+
"editor": { "tab": "settings" },
|
|
69
|
+
"type": "boolean | Signal<boolean>",
|
|
70
|
+
"default": false,
|
|
71
|
+
"description": "Visual error state — sets aria-invalid, red track border, shake on transition."
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"name": "errorMessage",
|
|
75
|
+
"label": "Error message",
|
|
76
|
+
"editor": { "tab": "settings" },
|
|
77
|
+
"type": "string | Signal<string>",
|
|
78
|
+
"description": "Error message shown below the toggle when error is truthy. Linked via aria-describedby with role='alert'."
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"name": "helperText",
|
|
82
|
+
"label": "Helper text",
|
|
83
|
+
"type": "string",
|
|
84
|
+
"description": "Persistent hint text below the toggle. Hidden when error is visible."
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"name": "success",
|
|
88
|
+
"label": "Success",
|
|
89
|
+
"editor": { "tab": "settings" },
|
|
90
|
+
"type": "boolean | Signal<boolean>",
|
|
91
|
+
"default": false,
|
|
92
|
+
"description": "Visual success state — green track border / fill. Error takes precedence."
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"name": "size",
|
|
96
|
+
"label": "Size",
|
|
97
|
+
"type": "enum",
|
|
98
|
+
"enum": ["sm", "md", "lg"],
|
|
99
|
+
"default": "md",
|
|
100
|
+
"description": "Control size — drives track/thumb dimensions and label font-size."
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
"name": "label",
|
|
104
|
+
"label": "Label",
|
|
105
|
+
"type": "string",
|
|
106
|
+
"required": true,
|
|
107
|
+
"placeholder": "Enable notifications",
|
|
108
|
+
"description": "Visible label text rendered next to the track. Always required."
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
"name": "loading",
|
|
112
|
+
"label": "Loading",
|
|
113
|
+
"editor": { "tab": "settings" },
|
|
114
|
+
"type": "boolean | Signal<boolean>",
|
|
115
|
+
"default": false,
|
|
116
|
+
"description": "Loading state — overlays a spinner inside the track and sets aria-busy."
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
"name": "onChange",
|
|
120
|
+
"type": "(checked: boolean, e: Event) => void",
|
|
121
|
+
"description": "Fires whenever the checked state changes."
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
"name": "onBlur",
|
|
125
|
+
"type": "(e: FocusEvent) => void",
|
|
126
|
+
"description": "Fires when the toggle loses focus."
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
"name": "onFocus",
|
|
130
|
+
"type": "(e: FocusEvent) => void",
|
|
131
|
+
"description": "Fires when the toggle gains focus."
|
|
132
|
+
}
|
|
133
|
+
],
|
|
134
|
+
"events": ["change", "blur", "focus"],
|
|
135
|
+
"slots": [],
|
|
136
|
+
"tokens": {
|
|
137
|
+
"track.height.sm": "calc(var(--font-size-xs) * 1.25)",
|
|
138
|
+
"track.height.md": "calc(var(--font-size-sm) * 1.25)",
|
|
139
|
+
"track.height.lg": "calc(var(--font-size-body) * 1.25)",
|
|
140
|
+
"track.width": "calc(track-height * 2)",
|
|
141
|
+
"track.bg.off": "--color-surface-variant",
|
|
142
|
+
"track.bg.on": "--color-primary",
|
|
143
|
+
"track.bg.on.hover": "--color-primary-hover",
|
|
144
|
+
"track.bg.error": "--color-danger",
|
|
145
|
+
"track.bg.success": "--color-success",
|
|
146
|
+
"track.border.default": "border(control) for width/style with border-color overridden to color-mix(in oklch, --color-border 80%, --color-text) — strengthened off-state contrast for ≥3:1 in dark mode",
|
|
147
|
+
"track.border.hover": "--color-primary",
|
|
148
|
+
"track.border.error": "--color-danger",
|
|
149
|
+
"track.border.success": "--color-success",
|
|
150
|
+
"track.radius": "--radius-pill",
|
|
151
|
+
"thumb.bg": "--color-on-primary",
|
|
152
|
+
"thumb.size": "calc(track-height - --_cmp-border-width * 2 - --border-width-hairline * 2)",
|
|
153
|
+
"thumb.radius": "50%",
|
|
154
|
+
"thumb.shadow": "--shadow-sm (unchecked), --shadow-md (checked/hover) — depth separation, no ring",
|
|
155
|
+
"label.color": "--color-text",
|
|
156
|
+
"label.color.error": "--color-danger",
|
|
157
|
+
"focus.ring": "ring() with --ring-offset: 2px",
|
|
158
|
+
"disabled.opacity": "--state-disabled-opacity",
|
|
159
|
+
"required.indicator": "--color-danger asterisk",
|
|
160
|
+
"shake.animation": "ui-form-shake",
|
|
161
|
+
"touch-target": "a11y.touch-target-pseudo (--control-min-touch)",
|
|
162
|
+
"spinner.color": "--_cmp-spinner-color → --color-primary (default), --color-on-primary (checked), --color-danger (error), --color-success (success)"
|
|
163
|
+
},
|
|
164
|
+
"spacing": {
|
|
165
|
+
"internal": {
|
|
166
|
+
"track-to-label": { "relationship": "lovers", "token": "xs" }
|
|
167
|
+
},
|
|
168
|
+
"external": {
|
|
169
|
+
"wrapper-to-helper": { "relationship": "lovers", "token": "xs" },
|
|
170
|
+
"wrapper-to-error": { "relationship": "lovers", "token": "xs" }
|
|
171
|
+
}
|
|
172
|
+
},
|
|
173
|
+
"constraints": [
|
|
174
|
+
"Never use raw hex colors — use design system tokens",
|
|
175
|
+
"Use logical CSS properties only",
|
|
176
|
+
"All transitions wrapped in @include a11y.motion-safe",
|
|
177
|
+
"Must handle forced-colors mode — Highlight for checked track, GrayText for disabled",
|
|
178
|
+
"No validation logic — error/success props are visual only",
|
|
179
|
+
"Label prop is required",
|
|
180
|
+
"Native disabled (not aria-disabled)",
|
|
181
|
+
"Error takes precedence over success visually",
|
|
182
|
+
"Error shake skips initial render (firstRun guard)",
|
|
183
|
+
"Readonly is custom — native checkboxes ignore the readonly attribute. Toggling is blocked via click preventDefault, Space keydown preventDefault, and a change-event rollback",
|
|
184
|
+
"Native input has role='switch' — required for correct AT announcement",
|
|
185
|
+
"aria-checked must be synced to checked state (required by role='switch')",
|
|
186
|
+
"Track + thumb are purely decorative — aria-hidden on track",
|
|
187
|
+
"Thumb slides via inset-inline-start (logical property for RTL)",
|
|
188
|
+
"Fieldset[disabled] cascade — when disabled via a parent <fieldset disabled>, hover/active/pressed styles are suppressed via :not(:has(.ui-toggle-input:disabled)) guards on hover and active selectors; desaturation + cursor applied via a dedicated cascade rule",
|
|
189
|
+
"ToggleProps extends FormControlBaseProps"
|
|
190
|
+
],
|
|
191
|
+
"a11y": [
|
|
192
|
+
"Native <input type='checkbox' role='switch'> — keyboard Space toggles",
|
|
193
|
+
"aria-checked synced to checked state (required by role='switch')",
|
|
194
|
+
"Wrapper is a <label> — clicking anywhere toggles the input",
|
|
195
|
+
"aria-invalid='true' when error prop is truthy",
|
|
196
|
+
"aria-describedby dynamically updated for helper/error",
|
|
197
|
+
"Error message has role='alert'",
|
|
198
|
+
"aria-required='true' when required",
|
|
199
|
+
"aria-readonly='true' when readonly",
|
|
200
|
+
"aria-busy='true' when loading",
|
|
201
|
+
"Auto-generated id enables FormField association",
|
|
202
|
+
"Focus ring on the visible track via :has(:focus-visible)",
|
|
203
|
+
"Forced-colors: Highlight for checked track, HighlightText for checked thumb, GrayText for disabled",
|
|
204
|
+
"Track has aria-hidden='true' (decorative — input is the real control)",
|
|
205
|
+
"Error shake respects prefers-reduced-motion",
|
|
206
|
+
"44px minimum touch target via touch-target-pseudo mixin (invisible hit area on wrapper)"
|
|
207
|
+
],
|
|
208
|
+
"ai": {
|
|
209
|
+
"synonyms": [
|
|
210
|
+
"switch",
|
|
211
|
+
"on/off",
|
|
212
|
+
"toggle switch",
|
|
213
|
+
"toggle button",
|
|
214
|
+
"boolean switch",
|
|
215
|
+
"flip switch"
|
|
216
|
+
],
|
|
217
|
+
"avoid": [
|
|
218
|
+
"div with role='switch' — use the native input via <Toggle>",
|
|
219
|
+
"raw color values for track / thumb — use design tokens",
|
|
220
|
+
"validation inside the component — belongs in Form/DynamicForm",
|
|
221
|
+
"Toggle without a label prop",
|
|
222
|
+
"Checkbox when you mean on/off — use Toggle for binary settings"
|
|
223
|
+
],
|
|
224
|
+
"patterns": [
|
|
225
|
+
"Basic: <Toggle label=\"'Dark mode'\" />",
|
|
226
|
+
"Controlled: <Toggle label=\"'Notifications'\" checked=\"isEnabled\" onChange=\"toggle\" />",
|
|
227
|
+
"Required: <Toggle label=\"'Accept tracking'\" required=\"true\" />",
|
|
228
|
+
"Helper text: <Toggle label=\"'Auto-save'\" helperText=\"'Saves every 30 seconds'\" />",
|
|
229
|
+
"Error: <Toggle label=\"'Enable feature'\" error=\"hasError\" errorMessage=\"'Feature unavailable'\" />",
|
|
230
|
+
"Disabled: <Toggle label=\"'Premium feature'\" disabled=\"true\" />",
|
|
231
|
+
"Loading: <Toggle label=\"'Syncing...'\" loading=\"isSyncing\" checked=\"isEnabled\" />"
|
|
232
|
+
]
|
|
233
|
+
},
|
|
234
|
+
"examples": [
|
|
235
|
+
{
|
|
236
|
+
"id": "basic",
|
|
237
|
+
"title": "Basic toggle",
|
|
238
|
+
"pithy": "<Toggle label=\"'Dark mode'\" />",
|
|
239
|
+
"assertions": [
|
|
240
|
+
"renders <input type='checkbox' role='switch'>",
|
|
241
|
+
"label is visible",
|
|
242
|
+
"aria-checked='false'",
|
|
243
|
+
"no axe violations"
|
|
244
|
+
]
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
"id": "checked",
|
|
248
|
+
"title": "Pre-checked toggle",
|
|
249
|
+
"pithy": "<Toggle label=\"'Notifications'\" checked=\"true\" />",
|
|
250
|
+
"assertions": [
|
|
251
|
+
"input.checked === true",
|
|
252
|
+
"data-checked on wrapper",
|
|
253
|
+
"aria-checked='true'"
|
|
254
|
+
]
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
"id": "disabled",
|
|
258
|
+
"title": "Disabled toggle",
|
|
259
|
+
"pithy": "<Toggle label=\"'Locked'\" disabled=\"true\" />",
|
|
260
|
+
"assertions": ["input.disabled === true", "data-disabled on wrapper"]
|
|
261
|
+
},
|
|
262
|
+
{
|
|
263
|
+
"id": "readonly",
|
|
264
|
+
"title": "Readonly toggle",
|
|
265
|
+
"pithy": "<Toggle label=\"'Auto-set'\" readonly=\"true\" checked=\"true\" />",
|
|
266
|
+
"assertions": [
|
|
267
|
+
"click does not toggle",
|
|
268
|
+
"Space does not toggle",
|
|
269
|
+
"remains focusable"
|
|
270
|
+
]
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
"id": "required",
|
|
274
|
+
"title": "Required toggle",
|
|
275
|
+
"pithy": "<Toggle label=\"'I agree'\" required=\"true\" />",
|
|
276
|
+
"assertions": ["aria-required on input", "asterisk visible on label"]
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
"id": "error",
|
|
280
|
+
"title": "Error with shake",
|
|
281
|
+
"pithy": "<Toggle label=\"'Enable'\" error=\"hasError\" errorMessage=\"'Unavailable'\" />",
|
|
282
|
+
"assertions": [
|
|
283
|
+
"aria-invalid on input",
|
|
284
|
+
"shake animation on transition",
|
|
285
|
+
"error message shown"
|
|
286
|
+
]
|
|
287
|
+
},
|
|
288
|
+
{
|
|
289
|
+
"id": "success",
|
|
290
|
+
"title": "Success state",
|
|
291
|
+
"pithy": "<Toggle label=\"'Verified'\" success=\"true\" checked=\"true\" />",
|
|
292
|
+
"assertions": ["data-success on wrapper", "green track fill"]
|
|
293
|
+
},
|
|
294
|
+
{
|
|
295
|
+
"id": "loading",
|
|
296
|
+
"title": "Loading state",
|
|
297
|
+
"pithy": "<Toggle label=\"'Saving'\" loading=\"isSaving\" />",
|
|
298
|
+
"assertions": ["spinner visible", "aria-busy='true'", "thumb hidden"]
|
|
299
|
+
},
|
|
300
|
+
{
|
|
301
|
+
"id": "helper",
|
|
302
|
+
"title": "With helper text",
|
|
303
|
+
"pithy": "<Toggle label=\"'Auto-save'\" helperText=\"'Saves every 30 seconds'\" />",
|
|
304
|
+
"assertions": ["helper text visible", "aria-describedby set"]
|
|
305
|
+
}
|
|
306
|
+
],
|
|
307
|
+
"designGuidance": {
|
|
308
|
+
"surface": "Track uses --color-surface-variant when off, switching to --color-primary when on. Hover deepens to --color-primary-hover. Thumb is always --color-on-primary (white).",
|
|
309
|
+
"depth": "Thumb has --shadow-sm (unchecked) / --shadow-md (checked/hover) for premium depth. Focus ring via box-shadow ring() with 2px offset on the track.",
|
|
310
|
+
"borders": "Stable border width on the track — only color changes across states. Pill shape via border-radius: 999px.",
|
|
311
|
+
"interactivity": "Hover grows thumb from border-thin inset to a flush edge-aligned position (filling the track height), and lifts shadow to --shadow-md (non-color size feedback for WCAG accessibility). Active applies pressed state-background + iOS-style thumb stretch (~30% wider) toward direction of travel (right when unchecking→checking, left when checking→unchecking). Focus shows ring on the track. Error shakes on transition. Thumb slides smoothly via inset-inline-start transition with springy easing (RTL-aware). Loading overlays spinner inside the track, hiding the thumb.",
|
|
312
|
+
"bestPractices": "Use Toggle for binary settings (on/off). Use Checkbox for opt-in/agreement scenarios. Always provide a label. Use disabled when the setting cannot be changed; use readonly when the value is meaningful but locked."
|
|
313
|
+
}
|
|
314
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
{
|
|
2
|
+
"kind": "component",
|
|
3
|
+
"id": "ui.grid-item",
|
|
4
|
+
"name": "GridItem",
|
|
5
|
+
"displayName": "Grid Item",
|
|
6
|
+
"version": "0.1.0",
|
|
7
|
+
"level": "atom",
|
|
8
|
+
"domain": "layout",
|
|
9
|
+
"studioReady": false,
|
|
10
|
+
"bidi": true,
|
|
11
|
+
"description": "Grid child component for structured placement within a Grid. Maps props to utility classes for column/row spanning and positioning.",
|
|
12
|
+
"props": [
|
|
13
|
+
{
|
|
14
|
+
"name": "span",
|
|
15
|
+
"label": "Span",
|
|
16
|
+
"editor": { "tab": "layout", "type": "string" },
|
|
17
|
+
"type": "number | 'full'",
|
|
18
|
+
"description": "Column span (1-12 or 'full') — maps to u-col-span-*"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"name": "start",
|
|
22
|
+
"label": "Column start",
|
|
23
|
+
"editor": { "tab": "layout" },
|
|
24
|
+
"type": "number",
|
|
25
|
+
"description": "Column start line (1-13) — maps to u-col-start-*"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"name": "end",
|
|
29
|
+
"label": "Column end",
|
|
30
|
+
"editor": { "tab": "layout" },
|
|
31
|
+
"type": "number",
|
|
32
|
+
"description": "Column end line (1-13) — maps to u-col-end-*"
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"name": "rowSpan",
|
|
36
|
+
"label": "Row span",
|
|
37
|
+
"editor": { "tab": "layout" },
|
|
38
|
+
"type": "number",
|
|
39
|
+
"description": "Row span (1-6) — maps to u-row-span-*"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"name": "rowStart",
|
|
43
|
+
"label": "Row start",
|
|
44
|
+
"editor": { "tab": "layout" },
|
|
45
|
+
"type": "number",
|
|
46
|
+
"description": "Row start line (1-7) — maps to u-row-start-*"
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"name": "rowEnd",
|
|
50
|
+
"label": "Row end",
|
|
51
|
+
"editor": { "tab": "layout" },
|
|
52
|
+
"type": "number",
|
|
53
|
+
"description": "Row end line (1-7) — maps to u-row-end-*"
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"name": "placeSelf",
|
|
57
|
+
"label": "Place self",
|
|
58
|
+
"editor": { "tab": "layout" },
|
|
59
|
+
"type": "enum",
|
|
60
|
+
"enum": ["start", "center", "end", "stretch"],
|
|
61
|
+
"description": "Place self alignment — maps to u-place-self-*"
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"name": "as",
|
|
65
|
+
"label": "Element",
|
|
66
|
+
"editor": { "tab": "settings" },
|
|
67
|
+
"type": "enum",
|
|
68
|
+
"enum": ["div", "section", "article", "aside", "li"],
|
|
69
|
+
"default": "div",
|
|
70
|
+
"description": "HTML tag to render"
|
|
71
|
+
}
|
|
72
|
+
],
|
|
73
|
+
"events": [],
|
|
74
|
+
"slots": [{ "name": "default", "displayName": "Content" }],
|
|
75
|
+
"tokens": {
|
|
76
|
+
"span": "u-col-span-{n} (1-12, full)",
|
|
77
|
+
"position": "u-col-start-{n}, u-col-end-{n}, u-row-start-{n}, u-row-end-{n}"
|
|
78
|
+
},
|
|
79
|
+
"spacing": {
|
|
80
|
+
"internal": "No internal spacing — controlled by parent Grid gap"
|
|
81
|
+
},
|
|
82
|
+
"constraints": [
|
|
83
|
+
"Must be a direct child of <Grid>",
|
|
84
|
+
"Column span clamped to 1-12",
|
|
85
|
+
"Column start/end clamped to 1-13",
|
|
86
|
+
"Row span clamped to 1-6",
|
|
87
|
+
"Row start/end clamped to 1-7",
|
|
88
|
+
"Use logical properties only (handled automatically via utility classes)"
|
|
89
|
+
],
|
|
90
|
+
"a11y": [
|
|
91
|
+
"Uses semantic HTML via as prop — use <li> when parent Grid renders as <ul>/<ol>",
|
|
92
|
+
"No ARIA attributes needed — placement is presentational"
|
|
93
|
+
],
|
|
94
|
+
"ai": {
|
|
95
|
+
"synonyms": ["grid cell", "grid child", "column span", "grid placement"],
|
|
96
|
+
"avoid": [
|
|
97
|
+
"manual grid-column CSS — use span/start/end props",
|
|
98
|
+
"GridItem outside of Grid — it has no effect without a grid parent"
|
|
99
|
+
],
|
|
100
|
+
"patterns": [
|
|
101
|
+
"Spanning 2 columns: <GridItem span=\"2\"><div>Wide</div></GridItem>",
|
|
102
|
+
"Full-width row: <GridItem span=\"'full'\"><div>Banner</div></GridItem>",
|
|
103
|
+
"Positioned item: <GridItem start=\"2\" end=\"4\"><div>Middle</div></GridItem>"
|
|
104
|
+
]
|
|
105
|
+
},
|
|
106
|
+
"examples": [
|
|
107
|
+
{
|
|
108
|
+
"id": "span-2",
|
|
109
|
+
"title": "Item spanning 2 columns",
|
|
110
|
+
"pithy": "<Grid columns=\"3\"><GridItem span=\"2\"><div>Wide</div></GridItem><div>Normal</div></Grid>",
|
|
111
|
+
"assertions": ["has u-col-span-2 class"]
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
"id": "full-width",
|
|
115
|
+
"title": "Full-width item",
|
|
116
|
+
"pithy": "<Grid columns=\"3\"><GridItem span=\"'full'\"><div>Banner</div></GridItem></Grid>",
|
|
117
|
+
"assertions": ["has u-col-span-full class"]
|
|
118
|
+
}
|
|
119
|
+
]
|
|
120
|
+
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
{
|
|
2
|
+
"kind": "component",
|
|
3
|
+
"id": "ui.grid",
|
|
4
|
+
"name": "Grid",
|
|
5
|
+
"displayName": "Grid",
|
|
6
|
+
"version": "0.1.0",
|
|
7
|
+
"level": "atom",
|
|
8
|
+
"domain": "layout",
|
|
9
|
+
"bidi": true,
|
|
10
|
+
"description": "CSS grid layout atom with simple column counts, responsive breakpoints via container queries, and intrinsic auto-fit/fill patterns. Mobile-first: defaults to 1 column.",
|
|
11
|
+
"props": [
|
|
12
|
+
{
|
|
13
|
+
"name": "columns",
|
|
14
|
+
"label": "Columns",
|
|
15
|
+
"editor": { "tab": "layout", "type": "string" },
|
|
16
|
+
"type": "number | ResponsiveColumns | 'auto-fit' | 'auto-fill'",
|
|
17
|
+
"default": 1,
|
|
18
|
+
"description": "Column configuration — number (1-12), responsive object ({ base, sm, md, lg, xl }), or intrinsic auto-fit/auto-fill"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"name": "rows",
|
|
22
|
+
"label": "Rows",
|
|
23
|
+
"editor": { "tab": "layout" },
|
|
24
|
+
"type": "number",
|
|
25
|
+
"description": "Number of rows (1-6, optional)"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"name": "gap",
|
|
29
|
+
"label": "Gap",
|
|
30
|
+
"editor": { "tab": "layout", "type": "token-space" },
|
|
31
|
+
"type": "enum",
|
|
32
|
+
"enum": ["0", "xs", "sm", "md", "lg", "xl"],
|
|
33
|
+
"default": "md",
|
|
34
|
+
"description": "Gap between children — maps to u-gap-* utilities"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"name": "rowGap",
|
|
38
|
+
"label": "Row gap",
|
|
39
|
+
"editor": { "tab": "layout", "type": "token-space" },
|
|
40
|
+
"type": "enum",
|
|
41
|
+
"enum": ["0", "xs", "sm", "md", "lg", "xl"],
|
|
42
|
+
"description": "Override gap for rows only — maps to u-row-gap-*"
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"name": "colGap",
|
|
46
|
+
"label": "Column gap",
|
|
47
|
+
"editor": { "tab": "layout", "type": "token-space" },
|
|
48
|
+
"type": "enum",
|
|
49
|
+
"enum": ["0", "xs", "sm", "md", "lg", "xl"],
|
|
50
|
+
"description": "Override gap for columns only — maps to u-col-gap-*"
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"name": "align",
|
|
54
|
+
"label": "Align",
|
|
55
|
+
"editor": { "tab": "layout" },
|
|
56
|
+
"type": "enum",
|
|
57
|
+
"enum": ["start", "center", "end", "stretch", "baseline"],
|
|
58
|
+
"description": "Cross-axis alignment — maps to u-items-* utilities"
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"name": "justify",
|
|
62
|
+
"label": "Justify",
|
|
63
|
+
"editor": { "tab": "layout" },
|
|
64
|
+
"type": "enum",
|
|
65
|
+
"enum": ["start", "end", "center", "between", "around", "evenly"],
|
|
66
|
+
"description": "Main-axis justification — maps to u-justify-* utilities"
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"name": "minColumnWidth",
|
|
70
|
+
"label": "Min column width",
|
|
71
|
+
"editor": { "tab": "layout" },
|
|
72
|
+
"type": "string",
|
|
73
|
+
"description": "CSS value for auto-fit/fill min column width, e.g. '250px', '15rem'"
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"name": "as",
|
|
77
|
+
"label": "Element",
|
|
78
|
+
"editor": { "tab": "settings" },
|
|
79
|
+
"type": "enum",
|
|
80
|
+
"enum": ["div", "section", "article", "aside", "ul", "ol"],
|
|
81
|
+
"default": "div",
|
|
82
|
+
"description": "HTML tag to render"
|
|
83
|
+
}
|
|
84
|
+
],
|
|
85
|
+
"events": [],
|
|
86
|
+
"slots": [{ "name": "default", "displayName": "Content" }],
|
|
87
|
+
"tokens": {
|
|
88
|
+
"gap": "--space-{gap} (via u-gap-*)",
|
|
89
|
+
"columns": "u-grid-cols-{n} (1-12)",
|
|
90
|
+
"auto-min": "--grid-auto-min (CSS custom property for auto-fit/fill)"
|
|
91
|
+
},
|
|
92
|
+
"spacing": {
|
|
93
|
+
"between-cells": "--space-{gap} (friendship model — choose gap based on cell relationship)",
|
|
94
|
+
"card-grid": "--space-md (friends — cards in a grid)"
|
|
95
|
+
},
|
|
96
|
+
"constraints": [
|
|
97
|
+
"Columns clamped to 1-12 range",
|
|
98
|
+
"Rows clamped to 1-6 range",
|
|
99
|
+
"minColumnWidth applies to auto-fit/auto-fill and fluid numeric columns (columns ≥ 2 in auto-fit mode); it is ignored when rows/explicit placement force fixed tracks — fr units are not valid inside minmax()",
|
|
100
|
+
"Responsive columns use container queries — wrap in a container-type context for proper behavior",
|
|
101
|
+
"Use logical properties only (handled automatically via utility classes)"
|
|
102
|
+
],
|
|
103
|
+
"a11y": [
|
|
104
|
+
"Uses semantic HTML via as prop",
|
|
105
|
+
"Grid is presentational — no ARIA grid role needed for layout grids",
|
|
106
|
+
"Use <ul>/<ol> with as prop for list-based grids"
|
|
107
|
+
],
|
|
108
|
+
"ai": {
|
|
109
|
+
"synonyms": [
|
|
110
|
+
"grid layout",
|
|
111
|
+
"columns",
|
|
112
|
+
"card grid",
|
|
113
|
+
"responsive grid",
|
|
114
|
+
"css grid"
|
|
115
|
+
],
|
|
116
|
+
"avoid": [
|
|
117
|
+
"manual grid-template-columns — use columns prop",
|
|
118
|
+
"media queries for responsive columns — use responsive object with container queries",
|
|
119
|
+
"float-based layouts — use <Grid>"
|
|
120
|
+
],
|
|
121
|
+
"patterns": [
|
|
122
|
+
"Simple 3-column grid: <Grid columns=\"3\" gap=\"'lg'\"><div>A</div><div>B</div><div>C</div></Grid>",
|
|
123
|
+
"Responsive grid: <Grid columns=\"{ base: 1, sm: 2, lg: 3 }\" gap=\"'md'\">...</Grid>",
|
|
124
|
+
"Auto-fit cards: <Grid columns=\"'auto-fit'\" minColumnWidth=\"'250px'\" gap=\"'md'\">...</Grid>"
|
|
125
|
+
]
|
|
126
|
+
},
|
|
127
|
+
"examples": [
|
|
128
|
+
{
|
|
129
|
+
"id": "simple-grid",
|
|
130
|
+
"title": "Simple 3-column grid",
|
|
131
|
+
"pithy": "<Grid columns=\"3\" gap=\"'lg'\"><div>A</div><div>B</div><div>C</div></Grid>",
|
|
132
|
+
"assertions": [
|
|
133
|
+
"renders u-grid class",
|
|
134
|
+
"has u-grid-cols-3",
|
|
135
|
+
"has u-gap-lg"
|
|
136
|
+
]
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
"id": "responsive-grid",
|
|
140
|
+
"title": "Responsive columns",
|
|
141
|
+
"pithy": "<Grid columns=\"{ base: 1, sm: 2, lg: 3 }\"><div>A</div><div>B</div><div>C</div></Grid>",
|
|
142
|
+
"assertions": [
|
|
143
|
+
"renders container wrapper",
|
|
144
|
+
"inner grid has responsive classes"
|
|
145
|
+
]
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
"id": "auto-fit",
|
|
149
|
+
"title": "Auto-fit with min width",
|
|
150
|
+
"pithy": "<Grid columns=\"'auto-fit'\" minColumnWidth=\"'250px'\"><div>Card</div><div>Card</div></Grid>",
|
|
151
|
+
"assertions": [
|
|
152
|
+
"has u-grid-auto-fit class",
|
|
153
|
+
"--grid-auto-min set to 250px"
|
|
154
|
+
]
|
|
155
|
+
}
|
|
156
|
+
]
|
|
157
|
+
}
|