@hkdigital/lib-sveltekit 0.2.8 → 0.2.10

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 (246) hide show
  1. package/README.md +135 -135
  2. package/dist/assets/autospuiten/car-paint-picker.js +41 -41
  3. package/dist/assets/autospuiten/labels.js +7 -7
  4. package/dist/classes/cache/IndexedDbCache.js +1407 -1407
  5. package/dist/classes/cache/MemoryResponseCache.js +138 -138
  6. package/dist/classes/cache/index.js +5 -5
  7. package/dist/classes/cache/typedef.js +41 -41
  8. package/dist/classes/data/IterableTree.js +243 -243
  9. package/dist/classes/data/Selector.js +190 -190
  10. package/dist/classes/data/index.js +2 -2
  11. package/dist/classes/events/EventEmitter.js +275 -275
  12. package/dist/classes/events/index.js +2 -2
  13. package/dist/classes/index.js +4 -4
  14. package/dist/classes/logging/Logger.js +158 -158
  15. package/dist/classes/logging/constants.js +18 -18
  16. package/dist/classes/logging/index.js +4 -4
  17. package/dist/classes/promise/HkPromise.js +377 -377
  18. package/dist/classes/promise/index.js +1 -1
  19. package/dist/classes/services/ServiceBase.js +409 -409
  20. package/dist/classes/services/ServiceManager.js +1114 -1114
  21. package/dist/classes/services/constants.js +12 -12
  22. package/dist/classes/services/index.js +5 -5
  23. package/dist/classes/stores/SubscribersCount.js +107 -107
  24. package/dist/classes/stores/index.js +1 -1
  25. package/dist/classes/streams/LogTransformStream.js +19 -19
  26. package/dist/classes/streams/ServerEventsStore.js +110 -110
  27. package/dist/classes/streams/TimeStampSource.js +26 -26
  28. package/dist/classes/streams/index.js +3 -3
  29. package/dist/classes/svelte/audio/AudioLoader.svelte.js +58 -58
  30. package/dist/classes/svelte/audio/AudioScene.svelte.js +324 -324
  31. package/dist/classes/svelte/audio/mocks.js +35 -35
  32. package/dist/classes/svelte/finite-state-machine/FiniteStateMachine.svelte.js +133 -133
  33. package/dist/classes/svelte/finite-state-machine/index.js +1 -1
  34. package/dist/classes/svelte/image/ImageLoader.svelte.js +45 -45
  35. package/dist/classes/svelte/image/ImageScene.svelte.js +249 -249
  36. package/dist/classes/svelte/image/ImageVariantsLoader.svelte.js +152 -152
  37. package/dist/classes/svelte/image/index.js +4 -4
  38. package/dist/classes/svelte/image/mocks.js +35 -35
  39. package/dist/classes/svelte/image/typedef.js +8 -8
  40. package/dist/classes/svelte/index.js +14 -14
  41. package/dist/classes/svelte/loading-state-machine/LoadingStateMachine.svelte.js +109 -109
  42. package/dist/classes/svelte/loading-state-machine/constants.js +16 -16
  43. package/dist/classes/svelte/loading-state-machine/index.js +3 -3
  44. package/dist/classes/svelte/network-loader/NetworkLoader.svelte.js +338 -338
  45. package/dist/classes/svelte/network-loader/constants.js +3 -3
  46. package/dist/classes/svelte/network-loader/index.js +3 -3
  47. package/dist/classes/svelte/network-loader/mocks.js +30 -30
  48. package/dist/classes/svelte/network-loader/typedef.js +8 -8
  49. package/dist/components/area/HkArea.svelte +49 -49
  50. package/dist/components/area/HkGridArea.svelte +77 -77
  51. package/dist/components/area/index.js +2 -2
  52. package/dist/components/buttons/button/Button.svelte +82 -82
  53. package/dist/components/buttons/button-icon-steeze/SteezeIconButton.svelte +30 -30
  54. package/dist/components/buttons/button-text/TextButton.svelte +21 -21
  55. package/dist/components/buttons/index.js +3 -3
  56. package/dist/components/debug/debug-panel-design-scaling/DebugPanelDesignScaling.svelte +146 -146
  57. package/dist/components/debug/index.js +1 -1
  58. package/dist/components/drag-drop/DragController.js +44 -44
  59. package/dist/components/drag-drop/DragDropContext.svelte +111 -110
  60. package/dist/components/drag-drop/Draggable.svelte +502 -512
  61. package/dist/components/drag-drop/{Dropzone.svelte → DropZone.svelte} +258 -258
  62. package/dist/components/drag-drop/DropZoneArea.svelte +119 -119
  63. package/dist/components/drag-drop/DropZoneList.svelte +125 -125
  64. package/dist/components/drag-drop/actions.d.ts +9 -0
  65. package/dist/components/drag-drop/actions.js +26 -0
  66. package/dist/components/drag-drop/drag-state.svelte.d.ts +3 -1
  67. package/dist/components/drag-drop/drag-state.svelte.js +322 -319
  68. package/dist/components/drag-drop/drag-state.svelte.js__ +319 -0
  69. package/dist/components/drag-drop/index.js +7 -7
  70. package/dist/components/drag-drop/util.d.ts +0 -32
  71. package/dist/components/drag-drop/util.js +85 -85
  72. package/dist/components/hkdev/blocks/TextBlock.svelte +46 -46
  73. package/dist/components/hkdev/buttons/CheckButton.svelte +62 -62
  74. package/dist/components/icons/HkIcon.svelte +86 -86
  75. package/dist/components/icons/HkTabIcon.svelte +116 -116
  76. package/dist/components/icons/SteezeIcon.svelte +97 -97
  77. package/dist/components/icons/index.js +6 -6
  78. package/dist/components/icons/typedef.js +16 -16
  79. package/dist/components/index.js +2 -2
  80. package/dist/components/inputs/index.js +1 -1
  81. package/dist/components/inputs/text-input/TestTextInput.svelte__ +102 -102
  82. package/dist/components/inputs/text-input/TextInput.svelte +223 -223
  83. package/dist/components/inputs/text-input/TextInput.svelte___ +83 -83
  84. package/dist/components/inputs/text-input/assets/IconInvalid.svelte +14 -14
  85. package/dist/components/inputs/text-input/assets/IconValid.svelte +12 -12
  86. package/dist/components/layout/grid-layers/GridLayers.svelte +63 -63
  87. package/dist/components/layout/grid-layers/GridLayers.svelte__heightFrom__ +372 -0
  88. package/dist/components/layout/grid-layers/util.js +74 -74
  89. package/dist/components/layout/index.js +1 -1
  90. package/dist/components/panels/index.js +1 -1
  91. package/dist/components/panels/panel/Panel.svelte +43 -43
  92. package/dist/components/rows/index.js +3 -3
  93. package/dist/components/rows/panel-grid-row/PanelGridRow.svelte +104 -104
  94. package/dist/components/rows/panel-row-2/PanelRow2.svelte +40 -40
  95. package/dist/components/tab-bar/HkTabBar.state.svelte.js +149 -149
  96. package/dist/components/tab-bar/HkTabBar.svelte +74 -74
  97. package/dist/components/tab-bar/HkTabBarSelector.state.svelte.js +93 -93
  98. package/dist/components/tab-bar/HkTabBarSelector.svelte +49 -49
  99. package/dist/components/tab-bar/index.js +17 -17
  100. package/dist/components/tab-bar/typedef.js +11 -11
  101. package/dist/config/imagetools-config.js +189 -189
  102. package/dist/config/imagetools.d.ts +72 -72
  103. package/dist/constants/bases.js +13 -13
  104. package/dist/constants/errors/api.js +9 -9
  105. package/dist/constants/errors/generic.js +5 -5
  106. package/dist/constants/errors/index.js +3 -3
  107. package/dist/constants/errors/jwt.js +5 -5
  108. package/dist/constants/http/headers.js +6 -6
  109. package/dist/constants/http/index.js +2 -2
  110. package/dist/constants/http/methods.js +2 -2
  111. package/dist/constants/index.js +3 -3
  112. package/dist/constants/mime/application.js +5 -5
  113. package/dist/constants/mime/audio.js +13 -13
  114. package/dist/constants/mime/image.js +3 -3
  115. package/dist/constants/mime/index.js +4 -4
  116. package/dist/constants/mime/text.js +2 -2
  117. package/dist/constants/regexp/index.js +31 -31
  118. package/dist/constants/regexp/inspiratie.js__ +95 -95
  119. package/dist/constants/regexp/text.js +49 -49
  120. package/dist/constants/regexp/user.js +32 -32
  121. package/dist/constants/regexp/web.js +3 -3
  122. package/dist/constants/state-labels/drag-states.js +6 -6
  123. package/dist/constants/state-labels/drop-states.js +6 -6
  124. package/dist/constants/state-labels/input-states.js +11 -11
  125. package/dist/constants/state-labels/submit-states.js +4 -4
  126. package/dist/constants/time.js +28 -28
  127. package/dist/css/utilities.css +43 -43
  128. package/dist/design/design-config.js +73 -73
  129. package/dist/design/tailwind-theme-extend.js +158 -158
  130. package/dist/features/button-group/ButtonGroup.svelte +82 -82
  131. package/dist/features/button-group/typedef.js +10 -10
  132. package/dist/features/compare-left-right/CompareLeftRight.svelte +179 -179
  133. package/dist/features/compare-left-right/index.js +1 -1
  134. package/dist/features/game-box/GameBox.svelte +577 -577
  135. package/dist/features/game-box/gamebox.util.js +83 -83
  136. package/dist/features/hk-app-layout/HkAppLayout.state.svelte.js +25 -25
  137. package/dist/features/hk-app-layout/HkAppLayout.svelte +251 -251
  138. package/dist/features/image-box/ImageBox.svelte +210 -210
  139. package/dist/features/image-box/index.js +5 -5
  140. package/dist/features/image-box/typedef.js +32 -32
  141. package/dist/features/index.js +23 -23
  142. package/dist/features/presenter/ImageSlide.svelte +64 -64
  143. package/dist/features/presenter/Presenter.state.svelte.js +638 -638
  144. package/dist/features/presenter/Presenter.svelte +142 -142
  145. package/dist/features/presenter/constants.js +7 -7
  146. package/dist/features/presenter/index.js +10 -10
  147. package/dist/features/presenter/typedef.js +106 -106
  148. package/dist/features/presenter/util.js +210 -210
  149. package/dist/features/virtual-viewport/VirtualViewport.svelte +196 -196
  150. package/dist/schemas/index.js +1 -1
  151. package/dist/schemas/validate-url.js +180 -180
  152. package/dist/server/index.js +1 -1
  153. package/dist/server/logger.js +94 -94
  154. package/dist/states/index.js +1 -1
  155. package/dist/states/navigation.svelte.js +55 -55
  156. package/dist/stores/index.js +1 -1
  157. package/dist/stores/theme.js +80 -80
  158. package/dist/themes/hkdev/components/blocks/text-block.css +41 -41
  159. package/dist/themes/hkdev/components/boxes/game-box.css +12 -12
  160. package/dist/themes/hkdev/components/buttons/button-icon-steeze.css +22 -22
  161. package/dist/themes/hkdev/components/buttons/button-text.css +32 -32
  162. package/dist/themes/hkdev/components/buttons/button.css +146 -146
  163. package/dist/themes/hkdev/components/buttons/skip-button.css +6 -6
  164. package/dist/themes/hkdev/components/drag-drop/draggable.css +73 -73
  165. package/dist/themes/hkdev/components/drag-drop/drop-zone.css +48 -48
  166. package/dist/themes/hkdev/components/icons/icon-steeze.css +22 -22
  167. package/dist/themes/hkdev/components/inputs/text-input.css +104 -104
  168. package/dist/themes/hkdev/components/panels/panel.css +27 -27
  169. package/dist/themes/hkdev/components/rows/panel-grid-row.css +6 -6
  170. package/dist/themes/hkdev/components/rows/panel-row-2.css +7 -7
  171. package/dist/themes/hkdev/components.css +53 -53
  172. package/dist/themes/hkdev/debug.css +1 -1
  173. package/dist/themes/hkdev/global/layout.css +39 -39
  174. package/dist/themes/hkdev/global/on-colors.css +53 -53
  175. package/dist/themes/hkdev/globals.css +11 -11
  176. package/dist/themes/hkdev/responsive.css +12 -12
  177. package/dist/themes/hkdev/theme-ext.js +15 -15
  178. package/dist/themes/hkdev/theme.js +235 -235
  179. package/dist/themes/index.js +1 -1
  180. package/dist/typedef/context.js +6 -6
  181. package/dist/typedef/drag.js +25 -25
  182. package/dist/typedef/drop.js +12 -12
  183. package/dist/typedef/image.js +38 -38
  184. package/dist/typedef/index.js +4 -4
  185. package/dist/util/array/index.js +436 -436
  186. package/dist/util/bases/base58.js +262 -262
  187. package/dist/util/bases/index.js +1 -1
  188. package/dist/util/compare/index.js +247 -247
  189. package/dist/util/css/css-vars.js +83 -83
  190. package/dist/util/css/index.js +1 -1
  191. package/dist/util/design-system/components/states.js +22 -22
  192. package/dist/util/design-system/css/clamp.js +66 -66
  193. package/dist/util/design-system/css/root-design-vars.js +102 -102
  194. package/dist/util/design-system/index.js +5 -5
  195. package/dist/util/design-system/layout/scaling.js +228 -228
  196. package/dist/util/design-system/skeleton.js +208 -208
  197. package/dist/util/design-system/tailwind.js +288 -288
  198. package/dist/util/env/index.js +9 -9
  199. package/dist/util/expect/arrays.js +47 -47
  200. package/dist/util/expect/index.js +259 -259
  201. package/dist/util/expect/primitives.js +55 -55
  202. package/dist/util/expect/url.js +60 -60
  203. package/dist/util/function/index.js +218 -218
  204. package/dist/util/geo/index.js +26 -26
  205. package/dist/util/http/caching.js +263 -263
  206. package/dist/util/http/errors.js +97 -97
  207. package/dist/util/http/headers.js +75 -75
  208. package/dist/util/http/http-request.js +379 -379
  209. package/dist/util/http/index.js +22 -22
  210. package/dist/util/http/json-request.js +224 -224
  211. package/dist/util/http/mocks.js +65 -65
  212. package/dist/util/http/response.js +294 -294
  213. package/dist/util/http/test-data__/content-length-test-hkdigital-small.V4HfZyBQ.avif +0 -0
  214. package/dist/util/http/typedef.js +93 -93
  215. package/dist/util/http/url.js +52 -52
  216. package/dist/util/image/index.js +86 -86
  217. package/dist/util/index.js +2 -2
  218. package/dist/util/is/index.js +140 -140
  219. package/dist/util/iterate/index.js +234 -234
  220. package/dist/util/object/index.js +1361 -1361
  221. package/dist/util/singleton/index.js +97 -97
  222. package/dist/util/string/array-path.js +75 -75
  223. package/dist/util/string/convert.js +54 -54
  224. package/dist/util/string/fs.js +226 -226
  225. package/dist/util/string/index.js +5 -5
  226. package/dist/util/string/interpolate.js +61 -61
  227. package/dist/util/string/pad.js +10 -10
  228. package/dist/util/svelte/index.js +4 -4
  229. package/dist/util/svelte/loading/loading-tracker.svelte.js +108 -108
  230. package/dist/util/svelte/observe/index.js +49 -49
  231. package/dist/util/svelte/state-context/index.js +117 -117
  232. package/dist/util/svelte/wait/index.js +38 -38
  233. package/dist/util/sveltekit/index.js +1 -1
  234. package/dist/util/sveltekit/route-folders/index.js +101 -101
  235. package/dist/util/time/index.js +323 -323
  236. package/dist/util/unique/index.js +249 -249
  237. package/dist/valibot/date.js__ +10 -10
  238. package/dist/valibot/index.js +9 -9
  239. package/dist/valibot/url.js +95 -95
  240. package/dist/valibot/user.js +23 -23
  241. package/dist/zod/all.js +33 -33
  242. package/dist/zod/generic.js +11 -11
  243. package/dist/zod/javascript.js +32 -32
  244. package/dist/zod/user.js +16 -16
  245. package/dist/zod/web.js +52 -52
  246. package/package.json +112 -112
