@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
@@ -1,32 +1,70 @@
1
1
  import { initializeTheme } from "./appearance/index.js";
2
2
  import { extendRegistry } from "./core/registry.js";
3
3
  import { setDefaultRegistry } from "./core/registry-context.js";
4
- import { createLayoutResolver, createPageResolver } from "./inertia.js";
4
+ import { LocaleReload } from "./i18n/locale-reload.js";
5
+ import { i18nConfigFromPageProps } from "./i18n/shared-props.js";
6
+ import { createLayoutResolver, createPageResolver, withVisitHeaders } from "./inertia.js";
5
7
  import { ProviderBase } from "./provider-base.js";
6
8
  import { registry } from "./registry.js";
7
9
  import { createInertiaApp } from "@inertiajs/react";
8
- import { jsx } from "react/jsx-runtime";
10
+ import { useEffect, useState } from "react";
11
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
9
12
  //#region resources/js/create-app.tsx
13
+ function AwaitReady({ ready, children }) {
14
+ const [isReady, setReady] = useState(false);
15
+ useEffect(() => {
16
+ let active = true;
17
+ const reveal = () => {
18
+ if (active) setReady(true);
19
+ };
20
+ ready.then(reveal, reveal);
21
+ return () => {
22
+ active = false;
23
+ };
24
+ }, [ready]);
25
+ return isReady ? children : null;
26
+ }
10
27
  /**
11
28
  * Bootstrap an Inertia app with the Lattice shell: the page/layout resolvers
12
29
  * (server-driven Lattice pages and normal Inertia pages alike), the Provider —
13
- * registry, sprite, flash toasts via Lattice's own Toaster — and theme
14
- * initialization. Forwards any other createInertiaApp option.
30
+ * registry, sprite, flash toasts via Lattice's own Toaster — theme
31
+ * initialization, and the i18n bootstrap. Forwards any other createInertiaApp
32
+ * option.
15
33
  */
