@odx/foundation 1.0.0-beta.152 → 1.0.0-beta.153

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.
@@ -5,6 +5,11 @@ declare global {
5
5
  'odx-scroll-container': OdxScrollContainer;
6
6
  }
7
7
  }
8
+ export interface ScrollContainerChangeEvent extends Event {
9
+ detail: {
10
+ scrollDirection: -1 | 1;
11
+ };
12
+ }
8
13
  /**
9
14
 
10
15
  * @slot scroll-action-left - Left action slot
@@ -19,7 +24,6 @@ export declare class OdxScrollContainer extends CustomElement {
19
24
  readonly stage: HTMLElement;
20
25
  leftOverflow: boolean;
21
26
  rightOverflow: boolean;
22
- get items(): HTMLElement[];
23
27
  constructor();
24
28
  protected firstUpdated(props: PropertyValues<this>): void;
25
29
  disconnectedCallback(): void;
@@ -1,6 +1,6 @@
1
1
  import { CustomElement } from '../../lib/main.js';
2
- import { OdxNavigationItem } from '../main.js';
3
2
  import { PropertyValues, TemplateResult } from 'lit';
3
+ import { OdxNavigationItem } from '../navigation-item/navigation-item.js';
4
4
  declare global {
5
5
  interface HTMLElementTagNameMap {
6
6
  'odx-tab-bar': OdxTabBar;
@@ -8,10 +8,14 @@ declare global {
8
8
  }
9
9
  export declare class OdxTabBar extends CustomElement {
10
10
  #private;
11
+ autoSelect: boolean;
11
12
  selectedIndex: number;
12
- get items(): OdxNavigationItem[];
13
13
  get selectedItem(): OdxNavigationItem | undefined;
14
14
  constructor();
15
+ getItems(): OdxNavigationItem[];
16
+ selectItem(item: OdxNavigationItem): void;
17
+ selectPreviousItem(): void;
18
+ selectNextItem(): void;
15
19
  protected render(): TemplateResult;
16
20
  protected updated(props: PropertyValues<this>): void;
17
21
  }
@@ -5,7 +5,6 @@ import { html, isServer, unsafeCSS, css, nothing } from 'lit';
5
5
  import { p as pick, e, d as autoUpdate, t as throttle, R as RovingTabindexController, r as round, g as debounce, n, i as c, j as e$1 } from './vendor.js';
6
6
  import { when } from 'lit/directives/when.js';
7
7
  import { IsLocalized, setTranslation } from '@odx/foundation/i18n';
8
- import { OdxNavigationItem as OdxNavigationItem$1 } from '@odx/foundation/components';
9
8
  import { signal, computed } from '@preact/signals-core';
10
9
  import 'lit/html.js';
11
10
 
@@ -2163,7 +2162,7 @@ __decorateClass([
2163
2162
  ], _OdxLineClamp.prototype, "max", 2);
2164
2163
  let OdxLineClamp = _OdxLineClamp;
2165
2164
 
2166
- const styles$K = "@layer base{:host{--indent-level: 0;--_block-size: var(--odx-size-300);--_padding-block: var(--odx-spacing-75);display:flex;flex-direction:column;place-items:initial;block-size:auto;max-inline-size:100%}[part~=base]{place-content:flex-start;z-index:1;outline-offset:calc(-1 * var(--odx-focus-ring-offset));padding-inline-start:calc(var(--odx-spacing-50) + var(--indent-level) * var(--odx-size-200));max-block-size:var(--_block-size);text-align:start;>*{--odx-focus-ring-offset: 0}}[part~=separator]{--spacing: 0px;--inner-spacing: var(--odx-spacing-25)}[part~=expand-control]{margin-block:var(--_icon-margin)}[part~=expand-control]::part(icon){transition:var(--odx-transition-reduced)}::slotted(odx-list){--item-indent-level: calc(var(--indent-level) + 1)}:host(:last-of-type) [part~=separator]{opacity:0}}@layer variant{[part~=base]:has([part~=expand-control]:active){--_color-background-pressed: var(--_color-background-hover)}:host(:not([compact])){::slotted(odx-icon){margin-inline:var(--odx-spacing-37)}}:host([compact]){--_block-size: var(--odx-size-225);[part~=expand-control]{--_icon-size: var(--odx-size-150)}[part~=base]{max-block-size:var(--_block-size)}}}@layer state{:host(:not([muted]):hover):after{opacity:0}:host([muted]:not([disabled])){--_color-background-hover: var(--_color-background);--_color-background-pressed: var(--_color-background);cursor:default}:host([selected]){--_color-background: var(--odx-color-background-transparent-selected-hover);--_color-background-hover: var(--odx-color-background-transparent-selected-hover)}:host([selected][disabled]){--_color-background: var(--odx-color-background-disabled-selected);--_color-background-hover: var(--_color-background);--_color-background-pressed: var(--_color-background);--_color-foreground: var(--odx-color-foreground-disabled-selected);cursor:not-allowed}:host([expanded]){[part~=separator]{opacity:1}[part~=expand-control]{--icon-rotation: 180deg}}}";
2165
+ const styles$K = "@layer base{:host{--indent-level: 0;--_block-size: var(--odx-size-300);--_padding-block: var(--odx-spacing-75);display:flex;flex-direction:column;place-items:initial;block-size:auto;max-inline-size:100%}[part~=base]{place-content:flex-start;z-index:1;outline-offset:calc(-1 * var(--odx-focus-ring-offset));padding-inline-start:calc(var(--odx-spacing-50) + var(--indent-level) * var(--odx-size-200));block-size:var(--_block-size);text-align:start;>*{--odx-focus-ring-offset: 0}}[part~=separator]{--spacing: 0px;--inner-spacing: var(--odx-spacing-25)}[part~=expand-control]{margin-block:var(--_icon-margin)}[part~=expand-control]::part(icon){transition:var(--odx-transition-reduced)}::slotted(odx-list){--item-indent-level: calc(var(--indent-level) + 1)}:host(:last-of-type) [part~=separator]{opacity:0}}@layer variant{[part~=base]:has([part~=expand-control]:active){--_color-background-pressed: var(--_color-background-hover)}:host(:not([compact])){::slotted(odx-icon){margin-inline:var(--odx-spacing-37)}}:host([compact]){--_block-size: var(--odx-size-225);[part~=expand-control]{--_icon-size: var(--odx-size-150)}[part~=base]{max-block-size:var(--_block-size)}}}@layer state{:host(:not([muted]):hover):after{opacity:0}:host([muted]:not([disabled])){--_color-background-hover: var(--_color-background);--_color-background-pressed: var(--_color-background);cursor:default}:host([selected]){--_color-background: var(--odx-color-background-transparent-selected-hover);--_color-background-hover: var(--odx-color-background-transparent-selected-hover)}:host([selected][disabled]){--_color-background: var(--odx-color-background-disabled-selected);--_color-background-hover: var(--_color-background);--_color-background-pressed: var(--_color-background);--_color-foreground: var(--odx-color-foreground-disabled-selected);cursor:not-allowed}:host([expanded]){[part~=separator]{opacity:1}[part~=expand-control]{--icon-rotation: 180deg}}}";
2167
2166
 
2168
2167
  const _OdxListItem = class _OdxListItem extends CanBeExpanded(InteractiveElement) {
2169
2168
  constructor() {
@@ -3312,20 +3311,19 @@ __decorateClass([
3312
3311
  ], _OdxRailNavigation.prototype, "size", 2);
3313
3312
  let OdxRailNavigation = _OdxRailNavigation;
3314
3313
 
3315
- const styles$r = ":host{--gradient-size: 0px;--_left-gradient-size: var(--gradient-size);--_right-gradient-size: var(--gradient-size);display:flex;position:relative;gap:var(--odx-spacing-50);align-items:center;max-inline-size:100%}[part~=base]{gap:inherit;transition:var(--odx-transition-default);transition-property:mask-image;overflow-x:scroll;scroll-snap-type:x mandatory;scroll-snap-stop:always;scrollbar-width:none;scroll-behavior:smooth;mask-image:linear-gradient(90deg,transparent calc(var(--_left-gradient-size) / 3),black var(--_left-gradient-size),black calc(100% - var(--_right-gradient-size)),transparent calc(100% - var(--_right-gradient-size) / 3));&::-webkit-scrollbar{display:none}}[part~=stage]{display:flex;position:relative;gap:inherit;padding:var(--odx-spacing-12);inline-size:max-content}.action{position:absolute;transition:var(--odx-transition-default);transition-property:opacity,visibility;visibility:hidden;opacity:0;z-index:1;&.left{inset-inline-start:0}&.right{inset-inline-end:0}&.visible{visibility:visible;opacity:1}}:not([name])::slotted(*){scroll-snap-align:start;flex:0 0 auto}";
3314
+ const styles$r = ":host{--gradient-size: 0px;--_left-gradient-size: var(--gradient-size);--_right-gradient-size: var(--gradient-size);display:flex;position:relative;gap:var(--odx-spacing-50);align-items:center;max-inline-size:100%}[part~=base]{gap:inherit;transition:var(--odx-transition-default);transition-property:mask-image;overflow-x:scroll;scroll-snap-type:x mandatory;scroll-snap-stop:always;scrollbar-width:none;scroll-behavior:smooth;mask-image:linear-gradient(90deg,transparent calc(var(--_left-gradient-size) / 3),black var(--_left-gradient-size),black calc(100% - var(--_right-gradient-size)),transparent calc(100% - var(--_right-gradient-size) / 3));&::-webkit-scrollbar{display:none}}[part~=stage]{display:flex;position:relative;gap:inherit;padding:var(--odx-spacing-12);inline-size:max-content}.action{position:absolute;transition:var(--odx-transition-default);transition-property:opacity,visibility;visibility:hidden;opacity:0;z-index:1;&.left{inset-inline-start:0}&.right{inset-inline-end:0}&.visible{visibility:visible;opacity:1}}:not([name])::slotted(*){scroll-snap-align:center;flex:0 0 auto}";
3316
3315
 
3317
3316
  const _OdxScrollContainer = class _OdxScrollContainer extends CustomElement {
3318
3317
  constructor() {
3319
3318
  super();
3320
- this.#intersectionState = /* @__PURE__ */ new Map();
3321
3319
  this.#scrollPadding = 0;