@@ -1,512 +1,502 @@
1
- <script>
2
- import { toStateClasses } from '../../util/design-system/index.js';
3
- import { createOrGetDragState } from './drag-state.svelte.js';
4
- import { DragController } from './DragController.js';
5
- import { generateLocalId } from '../../util/unique';
6
- import { onDestroy } from 'svelte';
7
- import {
8
- IDLE,
9
- DRAGGING,
10
- DRAG_PREVIEW,
11
- DROPPING
12
- } from '../../constants/state-labels/drag-states.js';
13
-
14
-
15
- /** @typedef {import('../../typedef').SimulatedDragEvent} SimulatedDragEvent */
16
-
17
- /**
18
- * @type {{
19
- * item: any,
20
- * group?: string,
21
- * source?: string,
22
- * disabled?: boolean,
23
- * dragDelay?: number,
24
- * base?: string,
25
- * classes?: string,
26
- * children: import('svelte').Snippet<[{
27
- * element: HTMLElement,
28
- * rect: DOMRect
29
- * }]>,
30
- * draggingSnippet?: import('svelte').Snippet<[{
31
- * element: HTMLElement,
32
- * rect: DOMRect
33
- * }]>,
34
- * contextKey?: import('../../typedef').ContextKey,
35
- * isDragging?: boolean,
36
- * isDropping?: boolean,
37
- * isDragPreview?: boolean,
38
- * onDragStart?: (detail: {
39
- * event: DragEvent,
40
- * item: any,
41
- * source: string,
42
- * group: string,
43
- * getController: () => DragController
44
- * }) => void,
45
- * onDragging?: (detail: {
46
- * event: DragEvent,
47
- * item: any
48
- * }) => void,
49
- * onDragEnd?: (detail: {
50
- * event: DragEvent,
51
- * item: any,
52
- * wasDropped: boolean
53
- * }) => void,
54
- * onDrop?: (detail: {
55
- * event: DragEvent,
56
- * item: any,
57
- * wasDropped: boolean
58
- * }) => void,
59
- * canDrag?: (item: any) => boolean,
60
- * [key: string]: any
61
- * }}
62
- */
63
- let {
64
- item,
65
- group = 'default',
66
- source = 'default',
67
- disabled = false,
68
- dragDelay = 0,
69
- base = '',
70
- classes = '',
71
- children,
72
- draggingSnippet,
73
- contextKey,
74
- isDragging = $bindable(false),
75
- isDropping = $bindable(false),
76
- isDragPreview = $bindable(false),
77
- onDragStart,
78
- onDragging,
79
- onDragEnd,
80
- onDrop,
81
- canDrag = () => true,
82
- ...attrs
83
- } = $props();
84
-
85
- const dragState = createOrGetDragState(contextKey);
86
-
87
- const draggableId = generateLocalId();
88
-
89
- // svelte-ignore non_reactive_update
90
- let draggableElement;
91
-
92
- let dragTimeout = null;
93
- let currentState = $state(IDLE);
94
-
95
- // Custom preview follower state
96
- let showPreview = $state(false);
97
- let previewX = $state(0);
98
- let previewY = $state(0);
99
- let dragOffsetX = $state(0);
100
- let dragOffsetY = $state(0);
101
- let customPreviewSet = $state(false);
102
- let elementRect = $state(null);
103
-
104
- // Track if current draggable can drop in the active zone
105
- let canDropInActiveZone = $derived.by(() => {
106
- if (currentState !== DRAGGING || !dragState.activeDropZone) return false;
107
-
108
- const activeZone = dragState.dropZones.get(dragState.activeDropZone);
109
- return activeZone?.canDrop || false;
110
- });
111
-
112
- // Computed state object for CSS classes
113
- let stateObject = $derived({
114
- idle: currentState === IDLE,
115
- dragging: currentState === DRAGGING,
116
- 'drag-preview': currentState === DRAG_PREVIEW,
117
- dropping: currentState === DROPPING,
118
- 'drag-disabled': disabled || !canDrag(item),
119
- 'can-drop': currentState === DRAGGING && canDropInActiveZone,
120
- 'cannot-drop': currentState === DRAGGING && dragState.activeDropZone && !canDropInActiveZone
121
- });
122
-
123
- let stateClasses = $derived(toStateClasses(stateObject));
124
-
125
- // Update bindable props
126
- $effect(() => {
127
- isDragging = currentState === DRAGGING;
128
- isDropping = currentState === DROPPING;
129
- isDragPreview = currentState === DRAG_PREVIEW;
130
- });
131
-
132
- // Clean up on component destroy
133
- onDestroy(() => {
134
- if (showPreview) {
135
- document.removeEventListener('dragover', handleDocumentDragOver);
136
- }
137
- });
138
-
139
- /**
140
- * Handle document level dragover to ensure we get position updates
141
- * @param {DragEvent} event
142
- */
143
- function handleDocumentDragOver(event) {
144
- if (showPreview && currentState === DRAGGING) {
145
- // Update position for the custom preview
146
- previewX = event.clientX - dragOffsetX;
147
- previewY = event.clientY - dragOffsetY;
148
-
149
- // Prevent default to allow drop
150
- event.preventDefault();
151
- }
152
- }
153
-
154
- /**
155
- * Handle drag start
156
- * @param {DragEvent} event
157
- */
158
- function handleDragStart(event) {
159
- if (disabled || !canDrag(item)) {
160
- event.preventDefault();
161
- return;
162
- }
163
-
164
- // Handle drag delay
165
- if (dragDelay > 0) {
166
- event.preventDefault();
167
- currentState = DRAG_PREVIEW;
168
-
169
- dragTimeout = setTimeout(() => {
170
- currentState = DRAGGING;
171
- startDrag(event);
172
- }, dragDelay);
173
- return;
174
- }
175
-
176
- currentState = DRAGGING;
177
- startDrag(event);
178
- }
179
-
180
- /**
181
- * Start the drag operation
182
- * @param {DragEvent} event - The drag event
183
- */
184
- function startDrag(event) {
185
- // Get the element's bounding rectangle
186
- const rect = draggableElement.getBoundingClientRect();
187
-
188
- // Calculate grab offsets - this is where the user grabbed the element
189
- dragOffsetX = event.clientX - rect.left;
190
- dragOffsetY = event.clientY - rect.top;
191
-
192
- // Create drag data with draggableId included
193
- const dragData = {
194
- draggableId,
195
- offsetX: dragOffsetX,
196
- offsetY: dragOffsetY,
197
- item,
198
- source,
199
- group
200
- };
201
-
202
- // Set shared drag state
203
- dragState.start(draggableId, dragData);
204
-
205
- // Set minimal data transfer for browser drag and drop API
206
- event.dataTransfer.effectAllowed = 'move';
207
- event.dataTransfer.setData(
208
- 'application/json',
209
- JSON.stringify({ draggableId })
210
- );
211
-
212
- // Chrome also likes to have text/plain
213
- event.dataTransfer.setData('text/plain', draggableId);
214
-
215
- // Create the preview controller
216
- const previewController = new DragController(event);
217
-
218
- // Function to get the preview controller
219
- const getController = () => previewController;
220
-
221
- // Call onDragStart with the getController function
222
- onDragStart?.({ event, item, source, group, getController });
223
-
224
- // Apply drag preview if available
225
- // if (draggingSnippet) {
226
- // try {
227
- // Store rectangle information for the snippet
228
- elementRect = rect;
229
-
230
- // These offsets represent where the user grabbed the element relative to its top-left corner
231
- dragOffsetX = event.clientX - rect.left;
232
- dragOffsetY = event.clientY - rect.top;
233
-
234
- // Set initial position - this places the preview at the element's original position
235
- previewX = rect.left;
236
- previewY = rect.top;
237
-
238
- // Set a transparent 1x1 pixel image to hide browser's
239
- // default preview
240
- const emptyImg = new Image();
241
- emptyImg.src =
242
- 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
243
-
244
- // Chrome needs the image to be loaded before setting it
245
- emptyImg.onload = () => {
246
- if (event.dataTransfer) {
247
- event.dataTransfer.setDragImage(emptyImg, 0, 0);
248
- }
249
- };
250
-
251
- // Fallback: try to set it immediately too
252
- event.dataTransfer.setDragImage(emptyImg, 0, 0);
253
-
254
- // Add document level event listener to track mouse movement
255
- document.addEventListener('dragover', handleDocumentDragOver);
256
-
257
- // Show custom preview
258
- showPreview = true;
259
- customPreviewSet = true;
260
- // } catch (err) {
261
- // console.error('Error setting up custom preview:', err);
262
- // // Fallback to default preview
263
- // previewController.applyDefaultPreview();
264
- // }
265
- // } else {
266
- // // Apply default preview if no custom preview was set
267
- // previewController.applyDefaultPreview();
268
- // }
269
- }
270
-
271
- /**
272
- * Handle during drag
273
- * @param {DragEvent} event
274
- */
275
- function handleDrag(event) {
276
- if (currentState === DRAGGING) {
277
- onDragging?.({ event, item });
278
- }
279
- }
280
-
281
- /**
282
- * Handle drag end
283
- * @param {DragEvent} event
284
- */
285
- function handleDragEnd(event) {
286
- clearTimeout(dragTimeout);
287
-
288
- // Clear global drag state
289
- dragState.end(draggableId);
290
-
291
- // Clean up document event listener
292
- if (customPreviewSet) {
293
- document.removeEventListener('dragover', handleDocumentDragOver);
294
- showPreview = false;
295
- customPreviewSet = false;
296
- elementRect = null;
297
- }
298
-
299
- // Check if drop was successful
300
- const wasDropped = event.dataTransfer.dropEffect !== 'none';
301
-
302
- if (wasDropped) {
303
- currentState = DROPPING;
304
- onDrop?.({ event, item, wasDropped: true });
305
-
306
- // Brief dropping state before returning to idle
307
- setTimeout(() => {
308
- currentState = IDLE;
309
- }, 100);
310
- } else {
311
- currentState = IDLE;
312
- }
313
-
314
- onDragEnd?.({ event, item, wasDropped });
315
- }
316
-
317
- /**
318
- * Handle mouse down for drag delay
319
- * @param {MouseEvent} event
320
- */
321
- function handleMouseDown(event) {
322
- if (dragDelay > 0 && !disabled && canDrag(item)) {
323
- // Could add visual feedback here
324
- }
325
- }
326
-
327
- /**
328
- * Handle mouse up to cancel drag delay
329
- * @param {MouseEvent} event
330
- */
331
- function handleMouseUp(event) {
332
- if (dragTimeout) {
333
- clearTimeout(dragTimeout);
334
- currentState = IDLE;
335
- }
336
- }
337
-
338
- // Add these variables for touch handling
339
- let touchDragging = $state(false);
340
- let touchStartX = 0;
341
- let touchStartY = 0;
342
- let touchPreviewElement = null;
343
-
344
- /**
345
- * Handle touch start
346
- * @param {TouchEvent} event
347
- */
348
- function handleTouchStart(event) {
349
- if (disabled || !canDrag(item)) return;
350
-
351
- const touch = event.touches[0];
352
- touchStartX = touch.clientX;
353
- touchStartY = touch.clientY;
354
-
355
- // Start drag after a small delay to distinguish from scrolling
356
- dragTimeout = setTimeout(() => {
357
- touchDragging = true;
358
- currentState = DRAGGING;
359
-
360
- // Create drag data
361
- const rect = draggableElement.getBoundingClientRect();
362
- dragOffsetX = touch.clientX - rect.left;
363
- dragOffsetY = touch.clientY - rect.top;
364
-
365
- const dragData = {
366
- draggableId,
367
- offsetX: dragOffsetX,
368
- offsetY: dragOffsetY,
369
- item,
370
- source,
371
- group
372
- };
373
-
374
- dragState.start(draggableId, dragData);
375
-
376
- // Show preview
377
- // if (draggingSnippet) {
378
- elementRect = rect;
379
- previewX = rect.left;
380
- previewY = rect.top;
381
- showPreview = true;
382
- // }
383
-
384
- // Prevent scrolling while dragging
385
- event.preventDefault();
386
-
387
- // Add document-level touch handlers
388
- document.addEventListener('touchmove', handleTouchMove, {
389
- passive: false
390
- });
391
- document.addEventListener('touchend', handleTouchEnd);
392
- }, 150); // 150ms delay to distinguish from scrolling
393
- }
394
-
395
- /**
396
- * Handle touch move
397
- * @param {TouchEvent} event
398
- */
399
- function handleTouchMove(event) {
400
- if (!touchDragging) return;
401
-
402
- event.preventDefault();
403
- const touch = event.touches[0];
404
-
405
- // Update preview position
406
- if (showPreview) {
407
- previewX = touch.clientX - dragOffsetX;
408
- previewY = touch.clientY - dragOffsetY;
409
- }
410
-
411
- /** @type {SimulatedDragEvent} */
412
- const simulatedEvent = {
413
- type: 'dragover',
414
- clientX: touch.clientX,
415
- clientY: touch.clientY,
416
- dataTransfer: {
417
- types: ['application/json', 'text/plain'],
418
- getData: () => JSON.stringify({ draggableId }),
419
- dropEffect: 'move',
420
- effectAllowed: 'move',
421
- files: []
422
- },
423
- preventDefault: () => {},
424
- stopPropagation: () => {}
425
- };
426
-
427
- // Update active dropzone in drag state
428
- dragState.updateActiveDropZone(touch.clientX, touch.clientY, simulatedEvent);
429
- }
430
-
431
- /**
432
- * Handle touch end
433
- * @param {TouchEvent} event
434
- */
435
- function handleTouchEnd(event) {
436
- clearTimeout(dragTimeout);
437
-
438
- if (!touchDragging) return;
439
-
440
- const touch = event.changedTouches[0];
441
-
442
- /** @type {SimulatedDragEvent} */
443
- const simulatedEvent = {
444
- type: 'drop',
445
- clientX: touch.clientX,
446
- clientY: touch.clientY,
447
- dataTransfer: {
448
- types: ['application/json', 'text'],
449
- getData: () => JSON.stringify({ draggableId }),
450
- dropEffect: 'move',
451
- effectAllowed: 'move',
452
- files: []
453
- },
454
- preventDefault: () => {}, // Add this!
455
- stopPropagation: () => {} // And this!
456
- };
457
-
458
- // Trigger drop at final touch position
459
- dragState.handleDropAtPoint(touch.clientX, touch.clientY, simulatedEvent);
460
-
461
- // Clean up
462
- touchDragging = false;
463
- currentState = IDLE;
464
- showPreview = false;
465
- dragState.end(draggableId);
466
-
467
- // Remove document handlers
468
- document.removeEventListener('touchmove', handleTouchMove);
469
- document.removeEventListener('touchend', handleTouchEnd);
470
- }
471
- </script>
472
-
473
- <div
474
- data-component="draggable"
475
- bind:this={draggableElement}
476
- draggable={!disabled && canDrag(item)}
477
- ondragstart={handleDragStart}
478
- ondrag={handleDrag}
479
- ondragend={handleDragEnd}
480
- onmousedown={handleMouseDown}
481
- onmouseup={handleMouseUp}
482
- ontouchstart={handleTouchStart}
483
- class="{base} {classes} {stateClasses}"
484
- style="touch-action: none;"
485
- {...attrs}
486
- >
487
- {@render children({ element: draggableElement, rect: elementRect })}
488
- </div>
489
-
490
- {#if showPreview && elementRect}
491
- <div
492
- data-companion="drag-preview-follower"
493
- class={stateClasses}
494
- style="position: fixed; z-index: 9999; pointer-events: none;"
495
- style:left="{previewX}px"
496
- style:top="{previewY}px"
497
- >
498
- {#if draggingSnippet}
499
- {@render draggingSnippet({ element: draggableElement, rect: elementRect })}
500
- {:else}
501
- {@render children({ element: draggableElement, rect: elementRect })}
502
- {/if}
503
- </div>
504
- {/if}
505
-
506
- <style>
507
- [data-component='draggable'] {
508
- -webkit-touch-callout: none;
509
- -webkit-user-select: none;
510
- user-select: none;
511
- }
512
- </style>
1
+ <script>
2
+ import { browser } from '$app/environment';
3
+
4
+ import { toStateClasses } from '../../util/design-system/index.js';
5
+ import { createOrGetDragState } from './drag-state.svelte.js';
6
+ import { DragController } from './DragController.js';
7
+ import { onDestroy } from 'svelte';
8
+ import {
9
+ IDLE,
10
+ DRAGGING,
11
+ DRAG_PREVIEW,
12
+ DROPPING
13
+ } from '../../constants/state-labels/drag-states.js';
14
+
15
+
16
+ /** @typedef {import('../../typedef').SimulatedDragEvent} SimulatedDragEvent */
17
+
18
+ /**
19
+ * @type {{
20
+ * item: any,
21
+ * group?: string,
22
+ * source?: string,
23
+ * disabled?: boolean,
24
+ * dragDelay?: number,
25
+ * base?: string,
26
+ * classes?: string,
27
+ * children: import('svelte').Snippet<[{
28
+ * element: HTMLElement,
29
+ * rect: DOMRect
30
+ * }]>,
31
+ * draggingSnippet?: import('svelte').Snippet<[{
32
+ * element: HTMLElement,
33
+ * rect: DOMRect
34
+ * }]>,
35
+ * contextKey?: import('../../typedef').ContextKey,
36
+ * isDragging?: boolean,
37
+ * isDropping?: boolean,
38
+ * isDragPreview?: boolean,
39
+ * onDragStart?: (detail: {
40
+ * event: DragEvent,
41
+ * item: any,
42
+ * source: string,
43
+ * group: string,
44
+ * getController: () => DragController
45
+ * }) => void,
46
+ * onDragging?: (detail: {
47
+ * event: DragEvent,
48
+ * item: any
49
+ * }) => void,
50
+ * onDragEnd?: (detail: {
51
+ * event: DragEvent,
52
+ * item: any,
53
+ * wasDropped: boolean
54
+ * }) => void,
55
+ * onDrop?: (detail: {
56
+ * event: DragEvent,
57
+ * item: any,
58
+ * wasDropped: boolean
59
+ * }) => void,
60
+ * canDrag?: (item: any) => boolean,
61
+ * [key: string]: any
62
+ * }}
63
+ */
64
+ let {
65
+ item,
66
+ group = 'default',
67
+ source = 'default',
68
+ disabled = false,
69
+ dragDelay = 0,
70
+ base = '',
71
+ classes = '',
72
+ children,
73
+ draggingSnippet,
74
+ contextKey,
75
+ isDragging = $bindable(false),
76
+ isDropping = $bindable(false),
77
+ isDragPreview = $bindable(false),
78
+ onDragStart,
79
+ onDragging,
80
+ onDragEnd,
81
+ onDrop,
82
+ canDrag = () => true,
83
+ ...attrs
84
+ } = $props();
85
+
86
+ const dragState = createOrGetDragState(contextKey);
87
+
88
+ const draggableId = dragState.newDraggableId();
89
+
90
+ // svelte-ignore non_reactive_update
91
+ let draggableElement;
92
+
93
+ let dragTimeout = null;
94
+ let currentState = $state(IDLE);
95
+
96
+ // Custom preview follower state
97
+ let showPreview = $state(false);
98
+ let previewX = $state(0);
99
+ let previewY = $state(0);
100
+ let dragOffsetX = $state(0);
101
+ let dragOffsetY = $state(0);
102
+ let customPreviewSet = $state(false);
103
+ let elementRect = $state(null);
104
+
105
+ // Track if current draggable can drop in the active zone
106
+ let canDropInActiveZone = $derived.by(() => {
107
+ if (currentState !== DRAGGING || !dragState.activeDropZone) return false;
108
+
109
+ const activeZone = dragState.dropZones.get(dragState.activeDropZone);
110
+ return activeZone?.canDrop || false;
111
+ });
112
+
113
+ // Computed state object for CSS classes
114
+ let stateObject = $derived({
115
+ idle: currentState === IDLE,
116
+ dragging: currentState === DRAGGING,
117
+ 'drag-preview': currentState === DRAG_PREVIEW,
118
+ dropping: currentState === DROPPING,
119
+ 'drag-disabled': disabled || !canDrag(item),
120
+ 'can-drop': currentState === DRAGGING && canDropInActiveZone,
121
+ 'cannot-drop': currentState === DRAGGING && dragState.activeDropZone && !canDropInActiveZone
122
+ });
123
+
124
+ let stateClasses = $derived(toStateClasses(stateObject));
125
+
126
+ // Update bindable props
127
+ $effect(() => {
128
+ isDragging = currentState === DRAGGING;
129
+ isDropping = currentState === DROPPING;
130
+ isDragPreview = currentState === DRAG_PREVIEW;
131
+ });
132
+
133
+ // Clean up on component destroy
134
+ onDestroy(() => {
135
+ if (showPreview) {
136
+ document.removeEventListener('dragover', handleDocumentDragOver);
137
+ }
138
+ });
139
+
140
+ /**
141
+ * Handle document level dragover to ensure we get position updates
142
+ * @param {DragEvent} event
143
+ */
144
+ function handleDocumentDragOver(event) {
145
+ if (showPreview && currentState === DRAGGING) {
146
+ // Update position for the custom preview
147
+ previewX = event.clientX - dragOffsetX;
148
+ previewY = event.clientY - dragOffsetY;
149
+
150
+ // Prevent default to allow drop
151
+ event.preventDefault();
152
+ }
153
+ }
154
+
155
+ /**
156
+ * Handle drag start
157
+ * @param {DragEvent} event
158
+ */
159
+ function handleDragStart(event) {
160
+ if (disabled || !canDrag(item)) {
161
+ event.preventDefault();
162
+ return;
163
+ }
164
+
165
+ // Handle drag delay
166
+ if (dragDelay > 0) {
167
+ event.preventDefault();
168
+ currentState = DRAG_PREVIEW;
169
+
170
+ dragTimeout = setTimeout(() => {
171
+ currentState = DRAGGING;
172
+ startDrag(event);
173
+ }, dragDelay);
174
+ return;
175
+ }
176
+
177
+ currentState = DRAGGING;
178
+ startDrag(event);
179
+ }
180
+
181
+ let transparentPixel;
182
+
183
+ if( browser )
184
+ {
185
+ transparentPixel = new Image();
186
+ transparentPixel.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
187
+ }
188
+
189
+ /**
190
+ * Start the drag operation
191
+ * @param {DragEvent} event - The drag event
192
+ */
193
+ function startDrag(event) {
194
+
195
+ // Set a transparent 1x1 pixel image to hide browser's default preview
196
+ event.dataTransfer.setDragImage(transparentPixel, 0, 0);
197
+
198
+ // Get the element's bounding rectangle
199
+ const rect = draggableElement.getBoundingClientRect();
200
+
201
+ // Calculate grab offsets - this is where the user grabbed the element
202
+ dragOffsetX = event.clientX - rect.left;
203
+ dragOffsetY = event.clientY - rect.top;
204
+
205
+ // Create drag data with draggableId included
206
+ const dragData = {
207
+ draggableId,
208
+ offsetX: dragOffsetX,
209
+ offsetY: dragOffsetY,
210
+ item,
211
+ source,
212
+ group
213
+ };
214
+
215
+ // console.debug('handleDragStart:', draggableId, dragData);
216
+
217
+ // Set shared drag state
218
+ dragState.start(draggableId, dragData);
219
+
220
+ // Set minimal data transfer for browser drag and drop API
221
+ event.dataTransfer.effectAllowed = 'move';
222
+
223
+ // Set draggableId as custom mime type, since that value is availabe
224
+ // during all event types (dragstart, dragenter, dragover, dragleave,
225
+ // drop and dragend)
226
+ event.dataTransfer.setData(`application/x-draggable-${draggableId}`, '1');
227
+
228
+ // Also keep text/plain for browser compatibility
229
+ event.dataTransfer.setData('text/plain', draggableId);
230
+
231
+ // Create the preview controller
232
+ const previewController = new DragController(event);
233
+
234
+ // Function to get the preview controller
235
+ const getController = () => previewController;
236
+
237
+ // Call onDragStart with the getController function
238
+ onDragStart?.({ event, item, source, group, getController });
239
+
240
+ // Store rectangle information for the snippet
241
+ elementRect = rect;
242
+
243
+ // These offsets represent where the user grabbed the element relative to its top-left corner
244
+ dragOffsetX = event.clientX - rect.left;
245
+ dragOffsetY = event.clientY - rect.top;
246
+
247
+ // Set initial position - this places the preview at the element's original position
248
+ previewX = rect.left;
249
+ previewY = rect.top;
250
+
251
+ // Add document level event listener to track mouse movement
252
+ document.addEventListener('dragover', handleDocumentDragOver);
253
+
254
+ // Show custom preview
255
+ showPreview = true;
256
+ customPreviewSet = true;
257
+ }
258
+
259
+ /**
260
+ * Handle during drag
261
+ * @param {DragEvent} event
262
+ */
263
+ function handleDrag(event) {
264
+ if (currentState === DRAGGING) {
265
+ onDragging?.({ event, item });
266
+ }
267
+ }
268
+
269
+ /**
270
+ * Handle drag end
271
+ * @param {DragEvent} event
272
+ */
273
+ function handleDragEnd(event) {
274
+ clearTimeout(dragTimeout);
275
+
276
+ // Clear global drag state
277
+ dragState.end(draggableId);
278
+
279
+ // Clean up document event listener
280
+ if (customPreviewSet) {
281
+ document.removeEventListener('dragover', handleDocumentDragOver);
282
+ showPreview = false;
283
+ customPreviewSet = false;
284
+ elementRect = null;
285
+ }
286
+
287
+ // Check if drop was successful
288
+ const wasDropped = event.dataTransfer.dropEffect !== 'none';
289
+
290
+ if (wasDropped) {
291
+ currentState = DROPPING;
292
+ onDrop?.({ event, item, wasDropped: true });
293
+
294
+ // Brief dropping state before returning to idle
295
+ setTimeout(() => {
296
+ currentState = IDLE;
297
+ }, 100);
298
+ } else {
299
+ currentState = IDLE;
300
+ }
301
+
302
+ onDragEnd?.({ event, item, wasDropped });
303
+ }
304
+
305
+ /**
306
+ * Handle mouse down for drag delay
307
+ * @param {MouseEvent} event
308
+ */
309
+ function handleMouseDown(event) {
310
+ if (dragDelay > 0 && !disabled && canDrag(item)) {
311
+ // Could add visual feedback here
312
+ }
313
+ }
314
+
315
+ /**
316
+ * Handle mouse up to cancel drag delay
317
+ * @param {MouseEvent} event
318
+ */
319
+ function handleMouseUp(event) {
320
+ if (dragTimeout) {
321
+ clearTimeout(dragTimeout);
322
+ currentState = IDLE;
323
+ }
324
+ }
325
+
326
+ // Add these variables for touch handling
327
+ let touchDragging = $state(false);
328
+ let touchStartX = 0;
329
+ let touchStartY = 0;
330
+ let touchPreviewElement = null;
331
+
332
+ /**
333
+ * Handle touch start
334
+ * @param {TouchEvent} event
335
+ */
336
+ function handleTouchStart(event) {
337
+ if (disabled || !canDrag(item)) return;
338
+
339
+ const touch = event.touches[0];
340
+ touchStartX = touch.clientX;
341
+ touchStartY = touch.clientY;
342
+
343
+ // Start drag after a small delay to distinguish from scrolling
344
+ dragTimeout = setTimeout(() => {
345
+ touchDragging = true;
346
+ currentState = DRAGGING;
347
+
348
+ // Create drag data
349
+ const rect = draggableElement.getBoundingClientRect();
350
+ dragOffsetX = touch.clientX - rect.left;
351
+ dragOffsetY = touch.clientY - rect.top;
352
+
353
+ const dragData = {
354
+ draggableId,
355
+ offsetX: dragOffsetX,
356
+ offsetY: dragOffsetY,
357
+ item,
358
+ source,
359
+ group
360
+ };
361
+
362
+ dragState.start(draggableId, dragData);
363
+
364
+ // Show preview
365
+ // if (draggingSnippet) {
366
+ elementRect = rect;
367
+ previewX = rect.left;
368
+ previewY = rect.top;
369
+ showPreview = true;
370
+ // }
371
+
372
+ // Prevent scrolling while dragging
373
+ event.preventDefault();
374
+
375
+ // Add document-level touch handlers
376
+ document.addEventListener('touchmove', handleTouchMove, {
377
+ passive: false
378
+ });
379
+
380
+ document.addEventListener('touchend', handleTouchEnd);
381
+ }, 150); // 150ms delay to distinguish from scrolling
382
+ }
383
+
384
+ /**
385
+ * Handle touch move
386
+ * @param {TouchEvent} event
387
+ */
388
+ function handleTouchMove(event) {
389
+ if (!touchDragging) return;
390
+
391
+ event.preventDefault();
392
+ const touch = event.touches[0];
393
+
394
+ // Update preview position
395
+ if (showPreview) {
396
+ previewX = touch.clientX - dragOffsetX;
397
+ previewY = touch.clientY - dragOffsetY;
398
+ }
399
+
400
+ /** @type {SimulatedDragEvent} */
401
+ const simulatedEvent = {
402
+ type: 'dragover',
403
+ clientX: touch.clientX,
404
+ clientY: touch.clientY,
405
+ dataTransfer: {
406
+ types: [`application/x-draggable-${draggableId}`, 'text/plain'],
407
+ getData: () => 1,
408
+ dropEffect: 'move',
409
+ effectAllowed: 'move',
410
+ files: []
411
+ },
412
+
413
+ preventDefault: () => {},
414
+ stopPropagation: () => {}
415
+ };
416
+
417
+ // Update active dropzone in drag state
418
+ dragState.updateActiveDropZone(touch.clientX, touch.clientY, simulatedEvent);
419
+ }
420
+
421
+ /**
422
+ * Handle touch end
423
+ * @param {TouchEvent} event
424
+ */
425
+ function handleTouchEnd(event) {
426
+ clearTimeout(dragTimeout);
427
+
428
+ if (!touchDragging) return;
429
+
430
+ const touch = event.changedTouches[0];
431
+
432
+ /** @type {SimulatedDragEvent} */
433
+ const simulatedEvent = {
434
+ type: 'drop',
435
+ clientX: touch.clientX,
436
+ clientY: touch.clientY,
437
+ dataTransfer: {
438
+ types: [`application/x-draggable-${draggableId}`, 'text/plain'],
439
+ getData: () => 1,
440
+ dropEffect: 'move',
441
+ effectAllowed: 'move',
442
+ files: []
443
+ },
444
+ preventDefault: () => {}, // Add this!
445
+ stopPropagation: () => {} // And this!
446
+ };
447
+
448
+ // Trigger drop at final touch position
449
+ dragState.handleDropAtPoint(touch.clientX, touch.clientY, simulatedEvent);
450
+
451
+ // Clean up
452
+ touchDragging = false;
453
+ currentState = IDLE;
454
+ showPreview = false;
455
+ dragState.end(draggableId);
456
+
457
+ // Remove document handlers
458
+ document.removeEventListener('touchmove', handleTouchMove);
459
+ document.removeEventListener('touchend', handleTouchEnd);
460
+ }
461
+ </script>
462
+
463
+ <div
464
+ data-component="draggable"
465
+ bind:this={draggableElement}
466
+ draggable={!disabled && canDrag(item)}
467
+ ondragstart={handleDragStart}
468
+ ondrag={handleDrag}
469
+ ondragend={handleDragEnd}
470
+ onmousedown={handleMouseDown}
471
+ onmouseup={handleMouseUp}
472
+ ontouchstart={handleTouchStart}
473
+ class="{base} {classes} {stateClasses}"
474
+ style="touch-action: none;"
475
+ {...attrs}
476
+ >
477
+ {@render children({ element: draggableElement, rect: elementRect })}
478
+ </div>
479
+
480
+ {#if showPreview && elementRect}
481
+ <div
482
+ data-companion="drag-preview-follower"
483
+ class={stateClasses}
484
+ style="position: fixed; z-index: 9999; pointer-events: none;"
485
+ style:left="{previewX}px"
486
+ style:top="{previewY}px"
487
+ >
488
+ {#if draggingSnippet}
489
+ {@render draggingSnippet({ element: draggableElement, rect: elementRect })}
490
+ {:else}
491
+ {@render children({ element: draggableElement, rect: elementRect })}
492
+ {/if}
493
+ </div>
494
+ {/if}
495
+
496
+ <style>
497
+ [data-component='draggable'] {
498
+ -webkit-touch-callout: none;
499
+ -webkit-user-select: none;
500
+ user-select: none;
501
+ }
502
+ </style>