16
- function createLatticeApp({ registry: registry$1, plugins, sprite, pages = {}, defaultLayout, strictMode = true, ...inertiaOptions } = {}) {
34
+ function createLatticeApp({ registry: registry$1, plugins, sprite, pages = {}, defaultLayout, strictMode = true, i18n, boot, wrap, ...inertiaOptions } = {}) {
17
35
  const baseRegistry = registry$1 ?? registry;
18
36
  const activeRegistry = plugins && plugins.length > 0 ? extendRegistry(baseRegistry, ...plugins) : baseRegistry;
19
37
  setDefaultRegistry(activeRegistry);
38
+ const i18nEnabled = i18n !== false;
39
+ const userVisitOptions = inertiaOptions.defaults?.visitOptions;
40
+ const defaults = i18nEnabled ? {
41
+ ...inertiaOptions.defaults,
42
+ visitOptions: (href, options) => withVisitHeaders(href, userVisitOptions?.(href, options) ?? options)
43
+ } : inertiaOptions.defaults;
20
44
  const app = createInertiaApp({
21
45
  ...inertiaOptions,
46
+ defaults,
22
47
  strictMode,
23
48
  resolve: createPageResolver(pages),
24
49
  layout: createLayoutResolver({ defaultLayout }),
25
- withApp: (node) => /* @__PURE__ */ jsx(ProviderBase, {
26
- registry: activeRegistry,
27
- sprite,
28
- children: node
29
- })
50
+ withApp: (node, { ssr, page }) => {
51
+ const pending = [];
52
+ if (!ssr) {
53
+ if (i18nEnabled && i18nConfigFromPageProps(page.props) !== void 0) pending.push(import("./i18n/page-props.js").then((module) => module.configureI18nFromPageProps(page.props, i18n ?? {})));
54
+ const booted = boot?.({ page });
55
+ if (booted) pending.push(booted);
56
+ }
57
+ const inner = /* @__PURE__ */ jsxs(Fragment$1, { children: [node, i18nEnabled ? /* @__PURE__ */ jsx(LocaleReload, {}) : null] });
58
+ const shell = /* @__PURE__ */ jsx(ProviderBase, {
59
+ registry: activeRegistry,
60
+ sprite,
61
+ children: wrap ? wrap(inner) : inner
62
+ });
63
+ return pending.length > 0 ? /* @__PURE__ */ jsx(AwaitReady, {
64
+ ready: Promise.all(pending),
65
+ children: shell
66
+ }) : shell;
67
+ }
30
68
  });
31
69
  initializeTheme();
32
70
  return app;
@@ -1 +1 @@
1
- {"version":3,"file":"create-app.js","names":[],"sources":["../resources/js/create-app.tsx"],"sourcesContent":["import { createInertiaApp } from \"@inertiajs/react\";\nimport type { ReactElement } from \"react\";\nimport { initializeTheme } from \"./appearance\";\nimport { extendRegistry, type Plugin, type Registry } from \"./core/registry\";\nimport { setDefaultRegistry } from \"./core/registry-context\";\nimport type { SpriteValue } from \"./icons/sprite\";\nimport {\n createLayoutResolver,\n createPageResolver,\n type CreateLayoutResolverOptions,\n type PageModules,\n} from \"./inertia\";\nimport { ProviderBase } from \"./provider-base\";\nimport { registry as defaultRegistry } from \"./registry\";\n\ntype InertiaAppOptions = NonNullable<Parameters<typeof createInertiaApp>[0]>;\n\nexport type CreateLatticeAppOptions = Omit<\n InertiaAppOptions,\n \"resolve\" | \"layout\" | \"setup\" | \"withApp\" | \"pages\"\n> & {\n registry?: Registry;\n /**\n * Component-package plugins to merge onto the registry — pass the\n * Composer-discovered `virtual:lattice/plugins` here to register vendor\n * components with no manual `extendRegistry` call.\n */\n plugins?: Plugin[];\n sprite?: SpriteValue;\n /** Normal Inertia page modules, e.g. `import.meta.glob('./pages/**\\/*.tsx')`. */\n pages?: PageModules;\n defaultLayout?: CreateLayoutResolverOptions[\"defaultLayout\"];\n};\n\n/**\n * Bootstrap an Inertia app with the Lattice shell: the page/layout resolvers\n * (server-driven Lattice pages and normal Inertia pages alike), the Provider —\n * registry, sprite, flash toasts via Lattice's own Toaster — and theme\n * initialization. Forwards any other createInertiaApp option.\n */\nexport function createLatticeApp({\n registry,\n plugins,\n sprite,\n pages = {},\n defaultLayout,\n strictMode = true,\n ...inertiaOptions\n}: CreateLatticeAppOptions = {}) {\n const baseRegistry = registry ?? defaultRegistry;\n const activeRegistry =\n plugins && plugins.length > 0 ? extendRegistry(baseRegistry, ...plugins) : baseRegistry;\n\n setDefaultRegistry(activeRegistry);\n\n const app = createInertiaApp({\n ...inertiaOptions,\n strictMode,\n resolve: createPageResolver(pages),\n layout: createLayoutResolver({ defaultLayout }),\n withApp: (node: ReactElement): ReactElement => (\n <ProviderBase registry={activeRegistry} sprite={sprite}>\n {node}\n </ProviderBase>\n ),\n });\n\n initializeTheme();\n\n return app;\n}\n"],"mappings":";;;;;;;;;;;;;;;AAwCA,SAAgB,iBAAiB,EAC/B,UAAA,YACA,SACA,QACA,QAAQ,CAAC,GACT,eACA,aAAa,MACb,GAAG,mBACwB,CAAC,GAAG;CAC/B,MAAM,eAAe,cAAY;CACjC,MAAM,iBACJ,WAAW,QAAQ,SAAS,IAAI,eAAe,cAAc,GAAG,OAAO,IAAI;CAE7E,mBAAmB,cAAc;CAEjC,MAAM,MAAM,iBAAiB;EAC3B,GAAG;EACH;EACA,SAAS,mBAAmB,KAAK;EACjC,QAAQ,qBAAqB,EAAE,cAAc,CAAC;EAC9C,UAAU,SACR,oBAAC,cAAD;GAAc,UAAU;GAAwB;aAC7C;EACW,CAAA;CAElB,CAAC;CAED,gBAAgB;CAEhB,OAAO;AACT"}
1
+ {"version":3,"file":"create-app.js","names":[],"sources":["../resources/js/create-app.tsx"],"sourcesContent":["import type { Page as InertiaPage, VisitOptions } from \"@inertiajs/core\";\nimport { createInertiaApp } from \"@inertiajs/react\";\nimport { useEffect, useState, type ReactElement, type ReactNode } from \"react\";\nimport { initializeTheme } from \"./appearance\";\nimport { extendRegistry, type Plugin, type Registry } from \"./core/registry\";\nimport { setDefaultRegistry } from \"./core/registry-context\";\nimport type { SpriteValue } from \"./icons/sprite\";\nimport { LocaleReload } from \"./i18n/locale-reload\";\nimport { i18nConfigFromPageProps } from \"./i18n/shared-props\";\nimport {\n createLayoutResolver,\n createPageResolver,\n withVisitHeaders,\n type CreateLayoutResolverOptions,\n type PageModules,\n} from \"./inertia\";\nimport { ProviderBase } from \"./provider-base\";\nimport { registry as defaultRegistry } from \"./registry\";\n\ntype InertiaAppOptions = NonNullable<Parameters<typeof createInertiaApp>[0]>;\n\nexport type CreateLatticeAppI18nOptions = {\n /** i18next namespaces to load, e.g. `[\"lattice\", \"app\"]`. Defaults to the package's own. */\n namespaces?: string[];\n};\n\nexport type CreateLatticeAppOptions = Omit<\n InertiaAppOptions,\n \"resolve\" | \"layout\" | \"setup\" | \"withApp\" | \"pages\"\n> & {\n registry?: Registry;\n /**\n * Component-package plugins to merge onto the registry — pass the\n * Composer-discovered `virtual:lattice/plugins` here to register vendor\n * components with no manual `extendRegistry` call.\n */\n plugins?: Plugin[];\n sprite?: SpriteValue;\n /** Normal Inertia page modules, e.g. `import.meta.glob('./pages/**\\/*.tsx')`. */\n pages?: PageModules;\n defaultLayout?: CreateLayoutResolverOptions[\"defaultLayout\"];\n /**\n * Lattice's i18n bootstrap, on by default: when the backend shares the\n * `lattice.i18n` prop, the first render waits for the translation setup (no\n * flash of untranslated fallbacks), `LocaleReload` re-fetches the page after\n * a locale switch, and every visit carries the locale/timezone headers. The\n * i18next chunk only loads when the backend actually shares the prop. Pass\n * `false` to opt out entirely.\n */\n i18n?: CreateLatticeAppI18nOptions | false;\n /**\n * App bootstrap that needs the initial page — e.g. `configureEcho` from a\n * shared connection prop. Runs on the client before the first render; a\n * returned promise delays that render until it resolves.\n */\n boot?: (context: { page: InertiaPage }) => void | Promise<void>;\n /**\n * Compose providers or siblings around the app. Applied inside the Lattice\n * Provider, so the registry, sprite, and toaster contexts are available.\n */\n wrap?: (app: ReactElement) => ReactElement;\n};\n\n// Fail-open: a failed bootstrap renders the app anyway (with fallback strings)\n// rather than a blank page.\nfunction AwaitReady({ ready, children }: { ready: Promise<unknown>; children: ReactNode }) {\n const [isReady, setReady] = useState(false);\n\n useEffect(() => {\n let active = true;\n const reveal = (): void => {\n if (active) {\n setReady(true);\n }\n };\n\n void ready.then(reveal, reveal);\n\n return () => {\n active = false;\n };\n }, [ready]);\n\n return isReady ? children : null;\n}\n\n/**\n * Bootstrap an Inertia app with the Lattice shell: the page/layout resolvers\n * (server-driven Lattice pages and normal Inertia pages alike), the Provider —\n * registry, sprite, flash toasts via Lattice's own Toaster — theme\n * initialization, and the i18n bootstrap. Forwards any other createInertiaApp\n * option.\n */\nexport function createLatticeApp({\n registry,\n plugins,\n sprite,\n pages = {},\n defaultLayout,\n strictMode = true,\n i18n,\n boot,\n wrap,\n ...inertiaOptions\n}: CreateLatticeAppOptions = {}) {\n const baseRegistry = registry ?? defaultRegistry;\n const activeRegistry =\n plugins && plugins.length > 0 ? extendRegistry(baseRegistry, ...plugins) : baseRegistry;\n\n setDefaultRegistry(activeRegistry);\n\n const i18nEnabled = i18n !== false;\n const userVisitOptions = inertiaOptions.defaults?.visitOptions;\n const defaults = i18nEnabled\n ? {\n ...inertiaOptions.defaults,\n visitOptions: (href: string, options: VisitOptions): VisitOptions =>\n withVisitHeaders(href, userVisitOptions?.(href, options) ?? options),\n }\n : inertiaOptions.defaults;\n\n const app = createInertiaApp({\n ...inertiaOptions,\n defaults,\n strictMode,\n resolve: createPageResolver(pages),\n layout: createLayoutResolver({ defaultLayout }),\n withApp: (node: ReactElement, { ssr, page }: { ssr: boolean; page: InertiaPage }) => {\n const pending: Promise<unknown>[] = [];\n\n if (!ssr) {\n // Loaded on demand so apps without the shared i18n prop never ship the\n // i18next backend; the disabled-config call still stores the timezone.\n if (i18nEnabled && i18nConfigFromPageProps(page.props) !== undefined) {\n pending.push(\n import(\"./i18n/page-props\").then((module) =>\n module.configureI18nFromPageProps(page.props, i18n ?? {}),\n ),\n );\n }\n\n const booted = boot?.({ page });\n\n if (booted) {\n pending.push(booted);\n }\n }\n\n const inner = (\n <>\n {node}\n {i18nEnabled ? <LocaleReload /> : null}\n </>\n );\n\n // The whole shell waits, not just the page: anything rendering a\n // translated string (the Toaster included) would otherwise initialize\n // i18next before the backend can register — init runs exactly once,\n // first caller wins.\n const shell = (\n <ProviderBase registry={activeRegistry} sprite={sprite}>\n {wrap ? wrap(inner) : inner}\n </ProviderBase>\n );\n\n return pending.length > 0 ? (\n <AwaitReady ready={Promise.all(pending)}>{shell}</AwaitReady>\n ) : (\n shell\n );\n },\n });\n\n initializeTheme();\n\n return app;\n}\n"],"mappings":";;;;;;;;;;;;AAiEA,SAAS,WAAW,EAAE,OAAO,YAA8D;CACzF,MAAM,CAAC,SAAS,YAAY,SAAS,KAAK;CAE1C,gBAAgB;EACd,IAAI,SAAS;EACb,MAAM,eAAqB;GACzB,IAAI,QACF,SAAS,IAAI;EAEjB;EAEA,MAAW,KAAK,QAAQ,MAAM;EAE9B,aAAa;GACX,SAAS;EACX;CACF,GAAG,CAAC,KAAK,CAAC;CAEV,OAAO,UAAU,WAAW;AAC9B;;;;;;;;AASA,SAAgB,iBAAiB,EAC/B,UAAA,YACA,SACA,QACA,QAAQ,CAAC,GACT,eACA,aAAa,MACb,MACA,MACA,MACA,GAAG,mBACwB,CAAC,GAAG;CAC/B,MAAM,eAAe,cAAY;CACjC,MAAM,iBACJ,WAAW,QAAQ,SAAS,IAAI,eAAe,cAAc,GAAG,OAAO,IAAI;CAE7E,mBAAmB,cAAc;CAEjC,MAAM,cAAc,SAAS;CAC7B,MAAM,mBAAmB,eAAe,UAAU;CAClD,MAAM,WAAW,cACb;EACE,GAAG,eAAe;EAClB,eAAe,MAAc,YAC3B,iBAAiB,MAAM,mBAAmB,MAAM,OAAO,KAAK,OAAO;CACvE,IACA,eAAe;CAEnB,MAAM,MAAM,iBAAiB;EAC3B,GAAG;EACH;EACA;EACA,SAAS,mBAAmB,KAAK;EACjC,QAAQ,qBAAqB,EAAE,cAAc,CAAC;EAC9C,UAAU,MAAoB,EAAE,KAAK,WAAgD;GACnF,MAAM,UAA8B,CAAC;GAErC,IAAI,CAAC,KAAK;IAGR,IAAI,eAAe,wBAAwB,KAAK,KAAK,MAAM,KAAA,GACzD,QAAQ,KACN,OAAO,wBAAqB,MAAM,WAChC,OAAO,2BAA2B,KAAK,OAAO,QAAQ,CAAC,CAAC,CAC1D,CACF;IAGF,MAAM,SAAS,OAAO,EAAE,KAAK,CAAC;IAE9B,IAAI,QACF,QAAQ,KAAK,MAAM;GAEvB;GAEA,MAAM,QACJ,qBAAA,YAAA,EAAA,UAAA,CACG,MACA,cAAc,oBAAC,cAAD,CAAe,CAAA,IAAI,IAClC,EAAA,CAAA;GAOJ,MAAM,QACJ,oBAAC,cAAD;IAAc,UAAU;IAAwB;cAC7C,OAAO,KAAK,KAAK,IAAI;GACV,CAAA;GAGhB,OAAO,QAAQ,SAAS,IACtB,oBAAC,YAAD;IAAY,OAAO,QAAQ,IAAI,OAAO;cAAI;GAAkB,CAAA,IAE5D;EAEJ;CACF,CAAC;CAED,gBAAgB;CAEhB,OAAO;AACT"}
@@ -1,4 +1,4 @@
1
- import { LATTICE_EVENT } from "../events/event-names.js";
1
+ import { LATTICE_EVENT } from "../core/event-names.js";
2
2
  import { builtinEffectHandlers } from "./registry.js";
3
3
  //#region resources/js/effects/dispatch.ts
4
4
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"dispatch.js","names":[],"sources":["../../resources/js/effects/dispatch.ts"],"sourcesContent":["import type { ActionResult, Effect } from \"@lattice-php/lattice/types/generated\";\nimport { LATTICE_EVENT } from \"@lattice-php/lattice/events/event-names\";\nimport { builtinEffectHandlers } from \"./registry\";\nimport type { EffectHandlerRegistry } from \"./registry\";\n\nexport type ActionEffect = Effect;\n\nexport type ActionResponse = Partial<ActionResult>;\n\n/**\n * Run each effect through its handler. Handlers default to the built-ins; the\n * Provider passes a merged registry that also includes consumer-registered\n * handlers. An effect with no handler is warned about (dev) and skipped.\n */\nexport function dispatchEffects(\n effects: ActionEffect[],\n handlers: EffectHandlerRegistry = builtinEffectHandlers,\n): void {\n if (typeof window === \"undefined\") {\n return;\n }\n\n for (const effect of effects) {\n const handler = handlers[effect.type];\n\n if (handler === undefined) {\n console.warn(`[lattice] No handler registered for effect type \"${effect.type}\".`);\n continue;\n }\n\n handler(effect);\n }\n}\n\nexport function dispatchActionError(error: unknown): void {\n if (typeof window === \"undefined\") {\n return;\n }\n\n window.dispatchEvent(new CustomEvent(LATTICE_EVENT.actionError, { detail: { error } }));\n}\n\nexport function getActionEffects(effects: unknown): ActionEffect[] {\n return Array.isArray(effects) ? effects.filter(isActionEffect) : [];\n}\n\n/**\n * Structural guard for an effect on the wire. Intentionally open: it accepts any\n * object with a string `type`, not only the built-in types, so consumer-registered\n * effects pass through getActionEffects() and reach their handlers. Dispatch warns\n * on (and skips) a type with no registered handler.\n */\nexport function isActionEffect(effect: unknown): effect is ActionEffect {\n return (\n typeof effect === \"object\" &&\n effect !== null &&\n \"type\" in effect &&\n typeof (effect as { type: unknown }).type === \"string\"\n );\n}\n"],"mappings":";;;;;;;;AAcA,SAAgB,gBACd,SACA,WAAkC,uBAC5B;CACN,IAAI,OAAO,WAAW,aACpB;CAGF,KAAK,MAAM,UAAU,SAAS;EAC5B,MAAM,UAAU,SAAS,OAAO;EAEhC,IAAI,YAAY,KAAA,GAAW;GACzB,QAAQ,KAAK,oDAAoD,OAAO,KAAK,GAAG;GAChF;EACF;EAEA,QAAQ,MAAM;CAChB;AACF;AAEA,SAAgB,oBAAoB,OAAsB;CACxD,IAAI,OAAO,WAAW,aACpB;CAGF,OAAO,cAAc,IAAI,YAAY,cAAc,aAAa,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;AACxF;AAEA,SAAgB,iBAAiB,SAAkC;CACjE,OAAO,MAAM,QAAQ,OAAO,IAAI,QAAQ,OAAO,cAAc,IAAI,CAAC;AACpE;;;;;;;AAQA,SAAgB,eAAe,QAAyC;CACtE,OACE,OAAO,WAAW,YAClB,WAAW,QACX,UAAU,UACV,OAAQ,OAA6B,SAAS;AAElD"}
1
+ {"version":3,"file":"dispatch.js","names":[],"sources":["../../resources/js/effects/dispatch.ts"],"sourcesContent":["import type { ActionResult, Effect } from \"@lattice-php/lattice/types/generated\";\nimport { LATTICE_EVENT } from \"@lattice-php/lattice/core/event-names\";\nimport { builtinEffectHandlers } from \"./registry\";\nimport type { EffectHandlerRegistry } from \"./registry\";\n\nexport type ActionEffect = Effect;\n\nexport type ActionResponse = Partial<ActionResult>;\n\n/**\n * Run each effect through its handler. Handlers default to the built-ins; the\n * Provider passes a merged registry that also includes consumer-registered\n * handlers. An effect with no handler is warned about (dev) and skipped.\n */\nexport function dispatchEffects(\n effects: ActionEffect[],\n handlers: EffectHandlerRegistry = builtinEffectHandlers,\n): void {\n if (typeof window === \"undefined\") {\n return;\n }\n\n for (const effect of effects) {\n const handler = handlers[effect.type];\n\n if (handler === undefined) {\n console.warn(`[lattice] No handler registered for effect type \"${effect.type}\".`);\n continue;\n }\n\n handler(effect);\n }\n}\n\nexport function dispatchActionError(error: unknown): void {\n if (typeof window === \"undefined\") {\n return;\n }\n\n window.dispatchEvent(new CustomEvent(LATTICE_EVENT.actionError, { detail: { error } }));\n}\n\nexport function getActionEffects(effects: unknown): ActionEffect[] {\n return Array.isArray(effects) ? effects.filter(isActionEffect) : [];\n}\n\n/**\n * Structural guard for an effect on the wire. Intentionally open: it accepts any\n * object with a string `type`, not only the built-in types, so consumer-registered\n * effects pass through getActionEffects() and reach their handlers. Dispatch warns\n * on (and skips) a type with no registered handler.\n */\nexport function isActionEffect(effect: unknown): effect is ActionEffect {\n return (\n typeof effect === \"object\" &&\n effect !== null &&\n \"type\" in effect &&\n typeof (effect as { type: unknown }).type === \"string\"\n );\n}\n"],"mappings":";;;;;;;;AAcA,SAAgB,gBACd,SACA,WAAkC,uBAC5B;CACN,IAAI,OAAO,WAAW,aACpB;CAGF,KAAK,MAAM,UAAU,SAAS;EAC5B,MAAM,UAAU,SAAS,OAAO;EAEhC,IAAI,YAAY,KAAA,GAAW;GACzB,QAAQ,KAAK,oDAAoD,OAAO,KAAK,GAAG;GAChF;EACF;EAEA,QAAQ,MAAM;CAChB;AACF;AAEA,SAAgB,oBAAoB,OAAsB;CACxD,IAAI,OAAO,WAAW,aACpB;CAGF,OAAO,cAAc,IAAI,YAAY,cAAc,aAAa,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;AACxF;AAEA,SAAgB,iBAAiB,SAAkC;CACjE,OAAO,MAAM,QAAQ,OAAO,IAAI,QAAQ,OAAO,cAAc,IAAI,CAAC;AACpE;;;;;;;AAQA,SAAgB,eAAe,QAAyC;CACtE,OACE,OAAO,WAAW,YAClB,WAAW,QACX,UAAU,UACV,OAAQ,OAA6B,SAAS;AAElD"}
@@ -1,16 +1,5 @@
1
- import { ResolveProps } from '../core/types.js';
2
- import { Effect, EffectPropsMap } from '../types/generated.js';
3
- /**
4
- * Consumer apps augment this via `declare module "@lattice-php/lattice"` to type
5
- * their custom effects' payloads; built-ins resolve through `EffectPropsMap`. The
6
- * effect counterpart of `ComponentProps`.
7
- */
8
- export interface EffectProps {
9
- }
10
- type EffectPayloadOf<TType extends string> = ResolveProps<EffectProps, EffectPropsMap, TType, Record<string, unknown>>;
11
- export type EffectOf<TType extends string> = string extends TType ? Effect : {
12
- type: TType;
13
- } & EffectPayloadOf<TType>;
1
+ import { EffectOf, EffectProps, EffectPropsMap, EffectPropsOf } from '../types/generated.js';
2
+ export type { EffectOf, EffectProps, EffectPropsOf };
14
3
  export type EffectHandler<TType extends string = string> = (effect: EffectOf<TType>) => void;
15
4
  export type EffectHandlerRegistry = Record<string, EffectHandler>;
16
5
  export type EffectHandlerRegistryFor<TTypes extends keyof EffectPropsMap & string> = Record<TTypes, EffectHandler>;
@@ -19,10 +8,5 @@ export type EffectHandlerRegistryFor<TTypes extends keyof EffectPropsMap & strin
19
8
  * register it through this — it erases the type parameter for the loose registry.
20
9
  */
21
10
  export declare function effectHandler<TType extends string>(_type: TType, fn: EffectHandler<TType>): EffectHandler;
22
- /**
23
- * Imperative effects act directly; the rest bridge to the `lattice:*` DOM events
24
- * that toast/callout/modal/fragment/form subscribe to.
25
- */
26
11
  export declare const builtinEffectHandlers: EffectHandlerRegistryFor<keyof EffectPropsMap & string>;
27
12
  export declare function mergeEffectHandlers(...registries: Array<EffectHandlerRegistry | undefined>): EffectHandlerRegistry;
28
- export {};
@@ -1,4 +1,4 @@
1
- import { LATTICE_EVENT } from "../events/event-names.js";
1
+ import { LATTICE_EVENT } from "../core/event-names.js";
2
2
  import { setLocale } from "../i18n/locale.js";
3
3
  import { router } from "@inertiajs/react";
4
4
  //#region resources/js/effects/registry.ts
@@ -18,17 +18,13 @@ function triggerDownload(url) {
18
18
  link.remove();
19
19
  }
20
20
  function bridge(event) {
21
- return (effect) => window.dispatchEvent(new CustomEvent(event, { detail: effect }));
21
+ return (effect) => window.dispatchEvent(new CustomEvent(event, { detail: effect.props }));
22
22
  }
23
- /**
24
- * Imperative effects act directly; the rest bridge to the `lattice:*` DOM events
25
- * that toast/callout/modal/fragment/form subscribe to.
26
- */
27
23
  var builtinEffectHandlers = {
28
24
  "reload-page": () => router.reload(),
29
- redirect: effectHandler("redirect", (effect) => router.visit(effect.url)),
30
- download: effectHandler("download", (effect) => triggerDownload(effect.url)),
31
- "locale-change": effectHandler("locale-change", (effect) => setLocale(effect.locale)),
25
+ redirect: (effect) => router.visit(effect.props.url),
26
+ download: (effect) => triggerDownload(effect.props.url),
27
+ "locale-change": (effect) => setLocale(effect.props.locale),
32
28
  toast: bridge(LATTICE_EVENT.toast),
33
29
  callout: bridge(LATTICE_EVENT.callout),
34
30
  "reload-component": bridge(LATTICE_EVENT.reloadComponent),
@@ -1 +1 @@
1
- {"version":3,"file":"registry.js","names":[],"sources":["../../resources/js/effects/registry.ts"],"sourcesContent":["import { router } from \"@inertiajs/react\";\nimport type { ResolveProps } from \"@lattice-php/lattice/core/types\";\nimport type { Effect, EffectPropsMap } from \"@lattice-php/lattice/types/generated\";\nimport { LATTICE_EVENT } from \"@lattice-php/lattice/events/event-names\";\nimport { setLocale } from \"@lattice-php/lattice/i18n/locale\";\n\n/**\n * Consumer apps augment this via `declare module \"@lattice-php/lattice\"` to type\n * their custom effects' payloads; built-ins resolve through `EffectPropsMap`. The\n * effect counterpart of `ComponentProps`.\n */\nexport interface EffectProps {}\n\ntype EffectPayloadOf<TType extends string> = ResolveProps<\n EffectProps,\n EffectPropsMap,\n TType,\n Record<string, unknown>\n>;\n\nexport type EffectOf<TType extends string> = string extends TType\n ? Effect\n : { type: TType } & EffectPayloadOf<TType>;\n\nexport type EffectHandler<TType extends string = string> = (effect: EffectOf<TType>) => void;\n\nexport type EffectHandlerRegistry = Record<string, EffectHandler>;\n\nexport type EffectHandlerRegistryFor<TTypes extends keyof EffectPropsMap & string> = Record<\n TTypes,\n EffectHandler\n>;\n\n/**\n * Author a handler against `EffectHandler<\"my.type\">` for a typed payload, then\n * register it through this — it erases the type parameter for the loose registry.\n */\nexport function effectHandler<TType extends string>(\n _type: TType,\n fn: EffectHandler<TType>,\n): EffectHandler {\n return fn as unknown as EffectHandler;\n}\n\nfunction triggerDownload(url: string): void {\n const link = document.createElement(\"a\");\n link.href = url;\n link.rel = \"noopener\";\n document.body.appendChild(link);\n link.click();\n link.remove();\n}\n\nfunction bridge(event: string): EffectHandler {\n return (effect) => window.dispatchEvent(new CustomEvent(event, { detail: effect }));\n}\n\n/**\n * Imperative effects act directly; the rest bridge to the `lattice:*` DOM events\n * that toast/callout/modal/fragment/form subscribe to.\n */\nexport const builtinEffectHandlers: EffectHandlerRegistryFor<keyof EffectPropsMap & string> = {\n \"reload-page\": () => router.reload(),\n redirect: effectHandler(\"redirect\", (effect) => router.visit(effect.url)),\n download: effectHandler(\"download\", (effect) => triggerDownload(effect.url)),\n \"locale-change\": effectHandler(\"locale-change\", (effect) => setLocale(effect.locale)),\n toast: bridge(LATTICE_EVENT.toast),\n callout: bridge(LATTICE_EVENT.callout),\n \"reload-component\": bridge(LATTICE_EVENT.reloadComponent),\n \"open-modal\": bridge(LATTICE_EVENT.openModal),\n \"close-modal\": bridge(LATTICE_EVENT.closeModal),\n \"reset-form\": bridge(LATTICE_EVENT.resetForm),\n \"toggle-sidebar\": bridge(LATTICE_EVENT.toggleSidebar),\n};\n\nexport function mergeEffectHandlers(\n ...registries: Array<EffectHandlerRegistry | undefined>\n): EffectHandlerRegistry {\n return registries.reduce<EffectHandlerRegistry>(\n (merged, registry) => ({ ...merged, ...registry }),\n {},\n );\n}\n"],"mappings":";;;;;;;;AAqCA,SAAgB,cACd,OACA,IACe;CACf,OAAO;AACT;AAEA,SAAS,gBAAgB,KAAmB;CAC1C,MAAM,OAAO,SAAS,cAAc,GAAG;CACvC,KAAK,OAAO;CACZ,KAAK,MAAM;CACX,SAAS,KAAK,YAAY,IAAI;CAC9B,KAAK,MAAM;CACX,KAAK,OAAO;AACd;AAEA,SAAS,OAAO,OAA8B;CAC5C,QAAQ,WAAW,OAAO,cAAc,IAAI,YAAY,OAAO,EAAE,QAAQ,OAAO,CAAC,CAAC;AACpF;;;;;AAMA,IAAa,wBAAiF;CAC5F,qBAAqB,OAAO,OAAO;CACnC,UAAU,cAAc,aAAa,WAAW,OAAO,MAAM,OAAO,GAAG,CAAC;CACxE,UAAU,cAAc,aAAa,WAAW,gBAAgB,OAAO,GAAG,CAAC;CAC3E,iBAAiB,cAAc,kBAAkB,WAAW,UAAU,OAAO,MAAM,CAAC;CACpF,OAAO,OAAO,cAAc,KAAK;CACjC,SAAS,OAAO,cAAc,OAAO;CACrC,oBAAoB,OAAO,cAAc,eAAe;CACxD,cAAc,OAAO,cAAc,SAAS;CAC5C,eAAe,OAAO,cAAc,UAAU;CAC9C,cAAc,OAAO,cAAc,SAAS;CAC5C,kBAAkB,OAAO,cAAc,aAAa;AACtD;AAEA,SAAgB,oBACd,GAAG,YACoB;CACvB,OAAO,WAAW,QACf,QAAQ,cAAc;EAAE,GAAG;EAAQ,GAAG;CAAS,IAChD,CAAC,CACH;AACF"}
1
+ {"version":3,"file":"registry.js","names":[],"sources":["../../resources/js/effects/registry.ts"],"sourcesContent":["import { router } from \"@inertiajs/react\";\nimport type {\n EffectOf,\n EffectProps,\n EffectPropsMap,\n EffectPropsOf,\n} from \"@lattice-php/lattice/types/generated\";\nimport { LATTICE_EVENT } from \"@lattice-php/lattice/core/event-names\";\nimport { setLocale } from \"@lattice-php/lattice/i18n/locale\";\n\nexport type { EffectOf, EffectProps, EffectPropsOf };\n\nexport type EffectHandler<TType extends string = string> = (effect: EffectOf<TType>) => void;\n\nexport type EffectHandlerRegistry = Record<string, EffectHandler>;\n\nexport type EffectHandlerRegistryFor<TTypes extends keyof EffectPropsMap & string> = Record<\n TTypes,\n EffectHandler\n>;\n\n/**\n * Author a handler against `EffectHandler<\"my.type\">` for a typed payload, then\n * register it through this — it erases the type parameter for the loose registry.\n */\nexport function effectHandler<TType extends string>(\n _type: TType,\n fn: EffectHandler<TType>,\n): EffectHandler {\n return fn as unknown as EffectHandler;\n}\n\nfunction triggerDownload(url: string): void {\n const link = document.createElement(\"a\");\n link.href = url;\n link.rel = \"noopener\";\n document.body.appendChild(link);\n link.click();\n link.remove();\n}\n\nfunction bridge<TType extends keyof EffectPropsMap & string>(event: string): EffectHandler<TType> {\n return (effect) => window.dispatchEvent(new CustomEvent(event, { detail: effect.props }));\n}\n\n/**\n * Imperative effects act directly; the rest bridge to the `lattice:*` DOM events\n * that toast/callout/modal/fragment/form subscribe to. The export cast erases\n * the mapped type to the loose registry shape — the same variance erasure\n * effectHandler performs.\n */\nconst typedBuiltinHandlers: { [K in keyof EffectPropsMap]: EffectHandler<K> } = {\n \"reload-page\": () => router.reload(),\n redirect: (effect) => router.visit(effect.props.url),\n download: (effect) => triggerDownload(effect.props.url),\n \"locale-change\": (effect) => setLocale(effect.props.locale),\n toast: bridge<\"toast\">(LATTICE_EVENT.toast),\n callout: bridge<\"callout\">(LATTICE_EVENT.callout),\n \"reload-component\": bridge<\"reload-component\">(LATTICE_EVENT.reloadComponent),\n \"open-modal\": bridge<\"open-modal\">(LATTICE_EVENT.openModal),\n \"close-modal\": bridge<\"close-modal\">(LATTICE_EVENT.closeModal),\n \"reset-form\": bridge<\"reset-form\">(LATTICE_EVENT.resetForm),\n \"toggle-sidebar\": bridge<\"toggle-sidebar\">(LATTICE_EVENT.toggleSidebar),\n};\n\nexport const builtinEffectHandlers: EffectHandlerRegistryFor<keyof EffectPropsMap & string> =\n typedBuiltinHandlers as EffectHandlerRegistryFor<keyof EffectPropsMap & string>;\n\nexport function mergeEffectHandlers(\n ...registries: Array<EffectHandlerRegistry | undefined>\n): EffectHandlerRegistry {\n return registries.reduce<EffectHandlerRegistry>(\n (merged, registry) => ({ ...merged, ...registry }),\n {},\n );\n}\n"],"mappings":";;;;;;;;AAyBA,SAAgB,cACd,OACA,IACe;CACf,OAAO;AACT;AAEA,SAAS,gBAAgB,KAAmB;CAC1C,MAAM,OAAO,SAAS,cAAc,GAAG;CACvC,KAAK,OAAO;CACZ,KAAK,MAAM;CACX,SAAS,KAAK,YAAY,IAAI;CAC9B,KAAK,MAAM;CACX,KAAK,OAAO;AACd;AAEA,SAAS,OAAoD,OAAqC;CAChG,QAAQ,WAAW,OAAO,cAAc,IAAI,YAAY,OAAO,EAAE,QAAQ,OAAO,MAAM,CAAC,CAAC;AAC1F;AAsBA,IAAa,wBACX;CAdA,qBAAqB,OAAO,OAAO;CACnC,WAAW,WAAW,OAAO,MAAM,OAAO,MAAM,GAAG;CACnD,WAAW,WAAW,gBAAgB,OAAO,MAAM,GAAG;CACtD,kBAAkB,WAAW,UAAU,OAAO,MAAM,MAAM;CAC1D,OAAO,OAAgB,cAAc,KAAK;CAC1C,SAAS,OAAkB,cAAc,OAAO;CAChD,oBAAoB,OAA2B,cAAc,eAAe;CAC5E,cAAc,OAAqB,cAAc,SAAS;CAC1D,eAAe,OAAsB,cAAc,UAAU;CAC7D,cAAc,OAAqB,cAAc,SAAS;CAC1D,kBAAkB,OAAyB,cAAc,aAAa;AAItE;AAEF,SAAgB,oBACd,GAAG,YACoB;CACvB,OAAO,WAAW,QACf,QAAQ,cAAc;EAAE,GAAG;EAAQ,GAAG;CAAS,IAChD,CAAC,CACH;AACF"}
@@ -1,5 +1,6 @@
1
1
  import { isAppearance } from "./appearance/index.js";
2
- import { LATTICE_EVENT } from "./events/event-names.js";
2
+ import { LATTICE_EVENT } from "./core/event-names.js";
3
+ import { useWindowEvent } from "./core/hooks/use-window-event.js";
3
4
  import { onToast } from "./toast/toast.js";
4
5
  import { useEffect } from "react";
5
6
  //#region resources/js/event-bridge.tsx
@@ -8,28 +9,14 @@ function EventBridge({ onAppearanceChange, onLocaleChange, onToast: onToast$1 })
8
9
  if (!onToast$1) return;
9
10
  return onToast(onToast$1);
10
11
  }, [onToast$1]);
