@ixfx/components 0.5.16 → 0.5.18

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.
Files changed (51) hide show
  1. package/bundle/index.d.ts +52 -3
  2. package/bundle/index.d.ts.map +1 -1
  3. package/bundle/index.js +438 -160
  4. package/bundle/index.js.map +1 -1
  5. package/dist/ac-text.d.ts +1 -1
  6. package/dist/colour-picker.d.ts +1 -1
  7. package/dist/crumb-navigation-DTwJ8468.js +1123 -0
  8. package/dist/crumb-navigation-DTwJ8468.js.map +1 -0
  9. package/dist/crumbs.d.ts +4 -3
  10. package/dist/crumbs.d.ts.map +1 -1
  11. package/dist/crumbs.js +1 -1101
  12. package/dist/{icon-DpA9x2Ve.d.ts → icon-BUwP1CZ1.d.ts} +2 -2
  13. package/dist/icon-BUwP1CZ1.d.ts.map +1 -0
  14. package/dist/icons.d.ts +2 -2
  15. package/dist/{index-D_ftz_IT.d.ts → index-BKAlRgbq.d.ts} +2 -2
  16. package/dist/{index-D_ftz_IT.d.ts.map → index-BKAlRgbq.d.ts.map} +1 -1
  17. package/dist/{index-CoqtMSd9.d.ts → index-BUB5SICW.d.ts} +2 -2
  18. package/dist/{index-CoqtMSd9.d.ts.map → index-BUB5SICW.d.ts.map} +1 -1
  19. package/dist/{index-DfEkTGvT.d.ts → index-DkhBGHgF.d.ts} +3 -3
  20. package/dist/{index-DfEkTGvT.d.ts.map → index-DkhBGHgF.d.ts.map} +1 -1
  21. package/dist/{index-BtGFYfaK.d.ts → index-RqMh1i-O.d.ts} +2 -2
  22. package/dist/{index-BtGFYfaK.d.ts.map → index-RqMh1i-O.d.ts.map} +1 -1
  23. package/dist/index.d.ts +55 -9
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +259 -5
  26. package/dist/index.js.map +1 -1
  27. package/dist/{labelled-input-base-DiTme1JO.d.ts → labelled-input-base-Dp_9KP0G.d.ts} +2 -2
  28. package/dist/{labelled-input-base-DiTme1JO.d.ts.map → labelled-input-base-Dp_9KP0G.d.ts.map} +1 -1
  29. package/dist/labelled-radial-input.d.ts +2 -2
  30. package/dist/labelled-radial-input.d.ts.map +1 -1
  31. package/dist/labelled-range-input.d.ts +1 -1
  32. package/dist/{menu-B8gE2MSo.js → menu-CdwSe_XN.js} +2 -2
  33. package/dist/{menu-B8gE2MSo.js.map → menu-CdwSe_XN.js.map} +1 -1
  34. package/dist/{menu-item-DSyf9f_L.d.ts → menu-item-BG5w7fi4.d.ts} +4 -2
  35. package/dist/menu-item-BG5w7fi4.d.ts.map +1 -0
  36. package/dist/{menu-item-BYRvfyXK.js → menu-item-CrmUwIoJ.js} +7 -2
  37. package/dist/menu-item-CrmUwIoJ.js.map +1 -0
  38. package/dist/menu.d.ts +2 -2
  39. package/dist/menu.js +2 -2
  40. package/dist/panel.d.ts +1 -1
  41. package/dist/{tab-list-ih-0I0NE.d.ts → tab-list-CLqlPnX-.d.ts} +2 -2
  42. package/dist/{tab-list-ih-0I0NE.d.ts.map → tab-list-CLqlPnX-.d.ts.map} +1 -1
  43. package/dist/tabs.d.ts +1 -1
  44. package/docs-user/README.md +1 -0
  45. package/docs-user/crumbs.md +15 -1
  46. package/docs-user/select-horiz.md +114 -0
  47. package/package.json +1 -1
  48. package/dist/crumbs.js.map +0 -1
  49. package/dist/icon-DpA9x2Ve.d.ts.map +0 -1
  50. package/dist/menu-item-BYRvfyXK.js.map +0 -1
  51. package/dist/menu-item-DSyf9f_L.d.ts.map +0 -1