3322
3320
  this.leftOverflow = false;
3323
3321
  this.rightOverflow = false;
3324
3322
  this.#handleClick = (event) => {
3325
3323
  const target = getElementFromEvent(event, (node) => node === this.leftAction || node === this.rightAction);
3326
3324
  if (!target) return;
3327
- event.stopPropagation();
3328
3325
  const scrollDirection = target === this.leftAction ? -1 : 1;
3326
+ if (this.emit("change", { detail: { scrollDirection } })) return;
3329
3327
  this.scroller.scrollBy({ left: scrollDirection * this.scroller.clientWidth / 2 });
3330
3328
  };
3331
3329
  if (!isServer) {
@@ -3333,14 +3331,10 @@ const _OdxScrollContainer = class _OdxScrollContainer extends CustomElement {
3333
3331
  }
3334
3332
  }
3335
3333
  #intersectionObserver;
3336
- #intersectionState;
3337
3334
  #scrollPadding;
3338
3335
  static {
3339
3336
  customElement("odx-scroll-container", styles$r)(_OdxScrollContainer);
3340
3337
  }
3341
- get items() {
3342
- return getAssignedElements(this.renderRoot, { flatten: true });
3343
- }
3344
3338
  firstUpdated(props) {
3345
3339
  super.firstUpdated(props);
3346
3340
  this.#scrollPadding = Number.parseFloat(getComputedStyle(this.stage).paddingLeft || "0");
@@ -3348,17 +3342,6 @@ const _OdxScrollContainer = class _OdxScrollContainer extends CustomElement {
3348
3342
  this.scroller,
3349
3343
  throttle(() => this.#sync(), 1e3 / 30, { edges: ["trailing", "trailing"] })
3350
3344
  );
3351
- this.#intersectionObserver = new IntersectionObserver(
3352
- (entries) => {
3353
- for (const { target, isIntersecting } of entries) {
3354
- this.#intersectionState.set(target, isIntersecting);
3355
- }
3356
- },
3357
- { root: this.scroller, threshold: 0.6 }
3358
- );
3359
- for (const item of Array.from(this.items)) {
3360
- this.#intersectionObserver.observe(item);
3361
- }
3362
3345
  }