11
- useEffect(() => {
12
- if (!onAppearanceChange) return;
13
- const listener = (event) => {
14
- const value = event.detail?.value;
15
- if (isAppearance(value)) onAppearanceChange(value);
16
- };
17
- window.addEventListener(LATTICE_EVENT.appearanceChange, listener);
18
- return () => {
19
- window.removeEventListener(LATTICE_EVENT.appearanceChange, listener);
20
- };
21
- }, [onAppearanceChange]);
22
- useEffect(() => {
23
- if (!onLocaleChange) return;
24
- const listener = (event) => {
25
- const locale = event.detail?.locale;
26
- if (typeof locale === "string" && locale !== "") onLocaleChange(locale);
27
- };
28
- window.addEventListener(LATTICE_EVENT.localeChange, listener);
29
- return () => {
30
- window.removeEventListener(LATTICE_EVENT.localeChange, listener);
31
- };
32
- }, [onLocaleChange]);
12
+ useWindowEvent(LATTICE_EVENT.appearanceChange, (event) => {
13
+ const value = event.detail?.value;
14
+ if (isAppearance(value)) onAppearanceChange?.(value);
15
+ }, { enabled: Boolean(onAppearanceChange) });
16
+ useWindowEvent(LATTICE_EVENT.localeChange, (event) => {
17
+ const locale = event.detail?.locale;
18
+ if (typeof locale === "string" && locale !== "") onLocaleChange?.(locale);
19
+ }, { enabled: Boolean(onLocaleChange) });
33
20
  return null;
