@solid-design-system/components 1.7.0 → 1.8.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 (76) hide show
  1. package/dist/components/es/accordion-group.js +1 -1
  2. package/dist/components/es/accordion.js +1 -1
  3. package/dist/components/es/dropdown.js +1 -0
  4. package/dist/components/es/event.js +1 -0
  5. package/dist/components/es/popup.js +1 -0
  6. package/dist/components/es/solid-components2.js +1 -1
  7. package/dist/components/es/solid-element.js +1 -1
  8. package/dist/components/umd/solid-components.js +15 -15
  9. package/dist/custom-elements.json +1 -1
  10. package/dist/package/components/dropdown/dropdown.d.ts +49 -0
  11. package/dist/package/components/dropdown/dropdown.js +335 -0
  12. package/dist/package/components/popup/popup.d.ts +42 -0
  13. package/dist/package/components/popup/popup.js +318 -0
  14. package/dist/package/internal/offset.d.ts +4 -0
  15. package/dist/package/internal/offset.js +9 -0
  16. package/dist/package/internal/scroll.d.ts +3 -0
  17. package/dist/package/internal/scroll.js +27 -0
  18. package/dist/package/internal/tabbable.d.ts +4 -0
  19. package/dist/package/internal/tabbable.js +50 -0
  20. package/dist/package/solid-components.d.ts +2 -0
  21. package/dist/package/solid-components.js +14 -10
  22. package/dist/package/styles/tailwind.css.js +1 -1
  23. package/dist/versioned-components/es/accordion-group.js +1 -1
  24. package/dist/versioned-components/es/accordion.js +1 -1
  25. package/dist/versioned-components/es/badge.js +1 -1
  26. package/dist/versioned-components/es/brandshape.js +1 -1
  27. package/dist/versioned-components/es/button.js +2 -2
  28. package/dist/versioned-components/es/divider.js +1 -1
  29. package/dist/versioned-components/es/dropdown.js +1 -0
  30. package/dist/versioned-components/es/event.js +1 -0
  31. package/dist/versioned-components/es/icon.js +1 -1
  32. package/dist/versioned-components/es/include.js +1 -1
  33. package/dist/versioned-components/es/link.js +1 -1
  34. package/dist/versioned-components/es/popup.js +1 -0
  35. package/dist/versioned-components/es/solid-components2.js +1 -1
  36. package/dist/versioned-components/es/solid-element.js +1 -1
  37. package/dist/versioned-components/es/spinner.js +1 -1
  38. package/dist/versioned-components/es/teaser.js +1 -1
  39. package/dist/versioned-package/components/accordion/accordion.d.ts +1 -1
  40. package/dist/versioned-package/components/accordion/accordion.js +2 -2
  41. package/dist/versioned-package/components/accordion-group/accordion-group.d.ts +1 -1
  42. package/dist/versioned-package/components/accordion-group/accordion-group.js +3 -3
  43. package/dist/versioned-package/components/badge/badge.d.ts +1 -1
  44. package/dist/versioned-package/components/badge/badge.js +1 -1
  45. package/dist/versioned-package/components/brandshape/brandshape.d.ts +1 -1
  46. package/dist/versioned-package/components/brandshape/brandshape.js +1 -1
  47. package/dist/versioned-package/components/button/button.d.ts +1 -1
  48. package/dist/versioned-package/components/button/button.js +4 -4
  49. package/dist/versioned-package/components/divider/divider.d.ts +1 -1
  50. package/dist/versioned-package/components/divider/divider.js +2 -2
  51. package/dist/versioned-package/components/dropdown/dropdown.d.ts +49 -0
  52. package/dist/versioned-package/components/dropdown/dropdown.js +335 -0
  53. package/dist/versioned-package/components/icon/icon.d.ts +1 -1
  54. package/dist/versioned-package/components/icon/icon.js +1 -1
  55. package/dist/versioned-package/components/include/include.d.ts +1 -1
  56. package/dist/versioned-package/components/include/include.js +1 -1
  57. package/dist/versioned-package/components/link/link.d.ts +1 -1
  58. package/dist/versioned-package/components/link/link.js +2 -2
  59. package/dist/versioned-package/components/popup/popup.d.ts +42 -0
  60. package/dist/versioned-package/components/popup/popup.js +318 -0
  61. package/dist/versioned-package/components/spinner/spinner.d.ts +1 -1
  62. package/dist/versioned-package/components/spinner/spinner.js +1 -1
  63. package/dist/versioned-package/components/teaser/teaser.js +1 -1
  64. package/dist/versioned-package/internal/form.js +1 -1
  65. package/dist/versioned-package/internal/offset.d.ts +4 -0
  66. package/dist/versioned-package/internal/offset.js +9 -0
  67. package/dist/versioned-package/internal/scroll.d.ts +3 -0
  68. package/dist/versioned-package/internal/scroll.js +27 -0
  69. package/dist/versioned-package/internal/tabbable.d.ts +4 -0
  70. package/dist/versioned-package/internal/tabbable.js +50 -0
  71. package/dist/versioned-package/solid-components.d.ts +2 -0
  72. package/dist/versioned-package/solid-components.js +14 -10
  73. package/dist/versioned-package/styles/tailwind.css.js +1 -1
  74. package/dist/vscode.html-custom-data.json +653 -11
  75. package/dist/web-types.json +1240 -64
  76. package/package.json +4 -3
