@sky.ui/core 0.0.42 → 0.0.43

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 (35) hide show
  1. package/dist/custom-elements.json +2850 -2850
  2. package/dist/helper/controllers/animation-controller.d.ts +4 -4
  3. package/dist/helper/controllers/animation-controller.js.map +1 -1
  4. package/dist/helper/iconify-offline.js.map +1 -1
  5. package/dist/helper/utils/color-resolver.js.map +1 -1
  6. package/dist/helper/utils/contrast-color.js.map +1 -1
  7. package/dist/helper/utils/size-resolver.js.map +1 -1
  8. package/dist/sky-alert/sky-alert.js.map +1 -1
  9. package/dist/sky-appbar/sky-appbar.js.map +1 -1
  10. package/dist/sky-avatar/sky-avatar.js.map +1 -1
  11. package/dist/sky-badge/sky-badge.js.map +1 -1
  12. package/dist/sky-button/sky-button.js.map +1 -1
  13. package/dist/sky-card/sky-card.js.map +1 -1
  14. package/dist/sky-checkbox/sky-checkbox.js.map +1 -1
  15. package/dist/sky-chip/sky-chip.js.map +1 -1
  16. package/dist/sky-col/sky-col.js.map +1 -1
  17. package/dist/sky-combobox/sky-combobox.js.map +1 -1
  18. package/dist/sky-dialog/sky-dialog.js.map +1 -1
  19. package/dist/sky-divider/sky-divider.js.map +1 -1
  20. package/dist/sky-flexbox/sky-flexbox.js.map +1 -1
  21. package/dist/sky-flexcol/sky-flexcol.js.map +1 -1
  22. package/dist/sky-grid/sky-grid.js.map +1 -1
  23. package/dist/sky-icon/sky-icon.js +1 -1
  24. package/dist/sky-icon/sky-icon.js.map +1 -1
  25. package/dist/sky-image/sky-image.js.map +1 -1
  26. package/dist/sky-image/srcset-utils.js.map +1 -1
  27. package/dist/sky-input/sky-input.js.map +1 -1
  28. package/dist/sky-list/sky-list.js.map +1 -1
  29. package/dist/sky-listitem/sky-listitem.js.map +1 -1
  30. package/dist/sky-radio/sky-radio.js.map +1 -1
  31. package/dist/sky-row/sky-row.js.map +1 -1
  32. package/dist/sky-sheet/sky-sheet.js.map +1 -1
  33. package/dist/sky-simple-table/sky-simple-table.js.map +1 -1
  34. package/dist/sky-theme-provider/sky-theme-provider.js.map +1 -1
  35. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"sky-avatar.js","sources":["../../src/sky-avatar/sky-avatar.ts"],"sourcesContent":["import { LitElement, html, css, PropertyValues, nothing } from \"lit\";\r\nimport { customElement, property, state } from \"lit/decorators.js\";\r\nimport { when } from \"lit/directives/when.js\";\r\nimport { keyed } from \"lit/directives/keyed.js\";\r\nimport { resolveRadius } from \"../helper/utils/size-resolver\";\r\nimport { resolveColor } from \"../helper/utils/color-resolver\";\r\nimport { styleMap } from \"lit/directives/style-map.js\";\r\nimport { classMap } from \"lit/directives/class-map.js\";\r\nimport { PresetController } from \"../helper/controllers/preset-controller\";\n\r\nexport type SkyAvatarFit = \"cover\" | \"contain\";\r\n\r\nconst SIZE_PRESETS: Record<string, string> = {\r\n sm: \"var(--sky-space-8, 2rem)\",\r\n md: \"var(--sky-space-10, 2.5rem)\",\r\n lg: \"var(--sky-space-12, 3rem)\",\r\n};\r\n\r\nconst SIZE_PX: Record<string, number> = { sm: 32, md: 40, lg: 48 };\r\n\r\n\r\n/**\r\n * @element sky-avatar\r\n *\r\n * @summary Avatar that renders image content or fallback slot content with configurable size, radius, outline, and loading state.\r\n *\r\n * @status stable\r\n * @since 1.0.0\r\n *\r\n * @documentation https://sky-ui.com/components/avatar\r\n *\r\n * @slot - Fallback content (e.g., initials or an icon) rendered when `image` is empty.\r\n *\r\n * @property {string} size - Avatar size: preset `sm` | `md` | `lg` or CSS length (for example `50px`).\r\n * @property {string} image - Image URL; fallback slot is shown on load error.\r\n * @property {SkyAvatarFit} fit - Image fill mode: `cover` (default) or `contain`.\r\n * @property {string} radius - Border radius token or CSS value.\r\n * @property {string} color - Token or CSS color applied to fallback slot content.\r\n * @property {string} alt - Accessible name when image content conveys meaning.\r\n * @property {string} outline - CSS `outline` value.\r\n * @property {string} outlineOffset - CSS `outline-offset` value.\r\n * @property {boolean} loading - Shows loading overlay when true.\r\n * @property {boolean} disabled - Dims and disables pointer interactions.\r\n * @property {boolean} interactive - Enables interactive behavior with keyboard/click activation.\r\n * @property {boolean} shadow - When true, applies solid surface, border ring, and elevation; no backdrop blur.\r\n * @property {string} preset - Named prop preset from nearest `sky-config-provider`. Default: `\"\"`.\n *\r\n * @csspart avatar - The avatar container element.\r\n * @csspart loading-overlay - The loading overlay container (shown when `loading` is true).\r\n * @csspart spinner - The spinner element shown when loading.\r\n *\r\n * @Behavior\r\n * - Applies image content when available; otherwise renders fallback slot content.\r\n * - Uses keyed rendering to reset avatar content when image availability changes.\r\n * - Scales spinner dimensions from resolved avatar size for numeric values.\r\n * - Respects reduced-motion preference by disabling spinner animation.\r\n *\r\n * @example\r\n * ```html\r\n * <sky-avatar size=\"56px\" radius=\"full\" color=\"primary\">\r\n * JD\r\n * </sky-avatar>\r\n * ```\r\n * ```vue\r\n * <template>\r\n * <sky-avatar size=\"56px\" radius=\"full\" color=\"primary\">\r\n * JD\r\n * </sky-avatar>\r\n * </template>\r\n * ```\r\n * ```jsx\r\n * export default function Demo() {\r\n * return (\r\n * <sky-avatar size=\"56px\" radius=\"full\" color=\"primary\">\r\n * JD\r\n * </sky-avatar>\r\n * );\r\n * }\r\n * ```\r\n */\r\n@customElement(\"sky-avatar\")\r\nexport class SkyAvatar extends LitElement {\r\n\r\n /** Avatar size: preset sm|md|lg or CSS length. @default \"50px\" */\r\n @property({ type: String }) size: string = \"50px\";\r\n\r\n /** Image URL. On error, slot is shown. @default \"\" */\r\n @property({ type: String }) image: string = \"\";\r\n\r\n /** How the image fills the avatar. @default \"cover\" */\r\n @property({ type: String, reflect: true }) fit: SkyAvatarFit = \"cover\";\r\n\r\n /** Border radius token or CSS value. @default \"md\" */\r\n @property({ type: String }) radius: string = \"md\";\r\n\r\n /** Accessible name when image is set. @default \"\" */\r\n @property({ type: String }) alt: string = \"\";\r\n\r\n /** Slot text/icon color token/CSS color. @default \"dark\" */\r\n @property({ type: String }) color: string = \"dark\";\r\n\r\n /** Outline string. @default \"\" */\r\n @property({ type: String }) outline: string = \"\";\r\n\r\n /** Outline offset value. @default \"2px\" */\r\n @property({ type: String }) outlineOffset: string = \"2px\";\r\n\r\n /** Loading state. @default false */\r\n @property({ type: Boolean, reflect: true }) loading: boolean = false;\r\n\r\n /** Disables the avatar. @default false */\r\n @property({ type: Boolean, reflect: true }) disabled: boolean = false;\r\n\r\n /** When true, focusable with focus ring and click. @default false */\r\n @property({ type: Boolean }) interactive: boolean = false;\r\n\r\n /**\r\n * Elevated ring styling (`border`, inset shadow). No backdrop blur on avatar media.\r\n * `false` (default) keeps the avatar minimal for inline use.\r\n */\r\n @property({ type: Boolean, reflect: true })\r\n shadow = false;\r\n\r\n /** True when image failed to load; show slot instead. */\r\n @state() private _imageError = false;\r\n\r\n\r\n\n /** Named prop preset from nearest `sky-config-provider`. */\n @property({ type: String, reflect: true }) preset = \"\";\n\n private _presets = new PresetController(this);\n\n static override styles = css`\r\n :host {\r\n display: inline-flex;\r\n line-height: 0;\r\n justify-content: center;\r\n align-items: center;\r\n }\r\n\r\n :host([disabled]) {\r\n opacity: var(--sky-opacity-disabled, 0.5);\r\n pointer-events: none;\r\n }\r\n\r\n .avatar {\r\n width: var(--avatar-size);\r\n height: var(--avatar-size);\r\n position: relative;\r\n background-size: var(--avatar-bg-size, cover);\r\n background-position: center;\r\n background-repeat: no-repeat;\r\n border-radius: var(--avatar-border-radius, var(--sky-radius-secondary));\r\n display: flex;\r\n color: var(--slot-text-color);\r\n justify-content: center;\r\n align-items: center;\r\n background-clip: padding-box;\r\n -webkit-background-clip: padding-box;\r\n box-sizing: border-box;\r\n overflow: hidden;\r\n backdrop-filter: none;\r\n -webkit-backdrop-filter: none;\r\n }\r\n\r\n :host([shadow]) .avatar {\r\n background-color: var(--sky-glass-solid);\r\n box-shadow:\r\n var(--sky-box-shadow-inset),\r\n var(--sky-box-shadow-primary);\r\n border: var(--sky-border-primary);\r\n }\r\n\r\n :host([loading]) .avatar {\r\n will-change: transform;\r\n transform: translateZ(0);\r\n }\r\n\r\n .avatar:focus-visible {\r\n outline: none;\r\n box-shadow: var(--sky-focus-ring);\r\n }\r\n\r\n :host([shadow]) .avatar:focus-visible {\r\n box-shadow:\r\n var(--sky-focus-ring),\r\n var(--sky-box-shadow-inset),\r\n var(--sky-box-shadow-primary);\r\n }\r\n\r\n .avatar--interactive {\r\n cursor: pointer;\r\n -webkit-tap-highlight-color: transparent;\r\n }\r\n\r\n .image-probe {\r\n position: absolute;\r\n width: 0;\r\n height: 0;\r\n opacity: 0;\r\n pointer-events: none;\r\n }\r\n\r\n ::slotted(*) {\r\n font-family: var(--sky-font);\r\n font-weight: var(--sky-font-weight-semibold, 600);\r\n font-size: calc(var(--avatar-size) * 0.38);\r\n line-height: 1;\r\n letter-spacing: var(--sky-letter-spacing-normal, 0);\r\n text-align: center;\r\n display: flex;\r\n justify-content: center;\r\n align-items: center;\r\n object-fit: contain;\r\n backdrop-filter: none;\r\n -webkit-backdrop-filter: none;\r\n }\r\n\r\n .loading-overlay {\r\n position: absolute;\r\n inset: 0;\r\n border-radius: inherit;\r\n background: var(--sky-overlay-secondary);\r\n display: flex;\r\n justify-content: center;\r\n align-items: center;\r\n z-index: 1;\r\n visibility: hidden;\r\n backdrop-filter: none;\r\n -webkit-backdrop-filter: none;\r\n }\r\n :host([loading]) .loading-overlay {\r\n visibility: visible;\r\n }\r\n\r\n .spinner {\r\n border-width: 2px;\r\n border-style: solid;\r\n border-color: var(--sky-border-light);\r\n border-top-color: var(--slot-text-color, var(--sky-text-primary));\r\n border-radius: var(--sky-radius-full);\r\n width: 40px;\r\n height: 40px;\r\n animation: spin var(--sky-duration-slow, 1s) linear infinite;\r\n }\r\n\r\n @keyframes spin {\r\n 0% {\r\n transform: rotate(0deg);\r\n }\r\n 100% {\r\n transform: rotate(360deg);\r\n }\r\n }\r\n\r\n @media (prefers-reduced-motion: reduce) {\r\n :host([loading]) .avatar {\r\n will-change: auto;\r\n transform: none;\r\n }\r\n\r\n .spinner {\r\n animation: none;\r\n border-top-color: var(--slot-text-color, var(--sky-text-primary));\r\n opacity: var(--sky-opacity-muted, 0.7);\r\n }\r\n }\r\n `;\r\n\r\n override updated(changed: PropertyValues): void {\r\n super.updated(changed);\r\n\r\n if (changed.has(\"image\")) {\r\n this._imageError = false;\r\n }\r\n\r\n const resolvedSize = SIZE_PRESETS[this.size] ?? this.size;\r\n this.style.setProperty(\"--avatar-size\", resolvedSize);\r\n\r\n this.style.setProperty(\r\n \"--avatar-bg-size\",\r\n this.fit === \"contain\" ? \"contain\" : \"cover\",\r\n );\r\n\r\n this.style.setProperty(\r\n \"--avatar-border-radius\",\r\n resolveRadius(this.radius),\r\n );\r\n\r\n if (this.color) {\r\n this.style.setProperty(\"--slot-text-color\", resolveColor(this.color));\r\n }\r\n\r\n this.adjustSpinnerSize();\r\n }\r\n\r\n /** Marks image load success and keeps image rendering active. */\r\n private _onImageLoad = (): void => {\r\n this._imageError = false;\r\n };\r\n\r\n /** Marks image load failure and enables fallback slot rendering. */\r\n private _onImageError = (): void => {\r\n this._imageError = true;\r\n };\r\n\r\n /** Re-dispatches click in interactive mode for host-level consumers. */\r\n private _handleInteractiveClick(e: Event): void {\r\n if (!this.interactive || this.disabled) return;\r\n e.stopPropagation();\r\n this.dispatchEvent(new Event(\"click\", { bubbles: true, composed: true }));\r\n }\r\n\r\n /** Handles keyboard activation in interactive mode. */\r\n private _handleInteractiveKeydown(e: KeyboardEvent): void {\r\n if (!this.interactive || this.disabled) return;\r\n if (e.key === \"Enter\" || e.key === \" \") {\r\n e.preventDefault();\r\n this.dispatchEvent(new Event(\"click\", { bubbles: true, composed: true }));\r\n }\r\n }\r\n\r\n\r\n\r\n /** Derives spinner dimensions from current avatar size. */\r\n private adjustSpinnerSize(): void {\r\n const avatarSizePx =\r\n SIZE_PX[this.size] ?? parseFloat(this.size);\r\n if (Number.isFinite(avatarSizePx)) {\r\n const spinnerSize = avatarSizePx * 0.25;\r\n const spinner = this.shadowRoot?.querySelector<HTMLElement>(\".spinner\");\r\n if (spinner) {\r\n spinner.style.width = `${spinnerSize}px`;\r\n spinner.style.height = `${spinnerSize}px`;\r\n spinner.style.borderWidth = `${Math.max(1, spinnerSize / 10)}px`;\r\n }\r\n }\r\n }\r\n\r\n override render() {\r\n const showImage = this.image && !this._imageError;\r\n const avatarStyle: Record<string, string> = {};\r\n if (showImage) {\r\n avatarStyle[\"backgroundImage\"] = `url(${encodeURI(this.image)})`;\r\n }\r\n if (this.outline) {\r\n avatarStyle[\"outline\"] = this.outline;\r\n }\r\n if (this.outlineOffset) {\r\n avatarStyle[\"outlineOffset\"] = this.outlineOffset;\r\n }\r\n\r\n const role = this.interactive\r\n ? \"button\"\r\n : showImage && this.alt\r\n ? \"img\"\r\n : nothing;\r\n const ariaLabel =\r\n this.interactive && this.alt\r\n ? this.alt\r\n : showImage && this.alt\r\n ? this.alt\r\n : nothing;\r\n\r\n return html`\r\n <div\r\n class=${classMap({\r\n avatar: true,\r\n \"avatar--interactive\": !!this.interactive,\r\n })}\r\n part=\"avatar\"\r\n style=${styleMap(avatarStyle)}\r\n role=${role}\r\n aria-label=${ariaLabel}\r\n tabindex=${this.interactive && !this.disabled ? \"0\" : nothing}\r\n @click=${this._handleInteractiveClick}\r\n @keydown=${this._handleInteractiveKeydown}\r\n >\r\n ${this.image\r\n ? html`<img\r\n class=\"image-probe\"\r\n src=${this.image}\r\n alt=\"\"\r\n @load=${this._onImageLoad}\r\n @error=${this._onImageError}\r\n />`\r\n : nothing}\r\n <div class=\"loading-overlay\" part=\"loading-overlay\">\r\n <div class=\"spinner\" part=\"spinner\"></div>\r\n </div>\r\n ${keyed(\r\n showImage ? \"_img_\" : \"_slot_\",\r\n when(!showImage, () => html`<slot></slot>`, () => nothing),\r\n )}\r\n </div>\r\n `;\r\n }\r\n}\r\n"],"names":["SIZE_PRESETS","sm","md","lg","SIZE_PX","SkyAvatar","LitElement","constructor","super","arguments","this","size","image","fit","radius","alt","color","outline","outlineOffset","loading","disabled","interactive","shadow","_imageError","preset","_presets","PresetController","_onImageLoad","_onImageError","updated","changed","has","resolvedSize","style","setProperty","resolveRadius","resolveColor","adjustSpinnerSize","_handleInteractiveClick","e","stopPropagation","dispatchEvent","Event","bubbles","composed","_handleInteractiveKeydown","key","preventDefault","avatarSizePx","parseFloat","Number","isFinite","spinnerSize","spinner","shadowRoot","querySelector","width","height","borderWidth","Math","max","render","showImage","avatarStyle","encodeURI","role","nothing","ariaLabel","html","classMap","avatar","styleMap","keyed","when","styles","css","__decorateClass","property","type","String","prototype","reflect","Boolean","state","customElement"],"mappings":"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"}