34
21
  }
35
22
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"event-bridge.js","names":[],"sources":["../resources/js/event-bridge.tsx"],"sourcesContent":["import { useEffect } from \"react\";\nimport { onToast as subscribeToToasts } from \"@lattice-php/lattice/toast\";\nimport type { ToastMessage } from \"@lattice-php/lattice/toast\";\nimport { isAppearance, type Appearance } from \"./appearance\";\nimport { LATTICE_EVENT } from \"./events/event-names\";\n\ntype EventBridgeProps = {\n onAppearanceChange?: (appearance: Appearance) => void;\n onLocaleChange?: (locale: string) => void;\n onToast?: (toast: ToastMessage) => void;\n};\n\ntype AppearanceEvent = CustomEvent<{\n value?: unknown;\n}>;\n\ntype LocaleEvent = CustomEvent<{\n locale?: unknown;\n}>;\n\nexport function EventBridge({ onAppearanceChange, onLocaleChange, onToast }: EventBridgeProps) {\n useEffect(() => {\n if (!onToast) {\n return;\n }\n\n return subscribeToToasts(onToast);\n }, [onToast]);\n\n useEffect(() => {\n if (!onAppearanceChange) {\n return;\n }\n\n const listener = (event: Event): void => {\n const value = (event as AppearanceEvent).detail?.value;\n\n if (isAppearance(value)) {\n onAppearanceChange(value);\n }\n };\n\n window.addEventListener(LATTICE_EVENT.appearanceChange, listener);\n\n return () => {\n window.removeEventListener(LATTICE_EVENT.appearanceChange, listener);\n };\n }, [onAppearanceChange]);\n\n useEffect(() => {\n if (!onLocaleChange) {\n return;\n }\n\n const listener = (event: Event): void => {\n const locale = (event as LocaleEvent).detail?.locale;\n\n if (typeof locale === \"string\" && locale !== \"\") {\n onLocaleChange(locale);\n }\n };\n\n window.addEventListener(LATTICE_EVENT.localeChange, listener);\n\n return () => {\n window.removeEventListener(LATTICE_EVENT.localeChange, listener);\n };\n }, [onLocaleChange]);\n\n return null;\n}\n"],"mappings":";;;;;AAoBA,SAAgB,YAAY,EAAE,oBAAoB,gBAAgB,SAAA,aAA6B;CAC7F,gBAAgB;EACd,IAAI,CAAC,WACH;EAGF,OAAO,QAAkB,SAAO;CAClC,GAAG,CAAC,SAAO,CAAC;CAEZ,gBAAgB;EACd,IAAI,CAAC,oBACH;EAGF,MAAM,YAAY,UAAuB;GACvC,MAAM,QAAS,MAA0B,QAAQ;GAEjD,IAAI,aAAa,KAAK,GACpB,mBAAmB,KAAK;EAE5B;EAEA,OAAO,iBAAiB,cAAc,kBAAkB,QAAQ;EAEhE,aAAa;GACX,OAAO,oBAAoB,cAAc,kBAAkB,QAAQ;EACrE;CACF,GAAG,CAAC,kBAAkB,CAAC;CAEvB,gBAAgB;EACd,IAAI,CAAC,gBACH;EAGF,MAAM,YAAY,UAAuB;GACvC,MAAM,SAAU,MAAsB,QAAQ;GAE9C,IAAI,OAAO,WAAW,YAAY,WAAW,IAC3C,eAAe,MAAM;EAEzB;EAEA,OAAO,iBAAiB,cAAc,cAAc,QAAQ;EAE5D,aAAa;GACX,OAAO,oBAAoB,cAAc,cAAc,QAAQ;EACjE;CACF,GAAG,CAAC,cAAc,CAAC;CAEnB,OAAO;AACT"}
1
+ {"version":3,"file":"event-bridge.js","names":[],"sources":["../resources/js/event-bridge.tsx"],"sourcesContent":["import { useEffect } from \"react\";\nimport { onToast as subscribeToToasts } from \"@lattice-php/lattice/toast\";\nimport type { ToastMessage } from \"@lattice-php/lattice/toast\";\nimport { useWindowEvent } from \"@lattice-php/lattice/core/hooks/use-window-event\";\nimport { isAppearance, type Appearance } from \"./appearance\";\nimport { LATTICE_EVENT } from \"./core/event-names\";\n\ntype EventBridgeProps = {\n onAppearanceChange?: (appearance: Appearance) => void;\n onLocaleChange?: (locale: string) => void;\n onToast?: (toast: ToastMessage) => void;\n};\n\ntype AppearanceEvent = CustomEvent<{\n value?: unknown;\n}>;\n\ntype LocaleEvent = CustomEvent<{\n locale?: unknown;\n}>;\n\nexport function EventBridge({ onAppearanceChange, onLocaleChange, onToast }: EventBridgeProps) {\n useEffect(() => {\n if (!onToast) {\n return;\n }\n\n return subscribeToToasts(onToast);\n }, [onToast]);\n\n useWindowEvent(\n LATTICE_EVENT.appearanceChange,\n (event) => {\n const value = (event as AppearanceEvent).detail?.value;\n\n if (isAppearance(value)) {\n onAppearanceChange?.(value);\n }\n },\n { enabled: Boolean(onAppearanceChange) },\n );\n\n useWindowEvent(\n LATTICE_EVENT.localeChange,\n (event) => {\n const locale = (event as LocaleEvent).detail?.locale;\n\n if (typeof locale === \"string\" && locale !== \"\") {\n onLocaleChange?.(locale);\n }\n },\n { enabled: Boolean(onLocaleChange) },\n );\n\n return null;\n}\n"],"mappings":";;;;;;AAqBA,SAAgB,YAAY,EAAE,oBAAoB,gBAAgB,SAAA,aAA6B;CAC7F,gBAAgB;EACd,IAAI,CAAC,WACH;EAGF,OAAO,QAAkB,SAAO;CAClC,GAAG,CAAC,SAAO,CAAC;CAEZ,eACE,cAAc,mBACb,UAAU;EACT,MAAM,QAAS,MAA0B,QAAQ;EAEjD,IAAI,aAAa,KAAK,GACpB,qBAAqB,KAAK;CAE9B,GACA,EAAE,SAAS,QAAQ,kBAAkB,EAAE,CACzC;CAEA,eACE,cAAc,eACb,UAAU;EACT,MAAM,SAAU,MAAsB,QAAQ;EAE9C,IAAI,OAAO,WAAW,YAAY,WAAW,IAC3C,iBAAiB,MAAM;CAE3B,GACA,EAAE,SAAS,QAAQ,cAAc,EAAE,CACrC;CAEA,OAAO;AACT"}
@@ -1,10 +1,10 @@
1
- import { FormLabelAction } from '../../types.js';
1
+ import { LabelAction } from '../../types.js';
2
2
  export declare function FormFieldFrame({ children, error, helperText, label, labelAction, name, required, tooltip, }: {
3
3
  children: React.ReactNode;
4
4
  error?: string;
5
5
  helperText?: string;
6
6
  label: string;
7
- labelAction?: FormLabelAction;
7
+ labelAction?: LabelAction;
8
8
  name: string;
9
9
  required?: boolean;
10
10
  tooltip?: string;
@@ -1,8 +1,8 @@
1
+ import { useInTableCell } from "../../hooks/row-layout-context.js";
1
2
  import { InfoTooltip } from "../../../ui/info-tooltip.js";
2
3
  import { TextLink } from "../../../ui/link.js";
3
4
  import InputError from "../../../ui/input-error.js";
4
5
  import { Label } from "../../../ui/label.js";
5
- import { useInTableCell } from "../../hooks/row-layout-context.js";
6
6
  import { jsx, jsxs } from "react/jsx-runtime";
7
7
  //#region resources/js/form/components/base/field.tsx
8
8
  function FormFieldFrame({ children, error, helperText, label, labelAction, name, required, tooltip }) {
@@ -36,7 +36,7 @@ function FormFieldFrame({ children, error, helperText, label, labelAction, name,
36
36
  /* @__PURE__ */ jsx(InfoTooltip, { content: tooltip }),
37
37
  labelAction && /* @__PURE__ */ jsx(TextLink, {
38
38
  href: labelAction.href,
39
- tabIndex: labelAction.tabIndex,
39
+ tabIndex: labelAction.tabIndex ?? void 0,
40
40
  className: "ml-auto text-sm",
41
41
  children: labelAction.label
42
42
  })
@@ -1 +1 @@
1
- {"version":3,"file":"field.js","names":[],"sources":["../../../../resources/js/form/components/base/field.tsx"],"sourcesContent":["import InputError from \"@lattice-php/lattice/ui/input-error\";\nimport { InfoTooltip } from \"@lattice-php/lattice/ui/info-tooltip\";\nimport { TextLink } from \"@lattice-php/lattice/ui/link\";\nimport { Label } from \"@lattice-php/lattice/ui/label\";\nimport { useInTableCell } from \"@lattice-php/lattice/form/hooks/row-layout-context\";\nimport type { FormLabelAction } from \"@lattice-php/lattice/form/types\";\n\nexport function FormFieldFrame({\n children,\n error,\n helperText,\n label,\n labelAction,\n name,\n required,\n tooltip,\n}: {\n children: React.ReactNode;\n error?: string;\n helperText?: string;\n label: string;\n labelAction?: FormLabelAction;\n name: string;\n required?: boolean;\n tooltip?: string;\n}) {\n const bare = useInTableCell();\n\n if (bare) {\n return (\n <div className=\"grid gap-1\">\n <Label htmlFor={name} className=\"sr-only\">\n {label}\n </Label>\n {children}\n <InputError message={error} />\n </div>\n );\n }\n\n return (\n <div className=\"grid gap-2\">\n <div className=\"flex min-h-5 items-center\">\n <Label htmlFor={name}>{label}</Label>\n {required && (\n <span aria-hidden=\"true\" className=\"ml-0.5 text-lt-danger\">\n *\n </span>\n )}\n <InfoTooltip content={tooltip} />\n {labelAction && (\n <TextLink\n href={labelAction.href}\n tabIndex={labelAction.tabIndex}\n className=\"ml-auto text-sm\"\n >\n {labelAction.label}\n </TextLink>\n )}\n </div>\n\n {children}\n\n {helperText && <p className=\"text-sm text-lt-muted-fg\">{helperText}</p>}\n\n <InputError message={error} />\n </div>\n );\n}\n"],"mappings":";;;;;;;AAOA,SAAgB,eAAe,EAC7B,UACA,OACA,YACA,OACA,aACA,MACA,UACA,WAUC;CAGD,IAFa,eAET,GACF,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf;GACE,oBAAC,OAAD;IAAO,SAAS;IAAM,WAAU;cAC7B;GACI,CAAA;GACN;GACD,oBAAC,YAAD,EAAY,SAAS,MAAQ,CAAA;EAC1B;;CAIT,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf;GACE,qBAAC,OAAD;IAAK,WAAU;cAAf;KACE,oBAAC,OAAD;MAAO,SAAS;gBAAO;KAAa,CAAA;KACnC,YACC,oBAAC,QAAD;MAAM,eAAY;MAAO,WAAU;gBAAwB;KAErD,CAAA;KAER,oBAAC,aAAD,EAAa,SAAS,QAAU,CAAA;KAC/B,eACC,oBAAC,UAAD;MACE,MAAM,YAAY;MAClB,UAAU,YAAY;MACtB,WAAU;gBAET,YAAY;KACL,CAAA;IAET;;GAEJ;GAEA,cAAc,oBAAC,KAAD;IAAG,WAAU;cAA4B;GAAc,CAAA;GAEtE,oBAAC,YAAD,EAAY,SAAS,MAAQ,CAAA;EAC1B;;AAET"}
1
+ {"version":3,"file":"field.js","names":[],"sources":["../../../../resources/js/form/components/base/field.tsx"],"sourcesContent":["import InputError from \"@lattice-php/lattice/ui/input-error\";\nimport { InfoTooltip } from \"@lattice-php/lattice/ui/info-tooltip\";\nimport { TextLink } from \"@lattice-php/lattice/ui/link\";\nimport { Label } from \"@lattice-php/lattice/ui/label\";\nimport { useInTableCell } from \"@lattice-php/lattice/form/hooks/row-layout-context\";\nimport type { LabelAction } from \"@lattice-php/lattice/form/types\";\n\nexport function FormFieldFrame({\n children,\n error,\n helperText,\n label,\n labelAction,\n name,\n required,\n tooltip,\n}: {\n children: React.ReactNode;\n error?: string;\n helperText?: string;\n label: string;\n labelAction?: LabelAction;\n name: string;\n required?: boolean;\n tooltip?: string;\n}) {\n const bare = useInTableCell();\n\n if (bare) {\n return (\n <div className=\"grid gap-1\">\n <Label htmlFor={name} className=\"sr-only\">\n {label}\n </Label>\n {children}\n <InputError message={error} />\n </div>\n );\n }\n\n return (\n <div className=\"grid gap-2\">\n <div className=\"flex min-h-5 items-center\">\n <Label htmlFor={name}>{label}</Label>\n {required && (\n <span aria-hidden=\"true\" className=\"ml-0.5 text-lt-danger\">\n *\n </span>\n )}\n <InfoTooltip content={tooltip} />\n {labelAction && (\n <TextLink\n href={labelAction.href}\n tabIndex={labelAction.tabIndex ?? undefined}\n className=\"ml-auto text-sm\"\n >\n {labelAction.label}\n </TextLink>\n )}\n </div>\n\n {children}\n\n {helperText && <p className=\"text-sm text-lt-muted-fg\">{helperText}</p>}\n\n <InputError message={error} />\n </div>\n );\n}\n"],"mappings":";;;;;;;AAOA,SAAgB,eAAe,EAC7B,UACA,OACA,YACA,OACA,aACA,MACA,UACA,WAUC;CAGD,IAFa,eAET,GACF,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf;GACE,oBAAC,OAAD;IAAO,SAAS;IAAM,WAAU;cAC7B;GACI,CAAA;GACN;GACD,oBAAC,YAAD,EAAY,SAAS,MAAQ,CAAA;EAC1B;;CAIT,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf;GACE,qBAAC,OAAD;IAAK,WAAU;cAAf;KACE,oBAAC,OAAD;MAAO,SAAS;gBAAO;KAAa,CAAA;KACnC,YACC,oBAAC,QAAD;MAAM,eAAY;MAAO,WAAU;gBAAwB;KAErD,CAAA;KAER,oBAAC,aAAD,EAAa,SAAS,QAAU,CAAA;KAC/B,eACC,oBAAC,UAAD;MACE,MAAM,YAAY;MAClB,UAAU,YAAY,YAAY,KAAA;MAClC,WAAU;gBAET,YAAY;KACL,CAAA;IAET;;GAEJ;GAEA,cAAc,oBAAC,KAAD;IAAG,WAAU;cAA4B;GAAc,CAAA;GAEtE,oBAAC,YAAD,EAAY,SAAS,MAAQ,CAAA;EAC1B;;AAET"}
@@ -0,0 +1,2 @@
1
+ import { RendererComponent } from '../../../core/types.js';
2
+ export declare const ColorPickerFieldComponent: RendererComponent<"field.color-picker">;
@@ -0,0 +1,57 @@
1
+ import { cn } from "../../../lib/utils.js";
2
+ import { Popover, PopoverContent, PopoverTrigger } from "../../../ui/popover.js";
3
+ import { controlSurface } from "../../../ui/control.js";
4
+ import { ColorPicker, normalizeHex } from "../../../ui/color-picker.js";
5
+ import { SimpleField } from "./simple-field.js";
6
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
7
+ //#region resources/js/form/components/fields/color-picker-field.tsx
8
+ var ColorPickerFieldComponent = ({ node }) => {
9
+ const props = node.props;
10
+ return /* @__PURE__ */ jsx(SimpleField, {
11
+ node,
12
+ label: props.label ?? "",
13
+ children: ({ name, value, readOnly, disabled, commit }) => {
14
+ const hex = normalizeHex(value);
15
+ return /* @__PURE__ */ jsxs(Popover, { children: [
16
+ /* @__PURE__ */ jsx("input", {
17
+ name,
18
+ type: "hidden",
19
+ value: hex ?? ""
20
+ }),
21
+ /* @__PURE__ */ jsx(PopoverTrigger, {
22
+ asChild: true,
23
+ children: /* @__PURE__ */ jsx("button", {
24
+ className: cn(controlSurface(), "flex items-center gap-2 text-left"),
25
+ "data-test": `color-picker-${name}`,
26
+ disabled: disabled || readOnly,
27
+ id: name,
28
+ type: "button",
29
+ children: hex ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
30
+ "aria-hidden": "true",
31
+ className: "size-4 shrink-0 rounded-full border border-lt-border",
32
+ style: { background: hex }
33
+ }), /* @__PURE__ */ jsx("span", {
34
+ className: "tabular-nums",
35
+ children: hex
36
+ })] }) : /* @__PURE__ */ jsx("span", {
37
+ className: "text-lt-muted-fg",
38
+ children: props.placeholder ?? ""
39
+ })
40
+ })
41
+ }),
42
+ /* @__PURE__ */ jsx(PopoverContent, {
43
+ className: "p-3",
44
+ children: /* @__PURE__ */ jsx(ColorPicker, {
45
+ onChange: (next) => commit(next),
46
+ palette: props.palette,
47
+ value: hex ?? "#6b7280"
48
+ })
49
+ })
50
+ ] });
51
+ }
52
+ });
53
+ };
54
+ //#endregion
55
+ export { ColorPickerFieldComponent };
56
+
57
+ //# sourceMappingURL=color-picker-field.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"color-picker-field.js","names":[],"sources":["../../../../resources/js/form/components/fields/color-picker-field.tsx"],"sourcesContent":["import type { RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport { ColorPicker, normalizeHex } from \"@lattice-php/lattice/ui/color-picker\";\nimport { controlSurface } from \"@lattice-php/lattice/ui/control\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"@lattice-php/lattice/ui/popover\";\nimport { SimpleField } from \"./simple-field\";\n\nexport const ColorPickerFieldComponent: RendererComponent<\"field.color-picker\"> = ({ node }) => {\n const props = node.props;\n\n return (\n <SimpleField node={node} label={props.label ?? \"\"}>\n {({ name, value, readOnly, disabled, commit }) => {\n const hex = normalizeHex(value);\n\n return (\n <Popover>\n <input name={name} type=\"hidden\" value={hex ?? \"\"} />\n <PopoverTrigger asChild>\n <button\n className={cn(controlSurface(), \"flex items-center gap-2 text-left\")}\n data-test={`color-picker-${name}`}\n disabled={disabled || readOnly}\n id={name}\n type=\"button\"\n >\n {hex ? (\n <>\n <span\n aria-hidden=\"true\"\n className=\"size-4 shrink-0 rounded-full border border-lt-border\"\n style={{ background: hex }}\n />\n <span className=\"tabular-nums\">{hex}</span>\n </>\n ) : (\n <span className=\"text-lt-muted-fg\">{props.placeholder ?? \"\"}</span>\n )}\n </button>\n </PopoverTrigger>\n <PopoverContent className=\"p-3\">\n <ColorPicker\n onChange={(next) => commit(next)}\n palette={props.palette}\n value={hex ?? \"#6b7280\"}\n />\n </PopoverContent>\n </Popover>\n );\n }}\n </SimpleField>\n );\n};\n"],"mappings":";;;;;;;AAOA,IAAa,6BAAsE,EAAE,WAAW;CAC9F,MAAM,QAAQ,KAAK;CAEnB,OACE,oBAAC,aAAD;EAAmB;EAAM,OAAO,MAAM,SAAS;aAC3C,EAAE,MAAM,OAAO,UAAU,UAAU,aAAa;GAChD,MAAM,MAAM,aAAa,KAAK;GAE9B,OACE,qBAAC,SAAD,EAAA,UAAA;IACE,oBAAC,SAAD;KAAa;KAAM,MAAK;KAAS,OAAO,OAAO;IAAK,CAAA;IACpD,oBAAC,gBAAD;KAAgB,SAAA;eACd,oBAAC,UAAD;MACE,WAAW,GAAG,eAAe,GAAG,mCAAmC;MACnE,aAAW,gBAAgB;MAC3B,UAAU,YAAY;MACtB,IAAI;MACJ,MAAK;gBAEJ,MACC,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,QAAD;OACE,eAAY;OACZ,WAAU;OACV,OAAO,EAAE,YAAY,IAAI;MAC1B,CAAA,GACD,oBAAC,QAAD;OAAM,WAAU;iBAAgB;MAAU,CAAA,CAC1C,EAAA,CAAA,IAEF,oBAAC,QAAD;OAAM,WAAU;iBAAoB,MAAM,eAAe;MAAS,CAAA;KAE9D,CAAA;IACM,CAAA;IAChB,oBAAC,gBAAD;KAAgB,WAAU;eACxB,oBAAC,aAAD;MACE,WAAW,SAAS,OAAO,IAAI;MAC/B,SAAS,MAAM;MACf,OAAO,OAAO;KACf,CAAA;IACa,CAAA;GACT,EAAA,CAAA;EAEb;CACW,CAAA;AAEjB"}
@@ -1,5 +1,5 @@
1
- import { DatePicker } from "./date-picker.js";
2
1
  import { SimpleField } from "./simple-field.js";
