@odx/foundation 1.0.0-beta.97 → 1.0.0-beta.99

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.
@@ -12,7 +12,6 @@ declare global {
12
12
  export declare class OdxBreadcrumbs extends CustomElement {
13
13
  #private;
14
14
  private itemElements;
15
- private renderedItemElements;
16
15
  max: number;
17
16
  items?: BreadcrumbsItem[] | null;
18
17
  protected firstUpdated(props: PropertyValues<this>): void;
@@ -17,7 +17,7 @@ export declare class OdxAutocomplete extends FormControl {
17
17
  searchFn: (option: OptionControl, query?: string) => boolean;
18
18
  get control(): HTMLInputElement | undefined;
19
19
  get controlValue(): string;
20
- firstUpdated(props: PropertyValues<this>): void;
20
+ protected firstUpdated(props: PropertyValues<this>): void;
21
21
  protected render(): TemplateResult;
22
22
  }
23
23
  //# sourceMappingURL=autocomplete.d.ts.map
@@ -18,7 +18,6 @@ export declare class OdxInput extends FormControl<string> {
18
18
  step?: number;
19
19
  type: HTMLInputElement['type'];
20
20
  value: string;
21
- clear(): void;
22
21
  stepUp(): void;
23
22
  stepDown(): void;
24
23
  protected willUpdate(props: PropertyValues<this>): void;
@@ -6,6 +6,7 @@ export declare abstract class PopoverHost extends PopoverHost_base {
6
6
  #private;
7
7
  static readonly styles: import('lit').CSSResult;
8
8
  protected popoverElement: OdxPopover;
9
+ open: boolean;
9
10
  set referenceElement(value: HTMLElement | null);
10
11
  get referenceElement(): HTMLElement | null;
11
12
  placement: Placement;
@@ -17,7 +18,7 @@ export declare abstract class PopoverHost extends PopoverHost_base {
17
18
  hasMountedPopover(element: HTMLElement): boolean;
18
19
  mountPopover(referenceElement: HTMLElement | null): void;
19
20
  unmountPopover(_referenceElement: HTMLElement): void;
20
- isPopoverOpen(): boolean;
21
+ hasOpenPopover(referenceElement: HTMLElement | null): boolean;
21
22
  showPopover(): Promise<void>;
22
23
  hidePopover(): void;
23
24
  togglePopover(state?: boolean): boolean;
@@ -13,11 +13,13 @@ export declare class OdxSelect extends ListboxFormControl<OptionControl> {
13
13
  protected readonly dropdown: OdxDropdown;
14
14
  maxVisibleSelectedOptions: number;
15
15
  constructor();
16
- connectedCallback(): void;
17
- firstUpdated(props: PropertyValues<this>): void;
16
+ clear(): void;
18
17
  isDropdownOpen(): boolean;
19
18
  showDropdown(): void;
20
19
  hideDropdown(): void;
20
+ connectedCallback(): void;
21
+ firstUpdated(props: PropertyValues<this>): void;
22
+ protected canSelect(option: OptionControl): boolean;
21
23
  protected render(): TemplateResult;
22
24
  protected updated(props: PropertyValues<this>): void;
23
25
  }
@@ -12,6 +12,7 @@ export declare class OdxSpinbox extends FormControl<string> {
12
12
  selectedIndex: number;
13
13
  value: string;
14
14
  constructor();
15
+ clear(): void;
15
16
  protected willUpdate(props: PropertyValues<this>): void;
16
17
  protected updated(props: PropertyValues<this>): void;
17
18
  previous(): void;
@@ -1,13 +1,12 @@
1
1
  import { _ as __decorateClass } from './_virtual_class-decorator-runtime.js';
2
2
  import { CustomElement, ExpandableItemManager, customElement, CanBeExpanded, InteractiveElement, getUniqueId, toAriaBooleanAttribute, Size, Variant, optionalAttr, InteractiveLink, getElementFromEvent, Shape, CanBeDisabled, optionalSlot, CheckboxFormControl, CheckboxGroupFormControl, SharedResizeObserver, findClosestDocument, Placement, waitForAnimations, PopoverPlacementOptions, computePopoverPlacement, getKeyInfo, FormControl, ActiveDescendantsController, getAssignedElement, parseDate, forwardEvent, OptionControl, toPx, RadioGroupFormControl, ListboxFormControl, IsDraggable, NumberFormControl, IS_DRAG_ACTIVE_ATTRIBUTE, DragController } from '@odx/foundation';
3
- import { queryAssignedElements, property, query, state, queryAll } from 'lit/decorators.js';
3
+ import { queryAssignedElements, property, query, state } from 'lit/decorators.js';
4
4
  import { html, isServer, unsafeCSS, css, nothing } from 'lit';
5
5
  import { p as pick, e, a 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
8
  import { signal, computed } from '@preact/signals-core';
9
9
  import 'lit/html.js';
10
- import { repeat } from 'lit/directives/repeat.js';
11
10
 
12
11
  const styles$1g = ":host{display:block}:host(:not([compact])) ::slotted(odx-accordion-item){margin-block:var(--odx-spacing-37)}";
13
12
 
@@ -400,11 +399,7 @@ const _OdxAnchorNavigation = class _OdxAnchorNavigation extends e(CustomElement)
400
399
  render() {
401
400
  const anchors = this.#anchorObserver?.anchors.value ?? [];
402
401
  const visibleAnchors = this.#anchorObserver?.visibleAnchors.value;
403
- return repeat(
404
- anchors,
405
- (anchor) => anchor.id,
406
- (anchor) => this.renderAnchorLink(anchor, visibleAnchors?.[0] === anchor)
407
- );
402
+ return html`${anchors.map((anchor) => this.renderAnchorLink(anchor, visibleAnchors?.[0] === anchor))}`;
408
403
  }
409
404
  updated(props) {
410
405
  if (props.has("container")) {
@@ -602,13 +597,7 @@ const _OdxBreadcrumbs = class _OdxBreadcrumbs extends CustomElement {
602
597
  render() {
603
598
  if (Array.isArray(this.items)) {
604
599
  const items = this.items.filter((...args) => this.#isItemVisible(...args));
605
- return repeat(
606
- items,
607
- (item) => item.href,
608
- ({ label, href }) => html`
609
- <odx-breadcrumbs-item><odx-link href=${href}>${label}</odx-link></odx-breadcrumbs-item>
610
- `
611
- );
600
+ return html`${items.map(({ label, href }) => html`<odx-breadcrumbs-item><odx-link href=${href}>${label}</odx-link></odx-breadcrumbs-item>`)}`;
612
601
  }
613
602
  return html`<slot @slotchange=${this.#updateContext}></slot>`;
614
603
  }
@@ -625,7 +614,9 @@ const _OdxBreadcrumbs = class _OdxBreadcrumbs extends CustomElement {
625
614
  for (const [index, item] of this.itemElements.entries()) {
626
615
  item.hidden = !this.#isItemVisible(item, index, this.itemElements);
627
616
  }
628
- for (const [, item] of Array.from(this.renderedItemElements).entries()) {
617
+ const renderedItemElements = this.shadowRoot?.querySelectorAll(OdxBreadcrumbsItem.tagName) ?? [];
618
+ if (renderedItemElements.length === 0) return;
619
+ for (const item of Array.from(renderedItemElements)) {
629
620
  item.requestUpdate();
630
621
  }
631
622
  }
@@ -633,9 +624,6 @@ const _OdxBreadcrumbs = class _OdxBreadcrumbs extends CustomElement {
633
624
  __decorateClass([
634
625
  queryAssignedElements({ selector: OdxBreadcrumbsItem.tagName, flatten: true })
635
626
  ], _OdxBreadcrumbs.prototype, "itemElements", 2);
636
- __decorateClass([
637
- queryAll(OdxBreadcrumbsItem.tagName)
638
- ], _OdxBreadcrumbs.prototype, "renderedItemElements", 2);
639
627
  __decorateClass([
640
628
  property({ type: Number })
641
629
  ], _OdxBreadcrumbs.prototype, "max", 2);
@@ -976,7 +964,7 @@ __decorateClass([
976
964
  ], _OdxCircularProgressBar.prototype, "size", 2);
977
965
  let OdxCircularProgressBar = _OdxCircularProgressBar;
978
966
 
979
- const styles$Z = "@layer base{:host{--max-block-size: 100%;--max-inline-size: 100%;--_popover-color-background: var(--odx-color-background-level-2);--_popover-color-foreground: var(--odx-color-foreground-rest);--_popover-min-block-size: inherit;--_popover-max-block-size: 100%;--_popover-min-inline-size: inherit;--_popover-max-inline-size: 100%;--_popover-transition: var(--odx-popover-transition, var(--odx-motion-duration-default));--_popover-offset: var(--odx-size-50);--_popover-shadow: var(--odx-popover-shadow, var(--odx-shadow-level-1));--_popover-outer-padding: var(--odx-size-75);--_popover-arrow-size: var(--odx-size-50);--_popover-arrow-offset: calc(var(--_popover-offset) - var(--_popover-arrow-size) / 2);--_max-block-size: min(var(--_popover-max-block-size), var(--max-block-size));--_max-inline-size: min(var(--_popover-max-inline-size), var(--max-inline-size));top:var(--_popover-position-y);left:var(--_popover-position-x);transform:translate3d(var(--_popover-transition-offset-x),var(--_popover-transition-offset-y),0);transition:opacity var(--_popover-transition),transform var(--_popover-transition) allow-discrete,overlay var(--_popover-transition) allow-discrete,display var(--_popover-transition) allow-discrete;opacity:0;margin:0;background-color:transparent;max-block-size:var(--_max-block-size);max-inline-size:var(--_max-inline-size)}:host(:not(:popover-open)){display:none}:host(:popover-open){display:flex;transform:translate(0);opacity:1;@starting-style{transform:translate(var(--_popover-transition-offset-x),var(--_popover-transition-offset-y));opacity:0}}odx-popover::part(arrow){transform:rotate(45deg)}}@layer state{:host([popover-placement^=\"top\"]){--_popover-transition-offset-x: 0;--_popover-transition-offset-y: calc(-1 * var(--_popover-offset));padding-block:var(--_popover-outer-padding) var(--_popover-offset);max-block-size:calc(var(--_max-block-size) - var(--_popover-outer-padding));odx-popover::part(arrow){bottom:var(--_popover-arrow-offset)}}:host([popover-placement^=\"right\"]){--_popover-transition-offset-x: var(--_popover-offset);--_popover-transition-offset-y: 0;padding-inline:var(--_popover-offset) var(--_popover-outer-padding);max-inline-size:calc(var(--_max-inline-size) - var(--_popover-outer-padding));odx-popover::part(arrow){left:var(--_popover-arrow-offset)}}:host([popover-placement^=\"bottom\"]){--_popover-transition-offset-x: 0;--_popover-transition-offset-y: var(--_popover-offset);--_popover-arrow-offset-y: calc(var(--_popover-offset) - 6px);padding-block:var(--_popover-offset) var(--_popover-outer-padding);max-block-size:calc(var(--_max-block-size) - var(--_popover-outer-padding));odx-popover::part(arrow){top:var(--_popover-arrow-offset)}}:host([popover-placement^=\"left\"]){--_popover-transition-offset-x: calc(-1 * var(--_popover-offset));--_popover-transition-offset-y: 0;--_popover-arrow-offset-x: calc(var(--_popover-offset) - var(--_arrow-size) / 2);--_popover-arrow-offset-y: 0;padding-inline:var(--_popover-offset) var(--_popover-outer-padding);max-inline-size:calc(var(--_max-inline-size) - var(--_popover-outer-padding));odx-popover::part(arrow){right:var(--_popover-offset)}}}";
967
+ const styles$Z = "@layer base{:host{--max-block-size: 100%;--max-inline-size: 100%;--_popover-color-background: var(--odx-color-background-level-2);--_popover-color-foreground: var(--odx-color-foreground-rest);--_popover-min-block-size: inherit;--_popover-max-block-size: 100%;--_popover-min-inline-size: inherit;--_popover-max-inline-size: 100%;--_popover-transition: var(--odx-popover-transition, var(--odx-motion-duration-default));--_popover-offset: var(--odx-size-50);--_popover-shadow: var(--odx-popover-shadow, var(--odx-shadow-level-1));--_popover-outer-padding: var(--odx-size-75);--_popover-arrow-size: var(--odx-size-50);--_popover-arrow-offset: calc(var(--_popover-offset) - var(--_popover-arrow-size) / 2);--_max-block-size: min(var(--_popover-max-block-size), var(--max-block-size));--_max-inline-size: min(var(--_popover-max-inline-size), var(--max-inline-size));top:var(--_popover-position-y);left:var(--_popover-position-x);transform:translate3d(var(--_popover-transition-offset-x),var(--_popover-transition-offset-y),0);transition:opacity var(--_popover-transition),transform var(--_popover-transition) allow-discrete,overlay var(--_popover-transition) allow-discrete,display var(--_popover-transition) allow-discrete;opacity:0;margin:0;background-color:transparent;max-block-size:var(--_max-block-size);max-inline-size:var(--_max-inline-size)}:host(:not(:popover-open)){display:none}:host(:popover-open){display:flex;transform:translate(0);opacity:1;@starting-style{transform:translate(var(--_popover-transition-offset-x),var(--_popover-transition-offset-y));opacity:0}}odx-popover::part(arrow){transform:rotate(45deg)}}@layer state{:host([popover-placement^=\"top\"]){--_popover-transition-offset-x: 0;--_popover-transition-offset-y: var(--_popover-offset);padding-block:var(--_popover-outer-padding) var(--_popover-offset);max-block-size:calc(var(--_max-block-size) - var(--_popover-outer-padding));odx-popover::part(arrow){bottom:var(--_popover-arrow-offset)}}:host([popover-placement^=\"right\"]){--_popover-transition-offset-x: calc(-1 * var(--_popover-offset));--_popover-transition-offset-y: 0;padding-inline:var(--_popover-offset) var(--_popover-outer-padding);max-inline-size:calc(var(--_max-inline-size) - var(--_popover-outer-padding));odx-popover::part(arrow){left:var(--_popover-arrow-offset)}}:host([popover-placement^=\"bottom\"]){--_popover-transition-offset-x: 0;--_popover-transition-offset-y: calc(-1 * var(--_popover-offset));--_popover-arrow-offset-y: calc(var(--_popover-offset) - 6px);padding-block:var(--_popover-offset) var(--_popover-outer-padding);max-block-size:calc(var(--_max-block-size) - var(--_popover-outer-padding));odx-popover::part(arrow){top:var(--_popover-arrow-offset)}}:host([popover-placement^=\"left\"]){--_popover-transition-offset-x: var(--_popover-offset);--_popover-transition-offset-y: 0;--_popover-arrow-offset-x: calc(var(--_popover-offset) - var(--_arrow-size) / 2);--_popover-arrow-offset-y: 0;padding-inline:var(--_popover-offset) var(--_popover-outer-padding);max-inline-size:calc(var(--_max-inline-size) - var(--_popover-outer-padding));odx-popover::part(arrow){right:var(--_popover-offset)}}}";
980
968
 
981
969
  const popoverTargetAttribute = "odx-popovertarget";
982
970
  class PopoverObserver {
@@ -1015,10 +1003,12 @@ class PopoverHost extends CanBeDisabled(CustomElement) {
1015
1003
  super();
1016
1004
  this.#currentReferenceElement = null;
1017
1005
  this.#openPopovers = /* @__PURE__ */ new WeakSet();
1006
+ this.open = false;
1018
1007
  this.placement = Placement.BOTTOM;
1019
1008
  this.fpsLimit = 60;
1020
1009
  this.#handleToggle = async (event) => {
1021
- if (this.isPopoverOpen()) {
1010
+ this.open = !!this.referenceElement && event.newState === "open";
1011
+ if (this.hasOpenPopover(this.referenceElement)) {
1022
1012
  await this.onBeforePopoverShow?.();
1023
1013
  await waitForAnimations(this);
1024
1014
  await this.onPopoverShow?.();
@@ -1028,7 +1018,7 @@ class PopoverHost extends CanBeDisabled(CustomElement) {
1028
1018
  await this.onPopoverHide?.();
1029
1019
  }
1030
1020
  if (!this.referenceElement) return;
1031
- if (event.newState === "open") {
1021
+ if (this.open) {
1032
1022
  this.#openPopovers.add(this.referenceElement);
1033
1023
  } else {
1034
1024
  this.#openPopovers.delete(this.referenceElement);
@@ -1077,16 +1067,15 @@ class PopoverHost extends CanBeDisabled(CustomElement) {
1077
1067
  unmountPopover(_referenceElement) {
1078
1068
  this.referenceElement = null;
1079
1069
  }
1080
- isPopoverOpen() {
1081
- return !!this.referenceElement && this.#openPopovers.has(this.referenceElement);
1070
+ hasOpenPopover(referenceElement) {
1071
+ return !!referenceElement && this.#openPopovers.has(referenceElement);
1082
1072
  }
1083
1073
  async showPopover() {
1084
1074
  if (!this.referenceElement || this.disabled || this.canPopoverShow?.() === false) return;
1085
1075
  await 0;
1076
+ this.#positionUpdater?.();
1086
1077
  computePopoverPlacement(this.referenceElement, this, this.options);
1087
1078
  super.showPopover();
1088
- this.#openPopovers.add(this.referenceElement);
1089
- this.#positionUpdater?.();
1090
1079
  this.#positionUpdater = autoUpdate(
1091
1080
  this.referenceElement,
1092
1081
  this,
@@ -1094,16 +1083,13 @@ class PopoverHost extends CanBeDisabled(CustomElement) {
1094
1083
  );
1095
1084
  }
1096
1085
  hidePopover() {
1097
- if (!this.isPopoverOpen() || this.canPopoverHide?.() === false) return;
1098
- this.#positionUpdater?.();
1086
+ if (!this.open || this.canPopoverHide?.() === false) return;
1099
1087
  super.hidePopover();
1100
- if (this.referenceElement) {
1101
- this.#openPopovers.delete(this.referenceElement);
1102
- }
1088
+ this.#positionUpdater?.();
1103
1089
  this.#positionUpdater = void 0;
1104
1090
  }
1105
1091
  togglePopover(state) {
1106
- const isOpen = state ?? !this.isPopoverOpen();
1092
+ const isOpen = state ?? !this.hasOpenPopover(this.referenceElement);
1107
1093
  if (isOpen) {
1108
1094
  this.showPopover();
1109
1095
  } else {
@@ -1118,9 +1104,9 @@ class PopoverHost extends CanBeDisabled(CustomElement) {
1118
1104
  }
1119
1105
  willUpdate(props) {
1120
1106
  super.willUpdate(props);
1121
- if (props.has("referenceElement") && this.referenceElement !== props.get("referenceElement")) {
1107
+ if (props.has("referenceElement")) {
1122
1108
  const previousReferenceElement = props.get("referenceElement");
1123
- if (previousReferenceElement) {
1109
+ if (previousReferenceElement && this.referenceElement !== previousReferenceElement) {
1124
1110
  this.#openPopovers.delete(previousReferenceElement);
1125
1111
  }
1126
1112
  }
@@ -1139,6 +1125,9 @@ class PopoverHost extends CanBeDisabled(CustomElement) {
1139
1125
  __decorateClass([
1140
1126
  query("odx-popover", true)
1141
1127
  ], PopoverHost.prototype, "popoverElement", 2);
1128
+ __decorateClass([
1129
+ property({ type: Boolean, reflect: true, useDefault: true })
1130
+ ], PopoverHost.prototype, "open", 2);
1142
1131
  __decorateClass([
1143
1132
  property({ attribute: false })
1144
1133
  ], PopoverHost.prototype, "referenceElement", 1);
@@ -1157,17 +1146,19 @@ const _OdxDropdown = class _OdxDropdown extends PopoverHost {
1157
1146
  super(...arguments);
1158
1147
  this.matchReferenceWidth = false;
1159
1148
  this.placement = DropdownPlacement.BOTTOM;
1160
- this.#handleClick = (event) => {
1161
- if (event?.defaultPrevented) return;
1149
+ this.#handleInteraction = (event) => {
1150
+ if (event.defaultPrevented) return;
1162
1151
  this.updateReferenceElementFromEvent(event);
1163
1152
  this.togglePopover();
1164
1153
  };
1165
1154
  this.#handleKeyboardEvent = (event) => {
1166
1155
  const key = getKeyInfo(event);
1167
- if (!key.enter || event.defaultPrevented) return;
1168
- if (!this.isPopoverOpen()) {
1156
+ if (!(key.enter || key.space) || event.defaultPrevented) return;
1157
+ if (!this.open) {
1158
+ event.preventDefault();
1169
1159
  event.stopImmediatePropagation();
1170
1160
  }
1161
+ this.updateReferenceElementFromEvent(event);
1171
1162
  this.showPopover();
1172
1163
  };
1173
1164
  }
@@ -1188,14 +1179,14 @@ const _OdxDropdown = class _OdxDropdown extends PopoverHost {
1188
1179
  super.mountPopover(referenceElement);
1189
1180
  if (!referenceElement) return;
1190
1181
  this.#updateAriaAttributes(referenceElement, this.id);
1191
- referenceElement.addEventListener("click", this.#handleClick);
1182
+ referenceElement.addEventListener("click", this.#handleInteraction);
1192
1183
  referenceElement.addEventListener("keydown", this.#handleKeyboardEvent);
1193
1184
  }
1194
1185
  unmountPopover(referenceElement) {
1195
1186
  super.unmountPopover(referenceElement);
1196
1187
  if (!referenceElement) return;
1197
1188
  this.#updateAriaAttributes(referenceElement, null);
1198
- referenceElement.removeEventListener("click", this.#handleClick);
1189
+ referenceElement.removeEventListener("click", this.#handleInteraction);
1199
1190
  referenceElement.removeEventListener("keydown", this.#handleKeyboardEvent);
1200
1191
  }
1201
1192
  render() {
@@ -1219,7 +1210,7 @@ const _OdxDropdown = class _OdxDropdown extends PopoverHost {
1219
1210
  referenceElement.removeAttribute(ariaAttribute);
1220
1211
  }
1221
1212
  }
1222
- #handleClick;
1213
+ #handleInteraction;
1223
1214
  #handleKeyboardEvent;
1224
1215
  };
1225
1216
  __decorateClass([
@@ -1346,7 +1337,7 @@ const _OdxAutocomplete = class _OdxAutocomplete extends FormControl {
1346
1337
  this.dropdown.hidePopover();
1347
1338
  };
1348
1339
  this.#handleControlClear = () => {
1349
- if (!this.dropdown.isPopoverOpen()) return;
1340
+ if (!this.dropdown.open) return;
1350
1341
  this.#handleControlValueChange(void 0);
1351
1342
  };
1352
1343
  this.#handleControlInput = () => {
@@ -1355,7 +1346,7 @@ const _OdxAutocomplete = class _OdxAutocomplete extends FormControl {
1355
1346
  } else if (this.controlValue.length === 0) {
1356
1347
  this.dropdown.hidePopover();
1357
1348
  }
1358
- if (!this.dropdown.isPopoverOpen()) return;
1349
+ if (!this.dropdown.open) return;
1359
1350
  this.#handleControlValueChange(this.controlValue);
1360
1351
  };
1361
1352
  this.#handleControlKeyboardEvent = (event) => {
@@ -1970,23 +1961,25 @@ const _OdxInput = class _OdxInput extends FormControl {
1970
1961
  this.placeholder = "";
1971
1962
  this.type = "text";
1972
1963
  this.value = "";
1964
+ this.#handleClear = (event) => {
1965
+ if (!this.#isClearable()) return;
1966
+ event.preventDefault();
1967
+ event.stopPropagation();
1968
+ if (this.emit("clear")) return;
1969
+ this.clear();
1970
+ };
1973
1971
  this.#handleInput = (event) => {
1974
1972
  this.value = event.target.value;
1975
1973
  };
1976
1974
  this.#handleKeyDown = (event) => {
1977
- if (!getKeyInfo(event).escape) return;
1978
- event.preventDefault();
1979
- this.clear();
1975
+ const key = getKeyInfo(event);
1976
+ if (!key.escape) return;
1977
+ this.#handleClear(event);
1980
1978
  };
1981
1979
  }
1982
1980
  static {
1983
1981
  customElement("odx-input", styles$M)(_OdxInput);
1984
1982
  }
1985
- clear() {
1986
- if (!this.#isClearable() || this.emit("clear")) return;
1987
- this.value = "";
1988
- this.focus();
1989
- }
1990
1983
  stepUp() {
1991
1984
  if (!this.nativeInput) return;
1992
1985
  this.nativeInput.stepUp();
@@ -2039,7 +2032,7 @@ const _OdxInput = class _OdxInput extends FormControl {
2039
2032
  ${this.renderControl("increment", "core::plus", () => this.stepUp(), this.disabled || !canStepUp)}
2040
2033
  </odx-button-group>
2041
2034
  `,
2042
- () => when(!(this.disabled || this.readonly) && this.clearable, () => this.renderControl("clear", "core::cancel", () => this.clear(), this.disabled))
2035
+ () => when(this.#isClearable(), () => this.renderControl("clear", "core::cancel", this.#handleClear, this.disabled))
2043
2036
  )}
2044
2037
  <slot name="suffix"></slot>
2045
2038
  `;
@@ -2054,6 +2047,7 @@ const _OdxInput = class _OdxInput extends FormControl {
2054
2047
  #isClearable() {
2055
2048
  return this.clearable && !this.disabled && !this.readonly && !this.required && !!this.value;
2056
2049
  }
2050
+ #handleClear;
2057
2051
  #handleInput;
2058
2052
  #handleKeyDown;
2059
2053
  };
@@ -2584,7 +2578,7 @@ class OdxMenu extends PopoverHost {
2584
2578
  };
2585
2579
  #handleKeyDown = (event) => {
2586
2580
  const key = getKeyInfo(event);
2587
- if (!(this.isPopoverOpen() && (key.tab || key.backTab))) return;
2581
+ if (!(this.open && (key.tab || key.backTab))) return;
2588
2582
  event?.preventDefault();
2589
2583
  event.stopPropagation();
2590
2584
  this.hidePopover();
@@ -2627,7 +2621,7 @@ __decorateClass([
2627
2621
  ], _OdxMenuItem.prototype, "icon", 2);
2628
2622
  let OdxMenuItem = _OdxMenuItem;
2629
2623
 
2630
- const styles$A = "@layer base{:host{--max-inline-size: 640px;--margin-block-start: var(--odx-size-450);--_modal-transition: var(--odx-popover-transition, var(--odx-motion-duration-default));--_modal-transition-offset-x: 0;--_modal-transition-offset-y: calc(-1 * var(--_modal-offset));--_modal-outer-padding: var(--odx-breakpoint-spacing-150);display:contents;transition-property:display}:host,.base,.base::backdrop{transition:var(--odx-transition-default);transition-behavior:allow-discrete}.base,.base::backdrop{opacity:0}.base{transform:translateY(var(--odx-size-100));transition-property:opacity,display,overlay,transform,outline;margin-block-start:var(--margin-block-start);border:0;border-radius:var(--odx-border-radius-ml);box-shadow:var(--odx-shadow-level-2);background:transparent;padding:0;inline-size:min(var(--max-inline-size),100% - 2 * var(--_modal-outer-padding));overflow:unset;color:var(--odx-color-foreground-rest);&::backdrop{transition-property:opacity;background-color:var(--odx-color-backdrop);backdrop-filter:blur(var(--odx-elevation-blur))}}.inner{display:flex;flex-direction:column;border-radius:inherit;background-color:var(--odx-color-background-level-1);padding:var(--odx-spacing-50) var(--odx-breakpoint-spacing-150);max-block-size:calc(100dvh - 2 * var(--_modal-outer-padding))}.header,.footer{min-block-size:var(--odx-size-300)}.content{padding:var(--odx-size-75) 0}.dismiss-action{margin-inline-start:auto}}@layer state{:host(:not([open])){display:none}.base:focus-visible{outline-color:var(--odx-color-stroke-focus-outer)}.base[open]{transform:translate(0);&,&::backdrop{opacity:1;@starting-style{opacity:0}}@starting-style{transform:translateY(var(--odx-size-100))}}}";
2624
+ const styles$A = "@layer base{:host{--max-inline-size: 640px;--_modal-outer-padding: var(--odx-breakpoint-spacing-150);display:contents;transition-property:display}:host,.base,.base::backdrop{transition:var(--odx-transition-slow);transition-behavior:allow-discrete}.base,.base::backdrop{opacity:0}.base{transform:translateY(var(--odx-size-100));transition-property:opacity,display,overlay,transform,box-shadow;border:0;border-radius:var(--odx-border-radius-ml);background:transparent;padding:0;inline-size:min(var(--max-inline-size),100% - 2 * var(--_modal-outer-padding));overflow:unset;color:var(--odx-color-foreground-rest);&::backdrop{transition-property:opacity;background-color:var(--odx-color-backdrop);backdrop-filter:blur(var(--odx-elevation-blur))}}.inner{display:flex;flex-direction:column;border-radius:inherit;background-color:var(--odx-color-background-level-1);padding:var(--odx-spacing-50) var(--odx-breakpoint-spacing-150);max-block-size:calc(100dvh - 2 * var(--_modal-outer-padding))}.header,.footer{min-block-size:var(--odx-size-300)}.content{padding:var(--odx-size-75) 0;overflow:auto}.dismiss-action{margin-inline-start:auto}}@layer state{:host(:not([open])){display:none}.base:focus-visible{outline-color:var(--odx-color-stroke-focus-outer)}.base[open]{transform:translate(0);box-shadow:var(--odx-shadow-level-2);&,&::backdrop{opacity:1;@starting-style{opacity:0}}@starting-style{transform:translateY(var(--odx-size-100))}}}";
2631
2625
 
2632
2626
  const ModalLayout = { MODAL: "modal", SIDESHEET: "sidesheet" };
2633
2627
  (async () => {
@@ -3268,7 +3262,7 @@ __decorateClass([
3268
3262
  ], _OdxSearchBar.prototype, "readonly", 2);
3269
3263
  let OdxSearchBar = _OdxSearchBar;
3270
3264
 
3271
- const styles$o = "@layer base{:host{--_color-background: var(--odx-color-background-control-rest);--_color-foreground: var(--odx-color-foreground-rest);--_color-stroke: var(--odx-color-stroke-control-rest);--_control-size: var(--odx-size-225);--_padding-block: var(--odx-size-37);--_padding-inline: var(--odx-size-50);display:block;border-radius:var(--odx-border-radius-controls);cursor:pointer;inline-size:100%;max-inline-size:320px;overflow:hidden;color:var(--_color-foreground)}.base{display:flex;gap:var(--_padding-block);align-items:center;transition:var(--odx-transition-reduced);transition-property:background-color,border-color;border:var(--odx-border-width-thin) solid transparent;border-bottom-color:var(--_color-stroke);background-color:var(--_color-background);padding-inline:var(--_padding-inline);block-size:var(--_control-size);min-width:200px;overflow:hidden;text-align:start;user-select:none;&:focus-visible{outline:var(--odx-focus-ring-outline);outline-color:var(--odx-color-stroke-focus-outer)}}.value{margin-inline-end:auto;font-weight:var(--odx-typography-font-weight-medium)}.indicator{font-size:var(--odx-typography-font-size-6)}[part~=dropdown]{--max-block-size: 320px}odx-chip{--_border-radius: var(--odx-border-radius-controls)}slot[name=placeholder]{color:var(--odx-color-foreground-rest-subtle);font-weight:var(--odx-typography-font-weight-normal)}}@layer state{:host(:hover){--_color-background: var(--odx-color-background-control-hover);--_color-stroke: var(--odx-color-stroke-control-hover)}:host([multiple]):has(odx-chip) .base{padding-inline-start:var(--_padding-block)}:host([disabled]:not([readonly])){--_color-foreground: var(--odx-color-foreground-disabled-rest);--_color-background: var(--odx-color-background-disabled-rest);--_color-stroke: var(--odx-color-stroke-disabled-rest);cursor:not-allowed;slot[name=placeholder]{color:var(---_color-foreground)}}:host([readonly]){--_color-background: var(--odx-color-background-control-readonly);--_color-stroke: var(--odx-color-stroke-control-readonly);cursor:default;odx-chip{--_color-background: var(--odx-color-foreground-disabled-rest)}.indicator{color:var(--odx-color-foreground-rest-subtle)}}}";
3265
+ const styles$o = "@layer base{:host{--_color-background: var(--odx-color-background-control-rest);--_color-foreground: var(--odx-color-foreground-rest);--_color-stroke: var(--odx-color-stroke-control-rest);--_control-size: var(--odx-size-225);--_padding-block: var(--odx-size-37);--_padding-inline: var(--odx-size-50);display:block;border-radius:var(--odx-border-radius-controls);cursor:pointer;inline-size:100%;max-inline-size:320px;overflow:hidden;color:var(--_color-foreground)}.base{display:flex;gap:var(--_padding-block);align-items:center;transition:var(--odx-transition-reduced);transition-property:background-color,border-color;border:var(--odx-border-width-thin) solid transparent;border-bottom-color:var(--_color-stroke);background-color:var(--_color-background);padding-inline:var(--_padding-inline);block-size:var(--_control-size);min-width:200px;overflow:hidden;text-align:start;user-select:none;&:focus-visible{outline:var(--odx-focus-ring-outline);outline-color:var(--odx-color-stroke-focus-outer)}}.value{margin-inline-end:auto;font-weight:var(--odx-typography-font-weight-medium)}.indicator{font-size:var(--odx-typography-font-size-6)}[part~=dropdown]{--max-block-size: 320px}odx-chip{--_border-radius: var(--odx-border-radius-controls)}slot[name=placeholder]{color:var(--odx-color-foreground-rest-subtle);font-weight:var(--odx-typography-font-weight-normal)}:host:has(odx-dropdown[open]){--_color-background: var(--odx-color-background-control-hover);--_color-stroke: var(--odx-color-stroke-control-hover)}}@layer state{:host(:hover){--_color-background: var(--odx-color-background-control-hover);--_color-stroke: var(--odx-color-stroke-control-hover)}:host([multiple]):has(odx-chip) .base{padding-inline-start:var(--_padding-block)}:host([disabled]:not([readonly])){--_color-foreground: var(--odx-color-foreground-disabled-rest);--_color-background: var(--odx-color-background-disabled-rest);--_color-stroke: var(--odx-color-stroke-disabled-rest);cursor:not-allowed;slot[name=placeholder]{color:var(---_color-foreground)}}:host([readonly]){--_color-background: var(--odx-color-background-control-readonly);--_color-stroke: var(--odx-color-stroke-control-readonly);cursor:default;odx-chip{--_color-background: var(--odx-color-foreground-disabled-rest)}.indicator{color:var(--odx-color-foreground-rest-subtle)}}}";
3272
3266
 
3273
3267
  const _OdxSelect = class _OdxSelect extends ListboxFormControl {
3274
3268
  constructor() {
@@ -3290,13 +3284,13 @@ const _OdxSelect = class _OdxSelect extends ListboxFormControl {
3290
3284
  this.value = this.value.length === this.options.length ? [] : this.options.map((option) => option.value);
3291
3285
  };
3292
3286
  this.#handleClear = (event) => {
3293
- event.stopPropagation();
3294
3287
  event.preventDefault();
3295
- if (!this.#isClearable() || this.emit("clear")) return;
3296
- this.updateValue(void 0);
3288
+ event.stopPropagation();
3289
+ if (this.emit("clear")) return;
3290
+ this.clear();
3297
3291
  };
3298
3292
  this.#handleSelect = () => {
3299
- if (this.autoSelect && !this.isDropdownOpen() || this.multiple) return;
3293
+ if (this.autoSelect || this.multiple) return;
3300
3294
  this.hideDropdown();
3301
3295
  };
3302
3296
  if (!isServer) {
@@ -3307,16 +3301,11 @@ const _OdxSelect = class _OdxSelect extends ListboxFormControl {
3307
3301
  static {
3308
3302
  customElement("odx-select", styles$o)(_OdxSelect);
3309
3303
  }
3310
- connectedCallback() {
3311
- super.connectedCallback();
3312
- this.role = "combobox";
3313
- }
3314
- firstUpdated(props) {
3315
- super.firstUpdated(props);
3316
- this.dropdown.mountPopover(this.shadowRoot?.querySelector(".base") ?? null);
3304
+ clear() {
3305
+ this.value = this.multiple ? [] : "";
3317
3306
  }
3318
3307
  isDropdownOpen() {
3319
- return this.dropdown?.isPopoverOpen();
3308
+ return this.dropdown.open;
3320
3309
  }
3321
3310
  showDropdown() {
3322
3311
  this.dropdown.showPopover();
@@ -3324,6 +3313,17 @@ const _OdxSelect = class _OdxSelect extends ListboxFormControl {
3324
3313
  hideDropdown() {
3325
3314
  this.dropdown.hidePopover();
3326
3315
  }
3316
+ connectedCallback() {
3317
+ super.connectedCallback();
3318
+ this.role = "combobox";
3319
+ }
3320
+ firstUpdated(props) {
3321
+ super.firstUpdated(props);
3322
+ this.dropdown.mountPopover(this.shadowRoot?.querySelector(".base") ?? null);
3323
+ }
3324
+ canSelect(option) {
3325
+ return (this.autoSelect || this.dropdown.open) && super.canSelect(option);
3326
+ }
3327
3327
  render() {
3328
3328
  const allSelected = this.value.length === this.options.length;
3329
3329
  const dropdownDisabled = this.disabled || this.readonly && (!this.multiple || this.selectedOptions.length === 0);
@@ -3706,7 +3706,7 @@ const _OdxSliderMarks = class _OdxSliderMarks extends CustomElement {
3706
3706
  const markCount = Math.floor(this.context.range / step);
3707
3707
  const marks = new Array(markCount).fill(null).map((_, index) => step * index + this.context.min);
3708
3708
  return html`
3709
- ${repeat(marks, (value) => this.renderMark(value))}
3709
+ ${marks.map((value) => this.renderMark(value))}
3710
3710
  ${this.renderMark(this.context.max, true)}
3711
3711
  `;
3712
3712
  }
@@ -3791,6 +3791,9 @@ const _OdxSpinbox = class _OdxSpinbox extends FormControl {
3791
3791
  delegatesFocus: false
3792
3792
  };
3793
3793
  }
3794
+ clear() {
3795
+ this.value = "";
3796
+ }
3794
3797
  willUpdate(props) {
3795
3798
  super.willUpdate(props);
3796
3799
  if (props.has("selectedIndex")) {
@@ -8,6 +8,7 @@ export declare abstract class CheckboxFormControl extends FormControl<string> {
8
8
  value: string;
9
9
  constructor();
10
10
  toFormValue(): string | File | FormData | null;
11
+ clear(): void;
11
12
  toggle(state?: boolean, emitEvent?: boolean): void;
12
13
  connectedCallback(): void;
13
14
  updateAriaAttributes(): void;
@@ -10,11 +10,12 @@ export declare abstract class CheckboxGroupFormControl extends FormControl<strin
10
10
  get groupControl(): CheckboxFormControl | null;
11
11
  value: string[];
12
12
  constructor();
13
- protected firstUpdated(_changedProperties: PropertyValues): Promise<void>;
13
+ clear(): void;
14
14
  toFormValue(): FormData;
15
15
  protected isControl(element: unknown): element is CheckboxFormControl;
16
16
  protected isGroupControl(element: unknown): element is CheckboxFormControl;
17
17
  protected isControlChecked(control: CheckboxFormControl): boolean;
18
+ protected firstUpdated(_changedProperties: PropertyValues): Promise<void>;
18
19
  protected updated(props: PropertyValues<this>): void;
19
20
  protected updateControls(updateFn: (control: CheckboxFormControl, index: number) => void): void;
20
21
  protected updateValue(value: string[], dispatchEvent?: boolean): void;
@@ -2,7 +2,7 @@ import { PropertyValues } from 'lit';
2
2
  import { CustomElement } from '../custom-element.js';
3
3
  import { CanBeDisabled } from '../mixins/can-be-disabled.js';
4
4
  declare const FormControl_base: import('../main.js').Constructor<CanBeDisabled> & typeof CustomElement;
5
- export declare class FormControl<V extends string | number | string[] = string> extends FormControl_base {
5
+ export declare abstract class FormControl<V extends string | number | string[] = string> extends FormControl_base {
6
6
  /** @internal */
7
7
  static readonly formAssociated = true;
8
8
  /** @internal */
@@ -23,6 +23,7 @@ export declare class FormControl<V extends string | number | string[] = string>
23
23
  checkValidity(): boolean;
24
24
  setValidity(flags?: ValidityStateFlags, target?: HTMLElement): void;
25
25
  reportValidity(): void;
26
+ clear(): void;
26
27
  protected willUpdate(props: PropertyValues<this>): void;
27
28
  }
28
29
  export {};
@@ -16,6 +16,7 @@ export declare abstract class ListboxFormControl<Option extends OptionControl> e
16
16
  protected canAutoSelect(option: Option): boolean;
17
17
  protected canSelect(option: Option): boolean;
18
18
  toggleOption(option: Option, state?: boolean): void;
19
+ clear(): void;
19
20
  connectedCallback(): void;
20
21
  protected handleSlotChange(): void;
21
22
  protected updateValue(option?: Option): void;
@@ -5,6 +5,7 @@ export declare class NumberFormControl extends FormControl<number> {
5
5
  max: number;
6
6
  step: number;
7
7
  value: number;
8
+ clear(): void;
8
9
  getValueText(): string;
9
10
  protected willUpdate(props: PropertyValues<this>): void;
10
11
  toFormValue(): string;
package/dist/main.js CHANGED
@@ -177,6 +177,9 @@ class FormControl extends CanBeDisabled(CustomElement) {
177
177
  reportValidity() {
178
178
  this.internals.reportValidity();
179
179
  }
180
+ clear() {
181
+ this.value = "";
182
+ }
180
183
  willUpdate(props) {
181
184
  super.willUpdate(props);
182
185
  if (props.has("required")) {
@@ -238,6 +241,9 @@ class CheckboxFormControl extends FormControl {
238
241
  }
239
242
  return this.checked ? "on" : null;
240
243
  }
244
+ clear() {
245
+ this.checked = false;
246
+ }
241
247
  toggle(state, emitEvent = false) {
242
248
  const currentState = this.checked;
243
249
  const newState = state ?? !currentState;
@@ -302,9 +308,8 @@ const _CheckboxGroupFormControl = class _CheckboxGroupFormControl extends FormCo
302
308
  get groupControl() {
303
309
  return this.#findControls((element) => element.hasAttribute(GROUP_CONTROL_SELECTOR))[0] ?? null;
304
310
  }
305
- async firstUpdated(_changedProperties) {
306
- await 0;
307
- this.value = this.controls.filter((control) => control.checked).map((control) => control.value);
311
+ clear() {
312
+ this.value = [];
308
313
  }
309
314
  toFormValue() {
310
315
  const formData = new FormData();
@@ -322,6 +327,10 @@ const _CheckboxGroupFormControl = class _CheckboxGroupFormControl extends FormCo
322
327
  isControlChecked(control) {
323
328
  return this.value.includes(control.value);
324
329
  }
330
+ async firstUpdated(_changedProperties) {
331
+ await 0;
332
+ this.value = this.controls.filter((control) => control.checked).map((control) => control.value);
333
+ }
325
334
  updated(props) {
326
335
  super.updated(props);
327
336
  if (props.has("value")) {
@@ -341,11 +350,17 @@ const _CheckboxGroupFormControl = class _CheckboxGroupFormControl extends FormCo
341
350
  });
342
351
  }
343
352
  if (props.has("disabled")) {
353
+ if (this.groupControl) {
354
+ this.groupControl.disabled = this.disabled;
355
+ }
344
356
  this.updateControls((control) => {
345
357
  control.disabled = this.disabled;
346
358
  });
347
359
  }
348
360
  if (props.has("readonly")) {
361
+ if (this.groupControl) {
362
+ this.groupControl.readonly = this.disabled;
363
+ }
349
364
  this.updateControls((control) => {
350
365
  control.readonly = this.readonly;
351
366
  });
@@ -525,9 +540,9 @@ class ListboxFormControl extends FormControl {
525
540
  super();
526
541
  this.activeDescendants = new ActiveDescendantsController(this, {
527
542
  getItems: () => this.options,
528
- onChange: (_, option, firstChange) => {
543
+ onChange: (_, option) => {
529
544
  option?.scrollIntoView();
530
- if (!(option && this.canAutoSelect(option)) || firstChange || option.selected) return;
545
+ if (!(option && this.canAutoSelect(option)) || option.selected) return;
531
546
  this.toggleOption(option, true);
532
547
  }
533
548
  });
@@ -589,6 +604,9 @@ class ListboxFormControl extends FormControl {
589
604
  option.scrollIntoView();
590
605
  }
591
606
  }
607
+ clear() {
608
+ this.value = this.multiple ? [] : "";
609
+ }
592
610
  connectedCallback() {
593
611
  super.connectedCallback();
594
612
  this.role ||= "listbox";
@@ -674,6 +692,9 @@ class NumberFormControl extends FormControl {
674
692
  this.step = 1;
675
693
  this.value = 0;
676
694
  }
695
+ clear() {
696
+ this.value = 0;
697
+ }
677
698
  getValueText() {
678
699
  return this.ariaValueText?.trim() ?? "";
679
700
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@odx/foundation",
3
3
  "description": "A library of Web Component building blocks for ODX",
4
- "version": "1.0.0-beta.97",
4
+ "version": "1.0.0-beta.99",
5
5
  "author": "Drägerwerk AG & Co.KGaA",
6
6
  "license": "SEE LICENSE IN LICENSE",
7
7
  "homepage": "https://odx.draeger.com",
@@ -40,8 +40,8 @@
40
40
  "ts-lit-plugin": "2.0.2",
41
41
  "vite": "6.3.5",
42
42
  "vite-plugin-dts": "4.5.4",
43
- "@odx/storybook-utils": "0.0.0",
44
- "@odx/typescript-config": "0.0.0"
43
+ "@odx/typescript-config": "0.0.0",
44
+ "@odx/storybook-utils": "0.0.0"
45
45
  },
46
46
  "sideEffects": [
47
47
  "dist/i18n.js",