@pearpages/pulp-react 0.0.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 (286) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +65 -0
  3. package/dist/ListboxOptions-DLsT-dkV.d.ts +11 -0
  4. package/dist/ToggleField-C-qKSgHh.d.ts +3 -0
  5. package/dist/accordion.css +90 -0
  6. package/dist/accordion.css.map +1 -0
  7. package/dist/accordion.d.ts +71 -0
  8. package/dist/accordion.js +6 -0
  9. package/dist/accordion.js.map +1 -0
  10. package/dist/alert.css +246 -0
  11. package/dist/alert.css.map +1 -0
  12. package/dist/alert.d.ts +46 -0
  13. package/dist/alert.js +10 -0
  14. package/dist/alert.js.map +1 -0
  15. package/dist/badge.css +89 -0
  16. package/dist/badge.css.map +1 -0
  17. package/dist/badge.d.ts +38 -0
  18. package/dist/badge.js +5 -0
  19. package/dist/badge.js.map +1 -0
  20. package/dist/button.css +162 -0
  21. package/dist/button.css.map +1 -0
  22. package/dist/button.d.ts +61 -0
  23. package/dist/button.js +8 -0
  24. package/dist/button.js.map +1 -0
  25. package/dist/calendar.css +128 -0
  26. package/dist/calendar.css.map +1 -0
  27. package/dist/calendar.d.ts +48 -0
  28. package/dist/calendar.js +6 -0
  29. package/dist/calendar.js.map +1 -0
  30. package/dist/card.css +66 -0
  31. package/dist/card.css.map +1 -0
  32. package/dist/card.d.ts +69 -0
  33. package/dist/card.js +5 -0
  34. package/dist/card.js.map +1 -0
  35. package/dist/checkbox.css +106 -0
  36. package/dist/checkbox.css.map +1 -0
  37. package/dist/checkbox.d.ts +41 -0
  38. package/dist/checkbox.js +7 -0
  39. package/dist/checkbox.js.map +1 -0
  40. package/dist/chunk-2PXTVZ7H.js +95 -0
  41. package/dist/chunk-2PXTVZ7H.js.map +1 -0
  42. package/dist/chunk-2ZP4ZBI5.js +43 -0
  43. package/dist/chunk-2ZP4ZBI5.js.map +1 -0
  44. package/dist/chunk-3GWESUGD.js +28 -0
  45. package/dist/chunk-3GWESUGD.js.map +1 -0
  46. package/dist/chunk-4HRNRTXI.js +25 -0
  47. package/dist/chunk-4HRNRTXI.js.map +1 -0
  48. package/dist/chunk-5SBKZS56.js +56 -0
  49. package/dist/chunk-5SBKZS56.js.map +1 -0
  50. package/dist/chunk-6I26MMQF.js +19 -0
  51. package/dist/chunk-6I26MMQF.js.map +1 -0
  52. package/dist/chunk-75GTNRBH.js +45 -0
  53. package/dist/chunk-75GTNRBH.js.map +1 -0
  54. package/dist/chunk-7DS4I7OJ.js +30 -0
  55. package/dist/chunk-7DS4I7OJ.js.map +1 -0
  56. package/dist/chunk-ASNTNTJW.js +27 -0
  57. package/dist/chunk-ASNTNTJW.js.map +1 -0
  58. package/dist/chunk-ASOQ2MVR.js +19 -0
  59. package/dist/chunk-ASOQ2MVR.js.map +1 -0
  60. package/dist/chunk-AWQHULJC.js +31 -0
  61. package/dist/chunk-AWQHULJC.js.map +1 -0
  62. package/dist/chunk-BBV4L5WO.js +43 -0
  63. package/dist/chunk-BBV4L5WO.js.map +1 -0
  64. package/dist/chunk-CZBCGLEM.js +9 -0
  65. package/dist/chunk-CZBCGLEM.js.map +1 -0
  66. package/dist/chunk-DWE374JX.js +65 -0
  67. package/dist/chunk-DWE374JX.js.map +1 -0
  68. package/dist/chunk-DXOOW6Q6.js +159 -0
  69. package/dist/chunk-DXOOW6Q6.js.map +1 -0
  70. package/dist/chunk-F3OFZGGE.js +116 -0
  71. package/dist/chunk-F3OFZGGE.js.map +1 -0
  72. package/dist/chunk-FH54XQ35.js +125 -0
  73. package/dist/chunk-FH54XQ35.js.map +1 -0
  74. package/dist/chunk-FXRSZUDH.js +38 -0
  75. package/dist/chunk-FXRSZUDH.js.map +1 -0
  76. package/dist/chunk-GTTXRDXV.js +181 -0
  77. package/dist/chunk-GTTXRDXV.js.map +1 -0
  78. package/dist/chunk-I4KC4V6A.js +31 -0
  79. package/dist/chunk-I4KC4V6A.js.map +1 -0
  80. package/dist/chunk-I5OZ63W7.js +50 -0
  81. package/dist/chunk-I5OZ63W7.js.map +1 -0
  82. package/dist/chunk-IDNGNQNV.js +41 -0
  83. package/dist/chunk-IDNGNQNV.js.map +1 -0
  84. package/dist/chunk-J5S2HVHO.js +67 -0
  85. package/dist/chunk-J5S2HVHO.js.map +1 -0
  86. package/dist/chunk-K5QGGQOV.js +84 -0
  87. package/dist/chunk-K5QGGQOV.js.map +1 -0
  88. package/dist/chunk-KPQGS4PG.js +77 -0
  89. package/dist/chunk-KPQGS4PG.js.map +1 -0
  90. package/dist/chunk-MI4QUKQS.js +8 -0
  91. package/dist/chunk-MI4QUKQS.js.map +1 -0
  92. package/dist/chunk-MRQWUCBA.js +57 -0
  93. package/dist/chunk-MRQWUCBA.js.map +1 -0
  94. package/dist/chunk-MXWXJZFS.js +48 -0
  95. package/dist/chunk-MXWXJZFS.js.map +1 -0
  96. package/dist/chunk-N7L66GMG.js +129 -0
  97. package/dist/chunk-N7L66GMG.js.map +1 -0
  98. package/dist/chunk-NAYFLTK6.js +32 -0
  99. package/dist/chunk-NAYFLTK6.js.map +1 -0
  100. package/dist/chunk-O6OBFL3Q.js +155 -0
  101. package/dist/chunk-O6OBFL3Q.js.map +1 -0
  102. package/dist/chunk-OGIQRHNF.js +52 -0
  103. package/dist/chunk-OGIQRHNF.js.map +1 -0
  104. package/dist/chunk-OUFAFINB.js +45 -0
  105. package/dist/chunk-OUFAFINB.js.map +1 -0
  106. package/dist/chunk-OXYP34CG.js +43 -0
  107. package/dist/chunk-OXYP34CG.js.map +1 -0
  108. package/dist/chunk-P5C2U5ZF.js +73 -0
  109. package/dist/chunk-P5C2U5ZF.js.map +1 -0
  110. package/dist/chunk-PM4YO67Q.js +53 -0
  111. package/dist/chunk-PM4YO67Q.js.map +1 -0
  112. package/dist/chunk-Q6J6BMSB.js +86 -0
  113. package/dist/chunk-Q6J6BMSB.js.map +1 -0
  114. package/dist/chunk-T76YSNTZ.js +33 -0
  115. package/dist/chunk-T76YSNTZ.js.map +1 -0
  116. package/dist/chunk-TGMDOQCL.js +53 -0
  117. package/dist/chunk-TGMDOQCL.js.map +1 -0
  118. package/dist/chunk-TVI5AXLE.js +41 -0
  119. package/dist/chunk-TVI5AXLE.js.map +1 -0
  120. package/dist/chunk-U6QRAD73.js +22 -0
  121. package/dist/chunk-U6QRAD73.js.map +1 -0
  122. package/dist/chunk-UX42PQLT.js +76 -0
  123. package/dist/chunk-UX42PQLT.js.map +1 -0
  124. package/dist/chunk-XDVS7HX7.js +100 -0
  125. package/dist/chunk-XDVS7HX7.js.map +1 -0
  126. package/dist/chunk-Y4TZA77G.js +57 -0
  127. package/dist/chunk-Y4TZA77G.js.map +1 -0
  128. package/dist/chunk-YUHS5S5Y.js +12 -0
  129. package/dist/chunk-YUHS5S5Y.js.map +1 -0
  130. package/dist/chunk-Z4PN6B2C.js +17 -0
  131. package/dist/chunk-Z4PN6B2C.js.map +1 -0
  132. package/dist/chunk-ZVDN3GRI.js +49 -0
  133. package/dist/chunk-ZVDN3GRI.js.map +1 -0
  134. package/dist/combobox.css +280 -0
  135. package/dist/combobox.css.map +1 -0
  136. package/dist/combobox.d.ts +75 -0
  137. package/dist/combobox.js +10 -0
  138. package/dist/combobox.js.map +1 -0
  139. package/dist/component-manifest.json +3370 -0
  140. package/dist/date-picker.css +267 -0
  141. package/dist/date-picker.css.map +1 -0
  142. package/dist/date-picker.d.ts +59 -0
  143. package/dist/date-picker.js +8 -0
  144. package/dist/date-picker.js.map +1 -0
  145. package/dist/dialog.css +62 -0
  146. package/dist/dialog.css.map +1 -0
  147. package/dist/dialog.d.ts +56 -0
  148. package/dist/dialog.js +3 -0
  149. package/dist/dialog.js.map +1 -0
  150. package/dist/field.css +28 -0
  151. package/dist/field.css.map +1 -0
  152. package/dist/field.d.ts +98 -0
  153. package/dist/field.js +5 -0
  154. package/dist/field.js.map +1 -0
  155. package/dist/floating-Bw-LN_QT.d.ts +5 -0
  156. package/dist/heading.css +30 -0
  157. package/dist/heading.css.map +1 -0
  158. package/dist/heading.d.ts +316 -0
  159. package/dist/heading.js +4 -0
  160. package/dist/heading.js.map +1 -0
  161. package/dist/icon-button.css +177 -0
  162. package/dist/icon-button.css.map +1 -0
  163. package/dist/icon-button.d.ts +29 -0
  164. package/dist/icon-button.js +9 -0
  165. package/dist/icon-button.js.map +1 -0
  166. package/dist/icon.css +25 -0
  167. package/dist/icon.css.map +1 -0
  168. package/dist/icon.d.ts +33 -0
  169. package/dist/icon.js +4 -0
  170. package/dist/icon.js.map +1 -0
  171. package/dist/index.css +2345 -0
  172. package/dist/index.css.map +1 -0
  173. package/dist/index.d.ts +42 -0
  174. package/dist/index.js +49 -0
  175. package/dist/index.js.map +1 -0
  176. package/dist/inline.css +63 -0
  177. package/dist/inline.css.map +1 -0
  178. package/dist/inline.d.ts +322 -0
  179. package/dist/inline.js +4 -0
  180. package/dist/inline.js.map +1 -0
  181. package/dist/listbox.css +95 -0
  182. package/dist/listbox.css.map +1 -0
  183. package/dist/listbox.d.ts +47 -0
  184. package/dist/listbox.js +7 -0
  185. package/dist/listbox.js.map +1 -0
  186. package/dist/menu.css +102 -0
  187. package/dist/menu.css.map +1 -0
  188. package/dist/menu.d.ts +76 -0
  189. package/dist/menu.js +9 -0
  190. package/dist/menu.js.map +1 -0
  191. package/dist/pagination.css +212 -0
  192. package/dist/pagination.css.map +1 -0
  193. package/dist/pagination.d.ts +52 -0
  194. package/dist/pagination.js +10 -0
  195. package/dist/pagination.js.map +1 -0
  196. package/dist/picker.css +209 -0
  197. package/dist/picker.css.map +1 -0
  198. package/dist/picker.d.ts +57 -0
  199. package/dist/picker.js +8 -0
  200. package/dist/picker.js.map +1 -0
  201. package/dist/popover.css +48 -0
  202. package/dist/popover.css.map +1 -0
  203. package/dist/popover.d.ts +68 -0
  204. package/dist/popover.js +7 -0
  205. package/dist/popover.js.map +1 -0
  206. package/dist/progress.css +83 -0
  207. package/dist/progress.css.map +1 -0
  208. package/dist/progress.d.ts +40 -0
  209. package/dist/progress.js +5 -0
  210. package/dist/progress.js.map +1 -0
  211. package/dist/radio.css +107 -0
  212. package/dist/radio.css.map +1 -0
  213. package/dist/radio.d.ts +68 -0
  214. package/dist/radio.js +6 -0
  215. package/dist/radio.js.map +1 -0
  216. package/dist/select.css +98 -0
  217. package/dist/select.css.map +1 -0
  218. package/dist/select.d.ts +39 -0
  219. package/dist/select.js +6 -0
  220. package/dist/select.js.map +1 -0
  221. package/dist/skeleton.css +59 -0
  222. package/dist/skeleton.css.map +1 -0
  223. package/dist/skeleton.d.ts +34 -0
  224. package/dist/skeleton.js +4 -0
  225. package/dist/skeleton.js.map +1 -0
  226. package/dist/slider.css +126 -0
  227. package/dist/slider.css.map +1 -0
  228. package/dist/slider.d.ts +61 -0
  229. package/dist/slider.js +5 -0
  230. package/dist/slider.js.map +1 -0
  231. package/dist/spinner.css +60 -0
  232. package/dist/spinner.css.map +1 -0
  233. package/dist/spinner.d.ts +34 -0
  234. package/dist/spinner.js +5 -0
  235. package/dist/spinner.js.map +1 -0
  236. package/dist/stack.css +60 -0
  237. package/dist/stack.css.map +1 -0
  238. package/dist/stack.d.ts +319 -0
  239. package/dist/stack.js +4 -0
  240. package/dist/stack.js.map +1 -0
  241. package/dist/switch.css +97 -0
  242. package/dist/switch.css.map +1 -0
  243. package/dist/switch.d.ts +35 -0
  244. package/dist/switch.js +7 -0
  245. package/dist/switch.js.map +1 -0
  246. package/dist/table.css +188 -0
  247. package/dist/table.css.map +1 -0
  248. package/dist/table.d.ts +137 -0
  249. package/dist/table.js +6 -0
  250. package/dist/table.js.map +1 -0
  251. package/dist/tabs.css +75 -0
  252. package/dist/tabs.css.map +1 -0
  253. package/dist/tabs.d.ts +73 -0
  254. package/dist/tabs.js +5 -0
  255. package/dist/tabs.js.map +1 -0
  256. package/dist/text-field.css +75 -0
  257. package/dist/text-field.css.map +1 -0
  258. package/dist/text-field.d.ts +43 -0
  259. package/dist/text-field.js +6 -0
  260. package/dist/text-field.js.map +1 -0
  261. package/dist/text.css +53 -0
  262. package/dist/text.css.map +1 -0
  263. package/dist/text.d.ts +331 -0
  264. package/dist/text.js +4 -0
  265. package/dist/text.js.map +1 -0
  266. package/dist/textarea.css +84 -0
  267. package/dist/textarea.css.map +1 -0
  268. package/dist/textarea.d.ts +40 -0
  269. package/dist/textarea.js +6 -0
  270. package/dist/textarea.js.map +1 -0
  271. package/dist/toast.css +300 -0
  272. package/dist/toast.css.map +1 -0
  273. package/dist/toast.d.ts +60 -0
  274. package/dist/toast.js +11 -0
  275. package/dist/toast.js.map +1 -0
  276. package/dist/tooltip.css +36 -0
  277. package/dist/tooltip.css.map +1 -0
  278. package/dist/tooltip.d.ts +34 -0
  279. package/dist/tooltip.js +5 -0
  280. package/dist/tooltip.js.map +1 -0
  281. package/dist/visually-hidden.css +15 -0
  282. package/dist/visually-hidden.css.map +1 -0
  283. package/dist/visually-hidden.d.ts +308 -0
  284. package/dist/visually-hidden.js +4 -0
  285. package/dist/visually-hidden.js.map +1 -0
  286. package/package.json +261 -0
