@hkdigital/lib-sveltekit 0.2.10 → 0.2.12

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.
@@ -0,0 +1,169 @@
1
+ /**
2
+ * @fileoverview Type definitions for the service management system.
3
+ *
4
+ * This file contains all TypeScript/JSDoc type definitions used throughout
5
+ * the service management system. Import these types in your service
6
+ * implementations and when using the ServiceManager.
7
+ *
8
+ * @example
9
+ * // In your service implementation
10
+ * import { ServiceBase } from './ServiceBase.js';
11
+ *
12
+ * // @typedef {import('./typedef.js').ServiceConfig} ServiceConfig
13
+ * // @typedef {import('./typedef.js').HealthStatus} HealthStatus
14
+ *
15
+ * class MyService extends ServiceBase {
16
+ * async _init(config) {
17
+ * // config is typed as ServiceConfig
18
+ * }
19
+ *
20
+ * async _healthCheck() {
21
+ * // Return type is HealthStatus
22
+ * return { latency: 10 };
23
+ * }
24
+ * }
25
+ *
26
+ * @example
27
+ * // When using ServiceManager
28
+ * import { ServiceManager } from './ServiceManager.js';
29
+ *
30
+ * // @typedef {import('./typedef.js').ServiceManagerConfig} ServiceManagerConfig
31
+ * // @typedef {import('./typedef.js').ServiceRegistrationOptions} ServiceRegistrationOptions
32
+ *
33
+ * const config = {
34
+ * environment: 'development',
35
+ * stopTimeout: 5000
36
+ * };
37
+ *
38
+ * const manager = new ServiceManager(config);
39
+ *
40
+ * const options = {
41
+ * dependencies: ['database'],
42
+ * tags: ['critical']
43
+ * };
44
+ *
45
+ * manager.register('auth', AuthService, {}, options);
46
+ */
47
+
48
+ /**
49
+ * Service configuration object passed to service initialization
50
+ * @typedef {Object} ServiceConfig
51
+ * @property {*} [*] - Service-specific configuration properties
52
+ */
53
+
54
+ /**
55
+ * Options for creating a service instance
56
+ * @typedef {Object} ServiceOptions
57
+ * @property {string} [logLevel] - Initial log level for the service
58
+ * @property {number} [shutdownTimeout=5000] - Timeout for graceful shutdown
59
+ */
60
+
61
+ /**
62
+ * Options for stopping a service
63
+ * @typedef {Object} StopOptions
64
+ * @property {number} [timeout] - Override shutdown timeout
65
+ * @property {boolean} [force=false] - Force stop even if timeout exceeded
66
+ */
67
+
68
+ /**
69
+ * Health status returned by service health checks
70
+ * @typedef {Object} HealthStatus
71
+ * @property {string} name - Service name
72
+ * @property {string} state - Current service state
73
+ * @property {boolean} healthy - Whether the service is healthy
74
+ * @property {string} [error] - Error message if unhealthy
75
+ * @property {string} [checkError] - Error from health check itself
76
+ * @property {*} [*] - Additional health check properties
77
+ */
78
+
79
+ /**
80
+ * Event emitted when service state changes
81
+ * @typedef {Object} StateChangeEvent
82
+ * @property {string} service - Service name
83
+ * @property {string} oldState - Previous state
84
+ * @property {string} newState - New state
85
+ */
86
+
87
+ /**
88
+ * Event emitted when service health changes
89
+ * @typedef {Object} HealthChangeEvent
90
+ * @property {string} service - Service name
91
+ * @property {boolean} healthy - New health status
92
+ */
93
+
94
+ /**
95
+ * Event emitted when service encounters an error
96
+ * @typedef {Object} ServiceErrorEvent
97
+ * @property {string} service - Service name
98
+ * @property {string} operation - Operation that failed
99
+ * @property {Error} error - Error that occurred
100
+ */
101
+
102
+ /**
103
+ * Service class constructor type
104
+ * @typedef {new (name: string, options?: ServiceOptions) => ServiceBase} ServiceConstructor
105
+ */
106
+
107
+ /**
108
+ * Options for registering a service
109
+ * @typedef {Object} ServiceRegistrationOptions
110
+ * @property {string[]} [dependencies=[]] - Services this service depends on
111
+ * @property {string[]} [tags=[]] - Tags for grouping services
112
+ * @property {number} [priority=0] - Startup priority (higher starts first)
113
+ */
114
+
115
+ /**
116
+ * Configuration for ServiceManager
117
+ * @typedef {Object} ServiceManagerConfig
118
+ * @property {string} [environment='production'] - Runtime environment
119
+ * @property {boolean} [autoStart=false] - Auto-start services on registration
120
+ * @property {number} [stopTimeout=10000] - Default timeout for stopping services
121
+ * @property {string} [logLevel] - Initial log level for ServiceManager
122
+ * @property {LogConfig} [logConfig={}] - Logging configuration
123
+ */
124
+
125
+ /**
126
+ * Logging configuration
127
+ * @typedef {Object} LogConfig
128
+ * @property {string} [defaultLevel] - Default log level for services
129
+ * @property {string} [globalLevel] - Override level for all services
130
+ * @property {Object<string, string>} [serviceLevels] - Per-service log levels
131
+ */
132
+
133
+ /**
134
+ * Internal service registry entry
135
+ * @typedef {Object} ServiceEntry
136
+ * @property {ServiceConstructor} ServiceClass - Service class constructor
137
+ * @property {ServiceBase|null} instance - Service instance (lazy-created)
138
+ * @property {ServiceConfig} config - Service configuration
139
+ * @property {string[]} dependencies - Service dependencies
140
+ * @property {Set<string>} dependents - Services that depend on this one
141
+ * @property {string[]} tags - Service tags
142
+ * @property {number} priority - Startup priority
143
+ */
144
+
145
+ /**
146
+ * Result of health check for all services
147
+ * @typedef {Object<string, HealthStatus>} HealthCheckResult
148
+ */
149
+
150
+ /**
151
+ * Base class interface that services must implement
152
+ * @typedef {Object} ServiceBase
153
+ * @property {string} name - Service name
154
+ * @property {string} state - Current state
155
+ * @property {boolean} healthy - Health status
156
+ * @property {Error|null} error - Last error
157
+ * @property {Logger} logger - Service logger
158
+ * @property {(config?: ServiceConfig) => Promise<boolean>} initialize
159
+ * @property {() => Promise<boolean>} start
160
+ * @property {(options?: StopOptions) => Promise<boolean>} stop
161
+ * @property {() => Promise<boolean>} recover
162
+ * @property {() => Promise<boolean>} destroy
163
+ * @property {() => Promise<HealthStatus>} getHealth
164
+ * @property {(level: string) => boolean} setLogLevel
165
+ * @property {(event: string, handler: Function) => Function} on
166
+ * @property {(event: string, data: any) => boolean} emit
167
+ */
168
+
169
+ export {};
@@ -12,7 +12,6 @@
12
12
  DROPPING
