@adobe/spectrum-wc-core 2.0.0-beta.2 → 2.0.0-beta.3
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/CHANGELOG.md +75 -9
- package/dist/components/accordion/Accordion.base.js +28 -22
- package/dist/components/accordion/Accordion.base.js.map +1 -1
- package/dist/components/accordion/AccordionItem.base.d.ts +16 -6
- package/dist/components/accordion/AccordionItem.base.js +6 -3
- package/dist/components/accordion/AccordionItem.base.js.map +1 -1
- package/dist/components/action-group/ActionGroup.base.d.ts +108 -0
- package/dist/components/action-group/ActionGroup.base.js +53 -0
- package/dist/components/action-group/ActionGroup.base.js.map +1 -0
- package/dist/components/action-group/ActionGroup.types.d.ts +17 -0
- package/dist/components/action-group/ActionGroup.types.js +12 -0
- package/dist/components/action-group/ActionGroup.types.js.map +1 -0
- package/dist/components/action-group/index.d.ts +13 -0
- package/dist/components/action-group/index.js +3 -0
- package/dist/components/alert-banner/AlertBanner.base.js +11 -10
- package/dist/components/alert-banner/AlertBanner.base.js.map +1 -1
- package/dist/components/asset/Asset.base.d.ts +1 -1
- package/dist/components/asset/Asset.base.js +14 -8
- package/dist/components/asset/Asset.base.js.map +1 -1
- package/dist/components/avatar/Avatar.base.js +18 -22
- package/dist/components/avatar/Avatar.base.js.map +1 -1
- package/dist/components/badge/Badge.base.d.ts +24 -8
- package/dist/components/badge/Badge.base.js +22 -17
- package/dist/components/badge/Badge.base.js.map +1 -1
- package/dist/components/button/Button.base.d.ts +20 -10
- package/dist/components/button/Button.base.js +17 -12
- package/dist/components/button/Button.base.js.map +1 -1
- package/dist/components/button-group/ButtonGroup.base.js +19 -12
- package/dist/components/button-group/ButtonGroup.base.js.map +1 -1
- package/dist/components/card/Card.base.d.ts +95 -46
- package/dist/components/card/Card.base.js +71 -23
- package/dist/components/card/Card.base.js.map +1 -1
- package/dist/components/card/Card.types.d.ts +1 -0
- package/dist/components/card/Card.types.js +2 -2
- package/dist/components/card/Card.types.js.map +1 -1
- package/dist/components/card/index.js +3 -3
- package/dist/components/divider/Divider.base.js +13 -8
- package/dist/components/divider/Divider.base.js.map +1 -1
- package/dist/components/dropzone/Dropzone.base.d.ts +74 -0
- package/dist/components/dropzone/Dropzone.base.js +82 -0
- package/dist/components/dropzone/Dropzone.base.js.map +1 -0
- package/dist/components/dropzone/Dropzone.types.d.ts +43 -0
- package/dist/components/dropzone/Dropzone.types.js +15 -0
- package/dist/components/dropzone/Dropzone.types.js.map +1 -0
- package/dist/components/dropzone/index.d.ts +13 -0
- package/dist/components/dropzone/index.js +3 -0
- package/dist/components/icon/Icon.base.d.ts +11 -7
- package/dist/components/icon/Icon.base.js +13 -20
- package/dist/components/icon/Icon.base.js.map +1 -1
- package/dist/components/illustrated-message/IllustratedMessage.base.d.ts +22 -8
- package/dist/components/illustrated-message/IllustratedMessage.base.js +33 -20
- package/dist/components/illustrated-message/IllustratedMessage.base.js.map +1 -1
- package/dist/components/infield-button/InfieldButton.base.d.ts +28 -0
- package/dist/components/infield-button/InfieldButton.base.js +22 -0
- package/dist/components/infield-button/InfieldButton.base.js.map +1 -0
- package/dist/components/infield-button/InfieldButton.types.d.ts +13 -0
- package/dist/components/infield-button/InfieldButton.types.js +11 -0
- package/dist/components/infield-button/InfieldButton.types.js.map +1 -0
- package/dist/components/infield-button/index.d.ts +13 -0
- package/dist/components/infield-button/index.js +3 -0
- package/dist/components/meter/Meter.base.js +11 -9
- package/dist/components/meter/Meter.base.js.map +1 -1
- package/dist/components/popover/Popover.base.js +46 -42
- package/dist/components/popover/Popover.base.js.map +1 -1
- package/dist/components/progress-circle/ProgressCircle.base.d.ts +0 -1
- package/dist/components/progress-circle/ProgressCircle.base.js +26 -22
- package/dist/components/progress-circle/ProgressCircle.base.js.map +1 -1
- package/dist/components/status-light/StatusLight.base.d.ts +1 -1
- package/dist/components/status-light/StatusLight.base.js +12 -9
- package/dist/components/status-light/StatusLight.base.js.map +1 -1
- package/dist/components/tabs/Tabs.base.js +44 -32
- package/dist/components/tabs/Tabs.base.js.map +1 -1
- package/dist/components/tooltip/Tooltip.base.js +57 -22
- package/dist/components/tooltip/Tooltip.base.js.map +1 -1
- package/dist/controllers/color-controller/src/color-controller.js +45 -44
- package/dist/controllers/color-controller/src/color-controller.js.map +1 -1
- package/dist/controllers/drag-and-drop-controller/index.d.ts +12 -0
- package/dist/controllers/drag-and-drop-controller/index.js +2 -0
- package/dist/controllers/drag-and-drop-controller/src/drag-and-drop-controller.d.ts +68 -0
- package/dist/controllers/drag-and-drop-controller/src/drag-and-drop-controller.js +56 -0
- package/dist/controllers/drag-and-drop-controller/src/drag-and-drop-controller.js.map +1 -0
- package/dist/controllers/index.d.ts +4 -1
- package/dist/controllers/index.js +14 -11
- package/dist/controllers/page-scroll-lock-controller/index.d.ts +12 -0
- package/dist/controllers/page-scroll-lock-controller/index.js +2 -0
- package/dist/controllers/{page-scroll-lock.js → page-scroll-lock-controller/src/page-scroll-lock.js} +1 -1
- package/dist/controllers/page-scroll-lock-controller/src/page-scroll-lock.js.map +1 -0
- package/dist/controllers/slot-presence-controller/index.d.ts +12 -0
- package/dist/controllers/slot-presence-controller/index.js +2 -0
- package/dist/controllers/slot-presence-controller/src/slot-presence-controller.d.ts +57 -0
- package/dist/controllers/slot-presence-controller/src/slot-presence-controller.js +44 -0
- package/dist/controllers/slot-presence-controller/src/slot-presence-controller.js.map +1 -0
- package/dist/controllers/slot-text-controller/index.d.ts +12 -0
- package/dist/controllers/slot-text-controller/index.js +2 -0
- package/dist/controllers/slot-text-controller/src/slot-text-controller.d.ts +92 -0
- package/dist/controllers/slot-text-controller/src/slot-text-controller.js +53 -0
- package/dist/controllers/slot-text-controller/src/slot-text-controller.js.map +1 -0
- package/dist/element/index.d.ts +1 -1
- package/dist/element/index.js +2 -2
- package/dist/element/spectrum-element.d.ts +58 -15
- package/dist/element/spectrum-element.js +55 -36
- package/dist/element/spectrum-element.js.map +1 -1
- package/dist/element/version.d.ts +2 -2
- package/dist/element/version.js +1 -1
- package/dist/element/version.js.map +1 -1
- package/dist/mixins/index.d.ts +0 -2
- package/dist/mixins/index.js +4 -6
- package/dist/mixins/linear-progress-mixin.d.ts +1 -2
- package/dist/mixins/linear-progress-mixin.js +35 -34
- package/dist/mixins/linear-progress-mixin.js.map +1 -1
- package/dist/mixins/pending-mixin.js +12 -11
- package/dist/mixins/pending-mixin.js.map +1 -1
- package/dist/mixins/sized-mixin.d.ts +28 -0
- package/dist/mixins/sized-mixin.js +6 -6
- package/dist/mixins/sized-mixin.js.map +1 -1
- package/dist/utils/dev-validation.d.ts +88 -0
- package/dist/utils/dev-validation.js +33 -0
- package/dist/utils/dev-validation.js.map +1 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.js +12 -10
- package/dist/utils/is-focus-visible-in-tree.d.ts +33 -0
- package/dist/utils/is-focus-visible-in-tree.js +11 -0
- package/dist/utils/is-focus-visible-in-tree.js.map +1 -0
- package/package.json +68 -15
- package/dist/_virtual/_@oxc-project_runtime@0.124.0/helpers/defineProperty.js +0 -12
- package/dist/_virtual/_@oxc-project_runtime@0.124.0/helpers/toPrimitive.js +0 -14
- package/dist/_virtual/_@oxc-project_runtime@0.124.0/helpers/toPropertyKey.js +0 -9
- package/dist/_virtual/_@oxc-project_runtime@0.124.0/helpers/typeof.js +0 -11
- package/dist/controllers/page-scroll-lock.js.map +0 -1
- package/dist/mixins/observe-slot-presence.d.ts +0 -12
- package/dist/mixins/observe-slot-presence.js +0 -40
- package/dist/mixins/observe-slot-presence.js.map +0 -1
- package/dist/mixins/observe-slot-text.d.ts +0 -11
- package/dist/mixins/observe-slot-text.js +0 -60
- package/dist/mixins/observe-slot-text.js.map +0 -1
- /package/dist/controllers/{page-scroll-lock.d.ts → page-scroll-lock-controller/src/page-scroll-lock.d.ts} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Popover.base.js","names":[],"sources":["../../../components/popover/Popover.base.ts"],"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 { PropertyValues } from 'lit';\nimport { property } from 'lit/decorators.js';\n\nimport {\n PageScrollLockController,\n PlacementController,\n type VirtualTrigger,\n} from '@adobe/spectrum-wc-core/controllers/index.js';\nimport { SpectrumElement } from '@adobe/spectrum-wc-core/element/index.js';\nimport {\n deepContains,\n getActiveElement,\n isTopDismissible,\n physicalSide,\n registerDismissible,\n resolveTrigger,\n runAfterTransition,\n unregisterDismissible,\n} from '@adobe/spectrum-wc-core/utils/index.js';\n\nimport {\n type Placement,\n POPOVER_VALID_PLACEMENTS,\n POPOVER_VALID_SIZES,\n type PopoverCloseSource,\n type PopoverSize,\n} from './Popover.types.js';\n\n/**\n * The `aria-controls` relationship is wired via the element-reference IDL\n * (`ariaControlsElements`) so it works across shadow boundaries. The property\n * is Baseline but not yet in every TypeScript DOM lib, so it is declared here.\n */\ninterface ARIAControlsElements {\n ariaControlsElements?: readonly Element[] | null;\n}\n\n/** Properties whose change re-anchors the surface while open. */\nconst POSITIONING_PROPERTIES = [\n 'placement',\n 'offset',\n 'crossOffset',\n 'containerPadding',\n 'shouldFlip',\n 'hideArrow',\n 'tipPadding',\n 'size',\n] as const;\n\n/**\n * Abstract base for the popover component. Owns the popover's behavior: the\n * dual-mode dialog lifecycle (`showPopover()` / `showModal()`), trigger and ARIA\n * wiring, positioning through the `PlacementController`, dismissal coordination,\n * and `swc-*` event dispatch. The concrete SWC subclass adds only the styles, the\n * render template, and the shadow-DOM element getters (`internalElement`,\n * `tipElement`) it overrides.\n *\n * @slot - Popover content. Free-form; consumers slot whatever pattern they build.\n */\nexport abstract class PopoverBase extends SpectrumElement {\n /**\n * @internal\n *\n * The valid placement values for the popover. Narrowed in downstream\n * first-party subclasses per the proxy pattern.\n */\n static readonly VALID_PLACEMENTS: readonly Placement[] =\n POPOVER_VALID_PLACEMENTS;\n\n /**\n * @internal\n *\n * The valid fixed sizes for the popover.\n */\n static readonly VALID_SIZES: readonly PopoverSize[] = POPOVER_VALID_SIZES;\n\n /**\n * Whether the popover is open.\n *\n * @default false\n */\n @property({ type: Boolean, reflect: true })\n public open = false;\n\n /**\n * Opt in to blocking modal behavior (`<dialog>.showModal()`): focus trap,\n * background inert, native `role=\"dialog\"`. When unset, the popover uses\n * `popover=\"auto\"` light-dismiss behavior.\n *\n * @default false\n */\n @property({ type: Boolean, reflect: true })\n public modal = false;\n\n /**\n * Accessible name for the popover's dialog surface, forwarded as `aria-label`\n * to the internal element. Required in both modes (the surface is a dialog);\n * the component dev-warns when opened without one.\n */\n @property({ type: String, attribute: 'accessible-label' })\n public accessibleLabel = '';\n\n /**\n * The placement of the popover relative to its trigger.\n *\n * @default 'bottom'\n */\n @property({ type: String, reflect: true })\n public placement: Placement = 'bottom';\n\n /**\n * Optional fixed size. When set, the popover uses a fixed inline size\n * (`s` → 336px, `m` → 416px, `l` → 576px); when unset, it fits its contents.\n */\n @property({ type: String, reflect: true })\n public size?: PopoverSize;\n\n // The flipped placement is kept off the public property surface (a readonly\n // property is still writable at runtime and could desync from the controller).\n // It is reflected as the internal `actual-placement` host attribute for CSS\n // only, mirroring Tooltip; consumers read the requested side via `placement`.\n\n /**\n * Hide the popover's arrow (tip). The arrow is shown by default.\n *\n * @default false\n */\n @property({ type: Boolean, reflect: true, attribute: 'hide-arrow' })\n public hideArrow = false;\n\n /**\n * Main-axis offset in pixels from the trigger.\n *\n * @default 8\n */\n @property({ type: Number })\n public offset = 8;\n\n /**\n * Cross-axis offset in pixels from the trigger.\n *\n * @default 0\n */\n @property({ type: Number, attribute: 'cross-offset' })\n public crossOffset = 0;\n\n /**\n * Distance from the viewport edge for the `flip` and `shift` middleware.\n *\n * Positioning implementation detail. Set by first-party components; excluded\n * from the public API. Users are not expected to set it.\n *\n * @internal\n * @default 8\n */\n @property({ type: Number, attribute: 'container-padding' })\n public containerPadding = 8;\n\n /**\n * Allow the popover to flip to the opposite side when constrained. When\n * `false`, the popover stays in the requested placement.\n *\n * @default true\n */\n @property({ type: Boolean, reflect: true, attribute: 'should-flip' })\n public shouldFlip = true;\n\n /**\n * Minimum inset of the tip from the popover's corners, passed to the\n * `PlacementController`'s `arrow` middleware as its `padding`.\n *\n * Positioning implementation detail. Set by first-party components; excluded\n * from the public API. Users are not expected to set it.\n *\n * @internal\n * @default 8\n */\n @property({ type: Number, attribute: 'tip-padding' })\n public tipPadding = 8;\n\n /**\n * ID of the trigger element in the same document tree root.\n */\n @property({ type: String })\n public for?: string;\n\n /**\n * Direct trigger reference. Overrides `for` when both are set. Use for\n * cross-shadow-root triggers or programmatic wiring.\n */\n @property({ attribute: false })\n public triggerElement: HTMLElement | VirtualTrigger | null = null;\n\n /**\n * Suppress the automatic click-to-toggle wiring on the resolved trigger. When\n * set, control visibility through the `open` property instead. ARIA\n * relationship wiring still applies.\n *\n * @default false\n */\n @property({ type: Boolean, reflect: true })\n public manual = false;\n\n // ──────────────────────────────\n // RENDERING-LAYER HANDLES\n // ──────────────────────────────\n\n /**\n * The internal top-layer element (a `<div popover>` or a `<dialog>`) the\n * lifecycle drives. Mandatory: the SWC rendering layer must implement this to\n * return the rendered `.swc-Popover` element from the shadow DOM (it may still\n * return `null` before the first render, which the lifecycle guards against).\n */\n protected abstract get internalElement(): HTMLElement | null;\n\n /**\n * The arrow tip element passed to the `PlacementController`. Optional: returns\n * `null` in the base class (no arrow), and the SWC rendering layer overrides it\n * to return the rendered `.swc-Popover-tip` element when an arrow is shown.\n */\n protected get tipElement(): HTMLElement | null {\n return null;\n }\n\n /**\n * The arrow's height in pixels, added to the trigger gap when the arrow is\n * shown. Returns `0` in the base class; the SWC rendering layer overrides it\n * with the token-derived value so the gap stays in sync with the tip, keeping\n * the base free of any coupling to the surface's CSS.\n */\n protected get arrowHeight(): number {\n return 0;\n }\n\n // ──────────────────\n // STATE\n // ──────────────────\n\n private _placementController = new PlacementController(this);\n\n /**\n * Page-scroll lock for modal mode. Reference-counted at module scope so stacked\n * modal surfaces coordinate a single lock and restore the original overflow\n * exactly once. See {@link PageScrollLockController}.\n */\n private _scrollLock = new PageScrollLockController(this);\n\n /** The trigger's AT-facing element that receives ARIA wiring. */\n private _interactiveElement: (HTMLElement & ARIAControlsElements) | null =\n null;\n\n /** The positioning anchor (an element or a `VirtualTrigger`). */\n private _anchor: HTMLElement | VirtualTrigger | null = null;\n\n /** The element the click-to-toggle listeners are currently attached to. */\n private _clickTrigger: HTMLElement | null = null;\n\n /**\n * True between a trigger press start (`pointerdown`/`touchstart`) and its\n * `click`, so a light-dismiss inside that window is attributed to the press.\n * Both events open it, covering touch (where the dismiss can fire off\n * `touchstart` before `pointerdown`).\n */\n private _triggerPointerActive = false;\n\n /** Cancels the pending press-end listeners armed in `_onTriggerPressStart`. */\n private _pressEndAbort: AbortController | null = null;\n\n /**\n * Set when the trigger press light-dismissed an open popover (an `'outside'`\n * close observed while `_triggerPointerActive`), so the trailing `click` of\n * that same gesture is read as the close rather than a reopen.\n */\n private _dismissedByTriggerPress = false;\n\n /** Cause of the in-progress close, read when dispatching `swc-close`. */\n private _closeSource: PopoverCloseSource | null = null;\n\n /** Suppresses the open/close effect when `open` is synced from a native event. */\n private _syncingOpen = false;\n\n /**\n * Suppresses the next `swc-open` dispatch. Set when re-showing an\n * already-open popover (a `modal` toggle swaps the internal element), so the\n * mode swap does not emit a second `swc-open` with no intervening close.\n */\n private _suppressOpenEvent = false;\n\n /** Document Escape listener (default mode) used to label the close source. */\n private _escapeListener?: (event: KeyboardEvent) => void;\n\n /** Tears down the in-flight `_afterTransition` wiring (listener + fallback timer). */\n private _cancelAfterTransition?: () => void;\n\n /**\n * Set after the first render. Auto-focus on open is suppressed until then so an\n * initially-`open` popover (server-rendered or a static demo) does not steal\n * focus on mount; only an open triggered after the element is live moves focus.\n */\n private _hasCompletedFirstUpdate = false;\n\n /**\n * Set when a default-mode open should move focus into the dialog surface;\n * consumed by the first placement compute so focus lands after the surface is\n * anchored on screen (focusing it at its 0,0 reset origin would shift layout).\n * Modal mode moves focus natively via `showModal()`.\n */\n private _pendingFocusOnOpen = false;\n\n // ──────────────────\n // LIFECYCLE\n // ──────────────────\n\n public override disconnectedCallback(): void {\n super.disconnectedCallback();\n this._placementController.stop();\n this._cancelAfterTransition?.();\n unregisterDismissible(this);\n this._removeEscapeListener();\n this._scrollLock.unlock();\n this._removeTriggerListeners();\n this._clearTriggerAria();\n this._interactiveElement = null;\n this._anchor = null;\n // Focus restoration on close is handled elsewhere (default mode in\n // `_onBeforeToggle`, modal mode natively). Removing an open popover from the\n // DOM is not: the browser has already moved focus to `<body>` before this\n // runs, so there is no trigger to restore to.\n }\n\n protected override update(changedProperties: PropertyValues): void {\n if (window.__swc?.DEBUG) {\n // Validate against the static so subclasses that narrow the placement set\n // (the proxy pattern) get their own valid values checked at runtime.\n const constructor = this.constructor as typeof PopoverBase;\n if (!constructor.VALID_PLACEMENTS.includes(this.placement)) {\n window.__swc.warn(\n this,\n `<${this.localName}> element expects the \"placement\" attribute to be one of the following:`,\n 'https://spectrum-web-components.adobe.com/?path=/docs/components-popover--docs',\n {\n issues: [...constructor.VALID_PLACEMENTS],\n }\n );\n }\n }\n super.update(changedProperties);\n }\n\n protected override updated(changedProperties: PropertyValues): void {\n super.updated(changedProperties);\n\n if (\n changedProperties.has('for') ||\n changedProperties.has('triggerElement') ||\n changedProperties.has('modal') ||\n changedProperties.has('manual')\n ) {\n this._wireTrigger();\n }\n\n if (changedProperties.has('open')) {\n if (this._syncingOpen) {\n // The change came from a native event; the element is already in the\n // right state. Just consume the guard.\n this._syncingOpen = false;\n } else if (this.open) {\n this._show();\n } else {\n this._hide();\n }\n this._interactiveElement?.setAttribute(\n 'aria-expanded',\n String(this.open)\n );\n } else if (this.open && changedProperties.has('modal')) {\n // `modal` toggled while open: the render swapped the internal element\n // between a `<div popover=\"auto\">` and a `<dialog>`. Lit removed the old\n // element (the browser closes a disconnected top-layer element), so the\n // newly rendered element is present but never went through its show API.\n // Re-show so the correct mode engages (e.g. `showModal()` traps focus),\n // without re-emitting `swc-open` for a popover that never closed.\n this._show(true);\n } else if (\n this.open &&\n (this._positioningChanged(changedProperties) ||\n changedProperties.has('for') ||\n changedProperties.has('triggerElement'))\n ) {\n // Re-anchor while open when a positioning input or the trigger changes.\n this._startPositioning();\n }\n\n // First render is done: subsequent opens may move focus into the surface.\n this._hasCompletedFirstUpdate = true;\n }\n\n private _positioningChanged(changedProperties: PropertyValues): boolean {\n return POSITIONING_PROPERTIES.some((prop) => changedProperties.has(prop));\n }\n\n // ──────────────────────────\n // TRIGGER + ARIA\n // ──────────────────────────\n\n private _wireTrigger(): void {\n const { trigger, interactiveElement } = resolveTrigger(this, {\n for: this.for,\n triggerElement:\n this.triggerElement instanceof HTMLElement ? this.triggerElement : null,\n });\n\n if (!trigger && this.for && window.__swc?.DEBUG) {\n window.__swc.warn(\n this,\n `<${this.localName}> for=\"${this.for}\" did not resolve to an element in the current tree root. Check that the referenced id exists in the same document tree root.`,\n 'https://spectrum-web-components.adobe.com/?path=/docs/components-popover--docs',\n { level: 'high' }\n );\n }\n\n if (\n this._interactiveElement &&\n this._interactiveElement !== interactiveElement\n ) {\n this._clearTriggerAria();\n }\n\n this._interactiveElement = interactiveElement;\n // A `VirtualTrigger` (non-element) anchors positioning only; an element\n // trigger anchors positioning and carries ARIA.\n this._anchor =\n this.triggerElement && !(this.triggerElement instanceof HTMLElement)\n ? this.triggerElement\n : trigger;\n\n if (interactiveElement) {\n // Durable across open/close cycles; visibility is conveyed by aria-expanded.\n interactiveElement.ariaControlsElements = [this];\n interactiveElement.setAttribute('aria-expanded', String(this.open));\n // The surface is a dialog in both modes, so the trigger always signals it.\n interactiveElement.setAttribute('aria-haspopup', 'dialog');\n }\n\n // Click-to-toggle on the trigger host, unless the consumer drives `open`\n // themselves (`manual`). Listens on the host so clicks bubbling from an inner\n // button are caught. The capturing `pointerdown`/`touchstart` listeners open\n // the reopen-guard gesture window (see `_onTriggerPressStart`).\n const clickTrigger = this.manual ? null : trigger;\n if (clickTrigger !== this._clickTrigger) {\n this._removeTriggerListeners();\n if (clickTrigger) {\n clickTrigger.addEventListener(\n 'pointerdown',\n this._onTriggerPressStart,\n {\n capture: true,\n }\n );\n clickTrigger.addEventListener('touchstart', this._onTriggerPressStart, {\n capture: true,\n });\n clickTrigger.addEventListener('click', this._onTriggerClick);\n this._clickTrigger = clickTrigger;\n }\n }\n // Re-anchoring while open (trigger or positioning input changed) is driven\n // from `updated()`, so this method only wires the trigger and ARIA. Doing it\n // here too would double-start the controller when `updated()` also re-shows\n // or re-anchors in the same cycle (e.g. a `modal` toggle while open).\n }\n\n private _removeTriggerListeners(): void {\n this._clickTrigger?.removeEventListener(\n 'pointerdown',\n this._onTriggerPressStart,\n { capture: true }\n );\n this._clickTrigger?.removeEventListener(\n 'touchstart',\n this._onTriggerPressStart,\n { capture: true }\n );\n this._clickTrigger?.removeEventListener('click', this._onTriggerClick);\n this._clickTrigger = null;\n }\n\n // In the default mode, pressing the (outside) trigger while open is a native\n // light-dismiss: the browser hides the popover before the click fires. Opening\n // the gesture window at press start (capture, before the dismiss) lets\n // `_onBeforeToggle` attribute that close to the press, so `_onTriggerClick`\n // reads the trailing click as a close, not a reopen. Only sets the flag, never\n // clears `_dismissedByTriggerPress`: on touch both `pointerdown` and\n // `touchstart` fire for one press, and the second must not reset a dismissal\n // already recorded (`_onTriggerClick` clears it per gesture).\n private _onTriggerPressStart = (): void => {\n this._triggerPointerActive = true;\n // Catches a press that ends without a click (drag off the trigger, or a\n // cancelled gesture), which would otherwise leave the flag stuck true.\n this._pressEndAbort = new AbortController();\n const { signal } = this._pressEndAbort;\n document.addEventListener('pointerup', this._onTriggerPressEnd, {\n capture: true,\n once: true,\n signal,\n });\n document.addEventListener('pointercancel', this._onTriggerPressEnd, {\n capture: true,\n once: true,\n signal,\n });\n };\n\n private _onTriggerPressEnd = (event: PointerEvent): void => {\n this._pressEndAbort?.abort();\n // A same-target pointerup still gets its own click, which resets the flag\n // itself; resetting it here too would race that click's read of\n // `_dismissedByTriggerPress`. pointercancel never gets a click, so it\n // always resets.\n if (\n event.type === 'pointerup' &&\n event.composedPath().includes(this._clickTrigger as EventTarget)\n ) {\n return;\n }\n this._triggerPointerActive = false;\n };\n\n // If the press light-dismissed the popover (recorded in `_onBeforeToggle`),\n // consume this click so it does not toggle back open; otherwise toggle from the\n // live state. Keying off the real close event makes this correct with or without\n // a native dismiss (e.g. keyboard activation) and needs no timer. (`popovertarget`\n // can't reach the shadow-DOM surface across roots, so the correlation is manual.)\n private _onTriggerClick = (): void => {\n const dismissedByThisGesture = this._dismissedByTriggerPress;\n this._triggerPointerActive = false;\n this._dismissedByTriggerPress = false;\n if (dismissedByThisGesture) {\n return;\n }\n this.open = !this.open;\n };\n\n private _clearTriggerAria(): void {\n const element = this._interactiveElement;\n if (!element) {\n return;\n }\n element.ariaControlsElements = null;\n element.removeAttribute('aria-expanded');\n element.removeAttribute('aria-haspopup');\n }\n\n // Whether focus is currently within the popover's content. `deepContains`\n // crosses shadow boundaries, so focus inside a slotted custom element (e.g. a\n // button's inner control) is detected; the content is slotted, so its DOM\n // ancestors lead back to this host.\n private _isFocusWithin(): boolean {\n return deepContains(this, getActiveElement());\n }\n\n // ──────────────────────────\n // POSITIONING\n // ──────────────────────────\n\n private _startPositioning(): void {\n const floating = this.internalElement;\n if (!floating || !this._anchor) {\n // No element or no anchor to position against (e.g. the trigger was\n // changed to an unresolved id while open). Tear down any prior session so\n // the surface is not left anchored to stale geometry; clearing\n // `actual-placement` also re-gates it hidden until a valid anchor returns.\n this._placementController.stop();\n this.removeAttribute('actual-placement');\n return;\n }\n const showArrow = !this.hideArrow;\n // Clear `actual-placement` to re-gate the surface and tip for this session:\n // `start()` calls `stop()`, which resets the inline `translate` to the 0,0\n // origin until the async first compute re-anchors. The stylesheet reveals the\n // surface and tip only once `actual-placement` is present, so they stay hidden\n // through that window (and a rapid reopen during the close fade) instead of\n // painting at 0,0. Re-set by `onPlacementChange` once the session anchors.\n this.removeAttribute('actual-placement');\n // Add the arrow height to the trigger gap so the surface clears the tip on\n // every side. Applied through the controller's direction-aware main-axis\n // offset, not a CSS margin (a margin only shifts the absolutely-positioned\n // surface on its block-/inline-start sides). `arrowHeight` comes from the\n // rendering layer.\n this._placementController.start(this._anchor, floating, {\n placement: this.placement,\n offset: this.offset + (showArrow ? this.arrowHeight : 0),\n crossOffset: this.crossOffset,\n containerPadding: this.containerPadding,\n shouldFlip: this.shouldFlip,\n tipElement: showArrow ? (this.tipElement ?? undefined) : undefined,\n tipPadding: this.tipPadding,\n onPlacementChange: (next) => {\n // Expose the computed physical side as the `actual-placement` host\n // attribute for CSS: it orients the tip and, by its presence, reveals the\n // surface and tip (gated off until now so the entry fade runs from the\n // anchored position, not the 0,0 origin). The first compute of a session\n // always fires this (`stop()` resets the last-notified placement). The\n // controller skips the compute only for a 0x0 element, but the surface\n // always has border and padded chrome, so it is never zero-sized while\n // open. Not a public property; removed in `_stopPositioningWhenClosed`.\n this.setAttribute('actual-placement', physicalSide(next));\n // Now anchored and revealed: move focus in for a pending default-mode\n // open. Focusing earlier, at the 0,0 origin, would shift layout/scroll.\n if (this._pendingFocusOnOpen) {\n this._pendingFocusOnOpen = false;\n this._focusSurface();\n }\n },\n });\n }\n\n // ──────────────────\n // OPEN/CLOSE\n // ──────────────────\n\n // `reShow` is true when re-engaging the show API for a popover that is already\n // open (a `modal` toggle swaps the internal element). It suppresses a second\n // `swc-open` for a popover that never closed.\n private _show(reShow = false): void {\n const element = this.internalElement;\n if (!element) {\n return;\n }\n // The surface is a dialog in both modes, so it must have an accessible name.\n if (window.__swc?.DEBUG && !this.accessibleLabel.trim()) {\n window.__swc.warn(\n this,\n `<${this.localName}> must have an \"accessible-label\" attribute to name the dialog for assistive technology.`,\n 'https://spectrum-web-components.adobe.com/?path=/docs/components-popover--docs',\n { issues: ['accessible-label'] }\n );\n }\n // Enter the top layer first; only register listeners, the dismissible stack,\n // and positioning once the native show actually succeeds, so a failed\n // `showPopover()`/`showModal()` does not leave the component wired up for a\n // popover that never opened.\n if (this.modal) {\n const dialog = element as HTMLDialogElement;\n let shown = dialog.open;\n if (!shown) {\n // `showModal()` synchronously moves focus into the dialog, scrolling the\n // page to it, and has no `preventScroll` option. Positioning is async, so\n // the surface is still at its 0,0 origin when focus lands. Capture and\n // restore the scroll position around the call; it is synchronous, so the\n // restore is seamless (no paint between).\n const { scrollX, scrollY } = window;\n try {\n dialog.showModal();\n shown = true;\n } catch {\n shown = false;\n }\n window.scrollTo(scrollX, scrollY);\n }\n if (!shown) {\n return;\n }\n // Modal mode uses the native `<dialog>` Escape (`cancel`); drop any\n // default-mode document listener left over from a prior mode.\n this._removeEscapeListener();\n this._scrollLock.lock();\n registerDismissible(this);\n // `<dialog>` modal-mode has no native open event, so dispatch here (unless\n // this is a re-show of an already-open popover).\n if (!reShow) {\n this._dispatchOpen();\n }\n } else {\n let shown = element.matches(':popover-open');\n if (!shown) {\n // `showPopover()` fires `beforetoggle` synchronously, which dispatches\n // `swc-open`; suppress that one dispatch on a re-show.\n this._suppressOpenEvent = reShow;\n try {\n element.showPopover();\n shown = true;\n } catch {\n this._suppressOpenEvent = false;\n shown = false;\n }\n }\n if (!shown) {\n return;\n }\n // Default mode never locks scroll; release a lock left from a prior modal\n // mode (e.g. `modal` toggled false while open).\n this._scrollLock.unlock();\n registerDismissible(this);\n this._addEscapeListener();\n // Move focus into the dialog surface so assistive technology lands inside\n // it (modal mode does this natively via `showModal()`). Deferred to the\n // first placement compute so focus lands once the surface is anchored on\n // screen, not at its 0,0 reset origin. Suppressed on the initial render so\n // an initially-`open` popover does not steal focus.\n this._pendingFocusOnOpen = this._hasCompletedFirstUpdate;\n // `swc-open` is dispatched from the `beforetoggle` listener.\n }\n this._startPositioning();\n }\n\n // Move focus into the open default-mode dialog surface. The surface is a named\n // `role=\"dialog\"` element, so focusing it announces the dialog and seats the\n // user inside it; `preventScroll` because it is already anchored in the top\n // layer. Focus restoration on close is handled by `_onBeforeToggle`.\n private _focusSurface(): void {\n this.internalElement?.focus({ preventScroll: true });\n }\n\n private _hide(): void {\n const element = this.internalElement;\n if (!element) {\n return;\n }\n // Attribute a close source only when actually hiding an open element. Setting\n // it unconditionally would poison the next real close: the initial render\n // calls `_hide()` for the default `open = false`, and a stale `'programmatic'`\n // source would survive (no `beforetoggle` clears it), making the first genuine\n // light-dismiss read as non-`outside` and defeating the reopen guard.\n if (this.modal) {\n const dialog = element as HTMLDialogElement;\n if (dialog.open) {\n this._closeSource ??= 'programmatic';\n dialog.close();\n }\n } else if (element.matches(':popover-open')) {\n this._closeSource ??= 'programmatic';\n try {\n element.hidePopover();\n } catch {\n /* already hidden */\n }\n }\n }\n\n private _closeTeardown(): void {\n unregisterDismissible(this);\n this._removeEscapeListener();\n this._scrollLock.unlock();\n // `aria-expanded` is written by `updated()` on every `open` change, so it is\n // not set here. Positioning is frozen at close start (autoUpdate stopped in\n // `_dispatchClose`) and fully torn down only after the close transition (see\n // `_stopPositioningWhenClosed`), so the surface and arrow keep their position\n // and offset during the fade.\n }\n\n // Tear down positioning once the close animation has completed. Guarded by\n // `!this.open` so a rapid re-open during the fade keeps its positioning.\n private _stopPositioningWhenClosed(): void {\n if (this.open) {\n return;\n }\n this._placementController.stop();\n this.removeAttribute('actual-placement');\n }\n\n /** Set `open` without re-triggering the show/hide effect. */\n private _syncOpen(value: boolean): void {\n if (this.open === value) {\n return;\n }\n this._syncingOpen = true;\n this.open = value;\n }\n\n // ──────────────────────────────\n // NATIVE EVENT HANDLERS\n // (bound by the SWC render template)\n // ──────────────────────────────\n\n // Default mode: the popover-API lifecycle on the internal `<div>`.\n protected _onBeforeToggle = (event: ToggleEvent): void => {\n if (event.newState === 'open') {\n this._dispatchOpen();\n } else {\n const source = this._closeSource ?? 'outside';\n // Attribute an outside light-dismiss that lands during a trigger press to\n // that press, so `_onTriggerClick` reads the trailing click as the close\n // rather than a reopen.\n if (source === 'outside' && this._triggerPointerActive) {\n this._dismissedByTriggerPress = true;\n }\n // `beforetoggle` fires before the popover hides, so focus is still inside if\n // it was there. Unlike modal `<dialog>` (which restores focus natively), the\n // popover API drops focus to `<body>` when the focused content is hidden, so\n // restore it to the trigger. Gated on focus actually being inside our content\n // so an outside click that moved focus elsewhere is left alone.\n const restoreFocusToTrigger = this._isFocusWithin();\n this._syncOpen(false);\n this._dispatchClose(source);\n this._closeTeardown();\n if (restoreFocusToTrigger) {\n this._interactiveElement?.focus();\n }\n }\n };\n\n // Modal mode: Escape routes through the native `cancel` event. Honor the\n // dismissible stack so Escape dismisses the topmost layer first: if something\n // opened on top of this dialog, cancel the close and let that layer handle the\n // key. The next Escape, once this dialog is topmost, closes it.\n protected _onCancel = (event: Event): void => {\n if (!isTopDismissible(this)) {\n event.preventDefault();\n return;\n }\n this._closeSource = 'escape';\n };\n\n // Modal mode: `close` fires for Escape, backdrop-click, and programmatic close.\n protected _onClose = (): void => {\n const source = this._closeSource ?? 'programmatic';\n this._syncOpen(false);\n this._dispatchClose(source);\n this._closeTeardown();\n };\n\n // Modal mode: a pointerdown on the dialog's backdrop is an outside dismiss. The\n // backdrop targets the dialog element itself, as does its own border, so confirm\n // the point is outside the dialog box before closing; otherwise a press on the\n // 1px border would dismiss like a backdrop click.\n protected _onPointerDown = (event: PointerEvent): void => {\n const dialog = this.internalElement;\n if (!dialog || event.target !== dialog) {\n return;\n }\n const rect = dialog.getBoundingClientRect();\n const outsideDialogBox =\n event.clientX < rect.left ||\n event.clientX > rect.right ||\n event.clientY < rect.top ||\n event.clientY > rect.bottom;\n if (!outsideDialogBox) {\n return;\n }\n this._closeSource = 'outside';\n (dialog as HTMLDialogElement).close();\n };\n\n private _addEscapeListener(): void {\n if (this._escapeListener) {\n return;\n }\n this._escapeListener = (event: KeyboardEvent): void => {\n if (event.key === 'Escape' && isTopDismissible(this)) {\n this._closeSource = 'escape';\n }\n };\n document.addEventListener('keydown', this._escapeListener, {\n capture: true,\n });\n }\n\n private _removeEscapeListener(): void {\n if (!this._escapeListener) {\n return;\n }\n document.removeEventListener('keydown', this._escapeListener, {\n capture: true,\n });\n this._escapeListener = undefined;\n }\n\n // ──────────────────\n // EVENTS\n // ──────────────────\n\n private _dispatchOpen(): void {\n // A re-show of an already-open popover (modal toggle) must not emit a second\n // `swc-open`; consume the one-shot suppression set in `_show`.\n if (this._suppressOpenEvent) {\n this._suppressOpenEvent = false;\n return;\n }\n this.dispatchEvent(\n new CustomEvent('swc-open', { bubbles: true, composed: true })\n );\n // No fallback timer on open: nothing is gated on `swc-after-open`, so a\n // delayed (janky) `transitionend` must not be pre-empted by the timer.\n this._afterTransition(() => {\n this.dispatchEvent(\n new CustomEvent('swc-after-open', { bubbles: true, composed: true })\n );\n }, false);\n }\n\n private _dispatchClose(source: PopoverCloseSource): void {\n // Freeze positioning at the current location the moment the close begins.\n // `stop()` tears down the `autoUpdate` loop but leaves the inline `translate`\n // and `actual-placement` in place, so the surface fades out from where it is.\n // `beforetoggle` fires before the surface hides, so this runs before the fade.\n // Without it, a nested popover keeps auto-updating during its fade: when an\n // ancestor popover closes and its content collapses, the nested popover's\n // anchor shifts, `autoUpdate` recomputes, and it flashes to a new position\n // before disappearing. The attribute and remaining inline styles are cleared\n // after the transition in `_stopPositioningWhenClosed`.\n this._placementController.stop();\n this.dispatchEvent(\n new CustomEvent('swc-close', {\n detail: { source },\n bubbles: true,\n composed: true,\n })\n );\n this._afterTransition(() => {\n this.dispatchEvent(\n new CustomEvent('swc-after-close', { bubbles: true, composed: true })\n );\n // Positioning autoUpdate was already frozen at close start; this clears the\n // now-stale `actual-placement` attribute once the exit transition finishes.\n this._stopPositioningWhenClosed();\n });\n this._closeSource = null;\n }\n\n // Run `callback` once the internal element's transition settles (or\n // immediately when none will run). Each call supersedes the previous\n // open/close cycle's pending run, so a rapid close-then-reopen never\n // dispatches a spurious `swc-after-close` after reopening. `fallback` arms the\n // allow-discrete safety timer (default true; the close path relies on it to\n // always tear down positioning). Shared with Tooltip via `core/utils`.\n private _afterTransition(callback: () => void, fallback = true): void {\n this._cancelAfterTransition?.();\n const element = this.internalElement;\n if (!element) {\n callback();\n return;\n }\n this._cancelAfterTransition = runAfterTransition(\n element,\n () => {\n this._cancelAfterTransition = undefined;\n callback();\n },\n { fallback }\n );\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Popover.base.js","names":[],"sources":["../../../components/popover/Popover.base.ts"],"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 { PropertyValues } from 'lit';\nimport { property } from 'lit/decorators.js';\n\nimport {\n PageScrollLockController,\n PlacementController,\n type VirtualTrigger,\n} from '@adobe/spectrum-wc-core/controllers/index.js';\nimport { SpectrumElement } from '@adobe/spectrum-wc-core/element/index.js';\nimport {\n deepContains,\n getActiveElement,\n isTopDismissible,\n physicalSide,\n registerDismissible,\n resolveTrigger,\n runAfterTransition,\n unregisterDismissible,\n validateEnum,\n warnIf,\n} from '@adobe/spectrum-wc-core/utils/index.js';\n\nimport {\n type Placement,\n POPOVER_VALID_PLACEMENTS,\n POPOVER_VALID_SIZES,\n type PopoverCloseSource,\n type PopoverSize,\n} from './Popover.types.js';\n\n/**\n * The `aria-controls` relationship is wired via the element-reference IDL\n * (`ariaControlsElements`) so it works across shadow boundaries. The property\n * is Baseline but not yet in every TypeScript DOM lib, so it is declared here.\n */\ninterface ARIAControlsElements {\n ariaControlsElements?: readonly Element[] | null;\n}\n\n/** Properties whose change re-anchors the surface while open. */\nconst POSITIONING_PROPERTIES = [\n 'placement',\n 'offset',\n 'crossOffset',\n 'containerPadding',\n 'shouldFlip',\n 'hideArrow',\n 'tipPadding',\n 'size',\n] as const;\n\n/**\n * Abstract base for the popover component. Owns the popover's behavior: the\n * dual-mode dialog lifecycle (`showPopover()` / `showModal()`), trigger and ARIA\n * wiring, positioning through the `PlacementController`, dismissal coordination,\n * and `swc-*` event dispatch. The concrete SWC subclass adds only the styles, the\n * render template, and the shadow-DOM element getters (`internalElement`,\n * `tipElement`) it overrides.\n *\n * @slot - Popover content. Free-form; consumers slot whatever pattern they build.\n */\nexport abstract class PopoverBase extends SpectrumElement {\n /**\n * @internal\n *\n * The valid placement values for the popover. Narrowed in downstream\n * first-party subclasses per the proxy pattern.\n */\n static readonly VALID_PLACEMENTS: readonly Placement[] =\n POPOVER_VALID_PLACEMENTS;\n\n /**\n * @internal\n *\n * The valid fixed sizes for the popover.\n */\n static readonly VALID_SIZES: readonly PopoverSize[] = POPOVER_VALID_SIZES;\n\n /**\n * Whether the popover is open.\n *\n * @default false\n */\n @property({ type: Boolean, reflect: true })\n public open = false;\n\n /**\n * Opt in to blocking modal behavior (`<dialog>.showModal()`): focus trap,\n * background inert, native `role=\"dialog\"`. When unset, the popover uses\n * `popover=\"auto\"` light-dismiss behavior.\n *\n * @default false\n */\n @property({ type: Boolean, reflect: true })\n public modal = false;\n\n /**\n * Accessible name for the popover's dialog surface, forwarded as `aria-label`\n * to the internal element. Required in both modes (the surface is a dialog);\n * the component dev-warns when opened without one.\n */\n @property({ type: String, attribute: 'accessible-label' })\n public accessibleLabel = '';\n\n /**\n * The placement of the popover relative to its trigger.\n *\n * @default 'bottom'\n */\n @property({ type: String, reflect: true })\n public placement: Placement = 'bottom';\n\n /**\n * Optional fixed size. When set, the popover uses a fixed inline size\n * (`s` → 336px, `m` → 416px, `l` → 576px); when unset, it fits its contents.\n */\n @property({ type: String, reflect: true })\n public size?: PopoverSize;\n\n // The flipped placement is kept off the public property surface (a readonly\n // property is still writable at runtime and could desync from the controller).\n // It is reflected as the internal `actual-placement` host attribute for CSS\n // only, mirroring Tooltip; consumers read the requested side via `placement`.\n\n /**\n * Hide the popover's arrow (tip). The arrow is shown by default.\n *\n * @default false\n */\n @property({ type: Boolean, reflect: true, attribute: 'hide-arrow' })\n public hideArrow = false;\n\n /**\n * Main-axis offset in pixels from the trigger.\n *\n * @default 8\n */\n @property({ type: Number })\n public offset = 8;\n\n /**\n * Cross-axis offset in pixels from the trigger.\n *\n * @default 0\n */\n @property({ type: Number, attribute: 'cross-offset' })\n public crossOffset = 0;\n\n /**\n * Distance from the viewport edge for the `flip` and `shift` middleware.\n *\n * Positioning implementation detail. Set by first-party components; excluded\n * from the public API. Users are not expected to set it.\n *\n * @internal\n * @default 8\n */\n @property({ type: Number, attribute: 'container-padding' })\n public containerPadding = 8;\n\n /**\n * Allow the popover to flip to the opposite side when constrained. When\n * `false`, the popover stays in the requested placement.\n *\n * @default true\n */\n @property({ type: Boolean, reflect: true, attribute: 'should-flip' })\n public shouldFlip = true;\n\n /**\n * Minimum inset of the tip from the popover's corners, passed to the\n * `PlacementController`'s `arrow` middleware as its `padding`.\n *\n * Positioning implementation detail. Set by first-party components; excluded\n * from the public API. Users are not expected to set it.\n *\n * @internal\n * @default 8\n */\n @property({ type: Number, attribute: 'tip-padding' })\n public tipPadding = 8;\n\n /**\n * ID of the trigger element in the same document tree root.\n */\n @property({ type: String })\n public for?: string;\n\n /**\n * Direct trigger reference. Overrides `for` when both are set. Use for\n * cross-shadow-root triggers or programmatic wiring.\n */\n @property({ attribute: false })\n public triggerElement: HTMLElement | VirtualTrigger | null = null;\n\n /**\n * Suppress the automatic click-to-toggle wiring on the resolved trigger. When\n * set, control visibility through the `open` property instead. ARIA\n * relationship wiring still applies.\n *\n * @default false\n */\n @property({ type: Boolean, reflect: true })\n public manual = false;\n\n // ──────────────────────────────\n // RENDERING-LAYER HANDLES\n // ──────────────────────────────\n\n /**\n * The internal top-layer element (a `<div popover>` or a `<dialog>`) the\n * lifecycle drives. Mandatory: the SWC rendering layer must implement this to\n * return the rendered `.swc-Popover` element from the shadow DOM (it may still\n * return `null` before the first render, which the lifecycle guards against).\n */\n protected abstract get internalElement(): HTMLElement | null;\n\n /**\n * The arrow tip element passed to the `PlacementController`. Optional: returns\n * `null` in the base class (no arrow), and the SWC rendering layer overrides it\n * to return the rendered `.swc-Popover-tip` element when an arrow is shown.\n */\n protected get tipElement(): HTMLElement | null {\n return null;\n }\n\n /**\n * The arrow's height in pixels, added to the trigger gap when the arrow is\n * shown. Returns `0` in the base class; the SWC rendering layer overrides it\n * with the token-derived value so the gap stays in sync with the tip, keeping\n * the base free of any coupling to the surface's CSS.\n */\n protected get arrowHeight(): number {\n return 0;\n }\n\n // ──────────────────\n // STATE\n // ──────────────────\n\n private _placementController = new PlacementController(this);\n\n /**\n * Page-scroll lock for modal mode. Reference-counted at module scope so stacked\n * modal surfaces coordinate a single lock and restore the original overflow\n * exactly once. See {@link PageScrollLockController}.\n */\n private _scrollLock = new PageScrollLockController(this);\n\n /** The trigger's AT-facing element that receives ARIA wiring. */\n private _interactiveElement: (HTMLElement & ARIAControlsElements) | null =\n null;\n\n /** The positioning anchor (an element or a `VirtualTrigger`). */\n private _anchor: HTMLElement | VirtualTrigger | null = null;\n\n /** The element the click-to-toggle listeners are currently attached to. */\n private _clickTrigger: HTMLElement | null = null;\n\n /**\n * True between a trigger press start (`pointerdown`/`touchstart`) and its\n * `click`, so a light-dismiss inside that window is attributed to the press.\n * Both events open it, covering touch (where the dismiss can fire off\n * `touchstart` before `pointerdown`).\n */\n private _triggerPointerActive = false;\n\n /** Cancels the pending press-end listeners armed in `_onTriggerPressStart`. */\n private _pressEndAbort: AbortController | null = null;\n\n /**\n * Set when the trigger press light-dismissed an open popover (an `'outside'`\n * close observed while `_triggerPointerActive`), so the trailing `click` of\n * that same gesture is read as the close rather than a reopen.\n */\n private _dismissedByTriggerPress = false;\n\n /** Cause of the in-progress close, read when dispatching `swc-close`. */\n private _closeSource: PopoverCloseSource | null = null;\n\n /** Suppresses the open/close effect when `open` is synced from a native event. */\n private _syncingOpen = false;\n\n /**\n * Suppresses the next `swc-open` dispatch. Set when re-showing an\n * already-open popover (a `modal` toggle swaps the internal element), so the\n * mode swap does not emit a second `swc-open` with no intervening close.\n */\n private _suppressOpenEvent = false;\n\n /** Document Escape listener (default mode) used to label the close source. */\n private _escapeListener?: (event: KeyboardEvent) => void;\n\n /** Tears down the in-flight `_afterTransition` wiring (listener + fallback timer). */\n private _cancelAfterTransition?: () => void;\n\n /**\n * Set after the first render. Auto-focus on open is suppressed until then so an\n * initially-`open` popover (server-rendered or a static demo) does not steal\n * focus on mount; only an open triggered after the element is live moves focus.\n */\n private _hasCompletedFirstUpdate = false;\n\n /**\n * Set when a default-mode open should move focus into the dialog surface;\n * consumed by the first placement compute so focus lands after the surface is\n * anchored on screen (focusing it at its 0,0 reset origin would shift layout).\n * Modal mode moves focus natively via `showModal()`.\n */\n private _pendingFocusOnOpen = false;\n\n // ──────────────────\n // LIFECYCLE\n // ──────────────────\n\n public override disconnectedCallback(): void {\n super.disconnectedCallback();\n this._placementController.stop();\n this._cancelAfterTransition?.();\n unregisterDismissible(this);\n this._removeEscapeListener();\n this._scrollLock.unlock();\n this._removeTriggerListeners();\n this._clearTriggerAria();\n this._interactiveElement = null;\n this._anchor = null;\n // Focus restoration on close is handled elsewhere (default mode in\n // `_onBeforeToggle`, modal mode natively). Removing an open popover from the\n // DOM is not: the browser has already moved focus to `<body>` before this\n // runs, so there is no trigger to restore to.\n }\n\n protected override update(changedProperties: PropertyValues): void {\n // Validate against the static so subclasses that narrow the placement set\n // (the proxy pattern) get their own valid values checked at runtime.\n const constructor = this.constructor as typeof PopoverBase;\n validateEnum(this, {\n prop: 'placement',\n value: this.placement,\n valid: constructor.VALID_PLACEMENTS,\n url: 'https://spectrum-web-components.adobe.com/?path=/docs/components-popover--docs',\n });\n if (this.size !== undefined) {\n validateEnum(this, {\n prop: 'size',\n value: this.size,\n valid: constructor.VALID_SIZES,\n url: 'https://spectrum-web-components.adobe.com/?path=/docs/components-popover--docs',\n });\n }\n super.update(changedProperties);\n }\n\n protected override updated(changedProperties: PropertyValues): void {\n super.updated(changedProperties);\n\n if (\n changedProperties.has('for') ||\n changedProperties.has('triggerElement') ||\n changedProperties.has('modal') ||\n changedProperties.has('manual')\n ) {\n this._wireTrigger();\n }\n\n if (changedProperties.has('open')) {\n if (this._syncingOpen) {\n // The change came from a native event; the element is already in the\n // right state. Just consume the guard.\n this._syncingOpen = false;\n } else if (this.open) {\n this._show();\n } else {\n this._hide();\n }\n this._interactiveElement?.setAttribute(\n 'aria-expanded',\n String(this.open)\n );\n } else if (this.open && changedProperties.has('modal')) {\n // `modal` toggled while open: the render swapped the internal element\n // between a `<div popover=\"auto\">` and a `<dialog>`. Lit removed the old\n // element (the browser closes a disconnected top-layer element), so the\n // newly rendered element is present but never went through its show API.\n // Re-show so the correct mode engages (e.g. `showModal()` traps focus),\n // without re-emitting `swc-open` for a popover that never closed.\n this._show(true);\n } else if (\n this.open &&\n (this._positioningChanged(changedProperties) ||\n changedProperties.has('for') ||\n changedProperties.has('triggerElement'))\n ) {\n // Re-anchor while open when a positioning input or the trigger changes.\n this._startPositioning();\n }\n\n // First render is done: subsequent opens may move focus into the surface.\n this._hasCompletedFirstUpdate = true;\n }\n\n private _positioningChanged(changedProperties: PropertyValues): boolean {\n return POSITIONING_PROPERTIES.some((prop) => changedProperties.has(prop));\n }\n\n // ──────────────────────────\n // TRIGGER + ARIA\n // ──────────────────────────\n\n private _wireTrigger(): void {\n const { trigger, interactiveElement } = resolveTrigger(this, {\n for: this.for,\n triggerElement:\n this.triggerElement instanceof HTMLElement ? this.triggerElement : null,\n });\n\n warnIf(\n this,\n !trigger && Boolean(this.for),\n `<${this.localName}> for=\"${this.for}\" did not resolve to an element in the current tree root. Check that the referenced id exists in the same document tree root.`,\n 'https://spectrum-web-components.adobe.com/?path=/docs/components-popover--docs',\n { level: 'high' }\n );\n\n if (\n this._interactiveElement &&\n this._interactiveElement !== interactiveElement\n ) {\n this._clearTriggerAria();\n }\n\n this._interactiveElement = interactiveElement;\n // A `VirtualTrigger` (non-element) anchors positioning only; an element\n // trigger anchors positioning and carries ARIA.\n this._anchor =\n this.triggerElement && !(this.triggerElement instanceof HTMLElement)\n ? this.triggerElement\n : trigger;\n\n if (interactiveElement) {\n // Durable across open/close cycles; visibility is conveyed by aria-expanded.\n interactiveElement.ariaControlsElements = [this];\n interactiveElement.setAttribute('aria-expanded', String(this.open));\n // The surface is a dialog in both modes, so the trigger always signals it.\n interactiveElement.setAttribute('aria-haspopup', 'dialog');\n }\n\n // Click-to-toggle on the trigger host, unless the consumer drives `open`\n // themselves (`manual`). Listens on the host so clicks bubbling from an inner\n // button are caught. The capturing `pointerdown`/`touchstart` listeners open\n // the reopen-guard gesture window (see `_onTriggerPressStart`).\n const clickTrigger = this.manual ? null : trigger;\n if (clickTrigger !== this._clickTrigger) {\n this._removeTriggerListeners();\n if (clickTrigger) {\n clickTrigger.addEventListener(\n 'pointerdown',\n this._onTriggerPressStart,\n {\n capture: true,\n }\n );\n clickTrigger.addEventListener('touchstart', this._onTriggerPressStart, {\n capture: true,\n });\n clickTrigger.addEventListener('click', this._onTriggerClick);\n this._clickTrigger = clickTrigger;\n }\n }\n // Re-anchoring while open (trigger or positioning input changed) is driven\n // from `updated()`, so this method only wires the trigger and ARIA. Doing it\n // here too would double-start the controller when `updated()` also re-shows\n // or re-anchors in the same cycle (e.g. a `modal` toggle while open).\n }\n\n private _removeTriggerListeners(): void {\n this._clickTrigger?.removeEventListener(\n 'pointerdown',\n this._onTriggerPressStart,\n { capture: true }\n );\n this._clickTrigger?.removeEventListener(\n 'touchstart',\n this._onTriggerPressStart,\n { capture: true }\n );\n this._clickTrigger?.removeEventListener('click', this._onTriggerClick);\n this._clickTrigger = null;\n }\n\n // In the default mode, pressing the (outside) trigger while open is a native\n // light-dismiss: the browser hides the popover before the click fires. Opening\n // the gesture window at press start (capture, before the dismiss) lets\n // `_onBeforeToggle` attribute that close to the press, so `_onTriggerClick`\n // reads the trailing click as a close, not a reopen. Only sets the flag, never\n // clears `_dismissedByTriggerPress`: on touch both `pointerdown` and\n // `touchstart` fire for one press, and the second must not reset a dismissal\n // already recorded (`_onTriggerClick` clears it per gesture).\n private _onTriggerPressStart = (): void => {\n this._triggerPointerActive = true;\n // Catches a press that ends without a click (drag off the trigger, or a\n // cancelled gesture), which would otherwise leave the flag stuck true.\n this._pressEndAbort = new AbortController();\n const { signal } = this._pressEndAbort;\n document.addEventListener('pointerup', this._onTriggerPressEnd, {\n capture: true,\n once: true,\n signal,\n });\n document.addEventListener('pointercancel', this._onTriggerPressEnd, {\n capture: true,\n once: true,\n signal,\n });\n };\n\n private _onTriggerPressEnd = (event: PointerEvent): void => {\n this._pressEndAbort?.abort();\n // A same-target pointerup still gets its own click, which resets the flag\n // itself; resetting it here too would race that click's read of\n // `_dismissedByTriggerPress`. pointercancel never gets a click, so it\n // always resets.\n if (\n event.type === 'pointerup' &&\n event.composedPath().includes(this._clickTrigger as EventTarget)\n ) {\n return;\n }\n this._triggerPointerActive = false;\n };\n\n // If the press light-dismissed the popover (recorded in `_onBeforeToggle`),\n // consume this click so it does not toggle back open; otherwise toggle from the\n // live state. Keying off the real close event makes this correct with or without\n // a native dismiss (e.g. keyboard activation) and needs no timer. (`popovertarget`\n // can't reach the shadow-DOM surface across roots, so the correlation is manual.)\n private _onTriggerClick = (): void => {\n const dismissedByThisGesture = this._dismissedByTriggerPress;\n this._triggerPointerActive = false;\n this._dismissedByTriggerPress = false;\n if (dismissedByThisGesture) {\n return;\n }\n this.open = !this.open;\n };\n\n private _clearTriggerAria(): void {\n const element = this._interactiveElement;\n if (!element) {\n return;\n }\n element.ariaControlsElements = null;\n element.removeAttribute('aria-expanded');\n element.removeAttribute('aria-haspopup');\n }\n\n // Whether focus is currently within the popover's content. `deepContains`\n // crosses shadow boundaries, so focus inside a slotted custom element (e.g. a\n // button's inner control) is detected; the content is slotted, so its DOM\n // ancestors lead back to this host.\n private _isFocusWithin(): boolean {\n return deepContains(this, getActiveElement());\n }\n\n // ──────────────────────────\n // POSITIONING\n // ──────────────────────────\n\n private _startPositioning(): void {\n const floating = this.internalElement;\n if (!floating || !this._anchor) {\n // No element or no anchor to position against (e.g. the trigger was\n // changed to an unresolved id while open). Tear down any prior session so\n // the surface is not left anchored to stale geometry; clearing\n // `actual-placement` also re-gates it hidden until a valid anchor returns.\n this._placementController.stop();\n this.removeAttribute('actual-placement');\n return;\n }\n const showArrow = !this.hideArrow;\n // Clear `actual-placement` to re-gate the surface and tip for this session:\n // `start()` calls `stop()`, which resets the inline `translate` to the 0,0\n // origin until the async first compute re-anchors. The stylesheet reveals the\n // surface and tip only once `actual-placement` is present, so they stay hidden\n // through that window (and a rapid reopen during the close fade) instead of\n // painting at 0,0. Re-set by `onPlacementChange` once the session anchors.\n this.removeAttribute('actual-placement');\n // Add the arrow height to the trigger gap so the surface clears the tip on\n // every side. Applied through the controller's direction-aware main-axis\n // offset, not a CSS margin (a margin only shifts the absolutely-positioned\n // surface on its block-/inline-start sides). `arrowHeight` comes from the\n // rendering layer.\n this._placementController.start(this._anchor, floating, {\n placement: this.placement,\n offset: this.offset + (showArrow ? this.arrowHeight : 0),\n crossOffset: this.crossOffset,\n containerPadding: this.containerPadding,\n shouldFlip: this.shouldFlip,\n tipElement: showArrow ? (this.tipElement ?? undefined) : undefined,\n tipPadding: this.tipPadding,\n onPlacementChange: (next) => {\n // Expose the computed physical side as the `actual-placement` host\n // attribute for CSS: it orients the tip and, by its presence, reveals the\n // surface and tip (gated off until now so the entry fade runs from the\n // anchored position, not the 0,0 origin). The first compute of a session\n // always fires this (`stop()` resets the last-notified placement). The\n // controller skips the compute only for a 0x0 element, but the surface\n // always has border and padded chrome, so it is never zero-sized while\n // open. Not a public property; removed in `_stopPositioningWhenClosed`.\n this.setAttribute('actual-placement', physicalSide(next));\n // Now anchored and revealed: move focus in for a pending default-mode\n // open. Focusing earlier, at the 0,0 origin, would shift layout/scroll.\n if (this._pendingFocusOnOpen) {\n this._pendingFocusOnOpen = false;\n this._focusSurface();\n }\n },\n });\n }\n\n // ──────────────────\n // OPEN/CLOSE\n // ──────────────────\n\n // `reShow` is true when re-engaging the show API for a popover that is already\n // open (a `modal` toggle swaps the internal element). It suppresses a second\n // `swc-open` for a popover that never closed.\n private _show(reShow = false): void {\n const element = this.internalElement;\n if (!element) {\n return;\n }\n // The surface is a dialog in both modes, so it must have an accessible name.\n warnIf(\n this,\n !this.accessibleLabel.trim(),\n `<${this.localName}> must have an \"accessible-label\" attribute to name the dialog for assistive technology.`,\n 'https://spectrum-web-components.adobe.com/?path=/docs/components-popover--docs',\n { issues: ['accessible-label'] }\n );\n // Enter the top layer first; only register listeners, the dismissible stack,\n // and positioning once the native show actually succeeds, so a failed\n // `showPopover()`/`showModal()` does not leave the component wired up for a\n // popover that never opened.\n if (this.modal) {\n const dialog = element as HTMLDialogElement;\n let shown = dialog.open;\n if (!shown) {\n // `showModal()` synchronously moves focus into the dialog, scrolling the\n // page to it, and has no `preventScroll` option. Positioning is async, so\n // the surface is still at its 0,0 origin when focus lands. Capture and\n // restore the scroll position around the call; it is synchronous, so the\n // restore is seamless (no paint between).\n const { scrollX, scrollY } = window;\n try {\n dialog.showModal();\n shown = true;\n } catch {\n shown = false;\n }\n window.scrollTo(scrollX, scrollY);\n }\n if (!shown) {\n return;\n }\n // Modal mode uses the native `<dialog>` Escape (`cancel`); drop any\n // default-mode document listener left over from a prior mode.\n this._removeEscapeListener();\n this._scrollLock.lock();\n registerDismissible(this);\n // `<dialog>` modal-mode has no native open event, so dispatch here (unless\n // this is a re-show of an already-open popover).\n if (!reShow) {\n this._dispatchOpen();\n }\n } else {\n let shown = element.matches(':popover-open');\n if (!shown) {\n // `showPopover()` fires `beforetoggle` synchronously, which dispatches\n // `swc-open`; suppress that one dispatch on a re-show.\n this._suppressOpenEvent = reShow;\n try {\n element.showPopover();\n shown = true;\n } catch {\n this._suppressOpenEvent = false;\n shown = false;\n }\n }\n if (!shown) {\n return;\n }\n // Default mode never locks scroll; release a lock left from a prior modal\n // mode (e.g. `modal` toggled false while open).\n this._scrollLock.unlock();\n registerDismissible(this);\n this._addEscapeListener();\n // Move focus into the dialog surface so assistive technology lands inside\n // it (modal mode does this natively via `showModal()`). Deferred to the\n // first placement compute so focus lands once the surface is anchored on\n // screen, not at its 0,0 reset origin. Suppressed on the initial render so\n // an initially-`open` popover does not steal focus.\n this._pendingFocusOnOpen = this._hasCompletedFirstUpdate;\n // `swc-open` is dispatched from the `beforetoggle` listener.\n }\n this._startPositioning();\n }\n\n // Move focus into the open default-mode dialog surface. The surface is a named\n // `role=\"dialog\"` element, so focusing it announces the dialog and seats the\n // user inside it; `preventScroll` because it is already anchored in the top\n // layer. Focus restoration on close is handled by `_onBeforeToggle`.\n private _focusSurface(): void {\n this.internalElement?.focus({ preventScroll: true });\n }\n\n private _hide(): void {\n const element = this.internalElement;\n if (!element) {\n return;\n }\n // Attribute a close source only when actually hiding an open element. Setting\n // it unconditionally would poison the next real close: the initial render\n // calls `_hide()` for the default `open = false`, and a stale `'programmatic'`\n // source would survive (no `beforetoggle` clears it), making the first genuine\n // light-dismiss read as non-`outside` and defeating the reopen guard.\n if (this.modal) {\n const dialog = element as HTMLDialogElement;\n if (dialog.open) {\n this._closeSource ??= 'programmatic';\n dialog.close();\n }\n } else if (element.matches(':popover-open')) {\n this._closeSource ??= 'programmatic';\n try {\n element.hidePopover();\n } catch {\n /* already hidden */\n }\n }\n }\n\n private _closeTeardown(): void {\n unregisterDismissible(this);\n this._removeEscapeListener();\n this._scrollLock.unlock();\n // `aria-expanded` is written by `updated()` on every `open` change, so it is\n // not set here. Positioning is frozen at close start (autoUpdate stopped in\n // `_dispatchClose`) and fully torn down only after the close transition (see\n // `_stopPositioningWhenClosed`), so the surface and arrow keep their position\n // and offset during the fade.\n }\n\n // Tear down positioning once the close animation has completed. Guarded by\n // `!this.open` so a rapid re-open during the fade keeps its positioning.\n private _stopPositioningWhenClosed(): void {\n if (this.open) {\n return;\n }\n this._placementController.stop();\n this.removeAttribute('actual-placement');\n }\n\n /** Set `open` without re-triggering the show/hide effect. */\n private _syncOpen(value: boolean): void {\n if (this.open === value) {\n return;\n }\n this._syncingOpen = true;\n this.open = value;\n }\n\n // ──────────────────────────────\n // NATIVE EVENT HANDLERS\n // (bound by the SWC render template)\n // ──────────────────────────────\n\n // Default mode: the popover-API lifecycle on the internal `<div>`.\n protected _onBeforeToggle = (event: ToggleEvent): void => {\n if (event.newState === 'open') {\n this._dispatchOpen();\n } else {\n const source = this._closeSource ?? 'outside';\n // Attribute an outside light-dismiss that lands during a trigger press to\n // that press, so `_onTriggerClick` reads the trailing click as the close\n // rather than a reopen.\n if (source === 'outside' && this._triggerPointerActive) {\n this._dismissedByTriggerPress = true;\n }\n // `beforetoggle` fires before the popover hides, so focus is still inside if\n // it was there. Unlike modal `<dialog>` (which restores focus natively), the\n // popover API drops focus to `<body>` when the focused content is hidden, so\n // restore it to the trigger. Gated on focus actually being inside our content\n // so an outside click that moved focus elsewhere is left alone.\n const restoreFocusToTrigger = this._isFocusWithin();\n this._syncOpen(false);\n this._dispatchClose(source);\n this._closeTeardown();\n if (restoreFocusToTrigger) {\n // `preventScroll` so restoring focus does not scroll a trigger that the\n // user scrolled out of view back into it (matches `_focusSurface`).\n this._interactiveElement?.focus({ preventScroll: true });\n }\n }\n };\n\n // Modal mode: Escape routes through the native `cancel` event. Honor the\n // dismissible stack so Escape dismisses the topmost layer first: if something\n // opened on top of this dialog, cancel the close and let that layer handle the\n // key. The next Escape, once this dialog is topmost, closes it.\n protected _onCancel = (event: Event): void => {\n if (!isTopDismissible(this)) {\n event.preventDefault();\n return;\n }\n this._closeSource = 'escape';\n };\n\n // Modal mode: `close` fires for Escape, backdrop-click, and programmatic close.\n protected _onClose = (): void => {\n const source = this._closeSource ?? 'programmatic';\n this._syncOpen(false);\n this._dispatchClose(source);\n this._closeTeardown();\n };\n\n // Modal mode: a pointerdown on the dialog's backdrop is an outside dismiss. The\n // backdrop targets the dialog element itself, as does its own border, so confirm\n // the point is outside the dialog box before closing; otherwise a press on the\n // 1px border would dismiss like a backdrop click.\n protected _onPointerDown = (event: PointerEvent): void => {\n const dialog = this.internalElement;\n if (!dialog || event.target !== dialog) {\n return;\n }\n const rect = dialog.getBoundingClientRect();\n const outsideDialogBox =\n event.clientX < rect.left ||\n event.clientX > rect.right ||\n event.clientY < rect.top ||\n event.clientY > rect.bottom;\n if (!outsideDialogBox) {\n return;\n }\n this._closeSource = 'outside';\n (dialog as HTMLDialogElement).close();\n };\n\n private _addEscapeListener(): void {\n if (this._escapeListener) {\n return;\n }\n this._escapeListener = (event: KeyboardEvent): void => {\n if (event.key === 'Escape' && isTopDismissible(this)) {\n this._closeSource = 'escape';\n }\n };\n document.addEventListener('keydown', this._escapeListener, {\n capture: true,\n });\n }\n\n private _removeEscapeListener(): void {\n if (!this._escapeListener) {\n return;\n }\n document.removeEventListener('keydown', this._escapeListener, {\n capture: true,\n });\n this._escapeListener = undefined;\n }\n\n // ──────────────────\n // EVENTS\n // ──────────────────\n\n private _dispatchOpen(): void {\n // A re-show of an already-open popover (modal toggle) must not emit a second\n // `swc-open`; consume the one-shot suppression set in `_show`.\n if (this._suppressOpenEvent) {\n this._suppressOpenEvent = false;\n return;\n }\n this.dispatchEvent(\n new CustomEvent('swc-open', { bubbles: true, composed: true })\n );\n // No fallback timer on open: nothing is gated on `swc-after-open`, so a\n // delayed (janky) `transitionend` must not be pre-empted by the timer.\n this._afterTransition(() => {\n this.dispatchEvent(\n new CustomEvent('swc-after-open', { bubbles: true, composed: true })\n );\n }, false);\n }\n\n private _dispatchClose(source: PopoverCloseSource): void {\n // Freeze positioning at the current location the moment the close begins.\n // `stop()` tears down the `autoUpdate` loop but leaves the inline `translate`\n // and `actual-placement` in place, so the surface fades out from where it is.\n // `beforetoggle` fires before the surface hides, so this runs before the fade.\n // Without it, a nested popover keeps auto-updating during its fade: when an\n // ancestor popover closes and its content collapses, the nested popover's\n // anchor shifts, `autoUpdate` recomputes, and it flashes to a new position\n // before disappearing. The attribute and remaining inline styles are cleared\n // after the transition in `_stopPositioningWhenClosed`.\n this._placementController.stop();\n this.dispatchEvent(\n new CustomEvent('swc-close', {\n detail: { source },\n bubbles: true,\n composed: true,\n })\n );\n this._afterTransition(() => {\n this.dispatchEvent(\n new CustomEvent('swc-after-close', { bubbles: true, composed: true })\n );\n // Positioning autoUpdate was already frozen at close start; this clears the\n // now-stale `actual-placement` attribute once the exit transition finishes.\n this._stopPositioningWhenClosed();\n });\n this._closeSource = null;\n }\n\n // Run `callback` once the internal element's transition settles (or\n // immediately when none will run). Each call supersedes the previous\n // open/close cycle's pending run, so a rapid close-then-reopen never\n // dispatches a spurious `swc-after-close` after reopening. `fallback` arms the\n // allow-discrete safety timer (default true; the close path relies on it to\n // always tear down positioning). Shared with Tooltip via `core/utils`.\n private _afterTransition(callback: () => void, fallback = true): void {\n this._cancelAfterTransition?.();\n const element = this.internalElement;\n if (!element) {\n callback();\n return;\n }\n this._cancelAfterTransition = runAfterTransition(\n element,\n () => {\n this._cancelAfterTransition = undefined;\n callback();\n },\n { fallback }\n );\n }\n}\n"],"mappings":"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"}
|
|
@@ -76,7 +76,6 @@ export declare abstract class ProgressCircleBase extends ProgressCircleBase_base
|
|
|
76
76
|
private static clampProgress;
|
|
77
77
|
private formatProgress;
|
|
78
78
|
private warnDeprecatedLightDomChildren;
|
|
79
|
-
private warnMissingAccessibleName;
|
|
80
79
|
protected willUpdate(changes: PropertyValues): void;
|
|
81
80
|
protected firstUpdated(changes: PropertyValues): void;
|
|
82
81
|
protected updated(changes: PropertyValues): void;
|
|
@@ -3,11 +3,12 @@ import { PROGRESS_CIRCLE_VALID_SIZES as t } from "./ProgressCircle.types.js";
|
|
|
3
3
|
import { property as n } from "lit/decorators.js";
|
|
4
4
|
import { SpectrumElement as r } from "@adobe/spectrum-wc-core/element/index.js";
|
|
5
5
|
import { SizedMixin as i } from "@adobe/spectrum-wc-core/mixins/index.js";
|
|
6
|
-
import {
|
|
6
|
+
import { isDebug as a, validateEnum as o, warnIf as s } from "@adobe/spectrum-wc-core/utils/index.js";
|
|
7
|
+
import { LanguageResolutionController as c, languageResolverUpdatedSymbol as l } from "@adobe/spectrum-wc-core/controllers/language-resolution.js";
|
|
7
8
|
//#region components/progress-circle/ProgressCircle.base.ts
|
|
8
|
-
var
|
|
9
|
+
var u, d = class e extends i(r, { validSizes: t }) {
|
|
9
10
|
constructor(...e) {
|
|
10
|
-
super(...e), this.label = "", this.progress = null, this.languageResolver = new
|
|
11
|
+
super(...e), this.label = "", this.progress = null, this.languageResolver = new c(this);
|
|
11
12
|
}
|
|
12
13
|
static hasMeaningfulLightDomChildren(e) {
|
|
13
14
|
for (let n of e.childNodes) {
|
|
@@ -30,19 +31,7 @@ var s, c = class e extends i(r, { validSizes: t }) {
|
|
|
30
31
|
}).format(((e = this.progress) == null ? 0 : e) / 100);
|
|
31
32
|
}
|
|
32
33
|
warnDeprecatedLightDomChildren() {
|
|
33
|
-
|
|
34
|
-
(t = window.__swc) != null && t.DEBUG && e.hasMeaningfulLightDomChildren(this) && window.__swc.warn(this, `<${this.localName}> no longer has a default slot. Light DOM children are not rendered and are not used for an accessible name. Use the "label" attribute or property, or "aria-label" / "aria-labelledby" on the host instead.`, "https://opensource.adobe.com/spectrum-web-components/second-gen/?path=/docs/components-progress-circle--docs", { level: "deprecation" });
|
|
35
|
-
}
|
|
36
|
-
warnMissingAccessibleName() {
|
|
37
|
-
var t, n;
|
|
38
|
-
(t = window.__swc) != null && t.DEBUG && ((n = window.__swc) == null || n.warn(this, `<${this.localName}> requires an accessible name. A default label of "${e.DEFAULT_LABEL}" has been applied, but a more specific label should be provided via:`, "https://opensource.adobe.com/spectrum-web-components/second-gen/?path=/docs/components-progress-circle--docs", {
|
|
39
|
-
type: "accessibility",
|
|
40
|
-
issues: [
|
|
41
|
-
"value supplied to the \"label\" attribute, which will be displayed visually as part of the element, or",
|
|
42
|
-
"value supplied to the \"aria-label\" attribute, which will only be provided to screen readers, or",
|
|
43
|
-
"an element ID reference supplied to the \"aria-labelledby\" attribute, which will be provided by screen readers and will need to be managed manually by the parent application."
|
|
44
|
-
]
|
|
45
|
-
}));
|
|
34
|
+
s(this, e.hasMeaningfulLightDomChildren(this), `<${this.localName}> no longer has a default slot. Light DOM children are not rendered and are not used for an accessible name. Use the "label" attribute or property, or "aria-label" / "aria-labelledby" on the host instead.`, "https://spectrum-web-components.adobe.com/?path=/docs/components-progress-circle--docs", { level: "deprecation" });
|
|
46
35
|
}
|
|
47
36
|
willUpdate(t) {
|
|
48
37
|
if (t.has("progress") && this.progress !== null) {
|
|
@@ -55,19 +44,34 @@ var s, c = class e extends i(r, { validSizes: t }) {
|
|
|
55
44
|
super.firstUpdated(e), this.setAttribute("role", "progressbar");
|
|
56
45
|
}
|
|
57
46
|
updated(t) {
|
|
58
|
-
|
|
59
|
-
|
|
47
|
+
if (super.updated(t), t.has("progress") && (this.progress !== null && this.progress >= 0 ? (this.setAttribute("aria-valuemin", "0"), this.setAttribute("aria-valuemax", "100"), this.setAttribute("aria-valuenow", String(this.progress)), this.setAttribute("aria-valuetext", this.formatProgress())) : (this.removeAttribute("aria-valuemin"), this.removeAttribute("aria-valuemax"), this.removeAttribute("aria-valuenow"), this.removeAttribute("aria-valuetext"))), this.progress !== null && t.has(l) && this.setAttribute("aria-valuetext", this.formatProgress()), t.has("label") && (this.label.length ? this.setAttribute("aria-label", this.label) : t.get("label") === this.getAttribute("aria-label") && this.removeAttribute("aria-label")), t.has("label") && !this.hasAccessibleName() && (this.setAttribute("aria-label", e.DEFAULT_LABEL), s(this, !0, `<${this.localName}> requires an accessible name. A default label of "${e.DEFAULT_LABEL}" has been applied, but a more specific label should be provided via:`, "https://spectrum-web-components.adobe.com/?path=/docs/components-progress-circle--docs", {
|
|
48
|
+
type: "accessibility",
|
|
49
|
+
issues: [
|
|
50
|
+
"value supplied to the \"label\" attribute, which will be displayed visually as part of the element, or",
|
|
51
|
+
"value supplied to the \"aria-label\" attribute, which will only be provided to screen readers, or",
|
|
52
|
+
"an element ID reference supplied to the \"aria-labelledby\" attribute, which will be provided by screen readers and will need to be managed manually by the parent application."
|
|
53
|
+
]
|
|
54
|
+
})), t.has("staticColor") && this.staticColor !== void 0) {
|
|
55
|
+
let e = this.constructor;
|
|
56
|
+
o(this, {
|
|
57
|
+
prop: "static-color",
|
|
58
|
+
value: this.staticColor,
|
|
59
|
+
valid: e.STATIC_COLORS,
|
|
60
|
+
url: "https://spectrum-web-components.adobe.com/?path=/docs/components-progress-circle--docs"
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
a() && this.warnDeprecatedLightDomChildren();
|
|
60
64
|
}
|
|
61
65
|
};
|
|
62
|
-
|
|
66
|
+
u = d, u.DEFAULT_LABEL = "Loading", e([n({
|
|
63
67
|
type: String,
|
|
64
68
|
reflect: !0,
|
|
65
69
|
attribute: "static-color"
|
|
66
|
-
})],
|
|
70
|
+
})], d.prototype, "staticColor", void 0), e([n({ type: String })], d.prototype, "label", void 0), e([n({
|
|
67
71
|
type: Number,
|
|
68
72
|
reflect: !0
|
|
69
|
-
})],
|
|
73
|
+
})], d.prototype, "progress", void 0);
|
|
70
74
|
//#endregion
|
|
71
|
-
export {
|
|
75
|
+
export { d as ProgressCircleBase };
|
|
72
76
|
|
|
73
77
|
//# sourceMappingURL=ProgressCircle.base.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProgressCircle.base.js","names":[],"sources":["../../../components/progress-circle/ProgressCircle.base.ts"],"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 { PropertyValues } from 'lit';\nimport { property } from 'lit/decorators.js';\n\nimport {\n LanguageResolutionController,\n languageResolverUpdatedSymbol,\n} from '@adobe/spectrum-wc-core/controllers/language-resolution.js';\nimport { SpectrumElement } from '@adobe/spectrum-wc-core/element/index.js';\nimport { SizedMixin } from '@adobe/spectrum-wc-core/mixins/index.js';\n\nimport {\n PROGRESS_CIRCLE_VALID_SIZES,\n ProgressCircleStaticColor,\n} from './ProgressCircle.types.js';\n\n/**\n * A progress circle component that visually represents the completion progress of a task.\n * Can be used in both determinate (with specific progress value) and indeterminate (loading) states.\n *\n * @attribute {ElementSize} size - The size of the progress circle.\n */\nexport abstract class ProgressCircleBase extends SizedMixin(SpectrumElement, {\n validSizes: PROGRESS_CIRCLE_VALID_SIZES,\n}) {\n /**\n * The size of the progress circle.\n *\n * @default m\n */\n declare public size: (typeof PROGRESS_CIRCLE_VALID_SIZES)[number];\n\n // ─────────────────────────\n // API TO OVERRIDE\n // ─────────────────────────\n\n /**\n * @internal\n *\n * A readonly array of the valid static colors for the progress circle.\n *\n * This is an actual internal property, intended not for customer use\n * but for use in internal validation logic, stories, tests, etc.\n *\n * Because S1 and S2 support different static colors, the value of this\n * property must be set in each subclass.\n */\n static readonly STATIC_COLORS: readonly string[];\n\n /**\n * @internal\n *\n * Static color variant for use on different backgrounds.\n *\n * This is a public property, but its valid values vary between S1 and S2,\n * so the property (and its docs) need to be redefined in each subclass.\n *\n * The type declared here is a union of the valid values for S1 and S2,\n * and should be narrowed in each subclass.\n */\n @property({ type: String, reflect: true, attribute: 'static-color' })\n public staticColor?: ProgressCircleStaticColor;\n\n // ──────────────────\n // SHARED API\n // ──────────────────\n\n /**\n * Accessible label for the progress circle.\n *\n * Used to provide context about what is loading or progressing.\n * When no accessible name is provided (no label, aria-label, or\n * aria-labelledby), a default \"Loading\" label is applied.\n *\n * @todo Localize the default \"Loading\" fallback via LanguageResolutionController\n * once a runtime i18n system for static strings is available.\n */\n @property({ type: String })\n public label = '';\n\n /**\n * Progress value from 0 to 100.\n *\n * When `null` (indeterminate), the component shows a loading animation.\n * Setting a number switches to determinate mode. Removing the `progress`\n * attribute or setting this property to `null` returns to indeterminate.\n * Values outside 0–100 or non-finite numbers are clamped (non-finite becomes 0).\n *\n * Reflected to the `progress` attribute when set; the attribute is omitted when indeterminate.\n */\n @property({ type: Number, reflect: true })\n public progress: number | null = null;\n\n private languageResolver = new LanguageResolutionController(this);\n\n // ──────────────────────\n // IMPLEMENTATION\n // ──────────────────────\n\n /**\n * @todo Localize via LanguageResolutionController once a runtime i18n\n * system for static strings is available.\n */\n private static readonly DEFAULT_LABEL = 'Loading';\n\n /** True when light DOM has element nodes or non-whitespace text (no default slot). */\n private static hasMeaningfulLightDomChildren(host: HTMLElement): boolean {\n for (const node of host.childNodes) {\n if (\n node.nodeType === Node.ELEMENT_NODE ||\n (node.nodeType === Node.TEXT_NODE && node.textContent?.trim())\n ) {\n return true;\n }\n }\n return false;\n }\n\n private hasAccessibleName(): boolean {\n return Boolean(\n this.label ||\n this.getAttribute('aria-label') ||\n this.getAttribute('aria-labelledby')\n );\n }\n\n private static clampProgress(value: number): number {\n if (!Number.isFinite(value)) {\n return 0;\n }\n return Math.min(100, Math.max(0, value));\n }\n\n private formatProgress(): string {\n return new Intl.NumberFormat(this.languageResolver.language, {\n style: 'percent',\n unitDisplay: 'narrow',\n }).format((this.progress ?? 0) / 100);\n }\n\n private warnDeprecatedLightDomChildren(): void {\n if (!window.__swc?.DEBUG) {\n return;\n }\n if (!ProgressCircleBase.hasMeaningfulLightDomChildren(this)) {\n return;\n }\n window.__swc.warn(\n this,\n `<${this.localName}> no longer has a default slot. Light DOM children are not rendered and are not used for an accessible name. Use the \"label\" attribute or property, or \"aria-label\" / \"aria-labelledby\" on the host instead.`,\n 'https://opensource.adobe.com/spectrum-web-components/second-gen/?path=/docs/components-progress-circle--docs',\n { level: 'deprecation' }\n );\n }\n\n private warnMissingAccessibleName(): void {\n if (!window.__swc?.DEBUG) {\n return;\n }\n window.__swc?.warn(\n this,\n `<${this.localName}> requires an accessible name. A default label of \"${ProgressCircleBase.DEFAULT_LABEL}\" has been applied, but a more specific label should be provided via:`,\n 'https://opensource.adobe.com/spectrum-web-components/second-gen/?path=/docs/components-progress-circle--docs',\n {\n type: 'accessibility',\n issues: [\n 'value supplied to the \"label\" attribute, which will be displayed visually as part of the element, or',\n 'value supplied to the \"aria-label\" attribute, which will only be provided to screen readers, or',\n 'an element ID reference supplied to the \"aria-labelledby\" attribute, which will be provided by screen readers and will need to be managed manually by the parent application.',\n ],\n }\n );\n }\n\n protected override willUpdate(changes: PropertyValues): void {\n if (changes.has('progress') && this.progress !== null) {\n const clamped = ProgressCircleBase.clampProgress(this.progress);\n if (clamped !== this.progress) {\n this.progress = clamped;\n }\n }\n super.willUpdate(changes);\n }\n\n protected override firstUpdated(changes: PropertyValues): void {\n super.firstUpdated(changes);\n this.setAttribute('role', 'progressbar');\n }\n\n protected override updated(changes: PropertyValues): void {\n super.updated(changes);\n\n if (changes.has('progress')) {\n if (this.progress !== null && this.progress >= 0) {\n this.setAttribute('aria-valuemin', '0');\n this.setAttribute('aria-valuemax', '100');\n this.setAttribute('aria-valuenow', String(this.progress));\n this.setAttribute('aria-valuetext', this.formatProgress());\n } else {\n this.removeAttribute('aria-valuemin');\n this.removeAttribute('aria-valuemax');\n this.removeAttribute('aria-valuenow');\n this.removeAttribute('aria-valuetext');\n }\n }\n\n if (this.progress !== null && changes.has(languageResolverUpdatedSymbol)) {\n this.setAttribute('aria-valuetext', this.formatProgress());\n }\n\n if (changes.has('label')) {\n if (this.label.length) {\n this.setAttribute('aria-label', this.label);\n } else if (changes.get('label') === this.getAttribute('aria-label')) {\n this.removeAttribute('aria-label');\n }\n }\n\n // Apply default accessible name fallback after handling explicit label changes.\n if (changes.has('label') && !this.hasAccessibleName()) {\n this.setAttribute('aria-label', ProgressCircleBase.DEFAULT_LABEL);\n this.warnMissingAccessibleName();\n }\n\n if (window.__swc?.DEBUG) {\n this.warnDeprecatedLightDomChildren();\n }\n }\n}\n"],"mappings":";;;;;;;OAiCsB,IAAtB,MAAsB,UAA2B,EAAW,GAAiB,EAC3E,YAAY,GACb,CAAC,CAAC;;4BAsDc,oBAakB,8BAEN,IAAI,EAA6B,KAAK;;CAajE,OAAe,8BAA8B,GAA4B;AACvE,OAAK,IAAM,KAAQ,EAAK,YAAY;;AAClC,OACE,EAAK,aAAa,KAAK,gBACtB,EAAK,aAAa,KAAK,cAAA,IAAa,EAAK,gBAAA,QAAA,EAAa,MAAM,CAE7D,QAAO;;AAGX,SAAO;;CAGT,oBAAqC;AACnC,SAAO,GACL,KAAK,SACL,KAAK,aAAa,aAAa,IAC/B,KAAK,aAAa,kBAAkB;;CAIxC,OAAe,cAAc,GAAuB;AAIlD,SAHK,OAAO,SAAS,EAAM,GAGpB,KAAK,IAAI,KAAK,KAAK,IAAI,GAAG,EAAM,CAAC,GAF/B;;CAKX,iBAAiC;;AAC/B,SAAO,IAAI,KAAK,aAAa,KAAK,iBAAiB,UAAU;GAC3D,OAAO;GACP,aAAa;GACd,CAAC,CAAC,SAAA,IAAQ,KAAK,aAAA,OAAY,IAAZ,KAAiB,IAAI;;CAGvC,iCAA+C;;AACzC,GAAA,IAAC,OAAO,UAAA,QAAA,EAAO,SAGd,EAAmB,8BAA8B,KAAK,IAG3D,OAAO,MAAM,KACX,MACA,IAAI,KAAK,UAAU,+MACnB,gHACA,EAAE,OAAO,eAAe,CACzB;;CAGH,4BAA0C;;AACpC,GAAA,IAAC,OAAO,UAAA,QAAA,EAAO,WAGnB,IAAA,OAAO,UAAA,QAAA,EAAO,KACZ,MACA,IAAI,KAAK,UAAU,qDAAqD,EAAmB,cAAc,wEACzG,gHACA;GACE,MAAM;GACN,QAAQ;IACN;IACA;IACA;IACD;GACF,CACF;;CAGH,WAA8B,GAA+B;AAC3D,MAAI,EAAQ,IAAI,WAAW,IAAI,KAAK,aAAa,MAAM;GACrD,IAAM,IAAU,EAAmB,cAAc,KAAK,SAAS;AAC/D,GAAI,MAAY,KAAK,aACnB,KAAK,WAAW;;AAGpB,QAAM,WAAW,EAAQ;;CAG3B,aAAgC,GAA+B;AAE7D,EADA,MAAM,aAAa,EAAQ,EAC3B,KAAK,aAAa,QAAQ,cAAc;;CAG1C,QAA2B,GAA+B;;AAmCxD,EAlCA,MAAM,QAAQ,EAAQ,EAElB,EAAQ,IAAI,WAAW,KACrB,KAAK,aAAa,QAAQ,KAAK,YAAY,KAC7C,KAAK,aAAa,iBAAiB,IAAI,EACvC,KAAK,aAAa,iBAAiB,MAAM,EACzC,KAAK,aAAa,iBAAiB,OAAO,KAAK,SAAS,CAAC,EACzD,KAAK,aAAa,kBAAkB,KAAK,gBAAgB,CAAC,KAE1D,KAAK,gBAAgB,gBAAgB,EACrC,KAAK,gBAAgB,gBAAgB,EACrC,KAAK,gBAAgB,gBAAgB,EACrC,KAAK,gBAAgB,iBAAiB,IAItC,KAAK,aAAa,QAAQ,EAAQ,IAAI,EAA8B,IACtE,KAAK,aAAa,kBAAkB,KAAK,gBAAgB,CAAC,EAGxD,EAAQ,IAAI,QAAQ,KAClB,KAAK,MAAM,SACb,KAAK,aAAa,cAAc,KAAK,MAAM,GAClC,EAAQ,IAAI,QAAQ,KAAK,KAAK,aAAa,aAAa,IACjE,KAAK,gBAAgB,aAAa,GAKlC,EAAQ,IAAI,QAAQ,IAAI,CAAC,KAAK,mBAAmB,KACnD,KAAK,aAAa,cAAc,EAAmB,cAAc,EACjE,KAAK,2BAA2B,IAGlC,IAAI,OAAO,UAAA,QAAA,EAAO,SAChB,KAAK,gCAAgC;;;yBA1HD,cA3CvC,EAAS;CAAE,MAAM;CAAQ,SAAS;CAAM,WAAW;CAAgB,CAAC,CAAA,EAAA,EAAA,WAAA,eAAA,KAAA,EAAA,KAiBpE,EAAS,EAAE,MAAM,QAAQ,CAAC,CAAA,EAAA,EAAA,WAAA,SAAA,KAAA,EAAA,KAa1B,EAAS;CAAE,MAAM;CAAQ,SAAS;CAAM,CAAC,CAAA,EAAA,EAAA,WAAA,YAAA,KAAA,EAAA"}
|
|
1
|
+
{"version":3,"file":"ProgressCircle.base.js","names":[],"sources":["../../../components/progress-circle/ProgressCircle.base.ts"],"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 { PropertyValues } from 'lit';\nimport { property } from 'lit/decorators.js';\n\nimport {\n LanguageResolutionController,\n languageResolverUpdatedSymbol,\n} from '@adobe/spectrum-wc-core/controllers/language-resolution.js';\nimport { SpectrumElement } from '@adobe/spectrum-wc-core/element/index.js';\nimport { SizedMixin } from '@adobe/spectrum-wc-core/mixins/index.js';\nimport {\n isDebug,\n validateEnum,\n warnIf,\n} from '@adobe/spectrum-wc-core/utils/index.js';\n\nimport {\n PROGRESS_CIRCLE_VALID_SIZES,\n ProgressCircleStaticColor,\n} from './ProgressCircle.types.js';\n\n/**\n * A progress circle component that visually represents the completion progress of a task.\n * Can be used in both determinate (with specific progress value) and indeterminate (loading) states.\n *\n * @attribute {ElementSize} size - The size of the progress circle.\n */\nexport abstract class ProgressCircleBase extends SizedMixin(SpectrumElement, {\n validSizes: PROGRESS_CIRCLE_VALID_SIZES,\n}) {\n /**\n * The size of the progress circle.\n *\n * @default m\n */\n declare public size: (typeof PROGRESS_CIRCLE_VALID_SIZES)[number];\n\n // ─────────────────────────\n // API TO OVERRIDE\n // ─────────────────────────\n\n /**\n * @internal\n *\n * A readonly array of the valid static colors for the progress circle.\n *\n * This is an actual internal property, intended not for customer use\n * but for use in internal validation logic, stories, tests, etc.\n *\n * Because S1 and S2 support different static colors, the value of this\n * property must be set in each subclass.\n */\n static readonly STATIC_COLORS: readonly string[];\n\n /**\n * @internal\n *\n * Static color variant for use on different backgrounds.\n *\n * This is a public property, but its valid values vary between S1 and S2,\n * so the property (and its docs) need to be redefined in each subclass.\n *\n * The type declared here is a union of the valid values for S1 and S2,\n * and should be narrowed in each subclass.\n */\n @property({ type: String, reflect: true, attribute: 'static-color' })\n public staticColor?: ProgressCircleStaticColor;\n\n // ──────────────────\n // SHARED API\n // ──────────────────\n\n /**\n * Accessible label for the progress circle.\n *\n * Used to provide context about what is loading or progressing.\n * When no accessible name is provided (no label, aria-label, or\n * aria-labelledby), a default \"Loading\" label is applied.\n *\n * @todo Localize the default \"Loading\" fallback via LanguageResolutionController\n * once a runtime i18n system for static strings is available.\n */\n @property({ type: String })\n public label = '';\n\n /**\n * Progress value from 0 to 100.\n *\n * When `null` (indeterminate), the component shows a loading animation.\n * Setting a number switches to determinate mode. Removing the `progress`\n * attribute or setting this property to `null` returns to indeterminate.\n * Values outside 0–100 or non-finite numbers are clamped (non-finite becomes 0).\n *\n * Reflected to the `progress` attribute when set; the attribute is omitted when indeterminate.\n */\n @property({ type: Number, reflect: true })\n public progress: number | null = null;\n\n private languageResolver = new LanguageResolutionController(this);\n\n // ──────────────────────\n // IMPLEMENTATION\n // ──────────────────────\n\n /**\n * @todo Localize via LanguageResolutionController once a runtime i18n\n * system for static strings is available.\n */\n private static readonly DEFAULT_LABEL = 'Loading';\n\n /** True when light DOM has element nodes or non-whitespace text (no default slot). */\n private static hasMeaningfulLightDomChildren(host: HTMLElement): boolean {\n for (const node of host.childNodes) {\n if (\n node.nodeType === Node.ELEMENT_NODE ||\n (node.nodeType === Node.TEXT_NODE && node.textContent?.trim())\n ) {\n return true;\n }\n }\n return false;\n }\n\n private hasAccessibleName(): boolean {\n return Boolean(\n this.label ||\n this.getAttribute('aria-label') ||\n this.getAttribute('aria-labelledby')\n );\n }\n\n private static clampProgress(value: number): number {\n if (!Number.isFinite(value)) {\n return 0;\n }\n return Math.min(100, Math.max(0, value));\n }\n\n private formatProgress(): string {\n return new Intl.NumberFormat(this.languageResolver.language, {\n style: 'percent',\n unitDisplay: 'narrow',\n }).format((this.progress ?? 0) / 100);\n }\n\n private warnDeprecatedLightDomChildren(): void {\n warnIf(\n this,\n ProgressCircleBase.hasMeaningfulLightDomChildren(this),\n `<${this.localName}> no longer has a default slot. Light DOM children are not rendered and are not used for an accessible name. Use the \"label\" attribute or property, or \"aria-label\" / \"aria-labelledby\" on the host instead.`,\n 'https://spectrum-web-components.adobe.com/?path=/docs/components-progress-circle--docs',\n { level: 'deprecation' }\n );\n }\n\n protected override willUpdate(changes: PropertyValues): void {\n if (changes.has('progress') && this.progress !== null) {\n const clamped = ProgressCircleBase.clampProgress(this.progress);\n if (clamped !== this.progress) {\n this.progress = clamped;\n }\n }\n\n super.willUpdate(changes);\n }\n\n protected override firstUpdated(changes: PropertyValues): void {\n super.firstUpdated(changes);\n this.setAttribute('role', 'progressbar');\n }\n\n protected override updated(changes: PropertyValues): void {\n super.updated(changes);\n\n if (changes.has('progress')) {\n if (this.progress !== null && this.progress >= 0) {\n this.setAttribute('aria-valuemin', '0');\n this.setAttribute('aria-valuemax', '100');\n this.setAttribute('aria-valuenow', String(this.progress));\n this.setAttribute('aria-valuetext', this.formatProgress());\n } else {\n this.removeAttribute('aria-valuemin');\n this.removeAttribute('aria-valuemax');\n this.removeAttribute('aria-valuenow');\n this.removeAttribute('aria-valuetext');\n }\n }\n\n if (this.progress !== null && changes.has(languageResolverUpdatedSymbol)) {\n this.setAttribute('aria-valuetext', this.formatProgress());\n }\n\n if (changes.has('label')) {\n if (this.label.length) {\n this.setAttribute('aria-label', this.label);\n } else if (changes.get('label') === this.getAttribute('aria-label')) {\n this.removeAttribute('aria-label');\n }\n }\n\n // Apply default accessible name fallback after handling explicit label changes.\n if (changes.has('label') && !this.hasAccessibleName()) {\n this.setAttribute('aria-label', ProgressCircleBase.DEFAULT_LABEL);\n warnIf(\n this,\n true,\n `<${this.localName}> requires an accessible name. A default label of \"${ProgressCircleBase.DEFAULT_LABEL}\" has been applied, but a more specific label should be provided via:`,\n 'https://spectrum-web-components.adobe.com/?path=/docs/components-progress-circle--docs',\n {\n type: 'accessibility',\n issues: [\n 'value supplied to the \"label\" attribute, which will be displayed visually as part of the element, or',\n 'value supplied to the \"aria-label\" attribute, which will only be provided to screen readers, or',\n 'an element ID reference supplied to the \"aria-labelledby\" attribute, which will be provided by screen readers and will need to be managed manually by the parent application.',\n ],\n }\n );\n }\n\n if (changes.has('staticColor') && this.staticColor !== undefined) {\n const constructor = this.constructor as typeof ProgressCircleBase;\n validateEnum(this, {\n prop: 'static-color',\n value: this.staticColor,\n valid: constructor.STATIC_COLORS,\n url: 'https://spectrum-web-components.adobe.com/?path=/docs/components-progress-circle--docs',\n });\n }\n\n // Guard the call site: `hasMeaningfulLightDomChildren` traverses the light\n // DOM and the message is built eagerly as an argument, so both would run on\n // every `updated()` (including production) if passed straight to `warnIf`.\n // `isDebug()` skips that work entirely when validation is off.\n if (isDebug()) {\n this.warnDeprecatedLightDomChildren();\n }\n }\n}\n"],"mappings":"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"}
|
|
@@ -64,6 +64,6 @@ export declare abstract class StatusLightBase extends StatusLightBase_base {
|
|
|
64
64
|
* and should be narrowed in each subclass.
|
|
65
65
|
*/
|
|
66
66
|
variant: StatusLightVariant;
|
|
67
|
-
protected
|
|
67
|
+
protected update(changes: PropertyValues): void;
|
|
68
68
|
}
|
|
69
69
|
export {};
|
|
@@ -3,27 +3,30 @@ import { STATUS_LIGHT_VALID_SIZES as t } from "./StatusLight.types.js";
|
|
|
3
3
|
import { property as n } from "lit/decorators.js";
|
|
4
4
|
import { SpectrumElement as r } from "@adobe/spectrum-wc-core/element/index.js";
|
|
5
5
|
import { SizedMixin as i } from "@adobe/spectrum-wc-core/mixins/index.js";
|
|
6
|
+
import { validateEnum as a, warnIf as o } from "@adobe/spectrum-wc-core/utils/index.js";
|
|
6
7
|
//#region components/status-light/StatusLight.base.ts
|
|
7
|
-
var
|
|
8
|
+
var s = class extends i(r, {
|
|
8
9
|
validSizes: t,
|
|
9
10
|
noDefaultSize: !0
|
|
10
11
|
}) {
|
|
11
12
|
constructor(...e) {
|
|
12
13
|
super(...e), this.variant = "neutral";
|
|
13
14
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
update(e) {
|
|
16
|
+
let t = this.constructor;
|
|
17
|
+
this.variant === "accent" ? o(this, !0, `<${this.localName}> does not support the "accent" variant in Spectrum 2. Use "neutral" or "info" depending on intent.`, "https://spectrum-web-components.adobe.com/?path=/docs/status-light-migration-guide--docs", { level: "deprecation" }) : a(this, {
|
|
18
|
+
prop: "variant",
|
|
19
|
+
value: this.variant,
|
|
20
|
+
valid: t.VARIANTS,
|
|
21
|
+
url: "https://spectrum-web-components.adobe.com/?path=/docs/components-status-light--docs"
|
|
22
|
+
}), o(this, this.hasAttribute("disabled"), `<${this.localName}> does not support the "disabled" attribute. It was deprecated in Spectrum 1 and has been removed in Spectrum 2.`, "https://spectrum-web-components.adobe.com/?path=/docs/status-light-migration-guide--docs", { level: "deprecation" }), super.update(e);
|
|
20
23
|
}
|
|
21
24
|
};
|
|
22
25
|
e([n({
|
|
23
26
|
type: String,
|
|
24
27
|
reflect: !0
|
|
25
|
-
})],
|
|
28
|
+
})], s.prototype, "variant", void 0);
|
|
26
29
|
//#endregion
|
|
27
|
-
export {
|
|
30
|
+
export { s as StatusLightBase };
|
|
28
31
|
|
|
29
32
|
//# sourceMappingURL=StatusLight.base.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StatusLight.base.js","names":[],"sources":["../../../components/status-light/StatusLight.base.ts"],"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 */\nimport { PropertyValues } from 'lit';\nimport { property } from 'lit/decorators.js';\n\nimport { SpectrumElement } from '@adobe/spectrum-wc-core/element/index.js';\nimport { SizedMixin } from '@adobe/spectrum-wc-core/mixins/index.js';\n\nimport {\n STATUS_LIGHT_VALID_SIZES,\n type StatusLightSize,\n type StatusLightVariant,\n} from './StatusLight.types.js';\n\n/**\n * A status light is a great way to convey semantic meaning and the condition of an entity, such as statuses and categories. It provides visual indicators through colored dots accompanied by descriptive text.\n *\n * @slot - The text label of the status light.\n * @attribute {ElementSize} size - The size of the status light.\n */\nexport abstract class StatusLightBase extends SizedMixin(SpectrumElement, {\n validSizes: STATUS_LIGHT_VALID_SIZES,\n noDefaultSize: true,\n}) {\n /**\n * The size of the status light.\n */\n declare public size: StatusLightSize;\n\n // ─────────────────────────\n // API TO OVERRIDE\n // ─────────────────────────\n\n /**\n * @internal\n *\n * A readonly array of the valid color variants for the status light.\n *\n * This is an actual internal property, intended not for customer use\n * but for use in internal validation logic, stories, tests, etc.\n *\n * Because S1 and S2 support different color variants, the value of this\n * property must be set in each subclass.\n */\n static readonly VARIANTS_COLOR: readonly string[];\n\n /**\n * @internal\n *\n * A readonly array of the valid semantic variants for the status light.\n *\n * This is an actual internal property, intended not for customer use\n * but for use in internal validation logic, stories, tests, etc.\n *\n * Because S1 and S2 support different semantic variants, the value of this\n * property must be set in each subclass.\n */\n static readonly VARIANTS_SEMANTIC: readonly string[];\n\n /**\n * @internal\n *\n * A readonly array of all valid variants for the status light.\n *\n * This is an actual internal property, intended not for customer use\n * but for use in internal validation logic, stories, tests, etc.\n *\n * Because S1 and S2 support different variants, the value of this\n * property must be set in each subclass.\n */\n static readonly VARIANTS: readonly string[];\n\n /**\n * @internal\n *\n * The variant of the status light.\n *\n * This is a public property, but its valid values vary between S1 and S2,\n * so the property (and its docs) need to be redefined in each subclass.\n *\n * The type declared here is a union of the valid values for S1 and S2,\n * and should be narrowed in each subclass.\n */\n @property({ type: String, reflect: true })\n public variant: StatusLightVariant = 'neutral';\n\n // ──────────────────────\n // IMPLEMENTATION\n // ──────────────────────\n\n protected override
|
|
1
|
+
{"version":3,"file":"StatusLight.base.js","names":[],"sources":["../../../components/status-light/StatusLight.base.ts"],"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 */\nimport { PropertyValues } from 'lit';\nimport { property } from 'lit/decorators.js';\n\nimport { SpectrumElement } from '@adobe/spectrum-wc-core/element/index.js';\nimport { SizedMixin } from '@adobe/spectrum-wc-core/mixins/index.js';\nimport { validateEnum, warnIf } from '@adobe/spectrum-wc-core/utils/index.js';\n\nimport {\n STATUS_LIGHT_VALID_SIZES,\n type StatusLightSize,\n type StatusLightVariant,\n} from './StatusLight.types.js';\n\n/**\n * A status light is a great way to convey semantic meaning and the condition of an entity, such as statuses and categories. It provides visual indicators through colored dots accompanied by descriptive text.\n *\n * @slot - The text label of the status light.\n * @attribute {ElementSize} size - The size of the status light.\n */\nexport abstract class StatusLightBase extends SizedMixin(SpectrumElement, {\n validSizes: STATUS_LIGHT_VALID_SIZES,\n noDefaultSize: true,\n}) {\n /**\n * The size of the status light.\n */\n declare public size: StatusLightSize;\n\n // ─────────────────────────\n // API TO OVERRIDE\n // ─────────────────────────\n\n /**\n * @internal\n *\n * A readonly array of the valid color variants for the status light.\n *\n * This is an actual internal property, intended not for customer use\n * but for use in internal validation logic, stories, tests, etc.\n *\n * Because S1 and S2 support different color variants, the value of this\n * property must be set in each subclass.\n */\n static readonly VARIANTS_COLOR: readonly string[];\n\n /**\n * @internal\n *\n * A readonly array of the valid semantic variants for the status light.\n *\n * This is an actual internal property, intended not for customer use\n * but for use in internal validation logic, stories, tests, etc.\n *\n * Because S1 and S2 support different semantic variants, the value of this\n * property must be set in each subclass.\n */\n static readonly VARIANTS_SEMANTIC: readonly string[];\n\n /**\n * @internal\n *\n * A readonly array of all valid variants for the status light.\n *\n * This is an actual internal property, intended not for customer use\n * but for use in internal validation logic, stories, tests, etc.\n *\n * Because S1 and S2 support different variants, the value of this\n * property must be set in each subclass.\n */\n static readonly VARIANTS: readonly string[];\n\n /**\n * @internal\n *\n * The variant of the status light.\n *\n * This is a public property, but its valid values vary between S1 and S2,\n * so the property (and its docs) need to be redefined in each subclass.\n *\n * The type declared here is a union of the valid values for S1 and S2,\n * and should be narrowed in each subclass.\n */\n @property({ type: String, reflect: true })\n public variant: StatusLightVariant = 'neutral';\n\n // ──────────────────────\n // IMPLEMENTATION\n // ──────────────────────\n\n protected override update(changes: PropertyValues): void {\n const constructor = this.constructor as typeof StatusLightBase;\n // @ts-expect-error -- intentional runtime guard: 1st-gen consumers may pass 'accent'\n if (this.variant === 'accent') {\n warnIf(\n this,\n true,\n `<${this.localName}> does not support the \"accent\" variant in Spectrum 2. Use \"neutral\" or \"info\" depending on intent.`,\n 'https://spectrum-web-components.adobe.com/?path=/docs/status-light-migration-guide--docs',\n { level: 'deprecation' }\n );\n } else {\n validateEnum(this, {\n prop: 'variant',\n value: this.variant,\n valid: constructor.VARIANTS,\n url: 'https://spectrum-web-components.adobe.com/?path=/docs/components-status-light--docs',\n });\n }\n warnIf(\n this,\n this.hasAttribute('disabled'),\n `<${this.localName}> does not support the \"disabled\" attribute. It was deprecated in Spectrum 1 and has been removed in Spectrum 2.`,\n 'https://spectrum-web-components.adobe.com/?path=/docs/status-light-migration-guide--docs',\n { level: 'deprecation' }\n );\n\n super.update(changes);\n }\n}\n"],"mappings":";;;;;;;AA8BA,IAAsB,IAAtB,cAA8C,EAAW,GAAiB;CACxE,YAAY;CACZ,eAAe;CAChB,CAAC,CAAC;;8BA6DoC;;CAMrC,OAA0B,GAA+B;EACvD,IAAM,IAAc,KAAK;AA0BzB,EAxBI,KAAK,YAAY,WACnB,EACE,MACA,IACA,IAAI,KAAK,UAAU,sGACnB,4FACA,EAAE,OAAO,eAAe,CACzB,GAED,EAAa,MAAM;GACjB,MAAM;GACN,OAAO,KAAK;GACZ,OAAO,EAAY;GACnB,KAAK;GACN,CAAC,EAEJ,EACE,MACA,KAAK,aAAa,WAAW,EAC7B,IAAI,KAAK,UAAU,mHACnB,4FACA,EAAE,OAAO,eAAe,CACzB,EAED,MAAM,OAAO,EAAQ;;;GAlCtB,EAAS;CAAE,MAAM;CAAQ,SAAS;CAAM,CAAC,CAAA,EAAA,EAAA,WAAA,WAAA,KAAA,EAAA"}
|
|
@@ -3,8 +3,9 @@ import { KEYBOARD_ACTIVATIONS as t, KEYBOARD_ACTIVATION_DEFAULT as n, TABS_DEFAU
|
|
|
3
3
|
import { property as s, state as c } from "lit/decorators.js";
|
|
4
4
|
import { FocusgroupNavigationController as l, focusgroupNavigationActiveChange as u } from "@adobe/spectrum-wc-core/controllers/index.js";
|
|
5
5
|
import { SpectrumElement as d } from "@adobe/spectrum-wc-core/element/index.js";
|
|
6
|
+
import { validateEnum as f, warnIf as p } from "@adobe/spectrum-wc-core/utils/index.js";
|
|
6
7
|
//#region components/tabs/Tabs.base.ts
|
|
7
|
-
var
|
|
8
|
+
var m, h = class e extends d {
|
|
8
9
|
constructor(...t) {
|
|
9
10
|
super(...t), this._keyboardActivation = n, this._density = o, this._direction = r, this.disabled = !1, this.accessibleLabel = "", this.selected = "", this.selectionIndicatorStyle = "", this.shouldAnimate = !1, this._tabs = [], this._navigation = new l(this, {
|
|
10
11
|
direction: this._direction,
|
|
@@ -35,37 +36,49 @@ var f, p = class e extends d {
|
|
|
35
36
|
return this._keyboardActivation;
|
|
36
37
|
}
|
|
37
38
|
set keyboardActivation(e) {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
39
|
+
let r = t.includes(e);
|
|
40
|
+
f(this, {
|
|
41
|
+
prop: "keyboard-activation",
|
|
42
|
+
value: e,
|
|
43
|
+
valid: t,
|
|
44
|
+
url: "https://spectrum-web-components.adobe.com/?path=/docs/components-tabs--docs"
|
|
45
|
+
});
|
|
46
|
+
let i = r ? e : n;
|
|
47
|
+
if (this._keyboardActivation === i) return;
|
|
48
|
+
let a = this._keyboardActivation;
|
|
49
|
+
this._keyboardActivation = i, this.requestUpdate("keyboardActivation", a);
|
|
45
50
|
}
|
|
46
51
|
get density() {
|
|
47
52
|
return this._density;
|
|
48
53
|
}
|
|
49
54
|
set density(e) {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
let t = a.includes(e);
|
|
56
|
+
f(this, {
|
|
57
|
+
prop: "density",
|
|
58
|
+
value: e,
|
|
59
|
+
valid: a,
|
|
60
|
+
url: "https://spectrum-web-components.adobe.com/?path=/docs/components-tabs--docs"
|
|
61
|
+
});
|
|
62
|
+
let n = t ? e : o;
|
|
63
|
+
if (this._density === n) return;
|
|
64
|
+
let r = this._density;
|
|
65
|
+
this._density = n, this.requestUpdate("density", r);
|
|
57
66
|
}
|
|
58
67
|
get direction() {
|
|
59
68
|
return this._direction;
|
|
60
69
|
}
|
|
61
70
|
set direction(e) {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
71
|
+
let t = i.includes(e);
|
|
72
|
+
f(this, {
|
|
73
|
+
prop: "direction",
|
|
74
|
+
value: e,
|
|
75
|
+
valid: i,
|
|
76
|
+
url: "https://spectrum-web-components.adobe.com/?path=/docs/components-tabs--docs"
|
|
77
|
+
});
|
|
78
|
+
let n = t ? e : r;
|
|
79
|
+
if (this._direction === n) return;
|
|
80
|
+
let a = this._direction;
|
|
81
|
+
this._direction = n, this.requestUpdate("direction", a);
|
|
69
82
|
}
|
|
70
83
|
static isTabSlotNode(e) {
|
|
71
84
|
return e instanceof HTMLElement ? e.getAttribute("role") === "tab" ? !0 : e.localName === "swc-tab" : !1;
|
|
@@ -164,8 +177,7 @@ var f, p = class e extends d {
|
|
|
164
177
|
super.focus(e);
|
|
165
178
|
}
|
|
166
179
|
firstUpdated(e) {
|
|
167
|
-
|
|
168
|
-
super.firstUpdated(e), this.hasAttribute("direction") || this.setAttribute("direction", this.direction), (t = window.__swc) != null && t.DEBUG && !this.accessibleLabel && window.__swc.warn(this, `<${this.localName}> requires an "accessible-label" attribute to provide an accessible name for the tablist.`, "https://opensource.adobe.com/spectrum-web-components/components/tabs/", {
|
|
180
|
+
super.firstUpdated(e), this.hasAttribute("direction") || this.setAttribute("direction", this.direction), p(this, !this.accessibleLabel, `<${this.localName}> requires an "accessible-label" attribute to provide an accessible name for the tablist.`, "https://spectrum-web-components.adobe.com/?path=/docs/components-tabs--docs", {
|
|
169
181
|
type: "accessibility",
|
|
170
182
|
level: "high"
|
|
171
183
|
});
|
|
@@ -175,27 +187,27 @@ var f, p = class e extends d {
|
|
|
175
187
|
return await Promise.all(t), e;
|
|
176
188
|
}
|
|
177
189
|
};
|
|
178
|
-
|
|
190
|
+
m = h, m.VALID_DIRECTIONS = i, m.VALID_KEYBOARD_ACTIVATIONS = t, m.VALID_DENSITIES = a, m.INDICATOR_BASE_SIZE = 100, e([s({
|
|
179
191
|
type: String,
|
|
180
192
|
reflect: !0,
|
|
181
193
|
attribute: "keyboard-activation"
|
|
182
|
-
})],
|
|
194
|
+
})], h.prototype, "keyboardActivation", null), e([s({
|
|
183
195
|
type: String,
|
|
184
196
|
reflect: !0
|
|
185
|
-
})],
|
|
197
|
+
})], h.prototype, "density", null), e([s({
|
|
186
198
|
type: String,
|
|
187
199
|
reflect: !0
|
|
188
|
-
})],
|
|
200
|
+
})], h.prototype, "direction", null), e([s({
|
|
189
201
|
type: Boolean,
|
|
190
202
|
reflect: !0
|
|
191
|
-
})],
|
|
203
|
+
})], h.prototype, "disabled", void 0), e([s({
|
|
192
204
|
type: String,
|
|
193
205
|
attribute: "accessible-label"
|
|
194
|
-
})],
|
|
206
|
+
})], h.prototype, "accessibleLabel", void 0), e([s({
|
|
195
207
|
type: String,
|
|
196
208
|
reflect: !0
|
|
197
|
-
})],
|
|
209
|
+
})], h.prototype, "selected", void 0), e([c()], h.prototype, "selectionIndicatorStyle", void 0), e([c()], h.prototype, "shouldAnimate", void 0);
|
|
198
210
|
//#endregion
|
|
199
|
-
export {
|
|
211
|
+
export { h as TabsBase };
|
|
200
212
|
|
|
201
213
|
//# sourceMappingURL=Tabs.base.js.map
|