@ixfx/components 0.11.5 → 0.11.7
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 +70 -1
- package/bundle/index.d.ts.map +1 -1
- package/bundle/index.js +675 -4
- package/bundle/index.js.map +1 -1
- package/dist/checkbox.d.ts +3 -0
- package/dist/checkbox.d.ts.map +1 -1
- package/dist/checkbox.js +24 -1
- package/dist/checkbox.js.map +1 -1
- package/dist/checked-select-CglRukbP.d.ts +59 -0
- package/dist/checked-select-CglRukbP.d.ts.map +1 -0
- package/dist/checked-select-Dejl13qd.js +604 -0
- package/dist/checked-select-Dejl13qd.js.map +1 -0
- package/dist/checked-select.d.ts +2 -0
- package/dist/checked-select.js +3 -0
- package/dist/crumbs.d.ts +1 -1
- package/dist/crumbs.js +1 -1
- package/dist/{data-grid-CPsJBnL4.d.ts → data-grid-C6EjCe5O.d.ts} +2 -2
- package/dist/{data-grid-CPsJBnL4.d.ts.map → data-grid-C6EjCe5O.d.ts.map} +1 -1
- package/dist/data-grid.d.ts +1 -1
- package/dist/data-grid.js +1 -1
- package/dist/{detail-list-CmdCxddo.d.ts → detail-list-CgkOHYOa.d.ts} +3 -1
- package/dist/{detail-list-CmdCxddo.d.ts.map → detail-list-CgkOHYOa.d.ts.map} +1 -1
- package/dist/detail-list.d.ts +1 -1
- package/dist/detail-list.js +22 -0
- package/dist/detail-list.js.map +1 -1
- package/dist/{hex-editor-BiRfwTz1.js → hex-editor-DiYpgIKs.js} +2 -2
- package/dist/{hex-editor-BiRfwTz1.js.map → hex-editor-DiYpgIKs.js.map} +1 -1
- package/dist/hex.js +1 -1
- package/dist/{index-CnyoNA6m.d.ts → index-DyTSt9OK.d.ts} +2 -2
- package/dist/{index-CnyoNA6m.d.ts.map → index-DyTSt9OK.d.ts.map} +1 -1
- package/dist/index.d.ts +6 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -6
- package/dist/index.js.map +1 -1
- package/dist/{menu-BHT6HRND.js → menu-CsBUyUuS.js} +2 -2
- package/dist/{menu-BHT6HRND.js.map → menu-CsBUyUuS.js.map} +1 -1
- package/dist/{menu-item-DT7bKAIw.d.ts → menu-item-BbgdcwBX.d.ts} +10 -1
- package/dist/menu-item-BbgdcwBX.d.ts.map +1 -0
- package/dist/{menu-item-JcpHCyF0.js → menu-item-CfndBGO8.js} +38 -3
- package/dist/menu-item-CfndBGO8.js.map +1 -0
- package/dist/menu.d.ts +2 -2
- package/dist/menu.js +2 -2
- package/dist/plots.js +1 -1
- package/dist/{xy-axis-COKw338Q.js → xy-axis-CyMd_Bn1.js} +2 -2
- package/dist/{xy-axis-COKw338Q.js.map → xy-axis-CyMd_Bn1.js.map} +1 -1
- package/docs-user/README.md +1 -0
- package/docs-user/checked-select.md +63 -0
- package/docs-user/index.json +7 -2
- package/docs-user/llms.txt +1 -0
- package/docs-user/menu.md +30 -9
- package/llms.txt +1 -0
- package/package.json +5 -1
- package/dist/menu-item-DT7bKAIw.d.ts.map +0 -1
- package/dist/menu-item-JcpHCyF0.js.map +0 -1
package/bundle/index.js
CHANGED
|
@@ -5,10 +5,10 @@ import { styleMap } from "lit/directives/style-map.js";
|
|
|
5
5
|
import { unsafeHTML } from "lit/directives/unsafe-html.js";
|
|
6
6
|
import { Fzf } from "fzf";
|
|
7
7
|
import { createCommandRegistry } from "@clinth/ui-commands";
|
|
8
|
+
import { repeat } from "lit/directives/repeat.js";
|
|
8
9
|
import { Colour } from "@ixfx/visual";
|
|
9
10
|
import { Trees } from "@ixfx/collections";
|
|
10
11
|
import { clamp, clamper, rangeStream, round, scaler } from "@ixfx/numbers";
|
|
11
|
-
import { repeat } from "lit/directives/repeat.js";
|
|
12
12
|
import { classMap } from "lit/directives/class-map.js";
|
|
13
13
|
import { createRef, ref } from "lit/directives/ref.js";
|
|
14
14
|
import { Easings } from "@ixfx/modulation";
|
|
@@ -7248,6 +7248,7 @@ let MenuTrigger = class MenuTrigger extends LitElement {
|
|
|
7248
7248
|
this._hasContextTarget = false;
|
|
7249
7249
|
this._anchorName = `--mt-${_MenuTrigger._count++}`;
|
|
7250
7250
|
this._clickListener = this._handleClickOutside.bind(this);
|
|
7251
|
+
this._focusBeforeOpen = null;
|
|
7251
7252
|
this._handlePopoverToggle = (e) => {
|
|
7252
7253
|
if (e.newState === `closed`) {
|
|
7253
7254
|
this._isOpen = false;
|
|
@@ -7264,10 +7265,10 @@ let MenuTrigger = class MenuTrigger extends LitElement {
|
|
|
7264
7265
|
e.preventDefault();
|
|
7265
7266
|
e.stopPropagation();
|
|
7266
7267
|
this._closeMenu();
|
|
7267
|
-
this.
|
|
7268
|
+
this._restoreFocus();
|
|
7268
7269
|
} else if (e.key === `Tab`) {
|
|
7269
7270
|
this._closeMenu();
|
|
7270
|
-
this.
|
|
7271
|
+
this._restoreFocus();
|
|
7271
7272
|
}
|
|
7272
7273
|
};
|
|
7273
7274
|
}
|
|
@@ -7305,6 +7306,7 @@ let MenuTrigger = class MenuTrigger extends LitElement {
|
|
|
7305
7306
|
}
|
|
7306
7307
|
updated(changedProperties) {
|
|
7307
7308
|
if (changedProperties.has(`registry`) || changedProperties.has(`keyboardManager`)) this._propagateContext();
|
|
7309
|
+
if (changedProperties.has(`mode`) || changedProperties.has(`_hasContextTarget`)) this.toggleAttribute(`has-context-target`, this.mode === `context` && this._hasContextTarget);
|
|
7308
7310
|
if (changedProperties.has(`mode`)) this._updatePosition();
|
|
7309
7311
|
}
|
|
7310
7312
|
_updatePosition() {
|
|
@@ -7370,6 +7372,7 @@ let MenuTrigger = class MenuTrigger extends LitElement {
|
|
|
7370
7372
|
}
|
|
7371
7373
|
_openMenu() {
|
|
7372
7374
|
if (this._isOpen || !this._popup?.popover) return;
|
|
7375
|
+
this._focusBeforeOpen = deepActiveElement();
|
|
7373
7376
|
try {
|
|
7374
7377
|
this._popup.showPopover({ source: this });
|
|
7375
7378
|
this._isOpen = true;
|
|
@@ -7411,6 +7414,22 @@ let MenuTrigger = class MenuTrigger extends LitElement {
|
|
|
7411
7414
|
_getMenuContainer() {
|
|
7412
7415
|
return ((this.shadowRoot?.querySelector(`slot[name="menu"]`))?.assignedElements({ flatten: true }) ?? []).find((el) => el.tagName === `IXFX-MENU-CONTAINER`) ?? null;
|
|
7413
7416
|
}
|
|
7417
|
+
/**
|
|
7418
|
+
* Return focus after a keyboard close. The trigger button is the natural
|
|
7419
|
+
* target, but it is not rendered for a context target — then fall back to
|
|
7420
|
+
* whatever was focused at open (don't rely on the browser's popover focus
|
|
7421
|
+
* restoration), and finally the host.
|
|
7422
|
+
*/
|
|
7423
|
+
_restoreFocus() {
|
|
7424
|
+
if (this._triggerBtn) {
|
|
7425
|
+
this._triggerBtn.focus();
|
|
7426
|
+
return;
|
|
7427
|
+
}
|
|
7428
|
+
const previous = this._focusBeforeOpen;
|
|
7429
|
+
this._focusBeforeOpen = null;
|
|
7430
|
+
if (previous?.isConnected && previous !== document.body) previous.focus();
|
|
7431
|
+
else this.focus();
|
|
7432
|
+
}
|
|
7414
7433
|
_handleCommand(e) {
|
|
7415
7434
|
if (this._popup?.popover) try {
|
|
7416
7435
|
this._popup.hidePopover();
|
|
@@ -7454,6 +7473,16 @@ let MenuTrigger = class MenuTrigger extends LitElement {
|
|
|
7454
7473
|
--ixfx-button-padding: var(--ixfx-button-padding, var(--space-s) var(--space-m));
|
|
7455
7474
|
}
|
|
7456
7475
|
|
|
7476
|
+
/* Context mode with a context-target: dissolve the host's box so the
|
|
7477
|
+
slotted surface is itself the item in the consumer's flex/grid layout.
|
|
7478
|
+
Otherwise the host sizes to the surface's full un-scrolled content and
|
|
7479
|
+
a height-constrained parent never clips it. Safe because context opens
|
|
7480
|
+
position the popup at the pointer (fixed), not via the anchor.
|
|
7481
|
+
Override with --menu-trigger-display (e.g. block) to keep a box. */
|
|
7482
|
+
:host([mode="context"][has-context-target]) {
|
|
7483
|
+
display: var(--menu-trigger-display, contents);
|
|
7484
|
+
}
|
|
7485
|
+
|
|
7457
7486
|
.trigger-area {
|
|
7458
7487
|
anchor-name: var(--anchor-name);
|
|
7459
7488
|
/* Block flex (not inline-flex): as an inline-level box this would join
|
|
@@ -7581,6 +7610,12 @@ __decorate([state()], MenuTrigger.prototype, "_hasContextTarget", void 0);
|
|
|
7581
7610
|
__decorate([query(`.trigger-btn`)], MenuTrigger.prototype, "_triggerBtn", void 0);
|
|
7582
7611
|
__decorate([query(`.popup`)], MenuTrigger.prototype, "_popup", void 0);
|
|
7583
7612
|
MenuTrigger = _MenuTrigger = __decorate([safeCustomElement(`ixfx-menu-trigger`)], MenuTrigger);
|
|
7613
|
+
/** `document.activeElement`, followed down through open shadow roots. */
|
|
7614
|
+
function deepActiveElement() {
|
|
7615
|
+
let el = document.activeElement;
|
|
7616
|
+
while (el?.shadowRoot?.activeElement) el = el.shadowRoot.activeElement;
|
|
7617
|
+
return el instanceof HTMLElement ? el : null;
|
|
7618
|
+
}
|
|
7584
7619
|
//#endregion
|
|
7585
7620
|
//#region src/menu/menu-item.ts
|
|
7586
7621
|
let MenuItem = class MenuItem extends LitElement {
|
|
@@ -8203,6 +8238,7 @@ SplitButton = __decorate([safeCustomElement(`ixfx-split-button`)], SplitButton);
|
|
|
8203
8238
|
* Properties
|
|
8204
8239
|
* checked – checkbox state (default: false)
|
|
8205
8240
|
* disabled – disabled state (default: false)
|
|
8241
|
+
* readonly – display-only: no pointer/keyboard interaction, full opacity (default: false)
|
|
8206
8242
|
* label – label text
|
|
8207
8243
|
* name – form field name
|
|
8208
8244
|
* value – form field value
|
|
@@ -8234,12 +8270,14 @@ let Checkbox = class Checkbox extends LitElement {
|
|
|
8234
8270
|
this.checked = false;
|
|
8235
8271
|
this.disabled = false;
|
|
8236
8272
|
this.indeterminate = false;
|
|
8273
|
+
this.readonly = false;
|
|
8237
8274
|
this.label = ``;
|
|
8238
8275
|
this.name = ``;
|
|
8239
8276
|
this.value = ``;
|
|
8240
8277
|
this.#handleChange = (e) => {
|
|
8241
8278
|
const target = e.target;
|
|
8242
8279
|
this.checked = target.checked;
|
|
8280
|
+
this.indeterminate = false;
|
|
8243
8281
|
this.dispatchEvent(new CustomEvent(`change`, {
|
|
8244
8282
|
detail: { checked: this.checked },
|
|
8245
8283
|
bubbles: true,
|
|
@@ -8302,6 +8340,16 @@ let Checkbox = class Checkbox extends LitElement {
|
|
|
8302
8340
|
opacity: var(--box-opacity-checked);
|
|
8303
8341
|
}
|
|
8304
8342
|
|
|
8343
|
+
/* Display-only: inert, keeps full opacity, no hover reveal */
|
|
8344
|
+
:host([readonly]) {
|
|
8345
|
+
pointer-events: none;
|
|
8346
|
+
}
|
|
8347
|
+
:host([readonly]) label,
|
|
8348
|
+
:host([readonly]) label:hover {
|
|
8349
|
+
cursor: default;
|
|
8350
|
+
opacity: var(--box-opacity-checked);
|
|
8351
|
+
}
|
|
8352
|
+
|
|
8305
8353
|
input {
|
|
8306
8354
|
position: absolute;
|
|
8307
8355
|
opacity: 0;
|
|
@@ -8413,6 +8461,10 @@ let Checkbox = class Checkbox extends LitElement {
|
|
|
8413
8461
|
`
|
|
8414
8462
|
];
|
|
8415
8463
|
}
|
|
8464
|
+
/** Focus the inner input, so the host can be focused like a native checkbox. */
|
|
8465
|
+
focus(options) {
|
|
8466
|
+
this.renderRoot.querySelector(`input`)?.focus(options);
|
|
8467
|
+
}
|
|
8416
8468
|
#handleChange;
|
|
8417
8469
|
render() {
|
|
8418
8470
|
return html`
|
|
@@ -8422,6 +8474,8 @@ let Checkbox = class Checkbox extends LitElement {
|
|
|
8422
8474
|
type="checkbox"
|
|
8423
8475
|
.checked=${this.checked}
|
|
8424
8476
|
.disabled=${this.disabled}
|
|
8477
|
+
tabindex=${this.readonly ? `-1` : nothing}
|
|
8478
|
+
aria-hidden=${this.readonly ? `true` : nothing}
|
|
8425
8479
|
.indeterminate=${this.indeterminate}
|
|
8426
8480
|
.name=${this.name}
|
|
8427
8481
|
.value=${this.value}
|
|
@@ -8436,10 +8490,605 @@ let Checkbox = class Checkbox extends LitElement {
|
|
|
8436
8490
|
__decorate([property({ type: Boolean })], Checkbox.prototype, "checked", void 0);
|
|
8437
8491
|
__decorate([property({ type: Boolean })], Checkbox.prototype, "disabled", void 0);
|
|
8438
8492
|
__decorate([property({ type: Boolean })], Checkbox.prototype, "indeterminate", void 0);
|
|
8493
|
+
__decorate([property({
|
|
8494
|
+
type: Boolean,
|
|
8495
|
+
reflect: true
|
|
8496
|
+
})], Checkbox.prototype, "readonly", void 0);
|
|
8439
8497
|
__decorate([property({ type: String })], Checkbox.prototype, "label", void 0);
|
|
8440
8498
|
__decorate([property({ type: String })], Checkbox.prototype, "name", void 0);
|
|
8441
8499
|
__decorate([property({ type: String })], Checkbox.prototype, "value", void 0);
|
|
8442
8500
|
Checkbox = __decorate([safeCustomElement(`ixfx-checkbox`)], Checkbox);
|
|
8501
|
+
//#endregion
|
|
8502
|
+
//#region src/checked-select/logic.ts
|
|
8503
|
+
function byLabel(a, b) {
|
|
8504
|
+
return a.label.localeCompare(b.label, void 0, { sensitivity: `base` });
|
|
8505
|
+
}
|
|
8506
|
+
/** Checked/indeterminate items first, then the rest; each group sorted by label. */
|
|
8507
|
+
function sortForOpen(items) {
|
|
8508
|
+
const on = items.filter((i) => i.checked !== `false`).toSorted(byLabel);
|
|
8509
|
+
const off = items.filter((i) => i.checked === `false`).toSorted(byLabel);
|
|
8510
|
+
return [...on, ...off];
|
|
8511
|
+
}
|
|
8512
|
+
/** User toggle: indeterminate and unchecked become checked, checked becomes unchecked. */
|
|
8513
|
+
function toggleState(state) {
|
|
8514
|
+
return state === `true` ? `false` : `true`;
|
|
8515
|
+
}
|
|
8516
|
+
/** Items shown in the resting state, alphabetically. */
|
|
8517
|
+
function visibleAtRest(items) {
|
|
8518
|
+
return items.filter((i) => i.checked !== `false`).toSorted(byLabel);
|
|
8519
|
+
}
|
|
8520
|
+
const VARIES_LABEL = `(varies)`;
|
|
8521
|
+
/** Resting text entries: checked labels, then a single `(varies)` if any are indeterminate. */
|
|
8522
|
+
function restTextParts(items) {
|
|
8523
|
+
const on = items.filter((i) => i.checked === `true`).toSorted(byLabel).map((i) => i.label);
|
|
8524
|
+
const varies = items.some((i) => i.checked === `indeterminate`) ? [VARIES_LABEL] : [];
|
|
8525
|
+
return [...on, ...varies];
|
|
8526
|
+
}
|
|
8527
|
+
/** Plain-text resting summary, comma separated. */
|
|
8528
|
+
function restText(items) {
|
|
8529
|
+
return restTextParts(items).join(`, `);
|
|
8530
|
+
}
|
|
8531
|
+
/** Returns a new list with the item matching `value` toggled. */
|
|
8532
|
+
function applyToggle(items, value) {
|
|
8533
|
+
return items.map((i) => i.value === value ? {
|
|
8534
|
+
...i,
|
|
8535
|
+
checked: toggleState(i.checked)
|
|
8536
|
+
} : i);
|
|
8537
|
+
}
|
|
8538
|
+
/**
|
|
8539
|
+
* Index of the next label after `current` beginning with `char` (case-insensitive),
|
|
8540
|
+
* wrapping around. Returns -1 if nothing matches.
|
|
8541
|
+
*/
|
|
8542
|
+
function nextMatchIndex(labels, current, char) {
|
|
8543
|
+
const c = char.toLocaleLowerCase();
|
|
8544
|
+
const count = labels.length;
|
|
8545
|
+
for (let step = 1; step <= count; step++) {
|
|
8546
|
+
const index = (current + step + count) % count;
|
|
8547
|
+
if (labels[index].toLocaleLowerCase().startsWith(c)) return index;
|
|
8548
|
+
}
|
|
8549
|
+
return -1;
|
|
8550
|
+
}
|
|
8551
|
+
/** Items in `draft` whose state differs from `original`. */
|
|
8552
|
+
function diffItems(original, draft) {
|
|
8553
|
+
const before = new Map(original.map((i) => [i.value, i.checked]));
|
|
8554
|
+
return draft.filter((i) => before.get(i.value) !== i.checked);
|
|
8555
|
+
}
|
|
8556
|
+
function clampSize(size, min, max) {
|
|
8557
|
+
return {
|
|
8558
|
+
width: Math.min(Math.max(size.width, min.width), Math.max(max.width, min.width)),
|
|
8559
|
+
height: Math.min(Math.max(size.height, min.height), Math.max(max.height, min.height))
|
|
8560
|
+
};
|
|
8561
|
+
}
|
|
8562
|
+
//#endregion
|
|
8563
|
+
//#region src/checked-select/checked-select.ts
|
|
8564
|
+
let instanceCounter = 0;
|
|
8565
|
+
let CheckedSelect = class CheckedSelect extends LitElement {
|
|
8566
|
+
constructor(..._args) {
|
|
8567
|
+
super(..._args);
|
|
8568
|
+
this.items = [];
|
|
8569
|
+
this.multiline = false;
|
|
8570
|
+
this.itemsInert = false;
|
|
8571
|
+
this.itemDisplay = `checkbox`;
|
|
8572
|
+
this.orientation = `horizontal`;
|
|
8573
|
+
this.placeholder = ``;
|
|
8574
|
+
this.disabled = false;
|
|
8575
|
+
this._open = false;
|
|
8576
|
+
this._draft = [];
|
|
8577
|
+
this._order = [];
|
|
8578
|
+
this.#anchorName = `--checked-select-anchor-${instanceCounter++}`;
|
|
8579
|
+
this.#tickled = new TickledController(this, { getItems: () => this._order.map((_, i) => ({ id: i })) });
|
|
8580
|
+
this.#onRestCheckboxChange = (e, value) => {
|
|
8581
|
+
e.stopPropagation();
|
|
8582
|
+
if (this._open) return;
|
|
8583
|
+
const next = applyToggle(this.items, value);
|
|
8584
|
+
this.#emitChange(next, diffItems(this.items, next));
|
|
8585
|
+
this.#focusRestCheckbox(value);
|
|
8586
|
+
};
|
|
8587
|
+
this.#onDocumentPointerDown = (e) => {
|
|
8588
|
+
const path = e.composedPath();
|
|
8589
|
+
const popup = this.#popup;
|
|
8590
|
+
const trigger = this.#trigger;
|
|
8591
|
+
if (popup && path.includes(popup) || trigger && path.includes(trigger)) return;
|
|
8592
|
+
this.cancel();
|
|
8593
|
+
};
|
|
8594
|
+
this.#onTriggerClick = (e) => {
|
|
8595
|
+
if (e.target.closest?.(`ixfx-checkbox`)) return;
|
|
8596
|
+
const scroller = e.composedPath()[0];
|
|
8597
|
+
if (scroller.classList?.contains(`rest-items`) && e instanceof MouseEvent && (e.offsetX > scroller.clientWidth || e.offsetY > scroller.clientHeight)) return;
|
|
8598
|
+
if (this._open) this.commit();
|
|
8599
|
+
else this.open();
|
|
8600
|
+
};
|
|
8601
|
+
this.#onTriggerKeyDown = (e) => {
|
|
8602
|
+
if (this._open || e.target !== e.currentTarget) return;
|
|
8603
|
+
if (e.key === `Enter` || e.key === ` ` || e.key === `ArrowDown`) {
|
|
8604
|
+
e.preventDefault();
|
|
8605
|
+
this.open();
|
|
8606
|
+
}
|
|
8607
|
+
};
|
|
8608
|
+
this.#onListKeyDown = (e) => {
|
|
8609
|
+
const rows = this.#rows();
|
|
8610
|
+
switch (e.key) {
|
|
8611
|
+
case `ArrowDown`:
|
|
8612
|
+
e.preventDefault();
|
|
8613
|
+
this.#tickled.handleKeyboardNavigation(`next`);
|
|
8614
|
+
this.#scrollToCursor();
|
|
8615
|
+
return;
|
|
8616
|
+
case `ArrowUp`:
|
|
8617
|
+
e.preventDefault();
|
|
8618
|
+
this.#tickled.handleKeyboardNavigation(`previous`);
|
|
8619
|
+
this.#scrollToCursor();
|
|
8620
|
+
return;
|
|
8621
|
+
case `Home`:
|
|
8622
|
+
e.preventDefault();
|
|
8623
|
+
this.#tickled.handleKeyboardNavigation(`first`);
|
|
8624
|
+
this.#scrollToCursor();
|
|
8625
|
+
return;
|
|
8626
|
+
case `End`:
|
|
8627
|
+
e.preventDefault();
|
|
8628
|
+
this.#tickled.handleKeyboardNavigation(`last`);
|
|
8629
|
+
this.#scrollToCursor();
|
|
8630
|
+
return;
|
|
8631
|
+
case ` `: {
|
|
8632
|
+
e.preventDefault();
|
|
8633
|
+
const row = rows[this.#tickled.tickledId ?? -1];
|
|
8634
|
+
if (row) this.#toggleRow(row.value);
|
|
8635
|
+
return;
|
|
8636
|
+
}
|
|
8637
|
+
case `Enter`:
|
|
8638
|
+
e.preventDefault();
|
|
8639
|
+
this.commit();
|
|
8640
|
+
return;
|
|
8641
|
+
case `Escape`:
|
|
8642
|
+
e.preventDefault();
|
|
8643
|
+
this.cancel();
|
|
8644
|
+
return;
|
|
8645
|
+
case `Tab`:
|
|
8646
|
+
this.cancel();
|
|
8647
|
+
return;
|
|
8648
|
+
}
|
|
8649
|
+
if (e.key.length === 1 && !e.ctrlKey && !e.metaKey && !e.altKey) {
|
|
8650
|
+
const next = nextMatchIndex(rows.map((r) => r.label), this.#tickled.tickledId ?? -1, e.key);
|
|
8651
|
+
if (next >= 0) {
|
|
8652
|
+
this.#tickled.handleKeyboardNavigation(next);
|
|
8653
|
+
this.#scrollToCursor();
|
|
8654
|
+
}
|
|
8655
|
+
}
|
|
8656
|
+
};
|
|
8657
|
+
this.#onResizeDown = (e) => {
|
|
8658
|
+
const frame = this.shadowRoot?.querySelector(`.frame`);
|
|
8659
|
+
const zone = e.currentTarget;
|
|
8660
|
+
if (!frame) return;
|
|
8661
|
+
e.preventDefault();
|
|
8662
|
+
const start = frame.getBoundingClientRect();
|
|
8663
|
+
const originX = e.clientX;
|
|
8664
|
+
const originY = e.clientY;
|
|
8665
|
+
const style = getComputedStyle(this);
|
|
8666
|
+
const min = {
|
|
8667
|
+
width: Number.parseFloat(style.getPropertyValue(`--checked-select-min-width`)) || 128,
|
|
8668
|
+
height: Number.parseFloat(style.getPropertyValue(`--checked-select-min-height`)) || 80
|
|
8669
|
+
};
|
|
8670
|
+
const max = {
|
|
8671
|
+
width: window.innerWidth - start.left - 8,
|
|
8672
|
+
height: window.innerHeight - start.top - 8
|
|
8673
|
+
};
|
|
8674
|
+
zone.setPointerCapture?.(e.pointerId);
|
|
8675
|
+
zone.setAttribute(`data-active`, ``);
|
|
8676
|
+
const onMove = (m) => {
|
|
8677
|
+
this._size = clampSize({
|
|
8678
|
+
width: start.width + m.clientX - originX,
|
|
8679
|
+
height: start.height + m.clientY - originY
|
|
8680
|
+
}, min, max);
|
|
8681
|
+
};
|
|
8682
|
+
const onEnd = () => {
|
|
8683
|
+
zone.removeAttribute(`data-active`);
|
|
8684
|
+
zone.removeEventListener(`pointermove`, onMove);
|
|
8685
|
+
zone.removeEventListener(`pointerup`, onEnd);
|
|
8686
|
+
zone.removeEventListener(`pointercancel`, onEnd);
|
|
8687
|
+
this.#listbox?.focus();
|
|
8688
|
+
};
|
|
8689
|
+
zone.addEventListener(`pointermove`, onMove);
|
|
8690
|
+
zone.addEventListener(`pointerup`, onEnd);
|
|
8691
|
+
zone.addEventListener(`pointercancel`, onEnd);
|
|
8692
|
+
};
|
|
8693
|
+
}
|
|
8694
|
+
static {
|
|
8695
|
+
this.styles = [
|
|
8696
|
+
themeFallbacks,
|
|
8697
|
+
handleStyles,
|
|
8698
|
+
tickledStyles,
|
|
8699
|
+
tickledItemStyles,
|
|
8700
|
+
css`
|
|
8701
|
+
:host {
|
|
8702
|
+
--checked-select-gap: var(--space-m);
|
|
8703
|
+
--checked-select-padding: var(--space-s) var(--space-m);
|
|
8704
|
+
--checked-select-caret-width: 2rem;
|
|
8705
|
+
--checked-select-rest-max-height: 8rem;
|
|
8706
|
+
--checked-select-max-height: 16rem;
|
|
8707
|
+
--checked-select-min-width: 8rem;
|
|
8708
|
+
--checked-select-min-height: 5rem;
|
|
8709
|
+
|
|
8710
|
+
display: block;
|
|
8711
|
+
position: relative;
|
|
8712
|
+
}
|
|
8713
|
+
|
|
8714
|
+
:host([disabled]) {
|
|
8715
|
+
opacity: var(--prominence-disabled-opacity, 0.4);
|
|
8716
|
+
pointer-events: none;
|
|
8717
|
+
}
|
|
8718
|
+
|
|
8719
|
+
.rest {
|
|
8720
|
+
position: relative;
|
|
8721
|
+
box-sizing: border-box;
|
|
8722
|
+
cursor: pointer;
|
|
8723
|
+
background: var(--surface-4);
|
|
8724
|
+
color: var(--surface-4-text);
|
|
8725
|
+
border: var(--border);
|
|
8726
|
+
border-radius: var(--radius-m);
|
|
8727
|
+
user-select: none;
|
|
8728
|
+
}
|
|
8729
|
+
|
|
8730
|
+
.rest-items {
|
|
8731
|
+
display: flex;
|
|
8732
|
+
flex-wrap: nowrap;
|
|
8733
|
+
align-items: center;
|
|
8734
|
+
gap: var(--checked-select-gap);
|
|
8735
|
+
padding: var(--checked-select-padding);
|
|
8736
|
+
/* Room to scroll the last item clear of the caret */
|
|
8737
|
+
padding-inline-end: var(--checked-select-caret-width);
|
|
8738
|
+
min-height: 1.5em;
|
|
8739
|
+
box-sizing: border-box;
|
|
8740
|
+
overflow-x: auto;
|
|
8741
|
+
overflow-y: hidden;
|
|
8742
|
+
scrollbar-width: thin;
|
|
8743
|
+
}
|
|
8744
|
+
:host([multiline]) .rest-items {
|
|
8745
|
+
flex-wrap: wrap;
|
|
8746
|
+
overflow-x: hidden;
|
|
8747
|
+
overflow-y: auto;
|
|
8748
|
+
max-height: var(--checked-select-rest-max-height);
|
|
8749
|
+
/* Wrapping never runs under the caret, so keep its column clear (and the scrollbar beside it) */
|
|
8750
|
+
padding-inline-end: var(--space-m);
|
|
8751
|
+
margin-inline-end: var(--checked-select-caret-width);
|
|
8752
|
+
}
|
|
8753
|
+
|
|
8754
|
+
/* Vertical: one item per row, scrolling vertically beside the caret. Must follow the multiline rule. */
|
|
8755
|
+
:host([orientation="vertical"]) .rest-items {
|
|
8756
|
+
flex-direction: column;
|
|
8757
|
+
flex-wrap: nowrap;
|
|
8758
|
+
align-items: flex-start;
|
|
8759
|
+
overflow-x: hidden;
|
|
8760
|
+
overflow-y: auto;
|
|
8761
|
+
max-height: var(--checked-select-rest-max-height);
|
|
8762
|
+
padding-inline-end: var(--space-m);
|
|
8763
|
+
margin-inline-end: var(--checked-select-caret-width);
|
|
8764
|
+
}
|
|
8765
|
+
|
|
8766
|
+
/* Always-visible caret; items scroll underneath it */
|
|
8767
|
+
.caret {
|
|
8768
|
+
position: absolute;
|
|
8769
|
+
inset-block: 0;
|
|
8770
|
+
inset-inline-end: 0;
|
|
8771
|
+
width: var(--checked-select-caret-width);
|
|
8772
|
+
display: grid;
|
|
8773
|
+
place-items: center;
|
|
8774
|
+
background: inherit;
|
|
8775
|
+
border-radius: inherit;
|
|
8776
|
+
pointer-events: auto;
|
|
8777
|
+
}
|
|
8778
|
+
.caret svg {
|
|
8779
|
+
width: 1.1em;
|
|
8780
|
+
height: 1.1em;
|
|
8781
|
+
fill: none;
|
|
8782
|
+
stroke: currentColor;
|
|
8783
|
+
stroke-width: 2;
|
|
8784
|
+
stroke-linecap: round;
|
|
8785
|
+
stroke-linejoin: round;
|
|
8786
|
+
transition: rotate var(--transition, 0.1s ease-out);
|
|
8787
|
+
}
|
|
8788
|
+
.rest[aria-expanded="true"] .caret svg {
|
|
8789
|
+
rotate: 180deg;
|
|
8790
|
+
}
|
|
8791
|
+
/* While the popup is open its draft is authoritative */
|
|
8792
|
+
.rest[aria-expanded="true"] ixfx-checkbox {
|
|
8793
|
+
pointer-events: none;
|
|
8794
|
+
}
|
|
8795
|
+
.rest:hover {
|
|
8796
|
+
background: var(--surface-5);
|
|
8797
|
+
}
|
|
8798
|
+
.rest:focus-visible {
|
|
8799
|
+
outline: 2px solid var(--accent);
|
|
8800
|
+
outline-offset: 2px;
|
|
8801
|
+
}
|
|
8802
|
+
.rest ixfx-checkbox {
|
|
8803
|
+
flex-shrink: 0;
|
|
8804
|
+
}
|
|
8805
|
+
.rest-text {
|
|
8806
|
+
white-space: nowrap;
|
|
8807
|
+
}
|
|
8808
|
+
:host([multiline]) .rest-text {
|
|
8809
|
+
white-space: normal;
|
|
8810
|
+
}
|
|
8811
|
+
.placeholder {
|
|
8812
|
+
opacity: 0.6;
|
|
8813
|
+
}
|
|
8814
|
+
|
|
8815
|
+
.popup {
|
|
8816
|
+
/* Reset popover UA styles */
|
|
8817
|
+
inset: unset;
|
|
8818
|
+
margin: 0;
|
|
8819
|
+
padding: 0;
|
|
8820
|
+
border: none;
|
|
8821
|
+
background: transparent;
|
|
8822
|
+
overflow: visible;
|
|
8823
|
+
|
|
8824
|
+
/* CSS anchor positioning — position-anchor set inline */
|
|
8825
|
+
position: fixed;
|
|
8826
|
+
left: anchor(left);
|
|
8827
|
+
top: anchor(bottom);
|
|
8828
|
+
/* anchor-size() only works on the anchored element itself, so the width lives here */
|
|
8829
|
+
width: anchor-size(width);
|
|
8830
|
+
min-width: var(--checked-select-min-width);
|
|
8831
|
+
position-try-fallbacks: flip-block;
|
|
8832
|
+
margin-block: 4px;
|
|
8833
|
+
z-index: 100;
|
|
8834
|
+
}
|
|
8835
|
+
|
|
8836
|
+
.frame {
|
|
8837
|
+
position: relative;
|
|
8838
|
+
box-sizing: border-box;
|
|
8839
|
+
display: flex;
|
|
8840
|
+
flex-direction: column;
|
|
8841
|
+
width: 100%;
|
|
8842
|
+
max-height: var(--checked-select-max-height);
|
|
8843
|
+
background: var(--surface-3);
|
|
8844
|
+
color: var(--surface-3-text);
|
|
8845
|
+
border: var(--border);
|
|
8846
|
+
border-radius: var(--radius-m);
|
|
8847
|
+
}
|
|
8848
|
+
|
|
8849
|
+
.listbox {
|
|
8850
|
+
flex: 1;
|
|
8851
|
+
min-height: 0;
|
|
8852
|
+
overflow-y: auto;
|
|
8853
|
+
padding: var(--space-s);
|
|
8854
|
+
outline: none;
|
|
8855
|
+
}
|
|
8856
|
+
.listbox:focus-visible {
|
|
8857
|
+
outline: 2px solid var(--accent);
|
|
8858
|
+
outline-offset: -2px;
|
|
8859
|
+
}
|
|
8860
|
+
|
|
8861
|
+
.item {
|
|
8862
|
+
display: flex;
|
|
8863
|
+
width: 100%;
|
|
8864
|
+
box-sizing: border-box;
|
|
8865
|
+
}
|
|
8866
|
+
|
|
8867
|
+
/* Key-repeat outpaces the fade, smearing the cursor across rows. Snap while
|
|
8868
|
+
the keyboard drives the cursor; hover (mouse mode) keeps the transition. */
|
|
8869
|
+
.listbox[data-input-mode="keyboard"] .item {
|
|
8870
|
+
transition: none;
|
|
8871
|
+
}
|
|
8872
|
+
|
|
8873
|
+
.resize-zone {
|
|
8874
|
+
position: absolute;
|
|
8875
|
+
inset-block-end: 0;
|
|
8876
|
+
inset-inline-end: 0;
|
|
8877
|
+
width: 16px;
|
|
8878
|
+
height: 16px;
|
|
8879
|
+
display: grid;
|
|
8880
|
+
place-items: center;
|
|
8881
|
+
cursor: nwse-resize;
|
|
8882
|
+
touch-action: none;
|
|
8883
|
+
}
|
|
8884
|
+
.resize-zone .ixfx-handle {
|
|
8885
|
+
--ixfx-handle-spot-size: 10px;
|
|
8886
|
+
}
|
|
8887
|
+
`
|
|
8888
|
+
];
|
|
8889
|
+
}
|
|
8890
|
+
#anchorName;
|
|
8891
|
+
#tickled;
|
|
8892
|
+
get isOpen() {
|
|
8893
|
+
return this._open;
|
|
8894
|
+
}
|
|
8895
|
+
get #trigger() {
|
|
8896
|
+
return this.shadowRoot?.querySelector(`.rest`) ?? null;
|
|
8897
|
+
}
|
|
8898
|
+
get #popup() {
|
|
8899
|
+
return this.shadowRoot?.querySelector(`.popup`) ?? null;
|
|
8900
|
+
}
|
|
8901
|
+
get #listbox() {
|
|
8902
|
+
return this.shadowRoot?.querySelector(`.listbox`) ?? null;
|
|
8903
|
+
}
|
|
8904
|
+
/** Draft items in their frozen open-time order. */
|
|
8905
|
+
#rows() {
|
|
8906
|
+
const byValue = new Map(this._draft.map((i) => [i.value, i]));
|
|
8907
|
+
return this._order.flatMap((v) => byValue.get(v) ?? []);
|
|
8908
|
+
}
|
|
8909
|
+
disconnectedCallback() {
|
|
8910
|
+
super.disconnectedCallback();
|
|
8911
|
+
document.removeEventListener(`pointerdown`, this.#onDocumentPointerDown, true);
|
|
8912
|
+
}
|
|
8913
|
+
willUpdate(changed) {
|
|
8914
|
+
super.willUpdate(changed);
|
|
8915
|
+
if (changed.has(`disabled`) && this.disabled && this._open) this.cancel();
|
|
8916
|
+
}
|
|
8917
|
+
async open() {
|
|
8918
|
+
if (this._open || this.disabled) return;
|
|
8919
|
+
this._draft = this.items;
|
|
8920
|
+
this._order = sortForOpen(this.items).map((i) => i.value);
|
|
8921
|
+
this._size = void 0;
|
|
8922
|
+
this._open = true;
|
|
8923
|
+
if (this._order.length > 0) this.#tickled.handleKeyboardNavigation(`first`);
|
|
8924
|
+
document.addEventListener(`pointerdown`, this.#onDocumentPointerDown, true);
|
|
8925
|
+
await this.updateComplete;
|
|
8926
|
+
this.#popup?.showPopover?.();
|
|
8927
|
+
this.#listbox?.focus();
|
|
8928
|
+
}
|
|
8929
|
+
commit() {
|
|
8930
|
+
if (!this._open) return;
|
|
8931
|
+
const changed = diffItems(this.items, this._draft);
|
|
8932
|
+
const next = this._draft;
|
|
8933
|
+
this.#close();
|
|
8934
|
+
if (changed.length === 0) return;
|
|
8935
|
+
this.#emitChange(next, changed);
|
|
8936
|
+
}
|
|
8937
|
+
#emitChange(next, changed) {
|
|
8938
|
+
this.items = next;
|
|
8939
|
+
this.dispatchEvent(new CustomEvent(`change`, {
|
|
8940
|
+
detail: {
|
|
8941
|
+
items: next,
|
|
8942
|
+
changed
|
|
8943
|
+
},
|
|
8944
|
+
bubbles: true,
|
|
8945
|
+
composed: true
|
|
8946
|
+
}));
|
|
8947
|
+
}
|
|
8948
|
+
/** A resting checkbox was used directly: toggle and commit immediately. */
|
|
8949
|
+
#onRestCheckboxChange;
|
|
8950
|
+
async #focusRestCheckbox(value) {
|
|
8951
|
+
await this.updateComplete;
|
|
8952
|
+
(this.shadowRoot?.querySelector(`.rest ixfx-checkbox[data-value="${CSS.escape(value)}"]`) ?? this.#trigger)?.focus();
|
|
8953
|
+
}
|
|
8954
|
+
cancel() {
|
|
8955
|
+
if (!this._open) return;
|
|
8956
|
+
this.#close();
|
|
8957
|
+
}
|
|
8958
|
+
#close() {
|
|
8959
|
+
document.removeEventListener(`pointerdown`, this.#onDocumentPointerDown, true);
|
|
8960
|
+
this.#popup?.hidePopover?.();
|
|
8961
|
+
this._open = false;
|
|
8962
|
+
this._draft = [];
|
|
8963
|
+
this.#tickled.clearTickled();
|
|
8964
|
+
this.#trigger?.focus();
|
|
8965
|
+
}
|
|
8966
|
+
#onDocumentPointerDown;
|
|
8967
|
+
#onTriggerClick;
|
|
8968
|
+
#onTriggerKeyDown;
|
|
8969
|
+
#toggleRow(value) {
|
|
8970
|
+
this._draft = applyToggle(this._draft, value);
|
|
8971
|
+
}
|
|
8972
|
+
#onRowClick(value, index) {
|
|
8973
|
+
this.#tickled.setTickled(index);
|
|
8974
|
+
this.#toggleRow(value);
|
|
8975
|
+
}
|
|
8976
|
+
#onListKeyDown;
|
|
8977
|
+
async #scrollToCursor() {
|
|
8978
|
+
await this.updateComplete;
|
|
8979
|
+
const index = this.#tickled.tickledId;
|
|
8980
|
+
this.shadowRoot?.querySelector(`[data-index="${index}"]`)?.scrollIntoView?.({ block: `nearest` });
|
|
8981
|
+
}
|
|
8982
|
+
#onResizeDown;
|
|
8983
|
+
#renderRest() {
|
|
8984
|
+
const shown = visibleAtRest(this.items);
|
|
8985
|
+
if (shown.length === 0) return html`<span class="placeholder">${this.placeholder}</span>`;
|
|
8986
|
+
if (this.itemDisplay === `text`) {
|
|
8987
|
+
if (this.orientation === `vertical`) return restTextParts(this.items).map((part) => html`<span class="rest-text">${part}</span>`);
|
|
8988
|
+
return html`<span class="rest-text">${restText(this.items)}</span>`;
|
|
8989
|
+
}
|
|
8990
|
+
return repeat(shown, (i) => i.value, (i) => html`
|
|
8991
|
+
<ixfx-checkbox
|
|
8992
|
+
?readonly=${this.itemsInert}
|
|
8993
|
+
data-value=${i.value}
|
|
8994
|
+
label=${i.label}
|
|
8995
|
+
.checked=${i.checked === `true`}
|
|
8996
|
+
.indeterminate=${i.checked === `indeterminate`}
|
|
8997
|
+
@change=${(e) => this.#onRestCheckboxChange(e, i.value)}
|
|
8998
|
+
></ixfx-checkbox>`);
|
|
8999
|
+
}
|
|
9000
|
+
#renderRow(row, index) {
|
|
9001
|
+
return html`
|
|
9002
|
+
<div
|
|
9003
|
+
class="item ${this.#tickled.isTickled(index) ? `tickled` : ``}"
|
|
9004
|
+
role="option"
|
|
9005
|
+
id="opt-${index}"
|
|
9006
|
+
data-index=${index}
|
|
9007
|
+
aria-checked=${row.checked === `indeterminate` ? `mixed` : row.checked}
|
|
9008
|
+
@pointerenter=${() => this.#tickled.handlePointerEnter(index)}
|
|
9009
|
+
@click=${() => this.#onRowClick(row.value, index)}
|
|
9010
|
+
>
|
|
9011
|
+
<ixfx-checkbox
|
|
9012
|
+
readonly
|
|
9013
|
+
label=${row.label}
|
|
9014
|
+
.checked=${row.checked === `true`}
|
|
9015
|
+
.indeterminate=${row.checked === `indeterminate`}
|
|
9016
|
+
></ixfx-checkbox>
|
|
9017
|
+
</div>`;
|
|
9018
|
+
}
|
|
9019
|
+
render() {
|
|
9020
|
+
const rows = this._open ? this.#rows() : [];
|
|
9021
|
+
const cursor = this.#tickled.tickledId;
|
|
9022
|
+
const popupSize = this._size ? `width: ${this._size.width}px;` : ``;
|
|
9023
|
+
const frameStyle = this._size ? `height: ${this._size.height}px; max-height: none;` : ``;
|
|
9024
|
+
const summary = visibleAtRest(this.items).map((i) => i.label).join(`, `);
|
|
9025
|
+
return html`
|
|
9026
|
+
<div
|
|
9027
|
+
class="rest"
|
|
9028
|
+
role="combobox"
|
|
9029
|
+
tabindex=${this.disabled ? `-1` : `0`}
|
|
9030
|
+
aria-haspopup="listbox"
|
|
9031
|
+
aria-expanded=${this._open ? `true` : `false`}
|
|
9032
|
+
aria-disabled=${this.disabled ? `true` : nothing}
|
|
9033
|
+
title=${summary || nothing}
|
|
9034
|
+
style="anchor-name: ${this.#anchorName}"
|
|
9035
|
+
@click=${this.#onTriggerClick}
|
|
9036
|
+
@keydown=${this.#onTriggerKeyDown}
|
|
9037
|
+
>
|
|
9038
|
+
<div class="rest-items">${this.#renderRest()}</div>
|
|
9039
|
+
<div class="caret" aria-hidden="true">
|
|
9040
|
+
<svg viewBox="0 0 24 24"><path d="m6 9 6 6 6-6" /></svg>
|
|
9041
|
+
</div>
|
|
9042
|
+
</div>
|
|
9043
|
+
<div class="popup" popover="manual" style="position-anchor: ${this.#anchorName}; ${popupSize}">
|
|
9044
|
+
<div class="frame" style=${frameStyle}>
|
|
9045
|
+
<div
|
|
9046
|
+
class="listbox"
|
|
9047
|
+
role="listbox"
|
|
9048
|
+
aria-multiselectable="true"
|
|
9049
|
+
tabindex="-1"
|
|
9050
|
+
aria-activedescendant=${cursor === void 0 ? nothing : `opt-${cursor}`}
|
|
9051
|
+
data-input-mode=${this.#tickled.inputMode}
|
|
9052
|
+
@pointerleave=${(e) => this.#tickled.handlePointerLeave(e)}
|
|
9053
|
+
@keydown=${this.#onListKeyDown}
|
|
9054
|
+
>${rows.map((r, i) => this.#renderRow(r, i))}</div>
|
|
9055
|
+
<div class="resize-zone" @pointerdown=${this.#onResizeDown}>
|
|
9056
|
+
<span class="ixfx-handle" data-handle="dotted" data-shape="spot" part="handle"></span>
|
|
9057
|
+
</div>
|
|
9058
|
+
</div>
|
|
9059
|
+
</div>
|
|
9060
|
+
`;
|
|
9061
|
+
}
|
|
9062
|
+
};
|
|
9063
|
+
__decorate([property({ type: Array })], CheckedSelect.prototype, "items", void 0);
|
|
9064
|
+
__decorate([property({
|
|
9065
|
+
type: Boolean,
|
|
9066
|
+
reflect: true
|
|
9067
|
+
})], CheckedSelect.prototype, "multiline", void 0);
|
|
9068
|
+
__decorate([property({
|
|
9069
|
+
type: Boolean,
|
|
9070
|
+
attribute: `items-inert`,
|
|
9071
|
+
reflect: true
|
|
9072
|
+
})], CheckedSelect.prototype, "itemsInert", void 0);
|
|
9073
|
+
__decorate([property({
|
|
9074
|
+
type: String,
|
|
9075
|
+
attribute: `item-display`,
|
|
9076
|
+
reflect: true
|
|
9077
|
+
})], CheckedSelect.prototype, "itemDisplay", void 0);
|
|
9078
|
+
__decorate([property({
|
|
9079
|
+
type: String,
|
|
9080
|
+
reflect: true
|
|
9081
|
+
})], CheckedSelect.prototype, "orientation", void 0);
|
|
9082
|
+
__decorate([property({ type: String })], CheckedSelect.prototype, "placeholder", void 0);
|
|
9083
|
+
__decorate([property({
|
|
9084
|
+
type: Boolean,
|
|
9085
|
+
reflect: true
|
|
9086
|
+
})], CheckedSelect.prototype, "disabled", void 0);
|
|
9087
|
+
__decorate([state()], CheckedSelect.prototype, "_open", void 0);
|
|
9088
|
+
__decorate([state()], CheckedSelect.prototype, "_draft", void 0);
|
|
9089
|
+
__decorate([state()], CheckedSelect.prototype, "_order", void 0);
|
|
9090
|
+
__decorate([state()], CheckedSelect.prototype, "_size", void 0);
|
|
9091
|
+
CheckedSelect = __decorate([safeCustomElement(`ixfx-checked-select`)], CheckedSelect);
|
|
8443
9092
|
const RANGE_LIMITS = {
|
|
8444
9093
|
l: [0, 1],
|
|
8445
9094
|
c: [0, .4],
|
|
@@ -16527,6 +17176,14 @@ DataTableElement = __decorate([safeCustomElement(`ixfx-data-table`)], DataTableE
|
|
|
16527
17176
|
//#region src/detail-list/detail-list.ts
|
|
16528
17177
|
const ITEM_SELECTOR$3 = `:scope > li`;
|
|
16529
17178
|
const SEARCH_HIGHLIGHT_KEY = `detail-list-search`;
|
|
17179
|
+
const NAV_KEYS = /* @__PURE__ */ new Set([
|
|
17180
|
+
`ArrowDown`,
|
|
17181
|
+
`ArrowUp`,
|
|
17182
|
+
`ArrowLeft`,
|
|
17183
|
+
`ArrowRight`,
|
|
17184
|
+
`Home`,
|
|
17185
|
+
`End`
|
|
17186
|
+
]);
|
|
16530
17187
|
const LABEL_SPAN_CSS = `overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0`;
|
|
16531
17188
|
/**
|
|
16532
17189
|
* Layout for the per-item badge wrapper `#ensureBadge` adds. Applied as inline
|
|
@@ -16697,6 +17354,9 @@ let DetailListElement = class DetailListElement extends LitElement {
|
|
|
16697
17354
|
this._onPointerLeave = (e) => {
|
|
16698
17355
|
this.tickled.handlePointerLeave(e);
|
|
16699
17356
|
};
|
|
17357
|
+
this._endKeyboardNav = () => {
|
|
17358
|
+
this.removeAttribute(`data-keyboard-nav`);
|
|
17359
|
+
};
|
|
16700
17360
|
this._onKeyDown = (e) => {
|
|
16701
17361
|
if (this.search.isOpen) return;
|
|
16702
17362
|
if ((e.ctrlKey || e.metaKey) && e.key === `a`) {
|
|
@@ -16706,6 +17366,7 @@ let DetailListElement = class DetailListElement extends LitElement {
|
|
|
16706
17366
|
}
|
|
16707
17367
|
return;
|
|
16708
17368
|
}
|
|
17369
|
+
if (NAV_KEYS.has(e.key)) this.setAttribute(`data-keyboard-nav`, ``);
|
|
16709
17370
|
switch (e.key) {
|
|
16710
17371
|
case `ArrowDown`:
|
|
16711
17372
|
e.preventDefault();
|
|
@@ -16894,6 +17555,8 @@ let DetailListElement = class DetailListElement extends LitElement {
|
|
|
16894
17555
|
this.addEventListener(`pointerover`, this._onPointerOver);
|
|
16895
17556
|
this.addEventListener(`pointerleave`, this._onPointerLeave);
|
|
16896
17557
|
this.addEventListener(`keydown`, this._onKeyDown);
|
|
17558
|
+
this.addEventListener(`pointermove`, this._endKeyboardNav);
|
|
17559
|
+
this.addEventListener(`pointerdown`, this._endKeyboardNav);
|
|
16897
17560
|
this.addEventListener(`click`, this._onClick);
|
|
16898
17561
|
this.addEventListener(`dblclick`, this._onDblClick);
|
|
16899
17562
|
this.addEventListener(`wheel`, this._onWheel);
|
|
@@ -16940,6 +17603,8 @@ let DetailListElement = class DetailListElement extends LitElement {
|
|
|
16940
17603
|
this.removeEventListener(`pointerover`, this._onPointerOver);
|
|
16941
17604
|
this.removeEventListener(`pointerleave`, this._onPointerLeave);
|
|
16942
17605
|
this.removeEventListener(`keydown`, this._onKeyDown);
|
|
17606
|
+
this.removeEventListener(`pointermove`, this._endKeyboardNav);
|
|
17607
|
+
this.removeEventListener(`pointerdown`, this._endKeyboardNav);
|
|
16943
17608
|
this.removeEventListener(`click`, this._onClick);
|
|
16944
17609
|
this.removeEventListener(`dblclick`, this._onDblClick);
|
|
16945
17610
|
this.removeEventListener(`wheel`, this._onWheel);
|
|
@@ -17744,6 +18409,12 @@ let DetailListElement = class DetailListElement extends LitElement {
|
|
|
17744
18409
|
outline: 1px solid transparent;
|
|
17745
18410
|
}
|
|
17746
18411
|
|
|
18412
|
+
/* While navigating by keyboard, key-repeat outpaces the 0.1s fade so the
|
|
18413
|
+
cursor smears across rows. Snap instead. */
|
|
18414
|
+
:host([data-keyboard-nav]) ::slotted(li) {
|
|
18415
|
+
transition: none;
|
|
18416
|
+
}
|
|
18417
|
+
|
|
17747
18418
|
/* In checked mode, only the checkbox column is clickable; the row body
|
|
17748
18419
|
gets a default cursor so it doesn't suggest otherwise. */
|
|
17749
18420
|
:host([interaction-mode="checked"]) ::slotted(li) {
|
|
@@ -53278,6 +53949,6 @@ function init() {
|
|
|
53278
53949
|
console.log(`Init`);
|
|
53279
53950
|
}
|
|
53280
53951
|
//#endregion
|
|
53281
|
-
export { AcTextElement, AcTokenElement, BottomDrawerElement, ButtonElement, Checkbox, ColourPicker, ColourPickerPopup, CrumbNavigationElement, CrumbPathController, CrumbPathElement, DEFAULT_SIBLING_SPACING, DataController, DataDisplayComponent, DataGridElement, DataTableElement, DetailListElement, DockHostElement, DockPanelElement, EditableLabel, EditableNumber, FormElement, FormGroupElement, FormPartElement, GridListElement, GroupedItemListerElement, HyperbolicTreeListElement, ICON_CARET_RIGHT, ICON_CHECK, ICON_CHEVRON_DOWN, ICON_CLOSE, IcicleTreeListElement, IncrSearchTreeController as IncrSearchMillerController, IncrSearchTreeController, IxfxHexEditorElement, IxfxIconElement, IxfxTimelineElement, KeyedElementIndex, LIST_ITEM_MOTION_MS, LIST_SEARCH_COMMAND_IDS, LIST_SEARCH_MODES, LabelledRadialInput, LabelledRangeInput, LabelledSliderInput, LedElement, ListDragSelectController, ListNativeDragController, ListSearchController, ListSelectionController, menu_exports as Menu, MillerBaseElement, MillerListElement, MillerTreeController, MulticolListElement, NarrowedTextElement, NotificationManager, NotificationPillElement, PanTextElement, PanelElement, PanelGroupElement, PlotDataSeries, PlotHistogram, PlotMultiAxis, PlotSingleAxis, PlotXyAxis, PolarPad, RadialInputElement, RadioGroup, RangeElement, RangeInput, RangeMultiElement, RatingElement, SelectHorizElement, ShapefillValueElement, 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, TreeDropController, TreeKeyboardNavController, TreeListElement, TreemapListElement, TwoSplitLayoutElement, VerticalListElement, XyPad, addPanelToStack, animateListItemIn, animateListItemOut, applyAgeModification, applyHighlights, applyIsometry, applySnapshot, applyTreeDrop, attachTimelineInteractions, bottomDrawerCommandId, buildHighlightTargets, buildModel, captionForEntry, clampToDisk, clearHighlights, collectContainerNames, collectDataResult, collectPanelIds, collectStackPaths, composeIsometry, computeCanonicalPositions, computeColour, computeHyperbolicLayout, computeIcicleLayout, computeLeafGeoms, computeTreemapLayout, createAcCompletionProvider, createDataListSearchAdapter, createDefaultListDragPreview, createElementIncrSearch, createElementListSearchAdapter, createEmptyLayout, createEmptyStack, createFuzzySearch, createIncrSearch, createPillRenderer, createSplit, createStack, createTreeListAdapter, createTreeListSearchAdapter, createVerticalListAdapter, decomposeViewIsometry, distribute, dropTargetFor, euclideanRadiusForHyperbolicDistance, extractStack, findHyperbolicIdOf, findHyperbolicKeyPath, findHyperbolicNode, findHyperbolicPath, findHyperbolicPathById, findIcicleNode, findIciclePath, findNode, findPanelNode, findParentOf, findStackOf, findStackPathByName, findTreemapNode, findTreemapPath, geodesicInterpolate, geodesicPath, geodesicSegment, getActiveDragPanelId, getIcon, getIconEntry, getIconFont, getLeafNeighbours, hasIcon, hyperbolicBranchId, hyperbolicChildIds, hyperbolicDistanceForEuclideanRadius, hyperbolicIdDepth, hyperbolicRelativeFrame, iconBus, identityIsometry, init, insertBeside, invertIsometry, isDragging, isHyperbolicDescendantId, isMultiMode, isSplit, isStack, keyForElement, listItemFadeKeyframes, listSearchStyles, mobiusAdd, mobiusFromOrigin, mobiusToOrigin, monitorIndeterminate, moveLeafNodeToEdge, moveLeafStep, norm, normalise, normaliseValue, normalize, panelGapIndex, parseColourScaleAttr, parseLayout, poincareDistance, pointerOverAnyHost, prefersReducedMotion, preserveRestoreWeights, pruneDraggedDescendants, readBaseColour, registerFontIcon, registerIcon, registerListSearchCommands, removePanelFromStack, resolveCssVars, resolveGrid, resolveLeafPath, resolveTracks, rotationIsometry, serializeLayout, setActive, setIconFont, setPanelRestoreWeight, startListItemOutAnimation, svgToDataUri, swapLeaves, tickledItemStyles, tickledStyles, timelineStyles, toSnapshot, toolbarGapIndex, translationFromOrigin, viewIsometry, walk, wrapRoot };
|
|
53952
|
+
export { AcTextElement, AcTokenElement, BottomDrawerElement, ButtonElement, Checkbox, CheckedSelect, ColourPicker, ColourPickerPopup, CrumbNavigationElement, CrumbPathController, CrumbPathElement, DEFAULT_SIBLING_SPACING, DataController, DataDisplayComponent, DataGridElement, DataTableElement, DetailListElement, DockHostElement, DockPanelElement, EditableLabel, EditableNumber, FormElement, FormGroupElement, FormPartElement, GridListElement, GroupedItemListerElement, HyperbolicTreeListElement, ICON_CARET_RIGHT, ICON_CHECK, ICON_CHEVRON_DOWN, ICON_CLOSE, IcicleTreeListElement, IncrSearchTreeController as IncrSearchMillerController, IncrSearchTreeController, IxfxHexEditorElement, IxfxIconElement, IxfxTimelineElement, KeyedElementIndex, LIST_ITEM_MOTION_MS, LIST_SEARCH_COMMAND_IDS, LIST_SEARCH_MODES, LabelledRadialInput, LabelledRangeInput, LabelledSliderInput, LedElement, ListDragSelectController, ListNativeDragController, ListSearchController, ListSelectionController, menu_exports as Menu, MillerBaseElement, MillerListElement, MillerTreeController, MulticolListElement, NarrowedTextElement, NotificationManager, NotificationPillElement, PanTextElement, PanelElement, PanelGroupElement, PlotDataSeries, PlotHistogram, PlotMultiAxis, PlotSingleAxis, PlotXyAxis, PolarPad, RadialInputElement, RadioGroup, RangeElement, RangeInput, RangeMultiElement, RatingElement, SelectHorizElement, ShapefillValueElement, 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, TreeDropController, TreeKeyboardNavController, TreeListElement, TreemapListElement, TwoSplitLayoutElement, VerticalListElement, XyPad, addPanelToStack, animateListItemIn, animateListItemOut, applyAgeModification, applyHighlights, applyIsometry, applySnapshot, applyTreeDrop, attachTimelineInteractions, bottomDrawerCommandId, buildHighlightTargets, buildModel, captionForEntry, clampToDisk, clearHighlights, collectContainerNames, collectDataResult, collectPanelIds, collectStackPaths, composeIsometry, computeCanonicalPositions, computeColour, computeHyperbolicLayout, computeIcicleLayout, computeLeafGeoms, computeTreemapLayout, createAcCompletionProvider, createDataListSearchAdapter, createDefaultListDragPreview, createElementIncrSearch, createElementListSearchAdapter, createEmptyLayout, createEmptyStack, createFuzzySearch, createIncrSearch, createPillRenderer, createSplit, createStack, createTreeListAdapter, createTreeListSearchAdapter, createVerticalListAdapter, decomposeViewIsometry, distribute, dropTargetFor, euclideanRadiusForHyperbolicDistance, extractStack, findHyperbolicIdOf, findHyperbolicKeyPath, findHyperbolicNode, findHyperbolicPath, findHyperbolicPathById, findIcicleNode, findIciclePath, findNode, findPanelNode, findParentOf, findStackOf, findStackPathByName, findTreemapNode, findTreemapPath, geodesicInterpolate, geodesicPath, geodesicSegment, getActiveDragPanelId, getIcon, getIconEntry, getIconFont, getLeafNeighbours, hasIcon, hyperbolicBranchId, hyperbolicChildIds, hyperbolicDistanceForEuclideanRadius, hyperbolicIdDepth, hyperbolicRelativeFrame, iconBus, identityIsometry, init, insertBeside, invertIsometry, isDragging, isHyperbolicDescendantId, isMultiMode, isSplit, isStack, keyForElement, listItemFadeKeyframes, listSearchStyles, mobiusAdd, mobiusFromOrigin, mobiusToOrigin, monitorIndeterminate, moveLeafNodeToEdge, moveLeafStep, norm, normalise, normaliseValue, normalize, panelGapIndex, parseColourScaleAttr, parseLayout, poincareDistance, pointerOverAnyHost, prefersReducedMotion, preserveRestoreWeights, pruneDraggedDescendants, readBaseColour, registerFontIcon, registerIcon, registerListSearchCommands, removePanelFromStack, resolveCssVars, resolveGrid, resolveLeafPath, resolveTracks, rotationIsometry, serializeLayout, setActive, setIconFont, setPanelRestoreWeight, startListItemOutAnimation, svgToDataUri, swapLeaves, tickledItemStyles, tickledStyles, timelineStyles, toSnapshot, toolbarGapIndex, translationFromOrigin, viewIsometry, walk, wrapRoot };
|
|
53282
53953
|
|
|
53283
53954
|
//# sourceMappingURL=index.js.map
|