@funstack/ui 0.0.0-stage → 0.1.0-alpha.1

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 (299) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +42 -2
  3. package/dist/accordion/accordion-context.d.mts +5 -0
  4. package/dist/accordion/accordion-context.d.mts.map +1 -0
  5. package/dist/accordion/accordion-context.mjs +9 -0
  6. package/dist/accordion/accordion-context.mjs.map +1 -0
  7. package/dist/accordion/accordion-item.d.mts +53 -0
  8. package/dist/accordion/accordion-item.d.mts.map +1 -0
  9. package/dist/accordion/accordion-item.mjs +85 -0
  10. package/dist/accordion/accordion-item.mjs.map +1 -0
  11. package/dist/accordion/accordion-panel.d.mts +40 -0
  12. package/dist/accordion/accordion-panel.d.mts.map +1 -0
  13. package/dist/accordion/accordion-panel.mjs +40 -0
  14. package/dist/accordion/accordion-panel.mjs.map +1 -0
  15. package/dist/accordion/accordion-root.d.mts +90 -0
  16. package/dist/accordion/accordion-root.d.mts.map +1 -0
  17. package/dist/accordion/accordion-root.mjs +229 -0
  18. package/dist/accordion/accordion-root.mjs.map +1 -0
  19. package/dist/accordion/accordion-trigger.d.mts +37 -0
  20. package/dist/accordion/accordion-trigger.d.mts.map +1 -0
  21. package/dist/accordion/accordion-trigger.mjs +81 -0
  22. package/dist/accordion/accordion-trigger.mjs.map +1 -0
  23. package/dist/accordion/index.d.mts +20 -0
  24. package/dist/accordion/index.d.mts.map +1 -0
  25. package/dist/accordion/index.mjs +20 -0
  26. package/dist/accordion/index.mjs.map +1 -0
  27. package/dist/checkbox/checkbox.d.mts +92 -0
  28. package/dist/checkbox/checkbox.d.mts.map +1 -0
  29. package/dist/checkbox/checkbox.mjs +82 -0
  30. package/dist/checkbox/checkbox.mjs.map +1 -0
  31. package/dist/checkbox/index.d.mts +3 -0
  32. package/dist/checkbox/index.mjs +1 -0
  33. package/dist/checkbox-group/checkbox-group-context.mjs +24 -0
  34. package/dist/checkbox-group/checkbox-group-context.mjs.map +1 -0
  35. package/dist/checkbox-group/checkbox-group-item.d.mts +55 -0
  36. package/dist/checkbox-group/checkbox-group-item.d.mts.map +1 -0
  37. package/dist/checkbox-group/checkbox-group-item.mjs +90 -0
  38. package/dist/checkbox-group/checkbox-group-item.mjs.map +1 -0
  39. package/dist/checkbox-group/checkbox-group-label.d.mts +21 -0
  40. package/dist/checkbox-group/checkbox-group-label.d.mts.map +1 -0
  41. package/dist/checkbox-group/checkbox-group-label.mjs +30 -0
  42. package/dist/checkbox-group/checkbox-group-label.mjs.map +1 -0
  43. package/dist/checkbox-group/checkbox-group-parent.d.mts +68 -0
  44. package/dist/checkbox-group/checkbox-group-parent.d.mts.map +1 -0
  45. package/dist/checkbox-group/checkbox-group-parent.mjs +145 -0
  46. package/dist/checkbox-group/checkbox-group-parent.mjs.map +1 -0
  47. package/dist/checkbox-group/checkbox-group-root.d.mts +100 -0
  48. package/dist/checkbox-group/checkbox-group-root.d.mts.map +1 -0
  49. package/dist/checkbox-group/checkbox-group-root.mjs +291 -0
  50. package/dist/checkbox-group/checkbox-group-root.mjs.map +1 -0
  51. package/dist/checkbox-group/index.d.mts +23 -0
  52. package/dist/checkbox-group/index.d.mts.map +1 -0
  53. package/dist/checkbox-group/index.mjs +23 -0
  54. package/dist/checkbox-group/index.mjs.map +1 -0
  55. package/dist/dialog/dialog-close.d.mts +44 -0
  56. package/dist/dialog/dialog-close.d.mts.map +1 -0
  57. package/dist/dialog/dialog-close.mjs +76 -0
  58. package/dist/dialog/dialog-close.mjs.map +1 -0
  59. package/dist/dialog/dialog-context.mjs +13 -0
  60. package/dist/dialog/dialog-context.mjs.map +1 -0
  61. package/dist/dialog/dialog-description.d.mts +22 -0
  62. package/dist/dialog/dialog-description.d.mts.map +1 -0
  63. package/dist/dialog/dialog-description.mjs +31 -0
  64. package/dist/dialog/dialog-description.mjs.map +1 -0
  65. package/dist/dialog/dialog-form.d.mts +58 -0
  66. package/dist/dialog/dialog-form.d.mts.map +1 -0
  67. package/dist/dialog/dialog-form.mjs +108 -0
  68. package/dist/dialog/dialog-form.mjs.map +1 -0
  69. package/dist/dialog/dialog-popup.d.mts +81 -0
  70. package/dist/dialog/dialog-popup.d.mts.map +1 -0
  71. package/dist/dialog/dialog-popup.mjs +367 -0
  72. package/dist/dialog/dialog-popup.mjs.map +1 -0
  73. package/dist/dialog/dialog-root.d.mts +70 -0
  74. package/dist/dialog/dialog-root.d.mts.map +1 -0
  75. package/dist/dialog/dialog-root.mjs +113 -0
  76. package/dist/dialog/dialog-root.mjs.map +1 -0
  77. package/dist/dialog/dialog-title.d.mts +23 -0
  78. package/dist/dialog/dialog-title.d.mts.map +1 -0
  79. package/dist/dialog/dialog-title.mjs +31 -0
  80. package/dist/dialog/dialog-title.mjs.map +1 -0
  81. package/dist/dialog/dialog-trigger.d.mts +39 -0
  82. package/dist/dialog/dialog-trigger.d.mts.map +1 -0
  83. package/dist/dialog/dialog-trigger.mjs +80 -0
  84. package/dist/dialog/dialog-trigger.mjs.map +1 -0
  85. package/dist/dialog/index.d.mts +28 -0
  86. package/dist/dialog/index.d.mts.map +1 -0
  87. package/dist/dialog/index.mjs +28 -0
  88. package/dist/dialog/index.mjs.map +1 -0
  89. package/dist/index.d.mts +60 -0
  90. package/dist/index.mjs +12 -0
  91. package/dist/internal/action-details.mjs +47 -0
  92. package/dist/internal/action-details.mjs.map +1 -0
  93. package/dist/internal/anchor-position.d.mts +7 -0
  94. package/dist/internal/anchor-position.d.mts.map +1 -0
  95. package/dist/internal/anchor-position.mjs +16 -0
  96. package/dist/internal/anchor-position.mjs.map +1 -0
  97. package/dist/internal/data-attr.mjs +13 -0
  98. package/dist/internal/data-attr.mjs.map +1 -0
  99. package/dist/internal/merge-props.mjs +119 -0
  100. package/dist/internal/merge-props.mjs.map +1 -0
  101. package/dist/internal/platform-attributes.d.mts +55 -0
  102. package/dist/internal/platform-attributes.d.mts.map +1 -0
  103. package/dist/internal/sync-presence.mjs +19 -0
  104. package/dist/internal/sync-presence.mjs.map +1 -0
  105. package/dist/internal/transition-boundary.mjs +52 -0
  106. package/dist/internal/transition-boundary.mjs.map +1 -0
  107. package/dist/internal/transition-types.mjs +15 -0
  108. package/dist/internal/transition-types.mjs.map +1 -0
  109. package/dist/internal/types.d.mts +38 -0
  110. package/dist/internal/types.d.mts.map +1 -0
  111. package/dist/internal/use-action-trigger.mjs +58 -0
  112. package/dist/internal/use-action-trigger.mjs.map +1 -0
  113. package/dist/internal/use-controllable-action.mjs +115 -0
  114. package/dist/internal/use-controllable-action.mjs.map +1 -0
  115. package/dist/internal/use-delayed-pair.mjs +40 -0
  116. package/dist/internal/use-delayed-pair.mjs.map +1 -0
  117. package/dist/internal/use-dev-warning.mjs +21 -0
  118. package/dist/internal/use-dev-warning.mjs.map +1 -0
  119. package/dist/internal/use-exit-animation.mjs +55 -0
  120. package/dist/internal/use-exit-animation.mjs.map +1 -0
  121. package/dist/internal/use-form-reset.mjs +50 -0
  122. package/dist/internal/use-form-reset.mjs.map +1 -0
  123. package/dist/internal/use-native-checked.mjs +113 -0
  124. package/dist/internal/use-native-checked.mjs.map +1 -0
  125. package/dist/internal/use-native-group-reconciliation.mjs +64 -0
  126. package/dist/internal/use-native-group-reconciliation.mjs.map +1 -0
  127. package/dist/internal/use-popover-popup.mjs +274 -0
  128. package/dist/internal/use-popover-popup.mjs.map +1 -0
  129. package/dist/internal/use-popover-root.d.mts +2 -0
  130. package/dist/internal/use-popover-root.mjs +112 -0
  131. package/dist/internal/use-popover-root.mjs.map +1 -0
  132. package/dist/internal/use-popover-trigger.mjs +86 -0
  133. package/dist/internal/use-popover-trigger.mjs.map +1 -0
  134. package/dist/internal/use-render.mjs +51 -0
  135. package/dist/internal/use-render.mjs.map +1 -0
  136. package/dist/internal/use-until-found.mjs +40 -0
  137. package/dist/internal/use-until-found.mjs.map +1 -0
  138. package/dist/menu/index.d.mts +34 -0
  139. package/dist/menu/index.d.mts.map +1 -0
  140. package/dist/menu/index.mjs +34 -0
  141. package/dist/menu/index.mjs.map +1 -0
  142. package/dist/menu/menu-checkbox-item.d.mts +42 -0
  143. package/dist/menu/menu-checkbox-item.d.mts.map +1 -0
  144. package/dist/menu/menu-checkbox-item.mjs +71 -0
  145. package/dist/menu/menu-checkbox-item.mjs.map +1 -0
  146. package/dist/menu/menu-context.d.mts +1 -0
  147. package/dist/menu/menu-context.mjs +28 -0
  148. package/dist/menu/menu-context.mjs.map +1 -0
  149. package/dist/menu/menu-dom.mjs +37 -0
  150. package/dist/menu/menu-dom.mjs.map +1 -0
  151. package/dist/menu/menu-group.d.mts +48 -0
  152. package/dist/menu/menu-group.d.mts.map +1 -0
  153. package/dist/menu/menu-group.mjs +69 -0
  154. package/dist/menu/menu-group.mjs.map +1 -0
  155. package/dist/menu/menu-hover.mjs +29 -0
  156. package/dist/menu/menu-hover.mjs.map +1 -0
  157. package/dist/menu/menu-item.d.mts +45 -0
  158. package/dist/menu/menu-item.d.mts.map +1 -0
  159. package/dist/menu/menu-item.mjs +54 -0
  160. package/dist/menu/menu-item.mjs.map +1 -0
  161. package/dist/menu/menu-popup.d.mts +69 -0
  162. package/dist/menu/menu-popup.d.mts.map +1 -0
  163. package/dist/menu/menu-popup.mjs +207 -0
  164. package/dist/menu/menu-popup.mjs.map +1 -0
  165. package/dist/menu/menu-radio-group.d.mts +37 -0
  166. package/dist/menu/menu-radio-group.d.mts.map +1 -0
  167. package/dist/menu/menu-radio-group.mjs +72 -0
  168. package/dist/menu/menu-radio-group.mjs.map +1 -0
  169. package/dist/menu/menu-radio-item.d.mts +33 -0
  170. package/dist/menu/menu-radio-item.d.mts.map +1 -0
  171. package/dist/menu/menu-radio-item.mjs +62 -0
  172. package/dist/menu/menu-radio-item.mjs.map +1 -0
  173. package/dist/menu/menu-root.d.mts +54 -0
  174. package/dist/menu/menu-root.d.mts.map +1 -0
  175. package/dist/menu/menu-root.mjs +102 -0
  176. package/dist/menu/menu-root.mjs.map +1 -0
  177. package/dist/menu/menu-submenu-trigger.d.mts +31 -0
  178. package/dist/menu/menu-submenu-trigger.d.mts.map +1 -0
  179. package/dist/menu/menu-submenu-trigger.mjs +92 -0
  180. package/dist/menu/menu-submenu-trigger.mjs.map +1 -0
  181. package/dist/menu/menu-trigger.d.mts +36 -0
  182. package/dist/menu/menu-trigger.d.mts.map +1 -0
  183. package/dist/menu/menu-trigger.mjs +81 -0
  184. package/dist/menu/menu-trigger.mjs.map +1 -0
  185. package/dist/menu/use-menu-item.mjs +54 -0
  186. package/dist/menu/use-menu-item.mjs.map +1 -0
  187. package/dist/popover/index.d.mts +28 -0
  188. package/dist/popover/index.d.mts.map +1 -0
  189. package/dist/popover/index.mjs +28 -0
  190. package/dist/popover/index.mjs.map +1 -0
  191. package/dist/popover/popover-close.d.mts +41 -0
  192. package/dist/popover/popover-close.d.mts.map +1 -0
  193. package/dist/popover/popover-close.mjs +90 -0
  194. package/dist/popover/popover-close.mjs.map +1 -0
  195. package/dist/popover/popover-context.mjs +26 -0
  196. package/dist/popover/popover-context.mjs.map +1 -0
  197. package/dist/popover/popover-description.d.mts +22 -0
  198. package/dist/popover/popover-description.d.mts.map +1 -0
  199. package/dist/popover/popover-description.mjs +28 -0
  200. package/dist/popover/popover-description.mjs.map +1 -0
  201. package/dist/popover/popover-popup.d.mts +82 -0
  202. package/dist/popover/popover-popup.d.mts.map +1 -0
  203. package/dist/popover/popover-popup.mjs +93 -0
  204. package/dist/popover/popover-popup.mjs.map +1 -0
  205. package/dist/popover/popover-root.d.mts +64 -0
  206. package/dist/popover/popover-root.d.mts.map +1 -0
  207. package/dist/popover/popover-root.mjs +39 -0
  208. package/dist/popover/popover-root.mjs.map +1 -0
  209. package/dist/popover/popover-title.d.mts +23 -0
  210. package/dist/popover/popover-title.d.mts.map +1 -0
  211. package/dist/popover/popover-title.mjs +28 -0
  212. package/dist/popover/popover-title.mjs.map +1 -0
  213. package/dist/popover/popover-trigger.d.mts +37 -0
  214. package/dist/popover/popover-trigger.d.mts.map +1 -0
  215. package/dist/popover/popover-trigger.mjs +40 -0
  216. package/dist/popover/popover-trigger.mjs.map +1 -0
  217. package/dist/radio-group/index.d.mts +20 -0
  218. package/dist/radio-group/index.d.mts.map +1 -0
  219. package/dist/radio-group/index.mjs +20 -0
  220. package/dist/radio-group/index.mjs.map +1 -0
  221. package/dist/radio-group/radio-group-context.mjs +13 -0
  222. package/dist/radio-group/radio-group-context.mjs.map +1 -0
  223. package/dist/radio-group/radio-group-item.d.mts +54 -0
  224. package/dist/radio-group/radio-group-item.d.mts.map +1 -0
  225. package/dist/radio-group/radio-group-item.mjs +83 -0
  226. package/dist/radio-group/radio-group-item.mjs.map +1 -0
  227. package/dist/radio-group/radio-group-label.d.mts +21 -0
  228. package/dist/radio-group/radio-group-label.d.mts.map +1 -0
  229. package/dist/radio-group/radio-group-label.mjs +30 -0
  230. package/dist/radio-group/radio-group-label.mjs.map +1 -0
  231. package/dist/radio-group/radio-group-root.d.mts +92 -0
  232. package/dist/radio-group/radio-group-root.d.mts.map +1 -0
  233. package/dist/radio-group/radio-group-root.mjs +137 -0
  234. package/dist/radio-group/radio-group-root.mjs.map +1 -0
  235. package/dist/switch/index.d.mts +3 -0
  236. package/dist/switch/index.mjs +1 -0
  237. package/dist/switch/switch.d.mts +78 -0
  238. package/dist/switch/switch.d.mts.map +1 -0
  239. package/dist/switch/switch.mjs +77 -0
  240. package/dist/switch/switch.mjs.map +1 -0
  241. package/dist/tabs/index.d.mts +24 -0
  242. package/dist/tabs/index.d.mts.map +1 -0
  243. package/dist/tabs/index.mjs +23 -0
  244. package/dist/tabs/index.mjs.map +1 -0
  245. package/dist/tabs/tabs-context.d.mts +7 -0
  246. package/dist/tabs/tabs-context.d.mts.map +1 -0
  247. package/dist/tabs/tabs-context.mjs +14 -0
  248. package/dist/tabs/tabs-context.mjs.map +1 -0
  249. package/dist/tabs/tabs-ids.mjs +39 -0
  250. package/dist/tabs/tabs-ids.mjs.map +1 -0
  251. package/dist/tabs/tabs-indicator.d.mts +32 -0
  252. package/dist/tabs/tabs-indicator.d.mts.map +1 -0
  253. package/dist/tabs/tabs-indicator.mjs +49 -0
  254. package/dist/tabs/tabs-indicator.mjs.map +1 -0
  255. package/dist/tabs/tabs-list.d.mts +34 -0
  256. package/dist/tabs/tabs-list.d.mts.map +1 -0
  257. package/dist/tabs/tabs-list.mjs +130 -0
  258. package/dist/tabs/tabs-list.mjs.map +1 -0
  259. package/dist/tabs/tabs-panel.d.mts +50 -0
  260. package/dist/tabs/tabs-panel.d.mts.map +1 -0
  261. package/dist/tabs/tabs-panel.mjs +81 -0
  262. package/dist/tabs/tabs-panel.mjs.map +1 -0
  263. package/dist/tabs/tabs-root.d.mts +64 -0
  264. package/dist/tabs/tabs-root.d.mts.map +1 -0
  265. package/dist/tabs/tabs-root.mjs +90 -0
  266. package/dist/tabs/tabs-root.mjs.map +1 -0
  267. package/dist/tabs/tabs-tab.d.mts +49 -0
  268. package/dist/tabs/tabs-tab.d.mts.map +1 -0
  269. package/dist/tabs/tabs-tab.mjs +89 -0
  270. package/dist/tabs/tabs-tab.mjs.map +1 -0
  271. package/dist/toggle/index.d.mts +3 -0
  272. package/dist/toggle/index.mjs +1 -0
  273. package/dist/toggle/toggle.d.mts +57 -0
  274. package/dist/toggle/toggle.d.mts.map +1 -0
  275. package/dist/toggle/toggle.mjs +59 -0
  276. package/dist/toggle/toggle.mjs.map +1 -0
  277. package/dist/tooltip/index.d.mts +20 -0
  278. package/dist/tooltip/index.d.mts.map +1 -0
  279. package/dist/tooltip/index.mjs +19 -0
  280. package/dist/tooltip/index.mjs.map +1 -0
  281. package/dist/tooltip/tooltip-context.d.mts +5 -0
  282. package/dist/tooltip/tooltip-context.d.mts.map +1 -0
  283. package/dist/tooltip/tooltip-context.mjs +13 -0
  284. package/dist/tooltip/tooltip-context.mjs.map +1 -0
  285. package/dist/tooltip/tooltip-popup.d.mts +49 -0
  286. package/dist/tooltip/tooltip-popup.d.mts.map +1 -0
  287. package/dist/tooltip/tooltip-popup.mjs +52 -0
  288. package/dist/tooltip/tooltip-popup.mjs.map +1 -0
  289. package/dist/tooltip/tooltip-root.d.mts +41 -0
  290. package/dist/tooltip/tooltip-root.d.mts.map +1 -0
  291. package/dist/tooltip/tooltip-root.mjs +86 -0
  292. package/dist/tooltip/tooltip-root.mjs.map +1 -0
  293. package/dist/tooltip/tooltip-trigger.d.mts +38 -0
  294. package/dist/tooltip/tooltip-trigger.d.mts.map +1 -0
  295. package/dist/tooltip/tooltip-trigger.mjs +55 -0
  296. package/dist/tooltip/tooltip-trigger.mjs.map +1 -0
  297. package/dist/tooltip/use-tooltip-interaction.mjs +119 -0
  298. package/dist/tooltip/use-tooltip-interaction.mjs.map +1 -0
  299. package/package.json +73 -3
