@wzyjs/uis 0.3.29 → 0.3.31

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 (222) hide show
  1. package/dist/advanced/Com2Canvas/index.d.ts +8 -0
  2. package/dist/advanced/Com2Canvas/index.js +39 -0
  3. package/dist/advanced/Crud/components/CardList/index.d.ts +2 -0
  4. package/dist/advanced/Crud/components/CardList/index.js +90 -0
  5. package/dist/advanced/Crud/components/CreateUpdate/index.d.ts +2 -0
  6. package/dist/advanced/Crud/components/CreateUpdate/index.js +78 -0
  7. package/dist/advanced/Crud/components/ListTabs/index.d.ts +8 -0
  8. package/dist/advanced/Crud/components/ListTabs/index.js +7 -0
  9. package/dist/advanced/Crud/components/Provider/index.d.ts +7 -0
  10. package/dist/advanced/Crud/components/Provider/index.js +42 -0
  11. package/dist/advanced/Crud/components/QuickFilters/index.d.ts +8 -0
  12. package/dist/advanced/Crud/components/QuickFilters/index.js +20 -0
  13. package/dist/advanced/Crud/components/Remove/index.d.ts +2 -0
  14. package/dist/advanced/Crud/components/Remove/index.js +18 -0
  15. package/dist/advanced/Crud/components/index.d.ts +6 -0
  16. package/dist/advanced/Crud/components/index.js +6 -0
  17. package/dist/advanced/Crud/hooks/index.d.ts +5 -0
  18. package/dist/advanced/Crud/hooks/index.js +5 -0
  19. package/dist/advanced/Crud/hooks/useColumns.d.ts +11 -0
  20. package/dist/advanced/Crud/hooks/useColumns.js +111 -0
  21. package/dist/advanced/Crud/hooks/useList.d.ts +12 -0
  22. package/dist/advanced/Crud/hooks/useList.js +53 -0
  23. package/dist/advanced/Crud/hooks/useListFilters.d.ts +11 -0
  24. package/dist/advanced/Crud/hooks/useListFilters.js +159 -0
  25. package/dist/advanced/Crud/hooks/useOrderable.d.ts +15 -0
  26. package/dist/advanced/Crud/hooks/useOrderable.js +75 -0
  27. package/dist/advanced/Crud/hooks/useRequest.d.ts +13 -0
  28. package/dist/advanced/Crud/hooks/useRequest.js +27 -0
  29. package/dist/advanced/Crud/index.d.ts +3 -0
  30. package/dist/advanced/Crud/index.js +46 -0
  31. package/dist/advanced/Crud/types/index.d.ts +176 -0
  32. package/dist/advanced/Crud/types/index.js +1 -0
  33. package/dist/advanced/Crud/utils/index.d.ts +7 -0
  34. package/dist/advanced/Crud/utils/index.js +80 -0
  35. package/dist/advanced/Crud/utils/query.d.ts +3 -0
  36. package/dist/advanced/Crud/utils/query.js +34 -0
  37. package/dist/advanced/MindMap/context.d.ts +12 -0
  38. package/dist/advanced/MindMap/context.js +12 -0
  39. package/dist/advanced/MindMap/hooks/useAlignmentSnap.d.ts +15 -0
  40. package/dist/advanced/MindMap/hooks/useAlignmentSnap.js +164 -0
  41. package/dist/advanced/MindMap/hooks/useCopyPaste.d.ts +11 -0
  42. package/dist/advanced/MindMap/hooks/useCopyPaste.js +209 -0
  43. package/dist/advanced/MindMap/hooks/useDropToReparent.d.ts +21 -0
  44. package/dist/advanced/MindMap/hooks/useDropToReparent.js +216 -0
  45. package/dist/advanced/MindMap/hooks/useExpandCollapse.d.ts +18 -0
  46. package/dist/advanced/MindMap/hooks/useExpandCollapse.js +108 -0
  47. package/dist/advanced/MindMap/hooks/useMoveDescendants.d.ts +12 -0
  48. package/dist/advanced/MindMap/hooks/useMoveDescendants.js +98 -0
  49. package/dist/advanced/MindMap/hooks/useUndoRedo.d.ts +14 -0
  50. package/dist/advanced/MindMap/hooks/useUndoRedo.js +181 -0
  51. package/dist/advanced/MindMap/index.d.ts +29 -0
  52. package/dist/advanced/MindMap/index.js +52 -0
  53. package/dist/advanced/index.d.ts +5 -0
  54. package/dist/advanced/index.js +5 -0
  55. package/dist/antd/index.d.ts +6 -0
  56. package/dist/antd/index.js +5 -0
  57. package/dist/buttons/ButtonGroup/index.d.ts +8 -0
  58. package/dist/buttons/ButtonGroup/index.js +13 -0
  59. package/dist/buttons/ConfirmButton/index.d.ts +5 -0
  60. package/dist/buttons/ConfirmButton/index.js +9 -0
  61. package/dist/buttons/CopyButton/index.d.ts +6 -0
  62. package/dist/buttons/CopyButton/index.js +26 -0
  63. package/dist/buttons/DrawerButton/index.d.ts +6 -0
  64. package/dist/buttons/DrawerButton/index.js +13 -0
  65. package/dist/buttons/ProgressButton/index.css +63 -0
  66. package/dist/buttons/ProgressButton/index.d.ts +17 -0
  67. package/dist/buttons/ProgressButton/index.js +31 -0
  68. package/dist/buttons/SectorButton/index.d.ts +20 -0
  69. package/dist/buttons/SectorButton/index.js +130 -0
  70. package/dist/buttons/index.d.ts +6 -0
  71. package/dist/buttons/index.js +6 -0
  72. package/dist/display/CodeView/index.d.ts +26 -0
  73. package/dist/display/CodeView/index.js +60 -0
  74. package/dist/display/EnumTag/index.d.ts +12 -0
  75. package/dist/display/EnumTag/index.js +10 -0
  76. package/dist/display/HtmlDataRenderer/index.d.ts +6 -0
  77. package/dist/display/HtmlDataRenderer/index.js +15 -0
  78. package/dist/display/HtmlView/index.d.ts +6 -0
  79. package/dist/display/HtmlView/index.js +6 -0
  80. package/dist/display/IframePro/index.d.ts +8 -0
  81. package/dist/display/IframePro/index.js +24 -0
  82. package/dist/display/JsonSchemaRenderer/index.d.ts +11 -0
  83. package/dist/display/JsonSchemaRenderer/index.js +62 -0
  84. package/dist/display/JsonView/index.d.ts +3 -0
  85. package/dist/display/JsonView/index.js +7 -0
  86. package/dist/display/MarkdownView/index.d.ts +7 -0
  87. package/dist/display/MarkdownView/index.js +80 -0
  88. package/dist/display/MarkdownView/style.d.ts +1 -0
  89. package/{src/components/Markdown/style.ts → dist/display/MarkdownView/style.js} +1 -1
  90. package/dist/display/VideoPro/index.d.ts +9 -0
  91. package/dist/display/VideoPro/index.js +15 -0
  92. package/dist/display/index.d.ts +9 -0
  93. package/dist/display/index.js +9 -0
  94. package/dist/inputs/CheckboxButton/index.css +22 -0
  95. package/dist/inputs/CheckboxButton/index.d.ts +12 -0
  96. package/dist/inputs/CheckboxButton/index.js +9 -0
  97. package/dist/inputs/DateSwitcher/index.css +10 -0
  98. package/dist/inputs/DateSwitcher/index.d.ts +8 -0
  99. package/dist/inputs/DateSwitcher/index.js +29 -0
  100. package/dist/inputs/FetchSelect/index.d.ts +3 -0
  101. package/dist/inputs/FetchSelect/index.js +121 -0
  102. package/dist/inputs/FetchSelect/types.d.ts +33 -0
  103. package/dist/inputs/FetchSelect/types.js +1 -0
  104. package/dist/inputs/FetchSelect/utils.d.ts +21 -0
  105. package/dist/inputs/FetchSelect/utils.js +67 -0
  106. package/dist/inputs/FileUploader/index.d.ts +22 -0
  107. package/dist/inputs/FileUploader/index.js +79 -0
  108. package/dist/inputs/IconSelect/index.d.ts +89 -0
  109. package/dist/inputs/IconSelect/index.js +54 -0
  110. package/dist/inputs/ImageUploader/index.d.ts +12 -0
  111. package/dist/inputs/ImageUploader/index.js +192 -0
  112. package/dist/inputs/RadioButton/index.d.ts +15 -0
  113. package/dist/inputs/RadioButton/index.js +11 -0
  114. package/dist/inputs/RangeInput/index.d.ts +8 -0
  115. package/dist/inputs/RangeInput/index.js +17 -0
  116. package/dist/inputs/TextInput/index.d.ts +6 -0
  117. package/dist/inputs/TextInput/index.js +30 -0
  118. package/dist/inputs/index.d.ts +9 -0
  119. package/dist/inputs/index.js +9 -0
  120. package/dist/layout/DragSort/index.d.ts +16 -0
  121. package/dist/layout/DragSort/index.js +12 -0
  122. package/dist/layout/FoldCard/index.d.ts +9 -0
  123. package/dist/layout/FoldCard/index.js +69 -0
  124. package/dist/layout/PageBase/index.d.ts +6 -0
  125. package/dist/layout/PageBase/index.js +6 -0
  126. package/dist/layout/ResizableGridLayout/index.d.ts +11 -0
  127. package/dist/layout/ResizableGridLayout/index.js +13 -0
  128. package/dist/layout/SideMenu/index.d.ts +27 -0
  129. package/dist/layout/SideMenu/index.js +40 -0
  130. package/dist/layout/TabsPro/index.d.ts +9 -0
  131. package/dist/layout/TabsPro/index.js +87 -0
  132. package/dist/layout/index.d.ts +6 -0
  133. package/dist/layout/index.js +6 -0
  134. package/dist/web.css +363 -0
  135. package/dist/web.d.ts +7 -0
  136. package/dist/web.js +7 -0
  137. package/package.json +34 -12
  138. package/src/antd/form/CheckboxButton/index.module.scss +0 -24
  139. package/src/antd/form/CheckboxButton/index.tsx +0 -31
  140. package/src/antd/form/FileUploader/index.tsx +0 -163
  141. package/src/antd/form/RadioButton/index.tsx +0 -32
  142. package/src/antd/form/Upload/index.tsx +0 -65
  143. package/src/antd/form/UploadImage/index.tsx +0 -338
  144. package/src/antd/form/index.ts +0 -6
  145. package/src/antd/index.ts +0 -46
  146. package/src/antd/pro/FoldCard/index.tsx +0 -131
  147. package/src/antd/pro/RangeInput/index.tsx +0 -46
  148. package/src/antd/pro/Tabs/index.tsx +0 -135
  149. package/src/antd/pro/Typography/components/String.tsx +0 -72
  150. package/src/antd/pro/Typography/index.tsx +0 -9
  151. package/src/antd/pro/buttons/ButtonGroup.tsx +0 -26
  152. package/src/antd/pro/buttons/ConfirmButton.tsx +0 -24
  153. package/src/antd/pro/buttons/CopyButton.tsx +0 -47
  154. package/src/antd/pro/buttons/DrawerButton.tsx +0 -37
  155. package/src/antd/pro/buttons/index.tsx +0 -4
  156. package/src/antd/pro/index.ts +0 -5
  157. package/src/components/BottomBar/index.tsx +0 -28
  158. package/src/components/CodeView/index.tsx +0 -85
  159. package/src/components/Collapse/index.tsx +0 -26
  160. package/src/components/Com2Canvas/index.tsx +0 -60
  161. package/src/components/CompileHtml/index.tsx +0 -26
  162. package/src/components/Crud/components/CardList/index.tsx +0 -174
  163. package/src/components/Crud/components/CreateUpdate/index.tsx +0 -179
  164. package/src/components/Crud/components/Provider/index.tsx +0 -83
  165. package/src/components/Crud/components/Remove/index.tsx +0 -56
  166. package/src/components/Crud/components/index.ts +0 -4
  167. package/src/components/Crud/hooks/index.ts +0 -4
  168. package/src/components/Crud/hooks/useColumns.tsx +0 -169
  169. package/src/components/Crud/hooks/useList.ts +0 -65
  170. package/src/components/Crud/hooks/useOrderable.tsx +0 -107
  171. package/src/components/Crud/hooks/useRequest.ts +0 -41
  172. package/src/components/Crud/index.tsx +0 -91
  173. package/src/components/Crud/types/index.ts +0 -188
  174. package/src/components/Crud/utils/index.ts +0 -87
  175. package/src/components/DateSwitcher/index.module.scss +0 -10
  176. package/src/components/DateSwitcher/index.tsx +0 -75
  177. package/src/components/DownloadLink/index.tsx +0 -36
  178. package/src/components/DragSort/index.tsx +0 -77
  179. package/src/components/DynamicSelect/index.tsx +0 -76
  180. package/src/components/DynamicSelect/types.ts +0 -8
  181. package/src/components/DynamicSelect/utils.ts +0 -47
  182. package/src/components/EnumTag/index.tsx +0 -24
  183. package/src/components/FetchSelect/index.tsx +0 -57
  184. package/src/components/FormPro/index.tsx +0 -28
  185. package/src/components/GroupLayout/index.tsx +0 -45
  186. package/src/components/HtmlPro/index.tsx +0 -18
  187. package/src/components/IframePro/index.tsx +0 -52
  188. package/src/components/JsonRenderer/index.tsx +0 -114
  189. package/src/components/JsonView/index.tsx +0 -21
  190. package/src/components/Markdown/index.tsx +0 -152
  191. package/src/components/MindMap/context.tsx +0 -29
  192. package/src/components/MindMap/hooks/useAlignmentSnap.ts +0 -220
  193. package/src/components/MindMap/hooks/useCopyPaste.ts +0 -272
  194. package/src/components/MindMap/hooks/useDropToReparent.ts +0 -288
  195. package/src/components/MindMap/hooks/useExpandCollapse.ts +0 -146
  196. package/src/components/MindMap/hooks/useMoveDescendants.ts +0 -136
  197. package/src/components/MindMap/hooks/useUndoRedo.ts +0 -232
  198. package/src/components/MindMap/index.tsx +0 -117
  199. package/src/components/MultiImageDisplay/index.tsx +0 -63
  200. package/src/components/ProgressButton/index.module.scss +0 -65
  201. package/src/components/ProgressButton/index.tsx +0 -96
  202. package/src/components/SectorButton/index.tsx +0 -247
  203. package/src/components/TextInput/index.tsx +0 -61
  204. package/src/components/TimelineBar/components/CurrentWeekHighlight/index.tsx +0 -64
  205. package/src/components/TimelineBar/components/Guides/index.tsx +0 -61
  206. package/src/components/TimelineBar/components/Ticks/index.tsx +0 -56
  207. package/src/components/TimelineBar/components/TodayIndicator/index.tsx +0 -54
  208. package/src/components/TimelineBar/components/index.ts +0 -4
  209. package/src/components/TimelineBar/const.ts +0 -3
  210. package/src/components/TimelineBar/hooks/index.ts +0 -5
  211. package/src/components/TimelineBar/hooks/useHighlightRange.ts +0 -21
  212. package/src/components/TimelineBar/hooks/useMonthGuides.ts +0 -40
  213. package/src/components/TimelineBar/hooks/useTickValues.ts +0 -18
  214. package/src/components/TimelineBar/hooks/useVisibleRange.ts +0 -43
  215. package/src/components/TimelineBar/hooks/useWeekGuides.ts +0 -39
  216. package/src/components/TimelineBar/index.tsx +0 -63
  217. package/src/components/TimelineBar/utils.ts +0 -27
  218. package/src/components/Video/index.tsx +0 -37
  219. package/src/components/index.ts +0 -26
  220. package/src/rn.ts +0 -1
  221. package/src/rns/index.ts +0 -0
  222. package/src/web.ts +0 -2
