@lattice-php/lattice 0.19.0 → 0.20.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 (236) hide show
  1. package/dist/core/index.js +2 -2
  2. package/dist/core/types.d.ts +16 -4
  3. package/dist/create-app.d.ts +31 -3
  4. package/dist/create-app.js +48 -10
  5. package/dist/create-app.js.map +1 -1
  6. package/dist/effects/registry.d.ts +3 -3
  7. package/dist/effects/registry.js +4 -4
  8. package/dist/effects/registry.js.map +1 -1
  9. package/dist/form/components/base/field.d.ts +2 -2
  10. package/dist/form/components/base/field.js +2 -2
  11. package/dist/form/components/base/field.js.map +1 -1
  12. package/dist/form/components/fields/color-picker-field.d.ts +2 -0
  13. package/dist/form/components/fields/color-picker-field.js +57 -0
  14. package/dist/form/components/fields/color-picker-field.js.map +1 -0
  15. package/dist/form/components/fields/date-input.js +1 -1
  16. package/dist/form/components/fields/date-picker-field.js +1 -1
  17. package/dist/form/components/fields/date-time-input.js +1 -1
  18. package/dist/form/components/fields/file-upload.js +7 -12
  19. package/dist/form/components/fields/file-upload.js.map +1 -1
  20. package/dist/form/components/fields/number-input.js +1 -1
  21. package/dist/form/components/fields/rich-editor-field.js +35 -276
  22. package/dist/form/components/fields/rich-editor-field.js.map +1 -1
  23. package/dist/form/components/fields/row-action-menu.js +2 -2
  24. package/dist/form/components/fields/row-action-menu.js.map +1 -1
  25. package/dist/form/components/fields/row-actions.js +3 -1
  26. package/dist/form/components/fields/row-actions.js.map +1 -1
  27. package/dist/form/components/fields/select.js +59 -16
  28. package/dist/form/components/fields/select.js.map +1 -1
  29. package/dist/form/components/fields/table-rows.js +2 -2
  30. package/dist/form/components/fields/table-rows.js.map +1 -1
  31. package/dist/form/components/fields/text-input.js +8 -1
  32. package/dist/form/components/fields/text-input.js.map +1 -1
  33. package/dist/form/components/fields/time-input.js +1 -1
  34. package/dist/form/components/index.d.ts +1 -0
  35. package/dist/form/components/index.js +2 -1
  36. package/dist/form/embed.d.ts +1 -0
  37. package/dist/form/embed.js +2 -1
  38. package/dist/form/hooks/use-form-resolver.js.map +1 -1
  39. package/dist/form/index.js +2 -1
  40. package/dist/form/lib/conditions.d.ts +4 -10
  41. package/dist/form/lib/conditions.js.map +1 -1
  42. package/dist/form/lib/field-props.d.ts +4 -18
  43. package/dist/form/lib/field-props.js.map +1 -1
  44. package/dist/form/plugin.js +2 -0
  45. package/dist/form/plugin.js.map +1 -1
  46. package/dist/form/rich-editor/builtins.d.ts +6 -0
  47. package/dist/form/rich-editor/builtins.js +400 -0
  48. package/dist/form/rich-editor/builtins.js.map +1 -0
  49. package/dist/form/rich-editor/index.d.ts +7 -0
  50. package/dist/form/rich-editor/index.js +3 -0
  51. package/dist/form/rich-editor/registry.d.ts +67 -0
  52. package/dist/form/rich-editor/registry.js +79 -0
  53. package/dist/form/rich-editor/registry.js.map +1 -0
  54. package/dist/form/rich-editor/toolbar-button.d.ts +12 -0
  55. package/dist/form/rich-editor/toolbar-button.js +28 -0
  56. package/dist/form/rich-editor/toolbar-button.js.map +1 -0
  57. package/dist/form/types.d.ts +1 -6
  58. package/dist/format/date-time.d.ts +3 -2
  59. package/dist/format/date-time.js.map +1 -1
  60. package/dist/i18n/backend.js +1 -1
  61. package/dist/i18n/date-time.d.ts +3 -2
  62. package/dist/i18n/date-time.js.map +1 -1
  63. package/dist/i18n/index.js +3 -2
  64. package/dist/i18n/instance.js +1 -1
  65. package/dist/i18n/page-props.d.ts +3 -2
  66. package/dist/i18n/page-props.js +1 -15
  67. package/dist/i18n/page-props.js.map +1 -1
  68. package/dist/i18n/shared-props.d.ts +7 -0
  69. package/dist/i18n/shared-props.js +25 -0
  70. package/dist/i18n/shared-props.js.map +1 -0
  71. package/dist/index.d.ts +5 -3
  72. package/dist/index.js +7 -6
  73. package/dist/lattice.css +107 -47
  74. package/dist/layout/components/breadcrumbs.js +3 -1
  75. package/dist/layout/components/breadcrumbs.js.map +1 -1
  76. package/dist/layout/components/callouts.js +1 -1
  77. package/dist/lib/color.d.ts +9 -0
  78. package/dist/lib/color.js +48 -0
  79. package/dist/lib/color.js.map +1 -0
  80. package/dist/notifications/api.d.ts +6 -6
  81. package/dist/notifications/api.js.map +1 -1
  82. package/dist/notifications/types.d.ts +2 -10
  83. package/dist/provider-base.js +1 -1
  84. package/dist/realtime/build-effects.js +5 -5
  85. package/dist/realtime/build-effects.js.map +1 -1
  86. package/dist/realtime/listeners.d.ts +2 -2
  87. package/dist/realtime/listeners.js.map +1 -1
  88. package/dist/realtime/subscriptions.d.ts +2 -2
  89. package/dist/realtime/subscriptions.js.map +1 -1
  90. package/dist/table/components/bulk-bar.js +5 -5
  91. package/dist/table/components/bulk-bar.js.map +1 -1
  92. package/dist/table/components/cells/badge-cell.js +4 -1
  93. package/dist/table/components/cells/badge-cell.js.map +1 -1
  94. package/dist/table/components/cells/boolean-cell.js +3 -1
  95. package/dist/table/components/cells/boolean-cell.js.map +1 -1
  96. package/dist/table/components/cells/icon-cell.js +5 -2
  97. package/dist/table/components/cells/icon-cell.js.map +1 -1
  98. package/dist/table/components/cells/image-cell.js +8 -9
  99. package/dist/table/components/cells/image-cell.js.map +1 -1
  100. package/dist/table/components/cells/money-cell.js +9 -1
  101. package/dist/table/components/cells/money-cell.js.map +1 -1
  102. package/dist/table/components/cells/number-cell.js +9 -1
  103. package/dist/table/components/cells/number-cell.js.map +1 -1
  104. package/dist/table/components/cells/text-cell.js +4 -1
  105. package/dist/table/components/cells/text-cell.js.map +1 -1
  106. package/dist/table/components/column-filter-control.js +25 -32
  107. package/dist/table/components/column-filter-control.js.map +1 -1
  108. package/dist/table/components/column-header.d.ts +3 -3
  109. package/dist/table/components/column-header.js +5 -3
  110. package/dist/table/components/column-header.js.map +1 -1
  111. package/dist/table/components/column-visibility-menu.js +6 -11
  112. package/dist/table/components/column-visibility-menu.js.map +1 -1
  113. package/dist/table/components/filter-bar.d.ts +2 -2
  114. package/dist/table/components/filter-bar.js +13 -22
  115. package/dist/table/components/filter-bar.js.map +1 -1
  116. package/dist/table/components/filter-controls.d.ts +2 -1
  117. package/dist/table/components/filter-controls.js +36 -35
  118. package/dist/table/components/filter-controls.js.map +1 -1
  119. package/dist/table/components/filter-value-input.d.ts +0 -1
  120. package/dist/table/components/filter-value-input.js +21 -20
  121. package/dist/table/components/filter-value-input.js.map +1 -1
  122. package/dist/table/components/pagination.js +16 -20
  123. package/dist/table/components/pagination.js.map +1 -1
  124. package/dist/table/components/sort-bar.d.ts +3 -3
  125. package/dist/table/components/sort-bar.js +11 -12
  126. package/dist/table/components/sort-bar.js.map +1 -1
  127. package/dist/table/components/table-search.d.ts +9 -0
  128. package/dist/table/components/table-search.js +75 -0
  129. package/dist/table/components/table-search.js.map +1 -0
  130. package/dist/table/components/table.js +72 -19
  131. package/dist/table/components/table.js.map +1 -1
  132. package/dist/table/hooks/use-expanded-rows.d.ts +8 -0
  133. package/dist/table/hooks/use-expanded-rows.js +24 -0
  134. package/dist/table/hooks/use-expanded-rows.js.map +1 -0
  135. package/dist/table/hooks/use-table.d.ts +5 -3
  136. package/dist/table/hooks/use-table.js +56 -44
  137. package/dist/table/hooks/use-table.js.map +1 -1
  138. package/dist/table/lib/payload.d.ts +3 -2
  139. package/dist/table/lib/payload.js +16 -10
  140. package/dist/table/lib/payload.js.map +1 -1
  141. package/dist/table/lib/query.d.ts +5 -5
  142. package/dist/table/lib/query.js +20 -18
  143. package/dist/table/lib/query.js.map +1 -1
  144. package/dist/table/types.d.ts +3 -26
  145. package/dist/toast/callout.js +1 -3
  146. package/dist/toast/callout.js.map +1 -1
  147. package/dist/toast/toast.d.ts +1 -5
  148. package/dist/toast/toast.js +2 -7
  149. package/dist/toast/toast.js.map +1 -1
  150. package/dist/toast/toaster.js +2 -2
  151. package/dist/toast/toaster.js.map +1 -1
  152. package/dist/types/generated.d.ts +263 -188
  153. package/dist/ui/affix-group.d.ts +2 -1
  154. package/dist/ui/affix-group.js +9 -7
  155. package/dist/ui/affix-group.js.map +1 -1
  156. package/dist/ui/avatar.d.ts +3 -0
  157. package/dist/ui/avatar.js +52 -0
  158. package/dist/ui/avatar.js.map +1 -0
  159. package/dist/ui/button.d.ts +3 -1
  160. package/dist/ui/button.js +10 -3
  161. package/dist/ui/button.js.map +1 -1
  162. package/dist/ui/chart-view.js +161 -11
  163. package/dist/ui/chart-view.js.map +1 -1
  164. package/dist/ui/click-behavior.d.ts +1 -1
  165. package/dist/ui/click-behavior.js.map +1 -1
  166. package/dist/ui/color-picker.d.ts +8 -0
  167. package/dist/ui/color-picker.js +59 -0
  168. package/dist/ui/color-picker.js.map +1 -0
  169. package/dist/ui/combobox.d.ts +11 -2
  170. package/dist/ui/combobox.js +51 -8
  171. package/dist/ui/combobox.js.map +1 -1
  172. package/dist/ui/copyable-text.d.ts +7 -0
  173. package/dist/ui/copyable-text.js +21 -13
  174. package/dist/ui/copyable-text.js.map +1 -1
  175. package/dist/ui/fragment.js.map +1 -1
  176. package/dist/ui/heading.js +39 -21
  177. package/dist/ui/heading.js.map +1 -1
  178. package/dist/ui/icon-button.d.ts +22 -0
  179. package/dist/ui/icon-button.js +51 -0
  180. package/dist/ui/icon-button.js.map +1 -0
  181. package/dist/ui/icon.js +10 -11
  182. package/dist/ui/icon.js.map +1 -1
  183. package/dist/ui/image-preview.d.ts +12 -0
  184. package/dist/ui/image-preview.js +65 -0
  185. package/dist/ui/image-preview.js.map +1 -0
  186. package/dist/ui/image.d.ts +3 -0
  187. package/dist/ui/image.js +21 -0
  188. package/dist/ui/image.js.map +1 -0
  189. package/dist/ui/index.d.ts +2 -1
  190. package/dist/ui/index.js +4 -3
  191. package/dist/ui/info-tooltip.js +1 -1
  192. package/dist/ui/info-tooltip.js.map +1 -1
  193. package/dist/ui/input.d.ts +3 -1
  194. package/dist/ui/input.js +2 -2
  195. package/dist/ui/input.js.map +1 -1
  196. package/dist/ui/modal.js +14 -2
  197. package/dist/ui/modal.js.map +1 -1
  198. package/dist/ui/native-select.d.ts +10 -0
  199. package/dist/ui/native-select.js +23 -0
  200. package/dist/ui/native-select.js.map +1 -0
  201. package/dist/ui/plugin.js +11 -1
  202. package/dist/ui/plugin.js.map +1 -1
  203. package/dist/ui/progress.d.ts +3 -0
  204. package/dist/ui/progress.js +114 -0
  205. package/dist/ui/progress.js.map +1 -0
  206. package/dist/ui/separator.d.ts +3 -0
  207. package/dist/ui/separator.js +15 -0
  208. package/dist/ui/separator.js.map +1 -0
  209. package/dist/ui/text.js +5 -10
  210. package/dist/ui/text.js.map +1 -1
  211. package/dist/ui/tree-context.d.ts +33 -0
  212. package/dist/ui/tree-context.js +137 -0
  213. package/dist/ui/tree-context.js.map +1 -0
  214. package/dist/ui/tree.d.ts +19 -0
  215. package/dist/ui/tree.js +187 -0
  216. package/dist/ui/tree.js.map +1 -0
  217. package/dist-standalone/chunks/chart-view-wJmnVu7L.js +36 -0
  218. package/dist-standalone/chunks/date-picker-field-VbH9xrQO.js +1 -0
  219. package/dist-standalone/chunks/jsx-runtime-Drll_-DD.js +1 -0
  220. package/dist-standalone/chunks/locale-CXqr7LPR.js +1 -0
  221. package/dist-standalone/chunks/page-props-AIa5UR6n.js +1 -0
  222. package/dist-standalone/chunks/rich-editor-field-DLQTyt36.js +154 -0
  223. package/dist-standalone/chunks/{subscriptions-B3UuDBmx.js → subscriptions-DY2tj9Im.js} +1 -1
  224. package/dist-standalone/chunks/use-effect-dispatcher-feEs0GCP.js +97 -0
  225. package/dist-standalone/lattice.css +1 -1
  226. package/dist-standalone/lattice.js +15 -15
  227. package/dist-standalone/manifest.json +11 -9
  228. package/dist-standalone/sprite.svg +1 -1
  229. package/package.json +6 -1
  230. package/resources/icons/code-xml.svg +17 -0
  231. package/resources/icons/heading.svg +17 -0
  232. package/dist-standalone/chunks/chart-view-CK5fKIkR.js +0 -36
  233. package/dist-standalone/chunks/date-picker-field-BlCPFhZd.js +0 -1
  234. package/dist-standalone/chunks/jsx-runtime-CJ_btYLc.js +0 -1
  235. package/dist-standalone/chunks/rich-editor-field-DH5dS5c1.js +0 -154
  236. package/dist-standalone/chunks/use-effect-dispatcher-k98Nzf9M.js +0 -97
