@lattice-php/lattice 0.19.0 → 0.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (343) hide show
  1. package/dist/action/components/action-form.d.ts +6 -1
  2. package/dist/action/components/action-form.js +34 -49
  3. package/dist/action/components/action-form.js.map +1 -1
  4. package/dist/action/components/action-trigger-provider.d.ts +1 -1
  5. package/dist/action/components/action-trigger-provider.js.map +1 -1
  6. package/dist/action/hooks/use-action.d.ts +1 -1
  7. package/dist/action/hooks/use-action.js +3 -1
  8. package/dist/action/hooks/use-action.js.map +1 -1
  9. package/dist/action/index.d.ts +0 -2
  10. package/dist/action/index.js +1 -2
  11. package/dist/chat/plugin.d.ts +0 -1
  12. package/dist/chat/plugin.js.map +1 -1
  13. package/dist/clipboard/index.d.ts +0 -4
  14. package/dist/clipboard/index.js +1 -15
  15. package/dist/{events → core}/event-names.js +1 -1
  16. package/dist/core/event-names.js.map +1 -0
  17. package/dist/core/hooks/use-window-event.d.ts +8 -0
  18. package/dist/core/hooks/use-window-event.js +22 -0
  19. package/dist/core/hooks/use-window-event.js.map +1 -0
  20. package/dist/core/index.js +1 -1
  21. package/dist/core/types.d.ts +8 -61
  22. package/dist/create-app.d.ts +31 -3
  23. package/dist/create-app.js +48 -10
  24. package/dist/create-app.js.map +1 -1
  25. package/dist/effects/dispatch.js +1 -1
  26. package/dist/effects/dispatch.js.map +1 -1
  27. package/dist/effects/registry.d.ts +2 -18
  28. package/dist/effects/registry.js +5 -9
  29. package/dist/effects/registry.js.map +1 -1
  30. package/dist/event-bridge.js +10 -23
  31. package/dist/event-bridge.js.map +1 -1
  32. package/dist/form/components/base/field.d.ts +2 -2
  33. package/dist/form/components/base/field.js +2 -2
  34. package/dist/form/components/base/field.js.map +1 -1
  35. package/dist/form/components/fields/color-picker-field.d.ts +2 -0
  36. package/dist/form/components/fields/color-picker-field.js +57 -0
  37. package/dist/form/components/fields/color-picker-field.js.map +1 -0
  38. package/dist/form/components/fields/date-input.js +1 -1
  39. package/dist/form/components/fields/date-time-input.js +1 -1
  40. package/dist/form/components/fields/file-upload.js +11 -18
  41. package/dist/form/components/fields/file-upload.js.map +1 -1
  42. package/dist/form/components/fields/number-input.js +1 -1
  43. package/dist/form/components/fields/rich-editor-field.js +35 -276
  44. package/dist/form/components/fields/rich-editor-field.js.map +1 -1
  45. package/dist/form/components/fields/row-action-menu.js +2 -2
  46. package/dist/form/components/fields/row-action-menu.js.map +1 -1
  47. package/dist/form/components/fields/row-actions.js +3 -1
  48. package/dist/form/components/fields/row-actions.js.map +1 -1
  49. package/dist/form/components/fields/select.js +60 -17
  50. package/dist/form/components/fields/select.js.map +1 -1
  51. package/dist/form/components/fields/table-rows.js +5 -17
  52. package/dist/form/components/fields/table-rows.js.map +1 -1
  53. package/dist/form/components/fields/text-input.js +8 -1
  54. package/dist/form/components/fields/text-input.js.map +1 -1
  55. package/dist/form/components/fields/time-input.js +1 -1
  56. package/dist/form/components/form.js +8 -23
  57. package/dist/form/components/form.js.map +1 -1
  58. package/dist/form/components/index.d.ts +1 -0
  59. package/dist/form/components/index.js +2 -1
  60. package/dist/form/embed.d.ts +5 -0
  61. package/dist/form/embed.js +4 -1
  62. package/dist/form/hooks/use-form-resolver.js.map +1 -1
  63. package/dist/form/index.js +2 -1
  64. package/dist/form/lib/collect-fields.d.ts +7 -0
  65. package/dist/form/lib/collect-fields.js +19 -0
  66. package/dist/form/lib/collect-fields.js.map +1 -0
  67. package/dist/form/lib/conditions.d.ts +4 -10
  68. package/dist/form/lib/conditions.js.map +1 -1
  69. package/dist/form/lib/field-errors.d.ts +3 -0
  70. package/dist/form/lib/field-errors.js +11 -0
  71. package/dist/form/lib/field-errors.js.map +1 -0
  72. package/dist/form/lib/field-props.d.ts +4 -18
  73. package/dist/form/lib/field-props.js.map +1 -1
  74. package/dist/form/plugin.js +2 -0
  75. package/dist/form/plugin.js.map +1 -1
  76. package/dist/form/rich-editor/builtins.d.ts +6 -0
  77. package/dist/form/rich-editor/builtins.js +400 -0
  78. package/dist/form/rich-editor/builtins.js.map +1 -0
  79. package/dist/form/rich-editor/index.d.ts +7 -0
  80. package/dist/form/rich-editor/index.js +3 -0
  81. package/dist/form/rich-editor/registry.d.ts +67 -0
  82. package/dist/form/rich-editor/registry.js +79 -0
  83. package/dist/form/rich-editor/registry.js.map +1 -0
  84. package/dist/form/rich-editor/toolbar-button.d.ts +12 -0
  85. package/dist/form/rich-editor/toolbar-button.js +28 -0
  86. package/dist/form/rich-editor/toolbar-button.js.map +1 -0
  87. package/dist/form/types.d.ts +1 -6
  88. package/dist/format/date-time.d.ts +3 -2
  89. package/dist/format/date-time.js.map +1 -1
  90. package/dist/format/format-context.d.ts +6 -0
  91. package/dist/format/format-context.js +17 -0
  92. package/dist/format/format-context.js.map +1 -0
  93. package/dist/i18n/date-time.d.ts +3 -2
  94. package/dist/i18n/date-time.js.map +1 -1
  95. package/dist/i18n/index.js +3 -2
  96. package/dist/i18n/locale-reload.d.ts +1 -1
  97. package/dist/i18n/locale-reload.js +7 -6
  98. package/dist/i18n/locale-reload.js.map +1 -1
  99. package/dist/i18n/locale.js +1 -1
  100. package/dist/i18n/locale.js.map +1 -1
  101. package/dist/i18n/page-props.d.ts +3 -2
  102. package/dist/i18n/page-props.js +1 -15
  103. package/dist/i18n/page-props.js.map +1 -1
  104. package/dist/i18n/shared-props.d.ts +7 -0
  105. package/dist/i18n/shared-props.js +23 -0
  106. package/dist/i18n/shared-props.js.map +1 -0
  107. package/dist/i18n/timezone.js +1 -1
  108. package/dist/i18n/timezone.js.map +1 -1
  109. package/dist/index.d.ts +11 -10
  110. package/dist/index.js +5 -5
  111. package/dist/lattice.css +212 -47
  112. package/dist/layout/components/breadcrumbs.js +3 -1
  113. package/dist/layout/components/breadcrumbs.js.map +1 -1
  114. package/dist/layout/components/sidebar.js +15 -48
  115. package/dist/layout/components/sidebar.js.map +1 -1
  116. package/dist/layout/plugin.d.ts +0 -1
  117. package/dist/layout/plugin.js.map +1 -1
  118. package/dist/lib/color.d.ts +9 -0
  119. package/dist/lib/color.js +48 -0
  120. package/dist/lib/color.js.map +1 -0
  121. package/dist/lib/is-truthy.d.ts +2 -0
  122. package/dist/lib/is-truthy.js +9 -0
  123. package/dist/lib/is-truthy.js.map +1 -0
  124. package/dist/lib/use-debounced-callback.d.ts +10 -0
  125. package/dist/lib/use-debounced-callback.js +34 -0
  126. package/dist/lib/use-debounced-callback.js.map +1 -0
  127. package/dist/lib/use-media-query.d.ts +5 -0
  128. package/dist/lib/use-media-query.js +26 -0
  129. package/dist/lib/use-media-query.js.map +1 -0
  130. package/dist/lib/use-persistent-state.d.ts +13 -0
  131. package/dist/lib/use-persistent-state.js +62 -0
  132. package/dist/lib/use-persistent-state.js.map +1 -0
  133. package/dist/notifications/api.d.ts +6 -6
  134. package/dist/notifications/api.js.map +1 -1
  135. package/dist/notifications/components/notifications.js +3 -1
  136. package/dist/notifications/components/notifications.js.map +1 -1
  137. package/dist/notifications/plugin.d.ts +0 -1
  138. package/dist/notifications/plugin.js.map +1 -1
  139. package/dist/notifications/types.d.ts +2 -10
  140. package/dist/provider-base.js +1 -1
  141. package/dist/realtime/build-effects.js +5 -5
  142. package/dist/realtime/build-effects.js.map +1 -1
  143. package/dist/realtime/listeners.d.ts +2 -2
  144. package/dist/realtime/listeners.js +1 -1
  145. package/dist/realtime/listeners.js.map +1 -1
  146. package/dist/realtime/subscriptions.d.ts +2 -2
  147. package/dist/realtime/subscriptions.js.map +1 -1
  148. package/dist/registry.d.ts +5 -0
  149. package/dist/registry.js.map +1 -1
  150. package/dist/remote/components/data-list.js +1 -1
  151. package/dist/remote/plugin.d.ts +0 -1
  152. package/dist/remote/plugin.js.map +1 -1
  153. package/dist/table/components/bulk-bar.js +7 -5
  154. package/dist/table/components/bulk-bar.js.map +1 -1
  155. package/dist/table/components/cells/badge-cell.js +4 -1
  156. package/dist/table/components/cells/badge-cell.js.map +1 -1
  157. package/dist/table/components/cells/boolean-cell.js +4 -4
  158. package/dist/table/components/cells/boolean-cell.js.map +1 -1
  159. package/dist/table/components/cells/copyable-cell.d.ts +9 -0
  160. package/dist/table/components/cells/copyable-cell.js +17 -0
  161. package/dist/table/components/cells/copyable-cell.js.map +1 -0
  162. package/dist/table/components/cells/icon-cell.js +5 -2
  163. package/dist/table/components/cells/icon-cell.js.map +1 -1
  164. package/dist/table/components/cells/image-cell.js +8 -9
  165. package/dist/table/components/cells/image-cell.js.map +1 -1
  166. package/dist/table/components/cells/money-cell.js +7 -10
  167. package/dist/table/components/cells/money-cell.js.map +1 -1
  168. package/dist/table/components/cells/number-cell.js +14 -19
  169. package/dist/table/components/cells/number-cell.js.map +1 -1
  170. package/dist/table/components/cells/numeric-cell.d.ts +10 -0
  171. package/dist/table/components/cells/numeric-cell.js +25 -0
  172. package/dist/table/components/cells/numeric-cell.js.map +1 -0
  173. package/dist/table/components/cells/stack-cell.js +1 -1
  174. package/dist/table/components/cells/text-cell.js +8 -6
  175. package/dist/table/components/cells/text-cell.js.map +1 -1
  176. package/dist/table/components/column-filter-control.js +25 -32
  177. package/dist/table/components/column-filter-control.js.map +1 -1
  178. package/dist/table/components/column-header.d.ts +3 -3
  179. package/dist/table/components/column-header.js +5 -3
  180. package/dist/table/components/column-header.js.map +1 -1
  181. package/dist/table/components/column-visibility-menu.js +6 -11
  182. package/dist/table/components/column-visibility-menu.js.map +1 -1
  183. package/dist/table/components/filter-bar.d.ts +2 -2
  184. package/dist/table/components/filter-bar.js +13 -22
  185. package/dist/table/components/filter-bar.js.map +1 -1
  186. package/dist/table/components/filter-controls.d.ts +2 -1
  187. package/dist/table/components/filter-controls.js +37 -38
  188. package/dist/table/components/filter-controls.js.map +1 -1
  189. package/dist/table/components/filter-value-input.d.ts +0 -1
  190. package/dist/table/components/filter-value-input.js +21 -20
  191. package/dist/table/components/filter-value-input.js.map +1 -1
  192. package/dist/table/components/pagination.js +16 -20
  193. package/dist/table/components/pagination.js.map +1 -1
  194. package/dist/table/components/sort-bar.d.ts +3 -3
  195. package/dist/table/components/sort-bar.js +11 -12
  196. package/dist/table/components/sort-bar.js.map +1 -1
  197. package/dist/table/components/table-cell.js.map +1 -1
  198. package/dist/table/components/table-search.d.ts +9 -0
  199. package/dist/table/components/table-search.js +72 -0
  200. package/dist/table/components/table-search.js.map +1 -0
  201. package/dist/table/components/table.js +73 -21
  202. package/dist/table/components/table.js.map +1 -1
  203. package/dist/table/hooks/use-column-visibility.js +29 -58
  204. package/dist/table/hooks/use-column-visibility.js.map +1 -1
  205. package/dist/table/hooks/use-expanded-rows.d.ts +8 -0
  206. package/dist/table/hooks/use-expanded-rows.js +24 -0
  207. package/dist/table/hooks/use-expanded-rows.js.map +1 -0
  208. package/dist/table/hooks/use-table.d.ts +5 -3
  209. package/dist/table/hooks/use-table.js +59 -55
  210. package/dist/table/hooks/use-table.js.map +1 -1
  211. package/dist/table/lib/bulk.d.ts +2 -0
  212. package/dist/table/lib/bulk.js +3 -1
  213. package/dist/table/lib/bulk.js.map +1 -1
  214. package/dist/table/lib/payload.d.ts +3 -2
  215. package/dist/table/lib/payload.js +16 -10
  216. package/dist/table/lib/payload.js.map +1 -1
  217. package/dist/table/lib/query.d.ts +5 -5
  218. package/dist/table/lib/query.js +21 -19
  219. package/dist/table/lib/query.js.map +1 -1
  220. package/dist/table/plugin.d.ts +0 -1
  221. package/dist/table/plugin.js.map +1 -1
  222. package/dist/table/types.d.ts +5 -81
  223. package/dist/toast/callout.js +2 -4
  224. package/dist/toast/callout.js.map +1 -1
  225. package/dist/toast/index.d.ts +1 -1
  226. package/dist/toast/index.js +2 -2
  227. package/dist/toast/toast.d.ts +1 -7
  228. package/dist/toast/toast.js +3 -15
  229. package/dist/toast/toast.js.map +1 -1
  230. package/dist/toast/toaster.js.map +1 -1
  231. package/dist/types/generated.d.ts +444 -225
  232. package/dist/types/index.d.ts +1 -1
  233. package/dist/ui/affix-group.d.ts +2 -1
  234. package/dist/ui/affix-group.js +9 -7
  235. package/dist/ui/affix-group.js.map +1 -1
  236. package/dist/ui/avatar.d.ts +3 -0
  237. package/dist/ui/avatar.js +52 -0
  238. package/dist/ui/avatar.js.map +1 -0
  239. package/dist/ui/button.d.ts +5 -3
  240. package/dist/ui/button.js +10 -3
  241. package/dist/ui/button.js.map +1 -1
  242. package/dist/ui/chart-view.js +155 -28
  243. package/dist/ui/chart-view.js.map +1 -1
  244. package/dist/ui/click-behavior.d.ts +4 -4
  245. package/dist/ui/click-behavior.js.map +1 -1
  246. package/dist/ui/collapsible.js +3 -15
  247. package/dist/ui/collapsible.js.map +1 -1
  248. package/dist/ui/color-picker.d.ts +8 -0
  249. package/dist/ui/color-picker.js +59 -0
  250. package/dist/ui/color-picker.js.map +1 -0
  251. package/dist/ui/combobox.d.ts +11 -2
  252. package/dist/ui/combobox.js +57 -11
  253. package/dist/ui/combobox.js.map +1 -1
  254. package/dist/ui/confirm-dialog.js +1 -1
  255. package/dist/ui/confirm-dialog.js.map +1 -1
  256. package/dist/ui/control.d.ts +1 -1
  257. package/dist/ui/copyable-text.d.ts +7 -0
  258. package/dist/ui/copyable-text.js +21 -13
  259. package/dist/ui/copyable-text.js.map +1 -1
  260. package/dist/ui/dialog.d.ts +6 -2
  261. package/dist/ui/dialog.js +29 -5
  262. package/dist/ui/dialog.js.map +1 -1
  263. package/dist/ui/fragment.js +1 -1
  264. package/dist/ui/fragment.js.map +1 -1
  265. package/dist/ui/heading.js +39 -21
  266. package/dist/ui/heading.js.map +1 -1
  267. package/dist/ui/icon-button.d.ts +22 -0
  268. package/dist/ui/icon-button.js +51 -0
  269. package/dist/ui/icon-button.js.map +1 -0
  270. package/dist/ui/icon.js +10 -11
  271. package/dist/ui/icon.js.map +1 -1
  272. package/dist/ui/image-preview.d.ts +12 -0
  273. package/dist/ui/image-preview.js +65 -0
  274. package/dist/ui/image-preview.js.map +1 -0
  275. package/dist/ui/image.d.ts +3 -0
  276. package/dist/ui/image.js +21 -0
  277. package/dist/ui/image.js.map +1 -0
  278. package/dist/ui/index.d.ts +2 -1
  279. package/dist/ui/index.js +4 -3
  280. package/dist/ui/info-tooltip.js +1 -1
  281. package/dist/ui/info-tooltip.js.map +1 -1
  282. package/dist/ui/input.d.ts +3 -1
  283. package/dist/ui/input.js +2 -2
  284. package/dist/ui/input.js.map +1 -1
  285. package/dist/ui/modal.js +17 -4
  286. package/dist/ui/modal.js.map +1 -1
  287. package/dist/ui/native-select.d.ts +10 -0
  288. package/dist/ui/native-select.js +23 -0
  289. package/dist/ui/native-select.js.map +1 -0
  290. package/dist/ui/pill.d.ts +2 -0
  291. package/dist/ui/pill.js +10 -0
  292. package/dist/ui/pill.js.map +1 -0
  293. package/dist/ui/plugin.js +11 -1
  294. package/dist/ui/plugin.js.map +1 -1
  295. package/dist/ui/progress.d.ts +3 -0
  296. package/dist/ui/progress.js +114 -0
  297. package/dist/ui/progress.js.map +1 -0
  298. package/dist/ui/section.js +2 -15
  299. package/dist/ui/section.js.map +1 -1
  300. package/dist/ui/segmented-pills.js +2 -1
  301. package/dist/ui/segmented-pills.js.map +1 -1
  302. package/dist/ui/separator.d.ts +3 -0
  303. package/dist/ui/separator.js +15 -0
  304. package/dist/ui/separator.js.map +1 -0
  305. package/dist/ui/tabs.js +12 -10
  306. package/dist/ui/tabs.js.map +1 -1
  307. package/dist/ui/text.js +5 -10
  308. package/dist/ui/text.js.map +1 -1
  309. package/dist/ui/tree-context.d.ts +33 -0
  310. package/dist/ui/tree-context.js +135 -0
  311. package/dist/ui/tree-context.js.map +1 -0
  312. package/dist/ui/tree.d.ts +19 -0
  313. package/dist/ui/tree.js +187 -0
  314. package/dist/ui/tree.js.map +1 -0
  315. package/dist/ui/use-collapsible-state.d.ts +7 -0
  316. package/dist/ui/use-collapsible-state.js +21 -0
  317. package/dist/ui/use-collapsible-state.js.map +1 -0
  318. package/dist-standalone/chunks/chart-view-C6R5iPra.js +36 -0
  319. package/dist-standalone/chunks/date-picker-field-DhhEB-Mh.js +1 -0
  320. package/dist-standalone/chunks/jsx-runtime-Drll_-DD.js +1 -0
  321. package/dist-standalone/chunks/locale-CXqr7LPR.js +1 -0
  322. package/dist-standalone/chunks/page-props-DOfg30l5.js +1 -0
  323. package/dist-standalone/chunks/rich-editor-field-DORXTHPw.js +154 -0
  324. package/dist-standalone/chunks/{subscriptions-B3UuDBmx.js → subscriptions-B_ISgA7V.js} +1 -1
  325. package/dist-standalone/chunks/use-effect-dispatcher-D1wPPwHj.js +97 -0
  326. package/dist-standalone/lattice.css +1 -1
  327. package/dist-standalone/lattice.js +15 -15
  328. package/dist-standalone/manifest.json +11 -9
  329. package/dist-standalone/sprite.svg +1 -1
  330. package/package.json +6 -1
  331. package/resources/icons/code-xml.svg +17 -0
  332. package/resources/icons/heading.svg +17 -0
  333. package/dist/clipboard/index.js.map +0 -1
  334. package/dist/events/event-names.js.map +0 -1
  335. package/dist/table/components/table-action-node.d.ts +0 -4
  336. package/dist/table/components/table-action-node.js +0 -24
  337. package/dist/table/components/table-action-node.js.map +0 -1
  338. package/dist-standalone/chunks/chart-view-CK5fKIkR.js +0 -36
  339. package/dist-standalone/chunks/date-picker-field-BlCPFhZd.js +0 -1
  340. package/dist-standalone/chunks/jsx-runtime-CJ_btYLc.js +0 -1
  341. package/dist-standalone/chunks/rich-editor-field-DH5dS5c1.js +0 -154
  342. package/dist-standalone/chunks/use-effect-dispatcher-k98Nzf9M.js +0 -97
  343. /package/dist/{events → core}/event-names.d.ts +0 -0
