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

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 (230) hide show
  1. package/dist/accordion/accordion-root.mjs +2 -1
  2. package/dist/accordion/accordion-root.mjs.map +1 -1
  3. package/dist/combobox/combobox-clear.mjs +2 -1
  4. package/dist/combobox/combobox-clear.mjs.map +1 -1
  5. package/dist/combobox/combobox-list.mjs +2 -1
  6. package/dist/combobox/combobox-list.mjs.map +1 -1
  7. package/dist/combobox/combobox-popup.d.mts.map +1 -1
  8. package/dist/combobox/combobox-popup.mjs +7 -2
  9. package/dist/combobox/combobox-popup.mjs.map +1 -1
  10. package/dist/combobox/combobox-root.mjs +1 -1
  11. package/dist/combobox/combobox-trigger.mjs +2 -1
  12. package/dist/combobox/combobox-trigger.mjs.map +1 -1
  13. package/dist/dialog/dialog-close.mjs +2 -1
  14. package/dist/dialog/dialog-close.mjs.map +1 -1
  15. package/dist/dialog/dialog-form.d.mts +14 -8
  16. package/dist/dialog/dialog-form.d.mts.map +1 -1
  17. package/dist/dialog/dialog-form.mjs +36 -5
  18. package/dist/dialog/dialog-form.mjs.map +1 -1
  19. package/dist/dialog/dialog-popup.d.mts.map +1 -1
  20. package/dist/dialog/dialog-popup.mjs +13 -5
  21. package/dist/dialog/dialog-popup.mjs.map +1 -1
  22. package/dist/dialog/dialog-root.mjs +1 -1
  23. package/dist/dialog/dialog-trigger.mjs +2 -1
  24. package/dist/dialog/dialog-trigger.mjs.map +1 -1
  25. package/dist/field/field-root.mjs +5 -3
  26. package/dist/field/field-root.mjs.map +1 -1
  27. package/dist/form/form-root.mjs +2 -1
  28. package/dist/form/form-root.mjs.map +1 -1
  29. package/dist/form/form-submit.mjs +2 -1
  30. package/dist/form/form-submit.mjs.map +1 -1
  31. package/dist/index.d.mts +27 -1
  32. package/dist/index.mjs +6 -1
  33. package/dist/internal/announce.mjs +53 -0
  34. package/dist/internal/announce.mjs.map +1 -0
  35. package/dist/internal/decimal.mjs +27 -0
  36. package/dist/internal/decimal.mjs.map +1 -0
  37. package/dist/internal/dev-warn.mjs +17 -0
  38. package/dist/internal/dev-warn.mjs.map +1 -0
  39. package/dist/internal/field-context.mjs.map +1 -1
  40. package/dist/internal/range-value.mjs +51 -0
  41. package/dist/internal/range-value.mjs.map +1 -0
  42. package/dist/internal/render-element.mjs +54 -0
  43. package/dist/internal/render-element.mjs.map +1 -0
  44. package/dist/internal/toolbar-context.mjs +17 -0
  45. package/dist/internal/toolbar-context.mjs.map +1 -0
  46. package/dist/internal/use-exit-animation.mjs +26 -6
  47. package/dist/internal/use-exit-animation.mjs.map +1 -1
  48. package/dist/internal/use-field-control.mjs +5 -3
  49. package/dist/internal/use-field-control.mjs.map +1 -1
  50. package/dist/internal/use-popover-popup.mjs +3 -2
  51. package/dist/internal/use-popover-popup.mjs.map +1 -1
  52. package/dist/internal/use-popover-trigger.mjs +1 -1
  53. package/dist/internal/use-render.mjs +11 -34
  54. package/dist/internal/use-render.mjs.map +1 -1
  55. package/dist/internal/use-roving-focus.mjs +301 -0
  56. package/dist/internal/use-roving-focus.mjs.map +1 -0
  57. package/dist/menu/menu-checkbox-item.mjs +2 -1
  58. package/dist/menu/menu-checkbox-item.mjs.map +1 -1
  59. package/dist/menu/menu-item.mjs +2 -1
  60. package/dist/menu/menu-item.mjs.map +1 -1
  61. package/dist/menu/menu-popup.d.mts.map +1 -1
  62. package/dist/menu/menu-popup.mjs +7 -2
  63. package/dist/menu/menu-popup.mjs.map +1 -1
  64. package/dist/menu/menu-radio-item.mjs +2 -1
  65. package/dist/menu/menu-radio-item.mjs.map +1 -1
  66. package/dist/menu/menu-root.mjs +1 -1
  67. package/dist/menu/menu-trigger.d.mts +2 -1
  68. package/dist/menu/menu-trigger.d.mts.map +1 -1
  69. package/dist/menu/menu-trigger.mjs +15 -4
  70. package/dist/menu/menu-trigger.mjs.map +1 -1
  71. package/dist/meter/index.d.mts +24 -0
  72. package/dist/meter/index.d.mts.map +1 -0
  73. package/dist/meter/index.mjs +23 -0
  74. package/dist/meter/index.mjs.map +1 -0
  75. package/dist/meter/meter-context.mjs +13 -0
  76. package/dist/meter/meter-context.mjs.map +1 -0
  77. package/dist/meter/meter-indicator.d.mts +19 -0
  78. package/dist/meter/meter-indicator.d.mts.map +1 -0
  79. package/dist/meter/meter-indicator.mjs +25 -0
  80. package/dist/meter/meter-indicator.mjs.map +1 -0
  81. package/dist/meter/meter-label.d.mts +19 -0
  82. package/dist/meter/meter-label.d.mts.map +1 -0
  83. package/dist/meter/meter-label.mjs +28 -0
  84. package/dist/meter/meter-label.mjs.map +1 -0
  85. package/dist/meter/meter-region.d.mts +4 -0
  86. package/dist/meter/meter-region.d.mts.map +1 -0
  87. package/dist/meter/meter-region.mjs +39 -0
  88. package/dist/meter/meter-region.mjs.map +1 -0
  89. package/dist/meter/meter-root.d.mts +71 -0
  90. package/dist/meter/meter-root.d.mts.map +1 -0
  91. package/dist/meter/meter-root.mjs +83 -0
  92. package/dist/meter/meter-root.mjs.map +1 -0
  93. package/dist/meter/meter-track.d.mts +19 -0
  94. package/dist/meter/meter-track.d.mts.map +1 -0
  95. package/dist/meter/meter-track.mjs +25 -0
  96. package/dist/meter/meter-track.mjs.map +1 -0
  97. package/dist/meter/meter-value.d.mts +20 -0
  98. package/dist/meter/meter-value.d.mts.map +1 -0
  99. package/dist/meter/meter-value.mjs +29 -0
  100. package/dist/meter/meter-value.mjs.map +1 -0
  101. package/dist/number-field/index.d.mts +26 -0
  102. package/dist/number-field/index.d.mts.map +1 -0
  103. package/dist/number-field/index.mjs +26 -0
  104. package/dist/number-field/index.mjs.map +1 -0
  105. package/dist/number-field/number-field-arithmetic.mjs +78 -0
  106. package/dist/number-field/number-field-arithmetic.mjs.map +1 -0
  107. package/dist/number-field/number-field-context.d.mts +2 -0
  108. package/dist/number-field/number-field-context.mjs +13 -0
  109. package/dist/number-field/number-field-context.mjs.map +1 -0
  110. package/dist/number-field/number-field-decrement.d.mts +16 -0
  111. package/dist/number-field/number-field-decrement.d.mts.map +1 -0
  112. package/dist/number-field/number-field-decrement.mjs +19 -0
  113. package/dist/number-field/number-field-decrement.mjs.map +1 -0
  114. package/dist/number-field/number-field-format.mjs +279 -0
  115. package/dist/number-field/number-field-format.mjs.map +1 -0
  116. package/dist/number-field/number-field-increment.d.mts +32 -0
  117. package/dist/number-field/number-field-increment.d.mts.map +1 -0
  118. package/dist/number-field/number-field-increment.mjs +68 -0
  119. package/dist/number-field/number-field-increment.mjs.map +1 -0
  120. package/dist/number-field/number-field-input.d.mts +29 -0
  121. package/dist/number-field/number-field-input.d.mts.map +1 -0
  122. package/dist/number-field/number-field-input.mjs +163 -0
  123. package/dist/number-field/number-field-input.mjs.map +1 -0
  124. package/dist/number-field/number-field-label.d.mts +23 -0
  125. package/dist/number-field/number-field-label.d.mts.map +1 -0
  126. package/dist/number-field/number-field-label.mjs +47 -0
  127. package/dist/number-field/number-field-label.mjs.map +1 -0
  128. package/dist/number-field/number-field-root.d.mts +108 -0
  129. package/dist/number-field/number-field-root.d.mts.map +1 -0
  130. package/dist/number-field/number-field-root.mjs +523 -0
  131. package/dist/number-field/number-field-root.mjs.map +1 -0
  132. package/dist/number-field/use-step-button.mjs +107 -0
  133. package/dist/number-field/use-step-button.mjs.map +1 -0
  134. package/dist/popover/popover-close.mjs +2 -1
  135. package/dist/popover/popover-close.mjs.map +1 -1
  136. package/dist/popover/popover-popup.d.mts.map +1 -1
  137. package/dist/popover/popover-popup.mjs +7 -2
  138. package/dist/popover/popover-popup.mjs.map +1 -1
  139. package/dist/popover/popover-root.mjs +1 -1
  140. package/dist/progress/index.d.mts +24 -0
  141. package/dist/progress/index.d.mts.map +1 -0
  142. package/dist/progress/index.mjs +24 -0
  143. package/dist/progress/index.mjs.map +1 -0
  144. package/dist/progress/progress-context.mjs +13 -0
  145. package/dist/progress/progress-context.mjs.map +1 -0
  146. package/dist/progress/progress-indicator.d.mts +19 -0
  147. package/dist/progress/progress-indicator.d.mts.map +1 -0
  148. package/dist/progress/progress-indicator.mjs +29 -0
  149. package/dist/progress/progress-indicator.mjs.map +1 -0
  150. package/dist/progress/progress-label.d.mts +19 -0
  151. package/dist/progress/progress-label.d.mts.map +1 -0
  152. package/dist/progress/progress-label.mjs +30 -0
  153. package/dist/progress/progress-label.mjs.map +1 -0
  154. package/dist/progress/progress-root.d.mts +68 -0
  155. package/dist/progress/progress-root.d.mts.map +1 -0
  156. package/dist/progress/progress-root.mjs +80 -0
  157. package/dist/progress/progress-root.mjs.map +1 -0
  158. package/dist/progress/progress-track.d.mts +19 -0
  159. package/dist/progress/progress-track.d.mts.map +1 -0
  160. package/dist/progress/progress-track.mjs +29 -0
  161. package/dist/progress/progress-track.mjs.map +1 -0
  162. package/dist/progress/progress-value.d.mts +20 -0
  163. package/dist/progress/progress-value.d.mts.map +1 -0
  164. package/dist/progress/progress-value.mjs +33 -0
  165. package/dist/progress/progress-value.mjs.map +1 -0
  166. package/dist/slider/slider-arithmetic.mjs +1 -17
  167. package/dist/slider/slider-arithmetic.mjs.map +1 -1
  168. package/dist/slider/slider-root.mjs +3 -2
  169. package/dist/slider/slider-root.mjs.map +1 -1
  170. package/dist/slider/slider-thumb.mjs +2 -1
  171. package/dist/slider/slider-thumb.mjs.map +1 -1
  172. package/dist/slider/slider-track.mjs +2 -1
  173. package/dist/slider/slider-track.mjs.map +1 -1
  174. package/dist/tabs/tabs-indicator.mjs +2 -1
  175. package/dist/tabs/tabs-indicator.mjs.map +1 -1
  176. package/dist/tabs/tabs-tab.mjs +2 -1
  177. package/dist/tabs/tabs-tab.mjs.map +1 -1
  178. package/dist/toast/toast-action.mjs +2 -1
  179. package/dist/toast/toast-action.mjs.map +1 -1
  180. package/dist/toast/toast-close.mjs +2 -1
  181. package/dist/toast/toast-close.mjs.map +1 -1
  182. package/dist/toast/toast-root.mjs +3 -2
  183. package/dist/toast/toast-root.mjs.map +1 -1
  184. package/dist/toast/toast-viewport.d.mts.map +1 -1
  185. package/dist/toast/toast-viewport.mjs +30 -7
  186. package/dist/toast/toast-viewport.mjs.map +1 -1
  187. package/dist/toast/toast.d.mts.map +1 -1
  188. package/dist/toast/toast.mjs +5 -1
  189. package/dist/toast/toast.mjs.map +1 -1
  190. package/dist/toggle/toggle.mjs +2 -1
  191. package/dist/toggle/toggle.mjs.map +1 -1
  192. package/dist/toggle-group/index.d.mts +16 -0
  193. package/dist/toggle-group/index.d.mts.map +1 -0
  194. package/dist/toggle-group/index.mjs +15 -0
  195. package/dist/toggle-group/index.mjs.map +1 -0
  196. package/dist/toggle-group/toggle-group-context.d.mts +4 -0
  197. package/dist/toggle-group/toggle-group-context.d.mts.map +1 -0
  198. package/dist/toggle-group/toggle-group-context.mjs +13 -0
  199. package/dist/toggle-group/toggle-group-context.mjs.map +1 -0
  200. package/dist/toggle-group/toggle-group-item.d.mts +47 -0
  201. package/dist/toggle-group/toggle-group-item.d.mts.map +1 -0
  202. package/dist/toggle-group/toggle-group-item.mjs +63 -0
  203. package/dist/toggle-group/toggle-group-item.mjs.map +1 -0
  204. package/dist/toggle-group/toggle-group-root.d.mts +95 -0
  205. package/dist/toggle-group/toggle-group-root.d.mts.map +1 -0
  206. package/dist/toggle-group/toggle-group-root.mjs +211 -0
  207. package/dist/toggle-group/toggle-group-root.mjs.map +1 -0
  208. package/dist/toolbar/index.d.mts +18 -0
  209. package/dist/toolbar/index.d.mts.map +1 -0
  210. package/dist/toolbar/index.mjs +18 -0
  211. package/dist/toolbar/index.mjs.map +1 -0
  212. package/dist/toolbar/toolbar-button.d.mts +42 -0
  213. package/dist/toolbar/toolbar-button.d.mts.map +1 -0
  214. package/dist/toolbar/toolbar-button.mjs +50 -0
  215. package/dist/toolbar/toolbar-button.mjs.map +1 -0
  216. package/dist/toolbar/toolbar-root.d.mts +38 -0
  217. package/dist/toolbar/toolbar-root.d.mts.map +1 -0
  218. package/dist/toolbar/toolbar-root.mjs +66 -0
  219. package/dist/toolbar/toolbar-root.mjs.map +1 -0
  220. package/dist/toolbar/toolbar-separator.d.mts +25 -0
  221. package/dist/toolbar/toolbar-separator.d.mts.map +1 -0
  222. package/dist/toolbar/toolbar-separator.mjs +31 -0
  223. package/dist/toolbar/toolbar-separator.mjs.map +1 -0
  224. package/dist/tooltip/tooltip-popup.mjs +2 -1
  225. package/dist/tooltip/tooltip-popup.mjs.map +1 -1
  226. package/dist/tooltip/tooltip-root.mjs +18 -2
  227. package/dist/tooltip/tooltip-root.mjs.map +1 -1
  228. package/dist/tooltip/tooltip-trigger.mjs +2 -1
  229. package/dist/tooltip/tooltip-trigger.mjs.map +1 -1
  230. package/package.json +6 -1
