@crowdstrike/glide-core 0.29.1 → 0.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. package/dist/accordion.js +240 -1
  2. package/dist/accordion.styles.js +13 -7
  3. package/dist/button-group.button.js +143 -1
  4. package/dist/button-group.button.styles.js +43 -15
  5. package/dist/button-group.js +249 -1
  6. package/dist/button-group.styles.js +10 -5
  7. package/dist/button.js +206 -1
  8. package/dist/button.styles.js +12 -7
  9. package/dist/checkbox-group.js +479 -14
  10. package/dist/checkbox-group.styles.js +5 -2
  11. package/dist/checkbox.js +519 -32
  12. package/dist/checkbox.styles.js +10 -5
  13. package/dist/drawer.js +168 -1
  14. package/dist/drawer.styles.js +5 -2
  15. package/dist/dropdown.js +2423 -123
  16. package/dist/dropdown.option.js +536 -1
  17. package/dist/dropdown.option.styles.js +5 -2
  18. package/dist/dropdown.styles.js +14 -7
  19. package/dist/form-controls-layout.js +102 -1
  20. package/dist/form-controls-layout.styles.js +5 -2
  21. package/dist/icon-button.js +139 -1
  22. package/dist/icon-button.styles.js +19 -7
  23. package/dist/icons/checked.js +28 -1
  24. package/dist/icons/chevron.js +21 -1
  25. package/dist/icons/magnifying-glass.js +23 -1
  26. package/dist/icons/pencil.js +21 -1
  27. package/dist/icons/severity-critical.js +20 -1
  28. package/dist/icons/severity-informational.js +20 -1
  29. package/dist/icons/severity-medium.js +20 -1
  30. package/dist/icons/x.js +21 -1
  31. package/dist/inline-alert.js +118 -1
  32. package/dist/inline-alert.styles.js +5 -2
  33. package/dist/input.d.ts +8 -2
  34. package/dist/input.js +505 -41
  35. package/dist/input.styles.js +25 -4
  36. package/dist/label.js +303 -1
  37. package/dist/label.styles.js +11 -5
  38. package/dist/library/assert-slot.js +136 -1
  39. package/dist/library/expect-unhandled-rejection.js +14 -1
  40. package/dist/library/expect-window-error.js +26 -1
  41. package/dist/library/final.js +18 -1
  42. package/dist/library/form-control.js +1 -1
  43. package/dist/library/localize.js +10 -1
  44. package/dist/library/mouse.js +35 -1
  45. package/dist/library/on-resize.js +24 -1
  46. package/dist/library/required.js +35 -1
  47. package/dist/library/shadow-root-mode.js +4 -1
  48. package/dist/library/unique-id.js +3 -1
  49. package/dist/link.js +92 -1
  50. package/dist/link.styles.js +10 -5
  51. package/dist/menu.d.ts +3 -2
  52. package/dist/menu.js +1259 -1
  53. package/dist/menu.styles.js +34 -17
  54. package/dist/modal.d.ts +4 -0
  55. package/dist/modal.icon-button.js +60 -1
  56. package/dist/modal.icon-button.styles.js +5 -2
  57. package/dist/modal.js +473 -1
  58. package/dist/modal.styles.js +71 -22
  59. package/dist/option.d.ts +74 -0
  60. package/dist/option.js +498 -0
  61. package/dist/option.styles.js +140 -0
  62. package/dist/{menu.options.d.ts → options.d.ts} +5 -6
  63. package/dist/options.js +130 -0
  64. package/dist/options.styles.js +21 -0
  65. package/dist/popover.js +620 -1
  66. package/dist/popover.styles.js +11 -5
  67. package/dist/radio-group.js +624 -17
  68. package/dist/radio-group.radio.js +211 -1
  69. package/dist/radio-group.radio.styles.js +9 -4
  70. package/dist/radio-group.styles.js +5 -2
  71. package/dist/slider.js +1040 -61
  72. package/dist/slider.styles.js +9 -4
  73. package/dist/spinner.js +60 -1
  74. package/dist/spinner.styles.js +5 -2
  75. package/dist/split-button.js +116 -1
  76. package/dist/split-button.primary-button.js +100 -1
  77. package/dist/split-button.primary-button.styles.js +13 -6
  78. package/dist/split-button.primary-link.js +102 -1
  79. package/dist/split-button.secondary-button.d.ts +2 -3
  80. package/dist/split-button.secondary-button.js +121 -1
  81. package/dist/split-button.secondary-button.styles.js +12 -7
  82. package/dist/split-button.styles.js +9 -4
  83. package/dist/styles/focus-outline.js +9 -3
  84. package/dist/styles/fonts.css +6 -1
  85. package/dist/styles/opacity-and-scale-animation.js +6 -3
  86. package/dist/styles/skeleton.js +6 -3
  87. package/dist/styles/variables.css +410 -1
  88. package/dist/styles/visually-hidden.js +6 -3
  89. package/dist/tab.group.js +386 -1
  90. package/dist/tab.group.styles.js +5 -2
  91. package/dist/tab.js +133 -1
  92. package/dist/tab.panel.js +93 -1
  93. package/dist/tab.panel.styles.js +11 -5
  94. package/dist/tab.styles.js +9 -4
  95. package/dist/tag.js +207 -1
  96. package/dist/tag.styles.js +10 -5
  97. package/dist/textarea.js +353 -19
  98. package/dist/textarea.styles.js +23 -4
  99. package/dist/toast.js +130 -1
  100. package/dist/toast.toasts.js +248 -25
  101. package/dist/toast.toasts.styles.js +9 -4
  102. package/dist/toggle.js +178 -1
  103. package/dist/toggle.styles.js +25 -5
  104. package/dist/tooltip.container.d.ts +2 -0
  105. package/dist/tooltip.container.js +130 -1
  106. package/dist/tooltip.container.styles.js +18 -4
  107. package/dist/tooltip.d.ts +6 -0
  108. package/dist/tooltip.js +484 -1
  109. package/dist/tooltip.styles.js +21 -5
  110. package/dist/translations/en.js +36 -1
  111. package/dist/translations/fr.js +37 -1
  112. package/dist/translations/ja.js +37 -1
  113. package/package.json +8 -12
  114. package/dist/menu.button.d.ts +0 -42
  115. package/dist/menu.button.js +0 -1
  116. package/dist/menu.button.styles.js +0 -32
  117. package/dist/menu.link.d.ts +0 -44
  118. package/dist/menu.link.js +0 -1
  119. package/dist/menu.link.styles.js +0 -35
  120. package/dist/menu.options.js +0 -1
  121. package/dist/menu.options.styles.d.ts +0 -2
  122. package/dist/menu.options.styles.js +0 -20
  123. /package/dist/{menu.button.styles.d.ts → option.styles.d.ts} +0 -0
  124. /package/dist/{menu.link.styles.d.ts → options.styles.d.ts} +0 -0
