@funstack/ui 0.1.0-alpha.1 → 0.1.0-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (288) hide show
  1. package/dist/accordion/accordion-context.mjs.map +1 -1
  2. package/dist/accordion/accordion-item.mjs +18 -4
  3. package/dist/accordion/accordion-item.mjs.map +1 -1
  4. package/dist/accordion/accordion-panel.mjs +2 -3
  5. package/dist/accordion/accordion-panel.mjs.map +1 -1
  6. package/dist/accordion/accordion-root.d.mts.map +1 -1
  7. package/dist/accordion/accordion-root.mjs +32 -14
  8. package/dist/accordion/accordion-root.mjs.map +1 -1
  9. package/dist/accordion/accordion-trigger.mjs +4 -5
  10. package/dist/accordion/accordion-trigger.mjs.map +1 -1
  11. package/dist/checkbox/checkbox.d.mts +5 -3
  12. package/dist/checkbox/checkbox.d.mts.map +1 -1
  13. package/dist/checkbox/checkbox.mjs +25 -9
  14. package/dist/checkbox/checkbox.mjs.map +1 -1
  15. package/dist/checkbox-group/checkbox-group-context.mjs.map +1 -1
  16. package/dist/checkbox-group/checkbox-group-item.d.mts +2 -1
  17. package/dist/checkbox-group/checkbox-group-item.d.mts.map +1 -1
  18. package/dist/checkbox-group/checkbox-group-item.mjs +3 -1
  19. package/dist/checkbox-group/checkbox-group-item.mjs.map +1 -1
  20. package/dist/checkbox-group/checkbox-group-root.d.mts +5 -2
  21. package/dist/checkbox-group/checkbox-group-root.d.mts.map +1 -1
  22. package/dist/checkbox-group/checkbox-group-root.mjs +24 -5
  23. package/dist/checkbox-group/checkbox-group-root.mjs.map +1 -1
  24. package/dist/combobox/combobox-clear.d.mts +34 -0
  25. package/dist/combobox/combobox-clear.d.mts.map +1 -0
  26. package/dist/combobox/combobox-clear.mjs +58 -0
  27. package/dist/combobox/combobox-clear.mjs.map +1 -0
  28. package/dist/combobox/combobox-context.mjs +23 -0
  29. package/dist/combobox/combobox-context.mjs.map +1 -0
  30. package/dist/combobox/combobox-group.d.mts +72 -0
  31. package/dist/combobox/combobox-group.d.mts.map +1 -0
  32. package/dist/combobox/combobox-group.mjs +104 -0
  33. package/dist/combobox/combobox-group.mjs.map +1 -0
  34. package/dist/combobox/combobox-input.d.mts +42 -0
  35. package/dist/combobox/combobox-input.d.mts.map +1 -0
  36. package/dist/combobox/combobox-input.mjs +102 -0
  37. package/dist/combobox/combobox-input.mjs.map +1 -0
  38. package/dist/combobox/combobox-label.d.mts +22 -0
  39. package/dist/combobox/combobox-label.d.mts.map +1 -0
  40. package/dist/combobox/combobox-label.mjs +32 -0
  41. package/dist/combobox/combobox-label.mjs.map +1 -0
  42. package/dist/combobox/combobox-list.d.mts +37 -0
  43. package/dist/combobox/combobox-list.d.mts.map +1 -0
  44. package/dist/combobox/combobox-list.mjs +70 -0
  45. package/dist/combobox/combobox-list.mjs.map +1 -0
  46. package/dist/combobox/combobox-option.d.mts +45 -0
  47. package/dist/combobox/combobox-option.d.mts.map +1 -0
  48. package/dist/combobox/combobox-option.mjs +88 -0
  49. package/dist/combobox/combobox-option.mjs.map +1 -0
  50. package/dist/combobox/combobox-popup.d.mts +49 -0
  51. package/dist/combobox/combobox-popup.d.mts.map +1 -0
  52. package/dist/combobox/combobox-popup.mjs +86 -0
  53. package/dist/combobox/combobox-popup.mjs.map +1 -0
  54. package/dist/combobox/combobox-root.d.mts +135 -0
  55. package/dist/combobox/combobox-root.d.mts.map +1 -0
  56. package/dist/combobox/combobox-root.mjs +523 -0
  57. package/dist/combobox/combobox-root.mjs.map +1 -0
  58. package/dist/combobox/combobox-trigger.d.mts +36 -0
  59. package/dist/combobox/combobox-trigger.d.mts.map +1 -0
  60. package/dist/combobox/combobox-trigger.mjs +92 -0
  61. package/dist/combobox/combobox-trigger.mjs.map +1 -0
  62. package/dist/combobox/index.d.mts +36 -0
  63. package/dist/combobox/index.d.mts.map +1 -0
  64. package/dist/combobox/index.mjs +36 -0
  65. package/dist/combobox/index.mjs.map +1 -0
  66. package/dist/dialog/dialog-close.d.mts +17 -10
  67. package/dist/dialog/dialog-close.d.mts.map +1 -1
  68. package/dist/dialog/dialog-close.mjs +31 -20
  69. package/dist/dialog/dialog-close.mjs.map +1 -1
  70. package/dist/dialog/dialog-context.mjs.map +1 -1
  71. package/dist/dialog/dialog-form.d.mts +12 -5
  72. package/dist/dialog/dialog-form.d.mts.map +1 -1
  73. package/dist/dialog/dialog-form.mjs +16 -28
  74. package/dist/dialog/dialog-form.mjs.map +1 -1
  75. package/dist/dialog/dialog-popup.d.mts +10 -4
  76. package/dist/dialog/dialog-popup.d.mts.map +1 -1
  77. package/dist/dialog/dialog-popup.mjs +106 -41
  78. package/dist/dialog/dialog-popup.mjs.map +1 -1
  79. package/dist/dialog/dialog-root.d.mts +14 -8
  80. package/dist/dialog/dialog-root.d.mts.map +1 -1
  81. package/dist/dialog/dialog-root.mjs +66 -11
  82. package/dist/dialog/dialog-root.mjs.map +1 -1
  83. package/dist/dialog/dialog-trigger.d.mts +3 -2
  84. package/dist/dialog/dialog-trigger.d.mts.map +1 -1
  85. package/dist/dialog/dialog-trigger.mjs.map +1 -1
  86. package/dist/dialog/index.d.mts +4 -2
  87. package/dist/dialog/index.d.mts.map +1 -1
  88. package/dist/dialog/index.mjs +4 -2
  89. package/dist/dialog/index.mjs.map +1 -1
  90. package/dist/field/field-control.d.mts +33 -0
  91. package/dist/field/field-control.d.mts.map +1 -0
  92. package/dist/field/field-control.mjs +68 -0
  93. package/dist/field/field-control.mjs.map +1 -0
  94. package/dist/field/field-description.d.mts +24 -0
  95. package/dist/field/field-description.d.mts.map +1 -0
  96. package/dist/field/field-description.mjs +34 -0
  97. package/dist/field/field-description.mjs.map +1 -0
  98. package/dist/field/field-error.d.mts +30 -0
  99. package/dist/field/field-error.d.mts.map +1 -0
  100. package/dist/field/field-error.mjs +42 -0
  101. package/dist/field/field-error.mjs.map +1 -0
  102. package/dist/field/field-label.d.mts +25 -0
  103. package/dist/field/field-label.d.mts.map +1 -0
  104. package/dist/field/field-label.mjs +46 -0
  105. package/dist/field/field-label.mjs.map +1 -0
  106. package/dist/field/field-root.d.mts +53 -0
  107. package/dist/field/field-root.d.mts.map +1 -0
  108. package/dist/field/field-root.mjs +317 -0
  109. package/dist/field/field-root.mjs.map +1 -0
  110. package/dist/field/index.d.mts +18 -0
  111. package/dist/field/index.d.mts.map +1 -0
  112. package/dist/field/index.mjs +17 -0
  113. package/dist/field/index.mjs.map +1 -0
  114. package/dist/form/form-root.d.mts +58 -0
  115. package/dist/form/form-root.d.mts.map +1 -0
  116. package/dist/form/form-root.mjs +146 -0
  117. package/dist/form/form-root.mjs.map +1 -0
  118. package/dist/form/form-submit.d.mts +31 -0
  119. package/dist/form/form-submit.d.mts.map +1 -0
  120. package/dist/form/form-submit.mjs +52 -0
  121. package/dist/form/form-submit.mjs.map +1 -0
  122. package/dist/form/index.d.mts +11 -0
  123. package/dist/form/index.d.mts.map +1 -0
  124. package/dist/form/index.mjs +11 -0
  125. package/dist/form/index.mjs.map +1 -0
  126. package/dist/index.d.mts +46 -2
  127. package/dist/index.mjs +8 -1
  128. package/dist/internal/content-focus-probe.mjs +42 -0
  129. package/dist/internal/content-focus-probe.mjs.map +1 -0
  130. package/dist/internal/field-context.d.mts +19 -0
  131. package/dist/internal/field-context.d.mts.map +1 -0
  132. package/dist/internal/field-context.mjs +14 -0
  133. package/dist/internal/field-context.mjs.map +1 -0
  134. package/dist/internal/focus-first-invalid.mjs +67 -0
  135. package/dist/internal/focus-first-invalid.mjs.map +1 -0
  136. package/dist/internal/form-status-watcher.mjs +31 -0
  137. package/dist/internal/form-status-watcher.mjs.map +1 -0
  138. package/dist/internal/modal-registry.mjs +39 -0
  139. package/dist/internal/modal-registry.mjs.map +1 -0
  140. package/dist/internal/platform-attributes.d.mts +12 -1
  141. package/dist/internal/platform-attributes.d.mts.map +1 -1
  142. package/dist/internal/types.d.mts +11 -1
  143. package/dist/internal/types.d.mts.map +1 -1
  144. package/dist/internal/use-controllable-action.mjs +35 -13
  145. package/dist/internal/use-controllable-action.mjs.map +1 -1
  146. package/dist/internal/use-field-control.mjs +107 -0
  147. package/dist/internal/use-field-control.mjs.map +1 -0
  148. package/dist/internal/use-form-owner-event.mjs +44 -0
  149. package/dist/internal/use-form-owner-event.mjs.map +1 -0
  150. package/dist/internal/use-form-reset.mjs +12 -31
  151. package/dist/internal/use-form-reset.mjs.map +1 -1
  152. package/dist/internal/use-hydrated-mount.mjs +21 -0
  153. package/dist/internal/use-hydrated-mount.mjs.map +1 -0
  154. package/dist/internal/use-latest.mjs +32 -0
  155. package/dist/internal/use-latest.mjs.map +1 -0
  156. package/dist/internal/use-modal-registration.mjs +47 -0
  157. package/dist/internal/use-modal-registration.mjs.map +1 -0
  158. package/dist/internal/use-native-group-reconciliation.mjs +6 -5
  159. package/dist/internal/use-native-group-reconciliation.mjs.map +1 -1
  160. package/dist/internal/use-native-select-value.mjs +184 -0
  161. package/dist/internal/use-native-select-value.mjs.map +1 -0
  162. package/dist/internal/use-popover-popup.mjs +8 -22
  163. package/dist/internal/use-popover-popup.mjs.map +1 -1
  164. package/dist/internal/use-popover-root.mjs +58 -23
  165. package/dist/internal/use-popover-root.mjs.map +1 -1
  166. package/dist/internal/validity.d.mts +24 -0
  167. package/dist/internal/validity.d.mts.map +1 -0
  168. package/dist/internal/validity.mjs +108 -0
  169. package/dist/internal/validity.mjs.map +1 -0
  170. package/dist/menu/menu-group.d.mts.map +1 -1
  171. package/dist/menu/menu-group.mjs +3 -2
  172. package/dist/menu/menu-group.mjs.map +1 -1
  173. package/dist/menu/menu-radio-group.mjs +9 -4
  174. package/dist/menu/menu-radio-group.mjs.map +1 -1
  175. package/dist/menu/menu-root.mjs.map +1 -1
  176. package/dist/radio-group/radio-group-root.d.mts +4 -2
  177. package/dist/radio-group/radio-group-root.d.mts.map +1 -1
  178. package/dist/radio-group/radio-group-root.mjs +34 -8
  179. package/dist/radio-group/radio-group-root.mjs.map +1 -1
  180. package/dist/select/index.d.mts +30 -0
  181. package/dist/select/index.d.mts.map +1 -0
  182. package/dist/select/index.mjs +30 -0
  183. package/dist/select/index.mjs.map +1 -0
  184. package/dist/select/select-context.mjs +13 -0
  185. package/dist/select/select-context.mjs.map +1 -0
  186. package/dist/select/select-dom.mjs +44 -0
  187. package/dist/select/select-dom.mjs.map +1 -0
  188. package/dist/select/select-group-label.d.mts +22 -0
  189. package/dist/select/select-group-label.d.mts.map +1 -0
  190. package/dist/select/select-group-label.mjs +39 -0
  191. package/dist/select/select-group-label.mjs.map +1 -0
  192. package/dist/select/select-group.d.mts +28 -0
  193. package/dist/select/select-group.d.mts.map +1 -0
  194. package/dist/select/select-group.mjs +47 -0
  195. package/dist/select/select-group.mjs.map +1 -0
  196. package/dist/select/select-option.d.mts +42 -0
  197. package/dist/select/select-option.d.mts.map +1 -0
  198. package/dist/select/select-option.mjs +65 -0
  199. package/dist/select/select-option.mjs.map +1 -0
  200. package/dist/select/select-root.d.mts +68 -0
  201. package/dist/select/select-root.d.mts.map +1 -0
  202. package/dist/select/select-root.mjs +114 -0
  203. package/dist/select/select-root.mjs.map +1 -0
  204. package/dist/select/select-separator.d.mts +20 -0
  205. package/dist/select/select-separator.d.mts.map +1 -0
  206. package/dist/select/select-separator.mjs +30 -0
  207. package/dist/select/select-separator.mjs.map +1 -0
  208. package/dist/select/select-trigger.d.mts +29 -0
  209. package/dist/select/select-trigger.d.mts.map +1 -0
  210. package/dist/select/select-trigger.mjs +48 -0
  211. package/dist/select/select-trigger.mjs.map +1 -0
  212. package/dist/select/select-value.d.mts +31 -0
  213. package/dist/select/select-value.d.mts.map +1 -0
  214. package/dist/select/select-value.mjs +101 -0
  215. package/dist/select/select-value.mjs.map +1 -0
  216. package/dist/slider/index.d.mts +32 -0
  217. package/dist/slider/index.d.mts.map +1 -0
  218. package/dist/slider/index.mjs +27 -0
  219. package/dist/slider/index.mjs.map +1 -0
  220. package/dist/slider/slider-arithmetic.mjs +120 -0
  221. package/dist/slider/slider-arithmetic.mjs.map +1 -0
  222. package/dist/slider/slider-context.mjs +13 -0
  223. package/dist/slider/slider-context.mjs.map +1 -0
  224. package/dist/slider/slider-indicator.d.mts +22 -0
  225. package/dist/slider/slider-indicator.d.mts.map +1 -0
  226. package/dist/slider/slider-indicator.mjs +36 -0
  227. package/dist/slider/slider-indicator.mjs.map +1 -0
  228. package/dist/slider/slider-label.d.mts +23 -0
  229. package/dist/slider/slider-label.d.mts.map +1 -0
  230. package/dist/slider/slider-label.mjs +44 -0
  231. package/dist/slider/slider-label.mjs.map +1 -0
  232. package/dist/slider/slider-root.d.mts +111 -0
  233. package/dist/slider/slider-root.d.mts.map +1 -0
  234. package/dist/slider/slider-root.mjs +582 -0
  235. package/dist/slider/slider-root.mjs.map +1 -0
  236. package/dist/slider/slider-thumb.d.mts +58 -0
  237. package/dist/slider/slider-thumb.d.mts.map +1 -0
  238. package/dist/slider/slider-thumb.mjs +145 -0
  239. package/dist/slider/slider-thumb.mjs.map +1 -0
  240. package/dist/slider/slider-track.d.mts +29 -0
  241. package/dist/slider/slider-track.d.mts.map +1 -0
  242. package/dist/slider/slider-track.mjs +54 -0
  243. package/dist/slider/slider-track.mjs.map +1 -0
  244. package/dist/slider/slider-value.d.mts +34 -0
  245. package/dist/slider/slider-value.d.mts.map +1 -0
  246. package/dist/slider/slider-value.mjs +38 -0
  247. package/dist/slider/slider-value.mjs.map +1 -0
  248. package/dist/switch/switch.d.mts +5 -3
  249. package/dist/switch/switch.d.mts.map +1 -1
  250. package/dist/switch/switch.mjs +24 -8
  251. package/dist/switch/switch.mjs.map +1 -1
  252. package/dist/tabs/tabs-root.mjs +13 -3
  253. package/dist/tabs/tabs-root.mjs.map +1 -1
  254. package/dist/toast/index.d.mts +25 -0
  255. package/dist/toast/index.d.mts.map +1 -0
  256. package/dist/toast/index.mjs +26 -0
  257. package/dist/toast/index.mjs.map +1 -0
  258. package/dist/toast/toast-action.d.mts +39 -0
  259. package/dist/toast/toast-action.d.mts.map +1 -0
  260. package/dist/toast/toast-action.mjs +64 -0
  261. package/dist/toast/toast-action.mjs.map +1 -0
  262. package/dist/toast/toast-close.d.mts +25 -0
  263. package/dist/toast/toast-close.d.mts.map +1 -0
  264. package/dist/toast/toast-close.mjs +46 -0
  265. package/dist/toast/toast-close.mjs.map +1 -0
  266. package/dist/toast/toast-context.mjs +19 -0
  267. package/dist/toast/toast-context.mjs.map +1 -0
  268. package/dist/toast/toast-description.d.mts +24 -0
  269. package/dist/toast/toast-description.d.mts.map +1 -0
  270. package/dist/toast/toast-description.mjs +35 -0
  271. package/dist/toast/toast-description.mjs.map +1 -0
  272. package/dist/toast/toast-root.d.mts +43 -0
  273. package/dist/toast/toast-root.d.mts.map +1 -0
  274. package/dist/toast/toast-root.mjs +204 -0
  275. package/dist/toast/toast-root.mjs.map +1 -0
  276. package/dist/toast/toast-title.d.mts +24 -0
  277. package/dist/toast/toast-title.d.mts.map +1 -0
  278. package/dist/toast/toast-title.mjs +33 -0
  279. package/dist/toast/toast-title.mjs.map +1 -0
  280. package/dist/toast/toast-viewport.d.mts +52 -0
  281. package/dist/toast/toast-viewport.d.mts.map +1 -0
  282. package/dist/toast/toast-viewport.mjs +621 -0
  283. package/dist/toast/toast-viewport.mjs.map +1 -0
  284. package/dist/toast/toast.d.mts +119 -0
  285. package/dist/toast/toast.d.mts.map +1 -0
  286. package/dist/toast/toast.mjs +153 -0
  287. package/dist/toast/toast.mjs.map +1 -0
  288. package/package.json +7 -1
