@design.estate/dees-catalog 3.94.0 → 3.95.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_bundle/bundle.js +1711 -779
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/dist_ts_web/elements/00group-layout/dees-mosaic/dees-mosaic.d.ts +49 -0
- package/dist_ts_web/elements/00group-layout/dees-mosaic/dees-mosaic.demo.d.ts +1 -0
- package/dist_ts_web/elements/00group-layout/dees-mosaic/dees-mosaic.demo.js +82 -0
- package/dist_ts_web/elements/00group-layout/dees-mosaic/dees-mosaic.js +622 -0
- package/dist_ts_web/elements/00group-layout/dees-mosaic/index.d.ts +3 -0
- package/dist_ts_web/elements/00group-layout/dees-mosaic/index.js +4 -0
- package/dist_ts_web/elements/00group-layout/dees-mosaic/interaction.d.ts +37 -0
- package/dist_ts_web/elements/00group-layout/dees-mosaic/interaction.js +174 -0
- package/dist_ts_web/elements/00group-layout/dees-mosaic/tree.d.ts +33 -0
- package/dist_ts_web/elements/00group-layout/dees-mosaic/tree.js +199 -0
- package/dist_ts_web/elements/00group-layout/dees-mosaic/types.d.ts +52 -0
- package/dist_ts_web/elements/00group-layout/dees-mosaic/types.js +8 -0
- package/dist_ts_web/elements/00group-layout/index.d.ts +1 -0
- package/dist_ts_web/elements/00group-layout/index.js +2 -1
- package/dist_watch/bundle.js +1712 -780
- package/dist_watch/bundle.js.map +4 -4
- package/package.json +1 -1
- package/readme.md +28 -1
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/elements/00group-layout/dees-mosaic/dees-mosaic.demo.ts +87 -0
- package/ts_web/elements/00group-layout/dees-mosaic/dees-mosaic.ts +562 -0
- package/ts_web/elements/00group-layout/dees-mosaic/index.ts +3 -0
- package/ts_web/elements/00group-layout/dees-mosaic/interaction.ts +187 -0
- package/ts_web/elements/00group-layout/dees-mosaic/tree.ts +239 -0
- package/ts_web/elements/00group-layout/dees-mosaic/types.ts +63 -0
- package/ts_web/elements/00group-layout/index.ts +1 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Drag-and-dock gesture for dees-mosaic tilebars: pointer capture with a
|
|
3
|
+
* movement threshold, a fixed ghost chip, edge-quadrant drop targets with a
|
|
4
|
+
* live preview, and Escape/blur cancel. The commit path goes through the
|
|
5
|
+
* pure tree helpers; the component only re-renders from the host's next
|
|
6
|
+
* layout.
|
|
7
|
+
*/
|
|
8
|
+
import type { DeesMosaic } from './dees-mosaic.js';
|
|
9
|
+
import type { TMosaicDropEdge } from './types.js';
|
|
10
|
+
export interface IMosaicDropTarget {
|
|
11
|
+
leafId: string;
|
|
12
|
+
edge: TMosaicDropEdge;
|
|
13
|
+
previewRect: DOMRect;
|
|
14
|
+
}
|
|
15
|
+
export declare class MosaicDragController {
|
|
16
|
+
private host;
|
|
17
|
+
constructor(host: DeesMosaic);
|
|
18
|
+
private ghost;
|
|
19
|
+
private shield;
|
|
20
|
+
private keydownListener;
|
|
21
|
+
private blurListener;
|
|
22
|
+
private detachGesture;
|
|
23
|
+
private activeLeafId;
|
|
24
|
+
/**
|
|
25
|
+
* Cancels a gesture that is in flight, e.g. when the host element is
|
|
26
|
+
* disconnected mid-drag — the pointer will never deliver its up/lost
|
|
27
|
+
* events to a removed tilebar, so the window listeners must be detached
|
|
28
|
+
* deterministically here.
|
|
29
|
+
*/
|
|
30
|
+
cancelActiveGesture(): void;
|
|
31
|
+
handleTilebarPointerDown(event: PointerEvent, leafId: string, title: string): void;
|
|
32
|
+
private startDrag;
|
|
33
|
+
private updateDrag;
|
|
34
|
+
private resolveDropTarget;
|
|
35
|
+
private halfRect;
|
|
36
|
+
private finishDrag;
|
|
37
|
+
}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { mosaicMove } from './tree.js';
|
|
2
|
+
const dragThresholdPx = 4;
|
|
3
|
+
export class MosaicDragController {
|
|
4
|
+
host;
|
|
5
|
+
constructor(host) {
|
|
6
|
+
this.host = host;
|
|
7
|
+
}
|
|
8
|
+
ghost = null;
|
|
9
|
+
shield = null;
|
|
10
|
+
keydownListener = null;
|
|
11
|
+
blurListener = null;
|
|
12
|
+
detachGesture = null;
|
|
13
|
+
activeLeafId = null;
|
|
14
|
+
/**
|
|
15
|
+
* Cancels a gesture that is in flight, e.g. when the host element is
|
|
16
|
+
* disconnected mid-drag — the pointer will never deliver its up/lost
|
|
17
|
+
* events to a removed tilebar, so the window listeners must be detached
|
|
18
|
+
* deterministically here.
|
|
19
|
+
*/
|
|
20
|
+
cancelActiveGesture() {
|
|
21
|
+
this.detachGesture?.();
|
|
22
|
+
if (this.ghost && this.activeLeafId !== null) {
|
|
23
|
+
this.finishDrag(this.activeLeafId, false);
|
|
24
|
+
}
|
|
25
|
+
this.activeLeafId = null;
|
|
26
|
+
}
|
|
27
|
+
handleTilebarPointerDown(event, leafId, title) {
|
|
28
|
+
if (!this.host.dragEnabled || event.button !== 0)
|
|
29
|
+
return;
|
|
30
|
+
if (this.detachGesture)
|
|
31
|
+
return; // one gesture at a time (multi-touch guard)
|
|
32
|
+
const tilebar = event.currentTarget;
|
|
33
|
+
const pointerId = event.pointerId;
|
|
34
|
+
const startX = event.clientX;
|
|
35
|
+
const startY = event.clientY;
|
|
36
|
+
let started = false;
|
|
37
|
+
const onMove = (moveEvent) => {
|
|
38
|
+
if (!started) {
|
|
39
|
+
if (Math.hypot(moveEvent.clientX - startX, moveEvent.clientY - startY) < dragThresholdPx)
|
|
40
|
+
return;
|
|
41
|
+
started = true;
|
|
42
|
+
this.startDrag(tilebar, leafId, title);
|
|
43
|
+
}
|
|
44
|
+
this.updateDrag(moveEvent, leafId);
|
|
45
|
+
};
|
|
46
|
+
const cleanup = () => {
|
|
47
|
+
this.detachGesture = null;
|
|
48
|
+
tilebar.removeEventListener('pointermove', onMove);
|
|
49
|
+
tilebar.removeEventListener('pointerup', onUp);
|
|
50
|
+
tilebar.removeEventListener('lostpointercapture', onLost);
|
|
51
|
+
try {
|
|
52
|
+
tilebar.releasePointerCapture(pointerId);
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
// not captured (synthetic pointer or already released)
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
const onUp = () => {
|
|
59
|
+
cleanup();
|
|
60
|
+
if (started)
|
|
61
|
+
this.finishDrag(leafId, true);
|
|
62
|
+
};
|
|
63
|
+
const onLost = () => {
|
|
64
|
+
cleanup();
|
|
65
|
+
if (started)
|
|
66
|
+
this.finishDrag(leafId, false);
|
|
67
|
+
};
|
|
68
|
+
try {
|
|
69
|
+
tilebar.setPointerCapture(pointerId);
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
// synthetic pointers (tests) cannot be captured; listeners work anyway
|
|
73
|
+
}
|
|
74
|
+
this.detachGesture = cleanup;
|
|
75
|
+
this.activeLeafId = leafId;
|
|
76
|
+
tilebar.addEventListener('pointermove', onMove);
|
|
77
|
+
tilebar.addEventListener('pointerup', onUp);
|
|
78
|
+
tilebar.addEventListener('lostpointercapture', onLost);
|
|
79
|
+
}
|
|
80
|
+
startDrag(tilebar, leafId, title) {
|
|
81
|
+
tilebar.classList.add('dragging');
|
|
82
|
+
const root = this.host.shadowRoot.querySelector('.rootBox');
|
|
83
|
+
this.shield = document.createElement('div');
|
|
84
|
+
this.shield.className = 'dragShield';
|
|
85
|
+
root.appendChild(this.shield);
|
|
86
|
+
this.ghost = document.createElement('div');
|
|
87
|
+
this.ghost.className = 'dragGhost';
|
|
88
|
+
this.ghost.textContent = title;
|
|
89
|
+
root.appendChild(this.ghost);
|
|
90
|
+
this.keydownListener = (event) => {
|
|
91
|
+
if (event.key === 'Escape') {
|
|
92
|
+
event.preventDefault();
|
|
93
|
+
this.finishDrag(leafId, false);
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
this.blurListener = () => this.finishDrag(leafId, false);
|
|
97
|
+
window.addEventListener('keydown', this.keydownListener, true);
|
|
98
|
+
window.addEventListener('blur', this.blurListener);
|
|
99
|
+
this.host.dispatchEvent(new CustomEvent('mosaic-drag-state', {
|
|
100
|
+
detail: { dragging: true, leafId },
|
|
101
|
+
bubbles: true,
|
|
102
|
+
composed: true,
|
|
103
|
+
}));
|
|
104
|
+
}
|
|
105
|
+
updateDrag(event, draggedLeafId) {
|
|
106
|
+
if (this.ghost) {
|
|
107
|
+
this.ghost.style.left = `${event.clientX}px`;
|
|
108
|
+
this.ghost.style.top = `${event.clientY}px`;
|
|
109
|
+
}
|
|
110
|
+
this.host.dropTarget = this.resolveDropTarget(event.clientX, event.clientY, draggedLeafId);
|
|
111
|
+
}
|
|
112
|
+
resolveDropTarget(x, y, draggedLeafId) {
|
|
113
|
+
const rects = this.host.getLeafRects();
|
|
114
|
+
for (const [leafId, rect] of Object.entries(rects)) {
|
|
115
|
+
if (leafId === draggedLeafId)
|
|
116
|
+
continue;
|
|
117
|
+
if (x < rect.left || x > rect.right || y < rect.top || y > rect.bottom)
|
|
118
|
+
continue;
|
|
119
|
+
const distances = [
|
|
120
|
+
['left', x - rect.left],
|
|
121
|
+
['right', rect.right - x],
|
|
122
|
+
['top', y - rect.top],
|
|
123
|
+
['bottom', rect.bottom - y],
|
|
124
|
+
];
|
|
125
|
+
distances.sort((a, b) => a[1] - b[1]);
|
|
126
|
+
const edge = distances[0][0];
|
|
127
|
+
const previewRect = this.halfRect(rect, edge);
|
|
128
|
+
return { leafId, edge, previewRect };
|
|
129
|
+
}
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
halfRect(rect, edge) {
|
|
133
|
+
if (edge === 'left')
|
|
134
|
+
return new DOMRect(rect.left, rect.top, rect.width / 2, rect.height);
|
|
135
|
+
if (edge === 'right')
|
|
136
|
+
return new DOMRect(rect.left + rect.width / 2, rect.top, rect.width / 2, rect.height);
|
|
137
|
+
if (edge === 'top')
|
|
138
|
+
return new DOMRect(rect.left, rect.top, rect.width, rect.height / 2);
|
|
139
|
+
return new DOMRect(rect.left, rect.top + rect.height / 2, rect.width, rect.height / 2);
|
|
140
|
+
}
|
|
141
|
+
finishDrag(leafId, commit) {
|
|
142
|
+
// cancel paths (Escape/blur) arrive outside the pointer handlers: detach
|
|
143
|
+
// the gesture listeners so a held pointer can no longer revive or commit
|
|
144
|
+
// the cancelled drag on a later move/release
|
|
145
|
+
this.detachGesture?.();
|
|
146
|
+
this.activeLeafId = null;
|
|
147
|
+
const target = this.host.dropTarget;
|
|
148
|
+
this.host.dropTarget = null;
|
|
149
|
+
for (const tilebar of this.host.shadowRoot?.querySelectorAll('.tilebar.dragging') ?? []) {
|
|
150
|
+
tilebar.classList.remove('dragging');
|
|
151
|
+
}
|
|
152
|
+
this.ghost?.remove();
|
|
153
|
+
this.ghost = null;
|
|
154
|
+
this.shield?.remove();
|
|
155
|
+
this.shield = null;
|
|
156
|
+
if (this.keydownListener) {
|
|
157
|
+
window.removeEventListener('keydown', this.keydownListener, true);
|
|
158
|
+
this.keydownListener = null;
|
|
159
|
+
}
|
|
160
|
+
if (this.blurListener) {
|
|
161
|
+
window.removeEventListener('blur', this.blurListener);
|
|
162
|
+
this.blurListener = null;
|
|
163
|
+
}
|
|
164
|
+
this.host.dispatchEvent(new CustomEvent('mosaic-drag-state', {
|
|
165
|
+
detail: { dragging: false, leafId },
|
|
166
|
+
bubbles: true,
|
|
167
|
+
composed: true,
|
|
168
|
+
}));
|
|
169
|
+
if (commit && target) {
|
|
170
|
+
this.host.commitLayout(mosaicMove(this.host.layout, leafId, target.leafId, target.edge), 'drop');
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW50ZXJhY3Rpb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi90c193ZWIvZWxlbWVudHMvMDBncm91cC1sYXlvdXQvZGVlcy1tb3NhaWMvaW50ZXJhY3Rpb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBU0EsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLFdBQVcsQ0FBQztBQVF2QyxNQUFNLGVBQWUsR0FBRyxDQUFDLENBQUM7QUFFMUIsTUFBTSxPQUFPLG9CQUFvQjtJQUNYO0lBQXBCLFlBQW9CLElBQWdCO1FBQWhCLFNBQUksR0FBSixJQUFJLENBQVk7SUFBRyxDQUFDO0lBRWhDLEtBQUssR0FBdUIsSUFBSSxDQUFDO0lBQ2pDLE1BQU0sR0FBdUIsSUFBSSxDQUFDO0lBQ2xDLGVBQWUsR0FBNEMsSUFBSSxDQUFDO0lBQ2hFLFlBQVksR0FBd0IsSUFBSSxDQUFDO0lBQ3pDLGFBQWEsR0FBd0IsSUFBSSxDQUFDO0lBQzFDLFlBQVksR0FBa0IsSUFBSSxDQUFDO0lBRTNDOzs7OztPQUtHO0lBQ0ksbUJBQW1CO1FBQ3hCLElBQUksQ0FBQyxhQUFhLEVBQUUsRUFBRSxDQUFDO1FBQ3ZCLElBQUksSUFBSSxDQUFDLEtBQUssSUFBSSxJQUFJLENBQUMsWUFBWSxLQUFLLElBQUksRUFBRSxDQUFDO1lBQzdDLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLFlBQVksRUFBRSxLQUFLLENBQUMsQ0FBQztRQUM1QyxDQUFDO1FBQ0QsSUFBSSxDQUFDLFlBQVksR0FBRyxJQUFJLENBQUM7SUFDM0IsQ0FBQztJQUVNLHdCQUF3QixDQUFDLEtBQW1CLEVBQUUsTUFBYyxFQUFFLEtBQWE7UUFDaEYsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsV0FBVyxJQUFJLEtBQUssQ0FBQyxNQUFNLEtBQUssQ0FBQztZQUFFLE9BQU87UUFDekQsSUFBSSxJQUFJLENBQUMsYUFBYTtZQUFFLE9BQU8sQ0FBQyw0Q0FBNEM7UUFDNUUsTUFBTSxPQUFPLEdBQUcsS0FBSyxDQUFDLGFBQTRCLENBQUM7UUFDbkQsTUFBTSxTQUFTLEdBQUcsS0FBSyxDQUFDLFNBQVMsQ0FBQztRQUNsQyxNQUFNLE1BQU0sR0FBRyxLQUFLLENBQUMsT0FBTyxDQUFDO1FBQzdCLE1BQU0sTUFBTSxHQUFHLEtBQUssQ0FBQyxPQUFPLENBQUM7UUFDN0IsSUFBSSxPQUFPLEdBQUcsS0FBSyxDQUFDO1FBRXBCLE1BQU0sTUFBTSxHQUFHLENBQUMsU0FBdUIsRUFBRSxFQUFFO1lBQ3pDLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQztnQkFDYixJQUFJLElBQUksQ0FBQyxLQUFLLENBQUMsU0FBUyxDQUFDLE9BQU8sR0FBRyxNQUFNLEVBQUUsU0FBUyxDQUFDLE9BQU8sR0FBRyxNQUFNLENBQUMsR0FBRyxlQUFlO29CQUFFLE9BQU87Z0JBQ2pHLE9BQU8sR0FBRyxJQUFJLENBQUM7Z0JBQ2YsSUFBSSxDQUFDLFNBQVMsQ0FBQyxPQUFPLEVBQUUsTUFBTSxFQUFFLEtBQUssQ0FBQyxDQUFDO1lBQ3pDLENBQUM7WUFDRCxJQUFJLENBQUMsVUFBVSxDQUFDLFNBQVMsRUFBRSxNQUFNLENBQUMsQ0FBQztRQUNyQyxDQUFDLENBQUM7UUFDRixNQUFNLE9BQU8sR0FBRyxHQUFHLEVBQUU7WUFDbkIsSUFBSSxDQUFDLGFBQWEsR0FBRyxJQUFJLENBQUM7WUFDMUIsT0FBTyxDQUFDLG1CQUFtQixDQUFDLGFBQWEsRUFBRSxNQUFNLENBQUMsQ0FBQztZQUNuRCxPQUFPLENBQUMsbUJBQW1CLENBQUMsV0FBVyxFQUFFLElBQUksQ0FBQyxDQUFDO1lBQy9DLE9BQU8sQ0FBQyxtQkFBbUIsQ0FBQyxvQkFBb0IsRUFBRSxNQUFNLENBQUMsQ0FBQztZQUMxRCxJQUFJLENBQUM7Z0JBQ0gsT0FBTyxDQUFDLHFCQUFxQixDQUFDLFNBQVMsQ0FBQyxDQUFDO1lBQzNDLENBQUM7WUFBQyxNQUFNLENBQUM7Z0JBQ1AsdURBQXVEO1lBQ3pELENBQUM7UUFDSCxDQUFDLENBQUM7UUFDRixNQUFNLElBQUksR0FBRyxHQUFHLEVBQUU7WUFDaEIsT0FBTyxFQUFFLENBQUM7WUFDVixJQUFJLE9BQU87Z0JBQUUsSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLENBQUM7UUFDN0MsQ0FBQyxDQUFDO1FBQ0YsTUFBTSxNQUFNLEdBQUcsR0FBRyxFQUFFO1lBQ2xCLE9BQU8sRUFBRSxDQUFDO1lBQ1YsSUFBSSxPQUFPO2dCQUFFLElBQUksQ0FBQyxVQUFVLENBQUMsTUFBTSxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBQzlDLENBQUMsQ0FBQztRQUNGLElBQUksQ0FBQztZQUNILE9BQU8sQ0FBQyxpQkFBaUIsQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUN2QyxDQUFDO1FBQUMsTUFBTSxDQUFDO1lBQ1AsdUVBQXVFO1FBQ3pFLENBQUM7UUFDRCxJQUFJLENBQUMsYUFBYSxHQUFHLE9BQU8sQ0FBQztRQUM3QixJQUFJLENBQUMsWUFBWSxHQUFHLE1BQU0sQ0FBQztRQUMzQixPQUFPLENBQUMsZ0JBQWdCLENBQUMsYUFBYSxFQUFFLE1BQU0sQ0FBQyxDQUFDO1FBQ2hELE9BQU8sQ0FBQyxnQkFBZ0IsQ0FBQyxXQUFXLEVBQUUsSUFBSSxDQUFDLENBQUM7UUFDNUMsT0FBTyxDQUFDLGdCQUFnQixDQUFDLG9CQUFvQixFQUFFLE1BQU0sQ0FBQyxDQUFDO0lBQ3pELENBQUM7SUFFTyxTQUFTLENBQUMsT0FBb0IsRUFBRSxNQUFjLEVBQUUsS0FBYTtRQUNuRSxPQUFPLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUNsQyxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLFVBQVcsQ0FBQyxhQUFhLENBQUMsVUFBVSxDQUFnQixDQUFDO1FBQzVFLElBQUksQ0FBQyxNQUFNLEdBQUcsUUFBUSxDQUFDLGFBQWEsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUM1QyxJQUFJLENBQUMsTUFBTSxDQUFDLFNBQVMsR0FBRyxZQUFZLENBQUM7UUFDckMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDOUIsSUFBSSxDQUFDLEtBQUssR0FBRyxRQUFRLENBQUMsYUFBYSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQzNDLElBQUksQ0FBQyxLQUFLLENBQUMsU0FBUyxHQUFHLFdBQVcsQ0FBQztRQUNuQyxJQUFJLENBQUMsS0FBSyxDQUFDLFdBQVcsR0FBRyxLQUFLLENBQUM7UUFDL0IsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDN0IsSUFBSSxDQUFDLGVBQWUsR0FBRyxDQUFDLEtBQW9CLEVBQUUsRUFBRTtZQUM5QyxJQUFJLEtBQUssQ0FBQyxHQUFHLEtBQUssUUFBUSxFQUFFLENBQUM7Z0JBQzNCLEtBQUssQ0FBQyxjQUFjLEVBQUUsQ0FBQztnQkFDdkIsSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLEVBQUUsS0FBSyxDQUFDLENBQUM7WUFDakMsQ0FBQztRQUNILENBQUMsQ0FBQztRQUNGLElBQUksQ0FBQyxZQUFZLEdBQUcsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDekQsTUFBTSxDQUFDLGdCQUFnQixDQUFDLFNBQVMsRUFBRSxJQUFJLENBQUMsZUFBZSxFQUFFLElBQUksQ0FBQyxDQUFDO1FBQy9ELE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLFlBQVksQ0FBQyxDQUFDO1FBQ25ELElBQUksQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLElBQUksV0FBVyxDQUFDLG1CQUFtQixFQUFFO1lBQzNELE1BQU0sRUFBRSxFQUFFLFFBQVEsRUFBRSxJQUFJLEVBQUUsTUFBTSxFQUFFO1lBQ2xDLE9BQU8sRUFBRSxJQUFJO1lBQ2IsUUFBUSxFQUFFLElBQUk7U0FDZixDQUFDLENBQUMsQ0FBQztJQUNOLENBQUM7SUFFTyxVQUFVLENBQUMsS0FBbUIsRUFBRSxhQUFxQjtRQUMzRCxJQUFJLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQztZQUNmLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLElBQUksR0FBRyxHQUFHLEtBQUssQ0FBQyxPQUFPLElBQUksQ0FBQztZQUM3QyxJQUFJLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxHQUFHLEdBQUcsR0FBRyxLQUFLLENBQUMsT0FBTyxJQUFJLENBQUM7UUFDOUMsQ0FBQztRQUNELElBQUksQ0FBQyxJQUFJLENBQUMsVUFBVSxHQUFHLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxLQUFLLENBQUMsT0FBTyxFQUFFLEtBQUssQ0FBQyxPQUFPLEVBQUUsYUFBYSxDQUFDLENBQUM7SUFDN0YsQ0FBQztJQUVPLGlCQUFpQixDQUFDLENBQVMsRUFBRSxDQUFTLEVBQUUsYUFBcUI7UUFDbkUsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQztRQUN2QyxLQUFLLE1BQU0sQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLElBQUksTUFBTSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQ25ELElBQUksTUFBTSxLQUFLLGFBQWE7Z0JBQUUsU0FBUztZQUN2QyxJQUFJLENBQUMsR0FBRyxJQUFJLENBQUMsSUFBSSxJQUFJLENBQUMsR0FBRyxJQUFJLENBQUMsS0FBSyxJQUFJLENBQUMsR0FBRyxJQUFJLENBQUMsR0FBRyxJQUFJLENBQUMsR0FBRyxJQUFJLENBQUMsTUFBTTtnQkFBRSxTQUFTO1lBQ2pGLE1BQU0sU0FBUyxHQUFxQztnQkFDbEQsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUM7Z0JBQ3ZCLENBQUMsT0FBTyxFQUFFLElBQUksQ0FBQyxLQUFLLEdBQUcsQ0FBQyxDQUFDO2dCQUN6QixDQUFDLEtBQUssRUFBRSxDQUFDLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQztnQkFDckIsQ0FBQyxRQUFRLEVBQUUsSUFBSSxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUM7YUFDNUIsQ0FBQztZQUNGLFNBQVMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDdEMsTUFBTSxJQUFJLEdBQUcsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQzdCLE1BQU0sV0FBVyxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxDQUFDO1lBQzlDLE9BQU8sRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFLFdBQVcsRUFBRSxDQUFDO1FBQ3ZDLENBQUM7UUFDRCxPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFFTyxRQUFRLENBQUMsSUFBYSxFQUFFLElBQXFCO1FBQ25ELElBQUksSUFBSSxLQUFLLE1BQU07WUFBRSxPQUFPLElBQUksT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLEdBQUcsRUFBRSxJQUFJLENBQUMsS0FBSyxHQUFHLENBQUMsRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDMUYsSUFBSSxJQUFJLEtBQUssT0FBTztZQUFFLE9BQU8sSUFBSSxPQUFPLENBQUMsSUFBSSxDQUFDLElBQUksR0FBRyxJQUFJLENBQUMsS0FBSyxHQUFHLENBQUMsRUFBRSxJQUFJLENBQUMsR0FBRyxFQUFFLElBQUksQ0FBQyxLQUFLLEdBQUcsQ0FBQyxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUM1RyxJQUFJLElBQUksS0FBSyxLQUFLO1lBQUUsT0FBTyxJQUFJLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxHQUFHLEVBQUUsSUFBSSxDQUFDLEtBQUssRUFBRSxJQUFJLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDO1FBQ3pGLE9BQU8sSUFBSSxPQUFPLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsR0FBRyxHQUFHLElBQUksQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLElBQUksQ0FBQyxLQUFLLEVBQUUsSUFBSSxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQztJQUN6RixDQUFDO0lBRU8sVUFBVSxDQUFDLE1BQWMsRUFBRSxNQUFlO1FBQ2hELHlFQUF5RTtRQUN6RSx5RUFBeUU7UUFDekUsNkNBQTZDO1FBQzdDLElBQUksQ0FBQyxhQUFhLEVBQUUsRUFBRSxDQUFDO1FBQ3ZCLElBQUksQ0FBQyxZQUFZLEdBQUcsSUFBSSxDQUFDO1FBQ3pCLE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDO1FBQ3BDLElBQUksQ0FBQyxJQUFJLENBQUMsVUFBVSxHQUFHLElBQUksQ0FBQztRQUM1QixLQUFLLE1BQU0sT0FBTyxJQUFJLElBQUksQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFLGdCQUFnQixDQUFDLG1CQUFtQixDQUFDLElBQUksRUFBRSxFQUFFLENBQUM7WUFDeEYsT0FBTyxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUMsVUFBVSxDQUFDLENBQUM7UUFDdkMsQ0FBQztRQUNELElBQUksQ0FBQyxLQUFLLEVBQUUsTUFBTSxFQUFFLENBQUM7UUFDckIsSUFBSSxDQUFDLEtBQUssR0FBRyxJQUFJLENBQUM7UUFDbEIsSUFBSSxDQUFDLE1BQU0sRUFBRSxNQUFNLEVBQUUsQ0FBQztRQUN0QixJQUFJLENBQUMsTUFBTSxHQUFHLElBQUksQ0FBQztRQUNuQixJQUFJLElBQUksQ0FBQyxlQUFlLEVBQUUsQ0FBQztZQUN6QixNQUFNLENBQUMsbUJBQW1CLENBQUMsU0FBUyxFQUFFLElBQUksQ0FBQyxlQUFlLEVBQUUsSUFBSSxDQUFDLENBQUM7WUFDbEUsSUFBSSxDQUFDLGVBQWUsR0FBRyxJQUFJLENBQUM7UUFDOUIsQ0FBQztRQUNELElBQUksSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDO1lBQ3RCLE1BQU0sQ0FBQyxtQkFBbUIsQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLFlBQVksQ0FBQyxDQUFDO1lBQ3RELElBQUksQ0FBQyxZQUFZLEdBQUcsSUFBSSxDQUFDO1FBQzNCLENBQUM7UUFDRCxJQUFJLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLFdBQVcsQ0FBQyxtQkFBbUIsRUFBRTtZQUMzRCxNQUFNLEVBQUUsRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRTtZQUNuQyxPQUFPLEVBQUUsSUFBSTtZQUNiLFFBQVEsRUFBRSxJQUFJO1NBQ2YsQ0FBQyxDQUFDLENBQUM7UUFDSixJQUFJLE1BQU0sSUFBSSxNQUFNLEVBQUUsQ0FBQztZQUNyQixJQUFJLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FDcEIsVUFBVSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLE1BQU0sRUFBRSxNQUFNLENBQUMsTUFBTSxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsRUFDaEUsTUFBTSxDQUNQLENBQUM7UUFDSixDQUFDO0lBQ0gsQ0FBQztDQUNGIn0=
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure tree algebra for dees-mosaic layouts. No DOM access; unit-testable in
|
|
3
|
+
* node. Every mutation helper returns a NEW normalized layout; inputs are
|
|
4
|
+
* never mutated.
|
|
5
|
+
*
|
|
6
|
+
* Normalization invariants:
|
|
7
|
+
* - a split with a single child collapses to that child
|
|
8
|
+
* - nested splits with the same orientation merge into the parent
|
|
9
|
+
* - ratios.length === children.length, summing to 1, each held at or near
|
|
10
|
+
* the minimum share (single-pass redistribution may undershoot slightly)
|
|
11
|
+
* - an empty tree is { root: null }
|
|
12
|
+
*/
|
|
13
|
+
import type { IMosaicLayout, IMosaicLeafNode, TMosaicDropEdge } from './types.js';
|
|
14
|
+
export declare const createMosaicId: (prefix: string) => string;
|
|
15
|
+
export declare const createMosaicLeaf: (surface: string, id?: string) => IMosaicLeafNode;
|
|
16
|
+
export declare const mosaicNormalize: (layout: IMosaicLayout) => IMosaicLayout;
|
|
17
|
+
export declare const mosaicLeaves: (layout: IMosaicLayout) => IMosaicLeafNode[];
|
|
18
|
+
export declare const mosaicFindLeafBySurface: (layout: IMosaicLayout, surface: string) => IMosaicLeafNode | undefined;
|
|
19
|
+
export declare const mosaicFindLeaf: (layout: IMosaicLayout, leafId: string) => IMosaicLeafNode | undefined;
|
|
20
|
+
/** Removes a leaf; collapsing/merging is handled by normalization. */
|
|
21
|
+
export declare const mosaicRemove: (layout: IMosaicLayout, leafId: string) => IMosaicLayout;
|
|
22
|
+
/**
|
|
23
|
+
* Inserts a leaf next to targetLeafId on the given edge (splitting the target
|
|
24
|
+
* 50/50 along the edge's axis). targetLeafId null docks against the whole
|
|
25
|
+
* layout (or becomes the root of an empty one).
|
|
26
|
+
*/
|
|
27
|
+
export declare const mosaicInsert: (layout: IMosaicLayout, targetLeafId: string | null, edge: TMosaicDropEdge, leaf: IMosaicLeafNode) => IMosaicLayout;
|
|
28
|
+
/** Transfers ratio between two adjacent siblings of a split. */
|
|
29
|
+
export declare const mosaicResize: (layout: IMosaicLayout, splitId: string, dividerIndex: number, ratioDelta: number) => IMosaicLayout;
|
|
30
|
+
/** Equalizes the ratios of one split (or every split when splitId omitted). */
|
|
31
|
+
export declare const mosaicEqualize: (layout: IMosaicLayout, splitId?: string) => IMosaicLayout;
|
|
32
|
+
/** Moves an existing leaf next to another leaf (drag-and-dock commit). */
|
|
33
|
+
export declare const mosaicMove: (layout: IMosaicLayout, leafId: string, targetLeafId: string, edge: TMosaicDropEdge) => IMosaicLayout;
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
const minRatio = 0.05;
|
|
2
|
+
let idCounter = 0;
|
|
3
|
+
export const createMosaicId = (prefix) => {
|
|
4
|
+
idCounter += 1;
|
|
5
|
+
return `${prefix}-${Date.now().toString(36)}-${idCounter.toString(36)}`;
|
|
6
|
+
};
|
|
7
|
+
export const createMosaicLeaf = (surface, id) => ({
|
|
8
|
+
type: 'leaf',
|
|
9
|
+
id: id ?? createMosaicId('leaf'),
|
|
10
|
+
surface,
|
|
11
|
+
});
|
|
12
|
+
const cloneNode = (node) => {
|
|
13
|
+
if (node.type === 'leaf')
|
|
14
|
+
return { ...node };
|
|
15
|
+
return {
|
|
16
|
+
...node,
|
|
17
|
+
children: node.children.map(cloneNode),
|
|
18
|
+
ratios: [...node.ratios],
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
const normalizeRatios = (ratios, count) => {
|
|
22
|
+
let next = ratios.slice(0, count);
|
|
23
|
+
while (next.length < count)
|
|
24
|
+
next.push(1 / count);
|
|
25
|
+
next = next.map((ratio) => (Number.isFinite(ratio) && ratio > 0 ? ratio : 1 / count));
|
|
26
|
+
const sum = next.reduce((total, ratio) => total + ratio, 0);
|
|
27
|
+
next = next.map((ratio) => ratio / sum);
|
|
28
|
+
// clamp to the minimum share, re-distributing the deficit proportionally
|
|
29
|
+
const deficitIndices = next.map((ratio, index) => (ratio < minRatio ? index : -1)).filter((index) => index >= 0);
|
|
30
|
+
if (deficitIndices.length && deficitIndices.length < count) {
|
|
31
|
+
const deficit = deficitIndices.reduce((total, index) => total + (minRatio - next[index]), 0);
|
|
32
|
+
const donorSum = next.reduce((total, ratio, index) => (deficitIndices.includes(index) ? total : total + ratio), 0);
|
|
33
|
+
next = next.map((ratio, index) => {
|
|
34
|
+
if (deficitIndices.includes(index))
|
|
35
|
+
return minRatio;
|
|
36
|
+
return ratio - (deficit * ratio) / donorSum;
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
return next;
|
|
40
|
+
};
|
|
41
|
+
const normalizeNode = (node) => {
|
|
42
|
+
if (node.type === 'leaf')
|
|
43
|
+
return { ...node };
|
|
44
|
+
const flattenedChildren = [];
|
|
45
|
+
const flattenedRatios = [];
|
|
46
|
+
node.children.forEach((child, index) => {
|
|
47
|
+
const normalizedChild = normalizeNode(child);
|
|
48
|
+
if (!normalizedChild)
|
|
49
|
+
return;
|
|
50
|
+
const ratio = node.ratios[index] ?? 1 / node.children.length;
|
|
51
|
+
if (normalizedChild.type === 'split' && normalizedChild.orientation === node.orientation) {
|
|
52
|
+
// merge same-orientation splits: children inherit a share of the slot
|
|
53
|
+
normalizedChild.children.forEach((grandChild, grandIndex) => {
|
|
54
|
+
flattenedChildren.push(grandChild);
|
|
55
|
+
flattenedRatios.push(ratio * normalizedChild.ratios[grandIndex]);
|
|
56
|
+
});
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
flattenedChildren.push(normalizedChild);
|
|
60
|
+
flattenedRatios.push(ratio);
|
|
61
|
+
});
|
|
62
|
+
if (!flattenedChildren.length)
|
|
63
|
+
return null;
|
|
64
|
+
if (flattenedChildren.length === 1)
|
|
65
|
+
return flattenedChildren[0];
|
|
66
|
+
return {
|
|
67
|
+
type: 'split',
|
|
68
|
+
id: node.id,
|
|
69
|
+
orientation: node.orientation,
|
|
70
|
+
children: flattenedChildren,
|
|
71
|
+
ratios: normalizeRatios(flattenedRatios, flattenedChildren.length),
|
|
72
|
+
};
|
|
73
|
+
};
|
|
74
|
+
export const mosaicNormalize = (layout) => {
|
|
75
|
+
if (!layout.root)
|
|
76
|
+
return { root: null };
|
|
77
|
+
return { root: normalizeNode(cloneNode(layout.root)) };
|
|
78
|
+
};
|
|
79
|
+
export const mosaicLeaves = (layout) => {
|
|
80
|
+
const leaves = [];
|
|
81
|
+
const walk = (node) => {
|
|
82
|
+
if (!node)
|
|
83
|
+
return;
|
|
84
|
+
if (node.type === 'leaf') {
|
|
85
|
+
leaves.push(node);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
node.children.forEach(walk);
|
|
89
|
+
};
|
|
90
|
+
walk(layout.root);
|
|
91
|
+
return leaves;
|
|
92
|
+
};
|
|
93
|
+
export const mosaicFindLeafBySurface = (layout, surface) => mosaicLeaves(layout).find((leaf) => leaf.surface === surface);
|
|
94
|
+
export const mosaicFindLeaf = (layout, leafId) => mosaicLeaves(layout).find((leaf) => leaf.id === leafId);
|
|
95
|
+
/** Removes a leaf; collapsing/merging is handled by normalization. */
|
|
96
|
+
export const mosaicRemove = (layout, leafId) => {
|
|
97
|
+
const removeFrom = (node) => {
|
|
98
|
+
if (node.type === 'leaf')
|
|
99
|
+
return node.id === leafId ? null : node;
|
|
100
|
+
const children = [];
|
|
101
|
+
const ratios = [];
|
|
102
|
+
node.children.forEach((child, index) => {
|
|
103
|
+
const kept = removeFrom(child);
|
|
104
|
+
if (!kept)
|
|
105
|
+
return;
|
|
106
|
+
children.push(kept);
|
|
107
|
+
ratios.push(node.ratios[index]);
|
|
108
|
+
});
|
|
109
|
+
if (!children.length)
|
|
110
|
+
return null;
|
|
111
|
+
return { ...node, children, ratios };
|
|
112
|
+
};
|
|
113
|
+
if (!layout.root)
|
|
114
|
+
return { root: null };
|
|
115
|
+
const root = removeFrom(cloneNode(layout.root));
|
|
116
|
+
return mosaicNormalize({ root });
|
|
117
|
+
};
|
|
118
|
+
const edgeOrientation = (edge) => edge === 'left' || edge === 'right' ? 'row' : 'column';
|
|
119
|
+
const edgeBefore = (edge) => edge === 'left' || edge === 'top';
|
|
120
|
+
/**
|
|
121
|
+
* Inserts a leaf next to targetLeafId on the given edge (splitting the target
|
|
122
|
+
* 50/50 along the edge's axis). targetLeafId null docks against the whole
|
|
123
|
+
* layout (or becomes the root of an empty one).
|
|
124
|
+
*/
|
|
125
|
+
export const mosaicInsert = (layout, targetLeafId, edge, leaf) => {
|
|
126
|
+
if (!layout.root)
|
|
127
|
+
return { root: { ...leaf } };
|
|
128
|
+
const orientation = edgeOrientation(edge);
|
|
129
|
+
const before = edgeBefore(edge);
|
|
130
|
+
const wrap = (node) => ({
|
|
131
|
+
type: 'split',
|
|
132
|
+
id: createMosaicId('split'),
|
|
133
|
+
orientation,
|
|
134
|
+
children: before ? [{ ...leaf }, node] : [node, { ...leaf }],
|
|
135
|
+
ratios: [0.5, 0.5],
|
|
136
|
+
});
|
|
137
|
+
if (targetLeafId === null) {
|
|
138
|
+
return mosaicNormalize({ root: wrap(cloneNode(layout.root)) });
|
|
139
|
+
}
|
|
140
|
+
const insertInto = (node) => {
|
|
141
|
+
if (node.type === 'leaf') {
|
|
142
|
+
return node.id === targetLeafId ? wrap(node) : node;
|
|
143
|
+
}
|
|
144
|
+
return { ...node, children: node.children.map(insertInto) };
|
|
145
|
+
};
|
|
146
|
+
return mosaicNormalize({ root: insertInto(cloneNode(layout.root)) });
|
|
147
|
+
};
|
|
148
|
+
/** Transfers ratio between two adjacent siblings of a split. */
|
|
149
|
+
export const mosaicResize = (layout, splitId, dividerIndex, ratioDelta) => {
|
|
150
|
+
const apply = (node) => {
|
|
151
|
+
if (node.type === 'leaf')
|
|
152
|
+
return node;
|
|
153
|
+
if (node.id !== splitId) {
|
|
154
|
+
return { ...node, children: node.children.map(apply) };
|
|
155
|
+
}
|
|
156
|
+
const ratios = [...node.ratios];
|
|
157
|
+
const leftIndex = dividerIndex;
|
|
158
|
+
const rightIndex = dividerIndex + 1;
|
|
159
|
+
if (leftIndex < 0 || rightIndex >= ratios.length)
|
|
160
|
+
return node;
|
|
161
|
+
const pair = ratios[leftIndex] + ratios[rightIndex];
|
|
162
|
+
const nextLeft = Math.min(Math.max(ratios[leftIndex] + ratioDelta, minRatio), pair - minRatio);
|
|
163
|
+
ratios[leftIndex] = nextLeft;
|
|
164
|
+
ratios[rightIndex] = pair - nextLeft;
|
|
165
|
+
return { ...node, ratios };
|
|
166
|
+
};
|
|
167
|
+
if (!layout.root)
|
|
168
|
+
return { root: null };
|
|
169
|
+
return { root: apply(cloneNode(layout.root)) };
|
|
170
|
+
};
|
|
171
|
+
/** Equalizes the ratios of one split (or every split when splitId omitted). */
|
|
172
|
+
export const mosaicEqualize = (layout, splitId) => {
|
|
173
|
+
const apply = (node) => {
|
|
174
|
+
if (node.type === 'leaf')
|
|
175
|
+
return node;
|
|
176
|
+
const children = node.children.map(apply);
|
|
177
|
+
if (!splitId || node.id === splitId) {
|
|
178
|
+
return { ...node, children, ratios: children.map(() => 1 / children.length) };
|
|
179
|
+
}
|
|
180
|
+
return { ...node, children };
|
|
181
|
+
};
|
|
182
|
+
if (!layout.root)
|
|
183
|
+
return { root: null };
|
|
184
|
+
return { root: apply(cloneNode(layout.root)) };
|
|
185
|
+
};
|
|
186
|
+
/** Moves an existing leaf next to another leaf (drag-and-dock commit). */
|
|
187
|
+
export const mosaicMove = (layout, leafId, targetLeafId, edge) => {
|
|
188
|
+
if (leafId === targetLeafId)
|
|
189
|
+
return mosaicNormalize(layout);
|
|
190
|
+
const leaf = mosaicFindLeaf(layout, leafId);
|
|
191
|
+
if (!leaf)
|
|
192
|
+
return mosaicNormalize(layout);
|
|
193
|
+
const without = mosaicRemove(layout, leafId);
|
|
194
|
+
// the target may have been the leaf's only sibling — it still exists
|
|
195
|
+
if (!mosaicFindLeaf(without, targetLeafId))
|
|
196
|
+
return mosaicNormalize(layout);
|
|
197
|
+
return mosaicInsert(without, targetLeafId, edge, { ...leaf });
|
|
198
|
+
};
|
|
199
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJlZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3RzX3dlYi9lbGVtZW50cy8wMGdyb3VwLWxheW91dC9kZWVzLW1vc2FpYy90cmVlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQXFCQSxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUM7QUFFdEIsSUFBSSxTQUFTLEdBQUcsQ0FBQyxDQUFDO0FBRWxCLE1BQU0sQ0FBQyxNQUFNLGNBQWMsR0FBRyxDQUFDLE1BQWMsRUFBVSxFQUFFO0lBQ3ZELFNBQVMsSUFBSSxDQUFDLENBQUM7SUFDZixPQUFPLEdBQUcsTUFBTSxJQUFJLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDLElBQUksU0FBUyxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDO0FBQzFFLENBQUMsQ0FBQztBQUVGLE1BQU0sQ0FBQyxNQUFNLGdCQUFnQixHQUFHLENBQUMsT0FBZSxFQUFFLEVBQVcsRUFBbUIsRUFBRSxDQUFDLENBQUM7SUFDbEYsSUFBSSxFQUFFLE1BQU07SUFDWixFQUFFLEVBQUUsRUFBRSxJQUFJLGNBQWMsQ0FBQyxNQUFNLENBQUM7SUFDaEMsT0FBTztDQUNSLENBQUMsQ0FBQztBQUVILE1BQU0sU0FBUyxHQUFHLENBQUMsSUFBaUIsRUFBZSxFQUFFO0lBQ25ELElBQUksSUFBSSxDQUFDLElBQUksS0FBSyxNQUFNO1FBQUUsT0FBTyxFQUFFLEdBQUcsSUFBSSxFQUFFLENBQUM7SUFDN0MsT0FBTztRQUNMLEdBQUcsSUFBSTtRQUNQLFFBQVEsRUFBRSxJQUFJLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxTQUFTLENBQUM7UUFDdEMsTUFBTSxFQUFFLENBQUMsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDO0tBQ3pCLENBQUM7QUFDSixDQUFDLENBQUM7QUFFRixNQUFNLGVBQWUsR0FBRyxDQUFDLE1BQWdCLEVBQUUsS0FBYSxFQUFZLEVBQUU7SUFD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
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dees-mosaic — sway-like tiling layout model. A layout is a tree of split
|
|
3
|
+
* containers whose leaves reference host-defined surfaces. The component is
|
|
4
|
+
* controlled: hosts own the layout object and receive complete next layouts
|
|
5
|
+
* through events; the tree helpers in tree.ts are pure and DOM-free.
|
|
6
|
+
*/
|
|
7
|
+
export type TMosaicOrientation = 'row' | 'column';
|
|
8
|
+
export interface IMosaicLeafNode {
|
|
9
|
+
type: 'leaf';
|
|
10
|
+
/** stable node id — the slot contract is slot="tile-<id>" */
|
|
11
|
+
id: string;
|
|
12
|
+
/** host-defined surface key, e.g. 'chat' | 'theia' | 'browser' */
|
|
13
|
+
surface: string;
|
|
14
|
+
/** optional per-leaf override of the surface meta title */
|
|
15
|
+
title?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface IMosaicSplitNode {
|
|
18
|
+
type: 'split';
|
|
19
|
+
id: string;
|
|
20
|
+
orientation: TMosaicOrientation;
|
|
21
|
+
/** length >= 2 after normalization */
|
|
22
|
+
children: TMosaicNode[];
|
|
23
|
+
/** same length as children; each >= minimum share; sums to 1 */
|
|
24
|
+
ratios: number[];
|
|
25
|
+
}
|
|
26
|
+
export type TMosaicNode = IMosaicLeafNode | IMosaicSplitNode;
|
|
27
|
+
export interface IMosaicLayout {
|
|
28
|
+
/** null = empty workspace (the `empty` slot renders) */
|
|
29
|
+
root: TMosaicNode | null;
|
|
30
|
+
}
|
|
31
|
+
export interface IMosaicSurfaceMeta {
|
|
32
|
+
title: string;
|
|
33
|
+
/** dees-icon name, e.g. 'lucide:Globe' */
|
|
34
|
+
icon?: string;
|
|
35
|
+
/** default true */
|
|
36
|
+
closeable?: boolean;
|
|
37
|
+
}
|
|
38
|
+
export type TMosaicDropEdge = 'left' | 'right' | 'top' | 'bottom';
|
|
39
|
+
export type TMosaicLayoutChangeReason = 'resize' | 'drop' | 'close' | 'equalize';
|
|
40
|
+
export interface IMosaicLayoutChangeDetail {
|
|
41
|
+
/** the complete next layout — the host applies and persists it */
|
|
42
|
+
layout: IMosaicLayout;
|
|
43
|
+
reason: TMosaicLayoutChangeReason;
|
|
44
|
+
}
|
|
45
|
+
export interface IMosaicTileEventDetail {
|
|
46
|
+
leafId: string;
|
|
47
|
+
surface: string;
|
|
48
|
+
}
|
|
49
|
+
export interface IMosaicDragStateDetail {
|
|
50
|
+
dragging: boolean;
|
|
51
|
+
leafId?: string;
|
|
52
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dees-mosaic — sway-like tiling layout model. A layout is a tree of split
|
|
3
|
+
* containers whose leaves reference host-defined surfaces. The component is
|
|
4
|
+
* controlled: hosts own the layout object and receive complete next layouts
|
|
5
|
+
* through events; the tree helpers in tree.ts are pure and DOM-free.
|
|
6
|
+
*/
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi90c193ZWIvZWxlbWVudHMvMDBncm91cC1sYXlvdXQvZGVlcy1tb3NhaWMvdHlwZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7O0dBS0cifQ==
|
|
@@ -3,6 +3,7 @@ export * from './dees-dashboardgrid/index.js';
|
|
|
3
3
|
export * from './dees-heading/index.js';
|
|
4
4
|
export * from './dees-label/index.js';
|
|
5
5
|
export * from './dees-pagination/index.js';
|
|
6
|
+
export * from './dees-mosaic/index.js';
|
|
6
7
|
export * from './dees-panel/index.js';
|
|
7
8
|
export * from './dees-settings/index.js';
|
|
8
9
|
export * from './dees-sparklebox/index.js';
|
|
@@ -4,9 +4,10 @@ export * from './dees-dashboardgrid/index.js';
|
|
|
4
4
|
export * from './dees-heading/index.js';
|
|
5
5
|
export * from './dees-label/index.js';
|
|
6
6
|
export * from './dees-pagination/index.js';
|
|
7
|
+
export * from './dees-mosaic/index.js';
|
|
7
8
|
export * from './dees-panel/index.js';
|
|
8
9
|
export * from './dees-settings/index.js';
|
|
9
10
|
export * from './dees-sparklebox/index.js';
|
|
10
11
|
export * from './dees-stepper/index.js';
|
|
11
12
|
export * from './dees-tile/index.js';
|
|
12
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
13
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90c193ZWIvZWxlbWVudHMvMDBncm91cC1sYXlvdXQvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsb0JBQW9CO0FBQ3BCLGNBQWMsdUJBQXVCLENBQUM7QUFDdEMsY0FBYywrQkFBK0IsQ0FBQztBQUM5QyxjQUFjLHlCQUF5QixDQUFDO0FBQ3hDLGNBQWMsdUJBQXVCLENBQUM7QUFDdEMsY0FBYyw0QkFBNEIsQ0FBQztBQUMzQyxjQUFjLHdCQUF3QixDQUFDO0FBQ3ZDLGNBQWMsdUJBQXVCLENBQUM7QUFDdEMsY0FBYywwQkFBMEIsQ0FBQztBQUN6QyxjQUFjLDRCQUE0QixDQUFDO0FBQzNDLGNBQWMseUJBQXlCLENBQUM7QUFDeEMsY0FBYyxzQkFBc0IsQ0FBQyJ9
|