@lattice-php/lattice 0.20.0 → 0.22.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 (212) hide show
  1. package/README.md +10 -0
  2. package/dist/action/components/action-form.d.ts +6 -1
  3. package/dist/action/components/action-form.js +48 -58
  4. package/dist/action/components/action-form.js.map +1 -1
  5. package/dist/action/components/action-trigger-provider.d.ts +1 -1
  6. package/dist/action/components/action-trigger-provider.js.map +1 -1
  7. package/dist/action/components/action.js +2 -1
  8. package/dist/action/components/action.js.map +1 -1
  9. package/dist/action/hooks/use-action.d.ts +1 -1
  10. package/dist/action/hooks/use-action.js +42 -33
  11. package/dist/action/hooks/use-action.js.map +1 -1
  12. package/dist/action/index.d.ts +0 -2
  13. package/dist/action/index.js +1 -2
  14. package/dist/action/lib/action-label.d.ts +2 -0
  15. package/dist/action/lib/action-label.js +9 -0
  16. package/dist/action/lib/action-label.js.map +1 -0
  17. package/dist/action/lib/run-action.d.ts +7 -7
  18. package/dist/action/lib/run-action.js +8 -7
  19. package/dist/action/lib/run-action.js.map +1 -1
  20. package/dist/chat/plugin.d.ts +0 -1
  21. package/dist/chat/plugin.js.map +1 -1
  22. package/dist/clipboard/index.d.ts +0 -4
  23. package/dist/clipboard/index.js +1 -15
  24. package/dist/{events → core}/event-names.js +1 -1
  25. package/dist/core/event-names.js.map +1 -0
  26. package/dist/core/hooks/use-window-event.d.ts +8 -0
  27. package/dist/core/hooks/use-window-event.js +22 -0
  28. package/dist/core/hooks/use-window-event.js.map +1 -0
  29. package/dist/core/index.js +3 -3
  30. package/dist/core/types.d.ts +8 -73
  31. package/dist/create-app.js +1 -1
  32. package/dist/effects/dispatch.js +1 -1
  33. package/dist/effects/dispatch.js.map +1 -1
  34. package/dist/effects/registry.d.ts +2 -18
  35. package/dist/effects/registry.js +4 -8
  36. package/dist/effects/registry.js.map +1 -1
  37. package/dist/event-bridge.js +10 -23
  38. package/dist/event-bridge.js.map +1 -1
  39. package/dist/form/components/fields/date-picker-field.js +1 -1
  40. package/dist/form/components/fields/file-upload.js +4 -6
  41. package/dist/form/components/fields/file-upload.js.map +1 -1
  42. package/dist/form/components/fields/select.js +2 -2
  43. package/dist/form/components/fields/select.js.map +1 -1
  44. package/dist/form/components/fields/table-rows.js +3 -15
  45. package/dist/form/components/fields/table-rows.js.map +1 -1
  46. package/dist/form/components/form.js +11 -24
  47. package/dist/form/components/form.js.map +1 -1
  48. package/dist/form/embed.d.ts +4 -0
  49. package/dist/form/embed.js +3 -1
  50. package/dist/form/lib/collect-fields.d.ts +7 -0
  51. package/dist/form/lib/collect-fields.js +19 -0
  52. package/dist/form/lib/collect-fields.js.map +1 -0
  53. package/dist/form/lib/field-errors.d.ts +3 -0
  54. package/dist/form/lib/field-errors.js +11 -0
  55. package/dist/form/lib/field-errors.js.map +1 -0
  56. package/dist/format/format-context.d.ts +6 -0
  57. package/dist/format/format-context.js +17 -0
  58. package/dist/format/format-context.js.map +1 -0
  59. package/dist/format/number.d.ts +1 -1
  60. package/dist/format/number.js.map +1 -1
  61. package/dist/format/value.d.ts +1 -1
  62. package/dist/format/value.js.map +1 -1
  63. package/dist/i18n/backend.js +1 -1
  64. package/dist/i18n/index.js +2 -2
  65. package/dist/i18n/instance.js +1 -1
  66. package/dist/i18n/locale-reload.d.ts +1 -1
  67. package/dist/i18n/locale-reload.js +7 -6
  68. package/dist/i18n/locale-reload.js.map +1 -1
  69. package/dist/i18n/locale.js +1 -1
  70. package/dist/i18n/locale.js.map +1 -1
  71. package/dist/i18n/page-props.js +1 -1
  72. package/dist/i18n/shared-props.js +1 -3
  73. package/dist/i18n/shared-props.js.map +1 -1
  74. package/dist/i18n/timezone.js +1 -1
  75. package/dist/i18n/timezone.js.map +1 -1
  76. package/dist/index.d.ts +6 -7
  77. package/dist/index.js +7 -8
  78. package/dist/lattice.css +105 -0
  79. package/dist/layout/components/callouts.js +1 -1
  80. package/dist/layout/components/sidebar.js +15 -48
  81. package/dist/layout/components/sidebar.js.map +1 -1
  82. package/dist/layout/plugin.d.ts +0 -1
  83. package/dist/layout/plugin.js.map +1 -1
  84. package/dist/lib/is-truthy.d.ts +2 -0
  85. package/dist/lib/is-truthy.js +9 -0
  86. package/dist/lib/is-truthy.js.map +1 -0
  87. package/dist/lib/use-debounced-callback.d.ts +10 -0
  88. package/dist/lib/use-debounced-callback.js +34 -0
  89. package/dist/lib/use-debounced-callback.js.map +1 -0
  90. package/dist/lib/use-media-query.d.ts +5 -0
  91. package/dist/lib/use-media-query.js +26 -0
  92. package/dist/lib/use-media-query.js.map +1 -0
  93. package/dist/lib/use-persistent-state.d.ts +13 -0
  94. package/dist/lib/use-persistent-state.js +62 -0
  95. package/dist/lib/use-persistent-state.js.map +1 -0
  96. package/dist/notifications/components/notifications.js +4 -1
  97. package/dist/notifications/components/notifications.js.map +1 -1
  98. package/dist/notifications/plugin.d.ts +0 -1
  99. package/dist/notifications/plugin.js.map +1 -1
  100. package/dist/provider-base.js +1 -1
  101. package/dist/realtime/listeners.d.ts +1 -1
  102. package/dist/realtime/listeners.js +1 -1
  103. package/dist/realtime/listeners.js.map +1 -1
  104. package/dist/registry.d.ts +5 -0
  105. package/dist/registry.js.map +1 -1
  106. package/dist/remote/components/data-list.js +1 -1
  107. package/dist/remote/plugin.d.ts +0 -1
  108. package/dist/remote/plugin.js.map +1 -1
  109. package/dist/table/components/bulk-bar.js +18 -15
  110. package/dist/table/components/bulk-bar.js.map +1 -1
  111. package/dist/table/components/cells/boolean-cell.js +1 -3
  112. package/dist/table/components/cells/boolean-cell.js.map +1 -1
  113. package/dist/table/components/cells/copyable-cell.d.ts +9 -0
  114. package/dist/table/components/cells/copyable-cell.js +17 -0
  115. package/dist/table/components/cells/copyable-cell.js.map +1 -0
  116. package/dist/table/components/cells/money-cell.js +7 -18
  117. package/dist/table/components/cells/money-cell.js.map +1 -1
  118. package/dist/table/components/cells/number-cell.js +14 -27
  119. package/dist/table/components/cells/number-cell.js.map +1 -1
  120. package/dist/table/components/cells/numeric-cell.d.ts +10 -0
  121. package/dist/table/components/cells/numeric-cell.js +25 -0
  122. package/dist/table/components/cells/numeric-cell.js.map +1 -0
  123. package/dist/table/components/cells/stack-cell.js +1 -1
  124. package/dist/table/components/cells/text-cell.js +4 -5
  125. package/dist/table/components/cells/text-cell.js.map +1 -1
  126. package/dist/table/components/filter-controls.js +1 -3
  127. package/dist/table/components/filter-controls.js.map +1 -1
  128. package/dist/table/components/table-cell.js.map +1 -1
  129. package/dist/table/components/table-search.js +4 -7
  130. package/dist/table/components/table-search.js.map +1 -1
  131. package/dist/table/components/table.js +2 -3
  132. package/dist/table/components/table.js.map +1 -1
  133. package/dist/table/hooks/use-column-visibility.js +29 -58
  134. package/dist/table/hooks/use-column-visibility.js.map +1 -1
  135. package/dist/table/hooks/use-table.js +5 -13
  136. package/dist/table/hooks/use-table.js.map +1 -1
  137. package/dist/table/lib/bulk.d.ts +2 -0
  138. package/dist/table/lib/bulk.js +5 -2
  139. package/dist/table/lib/bulk.js.map +1 -1
  140. package/dist/table/lib/query.js +1 -1
  141. package/dist/table/lib/query.js.map +1 -1
  142. package/dist/table/plugin.d.ts +0 -1
  143. package/dist/table/plugin.js.map +1 -1
  144. package/dist/table/types.d.ts +4 -57
  145. package/dist/toast/callout.js +1 -1
  146. package/dist/toast/callout.js.map +1 -1
  147. package/dist/toast/index.d.ts +1 -1
  148. package/dist/toast/index.js +2 -2
  149. package/dist/toast/toast.d.ts +0 -2
  150. package/dist/toast/toast.js +3 -10
  151. package/dist/toast/toast.js.map +1 -1
  152. package/dist/toast/toaster.js +2 -2
  153. package/dist/types/generated.d.ts +224 -80
  154. package/dist/types/index.d.ts +1 -1
  155. package/dist/ui/button.d.ts +2 -2
  156. package/dist/ui/chart-view.js +7 -30
  157. package/dist/ui/chart-view.js.map +1 -1
  158. package/dist/ui/click-behavior.d.ts +4 -4
  159. package/dist/ui/click-behavior.js.map +1 -1
  160. package/dist/ui/collapsible.js +3 -15
  161. package/dist/ui/collapsible.js.map +1 -1
  162. package/dist/ui/combobox.js +6 -3
  163. package/dist/ui/combobox.js.map +1 -1
  164. package/dist/ui/confirm-dialog.js +1 -1
  165. package/dist/ui/confirm-dialog.js.map +1 -1
  166. package/dist/ui/control.d.ts +1 -1
  167. package/dist/ui/dialog.d.ts +6 -2
  168. package/dist/ui/dialog.js +29 -5
  169. package/dist/ui/dialog.js.map +1 -1
  170. package/dist/ui/fragment.js +1 -1
  171. package/dist/ui/fragment.js.map +1 -1
  172. package/dist/ui/icon-button.d.ts +1 -1
  173. package/dist/ui/image-preview.js +1 -1
  174. package/dist/ui/image-preview.js.map +1 -1
  175. package/dist/ui/modal.js +6 -3
  176. package/dist/ui/modal.js.map +1 -1
  177. package/dist/ui/pill.d.ts +2 -0
  178. package/dist/ui/pill.js +10 -0
  179. package/dist/ui/pill.js.map +1 -0
  180. package/dist/ui/plugin.js.map +1 -1
  181. package/dist/ui/progress.js +1 -1
  182. package/dist/ui/section.js +2 -15
  183. package/dist/ui/section.js.map +1 -1
  184. package/dist/ui/segmented-pills.js +2 -1
  185. package/dist/ui/segmented-pills.js.map +1 -1
  186. package/dist/ui/tabs.js +12 -10
  187. package/dist/ui/tabs.js.map +1 -1
  188. package/dist/ui/tree-context.js +11 -13
  189. package/dist/ui/tree-context.js.map +1 -1
  190. package/dist/ui/tree.js +1 -1
  191. package/dist/ui/tree.js.map +1 -1
  192. package/dist/ui/use-collapsible-state.d.ts +7 -0
  193. package/dist/ui/use-collapsible-state.js +21 -0
  194. package/dist/ui/use-collapsible-state.js.map +1 -0
  195. package/dist-standalone/chunks/chart-view-C6R5iPra.js +36 -0
  196. package/dist-standalone/chunks/{date-picker-field-VbH9xrQO.js → date-picker-field-DhhEB-Mh.js} +1 -1
  197. package/dist-standalone/chunks/{page-props-AIa5UR6n.js → page-props-DOfg30l5.js} +1 -1
  198. package/dist-standalone/chunks/{rich-editor-field-DLQTyt36.js → rich-editor-field-DORXTHPw.js} +2 -2
  199. package/dist-standalone/chunks/{subscriptions-DY2tj9Im.js → subscriptions-DK_s_F2g.js} +1 -1
  200. package/dist-standalone/chunks/use-effect-dispatcher-EVZxmfoo.js +97 -0
  201. package/dist-standalone/lattice.css +1 -1
  202. package/dist-standalone/lattice.js +15 -15
  203. package/dist-standalone/manifest.json +8 -8
  204. package/package.json +3 -3
  205. package/dist/clipboard/index.js.map +0 -1
  206. package/dist/events/event-names.js.map +0 -1
  207. package/dist/table/components/table-action-node.d.ts +0 -4
  208. package/dist/table/components/table-action-node.js +0 -24
  209. package/dist/table/components/table-action-node.js.map +0 -1
  210. package/dist-standalone/chunks/chart-view-wJmnVu7L.js +0 -36
  211. package/dist-standalone/chunks/use-effect-dispatcher-feEs0GCP.js +0 -97
  212. /package/dist/{events → core}/event-names.d.ts +0 -0
@@ -1 +1,6 @@
1
+ import { ActionNodeType, ChatNodeType, FormNodeType, FragmentNodeType, LayoutNodeType, NodeType, NotificationNodeType, RemoteNodeType, TableNodeType, UiNodeType } from './types/generated.js';
2
+ type RegisteredNodeType = ActionNodeType | ChatNodeType | FormNodeType | FragmentNodeType | LayoutNodeType | NotificationNodeType | RemoteNodeType | TableNodeType | UiNodeType;
3
+ type Assert<T extends true> = T;
4
+ export type AllNodeTypesRegistered = Assert<Exclude<NodeType, RegisteredNodeType> extends never ? true : false>;
1
5
  export declare const registry: import('./core/registry.js').Registry;