@@ -5,6 +5,7 @@ import { dataAttr } from "../internal/data-attr.mjs";
5
5
  import { transitionTypes } from "../internal/transition-types.mjs";
6
6
  import { useControllableAction } from "../internal/use-controllable-action.mjs";
7
7
  import { useRender } from "../internal/use-render.mjs";
8
+ import { fieldInputProps, useFieldControl, useFieldValueChange, useMergedRef } from "../internal/use-field-control.mjs";
8
9
  import { guardCheckableChange, useNativeChecked } from "../internal/use-native-checked.mjs";
9
10
  //#region src/switch/switch.tsx
10
11
  /**
@@ -14,11 +15,22 @@ import { guardCheckableChange, useNativeChecked } from "../internal/use-native-c
14
15
  *
15
16
  * Owned keys (a `render` element's value is overridden): `type`, `role`, `checked`,
16
17
  * `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
+ * `data-disabled`; inside a `Field.Root` also `id`, `name`, `required`, `aria-invalid`,
19
+ * `aria-describedby` (token-merged) and `data-invalid`, and `disabled` / `name` / `required`
20
+ * default from the Field. Event handlers are merged rather than owned: a `render` element's own
18
21
  * `onChange` (or `onClick`) runs first, then the library's; an `onClick` that calls
19
22
  * `preventDefault()` cancels the change (nothing is dispatched).
20
23
  */