package/dist/lattice.css CHANGED
@@ -85,6 +85,7 @@
85
85
 
86
86
  --lt-duration-fast: 120ms;
87
87
  --lt-duration-base: 160ms;
88
+ --lt-duration-slow: 240ms;
88
89
 
89
90
  --lt-sidebar-w: 16rem;
90
91
  --lt-sidebar-w-collapsed: 4rem;
@@ -96,6 +97,20 @@
96
97
  color-scheme: light;
97
98
  }
98
99
 
100
+ /*
101
+ * Radix keeps dialogs mounted until their exit animation ends, so reduced
102
+ * motion zeroes the durations instead of removing the animations — the
103
+ * animation events still fire and close stays instant.
104
+ */
105
+ @media (prefers-reduced-motion: reduce) {
106
+ :root,
107
+ [data-theme="light"] {
108
+ --lt-duration-fast: 0ms;
109
+ --lt-duration-base: 0ms;
110
+ --lt-duration-slow: 0ms;
111
+ }
112
+ }
113
+
99
114
  [data-theme="dark"],
100
115
  .dark {
101
116
  --lt-bg: var(--background, oklch(0.145 0 0));
@@ -205,6 +220,14 @@
205
220
  --font-weight-lt-bold: var(--lt-font-weight-bold);
206
221
  --animate-lt-toast-in: lt-toast-in var(--lt-duration-base) ease-out;
207
222
  --animate-lt-toast-out: lt-toast-out var(--lt-duration-fast) ease-in;
223
+ --animate-lt-fade-in: lt-fade-in var(--lt-duration-base) ease-out;
224
+ --animate-lt-fade-out: lt-fade-out var(--lt-duration-fast) ease-in;
225
+ --animate-lt-dialog-in: lt-dialog-in var(--lt-duration-base) ease-out;
226
+ --animate-lt-dialog-out: lt-dialog-out var(--lt-duration-fast) ease-in;
227
+ --animate-lt-sheet-in-start: lt-sheet-in-start var(--lt-duration-slow) ease-out;
228
+ --animate-lt-sheet-out-start: lt-sheet-out-start var(--lt-duration-fast) ease-in;
229
+ --animate-lt-sheet-in-end: lt-sheet-in-end var(--lt-duration-slow) ease-out;
230
+ --animate-lt-sheet-out-end: lt-sheet-out-end var(--lt-duration-fast) ease-in;
208
231
  }