6
+ export {};
@@ -1 +1 @@
1
- {"version":3,"file":"registry.js","names":[],"sources":["../resources/js/registry.ts"],"sourcesContent":["import { createRegistry } from \"@lattice-php/lattice/core/registry\";\nimport { actionComponents } from \"./action/plugin\";\nimport { chatComponents } from \"./chat/plugin\";\nimport { uiComponents } from \"./ui/plugin\";\nimport { formComponents } from \"./form/plugin\";\nimport { layoutComponents } from \"./layout/plugin\";\nimport { notificationsComponents } from \"./notifications/plugin\";\nimport { remoteComponents } from \"./remote/plugin\";\nimport { tableComponents } from \"./table/plugin\";\n\nexport const registry = createRegistry(\n uiComponents,\n actionComponents,\n formComponents,\n layoutComponents,\n tableComponents,\n chatComponents,\n notificationsComponents,\n remoteComponents,\n);\n"],"mappings":";;;;;;;;;;AAUA,IAAa,WAAW,eACtB,cACA,kBACA,gBACA,kBACA,iBACA,gBACA,yBACA,gBACF"}
1
+ {"version":3,"file":"registry.js","names":[],"sources":["../resources/js/registry.ts"],"sourcesContent":["import { createRegistry } from \"@lattice-php/lattice/core/registry\";\nimport type {\n ActionNodeType,\n ChatNodeType,\n FormNodeType,\n FragmentNodeType,\n LayoutNodeType,\n NodeType,\n NotificationNodeType,\n RemoteNodeType,\n TableNodeType,\n UiNodeType,\n} from \"@lattice-php/lattice/types/generated\";\nimport { actionComponents } from \"./action/plugin\";\nimport { chatComponents } from \"./chat/plugin\";\nimport { uiComponents } from \"./ui/plugin\";\nimport { formComponents } from \"./form/plugin\";\nimport { layoutComponents } from \"./layout/plugin\";\nimport { notificationsComponents } from \"./notifications/plugin\";\nimport { remoteComponents } from \"./remote/plugin\";\nimport { tableComponents } from \"./table/plugin\";\n\n// Compile-time totality: every generated NodeType must belong to a registered\n// plugin's union. A new PHP domain fails here until its plugin exists.\ntype RegisteredNodeType =\n | ActionNodeType\n | ChatNodeType\n | FormNodeType\n | FragmentNodeType\n | LayoutNodeType\n | NotificationNodeType\n | RemoteNodeType\n | TableNodeType\n | UiNodeType;\ntype Assert<T extends true> = T;\nexport type AllNodeTypesRegistered = Assert<\n Exclude<NodeType, RegisteredNodeType> extends never ? true : false\n>;\n\nexport const registry = createRegistry(\n uiComponents,\n actionComponents,\n formComponents,\n layoutComponents,\n tableComponents,\n chatComponents,\n notificationsComponents,\n remoteComponents,\n);\n"],"mappings":";;;;;;;;;;AAuCA,IAAa,WAAW,eACtB,cACA,kBACA,gBACA,kBACA,iBACA,gBACA,yBACA,gBACF"}
@@ -1,7 +1,7 @@
1
+ import { materializeSchema } from "../../core/materialize.js";
1
2
  import { Renderer } from "../../core/renderer.js";
2
3
  import { useT } from "../../i18n/instance.js";
3
4
  import { remoteJson } from "../../core/api.js";
4
- import { materializeSchema } from "../../core/materialize.js";
5
5
  import { useEffect, useState } from "react";
6
6
  import { jsx, jsxs } from "react/jsx-runtime";
7
7
  //#region resources/js/remote/components/data-list.tsx
@@ -1,2 +1 @@
1
- export type RemoteComponentType = "remote.data-list";
2
1
  export declare const remoteComponents: import('../core/registry.js').Plugin;
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.js","names":[],"sources":["../../resources/js/remote/plugin.ts"],"sourcesContent":["import {\n createPlugin,\n eagerComponent,\n type ComponentRegistryFor,\n} from \"@lattice-php/lattice/core/registry\";\nimport DataListComponent from \"./components/data-list\";\n\nexport type RemoteComponentType = \"remote.data-list\";\n\nexport const remoteComponents = createPlugin({\n components: {\n \"remote.data-list\": eagerComponent(DataListComponent),\n } satisfies ComponentRegistryFor<RemoteComponentType>,\n name: \"lattice/remote\",\n});\n"],"mappings":";;;AASA,IAAa,mBAAmB,aAAa;CAC3C,YAAY,EACV,oBAAoB,eAAe,QAAiB,EACtD;CACA,MAAM;AACR,CAAC"}
1
+ {"version":3,"file":"plugin.js","names":[],"sources":["../../resources/js/remote/plugin.ts"],"sourcesContent":["import {\n createPlugin,\n eagerComponent,\n type ComponentRegistryFor,\n} from \"@lattice-php/lattice/core/registry\";\nimport type { RemoteNodeType } from \"@lattice-php/lattice/types/generated\";\nimport DataListComponent from \"./components/data-list\";\n\nexport const remoteComponents = createPlugin({\n components: {\n \"remote.data-list\": eagerComponent(DataListComponent),\n } satisfies ComponentRegistryFor<RemoteNodeType>,\n name: \"lattice/remote\",\n});\n"],"mappings":";;;AAQA,IAAa,mBAAmB,aAAa;CAC3C,YAAY,EACV,oBAAoB,eAAe,QAAiB,EACtD;CACA,MAAM;AACR,CAAC"}
@@ -1,20 +1,18 @@
1
1
  import { useT } from "../../i18n/instance.js";
2
- import { withHeaders } from "../../core/headers.js";
3
2
  import { prefixedTestId } from "../../core/test-id.js";
4
- import { getActionEffects } from "../../effects/dispatch.js";
5
3
  import { useEffectDispatcher } from "../../effects/use-effect-dispatcher.js";
6
4
  import { Button } from "../../ui/button.js";
7
5
  import { Spinner } from "../../ui/spinner.js";
8
6
  import { ConfirmDialog } from "../../ui/confirm-dialog.js";
7
+ import { apiFetch } from "../../core/api.js";
9
8
  import { runAction } from "../../action/lib/run-action.js";
10
9
  import { ActionForm } from "../../action/components/action-form.js";
11
- import { useHttp } from "@inertiajs/react";
12
10
  import { useState } from "react";
13
11
  import { jsx, jsxs } from "react/jsx-runtime";
14
12
  //#region resources/js/table/components/bulk-bar.tsx
