@pithyjs/pidl-catalog 0.1.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/LICENSE +21 -0
  2. package/dist/specs/atoms/actions/button.pidl.json +289 -0
  3. package/dist/specs/atoms/actions/icon-group.pidl.json +141 -0
  4. package/dist/specs/atoms/actions/segmented-control.pidl.json +137 -0
  5. package/dist/specs/atoms/content/action-tile.pidl.json +135 -0
  6. package/dist/specs/atoms/content/badge.pidl.json +189 -0
  7. package/dist/specs/atoms/content/callout.pidl.json +170 -0
  8. package/dist/specs/atoms/content/code-block.pidl.json +170 -0
  9. package/dist/specs/atoms/content/heading.pidl.json +175 -0
  10. package/dist/specs/atoms/content/icon.pidl.json +127 -0
  11. package/dist/specs/atoms/content/image.pidl.json +227 -0
  12. package/dist/specs/atoms/content/prose.pidl.json +183 -0
  13. package/dist/specs/atoms/content/stat.pidl.json +158 -0
  14. package/dist/specs/atoms/content/tabs.pidl.json +207 -0
  15. package/dist/specs/atoms/content/text.pidl.json +212 -0
  16. package/dist/specs/atoms/content/tile.pidl.json +156 -0
  17. package/dist/specs/atoms/data/donut.pidl.json +352 -0
  18. package/dist/specs/atoms/data/gauge.pidl.json +274 -0
  19. package/dist/specs/atoms/forms/checkbox-group.pidl.json +170 -0
  20. package/dist/specs/atoms/forms/checkbox.pidl.json +323 -0
  21. package/dist/specs/atoms/forms/file-picker.pidl.json +161 -0
  22. package/dist/specs/atoms/forms/form-field.pidl.json +106 -0
  23. package/dist/specs/atoms/forms/input.pidl.json +466 -0
  24. package/dist/specs/atoms/forms/radio-group.pidl.json +174 -0
  25. package/dist/specs/atoms/forms/radio.pidl.json +312 -0
  26. package/dist/specs/atoms/forms/search-input.pidl.json +265 -0
  27. package/dist/specs/atoms/forms/select.pidl.json +420 -0
  28. package/dist/specs/atoms/forms/textarea.pidl.json +422 -0
  29. package/dist/specs/atoms/forms/toggle.pidl.json +314 -0
  30. package/dist/specs/layout/grid-item.pidl.json +120 -0
  31. package/dist/specs/layout/grid.pidl.json +157 -0
  32. package/dist/specs/layout/page-section.pidl.json +105 -0
  33. package/dist/specs/layout/smart-container.pidl.json +148 -0
  34. package/dist/specs/layout/stack.pidl.json +144 -0
  35. package/dist/specs/organisms/content/accordion.pidl.json +196 -0
  36. package/dist/specs/organisms/content/card.pidl.json +283 -0
  37. package/dist/specs/organisms/feedback/alert-dialog.pidl.json +158 -0
  38. package/dist/specs/organisms/feedback/modal.pidl.json +133 -0
  39. package/dist/specs/organisms/feedback/toast.pidl.json +150 -0
  40. package/dist/specs/organisms/forms/dynamic-form.pidl.json +314 -0
  41. package/dist/specs/organisms/forms/form.pidl.json +135 -0
  42. package/dist/specs/organisms/forms/subscribe-form.pidl.json +188 -0
  43. package/dist/specs/organisms/navigation/command-palette.pidl.json +263 -0
  44. package/dist/specs/organisms/navigation/docs-sidebar.pidl.json +264 -0
  45. package/dist/specs/organisms/navigation/navbar.pidl.json +356 -0
  46. package/dist/specs/organisms/navigation/table-of-contents.pidl.json +197 -0
  47. package/dist/specs/sections/contact-section.pidl.json +183 -0
  48. package/dist/specs/sections/cta-section.pidl.json +168 -0
  49. package/dist/specs/sections/faq-section.pidl.json +202 -0
  50. package/dist/specs/sections/features-section.pidl.json +214 -0
  51. package/dist/specs/sections/footer-section.pidl.json +187 -0
  52. package/dist/specs/sections/hero-section.pidl.json +202 -0
  53. package/dist/src/borders-psychology.d.ts +17 -0
  54. package/dist/src/borders-psychology.d.ts.map +1 -0
  55. package/dist/src/borders-psychology.js +42 -0
  56. package/dist/src/borders-psychology.js.map +1 -0
  57. package/dist/src/color-psychology.d.ts +20 -0
  58. package/dist/src/color-psychology.d.ts.map +1 -0
  59. package/dist/src/color-psychology.js +57 -0
  60. package/dist/src/color-psychology.js.map +1 -0
  61. package/dist/src/design-intelligence.d.ts +13 -0
  62. package/dist/src/design-intelligence.d.ts.map +1 -0
  63. package/dist/src/design-intelligence.js +36 -0
  64. package/dist/src/design-intelligence.js.map +1 -0
  65. package/dist/src/index.d.ts +6238 -0
  66. package/dist/src/index.d.ts.map +1 -0
  67. package/dist/src/index.js +105 -0
  68. package/dist/src/index.js.map +1 -0
  69. package/dist/src/motion-psychology.d.ts +19 -0
  70. package/dist/src/motion-psychology.d.ts.map +1 -0
  71. package/dist/src/motion-psychology.js +47 -0
  72. package/dist/src/motion-psychology.js.map +1 -0
  73. package/dist/src/mutation-vocabulary.d.ts +13 -0
  74. package/dist/src/mutation-vocabulary.d.ts.map +1 -0
  75. package/dist/src/mutation-vocabulary.js +67 -0
  76. package/dist/src/mutation-vocabulary.js.map +1 -0
  77. package/dist/src/radius-psychology.d.ts +17 -0
  78. package/dist/src/radius-psychology.d.ts.map +1 -0
  79. package/dist/src/radius-psychology.js +42 -0
  80. package/dist/src/radius-psychology.js.map +1 -0
  81. package/dist/src/shadows-psychology.d.ts +17 -0
  82. package/dist/src/shadows-psychology.d.ts.map +1 -0
  83. package/dist/src/shadows-psychology.js +44 -0
  84. package/dist/src/shadows-psychology.js.map +1 -0
  85. package/dist/src/spacing-psychology.d.ts +22 -0
  86. package/dist/src/spacing-psychology.d.ts.map +1 -0
  87. package/dist/src/spacing-psychology.js +59 -0
  88. package/dist/src/spacing-psychology.js.map +1 -0
  89. package/dist/src/typography-psychology.d.ts +22 -0
  90. package/dist/src/typography-psychology.d.ts.map +1 -0
  91. package/dist/src/typography-psychology.js +68 -0
  92. package/dist/src/typography-psychology.js.map +1 -0
  93. package/package.json +64 -0