2
+ import { DatePicker } from "./date-picker.js";
3
3
  import { jsx } from "react/jsx-runtime";
4
4
  //#region resources/js/form/components/fields/date-input.tsx
5
5
  var DateInputComponent = ({ node }) => {
@@ -1,6 +1,6 @@
1
1
  import { useTimezone } from "../../../i18n/timezone.js";
2
- import { DatePicker } from "./date-picker.js";
3
2
  import { SimpleField } from "./simple-field.js";
3
+ import { DatePicker } from "./date-picker.js";
4
4
  import { jsx } from "react/jsx-runtime";
5
5
  //#region resources/js/form/components/fields/date-time-input.tsx
6
6
  var DateTimeInputComponent = ({ node }) => {
@@ -1,4 +1,3 @@
1
- import { Icon } from "../../../icons/sprite.js";
2
1
  import { useT } from "../../../i18n/instance.js";
3
2
  import { testIdentity } from "../../../core/test-id.js";
4
3
  import { apiFetch } from "../../../core/api.js";
@@ -7,6 +6,7 @@ import { useFieldScope } from "../../hooks/field-scope.js";
7
6
  import { useFormValues, useSetFormValue } from "../../hooks/values.js";
8
7
  import { FormFieldFrame } from "../base/field.js";
9
8
  import { useDependentField } from "../../hooks/use-dependent-field.js";
9
+ import { IconButton } from "../../../ui/icon-button.js";
10
10
  import { useEffect, useId, useMemo, useRef, useState } from "react";
11
11
  import { jsx, jsxs } from "react/jsx-runtime";
12
12
  //#region resources/js/form/components/fields/file-upload.tsx
@@ -76,13 +76,13 @@ var FileUploadComponent = ({ node }) => {
76
76
  previewUrlsRef.current.forEach((url) => URL.revokeObjectURL(url));
77
77
  previewUrlsRef.current.clear();
78
78
  }, []);
79
- const multipartFiles = items.filter((item) => item.file && !item.existing).map((item) => item.file);
79
+ const multipartFiles = useMemo(() => items.filter((item) => item.file && !item.existing).map((item) => item.file), [items]);
80
80
  useEffect(() => {
81
81
  if (signed || !fileInputRef.current) return;
82
82
  const transfer = new DataTransfer();
83
83
  multipartFiles.forEach((file) => transfer.items.add(file));
84
84
  fileInputRef.current.files = transfer.files;
85
- });
85
+ }, [multipartFiles, signed]);
86
86
  function createPreviewUrl(file) {
87
87
  if (!props.image) return;
88
88
  const url = URL.createObjectURL(file);
@@ -116,7 +116,7 @@ var FileUploadComponent = ({ node }) => {
116
116
  const sign = await response.json();
117
117
  await new Promise((resolve) => {
118
118
  const request = new XMLHttpRequest();
119
- request.open(sign.method, sign.url, true);
119
+ request.open(sign.method.toUpperCase(), sign.url, true);
120
120
  Object.entries(sign.headers).forEach(([key, value]) => request.setRequestHeader(key, String(value)));
121
121
  request.upload.onprogress = (event) => {
122
122
  if (event.lengthComputable) {
@@ -172,10 +172,8 @@ var FileUploadComponent = ({ node }) => {
172
172
  function removeItem(id) {
173
173
  const target = items.find((item) => item.id === id);
174
174
  if (target) revokePreviewUrl(target);
175
- setItems((prev) => {
176
- if (target?.existing && target.token && !scope) setRemovedTokens((tokens) => [...tokens, target.token]);
177
- return prev.filter((i) => i.id !== id);
178
- });
175
+ if (target?.existing && target.token && !scope) setRemovedTokens((tokens) => [...tokens, target.token]);
176
+ setItems((prev) => prev.filter((i) => i.id !== id));
179
177
  }
180
178
  if (hidden) return null;
181
179
  return /* @__PURE__ */ jsx(FormFieldFrame, {
@@ -230,18 +228,13 @@ var FileUploadComponent = ({ node }) => {
230
228
  })
231
229
  ]
232
230
  }),
233
- (!item.existing || !scope) && /* @__PURE__ */ jsx("button", {
234
- "aria-label": t("form.file-upload.remove", "Remove {{name}}", { name: item.name }),
235
- className: "inline-flex size-7 shrink-0 items-center justify-center rounded-lt-sm text-lt-muted-fg transition-colors hover:bg-lt-accent hover:text-lt-accent-fg disabled:pointer-events-none disabled:opacity-50",
231
+ (!item.existing || !scope) && /* @__PURE__ */ jsx(IconButton, {
232
+ size: "sm",
233
+ icon: "x",
234
+ label: t("form.file-upload.remove", "Remove {{name}}", { name: item.name }),
236
235
  "data-test": testIdentity(item.existing ? `${name}-remove-existing` : `${name}-remove`),
237
236
  disabled: locked,
238
- onClick: () => removeItem(item.id),
239
- type: "button",
240
- children: /* @__PURE__ */ jsx(Icon, {
241
- name: "x",
242
- "aria-hidden": "true",
243
- className: "size-lt-icon-sm"
244
- })
237
+ onClick: () => removeItem(item.id)
245
238
  }),
246
239
  signed && !item.existing && item.key && item.status === "ready" && /* @__PURE__ */ jsx("input", {
247
240
  "data-test": testIdentity(`${name}-uploaded`),
@@ -1 +1 @@
1
- {"version":3,"file":"file-upload.js","names":[],"sources":["../../../../resources/js/form/components/fields/file-upload.tsx"],"sourcesContent":["import { apiFetch } from \"@lattice-php/lattice/core/api\";\nimport { testIdentity } from \"@lattice-php/lattice/core/test-id\";\nimport type { RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { Icon } from \"@lattice-php/lattice/icons\";\nimport { useT } from \"@lattice-php/lattice/i18n\";\nimport { useEffect, useId, useMemo, useRef, useState } from \"react\";\nimport { FormFieldFrame } from \"@lattice-php/lattice/form/components/base/field\";\nimport { useFormContext } from \"@lattice-php/lattice/form/hooks/context\";\nimport { useDependentField } from \"@lattice-php/lattice/form/hooks/use-dependent-field\";\nimport { useFieldScope } from \"@lattice-php/lattice/form/hooks/field-scope\";\nimport { useFormValues, useSetFormValue } from \"@lattice-php/lattice/form/hooks/values\";\n\ntype Item = {\n id: string;\n name: string;\n size: number | null;\n status: \"ready\" | \"uploading\" | \"error\";\n progress: number;\n file?: File;\n key?: string;\n url?: string | null;\n token?: string;\n existing: boolean;\n};\n\ntype SignResponse = {\n key: string;\n url: string;\n headers: Record<string, string>;\n method: string;\n};\n\nfunction uploadValueEquals(current: unknown, next: string[] | string): boolean {\n if (Array.isArray(next)) {\n return (\n Array.isArray(current) &&\n current.length === next.length &&\n current.every((value, index) => value === next[index])\n );\n }\n\n return current === next;\n}\n\nexport const FileUploadComponent: RendererComponent<\"field.file-upload\"> = ({ node }) => {\n const { t } = useT(\"lattice\");\n const props = node.props;\n const { hidden, required, readOnly, disabled } = useDependentField(node);\n const { action, componentRef, errors } = useFormContext();\n const name = props.name;\n const scope = useFieldScope();\n const domName = scope ? scope.scopedName(name) : name;\n const errorKey = scope ? scope.errorKey(name) : name;\n const uploadKey = errorKey;\n const values = useFormValues();\n const setValue = useSetFormValue();\n const inputId = useId();\n const fileInputRef = useRef<HTMLInputElement>(null);\n const previewUrlsRef = useRef<Set<string>>(new Set());\n const locked = readOnly || disabled;\n const signed = props.signed;\n const multiple = props.multiple;\n const fieldName = multiple ? `${domName}[]` : domName;\n\n const initial = useMemo<Item[]>(\n () =>\n (props.files ?? []).map((file) => ({\n id: crypto.randomUUID(),\n name: file.name,\n size: file.size,\n status: \"ready\" as const,\n progress: 100,\n key: file.key,\n url: file.url,\n token: file.token,\n existing: true,\n })),\n [props.files],\n );\n const [items, setItems] = useState<Item[]>(initial);\n const [removedTokens, setRemovedTokens] = useState<string[]>([]);\n\n useEffect(() => {\n if (!signed) {\n return;\n }\n\n const keys = items\n .filter((item) => !item.existing && item.key && item.status === \"ready\")\n .map((item) => item.key as string);\n const next = multiple ? keys : (keys[0] ?? \"\");\n\n if (scope) {\n if (!uploadValueEquals(scope.getValue(name), next)) {\n scope.setValue(name, next);\n }\n\n return;\n }\n\n setValue(name, next);\n }, [items, multiple, name, scope, setValue, signed]);\n\n useEffect(() => {\n if (!signed || scope) {\n return;\n }\n\n setValue(`${name}__removed`, removedTokens);\n }, [name, removedTokens, scope, setValue, signed]);\n\n useEffect(\n () => () => {\n previewUrlsRef.current.forEach((url) => URL.revokeObjectURL(url));\n previewUrlsRef.current.clear();\n },\n [],\n );\n\n const multipartFiles = items\n .filter((item) => item.file && !item.existing)\n .map((item) => item.file as File);\n useEffect(() => {\n if (signed || !fileInputRef.current) {\n return;\n }\n\n const transfer = new DataTransfer();\n multipartFiles.forEach((file) => transfer.items.add(file));\n fileInputRef.current.files = transfer.files;\n });\n\n function createPreviewUrl(file: File): string | undefined {\n if (!props.image) {\n return undefined;\n }\n\n const url = URL.createObjectURL(file);\n previewUrlsRef.current.add(url);\n\n return url;\n }\n\n function revokePreviewUrl(item: Item): void {\n if (!item.url || !previewUrlsRef.current.has(item.url)) {\n return;\n }\n\n URL.revokeObjectURL(item.url);\n previewUrlsRef.current.delete(item.url);\n }\n\n async function signAndUpload(item: Item, file: File): Promise<void> {\n const response = await apiFetch(action, {\n method: \"POST\",\n ref: componentRef,\n body: JSON.stringify({\n ...values,\n _upload: uploadKey,\n filename: file.name,\n contentType: file.type,\n }),\n throwOnError: false,\n });\n\n if (!response.ok) {\n setItems((prev) =>\n prev.map((entry) => (entry.id === item.id ? { ...entry, status: \"error\" } : entry)),\n );\n\n return;\n }\n\n const sign = (await response.json()) as SignResponse;\n\n await new Promise<void>((resolve) => {\n const request = new XMLHttpRequest();\n request.open(sign.method, sign.url, true);\n Object.entries(sign.headers).forEach(([key, value]) =>\n request.setRequestHeader(key, String(value)),\n );\n request.upload.onprogress = (event) => {\n if (event.lengthComputable) {\n const progress = Math.round((event.loaded / event.total) * 100);\n setItems((prev) =>\n prev.map((entry) => (entry.id === item.id ? { ...entry, progress } : entry)),\n );\n }\n };\n request.onload = () => {\n setItems((prev) =>\n prev.map((entry) =>\n entry.id === item.id\n ? {\n ...entry,\n status: request.status < 300 ? \"ready\" : \"error\",\n key: sign.key,\n progress: 100,\n }\n : entry,\n ),\n );\n resolve();\n };\n request.onerror = () => {\n setItems((prev) =>\n prev.map((entry) => (entry.id === item.id ? { ...entry, status: \"error\" } : entry)),\n );\n resolve();\n };\n request.send(file);\n });\n }\n\n function addFiles(fileList: FileList | null): void {\n if (!fileList || locked) {\n return;\n }\n\n const incoming = Array.from(fileList);\n const next = incoming.map<Item>((file) => ({\n id: crypto.randomUUID(),\n name: file.name,\n size: file.size,\n status: signed ? \"uploading\" : \"ready\",\n progress: 0,\n file,\n url: createPreviewUrl(file),\n existing: false,\n }));\n\n if (!multiple) {\n items.forEach(revokePreviewUrl);\n\n if (!scope) {\n const replacedTokens = items\n .filter((item) => item.existing && item.token)\n .map((item) => item.token as string);\n\n if (replacedTokens.length > 0) {\n setRemovedTokens((tokens) => [...tokens, ...replacedTokens]);\n }\n }\n }\n\n setItems((prev) => (multiple ? [...prev, ...next] : next));\n\n if (signed) {\n next.forEach((item, index) => void signAndUpload(item, incoming[index]));\n }\n }\n\n function removeItem(id: string): void {\n const target = items.find((item) => item.id === id);\n\n if (target) {\n revokePreviewUrl(target);\n }\n\n setItems((prev) => {\n if (target?.existing && target.token && !scope) {\n setRemovedTokens((tokens) => [...tokens, target.token as string]);\n }\n return prev.filter((i) => i.id !== id);\n });\n }\n\n if (hidden) {\n return null;\n }\n\n return (\n <FormFieldFrame\n error={errors[errorKey]}\n helperText={props.helperText ?? undefined}\n tooltip={props.tooltip ?? undefined}\n label={props.label ?? \"\"}\n name={name}\n required={required}\n >\n <div\n className=\"flex flex-col gap-3 rounded-lt-sm border border-dashed border-lt-border bg-lt-surface px-4 py-6\"\n data-test={testIdentity(name)}\n onDragOver={(event) => event.preventDefault()}\n onDrop={(event) => {\n event.preventDefault();\n addFiles(event.dataTransfer.files);\n }}\n >\n <button\n className=\"text-sm text-lt-muted-fg\"\n disabled={locked}\n onClick={() => fileInputRef.current?.click()}\n type=\"button\"\n >\n {t(\"form.file-upload.dropzone\", \"Drop files here or click to browse\")}\n </button>\n\n <ul\n className={props.image ? \"grid grid-cols-1 gap-3 sm:grid-cols-2\" : \"flex flex-col gap-2\"}\n >\n {items.map((item) => (\n <li\n className={\n props.image\n ? \"flex min-w-0 items-center gap-3 rounded-lt-sm border border-lt-border bg-lt-bg p-2 text-sm\"\n : \"flex items-center justify-between gap-3 text-sm\"\n }\n key={item.id}\n >\n {props.image && item.url ? (\n <img\n alt={item.name}\n className=\"size-16 shrink-0 rounded-lt-sm border border-lt-border object-cover\"\n data-test={testIdentity(`${name}-preview`)}\n src={item.url}\n />\n ) : null}\n <div className=\"min-w-0 flex-1\">\n <span className=\"block truncate\" data-test={testIdentity(`${name}-item`)}>\n {item.name}\n </span>\n {item.status === \"uploading\" && (\n <span className=\"text-xs text-lt-muted-fg\">{item.progress}%</span>\n )}\n {item.status === \"error\" && (\n <span className=\"text-xs text-lt-danger\">\n {t(\"form.file-upload.failed\", \"Failed\")}\n </span>\n )}\n </div>\n {(!item.existing || !scope) && (\n <button\n aria-label={t(\"form.file-upload.remove\", \"Remove {{name}}\", { name: item.name })}\n className=\"inline-flex size-7 shrink-0 items-center justify-center rounded-lt-sm text-lt-muted-fg transition-colors hover:bg-lt-accent hover:text-lt-accent-fg disabled:pointer-events-none disabled:opacity-50\"\n data-test={testIdentity(\n item.existing ? `${name}-remove-existing` : `${name}-remove`,\n )}\n disabled={locked}\n onClick={() => removeItem(item.id)}\n type=\"button\"\n >\n <Icon name=\"x\" aria-hidden=\"true\" className=\"size-lt-icon-sm\" />\n </button>\n )}\n {signed && !item.existing && item.key && item.status === \"ready\" && (\n <input\n data-test={testIdentity(`${name}-uploaded`)}\n name={fieldName}\n type=\"hidden\"\n value={item.key}\n />\n )}\n </li>\n ))}\n </ul>\n\n {!scope &&\n removedTokens.map((token) => (\n <input key={token} name={`${name}__removed[]`} type=\"hidden\" value={token} />\n ))}\n\n <input\n accept={props.accept ?? undefined}\n aria-label={props.label ?? name}\n className=\"sr-only\"\n data-test={testIdentity(`${name}-input`)}\n id={inputId}\n multiple={multiple}\n name={signed ? undefined : fieldName}\n onChange={(event) => {\n addFiles(event.target.files);\n if (signed) {\n event.target.value = \"\";\n }\n }}\n ref={fileInputRef}\n type=\"file\"\n />\n </div>\n </FormFieldFrame>\n );\n};\n"],"mappings":";;;;;;;;;;;;AAgCA,SAAS,kBAAkB,SAAkB,MAAkC;CAC7E,IAAI,MAAM,QAAQ,IAAI,GACpB,OACE,MAAM,QAAQ,OAAO,KACrB,QAAQ,WAAW,KAAK,UACxB,QAAQ,OAAO,OAAO,UAAU,UAAU,KAAK,MAAM;CAIzD,OAAO,YAAY;AACrB;AAEA,IAAa,uBAA+D,EAAE,WAAW;CACvF,MAAM,EAAE,MAAM,KAAK,SAAS;CAC5B,MAAM,QAAQ,KAAK;CACnB,MAAM,EAAE,QAAQ,UAAU,UAAU,aAAa,kBAAkB,IAAI;CACvE,MAAM,EAAE,QAAQ,cAAc,WAAW,eAAe;CACxD,MAAM,OAAO,MAAM;CACnB,MAAM,QAAQ,cAAc;CAC5B,MAAM,UAAU,QAAQ,MAAM,WAAW,IAAI,IAAI;CACjD,MAAM,WAAW,QAAQ,MAAM,SAAS,IAAI,IAAI;CAChD,MAAM,YAAY;CAClB,MAAM,SAAS,cAAc;CAC7B,MAAM,WAAW,gBAAgB;CACjC,MAAM,UAAU,MAAM;CACtB,MAAM,eAAe,OAAyB,IAAI;CAClD,MAAM,iBAAiB,uBAAoB,IAAI,IAAI,CAAC;CACpD,MAAM,SAAS,YAAY;CAC3B,MAAM,SAAS,MAAM;CACrB,MAAM,WAAW,MAAM;CACvB,MAAM,YAAY,WAAW,GAAG,QAAQ,MAAM;CAiB9C,MAAM,CAAC,OAAO,YAAY,SAfV,eAEX,MAAM,SAAS,CAAC,GAAG,KAAK,UAAU;EACjC,IAAI,OAAO,WAAW;EACtB,MAAM,KAAK;EACX,MAAM,KAAK;EACX,QAAQ;EACR,UAAU;EACV,KAAK,KAAK;EACV,KAAK,KAAK;EACV,OAAO,KAAK;EACZ,UAAU;CACZ,EAAE,GACJ,CAAC,MAAM,KAAK,CAE6B,CAAO;CAClD,MAAM,CAAC,eAAe,oBAAoB,SAAmB,CAAC,CAAC;CAE/D,gBAAgB;EACd,IAAI,CAAC,QACH;EAGF,MAAM,OAAO,MACV,QAAQ,SAAS,CAAC,KAAK,YAAY,KAAK,OAAO,KAAK,WAAW,OAAO,EACtE,KAAK,SAAS,KAAK,GAAa;EACnC,MAAM,OAAO,WAAW,OAAQ,KAAK,MAAM;EAE3C,IAAI,OAAO;GACT,IAAI,CAAC,kBAAkB,MAAM,SAAS,IAAI,GAAG,IAAI,GAC/C,MAAM,SAAS,MAAM,IAAI;GAG3B;EACF;EAEA,SAAS,MAAM,IAAI;CACrB,GAAG;EAAC;EAAO;EAAU;EAAM;EAAO;EAAU;CAAM,CAAC;CAEnD,gBAAgB;EACd,IAAI,CAAC,UAAU,OACb;EAGF,SAAS,GAAG,KAAK,YAAY,aAAa;CAC5C,GAAG;EAAC;EAAM;EAAe;EAAO;EAAU;CAAM,CAAC;CAEjD,sBACc;EACV,eAAe,QAAQ,SAAS,QAAQ,IAAI,gBAAgB,GAAG,CAAC;EAChE,eAAe,QAAQ,MAAM;CAC/B,GACA,CAAC,CACH;CAEA,MAAM,iBAAiB,MACpB,QAAQ,SAAS,KAAK,QAAQ,CAAC,KAAK,QAAQ,EAC5C,KAAK,SAAS,KAAK,IAAY;CAClC,gBAAgB;EACd,IAAI,UAAU,CAAC,aAAa,SAC1B;EAGF,MAAM,WAAW,IAAI,aAAa;EAClC,eAAe,SAAS,SAAS,SAAS,MAAM,IAAI,IAAI,CAAC;EACzD,aAAa,QAAQ,QAAQ,SAAS;CACxC,CAAC;CAED,SAAS,iBAAiB,MAAgC;EACxD,IAAI,CAAC,MAAM,OACT;EAGF,MAAM,MAAM,IAAI,gBAAgB,IAAI;EACpC,eAAe,QAAQ,IAAI,GAAG;EAE9B,OAAO;CACT;CAEA,SAAS,iBAAiB,MAAkB;EAC1C,IAAI,CAAC,KAAK,OAAO,CAAC,eAAe,QAAQ,IAAI,KAAK,GAAG,GACnD;EAGF,IAAI,gBAAgB,KAAK,GAAG;EAC5B,eAAe,QAAQ,OAAO,KAAK,GAAG;CACxC;CAEA,eAAe,cAAc,MAAY,MAA2B;EAClE,MAAM,WAAW,MAAM,SAAS,QAAQ;GACtC,QAAQ;GACR,KAAK;GACL,MAAM,KAAK,UAAU;IACnB,GAAG;IACH,SAAS;IACT,UAAU,KAAK;IACf,aAAa,KAAK;GACpB,CAAC;GACD,cAAc;EAChB,CAAC;EAED,IAAI,CAAC,SAAS,IAAI;GAChB,UAAU,SACR,KAAK,KAAK,UAAW,MAAM,OAAO,KAAK,KAAK;IAAE,GAAG;IAAO,QAAQ;GAAQ,IAAI,KAAM,CACpF;GAEA;EACF;EAEA,MAAM,OAAQ,MAAM,SAAS,KAAK;EAElC,MAAM,IAAI,SAAe,YAAY;GACnC,MAAM,UAAU,IAAI,eAAe;GACnC,QAAQ,KAAK,KAAK,QAAQ,KAAK,KAAK,IAAI;GACxC,OAAO,QAAQ,KAAK,OAAO,EAAE,SAAS,CAAC,KAAK,WAC1C,QAAQ,iBAAiB,KAAK,OAAO,KAAK,CAAC,CAC7C;GACA,QAAQ,OAAO,cAAc,UAAU;IACrC,IAAI,MAAM,kBAAkB;KAC1B,MAAM,WAAW,KAAK,MAAO,MAAM,SAAS,MAAM,QAAS,GAAG;KAC9D,UAAU,SACR,KAAK,KAAK,UAAW,MAAM,OAAO,KAAK,KAAK;MAAE,GAAG;MAAO;KAAS,IAAI,KAAM,CAC7E;IACF;GACF;GACA,QAAQ,eAAe;IACrB,UAAU,SACR,KAAK,KAAK,UACR,MAAM,OAAO,KAAK,KACd;KACE,GAAG;KACH,QAAQ,QAAQ,SAAS,MAAM,UAAU;KACzC,KAAK,KAAK;KACV,UAAU;IACZ,IACA,KACN,CACF;IACA,QAAQ;GACV;GACA,QAAQ,gBAAgB;IACtB,UAAU,SACR,KAAK,KAAK,UAAW,MAAM,OAAO,KAAK,KAAK;KAAE,GAAG;KAAO,QAAQ;IAAQ,IAAI,KAAM,CACpF;IACA,QAAQ;GACV;GACA,QAAQ,KAAK,IAAI;EACnB,CAAC;CACH;CAEA,SAAS,SAAS,UAAiC;EACjD,IAAI,CAAC,YAAY,QACf;EAGF,MAAM,WAAW,MAAM,KAAK,QAAQ;EACpC,MAAM,OAAO,SAAS,KAAW,UAAU;GACzC,IAAI,OAAO,WAAW;GACtB,MAAM,KAAK;GACX,MAAM,KAAK;GACX,QAAQ,SAAS,cAAc;GAC/B,UAAU;GACV;GACA,KAAK,iBAAiB,IAAI;GAC1B,UAAU;EACZ,EAAE;EAEF,IAAI,CAAC,UAAU;GACb,MAAM,QAAQ,gBAAgB;GAE9B,IAAI,CAAC,OAAO;IACV,MAAM,iBAAiB,MACpB,QAAQ,SAAS,KAAK,YAAY,KAAK,KAAK,EAC5C,KAAK,SAAS,KAAK,KAAe;IAErC,IAAI,eAAe,SAAS,GAC1B,kBAAkB,WAAW,CAAC,GAAG,QAAQ,GAAG,cAAc,CAAC;GAE/D;EACF;EAEA,UAAU,SAAU,WAAW,CAAC,GAAG,MAAM,GAAG,IAAI,IAAI,IAAK;EAEzD,IAAI,QACF,KAAK,SAAS,MAAM,UAAU,KAAK,cAAc,MAAM,SAAS,MAAM,CAAC;CAE3E;CAEA,SAAS,WAAW,IAAkB;EACpC,MAAM,SAAS,MAAM,MAAM,SAAS,KAAK,OAAO,EAAE;EAElD,IAAI,QACF,iBAAiB,MAAM;EAGzB,UAAU,SAAS;GACjB,IAAI,QAAQ,YAAY,OAAO,SAAS,CAAC,OACvC,kBAAkB,WAAW,CAAC,GAAG,QAAQ,OAAO,KAAe,CAAC;GAElE,OAAO,KAAK,QAAQ,MAAM,EAAE,OAAO,EAAE;EACvC,CAAC;CACH;CAEA,IAAI,QACF,OAAO;CAGT,OACE,oBAAC,gBAAD;EACE,OAAO,OAAO;EACd,YAAY,MAAM,cAAc,KAAA;EAChC,SAAS,MAAM,WAAW,KAAA;EAC1B,OAAO,MAAM,SAAS;EAChB;EACI;YAEV,qBAAC,OAAD;GACE,WAAU;GACV,aAAW,aAAa,IAAI;GAC5B,aAAa,UAAU,MAAM,eAAe;GAC5C,SAAS,UAAU;IACjB,MAAM,eAAe;IACrB,SAAS,MAAM,aAAa,KAAK;GACnC;aAPF;IASE,oBAAC,UAAD;KACE,WAAU;KACV,UAAU;KACV,eAAe,aAAa,SAAS,MAAM;KAC3C,MAAK;eAEJ,EAAE,6BAA6B,oCAAoC;IAC9D,CAAA;IAER,oBAAC,MAAD;KACE,WAAW,MAAM,QAAQ,0CAA0C;eAElE,MAAM,KAAK,SACV,qBAAC,MAAD;MACE,WACE,MAAM,QACF,+FACA;gBAJR;OAQG,MAAM,SAAS,KAAK,MACnB,oBAAC,OAAD;QACE,KAAK,KAAK;QACV,WAAU;QACV,aAAW,aAAa,GAAG,KAAK,SAAS;QACzC,KAAK,KAAK;OACX,CAAA,IACC;OACJ,qBAAC,OAAD;QAAK,WAAU;kBAAf;SACE,oBAAC,QAAD;UAAM,WAAU;UAAiB,aAAW,aAAa,GAAG,KAAK,MAAM;oBACpE,KAAK;SACF,CAAA;SACL,KAAK,WAAW,eACf,qBAAC,QAAD;UAAM,WAAU;oBAAhB,CAA4C,KAAK,UAAS,GAAO;;SAElE,KAAK,WAAW,WACf,oBAAC,QAAD;UAAM,WAAU;oBACb,EAAE,2BAA2B,QAAQ;SAClC,CAAA;QAEL;;QACH,CAAC,KAAK,YAAY,CAAC,UACnB,oBAAC,UAAD;QACE,cAAY,EAAE,2BAA2B,mBAAmB,EAAE,MAAM,KAAK,KAAK,CAAC;QAC/E,WAAU;QACV,aAAW,aACT,KAAK,WAAW,GAAG,KAAK,oBAAoB,GAAG,KAAK,QACtD;QACA,UAAU;QACV,eAAe,WAAW,KAAK,EAAE;QACjC,MAAK;kBAEL,oBAAC,MAAD;SAAM,MAAK;SAAI,eAAY;SAAO,WAAU;QAAmB,CAAA;OACzD,CAAA;OAET,UAAU,CAAC,KAAK,YAAY,KAAK,OAAO,KAAK,WAAW,WACvD,oBAAC,SAAD;QACE,aAAW,aAAa,GAAG,KAAK,UAAU;QAC1C,MAAM;QACN,MAAK;QACL,OAAO,KAAK;OACb,CAAA;MAED;QA7CG,KAAK,EA6CR,CACL;IACC,CAAA;IAEH,CAAC,SACA,cAAc,KAAK,UACjB,oBAAC,SAAD;KAAmB,MAAM,GAAG,KAAK;KAAc,MAAK;KAAS,OAAO;IAAQ,GAAhE,KAAgE,CAC7E;IAEH,oBAAC,SAAD;KACE,QAAQ,MAAM,UAAU,KAAA;KACxB,cAAY,MAAM,SAAS;KAC3B,WAAU;KACV,aAAW,aAAa,GAAG,KAAK,OAAO;KACvC,IAAI;KACM;KACV,MAAM,SAAS,KAAA,IAAY;KAC3B,WAAW,UAAU;MACnB,SAAS,MAAM,OAAO,KAAK;MAC3B,IAAI,QACF,MAAM,OAAO,QAAQ;KAEzB;KACA,KAAK;KACL,MAAK;IACN,CAAA;GACE;;CACS,CAAA;AAEpB"}
1
+ {"version":3,"file":"file-upload.js","names":[],"sources":["../../../../resources/js/form/components/fields/file-upload.tsx"],"sourcesContent":["import { apiFetch } from \"@lattice-php/lattice/core/api\";\nimport { testIdentity } from \"@lattice-php/lattice/core/test-id\";\nimport type { RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport type { SignedUpload } from \"@lattice-php/lattice/types/generated\";\nimport { IconButton } from \"@lattice-php/lattice/ui/icon-button\";\nimport { useT } from \"@lattice-php/lattice/i18n\";\nimport { useEffect, useId, useMemo, useRef, useState } from \"react\";\nimport { FormFieldFrame } from \"@lattice-php/lattice/form/components/base/field\";\nimport { useFormContext } from \"@lattice-php/lattice/form/hooks/context\";\nimport { useDependentField } from \"@lattice-php/lattice/form/hooks/use-dependent-field\";\nimport { useFieldScope } from \"@lattice-php/lattice/form/hooks/field-scope\";\nimport { useFormValues, useSetFormValue } from \"@lattice-php/lattice/form/hooks/values\";\n\ntype Item = {\n id: string;\n name: string;\n size: number | null;\n status: \"ready\" | \"uploading\" | \"error\";\n progress: number;\n file?: File;\n key?: string;\n url?: string | null;\n token?: string;\n existing: boolean;\n};\n\nfunction uploadValueEquals(current: unknown, next: string[] | string): boolean {\n if (Array.isArray(next)) {\n return (\n Array.isArray(current) &&\n current.length === next.length &&\n current.every((value, index) => value === next[index])\n );\n }\n\n return current === next;\n}\n\nexport const FileUploadComponent: RendererComponent<\"field.file-upload\"> = ({ node }) => {\n const { t } = useT(\"lattice\");\n const props = node.props;\n const { hidden, required, readOnly, disabled } = useDependentField(node);\n const { action, componentRef, errors } = useFormContext();\n const name = props.name;\n const scope = useFieldScope();\n const domName = scope ? scope.scopedName(name) : name;\n const errorKey = scope ? scope.errorKey(name) : name;\n const uploadKey = errorKey;\n const values = useFormValues();\n const setValue = useSetFormValue();\n const inputId = useId();\n const fileInputRef = useRef<HTMLInputElement>(null);\n const previewUrlsRef = useRef<Set<string>>(new Set());\n const locked = readOnly || disabled;\n const signed = props.signed;\n const multiple = props.multiple;\n const fieldName = multiple ? `${domName}[]` : domName;\n\n const initial = useMemo<Item[]>(\n () =>\n (props.files ?? []).map((file) => ({\n id: crypto.randomUUID(),\n name: file.name,\n size: file.size,\n status: \"ready\" as const,\n progress: 100,\n key: file.key,\n url: file.url,\n token: file.token,\n existing: true,\n })),\n [props.files],\n );\n const [items, setItems] = useState<Item[]>(initial);\n const [removedTokens, setRemovedTokens] = useState<string[]>([]);\n\n useEffect(() => {\n if (!signed) {\n return;\n }\n\n const keys = items\n .filter((item) => !item.existing && item.key && item.status === \"ready\")\n .map((item) => item.key as string);\n const next = multiple ? keys : (keys[0] ?? \"\");\n\n if (scope) {\n if (!uploadValueEquals(scope.getValue(name), next)) {\n scope.setValue(name, next);\n }\n\n return;\n }\n\n setValue(name, next);\n }, [items, multiple, name, scope, setValue, signed]);\n\n useEffect(() => {\n if (!signed || scope) {\n return;\n }\n\n setValue(`${name}__removed`, removedTokens);\n }, [name, removedTokens, scope, setValue, signed]);\n\n useEffect(\n () => () => {\n previewUrlsRef.current.forEach((url) => URL.revokeObjectURL(url));\n previewUrlsRef.current.clear();\n },\n [],\n );\n\n const multipartFiles = useMemo(\n () => items.filter((item) => item.file && !item.existing).map((item) => item.file as File),\n [items],\n );\n useEffect(() => {\n if (signed || !fileInputRef.current) {\n return;\n }\n\n const transfer = new DataTransfer();\n multipartFiles.forEach((file) => transfer.items.add(file));\n fileInputRef.current.files = transfer.files;\n }, [multipartFiles, signed]);\n\n function createPreviewUrl(file: File): string | undefined {\n if (!props.image) {\n return undefined;\n }\n\n const url = URL.createObjectURL(file);\n previewUrlsRef.current.add(url);\n\n return url;\n }\n\n function revokePreviewUrl(item: Item): void {\n if (!item.url || !previewUrlsRef.current.has(item.url)) {\n return;\n }\n\n URL.revokeObjectURL(item.url);\n previewUrlsRef.current.delete(item.url);\n }\n\n async function signAndUpload(item: Item, file: File): Promise<void> {\n const response = await apiFetch(action, {\n method: \"POST\",\n ref: componentRef,\n body: JSON.stringify({\n ...values,\n _upload: uploadKey,\n filename: file.name,\n contentType: file.type,\n }),\n throwOnError: false,\n });\n\n if (!response.ok) {\n setItems((prev) =>\n prev.map((entry) => (entry.id === item.id ? { ...entry, status: \"error\" } : entry)),\n );\n\n return;\n }\n\n const sign = (await response.json()) as SignedUpload;\n\n await new Promise<void>((resolve) => {\n const request = new XMLHttpRequest();\n request.open(sign.method.toUpperCase(), sign.url, true);\n Object.entries(sign.headers).forEach(([key, value]) =>\n request.setRequestHeader(key, String(value)),\n );\n request.upload.onprogress = (event) => {\n if (event.lengthComputable) {\n const progress = Math.round((event.loaded / event.total) * 100);\n setItems((prev) =>\n prev.map((entry) => (entry.id === item.id ? { ...entry, progress } : entry)),\n );\n }\n };\n request.onload = () => {\n setItems((prev) =>\n prev.map((entry) =>\n entry.id === item.id\n ? {\n ...entry,\n status: request.status < 300 ? \"ready\" : \"error\",\n key: sign.key,\n progress: 100,\n }\n : entry,\n ),\n );\n resolve();\n };\n request.onerror = () => {\n setItems((prev) =>\n prev.map((entry) => (entry.id === item.id ? { ...entry, status: \"error\" } : entry)),\n );\n resolve();\n };\n request.send(file);\n });\n }\n\n function addFiles(fileList: FileList | null): void {\n if (!fileList || locked) {\n return;\n }\n\n const incoming = Array.from(fileList);\n const next = incoming.map<Item>((file) => ({\n id: crypto.randomUUID(),\n name: file.name,\n size: file.size,\n status: signed ? \"uploading\" : \"ready\",\n progress: 0,\n file,\n url: createPreviewUrl(file),\n existing: false,\n }));\n\n if (!multiple) {\n items.forEach(revokePreviewUrl);\n\n if (!scope) {\n const replacedTokens = items\n .filter((item) => item.existing && item.token)\n .map((item) => item.token as string);\n\n if (replacedTokens.length > 0) {\n setRemovedTokens((tokens) => [...tokens, ...replacedTokens]);\n }\n }\n }\n\n setItems((prev) => (multiple ? [...prev, ...next] : next));\n\n if (signed) {\n next.forEach((item, index) => void signAndUpload(item, incoming[index]));\n }\n }\n\n function removeItem(id: string): void {\n const target = items.find((item) => item.id === id);\n\n if (target) {\n revokePreviewUrl(target);\n }\n\n if (target?.existing && target.token && !scope) {\n setRemovedTokens((tokens) => [...tokens, target.token as string]);\n }\n\n setItems((prev) => prev.filter((i) => i.id !== id));\n }\n\n if (hidden) {\n return null;\n }\n\n return (\n <FormFieldFrame\n error={errors[errorKey]}\n helperText={props.helperText ?? undefined}\n tooltip={props.tooltip ?? undefined}\n label={props.label ?? \"\"}\n name={name}\n required={required}\n >\n <div\n className=\"flex flex-col gap-3 rounded-lt-sm border border-dashed border-lt-border bg-lt-surface px-4 py-6\"\n data-test={testIdentity(name)}\n onDragOver={(event) => event.preventDefault()}\n onDrop={(event) => {\n event.preventDefault();\n addFiles(event.dataTransfer.files);\n }}\n >\n <button\n className=\"text-sm text-lt-muted-fg\"\n disabled={locked}\n onClick={() => fileInputRef.current?.click()}\n type=\"button\"\n >\n {t(\"form.file-upload.dropzone\", \"Drop files here or click to browse\")}\n </button>\n\n <ul\n className={props.image ? \"grid grid-cols-1 gap-3 sm:grid-cols-2\" : \"flex flex-col gap-2\"}\n >\n {items.map((item) => (\n <li\n className={\n props.image\n ? \"flex min-w-0 items-center gap-3 rounded-lt-sm border border-lt-border bg-lt-bg p-2 text-sm\"\n : \"flex items-center justify-between gap-3 text-sm\"\n }\n key={item.id}\n >\n {props.image && item.url ? (\n <img\n alt={item.name}\n className=\"size-16 shrink-0 rounded-lt-sm border border-lt-border object-cover\"\n data-test={testIdentity(`${name}-preview`)}\n src={item.url}\n />\n ) : null}\n <div className=\"min-w-0 flex-1\">\n <span className=\"block truncate\" data-test={testIdentity(`${name}-item`)}>\n {item.name}\n </span>\n {item.status === \"uploading\" && (\n <span className=\"text-xs text-lt-muted-fg\">{item.progress}%</span>\n )}\n {item.status === \"error\" && (\n <span className=\"text-xs text-lt-danger\">\n {t(\"form.file-upload.failed\", \"Failed\")}\n </span>\n )}\n </div>\n {(!item.existing || !scope) && (\n <IconButton\n size=\"sm\"\n icon=\"x\"\n label={t(\"form.file-upload.remove\", \"Remove {{name}}\", { name: item.name })}\n data-test={testIdentity(\n item.existing ? `${name}-remove-existing` : `${name}-remove`,\n )}\n disabled={locked}\n onClick={() => removeItem(item.id)}\n />\n )}\n {signed && !item.existing && item.key && item.status === \"ready\" && (\n <input\n data-test={testIdentity(`${name}-uploaded`)}\n name={fieldName}\n type=\"hidden\"\n value={item.key}\n />\n )}\n </li>\n ))}\n </ul>\n\n {!scope &&\n removedTokens.map((token) => (\n <input key={token} name={`${name}__removed[]`} type=\"hidden\" value={token} />\n ))}\n\n <input\n accept={props.accept ?? undefined}\n aria-label={props.label ?? name}\n className=\"sr-only\"\n data-test={testIdentity(`${name}-input`)}\n id={inputId}\n multiple={multiple}\n name={signed ? undefined : fieldName}\n onChange={(event) => {\n addFiles(event.target.files);\n if (signed) {\n event.target.value = \"\";\n }\n }}\n ref={fileInputRef}\n type=\"file\"\n />\n </div>\n </FormFieldFrame>\n );\n};\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
+ import { Input } from "../../../ui/input.js";
1
2
  import { SimpleField } from "./simple-field.js";
2
3
  import { AffixGroup } from "../../../ui/affix-group.js";
3
- import { Input } from "../../../ui/input.js";
4
4
  import { jsx, jsxs } from "react/jsx-runtime";
5
5
  //#region resources/js/form/components/fields/number-input.tsx
6
6
  var NumberInputComponent = ({ node }) => {