1
+ {"version":3,"file":"sky-avatar.js","sources":["../../src/sky-avatar/sky-avatar.ts"],"sourcesContent":["import { LitElement, html, css, PropertyValues, nothing } from \"lit\";\r\nimport { customElement, property, state } from \"lit/decorators.js\";\r\nimport { when } from \"lit/directives/when.js\";\r\nimport { keyed } from \"lit/directives/keyed.js\";\r\nimport { resolveRadius } from \"../helper/utils/size-resolver\";\r\nimport { resolveColor } from \"../helper/utils/color-resolver\";\r\nimport { styleMap } from \"lit/directives/style-map.js\";\r\nimport { classMap } from \"lit/directives/class-map.js\";\r\nimport { PresetController } from \"../helper/controllers/preset-controller\";\r\n\r\nexport type SkyAvatarFit = \"cover\" | \"contain\";\r\n\r\nconst SIZE_PRESETS: Record<string, string> = {\r\n sm: \"var(--sky-space-8, 2rem)\",\r\n md: \"var(--sky-space-10, 2.5rem)\",\r\n lg: \"var(--sky-space-12, 3rem)\",\r\n};\r\n\r\nconst SIZE_PX: Record<string, number> = { sm: 32, md: 40, lg: 48 };\r\n\r\n\r\n/**\r\n * @element sky-avatar\r\n *\r\n * @summary Avatar that renders image content or fallback slot content with configurable size, radius, outline, and loading state.\r\n *\r\n * @status stable\r\n * @since 1.0.0\r\n *\r\n * @documentation https://sky-ui.com/components/avatar\r\n *\r\n * @slot - Fallback content (e.g., initials or an icon) rendered when `image` is empty.\r\n *\r\n * @property {string} size - Avatar size: preset `sm` | `md` | `lg` or CSS length (for example `50px`).\r\n * @property {string} image - Image URL; fallback slot is shown on load error.\r\n * @property {SkyAvatarFit} fit - Image fill mode: `cover` (default) or `contain`.\r\n * @property {string} radius - Border radius token or CSS value.\r\n * @property {string} color - Token or CSS color applied to fallback slot content.\r\n * @property {string} alt - Accessible name when image content conveys meaning.\r\n * @property {string} outline - CSS `outline` value.\r\n * @property {string} outlineOffset - CSS `outline-offset` value.\r\n * @property {boolean} loading - Shows loading overlay when true.\r\n * @property {boolean} disabled - Dims and disables pointer interactions.\r\n * @property {boolean} interactive - Enables interactive behavior with keyboard/click activation.\r\n * @property {boolean} shadow - When true, applies solid surface, border ring, and elevation; no backdrop blur.\r\n * @property {string} preset - Named prop preset from nearest `sky-config-provider`. Default: `\"\"`.\r\n *\r\n * @csspart avatar - The avatar container element.\r\n * @csspart loading-overlay - The loading overlay container (shown when `loading` is true).\r\n * @csspart spinner - The spinner element shown when loading.\r\n *\r\n * @Behavior\r\n * - Applies image content when available; otherwise renders fallback slot content.\r\n * - Uses keyed rendering to reset avatar content when image availability changes.\r\n * - Scales spinner dimensions from resolved avatar size for numeric values.\r\n * - Respects reduced-motion preference by disabling spinner animation.\r\n *\r\n * @example\r\n * ```html\r\n * <sky-avatar size=\"56px\" radius=\"full\" color=\"primary\">\r\n * JD\r\n * </sky-avatar>\r\n * ```\r\n * ```vue\r\n * <template>\r\n * <sky-avatar size=\"56px\" radius=\"full\" color=\"primary\">\r\n * JD\r\n * </sky-avatar>\r\n * </template>\r\n * ```\r\n * ```jsx\r\n * export default function Demo() {\r\n * return (\r\n * <sky-avatar size=\"56px\" radius=\"full\" color=\"primary\">\r\n * JD\r\n * </sky-avatar>\r\n * );\r\n * }\r\n * ```\r\n */\r\n@customElement(\"sky-avatar\")\r\nexport class SkyAvatar extends LitElement {\r\n\r\n /** Avatar size: preset sm|md|lg or CSS length. @default \"50px\" */\r\n @property({ type: String }) size: string = \"50px\";\r\n\r\n /** Image URL. On error, slot is shown. @default \"\" */\r\n @property({ type: String }) image: string = \"\";\r\n\r\n /** How the image fills the avatar. @default \"cover\" */\r\n @property({ type: String, reflect: true }) fit: SkyAvatarFit = \"cover\";\r\n\r\n /** Border radius token or CSS value. @default \"md\" */\r\n @property({ type: String }) radius: string = \"md\";\r\n\r\n /** Accessible name when image is set. @default \"\" */\r\n @property({ type: String }) alt: string = \"\";\r\n\r\n /** Slot text/icon color token/CSS color. @default \"dark\" */\r\n @property({ type: String }) color: string = \"dark\";\r\n\r\n /** Outline string. @default \"\" */\r\n @property({ type: String }) outline: string = \"\";\r\n\r\n /** Outline offset value. @default \"2px\" */\r\n @property({ type: String }) outlineOffset: string = \"2px\";\r\n\r\n /** Loading state. @default false */\r\n @property({ type: Boolean, reflect: true }) loading: boolean = false;\r\n\r\n /** Disables the avatar. @default false */\r\n @property({ type: Boolean, reflect: true }) disabled: boolean = false;\r\n\r\n /** When true, focusable with focus ring and click. @default false */\r\n @property({ type: Boolean }) interactive: boolean = false;\r\n\r\n /**\r\n * Elevated ring styling (`border`, inset shadow). No backdrop blur on avatar media.\r\n * `false` (default) keeps the avatar minimal for inline use.\r\n */\r\n @property({ type: Boolean, reflect: true })\r\n shadow = false;\r\n\r\n /** True when image failed to load; show slot instead. */\r\n @state() private _imageError = false;\r\n\r\n\r\n\r\n /** Named prop preset from nearest `sky-config-provider`. */\r\n @property({ type: String, reflect: true }) preset = \"\";\r\n\r\n private _presets = new PresetController(this);\r\n\r\n static override styles = css`\r\n :host {\r\n display: inline-flex;\r\n line-height: 0;\r\n justify-content: center;\r\n align-items: center;\r\n }\r\n\r\n :host([disabled]) {\r\n opacity: var(--sky-opacity-disabled, 0.5);\r\n pointer-events: none;\r\n }\r\n\r\n .avatar {\r\n width: var(--avatar-size);\r\n height: var(--avatar-size);\r\n position: relative;\r\n background-size: var(--avatar-bg-size, cover);\r\n background-position: center;\r\n background-repeat: no-repeat;\r\n border-radius: var(--avatar-border-radius, var(--sky-radius-secondary));\r\n display: flex;\r\n color: var(--slot-text-color);\r\n justify-content: center;\r\n align-items: center;\r\n background-clip: padding-box;\r\n -webkit-background-clip: padding-box;\r\n box-sizing: border-box;\r\n overflow: hidden;\r\n backdrop-filter: none;\r\n -webkit-backdrop-filter: none;\r\n }\r\n\r\n :host([shadow]) .avatar {\r\n background-color: var(--sky-glass-solid);\r\n box-shadow:\r\n var(--sky-box-shadow-inset),\r\n var(--sky-box-shadow-primary);\r\n border: var(--sky-border-primary);\r\n }\r\n\r\n :host([loading]) .avatar {\r\n will-change: transform;\r\n transform: translateZ(0);\r\n }\r\n\r\n .avatar:focus-visible {\r\n outline: none;\r\n box-shadow: var(--sky-focus-ring);\r\n }\r\n\r\n :host([shadow]) .avatar:focus-visible {\r\n box-shadow:\r\n var(--sky-focus-ring),\r\n var(--sky-box-shadow-inset),\r\n var(--sky-box-shadow-primary);\r\n }\r\n\r\n .avatar--interactive {\r\n cursor: pointer;\r\n -webkit-tap-highlight-color: transparent;\r\n }\r\n\r\n .image-probe {\r\n position: absolute;\r\n width: 0;\r\n height: 0;\r\n opacity: 0;\r\n pointer-events: none;\r\n }\r\n\r\n ::slotted(*) {\r\n font-family: var(--sky-font);\r\n font-weight: var(--sky-font-weight-semibold, 600);\r\n font-size: calc(var(--avatar-size) * 0.38);\r\n line-height: 1;\r\n letter-spacing: var(--sky-letter-spacing-normal, 0);\r\n text-align: center;\r\n display: flex;\r\n justify-content: center;\r\n align-items: center;\r\n object-fit: contain;\r\n backdrop-filter: none;\r\n -webkit-backdrop-filter: none;\r\n }\r\n\r\n .loading-overlay {\r\n position: absolute;\r\n inset: 0;\r\n border-radius: inherit;\r\n background: var(--sky-overlay-secondary);\r\n display: flex;\r\n justify-content: center;\r\n align-items: center;\r\n z-index: 1;\r\n visibility: hidden;\r\n backdrop-filter: none;\r\n -webkit-backdrop-filter: none;\r\n }\r\n :host([loading]) .loading-overlay {\r\n visibility: visible;\r\n }\r\n\r\n .spinner {\r\n border-width: 2px;\r\n border-style: solid;\r\n border-color: var(--sky-border-light);\r\n border-top-color: var(--slot-text-color, var(--sky-text-primary));\r\n border-radius: var(--sky-radius-full);\r\n width: 40px;\r\n height: 40px;\r\n animation: spin var(--sky-duration-slow, 1s) linear infinite;\r\n }\r\n\r\n @keyframes spin {\r\n 0% {\r\n transform: rotate(0deg);\r\n }\r\n 100% {\r\n transform: rotate(360deg);\r\n }\r\n }\r\n\r\n @media (prefers-reduced-motion: reduce) {\r\n :host([loading]) .avatar {\r\n will-change: auto;\r\n transform: none;\r\n }\r\n\r\n .spinner {\r\n animation: none;\r\n border-top-color: var(--slot-text-color, var(--sky-text-primary));\r\n opacity: var(--sky-opacity-muted, 0.7);\r\n }\r\n }\r\n `;\r\n\r\n override updated(changed: PropertyValues): void {\r\n super.updated(changed);\r\n\r\n if (changed.has(\"image\")) {\r\n this._imageError = false;\r\n }\r\n\r\n const resolvedSize = SIZE_PRESETS[this.size] ?? this.size;\r\n this.style.setProperty(\"--avatar-size\", resolvedSize);\r\n\r\n this.style.setProperty(\r\n \"--avatar-bg-size\",\r\n this.fit === \"contain\" ? \"contain\" : \"cover\",\r\n );\r\n\r\n this.style.setProperty(\r\n \"--avatar-border-radius\",\r\n resolveRadius(this.radius),\r\n );\r\n\r\n if (this.color) {\r\n this.style.setProperty(\"--slot-text-color\", resolveColor(this.color));\r\n }\r\n\r\n this.adjustSpinnerSize();\r\n }\r\n\r\n /** Marks image load success and keeps image rendering active. */\r\n private _onImageLoad = (): void => {\r\n this._imageError = false;\r\n };\r\n\r\n /** Marks image load failure and enables fallback slot rendering. */\r\n private _onImageError = (): void => {\r\n this._imageError = true;\r\n };\r\n\r\n /** Re-dispatches click in interactive mode for host-level consumers. */\r\n private _handleInteractiveClick(e: Event): void {\r\n if (!this.interactive || this.disabled) return;\r\n e.stopPropagation();\r\n this.dispatchEvent(new Event(\"click\", { bubbles: true, composed: true }));\r\n }\r\n\r\n /** Handles keyboard activation in interactive mode. */\r\n private _handleInteractiveKeydown(e: KeyboardEvent): void {\r\n if (!this.interactive || this.disabled) return;\r\n if (e.key === \"Enter\" || e.key === \" \") {\r\n e.preventDefault();\r\n this.dispatchEvent(new Event(\"click\", { bubbles: true, composed: true }));\r\n }\r\n }\r\n\r\n\r\n\r\n /** Derives spinner dimensions from current avatar size. */\r\n private adjustSpinnerSize(): void {\r\n const avatarSizePx =\r\n SIZE_PX[this.size] ?? parseFloat(this.size);\r\n if (Number.isFinite(avatarSizePx)) {\r\n const spinnerSize = avatarSizePx * 0.25;\r\n const spinner = this.shadowRoot?.querySelector<HTMLElement>(\".spinner\");\r\n if (spinner) {\r\n spinner.style.width = `${spinnerSize}px`;\r\n spinner.style.height = `${spinnerSize}px`;\r\n spinner.style.borderWidth = `${Math.max(1, spinnerSize / 10)}px`;\r\n }\r\n }\r\n }\r\n\r\n override render() {\r\n const showImage = this.image && !this._imageError;\r\n const avatarStyle: Record<string, string> = {};\r\n if (showImage) {\r\n avatarStyle[\"backgroundImage\"] = `url(${encodeURI(this.image)})`;\r\n }\r\n if (this.outline) {\r\n avatarStyle[\"outline\"] = this.outline;\r\n }\r\n if (this.outlineOffset) {\r\n avatarStyle[\"outlineOffset\"] = this.outlineOffset;\r\n }\r\n\r\n const role = this.interactive\r\n ? \"button\"\r\n : showImage && this.alt\r\n ? \"img\"\r\n : nothing;\r\n const ariaLabel =\r\n this.interactive && this.alt\r\n ? this.alt\r\n : showImage && this.alt\r\n ? this.alt\r\n : nothing;\r\n\r\n return html`\r\n <div\r\n class=${classMap({\r\n avatar: true,\r\n \"avatar--interactive\": !!this.interactive,\r\n })}\r\n part=\"avatar\"\r\n style=${styleMap(avatarStyle)}\r\n role=${role}\r\n aria-label=${ariaLabel}\r\n tabindex=${this.interactive && !this.disabled ? \"0\" : nothing}\r\n @click=${this._handleInteractiveClick}\r\n @keydown=${this._handleInteractiveKeydown}\r\n >\r\n ${this.image\r\n ? html`<img\r\n class=\"image-probe\"\r\n src=${this.image}\r\n alt=\"\"\r\n @load=${this._onImageLoad}\r\n @error=${this._onImageError}\r\n />`\r\n : nothing}\r\n <div class=\"loading-overlay\" part=\"loading-overlay\">\r\n <div class=\"spinner\" part=\"spinner\"></div>\r\n </div>\r\n ${keyed(\r\n showImage ? \"_img_\" : \"_slot_\",\r\n when(!showImage, () => html`<slot></slot>`, () => nothing),\r\n )}\r\n </div>\r\n `;\r\n }\r\n}\r\n"],"names":["SIZE_PRESETS","sm","md","lg","SIZE_PX","SkyAvatar","LitElement","constructor","super","arguments","this","size","image","fit","radius","alt","color","outline","outlineOffset","loading","disabled","interactive","shadow","_imageError","preset","_presets","PresetController","_onImageLoad","_onImageError","updated","changed","has","resolvedSize","style","setProperty","resolveRadius","resolveColor","adjustSpinnerSize","_handleInteractiveClick","e","stopPropagation","dispatchEvent","Event","bubbles","composed","_handleInteractiveKeydown","key","preventDefault","avatarSizePx","parseFloat","Number","isFinite","spinnerSize","spinner","shadowRoot","querySelector","width","height","borderWidth","Math","max","render","showImage","avatarStyle","encodeURI","role","nothing","ariaLabel","html","classMap","avatar","styleMap","keyed","when","styles","css","__decorateClass","property","type","String","prototype","reflect","Boolean","state","customElement"],"mappings":"wuBAYA,MAAMA,EAAuC,CAC3CC,GAAI,2BACJC,GAAI,8BACJC,GAAI,6BAGAC,EAAkC,CAAEH,GAAI,GAAIC,GAAI,GAAIC,GAAI,IA+DvD,IAAME,EAAN,cAAwBC,EAAxB,WAAAC,GAAAC,SAAAC,WAGuBC,KAAAC,KAAe,OAGfD,KAAAE,MAAgB,GAGDF,KAAAG,IAAoB,QAGnCH,KAAAI,OAAiB,KAGjBJ,KAAAK,IAAc,GAGdL,KAAAM,MAAgB,OAGhBN,KAAAO,QAAkB,GAGlBP,KAAAQ,cAAwB,MAGRR,KAAAS,SAAmB,EAGnBT,KAAAU,UAAoB,EAGnCV,KAAAW,aAAuB,EAOpDX,KAAAY,QAAS,EAGAZ,KAAQa,aAAc,EAKYb,KAAAc,OAAS,GAEpDd,KAAQe,SAAW,IAAIC,EAAiBhB,MAuKxCA,KAAQiB,aAAe,KACrBjB,KAAKa,aAAc,GAIrBb,KAAQkB,cAAgB,KACtBlB,KAAKa,aAAc,EACrB,CAnCS,OAAAM,CAAQC,GACftB,MAAMqB,QAAQC,GAEVA,EAAQC,IAAI,WACdrB,KAAKa,aAAc,GAGrB,MAAMS,EAAehC,EAAaU,KAAKC,OAASD,KAAKC,KACrDD,KAAKuB,MAAMC,YAAY,gBAAiBF,GAExCtB,KAAKuB,MAAMC,YACT,mBACa,YAAbxB,KAAKG,IAAoB,UAAY,SAGvCH,KAAKuB,MAAMC,YACT,yBACAC,EAAczB,KAAKI,SAGjBJ,KAAKM,OACPN,KAAKuB,MAAMC,YAAY,oBAAqBE,EAAa1B,KAAKM,QAGhEN,KAAK2B,mBACP,CAaQ,uBAAAC,CAAwBC,GACzB7B,KAAKW,cAAeX,KAAKU,WAC9BmB,EAAEC,kBACF9B,KAAK+B,cAAc,IAAIC,MAAM,QAAS,CAAEC,SAAS,EAAMC,UAAU,KACnE,CAGQ,yBAAAC,CAA0BN,GAC3B7B,KAAKW,cAAeX,KAAKU,WAChB,UAAVmB,EAAEO,KAA6B,MAAVP,EAAEO,MACzBP,EAAEQ,iBACFrC,KAAK+B,cAAc,IAAIC,MAAM,QAAS,CAAEC,SAAS,EAAMC,UAAU,MAErE,CAKQ,iBAAAP,GACN,MAAMW,EACJ5C,EAAQM,KAAKC,OAASsC,WAAWvC,KAAKC,MACxC,GAAIuC,OAAOC,SAASH,GAAe,CACjC,MAAMI,EAA6B,IAAfJ,EACdK,EAAU3C,KAAK4C,YAAYC,cAA2B,YACxDF,IACFA,EAAQpB,MAAMuB,MAAQ,GAAGJ,MACzBC,EAAQpB,MAAMwB,OAAS,GAAGL,MAC1BC,EAAQpB,MAAMyB,YAAc,GAAGC,KAAKC,IAAI,EAAGR,EAAc,QAE7D,CACF,CAES,MAAAS,GACP,MAAMC,EAAYpD,KAAKE,QAAUF,KAAKa,YAChCwC,EAAsC,CAAA,EACxCD,IACFC,EAA6B,gBAAI,OAAOC,UAAUtD,KAAKE,WAErDF,KAAKO,UACP8C,EAAqB,QAAIrD,KAAKO,SAE5BP,KAAKQ,gBACP6C,EAA2B,cAAIrD,KAAKQ,eAGtC,MAAM+C,EAAOvD,KAAKW,YACd,SACAyC,GAAapD,KAAKK,IAChB,MACAmD,EACAC,EACJzD,KAAKW,aAAeX,KAAKK,KAErB+C,GAAapD,KAAKK,IADlBL,KAAKK,IAGHmD,EAER,OAAOE,CAAA;;gBAEKC,EAAS,CACfC,QAAQ,EACR,wBAAyB5D,KAAKW;;gBAGxBkD,EAASR;eACVE;qBACME;mBACFzD,KAAKW,cAAgBX,KAAKU,SAAW,IAAM8C;iBAC7CxD,KAAK4B;mBACH5B,KAAKmC;;UAEdnC,KAAKE,MACHwD,CAAA;;oBAEQ1D,KAAKE;;sBAEHF,KAAKiB;uBACJjB,KAAKkB;gBAEhBsC;;;;UAIFM,EACAV,EAAY,QAAU,SACtBW,GAAMX,EAAW,IAAMM,CAAA,gBAAqB,IAAMF;;KAI1D,GA5TW7D,EAoDKqE,OAASC,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAjDGC,EAAA,CAA3BC,EAAS,CAAEC,KAAMC,UAHP1E,EAGiB2E,UAAA,OAAA,GAGAJ,EAAA,CAA3BC,EAAS,CAAEC,KAAMC,UANP1E,EAMiB2E,UAAA,QAAA,GAGeJ,EAAA,CAA1CC,EAAS,CAAEC,KAAMC,OAAQE,SAAS,KATxB5E,EASgC2E,UAAA,MAAA,GAGfJ,EAAA,CAA3BC,EAAS,CAAEC,KAAMC,UAZP1E,EAYiB2E,UAAA,SAAA,GAGAJ,EAAA,CAA3BC,EAAS,CAAEC,KAAMC,UAfP1E,EAeiB2E,UAAA,MAAA,GAGAJ,EAAA,CAA3BC,EAAS,CAAEC,KAAMC,UAlBP1E,EAkBiB2E,UAAA,QAAA,GAGAJ,EAAA,CAA3BC,EAAS,CAAEC,KAAMC,UArBP1E,EAqBiB2E,UAAA,UAAA,GAGAJ,EAAA,CAA3BC,EAAS,CAAEC,KAAMC,UAxBP1E,EAwBiB2E,UAAA,gBAAA,GAGgBJ,EAAA,CAA3CC,EAAS,CAAEC,KAAMI,QAASD,SAAS,KA3BzB5E,EA2BiC2E,UAAA,UAAA,GAGAJ,EAAA,CAA3CC,EAAS,CAAEC,KAAMI,QAASD,SAAS,KA9BzB5E,EA8BiC2E,UAAA,WAAA,GAGfJ,EAAA,CAA5BC,EAAS,CAAEC,KAAMI,WAjCP7E,EAiCkB2E,UAAA,cAAA,GAO7BJ,EAAA,CADCC,EAAS,CAAEC,KAAMI,QAASD,SAAS,KAvCzB5E,EAwCX2E,UAAA,SAAA,GAGiBJ,EAAA,CAAhBO,KA3CU9E,EA2CM2E,UAAA,cAAA,GAK0BJ,EAAA,CAA1CC,EAAS,CAAEC,KAAMC,OAAQE,SAAS,KAhDxB5E,EAgDgC2E,UAAA,SAAA,GAhDhC3E,EAANuE,EAAA,CADNQ,EAAc,eACF/E"}
@@ -1 +1 @@
1
- {"version":3,"file":"sky-badge.js","sources":["../../src/sky-badge/sky-badge.ts"],"sourcesContent":["import { LitElement, html, css, PropertyValues, nothing, unsafeCSS } from \"lit\";\nimport { customElement, property, query } from \"lit/decorators.js\";\nimport { when } from \"lit/directives/when.js\";\nimport { ref, createRef } from \"lit/directives/ref.js\";\nimport {\n resolveColor,\n resolveSemanticSurfaceKey,\n semanticSoftSurfaceTokens,\n} from \"../helper/utils/color-resolver\";\nimport { cssOnFillEnhance, ON_COLOR_FALLBACK_LIGHT } from \"../helper/utils/contrast-color\";\nimport { styleMap } from \"lit/directives/style-map.js\";\nimport { PresetController } from \"../helper/controllers/preset-controller\";\nimport { SkyIcon } from \"../sky-icon/sky-icon.js\";\nimport { skyFocusRingHostStyles } from \"../helper/styles/focus-ring\";\n\nexport type SkyBadgeClickEventDetail = { originalEvent: Event };\nexport type SkyBadgePosition = \"default\" | \"floating\" | \"inline\";\nexport type SkyBadgeShape = \"circle\" | \"pill\" | \"custom\";\nexport type SkyBadgePlacement =\n | \"custom\"\n | \"top-right\"\n | \"top-left\"\n | \"bottom-left\"\n | \"bottom-right\"\n | \"top-center\";\n\nconst SKY_BADGE_POSITIONS: readonly SkyBadgePosition[] = [\n \"default\",\n \"floating\",\n \"inline\",\n] as const;\nconst SKY_BADGE_SHAPES: readonly SkyBadgeShape[] = [\"circle\", \"pill\", \"custom\"] as const;\nconst SKY_BADGE_PLACEMENTS: readonly SkyBadgePlacement[] = [\n \"custom\",\n \"top-right\",\n \"top-left\",\n \"bottom-left\",\n \"bottom-right\",\n \"top-center\",\n] as const;\n\n/**\n * @element sky-badge\n *\n * @summary Badge for status dots, counts, or icons anchored to slotted content.\n *\n * @status stable\n * @since 1.0.0\n *\n * @documentation https://sky-ui.com/components/badge\n * @dependency sky-icon\n *\n * @slot - The content the badge attaches to.\n * @slot badge - Optional slot to override the badge content entirely.\n *\n * @fires {CustomEvent<SkyBadgeClickEventDetail>} badge-click - Emitted when badge activation occurs via click, Enter, or Space while `interactive` is true.\n *\n * @csspart container - Wrapper around the slotted content and the badge.\n * @csspart badge - The badge element. Use `badgeRef` for positioning (e.g. tooltip anchor).\n * @csspart icon - The icon element when `isIcon` is true.\n *\n * @Behavior\n * - Visibility is controlled by `show` and `hideWhenZero`.\n * - Numeric values above `max` render as `<max>+`.\n * - Interactive mode supports click and keyboard activation.\n * - Reduced motion mode removes badge transitions.\n *\n * @property {string} statusColor - Badge background token or CSS color.\n * @property {string} textColor - Text color token or CSS color.\n * @property {string} iconColor - Icon color token or CSS color; falls back to `textColor` when empty.\n * @property {SkyBadgePosition} position - Layout mode: `default | floating | inline`.\n * @property {string} value - Badge text/count or icon name in icon mode.\n * @property {boolean} isIcon - Renders icon mode when true.\n * @property {string} size - Badge and icon size CSS length.\n * @property {SkyBadgeShape} shape - Badge shape: `circle | pill | custom`.\n * @property {number} max - Maximum numeric count before rendering overflow label.\n * @property {boolean} hideWhenZero - Hides badge when value resolves to numeric zero.\n * @property {boolean} show - Forces badge visibility independent of value.\n * @property {string} offsetX - Horizontal offset CSS length.\n * @property {string} offsetY - Vertical offset CSS length.\n * @property {boolean} ring - Enables visual ring around the badge.\n * @property {string} ringColor - Ring color token or CSS color.\n * @property {string} ringOffset - Ring offset CSS length.\n * @property {string | null} badgeLabel - ARIA label override.\n * @property {boolean} badgeAriaHidden - Hides badge from assistive technology when true.\n * @property {boolean} interactive - Enables focus/activation and `badge-click` emission.\n * @property {SkyBadgePlacement} placement - Anchor placement preset for badge positioning.\n * @property {string} preset - Named prop preset from nearest `sky-config-provider`. Default: `\"\"`.\n * @method showBadge Forces badge visibility on.\n * @method hideBadge Forces badge visibility off.\n * @method setValue Updates badge value text or icon name.\n *\n * @example\n * ```html\n * <sky-badge value=\"5\" statuscolor=\"danger\" placement=\"top-right\">\n * <sky-icon icon=\"mdi:bell-outline\"></sky-icon>\n * </sky-badge>\n * ```\n * ```vue\n * <template>\n * <sky-badge value=\"5\" statuscolor=\"danger\" placement=\"top-right\">\n * <sky-icon icon=\"mdi:bell-outline\"></sky-icon>\n * </sky-badge>\n * </template>\n * ```\n * ```jsx\n * export default function Demo() {\n * return (\n * <sky-badge value=\"5\" statuscolor=\"danger\" placement=\"top-right\">\n * <sky-icon icon=\"mdi:bell-outline\"></sky-icon>\n * </sky-badge>\n * );\n * }\n * ```\n */\n@customElement(\"sky-badge\")\nexport class SkyBadge extends LitElement {\n\n static dependencies: Record<string, CustomElementConstructor> = {\n \"sky-icon\": SkyIcon,\n };\n\n /** Background color of the badge. */\n @property({ type: String, reflect: true })\n statusColor: string = \"success\";\n\n /** Color of text content inside the badge. */\n @property({ type: String, reflect: true })\n textColor: string = \"default\";\n\n /** Color of the badge icon (when `isIcon` is true). */\n @property({ type: String, reflect: true })\n iconColor: string = \"\";\n\n /** Position of the badge relative to content. */\n @property({ type: String, reflect: true }) position: SkyBadgePosition = \"default\";\n\n /** Value or icon name displayed inside the badge. */\n @property({ type: String }) value: string = \"\";\n\n /** Whether the badge should render as an icon instead of text. */\n @property({ type: Boolean, reflect: true }) isIcon =\n false;\n\n /** Size (width/height) of the badge. e.g., `8px`, `1rem`. */\n @property({ type: String, reflect: true }) size: string = \"\";\n\n /** Shape of the badge. `circle`, `pill`, or `custom` (use `--sky-badge-radius`). */\n @property({ type: String, reflect: true }) shape: SkyBadgeShape = \"custom\";\n\n /** Maximum numeric count before showing e.g., `99+`. Ignored in icon mode. */\n @property({ type: Number }) max = 99;\n\n /** Do not render the badge if numeric value is `0`. */\n @property({ type: Boolean }) hideWhenZero =\n false;\n\n /** Controls visibility regardless of value (useful for async data). */\n @property({ type: Boolean, reflect: true }) show = true;\n\n /** Pixel or CSS length offsets for `default`/`floating` positions. */\n @property({ type: String }) offsetX: string = \"0px\";\n @property({ type: String }) offsetY: string = \"0px\";\n\n /** Optional outline ring around the badge. */\n @property({ type: Boolean }) ring = false;\n @property({ type: String }) ringColor: string =\n \"primary\";\n @property({ type: String }) ringOffset: string =\n \"1px\";\n\n /** Accessiblity: override the generated aria-label for screen readers. */\n @property({ type: String }) badgeLabel:\n | string\n | null = null;\n\n /** Accessibility: if true, hides the badge from assistive tech (purely decorative). */\n @property({ type: Boolean })\n badgeAriaHidden = false;\n\n /** Make badge focusable/clickable and emit `badge-click`. */\n @property({ type: Boolean }) interactive = false;\n\n /** Corner preset; use \"custom\" to rely on offsetX/offsetY and existing behavior. */\n @property({ type: String, reflect: true }) placement: SkyBadgePlacement = \"custom\";\n\n /** Named prop preset from nearest `sky-config-provider`. */\n @property({ type: String, reflect: true }) preset = \"\";\n\n private _presets = new PresetController(this);\n\n @query(\".badge\") private _badgeEl!: HTMLSpanElement;\n\n /** Ref for the badge element (e.g. for tooltip anchor or positioning). */\n public badgeRef = createRef<HTMLSpanElement>();\n\n static override shadowRootOptions: ShadowRootInit = {\n mode: \"open\",\n delegatesFocus: true,\n };\n\n static override styles = [\n skyFocusRingHostStyles,\n css`\n :host {\n display: inline-block;\n position: relative;\n box-sizing: border-box;\n /* Theming: override with --sky-badge-* for custom sizing */\n --sky-badge-radius: var(--sky-radius-secondary);\n --sky-badge-padding: var(--sky-space-0\\\\.5, 0.125rem);\n --sky-badge-font-size: var(--sky-font-size-xs, 0.75rem);\n --sky-badge-font-weight: var(--sky-font-weight-bold, 700);\n --sky-badge-shadow: none;\n --sky-badge-translate-x: 0px;\n --sky-badge-translate-y: 0px;\n }\n\n .container {\n display: inline-flex;\n position: relative;\n align-items: center;\n }\n\n /* Badge base */\n .badge {\n min-height: 5px;\n padding: var(--sky-badge-padding);\n display: inline-flex;\n justify-content: center;\n align-items: center;\n box-shadow: var(--sky-badge-shadow);\n color: var(--_badge-text-color);\n background-color: var(--_badge-bg);\n border: var(--_badge-border, none);\n font: var(--sky-text-caption);\n font-weight: var(--sky-badge-font-weight);\n font-size: var(--sky-badge-font-size);\n line-height: var(--sky-line-height-none, 1);\n letter-spacing: var(--sky-letter-spacing-tight, -0.01em);\n position: absolute;\n z-index: 1;\n border-radius: var(--_badge-radius);\n min-width: var(--_badge-size);\n min-height: var(--_badge-size);\n top: var(--_anchor-top, auto);\n right: var(--_anchor-right, auto);\n bottom: var(--_anchor-bottom, auto);\n left: var(--_anchor-left, auto);\n transform: translate(\n var(--sky-badge-translate-x),\n var(--sky-badge-translate-y)\n );\n user-select: none;\n -webkit-user-select: none;\n white-space: nowrap;\n backdrop-filter: none;\n -webkit-backdrop-filter: none;\n transition: var(--sky-transition-fast);\n }\n\n @media (prefers-reduced-motion: reduce) {\n .badge {\n transition: none;\n }\n }\n\n /* Floating offsets & overlap */\n .badge.floating {\n transform: translate(\n calc(50% + var(--sky-badge-translate-x)),\n calc(-50% + var(--sky-badge-translate-y))\n );\n }\n\n /* Inline style participates in text flow */\n .badge.inline {\n position: static;\n display: inline-flex;\n margin-inline-start: var(--sky-space-1\\\\.5, 6px);\n transform: translate(\n var(--sky-badge-translate-x),\n var(--sky-badge-translate-y)\n );\n }\n\n /* Icon styling */\n sky-icon[part=\"icon\"] {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1em;\n height: 1em;\n font-size: var(--_icon-size);\n color: var(--_icon-color);\n backdrop-filter: none;\n -webkit-backdrop-filter: none;\n }\n\n /* Interactive affordances */\n .badge[role=\"button\"] {\n cursor: pointer;\n outline: none;\n -webkit-tap-highlight-color: transparent;\n }\n .badge[role=\"button\"]:focus-visible {\n outline: none;\n box-shadow: var(--sky-focus-ring);\n }\n\n /* Ring (outline) */\n .badge.ringed::after {\n content: \"\";\n position: absolute;\n inset: calc(-1 * var(--_ring-offset));\n border-radius: inherit;\n box-shadow: 0 0 0 2px var(--_ring-color);\n pointer-events: none;\n }\n\n .badge[data-placement=\"top-center\"] {\n transform: translate(\n calc(-50% + var(--sky-badge-translate-x)),\n var(--sky-badge-translate-y)\n );\n }\n\n /* Custom solid status fills (not soft semantic surfaces). */\n ${unsafeCSS(\n cssOnFillEnhance([\n {\n selector: \".badge[data-solid-contrast]\",\n fillVar: \"--_badge-bg\",\n },\n {\n selector: '.badge[data-solid-contrast] sky-icon[part=\"icon\"]',\n fillVar: \"--_badge-bg\",\n },\n ]),\n )}\n `,\n ];\n\n protected override updated(changed: PropertyValues<this>): void {\n if (changed.has(\"size\")) {\n if (/^\\d+$/.test(this.size as string)) this.size = `${this.size}px`;\n }\n if (\n changed.has(\"position\") &&\n !SKY_BADGE_POSITIONS.includes(this.position)\n ) {\n this.position = \"default\";\n }\n if (changed.has(\"shape\") && !SKY_BADGE_SHAPES.includes(this.shape)) {\n this.shape = \"custom\";\n }\n if (\n changed.has(\"placement\") &&\n !SKY_BADGE_PLACEMENTS.includes(this.placement)\n ) {\n this.placement = \"custom\";\n }\n }\n\n /**\n * Forces badge visibility on.\n *\n * @returns {void}\n */\n public showBadge(): void {\n this.show = true;\n }\n\n /**\n * Forces badge visibility off.\n *\n * @returns {void}\n */\n public hideBadge(): void {\n this.show = false;\n }\n\n /**\n * Updates badge value for text/count or icon modes.\n *\n * @param value Badge value or icon name.\n * @returns {void}\n */\n public setValue(value: string): void {\n this.value = value;\n }\n\n /** Emits `badge-click` for interactive activation. */\n private _onActivate = (e: Event) => {\n if (!this.interactive) return;\n this.dispatchEvent(\n new CustomEvent<SkyBadgeClickEventDetail>(\"badge-click\", {\n detail: { originalEvent: e },\n bubbles: true,\n composed: true,\n })\n );\n };\n\n /** Handles keyboard activation with Enter and Space. */\n private _onKeydown = (e: KeyboardEvent) => {\n if (!this.interactive) return;\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n this._onActivate(e);\n }\n };\n\n /** Computes accessible badge label from current render state. */\n private _computeAriaLabel(displayValue: string | null): string | null {\n if (this.badgeAriaHidden) return null;\n if (this.badgeLabel) return this.badgeLabel;\n if (this.isIcon) return \"\"; // purely visual when icon unless overridden\n if (displayValue == null || displayValue === \"\") return \"Badge\";\n const n = Number(displayValue);\n return isNaN(n) ? `Badge: ${displayValue}` : `Badge count: ${displayValue}`;\n }\n\n /** Resolves anchor edges from placement preset. */\n private _computeAnchors(placement: SkyBadgePlacement): {\n top: string;\n right: string;\n bottom: string;\n left: string;\n } {\n if (placement === \"custom\") {\n return { top: \"0\", right: \"0\", bottom: \"auto\", left: \"auto\" };\n }\n switch (placement) {\n case \"top-right\":\n return { top: \"0\", right: \"0\", bottom: \"auto\", left: \"auto\" };\n case \"top-left\":\n return { top: \"0\", right: \"auto\", bottom: \"auto\", left: \"0\" };\n case \"bottom-left\":\n return { top: \"auto\", right: \"auto\", bottom: \"0\", left: \"0\" };\n case \"bottom-right\":\n return { top: \"auto\", right: \"0\", bottom: \"0\", left: \"auto\" };\n case \"top-center\":\n return { top: \"0\", right: \"auto\", bottom: \"auto\", left: \"50%\" };\n default:\n return { top: \"0\", right: \"0\", bottom: \"auto\", left: \"auto\" };\n }\n }\n\n /** Maps semantic status tokens to soft badge surface colors. */\n private _resolveBadgeSurface(): {\n bg: string;\n color: string;\n border: string;\n } {\n const semanticKey = resolveSemanticSurfaceKey(this.statusColor);\n if (semanticKey) {\n const soft = semanticSoftSurfaceTokens(semanticKey, { bordered: true });\n const color =\n this.textColor && this.textColor !== \"default\"\n ? resolveColor(this.textColor)\n : soft.color;\n return { bg: soft.bg, color, border: soft.border };\n }\n\n return {\n bg: resolveColor(this.statusColor),\n color:\n this.textColor && this.textColor !== \"default\"\n ? resolveColor(this.textColor)\n : ON_COLOR_FALLBACK_LIGHT,\n border: \"none\",\n };\n }\n\n override render() {\n const numeric = Number(this.value);\n const isNumeric = !isNaN(numeric) && !this.isIcon;\n const shouldHideZero = this.hideWhenZero && isNumeric && numeric === 0;\n const visible = this.show && !shouldHideZero;\n const displayValue = this.isIcon\n ? null\n : isNumeric && this.max > 0 && numeric > this.max\n ? `${this.max}+`\n : this.value;\n\n const cls = [\"badge\", this.position];\n if (this.ring) cls.push(\"ringed\");\n\n const computedRadius =\n this.shape === \"circle\"\n ? \"var(--sky-radius-full)\"\n : this.shape === \"pill\"\n ? \"var(--sky-radius-full)\"\n : \"var(--sky-badge-radius)\";\n\n const surface = this._resolveBadgeSurface();\n const solidContrast =\n !resolveSemanticSurfaceKey(this.statusColor) &&\n (!this.textColor || this.textColor === \"default\");\n const { top, right, bottom, left } = this._computeAnchors(this.placement);\n const badgeStyle = {\n \"--_badge-bg\": surface.bg,\n \"--_badge-text-color\": surface.color,\n \"--_badge-border\": surface.border,\n \"--_badge-radius\": computedRadius,\n \"--_badge-size\": this.size,\n \"--_icon-size\": this.size,\n \"--_icon-color\": this.iconColor\n ? resolveColor(this.iconColor)\n : this.textColor && this.textColor !== \"default\"\n ? resolveColor(this.textColor)\n : surface.color,\n \"--_ring-color\": resolveColor(this.ringColor),\n \"--_ring-offset\": this.ringOffset,\n \"--sky-badge-translate-x\": this.offsetX,\n \"--sky-badge-translate-y\": this.offsetY,\n \"--_anchor-top\": top,\n \"--_anchor-right\": right,\n \"--_anchor-bottom\": bottom,\n \"--_anchor-left\": left,\n \"--sky-focus-ring-color\": surface.bg,\n };\n\n const ariaLabel = this._computeAriaLabel(displayValue);\n\n return html`\n <div class=\"container\" part=\"container\">\n <slot></slot>\n ${when(\n visible,\n () => html`\n <span\n class=${cls.join(\" \")}\n part=\"badge\"\n style=${styleMap(badgeStyle)}\n role=${this.interactive ? \"button\" : \"status\"}\n aria-live=${this.interactive ? \"off\" : \"polite\"}\n data-placement=${this.placement}\n ?data-solid-contrast=${solidContrast}\n aria-atomic=\"true\"\n aria-label=${ariaLabel ?? nothing}\n aria-hidden=${this.badgeAriaHidden ? \"true\" : \"false\"}\n tabindex=${this.interactive ? 0 : -1}\n @click=${this._onActivate}\n @keydown=${this._onKeydown}\n ${ref(this.badgeRef)}\n >\n <slot name=\"badge\">\n ${when(\n this.isIcon,\n () =>\n html`<sky-icon part=\"icon\" icon=${this.value} aria-hidden=\"true\"></sky-icon>`,\n () => html`${displayValue}`,\n )}\n </slot>\n </span>\n `,\n )}\n </div>\n `;\n }\n}\n"],"names":["SKY_BADGE_POSITIONS","SKY_BADGE_SHAPES","SKY_BADGE_PLACEMENTS","SkyBadge","LitElement","constructor","super","arguments","this","statusColor","textColor","iconColor","position","value","isIcon","size","shape","max","hideWhenZero","show","offsetX","offsetY","ring","ringColor","ringOffset","badgeLabel","badgeAriaHidden","interactive","placement","preset","_presets","PresetController","badgeRef","createRef","_onActivate","e","dispatchEvent","CustomEvent","detail","originalEvent","bubbles","composed","_onKeydown","key","preventDefault","updated","changed","has","test","includes","showBadge","hideBadge","setValue","_computeAriaLabel","displayValue","n","Number","isNaN","_computeAnchors","top","right","bottom","left","_resolveBadgeSurface","semanticKey","resolveSemanticSurfaceKey","soft","semanticSoftSurfaceTokens","bordered","color","resolveColor","bg","border","ON_COLOR_FALLBACK_LIGHT","render","numeric","isNumeric","shouldHideZero","visible","cls","push","computedRadius","surface","solidContrast","badgeStyle","ariaLabel","html","when","join","styleMap","nothing","ref","dependencies","SkyIcon","shadowRootOptions","mode","delegatesFocus","styles","skyFocusRingHostStyles","css","unsafeCSS","cssOnFillEnhance","selector","fillVar","__decorateClass","property","type","String","reflect","prototype","Boolean","query","customElement"],"mappings":"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"}
1
+ {"version":3,"file":"sky-badge.js","sources":["../../src/sky-badge/sky-badge.ts"],"sourcesContent":["import { LitElement, html, css, PropertyValues, nothing, unsafeCSS } from \"lit\";\r\nimport { customElement, property, query } from \"lit/decorators.js\";\r\nimport { when } from \"lit/directives/when.js\";\r\nimport { ref, createRef } from \"lit/directives/ref.js\";\r\nimport {\r\n resolveColor,\r\n resolveSemanticSurfaceKey,\r\n semanticSoftSurfaceTokens,\r\n} from \"../helper/utils/color-resolver\";\r\nimport { cssOnFillEnhance, ON_COLOR_FALLBACK_LIGHT } from \"../helper/utils/contrast-color\";\r\nimport { styleMap } from \"lit/directives/style-map.js\";\r\nimport { PresetController } from \"../helper/controllers/preset-controller\";\r\nimport { SkyIcon } from \"../sky-icon/sky-icon.js\";\r\nimport { skyFocusRingHostStyles } from \"../helper/styles/focus-ring\";\r\n\r\nexport type SkyBadgeClickEventDetail = { originalEvent: Event };\r\nexport type SkyBadgePosition = \"default\" | \"floating\" | \"inline\";\r\nexport type SkyBadgeShape = \"circle\" | \"pill\" | \"custom\";\r\nexport type SkyBadgePlacement =\r\n | \"custom\"\r\n | \"top-right\"\r\n | \"top-left\"\r\n | \"bottom-left\"\r\n | \"bottom-right\"\r\n | \"top-center\";\r\n\r\nconst SKY_BADGE_POSITIONS: readonly SkyBadgePosition[] = [\r\n \"default\",\r\n \"floating\",\r\n \"inline\",\r\n] as const;\r\nconst SKY_BADGE_SHAPES: readonly SkyBadgeShape[] = [\"circle\", \"pill\", \"custom\"] as const;\r\nconst SKY_BADGE_PLACEMENTS: readonly SkyBadgePlacement[] = [\r\n \"custom\",\r\n \"top-right\",\r\n \"top-left\",\r\n \"bottom-left\",\r\n \"bottom-right\",\r\n \"top-center\",\r\n] as const;\r\n\r\n/**\r\n * @element sky-badge\r\n *\r\n * @summary Badge for status dots, counts, or icons anchored to slotted content.\r\n *\r\n * @status stable\r\n * @since 1.0.0\r\n *\r\n * @documentation https://sky-ui.com/components/badge\r\n * @dependency sky-icon\r\n *\r\n * @slot - The content the badge attaches to.\r\n * @slot badge - Optional slot to override the badge content entirely.\r\n *\r\n * @fires {CustomEvent<SkyBadgeClickEventDetail>} badge-click - Emitted when badge activation occurs via click, Enter, or Space while `interactive` is true.\r\n *\r\n * @csspart container - Wrapper around the slotted content and the badge.\r\n * @csspart badge - The badge element. Use `badgeRef` for positioning (e.g. tooltip anchor).\r\n * @csspart icon - The icon element when `isIcon` is true.\r\n *\r\n * @Behavior\r\n * - Visibility is controlled by `show` and `hideWhenZero`.\r\n * - Numeric values above `max` render as `<max>+`.\r\n * - Interactive mode supports click and keyboard activation.\r\n * - Reduced motion mode removes badge transitions.\r\n *\r\n * @property {string} statusColor - Badge background token or CSS color.\r\n * @property {string} textColor - Text color token or CSS color.\r\n * @property {string} iconColor - Icon color token or CSS color; falls back to `textColor` when empty.\r\n * @property {SkyBadgePosition} position - Layout mode: `default | floating | inline`.\r\n * @property {string} value - Badge text/count or icon name in icon mode.\r\n * @property {boolean} isIcon - Renders icon mode when true.\r\n * @property {string} size - Badge and icon size CSS length.\r\n * @property {SkyBadgeShape} shape - Badge shape: `circle | pill | custom`.\r\n * @property {number} max - Maximum numeric count before rendering overflow label.\r\n * @property {boolean} hideWhenZero - Hides badge when value resolves to numeric zero.\r\n * @property {boolean} show - Forces badge visibility independent of value.\r\n * @property {string} offsetX - Horizontal offset CSS length.\r\n * @property {string} offsetY - Vertical offset CSS length.\r\n * @property {boolean} ring - Enables visual ring around the badge.\r\n * @property {string} ringColor - Ring color token or CSS color.\r\n * @property {string} ringOffset - Ring offset CSS length.\r\n * @property {string | null} badgeLabel - ARIA label override.\r\n * @property {boolean} badgeAriaHidden - Hides badge from assistive technology when true.\r\n * @property {boolean} interactive - Enables focus/activation and `badge-click` emission.\r\n * @property {SkyBadgePlacement} placement - Anchor placement preset for badge positioning.\r\n * @property {string} preset - Named prop preset from nearest `sky-config-provider`. Default: `\"\"`.\r\n * @method showBadge Forces badge visibility on.\r\n * @method hideBadge Forces badge visibility off.\r\n * @method setValue Updates badge value text or icon name.\r\n *\r\n * @example\r\n * ```html\r\n * <sky-badge value=\"5\" statuscolor=\"danger\" placement=\"top-right\">\r\n * <sky-icon icon=\"mdi:bell-outline\"></sky-icon>\r\n * </sky-badge>\r\n * ```\r\n * ```vue\r\n * <template>\r\n * <sky-badge value=\"5\" statuscolor=\"danger\" placement=\"top-right\">\r\n * <sky-icon icon=\"mdi:bell-outline\"></sky-icon>\r\n * </sky-badge>\r\n * </template>\r\n * ```\r\n * ```jsx\r\n * export default function Demo() {\r\n * return (\r\n * <sky-badge value=\"5\" statuscolor=\"danger\" placement=\"top-right\">\r\n * <sky-icon icon=\"mdi:bell-outline\"></sky-icon>\r\n * </sky-badge>\r\n * );\r\n * }\r\n * ```\r\n */\r\n@customElement(\"sky-badge\")\r\nexport class SkyBadge extends LitElement {\r\n\r\n static dependencies: Record<string, CustomElementConstructor> = {\r\n \"sky-icon\": SkyIcon,\r\n };\r\n\r\n /** Background color of the badge. */\r\n @property({ type: String, reflect: true })\r\n statusColor: string = \"success\";\r\n\r\n /** Color of text content inside the badge. */\r\n @property({ type: String, reflect: true })\r\n textColor: string = \"default\";\r\n\r\n /** Color of the badge icon (when `isIcon` is true). */\r\n @property({ type: String, reflect: true })\r\n iconColor: string = \"\";\r\n\r\n /** Position of the badge relative to content. */\r\n @property({ type: String, reflect: true }) position: SkyBadgePosition = \"default\";\r\n\r\n /** Value or icon name displayed inside the badge. */\r\n @property({ type: String }) value: string = \"\";\r\n\r\n /** Whether the badge should render as an icon instead of text. */\r\n @property({ type: Boolean, reflect: true }) isIcon =\r\n false;\r\n\r\n /** Size (width/height) of the badge. e.g., `8px`, `1rem`. */\r\n @property({ type: String, reflect: true }) size: string = \"\";\r\n\r\n /** Shape of the badge. `circle`, `pill`, or `custom` (use `--sky-badge-radius`). */\r\n @property({ type: String, reflect: true }) shape: SkyBadgeShape = \"custom\";\r\n\r\n /** Maximum numeric count before showing e.g., `99+`. Ignored in icon mode. */\r\n @property({ type: Number }) max = 99;\r\n\r\n /** Do not render the badge if numeric value is `0`. */\r\n @property({ type: Boolean }) hideWhenZero =\r\n false;\r\n\r\n /** Controls visibility regardless of value (useful for async data). */\r\n @property({ type: Boolean, reflect: true }) show = true;\r\n\r\n /** Pixel or CSS length offsets for `default`/`floating` positions. */\r\n @property({ type: String }) offsetX: string = \"0px\";\r\n @property({ type: String }) offsetY: string = \"0px\";\r\n\r\n /** Optional outline ring around the badge. */\r\n @property({ type: Boolean }) ring = false;\r\n @property({ type: String }) ringColor: string =\r\n \"primary\";\r\n @property({ type: String }) ringOffset: string =\r\n \"1px\";\r\n\r\n /** Accessiblity: override the generated aria-label for screen readers. */\r\n @property({ type: String }) badgeLabel:\r\n | string\r\n | null = null;\r\n\r\n /** Accessibility: if true, hides the badge from assistive tech (purely decorative). */\r\n @property({ type: Boolean })\r\n badgeAriaHidden = false;\r\n\r\n /** Make badge focusable/clickable and emit `badge-click`. */\r\n @property({ type: Boolean }) interactive = false;\r\n\r\n /** Corner preset; use \"custom\" to rely on offsetX/offsetY and existing behavior. */\r\n @property({ type: String, reflect: true }) placement: SkyBadgePlacement = \"custom\";\r\n\r\n /** Named prop preset from nearest `sky-config-provider`. */\r\n @property({ type: String, reflect: true }) preset = \"\";\r\n\r\n private _presets = new PresetController(this);\r\n\r\n @query(\".badge\") private _badgeEl!: HTMLSpanElement;\r\n\r\n /** Ref for the badge element (e.g. for tooltip anchor or positioning). */\r\n public badgeRef = createRef<HTMLSpanElement>();\r\n\r\n static override shadowRootOptions: ShadowRootInit = {\r\n mode: \"open\",\r\n delegatesFocus: true,\r\n };\r\n\r\n static override styles = [\r\n skyFocusRingHostStyles,\r\n css`\r\n :host {\r\n display: inline-block;\r\n position: relative;\r\n box-sizing: border-box;\r\n /* Theming: override with --sky-badge-* for custom sizing */\r\n --sky-badge-radius: var(--sky-radius-secondary);\r\n --sky-badge-padding: var(--sky-space-0\\\\.5, 0.125rem);\r\n --sky-badge-font-size: var(--sky-font-size-xs, 0.75rem);\r\n --sky-badge-font-weight: var(--sky-font-weight-bold, 700);\r\n --sky-badge-shadow: none;\r\n --sky-badge-translate-x: 0px;\r\n --sky-badge-translate-y: 0px;\r\n }\r\n\r\n .container {\r\n display: inline-flex;\r\n position: relative;\r\n align-items: center;\r\n }\r\n\r\n /* Badge base */\r\n .badge {\r\n min-height: 5px;\r\n padding: var(--sky-badge-padding);\r\n display: inline-flex;\r\n justify-content: center;\r\n align-items: center;\r\n box-shadow: var(--sky-badge-shadow);\r\n color: var(--_badge-text-color);\r\n background-color: var(--_badge-bg);\r\n border: var(--_badge-border, none);\r\n font: var(--sky-text-caption);\r\n font-weight: var(--sky-badge-font-weight);\r\n font-size: var(--sky-badge-font-size);\r\n line-height: var(--sky-line-height-none, 1);\r\n letter-spacing: var(--sky-letter-spacing-tight, -0.01em);\r\n position: absolute;\r\n z-index: 1;\r\n border-radius: var(--_badge-radius);\r\n min-width: var(--_badge-size);\r\n min-height: var(--_badge-size);\r\n top: var(--_anchor-top, auto);\r\n right: var(--_anchor-right, auto);\r\n bottom: var(--_anchor-bottom, auto);\r\n left: var(--_anchor-left, auto);\r\n transform: translate(\r\n var(--sky-badge-translate-x),\r\n var(--sky-badge-translate-y)\r\n );\r\n user-select: none;\r\n -webkit-user-select: none;\r\n white-space: nowrap;\r\n backdrop-filter: none;\r\n -webkit-backdrop-filter: none;\r\n transition: var(--sky-transition-fast);\r\n }\r\n\r\n @media (prefers-reduced-motion: reduce) {\r\n .badge {\r\n transition: none;\r\n }\r\n }\r\n\r\n /* Floating offsets & overlap */\r\n .badge.floating {\r\n transform: translate(\r\n calc(50% + var(--sky-badge-translate-x)),\r\n calc(-50% + var(--sky-badge-translate-y))\r\n );\r\n }\r\n\r\n /* Inline style participates in text flow */\r\n .badge.inline {\r\n position: static;\r\n display: inline-flex;\r\n margin-inline-start: var(--sky-space-1\\\\.5, 6px);\r\n transform: translate(\r\n var(--sky-badge-translate-x),\r\n var(--sky-badge-translate-y)\r\n );\r\n }\r\n\r\n /* Icon styling */\r\n sky-icon[part=\"icon\"] {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 1em;\r\n height: 1em;\r\n font-size: var(--_icon-size);\r\n color: var(--_icon-color);\r\n backdrop-filter: none;\r\n -webkit-backdrop-filter: none;\r\n }\r\n\r\n /* Interactive affordances */\r\n .badge[role=\"button\"] {\r\n cursor: pointer;\r\n outline: none;\r\n -webkit-tap-highlight-color: transparent;\r\n }\r\n .badge[role=\"button\"]:focus-visible {\r\n outline: none;\r\n box-shadow: var(--sky-focus-ring);\r\n }\r\n\r\n /* Ring (outline) */\r\n .badge.ringed::after {\r\n content: \"\";\r\n position: absolute;\r\n inset: calc(-1 * var(--_ring-offset));\r\n border-radius: inherit;\r\n box-shadow: 0 0 0 2px var(--_ring-color);\r\n pointer-events: none;\r\n }\r\n\r\n .badge[data-placement=\"top-center\"] {\r\n transform: translate(\r\n calc(-50% + var(--sky-badge-translate-x)),\r\n var(--sky-badge-translate-y)\r\n );\r\n }\r\n\r\n /* Custom solid status fills (not soft semantic surfaces). */\r\n ${unsafeCSS(\r\n cssOnFillEnhance([\r\n {\r\n selector: \".badge[data-solid-contrast]\",\r\n fillVar: \"--_badge-bg\",\r\n },\r\n {\r\n selector: '.badge[data-solid-contrast] sky-icon[part=\"icon\"]',\r\n fillVar: \"--_badge-bg\",\r\n },\r\n ]),\r\n )}\r\n `,\r\n ];\r\n\r\n protected override updated(changed: PropertyValues<this>): void {\r\n if (changed.has(\"size\")) {\r\n if (/^\\d+$/.test(this.size as string)) this.size = `${this.size}px`;\r\n }\r\n if (\r\n changed.has(\"position\") &&\r\n !SKY_BADGE_POSITIONS.includes(this.position)\r\n ) {\r\n this.position = \"default\";\r\n }\r\n if (changed.has(\"shape\") && !SKY_BADGE_SHAPES.includes(this.shape)) {\r\n this.shape = \"custom\";\r\n }\r\n if (\r\n changed.has(\"placement\") &&\r\n !SKY_BADGE_PLACEMENTS.includes(this.placement)\r\n ) {\r\n this.placement = \"custom\";\r\n }\r\n }\r\n\r\n /**\r\n * Forces badge visibility on.\r\n *\r\n * @returns {void}\r\n */\r\n public showBadge(): void {\r\n this.show = true;\r\n }\r\n\r\n /**\r\n * Forces badge visibility off.\r\n *\r\n * @returns {void}\r\n */\r\n public hideBadge(): void {\r\n this.show = false;\r\n }\r\n\r\n /**\r\n * Updates badge value for text/count or icon modes.\r\n *\r\n * @param value Badge value or icon name.\r\n * @returns {void}\r\n */\r\n public setValue(value: string): void {\r\n this.value = value;\r\n }\r\n\r\n /** Emits `badge-click` for interactive activation. */\r\n private _onActivate = (e: Event) => {\r\n if (!this.interactive) return;\r\n this.dispatchEvent(\r\n new CustomEvent<SkyBadgeClickEventDetail>(\"badge-click\", {\r\n detail: { originalEvent: e },\r\n bubbles: true,\r\n composed: true,\r\n })\r\n );\r\n };\r\n\r\n /** Handles keyboard activation with Enter and Space. */\r\n private _onKeydown = (e: KeyboardEvent) => {\r\n if (!this.interactive) return;\r\n if (e.key === \"Enter\" || e.key === \" \") {\r\n e.preventDefault();\r\n this._onActivate(e);\r\n }\r\n };\r\n\r\n /** Computes accessible badge label from current render state. */\r\n private _computeAriaLabel(displayValue: string | null): string | null {\r\n if (this.badgeAriaHidden) return null;\r\n if (this.badgeLabel) return this.badgeLabel;\r\n if (this.isIcon) return \"\"; // purely visual when icon unless overridden\r\n if (displayValue == null || displayValue === \"\") return \"Badge\";\r\n const n = Number(displayValue);\r\n return isNaN(n) ? `Badge: ${displayValue}` : `Badge count: ${displayValue}`;\r\n }\r\n\r\n /** Resolves anchor edges from placement preset. */\r\n private _computeAnchors(placement: SkyBadgePlacement): {\r\n top: string;\r\n right: string;\r\n bottom: string;\r\n left: string;\r\n } {\r\n if (placement === \"custom\") {\r\n return { top: \"0\", right: \"0\", bottom: \"auto\", left: \"auto\" };\r\n }\r\n switch (placement) {\r\n case \"top-right\":\r\n return { top: \"0\", right: \"0\", bottom: \"auto\", left: \"auto\" };\r\n case \"top-left\":\r\n return { top: \"0\", right: \"auto\", bottom: \"auto\", left: \"0\" };\r\n case \"bottom-left\":\r\n return { top: \"auto\", right: \"auto\", bottom: \"0\", left: \"0\" };\r\n case \"bottom-right\":\r\n return { top: \"auto\", right: \"0\", bottom: \"0\", left: \"auto\" };\r\n case \"top-center\":\r\n return { top: \"0\", right: \"auto\", bottom: \"auto\", left: \"50%\" };\r\n default:\r\n return { top: \"0\", right: \"0\", bottom: \"auto\", left: \"auto\" };\r\n }\r\n }\r\n\r\n /** Maps semantic status tokens to soft badge surface colors. */\r\n private _resolveBadgeSurface(): {\r\n bg: string;\r\n color: string;\r\n border: string;\r\n } {\r\n const semanticKey = resolveSemanticSurfaceKey(this.statusColor);\r\n if (semanticKey) {\r\n const soft = semanticSoftSurfaceTokens(semanticKey, { bordered: true });\r\n const color =\r\n this.textColor && this.textColor !== \"default\"\r\n ? resolveColor(this.textColor)\r\n : soft.color;\r\n return { bg: soft.bg, color, border: soft.border };\r\n }\r\n\r\n return {\r\n bg: resolveColor(this.statusColor),\r\n color:\r\n this.textColor && this.textColor !== \"default\"\r\n ? resolveColor(this.textColor)\r\n : ON_COLOR_FALLBACK_LIGHT,\r\n border: \"none\",\r\n };\r\n }\r\n\r\n override render() {\r\n const numeric = Number(this.value);\r\n const isNumeric = !isNaN(numeric) && !this.isIcon;\r\n const shouldHideZero = this.hideWhenZero && isNumeric && numeric === 0;\r\n const visible = this.show && !shouldHideZero;\r\n const displayValue = this.isIcon\r\n ? null\r\n : isNumeric && this.max > 0 && numeric > this.max\r\n ? `${this.max}+`\r\n : this.value;\r\n\r\n const cls = [\"badge\", this.position];\r\n if (this.ring) cls.push(\"ringed\");\r\n\r\n const computedRadius =\r\n this.shape === \"circle\"\r\n ? \"var(--sky-radius-full)\"\r\n : this.shape === \"pill\"\r\n ? \"var(--sky-radius-full)\"\r\n : \"var(--sky-badge-radius)\";\r\n\r\n const surface = this._resolveBadgeSurface();\r\n const solidContrast =\r\n !resolveSemanticSurfaceKey(this.statusColor) &&\r\n (!this.textColor || this.textColor === \"default\");\r\n const { top, right, bottom, left } = this._computeAnchors(this.placement);\r\n const badgeStyle = {\r\n \"--_badge-bg\": surface.bg,\r\n \"--_badge-text-color\": surface.color,\r\n \"--_badge-border\": surface.border,\r\n \"--_badge-radius\": computedRadius,\r\n \"--_badge-size\": this.size,\r\n \"--_icon-size\": this.size,\r\n \"--_icon-color\": this.iconColor\r\n ? resolveColor(this.iconColor)\r\n : this.textColor && this.textColor !== \"default\"\r\n ? resolveColor(this.textColor)\r\n : surface.color,\r\n \"--_ring-color\": resolveColor(this.ringColor),\r\n \"--_ring-offset\": this.ringOffset,\r\n \"--sky-badge-translate-x\": this.offsetX,\r\n \"--sky-badge-translate-y\": this.offsetY,\r\n \"--_anchor-top\": top,\r\n \"--_anchor-right\": right,\r\n \"--_anchor-bottom\": bottom,\r\n \"--_anchor-left\": left,\r\n \"--sky-focus-ring-color\": surface.bg,\r\n };\r\n\r\n const ariaLabel = this._computeAriaLabel(displayValue);\r\n\r\n return html`\r\n <div class=\"container\" part=\"container\">\r\n <slot></slot>\r\n ${when(\r\n visible,\r\n () => html`\r\n <span\r\n class=${cls.join(\" \")}\r\n part=\"badge\"\r\n style=${styleMap(badgeStyle)}\r\n role=${this.interactive ? \"button\" : \"status\"}\r\n aria-live=${this.interactive ? \"off\" : \"polite\"}\r\n data-placement=${this.placement}\r\n ?data-solid-contrast=${solidContrast}\r\n aria-atomic=\"true\"\r\n aria-label=${ariaLabel ?? nothing}\r\n aria-hidden=${this.badgeAriaHidden ? \"true\" : \"false\"}\r\n tabindex=${this.interactive ? 0 : -1}\r\n @click=${this._onActivate}\r\n @keydown=${this._onKeydown}\r\n ${ref(this.badgeRef)}\r\n >\r\n <slot name=\"badge\">\r\n ${when(\r\n this.isIcon,\r\n () =>\r\n html`<sky-icon part=\"icon\" icon=${this.value} aria-hidden=\"true\"></sky-icon>`,\r\n () => html`${displayValue}`,\r\n )}\r\n </slot>\r\n </span>\r\n `,\r\n )}\r\n </div>\r\n `;\r\n }\r\n}\r\n"],"names":["SKY_BADGE_POSITIONS","SKY_BADGE_SHAPES","SKY_BADGE_PLACEMENTS","SkyBadge","LitElement","constructor","super","arguments","this","statusColor","textColor","iconColor","position","value","isIcon","size","shape","max","hideWhenZero","show","offsetX","offsetY","ring","ringColor","ringOffset","badgeLabel","badgeAriaHidden","interactive","placement","preset","_presets","PresetController","badgeRef","createRef","_onActivate","e","dispatchEvent","CustomEvent","detail","originalEvent","bubbles","composed","_onKeydown","key","preventDefault","updated","changed","has","test","includes","showBadge","hideBadge","setValue","_computeAriaLabel","displayValue","n","Number","isNaN","_computeAnchors","top","right","bottom","left","_resolveBadgeSurface","semanticKey","resolveSemanticSurfaceKey","soft","semanticSoftSurfaceTokens","bordered","color","resolveColor","bg","border","ON_COLOR_FALLBACK_LIGHT","render","numeric","isNumeric","shouldHideZero","visible","cls","push","computedRadius","surface","solidContrast","badgeStyle","ariaLabel","html","when","join","styleMap","nothing","ref","dependencies","SkyIcon","shadowRootOptions","mode","delegatesFocus","styles","skyFocusRingHostStyles","css","unsafeCSS","cssOnFillEnhance","selector","fillVar","__decorateClass","property","type","String","reflect","prototype","Boolean","query","customElement"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"sky-button.js","sources":["../../src/sky-button/sky-button.ts"],"sourcesContent":["import { LitElement, html, css, nothing, unsafeCSS } from \"lit\";\nimport { customElement, property, state, eventOptions } from \"lit/decorators.js\";\nimport { when } from \"lit/directives/when.js\";\nimport { styleMap } from \"lit/directives/style-map.js\";\nimport {\n createGradient,\n darkShade,\n fadeMix,\n hoverShade,\n resolveColor,\n resolveSemanticSurfaceKey,\n semanticSoftSurfaceTokens,\n skyBorderPrimaryShorthand,\n tuneSurfaceVariantForDefaultColor,\n} from \"../helper/utils/color-resolver\";\nimport { cssOnFillEnhance, contrastOverlay, ON_COLOR_FALLBACK_LIGHT } from \"../helper/utils/contrast-color\";\nimport { resolveRadius } from \"../helper/utils/size-resolver\";\nimport { PresetController } from \"../helper/controllers/preset-controller\";\nimport { skyFocusRingHostStyles } from \"../helper/styles/focus-ring\";\nimport { ifDefined } from \"lit/directives/if-defined.js\";\nimport { SkyIcon } from \"../sky-icon/sky-icon.js\";\n\nexport type SkyButtonVariant =\n | \"solid\"\n | \"faded\"\n | \"bordered\"\n | \"transparent\"\n | \"flat\"\n | \"ghost\"\n | \"relief\"\n | \"gradient\"\n | \"shadow\"\n | \"link\";\nexport type SkyButtonType = \"button\" | \"submit\" | \"reset\";\nexport type SkyButtonAnimation =\n | \"auto\"\n | \"none\"\n | \"lift\"\n | \"push\"\n | \"scale\"\n | \"rotate\"\n | \"custom\";\n\n/**\n * @element sky-button\n *\n * @summary Styled button supporting variants, icons, loading state, ripple feedback, and form-associated behavior.\n *\n * @status stable\n * @since 1.0.0\n *\n * @documentation https://sky-ui.com/components/button\n * @dependency sky-icon\n *\n * @slot - Default slot for the button label (replaces `label` property if used).\n *\n * @csspart button - The native `<button>` element.\n * @csspart icon - The optional left/right icons.\n * @csspart loading-overlay - Overlay displayed when loading.\n * @csspart spinner - Spinner displayed when loading.\n *\n * @property {SkyButtonVariant} variant - Visual variant of the button. Use `\"link\"` for text-only control with underline on hover. Default: `\"solid\"`.\n * @property {string} color - Base color token or custom CSS color. Default: `\"primary\"`.\n * @property {SkyButtonType} type - Button type attribute. Default: `\"button\"`.\n * @property {string} form - Associated form ID for custom submit handling.\n * @property {string} size - Preset size token (`xs…xl`) or CSS size (e.g., `\"15px\"`, `\"1rem\"`). Default: `\"md\"`.\n * @property {string} radius - Preset radius token (`none…full`) or CSS radius (e.g., `\"12px\"`). Default: `\"md\"`.\n * @property {string} label - Text label for the button. Ignored if default slot is used. Default: `\"Button\"`.\n * @property {boolean} disabled - Whether the button is disabled. Default: `false`.\n * @property {boolean} loading - Shows a loading overlay when true. Default: `false`.\n * @property {string} iconL - Optional left-side icon (Iconify name). Default: `\"\"`.\n * @property {string} iconR - Optional right-side icon (Iconify name). Default: `\"\"`.\n * @property {boolean} iconOnly - Square padding for icon-only buttons; hides label text. Default: `false`.\n * @property {string} colors - Comma-separated color stops for gradient variant. Default: `\"\"`.\n * @property {SkyButtonAnimation} animation - Transform animation style. Default: `\"auto\"`.\n * @property {string} preset - Named prop preset from nearest `sky-config-provider`. Default: `\"\"`.\n * @method focusButton Focuses the internal native button.\n * @method clickButton Triggers a click on the internal native button when enabled.\n *\n * @example\n * ```html\n * <sky-button variant=\"gradient\" colors=\"linear@90deg: primary, secondary\" iconl=\"ion:add\" label=\"Create\"></sky-button>\n * <sky-button preset=\"cancel\" label=\"Cancel\"></sky-button>\n * ```\n * ```vue\n * <template>\n * <sky-button variant=\"gradient\" colors=\"linear@90deg: primary, secondary\" iconl=\"ion:add\" label=\"Create\"></sky-button>\n * <sky-button preset=\"cancel\" label=\"Cancel\"></sky-button>\n * </template>\n * ```\n * ```jsx\n * export default function Demo() {\n * return (\n * <>\n * <sky-button variant=\"gradient\" colors=\"linear@90deg: primary, secondary\" iconl=\"ion:add\" label=\"Create\"></sky-button>\n * <sky-button preset=\"cancel\" label=\"Cancel\"></sky-button>\n * </>\n * );\n * }\n * ```\n */\n@customElement(\"sky-button\")\nexport class SkyButton extends LitElement {\n\n static dependencies: Record<string, CustomElementConstructor> = {\n \"sky-icon\": SkyIcon,\n };\n\n static formAssociated = true;\n\n private internals: ElementInternals;\n /** Visual variant of the button. */\n @property({ type: String, reflect: true }) variant: SkyButtonVariant = \"solid\";\n\n /** Accepts preset tokens OR any valid CSS color (e.g., #0af, rgb(), var(--x)). */\n @property({ type: String }) color: string = \"primary\";\n\n /** Button type attribute. */\n @property({ type: String }) type: SkyButtonType = \"button\";\n\n /** Associated form ID for custom form handling. */\n @property({ type: String }) form = \"\";\n\n /** Preset tokens (`xs…xl`) OR CSS size like `\"15px\"`. */\n @property({ type: String }) size: string = \"md\";\n\n /** Preset tokens (`none…full`) OR any CSS border radius. */\n @property({ type: String }) radius: string = \"md\";\n\n /** Text label for the button. */\n @property({ type: String }) label = \"Button\";\n\n /** Disables the button. */\n @property({ type: Boolean, reflect: true }) disabled = false;\n\n /** Shows a loading spinner overlay. */\n @property({ type: Boolean, reflect: true }) loading = false;\n\n /** Left-side icon (Iconify icon name). */\n @property({ type: String }) iconL = \"\";\n\n /** Right-side icon (Iconify icon name). */\n @property({ type: String }) iconR = \"\";\n\n /** Square padding and compact layout when the button shows only an icon. */\n @property({ type: Boolean, reflect: true }) iconOnly = false;\n\n /** Colors for gradient variant. */\n @property({ type: String }) colors: string = \"\";\n\n /** Animation style for hover/active transforms. */\n @property({ type: String, reflect: true }) animation: SkyButtonAnimation = \"auto\";\n\n /** Named prop preset from nearest `sky-config-provider`. */\n @property({ type: String, reflect: true }) preset = \"\";\n\n /** @internal Set by `sky-button-group` to flatten grouped button visuals. */\n @property({ type: Boolean, reflect: true }) inGroup = false;\n\n @state() private _hasMeaningfulSlot = false;\n\n /** Inline CSS variable cache. */\n private _styleVars: Record<string, string> = {};\n\n private _presets = new PresetController(this, {\n isPaused: () => this.inGroup,\n onChange: () => {\n this._styleDirty = true;\n },\n });\n\n private _lastPresetRevision = -1;\n /** Set when presets change so `update()` rebuilds CSS vars after hostUpdate. */\n private _styleDirty = true;\n\n static styles = [\n skyFocusRingHostStyles,\n css`\n :host {\n display: inline-block;\n }\n\n :host([disabled]) {\n cursor: not-allowed;\n pointer-events: none;\n }\n\n :host([in-group]) {\n align-self: stretch;\n }\n\n :host([iconOnly]) button {\n width: auto;\n min-width: var(--btn-min-width, auto);\n aspect-ratio: 1;\n gap: 0;\n }\n\n :host([variant=\"link\"]) button {\n width: auto;\n border-radius: 0;\n text-decoration: none;\n background-color: transparent;\n background-image: linear-gradient(currentColor, currentColor);\n background-position: 0 100%;\n background-repeat: no-repeat;\n background-size: 0% 1px;\n transition:\n background-size var(--sky-duration-normal, 200ms) var(--sky-ease-default, ease),\n color var(--sky-duration-fast, 120ms) var(--sky-ease-default, ease),\n box-shadow var(--sky-duration-fast, 120ms) var(--sky-ease-default, ease),\n border-color var(--sky-duration-fast, 120ms) var(--sky-ease-default, ease),\n transform var(--sky-duration-fast, 120ms) var(--sky-ease-default, ease);\n }\n :host([variant=\"link\"]) button:hover:not(:disabled),\n :host([variant=\"link\"]) button:focus-visible:not(:disabled) {\n background-color: transparent;\n background-image: linear-gradient(currentColor, currentColor);\n background-position: 0 100%;\n background-repeat: no-repeat;\n background-size: 100% 1px;\n }\n\n button {\n position: relative;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n overflow: hidden;\n border-radius: var(--btn-radius, var(--sky-radius-primary));\n font: inherit;\n cursor: pointer;\n box-sizing: border-box;\n outline: none;\n border: var(\n --btn-border,\n var(--btn-border-width, 0) solid var(--btn-border-color, transparent)\n );\n background-color: var(--btn-bg-color, transparent);\n background-image: none;\n color: var(--btn-color);\n box-shadow: var(--btn-shadow, none);\n transform: var(--btn-transform, none);\n gap: var(--btn-gap, var(--sky-space-1, 4px));\n padding: var(--btn-padding, var(--sky-space-2, 8px) var(--sky-space-3, 14px));\n font-size: var(--btn-font-size, var(--sky-font-size-md, 1rem));\n font-family: var(--sky-font);\n white-space: nowrap;\n text-align: center;\n text-decoration: var(--btn-text-decoration, none);\n width: 100%;\n height: auto;\n min-height: var(--btn-min-height, auto);\n backdrop-filter: none;\n -webkit-backdrop-filter: none;\n transition:\n background-color var(--sky-duration-fast, 120ms) var(--sky-ease-default, ease),\n border-color var(--sky-duration-fast, 120ms) var(--sky-ease-default, ease),\n color var(--sky-duration-fast, 120ms) var(--sky-ease-default, ease),\n box-shadow var(--sky-duration-fast, 120ms) var(--sky-ease-default, ease),\n transform var(--sky-duration-fast, 120ms) var(--sky-ease-out, ease),\n opacity var(--sky-duration-fast, 120ms) var(--sky-ease-default, ease);\n\n /* Ensure button doesn't shrink */\n flex-shrink: 0;\n }\n\n :host([variant=\"gradient\"]) button {\n background: var(--btn-bg);\n background-color: transparent;\n }\n\n button:hover:not(:disabled),\n button:focus-visible:not(:disabled) {\n background-color: var(--btn-bg-color-hover, var(--btn-bg-color, transparent));\n color: var(--btn-color-hover, var(--btn-color));\n box-shadow: var(--btn-shadow-hover, var(--btn-shadow));\n border: var(\n --btn-border-hover,\n var(\n --btn-border,\n var(--btn-border-width, 0) solid\n var(--btn-border-color-hover, var(--btn-border-color, transparent))\n )\n );\n text-decoration: var(\n --btn-text-decoration-hover,\n var(--btn-text-decoration, none)\n );\n transform: var(--btn-transform-hover, var(--btn-transform, none));\n height: auto;\n min-height: var(--btn-min-height, auto);\n }\n\n :host([variant=\"gradient\"]) button:hover:not(:disabled),\n :host([variant=\"gradient\"]) button:focus-visible:not(:disabled) {\n background: var(--btn-bg-hover, var(--btn-bg));\n }\n button:focus-visible:not(:disabled) {\n box-shadow:\n var(--sky-focus-ring),\n var(--btn-shadow-hover, var(--btn-shadow, none));\n }\n button:active:not(:disabled) {\n transform: var(\n --btn-transform-active,\n var(--btn-transform-hover, var(--btn-transform, none))\n );\n }\n button:disabled {\n opacity: var(--sky-opacity-disabled, 0.5);\n cursor: not-allowed;\n pointer-events: none;\n }\n\n @media (prefers-reduced-motion: reduce) {\n button,\n :host([variant=\"link\"]) button {\n transition: none;\n }\n\n button:active:not(:disabled) {\n transform: none;\n }\n\n .ripple {\n animation: none;\n }\n\n .spinner {\n animation: none;\n }\n }\n\n .ripple {\n position: absolute;\n border-radius: 50%;\n background: rgba(255, 255, 255, 0.5);\n transform: scale(0);\n animation: ripple-animation 0.6s linear;\n pointer-events: none;\n }\n @keyframes ripple-animation {\n to {\n transform: scale(4);\n opacity: 0;\n }\n }\n sky-icon {\n display: inline-block;\n width: 1em;\n height: 1em;\n font-size: var(--icon-size, 18px);\n backdrop-filter: none;\n -webkit-backdrop-filter: none;\n }\n .loading-overlay {\n position: absolute;\n inset: 0;\n display: flex;\n justify-content: center;\n align-items: center;\n background: var(--sky-overlay-secondary);\n visibility: hidden;\n backdrop-filter: none;\n -webkit-backdrop-filter: none;\n }\n button[loading] .loading-overlay {\n visibility: visible;\n }\n .spinner {\n width: var(--spinner-size, 18px);\n height: var(--spinner-size, 18px);\n border: 2px solid currentColor;\n border-top-color: transparent;\n border-radius: 50%;\n animation: spin 1s linear infinite;\n }\n @keyframes spin {\n to {\n transform: rotate(360deg);\n }\n }\n\n /* Solid fills: enhance FG with contrast-color when supported (fallback remains --btn-color).\n Glass shadow variant is excluded. Ghost is enhanced only on hover (fill becomes solid). */\n ${unsafeCSS(\n cssOnFillEnhance([\n {\n selector:\n ':host(:is([variant=\"solid\"], [variant=\"relief\"], [variant=\"gradient\"]):not([data-text-explicit])) button',\n fillVar: \"--btn-bg-color\",\n },\n {\n selector:\n ':host(:is([variant=\"solid\"], [variant=\"relief\"], [variant=\"gradient\"]):not([data-text-explicit])) button sky-icon',\n fillVar: \"--btn-bg-color\",\n },\n {\n selector:\n ':host(:is([variant=\"solid\"], [variant=\"relief\"], [variant=\"gradient\"]):not([data-text-explicit])) button:hover:not(:disabled), :host(:is([variant=\"solid\"], [variant=\"relief\"], [variant=\"gradient\"]):not([data-text-explicit])) button:focus-visible:not(:disabled)',\n fillVar: \"var(--btn-bg-color-hover, var(--btn-bg-color))\",\n },\n {\n selector:\n ':host(:is([variant=\"solid\"], [variant=\"relief\"], [variant=\"gradient\"]):not([data-text-explicit])) button:hover:not(:disabled) sky-icon, :host(:is([variant=\"solid\"], [variant=\"relief\"], [variant=\"gradient\"]):not([data-text-explicit])) button:focus-visible:not(:disabled) sky-icon',\n fillVar: \"var(--btn-bg-color-hover, var(--btn-bg-color))\",\n },\n {\n selector:\n ':host([variant=\"ghost\"]:not([data-text-explicit])) button:hover:not(:disabled), :host([variant=\"ghost\"]:not([data-text-explicit])) button:focus-visible:not(:disabled)',\n fillVar: \"var(--btn-bg-color-hover, var(--btn-bg-color))\",\n },\n {\n selector:\n ':host([variant=\"ghost\"]:not([data-text-explicit])) button:hover:not(:disabled) sky-icon, :host([variant=\"ghost\"]:not([data-text-explicit])) button:focus-visible:not(:disabled) sky-icon',\n fillVar: \"var(--btn-bg-color-hover, var(--btn-bg-color))\",\n },\n ]),\n )}\n `,\n ];\n\n constructor() {\n super();\n // @ts-ignore\n this.internals = this.attachInternals();\n }\n\n private _slotHasMeaningfulContent(slotEl: HTMLSlotElement): boolean {\n const nodes = slotEl.assignedNodes({ flatten: true });\n return nodes.some((n) =>\n n.nodeType === Node.ELEMENT_NODE\n ? true\n : (n.textContent ?? \"\").trim().length > 0\n );\n }\n\n // Slot change handler (not a lifecycle hook).\n private _onSlotChange = (e: Event) => {\n const slot = e.target as HTMLSlotElement;\n const next = this._slotHasMeaningfulContent(slot);\n // Only set state if it actually changed to avoid extra updates\n if (next !== this._hasMeaningfulSlot) this._hasMeaningfulSlot = next;\n };\n\n /** Uses vertical padding for equal sides (icon-only square control). */\n private _toSquarePadding(padding: string): string {\n const py = parseFloat(padding.trim().split(/\\s+/)[0]);\n const n = Number.isFinite(py) ? py : 8;\n return `${n}px`;\n }\n\n private _resolveSize(input: string): {\n padding: string;\n fontSize: string;\n gap: string;\n icon: string;\n spinner: string;\n } {\n const presets: Record<\n string,\n {\n padding: string;\n fontSize: string;\n gap: string;\n icon: string;\n spinner: string;\n }\n > = {\n xs: {\n padding: \"3px 7px\",\n fontSize: \"12px\",\n gap: \"3px\",\n icon: \"14px\",\n spinner: \"14px\",\n },\n sm: {\n padding: \"5px 9px\",\n fontSize: \"14px\",\n gap: \"4px\",\n icon: \"16px\",\n spinner: \"16px\",\n },\n md: {\n padding: \"8px 14px\",\n fontSize: \"16px\",\n gap: \"5px\",\n icon: \"18px\",\n spinner: \"18px\",\n },\n lg: {\n padding: \"10px 18px\",\n fontSize: \"18px\",\n gap: \"6px\",\n icon: \"20px\",\n spinner: \"20px\",\n },\n xl: {\n padding: \"14px 24px\",\n fontSize: \"20px\",\n gap: \"8px\",\n icon: \"24px\",\n spinner: \"24px\",\n },\n };\n if (presets[input]) return presets[input];\n\n const m = String(input)\n .trim()\n .match(/^([\\d.]+)(px|rem|em)?$/i);\n const unit = m?.[2] || \"px\";\n const fsNum = m ? parseFloat(m[1]) : 16;\n const fs = `${fsNum}${unit}`;\n\n const to = (n: number) => `${Math.round(n * 100) / 100}${unit}`;\n const clamp = (n: number, min: number, max: number) =>\n Math.max(min, Math.min(max, n));\n\n const py = clamp(fsNum * 0.55, 4, 18);\n const px = clamp(fsNum * 0.9, 8, 28);\n const gap = clamp(fsNum * 0.3, 3, 10);\n const icon = clamp(fsNum * 1.125, 12, 28);\n const spinner = icon;\n\n return {\n padding: `${to(py)} ${to(px)}`,\n fontSize: fs,\n gap: to(gap),\n icon: to(icon),\n spinner: to(spinner),\n };\n }\n\n /** Theme tokens like `var(--sky-border-primary)` are full border shorthands, not colors. */\n private _isThemeBorderShorthand(border: string | undefined): boolean {\n if (!border || border === \"none\") return false;\n return /^var\\(--sky-border-/.test(border.trim());\n }\n\n /** Extracts the color token from a `Npx solid …` border shorthand. */\n private _borderColorFromShorthand(border: string | undefined): string {\n if (!border || border === \"none\" || this._isThemeBorderShorthand(border)) {\n return \"transparent\";\n }\n const match = border.match(/solid\\s+(.+)$/);\n return match?.[1]?.trim() ?? \"transparent\";\n }\n\n /**\n * Lit order: `willUpdate` → controllers `hostUpdate` (presets) → `update`/render.\n * Style vars must be built in `update()` so they see preset-applied props.\n * Building in `willUpdate` left render with `{}` after PresetController cleared/wrote props.\n */\n protected override update(changedProperties: Map<string, unknown>): void {\n this._rebuildStyleVars(changedProperties);\n super.update(changedProperties);\n }\n\n private _rebuildStyleVars(changedProperties: Map<string, unknown>): void {\n const styleProps = [\n \"color\",\n \"variant\",\n \"size\",\n \"radius\",\n \"animation\",\n \"preset\",\n \"inGroup\",\n \"disabled\",\n \"loading\",\n \"colors\",\n \"iconOnly\",\n ];\n const presetChanged = this._presets.revision !== this._lastPresetRevision;\n const needsStyleUpdate =\n this._styleDirty ||\n presetChanged ||\n styleProps.some((p) => changedProperties.has(p));\n if (!needsStyleUpdate && Object.keys(this._styleVars).length > 0) {\n return;\n }\n this._lastPresetRevision = this._presets.revision;\n this._styleDirty = false;\n\n const baseColor = resolveColor(this.color);\n const textColor = ON_COLOR_FALLBACK_LIGHT;\n\n const variantDefaults = {\n solid: {\n bg: baseColor,\n color: textColor,\n border: \"none\",\n shadow: \"none\",\n hoverBg: baseColor,\n hoverColor: textColor,\n hoverShadow: \"var(--sky-box-shadow-hover)\",\n },\n faded: {\n bg: \"var(--sky-hover-tertiary)\",\n color: baseColor,\n border: \"1px solid var(--sky-text-tertiary)\",\n shadow: \"none\",\n hoverBg: \"var(--sky-hover-secondary)\",\n hoverColor: baseColor,\n hoverShadow: \"none\",\n hoverBorder: \"1px solid var(--sky-text-secondary)\",\n },\n bordered: {\n bg: \"transparent\",\n color: baseColor,\n border: `2px solid ${baseColor}`,\n shadow: \"none\",\n hoverBg: \"transparent\",\n hoverColor: baseColor,\n hoverShadow: \"none\",\n hoverBorder: `2px solid ${hoverShade(baseColor, 25)}`,\n },\n transparent: {\n bg: \"transparent\",\n color: baseColor,\n border: \"none\",\n shadow: \"none\",\n hoverBg: fadeMix(baseColor, 15),\n hoverColor: baseColor,\n hoverShadow: \"none\",\n },\n flat: {\n bg: fadeMix(baseColor, 20),\n color: hoverShade(baseColor, 30),\n border: \"none\",\n shadow: \"none\",\n hoverBg: fadeMix(baseColor, 25),\n hoverColor: hoverShade(baseColor, 35),\n hoverShadow: \"none\",\n },\n ghost: {\n bg: \"transparent\",\n color: baseColor,\n border: `2px solid ${baseColor}`,\n shadow: \"none\",\n hoverBg: baseColor,\n hoverColor: textColor,\n hoverShadow: \"none\",\n },\n shadow: {\n bg: \"var(--sky-glass-primary)\",\n color: \"var(--sky-text-primary)\",\n border: skyBorderPrimaryShorthand(),\n shadow: \"none\",\n hoverBg: \"var(--sky-glass-primary)\",\n hoverColor: baseColor,\n hoverShadow: \"var(--sky-box-shadow-hover)\",\n hoverBorder: skyBorderPrimaryShorthand(),\n },\n relief: {\n bg: baseColor,\n color: textColor,\n border: \"none\",\n shadow: `\n inset 0 1px 0 rgba(255,255,255,0.4),\n 0 3px 0 ${darkShade(baseColor, 40)},\n 0 4px 6px -1px ${fadeMix(baseColor, 40)}\n `,\n hoverBg: baseColor,\n hoverColor: textColor,\n hoverShadow: \"none\",\n },\n gradient: {\n bg: createGradient(this.colors, baseColor),\n color: textColor,\n border: \"none\",\n shadow: \"none\",\n hoverBg: createGradient(this.colors, baseColor),\n hoverColor: textColor,\n hoverShadow: \"none\",\n },\n link: {\n bg: \"transparent\",\n color: baseColor,\n border: \"none\",\n shadow: \"none\",\n hoverBg: \"transparent\",\n hoverColor: baseColor,\n hoverShadow: \"none\",\n },\n } as const;\n\n const transformsAuto = {\n solid: { hover: \"translateY(-3px)\", active: \"translateY(-3px)\" },\n faded: {},\n bordered: {},\n transparent: {},\n flat: {},\n ghost: {},\n shadow: { hover: \"translateY(-3px)\", active: \"translateY(-3px)\" },\n gradient: {},\n relief: { hover: \"translateY(2px)\", active: \"translateY(2px)\" },\n link: {},\n } as const;\n\n const presetToTransform = (p: typeof this.animation) => {\n switch (p) {\n case \"none\":\n return { hover: \"none\", active: \"none\" };\n case \"lift\":\n return { hover: \"translateY(-2px)\", active: \"translateY(-1px)\" };\n case \"push\":\n return { hover: \"translateY(2px)\", active: \"translateY(2px)\" };\n case \"scale\":\n return { hover: \"scale(1.05)\", active: \"scale(1.02)\" };\n case \"rotate\":\n return { hover: \"rotate(3deg)\", active: \"rotate(2deg)\" };\n case \"custom\":\n return {\n hover: \"var(--btn-hover-transform, none)\",\n active:\n \"var(--btn-active-transform, var(--btn-hover-transform, none))\",\n };\n default:\n return {};\n }\n };\n\n const effVariant = this.variant;\n const effColor = this.color;\n const effSize = this.size;\n const effRadius = this.radius;\n const effAnimation = this.animation;\n\n const current = (\n effVariant in variantDefaults ? effVariant : \"solid\"\n ) as keyof typeof variantDefaults;\n let v = { ...variantDefaults[current] };\n Object.assign(\n v,\n tuneSurfaceVariantForDefaultColor(effColor, current, variantDefaults[current]),\n );\n\n const semanticKey = resolveSemanticSurfaceKey(effColor);\n if (semanticKey && (current === \"flat\" || current === \"faded\")) {\n const soft = semanticSoftSurfaceTokens(semanticKey, {\n bordered: current === \"faded\",\n });\n Object.assign(v, {\n bg: soft.bg,\n color: soft.color,\n border: current === \"faded\" ? soft.border : \"none\",\n hoverBg: \"var(--sky-hover-primary)\",\n hoverColor: soft.color,\n hoverShadow: \"none\",\n ...(current === \"faded\" ? { hoverBorder: soft.border } : {}),\n });\n }\n\n const animationMode = this.inGroup ? \"none\" : effAnimation;\n const chosen =\n animationMode === \"auto\"\n ? transformsAuto[current]\n : presetToTransform(animationMode);\n const hoverTransform = (chosen as any).hover ?? \"none\";\n const activeTransform = (chosen as any).active ?? hoverTransform ?? \"none\";\n\n const s = this._resolveSize(effSize);\n const basePadding = this.iconOnly ? this._toSquarePadding(s.padding) : s.padding;\n const baseGap = this.iconOnly ? \"0\" : s.gap;\n\n let borderWidth = 0;\n const hasBorder2 = effVariant === \"bordered\" || effVariant === \"ghost\";\n const hasBorder1 = effVariant === \"faded\" || effVariant === \"shadow\";\n\n if (hasBorder2) {\n borderWidth = 2;\n } else if (hasBorder1) {\n borderWidth = 1;\n } else if (v.border && v.border.includes(\"px\")) {\n const match = v.border.match(/(\\d+)px/);\n borderWidth = match ? parseInt(match[1]) : 0;\n }\n\n let hoverBorderWidth = borderWidth;\n if ((v as any).hoverBorder && (v as any).hoverBorder.includes(\"px\")) {\n const match = (v as any).hoverBorder.match(/(\\d+)px/);\n hoverBorderWidth = match ? parseInt(match[1]) : borderWidth;\n }\n\n // Reduce padding on bordered variants to preserve outer height.\n let adjustedPadding = effVariant === \"link\" ? \"0\" : basePadding;\n if (borderWidth > 0) {\n // Parse the original padding\n const paddingParts = basePadding.split(\" \");\n if (paddingParts.length === 1) {\n const all = parseFloat(paddingParts[0]);\n const adjusted = Math.max(all - borderWidth, 2);\n adjustedPadding = `${adjusted}px`;\n } else if (paddingParts.length === 2) {\n // Format: \"vertical horizontal\"\n const vertical = parseFloat(paddingParts[0]);\n const horizontal = parseFloat(paddingParts[1]);\n\n // Reduce vertical padding by border width to maintain same content height\n const adjustedVertical = Math.max(vertical - borderWidth, 2);\n adjustedPadding = this.iconOnly\n ? `${adjustedVertical}px`\n : `${adjustedVertical}px ${horizontal}px`;\n } else if (paddingParts.length === 4) {\n // Format: \"top right bottom left\"\n const top = parseFloat(paddingParts[0]);\n const right = parseFloat(paddingParts[1]);\n const bottom = parseFloat(paddingParts[2]);\n const left = parseFloat(paddingParts[3]);\n\n // Reduce top/bottom padding by border width\n const adjustedTop = Math.max(top - borderWidth, 2);\n const adjustedBottom = Math.max(bottom - borderWidth, 2);\n adjustedPadding = `${adjustedTop}px ${right}px ${adjustedBottom}px ${left}px`;\n }\n }\n\n const fontSize = parseFloat(s.fontSize);\n const iconPx = parseFloat(s.icon);\n let btnMinHeight: string;\n let btnMinWidth: string | undefined;\n if (effVariant === \"link\") {\n btnMinHeight = \"auto\";\n } else if (this.iconOnly) {\n const pad = parseFloat(adjustedPadding) || 0;\n const side = pad * 2 + iconPx + borderWidth * 2;\n btnMinHeight = `${side}px`;\n btnMinWidth = `${side}px`;\n } else {\n const paddingValues = adjustedPadding.split(\" \");\n const verticalPadding =\n paddingValues.length >= 2\n ? parseFloat(paddingValues[0]) +\n parseFloat(paddingValues[2] || paddingValues[0])\n : parseFloat(paddingValues[0]) * 2 || 16;\n const baseHeight = verticalPadding + fontSize + 4 + borderWidth * 2;\n btnMinHeight = `${baseHeight}px`;\n }\n\n const hoverBorderShorthand = (v as { hoverBorder?: string }).hoverBorder;\n const usesThemeBorder =\n this._isThemeBorderShorthand(v.border) ||\n this._isThemeBorderShorthand(hoverBorderShorthand);\n const borderColor = this._borderColorFromShorthand(v.border);\n const borderColorHover = this._borderColorFromShorthand(\n hoverBorderShorthand ?? v.border,\n );\n\n const vars: Record<string, string> = {\n \"--btn-color\": v.color,\n \"--btn-shadow\": v.shadow,\n \"--btn-radius\":\n effVariant === \"link\" ? \"0\" : resolveRadius(effRadius),\n \"--btn-color-hover\": v.hoverColor,\n \"--btn-shadow-hover\": v.hoverShadow,\n \"--btn-transform\": \"none\",\n \"--btn-transform-hover\": hoverTransform,\n \"--btn-transform-active\": activeTransform,\n \"--btn-padding\": adjustedPadding, // Use adjusted padding!\n \"--btn-font-size\": s.fontSize,\n \"--btn-gap\": baseGap,\n \"--icon-size\": s.icon,\n \"--spinner-size\": s.spinner,\n\n // Set min-height to maintain consistent visual height\n \"--btn-min-height\": btnMinHeight,\n ...(btnMinWidth ? { \"--btn-min-width\": btnMinWidth } : {}),\n\n // Keep border width variables\n \"--btn-border-width\": `${borderWidth}px`,\n \"--btn-border-width-hover\": `${hoverBorderWidth}px`,\n\n // Focus ring follows `color` (not global active-primary).\n \"--sky-focus-ring-color\": baseColor,\n };\n\n if (usesThemeBorder) {\n vars[\"--btn-border\"] = v.border;\n vars[\"--btn-border-hover\"] = hoverBorderShorthand ?? v.border;\n } else {\n vars[\"--btn-border-color\"] = borderColor;\n vars[\"--btn-border-color-hover\"] = borderColorHover;\n }\n\n if (effVariant === \"gradient\") {\n vars[\"--btn-bg\"] = v.bg;\n vars[\"--btn-bg-hover\"] = v.hoverBg;\n // Opaque stop for contrast-color() — gradient paint still uses --btn-bg.\n vars[\"--btn-bg-color\"] = baseColor;\n vars[\"--btn-bg-color-hover\"] = baseColor;\n } else {\n vars[\"--btn-bg-color\"] = v.bg;\n vars[\"--btn-bg-color-hover\"] = v.hoverBg;\n }\n\n if (this.inGroup) {\n // In grouped mode, do not apply sky-button's own hover skin.\n // The container group controls visual interaction consistency.\n if (effVariant === \"gradient\") {\n // One gradient is painted on sky-button-group's `.group`; segments stay clear\n // (same idea as `::slotted(button)` transparent fills for native buttons).\n vars[\"--btn-bg\"] = \"transparent\";\n vars[\"--btn-bg-hover\"] = \"color-mix(in srgb, white 8%, transparent)\";\n } else {\n vars[\"--btn-bg-color-hover\"] = vars[\"--btn-bg-color\"] ?? \"transparent\";\n }\n vars[\"--btn-color-hover\"] = vars[\"--btn-color\"];\n if (usesThemeBorder) {\n vars[\"--btn-border-hover\"] = vars[\"--btn-border\"] ?? v.border;\n } else {\n vars[\"--btn-border-color-hover\"] = vars[\"--btn-border-color\"] ?? borderColor;\n }\n vars[\"--btn-shadow-hover\"] = \"none\";\n if (effVariant === \"relief\") {\n vars[\"--btn-transform-hover\"] = \"translateY(2px)\";\n vars[\"--btn-transform-active\"] = \"translateY(2px)\";\n } else {\n vars[\"--btn-transform-hover\"] = \"none\";\n vars[\"--btn-transform-active\"] = \"none\";\n }\n }\n\n this._styleVars = vars;\n }\n\n /**\n * Focuses the internal native button.\n *\n * @returns {void}\n */\n public focusButton(): void {\n this.renderRoot.querySelector<HTMLButtonElement>(\"button\")?.focus();\n }\n\n /**\n * Triggers a click on the internal native button when enabled.\n *\n * @returns {void}\n */\n public clickButton(): void {\n if (this.disabled || this.loading) return;\n this.renderRoot.querySelector<HTMLButtonElement>(\"button\")?.click();\n }\n\n private _createRipple(event: MouseEvent): void {\n const button = event.currentTarget as HTMLElement;\n const rect = button.getBoundingClientRect();\n const ripple = document.createElement(\"span\");\n\n const size = Math.max(button.offsetWidth, button.offsetHeight);\n const x = event.clientX - rect.left - size / 2;\n const y = event.clientY - rect.top - size / 2;\n\n ripple.style.width = ripple.style.height = `${size}px`;\n ripple.style.left = `${x}px`;\n ripple.style.top = `${y}px`;\n\n const bg = getComputedStyle(button).backgroundColor || \"\";\n ripple.style.background = contrastOverlay(bg);\n\n ripple.className = \"ripple\";\n const existing = button.querySelectorAll(\".ripple\");\n const maxRipples = 3;\n if (existing.length >= maxRipples && existing[0]) {\n existing[0].remove();\n }\n button.appendChild(ripple);\n ripple.addEventListener(\"animationend\", () => ripple.remove());\n }\n\n formDisabledCallback(disabled: boolean): void {\n this.disabled = disabled;\n }\n\n get formOwner(): HTMLFormElement | null {\n if (typeof document === \"undefined\") return null;\n const formId = typeof this.form === \"string\" ? this.form.trim() : \"\";\n return (\n this.internals.form ||\n (formId ? (document.getElementById(formId) as HTMLFormElement | null) : null) ||\n this.closest(\"form\")\n );\n }\n\n @eventOptions({ passive: false })\n private _handleClick(event: MouseEvent): void {\n if (this.disabled || this.loading) {\n event.preventDefault();\n return;\n }\n\n // If button type is \"button\", prevent any default navigation-like behavior\n if (this.type === \"button\") {\n event.preventDefault();\n }\n\n this._createRipple(event);\n\n const form = this.formOwner;\n if (this.type === \"submit\") {\n form?.requestSubmit();\n return;\n }\n if (this.type === \"reset\") {\n form?.reset();\n return;\n }\n }\n\n private _iconOnlyName(): string {\n return this.iconL || this.iconR;\n }\n\n override render() {\n const iconOnlyName = this._iconOnlyName();\n const ariaLabel =\n this.iconOnly && (this.label || iconOnlyName)\n ? this.label || iconOnlyName\n : undefined;\n\n return html`\n <button\n part=\"button\"\n style=${styleMap(this._styleVars)}\n type=${this.type}\n form=${ifDefined(this.form ?? undefined)}\n aria-label=${ifDefined(ariaLabel)}\n ?disabled=${this.disabled || this.loading}\n ?loading=${this.loading}\n @click=${this._handleClick}\n >\n ${when(\n this.iconOnly,\n () =>\n when(\n iconOnlyName,\n () => html`<sky-icon part=\"icon\" icon=\"${iconOnlyName}\"></sky-icon>`,\n ),\n () => html`\n ${when(this.iconL, () => html`<sky-icon part=\"icon\" icon=\"${this.iconL}\"></sky-icon>`)}\n <slot @slotchange=${this._onSlotChange}></slot>\n ${this._hasMeaningfulSlot ? nothing : this.label}\n ${when(this.iconR, () => html`<sky-icon part=\"icon\" icon=\"${this.iconR}\"></sky-icon>`)}\n `,\n )}\n ${when(\n this.loading,\n () => html`\n <div class=\"loading-overlay\" part=\"loading-overlay\">\n <div class=\"spinner\" part=\"spinner\"></div>\n </div>\n `,\n )}\n </button>\n `;\n }\n}\n"],"names":["SkyButton","LitElement","constructor","super","this","variant","color","type","form","size","radius","label","disabled","loading","iconL","iconR","iconOnly","colors","animation","preset","inGroup","_hasMeaningfulSlot","_styleVars","_presets","PresetController","isPaused","onChange","_styleDirty","_lastPresetRevision","_onSlotChange","e","slot","target","next","_slotHasMeaningfulContent","internals","attachInternals","slotEl","assignedNodes","flatten","some","n","nodeType","Node","ELEMENT_NODE","textContent","trim","length","_toSquarePadding","padding","py","parseFloat","split","Number","isFinite","_resolveSize","input","presets","xs","fontSize","gap","icon","spinner","sm","md","lg","xl","m","String","match","unit","fsNum","fs","to","Math","round","clamp","min","max","px","_isThemeBorderShorthand","border","test","_borderColorFromShorthand","update","changedProperties","_rebuildStyleVars","presetChanged","revision","p","has","Object","keys","baseColor","resolveColor","textColor","ON_COLOR_FALLBACK_LIGHT","variantDefaults","solid","bg","shadow","hoverBg","hoverColor","hoverShadow","faded","hoverBorder","bordered","hoverShade","transparent","fadeMix","flat","ghost","skyBorderPrimaryShorthand","relief","darkShade","gradient","createGradient","link","effVariant","effColor","effSize","effRadius","effAnimation","current","v","assign","tuneSurfaceVariantForDefaultColor","semanticKey","resolveSemanticSurfaceKey","soft","semanticSoftSurfaceTokens","animationMode","chosen","hover","active","presetToTransform","hoverTransform","activeTransform","s","basePadding","baseGap","borderWidth","includes","parseInt","hoverBorderWidth","adjustedPadding","paddingParts","all","vertical","horizontal","adjustedVertical","top","right","bottom","left","iconPx","btnMinHeight","btnMinWidth","side","paddingValues","hoverBorderShorthand","usesThemeBorder","borderColor","borderColorHover","vars","resolveRadius","focusButton","renderRoot","querySelector","focus","clickButton","click","_createRipple","event","button","currentTarget","rect","getBoundingClientRect","ripple","document","createElement","offsetWidth","offsetHeight","x","clientX","y","clientY","style","width","height","getComputedStyle","backgroundColor","background","contrastOverlay","className","existing","querySelectorAll","remove","appendChild","addEventListener","formDisabledCallback","formOwner","formId","getElementById","closest","_handleClick","preventDefault","reset","requestSubmit","_iconOnlyName","render","iconOnlyName","ariaLabel","html","styleMap","ifDefined","when","nothing","dependencies","SkyIcon","formAssociated","styles","skyFocusRingHostStyles","css","unsafeCSS","cssOnFillEnhance","selector","fillVar","__decorateClass","property","reflect","prototype","Boolean","state","eventOptions","passive","customElement"],"mappings":"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"}
1
+ {"version":3,"file":"sky-button.js","sources":["../../src/sky-button/sky-button.ts"],"sourcesContent":["import { LitElement, html, css, nothing, unsafeCSS } from \"lit\";\r\nimport { customElement, property, state, eventOptions } from \"lit/decorators.js\";\r\nimport { when } from \"lit/directives/when.js\";\r\nimport { styleMap } from \"lit/directives/style-map.js\";\r\nimport {\r\n createGradient,\r\n darkShade,\r\n fadeMix,\r\n hoverShade,\r\n resolveColor,\r\n resolveSemanticSurfaceKey,\r\n semanticSoftSurfaceTokens,\r\n skyBorderPrimaryShorthand,\r\n tuneSurfaceVariantForDefaultColor,\r\n} from \"../helper/utils/color-resolver\";\r\nimport { cssOnFillEnhance, contrastOverlay, ON_COLOR_FALLBACK_LIGHT } from \"../helper/utils/contrast-color\";\r\nimport { resolveRadius } from \"../helper/utils/size-resolver\";\r\nimport { PresetController } from \"../helper/controllers/preset-controller\";\r\nimport { skyFocusRingHostStyles } from \"../helper/styles/focus-ring\";\r\nimport { ifDefined } from \"lit/directives/if-defined.js\";\r\nimport { SkyIcon } from \"../sky-icon/sky-icon.js\";\r\n\r\nexport type SkyButtonVariant =\r\n | \"solid\"\r\n | \"faded\"\r\n | \"bordered\"\r\n | \"transparent\"\r\n | \"flat\"\r\n | \"ghost\"\r\n | \"relief\"\r\n | \"gradient\"\r\n | \"shadow\"\r\n | \"link\";\r\nexport type SkyButtonType = \"button\" | \"submit\" | \"reset\";\r\nexport type SkyButtonAnimation =\r\n | \"auto\"\r\n | \"none\"\r\n | \"lift\"\r\n | \"push\"\r\n | \"scale\"\r\n | \"rotate\"\r\n | \"custom\";\r\n\r\n/**\r\n * @element sky-button\r\n *\r\n * @summary Styled button supporting variants, icons, loading state, ripple feedback, and form-associated behavior.\r\n *\r\n * @status stable\r\n * @since 1.0.0\r\n *\r\n * @documentation https://sky-ui.com/components/button\r\n * @dependency sky-icon\r\n *\r\n * @slot - Default slot for the button label (replaces `label` property if used).\r\n *\r\n * @csspart button - The native `<button>` element.\r\n * @csspart icon - The optional left/right icons.\r\n * @csspart loading-overlay - Overlay displayed when loading.\r\n * @csspart spinner - Spinner displayed when loading.\r\n *\r\n * @property {SkyButtonVariant} variant - Visual variant of the button. Use `\"link\"` for text-only control with underline on hover. Default: `\"solid\"`.\r\n * @property {string} color - Base color token or custom CSS color. Default: `\"primary\"`.\r\n * @property {SkyButtonType} type - Button type attribute. Default: `\"button\"`.\r\n * @property {string} form - Associated form ID for custom submit handling.\r\n * @property {string} size - Preset size token (`xs…xl`) or CSS size (e.g., `\"15px\"`, `\"1rem\"`). Default: `\"md\"`.\r\n * @property {string} radius - Preset radius token (`none…full`) or CSS radius (e.g., `\"12px\"`). Default: `\"md\"`.\r\n * @property {string} label - Text label for the button. Ignored if default slot is used. Default: `\"Button\"`.\r\n * @property {boolean} disabled - Whether the button is disabled. Default: `false`.\r\n * @property {boolean} loading - Shows a loading overlay when true. Default: `false`.\r\n * @property {string} iconL - Optional left-side icon (Iconify name). Default: `\"\"`.\r\n * @property {string} iconR - Optional right-side icon (Iconify name). Default: `\"\"`.\r\n * @property {boolean} iconOnly - Square padding for icon-only buttons; hides label text. Default: `false`.\r\n * @property {string} colors - Comma-separated color stops for gradient variant. Default: `\"\"`.\r\n * @property {SkyButtonAnimation} animation - Transform animation style. Default: `\"auto\"`.\r\n * @property {string} preset - Named prop preset from nearest `sky-config-provider`. Default: `\"\"`.\r\n * @method focusButton Focuses the internal native button.\r\n * @method clickButton Triggers a click on the internal native button when enabled.\r\n *\r\n * @example\r\n * ```html\r\n * <sky-button variant=\"gradient\" colors=\"linear@90deg: primary, secondary\" iconl=\"ion:add\" label=\"Create\"></sky-button>\r\n * <sky-button preset=\"cancel\" label=\"Cancel\"></sky-button>\r\n * ```\r\n * ```vue\r\n * <template>\r\n * <sky-button variant=\"gradient\" colors=\"linear@90deg: primary, secondary\" iconl=\"ion:add\" label=\"Create\"></sky-button>\r\n * <sky-button preset=\"cancel\" label=\"Cancel\"></sky-button>\r\n * </template>\r\n * ```\r\n * ```jsx\r\n * export default function Demo() {\r\n * return (\r\n * <>\r\n * <sky-button variant=\"gradient\" colors=\"linear@90deg: primary, secondary\" iconl=\"ion:add\" label=\"Create\"></sky-button>\r\n * <sky-button preset=\"cancel\" label=\"Cancel\"></sky-button>\r\n * </>\r\n * );\r\n * }\r\n * ```\r\n */\r\n@customElement(\"sky-button\")\r\nexport class SkyButton extends LitElement {\r\n\r\n static dependencies: Record<string, CustomElementConstructor> = {\r\n \"sky-icon\": SkyIcon,\r\n };\r\n\r\n static formAssociated = true;\r\n\r\n private internals: ElementInternals;\r\n /** Visual variant of the button. */\r\n @property({ type: String, reflect: true }) variant: SkyButtonVariant = \"solid\";\r\n\r\n /** Accepts preset tokens OR any valid CSS color (e.g., #0af, rgb(), var(--x)). */\r\n @property({ type: String }) color: string = \"primary\";\r\n\r\n /** Button type attribute. */\r\n @property({ type: String }) type: SkyButtonType = \"button\";\r\n\r\n /** Associated form ID for custom form handling. */\r\n @property({ type: String }) form = \"\";\r\n\r\n /** Preset tokens (`xs…xl`) OR CSS size like `\"15px\"`. */\r\n @property({ type: String }) size: string = \"md\";\r\n\r\n /** Preset tokens (`none…full`) OR any CSS border radius. */\r\n @property({ type: String }) radius: string = \"md\";\r\n\r\n /** Text label for the button. */\r\n @property({ type: String }) label = \"Button\";\r\n\r\n /** Disables the button. */\r\n @property({ type: Boolean, reflect: true }) disabled = false;\r\n\r\n /** Shows a loading spinner overlay. */\r\n @property({ type: Boolean, reflect: true }) loading = false;\r\n\r\n /** Left-side icon (Iconify icon name). */\r\n @property({ type: String }) iconL = \"\";\r\n\r\n /** Right-side icon (Iconify icon name). */\r\n @property({ type: String }) iconR = \"\";\r\n\r\n /** Square padding and compact layout when the button shows only an icon. */\r\n @property({ type: Boolean, reflect: true }) iconOnly = false;\r\n\r\n /** Colors for gradient variant. */\r\n @property({ type: String }) colors: string = \"\";\r\n\r\n /** Animation style for hover/active transforms. */\r\n @property({ type: String, reflect: true }) animation: SkyButtonAnimation = \"auto\";\r\n\r\n /** Named prop preset from nearest `sky-config-provider`. */\r\n @property({ type: String, reflect: true }) preset = \"\";\r\n\r\n /** @internal Set by `sky-button-group` to flatten grouped button visuals. */\r\n @property({ type: Boolean, reflect: true }) inGroup = false;\r\n\r\n @state() private _hasMeaningfulSlot = false;\r\n\r\n /** Inline CSS variable cache. */\r\n private _styleVars: Record<string, string> = {};\r\n\r\n private _presets = new PresetController(this, {\r\n isPaused: () => this.inGroup,\r\n onChange: () => {\r\n this._styleDirty = true;\r\n },\r\n });\r\n\r\n private _lastPresetRevision = -1;\r\n /** Set when presets change so `update()` rebuilds CSS vars after hostUpdate. */\r\n private _styleDirty = true;\r\n\r\n static styles = [\r\n skyFocusRingHostStyles,\r\n css`\r\n :host {\r\n display: inline-block;\r\n }\r\n\r\n :host([disabled]) {\r\n cursor: not-allowed;\r\n pointer-events: none;\r\n }\r\n\r\n :host([in-group]) {\r\n align-self: stretch;\r\n }\r\n\r\n :host([iconOnly]) button {\r\n width: auto;\r\n min-width: var(--btn-min-width, auto);\r\n aspect-ratio: 1;\r\n gap: 0;\r\n }\r\n\r\n :host([variant=\"link\"]) button {\r\n width: auto;\r\n border-radius: 0;\r\n text-decoration: none;\r\n background-color: transparent;\r\n background-image: linear-gradient(currentColor, currentColor);\r\n background-position: 0 100%;\r\n background-repeat: no-repeat;\r\n background-size: 0% 1px;\r\n transition:\r\n background-size var(--sky-duration-normal, 200ms) var(--sky-ease-default, ease),\r\n color var(--sky-duration-fast, 120ms) var(--sky-ease-default, ease),\r\n box-shadow var(--sky-duration-fast, 120ms) var(--sky-ease-default, ease),\r\n border-color var(--sky-duration-fast, 120ms) var(--sky-ease-default, ease),\r\n transform var(--sky-duration-fast, 120ms) var(--sky-ease-default, ease);\r\n }\r\n :host([variant=\"link\"]) button:hover:not(:disabled),\r\n :host([variant=\"link\"]) button:focus-visible:not(:disabled) {\r\n background-color: transparent;\r\n background-image: linear-gradient(currentColor, currentColor);\r\n background-position: 0 100%;\r\n background-repeat: no-repeat;\r\n background-size: 100% 1px;\r\n }\r\n\r\n button {\r\n position: relative;\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n overflow: hidden;\r\n border-radius: var(--btn-radius, var(--sky-radius-primary));\r\n font: inherit;\r\n cursor: pointer;\r\n box-sizing: border-box;\r\n outline: none;\r\n border: var(\r\n --btn-border,\r\n var(--btn-border-width, 0) solid var(--btn-border-color, transparent)\r\n );\r\n background-color: var(--btn-bg-color, transparent);\r\n background-image: none;\r\n color: var(--btn-color);\r\n box-shadow: var(--btn-shadow, none);\r\n transform: var(--btn-transform, none);\r\n gap: var(--btn-gap, var(--sky-space-1, 4px));\r\n padding: var(--btn-padding, var(--sky-space-2, 8px) var(--sky-space-3, 14px));\r\n font-size: var(--btn-font-size, var(--sky-font-size-md, 1rem));\r\n font-family: var(--sky-font);\r\n white-space: nowrap;\r\n text-align: center;\r\n text-decoration: var(--btn-text-decoration, none);\r\n width: 100%;\r\n height: auto;\r\n min-height: var(--btn-min-height, auto);\r\n backdrop-filter: none;\r\n -webkit-backdrop-filter: none;\r\n transition:\r\n background-color var(--sky-duration-fast, 120ms) var(--sky-ease-default, ease),\r\n border-color var(--sky-duration-fast, 120ms) var(--sky-ease-default, ease),\r\n color var(--sky-duration-fast, 120ms) var(--sky-ease-default, ease),\r\n box-shadow var(--sky-duration-fast, 120ms) var(--sky-ease-default, ease),\r\n transform var(--sky-duration-fast, 120ms) var(--sky-ease-out, ease),\r\n opacity var(--sky-duration-fast, 120ms) var(--sky-ease-default, ease);\r\n\r\n /* Ensure button doesn't shrink */\r\n flex-shrink: 0;\r\n }\r\n\r\n :host([variant=\"gradient\"]) button {\r\n background: var(--btn-bg);\r\n background-color: transparent;\r\n }\r\n\r\n button:hover:not(:disabled),\r\n button:focus-visible:not(:disabled) {\r\n background-color: var(--btn-bg-color-hover, var(--btn-bg-color, transparent));\r\n color: var(--btn-color-hover, var(--btn-color));\r\n box-shadow: var(--btn-shadow-hover, var(--btn-shadow));\r\n border: var(\r\n --btn-border-hover,\r\n var(\r\n --btn-border,\r\n var(--btn-border-width, 0) solid\r\n var(--btn-border-color-hover, var(--btn-border-color, transparent))\r\n )\r\n );\r\n text-decoration: var(\r\n --btn-text-decoration-hover,\r\n var(--btn-text-decoration, none)\r\n );\r\n transform: var(--btn-transform-hover, var(--btn-transform, none));\r\n height: auto;\r\n min-height: var(--btn-min-height, auto);\r\n }\r\n\r\n :host([variant=\"gradient\"]) button:hover:not(:disabled),\r\n :host([variant=\"gradient\"]) button:focus-visible:not(:disabled) {\r\n background: var(--btn-bg-hover, var(--btn-bg));\r\n }\r\n button:focus-visible:not(:disabled) {\r\n box-shadow:\r\n var(--sky-focus-ring),\r\n var(--btn-shadow-hover, var(--btn-shadow, none));\r\n }\r\n button:active:not(:disabled) {\r\n transform: var(\r\n --btn-transform-active,\r\n var(--btn-transform-hover, var(--btn-transform, none))\r\n );\r\n }\r\n button:disabled {\r\n opacity: var(--sky-opacity-disabled, 0.5);\r\n cursor: not-allowed;\r\n pointer-events: none;\r\n }\r\n\r\n @media (prefers-reduced-motion: reduce) {\r\n button,\r\n :host([variant=\"link\"]) button {\r\n transition: none;\r\n }\r\n\r\n button:active:not(:disabled) {\r\n transform: none;\r\n }\r\n\r\n .ripple {\r\n animation: none;\r\n }\r\n\r\n .spinner {\r\n animation: none;\r\n }\r\n }\r\n\r\n .ripple {\r\n position: absolute;\r\n border-radius: 50%;\r\n background: rgba(255, 255, 255, 0.5);\r\n transform: scale(0);\r\n animation: ripple-animation 0.6s linear;\r\n pointer-events: none;\r\n }\r\n @keyframes ripple-animation {\r\n to {\r\n transform: scale(4);\r\n opacity: 0;\r\n }\r\n }\r\n sky-icon {\r\n display: inline-block;\r\n width: 1em;\r\n height: 1em;\r\n font-size: var(--icon-size, 18px);\r\n backdrop-filter: none;\r\n -webkit-backdrop-filter: none;\r\n }\r\n .loading-overlay {\r\n position: absolute;\r\n inset: 0;\r\n display: flex;\r\n justify-content: center;\r\n align-items: center;\r\n background: var(--sky-overlay-secondary);\r\n visibility: hidden;\r\n backdrop-filter: none;\r\n -webkit-backdrop-filter: none;\r\n }\r\n button[loading] .loading-overlay {\r\n visibility: visible;\r\n }\r\n .spinner {\r\n width: var(--spinner-size, 18px);\r\n height: var(--spinner-size, 18px);\r\n border: 2px solid currentColor;\r\n border-top-color: transparent;\r\n border-radius: 50%;\r\n animation: spin 1s linear infinite;\r\n }\r\n @keyframes spin {\r\n to {\r\n transform: rotate(360deg);\r\n }\r\n }\r\n\r\n /* Solid fills: enhance FG with contrast-color when supported (fallback remains --btn-color).\r\n Glass shadow variant is excluded. Ghost is enhanced only on hover (fill becomes solid). */\r\n ${unsafeCSS(\r\n cssOnFillEnhance([\r\n {\r\n selector:\r\n ':host(:is([variant=\"solid\"], [variant=\"relief\"], [variant=\"gradient\"]):not([data-text-explicit])) button',\r\n fillVar: \"--btn-bg-color\",\r\n },\r\n {\r\n selector:\r\n ':host(:is([variant=\"solid\"], [variant=\"relief\"], [variant=\"gradient\"]):not([data-text-explicit])) button sky-icon',\r\n fillVar: \"--btn-bg-color\",\r\n },\r\n {\r\n selector:\r\n ':host(:is([variant=\"solid\"], [variant=\"relief\"], [variant=\"gradient\"]):not([data-text-explicit])) button:hover:not(:disabled), :host(:is([variant=\"solid\"], [variant=\"relief\"], [variant=\"gradient\"]):not([data-text-explicit])) button:focus-visible:not(:disabled)',\r\n fillVar: \"var(--btn-bg-color-hover, var(--btn-bg-color))\",\r\n },\r\n {\r\n selector:\r\n ':host(:is([variant=\"solid\"], [variant=\"relief\"], [variant=\"gradient\"]):not([data-text-explicit])) button:hover:not(:disabled) sky-icon, :host(:is([variant=\"solid\"], [variant=\"relief\"], [variant=\"gradient\"]):not([data-text-explicit])) button:focus-visible:not(:disabled) sky-icon',\r\n fillVar: \"var(--btn-bg-color-hover, var(--btn-bg-color))\",\r\n },\r\n {\r\n selector:\r\n ':host([variant=\"ghost\"]:not([data-text-explicit])) button:hover:not(:disabled), :host([variant=\"ghost\"]:not([data-text-explicit])) button:focus-visible:not(:disabled)',\r\n fillVar: \"var(--btn-bg-color-hover, var(--btn-bg-color))\",\r\n },\r\n {\r\n selector:\r\n ':host([variant=\"ghost\"]:not([data-text-explicit])) button:hover:not(:disabled) sky-icon, :host([variant=\"ghost\"]:not([data-text-explicit])) button:focus-visible:not(:disabled) sky-icon',\r\n fillVar: \"var(--btn-bg-color-hover, var(--btn-bg-color))\",\r\n },\r\n ]),\r\n )}\r\n `,\r\n ];\r\n\r\n constructor() {\r\n super();\r\n // @ts-ignore\r\n this.internals = this.attachInternals();\r\n }\r\n\r\n private _slotHasMeaningfulContent(slotEl: HTMLSlotElement): boolean {\r\n const nodes = slotEl.assignedNodes({ flatten: true });\r\n return nodes.some((n) =>\r\n n.nodeType === Node.ELEMENT_NODE\r\n ? true\r\n : (n.textContent ?? \"\").trim().length > 0\r\n );\r\n }\r\n\r\n // Slot change handler (not a lifecycle hook).\r\n private _onSlotChange = (e: Event) => {\r\n const slot = e.target as HTMLSlotElement;\r\n const next = this._slotHasMeaningfulContent(slot);\r\n // Only set state if it actually changed to avoid extra updates\r\n if (next !== this._hasMeaningfulSlot) this._hasMeaningfulSlot = next;\r\n };\r\n\r\n /** Uses vertical padding for equal sides (icon-only square control). */\r\n private _toSquarePadding(padding: string): string {\r\n const py = parseFloat(padding.trim().split(/\\s+/)[0]);\r\n const n = Number.isFinite(py) ? py : 8;\r\n return `${n}px`;\r\n }\r\n\r\n private _resolveSize(input: string): {\r\n padding: string;\r\n fontSize: string;\r\n gap: string;\r\n icon: string;\r\n spinner: string;\r\n } {\r\n const presets: Record<\r\n string,\r\n {\r\n padding: string;\r\n fontSize: string;\r\n gap: string;\r\n icon: string;\r\n spinner: string;\r\n }\r\n > = {\r\n xs: {\r\n padding: \"3px 7px\",\r\n fontSize: \"12px\",\r\n gap: \"3px\",\r\n icon: \"14px\",\r\n spinner: \"14px\",\r\n },\r\n sm: {\r\n padding: \"5px 9px\",\r\n fontSize: \"14px\",\r\n gap: \"4px\",\r\n icon: \"16px\",\r\n spinner: \"16px\",\r\n },\r\n md: {\r\n padding: \"8px 14px\",\r\n fontSize: \"16px\",\r\n gap: \"5px\",\r\n icon: \"18px\",\r\n spinner: \"18px\",\r\n },\r\n lg: {\r\n padding: \"10px 18px\",\r\n fontSize: \"18px\",\r\n gap: \"6px\",\r\n icon: \"20px\",\r\n spinner: \"20px\",\r\n },\r\n xl: {\r\n padding: \"14px 24px\",\r\n fontSize: \"20px\",\r\n gap: \"8px\",\r\n icon: \"24px\",\r\n spinner: \"24px\",\r\n },\r\n };\r\n if (presets[input]) return presets[input];\r\n\r\n const m = String(input)\r\n .trim()\r\n .match(/^([\\d.]+)(px|rem|em)?$/i);\r\n const unit = m?.[2] || \"px\";\r\n const fsNum = m ? parseFloat(m[1]) : 16;\r\n const fs = `${fsNum}${unit}`;\r\n\r\n const to = (n: number) => `${Math.round(n * 100) / 100}${unit}`;\r\n const clamp = (n: number, min: number, max: number) =>\r\n Math.max(min, Math.min(max, n));\r\n\r\n const py = clamp(fsNum * 0.55, 4, 18);\r\n const px = clamp(fsNum * 0.9, 8, 28);\r\n const gap = clamp(fsNum * 0.3, 3, 10);\r\n const icon = clamp(fsNum * 1.125, 12, 28);\r\n const spinner = icon;\r\n\r\n return {\r\n padding: `${to(py)} ${to(px)}`,\r\n fontSize: fs,\r\n gap: to(gap),\r\n icon: to(icon),\r\n spinner: to(spinner),\r\n };\r\n }\r\n\r\n /** Theme tokens like `var(--sky-border-primary)` are full border shorthands, not colors. */\r\n private _isThemeBorderShorthand(border: string | undefined): boolean {\r\n if (!border || border === \"none\") return false;\r\n return /^var\\(--sky-border-/.test(border.trim());\r\n }\r\n\r\n /** Extracts the color token from a `Npx solid …` border shorthand. */\r\n private _borderColorFromShorthand(border: string | undefined): string {\r\n if (!border || border === \"none\" || this._isThemeBorderShorthand(border)) {\r\n return \"transparent\";\r\n }\r\n const match = border.match(/solid\\s+(.+)$/);\r\n return match?.[1]?.trim() ?? \"transparent\";\r\n }\r\n\r\n /**\r\n * Lit order: `willUpdate` → controllers `hostUpdate` (presets) → `update`/render.\r\n * Style vars must be built in `update()` so they see preset-applied props.\r\n * Building in `willUpdate` left render with `{}` after PresetController cleared/wrote props.\r\n */\r\n protected override update(changedProperties: Map<string, unknown>): void {\r\n this._rebuildStyleVars(changedProperties);\r\n super.update(changedProperties);\r\n }\r\n\r\n private _rebuildStyleVars(changedProperties: Map<string, unknown>): void {\r\n const styleProps = [\r\n \"color\",\r\n \"variant\",\r\n \"size\",\r\n \"radius\",\r\n \"animation\",\r\n \"preset\",\r\n \"inGroup\",\r\n \"disabled\",\r\n \"loading\",\r\n \"colors\",\r\n \"iconOnly\",\r\n ];\r\n const presetChanged = this._presets.revision !== this._lastPresetRevision;\r\n const needsStyleUpdate =\r\n this._styleDirty ||\r\n presetChanged ||\r\n styleProps.some((p) => changedProperties.has(p));\r\n if (!needsStyleUpdate && Object.keys(this._styleVars).length > 0) {\r\n return;\r\n }\r\n this._lastPresetRevision = this._presets.revision;\r\n this._styleDirty = false;\r\n\r\n const baseColor = resolveColor(this.color);\r\n const textColor = ON_COLOR_FALLBACK_LIGHT;\r\n\r\n const variantDefaults = {\r\n solid: {\r\n bg: baseColor,\r\n color: textColor,\r\n border: \"none\",\r\n shadow: \"none\",\r\n hoverBg: baseColor,\r\n hoverColor: textColor,\r\n hoverShadow: \"var(--sky-box-shadow-hover)\",\r\n },\r\n faded: {\r\n bg: \"var(--sky-hover-tertiary)\",\r\n color: baseColor,\r\n border: \"1px solid var(--sky-text-tertiary)\",\r\n shadow: \"none\",\r\n hoverBg: \"var(--sky-hover-secondary)\",\r\n hoverColor: baseColor,\r\n hoverShadow: \"none\",\r\n hoverBorder: \"1px solid var(--sky-text-secondary)\",\r\n },\r\n bordered: {\r\n bg: \"transparent\",\r\n color: baseColor,\r\n border: `2px solid ${baseColor}`,\r\n shadow: \"none\",\r\n hoverBg: \"transparent\",\r\n hoverColor: baseColor,\r\n hoverShadow: \"none\",\r\n hoverBorder: `2px solid ${hoverShade(baseColor, 25)}`,\r\n },\r\n transparent: {\r\n bg: \"transparent\",\r\n color: baseColor,\r\n border: \"none\",\r\n shadow: \"none\",\r\n hoverBg: fadeMix(baseColor, 15),\r\n hoverColor: baseColor,\r\n hoverShadow: \"none\",\r\n },\r\n flat: {\r\n bg: fadeMix(baseColor, 20),\r\n color: hoverShade(baseColor, 30),\r\n border: \"none\",\r\n shadow: \"none\",\r\n hoverBg: fadeMix(baseColor, 25),\r\n hoverColor: hoverShade(baseColor, 35),\r\n hoverShadow: \"none\",\r\n },\r\n ghost: {\r\n bg: \"transparent\",\r\n color: baseColor,\r\n border: `2px solid ${baseColor}`,\r\n shadow: \"none\",\r\n hoverBg: baseColor,\r\n hoverColor: textColor,\r\n hoverShadow: \"none\",\r\n },\r\n shadow: {\r\n bg: \"var(--sky-glass-primary)\",\r\n color: \"var(--sky-text-primary)\",\r\n border: skyBorderPrimaryShorthand(),\r\n shadow: \"none\",\r\n hoverBg: \"var(--sky-glass-primary)\",\r\n hoverColor: baseColor,\r\n hoverShadow: \"var(--sky-box-shadow-hover)\",\r\n hoverBorder: skyBorderPrimaryShorthand(),\r\n },\r\n relief: {\r\n bg: baseColor,\r\n color: textColor,\r\n border: \"none\",\r\n shadow: `\r\n inset 0 1px 0 rgba(255,255,255,0.4),\r\n 0 3px 0 ${darkShade(baseColor, 40)},\r\n 0 4px 6px -1px ${fadeMix(baseColor, 40)}\r\n `,\r\n hoverBg: baseColor,\r\n hoverColor: textColor,\r\n hoverShadow: \"none\",\r\n },\r\n gradient: {\r\n bg: createGradient(this.colors, baseColor),\r\n color: textColor,\r\n border: \"none\",\r\n shadow: \"none\",\r\n hoverBg: createGradient(this.colors, baseColor),\r\n hoverColor: textColor,\r\n hoverShadow: \"none\",\r\n },\r\n link: {\r\n bg: \"transparent\",\r\n color: baseColor,\r\n border: \"none\",\r\n shadow: \"none\",\r\n hoverBg: \"transparent\",\r\n hoverColor: baseColor,\r\n hoverShadow: \"none\",\r\n },\r\n } as const;\r\n\r\n const transformsAuto = {\r\n solid: { hover: \"translateY(-3px)\", active: \"translateY(-3px)\" },\r\n faded: {},\r\n bordered: {},\r\n transparent: {},\r\n flat: {},\r\n ghost: {},\r\n shadow: { hover: \"translateY(-3px)\", active: \"translateY(-3px)\" },\r\n gradient: {},\r\n relief: { hover: \"translateY(2px)\", active: \"translateY(2px)\" },\r\n link: {},\r\n } as const;\r\n\r\n const presetToTransform = (p: typeof this.animation) => {\r\n switch (p) {\r\n case \"none\":\r\n return { hover: \"none\", active: \"none\" };\r\n case \"lift\":\r\n return { hover: \"translateY(-2px)\", active: \"translateY(-1px)\" };\r\n case \"push\":\r\n return { hover: \"translateY(2px)\", active: \"translateY(2px)\" };\r\n case \"scale\":\r\n return { hover: \"scale(1.05)\", active: \"scale(1.02)\" };\r\n case \"rotate\":\r\n return { hover: \"rotate(3deg)\", active: \"rotate(2deg)\" };\r\n case \"custom\":\r\n return {\r\n hover: \"var(--btn-hover-transform, none)\",\r\n active:\r\n \"var(--btn-active-transform, var(--btn-hover-transform, none))\",\r\n };\r\n default:\r\n return {};\r\n }\r\n };\r\n\r\n const effVariant = this.variant;\r\n const effColor = this.color;\r\n const effSize = this.size;\r\n const effRadius = this.radius;\r\n const effAnimation = this.animation;\r\n\r\n const current = (\r\n effVariant in variantDefaults ? effVariant : \"solid\"\r\n ) as keyof typeof variantDefaults;\r\n let v = { ...variantDefaults[current] };\r\n Object.assign(\r\n v,\r\n tuneSurfaceVariantForDefaultColor(effColor, current, variantDefaults[current]),\r\n );\r\n\r\n const semanticKey = resolveSemanticSurfaceKey(effColor);\r\n if (semanticKey && (current === \"flat\" || current === \"faded\")) {\r\n const soft = semanticSoftSurfaceTokens(semanticKey, {\r\n bordered: current === \"faded\",\r\n });\r\n Object.assign(v, {\r\n bg: soft.bg,\r\n color: soft.color,\r\n border: current === \"faded\" ? soft.border : \"none\",\r\n hoverBg: \"var(--sky-hover-primary)\",\r\n hoverColor: soft.color,\r\n hoverShadow: \"none\",\r\n ...(current === \"faded\" ? { hoverBorder: soft.border } : {}),\r\n });\r\n }\r\n\r\n const animationMode = this.inGroup ? \"none\" : effAnimation;\r\n const chosen =\r\n animationMode === \"auto\"\r\n ? transformsAuto[current]\r\n : presetToTransform(animationMode);\r\n const hoverTransform = (chosen as any).hover ?? \"none\";\r\n const activeTransform = (chosen as any).active ?? hoverTransform ?? \"none\";\r\n\r\n const s = this._resolveSize(effSize);\r\n const basePadding = this.iconOnly ? this._toSquarePadding(s.padding) : s.padding;\r\n const baseGap = this.iconOnly ? \"0\" : s.gap;\r\n\r\n let borderWidth = 0;\r\n const hasBorder2 = effVariant === \"bordered\" || effVariant === \"ghost\";\r\n const hasBorder1 = effVariant === \"faded\" || effVariant === \"shadow\";\r\n\r\n if (hasBorder2) {\r\n borderWidth = 2;\r\n } else if (hasBorder1) {\r\n borderWidth = 1;\r\n } else if (v.border && v.border.includes(\"px\")) {\r\n const match = v.border.match(/(\\d+)px/);\r\n borderWidth = match ? parseInt(match[1]) : 0;\r\n }\r\n\r\n let hoverBorderWidth = borderWidth;\r\n if ((v as any).hoverBorder && (v as any).hoverBorder.includes(\"px\")) {\r\n const match = (v as any).hoverBorder.match(/(\\d+)px/);\r\n hoverBorderWidth = match ? parseInt(match[1]) : borderWidth;\r\n }\r\n\r\n // Reduce padding on bordered variants to preserve outer height.\r\n let adjustedPadding = effVariant === \"link\" ? \"0\" : basePadding;\r\n if (borderWidth > 0) {\r\n // Parse the original padding\r\n const paddingParts = basePadding.split(\" \");\r\n if (paddingParts.length === 1) {\r\n const all = parseFloat(paddingParts[0]);\r\n const adjusted = Math.max(all - borderWidth, 2);\r\n adjustedPadding = `${adjusted}px`;\r\n } else if (paddingParts.length === 2) {\r\n // Format: \"vertical horizontal\"\r\n const vertical = parseFloat(paddingParts[0]);\r\n const horizontal = parseFloat(paddingParts[1]);\r\n\r\n // Reduce vertical padding by border width to maintain same content height\r\n const adjustedVertical = Math.max(vertical - borderWidth, 2);\r\n adjustedPadding = this.iconOnly\r\n ? `${adjustedVertical}px`\r\n : `${adjustedVertical}px ${horizontal}px`;\r\n } else if (paddingParts.length === 4) {\r\n // Format: \"top right bottom left\"\r\n const top = parseFloat(paddingParts[0]);\r\n const right = parseFloat(paddingParts[1]);\r\n const bottom = parseFloat(paddingParts[2]);\r\n const left = parseFloat(paddingParts[3]);\r\n\r\n // Reduce top/bottom padding by border width\r\n const adjustedTop = Math.max(top - borderWidth, 2);\r\n const adjustedBottom = Math.max(bottom - borderWidth, 2);\r\n adjustedPadding = `${adjustedTop}px ${right}px ${adjustedBottom}px ${left}px`;\r\n }\r\n }\r\n\r\n const fontSize = parseFloat(s.fontSize);\r\n const iconPx = parseFloat(s.icon);\r\n let btnMinHeight: string;\r\n let btnMinWidth: string | undefined;\r\n if (effVariant === \"link\") {\r\n btnMinHeight = \"auto\";\r\n } else if (this.iconOnly) {\r\n const pad = parseFloat(adjustedPadding) || 0;\r\n const side = pad * 2 + iconPx + borderWidth * 2;\r\n btnMinHeight = `${side}px`;\r\n btnMinWidth = `${side}px`;\r\n } else {\r\n const paddingValues = adjustedPadding.split(\" \");\r\n const verticalPadding =\r\n paddingValues.length >= 2\r\n ? parseFloat(paddingValues[0]) +\r\n parseFloat(paddingValues[2] || paddingValues[0])\r\n : parseFloat(paddingValues[0]) * 2 || 16;\r\n const baseHeight = verticalPadding + fontSize + 4 + borderWidth * 2;\r\n btnMinHeight = `${baseHeight}px`;\r\n }\r\n\r\n const hoverBorderShorthand = (v as { hoverBorder?: string }).hoverBorder;\r\n const usesThemeBorder =\r\n this._isThemeBorderShorthand(v.border) ||\r\n this._isThemeBorderShorthand(hoverBorderShorthand);\r\n const borderColor = this._borderColorFromShorthand(v.border);\r\n const borderColorHover = this._borderColorFromShorthand(\r\n hoverBorderShorthand ?? v.border,\r\n );\r\n\r\n const vars: Record<string, string> = {\r\n \"--btn-color\": v.color,\r\n \"--btn-shadow\": v.shadow,\r\n \"--btn-radius\":\r\n effVariant === \"link\" ? \"0\" : resolveRadius(effRadius),\r\n \"--btn-color-hover\": v.hoverColor,\r\n \"--btn-shadow-hover\": v.hoverShadow,\r\n \"--btn-transform\": \"none\",\r\n \"--btn-transform-hover\": hoverTransform,\r\n \"--btn-transform-active\": activeTransform,\r\n \"--btn-padding\": adjustedPadding, // Use adjusted padding!\r\n \"--btn-font-size\": s.fontSize,\r\n \"--btn-gap\": baseGap,\r\n \"--icon-size\": s.icon,\r\n \"--spinner-size\": s.spinner,\r\n\r\n // Set min-height to maintain consistent visual height\r\n \"--btn-min-height\": btnMinHeight,\r\n ...(btnMinWidth ? { \"--btn-min-width\": btnMinWidth } : {}),\r\n\r\n // Keep border width variables\r\n \"--btn-border-width\": `${borderWidth}px`,\r\n \"--btn-border-width-hover\": `${hoverBorderWidth}px`,\r\n\r\n // Focus ring follows `color` (not global active-primary).\r\n \"--sky-focus-ring-color\": baseColor,\r\n };\r\n\r\n if (usesThemeBorder) {\r\n vars[\"--btn-border\"] = v.border;\r\n vars[\"--btn-border-hover\"] = hoverBorderShorthand ?? v.border;\r\n } else {\r\n vars[\"--btn-border-color\"] = borderColor;\r\n vars[\"--btn-border-color-hover\"] = borderColorHover;\r\n }\r\n\r\n if (effVariant === \"gradient\") {\r\n vars[\"--btn-bg\"] = v.bg;\r\n vars[\"--btn-bg-hover\"] = v.hoverBg;\r\n // Opaque stop for contrast-color() — gradient paint still uses --btn-bg.\r\n vars[\"--btn-bg-color\"] = baseColor;\r\n vars[\"--btn-bg-color-hover\"] = baseColor;\r\n } else {\r\n vars[\"--btn-bg-color\"] = v.bg;\r\n vars[\"--btn-bg-color-hover\"] = v.hoverBg;\r\n }\r\n\r\n if (this.inGroup) {\r\n // In grouped mode, do not apply sky-button's own hover skin.\r\n // The container group controls visual interaction consistency.\r\n if (effVariant === \"gradient\") {\r\n // One gradient is painted on sky-button-group's `.group`; segments stay clear\r\n // (same idea as `::slotted(button)` transparent fills for native buttons).\r\n vars[\"--btn-bg\"] = \"transparent\";\r\n vars[\"--btn-bg-hover\"] = \"color-mix(in srgb, white 8%, transparent)\";\r\n } else {\r\n vars[\"--btn-bg-color-hover\"] = vars[\"--btn-bg-color\"] ?? \"transparent\";\r\n }\r\n vars[\"--btn-color-hover\"] = vars[\"--btn-color\"];\r\n if (usesThemeBorder) {\r\n vars[\"--btn-border-hover\"] = vars[\"--btn-border\"] ?? v.border;\r\n } else {\r\n vars[\"--btn-border-color-hover\"] = vars[\"--btn-border-color\"] ?? borderColor;\r\n }\r\n vars[\"--btn-shadow-hover\"] = \"none\";\r\n if (effVariant === \"relief\") {\r\n vars[\"--btn-transform-hover\"] = \"translateY(2px)\";\r\n vars[\"--btn-transform-active\"] = \"translateY(2px)\";\r\n } else {\r\n vars[\"--btn-transform-hover\"] = \"none\";\r\n vars[\"--btn-transform-active\"] = \"none\";\r\n }\r\n }\r\n\r\n this._styleVars = vars;\r\n }\r\n\r\n /**\r\n * Focuses the internal native button.\r\n *\r\n * @returns {void}\r\n */\r\n public focusButton(): void {\r\n this.renderRoot.querySelector<HTMLButtonElement>(\"button\")?.focus();\r\n }\r\n\r\n /**\r\n * Triggers a click on the internal native button when enabled.\r\n *\r\n * @returns {void}\r\n */\r\n public clickButton(): void {\r\n if (this.disabled || this.loading) return;\r\n this.renderRoot.querySelector<HTMLButtonElement>(\"button\")?.click();\r\n }\r\n\r\n private _createRipple(event: MouseEvent): void {\r\n const button = event.currentTarget as HTMLElement;\r\n const rect = button.getBoundingClientRect();\r\n const ripple = document.createElement(\"span\");\r\n\r\n const size = Math.max(button.offsetWidth, button.offsetHeight);\r\n const x = event.clientX - rect.left - size / 2;\r\n const y = event.clientY - rect.top - size / 2;\r\n\r\n ripple.style.width = ripple.style.height = `${size}px`;\r\n ripple.style.left = `${x}px`;\r\n ripple.style.top = `${y}px`;\r\n\r\n const bg = getComputedStyle(button).backgroundColor || \"\";\r\n ripple.style.background = contrastOverlay(bg);\r\n\r\n ripple.className = \"ripple\";\r\n const existing = button.querySelectorAll(\".ripple\");\r\n const maxRipples = 3;\r\n if (existing.length >= maxRipples && existing[0]) {\r\n existing[0].remove();\r\n }\r\n button.appendChild(ripple);\r\n ripple.addEventListener(\"animationend\", () => ripple.remove());\r\n }\r\n\r\n formDisabledCallback(disabled: boolean): void {\r\n this.disabled = disabled;\r\n }\r\n\r\n get formOwner(): HTMLFormElement | null {\r\n if (typeof document === \"undefined\") return null;\r\n const formId = typeof this.form === \"string\" ? this.form.trim() : \"\";\r\n return (\r\n this.internals.form ||\r\n (formId ? (document.getElementById(formId) as HTMLFormElement | null) : null) ||\r\n this.closest(\"form\")\r\n );\r\n }\r\n\r\n @eventOptions({ passive: false })\r\n private _handleClick(event: MouseEvent): void {\r\n if (this.disabled || this.loading) {\r\n event.preventDefault();\r\n return;\r\n }\r\n\r\n // If button type is \"button\", prevent any default navigation-like behavior\r\n if (this.type === \"button\") {\r\n event.preventDefault();\r\n }\r\n\r\n this._createRipple(event);\r\n\r\n const form = this.formOwner;\r\n if (this.type === \"submit\") {\r\n form?.requestSubmit();\r\n return;\r\n }\r\n if (this.type === \"reset\") {\r\n form?.reset();\r\n return;\r\n }\r\n }\r\n\r\n private _iconOnlyName(): string {\r\n return this.iconL || this.iconR;\r\n }\r\n\r\n override render() {\r\n const iconOnlyName = this._iconOnlyName();\r\n const ariaLabel =\r\n this.iconOnly && (this.label || iconOnlyName)\r\n ? this.label || iconOnlyName\r\n : undefined;\r\n\r\n return html`\r\n <button\r\n part=\"button\"\r\n style=${styleMap(this._styleVars)}\r\n type=${this.type}\r\n form=${ifDefined(this.form ?? undefined)}\r\n aria-label=${ifDefined(ariaLabel)}\r\n ?disabled=${this.disabled || this.loading}\r\n ?loading=${this.loading}\r\n @click=${this._handleClick}\r\n >\r\n ${when(\r\n this.iconOnly,\r\n () =>\r\n when(\r\n iconOnlyName,\r\n () => html`<sky-icon part=\"icon\" icon=\"${iconOnlyName}\"></sky-icon>`,\r\n ),\r\n () => html`\r\n ${when(this.iconL, () => html`<sky-icon part=\"icon\" icon=\"${this.iconL}\"></sky-icon>`)}\r\n <slot @slotchange=${this._onSlotChange}></slot>\r\n ${this._hasMeaningfulSlot ? nothing : this.label}\r\n ${when(this.iconR, () => html`<sky-icon part=\"icon\" icon=\"${this.iconR}\"></sky-icon>`)}\r\n `,\r\n )}\r\n ${when(\r\n this.loading,\r\n () => html`\r\n <div class=\"loading-overlay\" part=\"loading-overlay\">\r\n <div class=\"spinner\" part=\"spinner\"></div>\r\n </div>\r\n `,\r\n )}\r\n </button>\r\n `;\r\n }\r\n}\r\n"],"names":["SkyButton","LitElement","constructor","super","this","variant","color","type","form","size","radius","label","disabled","loading","iconL","iconR","iconOnly","colors","animation","preset","inGroup","_hasMeaningfulSlot","_styleVars","_presets","PresetController","isPaused","onChange","_styleDirty","_lastPresetRevision","_onSlotChange","e","slot","target","next","_slotHasMeaningfulContent","internals","attachInternals","slotEl","assignedNodes","flatten","some","n","nodeType","Node","ELEMENT_NODE","textContent","trim","length","_toSquarePadding","padding","py","parseFloat","split","Number","isFinite","_resolveSize","input","presets","xs","fontSize","gap","icon","spinner","sm","md","lg","xl","m","String","match","unit","fsNum","fs","to","Math","round","clamp","min","max","px","_isThemeBorderShorthand","border","test","_borderColorFromShorthand","update","changedProperties","_rebuildStyleVars","presetChanged","revision","p","has","Object","keys","baseColor","resolveColor","textColor","ON_COLOR_FALLBACK_LIGHT","variantDefaults","solid","bg","shadow","hoverBg","hoverColor","hoverShadow","faded","hoverBorder","bordered","hoverShade","transparent","fadeMix","flat","ghost","skyBorderPrimaryShorthand","relief","darkShade","gradient","createGradient","link","effVariant","effColor","effSize","effRadius","effAnimation","current","v","assign","tuneSurfaceVariantForDefaultColor","semanticKey","resolveSemanticSurfaceKey","soft","semanticSoftSurfaceTokens","animationMode","chosen","hover","active","presetToTransform","hoverTransform","activeTransform","s","basePadding","baseGap","borderWidth","includes","parseInt","hoverBorderWidth","adjustedPadding","paddingParts","all","vertical","horizontal","adjustedVertical","top","right","bottom","left","iconPx","btnMinHeight","btnMinWidth","side","paddingValues","hoverBorderShorthand","usesThemeBorder","borderColor","borderColorHover","vars","resolveRadius","focusButton","renderRoot","querySelector","focus","clickButton","click","_createRipple","event","button","currentTarget","rect","getBoundingClientRect","ripple","document","createElement","offsetWidth","offsetHeight","x","clientX","y","clientY","style","width","height","getComputedStyle","backgroundColor","background","contrastOverlay","className","existing","querySelectorAll","remove","appendChild","addEventListener","formDisabledCallback","formOwner","formId","getElementById","closest","_handleClick","preventDefault","reset","requestSubmit","_iconOnlyName","render","iconOnlyName","ariaLabel","html","styleMap","ifDefined","when","nothing","dependencies","SkyIcon","formAssociated","styles","skyFocusRingHostStyles","css","unsafeCSS","cssOnFillEnhance","selector","fillVar","__decorateClass","property","reflect","prototype","Boolean","state","eventOptions","passive","customElement"],"mappings":"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"}