@sebgroup/green-core 1.0.0-beta.14 → 1.0.0-beta.16

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.
@@ -40,6 +40,33 @@ export declare class GdsDropdown<ValueT = any> extends GdsFormControlElement<Val
40
40
  * The value of the dropdown will be an array of the selected values.
41
41
  */
42
42
  multiple: boolean;
43
+ /**
44
+ * Delegate function for comparing option values.
45
+ * By default the option values are compared using strict equality.
46
+ * If you want to compare objects by field values, you can provide
47
+ * a custom compare function here. The function should return true
48
+ * if the values are considered equal.
49
+ *
50
+ * Example:
51
+ * ```ts
52
+ * dropdown.compareWith = (a, b) => a.id === b.id
53
+ * ```
54
+ */
55
+ compareWith: (a: ValueT, b: ValueT) => boolean;
56
+ /**
57
+ * Delegate function for customizing the search filtering.
58
+ * By default, the search filter will just check if the option label
59
+ * contains the search string using [String.includes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/includes).
60
+ *
61
+ * This property allows you to provide a custom filter function to use instead.
62
+ *
63
+ * For example, to filter on value instead of label:
64
+ * ```ts
65
+ * dropdown.searchFilter = (query, option) =>
66
+ * option.value.toLowerCase().includes(query.toLowerCase())
67
+ * ```
68
+ */
69
+ searchFilter: (q: string, o: GdsOption) => boolean;
43
70
  constructor();
44
71
  connectedCallback(): void;
45
72
  /**
package/index.js CHANGED
@@ -37,7 +37,7 @@ import { property as property5 } from "lit/decorators.js";
37
37
  import { unsafeHTML } from "lit/directives/unsafe-html.js";
38
38
  import { when as when2 } from "lit/directives/when.js";
39
39
  import { ifDefined } from "lit/directives/if-defined.js";
40
- import { createRef as createRef2, ref as ref2 } from "lit/directives/ref.js";
40
+ import { createRef as createRef3, ref as ref3 } from "lit/directives/ref.js";
41
41
  import { msg, str, updateWhenLocaleChanges } from "@lit/localize";
42
42
  import "reflect-metadata";
43
43
 
@@ -119,10 +119,31 @@ function observeLightDOM() {
119
119
  };
120
120
  }
121
121
 
122
+ // libs/core/src/utils/decorators/watch-media-query.ts
123
+ function watchMediaQuery(q) {
124
+ return (proto, _propertyKey, descriptor) => {
125
+ const mediaQuery = window.matchMedia(q);
126
+ const connectedCallback = proto.connectedCallback;
127
+ const disconnectedCallback = proto.disconnectedCallback;
128
+ proto.connectedCallback = function() {
129
+ connectedCallback?.call(this);
130
+ const listener = (e) => {
131
+ descriptor.value?.call(this, e.matches);
132
+ };
133
+ mediaQuery.addEventListener("change", listener);
134
+ this.disconnectedCallback = function() {
135
+ disconnectedCallback?.call(this);
136
+ mediaQuery.removeEventListener("change", listener);
137
+ };
138
+ descriptor.value?.call(this, mediaQuery.matches);
139
+ };
140
+ };
141
+ }
142
+
122
143
  // libs/core/src/utils/helpers/custom-element-scoping.ts
123
144
  import { html as litHtml } from "lit";
124
145
  import { customElement } from "lit/decorators.js";
125
- var VER_SUFFIX = "-00499f";
146
+ var VER_SUFFIX = "-c16ded";
126
147
  var elementLookupTable = /* @__PURE__ */ new Map();
