@ixfx/components 0.8.1 → 0.8.3
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 +326 -103
- package/bundle/index.d.ts.map +1 -1
- package/bundle/index.js +2840 -1285
- package/bundle/index.js.map +1 -1
- package/dist/ac-text.js +3 -3
- package/dist/ac-token.js +3 -3
- package/dist/checkbox.js +1 -1
- package/dist/{colour-picker-Ddsk-7E_.js → colour-picker-CSxwUmtE.js} +2 -2
- package/dist/{colour-picker-Ddsk-7E_.js.map → colour-picker-CSxwUmtE.js.map} +1 -1
- package/dist/colour-picker.js +1 -1
- package/dist/crumbs.js +4 -4
- package/dist/data-display.js +1 -1
- package/dist/data-grid-D-z7bx5-.d.ts.map +1 -1
- package/dist/data-grid.js +9 -6
- package/dist/data-grid.js.map +1 -1
- package/dist/detail-list-_ZJHYEBr.d.ts.map +1 -1
- package/dist/detail-list.js +68 -5
- package/dist/detail-list.js.map +1 -1
- package/dist/editable-label.js +1 -1
- package/dist/{fallbacks-DNI9xt0F.js → fallbacks-BcKGq-2F.js} +17 -1
- package/dist/{fallbacks-DNI9xt0F.js.map → fallbacks-BcKGq-2F.js.map} +1 -1
- package/dist/{grid-list-nRUQOcEL.js → grid-list-BXfY3XXX.js} +531 -29
- package/dist/grid-list-BXfY3XXX.js.map +1 -0
- package/dist/{grid-list-u33vmKzb.d.ts → grid-list-x550wJ0X.d.ts} +115 -3
- package/dist/grid-list-x550wJ0X.d.ts.map +1 -0
- package/dist/grid-list.d.ts +2 -2
- package/dist/grid-list.js +1 -1
- package/dist/handle-BPOxBOKf.js +219 -0
- package/dist/handle-BPOxBOKf.js.map +1 -0
- package/dist/{icon-DcEEGQa_.js → icon-Dy33gu4Z.js} +2 -2
- package/dist/{icon-DcEEGQa_.js.map → icon-Dy33gu4Z.js.map} +1 -1
- package/dist/icons.js +1 -1
- package/dist/{index-BeuCXtiO.d.ts → index-DV3iaUBW.d.ts} +2 -2
- package/dist/{index-BeuCXtiO.d.ts.map → index-DV3iaUBW.d.ts.map} +1 -1
- package/dist/index.d.ts +132 -50
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +554 -206
- package/dist/index.js.map +1 -1
- package/dist/{interaction-Cr13azbM.js → interaction-B9AAlsFO.js} +1 -1
- package/dist/labelled-radial-input.js +2 -2
- package/dist/{labelled-slider-input-BInB5GKL.js → labelled-slider-input-BCH9968c.js} +3 -3
- package/dist/{labelled-slider-input-BInB5GKL.js.map → labelled-slider-input-BCH9968c.js.map} +1 -1
- package/dist/labelled-slider-input.js +1 -1
- package/dist/list-selection-controller-SA4piSBi.js +589 -0
- package/dist/list-selection-controller-SA4piSBi.js.map +1 -0
- package/dist/{menu-Bg90Qr0B.js → menu-HMoxCPY2.js} +5 -5
- package/dist/{menu-Bg90Qr0B.js.map → menu-HMoxCPY2.js.map} +1 -1
- package/dist/{menu-item-Bx-Fs7jq.js → menu-item-BQDYxk5A.js} +5 -5
- package/dist/{menu-item-Bx-Fs7jq.js.map → menu-item-BQDYxk5A.js.map} +1 -1
- package/dist/menu.js +2 -2
- package/dist/miller.d.ts +1 -1
- package/dist/miller.js +3 -3
- package/dist/narrowed-text.js +3 -3
- package/dist/notifier.js +1 -1
- package/dist/panel.d.ts +1 -1
- package/dist/panel.js +1 -1
- package/dist/plots.d.ts +2 -2
- package/dist/plots.js +1 -1
- package/dist/polar-pad.js +1 -1
- package/dist/{radial-input-BfA3GO0H.js → radial-input-DyxfbNzD.js} +2 -2
- package/dist/{radial-input-BfA3GO0H.js.map → radial-input-DyxfbNzD.js.map} +1 -1
- package/dist/radial-input.js +1 -1
- package/dist/range-input.js +1 -1
- package/dist/range.js +1 -1
- package/dist/select-horiz.js +3 -3
- package/dist/{slider-input-Bl1hFE89.js → slider-input-WR8_RwHg.js} +2 -2
- package/dist/{slider-input-Bl1hFE89.js.map → slider-input-WR8_RwHg.js.map} +1 -1
- package/dist/slider-input.js +1 -1
- package/dist/snackbar.js +1 -1
- package/dist/{split-layout-BFSbUZQv.js → split-layout-CA5jbNbG.js} +22 -33
- package/dist/split-layout-CA5jbNbG.js.map +1 -0
- package/dist/split-layout-JK3xWVX2.d.ts.map +1 -1
- package/dist/split-layout.js +1 -1
- package/dist/swipe.js +1 -1
- package/dist/tabs.js +1 -1
- package/dist/{tickled-controller-Bn3YdQsM.d.ts → tickled-controller-C1ZsHpyg.d.ts} +10 -1
- package/dist/tickled-controller-C1ZsHpyg.d.ts.map +1 -0
- package/dist/{tickled-controller-C66DgJHl.js → tickled-controller-Dh1Uh_vG.js} +4 -1
- package/dist/tickled-controller-Dh1Uh_vG.js.map +1 -0
- package/dist/{timeline-B2fgDL4U.js → timeline-THyvH8xy.js} +14 -8
- package/dist/timeline-THyvH8xy.js.map +1 -0
- package/dist/timeline.d.ts +1 -1
- package/dist/timeline.js +1 -1
- package/dist/{titlebar-YQ-jVQoS.d.ts → titlebar-Tqu-VvMU.d.ts} +5 -1
- package/dist/titlebar-Tqu-VvMU.d.ts.map +1 -0
- package/dist/titlebar.d.ts +1 -1
- package/dist/titlebar.js +5 -3
- package/dist/titlebar.js.map +1 -1
- package/dist/{tree-Chptss7I.js → tree-DTQon838.js} +4 -4
- package/dist/{tree-Chptss7I.js.map → tree-DTQon838.js.map} +1 -1
- package/dist/tree.d.ts +1 -1
- package/dist/tree.js +1 -1
- package/dist/vertical-list-CFuFDygi.d.ts.map +1 -1
- package/dist/vertical-list.js +68 -4
- package/dist/vertical-list.js.map +1 -1
- package/dist/{xy-axis-DzM1brBZ.js → xy-axis-CrrVdDFe.js} +28 -3
- package/dist/xy-axis-CrrVdDFe.js.map +1 -0
- package/dist/{xy-axis-BfP9hKLj.d.ts → xy-axis-DQqd2yXJ.d.ts} +28 -12
- package/dist/{xy-axis-BfP9hKLj.d.ts.map → xy-axis-DQqd2yXJ.d.ts.map} +1 -1
- package/dist/xy-pad.js +1 -1
- package/docs-user/data-grid.md +1 -1
- package/docs-user/detail-list.md +4 -0
- package/docs-user/dock.md +6 -3
- package/docs-user/grid-list.md +49 -0
- package/docs-user/index.json +2 -2
- package/docs-user/infra-tickled.md +2 -0
- package/docs-user/split-layout.md +2 -4
- package/docs-user/twosplit-layout.md +14 -16
- package/docs-user/vertical-list.md +4 -0
- package/package.json +1 -1
- package/dist/grid-list-nRUQOcEL.js.map +0 -1
- package/dist/grid-list-u33vmKzb.d.ts.map +0 -1
- package/dist/list-selection-controller-DTFI40li.js +0 -264
- package/dist/list-selection-controller-DTFI40li.js.map +0 -1
- package/dist/split-layout-BFSbUZQv.js.map +0 -1
- package/dist/tickled-controller-Bn3YdQsM.d.ts.map +0 -1
- package/dist/tickled-controller-C66DgJHl.js.map +0 -1
- package/dist/timeline-B2fgDL4U.js.map +0 -1
- package/dist/titlebar-YQ-jVQoS.d.ts.map +0 -1
- package/dist/xy-axis-DzM1brBZ.js.map +0 -1
package/bundle/index.js
CHANGED
|
@@ -3,8 +3,8 @@ import { customElement, eventOptions, property, query, queryAssignedElements, st
|
|
|
3
3
|
import { styleMap } from "lit/directives/style-map.js";
|
|
4
4
|
import { unsafeHTML } from "lit/directives/unsafe-html.js";
|
|
5
5
|
import { Fzf } from "fzf";
|
|
6
|
-
import { Colour } from "@ixfx/visual";
|
|
7
6
|
import { createCommandRegistry } from "@clinth/ui-commands";
|
|
7
|
+
import { Colour } from "@ixfx/visual";
|
|
8
8
|
import { Trees } from "@ixfx/collections";
|
|
9
9
|
import { clamp, clamper, rangeStream, round, scaler } from "@ixfx/numbers";
|
|
10
10
|
import { repeat } from "lit/directives/repeat.js";
|
|
@@ -730,6 +730,7 @@ var TickledController = class TickledController {
|
|
|
730
730
|
this.host = host;
|
|
731
731
|
this.config = config;
|
|
732
732
|
this._inputMode = config.initialInputMode ?? `mouse`;
|
|
733
|
+
this.hoverDisabled = config.hoverDisabled ?? (() => false);
|
|
733
734
|
host.addController(this);
|
|
734
735
|
}
|
|
735
736
|
hostConnected() {
|
|
@@ -798,6 +799,7 @@ var TickledController = class TickledController {
|
|
|
798
799
|
* Switches to mouse mode and tickles the item.
|
|
799
800
|
*/
|
|
800
801
|
handlePointerEnter(id) {
|
|
802
|
+
if (this.hoverDisabled()) return;
|
|
801
803
|
if (!TickledController._mouseMovedSinceKeyboard) return;
|
|
802
804
|
const item = this.config.getItems().find((item) => item.id === id);
|
|
803
805
|
if (item && item.enabled === false) return;
|
|
@@ -815,6 +817,7 @@ var TickledController = class TickledController {
|
|
|
815
817
|
* @param _e The pointer event (not used, but kept for API compatibility)
|
|
816
818
|
*/
|
|
817
819
|
handlePointerLeave(_e) {
|
|
820
|
+
if (this.hoverDisabled()) return;
|
|
818
821
|
if (TickledController._mouseMovedSinceKeyboard) this.clearTickled();
|
|
819
822
|
}
|
|
820
823
|
/**
|
|
@@ -1287,6 +1290,22 @@ const _themeFallbacksCss = i$3`
|
|
|
1287
1290
|
inherits: true;
|
|
1288
1291
|
initial-value: 0 4px 24px rgba(0, 0, 0, 0.5);
|
|
1289
1292
|
}
|
|
1293
|
+
@property --deboss-3 {
|
|
1294
|
+
syntax: '*';
|
|
1295
|
+
inherits: true;
|
|
1296
|
+
initial-value:
|
|
1297
|
+
inset 1px 1px 1px 1px color-mix(in oklch, oklch(8% 0.02 240) 60%, transparent),
|
|
1298
|
+
inset -1px -1px 1px 1px color-mix(in oklch, oklch(15% 0.02 240) 50%, transparent),
|
|
1299
|
+
-2px -2px 1px 0px color-mix(in oklch, oklch(12% 0.02 240) 30%, transparent);
|
|
1300
|
+
}
|
|
1301
|
+
@property --emboss-3 {
|
|
1302
|
+
syntax: '*';
|
|
1303
|
+
inherits: true;
|
|
1304
|
+
initial-value:
|
|
1305
|
+
inset 1px 1px 1px 1px color-mix(in oklch, oklch(22% 0.02 240) 30%, transparent),
|
|
1306
|
+
inset -1px -1px 1px 1px color-mix(in oklch, oklch(12% 0.02 240) 20%, transparent),
|
|
1307
|
+
2px 2px 1px 0px color-mix(in oklch, oklch(12% 0.02 240) 30%, transparent);
|
|
1308
|
+
}
|
|
1290
1309
|
@property --item-bg {
|
|
1291
1310
|
syntax: '<color>';
|
|
1292
1311
|
inherits: true;
|
|
@@ -3893,488 +3912,1605 @@ __decorate([state()], AcTokenElement.prototype, "_selectedTokenIndex", void 0);
|
|
|
3893
3912
|
__decorate([state()], AcTokenElement.prototype, "_isOpen", void 0);
|
|
3894
3913
|
AcTokenElement = __decorate([safeCustomElement(`ixfx-ac-token`)], AcTokenElement);
|
|
3895
3914
|
//#endregion
|
|
3896
|
-
//#region src/
|
|
3897
|
-
/**
|
|
3898
|
-
* Chevron pointing down. Used for split-button dropdown toggle.
|
|
3899
|
-
* fill="currentColor" so it inherits CSS color.
|
|
3900
|
-
*/
|
|
3901
|
-
const ICON_CHEVRON_DOWN = `<svg viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"><path d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"/></svg>`;
|
|
3902
|
-
/**
|
|
3903
|
-
* Caret pointing right. Used for tree-basic expand indicator as a CSS mask.
|
|
3904
|
-
* fill="black" is correct for CSS mask-image use (shape only, color comes from background-color).
|
|
3905
|
-
*/
|
|
3906
|
-
const ICON_CARET_RIGHT = `<svg viewBox="0 0 24 24" fill="black" xmlns="http://www.w3.org/2000/svg"><path d="M10 7l6 5-6 5V7z"/></svg>`;
|
|
3907
|
-
/**
|
|
3908
|
-
* Checkmark. Useful for menu-check-item or confirmation states.
|
|
3909
|
-
* fill="currentColor" so it inherits CSS color.
|
|
3910
|
-
*/
|
|
3911
|
-
const ICON_CHECK = `<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z"/></svg>`;
|
|
3912
|
-
/**
|
|
3913
|
-
* Close / X icon. Useful for dialogs, notifications, dismissible elements.
|
|
3914
|
-
* fill="currentColor" so it inherits CSS color.
|
|
3915
|
-
*/
|
|
3916
|
-
const ICON_CLOSE = `<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41z"/></svg>`;
|
|
3917
|
-
/**
|
|
3918
|
-
* Plus / add icon. Pairs with `close` for add/remove actions.
|
|
3919
|
-
* fill="currentColor" so it inherits CSS color.
|
|
3920
|
-
*/
|
|
3921
|
-
const ICON_ADD = `<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg>`;
|
|
3922
|
-
/**
|
|
3923
|
-
* Error / warning icon. Useful for error notifications.
|
|
3924
|
-
* fill="currentColor" so it inherits CSS color.
|
|
3925
|
-
*/
|
|
3926
|
-
const ICON_ERROR = `<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z"/></svg>`;
|
|
3927
|
-
/**
|
|
3928
|
-
* Info icon. Useful for info notifications.
|
|
3929
|
-
* fill="currentColor" so it inherits CSS color.
|
|
3930
|
-
*/
|
|
3931
|
-
const ICON_INFO = `<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"/></svg>`;
|
|
3932
|
-
/**
|
|
3933
|
-
* Warning icon. Useful for warning notifications.
|
|
3934
|
-
* fill="currentColor" so it inherits CSS color.
|
|
3935
|
-
*/
|
|
3936
|
-
const ICON_WARNING = `<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z"/></svg>`;
|
|
3937
|
-
/**
|
|
3938
|
-
* Chevron pointing right. Used for split-button switcher toggle.
|
|
3939
|
-
* fill="currentColor" so it inherits CSS color.
|
|
3940
|
-
*/
|
|
3941
|
-
const ICON_CHEVRON_RIGHT = `<svg viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"><path d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z"/></svg>`;
|
|
3942
|
-
/**
|
|
3943
|
-
* Folder with up arrow. Angled line style for navigating up one level.
|
|
3944
|
-
* fill="currentColor" so it inherits CSS color.
|
|
3945
|
-
*/
|
|
3946
|
-
const ICON_FOLDER_UP = `<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M12 4L4 12h5v8h6v-8h5L12 4z"/></svg>`;
|
|
3947
|
-
/**
|
|
3948
|
-
* Folder. Useful for file explorers and sidebars.
|
|
3949
|
-
* fill="currentColor" so it inherits CSS color.
|
|
3950
|
-
*/
|
|
3951
|
-
const ICON_FOLDER = `<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 1.99-.9 1.99-2V8c0-1.1-.9-2-2-2h-8l-2-2z"/></svg>`;
|
|
3952
|
-
/**
|
|
3953
|
-
* Document / file page. Useful for file lists and document tabs.
|
|
3954
|
-
* fill="currentColor" so it inherits CSS color.
|
|
3955
|
-
*/
|
|
3956
|
-
const ICON_FILE = `<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M14 2H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8l-6-6zm2 16H8v-2h8v2zm0-4H8v-2h8v2zm-3-5V3.5L18.5 9H13z"/></svg>`;
|
|
3957
|
-
/**
|
|
3958
|
-
* Magnifying glass. Useful for search panels and inputs.
|
|
3959
|
-
* fill="currentColor" so it inherits CSS color.
|
|
3960
|
-
*/
|
|
3961
|
-
const ICON_SEARCH = `<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/></svg>`;
|
|
3962
|
-
function registerDefaults() {
|
|
3963
|
-
registerIcon(`chevron-down`, ICON_CHEVRON_DOWN);
|
|
3964
|
-
registerIcon(`chevron-right`, ICON_CHEVRON_RIGHT);
|
|
3965
|
-
registerIcon(`caret-right`, ICON_CARET_RIGHT);
|
|
3966
|
-
registerIcon(`check`, ICON_CHECK);
|
|
3967
|
-
registerIcon(`close`, ICON_CLOSE);
|
|
3968
|
-
registerIcon(`file`, ICON_FILE);
|
|
3969
|
-
registerIcon(`folder`, ICON_FOLDER);
|
|
3970
|
-
registerIcon(`search`, ICON_SEARCH);
|
|
3971
|
-
registerIcon(`add`, ICON_ADD);
|
|
3972
|
-
registerIcon(`error`, ICON_ERROR);
|
|
3973
|
-
registerIcon(`folder-up`, ICON_FOLDER_UP);
|
|
3974
|
-
registerIcon(`info`, ICON_INFO);
|
|
3975
|
-
registerIcon(`warning`, ICON_WARNING);
|
|
3976
|
-
}
|
|
3977
|
-
//#endregion
|
|
3978
|
-
//#region src/icons/index.ts
|
|
3979
|
-
registerDefaults();
|
|
3980
|
-
//#endregion
|
|
3981
|
-
//#region src/styles/prominence.ts
|
|
3915
|
+
//#region src/styles/handle.ts
|
|
3982
3916
|
/**
|
|
3983
|
-
* Shared
|
|
3917
|
+
* Shared drag / resize **handle** styling.
|
|
3984
3918
|
*
|
|
3985
|
-
*
|
|
3986
|
-
*
|
|
3987
|
-
*
|
|
3988
|
-
*/
|
|
3989
|
-
const prominenceVars = i$3`
|
|
3990
|
-
:host {
|
|
3991
|
-
--prominence-idle-opacity: 0.6;
|
|
3992
|
-
--prominence-idle-saturate: 0.4;
|
|
3993
|
-
--prominence-tickled-opacity: 0.85;
|
|
3994
|
-
--prominence-tickled-saturate: 0.8;
|
|
3995
|
-
--prominence-disabled-opacity: 0.3;
|
|
3996
|
-
--prominence-disabled-saturate: 0.1;
|
|
3997
|
-
}
|
|
3998
|
-
`;
|
|
3999
|
-
/**
|
|
4000
|
-
* Host-based prominence interaction feedback.
|
|
3919
|
+
* A handle is the grab affordance for moving or resizing an object. Apply the
|
|
3920
|
+
* `.ixfx-handle` class to a small decorative element inside your drag / resize
|
|
3921
|
+
* hit-zone and choose a look with two independent attributes:
|
|
4001
3922
|
*
|
|
4002
|
-
*
|
|
4003
|
-
* -
|
|
4004
|
-
* - **Idle** (default): reduced opacity + desaturated
|
|
4005
|
-
* - **Tickled** (`:hover` / `:focus-within`): elevated opacity + saturation
|
|
4006
|
-
* - **Active** (`:active` / `[dragging]`): full vibrancy (filter removed)
|
|
3923
|
+
* - `data-handle` — texture: `flat` (default) · `dotted` · `dimpled` · `grated`
|
|
3924
|
+
* - `data-shape` — topology: `horizontal` (default) · `vertical` · `spot`
|
|
4007
3925
|
*
|
|
4008
|
-
*
|
|
3926
|
+
* - **flat** — a solid rounded capsule (bar) or dot (`spot`), filled with
|
|
3927
|
+
* `--ixfx-handle-color`.
|
|
3928
|
+
* - **dotted** — marks in the [Lucide *grip*](https://lucide.dev/icons/grip)
|
|
3929
|
+
* arrangement: three in a row (`horizontal`), three in a column (`vertical`) or a
|
|
3930
|
+
* 3×3 block (`spot`). Tinted by `--ixfx-handle-color`. Each mark's corner
|
|
3931
|
+
* rounding is `--ixfx-handle-radius` (→ the theme `--radius-l`), so a flat,
|
|
3932
|
+
* squared-off theme renders them as **squares** instead of circles.
|
|
3933
|
+
* - **dimpled** — that same layout, but each bar mark is pressed in: a lighter
|
|
3934
|
+
* copy peeking out above-left and a darker copy below-right of the base mark.
|
|
3935
|
+
* - **grated** — fine 45° knurling: each ridge is a lit edge, the base colour,
|
|
3936
|
+
* then a shaded edge. `spot` is the same hatch on a square crop.
|
|
3937
|
+
*
|
|
3938
|
+
* `dotted` / `dimpled` / `grated` are texture only — no plate, box or border; the
|
|
3939
|
+
* gaps are transparent so the surface behind shows through. The base colour is
|
|
3940
|
+
* `--ixfx-handle-color` (a theme token); the deboss edges default to that colour
|
|
3941
|
+
* lightened / darkened.
|
|
3942
|
+
*
|
|
3943
|
+
* The handle is `pointer-events: none` — bind pointer handlers to the surrounding
|
|
3944
|
+
* hit-zone. It reaches its "active" look (`--ixfx-handle-opacity-active`, and for
|
|
3945
|
+
* `flat` / `dotted` the `--ixfx-handle-color-active` tint) when its immediate
|
|
3946
|
+
* parent (the hit-zone) is `:hover` / `:focus-visible` / `[data-active]`, or when
|
|
3947
|
+
* the handle itself is. Set `[data-active]` on the hit-zone yourself while a drag
|
|
3948
|
+
* is live so the handle stays lit after the pointer leaves it.
|
|
4009
3949
|
*
|
|
4010
|
-
* Usage:
|
|
4011
3950
|
* ```ts
|
|
4012
|
-
* import {
|
|
3951
|
+
* import { handleStyles } from '../styles/handle.js';
|
|
4013
3952
|
*
|
|
4014
|
-
*
|
|
4015
|
-
* static styles = [prominenceStyles, css`...`];
|
|
4016
|
-
* }
|
|
3953
|
+
* static styles = [themeFallbacks, handleStyles, css`...`];
|
|
4017
3954
|
* ```
|
|
3955
|
+
* ```html
|
|
3956
|
+
* <div class="hit-zone" @pointerdown=${this.#onDown}>
|
|
3957
|
+
* <span class="ixfx-handle" data-handle="dotted" data-shape="spot" part="handle"></span>
|
|
3958
|
+
* </div>
|
|
3959
|
+
* ```
|
|
3960
|
+
*
|
|
3961
|
+
* ## CSS variables (defaults shown; override on the element or any ancestor)
|
|
3962
|
+
* - `--ixfx-handle-color` `var(--surface-muted-text)` — `flat` / `dotted` fill
|
|
3963
|
+
* - `--ixfx-handle-color-active` `var(--accent)` — `flat` / `dotted` hover / focus
|
|
3964
|
+
* - `--ixfx-handle-thickness` `6px` — cross-axis size of a bar
|
|
3965
|
+
* - `--ixfx-handle-length` `44px` — long-axis size of a bar (`100%` to fill)
|
|
3966
|
+
* - `--ixfx-handle-spot-size` `14px` — width = height of a `spot`
|
|
3967
|
+
* - `--ixfx-handle-radius` `var(--radius-l)` — `flat` capsule / dotted & dimpled mark rounding
|
|
3968
|
+
* - `--ixfx-handle-opacity` `0.55` — rest opacity
|
|
3969
|
+
* - `--ixfx-handle-opacity-active` `1`
|
|
3970
|
+
* - `--ixfx-handle-dot-size` `3px` — mark size (dotted / dimpled)
|
|
3971
|
+
* - `--ixfx-handle-dot-gap` `length/4` (bar) · `spot/3` — mark centre-to-centre step
|
|
3972
|
+
* - `--ixfx-handle-tile` `5px` — knurl period (grated)
|
|
3973
|
+
* - `--ixfx-handle-highlight` `color-mix(currentColor 35%, #fff)` — lit deboss edge
|
|
3974
|
+
* - `--ixfx-handle-shadow` `color-mix(currentColor 60%, #000)` — shaded deboss edge
|
|
4018
3975
|
*/
|
|
4019
|
-
const
|
|
4020
|
-
|
|
4021
|
-
|
|
4022
|
-
|
|
4023
|
-
|
|
4024
|
-
|
|
4025
|
-
|
|
4026
|
-
|
|
4027
|
-
|
|
4028
|
-
|
|
4029
|
-
|
|
4030
|
-
|
|
4031
|
-
|
|
4032
|
-
|
|
4033
|
-
|
|
4034
|
-
|
|
4035
|
-
|
|
4036
|
-
|
|
4037
|
-
|
|
4038
|
-
|
|
4039
|
-
|
|
3976
|
+
const handleStyles = i$3`
|
|
3977
|
+
.ixfx-handle {
|
|
3978
|
+
/* Bridge: public --ixfx-handle-* (element or ancestor) → internal alias → fallback. */
|
|
3979
|
+
--_handle-color: var(--ixfx-handle-color, var(--surface-3-text));
|
|
3980
|
+
--_handle-color-active: var(--ixfx-handle-color-active, var(--surface-3-text));
|
|
3981
|
+
--_handle-thickness: var(--ixfx-handle-thickness, 6px);
|
|
3982
|
+
--_handle-length: var(--ixfx-handle-length, 44px);
|
|
3983
|
+
--_handle-spot: var(--ixfx-handle-spot-size, 14px);
|
|
3984
|
+
--_handle-radius: var(--ixfx-handle-radius, var(--radius-l));
|
|
3985
|
+
--_handle-opacity: var(--ixfx-handle-opacity, 0.55);
|
|
3986
|
+
--_handle-opacity-active: var(--ixfx-handle-opacity-active, 1);
|
|
3987
|
+
--_handle-dot: var(--ixfx-handle-dot-size, 3px);
|
|
3988
|
+
--_handle-tile: var(--ixfx-handle-tile, 5px);
|
|
3989
|
+
/* Centre-to-centre step of the dotted / dimpled marks (a length). Defaults to
|
|
3990
|
+
a share of the long axis; a bar shows ~3 marks. */
|
|
3991
|
+
--_handle-gap: var(--ixfx-handle-dot-gap, calc(var(--_handle-length) / 4));
|
|
3992
|
+
/* How far a dimpled mark's highlight / shadow copy is offset. */
|
|
3993
|
+
--_dimple-off: calc(var(--_handle-dot) * 0.15);
|
|
3994
|
+
/* The mark colour lightened / darkened for the two deboss edges. */
|
|
3995
|
+
--_handle-hi: var(--ixfx-handle-highlight, color-mix(in oklch, var(--surface-4) 50%, var(--_handle-color)));
|
|
3996
|
+
--_handle-lo: var(--ixfx-handle-shadow, color-mix(in oklch, var(--surface-2) 40%, var(--_handle-color)));
|
|
4040
3997
|
|
|
4041
|
-
|
|
4042
|
-
|
|
4043
|
-
|
|
4044
|
-
|
|
4045
|
-
|
|
4046
|
-
|
|
3998
|
+
box-sizing: border-box;
|
|
3999
|
+
display: inline-block;
|
|
4000
|
+
flex: none;
|
|
4001
|
+
width: var(--_handle-length);
|
|
4002
|
+
height: var(--_handle-thickness);
|
|
4003
|
+
color: var(--_handle-color);
|
|
4004
|
+
opacity: var(--_handle-opacity);
|
|
4047
4005
|
pointer-events: none;
|
|
4048
|
-
|
|
4049
|
-
|
|
4050
|
-
|
|
4051
|
-
${prominenceVars}
|
|
4052
|
-
|
|
4053
|
-
.prominence {
|
|
4054
|
-
filter:
|
|
4055
|
-
opacity(var(--prominence-idle-opacity))
|
|
4056
|
-
saturate(var(--prominence-idle-saturate));
|
|
4057
|
-
transition: filter var(--transition, 0.15s ease-out);
|
|
4058
|
-
}
|
|
4059
|
-
|
|
4060
|
-
.prominence:hover,
|
|
4061
|
-
.prominence:focus-within {
|
|
4062
|
-
filter:
|
|
4063
|
-
opacity(var(--prominence-tickled-opacity))
|
|
4064
|
-
saturate(var(--prominence-tickled-saturate));
|
|
4006
|
+
transition:
|
|
4007
|
+
color var(--transition, 0.15s ease-out),
|
|
4008
|
+
opacity var(--transition, 0.15s ease-out);
|
|
4065
4009
|
}
|
|
4066
4010
|
|
|
4067
|
-
.
|
|
4068
|
-
|
|
4069
|
-
|
|
4011
|
+
.ixfx-handle[data-shape='vertical'] {
|
|
4012
|
+
width: var(--_handle-thickness);
|
|
4013
|
+
height: var(--_handle-length);
|
|
4070
4014
|
}
|
|
4071
4015
|
|
|
4072
|
-
.
|
|
4073
|
-
|
|
4074
|
-
|
|
4075
|
-
|
|
4076
|
-
saturate(var(--prominence-disabled-saturate));
|
|
4077
|
-
pointer-events: none;
|
|
4078
|
-
}
|
|
4079
|
-
`;
|
|
4080
|
-
//#endregion
|
|
4081
|
-
//#region src/button/button-styles.ts
|
|
4082
|
-
const buttonStyles = i$3`
|
|
4083
|
-
:host {
|
|
4084
|
-
display: inline-flex;
|
|
4085
|
-
max-width: 100%;
|
|
4086
|
-
vertical-align: middle;
|
|
4087
|
-
user-select: none;
|
|
4088
|
-
-webkit-user-select: none;
|
|
4016
|
+
.ixfx-handle[data-shape='spot'] {
|
|
4017
|
+
width: var(--_handle-spot);
|
|
4018
|
+
height: var(--_handle-spot);
|
|
4019
|
+
--_handle-gap: var(--ixfx-handle-dot-gap, calc(var(--_handle-spot) / 3));
|
|
4089
4020
|
}
|
|
4090
4021
|
|
|
4091
|
-
:
|
|
4092
|
-
|
|
4022
|
+
.ixfx-handle:hover,
|
|
4023
|
+
.ixfx-handle:focus-visible,
|
|
4024
|
+
.ixfx-handle[data-active],
|
|
4025
|
+
:hover > .ixfx-handle,
|
|
4026
|
+
:focus-visible > .ixfx-handle,
|
|
4027
|
+
[data-active] > .ixfx-handle {
|
|
4028
|
+
color: var(--_handle-color-active);
|
|
4029
|
+
opacity: var(--_handle-opacity-active);
|
|
4093
4030
|
}
|
|
4094
4031
|
|
|
4095
|
-
|
|
4096
|
-
|
|
4097
|
-
|
|
4098
|
-
|
|
4099
|
-
color: var(--surface-3-text, #000);
|
|
4100
|
-
border: var(--border, 1px solid #999);
|
|
4101
|
-
outline: var(--ixfx-button-outline, none);
|
|
4102
|
-
border-radius: var(--radius-xl, 8px);
|
|
4103
|
-
corner-shape: superellipse(1);
|
|
4104
|
-
padding: var(--ixfx-button-padding-block, var(--space-m, 8px)) var(--ixfx-button-padding-inline, var(--space-l, 12px));
|
|
4105
|
-
font-family: var(--font-family, inherit);
|
|
4106
|
-
font-size: var(--text-m, 14px);
|
|
4107
|
-
margin: 0;
|
|
4108
|
-
display: inline-flex;
|
|
4109
|
-
align-items: center;
|
|
4110
|
-
justify-content: center;
|
|
4111
|
-
gap: 0.5em;
|
|
4112
|
-
width: 100%;
|
|
4113
|
-
overflow: hidden;
|
|
4114
|
-
white-space: nowrap;
|
|
4115
|
-
box-shadow:
|
|
4116
|
-
var(--ixfx-button-shade, none),
|
|
4117
|
-
inset 1px 1px 1px 1px color-mix(in oklch, var(--surface-4) 30%, transparent), inset -1px -1px 1px 1px color-mix(in oklch, var(--surface-2) 20%, transparent),
|
|
4118
|
-
2px 2px 1px 0px color-mix(in oklch, var(--surface-2) 30%, transparent);
|
|
4119
|
-
transition: background var(--transition, 0.2s), border-color var(--transition, 0.2s);
|
|
4032
|
+
/* ── flat: solid capsule / dot ────────────────────────────────────────── */
|
|
4033
|
+
.ixfx-handle[data-handle='flat'] {
|
|
4034
|
+
background: currentColor;
|
|
4035
|
+
border-radius: var(--_handle-radius);
|
|
4120
4036
|
}
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
opacity: 0.5;
|
|
4124
|
-
cursor: not-allowed;
|
|
4037
|
+
.ixfx-handle[data-handle='flat'][data-shape='spot'] {
|
|
4038
|
+
border-radius: 50%;
|
|
4125
4039
|
}
|
|
4126
4040
|
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
|
|
4130
|
-
|
|
4131
|
-
|
|
4132
|
-
|
|
4133
|
-
|
|
4041
|
+
/* ── dotted / dimpled: 3 marks in a row / column (or 3×3 for spot), drawn as
|
|
4042
|
+
one ::before mark whose border-radius follows the theme — round normally,
|
|
4043
|
+
square in a flat / squared-off theme (--radius-l: 0). box-shadow paints
|
|
4044
|
+
the rest of the marks. ─────────────────────────────────────────────── */
|
|
4045
|
+
.ixfx-handle[data-handle='dotted'],
|
|
4046
|
+
.ixfx-handle[data-handle='dimpled'] {
|
|
4047
|
+
position: relative;
|
|
4134
4048
|
}
|
|
4135
|
-
|
|
4136
|
-
|
|
4137
|
-
|
|
4138
|
-
|
|
4139
|
-
|
|
4049
|
+
.ixfx-handle[data-handle='dotted']::before,
|
|
4050
|
+
.ixfx-handle[data-handle='dimpled']::before {
|
|
4051
|
+
content: '';
|
|
4052
|
+
position: absolute;
|
|
4053
|
+
top: 50%;
|
|
4054
|
+
left: 50%;
|
|
4055
|
+
width: var(--_handle-dot);
|
|
4056
|
+
height: var(--_handle-dot);
|
|
4057
|
+
transform: translate(-50%, -50%);
|
|
4058
|
+
border-radius: var(--_handle-radius);
|
|
4059
|
+
background: currentColor;
|
|
4140
4060
|
}
|
|
4141
4061
|
|
|
4142
|
-
.
|
|
4143
|
-
|
|
4144
|
-
|
|
4145
|
-
|
|
4062
|
+
/* dotted — the two other marks are plain copies along the axis. */
|
|
4063
|
+
.ixfx-handle[data-handle='dotted']::before {
|
|
4064
|
+
box-shadow:
|
|
4065
|
+
calc(-1 * var(--_handle-gap)) 0 0 0 currentColor,
|
|
4066
|
+
var(--_handle-gap) 0 0 0 currentColor;
|
|
4146
4067
|
}
|
|
4147
|
-
|
|
4148
|
-
|
|
4149
|
-
|
|
4068
|
+
.ixfx-handle[data-handle='dotted'][data-shape='vertical']::before {
|
|
4069
|
+
box-shadow:
|
|
4070
|
+
0 calc(-1 * var(--_handle-gap)) 0 0 currentColor,
|
|
4071
|
+
0 var(--_handle-gap) 0 0 currentColor;
|
|
4150
4072
|
}
|
|
4151
|
-
|
|
4152
|
-
|
|
4153
|
-
|
|
4073
|
+
.ixfx-handle[data-handle='dotted'][data-shape='spot']::before,
|
|
4074
|
+
.ixfx-handle[data-handle='dimpled'][data-shape='spot']::before {
|
|
4075
|
+
box-shadow:
|
|
4076
|
+
calc(-1 * var(--_handle-gap)) calc(-1 * var(--_handle-gap)) 0 0 currentColor,
|
|
4077
|
+
0 calc(-1 * var(--_handle-gap)) 0 0 currentColor,
|
|
4078
|
+
var(--_handle-gap) calc(-1 * var(--_handle-gap)) 0 0 currentColor,
|
|
4079
|
+
calc(-1 * var(--_handle-gap)) 0 0 0 currentColor,
|
|
4080
|
+
var(--_handle-gap) 0 0 0 currentColor,
|
|
4081
|
+
calc(-1 * var(--_handle-gap)) var(--_handle-gap) 0 0 currentColor,
|
|
4082
|
+
0 var(--_handle-gap) 0 0 currentColor,
|
|
4083
|
+
var(--_handle-gap) var(--_handle-gap) 0 0 currentColor;
|
|
4154
4084
|
}
|
|
4155
4085
|
|
|
4156
|
-
|
|
4157
|
-
|
|
4086
|
+
/* dimpled — each bar mark also gets a lighter copy up-left and a darker copy
|
|
4087
|
+
down-right (spot stays plain — the 3D is imperceptible at that size). */
|
|
4088
|
+
.ixfx-handle[data-handle='dimpled']:not([data-shape='spot'])::before {
|
|
4089
|
+
box-shadow:
|
|
4090
|
+
calc(-1 * var(--_dimple-off)) calc(-1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
|
|
4091
|
+
var(--_dimple-off) var(--_dimple-off) 0 0 var(--_handle-lo),
|
|
4092
|
+
calc(-1 * var(--_handle-gap)) 0 0 0 currentColor,
|
|
4093
|
+
calc(-1 * var(--_handle-gap) - var(--_dimple-off)) calc(-1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
|
|
4094
|
+
calc(-1 * var(--_handle-gap) + var(--_dimple-off)) var(--_dimple-off) 0 0 var(--_handle-lo),
|
|
4095
|
+
var(--_handle-gap) 0 0 0 currentColor,
|
|
4096
|
+
calc(var(--_handle-gap) - var(--_dimple-off)) calc(-1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
|
|
4097
|
+
calc(var(--_handle-gap) + var(--_dimple-off)) var(--_dimple-off) 0 0 var(--_handle-lo);
|
|
4158
4098
|
}
|
|
4159
|
-
|
|
4160
|
-
|
|
4161
|
-
|
|
4099
|
+
.ixfx-handle[data-handle='dimpled'][data-shape='vertical']::before {
|
|
4100
|
+
box-shadow:
|
|
4101
|
+
calc(-1 * var(--_dimple-off)) calc(-1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
|
|
4102
|
+
var(--_dimple-off) var(--_dimple-off) 0 0 var(--_handle-lo),
|
|
4103
|
+
0 calc(-1 * var(--_handle-gap)) 0 0 currentColor,
|
|
4104
|
+
calc(-1 * var(--_dimple-off)) calc(-1 * var(--_handle-gap) - var(--_dimple-off)) 0 0 var(--_handle-hi),
|
|
4105
|
+
var(--_dimple-off) calc(-1 * var(--_handle-gap) + var(--_dimple-off)) 0 0 var(--_handle-lo),
|
|
4106
|
+
0 var(--_handle-gap) 0 0 currentColor,
|
|
4107
|
+
calc(-1 * var(--_dimple-off)) calc(var(--_handle-gap) - var(--_dimple-off)) 0 0 var(--_handle-hi),
|
|
4108
|
+
var(--_dimple-off) calc(var(--_handle-gap) + var(--_dimple-off)) 0 0 var(--_handle-lo);
|
|
4162
4109
|
}
|
|
4163
4110
|
|
|
4164
|
-
:
|
|
4165
|
-
|
|
4111
|
+
/* ── grated: fine 45° knurling — each ridge is a lit edge, the base colour,
|
|
4112
|
+
then a shaded edge. Same hatch at every shape (spot is a square crop). ── */
|
|
4113
|
+
.ixfx-handle[data-handle='grated'] {
|
|
4114
|
+
background-image: repeating-linear-gradient(
|
|
4115
|
+
45deg,
|
|
4116
|
+
var(--_handle-hi) 0 0.9px,
|
|
4117
|
+
currentColor 0.9px 1.6px,
|
|
4118
|
+
var(--_handle-lo) 1.6px 2.5px,
|
|
4119
|
+
transparent 2.5px var(--_handle-tile)
|
|
4120
|
+
);
|
|
4166
4121
|
}
|
|
4167
4122
|
|
|
4168
|
-
|
|
4169
|
-
|
|
4170
|
-
|
|
4123
|
+
@media (prefers-reduced-motion: reduce) {
|
|
4124
|
+
.ixfx-handle {
|
|
4125
|
+
transition: none;
|
|
4126
|
+
}
|
|
4171
4127
|
}
|
|
4172
4128
|
`;
|
|
4173
4129
|
//#endregion
|
|
4174
|
-
//#region src/
|
|
4175
|
-
let
|
|
4176
|
-
constructor(..._args) {
|
|
4177
|
-
super(..._args);
|
|
4178
|
-
this.disabled = false;
|
|
4179
|
-
this.hideIcon = false;
|
|
4180
|
-
this.hideLabel = false;
|
|
4181
|
-
this.hasIcon = false;
|
|
4182
|
-
this.subtle = false;
|
|
4183
|
-
}
|
|
4184
|
-
_renderIcon() {
|
|
4185
|
-
if (this.hideIcon || !this.icon) return A;
|
|
4186
|
-
if (this.icon.startsWith(`<svg`)) return b`<span class="button-icon">${unsafeHTML(this.icon)}</span>`;
|
|
4187
|
-
if (!hasIcon(this.icon)) return A;
|
|
4188
|
-
return b`<ixfx-icon class="button-icon" name="${this.icon}"></ixfx-icon>`;
|
|
4189
|
-
}
|
|
4190
|
-
render() {
|
|
4191
|
-
this.hasIcon = !this.hideIcon && !!this.icon;
|
|
4192
|
-
const label = this.hideLabel ? A : b`<span class="button-label"><slot></slot></span>`;
|
|
4193
|
-
return b`<button ?disabled=${this.disabled}>${this._renderIcon()}${label}</button>`;
|
|
4194
|
-
}
|
|
4195
|
-
static {
|
|
4196
|
-
this.styles = [prominenceStyles, buttonStyles];
|
|
4197
|
-
}
|
|
4198
|
-
};
|
|
4199
|
-
__decorate([property({ type: Boolean })], ButtonElement.prototype, "disabled", void 0);
|
|
4200
|
-
__decorate([property({ type: String })], ButtonElement.prototype, "icon", void 0);
|
|
4201
|
-
__decorate([property({
|
|
4202
|
-
type: Boolean,
|
|
4203
|
-
attribute: `hide-icon`,
|
|
4204
|
-
reflect: true
|
|
4205
|
-
})], ButtonElement.prototype, "hideIcon", void 0);
|
|
4206
|
-
__decorate([property({
|
|
4207
|
-
type: Boolean,
|
|
4208
|
-
attribute: `hide-label`,
|
|
4209
|
-
reflect: true
|
|
4210
|
-
})], ButtonElement.prototype, "hideLabel", void 0);
|
|
4211
|
-
__decorate([property({
|
|
4212
|
-
type: Boolean,
|
|
4213
|
-
attribute: `has-icon`,
|
|
4214
|
-
reflect: true
|
|
4215
|
-
})], ButtonElement.prototype, "hasIcon", void 0);
|
|
4216
|
-
__decorate([property({
|
|
4217
|
-
type: Boolean,
|
|
4218
|
-
reflect: true
|
|
4219
|
-
})], ButtonElement.prototype, "subtle", void 0);
|
|
4220
|
-
ButtonElement = __decorate([safeCustomElement(`ixfx-button`)], ButtonElement);
|
|
4221
|
-
//#endregion
|
|
4222
|
-
//#region src/button/radio-group.ts
|
|
4223
|
-
let RadioGroup = class RadioGroup extends i {
|
|
4130
|
+
//#region src/titlebar/titlebar.ts
|
|
4131
|
+
let TitlebarElement = class TitlebarElement extends i {
|
|
4224
4132
|
constructor(..._args) {
|
|
4225
4133
|
super(..._args);
|
|
4226
|
-
this.
|
|
4227
|
-
this.orientation = `horizontal`;
|
|
4228
|
-
this.items = [];
|
|
4229
|
-
this.name = ``;
|
|
4230
|
-
this.mode = `compact`;
|
|
4231
|
-
this.checked = false;
|
|
4232
|
-
this.valueOff = ``;
|
|
4134
|
+
this.title = ``;
|
|
4233
4135
|
this.iconName = ``;
|
|
4234
|
-
this.
|
|
4235
|
-
this.
|
|
4236
|
-
this.
|
|
4237
|
-
this.
|
|
4238
|
-
|
|
4239
|
-
|
|
4240
|
-
return this._computedItems.length === 0 && Boolean(this.textContent?.trim());
|
|
4241
|
-
}
|
|
4242
|
-
get _singleToggleIconName() {
|
|
4243
|
-
if (!this.iconName && !this.iconNameOff) return null;
|
|
4244
|
-
return this.checked ? this.iconName : this.iconNameOff || this.iconName;
|
|
4245
|
-
}
|
|
4246
|
-
firstUpdated() {
|
|
4247
|
-
this.#updateComputedItems();
|
|
4248
|
-
}
|
|
4249
|
-
updated(changedProperties) {
|
|
4250
|
-
if (changedProperties.has(`checked`)) {
|
|
4251
|
-
const input = this.shadowRoot?.querySelector(`.radio-toggle-input`);
|
|
4252
|
-
if (input && input.checked !== this.checked) {
|
|
4253
|
-
input.checked = this.checked;
|
|
4254
|
-
const newValue = this.checked ? this.value || `on` : this.valueOff || void 0;
|
|
4255
|
-
this.dispatchEvent(new CustomEvent(`change`, {
|
|
4256
|
-
detail: {
|
|
4257
|
-
checked: this.checked,
|
|
4258
|
-
value: newValue
|
|
4259
|
-
},
|
|
4260
|
-
bubbles: true,
|
|
4261
|
-
composed: true
|
|
4262
|
-
}));
|
|
4263
|
-
}
|
|
4264
|
-
}
|
|
4265
|
-
if (changedProperties.has(`value`) && !this._isSingleToggle) {
|
|
4266
|
-
const inputs = this.shadowRoot?.querySelectorAll(`.radio-input`);
|
|
4267
|
-
if (inputs) {
|
|
4268
|
-
for (const input of inputs) if (input.checked !== (input.value === this.value)) input.checked = input.value === this.value;
|
|
4269
|
-
}
|
|
4270
|
-
}
|
|
4271
|
-
}
|
|
4272
|
-
#updateComputedItems() {
|
|
4273
|
-
const options = this.querySelectorAll(`option`);
|
|
4274
|
-
const icons = /* @__PURE__ */ new Map();
|
|
4275
|
-
if (options.length > 0) {
|
|
4276
|
-
this._computedItems = Array.from(options, (el) => {
|
|
4277
|
-
const tempDiv = document.createElement(`div`);
|
|
4278
|
-
tempDiv.innerHTML = el.innerHTML;
|
|
4279
|
-
const iconEl = tempDiv.querySelector(`svg`);
|
|
4280
|
-
if (iconEl) icons.set(el.getAttribute(`value`) || ``, iconEl.outerHTML);
|
|
4281
|
-
return {
|
|
4282
|
-
value: el.getAttribute(`value`) || ``,
|
|
4283
|
-
label: el.textContent?.trim() || ``,
|
|
4284
|
-
disabled: el.hasAttribute(`disabled`),
|
|
4285
|
-
iconName: el.getAttribute(`icon-name`) || void 0,
|
|
4286
|
-
iconNameOff: el.getAttribute(`icon-name-off`) || void 0
|
|
4287
|
-
};
|
|
4288
|
-
});
|
|
4289
|
-
this._icons = icons;
|
|
4290
|
-
} else this._computedItems = [...this.items];
|
|
4136
|
+
this.orientation = `horizontal`;
|
|
4137
|
+
this.variant = `titlebar`;
|
|
4138
|
+
this.closable = false;
|
|
4139
|
+
this.collapsible = false;
|
|
4140
|
+
this.collapsed = false;
|
|
4141
|
+
this.toggleInteraction = `implicit`;
|
|
4291
4142
|
}
|
|
4292
|
-
|
|
4293
|
-
|
|
4294
|
-
|
|
4295
|
-
this.
|
|
4296
|
-
|
|
4297
|
-
detail: {
|
|
4298
|
-
checked: true,
|
|
4299
|
-
value: input.value
|
|
4300
|
-
},
|
|
4143
|
+
_onToggleClick() {
|
|
4144
|
+
if (!this.collapsible) return;
|
|
4145
|
+
this.collapsed = !this.collapsed;
|
|
4146
|
+
this.dispatchEvent(new CustomEvent(`toggle`, {
|
|
4147
|
+
detail: { collapsed: this.collapsed },
|
|
4301
4148
|
bubbles: true,
|
|
4302
4149
|
composed: true
|
|
4303
4150
|
}));
|
|
4304
4151
|
}
|
|
4305
|
-
|
|
4306
|
-
|
|
4307
|
-
const input = e.target;
|
|
4308
|
-
this.checked = input.checked;
|
|
4309
|
-
const newValue = this.checked ? this.value || `on` : this.valueOff || void 0;
|
|
4310
|
-
this.dispatchEvent(new CustomEvent(`change`, {
|
|
4311
|
-
detail: {
|
|
4312
|
-
checked: this.checked,
|
|
4313
|
-
value: newValue
|
|
4314
|
-
},
|
|
4152
|
+
_onCloseClick() {
|
|
4153
|
+
this.dispatchEvent(new CustomEvent(`close`, {
|
|
4315
4154
|
bubbles: true,
|
|
4316
4155
|
composed: true
|
|
4317
4156
|
}));
|
|
4318
4157
|
}
|
|
4319
|
-
|
|
4320
|
-
|
|
4321
|
-
if (iconName) return b`<ixfx-icon class="radio-icon" name="${iconName}"></ixfx-icon>`;
|
|
4322
|
-
const iconHtml = this._icons.get(item.value);
|
|
4323
|
-
if (!iconHtml) return null;
|
|
4324
|
-
return b`<span class="radio-icon">${unsafeHTML(iconHtml)}</span>`;
|
|
4158
|
+
_getCaretIcon() {
|
|
4159
|
+
return `chevron-down`;
|
|
4325
4160
|
}
|
|
4326
4161
|
render() {
|
|
4327
|
-
|
|
4328
|
-
|
|
4329
|
-
|
|
4330
|
-
|
|
4331
|
-
|
|
4332
|
-
|
|
4333
|
-
<input
|
|
4334
|
-
type="checkbox"
|
|
4335
|
-
class="radio-toggle-input"
|
|
4336
|
-
?checked=${this.checked}
|
|
4337
|
-
@change=${this.#handleToggleChange}
|
|
4338
|
-
/>
|
|
4339
|
-
${iconPart}
|
|
4340
|
-
${labelPart}
|
|
4341
|
-
</label>
|
|
4342
|
-
`;
|
|
4343
|
-
}
|
|
4162
|
+
const caretIcon = this._getCaretIcon();
|
|
4163
|
+
const isVertical = this.orientation === `vertical`;
|
|
4164
|
+
const showCaret = this.collapsible && this.toggleInteraction !== `disabled`;
|
|
4165
|
+
const implicitToggle = this.collapsible && this.toggleInteraction === `implicit`;
|
|
4166
|
+
const caretRotation = isVertical ? this.collapsed ? `` : `-90deg` : this.collapsed ? `-90deg` : ``;
|
|
4167
|
+
const treeVariant = this.variant === `tree`;
|
|
4344
4168
|
return b`
|
|
4345
|
-
<
|
|
4346
|
-
|
|
4347
|
-
|
|
4348
|
-
|
|
4349
|
-
|
|
4350
|
-
|
|
4351
|
-
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
|
|
4357
|
-
|
|
4358
|
-
|
|
4359
|
-
|
|
4360
|
-
|
|
4361
|
-
|
|
4362
|
-
|
|
4363
|
-
|
|
4364
|
-
|
|
4365
|
-
|
|
4366
|
-
|
|
4169
|
+
<div
|
|
4170
|
+
class="bar"
|
|
4171
|
+
role="toolbar"
|
|
4172
|
+
@click=${implicitToggle ? this._onToggleClick : A}
|
|
4173
|
+
>
|
|
4174
|
+
${treeVariant && showCaret ? b`
|
|
4175
|
+
<button
|
|
4176
|
+
class="caret-btn"
|
|
4177
|
+
type="button"
|
|
4178
|
+
aria-label=${this.collapsed ? `Expand panel` : `Collapse panel`}
|
|
4179
|
+
@click=${this._onToggleClick}
|
|
4180
|
+
>
|
|
4181
|
+
<ixfx-icon name=${caretIcon} prominence .rotate=${caretRotation.length > 0 ? caretRotation : A}></ixfx-icon>
|
|
4182
|
+
</button>
|
|
4183
|
+
` : A}
|
|
4184
|
+
<div class="title-text-wrapper">
|
|
4185
|
+
${this.iconName ? b`<ixfx-icon class="title-icon" name=${this.iconName}></ixfx-icon>` : A}
|
|
4186
|
+
<span class="title-text">${this.title}</span>
|
|
4187
|
+
</div>
|
|
4188
|
+
|
|
4189
|
+
<div class="toolbar" @click=${(e) => e.stopPropagation()}>
|
|
4190
|
+
<slot name="toolbar"></slot>
|
|
4191
|
+
${this.closable ? b`
|
|
4192
|
+
<button
|
|
4193
|
+
class="close-btn"
|
|
4194
|
+
type="button"
|
|
4195
|
+
aria-label="Close panel"
|
|
4196
|
+
@click=${this._onCloseClick}
|
|
4197
|
+
>
|
|
4198
|
+
<ixfx-icon name="close"></ixfx-icon>
|
|
4199
|
+
</button>
|
|
4200
|
+
` : A}
|
|
4201
|
+
${!treeVariant && showCaret ? b`
|
|
4202
|
+
<button
|
|
4203
|
+
class="caret-btn"
|
|
4204
|
+
type="button"
|
|
4205
|
+
aria-label=${this.collapsed ? `Expand panel` : `Collapse panel`}
|
|
4206
|
+
@click=${this._onToggleClick}
|
|
4207
|
+
>
|
|
4208
|
+
<ixfx-icon name=${caretIcon} prominence .rotate=${caretRotation.length > 0 ? caretRotation : A}></ixfx-icon>
|
|
4209
|
+
</button>
|
|
4210
|
+
` : A}
|
|
4211
|
+
</div>
|
|
4367
4212
|
</div>
|
|
4368
4213
|
`;
|
|
4369
4214
|
}
|
|
4370
4215
|
static {
|
|
4371
|
-
this.styles = [
|
|
4372
|
-
themeFallbacks,
|
|
4373
|
-
prominenceStyles,
|
|
4374
|
-
i$3`
|
|
4216
|
+
this.styles = [themeFallbacks, i$3`
|
|
4375
4217
|
:host {
|
|
4376
|
-
|
|
4377
|
-
|
|
4218
|
+
--titlebar-background: var(--surface-4);
|
|
4219
|
+
|
|
4220
|
+
display: block;
|
|
4221
|
+
box-sizing: border-box;
|
|
4222
|
+
}
|
|
4223
|
+
|
|
4224
|
+
.bar {
|
|
4225
|
+
display: flex;
|
|
4226
|
+
flex-direction: row;
|
|
4227
|
+
align-items: center;
|
|
4228
|
+
padding: var(--space-s) var(--space-m);
|
|
4229
|
+
background: var(--titlebar-background);
|
|
4230
|
+
color: var(--surface-3-text);
|
|
4231
|
+
min-height: 2em;
|
|
4232
|
+
height: 100%;
|
|
4233
|
+
flex-shrink: 0;
|
|
4234
|
+
box-sizing: border-box;
|
|
4235
|
+
}
|
|
4236
|
+
|
|
4237
|
+
:host([orientation="vertical"]) .bar {
|
|
4238
|
+
flex-direction: row;
|
|
4239
|
+
min-width: 2em;
|
|
4240
|
+
writing-mode: vertical-rl;
|
|
4241
|
+
text-orientation: mixed;
|
|
4242
|
+
}
|
|
4243
|
+
|
|
4244
|
+
.caret-btn,
|
|
4245
|
+
.close-btn {
|
|
4246
|
+
display: inline-flex;
|
|
4247
|
+
align-items: center;
|
|
4248
|
+
justify-content: center;
|
|
4249
|
+
background: none;
|
|
4250
|
+
border: none;
|
|
4251
|
+
padding: var(--space-xs);
|
|
4252
|
+
margin: 0;
|
|
4253
|
+
cursor: pointer;
|
|
4254
|
+
color: inherit;
|
|
4255
|
+
border-radius: var(--radius-s);
|
|
4256
|
+
transition: background var(--transition);
|
|
4257
|
+
opacity: var(--prominence-idle-opacity);
|
|
4258
|
+
}
|
|
4259
|
+
|
|
4260
|
+
.caret-btn:hover,
|
|
4261
|
+
.close-btn:hover {
|
|
4262
|
+
background: var(--surface-5);
|
|
4263
|
+
opacity: var(--prominence-tickled-opacity);
|
|
4264
|
+
}
|
|
4265
|
+
|
|
4266
|
+
.caret-btn:focus-visible,
|
|
4267
|
+
.close-btn:focus-visible {
|
|
4268
|
+
outline: 2px solid var(--accent);
|
|
4269
|
+
outline-offset: 1px;
|
|
4270
|
+
}
|
|
4271
|
+
|
|
4272
|
+
ixfx-icon {
|
|
4273
|
+
width: 1.25em;
|
|
4274
|
+
height: 1.25em;
|
|
4275
|
+
transition: transform var(--transition);
|
|
4276
|
+
}
|
|
4277
|
+
|
|
4278
|
+
.title-icon {
|
|
4279
|
+
flex-shrink: 0;
|
|
4280
|
+
}
|
|
4281
|
+
|
|
4282
|
+
.title-text {
|
|
4283
|
+
flex: 1;
|
|
4284
|
+
padding-left: 1ch;
|
|
4285
|
+
font-family: var(--font-family);
|
|
4286
|
+
font-size: var(--text-m);
|
|
4287
|
+
font-weight: var(--font-weight-bold, 600);
|
|
4288
|
+
white-space: nowrap;
|
|
4289
|
+
overflow: hidden;
|
|
4290
|
+
align-self: center;
|
|
4291
|
+
text-overflow: ellipsis;
|
|
4292
|
+
user-select: none;
|
|
4293
|
+
-webkit-user-select: none;
|
|
4294
|
+
}
|
|
4295
|
+
|
|
4296
|
+
:host([collapsible][toggle-interaction="implicit"]) .bar {
|
|
4297
|
+
cursor: pointer;
|
|
4298
|
+
}
|
|
4299
|
+
|
|
4300
|
+
:host([orientation="vertical"]) .title-text {
|
|
4301
|
+
writing-mode: vertical-rl;
|
|
4302
|
+
padding-left: 0;
|
|
4303
|
+
padding-bottom: 1ch;
|
|
4304
|
+
text-orientation: mixed;
|
|
4305
|
+
transform: rotate(180deg);
|
|
4306
|
+
}
|
|
4307
|
+
|
|
4308
|
+
.toolbar {
|
|
4309
|
+
display: flex;
|
|
4310
|
+
align-items: center;
|
|
4311
|
+
gap: var(--space-xs);
|
|
4312
|
+
margin-left: auto;
|
|
4313
|
+
}
|
|
4314
|
+
|
|
4315
|
+
:host([orientation="vertical"]) .toolbar {
|
|
4316
|
+
flex-direction: column;
|
|
4317
|
+
margin-left: 0;
|
|
4318
|
+
margin-top: auto;
|
|
4319
|
+
writing-mode: horizontal-tb;
|
|
4320
|
+
}
|
|
4321
|
+
|
|
4322
|
+
slot[name="toolbar"] {
|
|
4323
|
+
display: contents;
|
|
4324
|
+
}
|
|
4325
|
+
|
|
4326
|
+
::slotted(slot[name="toolbar"]) {
|
|
4327
|
+
display: contents;
|
|
4328
|
+
}
|
|
4329
|
+
|
|
4330
|
+
.title-text-wrapper {
|
|
4331
|
+
display: flex;
|
|
4332
|
+
padding: 0 var(--space-s);
|
|
4333
|
+
}
|
|
4334
|
+
|
|
4335
|
+
/* === Midline variant === */
|
|
4336
|
+
|
|
4337
|
+
:host([variant="midline"]) .bar {
|
|
4338
|
+
background: transparent;
|
|
4339
|
+
padding: var(--space-xs) var(--space-m);
|
|
4340
|
+
min-height: unset;
|
|
4341
|
+
position: relative;
|
|
4342
|
+
}
|
|
4343
|
+
|
|
4344
|
+
:host([variant="midline"][orientation="vertical"]) .bar {
|
|
4345
|
+
padding: var(--space-m) var(--space-xs);
|
|
4346
|
+
min-width: unset;
|
|
4347
|
+
}
|
|
4348
|
+
|
|
4349
|
+
:host([variant="midline"]) .title-text-wrapper {
|
|
4350
|
+
position: relative;
|
|
4351
|
+
z-index: 1;
|
|
4352
|
+
display: flex;
|
|
4353
|
+
align-items: center;
|
|
4354
|
+
gap: var(--space-s);
|
|
4355
|
+
background: var(--surface-3);
|
|
4356
|
+
}
|
|
4357
|
+
|
|
4358
|
+
:host([variant="midline"]) .title-text {
|
|
4359
|
+
font-weight: normal;
|
|
4360
|
+
color: var(--surface-3-text);
|
|
4361
|
+
padding: 0 0.5ch 0 0.5ch;
|
|
4362
|
+
background: transparent;
|
|
4363
|
+
box-shadow: none;
|
|
4364
|
+
flex: unset;
|
|
4365
|
+
width: auto;
|
|
4366
|
+
white-space: nowrap;
|
|
4367
|
+
}
|
|
4368
|
+
|
|
4369
|
+
:host([variant="midline"]) .title-icon {
|
|
4370
|
+
background: transparent;
|
|
4371
|
+
flex-shrink: 0;
|
|
4372
|
+
}
|
|
4373
|
+
|
|
4374
|
+
:host([variant="midline"]) .caret-btn {
|
|
4375
|
+
position: relative;
|
|
4376
|
+
z-index: 1;
|
|
4377
|
+
background: var(--surface-3);
|
|
4378
|
+
opacity: 1;
|
|
4379
|
+
}
|
|
4380
|
+
|
|
4381
|
+
:host([variant="midline"][orientation="vertical"]) .title-text {
|
|
4382
|
+
transform: rotate(180deg);
|
|
4383
|
+
padding: 0.5ch 0 0.5ch 0ch;
|
|
4384
|
+
}
|
|
4385
|
+
|
|
4386
|
+
:host([variant="midline"]) .toolbar {
|
|
4387
|
+
position: relative;
|
|
4388
|
+
z-index: 2;
|
|
4389
|
+
background: var(--surface-3);
|
|
4390
|
+
margin-left: 0;
|
|
4391
|
+
}
|
|
4392
|
+
|
|
4393
|
+
:host([variant="midline"][orientation="horizontal"]) .toolbar {
|
|
4394
|
+
margin-left: auto;
|
|
4395
|
+
}
|
|
4396
|
+
|
|
4397
|
+
/* Debossed line runs from after title-text to before toolbar */
|
|
4398
|
+
:host([variant="midline"]) .bar::after {
|
|
4399
|
+
content: '';
|
|
4400
|
+
position: absolute;
|
|
4401
|
+
top: 50%;
|
|
4402
|
+
left: 0;
|
|
4403
|
+
right: 0;
|
|
4404
|
+
height: 1px;
|
|
4405
|
+
transform: translateY(-50%);
|
|
4406
|
+
background: var(--surface-2);
|
|
4407
|
+
box-shadow:
|
|
4408
|
+
0 -1px 0 var(--surface-5),
|
|
4409
|
+
0 1px 0 var(--surface-1);
|
|
4410
|
+
z-index: 0;
|
|
4411
|
+
}
|
|
4412
|
+
|
|
4413
|
+
/* For vertical midline, line runs vertically */
|
|
4414
|
+
:host([variant="midline"][orientation="vertical"]) .bar::after {
|
|
4415
|
+
top: 0;
|
|
4416
|
+
bottom: 0;
|
|
4417
|
+
left: 50%;
|
|
4418
|
+
right: unset;
|
|
4419
|
+
width: 1px;
|
|
4420
|
+
height: 100%;
|
|
4421
|
+
transform: translateX(-50%);
|
|
4422
|
+
box-shadow:
|
|
4423
|
+
-1px 0 0 var(--surface-5),
|
|
4424
|
+
1px 0 0 var(--surface-1);
|
|
4425
|
+
}
|
|
4426
|
+
|
|
4427
|
+
/* === Tree variant: VS Code explorer / Outline style === */
|
|
4428
|
+
:host([variant="tree"]) .bar {
|
|
4429
|
+
background: transparent;
|
|
4430
|
+
padding: 0 var(--space-xs);
|
|
4431
|
+
min-height: unset;
|
|
4432
|
+
gap: var(--space-xs);
|
|
4433
|
+
}
|
|
4434
|
+
|
|
4435
|
+
:host([variant="tree"][orientation="vertical"]) .bar {
|
|
4436
|
+
padding: var(--space-xs) 0;
|
|
4437
|
+
flex-direction: column;
|
|
4438
|
+
min-width: unset;
|
|
4439
|
+
writing-mode: horizontal-tb;
|
|
4440
|
+
}
|
|
4441
|
+
|
|
4442
|
+
:host([variant="tree"]) .title-text-wrapper {
|
|
4443
|
+
display: inline-flex;
|
|
4444
|
+
align-items: center;
|
|
4445
|
+
gap: var(--space-xs);
|
|
4446
|
+
padding: 0;
|
|
4447
|
+
background: transparent;
|
|
4448
|
+
}
|
|
4449
|
+
|
|
4450
|
+
:host([variant="tree"]) .title-icon {
|
|
4451
|
+
background: transparent;
|
|
4452
|
+
flex-shrink: 0;
|
|
4453
|
+
}
|
|
4454
|
+
|
|
4455
|
+
:host([variant="tree"]) .title-text {
|
|
4456
|
+
font-weight: normal;
|
|
4457
|
+
color: var(--surface-3-text);
|
|
4458
|
+
padding: 0;
|
|
4459
|
+
background: transparent;
|
|
4460
|
+
box-shadow: none;
|
|
4461
|
+
flex: unset;
|
|
4462
|
+
width: auto;
|
|
4463
|
+
white-space: nowrap;
|
|
4464
|
+
}
|
|
4465
|
+
|
|
4466
|
+
:host([variant="tree"][orientation="vertical"]) .title-text {
|
|
4467
|
+
writing-mode: vertical-rl;
|
|
4468
|
+
transform: rotate(180deg);
|
|
4469
|
+
padding: 0;
|
|
4470
|
+
}
|
|
4471
|
+
|
|
4472
|
+
:host([variant="tree"]) .caret-btn {
|
|
4473
|
+
background: transparent;
|
|
4474
|
+
opacity: var(--prominence-idle-opacity);
|
|
4475
|
+
padding: 0;
|
|
4476
|
+
}
|
|
4477
|
+
|
|
4478
|
+
:host([variant="tree"]) .caret-btn:hover {
|
|
4479
|
+
background: transparent;
|
|
4480
|
+
opacity: var(--prominence-tickled-opacity);
|
|
4481
|
+
}
|
|
4482
|
+
|
|
4483
|
+
:host([variant="tree"]) .toolbar {
|
|
4484
|
+
margin-left: auto;
|
|
4485
|
+
}
|
|
4486
|
+
|
|
4487
|
+
:host([variant="tree"][orientation="vertical"]) .toolbar {
|
|
4488
|
+
flex-direction: row;
|
|
4489
|
+
margin-left: 0;
|
|
4490
|
+
margin-top: auto;
|
|
4491
|
+
}
|
|
4492
|
+
|
|
4493
|
+
:host([variant="tree"]) ixfx-icon {
|
|
4494
|
+
width: 1em;
|
|
4495
|
+
height: 1em;
|
|
4496
|
+
}
|
|
4497
|
+
`];
|
|
4498
|
+
}
|
|
4499
|
+
};
|
|
4500
|
+
__decorate([property({ type: String })], TitlebarElement.prototype, "title", void 0);
|
|
4501
|
+
__decorate([property({
|
|
4502
|
+
type: String,
|
|
4503
|
+
attribute: `icon-name`
|
|
4504
|
+
})], TitlebarElement.prototype, "iconName", void 0);
|
|
4505
|
+
__decorate([property({
|
|
4506
|
+
type: String,
|
|
4507
|
+
attribute: `orientation`,
|
|
4508
|
+
reflect: true
|
|
4509
|
+
})], TitlebarElement.prototype, "orientation", void 0);
|
|
4510
|
+
__decorate([property({
|
|
4511
|
+
type: String,
|
|
4512
|
+
attribute: `variant`,
|
|
4513
|
+
reflect: true
|
|
4514
|
+
})], TitlebarElement.prototype, "variant", void 0);
|
|
4515
|
+
__decorate([property({ type: Boolean })], TitlebarElement.prototype, "closable", void 0);
|
|
4516
|
+
__decorate([property({
|
|
4517
|
+
type: Boolean,
|
|
4518
|
+
reflect: true
|
|
4519
|
+
})], TitlebarElement.prototype, "collapsible", void 0);
|
|
4520
|
+
__decorate([property({
|
|
4521
|
+
type: Boolean,
|
|
4522
|
+
reflect: true
|
|
4523
|
+
})], TitlebarElement.prototype, "collapsed", void 0);
|
|
4524
|
+
__decorate([property({
|
|
4525
|
+
type: String,
|
|
4526
|
+
attribute: `toggle-interaction`
|
|
4527
|
+
})], TitlebarElement.prototype, "toggleInteraction", void 0);
|
|
4528
|
+
TitlebarElement = __decorate([safeCustomElement(`ixfx-titlebar`)], TitlebarElement);
|
|
4529
|
+
//#endregion
|
|
4530
|
+
//#region src/bottom-drawer/bottom-drawer.ts
|
|
4531
|
+
/** Builds the command id for a named drawer's command, e.g. `inspector.expand`. */
|
|
4532
|
+
function bottomDrawerCommandId(name, command) {
|
|
4533
|
+
return `${name.trim()}.${command}`;
|
|
4534
|
+
}
|
|
4535
|
+
function clampRange(value, min, max) {
|
|
4536
|
+
return Math.min(max, Math.max(min, value));
|
|
4537
|
+
}
|
|
4538
|
+
let BottomDrawerElement = class BottomDrawerElement extends i {
|
|
4539
|
+
constructor(..._args) {
|
|
4540
|
+
super(..._args);
|
|
4541
|
+
this.open = false;
|
|
4542
|
+
this.height = 320;
|
|
4543
|
+
this.minHeight = 160;
|
|
4544
|
+
this.dismissThreshold = 96;
|
|
4545
|
+
this.maxHeightRatio = .85;
|
|
4546
|
+
this.label = `Drawer`;
|
|
4547
|
+
this.iconName = ``;
|
|
4548
|
+
this.closable = true;
|
|
4549
|
+
this.collapsible = true;
|
|
4550
|
+
this.maintainHandle = false;
|
|
4551
|
+
this.name = ``;
|
|
4552
|
+
this.#dragStartY = 0;
|
|
4553
|
+
this.#dragStartHeight = 0;
|
|
4554
|
+
this.#collapsedDragging = false;
|
|
4555
|
+
this.#commandName = ``;
|
|
4556
|
+
this.#commandIds = [];
|
|
4557
|
+
this.#onResizeStart = (event) => {
|
|
4558
|
+
if (event.button !== 0) return;
|
|
4559
|
+
event.preventDefault();
|
|
4560
|
+
const edge = event.currentTarget;
|
|
4561
|
+
edge.setPointerCapture(event.pointerId);
|
|
4562
|
+
if (!this.open) {
|
|
4563
|
+
this.#collapsedDragging = false;
|
|
4564
|
+
this.#dragStartY = event.clientY;
|
|
4565
|
+
this.#dragStartHeight = this.dismissThreshold;
|
|
4566
|
+
edge.addEventListener(`pointermove`, this.#onTabPointerMove);
|
|
4567
|
+
edge.addEventListener(`pointerup`, this.#onTabPointerUp, { once: true });
|
|
4568
|
+
edge.addEventListener(`pointercancel`, this.#onTabPointerUp, { once: true });
|
|
4569
|
+
return;
|
|
4570
|
+
}
|
|
4571
|
+
this.#dragStartY = event.clientY;
|
|
4572
|
+
this.#dragStartHeight = this.#displayHeight();
|
|
4573
|
+
this._dragHeight = this.#dragStartHeight;
|
|
4574
|
+
this.toggleAttribute(`resizing`, true);
|
|
4575
|
+
edge.addEventListener(`pointermove`, this.#onResizeMove);
|
|
4576
|
+
edge.addEventListener(`pointerup`, this.#onResizeEnd, { once: true });
|
|
4577
|
+
edge.addEventListener(`pointercancel`, this.#onResizeEnd, { once: true });
|
|
4578
|
+
};
|
|
4579
|
+
this.#onResizeMove = (event) => {
|
|
4580
|
+
this._dragHeight = clampRange(this.#dragStartHeight + this.#dragStartY - event.clientY, 0, this.#maxHeight());
|
|
4581
|
+
};
|
|
4582
|
+
this.#onResizeEnd = (event) => {
|
|
4583
|
+
const edge = event.currentTarget;
|
|
4584
|
+
edge.removeEventListener(`pointermove`, this.#onResizeMove);
|
|
4585
|
+
edge.removeEventListener(`pointerup`, this.#onResizeEnd);
|
|
4586
|
+
edge.removeEventListener(`pointercancel`, this.#onResizeEnd);
|
|
4587
|
+
if (edge.hasPointerCapture(event.pointerId)) edge.releasePointerCapture(event.pointerId);
|
|
4588
|
+
this.toggleAttribute(`resizing`, false);
|
|
4589
|
+
const height = this._dragHeight ?? this.height;
|
|
4590
|
+
this._dragHeight = void 0;
|
|
4591
|
+
if (height < this.dismissThreshold) {
|
|
4592
|
+
this.close();
|
|
4593
|
+
return;
|
|
4594
|
+
}
|
|
4595
|
+
this.#setHeight(height);
|
|
4596
|
+
};
|
|
4597
|
+
this.#onResizeKeyDown = (event) => {
|
|
4598
|
+
if (!this.open) {
|
|
4599
|
+
if (event.key === `ArrowUp` || event.key === `Enter` || event.key === ` ` || event.key === `Home` || event.key === `End`) {
|
|
4600
|
+
event.preventDefault();
|
|
4601
|
+
this.show();
|
|
4602
|
+
}
|
|
4603
|
+
return;
|
|
4604
|
+
}
|
|
4605
|
+
const delta = event.shiftKey ? 64 : 16;
|
|
4606
|
+
if (event.key === `ArrowUp`) {
|
|
4607
|
+
event.preventDefault();
|
|
4608
|
+
this.#setHeight(this.height + delta);
|
|
4609
|
+
} else if (event.key === `ArrowDown`) {
|
|
4610
|
+
event.preventDefault();
|
|
4611
|
+
if (this.height - delta < this.dismissThreshold) this.close();
|
|
4612
|
+
else this.#setHeight(this.height - delta);
|
|
4613
|
+
} else if (event.key === `Home`) {
|
|
4614
|
+
event.preventDefault();
|
|
4615
|
+
this.#setHeight(this.minHeight);
|
|
4616
|
+
} else if (event.key === `End`) {
|
|
4617
|
+
event.preventDefault();
|
|
4618
|
+
this.#setHeight(this.#maxHeight());
|
|
4619
|
+
}
|
|
4620
|
+
};
|
|
4621
|
+
this.#onTabPointerMove = (event) => {
|
|
4622
|
+
const delta = this.#dragStartY - event.clientY;
|
|
4623
|
+
if (!this.#collapsedDragging) {
|
|
4624
|
+
if (delta < 4) return;
|
|
4625
|
+
this.#collapsedDragging = true;
|
|
4626
|
+
this.show();
|
|
4627
|
+
this.toggleAttribute(`resizing`, true);
|
|
4628
|
+
}
|
|
4629
|
+
this._dragHeight = clampRange(this.#dragStartHeight + this.#dragStartY - event.clientY, 0, this.#maxHeight());
|
|
4630
|
+
};
|
|
4631
|
+
this.#onTabPointerUp = (event) => {
|
|
4632
|
+
const target = event.currentTarget;
|
|
4633
|
+
target.removeEventListener(`pointermove`, this.#onTabPointerMove);
|
|
4634
|
+
target.removeEventListener(`pointerup`, this.#onTabPointerUp);
|
|
4635
|
+
target.removeEventListener(`pointercancel`, this.#onTabPointerUp);
|
|
4636
|
+
if (target.hasPointerCapture(event.pointerId)) target.releasePointerCapture(event.pointerId);
|
|
4637
|
+
if (!this.#collapsedDragging) {
|
|
4638
|
+
this.show();
|
|
4639
|
+
return;
|
|
4640
|
+
}
|
|
4641
|
+
this.#collapsedDragging = false;
|
|
4642
|
+
this.toggleAttribute(`resizing`, false);
|
|
4643
|
+
const height = this._dragHeight ?? this.height;
|
|
4644
|
+
this._dragHeight = void 0;
|
|
4645
|
+
if (height < this.dismissThreshold) {
|
|
4646
|
+
this.close();
|
|
4647
|
+
return;
|
|
4648
|
+
}
|
|
4649
|
+
this.#setHeight(height);
|
|
4650
|
+
};
|
|
4651
|
+
this.#onDrawerKeyDown = (event) => {
|
|
4652
|
+
if (event.key !== `Escape`) return;
|
|
4653
|
+
event.preventDefault();
|
|
4654
|
+
event.stopPropagation();
|
|
4655
|
+
this.close();
|
|
4656
|
+
};
|
|
4657
|
+
}
|
|
4658
|
+
static {
|
|
4659
|
+
this.styles = [
|
|
4660
|
+
themeFallbacks,
|
|
4661
|
+
handleStyles,
|
|
4662
|
+
i$3`
|
|
4663
|
+
:host {
|
|
4664
|
+
--bottom-drawer-background: color-mix(in srgb, var(--surface-2) 84%, transparent);
|
|
4665
|
+
--bottom-drawer-border: 1px solid color-mix(in srgb, var(--surface-2-text) 14%, transparent);
|
|
4666
|
+
--bottom-drawer-radius: var(--radius-l);
|
|
4667
|
+
--bottom-drawer-blur: 18px;
|
|
4668
|
+
--bottom-drawer-shadow: var(--shadow-l);
|
|
4669
|
+
--bottom-drawer-collapsed-width: 96px;
|
|
4670
|
+
|
|
4671
|
+
display: block;
|
|
4672
|
+
position: relative;
|
|
4673
|
+
height: 100%;
|
|
4674
|
+
min-width: 0;
|
|
4675
|
+
min-height: 0;
|
|
4676
|
+
overflow: hidden;
|
|
4677
|
+
}
|
|
4678
|
+
.content {
|
|
4679
|
+
position: absolute;
|
|
4680
|
+
inset: 0;
|
|
4681
|
+
min-width: 0;
|
|
4682
|
+
min-height: 0;
|
|
4683
|
+
}
|
|
4684
|
+
.content ::slotted(*) {
|
|
4685
|
+
width: 100%;
|
|
4686
|
+
height: 100%;
|
|
4687
|
+
}
|
|
4688
|
+
.drawer {
|
|
4689
|
+
--m: 0;
|
|
4690
|
+
position: absolute;
|
|
4691
|
+
z-index: 2;
|
|
4692
|
+
right: calc(var(--m) * (50% - var(--bottom-drawer-collapsed-width) / 2));
|
|
4693
|
+
bottom: 0;
|
|
4694
|
+
left: calc(var(--m) * (50% - var(--bottom-drawer-collapsed-width) / 2));
|
|
4695
|
+
display: flex;
|
|
4696
|
+
flex-direction: column;
|
|
4697
|
+
box-sizing: border-box;
|
|
4698
|
+
height: var(--bottom-drawer-height);
|
|
4699
|
+
max-height: 100%;
|
|
4700
|
+
min-height: 0;
|
|
4701
|
+
color: var(--surface-2-text);
|
|
4702
|
+
background: var(--bottom-drawer-background);
|
|
4703
|
+
border: var(--bottom-drawer-border);
|
|
4704
|
+
border-bottom: 0;
|
|
4705
|
+
border-radius: var(--bottom-drawer-radius) var(--bottom-drawer-radius) 0 0;
|
|
4706
|
+
box-shadow: var(--bottom-drawer-shadow);
|
|
4707
|
+
backdrop-filter: blur(var(--bottom-drawer-blur)) saturate(1.15);
|
|
4708
|
+
-webkit-backdrop-filter: blur(var(--bottom-drawer-blur)) saturate(1.15);
|
|
4709
|
+
opacity: 0;
|
|
4710
|
+
transform: translateY(100%);
|
|
4711
|
+
visibility: hidden;
|
|
4712
|
+
transition:
|
|
4713
|
+
transform var(--transition),
|
|
4714
|
+
opacity var(--transition),
|
|
4715
|
+
left var(--transition),
|
|
4716
|
+
right var(--transition),
|
|
4717
|
+
height var(--transition),
|
|
4718
|
+
visibility 0s linear 0.16s;
|
|
4719
|
+
will-change: transform, opacity;
|
|
4720
|
+
}
|
|
4721
|
+
:host([open]) .drawer {
|
|
4722
|
+
opacity: var(--bottom-drawer-opacity, 1);
|
|
4723
|
+
transform: translateY(0);
|
|
4724
|
+
visibility: visible;
|
|
4725
|
+
transition:
|
|
4726
|
+
transform var(--transition),
|
|
4727
|
+
opacity var(--transition),
|
|
4728
|
+
left var(--transition),
|
|
4729
|
+
right var(--transition),
|
|
4730
|
+
height var(--transition);
|
|
4731
|
+
}
|
|
4732
|
+
:host([resizing]) {
|
|
4733
|
+
cursor: ns-resize;
|
|
4734
|
+
user-select: none;
|
|
4735
|
+
}
|
|
4736
|
+
:host([resizing]) .drawer {
|
|
4737
|
+
transition: none;
|
|
4738
|
+
}
|
|
4739
|
+
.resize-edge {
|
|
4740
|
+
position: absolute;
|
|
4741
|
+
z-index: 1;
|
|
4742
|
+
top: -5px;
|
|
4743
|
+
right: 0;
|
|
4744
|
+
left: 0;
|
|
4745
|
+
height: 11px;
|
|
4746
|
+
cursor: ns-resize;
|
|
4747
|
+
touch-action: none;
|
|
4748
|
+
outline: none;
|
|
4749
|
+
}
|
|
4750
|
+
.resize-edge .ixfx-handle {
|
|
4751
|
+
position: absolute;
|
|
4752
|
+
top: 7px;
|
|
4753
|
+
left: 50%;
|
|
4754
|
+
transform: translateX(-50%);
|
|
4755
|
+
--ixfx-handle-length: 44px;
|
|
4756
|
+
--ixfx-handle-thickness: 3px;
|
|
4757
|
+
--ixfx-handle-radius: 999px;
|
|
4758
|
+
}
|
|
4759
|
+
/* Inner content fades as the drawer morphs into its collapsed tab. */
|
|
4760
|
+
ixfx-titlebar,
|
|
4761
|
+
.body {
|
|
4762
|
+
opacity: calc(1 - var(--m, 0));
|
|
4763
|
+
transition: opacity var(--transition);
|
|
4764
|
+
}
|
|
4765
|
+
:host([resizing]) ixfx-titlebar,
|
|
4766
|
+
:host([resizing]) .body {
|
|
4767
|
+
transition: none;
|
|
4768
|
+
}
|
|
4769
|
+
/* Collapsed tab: docked to the bottom edge, narrowed to handle width. */
|
|
4770
|
+
:host([maintain-handle]:not([open])) .drawer {
|
|
4771
|
+
--m: 1;
|
|
4772
|
+
height: 20px;
|
|
4773
|
+
opacity: 1;
|
|
4774
|
+
transform: translateY(0);
|
|
4775
|
+
visibility: visible;
|
|
4776
|
+
transition:
|
|
4777
|
+
transform var(--transition),
|
|
4778
|
+
opacity var(--transition),
|
|
4779
|
+
left var(--transition),
|
|
4780
|
+
right var(--transition),
|
|
4781
|
+
height var(--transition);
|
|
4782
|
+
}
|
|
4783
|
+
:host([maintain-handle]:not([open])) ixfx-titlebar,
|
|
4784
|
+
:host([maintain-handle]:not([open])) .body {
|
|
4785
|
+
display: none;
|
|
4786
|
+
}
|
|
4787
|
+
:host([maintain-handle]:not([open])) .resize-edge {
|
|
4788
|
+
top: 0;
|
|
4789
|
+
height: 100%;
|
|
4790
|
+
}
|
|
4791
|
+
:host([maintain-handle]:not([open])) .resize-edge .ixfx-handle {
|
|
4792
|
+
top: 50%;
|
|
4793
|
+
transform: translate(-50%, -50%);
|
|
4794
|
+
}
|
|
4795
|
+
ixfx-titlebar {
|
|
4796
|
+
flex: none;
|
|
4797
|
+
--titlebar-background: var(--bottom-drawer-title-background, transparent);
|
|
4798
|
+
border-bottom: 1px solid color-mix(in srgb, var(--surface-2-text) 10%, transparent);
|
|
4799
|
+
}
|
|
4800
|
+
.body {
|
|
4801
|
+
flex: 1;
|
|
4802
|
+
min-height: 0;
|
|
4803
|
+
overflow: auto;
|
|
4804
|
+
overscroll-behavior: contain;
|
|
4805
|
+
}
|
|
4806
|
+
.body ::slotted(*) {
|
|
4807
|
+
box-sizing: border-box;
|
|
4808
|
+
}
|
|
4809
|
+
@media (prefers-reduced-motion: reduce) {
|
|
4810
|
+
.drawer,
|
|
4811
|
+
ixfx-titlebar,
|
|
4812
|
+
.body {
|
|
4813
|
+
transition-duration: 0s;
|
|
4814
|
+
}
|
|
4815
|
+
}
|
|
4816
|
+
`
|
|
4817
|
+
];
|
|
4818
|
+
}
|
|
4819
|
+
#dragStartY;
|
|
4820
|
+
#dragStartHeight;
|
|
4821
|
+
#collapsedDragging;
|
|
4822
|
+
#ownedRegistry;
|
|
4823
|
+
#commandTarget;
|
|
4824
|
+
#commandName;
|
|
4825
|
+
#commandIds;
|
|
4826
|
+
connectedCallback() {
|
|
4827
|
+
super.connectedCallback();
|
|
4828
|
+
this.#syncCommands();
|
|
4829
|
+
}
|
|
4830
|
+
disconnectedCallback() {
|
|
4831
|
+
super.disconnectedCallback();
|
|
4832
|
+
this.#teardownCommands();
|
|
4833
|
+
if (this.#ownedRegistry !== void 0) {
|
|
4834
|
+
if (this.registry === this.#ownedRegistry) this.registry = void 0;
|
|
4835
|
+
this.#ownedRegistry = void 0;
|
|
4836
|
+
}
|
|
4837
|
+
}
|
|
4838
|
+
updated(changed) {
|
|
4839
|
+
super.updated(changed);
|
|
4840
|
+
if (changed.has(`name`) || changed.has(`registry`)) this.#syncCommands();
|
|
4841
|
+
}
|
|
4842
|
+
show() {
|
|
4843
|
+
this.open = true;
|
|
4844
|
+
}
|
|
4845
|
+
close() {
|
|
4846
|
+
if (!this.open) return;
|
|
4847
|
+
this.open = false;
|
|
4848
|
+
this.dispatchEvent(new CustomEvent(`drawer-close`, {
|
|
4849
|
+
bubbles: true,
|
|
4850
|
+
composed: true
|
|
4851
|
+
}));
|
|
4852
|
+
}
|
|
4853
|
+
toggle() {
|
|
4854
|
+
if (this.open) this.close();
|
|
4855
|
+
else this.show();
|
|
4856
|
+
}
|
|
4857
|
+
#syncCommands() {
|
|
4858
|
+
const name = this.name.trim();
|
|
4859
|
+
const target = this.registry ?? this.#ownedRegistry;
|
|
4860
|
+
if (name !== `` && this.isConnected && target !== void 0 && this.#commandTarget === target && this.#commandName === name) return;
|
|
4861
|
+
this.#teardownCommands();
|
|
4862
|
+
if (name === `` || !this.isConnected) return;
|
|
4863
|
+
const resolved = this.registry ?? (this.#ownedRegistry ??= createCommandRegistry());
|
|
4864
|
+
if (this.#ownedRegistry !== void 0 && resolved !== this.#ownedRegistry) this.#ownedRegistry = void 0;
|
|
4865
|
+
if (this.registry === void 0) this.registry = resolved;
|
|
4866
|
+
const registered = [];
|
|
4867
|
+
const commands = [
|
|
4868
|
+
{
|
|
4869
|
+
command: `expand`,
|
|
4870
|
+
label: `Expand ${this.label}`,
|
|
4871
|
+
description: `Open the ${this.label} drawer`,
|
|
4872
|
+
execute: () => this.show()
|
|
4873
|
+
},
|
|
4874
|
+
{
|
|
4875
|
+
command: `collapse`,
|
|
4876
|
+
label: `Collapse ${this.label}`,
|
|
4877
|
+
description: `Close the ${this.label} drawer`,
|
|
4878
|
+
execute: () => this.close()
|
|
4879
|
+
},
|
|
4880
|
+
{
|
|
4881
|
+
command: `toggle`,
|
|
4882
|
+
label: `Toggle ${this.label}`,
|
|
4883
|
+
description: `Open the ${this.label} drawer if closed, close it if open`,
|
|
4884
|
+
execute: () => this.toggle()
|
|
4885
|
+
}
|
|
4886
|
+
];
|
|
4887
|
+
for (const { command, label, description, execute } of commands) {
|
|
4888
|
+
const id = bottomDrawerCommandId(name, command);
|
|
4889
|
+
if (resolved.has(id)) continue;
|
|
4890
|
+
resolved.register({
|
|
4891
|
+
id,
|
|
4892
|
+
label,
|
|
4893
|
+
description,
|
|
4894
|
+
execute
|
|
4895
|
+
});
|
|
4896
|
+
registered.push(id);
|
|
4897
|
+
}
|
|
4898
|
+
this.#commandTarget = resolved;
|
|
4899
|
+
this.#commandName = name;
|
|
4900
|
+
this.#commandIds = registered;
|
|
4901
|
+
}
|
|
4902
|
+
#teardownCommands() {
|
|
4903
|
+
if (this.#commandTarget !== void 0) {
|
|
4904
|
+
for (const id of this.#commandIds) this.#commandTarget.unregister(id);
|
|
4905
|
+
this.#commandTarget = void 0;
|
|
4906
|
+
this.#commandName = ``;
|
|
4907
|
+
this.#commandIds = [];
|
|
4908
|
+
}
|
|
4909
|
+
}
|
|
4910
|
+
_onTitlebarToggle(event) {
|
|
4911
|
+
event.stopPropagation();
|
|
4912
|
+
if (event.detail.collapsed) this.close();
|
|
4913
|
+
else this.open = true;
|
|
4914
|
+
}
|
|
4915
|
+
_onTitlebarClose(event) {
|
|
4916
|
+
event.stopPropagation();
|
|
4917
|
+
this.close();
|
|
4918
|
+
}
|
|
4919
|
+
render() {
|
|
4920
|
+
const raw = this.#displayHeight();
|
|
4921
|
+
const max = this.#maxHeight();
|
|
4922
|
+
const morph = this.#morphProgress(raw);
|
|
4923
|
+
const height = this.open ? raw * (1 - morph) + 20 * morph : 20;
|
|
4924
|
+
const opacity = this.maintainHandle && this.open ? 1 : this.#dragOpacity(raw);
|
|
4925
|
+
return b`
|
|
4926
|
+
<div class="content"><slot></slot></div>
|
|
4927
|
+
<section
|
|
4928
|
+
class="drawer"
|
|
4929
|
+
style=${`--bottom-drawer-height: ${height}px; --bottom-drawer-opacity: ${opacity}; --m: ${morph}`}
|
|
4930
|
+
role="region"
|
|
4931
|
+
aria-label=${this.label}
|
|
4932
|
+
@keydown=${this.#onDrawerKeyDown}
|
|
4933
|
+
>
|
|
4934
|
+
<div
|
|
4935
|
+
class="resize-edge"
|
|
4936
|
+
role="separator"
|
|
4937
|
+
tabindex="0"
|
|
4938
|
+
aria-label=${`${this.open ? `Resize` : `Expand`} ${this.label}`}
|
|
4939
|
+
aria-orientation="horizontal"
|
|
4940
|
+
aria-valuemin=${this.minHeight}
|
|
4941
|
+
aria-valuemax=${max}
|
|
4942
|
+
aria-valuenow=${Math.round(raw)}
|
|
4943
|
+
@pointerdown=${this.#onResizeStart}
|
|
4944
|
+
@keydown=${this.#onResizeKeyDown}
|
|
4945
|
+
><span class="ixfx-handle" data-handle="dimpled" data-shape="horizontal" part="handle"></span></div>
|
|
4946
|
+
<ixfx-titlebar
|
|
4947
|
+
.title=${this.label}
|
|
4948
|
+
.iconName=${this.iconName}
|
|
4949
|
+
.closable=${this.closable}
|
|
4950
|
+
.collapsible=${this.collapsible}
|
|
4951
|
+
.collapsed=${!this.open}
|
|
4952
|
+
?inert=${!this.open}
|
|
4953
|
+
@toggle=${this._onTitlebarToggle}
|
|
4954
|
+
@close=${this._onTitlebarClose}
|
|
4955
|
+
>
|
|
4956
|
+
<slot name="toolbar" slot="toolbar"></slot>
|
|
4957
|
+
</ixfx-titlebar>
|
|
4958
|
+
<div class="body" ?inert=${!this.open}><slot name="drawer"></slot></div>
|
|
4959
|
+
</section>
|
|
4960
|
+
`;
|
|
4961
|
+
}
|
|
4962
|
+
#maxHeight() {
|
|
4963
|
+
const availableHeight = this.clientHeight || this.height;
|
|
4964
|
+
return Math.max(this.minHeight, availableHeight * clampRange(this.maxHeightRatio, 0, 1));
|
|
4965
|
+
}
|
|
4966
|
+
#displayHeight() {
|
|
4967
|
+
return clampRange(this._dragHeight ?? this.height, 0, this.#maxHeight());
|
|
4968
|
+
}
|
|
4969
|
+
#dragOpacity(height) {
|
|
4970
|
+
if (this._dragHeight === void 0 || height >= this.minHeight) return 1;
|
|
4971
|
+
const fadeRange = this.minHeight - this.dismissThreshold;
|
|
4972
|
+
if (fadeRange <= 0) return height >= this.dismissThreshold ? 1 : 0;
|
|
4973
|
+
return clampRange((height - this.dismissThreshold) / fadeRange, 0, 1);
|
|
4974
|
+
}
|
|
4975
|
+
#morphProgress(raw) {
|
|
4976
|
+
if (!this.open) return this.maintainHandle ? 1 : 0;
|
|
4977
|
+
if (this._dragHeight === void 0 || !this.maintainHandle) return 0;
|
|
4978
|
+
const range = this.minHeight - this.dismissThreshold;
|
|
4979
|
+
if (range <= 0) return raw < this.dismissThreshold ? 1 : 0;
|
|
4980
|
+
return clampRange((this.minHeight - raw) / range, 0, 1);
|
|
4981
|
+
}
|
|
4982
|
+
#setHeight(height) {
|
|
4983
|
+
this.height = clampRange(height, this.minHeight, this.#maxHeight());
|
|
4984
|
+
this.dispatchEvent(new CustomEvent(`drawer-resize`, {
|
|
4985
|
+
detail: { height: this.height },
|
|
4986
|
+
bubbles: true,
|
|
4987
|
+
composed: true
|
|
4988
|
+
}));
|
|
4989
|
+
}
|
|
4990
|
+
#onResizeStart;
|
|
4991
|
+
#onResizeMove;
|
|
4992
|
+
#onResizeEnd;
|
|
4993
|
+
#onResizeKeyDown;
|
|
4994
|
+
#onTabPointerMove;
|
|
4995
|
+
#onTabPointerUp;
|
|
4996
|
+
#onDrawerKeyDown;
|
|
4997
|
+
};
|
|
4998
|
+
__decorate([property({
|
|
4999
|
+
type: Boolean,
|
|
5000
|
+
reflect: true
|
|
5001
|
+
})], BottomDrawerElement.prototype, "open", void 0);
|
|
5002
|
+
__decorate([property({ type: Number })], BottomDrawerElement.prototype, "height", void 0);
|
|
5003
|
+
__decorate([property({
|
|
5004
|
+
type: Number,
|
|
5005
|
+
attribute: `min-height`
|
|
5006
|
+
})], BottomDrawerElement.prototype, "minHeight", void 0);
|
|
5007
|
+
__decorate([property({
|
|
5008
|
+
type: Number,
|
|
5009
|
+
attribute: `dismiss-threshold`
|
|
5010
|
+
})], BottomDrawerElement.prototype, "dismissThreshold", void 0);
|
|
5011
|
+
__decorate([property({
|
|
5012
|
+
type: Number,
|
|
5013
|
+
attribute: `max-height-ratio`
|
|
5014
|
+
})], BottomDrawerElement.prototype, "maxHeightRatio", void 0);
|
|
5015
|
+
__decorate([property({ type: String })], BottomDrawerElement.prototype, "label", void 0);
|
|
5016
|
+
__decorate([property({
|
|
5017
|
+
type: String,
|
|
5018
|
+
attribute: `icon-name`
|
|
5019
|
+
})], BottomDrawerElement.prototype, "iconName", void 0);
|
|
5020
|
+
__decorate([property({ type: Boolean })], BottomDrawerElement.prototype, "closable", void 0);
|
|
5021
|
+
__decorate([property({ type: Boolean })], BottomDrawerElement.prototype, "collapsible", void 0);
|
|
5022
|
+
__decorate([property({
|
|
5023
|
+
type: Boolean,
|
|
5024
|
+
attribute: `maintain-handle`,
|
|
5025
|
+
reflect: true
|
|
5026
|
+
})], BottomDrawerElement.prototype, "maintainHandle", void 0);
|
|
5027
|
+
__decorate([property({ type: String })], BottomDrawerElement.prototype, "name", void 0);
|
|
5028
|
+
__decorate([property({ attribute: false })], BottomDrawerElement.prototype, "registry", void 0);
|
|
5029
|
+
__decorate([state()], BottomDrawerElement.prototype, "_dragHeight", void 0);
|
|
5030
|
+
BottomDrawerElement = __decorate([safeCustomElement(`ixfx-bottom-drawer`)], BottomDrawerElement);
|
|
5031
|
+
//#endregion
|
|
5032
|
+
//#region src/icons/defaults.ts
|
|
5033
|
+
/**
|
|
5034
|
+
* Chevron pointing down. Used for split-button dropdown toggle.
|
|
5035
|
+
* fill="currentColor" so it inherits CSS color.
|
|
5036
|
+
*/
|
|
5037
|
+
const ICON_CHEVRON_DOWN = `<svg viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"><path d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"/></svg>`;
|
|
5038
|
+
/**
|
|
5039
|
+
* Caret pointing right. Used for tree-basic expand indicator as a CSS mask.
|
|
5040
|
+
* fill="black" is correct for CSS mask-image use (shape only, color comes from background-color).
|
|
5041
|
+
*/
|
|
5042
|
+
const ICON_CARET_RIGHT = `<svg viewBox="0 0 24 24" fill="black" xmlns="http://www.w3.org/2000/svg"><path d="M10 7l6 5-6 5V7z"/></svg>`;
|
|
5043
|
+
/**
|
|
5044
|
+
* Checkmark. Useful for menu-check-item or confirmation states.
|
|
5045
|
+
* fill="currentColor" so it inherits CSS color.
|
|
5046
|
+
*/
|
|
5047
|
+
const ICON_CHECK = `<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z"/></svg>`;
|
|
5048
|
+
/**
|
|
5049
|
+
* Close / X icon. Useful for dialogs, notifications, dismissible elements.
|
|
5050
|
+
* fill="currentColor" so it inherits CSS color.
|
|
5051
|
+
*/
|
|
5052
|
+
const ICON_CLOSE = `<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41z"/></svg>`;
|
|
5053
|
+
/**
|
|
5054
|
+
* Plus / add icon. Pairs with `close` for add/remove actions.
|
|
5055
|
+
* fill="currentColor" so it inherits CSS color.
|
|
5056
|
+
*/
|
|
5057
|
+
const ICON_ADD = `<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg>`;
|
|
5058
|
+
/**
|
|
5059
|
+
* Error / warning icon. Useful for error notifications.
|
|
5060
|
+
* fill="currentColor" so it inherits CSS color.
|
|
5061
|
+
*/
|
|
5062
|
+
const ICON_ERROR = `<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z"/></svg>`;
|
|
5063
|
+
/**
|
|
5064
|
+
* Info icon. Useful for info notifications.
|
|
5065
|
+
* fill="currentColor" so it inherits CSS color.
|
|
5066
|
+
*/
|
|
5067
|
+
const ICON_INFO = `<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"/></svg>`;
|
|
5068
|
+
/**
|
|
5069
|
+
* Warning icon. Useful for warning notifications.
|
|
5070
|
+
* fill="currentColor" so it inherits CSS color.
|
|
5071
|
+
*/
|
|
5072
|
+
const ICON_WARNING = `<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z"/></svg>`;
|
|
5073
|
+
/**
|
|
5074
|
+
* Chevron pointing right. Used for split-button switcher toggle.
|
|
5075
|
+
* fill="currentColor" so it inherits CSS color.
|
|
5076
|
+
*/
|
|
5077
|
+
const ICON_CHEVRON_RIGHT = `<svg viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"><path d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z"/></svg>`;
|
|
5078
|
+
/**
|
|
5079
|
+
* Folder with up arrow. Angled line style for navigating up one level.
|
|
5080
|
+
* fill="currentColor" so it inherits CSS color.
|
|
5081
|
+
*/
|
|
5082
|
+
const ICON_FOLDER_UP = `<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M12 4L4 12h5v8h6v-8h5L12 4z"/></svg>`;
|
|
5083
|
+
/**
|
|
5084
|
+
* Folder. Useful for file explorers and sidebars.
|
|
5085
|
+
* fill="currentColor" so it inherits CSS color.
|
|
5086
|
+
*/
|
|
5087
|
+
const ICON_FOLDER = `<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 1.99-.9 1.99-2V8c0-1.1-.9-2-2-2h-8l-2-2z"/></svg>`;
|
|
5088
|
+
/**
|
|
5089
|
+
* Document / file page. Useful for file lists and document tabs.
|
|
5090
|
+
* fill="currentColor" so it inherits CSS color.
|
|
5091
|
+
*/
|
|
5092
|
+
const ICON_FILE = `<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M14 2H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8l-6-6zm2 16H8v-2h8v2zm0-4H8v-2h8v2zm-3-5V3.5L18.5 9H13z"/></svg>`;
|
|
5093
|
+
/**
|
|
5094
|
+
* Magnifying glass. Useful for search panels and inputs.
|
|
5095
|
+
* fill="currentColor" so it inherits CSS color.
|
|
5096
|
+
*/
|
|
5097
|
+
const ICON_SEARCH = `<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/></svg>`;
|
|
5098
|
+
function registerDefaults() {
|
|
5099
|
+
registerIcon(`chevron-down`, ICON_CHEVRON_DOWN);
|
|
5100
|
+
registerIcon(`chevron-right`, ICON_CHEVRON_RIGHT);
|
|
5101
|
+
registerIcon(`caret-right`, ICON_CARET_RIGHT);
|
|
5102
|
+
registerIcon(`check`, ICON_CHECK);
|
|
5103
|
+
registerIcon(`close`, ICON_CLOSE);
|
|
5104
|
+
registerIcon(`file`, ICON_FILE);
|
|
5105
|
+
registerIcon(`folder`, ICON_FOLDER);
|
|
5106
|
+
registerIcon(`search`, ICON_SEARCH);
|
|
5107
|
+
registerIcon(`add`, ICON_ADD);
|
|
5108
|
+
registerIcon(`error`, ICON_ERROR);
|
|
5109
|
+
registerIcon(`folder-up`, ICON_FOLDER_UP);
|
|
5110
|
+
registerIcon(`info`, ICON_INFO);
|
|
5111
|
+
registerIcon(`warning`, ICON_WARNING);
|
|
5112
|
+
}
|
|
5113
|
+
//#endregion
|
|
5114
|
+
//#region src/icons/index.ts
|
|
5115
|
+
registerDefaults();
|
|
5116
|
+
//#endregion
|
|
5117
|
+
//#region src/styles/prominence.ts
|
|
5118
|
+
/**
|
|
5119
|
+
* Shared CSS variable defaults for prominence-based interaction feedback.
|
|
5120
|
+
*
|
|
5121
|
+
* Defines the `--prominence-*` variables on `:host`. Include this if you
|
|
5122
|
+
* are building custom prominence selectors; otherwise use `prominenceStyles`
|
|
5123
|
+
* or `prominenceSubStyles` which include these variables automatically.
|
|
5124
|
+
*/
|
|
5125
|
+
const prominenceVars = i$3`
|
|
5126
|
+
:host {
|
|
5127
|
+
--prominence-idle-opacity: 0.6;
|
|
5128
|
+
--prominence-idle-saturate: 0.4;
|
|
5129
|
+
--prominence-tickled-opacity: 0.85;
|
|
5130
|
+
--prominence-tickled-saturate: 0.8;
|
|
5131
|
+
--prominence-disabled-opacity: 0.3;
|
|
5132
|
+
--prominence-disabled-saturate: 0.1;
|
|
5133
|
+
}
|
|
5134
|
+
`;
|
|
5135
|
+
/**
|
|
5136
|
+
* Host-based prominence interaction feedback.
|
|
5137
|
+
*
|
|
5138
|
+
* Applies CSS `filter` to **the whole component host** to convey state:
|
|
5139
|
+
* - **Disabled** (`[disabled]` / `:disabled`): heavily muted
|
|
5140
|
+
* - **Idle** (default): reduced opacity + desaturated
|
|
5141
|
+
* - **Tickled** (`:hover` / `:focus-within`): elevated opacity + saturation
|
|
5142
|
+
* - **Active** (`:active` / `[dragging]`): full vibrancy (filter removed)
|
|
5143
|
+
*
|
|
5144
|
+
* Defaults are defined on `:host` and can be overridden per-instance.
|
|
5145
|
+
*
|
|
5146
|
+
* Usage:
|
|
5147
|
+
* ```ts
|
|
5148
|
+
* import { prominenceStyles } from '../styles/prominence.js';
|
|
5149
|
+
*
|
|
5150
|
+
* class MyComponent extends LitElement {
|
|
5151
|
+
* static styles = [prominenceStyles, css`...`];
|
|
5152
|
+
* }
|
|
5153
|
+
* ```
|
|
5154
|
+
*/
|
|
5155
|
+
const prominenceStyles = i$3`
|
|
5156
|
+
${prominenceVars}
|
|
5157
|
+
|
|
5158
|
+
:host {
|
|
5159
|
+
filter:
|
|
5160
|
+
opacity(var(--prominence-idle-opacity))
|
|
5161
|
+
saturate(var(--prominence-idle-saturate));
|
|
5162
|
+
transition: filter var(--transition, 0.15s ease-out);
|
|
5163
|
+
}
|
|
5164
|
+
|
|
5165
|
+
:host(:hover),
|
|
5166
|
+
:host(:focus-within) {
|
|
5167
|
+
filter:
|
|
5168
|
+
opacity(var(--prominence-tickled-opacity))
|
|
5169
|
+
saturate(var(--prominence-tickled-saturate));
|
|
5170
|
+
}
|
|
5171
|
+
|
|
5172
|
+
:host(:active),
|
|
5173
|
+
:host([dragging]) {
|
|
5174
|
+
filter: none;
|
|
5175
|
+
}
|
|
5176
|
+
|
|
5177
|
+
/* Disabled comes last to override tickled/active selectors of equal specificity */
|
|
5178
|
+
:host([disabled]),
|
|
5179
|
+
:host(:disabled) {
|
|
5180
|
+
filter:
|
|
5181
|
+
opacity(var(--prominence-disabled-opacity))
|
|
5182
|
+
saturate(var(--prominence-disabled-saturate));
|
|
5183
|
+
pointer-events: none;
|
|
5184
|
+
}
|
|
5185
|
+
`;
|
|
5186
|
+
i$3`
|
|
5187
|
+
${prominenceVars}
|
|
5188
|
+
|
|
5189
|
+
.prominence {
|
|
5190
|
+
filter:
|
|
5191
|
+
opacity(var(--prominence-idle-opacity))
|
|
5192
|
+
saturate(var(--prominence-idle-saturate));
|
|
5193
|
+
transition: filter var(--transition, 0.15s ease-out);
|
|
5194
|
+
}
|
|
5195
|
+
|
|
5196
|
+
.prominence:hover,
|
|
5197
|
+
.prominence:focus-within {
|
|
5198
|
+
filter:
|
|
5199
|
+
opacity(var(--prominence-tickled-opacity))
|
|
5200
|
+
saturate(var(--prominence-tickled-saturate));
|
|
5201
|
+
}
|
|
5202
|
+
|
|
5203
|
+
.prominence:active,
|
|
5204
|
+
.prominence.dragging {
|
|
5205
|
+
filter: none;
|
|
5206
|
+
}
|
|
5207
|
+
|
|
5208
|
+
.prominence[disabled],
|
|
5209
|
+
.prominence:disabled {
|
|
5210
|
+
filter:
|
|
5211
|
+
opacity(var(--prominence-disabled-opacity))
|
|
5212
|
+
saturate(var(--prominence-disabled-saturate));
|
|
5213
|
+
pointer-events: none;
|
|
5214
|
+
}
|
|
5215
|
+
`;
|
|
5216
|
+
//#endregion
|
|
5217
|
+
//#region src/button/button-styles.ts
|
|
5218
|
+
const buttonStyles = i$3`
|
|
5219
|
+
:host {
|
|
5220
|
+
display: inline-flex;
|
|
5221
|
+
max-width: 100%;
|
|
5222
|
+
vertical-align: middle;
|
|
5223
|
+
user-select: none;
|
|
5224
|
+
-webkit-user-select: none;
|
|
5225
|
+
}
|
|
5226
|
+
|
|
5227
|
+
:host([hidden]) {
|
|
5228
|
+
display: none;
|
|
5229
|
+
}
|
|
5230
|
+
|
|
5231
|
+
button {
|
|
5232
|
+
cursor: pointer;
|
|
5233
|
+
appearance: none;
|
|
5234
|
+
background: var(--surface-4, #ccc);
|
|
5235
|
+
color: var(--surface-3-text, #000);
|
|
5236
|
+
border: var(--border, 1px solid #999);
|
|
5237
|
+
outline: var(--ixfx-button-outline, none);
|
|
5238
|
+
border-radius: var(--radius-xl, 8px);
|
|
5239
|
+
corner-shape: superellipse(1);
|
|
5240
|
+
padding: var(--ixfx-button-padding-block, var(--space-m, 8px)) var(--ixfx-button-padding-inline, var(--space-l, 12px));
|
|
5241
|
+
font-family: var(--font-family, inherit);
|
|
5242
|
+
font-size: var(--text-m, 14px);
|
|
5243
|
+
margin: 0;
|
|
5244
|
+
display: inline-flex;
|
|
5245
|
+
align-items: center;
|
|
5246
|
+
justify-content: center;
|
|
5247
|
+
gap: 0.5em;
|
|
5248
|
+
width: 100%;
|
|
5249
|
+
overflow: hidden;
|
|
5250
|
+
white-space: nowrap;
|
|
5251
|
+
box-shadow:
|
|
5252
|
+
var(--ixfx-button-shade, none),
|
|
5253
|
+
inset 1px 1px 1px 1px color-mix(in oklch, var(--surface-4) 30%, transparent), inset -1px -1px 1px 1px color-mix(in oklch, var(--surface-2) 20%, transparent),
|
|
5254
|
+
2px 2px 1px 0px color-mix(in oklch, var(--surface-2) 30%, transparent);
|
|
5255
|
+
transition: background var(--transition, 0.2s), border-color var(--transition, 0.2s);
|
|
5256
|
+
}
|
|
5257
|
+
|
|
5258
|
+
button:disabled {
|
|
5259
|
+
opacity: 0.5;
|
|
5260
|
+
cursor: not-allowed;
|
|
5261
|
+
}
|
|
5262
|
+
|
|
5263
|
+
button:hover:not(:disabled) {
|
|
5264
|
+
background: color-mix(in oklch, var(--surface-4) 80%, transparent);
|
|
5265
|
+
border-color: var(--accent, #666);
|
|
5266
|
+
box-shadow:
|
|
5267
|
+
inset 1px 1px 1px 1px color-mix(in oklch, var(--surface-5) 70%, transparent),
|
|
5268
|
+
inset -1px -1px 1px 1px color-mix(in oklch, var(--surface-2) 60%, transparent),
|
|
5269
|
+
2px 2px 1px 0px color-mix(in oklch, var(--surface-2) 90%, transparent);
|
|
5270
|
+
}
|
|
5271
|
+
|
|
5272
|
+
button:active:not(:disabled) {
|
|
5273
|
+
background: var(--surface-2, #aaa);
|
|
5274
|
+
transform: translateY(1px);
|
|
5275
|
+
box-shadow: inset 1px 1px 0px 0.5px color-mix(in oklch,var(--surface-1),transparent);
|
|
5276
|
+
}
|
|
5277
|
+
|
|
5278
|
+
.button-icon {
|
|
5279
|
+
display: var(--ixfx-button-hide-icon, inline-flex);
|
|
5280
|
+
align-items: center;
|
|
5281
|
+
flex-shrink: 0;
|
|
5282
|
+
}
|
|
5283
|
+
|
|
5284
|
+
.button-label {
|
|
5285
|
+
white-space: nowrap;
|
|
5286
|
+
}
|
|
5287
|
+
|
|
5288
|
+
:host([has-icon]) .button-label {
|
|
5289
|
+
display: var(--ixfx-button-hide-label, inline);
|
|
5290
|
+
}
|
|
5291
|
+
|
|
5292
|
+
:host([hide-label]) .button-label {
|
|
5293
|
+
display: none;
|
|
5294
|
+
}
|
|
5295
|
+
|
|
5296
|
+
:host([hide-icon]) .button-icon {
|
|
5297
|
+
display: none;
|
|
5298
|
+
}
|
|
5299
|
+
|
|
5300
|
+
:host([subtle]) button {
|
|
5301
|
+
background: color-mix(in oklch, var(--surface-4, #ccc) 40%, transparent);
|
|
5302
|
+
}
|
|
5303
|
+
|
|
5304
|
+
:host([subtle]) button:hover:not(:disabled),
|
|
5305
|
+
:host([subtle]) button:focus-visible:not(:disabled) {
|
|
5306
|
+
background: color-mix(in oklch, var(--surface-4, #ccc) 70%, transparent);
|
|
5307
|
+
}
|
|
5308
|
+
`;
|
|
5309
|
+
//#endregion
|
|
5310
|
+
//#region src/button/button.ts
|
|
5311
|
+
let ButtonElement = class ButtonElement extends i {
|
|
5312
|
+
constructor(..._args) {
|
|
5313
|
+
super(..._args);
|
|
5314
|
+
this.disabled = false;
|
|
5315
|
+
this.hideIcon = false;
|
|
5316
|
+
this.hideLabel = false;
|
|
5317
|
+
this.hasIcon = false;
|
|
5318
|
+
this.subtle = false;
|
|
5319
|
+
}
|
|
5320
|
+
_renderIcon() {
|
|
5321
|
+
if (this.hideIcon || !this.icon) return A;
|
|
5322
|
+
if (this.icon.startsWith(`<svg`)) return b`<span class="button-icon">${unsafeHTML(this.icon)}</span>`;
|
|
5323
|
+
if (!hasIcon(this.icon)) return A;
|
|
5324
|
+
return b`<ixfx-icon class="button-icon" name="${this.icon}"></ixfx-icon>`;
|
|
5325
|
+
}
|
|
5326
|
+
render() {
|
|
5327
|
+
this.hasIcon = !this.hideIcon && !!this.icon;
|
|
5328
|
+
const label = this.hideLabel ? A : b`<span class="button-label"><slot></slot></span>`;
|
|
5329
|
+
return b`<button ?disabled=${this.disabled}>${this._renderIcon()}${label}</button>`;
|
|
5330
|
+
}
|
|
5331
|
+
static {
|
|
5332
|
+
this.styles = [prominenceStyles, buttonStyles];
|
|
5333
|
+
}
|
|
5334
|
+
};
|
|
5335
|
+
__decorate([property({ type: Boolean })], ButtonElement.prototype, "disabled", void 0);
|
|
5336
|
+
__decorate([property({ type: String })], ButtonElement.prototype, "icon", void 0);
|
|
5337
|
+
__decorate([property({
|
|
5338
|
+
type: Boolean,
|
|
5339
|
+
attribute: `hide-icon`,
|
|
5340
|
+
reflect: true
|
|
5341
|
+
})], ButtonElement.prototype, "hideIcon", void 0);
|
|
5342
|
+
__decorate([property({
|
|
5343
|
+
type: Boolean,
|
|
5344
|
+
attribute: `hide-label`,
|
|
5345
|
+
reflect: true
|
|
5346
|
+
})], ButtonElement.prototype, "hideLabel", void 0);
|
|
5347
|
+
__decorate([property({
|
|
5348
|
+
type: Boolean,
|
|
5349
|
+
attribute: `has-icon`,
|
|
5350
|
+
reflect: true
|
|
5351
|
+
})], ButtonElement.prototype, "hasIcon", void 0);
|
|
5352
|
+
__decorate([property({
|
|
5353
|
+
type: Boolean,
|
|
5354
|
+
reflect: true
|
|
5355
|
+
})], ButtonElement.prototype, "subtle", void 0);
|
|
5356
|
+
ButtonElement = __decorate([safeCustomElement(`ixfx-button`)], ButtonElement);
|
|
5357
|
+
//#endregion
|
|
5358
|
+
//#region src/button/radio-group.ts
|
|
5359
|
+
let RadioGroup = class RadioGroup extends i {
|
|
5360
|
+
constructor(..._args) {
|
|
5361
|
+
super(..._args);
|
|
5362
|
+
this.value = ``;
|
|
5363
|
+
this.orientation = `horizontal`;
|
|
5364
|
+
this.items = [];
|
|
5365
|
+
this.name = ``;
|
|
5366
|
+
this.mode = `compact`;
|
|
5367
|
+
this.checked = false;
|
|
5368
|
+
this.valueOff = ``;
|
|
5369
|
+
this.iconName = ``;
|
|
5370
|
+
this.iconNameOff = ``;
|
|
5371
|
+
this.hideLabels = false;
|
|
5372
|
+
this._computedItems = [];
|
|
5373
|
+
this._icons = /* @__PURE__ */ new Map();
|
|
5374
|
+
}
|
|
5375
|
+
get _isSingleToggle() {
|
|
5376
|
+
return this._computedItems.length === 0 && Boolean(this.textContent?.trim());
|
|
5377
|
+
}
|
|
5378
|
+
get _singleToggleIconName() {
|
|
5379
|
+
if (!this.iconName && !this.iconNameOff) return null;
|
|
5380
|
+
return this.checked ? this.iconName : this.iconNameOff || this.iconName;
|
|
5381
|
+
}
|
|
5382
|
+
firstUpdated() {
|
|
5383
|
+
this.#updateComputedItems();
|
|
5384
|
+
}
|
|
5385
|
+
updated(changedProperties) {
|
|
5386
|
+
if (changedProperties.has(`checked`)) {
|
|
5387
|
+
const input = this.shadowRoot?.querySelector(`.radio-toggle-input`);
|
|
5388
|
+
if (input && input.checked !== this.checked) {
|
|
5389
|
+
input.checked = this.checked;
|
|
5390
|
+
const newValue = this.checked ? this.value || `on` : this.valueOff || void 0;
|
|
5391
|
+
this.dispatchEvent(new CustomEvent(`change`, {
|
|
5392
|
+
detail: {
|
|
5393
|
+
checked: this.checked,
|
|
5394
|
+
value: newValue
|
|
5395
|
+
},
|
|
5396
|
+
bubbles: true,
|
|
5397
|
+
composed: true
|
|
5398
|
+
}));
|
|
5399
|
+
}
|
|
5400
|
+
}
|
|
5401
|
+
if (changedProperties.has(`value`) && !this._isSingleToggle) {
|
|
5402
|
+
const inputs = this.shadowRoot?.querySelectorAll(`.radio-input`);
|
|
5403
|
+
if (inputs) {
|
|
5404
|
+
for (const input of inputs) if (input.checked !== (input.value === this.value)) input.checked = input.value === this.value;
|
|
5405
|
+
}
|
|
5406
|
+
}
|
|
5407
|
+
}
|
|
5408
|
+
#updateComputedItems() {
|
|
5409
|
+
const options = this.querySelectorAll(`option`);
|
|
5410
|
+
const icons = /* @__PURE__ */ new Map();
|
|
5411
|
+
if (options.length > 0) {
|
|
5412
|
+
this._computedItems = Array.from(options, (el) => {
|
|
5413
|
+
const tempDiv = document.createElement(`div`);
|
|
5414
|
+
tempDiv.innerHTML = el.innerHTML;
|
|
5415
|
+
const iconEl = tempDiv.querySelector(`svg`);
|
|
5416
|
+
if (iconEl) icons.set(el.getAttribute(`value`) || ``, iconEl.outerHTML);
|
|
5417
|
+
return {
|
|
5418
|
+
value: el.getAttribute(`value`) || ``,
|
|
5419
|
+
label: el.textContent?.trim() || ``,
|
|
5420
|
+
disabled: el.hasAttribute(`disabled`),
|
|
5421
|
+
iconName: el.getAttribute(`icon-name`) || void 0,
|
|
5422
|
+
iconNameOff: el.getAttribute(`icon-name-off`) || void 0
|
|
5423
|
+
};
|
|
5424
|
+
});
|
|
5425
|
+
this._icons = icons;
|
|
5426
|
+
} else this._computedItems = [...this.items];
|
|
5427
|
+
}
|
|
5428
|
+
#handleRadioChange(e) {
|
|
5429
|
+
e.stopImmediatePropagation();
|
|
5430
|
+
const input = e.target;
|
|
5431
|
+
this.value = input.value;
|
|
5432
|
+
this.dispatchEvent(new CustomEvent(`change`, {
|
|
5433
|
+
detail: {
|
|
5434
|
+
checked: true,
|
|
5435
|
+
value: input.value
|
|
5436
|
+
},
|
|
5437
|
+
bubbles: true,
|
|
5438
|
+
composed: true
|
|
5439
|
+
}));
|
|
5440
|
+
}
|
|
5441
|
+
#handleToggleChange(e) {
|
|
5442
|
+
e.stopImmediatePropagation();
|
|
5443
|
+
const input = e.target;
|
|
5444
|
+
this.checked = input.checked;
|
|
5445
|
+
const newValue = this.checked ? this.value || `on` : this.valueOff || void 0;
|
|
5446
|
+
this.dispatchEvent(new CustomEvent(`change`, {
|
|
5447
|
+
detail: {
|
|
5448
|
+
checked: this.checked,
|
|
5449
|
+
value: newValue
|
|
5450
|
+
},
|
|
5451
|
+
bubbles: true,
|
|
5452
|
+
composed: true
|
|
5453
|
+
}));
|
|
5454
|
+
}
|
|
5455
|
+
#renderIcon(item) {
|
|
5456
|
+
const iconName = item.value === this.value ? item.iconName || null : item.iconNameOff || item.iconName || null;
|
|
5457
|
+
if (iconName) return b`<ixfx-icon class="radio-icon" name="${iconName}"></ixfx-icon>`;
|
|
5458
|
+
const iconHtml = this._icons.get(item.value);
|
|
5459
|
+
if (!iconHtml) return null;
|
|
5460
|
+
return b`<span class="radio-icon">${unsafeHTML(iconHtml)}</span>`;
|
|
5461
|
+
}
|
|
5462
|
+
render() {
|
|
5463
|
+
if (this._isSingleToggle) {
|
|
5464
|
+
const iconName = this._singleToggleIconName;
|
|
5465
|
+
const iconPart = iconName || this.hideLabels ? b`<ixfx-icon class="radio-icon" name="${iconName || `check`}"></ixfx-icon>` : null;
|
|
5466
|
+
const labelPart = !this.hideLabels ? b`<span class="radio-label" data-text="${this.textContent?.trim()}">${this.textContent?.trim()}</span>` : null;
|
|
5467
|
+
return b`
|
|
5468
|
+
<label class="radio-item ${this.checked ? `selected` : ``}">
|
|
5469
|
+
<input
|
|
5470
|
+
type="checkbox"
|
|
5471
|
+
class="radio-toggle-input"
|
|
5472
|
+
?checked=${this.checked}
|
|
5473
|
+
@change=${this.#handleToggleChange}
|
|
5474
|
+
/>
|
|
5475
|
+
${iconPart}
|
|
5476
|
+
${labelPart}
|
|
5477
|
+
</label>
|
|
5478
|
+
`;
|
|
5479
|
+
}
|
|
5480
|
+
return b`
|
|
5481
|
+
<slot @slotchange=${this.#updateComputedItems} style="display: none;"></slot>
|
|
5482
|
+
<div class="radio-group ${this.orientation} ${this.mode}" role="radiogroup" aria-label=${this.name}>
|
|
5483
|
+
${this._computedItems.map((item) => {
|
|
5484
|
+
const iconName = item.value === this.value ? item.iconName || null : item.iconNameOff || item.iconName || null;
|
|
5485
|
+
const iconPart = iconName || this.hideLabels ? b`<ixfx-icon class="radio-icon" name="${iconName || `check`}"></ixfx-icon>` : null;
|
|
5486
|
+
const labelPart = !this.hideLabels ? b`<span class="radio-label" data-text="${item.label}">${item.label}</span>` : null;
|
|
5487
|
+
return b`
|
|
5488
|
+
<label class="radio-item ${item.value === this.value ? `selected` : ``}" ?disabled=${item.disabled}>
|
|
5489
|
+
<input
|
|
5490
|
+
type="radio"
|
|
5491
|
+
class="radio-input"
|
|
5492
|
+
name=${this.name}
|
|
5493
|
+
value=${item.value}
|
|
5494
|
+
?disabled=${item.disabled}
|
|
5495
|
+
?checked=${item.value === this.value}
|
|
5496
|
+
@change=${this.#handleRadioChange}
|
|
5497
|
+
/>
|
|
5498
|
+
${iconPart}
|
|
5499
|
+
${labelPart}
|
|
5500
|
+
</label>
|
|
5501
|
+
`;
|
|
5502
|
+
})}
|
|
5503
|
+
</div>
|
|
5504
|
+
`;
|
|
5505
|
+
}
|
|
5506
|
+
static {
|
|
5507
|
+
this.styles = [
|
|
5508
|
+
themeFallbacks,
|
|
5509
|
+
prominenceStyles,
|
|
5510
|
+
i$3`
|
|
5511
|
+
:host {
|
|
5512
|
+
display: inline-flex;
|
|
5513
|
+
min-width: min-content;
|
|
4378
5514
|
box-sizing: border-box;
|
|
4379
5515
|
/* Default to looking like a cohesive control group */
|
|
4380
5516
|
background: var(--surface-4, transparent);
|
|
@@ -4559,6 +5695,306 @@ __decorate([state()], RadioGroup.prototype, "_icons", void 0);
|
|
|
4559
5695
|
__decorate([query(`slot`)], RadioGroup.prototype, "_slot", void 0);
|
|
4560
5696
|
RadioGroup = __decorate([safeCustomElement(`ixfx-radio-group`)], RadioGroup);
|
|
4561
5697
|
//#endregion
|
|
5698
|
+
//#region src/interaction/list-drag-select-controller.ts
|
|
5699
|
+
const DEFAULT_POINTER_TYPES = [`mouse`, `pen`];
|
|
5700
|
+
const DEFAULT_THRESHOLD = 4;
|
|
5701
|
+
/** Pointer distance (px) from an edge that triggers auto-scroll. */
|
|
5702
|
+
const EDGE_ZONE = 28;
|
|
5703
|
+
/** Max auto-scroll speed in px per frame. */
|
|
5704
|
+
const MAX_SCROLL_SPEED = 16;
|
|
5705
|
+
/**
|
|
5706
|
+
* Shared pointer-drag (marquee / rubber-band) selection for list components.
|
|
5707
|
+
*
|
|
5708
|
+
* Owns all pointer plumbing and rectangle state; knows nothing about DOM
|
|
5709
|
+
* geometry or the selection model — those are host callbacks. Mirrors the
|
|
5710
|
+
* `TickledController` attach pattern (`new ListDragSelectController(this, …)`).
|
|
5711
|
+
*
|
|
5712
|
+
* Behaviour: `pointerdown` on the surface records a start point; once the
|
|
5713
|
+
* pointer moves past `threshold`, the surface captures the pointer and every
|
|
5714
|
+
* move recomputes the rect, hit-tests, and calls `onPreview`. On release the
|
|
5715
|
+
* final set is delivered once via `onCommit`. A press that never crosses the
|
|
5716
|
+
* threshold does nothing (the normal `@click` path runs).
|
|
5717
|
+
*/
|
|
5718
|
+
var ListDragSelectController = class {
|
|
5719
|
+
#host;
|
|
5720
|
+
#config;
|
|
5721
|
+
#boundSurface;
|
|
5722
|
+
#pointerId;
|
|
5723
|
+
#startClientX = 0;
|
|
5724
|
+
#startClientY = 0;
|
|
5725
|
+
#startX = 0;
|
|
5726
|
+
#startY = 0;
|
|
5727
|
+
#currentClientX = 0;
|
|
5728
|
+
#currentClientY = 0;
|
|
5729
|
+
#lastModifiers = {
|
|
5730
|
+
shiftKey: false,
|
|
5731
|
+
ctrlKey: false,
|
|
5732
|
+
metaKey: false
|
|
5733
|
+
};
|
|
5734
|
+
#dragging = false;
|
|
5735
|
+
#suppressClick = false;
|
|
5736
|
+
/** Selection as it was when the drag started — the combine baseline. */
|
|
5737
|
+
#base = /* @__PURE__ */ new Set();
|
|
5738
|
+
/** Combine mode of the most recent preview (drives the commit flag). */
|
|
5739
|
+
#lastMode = `replace`;
|
|
5740
|
+
#preview = /* @__PURE__ */ new Set();
|
|
5741
|
+
#raf = 0;
|
|
5742
|
+
constructor(host, config) {
|
|
5743
|
+
this.#host = host;
|
|
5744
|
+
this.#config = config;
|
|
5745
|
+
host.addController(this);
|
|
5746
|
+
}
|
|
5747
|
+
/** `true` while a drag is in progress or its trailing click is still pending. */
|
|
5748
|
+
get isDragging() {
|
|
5749
|
+
return this.#dragging || this.#suppressClick;
|
|
5750
|
+
}
|
|
5751
|
+
/** `true` once the press has crossed the threshold and a rect is live. */
|
|
5752
|
+
get isActive() {
|
|
5753
|
+
return this.#dragging;
|
|
5754
|
+
}
|
|
5755
|
+
hostConnected() {
|
|
5756
|
+
this.#bindSurface();
|
|
5757
|
+
window.addEventListener(`pointermove`, this.#onPointerMove);
|
|
5758
|
+
window.addEventListener(`pointerup`, this.#onPointerUp);
|
|
5759
|
+
window.addEventListener(`pointercancel`, this.#onPointerCancel);
|
|
5760
|
+
}
|
|
5761
|
+
hostDisconnected() {
|
|
5762
|
+
this.#unbindSurface();
|
|
5763
|
+
window.removeEventListener(`pointermove`, this.#onPointerMove);
|
|
5764
|
+
window.removeEventListener(`pointerup`, this.#onPointerUp);
|
|
5765
|
+
window.removeEventListener(`pointercancel`, this.#onPointerCancel);
|
|
5766
|
+
this.#stopAutoScroll();
|
|
5767
|
+
this.#reset();
|
|
5768
|
+
}
|
|
5769
|
+
/** Re-bind when the surface element appears/changes (e.g. first render). */
|
|
5770
|
+
hostUpdated() {
|
|
5771
|
+
if ((this.#safeSurface() ?? this.#host) !== this.#boundSurface) this.#bindSurface();
|
|
5772
|
+
}
|
|
5773
|
+
#safeSurface() {
|
|
5774
|
+
try {
|
|
5775
|
+
return this.#config.getSurface();
|
|
5776
|
+
} catch {
|
|
5777
|
+
return;
|
|
5778
|
+
}
|
|
5779
|
+
}
|
|
5780
|
+
#bindSurface() {
|
|
5781
|
+
const next = this.#safeSurface() ?? this.#host;
|
|
5782
|
+
if (next === this.#boundSurface) return;
|
|
5783
|
+
this.#unbindSurface();
|
|
5784
|
+
this.#boundSurface = next;
|
|
5785
|
+
next.addEventListener(`pointerdown`, this.#onPointerDown);
|
|
5786
|
+
}
|
|
5787
|
+
#unbindSurface() {
|
|
5788
|
+
this.#boundSurface?.removeEventListener(`pointerdown`, this.#onPointerDown);
|
|
5789
|
+
this.#boundSurface = void 0;
|
|
5790
|
+
}
|
|
5791
|
+
#enabledTypes() {
|
|
5792
|
+
return this.#config.pointerTypes ?? DEFAULT_POINTER_TYPES;
|
|
5793
|
+
}
|
|
5794
|
+
#threshold() {
|
|
5795
|
+
return this.#config.threshold ?? DEFAULT_THRESHOLD;
|
|
5796
|
+
}
|
|
5797
|
+
#onPointerDown = (event) => {
|
|
5798
|
+
if (event.button !== 0) return;
|
|
5799
|
+
if (!this.#enabledTypes().includes(event.pointerType)) return;
|
|
5800
|
+
let enabled = false;
|
|
5801
|
+
try {
|
|
5802
|
+
enabled = this.#config.isEnabled();
|
|
5803
|
+
} catch {
|
|
5804
|
+
return;
|
|
5805
|
+
}
|
|
5806
|
+
if (!enabled) return;
|
|
5807
|
+
const target = event.target;
|
|
5808
|
+
if (target instanceof Element && typeof target.closest === `function`) {
|
|
5809
|
+
if (target.closest(`input,button,a,select,textarea,[contenteditable]`)) return;
|
|
5810
|
+
}
|
|
5811
|
+
if (this.#config.shouldStart) try {
|
|
5812
|
+
if (!this.#config.shouldStart(event)) return;
|
|
5813
|
+
} catch {
|
|
5814
|
+
return;
|
|
5815
|
+
}
|
|
5816
|
+
const box = (this.#safeSurface() ?? this.#host).getBoundingClientRect();
|
|
5817
|
+
this.#pointerId = event.pointerId;
|
|
5818
|
+
this.#startClientX = event.clientX;
|
|
5819
|
+
this.#startClientY = event.clientY;
|
|
5820
|
+
this.#currentClientX = event.clientX;
|
|
5821
|
+
this.#currentClientY = event.clientY;
|
|
5822
|
+
this.#startX = Math.min(Math.max(event.clientX - box.left, 0), Math.max(0, box.width));
|
|
5823
|
+
this.#startY = Math.min(Math.max(event.clientY - box.top, 0), Math.max(0, box.height));
|
|
5824
|
+
this.#dragging = false;
|
|
5825
|
+
this.#suppressClick = false;
|
|
5826
|
+
this.#base = /* @__PURE__ */ new Set();
|
|
5827
|
+
this.#lastMode = `replace`;
|
|
5828
|
+
this.#lastModifiers = {
|
|
5829
|
+
shiftKey: event.shiftKey,
|
|
5830
|
+
ctrlKey: event.ctrlKey,
|
|
5831
|
+
metaKey: event.metaKey
|
|
5832
|
+
};
|
|
5833
|
+
};
|
|
5834
|
+
/** Combine mode for the current modifiers: Shift adds, Cmd/Ctrl inverts. */
|
|
5835
|
+
#modeFor(modifiers) {
|
|
5836
|
+
if (modifiers.metaKey || modifiers.ctrlKey) return `invert`;
|
|
5837
|
+
if (modifiers.shiftKey) return `add`;
|
|
5838
|
+
return `replace`;
|
|
5839
|
+
}
|
|
5840
|
+
#onPointerMove = (event) => {
|
|
5841
|
+
if (this.#pointerId === void 0 || event.pointerId !== this.#pointerId) return;
|
|
5842
|
+
this.#currentClientX = event.clientX;
|
|
5843
|
+
this.#currentClientY = event.clientY;
|
|
5844
|
+
this.#lastModifiers = {
|
|
5845
|
+
shiftKey: event.shiftKey,
|
|
5846
|
+
ctrlKey: event.ctrlKey,
|
|
5847
|
+
metaKey: event.metaKey
|
|
5848
|
+
};
|
|
5849
|
+
const moved = Math.hypot(event.clientX - this.#startClientX, event.clientY - this.#startClientY);
|
|
5850
|
+
if (!this.#dragging) {
|
|
5851
|
+
if (moved < this.#threshold()) return;
|
|
5852
|
+
this.#dragging = true;
|
|
5853
|
+
try {
|
|
5854
|
+
this.#base = new Set(this.#config.getBaseSelection());
|
|
5855
|
+
} catch {
|
|
5856
|
+
this.#base = /* @__PURE__ */ new Set();
|
|
5857
|
+
}
|
|
5858
|
+
const surface = this.#safeSurface() ?? this.#host;
|
|
5859
|
+
try {
|
|
5860
|
+
if (typeof surface.setPointerCapture === `function`) surface.setPointerCapture(event.pointerId);
|
|
5861
|
+
} catch {}
|
|
5862
|
+
}
|
|
5863
|
+
try {
|
|
5864
|
+
event.preventDefault?.();
|
|
5865
|
+
} catch {}
|
|
5866
|
+
this.#updatePreview();
|
|
5867
|
+
this.#kickAutoScroll();
|
|
5868
|
+
};
|
|
5869
|
+
#surfaceBox() {
|
|
5870
|
+
const surface = this.#safeSurface() ?? this.#host;
|
|
5871
|
+
try {
|
|
5872
|
+
return surface.getBoundingClientRect();
|
|
5873
|
+
} catch {
|
|
5874
|
+
return;
|
|
5875
|
+
}
|
|
5876
|
+
}
|
|
5877
|
+
#currentRect() {
|
|
5878
|
+
const box = this.#surfaceBox();
|
|
5879
|
+
if (!box) return void 0;
|
|
5880
|
+
const cx = Math.min(Math.max(this.#currentClientX - box.left, 0), Math.max(0, box.width));
|
|
5881
|
+
const cy = Math.min(Math.max(this.#currentClientY - box.top, 0), Math.max(0, box.height));
|
|
5882
|
+
return {
|
|
5883
|
+
x: Math.min(this.#startX, cx),
|
|
5884
|
+
y: Math.min(this.#startY, cy),
|
|
5885
|
+
width: Math.abs(cx - this.#startX),
|
|
5886
|
+
height: Math.abs(cy - this.#startY)
|
|
5887
|
+
};
|
|
5888
|
+
}
|
|
5889
|
+
#updatePreview() {
|
|
5890
|
+
const rect = this.#currentRect();
|
|
5891
|
+
if (!rect) return;
|
|
5892
|
+
let hit = [];
|
|
5893
|
+
try {
|
|
5894
|
+
hit = this.#config.hitTest(rect);
|
|
5895
|
+
} catch {
|
|
5896
|
+
hit = [];
|
|
5897
|
+
}
|
|
5898
|
+
const mode = this.#modeFor(this.#lastModifiers);
|
|
5899
|
+
this.#lastMode = mode;
|
|
5900
|
+
const hitSet = new Set(hit);
|
|
5901
|
+
let preview;
|
|
5902
|
+
if (mode === `add`) preview = /* @__PURE__ */ new Set([...this.#base, ...hitSet]);
|
|
5903
|
+
else if (mode === `invert`) {
|
|
5904
|
+
const toggled = new Set(this.#base);
|
|
5905
|
+
for (const item of hitSet) if (toggled.has(item)) toggled.delete(item);
|
|
5906
|
+
else toggled.add(item);
|
|
5907
|
+
preview = toggled;
|
|
5908
|
+
} else preview = hitSet;
|
|
5909
|
+
this.#preview = preview;
|
|
5910
|
+
try {
|
|
5911
|
+
this.#config.onPreview(preview, rect);
|
|
5912
|
+
} catch {}
|
|
5913
|
+
}
|
|
5914
|
+
#onPointerUp = (event) => {
|
|
5915
|
+
if (this.#pointerId === void 0 || event.pointerId !== this.#pointerId) return;
|
|
5916
|
+
this.#lastModifiers = {
|
|
5917
|
+
shiftKey: event.shiftKey,
|
|
5918
|
+
ctrlKey: event.ctrlKey,
|
|
5919
|
+
metaKey: event.metaKey
|
|
5920
|
+
};
|
|
5921
|
+
const wasDragging = this.#dragging;
|
|
5922
|
+
const surface = this.#safeSurface() ?? this.#host;
|
|
5923
|
+
try {
|
|
5924
|
+
if (typeof surface.hasPointerCapture === `function` && typeof surface.releasePointerCapture === `function` && surface.hasPointerCapture(event.pointerId)) surface.releasePointerCapture(event.pointerId);
|
|
5925
|
+
} catch {}
|
|
5926
|
+
this.#stopAutoScroll();
|
|
5927
|
+
this.#pointerId = void 0;
|
|
5928
|
+
if (!wasDragging) {
|
|
5929
|
+
this.#reset();
|
|
5930
|
+
return;
|
|
5931
|
+
}
|
|
5932
|
+
this.#dragging = false;
|
|
5933
|
+
const final = this.#preview;
|
|
5934
|
+
try {
|
|
5935
|
+
this.#config.onCommit(final, { additive: this.#lastMode !== `replace` });
|
|
5936
|
+
} catch {}
|
|
5937
|
+
try {
|
|
5938
|
+
this.#config.onPreview(/* @__PURE__ */ new Set(), void 0);
|
|
5939
|
+
} catch {}
|
|
5940
|
+
this.#preview = /* @__PURE__ */ new Set();
|
|
5941
|
+
this.#suppressClick = true;
|
|
5942
|
+
window.setTimeout(() => {
|
|
5943
|
+
this.#suppressClick = false;
|
|
5944
|
+
}, 0);
|
|
5945
|
+
};
|
|
5946
|
+
#onPointerCancel = (event) => {
|
|
5947
|
+
if (this.#pointerId === void 0 || event.pointerId !== this.#pointerId) return;
|
|
5948
|
+
this.#stopAutoScroll();
|
|
5949
|
+
this.#pointerId = void 0;
|
|
5950
|
+
this.#dragging = false;
|
|
5951
|
+
this.#preview = /* @__PURE__ */ new Set();
|
|
5952
|
+
try {
|
|
5953
|
+
this.#config.onPreview(/* @__PURE__ */ new Set(), void 0);
|
|
5954
|
+
} catch {}
|
|
5955
|
+
this.#suppressClick = false;
|
|
5956
|
+
};
|
|
5957
|
+
#kickAutoScroll() {
|
|
5958
|
+
if (!this.#config.autoScroll || this.#raf !== 0) return;
|
|
5959
|
+
this.#raf = requestAnimationFrame(this.#autoScrollTick);
|
|
5960
|
+
}
|
|
5961
|
+
#autoScrollTick = () => {
|
|
5962
|
+
this.#raf = 0;
|
|
5963
|
+
if (!this.#dragging || this.#pointerId === void 0) return;
|
|
5964
|
+
const box = this.#surfaceBox();
|
|
5965
|
+
if (!box) return;
|
|
5966
|
+
const px = this.#currentClientX - box.left;
|
|
5967
|
+
const py = this.#currentClientY - box.top;
|
|
5968
|
+
let dx = 0;
|
|
5969
|
+
let dy = 0;
|
|
5970
|
+
if (px < EDGE_ZONE) dx = -Math.ceil(MAX_SCROLL_SPEED * (1 - Math.max(0, px) / EDGE_ZONE));
|
|
5971
|
+
else if (px > box.width - EDGE_ZONE) dx = Math.ceil(MAX_SCROLL_SPEED * (1 - Math.max(0, box.width - px) / EDGE_ZONE));
|
|
5972
|
+
if (py < EDGE_ZONE) dy = -Math.ceil(MAX_SCROLL_SPEED * (1 - Math.max(0, py) / EDGE_ZONE));
|
|
5973
|
+
else if (py > box.height - EDGE_ZONE) dy = Math.ceil(MAX_SCROLL_SPEED * (1 - Math.max(0, box.height - py) / EDGE_ZONE));
|
|
5974
|
+
if (dx === 0 && dy === 0) return;
|
|
5975
|
+
const autoScroll = this.#config.autoScroll;
|
|
5976
|
+
if (!autoScroll) return;
|
|
5977
|
+
try {
|
|
5978
|
+
autoScroll(dx, dy);
|
|
5979
|
+
} catch {}
|
|
5980
|
+
this.#updatePreview();
|
|
5981
|
+
this.#raf = requestAnimationFrame(this.#autoScrollTick);
|
|
5982
|
+
};
|
|
5983
|
+
#stopAutoScroll() {
|
|
5984
|
+
if (this.#raf !== 0) {
|
|
5985
|
+
cancelAnimationFrame(this.#raf);
|
|
5986
|
+
this.#raf = 0;
|
|
5987
|
+
}
|
|
5988
|
+
}
|
|
5989
|
+
#reset() {
|
|
5990
|
+
this.#dragging = false;
|
|
5991
|
+
this.#suppressClick = false;
|
|
5992
|
+
this.#base = /* @__PURE__ */ new Set();
|
|
5993
|
+
this.#lastMode = `replace`;
|
|
5994
|
+
this.#preview = /* @__PURE__ */ new Set();
|
|
5995
|
+
}
|
|
5996
|
+
};
|
|
5997
|
+
//#endregion
|
|
4562
5998
|
//#region src/interaction/list-item-animation.ts
|
|
4563
5999
|
/**
|
|
4564
6000
|
* Shared insertion / removal animation for the list & tree components.
|
|
@@ -4797,6 +6233,31 @@ var ListSelectionController = class {
|
|
|
4797
6233
|
this.#anchor = [...next].at(-1);
|
|
4798
6234
|
this.#apply(next);
|
|
4799
6235
|
}
|
|
6236
|
+
/**
|
|
6237
|
+
* Whether a drag / marquee gesture may build a selection in the current
|
|
6238
|
+
* modes: `selectionMode="multiple"`, or a multi interaction mode
|
|
6239
|
+
* (`checked` / `sticky` / `vscode`) outside `selectionMode="none"`.
|
|
6240
|
+
* Stricter than `canSelectMultiple()` — `single` + `standard` does not
|
|
6241
|
+
* qualify (a drag there would be a surprising multi-select).
|
|
6242
|
+
*/
|
|
6243
|
+
canDragSelect() {
|
|
6244
|
+
return this.#config.getModes().selectionMode !== `none` && this.#effectiveMulti();
|
|
6245
|
+
}
|
|
6246
|
+
/**
|
|
6247
|
+
* Replace the selection with `items` from a drag / marquee gesture. Like
|
|
6248
|
+
* `selectMany` but gated on `canDragSelect()` instead of throwing, and a
|
|
6249
|
+
* no-op in single/none modes. Non-selectable items are dropped; the anchor
|
|
6250
|
+
* moves to the last item. Fires `onChange` once. An empty result clears a
|
|
6251
|
+
* non-empty selection (e.g. a Cmd-drag that toggles everything off) but is
|
|
6252
|
+
* a no-op when nothing is selected.
|
|
6253
|
+
*/
|
|
6254
|
+
applyDragSelection(items) {
|
|
6255
|
+
if (!this.canDragSelect()) return;
|
|
6256
|
+
const next = new Set([...items].filter((t) => this.#config.isSelectable(t)));
|
|
6257
|
+
if (next.size === 0 && this.#selected.size === 0) return;
|
|
6258
|
+
this.#anchor = [...next].at(-1);
|
|
6259
|
+
this.#apply(next);
|
|
6260
|
+
}
|
|
4800
6261
|
/** Remove a single item from the selection. */
|
|
4801
6262
|
deselect(item) {
|
|
4802
6263
|
if (!this.#selected.has(item)) return;
|
|
@@ -11889,6 +13350,7 @@ let DataGridElement = class DataGridElement extends i {
|
|
|
11889
13350
|
static {
|
|
11890
13351
|
this.styles = [
|
|
11891
13352
|
themeFallbacks,
|
|
13353
|
+
handleStyles,
|
|
11892
13354
|
tickledStyles,
|
|
11893
13355
|
tickledItemStyles,
|
|
11894
13356
|
listItemFadeKeyframes,
|
|
@@ -11932,7 +13394,8 @@ let DataGridElement = class DataGridElement extends i {
|
|
|
11932
13394
|
.header-label { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
11933
13395
|
.sort-icon { font-size: 10px; opacity: 0.7; }
|
|
11934
13396
|
.resize-handle { position: absolute; right: 0; top: 0; bottom: 0; width: 8px; cursor: col-resize; z-index: 1; }
|
|
11935
|
-
.reorder-handle { cursor: grab; opacity: 0.5; padding: 0 2px; }
|
|
13397
|
+
.reorder-handle { cursor: grab; opacity: 0.5; padding: 0 2px; display: inline-flex; align-items: center; }
|
|
13398
|
+
.reorder-handle .ixfx-handle { --ixfx-handle-spot-size: 14px; --ixfx-handle-dot-size: 3px; }
|
|
11936
13399
|
.flyout-trigger { flex-shrink: 0; width: 36px; display: flex; align-items: center; justify-content: center; cursor: pointer; border-left: var(--border-subtle); background: var(--data-grid-header-bg); }
|
|
11937
13400
|
.viewport { flex: 1; overflow: auto; position: relative; }
|
|
11938
13401
|
.spacer { position: relative; }
|
|
@@ -12838,7 +14301,7 @@ let DataGridElement = class DataGridElement extends i {
|
|
|
12838
14301
|
@pointerenter=${() => this._tickled.handlePointerEnter(col.key)}>
|
|
12839
14302
|
${col.reorderable !== false ? b`<span class="reorder-handle" draggable="false"
|
|
12840
14303
|
@pointerdown=${(e) => this._beginHeaderDrag(e, col, idx)}
|
|
12841
|
-
|
|
14304
|
+
><span class="ixfx-handle" data-handle="dotted" data-shape="spot" part="reorder-handle"></span></span>` : A}
|
|
12842
14305
|
<span class="header-label">${col.label}</span>
|
|
12843
14306
|
${this.sortState?.key === col.key ? b`<span class="sort-icon">${this.sortState.direction === `asc` ? `▲` : `▼`}</span>` : A}
|
|
12844
14307
|
${col.resizable !== false ? b`<span class="resize-handle" @pointerdown=${(e) => this._onResizePointerDown(e, col)} @click=${(e) => e.stopPropagation()} @dblclick=${(e) => {
|
|
@@ -13426,7 +14889,28 @@ let DetailListElement = class DetailListElement extends i {
|
|
|
13426
14889
|
if (id !== void 0) this._dispatch(`list-tickle`, { item: id });
|
|
13427
14890
|
},
|
|
13428
14891
|
onStateChange: () => this._syncItemStates(),
|
|
13429
|
-
itemWrap: this.itemWrap
|
|
14892
|
+
itemWrap: this.itemWrap,
|
|
14893
|
+
hoverDisabled: () => this.#dragSelect.isDragging
|
|
14894
|
+
});
|
|
14895
|
+
this.#dragSelect = new ListDragSelectController(this, {
|
|
14896
|
+
getSurface: () => this.renderRoot.querySelector(`.container`),
|
|
14897
|
+
isEnabled: () => this.selection.canDragSelect() && this._getVisibleItems().length > 0 && !this.hasAttribute(`disable-drag-select`),
|
|
14898
|
+
hitTest: (rect) => this.#marqueeHitTest(rect),
|
|
14899
|
+
getBaseSelection: () => this.selection.selected,
|
|
14900
|
+
onPreview: (preview, rect) => {
|
|
14901
|
+
this.#marqueeRect = rect;
|
|
14902
|
+
for (const el of this._getVisibleItems()) el.toggleAttribute(`data-marquee`, preview.has(el));
|
|
14903
|
+
this.requestUpdate();
|
|
14904
|
+
},
|
|
14905
|
+
onCommit: (finalSet) => {
|
|
14906
|
+
this.selection.applyDragSelection(finalSet);
|
|
14907
|
+
for (const el of this._getVisibleItems()) el.removeAttribute(`data-marquee`);
|
|
14908
|
+
this.#marqueeRect = void 0;
|
|
14909
|
+
this.requestUpdate();
|
|
14910
|
+
},
|
|
14911
|
+
autoScroll: (dx, _dy) => {
|
|
14912
|
+
if (this._listEl) this._listEl.scrollLeft += dx;
|
|
14913
|
+
}
|
|
13430
14914
|
});
|
|
13431
14915
|
this.search = new ListSearchController(this, { adapter: createElementListSearchAdapter(this, {
|
|
13432
14916
|
itemSelector: ITEM_SELECTOR$3,
|
|
@@ -13503,6 +14987,7 @@ let DetailListElement = class DetailListElement extends i {
|
|
|
13503
14987
|
}
|
|
13504
14988
|
};
|
|
13505
14989
|
this._onClick = (e) => {
|
|
14990
|
+
if (this.#dragSelect.isDragging) return;
|
|
13506
14991
|
const item = this._findListItem(e.composedPath());
|
|
13507
14992
|
if (!item) return;
|
|
13508
14993
|
this.focus();
|
|
@@ -13529,6 +15014,30 @@ let DetailListElement = class DetailListElement extends i {
|
|
|
13529
15014
|
#builtFromProvider;
|
|
13530
15015
|
#providerBuilt;
|
|
13531
15016
|
#data;
|
|
15017
|
+
/** Live drag-select preview rect (surface-relative); the covered items carry `data-marquee`. */
|
|
15018
|
+
#marqueeRect;
|
|
15019
|
+
#dragSelect;
|
|
15020
|
+
/** Collect visible items whose surface-relative box intersects `rect`. */
|
|
15021
|
+
#marqueeHitTest(rect) {
|
|
15022
|
+
const surface = this.renderRoot.querySelector(`.container`);
|
|
15023
|
+
if (!surface) return [];
|
|
15024
|
+
const box = surface.getBoundingClientRect();
|
|
15025
|
+
const rx0 = rect.x;
|
|
15026
|
+
const ry0 = rect.y;
|
|
15027
|
+
const rx1 = rect.x + rect.width;
|
|
15028
|
+
const ry1 = rect.y + rect.height;
|
|
15029
|
+
const out = [];
|
|
15030
|
+
for (const el of this._getVisibleItems()) {
|
|
15031
|
+
const r = el.getBoundingClientRect();
|
|
15032
|
+
const left = r.left - box.left;
|
|
15033
|
+
const top = r.top - box.top;
|
|
15034
|
+
if (left <= rx1 && left + r.width >= rx0 && top <= ry1 && top + r.height >= ry0) out.push(el);
|
|
15035
|
+
}
|
|
15036
|
+
return out;
|
|
15037
|
+
}
|
|
15038
|
+
#marqueeStyle(rect) {
|
|
15039
|
+
return `left:${rect.x}px;top:${rect.y}px;width:${Math.max(0, rect.width)}px;height:${Math.max(0, rect.height)}px`;
|
|
15040
|
+
}
|
|
13532
15041
|
#searchRegistry;
|
|
13533
15042
|
#unregisterSearchCommands;
|
|
13534
15043
|
/** Command registry carrying this list's `list.search.*` commands. */
|
|
@@ -14301,6 +15810,22 @@ let DetailListElement = class DetailListElement extends i {
|
|
|
14301
15810
|
outline-offset: -2px;
|
|
14302
15811
|
}
|
|
14303
15812
|
|
|
15813
|
+
/* Drag-select (marquee) rectangle + covered-row preview.
|
|
15814
|
+
Style hooks: part="marquee", --detail-list-marquee-border,
|
|
15815
|
+
--detail-list-marquee-fill. */
|
|
15816
|
+
.marquee {
|
|
15817
|
+
position: absolute;
|
|
15818
|
+
pointer-events: none;
|
|
15819
|
+
z-index: 5;
|
|
15820
|
+
border: 1px solid var(--detail-list-marquee-border, var(--accent));
|
|
15821
|
+
background: var(--detail-list-marquee-fill, color-mix(in srgb, var(--accent) 15%, transparent));
|
|
15822
|
+
}
|
|
15823
|
+
|
|
15824
|
+
::slotted([data-marquee]) {
|
|
15825
|
+
background: var(--item-bg-selected);
|
|
15826
|
+
color: var(--item-text-selected);
|
|
15827
|
+
}
|
|
15828
|
+
|
|
14304
15829
|
/* checked mode: the injected checkbox communicates selection — suppress bg */
|
|
14305
15830
|
:host([interaction-mode="checked"]) ::slotted([data-selected]) {
|
|
14306
15831
|
background: transparent;
|
|
@@ -14341,6 +15866,7 @@ let DetailListElement = class DetailListElement extends i {
|
|
|
14341
15866
|
<ul part="list" class="scroll-fade-x">
|
|
14342
15867
|
<slot></slot>
|
|
14343
15868
|
</ul>
|
|
15869
|
+
${this.#marqueeRect ? b`<div class="marquee" part="marquee" style=${this.#marqueeStyle(this.#marqueeRect)}></div>` : ``}
|
|
14344
15870
|
<div class="loading" part="loading" ?hidden=${!loading}>
|
|
14345
15871
|
${loading ? progress !== void 0 ? `${Math.round(progress * 100)}%` : `loading…` : A}
|
|
14346
15872
|
</div>
|
|
@@ -15994,16 +17520,20 @@ let SplitLayoutElement = class SplitLayoutElement extends i {
|
|
|
15994
17520
|
style="cursor: ${cursor}; grid-column: ${gridColumn}; grid-row: ${gridRow};"
|
|
15995
17521
|
@pointerdown=${(e) => this._onGutterPointerDown(e, groupId, index)}
|
|
15996
17522
|
>
|
|
15997
|
-
<
|
|
15998
|
-
|
|
15999
|
-
|
|
16000
|
-
|
|
16001
|
-
|
|
17523
|
+
<span
|
|
17524
|
+
class="ixfx-handle"
|
|
17525
|
+
part="grip"
|
|
17526
|
+
data-handle="dimpled"
|
|
17527
|
+
data-shape=${isRow ? `vertical` : `horizontal`}
|
|
17528
|
+
></span>
|
|
16002
17529
|
</div>
|
|
16003
17530
|
`;
|
|
16004
17531
|
}
|
|
16005
17532
|
static {
|
|
16006
|
-
this.styles = [
|
|
17533
|
+
this.styles = [
|
|
17534
|
+
themeFallbacks,
|
|
17535
|
+
handleStyles,
|
|
17536
|
+
i$3`
|
|
16007
17537
|
:host {
|
|
16008
17538
|
display: block;
|
|
16009
17539
|
width: 100%;
|
|
@@ -16014,10 +17544,10 @@ let SplitLayoutElement = class SplitLayoutElement extends i {
|
|
|
16014
17544
|
--split-gutter-active-color: var(--accent);
|
|
16015
17545
|
--split-collapsed-size: 0px;
|
|
16016
17546
|
--split-snap: 24px;
|
|
16017
|
-
|
|
16018
|
-
|
|
16019
|
-
--
|
|
16020
|
-
--
|
|
17547
|
+
|
|
17548
|
+
/* Gutter grip — shared handle primitive (docs/infra-handle.md). */
|
|
17549
|
+
--ixfx-handle-length: 16px;
|
|
17550
|
+
--ixfx-handle-thickness: 8px;
|
|
16021
17551
|
}
|
|
16022
17552
|
|
|
16023
17553
|
* {
|
|
@@ -16079,31 +17609,15 @@ let SplitLayoutElement = class SplitLayoutElement extends i {
|
|
|
16079
17609
|
user-select: none;
|
|
16080
17610
|
}
|
|
16081
17611
|
|
|
16082
|
-
.
|
|
16083
|
-
width: var(--split-grab-dot-size);
|
|
16084
|
-
height: var(--split-grab-dot-size);
|
|
16085
|
-
border-radius: 50%;
|
|
16086
|
-
background: var(--split-grab-color);
|
|
16087
|
-
}
|
|
16088
|
-
|
|
16089
|
-
:host([direction="row"]) .grab-handle {
|
|
16090
|
-
flex-direction: column;
|
|
16091
|
-
gap: var(--split-grab-dot-size);
|
|
16092
|
-
}
|
|
16093
|
-
|
|
16094
|
-
:host([direction="column"]) .grab-handle {
|
|
16095
|
-
flex-direction: row;
|
|
16096
|
-
gap: var(--split-grab-dot-size);
|
|
16097
|
-
}
|
|
16098
|
-
|
|
16099
|
-
:host([data-dragging]) .grab-handle {
|
|
17612
|
+
:host([data-dragging]) .gutter .ixfx-handle {
|
|
16100
17613
|
display: none;
|
|
16101
17614
|
}
|
|
16102
17615
|
|
|
16103
|
-
:host(:not([data-dragging])) .gutter:hover .
|
|
16104
|
-
display:
|
|
17616
|
+
:host(:not([data-dragging])) .gutter:hover .ixfx-handle {
|
|
17617
|
+
display: none;
|
|
16105
17618
|
}
|
|
16106
|
-
`
|
|
17619
|
+
`
|
|
17620
|
+
];
|
|
16107
17621
|
}
|
|
16108
17622
|
};
|
|
16109
17623
|
__decorate([property({
|
|
@@ -16817,636 +18331,238 @@ let TabListItemElement = class TabListItemElement extends i {
|
|
|
16817
18331
|
/**
|
|
16818
18332
|
* Mirror the default-slot text into `.label[data-label]` for the `::after`
|
|
16819
18333
|
* width sizer. Slotted toolbar content is excluded.
|
|
16820
|
-
*/
|
|
16821
|
-
_syncLabelSizer() {
|
|
16822
|
-
const slot = this.shadowRoot?.querySelector(`slot:not([name])`);
|
|
16823
|
-
const label = this.shadowRoot?.querySelector(`.label`);
|
|
16824
|
-
if (slot === null || slot === void 0 || label === null || label === void 0) return;
|
|
16825
|
-
const text = slot.assignedNodes().filter((node) => !(node instanceof HTMLElement && node.hasAttribute(`slot`))).map((node) => node.textContent ?? ``).join(``);
|
|
16826
|
-
if (text) label.setAttribute(`data-label`, text);
|
|
16827
|
-
else label.removeAttribute(`data-label`);
|
|
16828
|
-
}
|
|
16829
|
-
_updateToolbarContent() {
|
|
16830
|
-
const slot = this.shadowRoot?.querySelector(`slot[name="toolbar"]`);
|
|
16831
|
-
this._hasToolbarContent = (slot?.assignedElements().length ?? 0) > 0;
|
|
16832
|
-
}
|
|
16833
|
-
firstUpdated() {
|
|
16834
|
-
this._updateToolbarContent();
|
|
16835
|
-
this._syncLabelSizer();
|
|
16836
|
-
}
|
|
16837
|
-
render() {
|
|
16838
|
-
const showLabel = !this.hideLabels || !this.iconName;
|
|
16839
|
-
const hasActions = this.closeable || this._hasToolbarContent;
|
|
16840
|
-
return b`
|
|
16841
|
-
<div>
|
|
16842
|
-
${this.iconName ? b`<ixfx-icon name="${this.iconName}"></ixfx-icon>` : A}
|
|
16843
|
-
${showLabel ? b`<span class="label"><slot></slot></span>` : A}
|
|
16844
|
-
${hasActions ? b`
|
|
16845
|
-
<div class="actions">
|
|
16846
|
-
<div class="toolbar"><slot name="toolbar"></slot></div>
|
|
16847
|
-
${this.closeable ? b`
|
|
16848
|
-
<button
|
|
16849
|
-
class="close-btn"
|
|
16850
|
-
type="button"
|
|
16851
|
-
aria-label="Close tab"
|
|
16852
|
-
@click=${this._onCloseClick}
|
|
16853
|
-
>
|
|
16854
|
-
<ixfx-icon name="close"></ixfx-icon>
|
|
16855
|
-
</button>
|
|
16856
|
-
` : A}
|
|
16857
|
-
</div>
|
|
16858
|
-
` : A}
|
|
16859
|
-
</div>
|
|
16860
|
-
`;
|
|
16861
|
-
}
|
|
16862
|
-
_onCloseClick(e) {
|
|
16863
|
-
e.stopPropagation();
|
|
16864
|
-
this.dispatchEvent(new CustomEvent(`close`, {
|
|
16865
|
-
bubbles: true,
|
|
16866
|
-
composed: true
|
|
16867
|
-
}));
|
|
16868
|
-
this.remove();
|
|
16869
|
-
}
|
|
16870
|
-
static {
|
|
16871
|
-
this.styles = [
|
|
16872
|
-
themeFallbacks,
|
|
16873
|
-
prominenceStyles,
|
|
16874
|
-
i$3`
|
|
16875
|
-
:host {
|
|
16876
|
-
--selected-tab-color: var(--ixfx-selected-tab-color, var(--surface-2-text));
|
|
16877
|
-
--selected-tab-icon-color: var(--ixfx-selected-tab-icon-color, var(--accent));
|
|
16878
|
-
--selected-tab-border-width: var(--ixfx-selected-tab-border-width, 1px);
|
|
16879
|
-
--selected-tab-weight: var(--ixfx-selected-tab-weight, bold);
|
|
16880
|
-
--selected-tab-text-decoration: var(--ixfx-selected-tab-text-decoration, none);
|
|
16881
|
-
--selected-tab-text-decoration-color: var(--ixfx-selected-tab-text-decoration-color, var(--accent));
|
|
16882
|
-
--selected-tab-text-decoration-thickness: var(--ixfx-selected-tab-text-decoration-thickness, 0px);
|
|
16883
|
-
--selected-tab-text-decoration-offset: var(--ixfx-selected-tab-text-decoration-offset, 2px);
|
|
16884
|
-
--selected-background: var(--ixfx-tab-selected-background, var(--surface-5));
|
|
16885
|
-
--tab-padding: var(--ixfx-tab-padding, var(--space-s));
|
|
16886
|
-
display: inline-flex;
|
|
16887
|
-
min-width: 0;
|
|
16888
|
-
user-select: none;
|
|
16889
|
-
box-sizing: border-box;
|
|
16890
|
-
font-size: var(--text-m);
|
|
16891
|
-
color: inherit;
|
|
16892
|
-
/* No explicit height: items stretch (align-self: stretch via the
|
|
16893
|
-
list's flex container) so every tab in a strip shares one height
|
|
16894
|
-
even when toolbars give some items taller content. */
|
|
16895
|
-
}
|
|
16896
|
-
|
|
16897
|
-
:host > div {
|
|
16898
|
-
display: flex;
|
|
16899
|
-
align-items: center;
|
|
16900
|
-
padding: var(--tab-padding) calc(2 * var(--tab-padding-horizontal, var(--tab-padding)));
|
|
16901
|
-
min-width: 0;
|
|
16902
|
-
width: 100%;
|
|
16903
|
-
font-weight: 500;
|
|
16904
|
-
border: var(--selected-tab-border-width) solid transparent;
|
|
16905
|
-
gap: var(--space-s);
|
|
16906
|
-
transition: background var(--transition, 0.15s);
|
|
16907
|
-
}
|
|
16908
|
-
|
|
16909
|
-
/* Hover ("tickle") background. When --ixfx-tab-hover-background is
|
|
16910
|
-
unset each state keeps its resting background, so existing
|
|
16911
|
-
consumers see no change. */
|
|
16912
|
-
:host(:hover:not([selected])) > div {
|
|
16913
|
-
background: var(--ixfx-tab-hover-background, transparent);
|
|
16914
|
-
}
|
|
16915
|
-
|
|
16916
|
-
:host([selected]:hover) > div {
|
|
16917
|
-
background: var(--ixfx-tab-hover-background, var(--selected-background));
|
|
16918
|
-
}
|
|
16919
|
-
|
|
16920
|
-
:host([selected]) > div {
|
|
16921
|
-
color: var(--selected-tab-color);
|
|
16922
|
-
border-top-color: var(--indicator-color-top, transparent);
|
|
16923
|
-
border-bottom-color: var(--indicator-color-bottom, transparent);
|
|
16924
|
-
border-left-color: var(--indicator-color-left, transparent);
|
|
16925
|
-
border-right-color: var(--indicator-color-right, transparent);
|
|
16926
|
-
background: var(--selected-background);
|
|
16927
|
-
font-weight: var(--selected-tab-weight);
|
|
16928
|
-
border-radius:var(--radius-m);
|
|
16929
|
-
}
|
|
16930
|
-
|
|
16931
|
-
:host([selected]) .label {
|
|
16932
|
-
text-decoration: var(--selected-tab-text-decoration);
|
|
16933
|
-
text-decoration-color: var(--selected-tab-text-decoration-color);
|
|
16934
|
-
text-decoration-thickness: var(--selected-tab-text-decoration-thickness);
|
|
16935
|
-
text-decoration-offset: var(--selected-tab-text-decoration-offset);
|
|
16936
|
-
}
|
|
16937
|
-
|
|
16938
|
-
.label {
|
|
16939
|
-
overflow: var(--allow-overflow, hidden);
|
|
16940
|
-
text-overflow: ellipsis;
|
|
16941
|
-
white-space: nowrap;
|
|
16942
|
-
min-width: 0;
|
|
16943
|
-
flex: 1 1 auto;
|
|
16944
|
-
}
|
|
16945
|
-
|
|
16946
|
-
/* Width sizer: an invisible copy of the label, always set at the
|
|
16947
|
-
selected weight, so activating a tab (bold) never shifts the strip.
|
|
16948
|
-
Text is mirrored from the default slot via the data-label attribute
|
|
16949
|
-
(see _syncLabelSizer). */
|
|
16950
|
-
.label::after {
|
|
16951
|
-
content: attr(data-label);
|
|
16952
|
-
display: block;
|
|
16953
|
-
height: 0;
|
|
16954
|
-
overflow: hidden;
|
|
16955
|
-
visibility: hidden;
|
|
16956
|
-
font-weight: var(--selected-tab-weight);
|
|
16957
|
-
}
|
|
16958
|
-
|
|
16959
|
-
ixfx-icon {
|
|
16960
|
-
flex-shrink: 0;
|
|
16961
|
-
}
|
|
16962
|
-
|
|
16963
|
-
/* Leading icon (direct child — not close/toolbar icons) picks up the
|
|
16964
|
-
accent when selected, so icon-only tabs read as active. */
|
|
16965
|
-
:host([selected]) > div > ixfx-icon {
|
|
16966
|
-
color: var(--selected-tab-icon-color);
|
|
16967
|
-
}
|
|
16968
|
-
|
|
16969
|
-
.actions {
|
|
16970
|
-
display: flex;
|
|
16971
|
-
align-items: center;
|
|
16972
|
-
gap: var(--space-xs);
|
|
16973
|
-
margin-left: auto;
|
|
16974
|
-
flex-shrink: 0;
|
|
16975
|
-
}
|
|
16976
|
-
|
|
16977
|
-
.toolbar {
|
|
16978
|
-
/* Always laid out (display: flex) so the tab's width doesn't shift when
|
|
16979
|
-
the toolbar appears on selection. visibility: hidden keeps the
|
|
16980
|
-
toolbar from receiving pointer events or painting, while preserving
|
|
16981
|
-
the space its contents take up. */
|
|
16982
|
-
display: flex;
|
|
16983
|
-
align-items: center;
|
|
16984
|
-
gap: var(--space-xs);
|
|
16985
|
-
visibility: hidden;
|
|
16986
|
-
}
|
|
16987
|
-
|
|
16988
|
-
:host([selected]) .toolbar {
|
|
16989
|
-
visibility: visible;
|
|
16990
|
-
}
|
|
16991
|
-
|
|
16992
|
-
slot[name="toolbar"] {
|
|
16993
|
-
display: contents;
|
|
16994
|
-
}
|
|
16995
|
-
|
|
16996
|
-
/* Slotted buttons inherit these through the shadow boundary; keeps a
|
|
16997
|
-
toolbar button from inflating the strip height. */
|
|
16998
|
-
.toolbar ::slotted(ixfx-button) {
|
|
16999
|
-
--ixfx-button-padding-block: var(--space-xs);
|
|
17000
|
-
}
|
|
17001
|
-
|
|
17002
|
-
.close-btn {
|
|
17003
|
-
display: inline-flex;
|
|
17004
|
-
align-items: center;
|
|
17005
|
-
justify-content: center;
|
|
17006
|
-
background: none;
|
|
17007
|
-
border: none;
|
|
17008
|
-
padding: var(--space-xs);
|
|
17009
|
-
cursor: pointer;
|
|
17010
|
-
color: inherit;
|
|
17011
|
-
border-radius: var(--radius-s);
|
|
17012
|
-
opacity: var(--prominence-idle-opacity);
|
|
17013
|
-
transition: opacity var(--transition), background var(--transition);
|
|
17014
|
-
}
|
|
17015
|
-
|
|
17016
|
-
.close-btn:hover {
|
|
17017
|
-
background: var(--surface-5);
|
|
17018
|
-
opacity: var(--prominence-tickled-opacity);
|
|
17019
|
-
}
|
|
17020
|
-
|
|
17021
|
-
.close-btn:focus-visible {
|
|
17022
|
-
outline: 2px solid var(--accent);
|
|
17023
|
-
outline-offset: 1px;
|
|
17024
|
-
}
|
|
17025
|
-
|
|
17026
|
-
:host([selected]) .close-btn,
|
|
17027
|
-
:host(:hover) .close-btn {
|
|
17028
|
-
opacity: var(--prominence-tickled-opacity);
|
|
17029
|
-
}
|
|
17030
|
-
`
|
|
17031
|
-
];
|
|
17032
|
-
}
|
|
17033
|
-
};
|
|
17034
|
-
__decorate([property({ type: Boolean })], TabListItemElement.prototype, "closeable", void 0);
|
|
17035
|
-
__decorate([property({
|
|
17036
|
-
type: Boolean,
|
|
17037
|
-
attribute: `hide-labels`
|
|
17038
|
-
})], TabListItemElement.prototype, "hideLabels", void 0);
|
|
17039
|
-
__decorate([property({
|
|
17040
|
-
type: String,
|
|
17041
|
-
attribute: `icon-name`
|
|
17042
|
-
})], TabListItemElement.prototype, "iconName", void 0);
|
|
17043
|
-
__decorate([property({ type: String })], TabListItemElement.prototype, "description", void 0);
|
|
17044
|
-
__decorate([property({
|
|
17045
|
-
type: String,
|
|
17046
|
-
attribute: `command-active`
|
|
17047
|
-
})], TabListItemElement.prototype, "commandActive", void 0);
|
|
17048
|
-
__decorate([property({ attribute: false })], TabListItemElement.prototype, "registry", void 0);
|
|
17049
|
-
__decorate([state()], TabListItemElement.prototype, "_compact", void 0);
|
|
17050
|
-
__decorate([state()], TabListItemElement.prototype, "_hasToolbarContent", void 0);
|
|
17051
|
-
TabListItemElement = __decorate([safeCustomElement(`ixfx-tab-list-item`)], TabListItemElement);
|
|
17052
|
-
//#endregion
|
|
17053
|
-
//#region src/titlebar/titlebar.ts
|
|
17054
|
-
let TitlebarElement = class TitlebarElement extends i {
|
|
17055
|
-
constructor(..._args) {
|
|
17056
|
-
super(..._args);
|
|
17057
|
-
this.title = ``;
|
|
17058
|
-
this.iconName = ``;
|
|
17059
|
-
this.orientation = `horizontal`;
|
|
17060
|
-
this.variant = `titlebar`;
|
|
17061
|
-
this.closable = false;
|
|
17062
|
-
this.collapsible = false;
|
|
17063
|
-
this.collapsed = false;
|
|
17064
|
-
this.toggleInteraction = `implicit`;
|
|
17065
|
-
}
|
|
17066
|
-
_onToggleClick() {
|
|
17067
|
-
if (!this.collapsible) return;
|
|
17068
|
-
this.collapsed = !this.collapsed;
|
|
17069
|
-
this.dispatchEvent(new CustomEvent(`toggle`, {
|
|
17070
|
-
detail: { collapsed: this.collapsed },
|
|
17071
|
-
bubbles: true,
|
|
17072
|
-
composed: true
|
|
17073
|
-
}));
|
|
17074
|
-
}
|
|
17075
|
-
_onCloseClick() {
|
|
17076
|
-
this.dispatchEvent(new CustomEvent(`close`, {
|
|
17077
|
-
bubbles: true,
|
|
17078
|
-
composed: true
|
|
17079
|
-
}));
|
|
17080
|
-
}
|
|
17081
|
-
_getCaretIcon() {
|
|
17082
|
-
return `chevron-down`;
|
|
17083
|
-
}
|
|
17084
|
-
render() {
|
|
17085
|
-
const caretIcon = this._getCaretIcon();
|
|
17086
|
-
const isVertical = this.orientation === `vertical`;
|
|
17087
|
-
const showCaret = this.collapsible && this.toggleInteraction !== `disabled`;
|
|
17088
|
-
const implicitToggle = this.collapsible && this.toggleInteraction === `implicit`;
|
|
17089
|
-
const caretRotation = isVertical ? this.collapsed ? `` : `-90deg` : this.collapsed ? `-90deg` : ``;
|
|
17090
|
-
const treeVariant = this.variant === `tree`;
|
|
17091
|
-
return b`
|
|
17092
|
-
<div
|
|
17093
|
-
class="bar"
|
|
17094
|
-
role="toolbar"
|
|
17095
|
-
@click=${implicitToggle ? this._onToggleClick : A}
|
|
17096
|
-
>
|
|
17097
|
-
${treeVariant && showCaret ? b`
|
|
17098
|
-
<button
|
|
17099
|
-
class="caret-btn"
|
|
17100
|
-
type="button"
|
|
17101
|
-
aria-label=${this.collapsed ? `Expand panel` : `Collapse panel`}
|
|
17102
|
-
@click=${this._onToggleClick}
|
|
17103
|
-
>
|
|
17104
|
-
<ixfx-icon name=${caretIcon} prominence .rotate=${caretRotation.length > 0 ? caretRotation : A}></ixfx-icon>
|
|
17105
|
-
</button>
|
|
17106
|
-
` : A}
|
|
17107
|
-
<div class="title-text-wrapper">
|
|
17108
|
-
${this.iconName ? b`<ixfx-icon class="title-icon" name=${this.iconName}></ixfx-icon>` : A}
|
|
17109
|
-
<span class="title-text">${this.title}</span>
|
|
17110
|
-
</div>
|
|
17111
|
-
|
|
17112
|
-
<div class="toolbar" @click=${(e) => e.stopPropagation()}>
|
|
17113
|
-
<slot name="toolbar"></slot>
|
|
17114
|
-
${this.closable ? b`
|
|
17115
|
-
<button
|
|
17116
|
-
class="close-btn"
|
|
17117
|
-
type="button"
|
|
17118
|
-
aria-label="Close panel"
|
|
17119
|
-
@click=${this._onCloseClick}
|
|
17120
|
-
>
|
|
17121
|
-
<ixfx-icon name="close"></ixfx-icon>
|
|
17122
|
-
</button>
|
|
17123
|
-
` : A}
|
|
17124
|
-
${!treeVariant && showCaret ? b`
|
|
17125
|
-
<button
|
|
17126
|
-
class="caret-btn"
|
|
17127
|
-
type="button"
|
|
17128
|
-
aria-label=${this.collapsed ? `Expand panel` : `Collapse panel`}
|
|
17129
|
-
@click=${this._onToggleClick}
|
|
17130
|
-
>
|
|
17131
|
-
<ixfx-icon name=${caretIcon} prominence .rotate=${caretRotation.length > 0 ? caretRotation : A}></ixfx-icon>
|
|
17132
|
-
</button>
|
|
17133
|
-
` : A}
|
|
17134
|
-
</div>
|
|
17135
|
-
</div>
|
|
17136
|
-
`;
|
|
17137
|
-
}
|
|
17138
|
-
static {
|
|
17139
|
-
this.styles = [themeFallbacks, i$3`
|
|
17140
|
-
:host {
|
|
17141
|
-
display: block;
|
|
17142
|
-
box-sizing: border-box;
|
|
17143
|
-
}
|
|
17144
|
-
|
|
17145
|
-
.bar {
|
|
17146
|
-
display: flex;
|
|
17147
|
-
flex-direction: row;
|
|
17148
|
-
align-items: center;
|
|
17149
|
-
padding: var(--space-s) var(--space-m);
|
|
17150
|
-
background: var(--surface-4);
|
|
17151
|
-
color: var(--surface-3-text);
|
|
17152
|
-
min-height: 2em;
|
|
17153
|
-
height: 100%;
|
|
17154
|
-
flex-shrink: 0;
|
|
17155
|
-
box-sizing: border-box;
|
|
17156
|
-
}
|
|
17157
|
-
|
|
17158
|
-
:host([orientation="vertical"]) .bar {
|
|
17159
|
-
flex-direction: row;
|
|
17160
|
-
min-width: 2em;
|
|
17161
|
-
writing-mode: vertical-rl;
|
|
17162
|
-
text-orientation: mixed;
|
|
17163
|
-
}
|
|
17164
|
-
|
|
17165
|
-
.caret-btn,
|
|
17166
|
-
.close-btn {
|
|
17167
|
-
display: inline-flex;
|
|
17168
|
-
align-items: center;
|
|
17169
|
-
justify-content: center;
|
|
17170
|
-
background: none;
|
|
17171
|
-
border: none;
|
|
17172
|
-
padding: var(--space-xs);
|
|
17173
|
-
margin: 0;
|
|
17174
|
-
cursor: pointer;
|
|
17175
|
-
color: inherit;
|
|
17176
|
-
border-radius: var(--radius-s);
|
|
17177
|
-
transition: background var(--transition);
|
|
17178
|
-
opacity: var(--prominence-idle-opacity);
|
|
17179
|
-
}
|
|
17180
|
-
|
|
17181
|
-
.caret-btn:hover,
|
|
17182
|
-
.close-btn:hover {
|
|
17183
|
-
background: var(--surface-5);
|
|
17184
|
-
opacity: var(--prominence-tickled-opacity);
|
|
17185
|
-
}
|
|
17186
|
-
|
|
17187
|
-
.caret-btn:focus-visible,
|
|
17188
|
-
.close-btn:focus-visible {
|
|
17189
|
-
outline: 2px solid var(--accent);
|
|
17190
|
-
outline-offset: 1px;
|
|
17191
|
-
}
|
|
17192
|
-
|
|
17193
|
-
ixfx-icon {
|
|
17194
|
-
width: 1.25em;
|
|
17195
|
-
height: 1.25em;
|
|
17196
|
-
transition: transform var(--transition);
|
|
17197
|
-
}
|
|
17198
|
-
|
|
17199
|
-
.title-icon {
|
|
17200
|
-
flex-shrink: 0;
|
|
17201
|
-
}
|
|
17202
|
-
|
|
17203
|
-
.title-text {
|
|
17204
|
-
flex: 1;
|
|
17205
|
-
padding-left: 1ch;
|
|
17206
|
-
font-family: var(--font-family);
|
|
17207
|
-
font-size: var(--text-m);
|
|
17208
|
-
font-weight: var(--font-weight-bold, 600);
|
|
17209
|
-
white-space: nowrap;
|
|
17210
|
-
overflow: hidden;
|
|
17211
|
-
align-self: center;
|
|
17212
|
-
text-overflow: ellipsis;
|
|
17213
|
-
user-select: none;
|
|
17214
|
-
-webkit-user-select: none;
|
|
17215
|
-
}
|
|
17216
|
-
|
|
17217
|
-
:host([collapsible][toggle-interaction="implicit"]) .bar {
|
|
17218
|
-
cursor: pointer;
|
|
17219
|
-
}
|
|
17220
|
-
|
|
17221
|
-
:host([orientation="vertical"]) .title-text {
|
|
17222
|
-
writing-mode: vertical-rl;
|
|
17223
|
-
padding-left: 0;
|
|
17224
|
-
padding-bottom: 1ch;
|
|
17225
|
-
text-orientation: mixed;
|
|
17226
|
-
transform: rotate(180deg);
|
|
17227
|
-
}
|
|
17228
|
-
|
|
17229
|
-
.toolbar {
|
|
17230
|
-
display: flex;
|
|
17231
|
-
align-items: center;
|
|
17232
|
-
gap: var(--space-xs);
|
|
17233
|
-
margin-left: auto;
|
|
17234
|
-
}
|
|
17235
|
-
|
|
17236
|
-
:host([orientation="vertical"]) .toolbar {
|
|
17237
|
-
flex-direction: column;
|
|
17238
|
-
margin-left: 0;
|
|
17239
|
-
margin-top: auto;
|
|
17240
|
-
writing-mode: horizontal-tb;
|
|
17241
|
-
}
|
|
17242
|
-
|
|
17243
|
-
slot[name="toolbar"] {
|
|
17244
|
-
display: contents;
|
|
17245
|
-
}
|
|
17246
|
-
|
|
17247
|
-
::slotted(slot[name="toolbar"]) {
|
|
17248
|
-
display: contents;
|
|
17249
|
-
}
|
|
17250
|
-
|
|
17251
|
-
.title-text-wrapper {
|
|
17252
|
-
display: flex;
|
|
17253
|
-
padding: 0 var(--space-s);
|
|
17254
|
-
}
|
|
17255
|
-
|
|
17256
|
-
/* === Midline variant === */
|
|
17257
|
-
|
|
17258
|
-
:host([variant="midline"]) .bar {
|
|
17259
|
-
background: transparent;
|
|
17260
|
-
padding: var(--space-xs) var(--space-m);
|
|
17261
|
-
min-height: unset;
|
|
17262
|
-
position: relative;
|
|
17263
|
-
}
|
|
17264
|
-
|
|
17265
|
-
:host([variant="midline"][orientation="vertical"]) .bar {
|
|
17266
|
-
padding: var(--space-m) var(--space-xs);
|
|
17267
|
-
min-width: unset;
|
|
17268
|
-
}
|
|
17269
|
-
|
|
17270
|
-
:host([variant="midline"]) .title-text-wrapper {
|
|
17271
|
-
position: relative;
|
|
17272
|
-
z-index: 1;
|
|
17273
|
-
display: flex;
|
|
17274
|
-
align-items: center;
|
|
17275
|
-
gap: var(--space-s);
|
|
17276
|
-
background: var(--surface-3);
|
|
17277
|
-
}
|
|
17278
|
-
|
|
17279
|
-
:host([variant="midline"]) .title-text {
|
|
17280
|
-
font-weight: normal;
|
|
17281
|
-
color: var(--surface-3-text);
|
|
17282
|
-
padding: 0 0.5ch 0 0.5ch;
|
|
17283
|
-
background: transparent;
|
|
17284
|
-
box-shadow: none;
|
|
17285
|
-
flex: unset;
|
|
17286
|
-
width: auto;
|
|
17287
|
-
white-space: nowrap;
|
|
17288
|
-
}
|
|
18334
|
+
*/
|
|
18335
|
+
_syncLabelSizer() {
|
|
18336
|
+
const slot = this.shadowRoot?.querySelector(`slot:not([name])`);
|
|
18337
|
+
const label = this.shadowRoot?.querySelector(`.label`);
|
|
18338
|
+
if (slot === null || slot === void 0 || label === null || label === void 0) return;
|
|
18339
|
+
const text = slot.assignedNodes().filter((node) => !(node instanceof HTMLElement && node.hasAttribute(`slot`))).map((node) => node.textContent ?? ``).join(``);
|
|
18340
|
+
if (text) label.setAttribute(`data-label`, text);
|
|
18341
|
+
else label.removeAttribute(`data-label`);
|
|
18342
|
+
}
|
|
18343
|
+
_updateToolbarContent() {
|
|
18344
|
+
const slot = this.shadowRoot?.querySelector(`slot[name="toolbar"]`);
|
|
18345
|
+
this._hasToolbarContent = (slot?.assignedElements().length ?? 0) > 0;
|
|
18346
|
+
}
|
|
18347
|
+
firstUpdated() {
|
|
18348
|
+
this._updateToolbarContent();
|
|
18349
|
+
this._syncLabelSizer();
|
|
18350
|
+
}
|
|
18351
|
+
render() {
|
|
18352
|
+
const showLabel = !this.hideLabels || !this.iconName;
|
|
18353
|
+
const hasActions = this.closeable || this._hasToolbarContent;
|
|
18354
|
+
return b`
|
|
18355
|
+
<div>
|
|
18356
|
+
${this.iconName ? b`<ixfx-icon name="${this.iconName}"></ixfx-icon>` : A}
|
|
18357
|
+
${showLabel ? b`<span class="label"><slot></slot></span>` : A}
|
|
18358
|
+
${hasActions ? b`
|
|
18359
|
+
<div class="actions">
|
|
18360
|
+
<div class="toolbar"><slot name="toolbar"></slot></div>
|
|
18361
|
+
${this.closeable ? b`
|
|
18362
|
+
<button
|
|
18363
|
+
class="close-btn"
|
|
18364
|
+
type="button"
|
|
18365
|
+
aria-label="Close tab"
|
|
18366
|
+
@click=${this._onCloseClick}
|
|
18367
|
+
>
|
|
18368
|
+
<ixfx-icon name="close"></ixfx-icon>
|
|
18369
|
+
</button>
|
|
18370
|
+
` : A}
|
|
18371
|
+
</div>
|
|
18372
|
+
` : A}
|
|
18373
|
+
</div>
|
|
18374
|
+
`;
|
|
18375
|
+
}
|
|
18376
|
+
_onCloseClick(e) {
|
|
18377
|
+
e.stopPropagation();
|
|
18378
|
+
this.dispatchEvent(new CustomEvent(`close`, {
|
|
18379
|
+
bubbles: true,
|
|
18380
|
+
composed: true
|
|
18381
|
+
}));
|
|
18382
|
+
this.remove();
|
|
18383
|
+
}
|
|
18384
|
+
static {
|
|
18385
|
+
this.styles = [
|
|
18386
|
+
themeFallbacks,
|
|
18387
|
+
prominenceStyles,
|
|
18388
|
+
i$3`
|
|
18389
|
+
:host {
|
|
18390
|
+
--selected-tab-color: var(--ixfx-selected-tab-color, var(--surface-2-text));
|
|
18391
|
+
--selected-tab-icon-color: var(--ixfx-selected-tab-icon-color, var(--accent));
|
|
18392
|
+
--selected-tab-border-width: var(--ixfx-selected-tab-border-width, 1px);
|
|
18393
|
+
--selected-tab-weight: var(--ixfx-selected-tab-weight, bold);
|
|
18394
|
+
--selected-tab-text-decoration: var(--ixfx-selected-tab-text-decoration, none);
|
|
18395
|
+
--selected-tab-text-decoration-color: var(--ixfx-selected-tab-text-decoration-color, var(--accent));
|
|
18396
|
+
--selected-tab-text-decoration-thickness: var(--ixfx-selected-tab-text-decoration-thickness, 0px);
|
|
18397
|
+
--selected-tab-text-decoration-offset: var(--ixfx-selected-tab-text-decoration-offset, 2px);
|
|
18398
|
+
--selected-background: var(--ixfx-tab-selected-background, var(--surface-5));
|
|
18399
|
+
--tab-padding: var(--ixfx-tab-padding, var(--space-s));
|
|
18400
|
+
display: inline-flex;
|
|
18401
|
+
min-width: 0;
|
|
18402
|
+
user-select: none;
|
|
18403
|
+
box-sizing: border-box;
|
|
18404
|
+
font-size: var(--text-m);
|
|
18405
|
+
color: inherit;
|
|
18406
|
+
/* No explicit height: items stretch (align-self: stretch via the
|
|
18407
|
+
list's flex container) so every tab in a strip shares one height
|
|
18408
|
+
even when toolbars give some items taller content. */
|
|
18409
|
+
}
|
|
17289
18410
|
|
|
17290
|
-
|
|
17291
|
-
|
|
17292
|
-
|
|
17293
|
-
|
|
18411
|
+
:host > div {
|
|
18412
|
+
display: flex;
|
|
18413
|
+
align-items: center;
|
|
18414
|
+
padding: var(--tab-padding) calc(2 * var(--tab-padding-horizontal, var(--tab-padding)));
|
|
18415
|
+
min-width: 0;
|
|
18416
|
+
width: 100%;
|
|
18417
|
+
font-weight: 500;
|
|
18418
|
+
border: var(--selected-tab-border-width) solid transparent;
|
|
18419
|
+
gap: var(--space-s);
|
|
18420
|
+
transition: background var(--transition, 0.15s);
|
|
18421
|
+
}
|
|
17294
18422
|
|
|
17295
|
-
|
|
17296
|
-
|
|
17297
|
-
|
|
17298
|
-
|
|
17299
|
-
|
|
17300
|
-
|
|
18423
|
+
/* Hover ("tickle") background. When --ixfx-tab-hover-background is
|
|
18424
|
+
unset each state keeps its resting background, so existing
|
|
18425
|
+
consumers see no change. */
|
|
18426
|
+
:host(:hover:not([selected])) > div {
|
|
18427
|
+
background: var(--ixfx-tab-hover-background, transparent);
|
|
18428
|
+
}
|
|
17301
18429
|
|
|
17302
|
-
|
|
17303
|
-
|
|
17304
|
-
|
|
17305
|
-
}
|
|
18430
|
+
:host([selected]:hover) > div {
|
|
18431
|
+
background: var(--ixfx-tab-hover-background, var(--selected-background));
|
|
18432
|
+
}
|
|
17306
18433
|
|
|
17307
|
-
|
|
17308
|
-
|
|
17309
|
-
|
|
17310
|
-
|
|
17311
|
-
|
|
17312
|
-
|
|
18434
|
+
:host([selected]) > div {
|
|
18435
|
+
color: var(--selected-tab-color);
|
|
18436
|
+
border-top-color: var(--indicator-color-top, transparent);
|
|
18437
|
+
border-bottom-color: var(--indicator-color-bottom, transparent);
|
|
18438
|
+
border-left-color: var(--indicator-color-left, transparent);
|
|
18439
|
+
border-right-color: var(--indicator-color-right, transparent);
|
|
18440
|
+
background: var(--selected-background);
|
|
18441
|
+
font-weight: var(--selected-tab-weight);
|
|
18442
|
+
border-radius:var(--radius-m);
|
|
18443
|
+
}
|
|
17313
18444
|
|
|
17314
|
-
|
|
17315
|
-
|
|
17316
|
-
|
|
18445
|
+
:host([selected]) .label {
|
|
18446
|
+
text-decoration: var(--selected-tab-text-decoration);
|
|
18447
|
+
text-decoration-color: var(--selected-tab-text-decoration-color);
|
|
18448
|
+
text-decoration-thickness: var(--selected-tab-text-decoration-thickness);
|
|
18449
|
+
text-decoration-offset: var(--selected-tab-text-decoration-offset);
|
|
18450
|
+
}
|
|
17317
18451
|
|
|
17318
|
-
|
|
17319
|
-
|
|
17320
|
-
|
|
17321
|
-
|
|
17322
|
-
|
|
17323
|
-
|
|
17324
|
-
|
|
17325
|
-
height: 1px;
|
|
17326
|
-
transform: translateY(-50%);
|
|
17327
|
-
background: var(--surface-2);
|
|
17328
|
-
box-shadow:
|
|
17329
|
-
0 -1px 0 var(--surface-5),
|
|
17330
|
-
0 1px 0 var(--surface-1);
|
|
17331
|
-
z-index: 0;
|
|
17332
|
-
}
|
|
18452
|
+
.label {
|
|
18453
|
+
overflow: var(--allow-overflow, hidden);
|
|
18454
|
+
text-overflow: ellipsis;
|
|
18455
|
+
white-space: nowrap;
|
|
18456
|
+
min-width: 0;
|
|
18457
|
+
flex: 1 1 auto;
|
|
18458
|
+
}
|
|
17333
18459
|
|
|
17334
|
-
|
|
17335
|
-
|
|
17336
|
-
|
|
17337
|
-
|
|
17338
|
-
|
|
17339
|
-
|
|
17340
|
-
|
|
17341
|
-
|
|
17342
|
-
|
|
17343
|
-
|
|
17344
|
-
-
|
|
17345
|
-
|
|
17346
|
-
}
|
|
18460
|
+
/* Width sizer: an invisible copy of the label, always set at the
|
|
18461
|
+
selected weight, so activating a tab (bold) never shifts the strip.
|
|
18462
|
+
Text is mirrored from the default slot via the data-label attribute
|
|
18463
|
+
(see _syncLabelSizer). */
|
|
18464
|
+
.label::after {
|
|
18465
|
+
content: attr(data-label);
|
|
18466
|
+
display: block;
|
|
18467
|
+
height: 0;
|
|
18468
|
+
overflow: hidden;
|
|
18469
|
+
visibility: hidden;
|
|
18470
|
+
font-weight: var(--selected-tab-weight);
|
|
18471
|
+
}
|
|
17347
18472
|
|
|
17348
|
-
|
|
17349
|
-
|
|
17350
|
-
|
|
17351
|
-
padding: 0 var(--space-xs);
|
|
17352
|
-
min-height: unset;
|
|
17353
|
-
gap: var(--space-xs);
|
|
17354
|
-
}
|
|
18473
|
+
ixfx-icon {
|
|
18474
|
+
flex-shrink: 0;
|
|
18475
|
+
}
|
|
17355
18476
|
|
|
17356
|
-
|
|
17357
|
-
|
|
17358
|
-
|
|
17359
|
-
|
|
17360
|
-
|
|
17361
|
-
}
|
|
18477
|
+
/* Leading icon (direct child — not close/toolbar icons) picks up the
|
|
18478
|
+
accent when selected, so icon-only tabs read as active. */
|
|
18479
|
+
:host([selected]) > div > ixfx-icon {
|
|
18480
|
+
color: var(--selected-tab-icon-color);
|
|
18481
|
+
}
|
|
17362
18482
|
|
|
17363
|
-
|
|
17364
|
-
|
|
17365
|
-
|
|
17366
|
-
|
|
17367
|
-
|
|
17368
|
-
|
|
17369
|
-
|
|
18483
|
+
.actions {
|
|
18484
|
+
display: flex;
|
|
18485
|
+
align-items: center;
|
|
18486
|
+
gap: var(--space-xs);
|
|
18487
|
+
margin-left: auto;
|
|
18488
|
+
flex-shrink: 0;
|
|
18489
|
+
}
|
|
17370
18490
|
|
|
17371
|
-
|
|
17372
|
-
|
|
17373
|
-
|
|
17374
|
-
|
|
18491
|
+
.toolbar {
|
|
18492
|
+
/* Always laid out (display: flex) so the tab's width doesn't shift when
|
|
18493
|
+
the toolbar appears on selection. visibility: hidden keeps the
|
|
18494
|
+
toolbar from receiving pointer events or painting, while preserving
|
|
18495
|
+
the space its contents take up. */
|
|
18496
|
+
display: flex;
|
|
18497
|
+
align-items: center;
|
|
18498
|
+
gap: var(--space-xs);
|
|
18499
|
+
visibility: hidden;
|
|
18500
|
+
}
|
|
17375
18501
|
|
|
17376
|
-
|
|
17377
|
-
|
|
17378
|
-
|
|
17379
|
-
padding: 0;
|
|
17380
|
-
background: transparent;
|
|
17381
|
-
box-shadow: none;
|
|
17382
|
-
flex: unset;
|
|
17383
|
-
width: auto;
|
|
17384
|
-
white-space: nowrap;
|
|
17385
|
-
}
|
|
18502
|
+
:host([selected]) .toolbar {
|
|
18503
|
+
visibility: visible;
|
|
18504
|
+
}
|
|
17386
18505
|
|
|
17387
|
-
|
|
17388
|
-
|
|
17389
|
-
|
|
17390
|
-
padding: 0;
|
|
17391
|
-
}
|
|
18506
|
+
slot[name="toolbar"] {
|
|
18507
|
+
display: contents;
|
|
18508
|
+
}
|
|
17392
18509
|
|
|
17393
|
-
|
|
17394
|
-
|
|
17395
|
-
|
|
17396
|
-
|
|
17397
|
-
|
|
18510
|
+
/* Slotted buttons inherit these through the shadow boundary; keeps a
|
|
18511
|
+
toolbar button from inflating the strip height. */
|
|
18512
|
+
.toolbar ::slotted(ixfx-button) {
|
|
18513
|
+
--ixfx-button-padding-block: var(--space-xs);
|
|
18514
|
+
}
|
|
17398
18515
|
|
|
17399
|
-
|
|
17400
|
-
|
|
17401
|
-
|
|
17402
|
-
|
|
18516
|
+
.close-btn {
|
|
18517
|
+
display: inline-flex;
|
|
18518
|
+
align-items: center;
|
|
18519
|
+
justify-content: center;
|
|
18520
|
+
background: none;
|
|
18521
|
+
border: none;
|
|
18522
|
+
padding: var(--space-xs);
|
|
18523
|
+
cursor: pointer;
|
|
18524
|
+
color: inherit;
|
|
18525
|
+
border-radius: var(--radius-s);
|
|
18526
|
+
opacity: var(--prominence-idle-opacity);
|
|
18527
|
+
transition: opacity var(--transition), background var(--transition);
|
|
18528
|
+
}
|
|
17403
18529
|
|
|
17404
|
-
|
|
17405
|
-
|
|
17406
|
-
|
|
18530
|
+
.close-btn:hover {
|
|
18531
|
+
background: var(--surface-5);
|
|
18532
|
+
opacity: var(--prominence-tickled-opacity);
|
|
18533
|
+
}
|
|
17407
18534
|
|
|
17408
|
-
|
|
17409
|
-
|
|
17410
|
-
|
|
17411
|
-
|
|
17412
|
-
}
|
|
18535
|
+
.close-btn:focus-visible {
|
|
18536
|
+
outline: 2px solid var(--accent);
|
|
18537
|
+
outline-offset: 1px;
|
|
18538
|
+
}
|
|
17413
18539
|
|
|
17414
|
-
|
|
17415
|
-
|
|
17416
|
-
|
|
17417
|
-
|
|
17418
|
-
|
|
18540
|
+
:host([selected]) .close-btn,
|
|
18541
|
+
:host(:hover) .close-btn {
|
|
18542
|
+
opacity: var(--prominence-tickled-opacity);
|
|
18543
|
+
}
|
|
18544
|
+
`
|
|
18545
|
+
];
|
|
17419
18546
|
}
|
|
17420
18547
|
};
|
|
17421
|
-
__decorate([property({ type:
|
|
17422
|
-
__decorate([property({
|
|
17423
|
-
type: String,
|
|
17424
|
-
attribute: `icon-name`
|
|
17425
|
-
})], TitlebarElement.prototype, "iconName", void 0);
|
|
17426
|
-
__decorate([property({
|
|
17427
|
-
type: String,
|
|
17428
|
-
attribute: `orientation`,
|
|
17429
|
-
reflect: true
|
|
17430
|
-
})], TitlebarElement.prototype, "orientation", void 0);
|
|
17431
|
-
__decorate([property({
|
|
17432
|
-
type: String,
|
|
17433
|
-
attribute: `variant`,
|
|
17434
|
-
reflect: true
|
|
17435
|
-
})], TitlebarElement.prototype, "variant", void 0);
|
|
17436
|
-
__decorate([property({ type: Boolean })], TitlebarElement.prototype, "closable", void 0);
|
|
18548
|
+
__decorate([property({ type: Boolean })], TabListItemElement.prototype, "closeable", void 0);
|
|
17437
18549
|
__decorate([property({
|
|
17438
18550
|
type: Boolean,
|
|
17439
|
-
|
|
17440
|
-
})],
|
|
18551
|
+
attribute: `hide-labels`
|
|
18552
|
+
})], TabListItemElement.prototype, "hideLabels", void 0);
|
|
17441
18553
|
__decorate([property({
|
|
17442
|
-
type:
|
|
17443
|
-
|
|
17444
|
-
})],
|
|
18554
|
+
type: String,
|
|
18555
|
+
attribute: `icon-name`
|
|
18556
|
+
})], TabListItemElement.prototype, "iconName", void 0);
|
|
18557
|
+
__decorate([property({ type: String })], TabListItemElement.prototype, "description", void 0);
|
|
17445
18558
|
__decorate([property({
|
|
17446
18559
|
type: String,
|
|
17447
|
-
attribute: `
|
|
17448
|
-
})],
|
|
17449
|
-
|
|
18560
|
+
attribute: `command-active`
|
|
18561
|
+
})], TabListItemElement.prototype, "commandActive", void 0);
|
|
18562
|
+
__decorate([property({ attribute: false })], TabListItemElement.prototype, "registry", void 0);
|
|
18563
|
+
__decorate([state()], TabListItemElement.prototype, "_compact", void 0);
|
|
18564
|
+
__decorate([state()], TabListItemElement.prototype, "_hasToolbarContent", void 0);
|
|
18565
|
+
TabListItemElement = __decorate([safeCustomElement(`ixfx-tab-list-item`)], TabListItemElement);
|
|
17450
18566
|
//#endregion
|
|
17451
18567
|
//#region src/dock/dock-panel.ts
|
|
17452
18568
|
/** Pointer movement threshold before a titlebar press becomes a dock drag. */
|
|
@@ -18687,7 +19803,7 @@ let DockHostElement = class DockHostElement extends i {
|
|
|
18687
19803
|
role="separator"
|
|
18688
19804
|
aria-label="Resize adjacent panels"
|
|
18689
19805
|
@pointerdown=${(e) => this._onJunctionPointerDown(e, junction)}
|
|
18690
|
-
></div>
|
|
19806
|
+
><span class="ixfx-handle" data-handle="dotted" data-shape="spot" part="junction-handle"></span></div>
|
|
18691
19807
|
`)}
|
|
18692
19808
|
</div>
|
|
18693
19809
|
<slot @slotchange=${this._onPoolSlotChange}></slot>
|
|
@@ -18781,7 +19897,10 @@ let DockHostElement = class DockHostElement extends i {
|
|
|
18781
19897
|
};
|
|
18782
19898
|
}
|
|
18783
19899
|
static {
|
|
18784
|
-
this.styles = [
|
|
19900
|
+
this.styles = [
|
|
19901
|
+
themeFallbacks,
|
|
19902
|
+
handleStyles,
|
|
19903
|
+
i$3`
|
|
18785
19904
|
:host {
|
|
18786
19905
|
display: block;
|
|
18787
19906
|
width: 100%;
|
|
@@ -18909,26 +20028,23 @@ let DockHostElement = class DockHostElement extends i {
|
|
|
18909
20028
|
border-radius: 50%;
|
|
18910
20029
|
cursor: nwse-resize;
|
|
18911
20030
|
pointer-events: auto;
|
|
20031
|
+
display: flex;
|
|
20032
|
+
align-items: center;
|
|
20033
|
+
justify-content: center;
|
|
18912
20034
|
}
|
|
18913
20035
|
|
|
18914
|
-
.junction-handle
|
|
18915
|
-
|
|
18916
|
-
|
|
18917
|
-
|
|
18918
|
-
|
|
18919
|
-
background: var(--dock-junction-color, var(--accent));
|
|
18920
|
-
opacity: 0;
|
|
18921
|
-
transition: opacity var(--transition);
|
|
18922
|
-
}
|
|
18923
|
-
|
|
18924
|
-
.junction-handle:hover::after {
|
|
18925
|
-
opacity: 0.9;
|
|
20036
|
+
.junction-handle .ixfx-handle {
|
|
20037
|
+
--ixfx-handle-spot-size: 12px;
|
|
20038
|
+
--ixfx-handle-dot-size: 3px;
|
|
20039
|
+
--ixfx-handle-opacity: 0;
|
|
20040
|
+
--ixfx-handle-opacity-active: 0.9;
|
|
18926
20041
|
}
|
|
18927
20042
|
|
|
18928
20043
|
slot:not([name]) {
|
|
18929
20044
|
display: none;
|
|
18930
20045
|
}
|
|
18931
|
-
`
|
|
20046
|
+
`
|
|
20047
|
+
];
|
|
18932
20048
|
}
|
|
18933
20049
|
};
|
|
18934
20050
|
__decorate([property({
|
|
@@ -20398,6 +21514,233 @@ var DataGridListSource = class {
|
|
|
20398
21514
|
}
|
|
20399
21515
|
};
|
|
20400
21516
|
//#endregion
|
|
21517
|
+
//#region src/pan-text/pan-text.ts
|
|
21518
|
+
const SPEED = 45;
|
|
21519
|
+
const END_PADDING = 4;
|
|
21520
|
+
const START_DELAY = 300;
|
|
21521
|
+
const END_DWELL = 2e3;
|
|
21522
|
+
const RESET_DURATION = 400;
|
|
21523
|
+
const PAN_EASING = `cubic-bezier(0.25, 0.46, 0.45, 0.94)`;
|
|
21524
|
+
let PanTextElement = class PanTextElement extends i {
|
|
21525
|
+
constructor(..._args) {
|
|
21526
|
+
super(..._args);
|
|
21527
|
+
this.direction = `end`;
|
|
21528
|
+
this.disabled = false;
|
|
21529
|
+
this.mode = `hover`;
|
|
21530
|
+
this._isOverflowing = false;
|
|
21531
|
+
this._isHovering = false;
|
|
21532
|
+
this._loopActive = false;
|
|
21533
|
+
this._loopAtEnd = false;
|
|
21534
|
+
this._overflow = 0;
|
|
21535
|
+
this._resizeObserver = null;
|
|
21536
|
+
this._loopTimer = 0;
|
|
21537
|
+
this._onMouseEnter = () => {
|
|
21538
|
+
this._isHovering = true;
|
|
21539
|
+
};
|
|
21540
|
+
this._onMouseLeave = () => {
|
|
21541
|
+
this._isHovering = false;
|
|
21542
|
+
};
|
|
21543
|
+
this._measure = () => {
|
|
21544
|
+
if (this._isHovering || this._loopAtEnd) return;
|
|
21545
|
+
const el = this._textEl;
|
|
21546
|
+
if (!el) return;
|
|
21547
|
+
this._overflow = Math.max(0, el.scrollWidth - el.clientWidth);
|
|
21548
|
+
const overflowing = this._overflow > 0;
|
|
21549
|
+
this.classList.toggle(`is-overflowing`, overflowing);
|
|
21550
|
+
if (overflowing !== this._isOverflowing) this._isOverflowing = overflowing;
|
|
21551
|
+
if (this._loopActive && this.mode === `loop` && !this.disabled && overflowing && this._loopTimer === 0) this._scheduleLoopPan(START_DELAY);
|
|
21552
|
+
if (!overflowing && this._loopAtEnd) {
|
|
21553
|
+
this._loopAtEnd = false;
|
|
21554
|
+
this.requestUpdate();
|
|
21555
|
+
}
|
|
21556
|
+
};
|
|
21557
|
+
}
|
|
21558
|
+
connectedCallback() {
|
|
21559
|
+
super.connectedCallback();
|
|
21560
|
+
this._resizeObserver = new ResizeObserver(() => this._measure());
|
|
21561
|
+
this.addEventListener(`mouseenter`, this._onMouseEnter);
|
|
21562
|
+
this.addEventListener(`mouseleave`, this._onMouseLeave);
|
|
21563
|
+
}
|
|
21564
|
+
disconnectedCallback() {
|
|
21565
|
+
super.disconnectedCallback();
|
|
21566
|
+
this._clearLoopTimer();
|
|
21567
|
+
this._loopActive = false;
|
|
21568
|
+
this._loopAtEnd = false;
|
|
21569
|
+
this._resizeObserver?.disconnect();
|
|
21570
|
+
this._resizeObserver = null;
|
|
21571
|
+
this.removeEventListener(`mouseenter`, this._onMouseEnter);
|
|
21572
|
+
this.removeEventListener(`mouseleave`, this._onMouseLeave);
|
|
21573
|
+
}
|
|
21574
|
+
firstUpdated() {
|
|
21575
|
+
this._measure();
|
|
21576
|
+
this._resizeObserver?.observe(this);
|
|
21577
|
+
document.fonts?.ready.then(() => this._measure());
|
|
21578
|
+
if (this.mode === `loop`) this.startLoop();
|
|
21579
|
+
}
|
|
21580
|
+
updated(changed) {
|
|
21581
|
+
if (changed.has(`mode`)) {
|
|
21582
|
+
if (this.mode === `loop`) this.startLoop();
|
|
21583
|
+
else this.stopLoop();
|
|
21584
|
+
}
|
|
21585
|
+
if (changed.has(`disabled`) && this.disabled) this.stopLoop();
|
|
21586
|
+
this._measure();
|
|
21587
|
+
}
|
|
21588
|
+
/**
|
|
21589
|
+
* Whether a loop pan is currently active (between `startLoop()` and `stopLoop()`).
|
|
21590
|
+
*/
|
|
21591
|
+
get looping() {
|
|
21592
|
+
return this._loopActive;
|
|
21593
|
+
}
|
|
21594
|
+
/**
|
|
21595
|
+
* Begin looping: pan to the end, dwell there for 2 seconds, reset to the
|
|
21596
|
+
* start and pan again, repeating until `stopLoop()` is called. A no-op when
|
|
21597
|
+
* `disabled`, when there is nothing to reveal, or under reduced-motion.
|
|
21598
|
+
*/
|
|
21599
|
+
startLoop() {
|
|
21600
|
+
if (this.disabled || this._prefersReducedMotion()) return;
|
|
21601
|
+
this._loopActive = true;
|
|
21602
|
+
this._loopAtEnd = false;
|
|
21603
|
+
this.requestUpdate();
|
|
21604
|
+
if (this._isOverflowing && this._loopTimer === 0) this._scheduleLoopPan(START_DELAY);
|
|
21605
|
+
}
|
|
21606
|
+
/**
|
|
21607
|
+
* Stop a loop started with `startLoop()` and snap back to the rest position.
|
|
21608
|
+
*/
|
|
21609
|
+
stopLoop() {
|
|
21610
|
+
if (!this._loopActive && !this._loopAtEnd && this._loopTimer === 0) return;
|
|
21611
|
+
this._clearLoopTimer();
|
|
21612
|
+
this._loopActive = false;
|
|
21613
|
+
this._loopAtEnd = false;
|
|
21614
|
+
this.requestUpdate();
|
|
21615
|
+
}
|
|
21616
|
+
_prefersReducedMotion() {
|
|
21617
|
+
return globalThis.matchMedia?.(`(prefers-reduced-motion: reduce)`).matches ?? false;
|
|
21618
|
+
}
|
|
21619
|
+
_panDuration() {
|
|
21620
|
+
return Math.max(1.5, (this._overflow + END_PADDING) / SPEED);
|
|
21621
|
+
}
|
|
21622
|
+
_clearLoopTimer() {
|
|
21623
|
+
if (this._loopTimer !== 0) {
|
|
21624
|
+
clearTimeout(this._loopTimer);
|
|
21625
|
+
this._loopTimer = 0;
|
|
21626
|
+
}
|
|
21627
|
+
}
|
|
21628
|
+
_scheduleLoopPan(delay) {
|
|
21629
|
+
this._clearLoopTimer();
|
|
21630
|
+
this._loopTimer = window.setTimeout(() => {
|
|
21631
|
+
this._loopTimer = 0;
|
|
21632
|
+
if (!this._loopActive || this.disabled || !this._isOverflowing) return;
|
|
21633
|
+
this._loopAtEnd = true;
|
|
21634
|
+
this.requestUpdate();
|
|
21635
|
+
const dwell = this._panDuration() * 1e3 + END_DWELL;
|
|
21636
|
+
this._loopTimer = window.setTimeout(() => {
|
|
21637
|
+
this._loopTimer = 0;
|
|
21638
|
+
if (!this._loopActive) return;
|
|
21639
|
+
this._loopAtEnd = false;
|
|
21640
|
+
this.requestUpdate();
|
|
21641
|
+
this._scheduleLoopPan(700);
|
|
21642
|
+
}, dwell);
|
|
21643
|
+
}, delay);
|
|
21644
|
+
}
|
|
21645
|
+
_textStyle() {
|
|
21646
|
+
if (!this._isOverflowing) return ``;
|
|
21647
|
+
const distance = this._overflow + END_PADDING;
|
|
21648
|
+
const duration = Math.max(1.5, distance / SPEED);
|
|
21649
|
+
const revealEnd = this.direction === `end`;
|
|
21650
|
+
const restX = revealEnd ? 0 : -distance;
|
|
21651
|
+
const hoverX = revealEnd ? -distance : 0;
|
|
21652
|
+
if (this._loopActive && this.mode === `loop`) {
|
|
21653
|
+
if (this._loopAtEnd) return [
|
|
21654
|
+
`transform: translateX(${hoverX}px)`,
|
|
21655
|
+
`transition: transform ${duration}s ${PAN_EASING}`,
|
|
21656
|
+
`overflow: visible`,
|
|
21657
|
+
`text-overflow: clip`
|
|
21658
|
+
].join(`; `);
|
|
21659
|
+
return [
|
|
21660
|
+
`transform: translateX(${restX}px)`,
|
|
21661
|
+
`transition: transform ${RESET_DURATION}ms ${PAN_EASING}`,
|
|
21662
|
+
revealEnd ? `` : `overflow: visible; text-overflow: clip`
|
|
21663
|
+
].filter(Boolean).join(`; `);
|
|
21664
|
+
}
|
|
21665
|
+
if (this._isHovering) return [
|
|
21666
|
+
`transform: translateX(${hoverX}px)`,
|
|
21667
|
+
`transition: transform ${duration}s ${PAN_EASING} ${START_DELAY}ms`,
|
|
21668
|
+
`overflow: visible`,
|
|
21669
|
+
`text-overflow: clip`
|
|
21670
|
+
].join(`; `);
|
|
21671
|
+
return [
|
|
21672
|
+
`transform: translateX(${restX}px)`,
|
|
21673
|
+
`transition: transform 400ms ${PAN_EASING}`,
|
|
21674
|
+
revealEnd ? `` : `overflow: visible; text-overflow: clip`
|
|
21675
|
+
].filter(Boolean).join(`; `);
|
|
21676
|
+
}
|
|
21677
|
+
render() {
|
|
21678
|
+
const textClasses = {
|
|
21679
|
+
"is-overflowing": this._isOverflowing,
|
|
21680
|
+
"is-hovering": this._isHovering
|
|
21681
|
+
};
|
|
21682
|
+
return b`
|
|
21683
|
+
<span class="text ${classMap(textClasses)}" part="text" style=${this._textStyle()}>
|
|
21684
|
+
<slot @slotchange=${this._measure}></slot>
|
|
21685
|
+
</span>
|
|
21686
|
+
`;
|
|
21687
|
+
}
|
|
21688
|
+
static {
|
|
21689
|
+
this.styles = [themeFallbacks, i$3`
|
|
21690
|
+
/* Renders like plain inline text: no colours, border, padding or margin
|
|
21691
|
+
of its own — it only adds the clipping needed to pan on hover. */
|
|
21692
|
+
:host {
|
|
21693
|
+
display: inline-block;
|
|
21694
|
+
overflow: hidden;
|
|
21695
|
+
white-space: nowrap;
|
|
21696
|
+
max-width: 100%;
|
|
21697
|
+
box-sizing: border-box;
|
|
21698
|
+
font: inherit;
|
|
21699
|
+
color: inherit;
|
|
21700
|
+
}
|
|
21701
|
+
|
|
21702
|
+
:host([disabled]) {
|
|
21703
|
+
opacity: var(--disabled-opacity, 0.5);
|
|
21704
|
+
pointer-events: none;
|
|
21705
|
+
}
|
|
21706
|
+
|
|
21707
|
+
.text {
|
|
21708
|
+
display: block;
|
|
21709
|
+
overflow: hidden;
|
|
21710
|
+
text-overflow: ellipsis;
|
|
21711
|
+
white-space: nowrap;
|
|
21712
|
+
will-change: transform;
|
|
21713
|
+
}
|
|
21714
|
+
|
|
21715
|
+
@media (prefers-reduced-motion: reduce) {
|
|
21716
|
+
.text {
|
|
21717
|
+
transition: none !important;
|
|
21718
|
+
transform: none !important;
|
|
21719
|
+
}
|
|
21720
|
+
}
|
|
21721
|
+
`];
|
|
21722
|
+
}
|
|
21723
|
+
};
|
|
21724
|
+
__decorate([property({
|
|
21725
|
+
type: String,
|
|
21726
|
+
attribute: `direction`
|
|
21727
|
+
})], PanTextElement.prototype, "direction", void 0);
|
|
21728
|
+
__decorate([property({
|
|
21729
|
+
type: Boolean,
|
|
21730
|
+
attribute: `disabled`
|
|
21731
|
+
})], PanTextElement.prototype, "disabled", void 0);
|
|
21732
|
+
__decorate([property({
|
|
21733
|
+
type: String,
|
|
21734
|
+
attribute: `mode`,
|
|
21735
|
+
reflect: true
|
|
21736
|
+
})], PanTextElement.prototype, "mode", void 0);
|
|
21737
|
+
__decorate([state()], PanTextElement.prototype, "_isOverflowing", void 0);
|
|
21738
|
+
__decorate([state()], PanTextElement.prototype, "_isHovering", void 0);
|
|
21739
|
+
__decorate([state()], PanTextElement.prototype, "_loopActive", void 0);
|
|
21740
|
+
__decorate([state()], PanTextElement.prototype, "_loopAtEnd", void 0);
|
|
21741
|
+
__decorate([query(`.text`)], PanTextElement.prototype, "_textEl", void 0);
|
|
21742
|
+
PanTextElement = __decorate([safeCustomElement(`ixfx-pan-text`)], PanTextElement);
|
|
21743
|
+
//#endregion
|
|
20401
21744
|
//#region src/grid-list/grid-list.ts
|
|
20402
21745
|
const ITEM_SELECTOR$1 = `:scope > *`;
|
|
20403
21746
|
const MIN_ITEM_SIZE = 16;
|
|
@@ -20483,6 +21826,7 @@ let GridListElement = class GridListElement extends i {
|
|
|
20483
21826
|
super(..._args);
|
|
20484
21827
|
this.selectionMode = `single`;
|
|
20485
21828
|
this.interactionMode = `standard`;
|
|
21829
|
+
this.disableHoverTickle = false;
|
|
20486
21830
|
this.itemSize = 160;
|
|
20487
21831
|
this.gap = 8;
|
|
20488
21832
|
this.orientation = `grid`;
|
|
@@ -20492,6 +21836,7 @@ let GridListElement = class GridListElement extends i {
|
|
|
20492
21836
|
this.captionBackdrop = `scrim`;
|
|
20493
21837
|
this.captionHeight = 24;
|
|
20494
21838
|
this.itemWrap = `stop`;
|
|
21839
|
+
this.itemsDraggable = false;
|
|
20495
21840
|
this.items = [];
|
|
20496
21841
|
this._scrollTop = 0;
|
|
20497
21842
|
this._scrollLeft = 0;
|
|
@@ -20528,10 +21873,56 @@ let GridListElement = class GridListElement extends i {
|
|
|
20528
21873
|
enabled: this.#source.isSelectable(i)
|
|
20529
21874
|
})),
|
|
20530
21875
|
onTickle: (k) => {
|
|
21876
|
+
this.#stopActiveCaptionPan();
|
|
20531
21877
|
if (k !== void 0) this.#emitItemEvent(`list-tickle`, k);
|
|
20532
21878
|
},
|
|
20533
21879
|
onStateChange: () => this._syncItemStates(),
|
|
20534
|
-
itemWrap: this.#itemWrap
|
|
21880
|
+
itemWrap: this.#itemWrap,
|
|
21881
|
+
hoverDisabled: () => this.disableHoverTickle || this.#dragSelect.isDragging
|
|
21882
|
+
});
|
|
21883
|
+
this.#marqueePreview = /* @__PURE__ */ new Set();
|
|
21884
|
+
this.#nativeDragging = false;
|
|
21885
|
+
this.#dragOriginKey = void 0;
|
|
21886
|
+
this.#postDragSuppressTimer = 0;
|
|
21887
|
+
this.#activeCaptionPan = null;
|
|
21888
|
+
this.#dragSelect = new ListDragSelectController(this, {
|
|
21889
|
+
getSurface: () => this.#viewportRef.value,
|
|
21890
|
+
isEnabled: () => this.selection.canDragSelect() && this.#source.count > 0 && !this.hasAttribute(`disable-drag-select`),
|
|
21891
|
+
hitTest: (rect) => this.#marqueeHitTest(rect),
|
|
21892
|
+
getBaseSelection: () => this.selection.selected,
|
|
21893
|
+
onPreview: (preview, rect) => {
|
|
21894
|
+
this.#marqueePreview = preview;
|
|
21895
|
+
this.#marqueeRect = rect;
|
|
21896
|
+
this.requestUpdate();
|
|
21897
|
+
},
|
|
21898
|
+
onCommit: (finalSet) => {
|
|
21899
|
+
this.selection.applyDragSelection(finalSet);
|
|
21900
|
+
this.#marqueePreview = /* @__PURE__ */ new Set();
|
|
21901
|
+
this.#marqueeRect = void 0;
|
|
21902
|
+
this.requestUpdate();
|
|
21903
|
+
},
|
|
21904
|
+
autoScroll: (dx, dy) => {
|
|
21905
|
+
const vp = this.#viewportRef.value;
|
|
21906
|
+
if (!vp) return;
|
|
21907
|
+
if (dx !== 0) {
|
|
21908
|
+
vp.scrollLeft += dx;
|
|
21909
|
+
this._scrollLeft = vp.scrollLeft;
|
|
21910
|
+
}
|
|
21911
|
+
if (dy !== 0) {
|
|
21912
|
+
vp.scrollTop += dy;
|
|
21913
|
+
this._scrollTop = vp.scrollTop;
|
|
21914
|
+
}
|
|
21915
|
+
},
|
|
21916
|
+
shouldStart: (event) => {
|
|
21917
|
+
if (!this.itemsDraggable) return true;
|
|
21918
|
+
const cell = event.composedPath()[0]?.closest?.(`.cell`);
|
|
21919
|
+
if (!cell) return true;
|
|
21920
|
+
const key = cell.dataset.key;
|
|
21921
|
+
if (!key) return true;
|
|
21922
|
+
const index = this.#source.indexOfKey(key);
|
|
21923
|
+
if (index < 0) return true;
|
|
21924
|
+
return !this.#source.isSelectable(index);
|
|
21925
|
+
}
|
|
20535
21926
|
});
|
|
20536
21927
|
this.#selectedSnapshot = /* @__PURE__ */ new Set();
|
|
20537
21928
|
this.#onScroll = (e) => {
|
|
@@ -20544,6 +21935,32 @@ let GridListElement = class GridListElement extends i {
|
|
|
20544
21935
|
this.#emitViewportChange();
|
|
20545
21936
|
});
|
|
20546
21937
|
};
|
|
21938
|
+
this.#onDragStart = (e, key) => {
|
|
21939
|
+
if (!this.itemsDraggable) return;
|
|
21940
|
+
const index = this.#source.indexOfKey(key);
|
|
21941
|
+
if (index < 0 || !this.#source.isSelectable(index)) return;
|
|
21942
|
+
if (!this.selection.selectedKeys.has(key)) this.selection.replace(key);
|
|
21943
|
+
const selectedKeys = this.#source.keys().filter((k) => !isSyntheticKey(k)).filter((k) => this.selection.selectedKeys.has(k));
|
|
21944
|
+
const detail = {
|
|
21945
|
+
key,
|
|
21946
|
+
index: this.#source.indexOfKey(key),
|
|
21947
|
+
item: this.#source.resolveKeyToData(key) ?? this.#source.resolveKeyToElement(key),
|
|
21948
|
+
selectedKeys
|
|
21949
|
+
};
|
|
21950
|
+
if (!this._dispatch(`grid-list-native-drag-start`, detail, true)) {
|
|
21951
|
+
e.preventDefault();
|
|
21952
|
+
return;
|
|
21953
|
+
}
|
|
21954
|
+
this.#nativeDragging = true;
|
|
21955
|
+
this.#dragOriginKey = key;
|
|
21956
|
+
this.toggleAttribute(`data-native-dragging`, true);
|
|
21957
|
+
const count = selectedKeys.length;
|
|
21958
|
+
this.setAttribute(`aria-label`, count === 1 ? `Dragging 1 item` : `Dragging ${count} items`);
|
|
21959
|
+
};
|
|
21960
|
+
this.#onDragEnd = () => {
|
|
21961
|
+
this.#clearNativeDragState();
|
|
21962
|
+
this.#startPostDragSuppressTimer();
|
|
21963
|
+
};
|
|
20547
21964
|
this._onKeyDown = (e) => {
|
|
20548
21965
|
if ((e.ctrlKey || e.metaKey) && e.key === `f`) return;
|
|
20549
21966
|
if ((e.ctrlKey || e.metaKey) && e.key === `a`) {
|
|
@@ -20613,6 +22030,7 @@ let GridListElement = class GridListElement extends i {
|
|
|
20613
22030
|
break;
|
|
20614
22031
|
}
|
|
20615
22032
|
case `Escape`:
|
|
22033
|
+
if (this.#nativeDragging) this.#clearNativeDragState();
|
|
20616
22034
|
this.selection.clear();
|
|
20617
22035
|
break;
|
|
20618
22036
|
default: return;
|
|
@@ -20680,7 +22098,18 @@ let GridListElement = class GridListElement extends i {
|
|
|
20680
22098
|
border-radius: var(--grid-list-radius);
|
|
20681
22099
|
}
|
|
20682
22100
|
|
|
20683
|
-
/* The square that holds the slotted content.
|
|
22101
|
+
/* The square that holds the slotted content — the "image well". Its
|
|
22102
|
+
background is a set of consumer-settable variables so a Finder-style
|
|
22103
|
+
look is possible: on selection the caption takes the accent colouring
|
|
22104
|
+
while the well takes a tint of the surface colour. Each variable is
|
|
22105
|
+
unset by default, so the fallback (today's look) applies until a
|
|
22106
|
+
consumer opts in.
|
|
22107
|
+
--grid-list-thumb-bg idle well background
|
|
22108
|
+
--grid-list-thumb-bg-tickled under the cursor
|
|
22109
|
+
--grid-list-thumb-bg-selected when the cell is selected
|
|
22110
|
+
--grid-list-thumb-bg-selected-tickled selected + under the cursor
|
|
22111
|
+
--grid-list-thumb-selection-wash colour of the box-mode wash (default: --accent)
|
|
22112
|
+
--grid-list-thumb-selection-wash-opacity strength of that wash (default: 0.18; set 0 to drop it) */
|
|
20684
22113
|
.thumb {
|
|
20685
22114
|
position: relative;
|
|
20686
22115
|
flex: 1;
|
|
@@ -20690,7 +22119,7 @@ let GridListElement = class GridListElement extends i {
|
|
|
20690
22119
|
box-sizing: border-box;
|
|
20691
22120
|
overflow: hidden;
|
|
20692
22121
|
border-radius: 0;
|
|
20693
|
-
background: transparent;
|
|
22122
|
+
background: var(--grid-list-thumb-bg, transparent);
|
|
20694
22123
|
border: 1px solid transparent;
|
|
20695
22124
|
transition: background var(--transition), border-color var(--transition);
|
|
20696
22125
|
}
|
|
@@ -20703,6 +22132,7 @@ let GridListElement = class GridListElement extends i {
|
|
|
20703
22132
|
align-items: center;
|
|
20704
22133
|
justify-content: center;
|
|
20705
22134
|
overflow: hidden;
|
|
22135
|
+
draggable: false;
|
|
20706
22136
|
}
|
|
20707
22137
|
.thumb ::slotted(*:empty)::after {
|
|
20708
22138
|
content: "Empty";
|
|
@@ -20714,19 +22144,27 @@ let GridListElement = class GridListElement extends i {
|
|
|
20714
22144
|
}
|
|
20715
22145
|
|
|
20716
22146
|
/* Selection / cursor wash — sits over the slotted content so it reads
|
|
20717
|
-
on photos and arbitrary DOM alike.
|
|
22147
|
+
on photos and arbitrary DOM alike. Set
|
|
22148
|
+
--grid-list-thumb-selection-wash-opacity: 0 to drop it in favour of a
|
|
22149
|
+
--grid-list-thumb-bg-selected tint. */
|
|
20718
22150
|
.thumb::after {
|
|
20719
22151
|
content: "";
|
|
20720
22152
|
position: absolute;
|
|
20721
22153
|
inset: 0;
|
|
20722
22154
|
pointer-events: none;
|
|
20723
22155
|
border-radius: inherit;
|
|
20724
|
-
background: var(--accent);
|
|
22156
|
+
background: var(--grid-list-thumb-selection-wash, var(--accent));
|
|
20725
22157
|
opacity: 0;
|
|
20726
22158
|
transition: opacity var(--transition, 0.1s ease-out);
|
|
20727
22159
|
}
|
|
20728
22160
|
.cell.selected .thumb::after {
|
|
20729
|
-
opacity: 0.18;
|
|
22161
|
+
opacity: var(--grid-list-thumb-selection-wash-opacity, 0.18);
|
|
22162
|
+
}
|
|
22163
|
+
:host(:not([caption-style="separate"])) .cell.selected .thumb {
|
|
22164
|
+
background: var(--grid-list-thumb-bg-selected, var(--grid-list-thumb-bg, transparent));
|
|
22165
|
+
}
|
|
22166
|
+
:host(:not([caption-style="separate"])) .cell.selected.tickled .thumb {
|
|
22167
|
+
background: var(--grid-list-thumb-bg-selected-tickled, var(--grid-list-thumb-bg-selected, var(--grid-list-thumb-bg, transparent)));
|
|
20730
22168
|
}
|
|
20731
22169
|
|
|
20732
22170
|
/* ---- Caption (base) ---- */
|
|
@@ -20744,6 +22182,18 @@ let GridListElement = class GridListElement extends i {
|
|
|
20744
22182
|
}
|
|
20745
22183
|
:host([caption-align="left"]) .caption { text-align: left; }
|
|
20746
22184
|
:host([caption-align="right"]) .caption { text-align: right; }
|
|
22185
|
+
/* Tickled captions swap their plain label for an ixfx-pan-text in loop
|
|
22186
|
+
mode so a truncated label scrolls instead of staying an ellipsis. The
|
|
22187
|
+
pan fills the caption band (flex in 'separate', block otherwise) and
|
|
22188
|
+
inherits its alignment. */
|
|
22189
|
+
.caption ixfx-pan-text {
|
|
22190
|
+
display: block;
|
|
22191
|
+
flex: 1;
|
|
22192
|
+
min-width: 0;
|
|
22193
|
+
max-width: 100%;
|
|
22194
|
+
font: inherit;
|
|
22195
|
+
color: inherit;
|
|
22196
|
+
}
|
|
20747
22197
|
|
|
20748
22198
|
/* ---- Box modes (hidden / under / overlaid): the cell is one box with a
|
|
20749
22199
|
single selection outline ---- */
|
|
@@ -20753,8 +22203,8 @@ let GridListElement = class GridListElement extends i {
|
|
|
20753
22203
|
overflow: hidden;
|
|
20754
22204
|
transition: background var(--transition), border-color var(--transition);
|
|
20755
22205
|
}
|
|
20756
|
-
:host(:not([caption-style="separate"])) .cell
|
|
20757
|
-
:host(:not([caption-style="separate"])) .cell
|
|
22206
|
+
:host(:not([caption-style="separate"])) .cell.tickled,
|
|
22207
|
+
:host(:not([caption-style="separate"]):not([disable-hover-tickle])) .cell:hover {
|
|
20758
22208
|
background: var(--item-bg-tickled);
|
|
20759
22209
|
border: var(--item-border-tickled);
|
|
20760
22210
|
}
|
|
@@ -20821,12 +22271,12 @@ let GridListElement = class GridListElement extends i {
|
|
|
20821
22271
|
:host([caption-style="separate"]) .thumb {
|
|
20822
22272
|
flex: none;
|
|
20823
22273
|
border-radius: var(--grid-list-radius);
|
|
20824
|
-
background: var(--grid-list-item-bg);
|
|
22274
|
+
background: var(--grid-list-thumb-bg, var(--grid-list-item-bg));
|
|
20825
22275
|
border: 1px solid transparent;
|
|
20826
22276
|
}
|
|
20827
|
-
:host([caption-style="separate"]) .cell
|
|
20828
|
-
:host([caption-style="separate"]) .cell
|
|
20829
|
-
background: var(--item-bg-tickled);
|
|
22277
|
+
:host([caption-style="separate"]) .cell.tickled .thumb,
|
|
22278
|
+
:host([caption-style="separate"]:not([disable-hover-tickle])) .cell:hover .thumb {
|
|
22279
|
+
background: var(--grid-list-thumb-bg-tickled, var(--item-bg-tickled));
|
|
20830
22280
|
border: var(--item-border-tickled);
|
|
20831
22281
|
}
|
|
20832
22282
|
:host([caption-style="separate"]) .caption {
|
|
@@ -20839,14 +22289,17 @@ let GridListElement = class GridListElement extends i {
|
|
|
20839
22289
|
}
|
|
20840
22290
|
:host([caption-style="separate"][caption-align="left"]) .caption { align-self: flex-start; }
|
|
20841
22291
|
:host([caption-style="separate"][caption-align="right"]) .caption { align-self: flex-end; }
|
|
22292
|
+
/* Inset the selection ring (negative offset) so it is never clipped by the
|
|
22293
|
+
scroll viewport's overflow when the cell sits against an edge. */
|
|
20842
22294
|
:host([caption-style="separate"]) .cell.selected .thumb {
|
|
22295
|
+
background: var(--grid-list-thumb-bg-selected, var(--grid-list-thumb-bg, var(--grid-list-item-bg)));
|
|
20843
22296
|
outline: 2px solid var(--accent);
|
|
20844
|
-
outline-offset: 2px;
|
|
22297
|
+
outline-offset: -2px;
|
|
20845
22298
|
}
|
|
20846
22299
|
:host([caption-style="separate"]) .cell.selected.tickled .thumb {
|
|
20847
|
-
background: var(--item-bg-selected-tickled);
|
|
22300
|
+
background: var(--grid-list-thumb-bg-selected-tickled, var(--item-bg-selected-tickled));
|
|
20848
22301
|
outline: 2px dashed var(--surface-3);
|
|
20849
|
-
outline-offset: 2px;
|
|
22302
|
+
outline-offset: -2px;
|
|
20850
22303
|
}
|
|
20851
22304
|
:host([caption-style="separate"]) .cell.selected .caption {
|
|
20852
22305
|
background: var(--accent);
|
|
@@ -20884,6 +22337,26 @@ let GridListElement = class GridListElement extends i {
|
|
|
20884
22337
|
:host([reflowing]) .cell { transition: background var(--transition), border-color var(--transition); }
|
|
20885
22338
|
.cell.entering { animation: none; }
|
|
20886
22339
|
}
|
|
22340
|
+
|
|
22341
|
+
/* Drag-select (marquee) rectangle + covered-cell preview. The preview
|
|
22342
|
+
reuses the selection wash so covered cells read as "about to be
|
|
22343
|
+
selected". Style hooks: part="marquee", --grid-list-marquee-border,
|
|
22344
|
+
--grid-list-marquee-fill. */
|
|
22345
|
+
.marquee {
|
|
22346
|
+
position: absolute;
|
|
22347
|
+
pointer-events: none;
|
|
22348
|
+
z-index: 5;
|
|
22349
|
+
border: 1px solid var(--grid-list-marquee-border, var(--accent));
|
|
22350
|
+
background: var(--grid-list-marquee-fill, color-mix(in srgb, var(--accent) 15%, transparent));
|
|
22351
|
+
}
|
|
22352
|
+
.cell.marquee .thumb::after {
|
|
22353
|
+
opacity: var(--grid-list-thumb-selection-wash-opacity, 0.18);
|
|
22354
|
+
}
|
|
22355
|
+
|
|
22356
|
+
/* Native item drag origin cell. */
|
|
22357
|
+
.cell.dragging-origin {
|
|
22358
|
+
opacity: 0.6;
|
|
22359
|
+
}
|
|
20887
22360
|
`
|
|
20888
22361
|
];
|
|
20889
22362
|
}
|
|
@@ -20916,6 +22389,62 @@ let GridListElement = class GridListElement extends i {
|
|
|
20916
22389
|
*/
|
|
20917
22390
|
#sourceElement;
|
|
20918
22391
|
#source;
|
|
22392
|
+
/** Live drag-select preview: covered keys + the surface-relative rect. */
|
|
22393
|
+
#marqueePreview;
|
|
22394
|
+
#marqueeRect;
|
|
22395
|
+
/** Native item drag state: true while a drag is active. */
|
|
22396
|
+
#nativeDragging;
|
|
22397
|
+
/** Key of the cell that originated the native drag. */
|
|
22398
|
+
#dragOriginKey;
|
|
22399
|
+
/** Timer handle for post-drag click suppression. */
|
|
22400
|
+
#postDragSuppressTimer;
|
|
22401
|
+
/**
|
|
22402
|
+
* The single caption pan-text currently scrolling. At most one caption is
|
|
22403
|
+
* a pan-text in loop mode at a time — when tickle moves, the old one is
|
|
22404
|
+
* stopped before the new one starts (see `#activateTickledPan`).
|
|
22405
|
+
*/
|
|
22406
|
+
#activeCaptionPan;
|
|
22407
|
+
#dragSelect;
|
|
22408
|
+
/**
|
|
22409
|
+
* Map a surface-relative (viewport-visible) rect to covered item keys using
|
|
22410
|
+
* the same `computeGridWindow` geometry the renderer uses — pure arithmetic,
|
|
22411
|
+
* so virtualized off-screen items are covered without DOM measurement.
|
|
22412
|
+
*/
|
|
22413
|
+
#marqueeHitTest(rect) {
|
|
22414
|
+
const count = this.#source.count;
|
|
22415
|
+
if (count === 0) return [];
|
|
22416
|
+
const horizontal = this.orientation === `row`;
|
|
22417
|
+
const win = computeGridWindow(count, this.itemSize, this.#rowHeight(), this.gap, Math.max(1, this._viewportWidth), Math.max(1, this._viewportHeight), horizontal ? this._scrollLeft : this._scrollTop, this.orientation, 0);
|
|
22418
|
+
const out = [];
|
|
22419
|
+
if (horizontal) {
|
|
22420
|
+
const x0 = rect.x + this._scrollLeft;
|
|
22421
|
+
const x1 = x0 + rect.width;
|
|
22422
|
+
const lo = Math.max(0, Math.floor(x0 / win.colStride));
|
|
22423
|
+
const hi = Math.min(count - 1, Math.floor(x1 / win.colStride));
|
|
22424
|
+
for (let i = lo; i <= hi; i++) out.push(i);
|
|
22425
|
+
} else {
|
|
22426
|
+
const x0 = rect.x + this._scrollLeft;
|
|
22427
|
+
const x1 = x0 + rect.width;
|
|
22428
|
+
const y0 = rect.y + this._scrollTop;
|
|
22429
|
+
const y1 = y0 + rect.height;
|
|
22430
|
+
const colLo = Math.max(0, Math.floor(x0 / win.colStride));
|
|
22431
|
+
const colHi = Math.min(win.cols - 1, Math.floor(x1 / win.colStride));
|
|
22432
|
+
const rowLo = Math.max(0, Math.floor(y0 / win.rowStride));
|
|
22433
|
+
const rowHi = Math.floor(y1 / win.rowStride);
|
|
22434
|
+
for (let row = rowLo; row <= rowHi; row++) for (let col = colLo; col <= colHi; col++) {
|
|
22435
|
+
const index = row * win.cols + col;
|
|
22436
|
+
if (index >= 0 && index < count) out.push(index);
|
|
22437
|
+
}
|
|
22438
|
+
}
|
|
22439
|
+
const keys = [];
|
|
22440
|
+
for (const index of out) {
|
|
22441
|
+
const key = this.#source.keyAt(index);
|
|
22442
|
+
if (!key || isSyntheticKey(key)) continue;
|
|
22443
|
+
if (!this.#source.isSelectable(index)) continue;
|
|
22444
|
+
keys.push(key);
|
|
22445
|
+
}
|
|
22446
|
+
return keys;
|
|
22447
|
+
}
|
|
20919
22448
|
#searchMode;
|
|
20920
22449
|
#searchFilterKeys;
|
|
20921
22450
|
/** (Re)build {@link search} for the current mode; a no-op if it already matches. */
|
|
@@ -20988,6 +22517,7 @@ let GridListElement = class GridListElement extends i {
|
|
|
20988
22517
|
}
|
|
20989
22518
|
disconnectedCallback() {
|
|
20990
22519
|
super.disconnectedCallback();
|
|
22520
|
+
this.#stopActiveCaptionPan();
|
|
20991
22521
|
this.removeEventListener(`keydown`, this._onKeyDown);
|
|
20992
22522
|
this.#resizeObserver?.disconnect();
|
|
20993
22523
|
this.#resizeObserver = void 0;
|
|
@@ -21000,6 +22530,7 @@ let GridListElement = class GridListElement extends i {
|
|
|
21000
22530
|
clearTimeout(this.#reflowTimer);
|
|
21001
22531
|
this.#reflowTimer = 0;
|
|
21002
22532
|
}
|
|
22533
|
+
if (this.#nativeDragging) this.#clearNativeDragState();
|
|
21003
22534
|
}
|
|
21004
22535
|
#onChildrenChanged(records) {
|
|
21005
22536
|
const previousLength = this.#items.length;
|
|
@@ -21187,6 +22718,7 @@ let GridListElement = class GridListElement extends i {
|
|
|
21187
22718
|
if (Math.abs(vp.scrollLeft - this._scrollLeft) > .5) vp.scrollLeft = this._scrollLeft;
|
|
21188
22719
|
}
|
|
21189
22720
|
this.#applyZoomAnchor();
|
|
22721
|
+
this.#activateTickledPan();
|
|
21190
22722
|
}
|
|
21191
22723
|
/** Re-anchor the scroll so the item captured in `willUpdate` stays centred. */
|
|
21192
22724
|
#applyZoomAnchor() {
|
|
@@ -21517,15 +23049,19 @@ let GridListElement = class GridListElement extends i {
|
|
|
21517
23049
|
element
|
|
21518
23050
|
});
|
|
21519
23051
|
}
|
|
21520
|
-
_dispatch(name, detail) {
|
|
21521
|
-
this.dispatchEvent(new CustomEvent(name, {
|
|
23052
|
+
_dispatch(name, detail, cancelable = false) {
|
|
23053
|
+
return this.dispatchEvent(new CustomEvent(name, {
|
|
21522
23054
|
detail,
|
|
21523
23055
|
bubbles: true,
|
|
21524
|
-
composed: true
|
|
23056
|
+
composed: true,
|
|
23057
|
+
cancelable
|
|
21525
23058
|
}));
|
|
21526
23059
|
}
|
|
21527
23060
|
/** Selected keys, snapshotted once per render so the cell renderers don't each rebuild the set. */
|
|
21528
23061
|
#selectedSnapshot;
|
|
23062
|
+
#marqueeStyle(rect) {
|
|
23063
|
+
return `left:${rect.x}px;top:${rect.y}px;width:${Math.max(0, rect.width)}px;height:${Math.max(0, rect.height)}px`;
|
|
23064
|
+
}
|
|
21529
23065
|
render() {
|
|
21530
23066
|
const win = this.#currentWindow();
|
|
21531
23067
|
this.#selectedSnapshot = this.selection.selectedKeys;
|
|
@@ -21542,6 +23078,7 @@ let GridListElement = class GridListElement extends i {
|
|
|
21542
23078
|
<div class="spacer" style=${spacerStyle}>
|
|
21543
23079
|
${this.#source instanceof DataGridListSource ? this.#renderDataCells(win) : this.#renderElementCells(win)}
|
|
21544
23080
|
</div>
|
|
23081
|
+
${this.#marqueeRect ? b`<div class="marquee" part="marquee" style=${this.#marqueeStyle(this.#marqueeRect)}></div>` : ``}
|
|
21545
23082
|
</div>
|
|
21546
23083
|
${this.search?.renderField()}
|
|
21547
23084
|
`;
|
|
@@ -21553,7 +23090,10 @@ let GridListElement = class GridListElement extends i {
|
|
|
21553
23090
|
#renderDataCell(index, win) {
|
|
21554
23091
|
const key = this.#source.keyAt(index);
|
|
21555
23092
|
const selected = this.#selectedSnapshot.has(key);
|
|
23093
|
+
const marquee = this.#marqueePreview.has(key);
|
|
21556
23094
|
const tickled = this.tickled.isTickled(key);
|
|
23095
|
+
const selectable = this.#source.isSelectable(index);
|
|
23096
|
+
const draggable = this.itemsDraggable && selectable;
|
|
21557
23097
|
const style = this.captionStyle;
|
|
21558
23098
|
const separate = style === `separate`;
|
|
21559
23099
|
const caption = style === `hidden` ? `` : this.#source.labelAt(index);
|
|
@@ -21564,24 +23104,69 @@ let GridListElement = class GridListElement extends i {
|
|
|
21564
23104
|
const captionCss = separate ? `height:${Math.max(0, this.captionHeight - 4)}px` : style === `under` ? `height:${this.captionHeight}px` : ``;
|
|
21565
23105
|
return b`
|
|
21566
23106
|
<div
|
|
21567
|
-
class="cell${selected ? ` selected` : ``}${tickled ? ` tickled` : ``}"
|
|
23107
|
+
class="cell${selected ? ` selected` : ``}${tickled ? ` tickled` : ``}${marquee ? ` marquee` : ``}${this.#nativeDragging && key === this.#dragOriginKey ? ` dragging-origin` : ``}"
|
|
21568
23108
|
part="item${selected ? ` selected` : ``}${tickled ? ` tickled` : ``}"
|
|
21569
23109
|
role="option"
|
|
21570
23110
|
aria-selected=${selected ? `true` : `false`}
|
|
21571
23111
|
style="width:${this.itemSize}px;height:${cellHeight}px;transform:translate(${x}px,${y}px)"
|
|
21572
23112
|
data-index=${index}
|
|
21573
23113
|
data-key=${key}
|
|
23114
|
+
draggable=${draggable ? `true` : `false`}
|
|
21574
23115
|
?data-selected=${selected}
|
|
21575
23116
|
?data-tickled=${tickled}
|
|
23117
|
+
?data-marquee=${marquee}
|
|
21576
23118
|
@click=${(e) => this.#onCellClick(e, key)}
|
|
21577
23119
|
@dblclick=${() => this.#onCellActivate(key)}
|
|
21578
23120
|
@pointerenter=${() => this.tickled.handlePointerEnter(key)}
|
|
23121
|
+
@dragstart=${(e) => this.#onDragStart(e, key)}
|
|
23122
|
+
@dragend=${() => this.#onDragEnd()}
|
|
21579
23123
|
>
|
|
21580
23124
|
<div class="content" part="content">${this.#source.renderCellContent(index)}</div>
|
|
21581
|
-
${showCaption ?
|
|
23125
|
+
${showCaption ? this.#renderCaption(caption, captionCss, tickled) : ``}
|
|
21582
23126
|
</div>
|
|
21583
23127
|
`;
|
|
21584
23128
|
}
|
|
23129
|
+
/**
|
|
23130
|
+
* A tickled cell swaps its plain label for an `ixfx-pan-text` in loop mode
|
|
23131
|
+
* so a truncated label scrolls instead of staying an ellipsis. Unticked
|
|
23132
|
+
* cells keep the cheap plain-text caption.
|
|
23133
|
+
*/
|
|
23134
|
+
#renderCaption(caption, captionCss, tickled) {
|
|
23135
|
+
if (tickled) return b`<div class="caption" part="caption" style=${captionCss} title=${caption}><ixfx-pan-text mode="loop">${caption}</ixfx-pan-text></div>`;
|
|
23136
|
+
return b`<div class="caption" part="caption" style=${captionCss} title=${caption}>${caption}</div>`;
|
|
23137
|
+
}
|
|
23138
|
+
/** Stop the active caption pan, if any, and forget it. */
|
|
23139
|
+
#stopActiveCaptionPan() {
|
|
23140
|
+
const active = this.#activeCaptionPan;
|
|
23141
|
+
this.#activeCaptionPan = null;
|
|
23142
|
+
try {
|
|
23143
|
+
active?.stopLoop?.();
|
|
23144
|
+
} catch {}
|
|
23145
|
+
}
|
|
23146
|
+
/**
|
|
23147
|
+
* Enforce a single scrolling caption: the tickled cell's pan-text loops,
|
|
23148
|
+
* every other pan-text is stopped. The pan-text also auto-starts when
|
|
23149
|
+
* `mode="loop"` is set; this covers the case where the element was already
|
|
23150
|
+
* connected before overflow was measured.
|
|
23151
|
+
*/
|
|
23152
|
+
#activateTickledPan() {
|
|
23153
|
+
const tickledCell = this.renderRoot.querySelector(`.cell[data-tickled]`);
|
|
23154
|
+
const pans = [...this.renderRoot.querySelectorAll(`ixfx-pan-text[mode="loop"]`)];
|
|
23155
|
+
const current = tickledCell?.querySelector(`ixfx-pan-text[mode="loop"]`) ?? null;
|
|
23156
|
+
for (const pan of pans) if (pan !== current) try {
|
|
23157
|
+
pan.stopLoop?.();
|
|
23158
|
+
} catch {}
|
|
23159
|
+
const active = this.#activeCaptionPan;
|
|
23160
|
+
if (active && active !== current) try {
|
|
23161
|
+
active.stopLoop?.();
|
|
23162
|
+
} catch {}
|
|
23163
|
+
if (!current) {
|
|
23164
|
+
this.#activeCaptionPan = null;
|
|
23165
|
+
return;
|
|
23166
|
+
}
|
|
23167
|
+
this.#activeCaptionPan = current;
|
|
23168
|
+
current.startLoop?.();
|
|
23169
|
+
}
|
|
21585
23170
|
#renderElementCells(win) {
|
|
21586
23171
|
const slice = this.#items.slice(win.startIndex, win.endIndex);
|
|
21587
23172
|
return repeat(slice, (_el, i) => this.#source.keyAt(win.startIndex + i), (el, i) => this.#renderCell(el, win.startIndex + i, win));
|
|
@@ -21589,8 +23174,11 @@ let GridListElement = class GridListElement extends i {
|
|
|
21589
23174
|
#renderCell(el, index, win) {
|
|
21590
23175
|
const key = this.#source.keyAt(index);
|
|
21591
23176
|
const selected = this.#selectedSnapshot.has(key);
|
|
23177
|
+
const marquee = this.#marqueePreview.has(key);
|
|
21592
23178
|
const tickled = this.tickled.isTickled(key);
|
|
21593
23179
|
const entering = this.#entering.has(el);
|
|
23180
|
+
const selectable = this.#source.isSelectable(index);
|
|
23181
|
+
const draggable = this.itemsDraggable && selectable;
|
|
21594
23182
|
const style = this.captionStyle;
|
|
21595
23183
|
const separate = style === `separate`;
|
|
21596
23184
|
const caption = style === `hidden` ? `` : this.#captionFor(el);
|
|
@@ -21602,23 +23190,27 @@ let GridListElement = class GridListElement extends i {
|
|
|
21602
23190
|
const captionCss = separate ? `height:${Math.max(0, this.captionHeight - 4)}px` : style === `under` ? `height:${this.captionHeight}px` : ``;
|
|
21603
23191
|
return b`
|
|
21604
23192
|
<div
|
|
21605
|
-
class="cell${selected ? ` selected` : ``}${tickled ? ` tickled` : ``}${entering ? ` entering` : ``}"
|
|
23193
|
+
class="cell${selected ? ` selected` : ``}${tickled ? ` tickled` : ``}${entering ? ` entering` : ``}${marquee ? ` marquee` : ``}${this.#nativeDragging && key === this.#dragOriginKey ? ` dragging-origin` : ``}"
|
|
21606
23194
|
part="item${selected ? ` selected` : ``}${tickled ? ` tickled` : ``}"
|
|
21607
23195
|
role="option"
|
|
21608
23196
|
aria-selected=${selected ? `true` : `false`}
|
|
21609
23197
|
style="width:${this.itemSize}px;height:${cellHeight}px;transform:translate(${x}px,${y}px)"
|
|
21610
23198
|
data-index=${index}
|
|
21611
23199
|
data-key=${key}
|
|
23200
|
+
draggable=${draggable ? `true` : `false`}
|
|
21612
23201
|
?data-selected=${selected}
|
|
21613
23202
|
?data-tickled=${tickled}
|
|
23203
|
+
?data-marquee=${marquee}
|
|
21614
23204
|
@click=${(e) => this.#onCellClick(e, key)}
|
|
21615
23205
|
@dblclick=${() => this.#onCellActivate(key)}
|
|
21616
23206
|
@pointerenter=${() => this.tickled.handlePointerEnter(key)}
|
|
23207
|
+
@dragstart=${(e) => this.#onDragStart(e, key)}
|
|
23208
|
+
@dragend=${() => this.#onDragEnd()}
|
|
21617
23209
|
>
|
|
21618
23210
|
<div class="thumb" part="thumb" style=${thumbStyle}>
|
|
21619
23211
|
${this.#source.renderCellContent(index)}
|
|
21620
23212
|
</div>
|
|
21621
|
-
${showCaption ?
|
|
23213
|
+
${showCaption ? this.#renderCaption(caption, captionCss, tickled) : ``}
|
|
21622
23214
|
</div>
|
|
21623
23215
|
`;
|
|
21624
23216
|
}
|
|
@@ -21630,9 +23222,24 @@ let GridListElement = class GridListElement extends i {
|
|
|
21630
23222
|
}
|
|
21631
23223
|
}
|
|
21632
23224
|
#onCellClick(e, key) {
|
|
23225
|
+
if (this.#dragSelect.isDragging || this.#nativeDragging || this.#postDragSuppressTimer !== 0) return;
|
|
21633
23226
|
this.selection.handleClick(key, e);
|
|
21634
23227
|
this.#emitItemEvent(`list-item-click`, key);
|
|
21635
23228
|
}
|
|
23229
|
+
#onDragStart;
|
|
23230
|
+
#onDragEnd;
|
|
23231
|
+
#startPostDragSuppressTimer() {
|
|
23232
|
+
if (this.#postDragSuppressTimer) clearTimeout(this.#postDragSuppressTimer);
|
|
23233
|
+
this.#postDragSuppressTimer = window.setTimeout(() => {
|
|
23234
|
+
this.#postDragSuppressTimer = 0;
|
|
23235
|
+
}, 0);
|
|
23236
|
+
}
|
|
23237
|
+
#clearNativeDragState() {
|
|
23238
|
+
this.#nativeDragging = false;
|
|
23239
|
+
this.#dragOriginKey = void 0;
|
|
23240
|
+
this.toggleAttribute(`data-native-dragging`, false);
|
|
23241
|
+
this.removeAttribute(`aria-label`);
|
|
23242
|
+
}
|
|
21636
23243
|
#onCellActivate(key) {
|
|
21637
23244
|
if (this.interactionMode !== `manual`) this.selection.replace(key);
|
|
21638
23245
|
this.#emitItemEvent(`list-activate`, key);
|
|
@@ -21646,6 +23253,11 @@ __decorate([property({
|
|
|
21646
23253
|
type: String,
|
|
21647
23254
|
attribute: `interaction-mode`
|
|
21648
23255
|
})], GridListElement.prototype, "interactionMode", void 0);
|
|
23256
|
+
__decorate([property({
|
|
23257
|
+
type: Boolean,
|
|
23258
|
+
attribute: `disable-hover-tickle`,
|
|
23259
|
+
reflect: true
|
|
23260
|
+
})], GridListElement.prototype, "disableHoverTickle", void 0);
|
|
21649
23261
|
__decorate([property({
|
|
21650
23262
|
type: Number,
|
|
21651
23263
|
attribute: `item-size`
|
|
@@ -21685,6 +23297,11 @@ __decorate([property({
|
|
|
21685
23297
|
})], GridListElement.prototype, "itemWrap", void 0);
|
|
21686
23298
|
__decorate([property({ attribute: false })], GridListElement.prototype, "filterPredicate", void 0);
|
|
21687
23299
|
__decorate([property({ attribute: false })], GridListElement.prototype, "itemFilterPredicate", void 0);
|
|
23300
|
+
__decorate([property({
|
|
23301
|
+
type: Boolean,
|
|
23302
|
+
attribute: `items-draggable`,
|
|
23303
|
+
reflect: true
|
|
23304
|
+
})], GridListElement.prototype, "itemsDraggable", void 0);
|
|
21688
23305
|
__decorate([property({
|
|
21689
23306
|
type: String,
|
|
21690
23307
|
attribute: `search-modes`,
|
|
@@ -23571,7 +25188,29 @@ let VerticalListElement = class VerticalListElement extends i {
|
|
|
23571
25188
|
if (id !== void 0) this._dispatch(`list-tickle`, { item: id });
|
|
23572
25189
|
},
|
|
23573
25190
|
onStateChange: () => this._syncItemStates(),
|
|
23574
|
-
itemWrap: this.itemWrap
|
|
25191
|
+
itemWrap: this.itemWrap,
|
|
25192
|
+
hoverDisabled: () => this.#dragSelect.isDragging
|
|
25193
|
+
});
|
|
25194
|
+
this.#dragSelect = new ListDragSelectController(this, {
|
|
25195
|
+
getSurface: () => this.renderRoot.querySelector(`.container`),
|
|
25196
|
+
isEnabled: () => this.selection.canDragSelect() && this._getVisibleItems().length > 0 && !this.hasAttribute(`disable-drag-select`),
|
|
25197
|
+
hitTest: (rect) => this.#marqueeHitTest(rect),
|
|
25198
|
+
getBaseSelection: () => this.selection.selected,
|
|
25199
|
+
onPreview: (preview, rect) => {
|
|
25200
|
+
this.#marqueeRect = rect;
|
|
25201
|
+
for (const el of this._getVisibleItems()) el.toggleAttribute(`data-marquee`, preview.has(el));
|
|
25202
|
+
this.requestUpdate();
|
|
25203
|
+
},
|
|
25204
|
+
onCommit: (finalSet) => {
|
|
25205
|
+
this.selection.applyDragSelection(finalSet);
|
|
25206
|
+
for (const el of this._getVisibleItems()) el.removeAttribute(`data-marquee`);
|
|
25207
|
+
this.#marqueeRect = void 0;
|
|
25208
|
+
this.requestUpdate();
|
|
25209
|
+
},
|
|
25210
|
+
autoScroll: (_dx, dy) => {
|
|
25211
|
+
const list = this.renderRoot.querySelector(`ul`);
|
|
25212
|
+
if (list) list.scrollTop += dy;
|
|
25213
|
+
}
|
|
23575
25214
|
});
|
|
23576
25215
|
this.search = new ListSearchController(this, { adapter: createElementListSearchAdapter(this, {
|
|
23577
25216
|
itemSelector: ITEM_SELECTOR,
|
|
@@ -23632,6 +25271,7 @@ let VerticalListElement = class VerticalListElement extends i {
|
|
|
23632
25271
|
}
|
|
23633
25272
|
};
|
|
23634
25273
|
this._onClick = (e) => {
|
|
25274
|
+
if (this.#dragSelect.isDragging) return;
|
|
23635
25275
|
const item = this._findListItem(e.composedPath());
|
|
23636
25276
|
if (!item) return;
|
|
23637
25277
|
this._dispatch(`list-item-click`, { item });
|
|
@@ -23648,6 +25288,30 @@ let VerticalListElement = class VerticalListElement extends i {
|
|
|
23648
25288
|
#itemObserver;
|
|
23649
25289
|
/** Items that have already played (or been skipped for) their enter animation. */
|
|
23650
25290
|
#animatedItems;
|
|
25291
|
+
/** Live drag-select preview rect (surface-relative); the covered items carry `data-marquee`. */
|
|
25292
|
+
#marqueeRect;
|
|
25293
|
+
#dragSelect;
|
|
25294
|
+
/** Collect visible items whose surface-relative box intersects `rect`. */
|
|
25295
|
+
#marqueeHitTest(rect) {
|
|
25296
|
+
const surface = this.renderRoot.querySelector(`.container`);
|
|
25297
|
+
if (!surface) return [];
|
|
25298
|
+
const box = surface.getBoundingClientRect();
|
|
25299
|
+
const rx0 = rect.x;
|
|
25300
|
+
const ry0 = rect.y;
|
|
25301
|
+
const rx1 = rect.x + rect.width;
|
|
25302
|
+
const ry1 = rect.y + rect.height;
|
|
25303
|
+
const out = [];
|
|
25304
|
+
for (const el of this._getVisibleItems()) {
|
|
25305
|
+
const r = el.getBoundingClientRect();
|
|
25306
|
+
const left = r.left - box.left;
|
|
25307
|
+
const top = r.top - box.top;
|
|
25308
|
+
if (left <= rx1 && left + r.width >= rx0 && top <= ry1 && top + r.height >= ry0) out.push(el);
|
|
25309
|
+
}
|
|
25310
|
+
return out;
|
|
25311
|
+
}
|
|
25312
|
+
#marqueeStyle(rect) {
|
|
25313
|
+
return `left:${rect.x}px;top:${rect.y}px;width:${Math.max(0, rect.width)}px;height:${Math.max(0, rect.height)}px`;
|
|
25314
|
+
}
|
|
23651
25315
|
#searchRegistry;
|
|
23652
25316
|
#unregisterSearchCommands;
|
|
23653
25317
|
/** Command registry carrying this list's `list.search.*` commands. */
|
|
@@ -24118,6 +25782,22 @@ let VerticalListElement = class VerticalListElement extends i {
|
|
|
24118
25782
|
outline-offset: -2px;
|
|
24119
25783
|
}
|
|
24120
25784
|
|
|
25785
|
+
/* Drag-select (marquee) rectangle + covered-row preview.
|
|
25786
|
+
Style hooks: part="marquee", --vertical-list-marquee-border,
|
|
25787
|
+
--vertical-list-marquee-fill. */
|
|
25788
|
+
.marquee {
|
|
25789
|
+
position: absolute;
|
|
25790
|
+
pointer-events: none;
|
|
25791
|
+
z-index: 5;
|
|
25792
|
+
border: 1px solid var(--vertical-list-marquee-border, var(--accent));
|
|
25793
|
+
background: var(--vertical-list-marquee-fill, color-mix(in srgb, var(--accent) 15%, transparent));
|
|
25794
|
+
}
|
|
25795
|
+
|
|
25796
|
+
::slotted([data-marquee]) {
|
|
25797
|
+
background: var(--item-bg-selected);
|
|
25798
|
+
color: var(--item-text-selected);
|
|
25799
|
+
}
|
|
25800
|
+
|
|
24121
25801
|
/* checked mode: checkbox (injected into li) communicates selection — suppress bg highlight */
|
|
24122
25802
|
:host([interaction-mode="checked"]) ::slotted([data-selected]) {
|
|
24123
25803
|
background: transparent;
|
|
@@ -24139,6 +25819,7 @@ let VerticalListElement = class VerticalListElement extends i {
|
|
|
24139
25819
|
<ul part="list">
|
|
24140
25820
|
<slot></slot>
|
|
24141
25821
|
</ul>
|
|
25822
|
+
${this.#marqueeRect ? b`<div class="marquee" part="marquee" style=${this.#marqueeStyle(this.#marqueeRect)}></div>` : ``}
|
|
24142
25823
|
${this.search.renderField()}
|
|
24143
25824
|
</div>
|
|
24144
25825
|
`;
|
|
@@ -30832,136 +32513,6 @@ function dismiss(id) {
|
|
|
30832
32513
|
syncRenderer();
|
|
30833
32514
|
}
|
|
30834
32515
|
//#endregion
|
|
30835
|
-
//#region src/pan-text/pan-text.ts
|
|
30836
|
-
const SPEED = 45;
|
|
30837
|
-
const END_PADDING = 4;
|
|
30838
|
-
const START_DELAY = 300;
|
|
30839
|
-
const PAN_EASING = `cubic-bezier(0.25, 0.46, 0.45, 0.94)`;
|
|
30840
|
-
let PanTextElement = class PanTextElement extends i {
|
|
30841
|
-
constructor(..._args) {
|
|
30842
|
-
super(..._args);
|
|
30843
|
-
this.direction = `end`;
|
|
30844
|
-
this.disabled = false;
|
|
30845
|
-
this._isOverflowing = false;
|
|
30846
|
-
this._isHovering = false;
|
|
30847
|
-
this._overflow = 0;
|
|
30848
|
-
this._resizeObserver = null;
|
|
30849
|
-
this._onMouseEnter = () => {
|
|
30850
|
-
this._isHovering = true;
|
|
30851
|
-
};
|
|
30852
|
-
this._onMouseLeave = () => {
|
|
30853
|
-
this._isHovering = false;
|
|
30854
|
-
};
|
|
30855
|
-
this._measure = () => {
|
|
30856
|
-
if (this._isHovering) return;
|
|
30857
|
-
const el = this._textEl;
|
|
30858
|
-
if (!el) return;
|
|
30859
|
-
this._overflow = Math.max(0, el.scrollWidth - el.clientWidth);
|
|
30860
|
-
const overflowing = this._overflow > 0;
|
|
30861
|
-
this.classList.toggle(`is-overflowing`, overflowing);
|
|
30862
|
-
if (overflowing !== this._isOverflowing) this._isOverflowing = overflowing;
|
|
30863
|
-
};
|
|
30864
|
-
}
|
|
30865
|
-
connectedCallback() {
|
|
30866
|
-
super.connectedCallback();
|
|
30867
|
-
this._resizeObserver = new ResizeObserver(() => this._measure());
|
|
30868
|
-
this.addEventListener(`mouseenter`, this._onMouseEnter);
|
|
30869
|
-
this.addEventListener(`mouseleave`, this._onMouseLeave);
|
|
30870
|
-
}
|
|
30871
|
-
disconnectedCallback() {
|
|
30872
|
-
super.disconnectedCallback();
|
|
30873
|
-
this._resizeObserver?.disconnect();
|
|
30874
|
-
this._resizeObserver = null;
|
|
30875
|
-
this.removeEventListener(`mouseenter`, this._onMouseEnter);
|
|
30876
|
-
this.removeEventListener(`mouseleave`, this._onMouseLeave);
|
|
30877
|
-
}
|
|
30878
|
-
firstUpdated() {
|
|
30879
|
-
this._measure();
|
|
30880
|
-
this._resizeObserver?.observe(this);
|
|
30881
|
-
document.fonts?.ready.then(() => this._measure());
|
|
30882
|
-
}
|
|
30883
|
-
updated() {
|
|
30884
|
-
this._measure();
|
|
30885
|
-
}
|
|
30886
|
-
_textStyle() {
|
|
30887
|
-
if (!this._isOverflowing) return ``;
|
|
30888
|
-
const distance = this._overflow + END_PADDING;
|
|
30889
|
-
const duration = Math.max(1.5, distance / SPEED);
|
|
30890
|
-
const revealEnd = this.direction === `end`;
|
|
30891
|
-
const restX = revealEnd ? 0 : -distance;
|
|
30892
|
-
const hoverX = revealEnd ? -distance : 0;
|
|
30893
|
-
if (this._isHovering) return [
|
|
30894
|
-
`transform: translateX(${hoverX}px)`,
|
|
30895
|
-
`transition: transform ${duration}s ${PAN_EASING} ${START_DELAY}ms`,
|
|
30896
|
-
`overflow: visible`,
|
|
30897
|
-
`text-overflow: clip`
|
|
30898
|
-
].join(`; `);
|
|
30899
|
-
return [
|
|
30900
|
-
`transform: translateX(${restX}px)`,
|
|
30901
|
-
`transition: transform 400ms ${PAN_EASING}`,
|
|
30902
|
-
revealEnd ? `` : `overflow: visible; text-overflow: clip`
|
|
30903
|
-
].filter(Boolean).join(`; `);
|
|
30904
|
-
}
|
|
30905
|
-
render() {
|
|
30906
|
-
const textClasses = {
|
|
30907
|
-
"is-overflowing": this._isOverflowing,
|
|
30908
|
-
"is-hovering": this._isHovering
|
|
30909
|
-
};
|
|
30910
|
-
return b`
|
|
30911
|
-
<span class="text ${classMap(textClasses)}" part="text" style=${this._textStyle()}>
|
|
30912
|
-
<slot @slotchange=${this._measure}></slot>
|
|
30913
|
-
</span>
|
|
30914
|
-
`;
|
|
30915
|
-
}
|
|
30916
|
-
static {
|
|
30917
|
-
this.styles = [themeFallbacks, i$3`
|
|
30918
|
-
/* Renders like plain inline text: no colours, border, padding or margin
|
|
30919
|
-
of its own — it only adds the clipping needed to pan on hover. */
|
|
30920
|
-
:host {
|
|
30921
|
-
display: inline-block;
|
|
30922
|
-
overflow: hidden;
|
|
30923
|
-
white-space: nowrap;
|
|
30924
|
-
max-width: 100%;
|
|
30925
|
-
box-sizing: border-box;
|
|
30926
|
-
font: inherit;
|
|
30927
|
-
color: inherit;
|
|
30928
|
-
}
|
|
30929
|
-
|
|
30930
|
-
:host([disabled]) {
|
|
30931
|
-
opacity: var(--disabled-opacity, 0.5);
|
|
30932
|
-
pointer-events: none;
|
|
30933
|
-
}
|
|
30934
|
-
|
|
30935
|
-
.text {
|
|
30936
|
-
display: block;
|
|
30937
|
-
overflow: hidden;
|
|
30938
|
-
text-overflow: ellipsis;
|
|
30939
|
-
white-space: nowrap;
|
|
30940
|
-
will-change: transform;
|
|
30941
|
-
}
|
|
30942
|
-
|
|
30943
|
-
@media (prefers-reduced-motion: reduce) {
|
|
30944
|
-
.text {
|
|
30945
|
-
transition: none !important;
|
|
30946
|
-
transform: none !important;
|
|
30947
|
-
}
|
|
30948
|
-
}
|
|
30949
|
-
`];
|
|
30950
|
-
}
|
|
30951
|
-
};
|
|
30952
|
-
__decorate([property({
|
|
30953
|
-
type: String,
|
|
30954
|
-
attribute: `direction`
|
|
30955
|
-
})], PanTextElement.prototype, "direction", void 0);
|
|
30956
|
-
__decorate([property({
|
|
30957
|
-
type: Boolean,
|
|
30958
|
-
attribute: `disabled`
|
|
30959
|
-
})], PanTextElement.prototype, "disabled", void 0);
|
|
30960
|
-
__decorate([state()], PanTextElement.prototype, "_isOverflowing", void 0);
|
|
30961
|
-
__decorate([state()], PanTextElement.prototype, "_isHovering", void 0);
|
|
30962
|
-
__decorate([query(`.text`)], PanTextElement.prototype, "_textEl", void 0);
|
|
30963
|
-
PanTextElement = __decorate([safeCustomElement(`ixfx-pan-text`)], PanTextElement);
|
|
30964
|
-
//#endregion
|
|
30965
32516
|
//#region src/panel/panel-group.ts
|
|
30966
32517
|
/** Pointer movement threshold (px) before a press becomes a drag. */
|
|
30967
32518
|
const DRAG_THRESHOLD_PX = 5;
|
|
@@ -32115,6 +33666,7 @@ let PlotHistogram = class PlotHistogram extends i {
|
|
|
32115
33666
|
this.#onPointerMove = (e) => {
|
|
32116
33667
|
if (this.interactionMode === `select` && this._isDragging) {
|
|
32117
33668
|
const index = this.#bucketIndexFromPosition(e.clientX, e.clientY);
|
|
33669
|
+
if (index === this._selectionEnd) return;
|
|
32118
33670
|
this._selectionEnd = index;
|
|
32119
33671
|
const start = Math.min(this._selectionStart, this._selectionEnd);
|
|
32120
33672
|
const end = Math.max(this._selectionStart, this._selectionEnd);
|
|
@@ -32126,6 +33678,7 @@ let PlotHistogram = class PlotHistogram extends i {
|
|
|
32126
33678
|
this._selectionOverlayText = `Select: ${startBar.valueMin.toFixed(2)} – ${endBar.valueMax.toFixed(2)}`;
|
|
32127
33679
|
}
|
|
32128
33680
|
this.requestUpdate();
|
|
33681
|
+
this.#emitSelectionChange(false);
|
|
32129
33682
|
return;
|
|
32130
33683
|
}
|
|
32131
33684
|
if (this.interactionMode === `select`) return;
|
|
@@ -32141,6 +33694,7 @@ let PlotHistogram = class PlotHistogram extends i {
|
|
|
32141
33694
|
this._isDragging = false;
|
|
32142
33695
|
this._selectionOverlayText = null;
|
|
32143
33696
|
this.requestUpdate();
|
|
33697
|
+
this.#emitSelectionChange(true);
|
|
32144
33698
|
}
|
|
32145
33699
|
return;
|
|
32146
33700
|
}
|
|
@@ -32160,9 +33714,13 @@ let PlotHistogram = class PlotHistogram extends i {
|
|
|
32160
33714
|
this.setColoredRange(startBar.valueMin, endBar.valueMax);
|
|
32161
33715
|
this._selectionOverlayText = `Select: ${startBar.valueMin.toFixed(2)} – ${endBar.valueMax.toFixed(2)}`;
|
|
32162
33716
|
this.requestUpdate();
|
|
33717
|
+
this.#emitSelectionChange(false);
|
|
32163
33718
|
};
|
|
32164
33719
|
this.#onPointerUp = () => {
|
|
32165
|
-
if (this.interactionMode === `select`
|
|
33720
|
+
if (this.interactionMode === `select` && this._isDragging) {
|
|
33721
|
+
this._isDragging = false;
|
|
33722
|
+
this.#emitSelectionChange(true);
|
|
33723
|
+
}
|
|
32166
33724
|
};
|
|
32167
33725
|
}
|
|
32168
33726
|
#series;
|
|
@@ -32211,11 +33769,14 @@ let PlotHistogram = class PlotHistogram extends i {
|
|
|
32211
33769
|
this.setColoredRange(startBar.valueMin, endBar.valueMax);
|
|
32212
33770
|
}
|
|
32213
33771
|
this.requestUpdate();
|
|
33772
|
+
this.#emitSelectionChange(true);
|
|
32214
33773
|
}
|
|
32215
33774
|
clearSelection() {
|
|
33775
|
+
const had = this._selectionStart !== null || this._selectionEnd !== null;
|
|
32216
33776
|
this._selectionStart = null;
|
|
32217
33777
|
this._selectionEnd = null;
|
|
32218
33778
|
this.requestUpdate();
|
|
33779
|
+
if (had) this.#emitSelectionChange(true);
|
|
32219
33780
|
}
|
|
32220
33781
|
getSelectedRange() {
|
|
32221
33782
|
if (this._selectionStart === null || this._selectionEnd === null) return {
|
|
@@ -32300,6 +33861,21 @@ let PlotHistogram = class PlotHistogram extends i {
|
|
|
32300
33861
|
composed: true
|
|
32301
33862
|
}));
|
|
32302
33863
|
}
|
|
33864
|
+
/**
|
|
33865
|
+
* Fire `plot-selection-change` with the current bar-range selection (indices +
|
|
33866
|
+
* data span). `committed` is `false` mid-drag, `true` on release / programmatic
|
|
33867
|
+
* change.
|
|
33868
|
+
*/
|
|
33869
|
+
#emitSelectionChange(committed) {
|
|
33870
|
+
this.dispatchEvent(new CustomEvent(`plot-selection-change`, {
|
|
33871
|
+
detail: {
|
|
33872
|
+
...this.getSelectedRange(),
|
|
33873
|
+
committed
|
|
33874
|
+
},
|
|
33875
|
+
bubbles: true,
|
|
33876
|
+
composed: true
|
|
33877
|
+
}));
|
|
33878
|
+
}
|
|
32303
33879
|
/** Bucket layout + counts, shared by render() and pointer hit-testing. */
|
|
32304
33880
|
#computeGeometry() {
|
|
32305
33881
|
const { values, range } = this.#series;
|
|
@@ -32387,7 +33963,7 @@ let PlotHistogram = class PlotHistogram extends i {
|
|
|
32387
33963
|
}
|
|
32388
33964
|
/** Gets bucket index from position, clamping to valid range (0 to bucketCount-1). */
|
|
32389
33965
|
#bucketIndexFromPosition(clientX, clientY) {
|
|
32390
|
-
const {
|
|
33966
|
+
const { isHorizontal, padding, bucketCount, availableMain } = this.#computeGeometry();
|
|
32391
33967
|
const rect = this.getBoundingClientRect();
|
|
32392
33968
|
const x = clientX - rect.left;
|
|
32393
33969
|
const y = clientY - rect.top;
|
|
@@ -38173,7 +39749,10 @@ let TimelineTrackTabElement = class TimelineTrackTabElement extends i {
|
|
|
38173
39749
|
};
|
|
38174
39750
|
}
|
|
38175
39751
|
static {
|
|
38176
|
-
this.styles =
|
|
39752
|
+
this.styles = [
|
|
39753
|
+
themeFallbacks,
|
|
39754
|
+
handleStyles,
|
|
39755
|
+
i$3`
|
|
38177
39756
|
:host {
|
|
38178
39757
|
display: flex;
|
|
38179
39758
|
align-items: center;
|
|
@@ -38200,13 +39779,13 @@ let TimelineTrackTabElement = class TimelineTrackTabElement extends i {
|
|
|
38200
39779
|
.handle {
|
|
38201
39780
|
display: none;
|
|
38202
39781
|
cursor: grab;
|
|
38203
|
-
|
|
38204
|
-
|
|
38205
|
-
|
|
39782
|
+
margin: 0 4px;
|
|
39783
|
+
--ixfx-handle-spot-size: 12px;
|
|
39784
|
+
--ixfx-handle-dot-size: 3px;
|
|
38206
39785
|
}
|
|
38207
39786
|
|
|
38208
39787
|
:host([reorderable]) .handle {
|
|
38209
|
-
display: block;
|
|
39788
|
+
display: inline-block;
|
|
38210
39789
|
}
|
|
38211
39790
|
|
|
38212
39791
|
.label {
|
|
@@ -38215,7 +39794,8 @@ let TimelineTrackTabElement = class TimelineTrackTabElement extends i {
|
|
|
38215
39794
|
text-overflow: ellipsis;
|
|
38216
39795
|
padding: 0 8px;
|
|
38217
39796
|
}
|
|
38218
|
-
|
|
39797
|
+
`
|
|
39798
|
+
];
|
|
38219
39799
|
}
|
|
38220
39800
|
#dragging;
|
|
38221
39801
|
#startScreenY;
|
|
@@ -38240,7 +39820,7 @@ let TimelineTrackTabElement = class TimelineTrackTabElement extends i {
|
|
|
38240
39820
|
}
|
|
38241
39821
|
render() {
|
|
38242
39822
|
return b`
|
|
38243
|
-
<span class="handle"
|
|
39823
|
+
<span class="handle ixfx-handle" data-handle="dotted" data-shape="spot" part="handle"></span>
|
|
38244
39824
|
<span class="label">${this.label}</span>
|
|
38245
39825
|
`;
|
|
38246
39826
|
}
|
|
@@ -40117,29 +41697,29 @@ let TwoSplitLayoutElement = class TwoSplitLayoutElement extends i {
|
|
|
40117
41697
|
<slot style=${sizeA} name="a"></slot>
|
|
40118
41698
|
${this._hasCorner ? b`<div class="corner-zone" @pointerdown=${this.#onCornerResizeDown}></div>` : ``}
|
|
40119
41699
|
<div @pointerdown=${this.#onResizeHandleDown} class="split-bar">
|
|
40120
|
-
${this.showGrabHandle ? b
|
|
40121
|
-
|
|
40122
|
-
|
|
40123
|
-
|
|
40124
|
-
|
|
40125
|
-
|
|
40126
|
-
` : ``}
|
|
41700
|
+
${this.showGrabHandle ? b`<span
|
|
41701
|
+
class="ixfx-handle"
|
|
41702
|
+
part="grip"
|
|
41703
|
+
data-handle="dimpled"
|
|
41704
|
+
data-shape=${this.layout === `horizontal` ? `horizontal` : `vertical`}
|
|
41705
|
+
></span>` : ``}
|
|
40127
41706
|
</div>
|
|
40128
41707
|
<slot style=${sizeB} name="b"></slot>
|
|
40129
41708
|
</div>`;
|
|
40130
41709
|
}
|
|
40131
41710
|
static {
|
|
40132
|
-
this.styles = [
|
|
41711
|
+
this.styles = [
|
|
41712
|
+
themeFallbacks,
|
|
41713
|
+
handleStyles,
|
|
41714
|
+
i$3`
|
|
40133
41715
|
:host {
|
|
40134
41716
|
--handle-size: 2px;
|
|
40135
41717
|
--handle-colour: transparent;
|
|
40136
41718
|
--handle-hover-colour: var(--surface-6);
|
|
40137
41719
|
--handle-active-colour: var(--accent);
|
|
40138
|
-
|
|
40139
|
-
--handle-
|
|
40140
|
-
--handle-
|
|
40141
|
-
--handle-grab-size: 16px;
|
|
40142
|
-
--handle-grab-thickness: 8px;
|
|
41720
|
+
/* Grip — shared handle primitive (docs/infra-handle.md). */
|
|
41721
|
+
--ixfx-handle-length: 16px;
|
|
41722
|
+
--ixfx-handle-thickness: 8px;
|
|
40143
41723
|
|
|
40144
41724
|
display: block;
|
|
40145
41725
|
box-sizing: border-box;
|
|
@@ -40182,40 +41762,14 @@ let TwoSplitLayoutElement = class TwoSplitLayoutElement extends i {
|
|
|
40182
41762
|
to { background-color: var(--handle-hover-colour); }
|
|
40183
41763
|
}
|
|
40184
41764
|
|
|
40185
|
-
.
|
|
41765
|
+
.split-bar .ixfx-handle {
|
|
40186
41766
|
position: absolute;
|
|
40187
41767
|
top: 50%;
|
|
40188
41768
|
left: 50%;
|
|
40189
41769
|
transform: translate(-50%, -50%);
|
|
40190
|
-
display: flex;
|
|
40191
|
-
align-items: center;
|
|
40192
|
-
justify-content: center;
|
|
40193
|
-
gap: var(--handle-grab-dot-size);
|
|
40194
|
-
background: var(--handle-bg);
|
|
40195
|
-
border-radius: var(--radius-s);
|
|
40196
|
-
}
|
|
40197
|
-
|
|
40198
|
-
.grab-handle .dot {
|
|
40199
|
-
width: var(--handle-grab-dot-size);
|
|
40200
|
-
height: var(--handle-grab-dot-size);
|
|
40201
|
-
border-radius: 50%;
|
|
40202
|
-
background: var(--handle-grab-colour);
|
|
40203
|
-
flex-shrink: 0;
|
|
40204
|
-
}
|
|
40205
|
-
|
|
40206
|
-
:host([layout="vertical"]) .grab-handle {
|
|
40207
|
-
flex-direction: column;
|
|
40208
|
-
width: var(--handle-grab-thickness);
|
|
40209
|
-
height: var(--handle-grab-size);
|
|
40210
|
-
}
|
|
40211
|
-
|
|
40212
|
-
:host([layout="horizontal"]) .grab-handle {
|
|
40213
|
-
flex-direction: row;
|
|
40214
|
-
width: var(--handle-grab-size);
|
|
40215
|
-
height: var(--handle-grab-thickness);
|
|
40216
41770
|
}
|
|
40217
41771
|
|
|
40218
|
-
#zone.user-resizing .
|
|
41772
|
+
#zone.user-resizing .ixfx-handle {
|
|
40219
41773
|
display: none;
|
|
40220
41774
|
}
|
|
40221
41775
|
#zone.user-resizing {
|
|
@@ -40268,7 +41822,8 @@ let TwoSplitLayoutElement = class TwoSplitLayoutElement extends i {
|
|
|
40268
41822
|
:host([data-collapsed-b]) slot[name="b"] {
|
|
40269
41823
|
display: none;
|
|
40270
41824
|
}
|
|
40271
|
-
`
|
|
41825
|
+
`
|
|
41826
|
+
];
|
|
40272
41827
|
}
|
|
40273
41828
|
};
|
|
40274
41829
|
__decorate([property({ type: String })], TwoSplitLayoutElement.prototype, "layout", void 0);
|
|
@@ -40820,6 +42375,6 @@ function init() {
|
|
|
40820
42375
|
console.log(`Init`);
|
|
40821
42376
|
}
|
|
40822
42377
|
//#endregion
|
|
40823
|
-
export { AcTextElement, AcTokenElement, ButtonElement, Checkbox, ColourPicker, ColourPickerPopup, CrumbNavigationElement, CrumbPathController, CrumbPathElement, DataController, DataDisplayComponent, DataGridElement, DataTableElement, DetailListElement, DockHostElement, DockPanelElement, EditableLabel, EditableNumber, FormElement, FormGroupElement, FormPartElement, GridListElement, GroupedItemListerElement, ICON_CARET_RIGHT, ICON_CHECK, ICON_CHEVRON_DOWN, ICON_CLOSE, IncrSearchTreeController as IncrSearchMillerController, IncrSearchTreeController, IxfxHexEditorElement, IxfxIconElement, IxfxTimelineElement, KeyedElementIndex, LIST_ITEM_MOTION_MS, LIST_SEARCH_COMMAND_IDS, LIST_SEARCH_MODES, LabelledRadialInput, LabelledRangeInput, LabelledSliderInput, LedElement, ListSearchController, ListSelectionController, menu_exports as Menu, MillerBaseElement, MillerListElement, MillerTreeController, NarrowedTextElement, NotificationManager, NotificationPillElement, PanTextElement, PanelElement, PanelGroupElement, PlotDataSeries, PlotHistogram, PlotMultiAxis, PlotSingleAxis, PlotXyAxis, PolarPad, RadialInputElement, RadioGroup, RangeElement, RangeInput, RangeMultiElement, RatingElement, SelectHorizElement, SliderInputElement, SlidingNumberElement, SnackbarElement, SnapContainer, SplitButton, SplitLayoutElement, SplitPanelElement, SwipeElement, TabController, TabListElement, TabListItemElement, TabPanelElement, TabPanelsElement, TextShimmerElement, TickledController, TimelineController, TimelineTrackTabElement, TitlebarElement, ToolbarElement, ToolbarGroupElement, TooltipElement, TransitoryLabelElement, TreeBaseElement, TreeController, TreeDataModel, TreeKeyboardNavController, TreeListElement, TwoSplitLayoutElement, VerticalListElement, XyPad, addPanelToStack, animateListItemIn, animateListItemOut, applyAgeModification, applyHighlights, applySnapshot, attachTimelineInteractions, buildHighlightTargets, buildModel, clearHighlights, collectContainerNames, collectDataResult, collectPanelIds, collectStackPaths, computeColour, computeLeafGeoms, createAcCompletionProvider, createDataListSearchAdapter, createElementIncrSearch, createElementListSearchAdapter, createEmptyLayout, createEmptyStack, createFuzzySearch, createIncrSearch, createPillRenderer, createSplit, createStack, createTreeListAdapter, createTreeListSearchAdapter, createVerticalListAdapter, distribute, extractStack, findNode, findParentOf, findStackOf, findStackPathByName, getActiveDragPanelId, getIcon, getIconEntry, getIconFont, getLeafNeighbours, hasIcon, iconBus, init, insertBeside, isDragging, isMultiMode, isSplit, isStack, keyForElement, listItemFadeKeyframes, listSearchStyles, monitorIndeterminate, moveLeafNodeToEdge, moveLeafStep, normalise, normalize, panelGapIndex, parseColourScaleAttr, parseLayout, pointerOverAnyHost, prefersReducedMotion, readBaseColour, registerFontIcon, registerIcon, registerListSearchCommands, removePanelFromStack, resolveCssVars, resolveGrid, resolveLeafPath, resolveTracks, serializeLayout, setActive, setIconFont, svgToDataUri, swapLeaves, tickledItemStyles, tickledStyles, timelineStyles, toSnapshot, walk, wrapRoot };
|
|
42378
|
+
export { AcTextElement, AcTokenElement, BottomDrawerElement, ButtonElement, Checkbox, ColourPicker, ColourPickerPopup, CrumbNavigationElement, CrumbPathController, CrumbPathElement, DataController, DataDisplayComponent, DataGridElement, DataTableElement, DetailListElement, DockHostElement, DockPanelElement, EditableLabel, EditableNumber, FormElement, FormGroupElement, FormPartElement, GridListElement, GroupedItemListerElement, ICON_CARET_RIGHT, ICON_CHECK, ICON_CHEVRON_DOWN, ICON_CLOSE, IncrSearchTreeController as IncrSearchMillerController, IncrSearchTreeController, IxfxHexEditorElement, IxfxIconElement, IxfxTimelineElement, KeyedElementIndex, LIST_ITEM_MOTION_MS, LIST_SEARCH_COMMAND_IDS, LIST_SEARCH_MODES, LabelledRadialInput, LabelledRangeInput, LabelledSliderInput, LedElement, ListDragSelectController, ListSearchController, ListSelectionController, menu_exports as Menu, MillerBaseElement, MillerListElement, MillerTreeController, NarrowedTextElement, NotificationManager, NotificationPillElement, PanTextElement, PanelElement, PanelGroupElement, PlotDataSeries, PlotHistogram, PlotMultiAxis, PlotSingleAxis, PlotXyAxis, PolarPad, RadialInputElement, RadioGroup, RangeElement, RangeInput, RangeMultiElement, RatingElement, SelectHorizElement, SliderInputElement, SlidingNumberElement, SnackbarElement, SnapContainer, SplitButton, SplitLayoutElement, SplitPanelElement, SwipeElement, TabController, TabListElement, TabListItemElement, TabPanelElement, TabPanelsElement, TextShimmerElement, TickledController, TimelineController, TimelineTrackTabElement, TitlebarElement, ToolbarElement, ToolbarGroupElement, TooltipElement, TransitoryLabelElement, TreeBaseElement, TreeController, TreeDataModel, TreeKeyboardNavController, TreeListElement, TwoSplitLayoutElement, VerticalListElement, XyPad, addPanelToStack, animateListItemIn, animateListItemOut, applyAgeModification, applyHighlights, applySnapshot, attachTimelineInteractions, bottomDrawerCommandId, buildHighlightTargets, buildModel, clearHighlights, collectContainerNames, collectDataResult, collectPanelIds, collectStackPaths, computeColour, computeLeafGeoms, createAcCompletionProvider, createDataListSearchAdapter, createElementIncrSearch, createElementListSearchAdapter, createEmptyLayout, createEmptyStack, createFuzzySearch, createIncrSearch, createPillRenderer, createSplit, createStack, createTreeListAdapter, createTreeListSearchAdapter, createVerticalListAdapter, distribute, extractStack, findNode, findParentOf, findStackOf, findStackPathByName, getActiveDragPanelId, getIcon, getIconEntry, getIconFont, getLeafNeighbours, hasIcon, iconBus, init, insertBeside, isDragging, isMultiMode, isSplit, isStack, keyForElement, listItemFadeKeyframes, listSearchStyles, monitorIndeterminate, moveLeafNodeToEdge, moveLeafStep, normalise, normalize, panelGapIndex, parseColourScaleAttr, parseLayout, pointerOverAnyHost, prefersReducedMotion, readBaseColour, registerFontIcon, registerIcon, registerListSearchCommands, removePanelFromStack, resolveCssVars, resolveGrid, resolveLeafPath, resolveTracks, serializeLayout, setActive, setIconFont, svgToDataUri, swapLeaves, tickledItemStyles, tickledStyles, timelineStyles, toSnapshot, walk, wrapRoot };
|
|
40824
42379
|
|
|
40825
42380
|
//# sourceMappingURL=index.js.map
|