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,8 +1,12 @@
|
|
|
1
1
|
import { getFlexiEventBus } from '../shared/event-bus.js';
|
|
2
2
|
import { AutoScrollService, getPointerService } from '../shared/utils.svelte.js';
|
|
3
3
|
import { InternalFlexiTargetController } from '../target/controller.svelte.js';
|
|
4
|
+
import { getInternalResponsiveFlexiboardCtx, hasInternalResponsiveFlexiboardCtx } from '../responsive/index.js';
|
|
4
5
|
export class InternalFlexiBoardController {
|
|
5
6
|
#currentWidgetAction = $state(null);
|
|
7
|
+
#activeInterpolations = $state(0);
|
|
8
|
+
#scrollbarCompensation = $state(0);
|
|
9
|
+
#hasScrollbarCompensation = false;
|
|
6
10
|
#targets = new Map();
|
|
7
11
|
hoveredTarget = null;
|
|
8
12
|
#hoveredOverDeleter = $state(false);
|
|
@@ -11,24 +15,95 @@ export class InternalFlexiBoardController {
|
|
|
11
15
|
#autoScrollService = new AutoScrollService(this.#ref);
|
|
12
16
|
#rawProps = $state(undefined);
|
|
13
17
|
config = $derived(this.#rawProps?.config);
|
|
18
|
+
registry = $derived(this.#rawProps?.config?.registry);
|
|
14
19
|
#nextTargetIndex = 0;
|
|
15
|
-
#storedLoadLayout = null;
|
|
16
20
|
#ready = false;
|
|
21
|
+
#storedLoadLayout;
|
|
17
22
|
portal = null;
|
|
18
23
|
#announcer = null;
|
|
19
24
|
#eventBus;
|
|
20
25
|
#unsubscribers = [];
|
|
26
|
+
#layoutChangeTimeout = null;
|
|
27
|
+
#layoutChangeDebounceMs = 150;
|
|
28
|
+
breakpoint;
|
|
29
|
+
/**
|
|
30
|
+
* Reference to the parent responsive controller, if this board is within a ResponsiveFlexiBoard.
|
|
31
|
+
*/
|
|
32
|
+
#responsiveController = null;
|
|
21
33
|
constructor(props) {
|
|
22
34
|
// Track the props proxy so our config reactively updates.
|
|
23
35
|
this.#rawProps = props;
|
|
24
36
|
this.#eventBus = getFlexiEventBus();
|
|
25
|
-
|
|
37
|
+
// Check if we're inside a responsive context
|
|
38
|
+
if (hasInternalResponsiveFlexiboardCtx()) {
|
|
39
|
+
this.#responsiveController = getInternalResponsiveFlexiboardCtx();
|
|
40
|
+
// Infer breakpoint from responsive controller's current state
|
|
41
|
+
this.breakpoint = this.#responsiveController.currentBreakpoint;
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
// Not in responsive context - use config breakpoint if provided (with warning)
|
|
45
|
+
this.breakpoint = this.#rawProps?.config?.breakpoint;
|
|
46
|
+
if (this.breakpoint) {
|
|
47
|
+
console.warn('Breakpoint is set for a non-responsive board. Ignoring breakpoint.');
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
this.#unsubscribers.push(this.#eventBus.subscribe('widget:grabbed', this.onWidgetGrabbed.bind(this)), this.#eventBus.subscribe('widget:resizing', this.onWidgetResizing.bind(this)), this.#eventBus.subscribe('widget:release', this.handleWidgetRelease.bind(this)), this.#eventBus.subscribe('widget:cancel', this.handleWidgetCancel.bind(this)), this.#eventBus.subscribe('target:pointerenter', this.onPointerEnterTarget.bind(this)), this.#eventBus.subscribe('target:pointerleave', this.onPointerLeaveTarget.bind(this)),
|
|
51
|
+
// Layout change events
|
|
52
|
+
this.#eventBus.subscribe('widget:dropped', this.#onLayoutChange.bind(this)), this.#eventBus.subscribe('widget:delete', this.#onLayoutChange.bind(this)),
|
|
53
|
+
// Responsive layout import events
|
|
54
|
+
this.#eventBus.subscribe('responsive:layoutimport', this.#onResponsiveLayoutImport.bind(this)));
|
|
55
|
+
}
|
|
56
|
+
#onLayoutChange(event) {
|
|
57
|
+
// Not our event
|
|
58
|
+
if (event.board !== this) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
// No point exporting if nobody is listening
|
|
62
|
+
if (!this.config?.onLayoutChange && !this.#responsiveController) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
// Debounce the callback
|
|
66
|
+
if (this.#layoutChangeTimeout) {
|
|
67
|
+
clearTimeout(this.#layoutChangeTimeout);
|
|
68
|
+
}
|
|
69
|
+
this.#layoutChangeTimeout = setTimeout(() => {
|
|
70
|
+
this.#layoutChangeTimeout = null;
|
|
71
|
+
const layout = this.#exportLayoutInternal();
|
|
72
|
+
// Emit event for responsive controller (and any other listeners)
|
|
73
|
+
this.#eventBus.dispatch('board:layoutchange', {
|
|
74
|
+
board: this,
|
|
75
|
+
layout,
|
|
76
|
+
breakpoint: this.breakpoint
|
|
77
|
+
});
|
|
78
|
+
// Also call local callback if provided
|
|
79
|
+
this.config?.onLayoutChange?.(layout);
|
|
80
|
+
}, this.#layoutChangeDebounceMs);
|
|
81
|
+
}
|
|
82
|
+
#onResponsiveLayoutImport(event) {
|
|
83
|
+
// Not our responsive controller
|
|
84
|
+
if (event.responsiveController !== this.#responsiveController) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
// Get the layout for our breakpoint and import it
|
|
88
|
+
if (this.breakpoint) {
|
|
89
|
+
const layout = this.#responsiveController?.getLayoutForBreakpoint(this.breakpoint);
|
|
90
|
+
if (layout) {
|
|
91
|
+
this.#importLayoutInternal(layout);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
26
94
|
}
|
|
27
95
|
style = $derived.by(() => {
|
|
96
|
+
const needsOverflowLock = this.#activeInterpolations > 0 || this.#currentWidgetAction;
|
|
97
|
+
const scrollbarPadding = this.#scrollbarCompensation > 0
|
|
98
|
+
? ` padding-right: ${this.#scrollbarCompensation}px;`
|
|
99
|
+
: '';
|
|
100
|
+
const overflow = needsOverflowLock
|
|
101
|
+
? ` overflow: hidden;${scrollbarPadding}`
|
|
102
|
+
: '';
|
|
28
103
|
if (!this.#currentWidgetAction) {
|
|
29
|
-
return
|
|
104
|
+
return `position: relative;${overflow}`;
|
|
30
105
|
}
|
|
31
|
-
return `position: relative
|
|
106
|
+
return `position: relative;${overflow} ${this.#getStyleForCurrentWidgetAction()}`;
|
|
32
107
|
});
|
|
33
108
|
#getStyleForCurrentWidgetAction() {
|
|
34
109
|
if (!this.#currentWidgetAction) {
|
|
@@ -41,6 +116,35 @@ export class InternalFlexiBoardController {
|
|
|
41
116
|
return `cursor: nwse-resize;`;
|
|
42
117
|
}
|
|
43
118
|
}
|
|
119
|
+
notifyInterpolationStarted() {
|
|
120
|
+
this.#captureScrollbarWidthIfNeeded();
|
|
121
|
+
this.#activeInterpolations++;
|
|
122
|
+
}
|
|
123
|
+
notifyInterpolationEnded() {
|
|
124
|
+
this.#activeInterpolations = Math.max(0, this.#activeInterpolations - 1);
|
|
125
|
+
this.#scheduleScrollbarCompensationRelease();
|
|
126
|
+
}
|
|
127
|
+
#captureScrollbarWidthIfNeeded() {
|
|
128
|
+
if (this.#hasScrollbarCompensation) {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
if (this.ref) {
|
|
132
|
+
const scrollbarWidth = this.ref.offsetWidth - this.ref.clientWidth;
|
|
133
|
+
if (scrollbarWidth > 0) {
|
|
134
|
+
const existingPadding = parseFloat(getComputedStyle(this.ref).paddingRight) || 0;
|
|
135
|
+
this.#scrollbarCompensation = existingPadding + scrollbarWidth;
|
|
136
|
+
}
|
|
137
|
+
this.#hasScrollbarCompensation = true;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
#scheduleScrollbarCompensationRelease() {
|
|
141
|
+
queueMicrotask(() => {
|
|
142
|
+
if (this.#activeInterpolations === 0 && !this.#currentWidgetAction) {
|
|
143
|
+
this.#scrollbarCompensation = 0;
|
|
144
|
+
this.#hasScrollbarCompensation = false;
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
}
|
|
44
148
|
get ref() {
|
|
45
149
|
return this.#ref.value;
|
|
46
150
|
}
|
|
@@ -102,6 +206,7 @@ export class InternalFlexiBoardController {
|
|
|
102
206
|
if (this.#currentWidgetAction || event.board !== this) {
|
|
103
207
|
return;
|
|
104
208
|
}
|
|
209
|
+
this.#captureScrollbarWidthIfNeeded();
|
|
105
210
|
if (event.clientX !== undefined && event.clientY !== undefined) {
|
|
106
211
|
this.#pointerService.updatePosition(event.clientX, event.clientY);
|
|
107
212
|
}
|
|
@@ -121,6 +226,7 @@ export class InternalFlexiBoardController {
|
|
|
121
226
|
if (this.#currentWidgetAction || event.board !== this) {
|
|
122
227
|
return;
|
|
123
228
|
}
|
|
229
|
+
this.#captureScrollbarWidthIfNeeded();
|
|
124
230
|
this.#currentWidgetAction = {
|
|
125
231
|
action: 'resize',
|
|
126
232
|
widget: event.widget,
|
|
@@ -160,6 +266,8 @@ export class InternalFlexiBoardController {
|
|
|
160
266
|
}
|
|
161
267
|
this.#unlockViewport();
|
|
162
268
|
const currentAction = this.#currentWidgetAction;
|
|
269
|
+
// Capture source target before any handlers might change widget.internalTarget
|
|
270
|
+
const sourceTarget = currentAction.widget.internalTarget;
|
|
163
271
|
switch (currentAction.action) {
|
|
164
272
|
case 'grab':
|
|
165
273
|
this.#handleGrabbedWidgetRelease(currentAction);
|
|
@@ -168,10 +276,34 @@ export class InternalFlexiBoardController {
|
|
|
168
276
|
this.#handleResizingWidgetRelease(currentAction);
|
|
169
277
|
break;
|
|
170
278
|
}
|
|
279
|
+
// Safety net: After all synchronous handlers complete, check if the source target
|
|
280
|
+
// still has a pre-grab snapshot (meaning the drop didn't happen). If so, restore it.
|
|
281
|
+
// This handles the case where the widget was released outside of all targets.
|
|
282
|
+
queueMicrotask(() => {
|
|
283
|
+
if (sourceTarget?.hasPreGrabSnapshot()) {
|
|
284
|
+
sourceTarget.restorePreGrabSnapshot();
|
|
285
|
+
sourceTarget.applyGridPostCompletionOperations();
|
|
286
|
+
}
|
|
287
|
+
});
|
|
171
288
|
}
|
|
172
289
|
handleWidgetCancel(event) {
|
|
290
|
+
// Not our event.
|
|
291
|
+
if (event.board !== this) {
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
173
294
|
this.#unlockViewport();
|
|
295
|
+
// Capture source target before releasing the action
|
|
296
|
+
const sourceTarget = this.#currentWidgetAction?.widget.internalTarget;
|
|
174
297
|
this.#releaseCurrentWidgetAction();
|
|
298
|
+
// Safety net: After all synchronous handlers complete, check if the source target
|
|
299
|
+
// still has a pre-grab snapshot. If so, restore it.
|
|
300
|
+
// This handles the case where the widget was cancelled while outside of all targets.
|
|
301
|
+
queueMicrotask(() => {
|
|
302
|
+
if (sourceTarget?.hasPreGrabSnapshot()) {
|
|
303
|
+
sourceTarget.restorePreGrabSnapshot();
|
|
304
|
+
sourceTarget.applyGridPostCompletionOperations();
|
|
305
|
+
}
|
|
306
|
+
});
|
|
175
307
|
}
|
|
176
308
|
attachAnnouncer(announcer) {
|
|
177
309
|
this.#announcer = announcer;
|
|
@@ -183,30 +315,95 @@ export class InternalFlexiBoardController {
|
|
|
183
315
|
}
|
|
184
316
|
oninitialloadcomplete() {
|
|
185
317
|
this.#ready = true;
|
|
186
|
-
//
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
318
|
+
// Check for stored layout from early import attempt
|
|
319
|
+
if (this.#storedLoadLayout) {
|
|
320
|
+
this.#importLayoutInternal(this.#storedLoadLayout);
|
|
321
|
+
this.#storedLoadLayout = undefined;
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
// If in responsive context, load from responsive controller
|
|
325
|
+
if (this.#responsiveController && this.breakpoint) {
|
|
326
|
+
const layout = this.#responsiveController.getLayoutForBreakpoint(this.breakpoint);
|
|
327
|
+
if (layout) {
|
|
328
|
+
this.#importLayoutInternal(layout);
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
// Fall through to loadLayout callback if no stored layout for this breakpoint
|
|
332
|
+
}
|
|
333
|
+
// Check for loadLayout in config (for non-responsive boards OR first-time breakpoint)
|
|
334
|
+
const loadLayoutFn = this.config?.loadLayout;
|
|
335
|
+
if (loadLayoutFn) {
|
|
336
|
+
const layout = loadLayoutFn();
|
|
337
|
+
if (layout) {
|
|
338
|
+
this.#importLayoutInternal(this.#normalizeLayout(layout));
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Imports a layout into this board.
|
|
344
|
+
*
|
|
345
|
+
* **Note**: If this board is under a ResponsiveFlexiBoard, prefer using
|
|
346
|
+
* `responsiveBoard.importLayout()` to import layouts for all breakpoints.
|
|
347
|
+
*/
|
|
348
|
+
importLayout(layout) {
|
|
349
|
+
if (this.#responsiveController) {
|
|
350
|
+
console.warn('importLayout() called directly on a FlexiBoard under ResponsiveFlexiBoard. ' +
|
|
351
|
+
'Use responsiveBoard.importLayout() instead to import layouts for all breakpoints.');
|
|
352
|
+
}
|
|
353
|
+
this.#importLayoutInternal(layout);
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* Internal implementation of importLayout - no warning, used by responsive controller.
|
|
357
|
+
*/
|
|
358
|
+
#importLayoutInternal(layout) {
|
|
359
|
+
// The board isn't ready to import widgets yet, so we'll store the layout and import it later.
|
|
360
|
+
if (!this.#ready) {
|
|
361
|
+
this.#storedLoadLayout = layout;
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
// Good to go - import the widgets into their respective targets.
|
|
365
|
+
this.#targets.forEach(target => {
|
|
366
|
+
const targetLayout = layout[target.key];
|
|
367
|
+
if (targetLayout) {
|
|
368
|
+
target.importLayout(targetLayout);
|
|
369
|
+
}
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
#normalizeLayout(layout) {
|
|
373
|
+
// If it's an array, assume single target (first one)
|
|
374
|
+
if (Array.isArray(layout)) {
|
|
375
|
+
const firstTargetKey = this.#targets.keys().next().value;
|
|
376
|
+
if (firstTargetKey) {
|
|
377
|
+
return { [firstTargetKey]: layout };
|
|
378
|
+
}
|
|
379
|
+
return {};
|
|
380
|
+
}
|
|
381
|
+
return layout;
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Exports the current layout from this board.
|
|
385
|
+
*
|
|
386
|
+
* **Note**: If this board is under a ResponsiveFlexiBoard, prefer using
|
|
387
|
+
* `responsiveBoard.exportLayout()` to export layouts for all breakpoints.
|
|
388
|
+
*/
|
|
389
|
+
exportLayout() {
|
|
390
|
+
if (this.#responsiveController) {
|
|
391
|
+
console.warn('exportLayout() called directly on a FlexiBoard under ResponsiveFlexiBoard. ' +
|
|
392
|
+
'Use responsiveBoard.exportLayout() instead to export layouts for all breakpoints.');
|
|
393
|
+
}
|
|
394
|
+
return this.#exportLayoutInternal();
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* Internal implementation of exportLayout - no warning, used internally.
|
|
398
|
+
*/
|
|
399
|
+
#exportLayoutInternal() {
|
|
400
|
+
const result = {};
|
|
401
|
+
// Grab the current layout of each target.
|
|
402
|
+
this.#targets.forEach(target => {
|
|
403
|
+
result[target.key] = target.exportLayout();
|
|
404
|
+
});
|
|
405
|
+
return result;
|
|
406
|
+
}
|
|
210
407
|
#handleGrabbedWidgetRelease(action) {
|
|
211
408
|
// If a deleter is hovered, then we'll delete the widget.
|
|
212
409
|
if (this.#hoveredOverDeleter) {
|
|
@@ -230,6 +427,7 @@ export class InternalFlexiBoardController {
|
|
|
230
427
|
}
|
|
231
428
|
this.announce(`You have released the widget.`);
|
|
232
429
|
this.#currentWidgetAction = null;
|
|
430
|
+
this.#scheduleScrollbarCompensationRelease();
|
|
233
431
|
}
|
|
234
432
|
/**
|
|
235
433
|
* Moves a widget from one target to another.
|
|
@@ -258,6 +456,12 @@ export class InternalFlexiBoardController {
|
|
|
258
456
|
get currentWidgetAction() {
|
|
259
457
|
return this.#currentWidgetAction;
|
|
260
458
|
}
|
|
459
|
+
/**
|
|
460
|
+
* Returns the parent responsive controller if this board is within a ResponsiveFlexiBoard.
|
|
461
|
+
*/
|
|
462
|
+
get responsiveController() {
|
|
463
|
+
return this.#responsiveController;
|
|
464
|
+
}
|
|
261
465
|
/**
|
|
262
466
|
* Cleanup method to be called when the board is destroyed
|
|
263
467
|
*/
|
|
@@ -268,5 +472,10 @@ export class InternalFlexiBoardController {
|
|
|
268
472
|
// Clean up event subscriptions
|
|
269
473
|
this.#unsubscribers.forEach((unsubscribe) => unsubscribe());
|
|
270
474
|
this.#unsubscribers = [];
|
|
475
|
+
// Clean up any pending layout change timeout
|
|
476
|
+
if (this.#layoutChangeTimeout) {
|
|
477
|
+
clearTimeout(this.#layoutChangeTimeout);
|
|
478
|
+
this.#layoutChangeTimeout = null;
|
|
479
|
+
}
|
|
271
480
|
}
|
|
272
481
|
}
|
|
@@ -1,6 +1,32 @@
|
|
|
1
1
|
import type { FlexiTargetDefaults } from '../target/types.js';
|
|
2
2
|
import type { FlexiWidgetDefaults } from '../widget/types.js';
|
|
3
|
+
export type FlexiLayoutChangeFn = (layout: FlexiLayout) => void;
|
|
3
4
|
export type FlexiBoardConfiguration = {
|
|
4
5
|
widgetDefaults?: FlexiWidgetDefaults;
|
|
5
6
|
targetDefaults?: FlexiTargetDefaults;
|
|
7
|
+
/**
|
|
8
|
+
* Optional breakpoint override.
|
|
9
|
+
*
|
|
10
|
+
* When this board is inside a ResponsiveFlexiBoard, the breakpoint is automatically
|
|
11
|
+
* inferred from the responsive controller's `currentBreakpoint`. You typically don't
|
|
12
|
+
* need to set this manually.
|
|
13
|
+
*
|
|
14
|
+
* If set outside of a ResponsiveFlexiBoard context, a warning will be logged.
|
|
15
|
+
*/
|
|
16
|
+
breakpoint?: string;
|
|
17
|
+
registry?: Record<string, FlexiRegistryEntry>;
|
|
18
|
+
loadLayout?: FlexiLoadLayoutFn;
|
|
19
|
+
onLayoutChange?: FlexiLayoutChangeFn;
|
|
6
20
|
};
|
|
21
|
+
export type FlexiRegistryEntry = Omit<FlexiWidgetDefaults, 'width' | 'height' | 'draggable'>;
|
|
22
|
+
export type FlexiWidgetLayoutEntry = {
|
|
23
|
+
id?: string;
|
|
24
|
+
type: string;
|
|
25
|
+
x: number;
|
|
26
|
+
y: number;
|
|
27
|
+
width: number;
|
|
28
|
+
height: number;
|
|
29
|
+
metadata?: Record<string, any>;
|
|
30
|
+
};
|
|
31
|
+
export type FlexiLayout = Record<string, FlexiWidgetLayoutEntry[]>;
|
|
32
|
+
export type FlexiLoadLayoutFn = () => FlexiLayout | FlexiWidgetLayoutEntry[] | undefined;
|
|
@@ -28,6 +28,15 @@ export declare abstract class FlexiGrid {
|
|
|
28
28
|
* Apply any post-completion operations like row/column collapsing.
|
|
29
29
|
*/
|
|
30
30
|
applyPostCompletionOperations(): void;
|
|
31
|
+
/**
|
|
32
|
+
* Stores a drag snapshot so that mapRawCellToFinalCell can map cursor positions
|
|
33
|
+
* through the snapshot's widget positions instead of the live (displaced) grid.
|
|
34
|
+
*/
|
|
35
|
+
setDragSnapshot(snapshot: unknown): void;
|
|
36
|
+
/**
|
|
37
|
+
* Clears the stored drag snapshot.
|
|
38
|
+
*/
|
|
39
|
+
clearDragSnapshot(): void;
|
|
31
40
|
_target: InternalFlexiTargetController;
|
|
32
41
|
_targetConfig: FlexiTargetConfiguration;
|
|
33
42
|
mouseCellPosition: {
|
|
@@ -8,6 +8,15 @@ export class FlexiGrid {
|
|
|
8
8
|
* Apply any post-completion operations like row/column collapsing.
|
|
9
9
|
*/
|
|
10
10
|
applyPostCompletionOperations() { }
|
|
11
|
+
/**
|
|
12
|
+
* Stores a drag snapshot so that mapRawCellToFinalCell can map cursor positions
|
|
13
|
+
* through the snapshot's widget positions instead of the live (displaced) grid.
|
|
14
|
+
*/
|
|
15
|
+
setDragSnapshot(snapshot) { }
|
|
16
|
+
/**
|
|
17
|
+
* Clears the stored drag snapshot.
|
|
18
|
+
*/
|
|
19
|
+
clearDragSnapshot() { }
|
|
11
20
|
_target;
|
|
12
21
|
_targetConfig;
|
|
13
22
|
mouseCellPosition = $state({
|
|
@@ -53,7 +62,9 @@ export class FlexiGrid {
|
|
|
53
62
|
this.mouseCellPosition.y = cell?.row ?? 0;
|
|
54
63
|
this._target.onmousegridcellmove({
|
|
55
64
|
cellX: this.mouseCellPosition.x,
|
|
56
|
-
cellY: this.mouseCellPosition.y
|
|
65
|
+
cellY: this.mouseCellPosition.y,
|
|
66
|
+
rawCellX: rawCell?.column ?? 0,
|
|
67
|
+
rawCellY: rawCell?.row ?? 0
|
|
57
68
|
});
|
|
58
69
|
}
|
|
59
70
|
watchGridElementDimensions() {
|