@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,50 @@
1
+ import { useCallback } from 'react';
2
+
3
+ // src/internal/useRovingFocus.ts
4
+ var isDisabled = (el) => el.hasAttribute("disabled") || el.getAttribute("aria-disabled") === "true";
5
+ function useRovingFocus({ orientation = "horizontal", selector, onFocusItem }) {
6
+ return useCallback(
7
+ (event) => {
8
+ const items = Array.from(event.currentTarget.querySelectorAll(selector)).filter(
9
+ (item2) => !isDisabled(item2)
10
+ );
11
+ if (items.length === 0) return;
12
+ const current = items.indexOf(document.activeElement);
13
+ const next = (delta) => current === -1 ? 0 : (current + delta + items.length) % items.length;
14
+ const horizontal = orientation !== "vertical";
15
+ const vertical = orientation !== "horizontal";
16
+ let target;
17
+ switch (event.key) {
18
+ case "ArrowRight":
19
+ if (horizontal) target = next(1);
20
+ break;
21
+ case "ArrowLeft":
22
+ if (horizontal) target = next(-1);
23
+ break;
24
+ case "ArrowDown":
25
+ if (vertical) target = next(1);
26
+ break;
27
+ case "ArrowUp":
28
+ if (vertical) target = next(-1);
29
+ break;
30
+ case "Home":
31
+ target = 0;
32
+ break;
33
+ case "End":
34
+ target = items.length - 1;
35
+ break;
36
+ }
37
+ if (target === void 0) return;
38
+ event.preventDefault();
39
+ const item = items[target];
40
+ if (!item) return;
41
+ item.focus();
42
+ onFocusItem?.(item);
43
+ },
44
+ [orientation, selector, onFocusItem]
45
+ );
46
+ }
47
+
48
+ export { useRovingFocus };
49
+ //# sourceMappingURL=chunk-I5OZ63W7.js.map
50
+ //# sourceMappingURL=chunk-I5OZ63W7.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/internal/useRovingFocus.ts"],"names":["item"],"mappings":";;;AAWA,IAAM,UAAA,GAAa,CAAC,EAAA,KAClB,EAAA,CAAG,YAAA,CAAa,UAAU,CAAA,IAAK,EAAA,CAAG,YAAA,CAAa,eAAe,CAAA,KAAM,MAAA;AAQ/D,SAAS,eAAe,EAAE,WAAA,GAAc,YAAA,EAAc,QAAA,EAAU,aAAY,EAAuB;AACxG,EAAA,OAAO,WAAA;AAAA,IACL,CAAC,KAAA,KAAsC;AACrC,MAAA,MAAM,KAAA,GAAQ,MAAM,IAAA,CAAK,KAAA,CAAM,cAAc,gBAAA,CAA8B,QAAQ,CAAC,CAAA,CAAE,MAAA;AAAA,QACpF,CAACA,KAAAA,KAAS,CAAC,UAAA,CAAWA,KAAI;AAAA,OAC5B;AACA,MAAA,IAAI,KAAA,CAAM,WAAW,CAAA,EAAG;AACxB,MAAA,MAAM,OAAA,GAAU,KAAA,CAAM,OAAA,CAAQ,QAAA,CAAS,aAA4B,CAAA;AAEnE,MAAA,MAAM,IAAA,GAAO,CAAC,KAAA,KAAmB,OAAA,KAAY,EAAA,GAAK,KAAK,OAAA,GAAU,KAAA,GAAQ,KAAA,CAAM,MAAA,IAAU,KAAA,CAAM,MAAA;AAC/F,MAAA,MAAM,aAAa,WAAA,KAAgB,UAAA;AACnC,MAAA,MAAM,WAAW,WAAA,KAAgB,YAAA;AAEjC,MAAA,IAAI,MAAA;AACJ,MAAA,QAAQ,MAAM,GAAA;AAAK,QACjB,KAAK,YAAA;AACH,UAAA,IAAI,UAAA,EAAY,MAAA,GAAS,IAAA,CAAK,CAAC,CAAA;AAC/B,UAAA;AAAA,QACF,KAAK,WAAA;AACH,UAAA,IAAI,UAAA,EAAY,MAAA,GAAS,IAAA,CAAK,EAAE,CAAA;AAChC,UAAA;AAAA,QACF,KAAK,WAAA;AACH,UAAA,IAAI,QAAA,EAAU,MAAA,GAAS,IAAA,CAAK,CAAC,CAAA;AAC7B,UAAA;AAAA,QACF,KAAK,SAAA;AACH,UAAA,IAAI,QAAA,EAAU,MAAA,GAAS,IAAA,CAAK,EAAE,CAAA;AAC9B,UAAA;AAAA,QACF,KAAK,MAAA;AACH,UAAA,MAAA,GAAS,CAAA;AACT,UAAA;AAAA,QACF,KAAK,KAAA;AACH,UAAA,MAAA,GAAS,MAAM,MAAA,GAAS,CAAA;AACxB,UAAA;AAAA;AAEJ,MAAA,IAAI,WAAW,MAAA,EAAW;AAE1B,MAAA,KAAA,CAAM,cAAA,EAAe;AACrB,MAAA,MAAM,IAAA,GAAO,MAAM,MAAM,CAAA;AACzB,MAAA,IAAI,CAAC,IAAA,EAAM;AACX,MAAA,IAAA,CAAK,KAAA,EAAM;AACX,MAAA,WAAA,GAAc,IAAI,CAAA;AAAA,IACpB,CAAA;AAAA,IACA,CAAC,WAAA,EAAa,QAAA,EAAU,WAAW;AAAA,GACrC;AACF","file":"chunk-I5OZ63W7.js","sourcesContent":["import { useCallback, type KeyboardEvent } from 'react';\n\nexport interface RovingFocusOptions {\n /** Which arrow keys move: horizontal uses Left/Right, vertical Up/Down, both uses all four. */\n orientation?: 'horizontal' | 'vertical' | 'both';\n /** Selector for the items inside the container. Disabled items are skipped. */\n selector: string;\n /** Called with the item that received focus. */\n onFocusItem?: (item: HTMLElement) => void;\n}\n\nconst isDisabled = (el: HTMLElement) =>\n el.hasAttribute('disabled') || el.getAttribute('aria-disabled') === 'true';\n\n/**\n * Keyboard navigation for a set of siblings that share one tab stop (tabs,\n * radio groups, menus): arrows move focus with wraparound, Home and End jump\n * to the ends, disabled items are skipped. Returns the keydown handler for the\n * container; the container decides which item carries `tabIndex={0}`.\n */\nexport function useRovingFocus({ orientation = 'horizontal', selector, onFocusItem }: RovingFocusOptions) {\n return useCallback(\n (event: KeyboardEvent<HTMLElement>) => {\n const items = Array.from(event.currentTarget.querySelectorAll<HTMLElement>(selector)).filter(\n (item) => !isDisabled(item),\n );\n if (items.length === 0) return;\n const current = items.indexOf(document.activeElement as HTMLElement);\n\n const next = (delta: number) => (current === -1 ? 0 : (current + delta + items.length) % items.length);\n const horizontal = orientation !== 'vertical';\n const vertical = orientation !== 'horizontal';\n\n let target: number | undefined;\n switch (event.key) {\n case 'ArrowRight':\n if (horizontal) target = next(1);\n break;\n case 'ArrowLeft':\n if (horizontal) target = next(-1);\n break;\n case 'ArrowDown':\n if (vertical) target = next(1);\n break;\n case 'ArrowUp':\n if (vertical) target = next(-1);\n break;\n case 'Home':\n target = 0;\n break;\n case 'End':\n target = items.length - 1;\n break;\n }\n if (target === undefined) return;\n\n event.preventDefault();\n const item = items[target];\n if (!item) return;\n item.focus();\n onFocusItem?.(item);\n },\n [orientation, selector, onFocusItem],\n );\n}\n"]}
@@ -0,0 +1,41 @@
1
+ import { useState, useEffect } from 'react';
2
+ import { ModalSystem, Modal, ModalTrigger, ModalContent, ModalHeader, ModalTitle, ModalDescription, ModalClose, ModalBody, ModalFooter } from '@pearpages/modals';
3
+ import { jsx } from 'react/jsx-runtime';
4
+
5
+ // src/dialog/Dialog.tsx
6
+
7
+ // src/dialog/Dialog.module.css
8
+ var Dialog_default = {
9
+ root: "Dialog_root"
10
+ };
11
+ function DialogSystem({ children, ...rest }) {
12
+ const [container] = useState(() => {
13
+ if (typeof document === "undefined") return void 0;
14
+ const element = document.createElement("div");
15
+ element.className = Dialog_default.root;
16
+ element.dataset.pulpDialogs = "";
17
+ return element;
18
+ });
19
+ useEffect(() => {
20
+ if (!container) return;
21
+ document.body.append(container);
22
+ return () => container.remove();
23
+ }, [container]);
24
+ return /* @__PURE__ */ jsx(ModalSystem, { ...rest, container, children });
25
+ }
26
+ function Dialog(props) {
27
+ return /* @__PURE__ */ jsx(Modal, { ...props });
28
+ }
29
+ Dialog.displayName = "Dialog";
30
+ Dialog.Trigger = ModalTrigger;
31
+ Dialog.Content = ModalContent;
32
+ Dialog.Header = ModalHeader;
33
+ Dialog.Title = ModalTitle;
34
+ Dialog.Description = ModalDescription;
35
+ Dialog.Close = ModalClose;
36
+ Dialog.Body = ModalBody;
37
+ Dialog.Footer = ModalFooter;
38
+
39
+ export { Dialog, DialogSystem };
40
+ //# sourceMappingURL=chunk-IDNGNQNV.js.map
41
+ //# sourceMappingURL=chunk-IDNGNQNV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/dialog/Dialog.module.css","../src/dialog/Dialog.tsx"],"names":["root","VendorSystem","VendorModal"],"mappings":";;;;;;;AAAA,IAAA,cAAA,GAAA;AAAA,EAOG,IAAA,EAAAA;AAAA,CAAA;AC6BI,SAAS,YAAA,CAAa,EAAE,QAAA,EAAU,GAAG,MAAK,EAAsB;AAIrE,EAAA,MAAM,CAAC,SAAS,CAAA,GAAI,QAAA,CAAqC,MAAM;AAC7D,IAAA,IAAI,OAAO,QAAA,KAAa,WAAA,EAAa,OAAO,MAAA;AAC5C,IAAA,MAAM,OAAA,GAAU,QAAA,CAAS,aAAA,CAAc,KAAK,CAAA;AAC5C,IAAA,OAAA,CAAQ,SAAA,GAAY,eAAO,IAAQ;AACnC,IAAA,OAAA,CAAQ,QAAQ,WAAA,GAAc,EAAA;AAC9B,IAAA,OAAO,OAAA;AAAA,EACT,CAAC,CAAA;AAED,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,SAAA,EAAW;AAChB,IAAA,QAAA,CAAS,IAAA,CAAK,OAAO,SAAS,CAAA;AAC9B,IAAA,OAAO,MAAM,UAAU,MAAA,EAAO;AAAA,EAChC,CAAA,EAAG,CAAC,SAAS,CAAC,CAAA;AAEd,EAAA,uBACE,GAAA,CAACC,WAAA,EAAA,EAAc,GAAG,IAAA,EAAM,WACrB,QAAA,EACH,CAAA;AAEJ;AAoBO,SAAS,OAAO,KAAA,EAAoB;AACzC,EAAA,uBAAO,GAAA,CAACC,KAAA,EAAA,EAAa,GAAG,KAAA,EAAO,CAAA;AACjC;AAEA,MAAA,CAAO,WAAA,GAAc,QAAA;AACrB,MAAA,CAAO,OAAA,GAAU,YAAA;AACjB,MAAA,CAAO,OAAA,GAAU,YAAA;AACjB,MAAA,CAAO,MAAA,GAAS,WAAA;AAChB,MAAA,CAAO,KAAA,GAAQ,UAAA;AACf,MAAA,CAAO,WAAA,GAAc,gBAAA;AACrB,MAAA,CAAO,KAAA,GAAQ,UAAA;AACf,MAAA,CAAO,IAAA,GAAO,SAAA;AACd,MAAA,CAAO,MAAA,GAAS,WAAA","file":"chunk-IDNGNQNV.js","sourcesContent":["/*\n * The vendor (@pearpages/modals) reads --modal-* custom properties. This class\n * goes on the portal element pulp owns, so every dialog inherits pulp's\n * --dialog-* tokens and the vendor's :root defaults never apply.\n */\n\n@layer components {\n .root {\n --modal-bg: var(--dialog-surface);\n --modal-surface-elevated: var(--dialog-surface);\n --modal-surface-subtle: var(--dialog-surface-subtle);\n --modal-color: var(--dialog-fg);\n --modal-text-secondary: var(--dialog-fg-muted);\n --modal-text-muted: var(--dialog-fg-muted);\n --modal-backdrop-bg: var(--dialog-backdrop);\n --modal-border-primary-color: var(--dialog-border);\n --modal-border-hover-color: var(--dialog-border-hover);\n --modal-border-focus-color: var(--dialog-focus);\n --modal-border-accent-color: var(--dialog-border);\n --modal-radius: var(--dialog-radius);\n --modal-radius-md: var(--dialog-radius);\n --modal-radius-sm: var(--radius-control);\n --modal-button-radius: var(--radius-control);\n --modal-shadow: var(--dialog-shadow);\n --modal-padding: var(--dialog-padding);\n --modal-spacing-xs: var(--space-1);\n --modal-spacing-sm: var(--space-2);\n --modal-spacing-md: var(--dialog-gap);\n --modal-spacing-lg: var(--space-4);\n --modal-spacing-xl: var(--space-5);\n --modal-font-family: var(--dialog-font-family);\n --modal-font-family-mono: var(--font-family-mono);\n --modal-font-size-title: var(--dialog-title-font-size);\n --modal-font-size-title-mobile: var(--dialog-title-font-size);\n --modal-font-weight-title: var(--dialog-title-font-weight);\n --modal-font-size-description: var(--dialog-description-font-size);\n --modal-font-size-description-mobile: var(--dialog-description-font-size);\n --modal-font-size-button: var(--font-size-sm);\n --modal-close-bg: var(--dialog-close-bg);\n --modal-close-hover-bg: var(--dialog-close-bg-hover);\n --modal-close-text: var(--dialog-close-fg);\n --modal-close-hover-text: var(--dialog-close-fg-hover);\n --modal-interactive-hover: var(--color-action-secondary-hover);\n --modal-interactive-active: var(--color-action-secondary-hover);\n --modal-interactive-focus: var(--color-action-primary-quiet);\n --modal-transition-duration: var(--dialog-motion-duration);\n --modal-transition-easing: var(--dialog-motion-easing);\n --modal-outline-width: var(--focus-ring-width);\n --modal-outline-offset: var(--focus-ring-offset);\n --modal-button-focus-color: var(--dialog-focus);\n --modal-button-primary-bg: var(--color-action-primary);\n --modal-button-primary-border: var(--color-action-primary);\n --modal-button-primary-color: var(--color-text-on-action);\n --modal-button-primary-hover-bg: var(--color-action-primary-hover);\n --modal-button-primary-hover-border: var(--color-action-primary-hover);\n --modal-button-primary-active-bg: var(--color-action-primary-active);\n --modal-button-primary-active-border: var(--color-action-primary-active);\n --modal-button-secondary-bg: var(--color-action-secondary);\n --modal-button-secondary-border: var(--color-border-default);\n --modal-button-secondary-color: var(--color-text-default);\n --modal-button-secondary-hover-bg: var(--color-action-secondary-hover);\n --modal-button-secondary-hover-border: var(--color-border-strong);\n --modal-button-secondary-active-bg: var(--color-action-secondary-hover);\n --modal-button-secondary-active-border: var(--color-border-strong);\n }\n}\n","import { useEffect, useState, type ComponentProps, type ReactNode } from 'react';\nimport {\n Modal as VendorModal,\n ModalBody,\n ModalClose,\n ModalContent,\n ModalDescription,\n ModalFooter,\n ModalHeader,\n ModalSystem as VendorSystem,\n ModalTitle,\n ModalTrigger,\n type ModalProps,\n} from '@pearpages/modals';\nimport styles from './Dialog.module.css';\n\nexport type DialogProps = ModalProps;\n\nexport interface DialogSystemProps extends Omit<ComponentProps<typeof VendorSystem>, 'container'> {\n children: ReactNode;\n}\n\n/**\n * Mount once near the app root. Owns the portal element every dialog renders\n * into and sets the vendor's `--modal-*` variables on it from pulp's\n * `--dialog-*` tokens, so backdrop, surface, type and motion follow the\n * current brand and scheme. Because the variables sit on an ancestor of the\n * dialog, they win over the vendor stylesheet regardless of cascade layers\n * or import order.\n *\n * @status stable\n * @category Overlays\n * @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.\n * @do Mount it once, near the app root, inside any providers dialogs need.\n * @dont Nest it; one system serves every dialog.\n */\nexport function DialogSystem({ children, ...rest }: DialogSystemProps) {\n // Created detached during the first render (no DOM mutation yet, so it is\n // safe to do here and needs no state update); attached and removed in the\n // effect. Undefined on the server, where the vendor falls back to its default.\n const [container] = useState<HTMLDivElement | undefined>(() => {\n if (typeof document === 'undefined') return undefined;\n const element = document.createElement('div');\n element.className = styles.root ?? '';\n element.dataset.pulpDialogs = '';\n return element;\n });\n\n useEffect(() => {\n if (!container) return;\n document.body.append(container);\n return () => container.remove();\n }, [container]);\n\n return (\n <VendorSystem {...rest} container={container}>\n {children}\n </VendorSystem>\n );\n}\n\n/**\n * An accessible modal dialog: focus trap, inert page, Escape and backdrop\n * dismissal, stacking. Built on `@pearpages/modals`; pulp adds the theming and\n * the 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\n * dialog's children render only while it is open. Use pulp's `Button` for\n * actions. Requires `DialogSystem` above it and the vendor stylesheet\n * `@pearpages/modals/styles.css`.\n *\n * @status stable\n * @category Overlays\n * @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`.\n * @do Always render a `Dialog.Title`.\n * Put the destructive action last in `Dialog.Footer` and make the safe one the default focus.\n * @dont Open a dialog from inside a Menu or Popover that stays open.\n * Use it for content that does not need the page blocked; use Popover.\n */\nexport function Dialog(props: DialogProps) {\n return <VendorModal {...props} />;\n}\n\nDialog.displayName = 'Dialog';\nDialog.Trigger = ModalTrigger;\nDialog.Content = ModalContent;\nDialog.Header = ModalHeader;\nDialog.Title = ModalTitle;\nDialog.Description = ModalDescription;\nDialog.Close = ModalClose;\nDialog.Body = ModalBody;\nDialog.Footer = ModalFooter;\n"]}
@@ -0,0 +1,67 @@
1
+ import { isPresent, AriaFieldLabel, AriaFieldDescription, AriaFieldError, ariaFieldClass } from './chunk-4HRNRTXI.js';
2
+ import { renderOption, renderEmpty, listClass } from './chunk-T76YSNTZ.js';
3
+ import { Icon } from './chunk-ASNTNTJW.js';
4
+ import { Select, Button, SelectValue, Popover, ListBox } from 'react-aria-components';
5
+ import { ChevronDown } from '@pearpages/pulp-icons';
6
+ import { jsxs, jsx } from 'react/jsx-runtime';
7
+
8
+ // src/picker/Picker.module.css
9
+ var Picker_default = {
10
+ root: "Picker_root",
11
+ trigger: "Picker_trigger",
12
+ value: "Picker_value",
13
+ chevron: "Picker_chevron",
14
+ popover: "Picker_popover",
15
+ list: "Picker_list"
16
+ };
17
+ function Picker({
18
+ label,
19
+ description,
20
+ error,
21
+ items,
22
+ value,
23
+ defaultValue,
24
+ onChange,
25
+ placeholder = "Select\u2026",
26
+ emptyMessage = "No options",
27
+ size = "md",
28
+ required = false,
29
+ disabled = false,
30
+ name,
31
+ autoFocus,
32
+ className,
33
+ ref
34
+ }) {
35
+ const invalid = isPresent(error);
36
+ return /* @__PURE__ */ jsxs(
37
+ Select,
38
+ {
39
+ className: ariaFieldClass(Picker_default.root, className),
40
+ "data-size": size,
41
+ selectedKey: value,
42
+ defaultSelectedKey: defaultValue,
43
+ onSelectionChange: (key) => onChange?.(key === null ? null : String(key)),
44
+ placeholder,
45
+ isRequired: required,
46
+ isDisabled: disabled,
47
+ isInvalid: invalid,
48
+ name,
49
+ autoFocus,
50
+ children: [
51
+ /* @__PURE__ */ jsx(AriaFieldLabel, { required, children: label }),
52
+ /* @__PURE__ */ jsxs(Button, { ref, className: Picker_default.trigger, children: [
53
+ /* @__PURE__ */ jsx(SelectValue, { className: Picker_default.value }),
54
+ /* @__PURE__ */ jsx(Icon, { size: "inherit", className: Picker_default.chevron, children: /* @__PURE__ */ jsx(ChevronDown, {}) })
55
+ ] }),
56
+ /* @__PURE__ */ jsx(AriaFieldDescription, { children: description }),
57
+ /* @__PURE__ */ jsx(AriaFieldError, { children: error }),
58
+ /* @__PURE__ */ jsx(Popover, { className: Picker_default.popover, placement: "bottom start", children: /* @__PURE__ */ jsx(ListBox, { className: listClass(Picker_default.list), items, renderEmptyState: () => renderEmpty(emptyMessage), children: renderOption }) })
59
+ ]
60
+ }
61
+ );
62
+ }
63
+ Picker.displayName = "Picker";
64
+
65
+ export { Picker };
66
+ //# sourceMappingURL=chunk-J5S2HVHO.js.map
67
+ //# sourceMappingURL=chunk-J5S2HVHO.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/picker/Picker.module.css","../src/picker/Picker.tsx"],"names":["root","trigger","value","chevron","popover","list","AriaSelect","AriaButton","AriaSelectValue","AriaPopover","AriaListBox"],"mappings":";;;;;;;;AAAA,IAAA,cAAA,GAAA;AAAA,EAOG,IAAA,EAAAA,aAAAA;AAAA,EAoBA,OAAA,EAAAC,gBAAAA;AAAA,EAkCA,KAAA,EAAAC,cAAAA;AAAA,EAWA,OAAA,EAAAC,gBAAAA;AAAA,EAKA,OAAA,EAAAC,gBAAAA;AAAA,EAUA,IAAA,EAAAC;AAAA,CAAA;AC9BI,SAAS,MAAA,CAAO;AAAA,EACrB,KAAA;AAAA,EACA,WAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,YAAA;AAAA,EACA,QAAA;AAAA,EACA,WAAA,GAAc,cAAA;AAAA,EACd,YAAA,GAAe,YAAA;AAAA,EACf,IAAA,GAAO,IAAA;AAAA,EACP,QAAA,GAAW,KAAA;AAAA,EACX,QAAA,GAAW,KAAA;AAAA,EACX,IAAA;AAAA,EACA,SAAA;AAAA,EACA,SAAA;AAAA,EACA;AACF,CAAA,EAAgB;AACd,EAAA,MAAM,OAAA,GAAU,UAAU,KAAK,CAAA;AAC/B,EAAA,uBACE,IAAA;AAAA,IAACC,MAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAW,cAAA,CAAe,cAAA,CAAO,IAAA,EAAM,SAAS,CAAA;AAAA,MAChD,WAAA,EAAW,IAAA;AAAA,MACX,WAAA,EAAa,KAAA;AAAA,MACb,kBAAA,EAAoB,YAAA;AAAA,MACpB,iBAAA,EAAmB,CAAC,GAAA,KAAQ,QAAA,GAAW,QAAQ,IAAA,GAAO,IAAA,GAAO,MAAA,CAAO,GAAG,CAAC,CAAA;AAAA,MACxE,WAAA;AAAA,MACA,UAAA,EAAY,QAAA;AAAA,MACZ,UAAA,EAAY,QAAA;AAAA,MACZ,SAAA,EAAW,OAAA;AAAA,MACX,IAAA;AAAA,MACA,SAAA;AAAA,MAEA,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,cAAA,EAAA,EAAe,UAAqB,QAAA,EAAA,KAAA,EAAM,CAAA;AAAA,wBAC3C,IAAA,CAACC,MAAA,EAAA,EAAW,GAAA,EAAU,SAAA,EAAW,eAAO,OAAA,EACtC,QAAA,EAAA;AAAA,0BAAA,GAAA,CAACC,WAAA,EAAA,EAAgB,SAAA,EAAW,cAAA,CAAO,KAAA,EAAO,CAAA;AAAA,0BAC1C,GAAA,CAAC,QAAK,IAAA,EAAK,SAAA,EAAU,WAAW,cAAA,CAAO,OAAA,EACrC,QAAA,kBAAA,GAAA,CAAC,WAAA,EAAA,EAAY,CAAA,EACf;AAAA,SAAA,EACF,CAAA;AAAA,wBACA,GAAA,CAAC,wBAAsB,QAAA,EAAA,WAAA,EAAY,CAAA;AAAA,wBACnC,GAAA,CAAC,kBAAgB,QAAA,EAAA,KAAA,EAAM,CAAA;AAAA,wBACvB,GAAA,CAACC,WAAY,SAAA,EAAW,cAAA,CAAO,SAAS,SAAA,EAAU,cAAA,EAChD,8BAACC,OAAA,EAAA,EAAY,SAAA,EAAW,UAAU,cAAA,CAAO,IAAI,GAAG,KAAA,EAAc,gBAAA,EAAkB,MAAM,WAAA,CAAY,YAAY,CAAA,EAC3G,QAAA,EAAA,YAAA,EACH,CAAA,EACF;AAAA;AAAA;AAAA,GACF;AAEJ;AAEA,MAAA,CAAO,WAAA,GAAc,QAAA","file":"chunk-J5S2HVHO.js","sourcesContent":["/*\n * Every value is a token (--picker-*); the options read --listbox-*. The\n * trigger is a button drawn like a text field. The popover is positioned by\n * React Aria; the gap is its own padding and --trigger-width (vendor) sizes it.\n */\n\n@layer components {\n .root {\n --_height: var(--picker-height-md);\n --_font-size: var(--picker-font-size-md);\n --_border: var(--picker-border-default);\n\n font-family: var(--picker-font-family);\n\n &[data-size=\"sm\"] {\n --_height: var(--picker-height-sm);\n --_font-size: var(--picker-font-size-sm);\n }\n\n &[data-size=\"lg\"] {\n --_height: var(--picker-height-lg);\n --_font-size: var(--picker-font-size-lg);\n }\n\n &[data-invalid] { --_border: var(--picker-border-invalid); }\n }\n\n .trigger {\n display: flex;\n align-items: center;\n gap: var(--picker-gap);\n inline-size: 100%;\n min-block-size: var(--_height);\n padding-block: 0;\n padding-inline: var(--picker-padding-inline);\n border: var(--size-hairline) solid var(--_border);\n border-radius: var(--picker-radius);\n background-color: var(--picker-bg);\n color: var(--picker-fg);\n font-family: inherit;\n font-size: var(--_font-size);\n text-align: start;\n cursor: pointer;\n transition: border-color var(--picker-motion-duration) var(--motion-easing-standard);\n\n &[data-focus-visible] {\n border-color: var(--picker-border-focus);\n outline: var(--picker-focus-ring-width) solid var(--picker-focus-ring);\n outline-offset: var(--picker-focus-ring-offset);\n }\n\n &[data-disabled] {\n cursor: not-allowed;\n opacity: 0.55;\n }\n\n &[data-hovered]:not([data-focus-visible], [data-disabled]) {\n border-color: var(--picker-border-hover);\n }\n }\n\n .value {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n\n &[data-placeholder] {\n color: var(--picker-placeholder);\n }\n }\n\n .chevron {\n flex: none;\n color: var(--picker-icon);\n }\n\n .popover {\n inline-size: var(--trigger-width);\n padding-block-start: var(--picker-gap);\n animation: fade var(--picker-popover-duration) var(--motion-easing-standard);\n\n &[data-placement=\"top\"] {\n padding-block: 0 var(--picker-gap);\n }\n }\n\n .list {\n box-shadow: var(--picker-popover-shadow);\n }\n\n @keyframes fade {\n from {\n opacity: 0;\n }\n }\n\n @media (prefers-reduced-motion: reduce) {\n .popover {\n animation: none;\n }\n }\n}\n","import type { ReactNode, Ref } from 'react';\nimport { Button as AriaButton, ListBox as AriaListBox, Popover as AriaPopover, Select as AriaSelect, SelectValue as AriaSelectValue } from 'react-aria-components';\nimport { ChevronDown } from '@pearpages/pulp-icons';\nimport { Icon } from '../icon';\nimport { AriaFieldDescription, AriaFieldError, AriaFieldLabel, ariaFieldClass, isPresent } from '../internal/AriaField';\nimport { listClass, renderEmpty, renderOption, type ListboxItem } from '../listbox/ListboxOptions';\nimport styles from './Picker.module.css';\n\nexport type PickerItem = ListboxItem;\nexport type PickerSize = 'sm' | 'md' | 'lg';\n\nexport interface PickerProps {\n /** Visible label. Always rendered. */\n label: ReactNode;\n description?: ReactNode;\n /** Presence marks the control invalid and announces the message. */\n error?: ReactNode;\n /** The options. Ids are the values. */\n items: readonly PickerItem[];\n /** Selected id (controlled). `null` is \"nothing selected\". */\n value?: string | null;\n defaultValue?: string | null;\n onChange?: (value: string | null) => void;\n /** Shown in the control until a value is chosen. @default 'Select…' */\n placeholder?: string;\n /** Shown when `items` is empty. @default 'No options' */\n emptyMessage?: ReactNode;\n /** @default 'md' */\n size?: PickerSize;\n /** @default false */\n required?: boolean;\n /** @default false */\n disabled?: boolean;\n /** Submitted with a form through a hidden native select. */\n name?: string;\n autoFocus?: boolean;\n /** Applied to the field wrapper, not the button. */\n className?: string;\n /** The trigger `<button>`. */\n ref?: Ref<HTMLButtonElement>;\n}\n\n/**\n * A single-choice select with rich options (a description line, consistent\n * styling in every browser), on React Aria's select (decision record 001):\n * a button opens a listbox, arrows and typing move, Enter chooses, Escape\n * closes, and a hidden native select carries the value in forms. For a\n * plain list of words, the native `Select` is the default; for several\n * choices at once, use Listbox.\n *\n * @status experimental\n * @category Forms\n * @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.\n * @do Use a `description` line on options when the label alone is ambiguous.\n * Prefer the native Select for a plain list of words.\n * @dont Use `placeholder` as the only label.\n */\nexport function Picker({\n label,\n description,\n error,\n items,\n value,\n defaultValue,\n onChange,\n placeholder = 'Select…',\n emptyMessage = 'No options',\n size = 'md',\n required = false,\n disabled = false,\n name,\n autoFocus,\n className,\n ref,\n}: PickerProps) {\n const invalid = isPresent(error);\n return (\n <AriaSelect\n className={ariaFieldClass(styles.root, className)}\n data-size={size}\n selectedKey={value}\n defaultSelectedKey={defaultValue}\n onSelectionChange={(key) => onChange?.(key === null ? null : String(key))}\n placeholder={placeholder}\n isRequired={required}\n isDisabled={disabled}\n isInvalid={invalid}\n name={name}\n autoFocus={autoFocus}\n >\n <AriaFieldLabel required={required}>{label}</AriaFieldLabel>\n <AriaButton ref={ref} className={styles.trigger}>\n <AriaSelectValue className={styles.value} />\n <Icon size=\"inherit\" className={styles.chevron}>\n <ChevronDown />\n </Icon>\n </AriaButton>\n <AriaFieldDescription>{description}</AriaFieldDescription>\n <AriaFieldError>{error}</AriaFieldError>\n <AriaPopover className={styles.popover} placement=\"bottom start\">\n <AriaListBox className={listClass(styles.list)} items={items} renderEmptyState={() => renderEmpty(emptyMessage)}>\n {renderOption}\n </AriaListBox>\n </AriaPopover>\n </AriaSelect>\n );\n}\n\nPicker.displayName = 'Picker';\n"]}
@@ -0,0 +1,84 @@
1
+ import { IconButton } from './chunk-FXRSZUDH.js';
2
+ import { Button } from './chunk-KPQGS4PG.js';
3
+ import { classes } from './chunk-MI4QUKQS.js';
4
+ import { ArrowLeft, ArrowRight } from '@pearpages/pulp-icons';
5
+ import { jsx, jsxs } from 'react/jsx-runtime';
6
+
7
+ // src/pagination/range.ts
8
+ function paginationRange(page, count, siblings, boundaries) {
9
+ const span = (from, to) => Array.from({ length: Math.max(0, to - from + 1) }, (_, i) => from + i);
10
+ const total = boundaries * 2 + siblings * 2 + 3;
11
+ if (count <= total) return span(1, count);
12
+ const start = span(1, boundaries);
13
+ const end = span(count - boundaries + 1, count);
14
+ const siblingStart = Math.max(Math.min(page - siblings, count - boundaries - siblings * 2 - 1), boundaries + 2);
15
+ const siblingEnd = Math.min(Math.max(page + siblings, boundaries + siblings * 2 + 2), count - boundaries - 1);
16
+ return [
17
+ ...start,
18
+ ...siblingStart > boundaries + 2 ? ["start-ellipsis"] : span(boundaries + 1, boundaries + 1),
19
+ ...span(siblingStart, siblingEnd),
20
+ ...siblingEnd < count - boundaries - 1 ? ["end-ellipsis"] : span(count - boundaries, count - boundaries),
21
+ ...end
22
+ ];
23
+ }
24
+
25
+ // src/pagination/Pagination.module.css
26
+ var Pagination_default = {
27
+ root: "Pagination_root",
28
+ list: "Pagination_list",
29
+ page: "Pagination_page",
30
+ ellipsis: "Pagination_ellipsis"
31
+ };
32
+ function Pagination({
33
+ page,
34
+ count,
35
+ onPageChange,
36
+ siblings = 1,
37
+ boundaries = 1,
38
+ getHref,
39
+ size = "md",
40
+ "aria-label": ariaLabel = "Pagination",
41
+ previousLabel = "Previous page",
42
+ nextLabel = "Next page",
43
+ pageLabel = (n) => `Page ${n}`,
44
+ className,
45
+ ref,
46
+ ...rest
47
+ }) {
48
+ const go = (target) => () => onPageChange?.(target);
49
+ return /* @__PURE__ */ jsx("nav", { ...rest, ref, "aria-label": ariaLabel, className: classes(Pagination_default.root, className), "data-size": size, children: /* @__PURE__ */ jsxs("ul", { className: Pagination_default.list, children: [
50
+ /* @__PURE__ */ jsx("li", { children: page > 1 && getHref ? /* @__PURE__ */ jsx(IconButton, { asChild: true, label: previousLabel, icon: /* @__PURE__ */ jsx(ArrowLeft, {}), variant: "ghost", size, onClick: go(page - 1), children: /* @__PURE__ */ jsx("a", { href: getHref(page - 1) }) }) : /* @__PURE__ */ jsx(IconButton, { label: previousLabel, icon: /* @__PURE__ */ jsx(ArrowLeft, {}), variant: "ghost", size, disabled: page <= 1, onClick: go(page - 1) }) }),
51
+ paginationRange(page, count, siblings, boundaries).map(
52
+ (item) => typeof item === "number" ? /* @__PURE__ */ jsx("li", { children: getHref ? /* @__PURE__ */ jsx(
53
+ Button,
54
+ {
55
+ asChild: true,
56
+ variant: item === page ? "primary" : "ghost",
57
+ size,
58
+ className: Pagination_default.page,
59
+ "aria-label": pageLabel(item),
60
+ "aria-current": item === page ? "page" : void 0,
61
+ onClick: go(item),
62
+ children: /* @__PURE__ */ jsx("a", { href: getHref(item), children: item })
63
+ }
64
+ ) : /* @__PURE__ */ jsx(
65
+ Button,
66
+ {
67
+ variant: item === page ? "primary" : "ghost",
68
+ size,
69
+ className: Pagination_default.page,
70
+ "aria-label": pageLabel(item),
71
+ "aria-current": item === page ? "page" : void 0,
72
+ onClick: go(item),
73
+ children: item
74
+ }
75
+ ) }, item) : /* @__PURE__ */ jsx("li", { className: Pagination_default.ellipsis, "aria-hidden": "true", children: "\u2026" }, item)
76
+ ),
77
+ /* @__PURE__ */ jsx("li", { children: page < count && getHref ? /* @__PURE__ */ jsx(IconButton, { asChild: true, label: nextLabel, icon: /* @__PURE__ */ jsx(ArrowRight, {}), variant: "ghost", size, onClick: go(page + 1), children: /* @__PURE__ */ jsx("a", { href: getHref(page + 1) }) }) : /* @__PURE__ */ jsx(IconButton, { label: nextLabel, icon: /* @__PURE__ */ jsx(ArrowRight, {}), variant: "ghost", size, disabled: page >= count, onClick: go(page + 1) }) })
78
+ ] }) });
79
+ }
80
+ Pagination.displayName = "Pagination";
81
+
82
+ export { Pagination, paginationRange };
83
+ //# sourceMappingURL=chunk-K5QGGQOV.js.map
84
+ //# sourceMappingURL=chunk-K5QGGQOV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/pagination/range.ts","../src/pagination/Pagination.module.css","../src/pagination/Pagination.tsx"],"names":["root","list","page","ellipsis"],"mappings":";;;;;;;AAGO,SAAS,eAAA,CAAgB,IAAA,EAAc,KAAA,EAAe,QAAA,EAAkB,UAAA,EAAsC;AACnH,EAAA,MAAM,IAAA,GAAO,CAAC,IAAA,EAAc,EAAA,KAAe,MAAM,IAAA,CAAK,EAAE,QAAQ,IAAA,CAAK,GAAA,CAAI,GAAG,EAAA,GAAK,IAAA,GAAO,CAAC,CAAA,EAAE,EAAG,CAAC,CAAA,EAAG,CAAA,KAAM,OAAO,CAAC,CAAA;AAChH,EAAA,MAAM,KAAA,GAAQ,UAAA,GAAa,CAAA,GAAI,QAAA,GAAW,CAAA,GAAI,CAAA;AAC9C,EAAA,IAAI,KAAA,IAAS,KAAA,EAAO,OAAO,IAAA,CAAK,GAAG,KAAK,CAAA;AACxC,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,CAAA,EAAG,UAAU,CAAA;AAChC,EAAA,MAAM,GAAA,GAAM,IAAA,CAAK,KAAA,GAAQ,UAAA,GAAa,GAAG,KAAK,CAAA;AAC9C,EAAA,MAAM,YAAA,GAAe,IAAA,CAAK,GAAA,CAAI,IAAA,CAAK,IAAI,IAAA,GAAO,QAAA,EAAU,KAAA,GAAQ,UAAA,GAAa,QAAA,GAAW,CAAA,GAAI,CAAC,CAAA,EAAG,aAAa,CAAC,CAAA;AAC9G,EAAA,MAAM,UAAA,GAAa,IAAA,CAAK,GAAA,CAAI,IAAA,CAAK,IAAI,IAAA,GAAO,QAAA,EAAU,UAAA,GAAa,QAAA,GAAW,CAAA,GAAI,CAAC,CAAA,EAAG,KAAA,GAAQ,aAAa,CAAC,CAAA;AAC5G,EAAA,OAAO;AAAA,IACL,GAAG,KAAA;AAAA,IACH,GAAI,YAAA,GAAe,UAAA,GAAa,CAAA,GAAK,CAAC,gBAAgB,CAAA,GAAyB,IAAA,CAAK,UAAA,GAAa,CAAA,EAAG,UAAA,GAAa,CAAC,CAAA;AAAA,IAClH,GAAG,IAAA,CAAK,YAAA,EAAc,UAAU,CAAA;AAAA,IAChC,GAAI,UAAA,GAAa,KAAA,GAAQ,UAAA,GAAa,CAAA,GAAK,CAAC,cAAc,CAAA,GAAyB,IAAA,CAAK,KAAA,GAAQ,UAAA,EAAY,KAAA,GAAQ,UAAU,CAAA;AAAA,IAC9H,GAAG;AAAA,GACL;AACF;;;AClBA,IAAA,kBAAA,GAAA;AAAA,EAGG,IAAA,EAAAA,iBAAAA;AAAA,EAYA,IAAA,EAAAC,iBAAAA;AAAA,EAUA,IAAA,EAAAC,iBAAAA;AAAA,EAMA,QAAA,EAAAC;AAAA,CAAA;ACiBI,SAAS,UAAA,CAAW;AAAA,EACzB,IAAA;AAAA,EACA,KAAA;AAAA,EACA,YAAA;AAAA,EACA,QAAA,GAAW,CAAA;AAAA,EACX,UAAA,GAAa,CAAA;AAAA,EACb,OAAA;AAAA,EACA,IAAA,GAAO,IAAA;AAAA,EACP,cAAc,SAAA,GAAY,YAAA;AAAA,EAC1B,aAAA,GAAgB,eAAA;AAAA,EAChB,SAAA,GAAY,WAAA;AAAA,EACZ,SAAA,GAAY,CAAC,CAAA,KAAM,CAAA,KAAA,EAAQ,CAAC,CAAA,CAAA;AAAA,EAC5B,SAAA;AAAA,EACA,GAAA;AAAA,EACA,GAAG;AACL,CAAA,EAAoB;AAClB,EAAA,MAAM,EAAA,GAAK,CAAC,MAAA,KAAmB,MAAM,eAAe,MAAM,CAAA;AAE1D,EAAA,2BACG,KAAA,EAAA,EAAK,GAAG,MAAM,GAAA,EAAU,YAAA,EAAY,WAAW,SAAA,EAAW,OAAA,CAAQ,mBAAO,IAAA,EAAM,SAAS,GAAG,WAAA,EAAW,IAAA,EACrG,+BAAC,IAAA,EAAA,EAAG,SAAA,EAAW,mBAAO,IAAA,EACpB,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,IAAA,EAAA,EACE,iBAAO,CAAA,IAAK,OAAA,uBACV,UAAA,EAAA,EAA8B,OAAA,EAAO,IAAA,EAAC,KAAA,EAAO,aAAA,EAAe,IAAA,sBAAO,SAAA,EAAA,EAAU,CAAA,EAAI,OAAA,EAAQ,OAAA,EAAQ,IAAA,EAAY,OAAA,EAAS,GAAG,IAAA,GAAO,CAAC,CAAA,EAChI,QAAA,kBAAA,GAAA,CAAC,GAAA,EAAA,EAAE,IAAA,EAAM,QAAQ,IAAA,GAAO,CAAC,GAAG,CAAA,EAC9B,CAAA,uBAEC,UAAA,EAAA,EAAW,KAAA,EAAO,aAAA,EAAe,IAAA,kBAAM,GAAA,CAAC,SAAA,EAAA,EAAU,GAAI,OAAA,EAAQ,OAAA,EAAQ,IAAA,EAAY,QAAA,EAAU,IAAA,IAAQ,CAAA,EAAG,SAAS,EAAA,CAAG,IAAA,GAAO,CAAC,CAAA,EAAG,CAAA,EAEnI,CAAA;AAAA,IACC,eAAA,CAAgB,IAAA,EAAM,KAAA,EAAO,QAAA,EAAU,UAAU,CAAA,CAAE,GAAA;AAAA,MAAI,CAAC,IAAA,KACvD,OAAO,SAAS,QAAA,mBACd,GAAA,CAAC,QACE,QAAA,EAAA,OAAA,mBACC,GAAA;AAAA,QAAC,MAAA;AAAA,QAAA;AAAA,UACC,OAAA,EAAO,IAAA;AAAA,UACP,OAAA,EAAS,IAAA,KAAS,IAAA,GAAO,SAAA,GAAY,OAAA;AAAA,UACrC,IAAA;AAAA,UACA,WAAW,kBAAA,CAAO,IAAA;AAAA,UAClB,YAAA,EAAY,UAAU,IAAI,CAAA;AAAA,UAC1B,cAAA,EAAc,IAAA,KAAS,IAAA,GAAO,MAAA,GAAS,MAAA;AAAA,UACvC,OAAA,EAAS,GAAG,IAAI,CAAA;AAAA,UAEhB,8BAAC,GAAA,EAAA,EAAE,IAAA,EAAM,OAAA,CAAQ,IAAI,GAAI,QAAA,EAAA,IAAA,EAAK;AAAA;AAAA,OAChC,mBAEA,GAAA;AAAA,QAAC,MAAA;AAAA,QAAA;AAAA,UACC,OAAA,EAAS,IAAA,KAAS,IAAA,GAAO,SAAA,GAAY,OAAA;AAAA,UACrC,IAAA;AAAA,UACA,WAAW,kBAAA,CAAO,IAAA;AAAA,UAClB,YAAA,EAAY,UAAU,IAAI,CAAA;AAAA,UAC1B,cAAA,EAAc,IAAA,KAAS,IAAA,GAAO,MAAA,GAAS,MAAA;AAAA,UACvC,OAAA,EAAS,GAAG,IAAI,CAAA;AAAA,UAEf,QAAA,EAAA;AAAA;AAAA,OACH,EAAA,EAvBK,IAyBT,CAAA,mBAEA,GAAA,CAAC,IAAA,EAAA,EAAc,SAAA,EAAW,kBAAA,CAAO,QAAA,EAAU,aAAA,EAAY,MAAA,EAAO,QAAA,EAAA,QAAA,EAAA,EAArD,IAET;AAAA,KAEJ;AAAA,oBACA,GAAA,CAAC,QACE,QAAA,EAAA,IAAA,GAAO,KAAA,IAAS,0BACf,GAAA,CAAC,UAAA,EAAA,EAA8B,OAAA,EAAO,IAAA,EAAC,KAAA,EAAO,SAAA,EAAW,sBAAM,GAAA,CAAC,UAAA,EAAA,EAAW,CAAA,EAAI,OAAA,EAAQ,OAAA,EAAQ,IAAA,EAAY,SAAS,EAAA,CAAG,IAAA,GAAO,CAAC,CAAA,EAC7H,QAAA,kBAAA,GAAA,CAAC,GAAA,EAAA,EAAE,MAAM,OAAA,CAAQ,IAAA,GAAO,CAAC,CAAA,EAAG,CAAA,EAC9B,CAAA,uBAEC,UAAA,EAAA,EAAW,KAAA,EAAO,SAAA,EAAW,IAAA,kBAAM,GAAA,CAAC,UAAA,EAAA,EAAW,GAAI,OAAA,EAAQ,OAAA,EAAQ,IAAA,EAAY,QAAA,EAAU,IAAA,IAAQ,KAAA,EAAO,SAAS,EAAA,CAAG,IAAA,GAAO,CAAC,CAAA,EAAG,CAAA,EAEpI;AAAA,GAAA,EACF,CAAA,EACF,CAAA;AAEJ;AAEA,UAAA,CAAW,WAAA,GAAc,YAAA","file":"chunk-K5QGGQOV.js","sourcesContent":["export type PaginationItem = number | 'start-ellipsis' | 'end-ellipsis';\n\n/** Which pages to show: boundaries at both ends, siblings around the current page, ellipses for the rest. */\nexport function paginationRange(page: number, count: number, siblings: number, boundaries: number): PaginationItem[] {\n const span = (from: number, to: number) => Array.from({ length: Math.max(0, to - from + 1) }, (_, i) => from + i);\n const total = boundaries * 2 + siblings * 2 + 3;\n if (count <= total) return span(1, count);\n const start = span(1, boundaries);\n const end = span(count - boundaries + 1, count);\n const siblingStart = Math.max(Math.min(page - siblings, count - boundaries - siblings * 2 - 1), boundaries + 2);\n const siblingEnd = Math.min(Math.max(page + siblings, boundaries + siblings * 2 + 2), count - boundaries - 1);\n return [\n ...start,\n ...(siblingStart > boundaries + 2 ? (['start-ellipsis'] as PaginationItem[]) : span(boundaries + 1, boundaries + 1)),\n ...span(siblingStart, siblingEnd),\n ...(siblingEnd < count - boundaries - 1 ? (['end-ellipsis'] as PaginationItem[]) : span(count - boundaries, count - boundaries)),\n ...end,\n ];\n}\n","/* Every value is a token (--pagination-*). The controls are Buttons; this file lays them out. */\n\n@layer components {\n .root {\n --_size: var(--pagination-ellipsis-size-md);\n --_font-size: var(--pagination-font-size-md);\n\n font-family: var(--pagination-font-family);\n\n &[data-size=\"sm\"] {\n --_size: var(--pagination-ellipsis-size-sm);\n --_font-size: var(--pagination-font-size-sm);\n }\n }\n\n .list {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--pagination-gap);\n padding: 0;\n margin: 0;\n list-style: none;\n }\n\n .page {\n min-inline-size: var(--_size);\n padding-inline: 0;\n font-variant-numeric: tabular-nums;\n }\n\n .ellipsis {\n display: grid;\n place-items: center;\n min-inline-size: var(--_size);\n block-size: var(--_size);\n color: var(--pagination-ellipsis-fg);\n font-size: var(--_font-size);\n }\n}\n","import type { HTMLAttributes, Ref } from 'react';\nimport { ArrowLeft, ArrowRight } from '@pearpages/pulp-icons';\nimport { Button } from '../button';\nimport { IconButton } from '../icon-button';\nimport { classes } from '../internal/classes';\nimport { paginationRange } from './range';\nimport styles from './Pagination.module.css';\n\nexport type PaginationSize = 'sm' | 'md';\nexport interface PaginationProps extends Omit<HTMLAttributes<HTMLElement>, 'onChange'> {\n /** The current page, 1-based. */\n page: number;\n /** Total number of pages. */\n count: number;\n onPageChange?: (page: number) => void;\n /** Pages shown on each side of the current one. @default 1 */\n siblings?: number;\n /** Pages always shown at each end. @default 1 */\n boundaries?: number;\n /** Render pages as links (server-side or router pagination) instead of buttons. */\n getHref?: (page: number) => string;\n /** @default 'md' */\n size?: PaginationSize;\n /** The landmark's name. @default 'Pagination' */\n 'aria-label'?: string;\n /** @default 'Previous page' */\n previousLabel?: string;\n /** @default 'Next page' */\n nextLabel?: string;\n /** Accessible name of a page control. @default (n) => `Page ${n}` */\n pageLabel?: (page: number) => string;\n ref?: Ref<HTMLElement>;\n}\n\n/**\n * Page controls in a `nav` landmark: previous, numbered pages with the\n * current one marked `aria-current=\"page\"`, and next. Distant pages\n * collapse into an ellipsis. Buttons by default; `getHref` renders links so\n * the pages are crawlable and open in new tabs. Built from Button and\n * IconButton, so it needs no keyboard model of its own.\n *\n * @status experimental\n * @category Navigation\n * @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.\n * @do Use `getHref` when pages have URLs so they can be opened in new tabs and crawled.\n * Keep `siblings` at 1 on narrow screens.\n * @dont Disable the whole component while a page loads; disable only what cannot be pressed.\n */\nexport function Pagination({\n page,\n count,\n onPageChange,\n siblings = 1,\n boundaries = 1,\n getHref,\n size = 'md',\n 'aria-label': ariaLabel = 'Pagination',\n previousLabel = 'Previous page',\n nextLabel = 'Next page',\n pageLabel = (n) => `Page ${n}`,\n className,\n ref,\n ...rest\n}: PaginationProps) {\n const go = (target: number) => () => onPageChange?.(target);\n\n return (\n <nav {...rest} ref={ref} aria-label={ariaLabel} className={classes(styles.root, className)} data-size={size}>\n <ul className={styles.list}>\n <li>\n {page > 1 && getHref ? (\n <IconButton<HTMLAnchorElement> asChild label={previousLabel} icon={<ArrowLeft />} variant=\"ghost\" size={size} onClick={go(page - 1)}>\n <a href={getHref(page - 1)} />\n </IconButton>\n ) : (\n <IconButton label={previousLabel} icon={<ArrowLeft />} variant=\"ghost\" size={size} disabled={page <= 1} onClick={go(page - 1)} />\n )}\n </li>\n {paginationRange(page, count, siblings, boundaries).map((item) =>\n typeof item === 'number' ? (\n <li key={item}>\n {getHref ? (\n <Button<HTMLAnchorElement>\n asChild\n variant={item === page ? 'primary' : 'ghost'}\n size={size}\n className={styles.page}\n aria-label={pageLabel(item)}\n aria-current={item === page ? 'page' : undefined}\n onClick={go(item)}\n >\n <a href={getHref(item)}>{item}</a>\n </Button>\n ) : (\n <Button\n variant={item === page ? 'primary' : 'ghost'}\n size={size}\n className={styles.page}\n aria-label={pageLabel(item)}\n aria-current={item === page ? 'page' : undefined}\n onClick={go(item)}\n >\n {item}\n </Button>\n )}\n </li>\n ) : (\n <li key={item} className={styles.ellipsis} aria-hidden=\"true\">\n …\n </li>\n ),\n )}\n <li>\n {page < count && getHref ? (\n <IconButton<HTMLAnchorElement> asChild label={nextLabel} icon={<ArrowRight />} variant=\"ghost\" size={size} onClick={go(page + 1)}>\n <a href={getHref(page + 1)} />\n </IconButton>\n ) : (\n <IconButton label={nextLabel} icon={<ArrowRight />} variant=\"ghost\" size={size} disabled={page >= count} onClick={go(page + 1)} />\n )}\n </li>\n </ul>\n </nav>\n );\n}\n\nPagination.displayName = 'Pagination';\n"]}
@@ -0,0 +1,77 @@
1
+ import { Spinner } from './chunk-I4KC4V6A.js';
2
+ import { renderAsChild } from './chunk-ZVDN3GRI.js';
3
+ import { Icon } from './chunk-ASNTNTJW.js';
4
+ import { classes } from './chunk-MI4QUKQS.js';
5
+ import { Children, isValidElement } from 'react';
6
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
7
+
8
+ // src/button/Button.module.css
9
+ var Button_default = {
10
+ button: "Button_button",
11
+ label: "Button_label"
12
+ };
13
+ var BLOCK = (event) => event.preventDefault();
14
+ var DEV = typeof process !== "undefined" && process.env?.NODE_ENV !== "production";
15
+ function hasText(node) {
16
+ return Children.toArray(node).some((child) => {
17
+ if (typeof child === "string") return child.trim().length > 0;
18
+ if (typeof child === "number") return true;
19
+ if (isValidElement(child)) return hasText(child.props.children);
20
+ return false;
21
+ });
22
+ }
23
+ function Button({
24
+ variant = "primary",
25
+ size = "md",
26
+ loading = false,
27
+ iconStart,
28
+ iconEnd,
29
+ asChild = false,
30
+ className,
31
+ disabled = false,
32
+ type,
33
+ onClick,
34
+ ref,
35
+ children,
36
+ ...rest
37
+ }) {
38
+ const inert = disabled || loading;
39
+ const nativeDisabled = !asChild && disabled;
40
+ if (DEV && !hasText(asChild ? children.props?.children : children)) {
41
+ if (!rest["aria-label"] && !rest["aria-labelledby"]) {
42
+ console.warn("Button: no text content and no aria-label. Icon-only buttons need an accessible name.");
43
+ }
44
+ }
45
+ const props = {
46
+ ...rest,
47
+ ref,
48
+ className: classes(Button_default.button, className),
49
+ "data-variant": variant,
50
+ "data-size": size,
51
+ "data-loading": loading ? "" : void 0,
52
+ "aria-busy": loading || void 0,
53
+ disabled: nativeDisabled || void 0,
54
+ "aria-disabled": inert && !nativeDisabled ? true : void 0,
55
+ type: asChild ? void 0 : type ?? "button",
56
+ onClick: inert ? BLOCK : onClick
57
+ };
58
+ const decorate = (label) => /* @__PURE__ */ jsxs(Fragment, { children: [
59
+ loading && /* @__PURE__ */ jsx(Spinner, { decorative: true, size: "inherit", tone: "inherit" }),
60
+ iconStart && /* @__PURE__ */ jsx(Icon, { size: "inherit", children: iconStart }),
61
+ /* @__PURE__ */ jsx("span", { className: Button_default.label, children: label }),
62
+ iconEnd && /* @__PURE__ */ jsx(Icon, { size: "inherit", children: iconEnd })
63
+ ] });
64
+ if (asChild) {
65
+ const child = children;
66
+ return renderAsChild("Button", children, { ...props, children: decorate(child.props?.children) }, {
67
+ // An inert control must not run the child's handler either.
68
+ replace: inert ? ["onClick"] : []
69
+ });
70
+ }
71
+ return /* @__PURE__ */ jsx("button", { ...props, children: decorate(children) });
72
+ }
73
+ Button.displayName = "Button";
74
+
75
+ export { Button };
76
+ //# sourceMappingURL=chunk-KPQGS4PG.js.map
77
+ //# sourceMappingURL=chunk-KPQGS4PG.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/button/Button.module.css","../src/button/Button.tsx"],"names":["button","label"],"mappings":"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","file":"chunk-KPQGS4PG.js","sourcesContent":["/*\n * Every value is a token. State is expressed through data attributes so the\n * styling hooks survive a change of styling tool, and so tests and agents can\n * read state off the DOM.\n */\n\n@layer components {\n .button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: var(--button-gap);\n min-block-size: var(--button-height-md);\n padding-block: 0;\n padding-inline: var(--button-padding-inline-md);\n border: 1px solid transparent;\n border-radius: var(--button-radius);\n font-family: var(--button-font-family);\n font-size: var(--button-font-size-md);\n font-weight: var(--button-font-weight);\n line-height: 1;\n text-decoration: none;\n white-space: nowrap;\n cursor: pointer;\n user-select: none;\n transition:\n background-color var(--button-motion-duration) var(--motion-easing-standard),\n border-color var(--button-motion-duration) var(--motion-easing-standard),\n color var(--button-motion-duration) var(--motion-easing-standard);\n\n &:focus-visible {\n outline: var(--button-focus-ring-width) solid var(--button-focus-ring);\n outline-offset: var(--button-focus-ring-offset);\n }\n\n &:disabled,\n &[aria-disabled=\"true\"] {\n cursor: not-allowed;\n opacity: 0.55;\n }\n\n &[data-loading] {\n cursor: progress;\n }\n\n &[data-size=\"sm\"] {\n min-block-size: var(--button-height-sm);\n padding-inline: var(--button-padding-inline-sm);\n font-size: var(--button-font-size-sm);\n }\n\n &[data-size=\"lg\"] {\n min-block-size: var(--button-height-lg);\n padding-inline: var(--button-padding-inline-lg);\n font-size: var(--button-font-size-lg);\n }\n\n &[data-variant=\"primary\"] {\n background-color: var(--button-primary-bg);\n color: var(--button-primary-fg);\n\n &:hover:not(:disabled, [aria-disabled=\"true\"]) {\n background-color: var(--button-primary-bg-hover);\n }\n\n &:active:not(:disabled, [aria-disabled=\"true\"]) {\n background-color: var(--button-primary-bg-active);\n }\n }\n\n &[data-variant=\"secondary\"] {\n background-color: var(--button-secondary-bg);\n border-color: var(--button-secondary-border);\n color: var(--button-secondary-fg);\n\n &:hover:not(:disabled, [aria-disabled=\"true\"]) {\n background-color: var(--button-secondary-bg-hover);\n }\n }\n\n &[data-variant=\"ghost\"] {\n background-color: transparent;\n color: var(--button-ghost-fg);\n\n &:hover:not(:disabled, [aria-disabled=\"true\"]) {\n background-color: var(--button-ghost-bg-hover);\n }\n }\n }\n\n .label {\n display: inline-block;\n }\n}\n","import { Children, isValidElement, type ButtonHTMLAttributes, type MouseEvent, type ReactNode, type Ref } from 'react';\nimport { Icon } from '../icon';\nimport { renderAsChild } from '../internal/asChild';\nimport { Spinner } from '../spinner';\nimport { classes } from '../internal/classes';\nimport styles from './Button.module.css';\n\nexport type ButtonVariant = 'primary' | 'secondary' | 'ghost';\nexport type ButtonSize = 'sm' | 'md' | 'lg';\n\nexport interface ButtonProps<E extends HTMLElement = HTMLButtonElement> extends ButtonHTMLAttributes<HTMLButtonElement> {\n /**\n * Visual emphasis. One `primary` per view; `secondary` for the rest;\n * `ghost` for actions that sit inside other content.\n * @default 'primary'\n */\n variant?: ButtonVariant;\n /** @default 'md' */\n size?: ButtonSize;\n /**\n * Shows a spinner, sets `aria-busy` and `aria-disabled`, and blocks\n * activation. The element stays focusable so focus is not lost mid-action,\n * and the label stays in place so the button keeps its width.\n * @default false\n */\n loading?: boolean;\n /** Decorative element before the label. Hidden from assistive technology. */\n iconStart?: ReactNode;\n /** Decorative element after the label. Hidden from assistive technology. */\n iconEnd?: ReactNode;\n /**\n * Render the single child element instead of a `<button>`, merging the\n * button's props into it. Use it to style a router `<Link>` or an `<a>` as a\n * button. Disabled and loading states then use `aria-disabled`, and the\n * child's own `onClick` does not run while the control is inert.\n * @default false\n */\n asChild?: boolean;\n /**\n * The rendered element. With `asChild` that is the child's element, so pass\n * the type parameter: `<Button<HTMLAnchorElement> asChild ref={anchorRef}>`.\n */\n ref?: Ref<E>;\n children: ReactNode;\n}\n\nconst BLOCK = (event: MouseEvent) => event.preventDefault();\n\nconst DEV = typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production';\n\n/** True when some text exists anywhere in the children tree. */\nfunction hasText(node: ReactNode): boolean {\n return Children.toArray(node).some((child) => {\n if (typeof child === 'string') return child.trim().length > 0;\n if (typeof child === 'number') return true;\n if (isValidElement<{ children?: ReactNode }>(child)) return hasText(child.props.children);\n return false;\n });\n}\n\n/**\n * The one action component. Variants map to emphasis, not colour: one\n * `primary` per view, `secondary` for the rest, `ghost` inside other content.\n * Every value comes from `--button-*` tokens, so a brand restyles it without\n * touching the component. State is exposed as `data-variant`, `data-size` and\n * `data-loading` for styling, tests and agents alike.\n *\n * @status stable\n * @category Actions\n * @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.\n * @do One `primary` per view.\n * Use `asChild` for links that look like buttons, keeping the `a` semantics.\n * @dont Use `loading` on a button that is not the one that started the work.\n * Rely on colour to tell variants apart; the label carries the meaning.\n */\nexport function Button<E extends HTMLElement = HTMLButtonElement>({\n variant = 'primary',\n size = 'md',\n loading = false,\n iconStart,\n iconEnd,\n asChild = false,\n className,\n disabled = false,\n type,\n onClick,\n ref,\n children,\n ...rest\n}: ButtonProps<E>) {\n // Inert: must not activate. `disabled` on a real <button> also removes it\n // from the tab order, which is right for \"disabled\" and wrong for \"loading\":\n // the element the user just pressed must keep focus. So loading (and every\n // asChild state) uses aria-disabled and blocks activation in the handler.\n const inert = disabled || loading;\n const nativeDisabled = !asChild && disabled;\n\n if (DEV && !hasText(asChild ? (children as { props?: { children?: ReactNode } }).props?.children : children)) {\n if (!rest['aria-label'] && !rest['aria-labelledby']) {\n console.warn('Button: no text content and no aria-label. Icon-only buttons need an accessible name.');\n }\n }\n\n const props = {\n ...rest,\n ref,\n className: classes(styles.button, className),\n 'data-variant': variant,\n 'data-size': size,\n 'data-loading': loading ? '' : undefined,\n 'aria-busy': loading || undefined,\n disabled: nativeDisabled || undefined,\n 'aria-disabled': inert && !nativeDisabled ? true : undefined,\n type: asChild ? undefined : (type ?? 'button'),\n onClick: inert ? BLOCK : onClick,\n };\n\n const decorate = (label: ReactNode) => (\n <>\n {loading && <Spinner decorative size=\"inherit\" tone=\"inherit\" />}\n {iconStart && <Icon size=\"inherit\">{iconStart}</Icon>}\n <span className={styles.label}>{label}</span>\n {iconEnd && <Icon size=\"inherit\">{iconEnd}</Icon>}\n </>\n );\n\n if (asChild) {\n const child = children as { props?: { children?: ReactNode } };\n // The helper merges the forwarded ref with the child's; nothing reads it.\n // eslint-disable-next-line react-hooks/refs -- forwarded, not read\n return renderAsChild('Button', children, { ...props, children: decorate(child.props?.children) }, {\n // An inert control must not run the child's handler either.\n replace: inert ? ['onClick'] : [],\n });\n }\n\n return <button {...(props as ButtonHTMLAttributes<HTMLButtonElement>)}>{decorate(children)}</button>;\n}\n\nButton.displayName = 'Button';\n"]}
@@ -0,0 +1,8 @@
1
+ // src/internal/classes.ts
2
+ function classes(...names) {
3
+ return names.filter(Boolean).join(" ");
4
+ }
5
+
6
+ export { classes };
7
+ //# sourceMappingURL=chunk-MI4QUKQS.js.map
8
+ //# sourceMappingURL=chunk-MI4QUKQS.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/internal/classes.ts"],"names":[],"mappings":";AACO,SAAS,WAAW,KAAA,EAAyD;AAClF,EAAA,OAAO,KAAA,CAAM,MAAA,CAAO,OAAO,CAAA,CAAE,KAAK,GAAG,CAAA;AACvC","file":"chunk-MI4QUKQS.js","sourcesContent":["/** Join class names, dropping falsy entries. */\nexport function classes(...names: Array<string | false | null | undefined>): string {\n return names.filter(Boolean).join(' ');\n}\n"]}
@@ -0,0 +1,57 @@
1
+ import { renderAsChild } from './chunk-ZVDN3GRI.js';
2
+ import { classes } from './chunk-MI4QUKQS.js';
3
+ import { jsx } from 'react/jsx-runtime';
4
+
5
+ // src/card/Card.module.css
6
+ var Card_default = {
7
+ card: "Card_card",
8
+ header: "Card_header",
9
+ body: "Card_body",
10
+ footer: "Card_footer"
11
+ };
12
+ function Card({
13
+ variant = "raised",
14
+ padding = "md",
15
+ interactive = false,
16
+ asChild = false,
17
+ className,
18
+ tabIndex,
19
+ ref,
20
+ children,
21
+ ...rest
22
+ }) {
23
+ const props = {
24
+ ...rest,
25
+ ref,
26
+ className: classes(Card_default.card, className),
27
+ "data-variant": variant,
28
+ "data-padding": padding,
29
+ "data-interactive": interactive ? "" : void 0,
30
+ // An interactive section must be reachable; a link or button already is.
31
+ tabIndex: tabIndex ?? (interactive && !asChild ? 0 : void 0)
32
+ };
33
+ if (asChild) {
34
+ return renderAsChild("Card", children, props);
35
+ }
36
+ return /* @__PURE__ */ jsx("section", { ...props, children });
37
+ }
38
+ function CardHeader({ className, ref, ...rest }) {
39
+ return /* @__PURE__ */ jsx("div", { ...rest, ref, className: classes(Card_default.header, className) });
40
+ }
41
+ function CardBody({ className, ref, ...rest }) {
42
+ return /* @__PURE__ */ jsx("div", { ...rest, ref, className: classes(Card_default.body, className) });
43
+ }
44
+ function CardFooter({ className, ref, ...rest }) {
45
+ return /* @__PURE__ */ jsx("div", { ...rest, ref, className: classes(Card_default.footer, className) });
46
+ }
47
+ Card.displayName = "Card";
48
+ CardHeader.displayName = "Card.Header";
49
+ CardBody.displayName = "Card.Body";
50
+ CardFooter.displayName = "Card.Footer";
51
+ Card.Header = CardHeader;
52
+ Card.Body = CardBody;
53
+ Card.Footer = CardFooter;
54
+
55
+ export { Card };
56
+ //# sourceMappingURL=chunk-MRQWUCBA.js.map
57
+ //# sourceMappingURL=chunk-MRQWUCBA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/card/Card.module.css","../src/card/Card.tsx"],"names":["card","header","body","footer"],"mappings":";;;;;AAAA,IAAA,YAAA,GAAA;AAAA,EAGG,IAAA,EAAAA,WAAAA;AAAA,EAmDA,MAAA,EAAAC,aAAAA;AAAA,EACA,IAAA,EAAAC,WAAAA;AAAA,EACA,MAAA,EAAAC;AAAA,CAAA;ACHI,SAAS,IAAA,CAA0C;AAAA,EACxD,OAAA,GAAU,QAAA;AAAA,EACV,OAAA,GAAU,IAAA;AAAA,EACV,WAAA,GAAc,KAAA;AAAA,EACd,OAAA,GAAU,KAAA;AAAA,EACV,SAAA;AAAA,EACA,QAAA;AAAA,EACA,GAAA;AAAA,EACA,QAAA;AAAA,EACA,GAAG;AACL,CAAA,EAAiB;AACf,EAAA,MAAM,KAAA,GAAQ;AAAA,IACZ,GAAG,IAAA;AAAA,IACH,GAAA;AAAA,IACA,SAAA,EAAW,OAAA,CAAQ,YAAA,CAAO,IAAA,EAAM,SAAS,CAAA;AAAA,IACzC,cAAA,EAAgB,OAAA;AAAA,IAChB,cAAA,EAAgB,OAAA;AAAA,IAChB,kBAAA,EAAoB,cAAc,EAAA,GAAK,MAAA;AAAA;AAAA,IAEvC,QAAA,EAAU,QAAA,KAAa,WAAA,IAAe,CAAC,UAAU,CAAA,GAAI,MAAA;AAAA,GACvD;AAEA,EAAA,IAAI,OAAA,EAAS;AAGX,IAAA,OAAO,aAAA,CAAc,MAAA,EAAQ,QAAA,EAAU,KAAK,CAAA;AAAA,EAC9C;AAEA,EAAA,uBAAO,GAAA,CAAC,SAAA,EAAA,EAAS,GAAI,KAAA,EAAwC,QAAA,EAAS,CAAA;AACxE;AAEA,SAAS,WAAW,EAAE,SAAA,EAAW,GAAA,EAAK,GAAG,MAAK,EAAc;AAC1D,EAAA,uBAAO,GAAA,CAAC,KAAA,EAAA,EAAK,GAAG,IAAA,EAAM,GAAA,EAAU,WAAW,OAAA,CAAQ,YAAA,CAAO,MAAA,EAAQ,SAAS,CAAA,EAAG,CAAA;AAChF;AAEA,SAAS,SAAS,EAAE,SAAA,EAAW,GAAA,EAAK,GAAG,MAAK,EAAc;AACxD,EAAA,uBAAO,GAAA,CAAC,KAAA,EAAA,EAAK,GAAG,IAAA,EAAM,GAAA,EAAU,WAAW,OAAA,CAAQ,YAAA,CAAO,IAAA,EAAM,SAAS,CAAA,EAAG,CAAA;AAC9E;AAEA,SAAS,WAAW,EAAE,SAAA,EAAW,GAAA,EAAK,GAAG,MAAK,EAAc;AAC1D,EAAA,uBAAO,GAAA,CAAC,KAAA,EAAA,EAAK,GAAG,IAAA,EAAM,GAAA,EAAU,WAAW,OAAA,CAAQ,YAAA,CAAO,MAAA,EAAQ,SAAS,CAAA,EAAG,CAAA;AAChF;AAEA,IAAA,CAAK,WAAA,GAAc,MAAA;AACnB,UAAA,CAAW,WAAA,GAAc,aAAA;AACzB,QAAA,CAAS,WAAA,GAAc,WAAA;AACvB,UAAA,CAAW,WAAA,GAAc,aAAA;AAEzB,IAAA,CAAK,MAAA,GAAS,UAAA;AACd,IAAA,CAAK,IAAA,GAAO,QAAA;AACZ,IAAA,CAAK,MAAA,GAAS,UAAA","file":"chunk-MRQWUCBA.js","sourcesContent":["/* Every value is a token (--card-*). Slots carry padding and dividers; the root is the surface. */\n\n@layer components {\n .card {\n --_pad: var(--card-padding-md);\n\n display: flex;\n flex-direction: column;\n min-inline-size: 0;\n border: 1px solid transparent;\n border-radius: var(--card-radius);\n background-color: var(--card-bg);\n color: var(--card-fg);\n text-decoration: none;\n transition:\n border-color var(--card-motion-duration) var(--motion-easing-standard),\n box-shadow var(--card-motion-duration) var(--motion-easing-standard),\n translate var(--card-motion-duration) var(--motion-easing-standard);\n\n &[data-padding=\"sm\"] {\n --_pad: var(--card-padding-sm);\n }\n\n &[data-padding=\"lg\"] {\n --_pad: var(--card-padding-lg);\n }\n\n &[data-variant=\"raised\"] {\n box-shadow: var(--card-shadow);\n }\n\n &[data-variant=\"outlined\"] {\n border-color: var(--card-border);\n }\n\n &[data-variant=\"sunken\"] {\n background-color: var(--card-bg-sunken);\n }\n\n &[data-interactive] {\n cursor: pointer;\n\n &:hover {\n border-color: var(--card-border-hover);\n translate: 0 -1px;\n }\n\n &:focus-visible {\n outline: var(--card-focus-ring-width) solid var(--card-focus-ring);\n outline-offset: var(--card-focus-ring-offset);\n }\n }\n }\n\n .header,\n .body,\n .footer {\n padding: var(--_pad);\n }\n\n .header {\n display: flex;\n flex-direction: column;\n gap: var(--card-gap);\n border-block-end: 1px solid var(--card-divider);\n }\n\n .body {\n flex: 1;\n }\n\n .footer {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--card-gap);\n border-block-start: 1px solid var(--card-divider);\n }\n}\n","import type { HTMLAttributes, ReactNode, Ref } from 'react';\nimport { renderAsChild } from '../internal/asChild';\nimport { classes } from '../internal/classes';\nimport styles from './Card.module.css';\n\nexport type CardVariant = 'raised' | 'outlined' | 'sunken';\nexport type CardPadding = 'sm' | 'md' | 'lg';\n\nexport interface CardProps<E extends HTMLElement = HTMLElement> extends HTMLAttributes<HTMLElement> {\n /**\n * How the card separates from the page: `raised` by shadow, `outlined` by\n * border, `sunken` by a recessed surface.\n * @default 'raised'\n */\n variant?: CardVariant;\n /** One knob for every slot's inner spacing. @default 'md' */\n padding?: CardPadding;\n /**\n * Hover and focus affordances for a card that is itself a target. Pair it\n * with `asChild` and a link, or supply your own role and handlers.\n * @default false\n */\n interactive?: boolean;\n /**\n * Render the single child element as the card (an `<a>` for a link card),\n * merging the card's props into it.\n * @default false\n */\n asChild?: boolean;\n /** The rendered element; a `<section>` unless `asChild`. */\n ref?: Ref<E>;\n children: ReactNode;\n}\n\ninterface SlotProps extends HTMLAttributes<HTMLDivElement> {\n ref?: Ref<HTMLDivElement>;\n children?: ReactNode;\n}\n\n/**\n * A surface that groups related content. Compose with `Card.Header`,\n * `Card.Body` and `Card.Footer`; the slots carry the padding and dividers so\n * the root stays a plain surface. Every value comes from `--card-*` tokens;\n * state is exposed as `data-variant`, `data-padding` and `data-interactive`.\n *\n * @status stable\n * @category Layout\n * @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.\n * @do Give a card an `aria-label` or a heading in `Card.Header` when it is a landmark worth naming.\n * Use `asChild` with an `a` for a whole-card link.\n * @dont Put more than one primary action inside an interactive card.\n * Nest interactive cards.\n */\nexport function Card<E extends HTMLElement = HTMLElement>({\n variant = 'raised',\n padding = 'md',\n interactive = false,\n asChild = false,\n className,\n tabIndex,\n ref,\n children,\n ...rest\n}: CardProps<E>) {\n const props = {\n ...rest,\n ref,\n className: classes(styles.card, className),\n 'data-variant': variant,\n 'data-padding': padding,\n 'data-interactive': interactive ? '' : undefined,\n // An interactive section must be reachable; a link or button already is.\n tabIndex: tabIndex ?? (interactive && !asChild ? 0 : undefined),\n };\n\n if (asChild) {\n // The helper merges the forwarded ref with the child's; nothing reads it.\n // eslint-disable-next-line react-hooks/refs -- forwarded, not read\n return renderAsChild('Card', children, props);\n }\n\n return <section {...(props as HTMLAttributes<HTMLElement>)}>{children}</section>;\n}\n\nfunction CardHeader({ className, ref, ...rest }: SlotProps) {\n return <div {...rest} ref={ref} className={classes(styles.header, className)} />;\n}\n\nfunction CardBody({ className, ref, ...rest }: SlotProps) {\n return <div {...rest} ref={ref} className={classes(styles.body, className)} />;\n}\n\nfunction CardFooter({ className, ref, ...rest }: SlotProps) {\n return <div {...rest} ref={ref} className={classes(styles.footer, className)} />;\n}\n\nCard.displayName = 'Card';\nCardHeader.displayName = 'Card.Header';\nCardBody.displayName = 'Card.Body';\nCardFooter.displayName = 'Card.Footer';\n\nCard.Header = CardHeader;\nCard.Body = CardBody;\nCard.Footer = CardFooter;\n"]}
@@ -0,0 +1,48 @@
1
+ import { Field } from './chunk-2PXTVZ7H.js';
2
+ import { classes } from './chunk-MI4QUKQS.js';
3
+ import { jsxs, jsx } from 'react/jsx-runtime';
4
+
5
+ // src/text-field/TextField.module.css
6
+ var TextField_default = {
7
+ field: "TextField_field",
8
+ input: "TextField_input"
9
+ };
10
+ function TextField({
11
+ label,
12
+ description,
13
+ error,
14
+ size = "md",
15
+ required,
16
+ disabled,
17
+ readOnly,
18
+ id,
19
+ className,
20
+ ref,
21
+ "aria-describedby": describedBy,
22
+ ...rest
23
+ }) {
24
+ const invalid = error !== void 0 && error !== null && error !== false && error !== "";
25
+ return /* @__PURE__ */ jsxs(
26
+ Field,
27
+ {
28
+ id,
29
+ invalid,
30
+ disabled: Boolean(disabled),
31
+ required: Boolean(required),
32
+ className: classes(TextField_default.field, className),
33
+ "data-size": size,
34
+ "data-readonly": readOnly ? "" : void 0,
35
+ children: [
36
+ /* @__PURE__ */ jsx(Field.Label, { children: label }),
37
+ /* @__PURE__ */ jsx(Field.Control, { "aria-describedby": describedBy, children: /* @__PURE__ */ jsx("input", { ...rest, ref, className: TextField_default.input, readOnly }) }),
38
+ description && /* @__PURE__ */ jsx(Field.Description, { children: description }),
39
+ invalid && /* @__PURE__ */ jsx(Field.Error, { children: error })
40
+ ]
41
+ }
42
+ );
43
+ }
44
+ TextField.displayName = "TextField";
45
+
46
+ export { TextField };
47
+ //# sourceMappingURL=chunk-MXWXJZFS.js.map
48
+ //# sourceMappingURL=chunk-MXWXJZFS.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/text-field/TextField.module.css","../src/text-field/TextField.tsx"],"names":["field","input"],"mappings":";;;;;AAAA,IAAA,iBAAA,GAAA;AAAA,EAOG,KAAA,EAAAA,iBAAAA;AAAA,EAIA,KAAA,EAAAC;AAAA,CAAA;AC8BI,SAAS,SAAA,CAAU;AAAA,EACxB,KAAA;AAAA,EACA,WAAA;AAAA,EACA,KAAA;AAAA,EACA,IAAA,GAAO,IAAA;AAAA,EACP,QAAA;AAAA,EACA,QAAA;AAAA,EACA,QAAA;AAAA,EACA,EAAA;AAAA,EACA,SAAA;AAAA,EACA,GAAA;AAAA,EACA,kBAAA,EAAoB,WAAA;AAAA,EACpB,GAAG;AACL,CAAA,EAAmB;AACjB,EAAA,MAAM,UAAU,KAAA,KAAU,MAAA,IAAa,UAAU,IAAA,IAAQ,KAAA,KAAU,SAAS,KAAA,KAAU,EAAA;AAEtF,EAAA,uBACE,IAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,EAAA;AAAA,MACA,OAAA;AAAA,MACA,QAAA,EAAU,QAAQ,QAAQ,CAAA;AAAA,MAC1B,QAAA,EAAU,QAAQ,QAAQ,CAAA;AAAA,MAC1B,SAAA,EAAW,OAAA,CAAQ,iBAAA,CAAO,KAAA,EAAO,SAAS,CAAA;AAAA,MAC1C,WAAA,EAAW,IAAA;AAAA,MACX,eAAA,EAAe,WAAW,EAAA,GAAK,MAAA;AAAA,MAE/B,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,KAAA,CAAM,KAAA,EAAN,EAAa,QAAA,EAAA,KAAA,EAAM,CAAA;AAAA,wBACpB,GAAA,CAAC,KAAA,CAAM,OAAA,EAAN,EAAc,oBAAkB,WAAA,EAC/B,QAAA,kBAAA,GAAA,CAAC,OAAA,EAAA,EAAO,GAAG,MAAM,GAAA,EAAU,SAAA,EAAW,iBAAA,CAAO,KAAA,EAAO,UAAoB,CAAA,EAC1E,CAAA;AAAA,QACC,WAAA,oBAAe,GAAA,CAAC,KAAA,CAAM,WAAA,EAAN,EAAmB,QAAA,EAAA,WAAA,EAAY,CAAA;AAAA,QAC/C,OAAA,oBAAW,GAAA,CAAC,KAAA,CAAM,KAAA,EAAN,EAAa,QAAA,EAAA,KAAA,EAAM;AAAA;AAAA;AAAA,GAClC;AAEJ;AAEA,SAAA,CAAU,WAAA,GAAc,WAAA","file":"chunk-MXWXJZFS.js","sourcesContent":["/*\n * The input's own styles (--text-field-*). Label, description and error come\n * from Field. State lives on the wrapper as data attributes and on the input\n * as native pseudo-classes.\n */\n\n@layer components {\n .field {\n font-family: var(--text-field-font-family);\n }\n\n .input {\n min-block-size: var(--text-field-height-md);\n padding-block: 0;\n padding-inline: var(--text-field-padding-inline);\n border: 1px solid var(--text-field-border-default);\n border-radius: var(--text-field-radius);\n background-color: var(--text-field-bg);\n color: var(--text-field-fg);\n font-size: var(--text-field-font-size-md);\n transition:\n border-color var(--text-field-motion-duration) var(--motion-easing-standard),\n background-color var(--text-field-motion-duration) var(--motion-easing-standard);\n\n &::placeholder {\n color: var(--text-field-placeholder);\n }\n\n &:focus-visible {\n border-color: var(--text-field-border-focus);\n outline: var(--text-field-focus-ring-width) solid var(--text-field-focus-ring);\n outline-offset: var(--text-field-focus-ring-offset);\n }\n\n &:disabled {\n cursor: not-allowed;\n opacity: 0.55;\n }\n\n &:read-only:not(:disabled) {\n background-color: var(--color-surface-sunken);\n }\n\n &:hover:not(:disabled, :focus-visible) {\n border-color: var(--text-field-border-hover);\n }\n }\n\n .field[data-size=\"sm\"] .input {\n min-block-size: var(--text-field-height-sm);\n font-size: var(--text-field-font-size-sm);\n }\n\n .field[data-size=\"lg\"] .input {\n min-block-size: var(--text-field-height-lg);\n font-size: var(--text-field-font-size-lg);\n }\n\n .field[data-invalid] .input {\n border-color: var(--text-field-border-invalid);\n }\n}\n","import type { InputHTMLAttributes, ReactNode, Ref } from 'react';\nimport { Field } from '../field';\nimport { classes } from '../internal/classes';\nimport styles from './TextField.module.css';\n\nexport type TextFieldSize = 'sm' | 'md' | 'lg';\n\nexport interface TextFieldProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'size'> {\n /** Visible label. Always rendered: a placeholder is not a label. */\n label: ReactNode;\n /** Help text under the field, exposed as the input's accessible description. */\n description?: ReactNode;\n /**\n * Error message. Its presence marks the input invalid (`aria-invalid`,\n * `data-invalid`) and the message is announced as an alert.\n */\n error?: ReactNode;\n /** @default 'md' */\n size?: TextFieldSize;\n /** The `<input>` element. */\n ref?: Ref<HTMLInputElement>;\n /** Applied to the wrapper, not the input. */\n className?: string;\n}\n\n/**\n * A single-line text input on top of `Field`: label, description and error\n * wired for assistive technology. Controlled and uncontrolled behave exactly\n * like the native input (`value`/`onChange` or `defaultValue`). Every value\n * comes from `--text-field-*` and `--field-*` tokens; state is exposed as\n * `data-size`, `data-invalid`, `data-disabled` and `data-readonly` on the\n * wrapper.\n *\n * @status stable\n * @category Forms\n * @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.\n * @do Always pass `label`; use a visible one.\n * Prefer `error` text that says how to fix the value.\n * @dont Use `placeholder` as the label.\n * Use it for multi-line text; use Textarea.\n */\nexport function TextField({\n label,\n description,\n error,\n size = 'md',\n required,\n disabled,\n readOnly,\n id,\n className,\n ref,\n 'aria-describedby': describedBy,\n ...rest\n}: TextFieldProps) {\n const invalid = error !== undefined && error !== null && error !== false && error !== '';\n\n return (\n <Field\n id={id}\n invalid={invalid}\n disabled={Boolean(disabled)}\n required={Boolean(required)}\n className={classes(styles.field, className)}\n data-size={size}\n data-readonly={readOnly ? '' : undefined}\n >\n <Field.Label>{label}</Field.Label>\n <Field.Control aria-describedby={describedBy}>\n <input {...rest} ref={ref} className={styles.input} readOnly={readOnly} />\n </Field.Control>\n {description && <Field.Description>{description}</Field.Description>}\n {invalid && <Field.Error>{error}</Field.Error>}\n </Field>\n );\n}\n\nTextField.displayName = 'TextField';\n"]}