21
- function Switch({ checked, defaultChecked, checkedChangeAction, disabled = false, transition, className, style, render, ...rest }) {
24
+ function Switch({ checked, defaultChecked, checkedChangeAction, disabled: disabledProp, transition, className, style, render, ...rest }) {
25
+ const field = useFieldControl({
26
+ labelable: true,
27
+ name: rest.name,
28
+ disabled: disabledProp,
29
+ required: rest.required,
30
+ id: rest.id,
31
+ component: "Switch"
32
+ });
33
+ const disabled = field.disabled;
22
34
  const { optimistic, pending, dispatch, latestInFlight } = useControllableAction({
23
35
  controlled: checked,
24
36
  defaultValue: defaultChecked,
@@ -30,6 +42,7 @@ function Switch({ checked, defaultChecked, checkedChangeAction, disabled = false
30
42
  prop: "checked"
31
43
  }
32
44
  });
45
+ useFieldValueChange(optimistic);
33
46
  const inputRef = useNativeChecked({
34
47
  type: "checkbox",
35
48
  component: "Switch",
@@ -38,20 +51,23 @@ function Switch({ checked, defaultChecked, checkedChangeAction, disabled = false
38
51
  latestInFlight,
39
52
  onPlatformChange: (next, event) => dispatch(next, createActionDetails(event, { reason: "platform" }))
40
53
  });
54
+ const state = {
55
+ checked: optimistic,
56
+ pending,
57
+ disabled
58
+ };
59
+ const ref = useMergedRef(inputRef, field.ref);
41
60
  const element = useRender({
42
61
  defaultElement: "input",
43
62
  render,
44
- state: {
45
- checked: optimistic,
46
- pending,
47
- disabled
48
- },
63
+ state,
49
64
  className,
50
65
  style,
51
66
  children: void 0,
52
- ref: inputRef,
67
+ ref,
53
68
  props: rest,
54
69
  libraryProps: {
70
+ ...fieldInputProps(field),
55
71
  type: "checkbox",
56
72
  role: "switch",
57
73
  checked: optimistic,
@@ -1 +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"}
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 {\n fieldInputProps,\n useFieldControl,\n useFieldValueChange,\n useMergedRef,\n} from \"../internal/use-field-control.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 (or the enclosing `Field.Root`'s). */\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`; inside a `Field.Root` also `id`, `name`, `required`, `aria-invalid`,\n * `aria-describedby` (token-merged) and `data-invalid`, and `disabled` / `name` / `required`\n * default from the Field. 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: disabledProp,\n transition,\n className,\n style,\n render,\n ...rest\n}: SwitchProps) {\n // Inside a Field.Root (design/components/field-form.md 7.2) the Field owns the id and the ARIA\n // wiring, and `name` / `required` / `disabled` default from it.\n const field = useFieldControl({\n labelable: true,\n name: rest.name,\n disabled: disabledProp,\n required: rest.required,\n id: rest.id,\n component: \"Switch\",\n });\n const disabled = field.disabled;\n\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 // Inside a Field: a value React writes with no event (a rejected action rolling back, a\n // controlled change) re-reads validity and `validate` after the commit.\n useFieldValueChange(optimistic);\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 ref = useMergedRef<HTMLInputElement>(inputRef, field.ref);\n\n const element = useRender<ComponentPropsWithRef<\"input\">, SwitchState>({\n defaultElement: \"input\",\n render,\n state,\n className,\n style,\n children: undefined,\n ref,\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 ...fieldInputProps(field),\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":";;;;;;;;;;;;;;;;;;;;;;;AA4GA,SAAgB,OAAO,EACrB,SACA,gBACA,qBACA,UAAU,cACV,YACA,WACA,OACA,QACA,GAAG,QACW;CAGd,MAAM,QAAQ,gBAAgB;EAC5B,WAAW;EACX,MAAM,KAAK;EACX,UAAU;EACV,UAAU,KAAK;EACf,IAAI,KAAK;EACT,WAAW;CACb,CAAC;CACD,MAAM,WAAW,MAAM;CAEvB,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;CAGD,oBAAoB,UAAU;CAE9B,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;CAED,MAAM,QAAqB;EAAE,SAAS;EAAY;EAAS;CAAS;CAEpE,MAAM,MAAM,aAA+B,UAAU,MAAM,GAAG;CAE9D,MAAM,UAAU,UAAuD;EACrE,gBAAgB;EAChB;EACA;EACA;EACA;EACA,UAAU,KAAA;EACV;EAEA,OAAO;EAEP,cAAc;GACZ,GAAG,gBAAgB,KAAK;GACxB,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"}
@@ -7,7 +7,7 @@ import { useRender } from "../internal/use-render.mjs";
7
7
  import { useDevWarning } from "../internal/use-dev-warning.mjs";
8
8
  import { TabsContext } from "./tabs-context.mjs";
9
9
  import { tabId } from "./tabs-ids.mjs";
10
- import { useId, useRef } from "react";
10
+ import { useId, useMemo, useRef } from "react";
11
11
  import { jsx } from "react/jsx-runtime";
12
12
  //#region src/tabs/tabs-root.tsx
13
13
  /** Looks up an element by id in the tree that contains `node` (document or shadow root). */
@@ -44,7 +44,7 @@ function TabsRoot({ value, defaultValue, valueChangeAction, orientation = "horiz
44
44
  }
45
45
  });
46
46
  useDevWarning(value === void 0 && defaultValue === void 0, "Tabs.Root: neither `value` nor `defaultValue` was passed, so no tab is selected and no panel is shown. Pass `defaultValue`, or `defaultValue={null}` to start with no selection.");
47
- const context = {
47
+ const context = useMemo(() => ({
48
48
  rootId,
49
49
  committed,
50
50
  optimistic,
@@ -57,7 +57,17 @@ function TabsRoot({ value, defaultValue, valueChangeAction, orientation = "horiz
57
57
  if (next === optimistic) return;
58
58
  dispatch(next, createActionDetails(event, { reason }));
59
59
  }
60
- };
60
+ }), [
61
+ rootId,
62
+ committed,
63
+ optimistic,
64
+ pending,
65
+ orientation,
66
+ activationMode,
67
+ loop,
68
+ disabled,
69
+ dispatch
70
+ ]);
61
71
  const element = useRender({
62
72
  defaultElement: "div",
63
73
  render,
@@ -1 +1 @@
1
- {"version":3,"file":"tabs-root.mjs","names":[],"sources":["../../src/tabs/tabs-root.tsx"],"sourcesContent":["\"use client\";\nimport { useId, 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 { ActionDetails, ChangeAction, RenderProp, StateValue } from \"../internal/types.js\";\nimport { useControllableAction } from \"../internal/use-controllable-action.js\";\nimport { useDevWarning } from \"../internal/use-dev-warning.js\";\nimport { useRender } from \"../internal/use-render.js\";\nimport { TabsContext } from \"./tabs-context.js\";\nimport type {\n TabsActivationMode,\n TabsChangeReason,\n TabsContextValue,\n TabsOrientation,\n} from \"./tabs-context.js\";\nimport { tabId } from \"./tabs-ids.js\";\n\nexport type { TabsActivationMode, TabsOrientation } from \"./tabs-context.js\";\n\n/** Details passed as the second argument of `valueChangeAction`. */\nexport interface TabsValueChangeDetails extends ActionDetails {\n /**\n * `\"activate\"`: the user selected the tab (click, Enter/Space, or focus in automatic mode).\n * `\"platform\"`: the browser revealed a `keepMounted=\"until-found\"` panel through find-in-page or a\n * text fragment (`details.event` is the `beforematch` event).\n */\n readonly reason: TabsChangeReason;\n}\n\nexport interface TabsRootState {\n /** Optimistic selected value, or `null`. Content rendered from it must not suspend. */\n readonly value: string | null;\n /** An action dispatched through this Tabs is in flight. */\n readonly pending: boolean;\n readonly orientation: TabsOrientation;\n readonly disabled: boolean;\n}\n\nexport interface TabsRootProps extends Omit<\n ComponentPropsWithRef<\"div\">,\n \"className\" | \"style\" | \"children\" | \"defaultValue\"\n> {\n /** Controlled selected value. `null` selects nothing; `undefined` means uncontrolled. */\n value?: string | null;\n /** Initial value in uncontrolled mode. Defaults to `null` (no panel shown). */\n defaultValue?: string | null;\n /**\n * Runs inside the Root's transition whenever the user selects a tab. May be sync or async;\n * rejections reach the nearest Error Boundary and roll the selection back.\n *\n * With `activationMode=\"automatic\"` every arrow key press calls it; prefer `\"manual\"` when the\n * action awaits a server round trip. A `setState` placed after your own `await` is not a\n * Transition update; wrap it in `startTransition` (React limitation).\n */\n valueChangeAction?: ChangeAction<string, TabsValueChangeDetails>;\n /** Layout and arrow-key axis. Default `\"horizontal\"`. */\n orientation?: TabsOrientation;\n /**\n * `\"automatic\"`: selection follows focus. `\"manual\"`: Enter, Space or click selects.\n * Default `\"automatic\"`.\n */\n activationMode?: TabsActivationMode;\n /** Whether arrow keys wrap from the last tab to the first. Default `true`. */\n loop?: boolean;\n /** Disables every Tab (focusable, never dispatches). */\n disabled?: boolean;\n className?: StateValue<string | undefined, TabsRootState>;\n style?: StateValue<CSSProperties | undefined, TabsRootState>;\n children?: StateValue<ReactNode, TabsRootState>;\n render?: RenderProp<ComponentPropsWithRef<\"div\">, TabsRootState>;\n}\n\n/** Looks up an element by id in the tree that contains `node` (document or shadow root). */\nfunction findById(node: Node | null, id: string): Element | null {\n const root = node?.getRootNode() ?? (typeof document === \"undefined\" ? null : document);\n if (root !== null && \"getElementById\" in root) {\n return (root as Document | ShadowRoot).getElementById(id);\n }\n return null;\n}\n\n/**\n * Owns the Tabs state (`value`), the transition, the ids and the context. Renders a `div` with\n * `data-pending` while a selection is in flight (including a suspending panel's wait).\n *\n * Owned keys (conventions 1.2): `data-pending`, `data-orientation`, `data-disabled`.\n */\nexport function TabsRoot({\n value,\n defaultValue,\n valueChangeAction,\n orientation = \"horizontal\",\n activationMode = \"automatic\",\n loop = true,\n disabled = false,\n className,\n style,\n children,\n render,\n ...rest\n}: TabsRootProps) {\n const rootId = useId();\n const rootRef = useRef<HTMLElement | null>(null);\n\n const { committed, optimistic, pending, dispatch } = useControllableAction<\n string | null,\n TabsValueChangeDetails\n >({\n controlled: value,\n defaultValue,\n initialValue: null,\n // Only ever dispatched with a string: the Tabs UI cannot deselect.\n action:\n valueChangeAction === undefined\n ? undefined\n : (next, details) => valueChangeAction(next as string, details),\n transitionTypes: (next, prev) => {\n // Direction is relative to the committed tab (design 10.2), by DOM order of the two tabs.\n if (next === null || prev === null || next === prev) return transitionTypes(\"tabs\");\n const prevTab = findById(rootRef.current, tabId(rootId, prev));\n const nextTab = findById(rootRef.current, tabId(rootId, next));\n if (prevTab === null || nextTab === null) return transitionTypes(\"tabs\");\n const following = prevTab.compareDocumentPosition(nextTab) & Node.DOCUMENT_POSITION_FOLLOWING;\n return transitionTypes(\"tabs\", following ? \"next\" : \"prev\");\n },\n warn: { component: \"Tabs.Root\", prop: \"value\" },\n });\n // `null` is a legitimate default (no panel), but forgetting both props is the likelier cause\n // of an empty Tabs (design open question 2, product owner decision).\n useDevWarning(\n value === undefined && defaultValue === undefined,\n \"Tabs.Root: neither `value` nor `defaultValue` was passed, so no tab is selected and no \" +\n \"panel is shown. Pass `defaultValue`, or `defaultValue={null}` to start with no selection.\",\n );\n\n const context: TabsContextValue = {\n rootId,\n committed,\n optimistic,\n pending,\n orientation,\n activationMode,\n loop,\n disabled,\n select: (next, event, reason) => {\n // No-op rule against the optimistic value (conventions 2.3 item 7, design section 9.4).\n if (next === optimistic) return;\n dispatch(next, createActionDetails(event, { reason }));\n },\n };\n\n const state: TabsRootState = { value: optimistic, pending, orientation, disabled };\n\n const element = useRender<ComponentPropsWithRef<\"div\">, TabsRootState>({\n defaultElement: \"div\",\n render,\n state,\n className,\n style,\n children,\n props: rest,\n libraryProps: {\n \"data-pending\": dataAttr(pending),\n \"data-orientation\": orientation,\n \"data-disabled\": dataAttr(disabled),\n },\n ref: rootRef,\n });\n\n return <TabsContext value={context}>{element}</TabsContext>;\n}\n\nTabsRoot.displayName = \"TabsRoot\";\n"],"mappings":";;;;;;;;;;;;;AA2EA,SAAS,SAAS,MAAmB,IAA4B;CAC/D,MAAM,OAAO,MAAM,YAAY,MAAM,OAAO,aAAa,cAAc,OAAO;CAC9E,IAAI,SAAS,QAAQ,oBAAoB,MACvC,OAAQ,KAA+B,eAAe,EAAE;CAE1D,OAAO;AACT;;;;;;;AAQA,SAAgB,SAAS,EACvB,OACA,cACA,mBACA,cAAc,cACd,iBAAiB,aACjB,OAAO,MACP,WAAW,OACX,WACA,OACA,UACA,QACA,GAAG,QACa;CAChB,MAAM,SAAS,MAAM;CACrB,MAAM,UAAU,OAA2B,IAAI;CAE/C,MAAM,EAAE,WAAW,YAAY,SAAS,aAAa,sBAGnD;EACA,YAAY;EACZ;EACA,cAAc;EAEd,QACE,sBAAsB,KAAA,IAClB,KAAA,KACC,MAAM,YAAY,kBAAkB,MAAgB,OAAO;EAClE,kBAAkB,MAAM,SAAS;GAE/B,IAAI,SAAS,QAAQ,SAAS,QAAQ,SAAS,MAAM,OAAO,gBAAgB,MAAM;GAClF,MAAM,UAAU,SAAS,QAAQ,SAAS,MAAM,QAAQ,IAAI,CAAC;GAC7D,MAAM,UAAU,SAAS,QAAQ,SAAS,MAAM,QAAQ,IAAI,CAAC;GAC7D,IAAI,YAAY,QAAQ,YAAY,MAAM,OAAO,gBAAgB,MAAM;GACvE,MAAM,YAAY,QAAQ,wBAAwB,OAAO,IAAI,KAAK;GAClE,OAAO,gBAAgB,QAAQ,YAAY,SAAS,MAAM;EAC5D;EACA,MAAM;GAAE,WAAW;GAAa,MAAM;EAAQ;CAChD,CAAC;CAGD,cACE,UAAU,KAAA,KAAa,iBAAiB,KAAA,GACxC,kLAEF;CAEA,MAAM,UAA4B;EAChC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,SAAS,MAAM,OAAO,WAAW;GAE/B,IAAI,SAAS,YAAY;GACzB,SAAS,MAAM,oBAAoB,OAAO,EAAE,OAAO,CAAC,CAAC;EACvD;CACF;CAIA,MAAM,UAAU,UAAuD;EACrE,gBAAgB;EAChB;EACA,OAAA;GAL6B,OAAO;GAAY;GAAS;GAAa;EAKlE;EACJ;EACA;EACA;EACA,OAAO;EACP,cAAc;GACZ,gBAAgB,SAAS,OAAO;GAChC,oBAAoB;GACpB,iBAAiB,SAAS,QAAQ;EACpC;EACA,KAAK;CACP,CAAC;CAED,OAAO,oBAAC,aAAD;EAAa,OAAO;EAAU,UAAA;CAAqB,CAAA;AAC5D;AAEA,SAAS,cAAc"}
1
+ {"version":3,"file":"tabs-root.mjs","names":[],"sources":["../../src/tabs/tabs-root.tsx"],"sourcesContent":["\"use client\";\nimport { useId, useMemo, 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 { ActionDetails, ChangeAction, RenderProp, StateValue } from \"../internal/types.js\";\nimport { useControllableAction } from \"../internal/use-controllable-action.js\";\nimport { useDevWarning } from \"../internal/use-dev-warning.js\";\nimport { useRender } from \"../internal/use-render.js\";\nimport { TabsContext } from \"./tabs-context.js\";\nimport type {\n TabsActivationMode,\n TabsChangeReason,\n TabsContextValue,\n TabsOrientation,\n} from \"./tabs-context.js\";\nimport { tabId } from \"./tabs-ids.js\";\n\nexport type { TabsActivationMode, TabsOrientation } from \"./tabs-context.js\";\n\n/** Details passed as the second argument of `valueChangeAction`. */\nexport interface TabsValueChangeDetails extends ActionDetails {\n /**\n * `\"activate\"`: the user selected the tab (click, Enter/Space, or focus in automatic mode).\n * `\"platform\"`: the browser revealed a `keepMounted=\"until-found\"` panel through find-in-page or a\n * text fragment (`details.event` is the `beforematch` event).\n */\n readonly reason: TabsChangeReason;\n}\n\nexport interface TabsRootState {\n /** Optimistic selected value, or `null`. Content rendered from it must not suspend. */\n readonly value: string | null;\n /** An action dispatched through this Tabs is in flight. */\n readonly pending: boolean;\n readonly orientation: TabsOrientation;\n readonly disabled: boolean;\n}\n\nexport interface TabsRootProps extends Omit<\n ComponentPropsWithRef<\"div\">,\n \"className\" | \"style\" | \"children\" | \"defaultValue\"\n> {\n /** Controlled selected value. `null` selects nothing; `undefined` means uncontrolled. */\n value?: string | null;\n /** Initial value in uncontrolled mode. Defaults to `null` (no panel shown). */\n defaultValue?: string | null;\n /**\n * Runs inside the Root's transition whenever the user selects a tab. May be sync or async;\n * rejections reach the nearest Error Boundary and roll the selection back.\n *\n * With `activationMode=\"automatic\"` every arrow key press calls it; prefer `\"manual\"` when the\n * action awaits a server round trip. A `setState` placed after your own `await` is not a\n * Transition update; wrap it in `startTransition` (React limitation).\n */\n valueChangeAction?: ChangeAction<string, TabsValueChangeDetails>;\n /** Layout and arrow-key axis. Default `\"horizontal\"`. */\n orientation?: TabsOrientation;\n /**\n * `\"automatic\"`: selection follows focus. `\"manual\"`: Enter, Space or click selects.\n * Default `\"automatic\"`.\n */\n activationMode?: TabsActivationMode;\n /** Whether arrow keys wrap from the last tab to the first. Default `true`. */\n loop?: boolean;\n /** Disables every Tab (focusable, never dispatches). */\n disabled?: boolean;\n className?: StateValue<string | undefined, TabsRootState>;\n style?: StateValue<CSSProperties | undefined, TabsRootState>;\n children?: StateValue<ReactNode, TabsRootState>;\n render?: RenderProp<ComponentPropsWithRef<\"div\">, TabsRootState>;\n}\n\n/** Looks up an element by id in the tree that contains `node` (document or shadow root). */\nfunction findById(node: Node | null, id: string): Element | null {\n const root = node?.getRootNode() ?? (typeof document === \"undefined\" ? null : document);\n if (root !== null && \"getElementById\" in root) {\n return (root as Document | ShadowRoot).getElementById(id);\n }\n return null;\n}\n\n/**\n * Owns the Tabs state (`value`), the transition, the ids and the context. Renders a `div` with\n * `data-pending` while a selection is in flight (including a suspending panel's wait).\n *\n * Owned keys (conventions 1.2): `data-pending`, `data-orientation`, `data-disabled`.\n */\nexport function TabsRoot({\n value,\n defaultValue,\n valueChangeAction,\n orientation = \"horizontal\",\n activationMode = \"automatic\",\n loop = true,\n disabled = false,\n className,\n style,\n children,\n render,\n ...rest\n}: TabsRootProps) {\n const rootId = useId();\n const rootRef = useRef<HTMLElement | null>(null);\n\n const { committed, optimistic, pending, dispatch } = useControllableAction<\n string | null,\n TabsValueChangeDetails\n >({\n controlled: value,\n defaultValue,\n initialValue: null,\n // Only ever dispatched with a string: the Tabs UI cannot deselect.\n action:\n valueChangeAction === undefined\n ? undefined\n : (next, details) => valueChangeAction(next as string, details),\n transitionTypes: (next, prev) => {\n // Direction is relative to the committed tab (design 10.2), by DOM order of the two tabs.\n if (next === null || prev === null || next === prev) return transitionTypes(\"tabs\");\n const prevTab = findById(rootRef.current, tabId(rootId, prev));\n const nextTab = findById(rootRef.current, tabId(rootId, next));\n if (prevTab === null || nextTab === null) return transitionTypes(\"tabs\");\n const following = prevTab.compareDocumentPosition(nextTab) & Node.DOCUMENT_POSITION_FOLLOWING;\n return transitionTypes(\"tabs\", following ? \"next\" : \"prev\");\n },\n warn: { component: \"Tabs.Root\", prop: \"value\" },\n });\n // `null` is a legitimate default (no panel), but forgetting both props is the likelier cause\n // of an empty Tabs (design open question 2, product owner decision).\n useDevWarning(\n value === undefined && defaultValue === undefined,\n \"Tabs.Root: neither `value` nor `defaultValue` was passed, so no tab is selected and no \" +\n \"panel is shown. Pass `defaultValue`, or `defaultValue={null}` to start with no selection.\",\n );\n\n // Memoised (#48): `dispatch` is stable, so this changes only with the state and the props below.\n const context = useMemo<TabsContextValue>(\n () => ({\n rootId,\n committed,\n optimistic,\n pending,\n orientation,\n activationMode,\n loop,\n disabled,\n select: (next, event, reason) => {\n // No-op rule against the optimistic value (conventions 2.3 item 7, design section 9.4).\n if (next === optimistic) return;\n dispatch(next, createActionDetails(event, { reason }));\n },\n }),\n [rootId, committed, optimistic, pending, orientation, activationMode, loop, disabled, dispatch],\n );\n\n const state: TabsRootState = { value: optimistic, pending, orientation, disabled };\n\n const element = useRender<ComponentPropsWithRef<\"div\">, TabsRootState>({\n defaultElement: \"div\",\n render,\n state,\n className,\n style,\n children,\n props: rest,\n libraryProps: {\n \"data-pending\": dataAttr(pending),\n \"data-orientation\": orientation,\n \"data-disabled\": dataAttr(disabled),\n },\n ref: rootRef,\n });\n\n return <TabsContext value={context}>{element}</TabsContext>;\n}\n\nTabsRoot.displayName = \"TabsRoot\";\n"],"mappings":";;;;;;;;;;;;;AA2EA,SAAS,SAAS,MAAmB,IAA4B;CAC/D,MAAM,OAAO,MAAM,YAAY,MAAM,OAAO,aAAa,cAAc,OAAO;CAC9E,IAAI,SAAS,QAAQ,oBAAoB,MACvC,OAAQ,KAA+B,eAAe,EAAE;CAE1D,OAAO;AACT;;;;;;;AAQA,SAAgB,SAAS,EACvB,OACA,cACA,mBACA,cAAc,cACd,iBAAiB,aACjB,OAAO,MACP,WAAW,OACX,WACA,OACA,UACA,QACA,GAAG,QACa;CAChB,MAAM,SAAS,MAAM;CACrB,MAAM,UAAU,OAA2B,IAAI;CAE/C,MAAM,EAAE,WAAW,YAAY,SAAS,aAAa,sBAGnD;EACA,YAAY;EACZ;EACA,cAAc;EAEd,QACE,sBAAsB,KAAA,IAClB,KAAA,KACC,MAAM,YAAY,kBAAkB,MAAgB,OAAO;EAClE,kBAAkB,MAAM,SAAS;GAE/B,IAAI,SAAS,QAAQ,SAAS,QAAQ,SAAS,MAAM,OAAO,gBAAgB,MAAM;GAClF,MAAM,UAAU,SAAS,QAAQ,SAAS,MAAM,QAAQ,IAAI,CAAC;GAC7D,MAAM,UAAU,SAAS,QAAQ,SAAS,MAAM,QAAQ,IAAI,CAAC;GAC7D,IAAI,YAAY,QAAQ,YAAY,MAAM,OAAO,gBAAgB,MAAM;GACvE,MAAM,YAAY,QAAQ,wBAAwB,OAAO,IAAI,KAAK;GAClE,OAAO,gBAAgB,QAAQ,YAAY,SAAS,MAAM;EAC5D;EACA,MAAM;GAAE,WAAW;GAAa,MAAM;EAAQ;CAChD,CAAC;CAGD,cACE,UAAU,KAAA,KAAa,iBAAiB,KAAA,GACxC,kLAEF;CAGA,MAAM,UAAU,eACP;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,SAAS,MAAM,OAAO,WAAW;GAE/B,IAAI,SAAS,YAAY;GACzB,SAAS,MAAM,oBAAoB,OAAO,EAAE,OAAO,CAAC,CAAC;EACvD;CACF,IACA;EAAC;EAAQ;EAAW;EAAY;EAAS;EAAa;EAAgB;EAAM;EAAU;CAAQ,CAChG;CAIA,MAAM,UAAU,UAAuD;EACrE,gBAAgB;EAChB;EACA,OAAA;GAL6B,OAAO;GAAY;GAAS;GAAa;EAKlE;EACJ;EACA;EACA;EACA,OAAO;EACP,cAAc;GACZ,gBAAgB,SAAS,OAAO;GAChC,oBAAoB;GACpB,iBAAiB,SAAS,QAAQ;EACpC;EACA,KAAK;CACP,CAAC;CAED,OAAO,oBAAC,aAAD;EAAa,OAAO;EAAU,UAAA;CAAqB,CAAA;AAC5D;AAEA,SAAS,cAAc"}
@@ -0,0 +1,25 @@
1
+ import { ToastActionDetails, ToastActionOptions, ToastCloseDetails, ToastItem, ToastManager, ToastOptions, ToastPriority, ToastPromiseOptions, createToastManager, toast } from "./toast.mjs";
2
+ import { ToastAction, ToastActionProps, ToastActionState } from "./toast-action.mjs";
3
+ import { ToastClose, ToastCloseProps, ToastCloseState } from "./toast-close.mjs";
4
+ import { ToastRoot, ToastRootProps, ToastRootState } from "./toast-root.mjs";
5
+ import { ToastDescription, ToastDescriptionProps } from "./toast-description.mjs";
6
+ import { ToastTitle, ToastTitleProps } from "./toast-title.mjs";
7
+ import { ToastViewport, ToastViewportProps, ToastViewportState } from "./toast-viewport.mjs";
8
+ //#region src/toast/index.d.ts
9
+ /**
10
+ * Toast notifications. The queue's input is the `toast()` function (urgent: a toast shows at
11
+ * once, even while the action it reports on is pending); its output is `Toast.Viewport`
12
+ * (`section[popover=manual]`, rendered once) mapping `state.toasts` to `Toast.Root`
13
+ * (`div[role=dialog]`) > `Title`, `Description`, `Action` (an action prop, e.g. Undo), `Close`.
14
+ */
15
+ export declare const Toast: {
16
+ readonly Viewport: typeof ToastViewport;
17
+ readonly Root: typeof ToastRoot;
18
+ readonly Title: typeof ToastTitle;
19
+ readonly Description: typeof ToastDescription;
20
+ readonly Action: typeof ToastAction;
21
+ readonly Close: typeof ToastClose;
22
+ };
23
+ //#endregion
24
+ export { type ToastActionDetails, type ToastActionOptions, type ToastActionProps, type ToastActionState, type ToastCloseDetails, type ToastCloseProps, type ToastCloseState, type ToastDescriptionProps, type ToastItem, type ToastManager, type ToastOptions, type ToastPriority, type ToastPromiseOptions, type ToastRootProps, type ToastRootState, type ToastTitleProps, type ToastViewportProps, type ToastViewportState, createToastManager, toast };
25
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/toast/index.ts"],"mappings":";;;;;;;;;;;;;;qBAaa;WACX,iBAAQ;WACR,aAAI;WACJ,cAAK;WACL,oBAAW;WACX,eAAM;WACN,cAAK"}
@@ -0,0 +1,26 @@
1
+ import { ToastAction } from "./toast-action.mjs";
2
+ import { ToastClose } from "./toast-close.mjs";
3
+ import { ToastDescription } from "./toast-description.mjs";
4
+ import { ToastRoot } from "./toast-root.mjs";
5
+ import { ToastTitle } from "./toast-title.mjs";
6
+ import { createToastManager, toast } from "./toast.mjs";
7
+ import { ToastViewport } from "./toast-viewport.mjs";
8
+ //#region src/toast/index.ts
9
+ /**
10
+ * Toast notifications. The queue's input is the `toast()` function (urgent: a toast shows at
11
+ * once, even while the action it reports on is pending); its output is `Toast.Viewport`
12
+ * (`section[popover=manual]`, rendered once) mapping `state.toasts` to `Toast.Root`
13
+ * (`div[role=dialog]`) > `Title`, `Description`, `Action` (an action prop, e.g. Undo), `Close`.
14
+ */
15
+ const Toast = {
16
+ Viewport: ToastViewport,
17
+ Root: ToastRoot,
18
+ Title: ToastTitle,
19
+ Description: ToastDescription,
20
+ Action: ToastAction,
21
+ Close: ToastClose
22
+ };
23
+ //#endregion
24
+ export { Toast, createToastManager, toast };
25
+
26
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/toast/index.ts"],"sourcesContent":["import { ToastAction } from \"./toast-action.js\";\nimport { ToastClose } from \"./toast-close.js\";\nimport { ToastDescription } from \"./toast-description.js\";\nimport { ToastRoot } from \"./toast-root.js\";\nimport { ToastTitle } from \"./toast-title.js\";\nimport { ToastViewport } from \"./toast-viewport.js\";\n\n/**\n * Toast notifications. The queue's input is the `toast()` function (urgent: a toast shows at\n * once, even while the action it reports on is pending); its output is `Toast.Viewport`\n * (`section[popover=manual]`, rendered once) mapping `state.toasts` to `Toast.Root`\n * (`div[role=dialog]`) > `Title`, `Description`, `Action` (an action prop, e.g. Undo), `Close`.\n */\nexport const Toast = {\n Viewport: ToastViewport,\n Root: ToastRoot,\n Title: ToastTitle,\n Description: ToastDescription,\n Action: ToastAction,\n Close: ToastClose,\n} as const;\n\nexport { toast, createToastManager } from \"./toast.js\";\nexport type {\n ToastOptions,\n ToastItem,\n ToastPriority,\n ToastActionOptions,\n ToastActionDetails,\n ToastCloseDetails,\n ToastPromiseOptions,\n ToastManager,\n} from \"./toast.js\";\nexport type { ToastViewportProps, ToastViewportState } from \"./toast-viewport.js\";\nexport type { ToastRootProps, ToastRootState } from \"./toast-root.js\";\nexport type { ToastTitleProps } from \"./toast-title.js\";\nexport type { ToastDescriptionProps } from \"./toast-description.js\";\nexport type { ToastActionProps, ToastActionState } from \"./toast-action.js\";\nexport type { ToastCloseProps, ToastCloseState } from \"./toast-close.js\";\n"],"mappings":";;;;;;;;;;;;;;AAaA,MAAa,QAAQ;CACnB,UAAU;CACV,MAAM;CACN,OAAO;CACP,aAAa;CACb,QAAQ;CACR,OAAO;AACT"}
@@ -0,0 +1,39 @@
1
+ import { Action, RenderProp, StateValue } from "../internal/types.mjs";
2
+ import { ToastActionDetails, ToastItem } from "./toast.mjs";
3
+ import { CSSProperties, ComponentPropsWithRef, ReactNode } from "react";
4
+ //#region src/toast/toast-action.d.ts
5
+ export interface ToastActionState {
6
+ /** This part's action is in flight. */
7
+ readonly pending: boolean;
8
+ readonly toast: ToastItem;
9
+ }
10
+ export interface ToastActionProps extends Omit<ComponentPropsWithRef<"button">, "onClick" | "className" | "style" | "children"> {
11
+ /**
12
+ * Runs in this part's own transition: `data-pending` on the Action and the Root, the toast's
13
+ * timer paused. When it resolves the toast closes with `reason: "activate"` (unless
14
+ * `closeOnSettle` is `false`); a rejection keeps the toast and reaches the nearest Error
15
+ * Boundary above the Viewport. A caught error counts as success and closes the toast: rethrow
16
+ * after `toast.update`, or use `closeOnSettle={false}`. Default: the toast's `action.action`.
17
+ */
18
+ action?: Action<[details: ToastActionDetails]>;
19
+ /** Close the toast when the action resolves. Default `true`. */
20
+ closeOnSettle?: boolean;
21
+ /** Default: the toast's `action.label`. */
22
+ children?: StateValue<ReactNode, ToastActionState>;
23
+ className?: StateValue<string | undefined, ToastActionState>;
24
+ style?: StateValue<CSSProperties | undefined, ToastActionState>;
25
+ render?: RenderProp<ComponentPropsWithRef<"button">, ToastActionState>;
26
+ }
27
+ /**
28
+ * The toast's action button (Undo, Retry, View): a `button type="button"` whose `action` runs as
29
+ * a transition. Renders nothing when neither the part nor the toast has an action. Never disabled
30
+ * while pending (a second click is a second dispatch, latest wins).
31
+ *
32
+ * Owned keys (conventions 1.2): `type` (on a `<button>` only), `onClick`, `data-pending`.
33
+ */
34
+ export declare function ToastAction({ action, closeOnSettle, children, className, style, render, ...rest }: ToastActionProps): ReactNode;
35
+ export declare namespace ToastAction {
36
+ var displayName: string;
37
+ }
38
+ //#endregion
39
+ //# sourceMappingURL=toast-action.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toast-action.d.mts","names":[],"sources":["../../src/toast/toast-action.tsx"],"mappings":";;;;iBAYiB;;WAEN;WACA,OAAO;;iBAGD,yBAAyB,KACxC;;;;;;;;EAUA,SAAS,QAAQ,SAAS;;EAE1B;;EAEA,WAAW,WAAW,WAAW;EACjC,YAAY,+BAA+B;EAC3C,QAAQ,WAAW,2BAA2B;EAC9C,SAAS,WAAW,iCAAiC;;;;;;;;;wBAUvC,cACd,QACA,eACA,UACA,WACA,OACA,WACG,QACF,mBAAgB;yBARH"}
@@ -0,0 +1,64 @@
1
+ "use client";
2
+ import { createActionDetails } from "../internal/action-details.mjs";
3
+ import { dataAttr } from "../internal/data-attr.mjs";
4
+ import { rendersButton, useRender } from "../internal/use-render.mjs";
5
+ import { useActionTrigger } from "../internal/use-action-trigger.mjs";
6
+ import { useToastRootContext } from "./toast-context.mjs";
7
+ import { useLayoutEffect, useState } from "react";
8
+ //#region src/toast/toast-action.tsx
9
+ /**
10
+ * The toast's action button (Undo, Retry, View): a `button type="button"` whose `action` runs as
11
+ * a transition. Renders nothing when neither the part nor the toast has an action. Never disabled
12
+ * while pending (a second click is a second dispatch, latest wins).
13
+ *
14
+ * Owned keys (conventions 1.2): `type` (on a `<button>` only), `onClick`, `data-pending`.
15
+ */
16
+ function ToastAction({ action, closeOnSettle = true, children, className, style, render, ...rest }) {
17
+ const root = useToastRootContext("Toast.Action");
18
+ const { pending, run } = useActionTrigger();
19
+ const [token] = useState(() => ({}));
20
+ const effective = action ?? root.toast.action?.action;
21
+ const { setActionPending } = root;
22
+ useLayoutEffect(() => {
23
+ if (!pending) return;
24
+ setActionPending(token, true);
25
+ return () => setActionPending(token, false);
26
+ }, [
27
+ pending,
28
+ setActionPending,
29
+ token
30
+ ]);
31
+ const state = {
32
+ pending,
33
+ toast: root.toast
34
+ };
35
+ const onClick = (event) => {
36
+ if (effective === void 0 || rest.disabled === true) return;
37
+ const native = event.nativeEvent;
38
+ const details = createActionDetails(native, { id: root.toast.id });
39
+ run(() => effective(details), () => {
40
+ if (closeOnSettle) root.close("activate", native);
41
+ });
42
+ };
43
+ const libraryProps = {
44
+ ...rendersButton(render) && { type: "button" },
45
+ onClick,
46
+ "data-pending": dataAttr(pending)
47
+ };
48
+ const element = useRender({
49
+ defaultElement: "button",
50
+ render,
51
+ state,
52
+ className,
53
+ style,
54
+ children: children ?? root.toast.action?.label,
55
+ props: rest,
56
+ libraryProps
57
+ });
58
+ return effective === void 0 ? null : element;
59
+ }
60
+ ToastAction.displayName = "ToastAction";
61
+ //#endregion
62
+ export { ToastAction };
63
+
64
+ //# sourceMappingURL=toast-action.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toast-action.mjs","names":[],"sources":["../../src/toast/toast-action.tsx"],"sourcesContent":["\"use client\";\nimport { useLayoutEffect, useState } from \"react\";\nimport type { ComponentPropsWithRef, CSSProperties, MouseEvent, ReactNode } from \"react\";\nimport { createActionDetails } from \"../internal/action-details.js\";\nimport { dataAttr } from \"../internal/data-attr.js\";\nimport type { Action, RenderProp, StateValue } from \"../internal/types.js\";\nimport { useActionTrigger } from \"../internal/use-action-trigger.js\";\nimport { rendersButton, useRender } from \"../internal/use-render.js\";\nimport type { DataAttributes } from \"../internal/use-render.js\";\nimport type { ToastActionDetails, ToastItem } from \"./toast.js\";\nimport { useToastRootContext } from \"./toast-context.js\";\n\nexport interface ToastActionState {\n /** This part's action is in flight. */\n readonly pending: boolean;\n readonly toast: ToastItem;\n}\n\nexport interface ToastActionProps extends Omit<\n ComponentPropsWithRef<\"button\">,\n \"onClick\" | \"className\" | \"style\" | \"children\"\n> {\n /**\n * Runs in this part's own transition: `data-pending` on the Action and the Root, the toast's\n * timer paused. When it resolves the toast closes with `reason: \"activate\"` (unless\n * `closeOnSettle` is `false`); a rejection keeps the toast and reaches the nearest Error\n * Boundary above the Viewport. A caught error counts as success and closes the toast: rethrow\n * after `toast.update`, or use `closeOnSettle={false}`. Default: the toast's `action.action`.\n */\n action?: Action<[details: ToastActionDetails]>;\n /** Close the toast when the action resolves. Default `true`. */\n closeOnSettle?: boolean;\n /** Default: the toast's `action.label`. */\n children?: StateValue<ReactNode, ToastActionState>;\n className?: StateValue<string | undefined, ToastActionState>;\n style?: StateValue<CSSProperties | undefined, ToastActionState>;\n render?: RenderProp<ComponentPropsWithRef<\"button\">, ToastActionState>;\n}\n\n/**\n * The toast's action button (Undo, Retry, View): a `button type=\"button\"` whose `action` runs as\n * a transition. Renders nothing when neither the part nor the toast has an action. Never disabled\n * while pending (a second click is a second dispatch, latest wins).\n *\n * Owned keys (conventions 1.2): `type` (on a `<button>` only), `onClick`, `data-pending`.\n */\nexport function ToastAction({\n action,\n closeOnSettle = true,\n children,\n className,\n style,\n render,\n ...rest\n}: ToastActionProps) {\n const root = useToastRootContext(\"Toast.Action\");\n const { pending, run } = useActionTrigger();\n const [token] = useState(() => ({}));\n const effective = action ?? root.toast.action?.action;\n const { setActionPending } = root;\n\n // The Root (and through it the Viewport's timer) sees this part's pending state.\n useLayoutEffect(() => {\n if (!pending) return;\n setActionPending(token, true);\n return () => setActionPending(token, false);\n }, [pending, setActionPending, token]);\n\n const state: ToastActionState = { pending, toast: root.toast };\n\n const onClick = (event: MouseEvent<HTMLElement>): void => {\n if (effective === undefined || rest.disabled === true) return;\n const native = event.nativeEvent;\n const details = createActionDetails(native, { id: root.toast.id });\n run(\n () => effective(details),\n () => {\n // A second resolve finds the toast already closed (closing is idempotent).\n if (closeOnSettle) root.close(\"activate\", native);\n },\n );\n };\n\n const libraryProps: ComponentPropsWithRef<\"button\"> & DataAttributes = {\n ...(rendersButton(render) && { type: \"button\" as const }),\n onClick,\n \"data-pending\": dataAttr(pending),\n };\n\n const element = useRender<ComponentPropsWithRef<\"button\">, ToastActionState>({\n defaultElement: \"button\",\n render,\n state,\n className,\n style,\n children: children ?? root.toast.action?.label,\n props: rest,\n libraryProps,\n });\n return effective === undefined ? null : element;\n}\n\nToastAction.displayName = \"ToastAction\";\n"],"mappings":";;;;;;;;;;;;;;;AA8CA,SAAgB,YAAY,EAC1B,QACA,gBAAgB,MAChB,UACA,WACA,OACA,QACA,GAAG,QACgB;CACnB,MAAM,OAAO,oBAAoB,cAAc;CAC/C,MAAM,EAAE,SAAS,QAAQ,iBAAiB;CAC1C,MAAM,CAAC,SAAS,gBAAgB,CAAC,EAAE;CACnC,MAAM,YAAY,UAAU,KAAK,MAAM,QAAQ;CAC/C,MAAM,EAAE,qBAAqB;CAG7B,sBAAsB;EACpB,IAAI,CAAC,SAAS;EACd,iBAAiB,OAAO,IAAI;EAC5B,aAAa,iBAAiB,OAAO,KAAK;CAC5C,GAAG;EAAC;EAAS;EAAkB;CAAK,CAAC;CAErC,MAAM,QAA0B;EAAE;EAAS,OAAO,KAAK;CAAM;CAE7D,MAAM,WAAW,UAAyC;EACxD,IAAI,cAAc,KAAA,KAAa,KAAK,aAAa,MAAM;EACvD,MAAM,SAAS,MAAM;EACrB,MAAM,UAAU,oBAAoB,QAAQ,EAAE,IAAI,KAAK,MAAM,GAAG,CAAC;EACjE,UACQ,UAAU,OAAO,SACjB;GAEJ,IAAI,eAAe,KAAK,MAAM,YAAY,MAAM;EAClD,CACF;CACF;CAEA,MAAM,eAAiE;EACrE,GAAI,cAAc,MAAM,KAAK,EAAE,MAAM,SAAkB;EACvD;EACA,gBAAgB,SAAS,OAAO;CAClC;CAEA,MAAM,UAAU,UAA6D;EAC3E,gBAAgB;EAChB;EACA;EACA;EACA;EACA,UAAU,YAAY,KAAK,MAAM,QAAQ;EACzC,OAAO;EACP;CACF,CAAC;CACD,OAAO,cAAc,KAAA,IAAY,OAAO;AAC1C;AAEA,YAAY,cAAc"}
@@ -0,0 +1,25 @@
1
+ import { RenderProp, StateValue } from "../internal/types.mjs";
2
+ import { ToastItem } from "./toast.mjs";
3
+ import { CSSProperties, ComponentPropsWithRef, ReactNode } from "react";
4
+ //#region src/toast/toast-close.d.ts
5
+ export interface ToastCloseState {
6
+ readonly toast: ToastItem;
7
+ }
8
+ export interface ToastCloseProps extends Omit<ComponentPropsWithRef<"button">, "onClick" | "className" | "style" | "children"> {
9
+ children?: StateValue<ReactNode, ToastCloseState>;
10
+ className?: StateValue<string | undefined, ToastCloseState>;
11
+ style?: StateValue<CSSProperties | undefined, ToastCloseState>;
12
+ render?: RenderProp<ComponentPropsWithRef<"button">, ToastCloseState>;
13
+ }
14
+ /**
15
+ * Dismisses the toast (`reason: "dismiss"`, the same as Escape). Label it yourself (`aria-label`
16
+ * or text). No Invoker Command: `hide-popover` would hide the whole region.
17
+ *
18
+ * Owned keys (conventions 1.2): `type` (on a `<button>` only), `onClick`.
19
+ */
20
+ export declare function ToastClose({ children, className, style, render, ...rest }: ToastCloseProps): ReactNode;
21
+ export declare namespace ToastClose {
22
+ var displayName: string;
23
+ }
24
+ //#endregion
25
+ //# sourceMappingURL=toast-close.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toast-close.d.mts","names":[],"sources":["../../src/toast/toast-close.tsx"],"mappings":";;;;iBASiB;WACN,OAAO;;iBAGD,wBAAwB,KACvC;EAGA,WAAW,WAAW,WAAW;EACjC,YAAY,+BAA+B;EAC3C,QAAQ,WAAW,2BAA2B;EAC9C,SAAS,WAAW,iCAAiC;;;;;;;;wBAWvC,aAAa,UAAU,WAAW,OAAO,WAAW,QAAQ,kBAAe;yBAA3E"}
@@ -0,0 +1,46 @@
1
+ "use client";
2
+ import { rendersButton, useRender } from "../internal/use-render.mjs";
3
+ import { useToastRootContext } from "./toast-context.mjs";
4
+ import { useCallback } from "react";
5
+ //#region src/toast/toast-close.tsx
6
+ const isDev = process.env.NODE_ENV !== "production";
7
+ /**
8
+ * Dismisses the toast (`reason: "dismiss"`, the same as Escape). Label it yourself (`aria-label`
9
+ * or text). No Invoker Command: `hide-popover` would hide the whole region.
10
+ *
11
+ * Owned keys (conventions 1.2): `type` (on a `<button>` only), `onClick`.
12
+ */
13
+ function ToastClose({ children, className, style, render, ...rest }) {
14
+ const root = useToastRootContext("Toast.Close");
15
+ const devRef = useCallback((element) => {
16
+ if (isDev) queueMicrotask(() => {
17
+ if (!element.isConnected) return;
18
+ if (!(element.hasAttribute("aria-label") || element.hasAttribute("aria-labelledby") || (element.textContent ?? "").trim() !== "")) console.error("Toast.Close: the button has no accessible name. Give it text or an `aria-label`.");
19
+ });
20
+ return () => {};
21
+ }, []);
22
+ const onClick = (event) => {
23
+ if (rest.disabled === true) return;
24
+ root.close("dismiss", event.nativeEvent);
25
+ };
26
+ const libraryProps = {
27
+ ...rendersButton(render) && { type: "button" },
28
+ onClick
29
+ };
30
+ return useRender({
31
+ defaultElement: "button",
32
+ render,
33
+ state: { toast: root.toast },
34
+ className,
35
+ style,
36
+ children,
37
+ props: rest,
38
+ libraryProps,
39
+ ref: devRef
40
+ });
41
+ }
42
+ ToastClose.displayName = "ToastClose";
43
+ //#endregion
44
+ export { ToastClose };
45
+
46
+ //# sourceMappingURL=toast-close.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toast-close.mjs","names":[],"sources":["../../src/toast/toast-close.tsx"],"sourcesContent":["\"use client\";\nimport { useCallback } from \"react\";\nimport type { ComponentPropsWithRef, CSSProperties, MouseEvent, ReactNode } from \"react\";\nimport type { RenderProp, StateValue } from \"../internal/types.js\";\nimport { rendersButton, useRender } from \"../internal/use-render.js\";\nimport type { DataAttributes } from \"../internal/use-render.js\";\nimport type { ToastItem } from \"./toast.js\";\nimport { useToastRootContext } from \"./toast-context.js\";\n\nexport interface ToastCloseState {\n readonly toast: ToastItem;\n}\n\nexport interface ToastCloseProps extends Omit<\n ComponentPropsWithRef<\"button\">,\n \"onClick\" | \"className\" | \"style\" | \"children\"\n> {\n children?: StateValue<ReactNode, ToastCloseState>;\n className?: StateValue<string | undefined, ToastCloseState>;\n style?: StateValue<CSSProperties | undefined, ToastCloseState>;\n render?: RenderProp<ComponentPropsWithRef<\"button\">, ToastCloseState>;\n}\n\nconst isDev = process.env.NODE_ENV !== \"production\";\n\n/**\n * Dismisses the toast (`reason: \"dismiss\"`, the same as Escape). Label it yourself (`aria-label`\n * or text). No Invoker Command: `hide-popover` would hide the whole region.\n *\n * Owned keys (conventions 1.2): `type` (on a `<button>` only), `onClick`.\n */\nexport function ToastClose({ children, className, style, render, ...rest }: ToastCloseProps) {\n const root = useToastRootContext(\"Toast.Close\");\n\n const devRef = useCallback((element: HTMLElement) => {\n if (isDev) {\n // After the commit: the text may come from children rendered in the same commit.\n queueMicrotask(() => {\n if (!element.isConnected) return;\n const named =\n element.hasAttribute(\"aria-label\") ||\n element.hasAttribute(\"aria-labelledby\") ||\n (element.textContent ?? \"\").trim() !== \"\";\n if (!named) {\n console.error(\n \"Toast.Close: the button has no accessible name. Give it text or an `aria-label`.\",\n );\n }\n });\n }\n return () => {};\n }, []);\n\n const onClick = (event: MouseEvent<HTMLElement>): void => {\n if (rest.disabled === true) return;\n root.close(\"dismiss\", event.nativeEvent);\n };\n\n const libraryProps: ComponentPropsWithRef<\"button\"> & DataAttributes = {\n ...(rendersButton(render) && { type: \"button\" as const }),\n onClick,\n };\n\n return useRender<ComponentPropsWithRef<\"button\">, ToastCloseState>({\n defaultElement: \"button\",\n render,\n state: { toast: root.toast },\n className,\n style,\n children,\n props: rest,\n libraryProps,\n ref: devRef,\n });\n}\n\nToastClose.displayName = \"ToastClose\";\n"],"mappings":";;;;;AAuBA,MAAM,QAAQ,QAAQ,IAAI,aAAa;;;;;;;AAQvC,SAAgB,WAAW,EAAE,UAAU,WAAW,OAAO,QAAQ,GAAG,QAAyB;CAC3F,MAAM,OAAO,oBAAoB,aAAa;CAE9C,MAAM,SAAS,aAAa,YAAyB;EACnD,IAAI,OAEF,qBAAqB;GACnB,IAAI,CAAC,QAAQ,aAAa;GAK1B,IAAI,EAHF,QAAQ,aAAa,YAAY,KACjC,QAAQ,aAAa,iBAAiB,MACrC,QAAQ,eAAe,GAAA,CAAI,KAAK,MAAM,KAEvC,QAAQ,MACN,kFACF;EAEJ,CAAC;EAEH,aAAa,CAAC;CAChB,GAAG,CAAC,CAAC;CAEL,MAAM,WAAW,UAAyC;EACxD,IAAI,KAAK,aAAa,MAAM;EAC5B,KAAK,MAAM,WAAW,MAAM,WAAW;CACzC;CAEA,MAAM,eAAiE;EACrE,GAAI,cAAc,MAAM,KAAK,EAAE,MAAM,SAAkB;EACvD;CACF;CAEA,OAAO,UAA4D;EACjE,gBAAgB;EAChB;EACA,OAAO,EAAE,OAAO,KAAK,MAAM;EAC3B;EACA;EACA;EACA,OAAO;EACP;EACA,KAAK;CACP,CAAC;AACH;AAEA,WAAW,cAAc"}
@@ -0,0 +1,19 @@
1
+ "use client";
2
+ import { createContext, use } from "react";
3
+ //#region src/toast/toast-context.ts
4
+ const ToastViewportContext = createContext(null);
5
+ function useToastViewportContext(part) {
6
+ const context = use(ToastViewportContext);
7
+ if (context === null) throw new Error(`${part} must be rendered inside a Toast.Viewport.`);
8
+ return context;
9
+ }
10
+ const ToastRootContext = createContext(null);
11
+ function useToastRootContext(part) {
12
+ const context = use(ToastRootContext);
13
+ if (context === null) throw new Error(`${part} must be rendered inside a Toast.Root.`);
14
+ return context;
15
+ }
16
+ //#endregion
17
+ export { ToastRootContext, ToastViewportContext, useToastRootContext, useToastViewportContext };
18
+
19
+ //# sourceMappingURL=toast-context.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toast-context.mjs","names":[],"sources":["../../src/toast/toast-context.ts"],"sourcesContent":["\"use client\";\nimport { createContext, use } from \"react\";\nimport type { ChangeReason } from \"../internal/types.js\";\nimport type { ToastItem, ToastPriority } from \"./toast.js\";\n\n/** What a Root (and the parts under it) need from the Viewport. Stable for the Viewport's life. */\nexport interface ToastViewportContextValue {\n /** Close toasts (`ending: true`), moving focus out first and scheduling `closeAction`. */\n readonly close: (ids: readonly string[], reason: ChangeReason, event: Event | undefined) => void;\n /** Remove an ending toast once its exit animations finished. */\n readonly drop: (id: string) => void;\n /** An action dispatched through the toast's Action part is (no longer) in flight. */\n readonly setActionPending: (id: string, pending: boolean) => void;\n /** The toast's content is (no longer) suspended behind the Root's guard. */\n readonly setSuspended: (id: string, suspended: boolean) => void;\n /** The Root's element, for arrow keys, the hotkey and focus moves; `null` to unregister. */\n readonly registerRoot: (id: string, element: HTMLElement | null) => void;\n /** Focus the next (`1`) or previous (`-1`) toast's Root, without wrapping. */\n readonly focusSibling: (id: string, direction: 1 | -1) => void;\n /** Queue an announcement; skipped when `text` equals the last one announced for `id`. */\n readonly announce: (id: string, text: string | null, priority: ToastPriority) => void;\n /** The Viewport's `announce` prop, read at announcement time. */\n readonly announcer: () => ((toast: ToastItem) => string | null) | undefined;\n /**\n * The animations that ran in the toast before it was marked ending (kept until it is dropped\n * or replaced): its exit waits only for the others.\n */\n readonly exitBaseline: (id: string) => ReadonlySet<Animation> | undefined;\n}\n\nexport const ToastViewportContext = createContext<ToastViewportContextValue | null>(null);\n\nexport function useToastViewportContext(part: string): ToastViewportContextValue {\n const context = use(ToastViewportContext);\n if (context === null) {\n throw new Error(`${part} must be rendered inside a Toast.Viewport.`);\n }\n return context;\n}\n\n/** What the parts inside a Root need. */\nexport interface ToastRootContextValue {\n readonly toast: ToastItem;\n readonly ids: { readonly title: string; readonly description: string };\n /** Root state, so Title and Description can resolve their function props against it. */\n readonly state: ToastRootStateShape;\n readonly registerTitle: (element: HTMLElement | null) => void;\n readonly registerDescription: (element: HTMLElement | null) => void;\n /** An Action part's run is (no longer) in flight; `token` identifies the part. */\n readonly setActionPending: (token: object, pending: boolean) => void;\n /**\n * A Title or Description committed: mounted, or shown again by a Suspense boundary inside the\n * Root (the consumer's skeleton), so the Root announces the text that now exists.\n */\n readonly contentCommitted: () => void;\n /** The Suspense guard mounted (`true`) or unmounted (`false`). */\n readonly setSuspended: (suspended: boolean) => void;\n /** Close this toast. */\n readonly close: (reason: ChangeReason, event: Event | undefined) => void;\n}\n\n/** Same shape as `ToastRootState` (declared in toast-root.tsx). */\nexport interface ToastRootStateShape {\n readonly toast: ToastItem;\n readonly pending: boolean;\n readonly ending: boolean;\n readonly type: string | undefined;\n readonly priority: ToastPriority;\n}\n\nexport const ToastRootContext = createContext<ToastRootContextValue | null>(null);\n\nexport function useToastRootContext(part: string): ToastRootContextValue {\n const context = use(ToastRootContext);\n if (context === null) {\n throw new Error(`${part} must be rendered inside a Toast.Root.`);\n }\n return context;\n}\n"],"mappings":";;;AA8BA,MAAa,uBAAuB,cAAgD,IAAI;AAExF,SAAgB,wBAAwB,MAAyC;CAC/E,MAAM,UAAU,IAAI,oBAAoB;CACxC,IAAI,YAAY,MACd,MAAM,IAAI,MAAM,GAAG,KAAK,2CAA2C;CAErE,OAAO;AACT;AAgCA,MAAa,mBAAmB,cAA4C,IAAI;AAEhF,SAAgB,oBAAoB,MAAqC;CACvE,MAAM,UAAU,IAAI,gBAAgB;CACpC,IAAI,YAAY,MACd,MAAM,IAAI,MAAM,GAAG,KAAK,uCAAuC;CAEjE,OAAO;AACT"}
@@ -0,0 +1,24 @@
1
+ import { RenderProp, StateValue } from "../internal/types.mjs";
2
+ import { ToastRootState } from "./toast-root.mjs";
3
+ import { CSSProperties, ComponentPropsWithRef, ReactNode } from "react";
4
+ //#region src/toast/toast-description.d.ts
5
+ export interface ToastDescriptionProps extends Omit<ComponentPropsWithRef<"p">, "id" | "className" | "style" | "children"> {
6
+ /** Default: the toast's `description`. Without either, nothing is rendered. */
7
+ children?: StateValue<ReactNode, ToastRootState>;
8
+ className?: StateValue<string | undefined, ToastRootState>;
9
+ style?: StateValue<CSSProperties | undefined, ToastRootState>;
10
+ render?: RenderProp<ComponentPropsWithRef<"p">, ToastRootState>;
11
+ }
12
+ /**
13
+ * The toast's description: a `p` whose id the Root references with `aria-describedby`. Renders
14
+ * nothing when the part has no `children` and the toast no `description`. Its text is part of the
15
+ * default announcement.
16
+ *
17
+ * Owned key (conventions 1.2): `id`.
18
+ */
19
+ export declare function ToastDescription({ children, className, style, render, ...rest }: ToastDescriptionProps): ReactNode;
20
+ export declare namespace ToastDescription {
21
+ var displayName: string;
22
+ }
23
+ //#endregion
24
+ //# sourceMappingURL=toast-description.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toast-description.d.mts","names":[],"sources":["../../src/toast/toast-description.tsx"],"mappings":";;;;iBAQiB,8BAA8B,KAC7C;;EAIA,WAAW,WAAW,WAAW;EACjC,YAAY,+BAA+B;EAC3C,QAAQ,WAAW,2BAA2B;EAC9C,SAAS,WAAW,4BAA4B;;;;;;;;;wBAUlC,mBACd,UACA,WACA,OACA,WACG,QACF,wBAAqB;yBANR"}
@@ -0,0 +1,35 @@
1
+ "use client";
2
+ import { useRender } from "../internal/use-render.mjs";
3
+ import { useToastRootContext } from "./toast-context.mjs";
4
+ import { useLayoutEffect } from "react";
5
+ //#region src/toast/toast-description.tsx
6
+ /**
7
+ * The toast's description: a `p` whose id the Root references with `aria-describedby`. Renders
8
+ * nothing when the part has no `children` and the toast no `description`. Its text is part of the
9
+ * default announcement.
10
+ *
11
+ * Owned key (conventions 1.2): `id`.
12
+ */
13
+ function ToastDescription({ children, className, style, render, ...rest }) {
14
+ const root = useToastRootContext("Toast.Description");
15
+ const content = children ?? root.toast.description;
16
+ const { contentCommitted } = root;
17
+ useLayoutEffect(() => contentCommitted(), [contentCommitted]);
18
+ const element = useRender({
19
+ defaultElement: "p",
20
+ render,
21
+ state: root.state,
22
+ className,
23
+ style,
24
+ children: content,
25
+ props: rest,
26
+ libraryProps: { id: root.ids.description },
27
+ ref: root.registerDescription
28
+ });
29
+ return content == null || content === false ? null : element;
30
+ }
31
+ ToastDescription.displayName = "ToastDescription";
32
+ //#endregion
33
+ export { ToastDescription };
34
+
35
+ //# sourceMappingURL=toast-description.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toast-description.mjs","names":[],"sources":["../../src/toast/toast-description.tsx"],"sourcesContent":["\"use client\";\nimport { useLayoutEffect } from \"react\";\nimport type { ComponentPropsWithRef, CSSProperties, ReactNode } from \"react\";\nimport type { RenderProp, StateValue } from \"../internal/types.js\";\nimport { useRender } from \"../internal/use-render.js\";\nimport { useToastRootContext } from \"./toast-context.js\";\nimport type { ToastRootState } from \"./toast-root.js\";\n\nexport interface ToastDescriptionProps extends Omit<\n ComponentPropsWithRef<\"p\">,\n \"id\" | \"className\" | \"style\" | \"children\"\n> {\n /** Default: the toast's `description`. Without either, nothing is rendered. */\n children?: StateValue<ReactNode, ToastRootState>;\n className?: StateValue<string | undefined, ToastRootState>;\n style?: StateValue<CSSProperties | undefined, ToastRootState>;\n render?: RenderProp<ComponentPropsWithRef<\"p\">, ToastRootState>;\n}\n\n/**\n * The toast's description: a `p` whose id the Root references with `aria-describedby`. Renders\n * nothing when the part has no `children` and the toast no `description`. Its text is part of the\n * default announcement.\n *\n * Owned key (conventions 1.2): `id`.\n */\nexport function ToastDescription({\n children,\n className,\n style,\n render,\n ...rest\n}: ToastDescriptionProps) {\n const root = useToastRootContext(\"Toast.Description\");\n const content = children ?? root.toast.description;\n // Mounted, or revealed by a Suspense boundary inside the Root: announce the text now present.\n const { contentCommitted } = root;\n useLayoutEffect(() => contentCommitted(), [contentCommitted]);\n const element = useRender<ComponentPropsWithRef<\"p\">, ToastRootState>({\n defaultElement: \"p\",\n render,\n state: root.state,\n className,\n style,\n children: content,\n props: rest,\n libraryProps: { id: root.ids.description },\n ref: root.registerDescription,\n });\n return content == null || content === false ? null : element;\n}\n\nToastDescription.displayName = \"ToastDescription\";\n"],"mappings":";;;;;;;;;;;;AA0BA,SAAgB,iBAAiB,EAC/B,UACA,WACA,OACA,QACA,GAAG,QACqB;CACxB,MAAM,OAAO,oBAAoB,mBAAmB;CACpD,MAAM,UAAU,YAAY,KAAK,MAAM;CAEvC,MAAM,EAAE,qBAAqB;CAC7B,sBAAsB,iBAAiB,GAAG,CAAC,gBAAgB,CAAC;CAC5D,MAAM,UAAU,UAAsD;EACpE,gBAAgB;EAChB;EACA,OAAO,KAAK;EACZ;EACA;EACA,UAAU;EACV,OAAO;EACP,cAAc,EAAE,IAAI,KAAK,IAAI,YAAY;EACzC,KAAK,KAAK;CACZ,CAAC;CACD,OAAO,WAAW,QAAQ,YAAY,QAAQ,OAAO;AACvD;AAEA,iBAAiB,cAAc"}