@@ -1 +1 @@
1
- {"version":3,"file":"toast.d.mts","names":[],"sources":["../../src/toast/toast.ts"],"mappings":";;;;YAOY;;iBAGK;;WAEN,OAAO;;;;;;;WAOP,QAAQ,QAAQ,SAAS;;iBAGnB;;WAEN;WACA,QAAQ;WACR,cAAc;;WAEd;;;;;WAKA,WAAW;;;;;;WAMX;WACA,SAAS;;;;;;;WAOT,cAAc,QAAQ,SAAS;;;;;WAK/B,aAAa,OAAO;;WAEpB;;;iBAIM,kBAAkB;WACxB;;;;;WAKA;;WAEA;;;iBAIM,2BAA2B;;WAEjC;;;iBAIM,0BAA0B;WAChC;;WAEA,QAAQ;;iBAGF,oBAAoB;;WAE1B,SAAS;;;;;WAKT,UAAU,iBAAiB,OAAO,MAAM;;;;;;;WAOxC,QAAQ,iBAAiB,oBAAoB;WAC7C;;;iBAIM;;GAEd,SAAS;WACD,MAAM,SAAS;;;;;;WAMf,UAAU,GACjB,SAAS,YAAY,IACrB,SAAS,oBAAoB,OAC1B,QAAQ;;WAEJ,SAAS,YAAY,SAAS,QAAQ;;WAEtC,UAAU;;;;;;wBAsGL,sBAAsB;;;;;;qBAqIzB,OAAO"}
1
+ {"version":3,"file":"toast.d.mts","names":[],"sources":["../../src/toast/toast.ts"],"mappings":";;;;YAOY;;iBAGK;;WAEN,OAAO;;;;;;;WAOP,QAAQ,QAAQ,SAAS;;iBAGnB;;WAEN;WACA,QAAQ;WACR,cAAc;;WAEd;;;;;WAKA,WAAW;;;;;;WAMX;WACA,SAAS;;;;;;;WAOT,cAAc,QAAQ,SAAS;;;;;WAK/B,aAAa,OAAO;;WAEpB;;;iBAIM,kBAAkB;WACxB;;;;;WAKA;;WAEA;;;iBAIM,2BAA2B;;WAEjC;;;iBAIM,0BAA0B;WAChC;;WAEA,QAAQ;;iBAGF,oBAAoB;;WAE1B,SAAS;;;;;WAKT,UAAU,iBAAiB,OAAO,MAAM;;;;;;;WAOxC,QAAQ,iBAAiB,oBAAoB;WAC7C;;;iBAIM;;GAEd,SAAS;WACD,MAAM,SAAS;;;;;;WAMf,UAAU,GACjB,SAAS,YAAY,IACrB,SAAS,oBAAoB,OAC1B,QAAQ;;WAEJ,SAAS,YAAY,SAAS,QAAQ;;WAEtC,UAAU;;;;;;wBA4GL,sBAAsB;;;;;;qBAoIzB,OAAO"}
@@ -8,6 +8,11 @@ function toastManagerInternals(manager) {
8
8
  }
9
9
  const isDev = process.env.NODE_ENV !== "production";
10
10
  let warnedServer = false;
11
+ /**
12
+ * Generated ids are unique across managers, so a Viewport whose `manager` prop changes never
13
+ * mistakes a late close from the old queue (an Undo settling) for one of the new queue's toasts.
14
+ */
15
+ let nextId = 0;
11
16
  /** On the server every method is a no-op, never buffered (design 13, product-owner amendment). */