@@ -1,272 +0,0 @@
1
- 'use client'
2
-
3
- import { useCallback, useEffect, useMemo, useRef } from 'react'
4
- import type { Edge, EdgeChange, Node, NodeChange } from '@xyflow/react'
5
-
6
- interface MindMapCopyPayload<TNodeData extends Record<string, unknown>> {
7
- nodes: Array<Node<TNodeData>>
8
- edges: Edge[]
9
- }
10
-
11
- interface MindMapClipboardData<TNodeData extends Record<string, unknown>> {
12
- t: 'mindmap'
13
- v: 1
14
- payload: MindMapCopyPayload<TNodeData>
15
- }
16
-
17
- interface UseCopyPasteParams<TNodeData extends Record<string, unknown>> {
18
- enabled?: boolean
19
- nodes: Array<Node<TNodeData>>
20
- edges: Edge[]
21
- onNodesChange?: (changes: Array<NodeChange<Node<TNodeData>>>) => void
22
- onEdgesChange?: (changes: Array<EdgeChange<Edge>>) => void
23
- pasteOffset?: number
24
- }
25
-
26
- const CLIPBOARD_MIME: string = 'application/x-mindmap+json'
27
-
28
- const getDescendantIdSet = (edges: Edge[], rootIds: string[]): Set<string> => {
29
- const sourceToTargets = new Map<string, string[]>()
30
- edges.forEach(edge => {
31
- const prev = sourceToTargets.get(edge.source) ?? []
32
- sourceToTargets.set(edge.source, [...prev, edge.target])
33
- })
34
-
35
- const visited = new Set<string>()
36
- const result = new Set<string>()
37
- const queue: string[] = [...rootIds]
38
-
39
- rootIds.forEach(id => {
40
- visited.add(id)
41
- result.add(id)
42
- })
43
-
44
- while (queue.length > 0) {
45
- const id = queue.shift()
46
- if (!id) {
47
- continue
48
- }
49
- const targets = sourceToTargets.get(id) ?? []
50
- for (const targetId of targets) {
51
- if (visited.has(targetId)) {
52
- continue
53
- }
54
- visited.add(targetId)
55
- result.add(targetId)
56
- queue.push(targetId)
57
- }
58
- }
59
-
60
- return result
61
- }
62
-
63
- const getCrypto = (): Crypto | undefined => {
64
- const anyGlobal = globalThis as unknown as { crypto?: Crypto }
65
- return anyGlobal.crypto
66
- }
67
-
68
- const createId = (): string => {
69
- const crypto = getCrypto()
70
- if (crypto?.randomUUID) {
71
- return crypto.randomUUID()
72
- }
73
- return `${Date.now()}-${Math.random().toString(16).slice(2)}`
74
- }
75
-
76
- const clone = <T,>(value: T): T => {
77
- const anyGlobal = globalThis as unknown as { structuredClone?: <V>(v: V) => V }
78
- if (typeof anyGlobal.structuredClone === 'function') {
79
- return anyGlobal.structuredClone(value)
80
- }
81
- return JSON.parse(JSON.stringify(value)) as T
82
- }
83
-
84
- const safeParseClipboard = <TNodeData extends Record<string, unknown>,>(text: string): MindMapCopyPayload<TNodeData> | null => {
85
- try {
86
- const parsed = JSON.parse(text) as MindMapClipboardData<TNodeData>
87
- if (parsed?.t !== 'mindmap' || parsed?.v !== 1) {
88
- return null
89
- }
90
- const payload = parsed.payload
91
- if (!payload?.nodes?.length) {
92
- return null
93
- }
94
- return payload
95
- } catch {
96
- return null
97
- }
98
- }
99
-
100
- export const useCopyPaste = <TNodeData extends Record<string, unknown>,>(params: UseCopyPasteParams<TNodeData>): void => {
101
- const {
102
- enabled = false,
103
- nodes,
104
- edges,
105
- onNodesChange,
106
- onEdgesChange,
107
- pasteOffset = 24,
108
- } = params
109
-
110
- const selectedNodes = useMemo((): Array<Node<TNodeData>> => {
111
- return nodes.filter(node => node.selected)
112
- }, [nodes])
113
-
114
- const copyIdSet = useMemo((): Set<string> => {
115
- if (selectedNodes.length === 0) {
116
- return new Set<string>()
117
- }
118
- const rootIds = selectedNodes.map(n => n.id)
119
- return getDescendantIdSet(edges, rootIds)
120
- }, [edges, selectedNodes])
121
-
122
- const nodesToCopy = useMemo((): Array<Node<TNodeData>> => {
123
- if (copyIdSet.size === 0) {
124
- return []
125
- }
126
- return nodes.filter(node => copyIdSet.has(node.id))
127
- }, [copyIdSet, nodes])
128
-
129
- const edgesToCopy = useMemo((): Edge[] => {
130
- if (copyIdSet.size === 0) {
131
- return []
132
- }
133
- return edges.filter(edge => copyIdSet.has(edge.source) && copyIdSet.has(edge.target))
134
- }, [copyIdSet, edges])
135
-
136
- const pasteIndexRef = useRef<number>(0)
137
-
138
- const isEditableTarget = useCallback((target: EventTarget | null): boolean => {
139
- const el = target as HTMLElement | null
140
- if (!el) {
141
- return false
142
- }
143
- const tag = el.tagName?.toLowerCase()
144
- if (tag === 'input' || tag === 'textarea') {
145
- return true
146
- }
147
- return el.isContentEditable
148
- }, [])
149
-
150
- const handleCopy = useCallback((event: ClipboardEvent): void => {
151
- if (!enabled) {
152
- return
153
- }
154
- if (isEditableTarget(event.target)) {
155
- return
156
- }
157
- if (nodesToCopy.length === 0) {
158
- return
159
- }
160
-
161
- const payload: MindMapCopyPayload<TNodeData> = {
162
- nodes: clone(nodesToCopy),
163
- edges: clone(edgesToCopy),
164
- }
165
-
166
- const clipboardData: MindMapClipboardData<TNodeData> = {
167
- t: 'mindmap',
168
- v: 1,
169
- payload,
170
- }
171
- const text = JSON.stringify(clipboardData)
172
-
173
- if (!event.clipboardData) {
174
- return
175
- }
176
- event.preventDefault()
177
- event.clipboardData.setData(CLIPBOARD_MIME, text)
178
- event.clipboardData.setData('text/plain', text)
179
- }, [enabled, edgesToCopy, isEditableTarget, nodesToCopy])
180
-
181
- const pastePayload = useCallback((payload: MindMapCopyPayload<TNodeData>): void => {
182
- if (!onNodesChange) {
183
- return
184
- }
185
-
186
- pasteIndexRef.current += 1
187
- const shift = pasteOffset * pasteIndexRef.current
188
-
189
- const idMap = new Map<string, string>()
190
- const nextNodes = payload.nodes.map(node => {
191
- const nextId = createId()
192
- idMap.set(node.id, nextId)
193
-
194
- const nextNode = clone(node)
195
- nextNode.id = nextId
196
- nextNode.position = {
197
- x: nextNode.position.x + shift,
198
- y: nextNode.position.y + shift,
199
- }
200
- nextNode.selected = true
201
- delete (nextNode as unknown as { positionAbsolute?: unknown }).positionAbsolute
202
- delete (nextNode as unknown as { measured?: unknown }).measured
203
- return nextNode
204
- })
205
-
206
- const nodeChanges: Array<NodeChange<Node<TNodeData>>> = nextNodes.map(item => ({
207
- type: 'add',
208
- item,
209
- }))
210
- onNodesChange(nodeChanges)
211
-
212
- if (!onEdgesChange || payload.edges.length === 0) {
213
- return
214
- }
215
-
216
- const nextEdges: Edge[] = payload.edges
217
- .map(edge => {
218
- const nextSource = idMap.get(edge.source)
219
- const nextTarget = idMap.get(edge.target)
220
- if (!nextSource || !nextTarget) {
221
- return null
222
- }
223
- const nextEdge = clone(edge)
224
- nextEdge.id = createId()
225
- nextEdge.source = nextSource
226
- nextEdge.target = nextTarget
227
- return nextEdge
228
- })
229
- .filter((e): e is Edge => !!e)
230
-
231
- if (nextEdges.length === 0) {
232
- return
233
- }
234
-
235
- const edgeChanges: Array<EdgeChange<Edge>> = nextEdges.map(item => ({
236
- type: 'add',
237
- item,
238
- }))
239
- onEdgesChange(edgeChanges)
240
- }, [onEdgesChange, onNodesChange, pasteOffset])
241
-
242
- const handlePaste = useCallback((event: ClipboardEvent): void => {
243
- if (!enabled) {
244
- return
245
- }
246
- if (isEditableTarget(event.target)) {
247
- return
248
- }
249
-
250
- const text = event.clipboardData?.getData(CLIPBOARD_MIME) || event.clipboardData?.getData('text/plain') || ''
251
- const payloadFromClipboard = text ? safeParseClipboard<TNodeData>(text) : null
252
- if (!payloadFromClipboard) {
253
- return
254
- }
255
-
256
- event.preventDefault()
257
- pastePayload(payloadFromClipboard)
258
- }, [enabled, isEditableTarget, pastePayload])
259
-
260
- useEffect(() => {
261
- if (!enabled) {
262
- return
263
- }
264
-
265
- document.addEventListener('copy', handleCopy)
266
- document.addEventListener('paste', handlePaste)
267
- return () => {
268
- document.removeEventListener('copy', handleCopy)
269
- document.removeEventListener('paste', handlePaste)
270
- }
271
- }, [enabled, handleCopy, handlePaste])
272
- }
@@ -1,288 +0,0 @@
1
- 'use client'
2
-
3
- import { useCallback, useMemo, useRef, useState } from 'react'
4
- import type { Edge, EdgeChange, Node, NodeChange } from '@xyflow/react'
5
-
6
- interface UseDropToReparentParams<TNodeData extends Record<string, unknown>> {
7
- enabled?: boolean
8
- nodes: Array<Node<TNodeData>>
9
- edges: Edge[]
10
- dropHighlightClassName?: string
11
- canDropOnNode?: (params: { draggingNode: Node<TNodeData>, targetNode: Node<TNodeData> }) => boolean
12
- onNodesChange?: (changes: Array<NodeChange<Node<TNodeData>>>) => void
13
- onEdgesChange?: (changes: Array<EdgeChange<Edge>>) => void
14
- }
15
-
16
- interface UseDropToReparentResult<TNodeData extends Record<string, unknown>> {
17
- onNodeDrag: (_event: unknown, node: Node<TNodeData>) => void
18
- onNodeDragStop: (_event: unknown, node: Node<TNodeData>) => void
19
- draggingNodeId: string | null
20
- dropTargetNodeId: string | null
21
- }
22
-
23
- const defaultDropHighlightClassName: string = 'ring-2 ring-sky-500'
24
-
25
- const normalizeClassName = (className?: string): string[] => {
26
- return (className ?? '').split(/\s+/).map(item => item.trim()).filter(Boolean)
27
- }
28
-
29
- const withClassTokens = (className: string | undefined, tokens: string[], enabled: boolean): string | undefined => {
30
- const list = normalizeClassName(className)
31
- const tokenSet = new Set(list)
32
-
33
- if (enabled) {
34
- tokens.forEach(token => tokenSet.add(token))
35
- } else {
36
- tokens.forEach(token => tokenSet.delete(token))
37
- }
38
-
39
- const next = Array.from(tokenSet).join(' ')
40
- return next.length > 0 ? next : undefined
41
- }
42
-
43
- const getNodeSize = <TNodeData extends Record<string, unknown>,>(node: Node<TNodeData>): { width: number, height: number } => {
44
- const width = node.measured?.width ?? node.width ?? 0
45
- const height = node.measured?.height ?? node.height ?? 0
46
- return { width, height }
47
- }
48
-
49
- const isPointInRect = (point: { x: number, y: number }, rect: { x: number, y: number, w: number, h: number }): boolean => {
50
- return point.x >= rect.x && point.x <= rect.x + rect.w && point.y >= rect.y && point.y <= rect.y + rect.h
51
- }
52
-
53
- const getDescendants = (edges: Edge[], rootId: string): Set<string> => {
54
- const sourceToTargets = new Map<string, string[]>()
55
- edges.forEach(edge => {
56
- const prev = sourceToTargets.get(edge.source) ?? []
57
- sourceToTargets.set(edge.source, [...prev, edge.target])
58
- })
59
-
60
- const visited = new Set<string>([rootId])
61
- const result = new Set<string>()
62
- const queue: string[] = [rootId]
63
-
64
- while (queue.length > 0) {
65
- const currentId = queue.shift()
66
- if (!currentId) {
67
- continue
68
- }
69
- const targets = sourceToTargets.get(currentId) ?? []
70
- for (const targetId of targets) {
71
- if (visited.has(targetId)) {
72
- continue
73
- }
74
- visited.add(targetId)
75
- result.add(targetId)
76
- queue.push(targetId)
77
- }
78
- }
79
-
80
- return result
81
- }
82
-
83
- const pickDropTargetId = <TNodeData extends Record<string, unknown>,>(
84
- nodes: Array<Node<TNodeData>>,
85
- draggingNode: Node<TNodeData>,
86
- edges: Edge[],
87
- canDropOnNode?: (params: { draggingNode: Node<TNodeData>, targetNode: Node<TNodeData> }) => boolean,
88
- ): string | null => {
89
- const draggingSize = getNodeSize(draggingNode)
90
- if (!draggingSize.width || !draggingSize.height) {
91
- return null
92
- }
93
-
94
- const descendants = getDescendants(edges, draggingNode.id)
95
-
96
- const center = {
97
- x: draggingNode.position.x + draggingSize.width / 2,
98
- y: draggingNode.position.y + draggingSize.height / 2,
99
- }
100
-
101
- let bestId: string | null = null
102
- let bestDist: number = Number.POSITIVE_INFINITY
103
-
104
- nodes.forEach(node => {
105
- if (node.id === draggingNode.id) {
106
- return
107
- }
108
- if (descendants.has(node.id)) {
109
- return
110
- }
111
- if (canDropOnNode && !canDropOnNode({ draggingNode, targetNode: node })) {
112
- return
113
- }
114
-
115
- const size = getNodeSize(node)
116
- if (!size.width || !size.height) {
117
- return
118
- }
119
-
120
- const rect = { x: node.position.x, y: node.position.y, w: size.width, h: size.height }
121
- if (!isPointInRect(center, rect)) {
122
- return
123
- }
124
-
125
- const nodeCenterX = node.position.x + size.width / 2
126
- const nodeCenterY = node.position.y + size.height / 2
127
- const dx = center.x - nodeCenterX
128
- const dy = center.y - nodeCenterY
129
- const dist = (dx * dx) + (dy * dy)
130
- if (dist < bestDist) {
131
- bestDist = dist
132
- bestId = node.id
133
- }
134
- })
135
-
136
- return bestId
137
- }
138
-
139
- export const useDropToReparent = <TNodeData extends Record<string, unknown>,>(
140
- params: UseDropToReparentParams<TNodeData>,
141
- ): UseDropToReparentResult<TNodeData> => {
142
- const {
143
- enabled = true,
144
- nodes,
145
- edges,
146
- dropHighlightClassName = defaultDropHighlightClassName,
147
- canDropOnNode,
148
- onNodesChange,
149
- onEdgesChange,
150
- } = params
151
-
152
- const dropTargetIdRef = useRef<string | null>(null)
153
- const [draggingNodeId, setDraggingNodeId] = useState<string | null>(null)
154
- const [dropTargetNodeId, setDropTargetNodeId] = useState<string | null>(null)
155
- const dropHighlightClassTokens = useMemo((): string[] => {
156
- return normalizeClassName(dropHighlightClassName)
157
- }, [dropHighlightClassName])
158
-
159
- const nodeById = useMemo((): Map<string, Node<TNodeData>> => {
160
- return new Map(nodes.map(node => [node.id, node]))
161
- }, [nodes])
162
-
163
- const setDropTargetId = useCallback((nextId: string | null): void => {
164
- const prevId = dropTargetIdRef.current
165
- if (prevId === nextId) {
166
- return
167
- }
168
- dropTargetIdRef.current = nextId
169
- setDropTargetNodeId(nextId)
170
-
171
- if (!onNodesChange) {
172
- return
173
- }
174
-
175
- const changes: Array<NodeChange<Node<TNodeData>>> = []
176
- if (prevId) {
177
- const prevNode = nodeById.get(prevId)
178
- if (prevNode) {
179
- changes.push({
180
- type: 'replace',
181
- id: prevId,
182
- item: {
183
- ...prevNode,
184
- className: withClassTokens(prevNode.className, dropHighlightClassTokens, false),
185
- },
186
- })
187
- }
188
- }
189
- if (nextId) {
190
- const nextNode = nodeById.get(nextId)
191
- if (nextNode) {
192
- changes.push({
193
- type: 'replace',
194
- id: nextId,
195
- item: {
196
- ...nextNode,
197
- className: withClassTokens(nextNode.className, dropHighlightClassTokens, true),
198
- },
199
- })
200
- }
201
- }
202
-
203
- if (changes.length > 0) {
204
- onNodesChange(changes)
205
- }
206
- }, [dropHighlightClassTokens, nodeById, onNodesChange])
207
-
208
- const onNodeDrag = useCallback((_event: unknown, node: Node<TNodeData>): void => {
209
- setDraggingNodeId(node.id)
210
- if (!enabled) {
211
- setDropTargetId(null)
212
- return
213
- }
214
- const targetId = pickDropTargetId(nodes, node, edges, canDropOnNode)
215
- setDropTargetId(targetId)
216
- }, [canDropOnNode, edges, enabled, nodes, setDropTargetId])
217
-
218
- const onNodeDragStop = useCallback((_event: unknown, node: Node<TNodeData>): void => {
219
- const targetId = dropTargetIdRef.current
220
- setDropTargetId(null)
221
- setDraggingNodeId(null)
222
-
223
- if (!enabled) {
224
- return
225
- }
226
- if (!targetId) {
227
- return
228
- }
229
- if (!onEdgesChange) {
230
- return
231
- }
232
-
233
- const childId = node.id
234
- if (targetId === childId) {
235
- return
236
- }
237
-
238
- const descendants = getDescendants(edges, childId)
239
- if (descendants.has(targetId)) {
240
- return
241
- }
242
-
243
- const targetNode = nodeById.get(targetId)
244
- if (!targetNode) {
245
- return
246
- }
247
- if (canDropOnNode && !canDropOnNode({ draggingNode: node, targetNode })) {
248
- return
249
- }
250
-
251
- const nextEdgeId = `e-${targetId}-${childId}`
252
- const hasSameEdge = edges.some(edge => edge.source === targetId && edge.target === childId)
253
- const incomingEdges = edges.filter(edge => edge.target === childId)
254
-
255
- const edgeChanges: Array<EdgeChange<Edge>> = []
256
- incomingEdges.forEach(edge => {
257
- if (edge.source === targetId && edge.target === childId) {
258
- return
259
- }
260
- edgeChanges.push({ type: 'remove', id: edge.id })
261
- })
262
-
263
- if (!hasSameEdge) {
264
- edgeChanges.push({
265
- type: 'add',
266
- item: {
267
- id: nextEdgeId,
268
- source: targetId,
269
- target: childId,
270
- type: 'smoothstep',
271
- },
272
- })
273
- }
274
-
275
- if (edgeChanges.length === 0) {
276
- return
277
- }
278
-
279
- onEdgesChange(edgeChanges)
280
- }, [canDropOnNode, edges, enabled, nodeById, onEdgesChange, setDropTargetId])
281
-
282
- return {
283
- onNodeDrag,
284
- onNodeDragStop,
285
- draggingNodeId,
286
- dropTargetNodeId,
287
- }
288
- }
@@ -1,146 +0,0 @@
1
- 'use client'
2
-
3
- import { useCallback, useMemo } from 'react'
4
- import type { Edge, EdgeChange, Node, NodeChange } from '@xyflow/react'
5
-
6
- interface GetCountsResult {
7
- childCount: number
8
- descendantCount: number
9
- }
10
-
11
- interface UseExpandCollapseParams<TNodeData extends Record<string, unknown>> {
12
- nodes: Array<Node<TNodeData>>
13
- edges: Edge[]
14
- onNodesChange?: (changes: Array<NodeChange<Node<TNodeData>>>) => void
15
- onEdgesChange?: (changes: Array<EdgeChange<Edge>>) => void
16
- }
17
-
18
- interface UseExpandCollapseResult {
19
- getCounts: (nodeId: string) => GetCountsResult
20
- expand: (nodeId: string) => void
21
- collapse: (nodeId: string) => void
22
- }
23
-
24
- const buildChildrenById = (edges: Edge[]): Map<string, string[]> => {
25
- const map = new Map<string, string[]>()
26
- edges.forEach(edge => {
27
- const prev = map.get(edge.source) ?? []
28
- map.set(edge.source, [...prev, edge.target])
29
- })
30
- return map
31
- }
32
-
33
- const getDescendantIdSet = (childrenById: Map<string, string[]>, rootId: string): Set<string> => {
34
- const visited = new Set<string>([rootId])
35
- const result = new Set<string>()
36
- const queue: string[] = [rootId]
37
-
38
- while (queue.length > 0) {
39
- const currentId = queue.shift()
40
- if (!currentId) {
41
- continue
42
- }
43
- const children = childrenById.get(currentId) ?? []
44
- for (const childId of children) {
45
- if (visited.has(childId)) {
46
- continue
47
- }
48
- visited.add(childId)
49
- result.add(childId)
50
- queue.push(childId)
51
- }
52
- }
53
-
54
- return result
55
- }
56
-
57
- export const useExpandCollapse = <TNodeData extends Record<string, unknown>,>(
58
- params: UseExpandCollapseParams<TNodeData>,
59
- ): UseExpandCollapseResult => {
60
- const { nodes, edges, onNodesChange, onEdgesChange } = params
61
-
62
- const childrenById = useMemo((): Map<string, string[]> => {
63
- return buildChildrenById(edges)
64
- }, [edges])
65
-
66
- const nodeById = useMemo((): Map<string, Node<TNodeData>> => {
67
- return new Map(nodes.map(n => [n.id, n]))
68
- }, [nodes])
69
-
70
- const edgeById = useMemo((): Map<string, Edge> => {
71
- return new Map(edges.map(e => [e.id, e]))
72
- }, [edges])
73
-
74
- const getCounts = useCallback((nodeId: string): GetCountsResult => {
75
- const childCount = (childrenById.get(nodeId) ?? []).length
76
- const descendantCount = getDescendantIdSet(childrenById, nodeId).size
77
- return { childCount, descendantCount }
78
- }, [childrenById])
79
-
80
- const setSubtreeHidden = useCallback((nodeId: string, hidden: boolean): void => {
81
- const descendantIdSet = getDescendantIdSet(childrenById, nodeId)
82
- if (descendantIdSet.size === 0) {
83
- return
84
- }
85
-
86
- if (onNodesChange) {
87
- const nodeChanges: Array<NodeChange<Node<TNodeData>>> = []
88
- descendantIdSet.forEach(id => {
89
- const node = nodeById.get(id)
90
- if (!node) {
91
- return
92
- }
93
- if ((node.hidden ?? false) === hidden) {
94
- return
95
- }
96
- nodeChanges.push({
97
- type: 'replace',
98
- id,
99
- item: {
100
- ...node,
101
- hidden,
102
- selected: false,
103
- },
104
- })
105
- })
106
- if (nodeChanges.length > 0) {
107
- onNodesChange(nodeChanges)
108
- }
109
- }
110
-
111
- if (onEdgesChange) {
112
- const idSet = new Set<string>([nodeId, ...Array.from(descendantIdSet)])
113
- const edgeChanges: Array<EdgeChange<Edge>> = edges
114
- .filter(edge => idSet.has(edge.source) && idSet.has(edge.target))
115
- .map(edge => edgeById.get(edge.id))
116
- .filter((edge): edge is Edge => !!edge)
117
- .filter(edge => (edge.hidden ?? false) !== hidden)
118
- .map(edge => ({
119
- type: 'replace',
120
- id: edge.id,
121
- item: {
122
- ...edge,
123
- hidden,
124
- },
125
- }))
126
-
127
- if (edgeChanges.length > 0) {
128
- onEdgesChange(edgeChanges)
129
- }
130
- }
131
- }, [childrenById, edgeById, edges, nodeById, onEdgesChange, onNodesChange])
132
-
133
- const expand = useCallback((nodeId: string): void => {
134
- setSubtreeHidden(nodeId, false)
135
- }, [setSubtreeHidden])
136
-
137
- const collapse = useCallback((nodeId: string): void => {
138
- setSubtreeHidden(nodeId, true)
139
- }, [setSubtreeHidden])
140
-
141
- return {
142
- getCounts,
143
- expand,
144
- collapse,
145
- }
146
- }