@@ -0,0 +1,21 @@
1
+ import { RenderProp, StateValue } from "../internal/types.mjs";
2
+ import { RadioGroupRootState } from "./radio-group-root.mjs";
3
+ import { CSSProperties, ComponentPropsWithRef, ReactNode } from "react";
4
+ //#region src/radio-group/radio-group-label.d.ts
5
+ export interface RadioGroupLabelProps extends Omit<ComponentPropsWithRef<"legend">, "className" | "style" | "children"> {
6
+ className?: StateValue<string | undefined, RadioGroupRootState>;
7
+ style?: StateValue<CSSProperties | undefined, RadioGroupRootState>;
8
+ /** Receives the Root's state: a group-level pending indicator goes here. */
9
+ children?: StateValue<ReactNode, RadioGroupRootState>;
10
+ render?: RenderProp<ComponentPropsWithRef<"legend">, RadioGroupRootState>;
11
+ }
12
+ /**
13
+ * The group's `<legend>`, which names the fieldset natively. Optional; must be the **first child**
14
+ * of `RadioGroup.Root` (HTML content model). Its state is the Root's state. Owns no keys.
15
+ */
16
+ export declare function RadioGroupLabel({ className, style, children, render, ...rest }: RadioGroupLabelProps): ReactNode;
17
+ export declare namespace RadioGroupLabel {
18
+ var displayName: string;
19
+ }
20
+ //#endregion
21
+ //# sourceMappingURL=radio-group-label.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"radio-group-label.d.mts","names":[],"sources":["../../src/radio-group/radio-group-label.tsx"],"mappings":";;;;iBAOiB,6BAA6B,KAC5C;EAGA,YAAY,+BAA+B;EAC3C,QAAQ,WAAW,2BAA2B;;EAE9C,WAAW,WAAW,WAAW;EACjC,SAAS,WAAW,iCAAiC;;;;;;wBAOvC,kBACd,WACA,OACA,UACA,WACG,QACF,uBAAoB;yBANP"}
@@ -0,0 +1,30 @@
1
+ "use client";
2
+ import { useRender } from "../internal/use-render.mjs";
3
+ import { useRadioGroupContext } from "./radio-group-context.mjs";
4
+ //#region src/radio-group/radio-group-label.tsx
5
+ /**
6
+ * The group's `<legend>`, which names the fieldset natively. Optional; must be the **first child**
7
+ * of `RadioGroup.Root` (HTML content model). Its state is the Root's state. Owns no keys.
8
+ */
9
+ function RadioGroupLabel({ className, style, children, render, ...rest }) {
10
+ const ctx = useRadioGroupContext("RadioGroup.Label");
11
+ const state = {
12
+ value: ctx.optimistic,
13
+ pending: ctx.pending,
14
+ disabled: ctx.disabled
15
+ };
16
+ return useRender({
17
+ defaultElement: "legend",
18
+ render,
19
+ state,
20
+ className,
21
+ style,
22
+ children,
23
+ props: rest
24
+ });
25
+ }
26
+ RadioGroupLabel.displayName = "RadioGroupLabel";
27
+ //#endregion
28
+ export { RadioGroupLabel };
29
+
30
+ //# sourceMappingURL=radio-group-label.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"radio-group-label.mjs","names":[],"sources":["../../src/radio-group/radio-group-label.tsx"],"sourcesContent":["\"use client\";\nimport type { ComponentPropsWithRef, CSSProperties, ReactNode } from \"react\";\nimport type { RenderProp, StateValue } from \"../internal/types.js\";\nimport { useRender } from \"../internal/use-render.js\";\nimport { useRadioGroupContext } from \"./radio-group-context.js\";\nimport type { RadioGroupRootState } from \"./radio-group-root.js\";\n\nexport interface RadioGroupLabelProps extends Omit<\n ComponentPropsWithRef<\"legend\">,\n \"className\" | \"style\" | \"children\"\n> {\n className?: StateValue<string | undefined, RadioGroupRootState>;\n style?: StateValue<CSSProperties | undefined, RadioGroupRootState>;\n /** Receives the Root's state: a group-level pending indicator goes here. */\n children?: StateValue<ReactNode, RadioGroupRootState>;\n render?: RenderProp<ComponentPropsWithRef<\"legend\">, RadioGroupRootState>;\n}\n\n/**\n * The group's `<legend>`, which names the fieldset natively. Optional; must be the **first child**\n * of `RadioGroup.Root` (HTML content model). Its state is the Root's state. Owns no keys.\n */\nexport function RadioGroupLabel({\n className,\n style,\n children,\n render,\n ...rest\n}: RadioGroupLabelProps) {\n const ctx = useRadioGroupContext(\"RadioGroup.Label\");\n const state: RadioGroupRootState = {\n value: ctx.optimistic,\n pending: ctx.pending,\n disabled: ctx.disabled,\n };\n return useRender<ComponentPropsWithRef<\"legend\">, RadioGroupRootState>({\n defaultElement: \"legend\",\n render,\n state,\n className,\n style,\n children,\n props: rest,\n });\n}\n\nRadioGroupLabel.displayName = \"RadioGroupLabel\";\n"],"mappings":";;;;;;;;AAsBA,SAAgB,gBAAgB,EAC9B,WACA,OACA,UACA,QACA,GAAG,QACoB;CACvB,MAAM,MAAM,qBAAqB,kBAAkB;CACnD,MAAM,QAA6B;EACjC,OAAO,IAAI;EACX,SAAS,IAAI;EACb,UAAU,IAAI;CAChB;CACA,OAAO,UAAgE;EACrE,gBAAgB;EAChB;EACA;EACA;EACA;EACA;EACA,OAAO;CACT,CAAC;AACH;AAEA,gBAAgB,cAAc"}
@@ -0,0 +1,92 @@
1
+ import { ActionDetails, ChangeAction, ChangeReason, RenderProp, StateValue } from "../internal/types.mjs";
2
+ import { CSSProperties, ComponentPropsWithRef, ReactNode } from "react";
3
+ //#region src/radio-group/radio-group-root.d.ts
4
+ /** Details passed as the second argument of `valueChangeAction`. */
5
+ export interface RadioGroupValueChangeDetails extends ActionDetails {
6
+ /**
7
+ * `"activate"`: the user checked a radio (click, Space, label click, or an arrow key, all of
8
+ * which arrive as a native `click`). `"platform"`: the browser changed the checked radio
9
+ * itself: a form reset (`details.event` is the `reset` event), or a click before hydration /
10
+ * Firefox form-state restoration found at mount (`details.event` is `undefined`).
11
+ */
12
+ readonly reason: ChangeReason;
13
+ }
14
+ export interface RadioGroupRootState {
15
+ /** Optimistic checked value, or `null`. Content rendered from it must not suspend. */
16
+ readonly value: string | null;
17
+ /** An action dispatched through this group is in flight. */
18
+ readonly pending: boolean;
19
+ /** The `disabled` prop. */
20
+ readonly disabled: boolean;
21
+ }
22
+ export interface RadioGroupRootProps extends Omit<ComponentPropsWithRef<"fieldset">, "className" | "style" | "children" | "defaultValue" | "defaultChecked" | "name" | "disabled" | "form"> {
23
+ /**
24
+ * Controlled checked value. `null` checks nothing; `undefined` means uncontrolled.
25
+ *
26
+ * A form reset returns each radio to the `checked` it had when *that radio* mounted (React sets
27
+ * `defaultChecked` once, from the initial `checked`). An Item added on the client while `value`
28
+ * equals its value therefore also gets `defaultChecked`, so two radios may carry it and the
29
+ * reset target is not necessarily the group's mount-time value. The reset is offered to
30
+ * `valueChangeAction` as usual; for a stable target remount the group with a `key` or use
31
+ * `defaultValue`, whose latest value every Item mirrors.
32
+ */
33
+ value?: string | null;
34
+ /**
35
+ * Initial value in uncontrolled mode. Defaults to `null` (nothing checked). Also the value a
36
+ * form reset returns to: the latest prop value is mirrored into the radios' `defaultChecked`.
37
+ */
38
+ defaultValue?: string | null;
39
+ /**
40
+ * Runs inside the Root's transition whenever the checked radio changes. May be sync or async
41
+ * (also a Server Function); rejections reach the nearest Error Boundary and roll the selection
42
+ * back.
43
+ *
44
+ * `next` is a string for every user interaction. It is `null` only with
45
+ * `details.reason === "platform"`, when a form reset returned the group to "nothing checked".
46
+ * Every arrow key press dispatches; the latest dispatch wins. A `setState` placed after your
47
+ * own `await` is not a Transition update; wrap it in `startTransition` (React limitation).
48
+ * `details.event.preventDefault()` is not a veto; use controlled mode to veto a change.
49
+ */
50
+ valueChangeAction?: ChangeAction<string | null, RadioGroupValueChangeDetails>;
51
+ /**
52
+ * The `name` shared by every radio in the group (form data key). Defaults to a `useId()` value;
53
+ * pass a real name when the group is inside a `<form>` you submit. Must be unique within the
54
+ * form: react-dom throws if a non-React radio shares it.
55
+ */
56
+ name?: string;
57
+ /** The `form` attribute, applied to the fieldset and to every radio. */
58
+ form?: string;
59
+ /**
60
+ * Marks every radio `required`, which makes the group required (one checked radio satisfies it),
61
+ * and renders `aria-required="true"` on the fieldset so the radiogroup itself is exposed as
62
+ * required.
63
+ */
64
+ required?: boolean;
65
+ /** Renders `<fieldset disabled>`: every radio is disabled, unfocusable and skipped by arrows. */
66
+ disabled?: boolean;
67
+ className?: StateValue<string | undefined, RadioGroupRootState>;
68
+ style?: StateValue<CSSProperties | undefined, RadioGroupRootState>;
69
+ children?: StateValue<ReactNode, RadioGroupRootState>;
70
+ /** Replace the rendered element. Must keep a `<fieldset>`. */
71
+ render?: RenderProp<ComponentPropsWithRef<"fieldset">, RadioGroupRootState>;
72
+ }
73
+ /**
74
+ * `<fieldset role="radiogroup">` that owns the group's state, the transition, the shared `name`,
75
+ * the form-reset listener and the mount reconciliation (design/components/radio-group.md 13.3).
76
+ * Carries `data-pending` while `valueChangeAction` is in flight.
77
+ *
78
+ * Owned keys (conventions 1.2): `role`, `aria-required`, `disabled`, `form`, `data-pending`,
79
+ * `data-disabled`.
80
+ *
81
+ * Keep every Item in the same Suspense boundary as its Root when server rendering. Partial
82
+ * hydration of a group (a boundary between Root and Items that stays dehydrated while the user
83
+ * interacts) is not supported by React: clicking a hydrated radio while same-`name` siblings are
84
+ * still dehydrated makes react-dom throw "Mixing React and non-React radio inputs with the same
85
+ * `name` is not supported". Development warns when Items hydrate after their Root.
86
+ */
87
+ export declare function RadioGroupRoot({ value, defaultValue, valueChangeAction, name: nameProp, form, required, disabled, className, style, children, render, ...rest }: RadioGroupRootProps): import("react").JSX.Element;
88
+ export declare namespace RadioGroupRoot {
89
+ var displayName: string;
90
+ }
91
+ //#endregion
92
+ //# sourceMappingURL=radio-group-root.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"radio-group-root.d.mts","names":[],"sources":["../../src/radio-group/radio-group-root.tsx"],"mappings":";;;;iBAsBiB,qCAAqC;;;;;;;WAO3C,QAAQ;;iBAGF;;WAEN;;WAEA;;WAEA;;iBAGM,4BAA4B,KAC3C;;;;;;;;;;;EAoBA;;;;;EAKA;;;;;;;;;;;;EAYA,oBAAoB,4BAA4B;;;;;;EAMhD;;EAEA;;;;;;EAMA;;EAEA;EACA,YAAY,+BAA+B;EAC3C,QAAQ,WAAW,2BAA2B;EAC9C,WAAW,WAAW,WAAW;;EAEjC,SAAS,WAAW,mCAAmC;;;;;;;;;;;;;;;;wBAkCzC,iBACd,OACA,cACA,mBACA,MAAM,UACN,MACA,UACA,UACA,WACA,OACA,UACA,WACG,QACF,sCAAmB,IAAA;yBAbN"}
@@ -0,0 +1,137 @@
1
+ "use client";
2
+ import { createActionDetails } from "../internal/action-details.mjs";
3
+ import { dataAttr } from "../internal/data-attr.mjs";
4
+ import { transitionTypes } from "../internal/transition-types.mjs";
5
+ import { useControllableAction } from "../internal/use-controllable-action.mjs";
6
+ import { useRender } from "../internal/use-render.mjs";
7
+ import { RadioGroupContext } from "./radio-group-context.mjs";
8
+ import { useNativeGroupReconciliation } from "../internal/use-native-group-reconciliation.mjs";
9
+ import { useCallback, useId, useLayoutEffect, useRef } from "react";
10
+ import { jsx } from "react/jsx-runtime";
11
+ //#region src/radio-group/radio-group-root.tsx
12
+ const isDev = process.env.NODE_ENV !== "production";
13
+ /**
14
+ * Value of the group's checked radio as the DOM shows it (`prop: "checked"`) or as a form reset
15
+ * leaves it (`prop: "defaultChecked"`), or `null`. Only radios of this group's `name` count, so a
16
+ * nested group is ignored.
17
+ */
18
+ function readGroup(fieldset, name, prop) {
19
+ if (fieldset === null) return null;
20
+ for (const radio of fieldset.querySelectorAll("input[type=\"radio\"]")) if (radio.name === name && radio[prop]) return radio.value;
21
+ return null;
22
+ }
23
+ /**
24
+ * `<fieldset role="radiogroup">` that owns the group's state, the transition, the shared `name`,
25
+ * the form-reset listener and the mount reconciliation (design/components/radio-group.md 13.3).
26
+ * Carries `data-pending` while `valueChangeAction` is in flight.
27
+ *
28
+ * Owned keys (conventions 1.2): `role`, `aria-required`, `disabled`, `form`, `data-pending`,
29
+ * `data-disabled`.
30
+ *
31
+ * Keep every Item in the same Suspense boundary as its Root when server rendering. Partial
32
+ * hydration of a group (a boundary between Root and Items that stays dehydrated while the user
33
+ * interacts) is not supported by React: clicking a hydrated radio while same-`name` siblings are
34
+ * still dehydrated makes react-dom throw "Mixing React and non-React radio inputs with the same
35
+ * `name` is not supported". Development warns when Items hydrate after their Root.
36
+ */
37
+ function RadioGroupRoot({ value, defaultValue, valueChangeAction, name: nameProp, form, required = false, disabled = false, className, style, children, render, ...rest }) {
38
+ const fallbackName = useId();
39
+ const name = nameProp ?? fallbackName;
40
+ const fieldsetRef = useRef(null);
41
+ const warnedElement = useRef(false);
42
+ const { optimistic, pending, dispatch, latestInFlight } = useControllableAction({
43
+ controlled: value,
44
+ defaultValue,
45
+ initialValue: null,
46
+ action: valueChangeAction,
47
+ transitionTypes: () => transitionTypes("radio-group"),
48
+ warn: {
49
+ component: "RadioGroup.Root",
50
+ prop: "value"
51
+ }
52
+ });
53
+ /** What the user intends: the latest in-flight dispatch, else optimistic (conventions 3.8 rule 1). */
54
+ const base = () => {
55
+ const inFlight = latestInFlight();
56
+ return inFlight === null ? optimistic : inFlight.next;
57
+ };
58
+ const { onItemMounted } = useNativeGroupReconciliation({
59
+ element: fieldsetRef,
60
+ readCurrent: () => readGroup(fieldsetRef.current, name, "checked"),
61
+ readDefault: () => readGroup(fieldsetRef.current, name, "defaultChecked"),
62
+ base,
63
+ onPlatformChange: (next, event) => dispatch(next, createActionDetails(event, { reason: "platform" }))
64
+ });
65
+ const serverRadios = useRef(null);
66
+ const warnedPartialHydration = useRef(false);
67
+ useLayoutEffect(() => {
68
+ if (!isDev) return;
69
+ const el = fieldsetRef.current;
70
+ serverRadios.current = new Set(el === null ? [] : el.querySelectorAll("input[type=\"radio\"]"));
71
+ return () => {
72
+ serverRadios.current = null;
73
+ };
74
+ }, []);
75
+ const onItemMountedWithCheck = useCallback((element) => {
76
+ if (isDev && !warnedPartialHydration.current && element != null && serverRadios.current?.has(element) === true) {
77
+ warnedPartialHydration.current = true;
78
+ console.error("RadioGroup.Item: an Item hydrated after its RadioGroup.Root (a Suspense boundary between them). Partial hydration of a radio group is not supported by React: clicking a hydrated radio while same-name radios are still dehydrated makes react-dom throw \"Mixing React and non-React radio inputs with the same name is not supported\". Keep every Item in the same Suspense boundary as its Root.");
79
+ }
80
+ onItemMounted(element);
81
+ }, [onItemMounted]);
82
+ const libraryRef = useCallback((el) => {
83
+ fieldsetRef.current = el;
84
+ if (isDev && !warnedElement.current && el.tagName !== "FIELDSET") {
85
+ warnedElement.current = true;
86
+ console.error(`RadioGroup.Root: expected to render a <fieldset> element but got <${el.tagName.toLowerCase()}>. The platform semantics (legend naming, disabled inheritance, form reset) need a real <fieldset>.`);
87
+ }
88
+ return () => {
89
+ fieldsetRef.current = null;
90
+ };
91
+ }, []);
92
+ const context = {
93
+ name,
94
+ form,
95
+ required,
96
+ optimistic,
97
+ pending,
98
+ disabled,
99
+ defaultValue: value === void 0 ? defaultValue ?? null : void 0,
100
+ onItemMounted: onItemMountedWithCheck,
101
+ select: (next, event) => {
102
+ if (next === optimistic) return;
103
+ dispatch(next, createActionDetails(event, { reason: "activate" }));
104
+ }
105
+ };
106
+ const element = useRender({
107
+ defaultElement: "fieldset",
108
+ render,
109
+ state: {
110
+ value: optimistic,
111
+ pending,
112
+ disabled
113
+ },
114
+ className,
115
+ style,
116
+ children,
117
+ props: rest,
118
+ libraryProps: {
119
+ role: "radiogroup",
120
+ "aria-required": required ? "true" : void 0,
121
+ disabled,
122
+ form,
123
+ "data-pending": dataAttr(pending),
124
+ "data-disabled": dataAttr(disabled)
125
+ },
126
+ ref: libraryRef
127
+ });
128
+ return /* @__PURE__ */ jsx(RadioGroupContext, {
129
+ value: context,
130
+ children: element
131
+ });
132
+ }
133
+ RadioGroupRoot.displayName = "RadioGroupRoot";
134
+ //#endregion
135
+ export { RadioGroupRoot };
136
+
137
+ //# sourceMappingURL=radio-group-root.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"radio-group-root.mjs","names":[],"sources":["../../src/radio-group/radio-group-root.tsx"],"sourcesContent":["\"use client\";\nimport { useCallback, useId, useLayoutEffect, useRef } from \"react\";\nimport type { ComponentPropsWithRef, CSSProperties, ReactNode } from \"react\";\nimport { createActionDetails } from \"../internal/action-details.js\";\nimport { dataAttr } from \"../internal/data-attr.js\";\nimport { transitionTypes } from \"../internal/transition-types.js\";\nimport type {\n ActionDetails,\n ChangeAction,\n ChangeReason,\n RenderProp,\n StateValue,\n} from \"../internal/types.js\";\nimport { useControllableAction } from \"../internal/use-controllable-action.js\";\nimport { useNativeGroupReconciliation } from \"../internal/use-native-group-reconciliation.js\";\nimport { useRender } from \"../internal/use-render.js\";\nimport { RadioGroupContext } from \"./radio-group-context.js\";\nimport type { RadioGroupContextValue } from \"./radio-group-context.js\";\n\nconst isDev = process.env.NODE_ENV !== \"production\";\n\n/** Details passed as the second argument of `valueChangeAction`. */\nexport interface RadioGroupValueChangeDetails extends ActionDetails {\n /**\n * `\"activate\"`: the user checked a radio (click, Space, label click, or an arrow key, all of\n * which arrive as a native `click`). `\"platform\"`: the browser changed the checked radio\n * itself: a form reset (`details.event` is the `reset` event), or a click before hydration /\n * Firefox form-state restoration found at mount (`details.event` is `undefined`).\n */\n readonly reason: ChangeReason;\n}\n\nexport interface RadioGroupRootState {\n /** Optimistic checked value, or `null`. Content rendered from it must not suspend. */\n readonly value: string | null;\n /** An action dispatched through this group is in flight. */\n readonly pending: boolean;\n /** The `disabled` prop. */\n readonly disabled: boolean;\n}\n\nexport interface RadioGroupRootProps extends Omit<\n ComponentPropsWithRef<\"fieldset\">,\n | \"className\"\n | \"style\"\n | \"children\"\n | \"defaultValue\"\n | \"defaultChecked\"\n | \"name\"\n | \"disabled\"\n | \"form\"\n> {\n /**\n * Controlled checked value. `null` checks nothing; `undefined` means uncontrolled.\n *\n * A form reset returns each radio to the `checked` it had when *that radio* mounted (React sets\n * `defaultChecked` once, from the initial `checked`). An Item added on the client while `value`\n * equals its value therefore also gets `defaultChecked`, so two radios may carry it and the\n * reset target is not necessarily the group's mount-time value. The reset is offered to\n * `valueChangeAction` as usual; for a stable target remount the group with a `key` or use\n * `defaultValue`, whose latest value every Item mirrors.\n */\n value?: string | null;\n /**\n * Initial value in uncontrolled mode. Defaults to `null` (nothing checked). Also the value a\n * form reset returns to: the latest prop value is mirrored into the radios' `defaultChecked`.\n */\n defaultValue?: string | null;\n /**\n * Runs inside the Root's transition whenever the checked radio changes. May be sync or async\n * (also a Server Function); rejections reach the nearest Error Boundary and roll the selection\n * back.\n *\n * `next` is a string for every user interaction. It is `null` only with\n * `details.reason === \"platform\"`, when a form reset returned the group to \"nothing checked\".\n * Every arrow key press dispatches; the latest dispatch wins. A `setState` placed after your\n * own `await` is not a Transition update; wrap it in `startTransition` (React limitation).\n * `details.event.preventDefault()` is not a veto; use controlled mode to veto a change.\n */\n valueChangeAction?: ChangeAction<string | null, RadioGroupValueChangeDetails>;\n /**\n * The `name` shared by every radio in the group (form data key). Defaults to a `useId()` value;\n * pass a real name when the group is inside a `<form>` you submit. Must be unique within the\n * form: react-dom throws if a non-React radio shares it.\n */\n name?: string;\n /** The `form` attribute, applied to the fieldset and to every radio. */\n form?: string;\n /**\n * Marks every radio `required`, which makes the group required (one checked radio satisfies it),\n * and renders `aria-required=\"true\"` on the fieldset so the radiogroup itself is exposed as\n * required.\n */\n required?: boolean;\n /** Renders `<fieldset disabled>`: every radio is disabled, unfocusable and skipped by arrows. */\n disabled?: boolean;\n className?: StateValue<string | undefined, RadioGroupRootState>;\n style?: StateValue<CSSProperties | undefined, RadioGroupRootState>;\n children?: StateValue<ReactNode, RadioGroupRootState>;\n /** Replace the rendered element. Must keep a `<fieldset>`. */\n render?: RenderProp<ComponentPropsWithRef<\"fieldset\">, RadioGroupRootState>;\n}\n\n/**\n * Value of the group's checked radio as the DOM shows it (`prop: \"checked\"`) or as a form reset\n * leaves it (`prop: \"defaultChecked\"`), or `null`. Only radios of this group's `name` count, so a\n * nested group is ignored.\n */\nfunction readGroup(\n fieldset: HTMLFieldSetElement | null,\n name: string,\n prop: \"checked\" | \"defaultChecked\",\n): string | null {\n if (fieldset === null) return null;\n for (const radio of fieldset.querySelectorAll<HTMLInputElement>('input[type=\"radio\"]')) {\n if (radio.name === name && radio[prop]) return radio.value;\n }\n return null;\n}\n\n/**\n * `<fieldset role=\"radiogroup\">` that owns the group's state, the transition, the shared `name`,\n * the form-reset listener and the mount reconciliation (design/components/radio-group.md 13.3).\n * Carries `data-pending` while `valueChangeAction` is in flight.\n *\n * Owned keys (conventions 1.2): `role`, `aria-required`, `disabled`, `form`, `data-pending`,\n * `data-disabled`.\n *\n * Keep every Item in the same Suspense boundary as its Root when server rendering. Partial\n * hydration of a group (a boundary between Root and Items that stays dehydrated while the user\n * interacts) is not supported by React: clicking a hydrated radio while same-`name` siblings are\n * still dehydrated makes react-dom throw \"Mixing React and non-React radio inputs with the same\n * `name` is not supported\". Development warns when Items hydrate after their Root.\n */\nexport function RadioGroupRoot({\n value,\n defaultValue,\n valueChangeAction,\n name: nameProp,\n form,\n required = false,\n disabled = false,\n className,\n style,\n children,\n render,\n ...rest\n}: RadioGroupRootProps) {\n const fallbackName = useId();\n const name = nameProp ?? fallbackName;\n const fieldsetRef = useRef<HTMLFieldSetElement | null>(null);\n const warnedElement = useRef(false);\n\n const { optimistic, pending, dispatch, latestInFlight } = useControllableAction<\n string | null,\n RadioGroupValueChangeDetails\n >({\n controlled: value,\n defaultValue,\n initialValue: null,\n action: valueChangeAction,\n transitionTypes: () => transitionTypes(\"radio-group\"),\n warn: { component: \"RadioGroup.Root\", prop: \"value\" },\n });\n // Deliberately no warning when neither `value` nor `defaultValue` is given: an unchecked group\n // is the HTML default (design decision 2).\n\n /** What the user intends: the latest in-flight dispatch, else optimistic (conventions 3.8 rule 1). */\n const base = (): string | null => {\n const inFlight = latestInFlight();\n // Not `?.next ?? optimistic`: an in-flight reset to `null` is a real intent.\n return inFlight === null ? optimistic : inFlight.next;\n };\n\n // The residual browser paths (design section 5): one dispatch per group, from here. Items that\n // mount after the Root report through `onItemMounted` so the group is reconciled again.\n const { onItemMounted } = useNativeGroupReconciliation<string | null>({\n element: fieldsetRef,\n readCurrent: () => readGroup(fieldsetRef.current, name, \"checked\"),\n readDefault: () => readGroup(fieldsetRef.current, name, \"defaultChecked\"),\n base,\n onPlatformChange: (next, event) =>\n dispatch(next, createActionDetails(event, { reason: \"platform\" })),\n });\n\n // Dev-only partial-hydration detection. The radios present in the fieldset when the Root\n // mounts are either mounted in the Root's commit or still dehydrated server HTML. An Item that\n // mounts later on one of those elements hydrated after the Root (an Item created on the client\n // gets a new element). Items of the Root's own commit run their mount effect before this one,\n // while the snapshot is still `null`; StrictMode's re-run finds it reset by the cleanup.\n const serverRadios = useRef<ReadonlySet<Element> | null>(null);\n const warnedPartialHydration = useRef(false);\n useLayoutEffect(() => {\n if (!isDev) return;\n const el = fieldsetRef.current;\n serverRadios.current = new Set(el === null ? [] : el.querySelectorAll('input[type=\"radio\"]'));\n return () => {\n serverRadios.current = null;\n };\n }, []);\n const onItemMountedWithCheck = useCallback(\n (element?: Element | null) => {\n if (\n isDev &&\n !warnedPartialHydration.current &&\n element != null &&\n serverRadios.current?.has(element) === true\n ) {\n warnedPartialHydration.current = true;\n console.error(\n `RadioGroup.Item: an Item hydrated after its RadioGroup.Root (a Suspense boundary ` +\n `between them). Partial hydration of a radio group is not supported by React: ` +\n `clicking a hydrated radio while same-name radios are still dehydrated makes ` +\n `react-dom throw \"Mixing React and non-React radio inputs with the same name is not ` +\n `supported\". Keep every Item in the same Suspense boundary as its Root.`,\n );\n }\n onItemMounted(element);\n },\n [onItemMounted],\n );\n\n const libraryRef = useCallback((el: HTMLFieldSetElement) => {\n fieldsetRef.current = el;\n if (isDev && !warnedElement.current && el.tagName !== \"FIELDSET\") {\n warnedElement.current = true;\n console.error(\n `RadioGroup.Root: expected to render a <fieldset> element but got ` +\n `<${el.tagName.toLowerCase()}>. The platform semantics (legend naming, disabled ` +\n `inheritance, form reset) need a real <fieldset>.`,\n );\n }\n return () => {\n fieldsetRef.current = null;\n };\n }, []);\n\n const context: RadioGroupContextValue = {\n name,\n form,\n required,\n optimistic,\n pending,\n disabled,\n defaultValue: value === undefined ? (defaultValue ?? null) : undefined,\n onItemMounted: onItemMountedWithCheck,\n select: (next, event) => {\n // No-op rule against the optimistic value (conventions 2.3 item 7, design 4.2).\n if (next === optimistic) return;\n dispatch(next, createActionDetails(event, { reason: \"activate\" }));\n },\n };\n\n const state: RadioGroupRootState = { value: optimistic, pending, disabled };\n\n const element = useRender<ComponentPropsWithRef<\"fieldset\">, RadioGroupRootState>({\n defaultElement: \"fieldset\",\n render,\n state,\n className,\n style,\n children,\n props: rest,\n libraryProps: {\n role: \"radiogroup\",\n \"aria-required\": required ? \"true\" : undefined,\n disabled,\n form,\n \"data-pending\": dataAttr(pending),\n \"data-disabled\": dataAttr(disabled),\n },\n ref: libraryRef,\n });\n\n return <RadioGroupContext value={context}>{element}</RadioGroupContext>;\n}\n\nRadioGroupRoot.displayName = \"RadioGroupRoot\";\n"],"mappings":";;;;;;;;;;;AAmBA,MAAM,QAAQ,QAAQ,IAAI,aAAa;;;;;;AAyFvC,SAAS,UACP,UACA,MACA,MACe;CACf,IAAI,aAAa,MAAM,OAAO;CAC9B,KAAK,MAAM,SAAS,SAAS,iBAAmC,uBAAqB,GACnF,IAAI,MAAM,SAAS,QAAQ,MAAM,OAAO,OAAO,MAAM;CAEvD,OAAO;AACT;;;;;;;;;;;;;;;AAgBA,SAAgB,eAAe,EAC7B,OACA,cACA,mBACA,MAAM,UACN,MACA,WAAW,OACX,WAAW,OACX,WACA,OACA,UACA,QACA,GAAG,QACmB;CACtB,MAAM,eAAe,MAAM;CAC3B,MAAM,OAAO,YAAY;CACzB,MAAM,cAAc,OAAmC,IAAI;CAC3D,MAAM,gBAAgB,OAAO,KAAK;CAElC,MAAM,EAAE,YAAY,SAAS,UAAU,mBAAmB,sBAGxD;EACA,YAAY;EACZ;EACA,cAAc;EACd,QAAQ;EACR,uBAAuB,gBAAgB,aAAa;EACpD,MAAM;GAAE,WAAW;GAAmB,MAAM;EAAQ;CACtD,CAAC;;CAKD,MAAM,aAA4B;EAChC,MAAM,WAAW,eAAe;EAEhC,OAAO,aAAa,OAAO,aAAa,SAAS;CACnD;CAIA,MAAM,EAAE,kBAAkB,6BAA4C;EACpE,SAAS;EACT,mBAAmB,UAAU,YAAY,SAAS,MAAM,SAAS;EACjE,mBAAmB,UAAU,YAAY,SAAS,MAAM,gBAAgB;EACxE;EACA,mBAAmB,MAAM,UACvB,SAAS,MAAM,oBAAoB,OAAO,EAAE,QAAQ,WAAW,CAAC,CAAC;CACrE,CAAC;CAOD,MAAM,eAAe,OAAoC,IAAI;CAC7D,MAAM,yBAAyB,OAAO,KAAK;CAC3C,sBAAsB;EACpB,IAAI,CAAC,OAAO;EACZ,MAAM,KAAK,YAAY;EACvB,aAAa,UAAU,IAAI,IAAI,OAAO,OAAO,CAAC,IAAI,GAAG,iBAAiB,uBAAqB,CAAC;EAC5F,aAAa;GACX,aAAa,UAAU;EACzB;CACF,GAAG,CAAC,CAAC;CACL,MAAM,yBAAyB,aAC5B,YAA6B;EAC5B,IACE,SACA,CAAC,uBAAuB,WACxB,WAAW,QACX,aAAa,SAAS,IAAI,OAAO,MAAM,MACvC;GACA,uBAAuB,UAAU;GACjC,QAAQ,MACN,uYAKF;EACF;EACA,cAAc,OAAO;CACvB,GACA,CAAC,aAAa,CAChB;CAEA,MAAM,aAAa,aAAa,OAA4B;EAC1D,YAAY,UAAU;EACtB,IAAI,SAAS,CAAC,cAAc,WAAW,GAAG,YAAY,YAAY;GAChE,cAAc,UAAU;GACxB,QAAQ,MACN,qEACM,GAAG,QAAQ,YAAY,EAAE,oGAEjC;EACF;EACA,aAAa;GACX,YAAY,UAAU;EACxB;CACF,GAAG,CAAC,CAAC;CAEL,MAAM,UAAkC;EACtC;EACA;EACA;EACA;EACA;EACA;EACA,cAAc,UAAU,KAAA,IAAa,gBAAgB,OAAQ,KAAA;EAC7D,eAAe;EACf,SAAS,MAAM,UAAU;GAEvB,IAAI,SAAS,YAAY;GACzB,SAAS,MAAM,oBAAoB,OAAO,EAAE,QAAQ,WAAW,CAAC,CAAC;EACnE;CACF;CAIA,MAAM,UAAU,UAAkE;EAChF,gBAAgB;EAChB;EACA,OAAA;GALmC,OAAO;GAAY;GAAS;EAK3D;EACJ;EACA;EACA;EACA,OAAO;EACP,cAAc;GACZ,MAAM;GACN,iBAAiB,WAAW,SAAS,KAAA;GACrC;GACA;GACA,gBAAgB,SAAS,OAAO;GAChC,iBAAiB,SAAS,QAAQ;EACpC;EACA,KAAK;CACP,CAAC;CAED,OAAO,oBAAC,mBAAD;EAAmB,OAAO;EAAU,UAAA;CAA2B,CAAA;AACxE;AAEA,eAAe,cAAc"}
@@ -0,0 +1,3 @@
1
+ import "../internal/platform-attributes.mjs";
2
+ import { Switch, SwitchCheckedChangeDetails, SwitchProps, SwitchState } from "./switch.mjs";
3
+ export { Switch, type SwitchCheckedChangeDetails, type SwitchProps, type SwitchState };
@@ -0,0 +1 @@
1
+ export { Switch } from "./switch.mjs";
@@ -0,0 +1,78 @@
1
+ import { ActionDetails, ChangeAction, ChangeReason, RenderProp, StateValue } from "../internal/types.mjs";
2
+ import { CSSProperties, ComponentPropsWithRef, ViewTransitionClass } from "react";
3
+ //#region src/switch/switch.d.ts
4
+ export interface SwitchState {
5
+ /** Optimistic checked state: what the user sees, including an in-flight change. */
6
+ readonly checked: boolean;
7
+ /** An action dispatched by this Switch is in flight (including the resulting render). */
8
+ readonly pending: boolean;
9
+ /** The `disabled` prop. */
10
+ readonly disabled: boolean;
11
+ }
12
+ /** Details passed as the second argument of `checkedChangeAction`. */
13
+ export interface SwitchCheckedChangeDetails extends ActionDetails {
14
+ /**
15
+ * `"activate"`: the user toggled the switch (click, Space, label click); `event` is the native
16
+ * `click` event. `"platform"`: the browser changed the value itself: a form reset (`event` is
17
+ * the `reset` event) or a click before hydration / Firefox form-state restoration found on
18
+ * mount (`event` is `undefined`).
19
+ */
20
+ readonly reason: ChangeReason;
21
+ }
22
+ export interface SwitchProps extends Omit<ComponentPropsWithRef<"input">, "type" | "role" | "checked" | "defaultChecked" | "onChange" | "aria-checked" | "className" | "style" | "children"> {
23
+ /** Controlled checked state. `undefined` means uncontrolled. */
24
+ checked?: boolean;
25
+ /**
26
+ * Initial checked state in uncontrolled mode (default `false`). Also the value a form reset
27
+ * returns to: the latest prop value is mirrored into the input's `defaultChecked`.
28
+ */
29
+ defaultChecked?: boolean;
30
+ /**
31
+ * Called with the next checked state on every change. Runs inside the Switch's transition; may
32
+ * be sync or async (also a Server Function). Rejections reach the nearest Error Boundary.
33
+ * Also called with `details.reason === "platform"` for a form reset or a pre-hydration click.
34
+ *
35
+ * A `setState` placed after your own `await` is not a Transition update; wrap it in
36
+ * `startTransition` (React limitation). `details.event.preventDefault()` is not a veto and is
37
+ * unsupported here; use controlled mode to veto a change.
38
+ */
39
+ checkedChangeAction?: ChangeAction<boolean, SwitchCheckedChangeDetails>;
40
+ /** Renders a natively disabled input; never dispatches. Default `false`. */
41
+ disabled?: boolean;
42
+ /** Submitted as the input's value when checked. Default `"on"` (platform). */
43
+ value?: string;
44
+ /**
45
+ * Forwarded as `default` to the Switch's `<ViewTransition>`. Default: no boundary. Animates the
46
+ * commit that ends an action, not the optimistic flip; animate the flip with CSS on `:checked`.
47
+ *
48
+ * Static: without `transition` the part renders no `<ViewTransition>`; changing it between
49
+ * `undefined` and a value remounts the element. Any value, `"none"` included, makes a mount or
50
+ * `<Activity>` reveal of this part inside a transition start a document view transition: the
51
+ * page cross-fades for about 250 ms and the next transition commit waits for it (issue #35).
52
+ */
53
+ transition?: ViewTransitionClass;
54
+ className?: StateValue<string | undefined, SwitchState>;
55
+ style?: StateValue<CSSProperties | undefined, SwitchState>;
56
+ /**
57
+ * Replace the rendered element (element form) or take over rendering (function form). Must keep
58
+ * an `<input type="checkbox">`.
59
+ */
60
+ render?: RenderProp<ComponentPropsWithRef<"input">, SwitchState>;
61
+ }
62
+ /**
63
+ * An on/off switch (WAI-ARIA "Switch" pattern, HTML checkbox input variant). Renders
64
+ * `<input type="checkbox" role="switch">` whose DOM `checked` is the optimistic state; the input
65
+ * carries `data-pending` while `checkedChangeAction` is in flight and takes part in forms natively.
66
+ *
67
+ * Owned keys (a `render` element's value is overridden): `type`, `role`, `checked`,
68
+ * `defaultChecked`, `aria-checked` (always removed), `disabled`, `data-checked`, `data-pending`,
69
+ * `data-disabled`. Event handlers are merged rather than owned: a `render` element's own
70
+ * `onChange` (or `onClick`) runs first, then the library's; an `onClick` that calls
71
+ * `preventDefault()` cancels the change (nothing is dispatched).
72
+ */
73
+ export declare function Switch({ checked, defaultChecked, checkedChangeAction, disabled, transition, className, style, render, ...rest }: SwitchProps): import("react").ReactNode;
74
+ export declare namespace Switch {
75
+ var displayName: string;
76
+ }
77
+ //#endregion
78
+ //# sourceMappingURL=switch.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"switch.d.mts","names":[],"sources":["../../src/switch/switch.tsx"],"mappings":";;;iBAiBiB;;WAEN;;WAEA;;WAEA;;;iBAIM,mCAAmC;;;;;;;WAOzC,QAAQ;;iBAGF,oBAAoB,KACnC;;EAYA;;;;;EAKA;;;;;;;;;;EAUA,sBAAsB,sBAAsB;;EAE5C;;EAEA;;;;;;;;;;EAUA,aAAa;EACb,YAAY,+BAA+B;EAC3C,QAAQ,WAAW,2BAA2B;;;;;EAK9C,SAAS,WAAW,gCAAgC;;;;;;;;;;;;;wBActC,SACd,SACA,gBACA,qBACA,UACA,YACA,WACA,OACA,WACG,QACF,8BAAW;yBAVE"}
@@ -0,0 +1,77 @@
1
+ "use client";
2
+ import { useTransitionBoundary } from "../internal/transition-boundary.mjs";
3
+ import { createActionDetails } from "../internal/action-details.mjs";
4
+ import { dataAttr } from "../internal/data-attr.mjs";
5
+ import { transitionTypes } from "../internal/transition-types.mjs";
6
+ import { useControllableAction } from "../internal/use-controllable-action.mjs";
7
+ import { useRender } from "../internal/use-render.mjs";
8
+ import { guardCheckableChange, useNativeChecked } from "../internal/use-native-checked.mjs";
9
+ //#region src/switch/switch.tsx
10
+ /**
11
+ * An on/off switch (WAI-ARIA "Switch" pattern, HTML checkbox input variant). Renders
12
+ * `<input type="checkbox" role="switch">` whose DOM `checked` is the optimistic state; the input
13
+ * carries `data-pending` while `checkedChangeAction` is in flight and takes part in forms natively.
14
+ *
15
+ * Owned keys (a `render` element's value is overridden): `type`, `role`, `checked`,
16
+ * `defaultChecked`, `aria-checked` (always removed), `disabled`, `data-checked`, `data-pending`,
17
+ * `data-disabled`. Event handlers are merged rather than owned: a `render` element's own
18
+ * `onChange` (or `onClick`) runs first, then the library's; an `onClick` that calls
19
+ * `preventDefault()` cancels the change (nothing is dispatched).
20
+ */
21
+ function Switch({ checked, defaultChecked, checkedChangeAction, disabled = false, transition, className, style, render, ...rest }) {
22
+ const { optimistic, pending, dispatch, latestInFlight } = useControllableAction({
23
+ controlled: checked,
24
+ defaultValue: defaultChecked,
25
+ initialValue: false,
26
+ action: checkedChangeAction,
27
+ transitionTypes: (next) => transitionTypes("switch", next ? "on" : "off"),
28
+ warn: {
29
+ component: "Switch",
30
+ prop: "checked"
31
+ }
32
+ });
33
+ const inputRef = useNativeChecked({
34
+ type: "checkbox",
35
+ component: "Switch",
36
+ checked: optimistic,
37
+ defaultChecked: checked === void 0 ? defaultChecked ?? false : void 0,
38
+ latestInFlight,
39
+ onPlatformChange: (next, event) => dispatch(next, createActionDetails(event, { reason: "platform" }))
40
+ });
41
+ const element = useRender({
42
+ defaultElement: "input",
43
+ render,
44
+ state: {
45
+ checked: optimistic,
46
+ pending,
47
+ disabled
48
+ },
49
+ className,
50
+ style,
51
+ children: void 0,
52
+ ref: inputRef,
53
+ props: rest,
54
+ libraryProps: {
55
+ type: "checkbox",
56
+ role: "switch",
57
+ checked: optimistic,
58
+ defaultChecked: void 0,
59
+ "aria-checked": void 0,
60
+ disabled,
61
+ "data-checked": dataAttr(optimistic),
62
+ "data-pending": dataAttr(pending),
63
+ "data-disabled": dataAttr(disabled),
64
+ onChange: (event) => {
65
+ if (disabled) return;
66
+ const nativeEvent = event.nativeEvent;
67
+ guardCheckableChange(nativeEvent, () => dispatch(!optimistic, createActionDetails(nativeEvent, { reason: "activate" })), "Switch");
68
+ }
69
+ }
70
+ });
71
+ return useTransitionBoundary("Switch", transition, element);
72
+ }
73
+ Switch.displayName = "Switch";
74
+ //#endregion
75
+ export { Switch };
76
+
77
+ //# sourceMappingURL=switch.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"switch.mjs","names":[],"sources":["../../src/switch/switch.tsx"],"sourcesContent":["\"use client\";\nimport type { ChangeEvent, ComponentPropsWithRef, CSSProperties, ViewTransitionClass } from \"react\";\nimport { useTransitionBoundary } from \"../internal/transition-boundary.js\";\nimport { createActionDetails } from \"../internal/action-details.js\";\nimport { dataAttr } from \"../internal/data-attr.js\";\nimport { transitionTypes } from \"../internal/transition-types.js\";\nimport type {\n ActionDetails,\n ChangeAction,\n ChangeReason,\n RenderProp,\n StateValue,\n} from \"../internal/types.js\";\nimport { useControllableAction } from \"../internal/use-controllable-action.js\";\nimport { guardCheckableChange, useNativeChecked } from \"../internal/use-native-checked.js\";\nimport { useRender } from \"../internal/use-render.js\";\n\nexport interface SwitchState {\n /** Optimistic checked state: what the user sees, including an in-flight change. */\n readonly checked: boolean;\n /** An action dispatched by this Switch is in flight (including the resulting render). */\n readonly pending: boolean;\n /** The `disabled` prop. */\n readonly disabled: boolean;\n}\n\n/** Details passed as the second argument of `checkedChangeAction`. */\nexport interface SwitchCheckedChangeDetails extends ActionDetails {\n /**\n * `\"activate\"`: the user toggled the switch (click, Space, label click); `event` is the native\n * `click` event. `\"platform\"`: the browser changed the value itself: a form reset (`event` is\n * the `reset` event) or a click before hydration / Firefox form-state restoration found on\n * mount (`event` is `undefined`).\n */\n readonly reason: ChangeReason;\n}\n\nexport interface SwitchProps extends Omit<\n ComponentPropsWithRef<\"input\">,\n | \"type\"\n | \"role\"\n | \"checked\"\n | \"defaultChecked\"\n | \"onChange\"\n | \"aria-checked\"\n | \"className\"\n | \"style\"\n | \"children\"\n> {\n /** Controlled checked state. `undefined` means uncontrolled. */\n checked?: boolean;\n /**\n * Initial checked state in uncontrolled mode (default `false`). Also the value a form reset\n * returns to: the latest prop value is mirrored into the input's `defaultChecked`.\n */\n defaultChecked?: boolean;\n /**\n * Called with the next checked state on every change. Runs inside the Switch's transition; may\n * be sync or async (also a Server Function). Rejections reach the nearest Error Boundary.\n * Also called with `details.reason === \"platform\"` for a form reset or a pre-hydration click.\n *\n * A `setState` placed after your own `await` is not a Transition update; wrap it in\n * `startTransition` (React limitation). `details.event.preventDefault()` is not a veto and is\n * unsupported here; use controlled mode to veto a change.\n */\n checkedChangeAction?: ChangeAction<boolean, SwitchCheckedChangeDetails>;\n /** Renders a natively disabled input; never dispatches. Default `false`. */\n disabled?: boolean;\n /** Submitted as the input's value when checked. Default `\"on\"` (platform). */\n value?: string;\n /**\n * Forwarded as `default` to the Switch's `<ViewTransition>`. Default: no boundary. Animates the\n * commit that ends an action, not the optimistic flip; animate the flip with CSS on `:checked`.\n *\n * Static: without `transition` the part renders no `<ViewTransition>`; changing it between\n * `undefined` and a value remounts the element. Any value, `\"none\"` included, makes a mount or\n * `<Activity>` reveal of this part inside a transition start a document view transition: the\n * page cross-fades for about 250 ms and the next transition commit waits for it (issue #35).\n */\n transition?: ViewTransitionClass;\n className?: StateValue<string | undefined, SwitchState>;\n style?: StateValue<CSSProperties | undefined, SwitchState>;\n /**\n * Replace the rendered element (element form) or take over rendering (function form). Must keep\n * an `<input type=\"checkbox\">`.\n */\n render?: RenderProp<ComponentPropsWithRef<\"input\">, SwitchState>;\n}\n\n/**\n * An on/off switch (WAI-ARIA \"Switch\" pattern, HTML checkbox input variant). Renders\n * `<input type=\"checkbox\" role=\"switch\">` whose DOM `checked` is the optimistic state; the input\n * carries `data-pending` while `checkedChangeAction` is in flight and takes part in forms natively.\n *\n * Owned keys (a `render` element's value is overridden): `type`, `role`, `checked`,\n * `defaultChecked`, `aria-checked` (always removed), `disabled`, `data-checked`, `data-pending`,\n * `data-disabled`. Event handlers are merged rather than owned: a `render` element's own\n * `onChange` (or `onClick`) runs first, then the library's; an `onClick` that calls\n * `preventDefault()` cancels the change (nothing is dispatched).\n */\nexport function Switch({\n checked,\n defaultChecked,\n checkedChangeAction,\n disabled = false,\n transition,\n className,\n style,\n render,\n ...rest\n}: SwitchProps) {\n const { optimistic, pending, dispatch, latestInFlight } = useControllableAction<\n boolean,\n SwitchCheckedChangeDetails\n >({\n controlled: checked,\n defaultValue: defaultChecked,\n initialValue: false,\n action: checkedChangeAction,\n transitionTypes: (next) => transitionTypes(\"switch\", next ? \"on\" : \"off\"),\n warn: { component: \"Switch\", prop: \"checked\" },\n });\n\n const inputRef = useNativeChecked({\n type: \"checkbox\",\n component: \"Switch\",\n checked: optimistic,\n // Uncontrolled: the latest prop is the reset target. Controlled: React's mount-time value.\n defaultChecked: checked === undefined ? (defaultChecked ?? false) : undefined,\n latestInFlight,\n onPlatformChange: (next, event) =>\n dispatch(next, createActionDetails(event, { reason: \"platform\" })),\n });\n\n const state: SwitchState = { checked: optimistic, pending, disabled };\n\n const element = useRender<ComponentPropsWithRef<\"input\">, SwitchState>({\n defaultElement: \"input\",\n render,\n state,\n className,\n style,\n children: undefined,\n ref: inputRef,\n // Pass-through layer: a `render` element's own props win over these.\n props: rest,\n // Library-controlled layer (owned keys, conventions 1.2).\n libraryProps: {\n type: \"checkbox\",\n role: \"switch\",\n // The DOM state is the optimistic state (conventions 3.2): react-dom restores a controlled\n // input to its props after every event, and only the sync-lane optimistic value survives.\n checked: optimistic,\n defaultChecked: undefined,\n \"aria-checked\": undefined,\n // Owned so that native disabledness, `data-disabled` and the click guard always agree: a\n // `render` element cannot re-enable (`disabled={false}`) or disable the input on its own.\n disabled,\n \"data-checked\": dataAttr(optimistic),\n \"data-pending\": dataAttr(pending),\n \"data-disabled\": dataAttr(disabled),\n onChange: (event: ChangeEvent<HTMLInputElement>) => {\n // A natively disabled input fires no click; this covers `render` elements that do not\n // honour `disabled`.\n if (disabled) return;\n const nativeEvent = event.nativeEvent;\n guardCheckableChange(\n nativeEvent,\n () => dispatch(!optimistic, createActionDetails(nativeEvent, { reason: \"activate\" })),\n \"Switch\",\n );\n },\n },\n });\n\n return useTransitionBoundary(\"Switch\", transition, element);\n}\n\nSwitch.displayName = \"Switch\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAoGA,SAAgB,OAAO,EACrB,SACA,gBACA,qBACA,WAAW,OACX,YACA,WACA,OACA,QACA,GAAG,QACW;CACd,MAAM,EAAE,YAAY,SAAS,UAAU,mBAAmB,sBAGxD;EACA,YAAY;EACZ,cAAc;EACd,cAAc;EACd,QAAQ;EACR,kBAAkB,SAAS,gBAAgB,UAAU,OAAO,OAAO,KAAK;EACxE,MAAM;GAAE,WAAW;GAAU,MAAM;EAAU;CAC/C,CAAC;CAED,MAAM,WAAW,iBAAiB;EAChC,MAAM;EACN,WAAW;EACX,SAAS;EAET,gBAAgB,YAAY,KAAA,IAAa,kBAAkB,QAAS,KAAA;EACpE;EACA,mBAAmB,MAAM,UACvB,SAAS,MAAM,oBAAoB,OAAO,EAAE,QAAQ,WAAW,CAAC,CAAC;CACrE,CAAC;CAID,MAAM,UAAU,UAAuD;EACrE,gBAAgB;EAChB;EACA,OAAA;GAL2B,SAAS;GAAY;GAAS;EAKrD;EACJ;EACA;EACA,UAAU,KAAA;EACV,KAAK;EAEL,OAAO;EAEP,cAAc;GACZ,MAAM;GACN,MAAM;GAGN,SAAS;GACT,gBAAgB,KAAA;GAChB,gBAAgB,KAAA;GAGhB;GACA,gBAAgB,SAAS,UAAU;GACnC,gBAAgB,SAAS,OAAO;GAChC,iBAAiB,SAAS,QAAQ;GAClC,WAAW,UAAyC;IAGlD,IAAI,UAAU;IACd,MAAM,cAAc,MAAM;IAC1B,qBACE,mBACM,SAAS,CAAC,YAAY,oBAAoB,aAAa,EAAE,QAAQ,WAAW,CAAC,CAAC,GACpF,QACF;GACF;EACF;CACF,CAAC;CAED,OAAO,sBAAsB,UAAU,YAAY,OAAO;AAC5D;AAEA,OAAO,cAAc"}
@@ -0,0 +1,24 @@
1
+ import "../internal/platform-attributes.mjs";
2
+ import { TabsActivationMode, TabsOrientation } from "./tabs-context.mjs";
3
+ import { TabsIndicator, TabsIndicatorProps, TabsIndicatorState } from "./tabs-indicator.mjs";
4
+ import { TabsList, TabsListProps, TabsListState } from "./tabs-list.mjs";
5
+ import { TabsPanel, TabsPanelProps, TabsPanelState } from "./tabs-panel.mjs";
6
+ import { TabsRoot, TabsRootProps, TabsRootState, TabsValueChangeDetails } from "./tabs-root.mjs";
7
+ import { TabsTab, TabsTabProps, TabsTabState } from "./tabs-tab.mjs";
8
+ //#region src/tabs/index.d.ts
9
+ /**
10
+ * Tabs (WAI-ARIA APG Tabs pattern): `Root` (div) > `List` (tablist) > `Tab` (button) and an
11
+ * optional `Indicator` (span), plus one `Panel` (tabpanel) per tab. Tabs and the Indicator render
12
+ * the optimistic selection; Panels render the committed one, so a suspending panel keeps the
13
+ * current panel on screen while the Root and the selected Tab show `data-pending`.
14
+ */
15
+ export declare const Tabs: {
16
+ readonly Root: typeof TabsRoot;
17
+ readonly List: typeof TabsList;
18
+ readonly Tab: typeof TabsTab;
19
+ readonly Panel: typeof TabsPanel;
20
+ readonly Indicator: typeof TabsIndicator;
21
+ };
22
+ //#endregion
23
+ export type { TabsActivationMode, TabsIndicatorProps, TabsIndicatorState, TabsListProps, TabsListState, TabsOrientation, TabsPanelProps, TabsPanelState, TabsRootProps, TabsRootState, TabsTabProps, TabsTabState, TabsValueChangeDetails };
24
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/tabs/index.ts"],"mappings":";;;;;;;;;;;;;;qBAea;WACX,aAAI;WACJ,aAAI;WACJ,YAAG;WACH,cAAK;WACL,kBAAS"}
@@ -0,0 +1,23 @@
1
+ import { TabsIndicator } from "./tabs-indicator.mjs";
2
+ import { TabsList } from "./tabs-list.mjs";
3
+ import { TabsPanel } from "./tabs-panel.mjs";
4
+ import { TabsRoot } from "./tabs-root.mjs";
5
+ import { TabsTab } from "./tabs-tab.mjs";
6
+ //#region src/tabs/index.ts
7
+ /**
8
+ * Tabs (WAI-ARIA APG Tabs pattern): `Root` (div) > `List` (tablist) > `Tab` (button) and an
9
+ * optional `Indicator` (span), plus one `Panel` (tabpanel) per tab. Tabs and the Indicator render
10
+ * the optimistic selection; Panels render the committed one, so a suspending panel keeps the
11
+ * current panel on screen while the Root and the selected Tab show `data-pending`.
12
+ */
13
+ const Tabs = {
14
+ Root: TabsRoot,
15
+ List: TabsList,
16
+ Tab: TabsTab,
17
+ Panel: TabsPanel,
18
+ Indicator: TabsIndicator
19
+ };
20
+ //#endregion
21
+ export { Tabs };
22
+
23
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/tabs/index.ts"],"sourcesContent":["// Ships the platform attribute typings with this subpath (conventions 7.4). Type-only: the\n// built JS has no import of it.\nimport \"../internal/platform-attributes.js\";\nimport { TabsIndicator } from \"./tabs-indicator.js\";\nimport { TabsList } from \"./tabs-list.js\";\nimport { TabsPanel } from \"./tabs-panel.js\";\nimport { TabsRoot } from \"./tabs-root.js\";\nimport { TabsTab } from \"./tabs-tab.js\";\n\n/**\n * Tabs (WAI-ARIA APG Tabs pattern): `Root` (div) > `List` (tablist) > `Tab` (button) and an\n * optional `Indicator` (span), plus one `Panel` (tabpanel) per tab. Tabs and the Indicator render\n * the optimistic selection; Panels render the committed one, so a suspending panel keeps the\n * current panel on screen while the Root and the selected Tab show `data-pending`.\n */\nexport const Tabs = {\n Root: TabsRoot,\n List: TabsList,\n Tab: TabsTab,\n Panel: TabsPanel,\n Indicator: TabsIndicator,\n} as const;\n\nexport type {\n TabsRootProps,\n TabsRootState,\n TabsValueChangeDetails,\n TabsOrientation,\n TabsActivationMode,\n} from \"./tabs-root.js\";\nexport type { TabsListProps, TabsListState } from \"./tabs-list.js\";\nexport type { TabsTabProps, TabsTabState } from \"./tabs-tab.js\";\nexport type { TabsPanelProps, TabsPanelState } from \"./tabs-panel.js\";\nexport type { TabsIndicatorProps, TabsIndicatorState } from \"./tabs-indicator.js\";\n"],"mappings":";;;;;;;;;;;;AAeA,MAAa,OAAO;CAClB,MAAM;CACN,MAAM;CACN,KAAK;CACL,OAAO;CACP,WAAW;AACb"}
@@ -0,0 +1,7 @@
1
+ //#region src/tabs/tabs-context.d.ts
2
+ export type TabsOrientation = "horizontal" | "vertical";
3
+ export type TabsActivationMode = "automatic" | "manual";
4
+ /** Why a Tabs change was dispatched (design section 3.1). */
5
+ export type TabsChangeReason = "activate" | "platform";
6
+ //#endregion
7
+ //# sourceMappingURL=tabs-context.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tabs-context.d.mts","names":[],"sources":["../../src/tabs/tabs-context.ts"],"mappings":";YAGY;YACA;;YAGA"}
@@ -0,0 +1,14 @@
1
+ "use client";
2
+ import { createContext, use } from "react";
3
+ //#region src/tabs/tabs-context.ts
4
+ const TabsContext = createContext(null);
5
+ const TabsListContext = createContext(null);
6
+ function useTabsContext(part) {
7
+ const context = use(TabsContext);
8
+ if (context === null) throw new Error(`${part} must be rendered inside a Tabs.Root.`);
9
+ return context;
10
+ }
11
+ //#endregion
12
+ export { TabsContext, TabsListContext, useTabsContext };
13
+
14
+ //# sourceMappingURL=tabs-context.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tabs-context.mjs","names":[],"sources":["../../src/tabs/tabs-context.ts"],"sourcesContent":["\"use client\";\nimport { createContext, use } from \"react\";\n\nexport type TabsOrientation = \"horizontal\" | \"vertical\";\nexport type TabsActivationMode = \"automatic\" | \"manual\";\n\n/** Why a Tabs change was dispatched (design section 3.1). */\nexport type TabsChangeReason = \"activate\" | \"platform\";\n\nexport interface TabsContextValue {\n readonly rootId: string;\n /** Committed value: Panels render this. */\n readonly committed: string | null;\n /** Optimistic value: Tabs and the Indicator render this. */\n readonly optimistic: string | null;\n readonly pending: boolean;\n readonly orientation: TabsOrientation;\n readonly activationMode: TabsActivationMode;\n readonly loop: boolean;\n readonly disabled: boolean;\n /** Dispatches a change. No-op if `value` is the optimistic value. Never checks `disabled`. */\n readonly select: (value: string, event: Event | undefined, reason: TabsChangeReason) => void;\n}\n\nexport const TabsContext = createContext<TabsContextValue | null>(null);\n\n/** What a Tabs.List tells its Tabs about `experimental_focusgroup`. */\nexport interface TabsListContextValue {\n /** `experimental_focusgroup` is on: the selected Tab carries `focusgroupstart`. */\n readonly focusgroup: boolean;\n /**\n * The flag is on and the engine implements `focusgroup` (detected in an effect, so false during\n * SSR and hydration). Unselected Tabs then drop `tabindex=\"-1\"`: Chromium leaves an element with\n * a negative tabindex out of the focusgroup, so roving tabindex would disable the native arrows.\n */\n readonly nativeFocusgroup: boolean;\n}\n\nexport const TabsListContext = createContext<TabsListContextValue | null>(null);\n\nexport function useTabsContext(part: string): TabsContextValue {\n const context = use(TabsContext);\n if (context === null) {\n throw new Error(`${part} must be rendered inside a Tabs.Root.`);\n }\n return context;\n}\n"],"mappings":";;;AAwBA,MAAa,cAAc,cAAuC,IAAI;AActE,MAAa,kBAAkB,cAA2C,IAAI;AAE9E,SAAgB,eAAe,MAAgC;CAC7D,MAAM,UAAU,IAAI,WAAW;CAC/B,IAAI,YAAY,MACd,MAAM,IAAI,MAAM,GAAG,KAAK,sCAAsC;CAEhE,OAAO;AACT"}