svelte-flexiboards 0.3.0 → 0.3.2-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/system/target/controller.svelte.js +18 -6
- package/dist/system/widget/base.svelte.d.ts +13 -42
- package/dist/system/widget/base.svelte.js +1 -96
- package/dist/system/widget/controller.svelte.d.ts +12 -32
- package/dist/system/widget/controller.svelte.js +74 -146
- package/dist/system/widget/events.js +20 -66
- package/dist/system/widget/index.js +1 -6
- package/dist/system/widget/triggers.svelte.js +11 -4
- package/package.json +1 -1
- package/dist/system/widget/state.svelte.d.ts +0 -59
- package/dist/system/widget/state.svelte.js +0 -102
|
@@ -26,6 +26,7 @@ export class InternalFlexiTargetController {
|
|
|
26
26
|
value: null
|
|
27
27
|
});
|
|
28
28
|
#isDropzoneWidgetAdded = $state(false);
|
|
29
|
+
#dropzoneWidgetEffectCleanup = null;
|
|
29
30
|
#mouseCellPosition = $state({
|
|
30
31
|
x: 0,
|
|
31
32
|
y: 0
|
|
@@ -100,11 +101,7 @@ export class InternalFlexiTargetController {
|
|
|
100
101
|
this.#updateOrderedWidgets();
|
|
101
102
|
widget.target = this;
|
|
102
103
|
widget.internalTarget = this;
|
|
103
|
-
//
|
|
104
|
-
// This is especially important for adder widgets that weren't created via target.createWidget()
|
|
105
|
-
if (!widget.interpolator) {
|
|
106
|
-
widget.createReactiveState();
|
|
107
|
-
}
|
|
104
|
+
// Widget is now fully reactive by default - no additional setup needed
|
|
108
105
|
}
|
|
109
106
|
return added;
|
|
110
107
|
}
|
|
@@ -388,7 +385,12 @@ export class InternalFlexiTargetController {
|
|
|
388
385
|
const grid = this.grid;
|
|
389
386
|
// Take a snapshot of the grid so we can restore its state if the hover stops.
|
|
390
387
|
this.#gridSnapshot = grid.takeSnapshot();
|
|
391
|
-
|
|
388
|
+
// Wrap only the widget creation in $effect.root to ensure proper reactivity context
|
|
389
|
+
let shadowWidget;
|
|
390
|
+
this.#dropzoneWidgetEffectCleanup = $effect.root(() => {
|
|
391
|
+
shadowWidget = this.#createShadow(this.actionWidget.widget);
|
|
392
|
+
});
|
|
393
|
+
this.dropzoneWidget = shadowWidget;
|
|
392
394
|
let [x, y, width, height] = this.#getDropzoneLocation(this.actionWidget);
|
|
393
395
|
const added = this.grid.tryPlaceWidget(this.dropzoneWidget, x, y, width, height, true);
|
|
394
396
|
if (added) {
|
|
@@ -478,6 +480,11 @@ export class InternalFlexiTargetController {
|
|
|
478
480
|
}
|
|
479
481
|
grid.restoreFromSnapshot(this.#gridSnapshot);
|
|
480
482
|
this.#gridSnapshot = null;
|
|
483
|
+
// Cleanup the effect root
|
|
484
|
+
if (this.#dropzoneWidgetEffectCleanup) {
|
|
485
|
+
this.#dropzoneWidgetEffectCleanup();
|
|
486
|
+
this.#dropzoneWidgetEffectCleanup = null;
|
|
487
|
+
}
|
|
481
488
|
this.dropzoneWidget = null;
|
|
482
489
|
}
|
|
483
490
|
// State-related getters and setters
|
|
@@ -553,6 +560,11 @@ export class InternalFlexiTargetController {
|
|
|
553
560
|
}
|
|
554
561
|
});
|
|
555
562
|
this.widgets.clear();
|
|
563
|
+
// Clean up dropzone widget effect
|
|
564
|
+
if (this.#dropzoneWidgetEffectCleanup) {
|
|
565
|
+
this.#dropzoneWidgetEffectCleanup();
|
|
566
|
+
this.#dropzoneWidgetEffectCleanup = null;
|
|
567
|
+
}
|
|
556
568
|
// Clean up event subscriptions
|
|
557
569
|
this.#unsubscribers.forEach((unsubscribe) => unsubscribe());
|
|
558
570
|
this.#unsubscribers = [];
|
|
@@ -2,8 +2,7 @@ import type { Component } from 'svelte';
|
|
|
2
2
|
import type { FlexiTargetController } from '../target/index.js';
|
|
3
3
|
import type { WidgetAction, WidgetResizability } from '../types.js';
|
|
4
4
|
import { type FlexiWidgetChildrenSnippet, type FlexiWidgetClasses, type FlexiWidgetConstructorParams } from './types.js';
|
|
5
|
-
|
|
6
|
-
export declare class FlexiWidgetController {
|
|
5
|
+
export declare abstract class FlexiWidgetController {
|
|
7
6
|
#private;
|
|
8
7
|
/**
|
|
9
8
|
* The target this widget is under. This is not defined if the widget has not yet been dropped in the board.
|
|
@@ -16,24 +15,24 @@ export declare class FlexiWidgetController {
|
|
|
16
15
|
/**
|
|
17
16
|
* Whether this widget is a shadow dropzone widget.
|
|
18
17
|
*/
|
|
19
|
-
isShadow: boolean;
|
|
18
|
+
abstract get isShadow(): boolean;
|
|
19
|
+
abstract get currentAction(): WidgetAction | null;
|
|
20
|
+
abstract get width(): number;
|
|
21
|
+
abstract get height(): number;
|
|
22
|
+
abstract get x(): number;
|
|
23
|
+
abstract get y(): number;
|
|
24
|
+
abstract get isBeingDropped(): boolean;
|
|
25
|
+
abstract get hasGrabbers(): boolean;
|
|
26
|
+
abstract get hasResizers(): boolean;
|
|
20
27
|
/**
|
|
21
28
|
* Whether this widget is grabbed.
|
|
22
29
|
*/
|
|
23
|
-
isGrabbed: boolean;
|
|
30
|
+
abstract get isGrabbed(): boolean;
|
|
24
31
|
/**
|
|
25
32
|
* Whether this widget is being resized.
|
|
26
33
|
*/
|
|
27
|
-
isResizing: boolean;
|
|
28
|
-
|
|
29
|
-
backingState: WidgetStateData;
|
|
30
|
-
constructor(state: WidgetStateData, params: FlexiWidgetConstructorParams);
|
|
31
|
-
/**
|
|
32
|
-
* When the widget is being grabbed, this contains information that includes its position, size and offset.
|
|
33
|
-
* When this is null, the widget is not being grabbed.
|
|
34
|
-
*/
|
|
35
|
-
get currentAction(): WidgetAction | null;
|
|
36
|
-
set currentAction(value: WidgetAction | null);
|
|
34
|
+
abstract get isResizing(): boolean;
|
|
35
|
+
constructor(params: FlexiWidgetConstructorParams);
|
|
37
36
|
/**
|
|
38
37
|
* Whether the widget is draggable.
|
|
39
38
|
*/
|
|
@@ -48,14 +47,6 @@ export declare class FlexiWidgetController {
|
|
|
48
47
|
* Whether the widget is resizable.
|
|
49
48
|
*/
|
|
50
49
|
get resizable(): boolean;
|
|
51
|
-
/**
|
|
52
|
-
* The width in units of the widget.
|
|
53
|
-
*/
|
|
54
|
-
get width(): number;
|
|
55
|
-
/**
|
|
56
|
-
* The height in units of the widget.
|
|
57
|
-
*/
|
|
58
|
-
get height(): number;
|
|
59
50
|
/**
|
|
60
51
|
* The component that is rendered by this widget.
|
|
61
52
|
*/
|
|
@@ -76,14 +67,6 @@ export declare class FlexiWidgetController {
|
|
|
76
67
|
*/
|
|
77
68
|
get className(): FlexiWidgetClasses | undefined;
|
|
78
69
|
set className(value: FlexiWidgetClasses | undefined);
|
|
79
|
-
/**
|
|
80
|
-
* Gets the column (x-coordinate) of the widget. This value is readonly and is managed by the target.
|
|
81
|
-
*/
|
|
82
|
-
get x(): number;
|
|
83
|
-
/**
|
|
84
|
-
* Gets the row (y-coordinate) of the widget. This value is readonly and is managed by the target.
|
|
85
|
-
*/
|
|
86
|
-
get y(): number;
|
|
87
70
|
/**
|
|
88
71
|
* The metadata associated with this widget, if any.
|
|
89
72
|
*/
|
|
@@ -102,18 +85,6 @@ export declare class FlexiWidgetController {
|
|
|
102
85
|
* Gets the transition configuration for this widget.
|
|
103
86
|
*/
|
|
104
87
|
get transitionConfig(): import("./types.js").FlexiWidgetTransitionConfiguration;
|
|
105
|
-
/**
|
|
106
|
-
* Whether the widget has any grabbers attached.
|
|
107
|
-
*/
|
|
108
|
-
get hasGrabbers(): boolean;
|
|
109
|
-
/**
|
|
110
|
-
* Whether the widget has any resizers attached
|
|
111
|
-
*/
|
|
112
|
-
get hasResizers(): boolean;
|
|
113
|
-
/**
|
|
114
|
-
* Whether the widget is currently being dropped after a drag operation.
|
|
115
|
-
*/
|
|
116
|
-
get isBeingDropped(): boolean;
|
|
117
88
|
}
|
|
118
89
|
export type WidgetStateData = {
|
|
119
90
|
currentAction: WidgetAction | null;
|
|
@@ -13,18 +13,6 @@ export class FlexiWidgetController {
|
|
|
13
13
|
#providerWidgetDefaults = $derived(this.target?.providerWidgetDefaults);
|
|
14
14
|
#targetWidgetDefaults = $derived(this.target?.config.widgetDefaults);
|
|
15
15
|
#rawConfig = $state();
|
|
16
|
-
/**
|
|
17
|
-
* Whether this widget is a shadow dropzone widget.
|
|
18
|
-
*/
|
|
19
|
-
isShadow = $state(false);
|
|
20
|
-
/**
|
|
21
|
-
* Whether this widget is grabbed.
|
|
22
|
-
*/
|
|
23
|
-
isGrabbed = $derived(this.currentAction?.action == 'grab');
|
|
24
|
-
/**
|
|
25
|
-
* Whether this widget is being resized.
|
|
26
|
-
*/
|
|
27
|
-
isResizing = $derived(this.currentAction?.action == 'resize');
|
|
28
16
|
/**
|
|
29
17
|
* The reactive configuration of the widget. When these properties are changed, either due to a change in the widget's configuration,
|
|
30
18
|
* or a change in the target's, or the board's, they will be updated to reflect the new values.
|
|
@@ -64,33 +52,13 @@ export class FlexiWidgetController {
|
|
|
64
52
|
this.#providerWidgetDefaults?.resizeTrigger ??
|
|
65
53
|
defaultTriggerConfig
|
|
66
54
|
});
|
|
67
|
-
|
|
68
|
-
backingState;
|
|
69
|
-
constructor(state, params) {
|
|
70
|
-
this.backingState = state;
|
|
55
|
+
constructor(params) {
|
|
71
56
|
this.#rawConfig = params.config;
|
|
72
57
|
if (params.target) {
|
|
73
58
|
this.target = params.target;
|
|
74
|
-
this.isShadow = params.isShadow ?? false;
|
|
75
59
|
}
|
|
76
60
|
}
|
|
77
61
|
// Getters and setters
|
|
78
|
-
/**
|
|
79
|
-
* When the widget is being grabbed, this contains information that includes its position, size and offset.
|
|
80
|
-
* When this is null, the widget is not being grabbed.
|
|
81
|
-
*/
|
|
82
|
-
get currentAction() {
|
|
83
|
-
if (this.reactiveState) {
|
|
84
|
-
return this.reactiveState.currentAction;
|
|
85
|
-
}
|
|
86
|
-
return this.backingState.currentAction;
|
|
87
|
-
}
|
|
88
|
-
set currentAction(value) {
|
|
89
|
-
if (this.reactiveState) {
|
|
90
|
-
this.reactiveState.currentAction = value;
|
|
91
|
-
}
|
|
92
|
-
this.backingState.currentAction = value;
|
|
93
|
-
}
|
|
94
62
|
/**
|
|
95
63
|
* Whether the widget is draggable.
|
|
96
64
|
*/
|
|
@@ -115,24 +83,6 @@ export class FlexiWidgetController {
|
|
|
115
83
|
get resizable() {
|
|
116
84
|
return this.resizability !== 'none';
|
|
117
85
|
}
|
|
118
|
-
/**
|
|
119
|
-
* The width in units of the widget.
|
|
120
|
-
*/
|
|
121
|
-
get width() {
|
|
122
|
-
if (this.reactiveState) {
|
|
123
|
-
return this.reactiveState.width;
|
|
124
|
-
}
|
|
125
|
-
return this.backingState.width;
|
|
126
|
-
}
|
|
127
|
-
/**
|
|
128
|
-
* The height in units of the widget.
|
|
129
|
-
*/
|
|
130
|
-
get height() {
|
|
131
|
-
if (this.reactiveState) {
|
|
132
|
-
return this.reactiveState.height;
|
|
133
|
-
}
|
|
134
|
-
return this.backingState.height;
|
|
135
|
-
}
|
|
136
86
|
/**
|
|
137
87
|
* The component that is rendered by this widget.
|
|
138
88
|
*/
|
|
@@ -169,24 +119,6 @@ export class FlexiWidgetController {
|
|
|
169
119
|
set className(value) {
|
|
170
120
|
this.#rawConfig.className = value;
|
|
171
121
|
}
|
|
172
|
-
/**
|
|
173
|
-
* Gets the column (x-coordinate) of the widget. This value is readonly and is managed by the target.
|
|
174
|
-
*/
|
|
175
|
-
get x() {
|
|
176
|
-
if (this.reactiveState) {
|
|
177
|
-
return this.reactiveState.x;
|
|
178
|
-
}
|
|
179
|
-
return this.backingState.x;
|
|
180
|
-
}
|
|
181
|
-
/**
|
|
182
|
-
* Gets the row (y-coordinate) of the widget. This value is readonly and is managed by the target.
|
|
183
|
-
*/
|
|
184
|
-
get y() {
|
|
185
|
-
if (this.reactiveState) {
|
|
186
|
-
return this.reactiveState.y;
|
|
187
|
-
}
|
|
188
|
-
return this.backingState.y;
|
|
189
|
-
}
|
|
190
122
|
/**
|
|
191
123
|
* The metadata associated with this widget, if any.
|
|
192
124
|
*/
|
|
@@ -215,31 +147,4 @@ export class FlexiWidgetController {
|
|
|
215
147
|
get transitionConfig() {
|
|
216
148
|
return this.#config.transition;
|
|
217
149
|
}
|
|
218
|
-
/**
|
|
219
|
-
* Whether the widget has any grabbers attached.
|
|
220
|
-
*/
|
|
221
|
-
get hasGrabbers() {
|
|
222
|
-
if (this.reactiveState) {
|
|
223
|
-
return this.reactiveState.hasGrabbers;
|
|
224
|
-
}
|
|
225
|
-
return this.backingState.hasGrabbers;
|
|
226
|
-
}
|
|
227
|
-
/**
|
|
228
|
-
* Whether the widget has any resizers attached
|
|
229
|
-
*/
|
|
230
|
-
get hasResizers() {
|
|
231
|
-
if (this.reactiveState) {
|
|
232
|
-
return this.reactiveState.hasResizers;
|
|
233
|
-
}
|
|
234
|
-
return this.backingState.hasResizers;
|
|
235
|
-
}
|
|
236
|
-
/**
|
|
237
|
-
* Whether the widget is currently being dropped after a drag operation.
|
|
238
|
-
*/
|
|
239
|
-
get isBeingDropped() {
|
|
240
|
-
if (this.reactiveState) {
|
|
241
|
-
return this.reactiveState.isBeingDropped;
|
|
242
|
-
}
|
|
243
|
-
return this.backingState.isBeingDropped;
|
|
244
|
-
}
|
|
245
150
|
}
|
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import type { WidgetDroppedEvent, WidgetEvent, WidgetGrabbedEvent, WidgetResizingEvent } from '../types.js';
|
|
1
|
+
import type { WidgetAction, WidgetDroppedEvent, WidgetEvent, WidgetGrabbedEvent, WidgetResizingEvent } from '../types.js';
|
|
2
2
|
import { FlexiWidgetController } from './base.svelte.js';
|
|
3
3
|
import type { InternalFlexiTargetController } from '../target/controller.svelte.js';
|
|
4
|
+
import { WidgetMoveInterpolator } from './interpolator.svelte.js';
|
|
4
5
|
import type { FlexiWidgetConstructorParams } from './types.js';
|
|
5
6
|
import type { InternalFlexiBoardController } from '../board/controller.svelte.js';
|
|
6
7
|
export declare class InternalFlexiWidgetController extends FlexiWidgetController {
|
|
7
8
|
#private;
|
|
8
9
|
internalTarget?: InternalFlexiTargetController;
|
|
9
10
|
provider: InternalFlexiBoardController;
|
|
11
|
+
interpolator: WidgetMoveInterpolator;
|
|
10
12
|
mounted: boolean;
|
|
11
13
|
/**
|
|
12
14
|
* The styling to apply to the widget.
|
|
@@ -39,47 +41,25 @@ export declare class InternalFlexiWidgetController extends FlexiWidgetController
|
|
|
39
41
|
*/
|
|
40
42
|
delete(): void;
|
|
41
43
|
onDelete(event: WidgetEvent): void;
|
|
42
|
-
/**
|
|
43
|
-
* Creates the reactive state container when the widget component mounts.
|
|
44
|
-
* This should be called from the component's onMount lifecycle.
|
|
45
|
-
*/
|
|
46
|
-
createReactiveState(): void;
|
|
47
44
|
/**
|
|
48
45
|
* Cleanup method to be called when the widget is destroyed
|
|
49
46
|
*/
|
|
50
47
|
destroy(): void;
|
|
51
|
-
|
|
52
|
-
* Destroys the reactive state container when the widget component unmounts.
|
|
53
|
-
* This should be called from the component's onDestroy lifecycle.
|
|
54
|
-
*/
|
|
55
|
-
destroyReactiveState(): void;
|
|
56
|
-
/**
|
|
57
|
-
* The width in units of the widget.
|
|
58
|
-
*/
|
|
48
|
+
get currentAction(): WidgetAction | null;
|
|
59
49
|
get width(): number;
|
|
60
|
-
/**
|
|
61
|
-
* The height in units of the widget.
|
|
62
|
-
*/
|
|
63
50
|
get height(): number;
|
|
64
|
-
set width(value: number);
|
|
65
|
-
set height(value: number);
|
|
66
|
-
/**
|
|
67
|
-
* Gets the column (x-coordinate) of the widget. This value is readonly and is managed by the target.
|
|
68
|
-
*/
|
|
69
51
|
get x(): number;
|
|
70
|
-
/**
|
|
71
|
-
* Gets the row (y-coordinate) of the widget. This value is readonly and is managed by the target.
|
|
72
|
-
*/
|
|
73
52
|
get y(): number;
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
get
|
|
53
|
+
get isBeingDropped(): boolean;
|
|
54
|
+
get hasGrabbers(): boolean;
|
|
55
|
+
get hasResizers(): boolean;
|
|
56
|
+
get isShadow(): boolean;
|
|
57
|
+
get isGrabbed(): boolean;
|
|
58
|
+
get isResizing(): boolean;
|
|
59
|
+
set currentAction(value: WidgetAction | null);
|
|
60
|
+
set isBeingDropped(value: boolean);
|
|
80
61
|
/**
|
|
81
62
|
* Whether the widget should draw a placeholder widget in the DOM.
|
|
82
63
|
*/
|
|
83
64
|
get shouldDrawPlaceholder(): boolean;
|
|
84
|
-
set isBeingDropped(value: boolean);
|
|
85
65
|
}
|
|
@@ -1,19 +1,28 @@
|
|
|
1
1
|
import { getFlexiEventBus } from '../shared/event-bus.js';
|
|
2
2
|
import { generateUniqueId, getElementMidpoint, getPointerService } from '../shared/utils.svelte.js';
|
|
3
3
|
import { FlexiWidgetController } from './base.svelte.js';
|
|
4
|
-
import {} from './interpolator.svelte.js';
|
|
4
|
+
import { WidgetMoveInterpolator } from './interpolator.svelte.js';
|
|
5
5
|
import { WidgetPointerEventWatcher } from './triggers.svelte.js';
|
|
6
|
-
import { WidgetReactiveState } from './state.svelte.js';
|
|
7
6
|
export class InternalFlexiWidgetController extends FlexiWidgetController {
|
|
8
7
|
#pointerService = getPointerService();
|
|
9
|
-
// Legacy non-reactive state tracking (for when reactive state is not available)
|
|
10
|
-
#grabbersCount = 0;
|
|
11
|
-
#resizersCount = 0;
|
|
12
8
|
internalTarget = undefined;
|
|
13
9
|
provider;
|
|
14
|
-
//
|
|
15
|
-
|
|
10
|
+
// Private reactive state properties
|
|
11
|
+
#currentAction = $state(null);
|
|
12
|
+
#width = $state(1);
|
|
13
|
+
#height = $state(1);
|
|
14
|
+
#x = $state(0);
|
|
15
|
+
#y = $state(0);
|
|
16
|
+
#isBeingDropped = $state(false);
|
|
17
|
+
#hasGrabbers = $state(false);
|
|
18
|
+
#hasResizers = $state(false);
|
|
19
|
+
#isShadow = $state(false);
|
|
20
|
+
// Movement interpolation
|
|
21
|
+
interpolator;
|
|
16
22
|
mounted = $state(false);
|
|
23
|
+
// Grabber and resizer tracking
|
|
24
|
+
#grabbersCount = 0;
|
|
25
|
+
#resizersCount = 0;
|
|
17
26
|
#eventBus;
|
|
18
27
|
#unsubscribers = [];
|
|
19
28
|
/**
|
|
@@ -48,7 +57,7 @@ export class InternalFlexiWidgetController extends FlexiWidgetController {
|
|
|
48
57
|
if (this.isResizing) {
|
|
49
58
|
return 'pointer-events: none; user-select: none; cursor: nwse-resize;';
|
|
50
59
|
}
|
|
51
|
-
const grabberCount = this
|
|
60
|
+
const grabberCount = this.#grabbersCount;
|
|
52
61
|
if (grabberCount == 0) {
|
|
53
62
|
return 'user-select: none; cursor: grab; touch-action: none;';
|
|
54
63
|
}
|
|
@@ -100,21 +109,18 @@ export class InternalFlexiWidgetController extends FlexiWidgetController {
|
|
|
100
109
|
return `pointer-events: none; user-select: none; cursor: nwse-resize; position: absolute; top: ${top}px; left: ${left}px; height: ${height}px; width: ${width}px;`;
|
|
101
110
|
}
|
|
102
111
|
constructor(params) {
|
|
103
|
-
//
|
|
104
|
-
super(
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
x: 0,
|
|
109
|
-
y: 0,
|
|
110
|
-
hasGrabbers: false,
|
|
111
|
-
hasResizers: false,
|
|
112
|
-
isBeingDropped: false
|
|
113
|
-
}, params);
|
|
112
|
+
// Initialize base class
|
|
113
|
+
super(params);
|
|
114
|
+
// Initialize private state with config values
|
|
115
|
+
this.#width = params.config.width ?? 1;
|
|
116
|
+
this.#height = params.config.height ?? 1;
|
|
114
117
|
if (params.target) {
|
|
115
118
|
this.internalTarget = params.target;
|
|
119
|
+
this.#isShadow = params.isShadow ?? false;
|
|
116
120
|
}
|
|
117
121
|
this.provider = params.provider;
|
|
122
|
+
// Create the widget's interpolator.
|
|
123
|
+
this.interpolator = new WidgetMoveInterpolator(params.provider, this);
|
|
118
124
|
this.#eventBus = getFlexiEventBus();
|
|
119
125
|
this.#unsubscribers.push(this.#eventBus.subscribe('widget:grabbed', this.onGrabbed.bind(this)), this.#eventBus.subscribe('widget:resizing', this.onResizing.bind(this)), this.#eventBus.subscribe('widget:release', this.onReleased.bind(this)), this.#eventBus.subscribe('widget:cancel', this.onReleased.bind(this)), this.#eventBus.subscribe('widget:delete', this.onDelete.bind(this)), this.#eventBus.subscribe('widget:dropped', this.onDropped.bind(this)));
|
|
120
126
|
}
|
|
@@ -132,7 +138,7 @@ export class InternalFlexiWidgetController extends FlexiWidgetController {
|
|
|
132
138
|
setTimeout(() => {
|
|
133
139
|
this.ref?.focus();
|
|
134
140
|
}, 0);
|
|
135
|
-
this
|
|
141
|
+
this.#currentAction = {
|
|
136
142
|
action: 'grab',
|
|
137
143
|
widget: this,
|
|
138
144
|
offsetX: event.xOffset,
|
|
@@ -149,7 +155,7 @@ export class InternalFlexiWidgetController extends FlexiWidgetController {
|
|
|
149
155
|
setTimeout(() => {
|
|
150
156
|
this.ref?.focus();
|
|
151
157
|
}, 0);
|
|
152
|
-
this
|
|
158
|
+
this.#currentAction = {
|
|
153
159
|
action: 'resize',
|
|
154
160
|
widget: this,
|
|
155
161
|
offsetX: event.offsetX,
|
|
@@ -166,7 +172,7 @@ export class InternalFlexiWidgetController extends FlexiWidgetController {
|
|
|
166
172
|
if (event.widget !== this) {
|
|
167
173
|
return;
|
|
168
174
|
}
|
|
169
|
-
this
|
|
175
|
+
this.#currentAction = null;
|
|
170
176
|
}
|
|
171
177
|
/**
|
|
172
178
|
* Sets the bounds of the widget.
|
|
@@ -180,10 +186,10 @@ export class InternalFlexiWidgetController extends FlexiWidgetController {
|
|
|
180
186
|
if (this.x == x && this.y == y && this.width == width && this.height == height) {
|
|
181
187
|
return;
|
|
182
188
|
}
|
|
183
|
-
this
|
|
184
|
-
this
|
|
185
|
-
this
|
|
186
|
-
this
|
|
189
|
+
this.#x = x;
|
|
190
|
+
this.#y = y;
|
|
191
|
+
this.#width = width;
|
|
192
|
+
this.#height = height;
|
|
187
193
|
if (interpolate) {
|
|
188
194
|
this.#interpolateMove(x, y, width, height);
|
|
189
195
|
}
|
|
@@ -214,55 +220,35 @@ export class InternalFlexiWidgetController extends FlexiWidgetController {
|
|
|
214
220
|
width: rect.width,
|
|
215
221
|
height: rect.height
|
|
216
222
|
}, this.#getMovementAnimation());
|
|
217
|
-
this
|
|
223
|
+
this.#isBeingDropped = false;
|
|
218
224
|
}
|
|
219
225
|
/**
|
|
220
226
|
* Registers a grabber to the widget.
|
|
221
227
|
*/
|
|
222
228
|
addGrabber() {
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
}
|
|
226
|
-
else {
|
|
227
|
-
this.#grabbersCount++;
|
|
228
|
-
this.backingState.hasGrabbers = this.#grabbersCount > 0;
|
|
229
|
-
}
|
|
229
|
+
this.#grabbersCount++;
|
|
230
|
+
this.#hasGrabbers = this.#grabbersCount > 0;
|
|
230
231
|
}
|
|
231
232
|
/**
|
|
232
233
|
* Unregisters a grabber from the widget.
|
|
233
234
|
*/
|
|
234
235
|
removeGrabber() {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
}
|
|
238
|
-
else {
|
|
239
|
-
this.#grabbersCount--;
|
|
240
|
-
this.backingState.hasGrabbers = this.#grabbersCount > 0;
|
|
241
|
-
}
|
|
236
|
+
this.#grabbersCount--;
|
|
237
|
+
this.#hasGrabbers = this.#grabbersCount > 0;
|
|
242
238
|
}
|
|
243
239
|
/**
|
|
244
240
|
* Registers a resizer to the widget.
|
|
245
241
|
*/
|
|
246
242
|
addResizer() {
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
}
|
|
250
|
-
else {
|
|
251
|
-
this.#resizersCount++;
|
|
252
|
-
this.backingState.hasResizers = this.#resizersCount > 0;
|
|
253
|
-
}
|
|
243
|
+
this.#resizersCount++;
|
|
244
|
+
this.#hasResizers = this.#resizersCount > 0;
|
|
254
245
|
}
|
|
255
246
|
/**
|
|
256
247
|
* Unregisters a resizer from the widget.
|
|
257
248
|
*/
|
|
258
249
|
removeResizer() {
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
}
|
|
262
|
-
else {
|
|
263
|
-
this.#resizersCount--;
|
|
264
|
-
this.backingState.hasResizers = this.#resizersCount > 0;
|
|
265
|
-
}
|
|
250
|
+
this.#resizersCount--;
|
|
251
|
+
this.#hasResizers = this.#resizersCount > 0;
|
|
266
252
|
}
|
|
267
253
|
/**
|
|
268
254
|
* Deletes this widget from its target and board.
|
|
@@ -295,124 +281,66 @@ export class InternalFlexiWidgetController extends FlexiWidgetController {
|
|
|
295
281
|
if (event.widget != this) {
|
|
296
282
|
return;
|
|
297
283
|
}
|
|
298
|
-
this
|
|
284
|
+
this.#currentAction = null;
|
|
299
285
|
// Clean up event subscriptions when widget is deleted
|
|
300
286
|
this.destroy();
|
|
301
287
|
}
|
|
302
|
-
/**
|
|
303
|
-
* Creates the reactive state container when the widget component mounts.
|
|
304
|
-
* This should be called from the component's onMount lifecycle.
|
|
305
|
-
*/
|
|
306
|
-
createReactiveState() {
|
|
307
|
-
// Create the reactive state with current backing state
|
|
308
|
-
this.reactiveState = new WidgetReactiveState(this, this.backingState);
|
|
309
|
-
// Transfer current grabber/resizer counts to reactive state
|
|
310
|
-
for (let i = 0; i < this.#grabbersCount; i++) {
|
|
311
|
-
this.reactiveState.addGrabber();
|
|
312
|
-
}
|
|
313
|
-
for (let i = 0; i < this.#resizersCount; i++) {
|
|
314
|
-
this.reactiveState.addResizer();
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
288
|
/**
|
|
318
289
|
* Cleanup method to be called when the widget is destroyed
|
|
319
290
|
*/
|
|
320
291
|
destroy() {
|
|
321
|
-
// Clean up reactive state first
|
|
322
|
-
this.destroyReactiveState();
|
|
323
292
|
// Clean up event subscriptions
|
|
324
293
|
this.#unsubscribers.forEach((unsubscribe) => unsubscribe());
|
|
325
294
|
this.#unsubscribers = [];
|
|
295
|
+
// Reset counters
|
|
296
|
+
this.#grabbersCount = 0;
|
|
297
|
+
this.#resizersCount = 0;
|
|
326
298
|
}
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
*/
|
|
331
|
-
destroyReactiveState() {
|
|
332
|
-
if (this.reactiveState) {
|
|
333
|
-
this.reactiveState.destroy();
|
|
334
|
-
this.reactiveState = undefined;
|
|
335
|
-
}
|
|
299
|
+
// Implement abstract getters from base class
|
|
300
|
+
get currentAction() {
|
|
301
|
+
return this.#currentAction;
|
|
336
302
|
}
|
|
337
|
-
/**
|
|
338
|
-
* The width in units of the widget.
|
|
339
|
-
*/
|
|
340
303
|
get width() {
|
|
341
|
-
|
|
342
|
-
return this.reactiveState.width;
|
|
343
|
-
}
|
|
344
|
-
return this.backingState.width;
|
|
304
|
+
return this.#width;
|
|
345
305
|
}
|
|
346
|
-
/**
|
|
347
|
-
* The height in units of the widget.
|
|
348
|
-
*/
|
|
349
306
|
get height() {
|
|
350
|
-
|
|
351
|
-
return this.reactiveState.height;
|
|
352
|
-
}
|
|
353
|
-
return this.backingState.height;
|
|
354
|
-
}
|
|
355
|
-
set width(value) {
|
|
356
|
-
if (this.reactiveState) {
|
|
357
|
-
this.reactiveState.width = value;
|
|
358
|
-
}
|
|
359
|
-
this.backingState.width = value;
|
|
307
|
+
return this.#height;
|
|
360
308
|
}
|
|
361
|
-
set height(value) {
|
|
362
|
-
if (this.reactiveState) {
|
|
363
|
-
this.reactiveState.height = value;
|
|
364
|
-
}
|
|
365
|
-
this.backingState.height = value;
|
|
366
|
-
}
|
|
367
|
-
/**
|
|
368
|
-
* Gets the column (x-coordinate) of the widget. This value is readonly and is managed by the target.
|
|
369
|
-
*/
|
|
370
309
|
get x() {
|
|
371
|
-
|
|
372
|
-
return this.reactiveState.x;
|
|
373
|
-
}
|
|
374
|
-
return this.backingState.x;
|
|
310
|
+
return this.#x;
|
|
375
311
|
}
|
|
376
|
-
/**
|
|
377
|
-
* Gets the row (y-coordinate) of the widget. This value is readonly and is managed by the target.
|
|
378
|
-
*/
|
|
379
312
|
get y() {
|
|
380
|
-
|
|
381
|
-
return this.reactiveState.y;
|
|
382
|
-
}
|
|
383
|
-
return this.backingState.y;
|
|
313
|
+
return this.#y;
|
|
384
314
|
}
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
this.reactiveState.x = value;
|
|
388
|
-
}
|
|
389
|
-
this.backingState.x = value;
|
|
315
|
+
get isBeingDropped() {
|
|
316
|
+
return this.#isBeingDropped;
|
|
390
317
|
}
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
this.reactiveState.y = value;
|
|
394
|
-
}
|
|
395
|
-
this.backingState.y = value;
|
|
318
|
+
get hasGrabbers() {
|
|
319
|
+
return this.#hasGrabbers;
|
|
396
320
|
}
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
get
|
|
401
|
-
return this
|
|
321
|
+
get hasResizers() {
|
|
322
|
+
return this.#hasResizers;
|
|
323
|
+
}
|
|
324
|
+
get isShadow() {
|
|
325
|
+
return this.#isShadow;
|
|
326
|
+
}
|
|
327
|
+
get isGrabbed() {
|
|
328
|
+
return this.#currentAction?.action == 'grab';
|
|
329
|
+
}
|
|
330
|
+
get isResizing() {
|
|
331
|
+
return this.#currentAction?.action == 'resize';
|
|
332
|
+
}
|
|
333
|
+
// Internal setters for these properties
|
|
334
|
+
set currentAction(value) {
|
|
335
|
+
this.#currentAction = value;
|
|
336
|
+
}
|
|
337
|
+
set isBeingDropped(value) {
|
|
338
|
+
this.#isBeingDropped = value;
|
|
402
339
|
}
|
|
403
340
|
/**
|
|
404
341
|
* Whether the widget should draw a placeholder widget in the DOM.
|
|
405
342
|
*/
|
|
406
343
|
get shouldDrawPlaceholder() {
|
|
407
|
-
if (this.reactiveState) {
|
|
408
|
-
return this.reactiveState.interpolator?.active ?? false;
|
|
409
|
-
}
|
|
410
344
|
return this.interpolator?.active ?? false;
|
|
411
345
|
}
|
|
412
|
-
set isBeingDropped(value) {
|
|
413
|
-
if (this.reactiveState) {
|
|
414
|
-
this.reactiveState.isBeingDropped = value;
|
|
415
|
-
}
|
|
416
|
-
this.backingState.isBeingDropped = value;
|
|
417
|
-
}
|
|
418
346
|
}
|
|
@@ -5,14 +5,15 @@ import { WidgetPointerEventWatcher } from './triggers.svelte.js';
|
|
|
5
5
|
export function widgetEvents(widget) {
|
|
6
6
|
const eventBus = getFlexiEventBusCtx();
|
|
7
7
|
const board = getInternalFlexiboardCtx();
|
|
8
|
-
const
|
|
8
|
+
const grabWatcher = new WidgetPointerEventWatcher(widget, 'grab');
|
|
9
9
|
return {
|
|
10
10
|
onpointerdown: (event) => {
|
|
11
11
|
// Grabbing the widget directly only works if the widget does not have grabbers.
|
|
12
12
|
if (widget.hasGrabbers) {
|
|
13
13
|
return;
|
|
14
14
|
}
|
|
15
|
-
|
|
15
|
+
// Invoke the trigger watcher which respects trigger configuration (immediate vs long press).
|
|
16
|
+
grabWatcher.onstartpointerdown(event);
|
|
16
17
|
},
|
|
17
18
|
onkeydown: (event) => {
|
|
18
19
|
// Grabbing the widget directly only works if the widget does not have grabbers.
|
|
@@ -26,39 +27,27 @@ export function widgetEvents(widget) {
|
|
|
26
27
|
export function widgetGrabberEvents(widget) {
|
|
27
28
|
const eventBus = getFlexiEventBusCtx();
|
|
28
29
|
const board = getInternalFlexiboardCtx();
|
|
30
|
+
const grabWatcher = new WidgetPointerEventWatcher(widget, 'grab');
|
|
29
31
|
return {
|
|
30
|
-
onpointerdown: (event) =>
|
|
32
|
+
onpointerdown: (event) => {
|
|
33
|
+
// Use the trigger watcher which respects trigger configuration (immediate vs long press)
|
|
34
|
+
grabWatcher.onstartpointerdown(event);
|
|
35
|
+
},
|
|
31
36
|
onkeydown: (event) => dispatchKeyDownGrab(eventBus, widget, board, event)
|
|
32
37
|
};
|
|
33
38
|
}
|
|
34
39
|
export function widgetResizerEvents(widget) {
|
|
35
40
|
const eventBus = getFlexiEventBusCtx();
|
|
36
41
|
const board = getInternalFlexiboardCtx();
|
|
42
|
+
const resizeWatcher = new WidgetPointerEventWatcher(widget, 'resize');
|
|
37
43
|
return {
|
|
38
|
-
onpointerdown: (event) =>
|
|
44
|
+
onpointerdown: (event) => {
|
|
45
|
+
// Invoke the trigger watcher which respects trigger configuration (immediate vs long press).
|
|
46
|
+
resizeWatcher.onstartpointerdown(event);
|
|
47
|
+
},
|
|
39
48
|
onkeydown: (event) => dispatchKeyDownResize(eventBus, widget, board, event)
|
|
40
49
|
};
|
|
41
50
|
}
|
|
42
|
-
/**
|
|
43
|
-
* Releases the pointer capture on the event target, before dispatching a 'widget:grabbed' event.
|
|
44
|
-
* @param eventBus The event bus to dispatch the event to.
|
|
45
|
-
* @param widget The widget that was grabbed.
|
|
46
|
-
* @param event The pointer event.
|
|
47
|
-
*/
|
|
48
|
-
function dispatchPointerDownGrab(eventBus, widget, board, event) {
|
|
49
|
-
if (!widget.draggable || !widget.ref || !isGrabPointerEvent(event)) {
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
// TODO: this MIGHT not be necessary anymore, due to our simulated pointer watcher.
|
|
53
|
-
// Don't implicitly keep the pointer capture, as then mobile can't move the widget in and out of targets.
|
|
54
|
-
// (event.target as HTMLElement).releasePointerCapture(event.pointerId);
|
|
55
|
-
// event.stopPropagation();
|
|
56
|
-
// event.preventDefault();
|
|
57
|
-
dispatchGrab(eventBus, widget, board, {
|
|
58
|
-
clientX: event.clientX,
|
|
59
|
-
clientY: event.clientY
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
51
|
/**
|
|
63
52
|
* Resolves clientX/clientY coordinates from a keyboard event, before dispatching a 'widget:grabbed' event.
|
|
64
53
|
* @param eventBus The event bus to dispatch the event to.
|
|
@@ -110,25 +99,6 @@ function dispatchGrab(eventBus, widget, board, { clientX, clientY }) {
|
|
|
110
99
|
yOffset: clientY - rect.top
|
|
111
100
|
});
|
|
112
101
|
}
|
|
113
|
-
/**
|
|
114
|
-
* Releases the pointer capture on the event target, before dispatching a 'widget:resizing' event.
|
|
115
|
-
* @param eventBus The event bus to dispatch the event to.
|
|
116
|
-
* @param widget The widget that was resized.
|
|
117
|
-
* @param event The pointer event.
|
|
118
|
-
*/
|
|
119
|
-
function dispatchPointerDownResize(eventBus, widget, board, event) {
|
|
120
|
-
if (!widget.resizable || !widget.ref) {
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
123
|
-
// Don't implicitly keep the pointer capture, as then mobile can't move the widget in and out of targets.
|
|
124
|
-
// (event.target as HTMLElement).releasePointerCapture(event.pointerId);
|
|
125
|
-
// event.stopPropagation();
|
|
126
|
-
// event.preventDefault();
|
|
127
|
-
dispatchResize(eventBus, widget, board, {
|
|
128
|
-
clientX: event.clientX,
|
|
129
|
-
clientY: event.clientY
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
102
|
/**
|
|
133
103
|
* Resolves clientX/clientY coordinates from a keyboard event, before dispatching a 'widget:resizing' event.
|
|
134
104
|
* @param eventBus The event bus to dispatch the event to.
|
|
@@ -146,24 +116,7 @@ function dispatchKeyDownResize(eventBus, widget, board, event) {
|
|
|
146
116
|
}
|
|
147
117
|
event.stopPropagation();
|
|
148
118
|
event.preventDefault();
|
|
149
|
-
const
|
|
150
|
-
dispatchResize(eventBus, widget, board, {
|
|
151
|
-
clientX: x,
|
|
152
|
-
clientY: y
|
|
153
|
-
});
|
|
154
|
-
}
|
|
155
|
-
/**
|
|
156
|
-
* Dispatches a 'widget:resizing' event to the event bus.
|
|
157
|
-
* @param eventBus The event bus to dispatch the event to.
|
|
158
|
-
* @param widget The widget that was resized.
|
|
159
|
-
* @param clientX The x-coordinate of the pointer event.
|
|
160
|
-
* @param clientY The y-coordinate of the pointer event.
|
|
161
|
-
*/
|
|
162
|
-
function dispatchResize(eventBus, widget, board, { clientX, clientY }) {
|
|
163
|
-
if (!widget.resizable || !widget.ref) {
|
|
164
|
-
return;
|
|
165
|
-
}
|
|
166
|
-
const rect = widget.ref?.getBoundingClientRect();
|
|
119
|
+
const rect = widget.ref.getBoundingClientRect();
|
|
167
120
|
if (!rect) {
|
|
168
121
|
return;
|
|
169
122
|
}
|
|
@@ -171,17 +124,18 @@ function dispatchResize(eventBus, widget, board, { clientX, clientY }) {
|
|
|
171
124
|
if (!boardRect) {
|
|
172
125
|
return;
|
|
173
126
|
}
|
|
127
|
+
const { x, y } = getElementMidpoint(event.target);
|
|
128
|
+
// Calculate position relative to board container (same as resize trigger logic)
|
|
174
129
|
const left = rect.left - boardRect.left + board.ref.scrollLeft;
|
|
175
130
|
const top = rect.top - boardRect.top + board.ref.scrollTop;
|
|
176
|
-
// TODO: resizing event schema
|
|
177
131
|
eventBus.dispatch('widget:resizing', {
|
|
178
132
|
widget,
|
|
179
133
|
board,
|
|
180
134
|
target: widget.internalTarget,
|
|
181
|
-
offsetX:
|
|
182
|
-
offsetY:
|
|
183
|
-
clientX,
|
|
184
|
-
clientY,
|
|
135
|
+
offsetX: x - left,
|
|
136
|
+
offsetY: y - top,
|
|
137
|
+
clientX: x,
|
|
138
|
+
clientY: y,
|
|
185
139
|
left,
|
|
186
140
|
top,
|
|
187
141
|
capturedHeightPx: rect.height,
|
|
@@ -13,7 +13,6 @@ export function flexiwidget(config) {
|
|
|
13
13
|
throw new Error("Failed to create widget. Check that the widget's x and y coordinates do not lead to an unresolvable collision.");
|
|
14
14
|
}
|
|
15
15
|
setContext(contextKey, widget);
|
|
16
|
-
widget.createReactiveState();
|
|
17
16
|
return {
|
|
18
17
|
widget
|
|
19
18
|
};
|
|
@@ -27,11 +26,7 @@ export function renderedflexiwidget(widget) {
|
|
|
27
26
|
widget.mounted = true;
|
|
28
27
|
});
|
|
29
28
|
const events = widgetEvents(widget);
|
|
30
|
-
//
|
|
31
|
-
// (it may have been created earlier when widget was added to target)
|
|
32
|
-
if (!widget.interpolator) {
|
|
33
|
-
widget.createReactiveState();
|
|
34
|
-
}
|
|
29
|
+
// Widget is now fully reactive by default - no additional setup needed
|
|
35
30
|
return {
|
|
36
31
|
widget,
|
|
37
32
|
...events
|
|
@@ -90,16 +90,23 @@ export class WidgetPointerEventWatcher {
|
|
|
90
90
|
if (!this.#widget.resizable) {
|
|
91
91
|
return;
|
|
92
92
|
}
|
|
93
|
+
// For resize, calculate position relative to board container.
|
|
94
|
+
const boardRect = this.#board.ref?.getBoundingClientRect();
|
|
95
|
+
if (!boardRect) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const left = rect.left - boardRect.left + this.#board.ref.scrollLeft;
|
|
99
|
+
const top = rect.top - boardRect.top + this.#board.ref.scrollTop;
|
|
93
100
|
this.#eventBus.dispatch('widget:resizing', {
|
|
94
101
|
widget: this.#widget,
|
|
95
102
|
board: this.#board,
|
|
96
103
|
target: this.#widget.target,
|
|
97
|
-
offsetX: event.clientX -
|
|
98
|
-
offsetY: event.clientY -
|
|
104
|
+
offsetX: event.clientX - left,
|
|
105
|
+
offsetY: event.clientY - top,
|
|
99
106
|
clientX: event.clientX,
|
|
100
107
|
clientY: event.clientY,
|
|
101
|
-
left
|
|
102
|
-
top
|
|
108
|
+
left,
|
|
109
|
+
top,
|
|
103
110
|
capturedHeightPx: rect.height,
|
|
104
111
|
capturedWidthPx: rect.width
|
|
105
112
|
});
|
package/package.json
CHANGED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import type { WidgetAction } from '../types.js';
|
|
2
|
-
import type { WidgetStateData } from './base.svelte.js';
|
|
3
|
-
import type { InternalFlexiWidgetController } from './controller.svelte.js';
|
|
4
|
-
import { WidgetMoveInterpolator } from './interpolator.svelte.js';
|
|
5
|
-
/**
|
|
6
|
-
* Reactive state container for FlexiWidgets.
|
|
7
|
-
* Constructed separately from the widget controller, as each state container
|
|
8
|
-
* is bound to the lifecycle of a widget component.
|
|
9
|
-
*/
|
|
10
|
-
export declare class WidgetReactiveState {
|
|
11
|
-
#private;
|
|
12
|
-
currentAction: WidgetAction | null;
|
|
13
|
-
width: number;
|
|
14
|
-
height: number;
|
|
15
|
-
x: number;
|
|
16
|
-
y: number;
|
|
17
|
-
isBeingDropped: boolean;
|
|
18
|
-
hasGrabbers: boolean;
|
|
19
|
-
hasResizers: boolean;
|
|
20
|
-
interpolator: WidgetMoveInterpolator;
|
|
21
|
-
constructor(widget: InternalFlexiWidgetController, initialState: WidgetStateData);
|
|
22
|
-
/**
|
|
23
|
-
* Adds a grabber and returns the current count
|
|
24
|
-
*/
|
|
25
|
-
addGrabber(): number;
|
|
26
|
-
/**
|
|
27
|
-
* Removes a grabber and returns the current count
|
|
28
|
-
*/
|
|
29
|
-
removeGrabber(): number;
|
|
30
|
-
/**
|
|
31
|
-
* Adds a resizer and returns the current count
|
|
32
|
-
*/
|
|
33
|
-
addResizer(): number;
|
|
34
|
-
/**
|
|
35
|
-
* Removes a resizer and returns the current count
|
|
36
|
-
*/
|
|
37
|
-
removeResizer(): number;
|
|
38
|
-
/**
|
|
39
|
-
* Gets the current grabber count
|
|
40
|
-
*/
|
|
41
|
-
get grabberCount(): number;
|
|
42
|
-
/**
|
|
43
|
-
* Gets the current resizer count
|
|
44
|
-
*/
|
|
45
|
-
get resizerCount(): number;
|
|
46
|
-
/**
|
|
47
|
-
* Syncs this reactive state back to the widget's backing state.
|
|
48
|
-
*/
|
|
49
|
-
syncToBackingState(): void;
|
|
50
|
-
/**
|
|
51
|
-
* Clean up resources when state is destroyed
|
|
52
|
-
*/
|
|
53
|
-
destroy(): void;
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* Legacy export for backwards compatibility
|
|
57
|
-
* @deprecated Use WidgetReactiveState instead
|
|
58
|
-
*/
|
|
59
|
-
export declare const WidgetState: typeof WidgetReactiveState;
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
import { WidgetMoveInterpolator } from './interpolator.svelte.js';
|
|
2
|
-
/**
|
|
3
|
-
* Reactive state container for FlexiWidgets.
|
|
4
|
-
* Constructed separately from the widget controller, as each state container
|
|
5
|
-
* is bound to the lifecycle of a widget component.
|
|
6
|
-
*/
|
|
7
|
-
export class WidgetReactiveState {
|
|
8
|
-
// Core state data
|
|
9
|
-
currentAction = $state(null);
|
|
10
|
-
width = $state(1);
|
|
11
|
-
height = $state(1);
|
|
12
|
-
x = $state(0);
|
|
13
|
-
y = $state(0);
|
|
14
|
-
isBeingDropped = $state(false);
|
|
15
|
-
// Grabber and resizer tracking
|
|
16
|
-
#grabbers = $state(0);
|
|
17
|
-
#resizers = $state(0);
|
|
18
|
-
// Derived reactive properties
|
|
19
|
-
hasGrabbers = $derived(this.#grabbers > 0);
|
|
20
|
-
hasResizers = $derived(this.#resizers > 0);
|
|
21
|
-
// Movement interpolation
|
|
22
|
-
interpolator;
|
|
23
|
-
// Reference to the controller (for callbacks, not state)
|
|
24
|
-
#widget;
|
|
25
|
-
constructor(widget, initialState) {
|
|
26
|
-
this.#widget = widget;
|
|
27
|
-
// Initialize with backing state values
|
|
28
|
-
this.currentAction = initialState.currentAction;
|
|
29
|
-
this.width = initialState.width;
|
|
30
|
-
this.height = initialState.height;
|
|
31
|
-
this.x = initialState.x;
|
|
32
|
-
this.y = initialState.y;
|
|
33
|
-
this.isBeingDropped = initialState.isBeingDropped;
|
|
34
|
-
// Create the widget's interpolator.
|
|
35
|
-
this.interpolator = new WidgetMoveInterpolator(widget.provider, widget);
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* Adds a grabber and returns the current count
|
|
39
|
-
*/
|
|
40
|
-
addGrabber() {
|
|
41
|
-
return ++this.#grabbers;
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* Removes a grabber and returns the current count
|
|
45
|
-
*/
|
|
46
|
-
removeGrabber() {
|
|
47
|
-
return --this.#grabbers;
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* Adds a resizer and returns the current count
|
|
51
|
-
*/
|
|
52
|
-
addResizer() {
|
|
53
|
-
return ++this.#resizers;
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* Removes a resizer and returns the current count
|
|
57
|
-
*/
|
|
58
|
-
removeResizer() {
|
|
59
|
-
return --this.#resizers;
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
|
-
* Gets the current grabber count
|
|
63
|
-
*/
|
|
64
|
-
get grabberCount() {
|
|
65
|
-
return this.#grabbers;
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Gets the current resizer count
|
|
69
|
-
*/
|
|
70
|
-
get resizerCount() {
|
|
71
|
-
return this.#resizers;
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
* Syncs this reactive state back to the widget's backing state.
|
|
75
|
-
*/
|
|
76
|
-
syncToBackingState() {
|
|
77
|
-
const backing = this.#widget.backingState;
|
|
78
|
-
backing.currentAction = this.currentAction;
|
|
79
|
-
backing.width = this.width;
|
|
80
|
-
backing.height = this.height;
|
|
81
|
-
backing.x = this.x;
|
|
82
|
-
backing.y = this.y;
|
|
83
|
-
backing.isBeingDropped = this.isBeingDropped;
|
|
84
|
-
backing.hasGrabbers = this.hasGrabbers;
|
|
85
|
-
backing.hasResizers = this.hasResizers;
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Clean up resources when state is destroyed
|
|
89
|
-
*/
|
|
90
|
-
destroy() {
|
|
91
|
-
// Sync final state back to backing store
|
|
92
|
-
this.syncToBackingState();
|
|
93
|
-
// Reset counters
|
|
94
|
-
this.#grabbers = 0;
|
|
95
|
-
this.#resizers = 0;
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* Legacy export for backwards compatibility
|
|
100
|
-
* @deprecated Use WidgetReactiveState instead
|
|
101
|
-
*/
|
|
102
|
-
export const WidgetState = WidgetReactiveState;
|