@ixfx/components 0.10.0 → 0.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundle/index.d.ts +60 -1
- package/bundle/index.d.ts.map +1 -1
- package/bundle/index.js +257 -30
- package/bundle/index.js.map +1 -1
- package/bundle/style.css +38 -85
- package/dist/ac-text.d.ts +1 -1
- package/dist/{ac-token--_vCHXWw.d.ts → ac-token-TCLAZeVg.d.ts} +2 -2
- package/dist/{ac-token--_vCHXWw.d.ts.map → ac-token-TCLAZeVg.d.ts.map} +1 -1
- package/dist/ac-token.d.ts +1 -1
- package/dist/button.d.ts +1 -1
- package/dist/button.d.ts.map +1 -1
- package/dist/colour-picker.d.ts +1 -1
- package/dist/crumbs.d.ts +2 -2
- package/dist/{data-grid-C5hk_pzK.d.ts → data-grid-BT1d_nlu.d.ts} +4 -4
- package/dist/{data-grid-C5hk_pzK.d.ts.map → data-grid-BT1d_nlu.d.ts.map} +1 -1
- package/dist/data-grid.d.ts +2 -2
- package/dist/data-grid.js +1 -1
- package/dist/{detail-list-CxPpv89T.d.ts → detail-list-BCaIN7nx.d.ts} +5 -5
- package/dist/{detail-list-CxPpv89T.d.ts.map → detail-list-BCaIN7nx.d.ts.map} +1 -1
- package/dist/detail-list.d.ts +3 -3
- package/dist/detail-list.js +1 -1
- package/dist/{grid-list-BGvoWbZz.d.ts → grid-list-CiwlNE4c.d.ts} +4 -4
- package/dist/{grid-list-BGvoWbZz.d.ts.map → grid-list-CiwlNE4c.d.ts.map} +1 -1
- package/dist/{grid-list-DSnYOGh7.js → grid-list-DLfw5HI4.js} +10 -5
- package/dist/grid-list-DLfw5HI4.js.map +1 -0
- package/dist/grid-list.d.ts +2 -2
- package/dist/grid-list.js +1 -1
- package/dist/{grouped-item-lister-fdZHVxFM.d.ts → grouped-item-lister-CEZ72VOs.d.ts} +2 -2
- package/dist/{grouped-item-lister-fdZHVxFM.d.ts.map → grouped-item-lister-CEZ72VOs.d.ts.map} +1 -1
- package/dist/grouped-item-lister.d.ts +1 -1
- package/dist/{icon-CDGprSdE.d.ts → icon-DR_3rSyZ.d.ts} +2 -2
- package/dist/icon-DR_3rSyZ.d.ts.map +1 -0
- package/dist/icons.d.ts +2 -2
- package/dist/incr-search.d.ts +1 -1
- package/dist/{index-tq6f8007.d.ts → index-BOUaDIW-.d.ts} +2 -2
- package/dist/{index-tq6f8007.d.ts.map → index-BOUaDIW-.d.ts.map} +1 -1
- package/dist/{index-CoqtMSd9.d.ts → index-BUB5SICW.d.ts} +2 -2
- package/dist/{index-CoqtMSd9.d.ts.map → index-BUB5SICW.d.ts.map} +1 -1
- package/dist/{index-9AhaHIT2.d.ts → index-C59-JEPl.d.ts} +3 -3
- package/dist/{index-9AhaHIT2.d.ts.map → index-C59-JEPl.d.ts.map} +1 -1
- package/dist/{index-UvnoZUAo.d.ts → index-CJ5fshD3.d.ts} +2 -2
- package/dist/{index-UvnoZUAo.d.ts.map → index-CJ5fshD3.d.ts.map} +1 -1
- package/dist/{index--5BSdbnL.d.ts → index-DPFrRhKL.d.ts} +2 -2
- package/dist/{index--5BSdbnL.d.ts.map → index-DPFrRhKL.d.ts.map} +1 -1
- package/dist/{index-CS9yM8L-.d.ts → index-DsjpDksO.d.ts} +2 -2
- package/dist/{index-CS9yM8L-.d.ts.map → index-DsjpDksO.d.ts.map} +1 -1
- package/dist/index.d.ts +66 -20
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +247 -27
- package/dist/index.js.map +1 -1
- package/dist/{labelled-input-base-DiTme1JO.d.ts → labelled-input-base-Dp_9KP0G.d.ts} +2 -2
- package/dist/{labelled-input-base-DiTme1JO.d.ts.map → labelled-input-base-Dp_9KP0G.d.ts.map} +1 -1
- package/dist/labelled-radial-input.d.ts +2 -2
- package/dist/labelled-radial-input.d.ts.map +1 -1
- package/dist/labelled-range-input.d.ts +1 -1
- package/dist/labelled-slider-input.d.ts +1 -1
- package/dist/{list-native-drag-controller-D97TYjn1.js → list-native-drag-controller-B9xO0XWn.js} +6 -4
- package/dist/list-native-drag-controller-B9xO0XWn.js.map +1 -0
- package/dist/{list-native-drag-controller-DWiXQZou.d.ts → list-native-drag-controller-BAuWAtyQ.d.ts} +2 -2
- package/dist/{list-native-drag-controller-DWiXQZou.d.ts.map → list-native-drag-controller-BAuWAtyQ.d.ts.map} +1 -1
- package/dist/{menu-item-CZi9vy5O.d.ts → menu-item-ZmkXNjek.d.ts} +2 -2
- package/dist/{menu-item-CZi9vy5O.d.ts.map → menu-item-ZmkXNjek.d.ts.map} +1 -1
- package/dist/menu.d.ts +2 -2
- package/dist/miller.d.ts +2 -2
- package/dist/panel.d.ts +1 -1
- package/dist/{split-layout-JK3xWVX2.d.ts → split-layout-C5SYbDrq.d.ts} +2 -2
- package/dist/{split-layout-JK3xWVX2.d.ts.map → split-layout-C5SYbDrq.d.ts.map} +1 -1
- package/dist/split-layout.d.ts +1 -1
- package/dist/style.css +38 -85
- package/dist/{tab-list-CGyPt07Z.d.ts → tab-list-DbMIL520.d.ts} +2 -2
- package/dist/{tab-list-CGyPt07Z.d.ts.map → tab-list-DbMIL520.d.ts.map} +1 -1
- package/dist/tabs.d.ts +1 -1
- package/dist/{titlebar-Tqu-VvMU.d.ts → titlebar-B5zSTZnF.d.ts} +2 -2
- package/dist/{titlebar-Tqu-VvMU.d.ts.map → titlebar-B5zSTZnF.d.ts.map} +1 -1
- package/dist/titlebar.d.ts +1 -1
- package/dist/{tree-C25xYUa6.js → tree-BuzWn18_.js} +2 -2
- package/dist/{tree-C25xYUa6.js.map → tree-BuzWn18_.js.map} +1 -1
- package/dist/{tree-component-mw8x-n2Y.d.ts → tree-component-DGmKBbpy.d.ts} +14 -1
- package/dist/tree-component-DGmKBbpy.d.ts.map +1 -0
- package/dist/tree.d.ts +3 -3
- package/dist/tree.js +1 -1
- package/dist/{vertical-list--tFanQwM.d.ts → vertical-list-BLvJ4-Zf.d.ts} +3 -3
- package/dist/{vertical-list--tFanQwM.d.ts.map → vertical-list-BLvJ4-Zf.d.ts.map} +1 -1
- package/dist/vertical-list.d.ts +2 -2
- package/dist/vertical-list.js +1 -1
- package/docs-user/index.json +2 -2
- package/package.json +1 -1
- package/dist/grid-list-DSnYOGh7.js.map +0 -1
- package/dist/icon-CDGprSdE.d.ts.map +0 -1
- package/dist/list-native-drag-controller-D97TYjn1.js.map +0 -1
- package/dist/tree-component-mw8x-n2Y.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -16,7 +16,7 @@ import { i as ICON_CLOSE, n as ICON_CHECK, r as ICON_CHEVRON_DOWN, t as ICON_CAR
|
|
|
16
16
|
import "./icons.js";
|
|
17
17
|
import { t as prominenceStyles } from "./prominence-DlFShic3.js";
|
|
18
18
|
import { n as buttonStyles, t as ButtonElement } from "./button-DsFbV4XD.js";
|
|
19
|
-
import { n as captionForEntry, r as createDefaultListDragPreview, t as ListNativeDragController } from "./list-native-drag-controller-
|
|
19
|
+
import { n as captionForEntry, r as createDefaultListDragPreview, t as ListNativeDragController } from "./list-native-drag-controller-B9xO0XWn.js";
|
|
20
20
|
import { n as isMultiMode, r as ListDragSelectController, t as ListSelectionController } from "./list-selection-controller-SA4piSBi.js";
|
|
21
21
|
import { a as prefersReducedMotion, i as listItemFadeKeyframes, n as animateListItemIn, o as startListItemOutAnimation, r as animateListItemOut, t as LIST_ITEM_MOTION_MS } from "./list-item-animation-BUoEKi5s.js";
|
|
22
22
|
import "./interaction-BskmlA9t.js";
|
|
@@ -25,7 +25,7 @@ import { Checkbox } from "./checkbox.js";
|
|
|
25
25
|
import { n as ColourPicker, t as ColourPickerPopup } from "./colour-picker-R73i0QTP.js";
|
|
26
26
|
import { LabelledRangeInput } from "./labelled-range-input.js";
|
|
27
27
|
import { t as collectDataResult } from "./data-provider-35TyWclX.js";
|
|
28
|
-
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-
|
|
28
|
+
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-BuzWn18_.js";
|
|
29
29
|
import { t as scrollFadeStyles } from "./scroll-fade-CAs1EabA.js";
|
|
30
30
|
import { NarrowedTextElement } from "./narrowed-text.js";
|
|
31
31
|
import { CrumbNavigationElement } from "./crumbs.js";
|
|
@@ -40,7 +40,7 @@ import { TabListElement } from "./tabs.js";
|
|
|
40
40
|
import { EditableLabel } from "./editable-label.js";
|
|
41
41
|
import { n as EditableNumber, t as LabelledSliderInput } from "./labelled-slider-input-CF2RtzgG.js";
|
|
42
42
|
import { t as FormElement } from "./form-CsXJX15p.js";
|
|
43
|
-
import { t as GridListElement } from "./grid-list-
|
|
43
|
+
import { t as GridListElement } from "./grid-list-DLfw5HI4.js";
|
|
44
44
|
import { PanelElement } from "./panel.js";
|
|
45
45
|
import { GroupedItemListerElement } from "./grouped-item-lister.js";
|
|
46
46
|
import { VerticalListElement } from "./vertical-list.js";
|
|
@@ -9731,12 +9731,16 @@ function subdivide(box, weights, method, relativeDepth) {
|
|
|
9731
9731
|
*/
|
|
9732
9732
|
function computeTreemapLayout(root, options = {}) {
|
|
9733
9733
|
if (!root?.children?.length) return [];
|
|
9734
|
-
const { maxDepth = Number.POSITIVE_INFINITY, valueAccessor = () => 1, zoomKey, tilingMethod = `squarify
|
|
9734
|
+
const { maxDepth = Number.POSITIVE_INFINITY, valueAccessor = () => 1, zoomKey, tilingMethod = `squarify`, hideLeaves = false } = options;
|
|
9735
9735
|
if (maxDepth <= 0) return [];
|
|
9736
|
+
const visibleChildren = (node) => {
|
|
9737
|
+
const children = node.children ?? [];
|
|
9738
|
+
return hideLeaves ? children.filter((n) => n.item.isLeaf !== true) : children;
|
|
9739
|
+
};
|
|
9736
9740
|
const zoomNode = zoomKey === void 0 ? root : findTreemapNode(root, zoomKey) ?? root;
|
|
9737
9741
|
const zoomPath = findTreemapPath(root, zoomNode.item.key);
|
|
9738
9742
|
const zoomDepth = zoomPath ? zoomPath.length - 2 : -1;
|
|
9739
|
-
const siblings = zoomNode
|
|
9743
|
+
const siblings = visibleChildren(zoomNode);
|
|
9740
9744
|
if (siblings.length === 0) return [];
|
|
9741
9745
|
const rects = [];
|
|
9742
9746
|
const layoutLevel = (nodes, box, depth, relativeDepth, parentKey) => {
|
|
@@ -9745,7 +9749,7 @@ function computeTreemapLayout(root, options = {}) {
|
|
|
9745
9749
|
const setSize = nodes.length;
|
|
9746
9750
|
nodes.forEach((node, index) => {
|
|
9747
9751
|
const childBox = boxes[index];
|
|
9748
|
-
const children = node
|
|
9752
|
+
const children = visibleChildren(node);
|
|
9749
9753
|
rects.push({
|
|
9750
9754
|
node,
|
|
9751
9755
|
depth,
|
|
@@ -9780,8 +9784,11 @@ let TreemapListElement = class TreemapListElement extends LitElement {
|
|
|
9780
9784
|
this.interactionMode = `standard`;
|
|
9781
9785
|
this.tilingMethod = `squarify`;
|
|
9782
9786
|
this.maxDepth = 4;
|
|
9787
|
+
this.hideLeaves = false;
|
|
9783
9788
|
this.minLabelArea = 1600;
|
|
9789
|
+
this.minTileWidth = 24;
|
|
9784
9790
|
this.padding = 4;
|
|
9791
|
+
this.minChildArea = 400;
|
|
9785
9792
|
this.valueAccessor = () => 1;
|
|
9786
9793
|
this._selectedNodes = /* @__PURE__ */ new Set();
|
|
9787
9794
|
this.disableKeyboardNavigation = false;
|
|
@@ -9815,6 +9822,7 @@ let TreemapListElement = class TreemapListElement extends LitElement {
|
|
|
9815
9822
|
});
|
|
9816
9823
|
this.#pendingKeys = /* @__PURE__ */ new Set();
|
|
9817
9824
|
this.#aborters = /* @__PURE__ */ new Map();
|
|
9825
|
+
this.#wheelCooldownUntil = 0;
|
|
9818
9826
|
}
|
|
9819
9827
|
get selectedNodes() {
|
|
9820
9828
|
return this._selectedNodes;
|
|
@@ -9831,15 +9839,22 @@ let TreemapListElement = class TreemapListElement extends LitElement {
|
|
|
9831
9839
|
#ownedRegistry;
|
|
9832
9840
|
#unregisterSearchCommands;
|
|
9833
9841
|
#resizeObserver;
|
|
9842
|
+
#pendingFlip;
|
|
9843
|
+
/** `performance.now()` timestamp before which further Cmd+wheel zoom steps are ignored. */
|
|
9844
|
+
#wheelCooldownUntil;
|
|
9834
9845
|
get #effectiveRoot() {
|
|
9835
9846
|
return this.model?.root ?? this.root;
|
|
9836
9847
|
}
|
|
9837
9848
|
#rects() {
|
|
9849
|
+
return this.#rectsForZoom(this._zoomKey);
|
|
9850
|
+
}
|
|
9851
|
+
#rectsForZoom(zoomKey) {
|
|
9838
9852
|
return computeTreemapLayout(this.#effectiveRoot, {
|
|
9839
9853
|
valueAccessor: this.valueAccessor,
|
|
9840
9854
|
maxDepth: this.maxDepth,
|
|
9841
|
-
zoomKey
|
|
9842
|
-
tilingMethod: this.tilingMethod
|
|
9855
|
+
zoomKey,
|
|
9856
|
+
tilingMethod: this.tilingMethod,
|
|
9857
|
+
hideLeaves: this.hideLeaves
|
|
9843
9858
|
});
|
|
9844
9859
|
}
|
|
9845
9860
|
connectedCallback() {
|
|
@@ -9915,8 +9930,14 @@ let TreemapListElement = class TreemapListElement extends LitElement {
|
|
|
9915
9930
|
if (changedProps.has(`searchModes`)) this.#syncSearchCommands();
|
|
9916
9931
|
if (this._zoomKey !== void 0 && !findTreemapNode(this.#effectiveRoot, this._zoomKey)) this._zoomKey = void 0;
|
|
9917
9932
|
this.#ensureVisibleChildren();
|
|
9933
|
+
if (this.#pendingFlip) {
|
|
9934
|
+
const flip = this.#pendingFlip;
|
|
9935
|
+
this.#pendingFlip = void 0;
|
|
9936
|
+
this.#applyFlip(flip);
|
|
9937
|
+
}
|
|
9918
9938
|
}
|
|
9919
9939
|
#resetViewState() {
|
|
9940
|
+
this.#pendingFlip = void 0;
|
|
9920
9941
|
this.#clearSelectionInternal();
|
|
9921
9942
|
this.tickled.clearTickled();
|
|
9922
9943
|
this._zoomKey = void 0;
|
|
@@ -10029,6 +10050,7 @@ let TreemapListElement = class TreemapListElement extends LitElement {
|
|
|
10029
10050
|
*/
|
|
10030
10051
|
zoomTo(node) {
|
|
10031
10052
|
if (this._zoomKey === node.item.key) return;
|
|
10053
|
+
this.#pendingFlip = this.#planFlip(node.item.key);
|
|
10032
10054
|
this._zoomKey = node.item.key;
|
|
10033
10055
|
this.tickled.clearTickled();
|
|
10034
10056
|
const depth = findTreemapPath(this.#effectiveRoot, node.item.key)?.length;
|
|
@@ -10057,6 +10079,7 @@ let TreemapListElement = class TreemapListElement extends LitElement {
|
|
|
10057
10079
|
*/
|
|
10058
10080
|
zoomOut() {
|
|
10059
10081
|
if (this._zoomKey === void 0) return;
|
|
10082
|
+
this.#pendingFlip = this.#planFlip(void 0);
|
|
10060
10083
|
const previous = this.focusedNode;
|
|
10061
10084
|
const path = this._zoomKey === void 0 ? void 0 : findTreemapPath(this.#effectiveRoot, this._zoomKey);
|
|
10062
10085
|
const absoluteDepth = path === void 0 ? -1 : path.length - 2;
|
|
@@ -10080,9 +10103,66 @@ let TreemapListElement = class TreemapListElement extends LitElement {
|
|
|
10080
10103
|
}));
|
|
10081
10104
|
this.requestUpdate();
|
|
10082
10105
|
}
|
|
10106
|
+
/**
|
|
10107
|
+
* Work out (before `_zoomKey` changes) whether the upcoming zoom should
|
|
10108
|
+
* animate, and how — see `FlipPlan`. Returns `undefined` to skip the
|
|
10109
|
+
* animation: reduced-motion is requested, or the node needed to anchor it
|
|
10110
|
+
* isn't in either the old or new layout's visible window.
|
|
10111
|
+
*/
|
|
10112
|
+
#planFlip(targetKey) {
|
|
10113
|
+
if (typeof matchMedia === `function` && matchMedia(`(prefers-reduced-motion: reduce)`).matches) return void 0;
|
|
10114
|
+
if (targetKey !== void 0) {
|
|
10115
|
+
const visible = this.#rects().find((r) => r.node.item.key === targetKey);
|
|
10116
|
+
if (visible) return {
|
|
10117
|
+
direction: `in`,
|
|
10118
|
+
rect: {
|
|
10119
|
+
x: visible.x,
|
|
10120
|
+
y: visible.y,
|
|
10121
|
+
width: visible.width,
|
|
10122
|
+
height: visible.height
|
|
10123
|
+
}
|
|
10124
|
+
};
|
|
10125
|
+
}
|
|
10126
|
+
const fromKey = this._zoomKey;
|
|
10127
|
+
if (fromKey === void 0) return void 0;
|
|
10128
|
+
const landing = this.#rectsForZoom(targetKey).find((r) => r.node.item.key === fromKey);
|
|
10129
|
+
if (!landing) return void 0;
|
|
10130
|
+
return {
|
|
10131
|
+
direction: `out`,
|
|
10132
|
+
rect: {
|
|
10133
|
+
x: landing.x,
|
|
10134
|
+
y: landing.y,
|
|
10135
|
+
width: landing.width,
|
|
10136
|
+
height: landing.height
|
|
10137
|
+
}
|
|
10138
|
+
};
|
|
10139
|
+
}
|
|
10140
|
+
/** Apply a planned FLIP animation once the new layout has rendered — see `FlipPlan`. */
|
|
10141
|
+
#applyFlip(flip) {
|
|
10142
|
+
const inner = this.renderRoot.querySelector(`.viewport-inner`);
|
|
10143
|
+
const viewport = this.renderRoot.querySelector(`.viewport`);
|
|
10144
|
+
if (!(inner instanceof HTMLElement) || !(viewport instanceof HTMLElement)) return;
|
|
10145
|
+
const vw = viewport.clientWidth;
|
|
10146
|
+
const vh = viewport.clientHeight;
|
|
10147
|
+
if (vw <= 0 || vh <= 0) return;
|
|
10148
|
+
const { rect, direction } = flip;
|
|
10149
|
+
const startTransform = direction === `in` ? `translate(${rect.x * vw}px, ${rect.y * vh}px) scale(${Math.max(rect.width, 1e-4)}, ${Math.max(rect.height, 1e-4)})` : (() => {
|
|
10150
|
+
const sx = rect.width > 0 ? 1 / rect.width : 1;
|
|
10151
|
+
const sy = rect.height > 0 ? 1 / rect.height : 1;
|
|
10152
|
+
return `translate(${-rect.x * sx * vw}px, ${-rect.y * sy * vh}px) scale(${sx}, ${sy})`;
|
|
10153
|
+
})();
|
|
10154
|
+
inner.classList.remove(`flipping`);
|
|
10155
|
+
inner.style.transform = startTransform;
|
|
10156
|
+
inner.offsetWidth;
|
|
10157
|
+
requestAnimationFrame(() => {
|
|
10158
|
+
inner.classList.add(`flipping`);
|
|
10159
|
+
inner.style.transform = `none`;
|
|
10160
|
+
});
|
|
10161
|
+
inner.addEventListener(`transitionend`, () => inner.classList.remove(`flipping`), { once: true });
|
|
10162
|
+
}
|
|
10083
10163
|
#canZoom(node) {
|
|
10084
10164
|
if (node.item.isLeaf === true) return false;
|
|
10085
|
-
if (node.children !== void 0) return node.children.length > 0;
|
|
10165
|
+
if (node.children !== void 0) return this.hideLeaves ? node.children.some((n) => n.item.isLeaf !== true) : node.children.length > 0;
|
|
10086
10166
|
return this.model !== void 0 || this.loadChildren !== void 0;
|
|
10087
10167
|
}
|
|
10088
10168
|
/**
|
|
@@ -10309,6 +10389,39 @@ let TreemapListElement = class TreemapListElement extends LitElement {
|
|
|
10309
10389
|
}
|
|
10310
10390
|
}
|
|
10311
10391
|
}
|
|
10392
|
+
/**
|
|
10393
|
+
* Cmd+wheel zooms: scrolling backward (deltaY < 0, towards the user) zooms
|
|
10394
|
+
* into the tile under the pointer — the same as clicking it; scrolling
|
|
10395
|
+
* forward (deltaY > 0, away from the user) zooms out one level at a time
|
|
10396
|
+
* (see `#zoomOutOneStep`), not straight to the root. Plain wheel (no Cmd)
|
|
10397
|
+
* is left alone for normal page scroll. A short cooldown after each step
|
|
10398
|
+
* keeps a single trackpad gesture (which fires many small wheel events)
|
|
10399
|
+
* from firing a cascade of zoom steps.
|
|
10400
|
+
*/
|
|
10401
|
+
#handleWheel(event) {
|
|
10402
|
+
if (!event.metaKey || event.deltaY === 0) return;
|
|
10403
|
+
event.preventDefault();
|
|
10404
|
+
if (performance.now() < this.#wheelCooldownUntil) return;
|
|
10405
|
+
if (event.deltaY > 0) {
|
|
10406
|
+
if (this._zoomKey === void 0) return;
|
|
10407
|
+
this.#wheelCooldownUntil = performance.now() + 260;
|
|
10408
|
+
this.#zoomOutOneStep();
|
|
10409
|
+
return;
|
|
10410
|
+
}
|
|
10411
|
+
const key = (event.target?.closest(`.tile`))?.getAttribute(`data-key`) ?? void 0;
|
|
10412
|
+
if (key === void 0) return;
|
|
10413
|
+
const rect = this.#rects().find((r) => r.node.item.key === key);
|
|
10414
|
+
if (!rect || !this.#canZoom(rect.node)) return;
|
|
10415
|
+
this.#wheelCooldownUntil = performance.now() + 260;
|
|
10416
|
+
this.zoomTo(rect.node);
|
|
10417
|
+
}
|
|
10418
|
+
/** Zoom to the current zoom node's parent, or fully out when it's a direct child of the root. */
|
|
10419
|
+
#zoomOutOneStep() {
|
|
10420
|
+
const path = this._zoomKey === void 0 ? void 0 : findTreemapPath(this.#effectiveRoot, this._zoomKey);
|
|
10421
|
+
const parent = path && path.length > 2 ? path[path.length - 2] : void 0;
|
|
10422
|
+
if (parent) this.zoomTo(parent);
|
|
10423
|
+
else this.zoomOut();
|
|
10424
|
+
}
|
|
10312
10425
|
#renderBreadcrumb() {
|
|
10313
10426
|
const zoomNode = this.focusedNode;
|
|
10314
10427
|
if (zoomNode === void 0) return nothing;
|
|
@@ -10338,25 +10451,60 @@ let TreemapListElement = class TreemapListElement extends LitElement {
|
|
|
10338
10451
|
if (node.item.key === this.#effectiveRoot?.item.key) this.zoomOut();
|
|
10339
10452
|
else this.zoomTo(node);
|
|
10340
10453
|
}
|
|
10341
|
-
|
|
10454
|
+
/** On-screen size (px) of `rect`, or `undefined` before the host has been measured. */
|
|
10455
|
+
#pixelSize(rect) {
|
|
10342
10456
|
const hostWidth = this.clientWidth || 0;
|
|
10343
10457
|
const hostHeight = this.clientHeight || 0;
|
|
10344
|
-
if (hostWidth <= 0 || hostHeight <= 0) return
|
|
10345
|
-
return
|
|
10458
|
+
if (hostWidth <= 0 || hostHeight <= 0) return void 0;
|
|
10459
|
+
return {
|
|
10460
|
+
width: rect.width * hostWidth,
|
|
10461
|
+
height: rect.height * hostHeight
|
|
10462
|
+
};
|
|
10346
10463
|
}
|
|
10347
|
-
|
|
10464
|
+
/** Hide when too small by area, or too narrow to fit any readable text even truncated. */
|
|
10465
|
+
#hideLabel(rect) {
|
|
10466
|
+
const size = this.#pixelSize(rect);
|
|
10467
|
+
if (size === void 0) return false;
|
|
10468
|
+
return size.width * size.height < this.minLabelArea || size.width < this.minTileWidth;
|
|
10469
|
+
}
|
|
10470
|
+
/** Whether `rect` is large enough on-screen for its own children to be subdivided and drawn. */
|
|
10471
|
+
#canDescend(rect) {
|
|
10472
|
+
const size = this.#pixelSize(rect);
|
|
10473
|
+
if (size === void 0) return true;
|
|
10474
|
+
return size.width * size.height >= this.minChildArea && size.width >= this.minTileWidth;
|
|
10475
|
+
}
|
|
10476
|
+
/** Slugify a category name into a CSS custom-property-safe token. */
|
|
10477
|
+
#categorySlug(category) {
|
|
10478
|
+
return category.replace(/[^\w-]/g, `-`);
|
|
10479
|
+
}
|
|
10480
|
+
/**
|
|
10481
|
+
* Inline colour overrides for `node`'s category, or `undefined` for none.
|
|
10482
|
+
* Set as real `background-color`/`color` (not custom properties) so they
|
|
10483
|
+
* simply win over `.tile`'s CSS-variable-driven defaults by specificity —
|
|
10484
|
+
* no risk of an unresolvable `var()` chain leaving the property invalid.
|
|
10485
|
+
*/
|
|
10486
|
+
#categoryStyle(node) {
|
|
10487
|
+
const category = this.categoryAccessor?.(node.item);
|
|
10488
|
+
if (!category) return void 0;
|
|
10489
|
+
const slug = this.#categorySlug(category);
|
|
10490
|
+
return `background-color:var(--treemap-category-${slug}-bg, var(--treemap-tile-bg));color:var(--treemap-category-${slug}-text, var(--treemap-tile-text));`;
|
|
10491
|
+
}
|
|
10492
|
+
#renderTileBox(rect, positionStyle, hasVisibleChildren, childrenContent) {
|
|
10348
10493
|
const { node } = rect;
|
|
10349
10494
|
const selected = this._selectedNodes.has(node);
|
|
10350
10495
|
const tickled = this.tickled.isTickled(node.item.key);
|
|
10351
10496
|
const filtered = !this.#matchesFilter(node, rect.depth);
|
|
10352
10497
|
const pending = this.#pendingKeys.has(node.item.key);
|
|
10353
10498
|
const hideLabel = this.#hideLabel(rect);
|
|
10354
|
-
const showHeader =
|
|
10499
|
+
const showHeader = hasVisibleChildren && !hideLabel;
|
|
10500
|
+
const category = this.categoryAccessor?.(node.item);
|
|
10501
|
+
const categoryStyle = this.#categoryStyle(node);
|
|
10355
10502
|
return html`
|
|
10356
10503
|
<div
|
|
10357
|
-
class="item tile ${
|
|
10504
|
+
class="item tile ${selected ? `selected` : ``} ${tickled ? `tickled` : ``} ${filtered ? `filtered` : ``} ${pending ? `loading` : ``} ${rect.width <= 0 || rect.height <= 0 ? `empty` : ``}"
|
|
10358
10505
|
data-key=${node.item.key}
|
|
10359
10506
|
data-depth=${rect.relativeDepth}
|
|
10507
|
+
data-category=${category ?? nothing}
|
|
10360
10508
|
role="treeitem"
|
|
10361
10509
|
tabindex="-1"
|
|
10362
10510
|
aria-level=${rect.depth + 1}
|
|
@@ -10366,7 +10514,7 @@ let TreemapListElement = class TreemapListElement extends LitElement {
|
|
|
10366
10514
|
aria-label=${node.item.label}
|
|
10367
10515
|
title=${node.item.label}
|
|
10368
10516
|
part="tile"
|
|
10369
|
-
style=${positionStyle}
|
|
10517
|
+
style=${categoryStyle ? `${positionStyle};${categoryStyle}` : positionStyle}
|
|
10370
10518
|
@click=${(e) => {
|
|
10371
10519
|
e.stopPropagation();
|
|
10372
10520
|
this.#handleItemClick(rect, this.#rects().findIndex((r) => r.node.item.key === node.item.key), e);
|
|
@@ -10378,23 +10526,46 @@ let TreemapListElement = class TreemapListElement extends LitElement {
|
|
|
10378
10526
|
@pointerenter=${() => this.tickled.handlePointerEnter(node.item.key)}
|
|
10379
10527
|
>
|
|
10380
10528
|
${showHeader ? html`<div class="tile-header" part="tile-header"><span class="treemap-label" part="label">${node.item.label}</span></div>` : html`<span class="treemap-label ${hideLabel ? `hide-label` : ``}" part="label">${node.item.label}</span>`}
|
|
10381
|
-
${
|
|
10382
|
-
<div class="tile-children" role="group">
|
|
10383
|
-
${repeat(children, (r) => r.node.item.key, (r) => this.#renderNestedTile(r, rect, byParent))}
|
|
10384
|
-
</div>
|
|
10385
|
-
` : nothing}
|
|
10529
|
+
${childrenContent}
|
|
10386
10530
|
</div>
|
|
10387
10531
|
`;
|
|
10388
10532
|
}
|
|
10533
|
+
/**
|
|
10534
|
+
* Render `rect` plus (if it's large enough to descend into — see
|
|
10535
|
+
* `#canDescend`) a `.tile-children` holding its own children, each
|
|
10536
|
+
* positioned relative to `rect` itself and recursing the same way.
|
|
10537
|
+
*
|
|
10538
|
+
* Each level gets its own real `.tile-header` + `.tile-children` box, so a
|
|
10539
|
+
* header reserves its own space via normal box-model layout (flex column:
|
|
10540
|
+
* header, then the remaining space for children) at *every* level — not
|
|
10541
|
+
* just the top one. That matters because layout rects are purely
|
|
10542
|
+
* geometric (no allowance for header height), so a folder whose one child
|
|
10543
|
+
* fills ~100% of its area gets a child rect nearly identical to its own;
|
|
10544
|
+
* positioning that child against its direct parent (not some flattened
|
|
10545
|
+
* shared ancestor) is what keeps the parent's header from being painted
|
|
10546
|
+
* over by an opaque, near-identically-sized child box.
|
|
10547
|
+
*/
|
|
10548
|
+
#renderTile(rect, positionStyle, byParent) {
|
|
10549
|
+
const children = rect.hasChildren && this.#canDescend(rect) ? byParent.get(rect.node.item.key) ?? [] : [];
|
|
10550
|
+
const childrenContent = children.length > 0 ? html`
|
|
10551
|
+
<div class="tile-children" role="group">
|
|
10552
|
+
${repeat(children, (r) => r.node.item.key, (r) => this.#renderNestedTile(r, rect, byParent))}
|
|
10553
|
+
</div>
|
|
10554
|
+
` : nothing;
|
|
10555
|
+
return this.#renderTileBox(rect, positionStyle, children.length > 0, childrenContent);
|
|
10556
|
+
}
|
|
10557
|
+
/** A child tile, positioned as a percentage of `parent`'s own box. */
|
|
10389
10558
|
#renderNestedTile(rect, parent, byParent) {
|
|
10390
10559
|
const relX = parent.width > 0 ? (rect.x - parent.x) / parent.width : 0;
|
|
10391
10560
|
const relY = parent.height > 0 ? (rect.y - parent.y) / parent.height : 0;
|
|
10392
10561
|
const relW = parent.width > 0 ? rect.width / parent.width : 0;
|
|
10393
10562
|
const relH = parent.height > 0 ? rect.height / parent.height : 0;
|
|
10394
|
-
|
|
10563
|
+
const style = `left:${(relX * 100).toFixed(4)}%;top:${(relY * 100).toFixed(4)}%;width:${(relW * 100).toFixed(4)}%;height:${(relH * 100).toFixed(4)}%`;
|
|
10564
|
+
return this.#renderTile(rect, style, byParent);
|
|
10395
10565
|
}
|
|
10396
10566
|
#renderTopTile(rect, byParent) {
|
|
10397
|
-
|
|
10567
|
+
const style = `left:${(rect.x * 100).toFixed(4)}%;top:${(rect.y * 100).toFixed(4)}%;width:${(rect.width * 100).toFixed(4)}%;height:${(rect.height * 100).toFixed(4)}%`;
|
|
10568
|
+
return this.#renderTile(rect, style, byParent);
|
|
10398
10569
|
}
|
|
10399
10570
|
render() {
|
|
10400
10571
|
const rects = this.#rects();
|
|
@@ -10416,11 +10587,14 @@ let TreemapListElement = class TreemapListElement extends LitElement {
|
|
|
10416
10587
|
style=${`--treemap-padding:${this.padding}px`}
|
|
10417
10588
|
@keydown=${(e) => this.#handleKeyDown(e)}
|
|
10418
10589
|
@pointerleave=${() => this.tickled.clearTickled()}
|
|
10590
|
+
@wheel=${(e) => this.#handleWheel(e)}
|
|
10419
10591
|
>
|
|
10420
10592
|
${this.#renderBreadcrumb()}
|
|
10421
10593
|
${rects.length === 0 ? html`<div class="empty-state">No data</div>` : html`
|
|
10422
10594
|
<div class="viewport" part="viewport">
|
|
10423
|
-
|
|
10595
|
+
<div class="viewport-inner">
|
|
10596
|
+
${repeat(topLevel, (r) => r.node.item.key, (r) => this.#renderTopTile(r, byParent))}
|
|
10597
|
+
</div>
|
|
10424
10598
|
</div>
|
|
10425
10599
|
`}
|
|
10426
10600
|
</div>
|
|
@@ -10443,11 +10617,18 @@ let TreemapListElement = class TreemapListElement extends LitElement {
|
|
|
10443
10617
|
--treemap-tile-border: var(--border-subtle);
|
|
10444
10618
|
--treemap-header-bg: rgb(0 0 0 / 0.12);
|
|
10445
10619
|
--treemap-font-size: var(--text-s);
|
|
10620
|
+
--treemap-zoom-duration: 220ms;
|
|
10446
10621
|
|
|
10447
10622
|
display: block;
|
|
10448
|
-
overflow:
|
|
10623
|
+
overflow: hidden;
|
|
10449
10624
|
}
|
|
10450
10625
|
|
|
10626
|
+
/* Per-category tile colours (set categoryAccessor to opt in): define
|
|
10627
|
+
--treemap-category-SLUG-bg / -text at whatever scope suits (:host
|
|
10628
|
+
here, or globally) for each category your accessor can return —
|
|
10629
|
+
e.g. --treemap-category-urgent-bg: oklch(55% 0.18 25). A category
|
|
10630
|
+
with no matching pair falls back to --treemap-tile-bg/-text. */
|
|
10631
|
+
|
|
10451
10632
|
.treemap {
|
|
10452
10633
|
display: flex;
|
|
10453
10634
|
flex-direction: column;
|
|
@@ -10476,18 +10657,44 @@ let TreemapListElement = class TreemapListElement extends LitElement {
|
|
|
10476
10657
|
.viewport {
|
|
10477
10658
|
position: relative;
|
|
10478
10659
|
width: 100%;
|
|
10479
|
-
|
|
10480
|
-
|
|
10660
|
+
/* flex-basis of --treemap-height (its size when nothing forces a
|
|
10661
|
+
different one — the common case of an auto-height host) but
|
|
10662
|
+
allowed to grow/shrink like any flex item, so it shares the
|
|
10663
|
+
.treemap column's height with the breadcrumb instead of a plain
|
|
10664
|
+
fixed height always claiming that full amount regardless of what
|
|
10665
|
+
else needs space — which is what let the breadcrumb push the
|
|
10666
|
+
host past its own height and scroll once a zoom made it appear. */
|
|
10667
|
+
flex: 1 1 var(--treemap-height);
|
|
10668
|
+
min-height: 0;
|
|
10481
10669
|
overflow: hidden;
|
|
10482
10670
|
border-radius: var(--radius-m);
|
|
10483
10671
|
}
|
|
10484
10672
|
|
|
10673
|
+
/* Transform target for the zoom-in/zoom-out FLIP animation (see
|
|
10674
|
+
#planFlip/#applyFlip) — kept separate from .viewport so the
|
|
10675
|
+
transform never fights that element's own sizing/overflow. */
|
|
10676
|
+
.viewport-inner {
|
|
10677
|
+
position: absolute;
|
|
10678
|
+
inset: 0;
|
|
10679
|
+
transform-origin: 0 0;
|
|
10680
|
+
}
|
|
10681
|
+
|
|
10682
|
+
.viewport-inner.flipping {
|
|
10683
|
+
transition: transform var(--treemap-zoom-duration, 220ms) ease-out;
|
|
10684
|
+
}
|
|
10685
|
+
|
|
10485
10686
|
.tile {
|
|
10486
10687
|
position: absolute;
|
|
10487
10688
|
box-sizing: border-box;
|
|
10488
10689
|
overflow: hidden;
|
|
10489
10690
|
display: flex;
|
|
10490
10691
|
flex-direction: column;
|
|
10692
|
+
/* Override the shared .item class's align-items:center (built for
|
|
10693
|
+
icon+label rows) — tiles need their flex children to stretch to
|
|
10694
|
+
full width, or .tile-children collapses to its (empty) content
|
|
10695
|
+
width and every nested tile collapses with it. */
|
|
10696
|
+
align-items: stretch;
|
|
10697
|
+
white-space: normal;
|
|
10491
10698
|
background: var(--treemap-tile-bg);
|
|
10492
10699
|
color: var(--treemap-tile-text);
|
|
10493
10700
|
border: var(--treemap-tile-border);
|
|
@@ -10580,12 +10787,25 @@ __decorate([property({
|
|
|
10580
10787
|
type: Number,
|
|
10581
10788
|
attribute: `max-depth`
|
|
10582
10789
|
})], TreemapListElement.prototype, "maxDepth", void 0);
|
|
10790
|
+
__decorate([property({
|
|
10791
|
+
type: Boolean,
|
|
10792
|
+
attribute: `hide-leaves`
|
|
10793
|
+
})], TreemapListElement.prototype, "hideLeaves", void 0);
|
|
10583
10794
|
__decorate([property({
|
|
10584
10795
|
type: Number,
|
|
10585
10796
|
attribute: `min-label-area`
|
|
10586
10797
|
})], TreemapListElement.prototype, "minLabelArea", void 0);
|
|
10798
|
+
__decorate([property({
|
|
10799
|
+
type: Number,
|
|
10800
|
+
attribute: `min-tile-width`
|
|
10801
|
+
})], TreemapListElement.prototype, "minTileWidth", void 0);
|
|
10587
10802
|
__decorate([property({ type: Number })], TreemapListElement.prototype, "padding", void 0);
|
|
10803
|
+
__decorate([property({
|
|
10804
|
+
type: Number,
|
|
10805
|
+
attribute: `min-child-area`
|
|
10806
|
+
})], TreemapListElement.prototype, "minChildArea", void 0);
|
|
10588
10807
|
__decorate([property({ attribute: false })], TreemapListElement.prototype, "valueAccessor", void 0);
|
|
10808
|
+
__decorate([property({ attribute: false })], TreemapListElement.prototype, "categoryAccessor", void 0);
|
|
10589
10809
|
__decorate([property({ attribute: false })], TreemapListElement.prototype, "selectedNode", void 0);
|
|
10590
10810
|
__decorate([state()], TreemapListElement.prototype, "_selectedNodes", void 0);
|
|
10591
10811
|
__decorate([property({ attribute: false })], TreemapListElement.prototype, "filterPredicate", void 0);
|