@@ -0,0 +1,3370 @@
1
+ {
2
+ "package": "@pearpages/pulp-react",
3
+ "categories": [
4
+ "Typography",
5
+ "Layout",
6
+ "Actions",
7
+ "Forms",
8
+ "Navigation",
9
+ "Overlays",
10
+ "Feedback",
11
+ "Data",
12
+ "Utilities"
13
+ ],
14
+ "requires": {
15
+ "tokens": "@pearpages/pulp-tokens/tokens.css (every --<component>-* value resolves through it; without it components render unstyled)",
16
+ "base": "@pearpages/pulp-css (optional: layer order, reset, body defaults, vendor layer)",
17
+ "icons": "@pearpages/pulp-icons (optional: stroke glyphs; wrap them in Icon or pass them to Button slots)",
18
+ "dialogs": "@pearpages/modals/styles.css (only when using Dialog; import it into the vendor layer)",
19
+ "headless": "react-aria-components (installed automatically; Combobox, Listbox, Picker, Calendar, DatePicker, Slider and Table build on it, see docs/decisions/001)",
20
+ "fonts": "consumers load the brand typefaces themselves (pulp: Archivo, Instrument Sans, Geist Mono; bitepals: Nunito, Inter)"
21
+ },
22
+ "components": [
23
+ {
24
+ "name": "Accordion",
25
+ "description": "Vertically stacked sections that expand one at a time or independently.\nEach trigger is a button inside a real heading, each panel a labelled\nregion; arrows, Home and End move between triggers. Controlled or\nuncontrolled by `value`. Compose with `Accordion.Item`,\n`Accordion.Trigger` and `Accordion.Panel`.",
26
+ "status": "stable",
27
+ "category": "Navigation",
28
+ "accessibility": "Each trigger is a `button` inside a heading of the given `headingLevel`; each panel is a `region` labelled by its trigger. Arrows, Home and End move between triggers; Enter or Space toggles.",
29
+ "do": [
30
+ "Set `headingLevel` to fit the page outline.",
31
+ "Use `multiple` when sections are independent reference material."
32
+ ],
33
+ "dont": [
34
+ "Nest interactive content in the trigger; it is one button.",
35
+ "Use it for a single show-more; use Popover or plain content instead."
36
+ ],
37
+ "import": "import { Accordion } from '@pearpages/pulp-react/accordion';",
38
+ "css": "@pearpages/pulp-react/accordion.css",
39
+ "tokens": "--accordion-*",
40
+ "props": [
41
+ {
42
+ "name": "collapsible",
43
+ "type": "boolean",
44
+ "required": false,
45
+ "default": "true",
46
+ "description": "In `single` mode, whether the open item can be closed again."
47
+ },
48
+ {
49
+ "name": "defaultValue",
50
+ "type": "string | string[]",
51
+ "required": false,
52
+ "default": null,
53
+ "description": ""
54
+ },
55
+ {
56
+ "name": "headingLevel",
57
+ "type": "enum",
58
+ "required": false,
59
+ "default": "3",
60
+ "description": "The heading level of every trigger, for the document outline."
61
+ },
62
+ {
63
+ "name": "onValueChange",
64
+ "type": "((value: string | string[]) => void)",
65
+ "required": false,
66
+ "default": null,
67
+ "description": ""
68
+ },
69
+ {
70
+ "name": "ref",
71
+ "type": "Ref<HTMLDivElement>",
72
+ "required": false,
73
+ "default": null,
74
+ "description": ""
75
+ },
76
+ {
77
+ "name": "type",
78
+ "type": "enum",
79
+ "required": false,
80
+ "default": "single",
81
+ "description": "`single` keeps one item open; `multiple` allows any number."
82
+ },
83
+ {
84
+ "name": "value",
85
+ "type": "string | string[]",
86
+ "required": false,
87
+ "default": null,
88
+ "description": "Controlled open item(s): a string for `single`, an array for `multiple`."
89
+ }
90
+ ],
91
+ "parts": [
92
+ {
93
+ "name": "Accordion.Item",
94
+ "description": "",
95
+ "props": [
96
+ {
97
+ "name": "value",
98
+ "type": "string",
99
+ "required": true,
100
+ "default": null,
101
+ "description": ""
102
+ },
103
+ {
104
+ "name": "disabled",
105
+ "type": "boolean",
106
+ "required": false,
107
+ "default": "false",
108
+ "description": ""
109
+ },
110
+ {
111
+ "name": "ref",
112
+ "type": "Ref<HTMLDivElement>",
113
+ "required": false,
114
+ "default": null,
115
+ "description": ""
116
+ }
117
+ ]
118
+ },
119
+ {
120
+ "name": "Accordion.Trigger",
121
+ "description": "",
122
+ "props": [
123
+ {
124
+ "name": "ref",
125
+ "type": "Ref<HTMLButtonElement>",
126
+ "required": false,
127
+ "default": null,
128
+ "description": ""
129
+ }
130
+ ]
131
+ },
132
+ {
133
+ "name": "Accordion.Panel",
134
+ "description": "",
135
+ "props": [
136
+ {
137
+ "name": "ref",
138
+ "type": "Ref<HTMLDivElement>",
139
+ "required": false,
140
+ "default": null,
141
+ "description": ""
142
+ }
143
+ ]
144
+ }
145
+ ]
146
+ },
147
+ {
148
+ "name": "Alert",
149
+ "description": "An inline message with a tone. Tint, accent and title colour come from\nthe status tokens; the body keeps the default text colour so long\nmessages stay readable. Toast renders one Alert per notification.",
150
+ "status": "stable",
151
+ "category": "Feedback",
152
+ "accessibility": "`role=\"alert\"` for `tone=\"error\"` (assertive), `role=\"status\"` otherwise (polite); `live=\"off\"` opts out. The glyph is decorative; the tone is carried by the title and text, never by colour alone.",
153
+ "do": [
154
+ "Give it a `title` when the body is more than one sentence.",
155
+ "Use `onDismiss` for messages the user can act on and clear."
156
+ ],
157
+ "dont": [
158
+ "Announce errors through both an Alert and a Toast.",
159
+ "Use it as a page-level banner for marketing copy."
160
+ ],
161
+ "import": "import { Alert } from '@pearpages/pulp-react/alert';",
162
+ "css": "@pearpages/pulp-react/alert.css",
163
+ "tokens": "--alert-*",
164
+ "props": [
165
+ {
166
+ "name": "action",
167
+ "type": "ReactNode",
168
+ "required": false,
169
+ "default": null,
170
+ "description": "Buttons or links placed under the body."
171
+ },
172
+ {
173
+ "name": "dismissLabel",
174
+ "type": "string",
175
+ "required": false,
176
+ "default": "Dismiss",
177
+ "description": ""
178
+ },
179
+ {
180
+ "name": "icon",
181
+ "type": "ReactNode",
182
+ "required": false,
183
+ "default": null,
184
+ "description": "Replaces the tone's default glyph; `null` shows none."
185
+ },
186
+ {
187
+ "name": "live",
188
+ "type": "enum",
189
+ "required": false,
190
+ "default": null,
191
+ "description": "How assistive technology announces it: `assertive` (`role=\"alert\"`),\n`polite` (`role=\"status\"`) or `off` (no live role, for content present at\npage load or inside another live region). Defaults to assertive for\n`error`, polite otherwise."
192
+ },
193
+ {
194
+ "name": "onDismiss",
195
+ "type": "(() => void)",
196
+ "required": false,
197
+ "default": null,
198
+ "description": "Renders a dismiss button that calls this."
199
+ },
200
+ {
201
+ "name": "ref",
202
+ "type": "Ref<HTMLDivElement>",
203
+ "required": false,
204
+ "default": null,
205
+ "description": ""
206
+ },
207
+ {
208
+ "name": "title",
209
+ "type": "ReactNode",
210
+ "required": false,
211
+ "default": null,
212
+ "description": ""
213
+ },
214
+ {
215
+ "name": "tone",
216
+ "type": "enum",
217
+ "required": false,
218
+ "default": "info",
219
+ "description": ""
220
+ }
221
+ ],
222
+ "parts": []
223
+ },
224
+ {
225
+ "name": "Badge",
226
+ "description": "A small label for status, counts and tags. Tone and variant resolve\nthrough `--badge-*` onto the status tokens, whose contrast is proven by\nthe token tests. Not interactive: for a removable chip, compose with a\nButton.",
227
+ "status": "stable",
228
+ "category": "Feedback",
229
+ "accessibility": "Plain text: no role, no interaction. Every tone × variant pair meets WCAG AA, proven by the token tests. Tone is reinforced by the text, not only by colour.",
230
+ "do": [
231
+ "Keep the text to one or two words.",
232
+ "Pair a leading icon with text, never alone."
233
+ ],
234
+ "dont": [
235
+ "Make it clickable; compose a Button for a removable chip.",
236
+ "Use tone alone to convey meaning; say it in the text."
237
+ ],
238
+ "import": "import { Badge } from '@pearpages/pulp-react/badge';",
239
+ "css": "@pearpages/pulp-react/badge.css",
240
+ "tokens": "--badge-*",
241
+ "props": [
242
+ {
243
+ "name": "icon",
244
+ "type": "ReactNode",
245
+ "required": false,
246
+ "default": null,
247
+ "description": "Leading glyph, decorative."
248
+ },
249
+ {
250
+ "name": "ref",
251
+ "type": "Ref<HTMLSpanElement>",
252
+ "required": false,
253
+ "default": null,
254
+ "description": ""
255
+ },
256
+ {
257
+ "name": "size",
258
+ "type": "enum",
259
+ "required": false,
260
+ "default": "md",
261
+ "description": ""
262
+ },
263
+ {
264
+ "name": "tone",
265
+ "type": "enum",
266
+ "required": false,
267
+ "default": "neutral",
268
+ "description": "Meaning, not colour: `neutral` for counts and tags."
269
+ },
270
+ {
271
+ "name": "variant",
272
+ "type": "enum",
273
+ "required": false,
274
+ "default": "subtle",
275
+ "description": "`solid` fills with the tone; `subtle` tints and uses the tone as text."
276
+ }
277
+ ],
278
+ "parts": []
279
+ },
280
+ {
281
+ "name": "Button",
282
+ "description": "The one action component. Variants map to emphasis, not colour: one\n`primary` per view, `secondary` for the rest, `ghost` inside other content.\nEvery value comes from `--button-*` tokens, so a brand restyles it without\ntouching the component. State is exposed as `data-variant`, `data-size` and\n`data-loading` for styling, tests and agents alike.",
283
+ "status": "stable",
284
+ "category": "Actions",
285
+ "accessibility": "A native `button` (or the child element with `asChild`). `loading` sets `aria-disabled` and `aria-busy` and keeps focus; only `disabled` removes it from the tab order. Icon-only use warns in development: use IconButton, which requires a name.",
286
+ "do": [
287
+ "One `primary` per view.",
288
+ "Use `asChild` for links that look like buttons, keeping the `a` semantics."
289
+ ],
290
+ "dont": [
291
+ "Use `loading` on a button that is not the one that started the work.",
292
+ "Rely on colour to tell variants apart; the label carries the meaning."
293
+ ],
294
+ "import": "import { Button } from '@pearpages/pulp-react/button';",
295
+ "css": "@pearpages/pulp-react/button.css",
296
+ "tokens": "--button-*",
297
+ "props": [
298
+ {
299
+ "name": "asChild",
300
+ "type": "boolean",
301
+ "required": false,
302
+ "default": "false",
303
+ "description": "Render the single child element instead of a `<button>`, merging the\nbutton's props into it. Use it to style a router `<Link>` or an `<a>` as a\nbutton. Disabled and loading states then use `aria-disabled`, and the\nchild's own `onClick` does not run while the control is inert."
304
+ },
305
+ {
306
+ "name": "iconEnd",
307
+ "type": "ReactNode",
308
+ "required": false,
309
+ "default": null,
310
+ "description": "Decorative element after the label. Hidden from assistive technology."
311
+ },
312
+ {
313
+ "name": "iconStart",
314
+ "type": "ReactNode",
315
+ "required": false,
316
+ "default": null,
317
+ "description": "Decorative element before the label. Hidden from assistive technology."
318
+ },
319
+ {
320
+ "name": "loading",
321
+ "type": "boolean",
322
+ "required": false,
323
+ "default": "false",
324
+ "description": "Shows a spinner, sets `aria-busy` and `aria-disabled`, and blocks\nactivation. The element stays focusable so focus is not lost mid-action,\nand the label stays in place so the button keeps its width."
325
+ },
326
+ {
327
+ "name": "ref",
328
+ "type": "Ref<E>",
329
+ "required": false,
330
+ "default": null,
331
+ "description": "The rendered element. With `asChild` that is the child's element, so pass\nthe type parameter: `<Button<HTMLAnchorElement> asChild ref={anchorRef}>`."
332
+ },
333
+ {
334
+ "name": "size",
335
+ "type": "enum",
336
+ "required": false,
337
+ "default": "md",
338
+ "description": ""
339
+ },
340
+ {
341
+ "name": "variant",
342
+ "type": "enum",
343
+ "required": false,
344
+ "default": "primary",
345
+ "description": "Visual emphasis. One `primary` per view; `secondary` for the rest;\n`ghost` for actions that sit inside other content."
346
+ }
347
+ ],
348
+ "parts": []
349
+ },
350
+ {
351
+ "name": "Calendar",
352
+ "description": "A month grid for choosing one date, on React Aria's calendar (decision\nrecord 001): arrows move by day and week, Page Up/Down by month, Home and\nEnd to the edges of the week, Enter or Space selects; every cell is\nannounced with its full date and the grid is named by a visually hidden\nlevel-2 heading. Dates cross the API as ISO strings. For a date inside a\nform, DatePicker wraps this in a field with a popover.",
353
+ "status": "experimental",
354
+ "category": "Forms",
355
+ "accessibility": "The grid is `role=\"grid\"` named by a visually hidden level-2 heading (\"Calendar, September 2026\"); each day is a button announced with its full date, today and selection state. Arrows move by day and week, Page Up/Down by month, Home/End to the week edges, Enter or Space selects.",
356
+ "do": [
357
+ "Pass `locale` when the app's language is not the browser's.",
358
+ "Mark unavailable dates with `isDateUnavailable` rather than removing them."
359
+ ],
360
+ "dont": [
361
+ "Use it inside a form; use DatePicker, which adds the field and the popover.",
362
+ "Set `min` after `max`; the vendor disables the whole grid."
363
+ ],
364
+ "import": "import { Calendar } from '@pearpages/pulp-react/calendar';",
365
+ "css": "@pearpages/pulp-react/calendar.css",
366
+ "tokens": "--calendar-*",
367
+ "props": [
368
+ {
369
+ "name": "aria-label",
370
+ "type": "string",
371
+ "required": false,
372
+ "default": "Calendar",
373
+ "description": "The grid's accessible name."
374
+ },
375
+ {
376
+ "name": "className",
377
+ "type": "string",
378
+ "required": false,
379
+ "default": null,
380
+ "description": ""
381
+ },
382
+ {
383
+ "name": "defaultValue",
384
+ "type": "string | null",
385
+ "required": false,
386
+ "default": null,
387
+ "description": ""
388
+ },
389
+ {
390
+ "name": "disabled",
391
+ "type": "boolean",
392
+ "required": false,
393
+ "default": "false",
394
+ "description": ""
395
+ },
396
+ {
397
+ "name": "id",
398
+ "type": "string",
399
+ "required": false,
400
+ "default": null,
401
+ "description": ""
402
+ },
403
+ {
404
+ "name": "isDateUnavailable",
405
+ "type": "((date: string) => boolean)",
406
+ "required": false,
407
+ "default": null,
408
+ "description": "Marks single dates as unavailable (shown, not selectable)."
409
+ },
410
+ {
411
+ "name": "locale",
412
+ "type": "string",
413
+ "required": false,
414
+ "default": null,
415
+ "description": "BCP 47 tag. Month names, weekday order and the first day of the week follow it; defaults to the browser's."
416
+ },
417
+ {
418
+ "name": "max",
419
+ "type": "string",
420
+ "required": false,
421
+ "default": null,
422
+ "description": "Latest selectable date, `YYYY-MM-DD`."
423
+ },
424
+ {
425
+ "name": "min",
426
+ "type": "string",
427
+ "required": false,
428
+ "default": null,
429
+ "description": "Earliest selectable date, `YYYY-MM-DD`."
430
+ },
431
+ {
432
+ "name": "onChange",
433
+ "type": "((value: string | null) => void)",
434
+ "required": false,
435
+ "default": null,
436
+ "description": ""
437
+ },
438
+ {
439
+ "name": "readOnly",
440
+ "type": "boolean",
441
+ "required": false,
442
+ "default": "false",
443
+ "description": ""
444
+ },
445
+ {
446
+ "name": "ref",
447
+ "type": "Ref<HTMLDivElement>",
448
+ "required": false,
449
+ "default": null,
450
+ "description": ""
451
+ },
452
+ {
453
+ "name": "value",
454
+ "type": "string | null",
455
+ "required": false,
456
+ "default": null,
457
+ "description": "Selected date as `YYYY-MM-DD` (controlled). `null` is \"none\"."
458
+ }
459
+ ],
460
+ "parts": []
461
+ },
462
+ {
463
+ "name": "Card",
464
+ "description": "A surface that groups related content. Compose with `Card.Header`,\n`Card.Body` and `Card.Footer`; the slots carry the padding and dividers so\nthe root stays a plain surface. Every value comes from `--card-*` tokens;\nstate is exposed as `data-variant`, `data-padding` and `data-interactive`.",
465
+ "status": "stable",
466
+ "category": "Layout",
467
+ "accessibility": "A `section` by default (a `region` when it has an accessible name); with `asChild` the child element's own semantics apply. `interactive` adds a focus ring and a tab stop only when the element is not already focusable.",
468
+ "do": [
469
+ "Give a card an `aria-label` or a heading in `Card.Header` when it is a landmark worth naming.",
470
+ "Use `asChild` with an `a` for a whole-card link."
471
+ ],
472
+ "dont": [
473
+ "Put more than one primary action inside an interactive card.",
474
+ "Nest interactive cards."
475
+ ],
476
+ "import": "import { Card } from '@pearpages/pulp-react/card';",
477
+ "css": "@pearpages/pulp-react/card.css",
478
+ "tokens": "--card-*",
479
+ "props": [
480
+ {
481
+ "name": "asChild",
482
+ "type": "boolean",
483
+ "required": false,
484
+ "default": "false",
485
+ "description": "Render the single child element as the card (an `<a>` for a link card),\nmerging the card's props into it."
486
+ },
487
+ {
488
+ "name": "interactive",
489
+ "type": "boolean",
490
+ "required": false,
491
+ "default": "false",
492
+ "description": "Hover and focus affordances for a card that is itself a target. Pair it\nwith `asChild` and a link, or supply your own role and handlers."
493
+ },
494
+ {
495
+ "name": "padding",
496
+ "type": "enum",
497
+ "required": false,
498
+ "default": "md",
499
+ "description": "One knob for every slot's inner spacing."
500
+ },
501
+ {
502
+ "name": "ref",
503
+ "type": "Ref<E>",
504
+ "required": false,
505
+ "default": null,
506
+ "description": "The rendered element; a `<section>` unless `asChild`."
507
+ },
508
+ {
509
+ "name": "variant",
510
+ "type": "enum",
511
+ "required": false,
512
+ "default": "raised",
513
+ "description": "How the card separates from the page: `raised` by shadow, `outlined` by\nborder, `sunken` by a recessed surface."
514
+ }
515
+ ],
516
+ "parts": [
517
+ {
518
+ "name": "Card.Header",
519
+ "description": "",
520
+ "props": [
521
+ {
522
+ "name": "ref",
523
+ "type": "Ref<HTMLDivElement>",
524
+ "required": false,
525
+ "default": null,
526
+ "description": ""
527
+ }
528
+ ]
529
+ },
530
+ {
531
+ "name": "Card.Body",
532
+ "description": "",
533
+ "props": [
534
+ {
535
+ "name": "ref",
536
+ "type": "Ref<HTMLDivElement>",
537
+ "required": false,
538
+ "default": null,
539
+ "description": ""
540
+ }
541
+ ]
542
+ },
543
+ {
544
+ "name": "Card.Footer",
545
+ "description": "",
546
+ "props": [
547
+ {
548
+ "name": "ref",
549
+ "type": "Ref<HTMLDivElement>",
550
+ "required": false,
551
+ "default": null,
552
+ "description": ""
553
+ }
554
+ ]
555
+ }
556
+ ]
557
+ },
558
+ {
559
+ "name": "Checkbox",
560
+ "description": "A native checkbox drawn with tokens: `appearance: none` on the input, the\nbox and tick in CSS, so keyboard, forms and assistive technology are the\nbrowser's own. Label, description and error come from Field. Controlled and\nuncontrolled behave like the native input. State is the native `:checked`\nand `:indeterminate`, plus `data-indeterminate` on the input.",
561
+ "status": "stable",
562
+ "category": "Forms",
563
+ "accessibility": "A native `input type=\"checkbox\"` with `appearance: none`; label, description and error wire through Field. `indeterminate` sets the DOM property and `aria-checked=\"mixed\"`. Keyboard: Space toggles.",
564
+ "do": [
565
+ "Use `indeterminate` for a parent whose children are partly selected.",
566
+ "Group related checkboxes under a `fieldset`."
567
+ ],
568
+ "dont": [
569
+ "Use it for an immediate setting; use Switch.",
570
+ "Hide the label; the description does not name the control."
571
+ ],
572
+ "import": "import { Checkbox } from '@pearpages/pulp-react/checkbox';",
573
+ "css": "@pearpages/pulp-react/checkbox.css",
574
+ "tokens": "--checkbox-*",
575
+ "props": [
576
+ {
577
+ "name": "label",
578
+ "type": "ReactNode",
579
+ "required": true,
580
+ "default": null,
581
+ "description": "Visible label beside the box."
582
+ },
583
+ {
584
+ "name": "className",
585
+ "type": "string",
586
+ "required": false,
587
+ "default": null,
588
+ "description": "Applied to the wrapper, not the input."
589
+ },
590
+ {
591
+ "name": "description",
592
+ "type": "ReactNode",
593
+ "required": false,
594
+ "default": null,
595
+ "description": ""
596
+ },
597
+ {
598
+ "name": "error",
599
+ "type": "ReactNode",
600
+ "required": false,
601
+ "default": null,
602
+ "description": "Presence marks the control invalid and announces the message."
603
+ },
604
+ {
605
+ "name": "indeterminate",
606
+ "type": "boolean",
607
+ "required": false,
608
+ "default": "false",
609
+ "description": "The \"some selected\" state; visual and `aria-checked=\"mixed\"`, independent of `checked`."
610
+ },
611
+ {
612
+ "name": "ref",
613
+ "type": "Ref<HTMLInputElement>",
614
+ "required": false,
615
+ "default": null,
616
+ "description": "The `<input>` element."
617
+ },
618
+ {
619
+ "name": "size",
620
+ "type": "enum",
621
+ "required": false,
622
+ "default": "md",
623
+ "description": ""
624
+ }
625
+ ],
626
+ "parts": []
627
+ },
628
+ {
629
+ "name": "Combobox",
630
+ "description": "A text input that suggests options as the user types, on React Aria's\ncombobox (decision record 001): the list is announced through\n`aria-activedescendant`, arrows move, Enter selects, Escape closes and\nthen clears. Static lists filter themselves; for async options, control\n`inputValue`, fetch, and pass the results with `filter=\"none\"` and\n`loading` while they arrive. Options look the same as Listbox's.",
631
+ "status": "experimental",
632
+ "category": "Forms",
633
+ "accessibility": "A `combobox` input with `aria-autocomplete=\"list\"`; the open list is a `listbox` announced through `aria-activedescendant`, so focus stays in the input. Arrows move, Enter selects, Escape closes and then clears. Loading and empty states are announced from inside the list.",
634
+ "do": [
635
+ "Use `filter=\"none\"` with controlled `inputValue` for server-side search.",
636
+ "Keep `loading` true until the results for the current text arrive."
637
+ ],
638
+ "dont": [
639
+ "Use it for fewer than five fixed options; use Picker or the native Select.",
640
+ "Set `menuTrigger=\"focus\"` on a long list; opening on every focus is noisy."
641
+ ],
642
+ "import": "import { Combobox } from '@pearpages/pulp-react/combobox';",
643
+ "css": "@pearpages/pulp-react/combobox.css",
644
+ "tokens": "--combobox-*",
645
+ "props": [
646
+ {
647
+ "name": "items",
648
+ "type": "readonly ListboxItem[]",
649
+ "required": true,
650
+ "default": null,
651
+ "description": "The options. With `filter=\"none\"` they are shown as given."
652
+ },
653
+ {
654
+ "name": "label",
655
+ "type": "ReactNode",
656
+ "required": true,
657
+ "default": null,
658
+ "description": "Visible label. Always rendered."
659
+ },
660
+ {
661
+ "name": "allowsCustomValue",
662
+ "type": "boolean",
663
+ "required": false,
664
+ "default": "false",
665
+ "description": "Let the typed text stand as the value even when it matches no option."
666
+ },
667
+ {
668
+ "name": "autoFocus",
669
+ "type": "boolean",
670
+ "required": false,
671
+ "default": null,
672
+ "description": ""
673
+ },
674
+ {
675
+ "name": "className",
676
+ "type": "string",
677
+ "required": false,
678
+ "default": null,
679
+ "description": "Applied to the field wrapper, not the input."
680
+ },
681
+ {
682
+ "name": "defaultInputValue",
683
+ "type": "string",
684
+ "required": false,
685
+ "default": null,
686
+ "description": ""
687
+ },
688
+ {
689
+ "name": "defaultValue",
690
+ "type": "string | null",
691
+ "required": false,
692
+ "default": null,
693
+ "description": ""
694
+ },
695
+ {
696
+ "name": "description",
697
+ "type": "ReactNode",
698
+ "required": false,
699
+ "default": null,
700
+ "description": ""
701
+ },
702
+ {
703
+ "name": "disabled",
704
+ "type": "boolean",
705
+ "required": false,
706
+ "default": "false",
707
+ "description": ""
708
+ },
709
+ {
710
+ "name": "emptyMessage",
711
+ "type": "ReactNode",
712
+ "required": false,
713
+ "default": "No results",
714
+ "description": "Shown in the open list when no option matches."
715
+ },
716
+ {
717
+ "name": "error",
718
+ "type": "ReactNode",
719
+ "required": false,
720
+ "default": null,
721
+ "description": "Presence marks the control invalid and announces the message."
722
+ },
723
+ {
724
+ "name": "filter",
725
+ "type": "enum",
726
+ "required": false,
727
+ "default": "contains",
728
+ "description": ""
729
+ },
730
+ {
731
+ "name": "inputValue",
732
+ "type": "string",
733
+ "required": false,
734
+ "default": null,
735
+ "description": "The text in the input (controlled). Pair with `onInputChange` to fetch options as the user types."
736
+ },
737
+ {
738
+ "name": "loading",
739
+ "type": "boolean",
740
+ "required": false,
741
+ "default": "false",
742
+ "description": "Keeps the list open with a spinner in the control while options load."
743
+ },
744
+ {
745
+ "name": "loadingMessage",
746
+ "type": "ReactNode",
747
+ "required": false,
748
+ "default": "Loading…",
749
+ "description": "Announced while `loading`."
750
+ },
751
+ {
752
+ "name": "menuTrigger",
753
+ "type": "enum",
754
+ "required": false,
755
+ "default": "input",
756
+ "description": "When the list opens: on focus, on typing, or only from the button and arrow keys."
757
+ },
758
+ {
759
+ "name": "name",
760
+ "type": "string",
761
+ "required": false,
762
+ "default": null,
763
+ "description": "Submitted with a form: the selected id (or the text with `allowsCustomValue`)."
764
+ },
765
+ {
766
+ "name": "onChange",
767
+ "type": "((value: string | null) => void)",
768
+ "required": false,
769
+ "default": null,
770
+ "description": ""
771
+ },
772
+ {
773
+ "name": "onInputChange",
774
+ "type": "((text: string) => void)",
775
+ "required": false,
776
+ "default": null,
777
+ "description": ""
778
+ },
779
+ {
780
+ "name": "placeholder",
781
+ "type": "string",
782
+ "required": false,
783
+ "default": null,
784
+ "description": ""
785
+ },
786
+ {
787
+ "name": "readOnly",
788
+ "type": "boolean",
789
+ "required": false,
790
+ "default": "false",
791
+ "description": ""
792
+ },
793
+ {
794
+ "name": "ref",
795
+ "type": "Ref<HTMLInputElement>",
796
+ "required": false,
797
+ "default": null,
798
+ "description": "The `<input>` element."
799
+ },
800
+ {
801
+ "name": "required",
802
+ "type": "boolean",
803
+ "required": false,
804
+ "default": "false",
805
+ "description": ""
806
+ },
807
+ {
808
+ "name": "size",
809
+ "type": "enum",
810
+ "required": false,
811
+ "default": "md",
812
+ "description": ""
813
+ },
814
+ {
815
+ "name": "value",
816
+ "type": "string | null",
817
+ "required": false,
818
+ "default": null,
819
+ "description": "Selected id (controlled). `null` is \"nothing selected\"."
820
+ }
821
+ ],
822
+ "parts": []
823
+ },
824
+ {
825
+ "name": "DatePicker",
826
+ "description": "A date field with a calendar popover, on React Aria's date picker\n(decision record 001): the date is typed segment by segment in the\nuser's locale order (arrows and digits, no free text to parse), and the\nbutton opens the same month grid as Calendar. Dates cross the API as\nISO strings.",
827
+ "status": "experimental",
828
+ "category": "Forms",
829
+ "accessibility": "A `group` named by the label holding one `spinbutton` per date segment (day, month, year in the locale's order), a button that opens a `dialog` containing the Calendar grid, and a hidden input for forms. Arrows step a segment, digits type it, Escape closes the dialog and returns focus.",
830
+ "do": [
831
+ "Pass `locale` when the app's language is not the browser's.",
832
+ "Use `min`/`max` for ranges the user cannot choose outside of."
833
+ ],
834
+ "dont": [
835
+ "Parse the value yourself; it is always `YYYY-MM-DD`.",
836
+ "Use it for a date of birth decades away; the segments are faster than the calendar."
837
+ ],
838
+ "import": "import { DatePicker } from '@pearpages/pulp-react/date-picker';",
839
+ "css": "@pearpages/pulp-react/date-picker.css",
840
+ "tokens": "--date-picker-*",
841
+ "props": [
842
+ {
843
+ "name": "label",
844
+ "type": "ReactNode",
845
+ "required": true,
846
+ "default": null,
847
+ "description": "Visible label. Always rendered."
848
+ },
849
+ {
850
+ "name": "autoFocus",
851
+ "type": "boolean",
852
+ "required": false,
853
+ "default": null,
854
+ "description": ""
855
+ },
856
+ {
857
+ "name": "className",
858
+ "type": "string",
859
+ "required": false,
860
+ "default": null,
861
+ "description": "Applied to the field wrapper."
862
+ },
863
+ {
864
+ "name": "defaultValue",
865
+ "type": "string | null",
866
+ "required": false,
867
+ "default": null,
868
+ "description": ""
869
+ },
870
+ {
871
+ "name": "description",
872
+ "type": "ReactNode",
873
+ "required": false,
874
+ "default": null,
875
+ "description": ""
876
+ },
877
+ {
878
+ "name": "disabled",
879
+ "type": "boolean",
880
+ "required": false,
881
+ "default": "false",
882
+ "description": ""
883
+ },
884
+ {
885
+ "name": "error",
886
+ "type": "ReactNode",
887
+ "required": false,
888
+ "default": null,
889
+ "description": "Presence marks the control invalid and announces the message."
890
+ },
891
+ {
892
+ "name": "isDateUnavailable",
893
+ "type": "((date: string) => boolean)",
894
+ "required": false,
895
+ "default": null,
896
+ "description": "Marks single dates as unavailable in the calendar."
897
+ },
898
+ {
899
+ "name": "locale",
900
+ "type": "string",
901
+ "required": false,
902
+ "default": null,
903
+ "description": "BCP 47 tag. Segment order, month names and the first weekday follow it; defaults to the browser's."
904
+ },
905
+ {
906
+ "name": "max",
907
+ "type": "string",
908
+ "required": false,
909
+ "default": null,
910
+ "description": "Latest selectable date, `YYYY-MM-DD`."
911
+ },
912
+ {
913
+ "name": "min",
914
+ "type": "string",
915
+ "required": false,
916
+ "default": null,
917
+ "description": "Earliest selectable date, `YYYY-MM-DD`."
918
+ },
919
+ {
920
+ "name": "name",
921
+ "type": "string",
922
+ "required": false,
923
+ "default": null,
924
+ "description": "Submitted with a form as `YYYY-MM-DD` through a hidden input."
925
+ },
926
+ {
927
+ "name": "onChange",
928
+ "type": "((value: string | null) => void)",
929
+ "required": false,
930
+ "default": null,
931
+ "description": ""
932
+ },
933
+ {
934
+ "name": "readOnly",
935
+ "type": "boolean",
936
+ "required": false,
937
+ "default": "false",
938
+ "description": ""
939
+ },
940
+ {
941
+ "name": "ref",
942
+ "type": "Ref<HTMLDivElement>",
943
+ "required": false,
944
+ "default": null,
945
+ "description": "The wrapper element."
946
+ },
947
+ {
948
+ "name": "required",
949
+ "type": "boolean",
950
+ "required": false,
951
+ "default": "false",
952
+ "description": ""
953
+ },
954
+ {
955
+ "name": "size",
956
+ "type": "enum",
957
+ "required": false,
958
+ "default": "md",
959
+ "description": ""
960
+ },
961
+ {
962
+ "name": "value",
963
+ "type": "string | null",
964
+ "required": false,
965
+ "default": null,
966
+ "description": "The date as `YYYY-MM-DD` (controlled). `null` is \"none\"."
967
+ }
968
+ ],
969
+ "parts": []
970
+ },
971
+ {
972
+ "name": "DialogSystem",
973
+ "description": "Mount once near the app root. Owns the portal element every dialog renders\ninto and sets the vendor's `--modal-*` variables on it from pulp's\n`--dialog-*` tokens, so backdrop, surface, type and motion follow the\ncurrent brand and scheme. Because the variables sit on an ancestor of the\ndialog, they win over the vendor stylesheet regardless of cascade layers\nor import order.",
974
+ "status": "stable",
975
+ "category": "Overlays",
976
+ "accessibility": "Renders nothing visible itself; the portal element it owns is where every dialog mounts, so the vendor's focus trap and `inert` handling apply to the rest of the page.",
977
+ "do": [
978
+ "Mount it once, near the app root, inside any providers dialogs need."
979
+ ],
980
+ "dont": [
981
+ "Nest it; one system serves every dialog."
982
+ ],
983
+ "import": "import { DialogSystem } from '@pearpages/pulp-react/dialog';",
984
+ "css": "@pearpages/pulp-react/dialog.css",
985
+ "tokens": "--dialog-*",
986
+ "props": [
987
+ {
988
+ "name": "children",
989
+ "type": "ReactNode",
990
+ "required": true,
991
+ "default": null,
992
+ "description": "Children components"
993
+ },
994
+ {
995
+ "name": "baseZIndex",
996
+ "type": "number",
997
+ "required": false,
998
+ "default": null,
999
+ "description": "Base z-index for modal layering"
1000
+ }
1001
+ ],
1002
+ "parts": []
1003
+ },
1004
+ {
1005
+ "name": "Dialog",
1006
+ "description": "An accessible modal dialog: focus trap, inert page, Escape and backdrop\ndismissal, stacking. Built on `@pearpages/modals`; pulp adds the theming and\nthe compound API (`Dialog.Trigger`, `Dialog.Content`, `Dialog.Header`,\n`Dialog.Title`, `Dialog.Description`, `Dialog.Close`, `Dialog.Body`,\n`Dialog.Footer`). The trigger is a sibling of the dialog, not a child: a\ndialog's children render only while it is open. Use pulp's `Button` for\nactions. Requires `DialogSystem` above it and the vendor stylesheet\n`@pearpages/modals/styles.css`.",
1007
+ "status": "stable",
1008
+ "category": "Overlays",
1009
+ "accessibility": "`role=\"dialog\"` with `aria-modal`, named by `Dialog.Title` and described by `Dialog.Description`; focus moves in on open and back to the trigger on close; the page behind is inert; Escape and the backdrop close it. Provided by `@pearpages/modals`.",
1010
+ "do": [
1011
+ "Always render a `Dialog.Title`.",
1012
+ "Put the destructive action last in `Dialog.Footer` and make the safe one the default focus."
1013
+ ],
1014
+ "dont": [
1015
+ "Open a dialog from inside a Menu or Popover that stays open.",
1016
+ "Use it for content that does not need the page blocked; use Popover."
1017
+ ],
1018
+ "import": "import { Dialog } from '@pearpages/pulp-react/dialog';",
1019
+ "css": "@pearpages/pulp-react/dialog.css",
1020
+ "tokens": "--dialog-*",
1021
+ "props": [
1022
+ {
1023
+ "name": "children",
1024
+ "type": "ReactNode",
1025
+ "required": true,
1026
+ "default": null,
1027
+ "description": "Children components (typically Modal.Content)"
1028
+ },
1029
+ {
1030
+ "name": "id",
1031
+ "type": "string",
1032
+ "required": true,
1033
+ "default": null,
1034
+ "description": "Unique identifier for the modal within a ModalSystem instance"
1035
+ },
1036
+ {
1037
+ "name": "onOpenChange",
1038
+ "type": "((open: boolean) => void)",
1039
+ "required": false,
1040
+ "default": null,
1041
+ "description": "Callback fired when open state changes"
1042
+ },
1043
+ {
1044
+ "name": "open",
1045
+ "type": "boolean",
1046
+ "required": false,
1047
+ "default": null,
1048
+ "description": "Controlled open state"
1049
+ }
1050
+ ],
1051
+ "parts": []
1052
+ },
1053
+ {
1054
+ "name": "Field",
1055
+ "description": "The wiring every form control shares: a label pointing at the control, a\ndescription and an error exposed through `aria-describedby`, and invalid,\ndisabled and required state in one place. Only parts that are mounted end\nup in `aria-describedby`, so no id ever dangles. Compose with\n`Field.Label`, `Field.Control`, `Field.Description` and `Field.Error`\n(one of each); state on the DOM as `data-invalid`, `data-disabled`,\n`data-required`.\n\nKnown limitation: parts register in a layout effect, so server-rendered\nHTML carries no `aria-describedby` until hydration. The relationship is\ncomplete for every interactive use; static HTML consumers should not rely\non it yet.",
1056
+ "status": "stable",
1057
+ "category": "Forms",
1058
+ "accessibility": "Wires `label[for]`, `aria-describedby` (only mounted parts), `aria-invalid`, `aria-required` and `disabled` onto the control. Server-rendered HTML has no `aria-describedby` until hydration (a test pins the gap).",
1059
+ "do": [
1060
+ "Use `Field.Label as=\"span\"` with `useField().labelId` for groups that cannot be labelled by `for`."
1061
+ ],
1062
+ "dont": [
1063
+ "Mount two `Field.Description` or two `Field.Error`; ids would collide (development warns)."
1064
+ ],
1065
+ "import": "import { Field } from '@pearpages/pulp-react/field';",
1066
+ "css": "@pearpages/pulp-react/field.css",
1067
+ "tokens": "--field-*",
1068
+ "props": [
1069
+ {
1070
+ "name": "disabled",
1071
+ "type": "boolean",
1072
+ "required": false,
1073
+ "default": "false",
1074
+ "description": ""
1075
+ },
1076
+ {
1077
+ "name": "id",
1078
+ "type": "string",
1079
+ "required": false,
1080
+ "default": null,
1081
+ "description": "The control's id. Generated when omitted."
1082
+ },
1083
+ {
1084
+ "name": "invalid",
1085
+ "type": "boolean",
1086
+ "required": false,
1087
+ "default": "false",
1088
+ "description": ""
1089
+ },
1090
+ {
1091
+ "name": "ref",
1092
+ "type": "Ref<HTMLDivElement>",
1093
+ "required": false,
1094
+ "default": null,
1095
+ "description": ""
1096
+ },
1097
+ {
1098
+ "name": "required",
1099
+ "type": "boolean",
1100
+ "required": false,
1101
+ "default": "false",
1102
+ "description": ""
1103
+ }
1104
+ ],
1105
+ "parts": [
1106
+ {
1107
+ "name": "Field.Label",
1108
+ "description": "",
1109
+ "props": [
1110
+ {
1111
+ "name": "as",
1112
+ "type": "enum",
1113
+ "required": false,
1114
+ "default": "label",
1115
+ "description": "`label` points at the control with `for`. `span` is for controls that are\nnot labelable (a radio group, a fieldset): it carries `labelId` and the\ncontrol references it with `aria-labelledby`."
1116
+ },
1117
+ {
1118
+ "name": "ref",
1119
+ "type": "Ref<HTMLLabelElement>",
1120
+ "required": false,
1121
+ "default": null,
1122
+ "description": ""
1123
+ }
1124
+ ]
1125
+ },
1126
+ {
1127
+ "name": "Field.Control",
1128
+ "description": "",
1129
+ "props": [
1130
+ {
1131
+ "name": "children",
1132
+ "type": "ReactNode",
1133
+ "required": true,
1134
+ "default": null,
1135
+ "description": "The single control element; the field's wiring is merged into it."
1136
+ },
1137
+ {
1138
+ "name": "aria-describedby",
1139
+ "type": "string",
1140
+ "required": false,
1141
+ "default": null,
1142
+ "description": "Extra ids to describe the control by, kept alongside the field's own."
1143
+ }
1144
+ ]
1145
+ },
1146
+ {
1147
+ "name": "Field.Description",
1148
+ "description": "",
1149
+ "props": [
1150
+ {
1151
+ "name": "ref",
1152
+ "type": "Ref<HTMLParagraphElement>",
1153
+ "required": false,
1154
+ "default": null,
1155
+ "description": ""
1156
+ }
1157
+ ]
1158
+ },
1159
+ {
1160
+ "name": "Field.Error",
1161
+ "description": "",
1162
+ "props": [
1163
+ {
1164
+ "name": "ref",
1165
+ "type": "Ref<HTMLParagraphElement>",
1166
+ "required": false,
1167
+ "default": null,
1168
+ "description": ""
1169
+ }
1170
+ ]
1171
+ }
1172
+ ]
1173
+ },
1174
+ {
1175
+ "name": "Heading",
1176
+ "description": "A heading whose outline level and visual size are separate decisions, so\nthe document structure stays honest while the design stays flexible.\nDisplay family and tight leading from `--heading-*` tokens.",
1177
+ "status": "stable",
1178
+ "category": "Typography",
1179
+ "accessibility": "Renders the `h1`–`h6` element of `level`; `size` changes only the look, so the outline stays truthful.",
1180
+ "do": [
1181
+ "Pick `level` from the outline, then `size` from the design."
1182
+ ],
1183
+ "dont": [
1184
+ "Skip heading levels to get a smaller size; change `size` instead."
1185
+ ],
1186
+ "import": "import { Heading } from '@pearpages/pulp-react/heading';",
1187
+ "css": "@pearpages/pulp-react/heading.css",
1188
+ "tokens": "--heading-*",
1189
+ "props": [
1190
+ {
1191
+ "name": "level",
1192
+ "type": "enum",
1193
+ "required": true,
1194
+ "default": null,
1195
+ "description": "The document outline level; sets the element (`h1`–`h6`)."
1196
+ },
1197
+ {
1198
+ "name": "ref",
1199
+ "type": "Ref<HTMLHeadingElement>",
1200
+ "required": false,
1201
+ "default": null,
1202
+ "description": ""
1203
+ },
1204
+ {
1205
+ "name": "size",
1206
+ "type": "enum",
1207
+ "required": false,
1208
+ "default": null,
1209
+ "description": "Visual size, decoupled from the level. Defaults by level: 1→2xl, 2→xl, 3→lg, 4→md, 5 and 6→sm."
1210
+ },
1211
+ {
1212
+ "name": "tone",
1213
+ "type": "enum",
1214
+ "required": false,
1215
+ "default": "default",
1216
+ "description": ""
1217
+ }
1218
+ ],
1219
+ "parts": []
1220
+ },
1221
+ {
1222
+ "name": "Icon",
1223
+ "description": "Sizes any SVG to the icon scale and settles its accessibility: decorative\nby default, an image when given a `label`. Colour is `currentColor`, so an\nicon inherits the text tone around it.",
1224
+ "status": "stable",
1225
+ "category": "Utilities",
1226
+ "accessibility": "`aria-hidden` by default (decorative); `role=\"img\"` with `aria-label` when `label` is given. Sized in `em` so it follows the text around it.",
1227
+ "do": [
1228
+ "Give `label` only when the icon carries meaning the text around it does not."
1229
+ ],
1230
+ "dont": [
1231
+ "Use a labelled icon as the only name of a control; use IconButton."
1232
+ ],
1233
+ "import": "import { Icon } from '@pearpages/pulp-react/icon';",
1234
+ "css": "@pearpages/pulp-react/icon.css",
1235
+ "tokens": "--icon-*",
1236
+ "props": [
1237
+ {
1238
+ "name": "children",
1239
+ "type": "ReactNode",
1240
+ "required": true,
1241
+ "default": null,
1242
+ "description": "Any SVG (for instance from `@pearpages/pulp-icons`); it is sized to the icon box."
1243
+ },
1244
+ {
1245
+ "name": "label",
1246
+ "type": "string",
1247
+ "required": false,
1248
+ "default": null,
1249
+ "description": "Accessible name. Without it the icon is decorative and hidden from\nassistive technology; with it the icon is an image with that name."
1250
+ },
1251
+ {
1252
+ "name": "ref",
1253
+ "type": "Ref<HTMLSpanElement>",
1254
+ "required": false,
1255
+ "default": null,
1256
+ "description": ""
1257
+ },
1258
+ {
1259
+ "name": "size",
1260
+ "type": "enum",
1261
+ "required": false,
1262
+ "default": "md",
1263
+ "description": "`inherit` follows the surrounding font size, for icons inside text-sized controls."
1264
+ }
1265
+ ],
1266
+ "parts": []
1267
+ },
1268
+ {
1269
+ "name": "IconButton",
1270
+ "description": "A square Button that shows only an icon and therefore *requires* a name.\nEverything else (variants, sizes, loading, asChild) is Button's; the\n`--icon-button-size-*` tokens make it square.",
1271
+ "status": "stable",
1272
+ "category": "Actions",
1273
+ "accessibility": "A Button with `aria-label` from the required `label`; `title` shows it as a tooltip. Everything else is Button's.",
1274
+ "do": [
1275
+ "Write the label as the action (\"Close\", \"Add item\")."
1276
+ ],
1277
+ "dont": [
1278
+ "Use the icon's name as the label."
1279
+ ],
1280
+ "import": "import { IconButton } from '@pearpages/pulp-react/icon-button';",
1281
+ "css": "@pearpages/pulp-react/icon-button.css",
1282
+ "tokens": "--icon-button-*",
1283
+ "props": [
1284
+ {
1285
+ "name": "icon",
1286
+ "type": "ReactNode",
1287
+ "required": true,
1288
+ "default": null,
1289
+ "description": "The glyph, for instance from `@pearpages/pulp-icons`."
1290
+ },
1291
+ {
1292
+ "name": "label",
1293
+ "type": "string",
1294
+ "required": true,
1295
+ "default": null,
1296
+ "description": "The accessible name. Required: an icon alone is not a name. Also used as the tooltip unless `title` is given."
1297
+ },
1298
+ {
1299
+ "name": "asChild",
1300
+ "type": "boolean",
1301
+ "required": false,
1302
+ "default": "false",
1303
+ "description": "Render the single child element instead of a `<button>`, merging the\nbutton's props into it. Use it to style a router `<Link>` or an `<a>` as a\nbutton. Disabled and loading states then use `aria-disabled`, and the\nchild's own `onClick` does not run while the control is inert."
1304
+ },
1305
+ {
1306
+ "name": "children",
1307
+ "type": "ReactElement<unknown, string | JSXElementConstructor<any>>",
1308
+ "required": false,
1309
+ "default": null,
1310
+ "description": "With `asChild`: the element to render (a link, for instance). Its own children are replaced by the icon."
1311
+ },
1312
+ {
1313
+ "name": "loading",
1314
+ "type": "boolean",
1315
+ "required": false,
1316
+ "default": "false",
1317
+ "description": "Shows a spinner, sets `aria-busy` and `aria-disabled`, and blocks\nactivation. The element stays focusable so focus is not lost mid-action,\nand the label stays in place so the button keeps its width."
1318
+ },
1319
+ {
1320
+ "name": "ref",
1321
+ "type": "Ref<E>",
1322
+ "required": false,
1323
+ "default": null,
1324
+ "description": "The rendered element. With `asChild` that is the child's element, so pass\nthe type parameter: `<Button<HTMLAnchorElement> asChild ref={anchorRef}>`."
1325
+ },
1326
+ {
1327
+ "name": "size",
1328
+ "type": "enum",
1329
+ "required": false,
1330
+ "default": "'md'",
1331
+ "description": ""
1332
+ },
1333
+ {
1334
+ "name": "variant",
1335
+ "type": "enum",
1336
+ "required": false,
1337
+ "default": "'primary'",
1338
+ "description": "Visual emphasis. One `primary` per view; `secondary` for the rest;\n`ghost` for actions that sit inside other content."
1339
+ }
1340
+ ],
1341
+ "parts": []
1342
+ },
1343
+ {
1344
+ "name": "Inline",
1345
+ "description": "A flex row whose gap is a step on the spacing scale, so consumers\ncompose layout from tokens instead of writing padding and margins.\nRendered as `ul`/`ol` it keeps `role=\"list\"` explicitly, because Safari\nstops announcing a list once `list-style` is removed.",
1346
+ "status": "stable",
1347
+ "category": "Layout",
1348
+ "accessibility": "Layout only: no role unless rendered as `ul`/`ol`, where `role=\"list\"` is kept explicitly because Safari drops list semantics without markers.",
1349
+ "do": [
1350
+ "Use `as=\"ul\"` for a list of like items so the count is announced."
1351
+ ],
1352
+ "dont": [
1353
+ "Use it to space unrelated regions; it is one flex row."
1354
+ ],
1355
+ "import": "import { Inline } from '@pearpages/pulp-react/inline';",
1356
+ "css": "@pearpages/pulp-react/inline.css",
1357
+ "tokens": "--inline-*",
1358
+ "props": [
1359
+ {
1360
+ "name": "align",
1361
+ "type": "enum",
1362
+ "required": false,
1363
+ "default": null,
1364
+ "description": ""
1365
+ },
1366
+ {
1367
+ "name": "as",
1368
+ "type": "enum",
1369
+ "required": false,
1370
+ "default": "div",
1371
+ "description": ""
1372
+ },
1373
+ {
1374
+ "name": "gap",
1375
+ "type": "enum",
1376
+ "required": false,
1377
+ "default": "3",
1378
+ "description": "Step on the spacing scale (`--space-1` … `--space-8`)."
1379
+ },
1380
+ {
1381
+ "name": "justify",
1382
+ "type": "enum",
1383
+ "required": false,
1384
+ "default": null,
1385
+ "description": ""
1386
+ },
1387
+ {
1388
+ "name": "ref",
1389
+ "type": "Ref<HTMLElement>",
1390
+ "required": false,
1391
+ "default": null,
1392
+ "description": ""
1393
+ },
1394
+ {
1395
+ "name": "wrap",
1396
+ "type": "boolean",
1397
+ "required": false,
1398
+ "default": "true",
1399
+ "description": "Wrap onto new lines when the row overflows."
1400
+ }
1401
+ ],
1402
+ "parts": []
1403
+ },
1404
+ {
1405
+ "name": "Listbox",
1406
+ "description": "A visible list of options with single or multiple selection, on React\nAria's listbox (decision record 001): arrow keys move, Space toggles,\ntyping jumps, Shift and Ctrl/Cmd extend a multiple selection, Ctrl/Cmd+A\nselects all. For a list that opens from a control, use Picker; for one\nthat filters as you type, use Combobox. Both render these options.",
1407
+ "status": "experimental",
1408
+ "category": "Forms",
1409
+ "accessibility": "`role=\"listbox\"` (with `aria-multiselectable` when multiple) named by `aria-label` or `aria-labelledby`; options carry `aria-selected` and `aria-disabled`. One tab stop: arrows move, Space toggles, typing jumps, Shift and Ctrl/Cmd extend, Ctrl/Cmd+A selects all.",
1410
+ "do": [
1411
+ "Give it a name: `aria-label`, or `aria-labelledby` pointing at a visible heading.",
1412
+ "Use `selectionMode=\"multiple\"` for several choices; a group of Checkboxes works too and needs no explanation."
1413
+ ],
1414
+ "dont": [
1415
+ "Show more than a screen of options; filter with Combobox."
1416
+ ],
1417
+ "import": "import { Listbox } from '@pearpages/pulp-react/listbox';",
1418
+ "css": "@pearpages/pulp-react/listbox.css",
1419
+ "tokens": "--listbox-*",
1420
+ "props": [
1421
+ {
1422
+ "name": "items",
1423
+ "type": "readonly ListboxItem[]",
1424
+ "required": true,
1425
+ "default": null,
1426
+ "description": "The options, in order. Ids are the values."
1427
+ },
1428
+ {
1429
+ "name": "aria-label",
1430
+ "type": "string",
1431
+ "required": false,
1432
+ "default": null,
1433
+ "description": "The list's accessible name. Pass `aria-labelledby` instead when a visible heading names it."
1434
+ },
1435
+ {
1436
+ "name": "aria-labelledby",
1437
+ "type": "string",
1438
+ "required": false,
1439
+ "default": null,
1440
+ "description": ""
1441
+ },
1442
+ {
1443
+ "name": "className",
1444
+ "type": "string",
1445
+ "required": false,
1446
+ "default": null,
1447
+ "description": ""
1448
+ },
1449
+ {
1450
+ "name": "defaultValue",
1451
+ "type": "readonly string[]",
1452
+ "required": false,
1453
+ "default": "[]",
1454
+ "description": ""
1455
+ },
1456
+ {
1457
+ "name": "disabled",
1458
+ "type": "boolean",
1459
+ "required": false,
1460
+ "default": "false",
1461
+ "description": ""
1462
+ },
1463
+ {
1464
+ "name": "emptyMessage",
1465
+ "type": "ReactNode",
1466
+ "required": false,
1467
+ "default": "No options",
1468
+ "description": "Shown when `items` is empty."
1469
+ },
1470
+ {
1471
+ "name": "id",
1472
+ "type": "string",
1473
+ "required": false,
1474
+ "default": null,
1475
+ "description": ""
1476
+ },
1477
+ {
1478
+ "name": "onChange",
1479
+ "type": "((value: string[]) => void)",
1480
+ "required": false,
1481
+ "default": null,
1482
+ "description": ""
1483
+ },
1484
+ {
1485
+ "name": "ref",
1486
+ "type": "Ref<HTMLDivElement>",
1487
+ "required": false,
1488
+ "default": null,
1489
+ "description": "The list element (`role=\"listbox\"`)."
1490
+ },
1491
+ {
1492
+ "name": "selectionMode",
1493
+ "type": "enum",
1494
+ "required": false,
1495
+ "default": "single",
1496
+ "description": ""
1497
+ },
1498
+ {
1499
+ "name": "value",
1500
+ "type": "readonly string[]",
1501
+ "required": false,
1502
+ "default": null,
1503
+ "description": "Selected ids (controlled). An array in both modes; single mode holds at most one."
1504
+ }
1505
+ ],
1506
+ "parts": []
1507
+ },
1508
+ {
1509
+ "name": "Menu",
1510
+ "description": "A list of actions opened from a button, following the WAI-ARIA menu\nbutton pattern: Down/Up arrow on the trigger opens and focuses the first\nor last item, arrows move with wraparound, Home and End jump, typing\njumps to the next item starting with that letter, Enter, Space or click\nselects and closes, Escape and Tab close and return focus. Compose with\n`Menu.Trigger`, `Menu.Content`, `Menu.Item` and `Menu.Separator`.",
1511
+ "status": "stable",
1512
+ "category": "Overlays",
1513
+ "accessibility": "The WAI-ARIA menu button pattern: the trigger has `aria-haspopup=\"menu\"` and `aria-expanded`; the popup is `role=\"menu\"` named by the trigger with `menuitem` children. Down/Up opens to the first/last item, arrows wrap, Home/End jump, typing jumps, Enter/Space/click select and close, Escape and Tab close and return focus.",
1514
+ "do": [
1515
+ "Use `tone=\"danger\"` for destructive items and put them after a separator."
1516
+ ],
1517
+ "dont": [
1518
+ "Put form controls or links that navigate inside a menu; those want Popover or a navigation list.",
1519
+ "Use it for navigation between pages."
1520
+ ],
1521
+ "import": "import { Menu } from '@pearpages/pulp-react/menu';",
1522
+ "css": "@pearpages/pulp-react/menu.css",
1523
+ "tokens": "--menu-*",
1524
+ "props": [
1525
+ {
1526
+ "name": "defaultOpen",
1527
+ "type": "boolean",
1528
+ "required": false,
1529
+ "default": "false",
1530
+ "description": ""
1531
+ },
1532
+ {
1533
+ "name": "onOpenChange",
1534
+ "type": "((open: boolean) => void)",
1535
+ "required": false,
1536
+ "default": null,
1537
+ "description": ""
1538
+ },
1539
+ {
1540
+ "name": "open",
1541
+ "type": "boolean",
1542
+ "required": false,
1543
+ "default": null,
1544
+ "description": ""
1545
+ },
1546
+ {
1547
+ "name": "placement",
1548
+ "type": "enum",
1549
+ "required": false,
1550
+ "default": "bottom-start",
1551
+ "description": ""
1552
+ }
1553
+ ],
1554
+ "parts": [
1555
+ {
1556
+ "name": "Menu.Trigger",
1557
+ "description": "",
1558
+ "props": [
1559
+ {
1560
+ "name": "asChild",
1561
+ "type": "boolean",
1562
+ "required": false,
1563
+ "default": "false",
1564
+ "description": ""
1565
+ },
1566
+ {
1567
+ "name": "ref",
1568
+ "type": "Ref<HTMLButtonElement>",
1569
+ "required": false,
1570
+ "default": null,
1571
+ "description": ""
1572
+ }
1573
+ ]
1574
+ },
1575
+ {
1576
+ "name": "Menu.Content",
1577
+ "description": "",
1578
+ "props": [
1579
+ {
1580
+ "name": "ref",
1581
+ "type": "Ref<HTMLDivElement>",
1582
+ "required": false,
1583
+ "default": null,
1584
+ "description": ""
1585
+ }
1586
+ ]
1587
+ },
1588
+ {
1589
+ "name": "Menu.Item",
1590
+ "description": "",
1591
+ "props": [
1592
+ {
1593
+ "name": "icon",
1594
+ "type": "ReactNode",
1595
+ "required": false,
1596
+ "default": null,
1597
+ "description": "Leading glyph, decorative."
1598
+ },
1599
+ {
1600
+ "name": "onSelect",
1601
+ "type": "(() => void)",
1602
+ "required": false,
1603
+ "default": null,
1604
+ "description": "Called when the item is chosen; the menu closes afterwards."
1605
+ },
1606
+ {
1607
+ "name": "ref",
1608
+ "type": "Ref<HTMLButtonElement>",
1609
+ "required": false,
1610
+ "default": null,
1611
+ "description": ""
1612
+ },
1613
+ {
1614
+ "name": "tone",
1615
+ "type": "enum",
1616
+ "required": false,
1617
+ "default": "default",
1618
+ "description": ""
1619
+ }
1620
+ ]
1621
+ },
1622
+ {
1623
+ "name": "Menu.Separator",
1624
+ "description": "",
1625
+ "props": []
1626
+ }
1627
+ ]
1628
+ },
1629
+ {
1630
+ "name": "Pagination",
1631
+ "description": "Page controls in a `nav` landmark: previous, numbered pages with the\ncurrent one marked `aria-current=\"page\"`, and next. Distant pages\ncollapse into an ellipsis. Buttons by default; `getHref` renders links so\nthe pages are crawlable and open in new tabs. Built from Button and\nIconButton, so it needs no keyboard model of its own.",
1632
+ "status": "experimental",
1633
+ "category": "Navigation",
1634
+ "accessibility": "A `nav` landmark named by `aria-label`; the current page carries `aria-current=\"page\"`; previous and next are IconButtons with names; ellipses are hidden from assistive technology. With `getHref` the controls are links.",
1635
+ "do": [
1636
+ "Use `getHref` when pages have URLs so they can be opened in new tabs and crawled.",
1637
+ "Keep `siblings` at 1 on narrow screens."
1638
+ ],
1639
+ "dont": [
1640
+ "Disable the whole component while a page loads; disable only what cannot be pressed."
1641
+ ],
1642
+ "import": "import { Pagination } from '@pearpages/pulp-react/pagination';",
1643
+ "css": "@pearpages/pulp-react/pagination.css",
1644
+ "tokens": "--pagination-*",
1645
+ "props": [
1646
+ {
1647
+ "name": "count",
1648
+ "type": "number",
1649
+ "required": true,
1650
+ "default": null,
1651
+ "description": "Total number of pages."
1652
+ },
1653
+ {
1654
+ "name": "page",
1655
+ "type": "number",
1656
+ "required": true,
1657
+ "default": null,
1658
+ "description": "The current page, 1-based."
1659
+ },
1660
+ {
1661
+ "name": "aria-label",
1662
+ "type": "string",
1663
+ "required": false,
1664
+ "default": "Pagination",
1665
+ "description": "The landmark's name."
1666
+ },
1667
+ {
1668
+ "name": "boundaries",
1669
+ "type": "number",
1670
+ "required": false,
1671
+ "default": "1",
1672
+ "description": "Pages always shown at each end."
1673
+ },
1674
+ {
1675
+ "name": "getHref",
1676
+ "type": "((page: number) => string)",
1677
+ "required": false,
1678
+ "default": null,
1679
+ "description": "Render pages as links (server-side or router pagination) instead of buttons."
1680
+ },
1681
+ {
1682
+ "name": "nextLabel",
1683
+ "type": "string",
1684
+ "required": false,
1685
+ "default": "Next page",
1686
+ "description": ""
1687
+ },
1688
+ {
1689
+ "name": "onPageChange",
1690
+ "type": "((page: number) => void)",
1691
+ "required": false,
1692
+ "default": null,
1693
+ "description": ""
1694
+ },
1695
+ {
1696
+ "name": "pageLabel",
1697
+ "type": "((page: number) => string)",
1698
+ "required": false,
1699
+ "default": "(n) => `Page ${n}`",
1700
+ "description": "Accessible name of a page control."
1701
+ },
1702
+ {
1703
+ "name": "previousLabel",
1704
+ "type": "string",
1705
+ "required": false,
1706
+ "default": "Previous page",
1707
+ "description": ""
1708
+ },
1709
+ {
1710
+ "name": "ref",
1711
+ "type": "Ref<HTMLElement>",
1712
+ "required": false,
1713
+ "default": null,
1714
+ "description": ""
1715
+ },
1716
+ {
1717
+ "name": "siblings",
1718
+ "type": "number",
1719
+ "required": false,
1720
+ "default": "1",
1721
+ "description": "Pages shown on each side of the current one."
1722
+ },
1723
+ {
1724
+ "name": "size",
1725
+ "type": "enum",
1726
+ "required": false,
1727
+ "default": "md",
1728
+ "description": ""
1729
+ }
1730
+ ],
1731
+ "parts": []
1732
+ },
1733
+ {
1734
+ "name": "Picker",
1735
+ "description": "A single-choice select with rich options (a description line, consistent\nstyling in every browser), on React Aria's select (decision record 001):\na button opens a listbox, arrows and typing move, Enter chooses, Escape\ncloses, and a hidden native select carries the value in forms. For a\nplain list of words, the native `Select` is the default; for several\nchoices at once, use Listbox.",
1736
+ "status": "experimental",
1737
+ "category": "Forms",
1738
+ "accessibility": "A `button` named by the label with `aria-haspopup=\"listbox\"` and `aria-expanded`; the popup is a `listbox` with selected and disabled options; a hidden native select carries `name` and value for forms. Arrows open and move, typing jumps, Enter chooses, Escape closes and returns focus.",
1739
+ "do": [
1740
+ "Use a `description` line on options when the label alone is ambiguous.",
1741
+ "Prefer the native Select for a plain list of words."
1742
+ ],
1743
+ "dont": [
1744
+ "Use `placeholder` as the only label."
1745
+ ],
1746
+ "import": "import { Picker } from '@pearpages/pulp-react/picker';",
1747
+ "css": "@pearpages/pulp-react/picker.css",
1748
+ "tokens": "--picker-*",
1749
+ "props": [
1750
+ {
1751
+ "name": "items",
1752
+ "type": "readonly ListboxItem[]",
1753
+ "required": true,
1754
+ "default": null,
1755
+ "description": "The options. Ids are the values."
1756
+ },
1757
+ {
1758
+ "name": "label",
1759
+ "type": "ReactNode",
1760
+ "required": true,
1761
+ "default": null,
1762
+ "description": "Visible label. Always rendered."
1763
+ },
1764
+ {
1765
+ "name": "autoFocus",
1766
+ "type": "boolean",
1767
+ "required": false,
1768
+ "default": null,
1769
+ "description": ""
1770
+ },
1771
+ {
1772
+ "name": "className",
1773
+ "type": "string",
1774
+ "required": false,
1775
+ "default": null,
1776
+ "description": "Applied to the field wrapper, not the button."
1777
+ },
1778
+ {
1779
+ "name": "defaultValue",
1780
+ "type": "string | null",
1781
+ "required": false,
1782
+ "default": null,
1783
+ "description": ""
1784
+ },
1785
+ {
1786
+ "name": "description",
1787
+ "type": "ReactNode",
1788
+ "required": false,
1789
+ "default": null,
1790
+ "description": ""
1791
+ },
1792
+ {
1793
+ "name": "disabled",
1794
+ "type": "boolean",
1795
+ "required": false,
1796
+ "default": "false",
1797
+ "description": ""
1798
+ },
1799
+ {
1800
+ "name": "emptyMessage",
1801
+ "type": "ReactNode",
1802
+ "required": false,
1803
+ "default": "No options",
1804
+ "description": "Shown when `items` is empty."
1805
+ },
1806
+ {
1807
+ "name": "error",
1808
+ "type": "ReactNode",
1809
+ "required": false,
1810
+ "default": null,
1811
+ "description": "Presence marks the control invalid and announces the message."
1812
+ },
1813
+ {
1814
+ "name": "name",
1815
+ "type": "string",
1816
+ "required": false,
1817
+ "default": null,
1818
+ "description": "Submitted with a form through a hidden native select."
1819
+ },
1820
+ {
1821
+ "name": "onChange",
1822
+ "type": "((value: string | null) => void)",
1823
+ "required": false,
1824
+ "default": null,
1825
+ "description": ""
1826
+ },
1827
+ {
1828
+ "name": "placeholder",
1829
+ "type": "string",
1830
+ "required": false,
1831
+ "default": "Select…",
1832
+ "description": "Shown in the control until a value is chosen."
1833
+ },
1834
+ {
1835
+ "name": "ref",
1836
+ "type": "Ref<HTMLButtonElement>",
1837
+ "required": false,
1838
+ "default": null,
1839
+ "description": "The trigger `<button>`."
1840
+ },
1841
+ {
1842
+ "name": "required",
1843
+ "type": "boolean",
1844
+ "required": false,
1845
+ "default": "false",
1846
+ "description": ""
1847
+ },
1848
+ {
1849
+ "name": "size",
1850
+ "type": "enum",
1851
+ "required": false,
1852
+ "default": "md",
1853
+ "description": ""
1854
+ },
1855
+ {
1856
+ "name": "value",
1857
+ "type": "string | null",
1858
+ "required": false,
1859
+ "default": null,
1860
+ "description": "Selected id (controlled). `null` is \"nothing selected\"."
1861
+ }
1862
+ ],
1863
+ "parts": []
1864
+ },
1865
+ {
1866
+ "name": "Popover",
1867
+ "description": "A non-modal layer anchored to its trigger: a small form, a filter, a\ndetail panel. The page stays interactive; Escape, a click outside or\n`Popover.Close` dismiss it and focus returns to the trigger. Compose with\n`Popover.Trigger`, `Popover.Content` and `Popover.Close`. For anything that\nmust block the page, use Dialog.",
1868
+ "status": "stable",
1869
+ "category": "Overlays",
1870
+ "accessibility": "A non-modal `role=\"dialog\"` named by `title` (or `aria-label`); the trigger has `aria-haspopup=\"dialog\"` and `aria-expanded`. Focus moves to the first focusable element on open and back to the trigger on close; Escape and a click outside dismiss it.",
1871
+ "do": [
1872
+ "Give it a `title` or `aria-label`.",
1873
+ "Use `Popover.Close` inside forms so a keyboard user has a clear exit."
1874
+ ],
1875
+ "dont": [
1876
+ "Put a long form or a destructive confirmation in it; use Dialog.",
1877
+ "Open it on hover; that is Tooltip."
1878
+ ],
1879
+ "import": "import { Popover } from '@pearpages/pulp-react/popover';",
1880
+ "css": "@pearpages/pulp-react/popover.css",
1881
+ "tokens": "--popover-*",
1882
+ "props": [
1883
+ {
1884
+ "name": "defaultOpen",
1885
+ "type": "boolean",
1886
+ "required": false,
1887
+ "default": "false",
1888
+ "description": ""
1889
+ },
1890
+ {
1891
+ "name": "onOpenChange",
1892
+ "type": "((open: boolean) => void)",
1893
+ "required": false,
1894
+ "default": null,
1895
+ "description": ""
1896
+ },
1897
+ {
1898
+ "name": "open",
1899
+ "type": "boolean",
1900
+ "required": false,
1901
+ "default": null,
1902
+ "description": "Controlled open state."
1903
+ },
1904
+ {
1905
+ "name": "placement",
1906
+ "type": "enum",
1907
+ "required": false,
1908
+ "default": "bottom-start",
1909
+ "description": "Preferred side; flips when there is no room."
1910
+ }
1911
+ ],
1912
+ "parts": [
1913
+ {
1914
+ "name": "Popover.Trigger",
1915
+ "description": "",
1916
+ "props": [
1917
+ {
1918
+ "name": "asChild",
1919
+ "type": "boolean",
1920
+ "required": false,
1921
+ "default": "false",
1922
+ "description": "Render the child element as the trigger instead of a plain button."
1923
+ },
1924
+ {
1925
+ "name": "ref",
1926
+ "type": "Ref<HTMLButtonElement>",
1927
+ "required": false,
1928
+ "default": null,
1929
+ "description": ""
1930
+ }
1931
+ ]
1932
+ },
1933
+ {
1934
+ "name": "Popover.Content",
1935
+ "description": "",
1936
+ "props": [
1937
+ {
1938
+ "name": "ref",
1939
+ "type": "Ref<HTMLDivElement>",
1940
+ "required": false,
1941
+ "default": null,
1942
+ "description": ""
1943
+ },
1944
+ {
1945
+ "name": "title",
1946
+ "type": "ReactNode",
1947
+ "required": false,
1948
+ "default": null,
1949
+ "description": "Rendered as the dialog's heading and used as its accessible name. Otherwise pass `aria-label`."
1950
+ }
1951
+ ]
1952
+ },
1953
+ {
1954
+ "name": "Popover.Close",
1955
+ "description": "",
1956
+ "props": [
1957
+ {
1958
+ "name": "asChild",
1959
+ "type": "boolean",
1960
+ "required": false,
1961
+ "default": "false",
1962
+ "description": ""
1963
+ }
1964
+ ]
1965
+ }
1966
+ ]
1967
+ },
1968
+ {
1969
+ "name": "Progress",
1970
+ "description": "A determinate or indeterminate progress bar. The bar is `role=\"progressbar\"`\nlabelled by the visible (or visually hidden) label; the fill width is the\none place in the library that carries a per-instance inline value, set as\na custom property. Indeterminate motion stops under reduced motion.",
1971
+ "status": "stable",
1972
+ "category": "Feedback",
1973
+ "accessibility": "`role=\"progressbar\"` labelled by the required `label` (visible or visually hidden), with `aria-valuenow`/`aria-valuemin`/`aria-valuemax` when determinate and `aria-valuetext` from `valueText`. Indeterminate bars omit `aria-valuenow`.",
1974
+ "do": [
1975
+ "Set `valueText` when the percentage is not the meaningful reading (\"3 of 5 files\")."
1976
+ ],
1977
+ "dont": [
1978
+ "Use it for an unknown wait shorter than a few seconds; use Spinner."
1979
+ ],
1980
+ "import": "import { Progress } from '@pearpages/pulp-react/progress';",
1981
+ "css": "@pearpages/pulp-react/progress.css",
1982
+ "tokens": "--progress-*",
1983
+ "props": [
1984
+ {
1985
+ "name": "label",
1986
+ "type": "ReactNode",
1987
+ "required": true,
1988
+ "default": null,
1989
+ "description": "Required: what is progressing. Visible unless `hideLabel`."
1990
+ },
1991
+ {
1992
+ "name": "hideLabel",
1993
+ "type": "boolean",
1994
+ "required": false,
1995
+ "default": "false",
1996
+ "description": "Keep the label for assistive technology only."
1997
+ },
1998
+ {
1999
+ "name": "max",
2000
+ "type": "number",
2001
+ "required": false,
2002
+ "default": "100",
2003
+ "description": ""
2004
+ },
2005
+ {
2006
+ "name": "ref",
2007
+ "type": "Ref<HTMLDivElement>",
2008
+ "required": false,
2009
+ "default": null,
2010
+ "description": ""
2011
+ },
2012
+ {
2013
+ "name": "size",
2014
+ "type": "enum",
2015
+ "required": false,
2016
+ "default": "md",
2017
+ "description": ""
2018
+ },
2019
+ {
2020
+ "name": "tone",
2021
+ "type": "enum",
2022
+ "required": false,
2023
+ "default": "primary",
2024
+ "description": ""
2025
+ },
2026
+ {
2027
+ "name": "value",
2028
+ "type": "number",
2029
+ "required": false,
2030
+ "default": null,
2031
+ "description": "Current value; omit for indeterminate."
2032
+ },
2033
+ {
2034
+ "name": "valueText",
2035
+ "type": "string",
2036
+ "required": false,
2037
+ "default": null,
2038
+ "description": "Human-readable value (\"3 of 10 files\"); defaults to a percentage."
2039
+ }
2040
+ ],
2041
+ "parts": []
2042
+ },
2043
+ {
2044
+ "name": "RadioGroup",
2045
+ "description": "A set of native radios under one label. The group is labelled by\nreference (`aria-labelledby`) and described through Field, so description\nand error apply to the whole set. Keyboard is the browser's own: arrows\nmove and select within the group. Controlled or uncontrolled by `value`.",
2046
+ "status": "stable",
2047
+ "category": "Forms",
2048
+ "accessibility": "A `radiogroup` labelled by reference through Field and described by its description and error. Native radios: arrows move and select within the group, Tab leaves it.",
2049
+ "do": [
2050
+ "Use it for two to five exclusive options that should all be visible."
2051
+ ],
2052
+ "dont": [
2053
+ "Preselect a consequential choice; leave the group empty and mark it required."
2054
+ ],
2055
+ "import": "import { RadioGroup } from '@pearpages/pulp-react/radio';",
2056
+ "css": "@pearpages/pulp-react/radio.css",
2057
+ "tokens": "--radio-*",
2058
+ "props": [
2059
+ {
2060
+ "name": "label",
2061
+ "type": "ReactNode",
2062
+ "required": true,
2063
+ "default": null,
2064
+ "description": "Visible group label."
2065
+ },
2066
+ {
2067
+ "name": "defaultValue",
2068
+ "type": "string",
2069
+ "required": false,
2070
+ "default": null,
2071
+ "description": "Initially selected value when uncontrolled."
2072
+ },
2073
+ {
2074
+ "name": "description",
2075
+ "type": "ReactNode",
2076
+ "required": false,
2077
+ "default": null,
2078
+ "description": ""
2079
+ },
2080
+ {
2081
+ "name": "disabled",
2082
+ "type": "boolean",
2083
+ "required": false,
2084
+ "default": "false",
2085
+ "description": ""
2086
+ },
2087
+ {
2088
+ "name": "error",
2089
+ "type": "ReactNode",
2090
+ "required": false,
2091
+ "default": null,
2092
+ "description": ""
2093
+ },
2094
+ {
2095
+ "name": "name",
2096
+ "type": "string",
2097
+ "required": false,
2098
+ "default": null,
2099
+ "description": "Form field name shared by the radios. Generated when omitted."
2100
+ },
2101
+ {
2102
+ "name": "onValueChange",
2103
+ "type": "((value: string) => void)",
2104
+ "required": false,
2105
+ "default": null,
2106
+ "description": ""
2107
+ },
2108
+ {
2109
+ "name": "orientation",
2110
+ "type": "enum",
2111
+ "required": false,
2112
+ "default": "vertical",
2113
+ "description": ""
2114
+ },
2115
+ {
2116
+ "name": "ref",
2117
+ "type": "Ref<HTMLDivElement>",
2118
+ "required": false,
2119
+ "default": null,
2120
+ "description": ""
2121
+ },
2122
+ {
2123
+ "name": "required",
2124
+ "type": "boolean",
2125
+ "required": false,
2126
+ "default": "false",
2127
+ "description": ""
2128
+ },
2129
+ {
2130
+ "name": "size",
2131
+ "type": "enum",
2132
+ "required": false,
2133
+ "default": "md",
2134
+ "description": ""
2135
+ },
2136
+ {
2137
+ "name": "value",
2138
+ "type": "string",
2139
+ "required": false,
2140
+ "default": null,
2141
+ "description": "Controlled selected value."
2142
+ }
2143
+ ],
2144
+ "parts": []
2145
+ },
2146
+ {
2147
+ "name": "Radio",
2148
+ "description": "One option of a RadioGroup: a native radio with its own visible label.",
2149
+ "status": "stable",
2150
+ "category": "Forms",
2151
+ "accessibility": "A native `input type=\"radio\"` labelled by its visible text; the group semantics, description and error come from RadioGroup.",
2152
+ "do": [
2153
+ "Render it only inside RadioGroup."
2154
+ ],
2155
+ "dont": [
2156
+ "Disable a single radio without saying why in its label or the group description."
2157
+ ],
2158
+ "import": "import { Radio } from '@pearpages/pulp-react/radio';",
2159
+ "css": "@pearpages/pulp-react/radio.css",
2160
+ "tokens": "--radio-*",
2161
+ "props": [
2162
+ {
2163
+ "name": "label",
2164
+ "type": "ReactNode",
2165
+ "required": true,
2166
+ "default": null,
2167
+ "description": "Visible label beside the radio."
2168
+ },
2169
+ {
2170
+ "name": "value",
2171
+ "type": "string",
2172
+ "required": true,
2173
+ "default": null,
2174
+ "description": "The value this radio contributes to the group."
2175
+ },
2176
+ {
2177
+ "name": "className",
2178
+ "type": "string",
2179
+ "required": false,
2180
+ "default": null,
2181
+ "description": "Applied to the wrapping label, not the input."
2182
+ },
2183
+ {
2184
+ "name": "ref",
2185
+ "type": "Ref<HTMLInputElement>",
2186
+ "required": false,
2187
+ "default": null,
2188
+ "description": "The `<input>` element."
2189
+ }
2190
+ ],
2191
+ "parts": []
2192
+ },
2193
+ {
2194
+ "name": "Select",
2195
+ "description": "A native `<select>` on top of Field: the browser's own popup, keyboard and\nassistive-technology support, with the closed control drawn from\n`--select-*` tokens. For rich options or multi-select, a listbox component\ncomes later on a headless layer; this one stays native on purpose.",
2196
+ "status": "stable",
2197
+ "category": "Forms",
2198
+ "accessibility": "A native `select` on top of Field: the browser's own popup, keyboard and screen-reader behaviour; the placeholder is a disabled empty option when `required`.",
2199
+ "do": [
2200
+ "Use it for a plain list of words; it is the most robust choice on every platform."
2201
+ ],
2202
+ "dont": [
2203
+ "Use it for options that need a description or an icon; use Picker."
2204
+ ],
2205
+ "import": "import { Select } from '@pearpages/pulp-react/select';",
2206
+ "css": "@pearpages/pulp-react/select.css",
2207
+ "tokens": "--select-*",
2208
+ "props": [
2209
+ {
2210
+ "name": "children",
2211
+ "type": "ReactNode",
2212
+ "required": true,
2213
+ "default": null,
2214
+ "description": "`<option>` and `<optgroup>` elements."
2215
+ },
2216
+ {
2217
+ "name": "label",
2218
+ "type": "ReactNode",
2219
+ "required": true,
2220
+ "default": null,
2221
+ "description": "Visible label. Always rendered."
2222
+ },
2223
+ {
2224
+ "name": "className",
2225
+ "type": "string",
2226
+ "required": false,
2227
+ "default": null,
2228
+ "description": "Applied to the wrapper, not the select."
2229
+ },
2230
+ {
2231
+ "name": "description",
2232
+ "type": "ReactNode",
2233
+ "required": false,
2234
+ "default": null,
2235
+ "description": ""
2236
+ },
2237
+ {
2238
+ "name": "error",
2239
+ "type": "ReactNode",
2240
+ "required": false,
2241
+ "default": null,
2242
+ "description": "Presence marks the control invalid and announces the message."
2243
+ },
2244
+ {
2245
+ "name": "placeholder",
2246
+ "type": "string",
2247
+ "required": false,
2248
+ "default": null,
2249
+ "description": "An empty first option shown until a value is chosen."
2250
+ },
2251
+ {
2252
+ "name": "ref",
2253
+ "type": "Ref<HTMLSelectElement>",
2254
+ "required": false,
2255
+ "default": null,
2256
+ "description": "The `<select>` element."
2257
+ },
2258
+ {
2259
+ "name": "size",
2260
+ "type": "enum",
2261
+ "required": false,
2262
+ "default": "md",
2263
+ "description": ""
2264
+ }
2265
+ ],
2266
+ "parts": []
2267
+ },
2268
+ {
2269
+ "name": "Skeleton",
2270
+ "description": "A placeholder for content that is loading. Decorative: hidden from\nassistive technology, so mark the *container* `aria-busy` and announce\nthe loaded state there. Width for text and rect is the consumer's (pass\na `className`); the shimmer runs only when motion is allowed.",
2271
+ "status": "stable",
2272
+ "category": "Feedback",
2273
+ "accessibility": "`aria-hidden`: a placeholder has nothing to announce. Mark the container `aria-busy` while loading and clear it when content arrives; the shimmer stops under reduced motion.",
2274
+ "do": [
2275
+ "Match the shape of the content it stands in for.",
2276
+ "Set `aria-busy` on the region, not on the skeleton."
2277
+ ],
2278
+ "dont": [
2279
+ "Show it for content that arrives in under a few hundred milliseconds.",
2280
+ "Animate it when the user prefers reduced motion; the CSS already stops it."
2281
+ ],
2282
+ "import": "import { Skeleton } from '@pearpages/pulp-react/skeleton';",
2283
+ "css": "@pearpages/pulp-react/skeleton.css",
2284
+ "tokens": "--skeleton-*",
2285
+ "props": [
2286
+ {
2287
+ "name": "lines",
2288
+ "type": "number",
2289
+ "required": false,
2290
+ "default": "1",
2291
+ "description": "Number of text lines; the last is shorter."
2292
+ },
2293
+ {
2294
+ "name": "ref",
2295
+ "type": "Ref<HTMLSpanElement>",
2296
+ "required": false,
2297
+ "default": null,
2298
+ "description": ""
2299
+ },
2300
+ {
2301
+ "name": "shape",
2302
+ "type": "enum",
2303
+ "required": false,
2304
+ "default": "text",
2305
+ "description": ""
2306
+ },
2307
+ {
2308
+ "name": "size",
2309
+ "type": "enum",
2310
+ "required": false,
2311
+ "default": "md",
2312
+ "description": "Circle diameter, from the control scale."
2313
+ }
2314
+ ],
2315
+ "parts": []
2316
+ },
2317
+ {
2318
+ "name": "Slider",
2319
+ "description": "Picks a number, or a range, on a track: React Aria's slider (decision\nrecord 001) provides the hidden range inputs, arrow, Page Up/Down, Home and\nEnd keys, drag with a thumb that stays under the pointer, and\n`aria-valuetext` in the formatted form. The output element shows the\nsame text, so what a screen reader hears is what sighted users see.",
2320
+ "status": "experimental",
2321
+ "category": "Forms",
2322
+ "accessibility": "A `group` named by the label containing one hidden `input type=\"range\"` per thumb (named by `thumbLabels` for a range) with `aria-valuetext` in the formatted form; the `output` element shows the same text. Arrows step, Page Up/Down step by ten, Home/End jump; thumbs drag with mouse or touch.",
2323
+ "do": [
2324
+ "Set `formatOptions` so the spoken value matches the unit (\"40%\", \"€200\").",
2325
+ "Use `hideLabel` only when a visible heading already names it."
2326
+ ],
2327
+ "dont": [
2328
+ "Use it for precise values; provide a numeric field alongside.",
2329
+ "Use a `step` so small the keyboard cannot reach the ends in reasonable time."
2330
+ ],
2331
+ "import": "import { Slider } from '@pearpages/pulp-react/slider';",
2332
+ "css": "@pearpages/pulp-react/slider.css",
2333
+ "tokens": "--slider-*",
2334
+ "props": [
2335
+ {
2336
+ "name": "label",
2337
+ "type": "ReactNode",
2338
+ "required": true,
2339
+ "default": null,
2340
+ "description": "Visible label. Always rendered; `hideLabel` keeps it for assistive technology only."
2341
+ },
2342
+ {
2343
+ "name": "className",
2344
+ "type": "string",
2345
+ "required": false,
2346
+ "default": null,
2347
+ "description": ""
2348
+ },
2349
+ {
2350
+ "name": "defaultValue",
2351
+ "type": "SliderValue",
2352
+ "required": false,
2353
+ "default": null,
2354
+ "description": ""
2355
+ },
2356
+ {
2357
+ "name": "description",
2358
+ "type": "ReactNode",
2359
+ "required": false,
2360
+ "default": null,
2361
+ "description": ""
2362
+ },
2363
+ {
2364
+ "name": "disabled",
2365
+ "type": "boolean",
2366
+ "required": false,
2367
+ "default": "false",
2368
+ "description": ""
2369
+ },
2370
+ {
2371
+ "name": "formatOptions",
2372
+ "type": "NumberFormatOptions",
2373
+ "required": false,
2374
+ "default": null,
2375
+ "description": "How the value reads in the output and to assistive technology, for instance `{ style: 'percent' }` or `{ style: 'currency', currency: 'EUR' }`."
2376
+ },
2377
+ {
2378
+ "name": "hideLabel",
2379
+ "type": "boolean",
2380
+ "required": false,
2381
+ "default": "false",
2382
+ "description": ""
2383
+ },
2384
+ {
2385
+ "name": "max",
2386
+ "type": "number",
2387
+ "required": false,
2388
+ "default": "100",
2389
+ "description": ""
2390
+ },
2391
+ {
2392
+ "name": "min",
2393
+ "type": "number",
2394
+ "required": false,
2395
+ "default": "0",
2396
+ "description": ""
2397
+ },
2398
+ {
2399
+ "name": "name",
2400
+ "type": "string",
2401
+ "required": false,
2402
+ "default": null,
2403
+ "description": "Submitted with a form; a range submits two inputs with this name."
2404
+ },
2405
+ {
2406
+ "name": "onChange",
2407
+ "type": "((value: T) => void)",
2408
+ "required": false,
2409
+ "default": null,
2410
+ "description": "Called on every change while dragging or pressing arrows."
2411
+ },
2412
+ {
2413
+ "name": "onChangeEnd",
2414
+ "type": "((value: T) => void)",
2415
+ "required": false,
2416
+ "default": null,
2417
+ "description": "Called once when the drag ends or the key is released."
2418
+ },
2419
+ {
2420
+ "name": "orientation",
2421
+ "type": "enum",
2422
+ "required": false,
2423
+ "default": "horizontal",
2424
+ "description": ""
2425
+ },
2426
+ {
2427
+ "name": "ref",
2428
+ "type": "Ref<HTMLDivElement>",
2429
+ "required": false,
2430
+ "default": null,
2431
+ "description": "The group element."
2432
+ },
2433
+ {
2434
+ "name": "showOutput",
2435
+ "type": "boolean",
2436
+ "required": false,
2437
+ "default": "true",
2438
+ "description": "Show the formatted value next to the label."
2439
+ },
2440
+ {
2441
+ "name": "step",
2442
+ "type": "number",
2443
+ "required": false,
2444
+ "default": "1",
2445
+ "description": ""
2446
+ },
2447
+ {
2448
+ "name": "thumbLabels",
2449
+ "type": "readonly [string, string]",
2450
+ "required": false,
2451
+ "default": "['Minimum', 'Maximum']",
2452
+ "description": "Names for the two thumbs of a range."
2453
+ },
2454
+ {
2455
+ "name": "value",
2456
+ "type": "SliderValue",
2457
+ "required": false,
2458
+ "default": null,
2459
+ "description": "One number, or a `[start, end]` pair for a range with two thumbs."
2460
+ }
2461
+ ],
2462
+ "parts": []
2463
+ },
2464
+ {
2465
+ "name": "Spinner",
2466
+ "description": "An indeterminate progress indicator. Announces its label as a status\nunless `decorative`, in which case the parent is responsible (Button sets\n`aria-busy`). Under reduced motion the ring stops but keeps its coloured\nquarter, so it still reads as \"in progress\".",
2467
+ "status": "stable",
2468
+ "category": "Feedback",
2469
+ "accessibility": "`role=\"status\"` with a visually hidden label (\"Loading\" by default) unless `decorative`, in which case the parent announces busy. Under reduced motion the ring stops but keeps its coloured quarter.",
2470
+ "do": [
2471
+ "Use `decorative` inside a control that already sets `aria-busy`."
2472
+ ],
2473
+ "dont": [
2474
+ "Show several spinners for one operation."
2475
+ ],
2476
+ "import": "import { Spinner } from '@pearpages/pulp-react/spinner';",
2477
+ "css": "@pearpages/pulp-react/spinner.css",
2478
+ "tokens": "--spinner-*",
2479
+ "props": [
2480
+ {
2481
+ "name": "decorative",
2482
+ "type": "boolean",
2483
+ "required": false,
2484
+ "default": "false",
2485
+ "description": "Hide from assistive technology: the parent already announces busy."
2486
+ },
2487
+ {
2488
+ "name": "label",
2489
+ "type": "string",
2490
+ "required": false,
2491
+ "default": "Loading",
2492
+ "description": "Announced to assistive technology (`role=\"status\"`)."
2493
+ },
2494
+ {
2495
+ "name": "ref",
2496
+ "type": "Ref<HTMLSpanElement>",
2497
+ "required": false,
2498
+ "default": null,
2499
+ "description": ""
2500
+ },
2501
+ {
2502
+ "name": "size",
2503
+ "type": "enum",
2504
+ "required": false,
2505
+ "default": "md",
2506
+ "description": "`inherit` follows the surrounding font size, for spinners inside controls."
2507
+ },
2508
+ {
2509
+ "name": "tone",
2510
+ "type": "enum",
2511
+ "required": false,
2512
+ "default": "default",
2513
+ "description": "`inherit` draws with the surrounding text colour, for coloured controls."
2514
+ }
2515
+ ],
2516
+ "parts": []
2517
+ },
2518
+ {
2519
+ "name": "Stack",
2520
+ "description": "A flex column whose gap is a step on the spacing scale, so consumers\ncompose layout from tokens instead of writing padding and margins.\nRendered as `ul`/`ol` it keeps `role=\"list\"` explicitly, because Safari\nstops announcing a list once `list-style` is removed.",
2521
+ "status": "stable",
2522
+ "category": "Layout",
2523
+ "accessibility": "Layout only: no role unless rendered as `ul`/`ol`, where `role=\"list\"` is kept explicitly because Safari drops list semantics without markers.",
2524
+ "do": [
2525
+ "Use `as=\"ul\"` for a list of like items so the count is announced."
2526
+ ],
2527
+ "dont": [
2528
+ "Use it to space unrelated regions; it is one flex column."
2529
+ ],
2530
+ "import": "import { Stack } from '@pearpages/pulp-react/stack';",
2531
+ "css": "@pearpages/pulp-react/stack.css",
2532
+ "tokens": "--stack-*",
2533
+ "props": [
2534
+ {
2535
+ "name": "align",
2536
+ "type": "enum",
2537
+ "required": false,
2538
+ "default": null,
2539
+ "description": ""
2540
+ },
2541
+ {
2542
+ "name": "as",
2543
+ "type": "enum",
2544
+ "required": false,
2545
+ "default": "div",
2546
+ "description": ""
2547
+ },
2548
+ {
2549
+ "name": "gap",
2550
+ "type": "enum",
2551
+ "required": false,
2552
+ "default": "3",
2553
+ "description": "Step on the spacing scale (`--space-1` … `--space-8`)."
2554
+ },
2555
+ {
2556
+ "name": "justify",
2557
+ "type": "enum",
2558
+ "required": false,
2559
+ "default": null,
2560
+ "description": ""
2561
+ },
2562
+ {
2563
+ "name": "ref",
2564
+ "type": "Ref<HTMLElement>",
2565
+ "required": false,
2566
+ "default": null,
2567
+ "description": ""
2568
+ }
2569
+ ],
2570
+ "parts": []
2571
+ },
2572
+ {
2573
+ "name": "Switch",
2574
+ "description": "An on/off control: a native checkbox with `role=\"switch\"`, so assistive\ntechnology announces on and off, and the browser handles keyboard, forms\nand state. Use it for settings that take effect immediately; use Checkbox\nfor choices submitted with a form. Drawn with `--switch-*` tokens.",
2575
+ "status": "stable",
2576
+ "category": "Forms",
2577
+ "accessibility": "A native checkbox with `role=\"switch\"`, so on and off are announced; Space toggles; label, description and error wire through Field.",
2578
+ "do": [
2579
+ "Use it for settings that apply immediately."
2580
+ ],
2581
+ "dont": [
2582
+ "Use it inside a form that needs a submit; use Checkbox."
2583
+ ],
2584
+ "import": "import { Switch } from '@pearpages/pulp-react/switch';",
2585
+ "css": "@pearpages/pulp-react/switch.css",
2586
+ "tokens": "--switch-*",
2587
+ "props": [
2588
+ {
2589
+ "name": "label",
2590
+ "type": "ReactNode",
2591
+ "required": true,
2592
+ "default": null,
2593
+ "description": "Visible label beside the switch."
2594
+ },
2595
+ {
2596
+ "name": "className",
2597
+ "type": "string",
2598
+ "required": false,
2599
+ "default": null,
2600
+ "description": "Applied to the wrapper, not the input."
2601
+ },
2602
+ {
2603
+ "name": "description",
2604
+ "type": "ReactNode",
2605
+ "required": false,
2606
+ "default": null,
2607
+ "description": ""
2608
+ },
2609
+ {
2610
+ "name": "error",
2611
+ "type": "ReactNode",
2612
+ "required": false,
2613
+ "default": null,
2614
+ "description": ""
2615
+ },
2616
+ {
2617
+ "name": "ref",
2618
+ "type": "Ref<HTMLInputElement>",
2619
+ "required": false,
2620
+ "default": null,
2621
+ "description": "The `<input>` element."
2622
+ },
2623
+ {
2624
+ "name": "size",
2625
+ "type": "enum",
2626
+ "required": false,
2627
+ "default": "md",
2628
+ "description": ""
2629
+ }
2630
+ ],
2631
+ "parts": []
2632
+ },
2633
+ {
2634
+ "name": "Table",
2635
+ "description": "A data table on React Aria's grid (decision record 001): one Tab stop,\narrows move between rows and cells, Space toggles selection, Enter runs\nthe row action (see `onRowAction` for the selection rule), sortable\nheaders carry `aria-sort` and are pressed to change direction. Selection and sort are the caller's state; the table\nreports changes and renders them. Compose with `Table.Header`,\n`Table.Column`, `Table.Body`, `Table.Row` and `Table.Cell`; the selection\ncolumn appears by itself when rows are selectable.",
2636
+ "status": "experimental",
2637
+ "category": "Data",
2638
+ "accessibility": "`role=\"grid\"` named by `aria-label` or `aria-labelledby`; one column is the row header (`isRowHeader`), sortable columns carry `aria-sort`, selectable rows `aria-selected`, and the selection column holds real checkboxes (\"Select All\" in the header). One tab stop: arrows move between rows and cells, Space toggles selection, Enter runs the row action, the header cells are pressed to sort.",
2639
+ "do": [
2640
+ "Mark exactly one column `isRowHeader`.",
2641
+ "Give the table a name that says what the rows are."
2642
+ ],
2643
+ "dont": [
2644
+ "Sort the data inside the table; sort your data from `onSortChange` and pass it back.",
2645
+ "Use it for layout."
2646
+ ],
2647
+ "import": "import { Table } from '@pearpages/pulp-react/table';",
2648
+ "css": "@pearpages/pulp-react/table.css",
2649
+ "tokens": "--table-*",
2650
+ "props": [
2651
+ {
2652
+ "name": "children",
2653
+ "type": "ReactNode",
2654
+ "required": true,
2655
+ "default": null,
2656
+ "description": "`Table.Header` then `Table.Body`."
2657
+ },
2658
+ {
2659
+ "name": "aria-label",
2660
+ "type": "string",
2661
+ "required": false,
2662
+ "default": null,
2663
+ "description": "The table's accessible name. Pass `aria-labelledby` instead when a visible heading names it."
2664
+ },
2665
+ {
2666
+ "name": "aria-labelledby",
2667
+ "type": "string",
2668
+ "required": false,
2669
+ "default": null,
2670
+ "description": ""
2671
+ },
2672
+ {
2673
+ "name": "className",
2674
+ "type": "string",
2675
+ "required": false,
2676
+ "default": null,
2677
+ "description": "Applied to the scroll container around the table."
2678
+ },
2679
+ {
2680
+ "name": "defaultSelected",
2681
+ "type": "readonly string[]",
2682
+ "required": false,
2683
+ "default": "[]",
2684
+ "description": ""
2685
+ },
2686
+ {
2687
+ "name": "defaultSort",
2688
+ "type": "TableSort",
2689
+ "required": false,
2690
+ "default": null,
2691
+ "description": ""
2692
+ },
2693
+ {
2694
+ "name": "density",
2695
+ "type": "enum",
2696
+ "required": false,
2697
+ "default": "default",
2698
+ "description": "Row padding steps down one token. The brand's `space.unit` sets the base."
2699
+ },
2700
+ {
2701
+ "name": "disabledIds",
2702
+ "type": "readonly string[]",
2703
+ "required": false,
2704
+ "default": null,
2705
+ "description": "Rows that cannot be selected or activated."
2706
+ },
2707
+ {
2708
+ "name": "onRowAction",
2709
+ "type": "((id: string) => void)",
2710
+ "required": false,
2711
+ "default": null,
2712
+ "description": "Called with the row id on Enter, on click, and on double click. Once\nrows are selectable and a selection exists, Enter and click toggle the\nselection instead (the vendor's rule, so touch users select without a\nmodifier key); double click still runs the action."
2713
+ },
2714
+ {
2715
+ "name": "onSelectedChange",
2716
+ "type": "((ids: string[]) => void)",
2717
+ "required": false,
2718
+ "default": null,
2719
+ "description": ""
2720
+ },
2721
+ {
2722
+ "name": "onSortChange",
2723
+ "type": "((sort: TableSort) => void)",
2724
+ "required": false,
2725
+ "default": null,
2726
+ "description": ""
2727
+ },
2728
+ {
2729
+ "name": "ref",
2730
+ "type": "Ref<HTMLTableElement>",
2731
+ "required": false,
2732
+ "default": null,
2733
+ "description": "The `<table>` element."
2734
+ },
2735
+ {
2736
+ "name": "selected",
2737
+ "type": "readonly string[]",
2738
+ "required": false,
2739
+ "default": null,
2740
+ "description": "Selected row ids (controlled)."
2741
+ },
2742
+ {
2743
+ "name": "selectionMode",
2744
+ "type": "enum",
2745
+ "required": false,
2746
+ "default": "none",
2747
+ "description": ""
2748
+ },
2749
+ {
2750
+ "name": "sort",
2751
+ "type": "TableSort | null",
2752
+ "required": false,
2753
+ "default": null,
2754
+ "description": "Current sort (controlled). Sorting the data is the caller's job: this is the header state."
2755
+ },
2756
+ {
2757
+ "name": "stickyHeader",
2758
+ "type": "boolean",
2759
+ "required": false,
2760
+ "default": "false",
2761
+ "description": "The header stays visible while the container scrolls. Give the container a height through `className`."
2762
+ }
2763
+ ],
2764
+ "parts": [
2765
+ {
2766
+ "name": "Table.Header",
2767
+ "description": "",
2768
+ "props": [
2769
+ {
2770
+ "name": "children",
2771
+ "type": "ReactNode",
2772
+ "required": true,
2773
+ "default": null,
2774
+ "description": "`Table.Column` elements."
2775
+ },
2776
+ {
2777
+ "name": "className",
2778
+ "type": "string",
2779
+ "required": false,
2780
+ "default": null,
2781
+ "description": ""
2782
+ }
2783
+ ]
2784
+ },
2785
+ {
2786
+ "name": "Table.Column",
2787
+ "description": "",
2788
+ "props": [
2789
+ {
2790
+ "name": "align",
2791
+ "type": "enum",
2792
+ "required": false,
2793
+ "default": "start",
2794
+ "description": ""
2795
+ },
2796
+ {
2797
+ "name": "allowsSorting",
2798
+ "type": "boolean",
2799
+ "required": false,
2800
+ "default": "false",
2801
+ "description": "Pressing the header sorts by it; the table reports the change through `onSortChange`."
2802
+ },
2803
+ {
2804
+ "name": "className",
2805
+ "type": "string",
2806
+ "required": false,
2807
+ "default": null,
2808
+ "description": ""
2809
+ },
2810
+ {
2811
+ "name": "id",
2812
+ "type": "string",
2813
+ "required": false,
2814
+ "default": null,
2815
+ "description": "The column id `sort.column` refers to. Defaults to the column's text."
2816
+ },
2817
+ {
2818
+ "name": "isRowHeader",
2819
+ "type": "boolean",
2820
+ "required": false,
2821
+ "default": "false",
2822
+ "description": "This column names the row for assistive technology. Exactly one column per table."
2823
+ }
2824
+ ]
2825
+ },
2826
+ {
2827
+ "name": "Table.Body",
2828
+ "description": "",
2829
+ "props": [
2830
+ {
2831
+ "name": "children",
2832
+ "type": "ReactNode | ((item: T) => ReactElement<unknown, string | JSXElementConstructor<any>>)",
2833
+ "required": true,
2834
+ "default": null,
2835
+ "description": "`Table.Row` elements, or a function from an item to one when `items` is given."
2836
+ },
2837
+ {
2838
+ "name": "className",
2839
+ "type": "string",
2840
+ "required": false,
2841
+ "default": null,
2842
+ "description": ""
2843
+ },
2844
+ {
2845
+ "name": "emptyMessage",
2846
+ "type": "ReactNode",
2847
+ "required": false,
2848
+ "default": "No rows",
2849
+ "description": "Shown when there are no rows."
2850
+ },
2851
+ {
2852
+ "name": "items",
2853
+ "type": "Iterable<T>",
2854
+ "required": false,
2855
+ "default": null,
2856
+ "description": "Rows from data: each item renders through the `children` function, keyed by `item.id`."
2857
+ }
2858
+ ]
2859
+ },
2860
+ {
2861
+ "name": "Table.Row",
2862
+ "description": "",
2863
+ "props": [
2864
+ {
2865
+ "name": "children",
2866
+ "type": "ReactNode",
2867
+ "required": true,
2868
+ "default": null,
2869
+ "description": "`Table.Cell` elements."
2870
+ },
2871
+ {
2872
+ "name": "className",
2873
+ "type": "string",
2874
+ "required": false,
2875
+ "default": null,
2876
+ "description": ""
2877
+ },
2878
+ {
2879
+ "name": "id",
2880
+ "type": "string",
2881
+ "required": false,
2882
+ "default": null,
2883
+ "description": "The row id used for selection, sorting callbacks and `onRowAction`. Required unless the row comes from `items`."
2884
+ }
2885
+ ]
2886
+ },
2887
+ {
2888
+ "name": "Table.Cell",
2889
+ "description": "",
2890
+ "props": [
2891
+ {
2892
+ "name": "align",
2893
+ "type": "enum",
2894
+ "required": false,
2895
+ "default": "start",
2896
+ "description": ""
2897
+ },
2898
+ {
2899
+ "name": "className",
2900
+ "type": "string",
2901
+ "required": false,
2902
+ "default": null,
2903
+ "description": ""
2904
+ }
2905
+ ]
2906
+ }
2907
+ ]
2908
+ },
2909
+ {
2910
+ "name": "Tabs",
2911
+ "description": "Tabbed sections following the WAI-ARIA Tabs pattern. Compose with\n`Tabs.List`, `Tabs.Tab` and `Tabs.Panel`; ids and ARIA relationships are\nwired automatically. One tab stop: arrows move between tabs, Home and End\njump to the ends, disabled tabs are skipped. State on the DOM:\n`data-orientation`, `data-state=\"active|inactive\"`.",
2912
+ "status": "stable",
2913
+ "category": "Navigation",
2914
+ "accessibility": "The WAI-ARIA Tabs pattern: `tablist` with `aria-orientation`, `tab`s carrying `aria-selected` and `aria-controls`, `tabpanel`s labelled by their tab. One tab stop: arrows move (and select with automatic activation), Home/End jump, disabled tabs are skipped.",
2915
+ "do": [
2916
+ "Use `activation=\"manual\"` when switching a tab is expensive.",
2917
+ "Name the `Tabs.List` with `aria-label`."
2918
+ ],
2919
+ "dont": [
2920
+ "Use tabs for sequential steps; use a stepper pattern.",
2921
+ "Put a link inside a tab."
2922
+ ],
2923
+ "import": "import { Tabs } from '@pearpages/pulp-react/tabs';",
2924
+ "css": "@pearpages/pulp-react/tabs.css",
2925
+ "tokens": "--tabs-*",
2926
+ "props": [
2927
+ {
2928
+ "name": "activation",
2929
+ "type": "enum",
2930
+ "required": false,
2931
+ "default": "automatic",
2932
+ "description": "`automatic` selects a tab when it receives focus (arrow keys); `manual`\nmoves focus only and selects on Enter, Space or click."
2933
+ },
2934
+ {
2935
+ "name": "defaultValue",
2936
+ "type": "string",
2937
+ "required": false,
2938
+ "default": null,
2939
+ "description": "Initially selected tab when uncontrolled."
2940
+ },
2941
+ {
2942
+ "name": "onValueChange",
2943
+ "type": "((value: string) => void)",
2944
+ "required": false,
2945
+ "default": null,
2946
+ "description": ""
2947
+ },
2948
+ {
2949
+ "name": "orientation",
2950
+ "type": "enum",
2951
+ "required": false,
2952
+ "default": "horizontal",
2953
+ "description": "Layout and arrow-key axis."
2954
+ },
2955
+ {
2956
+ "name": "ref",
2957
+ "type": "Ref<HTMLDivElement>",
2958
+ "required": false,
2959
+ "default": null,
2960
+ "description": ""
2961
+ },
2962
+ {
2963
+ "name": "value",
2964
+ "type": "string",
2965
+ "required": false,
2966
+ "default": null,
2967
+ "description": "Controlled selected tab."
2968
+ }
2969
+ ],
2970
+ "parts": [
2971
+ {
2972
+ "name": "Tabs.List",
2973
+ "description": "",
2974
+ "props": [
2975
+ {
2976
+ "name": "ref",
2977
+ "type": "Ref<HTMLDivElement>",
2978
+ "required": false,
2979
+ "default": null,
2980
+ "description": ""
2981
+ }
2982
+ ]
2983
+ },
2984
+ {
2985
+ "name": "Tabs.Tab",
2986
+ "description": "",
2987
+ "props": [
2988
+ {
2989
+ "name": "value",
2990
+ "type": "string",
2991
+ "required": true,
2992
+ "default": null,
2993
+ "description": "Identifies the tab; the panel with the same value belongs to it."
2994
+ },
2995
+ {
2996
+ "name": "ref",
2997
+ "type": "Ref<HTMLButtonElement>",
2998
+ "required": false,
2999
+ "default": null,
3000
+ "description": ""
3001
+ }
3002
+ ]
3003
+ },
3004
+ {
3005
+ "name": "Tabs.Panel",
3006
+ "description": "",
3007
+ "props": [
3008
+ {
3009
+ "name": "value",
3010
+ "type": "string",
3011
+ "required": true,
3012
+ "default": null,
3013
+ "description": ""
3014
+ },
3015
+ {
3016
+ "name": "ref",
3017
+ "type": "Ref<HTMLDivElement>",
3018
+ "required": false,
3019
+ "default": null,
3020
+ "description": ""
3021
+ }
3022
+ ]
3023
+ }
3024
+ ]
3025
+ },
3026
+ {
3027
+ "name": "Text",
3028
+ "description": "The type scale as a component. Every combination of size, weight, tone and\nfamily resolves through `--text-*` tokens, so body copy never carries its\nown font declarations. State on the DOM: `data-size`, `data-weight`,\n`data-tone`, `data-family`, `data-align`, `data-truncate`.",
3029
+ "status": "stable",
3030
+ "category": "Typography",
3031
+ "accessibility": "Plain text with no role beyond the element chosen by `as`; `truncate` clips visually while the full text stays in the accessibility tree.",
3032
+ "do": [
3033
+ "Use `tone=\"faint\"` only on base and raised surfaces (its contrast is promised there)."
3034
+ ],
3035
+ "dont": [
3036
+ "Use `as=\"label\"`; labels belong to Field."
3037
+ ],
3038
+ "import": "import { Text } from '@pearpages/pulp-react/text';",
3039
+ "css": "@pearpages/pulp-react/text.css",
3040
+ "tokens": "--text-*",
3041
+ "props": [
3042
+ {
3043
+ "name": "align",
3044
+ "type": "enum",
3045
+ "required": false,
3046
+ "default": null,
3047
+ "description": ""
3048
+ },
3049
+ {
3050
+ "name": "as",
3051
+ "type": "enum",
3052
+ "required": false,
3053
+ "default": "p",
3054
+ "description": "The element to render. For a label use `Field.Label`."
3055
+ },
3056
+ {
3057
+ "name": "family",
3058
+ "type": "enum",
3059
+ "required": false,
3060
+ "default": "body",
3061
+ "description": ""
3062
+ },
3063
+ {
3064
+ "name": "ref",
3065
+ "type": "Ref<HTMLElement>",
3066
+ "required": false,
3067
+ "default": null,
3068
+ "description": ""
3069
+ },
3070
+ {
3071
+ "name": "size",
3072
+ "type": "enum",
3073
+ "required": false,
3074
+ "default": "md",
3075
+ "description": ""
3076
+ },
3077
+ {
3078
+ "name": "tone",
3079
+ "type": "enum",
3080
+ "required": false,
3081
+ "default": "default",
3082
+ "description": "Emphasis: `muted` for secondary text, `faint` for the least important."
3083
+ },
3084
+ {
3085
+ "name": "truncate",
3086
+ "type": "boolean",
3087
+ "required": false,
3088
+ "default": "false",
3089
+ "description": "Single line with an ellipsis."
3090
+ },
3091
+ {
3092
+ "name": "weight",
3093
+ "type": "enum",
3094
+ "required": false,
3095
+ "default": "regular",
3096
+ "description": ""
3097
+ }
3098
+ ],
3099
+ "parts": []
3100
+ },
3101
+ {
3102
+ "name": "TextField",
3103
+ "description": "A single-line text input on top of `Field`: label, description and error\nwired for assistive technology. Controlled and uncontrolled behave exactly\nlike the native input (`value`/`onChange` or `defaultValue`). Every value\ncomes from `--text-field-*` and `--field-*` tokens; state is exposed as\n`data-size`, `data-invalid`, `data-disabled` and `data-readonly` on the\nwrapper.",
3104
+ "status": "stable",
3105
+ "category": "Forms",
3106
+ "accessibility": "A native text `input` wired through Field: `label[for]`, `aria-describedby` for description and error, `aria-invalid` and `aria-required`. Everything the browser gives a native input (autofill, IME, forms) applies.",
3107
+ "do": [
3108
+ "Always pass `label`; use a visible one.",
3109
+ "Prefer `error` text that says how to fix the value."
3110
+ ],
3111
+ "dont": [
3112
+ "Use `placeholder` as the label.",
3113
+ "Use it for multi-line text; use Textarea."
3114
+ ],
3115
+ "import": "import { TextField } from '@pearpages/pulp-react/text-field';",
3116
+ "css": "@pearpages/pulp-react/text-field.css",
3117
+ "tokens": "--text-field-*",
3118
+ "props": [
3119
+ {
3120
+ "name": "label",
3121
+ "type": "ReactNode",
3122
+ "required": true,
3123
+ "default": null,
3124
+ "description": "Visible label. Always rendered: a placeholder is not a label."
3125
+ },
3126
+ {
3127
+ "name": "className",
3128
+ "type": "string",
3129
+ "required": false,
3130
+ "default": null,
3131
+ "description": "Applied to the wrapper, not the input."
3132
+ },
3133
+ {
3134
+ "name": "description",
3135
+ "type": "ReactNode",
3136
+ "required": false,
3137
+ "default": null,
3138
+ "description": "Help text under the field, exposed as the input's accessible description."
3139
+ },
3140
+ {
3141
+ "name": "error",
3142
+ "type": "ReactNode",
3143
+ "required": false,
3144
+ "default": null,
3145
+ "description": "Error message. Its presence marks the input invalid (`aria-invalid`,\n`data-invalid`) and the message is announced as an alert."
3146
+ },
3147
+ {
3148
+ "name": "ref",
3149
+ "type": "Ref<HTMLInputElement>",
3150
+ "required": false,
3151
+ "default": null,
3152
+ "description": "The `<input>` element."
3153
+ },
3154
+ {
3155
+ "name": "size",
3156
+ "type": "enum",
3157
+ "required": false,
3158
+ "default": "md",
3159
+ "description": ""
3160
+ }
3161
+ ],
3162
+ "parts": []
3163
+ },
3164
+ {
3165
+ "name": "Textarea",
3166
+ "description": "A multi-line text input on top of Field. Same contract as TextField;\nits own `--textarea-*` tokens so it can diverge. `rows` sets the initial\nheight; `autoGrow` follows the content in browsers that support\n`field-sizing`, and falls back to `rows` elsewhere.",
3167
+ "status": "stable",
3168
+ "category": "Forms",
3169
+ "accessibility": "A native `textarea` wired through Field; `autoGrow` uses `field-sizing: content` where supported and falls back to `rows`.",
3170
+ "do": [
3171
+ "Set `rows` to the typical length of the answer."
3172
+ ],
3173
+ "dont": [
3174
+ "Disable `resize` without giving the field enough rows."
3175
+ ],
3176
+ "import": "import { Textarea } from '@pearpages/pulp-react/textarea';",
3177
+ "css": "@pearpages/pulp-react/textarea.css",
3178
+ "tokens": "--textarea-*",
3179
+ "props": [
3180
+ {
3181
+ "name": "label",
3182
+ "type": "ReactNode",
3183
+ "required": true,
3184
+ "default": null,
3185
+ "description": "Visible label. Always rendered."
3186
+ },
3187
+ {
3188
+ "name": "autoGrow",
3189
+ "type": "boolean",
3190
+ "required": false,
3191
+ "default": "false",
3192
+ "description": "Grow with the content (`field-sizing: content`, where supported)."
3193
+ },
3194
+ {
3195
+ "name": "className",
3196
+ "type": "string",
3197
+ "required": false,
3198
+ "default": null,
3199
+ "description": "Applied to the wrapper, not the textarea."
3200
+ },
3201
+ {
3202
+ "name": "description",
3203
+ "type": "ReactNode",
3204
+ "required": false,
3205
+ "default": null,
3206
+ "description": ""
3207
+ },
3208
+ {
3209
+ "name": "error",
3210
+ "type": "ReactNode",
3211
+ "required": false,
3212
+ "default": null,
3213
+ "description": "Presence marks the control invalid and announces the message."
3214
+ },
3215
+ {
3216
+ "name": "ref",
3217
+ "type": "Ref<HTMLTextAreaElement>",
3218
+ "required": false,
3219
+ "default": null,
3220
+ "description": "The `<textarea>` element."
3221
+ },
3222
+ {
3223
+ "name": "resize",
3224
+ "type": "enum",
3225
+ "required": false,
3226
+ "default": "vertical",
3227
+ "description": ""
3228
+ },
3229
+ {
3230
+ "name": "size",
3231
+ "type": "enum",
3232
+ "required": false,
3233
+ "default": "md",
3234
+ "description": ""
3235
+ }
3236
+ ],
3237
+ "parts": []
3238
+ },
3239
+ {
3240
+ "name": "ToastProvider",
3241
+ "description": "Mount once near the app root. Owns a portal element with a polite live\nregion; `useToast()` adds notifications to it. Timers pause while the\nregion is hovered or holds focus, Escape dismisses the focused toast, and\nerror toasts stay until dismissed. Each toast is an Alert.",
3242
+ "status": "stable",
3243
+ "category": "Feedback",
3244
+ "accessibility": "Owns a `region` named \"Notifications\" with `aria-live=\"polite\"`; each toast is an Alert with its live role off (the region announces). Timers pause while the region is hovered or holds focus; Escape dismisses the focused toast; error toasts stay until dismissed.",
3245
+ "do": [
3246
+ "Mount it once near the app root.",
3247
+ "Keep messages to one sentence; put detail behind an `action`."
3248
+ ],
3249
+ "dont": [
3250
+ "Use a toast for an error the user must fix in a form; show it at the field.",
3251
+ "Stack more than a few; the cap drops the oldest."
3252
+ ],
3253
+ "import": "import { ToastProvider } from '@pearpages/pulp-react/toast';",
3254
+ "css": "@pearpages/pulp-react/toast.css",
3255
+ "tokens": "--toast-*",
3256
+ "props": [
3257
+ {
3258
+ "name": "duration",
3259
+ "type": "number",
3260
+ "required": false,
3261
+ "default": "6000",
3262
+ "description": "Default auto-dismiss time in milliseconds."
3263
+ },
3264
+ {
3265
+ "name": "label",
3266
+ "type": "string",
3267
+ "required": false,
3268
+ "default": "Notifications",
3269
+ "description": "Accessible name of the region."
3270
+ },
3271
+ {
3272
+ "name": "max",
3273
+ "type": "number",
3274
+ "required": false,
3275
+ "default": "5",
3276
+ "description": "Most toasts shown at once; the oldest is dismissed first."
3277
+ },
3278
+ {
3279
+ "name": "placement",
3280
+ "type": "enum",
3281
+ "required": false,
3282
+ "default": "bottom-end",
3283
+ "description": ""
3284
+ }
3285
+ ],
3286
+ "parts": []
3287
+ },
3288
+ {
3289
+ "name": "Tooltip",
3290
+ "description": "A short description shown on hover or focus and linked with\n`aria-describedby` while visible. Never the only name of a control: use it\nfor extra detail, and give icon-only controls a real label. Escape hides it.",
3291
+ "status": "stable",
3292
+ "category": "Overlays",
3293
+ "accessibility": "Shown on hover after a delay and on focus immediately; the trigger gets `aria-describedby` pointing at the `tooltip` while it is visible; Escape hides it. It is a description, never a name.",
3294
+ "do": [
3295
+ "Use it for extra detail on controls that already have a name."
3296
+ ],
3297
+ "dont": [
3298
+ "Put interactive content in it.",
3299
+ "Use it to name an icon-only control; use IconButton's `label`."
3300
+ ],
3301
+ "import": "import { Tooltip } from '@pearpages/pulp-react/tooltip';",
3302
+ "css": "@pearpages/pulp-react/tooltip.css",
3303
+ "tokens": "--tooltip-*",
3304
+ "props": [
3305
+ {
3306
+ "name": "children",
3307
+ "type": "ReactElement<unknown, string | JSXElementConstructor<any>>",
3308
+ "required": true,
3309
+ "default": null,
3310
+ "description": "The single element that owns the tooltip; it receives the hover, focus and `aria-describedby` wiring."
3311
+ },
3312
+ {
3313
+ "name": "content",
3314
+ "type": "ReactNode",
3315
+ "required": true,
3316
+ "default": null,
3317
+ "description": "The tooltip text. Supplementary only: it must not be the control's only name."
3318
+ },
3319
+ {
3320
+ "name": "delay",
3321
+ "type": "number",
3322
+ "required": false,
3323
+ "default": "300",
3324
+ "description": "Hover delay in milliseconds. Focus shows immediately."
3325
+ },
3326
+ {
3327
+ "name": "placement",
3328
+ "type": "enum",
3329
+ "required": false,
3330
+ "default": "top",
3331
+ "description": "Preferred side; flips when there is no room."
3332
+ }
3333
+ ],
3334
+ "parts": []
3335
+ },
3336
+ {
3337
+ "name": "VisuallyHidden",
3338
+ "description": "Content for assistive technology only: read by screen readers, invisible\non screen, still in the accessibility tree (unlike `display: none`). Use\nit to give icon-only controls a name or to add context a sighted user\ngets from layout.",
3339
+ "status": "stable",
3340
+ "category": "Utilities",
3341
+ "accessibility": "In the accessibility tree, out of the layout (clip-path, not `display: none`).",
3342
+ "do": [
3343
+ "Use it for context a sighted user gets from layout (\"Sort by\", \"Step 2 of 4\")."
3344
+ ],
3345
+ "dont": [
3346
+ "Hide instructions that sighted users also need."
3347
+ ],
3348
+ "import": "import { VisuallyHidden } from '@pearpages/pulp-react/visually-hidden';",
3349
+ "css": "@pearpages/pulp-react/visually-hidden.css",
3350
+ "tokens": "--visually-hidden-*",
3351
+ "props": [
3352
+ {
3353
+ "name": "as",
3354
+ "type": "enum",
3355
+ "required": false,
3356
+ "default": "span",
3357
+ "description": ""
3358
+ },
3359
+ {
3360
+ "name": "ref",
3361
+ "type": "Ref<HTMLElement>",
3362
+ "required": false,
3363
+ "default": null,
3364
+ "description": ""
3365
+ }
3366
+ ],
3367
+ "parts": []
3368
+ }
3369
+ ]
3370
+ }