package/bundle/index.js CHANGED
@@ -3843,6 +3843,7 @@ let MenuTrigger = class MenuTrigger extends i {
3843
3843
  this.mode = `trigger`;
3844
3844
  this.label = `⋮`;
3845
3845
  this.placement = `bottom-start`;
3846
+ this.tabStop = true;
3846
3847
  this._isOpen = false;
3847
3848
  this._hasMenu = false;
3848
3849
  this._hasTriggerSlot = false;
@@ -4105,7 +4106,7 @@ let MenuTrigger = class MenuTrigger extends i {
4105
4106
  @click=${this._handleTriggerClick}
4106
4107
  @contextmenu=${this._handleContextMenu}
4107
4108
  >
4108
- ${showButton ? b`<button class="trigger-btn" part="base">${this.label}</button>` : null}
4109
+ ${showButton ? b`<button class="trigger-btn" part="base" tabindex=${this.tabStop ? `0` : `-1`}>${this.label}</button>` : null}
4109
4110
  <slot name="trigger" @slotchange=${this._handleTriggerSlotChange}></slot>
4110
4111
  </div>
4111
4112
  <div
@@ -4123,6 +4124,10 @@ __decorate([property({ type: String })], MenuTrigger.prototype, "label", void 0)
4123
4124
  __decorate([property({ attribute: false })], MenuTrigger.prototype, "registry", void 0);
4124
4125
  __decorate([property({ attribute: false })], MenuTrigger.prototype, "keyboardManager", void 0);
4125
4126
  __decorate([property({ type: String })], MenuTrigger.prototype, "placement", void 0);
4127
+ __decorate([property({
4128
+ type: Boolean,
4129
+ attribute: `tab-stop`
4130
+ })], MenuTrigger.prototype, "tabStop", void 0);
4126
4131
  __decorate([state()], MenuTrigger.prototype, "_isOpen", void 0);
4127
4132
  __decorate([state()], MenuTrigger.prototype, "_hasMenu", void 0);
4128
4133
  __decorate([state()], MenuTrigger.prototype, "_hasTriggerSlot", void 0);
@@ -6409,6 +6414,72 @@ var TreeDataModel = class {
6409
6414
  }
6410
6415
  };
6411
6416
  //#endregion
6417
+ //#region src/styles/scroll-fade.ts
6418
+ /**
6419
+ * Zero-JS scroll edge fade.
6420
+ *
6421
+ * A CSS alpha mask driven by a scroll-linked animation (`scroll-timeline`),
6422
+ * rather than a JS scroll/resize listener - so it can never go stale after
6423
+ * a resize (widening a scroller so content fully fits clears the fade
6424
+ * immediately, with no JS involved), and it fades the whole element
6425
+ * including its children, not just a background layer that an opaque
6426
+ * item background would hide.
6427
+ *
6428
+ * Apply the returned `.scroll-fade-x` / `.scroll-fade-y` class to
6429
+ * whichever element actually has `overflow` scrolling on that axis.
6430
+ *
6431
+ * CSS variables:
6432
+ * - `--scroll-fade-width` (default `30px`): how far the fade extends from each edge.
6433
+ *
6434
+ * ```ts
6435
+ * import { scrollFadeStyles } from '../styles/scroll-fade.js';
6436
+ *
6437
+ * static styles = [scrollFadeStyles(`x`), css`...`];
6438
+ * ```
6439
+ * ```html
6440
+ * <div class="scroll-fade-x" style="overflow-x: scroll">...</div>
6441
+ * ```
6442
+ */
6443
+ function scrollFadeStyles(axis) {
6444
+ const className = `scroll-fade-${axis}`;
6445
+ const start = `--${className}-start`;
6446
+ const end = `--${className}-end`;
6447
+ const timeline = `--${className}-timeline`;
6448
+ const keyframesName = `${className}-fade`;
6449
+ const gradientDirection = axis === `x` ? `to right` : `to bottom`;
6450
+ return i$3`
6451
+ @property ${r$2(start)} {
6452
+ syntax: '<length>';
6453
+ inherits: false;
6454
+ initial-value: 0px;
6455
+ }
6456
+
6457
+ @property ${r$2(end)} {
6458
+ syntax: '<length>';
6459
+ inherits: false;
6460
+ initial-value: 0px;
6461
+ }
6462
+
6463
+ @keyframes ${r$2(keyframesName)} {
6464
+ 0% { ${r$2(start)}: 0px; }
6465
+ 10%, 100% { ${r$2(start)}: var(--scroll-fade-width, 30px); }
6466
+ 0%, 90% { ${r$2(end)}: var(--scroll-fade-width, 30px); }
6467
+ 100% { ${r$2(end)}: 0px; }
6468
+ }
6469
+
6470
+ .${r$2(className)} {
6471
+ scroll-timeline: ${r$2(timeline)} ${r$2(axis)};
6472
+ animation: ${r$2(keyframesName)};
6473
+ animation-timeline: ${r$2(timeline)};
6474
+ mask-image: linear-gradient(${r$2(gradientDirection)},
6475
+ transparent,
6476
+ black var(${r$2(start)}, 0px) calc(100% - var(${r$2(end)}, 0px)),
6477
+ transparent
6478
+ );
6479
+ }
6480
+ `;
6481
+ }
6482
+ //#endregion
6412
6483
  //#region src/narrowed-text/narrowed-text.ts
6413
6484
  const HIGHLIGHT_KEY = `narrowed-text-highlight`;
6414
6485
  let NarrowedTextElement = class NarrowedTextElement extends i {
@@ -7025,6 +7096,7 @@ let CrumbNavigationElement = class CrumbNavigationElement extends i {
7025
7096
  this.exclusivity = `none`;
7026
7097
  this.selectionFilter = `leaf`;
7027
7098
  this._openIdx = -1;
7099
+ this._isFocused = false;
7028
7100
  this._menuOpen = false;
7029
7101
  this._focusOnNarrowedText = false;
7030
7102
  this.inputMode = ``;
@@ -7042,15 +7114,21 @@ let CrumbNavigationElement = class CrumbNavigationElement extends i {
7042
7114
  if (index !== void 0) this.#onTickled(index);
7043
7115
  }
7044
7116
  });
7117
+ this.#onFocus = () => {
7118
+ this._isFocused = true;
7119
+ };
7120
+ this.#onBlur = () => {
7121
+ this._isFocused = false;
7122
+ };
7045
7123
  this.#onHostClick = () => {
7046
- this.focus();
7124
+ this.#getHostContainer()?.focus();
7047
7125
  };
7048
7126
  this.#onMenuTriggerClose = () => {
7049
7127
  document.removeEventListener(`keydown`, this.#onMenuKeyNav, { capture: true });
7050
7128
  this.#currentOpenTrigger = null;
7051
7129
  this.#menuOpenedByKeyboard = false;
7052
7130
  requestAnimationFrame(() => {
7053
- this.focus();
7131
+ this.#getHostContainer()?.focus();
7054
7132
  });
7055
7133
  };
7056
7134
  this.#onMenuKeyNav = (e) => {
@@ -7064,7 +7142,7 @@ let CrumbNavigationElement = class CrumbNavigationElement extends i {
7064
7142
  const r = this.root;
7065
7143
  const sel = this.selectedNode;
7066
7144
  if (!r || !sel) break;
7067
- const totalItems = (this.#findPath(r, sel) ?? [r]).length + (this.#hasChildOptions() ? 1 : 0);
7145
+ const totalItems = this.#getTickledItems().length;
7068
7146
  const currentTickled = this.tickled.tickledId ?? -1;
7069
7147
  if (e.key === `ArrowLeft`) {
7070
7148
  if (currentTickled > 0) this.tickled.handleKeyboardNavigation(`previous`);
@@ -7073,18 +7151,17 @@ let CrumbNavigationElement = class CrumbNavigationElement extends i {
7073
7151
  }
7074
7152
  }
7075
7153
  };
7076
- this.#onKeyDown = (event) => {
7077
- const e = event;
7154
+ this.#onKeyDown = (e) => {
7078
7155
  const r = this.root;
7079
7156
  const sel = this.selectedNode;
7080
7157
  if (!r || !sel) return;
7081
- const totalItems = (this.#findPath(r, sel) ?? [r]).length + (this.#hasChildOptions() ? 1 : 0);
7158
+ const totalItems = this.#getTickledItems().length;
7082
7159
  const currentTickled = this.tickled.tickledId ?? -1;
7083
7160
  switch (e.key) {
7084
7161
  case `ArrowRight`:
7085
7162
  e.preventDefault();
7086
7163
  if (currentTickled < totalItems - 1) this.tickled.handleKeyboardNavigation(`next`);
7087
- else if (currentTickled === totalItems - 1) this.#shiftFocusToNarrowedText();
7164
+ else if (currentTickled === totalItems - 1 && this.#canFocusSuggestions()) this.#shiftFocusToNarrowedText();
7088
7165
  break;
7089
7166
  case `ArrowLeft`:
7090
7167
  e.preventDefault();
@@ -7104,8 +7181,9 @@ let CrumbNavigationElement = class CrumbNavigationElement extends i {
7104
7181
  }
7105
7182
  break;
7106
7183
  case `Enter`:
7184
+ case ` `:
7107
7185
  e.preventDefault();
7108
- this.#handleEnter();
7186
+ this.#activateTickled();
7109
7187
  break;
7110
7188
  case `Escape`:
7111
7189
  e.preventDefault();
@@ -7113,16 +7191,12 @@ let CrumbNavigationElement = class CrumbNavigationElement extends i {
7113
7191
  this.tickled.clearTickled();
7114
7192
  this.blur();
7115
7193
  break;
7116
- case `Tab`: if (e.shiftKey) {
7117
- e.preventDefault();
7118
- this.#shiftFocusToPath();
7119
- } else if (currentTickled === totalItems - 1) {
7120
- e.preventDefault();
7121
- this._menuOpen = false;
7122
- this._focusOnNarrowedText = true;
7123
- const narrowedText = this.shadowRoot?.querySelector(`ixfx-narrowed-text`);
7124
- if (narrowedText) narrowedText.focus();
7125
- }
7194
+ case `Tab`:
7195
+ if (e.shiftKey) break;
7196
+ if (currentTickled === totalItems - 1 && this.#canFocusSuggestions()) {
7197
+ e.preventDefault();
7198
+ this.#shiftFocusToNarrowedText();
7199
+ }
7126
7200
  }
7127
7201
  };
7128
7202
  this.#onNarrowedTextBlur = () => {
@@ -7133,9 +7207,6 @@ let CrumbNavigationElement = class CrumbNavigationElement extends i {
7133
7207
  this._focusOnNarrowedText = false;
7134
7208
  this.#shiftFocusToPath();
7135
7209
  };
7136
- this.#onMouseOut = (e) => {
7137
- this.tickled.handlePointerLeave(e);
7138
- };
7139
7210
  this.#isWheelScrolling = false;
7140
7211
  this.#onWheel = (e) => {
7141
7212
  const wheelEvent = e;
@@ -7145,16 +7216,14 @@ let CrumbNavigationElement = class CrumbNavigationElement extends i {
7145
7216
  this.#isWheelScrolling = true;
7146
7217
  this.tickled.clearTickled();
7147
7218
  }
7148
- this.scrollLeft += wheelEvent.deltaX + wheelEvent.deltaY;
7219
+ const hostContainer = this.#getHostContainer();
7220
+ if (hostContainer) hostContainer.scrollLeft += wheelEvent.deltaX + wheelEvent.deltaY;
7149
7221
  clearTimeout(this.#wheelScrollTimeout);
7150
7222
  this.#wheelScrollTimeout = setTimeout(() => {
7151
7223
  this.#isWheelScrolling = false;
7152
7224
  }, 150);
7153
7225
  }
