svelte-flexiboards 0.3.2 → 0.4.1
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/components/flexi-add.svelte +2 -15
- package/dist/components/flexi-add.svelte.d.ts +0 -12
- package/dist/components/flexi-delete.svelte +3 -16
- package/dist/components/flexi-delete.svelte.d.ts +0 -12
- package/dist/components/flexi-grab.svelte +2 -2
- package/dist/components/flexi-target.svelte +8 -19
- package/dist/components/flexi-widget.svelte +2 -2
- package/dist/components/responsive-flexi-board.svelte +83 -0
- package/dist/components/responsive-flexi-board.svelte.d.ts +34 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.js +4 -1
- package/dist/system/board/base.svelte.d.ts +15 -0
- package/dist/system/board/controller.svelte.d.ts +26 -4
- package/dist/system/board/controller.svelte.js +237 -28
- package/dist/system/board/types.d.ts +26 -0
- package/dist/system/grid/base.svelte.d.ts +9 -0
- package/dist/system/grid/base.svelte.js +12 -1
- package/dist/system/grid/flow-grid.svelte.js +105 -36
- package/dist/system/grid/free-grid.svelte.d.ts +6 -2
- package/dist/system/grid/free-grid.svelte.js +139 -20
- package/dist/system/misc/deleter.svelte.d.ts +0 -4
- package/dist/system/misc/deleter.svelte.js +1 -6
- package/dist/system/portal.js +0 -1
- package/dist/system/responsive/base.svelte.d.ts +46 -0
- package/dist/system/responsive/base.svelte.js +1 -0
- package/dist/system/responsive/controller.svelte.d.ts +78 -0
- package/dist/system/responsive/controller.svelte.js +264 -0
- package/dist/system/responsive/index.d.ts +16 -0
- package/dist/system/responsive/index.js +36 -0
- package/dist/system/responsive/types.d.ts +56 -0
- package/dist/system/responsive/types.js +1 -0
- package/dist/system/shared/event-bus.d.ts +3 -1
- package/dist/system/shared/utils.svelte.d.ts +2 -0
- package/dist/system/shared/utils.svelte.js +39 -22
- package/dist/system/target/controller.svelte.d.ts +7 -2
- package/dist/system/target/controller.svelte.js +103 -30
- package/dist/system/types.d.ts +13 -2
- package/dist/system/widget/base.svelte.d.ts +40 -1
- package/dist/system/widget/base.svelte.js +84 -2
- package/dist/system/widget/controller.svelte.d.ts +4 -1
- package/dist/system/widget/controller.svelte.js +106 -17
- package/dist/system/widget/events.js +10 -3
- package/dist/system/widget/interpolation-utils.d.ts +14 -0
- package/dist/system/widget/interpolation-utils.js +32 -0
- package/dist/system/widget/interpolator.svelte.d.ts +2 -1
- package/dist/system/widget/interpolator.svelte.js +63 -22
- package/dist/system/widget/triggers.svelte.js +1 -1
- package/dist/system/widget/types.d.ts +51 -6
- package/package.json +1 -1
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { tick, untrack } from 'svelte';
|
|
2
|
-
import { FreeFormFlexiGrid } from '../grid/free-grid.svelte.js';
|
|
3
2
|
import { FlexiGrid, FlowFlexiGrid } from '../grid/index.js';
|
|
4
3
|
import { FlexiWidgetController } from '../widget/base.svelte.js';
|
|
5
4
|
import { InternalFlexiWidgetController } from '../widget/controller.svelte.js';
|
|
6
5
|
import { getFlexiEventBus } from '../shared/event-bus.js';
|
|
7
6
|
import { SvelteSet } from 'svelte/reactivity';
|
|
8
7
|
import { getPointerService } from '../shared/utils.svelte.js';
|
|
8
|
+
import { FreeFormFlexiGrid } from '../grid/free-grid.svelte.js';
|
|
9
9
|
export class InternalFlexiTargetController {
|
|
10
10
|
#widgets = $state(new SvelteSet());
|
|
11
11
|
#orderedWidgets = $state([]);
|
|
@@ -32,10 +32,16 @@ export class InternalFlexiTargetController {
|
|
|
32
32
|
x: 0,
|
|
33
33
|
y: 0
|
|
34
34
|
});
|
|
35
|
+
// Raw (fractional) cell position - used for resize snapping (rounds instead of floors)
|
|
36
|
+
#rawMouseCellPosition = $state({
|
|
37
|
+
x: 0,
|
|
38
|
+
y: 0
|
|
39
|
+
});
|
|
35
40
|
key;
|
|
36
41
|
#grid = null;
|
|
37
42
|
#preGrabSnapshot = null;
|
|
38
43
|
#gridSnapshot = null;
|
|
44
|
+
registry = $derived(this.provider?.registry);
|
|
39
45
|
#targetConfig = $state(undefined);
|
|
40
46
|
#pointerService = getPointerService();
|
|
41
47
|
config = $derived({
|
|
@@ -122,10 +128,20 @@ export class InternalFlexiTargetController {
|
|
|
122
128
|
}
|
|
123
129
|
createWidget(config) {
|
|
124
130
|
const [x, y, width, height] = [config.x, config.y, config.width, config.height];
|
|
131
|
+
let widgetConfig = {};
|
|
132
|
+
if (config.type) {
|
|
133
|
+
if (!this.registry?.[config.type]) {
|
|
134
|
+
console.warn('createWidget(): widget with type ', config.type, ' not found in registry, it will be missing settings.');
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
widgetConfig = { ...this.registry[config.type] };
|
|
138
|
+
}
|
|
139
|
+
}
|
|
125
140
|
const widget = new InternalFlexiWidgetController({
|
|
126
|
-
config,
|
|
141
|
+
config: { ...widgetConfig, ...config },
|
|
127
142
|
provider: this.provider,
|
|
128
|
-
target: this
|
|
143
|
+
target: this,
|
|
144
|
+
type: config.type
|
|
129
145
|
});
|
|
130
146
|
// If the widget can't be added, it's probably a collision.
|
|
131
147
|
if (!this.#tryAddWidget(widget, x, y, width, height)) {
|
|
@@ -160,19 +176,46 @@ export class InternalFlexiTargetController {
|
|
|
160
176
|
if (deleted && 'destroy' in widget) {
|
|
161
177
|
widget.destroy();
|
|
162
178
|
}
|
|
179
|
+
// Clear the pre-grab snapshot only if the deleted widget is the one being grabbed/resized
|
|
180
|
+
// (prevents the board's safety net from restoring a widget that was intentionally removed)
|
|
181
|
+
// Note: We don't clear if a different widget is deleted during a grab operation
|
|
182
|
+
if (this.actionWidget?.widget === widget) {
|
|
183
|
+
this.forgetPreGrabSnapshot();
|
|
184
|
+
}
|
|
163
185
|
// Apply any deferred operations like row collapsing now that the operation is complete
|
|
164
186
|
this.applyGridPostCompletionOperations();
|
|
165
187
|
return deleted;
|
|
166
188
|
}
|
|
167
189
|
/**
|
|
168
190
|
* Imports a layout of widgets into this target, replacing any existing widgets.
|
|
191
|
+
* Widgets with types not found in the registry will be skipped with a warning.
|
|
169
192
|
* @param layout The layout to import.
|
|
170
193
|
*/
|
|
171
194
|
importLayout(layout) {
|
|
195
|
+
if (!this.registry) {
|
|
196
|
+
console.warn('importLayout(): no registry provided, cannot import layout. Provide a registry to the FlexiBoard component.');
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
172
199
|
this.widgets.clear();
|
|
173
200
|
this.grid.clear();
|
|
174
|
-
for (const
|
|
175
|
-
|
|
201
|
+
for (const entry of layout) {
|
|
202
|
+
if (!entry.type) {
|
|
203
|
+
console.warn('importLayout(): skipping widget entry with no type:', entry);
|
|
204
|
+
continue;
|
|
205
|
+
}
|
|
206
|
+
if (!this.registry[entry.type]) {
|
|
207
|
+
console.warn(`importLayout(): widget type "${entry.type}" not found in registry, skipping widget.`);
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
this.createWidget({
|
|
211
|
+
id: entry.id,
|
|
212
|
+
type: entry.type,
|
|
213
|
+
x: entry.x,
|
|
214
|
+
y: entry.y,
|
|
215
|
+
width: entry.width,
|
|
216
|
+
height: entry.height,
|
|
217
|
+
metadata: entry.metadata
|
|
218
|
+
});
|
|
176
219
|
}
|
|
177
220
|
}
|
|
178
221
|
/**
|
|
@@ -180,41 +223,51 @@ export class InternalFlexiTargetController {
|
|
|
180
223
|
* @returns The layout of widgets.
|
|
181
224
|
*/
|
|
182
225
|
exportLayout() {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
226
|
+
// Prevent reactive subscriptions onto exportLayout directly - they should use onLayoutChange.
|
|
227
|
+
return untrack(() => {
|
|
228
|
+
const result = [];
|
|
229
|
+
// Likely much more information than needed, but we've got it.
|
|
230
|
+
for (const widget of this.internalWidgets) {
|
|
231
|
+
if (!widget.type) {
|
|
232
|
+
console.warn('exportLayout(): widget has no type, it will be skipped.');
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
235
|
+
const entry = {
|
|
236
|
+
type: widget.type,
|
|
237
|
+
width: widget.width,
|
|
238
|
+
height: widget.height,
|
|
239
|
+
x: widget.x,
|
|
240
|
+
y: widget.y,
|
|
241
|
+
metadata: widget.metadata
|
|
242
|
+
};
|
|
243
|
+
// Only include id if user provided one
|
|
244
|
+
if (widget.userProvidedId) {
|
|
245
|
+
entry.id = widget.userProvidedId;
|
|
246
|
+
}
|
|
247
|
+
result.push(entry);
|
|
248
|
+
}
|
|
249
|
+
return result;
|
|
250
|
+
});
|
|
201
251
|
}
|
|
202
|
-
#createShadow(of) {
|
|
252
|
+
#createShadow(of, action) {
|
|
203
253
|
const shadow = new InternalFlexiWidgetController({
|
|
204
254
|
config: {
|
|
205
255
|
width: of.width,
|
|
206
256
|
height: of.height,
|
|
207
257
|
component: of.component,
|
|
208
258
|
draggable: of.draggable,
|
|
259
|
+
draggability: of.draggability,
|
|
209
260
|
resizability: of.resizability,
|
|
210
261
|
snippet: of.snippet,
|
|
211
262
|
className: of.className,
|
|
212
|
-
componentProps: of.componentProps
|
|
263
|
+
componentProps: of.componentProps,
|
|
264
|
+
metadata: of.metadata
|
|
213
265
|
},
|
|
214
266
|
provider: this.provider,
|
|
215
267
|
target: this,
|
|
216
268
|
isShadow: true
|
|
217
269
|
});
|
|
270
|
+
shadow.interpolationAnimationHint = action === 'resize' ? 'resize' : 'move';
|
|
218
271
|
return shadow;
|
|
219
272
|
}
|
|
220
273
|
// Events
|
|
@@ -240,6 +293,9 @@ export class InternalFlexiTargetController {
|
|
|
240
293
|
forgetPreGrabSnapshot() {
|
|
241
294
|
this.#preGrabSnapshot = null;
|
|
242
295
|
}
|
|
296
|
+
hasPreGrabSnapshot() {
|
|
297
|
+
return this.#preGrabSnapshot !== null;
|
|
298
|
+
}
|
|
243
299
|
applyGridPostCompletionOperations() {
|
|
244
300
|
this.grid.applyPostCompletionOperations();
|
|
245
301
|
}
|
|
@@ -259,6 +315,9 @@ export class InternalFlexiTargetController {
|
|
|
259
315
|
// Try to formally place the widget in the grid, which will also serve as a final check that
|
|
260
316
|
// the drop is possible.
|
|
261
317
|
const result = this.#tryAddWidget(widget, x, y, width, height);
|
|
318
|
+
if (!result) {
|
|
319
|
+
widget.isBeingDropped = false;
|
|
320
|
+
}
|
|
262
321
|
// Apply any deferred operations like row collapsing now that the operation is complete
|
|
263
322
|
if (result) {
|
|
264
323
|
this.applyGridPostCompletionOperations();
|
|
@@ -269,6 +328,8 @@ export class InternalFlexiTargetController {
|
|
|
269
328
|
}
|
|
270
329
|
onmousegridcellmove(event) {
|
|
271
330
|
this.#updateMouseCellPosition(event.cellX, event.cellY);
|
|
331
|
+
this.#rawMouseCellPosition.x = event.rawCellX;
|
|
332
|
+
this.#rawMouseCellPosition.y = event.rawCellY;
|
|
272
333
|
this.#updateDropzoneWidget();
|
|
273
334
|
}
|
|
274
335
|
onWidgetGrabbed(event) {
|
|
@@ -394,9 +455,10 @@ export class InternalFlexiTargetController {
|
|
|
394
455
|
const grid = this.grid;
|
|
395
456
|
// Take a snapshot of the grid so we can restore its state if the hover stops.
|
|
396
457
|
this.#gridSnapshot = grid.takeSnapshot();
|
|
458
|
+
grid.setDragSnapshot(this.#gridSnapshot);
|
|
397
459
|
// TODO: Not sure why the $effect.root is needed, but it is.
|
|
398
460
|
this.#dropzoneWidgetDestroy = $effect.root(() => {
|
|
399
|
-
this.dropzoneWidget = this.#createShadow(this.actionWidget.widget);
|
|
461
|
+
this.dropzoneWidget = this.#createShadow(this.actionWidget.widget, this.actionWidget.action);
|
|
400
462
|
});
|
|
401
463
|
let [x, y, width, height] = this.#getDropzoneLocation(this.actionWidget);
|
|
402
464
|
const added = this.grid.tryPlaceWidget(this.dropzoneWidget, x, y, width, height, true);
|
|
@@ -455,8 +517,12 @@ export class InternalFlexiTargetController {
|
|
|
455
517
|
}
|
|
456
518
|
#getNewWidgetHeightAndWidth(widget, mouseCellPosition) {
|
|
457
519
|
const grid = this.grid;
|
|
458
|
-
|
|
459
|
-
|
|
520
|
+
// Use raw (fractional) position with rounding for smoother resize snapping
|
|
521
|
+
// This makes the widget snap to the next cell when more than halfway through
|
|
522
|
+
const roundedX = Math.round(this.#rawMouseCellPosition.x);
|
|
523
|
+
const roundedY = Math.round(this.#rawMouseCellPosition.y);
|
|
524
|
+
let newWidth = Math.max(1, Math.min(widget.maxWidth, Math.max(roundedX - widget.x, widget.minWidth)));
|
|
525
|
+
let newHeight = Math.max(1, Math.min(widget.maxHeight, Math.max(roundedY - widget.y, widget.minHeight)));
|
|
460
526
|
// If the widget is in a flow layout, then they can't change their flow axis dimensions.
|
|
461
527
|
// NEXT: show this visually to the user by faking the "horizontal"/"vertical" resizable modes.
|
|
462
528
|
if (this.config.layout.type == 'flow' && this.config.layout.flowAxis == 'row') {
|
|
@@ -479,17 +545,21 @@ export class InternalFlexiTargetController {
|
|
|
479
545
|
if (!this.dropzoneWidget) {
|
|
480
546
|
return;
|
|
481
547
|
}
|
|
548
|
+
const dropzoneWidget = this.dropzoneWidget;
|
|
482
549
|
const grid = this.grid;
|
|
483
|
-
grid.removeWidget(
|
|
550
|
+
grid.removeWidget(dropzoneWidget);
|
|
484
551
|
if (this.#isDropzoneWidgetAdded) {
|
|
485
|
-
this.widgets.delete(
|
|
552
|
+
this.widgets.delete(dropzoneWidget);
|
|
486
553
|
this.#isDropzoneWidgetAdded = false;
|
|
487
554
|
}
|
|
488
555
|
grid.restoreFromSnapshot(this.#gridSnapshot);
|
|
556
|
+
grid.clearDragSnapshot();
|
|
489
557
|
this.#gridSnapshot = null;
|
|
490
558
|
this.dropzoneWidget = null;
|
|
491
559
|
this.#dropzoneWidgetDestroy?.();
|
|
492
560
|
this.#dropzoneWidgetDestroy = null;
|
|
561
|
+
// Clean up the shadow widget's event subscriptions and reset counters
|
|
562
|
+
dropzoneWidget.destroy();
|
|
493
563
|
}
|
|
494
564
|
// State-related getters and setters
|
|
495
565
|
/**
|
|
@@ -543,6 +613,9 @@ export class InternalFlexiTargetController {
|
|
|
543
613
|
set dropzoneWidget(value) {
|
|
544
614
|
this.#dropzoneWidget.value = value;
|
|
545
615
|
}
|
|
616
|
+
get shouldRenderDropzoneWidget() {
|
|
617
|
+
return this.#isDropzoneWidgetAdded && !!this.dropzoneWidget;
|
|
618
|
+
}
|
|
546
619
|
get widgets() {
|
|
547
620
|
return this.#widgets;
|
|
548
621
|
}
|
package/dist/system/types.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type { InternalFlexiTargetController } from './target/controller.svelte.js';
|
|
2
2
|
import type { FlexiAddController, InternalFlexiAddController } from './misc/adder.svelte.js';
|
|
3
3
|
import type { FlexiWidgetController } from './widget/base.svelte.js';
|
|
4
|
-
import type { FlexiWidgetConfiguration } from './widget/types.js';
|
|
5
4
|
import type { InternalFlexiBoardController } from './board/controller.svelte.js';
|
|
6
5
|
import type { InternalFlexiWidgetController } from './widget/controller.svelte.js';
|
|
6
|
+
import type { FlexiLayout } from './board/types.js';
|
|
7
|
+
import type { InternalResponsiveFlexiBoardController } from './responsive/controller.svelte.js';
|
|
7
8
|
export type ProxiedValue<T> = {
|
|
8
9
|
value: T;
|
|
9
10
|
};
|
|
@@ -16,6 +17,7 @@ export type FlexiCommonProps<T> = {
|
|
|
16
17
|
onfirstcreate?: (instance: T) => void;
|
|
17
18
|
};
|
|
18
19
|
export type WidgetResizability = 'none' | 'horizontal' | 'vertical' | 'both';
|
|
20
|
+
export type WidgetDraggability = 'none' | 'movable' | 'full';
|
|
19
21
|
export type WidgetGrabAction = {
|
|
20
22
|
action: 'grab';
|
|
21
23
|
widget: InternalFlexiWidgetController;
|
|
@@ -112,6 +114,8 @@ export type TargetEvent = {
|
|
|
112
114
|
export type MouseGridCellMoveEvent = {
|
|
113
115
|
cellX: number;
|
|
114
116
|
cellY: number;
|
|
117
|
+
rawCellX: number;
|
|
118
|
+
rawCellY: number;
|
|
115
119
|
};
|
|
116
120
|
export type GrabbedWidgetMouseEvent = {
|
|
117
121
|
widget: FlexiWidgetController;
|
|
@@ -119,7 +123,6 @@ export type GrabbedWidgetMouseEvent = {
|
|
|
119
123
|
export type HoveredTargetEvent = {
|
|
120
124
|
target: InternalFlexiTargetController;
|
|
121
125
|
};
|
|
122
|
-
export type FlexiSavedLayout = Record<string, FlexiWidgetConfiguration[]>;
|
|
123
126
|
export type WidgetActionEvent = (PointerEvent & {
|
|
124
127
|
isKeyboard?: undefined;
|
|
125
128
|
}) | (KeyboardEvent & {
|
|
@@ -127,3 +130,11 @@ export type WidgetActionEvent = (PointerEvent & {
|
|
|
127
130
|
clientX: number;
|
|
128
131
|
clientY: number;
|
|
129
132
|
});
|
|
133
|
+
export type BoardLayoutChangeEvent = {
|
|
134
|
+
board: InternalFlexiBoardController;
|
|
135
|
+
layout: FlexiLayout;
|
|
136
|
+
breakpoint?: string;
|
|
137
|
+
};
|
|
138
|
+
export type ResponsiveLayoutImportEvent = {
|
|
139
|
+
responsiveController: InternalResponsiveFlexiBoardController;
|
|
140
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Component } from 'svelte';
|
|
2
2
|
import type { FlexiTargetController } from '../target/index.js';
|
|
3
|
-
import type { WidgetAction, WidgetResizability } from '../types.js';
|
|
3
|
+
import type { WidgetAction, WidgetDraggability, WidgetResizability } from '../types.js';
|
|
4
4
|
import { type FlexiWidgetChildrenSnippet, type FlexiWidgetClasses, type FlexiWidgetConstructorParams } from './types.js';
|
|
5
5
|
export declare class FlexiWidgetController {
|
|
6
6
|
#private;
|
|
@@ -43,9 +43,23 @@ export declare class FlexiWidgetController {
|
|
|
43
43
|
set currentAction(value: WidgetAction | null);
|
|
44
44
|
/**
|
|
45
45
|
* Whether the widget is draggable.
|
|
46
|
+
* @deprecated Prefer the use of `draggability` instead for finer control. When `true`, `draggability = 'full'`, when `false`, `draggability = 'none'`.
|
|
46
47
|
*/
|
|
47
48
|
get draggable(): boolean;
|
|
48
49
|
set draggable(value: boolean);
|
|
50
|
+
/**
|
|
51
|
+
* The draggability of the widget.
|
|
52
|
+
*/
|
|
53
|
+
get draggability(): WidgetDraggability;
|
|
54
|
+
set draggability(value: WidgetDraggability);
|
|
55
|
+
/**
|
|
56
|
+
* Whether the widget can be grabbed.
|
|
57
|
+
*/
|
|
58
|
+
get isGrabbable(): boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Whether the widget can be moved.
|
|
61
|
+
*/
|
|
62
|
+
get isMovable(): boolean;
|
|
49
63
|
/**
|
|
50
64
|
* The resizability of the widget.
|
|
51
65
|
*/
|
|
@@ -122,6 +136,31 @@ export declare class FlexiWidgetController {
|
|
|
122
136
|
*/
|
|
123
137
|
get isBeingDropped(): boolean;
|
|
124
138
|
set isBeingDropped(value: boolean);
|
|
139
|
+
/**
|
|
140
|
+
* The minimum width of the widget in units.
|
|
141
|
+
*/
|
|
142
|
+
get minWidth(): number;
|
|
143
|
+
/**
|
|
144
|
+
* The minimum height of the widget in units.
|
|
145
|
+
*/
|
|
146
|
+
get minHeight(): number;
|
|
147
|
+
/**
|
|
148
|
+
* The maximum width of the widget in units.
|
|
149
|
+
*/
|
|
150
|
+
get maxWidth(): number;
|
|
151
|
+
/**
|
|
152
|
+
* The maximum height of the widget in units.
|
|
153
|
+
*/
|
|
154
|
+
get maxHeight(): number;
|
|
155
|
+
/**
|
|
156
|
+
* The user-provided stable identifier for this widget, if any.
|
|
157
|
+
* This is used for persistence and layout import/export.
|
|
158
|
+
*/
|
|
159
|
+
get userProvidedId(): string | undefined;
|
|
160
|
+
/**
|
|
161
|
+
* The type of this widget (registry key for looking up configuration).
|
|
162
|
+
*/
|
|
163
|
+
get type(): string | undefined;
|
|
125
164
|
}
|
|
126
165
|
export type WidgetStateData = {
|
|
127
166
|
currentAction: WidgetAction | null;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { FlexiControllerBase } from '../base.svelte.js';
|
|
2
2
|
import { defaultTriggerConfig } from './types.js';
|
|
3
|
-
import { WidgetMoveInterpolator } from './interpolator.svelte.js';
|
|
4
3
|
export class FlexiWidgetController {
|
|
5
4
|
/**
|
|
6
5
|
* The target this widget is under. This is not defined if the widget has not yet been dropped in the board.
|
|
@@ -47,6 +46,14 @@ export class FlexiWidgetController {
|
|
|
47
46
|
this.#targetWidgetDefaults?.draggable ??
|
|
48
47
|
this.#providerWidgetDefaults?.draggable ??
|
|
49
48
|
true,
|
|
49
|
+
draggability: this.#rawConfig.draggability ??
|
|
50
|
+
this.#targetWidgetDefaults?.draggability ??
|
|
51
|
+
this.#providerWidgetDefaults?.draggability ??
|
|
52
|
+
// This is not pretty but will ensure backwards compatibility with the old `draggable` property.
|
|
53
|
+
(this.#rawConfig.draggable !== undefined ? (this.#rawConfig.draggable ? 'full' : 'none') : undefined) ??
|
|
54
|
+
(this.#targetWidgetDefaults?.draggable !== undefined ? (this.#targetWidgetDefaults?.draggable ? 'full' : 'none') : undefined) ??
|
|
55
|
+
(this.#providerWidgetDefaults?.draggable !== undefined ? (this.#providerWidgetDefaults?.draggable ? 'full' : 'none') : undefined) ??
|
|
56
|
+
'full',
|
|
50
57
|
className: this.#rawConfig.className ??
|
|
51
58
|
this.#targetWidgetDefaults?.className ??
|
|
52
59
|
this.#providerWidgetDefaults?.className,
|
|
@@ -62,7 +69,23 @@ export class FlexiWidgetController {
|
|
|
62
69
|
resizeTrigger: this.#rawConfig.resizeTrigger ??
|
|
63
70
|
this.#targetWidgetDefaults?.resizeTrigger ??
|
|
64
71
|
this.#providerWidgetDefaults?.resizeTrigger ??
|
|
65
|
-
defaultTriggerConfig
|
|
72
|
+
defaultTriggerConfig,
|
|
73
|
+
minWidth: this.#rawConfig.minWidth ??
|
|
74
|
+
this.#targetWidgetDefaults?.minWidth ??
|
|
75
|
+
this.#providerWidgetDefaults?.minWidth ??
|
|
76
|
+
1,
|
|
77
|
+
minHeight: this.#rawConfig.minHeight ??
|
|
78
|
+
this.#targetWidgetDefaults?.minHeight ??
|
|
79
|
+
this.#providerWidgetDefaults?.minHeight ??
|
|
80
|
+
1,
|
|
81
|
+
maxWidth: this.#rawConfig.maxWidth ??
|
|
82
|
+
this.#targetWidgetDefaults?.maxWidth ??
|
|
83
|
+
this.#providerWidgetDefaults?.maxWidth ??
|
|
84
|
+
Infinity,
|
|
85
|
+
maxHeight: this.#rawConfig.maxHeight ??
|
|
86
|
+
this.#targetWidgetDefaults?.maxHeight ??
|
|
87
|
+
this.#providerWidgetDefaults?.maxHeight ??
|
|
88
|
+
Infinity,
|
|
66
89
|
});
|
|
67
90
|
// Reactive state properties - single source of truth
|
|
68
91
|
backingState = $state();
|
|
@@ -97,6 +120,7 @@ export class FlexiWidgetController {
|
|
|
97
120
|
}
|
|
98
121
|
/**
|
|
99
122
|
* Whether the widget is draggable.
|
|
123
|
+
* @deprecated Prefer the use of `draggability` instead for finer control. When `true`, `draggability = 'full'`, when `false`, `draggability = 'none'`.
|
|
100
124
|
*/
|
|
101
125
|
get draggable() {
|
|
102
126
|
return this.#config.draggable;
|
|
@@ -104,6 +128,27 @@ export class FlexiWidgetController {
|
|
|
104
128
|
set draggable(value) {
|
|
105
129
|
this.#rawConfig.draggable = value;
|
|
106
130
|
}
|
|
131
|
+
/**
|
|
132
|
+
* The draggability of the widget.
|
|
133
|
+
*/
|
|
134
|
+
get draggability() {
|
|
135
|
+
return this.#config.draggability;
|
|
136
|
+
}
|
|
137
|
+
set draggability(value) {
|
|
138
|
+
this.#rawConfig.draggability = value;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Whether the widget can be grabbed.
|
|
142
|
+
*/
|
|
143
|
+
get isGrabbable() {
|
|
144
|
+
return this.#config.draggability == 'full';
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Whether the widget can be moved.
|
|
148
|
+
*/
|
|
149
|
+
get isMovable() {
|
|
150
|
+
return this.#config.draggability == 'movable' || this.#config.draggability == 'full';
|
|
151
|
+
}
|
|
107
152
|
/**
|
|
108
153
|
* The resizability of the widget.
|
|
109
154
|
*/
|
|
@@ -228,4 +273,41 @@ export class FlexiWidgetController {
|
|
|
228
273
|
set isBeingDropped(value) {
|
|
229
274
|
this.backingState.isBeingDropped = value;
|
|
230
275
|
}
|
|
276
|
+
/**
|
|
277
|
+
* The minimum width of the widget in units.
|
|
278
|
+
*/
|
|
279
|
+
get minWidth() {
|
|
280
|
+
return this.#config.minWidth;
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* The minimum height of the widget in units.
|
|
284
|
+
*/
|
|
285
|
+
get minHeight() {
|
|
286
|
+
return this.#config.minHeight;
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* The maximum width of the widget in units.
|
|
290
|
+
*/
|
|
291
|
+
get maxWidth() {
|
|
292
|
+
return this.#config.maxWidth;
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* The maximum height of the widget in units.
|
|
296
|
+
*/
|
|
297
|
+
get maxHeight() {
|
|
298
|
+
return this.#config.maxHeight;
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* The user-provided stable identifier for this widget, if any.
|
|
302
|
+
* This is used for persistence and layout import/export.
|
|
303
|
+
*/
|
|
304
|
+
get userProvidedId() {
|
|
305
|
+
return undefined; // Overridden in InternalFlexiWidgetController
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* The type of this widget (registry key for looking up configuration).
|
|
309
|
+
*/
|
|
310
|
+
get type() {
|
|
311
|
+
return undefined; // Overridden in InternalFlexiWidgetController
|
|
312
|
+
}
|
|
231
313
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { 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
|
+
import { WidgetMoveInterpolator, type WidgetMovementAnimation } from './interpolator.svelte.js';
|
|
5
5
|
import type { FlexiWidgetConstructorParams } from './types.js';
|
|
6
6
|
import type { InternalFlexiBoardController } from '../board/controller.svelte.js';
|
|
7
7
|
export declare class InternalFlexiWidgetController extends FlexiWidgetController {
|
|
@@ -10,6 +10,8 @@ export declare class InternalFlexiWidgetController extends FlexiWidgetController
|
|
|
10
10
|
internalTarget?: InternalFlexiTargetController;
|
|
11
11
|
provider: InternalFlexiBoardController;
|
|
12
12
|
mounted: boolean;
|
|
13
|
+
get type(): string | undefined;
|
|
14
|
+
get userProvidedId(): string | undefined;
|
|
13
15
|
/**
|
|
14
16
|
* The styling to apply to the widget.
|
|
15
17
|
*/
|
|
@@ -57,4 +59,5 @@ export declare class InternalFlexiWidgetController extends FlexiWidgetController
|
|
|
57
59
|
* Whether the widget should draw a placeholder widget in the DOM.
|
|
58
60
|
*/
|
|
59
61
|
get shouldDrawPlaceholder(): boolean;
|
|
62
|
+
set interpolationAnimationHint(value: WidgetMovementAnimation | null);
|
|
60
63
|
}
|