@ttt-productions/ui-core 0.11.32 → 0.11.34

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 (218) hide show
  1. package/dist/browser/index.d.ts +2 -2
  2. package/dist/browser/index.js +1 -1
  3. package/dist/browser/index.js.map +1 -1
  4. package/dist/browser/reload-recovery-watch.d.ts +2 -2
  5. package/dist/browser/reload-recovery-watch.d.ts.map +1 -1
  6. package/dist/browser/reload-recovery-watch.js +5 -5
  7. package/dist/browser/reload-recovery-watch.js.map +1 -1
  8. package/dist/index.d.ts +3 -3
  9. package/dist/index.js +3 -3
  10. package/dist/index.js.map +1 -1
  11. package/dist/lib/format-numbers.js +2 -2
  12. package/dist/lib/format-numbers.js.map +1 -1
  13. package/dist/lib/reload-recovery.js +13 -13
  14. package/dist/lib/reload-recovery.js.map +1 -1
  15. package/dist/lib/utils.js.map +1 -1
  16. package/dist/react/components/accordion.d.ts +2 -2
  17. package/dist/react/components/accordion.d.ts.map +1 -1
  18. package/dist/react/components/accordion.js +8 -8
  19. package/dist/react/components/accordion.js.map +1 -1
  20. package/dist/react/components/action-row.d.ts +32 -0
  21. package/dist/react/components/action-row.d.ts.map +1 -0
  22. package/dist/react/components/action-row.js +16 -0
  23. package/dist/react/components/action-row.js.map +1 -0
  24. package/dist/react/components/alert-dialog.d.ts +2 -2
  25. package/dist/react/components/alert-dialog.d.ts.map +1 -1
  26. package/dist/react/components/alert-dialog.js +15 -15
  27. package/dist/react/components/alert-dialog.js.map +1 -1
  28. package/dist/react/components/alert.d.ts +2 -2
  29. package/dist/react/components/alert.d.ts.map +1 -1
  30. package/dist/react/components/alert.js +12 -12
  31. package/dist/react/components/alert.js.map +1 -1
  32. package/dist/react/components/avatar.d.ts +2 -2
  33. package/dist/react/components/avatar.d.ts.map +1 -1
  34. package/dist/react/components/avatar.js +7 -7
  35. package/dist/react/components/avatar.js.map +1 -1
  36. package/dist/react/components/badge.d.ts +2 -2
  37. package/dist/react/components/badge.d.ts.map +1 -1
  38. package/dist/react/components/badge.js +9 -9
  39. package/dist/react/components/badge.js.map +1 -1
  40. package/dist/react/components/button.d.ts +2 -2
  41. package/dist/react/components/button.d.ts.map +1 -1
  42. package/dist/react/components/button.js +28 -28
  43. package/dist/react/components/button.js.map +1 -1
  44. package/dist/react/components/card.d.ts +1 -1
  45. package/dist/react/components/card.d.ts.map +1 -1
  46. package/dist/react/components/card.js +15 -15
  47. package/dist/react/components/card.js.map +1 -1
  48. package/dist/react/components/checkbox.d.ts +2 -2
  49. package/dist/react/components/checkbox.d.ts.map +1 -1
  50. package/dist/react/components/checkbox.js +6 -6
  51. package/dist/react/components/checkbox.js.map +1 -1
  52. package/dist/react/components/collapsible.d.ts +1 -1
  53. package/dist/react/components/collapsible.d.ts.map +1 -1
  54. package/dist/react/components/collapsible.js +2 -2
  55. package/dist/react/components/collapsible.js.map +1 -1
  56. package/dist/react/components/consequence-dialog.d.ts.map +1 -1
  57. package/dist/react/components/consequence-dialog.js +4 -2
  58. package/dist/react/components/consequence-dialog.js.map +1 -1
  59. package/dist/react/components/date-picker.d.ts +1 -1
  60. package/dist/react/components/date-picker.d.ts.map +1 -1
  61. package/dist/react/components/date-picker.js +102 -66
  62. package/dist/react/components/date-picker.js.map +1 -1
  63. package/dist/react/components/date-time-picker.d.ts +1 -1
  64. package/dist/react/components/date-time-picker.d.ts.map +1 -1
  65. package/dist/react/components/date-time-picker.js +20 -18
  66. package/dist/react/components/date-time-picker.js.map +1 -1
  67. package/dist/react/components/dialog.d.ts +2 -2
  68. package/dist/react/components/dialog.d.ts.map +1 -1
  69. package/dist/react/components/dialog.js +14 -14
  70. package/dist/react/components/dialog.js.map +1 -1
  71. package/dist/react/components/dropdown-menu.d.ts +2 -2
  72. package/dist/react/components/dropdown-menu.d.ts.map +1 -1
  73. package/dist/react/components/dropdown-menu.js +23 -18
  74. package/dist/react/components/dropdown-menu.js.map +1 -1
  75. package/dist/react/components/end-of-list-indicator.d.ts +1 -1
  76. package/dist/react/components/end-of-list-indicator.js +3 -3
  77. package/dist/react/components/end-of-list-indicator.js.map +1 -1
  78. package/dist/react/components/form.d.ts +3 -3
  79. package/dist/react/components/form.d.ts.map +1 -1
  80. package/dist/react/components/form.js +17 -17
  81. package/dist/react/components/form.js.map +1 -1
  82. package/dist/react/components/format-control.d.ts +12 -5
  83. package/dist/react/components/format-control.d.ts.map +1 -1
  84. package/dist/react/components/format-control.js +23 -7
  85. package/dist/react/components/format-control.js.map +1 -1
  86. package/dist/react/components/input.d.ts +10 -10
  87. package/dist/react/components/input.d.ts.map +1 -1
  88. package/dist/react/components/input.js +11 -7
  89. package/dist/react/components/input.js.map +1 -1
  90. package/dist/react/components/label.d.ts +3 -3
  91. package/dist/react/components/label.d.ts.map +1 -1
  92. package/dist/react/components/label.js +6 -6
  93. package/dist/react/components/label.js.map +1 -1
  94. package/dist/react/components/layout/screen-adaptive-view.d.ts +2 -2
  95. package/dist/react/components/layout/screen-adaptive-view.d.ts.map +1 -1
  96. package/dist/react/components/layout/screen-adaptive-view.js +39 -35
  97. package/dist/react/components/layout/screen-adaptive-view.js.map +1 -1
  98. package/dist/react/components/list-pagination.d.ts +1 -1
  99. package/dist/react/components/list-pagination.js +10 -10
  100. package/dist/react/components/list-pagination.js.map +1 -1
  101. package/dist/react/components/menubar.d.ts +2 -2
  102. package/dist/react/components/menubar.d.ts.map +1 -1
  103. package/dist/react/components/menubar.js +17 -17
  104. package/dist/react/components/menubar.js.map +1 -1
  105. package/dist/react/components/opener-focus.d.ts +1 -1
  106. package/dist/react/components/opener-focus.d.ts.map +1 -1
  107. package/dist/react/components/opener-focus.js +3 -3
  108. package/dist/react/components/opener-focus.js.map +1 -1
  109. package/dist/react/components/pending-guard.d.ts +1 -1
  110. package/dist/react/components/pending-guard.d.ts.map +1 -1
  111. package/dist/react/components/pending-guard.js +1 -1
  112. package/dist/react/components/pending-guard.js.map +1 -1
  113. package/dist/react/components/popover.d.ts +2 -2
  114. package/dist/react/components/popover.d.ts.map +1 -1
  115. package/dist/react/components/popover.js +5 -5
  116. package/dist/react/components/popover.js.map +1 -1
  117. package/dist/react/components/progress.d.ts +2 -2
  118. package/dist/react/components/progress.d.ts.map +1 -1
  119. package/dist/react/components/progress.js +5 -5
  120. package/dist/react/components/progress.js.map +1 -1
  121. package/dist/react/components/radio-group.d.ts +2 -2
  122. package/dist/react/components/radio-group.d.ts.map +1 -1
  123. package/dist/react/components/radio-group.js +7 -7
  124. package/dist/react/components/radio-group.js.map +1 -1
  125. package/dist/react/components/relative-time.d.ts +1 -1
  126. package/dist/react/components/relative-time.d.ts.map +1 -1
  127. package/dist/react/components/relative-time.js +8 -7
  128. package/dist/react/components/relative-time.js.map +1 -1
  129. package/dist/react/components/reload-recovery-notice.d.ts +3 -3
  130. package/dist/react/components/reload-recovery-notice.js +7 -7
  131. package/dist/react/components/reload-recovery-notice.js.map +1 -1
  132. package/dist/react/components/scroll-area.d.ts +2 -2
  133. package/dist/react/components/scroll-area.d.ts.map +1 -1
  134. package/dist/react/components/scroll-area.js +6 -8
  135. package/dist/react/components/scroll-area.js.map +1 -1
  136. package/dist/react/components/scroll-to-top-button.d.ts +5 -5
  137. package/dist/react/components/scroll-to-top-button.js +9 -9
  138. package/dist/react/components/scroll-to-top-button.js.map +1 -1
  139. package/dist/react/components/search-dropdown.d.ts.map +1 -1
  140. package/dist/react/components/search-dropdown.js +8 -3
  141. package/dist/react/components/search-dropdown.js.map +1 -1
  142. package/dist/react/components/select.d.ts +2 -2
  143. package/dist/react/components/select.d.ts.map +1 -1
  144. package/dist/react/components/select.js +19 -19
  145. package/dist/react/components/select.js.map +1 -1
  146. package/dist/react/components/separator.d.ts +2 -2
  147. package/dist/react/components/separator.d.ts.map +1 -1
  148. package/dist/react/components/separator.js +5 -5
  149. package/dist/react/components/separator.js.map +1 -1
  150. package/dist/react/components/sheet.d.ts +3 -3
  151. package/dist/react/components/sheet.d.ts.map +1 -1
  152. package/dist/react/components/sheet.js +21 -21
  153. package/dist/react/components/sheet.js.map +1 -1
  154. package/dist/react/components/show-more-toggle.d.ts +2 -2
  155. package/dist/react/components/show-more-toggle.d.ts.map +1 -1
  156. package/dist/react/components/show-more-toggle.js +6 -6
  157. package/dist/react/components/show-more-toggle.js.map +1 -1
  158. package/dist/react/components/skeleton.d.ts +1 -1
  159. package/dist/react/components/skeleton.d.ts.map +1 -1
  160. package/dist/react/components/skeleton.js +3 -3
  161. package/dist/react/components/skeleton.js.map +1 -1
  162. package/dist/react/components/slider.d.ts +2 -2
  163. package/dist/react/components/slider.d.ts.map +1 -1
  164. package/dist/react/components/slider.js +5 -5
  165. package/dist/react/components/slider.js.map +1 -1
  166. package/dist/react/components/spinner.d.ts +1 -1
  167. package/dist/react/components/spinner.d.ts.map +1 -1
  168. package/dist/react/components/spinner.js +10 -10
  169. package/dist/react/components/spinner.js.map +1 -1
  170. package/dist/react/components/switch.d.ts +2 -2
  171. package/dist/react/components/switch.d.ts.map +1 -1
  172. package/dist/react/components/switch.js +13 -8
  173. package/dist/react/components/switch.js.map +1 -1
  174. package/dist/react/components/table.d.ts +2 -2
  175. package/dist/react/components/table.d.ts.map +1 -1
  176. package/dist/react/components/table.js +24 -24
  177. package/dist/react/components/table.js.map +1 -1
  178. package/dist/react/components/tabs.d.ts +2 -2
  179. package/dist/react/components/tabs.d.ts.map +1 -1
  180. package/dist/react/components/tabs.js +7 -7
  181. package/dist/react/components/tabs.js.map +1 -1
  182. package/dist/react/components/textarea.d.ts +5 -5
  183. package/dist/react/components/textarea.d.ts.map +1 -1
  184. package/dist/react/components/textarea.js +11 -7
  185. package/dist/react/components/textarea.js.map +1 -1
  186. package/dist/react/components/toast.d.ts +4 -4
  187. package/dist/react/components/toast.d.ts.map +1 -1
  188. package/dist/react/components/toast.js +25 -25
  189. package/dist/react/components/toast.js.map +1 -1
  190. package/dist/react/components/toaster.d.ts.map +1 -1
  191. package/dist/react/components/toaster.js +5 -5
  192. package/dist/react/components/toaster.js.map +1 -1
  193. package/dist/react/components/tooltip.d.ts +2 -2
  194. package/dist/react/components/tooltip.d.ts.map +1 -1
  195. package/dist/react/components/tooltip.js +5 -5
  196. package/dist/react/components/tooltip.js.map +1 -1
  197. package/dist/react/hooks/use-async-action.js +2 -2
  198. package/dist/react/hooks/use-async-action.js.map +1 -1
  199. package/dist/react/hooks/use-cursor-page.d.ts +1 -1
  200. package/dist/react/hooks/use-cursor-page.js +2 -2
  201. package/dist/react/hooks/use-cursor-page.js.map +1 -1
  202. package/dist/react/hooks/use-media-query.js +5 -5
  203. package/dist/react/hooks/use-media-query.js.map +1 -1
  204. package/dist/react/hooks/use-paged-list.js +2 -2
  205. package/dist/react/hooks/use-paged-list.js.map +1 -1
  206. package/dist/react/hooks/use-return-scroll.d.ts +1 -1
  207. package/dist/react/hooks/use-return-scroll.d.ts.map +1 -1
  208. package/dist/react/hooks/use-return-scroll.js +11 -11
  209. package/dist/react/hooks/use-return-scroll.js.map +1 -1
  210. package/dist/react/hooks/use-toast.d.ts +3 -3
  211. package/dist/react/hooks/use-toast.d.ts.map +1 -1
  212. package/dist/react/hooks/use-toast.js +17 -17
  213. package/dist/react/hooks/use-toast.js.map +1 -1
  214. package/dist/react/index.d.ts +74 -72
  215. package/dist/react/index.d.ts.map +1 -1
  216. package/dist/react/index.js +51 -50
  217. package/dist/react/index.js.map +1 -1
  218. package/package.json +8 -6
@@ -1,11 +1,11 @@
1
- import * as React from "react";
2
- import type { DeclaredInputFormat } from "@ttt-productions/input-format-core";
3
- type NativeTextareaProps = React.ComponentPropsWithoutRef<"textarea">;
1
+ import * as React from 'react';
2
+ import type { DeclaredInputFormat } from '@ttt-productions/input-format-core';
3
+ type NativeTextareaProps = React.ComponentPropsWithoutRef<'textarea'>;
4
4
  /**
5
5
  * A multi-line free-text input: its declaration is required, and its length bounds come only from
6
6
  * that declaration (ENG-005), so `maxLength`, `minLength`, and `required` are not props.
7
7
  */