127
148
  var gdsCustomElement = (tagName) => {
128
149
  if (globalThis.GDS_DISABLE_VERSIONED_ELEMENTS) {
@@ -381,6 +402,7 @@ var GdsListbox = class extends LitElement2 {
381
402
  constructor() {
382
403
  super();
383
404
  this.multiple = false;
405
+ this.compareWith = (a, b) => a === b;
384
406
  __privateAdd(this, _slotRef, createRef());
385
407
  __privateAdd(this, _handleSelect, (e) => {
386
408
  const option = e.target;
@@ -478,7 +500,7 @@ var GdsListbox = class extends LitElement2 {
478
500
  }
479
501
  set selection(values) {
480
502
  this.options.forEach((el) => {
481
- el.selected = values.includes(el.value) || values.includes(el);
503
+ el.selected = values.some((v) => this.compareWith(v, el.value));
482
504
  });
483
505
  }
484
506
  connectedCallback() {
@@ -520,6 +542,9 @@ __decorateClass([
520
542
  }
521
543
  })
522
544
  ], GdsListbox.prototype, "multiple", 2);
545
+ __decorateClass([
546
+ property2()
547
+ ], GdsListbox.prototype, "compareWith", 2);
523
548
  __decorateClass([
524
549
  watch("multiple")
525
550
  ], GdsListbox.prototype, "_rerenderOptions", 1);
@@ -530,6 +555,7 @@ GdsListbox = __decorateClass([
530
555
  // libs/core/src/primitives/popover/popover.ts
531
556
  import { LitElement as LitElement3, html as html3, unsafeCSS as unsafeCSS3 } from "lit";
532
557
  import { property as property3 } from "lit/decorators.js";
558
+ import { createRef as createRef2, ref as ref2 } from "lit/directives/ref.js";
533
559
  import { computePosition, autoUpdate, offset, flip } from "@floating-ui/dom";
534
560
 
535
561
  // libs/core/src/primitives/popover/popover.styles.ts
@@ -540,19 +566,31 @@ var style3 = css3`
540
566
  background-color: white;
541
567
  box-shadow: 0 1rem 1rem 1rem rgba(0, 0, 0, 0.1);
542
568
  }
569
+
570
+ dialog::backdrop {
571
+ pointer-events: none;
572
+ }
543
573
  `;
544
574
  var popover_styles_default = style3;
545
575
 
546
576
  // libs/core/src/primitives/popover/popover.ts
547
- var _autoPositionCleanup, _registerTriggerEvents, registerTriggerEvents_fn, _unregisterTriggerEvents, unregisterTriggerEvents_fn, _triggerKeyDownListener, _setOpen, setOpen_fn;
577
+ var _dialogElementRef, _handleCloseButton, _registerTriggerEvents, registerTriggerEvents_fn, _unregisterTriggerEvents, unregisterTriggerEvents_fn, _autoPositionCleanup, _registerAutoPositioning, registerAutoPositioning_fn, _triggerKeyDownListener, _focusFirstSlottedChild;
548
578
  var GdsPopover = class extends LitElement3 {
549
579
  constructor() {
550
580
  super(...arguments);
551
581
  __privateAdd(this, _registerTriggerEvents);
552
582
  __privateAdd(this, _unregisterTriggerEvents);
553
- __privateAdd(this, _setOpen);
583
+ __privateAdd(this, _registerAutoPositioning);
554
584
  this.open = false;
555
585
  this.trigger = void 0;
586
+ this.label = void 0;
587
+ __privateAdd(this, _dialogElementRef, createRef2());
588
+ __privateAdd(this, _handleCloseButton, (e) => {
589
+ e.stopPropagation();
590
+ e.preventDefault();
591
+ this.open = false;
592
+ setTimeout(() => this.trigger?.focus(), 250);
593
+ });
556
594
  __privateAdd(this, _autoPositionCleanup, void 0);
557
595
  /**
558
596
  * ArrowDown on the trigger element will trigger the popover by default, and escape will close it.
@@ -560,16 +598,21 @@ var GdsPopover = class extends LitElement3 {
560
598
  __privateAdd(this, _triggerKeyDownListener, (e) => {
561
599
  if (e.key === "ArrowDown") {
562
600
  e.preventDefault();
563
- __privateMethod(this, _setOpen, setOpen_fn).call(this, true);
564
- const firstSlottedChild = this.shadowRoot?.querySelector("slot")?.assignedElements()[0];
565
- this.updateComplete.then(() => {
566
- firstSlottedChild?.focus();
567
- });
601
+ this.open = true;
568
602
  }
569
603
  if (e.key === "Escape") {
570
- __privateMethod(this, _setOpen, setOpen_fn).call(this, false);
604
+ this.open = false;
571
605
  }
572
606
  });
607
+ /**
608
+ * Move focus to the first slotted child.
609
+ */
610
+ __privateAdd(this, _focusFirstSlottedChild, () => {
611
+ const firstSlottedChild = this.shadowRoot?.querySelector("slot")?.assignedElements()[0];
612
+ this.updateComplete.then(() => {
613
+ firstSlottedChild?.focus();
614
+ });
615
+ });
573
616
  }
574
617
  _handleTriggerChanged() {
575
618
  __privateMethod(this, _registerTriggerEvents, registerTriggerEvents_fn).call(this);
@@ -578,10 +621,10 @@ var GdsPopover = class extends LitElement3 {
578
621
  super.connectedCallback();
579
622
  TransitionalStyles.instance.apply(this, "gds-popover");
580
623
  __privateMethod(this, _registerTriggerEvents, registerTriggerEvents_fn).call(this);
581
- this._updateHidden();
624
+ this._handleOpenChange();
582
625
  this.addEventListener("keydown", (e) => {
583
626
  if (e.key === "Escape") {
584
- __privateMethod(this, _setOpen, setOpen_fn).call(this, false);
627
+ this.open = false;
585
628
  }
586
629
  });
587
630
  }
@@ -590,50 +633,86 @@ var GdsPopover = class extends LitElement3 {
590
633
  __privateMethod(this, _unregisterTriggerEvents, unregisterTriggerEvents_fn).call(this);
591
634
  }
592
635
  render() {
593
- return html3` <slot></slot> `;
636
+ return html3`<dialog ${ref2(__privateGet(this, _dialogElementRef))}>
637
+ <header>
638
+ <h2>${this.label}</h2>
639
+ <button class="close" @click=${__privateGet(this, _handleCloseButton)}>
640
+ <i></i>
641
+ </button>
642
+ </header>
643
+ <slot></slot>
644
+ </dialog>`;
594
645
  }
595
- _updateHidden() {
646
+ _handleOpenChange() {
596
647
  this.setAttribute("aria-hidden", String(!this.open));
597
648
  this.hidden = !this.open;
649
+ this.updateComplete.then(() => {
650
+ if (this.open) {
651
+ __privateGet(this, _dialogElementRef).value?.showModal();
652
+ __privateGet(this, _focusFirstSlottedChild).call(this);
653
+ } else {
654
+ __privateGet(this, _dialogElementRef).value?.close();
655
+ }
656
+ });
657
+ this.dispatchEvent(
658
+ new CustomEvent("gds-ui-state", {
659
+ detail: { open: this.open },
660
+ bubbles: true,
661
+ composed: false
662
+ })
663
+ );
664
+ }
665
+ _handleMobileLayout(matches) {
666
+ var _a;
667
+ if (matches) {
668
+ (_a = __privateGet(this, _autoPositionCleanup)) == null ? void 0 : _a.call(this);
669
+ __privateGet(this, _dialogElementRef).value?.style.removeProperty("left");
670
+ __privateGet(this, _dialogElementRef).value?.style.removeProperty("top");
671
+ this.updateComplete.then(() => {
672
+ if (this.open)
673
+ __privateGet(this, _dialogElementRef).value?.showModal();
674
+ });
675
+ } else {
676
+ this.updateComplete.then(() => {
677
+ __privateMethod(this, _registerAutoPositioning, registerAutoPositioning_fn).call(this);
678
+ });
679
+ }
598
680
  }
599
681
  };
600
- _autoPositionCleanup = new WeakMap();
682
+ _dialogElementRef = new WeakMap();
683
+ _handleCloseButton = new WeakMap();
601
684
  _registerTriggerEvents = new WeakSet();
602
685
  registerTriggerEvents_fn = function() {
603
- if (!this.trigger)
604
- return;
605
- this.trigger.addEventListener("keydown", __privateGet(this, _triggerKeyDownListener));
686
+ this.trigger?.addEventListener("keydown", __privateGet(this, _triggerKeyDownListener));
687
+ };
688
+ _unregisterTriggerEvents = new WeakSet();
689
+ unregisterTriggerEvents_fn = function() {
690
+ var _a;
691
+ this.trigger?.removeEventListener("keydown", __privateGet(this, _triggerKeyDownListener));
692
+ (_a = __privateGet(this, _autoPositionCleanup)) == null ? void 0 : _a.call(this);
693
+ };
694
+ _autoPositionCleanup = new WeakMap();
695
+ _registerAutoPositioning = new WeakSet();
696
+ registerAutoPositioning_fn = function() {
606
697
  const referenceEl = this.trigger;
607
- __privateSet(this, _autoPositionCleanup, autoUpdate(referenceEl, this, () => {
608
- computePosition(referenceEl, this, {
698
+ const floatingEl = __privateGet(this, _dialogElementRef).value;
699
+ if (!referenceEl || !floatingEl)
700
+ return;
701
+ __privateSet(this, _autoPositionCleanup, autoUpdate(referenceEl, floatingEl, () => {
702
+ computePosition(referenceEl, floatingEl, {
609
703
  placement: "bottom-start",
610
704
  middleware: [offset(8), flip()]
611
705
  }).then(({ x, y }) => {
612
- Object.assign(this.style, {
706
+ Object.assign(floatingEl.style, {
613
707
  left: `${x}px`,
614
- top: `${y}px`
708
+ top: `${y}px`,
709
+ minWidth: `${referenceEl.offsetWidth}px`
615
710
  });
616
711
  });
617
712
  }));
618
713
  };
619
- _unregisterTriggerEvents = new WeakSet();
620
- unregisterTriggerEvents_fn = function() {
621
- var _a;
622
- this.trigger?.removeEventListener("keydown", __privateGet(this, _triggerKeyDownListener));
623
- (_a = __privateGet(this, _autoPositionCleanup)) == null ? void 0 : _a.call(this);
624
- };
625
714
  _triggerKeyDownListener = new WeakMap();
626
- _setOpen = new WeakSet();
627
- setOpen_fn = function(open) {
628
- this.open = open;
629
- this.dispatchEvent(
630
- new CustomEvent("gds-ui-state", {
631
- detail: { open },
632
- bubbles: true,
633
- composed: false
634
- })
635
- );
636
- };
715
+ _focusFirstSlottedChild = new WeakMap();
637
716
  GdsPopover.styles = unsafeCSS3(popover_styles_default);
638
717
  __decorateClass([
639
718
  property3({ type: Boolean, reflect: true })
@@ -641,12 +720,18 @@ __decorateClass([
641
720
  __decorateClass([
642
721
  property3()
643
722
  ], GdsPopover.prototype, "trigger", 2);
723
+ __decorateClass([
724
+ property3()
725
+ ], GdsPopover.prototype, "label", 2);
644
726
  __decorateClass([
645
727
  watch("trigger")
646
728
  ], GdsPopover.prototype, "_handleTriggerChanged", 1);
647
729
  __decorateClass([
648
730
  watch("open")
649
- ], GdsPopover.prototype, "_updateHidden", 1);
731
+ ], GdsPopover.prototype, "_handleOpenChange", 1);
732
+ __decorateClass([
733
+ watchMediaQuery("(max-width: 576px)")
734
+ ], GdsPopover.prototype, "_handleMobileLayout", 1);
650
735
  GdsPopover = __decorateClass([
651
736
  gdsCustomElement("gds-popover")
652
737
  ], GdsPopover);
@@ -763,7 +848,7 @@ var style4 = css4`
763
848
  var dropdown_styles_default = style4;
764
849
 
765
850
  // libs/core/src/components/dropdown/dropdown.ts
766
- var _listboxRef, _triggerRef, _searchInputRef, _optionElements, _listboxId, _triggerId, _handleSearchFieldKeyUp, _handleSearchFieldKeyDown, _handleOptionFocusChange, _registerPopoverTrigger, registerPopoverTrigger_fn, _handleSelectionChange, handleSelectionChange_fn, _registerAutoCloseListener, registerAutoCloseListener_fn, _unregisterAutoCloseListener, unregisterAutoCloseListener_fn, _autoCloseListener;
851
+ var _listboxRef, _triggerRef, _searchInputRef, _optionElements, _listboxId, _triggerId, _handleSearchFieldKeyUp, _handleSearchFieldKeyDown, _handleListboxKeyDown, _handleOptionFocusChange, _registerPopoverTrigger, registerPopoverTrigger_fn, _handleSelectionChange, handleSelectionChange_fn, _registerAutoCloseListener, registerAutoCloseListener_fn, _unregisterAutoCloseListener, unregisterAutoCloseListener_fn, _autoCloseListener, _tabCloseListener;
767
852
  var GdsDropdown = class extends GdsFormControlElement {
768
853
  constructor() {
769
854
  super();
@@ -785,10 +870,12 @@ var GdsDropdown = class extends GdsFormControlElement {
785
870
  this.open = false;
786
871
  this.searchable = false;
787
872
  this.multiple = false;
873
+ this.compareWith = (a, b) => a === b;
874
+ this.searchFilter = (q, o) => o.innerHTML.toLowerCase().includes(q.toLowerCase());
788
875
  // Private members
789
- __privateAdd(this, _listboxRef, createRef2());
790
- __privateAdd(this, _triggerRef, createRef2());
791
- __privateAdd(this, _searchInputRef, createRef2());
876
+ __privateAdd(this, _listboxRef, createRef3());
877
+ __privateAdd(this, _triggerRef, createRef3());
878
+ __privateAdd(this, _searchInputRef, createRef3());
792
879
  __privateAdd(this, _optionElements, void 0);
793
880
  __privateAdd(this, _listboxId, randomId());
794
881
  __privateAdd(this, _triggerId, randomId());
@@ -798,26 +885,38 @@ var GdsDropdown = class extends GdsFormControlElement {
798
885
  * @param e The keyboard event.
799
886
  */
800
887
  __privateAdd(this, _handleSearchFieldKeyUp, (e) => {
801
- const input = e.target;
888
+ const input = __privateGet(this, _searchInputRef).value;
802
889
  const options = Array.from(__privateGet(this, _optionElements));
803
890
  options.forEach((o) => o.hidden = false);
804
891
  if (!input.value)
805
892
  return;
806
893
  const filteredOptions = options.filter(
807
- (o) => !o.innerHTML.toLowerCase().includes(input.value.toLowerCase())
894
+ (o) => !this.searchFilter(input.value, o)
808
895
  );
809
896
  filteredOptions.forEach((o) => o.hidden = true);
810
897
  });
811
898
  /**
812
- * Check for ArrowDown in the search field.
899
+ * Check for ArrowDown or Tab in the search field.
813
900
  * If found, focus should be moved to the listbox.
814
901
  */
815
902
  __privateAdd(this, _handleSearchFieldKeyDown, (e) => {
816
- if (e.key === "ArrowDown") {
903
+ if (e.key === "ArrowDown" || e.key === "Tab") {
904
+ e.preventDefault();
817
905
  __privateGet(this, _listboxRef).value?.focus();
818
906
  return;
819
907
  }
820
908
  });
909
+ /**
910
+ * Check for Tab in the listbox.
911
+ * If found, focus should be moved to the search field.
912
+ */
913
+ __privateAdd(this, _handleListboxKeyDown, (e) => {
914
+ if (e.key === "Tab" && this.searchable) {
915
+ e.preventDefault();
916
+ __privateGet(this, _searchInputRef).value?.focus();
917
+ return;
918
+ }
919
+ });
821
920
  __privateAdd(this, _handleOptionFocusChange, (e) => {
822
921
  const triggerButton = __privateGet(this, _triggerRef).value;
823
922
  if (triggerButton)
@@ -833,6 +932,13 @@ var GdsDropdown = class extends GdsFormControlElement {
833
932
  if (isClickOutside || isFocusOutside)
834
933
  this.open = false;
835
934
  });
935
+ __privateAdd(this, _tabCloseListener, (e) => {
936
+ if (e.key === "Tab" && !this.searchable) {
937
+ e.preventDefault();
938
+ this.open = false;
939
+ __privateGet(this, _triggerRef).value?.focus();
940
+ }
941
+ });
836
942
  constrainSlots(this);
837
943
  updateWhenLocaleChanges(this);
838
944
  __privateSet(this, _optionElements, this.getElementsByTagName(
@@ -897,7 +1003,7 @@ var GdsDropdown = class extends GdsFormControlElement {
897
1003
  aria-owns="${__privateGet(this, _listboxId)}"
898
1004
  aria-controls="${__privateGet(this, _listboxId)}"
899
1005
  aria-expanded="${this.open}"
900
- ${ref2(__privateGet(this, _triggerRef))}
1006
+ ${ref3(__privateGet(this, _triggerRef))}
901
1007
  >
902
1008
  <slot name="trigger">
903
1009
  <span>${unsafeHTML(this.displayValue)}</span>
@@ -907,9 +1013,10 @@ var GdsDropdown = class extends GdsFormControlElement {
907
1013
  <span class="form-info"><slot name="message"></slot></span>
908
1014
 
909
1015
  <gds-popover
1016
+ .label=${this.label}
910
1017
  .open=${this.open}
911
1018
  @gds-ui-state=${(e) => this.open = e.detail.open}
912
- ${ref2(__privateMethod(this, _registerPopoverTrigger, registerPopoverTrigger_fn))}
1019
+ ${ref3(__privateMethod(this, _registerPopoverTrigger, registerPopoverTrigger_fn))}
913
1020
  >
914
1021
  ${when2(
915
1022
  this.searchable,
@@ -917,7 +1024,7 @@ var GdsDropdown = class extends GdsFormControlElement {
917
1024
  type="text"
918
1025
  aria-label="${msg("Filter available options")}"
919
1026
  placeholder="${msg("Search")}"
920
- ${ref2(__privateGet(this, _searchInputRef))}
1027
+ ${ref3(__privateGet(this, _searchInputRef))}
921
1028
  @keydown=${__privateGet(this, _handleSearchFieldKeyDown)}
922
1029
  @keyup=${__privateGet(this, _handleSearchFieldKeyUp)}
923
1030
  />`
@@ -926,9 +1033,11 @@ var GdsDropdown = class extends GdsFormControlElement {
926
1033
  <gds-listbox
927
1034
  id="${__privateGet(this, _listboxId)}"
928
1035
  .multiple="${ifDefined(this.multiple)}"
929
- ${ref2(__privateGet(this, _listboxRef))}
1036
+ .compareWith="${this.compareWith}"
1037
+ ${ref3(__privateGet(this, _listboxRef))}
930
1038
  @change="${__privateMethod(this, _handleSelectionChange, handleSelectionChange_fn)}"
931
1039
  @gds-focus="${__privateGet(this, _handleOptionFocusChange)}"
1040
+ @keydown=${__privateGet(this, _handleListboxKeyDown)}
932
1041
  >
933
1042
  <slot gds-allow="gds-option"></slot>
934
1043
  </gds-listbox>
@@ -960,12 +1069,12 @@ var GdsDropdown = class extends GdsFormControlElement {
960
1069
  }
961
1070
  _onOpenChange() {
962
1071
  const open = this.open;
1072
+ Array.from(__privateGet(this, _optionElements)).forEach((o) => o.hidden = !open);
963
1073
  if (open)
964
1074
  __privateMethod(this, _registerAutoCloseListener, registerAutoCloseListener_fn).call(this);
965
1075
  else {
966
1076
  __privateMethod(this, _unregisterAutoCloseListener, unregisterAutoCloseListener_fn).call(this);
967
1077
  __privateGet(this, _searchInputRef).value && (__privateGet(this, _searchInputRef).value.value = "");
968
- Array.from(__privateGet(this, _optionElements)).forEach((o) => o.hidden = false);
969
1078
  }
970
1079
  this.dispatchEvent(
971
1080
  new CustomEvent("gds-ui-state", {
@@ -984,6 +1093,7 @@ _listboxId = new WeakMap();
984
1093
  _triggerId = new WeakMap();
985
1094
  _handleSearchFieldKeyUp = new WeakMap();
986
1095
  _handleSearchFieldKeyDown = new WeakMap();
1096
+ _handleListboxKeyDown = new WeakMap();
987
1097
  _handleOptionFocusChange = new WeakMap();
988
1098
  _registerPopoverTrigger = new WeakSet();
989
1099
  registerPopoverTrigger_fn = function(el) {
@@ -1017,14 +1127,17 @@ registerAutoCloseListener_fn = function() {
1017
1127
  window.addEventListener("click", __privateGet(this, _autoCloseListener));
1018
1128
  this.addEventListener("blur", __privateGet(this, _autoCloseListener));
1019
1129
  this.addEventListener("gds-blur", __privateGet(this, _autoCloseListener));
1130
+ this.addEventListener("keydown", __privateGet(this, _tabCloseListener));
1020
1131
  };
1021
1132
  _unregisterAutoCloseListener = new WeakSet();
1022
1133
  unregisterAutoCloseListener_fn = function() {
1023
1134
  window.removeEventListener("click", __privateGet(this, _autoCloseListener));
1024
1135
  this.removeEventListener("blur", __privateGet(this, _autoCloseListener));
1025
1136
  this.removeEventListener("gds-blur", __privateGet(this, _autoCloseListener));
1137
+ this.removeEventListener("keydown", __privateGet(this, _tabCloseListener));
1026
1138
  };
1027
1139
  _autoCloseListener = new WeakMap();
1140
+ _tabCloseListener = new WeakMap();
1028
1141
  GdsDropdown.styles = dropdown_styles_default;
1029
1142
  GdsDropdown.shadowRootOptions = {
1030
1143
  mode: "open",
@@ -1042,6 +1155,12 @@ __decorateClass([
1042
1155
  __decorateClass([
1043
1156
  property5({ type: Boolean, reflect: true })
1044
1157
  ], GdsDropdown.prototype, "multiple", 2);
1158
+ __decorateClass([
1159
+ property5()
1160
+ ], GdsDropdown.prototype, "compareWith", 2);
1161
+ __decorateClass([
1162
+ property5()
1163
+ ], GdsDropdown.prototype, "searchFilter", 2);
1045
1164
  __decorateClass([
1046
1165
  observeLightDOM()
1047
1166
  ], GdsDropdown.prototype, "_handleLightDOMChange", 1);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@sebgroup/green-core",
3
3
  "description": "A carefully crafted set of Web Components, laying the foundation of the Green Design System.",
4
- "version": "1.0.0-beta.14",
4
+ "version": "1.0.0-beta.16",
5
5
  "main": "index.js",
6
6
  "module": "index.js",
7
7
  "type": "module",
@@ -21,6 +21,10 @@ export declare class GdsListbox extends LitElement implements OptionsContainer {
21
21
  * Controls whether the listbox allows multiple selection or not.
22
22
  */
23
23
  multiple: boolean;
24
+ /**
25
+ * Delegate function for comparing option values.
26
+ */
27
+ compareWith: (a: any, b: any) => boolean;
24
28
  constructor();
25
29
  /**
26
30
  * Returns a list of all `gds-option` elements in the listbox.
@@ -38,7 +42,7 @@ export declare class GdsListbox extends LitElement implements OptionsContainer {
38
42
  * Returns a list of all selected `gds-option` elements in the listbox.
39
43
  */
40
44
  get selection(): GdsOption[];
41
- set selection(values: GdsOption[] | any[]);
45
+ set selection(values: any[]);
42
46
  connectedCallback(): void;
43
47
  /**
44
48
  * Focuses the first selected option in the listbox.
@@ -23,9 +23,14 @@ export declare class GdsPopover extends LitElement {
23
23
  * Optional trigger element for the popover.
24
24
  */
25
25
  trigger: HTMLElement | undefined;
26
+ /**
27
+ * Optional trigger element for the popover.
28
+ */
29
+ label: string | undefined;
26
30
  private _handleTriggerChanged;
27
31
  connectedCallback(): void;
28
32
  disconnectedCallback(): void;
29
33
  render(): import("lit-html").TemplateResult<1>;
30
- private _updateHidden;
34
+ private _handleOpenChange;
35
+ private _handleMobileLayout;
31
36
  }
@@ -21,6 +21,7 @@ var listbox_trans_styles_default = `
21
21
  display: flex;
22
22
  flex-direction: column;
23
23
  list-style: none;
24
+ overflow-y: auto;
24
25
  }
25
26
  :host > li {
26
27
  padding-bottom: 0.5rem;
@@ -1723,6 +1724,7 @@ a.button.tertiary.danger:focus {
1723
1724
  cursor: pointer;
1724
1725
  display: flex;
1725
1726
  gap: 0.75rem;
1727
+ user-select: none;
1726
1728
  }
1727
1729
  :host:not(:disabled, .disabled, [aria-disabled]):hover {
1728
1730
  background-color: #199be3;
@@ -3471,7 +3473,106 @@ a.button.tertiary.danger:focus {
3471
3473
  outline-style: solid;
3472
3474
  }
3473
3475
 
3474
- :host {
3476
+ .close {
3477
+ /* smartphones, touchscreens */
3478
+ outline: none;
3479
+ font-size: 0;
3480
+ background: hsla(var(--background-hsl), 0);
3481
+ border: 0;
3482
+ border-radius: 50%;
3483
+ content: "";
3484
+ cursor: pointer;
3485
+ display: flex;
3486
+ font-family: inherit;
3487
+ height: 2rem;
3488
+ position: relative;
3489
+ width: 2rem;
3490
+ }
3491
+ @media (hover: none) and (pointer: coarse) {
3492
+ .close:not(:disabled):not(.disabled) {
3493
+ padding: 0.375rem;
3494
+ height: 2.75rem;
3495
+ width: 2.75rem;
3496
+ }
3497
+ .close:not(:disabled):not(.disabled) > i {
3498
+ background: var(--gds-ref-pallet-base200);
3499
+ height: 2rem;
3500
+ width: 2rem;
3501
+ border-radius: 50%;
3502
+ position: relative;
3503
+ }
3504
+ .close:not(:disabled):not(.disabled) > div::after, .close:not(:disabled):not(.disabled) > div::before {
3505
+ height: 0.789375rem;
3506
+ width: 0.130625rem;
3507
+ top: 0.625rem;
3508
+ }
3509
+ }
3510
+ .close:focus-visible > i {
3511
+ border-color: var(--gds-sys-color-blue-dark-2);
3512
+ box-shadow: 0 0 0.0625rem 0 var(--gds-sys-color-blue-dark-2), 0 0 0.25rem 0.0625rem var(--gds-sys-color-blue-dark-2);
3513
+ outline-color: transparent;
3514
+ outline-style: solid;
3515
+ }
3516
+ .close > i {
3517
+ border-radius: var(--gds-sys-shape-corner-round);
3518
+ display: block;
3519
+ width: 100%;
3520
+ height: 100%;
3521
+ }
3522
+ .close > i::after, .close > i::before {
3523
+ background: var(--gds-sys-color-font);
3524
+ content: "";
3525
+ display: block;
3526
+ height: 0.789375rem;
3527
+ width: 0.130625rem;
3528
+ border-radius: 0.5px;
3529
+ left: calc(50% - 0.0625rem);
3530
+ position: absolute;
3531
+ top: 0.625rem;
3532
+ }
3533
+ .close > i::after {
3534
+ transform: rotateZ(45deg);
3535
+ }
3536
+ .close > i::before {
3537
+ transform: rotateZ(-45deg);
3538
+ }
3539
+ .close > svg path {
3540
+ fill: var(--gds-sys-color-font);
3541
+ }
3542
+ @media (min-width: 768px) {
3543
+ .close:not(:disabled, .disabled):hover > i {
3544
+ background: var(--gds-ref-pallet-base200);
3545
+ }
3546
+ .close:not(:disabled, .disabled):hover:active > i {
3547
+ background: var(--gds-ref-pallet-base500);
3548
+ }
3549
+ }
3550
+
3551
+ :host([open]) dialog {
3552
+ opacity: 1;
3553
+ transform: translate3d(0, 0, 0);
3554
+ visibility: visible;
3555
+ }
3556
+
3557
+ header {
3558
+ border-bottom: 1px solid var(--border-color);
3559
+ display: flex;
3560
+ padding: 0.5rem 0.75rem;
3561
+ }
3562
+ @media (min-width: 576px) {
3563
+ header {
3564
+ display: none;
3565
+ }
3566
+ }
3567
+
3568
+ header h2 {
3569
+ flex-grow: 1;
3570
+ font-weight: 500;
3571
+ line-height: 1.5;
3572
+ margin: 0;
3573
+ }
3574
+
3575
+ dialog {
3475
3576
  --z-index: var(--sg-z-index-popover);
3476
3577
  max-height: calc(100% - 1rem);
3477
3578
  background-color: var(--sg-popover-background);
@@ -3482,10 +3583,13 @@ a.button.tertiary.danger:focus {
3482
3583
  position: fixed;
3483
3584
  visibility: hidden;
3484
3585
  z-index: var(--z-index);
3586
+ border-width: 0;
3485
3587
  overflow: hidden;
3588
+ padding: 0;
3589
+ right: 0;
3486
3590
  }
3487
3591
  @media (max-width: 575.98px) {
3488
- :host {
3592
+ dialog {
3489
3593
  border-top: solid var(--sg-border-width) var(--sg-border-color);
3490
3594
  --border-color: var(--sg-border-color);
3491
3595
  padding-bottom: 0.5rem;
@@ -3499,7 +3603,7 @@ a.button.tertiary.danger:focus {
3499
3603
  }
3500
3604
  }
3501
3605
  @media (min-width: 576px) {
3502
- :host {
3606
+ dialog {
3503
3607
  padding-bottom: 0;
3504
3608
  border: solid var(--sg-border-width) var(--sg-border-color);
3505
3609
  --border-color: var(--sg-popover-border-color);
@@ -3511,30 +3615,47 @@ a.button.tertiary.danger:focus {
3511
3615
  position: absolute;
3512
3616
  }
3513
3617
  }
3514
- :host > [role=listbox] {
3618
+ dialog > [role=listbox] {
3515
3619
  width: 100%;
3516
3620
  overflow-y: auto;
3517
3621
  }
3518
- :host.active {
3622
+ dialog.active {
3519
3623
  opacity: 1;
3520
3624
  transform: translate3d(0, 0, 0);
3521
3625
  visibility: visible;
3522
3626
  }
3523
- :host .close {
3627
+ dialog .close {
3524
3628
  margin: 0.25rem;
3525
3629
  flex-shrink: 0;
3526
3630
  align-self: flex-end;
3527
3631
  }
3528
3632
  @media (min-width: 576px) {
3529
- :host .close {
3633
+ dialog .close {
3530
3634
  display: none;
3531
3635
  }
3532
3636
  }
3637
+ @media (max-width: 575.98px) {
3638
+ dialog {
3639
+ border-radius: 1rem;
3640
+ }
3641
+ }
3642
+ @media (min-width: 576px) {
3643
+ dialog {
3644
+ inset: auto;
3645
+ position: absolute;
3646
+ }
3647
+ }
3533
3648
 
3534
- :host([open]) {
3535
- opacity: 1;
3536
- transform: translate3d(0, 0, 0);
3537
- visibility: visible;
3649
+ dialog::backdrop {
3650
+ background-color: rgba(0, 0, 0, 0.2);
3651
+ display: block;
3652
+ pointer-events: none;
3653
+ position: fixed;
3654
+ }
3655
+ @media (min-width: 576px) {
3656
+ dialog::backdrop {
3657
+ display: none;
3658
+ }
3538
3659
  }`;
3539
3660
 
3540
3661
  // libs/core/src/primitives/popover/popover.trans.styles.ts
@@ -5472,6 +5593,7 @@ input[type=number]::-webkit-outer-spin-button, input[type=number]::-webkit-inner
5472
5593
 
5473
5594
  input[type=text] {
5474
5595
  border-radius: 0;
5596
+ font-size: 1rem;
5475
5597
  line-height: 1;
5476
5598
  margin: -1px;
5477
5599
  min-height: auto;
@@ -1,2 +1,3 @@
1
1
  export * from './watch';
2
2
  export * from './observe-light-dom';
3
+ export * from './watch-media-query';
@@ -0,0 +1,31 @@
1
+ import type { LitElement } from 'lit';
2
+ declare type Handler = (matches: boolean) => void;
3
+ /**
4
+ * Media queries expressing standard breakpoints.
5
+ * TODO: These should probably be imported from somehere, so that they are always in sync with CSS.
6
+ */
7
+ export declare const standardBreakpoints: {
8
+ sm: string;
9
+ md: string;
10
+ lg: string;
11
+ xl: string;
12
+ };
13
+ /**
14
+ * Runs when the match state of the specified media query changes.
15
+ *
16
+ * @param q The media query to watch.
17
+ *
18
+ * Usage:
19
+ * ```javascript
20
+ * \@watchMediaQuery('(max-width: 576px)')
21
+ * handleMobileLayout(matches) {
22
+ * if (matches) {
23
+ * // Do something when the media query matches
24
+ * } else
25
+ * // Do something when the media query no longer matches
26
+ * }
27
+ * }
28
+ * ```
29
+ */
30
+ export declare function watchMediaQuery(q: string): <ElemClass extends LitElement>(proto: ElemClass, _propertyKey: string, descriptor: TypedPropertyDescriptor<Handler>) => void;
31
+ export {};