12
17
  function onServer() {
13
18
  if (typeof document !== "undefined") return false;
@@ -32,7 +37,6 @@ function createToastManager() {
32
37
  /** Commands of the current tick, flushed together from one microtask. */
33
38
  let batch = [];
34
39
  let scheduled = false;
35
- let nextId = 0;
36
40
  const flush = () => {
37
41
  scheduled = false;
38
42
  const commands = batch;
@@ -1 +1 @@
1
- {"version":3,"file":"toast.mjs","names":[],"sources":["../../src/toast/toast.ts"],"sourcesContent":["// No \"use client\" directive: the manager uses no React and no DOM API beyond `queueMicrotask`,\n// so a Server Component may import `toast` (for its type, or to pass nothing) without a client\n// reference (design/components/toast.md 13). The parts are client modules.\nimport type { ReactNode } from \"react\";\nimport type { Action, ActionDetails, ChangeReason } from \"../internal/types.js\";\n\n/** Announcement priority and role of a toast. */\nexport type ToastPriority = \"normal\" | \"high\";\n\n/** The `action` of a toast: what `Toast.Action` renders and runs by default. */\nexport interface ToastActionOptions {\n /** The Action button's content. */\n readonly label: ReactNode;\n /**\n * Runs in the Action part's own transition (`data-pending` on the Action and the Root, the\n * timer paused). The toast closes with `reason: \"activate\"` when it resolves; a rejection\n * keeps the toast and reaches the nearest Error Boundary above the Viewport. A caught error\n * resolves the action and therefore closes the toast: rethrow after `toast.update` to keep it.\n */\n readonly action: Action<[details: ToastActionDetails]>;\n}\n\nexport interface ToastOptions {\n /** Explicit id: an existing one updates that toast. Default: generated. */\n readonly id?: string | undefined;\n readonly title?: ReactNode;\n readonly description?: ReactNode;\n /** Free-form, rendered as `data-type` on the Root (`\"success\"`, `\"error\"`, ...). */\n readonly type?: string | undefined;\n /**\n * Announcement priority and role: `\"high\"` announces with `ariaNotify` priority `\"high\"` and\n * renders the Root as an `alertdialog`. Default `\"normal\"`.\n */\n readonly priority?: ToastPriority | undefined;\n /**\n * Milliseconds before the toast closes with `reason: \"timeout\"`; `null` never. Default: the\n * Viewport's `duration`, or `null` (persistent) when the toast has an `action`. A timed action\n * toast must keep its action reachable elsewhere too (WCAG 2.2.1).\n */\n readonly duration?: number | null | undefined;\n readonly action?: ToastActionOptions | undefined;\n /**\n * Called once when the toast leaves, with the reason: `\"activate\"` (the Action part settled),\n * `\"dismiss\"` (Close, Escape, `toast.dismiss()`, a promise toast with no message for its\n * outcome) or `\"timeout\"`. Runs in the Viewport's transition; a rejection reaches the boundary\n * above the Viewport. Not called when the Viewport unmounts.\n */\n readonly closeAction?: Action<[details: ToastCloseDetails]> | undefined;\n /**\n * The text `document.ariaNotify()` speaks for this toast; `null` announces nothing. Default:\n * the Viewport's `announce`, else the text of the toast's Title and Description.\n */\n readonly announce?: ((toast: ToastItem) => string | null) | undefined;\n /** Anything the Viewport's children want to render. */\n readonly data?: unknown;\n}\n\n/** A toast in the queue, as the Viewport's `children(state)` receives it. */\nexport interface ToastItem extends ToastOptions {\n readonly id: string;\n /**\n * The promise given to `toast.promise` is unsettled, or an action dispatched through this\n * toast's Action part is in flight.\n */\n readonly pending: boolean;\n /** Closed; kept mounted (and `inert`) for its exit animation. */\n readonly ending: boolean;\n}\n\n/** Details passed to a toast's Action. */\nexport interface ToastActionDetails extends ActionDetails {\n /** The toast's id, so an inline action can `toast.update` or `toast.dismiss` its own toast. */\n readonly id: string;\n}\n\n/** Details passed to a toast's `closeAction`. */\nexport interface ToastCloseDetails extends ActionDetails {\n readonly id: string;\n /** `\"activate\"`, `\"dismiss\"` or `\"timeout\"`. */\n readonly reason: ChangeReason;\n}\n\nexport interface ToastPromiseOptions<T> {\n /** Shown at once, with `data-pending`; no timer until the promise settles. */\n readonly pending: ToastOptions;\n /**\n * Replaces the toast when the promise fulfils; omitted: the toast is dismissed. A function that\n * throws dismisses the toast, and the returned promise rejects with what it threw.\n */\n readonly success?: ToastOptions | ((value: T) => ToastOptions) | undefined;\n /**\n * Replaces the toast when the promise rejects; the returned promise then resolves with\n * `undefined` (the toast is the handler). Omitted: the toast is dismissed and the returned\n * promise rejects with the same reason. A function that throws dismisses the toast, and the\n * returned promise rejects with what it threw.\n */\n readonly error?: ToastOptions | ((reason: unknown) => ToastOptions) | undefined;\n readonly id?: string | undefined;\n}\n\n/** The queue's input: `toast(options)` and its methods. */\nexport interface ToastManager {\n /** Adds a toast (or updates the one with `options.id`) and returns its id. */\n (options: ToastOptions): string;\n readonly add: (options: ToastOptions) => string;\n /**\n * Shows `options.pending` at once and swaps to `success` / `error` when `promise` settles.\n * Returns a promise that settles with `promise`, except that a rejection resolves with\n * `undefined` when `error` was given.\n */\n readonly promise: <T>(\n promise: PromiseLike<T>,\n options: ToastPromiseOptions<T>,\n ) => Promise<T | undefined>;\n /** Changes a toast in place (same position, same element). Unknown or closed ids are ignored. */\n readonly update: (id: string, options: Partial<ToastOptions>) => void;\n /** Closes one toast, or every toast when `id` is omitted, with `reason: \"dismiss\"`. */\n readonly dismiss: (id?: string) => void;\n}\n\n// --- Internal: the command channel between a manager and its Viewport --------------------------\n\n/** A queue mutation, applied by the subscribed Viewport (or buffered until one subscribes). */\nexport type ToastCommand =\n | {\n readonly kind: \"add\";\n readonly id: string;\n readonly options: ToastOptions;\n /** Added by `toast.promise`: pending until the promise settles. */\n readonly pending: boolean;\n }\n | {\n readonly kind: \"update\";\n readonly id: string;\n readonly options: Partial<ToastOptions>;\n /** A promise settle: the options replace the toast's (keeping its id), pending ends. */\n readonly settle: boolean;\n }\n | { readonly kind: \"dismiss\"; readonly id: string | undefined };\n\n/** What a Viewport hands its manager. */\nexport interface ToastListener {\n /**\n * Takes over the toasts a previous Viewport left behind (called on subscribe, before the\n * buffer is applied).\n */\n readonly restore: (toasts: readonly RetainedToast[]) => void;\n /** Applies a batch of commands, in dispatch order. */\n readonly apply: (commands: readonly ToastCommand[]) => void;\n /** The toasts to keep when this Viewport unsubscribes. */\n readonly retain: () => readonly RetainedToast[];\n}\n\n/** A retained queue entry: what a Viewport leaves behind when it unmounts (design 14 item 11). */\nexport interface RetainedToast {\n readonly options: ToastOptions & { readonly id: string };\n readonly pending: boolean;\n /**\n * The text last announced for it (`null`: silenced), so the next Viewport does not announce\n * it again; `undefined` when nothing was announced yet.\n */\n readonly announced?: string | null | undefined;\n}\n\nexport interface ToastManagerInternals {\n /**\n * Sets the listener, hands it the retained toasts and drains the buffer into it. Returns the\n * unsubscribe function, or `null` (changing nothing) when a different listener is subscribed:\n * the second-Viewport case.\n */\n readonly subscribe: (listener: ToastListener) => (() => void) | null;\n /** Whether a listener other than `listener` is subscribed (read during render). */\n readonly isTaken: (listener: ToastListener) => boolean;\n}\n\nconst internals = new WeakMap<ToastManager, ToastManagerInternals>();\n\n/** The command channel of `manager` (library-internal). */\nexport function toastManagerInternals(manager: ToastManager): ToastManagerInternals {\n const value = internals.get(manager);\n if (value === undefined) {\n throw new TypeError(\"Toast.Viewport: `manager` must come from `createToastManager()`.\");\n }\n return value;\n}\n\nconst isDev = process.env.NODE_ENV !== \"production\";\n\nlet warnedServer = false;\n\n/** On the server every method is a no-op, never buffered (design 13, product-owner amendment). */\nfunction onServer(): boolean {\n if (typeof document !== \"undefined\") return false;\n if (isDev && !warnedServer) {\n warnedServer = true;\n console.error(\n \"toast(): called on the server. Toasts are client-only; the call does nothing. Return data \" +\n \"from the Server Function and call `toast()` on the client.\",\n );\n }\n return true;\n}\n\n/** Resets the once-per-process server warning (tests only). */\nexport function resetToastServerWarning(): void {\n warnedServer = false;\n}\n\nfunction resolveOptions<V>(\n options: ToastOptions | ((value: V) => ToastOptions),\n value: V,\n): ToastOptions {\n return typeof options === \"function\" ? options(value) : options;\n}\n\n/**\n * Creates an isolated queue: `<Toast.Viewport manager={m}>` renders it. For a second React root,\n * a micro-frontend, or a test that wants a clean queue. `toast` is the default manager.\n */\nexport function createToastManager(): ToastManager {\n let listener: ToastListener | null = null;\n let retained: readonly RetainedToast[] = [];\n /** Commands issued before any Viewport subscribed (client only). */\n let buffer: ToastCommand[] = [];\n /** Commands of the current tick, flushed together from one microtask. */\n let batch: ToastCommand[] = [];\n let scheduled = false;\n let nextId = 0;\n\n const flush = (): void => {\n scheduled = false;\n const commands = batch;\n batch = [];\n if (commands.length === 0) return;\n if (listener !== null) listener.apply(commands);\n else buffer.push(...commands);\n };\n\n // A microtask, not a synchronous dispatch: a call made inside a `startTransition` scope (an\n // action's sync prefix) is no longer inside it when the microtask runs, so the queue update is\n // urgent and shows at once even while the action is pending (design 3.4).\n const dispatch = (command: ToastCommand): void => {\n batch.push(command);\n if (scheduled) return;\n scheduled = true;\n queueMicrotask(flush);\n };\n\n const generateId = (): string => `fsui-toast-${++nextId}`;\n\n const add = (options: ToastOptions): string => {\n const id = options.id ?? generateId();\n if (onServer()) return id;\n dispatch({ kind: \"add\", id, options, pending: false });\n return id;\n };\n\n const update = (id: string, options: Partial<ToastOptions>): void => {\n if (onServer()) return;\n dispatch({ kind: \"update\", id, options, settle: false });\n };\n\n const dismiss = (id?: string): void => {\n if (onServer()) return;\n dispatch({ kind: \"dismiss\", id });\n };\n\n const promise = <T>(\n input: PromiseLike<T>,\n options: ToastPromiseOptions<T>,\n ): Promise<T | undefined> => {\n const { success, error } = options;\n if (onServer()) {\n return Promise.resolve(input).then(\n (value) => value,\n (reason: unknown) => {\n if (error !== undefined) return undefined;\n throw reason;\n },\n );\n }\n const id = options.id ?? options.pending.id ?? generateId();\n dispatch({ kind: \"add\", id, options: options.pending, pending: true });\n // The returned promise is built from the same `then`, so it settles in the same tick as the\n // toast's update and an awaiting action prop is pending exactly as long as the toast.\n // A `success` / `error` function that throws dismisses the toast (it must not stay pending\n // forever) and the returned promise rejects with what it threw: the operation's outcome is\n // known, but its message is not, and the `error` message would misreport a fulfilment.\n const settle = <V>(options: ToastOptions | ((value: V) => ToastOptions), value: V): void => {\n let resolved: ToastOptions;\n try {\n resolved = resolveOptions(options, value);\n } catch (thrown) {\n dismiss(id);\n throw thrown;\n }\n dispatch({ kind: \"update\", id, options: resolved, settle: true });\n };\n return Promise.resolve(input).then(\n (value) => {\n if (success === undefined) dismiss(id);\n else settle(success, value);\n return value;\n },\n (reason: unknown) => {\n if (error === undefined) {\n dismiss(id);\n throw reason;\n }\n settle(error, reason);\n return undefined;\n },\n );\n };\n\n const manager = Object.assign((options: ToastOptions) => add(options), {\n add,\n promise,\n update,\n dismiss,\n }) as ToastManager;\n\n internals.set(manager, {\n subscribe: (next) => {\n if (listener !== null && listener !== next) return null;\n listener = next;\n const handedOver = retained;\n retained = [];\n if (handedOver.length > 0) next.restore(handedOver);\n // Commands issued before this Viewport subscribed, in order.\n const pending = buffer;\n buffer = [];\n if (pending.length > 0) next.apply(pending);\n return () => {\n if (listener !== next) return;\n // The queue survives the Viewport (a route-level Viewport remounting on navigation does\n // not lose an Undo); timers and `closeAction`s do not.\n retained = next.retain();\n listener = null;\n };\n },\n isTaken: (candidate) => listener !== null && listener !== candidate,\n });\n\n return manager;\n}\n\n/**\n * The default toast manager: `toast({ title: \"Saved\" })` from anywhere on the client (action\n * bodies, stores, effects). `<Toast.Viewport>` without `manager` renders it. On the server every\n * call is a no-op.\n */\nexport const toast: ToastManager = createToastManager();\n"],"mappings":"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"}
1
+ {"version":3,"file":"toast.mjs","names":[],"sources":["../../src/toast/toast.ts"],"sourcesContent":["// No \"use client\" directive: the manager uses no React and no DOM API beyond `queueMicrotask`,\n// so a Server Component may import `toast` (for its type, or to pass nothing) without a client\n// reference (design/components/toast.md 13). The parts are client modules.\nimport type { ReactNode } from \"react\";\nimport type { Action, ActionDetails, ChangeReason } from \"../internal/types.js\";\n\n/** Announcement priority and role of a toast. */\nexport type ToastPriority = \"normal\" | \"high\";\n\n/** The `action` of a toast: what `Toast.Action` renders and runs by default. */\nexport interface ToastActionOptions {\n /** The Action button's content. */\n readonly label: ReactNode;\n /**\n * Runs in the Action part's own transition (`data-pending` on the Action and the Root, the\n * timer paused). The toast closes with `reason: \"activate\"` when it resolves; a rejection\n * keeps the toast and reaches the nearest Error Boundary above the Viewport. A caught error\n * resolves the action and therefore closes the toast: rethrow after `toast.update` to keep it.\n */\n readonly action: Action<[details: ToastActionDetails]>;\n}\n\nexport interface ToastOptions {\n /** Explicit id: an existing one updates that toast. Default: generated. */\n readonly id?: string | undefined;\n readonly title?: ReactNode;\n readonly description?: ReactNode;\n /** Free-form, rendered as `data-type` on the Root (`\"success\"`, `\"error\"`, ...). */\n readonly type?: string | undefined;\n /**\n * Announcement priority and role: `\"high\"` announces with `ariaNotify` priority `\"high\"` and\n * renders the Root as an `alertdialog`. Default `\"normal\"`.\n */\n readonly priority?: ToastPriority | undefined;\n /**\n * Milliseconds before the toast closes with `reason: \"timeout\"`; `null` never. Default: the\n * Viewport's `duration`, or `null` (persistent) when the toast has an `action`. A timed action\n * toast must keep its action reachable elsewhere too (WCAG 2.2.1).\n */\n readonly duration?: number | null | undefined;\n readonly action?: ToastActionOptions | undefined;\n /**\n * Called once when the toast leaves, with the reason: `\"activate\"` (the Action part settled),\n * `\"dismiss\"` (Close, Escape, `toast.dismiss()`, a promise toast with no message for its\n * outcome) or `\"timeout\"`. Runs in the Viewport's transition; a rejection reaches the boundary\n * above the Viewport. Not called when the Viewport unmounts.\n */\n readonly closeAction?: Action<[details: ToastCloseDetails]> | undefined;\n /**\n * The text `document.ariaNotify()` speaks for this toast; `null` announces nothing. Default:\n * the Viewport's `announce`, else the text of the toast's Title and Description.\n */\n readonly announce?: ((toast: ToastItem) => string | null) | undefined;\n /** Anything the Viewport's children want to render. */\n readonly data?: unknown;\n}\n\n/** A toast in the queue, as the Viewport's `children(state)` receives it. */\nexport interface ToastItem extends ToastOptions {\n readonly id: string;\n /**\n * The promise given to `toast.promise` is unsettled, or an action dispatched through this\n * toast's Action part is in flight.\n */\n readonly pending: boolean;\n /** Closed; kept mounted (and `inert`) for its exit animation. */\n readonly ending: boolean;\n}\n\n/** Details passed to a toast's Action. */\nexport interface ToastActionDetails extends ActionDetails {\n /** The toast's id, so an inline action can `toast.update` or `toast.dismiss` its own toast. */\n readonly id: string;\n}\n\n/** Details passed to a toast's `closeAction`. */\nexport interface ToastCloseDetails extends ActionDetails {\n readonly id: string;\n /** `\"activate\"`, `\"dismiss\"` or `\"timeout\"`. */\n readonly reason: ChangeReason;\n}\n\nexport interface ToastPromiseOptions<T> {\n /** Shown at once, with `data-pending`; no timer until the promise settles. */\n readonly pending: ToastOptions;\n /**\n * Replaces the toast when the promise fulfils; omitted: the toast is dismissed. A function that\n * throws dismisses the toast, and the returned promise rejects with what it threw.\n */\n readonly success?: ToastOptions | ((value: T) => ToastOptions) | undefined;\n /**\n * Replaces the toast when the promise rejects; the returned promise then resolves with\n * `undefined` (the toast is the handler). Omitted: the toast is dismissed and the returned\n * promise rejects with the same reason. A function that throws dismisses the toast, and the\n * returned promise rejects with what it threw.\n */\n readonly error?: ToastOptions | ((reason: unknown) => ToastOptions) | undefined;\n readonly id?: string | undefined;\n}\n\n/** The queue's input: `toast(options)` and its methods. */\nexport interface ToastManager {\n /** Adds a toast (or updates the one with `options.id`) and returns its id. */\n (options: ToastOptions): string;\n readonly add: (options: ToastOptions) => string;\n /**\n * Shows `options.pending` at once and swaps to `success` / `error` when `promise` settles.\n * Returns a promise that settles with `promise`, except that a rejection resolves with\n * `undefined` when `error` was given.\n */\n readonly promise: <T>(\n promise: PromiseLike<T>,\n options: ToastPromiseOptions<T>,\n ) => Promise<T | undefined>;\n /** Changes a toast in place (same position, same element). Unknown or closed ids are ignored. */\n readonly update: (id: string, options: Partial<ToastOptions>) => void;\n /** Closes one toast, or every toast when `id` is omitted, with `reason: \"dismiss\"`. */\n readonly dismiss: (id?: string) => void;\n}\n\n// --- Internal: the command channel between a manager and its Viewport --------------------------\n\n/** A queue mutation, applied by the subscribed Viewport (or buffered until one subscribes). */\nexport type ToastCommand =\n | {\n readonly kind: \"add\";\n readonly id: string;\n readonly options: ToastOptions;\n /** Added by `toast.promise`: pending until the promise settles. */\n readonly pending: boolean;\n }\n | {\n readonly kind: \"update\";\n readonly id: string;\n readonly options: Partial<ToastOptions>;\n /** A promise settle: the options replace the toast's (keeping its id), pending ends. */\n readonly settle: boolean;\n }\n | { readonly kind: \"dismiss\"; readonly id: string | undefined };\n\n/** What a Viewport hands its manager. */\nexport interface ToastListener {\n /**\n * Takes over the toasts a previous Viewport left behind (called on subscribe, before the\n * buffer is applied).\n */\n readonly restore: (toasts: readonly RetainedToast[]) => void;\n /** Applies a batch of commands, in dispatch order. */\n readonly apply: (commands: readonly ToastCommand[]) => void;\n /** The toasts to keep when this Viewport unsubscribes. */\n readonly retain: () => readonly RetainedToast[];\n}\n\n/** A retained queue entry: what a Viewport leaves behind when it unmounts (design 14 item 11). */\nexport interface RetainedToast {\n readonly options: ToastOptions & { readonly id: string };\n readonly pending: boolean;\n /**\n * The text last announced for it (`null`: silenced), so the next Viewport does not announce\n * it again; `undefined` when nothing was announced yet.\n */\n readonly announced?: string | null | undefined;\n}\n\nexport interface ToastManagerInternals {\n /**\n * Sets the listener, hands it the retained toasts and drains the buffer into it. Returns the\n * unsubscribe function, or `null` (changing nothing) when a different listener is subscribed:\n * the second-Viewport case.\n */\n readonly subscribe: (listener: ToastListener) => (() => void) | null;\n /** Whether a listener other than `listener` is subscribed (read during render). */\n readonly isTaken: (listener: ToastListener) => boolean;\n}\n\nconst internals = new WeakMap<ToastManager, ToastManagerInternals>();\n\n/** The command channel of `manager` (library-internal). */\nexport function toastManagerInternals(manager: ToastManager): ToastManagerInternals {\n const value = internals.get(manager);\n if (value === undefined) {\n throw new TypeError(\"Toast.Viewport: `manager` must come from `createToastManager()`.\");\n }\n return value;\n}\n\nconst isDev = process.env.NODE_ENV !== \"production\";\n\nlet warnedServer = false;\n\n/**\n * Generated ids are unique across managers, so a Viewport whose `manager` prop changes never\n * mistakes a late close from the old queue (an Undo settling) for one of the new queue's toasts.\n */\nlet nextId = 0;\n\n/** On the server every method is a no-op, never buffered (design 13, product-owner amendment). */\nfunction onServer(): boolean {\n if (typeof document !== \"undefined\") return false;\n if (isDev && !warnedServer) {\n warnedServer = true;\n console.error(\n \"toast(): called on the server. Toasts are client-only; the call does nothing. Return data \" +\n \"from the Server Function and call `toast()` on the client.\",\n );\n }\n return true;\n}\n\n/** Resets the once-per-process server warning (tests only). */\nexport function resetToastServerWarning(): void {\n warnedServer = false;\n}\n\nfunction resolveOptions<V>(\n options: ToastOptions | ((value: V) => ToastOptions),\n value: V,\n): ToastOptions {\n return typeof options === \"function\" ? options(value) : options;\n}\n\n/**\n * Creates an isolated queue: `<Toast.Viewport manager={m}>` renders it. For a second React root,\n * a micro-frontend, or a test that wants a clean queue. `toast` is the default manager.\n */\nexport function createToastManager(): ToastManager {\n let listener: ToastListener | null = null;\n let retained: readonly RetainedToast[] = [];\n /** Commands issued before any Viewport subscribed (client only). */\n let buffer: ToastCommand[] = [];\n /** Commands of the current tick, flushed together from one microtask. */\n let batch: ToastCommand[] = [];\n let scheduled = false;\n\n const flush = (): void => {\n scheduled = false;\n const commands = batch;\n batch = [];\n if (commands.length === 0) return;\n if (listener !== null) listener.apply(commands);\n else buffer.push(...commands);\n };\n\n // A microtask, not a synchronous dispatch: a call made inside a `startTransition` scope (an\n // action's sync prefix) is no longer inside it when the microtask runs, so the queue update is\n // urgent and shows at once even while the action is pending (design 3.4).\n const dispatch = (command: ToastCommand): void => {\n batch.push(command);\n if (scheduled) return;\n scheduled = true;\n queueMicrotask(flush);\n };\n\n const generateId = (): string => `fsui-toast-${++nextId}`;\n\n const add = (options: ToastOptions): string => {\n const id = options.id ?? generateId();\n if (onServer()) return id;\n dispatch({ kind: \"add\", id, options, pending: false });\n return id;\n };\n\n const update = (id: string, options: Partial<ToastOptions>): void => {\n if (onServer()) return;\n dispatch({ kind: \"update\", id, options, settle: false });\n };\n\n const dismiss = (id?: string): void => {\n if (onServer()) return;\n dispatch({ kind: \"dismiss\", id });\n };\n\n const promise = <T>(\n input: PromiseLike<T>,\n options: ToastPromiseOptions<T>,\n ): Promise<T | undefined> => {\n const { success, error } = options;\n if (onServer()) {\n return Promise.resolve(input).then(\n (value) => value,\n (reason: unknown) => {\n if (error !== undefined) return undefined;\n throw reason;\n },\n );\n }\n const id = options.id ?? options.pending.id ?? generateId();\n dispatch({ kind: \"add\", id, options: options.pending, pending: true });\n // The returned promise is built from the same `then`, so it settles in the same tick as the\n // toast's update and an awaiting action prop is pending exactly as long as the toast.\n // A `success` / `error` function that throws dismisses the toast (it must not stay pending\n // forever) and the returned promise rejects with what it threw: the operation's outcome is\n // known, but its message is not, and the `error` message would misreport a fulfilment.\n const settle = <V>(options: ToastOptions | ((value: V) => ToastOptions), value: V): void => {\n let resolved: ToastOptions;\n try {\n resolved = resolveOptions(options, value);\n } catch (thrown) {\n dismiss(id);\n throw thrown;\n }\n dispatch({ kind: \"update\", id, options: resolved, settle: true });\n };\n return Promise.resolve(input).then(\n (value) => {\n if (success === undefined) dismiss(id);\n else settle(success, value);\n return value;\n },\n (reason: unknown) => {\n if (error === undefined) {\n dismiss(id);\n throw reason;\n }\n settle(error, reason);\n return undefined;\n },\n );\n };\n\n const manager = Object.assign((options: ToastOptions) => add(options), {\n add,\n promise,\n update,\n dismiss,\n }) as ToastManager;\n\n internals.set(manager, {\n subscribe: (next) => {\n if (listener !== null && listener !== next) return null;\n listener = next;\n const handedOver = retained;\n retained = [];\n if (handedOver.length > 0) next.restore(handedOver);\n // Commands issued before this Viewport subscribed, in order.\n const pending = buffer;\n buffer = [];\n if (pending.length > 0) next.apply(pending);\n return () => {\n if (listener !== next) return;\n // The queue survives the Viewport (a route-level Viewport remounting on navigation does\n // not lose an Undo); timers and `closeAction`s do not.\n retained = next.retain();\n listener = null;\n };\n },\n isTaken: (candidate) => listener !== null && listener !== candidate,\n });\n\n return manager;\n}\n\n/**\n * The default toast manager: `toast({ title: \"Saved\" })` from anywhere on the client (action\n * bodies, stores, effects). `<Toast.Viewport>` without `manager` renders it. On the server every\n * call is a no-op.\n */\nexport const toast: ToastManager = createToastManager();\n"],"mappings":"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"}
@@ -4,7 +4,8 @@ import { createActionDetails } from "../internal/action-details.mjs";
4
4
  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
- import { rendersButton, useRender } from "../internal/use-render.mjs";
7
+ import { rendersButton } from "../internal/render-element.mjs";
8
+ import { useRender } from "../internal/use-render.mjs";
8
9
  //#region src/toggle/toggle.tsx
9
10
  /**
10
11
  * A two-state button (WAI-ARIA "Button" pattern, toggle variant). Renders
@@ -1 +1 @@
1
- {"version":3,"file":"toggle.mjs","names":[],"sources":["../../src/toggle/toggle.tsx"],"sourcesContent":["\"use client\";\nimport type {\n ComponentPropsWithRef,\n CSSProperties,\n MouseEvent,\n ReactNode,\n ViewTransitionClass,\n} 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 { ActionDetails, ChangeAction, RenderProp, StateValue } from \"../internal/types.js\";\nimport { useControllableAction } from \"../internal/use-controllable-action.js\";\nimport { rendersButton, useRender } from \"../internal/use-render.js\";\n\nexport interface ToggleState {\n /** Optimistic pressed state: what the user sees, including an in-flight change. */\n readonly pressed: boolean;\n /** An action dispatched by this Toggle 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 `pressedChangeAction`. */\nexport interface TogglePressedChangeDetails extends ActionDetails {\n // v0 adds nothing beyond `event`; the interface exists so fields can be added without a\n // breaking change (e.g. a `reason` if a ToggleGroup ever dispatches on an item's behalf).\n}\n\nexport interface ToggleProps extends Omit<\n ComponentPropsWithRef<\"button\">,\n \"onClick\" | \"type\" | \"aria-pressed\" | \"className\" | \"style\" | \"children\"\n> {\n /** Controlled pressed state. `undefined` means uncontrolled. */\n pressed?: boolean;\n /** Initial pressed state in uncontrolled mode. Default `false`. */\n defaultPressed?: boolean;\n /**\n * Called with the next pressed state on every user-initiated change. Runs inside the Toggle's\n * transition; may be sync or async. Rejections reach the nearest Error Boundary.\n *\n * A `setState` placed after your own `await` is not a Transition update; wrap it in\n * `startTransition` (React limitation).\n */\n pressedChangeAction?: ChangeAction<boolean, TogglePressedChangeDetails>;\n /** Renders a native disabled button; never dispatches. Default `false`. */\n disabled?: boolean;\n /**\n * Forwarded as `default` to the Toggle's `<ViewTransition>`. Default: no boundary. Animates the\n * commit that ends an action (and rollbacks), not the optimistic flip itself; animate the flip\n * with a CSS `transition` on `[data-pressed]`.\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, ToggleState>;\n style?: StateValue<CSSProperties | undefined, ToggleState>;\n /** Rendered from optimistic state inside the button; must not suspend. */\n children?: StateValue<ReactNode, ToggleState>;\n /** Replace the rendered element (element form) or take over rendering (function form). */\n render?: RenderProp<ComponentPropsWithRef<\"button\">, ToggleState>;\n}\n\n/**\n * A two-state button (WAI-ARIA \"Button\" pattern, toggle variant). Renders\n * `<button type=\"button\" aria-pressed>`; the pressed state flips optimistically and the element\n * carries `data-pending` while `pressedChangeAction` is in flight.\n */\nexport function Toggle({\n pressed,\n defaultPressed,\n pressedChangeAction,\n disabled = false,\n transition,\n className,\n style,\n children,\n render,\n ...rest\n}: ToggleProps) {\n const { optimistic, pending, dispatch } = useControllableAction<\n boolean,\n TogglePressedChangeDetails\n >({\n controlled: pressed,\n defaultValue: defaultPressed,\n initialValue: false,\n action: pressedChangeAction,\n transitionTypes: (next) => transitionTypes(\"toggle\", next ? \"press\" : \"release\"),\n warn: { component: \"Toggle\", prop: \"pressed\" },\n });\n\n const state: ToggleState = { pressed: optimistic, pending, disabled };\n\n const element = useRender<ComponentPropsWithRef<\"button\">, ToggleState>({\n defaultElement: \"button\",\n render,\n state,\n className,\n style,\n children,\n // Pass-through layer: a `render` element's own props win over these (its `type` included).\n // `type=\"button\"` only on a real button; an `<a>` or a component element does not get it.\n props: rendersButton(render) ? { ...rest, type: \"button\" } : rest,\n // Library-controlled layer: wins over a `render` element's props.\n libraryProps: {\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 button on its own.\n disabled,\n \"aria-pressed\": optimistic,\n \"data-pressed\": dataAttr(optimistic),\n \"data-pending\": dataAttr(pending),\n \"data-disabled\": dataAttr(disabled),\n onClick: (event: MouseEvent<HTMLButtonElement>) => {\n // Native buttons do not fire `click` when disabled; the guard covers `render` elements\n // that do not honour `disabled`.\n if (disabled) return;\n dispatch(!optimistic, createActionDetails(event.nativeEvent, {}));\n },\n },\n });\n\n return useTransitionBoundary(\"Toggle\", transition, element);\n}\n\nToggle.displayName = \"Toggle\";\n"],"mappings":";;;;;;;;;;;;;AAyEA,SAAgB,OAAO,EACrB,SACA,gBACA,qBACA,WAAW,OACX,YACA,WACA,OACA,UACA,QACA,GAAG,QACW;CACd,MAAM,EAAE,YAAY,SAAS,aAAa,sBAGxC;EACA,YAAY;EACZ,cAAc;EACd,cAAc;EACd,QAAQ;EACR,kBAAkB,SAAS,gBAAgB,UAAU,OAAO,UAAU,SAAS;EAC/E,MAAM;GAAE,WAAW;GAAU,MAAM;EAAU;CAC/C,CAAC;CAID,MAAM,UAAU,UAAwD;EACtE,gBAAgB;EAChB;EACA,OAAA;GAL2B,SAAS;GAAY;GAAS;EAKrD;EACJ;EACA;EACA;EAGA,OAAO,cAAc,MAAM,IAAI;GAAE,GAAG;GAAM,MAAM;EAAS,IAAI;EAE7D,cAAc;GAGZ;GACA,gBAAgB;GAChB,gBAAgB,SAAS,UAAU;GACnC,gBAAgB,SAAS,OAAO;GAChC,iBAAiB,SAAS,QAAQ;GAClC,UAAU,UAAyC;IAGjD,IAAI,UAAU;IACd,SAAS,CAAC,YAAY,oBAAoB,MAAM,aAAa,CAAC,CAAC,CAAC;GAClE;EACF;CACF,CAAC;CAED,OAAO,sBAAsB,UAAU,YAAY,OAAO;AAC5D;AAEA,OAAO,cAAc"}
1
+ {"version":3,"file":"toggle.mjs","names":[],"sources":["../../src/toggle/toggle.tsx"],"sourcesContent":["\"use client\";\nimport type {\n ComponentPropsWithRef,\n CSSProperties,\n MouseEvent,\n ReactNode,\n ViewTransitionClass,\n} 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 { ActionDetails, ChangeAction, RenderProp, StateValue } from \"../internal/types.js\";\nimport { useControllableAction } from \"../internal/use-controllable-action.js\";\nimport { rendersButton, useRender } from \"../internal/use-render.js\";\n\nexport interface ToggleState {\n /** Optimistic pressed state: what the user sees, including an in-flight change. */\n readonly pressed: boolean;\n /** An action dispatched by this Toggle 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 `pressedChangeAction`. */\nexport interface TogglePressedChangeDetails extends ActionDetails {\n // v0 adds nothing beyond `event`; the interface exists so fields can be added without a\n // breaking change (e.g. a `reason` if a ToggleGroup ever dispatches on an item's behalf).\n}\n\nexport interface ToggleProps extends Omit<\n ComponentPropsWithRef<\"button\">,\n \"onClick\" | \"type\" | \"aria-pressed\" | \"className\" | \"style\" | \"children\"\n> {\n /** Controlled pressed state. `undefined` means uncontrolled. */\n pressed?: boolean;\n /** Initial pressed state in uncontrolled mode. Default `false`. */\n defaultPressed?: boolean;\n /**\n * Called with the next pressed state on every user-initiated change. Runs inside the Toggle's\n * transition; may be sync or async. Rejections reach the nearest Error Boundary.\n *\n * A `setState` placed after your own `await` is not a Transition update; wrap it in\n * `startTransition` (React limitation).\n */\n pressedChangeAction?: ChangeAction<boolean, TogglePressedChangeDetails>;\n /** Renders a native disabled button; never dispatches. Default `false`. */\n disabled?: boolean;\n /**\n * Forwarded as `default` to the Toggle's `<ViewTransition>`. Default: no boundary. Animates the\n * commit that ends an action (and rollbacks), not the optimistic flip itself; animate the flip\n * with a CSS `transition` on `[data-pressed]`.\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, ToggleState>;\n style?: StateValue<CSSProperties | undefined, ToggleState>;\n /** Rendered from optimistic state inside the button; must not suspend. */\n children?: StateValue<ReactNode, ToggleState>;\n /** Replace the rendered element (element form) or take over rendering (function form). */\n render?: RenderProp<ComponentPropsWithRef<\"button\">, ToggleState>;\n}\n\n/**\n * A two-state button (WAI-ARIA \"Button\" pattern, toggle variant). Renders\n * `<button type=\"button\" aria-pressed>`; the pressed state flips optimistically and the element\n * carries `data-pending` while `pressedChangeAction` is in flight.\n */\nexport function Toggle({\n pressed,\n defaultPressed,\n pressedChangeAction,\n disabled = false,\n transition,\n className,\n style,\n children,\n render,\n ...rest\n}: ToggleProps) {\n const { optimistic, pending, dispatch } = useControllableAction<\n boolean,\n TogglePressedChangeDetails\n >({\n controlled: pressed,\n defaultValue: defaultPressed,\n initialValue: false,\n action: pressedChangeAction,\n transitionTypes: (next) => transitionTypes(\"toggle\", next ? \"press\" : \"release\"),\n warn: { component: \"Toggle\", prop: \"pressed\" },\n });\n\n const state: ToggleState = { pressed: optimistic, pending, disabled };\n\n const element = useRender<ComponentPropsWithRef<\"button\">, ToggleState>({\n defaultElement: \"button\",\n render,\n state,\n className,\n style,\n children,\n // Pass-through layer: a `render` element's own props win over these (its `type` included).\n // `type=\"button\"` only on a real button; an `<a>` or a component element does not get it.\n props: rendersButton(render) ? { ...rest, type: \"button\" } : rest,\n // Library-controlled layer: wins over a `render` element's props.\n libraryProps: {\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 button on its own.\n disabled,\n \"aria-pressed\": optimistic,\n \"data-pressed\": dataAttr(optimistic),\n \"data-pending\": dataAttr(pending),\n \"data-disabled\": dataAttr(disabled),\n onClick: (event: MouseEvent<HTMLButtonElement>) => {\n // Native buttons do not fire `click` when disabled; the guard covers `render` elements\n // that do not honour `disabled`.\n if (disabled) return;\n dispatch(!optimistic, createActionDetails(event.nativeEvent, {}));\n },\n },\n });\n\n return useTransitionBoundary(\"Toggle\", transition, element);\n}\n\nToggle.displayName = \"Toggle\";\n"],"mappings":";;;;;;;;;;;;;;AAyEA,SAAgB,OAAO,EACrB,SACA,gBACA,qBACA,WAAW,OACX,YACA,WACA,OACA,UACA,QACA,GAAG,QACW;CACd,MAAM,EAAE,YAAY,SAAS,aAAa,sBAGxC;EACA,YAAY;EACZ,cAAc;EACd,cAAc;EACd,QAAQ;EACR,kBAAkB,SAAS,gBAAgB,UAAU,OAAO,UAAU,SAAS;EAC/E,MAAM;GAAE,WAAW;GAAU,MAAM;EAAU;CAC/C,CAAC;CAID,MAAM,UAAU,UAAwD;EACtE,gBAAgB;EAChB;EACA,OAAA;GAL2B,SAAS;GAAY;GAAS;EAKrD;EACJ;EACA;EACA;EAGA,OAAO,cAAc,MAAM,IAAI;GAAE,GAAG;GAAM,MAAM;EAAS,IAAI;EAE7D,cAAc;GAGZ;GACA,gBAAgB;GAChB,gBAAgB,SAAS,UAAU;GACnC,gBAAgB,SAAS,OAAO;GAChC,iBAAiB,SAAS,QAAQ;GAClC,UAAU,UAAyC;IAGjD,IAAI,UAAU;IACd,SAAS,CAAC,YAAY,oBAAoB,MAAM,aAAa,CAAC,CAAC,CAAC;GAClE;EACF;CACF,CAAC;CAED,OAAO,sBAAsB,UAAU,YAAY,OAAO;AAC5D;AAEA,OAAO,cAAc"}
@@ -0,0 +1,16 @@
1
+ import "../internal/platform-attributes.mjs";
2
+ import { ToggleGroupOrientation } from "./toggle-group-context.mjs";
3
+ import { ToggleGroupItem, ToggleGroupItemProps, ToggleGroupItemState } from "./toggle-group-item.mjs";
4
+ import { ToggleGroupExclusiveProps, ToggleGroupMultipleProps, ToggleGroupRoot, ToggleGroupRootProps, ToggleGroupRootState, ToggleGroupValueChangeDetails } from "./toggle-group-root.mjs";
5
+ //#region src/toggle-group/index.d.ts
6
+ /**
7
+ * A set of toggle buttons sharing one value (design/components/toggle-group.md): several values
8
+ * by default, at most one with `exclusive`.
9
+ */
10
+ export declare const ToggleGroup: {
11
+ readonly Root: typeof ToggleGroupRoot;
12
+ readonly Item: typeof ToggleGroupItem;
13
+ };
14
+ //#endregion
15
+ export type { ToggleGroupExclusiveProps, ToggleGroupItemProps, ToggleGroupItemState, ToggleGroupMultipleProps, ToggleGroupOrientation, ToggleGroupRootProps, ToggleGroupRootState, ToggleGroupValueChangeDetails };
16
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/toggle-group/index.ts"],"mappings":";;;;;;;;;qBAUa;WAAgB,aAAI;WAAmB,aAAI"}
@@ -0,0 +1,15 @@
1
+ import { ToggleGroupItem } from "./toggle-group-item.mjs";
2
+ import { ToggleGroupRoot } from "./toggle-group-root.mjs";
3
+ //#region src/toggle-group/index.ts
4
+ /**
5
+ * A set of toggle buttons sharing one value (design/components/toggle-group.md): several values
6
+ * by default, at most one with `exclusive`.
7
+ */
8
+ const ToggleGroup = {
9
+ Root: ToggleGroupRoot,
10
+ Item: ToggleGroupItem
11
+ };
12
+ //#endregion
13
+ export { ToggleGroup };
14
+
15
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/toggle-group/index.ts"],"sourcesContent":["// Platform attribute typings (`focusgroup`, `focusgroupstart`) for consumers of this subpath\n// (conventions 7.4). Type-only.\nimport \"../internal/platform-attributes.js\";\nimport { ToggleGroupItem } from \"./toggle-group-item.js\";\nimport { ToggleGroupRoot } from \"./toggle-group-root.js\";\n\n/**\n * A set of toggle buttons sharing one value (design/components/toggle-group.md): several values\n * by default, at most one with `exclusive`.\n */\nexport const ToggleGroup = { Root: ToggleGroupRoot, Item: ToggleGroupItem } as const;\n\nexport type {\n ToggleGroupRootProps,\n ToggleGroupMultipleProps,\n ToggleGroupExclusiveProps,\n ToggleGroupRootState,\n ToggleGroupValueChangeDetails,\n ToggleGroupOrientation,\n} from \"./toggle-group-root.js\";\nexport type { ToggleGroupItemProps, ToggleGroupItemState } from \"./toggle-group-item.js\";\n"],"mappings":";;;;;;;AAUA,MAAa,cAAc;CAAE,MAAM;CAAiB,MAAM;AAAgB"}
@@ -0,0 +1,4 @@
1
+ //#region src/toggle-group/toggle-group-context.d.ts
2
+ export type ToggleGroupOrientation = "horizontal" | "vertical";
3
+ //#endregion
4
+ //# sourceMappingURL=toggle-group-context.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toggle-group-context.d.mts","names":[],"sources":["../../src/toggle-group/toggle-group-context.ts"],"mappings":";YAGY"}
@@ -0,0 +1,13 @@
1
+ "use client";
2
+ import { createContext, use } from "react";
3
+ //#region src/toggle-group/toggle-group-context.ts
4
+ const ToggleGroupContext = createContext(null);
5
+ function useToggleGroupContext(part) {
6
+ const context = use(ToggleGroupContext);
7
+ if (context === null) throw new Error(`${part} must be rendered inside a ToggleGroup.Root.`);
8
+ return context;
9
+ }
10
+ //#endregion
11
+ export { ToggleGroupContext, useToggleGroupContext };
12
+
13
+ //# sourceMappingURL=toggle-group-context.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toggle-group-context.mjs","names":[],"sources":["../../src/toggle-group/toggle-group-context.ts"],"sourcesContent":["\"use client\";\nimport { createContext, use } from \"react\";\n\nexport type ToggleGroupOrientation = \"horizontal\" | \"vertical\";\n\nexport interface ToggleGroupContextValue {\n /** Optimistic pressed values: Items render `aria-pressed` from it. */\n readonly optimistic: ReadonlySet<string>;\n /** Committed pressed values; for per-Item pending only (design 5.3). */\n readonly committed: ReadonlySet<string>;\n readonly pending: boolean;\n /** `Root disabled`. */\n readonly disabled: boolean;\n /** The effective orientation: the Toolbar's inside one. */\n readonly orientation: ToggleGroupOrientation;\n /**\n * The value whose Item renders `focusgroupstart` (standalone group with\n * `experimental_focusgroup`): the first pressed enabled Item in document order, else `null`.\n */\n readonly focusgroupStartValue: string | null;\n /** An Item was activated (stable). Computes the patch of design 5.2 against the optimistic set. */\n readonly toggle: (value: string, event: Event) => void;\n /** Registers an Item's element and value; returns the cleanup (stable; used as a callback ref). */\n readonly register: (element: HTMLElement, value: string) => () => void;\n}\n\nexport const ToggleGroupContext = createContext<ToggleGroupContextValue | null>(null);\n\nexport function useToggleGroupContext(part: string): ToggleGroupContextValue {\n const context = use(ToggleGroupContext);\n if (context === null) {\n throw new Error(`${part} must be rendered inside a ToggleGroup.Root.`);\n }\n return context;\n}\n"],"mappings":";;;AA0BA,MAAa,qBAAqB,cAA8C,IAAI;AAEpF,SAAgB,sBAAsB,MAAuC;CAC3E,MAAM,UAAU,IAAI,kBAAkB;CACtC,IAAI,YAAY,MACd,MAAM,IAAI,MAAM,GAAG,KAAK,6CAA6C;CAEvE,OAAO;AACT"}
@@ -0,0 +1,47 @@
1
+ import { RenderProp, StateValue } from "../internal/types.mjs";
2
+ import { ToggleGroupOrientation } from "./toggle-group-context.mjs";
3
+ import { CSSProperties, ComponentPropsWithRef, ReactNode, ViewTransitionClass } from "react";
4
+ //#region src/toggle-group/toggle-group-item.d.ts
5
+ export interface ToggleGroupItemState {
6
+ /** Optimistic pressed state. */
7
+ readonly pressed: boolean;
8
+ /** The group's action is in flight and this Item's optimistic state differs from its committed one. */
9
+ readonly pending: boolean;
10
+ /** Own `disabled` or the Root's. */
11
+ readonly disabled: boolean;
12
+ readonly orientation: ToggleGroupOrientation;
13
+ }
14
+ export interface ToggleGroupItemProps extends Omit<ComponentPropsWithRef<"button">, "onClick" | "type" | "value" | "tabIndex" | "aria-pressed" | "className" | "style" | "children"> {
15
+ /** The value this Item presses. Unique within the group. */
16
+ value: string;
17
+ /** Renders a native disabled button; never dispatches; skipped by arrow keys. */
18
+ disabled?: boolean;
19
+ /**
20
+ * Forwarded as `default` to the Item's `<ViewTransition>`. As on Toggle: animates the commit
21
+ * that ends the group's action (and rollbacks), not the optimistic flip, which is a CSS
22
+ * `transition` on `[data-pressed]`. Static; any value makes a mount inside a transition start a
23
+ * document view transition (issue #35).
24
+ */
25
+ transition?: ViewTransitionClass;
26
+ className?: StateValue<string | undefined, ToggleGroupItemState>;
27
+ style?: StateValue<CSSProperties | undefined, ToggleGroupItemState>;
28
+ /** Rendered from optimistic state; must not suspend. */
29
+ children?: StateValue<ReactNode, ToggleGroupItemState>;
30
+ /** Must be, or render, a `<button>` (a toggle is a button). */
31
+ render?: RenderProp<ComponentPropsWithRef<"button">, ToggleGroupItemState>;
32
+ }
33
+ /**
34
+ * One toggle of a ToggleGroup: the `Toggle` element (`<button type="button" aria-pressed>`) whose
35
+ * pressed state is the Root's (design/components/toggle-group.md 16.3). Its `tabindex` is written
36
+ * by the roving engine (the group's, or the enclosing Toolbar's).
37
+ *
38
+ * Owned keys (conventions 1.2): `type` (on a `<button>` only), `aria-pressed`, `disabled`,
39
+ * `data-pressed`, `data-pending`, `data-disabled`, `data-orientation`, `onClick`, and
40
+ * `focusgroupstart` while the Root renders `focusgroup`.
41
+ */
42
+ export declare function ToggleGroupItem({ value, disabled: disabledProp, transition, className, style, children, render, ...rest }: ToggleGroupItemProps): ReactNode;
43
+ export declare namespace ToggleGroupItem {
44
+ var displayName: string;
45
+ }
46
+ //#endregion
47
+ //# sourceMappingURL=toggle-group-item.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toggle-group-item.d.mts","names":[],"sources":["../../src/toggle-group/toggle-group-item.tsx"],"mappings":";;;;iBAgBiB;;WAEN;;WAEA;;WAEA;WACA,aAAa;;iBAGP,6BAA6B,KAC5C;;EAIA;;EAEA;;;;;;;EAOA,aAAa;EACb,YAAY,+BAA+B;EAC3C,QAAQ,WAAW,2BAA2B;;EAE9C,WAAW,WAAW,WAAW;;EAEjC,SAAS,WAAW,iCAAiC;;;;;;;;;;;wBAYvC,kBACd,OACA,UAAU,cACV,YACA,WACA,OACA,UACA,WACG,QACF,uBAAoB;yBATP"}
@@ -0,0 +1,63 @@
1
+ "use client";
2
+ import { useTransitionBoundary } from "../internal/transition-boundary.mjs";
3
+ import { dataAttr } from "../internal/data-attr.mjs";
4
+ import { rendersButton } from "../internal/render-element.mjs";
5
+ import { useRender } from "../internal/use-render.mjs";
6
+ import { useToggleGroupContext } from "./toggle-group-context.mjs";
7
+ import { useCallback } from "react";
8
+ //#region src/toggle-group/toggle-group-item.tsx
9
+ /**
10
+ * One toggle of a ToggleGroup: the `Toggle` element (`<button type="button" aria-pressed>`) whose
11
+ * pressed state is the Root's (design/components/toggle-group.md 16.3). Its `tabindex` is written
12
+ * by the roving engine (the group's, or the enclosing Toolbar's).
13
+ *
14
+ * Owned keys (conventions 1.2): `type` (on a `<button>` only), `aria-pressed`, `disabled`,
15
+ * `data-pressed`, `data-pending`, `data-disabled`, `data-orientation`, `onClick`, and
16
+ * `focusgroupstart` while the Root renders `focusgroup`.
17
+ */
18
+ function ToggleGroupItem({ value, disabled: disabledProp = false, transition, className, style, children, render, ...rest }) {
19
+ const ctx = useToggleGroupContext("ToggleGroup.Item");
20
+ const pressed = ctx.optimistic.has(value);
21
+ const pending = ctx.pending && pressed !== ctx.committed.has(value);
22
+ const disabled = ctx.disabled || disabledProp;
23
+ const { register } = ctx;
24
+ const registerRef = useCallback((el) => register(el, value), [register, value]);
25
+ const state = {
26
+ pressed,
27
+ pending,
28
+ disabled,
29
+ orientation: ctx.orientation
30
+ };
31
+ const element = useRender({
32
+ defaultElement: "button",
33
+ render,
34
+ state,
35
+ className,
36
+ style,
37
+ children,
38
+ props: rendersButton(render) ? {
39
+ ...rest,
40
+ type: "button"
41
+ } : rest,
42
+ libraryProps: {
43
+ disabled,
44
+ "aria-pressed": pressed,
45
+ "data-pressed": dataAttr(pressed),
46
+ "data-pending": dataAttr(pending),
47
+ "data-disabled": dataAttr(disabled),
48
+ "data-orientation": ctx.orientation,
49
+ ...ctx.focusgroupStartValue !== null && { focusgroupstart: ctx.focusgroupStartValue === value ? "" : void 0 },
50
+ onClick: (event) => {
51
+ if (disabled) return;
52
+ ctx.toggle(value, event.nativeEvent);
53
+ }
54
+ },
55
+ ref: registerRef
56
+ });
57
+ return useTransitionBoundary("ToggleGroup.Item", transition, element);
58
+ }
59
+ ToggleGroupItem.displayName = "ToggleGroupItem";
60
+ //#endregion
61
+ export { ToggleGroupItem };
62
+
63
+ //# sourceMappingURL=toggle-group-item.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toggle-group-item.mjs","names":[],"sources":["../../src/toggle-group/toggle-group-item.tsx"],"sourcesContent":["\"use client\";\nimport { useCallback } from \"react\";\nimport type {\n ComponentPropsWithRef,\n CSSProperties,\n MouseEvent,\n ReactNode,\n ViewTransitionClass,\n} from \"react\";\nimport { dataAttr } from \"../internal/data-attr.js\";\nimport { useTransitionBoundary } from \"../internal/transition-boundary.js\";\nimport type { RenderProp, StateValue } from \"../internal/types.js\";\nimport { rendersButton, useRender } from \"../internal/use-render.js\";\nimport { useToggleGroupContext } from \"./toggle-group-context.js\";\nimport type { ToggleGroupOrientation } from \"./toggle-group-context.js\";\n\nexport interface ToggleGroupItemState {\n /** Optimistic pressed state. */\n readonly pressed: boolean;\n /** The group's action is in flight and this Item's optimistic state differs from its committed one. */\n readonly pending: boolean;\n /** Own `disabled` or the Root's. */\n readonly disabled: boolean;\n readonly orientation: ToggleGroupOrientation;\n}\n\nexport interface ToggleGroupItemProps extends Omit<\n ComponentPropsWithRef<\"button\">,\n \"onClick\" | \"type\" | \"value\" | \"tabIndex\" | \"aria-pressed\" | \"className\" | \"style\" | \"children\"\n> {\n /** The value this Item presses. Unique within the group. */\n value: string;\n /** Renders a native disabled button; never dispatches; skipped by arrow keys. */\n disabled?: boolean;\n /**\n * Forwarded as `default` to the Item's `<ViewTransition>`. As on Toggle: animates the commit\n * that ends the group's action (and rollbacks), not the optimistic flip, which is a CSS\n * `transition` on `[data-pressed]`. Static; any value makes a mount inside a transition start a\n * document view transition (issue #35).\n */\n transition?: ViewTransitionClass;\n className?: StateValue<string | undefined, ToggleGroupItemState>;\n style?: StateValue<CSSProperties | undefined, ToggleGroupItemState>;\n /** Rendered from optimistic state; must not suspend. */\n children?: StateValue<ReactNode, ToggleGroupItemState>;\n /** Must be, or render, a `<button>` (a toggle is a button). */\n render?: RenderProp<ComponentPropsWithRef<\"button\">, ToggleGroupItemState>;\n}\n\n/**\n * One toggle of a ToggleGroup: the `Toggle` element (`<button type=\"button\" aria-pressed>`) whose\n * pressed state is the Root's (design/components/toggle-group.md 16.3). Its `tabindex` is written\n * by the roving engine (the group's, or the enclosing Toolbar's).\n *\n * Owned keys (conventions 1.2): `type` (on a `<button>` only), `aria-pressed`, `disabled`,\n * `data-pressed`, `data-pending`, `data-disabled`, `data-orientation`, `onClick`, and\n * `focusgroupstart` while the Root renders `focusgroup`.\n */\nexport function ToggleGroupItem({\n value,\n disabled: disabledProp = false,\n transition,\n className,\n style,\n children,\n render,\n ...rest\n}: ToggleGroupItemProps) {\n const ctx = useToggleGroupContext(\"ToggleGroup.Item\");\n const pressed = ctx.optimistic.has(value);\n const pending = ctx.pending && pressed !== ctx.committed.has(value);\n const disabled = ctx.disabled || disabledProp;\n const { register } = ctx;\n const registerRef = useCallback((el: HTMLElement) => register(el, value), [register, value]);\n\n const state: ToggleGroupItemState = {\n pressed,\n pending,\n disabled,\n orientation: ctx.orientation,\n };\n\n const element = useRender<ComponentPropsWithRef<\"button\">, ToggleGroupItemState>({\n defaultElement: \"button\",\n render,\n state,\n className,\n style,\n children,\n // Pass-through layer, as Toggle: a `render` element's own `type` wins.\n props: rendersButton(render) ? { ...rest, type: \"button\" } : rest,\n libraryProps: {\n disabled,\n \"aria-pressed\": pressed,\n \"data-pressed\": dataAttr(pressed),\n \"data-pending\": dataAttr(pending),\n \"data-disabled\": dataAttr(disabled),\n \"data-orientation\": ctx.orientation,\n ...(ctx.focusgroupStartValue !== null && {\n focusgroupstart: ctx.focusgroupStartValue === value ? \"\" : undefined,\n }),\n onClick: (event: MouseEvent<HTMLButtonElement>) => {\n // Native buttons do not fire `click` when disabled; the guard covers `render` elements.\n if (disabled) return;\n ctx.toggle(value, event.nativeEvent);\n },\n },\n ref: registerRef,\n });\n\n return useTransitionBoundary(\"ToggleGroup.Item\", transition, element);\n}\n\nToggleGroupItem.displayName = \"ToggleGroupItem\";\n"],"mappings":";;;;;;;;;;;;;;;;;AA0DA,SAAgB,gBAAgB,EAC9B,OACA,UAAU,eAAe,OACzB,YACA,WACA,OACA,UACA,QACA,GAAG,QACoB;CACvB,MAAM,MAAM,sBAAsB,kBAAkB;CACpD,MAAM,UAAU,IAAI,WAAW,IAAI,KAAK;CACxC,MAAM,UAAU,IAAI,WAAW,YAAY,IAAI,UAAU,IAAI,KAAK;CAClE,MAAM,WAAW,IAAI,YAAY;CACjC,MAAM,EAAE,aAAa;CACrB,MAAM,cAAc,aAAa,OAAoB,SAAS,IAAI,KAAK,GAAG,CAAC,UAAU,KAAK,CAAC;CAE3F,MAAM,QAA8B;EAClC;EACA;EACA;EACA,aAAa,IAAI;CACnB;CAEA,MAAM,UAAU,UAAiE;EAC/E,gBAAgB;EAChB;EACA;EACA;EACA;EACA;EAEA,OAAO,cAAc,MAAM,IAAI;GAAE,GAAG;GAAM,MAAM;EAAS,IAAI;EAC7D,cAAc;GACZ;GACA,gBAAgB;GAChB,gBAAgB,SAAS,OAAO;GAChC,gBAAgB,SAAS,OAAO;GAChC,iBAAiB,SAAS,QAAQ;GAClC,oBAAoB,IAAI;GACxB,GAAI,IAAI,yBAAyB,QAAQ,EACvC,iBAAiB,IAAI,yBAAyB,QAAQ,KAAK,KAAA,EAC7D;GACA,UAAU,UAAyC;IAEjD,IAAI,UAAU;IACd,IAAI,OAAO,OAAO,MAAM,WAAW;GACrC;EACF;EACA,KAAK;CACP,CAAC;CAED,OAAO,sBAAsB,oBAAoB,YAAY,OAAO;AACtE;AAEA,gBAAgB,cAAc"}
@@ -0,0 +1,95 @@
1
+ import { ActionDetails, ChangeAction, RenderProp, StateValue } from "../internal/types.mjs";
2
+ import { ToggleGroupOrientation } from "./toggle-group-context.mjs";
3
+ import { CSSProperties, ComponentPropsWithRef, ReactNode } from "react";
4
+ //#region src/toggle-group/toggle-group-root.d.ts
5
+ /** Details passed as the second argument of `valueChangeAction`, in both modes. */
6
+ export interface ToggleGroupValueChangeDetails extends ActionDetails {
7
+ /** Values this dispatch pressed (document order of their Items). Exclusive mode: `[next]` or `[]`. */
8
+ readonly added: readonly string[];
9
+ /** Values this dispatch released. Exclusive mode: `[previous]` or `[]`. */
10
+ readonly removed: readonly string[];
11
+ }
12
+ export interface ToggleGroupRootState {
13
+ /**
14
+ * Optimistic pressed values in document order of the Items (exclusive mode: `[value]` or `[]`,
15
+ * so one state shape serves both modes). The server render and the first client render use the
16
+ * value's own order. Content rendered from it must not suspend.
17
+ */
18
+ readonly value: readonly string[];
19
+ /** An action dispatched through this group is in flight. */
20
+ readonly pending: boolean;
21
+ readonly disabled: boolean;
22
+ /** The effective orientation: the Toolbar's when inside one. */
23
+ readonly orientation: ToggleGroupOrientation;
24
+ }
25
+ interface ToggleGroupRootBaseProps extends Omit<ComponentPropsWithRef<"div">, "role" | "onKeyDown" | "onFocus" | "onBlur" | "onPointerDown" | "defaultValue" | "className" | "style" | "children"> {
26
+ /** Axis of the arrow keys and `data-orientation`. Default `"horizontal"`. Ignored inside a Toolbar (dev warning). */
27
+ orientation?: ToggleGroupOrientation;
28
+ /** Whether arrows wrap from the last Item to the first. Default `true`. Ignored inside a Toolbar (dev warning). */
29
+ loop?: boolean;
30
+ /** Disables every Item (native `disabled`). */
31
+ disabled?: boolean;
32
+ /**
33
+ * Render `focusgroup="toolbar …"` and, where the browser implements it, let the browser move
34
+ * focus between the Items. Chromium 150+ only; elsewhere the JS path stays active. Ignored
35
+ * inside a Toolbar (a nested focusgroup would split the Toolbar's sequence; dev warning).
36
+ * Default `false`.
37
+ */
38
+ experimental_focusgroup?: boolean;
39
+ className?: StateValue<string | undefined, ToggleGroupRootState>;
40
+ style?: StateValue<CSSProperties | undefined, ToggleGroupRootState>;
41
+ children?: StateValue<ReactNode, ToggleGroupRootState>;
42
+ render?: RenderProp<ComponentPropsWithRef<"div">, ToggleGroupRootState>;
43
+ }
44
+ export interface ToggleGroupMultipleProps extends ToggleGroupRootBaseProps {
45
+ exclusive?: false;
46
+ /** Controlled pressed values. `[]` presses nothing; `undefined` means uncontrolled. Order is not significant; duplicates ignored. */
47
+ value?: string[];
48
+ /** Initial pressed values in uncontrolled mode. Default `[]`. */
49
+ defaultValue?: string[];
50
+ /**
51
+ * Runs inside the Root's transition whenever the set of pressed Items changes. Sync or async (a
52
+ * Server Function may be passed directly); rejections reach the nearest Error Boundary and roll
53
+ * the change back. `next` is the whole set as a fresh array in document order;
54
+ * `details.added` / `details.removed` say what changed. A `setState` after your own `await` is
55
+ * not a Transition update; wrap it in `startTransition`. Prefer a functional update keyed by
56
+ * `added` / `removed` when controlled.
57
+ */
58
+ valueChangeAction?: ChangeAction<string[], ToggleGroupValueChangeDetails>;
59
+ /** Exclusive mode only: a type error here (TypeScript's union excess-property check would let it through otherwise). */
60
+ deselectable?: never;
61
+ }
62
+ export interface ToggleGroupExclusiveProps extends ToggleGroupRootBaseProps {
63
+ /** At most one Item is pressed; `value` is `string | null`. */
64
+ exclusive: true;
65
+ /** Controlled pressed value. `null` presses nothing; `undefined` means uncontrolled. */
66
+ value?: string | null;
67
+ /** Initial pressed value in uncontrolled mode. Default `null`. */
68
+ defaultValue?: string | null;
69
+ /**
70
+ * Whether pressing the pressed Item releases it (`next === null`). Default `true`. With
71
+ * `false` that press is a no-op and dispatches nothing; `value` stays `string | null` because
72
+ * the group may start with nothing pressed, but the action is then never called with `null`.
73
+ */
74
+ deselectable?: boolean;
75
+ /** See {@link ToggleGroupMultipleProps.valueChangeAction}; `next` is the pressed value or `null`. */
76
+ valueChangeAction?: ChangeAction<string | null, ToggleGroupValueChangeDetails>;
77
+ }
78
+ /** Props of `ToggleGroup.Root`, discriminated on `exclusive`. */
79
+ export type ToggleGroupRootProps = ToggleGroupMultipleProps | ToggleGroupExclusiveProps;
80
+ /**
81
+ * `<div role="group">` that owns the pressed set, the transition and, when standalone, the roving
82
+ * focus over its Items (design/components/toggle-group.md 16.2). Inside a `Toolbar.Root` it runs
83
+ * no engine of its own: its Items are members of the Toolbar's sequence.
84
+ *
85
+ * Owned keys (conventions 1.2): `role`, `data-orientation`, `data-pending`, `data-disabled`;
86
+ * standalone also `onKeyDown`, `onFocus`, `onBlur`, `onPointerDown` and, with the flag,
87
+ * `focusgroup`.
88
+ */
89
+ export declare function ToggleGroupRoot(props: ToggleGroupRootProps): import("react").JSX.Element;
90
+ export declare namespace ToggleGroupRoot {
91
+ var displayName: string;
92
+ }
93
+ //#endregion
94
+ export type { ToggleGroupOrientation };
95
+ //# sourceMappingURL=toggle-group-root.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toggle-group-root.d.mts","names":[],"sources":["../../src/toggle-group/toggle-group-root.tsx"],"mappings":";;;;;iBA6BiB,sCAAsC;;WAE5C;;WAEA;;iBAGM;;;;;;WAMN;;WAEA;WACA;;WAEA,aAAa;;UAGd,iCAAiC,KACzC;;EAYA,cAAc;;EAEd;;EAEA;;;;;;;EAOA;EACA,YAAY,+BAA+B;EAC3C,QAAQ,WAAW,2BAA2B;EAC9C,WAAW,WAAW,WAAW;EACjC,SAAS,WAAW,8BAA8B;;iBAGnC,iCAAiC;EAChD;;EAEA;;EAEA;;;;;;;;;EASA,oBAAoB,uBAAuB;;EAE3C;;iBAGe,kCAAkC;;EAEjD;;EAEA;;EAEA;;;;;;EAMA;;EAEA,oBAAoB,4BAA4B;;;YAItC,uBAAuB,2BAA2B;;;;;;;;;;wBA6E9C,gBAAgB,OAAO,uCAAoB,IAAA;yBAA3C"}