209
232
 
210
233
  @theme {
@@ -285,13 +308,124 @@
285
308
  }
286
309
  }
287
310
 
311
+ @keyframes lt-fade-in {
312
+ from {
313
+ opacity: 0;
314
+ }
315
+ to {
316
+ opacity: 1;
317
+ }
318
+ }
319
+
320
+ @keyframes lt-fade-out {
321
+ from {
322
+ opacity: 1;
323
+ }
324
+ to {
325
+ opacity: 0;
326
+ }
327
+ }
328
+
329
+ /* Centering uses Tailwind's standalone translate property, which composes
330
+ with transform — so these keyframes may only animate opacity and scale,
331
+ never a translate of their own. */
332
+ @keyframes lt-dialog-in {
333
+ from {
334
+ opacity: 0;
335
+ transform: scale(0.98);
336
+ }
337
+ to {
338
+ opacity: 1;
339
+ transform: scale(1);
340
+ }
341
+ }
342
+
343
+ @keyframes lt-dialog-out {
344
+ from {
345
+ opacity: 1;
346
+ transform: scale(1);
347
+ }
348
+ to {
349
+ opacity: 0;
350
+ transform: scale(0.98);
351
+ }
352
+ }
353
+
354
+ /* Sheet slides are physical (translateX): under RTL a sheet docks to the
355
+ correct logical edge but enters from the mirrored side. Shipped locales
356
+ are LTR. */
357
+ @keyframes lt-sheet-in-start {
358
+ from {
359
+ transform: translateX(-100%);
360
+ }
361
+ to {
362
+ transform: translateX(0);
363
+ }
364
+ }
365
+
366
+ @keyframes lt-sheet-out-start {
367
+ from {
368
+ transform: translateX(0);
369
+ }
370
+ to {
371
+ transform: translateX(-100%);
372
+ }
373
+ }
374
+
375
+ @keyframes lt-sheet-in-end {
376
+ from {
377
+ transform: translateX(100%);
378
+ }
379
+ to {
380
+ transform: translateX(0);
381
+ }
382
+ }
383
+
384
+ @keyframes lt-sheet-out-end {
385
+ from {
386
+ transform: translateX(0);
387
+ }
388
+ to {
389
+ transform: translateX(100%);
390
+ }
391
+ }
392
+
288
393
  /*
289
- * Status colours for Badge and Icon table cells. Each tone sets a soft
290
- * background and a readable foreground in oklch; the `.dark` block swaps them.
291
- * Defined here (not as utility strings in the renderer) so the palette lives
292
- * with the theme and can be overridden, and so the cells can pick a tone by
293
- * name without Tailwind needing to see every class. Gray follows the muted token.
394
+ * Named colours. Semantic names alias the theme tokens; hue names carry their
395
+ * own oklch values with `.dark` overrides. Renderers resolve a named colour to
396
+ * `var(--lt-color-<name>)` for paint, or to an `.lt-tone-<name>` class for the
397
+ * soft-background/strong-foreground pair used by badge and icon cells. Defined
398
+ * here (not as utility strings in the renderers) so the palette lives with the
399
+ * theme and can be overridden, and so a colour can be picked by name at
400
+ * runtime without Tailwind needing to see every class.
294
401
  */
402
+ :root {
403
+ --lt-color-default: var(--lt-fg);
404
+ --lt-color-muted: var(--lt-muted-fg);
405
+ --lt-color-primary: var(--lt-primary);
406
+ --lt-color-success: var(--lt-success);
407
+ --lt-color-info: var(--lt-info);
408
+ --lt-color-warning: var(--lt-warning);
409
+ --lt-color-danger: var(--lt-danger);
410
+ --lt-color-gray: var(--lt-muted-fg);
411
+ --lt-color-red: oklch(0.51 0.19 27);
412
+ --lt-color-orange: oklch(0.55 0.14 55);
413
+ --lt-color-yellow: oklch(0.52 0.1 85);
414
+ --lt-color-green: oklch(0.52 0.13 152);
415
+ --lt-color-blue: oklch(0.54 0.17 252);
416
+ --lt-color-purple: oklch(0.53 0.19 305);
417
+ }
418
+
419
+ [data-theme="dark"],
420
+ .dark {
421
+ --lt-color-red: oklch(0.83 0.11 27);
422
+ --lt-color-orange: oklch(0.84 0.1 65);
423
+ --lt-color-yellow: oklch(0.87 0.11 100);
424
+ --lt-color-green: oklch(0.85 0.13 155);
425
+ --lt-color-blue: oklch(0.84 0.11 250);
426
+ --lt-color-purple: oklch(0.85 0.11 305);
427
+ }
428
+
295
429
  .lt-cell-badge {
296
430
  display: inline-flex;
297
431
  align-items: center;
@@ -301,67 +435,98 @@
301
435
  font-size: 0.75rem;
302
436
  line-height: 1rem;
303
437
  font-weight: 500;
304
- background-color: var(--lt-cell-bg, var(--lt-muted));
305
- color: var(--lt-cell-fg, var(--lt-muted-fg));
438
+ background-color: var(--lt-tone-bg, var(--lt-muted));
439
+ color: var(--lt-tone-fg, var(--lt-muted-fg));
306
440
  }
307
441
 
308
442
  .lt-cell-icon {
309
443
  display: inline-flex;
310
- color: var(--lt-cell-fg, var(--lt-fg));
444
+ color: var(--lt-tone-fg, var(--lt-fg));
311
445
  }
312
446
 