@@ -0,0 +1,137 @@
1
+ import { createContext, useCallback, useContext, useMemo, useRef, useState } from "react";
2
+ var TreeContext = createContext({
3
+ activate: () => {},
4
+ activeId: null,
5
+ expanded: /* @__PURE__ */ new Set(),
6
+ focus: () => {},
7
+ focusedId: null,
8
+ moveFocus: () => {},
9
+ register: () => {},
10
+ toggle: () => {},
11
+ typeAhead: () => {},
12
+ unregister: () => {}
13
+ });
14
+ function useTreeContext() {
15
+ return useContext(TreeContext);
16
+ }
17
+ function readStoredExpanded(key, remember, fallback) {
18
+ if (!remember || typeof window === "undefined") return new Set(fallback);
19
+ const stored = window.localStorage.getItem(key);
20
+ if (stored === null) return new Set(fallback);
21
+ try {
22
+ const parsed = JSON.parse(stored);
23
+ return Array.isArray(parsed) ? new Set(parsed.filter((id) => typeof id === "string")) : new Set(fallback);
24
+ } catch {
25
+ return new Set(fallback);
26
+ }
27
+ }
28
+ function visibleOrder(registry) {
29
+ return [...registry.values()].sort((a, b) => a.orderPath.localeCompare(b.orderPath));
30
+ }
31
+ var TYPEAHEAD_IDLE_MS = 800;
32
+ function useTreeState({ activeId: initialActiveId, defaultExpanded, nodes, rememberState, storageKey }) {
33
+ const [expanded, setExpanded] = useState(() => readStoredExpanded(storageKey, rememberState, defaultExpanded));
34
+ const [activeId, setActiveId] = useState(initialActiveId);
35
+ const [focusedId, setFocusedId] = useState(() => nodes[0]?.id ?? null);
36
+ const registryRef = useRef(/* @__PURE__ */ new Map());
37
+ const typeAheadRef = useRef({
38
+ text: "",
39
+ timestamp: 0
40
+ });
41
+ const toggle = useCallback((id) => {
42
+ setExpanded((current) => {
43
+ const next = new Set(current);
44
+ if (next.has(id)) next.delete(id);
45
+ else next.add(id);
46
+ if (rememberState && typeof window !== "undefined") window.localStorage.setItem(storageKey, JSON.stringify([...next]));
47
+ return next;
48
+ });
49
+ }, [rememberState, storageKey]);
50
+ const activate = useCallback((id) => setActiveId(id), []);
51
+ const focus = useCallback((id) => {
52
+ setFocusedId(id);
53
+ [...registryRef.current.values()].find((candidate) => candidate.id === id)?.ref.current?.focus();
54
+ }, []);
55
+ const register = useCallback((entry) => {
56
+ registryRef.current.set(entry.path, entry);
57
+ }, []);
58
+ const unregister = useCallback((path) => {
59
+ registryRef.current.delete(path);
60
+ }, []);
61
+ const moveFocus = useCallback((fromId, direction) => {
62
+ const order = visibleOrder(registryRef.current);
63
+ if (order.length === 0) return;
64
+ const index = order.findIndex((entry) => entry.id === fromId);
65
+ const current = index === -1 ? void 0 : order[index];
66
+ let target;
67
+ switch (direction) {
68
+ case "next":
69
+ target = index === -1 ? void 0 : order[index + 1];
70
+ break;
71
+ case "prev":
72
+ target = index === -1 ? void 0 : order[index - 1];
73
+ break;
74
+ case "first":
75
+ target = order[0];
76
+ break;
77
+ case "last":
78
+ target = order[order.length - 1];
79
+ break;
80
+ case "parent":
81
+ target = current ? order.find((entry) => entry.path === current.parentPath) : void 0;
82
+ break;
83
+ case "firstChild":
84
+ target = current ? order.find((entry) => entry.parentPath === current.path) : void 0;
85
+ break;
86
+ }
87
+ if (target) focus(target.id);
88
+ }, [focus]);
89
+ const typeAhead = useCallback((fromId, character) => {
90
+ const order = visibleOrder(registryRef.current);
91
+ if (order.length === 0) return;
92
+ const now = Date.now();
93
+ const buffer = typeAheadRef.current;
94
+ const text = now - buffer.timestamp > TYPEAHEAD_IDLE_MS ? character : buffer.text + character;
95
+ typeAheadRef.current = {
96
+ text,
97
+ timestamp: now
98
+ };
99
+ const needle = text.toLowerCase();
100
+ const startIndex = order.findIndex((entry) => entry.id === fromId);
101
+ const start = startIndex === -1 ? 0 : startIndex;
102
+ for (let offset = 1; offset <= order.length; offset++) {
103
+ const candidate = order[(start + offset) % order.length];
104
+ if (candidate.label.toLowerCase().startsWith(needle)) {
105
+ focus(candidate.id);
106
+ return;
107
+ }
108
+ }
109
+ }, [focus]);
110
+ return useMemo(() => ({
111
+ activate,
112
+ activeId,
113
+ expanded,
114
+ focus,
115
+ focusedId,
116
+ moveFocus,
117
+ register,
118
+ toggle,
119
+ typeAhead,
120
+ unregister
121
+ }), [
122
+ activate,
123
+ activeId,
124
+ expanded,
125
+ focus,
126
+ focusedId,
127
+ moveFocus,
128
+ register,
129
+ toggle,
130
+ typeAhead,
131
+ unregister
132
+ ]);
133
+ }
134
+ //#endregion
135
+ export { TreeContext, useTreeContext, useTreeState };
136
+
137
+ //# sourceMappingURL=tree-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tree-context.js","names":[],"sources":["../../resources/js/ui/tree-context.tsx"],"sourcesContent":["import { createContext, useCallback, useContext, useMemo, useRef, useState } from \"react\";\nimport type { RefObject } from \"react\";\n\nexport type TreeItemRegistration = {\n id: string;\n label: string;\n orderPath: string;\n parentPath: string | null;\n path: string;\n ref: RefObject<HTMLLIElement | null>;\n};\n\nexport type TreeFocusDirection = \"first\" | \"firstChild\" | \"last\" | \"next\" | \"parent\" | \"prev\";\n\nexport type TreeContextValue = {\n activate: (id: string) => void;\n activeId: string | null;\n expanded: Set<string>;\n focus: (id: string) => void;\n focusedId: string | null;\n moveFocus: (fromId: string, direction: TreeFocusDirection) => void;\n register: (entry: TreeItemRegistration) => void;\n toggle: (id: string) => void;\n typeAhead: (fromId: string, character: string) => void;\n unregister: (path: string) => void;\n};\n\nconst defaultTreeContext: TreeContextValue = {\n activate: () => {},\n activeId: null,\n expanded: new Set(),\n focus: () => {},\n focusedId: null,\n moveFocus: () => {},\n register: () => {},\n toggle: () => {},\n typeAhead: () => {},\n unregister: () => {},\n};\n\nexport const TreeContext = createContext<TreeContextValue>(defaultTreeContext);\n\nexport function useTreeContext(): TreeContextValue {\n return useContext(TreeContext);\n}\n\nfunction readStoredExpanded(key: string, remember: boolean, fallback: string[]): Set<string> {\n if (!remember || typeof window === \"undefined\") {\n return new Set(fallback);\n }\n\n const stored = window.localStorage.getItem(key);\n\n if (stored === null) {\n return new Set(fallback);\n }\n\n try {\n const parsed: unknown = JSON.parse(stored);\n\n return Array.isArray(parsed)\n ? new Set(parsed.filter((id): id is string => typeof id === \"string\"))\n : new Set(fallback);\n } catch {\n return new Set(fallback);\n }\n}\n\nfunction visibleOrder(registry: Map<string, TreeItemRegistration>): TreeItemRegistration[] {\n return [...registry.values()].sort((a, b) => a.orderPath.localeCompare(b.orderPath));\n}\n\nconst TYPEAHEAD_IDLE_MS = 800;\n\nexport function useTreeState({\n activeId: initialActiveId,\n defaultExpanded,\n nodes,\n rememberState,\n storageKey,\n}: {\n activeId: string | null;\n defaultExpanded: string[];\n nodes: Array<{ id: string }>;\n rememberState: boolean;\n storageKey: string;\n}): TreeContextValue {\n const [expanded, setExpanded] = useState<Set<string>>(() =>\n readStoredExpanded(storageKey, rememberState, defaultExpanded),\n );\n const [activeId, setActiveId] = useState<string | null>(initialActiveId);\n const [focusedId, setFocusedId] = useState<string | null>(() => nodes[0]?.id ?? null);\n const registryRef = useRef<Map<string, TreeItemRegistration>>(new Map());\n const typeAheadRef = useRef<{ text: string; timestamp: number }>({ text: \"\", timestamp: 0 });\n\n const toggle = useCallback(\n (id: string) => {\n setExpanded((current) => {\n const next = new Set(current);\n\n if (next.has(id)) {\n next.delete(id);\n } else {\n next.add(id);\n }\n\n if (rememberState && typeof window !== \"undefined\") {\n window.localStorage.setItem(storageKey, JSON.stringify([...next]));\n }\n\n return next;\n });\n },\n [rememberState, storageKey],\n );\n\n const activate = useCallback((id: string) => setActiveId(id), []);\n\n const focus = useCallback((id: string) => {\n setFocusedId(id);\n const entry = [...registryRef.current.values()].find((candidate) => candidate.id === id);\n entry?.ref.current?.focus();\n }, []);\n\n const register = useCallback((entry: TreeItemRegistration) => {\n registryRef.current.set(entry.path, entry);\n }, []);\n\n const unregister = useCallback((path: string) => {\n registryRef.current.delete(path);\n }, []);\n\n const moveFocus = useCallback(\n (fromId: string, direction: TreeFocusDirection) => {\n const order = visibleOrder(registryRef.current);\n\n if (order.length === 0) {\n return;\n }\n\n const index = order.findIndex((entry) => entry.id === fromId);\n const current = index === -1 ? undefined : order[index];\n\n let target: TreeItemRegistration | undefined;\n\n switch (direction) {\n case \"next\":\n target = index === -1 ? undefined : order[index + 1];\n break;\n case \"prev\":\n target = index === -1 ? undefined : order[index - 1];\n break;\n case \"first\":\n target = order[0];\n break;\n case \"last\":\n target = order[order.length - 1];\n break;\n case \"parent\":\n target = current ? order.find((entry) => entry.path === current.parentPath) : undefined;\n break;\n case \"firstChild\":\n target = current ? order.find((entry) => entry.parentPath === current.path) : undefined;\n break;\n }\n\n if (target) {\n focus(target.id);\n }\n },\n [focus],\n );\n\n const typeAhead = useCallback(\n (fromId: string, character: string) => {\n const order = visibleOrder(registryRef.current);\n\n if (order.length === 0) {\n return;\n }\n\n const now = Date.now();\n const buffer = typeAheadRef.current;\n const text = now - buffer.timestamp > TYPEAHEAD_IDLE_MS ? character : buffer.text + character;\n typeAheadRef.current = { text, timestamp: now };\n\n const needle = text.toLowerCase();\n const startIndex = order.findIndex((entry) => entry.id === fromId);\n const start = startIndex === -1 ? 0 : startIndex;\n\n for (let offset = 1; offset <= order.length; offset++) {\n const candidate = order[(start + offset) % order.length];\n\n if (candidate.label.toLowerCase().startsWith(needle)) {\n focus(candidate.id);\n return;\n }\n }\n },\n [focus],\n );\n\n return useMemo(\n () => ({\n activate,\n activeId,\n expanded,\n focus,\n focusedId,\n moveFocus,\n register,\n toggle,\n typeAhead,\n unregister,\n }),\n [\n activate,\n activeId,\n expanded,\n focus,\n focusedId,\n moveFocus,\n register,\n toggle,\n typeAhead,\n unregister,\n ],\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import { RendererComponent } from '../core/types.js';
2
+ import { Tree as TreeProps, TreeNode as GeneratedTreeNode } from '../types/generated.js';
3
+ /**
4
+ * The actual sparse wire shape a tree node serializes as (see `TreeNode::jsonSerialize()`):
5
+ * every optional/falsy field is omitted rather than sent as `null`/`false`, unlike the
6
+ * generated `TreeNode`, which reflects every declared PHP property as required.
7
+ */
8
+ export type TreeNodeData = Pick<GeneratedTreeNode, "id" | "label"> & Partial<Omit<GeneratedTreeNode, "children" | "id" | "label">> & {
9
+ children?: TreeNodeData[];
10
+ };
11
+ declare module '../core/types' {
12
+ interface ComponentProps {
13
+ tree: TreeProps & {
14
+ nodes: TreeNodeData[];
15
+ };
16
+ }
17
+ }
18
+ declare const TreeComponent: RendererComponent<"tree">;
19
+ export default TreeComponent;
@@ -0,0 +1,187 @@
1
+ import { cn } from "../lib/utils.js";
2
+ import { Icon } from "../icons/sprite.js";
3
+ import { IconRenderer } from "../icons/icon-renderer.js";
4
+ import { Renderer } from "../core/renderer.js";
5
+ import { useT } from "../i18n/instance.js";
6
+ import { nodeIdentity } from "../core/test-id.js";
7
+ import { Badge } from "./badge.js";
8
+ import { TextLink } from "./link.js";
9
+ import { TreeContext, useTreeContext, useTreeState } from "./tree-context.js";
10
+ import { router } from "@inertiajs/react";
11
+ import { useEffect, useRef } from "react";
12
+ import { jsx, jsxs } from "react/jsx-runtime";
13
+ //#region resources/js/ui/tree.tsx
14
+ function hasExpandableChildren(node) {
15
+ return Boolean(node.children?.length) || node.hasChildren === true;
16
+ }
17
+ var ORDER_PATH_SEGMENT_WIDTH = 6;
18
+ function orderPathSegment(index) {
19
+ return String(index).padStart(ORDER_PATH_SEGMENT_WIDTH, "0");
20
+ }
21
+ function TreeItem({ depth, node, orderPath, parentPath, siblingCount, siblingIndex }) {
22
+ const { activate, activeId, expanded, focusedId, moveFocus, register, toggle, typeAhead, unregister } = useTreeContext();
23
+ const { t } = useT("lattice");
24
+ const ref = useRef(null);
25
+ const path = parentPath ? `${parentPath}/${node.id}` : node.id;
26
+ const isExpanded = expanded.has(node.id);
27
+ const isActive = activeId === node.id;
28
+ const isFocused = focusedId === node.id;
29
+ const isDisabled = node.disabled === true;
30
+ const expandable = hasExpandableChildren(node);
31
+ const actionsRef = useRef(null);
32
+ useEffect(() => {
33
+ register({
34
+ id: node.id,
35
+ label: node.label,
36
+ orderPath,
37
+ parentPath,
38
+ path,
39
+ ref
40
+ });
41
+ return () => unregister(path);
42
+ }, [
43
+ node.id,
44
+ node.label,
45
+ orderPath,
46
+ parentPath,
47
+ path,
48
+ register,
49
+ unregister
50
+ ]);
51
+ useEffect(() => {
52
+ const container = actionsRef.current;
53
+ if (!container) return;
54
+ container.querySelectorAll("button, a[href], [tabindex]").forEach((control) => {
55
+ control.tabIndex = -1;
56
+ });
57
+ });
58
+ function onKeyDown(event) {
59
+ if (event.target !== event.currentTarget) return;
60
+ switch (event.key) {
61
+ case "ArrowDown":
62
+ event.preventDefault();
63
+ moveFocus(node.id, "next");
64
+ return;
65
+ case "ArrowUp":
66
+ event.preventDefault();
67
+ moveFocus(node.id, "prev");
68
+ return;
69
+ case "ArrowRight":
70
+ event.preventDefault();
71
+ if (expandable && !isExpanded) toggle(node.id);
72
+ else if (expandable) moveFocus(node.id, "firstChild");
73
+ return;
74
+ case "ArrowLeft":
75
+ event.preventDefault();
76
+ if (expandable && isExpanded) toggle(node.id);
77
+ else moveFocus(node.id, "parent");
78
+ return;
79
+ case "Home":
80
+ event.preventDefault();
81
+ moveFocus(node.id, "first");
82
+ return;
83
+ case "End":
84
+ event.preventDefault();
85
+ moveFocus(node.id, "last");
86
+ return;
87
+ case "Enter":
88
+ case " ":
89
+ event.preventDefault();
90
+ if (isDisabled) return;
91
+ if (node.href) router.visit(node.href);
92
+ else if (node.actions) {
93
+ actionsRef.current?.querySelector("button")?.click();
94
+ ref.current?.focus();
95
+ } else activate(node.id);
96
+ return;
97
+ default: if (event.key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey) typeAhead(node.id, event.key);
98
+ }
99
+ }
100
+ return /* @__PURE__ */ jsxs("li", {
101
+ "aria-disabled": isDisabled,
102
+ "aria-expanded": expandable ? isExpanded : void 0,
103
+ "aria-level": depth,
104
+ "aria-posinset": siblingIndex,
105
+ "aria-selected": isActive,
106
+ "aria-setsize": siblingCount,
107
+ "data-test": `tree-node-${node.id}`,
108
+ onKeyDown,
109
+ ref,
110
+ role: "treeitem",
111
+ tabIndex: isFocused ? 0 : -1,
112
+ children: [/* @__PURE__ */ jsxs("div", {
113
+ className: cn("flex items-center gap-2 rounded-lt-sm px-2 py-1.5 text-sm text-lt-fg", isActive && "bg-lt-muted font-medium", isDisabled && "pointer-events-none opacity-50"),
114
+ children: [
115
+ expandable ? /* @__PURE__ */ jsx("button", {
116
+ "aria-label": isExpanded ? t("common.tree.collapse", "Collapse {{label}}", { label: node.label }) : t("common.tree.expand", "Expand {{label}}", { label: node.label }),
117
+ "data-test": `tree-node-${node.id}-toggle`,
118
+ onClick: () => toggle(node.id),
119
+ tabIndex: -1,
120
+ type: "button",
121
+ children: /* @__PURE__ */ jsx(Icon, {
122
+ className: cn("size-lt-icon-md shrink-0 transition-transform", isExpanded && "rotate-90"),
123
+ name: "chevron-right"
124
+ })
125
+ }) : null,
126
+ node.icon ? /* @__PURE__ */ jsx(IconRenderer, {
127
+ className: "size-lt-icon-md shrink-0",
128
+ icon: node.icon
129
+ }) : null,
130
+ node.href && !isDisabled ? /* @__PURE__ */ jsx(TextLink, {
131
+ href: node.href,
132
+ tabIndex: -1,
133
+ children: node.label
134
+ }) : /* @__PURE__ */ jsx("span", { children: node.label }),
135
+ node.badge ? /* @__PURE__ */ jsx(Badge, {
136
+ variant: "secondary",
137
+ children: node.badge
138
+ }) : null,
139
+ node.actions ? /* @__PURE__ */ jsx("span", {
140
+ className: "ml-auto",
141
+ ref: actionsRef,
142
+ children: /* @__PURE__ */ jsx(Renderer, { nodes: [node.actions] })
143
+ }) : null
144
+ ]
145
+ }), expandable && isExpanded && node.children && node.children.length > 0 ? /* @__PURE__ */ jsx("ul", {
146
+ className: "pl-6",
147
+ role: "group",
148
+ children: node.children.map((child, index) => /* @__PURE__ */ jsx(TreeItem, {
149
+ depth: depth + 1,
150
+ node: child,
151
+ orderPath: `${orderPath}.${orderPathSegment(index)}`,
152
+ parentPath: path,
153
+ siblingCount: node.children?.length ?? 1,
154
+ siblingIndex: index + 1
155
+ }, child.id))
156
+ }) : null]
157
+ });
158
+ }
159
+ var TreeComponent = ({ node }) => {
160
+ const identity = nodeIdentity(node);
161
+ const value = useTreeState({
162
+ activeId: node.props.activeId,
163
+ defaultExpanded: node.props.defaultExpanded,
164
+ nodes: node.props.nodes,
165
+ rememberState: node.props.rememberState,
166
+ storageKey: `lattice:tree:${identity ?? "default"}`
167
+ });
168
+ return /* @__PURE__ */ jsx(TreeContext.Provider, {
169
+ value,
170
+ children: /* @__PURE__ */ jsx("ul", {
171
+ "data-lattice-component": identity,
172
+ role: "tree",
173
+ children: node.props.nodes.map((child, index) => /* @__PURE__ */ jsx(TreeItem, {
174
+ depth: 1,
175
+ node: child,
176
+ orderPath: orderPathSegment(index),
177
+ parentPath: null,
178
+ siblingCount: node.props.nodes.length,
179
+ siblingIndex: index + 1
180
+ }, child.id))
181
+ })
182
+ });
183
+ };
184
+ //#endregion
185
+ export { TreeComponent as default };
186
+
187
+ //# sourceMappingURL=tree.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tree.js","names":[],"sources":["../../resources/js/ui/tree.tsx"],"sourcesContent":["import { router } from \"@inertiajs/react\";\nimport { useEffect, useRef } from \"react\";\nimport type { KeyboardEvent } from \"react\";\nimport { Renderer } from \"@lattice-php/lattice/core/renderer\";\nimport { nodeIdentity } from \"@lattice-php/lattice/core/test-id\";\nimport type { RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { Icon, IconRenderer } from \"@lattice-php/lattice/icons\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport { useT } from \"@lattice-php/lattice/i18n\";\nimport type {\n Tree as TreeProps,\n TreeNode as GeneratedTreeNode,\n} from \"@lattice-php/lattice/types/generated\";\nimport { Badge } from \"./badge\";\nimport { TextLink } from \"./link\";\nimport { TreeContext, useTreeContext, useTreeState } from \"./tree-context\";\n\n/**\n * The actual sparse wire shape a tree node serializes as (see `TreeNode::jsonSerialize()`):\n * every optional/falsy field is omitted rather than sent as `null`/`false`, unlike the\n * generated `TreeNode`, which reflects every declared PHP property as required.\n */\nexport type TreeNodeData = Pick<GeneratedTreeNode, \"id\" | \"label\"> &\n Partial<Omit<GeneratedTreeNode, \"children\" | \"id\" | \"label\">> & {\n children?: TreeNodeData[];\n };\n\ndeclare module \"@lattice-php/lattice/core/types\" {\n interface ComponentProps {\n tree: TreeProps & { nodes: TreeNodeData[] };\n }\n}\n\nfunction hasExpandableChildren(node: TreeNodeData): boolean {\n return Boolean(node.children?.length) || node.hasChildren === true;\n}\n\nconst ORDER_PATH_SEGMENT_WIDTH = 6;\n\nfunction orderPathSegment(index: number): string {\n return String(index).padStart(ORDER_PATH_SEGMENT_WIDTH, \"0\");\n}\n\nfunction TreeItem({\n depth,\n node,\n orderPath,\n parentPath,\n siblingCount,\n siblingIndex,\n}: {\n depth: number;\n node: TreeNodeData;\n orderPath: string;\n parentPath: string | null;\n siblingCount: number;\n siblingIndex: number;\n}) {\n const {\n activate,\n activeId,\n expanded,\n focusedId,\n moveFocus,\n register,\n toggle,\n typeAhead,\n unregister,\n } = useTreeContext();\n const { t } = useT(\"lattice\");\n const ref = useRef<HTMLLIElement>(null);\n const path = parentPath ? `${parentPath}/${node.id}` : node.id;\n const isExpanded = expanded.has(node.id);\n const isActive = activeId === node.id;\n const isFocused = focusedId === node.id;\n const isDisabled = node.disabled === true;\n const expandable = hasExpandableChildren(node);\n const actionsRef = useRef<HTMLSpanElement>(null);\n\n useEffect(() => {\n register({ id: node.id, label: node.label, orderPath, parentPath, path, ref });\n\n return () => unregister(path);\n }, [node.id, node.label, orderPath, parentPath, path, register, unregister]);\n\n useEffect(() => {\n const container = actionsRef.current;\n\n if (!container) {\n return;\n }\n\n container.querySelectorAll<HTMLElement>(\"button, a[href], [tabindex]\").forEach((control) => {\n control.tabIndex = -1;\n });\n });\n\n function onKeyDown(event: KeyboardEvent<HTMLLIElement>): void {\n if (event.target !== event.currentTarget) {\n return;\n }\n\n switch (event.key) {\n case \"ArrowDown\":\n event.preventDefault();\n moveFocus(node.id, \"next\");\n return;\n case \"ArrowUp\":\n event.preventDefault();\n moveFocus(node.id, \"prev\");\n return;\n case \"ArrowRight\":\n event.preventDefault();\n if (expandable && !isExpanded) {\n toggle(node.id);\n } else if (expandable) {\n moveFocus(node.id, \"firstChild\");\n }\n return;\n case \"ArrowLeft\":\n event.preventDefault();\n if (expandable && isExpanded) {\n toggle(node.id);\n } else {\n moveFocus(node.id, \"parent\");\n }\n return;\n case \"Home\":\n event.preventDefault();\n moveFocus(node.id, \"first\");\n return;\n case \"End\":\n event.preventDefault();\n moveFocus(node.id, \"last\");\n return;\n case \"Enter\":\n case \" \":\n event.preventDefault();\n if (isDisabled) {\n return;\n }\n if (node.href) {\n router.visit(node.href);\n } else if (node.actions) {\n actionsRef.current?.querySelector(\"button\")?.click();\n ref.current?.focus();\n } else {\n activate(node.id);\n }\n return;\n default:\n if (event.key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey) {\n typeAhead(node.id, event.key);\n }\n }\n }\n\n return (\n <li\n aria-disabled={isDisabled}\n aria-expanded={expandable ? isExpanded : undefined}\n aria-level={depth}\n aria-posinset={siblingIndex}\n aria-selected={isActive}\n aria-setsize={siblingCount}\n data-test={`tree-node-${node.id}`}\n onKeyDown={onKeyDown}\n ref={ref}\n role=\"treeitem\"\n tabIndex={isFocused ? 0 : -1}\n >\n <div\n className={cn(\n \"flex items-center gap-2 rounded-lt-sm px-2 py-1.5 text-sm text-lt-fg\",\n isActive && \"bg-lt-muted font-medium\",\n isDisabled && \"pointer-events-none opacity-50\",\n )}\n >\n {expandable ? (\n <button\n aria-label={\n isExpanded\n ? t(\"common.tree.collapse\", \"Collapse {{label}}\", { label: node.label })\n : t(\"common.tree.expand\", \"Expand {{label}}\", { label: node.label })\n }\n data-test={`tree-node-${node.id}-toggle`}\n onClick={() => toggle(node.id)}\n tabIndex={-1}\n type=\"button\"\n >\n <Icon\n className={cn(\n \"size-lt-icon-md shrink-0 transition-transform\",\n isExpanded && \"rotate-90\",\n )}\n name=\"chevron-right\"\n />\n </button>\n ) : null}\n {node.icon ? <IconRenderer className=\"size-lt-icon-md shrink-0\" icon={node.icon} /> : null}\n {node.href && !isDisabled ? (\n <TextLink href={node.href} tabIndex={-1}>\n {node.label}\n </TextLink>\n ) : (\n <span>{node.label}</span>\n )}\n {node.badge ? <Badge variant=\"secondary\">{node.badge}</Badge> : null}\n {node.actions ? (\n <span className=\"ml-auto\" ref={actionsRef}>\n <Renderer nodes={[node.actions]} />\n </span>\n ) : null}\n </div>\n {expandable && isExpanded && node.children && node.children.length > 0 ? (\n <ul className=\"pl-6\" role=\"group\">\n {node.children.map((child, index) => (\n <TreeItem\n depth={depth + 1}\n key={child.id}\n node={child}\n orderPath={`${orderPath}.${orderPathSegment(index)}`}\n parentPath={path}\n siblingCount={node.children?.length ?? 1}\n siblingIndex={index + 1}\n />\n ))}\n </ul>\n ) : null}\n </li>\n );\n}\n\nconst TreeComponent: RendererComponent<\"tree\"> = ({ node }) => {\n const identity = nodeIdentity(node);\n const value = useTreeState({\n activeId: node.props.activeId,\n defaultExpanded: node.props.defaultExpanded,\n nodes: node.props.nodes,\n rememberState: node.props.rememberState,\n storageKey: `lattice:tree:${identity ?? \"default\"}`,\n });\n\n return (\n <TreeContext.Provider value={value}>\n <ul data-lattice-component={identity} role=\"tree\">\n {node.props.nodes.map((child, index) => (\n <TreeItem\n depth={1}\n key={child.id}\n node={child}\n orderPath={orderPathSegment(index)}\n parentPath={null}\n siblingCount={node.props.nodes.length}\n siblingIndex={index + 1}\n />\n ))}\n </ul>\n </TreeContext.Provider>\n );\n};\n\nexport default TreeComponent;\n"],"mappings":"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"}