13
13
  } from '../../constants/state-labels/drag-states.js';
14
14
 
15
-
16
15
  /** @typedef {import('../../typedef').SimulatedDragEvent} SimulatedDragEvent */
17
16
 
18
17
  /**
@@ -26,7 +25,8 @@
26
25
  * classes?: string,
27
26
  * children: import('svelte').Snippet<[{
28
27
  * element: HTMLElement,
29
- * rect: DOMRect
28
+ * rect: DOMRect,
29
+ * isDragging: boolean
30
30
  * }]>,
31
31
  * draggingSnippet?: import('svelte').Snippet<[{
32
32
  * element: HTMLElement,
@@ -102,24 +102,27 @@
102
102
  let customPreviewSet = $state(false);
103
103
  let elementRect = $state(null);
104
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
- });
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
+ });
123
126
 
124
127
  let stateClasses = $derived(toStateClasses(stateObject));
125
128
 
@@ -180,10 +183,10 @@ let stateObject = $derived({
180
183
 
181
184
  let transparentPixel;
182
185
 
183
- if( browser )
184
- {
186
+ if (browser) {
185
187
  transparentPixel = new Image();
186
- transparentPixel.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
188
+ transparentPixel.src =
189
+ 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
187
190
  }
188
191
 
189
192
  /**
@@ -191,7 +194,6 @@ let stateObject = $derived({
191
194
  * @param {DragEvent} event - The drag event
192
195
  */