313
- .lt-cell-tone-gray {
314
- --lt-cell-bg: var(--lt-muted);
315
- --lt-cell-fg: var(--lt-muted-fg);
447
+ .lt-tone-gray {
448
+ --lt-tone-bg: var(--lt-muted);
449
+ --lt-tone-fg: var(--lt-color-gray);
450
+ }
451
+ .lt-tone-red {
452
+ --lt-tone-bg: oklch(0.94 0.03 25);
453
+ --lt-tone-fg: var(--lt-color-red);
454
+ }
455
+ .lt-tone-orange {
456
+ --lt-tone-bg: oklch(0.95 0.04 65);
457
+ --lt-tone-fg: var(--lt-color-orange);
458
+ }
459
+ .lt-tone-yellow {
460
+ --lt-tone-bg: oklch(0.96 0.05 100);
461
+ --lt-tone-fg: var(--lt-color-yellow);
462
+ }
463
+ .lt-tone-green {
464
+ --lt-tone-bg: oklch(0.95 0.05 155);
465
+ --lt-tone-fg: var(--lt-color-green);
466
+ }
467
+ .lt-tone-blue {
468
+ --lt-tone-bg: oklch(0.95 0.03 245);
469
+ --lt-tone-fg: var(--lt-color-blue);
470
+ }
471
+ .lt-tone-purple {
472
+ --lt-tone-bg: oklch(0.95 0.03 305);
473
+ --lt-tone-fg: var(--lt-color-purple);
474
+ }
475
+
476
+ .lt-tone-default,
477
+ .lt-tone-primary,
478
+ .lt-tone-success,
479
+ .lt-tone-info,
480
+ .lt-tone-warning,
481
+ .lt-tone-danger {
482
+ --lt-tone-bg: color-mix(in oklab, var(--lt-tone-fg) 12%, transparent);
483
+ }
484
+ .lt-tone-default {
485
+ --lt-tone-fg: var(--lt-color-default);
316
486
  }
317
- .lt-cell-tone-red {
318
- --lt-cell-bg: oklch(0.94 0.03 25);
319
- --lt-cell-fg: oklch(0.51 0.19 27);
487
+ .lt-tone-muted {
488
+ --lt-tone-bg: var(--lt-muted);
489
+ --lt-tone-fg: var(--lt-color-muted);
320
490
  }
321
- .lt-cell-tone-orange {
322
- --lt-cell-bg: oklch(0.95 0.04 65);
323
- --lt-cell-fg: oklch(0.55 0.14 55);
491
+ .lt-tone-primary {
492
+ --lt-tone-fg: var(--lt-color-primary);
324
493
  }
325
- .lt-cell-tone-yellow {
326
- --lt-cell-bg: oklch(0.96 0.05 100);
327
- --lt-cell-fg: oklch(0.52 0.1 85);
494
+ .lt-tone-success {
495
+ --lt-tone-fg: var(--lt-color-success);
328
496
  }
329
- .lt-cell-tone-green {
330
- --lt-cell-bg: oklch(0.95 0.05 155);
331
- --lt-cell-fg: oklch(0.52 0.13 152);
497
+ .lt-tone-info {
498
+ --lt-tone-fg: var(--lt-color-info);
332
499
  }
333
- .lt-cell-tone-blue {
334
- --lt-cell-bg: oklch(0.95 0.03 245);
335
- --lt-cell-fg: oklch(0.54 0.17 252);
500
+ .lt-tone-warning {
501
+ --lt-tone-fg: var(--lt-color-warning);
336
502
  }
337
- .lt-cell-tone-purple {
338
- --lt-cell-bg: oklch(0.95 0.03 305);
339
- --lt-cell-fg: oklch(0.53 0.19 305);
503
+ .lt-tone-danger {
504
+ --lt-tone-fg: var(--lt-color-danger);
340
505
  }
341
506
 
342
- .dark .lt-cell-tone-red {
343
- --lt-cell-bg: oklch(0.29 0.08 27);
344
- --lt-cell-fg: oklch(0.83 0.11 27);
507
+ [data-theme="dark"] .lt-tone-red,
508
+ .dark .lt-tone-red {
509
+ --lt-tone-bg: oklch(0.29 0.08 27);
345
510
  }
346
- .dark .lt-cell-tone-orange {
347
- --lt-cell-bg: oklch(0.3 0.07 65);
348
- --lt-cell-fg: oklch(0.84 0.1 65);
511
+ [data-theme="dark"] .lt-tone-orange,
512
+ .dark .lt-tone-orange {
513
+ --lt-tone-bg: oklch(0.3 0.07 65);
349
514
  }
350
- .dark .lt-cell-tone-yellow {
351
- --lt-cell-bg: oklch(0.31 0.06 100);
352
- --lt-cell-fg: oklch(0.87 0.11 100);
515
+ [data-theme="dark"] .lt-tone-yellow,
516
+ .dark .lt-tone-yellow {
517
+ --lt-tone-bg: oklch(0.31 0.06 100);
353
518
  }
354
- .dark .lt-cell-tone-green {
355
- --lt-cell-bg: oklch(0.3 0.07 155);
356
- --lt-cell-fg: oklch(0.85 0.13 155);
519
+ [data-theme="dark"] .lt-tone-green,
520
+ .dark .lt-tone-green {
521
+ --lt-tone-bg: oklch(0.3 0.07 155);
357
522
  }
358
- .dark .lt-cell-tone-blue {
359
- --lt-cell-bg: oklch(0.3 0.07 245);
360
- --lt-cell-fg: oklch(0.84 0.11 250);
523
+ [data-theme="dark"] .lt-tone-blue,
524
+ .dark .lt-tone-blue {
525
+ --lt-tone-bg: oklch(0.3 0.07 245);
361
526
  }
362
- .dark .lt-cell-tone-purple {
363
- --lt-cell-bg: oklch(0.3 0.07 305);
364
- --lt-cell-fg: oklch(0.85 0.11 305);
527
+ [data-theme="dark"] .lt-tone-purple,
528
+ .dark .lt-tone-purple {
529
+ --lt-tone-bg: oklch(0.3 0.07 305);
365
530
  }
366
531
 
367
532
  /*
@@ -1,13 +1,15 @@
1
+ import { useT } from "../../i18n/instance.js";
1
2
  import { nodeIdentity } from "../../core/test-id.js";
2
3
  import { Link, usePage } from "@inertiajs/react";
3
4
  import { Fragment } from "react";
4
5
  import { jsx, jsxs } from "react/jsx-runtime";
5
6
  //#region resources/js/layout/components/breadcrumbs.tsx
6
7
  var BreadcrumbsComponent = ({ node }) => {
8
+ const { t } = useT("lattice");
7
9
  const crumbs = usePage().props.lattice?.breadcrumbs ?? [];
8
10
  if (crumbs.length === 0) return null;
9
11
  return /* @__PURE__ */ jsx("nav", {
10
- "aria-label": "Breadcrumb",
12
+ "aria-label": t("common.breadcrumb", "Breadcrumb"),
11
13
  "data-lattice-component": nodeIdentity(node),
12
14
  children: /* @__PURE__ */ jsx("ol", {
13
15
  className: "flex items-center gap-2 text-sm text-lt-muted-fg",
@@ -1 +1 @@
1
- {"version":3,"file":"breadcrumbs.js","names":[],"sources":["../../../resources/js/layout/components/breadcrumbs.tsx"],"sourcesContent":["import { Link, usePage } from \"@inertiajs/react\";\nimport { Fragment } from \"react\";\nimport type { PagePayload, RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { nodeIdentity } from \"@lattice-php/lattice/core/test-id\";\n\nconst BreadcrumbsComponent: RendererComponent<\"breadcrumbs\"> = ({ node }) => {\n const page = usePage();\n const crumbs = (page.props.lattice as PagePayload | undefined)?.breadcrumbs ?? [];\n\n if (crumbs.length === 0) {\n return null;\n }\n\n return (\n <nav aria-label=\"Breadcrumb\" data-lattice-component={nodeIdentity(node)}>\n <ol className=\"flex items-center gap-2 text-sm text-lt-muted-fg\">\n {crumbs.map((crumb, index) => {\n const isLast = index === crumbs.length - 1;\n\n return (\n <Fragment key={crumb.href}>\n <li>\n {isLast ? (\n <span aria-current=\"page\" className=\"text-lt-fg\">\n {crumb.title}\n </span>\n ) : (\n <Link className=\"hover:text-lt-fg\" href={crumb.href}>\n {crumb.title}\n </Link>\n )}\n </li>\n {isLast ? null : <li aria-hidden=\"true\">/</li>}\n </Fragment>\n );\n })}\n </ol>\n </nav>\n );\n};\n\nexport default BreadcrumbsComponent;\n"],"mappings":";;;;;AAKA,IAAM,wBAA0D,EAAE,WAAW;CAE3E,MAAM,SADO,QACG,EAAK,MAAM,SAAqC,eAAe,CAAC;CAEhF,IAAI,OAAO,WAAW,GACpB,OAAO;CAGT,OACE,oBAAC,OAAD;EAAK,cAAW;EAAa,0BAAwB,aAAa,IAAI;YACpE,oBAAC,MAAD;GAAI,WAAU;aACX,OAAO,KAAK,OAAO,UAAU;IAC5B,MAAM,SAAS,UAAU,OAAO,SAAS;IAEzC,OACE,qBAAC,UAAD,EAAA,UAAA,CACE,oBAAC,MAAD,EAAA,UACG,SACC,oBAAC,QAAD;KAAM,gBAAa;KAAO,WAAU;eACjC,MAAM;IACH,CAAA,IAEN,oBAAC,MAAD;KAAM,WAAU;KAAmB,MAAM,MAAM;eAC5C,MAAM;IACH,CAAA,EAEN,CAAA,GACH,SAAS,OAAO,oBAAC,MAAD;KAAI,eAAY;eAAO;IAAK,CAAA,CACrC,EAAA,GAbK,MAAM,IAaX;GAEd,CAAC;EACC,CAAA;CACD,CAAA;AAET"}
1
+ {"version":3,"file":"breadcrumbs.js","names":[],"sources":["../../../resources/js/layout/components/breadcrumbs.tsx"],"sourcesContent":["import { Link, usePage } from \"@inertiajs/react\";\nimport { Fragment } from \"react\";\nimport type { PagePayload, RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { nodeIdentity } from \"@lattice-php/lattice/core/test-id\";\nimport { useT } from \"@lattice-php/lattice/i18n\";\n\nconst BreadcrumbsComponent: RendererComponent<\"breadcrumbs\"> = ({ node }) => {\n const { t } = useT(\"lattice\");\n const page = usePage();\n const crumbs = (page.props.lattice as PagePayload | undefined)?.breadcrumbs ?? [];\n\n if (crumbs.length === 0) {\n return null;\n }\n\n return (\n <nav\n aria-label={t(\"common.breadcrumb\", \"Breadcrumb\")}\n data-lattice-component={nodeIdentity(node)}\n >\n <ol className=\"flex items-center gap-2 text-sm text-lt-muted-fg\">\n {crumbs.map((crumb, index) => {\n const isLast = index === crumbs.length - 1;\n\n return (\n <Fragment key={crumb.href}>\n <li>\n {isLast ? (\n <span aria-current=\"page\" className=\"text-lt-fg\">\n {crumb.title}\n </span>\n ) : (\n <Link className=\"hover:text-lt-fg\" href={crumb.href}>\n {crumb.title}\n </Link>\n )}\n </li>\n {isLast ? null : <li aria-hidden=\"true\">/</li>}\n </Fragment>\n );\n })}\n </ol>\n </nav>\n );\n};\n\nexport default BreadcrumbsComponent;\n"],"mappings":";;;;;;AAMA,IAAM,wBAA0D,EAAE,WAAW;CAC3E,MAAM,EAAE,MAAM,KAAK,SAAS;CAE5B,MAAM,SADO,QACG,EAAK,MAAM,SAAqC,eAAe,CAAC;CAEhF,IAAI,OAAO,WAAW,GACpB,OAAO;CAGT,OACE,oBAAC,OAAD;EACE,cAAY,EAAE,qBAAqB,YAAY;EAC/C,0BAAwB,aAAa,IAAI;YAEzC,oBAAC,MAAD;GAAI,WAAU;aACX,OAAO,KAAK,OAAO,UAAU;IAC5B,MAAM,SAAS,UAAU,OAAO,SAAS;IAEzC,OACE,qBAAC,UAAD,EAAA,UAAA,CACE,oBAAC,MAAD,EAAA,UACG,SACC,oBAAC,QAAD;KAAM,gBAAa;KAAO,WAAU;eACjC,MAAM;IACH,CAAA,IAEN,oBAAC,MAAD;KAAM,WAAU;KAAmB,MAAM,MAAM;eAC5C,MAAM;IACH,CAAA,EAEN,CAAA,GACH,SAAS,OAAO,oBAAC,MAAD;KAAI,eAAY;eAAO;IAAK,CAAA,CACrC,EAAA,GAbK,MAAM,IAaX;GAEd,CAAC;EACC,CAAA;CACD,CAAA;AAET"}
@@ -1,70 +1,37 @@
1
- import { LATTICE_EVENT } from "../../events/event-names.js";
1
+ import { LATTICE_EVENT } from "../../core/event-names.js";
2
+ import { useWindowEvent } from "../../core/hooks/use-window-event.js";
2
3
  import { cn } from "../../lib/utils.js";
3
4
  import { CollapsedContext } from "../../core/collapsed-context.js";
4
5
  import { nodeIdentity } from "../../core/test-id.js";
6
+ import { useMediaQuery } from "../../lib/use-media-query.js";
7
+ import { useCollapsibleState } from "../../ui/use-collapsible-state.js";
5
8
  import { router } from "@inertiajs/react";
6
9
  import { useEffect, useState } from "react";
7
10
  import { jsx, jsxs } from "react/jsx-runtime";
8
11
  //#region resources/js/layout/components/sidebar.tsx
9
12
  var DESKTOP_QUERY = "(min-width: 768px)";
10
- function readStored(key, remember) {
11
- if (!remember || typeof window === "undefined") return false;
12
- return window.localStorage.getItem(key) === "true";
13
- }
14
13
  function matchesTarget(event, identity) {
15
14
  const target = event.detail?.target;
16
15
  return target == null || target === identity;
17
16
  }
18
- function useIsDesktop() {
19
- const supported = () => typeof window !== "undefined" && typeof window.matchMedia === "function";
20
- const [isDesktop, setIsDesktop] = useState(() => supported() ? window.matchMedia(DESKTOP_QUERY).matches : true);
21
- useEffect(() => {
22
- if (!supported()) return;
23
- const query = window.matchMedia(DESKTOP_QUERY);
24
- const update = () => setIsDesktop(query.matches);
25
- update();
26
- query.addEventListener("change", update);
27
- return () => query.removeEventListener("change", update);
28
- }, []);
29
- return isDesktop;
30
- }
31
17
  var SidebarComponent = ({ children, node }) => {
32
18
  const collapsible = node.props.collapsible;
33
19
  const rememberState = node.props.rememberState;
34
20
  const identity = nodeIdentity(node);
35
21
  const storageKey = `lattice:sidebar:${identity ?? "default"}`;
36
- const isDesktop = useIsDesktop();
37
- const [collapsed, setCollapsed] = useState(() => readStored(storageKey, collapsible && rememberState));
22
+ const isDesktop = useMediaQuery(DESKTOP_QUERY, true);
23
+ const [collapsed, toggleCollapsed] = useCollapsibleState(storageKey, false, collapsible && rememberState);
38
24
  const [mobileOpen, setMobileOpen] = useState(false);
39
- useEffect(() => {
40
- function toggle(event) {
41
- if (!matchesTarget(event, identity)) return;
42
- if (window.matchMedia?.(DESKTOP_QUERY).matches ?? true) {
43
- if (!collapsible) return;
44
- setCollapsed((value) => {
45
- const next = !value;
46
- if (rememberState && typeof window !== "undefined") window.localStorage.setItem(storageKey, String(next));
47
- return next;
48
- });
49
- } else setMobileOpen((open) => !open);
50
- }
51
- window.addEventListener(LATTICE_EVENT.toggleSidebar, toggle);
52
- return () => window.removeEventListener(LATTICE_EVENT.toggleSidebar, toggle);
53
- }, [
54
- identity,
55
- collapsible,
56
- rememberState,
57
- storageKey
58
- ]);
25
+ useWindowEvent(LATTICE_EVENT.toggleSidebar, (event) => {
26
+ if (!matchesTarget(event, identity)) return;
27
+ if (window.matchMedia?.(DESKTOP_QUERY).matches ?? true) {
28
+ if (collapsible) toggleCollapsed();
29
+ } else setMobileOpen((open) => !open);
30
+ });
59
31
  useEffect(() => router.on("navigate", () => setMobileOpen(false)), []);
60
- useEffect(() => {
61
- if (!mobileOpen) return;
62
- function close(event) {
63
- if (event.key === "Escape") setMobileOpen(false);
64
- }
65
- window.addEventListener("keydown", close);
66
- return () => window.removeEventListener("keydown", close);
67
- }, [mobileOpen]);
32
+ useWindowEvent("keydown", (event) => {
33
+ if (event.key === "Escape") setMobileOpen(false);
34
+ }, { enabled: mobileOpen });
68
35
  const isCollapsed = collapsible && collapsed && isDesktop;
69
36
  return /* @__PURE__ */ jsxs(CollapsedContext.Provider, {
70
37
  value: isCollapsed,
@@ -1 +1 @@
1
- {"version":3,"file":"sidebar.js","names":[],"sources":["../../../resources/js/layout/components/sidebar.tsx"],"sourcesContent":["import { router } from \"@inertiajs/react\";\nimport { useEffect, useState } from \"react\";\nimport type { RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { CollapsedContext } from \"@lattice-php/lattice/core/collapsed-context\";\nimport { LATTICE_EVENT } from \"@lattice-php/lattice/events/event-names\";\nimport { nodeIdentity } from \"@lattice-php/lattice/core/test-id\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\n\nconst DESKTOP_QUERY = \"(min-width: 768px)\";\n\nfunction readStored(key: string, remember: boolean): boolean {\n if (!remember || typeof window === \"undefined\") {\n return false;\n }\n\n return window.localStorage.getItem(key) === \"true\";\n}\n\nfunction matchesTarget(event: Event, identity: string | undefined): boolean {\n const target = (event as CustomEvent<{ target?: string }>).detail?.target;\n\n return target == null || target === identity;\n}\n\nfunction useIsDesktop(): boolean {\n const supported = () => typeof window !== \"undefined\" && typeof window.matchMedia === \"function\";\n const [isDesktop, setIsDesktop] = useState(() =>\n supported() ? window.matchMedia(DESKTOP_QUERY).matches : true,\n );\n\n useEffect(() => {\n if (!supported()) {\n return;\n }\n\n const query = window.matchMedia(DESKTOP_QUERY);\n const update = (): void => setIsDesktop(query.matches);\n\n update();\n query.addEventListener(\"change\", update);\n\n return () => query.removeEventListener(\"change\", update);\n }, []);\n\n return isDesktop;\n}\n\nconst SidebarComponent: RendererComponent<\"sidebar\"> = ({ children, node }) => {\n const collapsible = node.props.collapsible;\n const rememberState = node.props.rememberState;\n const identity = nodeIdentity(node);\n const storageKey = `lattice:sidebar:${identity ?? \"default\"}`;\n const isDesktop = useIsDesktop();\n\n const [collapsed, setCollapsed] = useState(() =>\n readStored(storageKey, collapsible && rememberState),\n );\n const [mobileOpen, setMobileOpen] = useState(false);\n\n useEffect(() => {\n function toggle(event: Event): void {\n if (!matchesTarget(event, identity)) {\n return;\n }\n\n if (window.matchMedia?.(DESKTOP_QUERY).matches ?? true) {\n if (!collapsible) {\n return;\n }\n\n setCollapsed((value) => {\n const next = !value;\n\n if (rememberState && typeof window !== \"undefined\") {\n window.localStorage.setItem(storageKey, String(next));\n }\n\n return next;\n });\n } else {\n setMobileOpen((open) => !open);\n }\n }\n\n window.addEventListener(LATTICE_EVENT.toggleSidebar, toggle);\n\n return () => window.removeEventListener(LATTICE_EVENT.toggleSidebar, toggle);\n }, [identity, collapsible, rememberState, storageKey]);\n\n useEffect(() => router.on(\"navigate\", () => setMobileOpen(false)), []);\n\n useEffect(() => {\n if (!mobileOpen) {\n return;\n }\n\n function close(event: KeyboardEvent): void {\n if (event.key === \"Escape\") {\n setMobileOpen(false);\n }\n }\n\n window.addEventListener(\"keydown\", close);\n\n return () => window.removeEventListener(\"keydown\", close);\n }, [mobileOpen]);\n\n const isCollapsed = collapsible && collapsed && isDesktop;\n\n return (\n <CollapsedContext.Provider value={isCollapsed}>\n {mobileOpen ? (\n <div\n aria-hidden=\"true\"\n className=\"fixed inset-0 z-lt-overlay bg-lt-overlay md:hidden\"\n data-test=\"sidebar-backdrop\"\n onClick={() => setMobileOpen(false)}\n />\n ) : null}\n <aside\n className={cn(\n \"fixed inset-y-0 left-0 z-lt-modal flex h-svh w-72 max-w-[80vw] shrink-0 flex-col gap-4 border-r border-lt-border bg-lt-bg p-4 transition-transform\",\n \"md:sticky md:top-0 md:z-auto md:max-w-none md:translate-x-0 md:transition-[width]\",\n mobileOpen ? \"translate-x-0\" : \"-translate-x-full\",\n isCollapsed\n ? \"md:w-16 md:overflow-visible\"\n : \"md:w-64 md:overflow-x-hidden md:overflow-y-auto\",\n )}\n data-collapsed={isCollapsed ? \"true\" : \"false\"}\n data-lattice-component={identity}\n data-test=\"sidebar\"\n >\n {children}\n </aside>\n </CollapsedContext.Provider>\n );\n};\n\nexport default SidebarComponent;\n"],"mappings":";;;;;;;;AAQA,IAAM,gBAAgB;AAEtB,SAAS,WAAW,KAAa,UAA4B;CAC3D,IAAI,CAAC,YAAY,OAAO,WAAW,aACjC,OAAO;CAGT,OAAO,OAAO,aAAa,QAAQ,GAAG,MAAM;AAC9C;AAEA,SAAS,cAAc,OAAc,UAAuC;CAC1E,MAAM,SAAU,MAA2C,QAAQ;CAEnE,OAAO,UAAU,QAAQ,WAAW;AACtC;AAEA,SAAS,eAAwB;CAC/B,MAAM,kBAAkB,OAAO,WAAW,eAAe,OAAO,OAAO,eAAe;CACtF,MAAM,CAAC,WAAW,gBAAgB,eAChC,UAAU,IAAI,OAAO,WAAW,aAAa,EAAE,UAAU,IAC3D;CAEA,gBAAgB;EACd,IAAI,CAAC,UAAU,GACb;EAGF,MAAM,QAAQ,OAAO,WAAW,aAAa;EAC7C,MAAM,eAAqB,aAAa,MAAM,OAAO;EAErD,OAAO;EACP,MAAM,iBAAiB,UAAU,MAAM;EAEvC,aAAa,MAAM,oBAAoB,UAAU,MAAM;CACzD,GAAG,CAAC,CAAC;CAEL,OAAO;AACT;AAEA,IAAM,oBAAkD,EAAE,UAAU,WAAW;CAC7E,MAAM,cAAc,KAAK,MAAM;CAC/B,MAAM,gBAAgB,KAAK,MAAM;CACjC,MAAM,WAAW,aAAa,IAAI;CAClC,MAAM,aAAa,mBAAmB,YAAY;CAClD,MAAM,YAAY,aAAa;CAE/B,MAAM,CAAC,WAAW,gBAAgB,eAChC,WAAW,YAAY,eAAe,aAAa,CACrD;CACA,MAAM,CAAC,YAAY,iBAAiB,SAAS,KAAK;CAElD,gBAAgB;EACd,SAAS,OAAO,OAAoB;GAClC,IAAI,CAAC,cAAc,OAAO,QAAQ,GAChC;GAGF,IAAI,OAAO,aAAa,aAAa,EAAE,WAAW,MAAM;IACtD,IAAI,CAAC,aACH;IAGF,cAAc,UAAU;KACtB,MAAM,OAAO,CAAC;KAEd,IAAI,iBAAiB,OAAO,WAAW,aACrC,OAAO,aAAa,QAAQ,YAAY,OAAO,IAAI,CAAC;KAGtD,OAAO;IACT,CAAC;GACH,OACE,eAAe,SAAS,CAAC,IAAI;EAEjC;EAEA,OAAO,iBAAiB,cAAc,eAAe,MAAM;EAE3D,aAAa,OAAO,oBAAoB,cAAc,eAAe,MAAM;CAC7E,GAAG;EAAC;EAAU;EAAa;EAAe;CAAU,CAAC;CAErD,gBAAgB,OAAO,GAAG,kBAAkB,cAAc,KAAK,CAAC,GAAG,CAAC,CAAC;CAErE,gBAAgB;EACd,IAAI,CAAC,YACH;EAGF,SAAS,MAAM,OAA4B;GACzC,IAAI,MAAM,QAAQ,UAChB,cAAc,KAAK;EAEvB;EAEA,OAAO,iBAAiB,WAAW,KAAK;EAExC,aAAa,OAAO,oBAAoB,WAAW,KAAK;CAC1D,GAAG,CAAC,UAAU,CAAC;CAEf,MAAM,cAAc,eAAe,aAAa;CAEhD,OACE,qBAAC,iBAAiB,UAAlB;EAA2B,OAAO;YAAlC,CACG,aACC,oBAAC,OAAD;GACE,eAAY;GACZ,WAAU;GACV,aAAU;GACV,eAAe,cAAc,KAAK;EACnC,CAAA,IACC,MACJ,oBAAC,SAAD;GACE,WAAW,GACT,sJACA,qFACA,aAAa,kBAAkB,qBAC/B,cACI,gCACA,iDACN;GACA,kBAAgB,cAAc,SAAS;GACvC,0BAAwB;GACxB,aAAU;GAET;EACI,CAAA,CACkB;;AAE/B"}
1
+ {"version":3,"file":"sidebar.js","names":[],"sources":["../../../resources/js/layout/components/sidebar.tsx"],"sourcesContent":["import { router } from \"@inertiajs/react\";\nimport { useEffect, useState } from \"react\";\nimport type { RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { CollapsedContext } from \"@lattice-php/lattice/core/collapsed-context\";\nimport { LATTICE_EVENT } from \"@lattice-php/lattice/core/event-names\";\nimport { useWindowEvent } from \"@lattice-php/lattice/core/hooks/use-window-event\";\nimport { nodeIdentity } from \"@lattice-php/lattice/core/test-id\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport { useMediaQuery } from \"@lattice-php/lattice/lib/use-media-query\";\nimport { useCollapsibleState } from \"@lattice-php/lattice/ui/use-collapsible-state\";\n\nconst DESKTOP_QUERY = \"(min-width: 768px)\";\n\nfunction matchesTarget(event: Event, identity: string | undefined): boolean {\n const target = (event as CustomEvent<{ target?: string }>).detail?.target;\n\n return target == null || target === identity;\n}\n\nconst SidebarComponent: RendererComponent<\"sidebar\"> = ({ children, node }) => {\n const collapsible = node.props.collapsible;\n const rememberState = node.props.rememberState;\n const identity = nodeIdentity(node);\n const storageKey = `lattice:sidebar:${identity ?? \"default\"}`;\n const isDesktop = useMediaQuery(DESKTOP_QUERY, true);\n\n const [collapsed, toggleCollapsed] = useCollapsibleState(\n storageKey,\n false,\n collapsible && rememberState,\n );\n const [mobileOpen, setMobileOpen] = useState(false);\n\n useWindowEvent(LATTICE_EVENT.toggleSidebar, (event) => {\n if (!matchesTarget(event, identity)) {\n return;\n }\n\n if (window.matchMedia?.(DESKTOP_QUERY).matches ?? true) {\n if (collapsible) {\n toggleCollapsed();\n }\n } else {\n setMobileOpen((open) => !open);\n }\n });\n\n useEffect(() => router.on(\"navigate\", () => setMobileOpen(false)), []);\n\n useWindowEvent(\n \"keydown\",\n (event) => {\n if ((event as KeyboardEvent).key === \"Escape\") {\n setMobileOpen(false);\n }\n },\n { enabled: mobileOpen },\n );\n\n const isCollapsed = collapsible && collapsed && isDesktop;\n\n return (\n <CollapsedContext.Provider value={isCollapsed}>\n {mobileOpen ? (\n <div\n aria-hidden=\"true\"\n className=\"fixed inset-0 z-lt-overlay bg-lt-overlay md:hidden\"\n data-test=\"sidebar-backdrop\"\n onClick={() => setMobileOpen(false)}\n />\n ) : null}\n <aside\n className={cn(\n \"fixed inset-y-0 left-0 z-lt-modal flex h-svh w-72 max-w-[80vw] shrink-0 flex-col gap-4 border-r border-lt-border bg-lt-bg p-4 transition-transform\",\n \"md:sticky md:top-0 md:z-auto md:max-w-none md:translate-x-0 md:transition-[width]\",\n mobileOpen ? \"translate-x-0\" : \"-translate-x-full\",\n isCollapsed\n ? \"md:w-16 md:overflow-visible\"\n : \"md:w-64 md:overflow-x-hidden md:overflow-y-auto\",\n )}\n data-collapsed={isCollapsed ? \"true\" : \"false\"}\n data-lattice-component={identity}\n data-test=\"sidebar\"\n >\n {children}\n </aside>\n </CollapsedContext.Provider>\n );\n};\n\nexport default SidebarComponent;\n"],"mappings":";;;;;;;;;;;AAWA,IAAM,gBAAgB;AAEtB,SAAS,cAAc,OAAc,UAAuC;CAC1E,MAAM,SAAU,MAA2C,QAAQ;CAEnE,OAAO,UAAU,QAAQ,WAAW;AACtC;AAEA,IAAM,oBAAkD,EAAE,UAAU,WAAW;CAC7E,MAAM,cAAc,KAAK,MAAM;CAC/B,MAAM,gBAAgB,KAAK,MAAM;CACjC,MAAM,WAAW,aAAa,IAAI;CAClC,MAAM,aAAa,mBAAmB,YAAY;CAClD,MAAM,YAAY,cAAc,eAAe,IAAI;CAEnD,MAAM,CAAC,WAAW,mBAAmB,oBACnC,YACA,OACA,eAAe,aACjB;CACA,MAAM,CAAC,YAAY,iBAAiB,SAAS,KAAK;CAElD,eAAe,cAAc,gBAAgB,UAAU;EACrD,IAAI,CAAC,cAAc,OAAO,QAAQ,GAChC;EAGF,IAAI,OAAO,aAAa,aAAa,EAAE,WAAW;OAC5C,aACF,gBAAgB;EAAA,OAGlB,eAAe,SAAS,CAAC,IAAI;CAEjC,CAAC;CAED,gBAAgB,OAAO,GAAG,kBAAkB,cAAc,KAAK,CAAC,GAAG,CAAC,CAAC;CAErE,eACE,YACC,UAAU;EACT,IAAK,MAAwB,QAAQ,UACnC,cAAc,KAAK;CAEvB,GACA,EAAE,SAAS,WAAW,CACxB;CAEA,MAAM,cAAc,eAAe,aAAa;CAEhD,OACE,qBAAC,iBAAiB,UAAlB;EAA2B,OAAO;YAAlC,CACG,aACC,oBAAC,OAAD;GACE,eAAY;GACZ,WAAU;GACV,aAAU;GACV,eAAe,cAAc,KAAK;EACnC,CAAA,IACC,MACJ,oBAAC,SAAD;GACE,WAAW,GACT,sJACA,qFACA,aAAa,kBAAkB,qBAC/B,cACI,gCACA,iDACN;GACA,kBAAgB,cAAc,SAAS;GACvC,0BAAwB;GACxB,aAAU;GAET;EACI,CAAA,CACkB;;AAE/B"}
@@ -1,2 +1 @@
1
- export type LayoutComponentType = "breadcrumbs" | "callouts" | "dropdown" | "menu" | "menu-item" | "outlet" | "sidebar" | "topbar";
2
1
  export declare const layoutComponents: import('../core/registry.js').Plugin;
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.js","names":[],"sources":["../../resources/js/layout/plugin.ts"],"sourcesContent":["import {\n createPlugin,\n eagerComponent,\n type ComponentRegistryFor,\n} from \"@lattice-php/lattice/core/registry\";\nimport BreadcrumbsComponent from \"./components/breadcrumbs\";\nimport CalloutsComponent from \"./components/callouts\";\nimport DropdownComponent from \"./components/dropdown\";\nimport MenuComponent from \"./components/menu\";\nimport MenuItemComponent from \"./components/menu-item\";\nimport OutletComponent from \"./components/outlet\";\nimport SidebarComponent from \"./components/sidebar\";\nimport TopbarComponent from \"./components/topbar\";\n\nexport type LayoutComponentType =\n | \"breadcrumbs\"\n | \"callouts\"\n | \"dropdown\"\n | \"menu\"\n | \"menu-item\"\n | \"outlet\"\n | \"sidebar\"\n | \"topbar\";\n\nexport const layoutComponents = createPlugin({\n components: {\n breadcrumbs: eagerComponent(BreadcrumbsComponent),\n callouts: eagerComponent(CalloutsComponent),\n dropdown: eagerComponent(DropdownComponent),\n menu: eagerComponent(MenuComponent),\n \"menu-item\": eagerComponent(MenuItemComponent),\n outlet: eagerComponent(OutletComponent),\n sidebar: eagerComponent(SidebarComponent),\n topbar: eagerComponent(TopbarComponent),\n } satisfies ComponentRegistryFor<LayoutComponentType>,\n name: \"lattice/layout\",\n});\n"],"mappings":";;;;;;;;;;AAwBA,IAAa,mBAAmB,aAAa;CAC3C,YAAY;EACV,aAAa,eAAe,oBAAoB;EAChD,UAAU,eAAe,QAAiB;EAC1C,UAAU,eAAe,iBAAiB;EAC1C,MAAM,eAAe,aAAa;EAClC,aAAa,eAAe,iBAAiB;EAC7C,QAAQ,eAAe,eAAe;EACtC,SAAS,eAAe,gBAAgB;EACxC,QAAQ,eAAe,eAAe;CACxC;CACA,MAAM;AACR,CAAC"}
1
+ {"version":3,"file":"plugin.js","names":[],"sources":["../../resources/js/layout/plugin.ts"],"sourcesContent":["import {\n createPlugin,\n eagerComponent,\n type ComponentRegistryFor,\n} from \"@lattice-php/lattice/core/registry\";\nimport type { LayoutNodeType } from \"@lattice-php/lattice/types/generated\";\nimport BreadcrumbsComponent from \"./components/breadcrumbs\";\nimport CalloutsComponent from \"./components/callouts\";\nimport DropdownComponent from \"./components/dropdown\";\nimport MenuComponent from \"./components/menu\";\nimport MenuItemComponent from \"./components/menu-item\";\nimport OutletComponent from \"./components/outlet\";\nimport SidebarComponent from \"./components/sidebar\";\nimport TopbarComponent from \"./components/topbar\";\n\nexport const layoutComponents = createPlugin({\n components: {\n breadcrumbs: eagerComponent(BreadcrumbsComponent),\n callouts: eagerComponent(CalloutsComponent),\n dropdown: eagerComponent(DropdownComponent),\n menu: eagerComponent(MenuComponent),\n \"menu-item\": eagerComponent(MenuItemComponent),\n outlet: eagerComponent(OutletComponent),\n sidebar: eagerComponent(SidebarComponent),\n topbar: eagerComponent(TopbarComponent),\n } satisfies ComponentRegistryFor<LayoutNodeType>,\n name: \"lattice/layout\",\n});\n"],"mappings":";;;;;;;;;;AAeA,IAAa,mBAAmB,aAAa;CAC3C,YAAY;EACV,aAAa,eAAe,oBAAoB;EAChD,UAAU,eAAe,QAAiB;EAC1C,UAAU,eAAe,iBAAiB;EAC1C,MAAM,eAAe,aAAa;EAClC,aAAa,eAAe,iBAAiB;EAC7C,QAAQ,eAAe,eAAe;EACtC,SAAS,eAAe,gBAAgB;EACxC,QAAQ,eAAe,eAAe;CACxC;CACA,MAAM;AACR,CAAC"}
@@ -0,0 +1,9 @@
1
+ import { CSSProperties } from 'react';
2
+ import { Color, ColorName } from '../types/generated.js';
3
+ export declare function namedColor(value: ColorName): Color;
4
+ export declare function coerceColor(value: unknown): Color | undefined;
5
+ export declare function colorValue(color: Color): string;
6
+ export declare function toneProps(color: Color): {
7
+ className?: string;
8
+ style?: CSSProperties;
9
+ };
@@ -0,0 +1,48 @@
1
+ //#region resources/js/lib/color.ts
2
+ var names = new Set([
3
+ "default",
4
+ "muted",
5
+ "primary",
6
+ "success",
7
+ "info",
8
+ "warning",
9
+ "danger",
10
+ "gray",
11
+ "red",
12
+ "orange",
13
+ "yellow",
14
+ "green",
15
+ "blue",
16
+ "purple"
17
+ ]);
18
+ function namedColor(value) {
19
+ return {
20
+ kind: "named",
21
+ value,
22
+ dark: null
23
+ };
24
+ }
25
+ function coerceColor(value) {
26
+ if (typeof value === "string" && value !== "") return names.has(value) ? namedColor(value) : {
27
+ kind: "css",
28
+ value,
29
+ dark: null
30
+ };
31
+ if (typeof value === "object" && value !== null && "kind" in value && "value" in value) return value;
32
+ }
33
+ function colorValue(color) {
34
+ if (color.kind === "named") return `var(--lt-color-${color.value})`;
35
+ return color.dark === null ? color.value : `light-dark(${color.value}, ${color.dark})`;
36
+ }
37
+ function toneProps(color) {
38
+ if (color.kind === "named") return { className: `lt-tone-${color.value}` };
39
+ const paint = colorValue(color);
40
+ return { style: {
41
+ "--lt-tone-bg": `color-mix(in oklab, ${paint} 12%, transparent)`,
42
+ "--lt-tone-fg": paint
43
+ } };
44
+ }
45
+ //#endregion
46
+ export { coerceColor, colorValue, namedColor, toneProps };
47
+
48
+ //# sourceMappingURL=color.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"color.js","names":[],"sources":["../../resources/js/lib/color.ts"],"sourcesContent":["import type { CSSProperties } from \"react\";\nimport type { Color, ColorName } from \"@lattice-php/lattice/types/generated\";\n\nconst names: ReadonlySet<string> = new Set([\n \"default\",\n \"muted\",\n \"primary\",\n \"success\",\n \"info\",\n \"warning\",\n \"danger\",\n \"gray\",\n \"red\",\n \"orange\",\n \"yellow\",\n \"green\",\n \"blue\",\n \"purple\",\n] satisfies ColorName[]);\n\nexport function namedColor(value: ColorName): Color {\n return { kind: \"named\", value, dark: null };\n}\n\nexport function coerceColor(value: unknown): Color | undefined {\n if (typeof value === \"string\" && value !== \"\") {\n return names.has(value) ? namedColor(value as ColorName) : { kind: \"css\", value, dark: null };\n }\n\n if (typeof value === \"object\" && value !== null && \"kind\" in value && \"value\" in value) {\n return value as Color;\n }\n\n return undefined;\n}\n\nexport function colorValue(color: Color): string {\n if (color.kind === \"named\") {\n return `var(--lt-color-${color.value})`;\n }\n\n return color.dark === null ? color.value : `light-dark(${color.value}, ${color.dark})`;\n}\n\nexport function toneProps(color: Color): { className?: string; style?: CSSProperties } {\n if (color.kind === \"named\") {\n return { className: `lt-tone-${color.value}` };\n }\n\n const paint = colorValue(color);\n\n return {\n style: {\n \"--lt-tone-bg\": `color-mix(in oklab, ${paint} 12%, transparent)`,\n \"--lt-tone-fg\": paint,\n } as CSSProperties,\n };\n}\n"],"mappings":";AAGA,IAAM,QAA6B,IAAI,IAAI;CACzC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAuB;AAEvB,SAAgB,WAAW,OAAyB;CAClD,OAAO;EAAE,MAAM;EAAS;EAAO,MAAM;CAAK;AAC5C;AAEA,SAAgB,YAAY,OAAmC;CAC7D,IAAI,OAAO,UAAU,YAAY,UAAU,IACzC,OAAO,MAAM,IAAI,KAAK,IAAI,WAAW,KAAkB,IAAI;EAAE,MAAM;EAAO;EAAO,MAAM;CAAK;CAG9F,IAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,UAAU,SAAS,WAAW,OAC/E,OAAO;AAIX;AAEA,SAAgB,WAAW,OAAsB;CAC/C,IAAI,MAAM,SAAS,SACjB,OAAO,kBAAkB,MAAM,MAAM;CAGvC,OAAO,MAAM,SAAS,OAAO,MAAM,QAAQ,cAAc,MAAM,MAAM,IAAI,MAAM,KAAK;AACtF;AAEA,SAAgB,UAAU,OAA6D;CACrF,IAAI,MAAM,SAAS,SACjB,OAAO,EAAE,WAAW,WAAW,MAAM,QAAQ;CAG/C,MAAM,QAAQ,WAAW,KAAK;CAE9B,OAAO,EACL,OAAO;EACL,gBAAgB,uBAAuB,MAAM;EAC7C,gBAAgB;CAClB,EACF;AACF"}
@@ -0,0 +1,2 @@
1
+ /** Coerce a wire value (boolean, `1`/`0`, `"1"`/`"true"`) to a boolean. */
2
+ export declare function isTruthy(value: unknown): boolean;
@@ -0,0 +1,9 @@
1
+ //#region resources/js/lib/is-truthy.ts
2
+ /** Coerce a wire value (boolean, `1`/`0`, `"1"`/`"true"`) to a boolean. */
3
+ function isTruthy(value) {
4
+ return value === true || value === 1 || value === "1" || value === "true";
5
+ }
6
+ //#endregion
7
+ export { isTruthy };
8
+
9
+ //# sourceMappingURL=is-truthy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"is-truthy.js","names":[],"sources":["../../resources/js/lib/is-truthy.ts"],"sourcesContent":["/** Coerce a wire value (boolean, `1`/`0`, `\"1\"`/`\"true\"`) to a boolean. */\nexport function isTruthy(value: unknown): boolean {\n return value === true || value === 1 || value === \"1\" || value === \"true\";\n}\n"],"mappings":";;AACA,SAAgB,SAAS,OAAyB;CAChD,OAAO,UAAU,QAAQ,UAAU,KAAK,UAAU,OAAO,UAAU;AACrE"}
@@ -0,0 +1,10 @@
1
+ export type DebouncedCallback<A extends unknown[]> = {
2
+ (...args: A): void;
3
+ cancel: () => void;
4
+ };
5
+ /**
6
+ * A debounced wrapper around `callback` that is stable across renders (it reads
7
+ * the latest callback via a ref) and clears its pending timer on unmount, so a
8
+ * late fire can never run against a torn-down component.
9
+ */
10
+ export declare function useDebouncedCallback<A extends unknown[]>(callback: (...args: A) => void, delayMs: number): DebouncedCallback<A>;
@@ -0,0 +1,34 @@
1
+ import { useCallback, useEffect, useMemo, useRef } from "react";
2
+ //#region resources/js/lib/use-debounced-callback.ts
3
+ /**
4
+ * A debounced wrapper around `callback` that is stable across renders (it reads
5
+ * the latest callback via a ref) and clears its pending timer on unmount, so a
6
+ * late fire can never run against a torn-down component.
7
+ */
8
+ function useDebouncedCallback(callback, delayMs) {
9
+ const callbackRef = useRef(callback);
10
+ callbackRef.current = callback;
11
+ const timerRef = useRef(null);
12
+ const cancel = useCallback(() => {
13
+ if (timerRef.current !== null) {
14
+ clearTimeout(timerRef.current);
15
+ timerRef.current = null;
16
+ }
17
+ }, []);
18
+ useEffect(() => cancel, [cancel]);
19
+ return useMemo(() => {
20
+ const debounced = (...args) => {
21
+ cancel();
22
+ timerRef.current = setTimeout(() => {
23
+ timerRef.current = null;
24
+ callbackRef.current(...args);
25
+ }, delayMs);
26
+ };
27
+ debounced.cancel = cancel;
28
+ return debounced;
29
+ }, [cancel, delayMs]);
30
+ }
31
+ //#endregion
32
+ export { useDebouncedCallback };
33
+
34
+ //# sourceMappingURL=use-debounced-callback.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-debounced-callback.js","names":[],"sources":["../../resources/js/lib/use-debounced-callback.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef } from \"react\";\n\nexport type DebouncedCallback<A extends unknown[]> = {\n (...args: A): void;\n cancel: () => void;\n};\n\n/**\n * A debounced wrapper around `callback` that is stable across renders (it reads\n * the latest callback via a ref) and clears its pending timer on unmount, so a\n * late fire can never run against a torn-down component.\n */\nexport function useDebouncedCallback<A extends unknown[]>(\n callback: (...args: A) => void,\n delayMs: number,\n): DebouncedCallback<A> {\n const callbackRef = useRef(callback);\n callbackRef.current = callback;\n\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const cancel = useCallback(() => {\n if (timerRef.current !== null) {\n clearTimeout(timerRef.current);\n timerRef.current = null;\n }\n }, []);\n\n useEffect(() => cancel, [cancel]);\n\n return useMemo(() => {\n const debounced = (...args: A): void => {\n cancel();\n timerRef.current = setTimeout(() => {\n timerRef.current = null;\n callbackRef.current(...args);\n }, delayMs);\n };\n\n debounced.cancel = cancel;\n\n return debounced;\n }, [cancel, delayMs]);\n}\n"],"mappings":";;;;;;;AAYA,SAAgB,qBACd,UACA,SACsB;CACtB,MAAM,cAAc,OAAO,QAAQ;CACnC,YAAY,UAAU;CAEtB,MAAM,WAAW,OAA6C,IAAI;CAElE,MAAM,SAAS,kBAAkB;EAC/B,IAAI,SAAS,YAAY,MAAM;GAC7B,aAAa,SAAS,OAAO;GAC7B,SAAS,UAAU;EACrB;CACF,GAAG,CAAC,CAAC;CAEL,gBAAgB,QAAQ,CAAC,MAAM,CAAC;CAEhC,OAAO,cAAc;EACnB,MAAM,aAAa,GAAG,SAAkB;GACtC,OAAO;GACP,SAAS,UAAU,iBAAiB;IAClC,SAAS,UAAU;IACnB,YAAY,QAAQ,GAAG,IAAI;GAC7B,GAAG,OAAO;EACZ;EAEA,UAAU,SAAS;EAEnB,OAAO;CACT,GAAG,CAAC,QAAQ,OAAO,CAAC;AACtB"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Track a CSS media query. `fallback` is the SSR / no-`matchMedia` value and the
3
+ * initial state before the effect subscribes.
4
+ */
5
+ export declare function useMediaQuery(query: string, fallback?: boolean): boolean;
@@ -0,0 +1,26 @@
1
+ import { useEffect, useState } from "react";
2
+ //#region resources/js/lib/use-media-query.ts
3
+ function matches(query, fallback) {
4
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") return fallback;
5
+ return window.matchMedia(query).matches;
6
+ }
7
+ /**
8
+ * Track a CSS media query. `fallback` is the SSR / no-`matchMedia` value and the
9
+ * initial state before the effect subscribes.
10
+ */
11
+ function useMediaQuery(query, fallback = false) {
12
+ const [state, setState] = useState(() => matches(query, fallback));
13
+ useEffect(() => {
14
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
15
+ const media = window.matchMedia(query);
16
+ const update = () => setState(media.matches);
17
+ update();
18
+ media.addEventListener("change", update);
19
+ return () => media.removeEventListener("change", update);
20
+ }, [query]);
21
+ return state;
22
+ }
23
+ //#endregion
24
+ export { useMediaQuery };
25
+
26
+ //# sourceMappingURL=use-media-query.js.map