7154
7226
  };
7155
- this.#onScroll = () => {
7156
- this.#updateFade();
7157
- };
7158
7227
  this.#currentLeadingSiblings = void 0;
7159
7228
  }
7160
7229
  get selectedNodes() {
@@ -7179,7 +7248,7 @@ let CrumbNavigationElement = class CrumbNavigationElement extends i {
7179
7248
  enabled: true
7180
7249
  });
7181
7250
  });
7182
- if (this.#hasChildOptions()) items.push({
7251
+ if (this.#canFocusSuggestions()) items.push({
7183
7252
  id: pathNodes.length,
7184
7253
  enabled: true
7185
7254
  });
@@ -7215,8 +7284,8 @@ let CrumbNavigationElement = class CrumbNavigationElement extends i {
7215
7284
  if (!r || !sel) return;
7216
7285
  const pathNodes = this.#findPath(r, sel) ?? [r];
7217
7286
  let el = null;
7218
- if (index < pathNodes.length) el = this.shadowRoot?.querySelectorAll(`.crumb-segment`)[index] ?? null;
7219
- else if (index === pathNodes.length) el = this.shadowRoot?.querySelector(`#child-options-trigger`) ?? null;
7287
+ if (this.caretEmbedded && this.#canFocusSuggestions() && index === pathNodes.length) el = this.shadowRoot?.querySelector(`ixfx-narrowed-text`) ?? null;
7288
+ else el = this.shadowRoot?.querySelectorAll(`.crumb-segment`)[index] ?? null;
7220
7289
  el?.scrollIntoView({
7221
7290
  inline: `nearest`,
7222
7291
  block: `nearest`,
@@ -7229,6 +7298,15 @@ let CrumbNavigationElement = class CrumbNavigationElement extends i {
7229
7298
  const isPending = this.#pendingNode === s;
7230
7299
  return (s.children ?? []).length > 0 || isPending;
7231
7300
  }
7301
+ /** True when the suggestions (narrowed-text) sub-part is renderable and focusable. */
7302
+ #canFocusSuggestions() {
7303
+ return this.showSuggestions && this.#hasChildOptions();
7304
+ }
7305
+ #onFocus;
7306
+ #onBlur;
7307
+ #getHostContainer() {
7308
+ return this.shadowRoot?.querySelector(`.host-container`) ?? null;
7309
+ }
7232
7310
  #onHostClick;
7233
7311
  #handleOpenCaretMenu() {
7234
7312
  const currentTickled = this.tickled.tickledId;
@@ -7236,26 +7314,18 @@ let CrumbNavigationElement = class CrumbNavigationElement extends i {
7236
7314
  const r = this.root;
7237
7315
  const sel = this.selectedNode;
7238
7316
  if (!r || !sel) return;
7239
- if (currentTickled < (this.#findPath(r, sel) ?? [r]).length - 1) {
7240
- const trigger = (this.shadowRoot?.querySelectorAll(`.crumb-segment`))?.[currentTickled]?.querySelector(`.caret ixfx-menu-trigger`);
7241
- if (trigger) {
7242
- this.#menuOpenedByKeyboard = true;
7243
- this.#currentOpenTrigger = trigger;
7244
- document.addEventListener(`keydown`, this.#onMenuKeyNav, { capture: true });
7245
- trigger.openMenu();
7246
- this.#propagateInputModeToMenu();
7247
- return;
7248
- }
7317
+ const pathNodes = this.#findPath(r, sel) ?? [r];
7318
+ if (this.caretEmbedded && this.#canFocusSuggestions() && currentTickled === pathNodes.length) {
7319
+ this.#shiftFocusToNarrowedText();
7320
+ return;
7249
7321
  }
7250
- if (this.#hasChildOptions()) {
7251
- const trigger = this.shadowRoot?.querySelector(`#child-options-trigger`);
7252
- if (trigger) {
7253
- this.#menuOpenedByKeyboard = true;
7254
- this.#currentOpenTrigger = trigger;
7255
- document.addEventListener(`keydown`, this.#onMenuKeyNav, { capture: true });
7256
- trigger.openMenu();
7257
- this.#propagateInputModeToMenu();
7258
- }
7322
+ const trigger = (this.shadowRoot?.querySelectorAll(`.crumb-segment`))?.[currentTickled]?.querySelector(`.caret ixfx-menu-trigger`);
7323
+ if (trigger) {
7324
+ this.#menuOpenedByKeyboard = true;
7325
+ this.#currentOpenTrigger = trigger;
7326
+ document.addEventListener(`keydown`, this.#onMenuKeyNav, { capture: true });
7327
+ trigger.openMenu();
7328
+ this.#propagateInputModeToMenu();
7259
7329
  }
7260
7330
  }
7261
7331
  #propagateInputModeToMenu() {
@@ -7268,47 +7338,32 @@ let CrumbNavigationElement = class CrumbNavigationElement extends i {
7268
7338
  #onMenuTriggerClose;
7269
7339
  #onMenuKeyNav;
7270
7340
  #onKeyDown;
7271
- #handleEnter() {
7341
+ /** Activates the currently tickled item, as if it had been clicked. */
7342
+ #activateTickled() {
7343
+ const currentTickled = this.tickled.tickledId;
7344
+ if (currentTickled === void 0) return;
7272
7345
  const r = this.root;
7273
7346
  const sel = this.selectedNode;
7274
7347
  if (!r || !sel) return;
7275
7348
  const pathNodes = this.#findPath(r, sel) ?? [r];
7276
- const hasChildOptions = this.#hasChildOptions();
7277
- const currentTickled = this.tickled.tickledId ?? -1;
7278
- if (currentTickled < pathNodes.length) {
7279
- const node = pathNodes[currentTickled];
7280
- this.#setSelected(node);
7281
- this._menuOpen = false;
7282
- this.dispatchEvent(new CustomEvent(`item-click`, {
7283
- detail: {
7284
- node,
7285
- depth: currentTickled
7286
- },
7287
- bubbles: true,
7288
- composed: true
7289
- }));
7290
- } else if (hasChildOptions && currentTickled === pathNodes.length) {
7291
- this._menuOpen = true;
7292
- this.#menuOpenedByKeyboard = true;
7293
- const trigger = this.shadowRoot?.querySelector(`#child-options-trigger`);
7294
- if (trigger) {
7295
- this.#currentOpenTrigger = trigger;
7296
- document.addEventListener(`keydown`, this.#onMenuKeyNav, { capture: true });
7297
- trigger.openMenu();
7298
- this.#propagateInputModeToMenu();
7299
- }
7349
+ if (this.caretEmbedded && this.#canFocusSuggestions() && currentTickled === pathNodes.length) {
7350
+ this.#shiftFocusToNarrowedText();
7351
+ return;
7300
7352
  }
7353
+ (this.shadowRoot?.querySelector(`.crumb-segment[data-segment-id="${currentTickled}"]`))?.click();
7301
7354
  }
7302
7355
  #shiftFocusToNarrowedText() {
7303
7356
  const narrowedText = this.shadowRoot?.querySelector(`ixfx-narrowed-text`);
7304
7357
  if (narrowedText) {
7358
+ this._menuOpen = false;
7305
7359
  this._focusOnNarrowedText = true;
7306
7360
  narrowedText.focus();
7307
7361
  }
7308
7362
  }
7309
7363
  #shiftFocusToPath() {
7310
7364
  this._focusOnNarrowedText = false;
7311
- this.focus();
7365
+ const hostContainer = this.#getHostContainer();
7366
+ if (hostContainer) hostContainer.focus();
7312
7367
  }
7313
7368
  #onNarrowedTextBlur;
7314
7369
  #onNarrowedTextShiftTab;
@@ -7355,42 +7410,25 @@ let CrumbNavigationElement = class CrumbNavigationElement extends i {
7355
7410
  }
7356
7411
  connectedCallback() {
7357
7412
  super.connectedCallback();
7358
- this.tabIndex = 0;
7359
7413
  this.addEventListener(`click`, this.#onHostClick);
7360
7414
  this.addEventListener(`wheel`, this.#onWheel, { passive: false });
7361
- this.addEventListener(`scroll`, this.#onScroll);
7362
- this.addEventListener(`keydown`, this.#onKeyDown);
7363
- this.addEventListener(`menu-trigger-close`, this.#onMenuTriggerClose);
7364
- this.addEventListener(`mouseout`, this.#onMouseOut);
7365
7415
  }
7366
7416
  disconnectedCallback() {
7367
7417
  super.disconnectedCallback();
7368
7418
  this.removeEventListener(`click`, this.#onHostClick);
7369
7419
  this.removeEventListener(`wheel`, this.#onWheel);
7370
- this.removeEventListener(`scroll`, this.#onScroll);
7371
- this.removeEventListener(`keydown`, this.#onKeyDown);
7372
- this.removeEventListener(`menu-trigger-close`, this.#onMenuTriggerClose);
7373
- this.removeEventListener(`mouseout`, this.#onMouseOut);
7374
7420
  this.#modelUnsubscribe?.();
7375
7421
  this.#modelUnsubscribe = void 0;
7376
7422
  document.removeEventListener(`keydown`, this.#onMenuKeyNav, { capture: true });
7377
7423
  this.#currentOpenTrigger = null;
7378
7424
  }
7379
7425
  firstUpdated() {
7380
- this.scrollLeft = this.scrollWidth - this.clientWidth;
7381
- this.#updateFade();
7426
+ const hostContainer = this.#getHostContainer();
7427
+ if (hostContainer) hostContainer.scrollLeft = hostContainer.scrollWidth - hostContainer.clientWidth;
7382
7428
  }
7383
- #onMouseOut;
7384
7429
  #isWheelScrolling;
7385
7430
  #onWheel;
7386
7431
  #wheelScrollTimeout;
7387
- #onScroll;
7388
- #updateFade() {
7389
- const hasLeftFade = this.scrollLeft > 0;
7390
- const hasRightFade = this.scrollLeft < this.scrollWidth - this.clientWidth - 1;
7391
- this.classList.toggle(`has-left-fade`, hasLeftFade);
7392
- this.classList.toggle(`has-right-fade`, hasRightFade);
7393
- }
7394
7432
  #runLayoutUpdate(_changedProperties) {
7395
7433
  if (!this.shadowRoot) return;
7396
7434
  const hsiElement = this.shadowRoot.querySelector(`.horiz-select-items`);
@@ -7473,7 +7511,7 @@ let CrumbNavigationElement = class CrumbNavigationElement extends i {
7473
7511
  #onLabelClick(node, depth) {
7474
7512
  this._openIdx = -1;
7475
7513
  this.#setSelected(node);
7476
- if (this.leadingCaret) this.#scrollSegmentIntoView(depth);
7514
+ this.#scrollSegmentIntoView(depth);
7477
7515
  this.dispatchEvent(new CustomEvent(`item-click`, {
7478
7516
  detail: {
7479
7517
  node,
@@ -7655,7 +7693,7 @@ let CrumbNavigationElement = class CrumbNavigationElement extends i {
7655
7693
  if (this.caretEmbedded) {
7656
7694
  const canTruncate = !this.noTruncate && !isLast && !isTickled;
7657
7695
  parts.push(b`
7658
- <div class="item crumb-segment ${isTickled ? `tickled` : ``} ${canTruncate ? `truncatable` : ``} ${this.leadingCaret ? `leading-caret` : ``}" data-segment-id="${i}" data-path-index="${i}"
7696
+ <div class="item crumb-segment ${isTickled ? `tickled` : ``} ${canTruncate ? `truncatable` : ``} ${this.leadingCaret ? `leading-caret` : ``} ${isLast ? `last-label` : ``}" data-segment-id="${i}" data-path-index="${i}"
7659
7697
  @click=${(e) => {
7660
7698
  if (e.target.closest(`.caret`)) return;
7661
7699
  this.#onLabelClick(node, i);
@@ -7664,7 +7702,7 @@ let CrumbNavigationElement = class CrumbNavigationElement extends i {
7664
7702
  ${showLeadingCaret ? b`
7665
7703
  <span class="caret ${isOpen ? `open` : ``} ${isPending ? `pending` : ``}">
7666
7704
  ${isPending ? b`<span class="loading-spinner"></span>` : b`
7667
- <ixfx-menu-trigger mode="trigger" label="›" @menu-command=${(e) => this.#onSegmentMenuCommand(e, node, i)}>
7705
+ <ixfx-menu-trigger mode="trigger" label="›" .tabStop=${false} @menu-command=${(e) => this.#onSegmentMenuCommand(e, node, i)}>
7668
7706
  <ixfx-menu-container slot="menu">
7669
7707
  ${siblingMenuItems}
7670
7708
  </ixfx-menu-container>
@@ -7676,7 +7714,7 @@ let CrumbNavigationElement = class CrumbNavigationElement extends i {
7676
7714
  ${showTrailingCaret ? b`
7677
7715
  <span class="caret ${isOpen ? `open` : ``} ${isPending ? `pending` : ``}">
7678
7716
  ${isPending ? b`<span class="loading-spinner"></span>` : b`
7679
- <ixfx-menu-trigger mode="trigger" label="›" placement="right-start" @menu-command=${(e) => this.#onSegmentMenuCommand(e, node, i)}>
7717
+ <ixfx-menu-trigger mode="trigger" label="›" .tabStop=${false} placement="right-start" @menu-command=${(e) => this.#onSegmentMenuCommand(e, node, i)}>
7680
7718
  <ixfx-menu-container slot="menu">
7681
7719
  ${childMenuItems}
7682
7720
  </ixfx-menu-container>
@@ -7698,7 +7736,7 @@ let CrumbNavigationElement = class CrumbNavigationElement extends i {
7698
7736
  >
7699
7737
  <span class="caret ${isOpen ? `open` : ``} ${isPending ? `pending` : ``}">
7700
7738
  ${isPending ? b`<span class="loading-spinner"></span>` : b`
7701
- <ixfx-menu-trigger mode="trigger" label="›" placement="right-start" @menu-command=${(e) => this.#onSegmentMenuCommand(e, node, i)}>
7739
+ <ixfx-menu-trigger mode="trigger" label="›" .tabStop=${false} placement="right-start" @menu-command=${(e) => this.#onSegmentMenuCommand(e, node, i)}>
7702
7740
  <ixfx-menu-container slot="menu">
7703
7741
  ${siblingMenuItems}
7704
7742
  </ixfx-menu-container>
@@ -7712,7 +7750,7 @@ let CrumbNavigationElement = class CrumbNavigationElement extends i {
7712
7750
  const labelTickled = this.tickled.isTickled(segmentId);
7713
7751
  const canTruncate = !this.noTruncate && !isLast && !labelTickled;
7714
7752
  parts.push(b`
7715
- <div class="item crumb-segment ${labelTickled ? `tickled` : ``} ${canTruncate ? `truncatable` : ``}" data-segment-id="${segmentId}" data-path-index="${i}"
7753
+ <div class="item crumb-segment ${labelTickled ? `tickled` : ``} ${canTruncate ? `truncatable` : ``} ${isLast ? `last-label` : ``}" data-segment-id="${segmentId}" data-path-index="${i}"
7716
7754
  @click=${(e) => {
7717
7755
  if (e.target.closest(`.caret`)) return;
7718
7756
  this.#onLabelClick(node, i);
@@ -7733,7 +7771,7 @@ let CrumbNavigationElement = class CrumbNavigationElement extends i {
7733
7771
  >
7734
7772
  <span class="caret ${isOpen ? `open` : ``} ${isPending ? `pending` : ``}">
7735
7773
  ${isPending ? b`<span class="loading-spinner"></span>` : b`
7736
- <ixfx-menu-trigger mode="trigger" label="›" @menu-command=${(e) => this.#onSegmentMenuCommand(e, node, i)}>
7774
+ <ixfx-menu-trigger mode="trigger" label="›" .tabStop=${false} @menu-command=${(e) => this.#onSegmentMenuCommand(e, node, i)}>
7737
7775
  <ixfx-menu-container slot="menu">
7738
7776
  ${childMenuItems}
7739
7777
  </ixfx-menu-container>
@@ -7747,8 +7785,18 @@ let CrumbNavigationElement = class CrumbNavigationElement extends i {
7747
7785
  }
7748
7786
  });
7749
7787
  return b`
7750
- <div class="parts"
7751
- @mouseover=${(e) => {
7788
+ <div
7789
+ class="host-container scroll-fade-x"
7790
+ tabindex="0"
7791
+ @focus=${this.#onFocus}
7792
+ @blur=${this.#onBlur}
7793
+ @keydown=${this.#onKeyDown}
7794
+ @click=${this.#onHostClick}
7795
+ @menu-trigger-close=${this.#onMenuTriggerClose}
7796
+ @mouseout=${(e) => this.tickled.handlePointerLeave(e)}
7797
+ >
7798
+ <div class="parts"
7799
+ @mouseover=${(e) => {
7752
7800
  if (this.#isWheelScrolling) return;
7753
7801
  const target = e.target;
7754
7802
  if (!(target instanceof HTMLElement)) return;
@@ -7769,8 +7817,9 @@ let CrumbNavigationElement = class CrumbNavigationElement extends i {
7769
7817
  composed: true
7770
7818
  }));
7771
7819
  }}
7772
- >${parts}<div class="trailing"></div></div>
7773
- ${this.showSuggestions ? this.#renderChildOptions() : A}
7820
+ >${parts}<div class="trailing"></div></div>
7821
+ ${this.showSuggestions ? this.#renderChildOptions() : A}
7822
+ </div>
7774
7823
  `;
7775
7824
  }
7776
7825
  #renderChildOptions() {
@@ -7822,6 +7871,7 @@ let CrumbNavigationElement = class CrumbNavigationElement extends i {
7822
7871
  themeFallbacks,
7823
7872
  tickledStyles,
7824
7873
  tickledItemStyles,
7874
+ scrollFadeStyles(`x`),
7825
7875
  i$3`
7826
7876
  :host {
7827
7877
  --crumb-item-bg: var(--item-bg, transparent);
@@ -7829,56 +7879,32 @@ let CrumbNavigationElement = class CrumbNavigationElement extends i {
7829
7879
  --crumb-item-text-tickled: var(--item-text-tickled);
7830
7880
  --crumb-item-border: var(--item-border);
7831
7881
  --crumb-item-border-tickled: var(--item-border-tickled);
7832
- --crumb-item-padding: var(--space-xs);
7882
+ --crumb-item-padding: var(--space-s, 2px);
7833
7883
  --crumb-item-border-radius: var(--item-border-radius);
7834
- --crumb-item-gap: var(--space-xs);
7884
+ --crumb-item-gap: var(--item-gap, var(--space-xs));
7835
7885
  --crumb-separator: var(--surface-muted-text);
7836
7886
  --crumb-truncate-min-width: 10ch;
7837
- --crumb-fade-width: 30px;
7838
- --crumb-fade-color: var(--surface-3);
7839
- position: relative;
7840
7887
  display: flex;
7841
- overflow: scroll;
7842
7888
  width: 100%;
7843
- scroll-snap-type: x mandatory;
7844
- scrollbar-width: none;
7845
7889
  }
7846
7890
 
7847
- :host(:focus) {
7848
- outline: none;
7849
- }
7850
-
7851
- :host(:focus) .parts {
7891
+ /* Outline goes on :host, not .host-container: .host-container carries the
7892
+ * scroll-fade mask-image, and CSS masks clip everything painted outside
7893
+ * the masked box - including an outline, which paints outside the border edge. */
7894
+ :host(:focus-within) {
7852
7895
  outline: 2px solid var(--accent);
7853
7896
  outline-offset: 2px;
7854
7897
  }
7855
7898
 
7856
- :host::before,
7857
- :host::after {
7858
- content: '';
7859
- position: absolute;
7860
- top: 0;
7861
- bottom: 0;
7862
- width: var(--crumb-fade-width);
7863
- pointer-events: none;
7864
- opacity: 0;
7865
- transition: opacity 0.2s ease;
7866
- z-index: 1;
7867
- }
7868
-
7869
- :host::before {
7870
- left: 0;
7871
- background: linear-gradient(to right, var(--crumb-fade-color), transparent);
7872
- }
7873
-
7874
- :host::after {
7875
- right: 0;
7876
- background: linear-gradient(to left, var(--crumb-fade-color), transparent);
7877
- }
7878
-
7879
- :host(.has-left-fade)::before,
7880
- :host(.has-right-fade)::after {
7881
- opacity: 1;
7899
+ /* Edge fade (shows/hides based on scroll position) comes from the
7900
+ * shared .scroll-fade-x class - see ../styles/scroll-fade.ts */
7901
+ .host-container {
7902
+ display: flex;
7903
+ width: 100%;
7904
+ outline: none;
7905
+ overflow: scroll;
7906
+ scroll-snap-type: x mandatory;
7907
+ scrollbar-width: none;
7882
7908
  }
7883
7909
 
7884
7910
  .parts {
@@ -7899,22 +7925,13 @@ let CrumbNavigationElement = class CrumbNavigationElement extends i {
7899
7925
  background: var(--crumb-item-bg);
7900
7926
  border: var(--crumb-item-border);
7901
7927
  border-radius: var(--crumb-item-border-radius);
7928
+ padding:0;
7902
7929
  }
7903
7930
 
7904
7931
  .crumb-segment.leading-caret {
7905
7932
  flex-direction: row;
7906
7933
  }
7907
7934
 
7908
- .crumb-segment.leading-caret-only {
7909
- flex-direction: row;
7910
- padding: var(--crumb-item-padding);
7911
- }
7912
-
7913
- .crumb-segment.trailing-caret-only {
7914
- flex-direction: row;
7915
- padding: var(--crumb-item-padding);
7916
- }
7917
-
7918
7935
  .crumb-segment.tickled {
7919
7936
  background: var(--crumb-item-bg-tickled);
7920
7937
  border-color: var(--crumb-item-border-tickled);
@@ -7937,11 +7954,20 @@ let CrumbNavigationElement = class CrumbNavigationElement extends i {
7937
7954
  }
7938
7955
 
7939
7956
  .label {
7957
+ padding: var(--crumb-item-padding);
7940
7958
  cursor: pointer;
7941
7959
  white-space: nowrap;
7942
7960
  color: inherit;
7943
7961
  }
7944
7962
 
7963
+ .crumb-segment.last-label .label {
7964
+ color: var(--crumb-last-label-color, inherit);
7965
+ font-style: var(--crumb-last-label-font-style, inherit);
7966
+ font-weight: var(--crumb-last-label-font-weight, inherit);
7967
+ text-decoration: var(--crumb-last-label-text-decoration, inherit);
7968
+ text-underline-offset: var(--crumb-last-label-text-underline-offset, auto);
7969
+ }
7970
+
7945
7971
  .crumb-segment.tickled .label {
7946
7972
  color: var(--crumb-item-text-tickled);
7947
7973
  overflow: visible;
@@ -7949,13 +7975,12 @@ let CrumbNavigationElement = class CrumbNavigationElement extends i {
7949
7975
  }
7950
7976
 
7951
7977
  .crumb-segment ixfx-menu-trigger {
7952
- --ixfx-button-padding: var(--space-xs) 8px;
7978
+ --ixfx-button-padding: var(--space-s, 2px);
7953
7979
  }
7954
7980
 
7955
7981
  .caret {
7956
7982
  position: relative;
7957
- cursor: pointer;
7958
-
7983
+ cursor: pointer;
7959
7984
  color: var(--crumb-separator);
7960
7985
  display: inline-flex;
7961
7986
  align-items: center;
@@ -7982,7 +8007,6 @@ let CrumbNavigationElement = class CrumbNavigationElement extends i {
7982
8007
  background: none;
7983
8008
  border: none;
7984
8009
  color: inherit;
7985
- padding: 0;
7986
8010
  cursor: pointer;
7987
8011
  font-size: inherit;
7988
8012
  line-height: 1;
@@ -8075,6 +8099,7 @@ __decorate([property({
8075
8099
  attribute: `selection-filter`
8076
8100
  })], CrumbNavigationElement.prototype, "selectionFilter", void 0);
8077
8101
  __decorate([state()], CrumbNavigationElement.prototype, "_openIdx", void 0);
8102
+ __decorate([state()], CrumbNavigationElement.prototype, "_isFocused", void 0);
8078
8103
  __decorate([state()], CrumbNavigationElement.prototype, "_menuOpen", void 0);
8079
8104
  __decorate([state()], CrumbNavigationElement.prototype, "_focusOnNarrowedText", void 0);
8080
8105
  __decorate([property({
@@ -8104,7 +8129,7 @@ __decorate([property({
8104
8129
  __decorate([property({
8105
8130
  type: Boolean,
8106
8131
  reflect: true,
8107
- attribute: `hideroot`
8132
+ attribute: `hide-root`
8108
8133
  })], CrumbNavigationElement.prototype, "hideRoot", void 0);
8109
8134
  CrumbNavigationElement = __decorate([safeCustomElement(`ixfx-crumb-navigation`)], CrumbNavigationElement);
8110
8135
  //#endregion
@@ -8586,7 +8611,7 @@ let CrumbPathElement = class CrumbPathElement extends i {
8586
8611
  ${this.separator}
8587
8612
  </div>` : A;
8588
8613
  return b`
8589
- <div class="crumbs" tabindex="0" @keydown=${this.#onHostKeyDown}>
8614
+ <div class="crumbs scroll-fade-x" tabindex="0" @keydown=${this.#onHostKeyDown}>
8590
8615
  ${rootSegments.length > 0 ? rootSegments.map((label, i) => this.#renderRootSegment(label, i)) : A}
8591
8616
  ${leadingCaret}
8592
8617
  ${segments.map((label, i) => this.#renderSegment(label, i, i === segments.length - 1))}
@@ -8607,6 +8632,7 @@ let CrumbPathElement = class CrumbPathElement extends i {
8607
8632
  prominenceStyles,
8608
8633
  themeFallbacks,
8609
8634
  popupSurfaceStyles,
8635
+ scrollFadeStyles(`x`),
8610
8636
  i$3`
8611
8637
  :host {
8612
8638
  --text-highlight: var(--accent);
@@ -21614,6 +21640,258 @@ __decorate([property({ type: Number })], RangeElement.prototype, "value", null);
21614
21640
  __decorate([property({ type: Number })], RangeElement.prototype, "step", void 0);
21615
21641
  RangeElement = __decorate([safeCustomElement(`ixfx-range`)], RangeElement);
21616
21642
  //#endregion
21643
+ //#region src/select-horiz/select-horiz.ts
21644
+ let SelectHorizElement = class SelectHorizElement extends WheelNudgeMixin(i) {
21645
+ constructor(..._args) {
21646
+ super(..._args);
21647
+ this._selectedIndex = -1;
21648
+ this._slottedItems = [];
21649
+ this.tickled = new TickledController(this, {
21650
+ getItems: () => this._slottedItems.map((_, i) => ({
21651
+ id: i,
21652
+ enabled: true
21653
+ })),
21654
+ onStateChange: () => this._syncTickled()
21655
+ });
21656
+ this._onSlotChange = () => {
21657
+ this._slottedItems = Array.from(this.shadowRoot?.querySelector(`slot`)?.assignedElements() ?? []);
21658
+ const declaredIndex = this._slottedItems.findIndex((item) => item.hasAttribute(`selected`));
21659
+ let resolvedIndex = declaredIndex >= 0 ? declaredIndex : this._selectedIndex;
21660
+ if (resolvedIndex >= this._slottedItems.length) resolvedIndex = this._slottedItems.length - 1;
21661
+ if (resolvedIndex < 0 && this._slottedItems.length > 0) resolvedIndex = 0;
21662
+ this.selectedIndex = resolvedIndex;
21663
+ };
21664
+ this._syncTickled = () => {
21665
+ this._slottedItems.forEach((item, i) => {
21666
+ const isTickled = this.tickled.isTickled(i);
21667
+ item.classList.toggle(`tickled`, isTickled);
21668
+ item.tabIndex = isTickled && this.tickled.inputMode === `keyboard` ? 0 : -1;
21669
+ });
21670
+ };
21671
+ this._findSlottedItem = (target) => {
21672
+ let el = target instanceof Element ? target : null;
21673
+ while (el) {
21674
+ if (this._slottedItems.includes(el)) return el;
21675
+ el = el.parentElement;
21676
+ }
21677
+ };
21678
+ this._handlePointerOver = (e) => {
21679
+ const item = this._findSlottedItem(e.target);
21680
+ if (item) this.tickled.handlePointerEnter(this._slottedItems.indexOf(item));
21681
+ };
21682
+ this._handleKeyDown = (e) => {
21683
+ if (e.key === `ArrowLeft`) {
21684
+ e.preventDefault();
21685
+ this.tickled.handleKeyboardNavigation(`previous`);
21686
+ this._applyTickledSelection();
21687
+ } else if (e.key === `ArrowRight`) {
21688
+ e.preventDefault();
21689
+ this.tickled.handleKeyboardNavigation(`next`);
21690
+ this._applyTickledSelection();
21691
+ } else if (e.key === `Home`) {
21692
+ e.preventDefault();
21693
+ this.tickled.handleKeyboardNavigation(`first`);
21694
+ this._applyTickledSelection();
21695
+ } else if (e.key === `End`) {
21696
+ e.preventDefault();
21697
+ this.tickled.handleKeyboardNavigation(`last`);
21698
+ this._applyTickledSelection();
21699
+ }
21700
+ };
21701
+ this._applyTickledSelection = () => {
21702
+ const id = this.tickled.tickledId;
21703
+ if (id !== void 0 && id !== this._selectedIndex) this.selectedIndex = id;
21704
+ };
21705
+ this._wheelCooldown = false;
21706
+ this._handleClick = (e) => {
21707
+ e.currentTarget.focus();
21708
+ const item = this._findSlottedItem(e.target);
21709
+ const index = item ? this._slottedItems.indexOf(item) : -1;
21710
+ if (index >= 0 && index !== this._selectedIndex) this.selectedIndex = index;
21711
+ };
21712
+ this._updateSelectedAttribute = () => {
21713
+ this._slottedItems.forEach((item, i) => {
21714
+ if (i === this._selectedIndex) item.setAttribute(`selected`, ``);
21715
+ else item.removeAttribute(`selected`);
21716
+ });
21717
+ };
21718
+ this._scrollSelectedIntoView = () => {
21719
+ const item = this._slottedItems[this._selectedIndex];
21720
+ if (item) item.scrollIntoView({
21721
+ inline: `center`,
21722
+ behavior: `smooth`
21723
+ });
21724
+ };
21725
+ this._emitChange = () => {
21726
+ this.dispatchEvent(new CustomEvent(`change`, {
21727
+ detail: {
21728
+ selectedIndex: this._selectedIndex,
21729
+ selectedItem: this.selectedItem,
21730
+ selectedValue: this.selectedValue
21731
+ },
21732
+ bubbles: true,
21733
+ composed: true
21734
+ }));
21735
+ };
21736
+ }
21737
+ static {
21738
+ this.styles = [
21739
+ themeFallbacks,
21740
+ tickledStyles,
21741
+ tickledItemStyles,
21742
+ scrollFadeStyles(`x`),
21743
+ i$3`
21744
+ :host {
21745
+ --select-horiz-item-width: 80%;
21746
+ --select-horiz-gap: var(--space-s);
21747
+ --select-horiz-bg: var(--surface-3);
21748
+ --select-horiz-border: var(--border);
21749
+ --select-horiz-radius: var(--radius-l);
21750
+ display: flex;
21751
+ width: 100%;
21752
+ background: var(--select-horiz-bg);
21753
+ border: var(--select-horiz-border);
21754
+ border-radius: var(--select-horiz-radius);
21755
+ }
21756
+
21757
+ /* Edge fade (the scroll-fade-x class, see ../styles/scroll-fade.ts) must sit on
21758
+ * the element that actually scrolls - its mask is sized to this element's own
21759
+ * box, and content overflowing a *different*, non-scrolling ancestor gets the
21760
+ * mask tiled across it instead of fading correctly. */
21761
+ .items {
21762
+ display: flex;
21763
+ align-items: center;
21764
+ gap: var(--select-horiz-gap);
21765
+ padding: var(--space-xs) var(--scroll-fade-width, 30px);
21766
+ width: 100%;
21767
+ min-height: 48px;
21768
+ overflow-x: scroll;
21769
+ overflow-y: hidden;
21770
+ scrollbar-width: none;
21771
+ scroll-snap-type: x mandatory;
21772
+ -webkit-overflow-scrolling: touch;
21773
+ cursor: grab;
21774
+
21775
+ box-sizing: border-box;
21776
+ }
21777
+
21778
+ .items:focus-within {
21779
+ cursor: default;
21780
+ }
21781
+
21782
+ .spacer {
21783
+ flex: 0 0 var(--select-horiz-spacer-width, 10%);
21784
+ pointer-events: none;
21785
+ user-select: none;
21786
+ }
21787
+
21788
+ ::slotted(*) {
21789
+ flex: 0 0 var(--select-horiz-item-width);
21790
+ scroll-snap-align: center;
21791
+ user-select: none;
21792
+ min-height: 100%;
21793
+ box-sizing: border-box;
21794
+ transition: opacity var(--transition), background var(--transition), border-color var(--transition), color var(--transition);
21795
+ background: var(--item-bg);
21796
+ border: var(--item-border);
21797
+ border-radius: var(--item-border-radius);
21798
+ padding: var(--item-padding);
21799
+ display: grid;
21800
+ align-content: center;
21801
+ justify-content: center;
21802
+ }
21803
+
21804
+ ::slotted(.tickled) {
21805
+ background: var(--item-bg-tickled);
21806
+ border-color: var(--item-border-tickled);
21807
+ color: var(--item-text-tickled);
21808
+ }
21809
+
21810
+ ::slotted([selected]) {
21811
+ background: var(--item-bg-selected);
21812
+ border-color: var(--item-border-selected);
21813
+ color: var(--item-text-selected);
21814
+ }
21815
+
21816
+ ::slotted([selected].tickled) {
21817
+ background: var(--item-bg-selected-tickled);
21818
+ outline: 2px dashed var(--surface-3);
21819
+ outline-offset: -2px;
21820
+ }
21821
+
21822
+ ::-webkit-scrollbar {
21823
+ display: none;
21824
+ }
21825
+ `
21826
+ ];
21827
+ }
21828
+ get selectedIndex() {
21829
+ return this._selectedIndex;
21830
+ }
21831
+ set selectedIndex(value) {
21832
+ const oldValue = this._selectedIndex;
21833
+ if (value < -1 || this._slottedItems.length > 0 && value >= this._slottedItems.length) return;
21834
+ this._selectedIndex = value;
21835
+ this._updateSelectedAttribute();
21836
+ this._scrollSelectedIntoView();
21837
+ this.tickled.setTickled(value === -1 ? void 0 : value);
21838
+ if (oldValue !== value) this._emitChange();
21839
+ }
21840
+ get selectedValue() {
21841
+ return this._slottedItems[this._selectedIndex]?.getAttribute(`value`) ?? null;
21842
+ }
21843
+ set selectedValue(value) {
21844
+ if (value === null) return;
21845
+ const index = this._slottedItems.findIndex((item) => item.getAttribute(`value`) === value);
21846
+ if (index >= 0) this.selectedIndex = index;
21847
+ }
21848
+ get selectedItem() {
21849
+ return this._slottedItems[this._selectedIndex] ?? null;
21850
+ }
21851
+ get items() {
21852
+ return this._slottedItems;
21853
+ }
21854
+ render() {
21855
+ return b`
21856
+ <div
21857
+ class="items scroll-fade-x"
21858
+ tabindex="0"
21859
+ data-input-mode=${this.tickled.inputMode}
21860
+ @pointerover=${this._handlePointerOver}
21861
+ @pointerleave=${(e) => this.tickled.handlePointerLeave(e)}
21862
+ @keydown=${this._handleKeyDown}
21863
+ @click=${this._handleClick}
21864
+ >
21865
+ <div class="spacer"></div>
21866
+ <slot @slotchange=${this._onSlotChange}></slot>
21867
+ <div class="spacer"></div>
21868
+ </div>
21869
+ `;
21870
+ }
21871
+ willUpdate(changed) {
21872
+ super.willUpdate(changed);
21873
+ this.setAttribute(`data-input-mode`, this.tickled.inputMode);
21874
+ }
21875
+ _applyWheelDelta(direction, _event) {
21876
+ if (this._wheelCooldown) return;
21877
+ this._wheelCooldown = true;
21878
+ this.tickled.handleKeyboardNavigation(direction === 1 ? `next` : `previous`);
21879
+ this._applyTickledSelection();
21880
+ setTimeout(() => {
21881
+ this._wheelCooldown = false;
21882
+ }, 250);
21883
+ }
21884
+ };
21885
+ __decorate([state()], SelectHorizElement.prototype, "_selectedIndex", void 0);
21886
+ __decorate([state()], SelectHorizElement.prototype, "_slottedItems", void 0);
21887
+ __decorate([property({
21888
+ type: Number,
21889
+ reflect: true,
21890
+ attribute: `selected-index`
21891
+ })], SelectHorizElement.prototype, "selectedIndex", null);
21892
+ __decorate([property({ type: String })], SelectHorizElement.prototype, "selectedValue", null);
21893
+ SelectHorizElement = __decorate([safeCustomElement(`ixfx-select-horiz`)], SelectHorizElement);
21894
+ //#endregion
21617
21895
  //#region src/selecthorizontal.ts
21618
21896
  let SelectHorizontalElement = class SelectHorizontalElement extends i {
21619
21897
  constructor(..._args) {
@@ -28354,6 +28632,6 @@ function init() {
28354
28632
  console.log(`Init`);
28355
28633
  }
28356
28634
  //#endregion
28357
- export { AcTextElement, AcTokenElement, ButtonElement, Checkbox, ColourPicker, ColourPickerPopup, CrumbNavigationElement, CrumbPathController, CrumbPathElement, DataController, DataDisplayComponent, EditableLabel, EditableNumber, FormElement, FormGroupElement, FormPartElement, GroupedItemListerElement, ICON_CARET_RIGHT, ICON_CHECK, ICON_CHEVRON_DOWN, ICON_CLOSE, IncrSearchTreeController as IncrSearchMillerController, IncrSearchTreeController, IxfxHexEditorElement, IxfxIconElement, IxfxTimelineElement, LabelledRadialInput, LabelledRangeInput, LedElement, menu_exports as Menu, MillerBaseElement, MillerListElement, MillerTreeController, NarrowedTextElement, NotificationManager, NotificationPillElement, PanelElement, PanelGroupElement, PlotDataSeries, PlotHistogram, PlotMultiAxis, PlotSingleAxis, PlotXyAxis, PolarPad, RadialInputElement, RadioGroup, RangeElement, RangeInput, RangeMultiElement, SelectHorizontalElement, SliderInputElement, SnackbarElement, SnapContainer, SplitButton, SplitLayoutElement, SwipeElement, TabController, TabListElement, TabListItemElement, TabPanelElement, TabPanelsElement, TimelineController, TimelineTrackTabElement, TooltipElement, TransitoryLabelElement, TreeBaseElement, TreeController, TreeDataModel, TreeListElement, VerticalListElement, XyPad, applyAgeModification, applyHighlights, attachTimelineInteractions, buildHighlightTargets, clearHighlights, collectDataResult, computeColour, createAcCompletionProvider, createElementIncrSearch, createFuzzySearch, createIncrSearch, createPillRenderer, createTreeListAdapter, createVerticalListAdapter, getIcon, hasIcon, iconBus, init, monitorIndeterminate, parseColourScaleAttr, readBaseColour, registerIcon, resolveCssVars, resolveGrid, svgToDataUri, timelineStyles };
28635
+ export { AcTextElement, AcTokenElement, ButtonElement, Checkbox, ColourPicker, ColourPickerPopup, CrumbNavigationElement, CrumbPathController, CrumbPathElement, DataController, DataDisplayComponent, EditableLabel, EditableNumber, FormElement, FormGroupElement, FormPartElement, GroupedItemListerElement, ICON_CARET_RIGHT, ICON_CHECK, ICON_CHEVRON_DOWN, ICON_CLOSE, IncrSearchTreeController as IncrSearchMillerController, IncrSearchTreeController, IxfxHexEditorElement, IxfxIconElement, IxfxTimelineElement, LabelledRadialInput, LabelledRangeInput, LedElement, menu_exports as Menu, MillerBaseElement, MillerListElement, MillerTreeController, NarrowedTextElement, NotificationManager, NotificationPillElement, PanelElement, PanelGroupElement, PlotDataSeries, PlotHistogram, PlotMultiAxis, PlotSingleAxis, PlotXyAxis, PolarPad, RadialInputElement, RadioGroup, RangeElement, RangeInput, RangeMultiElement, SelectHorizElement, SelectHorizontalElement, SliderInputElement, SnackbarElement, SnapContainer, SplitButton, SplitLayoutElement, SwipeElement, TabController, TabListElement, TabListItemElement, TabPanelElement, TabPanelsElement, TimelineController, TimelineTrackTabElement, TooltipElement, TransitoryLabelElement, TreeBaseElement, TreeController, TreeDataModel, TreeListElement, VerticalListElement, XyPad, applyAgeModification, applyHighlights, attachTimelineInteractions, buildHighlightTargets, clearHighlights, collectDataResult, computeColour, createAcCompletionProvider, createElementIncrSearch, createFuzzySearch, createIncrSearch, createPillRenderer, createTreeListAdapter, createVerticalListAdapter, getIcon, hasIcon, iconBus, init, monitorIndeterminate, parseColourScaleAttr, readBaseColour, registerIcon, resolveCssVars, resolveGrid, svgToDataUri, timelineStyles };
28358
28636
 
28359
28637
  //# sourceMappingURL=index.js.map