@felleslosninger/minid-elements 0.0.100 → 0.0.102

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 (45) hide show
  1. package/dist/components/alert.component.d.ts.map +1 -1
  2. package/dist/components/alert.js +3 -4
  3. package/dist/components/alert.js.map +1 -1
  4. package/dist/components/button.component.d.ts +3 -2
  5. package/dist/components/button.component.d.ts.map +1 -1
  6. package/dist/components/button.js +12 -5
  7. package/dist/components/button.js.map +1 -1
  8. package/dist/components/combobox.component.d.ts +2 -2
  9. package/dist/components/combobox.component.d.ts.map +1 -1
  10. package/dist/components/combobox.js +1 -1
  11. package/dist/components/combobox.js.map +1 -1
  12. package/dist/components/dropdown.component.d.ts +47 -3
  13. package/dist/components/dropdown.component.d.ts.map +1 -1
  14. package/dist/components/dropdown.js +262 -29
  15. package/dist/components/dropdown.js.map +1 -1
  16. package/dist/components/link.js +1 -1
  17. package/dist/components/link.js.map +1 -1
  18. package/dist/components/menu-item.component.d.ts +3 -0
  19. package/dist/components/menu-item.component.d.ts.map +1 -1
  20. package/dist/components/menu-item.js +20 -2
  21. package/dist/components/menu-item.js.map +1 -1
  22. package/dist/components/menu.component.d.ts +1 -1
  23. package/dist/components/menu.component.d.ts.map +1 -1
  24. package/dist/components/menu.js +4 -4
  25. package/dist/components/menu.js.map +1 -1
  26. package/dist/components/phone-input.js +1 -1
  27. package/dist/components/phone-input.js.map +1 -1
  28. package/dist/components/popup.component.d.ts +0 -1
  29. package/dist/components/popup.component.d.ts.map +1 -1
  30. package/dist/components/popup.js +1 -14
  31. package/dist/components/popup.js.map +1 -1
  32. package/dist/components/step-indicator.component.d.ts +14 -0
  33. package/dist/components/step-indicator.component.d.ts.map +1 -0
  34. package/dist/components/step-indicator.js +58 -0
  35. package/dist/components/step-indicator.js.map +1 -0
  36. package/dist/events/events.d.ts +2 -0
  37. package/dist/events/events.d.ts.map +1 -0
  38. package/dist/events/mid-select.d.ts +10 -0
  39. package/dist/events/mid-select.d.ts.map +1 -0
  40. package/dist/index.d.ts +3 -1
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/index.js +3 -1
  43. package/dist/index.js.map +1 -1
  44. package/dist/mixins/tailwind.mixin.js +2 -2
  45. package/package.json +9 -6
@@ -1,9 +1,14 @@
1
1
  import { css, LitElement, html } from "lit";
2
- import { property, customElement } from "lit/decorators.js";
2
+ import { query, property, customElement } from "lit/decorators.js";
3
3
  import { ifDefined } from "lit/directives/if-defined.js";
4
+ import { classMap } from "lit/directives/class-map.js";
4
5
  import { styled } from "../mixins/tailwind.mixin.js";
5
6
  import "./popup.js";
6
- import { classMap } from "lit/directives/class-map.js";
7
+ import { getAnimation, setDefaultAnimation } from "../utilities/animation-registry.js";
8
+ import { waitForEvent } from "../internal/event.js";
9
+ import { watch } from "../internal/watch.js";
10
+ import { stopAnimations, animateTo } from "../internal/animate.js";
11
+ import { getTabbableBoundary } from "../internal/tabbable.js";
7
12
  var __defProp = Object.defineProperty;
