@design.estate/dees-catalog 3.94.0 → 3.96.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 +1744 -788
- 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_ts_web/services/DeesServiceLibLoader.d.ts +14 -13
- package/dist_ts_web/services/DeesServiceLibLoader.js +37 -12
- package/dist_watch/bundle.js +1745 -789
- 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
- package/ts_web/services/DeesServiceLibLoader.ts +42 -12
|
@@ -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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW50ZXJhY3Rpb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi90c193ZWIvZWxlbWVudHMvMDBncm91cC1sYXlvdXQvZGVlcy1tb3NhaWMvaW50ZXJhY3Rpb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBU0EsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLFdBQVcsQ0FBQztBQVF2QyxNQUFNLGVBQWUsR0FBRyxDQUFDLENBQUM7QUFFMUIsTUFBTSxPQUFPLG9CQUFvQjtJQUNYO0lBQXBCLFlBQW9CLElBQWdCO1FBQWhCLFNBQUksR0FBSixJQUFJLENBQVk7SUFBRyxDQUFDO0lBRWhDLEtBQUssR0FBdUIsSUFBSSxDQUFDO0lBQ2pDLE1BQU0sR0FBdUIsSUFBSSxDQUFDO0lBQ2xDLGVBQWUsR0FBNEMsSUFBSSxDQUFDO0lBQ2hFLFlBQVksR0FBd0IsSUFBSSxDQUFDO0lBQ3pDLGFBQWEsR0FBd0IsSUFBSSxDQUFDO0lBQzFDLFlBQVksR0FBa0IsSUFBSSxDQUFDO0lBRTNDOzs7OztPQUtHO0lBQ0ksbUJBQW1CO1FBQ3hCLElBQUksQ0FBQyxhQUFhLEVBQUUsRUFBRSxDQUFDO1FBQ3ZCLElBQUksSUFBSSxDQUFDLEtBQUssSUFBSSxJQUFJLENBQUMsWUFBWSxLQUFLLElBQUksRUFBRSxDQUFDO1lBQzdDLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLFlBQVksRUFBRSxLQUFLLENBQUMsQ0FBQztRQUM1QyxDQUFDO1FBQ0QsSUFBSSxDQUFDLFlBQVksR0FBRyxJQUFJLENBQUM7SUFDM0IsQ0FBQztJQUVNLHdCQUF3QixDQUFDLEtBQW1CLEVBQUUsTUFBYyxFQUFFLEtBQWE7UUFDaEYsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsV0FBVyxJQUFJLEtBQUssQ0FBQyxNQUFNLEtBQUssQ0FBQztZQUFFLE9BQU87UUFDekQsSUFBSSxJQUFJLENBQUMsYUFBYTtZQUFFLE9BQU8sQ0FBQyw0Q0FBNEM7UUFDNUUs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
|
|
@@ -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
|
|
@@ -111,19 +111,6 @@ export interface ITiptapBundle {
|
|
|
111
111
|
configure: (options?: any) => any;
|
|
112
112
|
};
|
|
113
113
|
}
|
|
114
|
-
/**
|
|
115
|
-
* Singleton service for lazy-loading heavy libraries from CDN.
|
|
116
|
-
*
|
|
117
|
-
* This reduces initial bundle size by loading libraries only when needed.
|
|
118
|
-
* Libraries are cached after first load to avoid duplicate fetches.
|
|
119
|
-
*
|
|
120
|
-
* @example
|
|
121
|
-
* ```typescript
|
|
122
|
-
* const libLoader = DeesServiceLibLoader.getInstance();
|
|
123
|
-
* const xterm = await libLoader.loadXterm();
|
|
124
|
-
* const terminal = new xterm.Terminal({ ... });
|
|
125
|
-
* ```
|
|
126
|
-
*/
|
|
127
114
|
export declare class DeesServiceLibLoader {
|
|
128
115
|
private static instance;
|
|
129
116
|
private xtermLib;
|
|
@@ -150,6 +137,20 @@ export declare class DeesServiceLibLoader {
|
|
|
150
137
|
* @returns Promise resolving to xterm module with Terminal class
|
|
151
138
|
*/
|
|
152
139
|
loadXterm(): Promise<IXtermBundle>;
|
|
140
|
+
/**
|
|
141
|
+
* Provides xterm modules from the host application instead of the CDN.
|
|
142
|
+
* Hosts that bundle xterm (e.g. Electron apps that must work offline)
|
|
143
|
+
* call this before any terminal component initializes; subsequent
|
|
144
|
+
* loadXterm/loadXtermFitAddon calls resolve from these caches without
|
|
145
|
+
* network access. Pass the css text of xterm.css so the document-level
|
|
146
|
+
* styles (normally fetched from the CDN) are injected too.
|
|
147
|
+
*/
|
|
148
|
+
provideXtermModules(input: {
|
|
149
|
+
xterm: IXtermBundle;
|
|
150
|
+
fitAddon?: IXtermFitAddonBundle;
|
|
151
|
+
cssText?: string;
|
|
152
|
+
}): void;
|
|
153
|
+
private injectProvidedXtermStyles;
|
|
153
154
|
/**
|
|
154
155
|
* Load xterm-addon-fit from CDN
|
|
155
156
|
* @returns Promise resolving to FitAddon class
|