@ixfx/components 0.13.7 → 0.13.9
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 +22 -0
- package/bundle/index.js +138 -107
- package/dist/{index-BG8E13J5.d.ts → index-CSCrK0hR.d.ts} +18 -0
- package/dist/index.d.ts +5 -1
- package/dist/index.js +109 -29
- package/dist/{tree-BjrfaX7d.js → tree-9Hs7VxuX.js} +63 -0
- package/dist/tree.d.ts +1 -1
- package/dist/tree.js +1 -1
- package/docs-user/hyperbolic-tree.md +1 -1
- package/docs-user/index.json +2 -2
- package/docs-user/multicol-list.md +1 -1
- package/docs-user/tree.md +33 -0
- package/package.json +1 -1
|
@@ -123,6 +123,24 @@ declare class TreeBaseElement extends LitElement implements TreeComponent, TreeS
|
|
|
123
123
|
clearSelection(): void;
|
|
124
124
|
selectAll(): void;
|
|
125
125
|
deselectAll(): void;
|
|
126
|
+
/**
|
|
127
|
+
* Expand every already-loaded branch in a single update. With `maxDepth`,
|
|
128
|
+
* only branches at depth < `maxDepth` are expanded (the root's children are
|
|
129
|
+
* depth 0), so rows at depth `maxDepth` become visible but stay collapsed.
|
|
130
|
+
*
|
|
131
|
+
* Unloaded (lazy) branches are not fetched — call again once their children
|
|
132
|
+
* have loaded to expand further. Bulk expansion ignores `exclusivity`. Fires
|
|
133
|
+
* one `expand` event per branch that actually opens — none for branches that
|
|
134
|
+
* were already expanded, including ones opened by filter auto-expansion.
|
|
135
|
+
*/
|
|
136
|
+
expandAll(maxDepth?: number): void;
|
|
137
|
+
/**
|
|
138
|
+
* Collapse expanded branches in a single update. With `maxDepth`, only
|
|
139
|
+
* branches at depth >= `maxDepth` are collapsed, leaving the tree open down
|
|
140
|
+
* to depth `maxDepth - 1` (`collapseAll(0)` is a full collapse). Fires one
|
|
141
|
+
* `collapse` event per branch that actually closes.
|
|
142
|
+
*/
|
|
143
|
+
collapseAll(maxDepth?: number): void;
|
|
126
144
|
navigateTo(keys: readonly string[], options?: TreeNavigateOptions): boolean;
|
|
127
145
|
navigateToNode(predicate: (node: TreeNode) => boolean): boolean;
|
|
128
146
|
/** Expand ancestors + move the cursor to `key`, without touching the selection (search "navigate" mode). */
|
package/dist/index.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ import { a as ColourPickerInputEvent, i as ColourPickerEventDetail, n as ColourP
|
|
|
9
9
|
import { t as LabelledRangeInput } from "./index-CoqtMSd9.js";
|
|
10
10
|
import { A as TreeTickleEvent, B as ListNativeDragStartEvent, C as TreeItemDblClickEvent, D as TreeSelectDetail, E as TreeSearchHost, F as ListDragPreviewContext, I as ListDragPreviewRenderer, L as ListDragPreviewSourceResolver, M as TreeDataModelOptions, N as ListDragEntry, O as TreeSelectEvent, P as ListDragPreview, R as ListDragSource, S as TreeItemDblClickDetail, T as TreeRevealMode, _ as TreeDropTarget, a as TreeComponent, b as TreeItemClickDetail, c as TreeDragContext, d as TreeDragStartEvent, f as TreeDropApplyContext, g as TreeDropPosition, h as TreeDropEvent, i as TreeCollapseEvent, j as TreeDataModel, k as TreeTickleDetail, l as TreeDragEndEvent, m as TreeDropDetail, n as TreeActivateEvent, o as TreeComponentEventMap, p as TreeDropContext, r as TreeCollapseDetail, s as TreeDndMode, t as TreeActivateDetail, u as TreeDragOverEvent, v as TreeExpandDetail, w as TreeNavigateOptions, x as TreeItemClickEvent, y as TreeExpandEvent, z as ListNativeDragStartDetail } from "./tree-component-Tslymyyl.js";
|
|
11
11
|
import { a as TreeItem, i as TreeInteractionMode, n as TreeExclusivity, o as TreeNode, r as TreeFilterPredicate, s as TreeSelectionFilter, t as LoadChildrenCallback } from "./types-DQ7KOUIj.js";
|
|
12
|
-
import { a as TreeDropVisibleRow, c as TreeListElement, d as TreeBaseElementEventMap, f as TreeVirtualize, i as TreeDropRowInfo, l as TreeCheckboxState, n as TreeDropControllerConfig, o as TreeController, p as TreeConfig, r as TreeDropResolvedDrag, s as TreeControllerOptions, t as TreeDropController, u as TreeBaseElement } from "./index-
|
|
12
|
+
import { a as TreeDropVisibleRow, c as TreeListElement, d as TreeBaseElementEventMap, f as TreeVirtualize, i as TreeDropRowInfo, l as TreeCheckboxState, n as TreeDropControllerConfig, o as TreeController, p as TreeConfig, r as TreeDropResolvedDrag, s as TreeControllerOptions, t as TreeDropController, u as TreeBaseElement } from "./index-CSCrK0hR.js";
|
|
13
13
|
import "./menu-item-bF6narIz.js";
|
|
14
14
|
import { a as NarrowedTextItem, i as NarrowedTextChangeEvent, n as FuzzySearchResult, o as Orientation, r as NarrowedTextChangeDetail, s as SelectionMode, t as NarrowedTextElement } from "./index-o-CWDt11.js";
|
|
15
15
|
import { CrumbNavigationChangeDetail, CrumbNavigationChangeEvent, CrumbNavigationElement, CrumbNavigationElementEventMap, CrumbNavigationExpandDetail, CrumbNavigationExpandEvent, CrumbNavigationItemClickDetail, CrumbNavigationItemClickEvent } from "./crumbs.js";
|
|
@@ -2446,6 +2446,8 @@ type MulticolCategoryDefaults = {
|
|
|
2446
2446
|
type MulticolCategory = {
|
|
2447
2447
|
readonly key: string;
|
|
2448
2448
|
readonly label: string;
|
|
2449
|
+
/** Shown as a tooltip on the column header label. */
|
|
2450
|
+
readonly description?: string;
|
|
2449
2451
|
readonly children?: readonly MulticolCategory[];
|
|
2450
2452
|
readonly defaults?: MulticolCategoryDefaults;
|
|
2451
2453
|
};
|
|
@@ -2523,6 +2525,8 @@ declare class MulticolListElement extends LitElement {
|
|
|
2523
2525
|
protected updated(changedProperties: Map<string, unknown>): void;
|
|
2524
2526
|
private _renderColumn;
|
|
2525
2527
|
private _getCategoryLabel;
|
|
2528
|
+
/** Category description if present, else the default 'Change category' hint. */
|
|
2529
|
+
private _getCategoryTooltip;
|
|
2526
2530
|
private _onHeaderPointerDown;
|
|
2527
2531
|
private _onResizePointerDown;
|
|
2528
2532
|
private _openCategoryPicker;
|
package/dist/index.js
CHANGED
|
@@ -27,7 +27,7 @@ import { t as CheckedSelect } from "./checked-select-lDgAQQ7v.js";
|
|
|
27
27
|
import { n as ColourPicker, t as ColourPickerPopup } from "./colour-picker-BCMU7W7R.js";
|
|
28
28
|
import { LabelledRangeInput } from "./labelled-range-input.js";
|
|
29
29
|
import { t as collectDataResult } from "./data-provider-35TyWclX.js";
|
|
30
|
-
import { a as TreeDataModel, c as pruneDraggedDescendants, i as TreeDropController, n as TreeListElement, o as applyTreeDrop, r as TreeBaseElement, s as dropTargetFor, t as TreeController } from "./tree-
|
|
30
|
+
import { a as TreeDataModel, c as pruneDraggedDescendants, i as TreeDropController, n as TreeListElement, o as applyTreeDrop, r as TreeBaseElement, s as dropTargetFor, t as TreeController } from "./tree-9Hs7VxuX.js";
|
|
31
31
|
import { t as scrollFadeStyles } from "./scroll-fade-Xx28D7mH.js";
|
|
32
32
|
import { NarrowedTextElement } from "./narrowed-text.js";
|
|
33
33
|
import { CrumbNavigationElement } from "./crumbs.js";
|
|
@@ -3848,7 +3848,7 @@ TabListItemElement = __decorate([safeCustomElement(`ixfx-tab-list-item`)], TabLi
|
|
|
3848
3848
|
//#endregion
|
|
3849
3849
|
//#region src/dock/dock-panel.ts
|
|
3850
3850
|
/** Pointer movement threshold before a titlebar press becomes a dock drag. */
|
|
3851
|
-
const DRAG_THRESHOLD_PX$
|
|
3851
|
+
const DRAG_THRESHOLD_PX$4 = 5;
|
|
3852
3852
|
let DockPanelElement = class DockPanelElement extends LitElement {
|
|
3853
3853
|
constructor(..._args) {
|
|
3854
3854
|
super(..._args);
|
|
@@ -3880,7 +3880,7 @@ let DockPanelElement = class DockPanelElement extends LitElement {
|
|
|
3880
3880
|
this._onPointerMove = (event) => {
|
|
3881
3881
|
if (this._dragPointerId === null || event.pointerId !== this._dragPointerId) return;
|
|
3882
3882
|
if (!this._dragStarted) {
|
|
3883
|
-
if (Math.hypot(event.clientX - this._dragStartX, event.clientY - this._dragStartY) < DRAG_THRESHOLD_PX$
|
|
3883
|
+
if (Math.hypot(event.clientX - this._dragStartX, event.clientY - this._dragStartY) < DRAG_THRESHOLD_PX$4) return;
|
|
3884
3884
|
this._dragStarted = true;
|
|
3885
3885
|
const pointerId = this._dragPointerId;
|
|
3886
3886
|
this._teardownDragListeners();
|
|
@@ -4035,7 +4035,7 @@ DockPanelElement = __decorate([safeCustomElement(`ixfx-dock-panel`)], DockPanelE
|
|
|
4035
4035
|
/** Fraction of the leaf rect (from each edge) that forms the split bands. */
|
|
4036
4036
|
const BAND = .25;
|
|
4037
4037
|
/** Pointer movement threshold before a press becomes a dock drag (matches tab-list). */
|
|
4038
|
-
const DRAG_THRESHOLD_PX$
|
|
4038
|
+
const DRAG_THRESHOLD_PX$3 = 5;
|
|
4039
4039
|
/** Tolerance (px) when matching a child gutter endpoint to a parent gutter line. */
|
|
4040
4040
|
const JUNCTION_TOL_PX = 6;
|
|
4041
4041
|
/** Junction points closer than this merge into one handle (a 4-way cross yields one per side). */
|
|
@@ -4152,7 +4152,7 @@ let DockHostElement = class DockHostElement extends LitElement {
|
|
|
4152
4152
|
this._onTabDragMove = (event) => {
|
|
4153
4153
|
const pending = this._tabDragPending;
|
|
4154
4154
|
if (pending === null || event.pointerId !== pending.pointerId) return;
|
|
4155
|
-
if (Math.hypot(event.clientX - pending.startX, event.clientY - pending.startY) < DRAG_THRESHOLD_PX$
|
|
4155
|
+
if (Math.hypot(event.clientX - pending.startX, event.clientY - pending.startY) < DRAG_THRESHOLD_PX$3) return;
|
|
4156
4156
|
this._tabDragPending = null;
|
|
4157
4157
|
this._teardownTabDragListeners();
|
|
4158
4158
|
this._suppressNextClick();
|
|
@@ -5880,6 +5880,16 @@ function createVerticalListAdapter(renderItem, options) {
|
|
|
5880
5880
|
});
|
|
5881
5881
|
return adapter;
|
|
5882
5882
|
}
|
|
5883
|
+
//#endregion
|
|
5884
|
+
//#region src/hyperbolic-tree/child-preview.ts
|
|
5885
|
+
/** Lucide `arrow-up`. */
|
|
5886
|
+
const upIcon = svg`<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m5 12 7-7 7 7"/><path d="M12 19V5"/></svg>`;
|
|
5887
|
+
/** Picks the popover's side for a node anchored at `anchor` in a `width` x `height` host. */
|
|
5888
|
+
function choosePreviewSide(anchor, width, height) {
|
|
5889
|
+
if (anchor.y < height * .25) return `below`;
|
|
5890
|
+
if (anchor.y > height * .75) return `above`;
|
|
5891
|
+
return anchor.x > width / 2 ? `left` : `right`;
|
|
5892
|
+
}
|
|
5883
5893
|
/**
|
|
5884
5894
|
* Whether `n` deserves a preview: it has children and at least one of them
|
|
5885
5895
|
* isn't legible right now — laid out without a label, or not laid out at
|
|
@@ -5906,7 +5916,7 @@ function renderChildPreview(preview, handlers) {
|
|
|
5906
5916
|
const more = children.length - listed.length;
|
|
5907
5917
|
return html`
|
|
5908
5918
|
<div
|
|
5909
|
-
class="child-preview ${preview.
|
|
5919
|
+
class="child-preview ${preview.side}"
|
|
5910
5920
|
part="child-preview"
|
|
5911
5921
|
role="dialog"
|
|
5912
5922
|
aria-label=${`Children of ${preview.node.item.label}`}
|
|
@@ -5915,7 +5925,17 @@ function renderChildPreview(preview, handlers) {
|
|
|
5915
5925
|
@pointerleave=${handlers.onPointerLeave}
|
|
5916
5926
|
@pointerdown=${(e) => e.stopPropagation()}
|
|
5917
5927
|
>
|
|
5918
|
-
<div class="child-preview-title"
|
|
5928
|
+
<div class="child-preview-title">
|
|
5929
|
+
${preview.parent ? html`<button
|
|
5930
|
+
type="button"
|
|
5931
|
+
class="child-preview-up"
|
|
5932
|
+
tabindex="-1"
|
|
5933
|
+
title=${`Up to ${preview.parent.item.label}`}
|
|
5934
|
+
aria-label=${`Up to ${preview.parent.item.label}`}
|
|
5935
|
+
@click=${() => handlers.onPick(preview.parent)}
|
|
5936
|
+
>${upIcon}</button>` : nothing}
|
|
5937
|
+
<span>${preview.node.item.label}</span>
|
|
5938
|
+
</div>
|
|
5919
5939
|
<ul>
|
|
5920
5940
|
${listed.map((child) => html`<li>
|
|
5921
5941
|
<button type="button" tabindex="-1" @click=${() => handlers.onPick(child)}>${child.item.label}</button>
|
|
@@ -5926,9 +5946,11 @@ function renderChildPreview(preview, handlers) {
|
|
|
5926
5946
|
`;
|
|
5927
5947
|
}
|
|
5928
5948
|
/**
|
|
5929
|
-
* Show/hide timing for the preview:
|
|
5930
|
-
*
|
|
5931
|
-
*
|
|
5949
|
+
* Show/hide timing for the preview: opens only after the pointer has rested
|
|
5950
|
+
* on a qualifying node for {@link PREVIEW_SHOW_DELAY_MS} (re-checked when the
|
|
5951
|
+
* delay elapses, so a drag in the meantime suppresses it); otherwise hides
|
|
5952
|
+
* after a short grace period, unless the pointer is over the popover itself —
|
|
5953
|
+
* so it can travel from the node onto the list.
|
|
5932
5954
|
*/
|
|
5933
5955
|
function createChildPreviewTiming(host) {
|
|
5934
5956
|
let hovered = false;
|
|
@@ -5937,7 +5959,11 @@ function createChildPreviewTiming(host) {
|
|
|
5937
5959
|
clearTimeout(timer);
|
|
5938
5960
|
const candidate = host.candidate(id);
|
|
5939
5961
|
if (candidate !== void 0) {
|
|
5940
|
-
host.
|
|
5962
|
+
if (candidate === host.currentId()) return;
|
|
5963
|
+
timer = setTimeout(() => {
|
|
5964
|
+
const still = host.candidate(id);
|
|
5965
|
+
if (still !== void 0) host.setPreviewId(still);
|
|
5966
|
+
}, 600);
|
|
5941
5967
|
return;
|
|
5942
5968
|
}
|
|
5943
5969
|
timer = setTimeout(() => {
|
|
@@ -6279,6 +6305,7 @@ function isBackground(event) {
|
|
|
6279
6305
|
function createGestureHandlers(host) {
|
|
6280
6306
|
const pointers = /* @__PURE__ */ new Map();
|
|
6281
6307
|
let pan;
|
|
6308
|
+
let dragged = false;
|
|
6282
6309
|
let pinch;
|
|
6283
6310
|
const screenOf = (event) => {
|
|
6284
6311
|
const rect = host.svgRect();
|
|
@@ -6289,11 +6316,13 @@ function createGestureHandlers(host) {
|
|
|
6289
6316
|
x: (a.x + b.x) / 2,
|
|
6290
6317
|
y: (a.y + b.y) / 2
|
|
6291
6318
|
});
|
|
6292
|
-
const startPan = (pointerId, screen) => {
|
|
6319
|
+
const startPan = (pointerId, screen, downClient, armed) => {
|
|
6293
6320
|
pan = {
|
|
6294
6321
|
pointerId,
|
|
6295
6322
|
start: diskOf(screen),
|
|
6296
|
-
baseView: host.takeView()
|
|
6323
|
+
baseView: host.takeView(),
|
|
6324
|
+
downClient,
|
|
6325
|
+
armed
|
|
6297
6326
|
};
|
|
6298
6327
|
};
|
|
6299
6328
|
const startPinch = () => {
|
|
@@ -6309,14 +6338,21 @@ function createGestureHandlers(host) {
|
|
|
6309
6338
|
};
|
|
6310
6339
|
return {
|
|
6311
6340
|
onPointerDown(event) {
|
|
6312
|
-
|
|
6341
|
+
dragged = false;
|
|
6342
|
+
const onBackground = isBackground(event);
|
|
6313
6343
|
host.focusTree();
|
|
6314
6344
|
const screen = screenOf(event);
|
|
6315
6345
|
if (!screen) return;
|
|
6316
|
-
|
|
6346
|
+
if (onBackground) {
|
|
6347
|
+
event.currentTarget.setPointerCapture?.(event.pointerId);
|
|
6348
|
+
host.onDragStart?.();
|
|
6349
|
+
}
|
|
6317
6350
|
pointers.set(event.pointerId, screen);
|
|
6318
6351
|
if (pointers.size === 2 && host.zoomGesturesEnabled()) startPinch();
|
|
6319
|
-
else if (pointers.size === 1) startPan(event.pointerId, screen
|
|
6352
|
+
else if (pointers.size === 1) startPan(event.pointerId, screen, {
|
|
6353
|
+
x: event.clientX,
|
|
6354
|
+
y: event.clientY
|
|
6355
|
+
}, onBackground);
|
|
6320
6356
|
},
|
|
6321
6357
|
onPointerMove(event) {
|
|
6322
6358
|
if (!pointers.has(event.pointerId)) return;
|
|
@@ -6337,14 +6373,26 @@ function createGestureHandlers(host) {
|
|
|
6337
6373
|
y: mid.y - clampedZoom * pinch.anchor.y
|
|
6338
6374
|
}
|
|
6339
6375
|
}));
|
|
6340
|
-
} else if (pan && pan.pointerId === event.pointerId)
|
|
6376
|
+
} else if (pan && pan.pointerId === event.pointerId) {
|
|
6377
|
+
if (!pan.armed) {
|
|
6378
|
+
if (Math.hypot(event.clientX - pan.downClient.x, event.clientY - pan.downClient.y) < 4) return;
|
|
6379
|
+
pan.armed = true;
|
|
6380
|
+
dragged = true;
|
|
6381
|
+
event.currentTarget.setPointerCapture?.(event.pointerId);
|
|
6382
|
+
host.onDragStart?.();
|
|
6383
|
+
}
|
|
6384
|
+
host.setView(panView(pan.baseView, pan.start, diskOf(screen)));
|
|
6385
|
+
}
|
|
6341
6386
|
},
|
|
6342
6387
|
onPointerUp(event) {
|
|
6343
6388
|
if (!pointers.delete(event.pointerId)) return;
|
|
6344
6389
|
if (pinch) {
|
|
6345
6390
|
pinch = void 0;
|
|
6346
6391
|
const [remaining] = [...pointers.entries()];
|
|
6347
|
-
if (remaining) startPan(remaining[0], remaining[1]
|
|
6392
|
+
if (remaining) startPan(remaining[0], remaining[1], {
|
|
6393
|
+
x: 0,
|
|
6394
|
+
y: 0
|
|
6395
|
+
}, true);
|
|
6348
6396
|
} else if (pan?.pointerId === event.pointerId) pan = void 0;
|
|
6349
6397
|
},
|
|
6350
6398
|
/**
|
|
@@ -6363,6 +6411,14 @@ function createGestureHandlers(host) {
|
|
|
6363
6411
|
const factor = Math.exp(-delta * (modified ? .01 : .002));
|
|
6364
6412
|
host.setZoomState(zoomAt(host.zoomState(), screen, factor));
|
|
6365
6413
|
},
|
|
6414
|
+
/** Whether the view is being dragged right now. */
|
|
6415
|
+
isDragging() {
|
|
6416
|
+
return pan?.armed === true;
|
|
6417
|
+
},
|
|
6418
|
+
/** Whether the last press turned into a drag — so the click that follows it shouldn't count. */
|
|
6419
|
+
wasDragged() {
|
|
6420
|
+
return dragged;
|
|
6421
|
+
},
|
|
6366
6422
|
/** Forget any in-progress pan (e.g. when a focus change takes over the view). */
|
|
6367
6423
|
cancel() {
|
|
6368
6424
|
pan = void 0;
|
|
@@ -6565,6 +6621,15 @@ const hyperbolicTreeStyles = css`
|
|
|
6565
6621
|
border-radius: var(--radius-m, 6px);
|
|
6566
6622
|
box-shadow: var(--shadow-m);
|
|
6567
6623
|
font-size: var(--hyperbolictree-font-size);
|
|
6624
|
+
/* Beside the node, never over it, with the dot level with the popover's middle. */
|
|
6625
|
+
transform: translate(14px, -50%);
|
|
6626
|
+
}
|
|
6627
|
+
|
|
6628
|
+
.child-preview.left {
|
|
6629
|
+
transform: translate(calc(-100% - 14px), -50%);
|
|
6630
|
+
}
|
|
6631
|
+
|
|
6632
|
+
.child-preview.below {
|
|
6568
6633
|
transform: translate(-50%, 14px);
|
|
6569
6634
|
}
|
|
6570
6635
|
|
|
@@ -6573,13 +6638,26 @@ const hyperbolicTreeStyles = css`
|
|
|
6573
6638
|
}
|
|
6574
6639
|
|
|
6575
6640
|
.child-preview-title {
|
|
6641
|
+
display: flex;
|
|
6642
|
+
align-items: center;
|
|
6643
|
+
gap: 4px;
|
|
6576
6644
|
padding: 2px 6px 4px;
|
|
6577
6645
|
font-weight: 600;
|
|
6646
|
+
}
|
|
6647
|
+
|
|
6648
|
+
.child-preview-title span {
|
|
6578
6649
|
overflow: hidden;
|
|
6579
6650
|
text-overflow: ellipsis;
|
|
6580
6651
|
white-space: nowrap;
|
|
6581
6652
|
}
|
|
6582
6653
|
|
|
6654
|
+
.child-preview button.child-preview-up {
|
|
6655
|
+
display: inline-flex;
|
|
6656
|
+
flex: none;
|
|
6657
|
+
width: auto;
|
|
6658
|
+
padding: 2px;
|
|
6659
|
+
}
|
|
6660
|
+
|
|
6583
6661
|
.child-preview ul {
|
|
6584
6662
|
margin: 0;
|
|
6585
6663
|
padding: 0;
|
|
@@ -7535,7 +7613,6 @@ function renderNodeGroup(n, args, transform, content) {
|
|
|
7535
7613
|
part="node node-${partToken(key)}"
|
|
7536
7614
|
style=${weightStyle + branchStyle(id, ctx.branches)}
|
|
7537
7615
|
transform=${transform}
|
|
7538
|
-
@pointerdown=${handlers.onPointerDown}
|
|
7539
7616
|
@mousedown=${preventMouseDownFocus}
|
|
7540
7617
|
@click=${(e) => handlers.onClick(n, e)}
|
|
7541
7618
|
@dblclick=${(e) => handlers.onDblClick(n, e)}
|
|
@@ -7657,8 +7734,9 @@ let HyperbolicTreeListElement = class HyperbolicTreeListElement extends LitEleme
|
|
|
7657
7734
|
candidate: (id) => {
|
|
7658
7735
|
const nodes = this.#layout().nodes;
|
|
7659
7736
|
const n = id === void 0 || this.disableChildPreview ? void 0 : nodes.find((v) => v.id === id);
|
|
7660
|
-
return n && needsChildPreview(n, nodes, this.#lastLabelIds) ? n.id : void 0;
|
|
7737
|
+
return n && !this.#gestures.isDragging() && needsChildPreview(n, nodes, this.#lastLabelIds) ? n.id : void 0;
|
|
7661
7738
|
},
|
|
7739
|
+
currentId: () => this._previewId,
|
|
7662
7740
|
setPreviewId: (id) => {
|
|
7663
7741
|
this._previewId = id;
|
|
7664
7742
|
}
|
|
@@ -7701,6 +7779,7 @@ let HyperbolicTreeListElement = class HyperbolicTreeListElement extends LitEleme
|
|
|
7701
7779
|
};
|
|
7702
7780
|
this.#gestures = createGestureHandlers({
|
|
7703
7781
|
svgRect: () => this.renderRoot.querySelector(`svg.hyperbolictree`)?.getBoundingClientRect(),
|
|
7782
|
+
onDragStart: () => this.#preview.hide(),
|
|
7704
7783
|
takeView: () => {
|
|
7705
7784
|
const view = this.#currentView();
|
|
7706
7785
|
this.#cancelAnimation();
|
|
@@ -8170,10 +8249,6 @@ let HyperbolicTreeListElement = class HyperbolicTreeListElement extends LitEleme
|
|
|
8170
8249
|
#focusTree() {
|
|
8171
8250
|
this.renderRoot.querySelector(`svg.hyperbolictree`)?.focus({ preventScroll: true });
|
|
8172
8251
|
}
|
|
8173
|
-
#handleNodePointerDown(event) {
|
|
8174
|
-
event.stopPropagation();
|
|
8175
|
-
this.#focusTree();
|
|
8176
|
-
}
|
|
8177
8252
|
#pickPreviewChild(child) {
|
|
8178
8253
|
this.#preview.hide();
|
|
8179
8254
|
if (this.interactionMode !== `manual`) this.select(child);
|
|
@@ -8187,10 +8262,12 @@ let HyperbolicTreeListElement = class HyperbolicTreeListElement extends LitEleme
|
|
|
8187
8262
|
if (!n) return void 0;
|
|
8188
8263
|
const { width, height } = this._hostSize;
|
|
8189
8264
|
const anchor = diskToHostPx(n.position, this.#zoomState(), width || 420, height || 420);
|
|
8265
|
+
const parent = n.parentId === void 0 ? void 0 : nodes.find((v) => v.id === n.parentId)?.node;
|
|
8190
8266
|
return {
|
|
8191
8267
|
node: n.node,
|
|
8192
8268
|
anchor,
|
|
8193
|
-
|
|
8269
|
+
side: choosePreviewSide(anchor, width || 420, height || 420),
|
|
8270
|
+
parent
|
|
8194
8271
|
};
|
|
8195
8272
|
}
|
|
8196
8273
|
#nodeContext(nodes, branches) {
|
|
@@ -8221,14 +8298,13 @@ let HyperbolicTreeListElement = class HyperbolicTreeListElement extends LitEleme
|
|
|
8221
8298
|
isPending: (node) => this.#lazy.isPending(node)
|
|
8222
8299
|
},
|
|
8223
8300
|
handlers: {
|
|
8224
|
-
onPointerDown: (e) => this.#handleNodePointerDown(e),
|
|
8225
8301
|
onClick: (n, e) => {
|
|
8226
8302
|
e.stopPropagation();
|
|
8227
|
-
this.#handleItemClick(n, e);
|
|
8303
|
+
if (!this.#gestures.wasDragged()) this.#handleItemClick(n, e);
|
|
8228
8304
|
},
|
|
8229
8305
|
onDblClick: (n, e) => {
|
|
8230
8306
|
e.stopPropagation();
|
|
8231
|
-
this.#handleItemDblClick(n);
|
|
8307
|
+
if (!this.#gestures.wasDragged()) this.#handleItemDblClick(n);
|
|
8232
8308
|
},
|
|
8233
8309
|
onPointerEnter: (id) => this.tickled.handlePointerEnter(id)
|
|
8234
8310
|
}
|
|
@@ -10026,7 +10102,7 @@ let MulticolListElement = class MulticolListElement extends LitElement {
|
|
|
10026
10102
|
><span class="ixfx-handle" data-handle="dotted" data-shape="vertical" part="reorder-handle"></span></span>
|
|
10027
10103
|
<button
|
|
10028
10104
|
class="column-label"
|
|
10029
|
-
data-tooltip
|
|
10105
|
+
data-tooltip=${this._getCategoryTooltip(col.categoryKey)}
|
|
10030
10106
|
@click=${(e) => {
|
|
10031
10107
|
e.stopPropagation();
|
|
10032
10108
|
this._openCategoryPicker(col, e.currentTarget);
|
|
@@ -10056,6 +10132,10 @@ let MulticolListElement = class MulticolListElement extends LitElement {
|
|
|
10056
10132
|
_getCategoryLabel(key) {
|
|
10057
10133
|
return this.categories.find((c) => c.key === key)?.label ?? key;
|
|
10058
10134
|
}
|
|
10135
|
+
/** Category description if present, else the default 'Change category' hint. */
|
|
10136
|
+
_getCategoryTooltip(key) {
|
|
10137
|
+
return this.categories.find((c) => c.key === key)?.description ?? `Change category`;
|
|
10138
|
+
}
|
|
10059
10139
|
#createController(id, category) {
|
|
10060
10140
|
return new MulticolColumnController({
|
|
10061
10141
|
id,
|
|
@@ -2386,6 +2386,69 @@ let TreeBaseElement = class TreeBaseElement extends LitElement {
|
|
|
2386
2386
|
this.#dispatchSelect(prev);
|
|
2387
2387
|
this.requestUpdate();
|
|
2388
2388
|
}
|
|
2389
|
+
/**
|
|
2390
|
+
* Expand every already-loaded branch in a single update. With `maxDepth`,
|
|
2391
|
+
* only branches at depth < `maxDepth` are expanded (the root's children are
|
|
2392
|
+
* depth 0), so rows at depth `maxDepth` become visible but stay collapsed.
|
|
2393
|
+
*
|
|
2394
|
+
* Unloaded (lazy) branches are not fetched — call again once their children
|
|
2395
|
+
* have loaded to expand further. Bulk expansion ignores `exclusivity`. Fires
|
|
2396
|
+
* one `expand` event per branch that actually opens — none for branches that
|
|
2397
|
+
* were already expanded, including ones opened by filter auto-expansion.
|
|
2398
|
+
*/
|
|
2399
|
+
expandAll(maxDepth) {
|
|
2400
|
+
this.#bulkExpand(true, maxDepth);
|
|
2401
|
+
}
|
|
2402
|
+
/**
|
|
2403
|
+
* Collapse expanded branches in a single update. With `maxDepth`, only
|
|
2404
|
+
* branches at depth >= `maxDepth` are collapsed, leaving the tree open down
|
|
2405
|
+
* to depth `maxDepth - 1` (`collapseAll(0)` is a full collapse). Fires one
|
|
2406
|
+
* `collapse` event per branch that actually closes.
|
|
2407
|
+
*/
|
|
2408
|
+
collapseAll(maxDepth) {
|
|
2409
|
+
this.#bulkExpand(false, maxDepth);
|
|
2410
|
+
}
|
|
2411
|
+
/** Shared bulk expand / collapse: one `_expandedKeys` write, per-node events for real changes only. */
|
|
2412
|
+
#bulkExpand(expand, maxDepth) {
|
|
2413
|
+
const root = this.root;
|
|
2414
|
+
if (!root) return;
|
|
2415
|
+
const inScope = (depth) => expand ? depth < (maxDepth ?? Number.POSITIVE_INFINITY) : depth >= (maxDepth ?? 0);
|
|
2416
|
+
const changed = [];
|
|
2417
|
+
let next = this._expandedKeys;
|
|
2418
|
+
const visit = (node, depth) => {
|
|
2419
|
+
const children = node.children;
|
|
2420
|
+
if (node.item.isLeaf !== true && children !== void 0 && children.length > 0 && inScope(depth)) {
|
|
2421
|
+
const keyed = next.has(node.item.key);
|
|
2422
|
+
if (expand && !keyed) {
|
|
2423
|
+
next = withKey(next, node.item.key);
|
|
2424
|
+
if (!this._isExpanded(node, depth)) changed.push({
|
|
2425
|
+
node,
|
|
2426
|
+
depth
|
|
2427
|
+
});
|
|
2428
|
+
} else if (!expand && keyed) {
|
|
2429
|
+
next = withoutKey(next, node.item.key);
|
|
2430
|
+
changed.push({
|
|
2431
|
+
node,
|
|
2432
|
+
depth
|
|
2433
|
+
});
|
|
2434
|
+
}
|
|
2435
|
+
}
|
|
2436
|
+
for (const child of children ?? []) visit(child, depth + 1);
|
|
2437
|
+
};
|
|
2438
|
+
for (const child of root.children ?? []) visit(child, 0);
|
|
2439
|
+
if (next === this._expandedKeys) return;
|
|
2440
|
+
this.#setExpanded(next);
|
|
2441
|
+
const type = expand ? `expand` : `collapse`;
|
|
2442
|
+
for (const { node, depth } of changed) this.dispatchEvent(new CustomEvent(type, {
|
|
2443
|
+
detail: {
|
|
2444
|
+
node,
|
|
2445
|
+
depth
|
|
2446
|
+
},
|
|
2447
|
+
bubbles: true,
|
|
2448
|
+
composed: true
|
|
2449
|
+
}));
|
|
2450
|
+
this.requestUpdate();
|
|
2451
|
+
}
|
|
2389
2452
|
navigateTo(keys, options = {}) {
|
|
2390
2453
|
if (!this.root?.children) return false;
|
|
2391
2454
|
const prevOrigin = this.#selectOrigin;
|
package/dist/tree.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { A as TreeTickleEvent, D as TreeSelectDetail, M as TreeDataModelOptions, O as TreeSelectEvent, T as TreeRevealMode, _ as TreeDropTarget, b as TreeItemClickDetail, c as TreeDragContext, d as TreeDragStartEvent, g as TreeDropPosition, h as TreeDropEvent, i as TreeCollapseEvent, j as TreeDataModel, k as TreeTickleDetail, l as TreeDragEndEvent, m as TreeDropDetail, n as TreeActivateEvent, o as TreeComponentEventMap, p as TreeDropContext, r as TreeCollapseDetail, s as TreeDndMode, t as TreeActivateDetail, u as TreeDragOverEvent, v as TreeExpandDetail, w as TreeNavigateOptions, x as TreeItemClickEvent, y as TreeExpandEvent } from "./tree-component-Tslymyyl.js";
|
|
2
2
|
import { a as TreeItem, n as TreeExclusivity, o as TreeNode, r as TreeFilterPredicate, s as TreeSelectionFilter, t as LoadChildrenCallback } from "./types-DQ7KOUIj.js";
|
|
3
|
-
import { a as TreeDropVisibleRow, c as TreeListElement, d as TreeBaseElementEventMap, f as TreeVirtualize, i as TreeDropRowInfo, l as TreeCheckboxState, n as TreeDropControllerConfig, o as TreeController, p as TreeConfig, r as TreeDropResolvedDrag, s as TreeControllerOptions, t as TreeDropController, u as TreeBaseElement } from "./index-
|
|
3
|
+
import { a as TreeDropVisibleRow, c as TreeListElement, d as TreeBaseElementEventMap, f as TreeVirtualize, i as TreeDropRowInfo, l as TreeCheckboxState, n as TreeDropControllerConfig, o as TreeController, p as TreeConfig, r as TreeDropResolvedDrag, s as TreeControllerOptions, t as TreeDropController, u as TreeBaseElement } from "./index-CSCrK0hR.js";
|
|
4
4
|
export { type LoadChildrenCallback, type TreeActivateDetail, type TreeActivateEvent, TreeBaseElement, TreeBaseElementEventMap, type TreeCheckboxState, type TreeCollapseDetail, type TreeCollapseEvent, type TreeComponentEventMap, TreeConfig, TreeController, TreeControllerOptions, TreeDataModel, type TreeDataModelOptions, type TreeDndMode, type TreeDragContext, type TreeDragEndEvent, type TreeDragOverEvent, type TreeDragStartEvent, type TreeDropContext, TreeDropController, TreeDropControllerConfig, type TreeDropDetail, type TreeDropEvent, type TreeDropPosition, TreeDropResolvedDrag, TreeDropRowInfo, type TreeDropTarget, TreeDropVisibleRow, type TreeExclusivity, type TreeExpandDetail, type TreeExpandEvent, type TreeFilterPredicate, type TreeItem, type TreeItemClickDetail, type TreeItemClickEvent, TreeListElement, type TreeNavigateOptions, type TreeNode, type TreeRevealMode, type TreeSelectDetail, type TreeSelectEvent, type TreeSelectionFilter, type TreeTickleDetail, type TreeTickleEvent, TreeVirtualize };
|
package/dist/tree.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as TreeDataModel, i as TreeDropController, n as TreeListElement, r as TreeBaseElement, t as TreeController } from "./tree-
|
|
1
|
+
import { a as TreeDataModel, i as TreeDropController, n as TreeListElement, r as TreeBaseElement, t as TreeController } from "./tree-9Hs7VxuX.js";
|
|
2
2
|
export { TreeBaseElement, TreeController, TreeDataModel, TreeDropController, TreeListElement };
|
|
@@ -118,7 +118,7 @@ Labels keep their on-screen size while zooming, so zooming in spreads a crowd ap
|
|
|
118
118
|
|
|
119
119
|
### Child preview
|
|
120
120
|
|
|
121
|
-
On by default; `disable-child-preview` turns it off. Hovering or keyboard-tickling a node whose children aren't all legible opens a popover listing them. That means some children had their labels culled, or sit beyond `maxRadius`. It shows up to 12 children, then "+N more". Clicking an entry focuses that child and selects it, per `interactionMode`. The popover stays open while the pointer moves onto it, and Escape closes it. Style it with `::part(child-preview)`. Nodes that can show a preview drop their native `<title>` tooltip so the two don't stack. With the preview disabled, every node keeps its tooltip.
|
|
121
|
+
On by default; `disable-child-preview` turns it off. Hovering or keyboard-tickling a node whose children aren't all legible, and resting there for 600ms, opens a popover listing them. That means some children had their labels culled, or sit beyond `maxRadius`. It shows up to 12 children, then "+N more". Clicking an entry focuses that child and selects it, per `interactionMode`. The popover stays open while the pointer moves onto it, and Escape closes it. Starting a drag (pan) cancels a pending preview and closes an open one. Style it with `::part(child-preview)`. Nodes that can show a preview drop their native `<title>` tooltip so the two don't stack. With the preview disabled, every node keeps its tooltip.
|
|
122
122
|
|
|
123
123
|
### Crowded fans
|
|
124
124
|
|
package/docs-user/index.json
CHANGED
|
@@ -17,7 +17,7 @@ provider returns that column's choices; items may carry a `count` for display.
|
|
|
17
17
|
|
|
18
18
|
| Property | Type | Default | Description |
|
|
19
19
|
|----------|------|---------|-------------|
|
|
20
|
-
| `categories` | `readonly MulticolCategory[]` | `[]` | Facet definitions (tree, shown in the header picker menu). Each may carry `defaults`: `grouped`, `groupBy`, `allLabel`, `sort`. |
|
|
20
|
+
| `categories` | `readonly MulticolCategory[]` | `[]` | Facet definitions (tree, shown in the header picker menu). Each may carry `description` (shown as a tooltip on the column header label) and `defaults`: `grouped`, `groupBy`, `allLabel`, `sort`. |
|
|
21
21
|
| `dataProvider` | `IDataProvider<MulticolQuery, MulticolItem>` \| `undefined` | — | Called per column whenever that column's inputs change. Sync arrays, Promises and async-iterables are supported; the `AbortSignal` is honoured. |
|
|
22
22
|
| `selectionMode` | `ListSelectionMode` | `'multiple'` | `'none'`, `'single'` or `'multiple'` selection within a column. |
|
|
23
23
|
| `minColumns` | `number` | `1` | Floor for column removal. |
|
package/docs-user/tree.md
CHANGED
|
@@ -330,6 +330,39 @@ el.addEventListener('select', ({ detail }) => {
|
|
|
330
330
|
|
|
331
331
|
---
|
|
332
332
|
|
|
333
|
+
## Expansion
|
|
334
|
+
|
|
335
|
+
### Programmatic expansion
|
|
336
|
+
|
|
337
|
+
```typescript
|
|
338
|
+
// Expand every already-loaded branch
|
|
339
|
+
el.expandAll();
|
|
340
|
+
|
|
341
|
+
// Expand down to depth 1: top-level branches open, so their children
|
|
342
|
+
// (depth 1) are visible (root's children are depth 0)
|
|
343
|
+
el.expandAll(1);
|
|
344
|
+
|
|
345
|
+
// Collapse everything
|
|
346
|
+
el.collapseAll();
|
|
347
|
+
|
|
348
|
+
// Collapse branches at depth 1 and deeper — top-level branches stay open,
|
|
349
|
+
// so the tree remains open down to depth 0
|
|
350
|
+
el.collapseAll(1);
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
Notes:
|
|
354
|
+
|
|
355
|
+
- Both methods apply in a single update — one re-render for the whole tree.
|
|
356
|
+
- Only **already-loaded** branches are expanded; lazily loaded children are not
|
|
357
|
+
fetched. Call `expandAll()` again after children load to expand further.
|
|
358
|
+
- Bulk expansion ignores `exclusivity` — it is an explicit "open everything"
|
|
359
|
+
command.
|
|
360
|
+
- One `expand` / `collapse` event fires per branch whose state actually changes;
|
|
361
|
+
branches already in the target state (including those opened by filter
|
|
362
|
+
auto-expansion) stay silent.
|
|
363
|
+
|
|
364
|
+
---
|
|
365
|
+
|
|
333
366
|
## Events
|
|
334
367
|
|
|
335
368
|
All events **bubble** and are **composed** (cross shadow-DOM boundaries).
|