3363
3346
  disconnectedCallback() {
3364
3347
  super.disconnectedCallback();
@@ -3390,10 +3373,6 @@ const _OdxScrollContainer = class _OdxScrollContainer extends CustomElement {
3390
3373
  #sync() {
3391
3374
  this.leftOverflow = this.scroller.scrollLeft > this.#scrollPadding;
3392
3375
  this.rightOverflow = this.scroller.scrollLeft + this.scroller.clientWidth < this.scroller.scrollWidth - this.#scrollPadding;
3393
- for (const [element, isIntersecting] of this.#intersectionState) {
3394
- element.toggleAttribute("inert", !isIntersecting);
3395
- }
3396
- this.#intersectionState.clear();
3397
3376
  }
3398
3377
  #handleClick;
3399
3378
  };
@@ -4189,36 +4168,81 @@ __decorateClass([
4189
4168
  ], _OdxSwitch.prototype, "indicatorPosition", 2);
4190
4169
  let OdxSwitch = _OdxSwitch;
4191
4170
 
4192
- const styles$f = ":host{--indicator-position: 0;display:block;border-bottom:var(--odx-border-width-thin) solid var(--odx-color-stroke-neutral-subtle)}odx-scroll-container{--gradient-size: var(--odx-size-350)}odx-scroll-container::part(stage){padding-block:var(--odx-spacing-37) calc(var(--odx-spacing-37) - var(--odx-border-width-thin))}odx-scroll-container::part(stage):after{position:absolute;inset-block-end:0;inset-inline-start:var(--indicator-position, 0);transition:var(--odx-transition-default);background-clip:content-box;background-color:var(--odx-color-background-accent-rest);padding-inline:var(--odx-spacing-25);block-size:var(--odx-border-width-thickest);inline-size:100%;max-inline-size:var(--odx-size-350);content:\"\"}::slotted(*){scroll-snap-align:center}";
4171
+ const styles$f = ":host{--indicator-position: 0;display:block;box-shadow:inset 0 calc(var(--odx-border-width-thin) * -1) 0 0 var(--odx-color-stroke-neutral-subtle)}odx-scroll-container{--gradient-size: var(--odx-size-350)}odx-scroll-container::part(stage){padding-block:var(--odx-spacing-37)}odx-scroll-container::part(stage):after{position:absolute;inset-block-end:0;inset-inline-start:var(--indicator-position, 0);transition:var(--odx-transition-default);background-clip:content-box;background-color:var(--odx-color-background-accent-rest);padding-inline:var(--odx-spacing-25);block-size:var(--odx-border-width-thickest);inline-size:100%;max-inline-size:var(--odx-size-350);content:\"\"}";
4193
4172
 