193
196
  function startDrag(event) {
194
-
195
197
  // Set a transparent 1x1 pixel image to hide browser's default preview
196
198
  event.dataTransfer.setDragImage(transparentPixel, 0, 0);
197
199
 
@@ -363,10 +365,10 @@ let stateObject = $derived({
363
365
 
364
366
  // Show preview
365
367
  // if (draggingSnippet) {
366
- elementRect = rect;
367
- previewX = rect.left;
368
- previewY = rect.top;
369
- showPreview = true;
368
+ elementRect = rect;
369
+ previewX = rect.left;
370
+ previewY = rect.top;
371
+ showPreview = true;
370
372
  // }
371
373
 
372
374
  // Prevent scrolling while dragging
@@ -385,79 +387,83 @@ let stateObject = $derived({
385
387
  * Handle touch move
386
388
  * @param {TouchEvent} event
387
389
  */
388
- function handleTouchMove(event) {
389
- if (!touchDragging) return;
390
+ function handleTouchMove(event) {
391
+ if (!touchDragging) return;
390
392
 
391
- event.preventDefault();
392
- const touch = event.touches[0];
393
+ event.preventDefault();
394
+ const touch = event.touches[0];
393
395
 
394
- // Update preview position
395
- if (showPreview) {
396
- previewX = touch.clientX - dragOffsetX;
397
- previewY = touch.clientY - dragOffsetY;
398
- }
396
+ // Update preview position
397
+ if (showPreview) {
398
+ previewX = touch.clientX - dragOffsetX;
399
+ previewY = touch.clientY - dragOffsetY;
400
+ }
399
401
 
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
- }
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
+ }
420
426
 
421
427
  /**
422
428
  * Handle touch end
423
429
  * @param {TouchEvent} event
424
430
  */
425
431
  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
- }
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
+ }
461
467
  </script>
462
468
 
463
469
  <div
@@ -474,7 +480,11 @@ function handleTouchMove(event) {
474
480
  style="touch-action: none;"
475
481
  {...attrs}
476
482
  >
477
- {@render children({ element: draggableElement, rect: elementRect })}
483
+ {@render children({
484
+ element: draggableElement,
485
+ rect: elementRect,
486
+ isDragging: false
487
+ })}
478
488
  </div>
479
489
 
480
490
  {#if showPreview && elementRect}
@@ -485,11 +495,18 @@ function handleTouchMove(event) {
485
495
  style:left="{previewX}px"
486
496
  style:top="{previewY}px"
487
497
  >
488
- {#if draggingSnippet}
489
- {@render draggingSnippet({ element: draggableElement, rect: elementRect })}
490
- {:else}
491
- {@render children({ element: draggableElement, rect: elementRect })}
492
- {/if}
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}
493
510
  </div>
494
511
  {/if}
495
512
 
@@ -13,6 +13,7 @@ type Draggable = {
13
13
  children: Snippet<[{
14
14
  element: HTMLElement;
15
15
  rect: DOMRect;
16
+ isDragging: boolean;
16
17
  }]>;
17
18
  draggingSnippet?: Snippet<[{
18
19
  element: HTMLElement;
@@ -58,6 +59,7 @@ declare const Draggable: import("svelte").Component<{
58
59
  children: import("svelte").Snippet<[{
59
60
  element: HTMLElement;
60
61
  rect: DOMRect;
62
+ isDragging: boolean;
61
63
  }]>;
62
64
  draggingSnippet?: import("svelte").Snippet<[{
63
65
  element: HTMLElement;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hkdigital/lib-sveltekit",
3
- "version": "0.2.10",
3
+ "version": "0.2.12",
4
4
  "author": {
5
5
  "name": "HKdigital",
6
6
  "url": "https://hkdigital.nl"