@ixfx/components 0.15.5 → 0.16.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/bundle/index.d.ts +917 -44
- package/bundle/index.js +702 -696
- package/dist/crumb-navigation-BbqfmkYs.d.ts +147 -0
- package/dist/crumb-navigation-YnFVFqrx.js +1290 -0
- package/dist/crumbs.d.ts +2 -115
- package/dist/crumbs.js +1 -1179
- package/dist/{data-grid-D7qzmMMp.d.ts → data-grid-CIG2DVip.d.ts} +45 -3
- package/dist/{data-grid-C1sZX6n9.js → data-grid-rMkLX2qo.js} +593 -206
- package/dist/data-grid.d.ts +3 -3
- package/dist/data-grid.js +1 -1
- package/dist/{detail-list-CKIKlszv.d.ts → detail-list-6iMTNP4N.d.ts} +34 -4
- package/dist/{detail-list-q8bs67BM.js → detail-list-C4pDSoI8.js} +218 -7
- package/dist/detail-list.d.ts +4 -4
- package/dist/detail-list.js +1 -1
- package/dist/{flat-list-DXMyDiSH.d.ts → flat-list-JPgQSmLW.d.ts} +27 -4
- package/dist/flat-list.d.ts +2 -2
- package/dist/flat-list.js +123 -4
- package/dist/{grid-list-y6dWJYu3.js → grid-list-CdEkScn-.js} +276 -75
- package/dist/{grid-list-0e7snW6t.d.ts → grid-list-D6n7WH8l.d.ts} +128 -22
- package/dist/grid-list.d.ts +3 -3
- package/dist/grid-list.js +1 -1
- package/dist/incr-search.d.ts +1 -1
- package/dist/index-9ttcdwlL.d.ts +71 -0
- package/dist/{index-DEVyVIn8.d.ts → index-Bx0BXPxI.d.ts} +52 -6
- package/dist/index-CYRc6Dah.d.ts +475 -0
- package/dist/{index-KN2MW_xD.d.ts → index-Dr80Zdl6.d.ts} +1 -1
- package/dist/index.d.ts +334 -23
- package/dist/index.js +2247 -867
- package/dist/{list-native-drag-controller-O2Nruqpi.d.ts → list-native-drag-controller-D_UrXipS.d.ts} +1 -1
- package/dist/{list-selection-controller-BeE70lbB.js → list-selection-controller-5L0Nj9tR.js} +87 -2
- package/dist/miller-BFRfn0ve.js +2237 -0
- package/dist/miller.d.ts +4 -437
- package/dist/miller.js +1 -1815
- package/dist/pending-BGidHppL.js +91 -0
- package/dist/scroll-hover-guard-Cjw6179Q.js +35 -0
- package/dist/{split-layout-JK3xWVX2.d.ts → split-layout-CophkNeU.d.ts} +41 -3
- package/dist/{split-layout-Deoxy47d.js → split-layout-DTY4PJRp.js} +251 -19
- package/dist/split-layout.d.ts +1 -1
- package/dist/split-layout.js +1 -1
- package/dist/sunburst-tree.d.ts +2 -2
- package/dist/sunburst-tree.js +1 -1
- package/dist/{sunbursttree-list-yXwS-uEI.js → sunbursttree-list-B_VxOHlo.js} +298 -79
- package/dist/{sunbursttree-list--Z0uyh8O.d.ts → sunbursttree-list-D6j5BxVQ.d.ts} +40 -3
- package/dist/tree-CftHwtEb.js +146 -0
- package/dist/{tree-D8VxvR9u.js → tree-Crdpl4nc.js} +275 -47
- package/dist/{tree-component-C6UHO-w9.d.ts → tree-component-DgfkxmVY.d.ts} +19 -8
- package/dist/tree.d.ts +3 -3
- package/dist/tree.js +1 -1
- package/dist/types-LU1u0CB8.d.ts +87 -0
- package/dist/vertical-list-1V1Vg2O5.js +1993 -0
- package/dist/{vertical-list-D8MksoTp.d.ts → vertical-list-BPDmZx6T.d.ts} +31 -3
- package/dist/vertical-list.d.ts +3 -3
- package/dist/vertical-list.js +1 -1789
- package/dist/view-state-controller-BdyXWUUM.js +305 -0
- package/docs-user/README.md +2 -0
- package/docs-user/crumbs.md +27 -0
- package/docs-user/data-grid.md +66 -1
- package/docs-user/detail-list.md +54 -0
- package/docs-user/dock.md +54 -12
- package/docs-user/flat-list.md +27 -0
- package/docs-user/grid-list.md +64 -11
- package/docs-user/hyperbolic-tree.md +31 -4
- package/docs-user/icicle-tree.md +36 -0
- package/docs-user/index.json +12 -2
- package/docs-user/llms.txt +2 -0
- package/docs-user/miller.md +52 -21
- package/docs-user/multicol-list.md +50 -8
- package/docs-user/split-layout.md +45 -17
- package/docs-user/sunburst-tree.md +32 -2
- package/docs-user/tree.md +45 -6
- package/docs-user/treemap.md +32 -0
- package/docs-user/twosplit-layout.md +22 -0
- package/docs-user/user-catalog.md +1 -1
- package/docs-user/vertical-list.md +55 -7
- package/llms.txt +2 -0
- package/package.json +1 -1
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
//#region src/common/view-state/pending.ts
|
|
2
|
+
/**
|
|
3
|
+
* Pure helpers for *pending* view state: keyed intent that is waiting for a
|
|
4
|
+
* matching item to appear in the data.
|
|
5
|
+
*
|
|
6
|
+
* Pending sets / maps are insertion-ordered (oldest first) and capped so a
|
|
7
|
+
* long-running app with churning data can't grow them without bound.
|
|
8
|
+
*/
|
|
9
|
+
/** Default cap on pending keys per facet. Oldest entries are dropped first. */
|
|
10
|
+
const MAX_PENDING_KEYS = 2e3;
|
|
11
|
+
const EMPTY_KEYS = /* @__PURE__ */ new Set();
|
|
12
|
+
const EMPTY_FLAGS = /* @__PURE__ */ new Map();
|
|
13
|
+
/**
|
|
14
|
+
* Split `keys` into those `has` reports present (to apply now) and those
|
|
15
|
+
* still missing (to keep pending). Returns the input set untouched as
|
|
16
|
+
* `missing` when nothing matched, so callers can cheaply detect "no change".
|
|
17
|
+
*/
|
|
18
|
+
function partitionKeys(keys, has) {
|
|
19
|
+
if (keys.size === 0) return {
|
|
20
|
+
present: [],
|
|
21
|
+
missing: keys
|
|
22
|
+
};
|
|
23
|
+
const present = [];
|
|
24
|
+
const missing = /* @__PURE__ */ new Set();
|
|
25
|
+
for (const key of keys) if (has(key)) present.push(key);
|
|
26
|
+
else missing.add(key);
|
|
27
|
+
return {
|
|
28
|
+
present,
|
|
29
|
+
missing: present.length === 0 ? keys : missing
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/** As {@link partitionKeys}, for keyed boolean flags (e.g. expanded / collapsed). */
|
|
33
|
+
function partitionFlags(flags, has) {
|
|
34
|
+
if (flags.size === 0) return {
|
|
35
|
+
present: [],
|
|
36
|
+
missing: flags
|
|
37
|
+
};
|
|
38
|
+
const present = [];
|
|
39
|
+
const missing = /* @__PURE__ */ new Map();
|
|
40
|
+
for (const [key, value] of flags) if (has(key)) present.push([key, value]);
|
|
41
|
+
else missing.set(key, value);
|
|
42
|
+
return {
|
|
43
|
+
present,
|
|
44
|
+
missing: present.length === 0 ? flags : missing
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/** Keep at most `max` keys, dropping the oldest. */
|
|
48
|
+
function capKeys(keys, max = MAX_PENDING_KEYS) {
|
|
49
|
+
if (keys.size <= max) return keys;
|
|
50
|
+
return new Set([...keys].slice(keys.size - max));
|
|
51
|
+
}
|
|
52
|
+
/** Keep at most `max` flags, dropping the oldest. */
|
|
53
|
+
function capFlags(flags, max = MAX_PENDING_KEYS) {
|
|
54
|
+
if (flags.size <= max) return flags;
|
|
55
|
+
return new Map([...flags].slice(flags.size - max));
|
|
56
|
+
}
|
|
57
|
+
/** `flags` without `key` (same instance when absent). */
|
|
58
|
+
function withoutFlag(flags, key) {
|
|
59
|
+
if (!flags.has(key)) return flags;
|
|
60
|
+
const next = new Map(flags);
|
|
61
|
+
next.delete(key);
|
|
62
|
+
return next;
|
|
63
|
+
}
|
|
64
|
+
/** JSON record → flags map. Non-boolean values are ignored. */
|
|
65
|
+
function flagsFromRecord(record) {
|
|
66
|
+
if (!record) return EMPTY_FLAGS;
|
|
67
|
+
const out = /* @__PURE__ */ new Map();
|
|
68
|
+
for (const [key, value] of Object.entries(record)) if (typeof value === `boolean`) out.set(key, value);
|
|
69
|
+
return out;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Combine pending and live flags into one JSON record. Live entries win when
|
|
73
|
+
* a key is in both (it shouldn't be — matched keys leave pending).
|
|
74
|
+
*/
|
|
75
|
+
function flagsToRecord(...sources) {
|
|
76
|
+
const out = {};
|
|
77
|
+
for (const source of sources) for (const [key, value] of source) out[key] = value;
|
|
78
|
+
return out;
|
|
79
|
+
}
|
|
80
|
+
/** Pending keys followed by live keys, de-duplicated, as a JSON array. */
|
|
81
|
+
function keysToArray(...sources) {
|
|
82
|
+
const out = /* @__PURE__ */ new Set();
|
|
83
|
+
for (const source of sources) for (const key of source) out.add(key);
|
|
84
|
+
return [...out];
|
|
85
|
+
}
|
|
86
|
+
/** Map `keys` to `true` flags — for components that record a plain key set. */
|
|
87
|
+
function keysAsFlags(keys, value = true) {
|
|
88
|
+
return [...keys].map((k) => [k, value]);
|
|
89
|
+
}
|
|
90
|
+
//#endregion
|
|
91
|
+
export { capKeys as a, keysAsFlags as c, partitionKeys as d, withoutFlag as f, capFlags as i, keysToArray as l, EMPTY_KEYS as n, flagsFromRecord as o, MAX_PENDING_KEYS as r, flagsToRecord as s, EMPTY_FLAGS as t, partitionFlags as u };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
//#region src/interaction/scroll-hover-guard.ts
|
|
2
|
+
const SCROLL_HOVER_SUPPRESS_ATTR = `data-scroll-hover-suppress`;
|
|
3
|
+
function createScrollHoverGuard(config) {
|
|
4
|
+
const { host, enabled, onResume } = config;
|
|
5
|
+
let suppressed = false;
|
|
6
|
+
let lastX = NaN;
|
|
7
|
+
let lastY = NaN;
|
|
8
|
+
const end = () => {
|
|
9
|
+
if (!suppressed) return;
|
|
10
|
+
suppressed = false;
|
|
11
|
+
host.toggleAttribute(SCROLL_HOVER_SUPPRESS_ATTR, false);
|
|
12
|
+
};
|
|
13
|
+
const onScroll = () => {
|
|
14
|
+
if (suppressed || !enabled()) return;
|
|
15
|
+
suppressed = true;
|
|
16
|
+
host.toggleAttribute(SCROLL_HOVER_SUPPRESS_ATTR, true);
|
|
17
|
+
};
|
|
18
|
+
const onPointerMove = (e) => {
|
|
19
|
+
const moved = !Number.isNaN(lastX) && (e.clientX !== lastX || e.clientY !== lastY);
|
|
20
|
+
lastX = e.clientX;
|
|
21
|
+
lastY = e.clientY;
|
|
22
|
+
if (!moved || !suppressed) return;
|
|
23
|
+
end();
|
|
24
|
+
onResume?.(e.clientX, e.clientY);
|
|
25
|
+
};
|
|
26
|
+
return {
|
|
27
|
+
suppressed: () => suppressed,
|
|
28
|
+
onScroll,
|
|
29
|
+
onPointerMove,
|
|
30
|
+
onPointerLeave: end,
|
|
31
|
+
end
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
//#endregion
|
|
35
|
+
export { createScrollHoverGuard as n, SCROLL_HOVER_SUPPRESS_ATTR as t };
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { a as ViewStateBase, t as GetViewStateOptions } from "./types-LU1u0CB8.js";
|
|
2
|
+
import "./index-9ttcdwlL.js";
|
|
1
3
|
import { LitElement, nothing } from "lit";
|
|
2
4
|
//#region src/split-layout/types.d.ts
|
|
3
5
|
type Axis = `row` | `column`;
|
|
@@ -35,6 +37,24 @@ interface LayoutSnapshot {
|
|
|
35
37
|
version: 1;
|
|
36
38
|
root: SnapshotNode;
|
|
37
39
|
}
|
|
40
|
+
/**
|
|
41
|
+
* Saved size of one direct child of an `ixfx-split-layout`, keyed by the
|
|
42
|
+
* child's `id` in {@link SplitLayoutViewState.layout}.
|
|
43
|
+
*/
|
|
44
|
+
interface SplitPanelViewState {
|
|
45
|
+
/**
|
|
46
|
+
* Share (0..1) of the weighted flow. For a collapsed panel, the share it
|
|
47
|
+
* returns to when expanded.
|
|
48
|
+
*/
|
|
49
|
+
readonly weight: number;
|
|
50
|
+
/** Collapsed to the gutter. Absent ⇒ expanded. */
|
|
51
|
+
readonly collapsed?: boolean;
|
|
52
|
+
}
|
|
53
|
+
/** `ixfx-split-layout` view state (`kind: 'split-layout'`). */
|
|
54
|
+
type SplitLayoutViewState = ViewStateBase & {
|
|
55
|
+
/** Direct children with an author-given `id`, keyed by that id. */
|
|
56
|
+
readonly layout?: Readonly<Record<string, SplitPanelViewState>>;
|
|
57
|
+
};
|
|
38
58
|
interface PanelInfo {
|
|
39
59
|
id: string;
|
|
40
60
|
el: HTMLElement;
|
|
@@ -100,10 +120,17 @@ declare global {
|
|
|
100
120
|
//#endregion
|
|
101
121
|
//#region src/split-layout/split-layout.d.ts
|
|
102
122
|
declare class SplitLayoutElement extends LitElement {
|
|
123
|
+
#private;
|
|
103
124
|
direction: Axis;
|
|
104
125
|
sizes: string;
|
|
105
126
|
gutterSize: string;
|
|
106
127
|
snap: string;
|
|
128
|
+
/**
|
|
129
|
+
* Forget the saved size of a child that leaves instead of re-applying it
|
|
130
|
+
* when a child with that id returns. For hosts that drive child sizes
|
|
131
|
+
* themselves (e.g. `ixfx-dock-host`, whose leaf ids are positional).
|
|
132
|
+
*/
|
|
133
|
+
forgetAbsent: boolean;
|
|
107
134
|
private _model;
|
|
108
135
|
private _resizing;
|
|
109
136
|
private _groupEl?;
|
|
@@ -116,9 +143,20 @@ declare class SplitLayoutElement extends LitElement {
|
|
|
116
143
|
firstUpdated(): void;
|
|
117
144
|
private _setupObserver;
|
|
118
145
|
private _rebuildModel;
|
|
146
|
+
private _writeCollapsedAttributes;
|
|
119
147
|
get panels(): PanelInfo[];
|
|
120
|
-
|
|
121
|
-
|
|
148
|
+
/**
|
|
149
|
+
* Snapshot the size and collapse of every direct child with an `id`.
|
|
150
|
+
* Includes saved entries for children not currently slotted.
|
|
151
|
+
*/
|
|
152
|
+
getViewState(options?: GetViewStateOptions<SplitLayoutViewState>): SplitLayoutViewState;
|
|
153
|
+
/**
|
|
154
|
+
* Apply saved sizes. Entries for children that aren't slotted yet are kept
|
|
155
|
+
* and applied when a child with that id appears. Present children without
|
|
156
|
+
* an entry keep their relative size.
|
|
157
|
+
*/
|
|
158
|
+
setViewState(state: Partial<SplitLayoutViewState>): void;
|
|
159
|
+
clearPendingViewState(): void;
|
|
122
160
|
getSizes(_groupId?: string): Record<string, number>;
|
|
123
161
|
setSizes(weights: number[] | Record<string, number>, _groupId?: string): void;
|
|
124
162
|
collapse(idOrEl: string | HTMLElement): void;
|
|
@@ -175,4 +213,4 @@ declare global {
|
|
|
175
213
|
}
|
|
176
214
|
}
|
|
177
215
|
//#endregion
|
|
178
|
-
export { SplitExpandEvent as _, LayoutNode as a,
|
|
216
|
+
export { WhenSmall as C, SplitResizeEvent as S, SplitExpandEvent as _, LayoutNode as a, SplitPanelViewState as b, PanelNode as c, SplitChangeEvent as d, SplitCloseDetail as f, SplitExpandDetail as g, SplitCollapseEvent as h, GroupNode as i, SnapshotNode as l, SplitCollapseDetail as m, SplitPanelElement as n, LayoutSnapshot as o, SplitCloseEvent as p, Axis as r, PanelInfo as s, SplitLayoutElement as t, SplitChangeDetail as u, SplitLayoutElementEventMap as v, SplitResizeDetail as x, SplitLayoutViewState as y };
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { t as themeFallbacks } from "./fallbacks-DQ_5OsmR.js";
|
|
2
2
|
import { n as safeCustomElement, t as __decorate } from "./decorate-VRK8rslU.js";
|
|
3
3
|
import { t as handleStyles } from "./handle-DAXs7kbJ.js";
|
|
4
|
+
import { r as MAX_PENDING_KEYS } from "./pending-BGidHppL.js";
|
|
5
|
+
import { t as ViewStateController } from "./view-state-controller-BdyXWUUM.js";
|
|
4
6
|
import { LitElement, css, html, nothing } from "lit";
|
|
5
7
|
import { property, query, state } from "lit/decorators.js";
|
|
6
8
|
//#region src/split-layout/split-drag.ts
|
|
@@ -389,6 +391,163 @@ function walkInner(node, path, visitor) {
|
|
|
389
391
|
if (node.kind === `group`) for (let i = 0; i < node.children.length; i++) walkInner(node.children[i], [...path, i], visitor);
|
|
390
392
|
}
|
|
391
393
|
//#endregion
|
|
394
|
+
//#region src/split-layout/split-view-state.ts
|
|
395
|
+
const EMPTY_ENTRIES = /* @__PURE__ */ new Map();
|
|
396
|
+
/** Whether `node` has an author-given id (and can therefore carry view state). */
|
|
397
|
+
function isKeyed(node) {
|
|
398
|
+
return node.id !== `` && node.el?.id === node.id;
|
|
399
|
+
}
|
|
400
|
+
/** Saved form of one child. Collapsed panels record the share they expand back to. */
|
|
401
|
+
function entryOf(node) {
|
|
402
|
+
if (node.kind === `panel` && node.collapsed) return {
|
|
403
|
+
weight: node.restoreWeight,
|
|
404
|
+
collapsed: true
|
|
405
|
+
};
|
|
406
|
+
return { weight: node.weight };
|
|
407
|
+
}
|
|
408
|
+
/** Entries for every keyed direct child of `group`. */
|
|
409
|
+
function captureLayout(group) {
|
|
410
|
+
const out = /* @__PURE__ */ new Map();
|
|
411
|
+
for (const child of group.children) if (isKeyed(child)) out.set(child.id, entryOf(child));
|
|
412
|
+
return out;
|
|
413
|
+
}
|
|
414
|
+
/** Combine entry sources into one JSON record (later sources win). */
|
|
415
|
+
function layoutToRecord(...sources) {
|
|
416
|
+
const out = {};
|
|
417
|
+
for (const source of sources) for (const [id, entry] of source) out[id] = entry;
|
|
418
|
+
return out;
|
|
419
|
+
}
|
|
420
|
+
/** JSON record → entries. Entries without a finite, non-negative `weight` are dropped. */
|
|
421
|
+
function layoutFromRecord(record) {
|
|
422
|
+
if (!record || typeof record !== `object`) return EMPTY_ENTRIES;
|
|
423
|
+
const out = /* @__PURE__ */ new Map();
|
|
424
|
+
for (const [id, entry] of Object.entries(record)) {
|
|
425
|
+
const weight = entry?.weight;
|
|
426
|
+
if (typeof weight !== `number` || !Number.isFinite(weight) || weight < 0) continue;
|
|
427
|
+
out.set(id, entry.collapsed === true ? {
|
|
428
|
+
weight,
|
|
429
|
+
collapsed: true
|
|
430
|
+
} : { weight });
|
|
431
|
+
}
|
|
432
|
+
return capEntries(out);
|
|
433
|
+
}
|
|
434
|
+
/** Keep at most `max` entries, dropping the oldest. */
|
|
435
|
+
function capEntries(entries, max = MAX_PENDING_KEYS) {
|
|
436
|
+
if (entries.size <= max) return entries;
|
|
437
|
+
return new Map([...entries].slice(entries.size - max));
|
|
438
|
+
}
|
|
439
|
+
/**
|
|
440
|
+
* Reconcile a freshly built (normalised) `next` model with the previous one
|
|
441
|
+
* and pending entries:
|
|
442
|
+
*
|
|
443
|
+
* - keyed children of `prev` that are gone → pending (when `retainAbsent`)
|
|
444
|
+
* - pending entries whose child is now present → applied (weight + collapse)
|
|
445
|
+
* and removed from pending
|
|
446
|
+
* - with `carry`, children that were already there keep their live weight;
|
|
447
|
+
* children that are new keep the share the DOM gives them
|
|
448
|
+
*
|
|
449
|
+
* Applied and new children are *pinned* to their share; carried children
|
|
450
|
+
* scale to fill what is left, so restoring three of five saved panels and
|
|
451
|
+
* later slotting the other two lands on the saved proportions.
|
|
452
|
+
*/
|
|
453
|
+
function reconcileLayout(prev, next, pending, options) {
|
|
454
|
+
const nextIds = new Set(next.children.map((c) => c.id));
|
|
455
|
+
const nextPending = new Map(pending);
|
|
456
|
+
const demoted = [];
|
|
457
|
+
if (prev && options.retainAbsent) {
|
|
458
|
+
for (const child of prev.children) if (isKeyed(child) && !nextIds.has(child.id)) {
|
|
459
|
+
nextPending.set(child.id, entryOf(child));
|
|
460
|
+
demoted.push(child.id);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
const prevById = options.carry && prev ? new Map(prev.children.map((c) => [c.id, c])) : void 0;
|
|
464
|
+
const applied = [];
|
|
465
|
+
const collapse = [];
|
|
466
|
+
const shares = [];
|
|
467
|
+
const children = next.children.map((child, i) => {
|
|
468
|
+
const entry = isKeyed(child) ? nextPending.get(child.id) : void 0;
|
|
469
|
+
if (entry) {
|
|
470
|
+
nextPending.delete(child.id);
|
|
471
|
+
applied.push(child.id);
|
|
472
|
+
shares[i] = {
|
|
473
|
+
value: entry.weight,
|
|
474
|
+
pinned: true
|
|
475
|
+
};
|
|
476
|
+
if (child.kind === `group`) return {
|
|
477
|
+
...child,
|
|
478
|
+
weight: entry.weight
|
|
479
|
+
};
|
|
480
|
+
const collapsed = entry.collapsed === true;
|
|
481
|
+
if (collapsed !== child.collapsed) collapse.push([child.el, collapsed]);
|
|
482
|
+
return {
|
|
483
|
+
...child,
|
|
484
|
+
collapsed,
|
|
485
|
+
weight: entry.weight,
|
|
486
|
+
restoreWeight: entry.weight
|
|
487
|
+
};
|
|
488
|
+
}
|
|
489
|
+
const before = prevById?.get(child.id);
|
|
490
|
+
if (before && sameShape(before, child)) {
|
|
491
|
+
shares[i] = {
|
|
492
|
+
value: before.weight,
|
|
493
|
+
pinned: false
|
|
494
|
+
};
|
|
495
|
+
return {
|
|
496
|
+
...child,
|
|
497
|
+
weight: before.weight
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
shares[i] = {
|
|
501
|
+
value: child.weight,
|
|
502
|
+
pinned: prevById !== void 0
|
|
503
|
+
};
|
|
504
|
+
return child;
|
|
505
|
+
});
|
|
506
|
+
return {
|
|
507
|
+
model: {
|
|
508
|
+
...next,
|
|
509
|
+
children: mergeShares(children, shares)
|
|
510
|
+
},
|
|
511
|
+
pending: demoted.length === 0 && applied.length === 0 ? pending : capEntries(nextPending),
|
|
512
|
+
applied,
|
|
513
|
+
demoted,
|
|
514
|
+
collapse
|
|
515
|
+
};
|
|
516
|
+
}
|
|
517
|
+
function sameShape(a, b) {
|
|
518
|
+
if (a.kind !== b.kind) return false;
|
|
519
|
+
return a.kind === `group` || b.kind === `panel` && a.collapsed === b.collapsed;
|
|
520
|
+
}
|
|
521
|
+
function isFlexible(node) {
|
|
522
|
+
return node.kind === `group` || node.fixedPx === null && !node.collapsed;
|
|
523
|
+
}
|
|
524
|
+
/**
|
|
525
|
+
* Pinned flexible children keep their share; floating ones scale to fill the
|
|
526
|
+
* rest. With nothing floating (or pins over-full) every flexible share is
|
|
527
|
+
* simply normalised.
|
|
528
|
+
*/
|
|
529
|
+
function mergeShares(children, shares) {
|
|
530
|
+
let pinnedTotal = 0;
|
|
531
|
+
let floatingTotal = 0;
|
|
532
|
+
children.forEach((child, i) => {
|
|
533
|
+
if (!isFlexible(child)) return;
|
|
534
|
+
if (shares[i].pinned) pinnedTotal += shares[i].value;
|
|
535
|
+
else floatingTotal += shares[i].value;
|
|
536
|
+
});
|
|
537
|
+
const scaleFloating = floatingTotal > 0 && pinnedTotal < 1;
|
|
538
|
+
const total = scaleFloating ? 1 : pinnedTotal + floatingTotal || 1;
|
|
539
|
+
const floatScale = scaleFloating ? (1 - pinnedTotal) / floatingTotal : 1 / total;
|
|
540
|
+
const pinScale = scaleFloating ? 1 : 1 / total;
|
|
541
|
+
return children.map((child, i) => {
|
|
542
|
+
if (!isFlexible(child)) return child;
|
|
543
|
+
const weight = shares[i].value * (shares[i].pinned ? pinScale : floatScale);
|
|
544
|
+
return weight === child.weight ? child : {
|
|
545
|
+
...child,
|
|
546
|
+
weight
|
|
547
|
+
};
|
|
548
|
+
});
|
|
549
|
+
}
|
|
550
|
+
//#endregion
|
|
392
551
|
//#region src/split-layout/split-panel.ts
|
|
393
552
|
let SplitPanelElement = class SplitPanelElement extends LitElement {
|
|
394
553
|
constructor(..._args) {
|
|
@@ -449,11 +608,17 @@ let SplitLayoutElement = class SplitLayoutElement extends LitElement {
|
|
|
449
608
|
this.sizes = ``;
|
|
450
609
|
this.gutterSize = ``;
|
|
451
610
|
this.snap = ``;
|
|
611
|
+
this.forgetAbsent = false;
|
|
452
612
|
this._model = null;
|
|
453
613
|
this._resizing = false;
|
|
454
614
|
this._observer = null;
|
|
455
615
|
this._applyingOwnMutation = false;
|
|
456
616
|
this._dragStructurallyChanged = false;
|
|
617
|
+
this.#viewState = new ViewStateController(this, {
|
|
618
|
+
kind: `split-layout`,
|
|
619
|
+
capture: () => this.getViewState()
|
|
620
|
+
});
|
|
621
|
+
this.#pendingLayout = EMPTY_ENTRIES;
|
|
457
622
|
this._dragMachine = createDragMachine({
|
|
458
623
|
onDragStart: (state) => this._handleDragStart(state),
|
|
459
624
|
onDragMove: (state, deltaX, deltaY) => this._handleDragMove(state, deltaX, deltaY),
|
|
@@ -479,6 +644,9 @@ let SplitLayoutElement = class SplitLayoutElement extends LitElement {
|
|
|
479
644
|
window.removeEventListener(`pointerup`, this._onPointerUp);
|
|
480
645
|
};
|
|
481
646
|
}
|
|
647
|
+
#viewState;
|
|
648
|
+
/** Saved entries for children not currently present. */
|
|
649
|
+
#pendingLayout;
|
|
482
650
|
connectedCallback() {
|
|
483
651
|
super.connectedCallback();
|
|
484
652
|
this._setupObserver();
|
|
@@ -491,8 +659,11 @@ let SplitLayoutElement = class SplitLayoutElement extends LitElement {
|
|
|
491
659
|
this._rebuildModel();
|
|
492
660
|
}
|
|
493
661
|
_setupObserver() {
|
|
494
|
-
this._observer = new MutationObserver(() => {
|
|
495
|
-
if (!this._applyingOwnMutation)
|
|
662
|
+
this._observer = new MutationObserver((records) => {
|
|
663
|
+
if (!this._applyingOwnMutation) {
|
|
664
|
+
const carry = !records.some((r) => isOwnAttributeChange(this, r));
|
|
665
|
+
Promise.resolve().then(() => this._rebuildModel(carry));
|
|
666
|
+
}
|
|
496
667
|
});
|
|
497
668
|
this._observer.observe(this, {
|
|
498
669
|
childList: true,
|
|
@@ -507,15 +678,33 @@ let SplitLayoutElement = class SplitLayoutElement extends LitElement {
|
|
|
507
678
|
`direction`,
|
|
508
679
|
`collapsed`,
|
|
509
680
|
`sizes`
|
|
510
|
-
]
|
|
681
|
+
],
|
|
682
|
+
attributeOldValue: true
|
|
511
683
|
});
|
|
512
684
|
}
|
|
513
|
-
_rebuildModel() {
|
|
685
|
+
_rebuildModel(carry = true) {
|
|
514
686
|
this._reindexSlots();
|
|
515
|
-
const
|
|
516
|
-
|
|
687
|
+
const model = buildModel(this);
|
|
688
|
+
const normalized = preserveRestoreWeights(this._model, normalise(model));
|
|
689
|
+
const result = reconcileLayout(this._model, normalized, this.#pendingLayout, {
|
|
690
|
+
carry,
|
|
691
|
+
retainAbsent: !this.forgetAbsent
|
|
692
|
+
});
|
|
693
|
+
this._model = result.model;
|
|
694
|
+
this.#pendingLayout = result.pending;
|
|
695
|
+
this._writeCollapsedAttributes(result.collapse);
|
|
696
|
+
if (result.applied.length > 0) this.#viewState.restoring(() => this.#viewState.notify());
|
|
697
|
+
else if (result.demoted.length > 0) this.#viewState.notify(`data`);
|
|
517
698
|
this.requestUpdate();
|
|
518
699
|
}
|
|
700
|
+
_writeCollapsedAttributes(writes) {
|
|
701
|
+
if (writes.length === 0) return;
|
|
702
|
+
for (const [el, collapsed] of writes) {
|
|
703
|
+
el.toggleAttribute(`collapsed`, collapsed);
|
|
704
|
+
el.toggleAttribute(`data-collapsed`, collapsed);
|
|
705
|
+
}
|
|
706
|
+
this._observer?.takeRecords();
|
|
707
|
+
}
|
|
519
708
|
get panels() {
|
|
520
709
|
if (!this._model) return [];
|
|
521
710
|
const panels = [];
|
|
@@ -534,17 +723,38 @@ let SplitLayoutElement = class SplitLayoutElement extends LitElement {
|
|
|
534
723
|
});
|
|
535
724
|
return panels;
|
|
536
725
|
}
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
726
|
+
/**
|
|
727
|
+
* Snapshot the size and collapse of every direct child with an `id`.
|
|
728
|
+
* Includes saved entries for children not currently slotted.
|
|
729
|
+
*/
|
|
730
|
+
getViewState(options) {
|
|
731
|
+
const withPending = options?.includePending ?? true;
|
|
732
|
+
const live = this._model ? captureLayout(this._model) : [];
|
|
733
|
+
return this.#viewState.shape({ layout: layoutToRecord(withPending ? this.#pendingLayout : [], live) }, options);
|
|
540
734
|
}
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
this.
|
|
735
|
+
/**
|
|
736
|
+
* Apply saved sizes. Entries for children that aren't slotted yet are kept
|
|
737
|
+
* and applied when a child with that id appears. Present children without
|
|
738
|
+
* an entry keep their relative size.
|
|
739
|
+
*/
|
|
740
|
+
setViewState(state) {
|
|
741
|
+
if (!this.#viewState.accepts(state) || state.layout === void 0) return;
|
|
742
|
+
this.#viewState.restoring(() => {
|
|
743
|
+
this.#pendingLayout = layoutFromRecord(state.layout);
|
|
744
|
+
if (!this._model) {
|
|
745
|
+
this.#viewState.notify();
|
|
746
|
+
return;
|
|
747
|
+
}
|
|
748
|
+
this._applyingOwnMutation = true;
|
|
749
|
+
this._rebuildModel();
|
|
750
|
+
this._observer?.takeRecords();
|
|
751
|
+
this._applyingOwnMutation = false;
|
|
752
|
+
this._emitResize();
|
|
753
|
+
this._emitChange();
|
|
754
|
+
});
|
|
755
|
+
}
|
|
756
|
+
clearPendingViewState() {
|
|
757
|
+
this.#pendingLayout = EMPTY_ENTRIES;
|
|
548
758
|
}
|
|
549
759
|
getSizes(_groupId) {
|
|
550
760
|
if (!this._model) return {};
|
|
@@ -818,9 +1028,9 @@ let SplitLayoutElement = class SplitLayoutElement extends LitElement {
|
|
|
818
1028
|
}));
|
|
819
1029
|
}
|
|
820
1030
|
_emitChange() {
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
const detail = { layout };
|
|
1031
|
+
if (!this._model) return;
|
|
1032
|
+
this.#viewState.notify();
|
|
1033
|
+
const detail = { layout: toSnapshot(this._model) };
|
|
824
1034
|
this.dispatchEvent(new CustomEvent(`ixfx-split-change`, {
|
|
825
1035
|
detail,
|
|
826
1036
|
bubbles: true,
|
|
@@ -1018,9 +1228,31 @@ __decorate([property({
|
|
|
1018
1228
|
attribute: `gutter-size`
|
|
1019
1229
|
})], SplitLayoutElement.prototype, "gutterSize", void 0);
|
|
1020
1230
|
__decorate([property({ type: String })], SplitLayoutElement.prototype, "snap", void 0);
|
|
1231
|
+
__decorate([property({
|
|
1232
|
+
type: Boolean,
|
|
1233
|
+
attribute: `forget-absent`
|
|
1234
|
+
})], SplitLayoutElement.prototype, "forgetAbsent", void 0);
|
|
1021
1235
|
__decorate([state()], SplitLayoutElement.prototype, "_model", void 0);
|
|
1022
1236
|
__decorate([state()], SplitLayoutElement.prototype, "_resizing", void 0);
|
|
1023
1237
|
__decorate([query(`.grid`)], SplitLayoutElement.prototype, "_groupEl", void 0);
|
|
1024
1238
|
SplitLayoutElement = __decorate([safeCustomElement(`ixfx-split-layout`)], SplitLayoutElement);
|
|
1239
|
+
/** Attributes that set a child's share (or take it out of the weighted flow). */
|
|
1240
|
+
const WEIGHT_ATTRIBUTES = /* @__PURE__ */ new Set([
|
|
1241
|
+
`size`,
|
|
1242
|
+
`weight`,
|
|
1243
|
+
`sizes`,
|
|
1244
|
+
`fixed`,
|
|
1245
|
+
`collapsed`
|
|
1246
|
+
]);
|
|
1247
|
+
/**
|
|
1248
|
+
* A weight attribute on `host` or one of its direct children whose value
|
|
1249
|
+
* really changed (not e.g. `direction` reflecting on first render).
|
|
1250
|
+
*/
|
|
1251
|
+
function isOwnAttributeChange(host, record) {
|
|
1252
|
+
if (record.type !== `attributes` || record.attributeName === null || !WEIGHT_ATTRIBUTES.has(record.attributeName)) return false;
|
|
1253
|
+
const target = record.target;
|
|
1254
|
+
if (target !== host && target.parentElement !== host) return false;
|
|
1255
|
+
return target.getAttribute(record.attributeName) !== record.oldValue;
|
|
1256
|
+
}
|
|
1025
1257
|
//#endregion
|
|
1026
1258
|
export { distribute as a, preserveRestoreWeights as c, toSnapshot as d, walk as f, buildModel as i, resolveTracks as l, SplitPanelElement as n, findPanelNode as o, applySnapshot as r, normalise as s, SplitLayoutElement as t, setPanelRestoreWeight as u };
|
package/dist/split-layout.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as SplitLayoutElement } from "./split-layout-
|
|
1
|
+
import { t as SplitLayoutElement } from "./split-layout-CophkNeU.js";
|
|
2
2
|
export { SplitLayoutElement };
|
package/dist/split-layout.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as SplitLayoutElement } from "./split-layout-
|
|
1
|
+
import { t as SplitLayoutElement } from "./split-layout-DTY4PJRp.js";
|
|
2
2
|
export { SplitLayoutElement };
|
package/dist/sunburst-tree.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as SunburstZoomEvent, n as SunburstTreeListElementEventMap, r as SunburstZoomDetail, t as SunburstTreeListElement } from "./sunbursttree-list
|
|
2
|
-
export { SunburstTreeListElement, SunburstTreeListElementEventMap, SunburstZoomDetail, SunburstZoomEvent };
|
|
1
|
+
import { a as SunburstViewState, i as SunburstZoomEvent, n as SunburstTreeListElementEventMap, r as SunburstZoomDetail, t as SunburstTreeListElement } from "./sunbursttree-list-D6j5BxVQ.js";
|
|
2
|
+
export { SunburstTreeListElement, SunburstTreeListElementEventMap, type SunburstViewState, SunburstZoomDetail, SunburstZoomEvent };
|
package/dist/sunburst-tree.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as SunburstTreeListElement } from "./sunbursttree-list-
|
|
1
|
+
import { t as SunburstTreeListElement } from "./sunbursttree-list-B_VxOHlo.js";
|
|
2
2
|
export { SunburstTreeListElement };
|