@@ -1 +1,536 @@
1
- var __decorate=this&&this.__decorate||function(e,t,i,o){var l,s=arguments.length,a=s<3?t:null===o?o=Object.getOwnPropertyDescriptor(t,i):o;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)a=Reflect.decorate(e,t,i,o);else for(var n=e.length-1;n>=0;n--)(l=e[n])&&(a=(s<3?l(a):s>3?l(t,i,a):l(t,i))||a);return s>3&&a&&Object.defineProperty(t,i,a),a};import"./checkbox.js";import"./tooltip.js";import{html,LitElement}from"lit";import{ifDefined}from"lit/directives/if-defined.js";import{classMap}from"lit/directives/class-map.js";import{createRef,ref}from"lit/directives/ref.js";import{customElement,property,state}from"lit/decorators.js";import{when}from"lit/directives/when.js";import packageJson from"../package.json"with{type:"json"};import checkedIcon from"./icons/checked.js";import pencilIcon from"./icons/pencil.js";import{LocalizeController}from"./library/localize.js";import styles from"./dropdown.option.styles.js";import shadowRootMode from"./library/shadow-root-mode.js";import final from"./library/final.js";import required from"./library/required.js";import uniqueId from"./library/unique-id.js";let DropdownOption=class DropdownOption extends LitElement{constructor(){super(...arguments),this.id=uniqueId(),this.privateActive=!1,this.privateIndeterminate=!1,this.privateIsEditActive=!1,this.privateIsTooltipOpen=!1,this.privateMultiple=!1,this.role="option",this.tabIndex=-1,this.version=packageJson.version,this.isLabelOverflow=!1,this.#e=createRef(),this.#t=createRef(),this.#i=!1,this.#o=!1,this.#l=createRef(),this.#s=new LocalizeController(this),this.#a=!1,this.#n=""}static{this.shadowRootOptions={...LitElement.shadowRootOptions,mode:shadowRootMode}}static{this.styles=styles}get label(){return this.#r}set label(e){this.#r=e,setTimeout((()=>{this.#d()})),this.dispatchEvent(new Event("private-label-change",{bubbles:!0}))}get disabled(){return this.#i}set disabled(e){this.#i=e,this.ariaDisabled=e.toString(),this.#e.value?.checked&&e?this.#e.value.checked=!1:this.#e.value&&this.selected&&!e&&(this.#e.value.checked=!0),this.dispatchEvent(new Event("private-disabled-change",{bubbles:!0}))}get editable(){return this.#o}set editable(e){this.#o=e,this.dispatchEvent(new Event("private-editable-change",{bubbles:!0}))}get selected(){return this.#a}set selected(e){this.#a=e,this.isMultiple&&this.#e.value&&(this.#e.value.checked=e),this.dispatchEvent(new Event("private-selected-change",{bubbles:!0}))}get value(){return this.#n}set value(e){this.dispatchEvent(new CustomEvent("private-value-change",{bubbles:!0,detail:{old:this.value,new:e}})),this.#n=e}get isMultiple(){return this.privateMultiple||this.closest("glide-core-dropdown")?.multiple}get lastSelectedAndEnabledOption(){const e=this.parentElement?.querySelectorAll("glide-core-dropdown-option");if(e&&e.length>0)return[...e].findLast((e=>e.selected&&!e.disabled))}click(){this.privateMultiple?this.#e.value?.click():this.#t.value?.click()}connectedCallback(){super.connectedCallback(),this.ariaDisabled=this.disabled.toString(),this.#c=new IntersectionObserver((()=>{this.checkVisibility()&&this.#d()})),this.#c.observe(this)}disconnectedCallback(){super.disconnectedCallback(),this.#c?.disconnect()}firstUpdated(){this.#e.value&&(this.#e.value.checked=this.selected&&!this.disabled)}privateEdit(){this.dispatchEvent(new Event("edit",{bubbles:!0,composed:!0}))}async privateUpdateCheckbox(){await this.updateComplete,this.#e.value&&(this.#e.value.checked=this.selected)}render(){return html`<div class="${classMap({component:!0,active:this.privateActive,disabled:this.disabled})}" data-test="component" ${ref(this.#t)}>${when(this.isMultiple,(()=>html`<glide-core-checkbox class="${classMap({checkbox:!0,editable:this.editable})}" data-test="checkbox" label="${this.label??""}" tabindex="-1" private-label-tooltip-offset="${12}" private-variant="minimal" value="${this.value}" @click="${this.#p}" private-internally-inert ?disabled="${this.disabled}" ?indeterminate="${this.privateIndeterminate}" ?private-show-label-tooltip="${this.privateIsTooltipOpen}" ?private-disable-label-tooltip="${this.disabled}" ${ref(this.#e)}><slot class="checkbox-icon-slot" name="icon" slot="private-icon"></slot></glide-core-checkbox>${when(this.editable,(()=>html`<button aria-label="${this.#s.term("editOption",this.label)}" class="${classMap({"edit-button":!0,active:this.privateIsEditActive,count:Boolean(this.count),disabled:this.disabled,multiple:Boolean(this.isMultiple)})}" data-test="edit-button" type="button" @mouseover="${this.#h}" @mouseout="${this.#b}">${pencilIcon}</button>`))} ${when(this.count&&this.count>0,(()=>html`<div class="${classMap({"count-container":!0,disabled:this.disabled})}" data-test="count-container">${when(this.count>=1e3,(()=>"999+"),(()=>this.count))}</div>`))}`),(()=>html`<div class="${classMap({option:!0,count:Boolean(this.count),disabled:this.disabled,editable:this.editable})}"><slot class="${classMap({"icon-slot":!0})}" name="icon"></slot><glide-core-tooltip class="tooltip" data-test="tooltip" label="${ifDefined(this.label)}" offset="${10}" ?disabled="${!this.isLabelOverflow||this.disabled}" ?open="${this.privateIsTooltipOpen}" screenreader-hidden @toggle="${this.#u}"><div class="label" data-test="label" slot="target" ${ref(this.#l)}>${this.label}</div></glide-core-tooltip>${when(this.selected&&this===this.lastSelectedAndEnabledOption&&!this.disabled,(()=>html`<div class="checked-icon-container" data-test="checked-icon-container">${checkedIcon}</div>`))} ${when(this.editable,(()=>html`<button aria-label="${this.#s.term("editOption",this.label)}" class="${classMap({"edit-button":!0,active:this.privateActive&&this.privateIsEditActive,count:Boolean(this.count),disabled:this.disabled})}" data-test="edit-button" type="button" @mouseover="${this.#h}" @mouseout="${this.#b}">${pencilIcon}</button>`))} ${when(this.count&&this.count>0,(()=>html`<div class="${classMap({"count-container":!0,disabled:this.disabled})}" data-test="count-container">${when(this.count>=1e3,(()=>"999+"),(()=>this.count))}</div>`))}</div>`))}</div>`}updated(){this.privateMultiple?this.ariaSelected=!this.disabled&&this.selected?"true":"false":this.ariaSelected=!this.disabled&&this.selected&&this===this.lastSelectedAndEnabledOption?"true":"false"}#e;#t;#c;#i;#o;#r;#l;#s;#a;#n;#p(e){e.stopPropagation()}#b(){this.privateIsEditActive=!1}#h(){this.privateIsEditActive=!0}#u(e){e.stopPropagation()}#d(){this.#l.value&&(this.isLabelOverflow=this.#l.value.scrollWidth>this.#l.value.clientWidth)}};__decorate([property({reflect:!0}),required],DropdownOption.prototype,"label",null),__decorate([property({reflect:!0,type:Number})],DropdownOption.prototype,"count",void 0),__decorate([property({reflect:!0,type:Boolean})],DropdownOption.prototype,"disabled",null),__decorate([property({reflect:!0,type:Boolean})],DropdownOption.prototype,"editable",null),__decorate([property({reflect:!0})],DropdownOption.prototype,"id",void 0),__decorate([property({type:Boolean})],DropdownOption.prototype,"privateActive",void 0),__decorate([property({attribute:"private-indeterminate",type:Boolean})],DropdownOption.prototype,"privateIndeterminate",void 0),__decorate([property({type:Boolean})],DropdownOption.prototype,"privateIsEditActive",void 0),__decorate([property({type:Boolean})],DropdownOption.prototype,"privateIsTooltipOpen",void 0),__decorate([property({attribute:"private-multiple",type:Boolean})],DropdownOption.prototype,"privateMultiple",void 0),__decorate([property({reflect:!0})],DropdownOption.prototype,"role",void 0),__decorate([property({type:Boolean})],DropdownOption.prototype,"selected",null),__decorate([property({attribute:"tabindex",reflect:!0,type:Number})],DropdownOption.prototype,"tabIndex",void 0),__decorate([property({reflect:!0})],DropdownOption.prototype,"value",null),__decorate([property({reflect:!0})],DropdownOption.prototype,"version",void 0),__decorate([state()],DropdownOption.prototype,"isMultiple",null),__decorate([state()],DropdownOption.prototype,"lastSelectedAndEnabledOption",null),__decorate([state()],DropdownOption.prototype,"isLabelOverflow",void 0),DropdownOption=__decorate([customElement("glide-core-dropdown-option"),final],DropdownOption);export default DropdownOption;
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import './checkbox.js';
8
+ import './tooltip.js';
9
+ import { html, LitElement } from 'lit';
10
+ import { ifDefined } from 'lit/directives/if-defined.js';
11
+ import { classMap } from 'lit/directives/class-map.js';
12
+ import { createRef, ref } from 'lit/directives/ref.js';
13
+ import { customElement, property, state } from 'lit/decorators.js';
14
+ import { when } from 'lit/directives/when.js';
15
+ import packageJson from '../package.json' with { type: 'json' };
16
+ import checkedIcon from './icons/checked.js';
17
+ import pencilIcon from './icons/pencil.js';
18
+ import { LocalizeController } from './library/localize.js';
19
+ import styles from './dropdown.option.styles.js';
20
+ import shadowRootMode from './library/shadow-root-mode.js';
21
+ import final from './library/final.js';
22
+ import required from './library/required.js';
23
+ import uniqueId from './library/unique-id.js';
24
+ /**
25
+ * @attr {string} label
26
+ * @attr {number} [count]
27
+ * @attr {boolean} [disabled=false]
28
+ * @attr {boolean} [editable=false]
29
+ *
30
+ * @readonly
31
+ * @attr {string} [id]
32
+ *
33
+ * @readonly
34
+ * @attr {string} [role='option']
35
+ *
36
+ * @attr {boolean} [selected=false]
37
+ *
38
+ * @readonly
39
+ * @attr {number} [tabindex=-1]
40
+ *
41
+ * @attr {string} [value='']
42
+ *
43
+ * @readonly
44
+ * @attr {string} [version]
45
+ *
46
+ * @slot {Element} [icon] - An icon before the label
47
+ *
48
+ * @fires {Event} edit
49
+ */
50
+ let DropdownOption = class DropdownOption extends LitElement {
51
+ constructor() {
52
+ super(...arguments);
53
+ // On the host instead of inside the shadow DOM so screenreaders can find it
54
+ // when Dropdown uses it with `aria-activedescendant`.
55
+ this.id = uniqueId();
56
+ // An option is considered active when it's interacted with via keyboard or
57
+ // hovered. Used by Dropdown.
58
+ this.privateActive = false;
59
+ // Private because it's only meant to be used by Dropdown.
60
+ this.privateIndeterminate = false;
61
+ // Private because it's only meant to be used by Dropdown.
62
+ this.privateIsEditActive = false;
63
+ this.privateIsTooltipOpen = false;
64
+ // Private because it's only meant to be used by Dropdown.
65
+ this.privateMultiple = false;
66
+ this.role = 'option';
67
+ this.tabIndex = -1;
68
+ this.version = packageJson.version;
69
+ this.isLabelOverflow = false;
70
+ this.#checkboxElementRef = createRef();
71
+ this.#componentElementRef = createRef();
72
+ this.#isDisabled = false;
73
+ this.#isEditable = false;
74
+ this.#labelElementRef = createRef();
75
+ this.#localize = new LocalizeController(this);
76
+ this.#selected = false;
77
+ this.#value = '';
78
+ }
79
+ static { this.shadowRootOptions = {
80
+ ...LitElement.shadowRootOptions,
81
+ mode: shadowRootMode,
82
+ }; }
83
+ static { this.styles = styles; }
84
+ /**
85
+ * @default undefined
86
+ */
87
+ get label() {
88
+ return this.#label;
89
+ }
90
+ set label(label) {
91
+ this.#label = label;
92
+ // Wait for the label to render. A rerender won't be scheduled by Lit
93
+ // until after this setter finishes. So awaiting `this.updateComplete`
94
+ // won't fly.
95
+ setTimeout(() => {
96
+ this.#updateLabelOverflow();
97
+ });
98
+ this.dispatchEvent(new Event('private-label-change', {
99
+ bubbles: true,
100
+ }));
101
+ }
102
+ /**
103
+ * @default false
104
+ */
105
+ get disabled() {
106
+ return this.#isDisabled;
107
+ }
108
+ set disabled(isDisabled) {
109
+ this.#isDisabled = isDisabled;
110
+ this.ariaDisabled = isDisabled.toString();
111
+ if (this.#checkboxElementRef.value?.checked && isDisabled) {
112
+ this.#checkboxElementRef.value.checked = false;
113
+ }
114
+ else if (this.#checkboxElementRef.value && this.selected && !isDisabled) {
115
+ this.#checkboxElementRef.value.checked = true;
116
+ }
117
+ this.dispatchEvent(new Event('private-disabled-change', { bubbles: true }));
118
+ }
119
+ /**
120
+ * @default false
121
+ */
122
+ get editable() {
123
+ return this.#isEditable;
124
+ }
125
+ set editable(isEditable) {
126
+ this.#isEditable = isEditable;
127
+ this.dispatchEvent(new Event('private-editable-change', {
128
+ bubbles: true,
129
+ }));
130
+ }
131
+ /**
132
+ * @default false
133
+ */
134
+ get selected() {
135
+ return this.#selected;
136
+ }
137
+ set selected(isSelected) {
138
+ this.#selected = isSelected;
139
+ if (this.isMultiple && this.#checkboxElementRef.value) {
140
+ this.#checkboxElementRef.value.checked = isSelected;
141
+ }
142
+ this.dispatchEvent(new Event('private-selected-change', { bubbles: true }));
143
+ }
144
+ /**
145
+ * @default ''
146
+ */
147
+ get value() {
148
+ return this.#value;
149
+ }
150
+ set value(value) {
151
+ // `this.value` can be set programmatically. Dropdown needs to know when that
152
+ // happens so it can update its own `this.value`.
153
+ this.dispatchEvent(new CustomEvent('private-value-change', {
154
+ bubbles: true,
155
+ // Without knowing what the old value was, Dropdown would be unable to find the
156
+ // value in its `this.value` array and remove it.
157
+ detail: {
158
+ old: this.value,
159
+ new: value,
160
+ },
161
+ }));
162
+ this.#value = value;
163
+ }
164
+ get isMultiple() {
165
+ // The soonest Dropdown can set `this.privateMultiple` is in its `firstUpdated`.
166
+ // By then, however, this component has has already completed its initial render.
167
+ // So we fall sadly back to `this.closest('glide-core-dropdown')`.
168
+ //
169
+ // `this.privateMultiple` is still useful fwhen Dropdown's `this.multiple` is set
170
+ // programmatically.
171
+ return (this.privateMultiple || this.closest('glide-core-dropdown')?.multiple);
172
+ }
173
+ get lastSelectedAndEnabledOption() {
174
+ const options = this.parentElement?.querySelectorAll('glide-core-dropdown-option');
175
+ if (options && options.length > 0) {
176
+ return [...options].findLast((option) => option.selected && !option.disabled);
177
+ }
178
+ }
179
+ click() {
180
+ if (this.privateMultiple) {
181
+ this.#checkboxElementRef.value?.click();
182
+ }
183
+ else {
184
+ this.#componentElementRef.value?.click();
185
+ }
186
+ }
187
+ connectedCallback() {
188
+ super.connectedCallback();
189
+ this.ariaDisabled = this.disabled.toString();
190
+ // Options are arbitrarily shown and hidden when Dropdown is opened and closed. So
191
+ // calling `#updateLabelOverflow` in the `label` setter isn't sufficient because
192
+ // the label's `scrollWidth` and `clientWidth` will both be zero until Dropdown
193
+ // is open. So, rather than expose a pseudo-private method for Dropdown to call
194
+ // on open, Dropdown Option simply monitors its own visibility.
195
+ this.#intersectionObserver = new IntersectionObserver(() => {
196
+ if (this.checkVisibility()) {
197
+ this.#updateLabelOverflow();
198
+ }
199
+ });
200
+ this.#intersectionObserver.observe(this);
201
+ }
202
+ disconnectedCallback() {
203
+ super.disconnectedCallback();
204
+ this.#intersectionObserver?.disconnect();
205
+ }
206
+ firstUpdated() {
207
+ if (this.#checkboxElementRef.value) {
208
+ this.#checkboxElementRef.value.checked = this.selected && !this.disabled;
209
+ }
210
+ }
211
+ privateEdit() {
212
+ this.dispatchEvent(new Event('edit', { bubbles: true, composed: true }));
213
+ }
214
+ async privateUpdateCheckbox() {
215
+ // Hacky indeed. This is for the case where Dropdown is set programmatically
216
+ // from a single to a multiselect. `this.isMultiple` is set to `true` but
217
+ // `this.#checkboxElementRef.value` in the `multiple` setter is `undefined`
218
+ // because this component hasn't had a chance to rerender. So we wait for it
219
+ // to rerender then update the checkbox to match `this.selected`. Halp!
220
+ await this.updateComplete;
221
+ if (this.#checkboxElementRef.value) {
222
+ this.#checkboxElementRef.value.checked = this.selected;
223
+ }
224
+ }
225
+ render() {
226
+ // The linter wants a keyboard handler. There's one on Dropdown itself. It's there
227
+ // because options aren't focusable and thus don't produce keyboard events when
228
+ // Dropdown is filterable.
229
+ return html `<div
230
+ class=${classMap({
231
+ component: true,
232
+ active: this.privateActive,
233
+ disabled: this.disabled,
234
+ })}
235
+ data-test="component"
236
+ ${ref(this.#componentElementRef)}
237
+ >
238
+ ${when(this.isMultiple, () => {
239
+ return html `
240
+ <glide-core-checkbox
241
+ class=${classMap({
242
+ checkbox: true,
243
+ editable: this.editable,
244
+ })}
245
+ data-test="checkbox"
246
+ label=${this.label ?? ''}
247
+ tabindex="-1"
248
+ private-label-tooltip-offset=${12}
249
+ private-variant="minimal"
250
+ value=${this.value}
251
+ @click=${this.#onCheckboxClick}
252
+ private-internally-inert
253
+ ?disabled=${this.disabled}
254
+ ?indeterminate=${this.privateIndeterminate}
255
+ ?private-show-label-tooltip=${this.privateIsTooltipOpen}
256
+ ?private-disable-label-tooltip=${this.disabled}
257
+ ${ref(this.#checkboxElementRef)}
258
+ >
259
+ <slot class="checkbox-icon-slot" name="icon" slot="private-icon">
260
+ <!--
261
+ An icon before the label
262
+ @type {Element}
263
+ -->
264
+ </slot>
265
+ </glide-core-checkbox>
266
+
267
+ ${when(this.editable, () => {
268
+ return html `<button
269
+ aria-label=${this.#localize.term('editOption',
270
+ // `this.label` is always defined because it's a required attribute.
271
+ //
272
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
273
+ this.label)}
274
+ class=${classMap({
275
+ 'edit-button': true,
276
+ active: this.privateIsEditActive,
277
+ count: Boolean(this.count),
278
+ disabled: this.disabled,
279
+ multiple: Boolean(this.isMultiple),
280
+ })}
281
+ data-test="edit-button"
282
+ type="button"
283
+ @mouseover=${this.#onEditButtonMouseover}
284
+ @mouseout=${this.#onEditButtonMouseout}
285
+ >
286
+ ${pencilIcon}
287
+ </button>`;
288
+ })}
289
+ ${when(this.count && this.count > 0, () => {
290
+ return html `<div
291
+ class=${classMap({
292
+ 'count-container': true,
293
+ disabled: this.disabled,
294
+ })}
295
+ data-test="count-container"
296
+ >
297
+ ${when(
298
+ // `this.count` is guaranteed to be defined by the `when()` above.
299
+ //
300
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
301
+ this.count >= 1000, () => {
302
+ return '999+';
303
+ }, () => {
304
+ return this.count;
305
+ })}
306
+ </div>`;
307
+ })}
308
+ `;
309
+ }, () => {
310
+ return html `
311
+ <div
312
+ class=${classMap({
313
+ option: true,
314
+ count: Boolean(this.count),
315
+ disabled: this.disabled,
316
+ editable: this.editable,
317
+ })}
318
+ >
319
+ <slot
320
+ class=${classMap({
321
+ 'icon-slot': true,
322
+ })}
323
+ name="icon"
324
+ >
325
+ <!--
326
+ An icon before the label
327
+ @type {Element}
328
+ -->
329
+ </slot>
330
+
331
+ <glide-core-tooltip
332
+ class="tooltip"
333
+ data-test="tooltip"
334
+ label=${ifDefined(this.label)}
335
+ offset=${10}
336
+ ?disabled=${!this.isLabelOverflow || this.disabled}
337
+ ?open=${this.privateIsTooltipOpen}
338
+ screenreader-hidden
339
+ @toggle=${this.#onTooltipToggle}>
340
+
341
+ <div
342
+ class="label"
343
+ data-test="label"
344
+ slot="target"
345
+ ${ref(this.#labelElementRef)}
346
+ >
347
+ ${this.label}
348
+ </div>
349
+ </glide-core-tooltip>
350
+
351
+ ${when(this.selected &&
352
+ this === this.lastSelectedAndEnabledOption &&
353
+ !this.disabled, () => {
354
+ return html `<div
355
+ class="checked-icon-container"
356
+ data-test="checked-icon-container"
357
+ >
358
+ ${checkedIcon}
359
+ </div>`;
360
+ })}
361
+
362
+ ${when(this.editable, () => {
363
+ return html `<button
364
+ aria-label=${this.#localize.term('editOption',
365
+ // `this.label` is always defined because it's a required attribute.
366
+ //
367
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
368
+ this.label)}
369
+ class=${classMap({
370
+ 'edit-button': true,
371
+ active: this.privateActive && this.privateIsEditActive,
372
+ count: Boolean(this.count),
373
+ disabled: this.disabled,
374
+ })}
375
+ data-test="edit-button"
376
+ type="button"
377
+ @mouseover=${this.#onEditButtonMouseover}
378
+ @mouseout=${this.#onEditButtonMouseout}
379
+ >
380
+ ${pencilIcon}
381
+ </button>`;
382
+ })}
383
+
384
+ ${when(this.count && this.count > 0, () => {
385
+ return html `<div
386
+ class=${classMap({
387
+ 'count-container': true,
388
+ disabled: this.disabled,
389
+ })}
390
+ data-test="count-container"
391
+ >
392
+ ${when(
393
+ // `this.count` is guaranteed to be defined by the `when()` above.
394
+ //
395
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
396
+ this.count >= 1000, () => {
397
+ return '999+';
398
+ }, () => {
399
+ return this.count;
400
+ })}
401
+ </div>`;
402
+ })}
403
+ </div>
404
+ </div>`;
405
+ })}
406
+ </div>`;
407
+ }
408
+ updated() {
409
+ // `this.ariaSelected` needs to be updated whenever `disabled`, `privateMulitple`,
410
+ // `selected`, or `this.lastSelectedAndEnabledOption` change.
411
+ //
412
+ // The logic below could be duplicated and added to each setter. But that wouldn't
413
+ // account for when `this.lastSelectedAndEnabledOption` is forcibly updated by
414
+ // Dropdown because another option has been selected or deselected.
415
+ //
416
+ // Setting `this.ariaSelected` here ensures `this.ariaSelected` is updated whenever
417
+ // `this.lastSelectedAndEnabledOption` changes. As a bonus, this logic is
418
+ // deduplicated.
419
+ if (this.privateMultiple) {
420
+ this.ariaSelected = !this.disabled && this.selected ? 'true' : 'false';
421
+ }
422
+ else {
423
+ this.ariaSelected =
424
+ !this.disabled &&
425
+ this.selected &&
426
+ this === this.lastSelectedAndEnabledOption
427
+ ? 'true'
428
+ : 'false';
429
+ }
430
+ }
431
+ #checkboxElementRef;
432
+ #componentElementRef;
433
+ #intersectionObserver;
434
+ #isDisabled;
435
+ #isEditable;
436
+ #label;
437
+ #labelElementRef;
438
+ #localize;
439
+ #selected;
440
+ #value;
441
+ #onCheckboxClick(event) {
442
+ // Form controls emit two events when their labels are clicked: one from the
443
+ // label, another from the control. Letting these events propagate would mean
444
+ // Dropdown receiving multiple "click" events and thus dispatching multiple
445
+ // "change" and "input" events.
446
+ //
447
+ // This is also why Dropdown listens for "input" when multiselect and "click"
448
+ // when single-select.
449
+ event.stopPropagation();
450
+ }
451
+ #onEditButtonMouseout() {
452
+ // A simple `:hover:` selector would be nice. But Dropdown needs to know if the
453
+ // button is active to decide what to do when the user is arrowing, among other
454
+ // things.
455
+ this.privateIsEditActive = false;
456
+ }
457
+ #onEditButtonMouseover() {
458
+ this.privateIsEditActive = true;
459
+ }
460
+ #onTooltipToggle(event) {
461
+ // Dropdown dispatches its own "toggle" event. Letting Tooltip's "toggle"
462
+ // propagate would mean that consumers listening for the event on Dropdown
463
+ // would have to filter it out when it comes from Tooltip. But first they'll
464
+ // probably file a bug. It's likely no consumer will be interested in knowing
465
+ // when this component's Tooltip is open. So it's probably best to stop the
466
+ // event from propagating.
467
+ event.stopPropagation();
468
+ }
469
+ #updateLabelOverflow() {
470
+ if (this.#labelElementRef.value) {
471
+ this.isLabelOverflow =
472
+ this.#labelElementRef.value.scrollWidth >
473
+ this.#labelElementRef.value.clientWidth;
474
+ }
475
+ }
476
+ };
477
+ __decorate([
478
+ property({ reflect: true }),
479
+ required
480
+ ], DropdownOption.prototype, "label", null);
481
+ __decorate([
482
+ property({ reflect: true, type: Number })
483
+ ], DropdownOption.prototype, "count", void 0);
484
+ __decorate([
485
+ property({ reflect: true, type: Boolean })
486
+ ], DropdownOption.prototype, "disabled", null);
487
+ __decorate([
488
+ property({ reflect: true, type: Boolean })
489
+ ], DropdownOption.prototype, "editable", null);
490
+ __decorate([
491
+ property({ reflect: true })
492
+ ], DropdownOption.prototype, "id", void 0);
493
+ __decorate([
494
+ property({ type: Boolean })
495
+ ], DropdownOption.prototype, "privateActive", void 0);
496
+ __decorate([
497
+ property({ attribute: 'private-indeterminate', type: Boolean })
498
+ ], DropdownOption.prototype, "privateIndeterminate", void 0);
499
+ __decorate([
500
+ property({ type: Boolean })
501
+ ], DropdownOption.prototype, "privateIsEditActive", void 0);
502
+ __decorate([
503
+ property({ type: Boolean })
504
+ ], DropdownOption.prototype, "privateIsTooltipOpen", void 0);
505
+ __decorate([
506
+ property({ attribute: 'private-multiple', type: Boolean })
507
+ ], DropdownOption.prototype, "privateMultiple", void 0);
508
+ __decorate([
509
+ property({ reflect: true })
510
+ ], DropdownOption.prototype, "role", void 0);
511
+ __decorate([
512
+ property({ type: Boolean })
513
+ ], DropdownOption.prototype, "selected", null);
514
+ __decorate([
515
+ property({ attribute: 'tabindex', reflect: true, type: Number })
516
+ ], DropdownOption.prototype, "tabIndex", void 0);
517
+ __decorate([
518
+ property({ reflect: true })
519
+ ], DropdownOption.prototype, "value", null);
520
+ __decorate([
521
+ property({ reflect: true })
522
+ ], DropdownOption.prototype, "version", void 0);
523
+ __decorate([
524
+ state()
525
+ ], DropdownOption.prototype, "isMultiple", null);
526
+ __decorate([
527
+ state()
528
+ ], DropdownOption.prototype, "lastSelectedAndEnabledOption", null);
529
+ __decorate([
530
+ state()
531
+ ], DropdownOption.prototype, "isLabelOverflow", void 0);
532
+ DropdownOption = __decorate([
533
+ customElement('glide-core-dropdown-option'),
534
+ final
535
+ ], DropdownOption);
536
+ export default DropdownOption;
@@ -1,4 +1,6 @@
1
- import{css}from"lit";export default[css`
1
+ import { css } from 'lit';
2
+ export default [
3
+ css `
2
4
  .component {
3
5
  align-items: center;
4
6
  block-size: var(--private-option-height);
@@ -144,4 +146,5 @@ import{css}from"lit";export default[css`
144
146
  color: var(--glide-core-icon-tertiary-disabled);
145
147
  }
146
148
  }
147
- `];
149
+ `,
150
+ ];
@@ -1,9 +1,15 @@
1
- import{css}from"lit";import opacityAndScaleAnimation from"./styles/opacity-and-scale-animation.js";import visuallyHidden from"./styles/visually-hidden.js";import skeleton from"./styles/skeleton.js";export default[css`
2
- ${opacityAndScaleAnimation(".options-and-feedback:popover-open")}
3
- ${skeleton(".loading-feedback")}
4
- ${visuallyHidden(".item-count")}
5
- ${visuallyHidden(".selected-option-labels")}
6
- `,css`
1
+ import { css } from 'lit';
2
+ import opacityAndScaleAnimation from './styles/opacity-and-scale-animation.js';
3
+ import visuallyHidden from './styles/visually-hidden.js';
4
+ import skeleton from './styles/skeleton.js';
5
+ export default [
6
+ css `
7
+ ${opacityAndScaleAnimation('.options-and-feedback:popover-open')}
8
+ ${skeleton('.loading-feedback')}
9
+ ${visuallyHidden('.item-count')}
10
+ ${visuallyHidden('.selected-option-labels')}
11
+ `,
12
+ css `
7
13
  .component {
8
14
  --private-min-inline-size: 9.375rem;
9
15
 
@@ -385,4 +391,5 @@ import{css}from"lit";import opacityAndScaleAnimation from"./styles/opacity-and-s
385
391
  .validity-message {
386
392
  display: block;
387
393
  }
388
- `];
394
+ `,
395
+ ];