@spectrum-web-components/overlay 1.12.0-testing.20260223092154 → 1.12.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.
- package/custom-elements.json +71 -0
- package/package.json +6 -6
- package/src/HoverController.dev.js +4 -0
- package/src/HoverController.dev.js.map +2 -2
- package/src/HoverController.js +1 -1
- package/src/HoverController.js.map +2 -2
- package/src/LongpressController.dev.js +4 -0
- package/src/LongpressController.dev.js.map +2 -2
- package/src/LongpressController.js +1 -1
- package/src/LongpressController.js.map +2 -2
- package/src/Overlay.d.ts +11 -0
- package/src/Overlay.dev.js +8 -3
- package/src/Overlay.dev.js.map +2 -2
- package/src/Overlay.js +2 -2
- package/src/Overlay.js.map +3 -3
- package/src/OverlayTrigger.d.ts +11 -0
- package/src/OverlayTrigger.dev.js +95 -16
- package/src/OverlayTrigger.dev.js.map +2 -2
- package/src/OverlayTrigger.js +6 -6
- package/src/OverlayTrigger.js.map +3 -3
- package/src/PlacementController.d.ts +9 -0
- package/src/PlacementController.dev.js +72 -3
- package/src/PlacementController.dev.js.map +3 -3
- package/src/PlacementController.js +1 -1
- package/src/PlacementController.js.map +3 -3
package/src/OverlayTrigger.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var u=Object.defineProperty;var v=Object.getOwnPropertyDescriptor;var s=(g,a,e,r)=>{for(var t=r>1?void 0:r?v(a,e):a,i=g.length-1,o;i>=0;i--)(o=g[i])&&(t=(r?o(a,e,t):o(t))||t);return r&&t&&u(a,e,t),t};import{html as p,SpectrumElement as y}from"@spectrum-web-components/base";import{property as l,query as h,state as c}from"@spectrum-web-components/base/src/decorators.js";import{randomID as f}from"@spectrum-web-components/shared/src/random-id.js";import"@spectrum-web-components/overlay/sp-overlay.js";import C from"./overlay-trigger.css.js";const n=class n extends y{constructor(){super(...arguments);this.offset=6;this.disabled=!1;this.receivesFocus="auto";this.clickContent=[];this.longpressContent=[];this.hoverContent=[];this.targetContent=[];this.ariaManagedElements=new WeakSet}static get styles(){return[C]}getAssignedElementsFromSlot(e){return e.assignedElements({flatten:!0})}handleTriggerContent(e){this.targetContent=this.getAssignedElementsFromSlot(e.target)}handleSlotContent(e){switch(e.target.name){case"click-content":this.clickContent=this.getAssignedElementsFromSlot(e.target);break;case"longpress-content":this.longpressContent=this.getAssignedElementsFromSlot(e.target);break;case"hover-content":this.hoverContent=this.getAssignedElementsFromSlot(e.target);break}}handleBeforetoggle(e){const{target:r}=e;let t;if(r===this.clickOverlayElement)t="click";else if(r===this.longpressOverlayElement)t="longpress";else if(r===this.hoverOverlayElement)t="hover";else return;e.newState==="open"?this.open=t:this.open===t&&(this.open=void 0)}resolveHaspopupValue(){const e=this.clickContent[0]||this.longpressContent[0];if(!e)return"dialog";const r=e.getAttribute("role");if(r&&n.VALID_HASPOPUP_ROLES.has(r))return r;const t=e.querySelector("[role]");return t&&n.VALID_HASPOPUP_ROLES.has(t.getAttribute("role"))?t.getAttribute("role"):"dialog"}removeAriaFromTrigger(e){this.ariaManagedElements.has(e)&&(e.removeAttribute("aria-expanded"),e.removeAttribute("aria-controls"),e.removeAttribute("aria-haspopup"),this.ariaManagedElements.delete(e))}manageAriaOnTrigger(){const e=this.targetContent[0];if(this.previousTriggerElement&&this.previousTriggerElement!==e&&this.removeAriaFromTrigger(this.previousTriggerElement),this.previousTriggerElement=e,!e)return;const r=this.clickContent.length>0,t=this.longpressContent.length>0;if(!r&&!t){this.removeAriaFromTrigger(e);return}const i=this.open==="click"||this.open==="longpress";e.setAttribute("aria-expanded",String(i)),(this.ariaManagedElements.has(e)||!e.hasAttribute("aria-haspopup"))&&e.setAttribute("aria-haspopup",this.resolveHaspopupValue()),this.ariaManagedElements.add(e);const o=this.open==="longpress"?this.longpressContent[0]:this.open==="click"?this.clickContent[0]:this.clickContent[0]||this.longpressContent[0];o?(o.id||(o.id=`sp-overlay-content-${f()}`),e.setAttribute("aria-controls",o.id)):e.removeAttribute("aria-controls")}disconnectedCallback(){this.previousTriggerElement&&(this.removeAriaFromTrigger(this.previousTriggerElement),this.previousTriggerElement=void 0),super.disconnectedCallback()}update(e){var r,t,i,o,d,m;e.has("clickContent")&&(this.clickPlacement=((r=this.clickContent[0])==null?void 0:r.getAttribute("placement"))||((t=this.clickContent[0])==null?void 0:t.getAttribute("direction"))||void 0),e.has("hoverContent")&&(this.hoverPlacement=((i=this.hoverContent[0])==null?void 0:i.getAttribute("placement"))||((o=this.hoverContent[0])==null?void 0:o.getAttribute("direction"))||void 0),e.has("longpressContent")&&(this.longpressPlacement=((d=this.longpressContent[0])==null?void 0:d.getAttribute("placement"))||((m=this.longpressContent[0])==null?void 0:m.getAttribute("direction"))||void 0),super.update(e)}renderSlot(e){return p`
|
|
2
2
|
<slot name=${e} @slotchange=${this.handleSlotContent}></slot>
|
|
3
|
-
`}renderClickOverlay(){var t;const e=this.renderSlot("click-content"),
|
|
3
|
+
`}renderClickOverlay(){var t;const e=this.renderSlot("click-content"),r=p`
|
|
4
4
|
<sp-overlay
|
|
5
5
|
id="click-overlay"
|
|
6
6
|
?disabled=${this.disabled||!this.clickContent.length}
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
>
|
|
16
16
|
${e}
|
|
17
17
|
</sp-overlay>
|
|
18
|
-
`;return(t=this.triggeredBy)!=null&&t.includes("click")||this.clickContent.length?
|
|
18
|
+
`;return(t=this.triggeredBy)!=null&&t.includes("click")||this.clickContent.length?r:e}renderHoverOverlay(){var t;const e=this.renderSlot("hover-content"),r=p`
|
|
19
19
|
<sp-overlay
|
|
20
20
|
id="hover-overlay"
|
|
21
21
|
?open=${this.open==="hover"&&!!this.hoverContent.length}
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
>
|
|
31
31
|
${e}
|
|
32
32
|
</sp-overlay>
|
|
33
|
-
`;return(t=this.triggeredBy)!=null&&t.includes("hover")||this.hoverContent.length?
|
|
33
|
+
`;return(t=this.triggeredBy)!=null&&t.includes("hover")||this.hoverContent.length?r:e}renderLongpressOverlay(){var t;const e=this.renderSlot("longpress-content"),r=p`
|
|
34
34
|
<sp-overlay
|
|
35
35
|
id="longpress-overlay"
|
|
36
36
|
?disabled=${this.disabled||!this.longpressContent.length}
|
|
@@ -46,12 +46,12 @@
|
|
|
46
46
|
${e}
|
|
47
47
|
</sp-overlay>
|
|
48
48
|
<slot name="longpress-describedby-descriptor"></slot>
|
|
49
|
-
`;return(t=this.triggeredBy)!=null&&t.includes("longpress")||this.longpressContent.length?
|
|
49
|
+
`;return(t=this.triggeredBy)!=null&&t.includes("longpress")||this.longpressContent.length?r:e}render(){return p`
|
|
50
50
|
<slot
|
|
51
51
|
id="trigger"
|
|
52
52
|
name="trigger"
|
|
53
53
|
@slotchange=${this.handleTriggerContent}
|
|
54
54
|
></slot>
|
|
55
55
|
${[this.renderClickOverlay(),this.renderHoverOverlay(),this.renderLongpressOverlay()]}
|
|
56
|
-
`}updated(e){if(super.updated(e),this.disabled&&e.has("disabled")){this.open=void 0;return}}async getUpdateComplete(){return await super.getUpdateComplete()}}
|
|
56
|
+
`}updated(e){if(super.updated(e),this.disabled&&e.has("disabled")){this.open=void 0;return}(e.has("open")||e.has("type")||e.has("targetContent")||e.has("clickContent")||e.has("longpressContent"))&&this.manageAriaOnTrigger()}async getUpdateComplete(){return await super.getUpdateComplete()}};n.VALID_HASPOPUP_ROLES=new Set(["menu","listbox","tree","grid","dialog"]),s([l({attribute:"triggered-by"})],n.prototype,"triggeredBy",2),s([l({reflect:!0})],n.prototype,"placement",2),s([l()],n.prototype,"type",2),s([l({type:Number})],n.prototype,"offset",2),s([l({reflect:!0})],n.prototype,"open",2),s([l({type:Boolean,reflect:!0})],n.prototype,"disabled",2),s([l({attribute:"receives-focus"})],n.prototype,"receivesFocus",2),s([c()],n.prototype,"clickContent",2),s([c()],n.prototype,"longpressContent",2),s([c()],n.prototype,"hoverContent",2),s([c()],n.prototype,"targetContent",2),s([h("#click-overlay",!0)],n.prototype,"clickOverlayElement",2),s([h("#longpress-overlay",!0)],n.prototype,"longpressOverlayElement",2),s([h("#hover-overlay",!0)],n.prototype,"hoverOverlayElement",2);export let OverlayTrigger=n;
|
|
57
57
|
//# sourceMappingURL=OverlayTrigger.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["OverlayTrigger.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Copyright 2026 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport type { Placement } from '@floating-ui/dom';\n\nimport {\n CSSResultArray,\n html,\n PropertyValues,\n SpectrumElement,\n TemplateResult,\n} from '@spectrum-web-components/base';\nimport {\n property,\n query,\n state,\n} from '@spectrum-web-components/base/src/decorators.js';\n\n/* eslint-disable import/no-extraneous-dependencies */\nimport '@spectrum-web-components/overlay/sp-overlay.js';\n\nimport type { BeforetoggleOpenEvent } from './events.js';\nimport type { Overlay } from './Overlay.js';\nimport overlayTriggerStyles from './overlay-trigger.css.js';\nimport type { OverlayTypes } from './overlay-types.js';\n\nexport type OverlayContentTypes = 'click' | 'hover' | 'longpress';\n\n// Helper type to create all unique combinations of OverlayContentTypes\ntype Combinations<T extends string, U extends string = T> = T extends string\n ? T | `${T} ${Combinations<Exclude<U, T>>}`\n : never;\n\nexport type TriggeredByType = Combinations<OverlayContentTypes>;\n\n/**\n * @element overlay-trigger\n *\n * A component that manages overlay content triggered by different interactions.\n * Supports click, hover, and longpress triggered overlays with configurable\n * placement and behavior.\n *\n * @slot trigger - The content that will trigger the various overlays\n * @slot hover-content - The content that will be displayed on hover\n * @slot click-content - The content that will be displayed on click\n * @slot longpress-content - The content that will be displayed on longpress\n * @slot longpress-describedby-descriptor - Description for longpress content\n *\n * @fires sp-opened - Announces that the overlay has been opened\n * @fires sp-closed - Announces that the overlay has been closed\n *\n * @attr {string} placement - The placement of the overlay relative to the trigger\n * @attr {number} offset - The distance between the overlay and the trigger\n * @attr {boolean} disabled - Whether the overlay trigger is disabled\n * @attr {string} receives-focus - How focus should be handled ('true'|'false'|'auto')\n * @attr {string} triggered-by - The type of interaction that will trigger the overlay ('click'|'hover'|'longpress')\n */\nexport class OverlayTrigger extends SpectrumElement {\n public static override get styles(): CSSResultArray {\n return [overlayTriggerStyles];\n }\n\n /**\n * Optional property to optimize performance and prevent race conditions.\n *\n * By explicitly declaring which content types are used (e.g. \"click\", \"longpress hover\"),\n * we can avoid:\n * 1. Extra renders from unnecessary slot reparenting\n * 2. Potential infinite render loops during content detection\n * 3. Race conditions during slot assignment\n *\n * By only returning overlay wrappers for explicitly declared content types,\n * we minimize unecessary DOM nodes, operations and ensure a more stable rendering behavior.\n */\n @property({ attribute: 'triggered-by' })\n public triggeredBy?: TriggeredByType;\n\n /**\n * @type {\"top\" | \"top-start\" | \"top-end\" | \"right\" | \"right-start\" | \"right-end\" | \"bottom\" | \"bottom-start\" | \"bottom-end\" | \"left\" | \"left-start\" | \"left-end\"}\n * @attr\n */\n @property({ reflect: true })\n public placement?: Placement;\n\n @property()\n public type?: OverlayTypes;\n\n @property({ type: Number })\n public offset = 6;\n\n @property({ reflect: true })\n public open?: OverlayContentTypes;\n\n @property({ type: Boolean, reflect: true })\n public disabled = false;\n\n @property({ attribute: 'receives-focus' })\n public receivesFocus: 'true' | 'false' | 'auto' = 'auto';\n\n @state()\n private clickContent: HTMLElement[] = [];\n\n private clickPlacement?: Placement;\n\n @state()\n private longpressContent: HTMLElement[] = [];\n\n private longpressPlacement?: Placement;\n\n @state()\n private hoverContent: HTMLElement[] = [];\n\n private hoverPlacement?: Placement;\n\n @state()\n private targetContent: HTMLElement[] = [];\n\n @query('#click-overlay', true)\n clickOverlayElement!: Overlay;\n\n @query('#longpress-overlay', true)\n longpressOverlayElement!: Overlay;\n\n @query('#hover-overlay', true)\n hoverOverlayElement!: Overlay;\n\n private getAssignedElementsFromSlot(slot: HTMLSlotElement): HTMLElement[] {\n return slot.assignedElements({ flatten: true }) as HTMLElement[];\n }\n\n private handleTriggerContent(\n event: Event & { target: HTMLSlotElement }\n ): void {\n this.targetContent = this.getAssignedElementsFromSlot(event.target);\n }\n\n private handleSlotContent(event: Event & { target: HTMLSlotElement }): void {\n switch (event.target.name) {\n case 'click-content':\n this.clickContent = this.getAssignedElementsFromSlot(event.target);\n break;\n case 'longpress-content':\n this.longpressContent = this.getAssignedElementsFromSlot(event.target);\n break;\n case 'hover-content':\n this.hoverContent = this.getAssignedElementsFromSlot(event.target);\n break;\n }\n }\n\n private handleBeforetoggle(event: BeforetoggleOpenEvent): void {\n const { target } = event;\n let type: OverlayContentTypes;\n if (target === this.clickOverlayElement) {\n type = 'click';\n } else if (target === this.longpressOverlayElement) {\n type = 'longpress';\n } else if (target === this.hoverOverlayElement) {\n type = 'hover';\n /* c8 ignore next 3 */\n } else {\n return;\n }\n if (event.newState === 'open') {\n this.open = type;\n } else if (this.open === type) {\n this.open = undefined;\n }\n }\n\n protected override update(changes: PropertyValues): void {\n if (changes.has('clickContent')) {\n this.clickPlacement =\n ((this.clickContent[0]?.getAttribute('placement') ||\n this.clickContent[0]?.getAttribute('direction')) as Placement) ||\n undefined;\n }\n if (changes.has('hoverContent')) {\n this.hoverPlacement =\n ((this.hoverContent[0]?.getAttribute('placement') ||\n this.hoverContent[0]?.getAttribute('direction')) as Placement) ||\n undefined;\n }\n if (changes.has('longpressContent')) {\n this.longpressPlacement =\n ((this.longpressContent[0]?.getAttribute('placement') ||\n this.longpressContent[0]?.getAttribute('direction')) as Placement) ||\n undefined;\n }\n super.update(changes);\n }\n\n protected renderSlot(name: string): TemplateResult {\n return html`\n <slot name=${name} @slotchange=${this.handleSlotContent}></slot>\n `;\n }\n\n protected renderClickOverlay(): TemplateResult {\n const slot = this.renderSlot('click-content');\n const clickOverlay = html`\n <sp-overlay\n id=\"click-overlay\"\n ?disabled=${this.disabled || !this.clickContent.length}\n ?open=${this.open === 'click' && !!this.clickContent.length}\n .offset=${this.offset}\n .placement=${this.clickPlacement || this.placement}\n .triggerElement=${this.targetContent[0]}\n .triggerInteraction=${'click'}\n .type=${this.type || 'auto'}\n @beforetoggle=${this.handleBeforetoggle}\n .receivesFocus=${this.receivesFocus}\n >\n ${slot}\n </sp-overlay>\n `;\n\n // If click interactions are explicitly enabled by customers, always return the overlay\n if (this.triggeredBy?.includes('click')) {\n return clickOverlay;\n }\n\n if (!this.clickContent.length) {\n return slot;\n } else {\n return clickOverlay;\n }\n }\n\n protected renderHoverOverlay(): TemplateResult {\n const slot = this.renderSlot('hover-content');\n const hoverOverlay = html`\n <sp-overlay\n id=\"hover-overlay\"\n ?open=${this.open === 'hover' && !!this.hoverContent.length}\n ?disabled=${this.disabled ||\n !this.hoverContent.length ||\n (!!this.open && this.open !== 'hover')}\n .offset=${this.offset}\n .placement=${this.hoverPlacement || this.placement}\n .triggerElement=${this.targetContent[0]}\n .triggerInteraction=${'hover'}\n .type=${'hint'}\n @beforetoggle=${this.handleBeforetoggle}\n .receivesFocus=${this.receivesFocus}\n >\n ${slot}\n </sp-overlay>\n `;\n\n // If hover interactions are explicitly enabled by customers, always return the overlay\n if (this.triggeredBy?.includes('hover')) {\n return hoverOverlay;\n }\n\n if (!this.hoverContent.length) {\n return slot;\n } else {\n return hoverOverlay;\n }\n }\n\n protected renderLongpressOverlay(): TemplateResult {\n const slot = this.renderSlot('longpress-content');\n const longpressOverlay = html`\n <sp-overlay\n id=\"longpress-overlay\"\n ?disabled=${this.disabled || !this.longpressContent.length}\n ?open=${this.open === 'longpress' && !!this.longpressContent.length}\n .offset=${this.offset}\n .placement=${this.longpressPlacement || this.placement}\n .triggerElement=${this.targetContent[0]}\n .triggerInteraction=${'longpress'}\n .type=${'auto'}\n @beforetoggle=${this.handleBeforetoggle}\n .receivesFocus=${this.receivesFocus}\n >\n ${slot}\n </sp-overlay>\n <slot name=\"longpress-describedby-descriptor\"></slot>\n `;\n\n // If click interactions are explicitly enabled by customers, always return the overlay\n if (this.triggeredBy?.includes('longpress')) {\n return longpressOverlay;\n }\n\n if (!this.longpressContent.length) {\n return slot;\n } else {\n return longpressOverlay;\n }\n }\n\n protected override render(): TemplateResult {\n // Keyboard event availability documented in README.md\n return html`\n <slot\n id=\"trigger\"\n name=\"trigger\"\n @slotchange=${this.handleTriggerContent}\n ></slot>\n ${[\n this.renderClickOverlay(),\n this.renderHoverOverlay(),\n this.renderLongpressOverlay(),\n ]}\n `;\n }\n\n protected override updated(changedProperties: PropertyValues): void {\n super.updated(changedProperties);\n\n if (window.__swc?.DEBUG && !this.triggeredBy) {\n const issues = [\n 'You have not specified the `triggeredBy` property. For optimal performance, consider explicitly declaring which overlay types you plan to use.',\n 'Example: triggered-by=\"click hover\"',\n 'This helps avoid unnecessary DOM operations and potential race conditions.',\n ];\n\n window.__swc.warn(\n this,\n 'Performance optimization available for <overlay-trigger>:',\n 'https://opensource.adobe.com/spectrum-web-components/components/overlay-trigger/#performance-optimization',\n { issues }\n );\n }\n\n if (this.disabled && changedProperties.has('disabled')) {\n this.open = undefined;\n return;\n }\n }\n\n protected override async getUpdateComplete(): Promise<boolean> {\n const complete = (await super.getUpdateComplete()) as boolean;\n return complete;\n }\n}\n"],
|
|
5
|
-
"mappings": "qNAcA,OAEE,QAAAA,EAEA,mBAAAC,MAEK,gCACP,OACE,YAAAC,EACA,SAAAC,EACA,SAAAC,MACK,
|
|
6
|
-
"names": ["html", "SpectrumElement", "property", "query", "state", "overlayTriggerStyles", "slot", "event", "target", "type", "changes", "_a", "_b", "_c", "_d", "_e", "_f", "name", "clickOverlay", "hoverOverlay", "longpressOverlay", "changedProperties", "__decorateClass"]
|
|
4
|
+
"sourcesContent": ["/**\n * Copyright 2026 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport type { Placement } from '@floating-ui/dom';\n\nimport {\n CSSResultArray,\n html,\n PropertyValues,\n SpectrumElement,\n TemplateResult,\n} from '@spectrum-web-components/base';\nimport {\n property,\n query,\n state,\n} from '@spectrum-web-components/base/src/decorators.js';\nimport { randomID } from '@spectrum-web-components/shared/src/random-id.js';\n\n/* eslint-disable import/no-extraneous-dependencies */\nimport '@spectrum-web-components/overlay/sp-overlay.js';\n\nimport type { BeforetoggleOpenEvent } from './events.js';\nimport type { Overlay } from './Overlay.js';\nimport overlayTriggerStyles from './overlay-trigger.css.js';\nimport type { OverlayTypes } from './overlay-types.js';\n\nexport type OverlayContentTypes = 'click' | 'hover' | 'longpress';\n\n// Helper type to create all unique combinations of OverlayContentTypes\ntype Combinations<T extends string, U extends string = T> = T extends string\n ? T | `${T} ${Combinations<Exclude<U, T>>}`\n : never;\n\nexport type TriggeredByType = Combinations<OverlayContentTypes>;\n\n/**\n * @element overlay-trigger\n *\n * A component that manages overlay content triggered by different interactions.\n * Supports click, hover, and longpress triggered overlays with configurable\n * placement and behavior.\n *\n * @slot trigger - The content that will trigger the various overlays\n * @slot hover-content - The content that will be displayed on hover\n * @slot click-content - The content that will be displayed on click\n * @slot longpress-content - The content that will be displayed on longpress\n * @slot longpress-describedby-descriptor - Description for longpress content\n *\n * @fires sp-opened - Announces that the overlay has been opened\n * @fires sp-closed - Announces that the overlay has been closed\n *\n * @attr {string} placement - The placement of the overlay relative to the trigger\n * @attr {number} offset - The distance between the overlay and the trigger\n * @attr {boolean} disabled - Whether the overlay trigger is disabled\n * @attr {string} receives-focus - How focus should be handled ('true'|'false'|'auto')\n * @attr {string} triggered-by - The type of interaction that will trigger the overlay ('click'|'hover'|'longpress')\n */\nexport class OverlayTrigger extends SpectrumElement {\n public static override get styles(): CSSResultArray {\n return [overlayTriggerStyles];\n }\n\n /**\n * Optional property to optimize performance and prevent race conditions.\n *\n * By explicitly declaring which content types are used (e.g. \"click\", \"longpress hover\"),\n * we can avoid:\n * 1. Extra renders from unnecessary slot reparenting\n * 2. Potential infinite render loops during content detection\n * 3. Race conditions during slot assignment\n *\n * By only returning overlay wrappers for explicitly declared content types,\n * we minimize unecessary DOM nodes, operations and ensure a more stable rendering behavior.\n */\n @property({ attribute: 'triggered-by' })\n public triggeredBy?: TriggeredByType;\n\n /**\n * @type {\"top\" | \"top-start\" | \"top-end\" | \"right\" | \"right-start\" | \"right-end\" | \"bottom\" | \"bottom-start\" | \"bottom-end\" | \"left\" | \"left-start\" | \"left-end\"}\n * @attr\n */\n @property({ reflect: true })\n public placement?: Placement;\n\n @property()\n public type?: OverlayTypes;\n\n @property({ type: Number })\n public offset = 6;\n\n @property({ reflect: true })\n public open?: OverlayContentTypes;\n\n @property({ type: Boolean, reflect: true })\n public disabled = false;\n\n @property({ attribute: 'receives-focus' })\n public receivesFocus: 'true' | 'false' | 'auto' = 'auto';\n\n @state()\n private clickContent: HTMLElement[] = [];\n\n private clickPlacement?: Placement;\n\n @state()\n private longpressContent: HTMLElement[] = [];\n\n private longpressPlacement?: Placement;\n\n @state()\n private hoverContent: HTMLElement[] = [];\n\n private hoverPlacement?: Placement;\n\n @state()\n private targetContent: HTMLElement[] = [];\n\n @query('#click-overlay', true)\n clickOverlayElement!: Overlay;\n\n @query('#longpress-overlay', true)\n longpressOverlayElement!: Overlay;\n\n @query('#hover-overlay', true)\n hoverOverlayElement!: Overlay;\n\n /**\n * Tracks elements where this component has taken ownership\n * of ARIA attributes, so consumer-set values are never removed.\n */\n private ariaManagedElements = new WeakSet<HTMLElement>();\n\n private previousTriggerElement?: HTMLElement;\n\n private getAssignedElementsFromSlot(slot: HTMLSlotElement): HTMLElement[] {\n return slot.assignedElements({ flatten: true }) as HTMLElement[];\n }\n\n private handleTriggerContent(\n event: Event & { target: HTMLSlotElement }\n ): void {\n this.targetContent = this.getAssignedElementsFromSlot(event.target);\n }\n\n private handleSlotContent(event: Event & { target: HTMLSlotElement }): void {\n switch (event.target.name) {\n case 'click-content':\n this.clickContent = this.getAssignedElementsFromSlot(event.target);\n break;\n case 'longpress-content':\n this.longpressContent = this.getAssignedElementsFromSlot(event.target);\n break;\n case 'hover-content':\n this.hoverContent = this.getAssignedElementsFromSlot(event.target);\n break;\n }\n }\n\n private handleBeforetoggle(event: BeforetoggleOpenEvent): void {\n const { target } = event;\n let type: OverlayContentTypes;\n if (target === this.clickOverlayElement) {\n type = 'click';\n } else if (target === this.longpressOverlayElement) {\n type = 'longpress';\n } else if (target === this.hoverOverlayElement) {\n type = 'hover';\n /* c8 ignore next 3 */\n } else {\n return;\n }\n if (event.newState === 'open') {\n this.open = type;\n } else if (this.open === type) {\n this.open = undefined;\n }\n }\n\n private static readonly VALID_HASPOPUP_ROLES = new Set([\n 'menu',\n 'listbox',\n 'tree',\n 'grid',\n 'dialog',\n ]);\n\n private resolveHaspopupValue(): string {\n const content = this.clickContent[0] || this.longpressContent[0];\n if (!content) {\n return 'dialog';\n }\n const role = content.getAttribute('role');\n if (role && OverlayTrigger.VALID_HASPOPUP_ROLES.has(role)) {\n return role;\n }\n const firstChild = content.querySelector('[role]') as HTMLElement | null;\n if (\n firstChild &&\n OverlayTrigger.VALID_HASPOPUP_ROLES.has(firstChild.getAttribute('role')!)\n ) {\n return firstChild.getAttribute('role')!;\n }\n return 'dialog';\n }\n\n private removeAriaFromTrigger(element: HTMLElement): void {\n if (!this.ariaManagedElements.has(element)) {\n return;\n }\n element.removeAttribute('aria-expanded');\n element.removeAttribute('aria-controls');\n element.removeAttribute('aria-haspopup');\n this.ariaManagedElements.delete(element);\n }\n\n private manageAriaOnTrigger(): void {\n const triggerElement = this.targetContent[0];\n\n if (\n this.previousTriggerElement &&\n this.previousTriggerElement !== triggerElement\n ) {\n this.removeAriaFromTrigger(this.previousTriggerElement);\n }\n this.previousTriggerElement = triggerElement;\n\n if (!triggerElement) {\n return;\n }\n\n const hasClickContent = this.clickContent.length > 0;\n const hasLongpressContent = this.longpressContent.length > 0;\n\n if (!hasClickContent && !hasLongpressContent) {\n this.removeAriaFromTrigger(triggerElement);\n return;\n }\n\n const isExpanded = this.open === 'click' || this.open === 'longpress';\n triggerElement.setAttribute('aria-expanded', String(isExpanded));\n\n if (\n this.ariaManagedElements.has(triggerElement) ||\n !triggerElement.hasAttribute('aria-haspopup')\n ) {\n triggerElement.setAttribute('aria-haspopup', this.resolveHaspopupValue());\n }\n this.ariaManagedElements.add(triggerElement);\n\n const content =\n this.open === 'longpress'\n ? this.longpressContent[0]\n : this.open === 'click'\n ? this.clickContent[0]\n : this.clickContent[0] || this.longpressContent[0];\n if (content) {\n if (!content.id) {\n content.id = `sp-overlay-content-${randomID()}`;\n }\n triggerElement.setAttribute('aria-controls', content.id);\n } else {\n triggerElement.removeAttribute('aria-controls');\n }\n }\n\n override disconnectedCallback(): void {\n if (this.previousTriggerElement) {\n this.removeAriaFromTrigger(this.previousTriggerElement);\n this.previousTriggerElement = undefined;\n }\n super.disconnectedCallback();\n }\n\n protected override update(changes: PropertyValues): void {\n if (changes.has('clickContent')) {\n this.clickPlacement =\n ((this.clickContent[0]?.getAttribute('placement') ||\n this.clickContent[0]?.getAttribute('direction')) as Placement) ||\n undefined;\n }\n if (changes.has('hoverContent')) {\n this.hoverPlacement =\n ((this.hoverContent[0]?.getAttribute('placement') ||\n this.hoverContent[0]?.getAttribute('direction')) as Placement) ||\n undefined;\n }\n if (changes.has('longpressContent')) {\n this.longpressPlacement =\n ((this.longpressContent[0]?.getAttribute('placement') ||\n this.longpressContent[0]?.getAttribute('direction')) as Placement) ||\n undefined;\n }\n super.update(changes);\n }\n\n protected renderSlot(name: string): TemplateResult {\n return html`\n <slot name=${name} @slotchange=${this.handleSlotContent}></slot>\n `;\n }\n\n protected renderClickOverlay(): TemplateResult {\n const slot = this.renderSlot('click-content');\n const clickOverlay = html`\n <sp-overlay\n id=\"click-overlay\"\n ?disabled=${this.disabled || !this.clickContent.length}\n ?open=${this.open === 'click' && !!this.clickContent.length}\n .offset=${this.offset}\n .placement=${this.clickPlacement || this.placement}\n .triggerElement=${this.targetContent[0]}\n .triggerInteraction=${'click'}\n .type=${this.type || 'auto'}\n @beforetoggle=${this.handleBeforetoggle}\n .receivesFocus=${this.receivesFocus}\n >\n ${slot}\n </sp-overlay>\n `;\n\n // If click interactions are explicitly enabled by customers, always return the overlay\n if (this.triggeredBy?.includes('click')) {\n return clickOverlay;\n }\n\n if (!this.clickContent.length) {\n return slot;\n } else {\n return clickOverlay;\n }\n }\n\n protected renderHoverOverlay(): TemplateResult {\n const slot = this.renderSlot('hover-content');\n const hoverOverlay = html`\n <sp-overlay\n id=\"hover-overlay\"\n ?open=${this.open === 'hover' && !!this.hoverContent.length}\n ?disabled=${this.disabled ||\n !this.hoverContent.length ||\n (!!this.open && this.open !== 'hover')}\n .offset=${this.offset}\n .placement=${this.hoverPlacement || this.placement}\n .triggerElement=${this.targetContent[0]}\n .triggerInteraction=${'hover'}\n .type=${'hint'}\n @beforetoggle=${this.handleBeforetoggle}\n .receivesFocus=${this.receivesFocus}\n >\n ${slot}\n </sp-overlay>\n `;\n\n // If hover interactions are explicitly enabled by customers, always return the overlay\n if (this.triggeredBy?.includes('hover')) {\n return hoverOverlay;\n }\n\n if (!this.hoverContent.length) {\n return slot;\n } else {\n return hoverOverlay;\n }\n }\n\n protected renderLongpressOverlay(): TemplateResult {\n const slot = this.renderSlot('longpress-content');\n const longpressOverlay = html`\n <sp-overlay\n id=\"longpress-overlay\"\n ?disabled=${this.disabled || !this.longpressContent.length}\n ?open=${this.open === 'longpress' && !!this.longpressContent.length}\n .offset=${this.offset}\n .placement=${this.longpressPlacement || this.placement}\n .triggerElement=${this.targetContent[0]}\n .triggerInteraction=${'longpress'}\n .type=${'auto'}\n @beforetoggle=${this.handleBeforetoggle}\n .receivesFocus=${this.receivesFocus}\n >\n ${slot}\n </sp-overlay>\n <slot name=\"longpress-describedby-descriptor\"></slot>\n `;\n\n // If click interactions are explicitly enabled by customers, always return the overlay\n if (this.triggeredBy?.includes('longpress')) {\n return longpressOverlay;\n }\n\n if (!this.longpressContent.length) {\n return slot;\n } else {\n return longpressOverlay;\n }\n }\n\n protected override render(): TemplateResult {\n // Keyboard event availability documented in README.md\n return html`\n <slot\n id=\"trigger\"\n name=\"trigger\"\n @slotchange=${this.handleTriggerContent}\n ></slot>\n ${[\n this.renderClickOverlay(),\n this.renderHoverOverlay(),\n this.renderLongpressOverlay(),\n ]}\n `;\n }\n\n protected override updated(changedProperties: PropertyValues): void {\n super.updated(changedProperties);\n\n if (window.__swc?.DEBUG && !this.triggeredBy) {\n const issues = [\n 'You have not specified the `triggeredBy` property. For optimal performance, consider explicitly declaring which overlay types you plan to use.',\n 'Example: triggered-by=\"click hover\"',\n 'This helps avoid unnecessary DOM operations and potential race conditions.',\n ];\n\n window.__swc.warn(\n this,\n 'Performance optimization available for <overlay-trigger>:',\n 'https://opensource.adobe.com/spectrum-web-components/components/overlay-trigger/#performance-optimization',\n { issues }\n );\n }\n\n if (this.disabled && changedProperties.has('disabled')) {\n this.open = undefined;\n return;\n }\n\n if (\n changedProperties.has('open') ||\n changedProperties.has('type') ||\n changedProperties.has('targetContent') ||\n changedProperties.has('clickContent') ||\n changedProperties.has('longpressContent')\n ) {\n this.manageAriaOnTrigger();\n }\n }\n\n protected override async getUpdateComplete(): Promise<boolean> {\n const complete = (await super.getUpdateComplete()) as boolean;\n return complete;\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["html", "SpectrumElement", "property", "query", "state", "randomID", "overlayTriggerStyles", "_OverlayTrigger", "slot", "event", "target", "type", "content", "role", "firstChild", "element", "triggerElement", "hasClickContent", "hasLongpressContent", "isExpanded", "changes", "_a", "_b", "_c", "_d", "_e", "_f", "name", "clickOverlay", "hoverOverlay", "longpressOverlay", "changedProperties", "__decorateClass"]
|
|
7
7
|
}
|
|
@@ -82,6 +82,15 @@ export declare class PlacementController implements ReactiveController {
|
|
|
82
82
|
* @type {HTMLElement}
|
|
83
83
|
*/
|
|
84
84
|
private target;
|
|
85
|
+
/**
|
|
86
|
+
* Incremented whenever the active placement session ends (`cleanup`) or a
|
|
87
|
+
* new session begins, so async `computePlacement` runs that started under an
|
|
88
|
+
* older session do not write styles after teardown or across stacked
|
|
89
|
+
* `placeOverlay` calls.
|
|
90
|
+
*
|
|
91
|
+
* @private
|
|
92
|
+
*/
|
|
93
|
+
private placementGeneration;
|
|
85
94
|
/**
|
|
86
95
|
* Creates an instance of the PlacementController.
|
|
87
96
|
*
|
|
@@ -51,6 +51,15 @@ export class PlacementController {
|
|
|
51
51
|
* @type {WeakMap<HTMLElement, Placement>}
|
|
52
52
|
*/
|
|
53
53
|
this.originalPlacements = /* @__PURE__ */ new WeakMap();
|
|
54
|
+
/**
|
|
55
|
+
* Incremented whenever the active placement session ends (`cleanup`) or a
|
|
56
|
+
* new session begins, so async `computePlacement` runs that started under an
|
|
57
|
+
* older session do not write styles after teardown or across stacked
|
|
58
|
+
* `placeOverlay` calls.
|
|
59
|
+
*
|
|
60
|
+
* @private
|
|
61
|
+
*/
|
|
62
|
+
this.placementGeneration = 0;
|
|
54
63
|
/**
|
|
55
64
|
* Flag to allow or disallow placement updates.
|
|
56
65
|
*
|
|
@@ -107,6 +116,9 @@ export class PlacementController {
|
|
|
107
116
|
* @returns {Promise<void>} A promise that resolves when the overlay has been placed.
|
|
108
117
|
*/
|
|
109
118
|
async placeOverlay(target = this.target, options = this.options) {
|
|
119
|
+
var _a;
|
|
120
|
+
(_a = this.cleanup) == null ? void 0 : _a.call(this);
|
|
121
|
+
this.cleanup = void 0;
|
|
110
122
|
this.target = target;
|
|
111
123
|
this.options = options;
|
|
112
124
|
if (!target || !options) {
|
|
@@ -130,9 +142,34 @@ export class PlacementController {
|
|
|
130
142
|
ancestorScroll: false
|
|
131
143
|
}
|
|
132
144
|
);
|
|
145
|
+
const visualViewport = window.visualViewport;
|
|
146
|
+
let visualViewportRafId = 0;
|
|
147
|
+
let visualViewportPlacementCancelled = false;
|
|
148
|
+
const onVisualViewportChange = () => {
|
|
149
|
+
if (visualViewportPlacementCancelled || visualViewportRafId) {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
visualViewportRafId = requestAnimationFrame(() => {
|
|
153
|
+
visualViewportRafId = 0;
|
|
154
|
+
if (visualViewportPlacementCancelled) {
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
this.updatePlacement();
|
|
158
|
+
});
|
|
159
|
+
};
|
|
160
|
+
if (visualViewport && isWebKit()) {
|
|
161
|
+
visualViewport.addEventListener("resize", onVisualViewportChange, {
|
|
162
|
+
passive: true
|
|
163
|
+
});
|
|
164
|
+
visualViewport.addEventListener("scroll", onVisualViewportChange, {
|
|
165
|
+
passive: true
|
|
166
|
+
});
|
|
167
|
+
}
|
|
133
168
|
this.cleanup = () => {
|
|
134
|
-
var
|
|
135
|
-
|
|
169
|
+
var _a2;
|
|
170
|
+
this.placementGeneration += 1;
|
|
171
|
+
visualViewportPlacementCancelled = true;
|
|
172
|
+
(_a2 = this.host.elements) == null ? void 0 : _a2.forEach((element) => {
|
|
136
173
|
element.addEventListener(
|
|
137
174
|
"sp-closed",
|
|
138
175
|
() => {
|
|
@@ -147,6 +184,14 @@ export class PlacementController {
|
|
|
147
184
|
});
|
|
148
185
|
cleanupAncestorResize();
|
|
149
186
|
cleanupElementResize();
|
|
187
|
+
if (visualViewport && isWebKit()) {
|
|
188
|
+
visualViewport.removeEventListener("resize", onVisualViewportChange);
|
|
189
|
+
visualViewport.removeEventListener("scroll", onVisualViewportChange);
|
|
190
|
+
if (visualViewportRafId) {
|
|
191
|
+
cancelAnimationFrame(visualViewportRafId);
|
|
192
|
+
visualViewportRafId = 0;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
150
195
|
};
|
|
151
196
|
}
|
|
152
197
|
/**
|
|
@@ -161,10 +206,18 @@ export class PlacementController {
|
|
|
161
206
|
async computePlacement() {
|
|
162
207
|
var _a, _b;
|
|
163
208
|
const { options, target } = this;
|
|
209
|
+
const genAtStart = this.placementGeneration;
|
|
210
|
+
const placementStillValid = () => this.host.open && this.placementGeneration === genAtStart && !!this.target && this.target === target;
|
|
164
211
|
await (document.fonts ? document.fonts.ready : Promise.resolve());
|
|
212
|
+
if (!placementStillValid()) {
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
165
215
|
if (isWebKit()) {
|
|
166
216
|
await new Promise((resolve) => requestAnimationFrame(resolve));
|
|
167
217
|
}
|
|
218
|
+
if (!placementStillValid()) {
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
168
221
|
const flipMiddleware = !(options.trigger instanceof HTMLElement) ? flip({
|
|
169
222
|
padding: REQUIRED_DISTANCE_TO_EDGE,
|
|
170
223
|
fallbackPlacements: getFallbackPlacements(options.placement)
|
|
@@ -213,10 +266,23 @@ export class PlacementController {
|
|
|
213
266
|
strategy: "fixed"
|
|
214
267
|
}
|
|
215
268
|
);
|
|
269
|
+
if (!placementStillValid()) {
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
let translateX = x;
|
|
273
|
+
let translateY = y;
|
|
274
|
+
const visualViewport = window.visualViewport;
|
|
275
|
+
if (visualViewport && isWebKit()) {
|
|
276
|
+
translateX -= visualViewport.offsetLeft;
|
|
277
|
+
translateY -= visualViewport.offsetTop;
|
|
278
|
+
}
|
|
279
|
+
if (!placementStillValid()) {
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
216
282
|
Object.assign(target.style, {
|
|
217
283
|
top: "0px",
|
|
218
284
|
left: "0px",
|
|
219
|
-
translate: `${roundByDPR(
|
|
285
|
+
translate: `${roundByDPR(translateX)}px ${roundByDPR(translateY)}px`
|
|
220
286
|
});
|
|
221
287
|
target.setAttribute("actual-placement", placement);
|
|
222
288
|
(_b = this.host.elements) == null ? void 0 : _b.forEach((element) => {
|
|
@@ -228,6 +294,9 @@ export class PlacementController {
|
|
|
228
294
|
}
|
|
229
295
|
element.setAttribute("placement", placement);
|
|
230
296
|
});
|
|
297
|
+
if (!placementStillValid()) {
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
231
300
|
if (tipElement && middlewareData.arrow) {
|
|
232
301
|
const { x: arrowX, y: arrowY } = middlewareData.arrow;
|
|
233
302
|
Object.assign(tipElement.style, {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["PlacementController.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Copyright 2026 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {\n arrow,\n autoUpdate,\n computePosition,\n flip,\n offset,\n Placement,\n shift,\n size,\n} from '@floating-ui/dom';\n\nimport type {\n ReactiveController,\n ReactiveElement,\n} from '@spectrum-web-components/base';\nimport { isWebKit } from '@spectrum-web-components/shared';\n\nimport type { Overlay } from './Overlay.dev.js'\nimport type { OpenableElement } from './overlay-types.dev.js'\nimport type { VirtualTrigger } from './VirtualTrigger.dev.js'\n\ntype OverlayOptionsV1 = {\n abortPromise?: Promise<boolean>;\n delayed?: boolean;\n offset?: number | [number, number]; // supporting multi-axis\n placement: Placement;\n notImmediatelyClosable?: boolean; // rename or place behind other API options\n receivesFocus?: 'auto';\n root?: HTMLElement;\n tipPadding?: number;\n trigger: HTMLElement | VirtualTrigger;\n type?: 'modal' | 'page' | 'hint' | 'auto' | 'manual';\n};\n\n/**\n * Rounds a number by the device pixel ratio (DPR).\n *\n * @param {number} [num] - The number to round.\n * @returns {number} The rounded number.\n */\nfunction roundByDPR(num?: number): number {\n if (typeof num === 'undefined') {\n return 0;\n }\n const dpr = window.devicePixelRatio || 1;\n return Math.round(num * dpr) / dpr;\n}\n\n// Minimum distance required between the overlay and the edge of the container.\n// See: https://spectrum.adobe.com/page/popover/#Container-padding\nconst REQUIRED_DISTANCE_TO_EDGE = 8;\n// Minimum height for the overlay.\n// See: https://github.com/adobe/spectrum-web-components/issues/910\nconst MIN_OVERLAY_HEIGHT = 100;\n\n/**\n * Gets fallback placements for the overlay based on the initial placement.\n *\n * @param {Placement} placement - The initial placement of the overlay.\n * @returns {Placement[]} An array of fallback placements.\n */\nconst getFallbackPlacements = (placement: Placement): Placement[] => {\n const fallbacks: Record<Placement, Placement[]> = {\n left: ['right', 'bottom', 'top'],\n 'left-start': ['right-start', 'bottom', 'top'],\n 'left-end': ['right-end', 'bottom', 'top'],\n right: ['left', 'bottom', 'top'],\n 'right-start': ['left-start', 'bottom', 'top'],\n 'right-end': ['left-end', 'bottom', 'top'],\n top: ['bottom', 'left', 'right'],\n 'top-start': ['bottom-start', 'left', 'right'],\n 'top-end': ['bottom-end', 'left', 'right'],\n bottom: ['top', 'left', 'right'],\n 'bottom-start': ['top-start', 'left', 'right'],\n 'bottom-end': ['top-end', 'left', 'right'],\n };\n return fallbacks[placement] ?? [placement];\n};\n\n/**\n * Symbol used to indicate that the placement has been updated.\n */\nexport const placementUpdatedSymbol = Symbol('placement updated');\n\n/**\n * Controller for managing the placement of an overlay.\n *\n * This class implements the ReactiveController interface and provides methods\n * for managing the positioning and constraints of an overlay element.\n */\nexport class PlacementController implements ReactiveController {\n /**\n * Function to clean up resources when the controller is no longer needed.\n *\n * @private\n */\n private cleanup?: () => void;\n\n /**\n * Initial height of the overlay.\n *\n * @type {number}\n */\n initialHeight?: number;\n\n /**\n * Indicates whether the overlay is constrained by available space.\n *\n * @type {boolean}\n */\n isConstrained?: boolean;\n\n /**\n * The host element that uses this controller.\n *\n * @private\n * @type {ReactiveElement & { elements: OpenableElement[] }}\n */\n private host!: ReactiveElement & { elements: OpenableElement[] };\n\n /**\n * Options for configuring the overlay placement.\n *\n * @private\n * @type {OverlayOptionsV1}\n */\n private options!: OverlayOptionsV1;\n\n /**\n * A WeakMap to store the original placements of overlay elements.\n *\n * @private\n * @type {WeakMap<HTMLElement, Placement>}\n */\n private originalPlacements = new WeakMap<HTMLElement, Placement>();\n\n /**\n * The target element for the overlay.\n *\n * @private\n * @type {HTMLElement}\n */\n private target!: HTMLElement;\n\n /**\n * Creates an instance of the PlacementController.\n *\n * @param {ReactiveElement & { elements: OpenableElement[] }} host - The host element that uses this controller.\n */\n constructor(host: ReactiveElement & { elements: OpenableElement[] }) {\n this.host = host;\n // Add the controller after the MutationObserver has been created in preparation\n // for the `hostConnected`/`hostDisconnected` callbacks to be run.\n this.host.addController(this);\n }\n\n /**\n * Places the overlay relative to the target element.\n *\n * This method sets up the necessary configurations and event listeners to manage the\n * positioning and constraints of the overlay element.\n *\n * @param {HTMLElement} [target=this.target] - The target element for the overlay.\n * @param {OverlayOptionsV1} [options=this.options] - The options for configuring the overlay placement.\n * @returns {Promise<void>} A promise that resolves when the overlay has been placed.\n */\n public async placeOverlay(\n target: HTMLElement = this.target,\n options: OverlayOptionsV1 = this.options\n ): Promise<void> {\n // Set the target and options for the overlay.\n this.target = target;\n this.options = options;\n if (!target || !options) {\n return;\n }\n\n // Set up auto-update for ancestor resize events.\n const cleanupAncestorResize = autoUpdate(\n options.trigger,\n target,\n this.closeForAncestorUpdate,\n {\n ancestorResize: false,\n elementResize: false,\n layoutShift: false,\n }\n );\n\n // Set up auto-update for element resize events.\n const cleanupElementResize = autoUpdate(\n options.trigger,\n target,\n this.updatePlacement,\n {\n ancestorScroll: false,\n }\n );\n\n // Define the cleanup function to remove event listeners and reset placements.\n this.cleanup = () => {\n this.host.elements?.forEach((element) => {\n element.addEventListener(\n 'sp-closed',\n () => {\n const placement = this.originalPlacements.get(element);\n\n if (placement) {\n element.setAttribute('placement', placement);\n }\n\n this.originalPlacements.delete(element);\n },\n { once: true }\n );\n });\n cleanupAncestorResize();\n cleanupElementResize();\n };\n }\n\n /**\n * Flag to allow or disallow placement updates.\n *\n * @type {boolean}\n */\n public allowPlacementUpdate = false;\n\n /**\n * Closes the overlay if an ancestor element is updated.\n *\n * This method checks if placement updates are allowed and if the overlay type is not 'modal'.\n * If these conditions are met and a cleanup function is defined, it dispatches a 'close' event\n * on the target element to close the overlay.\n */\n closeForAncestorUpdate = (): void => {\n if (\n !this.allowPlacementUpdate &&\n this.options.type !== 'modal' &&\n this.cleanup\n ) {\n // Dispatch a 'close' event to close the overlay.\n this.target.dispatchEvent(new Event('close', { bubbles: true }));\n }\n\n // Reset the flag to disallow placement updates.\n this.allowPlacementUpdate = false;\n };\n\n /**\n * Updates the placement of the overlay.\n *\n * This method calls the computePlacement method to recalculate the overlay's position.\n *\n * @private\n */\n private updatePlacement = (): void => {\n this.computePlacement();\n };\n\n /**\n * Computes the placement of the overlay relative to the target element.\n *\n * This method calculates the necessary positioning and constraints for the overlay element\n * using various middleware functions. It updates the overlay's style and attributes based\n * on the computed position.\n *\n * @returns {Promise<void>} A promise that resolves when the placement has been computed.\n */\n async computePlacement(): Promise<void> {\n const { options, target } = this;\n\n // Wait for document fonts to be ready before computing placement.\n await (document.fonts ? document.fonts.ready : Promise.resolve());\n\n if (isWebKit()) {\n // Computing placement requires a frame for layout stability in WebKit\n await new Promise((resolve) => requestAnimationFrame(resolve));\n }\n\n // Determine the flip middleware based on the type of trigger element.\n const flipMiddleware = !(options.trigger instanceof HTMLElement)\n ? flip({\n padding: REQUIRED_DISTANCE_TO_EDGE,\n fallbackPlacements: getFallbackPlacements(options.placement),\n })\n : flip();\n\n // Extract main axis and cross axis offsets from options.\n const [mainAxis = 0, crossAxis = 0] = Array.isArray(options?.offset)\n ? options.offset\n : [options.offset, 0];\n\n // Find the tip element within the host elements.\n const tipElement = this.host.elements.find(\n (el) => el.tipElement\n )?.tipElement;\n\n // Define middleware functions for positioning and constraints.\n const middleware = [\n offset({\n mainAxis,\n crossAxis,\n }),\n shift({ padding: REQUIRED_DISTANCE_TO_EDGE }),\n flipMiddleware,\n size({\n padding: REQUIRED_DISTANCE_TO_EDGE,\n apply: ({ availableWidth, availableHeight, rects: { floating } }) => {\n const maxHeight = Math.max(\n MIN_OVERLAY_HEIGHT,\n Math.floor(availableHeight)\n );\n const actualHeight = floating.height;\n this.initialHeight = !this.isConstrained // && !this.virtualTrigger\n ? actualHeight\n : this.initialHeight || actualHeight;\n this.isConstrained =\n actualHeight < this.initialHeight || maxHeight <= actualHeight;\n const appliedHeight = this.isConstrained ? `${maxHeight}px` : '';\n Object.assign(target.style, {\n maxWidth: `${Math.floor(availableWidth)}px`,\n maxHeight: appliedHeight,\n });\n },\n }),\n ...(tipElement\n ? [\n arrow({\n element: tipElement,\n padding: options.tipPadding || REQUIRED_DISTANCE_TO_EDGE,\n }),\n ]\n : []),\n ];\n\n // Compute the position of the overlay using the defined middleware.\n const { x, y, placement, middlewareData } = await computePosition(\n options.trigger,\n target,\n {\n placement: options.placement,\n middleware,\n strategy: 'fixed',\n }\n );\n\n // Update the overlay's style with the computed position.\n Object.assign(target.style, {\n top: '0px',\n left: '0px',\n translate: `${roundByDPR(x)}px ${roundByDPR(y)}px`,\n });\n\n // Set the 'actual-placement' attribute on the target element.\n target.setAttribute('actual-placement', placement);\n\n // Update the placement attribute for each host element.\n this.host.elements?.forEach((element) => {\n if (!this.originalPlacements.has(element)) {\n this.originalPlacements.set(\n element,\n element.getAttribute('placement') as Placement\n );\n }\n element.setAttribute('placement', placement);\n });\n\n // Update the tip element's style with the computed arrow position.\n if (tipElement && middlewareData.arrow) {\n const { x: arrowX, y: arrowY } = middlewareData.arrow;\n\n Object.assign(tipElement.style, {\n top:\n placement.startsWith('right') || placement.startsWith('left')\n ? '0px'\n : '',\n left:\n placement.startsWith('bottom') || placement.startsWith('top')\n ? '0px'\n : '',\n translate: `${roundByDPR(arrowX)}px ${roundByDPR(arrowY)}px`,\n });\n }\n }\n\n /**\n * Clears the overlay's position styles.\n *\n * This method removes the max-height and max-width styles from the target element,\n * and resets the initial height and constrained state of the overlay.\n */\n public clearOverlayPosition(): void {\n if (!this.target) {\n return;\n }\n // Remove max-height and max-width styles from the target element.\n this.target.style.removeProperty('max-height');\n this.target.style.removeProperty('max-width');\n // Reset the initial height and constrained state.\n this.initialHeight = undefined;\n this.isConstrained = false;\n }\n\n /**\n * Resets the overlay's position.\n *\n * This method clears the overlay's position, forces a reflow, and recomputes the placement.\n */\n public resetOverlayPosition = (): void => {\n if (!this.target || !this.options) {\n return;\n }\n // Clear the overlay's position.\n this.clearOverlayPosition();\n\n // Force a reflow.\n /** @todo investigate why this is needed and if there is a better way to do this or remove it entirely */\n // eslint-disable-next-line @typescript-eslint/no-unused-expressions\n this.host.offsetHeight;\n // Recompute the placement.\n this.computePlacement();\n };\n\n /**\n * Lifecycle method called when the host element is connected to the DOM.\n *\n * This method sets up an event listener to reset the overlay's position when the 'sp-update-overlays' event is dispatched.\n */\n hostConnected(): void {\n document.addEventListener('sp-update-overlays', this.resetOverlayPosition);\n }\n\n /**\n * Lifecycle method called when the host element is updated.\n *\n * This method cleans up resources if the overlay is not open.\n */\n hostUpdated(): void {\n if (!(this.host as Overlay).open) {\n // Clean up resources if the overlay is not open.\n this.cleanup?.();\n this.cleanup = undefined;\n }\n }\n\n /**\n * Lifecycle method called when the host element is disconnected from the DOM.\n *\n * This method removes the event listener and cleans up resources.\n */\n hostDisconnected(): void {\n // Clean up resources.\n this.cleanup?.();\n this.cleanup = undefined;\n // Remove the event listener.\n document.removeEventListener(\n 'sp-update-overlays',\n this.resetOverlayPosition\n );\n }\n}\n"],
|
|
5
|
-
"mappings": ";AAYA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,EACA;AAAA,OACK;AAMP,SAAS,gBAAgB;AAyBzB,SAAS,WAAW,KAAsB;AACxC,MAAI,OAAO,QAAQ,aAAa;AAC9B,WAAO;AAAA,EACT;AACA,QAAM,MAAM,OAAO,oBAAoB;AACvC,SAAO,KAAK,MAAM,MAAM,GAAG,IAAI;AACjC;AAIA,MAAM,4BAA4B;AAGlC,MAAM,qBAAqB;AAQ3B,MAAM,wBAAwB,CAAC,cAAsC;AAzErE;AA0EE,QAAM,YAA4C;AAAA,IAChD,MAAM,CAAC,SAAS,UAAU,KAAK;AAAA,IAC/B,cAAc,CAAC,eAAe,UAAU,KAAK;AAAA,IAC7C,YAAY,CAAC,aAAa,UAAU,KAAK;AAAA,IACzC,OAAO,CAAC,QAAQ,UAAU,KAAK;AAAA,IAC/B,eAAe,CAAC,cAAc,UAAU,KAAK;AAAA,IAC7C,aAAa,CAAC,YAAY,UAAU,KAAK;AAAA,IACzC,KAAK,CAAC,UAAU,QAAQ,OAAO;AAAA,IAC/B,aAAa,CAAC,gBAAgB,QAAQ,OAAO;AAAA,IAC7C,WAAW,CAAC,cAAc,QAAQ,OAAO;AAAA,IACzC,QAAQ,CAAC,OAAO,QAAQ,OAAO;AAAA,IAC/B,gBAAgB,CAAC,aAAa,QAAQ,OAAO;AAAA,IAC7C,cAAc,CAAC,WAAW,QAAQ,OAAO;AAAA,EAC3C;AACA,UAAO,eAAU,SAAS,MAAnB,YAAwB,CAAC,SAAS;AAC3C;AAKO,aAAM,yBAAyB,OAAO,mBAAmB;AAQzD,aAAM,oBAAkD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,
|
|
6
|
-
"names": []
|
|
4
|
+
"sourcesContent": ["/**\n * Copyright 2026 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {\n arrow,\n autoUpdate,\n computePosition,\n flip,\n offset,\n Placement,\n shift,\n size,\n} from '@floating-ui/dom';\n\nimport type {\n ReactiveController,\n ReactiveElement,\n} from '@spectrum-web-components/base';\nimport { isWebKit } from '@spectrum-web-components/shared';\n\nimport type { Overlay } from './Overlay.dev.js'\nimport type { OpenableElement } from './overlay-types.dev.js'\nimport type { VirtualTrigger } from './VirtualTrigger.dev.js'\n\ntype OverlayOptionsV1 = {\n abortPromise?: Promise<boolean>;\n delayed?: boolean;\n offset?: number | [number, number]; // supporting multi-axis\n placement: Placement;\n notImmediatelyClosable?: boolean; // rename or place behind other API options\n receivesFocus?: 'auto';\n root?: HTMLElement;\n tipPadding?: number;\n trigger: HTMLElement | VirtualTrigger;\n type?: 'modal' | 'page' | 'hint' | 'auto' | 'manual';\n};\n\n/**\n * Rounds a number by the device pixel ratio (DPR).\n *\n * @param {number} [num] - The number to round.\n * @returns {number} The rounded number.\n */\nfunction roundByDPR(num?: number): number {\n if (typeof num === 'undefined') {\n return 0;\n }\n const dpr = window.devicePixelRatio || 1;\n return Math.round(num * dpr) / dpr;\n}\n\n// Minimum distance required between the overlay and the edge of the container.\n// See: https://spectrum.adobe.com/page/popover/#Container-padding\nconst REQUIRED_DISTANCE_TO_EDGE = 8;\n// Minimum height for the overlay.\n// See: https://github.com/adobe/spectrum-web-components/issues/910\nconst MIN_OVERLAY_HEIGHT = 100;\n\n/**\n * Gets fallback placements for the overlay based on the initial placement.\n *\n * @param {Placement} placement - The initial placement of the overlay.\n * @returns {Placement[]} An array of fallback placements.\n */\nconst getFallbackPlacements = (placement: Placement): Placement[] => {\n const fallbacks: Record<Placement, Placement[]> = {\n left: ['right', 'bottom', 'top'],\n 'left-start': ['right-start', 'bottom', 'top'],\n 'left-end': ['right-end', 'bottom', 'top'],\n right: ['left', 'bottom', 'top'],\n 'right-start': ['left-start', 'bottom', 'top'],\n 'right-end': ['left-end', 'bottom', 'top'],\n top: ['bottom', 'left', 'right'],\n 'top-start': ['bottom-start', 'left', 'right'],\n 'top-end': ['bottom-end', 'left', 'right'],\n bottom: ['top', 'left', 'right'],\n 'bottom-start': ['top-start', 'left', 'right'],\n 'bottom-end': ['top-end', 'left', 'right'],\n };\n return fallbacks[placement] ?? [placement];\n};\n\n/**\n * Symbol used to indicate that the placement has been updated.\n */\nexport const placementUpdatedSymbol = Symbol('placement updated');\n\n/**\n * Controller for managing the placement of an overlay.\n *\n * This class implements the ReactiveController interface and provides methods\n * for managing the positioning and constraints of an overlay element.\n */\nexport class PlacementController implements ReactiveController {\n /**\n * Function to clean up resources when the controller is no longer needed.\n *\n * @private\n */\n private cleanup?: () => void;\n\n /**\n * Initial height of the overlay.\n *\n * @type {number}\n */\n initialHeight?: number;\n\n /**\n * Indicates whether the overlay is constrained by available space.\n *\n * @type {boolean}\n */\n isConstrained?: boolean;\n\n /**\n * The host element that uses this controller.\n *\n * @private\n * @type {ReactiveElement & { elements: OpenableElement[] }}\n */\n private host!: ReactiveElement & { elements: OpenableElement[] };\n\n /**\n * Options for configuring the overlay placement.\n *\n * @private\n * @type {OverlayOptionsV1}\n */\n private options!: OverlayOptionsV1;\n\n /**\n * A WeakMap to store the original placements of overlay elements.\n *\n * @private\n * @type {WeakMap<HTMLElement, Placement>}\n */\n private originalPlacements = new WeakMap<HTMLElement, Placement>();\n\n /**\n * The target element for the overlay.\n *\n * @private\n * @type {HTMLElement}\n */\n private target!: HTMLElement;\n\n /**\n * Incremented whenever the active placement session ends (`cleanup`) or a\n * new session begins, so async `computePlacement` runs that started under an\n * older session do not write styles after teardown or across stacked\n * `placeOverlay` calls.\n *\n * @private\n */\n private placementGeneration = 0;\n\n /**\n * Creates an instance of the PlacementController.\n *\n * @param {ReactiveElement & { elements: OpenableElement[] }} host - The host element that uses this controller.\n */\n constructor(host: ReactiveElement & { elements: OpenableElement[] }) {\n this.host = host;\n // Add the controller after the MutationObserver has been created in preparation\n // for the `hostConnected`/`hostDisconnected` callbacks to be run.\n this.host.addController(this);\n }\n\n /**\n * Places the overlay relative to the target element.\n *\n * This method sets up the necessary configurations and event listeners to manage the\n * positioning and constraints of the overlay element.\n *\n * @param {HTMLElement} [target=this.target] - The target element for the overlay.\n * @param {OverlayOptionsV1} [options=this.options] - The options for configuring the overlay placement.\n * @returns {Promise<void>} A promise that resolves when the overlay has been placed.\n */\n public async placeOverlay(\n target: HTMLElement = this.target,\n options: OverlayOptionsV1 = this.options\n ): Promise<void> {\n // If `placeOverlay` runs twice before `hostUpdated` clears the prior\n // session (rapid open, programmatic toggles), tear down the previous\n // listeners first so `visualViewport` handlers and pending rAFs cannot\n // leak.\n this.cleanup?.();\n this.cleanup = undefined;\n\n // Set the target and options for the overlay.\n this.target = target;\n this.options = options;\n if (!target || !options) {\n return;\n }\n\n // Set up auto-update for ancestor resize events.\n const cleanupAncestorResize = autoUpdate(\n options.trigger,\n target,\n this.closeForAncestorUpdate,\n {\n ancestorResize: false,\n elementResize: false,\n layoutShift: false,\n }\n );\n\n // Set up auto-update for element resize events.\n const cleanupElementResize = autoUpdate(\n options.trigger,\n target,\n this.updatePlacement,\n {\n ancestorScroll: false,\n }\n );\n\n // Recompute placement when the visual viewport diverges from the layout\n // viewport (URL bar showing/hiding, pinch-zoom, virtual keyboard, host-app\n // bottom sheets, etc.). Floating UI's `autoUpdate` does not observe\n // `window.visualViewport`, so without this an open overlay can drift away\n // from its trigger on WebKit (iOS Safari, WKWebView, and desktop Safari\n // when pinch-zoomed) until the next resize. See `computePlacement` for the\n // corresponding offset compensation.\n //\n // Listeners are passive (we never `preventDefault` in `updatePlacement`)\n // and rAF-coalesced so a burst of `resize`/`scroll` events during a URL\n // bar collapse or pinch gesture compresses to one Floating UI compute per\n // frame.\n const visualViewport = window.visualViewport;\n let visualViewportRafId = 0;\n let visualViewportPlacementCancelled = false;\n const onVisualViewportChange = (): void => {\n if (visualViewportPlacementCancelled || visualViewportRafId) {\n return;\n }\n visualViewportRafId = requestAnimationFrame(() => {\n visualViewportRafId = 0;\n if (visualViewportPlacementCancelled) {\n return;\n }\n this.updatePlacement();\n });\n };\n if (visualViewport && isWebKit()) {\n visualViewport.addEventListener('resize', onVisualViewportChange, {\n passive: true,\n });\n visualViewport.addEventListener('scroll', onVisualViewportChange, {\n passive: true,\n });\n }\n\n // Define the cleanup function to remove event listeners and reset placements.\n this.cleanup = () => {\n this.placementGeneration += 1;\n // Invalidate any `visualViewport` rAF callback scheduled before this\n // cleanup runs, so `updatePlacement` cannot start after teardown.\n visualViewportPlacementCancelled = true;\n this.host.elements?.forEach((element) => {\n element.addEventListener(\n 'sp-closed',\n () => {\n const placement = this.originalPlacements.get(element);\n\n if (placement) {\n element.setAttribute('placement', placement);\n }\n\n this.originalPlacements.delete(element);\n },\n { once: true }\n );\n });\n cleanupAncestorResize();\n cleanupElementResize();\n if (visualViewport && isWebKit()) {\n visualViewport.removeEventListener('resize', onVisualViewportChange);\n visualViewport.removeEventListener('scroll', onVisualViewportChange);\n if (visualViewportRafId) {\n cancelAnimationFrame(visualViewportRafId);\n visualViewportRafId = 0;\n }\n }\n };\n }\n\n /**\n * Flag to allow or disallow placement updates.\n *\n * @type {boolean}\n */\n public allowPlacementUpdate = false;\n\n /**\n * Closes the overlay if an ancestor element is updated.\n *\n * This method checks if placement updates are allowed and if the overlay type is not 'modal'.\n * If these conditions are met and a cleanup function is defined, it dispatches a 'close' event\n * on the target element to close the overlay.\n */\n closeForAncestorUpdate = (): void => {\n if (\n !this.allowPlacementUpdate &&\n this.options.type !== 'modal' &&\n this.cleanup\n ) {\n // Dispatch a 'close' event to close the overlay.\n this.target.dispatchEvent(new Event('close', { bubbles: true }));\n }\n\n // Reset the flag to disallow placement updates.\n this.allowPlacementUpdate = false;\n };\n\n /**\n * Updates the placement of the overlay.\n *\n * This method calls the computePlacement method to recalculate the overlay's position.\n *\n * @private\n */\n private updatePlacement = (): void => {\n this.computePlacement();\n };\n\n /**\n * Computes the placement of the overlay relative to the target element.\n *\n * This method calculates the necessary positioning and constraints for the overlay element\n * using various middleware functions. It updates the overlay's style and attributes based\n * on the computed position.\n *\n * @returns {Promise<void>} A promise that resolves when the placement has been computed.\n */\n async computePlacement(): Promise<void> {\n const { options, target } = this;\n\n const genAtStart = this.placementGeneration;\n const placementStillValid = (): boolean =>\n (this.host as Overlay).open &&\n this.placementGeneration === genAtStart &&\n !!this.target &&\n this.target === target;\n\n // Wait for document fonts to be ready before computing placement.\n await (document.fonts ? document.fonts.ready : Promise.resolve());\n if (!placementStillValid()) {\n return;\n }\n\n if (isWebKit()) {\n // Computing placement requires a frame for layout stability in WebKit\n await new Promise((resolve) => requestAnimationFrame(resolve));\n }\n if (!placementStillValid()) {\n return;\n }\n\n // Determine the flip middleware based on the type of trigger element.\n const flipMiddleware = !(options.trigger instanceof HTMLElement)\n ? flip({\n padding: REQUIRED_DISTANCE_TO_EDGE,\n fallbackPlacements: getFallbackPlacements(options.placement),\n })\n : flip();\n\n // Extract main axis and cross axis offsets from options.\n const [mainAxis = 0, crossAxis = 0] = Array.isArray(options?.offset)\n ? options.offset\n : [options.offset, 0];\n\n // Find the tip element within the host elements.\n const tipElement = this.host.elements.find(\n (el) => el.tipElement\n )?.tipElement;\n\n // Define middleware functions for positioning and constraints.\n const middleware = [\n offset({\n mainAxis,\n crossAxis,\n }),\n shift({ padding: REQUIRED_DISTANCE_TO_EDGE }),\n flipMiddleware,\n size({\n padding: REQUIRED_DISTANCE_TO_EDGE,\n apply: ({ availableWidth, availableHeight, rects: { floating } }) => {\n const maxHeight = Math.max(\n MIN_OVERLAY_HEIGHT,\n Math.floor(availableHeight)\n );\n const actualHeight = floating.height;\n this.initialHeight = !this.isConstrained // && !this.virtualTrigger\n ? actualHeight\n : this.initialHeight || actualHeight;\n this.isConstrained =\n actualHeight < this.initialHeight || maxHeight <= actualHeight;\n const appliedHeight = this.isConstrained ? `${maxHeight}px` : '';\n Object.assign(target.style, {\n maxWidth: `${Math.floor(availableWidth)}px`,\n maxHeight: appliedHeight,\n });\n },\n }),\n ...(tipElement\n ? [\n arrow({\n element: tipElement,\n padding: options.tipPadding || REQUIRED_DISTANCE_TO_EDGE,\n }),\n ]\n : []),\n ];\n\n // Compute the position of the overlay using the defined middleware.\n const { x, y, placement, middlewareData } = await computePosition(\n options.trigger,\n target,\n {\n placement: options.placement,\n middleware,\n strategy: 'fixed',\n }\n );\n if (!placementStillValid()) {\n return;\n }\n\n // On iOS WebKit (Safari and WKWebView hosts such as the Adobe Express\n // iOS app) the layout viewport and the visual viewport can diverge by\n // tens of pixels \u2014 for example when the URL bar is showing, when the\n // page is pinch-zoomed, when the virtual keyboard is open, or when a\n // native bottom sheet is overlaid. Floating UI computes `(x, y)` from\n // `getBoundingClientRect()`, which is in layout-viewport coordinates,\n // but the overlay is rendered in the top layer via the native popover\n // API and therefore painted relative to the visual viewport. Without\n // this compensation the overlay lands `visualViewport.offsetTop` px\n // below (and `offsetLeft` px to the side of) its trigger on iOS while\n // appearing correct on every other browser.\n let translateX = x;\n let translateY = y;\n const visualViewport = window.visualViewport;\n if (visualViewport && isWebKit()) {\n translateX -= visualViewport.offsetLeft;\n translateY -= visualViewport.offsetTop;\n }\n\n // Update the overlay's style with the computed position.\n if (!placementStillValid()) {\n return;\n }\n Object.assign(target.style, {\n top: '0px',\n left: '0px',\n translate: `${roundByDPR(translateX)}px ${roundByDPR(translateY)}px`,\n });\n\n // Set the 'actual-placement' attribute on the target element.\n target.setAttribute('actual-placement', placement);\n\n // Update the placement attribute for each host element.\n this.host.elements?.forEach((element) => {\n if (!this.originalPlacements.has(element)) {\n this.originalPlacements.set(\n element,\n element.getAttribute('placement') as Placement\n );\n }\n element.setAttribute('placement', placement);\n });\n\n // Update the tip element's style with the computed arrow position.\n if (!placementStillValid()) {\n return;\n }\n if (tipElement && middlewareData.arrow) {\n const { x: arrowX, y: arrowY } = middlewareData.arrow;\n\n Object.assign(tipElement.style, {\n top:\n placement.startsWith('right') || placement.startsWith('left')\n ? '0px'\n : '',\n left:\n placement.startsWith('bottom') || placement.startsWith('top')\n ? '0px'\n : '',\n translate: `${roundByDPR(arrowX)}px ${roundByDPR(arrowY)}px`,\n });\n }\n }\n\n /**\n * Clears the overlay's position styles.\n *\n * This method removes the max-height and max-width styles from the target element,\n * and resets the initial height and constrained state of the overlay.\n */\n public clearOverlayPosition(): void {\n if (!this.target) {\n return;\n }\n // Remove max-height and max-width styles from the target element.\n this.target.style.removeProperty('max-height');\n this.target.style.removeProperty('max-width');\n // Reset the initial height and constrained state.\n this.initialHeight = undefined;\n this.isConstrained = false;\n }\n\n /**\n * Resets the overlay's position.\n *\n * This method clears the overlay's position, forces a reflow, and recomputes the placement.\n */\n public resetOverlayPosition = (): void => {\n if (!this.target || !this.options) {\n return;\n }\n // Clear the overlay's position.\n this.clearOverlayPosition();\n\n // Force a reflow.\n /** @todo investigate why this is needed and if there is a better way to do this or remove it entirely */\n // eslint-disable-next-line @typescript-eslint/no-unused-expressions\n this.host.offsetHeight;\n // Recompute the placement.\n this.computePlacement();\n };\n\n /**\n * Lifecycle method called when the host element is connected to the DOM.\n *\n * This method sets up an event listener to reset the overlay's position when the 'sp-update-overlays' event is dispatched.\n */\n hostConnected(): void {\n document.addEventListener('sp-update-overlays', this.resetOverlayPosition);\n }\n\n /**\n * Lifecycle method called when the host element is updated.\n *\n * This method cleans up resources if the overlay is not open.\n */\n hostUpdated(): void {\n if (!(this.host as Overlay).open) {\n // Clean up resources if the overlay is not open.\n this.cleanup?.();\n this.cleanup = undefined;\n }\n }\n\n /**\n * Lifecycle method called when the host element is disconnected from the DOM.\n *\n * This method removes the event listener and cleans up resources.\n */\n hostDisconnected(): void {\n // Clean up resources.\n this.cleanup?.();\n this.cleanup = undefined;\n // Remove the event listener.\n document.removeEventListener(\n 'sp-update-overlays',\n this.resetOverlayPosition\n );\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["_a"]
|
|
7
7
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";import{arrow as
|
|
1
|
+
"use strict";import{arrow as C,autoUpdate as A,computePosition as M,flip as R,offset as T,shift as U,size as z}from"@floating-ui/dom";import{isWebKit as f}from"@spectrum-web-components/shared";function u(l){if(typeof l=="undefined")return 0;const t=window.devicePixelRatio||1;return Math.round(l*t)/t}const g=8,F=100,S=l=>{var e;return(e={left:["right","bottom","top"],"left-start":["right-start","bottom","top"],"left-end":["right-end","bottom","top"],right:["left","bottom","top"],"right-start":["left-start","bottom","top"],"right-end":["left-end","bottom","top"],top:["bottom","left","right"],"top-start":["bottom-start","left","right"],"top-end":["bottom-end","left","right"],bottom:["top","left","right"],"bottom-start":["top-start","left","right"],"bottom-end":["top-end","left","right"]}[l])!=null?e:[l]};export const placementUpdatedSymbol=Symbol("placement updated");export class PlacementController{constructor(t){this.originalPlacements=new WeakMap;this.placementGeneration=0;this.allowPlacementUpdate=!1;this.closeForAncestorUpdate=()=>{!this.allowPlacementUpdate&&this.options.type!=="modal"&&this.cleanup&&this.target.dispatchEvent(new Event("close",{bubbles:!0})),this.allowPlacementUpdate=!1};this.updatePlacement=()=>{this.computePlacement()};this.resetOverlayPosition=()=>{!this.target||!this.options||(this.clearOverlayPosition(),this.host.offsetHeight,this.computePlacement())};this.host=t,this.host.addController(this)}async placeOverlay(t=this.target,e=this.options){var m;if((m=this.cleanup)==null||m.call(this),this.cleanup=void 0,this.target=t,this.options=e,!t||!e)return;const v=A(e.trigger,t,this.closeForAncestorUpdate,{ancestorResize:!1,elementResize:!1,layoutShift:!1}),r=A(e.trigger,t,this.updatePlacement,{ancestorScroll:!1}),n=window.visualViewport;let o=0,c=!1;const a=()=>{c||o||(o=requestAnimationFrame(()=>{o=0,!c&&this.updatePlacement()}))};n&&f()&&(n.addEventListener("resize",a,{passive:!0}),n.addEventListener("scroll",a,{passive:!0})),this.cleanup=()=>{var h;this.placementGeneration+=1,c=!0,(h=this.host.elements)==null||h.forEach(p=>{p.addEventListener("sp-closed",()=>{const s=this.originalPlacements.get(p);s&&p.setAttribute("placement",s),this.originalPlacements.delete(p)},{once:!0})}),v(),r(),n&&f()&&(n.removeEventListener("resize",a),n.removeEventListener("scroll",a),o&&(cancelAnimationFrame(o),o=0))}}async computePlacement(){var x,O;const{options:t,target:e}=this,v=this.placementGeneration,r=()=>this.host.open&&this.placementGeneration===v&&!!this.target&&this.target===e;if(await(document.fonts?document.fonts.ready:Promise.resolve()),!r()||(f()&&await new Promise(i=>requestAnimationFrame(i)),!r()))return;const n=t.trigger instanceof HTMLElement?R():R({padding:g,fallbackPlacements:S(t.placement)}),[o=0,c=0]=Array.isArray(t==null?void 0:t.offset)?t.offset:[t.offset,0],a=(x=this.host.elements.find(i=>i.tipElement))==null?void 0:x.tipElement,m=[T({mainAxis:o,crossAxis:c}),U({padding:g}),n,z({padding:g,apply:({availableWidth:i,availableHeight:y,rects:{floating:V}})=>{const H=Math.max(F,Math.floor(y)),d=V.height;this.initialHeight=this.isConstrained&&this.initialHeight||d,this.isConstrained=d<this.initialHeight||H<=d;const L=this.isConstrained?`${H}px`:"";Object.assign(e.style,{maxWidth:`${Math.floor(i)}px`,maxHeight:L})}}),...a?[C({element:a,padding:t.tipPadding||g})]:[]],{x:h,y:p,placement:s,middlewareData:P}=await M(t.trigger,e,{placement:t.placement,middleware:m,strategy:"fixed"});if(!r())return;let E=h,w=p;const b=window.visualViewport;if(b&&f()&&(E-=b.offsetLeft,w-=b.offsetTop),!!r()&&(Object.assign(e.style,{top:"0px",left:"0px",translate:`${u(E)}px ${u(w)}px`}),e.setAttribute("actual-placement",s),(O=this.host.elements)==null||O.forEach(i=>{this.originalPlacements.has(i)||this.originalPlacements.set(i,i.getAttribute("placement")),i.setAttribute("placement",s)}),!!r()&&a&&P.arrow)){const{x:i,y}=P.arrow;Object.assign(a.style,{top:s.startsWith("right")||s.startsWith("left")?"0px":"",left:s.startsWith("bottom")||s.startsWith("top")?"0px":"",translate:`${u(i)}px ${u(y)}px`})}}clearOverlayPosition(){this.target&&(this.target.style.removeProperty("max-height"),this.target.style.removeProperty("max-width"),this.initialHeight=void 0,this.isConstrained=!1)}hostConnected(){document.addEventListener("sp-update-overlays",this.resetOverlayPosition)}hostUpdated(){var t;this.host.open||((t=this.cleanup)==null||t.call(this),this.cleanup=void 0)}hostDisconnected(){var t;(t=this.cleanup)==null||t.call(this),this.cleanup=void 0,document.removeEventListener("sp-update-overlays",this.resetOverlayPosition)}}
|
|
2
2
|
//# sourceMappingURL=PlacementController.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["PlacementController.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Copyright 2026 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {\n arrow,\n autoUpdate,\n computePosition,\n flip,\n offset,\n Placement,\n shift,\n size,\n} from '@floating-ui/dom';\n\nimport type {\n ReactiveController,\n ReactiveElement,\n} from '@spectrum-web-components/base';\nimport { isWebKit } from '@spectrum-web-components/shared';\n\nimport type { Overlay } from './Overlay.js';\nimport type { OpenableElement } from './overlay-types.js';\nimport type { VirtualTrigger } from './VirtualTrigger.js';\n\ntype OverlayOptionsV1 = {\n abortPromise?: Promise<boolean>;\n delayed?: boolean;\n offset?: number | [number, number]; // supporting multi-axis\n placement: Placement;\n notImmediatelyClosable?: boolean; // rename or place behind other API options\n receivesFocus?: 'auto';\n root?: HTMLElement;\n tipPadding?: number;\n trigger: HTMLElement | VirtualTrigger;\n type?: 'modal' | 'page' | 'hint' | 'auto' | 'manual';\n};\n\n/**\n * Rounds a number by the device pixel ratio (DPR).\n *\n * @param {number} [num] - The number to round.\n * @returns {number} The rounded number.\n */\nfunction roundByDPR(num?: number): number {\n if (typeof num === 'undefined') {\n return 0;\n }\n const dpr = window.devicePixelRatio || 1;\n return Math.round(num * dpr) / dpr;\n}\n\n// Minimum distance required between the overlay and the edge of the container.\n// See: https://spectrum.adobe.com/page/popover/#Container-padding\nconst REQUIRED_DISTANCE_TO_EDGE = 8;\n// Minimum height for the overlay.\n// See: https://github.com/adobe/spectrum-web-components/issues/910\nconst MIN_OVERLAY_HEIGHT = 100;\n\n/**\n * Gets fallback placements for the overlay based on the initial placement.\n *\n * @param {Placement} placement - The initial placement of the overlay.\n * @returns {Placement[]} An array of fallback placements.\n */\nconst getFallbackPlacements = (placement: Placement): Placement[] => {\n const fallbacks: Record<Placement, Placement[]> = {\n left: ['right', 'bottom', 'top'],\n 'left-start': ['right-start', 'bottom', 'top'],\n 'left-end': ['right-end', 'bottom', 'top'],\n right: ['left', 'bottom', 'top'],\n 'right-start': ['left-start', 'bottom', 'top'],\n 'right-end': ['left-end', 'bottom', 'top'],\n top: ['bottom', 'left', 'right'],\n 'top-start': ['bottom-start', 'left', 'right'],\n 'top-end': ['bottom-end', 'left', 'right'],\n bottom: ['top', 'left', 'right'],\n 'bottom-start': ['top-start', 'left', 'right'],\n 'bottom-end': ['top-end', 'left', 'right'],\n };\n return fallbacks[placement] ?? [placement];\n};\n\n/**\n * Symbol used to indicate that the placement has been updated.\n */\nexport const placementUpdatedSymbol = Symbol('placement updated');\n\n/**\n * Controller for managing the placement of an overlay.\n *\n * This class implements the ReactiveController interface and provides methods\n * for managing the positioning and constraints of an overlay element.\n */\nexport class PlacementController implements ReactiveController {\n /**\n * Function to clean up resources when the controller is no longer needed.\n *\n * @private\n */\n private cleanup?: () => void;\n\n /**\n * Initial height of the overlay.\n *\n * @type {number}\n */\n initialHeight?: number;\n\n /**\n * Indicates whether the overlay is constrained by available space.\n *\n * @type {boolean}\n */\n isConstrained?: boolean;\n\n /**\n * The host element that uses this controller.\n *\n * @private\n * @type {ReactiveElement & { elements: OpenableElement[] }}\n */\n private host!: ReactiveElement & { elements: OpenableElement[] };\n\n /**\n * Options for configuring the overlay placement.\n *\n * @private\n * @type {OverlayOptionsV1}\n */\n private options!: OverlayOptionsV1;\n\n /**\n * A WeakMap to store the original placements of overlay elements.\n *\n * @private\n * @type {WeakMap<HTMLElement, Placement>}\n */\n private originalPlacements = new WeakMap<HTMLElement, Placement>();\n\n /**\n * The target element for the overlay.\n *\n * @private\n * @type {HTMLElement}\n */\n private target!: HTMLElement;\n\n /**\n * Creates an instance of the PlacementController.\n *\n * @param {ReactiveElement & { elements: OpenableElement[] }} host - The host element that uses this controller.\n */\n constructor(host: ReactiveElement & { elements: OpenableElement[] }) {\n this.host = host;\n // Add the controller after the MutationObserver has been created in preparation\n // for the `hostConnected`/`hostDisconnected` callbacks to be run.\n this.host.addController(this);\n }\n\n /**\n * Places the overlay relative to the target element.\n *\n * This method sets up the necessary configurations and event listeners to manage the\n * positioning and constraints of the overlay element.\n *\n * @param {HTMLElement} [target=this.target] - The target element for the overlay.\n * @param {OverlayOptionsV1} [options=this.options] - The options for configuring the overlay placement.\n * @returns {Promise<void>} A promise that resolves when the overlay has been placed.\n */\n public async placeOverlay(\n target: HTMLElement = this.target,\n options: OverlayOptionsV1 = this.options\n ): Promise<void> {\n // Set the target and options for the overlay.\n this.target = target;\n this.options = options;\n if (!target || !options) {\n return;\n }\n\n // Set up auto-update for ancestor resize events.\n const cleanupAncestorResize = autoUpdate(\n options.trigger,\n target,\n this.closeForAncestorUpdate,\n {\n ancestorResize: false,\n elementResize: false,\n layoutShift: false,\n }\n );\n\n // Set up auto-update for element resize events.\n const cleanupElementResize = autoUpdate(\n options.trigger,\n target,\n this.updatePlacement,\n {\n ancestorScroll: false,\n }\n );\n\n // Define the cleanup function to remove event listeners and reset placements.\n this.cleanup = () => {\n this.host.elements?.forEach((element) => {\n element.addEventListener(\n 'sp-closed',\n () => {\n const placement = this.originalPlacements.get(element);\n\n if (placement) {\n element.setAttribute('placement', placement);\n }\n\n this.originalPlacements.delete(element);\n },\n { once: true }\n );\n });\n cleanupAncestorResize();\n cleanupElementResize();\n };\n }\n\n /**\n * Flag to allow or disallow placement updates.\n *\n * @type {boolean}\n */\n public allowPlacementUpdate = false;\n\n /**\n * Closes the overlay if an ancestor element is updated.\n *\n * This method checks if placement updates are allowed and if the overlay type is not 'modal'.\n * If these conditions are met and a cleanup function is defined, it dispatches a 'close' event\n * on the target element to close the overlay.\n */\n closeForAncestorUpdate = (): void => {\n if (\n !this.allowPlacementUpdate &&\n this.options.type !== 'modal' &&\n this.cleanup\n ) {\n // Dispatch a 'close' event to close the overlay.\n this.target.dispatchEvent(new Event('close', { bubbles: true }));\n }\n\n // Reset the flag to disallow placement updates.\n this.allowPlacementUpdate = false;\n };\n\n /**\n * Updates the placement of the overlay.\n *\n * This method calls the computePlacement method to recalculate the overlay's position.\n *\n * @private\n */\n private updatePlacement = (): void => {\n this.computePlacement();\n };\n\n /**\n * Computes the placement of the overlay relative to the target element.\n *\n * This method calculates the necessary positioning and constraints for the overlay element\n * using various middleware functions. It updates the overlay's style and attributes based\n * on the computed position.\n *\n * @returns {Promise<void>} A promise that resolves when the placement has been computed.\n */\n async computePlacement(): Promise<void> {\n const { options, target } = this;\n\n // Wait for document fonts to be ready before computing placement.\n await (document.fonts ? document.fonts.ready : Promise.resolve());\n\n if (isWebKit()) {\n // Computing placement requires a frame for layout stability in WebKit\n await new Promise((resolve) => requestAnimationFrame(resolve));\n }\n\n // Determine the flip middleware based on the type of trigger element.\n const flipMiddleware = !(options.trigger instanceof HTMLElement)\n ? flip({\n padding: REQUIRED_DISTANCE_TO_EDGE,\n fallbackPlacements: getFallbackPlacements(options.placement),\n })\n : flip();\n\n // Extract main axis and cross axis offsets from options.\n const [mainAxis = 0, crossAxis = 0] = Array.isArray(options?.offset)\n ? options.offset\n : [options.offset, 0];\n\n // Find the tip element within the host elements.\n const tipElement = this.host.elements.find(\n (el) => el.tipElement\n )?.tipElement;\n\n // Define middleware functions for positioning and constraints.\n const middleware = [\n offset({\n mainAxis,\n crossAxis,\n }),\n shift({ padding: REQUIRED_DISTANCE_TO_EDGE }),\n flipMiddleware,\n size({\n padding: REQUIRED_DISTANCE_TO_EDGE,\n apply: ({ availableWidth, availableHeight, rects: { floating } }) => {\n const maxHeight = Math.max(\n MIN_OVERLAY_HEIGHT,\n Math.floor(availableHeight)\n );\n const actualHeight = floating.height;\n this.initialHeight = !this.isConstrained // && !this.virtualTrigger\n ? actualHeight\n : this.initialHeight || actualHeight;\n this.isConstrained =\n actualHeight < this.initialHeight || maxHeight <= actualHeight;\n const appliedHeight = this.isConstrained ? `${maxHeight}px` : '';\n Object.assign(target.style, {\n maxWidth: `${Math.floor(availableWidth)}px`,\n maxHeight: appliedHeight,\n });\n },\n }),\n ...(tipElement\n ? [\n arrow({\n element: tipElement,\n padding: options.tipPadding || REQUIRED_DISTANCE_TO_EDGE,\n }),\n ]\n : []),\n ];\n\n // Compute the position of the overlay using the defined middleware.\n const { x, y, placement, middlewareData } = await computePosition(\n options.trigger,\n target,\n {\n placement: options.placement,\n middleware,\n strategy: 'fixed',\n }\n );\n\n // Update the overlay's style with the computed position.\n Object.assign(target.style, {\n top: '0px',\n left: '0px',\n translate: `${roundByDPR(x)}px ${roundByDPR(y)}px`,\n });\n\n // Set the 'actual-placement' attribute on the target element.\n target.setAttribute('actual-placement', placement);\n\n // Update the placement attribute for each host element.\n this.host.elements?.forEach((element) => {\n if (!this.originalPlacements.has(element)) {\n this.originalPlacements.set(\n element,\n element.getAttribute('placement') as Placement\n );\n }\n element.setAttribute('placement', placement);\n });\n\n // Update the tip element's style with the computed arrow position.\n if (tipElement && middlewareData.arrow) {\n const { x: arrowX, y: arrowY } = middlewareData.arrow;\n\n Object.assign(tipElement.style, {\n top:\n placement.startsWith('right') || placement.startsWith('left')\n ? '0px'\n : '',\n left:\n placement.startsWith('bottom') || placement.startsWith('top')\n ? '0px'\n : '',\n translate: `${roundByDPR(arrowX)}px ${roundByDPR(arrowY)}px`,\n });\n }\n }\n\n /**\n * Clears the overlay's position styles.\n *\n * This method removes the max-height and max-width styles from the target element,\n * and resets the initial height and constrained state of the overlay.\n */\n public clearOverlayPosition(): void {\n if (!this.target) {\n return;\n }\n // Remove max-height and max-width styles from the target element.\n this.target.style.removeProperty('max-height');\n this.target.style.removeProperty('max-width');\n // Reset the initial height and constrained state.\n this.initialHeight = undefined;\n this.isConstrained = false;\n }\n\n /**\n * Resets the overlay's position.\n *\n * This method clears the overlay's position, forces a reflow, and recomputes the placement.\n */\n public resetOverlayPosition = (): void => {\n if (!this.target || !this.options) {\n return;\n }\n // Clear the overlay's position.\n this.clearOverlayPosition();\n\n // Force a reflow.\n /** @todo investigate why this is needed and if there is a better way to do this or remove it entirely */\n // eslint-disable-next-line @typescript-eslint/no-unused-expressions\n this.host.offsetHeight;\n // Recompute the placement.\n this.computePlacement();\n };\n\n /**\n * Lifecycle method called when the host element is connected to the DOM.\n *\n * This method sets up an event listener to reset the overlay's position when the 'sp-update-overlays' event is dispatched.\n */\n hostConnected(): void {\n document.addEventListener('sp-update-overlays', this.resetOverlayPosition);\n }\n\n /**\n * Lifecycle method called when the host element is updated.\n *\n * This method cleans up resources if the overlay is not open.\n */\n hostUpdated(): void {\n if (!(this.host as Overlay).open) {\n // Clean up resources if the overlay is not open.\n this.cleanup?.();\n this.cleanup = undefined;\n }\n }\n\n /**\n * Lifecycle method called when the host element is disconnected from the DOM.\n *\n * This method removes the event listener and cleans up resources.\n */\n hostDisconnected(): void {\n // Clean up resources.\n this.cleanup?.();\n this.cleanup = undefined;\n // Remove the event listener.\n document.removeEventListener(\n 'sp-update-overlays',\n this.resetOverlayPosition\n );\n }\n}\n"],
|
|
5
|
-
"mappings": "aAYA,OACE,SAAAA,EACA,cAAAC,EACA,mBAAAC,EACA,QAAAC,EACA,UAAAC,EAEA,SAAAC,EACA,QAAAC,MACK,mBAMP,OAAS,YAAAC,MAAgB,kCAyBzB,SAASC,EAAWC,EAAsB,CACxC,GAAI,OAAOA,GAAQ,YACjB,MAAO,GAET,MAAMC,EAAM,OAAO,kBAAoB,EACvC,OAAO,KAAK,MAAMD,EAAMC,CAAG,EAAIA,CACjC,CAIA,MAAMC,EAA4B,EAG5BC,EAAqB,IAQrBC,EAAyBC,GAAsC,CAzErE,IAAAC,EAwFE,OAAOA,EAd2C,CAChD,KAAM,CAAC,QAAS,SAAU,KAAK,EAC/B,aAAc,CAAC,cAAe,SAAU,KAAK,EAC7C,WAAY,CAAC,YAAa,SAAU,KAAK,EACzC,MAAO,CAAC,OAAQ,SAAU,KAAK,EAC/B,cAAe,CAAC,aAAc,SAAU,KAAK,EAC7C,YAAa,CAAC,WAAY,SAAU,KAAK,EACzC,IAAK,CAAC,SAAU,OAAQ,OAAO,EAC/B,YAAa,CAAC,eAAgB,OAAQ,OAAO,EAC7C,UAAW,CAAC,aAAc,OAAQ,OAAO,EACzC,OAAQ,CAAC,MAAO,OAAQ,OAAO,EAC/B,eAAgB,CAAC,YAAa,OAAQ,OAAO,EAC7C,aAAc,CAAC,UAAW,OAAQ,OAAO,CAC3C,EACiBD,CAAS,IAAnB,KAAAC,EAAwB,CAACD,CAAS,CAC3C,EAKO,aAAM,uBAAyB,OAAO,mBAAmB,EAQzD,aAAM,mBAAkD,
|
|
6
|
-
"names": ["arrow", "autoUpdate", "computePosition", "flip", "offset", "shift", "size", "isWebKit", "roundByDPR", "num", "dpr", "REQUIRED_DISTANCE_TO_EDGE", "MIN_OVERLAY_HEIGHT", "getFallbackPlacements", "placement", "_a", "host", "target", "options", "cleanupAncestorResize", "cleanupElementResize", "element", "_b", "resolve", "flipMiddleware", "mainAxis", "crossAxis", "tipElement", "el", "middleware", "availableWidth", "availableHeight", "floating", "maxHeight", "actualHeight", "appliedHeight", "x", "y", "middlewareData", "arrowX", "arrowY"]
|
|
4
|
+
"sourcesContent": ["/**\n * Copyright 2026 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {\n arrow,\n autoUpdate,\n computePosition,\n flip,\n offset,\n Placement,\n shift,\n size,\n} from '@floating-ui/dom';\n\nimport type {\n ReactiveController,\n ReactiveElement,\n} from '@spectrum-web-components/base';\nimport { isWebKit } from '@spectrum-web-components/shared';\n\nimport type { Overlay } from './Overlay.js';\nimport type { OpenableElement } from './overlay-types.js';\nimport type { VirtualTrigger } from './VirtualTrigger.js';\n\ntype OverlayOptionsV1 = {\n abortPromise?: Promise<boolean>;\n delayed?: boolean;\n offset?: number | [number, number]; // supporting multi-axis\n placement: Placement;\n notImmediatelyClosable?: boolean; // rename or place behind other API options\n receivesFocus?: 'auto';\n root?: HTMLElement;\n tipPadding?: number;\n trigger: HTMLElement | VirtualTrigger;\n type?: 'modal' | 'page' | 'hint' | 'auto' | 'manual';\n};\n\n/**\n * Rounds a number by the device pixel ratio (DPR).\n *\n * @param {number} [num] - The number to round.\n * @returns {number} The rounded number.\n */\nfunction roundByDPR(num?: number): number {\n if (typeof num === 'undefined') {\n return 0;\n }\n const dpr = window.devicePixelRatio || 1;\n return Math.round(num * dpr) / dpr;\n}\n\n// Minimum distance required between the overlay and the edge of the container.\n// See: https://spectrum.adobe.com/page/popover/#Container-padding\nconst REQUIRED_DISTANCE_TO_EDGE = 8;\n// Minimum height for the overlay.\n// See: https://github.com/adobe/spectrum-web-components/issues/910\nconst MIN_OVERLAY_HEIGHT = 100;\n\n/**\n * Gets fallback placements for the overlay based on the initial placement.\n *\n * @param {Placement} placement - The initial placement of the overlay.\n * @returns {Placement[]} An array of fallback placements.\n */\nconst getFallbackPlacements = (placement: Placement): Placement[] => {\n const fallbacks: Record<Placement, Placement[]> = {\n left: ['right', 'bottom', 'top'],\n 'left-start': ['right-start', 'bottom', 'top'],\n 'left-end': ['right-end', 'bottom', 'top'],\n right: ['left', 'bottom', 'top'],\n 'right-start': ['left-start', 'bottom', 'top'],\n 'right-end': ['left-end', 'bottom', 'top'],\n top: ['bottom', 'left', 'right'],\n 'top-start': ['bottom-start', 'left', 'right'],\n 'top-end': ['bottom-end', 'left', 'right'],\n bottom: ['top', 'left', 'right'],\n 'bottom-start': ['top-start', 'left', 'right'],\n 'bottom-end': ['top-end', 'left', 'right'],\n };\n return fallbacks[placement] ?? [placement];\n};\n\n/**\n * Symbol used to indicate that the placement has been updated.\n */\nexport const placementUpdatedSymbol = Symbol('placement updated');\n\n/**\n * Controller for managing the placement of an overlay.\n *\n * This class implements the ReactiveController interface and provides methods\n * for managing the positioning and constraints of an overlay element.\n */\nexport class PlacementController implements ReactiveController {\n /**\n * Function to clean up resources when the controller is no longer needed.\n *\n * @private\n */\n private cleanup?: () => void;\n\n /**\n * Initial height of the overlay.\n *\n * @type {number}\n */\n initialHeight?: number;\n\n /**\n * Indicates whether the overlay is constrained by available space.\n *\n * @type {boolean}\n */\n isConstrained?: boolean;\n\n /**\n * The host element that uses this controller.\n *\n * @private\n * @type {ReactiveElement & { elements: OpenableElement[] }}\n */\n private host!: ReactiveElement & { elements: OpenableElement[] };\n\n /**\n * Options for configuring the overlay placement.\n *\n * @private\n * @type {OverlayOptionsV1}\n */\n private options!: OverlayOptionsV1;\n\n /**\n * A WeakMap to store the original placements of overlay elements.\n *\n * @private\n * @type {WeakMap<HTMLElement, Placement>}\n */\n private originalPlacements = new WeakMap<HTMLElement, Placement>();\n\n /**\n * The target element for the overlay.\n *\n * @private\n * @type {HTMLElement}\n */\n private target!: HTMLElement;\n\n /**\n * Incremented whenever the active placement session ends (`cleanup`) or a\n * new session begins, so async `computePlacement` runs that started under an\n * older session do not write styles after teardown or across stacked\n * `placeOverlay` calls.\n *\n * @private\n */\n private placementGeneration = 0;\n\n /**\n * Creates an instance of the PlacementController.\n *\n * @param {ReactiveElement & { elements: OpenableElement[] }} host - The host element that uses this controller.\n */\n constructor(host: ReactiveElement & { elements: OpenableElement[] }) {\n this.host = host;\n // Add the controller after the MutationObserver has been created in preparation\n // for the `hostConnected`/`hostDisconnected` callbacks to be run.\n this.host.addController(this);\n }\n\n /**\n * Places the overlay relative to the target element.\n *\n * This method sets up the necessary configurations and event listeners to manage the\n * positioning and constraints of the overlay element.\n *\n * @param {HTMLElement} [target=this.target] - The target element for the overlay.\n * @param {OverlayOptionsV1} [options=this.options] - The options for configuring the overlay placement.\n * @returns {Promise<void>} A promise that resolves when the overlay has been placed.\n */\n public async placeOverlay(\n target: HTMLElement = this.target,\n options: OverlayOptionsV1 = this.options\n ): Promise<void> {\n // If `placeOverlay` runs twice before `hostUpdated` clears the prior\n // session (rapid open, programmatic toggles), tear down the previous\n // listeners first so `visualViewport` handlers and pending rAFs cannot\n // leak.\n this.cleanup?.();\n this.cleanup = undefined;\n\n // Set the target and options for the overlay.\n this.target = target;\n this.options = options;\n if (!target || !options) {\n return;\n }\n\n // Set up auto-update for ancestor resize events.\n const cleanupAncestorResize = autoUpdate(\n options.trigger,\n target,\n this.closeForAncestorUpdate,\n {\n ancestorResize: false,\n elementResize: false,\n layoutShift: false,\n }\n );\n\n // Set up auto-update for element resize events.\n const cleanupElementResize = autoUpdate(\n options.trigger,\n target,\n this.updatePlacement,\n {\n ancestorScroll: false,\n }\n );\n\n // Recompute placement when the visual viewport diverges from the layout\n // viewport (URL bar showing/hiding, pinch-zoom, virtual keyboard, host-app\n // bottom sheets, etc.). Floating UI's `autoUpdate` does not observe\n // `window.visualViewport`, so without this an open overlay can drift away\n // from its trigger on WebKit (iOS Safari, WKWebView, and desktop Safari\n // when pinch-zoomed) until the next resize. See `computePlacement` for the\n // corresponding offset compensation.\n //\n // Listeners are passive (we never `preventDefault` in `updatePlacement`)\n // and rAF-coalesced so a burst of `resize`/`scroll` events during a URL\n // bar collapse or pinch gesture compresses to one Floating UI compute per\n // frame.\n const visualViewport = window.visualViewport;\n let visualViewportRafId = 0;\n let visualViewportPlacementCancelled = false;\n const onVisualViewportChange = (): void => {\n if (visualViewportPlacementCancelled || visualViewportRafId) {\n return;\n }\n visualViewportRafId = requestAnimationFrame(() => {\n visualViewportRafId = 0;\n if (visualViewportPlacementCancelled) {\n return;\n }\n this.updatePlacement();\n });\n };\n if (visualViewport && isWebKit()) {\n visualViewport.addEventListener('resize', onVisualViewportChange, {\n passive: true,\n });\n visualViewport.addEventListener('scroll', onVisualViewportChange, {\n passive: true,\n });\n }\n\n // Define the cleanup function to remove event listeners and reset placements.\n this.cleanup = () => {\n this.placementGeneration += 1;\n // Invalidate any `visualViewport` rAF callback scheduled before this\n // cleanup runs, so `updatePlacement` cannot start after teardown.\n visualViewportPlacementCancelled = true;\n this.host.elements?.forEach((element) => {\n element.addEventListener(\n 'sp-closed',\n () => {\n const placement = this.originalPlacements.get(element);\n\n if (placement) {\n element.setAttribute('placement', placement);\n }\n\n this.originalPlacements.delete(element);\n },\n { once: true }\n );\n });\n cleanupAncestorResize();\n cleanupElementResize();\n if (visualViewport && isWebKit()) {\n visualViewport.removeEventListener('resize', onVisualViewportChange);\n visualViewport.removeEventListener('scroll', onVisualViewportChange);\n if (visualViewportRafId) {\n cancelAnimationFrame(visualViewportRafId);\n visualViewportRafId = 0;\n }\n }\n };\n }\n\n /**\n * Flag to allow or disallow placement updates.\n *\n * @type {boolean}\n */\n public allowPlacementUpdate = false;\n\n /**\n * Closes the overlay if an ancestor element is updated.\n *\n * This method checks if placement updates are allowed and if the overlay type is not 'modal'.\n * If these conditions are met and a cleanup function is defined, it dispatches a 'close' event\n * on the target element to close the overlay.\n */\n closeForAncestorUpdate = (): void => {\n if (\n !this.allowPlacementUpdate &&\n this.options.type !== 'modal' &&\n this.cleanup\n ) {\n // Dispatch a 'close' event to close the overlay.\n this.target.dispatchEvent(new Event('close', { bubbles: true }));\n }\n\n // Reset the flag to disallow placement updates.\n this.allowPlacementUpdate = false;\n };\n\n /**\n * Updates the placement of the overlay.\n *\n * This method calls the computePlacement method to recalculate the overlay's position.\n *\n * @private\n */\n private updatePlacement = (): void => {\n this.computePlacement();\n };\n\n /**\n * Computes the placement of the overlay relative to the target element.\n *\n * This method calculates the necessary positioning and constraints for the overlay element\n * using various middleware functions. It updates the overlay's style and attributes based\n * on the computed position.\n *\n * @returns {Promise<void>} A promise that resolves when the placement has been computed.\n */\n async computePlacement(): Promise<void> {\n const { options, target } = this;\n\n const genAtStart = this.placementGeneration;\n const placementStillValid = (): boolean =>\n (this.host as Overlay).open &&\n this.placementGeneration === genAtStart &&\n !!this.target &&\n this.target === target;\n\n // Wait for document fonts to be ready before computing placement.\n await (document.fonts ? document.fonts.ready : Promise.resolve());\n if (!placementStillValid()) {\n return;\n }\n\n if (isWebKit()) {\n // Computing placement requires a frame for layout stability in WebKit\n await new Promise((resolve) => requestAnimationFrame(resolve));\n }\n if (!placementStillValid()) {\n return;\n }\n\n // Determine the flip middleware based on the type of trigger element.\n const flipMiddleware = !(options.trigger instanceof HTMLElement)\n ? flip({\n padding: REQUIRED_DISTANCE_TO_EDGE,\n fallbackPlacements: getFallbackPlacements(options.placement),\n })\n : flip();\n\n // Extract main axis and cross axis offsets from options.\n const [mainAxis = 0, crossAxis = 0] = Array.isArray(options?.offset)\n ? options.offset\n : [options.offset, 0];\n\n // Find the tip element within the host elements.\n const tipElement = this.host.elements.find(\n (el) => el.tipElement\n )?.tipElement;\n\n // Define middleware functions for positioning and constraints.\n const middleware = [\n offset({\n mainAxis,\n crossAxis,\n }),\n shift({ padding: REQUIRED_DISTANCE_TO_EDGE }),\n flipMiddleware,\n size({\n padding: REQUIRED_DISTANCE_TO_EDGE,\n apply: ({ availableWidth, availableHeight, rects: { floating } }) => {\n const maxHeight = Math.max(\n MIN_OVERLAY_HEIGHT,\n Math.floor(availableHeight)\n );\n const actualHeight = floating.height;\n this.initialHeight = !this.isConstrained // && !this.virtualTrigger\n ? actualHeight\n : this.initialHeight || actualHeight;\n this.isConstrained =\n actualHeight < this.initialHeight || maxHeight <= actualHeight;\n const appliedHeight = this.isConstrained ? `${maxHeight}px` : '';\n Object.assign(target.style, {\n maxWidth: `${Math.floor(availableWidth)}px`,\n maxHeight: appliedHeight,\n });\n },\n }),\n ...(tipElement\n ? [\n arrow({\n element: tipElement,\n padding: options.tipPadding || REQUIRED_DISTANCE_TO_EDGE,\n }),\n ]\n : []),\n ];\n\n // Compute the position of the overlay using the defined middleware.\n const { x, y, placement, middlewareData } = await computePosition(\n options.trigger,\n target,\n {\n placement: options.placement,\n middleware,\n strategy: 'fixed',\n }\n );\n if (!placementStillValid()) {\n return;\n }\n\n // On iOS WebKit (Safari and WKWebView hosts such as the Adobe Express\n // iOS app) the layout viewport and the visual viewport can diverge by\n // tens of pixels \u2014 for example when the URL bar is showing, when the\n // page is pinch-zoomed, when the virtual keyboard is open, or when a\n // native bottom sheet is overlaid. Floating UI computes `(x, y)` from\n // `getBoundingClientRect()`, which is in layout-viewport coordinates,\n // but the overlay is rendered in the top layer via the native popover\n // API and therefore painted relative to the visual viewport. Without\n // this compensation the overlay lands `visualViewport.offsetTop` px\n // below (and `offsetLeft` px to the side of) its trigger on iOS while\n // appearing correct on every other browser.\n let translateX = x;\n let translateY = y;\n const visualViewport = window.visualViewport;\n if (visualViewport && isWebKit()) {\n translateX -= visualViewport.offsetLeft;\n translateY -= visualViewport.offsetTop;\n }\n\n // Update the overlay's style with the computed position.\n if (!placementStillValid()) {\n return;\n }\n Object.assign(target.style, {\n top: '0px',\n left: '0px',\n translate: `${roundByDPR(translateX)}px ${roundByDPR(translateY)}px`,\n });\n\n // Set the 'actual-placement' attribute on the target element.\n target.setAttribute('actual-placement', placement);\n\n // Update the placement attribute for each host element.\n this.host.elements?.forEach((element) => {\n if (!this.originalPlacements.has(element)) {\n this.originalPlacements.set(\n element,\n element.getAttribute('placement') as Placement\n );\n }\n element.setAttribute('placement', placement);\n });\n\n // Update the tip element's style with the computed arrow position.\n if (!placementStillValid()) {\n return;\n }\n if (tipElement && middlewareData.arrow) {\n const { x: arrowX, y: arrowY } = middlewareData.arrow;\n\n Object.assign(tipElement.style, {\n top:\n placement.startsWith('right') || placement.startsWith('left')\n ? '0px'\n : '',\n left:\n placement.startsWith('bottom') || placement.startsWith('top')\n ? '0px'\n : '',\n translate: `${roundByDPR(arrowX)}px ${roundByDPR(arrowY)}px`,\n });\n }\n }\n\n /**\n * Clears the overlay's position styles.\n *\n * This method removes the max-height and max-width styles from the target element,\n * and resets the initial height and constrained state of the overlay.\n */\n public clearOverlayPosition(): void {\n if (!this.target) {\n return;\n }\n // Remove max-height and max-width styles from the target element.\n this.target.style.removeProperty('max-height');\n this.target.style.removeProperty('max-width');\n // Reset the initial height and constrained state.\n this.initialHeight = undefined;\n this.isConstrained = false;\n }\n\n /**\n * Resets the overlay's position.\n *\n * This method clears the overlay's position, forces a reflow, and recomputes the placement.\n */\n public resetOverlayPosition = (): void => {\n if (!this.target || !this.options) {\n return;\n }\n // Clear the overlay's position.\n this.clearOverlayPosition();\n\n // Force a reflow.\n /** @todo investigate why this is needed and if there is a better way to do this or remove it entirely */\n // eslint-disable-next-line @typescript-eslint/no-unused-expressions\n this.host.offsetHeight;\n // Recompute the placement.\n this.computePlacement();\n };\n\n /**\n * Lifecycle method called when the host element is connected to the DOM.\n *\n * This method sets up an event listener to reset the overlay's position when the 'sp-update-overlays' event is dispatched.\n */\n hostConnected(): void {\n document.addEventListener('sp-update-overlays', this.resetOverlayPosition);\n }\n\n /**\n * Lifecycle method called when the host element is updated.\n *\n * This method cleans up resources if the overlay is not open.\n */\n hostUpdated(): void {\n if (!(this.host as Overlay).open) {\n // Clean up resources if the overlay is not open.\n this.cleanup?.();\n this.cleanup = undefined;\n }\n }\n\n /**\n * Lifecycle method called when the host element is disconnected from the DOM.\n *\n * This method removes the event listener and cleans up resources.\n */\n hostDisconnected(): void {\n // Clean up resources.\n this.cleanup?.();\n this.cleanup = undefined;\n // Remove the event listener.\n document.removeEventListener(\n 'sp-update-overlays',\n this.resetOverlayPosition\n );\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["arrow", "autoUpdate", "computePosition", "flip", "offset", "shift", "size", "isWebKit", "roundByDPR", "num", "dpr", "REQUIRED_DISTANCE_TO_EDGE", "MIN_OVERLAY_HEIGHT", "getFallbackPlacements", "placement", "_a", "host", "target", "options", "cleanupAncestorResize", "cleanupElementResize", "visualViewport", "visualViewportRafId", "visualViewportPlacementCancelled", "onVisualViewportChange", "element", "_b", "genAtStart", "placementStillValid", "resolve", "flipMiddleware", "mainAxis", "crossAxis", "tipElement", "el", "middleware", "availableWidth", "availableHeight", "floating", "maxHeight", "actualHeight", "appliedHeight", "x", "y", "middlewareData", "translateX", "translateY", "arrowX", "arrowY"]
|
|
7
7
|
}
|