@@ -0,0 +1,265 @@
1
+ {
2
+ "kind": "component",
3
+ "id": "ui.search-input",
4
+ "name": "SearchInput",
5
+ "displayName": "Search input",
6
+ "version": "0.1.0",
7
+ "level": "atom",
8
+ "domain": "forms",
9
+ "studioReady": true,
10
+ "bidi": true,
11
+ "description": "Search field composed from the <Input> atom — leading magnifier, clear button, optional keyboard-shortcut chip, and a debounced query callback. Renders a <form role=\"search\"> landmark by default, which can be dropped (landmark=false) when the field lives inside a dialog such as <CommandPalette>. This is UI only: it owns no index, no fetching and no results list. Wire onSearch to whatever backend you have — the docs search engine itself lands in R3.",
12
+ "props": [
13
+ {
14
+ "name": "value",
15
+ "reactive": true,
16
+ "label": "Value",
17
+ "type": "string | Signal<string>",
18
+ "description": "Field value — a static string, or an accessor for a controlled field. Leave unset for an uncontrolled field."
19
+ },
20
+ {
21
+ "name": "placeholder",
22
+ "reactive": true,
23
+ "label": "Placeholder",
24
+ "type": "string | Signal<string>",
25
+ "default": "Search",
26
+ "placeholder": "Search the docs",
27
+ "description": "Placeholder text. An accessor is kept in sync after construction, so a locale switch takes effect without rebuilding the field."
28
+ },
29
+ {
30
+ "name": "label",
31
+ "label": "Label",
32
+ "type": "string",
33
+ "default": "Search",
34
+ "placeholder": "Search",
35
+ "description": "Accessible name. Always applied to the field's aria-label, and additionally rendered as a visible <label> when showLabel is true. A whitespace-only value falls back to 'Search' rather than producing an empty accessible name."
36
+ },
37
+ {
38
+ "name": "showLabel",
39
+ "label": "Show label",
40
+ "editor": { "tab": "content" },
41
+ "type": "boolean",
42
+ "default": false,
43
+ "description": "Render the label visibly above the field. Off by default: a magnifier plus a placeholder is the established convention for a search box, and a visible label costs a line of vertical space in a navbar."
44
+ },
45
+ {
46
+ "name": "size",
47
+ "label": "Size",
48
+ "type": "enum",
49
+ "enum": ["sm", "md", "lg"],
50
+ "default": "md",
51
+ "description": "Control size, passed straight through to <Input> so a search field lines up with every other control on the row."
52
+ },
53
+ {
54
+ "name": "disabled",
55
+ "label": "Disabled",
56
+ "editor": { "tab": "settings" },
57
+ "reactive": true,
58
+ "type": "boolean | Signal<boolean>",
59
+ "default": false,
60
+ "description": "Disabled state — uses the native disabled attribute via <Input>."
61
+ },
62
+ {
63
+ "name": "loading",
64
+ "label": "Loading",
65
+ "editor": { "tab": "settings" },
66
+ "reactive": true,
67
+ "type": "boolean | Signal<boolean>",
68
+ "default": false,
69
+ "description": "Shows the <Input> spinner and sets aria-busy. Use it while a query is in flight; the field stays editable."
70
+ },
71
+ {
72
+ "name": "debounce",
73
+ "label": "Debounce (ms)",
74
+ "editor": { "tab": "settings" },
75
+ "type": "number",
76
+ "default": 200,
77
+ "description": "Idle window before onSearch fires. 0 fires it synchronously on every keystroke — right for a local in-memory filter, wrong for anything that hits the network."
78
+ },
79
+ {
80
+ "name": "shortcutHint",
81
+ "label": "Shortcut hint",
82
+ "type": "string",
83
+ "placeholder": "⌘K",
84
+ "description": "Keyboard shortcut to advertise, rendered as a <kbd> chip in the Input suffix and hidden from assistive tech. Purely a hint for sighted users — it binds nothing. The binding belongs to <CommandPalette>."
85
+ },
86
+ {
87
+ "name": "landmark",
88
+ "label": "Search landmark",
89
+ "editor": { "tab": "settings" },
90
+ "type": "boolean",
91
+ "default": true,
92
+ "description": "Wrap the field in <form role=\"search\"> so it appears in a screen reader's landmark list. Set false inside a dialog: a search landmark nested in a modal is a landmark the reader cannot navigate to sensibly, and <CommandPalette> relies on this. Several mounted landmarks must not share a name — give each a distinct label or leave only one as a landmark; DEV warns on duplicates (axe: landmark-unique)."
93
+ },
94
+ {
95
+ "name": "id",
96
+ "label": "Element id",
97
+ "editor": { "tab": "settings" },
98
+ "type": "string",
99
+ "description": "Explicit id for the <input>. Generated when omitted — the visible label's `for` is wired to it either way."
100
+ },
101
+ {
102
+ "name": "name",
103
+ "label": "Name",
104
+ "editor": { "tab": "settings" },
105
+ "type": "string",
106
+ "placeholder": "q",
107
+ "description": "name attribute, for a field that posts to a real search endpoint."
108
+ },
109
+ {
110
+ "name": "autoFocus",
111
+ "label": "Autofocus",
112
+ "editor": { "tab": "settings" },
113
+ "type": "boolean",
114
+ "default": false,
115
+ "description": "Focus the field once mounted. Reserve it for a search-first surface (a dialog, a dedicated search page) — stealing focus on an ordinary page moves the reader without asking."
116
+ },
117
+ {
118
+ "name": "class",
119
+ "label": "Extra classes",
120
+ "editor": { "tab": "settings" },
121
+ "type": "string",
122
+ "description": "Extra class names appended after 'ui-search-input'."
123
+ },
124
+ {
125
+ "name": "onSearch",
126
+ "label": "On search",
127
+ "type": "(query: string) => void",
128
+ "description": "Debounced query callback — the one to hand a search backend. Fires `debounce` ms after the last change, always with the newest query."
129
+ },
130
+ {
131
+ "name": "onInput",
132
+ "label": "On input",
133
+ "type": "(query: string) => void",
134
+ "description": "Undebounced query callback, on every keystroke. Use it for local UI that must track the field exactly (a character count, a live filter over an array already in memory)."
135
+ },
136
+ {
137
+ "name": "onSubmit",
138
+ "label": "On submit",
139
+ "type": "(query: string) => void",
140
+ "description": "Enter, or a form submit. The pending debounced onSearch is flushed first, so a consumer never sees onSubmit for a query its onSearch was never told about."
141
+ },
142
+ {
143
+ "name": "onClear",
144
+ "label": "On clear",
145
+ "type": "() => void",
146
+ "description": "Fires when the query is deliberately emptied — the clear button, Escape, or clear(). Deleting the last character by hand does NOT fire it; that is an ordinary edit reported through onInput/onSearch."
147
+ }
148
+ ],
149
+ "tokens": {
150
+ "typography": "--font-size-sm + --font-weight-medium (visible label), --line-height-body; the field's own type scale comes from input.scss",
151
+ "color": "--color-text (label), --color-text-muted (magnifier at rest), --color-primary (magnifier on focus-within)",
152
+ "spacing": "--space-sm (label ↔ field, Close Friends)",
153
+ "icon": "--_input-icon-size — the private custom property input.scss sets per control size, so the magnifier tracks the same scale as the success/error state icon opposite it",
154
+ "motion": "--motion-transition-color on the magnifier, inside prefers-reduced-motion: no-preference",
155
+ "kbd": "the design system's kbd-chip mixin (--radius-sm, --border-width-hairline, --color-border, --color-surface, --color-text-muted)"
156
+ },
157
+ "spacing": {
158
+ "label-to-field": "--space-sm (Close Friends) — a label belongs to the field directly beneath it",
159
+ "icon-to-text": "inherited from .ui-input's --space-xs gap (Lovers) — the magnifier and the query are one unit"
160
+ },
161
+ "constraints": [
162
+ "COMPOSES the <Input> atom — it never renders a bare <input>. Sizing, border, focus ring, hover, disabled, loading and the clear button all come from input.scss, so a search field is visually identical to every other control on the page",
163
+ "The element is type=\"search\" (set on the element, not through <Input>'s type enum, which lists only the types it styles). WebKit's own cancel button is suppressed in CSS — <Input> already renders a real, keyboard-reachable clear button",
164
+ "Escape clears a non-empty field and stops there. On an EMPTY field it does nothing and does not stop propagation. That hands the key to an enclosing dialog ONLY if the dialog listens in the bubble phase: <Modal> listens on window in CAPTURE with stopImmediatePropagation(), so inside <CommandPalette> the FIRST Escape closes the dialog and this handler never runs (see the matching constraint in command-palette.pidl.json)",
165
+ "Enter always preventDefaults — the implicit form submission would reload the page. Callers navigate from onSubmit",
166
+ "onClear is fired only for a deliberate clear (clear button, Escape, clear()). The clear button is detected in the CAPTURE phase, which is what lets it be told apart from backspacing the last character: <Input>'s own click handler dispatches an identical synthetic input event",
167
+ "onSearch is debounced; onInput is not. Both fire for the same keystroke — pick one per consumer rather than wiring both to the same handler",
168
+ "destroy() cancels the pending debounced search, so a component unmounted mid-type never fires a query into a dead consumer",
169
+ "It owns no results and no request lifecycle. The backend (Pagefind / Fuse over the codex index) is R3"
170
+ ],
171
+ "a11y": [
172
+ "The field always has an accessible name: aria-label by default, plus a real <label for> when showLabel is true",
173
+ "role=\"search\" on the wrapping <form>, with an aria-label, so the field appears in a screen reader's landmark list under a name — and landmark=false exists precisely so it does NOT when it sits inside a dialog",
174
+ "Two landmarks of the same role must not share an accessible name (axe: landmark-unique) — a landmark list of identical 'Search' rows is no better than none. No single instance can see the collision, so a DEV-only cross-instance counter warns when duplicates are mounted together",
175
+ "shortcutHint is aria-hidden. A '⌘K' read aloud as part of the field's surroundings is noise: the chip is a hint for sighted users and binds nothing",
176
+ "The magnifier is decorative (aria-hidden) — the field's own name already says what it is",
177
+ "The clear button comes from <Input>: a real <button> that leaves the tab order (tabindex -1 + aria-hidden) while the field is empty, so there is no dead focus stop",
178
+ "Escape-to-clear is deliberately conditional, and propagation is stopped ONLY when the key actually cleared something. Swallowing Escape on an empty field would trap a keyboard user inside a bubble-phase dialog they were trying to leave. A capture-phase dialog such as <Modal> claims the key before this handler ever sees it",
179
+ "type=\"search\" earns the field the right virtual keyboard on touch — an enter key labelled 'search'",
180
+ "The magnifier's focus colour change is decoration on top of the field's own focus ring, never the only focus indicator",
181
+ "Colour transitions are wrapped in prefers-reduced-motion: no-preference via the a11y motion-safe mixin",
182
+ "The kbd chip restores a visible border under forced colours, where the background that normally shapes it is discarded"
183
+ ],
184
+ "ai": {
185
+ "synonyms": [
186
+ "search",
187
+ "search box",
188
+ "search field",
189
+ "search bar",
190
+ "filter input",
191
+ "query input",
192
+ "find",
193
+ "type to search",
194
+ "site search",
195
+ "docs search"
196
+ ],
197
+ "avoid": [
198
+ "hand-rolling <input type=\"search\"> with a magnifier — the clear button, debounce, Escape handling and landmark are exactly what this component exists to own",
199
+ "leaving landmark=true inside a dialog or a command palette — a search landmark nested in a modal is not navigable as a landmark",
200
+ "mounting several landmark=true fields that all fall back to the default 'Search' name — the landmark list becomes a row of identical entries; give each a distinct label",
201
+ "wiring the same handler to BOTH onInput and onSearch — the backend then runs twice per keystroke, once undebounced",
202
+ "debounce=0 with a network-backed onSearch — that is one request per keystroke",
203
+ "expecting it to render results: it renders a field. Compose it with your own list, or reach for <CommandPalette> for the dialog shell",
204
+ "setting autoFocus on an ordinary page — it moves the reader's focus without being asked"
205
+ ],
206
+ "patterns": [
207
+ "Docs header: <SearchInput placeholder=\"'Search the docs'\" shortcutHint=\"'⌘K'\" onSearch=\"runQuery\" />",
208
+ "Local list filter, no debounce: <SearchInput debounce=\"0\" onInput=\"setFilter\" />",
209
+ "Inside a dialog: <SearchInput landmark=\"false\" autoFocus=\"true\" onInput=\"setQuery\" />",
210
+ "Real GET form: <SearchInput name=\"'q'\" onSubmit=\"submitSearch\" />",
211
+ "Visible label on a dedicated search page: <SearchInput showLabel=\"true\" label=\"'Search articles'\" size=\"'lg'\" />"
212
+ ]
213
+ },
214
+ "designGuidance": {
215
+ "surface": "The <Input> surface, unmodified — --color-surface at rest, --color-surface-bright on hover. The two affix cells the Input normally paints (the bordered prefix/suffix wells that make a currency symbol read as attached) are stripped here: a magnifier is chrome INSIDE the field, not an affix beside it, so it sits transparent and flush with the text.",
216
+ "depth": "Flat, plus the Input's focus glow. A search field is a control on the page, not a surface above it.",
217
+ "borders": "One border, the Input's own, at a width that never changes across states — hover and focus recolour it rather than resize it, so nothing reflows as the reader moves through the form.",
218
+ "interactivity": "The magnifier warms from --color-text-muted to --color-primary on focus-within. That is decoration layered on the field's real focus ring, never a substitute for it. The clear button appears only once there is something to clear.",
219
+ "motion": "Colour only, and only outside prefers-reduced-motion: reduce.",
220
+ "darkMode": "Nothing to do — every value is a --color-* token, so the muted/active relationship inverts with the theme.",
221
+ "bestPractices": "Give it a placeholder that says what is being searched ('Search the docs'), not just 'Search' — the accessible name already says that. Add shortcutHint only when a shortcut actually exists. Keep the default 200ms debounce for anything network-backed and drop to 0 only for an in-memory filter. In a navbar, use the sm size and let the field flex; on a dedicated search page, lg with showLabel reads as the primary task."
222
+ },
223
+ "examples": [
224
+ {
225
+ "id": "default",
226
+ "title": "Docs search",
227
+ "pithy": "<SearchInput placeholder=\"'Search the docs'\" shortcutHint=\"'⌘K'\" />",
228
+ "assertions": [
229
+ "renders <form role='search' class='ui-search-input' aria-label='Search'>",
230
+ "the field is type='search' with a magnifier in .ui-input-prefix",
231
+ "the shortcut renders as a <kbd> inside an aria-hidden .ui-input-suffix"
232
+ ]
233
+ },
234
+ {
235
+ "id": "debounce",
236
+ "title": "Debounced query",
237
+ "pithy": "<SearchInput onSearch=\"runQuery\" debounce=\"200\" />",
238
+ "assertions": [
239
+ "a burst of keystrokes produces exactly one onSearch call",
240
+ "the call carries the newest query",
241
+ "destroy() cancels a pending call"
242
+ ]
243
+ },
244
+ {
245
+ "id": "clearing",
246
+ "title": "Clearing",
247
+ "pithy": "<SearchInput onClear=\"showEverything\" />",
248
+ "assertions": [
249
+ "the clear button empties the field and fires onClear",
250
+ "Escape on a non-empty field clears it and stops propagating",
251
+ "Escape on an empty field propagates so an enclosing dialog can close",
252
+ "deleting the last character by hand does not fire onClear"
253
+ ]
254
+ },
255
+ {
256
+ "id": "in-dialog",
257
+ "title": "Inside a dialog",
258
+ "pithy": "<SearchInput landmark=\"false\" autoFocus=\"true\" />",
259
+ "assertions": [
260
+ "renders a <div>, not a <form>, and carries no role",
261
+ "the field takes focus on the microtask after mount"
262
+ ]
263
+ }
264
+ ]
265
+ }