@adobe/spectrum-wc-core 2.0.0-beta.2 → 2.0.0-beta.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/README.md +1 -1
  2. package/dist/components/accordion/Accordion.base.js +28 -22
  3. package/dist/components/accordion/Accordion.base.js.map +1 -1
  4. package/dist/components/accordion/AccordionItem.base.d.ts +16 -6
  5. package/dist/components/accordion/AccordionItem.base.js +6 -3
  6. package/dist/components/accordion/AccordionItem.base.js.map +1 -1
  7. package/dist/components/action-group/ActionGroup.base.d.ts +108 -0
  8. package/dist/components/action-group/ActionGroup.base.js +53 -0
  9. package/dist/components/action-group/ActionGroup.base.js.map +1 -0
  10. package/dist/components/action-group/ActionGroup.types.d.ts +17 -0
  11. package/dist/components/action-group/ActionGroup.types.js +12 -0
  12. package/dist/components/action-group/ActionGroup.types.js.map +1 -0
  13. package/dist/components/action-group/index.d.ts +13 -0
  14. package/dist/components/action-group/index.js +3 -0
  15. package/dist/components/alert-banner/AlertBanner.base.js +11 -10
  16. package/dist/components/alert-banner/AlertBanner.base.js.map +1 -1
  17. package/dist/components/asset/Asset.base.d.ts +89 -10
  18. package/dist/components/asset/Asset.base.js +117 -12
  19. package/dist/components/asset/Asset.base.js.map +1 -1
  20. package/dist/components/asset/Asset.types.d.ts +20 -2
  21. package/dist/components/asset/Asset.types.js +10 -2
  22. package/dist/components/asset/Asset.types.js.map +1 -1
  23. package/dist/components/asset/index.js +3 -3
  24. package/dist/components/avatar/Avatar.base.js +18 -22
  25. package/dist/components/avatar/Avatar.base.js.map +1 -1
  26. package/dist/components/badge/Badge.base.d.ts +24 -8
  27. package/dist/components/badge/Badge.base.js +22 -17
  28. package/dist/components/badge/Badge.base.js.map +1 -1
  29. package/dist/components/button/Button.base.d.ts +20 -10
  30. package/dist/components/button/Button.base.js +17 -12
  31. package/dist/components/button/Button.base.js.map +1 -1
  32. package/dist/components/button-group/ButtonGroup.base.js +19 -12
  33. package/dist/components/button-group/ButtonGroup.base.js.map +1 -1
  34. package/dist/components/card/Card.base.d.ts +95 -46
  35. package/dist/components/card/Card.base.js +71 -23
  36. package/dist/components/card/Card.base.js.map +1 -1
  37. package/dist/components/card/Card.types.d.ts +1 -0
  38. package/dist/components/card/Card.types.js +2 -2
  39. package/dist/components/card/Card.types.js.map +1 -1
  40. package/dist/components/card/index.js +3 -3
  41. package/dist/components/divider/Divider.base.js +13 -8
  42. package/dist/components/divider/Divider.base.js.map +1 -1
  43. package/dist/components/dropzone/Dropzone.base.d.ts +74 -0
  44. package/dist/components/dropzone/Dropzone.base.js +82 -0
  45. package/dist/components/dropzone/Dropzone.base.js.map +1 -0
  46. package/dist/components/dropzone/Dropzone.types.d.ts +43 -0
  47. package/dist/components/dropzone/Dropzone.types.js +15 -0
  48. package/dist/components/dropzone/Dropzone.types.js.map +1 -0
  49. package/dist/components/dropzone/index.d.ts +13 -0
  50. package/dist/components/dropzone/index.js +3 -0
  51. package/dist/components/icon/Icon.base.d.ts +11 -7
  52. package/dist/components/icon/Icon.base.js +13 -20
  53. package/dist/components/icon/Icon.base.js.map +1 -1
  54. package/dist/components/illustrated-message/IllustratedMessage.base.d.ts +22 -8
  55. package/dist/components/illustrated-message/IllustratedMessage.base.js +33 -20
  56. package/dist/components/illustrated-message/IllustratedMessage.base.js.map +1 -1
  57. package/dist/components/infield-button/InfieldButton.base.d.ts +28 -0
  58. package/dist/components/infield-button/InfieldButton.base.js +22 -0
  59. package/dist/components/infield-button/InfieldButton.base.js.map +1 -0
  60. package/dist/components/infield-button/InfieldButton.types.d.ts +13 -0
  61. package/dist/components/infield-button/InfieldButton.types.js +11 -0
  62. package/dist/components/infield-button/InfieldButton.types.js.map +1 -0
  63. package/dist/components/infield-button/index.d.ts +13 -0
  64. package/dist/components/infield-button/index.js +3 -0
  65. package/dist/components/meter/Meter.base.js +11 -9
  66. package/dist/components/meter/Meter.base.js.map +1 -1
  67. package/dist/components/popover/Popover.base.d.ts +1 -21
  68. package/dist/components/popover/Popover.base.js +57 -77
  69. package/dist/components/popover/Popover.base.js.map +1 -1
  70. package/dist/components/progress-circle/ProgressCircle.base.d.ts +0 -1
  71. package/dist/components/progress-circle/ProgressCircle.base.js +26 -22
  72. package/dist/components/progress-circle/ProgressCircle.base.js.map +1 -1
  73. package/dist/components/status-light/StatusLight.base.d.ts +1 -1
  74. package/dist/components/status-light/StatusLight.base.js +12 -9
  75. package/dist/components/status-light/StatusLight.base.js.map +1 -1
  76. package/dist/components/tabs/TabPanel.base.d.ts +1 -1
  77. package/dist/components/tabs/TabPanel.base.js.map +1 -1
  78. package/dist/components/tabs/Tabs.base.js +44 -32
  79. package/dist/components/tabs/Tabs.base.js.map +1 -1
  80. package/dist/components/tooltip/Tooltip.base.js +57 -22
  81. package/dist/components/tooltip/Tooltip.base.js.map +1 -1
  82. package/dist/controllers/color-controller/src/color-controller.js +45 -44
  83. package/dist/controllers/color-controller/src/color-controller.js.map +1 -1
  84. package/dist/controllers/drag-and-drop-controller/index.d.ts +12 -0
  85. package/dist/controllers/drag-and-drop-controller/index.js +2 -0
  86. package/dist/controllers/drag-and-drop-controller/src/drag-and-drop-controller.d.ts +68 -0
  87. package/dist/controllers/drag-and-drop-controller/src/drag-and-drop-controller.js +56 -0
  88. package/dist/controllers/drag-and-drop-controller/src/drag-and-drop-controller.js.map +1 -0
  89. package/dist/controllers/focusgroup-navigation-controller/src/focusgroup-navigation-controller.d.ts +1 -1
  90. package/dist/controllers/focusgroup-navigation-controller/src/focusgroup-navigation-controller.js.map +1 -1
  91. package/dist/controllers/index.d.ts +6 -2
  92. package/dist/controllers/index.js +15 -11
  93. package/dist/controllers/language-resolution.d.ts +1 -1
  94. package/dist/controllers/language-resolution.js.map +1 -1
  95. package/dist/controllers/page-scroll-lock-controller/index.d.ts +12 -0
  96. package/dist/controllers/page-scroll-lock-controller/index.js +2 -0
  97. package/dist/controllers/{page-scroll-lock.js → page-scroll-lock-controller/src/page-scroll-lock.js} +1 -1
  98. package/dist/controllers/page-scroll-lock-controller/src/page-scroll-lock.js.map +1 -0
  99. package/dist/controllers/slot-presence-controller/index.d.ts +12 -0
  100. package/dist/controllers/slot-presence-controller/index.js +2 -0
  101. package/dist/controllers/slot-presence-controller/src/slot-presence-controller.d.ts +57 -0
  102. package/dist/controllers/slot-presence-controller/src/slot-presence-controller.js +44 -0
  103. package/dist/controllers/slot-presence-controller/src/slot-presence-controller.js.map +1 -0
  104. package/dist/controllers/slot-text-controller/index.d.ts +12 -0
  105. package/dist/controllers/slot-text-controller/index.js +2 -0
  106. package/dist/controllers/slot-text-controller/src/slot-text-controller.d.ts +92 -0
  107. package/dist/controllers/slot-text-controller/src/slot-text-controller.js +53 -0
  108. package/dist/controllers/slot-text-controller/src/slot-text-controller.js.map +1 -0
  109. package/dist/controllers/trigger-press-controller/index.d.ts +12 -0
  110. package/dist/controllers/trigger-press-controller/index.js +2 -0
  111. package/dist/controllers/trigger-press-controller/src/trigger-press-controller.d.ts +149 -0
  112. package/dist/controllers/trigger-press-controller/src/trigger-press-controller.js +43 -0
  113. package/dist/controllers/trigger-press-controller/src/trigger-press-controller.js.map +1 -0
  114. package/dist/directives/index.d.ts +1 -1
  115. package/dist/element/define-element.js +1 -1
  116. package/dist/element/define-element.js.map +1 -1
  117. package/dist/element/index.d.ts +1 -1
  118. package/dist/element/index.js +2 -2
  119. package/dist/element/spectrum-element.d.ts +58 -15
  120. package/dist/element/spectrum-element.js +56 -37
  121. package/dist/element/spectrum-element.js.map +1 -1
  122. package/dist/element/version.d.ts +3 -3
  123. package/dist/element/version.js +1 -1
  124. package/dist/element/version.js.map +1 -1
  125. package/dist/mixins/index.d.ts +0 -2
  126. package/dist/mixins/index.js +4 -6
  127. package/dist/mixins/linear-progress-mixin.d.ts +1 -2
  128. package/dist/mixins/linear-progress-mixin.js +35 -34
  129. package/dist/mixins/linear-progress-mixin.js.map +1 -1
  130. package/dist/mixins/pending-mixin.js +12 -11
  131. package/dist/mixins/pending-mixin.js.map +1 -1
  132. package/dist/mixins/sized-mixin.d.ts +28 -0
  133. package/dist/mixins/sized-mixin.js +6 -6
  134. package/dist/mixins/sized-mixin.js.map +1 -1
  135. package/dist/utils/dev-validation.d.ts +88 -0
  136. package/dist/utils/dev-validation.js +33 -0
  137. package/dist/utils/dev-validation.js.map +1 -0
  138. package/dist/utils/index.d.ts +2 -0
  139. package/dist/utils/index.js +12 -10
  140. package/dist/utils/is-focus-visible-in-tree.d.ts +33 -0
  141. package/dist/utils/is-focus-visible-in-tree.js +11 -0
  142. package/dist/utils/is-focus-visible-in-tree.js.map +1 -0
  143. package/dist/utils/resolve-trigger.js.map +1 -1
  144. package/package.json +213 -18
  145. package/CHANGELOG.md +0 -125
  146. package/dist/_virtual/_@oxc-project_runtime@0.124.0/helpers/defineProperty.js +0 -12
  147. package/dist/_virtual/_@oxc-project_runtime@0.124.0/helpers/toPrimitive.js +0 -14
  148. package/dist/_virtual/_@oxc-project_runtime@0.124.0/helpers/toPropertyKey.js +0 -9
  149. package/dist/_virtual/_@oxc-project_runtime@0.124.0/helpers/typeof.js +0 -11
  150. package/dist/controllers/page-scroll-lock.js.map +0 -1
  151. package/dist/mixins/observe-slot-presence.d.ts +0 -12
  152. package/dist/mixins/observe-slot-presence.js +0 -40
  153. package/dist/mixins/observe-slot-presence.js.map +0 -1
  154. package/dist/mixins/observe-slot-text.d.ts +0 -11
  155. package/dist/mixins/observe-slot-text.js +0 -60
  156. package/dist/mixins/observe-slot-text.js.map +0 -1
  157. /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":"Tooltip.base.js","names":[],"sources":["../../../components/tooltip/Tooltip.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';\n\nimport {\n HoverController,\n type HoverControllerHost,\n} from '../../controllers/hover-controller/index.js';\nimport {\n fromFloatingPlacement,\n type Placement as ControllerPlacement,\n PlacementController,\n toFloatingPlacement,\n} from '../../controllers/placement-controller/index.js';\nimport {\n TOOLTIP_PLACEMENTS,\n TOOLTIP_VARIANTS,\n type TooltipPlacement,\n type TooltipVariant,\n} from './Tooltip.types.js';\n\n/**\n * Abstract base class for the Tooltip component.\n * Handles all non-rendering logic: property declarations, popover lifecycle,\n * event dispatch, trigger resolution, ARIA wiring, `HoverController` integration\n * (hover/focus open/close), and `PlacementController` integration (pixel positioning).\n *\n * @slot - Text label displayed in the tooltip.\n *\n * @fires swc-open - Dispatched when the tooltip begins to open, before the transition plays.\n * @fires swc-close - Dispatched when the tooltip begins to close, before the transition plays.\n * @fires swc-after-open - Dispatched after the tooltip finishes opening, once the transition completes.\n * @fires swc-after-close - Dispatched after the tooltip finishes closing, once the transition completes.\n */\nexport abstract class TooltipBase\n extends SpectrumElement\n implements HoverControllerHost\n{\n // ──────────────────\n // SHARED API\n // ──────────────────\n\n /**\n * @internal\n *\n * All valid variants for the tooltip.\n */\n static readonly VARIANTS: readonly string[] = TOOLTIP_VARIANTS;\n\n /**\n * @internal\n *\n * All valid placement values: physical cardinals (`top`, `bottom`, `left`, `right`)\n * and logical inline values (`start`, `end`).\n */\n static readonly PLACEMENTS: readonly string[] = TOOLTIP_PLACEMENTS;\n\n /**\n * The semantic variant of the tooltip.\n *\n * @default 'neutral'\n */\n @property({ type: String, reflect: true })\n public variant: TooltipVariant = 'neutral';\n\n /**\n * Preferred placement of the tooltip relative to its trigger. This is always\n * the consumer's requested side; the resolved physical side (after any\n * viewport-driven flip) is reflected as `actual-placement`.\n *\n * @default 'top'\n */\n @property({ type: String, reflect: true })\n public placement: TooltipPlacement = 'top';\n\n /**\n * Whether the tooltip is visible.\n *\n * @default false\n */\n @property({ type: Boolean, reflect: true })\n public open: boolean = false;\n\n /**\n * The `id` of the trigger element in the same document tree root.\n */\n @property({ attribute: 'for', type: String })\n public for: string | undefined;\n\n /**\n * Explicit trigger element reference; overrides `for` when set.\n * Use when `getElementById` cannot reach the trigger, such as across a shadow boundary.\n *\n * @default null\n */\n @property({ attribute: false })\n public triggerElement: HTMLElement | null = null;\n\n /**\n * Warm-up delay in milliseconds before the tooltip opens on pointer hover.\n * Set to `0` to open immediately. Keyboard focus always opens immediately.\n *\n * @default 1500\n */\n @property({ type: Number, reflect: true })\n public delay: number = 1500;\n\n /**\n * When set, the tooltip does not respond to hover or focus events and cannot\n * be opened. `disabled` takes priority over `open`: setting `open` to `true`\n * while disabled is a no-op, and disabling an open tooltip closes it. Applies\n * in `manual` mode as well.\n *\n * @default false\n */\n @property({ type: Boolean, reflect: true })\n public disabled: boolean = false;\n\n /**\n * Suppresses automatic hover and focus wiring.\n * The consumer manages visibility via the `open` property or the popover API.\n *\n * @default false\n */\n @property({ type: Boolean, reflect: true })\n public manual: boolean = false;\n\n /**\n * Pixel gap along the placement axis between the trigger and the tooltip bubble.\n *\n * @default 4\n */\n @property({ type: Number })\n public offset: number = 4;\n\n /**\n * Slide along the trigger edge perpendicular to the placement direction, in pixels.\n *\n * @default 0\n */\n @property({ type: Number, attribute: 'cross-offset' })\n public crossOffset: number = 0;\n\n /**\n * Minimum inset from the viewport edge, in pixels, for collision detection.\n *\n * @default 12\n */\n @property({ type: Number, attribute: 'container-padding' })\n public containerPadding: number = 12;\n\n /**\n * Whether the tooltip may reposition to the opposite side when the requested\n * placement does not fit within the viewport.\n *\n * @default true\n */\n @property({ type: Boolean, attribute: 'should-flip' })\n public shouldFlip: boolean = true;\n\n /**\n * When set, the tooltip acts as the trigger's accessible name rather than its description.\n * Use for icon-only triggers where the tooltip text is the sole accessible name.\n *\n * @default false\n */\n @property({ type: Boolean, reflect: true })\n public labeling: boolean = false;\n\n // ──────────────────────\n // IMPLEMENTATION\n // ──────────────────────\n\n private readonly hoverController = new HoverController(this, {\n warmStateKey: 'swc-tooltip',\n });\n\n private readonly placementController = new PlacementController(this);\n\n // Guards dispatchAfterEvent so only the first transitionend per open/close cycle fires,\n // preventing one after event from firing for each CSS property that transitions.\n private afterEventPending = false;\n\n // Fallback timer for browsers that do not fire transitionend for\n // transition-behavior:allow-discrete discrete properties (e.g. Firefox in CI).\n // Cleared when transitionend fires or a new toggle starts.\n private afterEventFallbackTimer: ReturnType<typeof setTimeout> | null = null;\n\n // Tracks the most recently ARIA-wired target so syncAriaRelationship can\n // remove stale references when for or triggerElement changes while open.\n private _lastWiredTrigger:\n | (Element & {\n ariaDescribedByElements: Element[] | null;\n ariaLabelledByElements: Element[] | null;\n })\n | null = null;\n\n /**\n * Returns the tip arrow element to pass to `PlacementController` so the\n * `arrow` middleware keeps the tip aligned with the trigger when the bubble\n * is shifted (e.g. via `crossOffset` or viewport `shift`).\n *\n * Returns `null` in the base class; the SWC rendering layer overrides this\n * to return the actual `.swc-Tooltip-tip` element from the shadow DOM.\n */\n protected get tipElement(): HTMLElement | null {\n return null;\n }\n\n // Reflects the browser's actual popover state. Used in updated() to reconcile\n // `open` against native light-dismiss: when the browser closes the popover\n // (e.g. Escape or outside click), `open` is synced by the toggle listener\n // without re-invoking the Popover API, and the guard prevents a redundant\n // hidePopover() (which would throw on an already-closed popover).\n private get isPopoverOpen(): boolean {\n return this.matches(':popover-open');\n }\n\n /**\n * {@link HoverControllerHost} contract. `open` is the single source of truth\n * for visibility; the controller asks to open via this method rather than\n * driving the Popover API directly. `updated()` then reconciles the popover.\n */\n public requestOpen(): void {\n this.open = true;\n }\n\n /**\n * {@link HoverControllerHost} contract. Asks the tooltip to close by setting\n * `open`; `updated()` reconciles the popover.\n */\n public requestClose(): void {\n this.open = false;\n }\n\n // Writes actual-placement to the physical side of the declared `placement`,\n // resolving logical start/end against the trigger's writing direction. Used\n // synchronously before showPopover() so @starting-style has a direction; the\n // PlacementController overwrites it with the flip-resolved side afterwards.\n private setDeclaredActualPlacement(): void {\n const trigger = this.resolveTrigger();\n const direction =\n trigger && getComputedStyle(trigger).direction === 'rtl' ? 'rtl' : 'ltr';\n const side = fromFloatingPlacement(\n toFloatingPlacement(this.placement as ControllerPlacement, direction)\n ).split('-')[0];\n this.setAttribute('actual-placement', side);\n }\n\n private startPlacement(): void {\n const trigger = this.resolveTrigger();\n if (!trigger) {\n return;\n }\n this.placementController.start(trigger, this, {\n placement: this.placement as ControllerPlacement,\n offset: this.offset,\n crossOffset: this.crossOffset,\n containerPadding: this.containerPadding,\n shouldFlip: this.shouldFlip,\n tipElement: this.tipElement ?? undefined,\n onPlacementChange: (resolvedPlacement: ControllerPlacement) => {\n this.setAttribute('actual-placement', resolvedPlacement.split('-')[0]);\n },\n });\n }\n\n private resolveTrigger(): HTMLElement | null {\n if (this.triggerElement) {\n return this.triggerElement;\n }\n if (this.for) {\n const root = this.getRootNode() as Document | ShadowRoot;\n const trigger = root.getElementById(this.for);\n if (!trigger && 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://opensource.adobe.com/spectrum-web-components/components/tooltip/',\n { level: 'high' }\n );\n }\n return trigger;\n }\n return null;\n }\n\n // Removes this tooltip from the previously wired target's ARIA element arrays\n // and forgets the reference. Called before re-wiring and on disconnect so a\n // trigger never retains a reference to a detached tooltip node.\n private clearAriaRelationship(): void {\n if (!this._lastWiredTrigger) {\n return;\n }\n const stale = this._lastWiredTrigger;\n stale.ariaDescribedByElements = (\n stale.ariaDescribedByElements ?? []\n ).filter((el) => el !== this);\n stale.ariaLabelledByElements = (stale.ariaLabelledByElements ?? []).filter(\n (el) => el !== this\n );\n this._lastWiredTrigger = null;\n }\n\n private syncAriaRelationship(): void {\n // Remove stale references from the previously wired target before resolving\n // the new one. Handles for/triggerElement changes while the tooltip is open.\n this.clearAriaRelationship();\n\n const trigger = this.resolveTrigger();\n if (!trigger) {\n return;\n }\n const target = (trigger.shadowRoot?.querySelector('button') ??\n trigger) as Element & {\n ariaDescribedByElements: Element[] | null;\n ariaLabelledByElements: Element[] | null;\n };\n\n if (this.labeling) {\n // Remove any stale describedby reference (e.g. if labeling changed while open).\n const described = target.ariaDescribedByElements ?? [];\n target.ariaDescribedByElements = described.filter((el) => el !== this);\n\n const labelled = target.ariaLabelledByElements ?? [];\n target.ariaLabelledByElements = this.open\n ? [...labelled.filter((el) => el !== this), this]\n : labelled.filter((el) => el !== this);\n } else {\n // Remove any stale labelledby reference (e.g. if labeling changed while open).\n const labelled = target.ariaLabelledByElements ?? [];\n target.ariaLabelledByElements = labelled.filter((el) => el !== this);\n\n const described = target.ariaDescribedByElements ?? [];\n target.ariaDescribedByElements = this.open\n ? [...described.filter((el) => el !== this), this]\n : described.filter((el) => el !== this);\n }\n\n if (this.open) {\n this._lastWiredTrigger = target;\n }\n }\n\n private clearPositioningState(): void {\n // Called after the exit transition. Clearing earlier would displace the\n // tooltip to 0,0 while still visible and fading out.\n this.removeAttribute('actual-placement');\n this.style.removeProperty('translate');\n this.style.removeProperty('top');\n this.style.removeProperty('left');\n this.style.removeProperty('--swc-placement-available-width');\n this.style.removeProperty('--swc-placement-available-height');\n if (this.tipElement) {\n this.tipElement.style.removeProperty('translate');\n this.tipElement.style.removeProperty('top');\n this.tipElement.style.removeProperty('left');\n }\n }\n\n private dispatchAfterEvent(isOpen: boolean): void {\n this.dispatchEvent(\n new CustomEvent(isOpen ? 'swc-after-open' : 'swc-after-close', {\n bubbles: true,\n composed: true,\n })\n );\n if (!isOpen) {\n this.clearPositioningState();\n }\n }\n\n private readonly handleBeforeToggle = (event: Event): void => {\n const { newState } = event as ToggleEvent;\n const eventName = newState === 'open' ? 'swc-open' : 'swc-close';\n this.dispatchEvent(\n new CustomEvent(eventName, { bubbles: true, composed: true })\n );\n // Set here so the flag is set regardless of whether this.open already matches\n // newState. handleToggle exits early when open was set externally, which would\n // otherwise leave the flag unset and suppress swc-after-open / swc-after-close.\n this.afterEventPending = true;\n };\n\n private readonly handleToggle = (event: Event): void => {\n // Cancel any in-flight close fallback; a new toggle resets the cycle.\n if (this.afterEventFallbackTimer !== null) {\n clearTimeout(this.afterEventFallbackTimer);\n this.afterEventFallbackTimer = null;\n }\n const { newState } = event as ToggleEvent;\n const isOpen = newState === 'open';\n if (isOpen !== this.open) {\n this.open = isOpen;\n }\n // When no CSS transition is active, dispatch after-* immediately since transitionend will not fire.\n // transitionDuration is comma-separated when multiple properties transition (\"0s, 0s, …\"),\n // so check that every value in the list is zero rather than comparing the full string.\n const durations = getComputedStyle(this).transitionDuration.split(',');\n if (durations.every((d) => d.trim() === '0s')) {\n this.afterEventPending = false;\n this.dispatchAfterEvent(isOpen);\n } else if (!isOpen) {\n // Some browsers (e.g. Firefox in CI) do not fire transitionend for\n // transition-behavior:allow-discrete discrete properties. Start a fallback\n // so positioning is always cleared after the exit transition window.\n const maxMs = Math.max(\n 0,\n ...durations.map((d) => {\n const trimmed = d.trim();\n const value = parseFloat(trimmed);\n return trimmed.endsWith('ms') ? value : value * 1000;\n })\n );\n this.afterEventFallbackTimer = setTimeout(() => {\n this.afterEventFallbackTimer = null;\n if (this.afterEventPending) {\n this.afterEventPending = false;\n this.dispatchAfterEvent(false);\n }\n }, maxMs + 100);\n }\n };\n\n private readonly handleTransitionEnd = (event: TransitionEvent): void => {\n if (event.target !== this || !this.afterEventPending) {\n return;\n }\n if (this.afterEventFallbackTimer !== null) {\n clearTimeout(this.afterEventFallbackTimer);\n this.afterEventFallbackTimer = null;\n }\n this.afterEventPending = false;\n this.dispatchAfterEvent(this.open);\n };\n\n // Escape-to-close. Registered on `document` only while open (see updated()),\n // not for the whole connected lifetime: the tooltip is non-interactive and\n // never receives focus, so a host-level keydown would not fire, and scoping to\n // the open state keeps at most one listener active at a time (popover=\"auto\"\n // permits one open tooltip). Under `popover=\"auto\"` this duplicates the\n // browser's native Escape light-dismiss; it is kept as a mode-independent\n // handler so a `manual` tooltip (which gets no native light-dismiss, e.g. one\n // that coexists with an open popover) still closes on Escape.\n private readonly handleKeyDown = (event: KeyboardEvent): void => {\n if (event.key === 'Escape' && this.open) {\n this.open = false;\n }\n };\n\n protected override willUpdate(changedProperties: PropertyValues): void {\n super.willUpdate(changedProperties);\n // `disabled` takes priority over `open`: a disabled tooltip cannot be shown,\n // regardless of how `open` became true (set programmatically, or `disabled`\n // toggled on while already open). Normalizing here — before render and\n // before updated() acts on `open` — keeps `open` and visibility consistent\n // and prevents the `open` attribute from briefly reflecting `true`. Hover\n // and focus opening are separately blocked by HoverController's guards.\n if (this.disabled && this.open) {\n this.open = false;\n }\n }\n\n protected override updated(changedProperties: PropertyValues): void {\n super.updated(changedProperties);\n if (changedProperties.has('offset')) {\n this.style.setProperty(\n '--_swc-tooltip-animation-distance',\n `${this.offset}px`\n );\n }\n if (\n changedProperties.has('open') ||\n changedProperties.has('labeling') ||\n changedProperties.has('for') ||\n changedProperties.has('triggerElement')\n ) {\n this.syncAriaRelationship();\n }\n if (\n changedProperties.has('for') ||\n changedProperties.has('triggerElement')\n ) {\n this.hoverController.setTarget(this.resolveTrigger());\n }\n\n // Placement controller: start when opening, stop when closing, restart\n // when positioning options or the trigger change while already open.\n const openChanged = changedProperties.has('open');\n if (openChanged) {\n if (this.open) {\n // Register Escape handling only while open; removed on close below.\n document.addEventListener('keydown', this.handleKeyDown);\n // Set actual-placement to the declared side synchronously, before\n // showPopover(). @starting-style is evaluated by the browser the moment\n // the popover enters the top layer, so the direction-bearing attribute\n // must already be present or the entrance animation has no direction to\n // animate from. PlacementController writes actual-placement again from\n // onPlacementChange, but that is async (it awaits document.fonts.ready),\n // so it lands after showPopover() — too late for @starting-style. The\n // popover is display:none until shown and therefore unmeasurable, so a\n // viewport flip cannot be known here; on a flip the resolved side\n // arrives from onPlacementChange and the slide direction corrects then.\n this.setDeclaredActualPlacement();\n this.startPlacement();\n if (this.open !== this.isPopoverOpen) {\n this.showPopover();\n }\n } else {\n document.removeEventListener('keydown', this.handleKeyDown);\n if (this.open !== this.isPopoverOpen) {\n this.hidePopover();\n }\n // Stop autoUpdate immediately so positioning stops tracking the trigger\n // during the exit transition. clearPositioningState() runs after the\n // transition completes via dispatchAfterEvent.\n this.placementController.stop();\n }\n } else if (this.open) {\n const placementOptsChanged =\n changedProperties.has('placement') ||\n changedProperties.has('offset') ||\n changedProperties.has('crossOffset') ||\n changedProperties.has('containerPadding') ||\n changedProperties.has('shouldFlip') ||\n changedProperties.has('for') ||\n changedProperties.has('triggerElement');\n if (placementOptsChanged) {\n this.startPlacement();\n }\n }\n }\n\n public override connectedCallback(): void {\n super.connectedCallback();\n this.setAttribute('role', 'tooltip');\n this.setAttribute('popover', 'auto');\n this.addEventListener('beforetoggle', this.handleBeforeToggle);\n this.addEventListener('toggle', this.handleToggle);\n this.addEventListener('transitionend', this.handleTransitionEnd);\n }\n\n public override disconnectedCallback(): void {\n super.disconnectedCallback();\n this.removeEventListener('beforetoggle', this.handleBeforeToggle);\n this.removeEventListener('toggle', this.handleToggle);\n this.removeEventListener('transitionend', this.handleTransitionEnd);\n // Defensive: the keydown listener is normally removed on close, but a\n // tooltip disconnected while open would still have it registered.\n document.removeEventListener('keydown', this.handleKeyDown);\n if (this.afterEventFallbackTimer !== null) {\n clearTimeout(this.afterEventFallbackTimer);\n this.afterEventFallbackTimer = null;\n }\n // If the tooltip is removed while open, the trigger would otherwise retain a\n // reference to this now-detached node in its ARIA element arrays.\n this.clearAriaRelationship();\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"Tooltip.base.js","names":[],"sources":["../../../components/tooltip/Tooltip.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 {\n isTopDismissible,\n registerDismissible,\n unregisterDismissible,\n validateEnum,\n warnIf,\n} from '@adobe/spectrum-wc-core/utils/index.js';\n\nimport {\n HoverController,\n type HoverControllerHost,\n} from '../../controllers/hover-controller/index.js';\nimport {\n fromFloatingPlacement,\n type Placement as ControllerPlacement,\n PlacementController,\n toFloatingPlacement,\n} from '../../controllers/placement-controller/index.js';\nimport {\n TOOLTIP_PLACEMENTS,\n TOOLTIP_VARIANTS,\n type TooltipPlacement,\n type TooltipVariant,\n} from './Tooltip.types.js';\n\n// Currently shown tooltip. `popover=\"manual\"` drops the native auto singleton, so\n// restore it explicitly: one tooltip open at a time across all instances.\nlet openTooltip: TooltipBase | null = null;\n\n/**\n * Abstract base class for the Tooltip component.\n * Handles all non-rendering logic: property declarations, popover lifecycle,\n * event dispatch, trigger resolution, ARIA wiring, `HoverController` integration\n * (hover/focus open/close), and `PlacementController` integration (pixel positioning).\n *\n * @slot - Text label displayed in the tooltip.\n *\n * @fires swc-open - Dispatched when the tooltip begins to open, before the transition plays.\n * @fires swc-close - Dispatched when the tooltip begins to close, before the transition plays.\n * @fires swc-after-open - Dispatched after the tooltip finishes opening, once the transition completes.\n * @fires swc-after-close - Dispatched after the tooltip finishes closing, once the transition completes.\n */\nexport abstract class TooltipBase\n extends SpectrumElement\n implements HoverControllerHost\n{\n // ──────────────────\n // SHARED API\n // ──────────────────\n\n /**\n * @internal\n *\n * All valid variants for the tooltip.\n */\n static readonly VARIANTS: readonly string[] = TOOLTIP_VARIANTS;\n\n /**\n * @internal\n *\n * All valid placement values: physical cardinals (`top`, `bottom`, `left`, `right`)\n * and logical inline values (`start`, `end`).\n */\n static readonly PLACEMENTS: readonly string[] = TOOLTIP_PLACEMENTS;\n\n /**\n * The semantic variant of the tooltip.\n *\n * @default 'neutral'\n */\n @property({ type: String, reflect: true })\n public variant: TooltipVariant = 'neutral';\n\n /**\n * Preferred placement of the tooltip relative to its trigger. This is always\n * the consumer's requested side; the resolved physical side (after any\n * viewport-driven flip) is reflected as `actual-placement`.\n *\n * @default 'top'\n */\n @property({ type: String, reflect: true })\n public placement: TooltipPlacement = 'top';\n\n /**\n * Whether the tooltip is visible.\n *\n * @default false\n */\n @property({ type: Boolean, reflect: true })\n public open: boolean = false;\n\n /**\n * The `id` of the trigger element in the same document tree root.\n */\n @property({ attribute: 'for', type: String })\n public for: string | undefined;\n\n /**\n * Explicit trigger element reference; overrides `for` when set.\n * Use when `getElementById` cannot reach the trigger, such as across a shadow boundary.\n *\n * @default null\n */\n @property({ attribute: false })\n public triggerElement: HTMLElement | null = null;\n\n /**\n * Warm-up delay in milliseconds before the tooltip opens on pointer hover.\n * Set to `0` to open immediately. Keyboard focus always opens immediately.\n *\n * @default 1500\n */\n @property({ type: Number, reflect: true })\n public delay: number = 1500;\n\n /**\n * When set, the tooltip does not respond to hover or focus events and cannot\n * be opened. `disabled` takes priority over `open`: setting `open` to `true`\n * while disabled is a no-op, and disabling an open tooltip closes it. Applies\n * in `manual` mode as well.\n *\n * @default false\n */\n @property({ type: Boolean, reflect: true })\n public disabled: boolean = false;\n\n /**\n * Suppresses automatic hover and focus wiring.\n * The consumer manages visibility via the `open` property or the popover API.\n *\n * @default false\n */\n @property({ type: Boolean, reflect: true })\n public manual: boolean = false;\n\n /**\n * Pixel gap along the placement axis between the trigger and the tooltip bubble.\n *\n * @default 4\n */\n @property({ type: Number })\n public offset: number = 4;\n\n /**\n * Slide along the trigger edge perpendicular to the placement direction, in pixels.\n *\n * @default 0\n */\n @property({ type: Number, attribute: 'cross-offset' })\n public crossOffset: number = 0;\n\n /**\n * Minimum inset from the viewport edge, in pixels, for collision detection.\n *\n * @default 12\n */\n @property({ type: Number, attribute: 'container-padding' })\n public containerPadding: number = 12;\n\n /**\n * Whether the tooltip may reposition to the opposite side when the requested\n * placement does not fit within the viewport.\n *\n * @default true\n */\n @property({ type: Boolean, attribute: 'should-flip' })\n public shouldFlip: boolean = true;\n\n /**\n * When set, the tooltip acts as the trigger's accessible name rather than its description.\n * Use for icon-only triggers where the tooltip text is the sole accessible name.\n *\n * @default false\n */\n @property({ type: Boolean, reflect: true })\n public labeling: boolean = false;\n\n // ──────────────────────\n // IMPLEMENTATION\n // ──────────────────────\n\n private readonly hoverController = new HoverController(this, {\n warmStateKey: 'swc-tooltip',\n });\n\n private readonly placementController = new PlacementController(this);\n\n // Guards dispatchAfterEvent so only the first transitionend per open/close cycle fires,\n // preventing one after event from firing for each CSS property that transitions.\n private afterEventPending = false;\n\n // Fallback timer for browsers that do not fire transitionend for\n // transition-behavior:allow-discrete discrete properties (e.g. Firefox in CI).\n // Cleared when transitionend fires or a new toggle starts.\n private afterEventFallbackTimer: ReturnType<typeof setTimeout> | null = null;\n\n // Tracks the most recently ARIA-wired target so syncAriaRelationship can\n // remove stale references when for or triggerElement changes while open.\n private _lastWiredTrigger:\n | (Element & {\n ariaDescribedByElements: Element[] | null;\n ariaLabelledByElements: Element[] | null;\n })\n | null = null;\n\n /**\n * Returns the tip arrow element to pass to `PlacementController` so the\n * `arrow` middleware keeps the tip aligned with the trigger when the bubble\n * is shifted (e.g. via `crossOffset` or viewport `shift`).\n *\n * Returns `null` in the base class; the SWC rendering layer overrides this\n * to return the actual `.swc-Tooltip-tip` element from the shadow DOM.\n */\n protected get tipElement(): HTMLElement | null {\n return null;\n }\n\n // Reflects the browser's actual popover state. Used in updated() to reconcile\n // `open` against the native popover state: when a `toggle` event syncs `open`\n // (the toggle listener sets it without re-invoking the Popover API), this\n // guard prevents a redundant showPopover()/hidePopover() call in the following\n // update (hidePopover() would throw on an already-closed popover). Under\n // `popover=\"manual\"` the browser never closes the tooltip on its own, so the\n // only driver is the component itself, but the guard is still needed to keep\n // the `open`-driven and toggle-driven paths from double-invoking the API.\n private get isPopoverOpen(): boolean {\n return this.matches(':popover-open');\n }\n\n /**\n * {@link HoverControllerHost} contract. `open` is the single source of truth\n * for visibility; the controller asks to open via this method rather than\n * driving the Popover API directly. `updated()` then reconciles the popover.\n */\n public requestOpen(): void {\n this.open = true;\n }\n\n /**\n * {@link HoverControllerHost} contract. Asks the tooltip to close by setting\n * `open`; `updated()` reconciles the popover.\n */\n public requestClose(): void {\n this.open = false;\n }\n\n // Writes actual-placement to the physical side of the declared `placement`,\n // resolving logical start/end against the trigger's writing direction. Used\n // synchronously before showPopover() so @starting-style has a direction; the\n // PlacementController overwrites it with the flip-resolved side afterwards.\n private setDeclaredActualPlacement(): void {\n const trigger = this.resolveTrigger();\n const direction =\n trigger && getComputedStyle(trigger).direction === 'rtl' ? 'rtl' : 'ltr';\n const side = fromFloatingPlacement(\n toFloatingPlacement(this.placement as ControllerPlacement, direction)\n ).split('-')[0];\n this.setAttribute('actual-placement', side);\n }\n\n private startPlacement(): void {\n const trigger = this.resolveTrigger();\n if (!trigger) {\n return;\n }\n this.placementController.start(trigger, this, {\n placement: this.placement as ControllerPlacement,\n offset: this.offset,\n crossOffset: this.crossOffset,\n containerPadding: this.containerPadding,\n shouldFlip: this.shouldFlip,\n tipElement: this.tipElement ?? undefined,\n onPlacementChange: (resolvedPlacement: ControllerPlacement) => {\n this.setAttribute('actual-placement', resolvedPlacement.split('-')[0]);\n },\n });\n }\n\n private resolveTrigger(): HTMLElement | null {\n if (this.triggerElement) {\n return this.triggerElement;\n }\n if (this.for) {\n const root = this.getRootNode() as Document | ShadowRoot;\n const trigger = root.getElementById(this.for);\n warnIf(\n this,\n !trigger,\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-tooltip--docs',\n { level: 'high' }\n );\n return trigger;\n }\n return null;\n }\n\n // Removes this tooltip from the previously wired target's ARIA element arrays\n // and forgets the reference. Called before re-wiring and on disconnect so a\n // trigger never retains a reference to a detached tooltip node.\n private clearAriaRelationship(): void {\n if (!this._lastWiredTrigger) {\n return;\n }\n const stale = this._lastWiredTrigger;\n stale.ariaDescribedByElements = (\n stale.ariaDescribedByElements ?? []\n ).filter((el) => el !== this);\n stale.ariaLabelledByElements = (stale.ariaLabelledByElements ?? []).filter(\n (el) => el !== this\n );\n this._lastWiredTrigger = null;\n }\n\n private syncAriaRelationship(): void {\n // Remove stale references from the previously wired target before resolving\n // the new one. Handles for/triggerElement changes while the tooltip is open.\n this.clearAriaRelationship();\n\n const trigger = this.resolveTrigger();\n if (!trigger) {\n return;\n }\n const target = (trigger.shadowRoot?.querySelector('button') ??\n trigger) as Element & {\n ariaDescribedByElements: Element[] | null;\n ariaLabelledByElements: Element[] | null;\n };\n\n if (this.labeling) {\n // Remove any stale describedby reference (e.g. if labeling changed while open).\n const described = target.ariaDescribedByElements ?? [];\n target.ariaDescribedByElements = described.filter((el) => el !== this);\n\n const labelled = target.ariaLabelledByElements ?? [];\n target.ariaLabelledByElements = this.open\n ? [...labelled.filter((el) => el !== this), this]\n : labelled.filter((el) => el !== this);\n } else {\n // Remove any stale labelledby reference (e.g. if labeling changed while open).\n const labelled = target.ariaLabelledByElements ?? [];\n target.ariaLabelledByElements = labelled.filter((el) => el !== this);\n\n const described = target.ariaDescribedByElements ?? [];\n target.ariaDescribedByElements = this.open\n ? [...described.filter((el) => el !== this), this]\n : described.filter((el) => el !== this);\n }\n\n if (this.open) {\n this._lastWiredTrigger = target;\n }\n }\n\n private clearPositioningState(): void {\n // Called after the exit transition. Clearing earlier would displace the\n // tooltip to 0,0 while still visible and fading out.\n this.removeAttribute('actual-placement');\n this.style.removeProperty('translate');\n this.style.removeProperty('top');\n this.style.removeProperty('left');\n this.style.removeProperty('--swc-placement-available-width');\n this.style.removeProperty('--swc-placement-available-height');\n if (this.tipElement) {\n this.tipElement.style.removeProperty('translate');\n this.tipElement.style.removeProperty('top');\n this.tipElement.style.removeProperty('left');\n }\n }\n\n private dispatchAfterEvent(isOpen: boolean): void {\n this.dispatchEvent(\n new CustomEvent(isOpen ? 'swc-after-open' : 'swc-after-close', {\n bubbles: true,\n composed: true,\n })\n );\n if (!isOpen) {\n this.clearPositioningState();\n }\n }\n\n private readonly handleBeforeToggle = (event: Event): void => {\n const { newState } = event as ToggleEvent;\n const eventName = newState === 'open' ? 'swc-open' : 'swc-close';\n this.dispatchEvent(\n new CustomEvent(eventName, { bubbles: true, composed: true })\n );\n // Set here so the flag is set regardless of whether this.open already matches\n // newState. handleToggle exits early when open was set externally, which would\n // otherwise leave the flag unset and suppress swc-after-open / swc-after-close.\n this.afterEventPending = true;\n };\n\n private readonly handleToggle = (event: Event): void => {\n // Cancel any in-flight close fallback; a new toggle resets the cycle.\n if (this.afterEventFallbackTimer !== null) {\n clearTimeout(this.afterEventFallbackTimer);\n this.afterEventFallbackTimer = null;\n }\n const { newState } = event as ToggleEvent;\n const isOpen = newState === 'open';\n if (isOpen !== this.open) {\n this.open = isOpen;\n }\n // When no CSS transition is active, dispatch after-* immediately since transitionend will not fire.\n // transitionDuration is comma-separated when multiple properties transition (\"0s, 0s, …\"),\n // so check that every value in the list is zero rather than comparing the full string.\n const durations = getComputedStyle(this).transitionDuration.split(',');\n if (durations.every((d) => d.trim() === '0s')) {\n this.afterEventPending = false;\n this.dispatchAfterEvent(isOpen);\n } else if (!isOpen) {\n // Some browsers (e.g. Firefox in CI) do not fire transitionend for\n // transition-behavior:allow-discrete discrete properties. Start a fallback\n // so positioning is always cleared after the exit transition window.\n const maxMs = Math.max(\n 0,\n ...durations.map((d) => {\n const trimmed = d.trim();\n const value = parseFloat(trimmed);\n return trimmed.endsWith('ms') ? value : value * 1000;\n })\n );\n this.afterEventFallbackTimer = setTimeout(() => {\n this.afterEventFallbackTimer = null;\n if (this.afterEventPending) {\n this.afterEventPending = false;\n this.dispatchAfterEvent(false);\n }\n }, maxMs + 100);\n }\n };\n\n private readonly handleTransitionEnd = (event: TransitionEvent): void => {\n if (event.target !== this || !this.afterEventPending) {\n return;\n }\n if (this.afterEventFallbackTimer !== null) {\n clearTimeout(this.afterEventFallbackTimer);\n this.afterEventFallbackTimer = null;\n }\n this.afterEventPending = false;\n this.dispatchAfterEvent(this.open);\n };\n\n // Escape-to-close. Registered on `document` (capture) only while open (see\n // updated()); `popover=\"manual\"` gets no native light-dismiss, so this is the\n // sole Escape mechanism.\n private readonly handleKeyDown = (event: KeyboardEvent): void => {\n if (event.key !== 'Escape' || !this.open) {\n return;\n }\n // Only the topmost dismissible handles Escape; a surface above us gets it first.\n if (!isTopDismissible(this)) {\n return;\n }\n // A `manual` tooltip is outside the browser's auto-popover stack, so cancel\n // the native default (capture phase, before it runs) to keep an `auto`\n // popover underneath open; a later Escape, once we are gone, closes it.\n event.preventDefault();\n this.open = false;\n };\n\n protected override willUpdate(changedProperties: PropertyValues): void {\n super.willUpdate(changedProperties);\n // `disabled` takes priority over `open`: a disabled tooltip cannot be shown,\n // regardless of how `open` became true (set programmatically, or `disabled`\n // toggled on while already open). Normalizing here — before render and\n // before updated() acts on `open` — keeps `open` and visibility consistent\n // and prevents the `open` attribute from briefly reflecting `true`. Hover\n // and focus opening are separately blocked by HoverController's guards.\n if (this.disabled && this.open) {\n this.open = false;\n }\n\n if (changedProperties.has('variant')) {\n const constructor = this.constructor as typeof TooltipBase;\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-tooltip--docs',\n });\n }\n if (changedProperties.has('placement')) {\n const constructor = this.constructor as typeof TooltipBase;\n validateEnum(this, {\n prop: 'placement',\n value: this.placement,\n valid: constructor.PLACEMENTS,\n url: 'https://spectrum-web-components.adobe.com/?path=/docs/components-tooltip--docs',\n });\n }\n }\n\n protected override updated(changedProperties: PropertyValues): void {\n super.updated(changedProperties);\n if (changedProperties.has('variant')) {\n const constructor = this.constructor as typeof TooltipBase;\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-tooltip--docs',\n });\n }\n if (changedProperties.has('placement')) {\n const constructor = this.constructor as typeof TooltipBase;\n validateEnum(this, {\n prop: 'placement',\n value: this.placement,\n valid: constructor.PLACEMENTS,\n url: 'https://spectrum-web-components.adobe.com/?path=/docs/components-tooltip--docs',\n });\n }\n if (changedProperties.has('offset')) {\n this.style.setProperty(\n '--_swc-tooltip-animation-distance',\n `${this.offset}px`\n );\n }\n if (\n changedProperties.has('open') ||\n changedProperties.has('labeling') ||\n changedProperties.has('for') ||\n changedProperties.has('triggerElement')\n ) {\n this.syncAriaRelationship();\n }\n if (\n changedProperties.has('for') ||\n changedProperties.has('triggerElement')\n ) {\n this.hoverController.setTarget(this.resolveTrigger());\n }\n\n // Placement controller: start when opening, stop when closing, restart\n // when positioning options or the trigger change while already open.\n const openChanged = changedProperties.has('open');\n if (openChanged) {\n if (this.open) {\n // The single-open singleton restores popover=\"auto\"'s \"one open at a\n // time\" for automatic (hover/focus) tooltips. A `manual` tooltip is\n // consumer-managed and opts out, so several can coexist (e.g. a coach-mark\n // tour that points at multiple controls at once); it neither closes others\n // nor claims the singleton slot.\n if (!this.manual) {\n // Close any other open tooltip first. Assign after requestClose() so\n // the other's updated() (else branch) does not clear the reference we take.\n if (openTooltip && openTooltip !== this) {\n openTooltip.requestClose();\n }\n // eslint-disable-next-line @typescript-eslint/no-this-alias -- singleton registration, not a closure capture\n openTooltip = this;\n }\n // Join the dismissible stack and Escape handling while open (both torn\n // down on close below). Capture phase so preventDefault() beats the\n // native popover light-dismiss (see handleKeyDown).\n registerDismissible(this);\n document.addEventListener('keydown', this.handleKeyDown, {\n capture: true,\n });\n // Set actual-placement to the declared side synchronously, before\n // showPopover(). @starting-style is evaluated by the browser the moment\n // the popover enters the top layer, so the direction-bearing attribute\n // must already be present or the entrance animation has no direction to\n // animate from. PlacementController writes actual-placement again from\n // onPlacementChange, but that is async (it awaits document.fonts.ready),\n // so it lands after showPopover() — too late for @starting-style. The\n // popover is display:none until shown and therefore unmeasurable, so a\n // viewport flip cannot be known here; on a flip the resolved side\n // arrives from onPlacementChange and the slide direction corrects then.\n this.setDeclaredActualPlacement();\n this.startPlacement();\n if (this.open !== this.isPopoverOpen) {\n this.showPopover();\n }\n } else {\n if (openTooltip === this) {\n openTooltip = null;\n }\n unregisterDismissible(this);\n document.removeEventListener('keydown', this.handleKeyDown, {\n capture: true,\n });\n if (this.open !== this.isPopoverOpen) {\n this.hidePopover();\n }\n // Stop autoUpdate immediately so positioning stops tracking the trigger\n // during the exit transition. clearPositioningState() runs after the\n // transition completes via dispatchAfterEvent.\n this.placementController.stop();\n }\n } else if (this.open) {\n const placementOptsChanged =\n changedProperties.has('placement') ||\n changedProperties.has('offset') ||\n changedProperties.has('crossOffset') ||\n changedProperties.has('containerPadding') ||\n changedProperties.has('shouldFlip') ||\n changedProperties.has('for') ||\n changedProperties.has('triggerElement');\n if (placementOptsChanged) {\n this.startPlacement();\n }\n }\n }\n\n public override connectedCallback(): void {\n super.connectedCallback();\n this.setAttribute('role', 'tooltip');\n // `manual`, not `auto`: a tooltip must coexist with an open `swc-popover`\n // (or menu/picker/select). Under `popover=\"auto\"` the native light-dismiss\n // group closes every other open auto popover the moment a tooltip opens on\n // hover, tearing down an open popover the user is still working in. `manual`\n // takes the tooltip out of that group. The behaviors `manual` drops are\n // already handled internally: Escape via handleKeyDown (registered while\n // open) and close-on-leave via HoverController; show/hide is driven\n // explicitly through showPopover()/hidePopover() in updated().\n this.setAttribute('popover', 'manual');\n this.addEventListener('beforetoggle', this.handleBeforeToggle);\n this.addEventListener('toggle', this.handleToggle);\n this.addEventListener('transitionend', this.handleTransitionEnd);\n }\n\n public override disconnectedCallback(): void {\n super.disconnectedCallback();\n // Release the singleton so a detached node is not retained.\n if (openTooltip === this) {\n openTooltip = null;\n }\n this.removeEventListener('beforetoggle', this.handleBeforeToggle);\n this.removeEventListener('toggle', this.handleToggle);\n this.removeEventListener('transitionend', this.handleTransitionEnd);\n // Defensive: clear the stack entry and keydown listener in case the tooltip\n // is disconnected while still open (normally cleared on close).\n unregisterDismissible(this);\n document.removeEventListener('keydown', this.handleKeyDown, {\n capture: true,\n });\n if (this.afterEventFallbackTimer !== null) {\n clearTimeout(this.afterEventFallbackTimer);\n this.afterEventFallbackTimer = null;\n }\n // If the tooltip is removed while open, the trigger would otherwise retain a\n // reference to this now-detached node in its ARIA element arrays.\n this.clearAriaRelationship();\n }\n}\n"],"mappings":"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"}