@@ -0,0 +1,335 @@
1
+ import "../popup/popup.js";
2
+ import { stopAnimations, animateTo } from "../../internal/animate.js";
3
+ import { css, html } from "lit";
4
+ import { query, property, customElement } from "lit/decorators.js";
5
+ import { setDefaultAnimation, getAnimation } from "../../utilities/animation-registry.js";
6
+ import { getTabbableBoundary } from "../../internal/tabbable.js";
7
+ import { LocalizeController } from "../../utilities/localize.js";
8
+ import { scrollIntoView } from "../../internal/scroll.js";
9
+ import { waitForEvent } from "../../internal/event.js";
10
+ import { watch } from "../../internal/watch.js";
11
+ import componentStyles from "../../styles/component.styles.js";
12
+ import cx from "classix";
13
+ import SolidElement from "../../internal/solid-element.js";
14
+ var __defProp = Object.defineProperty;
15
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
16
+ var __decorateClass = (decorators, target, key, kind) => {
17
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
18
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
19
+ if (decorator = decorators[i])
20
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
21
+ if (kind && result)
22
+ __defProp(target, key, result);
23
+ return result;
24
+ };
25
+ let SdDropdown = class extends SolidElement {
26
+ constructor() {
27
+ super(...arguments);
28
+ this.localize = new LocalizeController(this);
29
+ this.open = false;
30
+ this.rounded = false;
31
+ this.placement = "bottom-start";
32
+ this.disabled = false;
33
+ this.stayOpenOnSelect = false;
34
+ this.distance = 0;
35
+ this.skidding = 0;
36
+ this.noAutoSize = false;
37
+ this.noFlip = false;
38
+ this.hoist = false;
39
+ }
40
+ connectedCallback() {
41
+ super.connectedCallback();
42
+ this.handleMenuItemActivate = this.handleMenuItemActivate.bind(this);
43
+ this.handlePanelSelect = this.handlePanelSelect.bind(this);
44
+ this.handleKeyDown = this.handleKeyDown.bind(this);
45
+ this.handleDocumentKeyDown = this.handleDocumentKeyDown.bind(this);
46
+ this.handleDocumentMouseDown = this.handleDocumentMouseDown.bind(this);
47
+ if (!this.containingElement) {
48
+ this.containingElement = this;
49
+ }
50
+ }
51
+ firstUpdated() {
52
+ this.panel.hidden = !this.open;
53
+ if (this.open) {
54
+ this.addOpenListeners();
55
+ this.popup.active = true;
56
+ }
57
+ }
58
+ disconnectedCallback() {
59
+ super.disconnectedCallback();
60
+ this.removeOpenListeners();
61
+ this.hide();
62
+ }
63
+ focusOnTrigger() {
64
+ const trigger = this.trigger.assignedElements({ flatten: true })[0];
65
+ if (typeof (trigger == null ? void 0 : trigger.focus) === "function") {
66
+ trigger.focus();
67
+ }
68
+ }
69
+ getMenu() {
70
+ return this.panel.assignedElements({ flatten: true }).find((el) => el.tagName.toLowerCase() === "sd-menu");
71
+ }
72
+ handleKeyDown(event) {
73
+ if (this.open && event.key === "Escape") {
74
+ event.stopPropagation();
75
+ this.hide();
76
+ this.focusOnTrigger();
77
+ }
78
+ }
79
+ handleDocumentKeyDown(event) {
80
+ var _a;
81
+ if (event.key === "Tab") {
82
+ if (this.open && ((_a = document.activeElement) == null ? void 0 : _a.tagName.toLowerCase()) === "sd-menu-item") {
83
+ event.preventDefault();
84
+ this.hide();
85
+ this.focusOnTrigger();
86
+ return;
87
+ }
88
+ setTimeout(() => {
89
+ var _a2, _b, _c;
90
+ const activeElement = ((_a2 = this.containingElement) == null ? void 0 : _a2.getRootNode()) instanceof ShadowRoot ? (_c = (_b = document.activeElement) == null ? void 0 : _b.shadowRoot) == null ? void 0 : _c.activeElement : document.activeElement;
91
+ if (!this.containingElement || (activeElement == null ? void 0 : activeElement.closest(this.containingElement.tagName.toLowerCase())) !== this.containingElement) {
92
+ this.hide();
93
+ }
94
+ });
95
+ }
96
+ }
97
+ handleDocumentMouseDown(event) {
98
+ const path = event.composedPath();
99
+ if (this.containingElement && !path.includes(this.containingElement)) {
100
+ this.hide();
101
+ }
102
+ }
103
+ handleMenuItemActivate(event) {
104
+ const item = event.target;
105
+ scrollIntoView(item, this.panel);
106
+ }
107
+ handlePanelSelect(event) {
108
+ const target = event.target;
109
+ if (!this.stayOpenOnSelect && target.tagName.toLowerCase() === "sd-menu") {
110
+ this.hide();
111
+ this.focusOnTrigger();
112
+ }
113
+ }
114
+ handleTriggerClick() {
115
+ if (this.open) {
116
+ this.hide();
117
+ } else {
118
+ this.show();
119
+ }
120
+ }
121
+ handleTriggerKeyDown(event) {
122
+ if (event.key === "Escape" && this.open) {
123
+ event.stopPropagation();
124
+ this.focusOnTrigger();
125
+ this.hide();
126
+ return;
127
+ }
128
+ if ([" ", "Enter"].includes(event.key)) {
129
+ event.preventDefault();
130
+ this.handleTriggerClick();
131
+ return;
132
+ }
133
+ const menu = this.getMenu();
134
+ if (menu) {
135
+ const menuItems = menu.defaultSlot.assignedElements({ flatten: true });
136
+ const firstMenuItem = menuItems[0];
137
+ const lastMenuItem = menuItems[menuItems.length - 1];
138
+ if (["ArrowDown", "ArrowUp", "Home", "End"].includes(event.key)) {
139
+ event.preventDefault();
140
+ if (!this.open) {
141
+ this.show();
142
+ }
143
+ if (menuItems.length > 0) {
144
+ requestAnimationFrame(() => {
145
+ if (event.key === "ArrowDown" || event.key === "Home") {
146
+ menu.setCurrentItem(firstMenuItem);
147
+ firstMenuItem.focus();
148
+ }
149
+ if (event.key === "ArrowUp" || event.key === "End") {
150
+ menu.setCurrentItem(lastMenuItem);
151
+ lastMenuItem.focus();
152
+ }
153
+ });
154
+ }
155
+ }
156
+ }
157
+ }
158
+ handleTriggerKeyUp(event) {
159
+ if (event.key === " ") {
160
+ event.preventDefault();
161
+ }
162
+ }
163
+ handleTriggerSlotChange() {
164
+ this.updateAccessibleTrigger();
165
+ }
166
+ //
167
+ // Slotted triggers can be arbitrary content, but we need to link them to the dropdown panel with `aria-haspopup` and
168
+ // `aria-expanded`. These must be applied to the "accessible trigger" (the tabbable portion of the trigger element
169
+ // that gets slotted in) so screen readers will understand them. The accessible trigger could be the slotted element,
170
+ // a child of the slotted element, or an element in the slotted element's shadow root.
171
+ //
172
+ // For example, the accessible trigger of an <sd-button> is a <button> located inside its shadow root.
173
+ //
174
+ // To determine this, we assume the first tabbable element in the trigger slot is the "accessible trigger."
175
+ //
176
+ updateAccessibleTrigger() {
177
+ const assignedElements = this.trigger.assignedElements({ flatten: true });
178
+ const accessibleTrigger = assignedElements.find((el) => getTabbableBoundary(el).start);
179
+ let target;
180
+ if (accessibleTrigger) {
181
+ switch (accessibleTrigger.tagName.toLowerCase()) {
182
+ case "sd-button":
183
+ case "sd-icon-button":
184
+ target = accessibleTrigger.button;
185
+ break;
186
+ default:
187
+ target = accessibleTrigger;
188
+ }
189
+ target.setAttribute("aria-haspopup", "true");
190
+ target.setAttribute("aria-expanded", this.open ? "true" : "false");
191
+ }
192
+ }
193
+ /** Shows the dropdown panel. */
194
+ async show() {
195
+ if (this.open) {
196
+ return void 0;
197
+ }
198
+ this.open = true;
199
+ return waitForEvent(this, "sd-after-show");
200
+ }
201
+ /** Hides the dropdown panel */
202
+ async hide() {
203
+ if (!this.open) {
204
+ return void 0;
205
+ }
206
+ this.open = false;
207
+ return waitForEvent(this, "sd-after-hide");
208
+ }
209
+ /**
210
+ * Instructs the dropdown menu to reposition. Useful when the position or size of the trigger changes when the menu
211
+ * is activated.
212
+ */
213
+ reposition() {
214
+ this.popup.reposition();
215
+ }
216
+ addOpenListeners() {
217
+ this.panel.addEventListener("sd-activate", this.handleMenuItemActivate);
218
+ this.panel.addEventListener("sd-select", this.handlePanelSelect);
219
+ this.panel.addEventListener("keydown", this.handleKeyDown);
220
+ document.addEventListener("keydown", this.handleDocumentKeyDown);
221
+ document.addEventListener("mousedown", this.handleDocumentMouseDown);
222
+ }
223
+ removeOpenListeners() {
224
+ if (this.panel) {
225
+ this.panel.removeEventListener("sd-activate", this.handleMenuItemActivate);
226
+ this.panel.removeEventListener("sd-select", this.handlePanelSelect);
227
+ this.panel.removeEventListener("keydown", this.handleKeyDown);
228
+ }
229
+ document.removeEventListener("keydown", this.handleDocumentKeyDown);
230
+ document.removeEventListener("mousedown", this.handleDocumentMouseDown);
231
+ }
232
+ async handleOpenChange() {
233
+ if (this.disabled) {
234
+ this.open = false;
235
+ return;
236
+ }
237
+ this.updateAccessibleTrigger();
238
+ if (this.open) {
239
+ this.emit("sd-show");
240
+ this.addOpenListeners();
241
+ await stopAnimations(this);
242
+ this.panel.hidden = false;
243
+ this.popup.active = true;
244
+ const { keyframes, options } = getAnimation(this, "dropdown.show", { dir: this.localize.dir() });
245
+ await animateTo(this.popup.popup, keyframes, options);
246
+ this.emit("sd-after-show");
247
+ } else {
248
+ this.emit("sd-hide");
249
+ this.removeOpenListeners();
250
+ await stopAnimations(this);
251
+ const { keyframes, options } = getAnimation(this, "dropdown.hide", { dir: this.localize.dir() });
252
+ await animateTo(this.popup.popup, keyframes, options);
253
+ this.panel.hidden = true;
254
+ this.popup.active = false;
255
+ this.emit("sd-after-hide");
256
+ }
257
+ }
258
+ render() {
259
+ return html`<sd-popup part="base" id="dropdown" placement="${this.placement}" distance="${this.rounded && this.distance < 1 ? 1 : this.distance}" skidding="${this.skidding}" strategy="${this.hoist ? "fixed" : "absolute"}" ?flip="${!this.noFlip}" shift auto-size="vertical" auto-size-padding="10" ?active="${this.open}"><slot name="trigger" slot="anchor" part="trigger" class="block" @click="${this.handleTriggerClick}" @keydown="${this.handleTriggerKeyDown}" @keyup="${this.handleTriggerKeyUp}" @slotchange="${this.handleTriggerSlotChange}"></slot><slot part="panel" class="${cx(
260
+ "shadow bg-white",
261
+ this.open ? "block pointer-events-auto" : "pointer-events-none",
262
+ this.rounded && "rounded-md"
263
+ )}" aria-hidden="${this.open ? "false" : "true"}" aria-labelledby="dropdown"></slot></sd-popup>`;
264
+ }
265
+ };
266
+ SdDropdown.styles = [
267
+ SolidElement.styles,
268
+ componentStyles,
269
+ css`:host{display:inline-block}#dropdown::part(popup){z-index:var(--sd-z-index-dropdown)}#dropdown[data-current-placement^=top]::part(popup){transform-origin:bottom}#dropdown[data-current-placement^=bottom]::part(popup){transform-origin:top}#dropdown[data-current-placement^=left]::part(popup){transform-origin:right}#dropdown[data-current-placement^=right]::part(popup){transform-origin:left}:host(:not([no-auto-size])) ::slotted(:not([slot=trigger])){overflow:auto;max-width:var(--auto-size-available-width)!important;max-height:var(--auto-size-available-height)!important}`
270
+ ];
271
+ __decorateClass([
272
+ query("#dropdown")
273
+ ], SdDropdown.prototype, "popup", 2);
274
+ __decorateClass([
275
+ query("[part=trigger]")
276
+ ], SdDropdown.prototype, "trigger", 2);
277
+ __decorateClass([
278
+ query("[part=panel]")
279
+ ], SdDropdown.prototype, "panel", 2);
280
+ __decorateClass([
281
+ property({ type: Boolean, reflect: true })
282
+ ], SdDropdown.prototype, "open", 2);
283
+ __decorateClass([
284
+ property({ type: Boolean, reflect: true })
285
+ ], SdDropdown.prototype, "rounded", 2);
286
+ __decorateClass([
287
+ property({ reflect: true })
288
+ ], SdDropdown.prototype, "placement", 2);
289
+ __decorateClass([
290
+ property({ type: Boolean, reflect: true })
291
+ ], SdDropdown.prototype, "disabled", 2);
292
+ __decorateClass([
293
+ property({ attribute: "stay-open-on-select", type: Boolean, reflect: true })
294
+ ], SdDropdown.prototype, "stayOpenOnSelect", 2);
295
+ __decorateClass([
296
+ property({ attribute: false })
297
+ ], SdDropdown.prototype, "containingElement", 2);
298
+ __decorateClass([
299
+ property({ type: Number })
300
+ ], SdDropdown.prototype, "distance", 2);
301
+ __decorateClass([
302
+ property({ type: Number })
303
+ ], SdDropdown.prototype, "skidding", 2);
304
+ __decorateClass([
305
+ property({ type: Boolean, reflect: true, attribute: "no-auto-size" })
306
+ ], SdDropdown.prototype, "noAutoSize", 2);
307
+ __decorateClass([
308
+ property({ type: Boolean, reflect: true, attribute: "no-flip" })
309
+ ], SdDropdown.prototype, "noFlip", 2);
310
+ __decorateClass([
311
+ property({ type: Boolean })
312
+ ], SdDropdown.prototype, "hoist", 2);
313
+ __decorateClass([
314
+ watch("open", { waitUntilFirstUpdate: true })
315
+ ], SdDropdown.prototype, "handleOpenChange", 1);
316
+ SdDropdown = __decorateClass([
317
+ customElement("sd-dropdown")
318
+ ], SdDropdown);
319
+ setDefaultAnimation("dropdown.show", {
320
+ keyframes: [
321
+ { opacity: 0, scale: 0.9 },
322
+ { opacity: 1, scale: 1 }
323
+ ],
324
+ options: { duration: 100, easing: "ease" }
325
+ });
326
+ setDefaultAnimation("dropdown.hide", {
327
+ keyframes: [
328
+ { opacity: 1, scale: 1 },
329
+ { opacity: 0, scale: 0.9 }
330
+ ],
331
+ options: { duration: 100, easing: "ease" }
332
+ });
333
+ export {
334
+ SdDropdown as default
335
+ };
@@ -0,0 +1,42 @@
1
+ import SolidElement from '../../internal/solid-element';
2
+ export default class SdPopup extends SolidElement {
3
+ private anchorEl;
4
+ private cleanup;
5
+ popup: HTMLElement;
6
+ private arrowEl;
7
+ anchor: Element | string;
8
+ active: boolean;
9
+ placement: 'top' | 'top-start' | 'top-end' | 'bottom' | 'bottom-start' | 'bottom-end' | 'right' | 'right-start' | 'right-end' | 'left' | 'left-start' | 'left-end';
10
+ strategy: 'absolute' | 'fixed';
11
+ distance: number;
12
+ skidding: number;
13
+ arrow: boolean;
14
+ arrowPlacement: 'start' | 'end' | 'center' | 'anchor';
15
+ arrowPadding: number;
16
+ flip: boolean;
17
+ flipFallbackPlacements: string;
18
+ flipFallbackStrategy: 'best-fit' | 'initial';
19
+ flipBoundary: Element | Element[];
20
+ flipPadding: number;
21
+ shift: boolean;
22
+ shiftBoundary: Element | Element[];
23
+ shiftPadding: number;
24
+ autoSize: 'horizontal' | 'vertical' | 'both';
25
+ sync: 'width' | 'height' | 'both';
26
+ autoSizeBoundary: Element | Element[];
27
+ autoSizePadding: number;
28
+ connectedCallback(): Promise<void>;
29
+ disconnectedCallback(): void;
30
+ updated(changedProps: Map<string, unknown>): Promise<void>;
31
+ private handleAnchorChange;
32
+ private start;
33
+ private stop;
34
+ reposition(): void;
35
+ render(): import("lit-html").TemplateResult<1>;
36
+ static styles: import("lit").CSSResultGroup[];
37
+ }
38
+ declare global {
39
+ interface HTMLElementTagNameMap {
40
+ 'sd-popup': SdPopup;
41
+ }
42
+ }
@@ -0,0 +1,318 @@
1
+ import { autoUpdate, offset, size, flip, shift, arrow, computePosition } from "@floating-ui/dom";
2
+ import { css, html } from "lit";
3
+ import { query, property, customElement } from "lit/decorators.js";
4
+ import componentStyles from "../../styles/component.styles.js";
5
+ import cx from "classix";
6
+ import SolidElement from "../../internal/solid-element.js";
7
+ var __defProp = Object.defineProperty;
8
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
9
+ var __decorateClass = (decorators, target, key, kind) => {
10
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
11
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
12
+ if (decorator = decorators[i])
13
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
14
+ if (kind && result)
15
+ __defProp(target, key, result);
16
+ return result;
17
+ };
18
+ let SdPopup = class extends SolidElement {
19
+ constructor() {
20
+ super(...arguments);
21
+ this.active = false;
22
+ this.placement = "top";
23
+ this.strategy = "absolute";
24
+ this.distance = 0;
25
+ this.skidding = 0;
26
+ this.arrow = false;
27
+ this.arrowPlacement = "anchor";
28
+ this.arrowPadding = 10;
29
+ this.flip = false;
30
+ this.flipFallbackPlacements = "";
31
+ this.flipFallbackStrategy = "best-fit";
32
+ this.flipPadding = 0;
33
+ this.shift = false;
34
+ this.shiftPadding = 0;
35
+ this.autoSizePadding = 0;
36
+ }
37
+ async connectedCallback() {
38
+ super.connectedCallback();
39
+ await this.updateComplete;
40
+ this.start();
41
+ }
42
+ disconnectedCallback() {
43
+ this.stop();
44
+ }
45
+ async updated(changedProps) {
46
+ super.updated(changedProps);
47
+ if (changedProps.has("active")) {
48
+ if (this.active) {
49
+ this.start();
50
+ } else {
51
+ this.stop();
52
+ }
53
+ }
54
+ if (changedProps.has("anchor")) {
55
+ this.handleAnchorChange();
56
+ }
57
+ if (this.active) {
58
+ await this.updateComplete;
59
+ this.reposition();
60
+ }
61
+ }
62
+ async handleAnchorChange() {
63
+ await this.stop();
64
+ if (this.anchor && typeof this.anchor === "string") {
65
+ const root = this.getRootNode();
66
+ this.anchorEl = root.getElementById(this.anchor);
67
+ } else if (this.anchor instanceof HTMLElement) {
68
+ this.anchorEl = this.anchor;
69
+ } else {
70
+ this.anchorEl = this.querySelector('[slot="anchor"]');
71
+ }
72
+ if (this.anchorEl instanceof HTMLSlotElement) {
73
+ this.anchorEl = this.anchorEl.assignedElements({ flatten: true })[0];
74
+ }
75
+ if (!this.anchorEl) {
76
+ throw new Error(
77
+ "Invalid anchor element: no anchor could be found using the anchor slot or the anchor attribute."
78
+ );
79
+ }
80
+ this.start();
81
+ }
82
+ start() {
83
+ if (!this.anchorEl) {
84
+ return;
85
+ }
86
+ this.cleanup = autoUpdate(this.anchorEl, this.popup, () => {
87
+ this.reposition();
88
+ });
89
+ }
90
+ async stop() {
91
+ return new Promise((resolve) => {
92
+ if (this.cleanup) {
93
+ this.cleanup();
94
+ this.cleanup = void 0;
95
+ this.removeAttribute("data-current-placement");
96
+ this.style.removeProperty("--auto-size-available-width");
97
+ this.style.removeProperty("--auto-size-available-height");
98
+ requestAnimationFrame(() => resolve());
99
+ } else {
100
+ resolve();
101
+ }
102
+ });
103
+ }
104
+ /** Forces the popup to recalculate and reposition itself. */
105
+ reposition() {
106
+ if (!this.active || !this.anchorEl) {
107
+ return;
108
+ }
109
+ const middleware = [
110
+ // The offset middleware goes first
111
+ offset({ mainAxis: this.distance, crossAxis: this.skidding })
112
+ ];
113
+ if (this.sync) {
114
+ middleware.push(
115
+ size({
116
+ apply: ({ rects }) => {
117
+ const syncWidth = this.sync === "width" || this.sync === "both";
118
+ const syncHeight = this.sync === "height" || this.sync === "both";
119
+ this.popup.style.width = syncWidth ? `${rects.reference.width}px` : "";
120
+ this.popup.style.height = syncHeight ? `${rects.reference.height}px` : "";
121
+ }
122
+ })
123
+ );
124
+ } else {
125
+ this.popup.style.width = "";
126
+ this.popup.style.height = "";
127
+ }
128
+ if (this.flip) {
129
+ middleware.push(
130
+ flip({
131
+ boundary: this.flipBoundary,
132
+ // @ts-expect-error - We're converting a string attribute to an array here
133
+ fallbackPlacements: this.flipFallbackPlacements,
134
+ fallbackStrategy: this.flipFallbackStrategy === "best-fit" ? "bestFit" : "initialPlacement",
135
+ padding: this.flipPadding
136
+ })
137
+ );
138
+ }
139
+ if (this.shift) {
140
+ middleware.push(
141
+ shift({
142
+ boundary: this.shiftBoundary,
143
+ padding: this.shiftPadding
144
+ })
145
+ );
146
+ }
147
+ if (this.autoSize) {
148
+ middleware.push(
149
+ size({
150
+ boundary: this.autoSizeBoundary,
151
+ padding: this.autoSizePadding,
152
+ apply: ({ availableWidth, availableHeight }) => {
153
+ if (this.autoSize === "vertical" || this.autoSize === "both") {
154
+ this.style.setProperty("--auto-size-available-height", `${availableHeight}px`);
155
+ } else {
156
+ this.style.removeProperty("--auto-size-available-height");
157
+ }
158
+ if (this.autoSize === "horizontal" || this.autoSize === "both") {
159
+ this.style.setProperty("--auto-size-available-width", `${availableWidth}px`);
160
+ } else {
161
+ this.style.removeProperty("--auto-size-available-width");
162
+ }
163
+ }
164
+ })
165
+ );
166
+ } else {
167
+ this.style.removeProperty("--auto-size-available-width");
168
+ this.style.removeProperty("--auto-size-available-height");
169
+ }
170
+ if (this.arrow) {
171
+ middleware.push(
172
+ arrow({
173
+ element: this.arrowEl,
174
+ padding: this.arrowPadding
175
+ })
176
+ );
177
+ }
178
+ computePosition(this.anchorEl, this.popup, {
179
+ placement: this.placement,
180
+ middleware,
181
+ strategy: this.strategy
182
+ }).then(({ x, y, middlewareData, placement }) => {
183
+ const isRtl = getComputedStyle(this).direction === "rtl";
184
+ const staticSide = { top: "bottom", right: "left", bottom: "top", left: "right" }[placement.split("-")[0]];
185
+ this.setAttribute("data-current-placement", placement);
186
+ Object.assign(this.popup.style, {
187
+ left: `${x}px`,
188
+ top: `${y}px`
189
+ });
190
+ if (this.arrow) {
191
+ const arrowX = middlewareData.arrow.x;
192
+ const arrowY = middlewareData.arrow.y;
193
+ let top = "";
194
+ let right = "";
195
+ let bottom = "";
196
+ let left = "";
197
+ if (this.arrowPlacement === "start") {
198
+ const value = typeof arrowX === "number" ? `calc(${this.arrowPadding}px - var(--arrow-padding-offset))` : "";
199
+ top = typeof arrowY === "number" ? `calc(${this.arrowPadding}px - var(--arrow-padding-offset))` : "";
200
+ right = isRtl ? value : "";
201
+ left = isRtl ? "" : value;
202
+ } else if (this.arrowPlacement === "end") {
203
+ const value = typeof arrowX === "number" ? `calc(${this.arrowPadding}px - var(--arrow-padding-offset))` : "";
204
+ right = isRtl ? "" : value;
205
+ left = isRtl ? value : "";
206
+ bottom = typeof arrowY === "number" ? `calc(${this.arrowPadding}px - var(--arrow-padding-offset))` : "";
207
+ } else if (this.arrowPlacement === "center") {
208
+ left = typeof arrowX === "number" ? `calc(50% - var(--arrow-size-diagonal))` : "";
209
+ top = typeof arrowY === "number" ? `calc(50% - var(--arrow-size-diagonal))` : "";
210
+ } else {
211
+ left = typeof arrowX === "number" ? `${arrowX}px` : "";
212
+ top = typeof arrowY === "number" ? `${arrowY}px` : "";
213
+ }
214
+ Object.assign(this.arrowEl.style, {
215
+ top,
216
+ right,
217
+ bottom,
218
+ left,
219
+ [staticSide]: "calc(var(--arrow-size-diagonal) * -1)"
220
+ });
221
+ }
222
+ });
223
+ this.emit("sd-reposition");
224
+ }
225
+ render() {
226
+ return html`<slot name="anchor" @slotchange="${this.handleAnchorChange}"></slot><div part="popup" class="${cx("isolate", this.strategy !== "fixed" ? "absolute" : "fixed", !this.active && "hidden")}"><slot></slot>${this.arrow ? html`<div part="arrow" class="absolute rotate-45 -z-10" role="presentation"></div>` : ""}</div>`;
227
+ }
228
+ };
229
+ SdPopup.styles = [
230
+ SolidElement.styles,
231
+ componentStyles,
232
+ css`:host{--arrow-color:var(--sd-color-neutral-1000);--arrow-size:6px;--arrow-size-diagonal:calc(var(--arrow-size) * 0.7071);--arrow-padding-offset:calc(var(--arrow-size-diagonal) - var(--arrow-size));display:contents}[part=popup]{max-width:var(--auto-size-available-width,none);max-height:var(--auto-size-available-height,none)}[part=arrow]{width:calc(var(--arrow-size-diagonal) * 2);height:calc(var(--arrow-size-diagonal) * 2);background:var(--arrow-color)}`
233
+ ];
234
+ __decorateClass([
235
+ query('[part="popup"]')
236
+ ], SdPopup.prototype, "popup", 2);
237
+ __decorateClass([
238
+ query('[part="arrow"]')
239
+ ], SdPopup.prototype, "arrowEl", 2);
240
+ __decorateClass([
241
+ property()
242
+ ], SdPopup.prototype, "anchor", 2);
243
+ __decorateClass([
244
+ property({ type: Boolean, reflect: true })
245
+ ], SdPopup.prototype, "active", 2);
246
+ __decorateClass([
247
+ property({ reflect: true })
248
+ ], SdPopup.prototype, "placement", 2);
249
+ __decorateClass([
250
+ property({ reflect: true })
251
+ ], SdPopup.prototype, "strategy", 2);
252
+ __decorateClass([
253
+ property({ type: Number })
254
+ ], SdPopup.prototype, "distance", 2);
255
+ __decorateClass([
256
+ property({ type: Number })
257
+ ], SdPopup.prototype, "skidding", 2);
258
+ __decorateClass([
259
+ property({ type: Boolean })
260
+ ], SdPopup.prototype, "arrow", 2);
261
+ __decorateClass([
262
+ property({ attribute: "arrow-placement" })
263
+ ], SdPopup.prototype, "arrowPlacement", 2);
264
+ __decorateClass([
265
+ property({ attribute: "arrow-padding", type: Number })
266
+ ], SdPopup.prototype, "arrowPadding", 2);
267
+ __decorateClass([
268
+ property({ type: Boolean })
269
+ ], SdPopup.prototype, "flip", 2);
270
+ __decorateClass([
271
+ property({
272
+ attribute: "flip-fallback-placements",
273
+ converter: {
274
+ fromAttribute: (value) => {
275
+ return value.split(" ").map((p) => p.trim()).filter((p) => p !== "");
276
+ },
277
+ toAttribute: (value) => {
278
+ return value.join(" ");
279
+ }
280
+ }
281
+ })
282
+ ], SdPopup.prototype, "flipFallbackPlacements", 2);
283
+ __decorateClass([
284
+ property({ attribute: "flip-fallback-strategy" })
285
+ ], SdPopup.prototype, "flipFallbackStrategy", 2);
286
+ __decorateClass([
287
+ property({ type: Object })
288
+ ], SdPopup.prototype, "flipBoundary", 2);
289
+ __decorateClass([
290
+ property({ attribute: "flip-padding", type: Number })
291
+ ], SdPopup.prototype, "flipPadding", 2);
292
+ __decorateClass([
293
+ property({ type: Boolean })
294
+ ], SdPopup.prototype, "shift", 2);
295
+ __decorateClass([
296
+ property({ type: Object })
297
+ ], SdPopup.prototype, "shiftBoundary", 2);
298
+ __decorateClass([
299
+ property({ attribute: "shift-padding", type: Number })
300
+ ], SdPopup.prototype, "shiftPadding", 2);
301
+ __decorateClass([
302
+ property({ attribute: "auto-size" })
303
+ ], SdPopup.prototype, "autoSize", 2);
304
+ __decorateClass([
305
+ property()
306
+ ], SdPopup.prototype, "sync", 2);
307
+ __decorateClass([
308
+ property({ type: Object })
309
+ ], SdPopup.prototype, "autoSizeBoundary", 2);
310
+ __decorateClass([
311
+ property({ attribute: "auto-size-padding", type: Number })
312
+ ], SdPopup.prototype, "autoSizePadding", 2);
313
+ SdPopup = __decorateClass([
314
+ customElement("sd-popup")
315
+ ], SdPopup);
316
+ export {
317
+ SdPopup as default
318
+ };
@@ -0,0 +1,4 @@
1
+ export declare function getOffset(element: HTMLElement, parent: HTMLElement): {
2
+ top: number;
3
+ left: number;
4
+ };