8
13
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
9
14
  var __decorateClass = (decorators, target, key, kind) => {
@@ -27,43 +32,228 @@ let MinidDropdown = class extends styled(LitElement, styles) {
27
32
  super(...arguments);
28
33
  this.popupId = `mid-dropdown-${nextUniqueId++}`;
29
34
  this.open = false;
35
+ this.disabled = false;
36
+ this.stayopenonselect = false;
30
37
  this.size = "md";
31
38
  this.placement = "bottom-end";
32
39
  this.distance = 4;
33
40
  this.skidding = 0;
34
41
  this.arrow = false;
35
42
  this.hoist = false;
36
- this.handleClickOutside = (event) => {
37
- if (!event.composedPath().includes(this)) {
38
- this.toggleDropdownOpen(event, false);
43
+ this.handleKeyDown = (event) => {
44
+ if (this.open && event.key === "Escape") {
45
+ event.stopPropagation();
46
+ this.hide();
47
+ this.focusOnTrigger();
48
+ }
49
+ };
50
+ this.handleDocumentKeyDown = (event) => {
51
+ if (event.key === "Escape" && this.open && !this.closeWatcher) {
52
+ event.stopPropagation();
53
+ this.focusOnTrigger();
54
+ this.hide();
55
+ return;
56
+ }
57
+ if (event.key === "Tab") {
58
+ const composedPath = event.composedPath();
59
+ const tabbedIsMenuItem = composedPath.some(
60
+ (e) => e.tagName?.toLowerCase() === "mid-menu-item"
61
+ );
62
+ if (this.open && tabbedIsMenuItem) {
63
+ event.preventDefault();
64
+ this.hide();
65
+ this.focusOnTrigger();
66
+ return;
67
+ }
68
+ setTimeout(() => {
69
+ if (composedPath.every((target) => target !== this.containingElement)) {
70
+ this.hide();
71
+ }
72
+ });
73
+ }
74
+ };
75
+ this.handleDocumentMouseDown = (event) => {
76
+ const path = event.composedPath();
77
+ if (this.containingElement && !path.includes(this.containingElement)) {
78
+ this.hide();
39
79
  }
40
80
  };
41
- this.handleAnchorClick = (event) => {
42
- if (event.detail.id !== this.popupId) {
43
- this.toggleDropdownOpen(event, false);
81
+ this.handlePanelSelect = (event) => {
82
+ const target = event.target;
83
+ if (!this.stayopenonselect && target.tagName.toLowerCase() === "mid-menu") {
84
+ this.hide();
85
+ this.focusOnTrigger();
44
86
  }
45
87
  };
46
88
  }
47
- toggleDropdownOpen(event, open) {
48
- event.stopPropagation();
49
- if (open !== void 0) {
50
- this.open = open;
89
+ connectedCallback() {
90
+ super.connectedCallback();
91
+ if (!this.containingElement) {
92
+ this.containingElement = this;
93
+ }
94
+ }
95
+ firstUpdated() {
96
+ this.panel.hidden = !this.open;
97
+ if (this.open) {
98
+ this.addOpenListeners();
99
+ this.popup.active = true;
100
+ }
101
+ }
102
+ disconnectedCallback() {
103
+ super.disconnectedCallback();
104
+ this.removeOpenListeners();
105
+ this.hide();
106
+ }
107
+ focusOnTrigger() {
108
+ const trigger = this.trigger.assignedElements({ flatten: true })[0];
109
+ if (typeof trigger?.focus === "function") {
110
+ trigger.focus();
111
+ }
112
+ }
113
+ getMenu() {
114
+ return this.panel.assignedElements({ flatten: true }).find((el) => el.tagName.toLowerCase() === "mid-menu");
115
+ }
116
+ handleTriggerClick() {
117
+ if (this.open) {
118
+ this.hide();
51
119
  } else {
52
- this.open = !this.open;
120
+ this.show();
121
+ this.focusOnTrigger();
53
122
  }
123
+ }
124
+ async handleTriggerKeyDown(event) {
125
+ if ([" ", "Enter"].includes(event.key)) {
126
+ event.preventDefault();
127
+ this.handleTriggerClick();
128
+ return;
129
+ }
130
+ const menu = this.getMenu();
131
+ if (menu) {
132
+ const menuItems = menu.getAllSelectableItems();
133
+ const firstMenuItem = menuItems[0];
134
+ const lastMenuItem = menuItems[menuItems.length - 1];
135
+ if (["ArrowDown", "ArrowUp", "Home", "End"].includes(event.key)) {
136
+ event.preventDefault();
137
+ if (!this.open) {
138
+ this.show();
139
+ await this.updateComplete;
140
+ }
141
+ if (menuItems.length > 0) {
142
+ this.updateComplete.then(() => {
143
+ if (event.key === "ArrowDown" || event.key === "Home") {
144
+ menu.setCurrentItem(firstMenuItem);
145
+ firstMenuItem.focus();
146
+ }
147
+ if (event.key === "ArrowUp" || event.key === "End") {
148
+ menu.setCurrentItem(lastMenuItem);
149
+ lastMenuItem.focus();
150
+ }
151
+ });
152
+ }
153
+ }
154
+ }
155
+ }
156
+ handleTriggerKeyUp(event) {
157
+ if (event.key === " ") {
158
+ event.preventDefault();
159
+ }
160
+ }
161
+ handleTriggerSlotChange() {
162
+ this.updateAccessibleTrigger();
163
+ }
164
+ updateAccessibleTrigger() {
165
+ const assignedElements = this.trigger.assignedElements({
166
+ flatten: true
167
+ });
168
+ const accessibleTrigger = assignedElements.find(
169
+ (el) => getTabbableBoundary(el).start
170
+ );
171
+ let target;
172
+ if (accessibleTrigger) {
173
+ if (accessibleTrigger.tagName.toLowerCase() === "mid-button") {
174
+ target = accessibleTrigger.button;
175
+ } else {
176
+ target = accessibleTrigger;
177
+ }
178
+ target.setAttribute("aria-haspopup", "true");
179
+ target.setAttribute("aria-expanded", this.open ? "true" : "false");
180
+ }
181
+ }
182
+ /**
183
+ * Shows the dropdown panel.
184
+ */
185
+ async show() {
54
186
  if (this.open) {
55
- addEventListener("click", this.handleClickOutside);
56
- addEventListener(
57
- "mid-anchor-click",
58
- this.handleAnchorClick
59
- );
187
+ return void 0;
188
+ }
189
+ this.open = true;
190
+ return waitForEvent(this, "mid-after-show");
191
+ }
192
+ /**
193
+ * Hides the dropdown panel
194
+ */
195
+ async hide() {
196
+ if (!this.open) {
197
+ return void 0;
198
+ }
199
+ this.open = false;
200
+ return waitForEvent(this, "mid-after-hide");
201
+ }
202
+ /**
203
+ * Instructs the dropdown menu to reposition. Useful when the position or size of the trigger changes when the menu
204
+ * is activated.
205
+ */
206
+ reposition() {
207
+ this.popup.reposition();
208
+ }
209
+ addOpenListeners() {
210
+ this.panel.addEventListener("mid-select", this.handlePanelSelect);
211
+ if ("CloseWatcher" in window) {
212
+ this.closeWatcher?.destroy();
213
+ this.closeWatcher = new CloseWatcher();
214
+ this.closeWatcher.onclose = () => {
215
+ this.hide();
216
+ this.focusOnTrigger();
217
+ };
60
218
  } else {
61
- this.blur();
62
- removeEventListener(
63
- "mid-anchor-click",
64
- this.handleAnchorClick
65
- );
66
- removeEventListener("click", this.handleClickOutside);
219
+ this.panel.addEventListener("keydown", this.handleKeyDown);
220
+ }
221
+ document.addEventListener("keydown", this.handleDocumentKeyDown);
222
+ document.addEventListener("mousedown", this.handleDocumentMouseDown);
223
+ }
224
+ removeOpenListeners() {
225
+ if (this.panel) {
226
+ this.panel.removeEventListener("mid-select", this.handlePanelSelect);
227
+ this.panel.removeEventListener("keydown", this.handleKeyDown);
228
+ }
229
+ document.removeEventListener("keydown", this.handleDocumentKeyDown);
230
+ document.removeEventListener("mousedown", this.handleDocumentMouseDown);
231
+ this.closeWatcher?.destroy();
232
+ }
233
+ async handleOpenChange() {
234
+ if (this.disabled) {
235
+ this.open = false;
236
+ return;
237
+ }
238
+ this.updateAccessibleTrigger();
239
+ if (this.open) {
240
+ this.dispatchEvent(new Event("mid-show"));
241
+ this.addOpenListeners();
242
+ await stopAnimations(this);
243
+ this.panel.hidden = false;
244
+ this.popup.active = true;
245
+ const { keyframes, options } = getAnimation(this, "dropdown.show");
246
+ await animateTo(this.popup.popup, keyframes, options);
247
+ this.dispatchEvent(new Event("mid-after-show"));
248
+ } else {
249
+ this.dispatchEvent(new Event("mid-hide"));
250
+ this.removeOpenListeners();
251
+ await stopAnimations(this);
252
+ const { keyframes, options } = getAnimation(this, "dropdown.hide");
253
+ await animateTo(this.popup.popup, keyframes, options);
254
+ this.panel.hidden = true;
255
+ this.popup.active = false;
256
+ this.dispatchEvent(new Event("mid-after-hide"));
67
257
  }
68
258
  }
69
259
  render() {
@@ -74,7 +264,7 @@ let MinidDropdown = class extends styled(LitElement, styles) {
74
264
  "text-body-sm": this.size === "sm",
75
265
  "text-body-md": this.size === "md",
76
266
  "text-body-lg": this.size === "lg"
77
- })} [--arrow-border-color:var(--border-color-neutral-subtle)] [--arrow-size:8px]"
267
+ })} popup [--arrow-border-color:var(--border-color-neutral-subtle)] [--arrow-size:8px]"
78
268
  distance=${this.distance}
79
269
  placement="${this.placement}"
80
270
  skidding=${this.skidding}
@@ -84,24 +274,47 @@ let MinidDropdown = class extends styled(LitElement, styles) {
84
274
  auto-size="vertical"
85
275
  auto-size-padding="10"
86
276
  sync=${ifDefined(this.sync)}
87
- ?active=${this.open}
88
277
  ?arrow=${this.arrow}
89
- @click=${this.toggleDropdownOpen}
90
278
  >
91
- <slot slot="anchor" name="trigger"> </slot>
279
+ <slot
280
+ slot="anchor"
281
+ name="trigger"
282
+ class="trigger"
283
+ @click=${this.handleTriggerClick}
284
+ @keydown=${this.handleTriggerKeyDown}
285
+ @keyup=${this.handleTriggerKeyUp}
286
+ @slotchange=${this.handleTriggerSlotChange}
287
+ >
288
+ </slot>
92
289
  <div
290
+ class="bg-accent min-w-68"
93
291
  aria-hidden=${this.open ? "false" : "true"}
94
292
  aria-labelledby="${this.popupId}"
95
293
  >
96
- <slot part="panel"></slot>
294
+ <slot part="panel" class="panel"></slot>
97
295
  </div>
98
296
  </mid-popup>
99
297
  `;
100
298
  }
101
299
  };
300
+ __decorateClass([
301
+ query(".popup")
302
+ ], MinidDropdown.prototype, "popup", 2);
303
+ __decorateClass([
304
+ query(".trigger")
305
+ ], MinidDropdown.prototype, "trigger", 2);
306
+ __decorateClass([
307
+ query(".panel")
308
+ ], MinidDropdown.prototype, "panel", 2);
102
309
  __decorateClass([
103
310
  property({ type: Boolean, reflect: true })
104
311
  ], MinidDropdown.prototype, "open", 2);
312
+ __decorateClass([
313
+ property({ type: Boolean, reflect: true })
314
+ ], MinidDropdown.prototype, "disabled", 2);
315
+ __decorateClass([
316
+ property({ type: Boolean, reflect: true })
317
+ ], MinidDropdown.prototype, "stayopenonselect", 2);
105
318
  __decorateClass([
106
319
  property()
107
320
  ], MinidDropdown.prototype, "size", 2);
@@ -123,9 +336,29 @@ __decorateClass([
123
336
  __decorateClass([
124
337
  property({ type: Boolean })
125
338
  ], MinidDropdown.prototype, "hoist", 2);
339
+ __decorateClass([
340
+ property({ attribute: false })
341
+ ], MinidDropdown.prototype, "containingElement", 2);
342
+ __decorateClass([
343
+ watch("open", { waitUntilFirstUpdate: true })
344
+ ], MinidDropdown.prototype, "handleOpenChange", 1);
126
345
  MinidDropdown = __decorateClass([
127
346
  customElement("mid-dropdown")
128
347
  ], MinidDropdown);
348
+ setDefaultAnimation("dropdown.show", {
349
+ keyframes: [
350
+ { opacity: 0, scale: 0.9 },
351
+ { opacity: 1, scale: 1 }
352
+ ],
353
+ options: { duration: 100, easing: "ease" }
354
+ });
355
+ setDefaultAnimation("dropdown.hide", {
356
+ keyframes: [
357
+ { opacity: 1, scale: 1 },
358
+ { opacity: 0, scale: 0.9 }
359
+ ],
360
+ options: { duration: 100, easing: "ease" }
361
+ });
129
362
  export {
130
363
  MinidDropdown
131
364
  };
@@ -1 +1 @@
1
- {"version":3,"file":"dropdown.js","sources":["../../src/components/dropdown.component.ts"],"sourcesContent":["import { css, html, LitElement } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport { styled } from '../mixins/tailwind.mixin.ts';\nimport './popup.component';\nimport { classMap } from 'lit/directives/class-map.js';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'mid-dropdown': MinidDropdown;\n }\n}\n\nlet nextUniqueId = 0;\n\nconst styles = [\n css`\n :host {\n display: inline-flex;\n }\n `,\n];\n\n/**\n * @slot -- Default slot for content of the dropdown panel\n * @slot trigger - Used for the button element that will be used to open the dropdown menu\n * @part panel - Select the dropdown panel host element\n */\n@customElement('mid-dropdown')\nexport class MinidDropdown extends styled(LitElement, styles) {\n private readonly popupId = `mid-dropdown-${nextUniqueId++}`;\n\n @property({ type: Boolean, reflect: true })\n open = false;\n\n @property()\n size: 'sm' | 'md' | 'lg' = 'md';\n\n @property({ reflect: true })\n placement:\n | 'top'\n | 'top-start'\n | 'top-end'\n | 'bottom'\n | 'bottom-start'\n | 'bottom-end'\n | 'right'\n | 'right-start'\n | 'right-end'\n | 'left'\n | 'left-start'\n | 'left-end' = 'bottom-end';\n\n /**\n * Sync the dropdown panel size with the trigger element\n */\n @property({ reflect: true })\n sync?: 'width' | 'height' | 'both';\n\n /**\n * Distance between trigger and dropdown panel\n */\n @property({ type: Number })\n distance = 4;\n\n /**\n * Nudge the dropdown panel position. Accepts a negative or positive number.\n */\n @property({ type: Number })\n skidding = 0;\n\n @property({ type: Boolean })\n arrow = false;\n\n /**\n * Choose if position is `fixed` or `absolute`. `absolute` is more performant,\n * but `fixed` can solve issues with overflow clipping\n */\n @property({ type: Boolean })\n hoist = false;\n\n private handleClickOutside = (event: Event) => {\n if (!event.composedPath().includes(this)) {\n this.toggleDropdownOpen(event, false);\n }\n };\n\n private toggleDropdownOpen(event: Event, open?: boolean) {\n event.stopPropagation();\n\n if (open !== undefined) {\n this.open = open;\n } else {\n this.open = !this.open;\n }\n\n if (this.open) {\n addEventListener('click', this.handleClickOutside);\n addEventListener(\n 'mid-anchor-click',\n this.handleAnchorClick as EventListener\n );\n } else {\n this.blur();\n removeEventListener(\n 'mid-anchor-click',\n this.handleAnchorClick as EventListener\n );\n removeEventListener('click', this.handleClickOutside);\n }\n }\n\n private handleAnchorClick = (event: CustomEvent<{ id: string }>) => {\n // to make sure clicking another element's anchor closes current element's dropdown menu\n if (event.detail.id !== this.popupId) {\n this.toggleDropdownOpen(event, false);\n }\n };\n\n override render() {\n return html`\n <mid-popup\n id=\"${this.popupId}\"\n class=\"${classMap({\n 'text-body-sm': this.size === 'sm',\n 'text-body-md': this.size === 'md',\n 'text-body-lg': this.size === 'lg',\n })} [--arrow-border-color:var(--border-color-neutral-subtle)] [--arrow-size:8px]\"\n distance=${this.distance}\n placement=\"${this.placement}\"\n skidding=${this.skidding}\n strategy=${this.hoist ? 'fixed' : 'absolute'}\n flip\n shift\n auto-size=\"vertical\"\n auto-size-padding=\"10\"\n sync=${ifDefined(this.sync)}\n ?active=${this.open}\n ?arrow=${this.arrow}\n @click=${this.toggleDropdownOpen}\n >\n <slot slot=\"anchor\" name=\"trigger\"> </slot>\n <div\n aria-hidden=${this.open ? 'false' : 'true'}\n aria-labelledby=\"${this.popupId}\"\n >\n <slot part=\"panel\"></slot>\n </div>\n </mid-popup>\n `;\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dropdown.js","sources":["../../src/components/dropdown.component.ts"],"sourcesContent":["import { css, html, LitElement } from 'lit';\nimport { customElement, property, query } from 'lit/decorators.js';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { styled } from '../mixins/tailwind.mixin.ts';\nimport './popup.component';\nimport {\n getAnimation,\n setDefaultAnimation,\n} from '../utilities/animation-registry.ts';\nimport { waitForEvent } from '../internal/event.ts';\nimport { MinidPopup } from './popup.component';\nimport { watch } from '../internal/watch.ts';\nimport { animateTo, stopAnimations } from '../internal/animate.ts';\nimport { getTabbableBoundary } from '../internal/tabbable.ts';\nimport { MinidButton } from '../components/button.component.ts';\nimport { MidSelectEvent } from '../events/mid-select.ts';\nimport { MinidMenu } from '../components/menu.component.ts';\nimport { MinidMenuItem } from 'src/components/menu-item.component.ts';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'mid-dropdown': MinidDropdown;\n }\n}\n\nlet nextUniqueId = 0;\n\nconst styles = [\n css`\n :host {\n display: inline-flex;\n }\n `,\n];\n\n/**\n * @slot -- Default slot for content of the dropdown panel\n * @slot trigger - Used for the button element that will be used to open the dropdown menu\n * @part panel - Select the dropdown panel host element\n */\n@customElement('mid-dropdown')\nexport class MinidDropdown extends styled(LitElement, styles) {\n private readonly popupId = `mid-dropdown-${nextUniqueId++}`;\n private closeWatcher?: CloseWatcher | null;\n\n @query('.popup')\n popup!: MinidPopup;\n\n @query('.trigger')\n trigger!: HTMLSlotElement;\n\n @query('.panel')\n panel!: HTMLSlotElement;\n\n @property({ type: Boolean, reflect: true })\n open = false;\n\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n /**\n * By default, the dropdown is closed when an item is selected. This attribute will keep it open instead. Useful for\n * dropdowns that allow for multiple interactions.\n */\n @property({ type: Boolean, reflect: true })\n stayopenonselect = false;\n\n @property()\n size: 'sm' | 'md' | 'lg' = 'md';\n\n @property({ reflect: true })\n placement:\n | 'top'\n | 'top-start'\n | 'top-end'\n | 'bottom'\n | 'bottom-start'\n | 'bottom-end'\n | 'right'\n | 'right-start'\n | 'right-end'\n | 'left'\n | 'left-start'\n | 'left-end' = 'bottom-end';\n\n /**\n * Sync the dropdown panel size with the trigger element\n */\n @property({ reflect: true })\n sync?: 'width' | 'height' | 'both';\n\n /**\n * Distance between trigger and dropdown panel\n */\n @property({ type: Number })\n distance = 4;\n\n /**\n * Nudge the dropdown panel position. Accepts a negative or positive number.\n */\n @property({ type: Number })\n skidding = 0;\n\n @property({ type: Boolean })\n arrow = false;\n\n /**\n * Choose if position is `fixed` or `absolute`. `absolute` is more performant,\n * but `fixed` can solve issues with overflow clipping\n */\n @property({ type: Boolean })\n hoist = false;\n\n /**\n * The dropdown will close when the user interacts outside of this element (e.g. clicking). Useful for composing other\n * components that use a dropdown internally.\n */\n @property({ attribute: false })\n containingElement?: HTMLElement;\n\n connectedCallback() {\n super.connectedCallback();\n\n if (!this.containingElement) {\n this.containingElement = this;\n }\n }\n\n firstUpdated() {\n this.panel.hidden = !this.open;\n\n // If the dropdown is visible on init, update its position\n if (this.open) {\n this.addOpenListeners();\n this.popup.active = true;\n }\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n this.removeOpenListeners();\n this.hide();\n }\n\n focusOnTrigger() {\n const trigger = this.trigger.assignedElements({ flatten: true })[0] as\n | HTMLElement\n | undefined;\n if (typeof trigger?.focus === 'function') {\n trigger.focus();\n }\n }\n\n getMenu() {\n return this.panel\n .assignedElements({ flatten: true })\n .find((el) => el.tagName.toLowerCase() === 'mid-menu') as\n | MinidMenu\n | undefined;\n }\n\n private handleKeyDown = (event: KeyboardEvent) => {\n // Close when escape is pressed inside an open dropdown. We need to listen on the panel itself and stop propagation\n // in case any ancestors are also listening for this key.\n if (this.open && event.key === 'Escape') {\n event.stopPropagation();\n this.hide();\n this.focusOnTrigger();\n }\n };\n\n private handleDocumentKeyDown = (event: KeyboardEvent) => {\n // Close when escape or tab is pressed\n if (event.key === 'Escape' && this.open && !this.closeWatcher) {\n event.stopPropagation();\n this.focusOnTrigger();\n this.hide();\n return;\n }\n\n // Handle tabbing\n if (event.key === 'Tab') {\n const composedPath = event.composedPath();\n const tabbedIsMenuItem = composedPath.some(\n (e): e is MinidMenuItem =>\n (e as HTMLElement).tagName?.toLowerCase() === 'mid-menu-item'\n );\n\n // Tabbing within an open menu should close the dropdown and refocus the trigger\n if (this.open && tabbedIsMenuItem) {\n event.preventDefault();\n this.hide();\n this.focusOnTrigger();\n return;\n }\n\n // Tabbing outside of the containing element closes the panel\n //\n // If the dropdown is used within a shadow DOM, we need to obtain the activeElement within that shadowRoot,\n // otherwise `document.activeElement` will only return the name of the parent shadow DOM element.\n setTimeout(() => {\n if (composedPath.every((target) => target !== this.containingElement)) {\n this.hide();\n }\n });\n }\n };\n\n private handleDocumentMouseDown = (event: MouseEvent) => {\n // Close when clicking outside of the containing element\n const path = event.composedPath();\n\n if (this.containingElement && !path.includes(this.containingElement)) {\n this.hide();\n }\n };\n\n private handlePanelSelect = (event: MidSelectEvent) => {\n const target = event.target as HTMLElement;\n\n // Hide the dropdown when a menu item is selected\n if (!this.stayopenonselect && target.tagName.toLowerCase() === 'mid-menu') {\n this.hide();\n this.focusOnTrigger();\n }\n };\n\n handleTriggerClick() {\n if (this.open) {\n this.hide();\n } else {\n this.show();\n this.focusOnTrigger();\n }\n }\n\n async handleTriggerKeyDown(event: KeyboardEvent) {\n // When spacebar/enter is pressed, show the panel but don't focus on the menu. This let's the user press the same\n // key again to hide the menu in case they don't want to make a selection.\n if ([' ', 'Enter'].includes(event.key)) {\n event.preventDefault();\n this.handleTriggerClick();\n return;\n }\n\n const menu = this.getMenu();\n\n if (menu) {\n const menuItems = menu.getAllSelectableItems();\n const firstMenuItem = menuItems[0];\n const lastMenuItem = menuItems[menuItems.length - 1];\n\n // When up/down is pressed, we make the assumption that the user is familiar with the menu and plans to make a\n // selection. Rather than toggle the panel, we focus on the menu (if one exists) and activate the first item for\n // faster navigation.\n if (['ArrowDown', 'ArrowUp', 'Home', 'End'].includes(event.key)) {\n event.preventDefault();\n\n // Show the menu if it's not already open\n if (!this.open) {\n this.show();\n\n // Wait for the dropdown to open before focusing, but not the animation\n await this.updateComplete;\n }\n\n if (menuItems.length > 0) {\n // Focus on the first/last menu item after showing\n this.updateComplete.then(() => {\n if (event.key === 'ArrowDown' || event.key === 'Home') {\n menu.setCurrentItem(firstMenuItem);\n firstMenuItem.focus();\n }\n\n if (event.key === 'ArrowUp' || event.key === 'End') {\n menu.setCurrentItem(lastMenuItem);\n lastMenuItem.focus();\n }\n });\n }\n }\n }\n }\n\n handleTriggerKeyUp(event: KeyboardEvent) {\n // Prevent space from triggering a click event in Firefox\n if (event.key === ' ') {\n event.preventDefault();\n }\n }\n\n handleTriggerSlotChange() {\n this.updateAccessibleTrigger();\n }\n\n updateAccessibleTrigger() {\n const assignedElements = this.trigger.assignedElements({\n flatten: true,\n }) as HTMLElement[];\n const accessibleTrigger = assignedElements.find(\n (el) => getTabbableBoundary(el).start\n );\n let target: HTMLElement;\n if (accessibleTrigger) {\n if (accessibleTrigger.tagName.toLowerCase() === 'mid-button') {\n target = (accessibleTrigger as MinidButton).button;\n } else {\n target = accessibleTrigger;\n }\n\n target.setAttribute('aria-haspopup', 'true');\n target.setAttribute('aria-expanded', this.open ? 'true' : 'false');\n }\n }\n\n /**\n * Shows the dropdown panel.\n */\n async show() {\n if (this.open) {\n return undefined;\n }\n\n this.open = true;\n return waitForEvent(this, 'mid-after-show');\n }\n\n /**\n * Hides the dropdown panel\n */\n async hide() {\n if (!this.open) {\n return undefined;\n }\n\n this.open = false;\n return waitForEvent(this, 'mid-after-hide');\n }\n\n /**\n * Instructs the dropdown menu to reposition. Useful when the position or size of the trigger changes when the menu\n * is activated.\n */\n reposition() {\n this.popup.reposition();\n }\n\n addOpenListeners() {\n this.panel.addEventListener('mid-select', this.handlePanelSelect);\n if ('CloseWatcher' in window) {\n this.closeWatcher?.destroy();\n this.closeWatcher = new CloseWatcher();\n this.closeWatcher.onclose = () => {\n this.hide();\n this.focusOnTrigger();\n };\n } else {\n this.panel.addEventListener('keydown', this.handleKeyDown);\n }\n document.addEventListener('keydown', this.handleDocumentKeyDown);\n document.addEventListener('mousedown', this.handleDocumentMouseDown);\n }\n\n removeOpenListeners() {\n if (this.panel) {\n this.panel.removeEventListener('mid-select', this.handlePanelSelect);\n this.panel.removeEventListener('keydown', this.handleKeyDown);\n }\n document.removeEventListener('keydown', this.handleDocumentKeyDown);\n document.removeEventListener('mousedown', this.handleDocumentMouseDown);\n this.closeWatcher?.destroy();\n }\n\n @watch('open', { waitUntilFirstUpdate: true })\n async handleOpenChange() {\n if (this.disabled) {\n this.open = false;\n return;\n }\n\n this.updateAccessibleTrigger();\n\n if (this.open) {\n // Show\n this.dispatchEvent(new Event('mid-show'));\n this.addOpenListeners();\n\n await stopAnimations(this);\n this.panel.hidden = false;\n this.popup.active = true;\n const { keyframes, options } = getAnimation(this, 'dropdown.show');\n await animateTo(this.popup.popup, keyframes, options);\n\n this.dispatchEvent(new Event('mid-after-show'));\n } else {\n // Hide\n this.dispatchEvent(new Event('mid-hide'));\n this.removeOpenListeners();\n\n await stopAnimations(this);\n const { keyframes, options } = getAnimation(this, 'dropdown.hide');\n await animateTo(this.popup.popup, keyframes, options);\n this.panel.hidden = true;\n this.popup.active = false;\n\n this.dispatchEvent(new Event('mid-after-hide'));\n }\n }\n\n override render() {\n return html`\n <mid-popup\n id=\"${this.popupId}\"\n class=\"${classMap({\n 'text-body-sm': this.size === 'sm',\n 'text-body-md': this.size === 'md',\n 'text-body-lg': this.size === 'lg',\n })} popup [--arrow-border-color:var(--border-color-neutral-subtle)] [--arrow-size:8px]\"\n distance=${this.distance}\n placement=\"${this.placement}\"\n skidding=${this.skidding}\n strategy=${this.hoist ? 'fixed' : 'absolute'}\n flip\n shift\n auto-size=\"vertical\"\n auto-size-padding=\"10\"\n sync=${ifDefined(this.sync)}\n ?arrow=${this.arrow}\n >\n <slot\n slot=\"anchor\"\n name=\"trigger\"\n class=\"trigger\"\n @click=${this.handleTriggerClick}\n @keydown=${this.handleTriggerKeyDown}\n @keyup=${this.handleTriggerKeyUp}\n @slotchange=${this.handleTriggerSlotChange}\n >\n </slot>\n <div\n class=\"bg-accent min-w-68\"\n aria-hidden=${this.open ? 'false' : 'true'}\n aria-labelledby=\"${this.popupId}\"\n >\n <slot part=\"panel\" class=\"panel\"></slot>\n </div>\n </mid-popup>\n `;\n }\n}\n\nsetDefaultAnimation('dropdown.show', {\n keyframes: [\n { opacity: 0, scale: 0.9 },\n { opacity: 1, scale: 1 },\n ],\n options: { duration: 100, easing: 'ease' },\n});\n\nsetDefaultAnimation('dropdown.hide', {\n keyframes: [\n { opacity: 1, scale: 1 },\n { opacity: 0, scale: 0.9 },\n ],\n options: { duration: 100, easing: 'ease' },\n});\n"],"names":[],"mappings":"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"}
@@ -16,7 +16,7 @@ let MinidLink = class extends styled(LitElement) {
16
16
  render() {
17
17
  return html`
18
18
  <a
19
- class="text-accent-subtle visited:text-link-visited focus-visible:bg-focus-outer inline-flex items-center gap-2 underline decoration-[.0625rem] underline-offset-[.27em] outline-0 focus-visible:text-white"
19
+ class="text-accent-subtle visited:text-link-visited focus-visible:bg-focus-outer hover:text-accent inline-flex items-center gap-2 underline decoration-[.0625rem] underline-offset-[.27em] outline-0 hover:decoration-[.125rem] focus-visible:text-white"
20
20
  href=${ifDefined(this.href)}
21
21
  target=${ifDefined(this.target)}
22
22
  >
@@ -1 +1 @@
1
- {"version":3,"file":"link.js","sources":["../../src/components/link.component.ts"],"sourcesContent":["import { html, LitElement } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport { styled } from '../mixins/tailwind.mixin';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'mid-link': MinidLink;\n }\n}\n\n@customElement('mid-link')\nexport class MinidLink extends styled(LitElement) {\n @property()\n href?: string;\n\n @property()\n target?: string;\n\n override render() {\n return html`\n <a\n class=\"text-accent-subtle visited:text-link-visited focus-visible:bg-focus-outer inline-flex items-center gap-2 underline decoration-[.0625rem] underline-offset-[.27em] outline-0 focus-visible:text-white\"\n href=${ifDefined(this.href)}\n target=${ifDefined(this.target)}\n >\n <slot></slot>\n </a>\n `;\n }\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;AAYO,IAAM,YAAN,cAAwB,OAAO,UAAU,EAAE;AAAA,EAOvC,SAAS;AACT,WAAA;AAAA;AAAA;AAAA,eAGI,UAAU,KAAK,IAAI,CAAC;AAAA,iBAClB,UAAU,KAAK,MAAM,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,EAAA;AAMvC;AAhBE,gBAAA;AAAA,EADC,SAAS;AAAA,GADC,UAEX,WAAA,QAAA,CAAA;AAGA,gBAAA;AAAA,EADC,SAAS;AAAA,GAJC,UAKX,WAAA,UAAA,CAAA;AALW,YAAN,gBAAA;AAAA,EADN,cAAc,UAAU;AAAA,GACZ,SAAA;"}
1
+ {"version":3,"file":"link.js","sources":["../../src/components/link.component.ts"],"sourcesContent":["import { html, LitElement } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport { styled } from '../mixins/tailwind.mixin';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'mid-link': MinidLink;\n }\n}\n\n@customElement('mid-link')\nexport class MinidLink extends styled(LitElement) {\n @property()\n href?: string;\n\n @property()\n target?: string;\n\n override render() {\n return html`\n <a\n class=\"text-accent-subtle visited:text-link-visited focus-visible:bg-focus-outer hover:text-accent inline-flex items-center gap-2 underline decoration-[.0625rem] underline-offset-[.27em] outline-0 hover:decoration-[.125rem] focus-visible:text-white\"\n href=${ifDefined(this.href)}\n target=${ifDefined(this.target)}\n >\n <slot></slot>\n </a>\n `;\n }\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;AAYO,IAAM,YAAN,cAAwB,OAAO,UAAU,EAAE;AAAA,EAOvC,SAAS;AACT,WAAA;AAAA;AAAA;AAAA,eAGI,UAAU,KAAK,IAAI,CAAC;AAAA,iBAClB,UAAU,KAAK,MAAM,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,EAAA;AAMvC;AAhBE,gBAAA;AAAA,EADC,SAAS;AAAA,GADC,UAEX,WAAA,QAAA,CAAA;AAGA,gBAAA;AAAA,EADC,SAAS;AAAA,GAJC,UAKX,WAAA,UAAA,CAAA;AALW,YAAN,gBAAA;AAAA,EADN,cAAc,UAAU;AAAA,GACZ,SAAA;"}
@@ -25,6 +25,9 @@ export declare class MinidMenuItem extends MinidMenuItem_base {
25
25
  */
26
26
  active: boolean;
27
27
  connectedCallback(): void;
28
+ disconnectedCallback(): void;
29
+ handleKeyDown(event: KeyboardEvent): void;
30
+ handleHostFocus(): void;
28
31
  focus(): void;
29
32
  setActive(active: boolean): void;
30
33
  render(): import('lit-html').TemplateResult<1>;
@@ -1 +1 @@
1
- {"version":3,"file":"menu-item.component.d.ts","sourceRoot":"","sources":["../../src/components/menu-item.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,UAAU,EAAE,MAAM,KAAK,CAAC;AAIvC,OAAO,oBAAoB,CAAC;AAC5B,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAGjD,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,eAAe,EAAE,aAAa,CAAC;KAChC;CACF;;AAED,qBACa,aAAc,SAAQ,kBAAkB;IAEnD,MAAM,EAAG,WAAW,CAAC;IAErB;;OAEG;IAEH,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IAEzB;;OAEG;IAEH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;OAEG;IAEH,OAAO,EAAE,UAAU,GAAG,UAAU,CAAc;IAE9C;;OAEG;IAEH,MAAM,UAAS;IAEf,iBAAiB,IAAI,IAAI;IAKzB,KAAK,IAAI,IAAI;IAIb,SAAS,CAAC,MAAM,EAAE,OAAO;IAIhB,MAAM;CA0BhB"}
1
+ {"version":3,"file":"menu-item.component.d.ts","sourceRoot":"","sources":["../../src/components/menu-item.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,UAAU,EAAE,MAAM,KAAK,CAAC;AAIvC,OAAO,oBAAoB,CAAC;AAC5B,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAGjD,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,eAAe,EAAE,aAAa,CAAC;KAChC;CACF;;AAED,qBACa,aAAc,SAAQ,kBAAkB;IAEnD,MAAM,EAAG,WAAW,CAAC;IAErB;;OAEG;IAEH,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IAEzB;;OAEG;IAEH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;OAEG;IAEH,OAAO,EAAE,UAAU,GAAG,UAAU,CAAc;IAE9C;;OAEG;IAEH,MAAM,UAAS;IAEf,iBAAiB,IAAI,IAAI;IAOzB,oBAAoB,IAAI,IAAI;IAM5B,aAAa,CAAC,KAAK,EAAE,aAAa;IAMlC,eAAe;IAQf,KAAK,IAAI,IAAI;IAIb,SAAS,CAAC,MAAM,EAAE,OAAO;IAIhB,MAAM;CA0BhB"}
@@ -23,6 +23,24 @@ let MinidMenuItem = class extends styled(LitElement) {
23
23
  connectedCallback() {
24
24
  super.connectedCallback();
25
25
  this.setAttribute("role", "menuitem");
26
+ this.addEventListener("focus", this.handleHostFocus);
27
+ this.addEventListener("keydown", this.handleKeyDown);
28
+ }
29
+ disconnectedCallback() {
30
+ super.disconnectedCallback();
31
+ this.removeEventListener("focus", this.handleHostFocus);
32
+ this.removeEventListener("keydown", this.handleKeyDown);
33
+ }
34
+ handleKeyDown(event) {
35
+ if (this.href && event.key === "Enter") {
36
+ window.location.href = this.href;
37
+ }
38
+ }
39
+ handleHostFocus() {
40
+ if (this.shadowRoot?.activeElement === this.button) {
41
+ return;
42
+ }
43
+ this.focus();
26
44
  }
27
45
  focus() {
28
46
  this.button.focus();
@@ -37,7 +55,7 @@ let MinidMenuItem = class extends styled(LitElement) {
37
55
  "border-transparent": !this.active,
38
56
  "bg-accent-tinted": this.active,
39
57
  "border-accent-base": this.active
40
- })} block w-full rounded border-l-[5px] px-3 py-2 font-medium"
58
+ })} button block w-full rounded border-l-[5px] px-3 py-2 font-medium"
41
59
  href=${ifDefined(this.href)}
42
60
  >
43
61
  <div class="flex items-center gap-2">
@@ -47,7 +65,7 @@ let MinidMenuItem = class extends styled(LitElement) {
47
65
  }
48
66
  return html`
49
67
  <mid-button
50
- class="flex w-full [&::part(base)]:justify-start"
68
+ class="button flex w-full [&::part(base)]:justify-start"
51
69
  variant="tertiary"
52
70
  href=${ifDefined(this.href)}
53
71
  >
@@ -1 +1 @@
1
- {"version":3,"file":"menu-item.js","sources":["../../src/components/menu-item.component.ts"],"sourcesContent":["import { html, LitElement } from 'lit';\nimport { customElement, property, query } from 'lit/decorators.js';\nimport { styled } from '../mixins/tailwind.mixin.ts';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport './button.component';\nimport { MinidButton } from './button.component';\nimport { classMap } from 'lit/directives/class-map.js';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'mid-menu-item': MinidMenuItem;\n }\n}\n\n@customElement('mid-menu-item')\nexport class MinidMenuItem extends styled(LitElement) {\n @query('.button')\n button!: MinidButton;\n\n /**\n * If set, the interactive element will be an anchor element\n */\n @property()\n href: string | undefined;\n\n /**\n * The items value\n */\n @property()\n value?: string;\n\n /**\n * Controls which styling to use\n */\n @property()\n variant: 'combobox' | 'dropdown' = 'dropdown';\n\n /**\n * Used as a focus state. So the actual focus can be somewhere else\n */\n @property({ type: Boolean, reflect: true })\n active = false;\n\n connectedCallback(): void {\n super.connectedCallback();\n this.setAttribute('role', 'menuitem');\n }\n\n focus(): void {\n this.button.focus();\n }\n\n setActive(active: boolean) {\n this.active = active;\n }\n\n override render() {\n if (this.variant === 'combobox') {\n return html` <button\n class=\"${classMap({\n 'border-transparent': !this.active,\n 'bg-accent-tinted': this.active,\n 'border-accent-base': this.active,\n })} block w-full rounded border-l-[5px] px-3 py-2 font-medium\"\n href=${ifDefined(this.href)}\n >\n <div class=\"flex items-center gap-2\">\n <slot></slot>\n </div>\n </button>`;\n }\n\n return html`\n <mid-button\n class=\"flex w-full [&::part(base)]:justify-start\"\n variant=\"tertiary\"\n href=${ifDefined(this.href)}\n >\n <slot></slot>\n </mid-button>\n `;\n }\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAeO,IAAM,gBAAN,cAA4B,OAAO,UAAU,EAAE;AAAA,EAA/C,cAAA;AAAA,UAAA,GAAA,SAAA;AAoB8B,SAAA,UAAA;AAM1B,SAAA,SAAA;AAAA,EAAA;AAAA,EAET,oBAA0B;AACxB,UAAM,kBAAkB;AACnB,SAAA,aAAa,QAAQ,UAAU;AAAA,EAAA;AAAA,EAGtC,QAAc;AACZ,SAAK,OAAO,MAAM;AAAA,EAAA;AAAA,EAGpB,UAAU,QAAiB;AACzB,SAAK,SAAS;AAAA,EAAA;AAAA,EAGP,SAAS;AACZ,QAAA,KAAK,YAAY,YAAY;AACxB,aAAA;AAAA,iBACI,SAAS;AAAA,QAChB,sBAAsB,CAAC,KAAK;AAAA,QAC5B,oBAAoB,KAAK;AAAA,QACzB,sBAAsB,KAAK;AAAA,MAAA,CAC5B,CAAC;AAAA,eACK,UAAU,KAAK,IAAI,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAA;AAQxB,WAAA;AAAA;AAAA;AAAA;AAAA,eAII,UAAU,KAAK,IAAI,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,EAAA;AAMnC;AAjEE,gBAAA;AAAA,EADC,MAAM,SAAS;AAAA,GADL,cAEX,WAAA,UAAA,CAAA;AAMA,gBAAA;AAAA,EADC,SAAS;AAAA,GAPC,cAQX,WAAA,QAAA,CAAA;AAMA,gBAAA;AAAA,EADC,SAAS;AAAA,GAbC,cAcX,WAAA,SAAA,CAAA;AAMA,gBAAA;AAAA,EADC,SAAS;AAAA,GAnBC,cAoBX,WAAA,WAAA,CAAA;AAMA,gBAAA;AAAA,EADC,SAAS,EAAE,MAAM,SAAS,SAAS,KAAM,CAAA;AAAA,GAzB/B,cA0BX,WAAA,UAAA,CAAA;AA1BW,gBAAN,gBAAA;AAAA,EADN,cAAc,eAAe;AAAA,GACjB,aAAA;"}
1
+ {"version":3,"file":"menu-item.js","sources":["../../src/components/menu-item.component.ts"],"sourcesContent":["import { html, LitElement } from 'lit';\nimport { customElement, property, query } from 'lit/decorators.js';\nimport { styled } from '../mixins/tailwind.mixin.ts';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport './button.component';\nimport { MinidButton } from './button.component';\nimport { classMap } from 'lit/directives/class-map.js';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'mid-menu-item': MinidMenuItem;\n }\n}\n\n@customElement('mid-menu-item')\nexport class MinidMenuItem extends styled(LitElement) {\n @query('.button')\n button!: MinidButton;\n\n /**\n * If set, the interactive element will be an anchor element\n */\n @property()\n href: string | undefined;\n\n /**\n * The items value\n */\n @property()\n value?: string;\n\n /**\n * Controls which styling to use\n */\n @property()\n variant: 'combobox' | 'dropdown' = 'dropdown';\n\n /**\n * Used as a focus state. So the actual focus can be somewhere else\n */\n @property({ type: Boolean, reflect: true })\n active = false;\n\n connectedCallback(): void {\n super.connectedCallback();\n this.setAttribute('role', 'menuitem');\n this.addEventListener('focus', this.handleHostFocus);\n this.addEventListener('keydown', this.handleKeyDown);\n }\n\n disconnectedCallback(): void {\n super.disconnectedCallback();\n this.removeEventListener('focus', this.handleHostFocus);\n this.removeEventListener('keydown', this.handleKeyDown);\n }\n\n handleKeyDown(event: KeyboardEvent) {\n if (this.href && event.key === 'Enter') {\n window.location.href = this.href;\n }\n }\n\n handleHostFocus() {\n if (this.shadowRoot?.activeElement === this.button) {\n return;\n }\n\n this.focus();\n }\n\n focus(): void {\n this.button.focus();\n }\n\n setActive(active: boolean) {\n this.active = active;\n }\n\n override render() {\n if (this.variant === 'combobox') {\n return html` <button\n class=\"${classMap({\n 'border-transparent': !this.active,\n 'bg-accent-tinted': this.active,\n 'border-accent-base': this.active,\n })} button block w-full rounded border-l-[5px] px-3 py-2 font-medium\"\n href=${ifDefined(this.href)}\n >\n <div class=\"flex items-center gap-2\">\n <slot></slot>\n </div>\n </button>`;\n }\n\n return html`\n <mid-button\n class=\"button flex w-full [&::part(base)]:justify-start\"\n variant=\"tertiary\"\n href=${ifDefined(this.href)}\n >\n <slot></slot>\n </mid-button>\n `;\n }\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAeO,IAAM,gBAAN,cAA4B,OAAO,UAAU,EAAE;AAAA,EAA/C,cAAA;AAAA,UAAA,GAAA,SAAA;AAoB8B,SAAA,UAAA;AAM1B,SAAA,SAAA;AAAA,EAAA;AAAA,EAET,oBAA0B;AACxB,UAAM,kBAAkB;AACnB,SAAA,aAAa,QAAQ,UAAU;AAC/B,SAAA,iBAAiB,SAAS,KAAK,eAAe;AAC9C,SAAA,iBAAiB,WAAW,KAAK,aAAa;AAAA,EAAA;AAAA,EAGrD,uBAA6B;AAC3B,UAAM,qBAAqB;AACtB,SAAA,oBAAoB,SAAS,KAAK,eAAe;AACjD,SAAA,oBAAoB,WAAW,KAAK,aAAa;AAAA,EAAA;AAAA,EAGxD,cAAc,OAAsB;AAClC,QAAI,KAAK,QAAQ,MAAM,QAAQ,SAAS;AAC/B,aAAA,SAAS,OAAO,KAAK;AAAA,IAAA;AAAA,EAC9B;AAAA,EAGF,kBAAkB;AAChB,QAAI,KAAK,YAAY,kBAAkB,KAAK,QAAQ;AAClD;AAAA,IAAA;AAGF,SAAK,MAAM;AAAA,EAAA;AAAA,EAGb,QAAc;AACZ,SAAK,OAAO,MAAM;AAAA,EAAA;AAAA,EAGpB,UAAU,QAAiB;AACzB,SAAK,SAAS;AAAA,EAAA;AAAA,EAGP,SAAS;AACZ,QAAA,KAAK,YAAY,YAAY;AACxB,aAAA;AAAA,iBACI,SAAS;AAAA,QAChB,sBAAsB,CAAC,KAAK;AAAA,QAC5B,oBAAoB,KAAK;AAAA,QACzB,sBAAsB,KAAK;AAAA,MAAA,CAC5B,CAAC;AAAA,eACK,UAAU,KAAK,IAAI,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAA;AAQxB,WAAA;AAAA;AAAA;AAAA;AAAA,eAII,UAAU,KAAK,IAAI,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,EAAA;AAMnC;AAvFE,gBAAA;AAAA,EADC,MAAM,SAAS;AAAA,GADL,cAEX,WAAA,UAAA,CAAA;AAMA,gBAAA;AAAA,EADC,SAAS;AAAA,GAPC,cAQX,WAAA,QAAA,CAAA;AAMA,gBAAA;AAAA,EADC,SAAS;AAAA,GAbC,cAcX,WAAA,SAAA,CAAA;AAMA,gBAAA;AAAA,EADC,SAAS;AAAA,GAnBC,cAoBX,WAAA,WAAA,CAAA;AAMA,gBAAA;AAAA,EADC,SAAS,EAAE,MAAM,SAAS,SAAS,KAAM,CAAA;AAAA,GAzB/B,cA0BX,WAAA,UAAA,CAAA;AA1BW,gBAAN,gBAAA;AAAA,EADN,cAAc,eAAe;AAAA,GACjB,aAAA;"}
@@ -21,7 +21,7 @@ export declare class MinidMenu extends MinidMenu_base {
21
21
  * Wether the menu should be styled as a dropdown or a combobox
22
22
  */
23
23
  variant: 'combobox' | 'dropdown';
24
- emptyItemList: boolean;
24
+ isEmptyItemList: boolean;
25
25
  protected firstUpdated(): void;
26
26
  connectedCallback(): void;
27
27
  private handleClick;
@@ -1 +1 @@
1
- {"version":3,"file":"menu.component.d.ts","sourceRoot":"","sources":["../../src/components/menu.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,UAAU,EAAW,MAAM,KAAK,CAAC;AAGrD,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAGtD,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,UAAU,EAAE,SAAS,CAAC;KACvB;CACF;;AAWD;;GAEG;AACH,qBACa,SAAU,SAAQ,cAA0B;IAEvD,WAAW,EAAG,eAAe,CAAC;IAG9B,WAAW,EAAG,gBAAgB,CAAC;IAG/B,QAAQ,EAAG,gBAAgB,CAAC;IAE5B;;OAEG;IAEH,UAAU,UAAS;IAEnB;;OAEG;IAEH,OAAO,EAAE,UAAU,GAAG,UAAU,CAAc;IAG9C,aAAa,UAAS;IAEtB,SAAS,CAAC,YAAY,IAAI,IAAI;IAS9B,iBAAiB;IAKjB,OAAO,CAAC,WAAW;IAoCnB,OAAO,CAAC,iBAAiB;IAYzB,OAAO,CAAC,oBAAoB;IAI5B,OAAO,CAAC,aAAa;IAgDrB,OAAO,CAAC,eAAe;IAQvB,OAAO,CAAC,gBAAgB;IASxB,OAAO,CAAC,UAAU;IASlB;;;OAGG;IACH,MAAM,GAAI,UAAU,CAAC,IAAI,EAAE,aAAa,KAAK,OAAO,UAUlD;IAEF,WAAW;IAMX;;OAEG;IACH,qBAAqB;IAQrB,WAAW;IAQX;;;OAGG;IACH,cAAc;IAMd;;;OAGG;IACH,cAAc,CAAC,IAAI,EAAE,aAAa;IAUlC,gBAAgB;IAMP,MAAM;CAwChB"}
1
+ {"version":3,"file":"menu.component.d.ts","sourceRoot":"","sources":["../../src/components/menu.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,UAAU,EAAW,MAAM,KAAK,CAAC;AAGrD,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAGtD,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,UAAU,EAAE,SAAS,CAAC;KACvB;CACF;;AAWD;;GAEG;AACH,qBACa,SAAU,SAAQ,cAA0B;IAEvD,WAAW,EAAG,eAAe,CAAC;IAG9B,WAAW,EAAG,gBAAgB,CAAC;IAG/B,QAAQ,EAAG,gBAAgB,CAAC;IAE5B;;OAEG;IAEH,UAAU,UAAS;IAEnB;;OAEG;IAEH,OAAO,EAAE,UAAU,GAAG,UAAU,CAAc;IAG9C,eAAe,UAAS;IAExB,SAAS,CAAC,YAAY,IAAI,IAAI;IAS9B,iBAAiB;IAKjB,OAAO,CAAC,WAAW;IAoCnB,OAAO,CAAC,iBAAiB;IAYzB,OAAO,CAAC,oBAAoB;IAI5B,OAAO,CAAC,aAAa;IAgDrB,OAAO,CAAC,eAAe;IAQvB,OAAO,CAAC,gBAAgB;IASxB,OAAO,CAAC,UAAU;IASlB;;;OAGG;IACH,MAAM,GAAI,UAAU,CAAC,IAAI,EAAE,aAAa,KAAK,OAAO,UAUlD;IAEF,WAAW;IAMX;;OAEG;IACH,qBAAqB;IAQrB,WAAW;IAQX;;;OAGG;IACH,cAAc;IAMd;;;OAGG;IACH,cAAc,CAAC,IAAI,EAAE,aAAa;IAUlC,gBAAgB;IAMP,MAAM;CAwChB"}
@@ -25,7 +25,7 @@ let MinidMenu = class extends styled(LitElement, styles) {
25
25
  super(...arguments);
26
26
  this.searchable = false;
27
27
  this.variant = "dropdown";
28
- this.emptyItemList = false;
28
+ this.isEmptyItemList = false;
29
29
  this.filter = (filterFn) => {
30
30
  this.getAllItems().forEach((item) => {
31
31
  if (filterFn(item)) {
@@ -78,7 +78,7 @@ let MinidMenu = class extends styled(LitElement, styles) {
78
78
  (item) => item.innerText.toLowerCase().includes(this.filterInput.value.toLowerCase())
79
79
  );
80
80
  const items = this.getAllSelectableItems();
81
- this.emptyItemList = items.length === 0;
81
+ this.isEmptyItemList = items.length === 0;
82
82
  this.setCurrentItem(items[0]);
83
83
  }
84
84
  scrollOptionIntoView(item) {
@@ -215,7 +215,7 @@ let MinidMenu = class extends styled(LitElement, styles) {
215
215
  @keydown=${this.handleKeyDown}
216
216
  @mousedown=${this.handleMouseDown}
217
217
  ></slot>
218
- ${this.emptyItemList ? html`<div class="p-2">Fant ingen treff</div>` : nothing}
218
+ ${this.isEmptyItemList ? html`<div class="p-2">Fant ingen treff</div>` : nothing}
219
219
  </ul>
220
220
  </div>
221
221
  `;
@@ -238,7 +238,7 @@ __decorateClass([
238
238
  ], MinidMenu.prototype, "variant", 2);
239
239
  __decorateClass([
240
240
  state()
241
- ], MinidMenu.prototype, "emptyItemList", 2);
241
+ ], MinidMenu.prototype, "isEmptyItemList", 2);
242
242
  MinidMenu = __decorateClass([
243
243
  customElement("mid-menu")
244
244
  ], MinidMenu);
@@ -1 +1 @@
1
- {"version":3,"file":"menu.js","sources":["../../src/components/menu.component.ts"],"sourcesContent":["import { css, html, LitElement, nothing } from 'lit';\nimport { customElement, property, query, state } from 'lit/decorators.js';\nimport { styled } from '../mixins/tailwind.mixin.ts';\nimport { MinidMenuItem } from './menu-item.component';\nimport { scrollIntoView } from '../internal/scroll';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'mid-menu': MinidMenu;\n }\n}\n\nconst styles = [\n css`\n :host {\n --max-height: none;\n --max-width: none;\n }\n `,\n];\n\n/**\n * @event {{ detail: { item: MidMenuItem } }} mid-select - Emitted when a menu item is selected.\n */\n@customElement('mid-menu')\nexport class MinidMenu extends styled(LitElement, styles) {\n @query('slot')\n defaultSlot!: HTMLSlotElement;\n\n @query('.filter-input')\n filterInput!: HTMLInputElement;\n\n @query('.item-list')\n itemList!: HTMLUListElement;\n\n /**\n * Adds an input element that filters selectable menu items\n */\n @property({ type: Boolean })\n searchable = false;\n\n /**\n * Wether the menu should be styled as a dropdown or a combobox\n */\n @property()\n variant: 'combobox' | 'dropdown' = 'dropdown';\n\n @state()\n emptyItemList = false;\n\n protected firstUpdated(): void {\n this.getAllItems().forEach((item) => {\n item.variant = this.variant;\n item.addEventListener('mouseenter', () => {\n this.setCurrentItem(item);\n });\n });\n }\n\n connectedCallback() {\n super.connectedCallback();\n this.setAttribute('role', 'menu');\n }\n\n private handleClick(event: MouseEvent) {\n const menuItemTypes = ['menuitem', 'menuitemcheckbox'];\n\n const composedPath = event.composedPath();\n const target = composedPath.find((el) =>\n menuItemTypes.includes((el as HTMLElement)?.getAttribute?.('role') || '')\n );\n\n if (!target) return;\n\n const closestMenu = composedPath.find(\n (el) => (el as HTMLElement)?.getAttribute?.('role') === 'menu'\n );\n const clickHasSubmenu = closestMenu !== this;\n\n // Make sure we're the menu thats supposed to be handling the click event.\n if (clickHasSubmenu) {\n return;\n }\n\n // This isn't true. But we use it for TypeScript checks below.\n const item = target as MinidMenuItem;\n\n // if (item.type === 'checkbox') {\n // item.checked = !item.checked;\n // }\n\n this.dispatchEvent(\n new CustomEvent('mid-select', {\n bubbles: true,\n composed: true,\n detail: { item },\n })\n );\n }\n\n private handleFilterItems() {\n this.filter((item) =>\n item.innerText\n .toLowerCase()\n .includes(this.filterInput.value.toLowerCase())\n );\n\n const items = this.getAllSelectableItems();\n this.emptyItemList = items.length === 0;\n this.setCurrentItem(items[0]);\n }\n\n private scrollOptionIntoView(item: MinidMenuItem): void {\n scrollIntoView(item, this.itemList, 'vertical', 'auto');\n }\n\n private handleKeyDown(event: KeyboardEvent) {\n // Make a selection when pressing enter or space\n if (event.key === 'Enter' || event.key === ' ') {\n const item = this.getCurrentItem();\n event.preventDefault();\n event.stopPropagation();\n\n // Simulate a click to support @click handlers on menu items that also work with the keyboard\n item?.click();\n }\n\n // Move the selection when pressing down or up\n else if (['ArrowDown', 'ArrowUp', 'Home', 'End'].includes(event.key)) {\n const items = this.getAllSelectableItems();\n const activeItem = this.getCurrentItem();\n let index = activeItem ? items.indexOf(activeItem) : 0;\n\n if (items.length > 0) {\n event.preventDefault();\n event.stopPropagation();\n\n if (event.key === 'ArrowDown') {\n index++;\n } else if (event.key === 'ArrowUp') {\n index--;\n } else if (event.key === 'Home') {\n index = 0;\n } else if (event.key === 'End') {\n index = items.length - 1;\n }\n\n if (index < 0) {\n index = items.length - 1;\n }\n if (index > items.length - 1) {\n index = 0;\n }\n\n this.setCurrentItem(items[index]);\n this.scrollOptionIntoView(items[index]);\n\n if (!this.searchable) {\n items[index].focus();\n }\n }\n }\n }\n\n private handleMouseDown(event: MouseEvent) {\n const target = event.target as HTMLElement;\n\n if (this.isMenuItem(target)) {\n this.setCurrentItem(target as MinidMenuItem);\n }\n }\n\n private handleSlotChange() {\n const items = this.getAllSelectableItems();\n\n // Reset the roving tab index when the slotted items change\n if (items.length > 0) {\n this.setCurrentItem(items[0]);\n }\n }\n\n private isMenuItem(item: HTMLElement) {\n return (\n item.tagName.toLowerCase() === 'mid-menu-item' ||\n ['menuitem', 'menuitemcheckbox', 'menuitemradio'].includes(\n item.getAttribute('role') ?? ''\n )\n );\n }\n\n /**\n * Pass a filter function to enable/disable menu items in the menu\n * @type {(item: MinidMenuItem) => boolean}\n */\n filter = (filterFn: (item: MinidMenuItem) => boolean) => {\n this.getAllItems().forEach((item) => {\n if (filterFn(item)) {\n item.removeAttribute('hidden');\n item.removeAttribute('inert');\n } else {\n item.setAttribute('inert', 'true');\n item.setAttribute('hidden', 'true');\n }\n });\n };\n\n clearFilter() {\n this.filterInput.value = '';\n this.itemList.scrollTop = 0;\n this.filterInput.dispatchEvent(new Event('input'));\n }\n\n /**\n * @internal Gets all slotted menu items, ignoring dividers, headers, and other elements.\n */\n getAllSelectableItems() {\n return [\n ...(this.defaultSlot.assignedElements({\n flatten: true,\n }) as MinidMenuItem[]),\n ].filter((el) => !(el.inert || !this.isMenuItem(el)));\n }\n\n getAllItems() {\n return [\n ...(this.defaultSlot.assignedElements({\n flatten: true,\n }) as MinidMenuItem[]),\n ].filter((el) => this.isMenuItem(el));\n }\n\n /**\n * @internal Gets the current menu item, which is the menu item that has `tabindex=\"0\"` within the roving tab index.\n * The menu item may or may not have focus, but for keyboard interaction purposes it's considered the \"active\" item.\n */\n getCurrentItem() {\n return this.getAllSelectableItems().find(\n (i) => i.getAttribute('tabindex') === '0'\n );\n }\n\n /**\n * @internal Sets the current menu item to the specified element. This sets `tabindex=\"0\"` on the target element and\n * `tabindex=\"-1\"` to all other items. This method must be called prior to setting focus on a menu item.\n */\n setCurrentItem(item: MinidMenuItem) {\n const items = this.getAllSelectableItems();\n\n // Update tab indexes\n items.forEach((i) => {\n i.setActive(i === item);\n i.setAttribute('tabindex', i === item ? '0' : '-1');\n });\n }\n\n focusSearchField() {\n if (this.searchable) {\n this.filterInput.focus();\n }\n }\n\n override render() {\n return html`\n <div\n class=\"text-neutral border-neutral-subtle rounded-md border shadow-md\"\n >\n ${!this.searchable\n ? nothing\n : html`<div\n class=\"border-neutral-subtle flex items-center gap-2 border-b p-2\"\n >\n <mid-icon\n class=\"text-6\"\n slot=\"prefix\"\n library=\"system\"\n name=\"magnifying-glass\"\n >\n </mid-icon>\n <input\n @input=${this.handleFilterItems}\n @keydown=${this.handleKeyDown}\n class=\"filter-input border-neutral-subtle focus-visible:outline-focus-outer h-8 w-full rounded border px-2\"\n type=\"search\"\n />\n </div>`}\n <ul\n class=\"item-list max-h-(--max-height) max-w-(--max-width) overflow-y-auto px-2 py-3\"\n >\n <slot\n @slotchange=${this.handleSlotChange}\n @click=${this.handleClick}\n @keydown=${this.handleKeyDown}\n @mousedown=${this.handleMouseDown}\n ></slot>\n ${this.emptyItemList\n ? html`<div class=\"p-2\">Fant ingen treff</div>`\n : nothing}\n </ul>\n </div>\n `;\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"menu.js","sources":["../../src/components/menu.component.ts"],"sourcesContent":["import { css, html, LitElement, nothing } from 'lit';\nimport { customElement, property, query, state } from 'lit/decorators.js';\nimport { styled } from '../mixins/tailwind.mixin.ts';\nimport { MinidMenuItem } from './menu-item.component';\nimport { scrollIntoView } from '../internal/scroll';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'mid-menu': MinidMenu;\n }\n}\n\nconst styles = [\n css`\n :host {\n --max-height: none;\n --max-width: none;\n }\n `,\n];\n\n/**\n * @event {{ detail: { item: MidMenuItem } }} mid-select - Emitted when a menu item is selected.\n */\n@customElement('mid-menu')\nexport class MinidMenu extends styled(LitElement, styles) {\n @query('slot')\n defaultSlot!: HTMLSlotElement;\n\n @query('.filter-input')\n filterInput!: HTMLInputElement;\n\n @query('.item-list')\n itemList!: HTMLUListElement;\n\n /**\n * Adds an input element that filters selectable menu items\n */\n @property({ type: Boolean })\n searchable = false;\n\n /**\n * Wether the menu should be styled as a dropdown or a combobox\n */\n @property()\n variant: 'combobox' | 'dropdown' = 'dropdown';\n\n @state()\n isEmptyItemList = false;\n\n protected firstUpdated(): void {\n this.getAllItems().forEach((item) => {\n item.variant = this.variant;\n item.addEventListener('mouseenter', () => {\n this.setCurrentItem(item);\n });\n });\n }\n\n connectedCallback() {\n super.connectedCallback();\n this.setAttribute('role', 'menu');\n }\n\n private handleClick(event: MouseEvent) {\n const menuItemTypes = ['menuitem', 'menuitemcheckbox'];\n\n const composedPath = event.composedPath();\n const target = composedPath.find((el) =>\n menuItemTypes.includes((el as HTMLElement)?.getAttribute?.('role') || '')\n );\n\n if (!target) return;\n\n const closestMenu = composedPath.find(\n (el) => (el as HTMLElement)?.getAttribute?.('role') === 'menu'\n );\n const clickHasSubmenu = closestMenu !== this;\n\n // Make sure we're the menu thats supposed to be handling the click event.\n if (clickHasSubmenu) {\n return;\n }\n\n // This isn't true. But we use it for TypeScript checks below.\n const item = target as MinidMenuItem;\n\n // if (item.type === 'checkbox') {\n // item.checked = !item.checked;\n // }\n\n this.dispatchEvent(\n new CustomEvent('mid-select', {\n bubbles: true,\n composed: true,\n detail: { item },\n })\n );\n }\n\n private handleFilterItems() {\n this.filter((item) =>\n item.innerText\n .toLowerCase()\n .includes(this.filterInput.value.toLowerCase())\n );\n\n const items = this.getAllSelectableItems();\n this.isEmptyItemList = items.length === 0;\n this.setCurrentItem(items[0]);\n }\n\n private scrollOptionIntoView(item: MinidMenuItem): void {\n scrollIntoView(item, this.itemList, 'vertical', 'auto');\n }\n\n private handleKeyDown(event: KeyboardEvent) {\n // Make a selection when pressing enter or space\n if (event.key === 'Enter' || event.key === ' ') {\n const item = this.getCurrentItem();\n event.preventDefault();\n event.stopPropagation();\n\n // Simulate a click to support @click handlers on menu items that also work with the keyboard\n item?.click();\n }\n\n // Move the selection when pressing down or up\n else if (['ArrowDown', 'ArrowUp', 'Home', 'End'].includes(event.key)) {\n const items = this.getAllSelectableItems();\n const activeItem = this.getCurrentItem();\n let index = activeItem ? items.indexOf(activeItem) : 0;\n\n if (items.length > 0) {\n event.preventDefault();\n event.stopPropagation();\n\n if (event.key === 'ArrowDown') {\n index++;\n } else if (event.key === 'ArrowUp') {\n index--;\n } else if (event.key === 'Home') {\n index = 0;\n } else if (event.key === 'End') {\n index = items.length - 1;\n }\n\n if (index < 0) {\n index = items.length - 1;\n }\n if (index > items.length - 1) {\n index = 0;\n }\n\n this.setCurrentItem(items[index]);\n this.scrollOptionIntoView(items[index]);\n\n if (!this.searchable) {\n items[index].focus();\n }\n }\n }\n }\n\n private handleMouseDown(event: MouseEvent) {\n const target = event.target as HTMLElement;\n\n if (this.isMenuItem(target)) {\n this.setCurrentItem(target as MinidMenuItem);\n }\n }\n\n private handleSlotChange() {\n const items = this.getAllSelectableItems();\n\n // Reset the roving tab index when the slotted items change\n if (items.length > 0) {\n this.setCurrentItem(items[0]);\n }\n }\n\n private isMenuItem(item: HTMLElement) {\n return (\n item.tagName.toLowerCase() === 'mid-menu-item' ||\n ['menuitem', 'menuitemcheckbox', 'menuitemradio'].includes(\n item.getAttribute('role') ?? ''\n )\n );\n }\n\n /**\n * Pass a filter function to enable/disable menu items in the menu\n * @type {(item: MinidMenuItem) => boolean}\n */\n filter = (filterFn: (item: MinidMenuItem) => boolean) => {\n this.getAllItems().forEach((item) => {\n if (filterFn(item)) {\n item.removeAttribute('hidden');\n item.removeAttribute('inert');\n } else {\n item.setAttribute('inert', 'true');\n item.setAttribute('hidden', 'true');\n }\n });\n };\n\n clearFilter() {\n this.filterInput.value = '';\n this.itemList.scrollTop = 0;\n this.filterInput.dispatchEvent(new Event('input'));\n }\n\n /**\n * @internal Gets all slotted menu items, ignoring dividers, headers, and other elements.\n */\n getAllSelectableItems() {\n return [\n ...(this.defaultSlot.assignedElements({\n flatten: true,\n }) as MinidMenuItem[]),\n ].filter((el) => !(el.inert || !this.isMenuItem(el)));\n }\n\n getAllItems() {\n return [\n ...(this.defaultSlot.assignedElements({\n flatten: true,\n }) as MinidMenuItem[]),\n ].filter((el) => this.isMenuItem(el));\n }\n\n /**\n * @internal Gets the current menu item, which is the menu item that has `tabindex=\"0\"` within the roving tab index.\n * The menu item may or may not have focus, but for keyboard interaction purposes it's considered the \"active\" item.\n */\n getCurrentItem() {\n return this.getAllSelectableItems().find(\n (i) => i.getAttribute('tabindex') === '0'\n );\n }\n\n /**\n * @internal Sets the current menu item to the specified element. This sets `tabindex=\"0\"` on the target element and\n * `tabindex=\"-1\"` to all other items. This method must be called prior to setting focus on a menu item.\n */\n setCurrentItem(item: MinidMenuItem) {\n const items = this.getAllSelectableItems();\n\n // Update tab indexes\n items.forEach((i) => {\n i.setActive(i === item);\n i.setAttribute('tabindex', i === item ? '0' : '-1');\n });\n }\n\n focusSearchField() {\n if (this.searchable) {\n this.filterInput.focus();\n }\n }\n\n override render() {\n return html`\n <div\n class=\"text-neutral border-neutral-subtle rounded-md border shadow-md\"\n >\n ${!this.searchable\n ? nothing\n : html`<div\n class=\"border-neutral-subtle flex items-center gap-2 border-b p-2\"\n >\n <mid-icon\n class=\"text-6\"\n slot=\"prefix\"\n library=\"system\"\n name=\"magnifying-glass\"\n >\n </mid-icon>\n <input\n @input=${this.handleFilterItems}\n @keydown=${this.handleKeyDown}\n class=\"filter-input border-neutral-subtle focus-visible:outline-focus-outer h-8 w-full rounded border px-2\"\n type=\"search\"\n />\n </div>`}\n <ul\n class=\"item-list max-h-(--max-height) max-w-(--max-width) overflow-y-auto px-2 py-3\"\n >\n <slot\n @slotchange=${this.handleSlotChange}\n @click=${this.handleClick}\n @keydown=${this.handleKeyDown}\n @mousedown=${this.handleMouseDown}\n ></slot>\n ${this.isEmptyItemList\n ? html`<div class=\"p-2\">Fant ingen treff</div>`\n : nothing}\n </ul>\n </div>\n `;\n }\n}\n"],"names":[],"mappings":"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"}