@@ -1,6 +1,7 @@
1
- import e from "colorjs.io";
1
+ import { isDebug as e } from "@adobe/spectrum-wc-core/utils/index.js";
2
+ import t from "colorjs.io";
2
3
  //#region controllers/color-controller/src/color-controller.ts
3
- var t = [
4
+ var n = [
4
5
  /rgba\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d*\.?\d+)\s*\)/i,
5
6
  /rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)/i,
6
7
  /^rgba\s+(\d{1,3})\s+(\d{1,3})\s+(\d{1,3})\s+(0|0?\.\d+|1)\s*$/i,
@@ -9,30 +10,30 @@ var t = [
9
10
  /^rgb\(\s*(\d{1,3})\s+(\d{1,3})\s+(\d{1,3})\s*\)$/i,
10
11
  /rgb\(\s*(100|[0-9]{1,2}%)\s*,\s*(100|[0-9]{1,2}%)\s*,\s*(100|[0-9]{1,2}%)\s*\)/i,
11
12
  /rgba\(\s*(100|[0-9]{1,2})%\s*,\s*(100|[0-9]{1,2})%\s*,\s*(100|[0-9]{1,2})%\s*,\s*(\d*\.?\d+)\s*\)/i
12
- ], n = [
13
+ ], r = [
13
14
  /hsla\(\s*(\d{1,3})\s*,\s*(\d{1,3}%?)\s*,\s*(\d{1,3}%?)\s*,\s*(\d*\.?\d+)\s*\)/i,
14
15
  /hsl\(\s*(\d{1,3})\s*,\s*(\d{1,3}%?)\s*,\s*(\d{1,3}%?)\s*\)/i,
15
16
  /^hsla\s+(\d{1,3})\s+(\d{1,3}%?)\s+(\d{1,3}%?)\s+(\d*\.?\d+)\s*$/i,
16
17
  /^hsl\s+(\d{1,3})\s+(\d{1,3}%?)\s+(\d{1,3}%?)\s*$/i,
17
18
  /^hsla\(\s*(\d{1,3})\s+(\d{1,3}%?)\s+(\d{1,3}%?)\s+(\d*\.?\d+)\s*\)$/i,
18
19
  /^hsl\(\s*(\d{1,3})\s+(\d{1,3}%?)\s+(\d{1,3}%?)\s*\)$/i
19
- ], r = [
20
+ ], i = [
20
21
  /hsva\(\s*(\d{1,3})\s*,\s*(\d{1,3}%?)\s*,\s*(\d{1,3}%?)\s*,\s*(\d*\.?\d+)\s*\)/i,
21
22
  /hsv\(\s*(\d{1,3})\s*,\s*(\d{1,3}%?)\s*,\s*(\d{1,3}%?)\s*\)/i,
22
23
  /^hsva\s+(\d{1,3})\s+(\d{1,3}%?)\s+(\d{1,3}%?)\s+(\d*\.?\d+)\s*$/i,
23
24
  /^hsv\s+(\d{1,3})\s+(\d{1,3}%?)\s+(\d{1,3}%?)\s*$/i,
24
25
  /^hsva\(\s*(\d{1,3})\s+(\d{1,3}%?)\s+(\d{1,3}%?)\s+(\d*\.?\d+)\s*\)$/i,
25
26
  /^hsv\(\s*(\d{1,3})\s+(\d{1,3}%?)\s+(\d{1,3}%?)\s*\)$/i
26
- ], i = [/^#([A-Fa-f0-9]{6})([A-Fa-f0-9]{2})?$/, /^#([A-Fa-f0-9]{3})([A-Fa-f0-9]{1})?$/], a = [
27
+ ], a = [/^#([A-Fa-f0-9]{6})([A-Fa-f0-9]{2})?$/, /^#([A-Fa-f0-9]{3})([A-Fa-f0-9]{1})?$/], o = [
27
28
  "srgb",
28
29
  "hsv",
29
30
  "hsl"
30
- ], o = "https://github.com/WICG/color-api/issues/196";
31
- function s(e, t, n) {
32
- var r;
33
- typeof window > "u" || !((r = window.__swc) != null && r.DEBUG) || window.__swc.warn(e, t, o, { issues: [n instanceof Error ? n.message : "Unknown error"] });
31
+ ], s = "https://github.com/WICG/color-api/issues/196";
32
+ function c(t, n, r) {
33
+ var i;
34
+ e() && ((i = window.__swc) == null || i.warn(t, n, s, { issues: [r instanceof Error ? r.message : "Unknown error"] }));
34
35
  }
