@hkdigital/lib-sveltekit 0.2.20 → 0.2.21

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