8
- export type FreeTextTextareaProps = Omit<NativeTextareaProps, "maxLength" | "minLength" | "required"> & {
8
+ export type FreeTextTextareaProps = Omit<NativeTextareaProps, 'maxLength' | 'minLength' | 'required'> & {
9
9
  inputFormat: DeclaredInputFormat;
10
10
  textEntry?: never;
11
11
  };
@@ -15,7 +15,7 @@ export type FreeTextTextareaProps = Omit<NativeTextareaProps, "maxLength" | "min
15
15
  * by its own rule (the one-segment id rule, or the item's own field declaration) — so the box has
16
16
  * no input format of its own.
17
17
  */
18
- export type NonFreeTextareaEntry = "identifier" | "list";
18
+ export type NonFreeTextareaEntry = 'identifier' | 'list';
19
19
  /** A multi-line box that is not free text: no input format; native bounds stay the caller's. */
20
20
  export type NonFreeTextTextareaProps = NativeTextareaProps & {
21
21
  textEntry: NonFreeTextareaEntry;
@@ -1 +1 @@
1
- {"version":3,"file":"textarea.d.ts","sourceRoot":"","sources":["../../../src/react/components/textarea.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAA;AAI7E,KAAK,mBAAmB,GAAG,KAAK,CAAC,wBAAwB,CAAC,UAAU,CAAC,CAAA;AAErE;;;GAGG;AACH,MAAM,MAAM,qBAAqB,GAAG,IAAI,CAAC,mBAAmB,EAAE,WAAW,GAAG,WAAW,GAAG,UAAU,CAAC,GAAG;IACtG,WAAW,EAAE,mBAAmB,CAAA;IAChC,SAAS,CAAC,EAAE,KAAK,CAAA;CAClB,CAAA;AAED;;;;;GAKG;AACH,MAAM,MAAM,oBAAoB,GAAG,YAAY,GAAG,MAAM,CAAA;AAExD,gGAAgG;AAChG,MAAM,MAAM,wBAAwB,GAAG,mBAAmB,GAAG;IAC3D,SAAS,EAAE,oBAAoB,CAAA;IAC/B,WAAW,CAAC,EAAE,KAAK,CAAA;CACpB,CAAA;AAED,MAAM,MAAM,aAAa,GAAG,qBAAqB,GAAG,wBAAwB,CAAA;AAE5E,QAAA,MAAM,QAAQ,2FAeb,CAAA;AAGD,OAAO,EAAE,QAAQ,EAAE,CAAA"}
1
+ {"version":3,"file":"textarea.d.ts","sourceRoot":"","sources":["../../../src/react/components/textarea.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AAI9E,KAAK,mBAAmB,GAAG,KAAK,CAAC,wBAAwB,CAAC,UAAU,CAAC,CAAC;AAEtE;;;GAGG;AACH,MAAM,MAAM,qBAAqB,GAAG,IAAI,CACtC,mBAAmB,EACnB,WAAW,GAAG,WAAW,GAAG,UAAU,CACvC,GAAG;IACF,WAAW,EAAE,mBAAmB,CAAC;IACjC,SAAS,CAAC,EAAE,KAAK,CAAC;CACnB,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,oBAAoB,GAAG,YAAY,GAAG,MAAM,CAAC;AAEzD,gGAAgG;AAChG,MAAM,MAAM,wBAAwB,GAAG,mBAAmB,GAAG;IAC3D,SAAS,EAAE,oBAAoB,CAAC;IAChC,WAAW,CAAC,EAAE,KAAK,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,qBAAqB,GAAG,wBAAwB,CAAC;AAE7E,QAAA,MAAM,QAAQ,2FAmBb,CAAC;AAGF,OAAO,EAAE,QAAQ,EAAE,CAAC"}
@@ -1,13 +1,17 @@
1
- "use client";
1
+ 'use client';
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
- import * as React from "react";
4
- import { cn } from "../../lib/utils.js";
5
- import { formatControlAttributes } from "./format-control.js";
3
+ import * as React from 'react';
4
+ import { cn } from '../../lib/utils.js';
5
+ import { formatControlAttributes, tidyOnBlur } from './format-control.js';
6
6
  const Textarea = React.forwardRef(
7
7
  // `textEntry` only selects the prop shape; it never reaches the DOM.
8
- ({ className, inputFormat, textEntry: _textEntry, ...props }, ref) => {
9
- return (_jsx("textarea", { className: cn("flex min-h-[80px] w-full rounded-md border-2 border-input bg-background px-3 py-2 text-base ring-offset-background placeholder:text-muted-foreground focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm", className), ref: ref, ...props, ...(inputFormat ? formatControlAttributes(inputFormat, props) : {}) }));
8
+ ({ className, inputFormat, textEntry: _textEntry, onBlur, ...props }, ref) => {
9
+ return (_jsx("textarea", { className: cn('flex min-h-[80px] w-full rounded-md border-2 border-input bg-background px-3 py-2 text-base ring-offset-background placeholder:text-muted-foreground focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm', className), ref: ref, ...props, ...(inputFormat ? formatControlAttributes(inputFormat, props) : {}), onBlur: (event) => {
10
+ if (inputFormat)
11
+ tidyOnBlur(event.currentTarget, inputFormat);
12
+ onBlur?.(event);
13
+ } }));
10
14
  });
11
- Textarea.displayName = "Textarea";
15
+ Textarea.displayName = 'Textarea';
12
16
  export { Textarea };
13
17
  //# sourceMappingURL=textarea.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"textarea.js","sourceRoot":"","sources":["../../../src/react/components/textarea.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,EAAE,EAAE,EAAE,MAAM,oBAAoB,CAAA;AACvC,OAAO,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAA;AA6B7D,MAAM,QAAQ,GAAG,KAAK,CAAC,UAAU;AAC/B,qEAAqE;AACrE,CAAC,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,KAAK,EAAE,EAAE,GAAG,EAAE,EAAE;IACnE,OAAO,CACL,mBACE,SAAS,EAAE,EAAE,CACX,uTAAuT,EACvT,SAAS,CACV,EACD,GAAG,EAAE,GAAG,KACJ,KAAK,KACL,CAAC,WAAW,CAAC,CAAC,CAAC,uBAAuB,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,GACpE,CACH,CAAA;AACH,CAAC,CACF,CAAA;AACD,QAAQ,CAAC,WAAW,GAAG,UAAU,CAAA;AAEjC,OAAO,EAAE,QAAQ,EAAE,CAAA","sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport type { DeclaredInputFormat } from \"@ttt-productions/input-format-core\"\nimport { cn } from \"../../lib/utils.js\"\nimport { formatControlAttributes } from \"./format-control.js\"\n\ntype NativeTextareaProps = React.ComponentPropsWithoutRef<\"textarea\">\n\n/**\n * A multi-line free-text input: its declaration is required, and its length bounds come only from\n * that declaration (ENG-005), so `maxLength`, `minLength`, and `required` are not props.\n */\nexport type FreeTextTextareaProps = Omit<NativeTextareaProps, \"maxLength\" | \"minLength\" | \"required\"> & {\n inputFormat: DeclaredInputFormat\n textEntry?: never\n}\n\n/**\n * What a multi-line box that is not free text holds: identifiers (account, document, or case ids),\n * or a list of items. The box's text is split into items by the consumer, and each item is judged\n * by its own rule (the one-segment id rule, or the item's own field declaration) — so the box has\n * no input format of its own.\n */\nexport type NonFreeTextareaEntry = \"identifier\" | \"list\"\n\n/** A multi-line box that is not free text: no input format; native bounds stay the caller's. */\nexport type NonFreeTextTextareaProps = NativeTextareaProps & {\n textEntry: NonFreeTextareaEntry\n inputFormat?: never\n}\n\nexport type TextareaProps = FreeTextTextareaProps | NonFreeTextTextareaProps\n\nconst Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(\n // `textEntry` only selects the prop shape; it never reaches the DOM.\n ({ className, inputFormat, textEntry: _textEntry, ...props }, ref) => {\n return (\n <textarea\n className={cn(\n \"flex min-h-[80px] w-full rounded-md border-2 border-input bg-background px-3 py-2 text-base ring-offset-background placeholder:text-muted-foreground focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm\",\n className\n )}\n ref={ref}\n {...props}\n {...(inputFormat ? formatControlAttributes(inputFormat, props) : {})}\n />\n )\n }\n)\nTextarea.displayName = \"Textarea\"\n\nexport { Textarea }\n"]}
1
+ {"version":3,"file":"textarea.js","sourceRoot":"","sources":["../../../src/react/components/textarea.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,EAAE,EAAE,EAAE,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,uBAAuB,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAgC1E,MAAM,QAAQ,GAAG,KAAK,CAAC,UAAU;AAC/B,qEAAqE;AACrE,CAAC,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,KAAK,EAAE,EAAE,GAAG,EAAE,EAAE;IAC3E,OAAO,CACL,mBACE,SAAS,EAAE,EAAE,CACX,uTAAuT,EACvT,SAAS,CACV,EACD,GAAG,EAAE,GAAG,KACJ,KAAK,KACL,CAAC,WAAW,CAAC,CAAC,CAAC,uBAAuB,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EACpE,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE;YAChB,IAAI,WAAW;gBAAE,UAAU,CAAC,KAAK,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC;YAC9D,MAAM,EAAE,CAAC,KAAK,CAAC,CAAC;QAClB,CAAC,GACD,CACH,CAAC;AACJ,CAAC,CACF,CAAC;AACF,QAAQ,CAAC,WAAW,GAAG,UAAU,CAAC;AAElC,OAAO,EAAE,QAAQ,EAAE,CAAC","sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport type { DeclaredInputFormat } from '@ttt-productions/input-format-core';\nimport { cn } from '../../lib/utils.js';\nimport { formatControlAttributes, tidyOnBlur } from './format-control.js';\n\ntype NativeTextareaProps = React.ComponentPropsWithoutRef<'textarea'>;\n\n/**\n * A multi-line free-text input: its declaration is required, and its length bounds come only from\n * that declaration (ENG-005), so `maxLength`, `minLength`, and `required` are not props.\n */\nexport type FreeTextTextareaProps = Omit<\n NativeTextareaProps,\n 'maxLength' | 'minLength' | 'required'\n> & {\n inputFormat: DeclaredInputFormat;\n textEntry?: never;\n};\n\n/**\n * What a multi-line box that is not free text holds: identifiers (account, document, or case ids),\n * or a list of items. The box's text is split into items by the consumer, and each item is judged\n * by its own rule (the one-segment id rule, or the item's own field declaration) — so the box has\n * no input format of its own.\n */\nexport type NonFreeTextareaEntry = 'identifier' | 'list';\n\n/** A multi-line box that is not free text: no input format; native bounds stay the caller's. */\nexport type NonFreeTextTextareaProps = NativeTextareaProps & {\n textEntry: NonFreeTextareaEntry;\n inputFormat?: never;\n};\n\nexport type TextareaProps = FreeTextTextareaProps | NonFreeTextTextareaProps;\n\nconst Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(\n // `textEntry` only selects the prop shape; it never reaches the DOM.\n ({ className, inputFormat, textEntry: _textEntry, onBlur, ...props }, ref) => {\n return (\n <textarea\n className={cn(\n 'flex min-h-[80px] w-full rounded-md border-2 border-input bg-background px-3 py-2 text-base ring-offset-background placeholder:text-muted-foreground focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',\n className,\n )}\n ref={ref}\n {...props}\n {...(inputFormat ? formatControlAttributes(inputFormat, props) : {})}\n onBlur={(event) => {\n if (inputFormat) tidyOnBlur(event.currentTarget, inputFormat);\n onBlur?.(event);\n }}\n />\n );\n },\n);\nTextarea.displayName = 'Textarea';\n\nexport { Textarea };\n"]}
@@ -1,6 +1,6 @@
1
- import * as React from "react";
2
- import * as ToastPrimitives from "@radix-ui/react-toast";
3
- import { type VariantProps } from "class-variance-authority";
1
+ import * as React from 'react';
2
+ import * as ToastPrimitives from '@radix-ui/react-toast';
3
+ import { type VariantProps } from 'class-variance-authority';
4
4
  declare const ToastProvider: React.FC<ToastPrimitives.ToastProviderProps>;
5
5
  declare const ToastViewport: React.ForwardRefExoticComponent<Omit<ToastPrimitives.ToastViewportProps & React.RefAttributes<HTMLOListElement>, "ref"> & React.RefAttributes<HTMLOListElement>>;
6
6
  declare const Toast: React.ForwardRefExoticComponent<Omit<ToastPrimitives.ToastProps & React.RefAttributes<HTMLLIElement>, "ref"> & VariantProps<(props?: ({
@@ -20,5 +20,5 @@ declare const ToastDescription: React.ForwardRefExoticComponent<Omit<ToastPrimit
20
20
  /** Exported types for consumers */
21
21
  export type ToastProps = React.ComponentPropsWithoutRef<typeof Toast>;
22
22
  export type ToastActionElement = React.ReactElement<typeof ToastAction>;
23
- export { ToastProvider, ToastViewport, Toast, ToastTitle, ToastDescription, ToastClose, ToastAction };
23
+ export { ToastProvider, ToastViewport, Toast, ToastTitle, ToastDescription, ToastClose, ToastAction, };
24
24
  //# sourceMappingURL=toast.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"toast.d.ts","sourceRoot":"","sources":["../../../src/react/components/toast.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,eAAe,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAkDlE,QAAA,MAAM,aAAa,8CAA2B,CAAC;AAE/C,QAAA,MAAM,aAAa,kKAajB,CAAC;AAaH,QAAA,MAAM,KAAK;;;IARP,4CAA4C;eACjC,MAAM;IACjB,oBAAoB;kBACN,OAAO;IACrB,oDAAoD;iBACvC,OAAO;uCAwEvB,CAAC;AAGF,QAAA,MAAM,WAAW,kKAKf,CAAC;AAGH,QAAA,MAAM,UAAU,iKAcd,CAAC;AAGH,QAAA,MAAM,UAAU,2JAKd,CAAC;AAGH,QAAA,MAAM,gBAAgB,iKAKpB,CAAC;AAGH,mCAAmC;AACnC,MAAM,MAAM,UAAU,GAAG,KAAK,CAAC,wBAAwB,CAAC,OAAO,KAAK,CAAC,CAAC;AACtE,MAAM,MAAM,kBAAkB,GAAG,KAAK,CAAC,YAAY,CAAC,OAAO,WAAW,CAAC,CAAC;AAExE,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC"}
1
+ {"version":3,"file":"toast.d.ts","sourceRoot":"","sources":["../../../src/react/components/toast.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,eAAe,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAsDlE,QAAA,MAAM,aAAa,8CAA2B,CAAC;AAE/C,QAAA,MAAM,aAAa,kKAajB,CAAC;AAaH,QAAA,MAAM,KAAK;;;IARP,4CAA4C;eACjC,MAAM;IACjB,oBAAoB;kBACN,OAAO;IACrB,oDAAoD;iBACvC,OAAO;uCAqFvB,CAAC;AAGF,QAAA,MAAM,WAAW,kKAKf,CAAC;AAGH,QAAA,MAAM,UAAU,iKAcd,CAAC;AAGH,QAAA,MAAM,UAAU,2JAKd,CAAC;AAGH,QAAA,MAAM,gBAAgB,iKAKpB,CAAC;AAGH,mCAAmC;AACnC,MAAM,MAAM,UAAU,GAAG,KAAK,CAAC,wBAAwB,CAAC,OAAO,KAAK,CAAC,CAAC;AACtE,MAAM,MAAM,kBAAkB,GAAG,KAAK,CAAC,YAAY,CAAC,OAAO,WAAW,CAAC,CAAC;AAExE,OAAO,EACL,aAAa,EACb,aAAa,EACb,KAAK,EACL,UAAU,EACV,gBAAgB,EAChB,UAAU,EACV,WAAW,GACZ,CAAC"}
@@ -1,9 +1,9 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import * as React from "react";
3
- import * as ToastPrimitives from "@radix-ui/react-toast";
4
- import { cva } from "class-variance-authority";
5
- import { X } from "lucide-react";
6
- import { cn } from "../../lib/utils.js";
2
+ import * as React from 'react';
3
+ import * as ToastPrimitives from '@radix-ui/react-toast';
4
+ import { cva } from 'class-variance-authority';
5
+ import { X } from 'lucide-react';
6
+ import { cn } from '../../lib/utils.js';
7
7
  /**
8
8
  * ui-core Toasts are consumed by multiple apps.
9
9
  *
@@ -18,24 +18,24 @@ function ToastKeyframes() {
18
18
  }
19
19
  const toastVariants = cva(cn(
20
20
  // base
21
- "pointer-events-auto relative flex w-full items-start justify-between gap-2 overflow-hidden rounded-md border bg-background p-4 text-foreground elevation-raised transition-all",
21
+ 'pointer-events-auto relative flex w-full items-start justify-between gap-2 overflow-hidden rounded-md border bg-background p-4 text-foreground elevation-raised duration-[var(--motion-base)] ease-[var(--motion-ease)]',
22
22
  // radix state/animation
23
- "data-[state=open]:animate-in data-[state=closed]:animate-out", "data-[state=closed]:fade-out-80 data-[state=open]:fade-in-80", "data-[state=closed]:slide-out-to-top-full data-[state=open]:slide-in-from-top-full", "data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)]", "data-[swipe=cancel]:translate-x-0 data-[swipe=cancel]:transition-[transform_200ms_ease-out]", "data-[swipe=end]:animate-out data-[swipe=end]:slide-out-to-right-full"), {
23
+ 'data-[state=open]:animate-in data-[state=closed]:animate-out', 'data-[state=closed]:fade-out-80 data-[state=open]:fade-in-80', 'data-[state=closed]:slide-out-to-top-full data-[state=open]:slide-in-from-top-full', 'data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)]', 'data-[swipe=cancel]:translate-x-0 data-[swipe=cancel]:transition-transform', 'data-[swipe=end]:animate-out data-[swipe=end]:slide-out-to-right-full'), {
24
24
  variants: {
25
25
  variant: {
26
- default: "",
27
- destructive: "border-[color:var(--toast-destructive-border)] bg-[color:var(--toast-destructive)] text-[color:var(--toast-destructive-foreground)]",
28
- success: "border-[color:var(--toast-success-border)] bg-[color:var(--toast-success)] text-[color:var(--toast-success-foreground)]",
29
- warning: "border-[color:var(--toast-warning-border)] bg-[color:var(--toast-warning)] text-[color:var(--toast-warning-foreground)]",
30
- error: "border-[color:var(--toast-destructive-border)] bg-[color:var(--toast-destructive)] text-[color:var(--toast-destructive-foreground)]",
26
+ default: '',
27
+ destructive: 'border-[color:var(--toast-destructive-border)] bg-[color:var(--toast-destructive)] text-[color:var(--toast-destructive-foreground)]',
28
+ success: 'border-[color:var(--toast-success-border)] bg-[color:var(--toast-success)] text-[color:var(--toast-success-foreground)]',
29
+ warning: 'border-[color:var(--toast-warning-border)] bg-[color:var(--toast-warning)] text-[color:var(--toast-warning-foreground)]',
30
+ error: 'border-[color:var(--toast-destructive-border)] bg-[color:var(--toast-destructive)] text-[color:var(--toast-destructive-foreground)]',
31
31
  },
32
32
  },
33
33
  defaultVariants: {
34
- variant: "default",
34
+ variant: 'default',
35
35
  },
36
36
  });
37
37
  const ToastProvider = ToastPrimitives.Provider;
38
- const ToastViewport = React.forwardRef(({ className, ...props }, ref) => (_jsx(ToastPrimitives.Viewport, { ref: ref, className: cn("fixed top-0 left-1/2 -translate-x-1/2 z-[100] flex max-h-screen w-full flex-col gap-2 p-4", "sm:max-w-[480px] md:max-w-[600px]", className), ...props })));
38
+ const ToastViewport = React.forwardRef(({ className, ...props }, ref) => (_jsx(ToastPrimitives.Viewport, { ref: ref, className: cn('fixed top-0 left-1/2 -translate-x-1/2 z-[100] flex max-h-screen w-full flex-col gap-2 p-4', 'sm:max-w-[480px] md:max-w-[600px]', className), ...props })));
39
39
  ToastViewport.displayName = ToastPrimitives.Viewport.displayName;
40
40
  const Toast = React.forwardRef(({ className, variant, duration, dismissible = true, persistent = false, style, children, onOpenChange, ...props }, ref) => {
41
41
  // Caller is the source of truth for duration. Persistent toasts disable
@@ -44,13 +44,13 @@ const Toast = React.forwardRef(({ className, variant, duration, dismissible = tr
44
44
  // pass duration to Radix AND to CSS countdown bar
45
45
  const mergedStyle = {
46
46
  ...style,
47
- ["--toast-duration"]: `${effectiveDuration}ms`,
47
+ ['--toast-duration']: `${effectiveDuration}ms`,
48
48
  };
49
- return (_jsxs(ToastPrimitives.Root, { ref: ref, duration: effectiveDuration, "data-variant": variant, "data-persistent": persistent ? "" : undefined, className: cn(toastVariants({ variant }), className), style: mergedStyle, onOpenChange: onOpenChange, ...props, children: [_jsx(ToastKeyframes, {}), children, !persistent ? (_jsx("div", { "aria-hidden": true, className: cn("absolute bottom-0 left-0 h-1 w-full bg-foreground/30", "origin-left"), style: {
50
- animationName: "toast-progress",
49
+ return (_jsxs(ToastPrimitives.Root, { ref: ref, duration: effectiveDuration, "data-variant": variant, "data-persistent": persistent ? '' : undefined, className: cn(toastVariants({ variant }), className), style: mergedStyle, onOpenChange: onOpenChange, ...props, children: [_jsx(ToastKeyframes, {}), children, !persistent ? (_jsx("div", { "aria-hidden": true, className: cn('absolute bottom-0 left-0 h-1 w-full bg-foreground/30', 'origin-left'), style: {
50
+ animationName: 'toast-progress',
51
51
  animationDuration: `${effectiveDuration}ms`,
52
- animationTimingFunction: "linear",
53
- animationFillMode: "forwards",
52
+ animationTimingFunction: 'linear',
53
+ animationFillMode: 'forwards',
54
54
  },
55
55
  // Radix's own auto-close timer PAUSES on pointer-over the viewport,
56
56
  // focus, and window-blur — but this CSS bar does not. When the bar
@@ -62,21 +62,21 @@ const Toast = React.forwardRef(({ className, variant, duration, dismissible = tr
62
62
  // it. Radix's `duration` above is the motion-independent timer that
63
63
  // closes the toast in that case.
64
64
  onAnimationEnd: (e) => {
65
- if (e.animationName !== "toast-progress")
65
+ if (e.animationName !== 'toast-progress')
66
66
  return;
67
67
  if (e.elapsedTime * 1000 < effectiveDuration / 2)
68
68
  return;
69
69
  onOpenChange?.(false);
70
- } })) : null, dismissible ? (_jsx(ToastPrimitives.Close, { className: cn("absolute right-2 top-2 inline-flex h-7 w-7 items-center justify-center rounded-md", "text-foreground/60 hover:text-foreground", "focus:outline-hidden focus:ring-2 focus:ring-ring focus:ring-offset-2 focus:ring-offset-background"), "aria-label": "Dismiss toast", children: _jsx(X, { className: "h-4 w-4" }) })) : null] }));
70
+ } })) : null, dismissible ? (_jsx(ToastPrimitives.Close, { className: cn('absolute right-2 top-2 inline-flex h-7 w-7 items-center justify-center rounded-md', 'text-foreground/60 hover:text-foreground', 'focus:outline-hidden focus:ring-2 focus:ring-ring focus:ring-offset-2 focus:ring-offset-background'), "aria-label": "Dismiss toast", children: _jsx(X, { className: "h-4 w-4" }) })) : null] }));
71
71
  });
72
72
  Toast.displayName = ToastPrimitives.Root.displayName;
73
73
  const ToastAction = React.forwardRef(({ className, ...props }, ref) => (_jsx(ToastPrimitives.Action, { ref: ref, className: cn(className), ...props })));
74
74
  ToastAction.displayName = ToastPrimitives.Action.displayName;
75
- const ToastClose = React.forwardRef(({ className, ...props }, ref) => (_jsx(ToastPrimitives.Close, { ref: ref, className: cn("absolute right-2 top-2 inline-flex h-7 w-7 items-center justify-center rounded-md", "text-foreground/60 hover:text-foreground", "focus:outline-hidden focus:ring-2 focus:ring-ring focus:ring-offset-2 focus:ring-offset-background", className), ...props })));
75
+ const ToastClose = React.forwardRef(({ className, ...props }, ref) => (_jsx(ToastPrimitives.Close, { ref: ref, className: cn('absolute right-2 top-2 inline-flex h-7 w-7 items-center justify-center rounded-md', 'text-foreground/60 hover:text-foreground', 'focus:outline-hidden focus:ring-2 focus:ring-ring focus:ring-offset-2 focus:ring-offset-background', className), ...props })));
76
76
  ToastClose.displayName = ToastPrimitives.Close.displayName;
77
- const ToastTitle = React.forwardRef(({ className, ...props }, ref) => (_jsx(ToastPrimitives.Title, { ref: ref, className: cn("break-words", className), ...props })));
77
+ const ToastTitle = React.forwardRef(({ className, ...props }, ref) => (_jsx(ToastPrimitives.Title, { ref: ref, className: cn('break-words', className), ...props })));
78
78
  ToastTitle.displayName = ToastPrimitives.Title.displayName;
79
- const ToastDescription = React.forwardRef(({ className, ...props }, ref) => (_jsx(ToastPrimitives.Description, { ref: ref, className: cn("break-words", className), ...props })));
79
+ const ToastDescription = React.forwardRef(({ className, ...props }, ref) => (_jsx(ToastPrimitives.Description, { ref: ref, className: cn('break-words', className), ...props })));
80
80
  ToastDescription.displayName = ToastPrimitives.Description.displayName;
81
- export { ToastProvider, ToastViewport, Toast, ToastTitle, ToastDescription, ToastClose, ToastAction };
81
+ export { ToastProvider, ToastViewport, Toast, ToastTitle, ToastDescription, ToastClose, ToastAction, };
82
82
  //# sourceMappingURL=toast.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"toast.js","sourceRoot":"","sources":["../../../src/react/components/toast.tsx"],"names":[],"mappings":"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","sourcesContent":["import * as React from \"react\";\nimport * as ToastPrimitives from \"@radix-ui/react-toast\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { X } from \"lucide-react\";\n\nimport { cn } from \"../../lib/utils.js\";\n\n/**\n * ui-core Toasts are consumed by multiple apps.\n *\n * Do NOT rely on app-level CSS (@apply) for critical positioning/visibility.\n * Keep all required styling inline as Tailwind utility classes.\n */\nfunction ToastKeyframes() {\n // Inject a tiny global keyframe used by the optional countdown bar.\n return (\n <style\n dangerouslySetInnerHTML={{\n __html: `@keyframes toast-progress{from{transform:scaleX(1)}to{transform:scaleX(0)}}`,\n }}\n />\n );\n}\n\nconst toastVariants = cva(\n cn(\n // base\n \"pointer-events-auto relative flex w-full items-start justify-between gap-2 overflow-hidden rounded-md border bg-background p-4 text-foreground elevation-raised transition-all\",\n // radix state/animation\n \"data-[state=open]:animate-in data-[state=closed]:animate-out\",\n \"data-[state=closed]:fade-out-80 data-[state=open]:fade-in-80\",\n \"data-[state=closed]:slide-out-to-top-full data-[state=open]:slide-in-from-top-full\",\n \"data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)]\",\n \"data-[swipe=cancel]:translate-x-0 data-[swipe=cancel]:transition-[transform_200ms_ease-out]\",\n \"data-[swipe=end]:animate-out data-[swipe=end]:slide-out-to-right-full\"\n ),\n {\n variants: {\n variant: {\n default: \"\",\n destructive: \"border-[color:var(--toast-destructive-border)] bg-[color:var(--toast-destructive)] text-[color:var(--toast-destructive-foreground)]\",\n success: \"border-[color:var(--toast-success-border)] bg-[color:var(--toast-success)] text-[color:var(--toast-success-foreground)]\",\n warning: \"border-[color:var(--toast-warning-border)] bg-[color:var(--toast-warning)] text-[color:var(--toast-warning-foreground)]\",\n error: \"border-[color:var(--toast-destructive-border)] bg-[color:var(--toast-destructive)] text-[color:var(--toast-destructive-foreground)]\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n);\n\nconst ToastProvider = ToastPrimitives.Provider;\n\nconst ToastViewport = React.forwardRef<\n React.ElementRef<typeof ToastPrimitives.Viewport>,\n React.ComponentPropsWithoutRef<typeof ToastPrimitives.Viewport>\n>(({ className, ...props }, ref) => (\n <ToastPrimitives.Viewport\n ref={ref}\n className={cn(\n \"fixed top-0 left-1/2 -translate-x-1/2 z-[100] flex max-h-screen w-full flex-col gap-2 p-4\",\n \"sm:max-w-[480px] md:max-w-[600px]\",\n className\n )}\n {...props}\n />\n));\nToastViewport.displayName = ToastPrimitives.Viewport.displayName;\n\ntype ToastRootProps = React.ComponentPropsWithoutRef<typeof ToastPrimitives.Root> &\n VariantProps<typeof toastVariants> & {\n /** ms; ignored when `persistent` is true */\n duration?: number;\n /** show X button */\n dismissible?: boolean;\n /** When true: no auto-dismiss, no countdown bar. */\n persistent?: boolean;\n };\n\nconst Toast = React.forwardRef<React.ElementRef<typeof ToastPrimitives.Root>, ToastRootProps>(\n ({ className, variant, duration, dismissible = true, persistent = false, style, children, onOpenChange, ...props }, ref) => {\n // Caller is the source of truth for duration. Persistent toasts disable\n // the auto-dismiss entirely by passing `Infinity` to Radix.\n const effectiveDuration = persistent ? Infinity : (duration ?? 5000);\n // pass duration to Radix AND to CSS countdown bar\n const mergedStyle: React.CSSProperties = {\n ...(style as React.CSSProperties),\n [\"--toast-duration\" as any]: `${effectiveDuration}ms`,\n };\n\n return (\n <ToastPrimitives.Root\n ref={ref}\n duration={effectiveDuration}\n data-variant={variant}\n data-persistent={persistent ? \"\" : undefined}\n className={cn(toastVariants({ variant }), className)}\n style={mergedStyle}\n onOpenChange={onOpenChange}\n {...props}\n >\n <ToastKeyframes />\n {children}\n\n {/* countdown bar — hidden entirely for persistent toasts */}\n {!persistent ? (\n <div\n aria-hidden\n className={cn(\"absolute bottom-0 left-0 h-1 w-full bg-foreground/30\", \"origin-left\")}\n style={{\n animationName: \"toast-progress\",\n animationDuration: `${effectiveDuration}ms`,\n animationTimingFunction: \"linear\",\n animationFillMode: \"forwards\",\n }}\n // Radix's own auto-close timer PAUSES on pointer-over the viewport,\n // focus, and window-blur — but this CSS bar does not. When the bar\n // empties we must dismiss regardless of Radix's paused timer, so the\n // toast never lingers after the countdown visibly reaches zero.\n // Only a bar that ran its course counts as empty: a reduced-motion\n // stylesheet that collapses every animation to near zero ends this one\n // at once, and closing then would hide the toast before anyone reads\n // it. Radix's `duration` above is the motion-independent timer that\n // closes the toast in that case.\n onAnimationEnd={(e) => {\n if (e.animationName !== \"toast-progress\") return;\n if (e.elapsedTime * 1000 < effectiveDuration / 2) return;\n onOpenChange?.(false);\n }}\n />\n ) : null}\n\n {/* dismiss button */}\n {dismissible ? (\n <ToastPrimitives.Close\n className={cn(\n \"absolute right-2 top-2 inline-flex h-7 w-7 items-center justify-center rounded-md\",\n \"text-foreground/60 hover:text-foreground\",\n \"focus:outline-hidden focus:ring-2 focus:ring-ring focus:ring-offset-2 focus:ring-offset-background\"\n )}\n aria-label=\"Dismiss toast\"\n >\n <X className=\"h-4 w-4\" />\n </ToastPrimitives.Close>\n ) : null}\n </ToastPrimitives.Root>\n );\n }\n);\nToast.displayName = ToastPrimitives.Root.displayName;\n\nconst ToastAction = React.forwardRef<\n React.ElementRef<typeof ToastPrimitives.Action>,\n React.ComponentPropsWithoutRef<typeof ToastPrimitives.Action>\n>(({ className, ...props }, ref) => (\n <ToastPrimitives.Action ref={ref} className={cn(className)} {...props} />\n));\nToastAction.displayName = ToastPrimitives.Action.displayName;\n\nconst ToastClose = React.forwardRef<\n React.ElementRef<typeof ToastPrimitives.Close>,\n React.ComponentPropsWithoutRef<typeof ToastPrimitives.Close>\n>(({ className, ...props }, ref) => (\n <ToastPrimitives.Close\n ref={ref}\n className={cn(\n \"absolute right-2 top-2 inline-flex h-7 w-7 items-center justify-center rounded-md\",\n \"text-foreground/60 hover:text-foreground\",\n \"focus:outline-hidden focus:ring-2 focus:ring-ring focus:ring-offset-2 focus:ring-offset-background\",\n className\n )}\n {...props}\n />\n));\nToastClose.displayName = ToastPrimitives.Close.displayName;\n\nconst ToastTitle = React.forwardRef<\n React.ElementRef<typeof ToastPrimitives.Title>,\n React.ComponentPropsWithoutRef<typeof ToastPrimitives.Title>\n>(({ className, ...props }, ref) => (\n <ToastPrimitives.Title ref={ref} className={cn(\"break-words\", className)} {...props} />\n));\nToastTitle.displayName = ToastPrimitives.Title.displayName;\n\nconst ToastDescription = React.forwardRef<\n React.ElementRef<typeof ToastPrimitives.Description>,\n React.ComponentPropsWithoutRef<typeof ToastPrimitives.Description>\n>(({ className, ...props }, ref) => (\n <ToastPrimitives.Description ref={ref} className={cn(\"break-words\", className)} {...props} />\n));\nToastDescription.displayName = ToastPrimitives.Description.displayName;\n\n/** Exported types for consumers */\nexport type ToastProps = React.ComponentPropsWithoutRef<typeof Toast>;\nexport type ToastActionElement = React.ReactElement<typeof ToastAction>;\n\nexport { ToastProvider, ToastViewport, Toast, ToastTitle, ToastDescription, ToastClose, ToastAction };\n"]}
1
+ {"version":3,"file":"toast.js","sourceRoot":"","sources":["../../../src/react/components/toast.tsx"],"names":[],"mappings":"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","sourcesContent":["import * as React from 'react';\nimport * as ToastPrimitives from '@radix-ui/react-toast';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { X } from 'lucide-react';\n\nimport { cn } from '../../lib/utils.js';\n\n/**\n * ui-core Toasts are consumed by multiple apps.\n *\n * Do NOT rely on app-level CSS (@apply) for critical positioning/visibility.\n * Keep all required styling inline as Tailwind utility classes.\n */\nfunction ToastKeyframes() {\n // Inject a tiny global keyframe used by the optional countdown bar.\n return (\n <style\n dangerouslySetInnerHTML={{\n __html: `@keyframes toast-progress{from{transform:scaleX(1)}to{transform:scaleX(0)}}`,\n }}\n />\n );\n}\n\nconst toastVariants = cva(\n cn(\n // base\n 'pointer-events-auto relative flex w-full items-start justify-between gap-2 overflow-hidden rounded-md border bg-background p-4 text-foreground elevation-raised duration-[var(--motion-base)] ease-[var(--motion-ease)]',\n // radix state/animation\n 'data-[state=open]:animate-in data-[state=closed]:animate-out',\n 'data-[state=closed]:fade-out-80 data-[state=open]:fade-in-80',\n 'data-[state=closed]:slide-out-to-top-full data-[state=open]:slide-in-from-top-full',\n 'data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)]',\n 'data-[swipe=cancel]:translate-x-0 data-[swipe=cancel]:transition-transform',\n 'data-[swipe=end]:animate-out data-[swipe=end]:slide-out-to-right-full',\n ),\n {\n variants: {\n variant: {\n default: '',\n destructive:\n 'border-[color:var(--toast-destructive-border)] bg-[color:var(--toast-destructive)] text-[color:var(--toast-destructive-foreground)]',\n success:\n 'border-[color:var(--toast-success-border)] bg-[color:var(--toast-success)] text-[color:var(--toast-success-foreground)]',\n warning:\n 'border-[color:var(--toast-warning-border)] bg-[color:var(--toast-warning)] text-[color:var(--toast-warning-foreground)]',\n error:\n 'border-[color:var(--toast-destructive-border)] bg-[color:var(--toast-destructive)] text-[color:var(--toast-destructive-foreground)]',\n },\n },\n defaultVariants: {\n variant: 'default',\n },\n },\n);\n\nconst ToastProvider = ToastPrimitives.Provider;\n\nconst ToastViewport = React.forwardRef<\n React.ElementRef<typeof ToastPrimitives.Viewport>,\n React.ComponentPropsWithoutRef<typeof ToastPrimitives.Viewport>\n>(({ className, ...props }, ref) => (\n <ToastPrimitives.Viewport\n ref={ref}\n className={cn(\n 'fixed top-0 left-1/2 -translate-x-1/2 z-[100] flex max-h-screen w-full flex-col gap-2 p-4',\n 'sm:max-w-[480px] md:max-w-[600px]',\n className,\n )}\n {...props}\n />\n));\nToastViewport.displayName = ToastPrimitives.Viewport.displayName;\n\ntype ToastRootProps = React.ComponentPropsWithoutRef<typeof ToastPrimitives.Root> &\n VariantProps<typeof toastVariants> & {\n /** ms; ignored when `persistent` is true */\n duration?: number;\n /** show X button */\n dismissible?: boolean;\n /** When true: no auto-dismiss, no countdown bar. */\n persistent?: boolean;\n };\n\nconst Toast = React.forwardRef<React.ElementRef<typeof ToastPrimitives.Root>, ToastRootProps>(\n (\n {\n className,\n variant,\n duration,\n dismissible = true,\n persistent = false,\n style,\n children,\n onOpenChange,\n ...props\n },\n ref,\n ) => {\n // Caller is the source of truth for duration. Persistent toasts disable\n // the auto-dismiss entirely by passing `Infinity` to Radix.\n const effectiveDuration = persistent ? Infinity : (duration ?? 5000);\n // pass duration to Radix AND to CSS countdown bar\n const mergedStyle: React.CSSProperties = {\n ...(style as React.CSSProperties),\n ['--toast-duration' as any]: `${effectiveDuration}ms`,\n };\n\n return (\n <ToastPrimitives.Root\n ref={ref}\n duration={effectiveDuration}\n data-variant={variant}\n data-persistent={persistent ? '' : undefined}\n className={cn(toastVariants({ variant }), className)}\n style={mergedStyle}\n onOpenChange={onOpenChange}\n {...props}\n >\n <ToastKeyframes />\n {children}\n\n {/* countdown bar — hidden entirely for persistent toasts */}\n {!persistent ? (\n <div\n aria-hidden\n className={cn('absolute bottom-0 left-0 h-1 w-full bg-foreground/30', 'origin-left')}\n style={{\n animationName: 'toast-progress',\n animationDuration: `${effectiveDuration}ms`,\n animationTimingFunction: 'linear',\n animationFillMode: 'forwards',\n }}\n // Radix's own auto-close timer PAUSES on pointer-over the viewport,\n // focus, and window-blur — but this CSS bar does not. When the bar\n // empties we must dismiss regardless of Radix's paused timer, so the\n // toast never lingers after the countdown visibly reaches zero.\n // Only a bar that ran its course counts as empty: a reduced-motion\n // stylesheet that collapses every animation to near zero ends this one\n // at once, and closing then would hide the toast before anyone reads\n // it. Radix's `duration` above is the motion-independent timer that\n // closes the toast in that case.\n onAnimationEnd={(e) => {\n if (e.animationName !== 'toast-progress') return;\n if (e.elapsedTime * 1000 < effectiveDuration / 2) return;\n onOpenChange?.(false);\n }}\n />\n ) : null}\n\n {/* dismiss button */}\n {dismissible ? (\n <ToastPrimitives.Close\n className={cn(\n 'absolute right-2 top-2 inline-flex h-7 w-7 items-center justify-center rounded-md',\n 'text-foreground/60 hover:text-foreground',\n 'focus:outline-hidden focus:ring-2 focus:ring-ring focus:ring-offset-2 focus:ring-offset-background',\n )}\n aria-label=\"Dismiss toast\"\n >\n <X className=\"h-4 w-4\" />\n </ToastPrimitives.Close>\n ) : null}\n </ToastPrimitives.Root>\n );\n },\n);\nToast.displayName = ToastPrimitives.Root.displayName;\n\nconst ToastAction = React.forwardRef<\n React.ElementRef<typeof ToastPrimitives.Action>,\n React.ComponentPropsWithoutRef<typeof ToastPrimitives.Action>\n>(({ className, ...props }, ref) => (\n <ToastPrimitives.Action ref={ref} className={cn(className)} {...props} />\n));\nToastAction.displayName = ToastPrimitives.Action.displayName;\n\nconst ToastClose = React.forwardRef<\n React.ElementRef<typeof ToastPrimitives.Close>,\n React.ComponentPropsWithoutRef<typeof ToastPrimitives.Close>\n>(({ className, ...props }, ref) => (\n <ToastPrimitives.Close\n ref={ref}\n className={cn(\n 'absolute right-2 top-2 inline-flex h-7 w-7 items-center justify-center rounded-md',\n 'text-foreground/60 hover:text-foreground',\n 'focus:outline-hidden focus:ring-2 focus:ring-ring focus:ring-offset-2 focus:ring-offset-background',\n className,\n )}\n {...props}\n />\n));\nToastClose.displayName = ToastPrimitives.Close.displayName;\n\nconst ToastTitle = React.forwardRef<\n React.ElementRef<typeof ToastPrimitives.Title>,\n React.ComponentPropsWithoutRef<typeof ToastPrimitives.Title>\n>(({ className, ...props }, ref) => (\n <ToastPrimitives.Title ref={ref} className={cn('break-words', className)} {...props} />\n));\nToastTitle.displayName = ToastPrimitives.Title.displayName;\n\nconst ToastDescription = React.forwardRef<\n React.ElementRef<typeof ToastPrimitives.Description>,\n React.ComponentPropsWithoutRef<typeof ToastPrimitives.Description>\n>(({ className, ...props }, ref) => (\n <ToastPrimitives.Description ref={ref} className={cn('break-words', className)} {...props} />\n));\nToastDescription.displayName = ToastPrimitives.Description.displayName;\n\n/** Exported types for consumers */\nexport type ToastProps = React.ComponentPropsWithoutRef<typeof Toast>;\nexport type ToastActionElement = React.ReactElement<typeof ToastAction>;\n\nexport {\n ToastProvider,\n ToastViewport,\n Toast,\n ToastTitle,\n ToastDescription,\n ToastClose,\n ToastAction,\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"toaster.d.ts","sourceRoot":"","sources":["../../../src/react/components/toaster.tsx"],"names":[],"mappings":"AAMA,wBAAgB,OAAO,gCAoCtB"}
1
+ {"version":3,"file":"toaster.d.ts","sourceRoot":"","sources":["../../../src/react/components/toaster.tsx"],"names":[],"mappings":"AAaA,wBAAgB,OAAO,gCAkDtB"}
@@ -1,13 +1,13 @@
1
- "use client";
1
+ 'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { Toast, ToastClose, ToastDescription, ToastProvider, ToastTitle, ToastViewport } from "./toast.js";
4
- import { useToast } from "../hooks/use-toast.js";
3
+ import { Toast, ToastClose, ToastDescription, ToastProvider, ToastTitle, ToastViewport, } from './toast.js';
4
+ import { useToast } from '../hooks/use-toast.js';
5
5
  export function Toaster() {
6
6
  const { toasts } = useToast();
7
7
  return (_jsxs(ToastProvider, { swipeDirection: "right", swipeThreshold: 32, children: [toasts.map((t) => {
8
8
  const { id, title, description, action, variant, duration, dismissible, persistent, open, onOpenChange, ...props } = t;
9
- const v = variant === "error" ? "destructive" : (variant ?? "default");
10
- return (_jsxs(Toast, { open: open, onOpenChange: onOpenChange, variant: v, duration: duration, dismissible: dismissible ?? true, persistent: persistent ?? false, ...props, children: [_jsxs("div", { className: "grid gap-1 pr-10", children: [title ? _jsx(ToastTitle, { className: "font-bold", children: title }) : null, description ? _jsx(ToastDescription, { className: "font-bold", children: description }) : null] }), action, _jsx(ToastClose, {})] }, id));
9
+ const v = variant === 'error' ? 'destructive' : (variant ?? 'default');
10
+ return (_jsxs(Toast, { open: open, onOpenChange: onOpenChange, variant: v, duration: duration, dismissible: dismissible ?? true, persistent: persistent ?? false, ...props, children: [_jsxs("div", { className: "grid gap-1 pr-10", children: [title ? _jsx(ToastTitle, { className: "font-bold", children: title }) : null, description ? (_jsx(ToastDescription, { className: "font-bold", children: description })) : null] }), action, _jsx(ToastClose, {})] }, id));
11
11
  }), _jsx(ToastViewport, {})] }));
12
12
  }
13
13
  //# sourceMappingURL=toaster.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"toaster.js","sourceRoot":"","sources":["../../../src/react/components/toaster.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,aAAa,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3G,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAGjD,MAAM,UAAU,OAAO;IACrB,MAAM,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAgC,CAAC;IAE5D,OAAO,CACL,MAAC,aAAa,IAAC,cAAc,EAAC,OAAO,EAAC,cAAc,EAAE,EAAE,aACrD,MAAM,CAAC,GAAG,CAAC,CAAC,CAAe,EAAE,EAAE;gBAC9B,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,UAAU,EAAE,IAAI,EAAE,YAAY,EAAE,GAAG,KAAK,EAAE,GAAG,CAAC,CAAC;gBAEvH,MAAM,CAAC,GACL,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,OAAO,IAAI,SAAS,CAAC,CAAC;gBAE/D,OAAO,CACL,MAAC,KAAK,IAEJ,IAAI,EAAE,IAAI,EACV,YAAY,EAAE,YAAY,EAC1B,OAAO,EAAE,CAAQ,EACjB,QAAQ,EAAE,QAAQ,EAClB,WAAW,EAAE,WAAW,IAAI,IAAI,EAChC,UAAU,EAAE,UAAU,IAAI,KAAK,KAC1B,KAAa,aAElB,eAAK,SAAS,EAAC,kBAAkB,aAC9B,KAAK,CAAC,CAAC,CAAC,KAAC,UAAU,IAAC,SAAS,EAAC,WAAW,YAAE,KAAK,GAAc,CAAC,CAAC,CAAC,IAAI,EACrE,WAAW,CAAC,CAAC,CAAC,KAAC,gBAAgB,IAAC,SAAS,EAAC,WAAW,YAAE,WAAW,GAAoB,CAAC,CAAC,CAAC,IAAI,IAC1F,EACL,MAAM,EACP,KAAC,UAAU,KAAG,KAdT,EAAE,CAeD,CACT,CAAC;YACJ,CAAC,CAAC,EAGF,KAAC,aAAa,KAAG,IACH,CACjB,CAAC;AACJ,CAAC","sourcesContent":["\"use client\";\n\nimport { Toast, ToastClose, ToastDescription, ToastProvider, ToastTitle, ToastViewport } from \"./toast.js\";\nimport { useToast } from \"../hooks/use-toast.js\";\nimport type { ToasterToast, ToastVariant } from \"../hooks/use-toast.js\";\n\nexport function Toaster() {\n const { toasts } = useToast() as { toasts: ToasterToast[] };\n\n return (\n <ToastProvider swipeDirection=\"right\" swipeThreshold={32}>\n {toasts.map((t: ToasterToast) => {\n const { id, title, description, action, variant, duration, dismissible, persistent, open, onOpenChange, ...props } = t;\n\n const v: ToastVariant | \"destructive\" =\n variant === \"error\" ? \"destructive\" : (variant ?? \"default\");\n\n return (\n <Toast\n key={id}\n open={open}\n onOpenChange={onOpenChange}\n variant={v as any}\n duration={duration}\n dismissible={dismissible ?? true}\n persistent={persistent ?? false}\n {...(props as any)}\n >\n <div className=\"grid gap-1 pr-10\">\n {title ? <ToastTitle className=\"font-bold\">{title}</ToastTitle> : null}\n {description ? <ToastDescription className=\"font-bold\">{description}</ToastDescription> : null}\n </div>\n {action}\n <ToastClose />\n </Toast>\n );\n })}\n\n {/* debug: proves viewport is visible/on-screen */}\n <ToastViewport />\n </ToastProvider>\n );\n}\n"]}
1
+ {"version":3,"file":"toaster.js","sourceRoot":"","sources":["../../../src/react/components/toaster.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EACL,KAAK,EACL,UAAU,EACV,gBAAgB,EAChB,aAAa,EACb,UAAU,EACV,aAAa,GACd,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAGjD,MAAM,UAAU,OAAO;IACrB,MAAM,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAgC,CAAC;IAE5D,OAAO,CACL,MAAC,aAAa,IAAC,cAAc,EAAC,OAAO,EAAC,cAAc,EAAE,EAAE,aACrD,MAAM,CAAC,GAAG,CAAC,CAAC,CAAe,EAAE,EAAE;gBAC9B,MAAM,EACJ,EAAE,EACF,KAAK,EACL,WAAW,EACX,MAAM,EACN,OAAO,EACP,QAAQ,EACR,WAAW,EACX,UAAU,EACV,IAAI,EACJ,YAAY,EACZ,GAAG,KAAK,EACT,GAAG,CAAC,CAAC;gBAEN,MAAM,CAAC,GACL,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,OAAO,IAAI,SAAS,CAAC,CAAC;gBAE/D,OAAO,CACL,MAAC,KAAK,IAEJ,IAAI,EAAE,IAAI,EACV,YAAY,EAAE,YAAY,EAC1B,OAAO,EAAE,CAAQ,EACjB,QAAQ,EAAE,QAAQ,EAClB,WAAW,EAAE,WAAW,IAAI,IAAI,EAChC,UAAU,EAAE,UAAU,IAAI,KAAK,KAC1B,KAAa,aAElB,eAAK,SAAS,EAAC,kBAAkB,aAC9B,KAAK,CAAC,CAAC,CAAC,KAAC,UAAU,IAAC,SAAS,EAAC,WAAW,YAAE,KAAK,GAAc,CAAC,CAAC,CAAC,IAAI,EACrE,WAAW,CAAC,CAAC,CAAC,CACb,KAAC,gBAAgB,IAAC,SAAS,EAAC,WAAW,YAAE,WAAW,GAAoB,CACzE,CAAC,CAAC,CAAC,IAAI,IACJ,EACL,MAAM,EACP,KAAC,UAAU,KAAG,KAhBT,EAAE,CAiBD,CACT,CAAC;YACJ,CAAC,CAAC,EAGF,KAAC,aAAa,KAAG,IACH,CACjB,CAAC;AACJ,CAAC","sourcesContent":["'use client';\n\nimport {\n Toast,\n ToastClose,\n ToastDescription,\n ToastProvider,\n ToastTitle,\n ToastViewport,\n} from './toast.js';\nimport { useToast } from '../hooks/use-toast.js';\nimport type { ToasterToast, ToastVariant } from '../hooks/use-toast.js';\n\nexport function Toaster() {\n const { toasts } = useToast() as { toasts: ToasterToast[] };\n\n return (\n <ToastProvider swipeDirection=\"right\" swipeThreshold={32}>\n {toasts.map((t: ToasterToast) => {\n const {\n id,\n title,\n description,\n action,\n variant,\n duration,\n dismissible,\n persistent,\n open,\n onOpenChange,\n ...props\n } = t;\n\n const v: ToastVariant | 'destructive' =\n variant === 'error' ? 'destructive' : (variant ?? 'default');\n\n return (\n <Toast\n key={id}\n open={open}\n onOpenChange={onOpenChange}\n variant={v as any}\n duration={duration}\n dismissible={dismissible ?? true}\n persistent={persistent ?? false}\n {...(props as any)}\n >\n <div className=\"grid gap-1 pr-10\">\n {title ? <ToastTitle className=\"font-bold\">{title}</ToastTitle> : null}\n {description ? (\n <ToastDescription className=\"font-bold\">{description}</ToastDescription>\n ) : null}\n </div>\n {action}\n <ToastClose />\n </Toast>\n );\n })}\n\n {/* debug: proves viewport is visible/on-screen */}\n <ToastViewport />\n </ToastProvider>\n );\n}\n"]}
@@ -1,5 +1,5 @@
1
- import * as React from "react";
2
- import * as TooltipPrimitive from "@radix-ui/react-tooltip";
1
+ import * as React from 'react';
2
+ import * as TooltipPrimitive from '@radix-ui/react-tooltip';
3
3
  declare const TooltipProvider: React.FC<TooltipPrimitive.TooltipProviderProps>;
4
4
  declare const Tooltip: React.FC<TooltipPrimitive.TooltipProps>;
5
5
  declare const TooltipTrigger: React.ForwardRefExoticComponent<TooltipPrimitive.TooltipTriggerProps & React.RefAttributes<HTMLButtonElement>>;
@@ -1 +1 @@
1
- {"version":3,"file":"tooltip.d.ts","sourceRoot":"","sources":["../../../src/react/components/tooltip.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,KAAK,gBAAgB,MAAM,yBAAyB,CAAA;AAI3D,QAAA,MAAM,eAAe,iDAA4B,CAAA;AACjD,QAAA,MAAM,OAAO,yCAAwB,CAAA;AACrC,QAAA,MAAM,cAAc,gHAA2B,CAAA;AAE/C,QAAA,MAAM,cAAc,gKAalB,CAAA;AAGF,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,eAAe,EAAE,CAAA"}
1
+ {"version":3,"file":"tooltip.d.ts","sourceRoot":"","sources":["../../../src/react/components/tooltip.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,gBAAgB,MAAM,yBAAyB,CAAC;AAI5D,QAAA,MAAM,eAAe,iDAA4B,CAAC;AAClD,QAAA,MAAM,OAAO,yCAAwB,CAAC;AACtC,QAAA,MAAM,cAAc,gHAA2B,CAAC;AAEhD,QAAA,MAAM,cAAc,gKAalB,CAAC;AAGH,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,eAAe,EAAE,CAAC"}
@@ -1,12 +1,12 @@
1
- "use client";
1
+ 'use client';
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
- import * as React from "react";
4
- import * as TooltipPrimitive from "@radix-ui/react-tooltip";
5
- import { cn } from "../../lib/utils.js";
3
+ import * as React from 'react';
4
+ import * as TooltipPrimitive from '@radix-ui/react-tooltip';
5
+ import { cn } from '../../lib/utils.js';
6
6
  const TooltipProvider = TooltipPrimitive.Provider;
7
7
  const Tooltip = TooltipPrimitive.Root;
8
8
  const TooltipTrigger = TooltipPrimitive.Trigger;
9
- const TooltipContent = React.forwardRef(({ className, sideOffset = 4, ...props }, ref) => (_jsx(TooltipPrimitive.Content, { ref: ref, sideOffset: sideOffset, className: cn("z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground elevation-popover animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", className), ...props })));
9
+ const TooltipContent = React.forwardRef(({ className, sideOffset = 4, ...props }, ref) => (_jsx(TooltipPrimitive.Content, { ref: ref, sideOffset: sideOffset, className: cn('z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground elevation-popover duration-[var(--motion-fast)] ease-[var(--motion-ease)] animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2', className), ...props })));
10
10
  TooltipContent.displayName = TooltipPrimitive.Content.displayName;
11
11
  export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
12
12
  //# sourceMappingURL=tooltip.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"tooltip.js","sourceRoot":"","sources":["../../../src/react/components/tooltip.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,KAAK,gBAAgB,MAAM,yBAAyB,CAAA;AAE3D,OAAO,EAAE,EAAE,EAAE,MAAM,oBAAoB,CAAA;AAEvC,MAAM,eAAe,GAAG,gBAAgB,CAAC,QAAQ,CAAA;AACjD,MAAM,OAAO,GAAG,gBAAgB,CAAC,IAAI,CAAA;AACrC,MAAM,cAAc,GAAG,gBAAgB,CAAC,OAAO,CAAA;AAE/C,MAAM,cAAc,GAAG,KAAK,CAAC,UAAU,CAGrC,CAAC,EAAE,SAAS,EAAE,UAAU,GAAG,CAAC,EAAE,GAAG,KAAK,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,CAClD,KAAC,gBAAgB,CAAC,OAAO,IACvB,GAAG,EAAE,GAAG,EACR,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,EAAE,CACX,4YAA4Y,EAC5Y,SAAS,CACV,KACG,KAAK,GACT,CACH,CAAC,CAAA;AACF,cAAc,CAAC,WAAW,GAAG,gBAAgB,CAAC,OAAO,CAAC,WAAW,CAAA;AAEjE,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,eAAe,EAAE,CAAA","sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport * as TooltipPrimitive from \"@radix-ui/react-tooltip\"\n\nimport { cn } from \"../../lib/utils.js\"\n\nconst TooltipProvider = TooltipPrimitive.Provider\nconst Tooltip = TooltipPrimitive.Root\nconst TooltipTrigger = TooltipPrimitive.Trigger\n\nconst TooltipContent = React.forwardRef<\n React.ElementRef<typeof TooltipPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>\n>(({ className, sideOffset = 4, ...props }, ref) => (\n <TooltipPrimitive.Content\n ref={ref}\n sideOffset={sideOffset}\n className={cn(\n \"z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground elevation-popover animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2\",\n className\n )}\n {...props}\n />\n))\nTooltipContent.displayName = TooltipPrimitive.Content.displayName\n\nexport { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }\n"]}
1
+ {"version":3,"file":"tooltip.js","sourceRoot":"","sources":["../../../src/react/components/tooltip.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,gBAAgB,MAAM,yBAAyB,CAAC;AAE5D,OAAO,EAAE,EAAE,EAAE,MAAM,oBAAoB,CAAC;AAExC,MAAM,eAAe,GAAG,gBAAgB,CAAC,QAAQ,CAAC;AAClD,MAAM,OAAO,GAAG,gBAAgB,CAAC,IAAI,CAAC;AACtC,MAAM,cAAc,GAAG,gBAAgB,CAAC,OAAO,CAAC;AAEhD,MAAM,cAAc,GAAG,KAAK,CAAC,UAAU,CAGrC,CAAC,EAAE,SAAS,EAAE,UAAU,GAAG,CAAC,EAAE,GAAG,KAAK,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,CAClD,KAAC,gBAAgB,CAAC,OAAO,IACvB,GAAG,EAAE,GAAG,EACR,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,EAAE,CACX,ocAAoc,EACpc,SAAS,CACV,KACG,KAAK,GACT,CACH,CAAC,CAAC;AACH,cAAc,CAAC,WAAW,GAAG,gBAAgB,CAAC,OAAO,CAAC,WAAW,CAAC;AAElE,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,eAAe,EAAE,CAAC","sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport * as TooltipPrimitive from '@radix-ui/react-tooltip';\n\nimport { cn } from '../../lib/utils.js';\n\nconst TooltipProvider = TooltipPrimitive.Provider;\nconst Tooltip = TooltipPrimitive.Root;\nconst TooltipTrigger = TooltipPrimitive.Trigger;\n\nconst TooltipContent = React.forwardRef<\n React.ElementRef<typeof TooltipPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>\n>(({ className, sideOffset = 4, ...props }, ref) => (\n <TooltipPrimitive.Content\n ref={ref}\n sideOffset={sideOffset}\n className={cn(\n 'z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground elevation-popover duration-[var(--motion-fast)] ease-[var(--motion-ease)] animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',\n className,\n )}\n {...props}\n />\n));\nTooltipContent.displayName = TooltipPrimitive.Content.displayName;\n\nexport { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };\n"]}
@@ -1,5 +1,5 @@
1
- "use client";
2
- import { useCallback, useRef, useState } from "react";
1
+ 'use client';
2
+ import { useCallback, useRef, useState } from 'react';
3
3
  /**
4
4
  * Pending state + repeat guard for async work that is NOT a React Query mutation
5
5
  * (a local media step, a sign-out, an awaited navigation). Feed `pending` to the
@@ -1 +1 @@
1
- {"version":3,"file":"use-async-action.js","sourceRoot":"","sources":["../../../src/react/hooks/use-async-action.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAuBtD;;;;;;;;GAQG;AACH,MAAM,UAAU,cAAc,CAC5B,MAA4C,EAC5C,OAA8B;IAE9B,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC9C,MAAM,WAAW,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAClC,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;IACjC,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3C,SAAS,CAAC,OAAO,GAAG,MAAM,CAAC;IAC3B,UAAU,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAErC,MAAM,GAAG,GAAG,WAAW,CAAC,KAAK,EAAE,GAAG,IAAW,EAAoB,EAAE;QACjE,IAAI,WAAW,CAAC,OAAO;YAAE,OAAO,KAAK,CAAC;QACtC,WAAW,CAAC,OAAO,GAAG,IAAI,CAAC;QAC3B,UAAU,CAAC,IAAI,CAAC,CAAC;QACjB,IAAI,CAAC;YACH,MAAM,SAAS,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC;YACjC,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;YAC1B,OAAO,KAAK,CAAC;QACf,CAAC;gBAAS,CAAC;YACT,WAAW,CAAC,OAAO,GAAG,KAAK,CAAC;YAC5B,UAAU,CAAC,KAAK,CAAC,CAAC;QACpB,CAAC;IACH,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC;AAC1B,CAAC","sourcesContent":["\"use client\";\n\nimport { useCallback, useRef, useState } from \"react\";\n\nexport interface UseAsyncActionOptions {\n /**\n * Receives anything the action throws. REQUIRED, so every call site decides what a\n * failure means (surface it, capture it, or accept that another layer already did):\n * `run` itself never rejects, so a fire-and-forget `onClick={() => void run()}` can\n * never become an unhandled rejection.\n */\n onError: (error: unknown) => void;\n}\n\nexport interface AsyncAction<TArgs extends unknown[]> {\n /**\n * Starts the action unless one is already in flight — a repeat call while pending is\n * ignored. Resolves once the action settles: `true` when it completed, `false` when it\n * was ignored or threw. Never rejects.\n */\n run: (...args: TArgs) => Promise<boolean>;\n /** True from the moment `run` starts the action until it settles. */\n pending: boolean;\n}\n\n/**\n * Pending state + repeat guard for async work that is NOT a React Query mutation\n * (a local media step, a sign-out, an awaited navigation). Feed `pending` to the\n * control's own `pending` prop. Server writes stay mutations — this hook does not\n * replace the data layer's one mutation path.\n *\n * The guard is a ref, not the state, so two clicks inside one frame cannot both start\n * the action.\n */\nexport function useAsyncAction<TArgs extends unknown[]>(\n action: (...args: TArgs) => Promise<unknown>,\n options: UseAsyncActionOptions,\n): AsyncAction<TArgs> {\n const [pending, setPending] = useState(false);\n const inFlightRef = useRef(false);\n const actionRef = useRef(action);\n const onErrorRef = useRef(options.onError);\n actionRef.current = action;\n onErrorRef.current = options.onError;\n\n const run = useCallback(async (...args: TArgs): Promise<boolean> => {\n if (inFlightRef.current) return false;\n inFlightRef.current = true;\n setPending(true);\n try {\n await actionRef.current(...args);\n return true;\n } catch (error) {\n onErrorRef.current(error);\n return false;\n } finally {\n inFlightRef.current = false;\n setPending(false);\n }\n }, []);\n\n return { run, pending };\n}\n"]}
1
+ {"version":3,"file":"use-async-action.js","sourceRoot":"","sources":["../../../src/react/hooks/use-async-action.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAuBtD;;;;;;;;GAQG;AACH,MAAM,UAAU,cAAc,CAC5B,MAA4C,EAC5C,OAA8B;IAE9B,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC9C,MAAM,WAAW,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAClC,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;IACjC,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3C,SAAS,CAAC,OAAO,GAAG,MAAM,CAAC;IAC3B,UAAU,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAErC,MAAM,GAAG,GAAG,WAAW,CAAC,KAAK,EAAE,GAAG,IAAW,EAAoB,EAAE;QACjE,IAAI,WAAW,CAAC,OAAO;YAAE,OAAO,KAAK,CAAC;QACtC,WAAW,CAAC,OAAO,GAAG,IAAI,CAAC;QAC3B,UAAU,CAAC,IAAI,CAAC,CAAC;QACjB,IAAI,CAAC;YACH,MAAM,SAAS,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC;YACjC,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;YAC1B,OAAO,KAAK,CAAC;QACf,CAAC;gBAAS,CAAC;YACT,WAAW,CAAC,OAAO,GAAG,KAAK,CAAC;YAC5B,UAAU,CAAC,KAAK,CAAC,CAAC;QACpB,CAAC;IACH,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC;AAC1B,CAAC","sourcesContent":["'use client';\n\nimport { useCallback, useRef, useState } from 'react';\n\nexport interface UseAsyncActionOptions {\n /**\n * Receives anything the action throws. REQUIRED, so every call site decides what a\n * failure means (surface it, capture it, or accept that another layer already did):\n * `run` itself never rejects, so a fire-and-forget `onClick={() => void run()}` can\n * never become an unhandled rejection.\n */\n onError: (error: unknown) => void;\n}\n\nexport interface AsyncAction<TArgs extends unknown[]> {\n /**\n * Starts the action unless one is already in flight — a repeat call while pending is\n * ignored. Resolves once the action settles: `true` when it completed, `false` when it\n * was ignored or threw. Never rejects.\n */\n run: (...args: TArgs) => Promise<boolean>;\n /** True from the moment `run` starts the action until it settles. */\n pending: boolean;\n}\n\n/**\n * Pending state + repeat guard for async work that is NOT a React Query mutation\n * (a local media step, a sign-out, an awaited navigation). Feed `pending` to the\n * control's own `pending` prop. Server writes stay mutations — this hook does not\n * replace the data layer's one mutation path.\n *\n * The guard is a ref, not the state, so two clicks inside one frame cannot both start\n * the action.\n */\nexport function useAsyncAction<TArgs extends unknown[]>(\n action: (...args: TArgs) => Promise<unknown>,\n options: UseAsyncActionOptions,\n): AsyncAction<TArgs> {\n const [pending, setPending] = useState(false);\n const inFlightRef = useRef(false);\n const actionRef = useRef(action);\n const onErrorRef = useRef(options.onError);\n actionRef.current = action;\n onErrorRef.current = options.onError;\n\n const run = useCallback(async (...args: TArgs): Promise<boolean> => {\n if (inFlightRef.current) return false;\n inFlightRef.current = true;\n setPending(true);\n try {\n await actionRef.current(...args);\n return true;\n } catch (error) {\n onErrorRef.current(error);\n return false;\n } finally {\n inFlightRef.current = false;\n setPending(false);\n }\n }, []);\n\n return { run, pending };\n}\n"]}
@@ -1,4 +1,4 @@
1
- import type { ListPaginationState } from "./use-paged-list.js";
1
+ import type { ListPaginationState } from './use-paged-list.js';
2
2
  /**
3
3
  * Render-time page state for a cursor feed, shaped as {@link ListPaginationState}
4
4
  * so it drops straight into the ONE `ListPagination` control. Produced by
@@ -1,5 +1,5 @@
1
- "use client";
2
- import { useCallback, useState } from "react";
1
+ 'use client';
2
+ import { useCallback, useState } from 'react';
3
3
  /**
4
4
  * Page state for a server-paged (cursor / `hasMore`) list: the 1-based page
5
5
  * number, the guarded step controls, and the reset — the pieces each
@@ -1 +1 @@
1
- {"version":3,"file":"use-cursor-page.js","sourceRoot":"","sources":["../../../src/react/hooks/use-cursor-page.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAwD9C;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,UAAU,aAAa,CAAC,UAAgC,EAAE;IAC9D,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;IAE3C,6EAA6E;IAC7E,2CAA2C;IAC3C,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAGvC,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC;IAE/B,8EAA8E;IAC9E,+EAA+E;IAC/E,MAAM,UAAU,GAAG,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;IAEtD,8EAA8E;IAC9E,2EAA2E;IAC3E,yEAAyE;IACzE,uEAAuE;IACvE,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,YAAY,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC3C,CAAC;IACD,+EAA+E;IAC/E,+EAA+E;IAC/E,+CAA+C;IAC/C,MAAM,WAAW,GAAG,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAEpD,MAAM,gBAAgB,GAAG,WAAW,CAAC,GAAG,EAAE;QACxC,IAAI,WAAW,IAAI,CAAC;YAAE,OAAO;QAC7B,YAAY,CAAC,EAAE,IAAI,EAAE,WAAW,GAAG,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC;QACvD,YAAY,EAAE,EAAE,CAAC;IACnB,CAAC,EAAE,CAAC,WAAW,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC;IAE1C,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE;QAC7B,IAAI,WAAW,KAAK,CAAC;YAAE,OAAO;QAC9B,YAAY,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC;QACzC,YAAY,EAAE,EAAE,CAAC;IACnB,CAAC,EAAE,CAAC,WAAW,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC;IAE1C,8EAA8E;IAC9E,8EAA8E;IAC9E,MAAM,aAAa,GAAG,WAAW,CAC/B,CAAC,OAAgB,EAAc,EAAE,CAAC,CAAC;QACjC,WAAW;QACX,eAAe,EAAE,WAAW,GAAG,CAAC;QAChC,WAAW,EAAE,OAAO;QACpB,gBAAgB;QAChB,YAAY,EAAE,GAAG,EAAE;YACjB,IAAI,CAAC,OAAO;gBAAE,OAAO;YACrB,YAAY,CAAC,EAAE,IAAI,EAAE,WAAW,GAAG,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC;YACvD,YAAY,EAAE,EAAE,CAAC;QACnB,CAAC;KACF,CAAC,EACF,CAAC,WAAW,EAAE,QAAQ,EAAE,YAAY,EAAE,gBAAgB,CAAC,CACxD,CAAC;IAEF,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC;AAC/C,CAAC","sourcesContent":["\"use client\";\n\nimport { useCallback, useState } from \"react\";\nimport type { ListPaginationState } from \"./use-paged-list.js\";\n\n/**\n * Render-time page state for a cursor feed, shaped as {@link ListPaginationState}\n * so it drops straight into the ONE `ListPagination` control. Produced by\n * {@link CursorPager.paginationFor} once the query for `currentPage` has\n * answered with its `hasMore`.\n */\nexport interface CursorPage extends ListPaginationState {\n /** Never known for cursor pagination — the counter reads \"Page N\". */\n totalPages?: undefined;\n}\n\nexport interface UseCursorPageOptions {\n /** Called after the page actually changed. Same contract as `usePagedList`. */\n onPageChange?: () => void;\n /**\n * A snapshot of the query inputs the page number belongs to — a tag, a filter,\n * a sort. When it changes, the page is 1 again **in the same render**, so the\n * query never fires for \"page 4\" of inputs whose page 4 may not exist.\n *\n * Use this when the input change arrives as a prop (there is no event handler\n * of yours to hang the reset on); use {@link CursorPager.reset} when your own\n * handler already owns the change. Compose several inputs into one string\n * (`` `${type}|${projectId ?? \"\"}` ``) — the type is deliberately narrowed to\n * primitives so a fresh object literal cannot pin the list to page 1 forever.\n */\n resetKey?: string | number | boolean | null;\n}\n\n/**\n * What {@link useCursorPage} owns: the page number, the guarded step controls,\n * and the return-to-page-1 control.\n */\nexport interface CursorPager {\n /** 1-based page to feed into the paged query. */\n currentPage: number;\n /**\n * Return to page 1 without walking back. Call it from the handler that changes\n * the query's inputs (a new filter, a new tag, a new sort) — page 4 of the old\n * result set is not page 4 of the new one. A no-op on page 1, so it never\n * fires `onPageChange` for nothing.\n */\n reset: () => void;\n /**\n * Bind the query's answer to the controls: pass the `hasMore` that came back\n * for {@link currentPage} and render the result as\n * `<ListPagination pagination={…} />`. `hasMore` binds HERE, after the query,\n * because that is the only moment it exists — a cursor query needs\n * `currentPage` as its input, so `hasMore` cannot be an argument to the hook\n * that produces `currentPage`.\n */\n paginationFor: (hasMore: boolean) => CursorPage;\n}\n\n/**\n * Page state for a server-paged (cursor / `hasMore`) list: the 1-based page\n * number, the guarded step controls, and the reset — the pieces each\n * server-paged surface was otherwise re-declaring as a local `useState(1)` plus\n * its own clamped increment/decrement and its own \"reset when the filter\n * changed\" adjustment (ENG-002, ENG-003).\n *\n * The data stays the caller's, and the two halves bind at different moments:\n *\n * ```tsx\n * const pager = useCursorPage({ resetKey: tag });\n * const { data, isFetching } = useThingsByTag(tag, pager.currentPage);\n * …\n * <ListPagination pagination={pager.paginationFor(data?.hasMore ?? false)} busy={isFetching} />\n * ```\n *\n * The guards live in here, not at the call site: a step that cannot move the\n * page changes nothing and does not fire `onPageChange`.\n *\n * A surface whose data hook ALREADY owns its page state (it returns\n * `page`/`hasNextPage`/`nextPage`/`prevPage` itself) does not need this hook —\n * it maps those fields onto {@link ListPaginationState} directly. The hook\n * exists for the surfaces that would otherwise hand-roll the state.\n */\nexport function useCursorPage(options: UseCursorPageOptions = {}): CursorPager {\n const { onPageChange, resetKey } = options;\n\n // The stored page is only meaningful for the inputs it was reached under, so\n // the key it belongs to is stored WITH it.\n const [pageState, setPageState] = useState<{\n page: number;\n key: UseCursorPageOptions[\"resetKey\"];\n }>({ page: 1, key: resetKey });\n\n // `Object.is`, the same comparison React uses for state and deps: a `NaN` key\n // must compare equal to itself, or the adjustment below would re-fire forever.\n const keyMatches = Object.is(pageState.key, resetKey);\n\n // React's \"adjusting state when a prop changes\": a new key retires the stored\n // page, because page 4 of the old result set is not page 4 of the new one.\n // Retiring it (rather than only ignoring it) is what makes going BACK to\n // earlier inputs start at page 1 too, instead of reviving a dead page.\n if (!keyMatches) {\n setPageState({ page: 1, key: resetKey });\n }\n // Derived as well as adjusted, so even the render that triggers the adjustment\n // already reports page 1 — the caller's query is never asked for a page of the\n // new inputs that the user never navigated to.\n const currentPage = keyMatches ? pageState.page : 1;\n\n const goToPreviousPage = useCallback(() => {\n if (currentPage <= 1) return;\n setPageState({ page: currentPage - 1, key: resetKey });\n onPageChange?.();\n }, [currentPage, resetKey, onPageChange]);\n\n const reset = useCallback(() => {\n if (currentPage === 1) return;\n setPageState({ page: 1, key: resetKey });\n onPageChange?.();\n }, [currentPage, resetKey, onPageChange]);\n\n // Memoized on the page state itself, so a consumer may hold it in a dep array\n // and it changes only when the page (or the callback/inputs) actually change.\n const paginationFor = useCallback(\n (hasMore: boolean): CursorPage => ({\n currentPage,\n canPreviousPage: currentPage > 1,\n canNextPage: hasMore,\n goToPreviousPage,\n goToNextPage: () => {\n if (!hasMore) return;\n setPageState({ page: currentPage + 1, key: resetKey });\n onPageChange?.();\n },\n }),\n [currentPage, resetKey, onPageChange, goToPreviousPage],\n );\n\n return { currentPage, reset, paginationFor };\n}\n"]}
1
+ {"version":3,"file":"use-cursor-page.js","sourceRoot":"","sources":["../../../src/react/hooks/use-cursor-page.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAwD9C;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,UAAU,aAAa,CAAC,UAAgC,EAAE;IAC9D,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;IAE3C,6EAA6E;IAC7E,2CAA2C;IAC3C,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAGvC,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC;IAE/B,8EAA8E;IAC9E,+EAA+E;IAC/E,MAAM,UAAU,GAAG,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;IAEtD,8EAA8E;IAC9E,2EAA2E;IAC3E,yEAAyE;IACzE,uEAAuE;IACvE,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,YAAY,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC3C,CAAC;IACD,+EAA+E;IAC/E,+EAA+E;IAC/E,+CAA+C;IAC/C,MAAM,WAAW,GAAG,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAEpD,MAAM,gBAAgB,GAAG,WAAW,CAAC,GAAG,EAAE;QACxC,IAAI,WAAW,IAAI,CAAC;YAAE,OAAO;QAC7B,YAAY,CAAC,EAAE,IAAI,EAAE,WAAW,GAAG,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC;QACvD,YAAY,EAAE,EAAE,CAAC;IACnB,CAAC,EAAE,CAAC,WAAW,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC;IAE1C,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE;QAC7B,IAAI,WAAW,KAAK,CAAC;YAAE,OAAO;QAC9B,YAAY,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC;QACzC,YAAY,EAAE,EAAE,CAAC;IACnB,CAAC,EAAE,CAAC,WAAW,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC;IAE1C,8EAA8E;IAC9E,8EAA8E;IAC9E,MAAM,aAAa,GAAG,WAAW,CAC/B,CAAC,OAAgB,EAAc,EAAE,CAAC,CAAC;QACjC,WAAW;QACX,eAAe,EAAE,WAAW,GAAG,CAAC;QAChC,WAAW,EAAE,OAAO;QACpB,gBAAgB;QAChB,YAAY,EAAE,GAAG,EAAE;YACjB,IAAI,CAAC,OAAO;gBAAE,OAAO;YACrB,YAAY,CAAC,EAAE,IAAI,EAAE,WAAW,GAAG,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC;YACvD,YAAY,EAAE,EAAE,CAAC;QACnB,CAAC;KACF,CAAC,EACF,CAAC,WAAW,EAAE,QAAQ,EAAE,YAAY,EAAE,gBAAgB,CAAC,CACxD,CAAC;IAEF,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC;AAC/C,CAAC","sourcesContent":["'use client';\n\nimport { useCallback, useState } from 'react';\nimport type { ListPaginationState } from './use-paged-list.js';\n\n/**\n * Render-time page state for a cursor feed, shaped as {@link ListPaginationState}\n * so it drops straight into the ONE `ListPagination` control. Produced by\n * {@link CursorPager.paginationFor} once the query for `currentPage` has\n * answered with its `hasMore`.\n */\nexport interface CursorPage extends ListPaginationState {\n /** Never known for cursor pagination — the counter reads \"Page N\". */\n totalPages?: undefined;\n}\n\nexport interface UseCursorPageOptions {\n /** Called after the page actually changed. Same contract as `usePagedList`. */\n onPageChange?: () => void;\n /**\n * A snapshot of the query inputs the page number belongs to — a tag, a filter,\n * a sort. When it changes, the page is 1 again **in the same render**, so the\n * query never fires for \"page 4\" of inputs whose page 4 may not exist.\n *\n * Use this when the input change arrives as a prop (there is no event handler\n * of yours to hang the reset on); use {@link CursorPager.reset} when your own\n * handler already owns the change. Compose several inputs into one string\n * (`` `${type}|${projectId ?? \"\"}` ``) — the type is deliberately narrowed to\n * primitives so a fresh object literal cannot pin the list to page 1 forever.\n */\n resetKey?: string | number | boolean | null;\n}\n\n/**\n * What {@link useCursorPage} owns: the page number, the guarded step controls,\n * and the return-to-page-1 control.\n */\nexport interface CursorPager {\n /** 1-based page to feed into the paged query. */\n currentPage: number;\n /**\n * Return to page 1 without walking back. Call it from the handler that changes\n * the query's inputs (a new filter, a new tag, a new sort) — page 4 of the old\n * result set is not page 4 of the new one. A no-op on page 1, so it never\n * fires `onPageChange` for nothing.\n */\n reset: () => void;\n /**\n * Bind the query's answer to the controls: pass the `hasMore` that came back\n * for {@link currentPage} and render the result as\n * `<ListPagination pagination={…} />`. `hasMore` binds HERE, after the query,\n * because that is the only moment it exists — a cursor query needs\n * `currentPage` as its input, so `hasMore` cannot be an argument to the hook\n * that produces `currentPage`.\n */\n paginationFor: (hasMore: boolean) => CursorPage;\n}\n\n/**\n * Page state for a server-paged (cursor / `hasMore`) list: the 1-based page\n * number, the guarded step controls, and the reset — the pieces each\n * server-paged surface was otherwise re-declaring as a local `useState(1)` plus\n * its own clamped increment/decrement and its own \"reset when the filter\n * changed\" adjustment (ENG-002, ENG-003).\n *\n * The data stays the caller's, and the two halves bind at different moments:\n *\n * ```tsx\n * const pager = useCursorPage({ resetKey: tag });\n * const { data, isFetching } = useThingsByTag(tag, pager.currentPage);\n * …\n * <ListPagination pagination={pager.paginationFor(data?.hasMore ?? false)} busy={isFetching} />\n * ```\n *\n * The guards live in here, not at the call site: a step that cannot move the\n * page changes nothing and does not fire `onPageChange`.\n *\n * A surface whose data hook ALREADY owns its page state (it returns\n * `page`/`hasNextPage`/`nextPage`/`prevPage` itself) does not need this hook —\n * it maps those fields onto {@link ListPaginationState} directly. The hook\n * exists for the surfaces that would otherwise hand-roll the state.\n */\nexport function useCursorPage(options: UseCursorPageOptions = {}): CursorPager {\n const { onPageChange, resetKey } = options;\n\n // The stored page is only meaningful for the inputs it was reached under, so\n // the key it belongs to is stored WITH it.\n const [pageState, setPageState] = useState<{\n page: number;\n key: UseCursorPageOptions['resetKey'];\n }>({ page: 1, key: resetKey });\n\n // `Object.is`, the same comparison React uses for state and deps: a `NaN` key\n // must compare equal to itself, or the adjustment below would re-fire forever.\n const keyMatches = Object.is(pageState.key, resetKey);\n\n // React's \"adjusting state when a prop changes\": a new key retires the stored\n // page, because page 4 of the old result set is not page 4 of the new one.\n // Retiring it (rather than only ignoring it) is what makes going BACK to\n // earlier inputs start at page 1 too, instead of reviving a dead page.\n if (!keyMatches) {\n setPageState({ page: 1, key: resetKey });\n }\n // Derived as well as adjusted, so even the render that triggers the adjustment\n // already reports page 1 — the caller's query is never asked for a page of the\n // new inputs that the user never navigated to.\n const currentPage = keyMatches ? pageState.page : 1;\n\n const goToPreviousPage = useCallback(() => {\n if (currentPage <= 1) return;\n setPageState({ page: currentPage - 1, key: resetKey });\n onPageChange?.();\n }, [currentPage, resetKey, onPageChange]);\n\n const reset = useCallback(() => {\n if (currentPage === 1) return;\n setPageState({ page: 1, key: resetKey });\n onPageChange?.();\n }, [currentPage, resetKey, onPageChange]);\n\n // Memoized on the page state itself, so a consumer may hold it in a dep array\n // and it changes only when the page (or the callback/inputs) actually change.\n const paginationFor = useCallback(\n (hasMore: boolean): CursorPage => ({\n currentPage,\n canPreviousPage: currentPage > 1,\n canNextPage: hasMore,\n goToPreviousPage,\n goToNextPage: () => {\n if (!hasMore) return;\n setPageState({ page: currentPage + 1, key: resetKey });\n onPageChange?.();\n },\n }),\n [currentPage, resetKey, onPageChange, goToPreviousPage],\n );\n\n return { currentPage, reset, paginationFor };\n}\n"]}
@@ -1,20 +1,20 @@
1
- "use client";
2
- import * as React from "react";
1
+ 'use client';
2
+ import * as React from 'react';
3
3
  export function useMediaQuery(query) {
4
4
  const [matches, setMatches] = React.useState(false);
5
5
  React.useEffect(() => {
6
- if (typeof window === "undefined" || !window.matchMedia)
6
+ if (typeof window === 'undefined' || !window.matchMedia)
7
7
  return;
8
8
  const mql = window.matchMedia(query);
9
9
  const onChange = (e) => setMatches(e.matches);
10
10
  setMatches(mql.matches);
11
11
  if (mql.addEventListener)
12
- mql.addEventListener("change", onChange);
12
+ mql.addEventListener('change', onChange);
13
13
  else
14
14
  mql.addListener(onChange);
15
15
  return () => {
16
16
  if (mql.removeEventListener)
17
- mql.removeEventListener("change", onChange);
17
+ mql.removeEventListener('change', onChange);
18
18
  else
19
19
  mql.removeListener(onChange);
20
20
  };
@@ -1 +1 @@
1
- {"version":3,"file":"use-media-query.js","sourceRoot":"","sources":["../../../src/react/hooks/use-media-query.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAEpD,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACnB,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,CAAC,MAAM,CAAC,UAAU;YAAE,OAAO;QAEhE,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;QACrC,MAAM,QAAQ,GAAG,CAAC,CAAsB,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;QAEnE,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAExB,IAAI,GAAG,CAAC,gBAAgB;YAAE,GAAG,CAAC,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;;YAC9D,GAAG,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;QAE/B,OAAO,GAAG,EAAE;YACV,IAAI,GAAG,CAAC,mBAAmB;gBAAE,GAAG,CAAC,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;;gBACpE,GAAG,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;QACpC,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;IAEZ,OAAO,OAAO,CAAC;AACjB,CAAC","sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\n\nexport function useMediaQuery(query: string) {\n const [matches, setMatches] = React.useState(false);\n\n React.useEffect(() => {\n if (typeof window === \"undefined\" || !window.matchMedia) return;\n\n const mql = window.matchMedia(query);\n const onChange = (e: MediaQueryListEvent) => setMatches(e.matches);\n\n setMatches(mql.matches);\n\n if (mql.addEventListener) mql.addEventListener(\"change\", onChange);\n else mql.addListener(onChange);\n\n return () => {\n if (mql.removeEventListener) mql.removeEventListener(\"change\", onChange);\n else mql.removeListener(onChange);\n };\n }, [query]);\n\n return matches;\n}\n"]}
1
+ {"version":3,"file":"use-media-query.js","sourceRoot":"","sources":["../../../src/react/hooks/use-media-query.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAEpD,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACnB,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,CAAC,MAAM,CAAC,UAAU;YAAE,OAAO;QAEhE,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;QACrC,MAAM,QAAQ,GAAG,CAAC,CAAsB,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;QAEnE,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAExB,IAAI,GAAG,CAAC,gBAAgB;YAAE,GAAG,CAAC,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;;YAC9D,GAAG,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;QAE/B,OAAO,GAAG,EAAE;YACV,IAAI,GAAG,CAAC,mBAAmB;gBAAE,GAAG,CAAC,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;;gBACpE,GAAG,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;QACpC,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;IAEZ,OAAO,OAAO,CAAC;AACjB,CAAC","sourcesContent":["'use client';\n\nimport * as React from 'react';\n\nexport function useMediaQuery(query: string) {\n const [matches, setMatches] = React.useState(false);\n\n React.useEffect(() => {\n if (typeof window === 'undefined' || !window.matchMedia) return;\n\n const mql = window.matchMedia(query);\n const onChange = (e: MediaQueryListEvent) => setMatches(e.matches);\n\n setMatches(mql.matches);\n\n if (mql.addEventListener) mql.addEventListener('change', onChange);\n else mql.addListener(onChange);\n\n return () => {\n if (mql.removeEventListener) mql.removeEventListener('change', onChange);\n else mql.removeListener(onChange);\n };\n }, [query]);\n\n return matches;\n}\n"]}
@@ -1,5 +1,5 @@
1
- "use client";
2
- import { useCallback, useMemo, useState } from "react";
1
+ 'use client';
2
+ import { useCallback, useMemo, useState } from 'react';
3
3
  /**
4
4
  * The single owner of client-side slice pagination: local page state, the page
5
5
  * math, and the current slice over an ALREADY-FETCHED list.
@@ -1 +1 @@
1
- {"version":3,"file":"use-paged-list.js","sourceRoot":"","sources":["../../../src/react/hooks/use-paged-list.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAmDvD;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,YAAY,CAC1B,KAAmB,EACnB,QAAgB,EAChB,UAA+B,EAAE;IAEjC,MAAM,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC;IACjC,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IAEtD,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC;IACnE,6EAA6E;IAC7E,4EAA4E;IAC5E,2DAA2D;IAC3D,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,aAAa,CAAC,EAAE,UAAU,CAAC,CAAC;IAErE,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,EAAE;QAC7B,MAAM,UAAU,GAAG,CAAC,WAAW,GAAG,CAAC,CAAC,GAAG,QAAQ,CAAC;QAChD,OAAO,KAAK,CAAC,KAAK,CAAC,UAAU,EAAE,UAAU,GAAG,QAAQ,CAAC,CAAC;IACxD,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC,CAAC;IAEnC,MAAM,gBAAgB,GAAG,WAAW,CAAC,GAAG,EAAE;QACxC,IAAI,WAAW,IAAI,CAAC;YAAE,OAAO;QAC7B,gBAAgB,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC;QAClC,YAAY,EAAE,EAAE,CAAC;IACnB,CAAC,EAAE,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC,CAAC;IAEhC,MAAM,YAAY,GAAG,WAAW,CAAC,GAAG,EAAE;QACpC,IAAI,WAAW,IAAI,UAAU;YAAE,OAAO;QACtC,gBAAgB,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC;QAClC,YAAY,EAAE,EAAE,CAAC;IACnB,CAAC,EAAE,CAAC,WAAW,EAAE,UAAU,EAAE,YAAY,CAAC,CAAC,CAAC;IAE5C,OAAO;QACL,WAAW;QACX,UAAU;QACV,SAAS;QACT,eAAe,EAAE,WAAW,GAAG,CAAC;QAChC,WAAW,EAAE,WAAW,GAAG,UAAU;QACrC,gBAAgB;QAChB,YAAY;KACb,CAAC;AACJ,CAAC","sourcesContent":["\"use client\";\n\nimport { useCallback, useMemo, useState } from \"react\";\n\n/**\n * The control state a paginated list exposes to its paginator UI, rendered by\n * the ONE `ListPagination` component. Nothing else builds\n * Previous / counter / Next controls.\n *\n * `totalPages` is the flavor discriminant, and the ONLY difference between the\n * two flavors:\n *\n * - **Known total** (client-side slice pagination — {@link usePagedList}):\n * `totalPages` is a number and the counter reads `\"2 of 5\"`.\n * - **Unknown total** (server/cursor pagination — `useCursorPage().paginationFor(hasMore)`,\n * or a caller's own query hook): `totalPages` is omitted and the counter reads\n * `\"Page 2\"`.\n *\n * Both flavors share one visibility rule, one disabled-edge rule, one live\n * region, and one set of classes because they share one component (ENG-002,\n * FRONTEND-001).\n */\nexport interface ListPaginationState {\n /** 1-based page currently on screen. */\n currentPage: number;\n /**\n * Total page count when it is knowable — at least 1, even for an empty list\n * (an empty list is one empty page). Omitted for cursor/`hasMore` pagination,\n * where the total is unknown until the last page is reached.\n */\n totalPages?: number;\n canPreviousPage: boolean;\n canNextPage: boolean;\n goToPreviousPage: () => void;\n goToNextPage: () => void;\n}\n\nexport interface PagedList<T> extends ListPaginationState {\n /** Always known for a slice-paginated list. */\n totalPages: number;\n /** The slice of `items` belonging to `currentPage`. */\n pageItems: T[];\n}\n\nexport interface UsePagedListOptions {\n /**\n * Called after the page actually changed. Surfaces that keep a per-page\n * selection (an open detail row) clear it here — the old selection is not on\n * the new page.\n */\n onPageChange?: () => void;\n}\n\n/**\n * The single owner of client-side slice pagination: local page state, the page\n * math, and the current slice over an ALREADY-FETCHED list.\n *\n * Page size is the caller's — every surface passes its own page-size constant\n * (ENG-005), never a literal. Ordering and filtering stay with the caller: pass\n * the list already sorted and filtered.\n *\n * Not for server-paged lists — a cursor/`hasMore` feed pages through the\n * caller's data layer, not through a slice; use `useCursorPage` (or the query\n * hook's own page state) with the same `ListPagination` control.\n */\nexport function usePagedList<T>(\n items: readonly T[],\n pageSize: number,\n options: UsePagedListOptions = {},\n): PagedList<T> {\n const { onPageChange } = options;\n const [requestedPage, setRequestedPage] = useState(1);\n\n const totalPages = Math.max(1, Math.ceil(items.length / pageSize));\n // The list can shrink under a page that is already open (an item is deleted,\n // a filter narrows). Clamping keeps the paginator on a real page instead of\n // rendering an empty slice under an out-of-range \"4 of 2\".\n const currentPage = Math.min(Math.max(1, requestedPage), totalPages);\n\n const pageItems = useMemo(() => {\n const startIndex = (currentPage - 1) * pageSize;\n return items.slice(startIndex, startIndex + pageSize);\n }, [items, currentPage, pageSize]);\n\n const goToPreviousPage = useCallback(() => {\n if (currentPage <= 1) return;\n setRequestedPage(currentPage - 1);\n onPageChange?.();\n }, [currentPage, onPageChange]);\n\n const goToNextPage = useCallback(() => {\n if (currentPage >= totalPages) return;\n setRequestedPage(currentPage + 1);\n onPageChange?.();\n }, [currentPage, totalPages, onPageChange]);\n\n return {\n currentPage,\n totalPages,\n pageItems,\n canPreviousPage: currentPage > 1,\n canNextPage: currentPage < totalPages,\n goToPreviousPage,\n goToNextPage,\n };\n}\n"]}
1
+ {"version":3,"file":"use-paged-list.js","sourceRoot":"","sources":["../../../src/react/hooks/use-paged-list.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAmDvD;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,YAAY,CAC1B,KAAmB,EACnB,QAAgB,EAChB,UAA+B,EAAE;IAEjC,MAAM,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC;IACjC,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IAEtD,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC;IACnE,6EAA6E;IAC7E,4EAA4E;IAC5E,2DAA2D;IAC3D,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,aAAa,CAAC,EAAE,UAAU,CAAC,CAAC;IAErE,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,EAAE;QAC7B,MAAM,UAAU,GAAG,CAAC,WAAW,GAAG,CAAC,CAAC,GAAG,QAAQ,CAAC;QAChD,OAAO,KAAK,CAAC,KAAK,CAAC,UAAU,EAAE,UAAU,GAAG,QAAQ,CAAC,CAAC;IACxD,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC,CAAC;IAEnC,MAAM,gBAAgB,GAAG,WAAW,CAAC,GAAG,EAAE;QACxC,IAAI,WAAW,IAAI,CAAC;YAAE,OAAO;QAC7B,gBAAgB,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC;QAClC,YAAY,EAAE,EAAE,CAAC;IACnB,CAAC,EAAE,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC,CAAC;IAEhC,MAAM,YAAY,GAAG,WAAW,CAAC,GAAG,EAAE;QACpC,IAAI,WAAW,IAAI,UAAU;YAAE,OAAO;QACtC,gBAAgB,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC;QAClC,YAAY,EAAE,EAAE,CAAC;IACnB,CAAC,EAAE,CAAC,WAAW,EAAE,UAAU,EAAE,YAAY,CAAC,CAAC,CAAC;IAE5C,OAAO;QACL,WAAW;QACX,UAAU;QACV,SAAS;QACT,eAAe,EAAE,WAAW,GAAG,CAAC;QAChC,WAAW,EAAE,WAAW,GAAG,UAAU;QACrC,gBAAgB;QAChB,YAAY;KACb,CAAC;AACJ,CAAC","sourcesContent":["'use client';\n\nimport { useCallback, useMemo, useState } from 'react';\n\n/**\n * The control state a paginated list exposes to its paginator UI, rendered by\n * the ONE `ListPagination` component. Nothing else builds\n * Previous / counter / Next controls.\n *\n * `totalPages` is the flavor discriminant, and the ONLY difference between the\n * two flavors:\n *\n * - **Known total** (client-side slice pagination — {@link usePagedList}):\n * `totalPages` is a number and the counter reads `\"2 of 5\"`.\n * - **Unknown total** (server/cursor pagination — `useCursorPage().paginationFor(hasMore)`,\n * or a caller's own query hook): `totalPages` is omitted and the counter reads\n * `\"Page 2\"`.\n *\n * Both flavors share one visibility rule, one disabled-edge rule, one live\n * region, and one set of classes because they share one component (ENG-002,\n * FRONTEND-001).\n */\nexport interface ListPaginationState {\n /** 1-based page currently on screen. */\n currentPage: number;\n /**\n * Total page count when it is knowable — at least 1, even for an empty list\n * (an empty list is one empty page). Omitted for cursor/`hasMore` pagination,\n * where the total is unknown until the last page is reached.\n */\n totalPages?: number;\n canPreviousPage: boolean;\n canNextPage: boolean;\n goToPreviousPage: () => void;\n goToNextPage: () => void;\n}\n\nexport interface PagedList<T> extends ListPaginationState {\n /** Always known for a slice-paginated list. */\n totalPages: number;\n /** The slice of `items` belonging to `currentPage`. */\n pageItems: T[];\n}\n\nexport interface UsePagedListOptions {\n /**\n * Called after the page actually changed. Surfaces that keep a per-page\n * selection (an open detail row) clear it here — the old selection is not on\n * the new page.\n */\n onPageChange?: () => void;\n}\n\n/**\n * The single owner of client-side slice pagination: local page state, the page\n * math, and the current slice over an ALREADY-FETCHED list.\n *\n * Page size is the caller's — every surface passes its own page-size constant\n * (ENG-005), never a literal. Ordering and filtering stay with the caller: pass\n * the list already sorted and filtered.\n *\n * Not for server-paged lists — a cursor/`hasMore` feed pages through the\n * caller's data layer, not through a slice; use `useCursorPage` (or the query\n * hook's own page state) with the same `ListPagination` control.\n */\nexport function usePagedList<T>(\n items: readonly T[],\n pageSize: number,\n options: UsePagedListOptions = {},\n): PagedList<T> {\n const { onPageChange } = options;\n const [requestedPage, setRequestedPage] = useState(1);\n\n const totalPages = Math.max(1, Math.ceil(items.length / pageSize));\n // The list can shrink under a page that is already open (an item is deleted,\n // a filter narrows). Clamping keeps the paginator on a real page instead of\n // rendering an empty slice under an out-of-range \"4 of 2\".\n const currentPage = Math.min(Math.max(1, requestedPage), totalPages);\n\n const pageItems = useMemo(() => {\n const startIndex = (currentPage - 1) * pageSize;\n return items.slice(startIndex, startIndex + pageSize);\n }, [items, currentPage, pageSize]);\n\n const goToPreviousPage = useCallback(() => {\n if (currentPage <= 1) return;\n setRequestedPage(currentPage - 1);\n onPageChange?.();\n }, [currentPage, onPageChange]);\n\n const goToNextPage = useCallback(() => {\n if (currentPage >= totalPages) return;\n setRequestedPage(currentPage + 1);\n onPageChange?.();\n }, [currentPage, totalPages, onPageChange]);\n\n return {\n currentPage,\n totalPages,\n pageItems,\n canPreviousPage: currentPage > 1,\n canNextPage: currentPage < totalPages,\n goToPreviousPage,\n goToNextPage,\n };\n}\n"]}
@@ -22,5 +22,5 @@ export declare function readReturnScroll(key: string): ReturnScrollEntry | null;
22
22
  export declare function saveReturnScroll(key: string, y?: number): void;
23
23
  /** Drop the entry for `key` (e.g. the list changed underneath the saved offset). */
24
24
  export declare function clearReturnScroll(key: string): void;
25
- export declare function useReturnScroll({ key, eligible, ready }: UseReturnScrollOptions): UseReturnScrollResult;
25
+ export declare function useReturnScroll({ key, eligible, ready, }: UseReturnScrollOptions): UseReturnScrollResult;
26
26
  //# sourceMappingURL=use-return-scroll.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-return-scroll.d.ts","sourceRoot":"","sources":["../../../src/react/hooks/use-return-scroll.ts"],"names":[],"mappings":"AA2BA,MAAM,WAAW,iBAAiB;IAChC,kCAAkC;IAClC,CAAC,EAAE,MAAM,CAAC;IACV,wFAAwF;IACxF,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,sBAAsB;IACrC,uFAAuF;IACvF,GAAG,EAAE,MAAM,CAAC;IACZ,uGAAuG;IACvG,QAAQ,EAAE,OAAO,CAAC;IAClB,6FAA6F;IAC7F,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,qBAAqB;IACpC,qFAAqF;IACrF,IAAI,EAAE,MAAM,IAAI,CAAC;CAClB;AAeD,iFAAiF;AACjF,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI,CActE;AAED,2FAA2F;AAC3F,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAU9D;AAED,oFAAoF;AACpF,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAQnD;AASD,wBAAgB,eAAe,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,sBAAsB,GAAG,qBAAqB,CAuCvG"}
1
+ {"version":3,"file":"use-return-scroll.d.ts","sourceRoot":"","sources":["../../../src/react/hooks/use-return-scroll.ts"],"names":[],"mappings":"AA2BA,MAAM,WAAW,iBAAiB;IAChC,kCAAkC;IAClC,CAAC,EAAE,MAAM,CAAC;IACV,wFAAwF;IACxF,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,sBAAsB;IACrC,uFAAuF;IACvF,GAAG,EAAE,MAAM,CAAC;IACZ,uGAAuG;IACvG,QAAQ,EAAE,OAAO,CAAC;IAClB,6FAA6F;IAC7F,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,qBAAqB;IACpC,qFAAqF;IACrF,IAAI,EAAE,MAAM,IAAI,CAAC;CAClB;AAeD,iFAAiF;AACjF,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI,CActE;AAED,2FAA2F;AAC3F,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAU9D;AAED,oFAAoF;AACpF,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAQnD;AASD,wBAAgB,eAAe,CAAC,EAC9B,GAAG,EACH,QAAQ,EACR,KAAK,GACN,EAAE,sBAAsB,GAAG,qBAAqB,CAuChD"}