4194
4173
  const _OdxTabBar = class _OdxTabBar extends CustomElement {
4195
4174
  constructor() {
4196
4175
  super();
4176
+ this.#rovingTabindexController = new RovingTabindexController(this, {
4177
+ elements: () => this.getItems(),
4178
+ isFocusableElement: (item) => !item.disabled,
4179
+ focusInIndex: (items) => this.#resolveInitialSelectedIndex(items),
4180
+ elementEnterAction: async (element) => {
4181
+ if (this.autoSelect) {
4182
+ element.click();
4183
+ } else {
4184
+ await 0;
4185
+ element.scrollIntoView({ inline: "center" });
4186
+ }
4187
+ },
4188
+ direction: "horizontal"
4189
+ });
4190
+ this.autoSelect = false;
4197
4191
  this.selectedIndex = 0;
4198
4192
  this.#handleClick = (event) => {
4199
- const navigationItem = getElementFromEvent(event, (node) => node instanceof OdxNavigationItem$1);
4193
+ const navigationItem = getElementFromEvent(event, (node) => node instanceof OdxNavigationItem);
4200
4194
  if (!navigationItem || navigationItem.disabled) return;
4201
- this.selectedIndex = this.items.indexOf(navigationItem);
4195
+ this.selectItem(navigationItem);
4196
+ };
4197
+ this.#handleScrollChange = (event) => {
4198
+ if (!this.autoSelect) return;
4199
+ event.preventDefault();
4200
+ event.stopPropagation();
4201
+ if (event.detail.scrollDirection < 1) {
4202
+ this.selectPreviousItem();
4203
+ } else {
4204
+ this.selectNextItem();
4205
+ }
4202
4206
  };
