@abuzareal/contour-ui 0.6.2 → 0.6.3
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/CHANGELOG.md +4 -0
- package/COMBOBOX.md +1 -1
- package/COMPONENT-GUIDES.md +3534 -0
- package/COMPOSITION.md +1 -1
- package/CONTRIBUTING.md +4 -0
- package/DOCS.md +61 -61
- package/FORMS.md +1 -1
- package/GETTING-STARTED.md +3 -3
- package/HELPERS.md +1 -1
- package/HOOKS.md +1 -1
- package/MANUAL-QA.md +1 -1
- package/MIGRATION.md +1 -1
- package/MODELS.md +1 -1
- package/OVERLAYS.md +1 -1
- package/PROP-REFERENCE.md +4 -4
- package/PUBLIC-API.md +166 -166
- package/README.md +5 -3
- package/RECIPES.md +1 -1
- package/REFERENCE.md +55 -55
- package/STYLING.md +1 -1
- package/SUPPORT.md +1 -1
- package/THREE.md +1 -1
- package/docs/component-guides.json +2217 -0
- package/docs/prop-metadata.json +5734 -751
- package/examples/catalogue/buttons.tsx +27 -0
- package/examples/catalogue/choices.tsx +51 -0
- package/examples/catalogue/combobox.tsx +119 -0
- package/examples/catalogue/content.tsx +108 -0
- package/examples/catalogue/data-table.tsx +18 -0
- package/examples/catalogue/dialogs.tsx +20 -0
- package/examples/catalogue/feedback.tsx +24 -0
- package/examples/catalogue/field.tsx +18 -0
- package/examples/catalogue/floating.tsx +41 -0
- package/examples/catalogue/identity.tsx +35 -0
- package/examples/catalogue/metadata.tsx +17 -0
- package/examples/catalogue/motion.tsx +47 -0
- package/examples/catalogue/navigation.tsx +43 -0
- package/examples/catalogue/scene-boundary.tsx +37 -0
- package/examples/catalogue/text-inputs.tsx +60 -0
- package/examples/catalogue/theme-copy.tsx +32 -0
- package/examples/catalogue/toasts.tsx +21 -0
- package/examples/reproduction/package.json +1 -1
- package/examples/starters/next/package.json +1 -1
- package/examples/starters/vite/package.json +1 -1
- package/package.json +5 -2
|
@@ -0,0 +1,2217 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"scope": "Authored contracts for existing core components; optional scene exports retain THREE.md. No new UI capability or accessibility certification.",
|
|
4
|
+
"components": [
|
|
5
|
+
{
|
|
6
|
+
"slug": "alert",
|
|
7
|
+
"name": "Alert",
|
|
8
|
+
"family": "feedback",
|
|
9
|
+
"summary": "A status or urgent alert with tone, title, optional action and dismiss request.",
|
|
10
|
+
"props": [
|
|
11
|
+
[
|
|
12
|
+
"title / children",
|
|
13
|
+
"string / ReactNode",
|
|
14
|
+
"Title required; body omitted",
|
|
15
|
+
"Explain the actual outcome and next step."
|
|
16
|
+
],
|
|
17
|
+
[
|
|
18
|
+
"tone / layout",
|
|
19
|
+
"AlertTone / inline | banner",
|
|
20
|
+
"neutral / inline",
|
|
21
|
+
"Tone also determines alert versus status semantics."
|
|
22
|
+
],
|
|
23
|
+
[
|
|
24
|
+
"action",
|
|
25
|
+
"ReactNode",
|
|
26
|
+
"Omitted",
|
|
27
|
+
"Use a separately labelled native action."
|
|
28
|
+
],
|
|
29
|
+
[
|
|
30
|
+
"onDismiss / dismissLabel",
|
|
31
|
+
"() => void / string",
|
|
32
|
+
"Omitted / Dismiss",
|
|
33
|
+
"Parent removes it; translate the accessible dismiss label."
|
|
34
|
+
]
|
|
35
|
+
],
|
|
36
|
+
"keyboard": "Message content is not a tab stop. Native action and dismiss buttons retain keyboard activation; the application owns focus after removing a focused message.",
|
|
37
|
+
"limits": "No auto-dismiss, fetching, retry engine, native form value or external root props/ref. Repeated urgent announcements can be disruptive.",
|
|
38
|
+
"tasks": "A status or urgent alert with tone, title, optional action and dismiss request. Use for meaningful inline or banner feedback. Reserve warning/danger for urgency; use nearby field errors for invalid inputs and do not fabricate successful requests.",
|
|
39
|
+
"detail": {
|
|
40
|
+
"use": "Use for meaningful inline or banner feedback. Reserve warning/danger for urgency; use nearby field errors for invalid inputs and do not fabricate successful requests.",
|
|
41
|
+
"anatomy": "Root role is alert for warning/danger and status otherwise. Decorative tone icon, strong title, optional body/action and dismiss button form the message; banner is the same component layout.",
|
|
42
|
+
"state": "Parent owns visibility and service status. onDismiss requests removal; the component does not hide itself. tone defaults neutral and layout inline.",
|
|
43
|
+
"forms": "Not a successful form control: no name, required constraint or native reset behavior. Reset any application-owned content/request state separately.",
|
|
44
|
+
"ref": "No public native-element ref is forwarded. Keep focus on actual native interactive children rather than making the presentation wrapper focusable.",
|
|
45
|
+
"edgeCases": "Show pending, service/permission failure and retry truthfully. Long titles/actions must wrap; do not use color alone or hide persistent actionable errors only in a toast.",
|
|
46
|
+
"localization": "Translate title/body/action/dismissLabel. Direction and text length are application context; test actual live-region announcements manually.",
|
|
47
|
+
"reference": "props",
|
|
48
|
+
"styling": "Use .contour-alert and tone/layout hooks with released semantic color/line/spacing tokens. Preserve native structure, visible labels and owned state/ARIA; visual customization does not change the interaction contract."
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"slug": "avatar",
|
|
53
|
+
"name": "Avatar",
|
|
54
|
+
"family": "metadata",
|
|
55
|
+
"summary": "A name-based image/initials display with an optional labelled presence dot.",
|
|
56
|
+
"props": [
|
|
57
|
+
[
|
|
58
|
+
"name",
|
|
59
|
+
"string",
|
|
60
|
+
"Required",
|
|
61
|
+
"Nonempty identity name; image alt/initials accessible label."
|
|
62
|
+
],
|
|
63
|
+
[
|
|
64
|
+
"initials / src",
|
|
65
|
+
"string",
|
|
66
|
+
"Derived initials / omitted",
|
|
67
|
+
"No automatic failed-image-to-initials switch."
|
|
68
|
+
],
|
|
69
|
+
["size", "sm | md | lg | xl", "md", "Visual size only."],
|
|
70
|
+
[
|
|
71
|
+
"status / statusLabel",
|
|
72
|
+
"online | away / string",
|
|
73
|
+
"Omitted / Online or Away",
|
|
74
|
+
"Status is app data; translate/customize the dot description."
|
|
75
|
+
]
|
|
76
|
+
],
|
|
77
|
+
"keyboard": "Not a keyboard control and does not add a tab stop. Interactive children retain their native behavior; do not use this display as a substitute for a button or link.",
|
|
78
|
+
"limits": "No upload/presence service, fallback on image-error, arbitrary native image props or forwarded ref. Initial derivation is not locale/grapheme-aware.",
|
|
79
|
+
"tasks": "A name-based image/initials display with an optional labelled presence dot. Use for identity context. Do not use initials or a presence color as the sole explanation of a person/action; put actionable behavior on a separate native control.",
|
|
80
|
+
"detail": {
|
|
81
|
+
"use": "Use for identity context. Do not use initials or a presence color as the sole explanation of a person/action; put actionable behavior on a separate native control.",
|
|
82
|
+
"anatomy": "Wrapper holds an img with alt=name or a role=img initials span; optional presence dot has its own accessible label.",
|
|
83
|
+
"state": "src chooses image versus initials. initials overrides a basic first-two-space-separated-name-parts derivation. size defaults md; status is caller-supplied online/away.",
|
|
84
|
+
"forms": "Not a successful form control: no name, required constraint or native reset behavior. Reset any application-owned content/request state separately.",
|
|
85
|
+
"ref": "No public native-element ref is forwarded. Keep focus on actual native interactive children rather than making the presentation wrapper focusable.",
|
|
86
|
+
"edgeCases": "If an image fails, native alt text remains; the app must remove/change src to select initials. Test empty/long names and unavailable status without inventing live presence.",
|
|
87
|
+
"localization": "Supply explicit initials for scripts/emoji/name order that basic splitting cannot handle. Translate statusLabel and keep full accessible names meaningful.",
|
|
88
|
+
"reference": "props",
|
|
89
|
+
"styling": "Use .contour-avatar, size and presence hooks with released semantic color/line/spacing tokens. Preserve native structure, visible labels and owned state/ARIA; visual customization does not change the interaction contract."
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"slug": "badge",
|
|
94
|
+
"name": "Badge",
|
|
95
|
+
"family": "metadata",
|
|
96
|
+
"summary": "A compact textual status label with optional dot or icon.",
|
|
97
|
+
"props": [
|
|
98
|
+
["children", "ReactNode", "Required", "Include readable status text."],
|
|
99
|
+
[
|
|
100
|
+
"tone",
|
|
101
|
+
"BadgeTone",
|
|
102
|
+
"accent",
|
|
103
|
+
"accent/neutral/invert/success/info/warning/danger."
|
|
104
|
+
],
|
|
105
|
+
[
|
|
106
|
+
"dot / icon",
|
|
107
|
+
"boolean / ReactNode",
|
|
108
|
+
"false / omitted",
|
|
109
|
+
"A dot is decorative; caller icon semantics remain caller-owned."
|
|
110
|
+
]
|
|
111
|
+
],
|
|
112
|
+
"keyboard": "Not a keyboard control and does not add a tab stop. Interactive children retain their native behavior; do not use this display as a substitute for a button or link.",
|
|
113
|
+
"limits": "No click/dismiss/selection behavior, root attributes/ref or automatic announcements. Icons and tone must not be the sole status explanation.",
|
|
114
|
+
"tasks": "A compact textual status label with optional dot or icon. Use for short metadata/status text. Use an action button for interaction and Alert for a meaningful announced service message; color alone is insufficient.",
|
|
115
|
+
"detail": {
|
|
116
|
+
"use": "Use for short metadata/status text. Use an action button for interaction and Alert for a meaningful announced service message; color alone is insufficient.",
|
|
117
|
+
"anatomy": "Inline span with tone class, optional decorative dot, caller icon and text children. It has no automatic live-region role.",
|
|
118
|
+
"state": "Pure display; tone defaults accent, dot false. Parent updates the actual status.",
|
|
119
|
+
"forms": "Not a successful form control: no name, required constraint or native reset behavior. Reset any application-owned content/request state separately.",
|
|
120
|
+
"ref": "No public native-element ref is forwarded. Keep focus on actual native interactive children rather than making the presentation wrapper focusable.",
|
|
121
|
+
"edgeCases": "Check long text and contrast in every used tone, both themes and forced colors; business failure/loading remains parent-owned.",
|
|
122
|
+
"localization": "Translate visible labels and optional icon descriptions where needed. Stable data status values should not depend on translated labels.",
|
|
123
|
+
"reference": "props",
|
|
124
|
+
"styling": "Use .contour-badge and tone/dot hooks with released semantic color/line/spacing tokens. Preserve native structure, visible labels and owned state/ARIA; visual customization does not change the interaction contract."
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
"slug": "brand-mark",
|
|
129
|
+
"name": "BrandMark",
|
|
130
|
+
"family": "identity",
|
|
131
|
+
"summary": "A fixed legacy aa. monogram rendered as a safe anchor.",
|
|
132
|
+
"props": [
|
|
133
|
+
[
|
|
134
|
+
"label",
|
|
135
|
+
"string",
|
|
136
|
+
"Required",
|
|
137
|
+
"Accessible name explains the actual legacy brand/link."
|
|
138
|
+
],
|
|
139
|
+
[
|
|
140
|
+
"href",
|
|
141
|
+
"string",
|
|
142
|
+
"#hero",
|
|
143
|
+
"Supply a real destination/anchor for your page."
|
|
144
|
+
],
|
|
145
|
+
[
|
|
146
|
+
"onClick",
|
|
147
|
+
"() => void",
|
|
148
|
+
"Omitted",
|
|
149
|
+
"No MouseEvent parameter/veto API is declared."
|
|
150
|
+
]
|
|
151
|
+
],
|
|
152
|
+
"keyboard": "Native anchor Enter/modified-click behavior applies when href is valid. Keep the accessible name and actual target meaningful.",
|
|
153
|
+
"limits": "Fixed aa. content, not a logo slot. No target/rel/native-props forwarding, configurable mark or ref; unsafe href is rejected.",
|
|
154
|
+
"tasks": "A fixed legacy aa. monogram rendered as a safe anchor. Use only when that existing mark is appropriate. It is not a customizable brand/logo system or the catalogue C mark; use your own labelled native logo link for another identity.",
|
|
155
|
+
"detail": {
|
|
156
|
+
"use": "Use only when that existing mark is appropriate. It is not a customizable brand/logo system or the catalogue C mark; use your own labelled native logo link for another identity.",
|
|
157
|
+
"anatomy": "Native anchor displays literal aa plus a dot, with caller aria-label, safe href and onClick callback.",
|
|
158
|
+
"state": "No state; href defaults#hero. The target anchor and application navigation remain caller-owned.",
|
|
159
|
+
"forms": "Native navigation link, not a form value/submit/reset control.",
|
|
160
|
+
"ref": "No public native-element ref is forwarded. Keep focus on actual native interactive children rather than making the presentation wrapper focusable.",
|
|
161
|
+
"edgeCases": "Verify the default#hero actually exists or supply another destination. No loading/error/selection behavior is added.",
|
|
162
|
+
"localization": "Translate label where appropriate; literal legacy lettering does not localize or change from props.",
|
|
163
|
+
"reference": "props",
|
|
164
|
+
"styling": "Use .contour-brand with released semantic color/line/spacing tokens. Preserve native structure, visible labels and owned state/ARIA; visual customization does not change the interaction contract."
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
"slug": "breadcrumbs",
|
|
169
|
+
"name": "Breadcrumbs",
|
|
170
|
+
"family": "navigation",
|
|
171
|
+
"summary": "A native breadcrumb navigation list with a current-page item.",
|
|
172
|
+
"props": [
|
|
173
|
+
[
|
|
174
|
+
"items",
|
|
175
|
+
"{label:string;href?:string}[]",
|
|
176
|
+
"Required",
|
|
177
|
+
"Supply hierarchy in reading order; last item is current."
|
|
178
|
+
],
|
|
179
|
+
["label", "string", "Breadcrumb", "Translate the navigation name."]
|
|
180
|
+
],
|
|
181
|
+
"keyboard": "Only actual anchors enter Tab order and retain native modified-click behavior. The current page is text rather than an unnecessary link.",
|
|
182
|
+
"limits": "No router element slot, generated destinations, native root props/ref or automatic label deduplication. safeHref does not verify a destination exists.",
|
|
183
|
+
"tasks": "A native breadcrumb navigation list with a current-page item. Use for hierarchy context. Use a page heading and primary navigation separately; this is not a client router or application history manager.",
|
|
184
|
+
"detail": {
|
|
185
|
+
"use": "Use for hierarchy context. Use a page heading and primary navigation separately; this is not a client router or application history manager.",
|
|
186
|
+
"anatomy": "Named nav contains an ordered list. The final item is a span with aria-current=page; earlier items with href use safe native anchors.",
|
|
187
|
+
"state": "Pure caller-owned items; item labels serve as React keys and should be unique in a trail. Missing href means noninteractive text.",
|
|
188
|
+
"forms": "Not a successful form control: no name, required constraint or native reset behavior. Reset any application-owned content/request state separately.",
|
|
189
|
+
"ref": "No public native-element ref is forwarded. Keep focus on actual native interactive children rather than making the presentation wrapper focusable.",
|
|
190
|
+
"edgeCases": "Check empty/single-item and lengthy trails, both themes and narrow wrapping. Failed data loading belongs outside this static navigation.",
|
|
191
|
+
"localization": "Translate labels and navigation name; preserve hierarchy order with surrounding dir rather than reversing the array for appearance.",
|
|
192
|
+
"reference": "props",
|
|
193
|
+
"styling": "Use .contour-breadcrumbs and [aria-current=page] with released semantic color/line/spacing tokens. Preserve native structure, visible labels and owned state/ARIA; visual customization does not change the interaction contract."
|
|
194
|
+
}
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
"slug": "button",
|
|
198
|
+
"name": "Button",
|
|
199
|
+
"family": "buttons",
|
|
200
|
+
"summary": "A native action button with loading, icon slots and explicit native refs.",
|
|
201
|
+
"props": [
|
|
202
|
+
[
|
|
203
|
+
"variant",
|
|
204
|
+
"primary | accent | secondary | ghost | danger",
|
|
205
|
+
"primary",
|
|
206
|
+
"Visual emphasis; navigation remains an anchor."
|
|
207
|
+
],
|
|
208
|
+
[
|
|
209
|
+
"size",
|
|
210
|
+
"sm | md | lg",
|
|
211
|
+
"md",
|
|
212
|
+
"Choose size while retaining useful targets."
|
|
213
|
+
],
|
|
214
|
+
[
|
|
215
|
+
"loading / loadingLabel",
|
|
216
|
+
"boolean / string",
|
|
217
|
+
"false / Loading",
|
|
218
|
+
"Loading disables activation and exposes a named spinner."
|
|
219
|
+
],
|
|
220
|
+
[
|
|
221
|
+
"leadingIcon / icon",
|
|
222
|
+
"ReactNode",
|
|
223
|
+
"Omitted",
|
|
224
|
+
"Before/after the label; decorative icons should be hidden from AT."
|
|
225
|
+
],
|
|
226
|
+
[
|
|
227
|
+
"type / disabled / ref",
|
|
228
|
+
"Native button props and ref",
|
|
229
|
+
"type=button",
|
|
230
|
+
"Use type=submit deliberately; ref targets HTMLButtonElement."
|
|
231
|
+
]
|
|
232
|
+
],
|
|
233
|
+
"keyboard": "Native Tab focus and Enter/Space activation. Disabled or loading buttons cannot activate.",
|
|
234
|
+
"limits": "No polymorphic as prop or routing integration. Use a styled native anchor or the pinned Next Link recipe for navigation.",
|
|
235
|
+
"tasks": "button submit loading ref icons action link",
|
|
236
|
+
"detail": {
|
|
237
|
+
"use": "Use for an application action. Use ExternalLink or a styled anchor for navigation; a button that looks like a link still has button semantics.",
|
|
238
|
+
"anatomy": "Native button contains a label span, optional leadingIcon or loading spinner, and optional trailing icon. Native attributes/handlers and the composed ref remain attached to the button.",
|
|
239
|
+
"state": "loading defaults false and disables the button along with disabled. loadingLabel defaults Loading. The component starts no request and never invents success. Variants default primary and sizes default md through buttonClassName.",
|
|
240
|
+
"forms": "Default type is button. Set submit/reset explicitly, and use native name/value/form when appropriate. The application owns save validation, pending guards and outcome messages.",
|
|
241
|
+
"ref": "Forwarded ref targets HTMLButtonElement in React 18/19. Render through React; the ref-enabled export is not an ordinary callable function.",
|
|
242
|
+
"edgeCases": "Do not put nested controls inside the label or icon slots. Check long labels and narrow rows, show a truthful pending label, and retain failure recovery beside the task.",
|
|
243
|
+
"localization": "Translate children/loadingLabel and ensure icons are decorative or separately named. Button labels are not translated by a global provider; verify RTL icon order in the composition.",
|
|
244
|
+
"reference": "composition",
|
|
245
|
+
"styling": "Use the released scoped CSS and semantic tokens inside contour-root/ThemeScope. Preserve native semantics, public part/state hooks and geometry ownership; see the component-specific anatomy and STYLING.md."
|
|
246
|
+
}
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
"slug": "card",
|
|
250
|
+
"name": "Card",
|
|
251
|
+
"family": "content",
|
|
252
|
+
"summary": "A semantic article container with optional slots and three visual tones.",
|
|
253
|
+
"props": [
|
|
254
|
+
[
|
|
255
|
+
"title / children",
|
|
256
|
+
"string / ReactNode",
|
|
257
|
+
"Title required; body omitted",
|
|
258
|
+
"Fit the fixed h3 into your hierarchy."
|
|
259
|
+
],
|
|
260
|
+
[
|
|
261
|
+
"eyebrow / footer / icon",
|
|
262
|
+
"string / ReactNode / ReactNode",
|
|
263
|
+
"Omitted",
|
|
264
|
+
"Use meaningful content and independently labelled actions."
|
|
265
|
+
],
|
|
266
|
+
[
|
|
267
|
+
"tone / interactive",
|
|
268
|
+
"surface | ink | acid / boolean",
|
|
269
|
+
"surface / false",
|
|
270
|
+
"Hover appearance does not add keyboard or navigation semantics."
|
|
271
|
+
]
|
|
272
|
+
],
|
|
273
|
+
"keyboard": "Not a keyboard control and does not add a tab stop. Interactive children retain their native behavior; do not use this display as a substitute for a button or link.",
|
|
274
|
+
"limits": "No href/onClick/root native props, selected state or forwarded ref. Do not nest conflicting controls in an artificial full-card hit area.",
|
|
275
|
+
"tasks": "A semantic article container with optional slots and three visual tones. Use to group related content. interactive adds hover styling only; compose real anchors/buttons for actions instead of making the article behave like a control.",
|
|
276
|
+
"detail": {
|
|
277
|
+
"use": "Use to group related content. interactive adds hover styling only; compose real anchors/buttons for actions instead of making the article behave like a control.",
|
|
278
|
+
"anatomy": "Article contains optional eyebrow/icon row, fixed h3 title, optional body and footer. Children/footer are content slots, not implicit links.",
|
|
279
|
+
"state": "Pure display; tone defaults surface and interactive false. No selection, expansion or request state is stored.",
|
|
280
|
+
"forms": "Not a successful form control: no name, required constraint or native reset behavior. Reset any application-owned content/request state separately.",
|
|
281
|
+
"ref": "No public native-element ref is forwarded. Keep focus on actual native interactive children rather than making the presentation wrapper focusable.",
|
|
282
|
+
"edgeCases": "Keep long body/footer/actions readable in both themes; handle loading/errors with actual content states. A lift effect is not a focus/activation contract.",
|
|
283
|
+
"localization": "Translate all authored text and preserve heading order; slots may contain localized content and native controls.",
|
|
284
|
+
"reference": "props",
|
|
285
|
+
"styling": "Use .contour-card, tone hooks and slot hooks with released semantic color/line/spacing tokens. Preserve native structure, visible labels and owned state/ARIA; visual customization does not change the interaction contract."
|
|
286
|
+
}
|
|
287
|
+
},
|
|
288
|
+
{
|
|
289
|
+
"slug": "checkbox",
|
|
290
|
+
"name": "Checkbox",
|
|
291
|
+
"family": "choices",
|
|
292
|
+
"summary": "A labelled native checkbox with optional description, error and an indeterminate appearance.",
|
|
293
|
+
"props": [
|
|
294
|
+
["label", "string", "Required", "Use a clear action or setting name."],
|
|
295
|
+
[
|
|
296
|
+
"checked / defaultChecked / onChange",
|
|
297
|
+
"Native input props",
|
|
298
|
+
"Uncontrolled when checked is omitted",
|
|
299
|
+
"Read event.currentTarget.checked. Use one state-ownership model."
|
|
300
|
+
],
|
|
301
|
+
[
|
|
302
|
+
"name / value / form",
|
|
303
|
+
"Native input props",
|
|
304
|
+
"Native defaults",
|
|
305
|
+
"Checked controls contribute to FormData. The application owns validation and submission."
|
|
306
|
+
],
|
|
307
|
+
[
|
|
308
|
+
"description / error",
|
|
309
|
+
"string",
|
|
310
|
+
"Omitted",
|
|
311
|
+
"Use error for the installed component's linked validation message."
|
|
312
|
+
],
|
|
313
|
+
[
|
|
314
|
+
"indeterminate",
|
|
315
|
+
"boolean",
|
|
316
|
+
"false",
|
|
317
|
+
"Set the mixed appearance explicitly; it does not choose child values or replace checked."
|
|
318
|
+
],
|
|
319
|
+
[
|
|
320
|
+
"disabled / required",
|
|
321
|
+
"boolean",
|
|
322
|
+
"false",
|
|
323
|
+
"Native disabled and required behavior. Disable only when the action is unavailable."
|
|
324
|
+
]
|
|
325
|
+
],
|
|
326
|
+
"keyboard": "Tab focuses the checkbox; Space toggles it. Its visible label also activates the control. A disabled checkbox is not keyboard-focusable.",
|
|
327
|
+
"limits": "Native input refs and caller id are supported. Caller aria-describedby is merged with description/error IDs. Checked named controls submit; unchecked/disabled controls are omitted. Native reset restores defaults; controlled values stay parent-owned until the application resets state. Indeterminate does not calculate mixed selection or replace checked.",
|
|
328
|
+
"tasks": "checkbox consent validation selection mixed native form",
|
|
329
|
+
"detail": {
|
|
330
|
+
"use": "Use for an independent binary choice or multi-selection. Use RadioGroup for exactly one option, or Switch for an immediately applicable setting.",
|
|
331
|
+
"anatomy": "Label wraps a native checkbox with a visual mark and text. Description/error IDs merge with caller aria-describedby. Caller id is retained.",
|
|
332
|
+
"state": "checked/onChange is controlled; defaultChecked is uncontrolled. indeterminate defaults false and does not calculate a mixed selection or replace checked.",
|
|
333
|
+
"forms": "Checked, enabled, named controls submit value (native default on). Unchecked controls are omitted. required uses native validity. Reset restores defaultChecked; a controlled owner changes its own state explicitly; the library restores the parent-controlled value after reset.",
|
|
334
|
+
"ref": "Forwarded ref targets HTMLInputElement for focus and form controllers.",
|
|
335
|
+
"edgeCases": "Disabled controls cannot activate. Keep long descriptions readable; display business errors with error and retain values on service failure. Indeterminate and disabled together still need an understandable label.",
|
|
336
|
+
"localization": "Translate the label, description and error. Native checkbox interaction follows the browser; check RTL order and long translations in the application.",
|
|
337
|
+
"reference": "forms",
|
|
338
|
+
"styling": "Use the released scoped CSS and semantic tokens inside contour-root/ThemeScope. Preserve native semantics, public part/state hooks and geometry ownership; see the component-specific anatomy and STYLING.md."
|
|
339
|
+
}
|
|
340
|
+
},
|
|
341
|
+
{
|
|
342
|
+
"slug": "combobox",
|
|
343
|
+
"name": "Combobox",
|
|
344
|
+
"family": "selection",
|
|
345
|
+
"summary": "Searchable allowed-value selection with native submission, reset and independent query state.",
|
|
346
|
+
"props": [
|
|
347
|
+
[
|
|
348
|
+
"label / options",
|
|
349
|
+
"string / readonly ComboboxOption[]",
|
|
350
|
+
"Required",
|
|
351
|
+
"Options use unique value/label records; disabled is optional."
|
|
352
|
+
],
|
|
353
|
+
[
|
|
354
|
+
"value / defaultValue / onValueChange",
|
|
355
|
+
"string | null / callback",
|
|
356
|
+
"Uncontrolled when value is omitted",
|
|
357
|
+
"The selection is separate from inputValue/onInputValueChange query state."
|
|
358
|
+
],
|
|
359
|
+
[
|
|
360
|
+
"name / form / required / disabled",
|
|
361
|
+
"Native form ownership",
|
|
362
|
+
"Optional",
|
|
363
|
+
"Submit the selected value, not arbitrary typed text."
|
|
364
|
+
],
|
|
365
|
+
[
|
|
366
|
+
"loading / searchError / onRetry",
|
|
367
|
+
"boolean / string / callback",
|
|
368
|
+
"Optional",
|
|
369
|
+
"Application-owned fetching and recovery."
|
|
370
|
+
],
|
|
371
|
+
[
|
|
372
|
+
"ref",
|
|
373
|
+
"React.Ref<HTMLInputElement>",
|
|
374
|
+
"Omitted",
|
|
375
|
+
"Focus the visible input."
|
|
376
|
+
]
|
|
377
|
+
],
|
|
378
|
+
"keyboard": "Arrow keys navigate enabled options; Enter selects. Escape dismisses the deepest open layer. Tab closes without consuming normal focus navigation. Query and selected value are separate.",
|
|
379
|
+
"limits": "Single allowed value only; no free text, multi-select or virtualized list. Remote fetching/filtering is application-owned. Manual VoiceOver/NVDA review remains pending.",
|
|
380
|
+
"tasks": "combobox searchable select async allowed value form reset project",
|
|
381
|
+
"detail": {
|
|
382
|
+
"use": "Use for searchable allowed-value selection. Use TextField for free text or SelectField when native selection is enough. Multi-select and custom values are not supported.",
|
|
383
|
+
"anatomy": "Label, visible input/trigger, hidden submitted value and labelled listbox/options. inputProps/rootProps/popupProps target parts. Portal geometry is shared with floating layers; no popup focus trap is used.",
|
|
384
|
+
"state": "Selected value, query and open state have separate controlled/default APIs. A query is not a selected value. Missing selected options retain explicit missing-value behavior; disabled options cannot be newly chosen.",
|
|
385
|
+
"forms": "name/form submit the selected allowed value. required validates selection, not typed text. Native reset restores default selection/query while controlled owners explicitly reset their own state; use the forms reference for exact semantics.",
|
|
386
|
+
"ref": "Forwarded ref targets the visible HTMLInputElement. The hidden value is not the focus target.",
|
|
387
|
+
"edgeCases": "loading/searchError/onRetry/emptyText describe application fetching; filteredOptions opts into external filtering. Debounce, abort and stale-result protection live in the async recipe. Open-state automated axe passes in 0.6.1; manual AT review remains pending.",
|
|
388
|
+
"localization": "Translate label, loadingText, emptyText, retryLabel, triggerLabel and missingValueText. Test RTL and long options; search matching and remote result ordering remain your responsibility.",
|
|
389
|
+
"reference": "selection",
|
|
390
|
+
"styling": "Use the released scoped CSS and semantic tokens inside contour-root/ThemeScope. Preserve native semantics, public part/state hooks and geometry ownership; see the component-specific anatomy and STYLING.md."
|
|
391
|
+
}
|
|
392
|
+
},
|
|
393
|
+
{
|
|
394
|
+
"slug": "count-up",
|
|
395
|
+
"name": "CountUp",
|
|
396
|
+
"family": "motion",
|
|
397
|
+
"summary": "A decorative one-time numeric count with a static accessible final value.",
|
|
398
|
+
"props": [
|
|
399
|
+
[
|
|
400
|
+
"to",
|
|
401
|
+
"number",
|
|
402
|
+
"Required",
|
|
403
|
+
"Supply a finite meaningful final value; no validation is added."
|
|
404
|
+
],
|
|
405
|
+
[
|
|
406
|
+
"duration / digits / suffix",
|
|
407
|
+
"number / number / string",
|
|
408
|
+
"1400 / 0 / empty string",
|
|
409
|
+
"Milliseconds, minimum digit padding and suffix."
|
|
410
|
+
],
|
|
411
|
+
[
|
|
412
|
+
"formatValue",
|
|
413
|
+
"(value:number)=>string",
|
|
414
|
+
"Omitted",
|
|
415
|
+
"Formats both visual and accessible values; replaces padding/suffix formatting."
|
|
416
|
+
]
|
|
417
|
+
],
|
|
418
|
+
"keyboard": "Not a keyboard control and does not add a tab stop. Interactive children retain their native behavior; do not use this display as a substitute for a button or link.",
|
|
419
|
+
"limits": "Decorative integer-rounded animation, not streaming data, locale parsing or an alert/live region. No forwarded ref/reset API; prop changes can start a new effect.",
|
|
420
|
+
"tasks": "A decorative one-time numeric count with a static accessible final value. Use only when animation adds useful emphasis. Do not present illustrative counts as live measurements or repeatedly announce each animation frame.",
|
|
421
|
+
"detail": {
|
|
422
|
+
"use": "Use only when animation adds useful emphasis. Do not present illustrative counts as live measurements or repeatedly announce each animation frame.",
|
|
423
|
+
"anatomy": "Root span contains aria-hidden animated text and a visually hidden final value. An observer activates requestAnimationFrame; cleanup disconnects/cancels.",
|
|
424
|
+
"state": "to is caller data; duration defaults to 1400 ms, digits0, suffix empty. Reduced/paused motion, nonpositive duration or missing observer goes straight to final value. Custom formatValue replaces default padding/suffix output.",
|
|
425
|
+
"forms": "Not a successful form control: no name, required constraint or native reset behavior. Reset any application-owned content/request state separately.",
|
|
426
|
+
"ref": "No public native-element ref is forwarded. Keep focus on actual native interactive children rather than making the presentation wrapper focusable.",
|
|
427
|
+
"edgeCases": "Label source/units/timestamp outside the count. Test zero/negative values, long formatted strings, missing data and reduced motion; never fabricate a known value to make animation work.",
|
|
428
|
+
"localization": "Use formatValue for localized numerals/units; default String/padStart is not locale-aware. Supply an adjacent meaningful quantity label.",
|
|
429
|
+
"reference": "hooks",
|
|
430
|
+
"styling": "Use .contour-count-up and visually-hidden final value with released semantic color/line/spacing tokens. Preserve native structure, visible labels and owned state/ARIA; visual customization does not change the interaction contract."
|
|
431
|
+
}
|
|
432
|
+
},
|
|
433
|
+
{
|
|
434
|
+
"slug": "data-table",
|
|
435
|
+
"name": "DataTable",
|
|
436
|
+
"family": "data-table",
|
|
437
|
+
"summary": "A semantic table with bounded local sorting of scalar records.",
|
|
438
|
+
"props": [
|
|
439
|
+
[
|
|
440
|
+
"caption",
|
|
441
|
+
"string",
|
|
442
|
+
"Required",
|
|
443
|
+
"Accessible caption is visually hidden by the Table composition."
|
|
444
|
+
],
|
|
445
|
+
[
|
|
446
|
+
"columns",
|
|
447
|
+
"TableColumn<Row>[]",
|
|
448
|
+
"Required",
|
|
449
|
+
"key/header plus optional align/sortable/compare/render; headers must be meaningful."
|
|
450
|
+
],
|
|
451
|
+
[
|
|
452
|
+
"rows / rowKey",
|
|
453
|
+
"Row[] / keyof Row & string",
|
|
454
|
+
"Required",
|
|
455
|
+
"Unique stable row keys; rows extend Record<string,string | number>."
|
|
456
|
+
]
|
|
457
|
+
],
|
|
458
|
+
"keyboard": "Native header buttons activate sorting with Enter/Space. The table uses semantic reading navigation, not grid arrow-key focus or cell editing.",
|
|
459
|
+
"limits": "Internal local sorting only; no controlled sorting, pagination, selection, virtualization, requests, built-in empty/error state or forwarded table ref. Object/date/nested records are outside its scalar generic contract.",
|
|
460
|
+
"tasks": "A semantic table with bounded local sorting of scalar records. Use for small local scalar datasets. Use Table plus a mature engine for controlled remote query/page/sort; neither this component nor its row count is an enterprise grid.",
|
|
461
|
+
"detail": {
|
|
462
|
+
"use": "Use for small local scalar datasets. Use Table plus a mature engine for controlled remote query/page/sort; neither this component nor its row count is an enterprise grid.",
|
|
463
|
+
"anatomy": "Table supplies a caption and scroll wrapper; native thead/tbody/tr/th/td render columns/rows. Sortable headers contain buttons and aria-sort.",
|
|
464
|
+
"state": "Rows/columns are application data; local sort starts null and toggles ascending/descending. A compare function overrides scalar comparison. Sorting copies rows instead of mutating the input.",
|
|
465
|
+
"forms": "Not a successful form control: no name, required constraint or native reset behavior. Reset any application-owned content/request state separately.",
|
|
466
|
+
"ref": "No public native-element ref is forwarded. Keep focus on actual native interactive children rather than making the presentation wrapper focusable.",
|
|
467
|
+
"edgeCases": "Own loading, empty dataset, no matches and service/permission errors outside the table. Keep stable row identity, long-cell scroll and a text/table data equivalent rather than masking errors as empty success.",
|
|
468
|
+
"localization": "Translate captions/headers/cells. Supply compare for locale-aware order; built-in scalar comparison is not a locale collation service.",
|
|
469
|
+
"reference": "recipes",
|
|
470
|
+
"styling": "Use .contour-data-table wrapper/table and native header controls with released semantic color/line/spacing tokens. Preserve native structure, visible labels and owned state/ARIA; visual customization does not change the interaction contract."
|
|
471
|
+
}
|
|
472
|
+
},
|
|
473
|
+
{
|
|
474
|
+
"slug": "depth-button",
|
|
475
|
+
"name": "DepthButton",
|
|
476
|
+
"family": "buttons",
|
|
477
|
+
"summary": "A native action button with CSS depth and a pressed face.",
|
|
478
|
+
"props": [
|
|
479
|
+
[
|
|
480
|
+
"children",
|
|
481
|
+
"ReactNode",
|
|
482
|
+
"Required",
|
|
483
|
+
"Provide an understandable accessible action name."
|
|
484
|
+
],
|
|
485
|
+
[
|
|
486
|
+
"type",
|
|
487
|
+
"Native button type",
|
|
488
|
+
"button",
|
|
489
|
+
"Opt into submit only deliberately."
|
|
490
|
+
],
|
|
491
|
+
[
|
|
492
|
+
"disabled / onClick / className",
|
|
493
|
+
"Native button props",
|
|
494
|
+
"Native defaults",
|
|
495
|
+
"Caller owns pending/error and disabled policy."
|
|
496
|
+
]
|
|
497
|
+
],
|
|
498
|
+
"keyboard": "Enter/Space activate the native button; disabled prevents interaction. Keep a visible focus indication and sufficient target size.",
|
|
499
|
+
"limits": "No Button variant/size/loading API or polymorphic navigation mode. Decorative depth must not displace or clip the focused hit target.",
|
|
500
|
+
"tasks": "A native action button with CSS depth and a pressed face. Use for an intentional prominent action, preserving the same native activation contract as a button. Use an anchor for navigation; CSS depth needs no Three.js.",
|
|
501
|
+
"detail": {
|
|
502
|
+
"use": "Use for an intentional prominent action, preserving the same native activation contract as a button. Use an anchor for navigation; CSS depth needs no Three.js.",
|
|
503
|
+
"anatomy": "Native button contains a visual face span. className appends to public root hooks; children supply the action name.",
|
|
504
|
+
"state": "No request/loading state. Native type defaults button; disabled and event handlers remain native caller props.",
|
|
505
|
+
"forms": "Native type=button avoids accidental submit; type=submit/name/value/form work when explicitly supplied. Disabled controls follow native successful-control rules.",
|
|
506
|
+
"ref": "Forwarded HTMLButtonElement, including focus access.",
|
|
507
|
+
"edgeCases": "Keep long labels readable, including translated pending/error messages nearby. Use native disabled and adjacent request feedback; no built-in loader is promised.",
|
|
508
|
+
"localization": "Translate action text. Verify RTL and long labels; geometric depth is visual rather than a directional navigation cue.",
|
|
509
|
+
"reference": "composition",
|
|
510
|
+
"styling": "Use .contour-depth-button and .contour-depth-button-face with released semantic color/line/spacing tokens. Preserve native structure, visible labels and owned state/ARIA; visual customization does not change the interaction contract."
|
|
511
|
+
}
|
|
512
|
+
},
|
|
513
|
+
{
|
|
514
|
+
"slug": "dialog",
|
|
515
|
+
"name": "Dialog",
|
|
516
|
+
"family": "dialogs",
|
|
517
|
+
"summary": "A controlled native modal or side drawer with focus return and background scroll locking.",
|
|
518
|
+
"props": [
|
|
519
|
+
["open", "boolean", "Required", "Your application owns visibility."],
|
|
520
|
+
[
|
|
521
|
+
"onClose",
|
|
522
|
+
"() => void",
|
|
523
|
+
"Required",
|
|
524
|
+
"Update open to false on Escape, close button or backdrop dismissal."
|
|
525
|
+
],
|
|
526
|
+
[
|
|
527
|
+
"title / description",
|
|
528
|
+
"string",
|
|
529
|
+
"Title required",
|
|
530
|
+
"Name the task and optionally explain its scope."
|
|
531
|
+
],
|
|
532
|
+
[
|
|
533
|
+
"children / footer",
|
|
534
|
+
"ReactNode",
|
|
535
|
+
"Children required; footer optional",
|
|
536
|
+
"Keep actions, pending and error states inside the modal."
|
|
537
|
+
],
|
|
538
|
+
[
|
|
539
|
+
"placement",
|
|
540
|
+
"\"center\" | \"left\" | \"right\"",
|
|
541
|
+
"\"center\"",
|
|
542
|
+
"Choose a modal or drawer composition."
|
|
543
|
+
]
|
|
544
|
+
],
|
|
545
|
+
"keyboard": "Focus enters the native modal; Tab remains within it. Escape requests onClose. Focus returns to the opener when the modal closes.",
|
|
546
|
+
"limits": "Does not confirm business operations, fetch content or prevent dismissal of unsaved data automatically. Browser native-dialog support is required; test your complete composition and nested overlays.",
|
|
547
|
+
"tasks": "modal drawer settings confirmation focus escape scroll",
|
|
548
|
+
"detail": {
|
|
549
|
+
"use": "Use for a task that needs modal focus confinement; placement left/right is the drawer composition. Use Popover for nonmodal supplementary content.",
|
|
550
|
+
"anatomy": "Native dialog contains panel, heading/description, close button, scrollable body and optional footer. panelProps/bodyProps/footerProps/closeButtonProps customize typed parts; preserve owned semantics.",
|
|
551
|
+
"state": "open/onClose is controlled. Escape, close button and backdrop request closure; the application changes open. initialFocus selects a mounted descendant; onOpenAutoFocus can cancel that explicit override, not native showModal autofocus.",
|
|
552
|
+
"forms": "Dialog is not a form. Compose a form or use external form attributes for footer actions. Pending, validation, unsaved changes and destructive confirmation remain application-owned.",
|
|
553
|
+
"ref": "Forwarded ref targets HTMLDialogElement. Part props can expose their native refs. There is no Dialog onCloseAutoFocus prop.",
|
|
554
|
+
"edgeCases": "Native top-layer focus confinement and nested background-scroll locks are supported. Portalled child layers stay inside the modal. Check short screens, long content and removed openers; keep a workflow focus fallback if the opener is removed.",
|
|
555
|
+
"localization": "Translate title, description, actions and closeButtonProps accessible label. Placement is physical left/right; select it deliberately for RTL. Verify your complete keyboard/AT flow.",
|
|
556
|
+
"reference": "overlays",
|
|
557
|
+
"styling": "Use the released scoped CSS and semantic tokens inside contour-root/ThemeScope. Preserve native semantics, public part/state hooks and geometry ownership; see the component-specific anatomy and STYLING.md."
|
|
558
|
+
}
|
|
559
|
+
},
|
|
560
|
+
{
|
|
561
|
+
"slug": "disclosure",
|
|
562
|
+
"name": "Disclosure",
|
|
563
|
+
"family": "content",
|
|
564
|
+
"summary": "Native details/summary with an expandable body and decorative plus icon.",
|
|
565
|
+
"props": [
|
|
566
|
+
[
|
|
567
|
+
"className / summary / children",
|
|
568
|
+
"string / ReactNode / ReactNode",
|
|
569
|
+
"Required",
|
|
570
|
+
"Keep summary a clear textual disclosure control."
|
|
571
|
+
],
|
|
572
|
+
[
|
|
573
|
+
"defaultOpen",
|
|
574
|
+
"boolean",
|
|
575
|
+
"false",
|
|
576
|
+
"Initial native open value; not a controlled state API."
|
|
577
|
+
],
|
|
578
|
+
[
|
|
579
|
+
"iconSize / iconStrokeWidth",
|
|
580
|
+
"number",
|
|
581
|
+
"23 / 1.25",
|
|
582
|
+
"Decorative icon geometry."
|
|
583
|
+
]
|
|
584
|
+
],
|
|
585
|
+
"keyboard": "Native summary toggles with Enter/Space and participates in Tab order; expanded children retain native behavior. No extra button is needed inside summary.",
|
|
586
|
+
"limits": "No root ref or forwarded native props, async request model, controlled open callback or accordion single-open coordination.",
|
|
587
|
+
"tasks": "Native details/summary with an expandable body and decorative plus icon. Use for supplementary content a user can expand. Do not hide essential instructions or place competing interactive controls inside summary.",
|
|
588
|
+
"detail": {
|
|
589
|
+
"use": "Use for supplementary content a user can expand. Do not hide essential instructions or place competing interactive controls inside summary.",
|
|
590
|
+
"anatomy": "Native details contains summary, decorative icon and children. Caller className is required; ccx adds public hooks.",
|
|
591
|
+
"state": "defaultOpen defaults false and is passed to native details.open at render. Browser owns user toggling; no controlled open/onToggle API is exposed.",
|
|
592
|
+
"forms": "Not a successful form control: no name, required constraint or native reset behavior. Reset any application-owned content/request state separately.",
|
|
593
|
+
"ref": "No public native-element ref is forwarded. Keep focus on actual native interactive children rather than making the presentation wrapper focusable.",
|
|
594
|
+
"edgeCases": "Keep long summary/body content readable. Applications own loading/error/retry and any state persistence; repeated rerender should not be treated as a controlled accordion contract.",
|
|
595
|
+
"localization": "Translate summary/body. Browser supplies native summary semantics; preserve logical reading order and test long RTL content.",
|
|
596
|
+
"reference": "props",
|
|
597
|
+
"styling": "Use .contour-disclosure and native [open] with released semantic color/line/spacing tokens. Preserve native structure, visible labels and owned state/ARIA; visual customization does not change the interaction contract."
|
|
598
|
+
}
|
|
599
|
+
},
|
|
600
|
+
{
|
|
601
|
+
"slug": "divider",
|
|
602
|
+
"name": "Divider",
|
|
603
|
+
"family": "content",
|
|
604
|
+
"summary": "A native horizontal rule, or a labelled separator presentation.",
|
|
605
|
+
"props": [
|
|
606
|
+
[
|
|
607
|
+
"label",
|
|
608
|
+
"string",
|
|
609
|
+
"Omitted",
|
|
610
|
+
"Optional centered visible text; not a heading."
|
|
611
|
+
]
|
|
612
|
+
],
|
|
613
|
+
"keyboard": "Not a keyboard control and does not add a tab stop. Interactive children retain their native behavior; do not use this display as a substitute for a button or link.",
|
|
614
|
+
"limits": "No vertical/orientation control, resize behavior, arbitrary root attributes or forwarded ref.",
|
|
615
|
+
"tasks": "A native horizontal rule, or a labelled separator presentation. Use to separate related content areas. Do not replace headings/navigation or use a visual rule as an interactive resize handle.",
|
|
616
|
+
"detail": {
|
|
617
|
+
"use": "Use to separate related content areas. Do not replace headings/navigation or use a visual rule as an interactive resize handle.",
|
|
618
|
+
"anatomy": "Without label renders hr; with label renders role=separator containing label text.",
|
|
619
|
+
"state": "Pure presentation; omitted/empty label chooses the native hr variant.",
|
|
620
|
+
"forms": "Not a successful form control: no name, required constraint or native reset behavior. Reset any application-owned content/request state separately.",
|
|
621
|
+
"ref": "No public native-element ref is forwarded. Keep focus on actual native interactive children rather than making the presentation wrapper focusable.",
|
|
622
|
+
"edgeCases": "Check contrast, narrow/long labels and surrounding spacing. Loading/error/form state is not applicable to a separator.",
|
|
623
|
+
"localization": "Translate label and preserve reading order; the labelled variant does not create a section heading.",
|
|
624
|
+
"reference": "props",
|
|
625
|
+
"styling": "Use .contour-divider and labelled hook with released semantic color/line/spacing tokens. Preserve native structure, visible labels and owned state/ARIA; visual customization does not change the interaction contract."
|
|
626
|
+
}
|
|
627
|
+
},
|
|
628
|
+
{
|
|
629
|
+
"slug": "dropdown-menu",
|
|
630
|
+
"name": "DropdownMenu",
|
|
631
|
+
"family": "floating",
|
|
632
|
+
"summary": "A button-triggered local action menu with focus movement and dismissal.",
|
|
633
|
+
"props": [
|
|
634
|
+
["label", "string", "Required", "Accessible trigger and menu name."],
|
|
635
|
+
[
|
|
636
|
+
"items",
|
|
637
|
+
"{id?, label, onSelect, icon?, danger?, disabled?}[]",
|
|
638
|
+
"Required",
|
|
639
|
+
"Supply stable ids when labels can repeat or change. Disabled items cannot be selected; decorative icons need aria-hidden."
|
|
640
|
+
],
|
|
641
|
+
[
|
|
642
|
+
"align",
|
|
643
|
+
"\"start\" | \"center\" | \"end\"",
|
|
644
|
+
"\"start\"",
|
|
645
|
+
"Align against the trigger within its container."
|
|
646
|
+
],
|
|
647
|
+
[
|
|
648
|
+
"open / defaultOpen / onOpenChange",
|
|
649
|
+
"boolean / boolean / (open: boolean) => void",
|
|
650
|
+
"Uncontrolled; defaultOpen is false",
|
|
651
|
+
"Provide open and update it from onOpenChange for controlled visibility. defaultOpen is only the initial uncontrolled state."
|
|
652
|
+
]
|
|
653
|
+
],
|
|
654
|
+
"keyboard": "Enter/Space open the trigger; ArrowDown/ArrowUp open at the first/last enabled item. Arrow keys and Home/End skip disabled items. Typing searches enabled labels. Escape dismisses with focus return; Tab dismisses and continues navigation.",
|
|
655
|
+
"limits": "Portal positioning, collision handling and native-dialog integration are supported. triggerProps targets the native button; renderTrigger composes one ref-forwarding button. There is no general submenu contract. Keep controlled or uncontrolled visibility consistent and verify focus return in the complete composition.",
|
|
656
|
+
"tasks": "menu actions popup popover context dropdown keyboard",
|
|
657
|
+
"detail": {
|
|
658
|
+
"use": "Use for a short list of actions. Use SelectField/Combobox for a submitted value and links for navigation semantics.",
|
|
659
|
+
"anatomy": "Wrapper, native trigger button and portalled menu/items. triggerProps/panelProps and renderTrigger customize typed parts; render exactly one ref-forwarding button with supplied props.",
|
|
660
|
+
"state": "open/onOpenChange is controlled or defaultOpen initializes local state. Stable item IDs and disabled entries are supported. Selection invokes your callback and requests closure.",
|
|
661
|
+
"forms": "Default trigger is type=button, not a selection field. Menu actions perform application commands; no named form value or reset is supplied.",
|
|
662
|
+
"ref": "Root ref targets the div; triggerProps.ref targets its button and panelProps.ref its panel. Do not treat the root as the trigger.",
|
|
663
|
+
"edgeCases": "Portal defaults true with collision-aware placement and native-dialog containment. First Escape dismisses the deepest layer; Tab dismisses without consuming navigation. No general submenus. Changing portal containers can remount child state.",
|
|
664
|
+
"localization": "Translate label/actions and use stable IDs rather than labels as identity. Alignment is logical in RTL; typeahead searches labels. Test long labels at the viewport edge.",
|
|
665
|
+
"reference": "overlays",
|
|
666
|
+
"styling": "Use the released scoped CSS and semantic tokens inside contour-root/ThemeScope. Preserve native semantics, public part/state hooks and geometry ownership; see the component-specific anatomy and STYLING.md."
|
|
667
|
+
}
|
|
668
|
+
},
|
|
669
|
+
{
|
|
670
|
+
"slug": "empty-state",
|
|
671
|
+
"name": "EmptyState",
|
|
672
|
+
"family": "content",
|
|
673
|
+
"summary": "An icon, heading, explanation and optional recovery action for a labelled empty situation.",
|
|
674
|
+
"props": [
|
|
675
|
+
[
|
|
676
|
+
"icon / title / message",
|
|
677
|
+
"ReactNode / string / string",
|
|
678
|
+
"Required",
|
|
679
|
+
"State the actual situation and useful next step."
|
|
680
|
+
],
|
|
681
|
+
[
|
|
682
|
+
"action",
|
|
683
|
+
"ReactNode",
|
|
684
|
+
"Omitted",
|
|
685
|
+
"Use a labelled native button/anchor with application behavior."
|
|
686
|
+
]
|
|
687
|
+
],
|
|
688
|
+
"keyboard": "Not a keyboard control and does not add a tab stop. Interactive children retain their native behavior; do not use this display as a substitute for a button or link.",
|
|
689
|
+
"limits": "No automatic loading/error classification, alert role, title-level prop, forwarding ref or data service. Its fixed h3 must fit the surrounding heading hierarchy.",
|
|
690
|
+
"tasks": "An icon, heading, explanation and optional recovery action for a labelled empty situation. Use to explain a genuinely empty result, not to hide a failed request. Differentiate no saved data, no filter matches, permissions and service failure in parent state.",
|
|
691
|
+
"detail": {
|
|
692
|
+
"use": "Use to explain a genuinely empty result, not to hide a failed request. Differentiate no saved data, no filter matches, permissions and service failure in parent state.",
|
|
693
|
+
"anatomy": "Decorative icon span, h3 title, message paragraph and optional action slot; no implicit live-region or request behavior.",
|
|
694
|
+
"state": "Pure display. Caller decides when to show each state and owns retry/create/filter-reset actions.",
|
|
695
|
+
"forms": "Not a successful form control: no name, required constraint or native reset behavior. Reset any application-owned content/request state separately.",
|
|
696
|
+
"ref": "No public native-element ref is forwarded. Keep focus on actual native interactive children rather than making the presentation wrapper focusable.",
|
|
697
|
+
"edgeCases": "Do not claim a successful response when permissions/network failed. Keep long copy/actions readable; avoid a dead primary action.",
|
|
698
|
+
"localization": "Translate title/message/action and verify heading order/RTL. Decorative icon supplies no accessible name; visible text carries meaning.",
|
|
699
|
+
"reference": "props",
|
|
700
|
+
"styling": "Use .contour-empty-state and semantic text/action tokens with released semantic color/line/spacing tokens. Preserve native structure, visible labels and owned state/ARIA; visual customization does not change the interaction contract."
|
|
701
|
+
}
|
|
702
|
+
},
|
|
703
|
+
{
|
|
704
|
+
"slug": "external-link",
|
|
705
|
+
"name": "ExternalLink",
|
|
706
|
+
"family": "buttons",
|
|
707
|
+
"summary": "A safe native anchor that opens an external destination in a new tab.",
|
|
708
|
+
"props": [
|
|
709
|
+
[
|
|
710
|
+
"href / children",
|
|
711
|
+
"Native anchor props",
|
|
712
|
+
"Omitted",
|
|
713
|
+
"Use an allowed destination and a clear link name."
|
|
714
|
+
],
|
|
715
|
+
[
|
|
716
|
+
"className / onClick / aria-label",
|
|
717
|
+
"Native anchor props",
|
|
718
|
+
"Native defaults",
|
|
719
|
+
"Preserve modified clicks and label icon-only links."
|
|
720
|
+
]
|
|
721
|
+
],
|
|
722
|
+
"keyboard": "Native anchor Enter and modified/middle clicks retain browser behavior. Explain new-tab behavior when it matters; no custom keyboard interception.",
|
|
723
|
+
"limits": "target/rel are deliberately excluded from caller props. URL validation is not a server authorization/security boundary or destination availability check.",
|
|
724
|
+
"tasks": "A safe native anchor that opens an external destination in a new tab. Use for off-site navigation where a new tab is appropriate. Use native anchors/router links for in-app destinations; do not implement navigation with a button.",
|
|
725
|
+
"detail": {
|
|
726
|
+
"use": "Use for off-site navigation where a new tab is appropriate. Use native anchors/router links for in-app destinations; do not implement navigation with a button.",
|
|
727
|
+
"anatomy": "Forwarded native anchor retains caller attributes/children. safeHref validates href; target=_blank and rel=noopener noreferrer are owned.",
|
|
728
|
+
"state": "No selection/request state. Destination and accessible name are application content; rejected URLs do not become a working link.",
|
|
729
|
+
"forms": "Navigation is not a successful form control or submit button; no native reset contract.",
|
|
730
|
+
"ref": "Forwarded HTMLAnchorElement for focus and compatible semantic link integrations.",
|
|
731
|
+
"edgeCases": "Handle missing/unsafe destinations by presenting useful text or another valid action. Do not imply a disabled or loading-link prop exists.",
|
|
732
|
+
"localization": "Translate the link name/new-tab explanation and test mixed-direction URLs. Icon children need an accessible name on the link.",
|
|
733
|
+
"reference": "composition",
|
|
734
|
+
"styling": "Use Caller anchor class plus semantic link/focus tokens with released semantic color/line/spacing tokens. Preserve native structure, visible labels and owned state/ARIA; visual customization does not change the interaction contract."
|
|
735
|
+
}
|
|
736
|
+
},
|
|
737
|
+
{
|
|
738
|
+
"slug": "field",
|
|
739
|
+
"name": "Field",
|
|
740
|
+
"family": "field",
|
|
741
|
+
"summary": "A label/supporting-text frame for an application-owned native control.",
|
|
742
|
+
"props": [
|
|
743
|
+
[
|
|
744
|
+
"id / label / children",
|
|
745
|
+
"string / string / ReactNode",
|
|
746
|
+
"Required",
|
|
747
|
+
"Give the actual child the same id; children own native attributes."
|
|
748
|
+
],
|
|
749
|
+
[
|
|
750
|
+
"hint / error / counter",
|
|
751
|
+
"string",
|
|
752
|
+
"Omitted",
|
|
753
|
+
"Connect descriptions with fieldDescribedBy; counter is caller-provided text."
|
|
754
|
+
],
|
|
755
|
+
[
|
|
756
|
+
"required / hideLabel / disabled",
|
|
757
|
+
"boolean",
|
|
758
|
+
"Omitted",
|
|
759
|
+
"These affect the frame; set required/disabled on the child too."
|
|
760
|
+
]
|
|
761
|
+
],
|
|
762
|
+
"keyboard": "Not a keyboard control and does not add a tab stop. Interactive children retain their native behavior; do not use this display as a substitute for a button or link.",
|
|
763
|
+
"limits": "No automatic child aria-invalid/aria-describedby/required/disabled wiring, no input state or forwarded ref. hideLabel hides visually rather than removing the accessible name.",
|
|
764
|
+
"tasks": "A label/supporting-text frame for an application-owned native control. Use when composing a control that TextField/SelectField do not already cover. Prefer those wrappers for their existing native wiring; Field does not validate or clone its child.",
|
|
765
|
+
"detail": {
|
|
766
|
+
"use": "Use when composing a control that TextField/SelectField do not already cover. Prefer those wrappers for their existing native wiring; Field does not validate or clone its child.",
|
|
767
|
+
"anatomy": "Frame renders label htmlFor=id, optional required marker, child slot and footer. Label ID is id-label; footer exposes id-hint or id-error and optional counter.",
|
|
768
|
+
"state": "Pure presentation. Parent owns value, errors, counters and any hidden-label/disabled appearance. Error takes precedence over hint.",
|
|
769
|
+
"forms": "The frame does not submit. Give the child id/name/form/required/disabled and native reset semantics explicitly; use fieldDescribedBy and aria-invalid for the child.",
|
|
770
|
+
"ref": "Attach a ref to the actual native child; Field forwards none.",
|
|
771
|
+
"edgeCases": "Business/server errors and pending states are application-owned. Test long hints/errors/counters and empty content; do not rely on the required asterisk as validation.",
|
|
772
|
+
"localization": "Translate label/hint/error/counter. Use suitable native inputMode/autoComplete/dir on the actual control and sensible localized count wording.",
|
|
773
|
+
"reference": "forms",
|
|
774
|
+
"styling": "Use .contour-field, .contour-field-label and footer states with released semantic color/line/spacing tokens. Preserve native structure, visible labels and owned state/ARIA; visual customization does not change the interaction contract."
|
|
775
|
+
}
|
|
776
|
+
},
|
|
777
|
+
{
|
|
778
|
+
"slug": "flip-card",
|
|
779
|
+
"name": "FlipCard",
|
|
780
|
+
"family": "motion",
|
|
781
|
+
"summary": "A two-face CSS card with an explicit accessible toggle.",
|
|
782
|
+
"props": [
|
|
783
|
+
[
|
|
784
|
+
"front / back",
|
|
785
|
+
"ReactNode",
|
|
786
|
+
"Required",
|
|
787
|
+
"Use meaningful face content and valid focusable children."
|
|
788
|
+
],
|
|
789
|
+
[
|
|
790
|
+
"label",
|
|
791
|
+
"string",
|
|
792
|
+
"Required",
|
|
793
|
+
"A clear toggle name; aria-pressed exposes the flipped state."
|
|
794
|
+
]
|
|
795
|
+
],
|
|
796
|
+
"keyboard": "Tab reaches the native toggle; Enter/Space flips. Hidden-face interactive content is inert. Caller should keep focus on the stable toggle rather than programmatically focus an inactive face.",
|
|
797
|
+
"limits": "No controlled flip/ref/hover-only contract. React18/19 inert behavior is deliberately supported; manual screen-reader review remains separate.",
|
|
798
|
+
"tasks": "A two-face CSS card with an explicit accessible toggle. Use for supplementary paired content, keeping essential information discoverable. Do not require hover or hide critical form instructions on the reverse.",
|
|
799
|
+
"detail": {
|
|
800
|
+
"use": "Use for supplementary paired content, keeping essential information discoverable. Do not require hover or hide critical form instructions on the reverse.",
|
|
801
|
+
"anatomy": "Front/back faces sit inside a flipped-state card; a separate native toggle remains stationary. Inactive face receives aria-hidden and inert in React18/19-compatible form.",
|
|
802
|
+
"state": "Internal boolean starts front-visible; toggle changes it. No controlled flipped prop or animation engine is exposed.",
|
|
803
|
+
"forms": "Not a successful form control: no name, required constraint or native reset behavior. Reset any application-owned content/request state separately.",
|
|
804
|
+
"ref": "No public native-element ref is forwarded. Keep focus on actual native interactive children rather than making the presentation wrapper focusable.",
|
|
805
|
+
"edgeCases": "Check long faces, fixed toggle position, reduced motion and inactive face focus/reading exclusion. A flip animation does not prove data loading/success.",
|
|
806
|
+
"localization": "Translate label/face content and verify RTL reading order. A single label is used for both states with aria-pressed.",
|
|
807
|
+
"reference": "hooks",
|
|
808
|
+
"styling": "Use .contour-flip-card, visible-state and face/toggle hooks with released semantic color/line/spacing tokens. Preserve native structure, visible labels and owned state/ARIA; visual customization does not change the interaction contract."
|
|
809
|
+
}
|
|
810
|
+
},
|
|
811
|
+
{
|
|
812
|
+
"slug": "github-icon",
|
|
813
|
+
"name": "GitHubIcon",
|
|
814
|
+
"family": "identity",
|
|
815
|
+
"summary": "A decorative GitHub brand SVG for a separately labelled link.",
|
|
816
|
+
"props": [
|
|
817
|
+
[
|
|
818
|
+
"size",
|
|
819
|
+
"number",
|
|
820
|
+
"17",
|
|
821
|
+
"Caller chooses sensible finite SVG dimensions."
|
|
822
|
+
]
|
|
823
|
+
],
|
|
824
|
+
"keyboard": "Not a keyboard control and does not add a tab stop. Interactive children retain their native behavior; do not use this display as a substitute for a button or link.",
|
|
825
|
+
"limits": "No children/title/aria-label/native SVG props/ref, social API request or automatic profile destination. The surrounding link supplies the name.",
|
|
826
|
+
"tasks": "A decorative GitHub brand SVG for a separately labelled link. Use only to identify the GitHub destination. A logo is not a link or accessible name; pair it with a native labelled anchor and appropriate brand attribution.",
|
|
827
|
+
"detail": {
|
|
828
|
+
"use": "Use only to identify the GitHub destination. A logo is not a link or accessible name; pair it with a native labelled anchor and appropriate brand attribution.",
|
|
829
|
+
"anatomy": "Fixed SVG viewBox/path uses currentColor and aria-hidden=true. size sets equal width/height; no link is created.",
|
|
830
|
+
"state": "Pure vector display; size defaults to 17. No interaction/state or network integration.",
|
|
831
|
+
"forms": "Not a successful form control: no name, required constraint or native reset behavior. Reset any application-owned content/request state separately.",
|
|
832
|
+
"ref": "No public native-element ref is forwarded. Keep focus on actual native interactive children rather than making the presentation wrapper focusable.",
|
|
833
|
+
"edgeCases": "Keep a suitable link target size/focus indication independent of icon dimensions; test contrast/forced colors and never use logo color alone.",
|
|
834
|
+
"localization": "The vector is fixed; translate the surrounding link label or explanatory text. The GitHub brand name remains an identity.",
|
|
835
|
+
"reference": "props",
|
|
836
|
+
"styling": "Use The SVG inherits currentColor from its labelled parent with released semantic color/line/spacing tokens. Preserve native structure, visible labels and owned state/ARIA; visual customization does not change the interaction contract."
|
|
837
|
+
}
|
|
838
|
+
},
|
|
839
|
+
{
|
|
840
|
+
"slug": "icon-button",
|
|
841
|
+
"name": "IconButton",
|
|
842
|
+
"family": "buttons",
|
|
843
|
+
"summary": "A native icon-only button with a mandatory accessible label and native ref.",
|
|
844
|
+
"props": [
|
|
845
|
+
[
|
|
846
|
+
"label / children",
|
|
847
|
+
"string / ReactNode",
|
|
848
|
+
"Required",
|
|
849
|
+
"The label supplies the accessible name; children supply the icon."
|
|
850
|
+
],
|
|
851
|
+
["variant", "outline | solid | accent", "outline", "Visual emphasis."],
|
|
852
|
+
[
|
|
853
|
+
"size / spin",
|
|
854
|
+
"sm | md | lg / boolean",
|
|
855
|
+
"md / false",
|
|
856
|
+
"Spin is optional decorative hover feedback."
|
|
857
|
+
],
|
|
858
|
+
[
|
|
859
|
+
"type / title / ref",
|
|
860
|
+
"Native button props and ref",
|
|
861
|
+
"button / label / omitted",
|
|
862
|
+
"Caller title is preserved; the ref targets HTMLButtonElement."
|
|
863
|
+
]
|
|
864
|
+
],
|
|
865
|
+
"keyboard": "Native button keyboard behavior. The icon's accessible label remains available without a tooltip or hover.",
|
|
866
|
+
"limits": "No anchor or arbitrary-element polymorphism. Keep decorative spin separate from essential state.",
|
|
867
|
+
"tasks": "icon button accessible label ref title spin",
|
|
868
|
+
"detail": {
|
|
869
|
+
"use": "Use for a familiar compact action with a clear accessible label. Prefer Button text for an unfamiliar or consequential action.",
|
|
870
|
+
"anatomy": "One native circular button contains caller icon children. label owns aria-label; title defaults to label unless caller title is supplied. Native props/ref stay on the button.",
|
|
871
|
+
"state": "variant defaults outline, size md and spin false. Disabled is native. Decorative spin does not indicate pending or successful work.",
|
|
872
|
+
"forms": "Default type is button. Use native submit/reset deliberately and keep form validation/application requests outside the component.",
|
|
873
|
+
"ref": "Forwarded ref targets HTMLButtonElement. Do not nest a button/anchor inside its children.",
|
|
874
|
+
"edgeCases": "label is mandatory even when the icon seems obvious. Check target size, disabled contrast and focus in both themes. Essential meaning cannot depend on rotation or hover title.",
|
|
875
|
+
"localization": "Translate label and optional title. Consider direction-specific icon meaning and preserve a useful name when the visual is mirrored.",
|
|
876
|
+
"reference": "composition",
|
|
877
|
+
"styling": "Use the released scoped CSS and semantic tokens inside contour-root/ThemeScope. Preserve native semantics, public part/state hooks and geometry ownership; see the component-specific anatomy and STYLING.md."
|
|
878
|
+
}
|
|
879
|
+
},
|
|
880
|
+
{
|
|
881
|
+
"slug": "kbd",
|
|
882
|
+
"name": "Kbd",
|
|
883
|
+
"family": "metadata",
|
|
884
|
+
"summary": "A native keyboard-key text treatment.",
|
|
885
|
+
"props": [
|
|
886
|
+
[
|
|
887
|
+
"children",
|
|
888
|
+
"ReactNode",
|
|
889
|
+
"Required",
|
|
890
|
+
"Use understandable platform-appropriate key names."
|
|
891
|
+
]
|
|
892
|
+
],
|
|
893
|
+
"keyboard": "Not a keyboard control and does not add a tab stop. Interactive children retain their native behavior; do not use this display as a substitute for a button or link.",
|
|
894
|
+
"limits": "No activation, key handling, platform detection, forwarded props or ref.",
|
|
895
|
+
"tasks": "A native keyboard-key text treatment. Use to describe an actual shortcut/key. Do not imply that displaying a key registers a shortcut or makes a noninteractive element operable.",
|
|
896
|
+
"detail": {
|
|
897
|
+
"use": "Use to describe an actual shortcut/key. Do not imply that displaying a key registers a shortcut or makes a noninteractive element operable.",
|
|
898
|
+
"anatomy": "Native kbd wraps caller children with a visual keycap class.",
|
|
899
|
+
"state": "Pure text display, with no key listeners or shortcut registry.",
|
|
900
|
+
"forms": "Not a successful form control: no name, required constraint or native reset behavior. Reset any application-owned content/request state separately.",
|
|
901
|
+
"ref": "No public native-element ref is forwarded. Keep focus on actual native interactive children rather than making the presentation wrapper focusable.",
|
|
902
|
+
"edgeCases": "Keep chord instructions readable and provide a real keyboard interaction separately; loading/error states do not apply to a key label.",
|
|
903
|
+
"localization": "Translate key/instruction text and distinguish platform conventions such as Control versus Command. A drawn symbol may need nearby explanation.",
|
|
904
|
+
"reference": "props",
|
|
905
|
+
"styling": "Use .contour-kbd with released semantic color/line/spacing tokens. Preserve native structure, visible labels and owned state/ARIA; visual customization does not change the interaction contract."
|
|
906
|
+
}
|
|
907
|
+
},
|
|
908
|
+
{
|
|
909
|
+
"slug": "linkedin-icon",
|
|
910
|
+
"name": "LinkedInIcon",
|
|
911
|
+
"family": "identity",
|
|
912
|
+
"summary": "A decorative LinkedIn brand SVG for a separately labelled link.",
|
|
913
|
+
"props": [
|
|
914
|
+
[
|
|
915
|
+
"size",
|
|
916
|
+
"number",
|
|
917
|
+
"17",
|
|
918
|
+
"Caller chooses sensible finite SVG dimensions."
|
|
919
|
+
]
|
|
920
|
+
],
|
|
921
|
+
"keyboard": "Not a keyboard control and does not add a tab stop. Interactive children retain their native behavior; do not use this display as a substitute for a button or link.",
|
|
922
|
+
"limits": "No children/title/aria-label/native SVG props/ref, social API request or automatic profile destination. The surrounding link supplies the name.",
|
|
923
|
+
"tasks": "A decorative LinkedIn brand SVG for a separately labelled link. Use only to identify the LinkedIn destination. A logo is not a link or accessible name; pair it with a native labelled anchor and appropriate brand attribution.",
|
|
924
|
+
"detail": {
|
|
925
|
+
"use": "Use only to identify the LinkedIn destination. A logo is not a link or accessible name; pair it with a native labelled anchor and appropriate brand attribution.",
|
|
926
|
+
"anatomy": "Fixed SVG viewBox/path uses currentColor and aria-hidden=true. size sets equal width/height; no link is created.",
|
|
927
|
+
"state": "Pure vector display; size defaults to 17. No interaction/state or network integration.",
|
|
928
|
+
"forms": "Not a successful form control: no name, required constraint or native reset behavior. Reset any application-owned content/request state separately.",
|
|
929
|
+
"ref": "No public native-element ref is forwarded. Keep focus on actual native interactive children rather than making the presentation wrapper focusable.",
|
|
930
|
+
"edgeCases": "Keep a suitable link target size/focus indication independent of icon dimensions; test contrast/forced colors and never use logo color alone.",
|
|
931
|
+
"localization": "The vector is fixed; translate the surrounding link label or explanatory text. The LinkedIn brand name remains an identity.",
|
|
932
|
+
"reference": "props",
|
|
933
|
+
"styling": "Use The SVG inherits currentColor from its labelled parent with released semantic color/line/spacing tokens. Preserve native structure, visible labels and owned state/ARIA; visual customization does not change the interaction contract."
|
|
934
|
+
}
|
|
935
|
+
},
|
|
936
|
+
{
|
|
937
|
+
"slug": "magnetic",
|
|
938
|
+
"name": "Magnetic",
|
|
939
|
+
"family": "motion",
|
|
940
|
+
"summary": "A CSS pointer-follow wrapper that leaves native child semantics intact.",
|
|
941
|
+
"props": [
|
|
942
|
+
[
|
|
943
|
+
"children",
|
|
944
|
+
"ReactNode",
|
|
945
|
+
"Required",
|
|
946
|
+
"Use a real labelled native control when interactive."
|
|
947
|
+
],
|
|
948
|
+
[
|
|
949
|
+
"strength",
|
|
950
|
+
"number",
|
|
951
|
+
"0.35",
|
|
952
|
+
"Choose a sensible finite fractional displacement."
|
|
953
|
+
]
|
|
954
|
+
],
|
|
955
|
+
"keyboard": "Not a keyboard control and does not add a tab stop. Interactive children retain their native behavior; do not use this display as a substitute for a button or link.",
|
|
956
|
+
"limits": "No click/drag/key interaction, forwarded ref or touch/pen magnet. The presentation wrapper is not a new control.",
|
|
957
|
+
"tasks": "A CSS pointer-follow wrapper that leaves native child semantics intact. Use for optional motion around a real control. Do not make essential targets depend on pointer movement or move them so far they become difficult to activate.",
|
|
958
|
+
"detail": {
|
|
959
|
+
"use": "Use for optional motion around a real control. Do not make essential targets depend on pointer movement or move them so far they become difficult to activate.",
|
|
960
|
+
"anatomy": "Span wrapper writes a magnet CSS custom property from mouse offset and resets it on pointer leave. Children retain their native semantics.",
|
|
961
|
+
"state": "strength defaults to 0.35 of pointer offset. Only mouse movement with enabled motion applies displacement; no state/persistence/service is owned.",
|
|
962
|
+
"forms": "Not a successful form control: no name, required constraint or native reset behavior. Reset any application-owned content/request state separately.",
|
|
963
|
+
"ref": "No public native-element ref is forwarded. Keep focus on actual native interactive children rather than making the presentation wrapper focusable.",
|
|
964
|
+
"edgeCases": "Keep target usability, focus indication and surrounding hit areas stable; test reduced/paused motion, long labels and narrow screens.",
|
|
965
|
+
"localization": "Children supply language/direction; pointer displacement has no semantic directional meaning.",
|
|
966
|
+
"reference": "hooks",
|
|
967
|
+
"styling": "Use .contour-magnetic and its --magnet geometry variable with released semantic color/line/spacing tokens. Preserve native structure, visible labels and owned state/ARIA; visual customization does not change the interaction contract."
|
|
968
|
+
}
|
|
969
|
+
},
|
|
970
|
+
{
|
|
971
|
+
"slug": "marquee",
|
|
972
|
+
"name": "Marquee",
|
|
973
|
+
"family": "motion",
|
|
974
|
+
"summary": "A labelled repeating visual ticker with one accessible item sequence.",
|
|
975
|
+
"props": [
|
|
976
|
+
[
|
|
977
|
+
"items / label",
|
|
978
|
+
"string[] / string",
|
|
979
|
+
"Required",
|
|
980
|
+
"Unique items and a meaningful region name."
|
|
981
|
+
],
|
|
982
|
+
[
|
|
983
|
+
"duration",
|
|
984
|
+
"number",
|
|
985
|
+
"28",
|
|
986
|
+
"Seconds per loop; validate a sensible positive finite value."
|
|
987
|
+
]
|
|
988
|
+
],
|
|
989
|
+
"keyboard": "Not a keyboard control and does not add a tab stop. Interactive children retain their native behavior; do not use this display as a substitute for a button or link.",
|
|
990
|
+
"limits": "No built-in pause button, live updates/announcements, arbitrary children or root ref. Do not imply the decorative duplicate is another dataset.",
|
|
991
|
+
"tasks": "A labelled repeating visual ticker with one accessible item sequence. Use for nonessential repeated metadata. Keep essential content available statically and provide an application pause control for ongoing motion.",
|
|
992
|
+
"detail": {
|
|
993
|
+
"use": "Use for nonessential repeated metadata. Keep essential content available statically and provide an application pause control for ongoing motion.",
|
|
994
|
+
"anatomy": "Named region contains two list tracks for seamless motion; the duplicated track is aria-hidden and decorative icons carry no meaning.",
|
|
995
|
+
"state": "Caller owns unique string items and positive duration (default 28 seconds). CSS handles hover/system reduction and surrounding app pause.",
|
|
996
|
+
"forms": "Not a successful form control: no name, required constraint or native reset behavior. Reset any application-owned content/request state separately.",
|
|
997
|
+
"ref": "No public native-element ref is forwarded. Keep focus on actual native interactive children rather than making the presentation wrapper focusable.",
|
|
998
|
+
"edgeCases": "Pause ongoing motion from the app, test reduced/paused states and long items. Loading/error/empty data belongs outside the ticker.",
|
|
999
|
+
"localization": "Translate label/items and verify RTL visual direction/reading order. Do not treat track motion as navigation.",
|
|
1000
|
+
"reference": "hooks",
|
|
1001
|
+
"styling": "Use .contour-marquee, track hooks and --marquee-duration with released semantic color/line/spacing tokens. Preserve native structure, visible labels and owned state/ARIA; visual customization does not change the interaction contract."
|
|
1002
|
+
}
|
|
1003
|
+
},
|
|
1004
|
+
{
|
|
1005
|
+
"slug": "pagination",
|
|
1006
|
+
"name": "Pagination",
|
|
1007
|
+
"family": "navigation",
|
|
1008
|
+
"summary": "Controlled one-based page navigation with translated labels and condensed page buttons.",
|
|
1009
|
+
"props": [
|
|
1010
|
+
[
|
|
1011
|
+
"page / pageCount / onChange",
|
|
1012
|
+
"number / number / (page:number)=>void",
|
|
1013
|
+
"Required",
|
|
1014
|
+
"Supply1 <= page <= pageCount and update state after requests as appropriate."
|
|
1015
|
+
],
|
|
1016
|
+
[
|
|
1017
|
+
"label / previousLabel / nextLabel",
|
|
1018
|
+
"string",
|
|
1019
|
+
"Pagination / Previous page / Next page",
|
|
1020
|
+
"Translate navigation and button names."
|
|
1021
|
+
],
|
|
1022
|
+
[
|
|
1023
|
+
"pageLabel / formatPage",
|
|
1024
|
+
"(page:number)=>string",
|
|
1025
|
+
"Page N / formatIndex",
|
|
1026
|
+
"Accessible names and visual numeral formatting are separate."
|
|
1027
|
+
]
|
|
1028
|
+
],
|
|
1029
|
+
"keyboard": "Tab reaches native enabled buttons; Enter/Space requests a page. First/last boundaries disable previous/next. No grid/radio arrow model or automatic result focus is added.",
|
|
1030
|
+
"limits": "No zero-page/invalid-number sanitization, router hrefs, pending/disabled prop or server operation. Callback success does not establish fetched data.",
|
|
1031
|
+
"tasks": "Controlled one-based page navigation with translated labels and condensed page buttons. Use to move through known result pages. Own URL/data loading separately; hide pagination or show an empty state when no pages exist.",
|
|
1032
|
+
"detail": {
|
|
1033
|
+
"use": "Use to move through known result pages. Own URL/data loading separately; hide pagination or show an empty state when no pages exist.",
|
|
1034
|
+
"anatomy": "Named nav contains previous/next buttons and an ordered condensed list; current page has aria-current=page. Gaps are decorative.",
|
|
1035
|
+
"state": "page and pageCount are caller-owned positive finite integers. onChange requests another one-based page; component neither clamps invalid inputs nor fetches rows.",
|
|
1036
|
+
"forms": "Not a successful form control: no name, required constraint or native reset behavior. Reset any application-owned content/request state separately.",
|
|
1037
|
+
"ref": "No public native-element ref is forwarded. Keep focus on actual native interactive children rather than making the presentation wrapper focusable.",
|
|
1038
|
+
"edgeCases": "Preserve current results/query on request failure; show retry/loading in the application. Check large page counts, narrow width and long translations.",
|
|
1039
|
+
"localization": "Use all label callbacks and formatPage for localized numerals. Verify RTL previous/next meaning with logical order and your product convention.",
|
|
1040
|
+
"reference": "props",
|
|
1041
|
+
"styling": "Use .contour-pagination, native buttons and [aria-current=page] with released semantic color/line/spacing tokens. Preserve native structure, visible labels and owned state/ARIA; visual customization does not change the interaction contract."
|
|
1042
|
+
}
|
|
1043
|
+
},
|
|
1044
|
+
{
|
|
1045
|
+
"slug": "popover",
|
|
1046
|
+
"name": "Popover",
|
|
1047
|
+
"family": "floating",
|
|
1048
|
+
"summary": "A nonmodal floating panel with collision-aware portals and typed focus/trigger composition.",
|
|
1049
|
+
"props": [
|
|
1050
|
+
[
|
|
1051
|
+
"trigger / title / children",
|
|
1052
|
+
"ReactNode / string / ReactNode",
|
|
1053
|
+
"Required",
|
|
1054
|
+
"Default trigger content must not be another button."
|
|
1055
|
+
],
|
|
1056
|
+
[
|
|
1057
|
+
"open / defaultOpen / onOpenChange",
|
|
1058
|
+
"boolean / boolean / callback",
|
|
1059
|
+
"Uncontrolled / false",
|
|
1060
|
+
"Keep one ownership model."
|
|
1061
|
+
],
|
|
1062
|
+
[
|
|
1063
|
+
"portal / side / align",
|
|
1064
|
+
"boolean / top | bottom | left | right / start | center | end",
|
|
1065
|
+
"true / bottom / start",
|
|
1066
|
+
"Placement follows collision bounds and logical alignment."
|
|
1067
|
+
],
|
|
1068
|
+
[
|
|
1069
|
+
"renderTrigger / triggerProps / panelProps",
|
|
1070
|
+
"Typed button renderer / native part props",
|
|
1071
|
+
"Omitted",
|
|
1072
|
+
"Spread supplied props into one ref-forwarding button."
|
|
1073
|
+
],
|
|
1074
|
+
[
|
|
1075
|
+
"initialFocus",
|
|
1076
|
+
"ref | false",
|
|
1077
|
+
"Panel focus on entry",
|
|
1078
|
+
"Override entry deliberately and retain a usable close path."
|
|
1079
|
+
]
|
|
1080
|
+
],
|
|
1081
|
+
"keyboard": "Nonmodal panel entry focuses its panel or requested target. Escape closes the deepest layer and returns focus; outside press keeps destination focus. Tab is not trapped.",
|
|
1082
|
+
"limits": "Portals affect DOM Tab order. No arbitrary link trigger or modal focus trap. Use Dialog when background interaction must be blocked.",
|
|
1083
|
+
"tasks": "popover popup portal focus renderTrigger collision nonmodal",
|
|
1084
|
+
"detail": {
|
|
1085
|
+
"use": "Use for supplementary interactive content that leaves the background available. Use Tooltip only for noninteractive hints and Dialog for a modal task.",
|
|
1086
|
+
"anatomy": "Root wrapper and button trigger own the panel relationship. Panel is a named nonmodal dialog. Typed triggerProps/panelProps expose parts; renderTrigger spreads owned attributes/handlers/ref into one button.",
|
|
1087
|
+
"state": "Use open/onOpenChange or defaultOpen. Default portal is true; side bottom, align start and sideOffset/collisionPadding eight pixels. initialFocus=false preserves trigger focus. Cancelable focus/dismiss events permit explicit workflow ownership.",
|
|
1088
|
+
"forms": "The trigger defaults type=button. Popover is not a form; portal movement can change DOM form ancestry, so use explicit form association when required.",
|
|
1089
|
+
"ref": "Root ref targets HTMLDivElement; triggerProps.ref and panelProps.ref target their native parts. Portals can detach/reattach panel refs when the container changes.",
|
|
1090
|
+
"edgeCases": "Native-dialog containment keeps the panel in the modal top layer. Collision observers update on scroll/resize and clean up on close. No focus trap; portalled DOM order may require an application focus policy. Changing containers may remount unsaved children.",
|
|
1091
|
+
"localization": "Translate title and trigger content. Alignment follows inherited RTL; physical side remains an explicit choice. Check long content, small viewports and a usable dismissal path.",
|
|
1092
|
+
"reference": "overlays",
|
|
1093
|
+
"styling": "Use the released scoped CSS and semantic tokens inside contour-root/ThemeScope. Preserve native semantics, public part/state hooks and geometry ownership; see the component-specific anatomy and STYLING.md."
|
|
1094
|
+
}
|
|
1095
|
+
},
|
|
1096
|
+
{
|
|
1097
|
+
"slug": "progress-bar",
|
|
1098
|
+
"name": "ProgressBar",
|
|
1099
|
+
"family": "feedback",
|
|
1100
|
+
"summary": "Labelled determinate or indeterminate progress for work managed by your application.",
|
|
1101
|
+
"props": [
|
|
1102
|
+
[
|
|
1103
|
+
"label",
|
|
1104
|
+
"string",
|
|
1105
|
+
"Required",
|
|
1106
|
+
"Describe the operation being reported."
|
|
1107
|
+
],
|
|
1108
|
+
[
|
|
1109
|
+
"value",
|
|
1110
|
+
"number",
|
|
1111
|
+
"Omitted: indeterminate",
|
|
1112
|
+
"Supply a finite number from 0 to 100 only when progress is known. Validate and bound it before rendering."
|
|
1113
|
+
],
|
|
1114
|
+
[
|
|
1115
|
+
"tone",
|
|
1116
|
+
"\"accent\" | \"success\" | \"danger\"",
|
|
1117
|
+
"\"accent\"",
|
|
1118
|
+
"Use text as well as color to explain completion or failure."
|
|
1119
|
+
]
|
|
1120
|
+
],
|
|
1121
|
+
"keyboard": "Progress is informational and does not take focus. Put cancel, retry or pause actions in separate labelled controls.",
|
|
1122
|
+
"limits": "The component does not start work, calculate percentages or clamp invalid inputs. Omit value for unknown progress. An indeterminate animation is not evidence that a request is succeeding; applications own status, recovery and cancellation.",
|
|
1123
|
+
"tasks": "progress loading percentage upload status indeterminate",
|
|
1124
|
+
"detail": {
|
|
1125
|
+
"use": "Use for measured completion or unknown-duration work. Use Spinner for a compact indicator; do not imply measured progress when the total is unknown.",
|
|
1126
|
+
"anatomy": "A named progressbar, visual track/fill and visible rounded percentage when determinate. No interactive parts or native input ref.",
|
|
1127
|
+
"state": "Omitted value is indeterminate. Caller supplies a finite 0–100 value; tone defaults accent and also supports success/danger. The component does not clamp invalid input or calculate progress.",
|
|
1128
|
+
"forms": "Informational output: no successful form control, required constraint or reset behavior. The application resets its progress state.",
|
|
1129
|
+
"ref": "No native ref contract. Put pause/cancel/retry in separate labelled controls.",
|
|
1130
|
+
"edgeCases": "Unknown, stalled and failed requests need truthful adjacent status. An animation does not prove success. Check 0 and 100, long labels, both themes and reduced motion.",
|
|
1131
|
+
"localization": "Translate label/status text. The built-in rounded percent is not a locale formatting service; use adjacent localized wording when needed.",
|
|
1132
|
+
"reference": "props",
|
|
1133
|
+
"styling": "Use the released scoped CSS and semantic tokens inside contour-root/ThemeScope. Preserve native semantics, public part/state hooks and geometry ownership; see the component-specific anatomy and STYLING.md."
|
|
1134
|
+
}
|
|
1135
|
+
},
|
|
1136
|
+
{
|
|
1137
|
+
"slug": "radio-group",
|
|
1138
|
+
"name": "RadioGroup",
|
|
1139
|
+
"family": "choices",
|
|
1140
|
+
"summary": "A named native radio set with a legend, controlled/default selection and per-option input access.",
|
|
1141
|
+
"props": [
|
|
1142
|
+
[
|
|
1143
|
+
"legend / options",
|
|
1144
|
+
"string / option records",
|
|
1145
|
+
"Required",
|
|
1146
|
+
"Supply a meaningful group name and unique value/label pairs."
|
|
1147
|
+
],
|
|
1148
|
+
[
|
|
1149
|
+
"value / defaultValue / onChange",
|
|
1150
|
+
"Value / Value / (value: Value) => void",
|
|
1151
|
+
"Uncontrolled if value omitted",
|
|
1152
|
+
"Callback receives the selected string, not an event."
|
|
1153
|
+
],
|
|
1154
|
+
[
|
|
1155
|
+
"name / form / required / disabled",
|
|
1156
|
+
"Native fieldset and group props",
|
|
1157
|
+
"Generated name; other props omitted",
|
|
1158
|
+
"Supply a caller name for stable FormData and form for an external owner."
|
|
1159
|
+
],
|
|
1160
|
+
["inline", "boolean", "false", "Changes layout, not radio semantics."],
|
|
1161
|
+
[
|
|
1162
|
+
"description / error",
|
|
1163
|
+
"string",
|
|
1164
|
+
"Omitted",
|
|
1165
|
+
"Keep validation linked and visible."
|
|
1166
|
+
]
|
|
1167
|
+
],
|
|
1168
|
+
"keyboard": "Tab enters the native radio set; arrow/Space behavior follows the browser. options.inputProps.ref targets each native input for focus/blur integration. Disabled choices cannot activate.",
|
|
1169
|
+
"limits": "Native radios, not a custom listbox. No multi-select, asynchronous loading model or root forwarded ref; values must remain unique and stable.",
|
|
1170
|
+
"tasks": "A named native radio set with a legend, controlled/default selection and per-option input access. Use for one choice from a visible list. Use independent Checkbox controls for multiple choices, or SelectField/Combobox when a popup is more appropriate.",
|
|
1171
|
+
"detail": {
|
|
1172
|
+
"use": "Use for one choice from a visible list. Use independent Checkbox controls for multiple choices, or SelectField/Combobox when a popup is more appropriate.",
|
|
1173
|
+
"anatomy": "Fieldset and legend contain labelled native radio inputs. description/error IDs merge with caller descriptions; each option may have its own description, disabled flag and inputProps.",
|
|
1174
|
+
"state": "value/onChange controls selection; otherwise defaultValue captures an uncontrolled initial selection. Keep unique stable string values. No singular root focus ref is exposed.",
|
|
1175
|
+
"forms": "A named checked enabled radio submits its string value; required uses native validity. Disabled values are omitted. Native/external form reset restores captured defaults; controlled owners reset their state and cancelled reset is respected.",
|
|
1176
|
+
"ref": "Use options[index].inputProps.ref for HTMLInputElement. No forwarded fieldset or aggregate native-input ref.",
|
|
1177
|
+
"edgeCases": "Show request failure/loading/empty choices outside the group. Keep long legends/descriptions readable and do not replace selection silently when choices change.",
|
|
1178
|
+
"localization": "Translate legend, labels, descriptions and errors. Native browser validation and radio key behavior vary by platform; test RTL and long labels.",
|
|
1179
|
+
"reference": "forms",
|
|
1180
|
+
"styling": "Use .contour-radio-group and .contour-choice with released semantic color/line/spacing tokens. Preserve native structure, visible labels and owned state/ARIA; visual customization does not change the interaction contract."
|
|
1181
|
+
}
|
|
1182
|
+
},
|
|
1183
|
+
{
|
|
1184
|
+
"slug": "reveal",
|
|
1185
|
+
"name": "Reveal",
|
|
1186
|
+
"family": "motion",
|
|
1187
|
+
"summary": "A one-time observer-driven entrance wrapper with a static reduced-motion path.",
|
|
1188
|
+
"props": [
|
|
1189
|
+
[
|
|
1190
|
+
"children",
|
|
1191
|
+
"ReactNode",
|
|
1192
|
+
"Required",
|
|
1193
|
+
"Keep native content semantics inside the wrapper."
|
|
1194
|
+
],
|
|
1195
|
+
[
|
|
1196
|
+
"className / delay",
|
|
1197
|
+
"string / number",
|
|
1198
|
+
"empty string / 0",
|
|
1199
|
+
"Append scoped classes and optional millisecond visual stagger."
|
|
1200
|
+
]
|
|
1201
|
+
],
|
|
1202
|
+
"keyboard": "Not a keyboard control and does not add a tab stop. Interactive children retain their native behavior; do not use this display as a substitute for a button or link.",
|
|
1203
|
+
"limits": "No enter/exit lifecycle API, repeated visibility callback, forwarded ref or data-loading orchestration.",
|
|
1204
|
+
"tasks": "A one-time observer-driven entrance wrapper with a static reduced-motion path. Use for optional presentation around already meaningful content. Essential content must remain usable without animation; do not use entrance timing as a loading state.",
|
|
1205
|
+
"detail": {
|
|
1206
|
+
"use": "Use for optional presentation around already meaningful content. Essential content must remain usable without animation; do not use entrance timing as a loading state.",
|
|
1207
|
+
"anatomy": "Div wrapper observes entry, adds public visible state hooks and disconnects. className appends; delay sets transition delay.",
|
|
1208
|
+
"state": "One-time viewport activation; className defaults empty and delay 0 ms. If IntersectionObserver is missing, visible hooks are applied immediately. System/app motion styling controls the animation.",
|
|
1209
|
+
"forms": "Not a successful form control: no name, required constraint or native reset behavior. Reset any application-owned content/request state separately.",
|
|
1210
|
+
"ref": "No public native-element ref is forwarded. Keep focus on actual native interactive children rather than making the presentation wrapper focusable.",
|
|
1211
|
+
"edgeCases": "Check static/reduced-motion/no-observer visibility, unmount cleanup and long content. Avoid stacking large delays on essential controls.",
|
|
1212
|
+
"localization": "Text is caller content; translate normally and preserve source reading order regardless of stagger.",
|
|
1213
|
+
"reference": "hooks",
|
|
1214
|
+
"styling": "Use .contour-reveal and .contour-is-visible with released semantic color/line/spacing tokens. Preserve native structure, visible labels and owned state/ARIA; visual customization does not change the interaction contract."
|
|
1215
|
+
}
|
|
1216
|
+
},
|
|
1217
|
+
{
|
|
1218
|
+
"slug": "reveal-heading",
|
|
1219
|
+
"name": "RevealHeading",
|
|
1220
|
+
"family": "identity",
|
|
1221
|
+
"summary": "A fixed h2 whose line spans can animate inside a Reveal.",
|
|
1222
|
+
"props": [
|
|
1223
|
+
[
|
|
1224
|
+
"id / lines",
|
|
1225
|
+
"string / {text:ReactNode;accent?:boolean}[]",
|
|
1226
|
+
"Required",
|
|
1227
|
+
"Keep a unique heading id and meaningful text in semantic order."
|
|
1228
|
+
]
|
|
1229
|
+
],
|
|
1230
|
+
"keyboard": "Not a keyboard control and does not add a tab stop. Interactive children retain their native behavior; do not use this display as a substitute for a button or link.",
|
|
1231
|
+
"limits": "Always h2; no as/heading-level prop, controlled animation, root class/ref or arbitrary native attributes.",
|
|
1232
|
+
"tasks": "A fixed h2 whose line spans can animate inside a Reveal. Use for an actual second-level section heading. Use native headings of the appropriate level elsewhere rather than forcing every heading into this visual style.",
|
|
1233
|
+
"detail": {
|
|
1234
|
+
"use": "Use for an actual second-level section heading. Use native headings of the appropriate level elsewhere rather than forcing every heading into this visual style.",
|
|
1235
|
+
"anatomy": "h2 with caller id contains line spans and inner type-run spans; each line accepts ReactNode text and optional accent.",
|
|
1236
|
+
"state": "Pure heading data. Reveal or app state controls entrance styling; this component adds no observer or animation state itself.",
|
|
1237
|
+
"forms": "Not a successful form control: no name, required constraint or native reset behavior. Reset any application-owned content/request state separately.",
|
|
1238
|
+
"ref": "No public native-element ref is forwarded. Keep focus on actual native interactive children rather than making the presentation wrapper focusable.",
|
|
1239
|
+
"edgeCases": "Long lines and rich text must remain readable at narrow widths. Reduced-motion/static visibility belongs to the surrounding reveal/style contract.",
|
|
1240
|
+
"localization": "Translate lines without using decorative line breaks to change reading order. Test scripts/RTL that wrap differently.",
|
|
1241
|
+
"reference": "hooks",
|
|
1242
|
+
"styling": "Use .contour-type-line, .contour-type-run and accent hook with released semantic color/line/spacing tokens. Preserve native structure, visible labels and owned state/ARIA; visual customization does not change the interaction contract."
|
|
1243
|
+
}
|
|
1244
|
+
},
|
|
1245
|
+
{
|
|
1246
|
+
"slug": "scene-boundary",
|
|
1247
|
+
"name": "SceneBoundary",
|
|
1248
|
+
"family": "scene-boundary",
|
|
1249
|
+
"summary": "An error boundary that hides a failed optional child without removing surrounding content.",
|
|
1250
|
+
"props": [
|
|
1251
|
+
[
|
|
1252
|
+
"children",
|
|
1253
|
+
"ReactNode",
|
|
1254
|
+
"Required",
|
|
1255
|
+
"Keep a usable static fallback and any retry control outside the boundary."
|
|
1256
|
+
]
|
|
1257
|
+
],
|
|
1258
|
+
"keyboard": "No added focus behavior or control. Keep fallback/retry in native labelled controls and restore useful focus in the application when replacing interactive children.",
|
|
1259
|
+
"limits": "Not a catch-all for event-handler, asynchronous callback, server-render or network errors. No automatic retry/fallback slot, loading state or GPU disposal. Existing optional3D APIs remain experimental.",
|
|
1260
|
+
"tasks": "An error boundary that hides a failed optional child without removing surrounding content. Use around an optional scene/rendering child with a useful static fallback outside it. Do not use it to hide essential UI failures or silently imply a failed operation succeeded.",
|
|
1261
|
+
"detail": {
|
|
1262
|
+
"use": "Use around an optional scene/rendering child with a useful static fallback outside it. Do not use it to hide essential UI failures or silently imply a failed operation succeeded.",
|
|
1263
|
+
"anatomy": "React class error boundary renders children or null after a caught descendant render/lifecycle error. It renders no wrapper DOM and owns no renderer resources.",
|
|
1264
|
+
"state": "Internal failed=false becomes true after a caught error. A caller key/remount resets the boundary; no reset/fallback/callback prop is exposed.",
|
|
1265
|
+
"forms": "Not a successful form control: no name, required constraint or native reset behavior. Reset any application-owned content/request state separately.",
|
|
1266
|
+
"ref": "A React class ref is an instance, not a native focus target; no public focus/retry command is defined.",
|
|
1267
|
+
"edgeCases": "Test missing/failed lazy modules, render failures and unmount. Dispose GPU work in the scene owner and keep honest external fallback text; remounting must not imply a service recovered.",
|
|
1268
|
+
"localization": "Translate app-owned static fallback/retry/status text. The boundary supplies no user-facing strings itself.",
|
|
1269
|
+
"reference": "three",
|
|
1270
|
+
"styling": "No component-specific visual wrapper contract. Style application content with released semantic tokens; preserve its native semantics and meaningful fallback."
|
|
1271
|
+
}
|
|
1272
|
+
},
|
|
1273
|
+
{
|
|
1274
|
+
"slug": "scroll-progress",
|
|
1275
|
+
"name": "ScrollProgress",
|
|
1276
|
+
"family": "motion",
|
|
1277
|
+
"summary": "A decorative page-scroll progress line without interactive semantics.",
|
|
1278
|
+
"props": [],
|
|
1279
|
+
"keyboard": "Not a keyboard control and does not add a tab stop. Interactive children retain their native behavior; do not use this display as a substitute for a button or link.",
|
|
1280
|
+
"limits": "Document/window scope, not nested-scroll containers. No progress label, callback/ref, controlled value or business completion semantics.",
|
|
1281
|
+
"tasks": "A decorative page-scroll progress line without interactive semantics. Use as a supplemental document-position cue. Keep real navigation/headings and reading order; this is not measured upload/task completion.",
|
|
1282
|
+
"detail": {
|
|
1283
|
+
"use": "Use as a supplemental document-position cue. Keep real navigation/headings and reading order; this is not measured upload/task completion.",
|
|
1284
|
+
"anatomy": "aria-hidden div is fixed by CSS; a frame-coalesced listener reads document scroll height/window scroll and writes its progress variable.",
|
|
1285
|
+
"state": "No props. Initial measurement plus scroll/resize updates; non-scrollable documents yield 0. Cleanup removes listeners and pending frame.",
|
|
1286
|
+
"forms": "Not a successful form control: no name, required constraint or native reset behavior. Reset any application-owned content/request state separately.",
|
|
1287
|
+
"ref": "No public native-element ref is forwarded. Keep focus on actual native interactive children rather than making the presentation wrapper focusable.",
|
|
1288
|
+
"edgeCases": "Check non-scrollable/long documents, resize/unmount and layout changes. It does not observe every asynchronous content-height change unless scroll/resize updates occur.",
|
|
1289
|
+
"localization": "No text; keep accessible document navigation separate and verify surrounding direction/styles.",
|
|
1290
|
+
"reference": "hooks",
|
|
1291
|
+
"styling": "Use .contour-scroll-progress and --scroll-progress with released semantic color/line/spacing tokens. Preserve native structure, visible labels and owned state/ARIA; visual customization does not change the interaction contract."
|
|
1292
|
+
}
|
|
1293
|
+
},
|
|
1294
|
+
{
|
|
1295
|
+
"slug": "section-label",
|
|
1296
|
+
"name": "SectionLabel",
|
|
1297
|
+
"family": "identity",
|
|
1298
|
+
"summary": "A numbered eyebrow using section metadata and a secondary note.",
|
|
1299
|
+
"props": [
|
|
1300
|
+
[
|
|
1301
|
+
"section",
|
|
1302
|
+
"Section",
|
|
1303
|
+
"Required",
|
|
1304
|
+
"Supply id/number/label/title; only number/title are displayed."
|
|
1305
|
+
],
|
|
1306
|
+
[
|
|
1307
|
+
"aside",
|
|
1308
|
+
"string",
|
|
1309
|
+
"Required",
|
|
1310
|
+
"Secondary nonessential note; may be hidden on small screens."
|
|
1311
|
+
]
|
|
1312
|
+
],
|
|
1313
|
+
"keyboard": "Not a keyboard control and does not add a tab stop. Interactive children retain their native behavior; do not use this display as a substitute for a button or link.",
|
|
1314
|
+
"limits": "No configurable heading level, formatting callback, forwarded ref or automatic navigation. The aside must not contain essential instructions.",
|
|
1315
|
+
"tasks": "A numbered eyebrow using section metadata and a secondary note. Use as supporting section context beside a real heading. It is not itself a heading, anchor, scroll-spy target or navigation control.",
|
|
1316
|
+
"detail": {
|
|
1317
|
+
"use": "Use as supporting section context beside a real heading. It is not itself a heading, anchor, scroll-spy target or navigation control.",
|
|
1318
|
+
"anatomy": "Div contains formatIndex(section.number) plus section.title, and an aside span that may hide at narrow widths.",
|
|
1319
|
+
"state": "Pure section/aside data. Section id/label remain caller metadata; this component does not create that section anchor.",
|
|
1320
|
+
"forms": "Not a successful form control: no name, required constraint or native reset behavior. Reset any application-owned content/request state separately.",
|
|
1321
|
+
"ref": "No public native-element ref is forwarded. Keep focus on actual native interactive children rather than making the presentation wrapper focusable.",
|
|
1322
|
+
"edgeCases": "Keep actual section anchors/headings in application markup and long section text bounded. No request/form lifecycle is supplied.",
|
|
1323
|
+
"localization": "Translate title/aside. formatIndex uses the library two-digit representation; localized numbering is not a prop.",
|
|
1324
|
+
"reference": "props",
|
|
1325
|
+
"styling": "Use .contour-section-label with released semantic color/line/spacing tokens. Preserve native structure, visible labels and owned state/ARIA; visual customization does not change the interaction contract."
|
|
1326
|
+
}
|
|
1327
|
+
},
|
|
1328
|
+
{
|
|
1329
|
+
"slug": "segmented-control",
|
|
1330
|
+
"name": "SegmentedControl",
|
|
1331
|
+
"family": "choices",
|
|
1332
|
+
"summary": "A controlled single-choice button group with radio semantics and roving focus.",
|
|
1333
|
+
"props": [
|
|
1334
|
+
[
|
|
1335
|
+
"label / options",
|
|
1336
|
+
"string / {value,label}[]",
|
|
1337
|
+
"Required",
|
|
1338
|
+
"Name the group and keep options nonempty with unique values."
|
|
1339
|
+
],
|
|
1340
|
+
[
|
|
1341
|
+
"value / onChange",
|
|
1342
|
+
"Value / (value:Value)=>void",
|
|
1343
|
+
"Required",
|
|
1344
|
+
"Update the selected value; no default/uncontrolled API."
|
|
1345
|
+
]
|
|
1346
|
+
],
|
|
1347
|
+
"keyboard": "Tab enters the selected button. Arrows/Home/End move and select with RTL-aware horizontal navigation; Enter/Space uses native button activation.",
|
|
1348
|
+
"limits": "No name/form/required serialization, disabled-option support, async state or forwarded aggregate ref. An absent selected value leaves no selected tab stop; validate it in the parent.",
|
|
1349
|
+
"tasks": "A controlled single-choice button group with radio semantics and roving focus. Use for a small mutually exclusive view/filter choice. Use native RadioGroup for successful form inputs and required validation; this does not create a global density/theme API.",
|
|
1350
|
+
"detail": {
|
|
1351
|
+
"use": "Use for a small mutually exclusive view/filter choice. Use native RadioGroup for successful form inputs and required validation; this does not create a global density/theme API.",
|
|
1352
|
+
"anatomy": "Named radiogroup contains native button role=radio for each option. Selected item is the tab stop and has aria-checked.",
|
|
1353
|
+
"state": "value and onChange are required controlled state; options use unique stable string values. Caller must keep value present in the set.",
|
|
1354
|
+
"forms": "Buttons are type=button and are not submitted. Use RadioGroup or an application-owned successful control if the selection must be in FormData.",
|
|
1355
|
+
"ref": "No public native-element ref is forwarded. Keep focus on actual native interactive children rather than making the presentation wrapper focusable.",
|
|
1356
|
+
"edgeCases": "Own pending/error and keep query/results stable while a view changes. Long labels should wrap rather than create offscreen controls.",
|
|
1357
|
+
"localization": "Translate group/options and supply dir. Stable IDs survive translation; do not use translated labels as selection identity.",
|
|
1358
|
+
"reference": "props",
|
|
1359
|
+
"styling": "Use .contour-segmented and [aria-checked] buttons with released semantic color/line/spacing tokens. Preserve native structure, visible labels and owned state/ARIA; visual customization does not change the interaction contract."
|
|
1360
|
+
}
|
|
1361
|
+
},
|
|
1362
|
+
{
|
|
1363
|
+
"slug": "select-field",
|
|
1364
|
+
"name": "SelectField",
|
|
1365
|
+
"family": "text-inputs",
|
|
1366
|
+
"summary": "A native select with a visible label, linked supporting text and a native ref.",
|
|
1367
|
+
"props": [
|
|
1368
|
+
[
|
|
1369
|
+
"label / options",
|
|
1370
|
+
"string / {value: string; label: string}[]",
|
|
1371
|
+
"Required",
|
|
1372
|
+
"Supply unique values and understandable labels."
|
|
1373
|
+
],
|
|
1374
|
+
[
|
|
1375
|
+
"value / defaultValue / onChange",
|
|
1376
|
+
"Native select props",
|
|
1377
|
+
"Uncontrolled when value is omitted",
|
|
1378
|
+
"Read event.currentTarget.value. Keep controlled state in the application."
|
|
1379
|
+
],
|
|
1380
|
+
[
|
|
1381
|
+
"placeholder",
|
|
1382
|
+
"string",
|
|
1383
|
+
"Omitted",
|
|
1384
|
+
"Adds a disabled empty option. Use an empty initial value when the visitor must choose."
|
|
1385
|
+
],
|
|
1386
|
+
[
|
|
1387
|
+
"hint / error",
|
|
1388
|
+
"string",
|
|
1389
|
+
"Omitted",
|
|
1390
|
+
"Messages are linked to the select; error sets aria-invalid."
|
|
1391
|
+
],
|
|
1392
|
+
[
|
|
1393
|
+
"id / name / form / ref",
|
|
1394
|
+
"Native select props and React.Ref<HTMLSelectElement>",
|
|
1395
|
+
"Generated id",
|
|
1396
|
+
"Use a name for FormData and a ref for focus. Caller descriptions are preserved."
|
|
1397
|
+
]
|
|
1398
|
+
],
|
|
1399
|
+
"keyboard": "The platform supplies native select keyboard behavior. Tab enters and leaves the control; selection and popup keys follow the browser and operating system.",
|
|
1400
|
+
"limits": "No searchable list, asynchronous option fetching or grouped-option contract. Supply loading, failed and empty option states in the surrounding application. Native styling and popup behavior vary by platform.",
|
|
1401
|
+
"tasks": "select options dropdown native form focus ref",
|
|
1402
|
+
"detail": {
|
|
1403
|
+
"use": "Use for a short native allowed-value list. Use Combobox for search or remote results; no free-text selection is offered here.",
|
|
1404
|
+
"anatomy": "Field connects label and supporting text to a native select; options are value/label records. Placeholder renders a disabled empty option.",
|
|
1405
|
+
"state": "Native value/onChange or defaultValue ownership. Loading, unavailable data and failed requests belong outside the select.",
|
|
1406
|
+
"forms": "name/form participate in native FormData and external form ownership. Native reset restores defaults; controlled owners restore their value. Use required and an empty initial value when a choice is mandatory.",
|
|
1407
|
+
"ref": "Forwarded ref targets HTMLSelectElement. Caller id and descriptions are preserved.",
|
|
1408
|
+
"edgeCases": "Use unique option values. Explain empty or failed option sources rather than presenting a disabled select as a successful response. Native popup geometry and styling vary by platform.",
|
|
1409
|
+
"localization": "Translate labels/options and test long translations. Browser/OS supply native popup keys and localized validation; verify your target platforms.",
|
|
1410
|
+
"reference": "forms",
|
|
1411
|
+
"styling": "Use the released scoped CSS and semantic tokens inside contour-root/ThemeScope. Preserve native semantics, public part/state hooks and geometry ownership; see the component-specific anatomy and STYLING.md."
|
|
1412
|
+
}
|
|
1413
|
+
},
|
|
1414
|
+
{
|
|
1415
|
+
"slug": "skeleton",
|
|
1416
|
+
"name": "Skeleton",
|
|
1417
|
+
"family": "feedback",
|
|
1418
|
+
"summary": "A hidden-from-assistive-tech visual placeholder with line, block or circle shape.",
|
|
1419
|
+
"props": [
|
|
1420
|
+
[
|
|
1421
|
+
"shape",
|
|
1422
|
+
"line | block | circle",
|
|
1423
|
+
"line",
|
|
1424
|
+
"Match the expected visual footprint."
|
|
1425
|
+
],
|
|
1426
|
+
[
|
|
1427
|
+
"width / height",
|
|
1428
|
+
"CSS length strings",
|
|
1429
|
+
"Omitted",
|
|
1430
|
+
"Caller-owned dimensions; ensure narrow layouts remain bounded."
|
|
1431
|
+
]
|
|
1432
|
+
],
|
|
1433
|
+
"keyboard": "Not a keyboard control and does not add a tab stop. Interactive children retain their native behavior; do not use this display as a substitute for a button or link.",
|
|
1434
|
+
"limits": "No text label, data fetch, role=status, automatic layout measurement or forwarded ref. A placeholder is not content or an error recovery flow.",
|
|
1435
|
+
"tasks": "A hidden-from-assistive-tech visual placeholder with line, block or circle shape. Use while real content loads. Pair with an accessible loading/status description; use a truthful empty/error state if work ends without content.",
|
|
1436
|
+
"detail": {
|
|
1437
|
+
"use": "Use while real content loads. Pair with an accessible loading/status description; use a truthful empty/error state if work ends without content.",
|
|
1438
|
+
"anatomy": "Noninteractive aria-hidden span takes width/height CSS strings and shape hooks. It contains no actual data or accessible text.",
|
|
1439
|
+
"state": "Pure visual placeholder. shape defaults line; caller owns when it disappears and any aria-busy state on the content region.",
|
|
1440
|
+
"forms": "Not a successful form control: no name, required constraint or native reset behavior. Reset any application-owned content/request state separately.",
|
|
1441
|
+
"ref": "No public native-element ref is forwarded. Keep focus on actual native interactive children rather than making the presentation wrapper focusable.",
|
|
1442
|
+
"edgeCases": "Reserve sensible layout space without clipping; make completion/error visible outside the skeleton. Motion may stop under reduced motion.",
|
|
1443
|
+
"localization": "Shape has no translatable text. Translate the surrounding real loading/error status and check direction/width on translated content.",
|
|
1444
|
+
"reference": "props",
|
|
1445
|
+
"styling": "Use .contour-skeleton and shape hooks with released semantic color/line/spacing tokens. Preserve native structure, visible labels and owned state/ARIA; visual customization does not change the interaction contract."
|
|
1446
|
+
}
|
|
1447
|
+
},
|
|
1448
|
+
{
|
|
1449
|
+
"slug": "slider",
|
|
1450
|
+
"name": "Slider",
|
|
1451
|
+
"family": "choices",
|
|
1452
|
+
"summary": "A native range input with numeric callbacks, formatted value text and reset-aware readout.",
|
|
1453
|
+
"props": [
|
|
1454
|
+
[
|
|
1455
|
+
"label",
|
|
1456
|
+
"string",
|
|
1457
|
+
"Required",
|
|
1458
|
+
"Provide the quantity name and nearby units."
|
|
1459
|
+
],
|
|
1460
|
+
[
|
|
1461
|
+
"value / defaultValue / onChange",
|
|
1462
|
+
"number / number / (value: number) => void",
|
|
1463
|
+
"Uncontrolled native-sanitized midpoint",
|
|
1464
|
+
"Callback is numeric, not a native event."
|
|
1465
|
+
],
|
|
1466
|
+
[
|
|
1467
|
+
"min / max / step",
|
|
1468
|
+
"number / number / number | \"any\"",
|
|
1469
|
+
"0 / 100 / 1",
|
|
1470
|
+
"Provide finite consistent bounds and a valid positive step."
|
|
1471
|
+
],
|
|
1472
|
+
[
|
|
1473
|
+
"format",
|
|
1474
|
+
"(value: number) => string",
|
|
1475
|
+
"String",
|
|
1476
|
+
"Readout and aria-valuetext formatting, not submission parsing."
|
|
1477
|
+
],
|
|
1478
|
+
[
|
|
1479
|
+
"name / form / disabled",
|
|
1480
|
+
"Native input props",
|
|
1481
|
+
"Omitted",
|
|
1482
|
+
"Native successful-control and external form ownership."
|
|
1483
|
+
]
|
|
1484
|
+
],
|
|
1485
|
+
"keyboard": "Native range arrows/Home/End/Page keys follow the browser and direction. The forwarded input ref supports focus. Do not replace keyboard interaction with a drag-only wrapper.",
|
|
1486
|
+
"limits": "One scalar range only; no multi-thumb/rich numeric parsing/required constraint. Display formatting does not change FormData serialization or native sanitization.",
|
|
1487
|
+
"tasks": "A native range input with numeric callbacks, formatted value text and reset-aware readout. Use for a bounded approximate numeric choice. Use a native number/text input for precise typed entry or locale-sensitive parsing; this is not NumberField.",
|
|
1488
|
+
"detail": {
|
|
1489
|
+
"use": "Use for a bounded approximate numeric choice. Use a native number/text input for precise typed entry or locale-sensitive parsing; this is not NumberField.",
|
|
1490
|
+
"anatomy": "Visible label/output accompany input type=range and linked hint/error. The native range owns sanitization, min/max/step and keyboard interaction.",
|
|
1491
|
+
"state": "value/onChange controls a number; defaultValue captures the initial uncontrolled value. If omitted, the initial midpoint is (min + max(min,max))/2 and the browser sanitizes it. format customizes readout/accessible text.",
|
|
1492
|
+
"forms": "name/form support native and external-owner submission as a numeric string; disabled omits the control. required is deliberately not supported by range. Reset restores uncontrolled input/readout or the parent-controlled value, and cancellation is respected.",
|
|
1493
|
+
"ref": "Forwarded HTMLInputElement for the visible native range.",
|
|
1494
|
+
"edgeCases": "Check bounds, step, zero-length/reversed inputs in your application and keep long formatted readouts readable. Request loading/failure and reset of controlled state belong to the parent.",
|
|
1495
|
+
"localization": "Use format for localized units/value text. Native serialized value remains a numeric string; verify RTL range behavior and real mobile controls.",
|
|
1496
|
+
"reference": "forms",
|
|
1497
|
+
"styling": "Use .contour-slider wrapper and its native range/output with released semantic color/line/spacing tokens. Preserve native structure, visible labels and owned state/ARIA; visual customization does not change the interaction contract."
|
|
1498
|
+
}
|
|
1499
|
+
},
|
|
1500
|
+
{
|
|
1501
|
+
"slug": "spinner",
|
|
1502
|
+
"name": "Spinner",
|
|
1503
|
+
"family": "feedback",
|
|
1504
|
+
"summary": "A decorative spinning mark with an accessible status label.",
|
|
1505
|
+
"props": [
|
|
1506
|
+
[
|
|
1507
|
+
"size",
|
|
1508
|
+
"sm | md | lg",
|
|
1509
|
+
"md",
|
|
1510
|
+
"Icon sizes16/24/40; no percentage meaning."
|
|
1511
|
+
],
|
|
1512
|
+
[
|
|
1513
|
+
"label",
|
|
1514
|
+
"string",
|
|
1515
|
+
"Loading",
|
|
1516
|
+
"Name the actual task and translate it."
|
|
1517
|
+
],
|
|
1518
|
+
[
|
|
1519
|
+
"className",
|
|
1520
|
+
"string",
|
|
1521
|
+
"Omitted",
|
|
1522
|
+
"Append scoped styling without removing the status label."
|
|
1523
|
+
]
|
|
1524
|
+
],
|
|
1525
|
+
"keyboard": "Not a keyboard control and does not add a tab stop. Interactive children retain their native behavior; do not use this display as a substitute for a button or link.",
|
|
1526
|
+
"limits": "No request lifecycle, progress value, cancellation control or forwarded ref. Do not leave a permanent spinner when a failure is known.",
|
|
1527
|
+
"tasks": "A decorative spinning mark with an accessible status label. Use for unknown-duration ongoing work, with context. Use ProgressBar for real measured completion and adjacent errors/retry for failed work.",
|
|
1528
|
+
"detail": {
|
|
1529
|
+
"use": "Use for unknown-duration ongoing work, with context. Use ProgressBar for real measured completion and adjacent errors/retry for failed work.",
|
|
1530
|
+
"anatomy": "Root span role=status contains a hidden label and decorative asterisk. Size controls icon geometry; className appends root hooks.",
|
|
1531
|
+
"state": "Pure indication of caller-owned work; size defaults md and label Loading. The animation is not evidence of request success.",
|
|
1532
|
+
"forms": "Not a successful form control: no name, required constraint or native reset behavior. Reset any application-owned content/request state separately.",
|
|
1533
|
+
"ref": "No public native-element ref is forwarded. Keep focus on actual native interactive children rather than making the presentation wrapper focusable.",
|
|
1534
|
+
"edgeCases": "Show truthful pending/failed/retry states. Reduced-motion appearance may be static; retain a meaningful textual status and avoid duplicate live announcements.",
|
|
1535
|
+
"localization": "Translate label and related status/error/action text. Actual live-region behavior requires manual platform checks.",
|
|
1536
|
+
"reference": "props",
|
|
1537
|
+
"styling": "Use .contour-spinner and size hooks with released semantic color/line/spacing tokens. Preserve native structure, visible labels and owned state/ARIA; visual customization does not change the interaction contract."
|
|
1538
|
+
}
|
|
1539
|
+
},
|
|
1540
|
+
{
|
|
1541
|
+
"slug": "stat",
|
|
1542
|
+
"name": "Stat",
|
|
1543
|
+
"family": "metadata",
|
|
1544
|
+
"summary": "A value, optional suffix and descriptive label without automatic animation.",
|
|
1545
|
+
"props": [
|
|
1546
|
+
[
|
|
1547
|
+
"value / label",
|
|
1548
|
+
"ReactNode / string",
|
|
1549
|
+
"Required",
|
|
1550
|
+
"Explain the quantity and its source/period nearby."
|
|
1551
|
+
],
|
|
1552
|
+
[
|
|
1553
|
+
"suffix",
|
|
1554
|
+
"string",
|
|
1555
|
+
"Omitted",
|
|
1556
|
+
"Units/suffix are visual text, not numeric parsing."
|
|
1557
|
+
]
|
|
1558
|
+
],
|
|
1559
|
+
"keyboard": "Not a keyboard control and does not add a tab stop. Interactive children retain their native behavior; do not use this display as a substitute for a button or link.",
|
|
1560
|
+
"limits": "No calculation, CountUp behavior, invalid-number validation, automatic live announcement or external root ref.",
|
|
1561
|
+
"tasks": "A value, optional suffix and descriptive label without automatic animation. Use for a meaningful measured value with units/context. Label illustrative counts and estimates; use CountUp only when decorative numeric animation is appropriate.",
|
|
1562
|
+
"detail": {
|
|
1563
|
+
"use": "Use for a meaningful measured value with units/context. Label illustrative counts and estimates; use CountUp only when decorative numeric animation is appropriate.",
|
|
1564
|
+
"anatomy": "Container holds a strong value/optional suffix and a mono label. It is not a live region or a chart.",
|
|
1565
|
+
"state": "Pure caller-owned value; no calculation, data source, formatting or refresh lifecycle.",
|
|
1566
|
+
"forms": "Not a successful form control: no name, required constraint or native reset behavior. Reset any application-owned content/request state separately.",
|
|
1567
|
+
"ref": "No public native-element ref is forwarded. Keep focus on actual native interactive children rather than making the presentation wrapper focusable.",
|
|
1568
|
+
"edgeCases": "Show unavailable/stale/error state honestly instead of a fabricated value. Check long values/units, both themes and responsive overflow.",
|
|
1569
|
+
"localization": "Format the value/units with application locale APIs before rendering; suffix does not automatically pluralize or format numbers.",
|
|
1570
|
+
"reference": "props",
|
|
1571
|
+
"styling": "Use .contour-stat and suffix hook with released semantic color/line/spacing tokens. Preserve native structure, visible labels and owned state/ARIA; visual customization does not change the interaction contract."
|
|
1572
|
+
}
|
|
1573
|
+
},
|
|
1574
|
+
{
|
|
1575
|
+
"slug": "stepper",
|
|
1576
|
+
"name": "Stepper",
|
|
1577
|
+
"family": "navigation",
|
|
1578
|
+
"summary": "A read-only ordered progress sequence with one zero-based current step.",
|
|
1579
|
+
"props": [
|
|
1580
|
+
[
|
|
1581
|
+
"steps / current",
|
|
1582
|
+
"step records[] / number",
|
|
1583
|
+
"Required",
|
|
1584
|
+
"Unique labels and a valid zero-based current index."
|
|
1585
|
+
],
|
|
1586
|
+
[
|
|
1587
|
+
"label",
|
|
1588
|
+
"string",
|
|
1589
|
+
"Progress",
|
|
1590
|
+
"Translate the ordered-list accessible name."
|
|
1591
|
+
]
|
|
1592
|
+
],
|
|
1593
|
+
"keyboard": "Not a keyboard control and does not add a tab stop. Interactive children retain their native behavior; do not use this display as a substitute for a button or link.",
|
|
1594
|
+
"limits": "No onChange, disabled/async/error state, clicking or current-range sanitization. Built-in hidden state words complete/current/upcoming and numeric formatting are not configurable.",
|
|
1595
|
+
"tasks": "A read-only ordered progress sequence with one zero-based current step. Use to describe progress through known stages. Supply separate real navigation controls; it is not a wizard engine or clickable step navigation.",
|
|
1596
|
+
"detail": {
|
|
1597
|
+
"use": "Use to describe progress through known stages. Supply separate real navigation controls; it is not a wizard engine or clickable step navigation.",
|
|
1598
|
+
"anatomy": "Ordered list with named progress, decorative number/check markers, labels/descriptions and aria-current=step on the current item.",
|
|
1599
|
+
"state": "Caller supplies steps/current; current is a zero-based index. Previous items are complete, following items upcoming; no validation or transitions are owned.",
|
|
1600
|
+
"forms": "Not a successful form control: no name, required constraint or native reset behavior. Reset any application-owned content/request state separately.",
|
|
1601
|
+
"ref": "No public native-element ref is forwarded. Keep focus on actual native interactive children rather than making the presentation wrapper focusable.",
|
|
1602
|
+
"edgeCases": "Show failed/pending business state beside the steps rather than claiming completion. Keep long descriptions/narrow layouts and zero/last step correct.",
|
|
1603
|
+
"localization": "Translate label/step text. Hidden state suffixes are currently English and numbers use formatIndex; do not claim complete localization.",
|
|
1604
|
+
"reference": "props",
|
|
1605
|
+
"styling": "Use .contour-stepper and current/complete/upcoming hooks with released semantic color/line/spacing tokens. Preserve native structure, visible labels and owned state/ARIA; visual customization does not change the interaction contract."
|
|
1606
|
+
}
|
|
1607
|
+
},
|
|
1608
|
+
{
|
|
1609
|
+
"slug": "switch",
|
|
1610
|
+
"name": "Switch",
|
|
1611
|
+
"family": "choices",
|
|
1612
|
+
"summary": "A button-based switch with native checkbox-backed submission, validation and reset.",
|
|
1613
|
+
"props": [
|
|
1614
|
+
["label", "string", "Required", "Use an understandable setting name."],
|
|
1615
|
+
[
|
|
1616
|
+
"checked / defaultChecked / onChange",
|
|
1617
|
+
"boolean / boolean / (checked: boolean) => void",
|
|
1618
|
+
"Uncontrolled false",
|
|
1619
|
+
"Choose controlled or default ownership."
|
|
1620
|
+
],
|
|
1621
|
+
[
|
|
1622
|
+
"name / form / value",
|
|
1623
|
+
"string",
|
|
1624
|
+
"value=\"on\"; name/form omitted",
|
|
1625
|
+
"Checked, enabled backing input submits this value."
|
|
1626
|
+
],
|
|
1627
|
+
[
|
|
1628
|
+
"required / requiredMessage",
|
|
1629
|
+
"boolean / string",
|
|
1630
|
+
"Message: Turn on this option to continue.",
|
|
1631
|
+
"Native invalid feedback focuses the visible button unless caller owns onInvalid."
|
|
1632
|
+
],
|
|
1633
|
+
[
|
|
1634
|
+
"description / error / onInvalid",
|
|
1635
|
+
"string / string / native invalid handler",
|
|
1636
|
+
"Omitted",
|
|
1637
|
+
"Preserve linked supporting text and caller-owned validation."
|
|
1638
|
+
]
|
|
1639
|
+
],
|
|
1640
|
+
"keyboard": "The native button toggles on Enter/Space. Its role and aria-checked communicate state; disabled prevents activation. The forwarded button ref supports programmatic focus.",
|
|
1641
|
+
"limits": "The ref is a button, not the hidden checkbox. Callback is boolean, not a native change event. Persistence, service errors and immediate-save policy remain application-owned.",
|
|
1642
|
+
"tasks": "A button-based switch with native checkbox-backed submission, validation and reset. Use for an on/off setting. Use Checkbox when the user is selecting an item or acknowledging a statement; a switch does not perform a backend operation by itself.",
|
|
1643
|
+
"detail": {
|
|
1644
|
+
"use": "Use for an on/off setting. Use Checkbox when the user is selecting an item or acknowledging a statement; a switch does not perform a backend operation by itself.",
|
|
1645
|
+
"anatomy": "Visible button role=switch links to its label, description and error. A hidden native checkbox supplies form participation; it is not the focus target.",
|
|
1646
|
+
"state": "checked/onChange is controlled; defaultChecked captures initial uncontrolled state, otherwise false. onChange receives the next boolean. A caller onClick may prevent activation.",
|
|
1647
|
+
"forms": "Named checked enabled state submits value (default \"on\"); unchecked/disabled is omitted. form supports external owners; required uses the backing checkbox with visible-button feedback. Native reset restores uncontrolled defaults without synthetic change callbacks; controlled owners reset explicitly.",
|
|
1648
|
+
"ref": "Forwarded HTMLButtonElement, not the hidden HTMLInputElement.",
|
|
1649
|
+
"edgeCases": "Expose pending/save failure without claiming a successful setting change. Keep the label and validation visible; loading is an application composition rather than a Switch prop.",
|
|
1650
|
+
"localization": "Translate label/description/error/requiredMessage. RTL follows surrounding direction; browser validation and actual announcements still require platform checks.",
|
|
1651
|
+
"reference": "forms",
|
|
1652
|
+
"styling": "Use .contour-switch, .contour-switch-track and checked/invalid states with released semantic color/line/spacing tokens. Preserve native structure, visible labels and owned state/ARIA; visual customization does not change the interaction contract."
|
|
1653
|
+
}
|
|
1654
|
+
},
|
|
1655
|
+
{
|
|
1656
|
+
"slug": "table",
|
|
1657
|
+
"name": "Table",
|
|
1658
|
+
"family": "selection",
|
|
1659
|
+
"summary": "Semantic table styling for native rows, cells and application-owned table engines.",
|
|
1660
|
+
"props": [
|
|
1661
|
+
[
|
|
1662
|
+
"caption / children",
|
|
1663
|
+
"string / ReactNode",
|
|
1664
|
+
"Required",
|
|
1665
|
+
"Supply semantic table children; the component owns caption."
|
|
1666
|
+
],
|
|
1667
|
+
[
|
|
1668
|
+
"showCaption",
|
|
1669
|
+
"boolean",
|
|
1670
|
+
"false",
|
|
1671
|
+
"Caption remains accessible when visually hidden."
|
|
1672
|
+
],
|
|
1673
|
+
[
|
|
1674
|
+
"scrollProps",
|
|
1675
|
+
"NativePartProps<div>",
|
|
1676
|
+
"Omitted",
|
|
1677
|
+
"Configure the scroll wrapper, including its native ref."
|
|
1678
|
+
],
|
|
1679
|
+
[
|
|
1680
|
+
"ref",
|
|
1681
|
+
"React.Ref<HTMLTableElement>",
|
|
1682
|
+
"Omitted",
|
|
1683
|
+
"Targets the table, not its wrapper."
|
|
1684
|
+
]
|
|
1685
|
+
],
|
|
1686
|
+
"keyboard": "Native table reading order. Interactive cell controls retain native keyboard behavior; Table adds no grid roving focus.",
|
|
1687
|
+
"limits": "No built-in data model, remote fetch, pagination, selection or virtualization. Compose the public recipe for controlled TanStack table integration.",
|
|
1688
|
+
"tasks": "table semantic tanstack remote sort pagination rows caption",
|
|
1689
|
+
"detail": {
|
|
1690
|
+
"use": "Use for semantic application-owned rows/cells or a table-engine integration. DataTable provides a bounded local-sort convenience API. Neither is a virtualized grid.",
|
|
1691
|
+
"anatomy": "Scrollable wrapper contains native table and an owned caption. Supply thead/tbody/tr/th/td with correct scopes; do not add a second caption. scrollProps customizes the wrapper.",
|
|
1692
|
+
"state": "Table has no fetching, sorting, pagination or selection state. showCaption defaults false while the caption remains accessible. The remote recipe owns its query and results.",
|
|
1693
|
+
"forms": "Not a form control. Place explicit labelled controls in cells where needed and own selection/submission separately.",
|
|
1694
|
+
"ref": "Forwarded ref targets HTMLTableElement; scrollProps.ref targets the wrapper div.",
|
|
1695
|
+
"edgeCases": "Provide truthful loading, empty, no-match, permission and service-failure states. Stable row IDs, remote totals, cancellation and stale-result protection are application contracts. Long cells can scroll at narrow widths.",
|
|
1696
|
+
"localization": "Translate caption/headings/status and format numbers/dates using your application locale. Use appropriate th scope and check RTL horizontal scrolling; a visual sort arrow alone is insufficient.",
|
|
1697
|
+
"reference": "recipes",
|
|
1698
|
+
"styling": "Use the released scoped CSS and semantic tokens inside contour-root/ThemeScope. Preserve native semantics, public part/state hooks and geometry ownership; see the component-specific anatomy and STYLING.md."
|
|
1699
|
+
}
|
|
1700
|
+
},
|
|
1701
|
+
{
|
|
1702
|
+
"slug": "tabs",
|
|
1703
|
+
"name": "Tabs",
|
|
1704
|
+
"family": "navigation",
|
|
1705
|
+
"summary": "Automatic-selection horizontal tabs for switching related local views.",
|
|
1706
|
+
"props": [
|
|
1707
|
+
["label", "string", "Required", "Accessible name of the tab list."],
|
|
1708
|
+
[
|
|
1709
|
+
"tabs",
|
|
1710
|
+
"{id, label, content}[]",
|
|
1711
|
+
"Required",
|
|
1712
|
+
"Use stable, unique ids and keep content relevant to the same task."
|
|
1713
|
+
],
|
|
1714
|
+
[
|
|
1715
|
+
"defaultTabId",
|
|
1716
|
+
"string",
|
|
1717
|
+
"First available tab",
|
|
1718
|
+
"Initial selection. Invalid ids fall back to the first tab; an empty list renders no selected tab."
|
|
1719
|
+
],
|
|
1720
|
+
[
|
|
1721
|
+
"activeTabId / onTabChange",
|
|
1722
|
+
"string / (id: string) => void",
|
|
1723
|
+
"Uncontrolled when activeTabId is omitted",
|
|
1724
|
+
"Update activeTabId in response to onTabChange for controlled selection. The application owns persistence and URL synchronization."
|
|
1725
|
+
]
|
|
1726
|
+
],
|
|
1727
|
+
"keyboard": "Left/Right select and focus the adjacent tab. Home/End move to first/last. The active panel follows the focused tab.",
|
|
1728
|
+
"limits": "No disabled-tab contract or automatic URL synchronization. Use stable ids, and keep controlled or uncontrolled ownership consistent.",
|
|
1729
|
+
"tasks": "tabs panels navigation switch controlled keyboard",
|
|
1730
|
+
"detail": {
|
|
1731
|
+
"use": "Use for related local views. Use anchors/navigation for routes, and avoid automatic activation for panels with expensive work that should require confirmation.",
|
|
1732
|
+
"anatomy": "Root div contains a named tablist and matched tab/button-panel IDs. listProps and each item's buttonProps/panelProps target typed native parts.",
|
|
1733
|
+
"state": "activeTabId/onTabChange is controlled; defaultTabId initializes uncontrolled selection. Stable IDs survive reorder. Invalid selection falls back to an available tab; empty arrays have no selected panel.",
|
|
1734
|
+
"forms": "Tab buttons are type=button and do not submit a form. Tabs does not reset application panel state or synchronize URL/history.",
|
|
1735
|
+
"ref": "Forwarded ref targets the root div; part refs target list, tab buttons and panels.",
|
|
1736
|
+
"edgeCases": "There is no disabled-tab contract. Keep ownership consistent and preserve important panel state explicitly. Loading/error belong inside the relevant panel; test long labels without clipped navigation.",
|
|
1737
|
+
"localization": "Translate the list name and labels. Left/Right follows inherited RTL; Home/End choose endpoints. Check your panel reading direction and mixed-language labels.",
|
|
1738
|
+
"reference": "composition",
|
|
1739
|
+
"styling": "Use the released scoped CSS and semantic tokens inside contour-root/ThemeScope. Preserve native semantics, public part/state hooks and geometry ownership; see the component-specific anatomy and STYLING.md."
|
|
1740
|
+
}
|
|
1741
|
+
},
|
|
1742
|
+
{
|
|
1743
|
+
"slug": "tag",
|
|
1744
|
+
"name": "Tag",
|
|
1745
|
+
"family": "metadata",
|
|
1746
|
+
"summary": "Text metadata that optionally exposes a native remove action.",
|
|
1747
|
+
"props": [
|
|
1748
|
+
[
|
|
1749
|
+
"children",
|
|
1750
|
+
"string",
|
|
1751
|
+
"Required",
|
|
1752
|
+
"Readable tag text and default removal-name input."
|
|
1753
|
+
],
|
|
1754
|
+
[
|
|
1755
|
+
"onRemove",
|
|
1756
|
+
"() => void",
|
|
1757
|
+
"Omitted",
|
|
1758
|
+
"Supplying it renders the remove button; update parent data."
|
|
1759
|
+
],
|
|
1760
|
+
[
|
|
1761
|
+
"removeLabel",
|
|
1762
|
+
"string",
|
|
1763
|
+
"Remove plus tag text",
|
|
1764
|
+
"Translate/customize the accessible action name."
|
|
1765
|
+
]
|
|
1766
|
+
],
|
|
1767
|
+
"keyboard": "Only a present remove button is focusable; Enter/Space requests removal. Parent chooses useful focus after deleting the focused tag.",
|
|
1768
|
+
"limits": "No arbitrary children, selection semantics, keyboard chip-list model, input parsing or successful-control serialization.",
|
|
1769
|
+
"tasks": "Text metadata that optionally exposes a native remove action. Use for a tag or removable chosen item. This is not a searchable multi-select, command chip or toggle button.",
|
|
1770
|
+
"detail": {
|
|
1771
|
+
"use": "Use for a tag or removable chosen item. This is not a searchable multi-select, command chip or toggle button.",
|
|
1772
|
+
"anatomy": "Without onRemove it is a text span. With onRemove it includes a type=button remove control named from removeLabel or Remove plus children.",
|
|
1773
|
+
"state": "Parent owns the tag collection and actually removes items. No internal selected/removed state or focus-reassignment policy.",
|
|
1774
|
+
"forms": "Not a successful form control: no name, required constraint or native reset behavior. Reset any application-owned content/request state separately.",
|
|
1775
|
+
"ref": "No public native-element ref is forwarded. Keep focus on actual native interactive children rather than making the presentation wrapper focusable.",
|
|
1776
|
+
"edgeCases": "Keep long names/remove targets usable; preserve data on service failure and label optimistic state if used. Removing the DOM node does not automatically focus its neighbor.",
|
|
1777
|
+
"localization": "Translate removeLabel; the default Remove prefix is English. Keep stable record IDs independent of display text.",
|
|
1778
|
+
"reference": "props",
|
|
1779
|
+
"styling": "Use .contour-tag and .contour-tag-remove with released semantic color/line/spacing tokens. Preserve native structure, visible labels and owned state/ARIA; visual customization does not change the interaction contract."
|
|
1780
|
+
}
|
|
1781
|
+
},
|
|
1782
|
+
{
|
|
1783
|
+
"slug": "text-area",
|
|
1784
|
+
"name": "TextArea",
|
|
1785
|
+
"family": "text-inputs",
|
|
1786
|
+
"summary": "A labelled multiline control with optional growth and a character count.",
|
|
1787
|
+
"props": [
|
|
1788
|
+
[
|
|
1789
|
+
"label",
|
|
1790
|
+
"string",
|
|
1791
|
+
"Required",
|
|
1792
|
+
"Visible accessible label; do not replace it with placeholder text."
|
|
1793
|
+
],
|
|
1794
|
+
[
|
|
1795
|
+
"value / defaultValue",
|
|
1796
|
+
"Native control props",
|
|
1797
|
+
"Uncontrolled when value is omitted",
|
|
1798
|
+
"Use value with onChange for application-controlled state. Keep one ownership model."
|
|
1799
|
+
],
|
|
1800
|
+
[
|
|
1801
|
+
"id / name / form",
|
|
1802
|
+
"string",
|
|
1803
|
+
"Generated id; native form association",
|
|
1804
|
+
"Supply name for FormData and a stable id when other content describes the field."
|
|
1805
|
+
],
|
|
1806
|
+
[
|
|
1807
|
+
"hint / error",
|
|
1808
|
+
"string",
|
|
1809
|
+
"Omitted",
|
|
1810
|
+
"Descriptions are linked to the control; error also sets aria-invalid."
|
|
1811
|
+
],
|
|
1812
|
+
[
|
|
1813
|
+
"maxLength",
|
|
1814
|
+
"number",
|
|
1815
|
+
"Omitted",
|
|
1816
|
+
"Native limit plus a counter, including a zero limit. Uncontrolled counters synchronize after native form.reset()."
|
|
1817
|
+
],
|
|
1818
|
+
[
|
|
1819
|
+
"disabled / required / onChange",
|
|
1820
|
+
"Native control props",
|
|
1821
|
+
"Native defaults",
|
|
1822
|
+
"Supply business validation, loading state and change handling in your application."
|
|
1823
|
+
],
|
|
1824
|
+
[
|
|
1825
|
+
"ref",
|
|
1826
|
+
"React.Ref<HTMLTextAreaElement>",
|
|
1827
|
+
"Omitted",
|
|
1828
|
+
"Access the native textarea for focus or a form controller."
|
|
1829
|
+
],
|
|
1830
|
+
[
|
|
1831
|
+
"autoResize",
|
|
1832
|
+
"boolean",
|
|
1833
|
+
"false",
|
|
1834
|
+
"Grows with content; check long values and constrained containers."
|
|
1835
|
+
],
|
|
1836
|
+
["rows", "number", "3", "Native initial row count."]
|
|
1837
|
+
],
|
|
1838
|
+
"keyboard": "Native multiline editing, selection and Tab order.",
|
|
1839
|
+
"limits": "Native reset restores uncontrolled values, counters and auto-resized height. Controlled values require an application state reset. Auto-resize measures the rendered control; verify constrained containers and long text.",
|
|
1840
|
+
"tasks": "textarea multiline description form auto grow reset",
|
|
1841
|
+
"detail": {
|
|
1842
|
+
"use": "Use for native text entry. Use SelectField or Combobox when only an allowed value is valid; TextArea is not a rich-text editor.",
|
|
1843
|
+
"anatomy": "Field renders the label, control slot and linked hint/error/counter. The actual input or textarea owns native attributes and focus. Error takes precedence over hint.",
|
|
1844
|
+
"state": "value/onChange controls the value; otherwise defaultValue initializes native state. Do not switch ownership after mount. Disabled and readOnly retain their native meanings.",
|
|
1845
|
+
"forms": "Set name to include the value in FormData, and form for an external form owner. Uncontrolled native reset restores value, counter and textarea measurement. Controlled owners must restore their state; reset cancellation is respected.",
|
|
1846
|
+
"ref": "The forwarded ref targets the native input (TextField) or textarea (TextArea), not the Field wrapper.",
|
|
1847
|
+
"edgeCases": "maxLength=0 is a real limit. Keep lengthy labels, errors and counters readable at narrow widths. Application loading, server validation and retry are separate; retain valid input after a failed save.",
|
|
1848
|
+
"localization": "Translate labels, hints and errors; use inputMode, autoComplete and dir where appropriate. The counter is not a locale-aware grapheme validator. Check mixed-direction values and your own formatting.",
|
|
1849
|
+
"reference": "forms",
|
|
1850
|
+
"styling": "Use the released scoped CSS and semantic tokens inside contour-root/ThemeScope. Preserve native semantics, public part/state hooks and geometry ownership; see the component-specific anatomy and STYLING.md."
|
|
1851
|
+
}
|
|
1852
|
+
},
|
|
1853
|
+
{
|
|
1854
|
+
"slug": "text-field",
|
|
1855
|
+
"name": "TextField",
|
|
1856
|
+
"family": "text-inputs",
|
|
1857
|
+
"summary": "A labelled native input with linked hint, error and character count.",
|
|
1858
|
+
"props": [
|
|
1859
|
+
[
|
|
1860
|
+
"label",
|
|
1861
|
+
"string",
|
|
1862
|
+
"Required",
|
|
1863
|
+
"Visible accessible label; do not replace it with placeholder text."
|
|
1864
|
+
],
|
|
1865
|
+
[
|
|
1866
|
+
"value / defaultValue",
|
|
1867
|
+
"Native control props",
|
|
1868
|
+
"Uncontrolled when value is omitted",
|
|
1869
|
+
"Use value with onChange for application-controlled state. Keep one ownership model."
|
|
1870
|
+
],
|
|
1871
|
+
[
|
|
1872
|
+
"id / name / form",
|
|
1873
|
+
"string",
|
|
1874
|
+
"Generated id; native form association",
|
|
1875
|
+
"Supply name for FormData and a stable id when other content describes the field."
|
|
1876
|
+
],
|
|
1877
|
+
[
|
|
1878
|
+
"hint / error",
|
|
1879
|
+
"string",
|
|
1880
|
+
"Omitted",
|
|
1881
|
+
"Descriptions are linked to the control; error also sets aria-invalid."
|
|
1882
|
+
],
|
|
1883
|
+
[
|
|
1884
|
+
"maxLength",
|
|
1885
|
+
"number",
|
|
1886
|
+
"Omitted",
|
|
1887
|
+
"Native limit plus a counter, including a zero limit. Uncontrolled counters synchronize after native form.reset()."
|
|
1888
|
+
],
|
|
1889
|
+
[
|
|
1890
|
+
"disabled / required / onChange",
|
|
1891
|
+
"Native control props",
|
|
1892
|
+
"Native defaults",
|
|
1893
|
+
"Supply business validation, loading state and change handling in your application."
|
|
1894
|
+
],
|
|
1895
|
+
[
|
|
1896
|
+
"ref",
|
|
1897
|
+
"React.Ref<HTMLInputElement>",
|
|
1898
|
+
"Omitted",
|
|
1899
|
+
"Access the native input for focus or a form controller."
|
|
1900
|
+
],
|
|
1901
|
+
[
|
|
1902
|
+
"leadingIcon / trailing",
|
|
1903
|
+
"ReactNode",
|
|
1904
|
+
"Omitted",
|
|
1905
|
+
"Decorative icons need aria-hidden; interactive content needs its own label."
|
|
1906
|
+
]
|
|
1907
|
+
],
|
|
1908
|
+
"keyboard": "Native input editing and Tab order. Errors are descriptions, not a focus manager.",
|
|
1909
|
+
"limits": "Business validation and submission remain application-owned. Native reset updates uncontrolled values and counters; controlled fields require your application to reset state. Keep one ownership model for the lifetime of the field.",
|
|
1910
|
+
"tasks": "input form validation error email search focus reset",
|
|
1911
|
+
"detail": {
|
|
1912
|
+
"use": "Use for native text entry. Use SelectField or Combobox when only an allowed value is valid; TextArea is not a rich-text editor.",
|
|
1913
|
+
"anatomy": "Field renders the label, control slot and linked hint/error/counter. The actual input or textarea owns native attributes and focus. Error takes precedence over hint.",
|
|
1914
|
+
"state": "value/onChange controls the value; otherwise defaultValue initializes native state. Do not switch ownership after mount. Disabled and readOnly retain their native meanings.",
|
|
1915
|
+
"forms": "Set name to include the value in FormData, and form for an external form owner. Uncontrolled native reset restores value, counter and textarea measurement. Controlled owners must restore their state; reset cancellation is respected.",
|
|
1916
|
+
"ref": "The forwarded ref targets the native input (TextField) or textarea (TextArea), not the Field wrapper.",
|
|
1917
|
+
"edgeCases": "maxLength=0 is a real limit. Keep lengthy labels, errors and counters readable at narrow widths. Application loading, server validation and retry are separate; retain valid input after a failed save.",
|
|
1918
|
+
"localization": "Translate labels, hints and errors; use inputMode, autoComplete and dir where appropriate. The counter is not a locale-aware grapheme validator. Check mixed-direction values and your own formatting.",
|
|
1919
|
+
"reference": "forms",
|
|
1920
|
+
"styling": "Use the released scoped CSS and semantic tokens inside contour-root/ThemeScope. Preserve native semantics, public part/state hooks and geometry ownership; see the component-specific anatomy and STYLING.md."
|
|
1921
|
+
}
|
|
1922
|
+
},
|
|
1923
|
+
{
|
|
1924
|
+
"slug": "theme-scope",
|
|
1925
|
+
"name": "ThemeScope",
|
|
1926
|
+
"family": "selection",
|
|
1927
|
+
"summary": "An independently controlled theme boundary for embedded Contour components and their portals.",
|
|
1928
|
+
"props": [
|
|
1929
|
+
["theme", "light | dark", "Required", "Explicit independent theme."],
|
|
1930
|
+
[
|
|
1931
|
+
"onThemeChange",
|
|
1932
|
+
"(theme: Theme) => void",
|
|
1933
|
+
"Omitted",
|
|
1934
|
+
"Caller accepts embedded theme requests and owns persistence."
|
|
1935
|
+
],
|
|
1936
|
+
[
|
|
1937
|
+
"children / dir / lang",
|
|
1938
|
+
"Native div props",
|
|
1939
|
+
"Optional",
|
|
1940
|
+
"Compose content and direction inside the scope."
|
|
1941
|
+
],
|
|
1942
|
+
[
|
|
1943
|
+
"ref",
|
|
1944
|
+
"React.Ref<HTMLDivElement>",
|
|
1945
|
+
"Omitted",
|
|
1946
|
+
"Access the scope root."
|
|
1947
|
+
]
|
|
1948
|
+
],
|
|
1949
|
+
"keyboard": "The root adds no keyboard control. Descendant theme buttons are type=button and keep their own focus behavior.",
|
|
1950
|
+
"limits": "Use scoped.css. Omitting onThemeChange makes embedded theme controls read-only. No motion or persistence prop is supplied.",
|
|
1951
|
+
"tasks": "theme scope isolated embedded light dark portal tokens",
|
|
1952
|
+
"detail": {
|
|
1953
|
+
"use": "Use to embed a light/dark Contour surface inside a host that owns its own theme. A document-wide theme control can use useTheme without a scope.",
|
|
1954
|
+
"anatomy": "A div with contour-root and explicit theme tokens supplies context to descendants and owned portalled layers. Use scoped.css for isolated component selectors.",
|
|
1955
|
+
"state": "theme is required and controlled. onThemeChange allows embedded useTheme/ThemeToggle to request a new value; omitting it makes those controls read-only. Persistence is caller-owned.",
|
|
1956
|
+
"forms": "No form value, validation or reset contract. A theme change does not submit the enclosing form.",
|
|
1957
|
+
"ref": "Forwarded ref targets HTMLDivElement. ThemeScope does not supply a motion setting or storage-key prop.",
|
|
1958
|
+
"edgeCases": "Check both light-in-dark and dark-in-light, nested scopes and portalled overlays. scoped.css does not rename the host's generic classes. Do not import the global reset unless its document-wide effect is intended.",
|
|
1959
|
+
"localization": "Native dir/lang attributes can be applied to the root. Translate toggle labels separately; theme selection does not determine language or direction.",
|
|
1960
|
+
"reference": "styles",
|
|
1961
|
+
"styling": "Use the released scoped CSS and semantic tokens inside contour-root/ThemeScope. Preserve native semantics, public part/state hooks and geometry ownership; see the component-specific anatomy and STYLING.md."
|
|
1962
|
+
}
|
|
1963
|
+
},
|
|
1964
|
+
{
|
|
1965
|
+
"slug": "theme-toggle",
|
|
1966
|
+
"name": "ThemeToggle",
|
|
1967
|
+
"family": "theme-copy",
|
|
1968
|
+
"summary": "A native button that toggles the current theme owner when it is writable.",
|
|
1969
|
+
"props": [
|
|
1970
|
+
[
|
|
1971
|
+
"animate",
|
|
1972
|
+
"boolean",
|
|
1973
|
+
"Required",
|
|
1974
|
+
"False switches instantly; system reduction/pause still governs motion."
|
|
1975
|
+
],
|
|
1976
|
+
[
|
|
1977
|
+
"darkLabel / lightTitle / darkTitle",
|
|
1978
|
+
"string",
|
|
1979
|
+
"Dark theme / Switch to light theme / Switch to dark theme",
|
|
1980
|
+
"Translate button name and action titles."
|
|
1981
|
+
]
|
|
1982
|
+
],
|
|
1983
|
+
"keyboard": "Native Enter/Space activation and visible button focus. Disabled when the nearest scope is read-only; aria-pressed communicates dark state.",
|
|
1984
|
+
"limits": "No native arbitrary button props or separate persistence namespace API. The accessible name is darkLabel in both states; title describes the next action.",
|
|
1985
|
+
"tasks": "A native button that toggles the current theme owner when it is writable. Use for a document preference or a writable ThemeScope. A controlled read-only scope cannot toggle itself; the owner must supply its change handler.",
|
|
1986
|
+
"detail": {
|
|
1987
|
+
"use": "Use for a document preference or a writable ThemeScope. A controlled read-only scope cannot toggle itself; the owner must supply its change handler.",
|
|
1988
|
+
"anatomy": "Native button with decorative moon/sun icons uses aria-pressed for dark state, an accessible darkLabel and a direction-specific title.",
|
|
1989
|
+
"state": "useTheme(animate) resolves the nearest theme owner; animate is required. Root integration owns aa-theme/storage/meta behavior; scoped owners own their state instead.",
|
|
1990
|
+
"forms": "Native type=button never submits a form; no name/value/reset contract. Theme state resets only through its owner.",
|
|
1991
|
+
"ref": "Forwarded HTMLButtonElement.",
|
|
1992
|
+
"edgeCases": "Handle blocked storage in root integration and verify nested scopes/portals. A theme change must not imply data was saved; actual animation depends on browser/reduced-motion support.",
|
|
1993
|
+
"localization": "Translate all supplied strings; surrounding dir governs layout. Verify both themes, focus/forced colors and read-only scope behavior.",
|
|
1994
|
+
"reference": "styles",
|
|
1995
|
+
"styling": "Use .contour-theme-toggle and aria-pressed with released semantic color/line/spacing tokens. Preserve native structure, visible labels and owned state/ARIA; visual customization does not change the interaction contract."
|
|
1996
|
+
}
|
|
1997
|
+
},
|
|
1998
|
+
{
|
|
1999
|
+
"slug": "tilt-card",
|
|
2000
|
+
"name": "TiltCard",
|
|
2001
|
+
"family": "motion",
|
|
2002
|
+
"summary": "A CSS depth wrapper reacting to mouse movement with a glare highlight.",
|
|
2003
|
+
"props": [
|
|
2004
|
+
[
|
|
2005
|
+
"children",
|
|
2006
|
+
"ReactNode",
|
|
2007
|
+
"Required",
|
|
2008
|
+
"Meaningful content stays usable without tilt."
|
|
2009
|
+
],
|
|
2010
|
+
[
|
|
2011
|
+
"maxTilt",
|
|
2012
|
+
"number",
|
|
2013
|
+
"12",
|
|
2014
|
+
"Caller chooses a sensible finite rotation bound."
|
|
2015
|
+
]
|
|
2016
|
+
],
|
|
2017
|
+
"keyboard": "Not a keyboard control and does not add a tab stop. Interactive children retain their native behavior; do not use this display as a substitute for a button or link.",
|
|
2018
|
+
"limits": "No gesture navigation, keyboard activation, forwarded ref or scene/GPU dependency. This is CSS, not a Three.js primitive.",
|
|
2019
|
+
"tasks": "A CSS depth wrapper reacting to mouse movement with a glare highlight. Use for optional visual emphasis. Put essential content/actions in native children; do not make pointer tilt necessary to discover or use them.",
|
|
2020
|
+
"detail": {
|
|
2021
|
+
"use": "Use for optional visual emphasis. Put essential content/actions in native children; do not make pointer tilt necessary to discover or use them.",
|
|
2022
|
+
"anatomy": "Outer stage contains inner tilt card, children and decorative glare span; pointer geometry writes CSS custom properties.",
|
|
2023
|
+
"state": "maxTilt defaults to 12 degrees. Mouse movement applies tilt unless motion is disabled; pointer leave removes tilt/glare overrides. Touch/pen do not drive the effect.",
|
|
2024
|
+
"forms": "Not a successful form control: no name, required constraint or native reset behavior. Reset any application-owned content/request state separately.",
|
|
2025
|
+
"ref": "No public native-element ref is forwarded. Keep focus on actual native interactive children rather than making the presentation wrapper focusable.",
|
|
2026
|
+
"edgeCases": "Test long content, stationary focus targets, touch/reduced/paused motion and both themes. Overflow/glare must not cover essential controls.",
|
|
2027
|
+
"localization": "Children carry all language/direction. Tilt is decorative; do not reinterpret its direction as navigation.",
|
|
2028
|
+
"reference": "hooks",
|
|
2029
|
+
"styling": "Use .contour-tilt-stage, .contour-tilt-card and glare hook with released semantic color/line/spacing tokens. Preserve native structure, visible labels and owned state/ARIA; visual customization does not change the interaction contract."
|
|
2030
|
+
}
|
|
2031
|
+
},
|
|
2032
|
+
{
|
|
2033
|
+
"slug": "timeline",
|
|
2034
|
+
"name": "Timeline",
|
|
2035
|
+
"family": "content",
|
|
2036
|
+
"summary": "A read-only ordered list of dated descriptions.",
|
|
2037
|
+
"props": [
|
|
2038
|
+
[
|
|
2039
|
+
"entries",
|
|
2040
|
+
"{date,title,body?,current?}[]",
|
|
2041
|
+
"Required",
|
|
2042
|
+
"Provide correctly ordered entries and meaningful date/time context."
|
|
2043
|
+
]
|
|
2044
|
+
],
|
|
2045
|
+
"keyboard": "Not a keyboard control and does not add a tab stop. Interactive children retain their native behavior; do not use this display as a substitute for a button or link.",
|
|
2046
|
+
"limits": "No date parser, sorting/time-zone conversion, semantic time datetime prop, async loading or event interaction.",
|
|
2047
|
+
"tasks": "A read-only ordered list of dated descriptions. Use for an explicit chronological sequence. Dates are display strings; sort/parse/time-zone and factual versus illustrative provenance remain application-owned.",
|
|
2048
|
+
"detail": {
|
|
2049
|
+
"use": "Use for an explicit chronological sequence. Dates are display strings; sort/parse/time-zone and factual versus illustrative provenance remain application-owned.",
|
|
2050
|
+
"anatomy": "Ordered list contains date, title, optional body and current class. Keys combine date/title; they must be unique and stable.",
|
|
2051
|
+
"state": "Pure supplied entries; current is a visual flag, not automatic time comparison or native navigation.",
|
|
2052
|
+
"forms": "Not a successful form control: no name, required constraint or native reset behavior. Reset any application-owned content/request state separately.",
|
|
2053
|
+
"ref": "No public native-element ref is forwarded. Keep focus on actual native interactive children rather than making the presentation wrapper focusable.",
|
|
2054
|
+
"edgeCases": "Distinguish an empty history from failed loading. Keep long titles/descriptions readable; duplicate date/title combinations are unsupported identity.",
|
|
2055
|
+
"localization": "Format date strings with explicit application calendar/time-zone rules; translate text and verify long RTL sequences.",
|
|
2056
|
+
"reference": "props",
|
|
2057
|
+
"styling": "Use .contour-timeline and current-entry hook with released semantic color/line/spacing tokens. Preserve native structure, visible labels and owned state/ARIA; visual customization does not change the interaction contract."
|
|
2058
|
+
}
|
|
2059
|
+
},
|
|
2060
|
+
{
|
|
2061
|
+
"slug": "toast-provider",
|
|
2062
|
+
"name": "ToastProvider",
|
|
2063
|
+
"family": "toasts",
|
|
2064
|
+
"summary": "A notification region and useToast().show() for outcomes your application has already established.",
|
|
2065
|
+
"props": [
|
|
2066
|
+
[
|
|
2067
|
+
"children",
|
|
2068
|
+
"ReactNode",
|
|
2069
|
+
"Required",
|
|
2070
|
+
"Wrap components that call useToast()."
|
|
2071
|
+
],
|
|
2072
|
+
[
|
|
2073
|
+
"show({title, message, tone})",
|
|
2074
|
+
"useToast() command",
|
|
2075
|
+
"Title required; message optional",
|
|
2076
|
+
"Report actual outcomes. A notification does not perform or persist the operation."
|
|
2077
|
+
],
|
|
2078
|
+
[
|
|
2079
|
+
"tone",
|
|
2080
|
+
"\"neutral\" | \"accent\" | \"info\" | \"success\" | \"warning\" | \"danger\"",
|
|
2081
|
+
"\"neutral\"",
|
|
2082
|
+
"Match the result; do not use success before a request completes."
|
|
2083
|
+
]
|
|
2084
|
+
],
|
|
2085
|
+
"keyboard": "The close control is keyboard accessible. Messages appear in a polite live region; essential failures should also remain beside the task.",
|
|
2086
|
+
"limits": "Notifications are temporary. This is not a durable inbox, async request controller or undo mechanism. Calling useToast outside the provider throws.",
|
|
2087
|
+
"tasks": "toast notification snackbar feedback success error live region",
|
|
2088
|
+
"detail": {
|
|
2089
|
+
"use": "Use for brief established outcomes. Keep actionable errors beside the task; use an in-page alert for a failure that needs sustained attention.",
|
|
2090
|
+
"anatomy": "Provider owns a polite notification region with up to the latest three messages and dismiss buttons. Descendants call useToast().show({title,message?,tone?}).",
|
|
2091
|
+
"state": "The queue auto-dismisses after five seconds and pauses while hovered/focused. show reports an outcome; it does not run an operation. There are no IDs, update commands, undo or durable inbox.",
|
|
2092
|
+
"forms": "No native form value or reset contract. Notify only after a real save result, and preserve field validation in the form.",
|
|
2093
|
+
"ref": "No native provider ref. Calling useToast outside the provider throws; mount a provider around actual consumers.",
|
|
2094
|
+
"edgeCases": "Rapid messages displace older entries. Do not put the only record of a failure in a temporary toast. Respect focus/motion and test translated long messages.",
|
|
2095
|
+
"localization": "Set label and dismissLabel on the provider and translate each title/message. Manual screen-reader announcement review remains pending; polite markup is not proof of every announcement.",
|
|
2096
|
+
"reference": "hooks",
|
|
2097
|
+
"styling": "Use the released scoped CSS and semantic tokens inside contour-root/ThemeScope. Preserve native semantics, public part/state hooks and geometry ownership; see the component-specific anatomy and STYLING.md."
|
|
2098
|
+
}
|
|
2099
|
+
},
|
|
2100
|
+
{
|
|
2101
|
+
"slug": "tooltip",
|
|
2102
|
+
"name": "Tooltip",
|
|
2103
|
+
"family": "floating",
|
|
2104
|
+
"summary": "Supplemental noninteractive text associated with one focusable child.",
|
|
2105
|
+
"props": [
|
|
2106
|
+
[
|
|
2107
|
+
"content / children",
|
|
2108
|
+
"string / one focusable ReactElement",
|
|
2109
|
+
"Required",
|
|
2110
|
+
"Supply supplemental text and a child that accepts its description attribute."
|
|
2111
|
+
],
|
|
2112
|
+
[
|
|
2113
|
+
"placement / align",
|
|
2114
|
+
"top | bottom | left | right / start | center | end",
|
|
2115
|
+
"top / center",
|
|
2116
|
+
"Collision placement may flip/shift."
|
|
2117
|
+
],
|
|
2118
|
+
[
|
|
2119
|
+
"sideOffset / collisionPadding",
|
|
2120
|
+
"number",
|
|
2121
|
+
"10 / 8",
|
|
2122
|
+
"Spacing and viewport collision padding."
|
|
2123
|
+
],
|
|
2124
|
+
[
|
|
2125
|
+
"portal / container",
|
|
2126
|
+
"boolean / HTMLElement",
|
|
2127
|
+
"true / inferred owner target",
|
|
2128
|
+
"Same-document custom container; disabling portals changes clipping/ancestor behavior."
|
|
2129
|
+
]
|
|
2130
|
+
],
|
|
2131
|
+
"keyboard": "Focus the child with its native keyboard mechanism. Escape dismisses only the active topmost layer; the hint is not a focus target. Interactive hint content is unsupported.",
|
|
2132
|
+
"limits": "One focusable child and string content; no interactive popup, validation message replacement or focus trap. Manual screen-reader announcements remain pending.",
|
|
2133
|
+
"tasks": "Supplemental noninteractive text associated with one focusable child. Use for a short nonessential hint. Keep essential instructions visible; use Popover/Dialog for interactive content and never use a tooltip as the only label.",
|
|
2134
|
+
"detail": {
|
|
2135
|
+
"use": "Use for a short nonessential hint. Keep essential instructions visible; use Popover/Dialog for interactive content and never use a tooltip as the only label.",
|
|
2136
|
+
"anatomy": "Anchor wraps one React element and merges its aria-describedby with the hint ID. The noninteractive tooltip portal uses owner-body/native-dialog placement and collision handling.",
|
|
2137
|
+
"state": "Hover/focus opens; pointer travel between anchor and content retains the hint. Escape suppresses it until the current hover/focus session ends. Closed portals are hidden in 0.6.2 and later without losing trigger description linkage.",
|
|
2138
|
+
"forms": "Not a successful form control: no name, required constraint or native reset behavior. Reset any application-owned content/request state separately.",
|
|
2139
|
+
"ref": "No public native-element ref is forwarded. Keep focus on actual native interactive children rather than making the presentation wrapper focusable.",
|
|
2140
|
+
"edgeCases": "Test edge/long content, clipped ancestors, nested native dialogs, pointer corridors and description merging. Keep a usable visible explanation if the hint cannot display.",
|
|
2141
|
+
"localization": "Translate content and child label; use surrounding dir for logical alignment. Long translations may wrap and collision positioning may change side.",
|
|
2142
|
+
"reference": "overlays",
|
|
2143
|
+
"styling": "Use .contour-tooltip and placement/state hooks with released semantic color/line/spacing tokens. Preserve native structure, visible labels and owned state/ARIA; visual customization does not change the interaction contract."
|
|
2144
|
+
}
|
|
2145
|
+
}
|
|
2146
|
+
],
|
|
2147
|
+
"families": [
|
|
2148
|
+
{
|
|
2149
|
+
"id": "buttons",
|
|
2150
|
+
"example": "examples/catalogue/buttons.tsx"
|
|
2151
|
+
},
|
|
2152
|
+
{
|
|
2153
|
+
"id": "text-inputs",
|
|
2154
|
+
"example": "examples/catalogue/text-inputs.tsx"
|
|
2155
|
+
},
|
|
2156
|
+
{
|
|
2157
|
+
"id": "field",
|
|
2158
|
+
"example": "examples/catalogue/field.tsx"
|
|
2159
|
+
},
|
|
2160
|
+
{
|
|
2161
|
+
"id": "choices",
|
|
2162
|
+
"example": "examples/catalogue/choices.tsx"
|
|
2163
|
+
},
|
|
2164
|
+
{
|
|
2165
|
+
"id": "navigation",
|
|
2166
|
+
"example": "examples/catalogue/navigation.tsx"
|
|
2167
|
+
},
|
|
2168
|
+
{
|
|
2169
|
+
"id": "metadata",
|
|
2170
|
+
"example": "examples/catalogue/metadata.tsx"
|
|
2171
|
+
},
|
|
2172
|
+
{
|
|
2173
|
+
"id": "content",
|
|
2174
|
+
"example": "examples/catalogue/content.tsx"
|
|
2175
|
+
},
|
|
2176
|
+
{
|
|
2177
|
+
"id": "data-table",
|
|
2178
|
+
"example": "examples/catalogue/data-table.tsx"
|
|
2179
|
+
},
|
|
2180
|
+
{
|
|
2181
|
+
"id": "feedback",
|
|
2182
|
+
"example": "examples/catalogue/feedback.tsx"
|
|
2183
|
+
},
|
|
2184
|
+
{
|
|
2185
|
+
"id": "toasts",
|
|
2186
|
+
"example": "examples/catalogue/toasts.tsx"
|
|
2187
|
+
},
|
|
2188
|
+
{
|
|
2189
|
+
"id": "dialogs",
|
|
2190
|
+
"example": "examples/catalogue/dialogs.tsx"
|
|
2191
|
+
},
|
|
2192
|
+
{
|
|
2193
|
+
"id": "floating",
|
|
2194
|
+
"example": "examples/catalogue/floating.tsx"
|
|
2195
|
+
},
|
|
2196
|
+
{
|
|
2197
|
+
"id": "identity",
|
|
2198
|
+
"example": "examples/catalogue/identity.tsx"
|
|
2199
|
+
},
|
|
2200
|
+
{
|
|
2201
|
+
"id": "motion",
|
|
2202
|
+
"example": "examples/catalogue/motion.tsx"
|
|
2203
|
+
},
|
|
2204
|
+
{
|
|
2205
|
+
"id": "theme-copy",
|
|
2206
|
+
"example": "examples/catalogue/theme-copy.tsx"
|
|
2207
|
+
},
|
|
2208
|
+
{
|
|
2209
|
+
"id": "selection",
|
|
2210
|
+
"example": "examples/catalogue/combobox.tsx"
|
|
2211
|
+
},
|
|
2212
|
+
{
|
|
2213
|
+
"id": "scene-boundary",
|
|
2214
|
+
"example": "examples/catalogue/scene-boundary.tsx"
|
|
2215
|
+
}
|
|
2216
|
+
]
|
|
2217
|
+
}
|