35
- function c(e) {
36
+ function l(e) {
36
37
  let { h: t, s: n, l: r, v: i, r: a, g: o, b: s } = e;
37
38
  if (t !== void 0 && n !== void 0) {
38
39
  if (r !== void 0) return "hsl";
@@ -40,12 +41,12 @@ function c(e) {
40
41
  }
41
42
  if (a !== void 0 && o !== void 0 && s !== void 0) return "srgb";
42
43
  }
43
- var l = class {
44
+ var u = class {
44
45
  get color() {
45
46
  return this._color;
46
47
  }
47
48
  validateColorString(e) {
48
- var a, o, s, c;
49
+ var t, o, s, c;
49
50
  let l = {
50
51
  spaceId: null,
51
52
  coords: [
@@ -55,7 +56,7 @@ var l = class {
55
56
  ],
56
57
  isValid: !1,
57
58
  alpha: 1
58
- }, u = (a = t.find((t) => t.test(e))) == null ? void 0 : a.exec(e), d = (o = n.find((t) => t.test(e))) == null ? void 0 : o.exec(e), f = (s = r.find((t) => t.test(e))) == null ? void 0 : s.exec(e), p = (c = i.find((t) => t.test(e))) == null ? void 0 : c.exec(e);
59
+ }, u = (t = n.find((t) => t.test(e))) == null ? void 0 : t.exec(e), d = (o = r.find((t) => t.test(e))) == null ? void 0 : o.exec(e), f = (s = i.find((t) => t.test(e))) == null ? void 0 : s.exec(e), p = (c = a.find((t) => t.test(e))) == null ? void 0 : c.exec(e);
59
60
  if (u) {
60
61
  let [, e, t, n, r] = u.filter((e) => typeof e == "string"), i = r === void 0 ? 1 : Number(r), a = (e) => e.includes("%") ? Number(e.replace("%", "")) / 100 : Number(e) / 255, o = a(e), s = a(t), c = a(n);
61
62
  l.spaceId = "srgb", l.coords = [
@@ -109,46 +110,46 @@ var l = class {
109
110
  let { r: n, g: r, b: i } = this._color.to("srgb").srgb, a = this._color.alpha, o = (e) => Math.round(e * 255).toString(16).padStart(2, "0"), s = o(n), c = o(r), l = o(i), u = o(a);
110
111
  return `${e ? "#" : ""}${s}${c}${l}${t ? u : ""}`;
111
112
  }
112
- set color(t) {
113
- this._colorOrigin = t;
113
+ set color(e) {
114
+ this._colorOrigin = e;
114
115
  let n;
115
- if (typeof t == "string") {
116
- let r = this.validateColorString(t);
116
+ if (typeof e == "string") {
117
+ let r = this.validateColorString(e);
117
118
  if (r.isValid) {
118
- let [t, i, a] = r.coords;
119
- n = new e(`${r.spaceId}`, [
120
- t,
119
+ let [e, i, a] = r.coords;
120
+ n = new t(`${r.spaceId}`, [
121
+ e,
121
122
  i,
122
123
  a
123
124
  ], r.alpha);
124
125
  } else try {
125
- e.parse(t);
126
+ t.parse(e);
126
127
  } catch (r) {
127
- s(this.host, `Failed to parse color: ${t}`, r);
128
+ c(this.host, `Failed to parse color: ${e}`, r);
128
129
  try {
129
- n = new e(`#${t}`);
130
- } catch (e) {
131
- s(this.host, `Failed to parse color as hex: ${t}`, e);
130
+ n = new t(`#${e}`);
131
+ } catch (t) {
132
+ c(this.host, `Failed to parse color as hex: ${e}`, t);
132
133
  return;
133
134
  }
134
135
  }
135
- } else if (t instanceof e) n = t;
136
- else if (!Array.isArray(t)) {
137
- let { h: r, s: i, l: a, v: o, r: s, g: c, b: l, a: u } = t;
136
+ } else if (e instanceof t) n = e;
137
+ else if (!Array.isArray(e)) {
138
+ let { h: r, s: i, l: a, v: o, r: s, g: c, b: l, a: u } = e;
138
139
  if (r !== void 0 && i !== void 0) {
139
- let t = a == null ? o : a;
140
- n = new e(a === void 0 ? "hsv" : "hsl", [
140
+ let e = a == null ? o : a;
141
+ n = new t(a === void 0 ? "hsv" : "hsl", [
141
142
  parseFloat(`${r}`),
142
143
  typeof i == "string" ? parseFloat(i) : i * 100,
143
- typeof t == "string" ? parseFloat(t) : t * 100
144
+ typeof e == "string" ? parseFloat(e) : e * 100
144
145
  ], parseFloat(`${u == null ? "1" : u}`));
145
- } else s !== void 0 && c !== void 0 && l !== void 0 && (n = new e("srgb", [
146
+ } else s !== void 0 && c !== void 0 && l !== void 0 && (n = new t("srgb", [
146
147
  parseFloat(`${s}`) / 255,
147
148
  parseFloat(`${c}`) / 255,
148
149
  parseFloat(`${l}`) / 255
149
150
  ], parseFloat(`${u == null ? "1" : u}`)));
150
151
  }
151
- n || (n = new e(t)), this.manageAs ? this._color = n.to(this.manageAs) : this._color = n, this.host.requestUpdate();
152
+ n || (n = new t(e)), this.manageAs ? this._color = n.to(this.manageAs) : this._color = n, this.host.requestUpdate();
152
153
  }
153
154
  get colorValue() {
154
155
  if (typeof this._colorOrigin == "string") {
@@ -176,14 +177,14 @@ var l = class {
176
177
  }
177
178
  }
178
179
  }
179
- let t;
180
+ let e;
180
181
  if (this._colorOrigin) try {
181
- ({spaceId: t} = new e(this._colorOrigin));
182
- } catch (e) {
183
- s(this.host, `Failed to parse color as default color types: ${JSON.stringify(this._colorOrigin)}`, e), t = c(this._colorOrigin);
182
+ ({spaceId: e} = new t(this._colorOrigin));
183
+ } catch (t) {
184
+ c(this.host, `Failed to parse color as default color types: ${JSON.stringify(this._colorOrigin)}`, t), e = l(this._colorOrigin);
184
185
  }
185
- else ({spaceId: t} = this.color);
186
- switch (t) {
186
+ else ({spaceId: e} = this.color);
187
+ switch (e) {
187
188
  case "hsv": {
188
189
  let { h: e, s: t, v: n } = this._color.to("hsv").hsv;
189
190
  return {
@@ -225,15 +226,15 @@ var l = class {
225
226
  set hue(e) {
226
227
  this._color.set("h", e), this.host.requestUpdate();
227
228
  }
228
- constructor(t, { manageAs: n } = {}) {
229
- this._color = new e("hsv", [
229
+ constructor(e, { manageAs: n } = {}) {
230
+ this._color = new t("hsv", [
230
231
  0,
231
232
  100,
232
233
  100
233
- ], 1), this.host = t, this.manageAs = n;
234
+ ], 1), this.host = e, this.manageAs = n;
234
235
  }
235
236
  getColor(e) {
236
- if (typeof e == "string" && !a.includes(e)) throw Error("not a valid format");
237
+ if (typeof e == "string" && !o.includes(e)) throw Error("not a valid format");
237
238
  return this._color.to(e);
238
239
  }
239
240
  getHslString() {
@@ -247,6 +248,6 @@ var l = class {
247
248
  }
248
249
  };
249
250
  //#endregion
250
- export { l as ColorController };
251
+ export { u as ColorController };
251
252
 
252
253
  //# sourceMappingURL=color-controller.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"color-controller.js","names":[],"sources":["../../../../controllers/color-controller/src/color-controller.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 type { ReactiveElement } from 'lit';\nimport type ColorSpace from 'colorjs.io';\nimport type { ColorObject, ColorTypes as DefaultColorTypes } from 'colorjs.io';\nimport Color from 'colorjs.io';\n\n// ─────────────────────────\n// TYPES\n// ─────────────────────────\n\n/**\n * Represents various color types that can be used in the application.\n *\n * This type can be one of the following:\n * - `DefaultColorTypes`: A predefined set of color types.\n * - An object representing an RGBA color with properties:\n * - `r`: Red component, can be a number or string.\n * - `g`: Green component, can be a number or string.\n * - `b`: Blue component, can be a number or string.\n * - `a` (optional): Alpha component, can be a number or string.\n * - An object representing an HSLA color with properties:\n * - `h`: Hue component, can be a number or string.\n * - `s`: Saturation component, can be a number or string.\n * - `l`: Lightness component, can be a number or string.\n * - `a` (optional): Alpha component, can be a number or string.\n * - An object representing an HSVA color with properties:\n * - `h`: Hue component, can be a number or string.\n * - `s`: Saturation component, can be a number or string.\n * - `v`: Value component, can be a number or string.\n * - `a` (optional): Alpha component, can be a number or string.\n */\ntype ColorTypes =\n | DefaultColorTypes\n | {\n r: number | string;\n g: number | string;\n b: number | string;\n a?: number | string;\n }\n | {\n h: number | string;\n s: number | string;\n l: number | string;\n a?: number | string;\n }\n | {\n h: number | string;\n s: number | string;\n v: number | string;\n a?: number | string;\n };\n\nexport type { Color, ColorTypes };\n\ntype ColorValidationResult = {\n spaceId: string | null;\n coords: number[];\n isValid: boolean;\n alpha: number;\n};\n\n/** Loose shape of a color object whose channel values may arrive as strings. */\ntype LooseColorObject = {\n h?: number | string;\n s?: number | string;\n l?: number | string;\n v?: number | string;\n r?: number | string;\n g?: number | string;\n b?: number | string;\n a?: number | string;\n};\n\n// ─────────────────────────\n// CONSTANTS\n// ─────────────────────────\n\n// These pattern arrays are static, so they live at module scope and are shared\n// across every controller instance and `validateColorString` call rather than\n// being rebuilt on each invocation.\n\n// RGB color formats\nconst RGB_REG_EXP_ARRAY = [\n // With commas\n /rgba\\(\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*,\\s*(\\d*\\.?\\d+)\\s*\\)/i, // rgba(r, g, b, a)\n /rgb\\(\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*\\)/i, // rgb(r, g, b)\n\n // With spaces\n /^rgba\\s+(\\d{1,3})\\s+(\\d{1,3})\\s+(\\d{1,3})\\s+(0|0?\\.\\d+|1)\\s*$/i, // rgba r g b a\n /^rgb\\s+(\\d{1,3})\\s+(\\d{1,3})\\s+(\\d{1,3})\\s*$/i, // rgb r g b\n\n // Spaces inside parentheses\n /^rgba\\(\\s*(\\d{1,3})\\s+(\\d{1,3})\\s+(\\d{1,3})\\s+(\\d*\\.?\\d+)\\s*\\)$/i, // rgba(r g b a)\n /^rgb\\(\\s*(\\d{1,3})\\s+(\\d{1,3})\\s+(\\d{1,3})\\s*\\)$/i, // rgb(r g b)\n\n // Percentage values\n /rgb\\(\\s*(100|[0-9]{1,2}%)\\s*,\\s*(100|[0-9]{1,2}%)\\s*,\\s*(100|[0-9]{1,2}%)\\s*\\)/i, // rgb(r%, g%, b%)\n /rgba\\(\\s*(100|[0-9]{1,2})%\\s*,\\s*(100|[0-9]{1,2})%\\s*,\\s*(100|[0-9]{1,2})%\\s*,\\s*(\\d*\\.?\\d+)\\s*\\)/i, // rgba(r%, g%, b%, a)\n] as const;\n\n// HSL color formats\nconst HSL_REG_EXP_ARRAY = [\n // With commas\n /hsla\\(\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3}%?)\\s*,\\s*(\\d{1,3}%?)\\s*,\\s*(\\d*\\.?\\d+)\\s*\\)/i, // hsla(h, s, l, a)\n /hsl\\(\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3}%?)\\s*,\\s*(\\d{1,3}%?)\\s*\\)/i, // hsl(h, s, l)\n\n // With spaces\n /^hsla\\s+(\\d{1,3})\\s+(\\d{1,3}%?)\\s+(\\d{1,3}%?)\\s+(\\d*\\.?\\d+)\\s*$/i, // hsla h s l a\n /^hsl\\s+(\\d{1,3})\\s+(\\d{1,3}%?)\\s+(\\d{1,3}%?)\\s*$/i, // hsl h s l\n\n // Spaces inside parentheses\n /^hsla\\(\\s*(\\d{1,3})\\s+(\\d{1,3}%?)\\s+(\\d{1,3}%?)\\s+(\\d*\\.?\\d+)\\s*\\)$/i, // hsla(h s l a)\n /^hsl\\(\\s*(\\d{1,3})\\s+(\\d{1,3}%?)\\s+(\\d{1,3}%?)\\s*\\)$/i, // hsl(h s l)\n] as const;\n\n// HSV color formats\nconst HSV_REG_EXP_ARRAY = [\n // With commas\n /hsva\\(\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3}%?)\\s*,\\s*(\\d{1,3}%?)\\s*,\\s*(\\d*\\.?\\d+)\\s*\\)/i, // hsva(h, s, v, a)\n /hsv\\(\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3}%?)\\s*,\\s*(\\d{1,3}%?)\\s*\\)/i, // hsv(h, s, v)\n\n // With spaces\n /^hsva\\s+(\\d{1,3})\\s+(\\d{1,3}%?)\\s+(\\d{1,3}%?)\\s+(\\d*\\.?\\d+)\\s*$/i, // hsva h s v a\n /^hsv\\s+(\\d{1,3})\\s+(\\d{1,3}%?)\\s+(\\d{1,3}%?)\\s*$/i, // hsv h s v\n\n // Spaces inside parentheses\n /^hsva\\(\\s*(\\d{1,3})\\s+(\\d{1,3}%?)\\s+(\\d{1,3}%?)\\s+(\\d*\\.?\\d+)\\s*\\)$/i, // hsva(h s v a)\n /^hsv\\(\\s*(\\d{1,3})\\s+(\\d{1,3}%?)\\s+(\\d{1,3}%?)\\s*\\)$/i, // hsv(h s v)\n] as const;\n\n// HEX color formats\nconst HEX_REG_EXP_ARRAY = [\n /^#([A-Fa-f0-9]{6})([A-Fa-f0-9]{2})?$/, // 6-digit hex with optional hex alpha\n /^#([A-Fa-f0-9]{3})([A-Fa-f0-9]{1})?$/, // 3-digit hex with optional hex alpha\n] as const;\n\n// The colorjs.io space ids `getColor` can convert to. `hsva`/`hsla` are not real\n// colorjs.io spaces (converting to them throws), so they are intentionally absent.\nconst VALID_GET_COLOR_FORMATS = ['srgb', 'hsv', 'hsl'] as const;\n\n/** Documentation URL surfaced alongside Dev Mode parse warnings. */\nconst COLOR_PARSE_HELP_URL = 'https://github.com/WICG/color-api/issues/196';\n\n/**\n * Emits a Dev Mode parse warning when `window.__swc.DEBUG` is enabled. Guarded by\n * a `typeof window` check so the controller is safe to evaluate in non-browser\n * (SSR / Node unit test) environments where `window` is undefined. Centralizes\n * the otherwise-repeated warn blocks.\n */\nfunction debugWarn(\n host: ReactiveElement | undefined,\n message: string,\n error: unknown\n): void {\n if (typeof window === 'undefined' || !window.__swc?.DEBUG) {\n return;\n }\n window.__swc.warn(host, message, COLOR_PARSE_HELP_URL, {\n issues: [error instanceof Error ? error.message : 'Unknown error'],\n });\n}\n\n/**\n * Derives a colorjs.io space id from a loose color object based on which channel\n * keys are present. Shared by the `color` setter and the `colorValue` getter so\n * the detection logic lives in one place.\n */\nfunction spaceIdFromColorObject(color: LooseColorObject): string | undefined {\n const { h, s, l, v, r, g, b } = color;\n if (typeof h !== 'undefined' && typeof s !== 'undefined') {\n if (typeof l !== 'undefined') {\n return 'hsl';\n }\n if (typeof v !== 'undefined') {\n return 'hsv';\n }\n }\n if (\n typeof r !== 'undefined' &&\n typeof g !== 'undefined' &&\n typeof b !== 'undefined'\n ) {\n return 'srgb';\n }\n return undefined;\n}\n\n/**\n * The `ColorController` class is responsible for managing and validating color values\n * in various color spaces (RGB, HSL, HSV, Hex). It provides methods to set, get, and\n * validate colors, as well as convert between different color formats.\n *\n * @class\n * @property {Color} color - Gets or sets the current color value.\n * @property {ColorTypes} colorValue - Gets the color value in various formats based on the original color input.\n * @property {number} hue - Gets or sets the hue value of the current color.\n *\n * @function validateColorString(color: string): ColorValidationResult - Validates a color string and returns the validation result.\n * @function getColor(format: string | ColorSpace): ColorObject - Converts the current color to the specified format.\n * @function getHslString(): string - Returns the current color in HSL string format.\n * @function savePreviousColor(): void - Saves the current color as the previous color.\n * @function restorePreviousColor(): void - Restores the previous color.\n *\n * @class\n * @param {ReactiveElement} host - The host element that uses this controller.\n * @param {object} [options] - Optional configuration options.\n * @param {string} [options.manageAs] - Specifies the color space to manage the color as.\n */\nexport class ColorController {\n get color(): Color {\n return this._color;\n }\n\n /**\n * Validates a color string and returns a result indicating the color space,\n * coordinates, alpha value, and whether the color is valid.\n *\n * @param color - The color string to validate. Supported formats include:\n * - RGB: `rgb(r, g, b)`, `rgba(r, g, b, a)`, `rgb r g b`, `rgba r g b a`\n * - HSL: `hsl(h, s, l)`, `hsla(h, s, l, a)`, `hsl h s l`, `hsla h s l a`\n * - HSV: `hsv(h, s, v)`, `hsva(h, s, v, a)`, `hsv h s v`, `hsva h s v a`\n * - HEX: `#rgb`, `#rgba`, `#rrggbb`, `#rrggbbaa`\n *\n * @returns An object containing the following properties:\n * - `spaceId`: The color space identifier (`'srgb'`, `'hsl'`, or `'hsv'`).\n * - `coords`: An array of numeric values representing the color coordinates.\n * - `alpha`: The alpha value of the color (0 to 1).\n * - `isValid`: A boolean indicating whether the color string is valid.\n */\n public validateColorString(color: string): ColorValidationResult {\n const result: ColorValidationResult = {\n spaceId: null,\n coords: [0, 0, 0],\n isValid: false,\n alpha: 1,\n };\n\n const rgbaMatch = RGB_REG_EXP_ARRAY.find((regex) =>\n regex.test(color)\n )?.exec(color);\n const hslaMatch = HSL_REG_EXP_ARRAY.find((regex) =>\n regex.test(color)\n )?.exec(color);\n const hsvaMatch = HSV_REG_EXP_ARRAY.find((regex) =>\n regex.test(color)\n )?.exec(color);\n const hexMatch = HEX_REG_EXP_ARRAY.find((regex) => regex.test(color))?.exec(\n color\n );\n\n if (rgbaMatch) {\n const [, r, g, b, a] = rgbaMatch.filter(\n (element) => typeof element === 'string'\n );\n const alpha = a === undefined ? 1 : Number(a);\n const processValue = (value: string): number => {\n if (value.includes('%')) {\n return Number(value.replace('%', '')) / 100;\n } else {\n return Number(value) / 255;\n }\n };\n const numericR = processValue(r);\n const numericG = processValue(g);\n const numericB = processValue(b);\n\n result.spaceId = 'srgb';\n result.coords = [numericR, numericG, numericB];\n result.alpha = alpha;\n result.isValid =\n numericR >= 0 &&\n numericR <= 1 &&\n numericG >= 0 &&\n numericG <= 1 &&\n numericB >= 0 &&\n numericB <= 1 &&\n alpha >= 0 &&\n alpha <= 1;\n } else if (hslaMatch) {\n const [, h, s, l, a] = hslaMatch;\n const values = [h, s, l, a === undefined ? '1' : a].map((value) =>\n Number(value.replace(/[^\\d.]/g, ''))\n );\n const [numericH, numericS, numericL, numericA] = values;\n\n result.spaceId = 'hsl';\n result.coords = [numericH, numericS, numericL];\n result.alpha = numericA;\n result.isValid =\n numericH >= 0 &&\n numericH <= 360 &&\n numericS >= 0 &&\n numericS <= 100 &&\n numericL >= 0 &&\n numericL <= 100 &&\n numericA >= 0 &&\n numericA <= 1;\n } else if (hsvaMatch) {\n const [, h, s, v, a] = hsvaMatch;\n const values = [h, s, v, a === undefined ? '1' : a].map((value) =>\n Number(value.replace(/[^\\d.]/g, ''))\n );\n const [numericH, numericS, numericV, numericA] = values;\n\n result.spaceId = 'hsv';\n result.coords = [numericH, numericS, numericV];\n result.alpha = numericA;\n result.isValid =\n numericH >= 0 &&\n numericH <= 360 &&\n numericS >= 0 &&\n numericS <= 100 &&\n numericV >= 0 &&\n numericV <= 100 &&\n numericA >= 0 &&\n numericA <= 1;\n } else if (hexMatch) {\n const [, hex, alphaHex] = hexMatch;\n\n // Function to process 2-digit or repeated 1-digit hex\n const processHex = (hex: string): number => {\n // For 3-digit hex values, repeat each digit\n if (hex.length === 1) {\n hex = hex + hex;\n }\n return parseInt(hex, 16) / 255;\n };\n\n // Handle both 3-digit and 6-digit hex\n let numericR, numericG, numericB;\n if (hex.length === 3) {\n // 3-digit hex (e.g., #3a7 -> #33aa77)\n numericR = processHex(hex.substring(0, 1));\n numericG = processHex(hex.substring(1, 2));\n numericB = processHex(hex.substring(2, 3));\n } else {\n // 6-digit hex (e.g., #33aa77)\n numericR = processHex(hex.substring(0, 2));\n numericG = processHex(hex.substring(2, 4));\n numericB = processHex(hex.substring(4, 6));\n }\n\n // Process hex alpha if provided (convert from 0-255 to 0-1)\n const numericA = alphaHex ? processHex(alphaHex) : 1;\n\n // Validate the color values\n result.spaceId = 'srgb';\n result.coords = [numericR, numericG, numericB];\n result.alpha = numericA;\n result.isValid =\n numericR >= 0 &&\n numericR <= 1 &&\n numericG >= 0 &&\n numericG <= 1 &&\n numericB >= 0 &&\n numericB <= 1 &&\n numericA >= 0 &&\n numericA <= 1;\n }\n\n return result;\n }\n\n /**\n * Represents the color state of the component.\n * Initialized with an HSV color model with hue 0, saturation 100, and value 100, and an alpha value of 1.\n *\n * @private\n * @type {Color}\n */\n private _color: Color = new Color('hsv', [0, 100, 100], 1);\n\n /**\n * Represents the original color value provided by the user.\n *\n * @private\n * @type {ColorTypes}\n */\n private _colorOrigin!: ColorTypes;\n\n /**\n * Gets the original color value provided by the user.\n *\n * @returns {ColorTypes} The original color value.\n */\n get colorOrigin(): ColorTypes {\n return this._colorOrigin;\n }\n\n /**\n * Sets the original color value provided by the user.\n *\n * @param {ColorTypes} colorOrigin - The original color value to set.\n */\n set colorOrigin(colorOrigin: ColorTypes) {\n this._colorOrigin = colorOrigin;\n }\n\n /**\n * An optional string property that specifies how the color should be managed(its value is the name of color space in which color object will be managed).\n * This property can be used to define a specific management strategy or identifier.\n */\n private manageAs?: string;\n\n /**\n * Stores the previous color value.\n * This is used to keep track of the color before any changes are made.\n *\n * @private\n */\n private _previousColor!: Color;\n\n /**\n * Private helper method to convert RGB color to hex format with optional alpha\n *\n * @private\n * @param {boolean} includeHash - Whether to include the # prefix in the returned string\n * @param {boolean} includeAlpha - Whether to include the alpha channel in the returned string\n * @returns {string} The color in hex format\n */\n private _getHexString(includeHash: boolean, includeAlpha: boolean): string {\n const { r, g, b } = (this._color.to('srgb') as Color).srgb;\n const a = this._color.alpha;\n\n const toHex = (channel: number): string =>\n Math.round(channel * 255)\n .toString(16)\n .padStart(2, '0');\n\n const rHex = toHex(r);\n const gHex = toHex(g);\n const bHex = toHex(b);\n const aHex = toHex(a);\n\n return `${includeHash ? '#' : ''}${rHex}${gHex}${bHex}${includeAlpha ? aHex : ''}`;\n }\n\n /**\n * Sets the color value for the controller. The color can be provided in various formats:\n * - A string representing a color name, hex code, or other color format.\n * - An instance of the `Color` class.\n * - An object containing color properties such as `h`, `s`, `l`, `v`, `r`, `g`, `b`, and optionally `a`.\n *\n * The method validates and parses the input color, converting it to a `Color` instance.\n * If the color is invalid, it attempts to parse it as a hex code or returns without setting a new color.\n *\n * @param {ColorTypes} color - The color value to set. It can be a string, an instance of `Color`, or an object with color properties.\n */\n set color(color: ColorTypes) {\n this._colorOrigin = color;\n let newColor!: Color;\n if (typeof color === 'string') {\n const colorValidationResult = this.validateColorString(color as string);\n if (colorValidationResult.isValid) {\n const [coord1, coord2, coord3] = colorValidationResult.coords;\n newColor = new Color(\n `${colorValidationResult.spaceId}`,\n [coord1, coord2, coord3],\n colorValidationResult.alpha\n );\n } else {\n try {\n Color.parse(color);\n } catch (error) {\n debugWarn(this.host, `Failed to parse color: ${color}`, error);\n try {\n newColor = new Color(`#${color}`);\n } catch (error) {\n debugWarn(\n this.host,\n `Failed to parse color as hex: ${color}`,\n error\n );\n return;\n }\n }\n }\n } else if (color instanceof Color) {\n newColor = color;\n } else if (!Array.isArray(color)) {\n const { h, s, l, v, r, g, b, a } = color as LooseColorObject;\n if (typeof h !== 'undefined' && typeof s !== 'undefined') {\n const lv = l ?? v;\n newColor = new Color(\n typeof l !== 'undefined' ? 'hsl' : 'hsv',\n [\n parseFloat(`${h}`),\n typeof s !== 'string' ? (s as number) * 100 : parseFloat(s),\n typeof lv !== 'string' ? (lv as number) * 100 : parseFloat(lv),\n ],\n parseFloat(`${a ?? '1'}`)\n );\n } else if (\n typeof r !== 'undefined' &&\n typeof g !== 'undefined' &&\n typeof b !== 'undefined'\n ) {\n newColor = new Color(\n 'srgb',\n [\n parseFloat(`${r}`) / 255,\n parseFloat(`${g}`) / 255,\n parseFloat(`${b}`) / 255,\n ],\n parseFloat(`${a ?? '1'}`)\n );\n }\n }\n\n if (!newColor) {\n newColor = new Color(color as DefaultColorTypes);\n }\n\n if (this.manageAs) {\n this._color = newColor.to(this.manageAs) as Color;\n } else {\n this._color = newColor;\n }\n this.host.requestUpdate();\n }\n\n /**\n * Gets the color value in various formats based on the original color input.\n *\n * The method determines the color space of the original color input and converts\n * the color to the appropriate format. The supported color spaces are:\n * - HSV (Hue, Saturation, Value)\n * - HSL (Hue, Saturation, Lightness)\n * - Hexadecimal (with or without alpha)\n * - RGB (Red, Green, Blue) with optional alpha\n *\n * @returns {ColorTypes} The color value in the appropriate format.\n *\n * The method handles the following cases:\n * - If the original color input is a string, it checks the prefix to determine the color space.\n * - If the original color input is an object, it checks the properties to determine the color space.\n * - If the original color input is not provided, it defaults to the current color space of the color object.\n *\n * The returned color value can be in one of the following formats:\n * - `hsv(h, s%, v%)` or `hsva(h, s%, v%, a)`\n * - `hsl(h, s%, l%)` or `hsla(h, s%, l%, a)`\n * - `#rrggbb` or `#rrggbbaa`\n * - `rgb(r, g, b)` or `rgba(r, g, b, a)`\n * - `{ h, s, v, a }` for HSV object\n * - `{ h, s, l, a }` for HSL object\n * - `{ r, g, b, a }` for RGB object\n */\n get colorValue(): ColorTypes {\n if (typeof this._colorOrigin === 'string') {\n let spaceId = '';\n if (this._colorOrigin.startsWith('#')) {\n spaceId = 'hex string';\n } else if (this._colorOrigin.startsWith('rgb')) {\n spaceId = 'rgb';\n } else if (this._colorOrigin.startsWith('hsl')) {\n spaceId = 'hsl';\n } else if (this._colorOrigin.startsWith('hsv')) {\n spaceId = 'hsv';\n } else {\n spaceId = 'hex';\n }\n switch (spaceId) {\n case 'hsv': {\n const hadAlpha = this._colorOrigin[3] === 'a';\n const { h, s, v } = (this._color.to('hsv') as Color).hsv;\n const a = this._color.alpha;\n return `hsv${hadAlpha ? `a` : ''}(${Math.round(\n h\n )}, ${Math.round(s)}%, ${Math.round(v)}%${hadAlpha ? `, ${a}` : ''})`;\n }\n case 'hsl': {\n const hadAlpha = this._colorOrigin[3] === 'a';\n const { h, s, l } = (this._color.to('hsl') as Color).hsl;\n const a = this._color.alpha;\n return `hsl${hadAlpha ? `a` : ''}(${Math.round(\n h\n )}, ${Math.round(s)}%, ${Math.round(l)}%${hadAlpha ? `, ${a}` : ''})`;\n }\n case 'hex string': {\n // Check if the original input included alpha\n const hadAlpha =\n this._colorOrigin.length === 9 || // #RRGGBBAA format\n this._colorOrigin.length === 5; // #RGBA format\n return this._getHexString(true, hadAlpha);\n }\n case 'hex': {\n // Check if the original input included alpha\n const hadAlpha =\n this._colorOrigin.length === 8 || // RRGGBBAA format (no #)\n this._colorOrigin.length === 4; // RGBA format (no #)\n return this._getHexString(false, hadAlpha);\n }\n //rgb\n default: {\n const { r, g, b } = (this._color.to('srgb') as Color).srgb;\n const hadAlpha = this._colorOrigin[3] === 'a';\n const a = this._color.alpha;\n if (this._colorOrigin.search('%') > -1) {\n return `rgb${hadAlpha ? `a` : ''}(${Math.round(r * 100)}%, ${Math.round(\n g * 100\n )}%, ${Math.round(b * 100)}%${hadAlpha ? `,${Math.round(a * 100)}%` : ''})`;\n }\n return `rgb${hadAlpha ? `a` : ''}(${Math.round(r * 255)}, ${Math.round(\n g * 255\n )}, ${Math.round(b * 255)}${hadAlpha ? `, ${a}` : ''})`;\n }\n }\n }\n let spaceId;\n if (this._colorOrigin) {\n try {\n ({ spaceId } = new Color(this._colorOrigin as DefaultColorTypes));\n } catch (error) {\n debugWarn(\n this.host,\n `Failed to parse color as default color types: ${JSON.stringify(\n this._colorOrigin\n )}`,\n error\n );\n spaceId = spaceIdFromColorObject(this._colorOrigin as LooseColorObject);\n }\n } else {\n ({ spaceId } = this.color);\n }\n switch (spaceId) {\n case 'hsv': {\n const { h, s, v } = (this._color.to('hsv') as Color).hsv;\n return {\n h,\n s: s / 100,\n v: v / 100,\n a: this._color.alpha,\n };\n }\n case 'hsl': {\n const { h, s, l } = (this._color.to('hsl') as Color).hsl;\n return {\n h,\n s: s / 100,\n l: l / 100,\n a: this._color.alpha,\n };\n }\n case 'srgb': {\n const { r, g, b } = (this._color.to('srgb') as Color).srgb;\n if (\n this._colorOrigin &&\n typeof (this._colorOrigin as { r: string }).r === 'string' &&\n (this._colorOrigin as { r: string }).r.includes('%')\n ) {\n return {\n r: `${Math.round(r * 100)}%`,\n g: `${Math.round(g * 100)}%`,\n b: `${Math.round(b * 100)}%`,\n a: this._color.alpha,\n };\n }\n return {\n r: Math.round(r * 255),\n g: Math.round(g * 255),\n b: Math.round(b * 255),\n a: this._color.alpha,\n };\n }\n }\n return this._color;\n }\n\n protected host: ReactiveElement;\n\n /**\n * Gets the hue value of the current color in HSL format.\n *\n * @returns {number} The hue value as a number.\n */\n get hue(): number {\n return Number((this._color.to('hsl') as Color).hsl.h);\n }\n\n /**\n * Sets the hue value of the color and requests an update from the host.\n *\n * @param hue - The hue value to set, represented as a number.\n */\n set hue(hue: number) {\n this._color.set('h', hue);\n this.host.requestUpdate();\n }\n\n /**\n * Creates an instance of ColorController.\n *\n * @param host - The ReactiveElement that this controller is associated with.\n * @param options - An object containing optional parameters.\n * @param options.manageAs - A string to manage the controller as a specific type.\n */\n constructor(\n host: ReactiveElement,\n {\n manageAs,\n }: {\n manageAs?: string;\n } = {}\n ) {\n this.host = host;\n this.manageAs = manageAs;\n }\n\n /**\n * Converts the current color to the specified format.\n *\n * @param format - The desired color format. It can be a string representing one of the valid formats\n * ('srgb', 'hsv', 'hsl') or a ColorSpace.Space object.\n * @returns The color object in the specified format.\n * @throws Will throw an error if the provided format is not a valid string format.\n */\n getColor(format: string | ColorSpace.Space): ColorObject {\n if (\n typeof format === 'string' &&\n !VALID_GET_COLOR_FORMATS.includes(\n format as (typeof VALID_GET_COLOR_FORMATS)[number]\n )\n ) {\n throw new Error('not a valid format');\n }\n\n return this._color.to(format);\n }\n\n /**\n * Converts the current color to an HSL string representation.\n *\n * @returns {string} The HSL string representation of the current color.\n */\n getHslString(): string {\n return this._color.to('hsl').toString();\n }\n\n /**\n * Saves the current color state by cloning the current color and storing it\n * as the previous color. This allows for the ability to revert to the previous\n * color state if needed.\n *\n * @returns {void}\n */\n savePreviousColor(): void {\n this._previousColor = this._color.clone();\n }\n\n /**\n * Restores the color to the previously saved color value.\n *\n * This method sets the current color (`_color`) to the previously stored color (`_previousColor`).\n */\n restorePreviousColor(): void {\n this._color = this._previousColor;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"color-controller.js","names":[],"sources":["../../../../controllers/color-controller/src/color-controller.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 type { ReactiveElement } from 'lit';\nimport type ColorSpace from 'colorjs.io';\nimport type { ColorObject, ColorTypes as DefaultColorTypes } from 'colorjs.io';\nimport Color from 'colorjs.io';\n\nimport { isDebug } from '@adobe/spectrum-wc-core/utils/index.js';\n\n// ─────────────────────────\n// TYPES\n// ─────────────────────────\n\n/**\n * Represents various color types that can be used in the application.\n *\n * This type can be one of the following:\n * - `DefaultColorTypes`: A predefined set of color types.\n * - An object representing an RGBA color with properties:\n * - `r`: Red component, can be a number or string.\n * - `g`: Green component, can be a number or string.\n * - `b`: Blue component, can be a number or string.\n * - `a` (optional): Alpha component, can be a number or string.\n * - An object representing an HSLA color with properties:\n * - `h`: Hue component, can be a number or string.\n * - `s`: Saturation component, can be a number or string.\n * - `l`: Lightness component, can be a number or string.\n * - `a` (optional): Alpha component, can be a number or string.\n * - An object representing an HSVA color with properties:\n * - `h`: Hue component, can be a number or string.\n * - `s`: Saturation component, can be a number or string.\n * - `v`: Value component, can be a number or string.\n * - `a` (optional): Alpha component, can be a number or string.\n */\ntype ColorTypes =\n | DefaultColorTypes\n | {\n r: number | string;\n g: number | string;\n b: number | string;\n a?: number | string;\n }\n | {\n h: number | string;\n s: number | string;\n l: number | string;\n a?: number | string;\n }\n | {\n h: number | string;\n s: number | string;\n v: number | string;\n a?: number | string;\n };\n\nexport type { Color, ColorTypes };\n\ntype ColorValidationResult = {\n spaceId: string | null;\n coords: number[];\n isValid: boolean;\n alpha: number;\n};\n\n/** Loose shape of a color object whose channel values may arrive as strings. */\ntype LooseColorObject = {\n h?: number | string;\n s?: number | string;\n l?: number | string;\n v?: number | string;\n r?: number | string;\n g?: number | string;\n b?: number | string;\n a?: number | string;\n};\n\n// ─────────────────────────\n// CONSTANTS\n// ─────────────────────────\n\n// These pattern arrays are static, so they live at module scope and are shared\n// across every controller instance and `validateColorString` call rather than\n// being rebuilt on each invocation.\n\n// RGB color formats\nconst RGB_REG_EXP_ARRAY = [\n // With commas\n /rgba\\(\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*,\\s*(\\d*\\.?\\d+)\\s*\\)/i, // rgba(r, g, b, a)\n /rgb\\(\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*\\)/i, // rgb(r, g, b)\n\n // With spaces\n /^rgba\\s+(\\d{1,3})\\s+(\\d{1,3})\\s+(\\d{1,3})\\s+(0|0?\\.\\d+|1)\\s*$/i, // rgba r g b a\n /^rgb\\s+(\\d{1,3})\\s+(\\d{1,3})\\s+(\\d{1,3})\\s*$/i, // rgb r g b\n\n // Spaces inside parentheses\n /^rgba\\(\\s*(\\d{1,3})\\s+(\\d{1,3})\\s+(\\d{1,3})\\s+(\\d*\\.?\\d+)\\s*\\)$/i, // rgba(r g b a)\n /^rgb\\(\\s*(\\d{1,3})\\s+(\\d{1,3})\\s+(\\d{1,3})\\s*\\)$/i, // rgb(r g b)\n\n // Percentage values\n /rgb\\(\\s*(100|[0-9]{1,2}%)\\s*,\\s*(100|[0-9]{1,2}%)\\s*,\\s*(100|[0-9]{1,2}%)\\s*\\)/i, // rgb(r%, g%, b%)\n /rgba\\(\\s*(100|[0-9]{1,2})%\\s*,\\s*(100|[0-9]{1,2})%\\s*,\\s*(100|[0-9]{1,2})%\\s*,\\s*(\\d*\\.?\\d+)\\s*\\)/i, // rgba(r%, g%, b%, a)\n] as const;\n\n// HSL color formats\nconst HSL_REG_EXP_ARRAY = [\n // With commas\n /hsla\\(\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3}%?)\\s*,\\s*(\\d{1,3}%?)\\s*,\\s*(\\d*\\.?\\d+)\\s*\\)/i, // hsla(h, s, l, a)\n /hsl\\(\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3}%?)\\s*,\\s*(\\d{1,3}%?)\\s*\\)/i, // hsl(h, s, l)\n\n // With spaces\n /^hsla\\s+(\\d{1,3})\\s+(\\d{1,3}%?)\\s+(\\d{1,3}%?)\\s+(\\d*\\.?\\d+)\\s*$/i, // hsla h s l a\n /^hsl\\s+(\\d{1,3})\\s+(\\d{1,3}%?)\\s+(\\d{1,3}%?)\\s*$/i, // hsl h s l\n\n // Spaces inside parentheses\n /^hsla\\(\\s*(\\d{1,3})\\s+(\\d{1,3}%?)\\s+(\\d{1,3}%?)\\s+(\\d*\\.?\\d+)\\s*\\)$/i, // hsla(h s l a)\n /^hsl\\(\\s*(\\d{1,3})\\s+(\\d{1,3}%?)\\s+(\\d{1,3}%?)\\s*\\)$/i, // hsl(h s l)\n] as const;\n\n// HSV color formats\nconst HSV_REG_EXP_ARRAY = [\n // With commas\n /hsva\\(\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3}%?)\\s*,\\s*(\\d{1,3}%?)\\s*,\\s*(\\d*\\.?\\d+)\\s*\\)/i, // hsva(h, s, v, a)\n /hsv\\(\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3}%?)\\s*,\\s*(\\d{1,3}%?)\\s*\\)/i, // hsv(h, s, v)\n\n // With spaces\n /^hsva\\s+(\\d{1,3})\\s+(\\d{1,3}%?)\\s+(\\d{1,3}%?)\\s+(\\d*\\.?\\d+)\\s*$/i, // hsva h s v a\n /^hsv\\s+(\\d{1,3})\\s+(\\d{1,3}%?)\\s+(\\d{1,3}%?)\\s*$/i, // hsv h s v\n\n // Spaces inside parentheses\n /^hsva\\(\\s*(\\d{1,3})\\s+(\\d{1,3}%?)\\s+(\\d{1,3}%?)\\s+(\\d*\\.?\\d+)\\s*\\)$/i, // hsva(h s v a)\n /^hsv\\(\\s*(\\d{1,3})\\s+(\\d{1,3}%?)\\s+(\\d{1,3}%?)\\s*\\)$/i, // hsv(h s v)\n] as const;\n\n// HEX color formats\nconst HEX_REG_EXP_ARRAY = [\n /^#([A-Fa-f0-9]{6})([A-Fa-f0-9]{2})?$/, // 6-digit hex with optional hex alpha\n /^#([A-Fa-f0-9]{3})([A-Fa-f0-9]{1})?$/, // 3-digit hex with optional hex alpha\n] as const;\n\n// The colorjs.io space ids `getColor` can convert to. `hsva`/`hsla` are not real\n// colorjs.io spaces (converting to them throws), so they are intentionally absent.\nconst VALID_GET_COLOR_FORMATS = ['srgb', 'hsv', 'hsl'] as const;\n\n/** Documentation URL surfaced alongside Dev Mode parse warnings. */\nconst COLOR_PARSE_HELP_URL = 'https://github.com/WICG/color-api/issues/196';\n\n/**\n * Emits a Dev Mode parse warning when dev validation is active. Gated by\n * `isDebug()`, which is `false` in production and in non-browser (SSR / Node\n * unit test) environments where `window` is undefined, so the controller stays\n * safe to evaluate server-side. Centralizes the otherwise-repeated warn blocks.\n */\nfunction debugWarn(\n host: ReactiveElement | undefined,\n message: string,\n error: unknown\n): void {\n if (!isDebug()) {\n return;\n }\n window.__swc?.warn(host, message, COLOR_PARSE_HELP_URL, {\n issues: [error instanceof Error ? error.message : 'Unknown error'],\n });\n}\n\n/**\n * Derives a colorjs.io space id from a loose color object based on which channel\n * keys are present. Shared by the `color` setter and the `colorValue` getter so\n * the detection logic lives in one place.\n */\nfunction spaceIdFromColorObject(color: LooseColorObject): string | undefined {\n const { h, s, l, v, r, g, b } = color;\n if (typeof h !== 'undefined' && typeof s !== 'undefined') {\n if (typeof l !== 'undefined') {\n return 'hsl';\n }\n if (typeof v !== 'undefined') {\n return 'hsv';\n }\n }\n if (\n typeof r !== 'undefined' &&\n typeof g !== 'undefined' &&\n typeof b !== 'undefined'\n ) {\n return 'srgb';\n }\n return undefined;\n}\n\n/**\n * The `ColorController` class is responsible for managing and validating color values\n * in various color spaces (RGB, HSL, HSV, Hex). It provides methods to set, get, and\n * validate colors, as well as convert between different color formats.\n *\n * @class\n * @property {Color} color - Gets or sets the current color value.\n * @property {ColorTypes} colorValue - Gets the color value in various formats based on the original color input.\n * @property {number} hue - Gets or sets the hue value of the current color.\n *\n * @function validateColorString(color: string): ColorValidationResult - Validates a color string and returns the validation result.\n * @function getColor(format: string | ColorSpace): ColorObject - Converts the current color to the specified format.\n * @function getHslString(): string - Returns the current color in HSL string format.\n * @function savePreviousColor(): void - Saves the current color as the previous color.\n * @function restorePreviousColor(): void - Restores the previous color.\n *\n * @class\n * @param {ReactiveElement} host - The host element that uses this controller.\n * @param {object} [options] - Optional configuration options.\n * @param {string} [options.manageAs] - Specifies the color space to manage the color as.\n */\nexport class ColorController {\n get color(): Color {\n return this._color;\n }\n\n /**\n * Validates a color string and returns a result indicating the color space,\n * coordinates, alpha value, and whether the color is valid.\n *\n * @param color - The color string to validate. Supported formats include:\n * - RGB: `rgb(r, g, b)`, `rgba(r, g, b, a)`, `rgb r g b`, `rgba r g b a`\n * - HSL: `hsl(h, s, l)`, `hsla(h, s, l, a)`, `hsl h s l`, `hsla h s l a`\n * - HSV: `hsv(h, s, v)`, `hsva(h, s, v, a)`, `hsv h s v`, `hsva h s v a`\n * - HEX: `#rgb`, `#rgba`, `#rrggbb`, `#rrggbbaa`\n *\n * @returns An object containing the following properties:\n * - `spaceId`: The color space identifier (`'srgb'`, `'hsl'`, or `'hsv'`).\n * - `coords`: An array of numeric values representing the color coordinates.\n * - `alpha`: The alpha value of the color (0 to 1).\n * - `isValid`: A boolean indicating whether the color string is valid.\n */\n public validateColorString(color: string): ColorValidationResult {\n const result: ColorValidationResult = {\n spaceId: null,\n coords: [0, 0, 0],\n isValid: false,\n alpha: 1,\n };\n\n const rgbaMatch = RGB_REG_EXP_ARRAY.find((regex) =>\n regex.test(color)\n )?.exec(color);\n const hslaMatch = HSL_REG_EXP_ARRAY.find((regex) =>\n regex.test(color)\n )?.exec(color);\n const hsvaMatch = HSV_REG_EXP_ARRAY.find((regex) =>\n regex.test(color)\n )?.exec(color);\n const hexMatch = HEX_REG_EXP_ARRAY.find((regex) => regex.test(color))?.exec(\n color\n );\n\n if (rgbaMatch) {\n const [, r, g, b, a] = rgbaMatch.filter(\n (element) => typeof element === 'string'\n );\n const alpha = a === undefined ? 1 : Number(a);\n const processValue = (value: string): number => {\n if (value.includes('%')) {\n return Number(value.replace('%', '')) / 100;\n } else {\n return Number(value) / 255;\n }\n };\n const numericR = processValue(r);\n const numericG = processValue(g);\n const numericB = processValue(b);\n\n result.spaceId = 'srgb';\n result.coords = [numericR, numericG, numericB];\n result.alpha = alpha;\n result.isValid =\n numericR >= 0 &&\n numericR <= 1 &&\n numericG >= 0 &&\n numericG <= 1 &&\n numericB >= 0 &&\n numericB <= 1 &&\n alpha >= 0 &&\n alpha <= 1;\n } else if (hslaMatch) {\n const [, h, s, l, a] = hslaMatch;\n const values = [h, s, l, a === undefined ? '1' : a].map((value) =>\n Number(value.replace(/[^\\d.]/g, ''))\n );\n const [numericH, numericS, numericL, numericA] = values;\n\n result.spaceId = 'hsl';\n result.coords = [numericH, numericS, numericL];\n result.alpha = numericA;\n result.isValid =\n numericH >= 0 &&\n numericH <= 360 &&\n numericS >= 0 &&\n numericS <= 100 &&\n numericL >= 0 &&\n numericL <= 100 &&\n numericA >= 0 &&\n numericA <= 1;\n } else if (hsvaMatch) {\n const [, h, s, v, a] = hsvaMatch;\n const values = [h, s, v, a === undefined ? '1' : a].map((value) =>\n Number(value.replace(/[^\\d.]/g, ''))\n );\n const [numericH, numericS, numericV, numericA] = values;\n\n result.spaceId = 'hsv';\n result.coords = [numericH, numericS, numericV];\n result.alpha = numericA;\n result.isValid =\n numericH >= 0 &&\n numericH <= 360 &&\n numericS >= 0 &&\n numericS <= 100 &&\n numericV >= 0 &&\n numericV <= 100 &&\n numericA >= 0 &&\n numericA <= 1;\n } else if (hexMatch) {\n const [, hex, alphaHex] = hexMatch;\n\n // Function to process 2-digit or repeated 1-digit hex\n const processHex = (hex: string): number => {\n // For 3-digit hex values, repeat each digit\n if (hex.length === 1) {\n hex = hex + hex;\n }\n return parseInt(hex, 16) / 255;\n };\n\n // Handle both 3-digit and 6-digit hex\n let numericR, numericG, numericB;\n if (hex.length === 3) {\n // 3-digit hex (e.g., #3a7 -> #33aa77)\n numericR = processHex(hex.substring(0, 1));\n numericG = processHex(hex.substring(1, 2));\n numericB = processHex(hex.substring(2, 3));\n } else {\n // 6-digit hex (e.g., #33aa77)\n numericR = processHex(hex.substring(0, 2));\n numericG = processHex(hex.substring(2, 4));\n numericB = processHex(hex.substring(4, 6));\n }\n\n // Process hex alpha if provided (convert from 0-255 to 0-1)\n const numericA = alphaHex ? processHex(alphaHex) : 1;\n\n // Validate the color values\n result.spaceId = 'srgb';\n result.coords = [numericR, numericG, numericB];\n result.alpha = numericA;\n result.isValid =\n numericR >= 0 &&\n numericR <= 1 &&\n numericG >= 0 &&\n numericG <= 1 &&\n numericB >= 0 &&\n numericB <= 1 &&\n numericA >= 0 &&\n numericA <= 1;\n }\n\n return result;\n }\n\n /**\n * Represents the color state of the component.\n * Initialized with an HSV color model with hue 0, saturation 100, and value 100, and an alpha value of 1.\n *\n * @private\n * @type {Color}\n */\n private _color: Color = new Color('hsv', [0, 100, 100], 1);\n\n /**\n * Represents the original color value provided by the user.\n *\n * @private\n * @type {ColorTypes}\n */\n private _colorOrigin!: ColorTypes;\n\n /**\n * Gets the original color value provided by the user.\n *\n * @returns {ColorTypes} The original color value.\n */\n get colorOrigin(): ColorTypes {\n return this._colorOrigin;\n }\n\n /**\n * Sets the original color value provided by the user.\n *\n * @param {ColorTypes} colorOrigin - The original color value to set.\n */\n set colorOrigin(colorOrigin: ColorTypes) {\n this._colorOrigin = colorOrigin;\n }\n\n /**\n * An optional string property that specifies how the color should be managed(its value is the name of color space in which color object will be managed).\n * This property can be used to define a specific management strategy or identifier.\n */\n private manageAs?: string;\n\n /**\n * Stores the previous color value.\n * This is used to keep track of the color before any changes are made.\n *\n * @private\n */\n private _previousColor!: Color;\n\n /**\n * Private helper method to convert RGB color to hex format with optional alpha\n *\n * @private\n * @param {boolean} includeHash - Whether to include the # prefix in the returned string\n * @param {boolean} includeAlpha - Whether to include the alpha channel in the returned string\n * @returns {string} The color in hex format\n */\n private _getHexString(includeHash: boolean, includeAlpha: boolean): string {\n const { r, g, b } = (this._color.to('srgb') as Color).srgb;\n const a = this._color.alpha;\n\n const toHex = (channel: number): string =>\n Math.round(channel * 255)\n .toString(16)\n .padStart(2, '0');\n\n const rHex = toHex(r);\n const gHex = toHex(g);\n const bHex = toHex(b);\n const aHex = toHex(a);\n\n return `${includeHash ? '#' : ''}${rHex}${gHex}${bHex}${includeAlpha ? aHex : ''}`;\n }\n\n /**\n * Sets the color value for the controller. The color can be provided in various formats:\n * - A string representing a color name, hex code, or other color format.\n * - An instance of the `Color` class.\n * - An object containing color properties such as `h`, `s`, `l`, `v`, `r`, `g`, `b`, and optionally `a`.\n *\n * The method validates and parses the input color, converting it to a `Color` instance.\n * If the color is invalid, it attempts to parse it as a hex code or returns without setting a new color.\n *\n * @param {ColorTypes} color - The color value to set. It can be a string, an instance of `Color`, or an object with color properties.\n */\n set color(color: ColorTypes) {\n this._colorOrigin = color;\n let newColor!: Color;\n if (typeof color === 'string') {\n const colorValidationResult = this.validateColorString(color as string);\n if (colorValidationResult.isValid) {\n const [coord1, coord2, coord3] = colorValidationResult.coords;\n newColor = new Color(\n `${colorValidationResult.spaceId}`,\n [coord1, coord2, coord3],\n colorValidationResult.alpha\n );\n } else {\n try {\n Color.parse(color);\n } catch (error) {\n debugWarn(this.host, `Failed to parse color: ${color}`, error);\n try {\n newColor = new Color(`#${color}`);\n } catch (error) {\n debugWarn(\n this.host,\n `Failed to parse color as hex: ${color}`,\n error\n );\n return;\n }\n }\n }\n } else if (color instanceof Color) {\n newColor = color;\n } else if (!Array.isArray(color)) {\n const { h, s, l, v, r, g, b, a } = color as LooseColorObject;\n if (typeof h !== 'undefined' && typeof s !== 'undefined') {\n const lv = l ?? v;\n newColor = new Color(\n typeof l !== 'undefined' ? 'hsl' : 'hsv',\n [\n parseFloat(`${h}`),\n typeof s !== 'string' ? (s as number) * 100 : parseFloat(s),\n typeof lv !== 'string' ? (lv as number) * 100 : parseFloat(lv),\n ],\n parseFloat(`${a ?? '1'}`)\n );\n } else if (\n typeof r !== 'undefined' &&\n typeof g !== 'undefined' &&\n typeof b !== 'undefined'\n ) {\n newColor = new Color(\n 'srgb',\n [\n parseFloat(`${r}`) / 255,\n parseFloat(`${g}`) / 255,\n parseFloat(`${b}`) / 255,\n ],\n parseFloat(`${a ?? '1'}`)\n );\n }\n }\n\n if (!newColor) {\n newColor = new Color(color as DefaultColorTypes);\n }\n\n if (this.manageAs) {\n this._color = newColor.to(this.manageAs) as Color;\n } else {\n this._color = newColor;\n }\n this.host.requestUpdate();\n }\n\n /**\n * Gets the color value in various formats based on the original color input.\n *\n * The method determines the color space of the original color input and converts\n * the color to the appropriate format. The supported color spaces are:\n * - HSV (Hue, Saturation, Value)\n * - HSL (Hue, Saturation, Lightness)\n * - Hexadecimal (with or without alpha)\n * - RGB (Red, Green, Blue) with optional alpha\n *\n * @returns {ColorTypes} The color value in the appropriate format.\n *\n * The method handles the following cases:\n * - If the original color input is a string, it checks the prefix to determine the color space.\n * - If the original color input is an object, it checks the properties to determine the color space.\n * - If the original color input is not provided, it defaults to the current color space of the color object.\n *\n * The returned color value can be in one of the following formats:\n * - `hsv(h, s%, v%)` or `hsva(h, s%, v%, a)`\n * - `hsl(h, s%, l%)` or `hsla(h, s%, l%, a)`\n * - `#rrggbb` or `#rrggbbaa`\n * - `rgb(r, g, b)` or `rgba(r, g, b, a)`\n * - `{ h, s, v, a }` for HSV object\n * - `{ h, s, l, a }` for HSL object\n * - `{ r, g, b, a }` for RGB object\n */\n get colorValue(): ColorTypes {\n if (typeof this._colorOrigin === 'string') {\n let spaceId = '';\n if (this._colorOrigin.startsWith('#')) {\n spaceId = 'hex string';\n } else if (this._colorOrigin.startsWith('rgb')) {\n spaceId = 'rgb';\n } else if (this._colorOrigin.startsWith('hsl')) {\n spaceId = 'hsl';\n } else if (this._colorOrigin.startsWith('hsv')) {\n spaceId = 'hsv';\n } else {\n spaceId = 'hex';\n }\n switch (spaceId) {\n case 'hsv': {\n const hadAlpha = this._colorOrigin[3] === 'a';\n const { h, s, v } = (this._color.to('hsv') as Color).hsv;\n const a = this._color.alpha;\n return `hsv${hadAlpha ? `a` : ''}(${Math.round(\n h\n )}, ${Math.round(s)}%, ${Math.round(v)}%${hadAlpha ? `, ${a}` : ''})`;\n }\n case 'hsl': {\n const hadAlpha = this._colorOrigin[3] === 'a';\n const { h, s, l } = (this._color.to('hsl') as Color).hsl;\n const a = this._color.alpha;\n return `hsl${hadAlpha ? `a` : ''}(${Math.round(\n h\n )}, ${Math.round(s)}%, ${Math.round(l)}%${hadAlpha ? `, ${a}` : ''})`;\n }\n case 'hex string': {\n // Check if the original input included alpha\n const hadAlpha =\n this._colorOrigin.length === 9 || // #RRGGBBAA format\n this._colorOrigin.length === 5; // #RGBA format\n return this._getHexString(true, hadAlpha);\n }\n case 'hex': {\n // Check if the original input included alpha\n const hadAlpha =\n this._colorOrigin.length === 8 || // RRGGBBAA format (no #)\n this._colorOrigin.length === 4; // RGBA format (no #)\n return this._getHexString(false, hadAlpha);\n }\n //rgb\n default: {\n const { r, g, b } = (this._color.to('srgb') as Color).srgb;\n const hadAlpha = this._colorOrigin[3] === 'a';\n const a = this._color.alpha;\n if (this._colorOrigin.search('%') > -1) {\n return `rgb${hadAlpha ? `a` : ''}(${Math.round(r * 100)}%, ${Math.round(\n g * 100\n )}%, ${Math.round(b * 100)}%${hadAlpha ? `,${Math.round(a * 100)}%` : ''})`;\n }\n return `rgb${hadAlpha ? `a` : ''}(${Math.round(r * 255)}, ${Math.round(\n g * 255\n )}, ${Math.round(b * 255)}${hadAlpha ? `, ${a}` : ''})`;\n }\n }\n }\n let spaceId;\n if (this._colorOrigin) {\n try {\n ({ spaceId } = new Color(this._colorOrigin as DefaultColorTypes));\n } catch (error) {\n debugWarn(\n this.host,\n `Failed to parse color as default color types: ${JSON.stringify(\n this._colorOrigin\n )}`,\n error\n );\n spaceId = spaceIdFromColorObject(this._colorOrigin as LooseColorObject);\n }\n } else {\n ({ spaceId } = this.color);\n }\n switch (spaceId) {\n case 'hsv': {\n const { h, s, v } = (this._color.to('hsv') as Color).hsv;\n return {\n h,\n s: s / 100,\n v: v / 100,\n a: this._color.alpha,\n };\n }\n case 'hsl': {\n const { h, s, l } = (this._color.to('hsl') as Color).hsl;\n return {\n h,\n s: s / 100,\n l: l / 100,\n a: this._color.alpha,\n };\n }\n case 'srgb': {\n const { r, g, b } = (this._color.to('srgb') as Color).srgb;\n if (\n this._colorOrigin &&\n typeof (this._colorOrigin as { r: string }).r === 'string' &&\n (this._colorOrigin as { r: string }).r.includes('%')\n ) {\n return {\n r: `${Math.round(r * 100)}%`,\n g: `${Math.round(g * 100)}%`,\n b: `${Math.round(b * 100)}%`,\n a: this._color.alpha,\n };\n }\n return {\n r: Math.round(r * 255),\n g: Math.round(g * 255),\n b: Math.round(b * 255),\n a: this._color.alpha,\n };\n }\n }\n return this._color;\n }\n\n protected host: ReactiveElement;\n\n /**\n * Gets the hue value of the current color in HSL format.\n *\n * @returns {number} The hue value as a number.\n */\n get hue(): number {\n return Number((this._color.to('hsl') as Color).hsl.h);\n }\n\n /**\n * Sets the hue value of the color and requests an update from the host.\n *\n * @param hue - The hue value to set, represented as a number.\n */\n set hue(hue: number) {\n this._color.set('h', hue);\n this.host.requestUpdate();\n }\n\n /**\n * Creates an instance of ColorController.\n *\n * @param host - The ReactiveElement that this controller is associated with.\n * @param options - An object containing optional parameters.\n * @param options.manageAs - A string to manage the controller as a specific type.\n */\n constructor(\n host: ReactiveElement,\n {\n manageAs,\n }: {\n manageAs?: string;\n } = {}\n ) {\n this.host = host;\n this.manageAs = manageAs;\n }\n\n /**\n * Converts the current color to the specified format.\n *\n * @param format - The desired color format. It can be a string representing one of the valid formats\n * ('srgb', 'hsv', 'hsl') or a ColorSpace.Space object.\n * @returns The color object in the specified format.\n * @throws Will throw an error if the provided format is not a valid string format.\n */\n getColor(format: string | ColorSpace.Space): ColorObject {\n if (\n typeof format === 'string' &&\n !VALID_GET_COLOR_FORMATS.includes(\n format as (typeof VALID_GET_COLOR_FORMATS)[number]\n )\n ) {\n throw new Error('not a valid format');\n }\n\n return this._color.to(format);\n }\n\n /**\n * Converts the current color to an HSL string representation.\n *\n * @returns {string} The HSL string representation of the current color.\n */\n getHslString(): string {\n return this._color.to('hsl').toString();\n }\n\n /**\n * Saves the current color state by cloning the current color and storing it\n * as the previous color. This allows for the ability to revert to the previous\n * color state if needed.\n *\n * @returns {void}\n */\n savePreviousColor(): void {\n this._previousColor = this._color.clone();\n }\n\n /**\n * Restores the color to the previously saved color value.\n *\n * This method sets the current color (`_color`) to the previously stored color (`_previousColor`).\n */\n restorePreviousColor(): void {\n this._color = this._previousColor;\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Copyright 2026 Adobe. All rights reserved.
3
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License. You may obtain a copy
5
+ * of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ *
7
+ * Unless required by applicable law or agreed to in writing, software distributed under
8
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ * OF ANY KIND, either express or implied. See the License for the specific language
10
+ * governing permissions and limitations under the License.
11
+ */
12
+ export { DragAndDropController, type DragAndDropControllerOptions, type DragLeaveSnapshot, } from './src/drag-and-drop-controller.js';
@@ -0,0 +1,2 @@
1
+ import { DragAndDropController as e } from "./src/drag-and-drop-controller.js";
2
+ export { e as DragAndDropController };
@@ -0,0 +1,68 @@
1
+ import { ReactiveController, ReactiveElement } from 'lit';
2
+ /**
3
+ * Snapshot of the fields read from a native `DragEvent` before it's recycled
4
+ * by the browser, safe to read after the debounce in {@link DragAndDropControllerOptions.onDragLeave}.
5
+ */
6
+ export interface DragLeaveSnapshot {
7
+ clientX: number;
8
+ clientY: number;
9
+ relatedTarget: EventTarget | null;
10
+ }
11
+ /** Configuration options for {@link DragAndDropController}. */
12
+ export interface DragAndDropControllerOptions {
13
+ /**
14
+ * The host's own current "is a drag over me" flag. The controller never
15
+ * keeps a copy of this state; it re-reads it on every native event so a
16
+ * host that also exposes this flag as a public, externally-settable
17
+ * property (as `swc-dropzone` does) can never drift out of sync with it.
18
+ */
19
+ isDragged: () => boolean;
20
+ /**
21
+ * Return `false` to reject the current drag payload; sets the OS cursor to
22
+ * "not-allowed". Called on every native `dragover` tick. Defaults to
23
+ * always-accept.
24
+ */
25
+ shouldAccept?: (event: DragEvent) => boolean;
26
+ /** Called once when an accepted drag enters — not on every `dragover` tick. Set `isDragged`'s backing flag to `true` here. */
27
+ onDragEnter?: (event: DragEvent) => void;
28
+ /** Called once the accepted drag leaves or becomes rejected. Set `isDragged`'s backing flag to `false` here. */
29
+ onDragLeave?: (snapshot: DragLeaveSnapshot) => void;
30
+ /** Called on drop, only when `isDragged()` is currently `true`. */
31
+ onDrop?: (event: DragEvent) => void;
32
+ /** OS cursor feedback while an accepted drag hovers. Defaults to `'copy'`. */
33
+ dropEffect?: () => DataTransfer['dropEffect'];
34
+ }
35
+ /**
36
+ * A Lit {@link ReactiveController} that manages native drag-and-drop event
37
+ * wiring (`dragover` / `dragleave` / `drop`) for a host element: debounces
38
+ * `dragleave` so passing over a child element doesn't flicker the state,
39
+ * de-duplicates entry so `onDragEnter` fires once per hover session rather
40
+ * than on every `dragover` tick, and lets the host veto payloads it doesn't
41
+ * want via `shouldAccept`.
42
+ *
43
+ * The host owns its own "dragged" state (via `isDragged`/`onDragEnter`/
44
+ * `onDragLeave`); this controller only drives the timing.
45
+ *
46
+ * @example
47
+ * ```ts
48
+ * const dragAndDrop = new DragAndDropController(this, {
49
+ * isDragged: () => this._dragged,
50
+ * onDragEnter: () => { this._dragged = true; },
51
+ * onDragLeave: () => { this._dragged = false; },
52
+ * onDrop: (event) => this._handleFilesDropped(event.dataTransfer?.files),
53
+ * });
54
+ * ```
55
+ */
56
+ export declare class DragAndDropController implements ReactiveController {
57
+ private readonly _host;
58
+ private readonly _options;
59
+ private _dragLeaveTimer;
60
+ private _abortController;
61
+ constructor(host: ReactiveElement, options: DragAndDropControllerOptions);
62
+ hostConnected(): void;
63
+ hostDisconnected(): void;
64
+ private readonly _onDragOver;
65
+ private readonly _onDragLeave;
66
+ private readonly _onDrop;
67
+ private _clearDragLeaveTimer;
68
+ }