15
13
  function BulkBar({ actions, selectedKeys, allMatching, total, query, canSelectAllMatching, onSelectAllMatching, onCompleted }) {
16
14
  const { t } = useT("lattice");
17
- const http = useHttp({});
15
+ const [processing, setProcessing] = useState(false);
18
16
  const dispatch = useEffectDispatcher();
19
17
  const [confirming, setConfirming] = useState(null);
20
18
  const [filling, setFilling] = useState(null);
@@ -23,11 +21,15 @@ function BulkBar({ actions, selectedKeys, allMatching, total, query, canSelectAl
23
21
  ...query
24
22
  } : { selected: selectedKeys };
25
23
  async function submit(action) {
26
- http.transform((data) => ({
27
- ...data,
28
- ...selectionPayload()
29
- }));
30
- if (await runAction(() => http[action.method](action.endpoint, { headers: withHeaders(action.ref ?? "") }), dispatch)) {
24
+ setProcessing(true);
25
+ const ok = await runAction(() => apiFetch(action.endpoint, {
26
+ method: action.method,
27
+ ref: action.ref,
28
+ body: JSON.stringify(selectionPayload()),
29
+ throwOnError: false
30
+ }), dispatch);
31
+ setProcessing(false);
32
+ if (ok) {
31
33
  setConfirming(null);
32
34
  onCompleted();
33
35
  }
@@ -64,9 +66,9 @@ function BulkBar({ actions, selectedKeys, allMatching, total, query, canSelectAl
64
66
  type: "button",
65
67
  "data-test": prefixedTestId("bulk-action", action.id),
66
68
  variant: action.variant,
67
- disabled: http.processing,
69
+ disabled: processing,
68
70
  onClick: () => run(action),
69
- children: [http.processing && /* @__PURE__ */ jsx(Spinner, {}), action.label]
71
+ children: [processing && /* @__PURE__ */ jsx(Spinner, {}), action.label]
70
72
  }, action.id))
71
73
  }),
72
74
  confirming?.confirmation && /* @__PURE__ */ jsx(ConfirmDialog, {
@@ -75,7 +77,7 @@ function BulkBar({ actions, selectedKeys, allMatching, total, query, canSelectAl
75
77
  confirmLabel: confirming.confirmation.confirmLabel ?? confirming.label,
76
78
  cancelLabel: confirming.confirmation.cancelLabel ?? t("common.cancel", "Cancel"),
77
79
  confirmVariant: confirming.variant,
78
- processing: http.processing,
80
+ processing,
79
81
  onConfirm: () => void submit(confirming),
80
82
  onCancel: () => setConfirming(null)
81
83
  }),
@@ -88,13 +90,14 @@ function BulkBar({ actions, selectedKeys, allMatching, total, query, canSelectAl
88
90
  formNode: filling.form,
89
91
  method: filling.method,
90
92
  onClose: () => setFilling(null),
91
- onSuccess: (response) => {
92
- dispatch(getActionEffects(response.effects));
93
+ onSuccess: () => {
93
94
  setFilling(null);
94
95
  onCompleted();
95
96
  },
97
+ placement: filling.modalSide ?? "center",
96
98
  submitLabel: filling.confirmation?.confirmLabel ?? filling.label,
97
- title: filling.confirmation?.title ?? filling.label
99
+ title: filling.confirmation?.title ?? filling.label,
100
+ width: filling.modalWidth ?? void 0
98
101
  })
99
102
  ]
100
103
  });
@@ -1 +1 @@
1
- {"version":3,"file":"bulk-bar.js","names":[],"sources":["../../../resources/js/table/components/bulk-bar.tsx"],"sourcesContent":["import { useHttp } from \"@inertiajs/react\";\nimport { useState } from \"react\";\nimport { ActionForm, runAction } from \"@lattice-php/lattice/action\";\nimport { getActionEffects } from \"@lattice-php/lattice/effects/dispatch\";\nimport type { ActionResponse } from \"@lattice-php/lattice/effects/dispatch\";\nimport { useEffectDispatcher } from \"@lattice-php/lattice/effects/use-effect-dispatcher\";\nimport { withHeaders } from \"@lattice-php/lattice/core/headers\";\nimport { Button } from \"@lattice-php/lattice/ui/button\";\nimport { ConfirmDialog } from \"@lattice-php/lattice/ui/confirm-dialog\";\nimport { Spinner } from \"@lattice-php/lattice/ui/spinner\";\nimport { prefixedTestId } from \"@lattice-php/lattice/core/test-id\";\nimport { useT } from \"@lattice-php/lattice/i18n\";\nimport type { BulkAction } from \"@lattice-php/lattice/table/lib/bulk\";\n\ntype BulkData = {\n allMatching?: boolean;\n selected?: string[];\n};\n\nexport function BulkBar({\n actions,\n selectedKeys,\n allMatching,\n total,\n query,\n canSelectAllMatching,\n onSelectAllMatching,\n onCompleted,\n}: {\n actions: BulkAction[];\n selectedKeys: string[];\n allMatching: boolean;\n total?: number;\n query: Record<string, unknown>;\n canSelectAllMatching: boolean;\n onSelectAllMatching: () => void;\n onCompleted: () => void;\n}) {\n const { t } = useT(\"lattice\");\n const http = useHttp<BulkData, ActionResponse>({});\n const dispatch = useEffectDispatcher();\n const [confirming, setConfirming] = useState<BulkAction | null>(null);\n const [filling, setFilling] = useState<BulkAction | null>(null);\n\n const selectionPayload = (): Record<string, unknown> =>\n allMatching ? { allMatching: true, ...query } : { selected: selectedKeys };\n\n async function submit(action: BulkAction): Promise<void> {\n http.transform((data) => ({ ...data, ...selectionPayload() }));\n\n const ok = await runAction(\n () => http[action.method](action.endpoint, { headers: withHeaders(action.ref ?? \"\") }),\n dispatch,\n );\n\n if (ok) {\n setConfirming(null);\n onCompleted();\n }\n }\n\n function run(action: BulkAction): void {\n if (action.form) {\n setFilling(action);\n\n return;\n }\n\n if (action.confirmation) {\n setConfirming(action);\n\n return;\n }\n\n void submit(action);\n }\n\n const count = allMatching ? (total ?? selectedKeys.length) : selectedKeys.length;\n\n return (\n <div className=\"flex flex-wrap items-center gap-3 border-b border-lt-border bg-lt-muted/50 p-4 text-sm\">\n <span className=\"font-medium\">\n {allMatching\n ? t(\"table.bulk.all-selected\", \"All {{count}} selected\", { count })\n : t(\"table.bulk.selected\", \"{{count}} selected\", { count })}\n </span>\n {canSelectAllMatching && (\n <button\n type=\"button\"\n data-test=\"bulk-select-all-matching\"\n className=\"font-medium text-lt-primary underline underline-offset-2\"\n onClick={onSelectAllMatching}\n >\n {t(\"table.bulk.select-all-matching\", \"Select all {{total}} matching\", { total })}\n </button>\n )}\n <div className=\"flex flex-wrap items-center gap-2\">\n {actions.map((action) => (\n <Button\n key={action.id}\n type=\"button\"\n data-test={prefixedTestId(\"bulk-action\", action.id)}\n variant={action.variant}\n disabled={http.processing}\n onClick={() => run(action)}\n >\n {http.processing && <Spinner />}\n {action.label}\n </Button>\n ))}\n </div>\n\n {confirming?.confirmation && (\n <ConfirmDialog\n title={confirming.confirmation.title ?? confirming.label}\n description={confirming.confirmation.description ?? undefined}\n confirmLabel={confirming.confirmation.confirmLabel ?? confirming.label}\n cancelLabel={confirming.confirmation.cancelLabel ?? t(\"common.cancel\", \"Cancel\")}\n confirmVariant={confirming.variant}\n processing={http.processing}\n onConfirm={() => void submit(confirming)}\n onCancel={() => setConfirming(null)}\n />\n )}\n\n {filling?.form && (\n <ActionForm\n cancelLabel={filling.confirmation?.cancelLabel ?? t(\"common.cancel\", \"Cancel\")}\n componentRef={filling.ref}\n description={filling.confirmation?.description ?? undefined}\n endpoint={filling.endpoint}\n extraData={selectionPayload()}\n formNode={filling.form}\n method={filling.method}\n onClose={() => setFilling(null)}\n onSuccess={(response) => {\n dispatch(getActionEffects(response.effects));\n setFilling(null);\n onCompleted();\n }}\n submitLabel={filling.confirmation?.confirmLabel ?? filling.label}\n title={filling.confirmation?.title ?? filling.label}\n />\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;AAmBA,SAAgB,QAAQ,EACtB,SACA,cACA,aACA,OACA,OACA,sBACA,qBACA,eAUC;CACD,MAAM,EAAE,MAAM,KAAK,SAAS;CAC5B,MAAM,OAAO,QAAkC,CAAC,CAAC;CACjD,MAAM,WAAW,oBAAoB;CACrC,MAAM,CAAC,YAAY,iBAAiB,SAA4B,IAAI;CACpE,MAAM,CAAC,SAAS,cAAc,SAA4B,IAAI;CAE9D,MAAM,yBACJ,cAAc;EAAE,aAAa;EAAM,GAAG;CAAM,IAAI,EAAE,UAAU,aAAa;CAE3E,eAAe,OAAO,QAAmC;EACvD,KAAK,WAAW,UAAU;GAAE,GAAG;GAAM,GAAG,iBAAiB;EAAE,EAAE;EAO7D,IAAI,MALa,gBACT,KAAK,OAAO,QAAQ,OAAO,UAAU,EAAE,SAAS,YAAY,OAAO,OAAO,EAAE,EAAE,CAAC,GACrF,QACF,GAEQ;GACN,cAAc,IAAI;GAClB,YAAY;EACd;CACF;CAEA,SAAS,IAAI,QAA0B;EACrC,IAAI,OAAO,MAAM;GACf,WAAW,MAAM;GAEjB;EACF;EAEA,IAAI,OAAO,cAAc;GACvB,cAAc,MAAM;GAEpB;EACF;EAEA,OAAY,MAAM;CACpB;CAEA,MAAM,QAAQ,cAAe,SAAS,aAAa,SAAU,aAAa;CAE1E,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf;GACE,oBAAC,QAAD;IAAM,WAAU;cACb,cACG,EAAE,2BAA2B,0BAA0B,EAAE,MAAM,CAAC,IAChE,EAAE,uBAAuB,sBAAsB,EAAE,MAAM,CAAC;GACxD,CAAA;GACL,wBACC,oBAAC,UAAD;IACE,MAAK;IACL,aAAU;IACV,WAAU;IACV,SAAS;cAER,EAAE,kCAAkC,iCAAiC,EAAE,MAAM,CAAC;GACzE,CAAA;GAEV,oBAAC,OAAD;IAAK,WAAU;cACZ,QAAQ,KAAK,WACZ,qBAAC,QAAD;KAEE,MAAK;KACL,aAAW,eAAe,eAAe,OAAO,EAAE;KAClD,SAAS,OAAO;KAChB,UAAU,KAAK;KACf,eAAe,IAAI,MAAM;eAN3B,CAQG,KAAK,cAAc,oBAAC,SAAD,CAAU,CAAA,GAC7B,OAAO,KACF;OATD,OAAO,EASN,CACT;GACE,CAAA;GAEJ,YAAY,gBACX,oBAAC,eAAD;IACE,OAAO,WAAW,aAAa,SAAS,WAAW;IACnD,aAAa,WAAW,aAAa,eAAe,KAAA;IACpD,cAAc,WAAW,aAAa,gBAAgB,WAAW;IACjE,aAAa,WAAW,aAAa,eAAe,EAAE,iBAAiB,QAAQ;IAC/E,gBAAgB,WAAW;IAC3B,YAAY,KAAK;IACjB,iBAAiB,KAAK,OAAO,UAAU;IACvC,gBAAgB,cAAc,IAAI;GACnC,CAAA;GAGF,SAAS,QACR,oBAAC,YAAD;IACE,aAAa,QAAQ,cAAc,eAAe,EAAE,iBAAiB,QAAQ;IAC7E,cAAc,QAAQ;IACtB,aAAa,QAAQ,cAAc,eAAe,KAAA;IAClD,UAAU,QAAQ;IAClB,WAAW,iBAAiB;IAC5B,UAAU,QAAQ;IAClB,QAAQ,QAAQ;IAChB,eAAe,WAAW,IAAI;IAC9B,YAAY,aAAa;KACvB,SAAS,iBAAiB,SAAS,OAAO,CAAC;KAC3C,WAAW,IAAI;KACf,YAAY;IACd;IACA,aAAa,QAAQ,cAAc,gBAAgB,QAAQ;IAC3D,OAAO,QAAQ,cAAc,SAAS,QAAQ;GAC/C,CAAA;EAEA;;AAET"}
1
+ {"version":3,"file":"bulk-bar.js","names":[],"sources":["../../../resources/js/table/components/bulk-bar.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport { ActionForm, runAction } from \"@lattice-php/lattice/action\";\nimport { apiFetch } from \"@lattice-php/lattice/core/api\";\nimport { useEffectDispatcher } from \"@lattice-php/lattice/effects/use-effect-dispatcher\";\nimport { Button } from \"@lattice-php/lattice/ui/button\";\nimport { ConfirmDialog } from \"@lattice-php/lattice/ui/confirm-dialog\";\nimport { Spinner } from \"@lattice-php/lattice/ui/spinner\";\nimport { prefixedTestId } from \"@lattice-php/lattice/core/test-id\";\nimport { useT } from \"@lattice-php/lattice/i18n\";\nimport type { BulkAction } from \"@lattice-php/lattice/table/lib/bulk\";\n\nexport function BulkBar({\n actions,\n selectedKeys,\n allMatching,\n total,\n query,\n canSelectAllMatching,\n onSelectAllMatching,\n onCompleted,\n}: {\n actions: BulkAction[];\n selectedKeys: string[];\n allMatching: boolean;\n total?: number;\n query: Record<string, unknown>;\n canSelectAllMatching: boolean;\n onSelectAllMatching: () => void;\n onCompleted: () => void;\n}) {\n const { t } = useT(\"lattice\");\n const [processing, setProcessing] = useState(false);\n const dispatch = useEffectDispatcher();\n const [confirming, setConfirming] = useState<BulkAction | null>(null);\n const [filling, setFilling] = useState<BulkAction | null>(null);\n\n const selectionPayload = (): Record<string, unknown> =>\n allMatching ? { allMatching: true, ...query } : { selected: selectedKeys };\n\n async function submit(action: BulkAction): Promise<void> {\n setProcessing(true);\n\n const ok = await runAction(\n () =>\n apiFetch(action.endpoint, {\n method: action.method,\n ref: action.ref,\n body: JSON.stringify(selectionPayload()),\n throwOnError: false,\n }),\n dispatch,\n );\n\n setProcessing(false);\n\n if (ok) {\n setConfirming(null);\n onCompleted();\n }\n }\n\n function run(action: BulkAction): void {\n if (action.form) {\n setFilling(action);\n\n return;\n }\n\n if (action.confirmation) {\n setConfirming(action);\n\n return;\n }\n\n void submit(action);\n }\n\n const count = allMatching ? (total ?? selectedKeys.length) : selectedKeys.length;\n\n return (\n <div className=\"flex flex-wrap items-center gap-3 border-b border-lt-border bg-lt-muted/50 p-4 text-sm\">\n <span className=\"font-medium\">\n {allMatching\n ? t(\"table.bulk.all-selected\", \"All {{count}} selected\", { count })\n : t(\"table.bulk.selected\", \"{{count}} selected\", { count })}\n </span>\n {canSelectAllMatching && (\n <button\n type=\"button\"\n data-test=\"bulk-select-all-matching\"\n className=\"font-medium text-lt-primary underline underline-offset-2\"\n onClick={onSelectAllMatching}\n >\n {t(\"table.bulk.select-all-matching\", \"Select all {{total}} matching\", { total })}\n </button>\n )}\n <div className=\"flex flex-wrap items-center gap-2\">\n {actions.map((action) => (\n <Button\n key={action.id}\n type=\"button\"\n data-test={prefixedTestId(\"bulk-action\", action.id)}\n variant={action.variant}\n disabled={processing}\n onClick={() => run(action)}\n >\n {processing && <Spinner />}\n {action.label}\n </Button>\n ))}\n </div>\n\n {confirming?.confirmation && (\n <ConfirmDialog\n title={confirming.confirmation.title ?? confirming.label}\n description={confirming.confirmation.description ?? undefined}\n confirmLabel={confirming.confirmation.confirmLabel ?? confirming.label}\n cancelLabel={confirming.confirmation.cancelLabel ?? t(\"common.cancel\", \"Cancel\")}\n confirmVariant={confirming.variant}\n processing={processing}\n onConfirm={() => void submit(confirming)}\n onCancel={() => setConfirming(null)}\n />\n )}\n\n {filling?.form && (\n <ActionForm\n cancelLabel={filling.confirmation?.cancelLabel ?? t(\"common.cancel\", \"Cancel\")}\n componentRef={filling.ref}\n description={filling.confirmation?.description ?? undefined}\n endpoint={filling.endpoint}\n extraData={selectionPayload()}\n formNode={filling.form}\n method={filling.method}\n onClose={() => setFilling(null)}\n onSuccess={() => {\n setFilling(null);\n onCompleted();\n }}\n placement={filling.modalSide ?? \"center\"}\n submitLabel={filling.confirmation?.confirmLabel ?? filling.label}\n title={filling.confirmation?.title ?? filling.label}\n width={filling.modalWidth ?? undefined}\n />\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;AAWA,SAAgB,QAAQ,EACtB,SACA,cACA,aACA,OACA,OACA,sBACA,qBACA,eAUC;CACD,MAAM,EAAE,MAAM,KAAK,SAAS;CAC5B,MAAM,CAAC,YAAY,iBAAiB,SAAS,KAAK;CAClD,MAAM,WAAW,oBAAoB;CACrC,MAAM,CAAC,YAAY,iBAAiB,SAA4B,IAAI;CACpE,MAAM,CAAC,SAAS,cAAc,SAA4B,IAAI;CAE9D,MAAM,yBACJ,cAAc;EAAE,aAAa;EAAM,GAAG;CAAM,IAAI,EAAE,UAAU,aAAa;CAE3E,eAAe,OAAO,QAAmC;EACvD,cAAc,IAAI;EAElB,MAAM,KAAK,MAAM,gBAEb,SAAS,OAAO,UAAU;GACxB,QAAQ,OAAO;GACf,KAAK,OAAO;GACZ,MAAM,KAAK,UAAU,iBAAiB,CAAC;GACvC,cAAc;EAChB,CAAC,GACH,QACF;EAEA,cAAc,KAAK;EAEnB,IAAI,IAAI;GACN,cAAc,IAAI;GAClB,YAAY;EACd;CACF;CAEA,SAAS,IAAI,QAA0B;EACrC,IAAI,OAAO,MAAM;GACf,WAAW,MAAM;GAEjB;EACF;EAEA,IAAI,OAAO,cAAc;GACvB,cAAc,MAAM;GAEpB;EACF;EAEA,OAAY,MAAM;CACpB;CAEA,MAAM,QAAQ,cAAe,SAAS,aAAa,SAAU,aAAa;CAE1E,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf;GACE,oBAAC,QAAD;IAAM,WAAU;cACb,cACG,EAAE,2BAA2B,0BAA0B,EAAE,MAAM,CAAC,IAChE,EAAE,uBAAuB,sBAAsB,EAAE,MAAM,CAAC;GACxD,CAAA;GACL,wBACC,oBAAC,UAAD;IACE,MAAK;IACL,aAAU;IACV,WAAU;IACV,SAAS;cAER,EAAE,kCAAkC,iCAAiC,EAAE,MAAM,CAAC;GACzE,CAAA;GAEV,oBAAC,OAAD;IAAK,WAAU;cACZ,QAAQ,KAAK,WACZ,qBAAC,QAAD;KAEE,MAAK;KACL,aAAW,eAAe,eAAe,OAAO,EAAE;KAClD,SAAS,OAAO;KAChB,UAAU;KACV,eAAe,IAAI,MAAM;eAN3B,CAQG,cAAc,oBAAC,SAAD,CAAU,CAAA,GACxB,OAAO,KACF;OATD,OAAO,EASN,CACT;GACE,CAAA;GAEJ,YAAY,gBACX,oBAAC,eAAD;IACE,OAAO,WAAW,aAAa,SAAS,WAAW;IACnD,aAAa,WAAW,aAAa,eAAe,KAAA;IACpD,cAAc,WAAW,aAAa,gBAAgB,WAAW;IACjE,aAAa,WAAW,aAAa,eAAe,EAAE,iBAAiB,QAAQ;IAC/E,gBAAgB,WAAW;IACf;IACZ,iBAAiB,KAAK,OAAO,UAAU;IACvC,gBAAgB,cAAc,IAAI;GACnC,CAAA;GAGF,SAAS,QACR,oBAAC,YAAD;IACE,aAAa,QAAQ,cAAc,eAAe,EAAE,iBAAiB,QAAQ;IAC7E,cAAc,QAAQ;IACtB,aAAa,QAAQ,cAAc,eAAe,KAAA;IAClD,UAAU,QAAQ;IAClB,WAAW,iBAAiB;IAC5B,UAAU,QAAQ;IAClB,QAAQ,QAAQ;IAChB,eAAe,WAAW,IAAI;IAC9B,iBAAiB;KACf,WAAW,IAAI;KACf,YAAY;IACd;IACA,WAAW,QAAQ,aAAa;IAChC,aAAa,QAAQ,cAAc,gBAAgB,QAAQ;IAC3D,OAAO,QAAQ,cAAc,SAAS,QAAQ;IAC9C,OAAO,QAAQ,cAAc,KAAA;GAC9B,CAAA;EAEA;;AAET"}
@@ -1,11 +1,9 @@
1
1
  import { cn } from "../../../lib/utils.js";
2
2
  import { Icon } from "../../../icons/sprite.js";
3
3
  import { useT } from "../../../i18n/instance.js";
4
+ import { isTruthy } from "../../../lib/is-truthy.js";
4
5
  import { jsx } from "react/jsx-runtime";
5
6
  //#region resources/js/table/components/cells/boolean-cell.tsx
6
- function isTruthy(value) {
7
- return value === true || value === 1 || value === "1" || value === "true";
8
- }
9
7
  var BooleanCell = ({ value }) => {
10
8
  const { t } = useT("lattice");
11
9
  const truthy = isTruthy(value);
@@ -1 +1 @@
1
- {"version":3,"file":"boolean-cell.js","names":[],"sources":["../../../../resources/js/table/components/cells/boolean-cell.tsx"],"sourcesContent":["import { Icon } from \"@lattice-php/lattice/icons\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport { useT } from \"@lattice-php/lattice/i18n\";\nimport type { ColumnCellComponent } from \"@lattice-php/lattice/table/registry\";\n\nfunction isTruthy(value: unknown): boolean {\n return value === true || value === 1 || value === \"1\" || value === \"true\";\n}\n\nexport const BooleanCell: ColumnCellComponent<\"column.boolean\"> = ({ value }) => {\n const { t } = useT(\"lattice\");\n const truthy = isTruthy(value);\n\n return (\n <span aria-label={truthy ? t(\"common.yes\", \"Yes\") : t(\"common.no\", \"No\")} role=\"img\">\n <Icon\n name={truthy ? \"check\" : \"x\"}\n className={cn(\"size-lt-icon-md\", truthy ? \"text-lt-success\" : \"text-lt-muted-fg\")}\n />\n </span>\n );\n};\n"],"mappings":";;;;;AAKA,SAAS,SAAS,OAAyB;CACzC,OAAO,UAAU,QAAQ,UAAU,KAAK,UAAU,OAAO,UAAU;AACrE;AAEA,IAAa,eAAsD,EAAE,YAAY;CAC/E,MAAM,EAAE,MAAM,KAAK,SAAS;CAC5B,MAAM,SAAS,SAAS,KAAK;CAE7B,OACE,oBAAC,QAAD;EAAM,cAAY,SAAS,EAAE,cAAc,KAAK,IAAI,EAAE,aAAa,IAAI;EAAG,MAAK;YAC7E,oBAAC,MAAD;GACE,MAAM,SAAS,UAAU;GACzB,WAAW,GAAG,mBAAmB,SAAS,oBAAoB,kBAAkB;EACjF,CAAA;CACG,CAAA;AAEV"}
1
+ {"version":3,"file":"boolean-cell.js","names":[],"sources":["../../../../resources/js/table/components/cells/boolean-cell.tsx"],"sourcesContent":["import { Icon } from \"@lattice-php/lattice/icons\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport { isTruthy } from \"@lattice-php/lattice/lib/is-truthy\";\nimport { useT } from \"@lattice-php/lattice/i18n\";\nimport type { ColumnCellComponent } from \"@lattice-php/lattice/table/registry\";\n\nexport const BooleanCell: ColumnCellComponent<\"column.boolean\"> = ({ value }) => {\n const { t } = useT(\"lattice\");\n const truthy = isTruthy(value);\n\n return (\n <span aria-label={truthy ? t(\"common.yes\", \"Yes\") : t(\"common.no\", \"No\")} role=\"img\">\n <Icon\n name={truthy ? \"check\" : \"x\"}\n className={cn(\"size-lt-icon-md\", truthy ? \"text-lt-success\" : \"text-lt-muted-fg\")}\n />\n </span>\n );\n};\n"],"mappings":";;;;;;AAMA,IAAa,eAAsD,EAAE,YAAY;CAC/E,MAAM,EAAE,MAAM,KAAK,SAAS;CAC5B,MAAM,SAAS,SAAS,KAAK;CAE7B,OACE,oBAAC,QAAD;EAAM,cAAY,SAAS,EAAE,cAAc,KAAK,IAAI,EAAE,aAAa,IAAI;EAAG,MAAK;YAC7E,oBAAC,MAAD;GACE,MAAM,SAAS,UAAU;GACzB,WAAW,GAAG,mBAAmB,SAAS,oBAAoB,kBAAkB;EACjF,CAAA;CACG,CAAA;AAEV"}
@@ -0,0 +1,9 @@
1
+ import { ReactNode } from 'react';
2
+ import { TableColumn } from '../../types.js';
3
+ /** Wrap cell content in a copy-to-clipboard affordance when `copyable` is set. */
4
+ export declare function CopyableCell({ children, column, copyable, value, }: {
5
+ children: ReactNode;
6
+ column: TableColumn;
7
+ copyable?: boolean | null;
8
+ value: string;
9
+ }): ReactNode;
@@ -0,0 +1,17 @@
1
+ import { CopyableText } from "../../../ui/copyable-text.js";
2
+ import { jsx } from "react/jsx-runtime";
3
+ //#region resources/js/table/components/cells/copyable-cell.tsx
4
+ /** Wrap cell content in a copy-to-clipboard affordance when `copyable` is set. */
5
+ function CopyableCell({ children, column, copyable, value }) {
6
+ if (!copyable) return children;
7
+ return /* @__PURE__ */ jsx(CopyableText, {
8
+ value,
9
+ label: column.props.label ?? column.key,
10
+ testId: `copy-${column.key}`,
11
+ children
12
+ });
13
+ }
14
+ //#endregion
15
+ export { CopyableCell };
16
+
17
+ //# sourceMappingURL=copyable-cell.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copyable-cell.js","names":[],"sources":["../../../../resources/js/table/components/cells/copyable-cell.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { CopyableText } from \"@lattice-php/lattice/ui/copyable-text\";\nimport type { TableColumn } from \"@lattice-php/lattice/table/types\";\n\n/** Wrap cell content in a copy-to-clipboard affordance when `copyable` is set. */\nexport function CopyableCell({\n children,\n column,\n copyable,\n value,\n}: {\n children: ReactNode;\n column: TableColumn;\n copyable?: boolean | null;\n value: string;\n}): ReactNode {\n if (!copyable) {\n return children;\n }\n\n return (\n <CopyableText\n value={value}\n label={column.props.label ?? column.key}\n testId={`copy-${column.key}`}\n >\n {children}\n </CopyableText>\n );\n}\n"],"mappings":";;;;AAKA,SAAgB,aAAa,EAC3B,UACA,QACA,UACA,SAMY;CACZ,IAAI,CAAC,UACH,OAAO;CAGT,OACE,oBAAC,cAAD;EACS;EACP,OAAO,OAAO,MAAM,SAAS,OAAO;EACpC,QAAQ,QAAQ,OAAO;EAEtB;CACW,CAAA;AAElB"}
@@ -1,32 +1,21 @@
1
- import { useLocale } from "../../../i18n/locale.js";
2
- import { CopyableText } from "../../../ui/copyable-text.js";
3
- import { formatCell } from "../../lib/format.js";
4
- import { numericValue } from "../../../format/numeric.js";
5
- import { formatNumber } from "../../../format/number.js";
1
+ import { NumericCell } from "./numeric-cell.js";
6
2
  import { jsx } from "react/jsx-runtime";
7
3
  //#region resources/js/table/components/cells/money-cell.tsx
8
4
  var MoneyCell = ({ column, props, row, value }) => {
9
- const { locale } = useLocale();
10
- if (numericValue(value) === null) return /* @__PURE__ */ jsx("span", { children: formatCell(value, column) });
11
5
  const rawCode = props.currencyField ? row[props.currencyField] : void 0;
12
6
  const code = props.currency ?? (typeof rawCode === "string" ? rawCode : null);
13
- const content = /* @__PURE__ */ jsx("span", {
14
- className: "tabular-nums",
15
- children: formatNumber(value, {
7
+ return /* @__PURE__ */ jsx(NumericCell, {
8
+ column,
9
+ copyable: props.copyable,
10
+ value,
11
+ format: {
16
12
  kind: "number",
17
13
  notation: "standard",
18
14
  minimumFractionDigits: props.minimumFractionDigits,
19
15
  maximumFractionDigits: props.maximumFractionDigits,
20
16
  currency: code,
21
17
  unit: null
22
- }, locale)
23
- });
24
- if (!props.copyable) return content;
25
- return /* @__PURE__ */ jsx(CopyableText, {
26
- value: String(value),
27
- label: column.props.label ?? column.key,
28
- testId: `copy-${column.key}`,
29
- children: content
18
+ }
30
19
  });
31
20
  };
32
21
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"money-cell.js","names":[],"sources":["../../../../resources/js/table/components/cells/money-cell.tsx"],"sourcesContent":["import { useLocale } from \"@lattice-php/lattice/i18n\";\nimport { formatNumber } from \"@lattice-php/lattice/format/number\";\nimport { numericValue } from \"@lattice-php/lattice/format/numeric\";\nimport { formatCell } from \"@lattice-php/lattice/table/lib/format\";\nimport type { ColumnCellComponent } from \"@lattice-php/lattice/table/registry\";\nimport { CopyableText } from \"@lattice-php/lattice/ui/copyable-text\";\n\nexport const MoneyCell: ColumnCellComponent<\"column.money\"> = ({ column, props, row, value }) => {\n const { locale } = useLocale();\n\n if (numericValue(value) === null) {\n return <span>{formatCell(value, column)}</span>;\n }\n\n const rawCode = props.currencyField ? row[props.currencyField] : undefined;\n const code = props.currency ?? (typeof rawCode === \"string\" ? rawCode : null);\n\n const text = formatNumber(\n value,\n {\n kind: \"number\",\n notation: \"standard\",\n minimumFractionDigits: props.minimumFractionDigits,\n maximumFractionDigits: props.maximumFractionDigits,\n currency: code,\n unit: null,\n },\n locale,\n );\n\n const content = <span className=\"tabular-nums\">{text}</span>;\n\n if (!props.copyable) {\n return content;\n }\n\n return (\n <CopyableText\n value={String(value)}\n label={column.props.label ?? column.key}\n testId={`copy-${column.key}`}\n >\n {content}\n </CopyableText>\n );\n};\n"],"mappings":";;;;;;;AAOA,IAAa,aAAkD,EAAE,QAAQ,OAAO,KAAK,YAAY;CAC/F,MAAM,EAAE,WAAW,UAAU;CAE7B,IAAI,aAAa,KAAK,MAAM,MAC1B,OAAO,oBAAC,QAAD,EAAA,UAAO,WAAW,OAAO,MAAM,EAAQ,CAAA;CAGhD,MAAM,UAAU,MAAM,gBAAgB,IAAI,MAAM,iBAAiB,KAAA;CACjE,MAAM,OAAO,MAAM,aAAa,OAAO,YAAY,WAAW,UAAU;CAexE,MAAM,UAAU,oBAAC,QAAD;EAAM,WAAU;YAbnB,aACX,OACA;GACE,MAAM;GACN,UAAU;GACV,uBAAuB,MAAM;GAC7B,uBAAuB,MAAM;GAC7B,UAAU;GACV,MAAM;EACR,GACA,MAG8C;CAAW,CAAA;CAE3D,IAAI,CAAC,MAAM,UACT,OAAO;CAGT,OACE,oBAAC,cAAD;EACE,OAAO,OAAO,KAAK;EACnB,OAAO,OAAO,MAAM,SAAS,OAAO;EACpC,QAAQ,QAAQ,OAAO;YAEtB;CACW,CAAA;AAElB"}
1
+ {"version":3,"file":"money-cell.js","names":[],"sources":["../../../../resources/js/table/components/cells/money-cell.tsx"],"sourcesContent":["import type { ColumnCellComponent } from \"@lattice-php/lattice/table/registry\";\nimport { NumericCell } from \"./numeric-cell\";\n\nexport const MoneyCell: ColumnCellComponent<\"column.money\"> = ({ column, props, row, value }) => {\n const rawCode = props.currencyField ? row[props.currencyField] : undefined;\n const code = props.currency ?? (typeof rawCode === \"string\" ? rawCode : null);\n\n return (\n <NumericCell\n column={column}\n copyable={props.copyable}\n value={value}\n format={{\n kind: \"number\",\n notation: \"standard\",\n minimumFractionDigits: props.minimumFractionDigits,\n maximumFractionDigits: props.maximumFractionDigits,\n currency: code,\n unit: null,\n }}\n />\n );\n};\n"],"mappings":";;;AAGA,IAAa,aAAkD,EAAE,QAAQ,OAAO,KAAK,YAAY;CAC/F,MAAM,UAAU,MAAM,gBAAgB,IAAI,MAAM,iBAAiB,KAAA;CACjE,MAAM,OAAO,MAAM,aAAa,OAAO,YAAY,WAAW,UAAU;CAExE,OACE,oBAAC,aAAD;EACU;EACR,UAAU,MAAM;EACT;EACP,QAAQ;GACN,MAAM;GACN,UAAU;GACV,uBAAuB,MAAM;GAC7B,uBAAuB,MAAM;GAC7B,UAAU;GACV,MAAM;EACR;CACD,CAAA;AAEL"}
@@ -1,32 +1,19 @@
1
- import { useLocale } from "../../../i18n/locale.js";
2
- import { CopyableText } from "../../../ui/copyable-text.js";
3
- import { formatCell } from "../../lib/format.js";
4
- import { numericValue } from "../../../format/numeric.js";
5
- import { formatNumber } from "../../../format/number.js";
1
+ import { NumericCell } from "./numeric-cell.js";
6
2
  import { jsx } from "react/jsx-runtime";
7
3
  //#region resources/js/table/components/cells/number-cell.tsx
8
- var NumberCell = ({ column, props, value }) => {
9
- const { locale } = useLocale();
10
- if (numericValue(value) === null) return /* @__PURE__ */ jsx("span", { children: formatCell(value, column) });
11
- const content = /* @__PURE__ */ jsx("span", {
12
- className: "tabular-nums",
13
- children: formatNumber(value, {
14
- kind: "number",
15
- notation: props.compact ? "compact" : "standard",
16
- minimumFractionDigits: props.minimumFractionDigits,
17
- maximumFractionDigits: props.maximumFractionDigits,
18
- currency: null,
19
- unit: props.unit
20
- }, locale)
21
- });
22
- if (!props.copyable) return content;
23
- return /* @__PURE__ */ jsx(CopyableText, {
24
- value: String(value),
25
- label: column.props.label ?? column.key,
26
- testId: `copy-${column.key}`,
27
- children: content
28
- });
29
- };
4
+ var NumberCell = ({ column, props, value }) => /* @__PURE__ */ jsx(NumericCell, {
5
+ column,
6
+ copyable: props.copyable,
7
+ value,
8
+ format: {
9
+ kind: "number",
10
+ notation: props.compact ? "compact" : "standard",
11
+ minimumFractionDigits: props.minimumFractionDigits,
12
+ maximumFractionDigits: props.maximumFractionDigits,
13
+ currency: null,
14
+ unit: props.unit
15
+ }
16
+ });
30
17
  //#endregion
31
18
  export { NumberCell };
32
19
 
@@ -1 +1 @@
1
- {"version":3,"file":"number-cell.js","names":[],"sources":["../../../../resources/js/table/components/cells/number-cell.tsx"],"sourcesContent":["import { useLocale } from \"@lattice-php/lattice/i18n\";\nimport { formatNumber } from \"@lattice-php/lattice/format/number\";\nimport { numericValue } from \"@lattice-php/lattice/format/numeric\";\nimport { formatCell } from \"@lattice-php/lattice/table/lib/format\";\nimport type { ColumnCellComponent } from \"@lattice-php/lattice/table/registry\";\nimport { CopyableText } from \"@lattice-php/lattice/ui/copyable-text\";\n\nexport const NumberCell: ColumnCellComponent<\"column.number\"> = ({ column, props, value }) => {\n const { locale } = useLocale();\n\n if (numericValue(value) === null) {\n return <span>{formatCell(value, column)}</span>;\n }\n\n const text = formatNumber(\n value,\n {\n kind: \"number\",\n notation: props.compact ? \"compact\" : \"standard\",\n minimumFractionDigits: props.minimumFractionDigits,\n maximumFractionDigits: props.maximumFractionDigits,\n currency: null,\n unit: props.unit,\n },\n locale,\n );\n\n const content = <span className=\"tabular-nums\">{text}</span>;\n\n if (!props.copyable) {\n return content;\n }\n\n return (\n <CopyableText\n value={String(value)}\n label={column.props.label ?? column.key}\n testId={`copy-${column.key}`}\n >\n {content}\n </CopyableText>\n );\n};\n"],"mappings":";;;;;;;AAOA,IAAa,cAAoD,EAAE,QAAQ,OAAO,YAAY;CAC5F,MAAM,EAAE,WAAW,UAAU;CAE7B,IAAI,aAAa,KAAK,MAAM,MAC1B,OAAO,oBAAC,QAAD,EAAA,UAAO,WAAW,OAAO,MAAM,EAAQ,CAAA;CAgBhD,MAAM,UAAU,oBAAC,QAAD;EAAM,WAAU;YAbnB,aACX,OACA;GACE,MAAM;GACN,UAAU,MAAM,UAAU,YAAY;GACtC,uBAAuB,MAAM;GAC7B,uBAAuB,MAAM;GAC7B,UAAU;GACV,MAAM,MAAM;EACd,GACA,MAG8C;CAAW,CAAA;CAE3D,IAAI,CAAC,MAAM,UACT,OAAO;CAGT,OACE,oBAAC,cAAD;EACE,OAAO,OAAO,KAAK;EACnB,OAAO,OAAO,MAAM,SAAS,OAAO;EACpC,QAAQ,QAAQ,OAAO;YAEtB;CACW,CAAA;AAElB"}
1
+ {"version":3,"file":"number-cell.js","names":[],"sources":["../../../../resources/js/table/components/cells/number-cell.tsx"],"sourcesContent":["import type { ColumnCellComponent } from \"@lattice-php/lattice/table/registry\";\nimport { NumericCell } from \"./numeric-cell\";\n\nexport const NumberCell: ColumnCellComponent<\"column.number\"> = ({ column, props, value }) => (\n <NumericCell\n column={column}\n copyable={props.copyable}\n value={value}\n format={{\n kind: \"number\",\n notation: props.compact ? \"compact\" : \"standard\",\n minimumFractionDigits: props.minimumFractionDigits,\n maximumFractionDigits: props.maximumFractionDigits,\n currency: null,\n unit: props.unit,\n }}\n />\n);\n"],"mappings":";;;AAGA,IAAa,cAAoD,EAAE,QAAQ,OAAO,YAChF,oBAAC,aAAD;CACU;CACR,UAAU,MAAM;CACT;CACP,QAAQ;EACN,MAAM;EACN,UAAU,MAAM,UAAU,YAAY;EACtC,uBAAuB,MAAM;EAC7B,uBAAuB,MAAM;EAC7B,UAAU;EACV,MAAM,MAAM;CACd;AACD,CAAA"}
@@ -0,0 +1,10 @@
1
+ import { ReactNode } from 'react';
2
+ import { NumberFormat } from '../../../types/generated.js';
3
+ import { TableColumn } from '../../types.js';
4
+ /** Shared numeric cell body for the money and number columns. */
5
+ export declare function NumericCell({ column, copyable, format, value, }: {
6
+ column: TableColumn;
7
+ copyable?: boolean | null;
8
+ format: NumberFormat;
9
+ value: unknown;
10
+ }): ReactNode;
@@ -0,0 +1,25 @@
1
+ import { useLocale } from "../../../i18n/locale.js";
2
+ import { formatCell } from "../../lib/format.js";
3
+ import { numericValue } from "../../../format/numeric.js";
4
+ import { formatNumber } from "../../../format/number.js";
5
+ import { CopyableCell } from "./copyable-cell.js";
6
+ import { jsx } from "react/jsx-runtime";
7
+ //#region resources/js/table/components/cells/numeric-cell.tsx
8
+ /** Shared numeric cell body for the money and number columns. */
9
+ function NumericCell({ column, copyable, format, value }) {
10
+ const { locale } = useLocale();
11
+ if (numericValue(value) === null) return /* @__PURE__ */ jsx("span", { children: formatCell(value, column) });
12
+ return /* @__PURE__ */ jsx(CopyableCell, {
13
+ column,
14
+ copyable,
15
+ value: String(value),
16
+ children: /* @__PURE__ */ jsx("span", {
17
+ className: "tabular-nums",
18
+ children: formatNumber(value, format, locale)
19
+ })
20
+ });
21
+ }
22
+ //#endregion
23
+ export { NumericCell };
24
+
25
+ //# sourceMappingURL=numeric-cell.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"numeric-cell.js","names":[],"sources":["../../../../resources/js/table/components/cells/numeric-cell.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { useLocale } from \"@lattice-php/lattice/i18n\";\nimport type { NumberFormat } from \"@lattice-php/lattice/types/generated\";\nimport { formatNumber } from \"@lattice-php/lattice/format/number\";\nimport { numericValue } from \"@lattice-php/lattice/format/numeric\";\nimport { formatCell } from \"@lattice-php/lattice/table/lib/format\";\nimport type { TableColumn } from \"@lattice-php/lattice/table/types\";\nimport { CopyableCell } from \"./copyable-cell\";\n\n/** Shared numeric cell body for the money and number columns. */\nexport function NumericCell({\n column,\n copyable,\n format,\n value,\n}: {\n column: TableColumn;\n copyable?: boolean | null;\n format: NumberFormat;\n value: unknown;\n}): ReactNode {\n const { locale } = useLocale();\n\n if (numericValue(value) === null) {\n return <span>{formatCell(value, column)}</span>;\n }\n\n return (\n <CopyableCell column={column} copyable={copyable} value={String(value)}>\n <span className=\"tabular-nums\">{formatNumber(value, format, locale)}</span>\n </CopyableCell>\n );\n}\n"],"mappings":";;;;;;;;AAUA,SAAgB,YAAY,EAC1B,QACA,UACA,QACA,SAMY;CACZ,MAAM,EAAE,WAAW,UAAU;CAE7B,IAAI,aAAa,KAAK,MAAM,MAC1B,OAAO,oBAAC,QAAD,EAAA,UAAO,WAAW,OAAO,MAAM,EAAQ,CAAA;CAGhD,OACE,oBAAC,cAAD;EAAsB;EAAkB;EAAU,OAAO,OAAO,KAAK;YACnE,oBAAC,QAAD;GAAM,WAAU;aAAgB,aAAa,OAAO,QAAQ,MAAM;EAAQ,CAAA;CAC9D,CAAA;AAElB"}
@@ -1,5 +1,5 @@
1
- import { Renderer } from "../../../core/renderer.js";
2
1
  import { materializeSchema } from "../../../core/materialize.js";
2
+ import { Renderer } from "../../../core/renderer.js";
3
3
  import { jsx } from "react/jsx-runtime";
4
4
  //#region resources/js/table/components/cells/stack-cell.tsx
5
5
  var StackCell = ({ column, row }) => /* @__PURE__ */ jsx("div", {
@@ -1,8 +1,8 @@
1
1
  import { cn } from "../../../lib/utils.js";
2
2
  import { DateTime } from "../../../i18n/date-time.js";
3
- import { CopyableText } from "../../../ui/copyable-text.js";
4
3
  import { coerceColor, namedColor, toneProps } from "../../../lib/color.js";
5
4
  import { formatCell, resolveLink } from "../../lib/format.js";
5
+ import { CopyableCell } from "./copyable-cell.js";
6
6
  import { jsx } from "react/jsx-runtime";
7
7
  //#region resources/js/table/components/cells/text-cell.tsx
8
8
  var TextCell = (args) => {
@@ -57,11 +57,10 @@ function PlainTextCell({ column, props, row, value }) {
57
57
  dateStyle: dateProps.dateStyle,
58
58
  timeStyle: dateProps.timeStyle
59
59
  });
60
- if (!props.copyable) return content;
61
- return /* @__PURE__ */ jsx(CopyableText, {
60
+ return /* @__PURE__ */ jsx(CopyableCell, {
61
+ column,
62
+ copyable: props.copyable,
62
63
  value: text,
63
- label: column.props.label ?? column.key,
64
- testId: `copy-${column.key}`,
65
64
  children: content
66
65
  });
67
66
  }
@@ -1 +1 @@
1
- {"version":3,"file":"text-cell.js","names":[],"sources":["../../../../resources/js/table/components/cells/text-cell.tsx"],"sourcesContent":["import { DateTime } from \"@lattice-php/lattice/i18n\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport { coerceColor, namedColor, toneProps } from \"@lattice-php/lattice/lib/color\";\nimport { CopyableText } from \"@lattice-php/lattice/ui/copyable-text\";\nimport type { ReactNode } from \"react\";\nimport { formatCell, resolveLink } from \"@lattice-php/lattice/table/lib/format\";\nimport type { ColumnCellArgs, ColumnCellComponent } from \"@lattice-php/lattice/table/registry\";\nimport type { ColumnPropsOf } from \"@lattice-php/lattice/table/types\";\n\ntype TextProps = ColumnCellArgs<\"column.text\">[\"props\"];\n\nexport const TextCell: ColumnCellComponent<\"column.text\"> = (args) => {\n if (args.props.multiple) {\n return <MultipleCell {...args} />;\n }\n\n if (args.props.badge) {\n return <SingleBadgeCell {...args} />;\n }\n\n return <PlainTextCell {...args} />;\n};\n\nfunction Badge({ label, color }: { label: string; color?: string | null }): ReactNode {\n if (label === \"\") {\n return null;\n }\n\n const tone = toneProps(coerceColor(color) ?? namedColor(\"gray\"));\n\n return (\n <span className={cn(\"lt-cell-badge\", tone.className)} style={tone.style}>\n {label}\n </span>\n );\n}\n\nfunction MultipleCell({ column, props, value }: ColumnCellArgs<\"column.text\">): ReactNode {\n const items = Array.isArray(value) ? value : [];\n\n if (items.length === 0) {\n return null;\n }\n\n if (!props.badge) {\n return <span>{items.map((item) => formatCell(item, column)).join(\", \")}</span>;\n }\n\n return (\n <div className=\"flex flex-wrap gap-1\">\n {items.map((item, index) => {\n const chip = item as { value: unknown; color?: string };\n\n return <Badge key={index} label={formatCell(chip.value, column)} color={chip.color} />;\n })}\n </div>\n );\n}\n\nfunction SingleBadgeCell({ column, props, row, value }: ColumnCellArgs<\"column.text\">): ReactNode {\n const colorKey = (props.badge as NonNullable<TextProps[\"badge\"]>).colorKey;\n\n return <Badge label={formatCell(value, column)} color={String(row[colorKey] ?? \"\")} />;\n}\n\nfunction PlainTextCell({ column, props, row, value }: ColumnCellArgs<\"column.text\">): ReactNode {\n const dateProps = (column.props as ColumnPropsOf<\"column.text\">).date;\n const href = resolveLink(column, row, value);\n const text = formatCell(value, column);\n\n const content = href ? (\n <a\n className=\"underline underline-offset-2\"\n href={href}\n rel={props.link?.external ? \"noreferrer\" : undefined}\n target={props.link?.external ? \"_blank\" : undefined}\n >\n {text}\n </a>\n ) : (\n text\n );\n\n if (dateProps && !href && !props.copyable && value !== null && value !== undefined) {\n return (\n <DateTime value={value} dateStyle={dateProps.dateStyle} timeStyle={dateProps.timeStyle} />\n );\n }\n\n if (!props.copyable) {\n return content;\n }\n\n return (\n <CopyableText\n value={text}\n label={column.props.label ?? column.key}\n testId={`copy-${column.key}`}\n >\n {content}\n </CopyableText>\n );\n}\n"],"mappings":";;;;;;;AAWA,IAAa,YAAgD,SAAS;CACpE,IAAI,KAAK,MAAM,UACb,OAAO,oBAAC,cAAD,EAAc,GAAI,KAAO,CAAA;CAGlC,IAAI,KAAK,MAAM,OACb,OAAO,oBAAC,iBAAD,EAAiB,GAAI,KAAO,CAAA;CAGrC,OAAO,oBAAC,eAAD,EAAe,GAAI,KAAO,CAAA;AACnC;AAEA,SAAS,MAAM,EAAE,OAAO,SAA8D;CACpF,IAAI,UAAU,IACZ,OAAO;CAGT,MAAM,OAAO,UAAU,YAAY,KAAK,KAAK,WAAW,MAAM,CAAC;CAE/D,OACE,oBAAC,QAAD;EAAM,WAAW,GAAG,iBAAiB,KAAK,SAAS;EAAG,OAAO,KAAK;YAC/D;CACG,CAAA;AAEV;AAEA,SAAS,aAAa,EAAE,QAAQ,OAAO,SAAmD;CACxF,MAAM,QAAQ,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC;CAE9C,IAAI,MAAM,WAAW,GACnB,OAAO;CAGT,IAAI,CAAC,MAAM,OACT,OAAO,oBAAC,QAAD,EAAA,UAAO,MAAM,KAAK,SAAS,WAAW,MAAM,MAAM,CAAC,EAAE,KAAK,IAAI,EAAQ,CAAA;CAG/E,OACE,oBAAC,OAAD;EAAK,WAAU;YACZ,MAAM,KAAK,MAAM,UAAU;GAC1B,MAAM,OAAO;GAEb,OAAO,oBAAC,OAAD;IAAmB,OAAO,WAAW,KAAK,OAAO,MAAM;IAAG,OAAO,KAAK;GAAQ,GAAlE,KAAkE;EACvF,CAAC;CACE,CAAA;AAET;AAEA,SAAS,gBAAgB,EAAE,QAAQ,OAAO,KAAK,SAAmD;CAChG,MAAM,WAAY,MAAM,MAA0C;CAElE,OAAO,oBAAC,OAAD;EAAO,OAAO,WAAW,OAAO,MAAM;EAAG,OAAO,OAAO,IAAI,aAAa,EAAE;CAAI,CAAA;AACvF;AAEA,SAAS,cAAc,EAAE,QAAQ,OAAO,KAAK,SAAmD;CAC9F,MAAM,YAAa,OAAO,MAAuC;CACjE,MAAM,OAAO,YAAY,QAAQ,KAAK,KAAK;CAC3C,MAAM,OAAO,WAAW,OAAO,MAAM;CAErC,MAAM,UAAU,OACd,oBAAC,KAAD;EACE,WAAU;EACJ;EACN,KAAK,MAAM,MAAM,WAAW,eAAe,KAAA;EAC3C,QAAQ,MAAM,MAAM,WAAW,WAAW,KAAA;YAEzC;CACA,CAAA,IAEH;CAGF,IAAI,aAAa,CAAC,QAAQ,CAAC,MAAM,YAAY,UAAU,QAAQ,UAAU,KAAA,GACvE,OACE,oBAAC,UAAD;EAAiB;EAAO,WAAW,UAAU;EAAW,WAAW,UAAU;CAAY,CAAA;CAI7F,IAAI,CAAC,MAAM,UACT,OAAO;CAGT,OACE,oBAAC,cAAD;EACE,OAAO;EACP,OAAO,OAAO,MAAM,SAAS,OAAO;EACpC,QAAQ,QAAQ,OAAO;YAEtB;CACW,CAAA;AAElB"}
1
+ {"version":3,"file":"text-cell.js","names":[],"sources":["../../../../resources/js/table/components/cells/text-cell.tsx"],"sourcesContent":["import { DateTime } from \"@lattice-php/lattice/i18n\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport { coerceColor, namedColor, toneProps } from \"@lattice-php/lattice/lib/color\";\nimport type { ReactNode } from \"react\";\nimport { formatCell, resolveLink } from \"@lattice-php/lattice/table/lib/format\";\nimport type { ColumnCellArgs, ColumnCellComponent } from \"@lattice-php/lattice/table/registry\";\nimport type { ColumnPropsOf } from \"@lattice-php/lattice/table/types\";\nimport { CopyableCell } from \"./copyable-cell\";\n\ntype TextProps = ColumnCellArgs<\"column.text\">[\"props\"];\n\nexport const TextCell: ColumnCellComponent<\"column.text\"> = (args) => {\n if (args.props.multiple) {\n return <MultipleCell {...args} />;\n }\n\n if (args.props.badge) {\n return <SingleBadgeCell {...args} />;\n }\n\n return <PlainTextCell {...args} />;\n};\n\nfunction Badge({ label, color }: { label: string; color?: string | null }): ReactNode {\n if (label === \"\") {\n return null;\n }\n\n const tone = toneProps(coerceColor(color) ?? namedColor(\"gray\"));\n\n return (\n <span className={cn(\"lt-cell-badge\", tone.className)} style={tone.style}>\n {label}\n </span>\n );\n}\n\nfunction MultipleCell({ column, props, value }: ColumnCellArgs<\"column.text\">): ReactNode {\n const items = Array.isArray(value) ? value : [];\n\n if (items.length === 0) {\n return null;\n }\n\n if (!props.badge) {\n return <span>{items.map((item) => formatCell(item, column)).join(\", \")}</span>;\n }\n\n return (\n <div className=\"flex flex-wrap gap-1\">\n {items.map((item, index) => {\n const chip = item as { value: unknown; color?: string };\n\n return <Badge key={index} label={formatCell(chip.value, column)} color={chip.color} />;\n })}\n </div>\n );\n}\n\nfunction SingleBadgeCell({ column, props, row, value }: ColumnCellArgs<\"column.text\">): ReactNode {\n const colorKey = (props.badge as NonNullable<TextProps[\"badge\"]>).colorKey;\n\n return <Badge label={formatCell(value, column)} color={String(row[colorKey] ?? \"\")} />;\n}\n\nfunction PlainTextCell({ column, props, row, value }: ColumnCellArgs<\"column.text\">): ReactNode {\n const dateProps = (column.props as ColumnPropsOf<\"column.text\">).date;\n const href = resolveLink(column, row, value);\n const text = formatCell(value, column);\n\n const content = href ? (\n <a\n className=\"underline underline-offset-2\"\n href={href}\n rel={props.link?.external ? \"noreferrer\" : undefined}\n target={props.link?.external ? \"_blank\" : undefined}\n >\n {text}\n </a>\n ) : (\n text\n );\n\n if (dateProps && !href && !props.copyable && value !== null && value !== undefined) {\n return (\n <DateTime value={value} dateStyle={dateProps.dateStyle} timeStyle={dateProps.timeStyle} />\n );\n }\n\n return (\n <CopyableCell column={column} copyable={props.copyable} value={text}>\n {content}\n </CopyableCell>\n );\n}\n"],"mappings":";;;;;;;AAWA,IAAa,YAAgD,SAAS;CACpE,IAAI,KAAK,MAAM,UACb,OAAO,oBAAC,cAAD,EAAc,GAAI,KAAO,CAAA;CAGlC,IAAI,KAAK,MAAM,OACb,OAAO,oBAAC,iBAAD,EAAiB,GAAI,KAAO,CAAA;CAGrC,OAAO,oBAAC,eAAD,EAAe,GAAI,KAAO,CAAA;AACnC;AAEA,SAAS,MAAM,EAAE,OAAO,SAA8D;CACpF,IAAI,UAAU,IACZ,OAAO;CAGT,MAAM,OAAO,UAAU,YAAY,KAAK,KAAK,WAAW,MAAM,CAAC;CAE/D,OACE,oBAAC,QAAD;EAAM,WAAW,GAAG,iBAAiB,KAAK,SAAS;EAAG,OAAO,KAAK;YAC/D;CACG,CAAA;AAEV;AAEA,SAAS,aAAa,EAAE,QAAQ,OAAO,SAAmD;CACxF,MAAM,QAAQ,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC;CAE9C,IAAI,MAAM,WAAW,GACnB,OAAO;CAGT,IAAI,CAAC,MAAM,OACT,OAAO,oBAAC,QAAD,EAAA,UAAO,MAAM,KAAK,SAAS,WAAW,MAAM,MAAM,CAAC,EAAE,KAAK,IAAI,EAAQ,CAAA;CAG/E,OACE,oBAAC,OAAD;EAAK,WAAU;YACZ,MAAM,KAAK,MAAM,UAAU;GAC1B,MAAM,OAAO;GAEb,OAAO,oBAAC,OAAD;IAAmB,OAAO,WAAW,KAAK,OAAO,MAAM;IAAG,OAAO,KAAK;GAAQ,GAAlE,KAAkE;EACvF,CAAC;CACE,CAAA;AAET;AAEA,SAAS,gBAAgB,EAAE,QAAQ,OAAO,KAAK,SAAmD;CAChG,MAAM,WAAY,MAAM,MAA0C;CAElE,OAAO,oBAAC,OAAD;EAAO,OAAO,WAAW,OAAO,MAAM;EAAG,OAAO,OAAO,IAAI,aAAa,EAAE;CAAI,CAAA;AACvF;AAEA,SAAS,cAAc,EAAE,QAAQ,OAAO,KAAK,SAAmD;CAC9F,MAAM,YAAa,OAAO,MAAuC;CACjE,MAAM,OAAO,YAAY,QAAQ,KAAK,KAAK;CAC3C,MAAM,OAAO,WAAW,OAAO,MAAM;CAErC,MAAM,UAAU,OACd,oBAAC,KAAD;EACE,WAAU;EACJ;EACN,KAAK,MAAM,MAAM,WAAW,eAAe,KAAA;EAC3C,QAAQ,MAAM,MAAM,WAAW,WAAW,KAAA;YAEzC;CACA,CAAA,IAEH;CAGF,IAAI,aAAa,CAAC,QAAQ,CAAC,MAAM,YAAY,UAAU,QAAQ,UAAU,KAAA,GACvE,OACE,oBAAC,UAAD;EAAiB;EAAO,WAAW,UAAU;EAAW,WAAW,UAAU;CAAY,CAAA;CAI7F,OACE,oBAAC,cAAD;EAAsB;EAAQ,UAAU,MAAM;EAAU,OAAO;YAC5D;CACW,CAAA;AAElB"}
@@ -11,6 +11,7 @@ import { TableCellProvider } from "../../form/hooks/row-layout-context.js";
11
11
  import { Checkbox } from "../../ui/checkbox.js";
12
12
  import { IconButton } from "../../ui/icon-button.js";
13
13
  import { filterValue, isActiveFilterValue } from "../lib/filter-values.js";
14
+ import { isTruthy } from "../../lib/is-truthy.js";
14
15
  import { useCallback, useMemo, useRef } from "react";
15
16
  import { jsx, jsxs } from "react/jsx-runtime";
16
17
  //#region resources/js/table/components/filter-controls.tsx
@@ -120,9 +121,6 @@ function ToggleControl({ filter, value, processing, onChange }) {
120
121
  }), /* @__PURE__ */ jsx("span", { children: filter.props.label })]
121
122
  });
122
123
  }
123
- function isTruthy(value) {
124
- return value === true || value === "1" || value === 1 || value === "true";
125
- }
126
124
  //#endregion
127
125
  export { TableFilterControl };
128
126
 
@@ -1 +1 @@
1
- {"version":3,"file":"filter-controls.js","names":[],"sources":["../../../resources/js/table/components/filter-controls.tsx"],"sourcesContent":["import { useCallback, useMemo, useRef } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { Checkbox } from \"@lattice-php/lattice/ui/checkbox\";\nimport { Renderer } from \"@lattice-php/lattice/core/renderer\";\nimport type { Node, Option } from \"@lattice-php/lattice/core/types\";\nimport {\n FieldCommitOverrideProvider,\n FormProvider,\n FormValuesProvider,\n getPath,\n PrefillProvider,\n ResolvedNodesProvider,\n setPath,\n TableCellProvider,\n useFormValues,\n useSetFormValue,\n} from \"@lattice-php/lattice/form/embed\";\nimport { IconButton } from \"@lattice-php/lattice/ui/icon-button\";\nimport { useT } from \"@lattice-php/lattice/i18n\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport { filterValue, isActiveFilterValue } from \"@lattice-php/lattice/table/lib/filter-values\";\nimport type { FilterNode } from \"@lattice-php/lattice/table/types\";\n\nexport type FilterOptionSearch = (\n field: string,\n query: string,\n signal: AbortSignal,\n) => Promise<Option[]>;\n\ntype FilterValue = Record<string, unknown>;\n\nexport function TableFilterControl({\n filter,\n value,\n processing,\n bare = false,\n onChange,\n onSearch,\n}: {\n filter: FilterNode;\n value: unknown;\n processing: boolean;\n bare?: boolean;\n onChange: (value: unknown) => void;\n onSearch?: FilterOptionSearch;\n}) {\n const { t } = useT(\"lattice\");\n const schema = filter.schema ?? [];\n\n if (schema.length === 0) {\n return (\n <ToggleControl filter={filter} value={value} processing={processing} onChange={onChange} />\n );\n }\n\n return (\n <div className=\"flex items-end gap-2\">\n <div className=\"min-w-0 flex-1\">\n <SchemaControl\n filter={filter}\n schema={schema}\n value={value}\n processing={processing}\n bare={bare}\n onChange={onChange}\n onSearch={onSearch}\n />\n </div>\n {isActiveFilterValue(value) && (\n <IconButton\n size=\"md\"\n icon=\"x\"\n label={t(\"table.filter.clear\", \"Clear {{label}} filter\", {\n label: filter.props.label ?? \"\",\n })}\n disabled={processing}\n onClick={() => onChange(undefined)}\n />\n )}\n </div>\n );\n}\n\nfunction SchemaControl({\n filter,\n schema,\n value,\n processing,\n bare,\n onChange,\n onSearch,\n}: {\n filter: FilterNode;\n schema: Node[];\n value: unknown;\n processing: boolean;\n bare: boolean;\n onChange: (value: unknown) => void;\n onSearch?: FilterOptionSearch;\n}) {\n const initial = useMemo(() => filterValue(value), [value]);\n const form = useMemo(\n () => ({\n action: \"#\",\n clearErrors: () => {},\n componentId: `table-filter-${filter.key}`,\n componentRef: \"\",\n errors: {},\n fieldIdPrefix: `table-filter-${filter.key}`,\n fieldLabels: {},\n precognitive: false,\n processing,\n searchOptions: (\n field: string,\n query: string,\n _values: Record<string, unknown>,\n signal: AbortSignal,\n ) => (onSearch ? onSearch(field, query, signal) : Promise.resolve([])),\n validate: () => {},\n }),\n [filter.key, onSearch, processing],\n );\n\n const content = (\n <div\n aria-disabled={processing}\n className={cn(\"grid gap-3\", processing && \"pointer-events-none opacity-60\")}\n >\n <Renderer nodes={schema} />\n </div>\n );\n\n return (\n <FormProvider value={form}>\n <PrefillProvider value={{ markUserEdit: () => {} }}>\n <ResolvedNodesProvider nodes={{}}>\n <FormValuesProvider initial={initial}>\n <TableFilterCommitBridge onChange={onChange}>\n {bare ? <TableCellProvider>{content}</TableCellProvider> : content}\n </TableFilterCommitBridge>\n </FormValuesProvider>\n </ResolvedNodesProvider>\n </PrefillProvider>\n </FormProvider>\n );\n}\n\nfunction TableFilterCommitBridge({\n children,\n onChange,\n}: {\n children: ReactNode;\n onChange: (value: FilterValue) => void;\n}) {\n const values = useFormValues();\n const setValue = useSetFormValue();\n const valuesRef = useRef(values);\n valuesRef.current = values;\n\n const write = useCallback(\n (name: string, value: unknown) => {\n const nextValue =\n typeof value === \"function\"\n ? (value as (previous: unknown) => unknown)(getPath(valuesRef.current, name))\n : value;\n const next = setPath(valuesRef.current, name, nextValue);\n\n valuesRef.current = next;\n setValue(name, nextValue);\n onChange(next);\n },\n [onChange, setValue],\n );\n\n const commit = useMemo(\n () => ({\n blur: () => {},\n change: write,\n commit: write,\n }),\n [write],\n );\n\n return <FieldCommitOverrideProvider value={commit}>{children}</FieldCommitOverrideProvider>;\n}\n\nfunction ToggleControl({\n filter,\n value,\n processing,\n onChange,\n}: {\n filter: FilterNode;\n value: unknown;\n processing: boolean;\n onChange: (value: unknown) => void;\n}) {\n const checked = isTruthy(filterValue(value).value);\n\n return (\n <label className=\"flex h-lt-control-md cursor-pointer items-center gap-2 text-sm\">\n <Checkbox\n aria-label={filter.props.label ?? undefined}\n data-test={`table-filter-${filter.key}`}\n checked={checked}\n disabled={processing}\n onCheckedChange={(next) => onChange(next === true ? { value: \"1\" } : undefined)}\n />\n <span>{filter.props.label}</span>\n </label>\n );\n}\n\nfunction isTruthy(value: unknown): boolean {\n return value === true || value === \"1\" || value === 1 || value === \"true\";\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"filter-controls.js","names":[],"sources":["../../../resources/js/table/components/filter-controls.tsx"],"sourcesContent":["import { useCallback, useMemo, useRef } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { Checkbox } from \"@lattice-php/lattice/ui/checkbox\";\nimport { Renderer } from \"@lattice-php/lattice/core/renderer\";\nimport type { Node, Option } from \"@lattice-php/lattice/core/types\";\nimport {\n FieldCommitOverrideProvider,\n FormProvider,\n FormValuesProvider,\n getPath,\n PrefillProvider,\n ResolvedNodesProvider,\n setPath,\n TableCellProvider,\n useFormValues,\n useSetFormValue,\n} from \"@lattice-php/lattice/form/embed\";\nimport { IconButton } from \"@lattice-php/lattice/ui/icon-button\";\nimport { useT } from \"@lattice-php/lattice/i18n\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport { isTruthy } from \"@lattice-php/lattice/lib/is-truthy\";\nimport { filterValue, isActiveFilterValue } from \"@lattice-php/lattice/table/lib/filter-values\";\nimport type { FilterNode } from \"@lattice-php/lattice/table/types\";\n\nexport type FilterOptionSearch = (\n field: string,\n query: string,\n signal: AbortSignal,\n) => Promise<Option[]>;\n\ntype FilterValue = Record<string, unknown>;\n\nexport function TableFilterControl({\n filter,\n value,\n processing,\n bare = false,\n onChange,\n onSearch,\n}: {\n filter: FilterNode;\n value: unknown;\n processing: boolean;\n bare?: boolean;\n onChange: (value: unknown) => void;\n onSearch?: FilterOptionSearch;\n}) {\n const { t } = useT(\"lattice\");\n const schema = filter.schema ?? [];\n\n if (schema.length === 0) {\n return (\n <ToggleControl filter={filter} value={value} processing={processing} onChange={onChange} />\n );\n }\n\n return (\n <div className=\"flex items-end gap-2\">\n <div className=\"min-w-0 flex-1\">\n <SchemaControl\n filter={filter}\n schema={schema}\n value={value}\n processing={processing}\n bare={bare}\n onChange={onChange}\n onSearch={onSearch}\n />\n </div>\n {isActiveFilterValue(value) && (\n <IconButton\n size=\"md\"\n icon=\"x\"\n label={t(\"table.filter.clear\", \"Clear {{label}} filter\", {\n label: filter.props.label ?? \"\",\n })}\n disabled={processing}\n onClick={() => onChange(undefined)}\n />\n )}\n </div>\n );\n}\n\nfunction SchemaControl({\n filter,\n schema,\n value,\n processing,\n bare,\n onChange,\n onSearch,\n}: {\n filter: FilterNode;\n schema: Node[];\n value: unknown;\n processing: boolean;\n bare: boolean;\n onChange: (value: unknown) => void;\n onSearch?: FilterOptionSearch;\n}) {\n const initial = useMemo(() => filterValue(value), [value]);\n const form = useMemo(\n () => ({\n action: \"#\",\n clearErrors: () => {},\n componentId: `table-filter-${filter.key}`,\n componentRef: \"\",\n errors: {},\n fieldIdPrefix: `table-filter-${filter.key}`,\n fieldLabels: {},\n precognitive: false,\n processing,\n searchOptions: (\n field: string,\n query: string,\n _values: Record<string, unknown>,\n signal: AbortSignal,\n ) => (onSearch ? onSearch(field, query, signal) : Promise.resolve([])),\n validate: () => {},\n }),\n [filter.key, onSearch, processing],\n );\n\n const content = (\n <div\n aria-disabled={processing}\n className={cn(\"grid gap-3\", processing && \"pointer-events-none opacity-60\")}\n >\n <Renderer nodes={schema} />\n </div>\n );\n\n return (\n <FormProvider value={form}>\n <PrefillProvider value={{ markUserEdit: () => {} }}>\n <ResolvedNodesProvider nodes={{}}>\n <FormValuesProvider initial={initial}>\n <TableFilterCommitBridge onChange={onChange}>\n {bare ? <TableCellProvider>{content}</TableCellProvider> : content}\n </TableFilterCommitBridge>\n </FormValuesProvider>\n </ResolvedNodesProvider>\n </PrefillProvider>\n </FormProvider>\n );\n}\n\nfunction TableFilterCommitBridge({\n children,\n onChange,\n}: {\n children: ReactNode;\n onChange: (value: FilterValue) => void;\n}) {\n const values = useFormValues();\n const setValue = useSetFormValue();\n const valuesRef = useRef(values);\n valuesRef.current = values;\n\n const write = useCallback(\n (name: string, value: unknown) => {\n const nextValue =\n typeof value === \"function\"\n ? (value as (previous: unknown) => unknown)(getPath(valuesRef.current, name))\n : value;\n const next = setPath(valuesRef.current, name, nextValue);\n\n valuesRef.current = next;\n setValue(name, nextValue);\n onChange(next);\n },\n [onChange, setValue],\n );\n\n const commit = useMemo(\n () => ({\n blur: () => {},\n change: write,\n commit: write,\n }),\n [write],\n );\n\n return <FieldCommitOverrideProvider value={commit}>{children}</FieldCommitOverrideProvider>;\n}\n\nfunction ToggleControl({\n filter,\n value,\n processing,\n onChange,\n}: {\n filter: FilterNode;\n value: unknown;\n processing: boolean;\n onChange: (value: unknown) => void;\n}) {\n const checked = isTruthy(filterValue(value).value);\n\n return (\n <label className=\"flex h-lt-control-md cursor-pointer items-center gap-2 text-sm\">\n <Checkbox\n aria-label={filter.props.label ?? undefined}\n data-test={`table-filter-${filter.key}`}\n checked={checked}\n disabled={processing}\n onCheckedChange={(next) => onChange(next === true ? { value: \"1\" } : undefined)}\n />\n <span>{filter.props.label}</span>\n </label>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"table-cell.js","names":[],"sources":["../../../resources/js/table/components/table-cell.tsx"],"sourcesContent":["import { useColumnRegistry } from \"@lattice-php/lattice/core/registry-context\";\nimport type { ColumnType } from \"@lattice-php/lattice/types/generated\";\nimport {\n columnCell,\n type ColumnRegistry,\n type ColumnRegistryFor,\n} from \"@lattice-php/lattice/table/registry\";\nimport type { TableColumn, TableRow } from \"@lattice-php/lattice/table/types\";\nimport { BadgeCell } from \"./cells/badge-cell\";\nimport { BooleanCell } from \"./cells/boolean-cell\";\nimport { IconCell } from \"./cells/icon-cell\";\nimport { ImageCell } from \"./cells/image-cell\";\nimport { MoneyCell } from \"./cells/money-cell\";\nimport { NumberCell } from \"./cells/number-cell\";\nimport { StackCell } from \"./cells/stack-cell\";\nimport { TextCell } from \"./cells/text-cell\";\n\n// Built-in cells live with the (lazy-loaded) table feature rather than the\n// eager registry, so they stay code-split. Consumer-registered columns are\n// merged on top and win on type collisions.\nconst builtinColumnCells: ColumnRegistry = {\n \"column.badge\": columnCell(BadgeCell),\n \"column.boolean\": columnCell(BooleanCell),\n \"column.icon\": columnCell(IconCell),\n \"column.image\": columnCell(ImageCell),\n \"column.money\": columnCell(MoneyCell),\n \"column.number\": columnCell(NumberCell),\n \"column.stack\": columnCell(StackCell),\n \"column.text\": columnCell(TextCell),\n} satisfies ColumnRegistryFor<ColumnType>;\n\nexport function ColumnCell({ column, row }: { column: TableColumn; row: TableRow }) {\n const customCells = useColumnRegistry();\n const Cell =\n customCells[column.type] ??\n builtinColumnCells[column.type] ??\n builtinColumnCells[\"column.text\"];\n\n return <Cell column={column} props={column.props} row={row} value={row[column.key]} />;\n}\n"],"mappings":";;;;;;;;;;;;AAoBA,IAAM,qBAAqC;CACzC,gBAAgB,WAAW,SAAS;CACpC,kBAAkB,WAAW,WAAW;CACxC,eAAe,WAAW,QAAQ;CAClC,gBAAgB,WAAW,SAAS;CACpC,gBAAgB,WAAW,SAAS;CACpC,iBAAiB,WAAW,UAAU;CACtC,gBAAgB,WAAW,SAAS;CACpC,eAAe,WAAW,QAAQ;AACpC;AAEA,SAAgB,WAAW,EAAE,QAAQ,OAA+C;CAOlF,OAAO,oBANa,kBAElB,EAAY,OAAO,SACnB,mBAAmB,OAAO,SAC1B,mBAAmB,gBAEd;EAAc;EAAQ,OAAO,OAAO;EAAY;EAAK,OAAO,IAAI,OAAO;CAAO,CAAA;AACvF"}
1
+ {"version":3,"file":"table-cell.js","names":[],"sources":["../../../resources/js/table/components/table-cell.tsx"],"sourcesContent":["import { useColumnRegistry } from \"@lattice-php/lattice/core/registry-context\";\nimport type { ColumnNodeType } from \"@lattice-php/lattice/types/generated\";\nimport {\n columnCell,\n type ColumnRegistry,\n type ColumnRegistryFor,\n} from \"@lattice-php/lattice/table/registry\";\nimport type { TableColumn, TableRow } from \"@lattice-php/lattice/table/types\";\nimport { BadgeCell } from \"./cells/badge-cell\";\nimport { BooleanCell } from \"./cells/boolean-cell\";\nimport { IconCell } from \"./cells/icon-cell\";\nimport { ImageCell } from \"./cells/image-cell\";\nimport { MoneyCell } from \"./cells/money-cell\";\nimport { NumberCell } from \"./cells/number-cell\";\nimport { StackCell } from \"./cells/stack-cell\";\nimport { TextCell } from \"./cells/text-cell\";\n\n// Built-in cells live with the (lazy-loaded) table feature rather than the\n// eager registry, so they stay code-split. Consumer-registered columns are\n// merged on top and win on type collisions.\nconst builtinColumnCells: ColumnRegistry = {\n \"column.badge\": columnCell(BadgeCell),\n \"column.boolean\": columnCell(BooleanCell),\n \"column.icon\": columnCell(IconCell),\n \"column.image\": columnCell(ImageCell),\n \"column.money\": columnCell(MoneyCell),\n \"column.number\": columnCell(NumberCell),\n \"column.stack\": columnCell(StackCell),\n \"column.text\": columnCell(TextCell),\n} satisfies ColumnRegistryFor<ColumnNodeType>;\n\nexport function ColumnCell({ column, row }: { column: TableColumn; row: TableRow }) {\n const customCells = useColumnRegistry();\n const Cell =\n customCells[column.type] ??\n builtinColumnCells[column.type] ??\n builtinColumnCells[\"column.text\"];\n\n return <Cell column={column} props={column.props} row={row} value={row[column.key]} />;\n}\n"],"mappings":";;;;;;;;;;;;AAoBA,IAAM,qBAAqC;CACzC,gBAAgB,WAAW,SAAS;CACpC,kBAAkB,WAAW,WAAW;CACxC,eAAe,WAAW,QAAQ;CAClC,gBAAgB,WAAW,SAAS;CACpC,gBAAgB,WAAW,SAAS;CACpC,iBAAiB,WAAW,UAAU;CACtC,gBAAgB,WAAW,SAAS;CACpC,eAAe,WAAW,QAAQ;AACpC;AAEA,SAAgB,WAAW,EAAE,QAAQ,OAA+C;CAOlF,OAAO,oBANa,kBAElB,EAAY,OAAO,SACnB,mBAAmB,OAAO,SAC1B,mBAAmB,gBAEd;EAAc;EAAQ,OAAO,OAAO;EAAY;EAAK,OAAO,IAAI,OAAO;CAAO,CAAA;AACvF"}
@@ -1,6 +1,7 @@
1
1
  import { cn } from "../../lib/utils.js";
2
2
  import { Icon } from "../../icons/sprite.js";
3
3
  import { useT } from "../../i18n/instance.js";
4
+ import { useDebouncedCallback } from "../../lib/use-debounced-callback.js";
4
5
  import { Input } from "../../ui/input.js";
5
6
  import { IconButton } from "../../ui/icon-button.js";
6
7
  import { useEffect, useRef, useState } from "react";
@@ -15,7 +16,6 @@ var DEBOUNCE_MS = 300;
15
16
  function TableSearch({ value, onSearch }) {
16
17
  const { t } = useT("lattice");
17
18
  const [term, setTerm] = useState(value);
18
- const timer = useRef(null);
19
19
  const committed = useRef(value);
20
20
  useEffect(() => {
21
21
  if (value !== committed.current) {
@@ -23,20 +23,17 @@ function TableSearch({ value, onSearch }) {
23
23
  setTerm(value);
24
24
  }
25
25
  }, [value]);
26
- useEffect(() => () => {
27
- if (timer.current) clearTimeout(timer.current);
28
- }, []);
29
26
  function commit(next) {
30
27
  committed.current = next;
31
28
  onSearch(next);
32
29
  }
30
+ const commitDebounced = useDebouncedCallback(commit, DEBOUNCE_MS);
33
31
  function change(next) {
34
32
  setTerm(next);
35
- if (timer.current) clearTimeout(timer.current);
36
- timer.current = setTimeout(() => commit(next), DEBOUNCE_MS);
33
+ commitDebounced(next);
37
34
  }
38
35
  function clear() {
39
- if (timer.current) clearTimeout(timer.current);
36
+ commitDebounced.cancel();
40
37
  setTerm("");
41
38
  commit("");
42
39
  }
@@ -1 +1 @@
1
- {"version":3,"file":"table-search.js","names":[],"sources":["../../../resources/js/table/components/table-search.tsx"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport { Icon } from \"@lattice-php/lattice/icons\";\nimport { IconButton } from \"@lattice-php/lattice/ui/icon-button\";\nimport { Input } from \"@lattice-php/lattice/ui/input\";\nimport { useT } from \"@lattice-php/lattice/i18n\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\n\nconst DEBOUNCE_MS = 300;\n\n/**\n * The table-level quick-search box. Keystrokes update the input immediately and\n * commit the term to the server after a short debounce; an externally-changed\n * value (e.g. a filter reset) is adopted without echoing keystroke round-trips.\n */\nexport function TableSearch({\n value,\n onSearch,\n}: {\n value: string;\n onSearch: (term: string) => void;\n}) {\n const { t } = useT(\"lattice\");\n const [term, setTerm] = useState(value);\n const timer = useRef<ReturnType<typeof setTimeout> | null>(null);\n const committed = useRef(value);\n\n useEffect(() => {\n if (value !== committed.current) {\n committed.current = value;\n setTerm(value);\n }\n }, [value]);\n\n useEffect(\n () => () => {\n if (timer.current) {\n clearTimeout(timer.current);\n }\n },\n [],\n );\n\n function commit(next: string): void {\n committed.current = next;\n onSearch(next);\n }\n\n function change(next: string): void {\n setTerm(next);\n\n if (timer.current) {\n clearTimeout(timer.current);\n }\n\n timer.current = setTimeout(() => commit(next), DEBOUNCE_MS);\n }\n\n function clear(): void {\n if (timer.current) {\n clearTimeout(timer.current);\n }\n\n setTerm(\"\");\n commit(\"\");\n }\n\n const label = t(\"table.search.placeholder\", \"Search\");\n\n return (\n <div className=\"relative w-full max-w-xs\">\n <Icon\n name=\"search\"\n aria-hidden=\"true\"\n className=\"pointer-events-none absolute left-2.5 top-1/2 size-lt-icon-sm -translate-y-1/2 text-lt-muted-fg\"\n />\n <Input\n type=\"search\"\n data-test=\"table-search\"\n value={term}\n placeholder={label}\n aria-label={label}\n onChange={(event) => change(event.target.value)}\n className={cn(\"px-8\", \"[&::-webkit-search-cancel-button]:hidden\")}\n />\n {term !== \"\" && (\n <IconButton\n size=\"xs\"\n icon=\"x\"\n label={t(\"table.search.clear\", \"Clear search\")}\n data-test=\"table-search-clear\"\n className=\"absolute right-1.5 top-1/2 -translate-y-1/2\"\n onClick={clear}\n />\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;;;AAOA,IAAM,cAAc;;;;;;AAOpB,SAAgB,YAAY,EAC1B,OACA,YAIC;CACD,MAAM,EAAE,MAAM,KAAK,SAAS;CAC5B,MAAM,CAAC,MAAM,WAAW,SAAS,KAAK;CACtC,MAAM,QAAQ,OAA6C,IAAI;CAC/D,MAAM,YAAY,OAAO,KAAK;CAE9B,gBAAgB;EACd,IAAI,UAAU,UAAU,SAAS;GAC/B,UAAU,UAAU;GACpB,QAAQ,KAAK;EACf;CACF,GAAG,CAAC,KAAK,CAAC;CAEV,sBACc;EACV,IAAI,MAAM,SACR,aAAa,MAAM,OAAO;CAE9B,GACA,CAAC,CACH;CAEA,SAAS,OAAO,MAAoB;EAClC,UAAU,UAAU;EACpB,SAAS,IAAI;CACf;CAEA,SAAS,OAAO,MAAoB;EAClC,QAAQ,IAAI;EAEZ,IAAI,MAAM,SACR,aAAa,MAAM,OAAO;EAG5B,MAAM,UAAU,iBAAiB,OAAO,IAAI,GAAG,WAAW;CAC5D;CAEA,SAAS,QAAc;EACrB,IAAI,MAAM,SACR,aAAa,MAAM,OAAO;EAG5B,QAAQ,EAAE;EACV,OAAO,EAAE;CACX;CAEA,MAAM,QAAQ,EAAE,4BAA4B,QAAQ;CAEpD,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf;GACE,oBAAC,MAAD;IACE,MAAK;IACL,eAAY;IACZ,WAAU;GACX,CAAA;GACD,oBAAC,OAAD;IACE,MAAK;IACL,aAAU;IACV,OAAO;IACP,aAAa;IACb,cAAY;IACZ,WAAW,UAAU,OAAO,MAAM,OAAO,KAAK;IAC9C,WAAW,GAAG,QAAQ,0CAA0C;GACjE,CAAA;GACA,SAAS,MACR,oBAAC,YAAD;IACE,MAAK;IACL,MAAK;IACL,OAAO,EAAE,sBAAsB,cAAc;IAC7C,aAAU;IACV,WAAU;IACV,SAAS;GACV,CAAA;EAEA;;AAET"}
1
+ {"version":3,"file":"table-search.js","names":[],"sources":["../../../resources/js/table/components/table-search.tsx"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport { Icon } from \"@lattice-php/lattice/icons\";\nimport { IconButton } from \"@lattice-php/lattice/ui/icon-button\";\nimport { Input } from \"@lattice-php/lattice/ui/input\";\nimport { useT } from \"@lattice-php/lattice/i18n\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport { useDebouncedCallback } from \"@lattice-php/lattice/lib/use-debounced-callback\";\n\nconst DEBOUNCE_MS = 300;\n\n/**\n * The table-level quick-search box. Keystrokes update the input immediately and\n * commit the term to the server after a short debounce; an externally-changed\n * value (e.g. a filter reset) is adopted without echoing keystroke round-trips.\n */\nexport function TableSearch({\n value,\n onSearch,\n}: {\n value: string;\n onSearch: (term: string) => void;\n}) {\n const { t } = useT(\"lattice\");\n const [term, setTerm] = useState(value);\n const committed = useRef(value);\n\n useEffect(() => {\n if (value !== committed.current) {\n committed.current = value;\n setTerm(value);\n }\n }, [value]);\n\n function commit(next: string): void {\n committed.current = next;\n onSearch(next);\n }\n\n const commitDebounced = useDebouncedCallback(commit, DEBOUNCE_MS);\n\n function change(next: string): void {\n setTerm(next);\n commitDebounced(next);\n }\n\n function clear(): void {\n commitDebounced.cancel();\n setTerm(\"\");\n commit(\"\");\n }\n\n const label = t(\"table.search.placeholder\", \"Search\");\n\n return (\n <div className=\"relative w-full max-w-xs\">\n <Icon\n name=\"search\"\n aria-hidden=\"true\"\n className=\"pointer-events-none absolute left-2.5 top-1/2 size-lt-icon-sm -translate-y-1/2 text-lt-muted-fg\"\n />\n <Input\n type=\"search\"\n data-test=\"table-search\"\n value={term}\n placeholder={label}\n aria-label={label}\n onChange={(event) => change(event.target.value)}\n className={cn(\"px-8\", \"[&::-webkit-search-cancel-button]:hidden\")}\n />\n {term !== \"\" && (\n <IconButton\n size=\"xs\"\n icon=\"x\"\n label={t(\"table.search.clear\", \"Clear search\")}\n data-test=\"table-search-clear\"\n className=\"absolute right-1.5 top-1/2 -translate-y-1/2\"\n onClick={clear}\n />\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;AAQA,IAAM,cAAc;;;;;;AAOpB,SAAgB,YAAY,EAC1B,OACA,YAIC;CACD,MAAM,EAAE,MAAM,KAAK,SAAS;CAC5B,MAAM,CAAC,MAAM,WAAW,SAAS,KAAK;CACtC,MAAM,YAAY,OAAO,KAAK;CAE9B,gBAAgB;EACd,IAAI,UAAU,UAAU,SAAS;GAC/B,UAAU,UAAU;GACpB,QAAQ,KAAK;EACf;CACF,GAAG,CAAC,KAAK,CAAC;CAEV,SAAS,OAAO,MAAoB;EAClC,UAAU,UAAU;EACpB,SAAS,IAAI;CACf;CAEA,MAAM,kBAAkB,qBAAqB,QAAQ,WAAW;CAEhE,SAAS,OAAO,MAAoB;EAClC,QAAQ,IAAI;EACZ,gBAAgB,IAAI;CACtB;CAEA,SAAS,QAAc;EACrB,gBAAgB,OAAO;EACvB,QAAQ,EAAE;EACV,OAAO,EAAE;CACX;CAEA,MAAM,QAAQ,EAAE,4BAA4B,QAAQ;CAEpD,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf;GACE,oBAAC,MAAD;IACE,MAAK;IACL,eAAY;IACZ,WAAU;GACX,CAAA;GACD,oBAAC,OAAD;IACE,MAAK;IACL,aAAU;IACV,OAAO;IACP,aAAa;IACb,cAAY;IACZ,WAAW,UAAU,OAAO,MAAM,OAAO,KAAK;IAC9C,WAAW,GAAG,QAAQ,0CAA0C;GACjE,CAAA;GACA,SAAS,MACR,oBAAC,YAAD;IACE,MAAK;IACL,MAAK;IACL,OAAO,EAAE,sBAAsB,cAAc;IAC7C,aAAU;IACV,WAAU;IACV,SAAS;GACV,CAAA;EAEA;;AAET"}