4203
4207
  if (!isServer) {
4204
- this.addEventListener("click", this.#handleClick);
4208
+ this.addEventListener("click", this.#handleClick, { capture: true });
4205
4209
  }
4206
4210
  }
4207
4211
  static {
4208
4212
  customElement("odx-tab-bar", styles$f)(_OdxTabBar);
4209
4213
  }
4210
- get items() {
4211
- return getAssignedElements(this.renderRoot, { selector: OdxNavigationItem$1.tagName, flatten: true });
4212
- }
4214
+ #rovingTabindexController;
4213
4215
  get selectedItem() {
4214
- return this.items[this.selectedIndex];
4216
+ return this.getItems()[this.selectedIndex];
4217
+ }
4218
+ getItems() {
4219
+ return getAssignedElements(this.renderRoot, { selector: OdxNavigationItem.tagName, flatten: true });
4220
+ }
4221
+ selectItem(item) {
4222
+ this.selectedIndex = this.getItems().indexOf(item);
4223
+ }
4224
+ selectPreviousItem() {
4225
+ const nextIndex = this.getItems().findLastIndex((item, index) => !item.disabled && index < this.selectedIndex);
4226
+ if (nextIndex >= 0) {
4227
+ this.selectedIndex = nextIndex;
4228
+ } else {
4229
+ this.selectedIndex = this.getItems().findIndex((item) => !item.disabled);
4230
+ }
4231
+ }
4232
+ selectNextItem() {
4233
+ const nextIndex = this.getItems().findIndex((item, index) => !item.disabled && index > this.selectedIndex);
4234
+ if (nextIndex >= 0) {
4235
+ this.selectedIndex = nextIndex;
4236
+ } else {
4237
+ this.selectedIndex = this.getItems().findLastIndex((item) => !item.disabled);
4238
+ }
4215
4239
  }
4216
4240
  render() {
4217
4241
  return html`
4218
- <odx-scroll-container>
4219
- <odx-icon-button icon="core::chevron-left" variant="ghost" slot="scroll-action-left"></odx-icon-button>
4242
+ <odx-scroll-container @change=${this.#handleScrollChange}>
4243
+ <odx-icon-button icon="core::chevron-left" variant="ghost" slot="scroll-action-left" tabindex="-1"></odx-icon-button>
4220
4244
  <slot></slot>
4221
- <odx-icon-button icon="core::chevron-right" variant="ghost" slot="scroll-action-right"></odx-icon-button>
4245
+ <odx-icon-button icon="core::chevron-right" variant="ghost" slot="scroll-action-right" tabindex="-1"></odx-icon-button>
4222
4246
  </odx-scroll-container>
4223
4247
  `;
4224
4248
  }
@@ -4229,16 +4253,25 @@ const _OdxTabBar = class _OdxTabBar extends CustomElement {
4229
4253
  }
4230
4254
  }
4231
4255
  async #updateItemSelection() {
4232
- this.items.forEach((item, index) => {
4256
+ this.getItems().forEach((item, index) => {
4233
4257
  item.selected = this.selectedIndex === index;
4234
4258
  });
4235
4259
  if (!this.selectedItem) return;
4236
- await 0;
4260
+ this.#rovingTabindexController.currentIndex = this.selectedIndex;
4237
4261
  this.style.setProperty("--indicator-position", toPx(this.selectedItem.offsetLeft - this.offsetLeft));
4262
+ await 0;
4238
4263
  this.selectedItem.scrollIntoView({ inline: "center" });
4239
4264
  }
4265
+ #resolveInitialSelectedIndex(items) {
4266
+ const selectedIndex = items.findIndex((item) => !item.disabled && item.selected);
4267
+ return selectedIndex > -1 ? selectedIndex : items.findIndex((item) => !item.disabled);
4268
+ }
4240
4269
  #handleClick;
4270
+ #handleScrollChange;
4241
4271
  };
4272
+ __decorateClass([
4273
+ property({ type: Boolean, attribute: "auto-select" })
4274
+ ], _OdxTabBar.prototype, "autoSelect", 2);
4242
4275
  __decorateClass([
4243
4276
  property({ type: Number, attribute: "selected-index" })
4244
4277
  ], _OdxTabBar.prototype, "selectedIndex", 2);
package/dist/main.js CHANGED
@@ -6,7 +6,7 @@ import { getAssignedElements as getAssignedElements$1 } from '@odx/foundation';
6
6
 
7
7
  const name = "@odx/foundation";
8
8
  const displayName = "ODX Design System Foundation";
9
- const version = "1.0.0-beta.152";
9
+ const version = "1.0.0-beta.153";
10
10
  const pkg = {
11
11
  name,
12
12
  displayName,
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@odx/foundation",
3
3
  "displayName": "ODX Design System Foundation",
4
4
  "description": "A library of Web Component building blocks for ODX",
5
- "version": "1.0.0-beta.152",
5
+ "version": "1.0.0-beta.153",
6
6
  "author": "Drägerwerk AG & Co.KGaA",
7
7
  "license": "SEE LICENSE IN LICENSE",
8
8
  "homepage": "https://odx.draeger.com",
@@ -41,8 +41,8 @@
41
41
  "ts-lit-plugin": "2.0.2",
42
42
  "vite": "7.0.2",
43
43
  "vite-plugin-dts": "4.5.4",
44
- "@odx/typescript-config": "0.0.0",
45
- "@odx/storybook-utils": "0.0.0"
44
+ "@odx/storybook-utils": "0.0.0",
45
+ "@odx/typescript-config": "0.0.0"
46
46
  },
47
47
  "sideEffects": [
48
48
  "dist/i18n.js",