@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.
- package/dist/custom-elements.json +2850 -2850
- package/dist/helper/controllers/animation-controller.d.ts +4 -4
- package/dist/helper/controllers/animation-controller.js.map +1 -1
- package/dist/helper/iconify-offline.js.map +1 -1
- package/dist/helper/utils/color-resolver.js.map +1 -1
- package/dist/helper/utils/contrast-color.js.map +1 -1
- package/dist/helper/utils/size-resolver.js.map +1 -1
- package/dist/sky-alert/sky-alert.js.map +1 -1
- package/dist/sky-appbar/sky-appbar.js.map +1 -1
- package/dist/sky-avatar/sky-avatar.js.map +1 -1
- package/dist/sky-badge/sky-badge.js.map +1 -1
- package/dist/sky-button/sky-button.js.map +1 -1
- package/dist/sky-card/sky-card.js.map +1 -1
- package/dist/sky-checkbox/sky-checkbox.js.map +1 -1
- package/dist/sky-chip/sky-chip.js.map +1 -1
- package/dist/sky-col/sky-col.js.map +1 -1
- package/dist/sky-combobox/sky-combobox.js.map +1 -1
- package/dist/sky-dialog/sky-dialog.js.map +1 -1
- package/dist/sky-divider/sky-divider.js.map +1 -1
- package/dist/sky-flexbox/sky-flexbox.js.map +1 -1
- package/dist/sky-flexcol/sky-flexcol.js.map +1 -1
- package/dist/sky-grid/sky-grid.js.map +1 -1
- package/dist/sky-icon/sky-icon.js +1 -1
- package/dist/sky-icon/sky-icon.js.map +1 -1
- package/dist/sky-image/sky-image.js.map +1 -1
- package/dist/sky-image/srcset-utils.js.map +1 -1
- package/dist/sky-input/sky-input.js.map +1 -1
- package/dist/sky-list/sky-list.js.map +1 -1
- package/dist/sky-listitem/sky-listitem.js.map +1 -1
- package/dist/sky-radio/sky-radio.js.map +1 -1
- package/dist/sky-row/sky-row.js.map +1 -1
- package/dist/sky-sheet/sky-sheet.js.map +1 -1
- package/dist/sky-simple-table/sky-simple-table.js.map +1 -1
- package/dist/sky-theme-provider/sky-theme-provider.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sky-dialog.js","sources":["../../src/sky-dialog/sky-dialog.ts"],"sourcesContent":["import { LitElement, html, css, nothing } from \"lit\";\r\nimport { customElement, property, query, state } from \"lit/decorators.js\";\r\nimport { when } from \"lit/directives/when.js\";\r\nimport { ref, createRef } from \"lit/directives/ref.js\";\r\nimport { classMap } from \"lit/directives/class-map.js\";\r\nimport { animate } from \"@lit-labs/motion\";\r\nimport { SkyIcon } from \"../sky-icon/sky-icon.js\";\r\nimport { PresetController } from \"../helper/controllers/preset-controller\";\n\r\nexport type SkyDialogPadding = \"none\" | \"xs\" | \"sm\" | \"md\" | \"lg\" | \"xl\";\r\nexport type SkyDialogRequestCloseDetail = { reason: \"backdrop\" | \"escape\" | \"close-button\" };\r\n/** Shared scroll lock state so multiple dialogs don't double-restore scroll. */\r\nlet _dialogOpenCount = 0;\r\nlet _savedScrollY = 0;\r\n\r\n/**\r\n * @element sky-dialog\r\n *\r\n * @summary Accessible modal dialog built on native `<dialog>` with controlled open state, slots, and keyboard/backdrop handling.\r\n *\r\n * @status stable\r\n * @since 1.0.0\r\n *\r\n * @documentation https://sky-ui.com/components/dialog\r\n * @dependency sky-icon\r\n *\r\n * @uiVModel open request-close sync=constant:false\r\n *\r\n * @slot header - Header content area at the top of the dialog.\r\n * @slot body - Main content area of the dialog.\r\n * @slot footer - Footer actions area at the bottom of the dialog.\r\n *\r\n * @csspart dialog - The dialog surface wrapper element.\r\n * @csspart close-button - The top-right close button.\r\n * @csspart message - Optional message text shown above the body.\r\n * @csspart header - Container for the header slot.\r\n * @csspart content - Container for the body slot.\r\n * @csspart actions - Container for the footer slot.\r\n * @csspart footer - Alias part on the footer container.\r\n *\r\n * @fires {CustomEvent<SkyDialogRequestCloseDetail>} request-close - Fired when close intent is detected and parent should update `open`.\r\n * @fires {CustomEvent<void>} dialog-opened - Fired after open animation completes.\r\n * @fires {CustomEvent<void>} dialog-closed - Fired after close animation completes.\r\n *\r\n * @property {boolean} open - Whether the dialog is visible.\r\n * @property {boolean} closable - Shows a top-right close button.\r\n * @property {string} message - Optional message displayed above body content.\r\n * @property {boolean} overlay - Applies dim/blur backdrop effect.\r\n * @property {string} width - Max width of the dialog surface.\r\n * @property {boolean} separator - Shows separators around header/footer regions.\r\n * @property {boolean} persistent - Prevents outside/Escape close and highlights surface instead.\r\n * @property {boolean} closeOnEsc - Enables close intent on Escape key.\r\n * @property {SkyDialogPadding} headerPadding - Header padding token.\r\n * @property {SkyDialogPadding} bodyPadding - Body padding token.\r\n * @property {SkyDialogPadding} footerPadding - Footer padding token.\r\n * @property {boolean} highlightOnOutsideClick - Enables highlight animation on rejected outside click.\r\n * @property {string} preset - Named prop preset from nearest `sky-config-provider`. Default: `\"\"`.\n * @method show Opens the dialog by setting `open` to true.\r\n * @method hide Closes the dialog by setting `open` to false.\r\n * @method focusDialog Focuses the native dialog surface.\r\n * @method getDialogElement Returns the native dialog element reference.\r\n *\r\n * @Behavior\r\n * - Uses native `<dialog>` element with enhanced functionality\r\n * - Controlled exclusively by the `open` attribute/property\r\n * - Uses native dialog focus behavior\r\n * - Supports smooth animations with configurable timing\r\n * - Uses the floating modal surface (frosted tertiary glass)\r\n * - **Standard**: Click outside closes dialog\r\n * - **Persistent**: Click outside highlights dialog instead of closing\r\n * - **Closable**: Shows close button in top-right corner\r\n * - **Escape handling**: Configurable Escape key behavior\r\n * - Uses `aria-modal=\"true\"` for screen reader isolation\r\n * - Native dialog focus behavior\r\n * - Escape key handling with user preferences\r\n * - Close button with appropriate ARIA label\r\n * - Respects reduced motion preferences\r\n * - Smooth open/close animations with scale effects\r\n * - Highlight animation for persistent dialogs\r\n * - Configurable animation durations\r\n * - Uses Web Animations API for performance\r\n * - Works with any content in header/body/footer slots\r\n * - Compatible with form controls and interactive content\r\n * - Can be nested or stacked\r\n * - Responsive width and padding\r\n *\r\n * @example\r\n * ```html\r\n * <sky-dialog open closable width=\"420px\" separator>\r\n * <h3 slot=\"header\">Confirm Action</h3>\r\n * <p slot=\"body\">Are you sure you want to proceed?</p>\r\n * <div slot=\"footer\">\r\n * <button>Cancel</button>\r\n * <button>Confirm</button>\r\n * </div>\r\n * </sky-dialog>\r\n * ```\r\n * ```vue\r\n * <template>\r\n * <sky-dialog open closable width=\"420px\" separator>\r\n * <h3 slot=\"header\">Confirm Action</h3>\r\n * <p slot=\"body\">Are you sure you want to proceed?</p>\r\n * <div slot=\"footer\">\r\n * <button>Cancel</button>\r\n * <button>Confirm</button>\r\n * </div>\r\n * </sky-dialog>\r\n * </template>\r\n * ```\r\n * ```jsx\r\n * export default function Demo() {\r\n * return (\r\n * <sky-dialog open closable width=\"420px\" separator>\r\n * <h3 slot=\"header\">Confirm Action</h3>\r\n * <p slot=\"body\">Are you sure you want to proceed?</p>\r\n * <div slot=\"footer\">\r\n * <button>Cancel</button>\r\n * <button>Confirm</button>\r\n * </div>\r\n * </sky-dialog>\r\n * );\r\n * }\r\n * ```\r\n */\r\n@customElement(\"sky-dialog\")\r\nexport class SkyDialog extends LitElement {\r\n\r\n static dependencies: Record<string, CustomElementConstructor> = {\r\n \"sky-icon\": SkyIcon,\r\n };\r\n\r\n /** @public Whether the dialog is visible. */\r\n @property({ type: Boolean, reflect: true })\r\n open = false;\r\n\r\n /** @public Shows a top-right close button. */\r\n @property({ type: Boolean, reflect: true })\r\n closable = false;\r\n\r\n /** @public Optional message displayed above the body. */\r\n @property({ type: String })\r\n message = \"\";\r\n\r\n /** @public Applies dim/blur overlay on host. */\r\n @property({ type: Boolean, reflect: true })\r\n overlay = false;\r\n\r\n /** @public Max width of the dialog surface (e.g., \"480px\" or \"auto\"). */\r\n @property({ type: String })\r\n width = \"auto\";\r\n\r\n /** @public Shows header/footer separators. */\r\n @property({ type: Boolean, reflect: true })\r\n separator = false;\r\n\r\n /** @public Prevents close on outside click, highlights instead. */\r\n @property({ type: Boolean, reflect: true })\r\n persistent = false;\r\n\r\n /** @public Enables closing on Escape key. */\r\n @property({ type: Boolean, reflect: true })\r\n closeOnEsc = false;\r\n\r\n /** @public Padding token for header container. */\r\n @property({ type: String, reflect: true })\r\n headerPadding: SkyDialogPadding = \"sm\";\r\n\r\n /** @public Padding token for body container. */\r\n @property({ type: String, reflect: true })\r\n bodyPadding: SkyDialogPadding = \"sm\";\r\n\r\n /** @public Padding token for footer container. */\r\n @property({ type: String, reflect: true })\r\n footerPadding: SkyDialogPadding = \"sm\";\r\n\r\n\r\n /** @public Highlights dialog on outside click instead of closing. */\r\n @property({\r\n type: Boolean,\r\n reflect: true,\r\n })\r\n highlightOnOutsideClick = true;\r\n\r\n /** @private Whether header slot has content. */\r\n @state()\r\n private _hasHeader = false;\r\n\r\n /** @private Whether body slot has content. */\r\n @state()\r\n private _hasBody = false;\r\n\r\n /** @private Whether footer slot has content. */\r\n @state()\r\n private _hasFooter = false;\r\n\r\n /** @private Whether dialog is in closing animation. */\r\n @state()\r\n private _isClosing = false;\r\n\r\n /** @private Open animation instance. */\r\n private _openAnimation: Animation | null = null;\r\n\r\n /** @private Close animation instance. */\r\n private _closeAnimation: Animation | null = null;\r\n\r\n /** @private Highlight animation instance. */\r\n private _highlightAnimation: Animation | null = null;\r\n\r\n /** @private Reference to the native dialog element. */\r\n @query(\"dialog\")\r\n private dialogElement?: HTMLDialogElement;\r\n\r\n /** @public Ref for the dialog element (e.g. for focus trap or positioning). */\r\n dialogRef = createRef<HTMLDialogElement>();\r\n\r\n /** @private Handle clicks on the dialog backdrop (outside surface). */\r\n private _onBackdropPointerDown = (event: PointerEvent): void => {\r\n const dialog = this.dialogElement;\r\n if (!dialog || !dialog.open) return;\r\n\r\n // In the <dialog> element, backdrop clicks are retargeted to the dialog itself.\r\n // Clicks inside the surface target inner elements.\r\n if (event.target !== dialog) return;\r\n\r\n // \"Persistent\" dialogs don't close via outside click; they highlight instead (optional).\r\n if (this.persistent) {\r\n this._highlightDialog();\r\n return;\r\n }\r\n\r\n // Standard behavior: outside click requests close.\r\n this._requestClose(\"backdrop\");\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: contents;\r\n font-family: var(--sky-font);\r\n }\r\n\r\n /* Floating modal template (§20.3) — single canonical surface */\r\n dialog {\r\n padding: 0;\r\n margin: auto;\r\n color: var(--sky-text-primary);\r\n position: fixed;\r\n box-sizing: border-box;\r\n width: 100%;\r\n text-align: center;\r\n overflow: hidden;\r\n z-index: var(--sky-z-modal, 1300);\r\n background: var(--sky-glass-tertiary);\r\n background-image: var(--sky-glass-surface);\r\n backdrop-filter: var(--sky-blur-tertiary) var(--sky-saturation-tertiary)\r\n var(--sky-brightness-tertiary);\r\n -webkit-backdrop-filter: var(--sky-blur-tertiary)\r\n var(--sky-saturation-tertiary) var(--sky-brightness-tertiary);\r\n border: var(--sky-border-tertiary);\r\n border-radius: var(--sky-radius-tertiary);\r\n box-shadow:\r\n var(--sky-box-shadow-inset),\r\n var(--sky-box-shadow-tertiary);\r\n }\r\n\r\n dialog::backdrop {\r\n backdrop-filter: none;\r\n -webkit-backdrop-filter: none;\r\n transition: backdrop-filter 0.3s ease-in-out;\r\n }\r\n\r\n :host([overlay]) dialog::backdrop {\r\n backdrop-filter: var(--sky-blur-tertiary);\r\n -webkit-backdrop-filter: var(--sky-blur-tertiary);\r\n }\r\n\r\n .header-padding-none,\r\n .body-padding-none,\r\n .footer-padding-none {\r\n padding: var(--sky-space-0, 0);\r\n }\r\n\r\n .header-padding-xs,\r\n .body-padding-xs,\r\n .footer-padding-xs {\r\n padding: var(--sky-space-1, 4px);\r\n }\r\n\r\n .header-padding-sm,\r\n .body-padding-sm,\r\n .footer-padding-sm {\r\n padding: var(--sky-space-2, 8px);\r\n }\r\n\r\n .header-padding-md,\r\n .body-padding-md,\r\n .footer-padding-md {\r\n padding: var(--sky-space-4, 16px);\r\n }\r\n\r\n .header-padding-lg,\r\n .body-padding-lg,\r\n .footer-padding-lg {\r\n padding: var(--sky-space-6, 24px);\r\n }\r\n\r\n .header-padding-xl,\r\n .body-padding-xl,\r\n .footer-padding-xl {\r\n padding: var(--sky-space-8, 32px);\r\n }\r\n\r\n /* Close button — §20.6 inner dismiss affordance */\r\n .close-button {\r\n position: absolute;\r\n top: var(--sky-space-1\\\\.5, 6px);\r\n right: var(--sky-space-1\\\\.5, 6px);\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: var(--sky-space-6, 24px);\r\n height: var(--sky-space-6, 24px);\r\n box-sizing: border-box;\r\n border-radius: var(--sky-radius-full);\r\n font-size: var(--sky-font-size-sm, 14px);\r\n cursor: pointer;\r\n color: var(--sky-text-primary);\r\n border: none;\r\n background-color: var(--sky-hover-primary);\r\n backdrop-filter: none;\r\n -webkit-backdrop-filter: none;\r\n transition: color 0.2s ease, background-color 0.2s ease;\r\n z-index: 1;\r\n }\r\n\r\n .close-button sky-icon {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n line-height: 1;\r\n }\r\n\r\n .close-button:hover {\r\n color: var(--sky-danger-primary);\r\n }\r\n\r\n .close-button:focus-visible {\r\n outline: none;\r\n box-shadow: var(--sky-focus-ring);\r\n }\r\n\r\n /* Message */\r\n .message {\r\n padding: var(--sky-space-4, 16px) 0;\r\n margin: 0;\r\n }\r\n\r\n ::slotted([slot=\"header\"]) {\r\n font-size: var(--sky-font-size-md, 16px);\r\n font-weight: var(--sky-font-weight-bold, 700);\r\n color: var(--sky-text-primary);\r\n box-sizing: border-box;\r\n }\r\n\r\n dialog:focus,\r\n dialog:focus-visible {\r\n outline: none;\r\n }\r\n\r\n .header-separator {\r\n border-bottom: var(--sky-border-primary);\r\n }\r\n\r\n .footer-separator {\r\n border-top: var(--sky-border-primary);\r\n }\r\n\r\n sky-icon {\r\n display: inline-block;\r\n width: 1em;\r\n height: 1em;\r\n }\r\n\r\n /* RTL support */\r\n :host([dir=\"rtl\"]) .close-button {\r\n right: auto;\r\n left: var(--sky-space-1\\\\.5, 6px);\r\n }\r\n\r\n /* Animation classes */\r\n dialog.opening {\r\n opacity: 0;\r\n }\r\n\r\n dialog.closing {\r\n opacity: 1;\r\n }\r\n\r\n @media (prefers-reduced-motion: reduce) {\r\n dialog::backdrop,\r\n .close-button {\r\n transition: none;\r\n }\r\n }\r\n `;\r\n\r\n constructor() {\r\n super();\r\n this._handleCancel = this._handleCancel.bind(this);\r\n }\r\n\r\n /** @protected */\r\n override firstUpdated() {\r\n const d = this.dialogElement;\r\n if (!d) return;\r\n\r\n // Capture phase is important so we beat the native <dialog> cancel/close behavior\r\n d.addEventListener(\"keydown\", this._onKeyDown, { capture: true });\r\n d.addEventListener(\"pointerdown\", this._onBackdropPointerDown);\r\n d.addEventListener(\"cancel\", this._handleCancel as any); // optional extra safety\r\n d.addEventListener(\"close\", this._onNativeClose); // keep state in sync (below)\r\n }\r\n\r\n /** @protected */\r\n override disconnectedCallback() {\r\n const d = this.dialogElement;\r\n if (d) {\r\n d.removeEventListener(\"keydown\", this._onKeyDown, {\r\n capture: true,\r\n } as any);\r\n d.removeEventListener(\"pointerdown\", this._onBackdropPointerDown);\r\n d.removeEventListener(\"cancel\", this._handleCancel as any);\r\n d.removeEventListener(\"close\", this._onNativeClose);\r\n }\r\n super.disconnectedCallback();\r\n this._unlockScroll();\r\n if (d?.open) d.close();\r\n }\r\n\r\n /**\r\n * Opens the dialog programmatically.\r\n * @public\r\n */\r\n public show(): void {\r\n this.open = true;\r\n }\r\n\r\n /**\r\n * Closes the dialog programmatically.\r\n * @public\r\n */\r\n public hide(): void {\r\n this.open = false;\r\n }\r\n\r\n /**\r\n * Manually focuses the dialog element.\r\n * @public\r\n */\r\n public focusDialog(): void {\r\n if (this.dialogElement) {\r\n this.dialogElement.focus();\r\n }\r\n }\r\n\r\n /**\r\n * Gets the native dialog element.\r\n * @returns The native HTMLDialogElement or undefined\r\n * @public\r\n */\r\n public getDialogElement(): HTMLDialogElement | undefined {\r\n return this.dialogElement;\r\n }\r\n\r\n /** @private */\r\n private _onNativeClose = (): void => {\r\n // If parent still says open=true, reopen immediately (persistent behavior)\r\n if (this.open) {\r\n // restore modal state\r\n requestAnimationFrame(() => {\r\n if (!this.dialogElement?.open) {\r\n this.dialogElement?.showModal();\r\n }\r\n });\r\n }\r\n };\r\n\r\n /** @protected */\r\n override updated(changedProps: Map<string, any>) {\r\n if (changedProps.has(\"open\")) {\r\n // Use requestAnimationFrame to ensure DOM updates are complete\r\n requestAnimationFrame(() => {\r\n this._handleOpenChange(changedProps.get(\"open\"));\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Handles open state changes.\r\n * @param previousOpen - Previous open state\r\n * @private\r\n */\r\n private _handleOpenChange(previousOpen: boolean): void {\r\n if (!this.dialogElement) return;\r\n\r\n if (this.open && !this.dialogElement.open) {\r\n this._lockScroll();\r\n this.dialogElement.showModal();\r\n\r\n requestAnimationFrame(() => {\r\n this._animateOpen();\r\n });\r\n } else if (!this.open && previousOpen) {\r\n this._isClosing = true;\r\n this._animateClose();\r\n }\r\n }\r\n\r\n /** @private */\r\n private _lockScroll(): void {\r\n if (typeof window === \"undefined\" || typeof document === \"undefined\") return;\r\n if (_dialogOpenCount === 0) {\r\n _savedScrollY = window.scrollY;\r\n window.scrollTo(0, 0);\r\n }\r\n _dialogOpenCount++;\r\n document.documentElement.setAttribute(\"data-sky-dialog-open\", \"true\");\r\n }\r\n\r\n /** @private */\r\n private _unlockScroll(): void {\r\n if (typeof window === \"undefined\" || typeof document === \"undefined\") return;\r\n _dialogOpenCount = Math.max(0, _dialogOpenCount - 1);\r\n if (_dialogOpenCount === 0) {\r\n document.documentElement.removeAttribute(\"data-sky-dialog-open\");\r\n window.scrollTo(0, _savedScrollY);\r\n }\r\n }\r\n\r\n /** @private */\r\n private _prefersReducedMotion(): boolean {\r\n if (typeof window === \"undefined\" || !window.matchMedia) return false;\r\n return window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches;\r\n }\r\n\r\n /** @private */\r\n private _animateOpen(): void {\r\n const dialog = this.dialogElement;\r\n if (!dialog) return;\r\n\r\n this._openAnimation?.cancel();\r\n this._closeAnimation?.cancel();\r\n\r\n const duration = this._prefersReducedMotion() ? 0 : 300;\r\n const animation = dialog.animate(\r\n [\r\n {\r\n opacity: 0,\r\n transform: \"scale(0.95)\",\r\n transformOrigin: \"center center\",\r\n },\r\n { opacity: 1, transform: \"scale(1)\", transformOrigin: \"center center\" },\r\n ],\r\n {\r\n duration,\r\n easing: \"ease-out\",\r\n fill: \"forwards\",\r\n },\r\n );\r\n\r\n animation.onfinish = () => {\r\n this.dispatchEvent(\r\n new CustomEvent(\"dialog-opened\", {\r\n bubbles: true,\r\n composed: true,\r\n }),\r\n );\r\n };\r\n\r\n this._openAnimation = animation;\r\n }\r\n\r\n /** @private */\r\n private _animateClose(): void {\r\n const dialog = this.dialogElement;\r\n if (!dialog) return;\r\n this._openAnimation?.cancel();\r\n this._closeAnimation?.cancel();\r\n\r\n const duration = this._prefersReducedMotion() ? 0 : 150;\r\n const animation = dialog.animate(\r\n [\r\n { opacity: 1, transform: \"scale(1)\", transformOrigin: \"center center\" },\r\n {\r\n opacity: 0,\r\n transform: \"scale(0.95)\",\r\n transformOrigin: \"center center\",\r\n },\r\n ],\r\n {\r\n duration,\r\n easing: \"ease-out\",\r\n fill: \"forwards\",\r\n },\r\n );\r\n\r\n animation.onfinish = () => {\r\n dialog.close();\r\n this._unlockScroll();\r\n this._isClosing = false;\r\n this.dispatchEvent(\r\n new CustomEvent(\"dialog-closed\", {\r\n bubbles: true,\r\n composed: true,\r\n }),\r\n );\r\n };\r\n\r\n this._closeAnimation = animation;\r\n }\r\n\r\n /** @private */\r\n private _handleCancel(event: Event): void {\r\n event.preventDefault();\r\n\r\n if (this.persistent || !this.closeOnEsc) {\r\n this._highlightDialog();\r\n return;\r\n }\r\n\r\n this._requestClose(\"escape\");\r\n }\r\n\r\n /** @private */\r\n private _highlightDialog(): void {\r\n if (!this.highlightOnOutsideClick) return;\r\n if (this._prefersReducedMotion()) return;\r\n\r\n const dialog = this.dialogElement;\r\n if (!dialog) return;\r\n\r\n this._highlightAnimation?.cancel();\r\n\r\n const animation = dialog.animate(\r\n [\r\n { transform: \"scale(1)\" },\r\n { transform: \"scale(1.05)\" },\r\n { transform: \"scale(1)\" },\r\n ],\r\n {\r\n duration: 300,\r\n easing: \"ease-in-out\",\r\n },\r\n );\r\n\r\n this._highlightAnimation = animation;\r\n }\r\n\r\n\r\n\r\n /** @private */\r\n private _requestClose(reason: SkyDialogRequestCloseDetail[\"reason\"]): void {\r\n if (this._isClosing) return;\r\n this.dispatchEvent(\r\n new CustomEvent<SkyDialogRequestCloseDetail>(\"request-close\", {\r\n detail: { reason },\r\n bubbles: true,\r\n composed: true,\r\n }),\r\n );\r\n }\r\n\r\n /**\r\n * Checks if a slot has content.\r\n * @param slot - Slot element to check\r\n * @returns True if slot has content\r\n * @private\r\n */\r\n private _slotHasContent(slot: HTMLSlotElement): boolean {\r\n const nodes = slot.assignedNodes({ flatten: true });\r\n return nodes.some((n) => {\r\n if (n.nodeType === Node.TEXT_NODE) {\r\n return !!n.textContent?.trim();\r\n }\r\n return true;\r\n });\r\n }\r\n\r\n /** @private */\r\n private _onHeaderSlotChange = (e: Event): void => {\r\n const slot = e.target as HTMLSlotElement;\r\n this._hasHeader = this._slotHasContent(slot);\r\n };\r\n\r\n /** @private */\r\n private _onBodySlotChange = (e: Event): void => {\r\n const slot = e.target as HTMLSlotElement;\r\n this._hasBody = this._slotHasContent(slot);\r\n };\r\n\r\n /** @private */\r\n private _onFooterSlotChange = (e: Event): void => {\r\n const slot = e.target as HTMLSlotElement;\r\n this._hasFooter = this._slotHasContent(slot);\r\n };\r\n\r\n /** @private */\r\n private _onKeyDown = (e: KeyboardEvent): void => {\r\n if (e.key !== \"Escape\") return;\r\n\r\n // Always stop native <dialog> ESC behavior\r\n e.preventDefault();\r\n e.stopPropagation();\r\n // If persistent OR closeOnEsc is false → do NOT close, just highlight\r\n if (this.persistent || !this.closeOnEsc) {\r\n this._highlightDialog();\r\n return;\r\n }\r\n\r\n // Allowed to close via ESC\r\n this._requestClose(\"escape\");\r\n };\r\n\r\n /** @protected */\r\n override render() {\r\n const valid: Record<SkyDialogPadding, true> = {\r\n none: true,\r\n xs: true,\r\n sm: true,\r\n md: true,\r\n lg: true,\r\n xl: true,\r\n };\r\n\r\n const hp = valid[this.headerPadding] ? this.headerPadding : \"md\";\r\n const bp = valid[this.bodyPadding] ? this.bodyPadding : \"md\";\r\n const fp = valid[this.footerPadding] ? this.footerPadding : \"md\";\r\n\r\n const headerClasses: Record<string, boolean> = {};\r\n if (this._hasHeader) {\r\n headerClasses[`header-padding-${hp}`] = true;\r\n if (this.separator) {\r\n headerClasses[\"header-separator\"] = true;\r\n }\r\n }\r\n\r\n const footerClasses: Record<string, boolean> = {};\r\n if (this._hasFooter) {\r\n footerClasses[\"actions\"] = true;\r\n footerClasses[`footer-padding-${fp}`] = true;\r\n if (this.separator) {\r\n footerClasses[\"footer-separator\"] = true;\r\n }\r\n } else {\r\n footerClasses[\"actions\"] = true;\r\n }\r\n\r\n return html`\r\n <dialog\r\n part=\"dialog\"\r\n aria-modal=\"true\"\r\n style=\"max-width: ${this.width};\"\r\n @cancel=\"${this._handleCancel}\"\r\n ${ref(this.dialogRef)}\r\n ${animate({\r\n keyframeOptions: {\r\n duration: 300,\r\n easing: \"ease-out\",\r\n },\r\n })}\r\n >\r\n <slot></slot>\r\n\r\n ${when(this.message, () => html`\r\n <p class=\"message\" part=\"message\">${this.message}</p>\r\n `)}\r\n\r\n <div class=${classMap(headerClasses)} part=\"header\">\r\n <slot name=\"header\" @slotchange=${this._onHeaderSlotChange}></slot>\r\n </div>\r\n\r\n <div\r\n class=${classMap({\r\n [`body-padding-${bp}`]: this._hasBody,\r\n })}\r\n part=\"content\"\r\n >\r\n <slot name=\"body\" @slotchange=${this._onBodySlotChange}></slot>\r\n </div>\r\n\r\n <div class=${classMap(footerClasses)} part=\"actions footer\">\r\n <slot name=\"footer\" @slotchange=${this._onFooterSlotChange}></slot>\r\n </div>\r\n ${when(this.closable, () => html`\r\n <button\r\n class=\"close-button\"\r\n part=\"close-button\"\r\n type=\"button\"\r\n aria-label=\"Close dialog\"\r\n @click=${() => this._requestClose(\"close-button\")}\r\n >\r\n <sky-icon icon=\"ion:close\"></sky-icon>\r\n </button>\r\n `)}\r\n </dialog>\r\n `;\r\n }\r\n}\r\n"],"names":["_dialogOpenCount","_savedScrollY","SkyDialog","LitElement","constructor","super","this","open","closable","message","overlay","width","separator","persistent","closeOnEsc","headerPadding","bodyPadding","footerPadding","highlightOnOutsideClick","_hasHeader","_hasBody","_hasFooter","_isClosing","_openAnimation","_closeAnimation","_highlightAnimation","dialogRef","createRef","_onBackdropPointerDown","event","dialog","dialogElement","target","_highlightDialog","_requestClose","preset","_presets","PresetController","_onNativeClose","requestAnimationFrame","showModal","_onHeaderSlotChange","e","slot","_slotHasContent","_onBodySlotChange","_onFooterSlotChange","_onKeyDown","key","preventDefault","stopPropagation","_handleCancel","bind","firstUpdated","d","addEventListener","capture","disconnectedCallback","removeEventListener","_unlockScroll","close","show","hide","focusDialog","focus","getDialogElement","updated","changedProps","has","_handleOpenChange","get","previousOpen","_lockScroll","_animateOpen","_animateClose","window","document","scrollY","scrollTo","documentElement","setAttribute","Math","max","removeAttribute","_prefersReducedMotion","matchMedia","matches","cancel","duration","animation","animate","opacity","transform","transformOrigin","easing","fill","onfinish","dispatchEvent","CustomEvent","bubbles","composed","reason","detail","assignedNodes","flatten","some","n","nodeType","Node","TEXT_NODE","textContent","trim","render","valid","none","xs","sm","md","lg","xl","hp","bp","fp","headerClasses","footerClasses","html","ref","keyframeOptions","when","classMap","dependencies","SkyIcon","styles","css","__decorateClass","property","type","Boolean","reflect","prototype","String","state","query","customElement"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sky-dialog.js","sources":["../../src/sky-dialog/sky-dialog.ts"],"sourcesContent":["import { LitElement, html, css, nothing } from \"lit\";\r\nimport { customElement, property, query, state } from \"lit/decorators.js\";\r\nimport { when } from \"lit/directives/when.js\";\r\nimport { ref, createRef } from \"lit/directives/ref.js\";\r\nimport { classMap } from \"lit/directives/class-map.js\";\r\nimport { animate } from \"@lit-labs/motion\";\r\nimport { SkyIcon } from \"../sky-icon/sky-icon.js\";\r\nimport { PresetController } from \"../helper/controllers/preset-controller\";\r\n\r\nexport type SkyDialogPadding = \"none\" | \"xs\" | \"sm\" | \"md\" | \"lg\" | \"xl\";\r\nexport type SkyDialogRequestCloseDetail = { reason: \"backdrop\" | \"escape\" | \"close-button\" };\r\n/** Shared scroll lock state so multiple dialogs don't double-restore scroll. */\r\nlet _dialogOpenCount = 0;\r\nlet _savedScrollY = 0;\r\n\r\n/**\r\n * @element sky-dialog\r\n *\r\n * @summary Accessible modal dialog built on native `<dialog>` with controlled open state, slots, and keyboard/backdrop handling.\r\n *\r\n * @status stable\r\n * @since 1.0.0\r\n *\r\n * @documentation https://sky-ui.com/components/dialog\r\n * @dependency sky-icon\r\n *\r\n * @uiVModel open request-close sync=constant:false\r\n *\r\n * @slot header - Header content area at the top of the dialog.\r\n * @slot body - Main content area of the dialog.\r\n * @slot footer - Footer actions area at the bottom of the dialog.\r\n *\r\n * @csspart dialog - The dialog surface wrapper element.\r\n * @csspart close-button - The top-right close button.\r\n * @csspart message - Optional message text shown above the body.\r\n * @csspart header - Container for the header slot.\r\n * @csspart content - Container for the body slot.\r\n * @csspart actions - Container for the footer slot.\r\n * @csspart footer - Alias part on the footer container.\r\n *\r\n * @fires {CustomEvent<SkyDialogRequestCloseDetail>} request-close - Fired when close intent is detected and parent should update `open`.\r\n * @fires {CustomEvent<void>} dialog-opened - Fired after open animation completes.\r\n * @fires {CustomEvent<void>} dialog-closed - Fired after close animation completes.\r\n *\r\n * @property {boolean} open - Whether the dialog is visible.\r\n * @property {boolean} closable - Shows a top-right close button.\r\n * @property {string} message - Optional message displayed above body content.\r\n * @property {boolean} overlay - Applies dim/blur backdrop effect.\r\n * @property {string} width - Max width of the dialog surface.\r\n * @property {boolean} separator - Shows separators around header/footer regions.\r\n * @property {boolean} persistent - Prevents outside/Escape close and highlights surface instead.\r\n * @property {boolean} closeOnEsc - Enables close intent on Escape key.\r\n * @property {SkyDialogPadding} headerPadding - Header padding token.\r\n * @property {SkyDialogPadding} bodyPadding - Body padding token.\r\n * @property {SkyDialogPadding} footerPadding - Footer padding token.\r\n * @property {boolean} highlightOnOutsideClick - Enables highlight animation on rejected outside click.\r\n * @property {string} preset - Named prop preset from nearest `sky-config-provider`. Default: `\"\"`.\r\n * @method show Opens the dialog by setting `open` to true.\r\n * @method hide Closes the dialog by setting `open` to false.\r\n * @method focusDialog Focuses the native dialog surface.\r\n * @method getDialogElement Returns the native dialog element reference.\r\n *\r\n * @Behavior\r\n * - Uses native `<dialog>` element with enhanced functionality\r\n * - Controlled exclusively by the `open` attribute/property\r\n * - Uses native dialog focus behavior\r\n * - Supports smooth animations with configurable timing\r\n * - Uses the floating modal surface (frosted tertiary glass)\r\n * - **Standard**: Click outside closes dialog\r\n * - **Persistent**: Click outside highlights dialog instead of closing\r\n * - **Closable**: Shows close button in top-right corner\r\n * - **Escape handling**: Configurable Escape key behavior\r\n * - Uses `aria-modal=\"true\"` for screen reader isolation\r\n * - Native dialog focus behavior\r\n * - Escape key handling with user preferences\r\n * - Close button with appropriate ARIA label\r\n * - Respects reduced motion preferences\r\n * - Smooth open/close animations with scale effects\r\n * - Highlight animation for persistent dialogs\r\n * - Configurable animation durations\r\n * - Uses Web Animations API for performance\r\n * - Works with any content in header/body/footer slots\r\n * - Compatible with form controls and interactive content\r\n * - Can be nested or stacked\r\n * - Responsive width and padding\r\n *\r\n * @example\r\n * ```html\r\n * <sky-dialog open closable width=\"420px\" separator>\r\n * <h3 slot=\"header\">Confirm Action</h3>\r\n * <p slot=\"body\">Are you sure you want to proceed?</p>\r\n * <div slot=\"footer\">\r\n * <button>Cancel</button>\r\n * <button>Confirm</button>\r\n * </div>\r\n * </sky-dialog>\r\n * ```\r\n * ```vue\r\n * <template>\r\n * <sky-dialog open closable width=\"420px\" separator>\r\n * <h3 slot=\"header\">Confirm Action</h3>\r\n * <p slot=\"body\">Are you sure you want to proceed?</p>\r\n * <div slot=\"footer\">\r\n * <button>Cancel</button>\r\n * <button>Confirm</button>\r\n * </div>\r\n * </sky-dialog>\r\n * </template>\r\n * ```\r\n * ```jsx\r\n * export default function Demo() {\r\n * return (\r\n * <sky-dialog open closable width=\"420px\" separator>\r\n * <h3 slot=\"header\">Confirm Action</h3>\r\n * <p slot=\"body\">Are you sure you want to proceed?</p>\r\n * <div slot=\"footer\">\r\n * <button>Cancel</button>\r\n * <button>Confirm</button>\r\n * </div>\r\n * </sky-dialog>\r\n * );\r\n * }\r\n * ```\r\n */\r\n@customElement(\"sky-dialog\")\r\nexport class SkyDialog extends LitElement {\r\n\r\n static dependencies: Record<string, CustomElementConstructor> = {\r\n \"sky-icon\": SkyIcon,\r\n };\r\n\r\n /** @public Whether the dialog is visible. */\r\n @property({ type: Boolean, reflect: true })\r\n open = false;\r\n\r\n /** @public Shows a top-right close button. */\r\n @property({ type: Boolean, reflect: true })\r\n closable = false;\r\n\r\n /** @public Optional message displayed above the body. */\r\n @property({ type: String })\r\n message = \"\";\r\n\r\n /** @public Applies dim/blur overlay on host. */\r\n @property({ type: Boolean, reflect: true })\r\n overlay = false;\r\n\r\n /** @public Max width of the dialog surface (e.g., \"480px\" or \"auto\"). */\r\n @property({ type: String })\r\n width = \"auto\";\r\n\r\n /** @public Shows header/footer separators. */\r\n @property({ type: Boolean, reflect: true })\r\n separator = false;\r\n\r\n /** @public Prevents close on outside click, highlights instead. */\r\n @property({ type: Boolean, reflect: true })\r\n persistent = false;\r\n\r\n /** @public Enables closing on Escape key. */\r\n @property({ type: Boolean, reflect: true })\r\n closeOnEsc = false;\r\n\r\n /** @public Padding token for header container. */\r\n @property({ type: String, reflect: true })\r\n headerPadding: SkyDialogPadding = \"sm\";\r\n\r\n /** @public Padding token for body container. */\r\n @property({ type: String, reflect: true })\r\n bodyPadding: SkyDialogPadding = \"sm\";\r\n\r\n /** @public Padding token for footer container. */\r\n @property({ type: String, reflect: true })\r\n footerPadding: SkyDialogPadding = \"sm\";\r\n\r\n\r\n /** @public Highlights dialog on outside click instead of closing. */\r\n @property({\r\n type: Boolean,\r\n reflect: true,\r\n })\r\n highlightOnOutsideClick = true;\r\n\r\n /** @private Whether header slot has content. */\r\n @state()\r\n private _hasHeader = false;\r\n\r\n /** @private Whether body slot has content. */\r\n @state()\r\n private _hasBody = false;\r\n\r\n /** @private Whether footer slot has content. */\r\n @state()\r\n private _hasFooter = false;\r\n\r\n /** @private Whether dialog is in closing animation. */\r\n @state()\r\n private _isClosing = false;\r\n\r\n /** @private Open animation instance. */\r\n private _openAnimation: Animation | null = null;\r\n\r\n /** @private Close animation instance. */\r\n private _closeAnimation: Animation | null = null;\r\n\r\n /** @private Highlight animation instance. */\r\n private _highlightAnimation: Animation | null = null;\r\n\r\n /** @private Reference to the native dialog element. */\r\n @query(\"dialog\")\r\n private dialogElement?: HTMLDialogElement;\r\n\r\n /** @public Ref for the dialog element (e.g. for focus trap or positioning). */\r\n dialogRef = createRef<HTMLDialogElement>();\r\n\r\n /** @private Handle clicks on the dialog backdrop (outside surface). */\r\n private _onBackdropPointerDown = (event: PointerEvent): void => {\r\n const dialog = this.dialogElement;\r\n if (!dialog || !dialog.open) return;\r\n\r\n // In the <dialog> element, backdrop clicks are retargeted to the dialog itself.\r\n // Clicks inside the surface target inner elements.\r\n if (event.target !== dialog) return;\r\n\r\n // \"Persistent\" dialogs don't close via outside click; they highlight instead (optional).\r\n if (this.persistent) {\r\n this._highlightDialog();\r\n return;\r\n }\r\n\r\n // Standard behavior: outside click requests close.\r\n this._requestClose(\"backdrop\");\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: contents;\r\n font-family: var(--sky-font);\r\n }\r\n\r\n /* Floating modal template (§20.3) — single canonical surface */\r\n dialog {\r\n padding: 0;\r\n margin: auto;\r\n color: var(--sky-text-primary);\r\n position: fixed;\r\n box-sizing: border-box;\r\n width: 100%;\r\n text-align: center;\r\n overflow: hidden;\r\n z-index: var(--sky-z-modal, 1300);\r\n background: var(--sky-glass-tertiary);\r\n background-image: var(--sky-glass-surface);\r\n backdrop-filter: var(--sky-blur-tertiary) var(--sky-saturation-tertiary)\r\n var(--sky-brightness-tertiary);\r\n -webkit-backdrop-filter: var(--sky-blur-tertiary)\r\n var(--sky-saturation-tertiary) var(--sky-brightness-tertiary);\r\n border: var(--sky-border-tertiary);\r\n border-radius: var(--sky-radius-tertiary);\r\n box-shadow:\r\n var(--sky-box-shadow-inset),\r\n var(--sky-box-shadow-tertiary);\r\n }\r\n\r\n dialog::backdrop {\r\n backdrop-filter: none;\r\n -webkit-backdrop-filter: none;\r\n transition: backdrop-filter 0.3s ease-in-out;\r\n }\r\n\r\n :host([overlay]) dialog::backdrop {\r\n backdrop-filter: var(--sky-blur-tertiary);\r\n -webkit-backdrop-filter: var(--sky-blur-tertiary);\r\n }\r\n\r\n .header-padding-none,\r\n .body-padding-none,\r\n .footer-padding-none {\r\n padding: var(--sky-space-0, 0);\r\n }\r\n\r\n .header-padding-xs,\r\n .body-padding-xs,\r\n .footer-padding-xs {\r\n padding: var(--sky-space-1, 4px);\r\n }\r\n\r\n .header-padding-sm,\r\n .body-padding-sm,\r\n .footer-padding-sm {\r\n padding: var(--sky-space-2, 8px);\r\n }\r\n\r\n .header-padding-md,\r\n .body-padding-md,\r\n .footer-padding-md {\r\n padding: var(--sky-space-4, 16px);\r\n }\r\n\r\n .header-padding-lg,\r\n .body-padding-lg,\r\n .footer-padding-lg {\r\n padding: var(--sky-space-6, 24px);\r\n }\r\n\r\n .header-padding-xl,\r\n .body-padding-xl,\r\n .footer-padding-xl {\r\n padding: var(--sky-space-8, 32px);\r\n }\r\n\r\n /* Close button — §20.6 inner dismiss affordance */\r\n .close-button {\r\n position: absolute;\r\n top: var(--sky-space-1\\\\.5, 6px);\r\n right: var(--sky-space-1\\\\.5, 6px);\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: var(--sky-space-6, 24px);\r\n height: var(--sky-space-6, 24px);\r\n box-sizing: border-box;\r\n border-radius: var(--sky-radius-full);\r\n font-size: var(--sky-font-size-sm, 14px);\r\n cursor: pointer;\r\n color: var(--sky-text-primary);\r\n border: none;\r\n background-color: var(--sky-hover-primary);\r\n backdrop-filter: none;\r\n -webkit-backdrop-filter: none;\r\n transition: color 0.2s ease, background-color 0.2s ease;\r\n z-index: 1;\r\n }\r\n\r\n .close-button sky-icon {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n line-height: 1;\r\n }\r\n\r\n .close-button:hover {\r\n color: var(--sky-danger-primary);\r\n }\r\n\r\n .close-button:focus-visible {\r\n outline: none;\r\n box-shadow: var(--sky-focus-ring);\r\n }\r\n\r\n /* Message */\r\n .message {\r\n padding: var(--sky-space-4, 16px) 0;\r\n margin: 0;\r\n }\r\n\r\n ::slotted([slot=\"header\"]) {\r\n font-size: var(--sky-font-size-md, 16px);\r\n font-weight: var(--sky-font-weight-bold, 700);\r\n color: var(--sky-text-primary);\r\n box-sizing: border-box;\r\n }\r\n\r\n dialog:focus,\r\n dialog:focus-visible {\r\n outline: none;\r\n }\r\n\r\n .header-separator {\r\n border-bottom: var(--sky-border-primary);\r\n }\r\n\r\n .footer-separator {\r\n border-top: var(--sky-border-primary);\r\n }\r\n\r\n sky-icon {\r\n display: inline-block;\r\n width: 1em;\r\n height: 1em;\r\n }\r\n\r\n /* RTL support */\r\n :host([dir=\"rtl\"]) .close-button {\r\n right: auto;\r\n left: var(--sky-space-1\\\\.5, 6px);\r\n }\r\n\r\n /* Animation classes */\r\n dialog.opening {\r\n opacity: 0;\r\n }\r\n\r\n dialog.closing {\r\n opacity: 1;\r\n }\r\n\r\n @media (prefers-reduced-motion: reduce) {\r\n dialog::backdrop,\r\n .close-button {\r\n transition: none;\r\n }\r\n }\r\n `;\r\n\r\n constructor() {\r\n super();\r\n this._handleCancel = this._handleCancel.bind(this);\r\n }\r\n\r\n /** @protected */\r\n override firstUpdated() {\r\n const d = this.dialogElement;\r\n if (!d) return;\r\n\r\n // Capture phase is important so we beat the native <dialog> cancel/close behavior\r\n d.addEventListener(\"keydown\", this._onKeyDown, { capture: true });\r\n d.addEventListener(\"pointerdown\", this._onBackdropPointerDown);\r\n d.addEventListener(\"cancel\", this._handleCancel as any); // optional extra safety\r\n d.addEventListener(\"close\", this._onNativeClose); // keep state in sync (below)\r\n }\r\n\r\n /** @protected */\r\n override disconnectedCallback() {\r\n const d = this.dialogElement;\r\n if (d) {\r\n d.removeEventListener(\"keydown\", this._onKeyDown, {\r\n capture: true,\r\n } as any);\r\n d.removeEventListener(\"pointerdown\", this._onBackdropPointerDown);\r\n d.removeEventListener(\"cancel\", this._handleCancel as any);\r\n d.removeEventListener(\"close\", this._onNativeClose);\r\n }\r\n super.disconnectedCallback();\r\n this._unlockScroll();\r\n if (d?.open) d.close();\r\n }\r\n\r\n /**\r\n * Opens the dialog programmatically.\r\n * @public\r\n */\r\n public show(): void {\r\n this.open = true;\r\n }\r\n\r\n /**\r\n * Closes the dialog programmatically.\r\n * @public\r\n */\r\n public hide(): void {\r\n this.open = false;\r\n }\r\n\r\n /**\r\n * Manually focuses the dialog element.\r\n * @public\r\n */\r\n public focusDialog(): void {\r\n if (this.dialogElement) {\r\n this.dialogElement.focus();\r\n }\r\n }\r\n\r\n /**\r\n * Gets the native dialog element.\r\n * @returns The native HTMLDialogElement or undefined\r\n * @public\r\n */\r\n public getDialogElement(): HTMLDialogElement | undefined {\r\n return this.dialogElement;\r\n }\r\n\r\n /** @private */\r\n private _onNativeClose = (): void => {\r\n // If parent still says open=true, reopen immediately (persistent behavior)\r\n if (this.open) {\r\n // restore modal state\r\n requestAnimationFrame(() => {\r\n if (!this.dialogElement?.open) {\r\n this.dialogElement?.showModal();\r\n }\r\n });\r\n }\r\n };\r\n\r\n /** @protected */\r\n override updated(changedProps: Map<string, any>) {\r\n if (changedProps.has(\"open\")) {\r\n // Use requestAnimationFrame to ensure DOM updates are complete\r\n requestAnimationFrame(() => {\r\n this._handleOpenChange(changedProps.get(\"open\"));\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Handles open state changes.\r\n * @param previousOpen - Previous open state\r\n * @private\r\n */\r\n private _handleOpenChange(previousOpen: boolean): void {\r\n if (!this.dialogElement) return;\r\n\r\n if (this.open && !this.dialogElement.open) {\r\n this._lockScroll();\r\n this.dialogElement.showModal();\r\n\r\n requestAnimationFrame(() => {\r\n this._animateOpen();\r\n });\r\n } else if (!this.open && previousOpen) {\r\n this._isClosing = true;\r\n this._animateClose();\r\n }\r\n }\r\n\r\n /** @private */\r\n private _lockScroll(): void {\r\n if (typeof window === \"undefined\" || typeof document === \"undefined\") return;\r\n if (_dialogOpenCount === 0) {\r\n _savedScrollY = window.scrollY;\r\n window.scrollTo(0, 0);\r\n }\r\n _dialogOpenCount++;\r\n document.documentElement.setAttribute(\"data-sky-dialog-open\", \"true\");\r\n }\r\n\r\n /** @private */\r\n private _unlockScroll(): void {\r\n if (typeof window === \"undefined\" || typeof document === \"undefined\") return;\r\n _dialogOpenCount = Math.max(0, _dialogOpenCount - 1);\r\n if (_dialogOpenCount === 0) {\r\n document.documentElement.removeAttribute(\"data-sky-dialog-open\");\r\n window.scrollTo(0, _savedScrollY);\r\n }\r\n }\r\n\r\n /** @private */\r\n private _prefersReducedMotion(): boolean {\r\n if (typeof window === \"undefined\" || !window.matchMedia) return false;\r\n return window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches;\r\n }\r\n\r\n /** @private */\r\n private _animateOpen(): void {\r\n const dialog = this.dialogElement;\r\n if (!dialog) return;\r\n\r\n this._openAnimation?.cancel();\r\n this._closeAnimation?.cancel();\r\n\r\n const duration = this._prefersReducedMotion() ? 0 : 300;\r\n const animation = dialog.animate(\r\n [\r\n {\r\n opacity: 0,\r\n transform: \"scale(0.95)\",\r\n transformOrigin: \"center center\",\r\n },\r\n { opacity: 1, transform: \"scale(1)\", transformOrigin: \"center center\" },\r\n ],\r\n {\r\n duration,\r\n easing: \"ease-out\",\r\n fill: \"forwards\",\r\n },\r\n );\r\n\r\n animation.onfinish = () => {\r\n this.dispatchEvent(\r\n new CustomEvent(\"dialog-opened\", {\r\n bubbles: true,\r\n composed: true,\r\n }),\r\n );\r\n };\r\n\r\n this._openAnimation = animation;\r\n }\r\n\r\n /** @private */\r\n private _animateClose(): void {\r\n const dialog = this.dialogElement;\r\n if (!dialog) return;\r\n this._openAnimation?.cancel();\r\n this._closeAnimation?.cancel();\r\n\r\n const duration = this._prefersReducedMotion() ? 0 : 150;\r\n const animation = dialog.animate(\r\n [\r\n { opacity: 1, transform: \"scale(1)\", transformOrigin: \"center center\" },\r\n {\r\n opacity: 0,\r\n transform: \"scale(0.95)\",\r\n transformOrigin: \"center center\",\r\n },\r\n ],\r\n {\r\n duration,\r\n easing: \"ease-out\",\r\n fill: \"forwards\",\r\n },\r\n );\r\n\r\n animation.onfinish = () => {\r\n dialog.close();\r\n this._unlockScroll();\r\n this._isClosing = false;\r\n this.dispatchEvent(\r\n new CustomEvent(\"dialog-closed\", {\r\n bubbles: true,\r\n composed: true,\r\n }),\r\n );\r\n };\r\n\r\n this._closeAnimation = animation;\r\n }\r\n\r\n /** @private */\r\n private _handleCancel(event: Event): void {\r\n event.preventDefault();\r\n\r\n if (this.persistent || !this.closeOnEsc) {\r\n this._highlightDialog();\r\n return;\r\n }\r\n\r\n this._requestClose(\"escape\");\r\n }\r\n\r\n /** @private */\r\n private _highlightDialog(): void {\r\n if (!this.highlightOnOutsideClick) return;\r\n if (this._prefersReducedMotion()) return;\r\n\r\n const dialog = this.dialogElement;\r\n if (!dialog) return;\r\n\r\n this._highlightAnimation?.cancel();\r\n\r\n const animation = dialog.animate(\r\n [\r\n { transform: \"scale(1)\" },\r\n { transform: \"scale(1.05)\" },\r\n { transform: \"scale(1)\" },\r\n ],\r\n {\r\n duration: 300,\r\n easing: \"ease-in-out\",\r\n },\r\n );\r\n\r\n this._highlightAnimation = animation;\r\n }\r\n\r\n\r\n\r\n /** @private */\r\n private _requestClose(reason: SkyDialogRequestCloseDetail[\"reason\"]): void {\r\n if (this._isClosing) return;\r\n this.dispatchEvent(\r\n new CustomEvent<SkyDialogRequestCloseDetail>(\"request-close\", {\r\n detail: { reason },\r\n bubbles: true,\r\n composed: true,\r\n }),\r\n );\r\n }\r\n\r\n /**\r\n * Checks if a slot has content.\r\n * @param slot - Slot element to check\r\n * @returns True if slot has content\r\n * @private\r\n */\r\n private _slotHasContent(slot: HTMLSlotElement): boolean {\r\n const nodes = slot.assignedNodes({ flatten: true });\r\n return nodes.some((n) => {\r\n if (n.nodeType === Node.TEXT_NODE) {\r\n return !!n.textContent?.trim();\r\n }\r\n return true;\r\n });\r\n }\r\n\r\n /** @private */\r\n private _onHeaderSlotChange = (e: Event): void => {\r\n const slot = e.target as HTMLSlotElement;\r\n this._hasHeader = this._slotHasContent(slot);\r\n };\r\n\r\n /** @private */\r\n private _onBodySlotChange = (e: Event): void => {\r\n const slot = e.target as HTMLSlotElement;\r\n this._hasBody = this._slotHasContent(slot);\r\n };\r\n\r\n /** @private */\r\n private _onFooterSlotChange = (e: Event): void => {\r\n const slot = e.target as HTMLSlotElement;\r\n this._hasFooter = this._slotHasContent(slot);\r\n };\r\n\r\n /** @private */\r\n private _onKeyDown = (e: KeyboardEvent): void => {\r\n if (e.key !== \"Escape\") return;\r\n\r\n // Always stop native <dialog> ESC behavior\r\n e.preventDefault();\r\n e.stopPropagation();\r\n // If persistent OR closeOnEsc is false → do NOT close, just highlight\r\n if (this.persistent || !this.closeOnEsc) {\r\n this._highlightDialog();\r\n return;\r\n }\r\n\r\n // Allowed to close via ESC\r\n this._requestClose(\"escape\");\r\n };\r\n\r\n /** @protected */\r\n override render() {\r\n const valid: Record<SkyDialogPadding, true> = {\r\n none: true,\r\n xs: true,\r\n sm: true,\r\n md: true,\r\n lg: true,\r\n xl: true,\r\n };\r\n\r\n const hp = valid[this.headerPadding] ? this.headerPadding : \"md\";\r\n const bp = valid[this.bodyPadding] ? this.bodyPadding : \"md\";\r\n const fp = valid[this.footerPadding] ? this.footerPadding : \"md\";\r\n\r\n const headerClasses: Record<string, boolean> = {};\r\n if (this._hasHeader) {\r\n headerClasses[`header-padding-${hp}`] = true;\r\n if (this.separator) {\r\n headerClasses[\"header-separator\"] = true;\r\n }\r\n }\r\n\r\n const footerClasses: Record<string, boolean> = {};\r\n if (this._hasFooter) {\r\n footerClasses[\"actions\"] = true;\r\n footerClasses[`footer-padding-${fp}`] = true;\r\n if (this.separator) {\r\n footerClasses[\"footer-separator\"] = true;\r\n }\r\n } else {\r\n footerClasses[\"actions\"] = true;\r\n }\r\n\r\n return html`\r\n <dialog\r\n part=\"dialog\"\r\n aria-modal=\"true\"\r\n style=\"max-width: ${this.width};\"\r\n @cancel=\"${this._handleCancel}\"\r\n ${ref(this.dialogRef)}\r\n ${animate({\r\n keyframeOptions: {\r\n duration: 300,\r\n easing: \"ease-out\",\r\n },\r\n })}\r\n >\r\n <slot></slot>\r\n\r\n ${when(this.message, () => html`\r\n <p class=\"message\" part=\"message\">${this.message}</p>\r\n `)}\r\n\r\n <div class=${classMap(headerClasses)} part=\"header\">\r\n <slot name=\"header\" @slotchange=${this._onHeaderSlotChange}></slot>\r\n </div>\r\n\r\n <div\r\n class=${classMap({\r\n [`body-padding-${bp}`]: this._hasBody,\r\n })}\r\n part=\"content\"\r\n >\r\n <slot name=\"body\" @slotchange=${this._onBodySlotChange}></slot>\r\n </div>\r\n\r\n <div class=${classMap(footerClasses)} part=\"actions footer\">\r\n <slot name=\"footer\" @slotchange=${this._onFooterSlotChange}></slot>\r\n </div>\r\n ${when(this.closable, () => html`\r\n <button\r\n class=\"close-button\"\r\n part=\"close-button\"\r\n type=\"button\"\r\n aria-label=\"Close dialog\"\r\n @click=${() => this._requestClose(\"close-button\")}\r\n >\r\n <sky-icon icon=\"ion:close\"></sky-icon>\r\n </button>\r\n `)}\r\n </dialog>\r\n `;\r\n }\r\n}\r\n"],"names":["_dialogOpenCount","_savedScrollY","SkyDialog","LitElement","constructor","super","this","open","closable","message","overlay","width","separator","persistent","closeOnEsc","headerPadding","bodyPadding","footerPadding","highlightOnOutsideClick","_hasHeader","_hasBody","_hasFooter","_isClosing","_openAnimation","_closeAnimation","_highlightAnimation","dialogRef","createRef","_onBackdropPointerDown","event","dialog","dialogElement","target","_highlightDialog","_requestClose","preset","_presets","PresetController","_onNativeClose","requestAnimationFrame","showModal","_onHeaderSlotChange","e","slot","_slotHasContent","_onBodySlotChange","_onFooterSlotChange","_onKeyDown","key","preventDefault","stopPropagation","_handleCancel","bind","firstUpdated","d","addEventListener","capture","disconnectedCallback","removeEventListener","_unlockScroll","close","show","hide","focusDialog","focus","getDialogElement","updated","changedProps","has","_handleOpenChange","get","previousOpen","_lockScroll","_animateOpen","_animateClose","window","document","scrollY","scrollTo","documentElement","setAttribute","Math","max","removeAttribute","_prefersReducedMotion","matchMedia","matches","cancel","duration","animation","animate","opacity","transform","transformOrigin","easing","fill","onfinish","dispatchEvent","CustomEvent","bubbles","composed","reason","detail","assignedNodes","flatten","some","n","nodeType","Node","TEXT_NODE","textContent","trim","render","valid","none","xs","sm","md","lg","xl","hp","bp","fp","headerClasses","footerClasses","html","ref","keyframeOptions","when","classMap","dependencies","SkyIcon","styles","css","__decorateClass","property","type","Boolean","reflect","prototype","String","state","query","customElement"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sky-divider.js","sources":["../../src/sky-divider/sky-divider.ts"],"sourcesContent":["import { LitElement, html, css } from \"lit\";\r\nimport { customElement, property } from \"lit/decorators.js\";\r\nimport { when } from \"lit/directives/when.js\";\r\nimport { classMap } from \"lit/directives/class-map.js\";\r\nimport { resolveColor } from \"../helper/utils/color-resolver\";\r\nimport { PresetController } from \"../helper/controllers/preset-controller\";\n\r\nexport type SkyDividerDirection = \"horizontal\" | \"vertical\";\r\n\r\n/**\r\n * @element sky-divider\r\n *\r\n * @summary Visual separator component for horizontal and vertical layout separation.\r\n *\r\n * @status stable\r\n * @since 1.0.0\r\n *\r\n * @documentation https://sky-ui.com/components/divider\r\n *\r\n * @csspart divider - The divider line element (either `<hr>` or `<div>` depending on direction).\r\n *\r\n * @property {string} color - Divider color token or CSS color.\r\n * @property {string} thickness - Divider thickness (for example `1px` or `2px`).\r\n * @property {string} margin - Outer margin around the divider.\r\n * @property {SkyDividerDirection} direction - Divider orientation.\r\n * @property {boolean} inset - Enables indented divider layout.\r\n * @property {string} height - Height used for vertical orientation.\r\n * @property {string} preset - Named prop preset from nearest `sky-config-provider`. Default: `\"\"`.\n * @method getComputedColor Returns the resolved runtime divider color.\r\n * @method getComputedThickness Returns the resolved runtime divider thickness.\r\n *\r\n * @cssprop --divider-color - CSS custom property for divider color.\r\n * @cssprop --divider-thickness - CSS custom property for divider thickness.\r\n * @cssprop --divider-margin - CSS custom property for divider margin.\r\n * @cssprop --divider-height - CSS custom property for vertical divider height.\r\n *\r\n * @Behavior\r\n * - Simple visual divider that can be horizontal or vertical\r\n * - Supports extensive customization via properties\r\n * - Automatically resolves color values using color resolver\r\n * - Updates CSS custom properties when properties change\r\n * - **horizontal**: Renders as `<hr>` element, spans full width\r\n * - **vertical**: Renders as `<div>` element, spans configurable height\r\n * - Horizontal dividers use semantic `<hr>` element\r\n * - Vertical dividers use `<div>` with appropriate styling\r\n *\r\n * @example\r\n * ```html\r\n * <div style=\"display: flex; align-items: center;\">\r\n * <span>Left content</span>\r\n * <sky-divider\r\n * direction=\"vertical\"\r\n * height=\"50px\"\r\n * margin=\"0 16px\"\r\n * ></sky-divider>\r\n * <span>Right content</span>\r\n * </div>\r\n * ```\r\n * ```vue\r\n * <template>\r\n * <div style=\"display:flex;align-items:center;\">\r\n * <span>Left content</span>\r\n * <sky-divider direction=\"vertical\" height=\"50px\" margin=\"0 16px\"></sky-divider>\r\n * <span>Right content</span>\r\n * </div>\r\n * </template>\r\n * ```\r\n * ```jsx\r\n * export default function Demo() {\r\n * return (\r\n * <div style={{ display: \"flex\", alignItems: \"center\" }}>\r\n * <span>Left content</span>\r\n * <sky-divider direction=\"vertical\" height=\"50px\" margin=\"0 16px\"></sky-divider>\r\n * <span>Right content</span>\r\n * </div>\r\n * );\r\n * }\r\n * ```\r\n */\r\n@customElement(\"sky-divider\")\r\nexport class SkyDivider extends LitElement {\r\n /**\r\n * The color of the divider.\r\n * @public\r\n */\r\n @property({ type: String })\r\n color = \"muted\";\r\n\r\n /**\r\n * The thickness of the divider (e.g., `\"1px\"`, `\"2px\"`).\r\n * @public\r\n */\r\n @property({ type: String })\r\n thickness = \"1px\";\r\n\r\n /**\r\n * The margin around the divider.\r\n * @public\r\n */\r\n @property({ type: String })\r\n margin = \"\";\r\n\r\n /**\r\n * Divider orientation.\r\n * @public\r\n */\r\n @property({ type: String })\r\n direction: SkyDividerDirection = \"horizontal\";\r\n\r\n /**\r\n * Whether the divider should be inset (indented).\r\n * @public\r\n */\r\n @property({ type: Boolean })\r\n inset = false;\r\n\r\n /**\r\n * The height of a vertical divider.\r\n * @public\r\n */\r\n @property({ type: String })\r\n height = \"100%\";\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 hr {\r\n border: none;\r\n border-top: var(--divider-thickness, 2px) solid var(--divider-color);\r\n margin: var(--divider-margin);\r\n }\r\n\r\n .vertical {\r\n border-top: none;\r\n border-left: var(--divider-thickness, 2px) solid var(--divider-color);\r\n height: var(--divider-height, 100%);\r\n width: 0 !important;\r\n margin: var(--divider-margin);\r\n }\r\n\r\n .inset.horizontal {\r\n margin-left: 20px;\r\n margin-right: 20px;\r\n width: calc(100% - 20px * 2);\r\n }\r\n\r\n .inset.vertical {\r\n margin-top: 20px;\r\n margin-bottom: 20px;\r\n height: calc(100% - 20px * 2);\r\n }\r\n `;\r\n\r\n /** @protected */\r\n override updated(changedProperties: Map<string, unknown>): void {\r\n if (changedProperties.has(\"color\")) {\r\n this.style.setProperty(\"--divider-color\", resolveColor(this.color));\r\n }\r\n if (changedProperties.has(\"thickness\")) {\r\n this.style.setProperty(\"--divider-thickness\", this.thickness);\r\n }\r\n if (changedProperties.has(\"margin\")) {\r\n this.style.setProperty(\"--divider-margin\", this.margin);\r\n }\r\n if (changedProperties.has(\"height\")) {\r\n this.style.setProperty(\"--divider-height\", this.height);\r\n }\r\n }\r\n\r\n /**\r\n * Gets the current computed color of the divider.\r\n * @returns Resolved color value\r\n * @public\r\n */\r\n public getComputedColor(): string {\r\n return (\r\n getComputedStyle(this).getPropertyValue(\"--divider-color\").trim() ||\r\n this.color\r\n );\r\n }\r\n\r\n /**\r\n * Gets the current computed thickness of the divider.\r\n * @returns Resolved thickness value\r\n * @public\r\n */\r\n public getComputedThickness(): string {\r\n return (\r\n getComputedStyle(this).getPropertyValue(\"--divider-thickness\").trim() ||\r\n this.thickness\r\n );\r\n }\r\n\r\n /** @protected */\r\n override render() {\r\n const isVertical = this.direction === \"vertical\";\r\n const verticalClasses = classMap({\r\n vertical: true,\r\n inset: this.inset,\r\n });\r\n const horizontalClasses = classMap({\r\n horizontal: true,\r\n inset: this.inset,\r\n });\r\n\r\n return when(\r\n isVertical,\r\n () => html`\r\n <div\r\n class=${verticalClasses}\r\n part=\"divider\"\r\n role=\"separator\"\r\n aria-orientation=\"vertical\"\r\n ></div>\r\n `,\r\n () => html`\r\n <hr\r\n class=${horizontalClasses}\r\n part=\"divider\"\r\n role=\"separator\"\r\n aria-orientation=\"horizontal\"\r\n />\r\n `,\r\n );\r\n }\r\n}\r\n"],"names":["SkyDivider","LitElement","constructor","super","arguments","this","color","thickness","margin","direction","inset","height","preset","_presets","PresetController","updated","changedProperties","has","style","setProperty","resolveColor","getComputedColor","getComputedStyle","getPropertyValue","trim","getComputedThickness","render","isVertical","verticalClasses","classMap","vertical","horizontalClasses","horizontal","when","html","styles","css","__decorateClass","property","type","String","prototype","Boolean","reflect","customElement"],"mappings":"wiBAgFO,IAAMA,EAAN,cAAyBC,EAAzB,WAAAC,GAAAC,SAAAC,WAMLC,KAAAC,MAAQ,QAORD,KAAAE,UAAY,MAOZF,KAAAG,OAAS,GAOTH,KAAAI,UAAiC,aAOjCJ,KAAAK,OAAQ,EAORL,KAAAM,OAAS,OAIkCN,KAAAO,OAAS,GAEpDP,KAAQQ,SAAW,IAAIC,EAAiBT,KAAI,CA+BnC,OAAAU,CAAQC,GACXA,EAAkBC,IAAI,UACxBZ,KAAKa,MAAMC,YAAY,kBAAmBC,EAAaf,KAAKC,QAE1DU,EAAkBC,IAAI,cACxBZ,KAAKa,MAAMC,YAAY,sBAAuBd,KAAKE,WAEjDS,EAAkBC,IAAI,WACxBZ,KAAKa,MAAMC,YAAY,mBAAoBd,KAAKG,QAE9CQ,EAAkBC,IAAI,WACxBZ,KAAKa,MAAMC,YAAY,mBAAoBd,KAAKM,OAEpD,CAOO,gBAAAU,GACL,OACEC,iBAAiBjB,MAAMkB,iBAAiB,mBAAmBC,QAC3DnB,KAAKC,KAET,CAOO,oBAAAmB,GACL,OACEH,iBAAiBjB,MAAMkB,iBAAiB,uBAAuBC,QAC/DnB,KAAKE,SAET,CAGS,MAAAmB,GACP,MAAMC,EAAgC,aAAnBtB,KAAKI,UAClBmB,EAAkBC,EAAS,CAC/BC,UAAU,EACVpB,MAAOL,KAAKK,QAERqB,EAAoBF,EAAS,CACjCG,YAAY,EACZtB,MAAOL,KAAKK,QAGd,OAAOuB,EACLN,EACA,IAAMO,CAAA;;kBAEMN;;;;;QAMZ,IAAMM,CAAA;;kBAEMH;;;;;QAOhB,GApJW/B,EAiDKmC,OAASC,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;IA3CzBC,EAAA,CADCC,EAAS,CAAEC,KAAMC,UALPxC,EAMXyC,UAAA,QAAA,GAOAJ,EAAA,CADCC,EAAS,CAAEC,KAAMC,UAZPxC,EAaXyC,UAAA,YAAA,GAOAJ,EAAA,CADCC,EAAS,CAAEC,KAAMC,UAnBPxC,EAoBXyC,UAAA,SAAA,GAOAJ,EAAA,CADCC,EAAS,CAAEC,KAAMC,UA1BPxC,EA2BXyC,UAAA,YAAA,GAOAJ,EAAA,CADCC,EAAS,CAAEC,KAAMG,WAjCP1C,EAkCXyC,UAAA,QAAA,GAOAJ,EAAA,CADCC,EAAS,CAAEC,KAAMC,UAxCPxC,EAyCXyC,UAAA,SAAA,GAI2CJ,EAAA,CAA1CC,EAAS,CAAEC,KAAMC,OAAQG,SAAS,KA7CxB3C,EA6CgCyC,UAAA,SAAA,GA7ChCzC,EAANqC,EAAA,CADNO,EAAc,gBACF5C"}
|
|
1
|
+
{"version":3,"file":"sky-divider.js","sources":["../../src/sky-divider/sky-divider.ts"],"sourcesContent":["import { LitElement, html, css } from \"lit\";\r\nimport { customElement, property } from \"lit/decorators.js\";\r\nimport { when } from \"lit/directives/when.js\";\r\nimport { classMap } from \"lit/directives/class-map.js\";\r\nimport { resolveColor } from \"../helper/utils/color-resolver\";\r\nimport { PresetController } from \"../helper/controllers/preset-controller\";\r\n\r\nexport type SkyDividerDirection = \"horizontal\" | \"vertical\";\r\n\r\n/**\r\n * @element sky-divider\r\n *\r\n * @summary Visual separator component for horizontal and vertical layout separation.\r\n *\r\n * @status stable\r\n * @since 1.0.0\r\n *\r\n * @documentation https://sky-ui.com/components/divider\r\n *\r\n * @csspart divider - The divider line element (either `<hr>` or `<div>` depending on direction).\r\n *\r\n * @property {string} color - Divider color token or CSS color.\r\n * @property {string} thickness - Divider thickness (for example `1px` or `2px`).\r\n * @property {string} margin - Outer margin around the divider.\r\n * @property {SkyDividerDirection} direction - Divider orientation.\r\n * @property {boolean} inset - Enables indented divider layout.\r\n * @property {string} height - Height used for vertical orientation.\r\n * @property {string} preset - Named prop preset from nearest `sky-config-provider`. Default: `\"\"`.\r\n * @method getComputedColor Returns the resolved runtime divider color.\r\n * @method getComputedThickness Returns the resolved runtime divider thickness.\r\n *\r\n * @cssprop --divider-color - CSS custom property for divider color.\r\n * @cssprop --divider-thickness - CSS custom property for divider thickness.\r\n * @cssprop --divider-margin - CSS custom property for divider margin.\r\n * @cssprop --divider-height - CSS custom property for vertical divider height.\r\n *\r\n * @Behavior\r\n * - Simple visual divider that can be horizontal or vertical\r\n * - Supports extensive customization via properties\r\n * - Automatically resolves color values using color resolver\r\n * - Updates CSS custom properties when properties change\r\n * - **horizontal**: Renders as `<hr>` element, spans full width\r\n * - **vertical**: Renders as `<div>` element, spans configurable height\r\n * - Horizontal dividers use semantic `<hr>` element\r\n * - Vertical dividers use `<div>` with appropriate styling\r\n *\r\n * @example\r\n * ```html\r\n * <div style=\"display: flex; align-items: center;\">\r\n * <span>Left content</span>\r\n * <sky-divider\r\n * direction=\"vertical\"\r\n * height=\"50px\"\r\n * margin=\"0 16px\"\r\n * ></sky-divider>\r\n * <span>Right content</span>\r\n * </div>\r\n * ```\r\n * ```vue\r\n * <template>\r\n * <div style=\"display:flex;align-items:center;\">\r\n * <span>Left content</span>\r\n * <sky-divider direction=\"vertical\" height=\"50px\" margin=\"0 16px\"></sky-divider>\r\n * <span>Right content</span>\r\n * </div>\r\n * </template>\r\n * ```\r\n * ```jsx\r\n * export default function Demo() {\r\n * return (\r\n * <div style={{ display: \"flex\", alignItems: \"center\" }}>\r\n * <span>Left content</span>\r\n * <sky-divider direction=\"vertical\" height=\"50px\" margin=\"0 16px\"></sky-divider>\r\n * <span>Right content</span>\r\n * </div>\r\n * );\r\n * }\r\n * ```\r\n */\r\n@customElement(\"sky-divider\")\r\nexport class SkyDivider extends LitElement {\r\n /**\r\n * The color of the divider.\r\n * @public\r\n */\r\n @property({ type: String })\r\n color = \"muted\";\r\n\r\n /**\r\n * The thickness of the divider (e.g., `\"1px\"`, `\"2px\"`).\r\n * @public\r\n */\r\n @property({ type: String })\r\n thickness = \"1px\";\r\n\r\n /**\r\n * The margin around the divider.\r\n * @public\r\n */\r\n @property({ type: String })\r\n margin = \"\";\r\n\r\n /**\r\n * Divider orientation.\r\n * @public\r\n */\r\n @property({ type: String })\r\n direction: SkyDividerDirection = \"horizontal\";\r\n\r\n /**\r\n * Whether the divider should be inset (indented).\r\n * @public\r\n */\r\n @property({ type: Boolean })\r\n inset = false;\r\n\r\n /**\r\n * The height of a vertical divider.\r\n * @public\r\n */\r\n @property({ type: String })\r\n height = \"100%\";\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 hr {\r\n border: none;\r\n border-top: var(--divider-thickness, 2px) solid var(--divider-color);\r\n margin: var(--divider-margin);\r\n }\r\n\r\n .vertical {\r\n border-top: none;\r\n border-left: var(--divider-thickness, 2px) solid var(--divider-color);\r\n height: var(--divider-height, 100%);\r\n width: 0 !important;\r\n margin: var(--divider-margin);\r\n }\r\n\r\n .inset.horizontal {\r\n margin-left: 20px;\r\n margin-right: 20px;\r\n width: calc(100% - 20px * 2);\r\n }\r\n\r\n .inset.vertical {\r\n margin-top: 20px;\r\n margin-bottom: 20px;\r\n height: calc(100% - 20px * 2);\r\n }\r\n `;\r\n\r\n /** @protected */\r\n override updated(changedProperties: Map<string, unknown>): void {\r\n if (changedProperties.has(\"color\")) {\r\n this.style.setProperty(\"--divider-color\", resolveColor(this.color));\r\n }\r\n if (changedProperties.has(\"thickness\")) {\r\n this.style.setProperty(\"--divider-thickness\", this.thickness);\r\n }\r\n if (changedProperties.has(\"margin\")) {\r\n this.style.setProperty(\"--divider-margin\", this.margin);\r\n }\r\n if (changedProperties.has(\"height\")) {\r\n this.style.setProperty(\"--divider-height\", this.height);\r\n }\r\n }\r\n\r\n /**\r\n * Gets the current computed color of the divider.\r\n * @returns Resolved color value\r\n * @public\r\n */\r\n public getComputedColor(): string {\r\n return (\r\n getComputedStyle(this).getPropertyValue(\"--divider-color\").trim() ||\r\n this.color\r\n );\r\n }\r\n\r\n /**\r\n * Gets the current computed thickness of the divider.\r\n * @returns Resolved thickness value\r\n * @public\r\n */\r\n public getComputedThickness(): string {\r\n return (\r\n getComputedStyle(this).getPropertyValue(\"--divider-thickness\").trim() ||\r\n this.thickness\r\n );\r\n }\r\n\r\n /** @protected */\r\n override render() {\r\n const isVertical = this.direction === \"vertical\";\r\n const verticalClasses = classMap({\r\n vertical: true,\r\n inset: this.inset,\r\n });\r\n const horizontalClasses = classMap({\r\n horizontal: true,\r\n inset: this.inset,\r\n });\r\n\r\n return when(\r\n isVertical,\r\n () => html`\r\n <div\r\n class=${verticalClasses}\r\n part=\"divider\"\r\n role=\"separator\"\r\n aria-orientation=\"vertical\"\r\n ></div>\r\n `,\r\n () => html`\r\n <hr\r\n class=${horizontalClasses}\r\n part=\"divider\"\r\n role=\"separator\"\r\n aria-orientation=\"horizontal\"\r\n />\r\n `,\r\n );\r\n }\r\n}\r\n"],"names":["SkyDivider","LitElement","constructor","super","arguments","this","color","thickness","margin","direction","inset","height","preset","_presets","PresetController","updated","changedProperties","has","style","setProperty","resolveColor","getComputedColor","getComputedStyle","getPropertyValue","trim","getComputedThickness","render","isVertical","verticalClasses","classMap","vertical","horizontalClasses","horizontal","when","html","styles","css","__decorateClass","property","type","String","prototype","Boolean","reflect","customElement"],"mappings":"wiBAgFO,IAAMA,EAAN,cAAyBC,EAAzB,WAAAC,GAAAC,SAAAC,WAMLC,KAAAC,MAAQ,QAORD,KAAAE,UAAY,MAOZF,KAAAG,OAAS,GAOTH,KAAAI,UAAiC,aAOjCJ,KAAAK,OAAQ,EAORL,KAAAM,OAAS,OAIkCN,KAAAO,OAAS,GAEpDP,KAAQQ,SAAW,IAAIC,EAAiBT,KAAI,CA+BnC,OAAAU,CAAQC,GACXA,EAAkBC,IAAI,UACxBZ,KAAKa,MAAMC,YAAY,kBAAmBC,EAAaf,KAAKC,QAE1DU,EAAkBC,IAAI,cACxBZ,KAAKa,MAAMC,YAAY,sBAAuBd,KAAKE,WAEjDS,EAAkBC,IAAI,WACxBZ,KAAKa,MAAMC,YAAY,mBAAoBd,KAAKG,QAE9CQ,EAAkBC,IAAI,WACxBZ,KAAKa,MAAMC,YAAY,mBAAoBd,KAAKM,OAEpD,CAOO,gBAAAU,GACL,OACEC,iBAAiBjB,MAAMkB,iBAAiB,mBAAmBC,QAC3DnB,KAAKC,KAET,CAOO,oBAAAmB,GACL,OACEH,iBAAiBjB,MAAMkB,iBAAiB,uBAAuBC,QAC/DnB,KAAKE,SAET,CAGS,MAAAmB,GACP,MAAMC,EAAgC,aAAnBtB,KAAKI,UAClBmB,EAAkBC,EAAS,CAC/BC,UAAU,EACVpB,MAAOL,KAAKK,QAERqB,EAAoBF,EAAS,CACjCG,YAAY,EACZtB,MAAOL,KAAKK,QAGd,OAAOuB,EACLN,EACA,IAAMO,CAAA;;kBAEMN;;;;;QAMZ,IAAMM,CAAA;;kBAEMH;;;;;QAOhB,GApJW/B,EAiDKmC,OAASC,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;IA3CzBC,EAAA,CADCC,EAAS,CAAEC,KAAMC,UALPxC,EAMXyC,UAAA,QAAA,GAOAJ,EAAA,CADCC,EAAS,CAAEC,KAAMC,UAZPxC,EAaXyC,UAAA,YAAA,GAOAJ,EAAA,CADCC,EAAS,CAAEC,KAAMC,UAnBPxC,EAoBXyC,UAAA,SAAA,GAOAJ,EAAA,CADCC,EAAS,CAAEC,KAAMC,UA1BPxC,EA2BXyC,UAAA,YAAA,GAOAJ,EAAA,CADCC,EAAS,CAAEC,KAAMG,WAjCP1C,EAkCXyC,UAAA,QAAA,GAOAJ,EAAA,CADCC,EAAS,CAAEC,KAAMC,UAxCPxC,EAyCXyC,UAAA,SAAA,GAI2CJ,EAAA,CAA1CC,EAAS,CAAEC,KAAMC,OAAQG,SAAS,KA7CxB3C,EA6CgCyC,UAAA,SAAA,GA7ChCzC,EAANqC,EAAA,CADNO,EAAc,gBACF5C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sky-flexbox.js","sources":["../../src/sky-flexbox/sky-flexbox.ts"],"sourcesContent":["import { LitElement, html, css } from \"lit\";\r\nimport { customElement, property } from \"lit/decorators.js\";\r\nimport { PresetController } from \"../helper/controllers/preset-controller\";\n\r\nexport type SkyFlexboxDirection = \"row\" | \"row-reverse\" | \"column\" | \"column-reverse\";\r\nexport type SkyFlexboxWrap = \"nowrap\" | \"wrap\" | \"wrap-reverse\";\r\nexport type SkyFlexboxJustify =\r\n | \"flex-start\"\r\n | \"center\"\r\n | \"flex-end\"\r\n | \"space-between\"\r\n | \"space-around\"\r\n | \"space-evenly\";\r\nexport type SkyFlexboxAlign = \"stretch\" | \"flex-start\" | \"center\" | \"flex-end\" | \"baseline\";\r\nexport type SkyFlexboxAlignContent =\r\n | \"normal\"\r\n | \"stretch\"\r\n | \"center\"\r\n | \"start\"\r\n | \"end\"\r\n | \"flex-start\"\r\n | \"flex-end\"\r\n | \"space-between\"\r\n | \"space-around\"\r\n | \"space-evenly\";\r\n\r\n/**\r\n * @element sky-flexbox\r\n *\r\n * @summary Flexbox container with grid-like span support for slotted children.\r\n *\r\n * @status stable\r\n * @since 1.0.0\r\n *\r\n * @documentation https://sky-ui.com/components/flexbox\r\n *\r\n * @slot - Default slot for flex items (`<sky-flexcol>` or plain elements with `span` attributes).\r\n *\r\n * @property {SkyFlexboxDirection} direction - Flex direction.\r\n * @property {SkyFlexboxWrap} wrap - Flex wrap behavior.\r\n * @property {SkyFlexboxJustify} justify - Main-axis alignment.\r\n * @property {SkyFlexboxAlign} align - Cross-axis alignment.\r\n * @property {SkyFlexboxAlignContent} alignContent - Multi-line cross-axis distribution.\r\n * @property {string} gap - Shared row/column gap value.\r\n * @property {string | undefined} gapX - Horizontal gap override.\r\n * @property {string | undefined} gapY - Vertical gap override.\r\n * @property {number} col - Total column count used for span calculations.\r\n * @property {string} preset - Named prop preset from nearest `sky-config-provider`. Default: `\"\"`.\n *\r\n * @fires {Event} slotchange - Fired when slotted children change.\r\n * @method recalculateSpans Recomputes slotted child span CSS variables.\r\n *\r\n * @csspart container - The flex container element.\r\n *\r\n * @Behavior\r\n * - Implements CSS Flexbox with custom property-based configuration\r\n * - Supports responsive span calculations based on column grid system\r\n * - Automatically manages CSS custom properties for child elements\r\n * - Handles responsive breakpoints through span attributes\r\n *\r\n * - Uses a configurable column count (default: 12)\r\n * - Calculates item widths based on span values (1-col through total columns)\r\n * - Supports responsive spans: `span-lg`, `span-md`, `span-sm`, `span-xs`\r\n * - Clamps span values to valid range (1 to column count)\r\n *\r\n * - Supports unified `gap` property\r\n * - Optional `gapX` and `gapY` for separate horizontal/vertical spacing\r\n * - Gap values can use any CSS unit (px, rem, em, %, etc.)\r\n *\r\n * @example\r\n * ```html\r\n * <sky-flexbox col=\"12\" gap=\"16px\">\r\n * <sky-flexcol span=\"8\" span-md=\"12\">\r\n * Main content\r\n * </sky-flexcol>\r\n * <sky-flexcol span=\"4\" span-md=\"12\">\r\n * Sidebar\r\n * </sky-flexcol>\r\n * </sky-flexbox>\r\n * ```\r\n * ```vue\r\n * <template>\r\n * <sky-flexbox col=\"12\" gap=\"16px\">\r\n * <sky-flexcol span=\"8\" span-md=\"12\">Main content</sky-flexcol>\r\n * <sky-flexcol span=\"4\" span-md=\"12\">Sidebar</sky-flexcol>\r\n * </sky-flexbox>\r\n * </template>\r\n * ```\r\n * ```jsx\r\n * export default function Demo() {\r\n * return (\r\n * <sky-flexbox col=\"12\" gap=\"16px\">\r\n * <sky-flexcol span=\"8\" span-md=\"12\">Main content</sky-flexcol>\r\n * <sky-flexcol span=\"4\" span-md=\"12\">Sidebar</sky-flexcol>\r\n * </sky-flexbox>\r\n * );\r\n * }\r\n * ```\r\n */\r\n@customElement(\"sky-flexbox\")\r\nexport class SkyFlexbox extends LitElement {\r\n /**\r\n * Flex direction.\r\n * @public\r\n */\r\n @property({ type: String })\r\n direction: SkyFlexboxDirection = \"row\";\r\n\r\n /**\r\n * Wrap behavior.\r\n * @public\r\n */\r\n @property({ type: String })\r\n wrap: SkyFlexboxWrap = \"wrap\";\r\n\r\n /**\r\n * Main axis justification.\r\n * @public\r\n */\r\n @property({ type: String })\r\n justify: SkyFlexboxJustify = \"flex-start\";\r\n\r\n /**\r\n * Cross axis alignment.\r\n * @public\r\n */\r\n @property({ type: String })\r\n align: SkyFlexboxAlign = \"stretch\";\r\n\r\n /**\r\n * Multi-line alignment (when wrapping).\r\n * @public\r\n */\r\n @property({ type: String })\r\n alignContent: SkyFlexboxAlignContent = \"normal\";\r\n\r\n /**\r\n * Shorthand gap; used if gapX/gapY not provided.\r\n * @public\r\n */\r\n @property({ type: String }) gap: string = \"16px\";\r\n\r\n /**\r\n * Column gap.\r\n * @public\r\n */\r\n @property({ type: String })\r\n gapX?: string;\r\n\r\n /**\r\n * Row gap.\r\n * @public\r\n */\r\n @property({ type: String })\r\n gapY?: string;\r\n\r\n /**\r\n * Total columns used for span calculation.\r\n * @public\r\n */\r\n @property({ type: Number }) col: number = 12;\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: block;\r\n }\r\n\r\n .flex-container {\r\n display: flex;\r\n box-sizing: border-box;\r\n flex-wrap: var(--wrap, wrap);\r\n gap: var(--gap-y, var(--gap, 16px)) var(--gap-x, var(--gap, 16px));\r\n justify-content: var(--justify, flex-start);\r\n align-items: var(--align, stretch);\r\n align-content: var(--align-content, normal);\r\n flex-direction: var(--direction, row);\r\n }\r\n\r\n /* Default behaviour for any slotted child: */\r\n ::slotted(*) {\r\n box-sizing: border-box;\r\n min-width: 0;\r\n }\r\n\r\n .flex-container.is-row ::slotted(*) {\r\n flex-grow: 0;\r\n flex-shrink: 1;\r\n flex-basis: auto;\r\n max-width: none;\r\n }\r\n\r\n .flex-container.is-row ::slotted([data-flex-span]) {\r\n flex-shrink: 0;\r\n --span-current: var(--span, 1);\r\n --span-width: calc(\r\n 100% * var(--span-current) / var(--columns, 12) -\r\n var(--gap-x, var(--gap, 16px)) *\r\n (var(--columns, 12) - var(--span-current)) / var(--columns, 12)\r\n );\r\n\r\n flex-basis: var(--span-width);\r\n width: var(--span-width);\r\n max-width: var(--span-width);\r\n }\r\n\r\n .flex-container.is-column ::slotted(*) {\r\n width: 100%;\r\n flex-basis: auto;\r\n max-width: none;\r\n flex-shrink: 0;\r\n }\r\n\r\n @media (max-width: 1200px) {\r\n .flex-container.is-row ::slotted([data-flex-span]) {\r\n --span-current: var(--span-lg, var(--span-current));\r\n }\r\n }\r\n\r\n @media (max-width: 992px) {\r\n .flex-container.is-row ::slotted([data-flex-span]) {\r\n --span-current: var(--span-md, var(--span-current));\r\n }\r\n }\r\n\r\n @media (max-width: 768px) {\r\n .flex-container.is-row ::slotted([data-flex-span]) {\r\n --span-current: var(--span-sm, var(--span-current));\r\n }\r\n }\r\n\r\n @media (max-width: 576px) {\r\n .flex-container.is-row ::slotted([data-flex-span]) {\r\n --span-current: var(--span-xs, var(--span-current));\r\n }\r\n }\r\n `;\r\n\r\n /** @private */\r\n private _childMo?: MutationObserver;\r\n\r\n /** @protected */\r\n override connectedCallback() {\r\n super.connectedCallback();\r\n this._childMo = new MutationObserver(() => this.updateSpans());\r\n this._childMo.observe(this, {\r\n childList: true,\r\n subtree: true,\r\n attributes: true,\r\n attributeFilter: [\"span\", \"span-lg\", \"span-md\", \"span-sm\", \"span-xs\"],\r\n });\r\n }\r\n\r\n /** @protected */\r\n override disconnectedCallback() {\r\n super.disconnectedCallback();\r\n this._childMo?.disconnect();\r\n }\r\n\r\n /** @protected */\r\n override firstUpdated() {\r\n this.syncVars();\r\n this.updateSpans(); // initial\r\n }\r\n\r\n /** @protected */\r\n override updated(changed: Map<string | number | symbol, unknown>) {\r\n if (\r\n changed.has(\"wrap\") ||\r\n changed.has(\"gap\") ||\r\n changed.has(\"gapX\") ||\r\n changed.has(\"gapY\") ||\r\n changed.has(\"col\") ||\r\n changed.has(\"justify\") ||\r\n changed.has(\"direction\") ||\r\n changed.has(\"align\") ||\r\n changed.has(\"alignContent\")\r\n ) {\r\n this.syncVars();\r\n }\r\n if (changed.has(\"col\")) {\r\n this.updateSpans(); // re-validate span bounds when column count changes\r\n }\r\n }\r\n\r\n /**\r\n * Syncs component properties to CSS custom properties.\r\n * @private\r\n */\r\n private syncVars() {\r\n const styles = {\r\n \"--wrap\": this.wrap,\r\n \"--gap\": this.gap,\r\n \"--gap-x\": this.gapX ?? this.gap,\r\n \"--gap-y\": this.gapY ?? this.gap,\r\n \"--columns\": String(this.col),\r\n \"--justify\": this.justify,\r\n \"--direction\": this.direction,\r\n \"--align\": this.align,\r\n \"--align-content\": this.alignContent,\r\n } as Record<string, string>;\r\n Object.entries(styles).forEach(([k, v]) => this.style.setProperty(k, v));\r\n }\r\n\r\n /**\r\n * Forces recalculation of spans for all child elements.\r\n * Useful when dynamically adding/removing items.\r\n * @public\r\n */\r\n public recalculateSpans() {\r\n this.updateSpans();\r\n }\r\n\r\n /** @protected */\r\n override render() {\r\n const isColumn =\r\n this.direction === \"column\" || this.direction === \"column-reverse\";\r\n\r\n return html`\r\n <div\r\n class=\"flex-container ${isColumn ? \"is-column\" : \"is-row\"}\"\r\n part=\"container\"\r\n >\r\n <slot @slotchange=${this.updateSpans}></slot>\r\n </div>\r\n `;\r\n }\r\n\r\n /**\r\n * Reads span attributes off slotted children and maps them to CSS vars:\r\n * span, span-lg, span-md, span-sm, span-xs\r\n * @private\r\n */\r\n private updateSpans = () => {\r\n const nodes =\r\n this.shadowRoot\r\n ?.querySelector(\"slot\")\r\n ?.assignedElements({ flatten: true }) ?? [];\r\n for (const el of nodes) {\r\n if (!(el instanceof HTMLElement)) continue;\r\n\r\n this.applySpanVar(el, \"--span\", this.readSpanRaw(el, \"span\", \"span\"));\r\n this.applySpanVar(el, \"--span-lg\", this.readSpanRaw(el, \"span-lg\", \"spanLg\"));\r\n this.applySpanVar(el, \"--span-md\", this.readSpanRaw(el, \"span-md\", \"spanMd\"));\r\n this.applySpanVar(el, \"--span-sm\", this.readSpanRaw(el, \"span-sm\", \"spanSm\"));\r\n this.applySpanVar(el, \"--span-xs\", this.readSpanRaw(el, \"span-xs\", \"spanXs\"));\r\n\r\n const hasSpan =\r\n this.readSpanRaw(el, \"span\", \"span\") != null ||\r\n this.readSpanRaw(el, \"span-lg\", \"spanLg\") != null ||\r\n this.readSpanRaw(el, \"span-md\", \"spanMd\") != null ||\r\n this.readSpanRaw(el, \"span-sm\", \"spanSm\") != null ||\r\n this.readSpanRaw(el, \"span-xs\", \"spanXs\") != null;\r\n\r\n if (hasSpan) el.dataset.flexSpan = \"\";\r\n else delete el.dataset.flexSpan;\r\n }\r\n };\r\n\r\n /**\r\n * Reads a span value from an HTML attribute or element property.\r\n * @private\r\n */\r\n private readSpanRaw(\r\n el: HTMLElement,\r\n attrName: string,\r\n propName: string,\r\n ): string | null {\r\n const fromAttr = el.getAttribute(attrName);\r\n if (fromAttr != null && fromAttr !== \"\") return fromAttr;\r\n const fromProp = (el as unknown as Record<string, unknown>)[propName];\r\n if (fromProp != null && fromProp !== \"\") return String(fromProp);\r\n return null;\r\n }\r\n\r\n /**\r\n * Sets or clears a span CSS variable on a slotted child.\r\n * @private\r\n */\r\n private applySpanVar(\r\n el: HTMLElement,\r\n cssVar: string,\r\n raw: string | null,\r\n ): void {\r\n const value = this.clampSpan(raw);\r\n if (value) el.style.setProperty(cssVar, String(value));\r\n else el.style.removeProperty(cssVar);\r\n }\r\n\r\n /**\r\n * Clamps span value to valid range (1 to column count).\r\n * @param raw - Raw span value from attribute\r\n * @returns Clamped number or null if invalid\r\n * @private\r\n */\r\n private clampSpan(raw: string | null): number | null {\r\n if (!raw) return null;\r\n const n = Math.max(1, Math.min(this.col, Number(raw) || 1));\r\n return n;\r\n }\r\n}\r\n"],"names":["SkyFlexbox","LitElement","constructor","super","arguments","this","direction","wrap","justify","align","alignContent","gap","col","preset","_presets","PresetController","updateSpans","nodes","shadowRoot","querySelector","assignedElements","flatten","el","HTMLElement","applySpanVar","readSpanRaw","dataset","flexSpan","connectedCallback","_childMo","MutationObserver","observe","childList","subtree","attributes","attributeFilter","disconnectedCallback","disconnect","firstUpdated","syncVars","updated","changed","has","styles","gapX","gapY","String","Object","entries","forEach","k","v","style","setProperty","recalculateSpans","render","isColumn","html","attrName","propName","fromAttr","getAttribute","fromProp","cssVar","raw","value","clampSpan","removeProperty","Math","max","min","Number","css","__decorateClass","property","type","prototype","reflect","customElement"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sky-flexbox.js","sources":["../../src/sky-flexbox/sky-flexbox.ts"],"sourcesContent":["import { LitElement, html, css } from \"lit\";\r\nimport { customElement, property } from \"lit/decorators.js\";\r\nimport { PresetController } from \"../helper/controllers/preset-controller\";\r\n\r\nexport type SkyFlexboxDirection = \"row\" | \"row-reverse\" | \"column\" | \"column-reverse\";\r\nexport type SkyFlexboxWrap = \"nowrap\" | \"wrap\" | \"wrap-reverse\";\r\nexport type SkyFlexboxJustify =\r\n | \"flex-start\"\r\n | \"center\"\r\n | \"flex-end\"\r\n | \"space-between\"\r\n | \"space-around\"\r\n | \"space-evenly\";\r\nexport type SkyFlexboxAlign = \"stretch\" | \"flex-start\" | \"center\" | \"flex-end\" | \"baseline\";\r\nexport type SkyFlexboxAlignContent =\r\n | \"normal\"\r\n | \"stretch\"\r\n | \"center\"\r\n | \"start\"\r\n | \"end\"\r\n | \"flex-start\"\r\n | \"flex-end\"\r\n | \"space-between\"\r\n | \"space-around\"\r\n | \"space-evenly\";\r\n\r\n/**\r\n * @element sky-flexbox\r\n *\r\n * @summary Flexbox container with grid-like span support for slotted children.\r\n *\r\n * @status stable\r\n * @since 1.0.0\r\n *\r\n * @documentation https://sky-ui.com/components/flexbox\r\n *\r\n * @slot - Default slot for flex items (`<sky-flexcol>` or plain elements with `span` attributes).\r\n *\r\n * @property {SkyFlexboxDirection} direction - Flex direction.\r\n * @property {SkyFlexboxWrap} wrap - Flex wrap behavior.\r\n * @property {SkyFlexboxJustify} justify - Main-axis alignment.\r\n * @property {SkyFlexboxAlign} align - Cross-axis alignment.\r\n * @property {SkyFlexboxAlignContent} alignContent - Multi-line cross-axis distribution.\r\n * @property {string} gap - Shared row/column gap value.\r\n * @property {string | undefined} gapX - Horizontal gap override.\r\n * @property {string | undefined} gapY - Vertical gap override.\r\n * @property {number} col - Total column count used for span calculations.\r\n * @property {string} preset - Named prop preset from nearest `sky-config-provider`. Default: `\"\"`.\r\n *\r\n * @fires {Event} slotchange - Fired when slotted children change.\r\n * @method recalculateSpans Recomputes slotted child span CSS variables.\r\n *\r\n * @csspart container - The flex container element.\r\n *\r\n * @Behavior\r\n * - Implements CSS Flexbox with custom property-based configuration\r\n * - Supports responsive span calculations based on column grid system\r\n * - Automatically manages CSS custom properties for child elements\r\n * - Handles responsive breakpoints through span attributes\r\n *\r\n * - Uses a configurable column count (default: 12)\r\n * - Calculates item widths based on span values (1-col through total columns)\r\n * - Supports responsive spans: `span-lg`, `span-md`, `span-sm`, `span-xs`\r\n * - Clamps span values to valid range (1 to column count)\r\n *\r\n * - Supports unified `gap` property\r\n * - Optional `gapX` and `gapY` for separate horizontal/vertical spacing\r\n * - Gap values can use any CSS unit (px, rem, em, %, etc.)\r\n *\r\n * @example\r\n * ```html\r\n * <sky-flexbox col=\"12\" gap=\"16px\">\r\n * <sky-flexcol span=\"8\" span-md=\"12\">\r\n * Main content\r\n * </sky-flexcol>\r\n * <sky-flexcol span=\"4\" span-md=\"12\">\r\n * Sidebar\r\n * </sky-flexcol>\r\n * </sky-flexbox>\r\n * ```\r\n * ```vue\r\n * <template>\r\n * <sky-flexbox col=\"12\" gap=\"16px\">\r\n * <sky-flexcol span=\"8\" span-md=\"12\">Main content</sky-flexcol>\r\n * <sky-flexcol span=\"4\" span-md=\"12\">Sidebar</sky-flexcol>\r\n * </sky-flexbox>\r\n * </template>\r\n * ```\r\n * ```jsx\r\n * export default function Demo() {\r\n * return (\r\n * <sky-flexbox col=\"12\" gap=\"16px\">\r\n * <sky-flexcol span=\"8\" span-md=\"12\">Main content</sky-flexcol>\r\n * <sky-flexcol span=\"4\" span-md=\"12\">Sidebar</sky-flexcol>\r\n * </sky-flexbox>\r\n * );\r\n * }\r\n * ```\r\n */\r\n@customElement(\"sky-flexbox\")\r\nexport class SkyFlexbox extends LitElement {\r\n /**\r\n * Flex direction.\r\n * @public\r\n */\r\n @property({ type: String })\r\n direction: SkyFlexboxDirection = \"row\";\r\n\r\n /**\r\n * Wrap behavior.\r\n * @public\r\n */\r\n @property({ type: String })\r\n wrap: SkyFlexboxWrap = \"wrap\";\r\n\r\n /**\r\n * Main axis justification.\r\n * @public\r\n */\r\n @property({ type: String })\r\n justify: SkyFlexboxJustify = \"flex-start\";\r\n\r\n /**\r\n * Cross axis alignment.\r\n * @public\r\n */\r\n @property({ type: String })\r\n align: SkyFlexboxAlign = \"stretch\";\r\n\r\n /**\r\n * Multi-line alignment (when wrapping).\r\n * @public\r\n */\r\n @property({ type: String })\r\n alignContent: SkyFlexboxAlignContent = \"normal\";\r\n\r\n /**\r\n * Shorthand gap; used if gapX/gapY not provided.\r\n * @public\r\n */\r\n @property({ type: String }) gap: string = \"16px\";\r\n\r\n /**\r\n * Column gap.\r\n * @public\r\n */\r\n @property({ type: String })\r\n gapX?: string;\r\n\r\n /**\r\n * Row gap.\r\n * @public\r\n */\r\n @property({ type: String })\r\n gapY?: string;\r\n\r\n /**\r\n * Total columns used for span calculation.\r\n * @public\r\n */\r\n @property({ type: Number }) col: number = 12;\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: block;\r\n }\r\n\r\n .flex-container {\r\n display: flex;\r\n box-sizing: border-box;\r\n flex-wrap: var(--wrap, wrap);\r\n gap: var(--gap-y, var(--gap, 16px)) var(--gap-x, var(--gap, 16px));\r\n justify-content: var(--justify, flex-start);\r\n align-items: var(--align, stretch);\r\n align-content: var(--align-content, normal);\r\n flex-direction: var(--direction, row);\r\n }\r\n\r\n /* Default behaviour for any slotted child: */\r\n ::slotted(*) {\r\n box-sizing: border-box;\r\n min-width: 0;\r\n }\r\n\r\n .flex-container.is-row ::slotted(*) {\r\n flex-grow: 0;\r\n flex-shrink: 1;\r\n flex-basis: auto;\r\n max-width: none;\r\n }\r\n\r\n .flex-container.is-row ::slotted([data-flex-span]) {\r\n flex-shrink: 0;\r\n --span-current: var(--span, 1);\r\n --span-width: calc(\r\n 100% * var(--span-current) / var(--columns, 12) -\r\n var(--gap-x, var(--gap, 16px)) *\r\n (var(--columns, 12) - var(--span-current)) / var(--columns, 12)\r\n );\r\n\r\n flex-basis: var(--span-width);\r\n width: var(--span-width);\r\n max-width: var(--span-width);\r\n }\r\n\r\n .flex-container.is-column ::slotted(*) {\r\n width: 100%;\r\n flex-basis: auto;\r\n max-width: none;\r\n flex-shrink: 0;\r\n }\r\n\r\n @media (max-width: 1200px) {\r\n .flex-container.is-row ::slotted([data-flex-span]) {\r\n --span-current: var(--span-lg, var(--span-current));\r\n }\r\n }\r\n\r\n @media (max-width: 992px) {\r\n .flex-container.is-row ::slotted([data-flex-span]) {\r\n --span-current: var(--span-md, var(--span-current));\r\n }\r\n }\r\n\r\n @media (max-width: 768px) {\r\n .flex-container.is-row ::slotted([data-flex-span]) {\r\n --span-current: var(--span-sm, var(--span-current));\r\n }\r\n }\r\n\r\n @media (max-width: 576px) {\r\n .flex-container.is-row ::slotted([data-flex-span]) {\r\n --span-current: var(--span-xs, var(--span-current));\r\n }\r\n }\r\n `;\r\n\r\n /** @private */\r\n private _childMo?: MutationObserver;\r\n\r\n /** @protected */\r\n override connectedCallback() {\r\n super.connectedCallback();\r\n this._childMo = new MutationObserver(() => this.updateSpans());\r\n this._childMo.observe(this, {\r\n childList: true,\r\n subtree: true,\r\n attributes: true,\r\n attributeFilter: [\"span\", \"span-lg\", \"span-md\", \"span-sm\", \"span-xs\"],\r\n });\r\n }\r\n\r\n /** @protected */\r\n override disconnectedCallback() {\r\n super.disconnectedCallback();\r\n this._childMo?.disconnect();\r\n }\r\n\r\n /** @protected */\r\n override firstUpdated() {\r\n this.syncVars();\r\n this.updateSpans(); // initial\r\n }\r\n\r\n /** @protected */\r\n override updated(changed: Map<string | number | symbol, unknown>) {\r\n if (\r\n changed.has(\"wrap\") ||\r\n changed.has(\"gap\") ||\r\n changed.has(\"gapX\") ||\r\n changed.has(\"gapY\") ||\r\n changed.has(\"col\") ||\r\n changed.has(\"justify\") ||\r\n changed.has(\"direction\") ||\r\n changed.has(\"align\") ||\r\n changed.has(\"alignContent\")\r\n ) {\r\n this.syncVars();\r\n }\r\n if (changed.has(\"col\")) {\r\n this.updateSpans(); // re-validate span bounds when column count changes\r\n }\r\n }\r\n\r\n /**\r\n * Syncs component properties to CSS custom properties.\r\n * @private\r\n */\r\n private syncVars() {\r\n const styles = {\r\n \"--wrap\": this.wrap,\r\n \"--gap\": this.gap,\r\n \"--gap-x\": this.gapX ?? this.gap,\r\n \"--gap-y\": this.gapY ?? this.gap,\r\n \"--columns\": String(this.col),\r\n \"--justify\": this.justify,\r\n \"--direction\": this.direction,\r\n \"--align\": this.align,\r\n \"--align-content\": this.alignContent,\r\n } as Record<string, string>;\r\n Object.entries(styles).forEach(([k, v]) => this.style.setProperty(k, v));\r\n }\r\n\r\n /**\r\n * Forces recalculation of spans for all child elements.\r\n * Useful when dynamically adding/removing items.\r\n * @public\r\n */\r\n public recalculateSpans() {\r\n this.updateSpans();\r\n }\r\n\r\n /** @protected */\r\n override render() {\r\n const isColumn =\r\n this.direction === \"column\" || this.direction === \"column-reverse\";\r\n\r\n return html`\r\n <div\r\n class=\"flex-container ${isColumn ? \"is-column\" : \"is-row\"}\"\r\n part=\"container\"\r\n >\r\n <slot @slotchange=${this.updateSpans}></slot>\r\n </div>\r\n `;\r\n }\r\n\r\n /**\r\n * Reads span attributes off slotted children and maps them to CSS vars:\r\n * span, span-lg, span-md, span-sm, span-xs\r\n * @private\r\n */\r\n private updateSpans = () => {\r\n const nodes =\r\n this.shadowRoot\r\n ?.querySelector(\"slot\")\r\n ?.assignedElements({ flatten: true }) ?? [];\r\n for (const el of nodes) {\r\n if (!(el instanceof HTMLElement)) continue;\r\n\r\n this.applySpanVar(el, \"--span\", this.readSpanRaw(el, \"span\", \"span\"));\r\n this.applySpanVar(el, \"--span-lg\", this.readSpanRaw(el, \"span-lg\", \"spanLg\"));\r\n this.applySpanVar(el, \"--span-md\", this.readSpanRaw(el, \"span-md\", \"spanMd\"));\r\n this.applySpanVar(el, \"--span-sm\", this.readSpanRaw(el, \"span-sm\", \"spanSm\"));\r\n this.applySpanVar(el, \"--span-xs\", this.readSpanRaw(el, \"span-xs\", \"spanXs\"));\r\n\r\n const hasSpan =\r\n this.readSpanRaw(el, \"span\", \"span\") != null ||\r\n this.readSpanRaw(el, \"span-lg\", \"spanLg\") != null ||\r\n this.readSpanRaw(el, \"span-md\", \"spanMd\") != null ||\r\n this.readSpanRaw(el, \"span-sm\", \"spanSm\") != null ||\r\n this.readSpanRaw(el, \"span-xs\", \"spanXs\") != null;\r\n\r\n if (hasSpan) el.dataset.flexSpan = \"\";\r\n else delete el.dataset.flexSpan;\r\n }\r\n };\r\n\r\n /**\r\n * Reads a span value from an HTML attribute or element property.\r\n * @private\r\n */\r\n private readSpanRaw(\r\n el: HTMLElement,\r\n attrName: string,\r\n propName: string,\r\n ): string | null {\r\n const fromAttr = el.getAttribute(attrName);\r\n if (fromAttr != null && fromAttr !== \"\") return fromAttr;\r\n const fromProp = (el as unknown as Record<string, unknown>)[propName];\r\n if (fromProp != null && fromProp !== \"\") return String(fromProp);\r\n return null;\r\n }\r\n\r\n /**\r\n * Sets or clears a span CSS variable on a slotted child.\r\n * @private\r\n */\r\n private applySpanVar(\r\n el: HTMLElement,\r\n cssVar: string,\r\n raw: string | null,\r\n ): void {\r\n const value = this.clampSpan(raw);\r\n if (value) el.style.setProperty(cssVar, String(value));\r\n else el.style.removeProperty(cssVar);\r\n }\r\n\r\n /**\r\n * Clamps span value to valid range (1 to column count).\r\n * @param raw - Raw span value from attribute\r\n * @returns Clamped number or null if invalid\r\n * @private\r\n */\r\n private clampSpan(raw: string | null): number | null {\r\n if (!raw) return null;\r\n const n = Math.max(1, Math.min(this.col, Number(raw) || 1));\r\n return n;\r\n }\r\n}\r\n"],"names":["SkyFlexbox","LitElement","constructor","super","arguments","this","direction","wrap","justify","align","alignContent","gap","col","preset","_presets","PresetController","updateSpans","nodes","shadowRoot","querySelector","assignedElements","flatten","el","HTMLElement","applySpanVar","readSpanRaw","dataset","flexSpan","connectedCallback","_childMo","MutationObserver","observe","childList","subtree","attributes","attributeFilter","disconnectedCallback","disconnect","firstUpdated","syncVars","updated","changed","has","styles","gapX","gapY","String","Object","entries","forEach","k","v","style","setProperty","recalculateSpans","render","isColumn","html","attrName","propName","fromAttr","getAttribute","fromProp","cssVar","raw","value","clampSpan","removeProperty","Math","max","min","Number","css","__decorateClass","property","type","prototype","reflect","customElement"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sky-flexcol.js","sources":["../../src/sky-flexcol/sky-flexcol.ts"],"sourcesContent":["import { LitElement, html, css } from \"lit\";\r\nimport { customElement, property } from \"lit/decorators.js\";\r\nimport { PresetController } from \"../helper/controllers/preset-controller\";\n\r\nexport type SkyFlexcolAlignSelf =\r\n | \"auto\"\r\n | \"flex-start\"\r\n | \"center\"\r\n | \"flex-end\"\r\n | \"stretch\"\r\n | \"baseline\";\r\n\r\n/**\r\n * @element sky-flexcol\r\n *\r\n * @summary Flex column item for `sky-flexbox` layouts with responsive span controls.\r\n *\r\n * @status stable\r\n * @since 1.0.0\r\n *\r\n * @documentation https://sky-ui.com/components/flexbox\r\n *\r\n * @slot - Default slot for column content.\r\n *\r\n * @property {number} span - Base number of columns to span.\r\n * @property {number | undefined} spanLg - Span at large breakpoints.\r\n * @property {number | undefined} spanMd - Span at medium breakpoints.\r\n * @property {number | undefined} spanSm - Span at small breakpoints.\r\n * @property {number | undefined} spanXs - Span at extra-small breakpoints.\r\n * @property {number} grow - Flex grow factor.\r\n * @property {number} shrink - Flex shrink factor.\r\n * @property {string | null} basis - Flex basis override.\r\n * @property {number | undefined} order - Flex order override.\r\n * @property {SkyFlexcolAlignSelf | undefined} alignSelf - Cross-axis alignment override.\r\n * @property {string} preset - Named prop preset from nearest `sky-config-provider`. Default: `\"\"`.\n * @method refreshStyles Re-applies CSS custom properties from current values.\r\n * @method getSpan Returns current base span value.\r\n * @method setSpan Updates base span value and refreshes styles.\r\n *\r\n * @csspart col - The flex item wrapper.\r\n *\r\n * @Behavior\r\n * - Designed to work within `<sky-flexbox>` containers\r\n * - Supports responsive column spans with breakpoint attributes\r\n * - Exposes all standard flex item properties\r\n * - Automatically syncs properties to CSS custom properties\r\n *\r\n * - `span`: Base span across columns (1 to container's column count)\r\n * - `span-lg`: Span at large screens (≤1200px)\r\n * - `span-md`: Span at medium screens (≤992px)\r\n * - `span-sm`: Span at small screens (≤768px)\r\n * - `span-xs`: Span at extra-small screens (≤576px)\r\n *\r\n * @example\r\n * ```html\r\n * <sky-flexbox col=\"12\" gap=\"16px\">\r\n * <sky-flexcol span=\"8\">\r\n * <div class=\"card\">Main Content</div>\r\n * </sky-flexcol>\r\n * <sky-flexcol span=\"4\">\r\n * <div class=\"card\">Sidebar</div>\r\n * </sky-flexcol>\r\n * </sky-flexbox>\r\n * ```\r\n * ```vue\r\n * <template>\r\n * <sky-flexbox col=\"12\" gap=\"16px\">\r\n * <sky-flexcol span=\"8\" span-md=\"12\">Main Content</sky-flexcol>\r\n * <sky-flexcol span=\"4\" span-md=\"12\">Sidebar</sky-flexcol>\r\n * </sky-flexbox>\r\n * </template>\r\n * ```\r\n * ```jsx\r\n * export default function Demo() {\r\n * return (\r\n * <sky-flexbox col=\"12\" gap=\"16px\">\r\n * <sky-flexcol span=\"8\" span-md=\"12\">Main Content</sky-flexcol>\r\n * <sky-flexcol span=\"4\" span-md=\"12\">Sidebar</sky-flexcol>\r\n * </sky-flexbox>\r\n * );\r\n * }\r\n * ```\r\n */\r\n@customElement(\"sky-flexcol\")\r\nexport class SkyFlexcol extends LitElement {\r\n /**\r\n * Number of columns to span.\r\n * @public\r\n */\r\n @property({ type: Number })\r\n span = 1;\r\n\r\n /**\r\n * Columns spanned at large screens (≤1200px).\r\n * @public\r\n */\r\n @property({ type: Number })\r\n spanLg?: number;\r\n\r\n /**\r\n * Columns spanned at medium screens (≤992px).\r\n * @public\r\n */\r\n @property({ type: Number })\r\n spanMd?: number;\r\n\r\n /**\r\n * Columns spanned at small screens (≤768px).\r\n * @public\r\n */\r\n @property({ type: Number })\r\n spanSm?: number;\r\n\r\n /**\r\n * Columns spanned at extra-small screens (≤576px).\r\n * @public\r\n */\r\n @property({ type: Number })\r\n spanXs?: number;\r\n\r\n /**\r\n * Flex grow factor.\r\n * @public\r\n */\r\n @property({ type: Number })\r\n grow = 0;\r\n\r\n /**\r\n * Flex shrink factor.\r\n * @public\r\n */\r\n @property({ type: Number })\r\n shrink = 0;\r\n\r\n /**\r\n * Flex basis (e.g., `\"200px\"` or `\"auto\"`).\r\n * @public\r\n */\r\n @property({ type: String })\r\n basis: string | null = null;\r\n\r\n /**\r\n * Flex order relative to siblings.\r\n * @public\r\n */\r\n @property({ type: Number })\r\n order?: number;\r\n\r\n /**\r\n * Self alignment override.\r\n * @public\r\n */\r\n @property({ type: String })\r\n alignSelf?: SkyFlexcolAlignSelf;\r\n\r\nstatic override styles = css`\r\n :host {\r\n display: block;\r\n box-sizing: border-box;\r\n /* These are read by the container’s ::slotted(*) rules */\r\n flex-grow: var(--col-grow, 0);\r\n flex-shrink: var(--col-shrink, 0);\r\n order: var(--col-order, 0);\r\n align-self: var(--col-align-self, auto);\r\n /* If you set basis, it will override the basis calc coming from container's ::slotted(*) */\r\n flex-basis: var(--col-basis, auto);\r\n }\r\n `;\r\n\r\n /** @protected */\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 override firstUpdated() {\r\n this.syncVars();\r\n }\r\n\r\n /** @protected */\r\n override updated(changed: Map<string | number | symbol, unknown>) {\r\n if (\r\n changed.has(\"span\") ||\r\n changed.has(\"spanLg\") ||\r\n changed.has(\"spanMd\") ||\r\n changed.has(\"spanSm\") ||\r\n changed.has(\"spanXs\") ||\r\n changed.has(\"grow\") ||\r\n changed.has(\"shrink\") ||\r\n changed.has(\"basis\") ||\r\n changed.has(\"order\") ||\r\n changed.has(\"alignSelf\")\r\n ) {\r\n this.syncVars();\r\n }\r\n }\r\n\r\n /**\r\n * Syncs component properties to CSS custom properties.\r\n * @private\r\n */\r\n private syncVars() {\r\n // Span properties\r\n this.style.setProperty(\"--span\", String(this.span));\r\n if (this.spanLg) this.style.setProperty(\"--span-lg\", String(this.spanLg));\r\n if (this.spanMd) this.style.setProperty(\"--span-md\", String(this.spanMd));\r\n if (this.spanSm) this.style.setProperty(\"--span-sm\", String(this.spanSm));\r\n if (this.spanXs) this.style.setProperty(\"--span-xs\", String(this.spanXs));\r\n\r\n // Flex properties\r\n this.style.setProperty(\"--col-grow\", String(this.grow));\r\n this.style.setProperty(\"--col-shrink\", String(this.shrink));\r\n\r\n if (this.order != null) {\r\n this.style.setProperty(\"--col-order\", String(this.order));\r\n } else {\r\n this.style.removeProperty(\"--col-order\");\r\n }\r\n\r\n if (this.alignSelf) {\r\n this.style.setProperty(\"--col-align-self\", this.alignSelf);\r\n } else {\r\n this.style.removeProperty(\"--col-align-self\");\r\n }\r\n\r\n if (this.basis) {\r\n this.style.setProperty(\"--col-basis\", this.basis);\r\n } else {\r\n this.style.removeProperty(\"--col-basis\");\r\n }\r\n }\r\n\r\n /**\r\n * Forces resynchronization of CSS custom properties.\r\n * Useful when properties are changed programmatically.\r\n * @public\r\n */\r\n public refreshStyles() {\r\n this.syncVars();\r\n }\r\n\r\n /**\r\n * Gets the current span value.\r\n * @returns Current span value\r\n * @public\r\n */\r\n public getSpan(): number {\r\n return this.span;\r\n }\r\n\r\n /**\r\n * Sets the span value and updates styles.\r\n * @param value - New span value\r\n * @public\r\n */\r\n public setSpan(value: number): void {\r\n this.span = value;\r\n this.syncVars();\r\n }\r\n\r\n /** @protected */\r\n override render() {\r\n return html` <slot part=\"col\"></slot> `;\r\n }\r\n}\r\n"],"names":["SkyFlexcol","LitElement","constructor","super","arguments","this","span","grow","shrink","basis","preset","_presets","PresetController","firstUpdated","syncVars","updated","changed","has","style","setProperty","String","spanLg","spanMd","spanSm","spanXs","order","removeProperty","alignSelf","refreshStyles","getSpan","setSpan","value","render","html","styles","css","__decorateClass","property","type","Number","prototype","reflect","customElement"],"mappings":"kYAoFO,IAAMA,EAAN,cAAyBC,EAAzB,WAAAC,GAAAC,SAAAC,WAMLC,KAAAC,KAAO,EAmCPD,KAAAE,KAAO,EAOPF,KAAAG,OAAS,EAOTH,KAAAI,MAAuB,KAiCoBJ,KAAAK,OAAS,GAEpDL,KAAQM,SAAW,IAAIC,EAAiBP,KAAI,CAEnC,YAAAQ,GACPR,KAAKS,UACP,CAGS,OAAAC,CAAQC,IAEbA,EAAQC,IAAI,SACZD,EAAQC,IAAI,WACZD,EAAQC,IAAI,WACZD,EAAQC,IAAI,WACZD,EAAQC,IAAI,WACZD,EAAQC,IAAI,SACZD,EAAQC,IAAI,WACZD,EAAQC,IAAI,UACZD,EAAQC,IAAI,UACZD,EAAQC,IAAI,eAEZZ,KAAKS,UAET,CAMQ,QAAAA,GAENT,KAAKa,MAAMC,YAAY,SAAUC,OAAOf,KAAKC,OACzCD,KAAKgB,QAAQhB,KAAKa,MAAMC,YAAY,YAAaC,OAAOf,KAAKgB,SAC7DhB,KAAKiB,QAAQjB,KAAKa,MAAMC,YAAY,YAAaC,OAAOf,KAAKiB,SAC7DjB,KAAKkB,QAAQlB,KAAKa,MAAMC,YAAY,YAAaC,OAAOf,KAAKkB,SAC7DlB,KAAKmB,QAAQnB,KAAKa,MAAMC,YAAY,YAAaC,OAAOf,KAAKmB,SAGjEnB,KAAKa,MAAMC,YAAY,aAAcC,OAAOf,KAAKE,OACjDF,KAAKa,MAAMC,YAAY,eAAgBC,OAAOf,KAAKG,SAEjC,MAAdH,KAAKoB,MACPpB,KAAKa,MAAMC,YAAY,cAAeC,OAAOf,KAAKoB,QAElDpB,KAAKa,MAAMQ,eAAe,eAGxBrB,KAAKsB,UACPtB,KAAKa,MAAMC,YAAY,mBAAoBd,KAAKsB,WAEhDtB,KAAKa,MAAMQ,eAAe,oBAGxBrB,KAAKI,MACPJ,KAAKa,MAAMC,YAAY,cAAed,KAAKI,OAE3CJ,KAAKa,MAAMQ,eAAe,cAE9B,CAOO,aAAAE,GACLvB,KAAKS,UACP,CAOO,OAAAe,GACL,OAAOxB,KAAKC,IACd,CAOO,OAAAwB,CAAQC,GACb1B,KAAKC,KAAOyB,EACZ1B,KAAKS,UACP,CAGS,MAAAkB,GACP,OAAOC,CAAA,4BACT,GApLWjC,EAuEGkC,OAASC,CAAA;;;;;;;;;;;;IAjEvBC,EAAA,CADCC,EAAS,CAAEC,KAAMC,UALPvC,EAMXwC,UAAA,OAAA,GAOAJ,EAAA,CADCC,EAAS,CAAEC,KAAMC,UAZPvC,EAaXwC,UAAA,SAAA,GAOAJ,EAAA,CADCC,EAAS,CAAEC,KAAMC,UAnBPvC,EAoBXwC,UAAA,SAAA,GAOAJ,EAAA,CADCC,EAAS,CAAEC,KAAMC,UA1BPvC,EA2BXwC,UAAA,SAAA,GAOAJ,EAAA,CADCC,EAAS,CAAEC,KAAMC,UAjCPvC,EAkCXwC,UAAA,SAAA,GAOAJ,EAAA,CADCC,EAAS,CAAEC,KAAMC,UAxCPvC,EAyCXwC,UAAA,OAAA,GAOAJ,EAAA,CADCC,EAAS,CAAEC,KAAMC,UA/CPvC,EAgDXwC,UAAA,SAAA,GAOAJ,EAAA,CADCC,EAAS,CAAEC,KAAMlB,UAtDPpB,EAuDXwC,UAAA,QAAA,GAOAJ,EAAA,CADCC,EAAS,CAAEC,KAAMC,UA7DPvC,EA8DXwC,UAAA,QAAA,GAOAJ,EAAA,CADCC,EAAS,CAAEC,KAAMlB,UApEPpB,EAqEXwC,UAAA,YAAA,GAmB2CJ,EAAA,CAA1CC,EAAS,CAAEC,KAAMlB,OAAQqB,SAAS,KAxFxBzC,EAwFgCwC,UAAA,SAAA,GAxFhCxC,EAANoC,EAAA,CADNM,EAAc,gBACF1C"}
|
|
1
|
+
{"version":3,"file":"sky-flexcol.js","sources":["../../src/sky-flexcol/sky-flexcol.ts"],"sourcesContent":["import { LitElement, html, css } from \"lit\";\r\nimport { customElement, property } from \"lit/decorators.js\";\r\nimport { PresetController } from \"../helper/controllers/preset-controller\";\r\n\r\nexport type SkyFlexcolAlignSelf =\r\n | \"auto\"\r\n | \"flex-start\"\r\n | \"center\"\r\n | \"flex-end\"\r\n | \"stretch\"\r\n | \"baseline\";\r\n\r\n/**\r\n * @element sky-flexcol\r\n *\r\n * @summary Flex column item for `sky-flexbox` layouts with responsive span controls.\r\n *\r\n * @status stable\r\n * @since 1.0.0\r\n *\r\n * @documentation https://sky-ui.com/components/flexbox\r\n *\r\n * @slot - Default slot for column content.\r\n *\r\n * @property {number} span - Base number of columns to span.\r\n * @property {number | undefined} spanLg - Span at large breakpoints.\r\n * @property {number | undefined} spanMd - Span at medium breakpoints.\r\n * @property {number | undefined} spanSm - Span at small breakpoints.\r\n * @property {number | undefined} spanXs - Span at extra-small breakpoints.\r\n * @property {number} grow - Flex grow factor.\r\n * @property {number} shrink - Flex shrink factor.\r\n * @property {string | null} basis - Flex basis override.\r\n * @property {number | undefined} order - Flex order override.\r\n * @property {SkyFlexcolAlignSelf | undefined} alignSelf - Cross-axis alignment override.\r\n * @property {string} preset - Named prop preset from nearest `sky-config-provider`. Default: `\"\"`.\r\n * @method refreshStyles Re-applies CSS custom properties from current values.\r\n * @method getSpan Returns current base span value.\r\n * @method setSpan Updates base span value and refreshes styles.\r\n *\r\n * @csspart col - The flex item wrapper.\r\n *\r\n * @Behavior\r\n * - Designed to work within `<sky-flexbox>` containers\r\n * - Supports responsive column spans with breakpoint attributes\r\n * - Exposes all standard flex item properties\r\n * - Automatically syncs properties to CSS custom properties\r\n *\r\n * - `span`: Base span across columns (1 to container's column count)\r\n * - `span-lg`: Span at large screens (≤1200px)\r\n * - `span-md`: Span at medium screens (≤992px)\r\n * - `span-sm`: Span at small screens (≤768px)\r\n * - `span-xs`: Span at extra-small screens (≤576px)\r\n *\r\n * @example\r\n * ```html\r\n * <sky-flexbox col=\"12\" gap=\"16px\">\r\n * <sky-flexcol span=\"8\">\r\n * <div class=\"card\">Main Content</div>\r\n * </sky-flexcol>\r\n * <sky-flexcol span=\"4\">\r\n * <div class=\"card\">Sidebar</div>\r\n * </sky-flexcol>\r\n * </sky-flexbox>\r\n * ```\r\n * ```vue\r\n * <template>\r\n * <sky-flexbox col=\"12\" gap=\"16px\">\r\n * <sky-flexcol span=\"8\" span-md=\"12\">Main Content</sky-flexcol>\r\n * <sky-flexcol span=\"4\" span-md=\"12\">Sidebar</sky-flexcol>\r\n * </sky-flexbox>\r\n * </template>\r\n * ```\r\n * ```jsx\r\n * export default function Demo() {\r\n * return (\r\n * <sky-flexbox col=\"12\" gap=\"16px\">\r\n * <sky-flexcol span=\"8\" span-md=\"12\">Main Content</sky-flexcol>\r\n * <sky-flexcol span=\"4\" span-md=\"12\">Sidebar</sky-flexcol>\r\n * </sky-flexbox>\r\n * );\r\n * }\r\n * ```\r\n */\r\n@customElement(\"sky-flexcol\")\r\nexport class SkyFlexcol extends LitElement {\r\n /**\r\n * Number of columns to span.\r\n * @public\r\n */\r\n @property({ type: Number })\r\n span = 1;\r\n\r\n /**\r\n * Columns spanned at large screens (≤1200px).\r\n * @public\r\n */\r\n @property({ type: Number })\r\n spanLg?: number;\r\n\r\n /**\r\n * Columns spanned at medium screens (≤992px).\r\n * @public\r\n */\r\n @property({ type: Number })\r\n spanMd?: number;\r\n\r\n /**\r\n * Columns spanned at small screens (≤768px).\r\n * @public\r\n */\r\n @property({ type: Number })\r\n spanSm?: number;\r\n\r\n /**\r\n * Columns spanned at extra-small screens (≤576px).\r\n * @public\r\n */\r\n @property({ type: Number })\r\n spanXs?: number;\r\n\r\n /**\r\n * Flex grow factor.\r\n * @public\r\n */\r\n @property({ type: Number })\r\n grow = 0;\r\n\r\n /**\r\n * Flex shrink factor.\r\n * @public\r\n */\r\n @property({ type: Number })\r\n shrink = 0;\r\n\r\n /**\r\n * Flex basis (e.g., `\"200px\"` or `\"auto\"`).\r\n * @public\r\n */\r\n @property({ type: String })\r\n basis: string | null = null;\r\n\r\n /**\r\n * Flex order relative to siblings.\r\n * @public\r\n */\r\n @property({ type: Number })\r\n order?: number;\r\n\r\n /**\r\n * Self alignment override.\r\n * @public\r\n */\r\n @property({ type: String })\r\n alignSelf?: SkyFlexcolAlignSelf;\r\n\r\nstatic override styles = css`\r\n :host {\r\n display: block;\r\n box-sizing: border-box;\r\n /* These are read by the container’s ::slotted(*) rules */\r\n flex-grow: var(--col-grow, 0);\r\n flex-shrink: var(--col-shrink, 0);\r\n order: var(--col-order, 0);\r\n align-self: var(--col-align-self, auto);\r\n /* If you set basis, it will override the basis calc coming from container's ::slotted(*) */\r\n flex-basis: var(--col-basis, auto);\r\n }\r\n `;\r\n\r\n /** @protected */\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 override firstUpdated() {\r\n this.syncVars();\r\n }\r\n\r\n /** @protected */\r\n override updated(changed: Map<string | number | symbol, unknown>) {\r\n if (\r\n changed.has(\"span\") ||\r\n changed.has(\"spanLg\") ||\r\n changed.has(\"spanMd\") ||\r\n changed.has(\"spanSm\") ||\r\n changed.has(\"spanXs\") ||\r\n changed.has(\"grow\") ||\r\n changed.has(\"shrink\") ||\r\n changed.has(\"basis\") ||\r\n changed.has(\"order\") ||\r\n changed.has(\"alignSelf\")\r\n ) {\r\n this.syncVars();\r\n }\r\n }\r\n\r\n /**\r\n * Syncs component properties to CSS custom properties.\r\n * @private\r\n */\r\n private syncVars() {\r\n // Span properties\r\n this.style.setProperty(\"--span\", String(this.span));\r\n if (this.spanLg) this.style.setProperty(\"--span-lg\", String(this.spanLg));\r\n if (this.spanMd) this.style.setProperty(\"--span-md\", String(this.spanMd));\r\n if (this.spanSm) this.style.setProperty(\"--span-sm\", String(this.spanSm));\r\n if (this.spanXs) this.style.setProperty(\"--span-xs\", String(this.spanXs));\r\n\r\n // Flex properties\r\n this.style.setProperty(\"--col-grow\", String(this.grow));\r\n this.style.setProperty(\"--col-shrink\", String(this.shrink));\r\n\r\n if (this.order != null) {\r\n this.style.setProperty(\"--col-order\", String(this.order));\r\n } else {\r\n this.style.removeProperty(\"--col-order\");\r\n }\r\n\r\n if (this.alignSelf) {\r\n this.style.setProperty(\"--col-align-self\", this.alignSelf);\r\n } else {\r\n this.style.removeProperty(\"--col-align-self\");\r\n }\r\n\r\n if (this.basis) {\r\n this.style.setProperty(\"--col-basis\", this.basis);\r\n } else {\r\n this.style.removeProperty(\"--col-basis\");\r\n }\r\n }\r\n\r\n /**\r\n * Forces resynchronization of CSS custom properties.\r\n * Useful when properties are changed programmatically.\r\n * @public\r\n */\r\n public refreshStyles() {\r\n this.syncVars();\r\n }\r\n\r\n /**\r\n * Gets the current span value.\r\n * @returns Current span value\r\n * @public\r\n */\r\n public getSpan(): number {\r\n return this.span;\r\n }\r\n\r\n /**\r\n * Sets the span value and updates styles.\r\n * @param value - New span value\r\n * @public\r\n */\r\n public setSpan(value: number): void {\r\n this.span = value;\r\n this.syncVars();\r\n }\r\n\r\n /** @protected */\r\n override render() {\r\n return html` <slot part=\"col\"></slot> `;\r\n }\r\n}\r\n"],"names":["SkyFlexcol","LitElement","constructor","super","arguments","this","span","grow","shrink","basis","preset","_presets","PresetController","firstUpdated","syncVars","updated","changed","has","style","setProperty","String","spanLg","spanMd","spanSm","spanXs","order","removeProperty","alignSelf","refreshStyles","getSpan","setSpan","value","render","html","styles","css","__decorateClass","property","type","Number","prototype","reflect","customElement"],"mappings":"kYAoFO,IAAMA,EAAN,cAAyBC,EAAzB,WAAAC,GAAAC,SAAAC,WAMLC,KAAAC,KAAO,EAmCPD,KAAAE,KAAO,EAOPF,KAAAG,OAAS,EAOTH,KAAAI,MAAuB,KAiCoBJ,KAAAK,OAAS,GAEpDL,KAAQM,SAAW,IAAIC,EAAiBP,KAAI,CAEnC,YAAAQ,GACPR,KAAKS,UACP,CAGS,OAAAC,CAAQC,IAEbA,EAAQC,IAAI,SACZD,EAAQC,IAAI,WACZD,EAAQC,IAAI,WACZD,EAAQC,IAAI,WACZD,EAAQC,IAAI,WACZD,EAAQC,IAAI,SACZD,EAAQC,IAAI,WACZD,EAAQC,IAAI,UACZD,EAAQC,IAAI,UACZD,EAAQC,IAAI,eAEZZ,KAAKS,UAET,CAMQ,QAAAA,GAENT,KAAKa,MAAMC,YAAY,SAAUC,OAAOf,KAAKC,OACzCD,KAAKgB,QAAQhB,KAAKa,MAAMC,YAAY,YAAaC,OAAOf,KAAKgB,SAC7DhB,KAAKiB,QAAQjB,KAAKa,MAAMC,YAAY,YAAaC,OAAOf,KAAKiB,SAC7DjB,KAAKkB,QAAQlB,KAAKa,MAAMC,YAAY,YAAaC,OAAOf,KAAKkB,SAC7DlB,KAAKmB,QAAQnB,KAAKa,MAAMC,YAAY,YAAaC,OAAOf,KAAKmB,SAGjEnB,KAAKa,MAAMC,YAAY,aAAcC,OAAOf,KAAKE,OACjDF,KAAKa,MAAMC,YAAY,eAAgBC,OAAOf,KAAKG,SAEjC,MAAdH,KAAKoB,MACPpB,KAAKa,MAAMC,YAAY,cAAeC,OAAOf,KAAKoB,QAElDpB,KAAKa,MAAMQ,eAAe,eAGxBrB,KAAKsB,UACPtB,KAAKa,MAAMC,YAAY,mBAAoBd,KAAKsB,WAEhDtB,KAAKa,MAAMQ,eAAe,oBAGxBrB,KAAKI,MACPJ,KAAKa,MAAMC,YAAY,cAAed,KAAKI,OAE3CJ,KAAKa,MAAMQ,eAAe,cAE9B,CAOO,aAAAE,GACLvB,KAAKS,UACP,CAOO,OAAAe,GACL,OAAOxB,KAAKC,IACd,CAOO,OAAAwB,CAAQC,GACb1B,KAAKC,KAAOyB,EACZ1B,KAAKS,UACP,CAGS,MAAAkB,GACP,OAAOC,CAAA,4BACT,GApLWjC,EAuEGkC,OAASC,CAAA;;;;;;;;;;;;IAjEvBC,EAAA,CADCC,EAAS,CAAEC,KAAMC,UALPvC,EAMXwC,UAAA,OAAA,GAOAJ,EAAA,CADCC,EAAS,CAAEC,KAAMC,UAZPvC,EAaXwC,UAAA,SAAA,GAOAJ,EAAA,CADCC,EAAS,CAAEC,KAAMC,UAnBPvC,EAoBXwC,UAAA,SAAA,GAOAJ,EAAA,CADCC,EAAS,CAAEC,KAAMC,UA1BPvC,EA2BXwC,UAAA,SAAA,GAOAJ,EAAA,CADCC,EAAS,CAAEC,KAAMC,UAjCPvC,EAkCXwC,UAAA,SAAA,GAOAJ,EAAA,CADCC,EAAS,CAAEC,KAAMC,UAxCPvC,EAyCXwC,UAAA,OAAA,GAOAJ,EAAA,CADCC,EAAS,CAAEC,KAAMC,UA/CPvC,EAgDXwC,UAAA,SAAA,GAOAJ,EAAA,CADCC,EAAS,CAAEC,KAAMlB,UAtDPpB,EAuDXwC,UAAA,QAAA,GAOAJ,EAAA,CADCC,EAAS,CAAEC,KAAMC,UA7DPvC,EA8DXwC,UAAA,QAAA,GAOAJ,EAAA,CADCC,EAAS,CAAEC,KAAMlB,UApEPpB,EAqEXwC,UAAA,YAAA,GAmB2CJ,EAAA,CAA1CC,EAAS,CAAEC,KAAMlB,OAAQqB,SAAS,KAxFxBzC,EAwFgCwC,UAAA,SAAA,GAxFhCxC,EAANoC,EAAA,CADNM,EAAc,gBACF1C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sky-grid.js","sources":["../../src/sky-grid/sky-grid.ts"],"sourcesContent":["import { LitElement, html, css } from \"lit\";\r\nimport { customElement, property } from \"lit/decorators.js\";\r\nimport { PresetController } from \"../helper/controllers/preset-controller\";\n\r\nexport interface SkyGridColumnsConfig {\r\n columns: number;\r\n lg: number;\r\n md: number;\r\n sm: number;\r\n xs: number;\r\n}\r\n\r\n/**\r\n * @element sky-grid\r\n *\r\n * @summary Responsive CSS grid container with configurable breakpoint column counts.\r\n *\r\n * @status stable\r\n * @since 1.0.0\r\n *\r\n * @documentation https://sky-ui.com/components/grid\r\n *\r\n * @slot - Default slot for grid items (direct children become grid items).\r\n * @property {number} columns - Base number of grid columns.\r\n * @property {string} gap - Gap between grid items.\r\n * @property {number} lg - Column count at large breakpoints.\r\n * @property {number} md - Column count at medium breakpoints.\r\n * @property {number} sm - Column count at small breakpoints.\r\n * @property {number} xs - Column count at extra-small breakpoints.\r\n * @property {boolean} nowrap - Reuses `columns` across breakpoints when true.\r\n * @property {string} preset - Named prop preset from nearest `sky-config-provider`. Default: `\"\"`.\n *\r\n * @csspart grid - The grid container element.\r\n *\r\n * @Behavior\r\n * - Uses CSS variables for runtime breakpoint column updates\r\n * - Supports explicit per-breakpoint column counts\r\n * - Supports `nowrap` mode to keep a fixed column count\r\n *\r\n * @example\r\n * ```html\r\n * <sky-grid columns=\"12\" lg=\"4\" md=\"3\" sm=\"2\" xs=\"1\" gap=\"16px\">\r\n * <sky-card>Card 1</sky-card>\r\n * <sky-card>Card 2</sky-card>\r\n * <sky-card>Card 3</sky-card>\r\n * <sky-card>Card 4</sky-card>\r\n * </sky-grid>\r\n * ```\r\n * ```vue\r\n * <template>\r\n * <sky-grid columns=\"12\" lg=\"4\" md=\"3\" sm=\"2\" xs=\"1\" gap=\"16px\">\r\n * <sky-card>Card 1</sky-card>\r\n * <sky-card>Card 2</sky-card>\r\n * <sky-card>Card 3</sky-card>\r\n * <sky-card>Card 4</sky-card>\r\n * </sky-grid>\r\n * </template>\r\n * ```\r\n * ```jsx\r\n * export default function Demo() {\r\n * return (\r\n * <sky-grid columns=\"12\" lg=\"4\" md=\"3\" sm=\"2\" xs=\"1\" gap=\"16px\">\r\n * <sky-card>Card 1</sky-card>\r\n * <sky-card>Card 2</sky-card>\r\n * <sky-card>Card 3</sky-card>\r\n * <sky-card>Card 4</sky-card>\r\n * </sky-grid>\r\n * );\r\n * }\r\n * ```\r\n */\r\n@customElement(\"sky-grid\")\r\nexport class SkyGrid extends LitElement {\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: block;\r\n }\r\n\r\n .grid {\r\n display: grid;\r\n gap: var(--grid-gap, 1rem);\r\n grid-template-columns: repeat(var(--grid-columns, 4), 1fr);\r\n }\r\n\r\n @media (max-width: 1200px) {\r\n .grid {\r\n grid-template-columns: repeat(var(--grid-columns-lg), 1fr);\r\n }\r\n }\r\n\r\n @media (max-width: 992px) {\r\n .grid {\r\n grid-template-columns: repeat(var(--grid-columns-md), 1fr);\r\n }\r\n }\r\n\r\n @media (max-width: 768px) {\r\n .grid {\r\n grid-template-columns: repeat(var(--grid-columns-sm), 1fr);\r\n }\r\n }\r\n\r\n @media (max-width: 576px) {\r\n .grid {\r\n grid-template-columns: repeat(var(--grid-columns-xs), 1fr);\r\n }\r\n }\r\n `;\r\n\r\n @property({ type: Number }) columns = 12;\r\n @property({ type: String }) gap = \"10px\";\r\n @property({ type: Number }) lg = 3;\r\n @property({ type: Number }) md = 2;\r\n @property({ type: Number }) sm = 2;\r\n @property({ type: Number }) xs = 1;\r\n @property({ type: Boolean, reflect: true }) nowrap = false;\r\n\r\n override updated(changedProperties: Map<string | number | symbol, unknown>): void {\r\n if (\r\n changedProperties.has(\"nowrap\") ||\r\n changedProperties.has(\"lg\") ||\r\n changedProperties.has(\"md\") ||\r\n changedProperties.has(\"sm\") ||\r\n changedProperties.has(\"xs\") ||\r\n changedProperties.has(\"columns\")\r\n ) {\r\n this.style.setProperty(\"--grid-columns\", this.columns.toString());\r\n if (this.nowrap) {\r\n this.style.setProperty(\"--grid-columns-lg\", this.columns.toString());\r\n this.style.setProperty(\"--grid-columns-md\", this.columns.toString());\r\n this.style.setProperty(\"--grid-columns-sm\", this.columns.toString());\r\n this.style.setProperty(\"--grid-columns-xs\", this.columns.toString());\r\n } else {\r\n this.style.setProperty(\r\n \"--grid-columns-lg\",\r\n (this.lg || this.columns).toString(),\r\n );\r\n this.style.setProperty(\r\n \"--grid-columns-md\",\r\n (this.md || this.columns).toString(),\r\n );\r\n this.style.setProperty(\r\n \"--grid-columns-sm\",\r\n (this.sm || this.columns).toString(),\r\n );\r\n this.style.setProperty(\r\n \"--grid-columns-xs\",\r\n (this.xs || this.columns).toString(),\r\n );\r\n }\r\n }\r\n if (changedProperties.has(\"gap\")) {\r\n this.style.setProperty(\"--grid-gap\", this.gap);\r\n }\r\n }\r\n\r\n override render() {\r\n return html`\r\n <div class=\"grid\">\r\n <slot></slot>\r\n </div>\r\n `;\r\n }\r\n}\r\n"],"names":["SkyGrid","LitElement","constructor","super","arguments","this","preset","_presets","PresetController","columns","gap","lg","md","sm","xs","nowrap","updated","changedProperties","has","style","setProperty","toString","render","html","styles","css","__decorateClass","property","type","String","reflect","prototype","Number","Boolean","customElement"],"mappings":"kYAwEO,IAAMA,EAAN,cAAsBC,EAAtB,WAAAC,GAAAC,SAAAC,WAGsCC,KAAAC,OAAS,GAEpDD,KAAQE,SAAW,IAAIC,EAAiBH,MAsCZA,KAAAI,QAAU,GACVJ,KAAAK,IAAM,OACNL,KAAAM,GAAK,EACLN,KAAAO,GAAK,EACLP,KAAAQ,GAAK,EACLR,KAAAS,GAAK,EACWT,KAAAU,QAAS,CAAA,CAE5C,OAAAC,CAAQC,IAEbA,EAAkBC,IAAI,WACtBD,EAAkBC,IAAI,OACtBD,EAAkBC,IAAI,OACtBD,EAAkBC,IAAI,OACtBD,EAAkBC,IAAI,OACtBD,EAAkBC,IAAI,cAEtBb,KAAKc,MAAMC,YAAY,iBAAkBf,KAAKI,QAAQY,YAClDhB,KAAKU,QACPV,KAAKc,MAAMC,YAAY,oBAAqBf,KAAKI,QAAQY,YACzDhB,KAAKc,MAAMC,YAAY,oBAAqBf,KAAKI,QAAQY,YACzDhB,KAAKc,MAAMC,YAAY,oBAAqBf,KAAKI,QAAQY,YACzDhB,KAAKc,MAAMC,YAAY,oBAAqBf,KAAKI,QAAQY,cAEzDhB,KAAKc,MAAMC,YACT,qBACCf,KAAKM,IAAMN,KAAKI,SAASY,YAE5BhB,KAAKc,MAAMC,YACT,qBACCf,KAAKO,IAAMP,KAAKI,SAASY,YAE5BhB,KAAKc,MAAMC,YACT,qBACCf,KAAKQ,IAAMR,KAAKI,SAASY,YAE5BhB,KAAKc,MAAMC,YACT,qBACCf,KAAKS,IAAMT,KAAKI,SAASY,cAI5BJ,EAAkBC,IAAI,QACxBb,KAAKc,MAAMC,YAAY,aAAcf,KAAKK,IAE9C,CAES,MAAAY,GACP,OAAOC,CAAA;;;;KAKT,GAhGWvB,EAOKwB,OAASC,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAJkBC,EAAA,CAA1CC,EAAS,CAAEC,KAAMC,OAAQC,SAAS,KAHxB9B,EAGgC+B,UAAA,SAAA,GAwCfL,EAAA,CAA3BC,EAAS,CAAEC,KAAMI,UA3CPhC,EA2CiB+B,UAAA,UAAA,GACAL,EAAA,CAA3BC,EAAS,CAAEC,KAAMC,UA5CP7B,EA4CiB+B,UAAA,MAAA,GACAL,EAAA,CAA3BC,EAAS,CAAEC,KAAMI,UA7CPhC,EA6CiB+B,UAAA,KAAA,GACAL,EAAA,CAA3BC,EAAS,CAAEC,KAAMI,UA9CPhC,EA8CiB+B,UAAA,KAAA,GACAL,EAAA,CAA3BC,EAAS,CAAEC,KAAMI,UA/CPhC,EA+CiB+B,UAAA,KAAA,GACAL,EAAA,CAA3BC,EAAS,CAAEC,KAAMI,UAhDPhC,EAgDiB+B,UAAA,KAAA,GACgBL,EAAA,CAA3CC,EAAS,CAAEC,KAAMK,QAASH,SAAS,KAjDzB9B,EAiDiC+B,UAAA,SAAA,GAjDjC/B,EAAN0B,EAAA,CADNQ,EAAc,aACFlC"}
|
|
1
|
+
{"version":3,"file":"sky-grid.js","sources":["../../src/sky-grid/sky-grid.ts"],"sourcesContent":["import { LitElement, html, css } from \"lit\";\r\nimport { customElement, property } from \"lit/decorators.js\";\r\nimport { PresetController } from \"../helper/controllers/preset-controller\";\r\n\r\nexport interface SkyGridColumnsConfig {\r\n columns: number;\r\n lg: number;\r\n md: number;\r\n sm: number;\r\n xs: number;\r\n}\r\n\r\n/**\r\n * @element sky-grid\r\n *\r\n * @summary Responsive CSS grid container with configurable breakpoint column counts.\r\n *\r\n * @status stable\r\n * @since 1.0.0\r\n *\r\n * @documentation https://sky-ui.com/components/grid\r\n *\r\n * @slot - Default slot for grid items (direct children become grid items).\r\n * @property {number} columns - Base number of grid columns.\r\n * @property {string} gap - Gap between grid items.\r\n * @property {number} lg - Column count at large breakpoints.\r\n * @property {number} md - Column count at medium breakpoints.\r\n * @property {number} sm - Column count at small breakpoints.\r\n * @property {number} xs - Column count at extra-small breakpoints.\r\n * @property {boolean} nowrap - Reuses `columns` across breakpoints when true.\r\n * @property {string} preset - Named prop preset from nearest `sky-config-provider`. Default: `\"\"`.\r\n *\r\n * @csspart grid - The grid container element.\r\n *\r\n * @Behavior\r\n * - Uses CSS variables for runtime breakpoint column updates\r\n * - Supports explicit per-breakpoint column counts\r\n * - Supports `nowrap` mode to keep a fixed column count\r\n *\r\n * @example\r\n * ```html\r\n * <sky-grid columns=\"12\" lg=\"4\" md=\"3\" sm=\"2\" xs=\"1\" gap=\"16px\">\r\n * <sky-card>Card 1</sky-card>\r\n * <sky-card>Card 2</sky-card>\r\n * <sky-card>Card 3</sky-card>\r\n * <sky-card>Card 4</sky-card>\r\n * </sky-grid>\r\n * ```\r\n * ```vue\r\n * <template>\r\n * <sky-grid columns=\"12\" lg=\"4\" md=\"3\" sm=\"2\" xs=\"1\" gap=\"16px\">\r\n * <sky-card>Card 1</sky-card>\r\n * <sky-card>Card 2</sky-card>\r\n * <sky-card>Card 3</sky-card>\r\n * <sky-card>Card 4</sky-card>\r\n * </sky-grid>\r\n * </template>\r\n * ```\r\n * ```jsx\r\n * export default function Demo() {\r\n * return (\r\n * <sky-grid columns=\"12\" lg=\"4\" md=\"3\" sm=\"2\" xs=\"1\" gap=\"16px\">\r\n * <sky-card>Card 1</sky-card>\r\n * <sky-card>Card 2</sky-card>\r\n * <sky-card>Card 3</sky-card>\r\n * <sky-card>Card 4</sky-card>\r\n * </sky-grid>\r\n * );\r\n * }\r\n * ```\r\n */\r\n@customElement(\"sky-grid\")\r\nexport class SkyGrid extends LitElement {\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: block;\r\n }\r\n\r\n .grid {\r\n display: grid;\r\n gap: var(--grid-gap, 1rem);\r\n grid-template-columns: repeat(var(--grid-columns, 4), 1fr);\r\n }\r\n\r\n @media (max-width: 1200px) {\r\n .grid {\r\n grid-template-columns: repeat(var(--grid-columns-lg), 1fr);\r\n }\r\n }\r\n\r\n @media (max-width: 992px) {\r\n .grid {\r\n grid-template-columns: repeat(var(--grid-columns-md), 1fr);\r\n }\r\n }\r\n\r\n @media (max-width: 768px) {\r\n .grid {\r\n grid-template-columns: repeat(var(--grid-columns-sm), 1fr);\r\n }\r\n }\r\n\r\n @media (max-width: 576px) {\r\n .grid {\r\n grid-template-columns: repeat(var(--grid-columns-xs), 1fr);\r\n }\r\n }\r\n `;\r\n\r\n @property({ type: Number }) columns = 12;\r\n @property({ type: String }) gap = \"10px\";\r\n @property({ type: Number }) lg = 3;\r\n @property({ type: Number }) md = 2;\r\n @property({ type: Number }) sm = 2;\r\n @property({ type: Number }) xs = 1;\r\n @property({ type: Boolean, reflect: true }) nowrap = false;\r\n\r\n override updated(changedProperties: Map<string | number | symbol, unknown>): void {\r\n if (\r\n changedProperties.has(\"nowrap\") ||\r\n changedProperties.has(\"lg\") ||\r\n changedProperties.has(\"md\") ||\r\n changedProperties.has(\"sm\") ||\r\n changedProperties.has(\"xs\") ||\r\n changedProperties.has(\"columns\")\r\n ) {\r\n this.style.setProperty(\"--grid-columns\", this.columns.toString());\r\n if (this.nowrap) {\r\n this.style.setProperty(\"--grid-columns-lg\", this.columns.toString());\r\n this.style.setProperty(\"--grid-columns-md\", this.columns.toString());\r\n this.style.setProperty(\"--grid-columns-sm\", this.columns.toString());\r\n this.style.setProperty(\"--grid-columns-xs\", this.columns.toString());\r\n } else {\r\n this.style.setProperty(\r\n \"--grid-columns-lg\",\r\n (this.lg || this.columns).toString(),\r\n );\r\n this.style.setProperty(\r\n \"--grid-columns-md\",\r\n (this.md || this.columns).toString(),\r\n );\r\n this.style.setProperty(\r\n \"--grid-columns-sm\",\r\n (this.sm || this.columns).toString(),\r\n );\r\n this.style.setProperty(\r\n \"--grid-columns-xs\",\r\n (this.xs || this.columns).toString(),\r\n );\r\n }\r\n }\r\n if (changedProperties.has(\"gap\")) {\r\n this.style.setProperty(\"--grid-gap\", this.gap);\r\n }\r\n }\r\n\r\n override render() {\r\n return html`\r\n <div class=\"grid\">\r\n <slot></slot>\r\n </div>\r\n `;\r\n }\r\n}\r\n"],"names":["SkyGrid","LitElement","constructor","super","arguments","this","preset","_presets","PresetController","columns","gap","lg","md","sm","xs","nowrap","updated","changedProperties","has","style","setProperty","toString","render","html","styles","css","__decorateClass","property","type","String","reflect","prototype","Number","Boolean","customElement"],"mappings":"kYAwEO,IAAMA,EAAN,cAAsBC,EAAtB,WAAAC,GAAAC,SAAAC,WAGsCC,KAAAC,OAAS,GAEpDD,KAAQE,SAAW,IAAIC,EAAiBH,MAsCZA,KAAAI,QAAU,GACVJ,KAAAK,IAAM,OACNL,KAAAM,GAAK,EACLN,KAAAO,GAAK,EACLP,KAAAQ,GAAK,EACLR,KAAAS,GAAK,EACWT,KAAAU,QAAS,CAAA,CAE5C,OAAAC,CAAQC,IAEbA,EAAkBC,IAAI,WACtBD,EAAkBC,IAAI,OACtBD,EAAkBC,IAAI,OACtBD,EAAkBC,IAAI,OACtBD,EAAkBC,IAAI,OACtBD,EAAkBC,IAAI,cAEtBb,KAAKc,MAAMC,YAAY,iBAAkBf,KAAKI,QAAQY,YAClDhB,KAAKU,QACPV,KAAKc,MAAMC,YAAY,oBAAqBf,KAAKI,QAAQY,YACzDhB,KAAKc,MAAMC,YAAY,oBAAqBf,KAAKI,QAAQY,YACzDhB,KAAKc,MAAMC,YAAY,oBAAqBf,KAAKI,QAAQY,YACzDhB,KAAKc,MAAMC,YAAY,oBAAqBf,KAAKI,QAAQY,cAEzDhB,KAAKc,MAAMC,YACT,qBACCf,KAAKM,IAAMN,KAAKI,SAASY,YAE5BhB,KAAKc,MAAMC,YACT,qBACCf,KAAKO,IAAMP,KAAKI,SAASY,YAE5BhB,KAAKc,MAAMC,YACT,qBACCf,KAAKQ,IAAMR,KAAKI,SAASY,YAE5BhB,KAAKc,MAAMC,YACT,qBACCf,KAAKS,IAAMT,KAAKI,SAASY,cAI5BJ,EAAkBC,IAAI,QACxBb,KAAKc,MAAMC,YAAY,aAAcf,KAAKK,IAE9C,CAES,MAAAY,GACP,OAAOC,CAAA;;;;KAKT,GAhGWvB,EAOKwB,OAASC,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAJkBC,EAAA,CAA1CC,EAAS,CAAEC,KAAMC,OAAQC,SAAS,KAHxB9B,EAGgC+B,UAAA,SAAA,GAwCfL,EAAA,CAA3BC,EAAS,CAAEC,KAAMI,UA3CPhC,EA2CiB+B,UAAA,UAAA,GACAL,EAAA,CAA3BC,EAAS,CAAEC,KAAMC,UA5CP7B,EA4CiB+B,UAAA,MAAA,GACAL,EAAA,CAA3BC,EAAS,CAAEC,KAAMI,UA7CPhC,EA6CiB+B,UAAA,KAAA,GACAL,EAAA,CAA3BC,EAAS,CAAEC,KAAMI,UA9CPhC,EA8CiB+B,UAAA,KAAA,GACAL,EAAA,CAA3BC,EAAS,CAAEC,KAAMI,UA/CPhC,EA+CiB+B,UAAA,KAAA,GACAL,EAAA,CAA3BC,EAAS,CAAEC,KAAMI,UAhDPhC,EAgDiB+B,UAAA,KAAA,GACgBL,EAAA,CAA3CC,EAAS,CAAEC,KAAMK,QAASH,SAAS,KAjDzB9B,EAiDiC+B,UAAA,SAAA,GAjDjC/B,EAAN0B,EAAA,CADNQ,EAAc,aACFlC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sky-icon.js","sources":["../../src/sky-icon/sky-icon.ts"],"sourcesContent":["import { LitElement, html, css } from 'lit';\r\nimport { customElement, property, state } from 'lit/decorators.js';\r\nimport { styleMap } from 'lit/directives/style-map.js';\r\nimport { resolveColor } from '../helper/utils/color-resolver';\r\nimport skyLocalSetData from './ion-local.json';\r\nimport { PresetController } from \"../helper/controllers/preset-controller\";\r\n\r\nexport type SkyIconSizeValue = string | number;\r\nexport type SkyIconRotateValue = string | number;\r\nexport type SkyIconFlip = '' | 'horizontal' | 'vertical' | 'horizontal,vertical';\r\n\r\ninterface IconifyCollection {\r\n left?: number;\r\n top?: number;\r\n width?: number;\r\n height?: number;\r\n}\r\n\r\ninterface IconifySetData extends IconifyCollection {\r\n icons?: Record<string, IconifyIcon>;\r\n}\r\n\r\ninterface IconifyIcon {\r\n body?: string;\r\n left?: number;\r\n top?: number;\r\n width?: number;\r\n height?: number;\r\n viewBox?: string;\r\n}\r\n\r\nconst MAX_ICON_CACHE_SIZE = 100;\r\n\r\n\r\n/**\r\n * @element sky-icon\r\n *\r\n * @summary Icon renderer with Iconify fetch/caching, lazy loading, and optional slotted SVG fallback.\r\n *\r\n * @status stable\r\n * @since 1.0.0\r\n *\r\n * @documentation https://sky-ui.com/components/icon\r\n *\r\n * @slot - Optional fallback `<svg>` content when remote icon data is unavailable.\r\n * @property {string} icon - Icon name in `prefix:icon-name` format.\r\n * @property {SkyIconSizeValue} width - Icon width value.\r\n * @property {SkyIconSizeValue} height - Icon height value.\r\n * @property {string} color - Icon color value.\r\n * @property {boolean} inline - Applies inline alignment behavior for text contexts.\r\n * @property {SkyIconFlip} flip - Flip transform descriptor.\r\n * @property {boolean} hFlip - Horizontal flip shortcut.\r\n * @property {boolean} vFlip - Vertical flip shortcut.\r\n * @property {SkyIconRotateValue} rotate - Rotation descriptor.\r\n * @property {boolean} lazy - Defers loading until the icon is visible.\r\n *\r\n * @method registerLocalSet Registers a local Iconify set for offline/custom usage.\r\n * @method registerLocalIcon Registers a single local icon override.\r\n *\r\n * @csspart icon - The icon container element.\r\n * @csspart svg - The rendered SVG element.\r\n *\r\n * @Behavior\r\n * - Resolves icons from local registrations first, then Iconify API.\r\n * - Uses bounded in-memory caching for fetched SVG payloads.\r\n * - Supports custom slotted SVG fallback when external fetch fails or is blocked.\r\n *\r\n * @example\r\n * ```html\r\n * <sky-icon icon=\"ion:home\" width=\"24\" height=\"24\" color=\"#3b82f6\"></sky-icon>\r\n * ```\r\n * ```vue\r\n * <template>\r\n * <sky-icon icon=\"ion:home\" width=\"24\" height=\"24\" color=\"#3b82f6\"></sky-icon>\r\n * </template>\r\n * ```\r\n * ```jsx\r\n * export default function Demo() {\r\n * return <sky-icon icon=\"ion:home\" width=\"24\" height=\"24\" color=\"#3b82f6\"></sky-icon>;\r\n * }\r\n * ```\r\n */\r\n@customElement('sky-icon')\r\nexport class SkyIcon extends LitElement {\r\n /** Cache: icon name -> final SVG string (bounded by MAX_ICON_CACHE_SIZE, LRU eviction). */\r\n private static _iconCache = new Map<string, string>();\r\n\r\n /** Cache for in-flight fetches: icon name -> Promise<svg> */\r\n private static _iconPromiseCache = new Map<string, Promise<string>>();\r\n\r\n /** Local icon sets (prefix -> Iconify set data) for offline/custom icons */\r\n private static _localSets = new Map<string, IconifySetData>();\r\n\r\n /** Single local icons (full name -> icon data) */\r\n private static _localIcons = new Map<string, IconifyIcon>();\r\n\r\n /**\r\n * Register a local icon set (Iconify-compatible JSON) for offline or custom icons.\r\n * @param prefix - Set prefix (e.g. \"ion\", \"custom\"); use as icon=\"prefix:iconName\".\r\n * @param data - Set data with `icons` and optional defaults (width, height, left, top).\r\n */\r\n static registerLocalSet(prefix: string, data: IconifySetData): void {\r\n SkyIcon._localSets.set(prefix, data);\r\n for (const key of SkyIcon._iconCache.keys()) {\r\n if (key.startsWith(prefix + ':')) SkyIcon._iconCache.delete(key);\r\n }\r\n }\r\n\r\n /**\r\n * Register a single local icon (one-off custom icon without a full set).\r\n * @param fullName - Full icon name, e.g. \"ion:heart\".\r\n * @param icon - Icon data (body, width, height, viewBox, etc.).\r\n */\r\n static registerLocalIcon(fullName: string, icon: IconifyIcon): void {\r\n SkyIcon._localIcons.set(fullName, icon);\r\n SkyIcon._iconCache.delete(fullName);\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 styles = css`\r\n :host {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n vertical-align: middle;\r\n }\r\n .icon {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n line-height: 1;\r\n }\r\n .icon svg {\r\n display: block;\r\n width: 100%;\r\n height: 100%;\r\n flex-shrink: 0;\r\n }\r\n /* Custom SVG in slot: inherit size and color */\r\n .icon::slotted(svg) {\r\n display: block;\r\n width: 100%;\r\n height: 100%;\r\n flex-shrink: 0;\r\n fill: currentColor;\r\n }\r\n `;\r\n\r\n // Iconify-style public props\r\n\r\n @property({ type: String })\r\n icon = '';\r\n\r\n @property({ type: String })\r\n width: SkyIconSizeValue = '';\r\n\r\n @property({ type: String })\r\n height: SkyIconSizeValue = '';\r\n\r\n @property({ type: String })\r\n color = 'currentColor';\r\n\r\n @property({ type: Boolean })\r\n inline = false;\r\n\r\n @property({ type: String })\r\n flip: SkyIconFlip = '';\r\n\r\n @property({ type: Boolean })\r\n hFlip = false;\r\n\r\n @property({ type: Boolean })\r\n vFlip = false;\r\n\r\n @property({ type: String })\r\n rotate: SkyIconRotateValue = 0;\r\n\r\n @property({ type: Boolean })\r\n lazy = false;\r\n\r\n // Internal state\r\n\r\n @state()\r\n private _svgContent: string | null = null;\r\n\r\n @state()\r\n private _hasSlottedSvg = false;\r\n\r\n private _observer: IntersectionObserver | null = null;\r\n private _visible = false;\r\n\r\n // Lifecycle\r\n\r\n override connectedCallback(): void {\r\n super.connectedCallback();\r\n\r\n if (this.lazy) {\r\n this._startObserver();\r\n } else {\r\n this._visible = true;\r\n if (this.icon && !this._hasSlottedSvg) {\r\n this._loadIcon();\r\n }\r\n }\r\n }\r\n\r\n override disconnectedCallback(): void {\r\n super.disconnectedCallback();\r\n this._stopObserver();\r\n }\r\n\r\n override updated(changed: Map<string, unknown>): void {\r\n // Lazy flag changed: reconfigure observer / visibility\r\n if (changed.has('lazy')) {\r\n if (this.lazy) {\r\n this._startObserver();\r\n } else {\r\n this._stopObserver();\r\n this._visible = true;\r\n if (this.icon && !this._hasSlottedSvg) {\r\n this._loadIcon();\r\n }\r\n }\r\n }\r\n\r\n // Icon changed: reload if visible and no custom SVG, otherwise clear\r\n if (changed.has('icon')) {\r\n if (this._hasSlottedSvg) {\r\n this._setSvgContent(null);\r\n } else if (!this.lazy || this._visible) {\r\n this._loadIcon();\r\n } else {\r\n this._setSvgContent(null);\r\n }\r\n }\r\n }\r\n\r\n private _onSlotChange(e: Event): void {\r\n const slot = e.target as HTMLSlotElement;\r\n const nodes = slot.assignedNodes({ flatten: true });\r\n const hasSvg = nodes.some(\r\n (n) => n.nodeType === Node.ELEMENT_NODE && (n as Element).tagName === 'SVG'\r\n );\r\n if (this._hasSlottedSvg !== hasSvg) {\r\n this._hasSlottedSvg = hasSvg;\r\n if (hasSvg && this.icon) {\r\n this._setSvgContent(null);\r\n } else if (!hasSvg && this.icon && (this._visible || !this.lazy)) {\r\n this._loadIcon();\r\n }\r\n }\r\n }\r\n\r\n // Lazy loading\r\n\r\n private _startObserver(): void {\r\n if (typeof window === 'undefined') return;\r\n if (this._observer || !('IntersectionObserver' in window)) return;\r\n\r\n this._observer = new IntersectionObserver((entries) => {\r\n if (entries.some((e) => e.isIntersecting)) {\r\n this._visible = true;\r\n if (!this._hasSlottedSvg && this.icon) {\r\n this._loadIcon();\r\n }\r\n this._stopObserver();\r\n }\r\n });\r\n\r\n this._observer.observe(this);\r\n }\r\n\r\n private _stopObserver(): void {\r\n if (this._observer) {\r\n this._observer.disconnect();\r\n this._observer = null;\r\n }\r\n }\r\n\r\n // State setter (avoids nested update warning)\r\n\r\n private _setSvgContent(svg: string | null): void {\r\n // Avoid unnecessary updates\r\n if (this._svgContent === svg) return;\r\n\r\n // Schedule after current update cycle\r\n if (typeof queueMicrotask === 'function') {\r\n queueMicrotask(() => {\r\n this._svgContent = svg;\r\n });\r\n } else {\r\n // Fallback for environments without queueMicrotask\r\n Promise.resolve().then(() => {\r\n this._svgContent = svg;\r\n });\r\n }\r\n }\r\n\r\n // Icon loading\r\n\r\n private async _loadIcon(): Promise<void> {\r\n const name = this.icon.trim();\r\n if (!name) {\r\n this._setSvgContent(null);\r\n return;\r\n }\r\n\r\n // Cached SVG → still set via microtask to avoid nested update warning\r\n const cached = SkyIcon._iconCache.get(name);\r\n if (cached) {\r\n this._setSvgContent(cached);\r\n return;\r\n }\r\n\r\n let promise = SkyIcon._iconPromiseCache.get(name);\r\n if (!promise) {\r\n promise = this._fetchAndBuild(name);\r\n SkyIcon._iconPromiseCache.set(name, promise);\r\n }\r\n\r\n try {\r\n const svg = await promise;\r\n this._setSvgContent(svg);\r\n if (SkyIcon._iconCache.size >= MAX_ICON_CACHE_SIZE) {\r\n const firstKey = SkyIcon._iconCache.keys().next().value;\r\n if (firstKey != null) SkyIcon._iconCache.delete(firstKey);\r\n }\r\n SkyIcon._iconCache.set(name, svg);\r\n } catch {\r\n this._setSvgContent(null);\r\n } finally {\r\n SkyIcon._iconPromiseCache.delete(name);\r\n }\r\n }\r\n\r\n private async _fetchAndBuild(full: string): Promise<string> {\r\n const [prefix, iconName] = full.split(':');\r\n if (!prefix || !iconName) throw new Error('Invalid icon name');\r\n\r\n // 1) Single local icon (e.g. registerLocalIcon('ion:heart', {...}))\r\n const singleLocal = SkyIcon._localIcons.get(full);\r\n if (singleLocal) {\r\n return this._buildSvg(singleLocal, {});\r\n }\r\n\r\n // 2) Local set (e.g. registerLocalSet('ion', { icons: { home: {...} } }))\r\n const localSet = SkyIcon._localSets.get(prefix);\r\n if (localSet?.icons?.[iconName]) {\r\n return this._buildSvg(localSet.icons[iconName], localSet);\r\n }\r\n\r\n // 3) Fetch from Iconify API\r\n const url = `https://api.iconify.design/${prefix}.json?icons=${iconName}`;\r\n const res = await fetch(url);\r\n if (!res.ok) throw new Error('Failed to fetch icon set');\r\n\r\n const json = (await res.json()) as {\r\n icons?: Record<string, IconifyIcon>;\r\n left?: number;\r\n top?: number;\r\n width?: number;\r\n height?: number;\r\n };\r\n\r\n const data = json.icons?.[iconName];\r\n if (!data) throw new Error('Icon not found');\r\n\r\n return this._buildSvg(data, json);\r\n }\r\n\r\n private _buildSvg(icon: IconifyIcon, set: IconifyCollection): string {\r\n const body = icon.body ?? '';\r\n const l = icon.left ?? set.left ?? 0;\r\n const t = icon.top ?? set.top ?? 0;\r\n const w = icon.width ?? set.width ?? 24;\r\n const h = icon.height ?? set.height ?? 24;\r\n const viewBox = icon.viewBox || `${l} ${t} ${w} ${h}`;\r\n\r\n return `\r\n <svg xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"${viewBox}\"\r\n width=\"100%\"\r\n height=\"100%\"\r\n preserveAspectRatio=\"xMidYMid meet\"\r\n fill=\"currentColor\">\r\n ${body}\r\n </svg>\r\n `;\r\n }\r\n\r\n // Style helpers\r\n\r\n private _normalize(v: string | number): string {\r\n if (typeof v === 'number') return `${v}px`;\r\n if (/^\\d+$/.test(v)) return `${v}px`;\r\n return v;\r\n }\r\n\r\n private _rotationDeg(): number {\r\n const v = this.rotate;\r\n if (typeof v === 'number') return v * 90;\r\n if (typeof v === 'string') {\r\n if (v.endsWith('deg')) return parseFloat(v);\r\n const n = parseInt(v, 10);\r\n return Number.isFinite(n) ? n * 90 : 0;\r\n }\r\n return 0;\r\n }\r\n\r\n private _flipHas(val: 'horizontal' | 'vertical'): boolean {\r\n return this.flip\r\n .split(',')\r\n .map((v) => v.trim().toLowerCase())\r\n .includes(val);\r\n }\r\n\r\n private _transform(): string {\r\n const deg = this._rotationDeg();\r\n const h = this.hFlip || this._flipHas('horizontal');\r\n const v = this.vFlip || this._flipHas('vertical');\r\n\r\n const tr: string[] = [];\r\n if (deg) tr.push(`rotate(${deg}deg)`);\r\n if (h || v) tr.push(`scale(${h ? -1 : 1}, ${v ? -1 : 1})`);\r\n\r\n return tr.join(' ');\r\n }\r\n\r\n private _baseStyle(): Record<string, string> {\r\n const style: Record<string, string> = { color: resolveColor(this.color) };\r\n\r\n if (this.width) style.width = this._normalize(this.width);\r\n if (this.height) style.height = this._normalize(this.height);\r\n\r\n if (!this.width && !this.height) {\r\n style.width = '1em';\r\n style.height = '1em';\r\n }\r\n if (this.inline) style.verticalAlign = '-0.125em';\r\n\r\n return style;\r\n }\r\n\r\n // Render\r\n\r\n override render() {\r\n const style = this._baseStyle();\r\n const tf = this._transform();\r\n if (tf) style.transform = tf;\r\n\r\n const showIconify = !this._hasSlottedSvg && this.icon && this._svgContent;\r\n\r\n /* Iconify (API) path: same structure as before — single .icon div with innerHTML, no wrapper */\r\n if (showIconify) {\r\n return html`\r\n <div\r\n class=\"icon\"\r\n style=${styleMap(style)}\r\n part=\"icon\"\r\n .innerHTML=${this._svgContent!}\r\n ></div>\r\n `;\r\n }\r\n\r\n /* Custom SVG slot or empty: render slot for detection and display */\r\n return html`\r\n <div class=\"icon\" style=${styleMap(style)} part=\"icon\">\r\n <slot @slotchange=${this._onSlotChange}></slot>\r\n </div>\r\n `;\r\n }\r\n}\r\n\r\n// Register default local set (ion from ion-local.json); users can add more via SkyIcon.registerLocalSet / registerLocalIcon\r\nconst defaultSet = skyLocalSetData as IconifySetData;\r\nif (defaultSet?.icons) {\r\n SkyIcon.registerLocalSet('ion', defaultSet);\r\n}\r\n"],"names":["SkyIcon","LitElement","constructor","super","arguments","this","preset","_presets","PresetController","icon","width","height","color","inline","flip","hFlip","vFlip","rotate","lazy","_svgContent","_hasSlottedSvg","_observer","_visible","registerLocalSet","prefix","data","_localSets","set","key","_iconCache","keys","startsWith","delete","registerLocalIcon","fullName","_localIcons","connectedCallback","_startObserver","_loadIcon","disconnectedCallback","_stopObserver","updated","changed","has","_setSvgContent","_onSlotChange","e","hasSvg","target","assignedNodes","flatten","some","n","nodeType","Node","ELEMENT_NODE","tagName","window","IntersectionObserver","entries","isIntersecting","observe","disconnect","svg","queueMicrotask","Promise","resolve","then","name","trim","cached","get","promise","_iconPromiseCache","_fetchAndBuild","size","firstKey","next","value","full","iconName","split","Error","singleLocal","_buildSvg","localSet","icons","url","res","fetch","ok","json","body","l","left","t","top","w","h","viewBox","_normalize","v","test","_rotationDeg","endsWith","parseFloat","parseInt","Number","isFinite","_flipHas","val","map","toLowerCase","includes","_transform","deg","tr","push","join","_baseStyle","style","resolveColor","verticalAlign","render","tf","transform","html","styleMap","Map","styles","css","__decorateClass","property","type","String","reflect","prototype","Boolean","state","customElement","defaultSet","skyLocalSetData"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sky-icon.js","sources":["../../src/sky-icon/sky-icon.ts"],"sourcesContent":["import { LitElement, html, css } from 'lit';\r\nimport { customElement, property, state } from 'lit/decorators.js';\r\nimport { styleMap } from 'lit/directives/style-map.js';\r\nimport { resolveColor } from '../helper/utils/color-resolver';\r\nimport skyLocalSetData from './ion-local.json';\r\nimport { PresetController } from \"../helper/controllers/preset-controller\";\r\n\r\nexport type SkyIconSizeValue = string | number;\r\nexport type SkyIconRotateValue = string | number;\r\nexport type SkyIconFlip =\r\n '' | 'horizontal' | 'vertical' | 'horizontal,vertical';\r\n\r\ninterface IconifyCollection {\r\n left?: number;\r\n top?: number;\r\n width?: number;\r\n height?: number;\r\n}\r\n\r\ninterface IconifySetData extends IconifyCollection {\r\n icons?: Record<string, IconifyIcon>;\r\n}\r\n\r\ninterface IconifyIcon {\r\n body?: string;\r\n left?: number;\r\n top?: number;\r\n width?: number;\r\n height?: number;\r\n viewBox?: string;\r\n}\r\n\r\nconst MAX_ICON_CACHE_SIZE = 100;\r\n\r\n/**\r\n * @element sky-icon\r\n *\r\n * @summary Icon renderer with Iconify fetch/caching, lazy loading, and optional slotted SVG fallback.\r\n *\r\n * @status stable\r\n * @since 1.0.0\r\n *\r\n * @documentation https://sky-ui.com/components/icon\r\n *\r\n * @slot - Optional fallback `<svg>` content when remote icon data is unavailable.\r\n * @property {string} icon - Icon name in `prefix:icon-name` format.\r\n * @property {SkyIconSizeValue} width - Icon width value.\r\n * @property {SkyIconSizeValue} height - Icon height value.\r\n * @property {string} color - Icon color value.\r\n * @property {boolean} inline - Applies inline alignment behavior for text contexts.\r\n * @property {SkyIconFlip} flip - Flip transform descriptor.\r\n * @property {boolean} hFlip - Horizontal flip shortcut.\r\n * @property {boolean} vFlip - Vertical flip shortcut.\r\n * @property {SkyIconRotateValue} rotate - Rotation descriptor.\r\n * @property {boolean} lazy - Defers loading until the icon is visible.\r\n *\r\n * @method registerLocalSet Registers a local Iconify set for offline/custom usage.\r\n * @method registerLocalIcon Registers a single local icon override.\r\n *\r\n * @csspart icon - The icon container element.\r\n * @csspart svg - The rendered SVG element.\r\n *\r\n * @Behavior\r\n * - Resolves icons from local registrations first, then Iconify API.\r\n * - Uses bounded in-memory caching for fetched SVG payloads.\r\n * - Supports custom slotted SVG fallback when external fetch fails or is blocked.\r\n *\r\n * @example\r\n * ```html\r\n * <sky-icon icon=\"ion:home\" width=\"24\" height=\"24\" color=\"#3b82f6\"></sky-icon>\r\n * ```\r\n * ```vue\r\n * <template>\r\n * <sky-icon icon=\"ion:home\" width=\"24\" height=\"24\" color=\"#3b82f6\"></sky-icon>\r\n * </template>\r\n * ```\r\n * ```jsx\r\n * export default function Demo() {\r\n * return <sky-icon icon=\"ion:home\" width=\"24\" height=\"24\" color=\"#3b82f6\"></sky-icon>;\r\n * }\r\n * ```\r\n */\r\n@customElement('sky-icon')\r\nexport class SkyIcon extends LitElement {\r\n /** Cache: icon name -> final SVG string (bounded by MAX_ICON_CACHE_SIZE, LRU eviction). */\r\n private static _iconCache = new Map<string, string>();\r\n\r\n /** Cache for in-flight fetches: icon name -> Promise<svg> */\r\n private static _iconPromiseCache = new Map<string, Promise<string>>();\r\n\r\n /** Local icon sets (prefix -> Iconify set data) for offline/custom icons */\r\n private static _localSets = new Map<string, IconifySetData>();\r\n\r\n /** Single local icons (full name -> icon data) */\r\n private static _localIcons = new Map<string, IconifyIcon>();\r\n\r\n /**\r\n * Register a local icon set (Iconify-compatible JSON) for offline or custom icons.\r\n * @param prefix - Set prefix (e.g. \"ion\", \"custom\"); use as icon=\"prefix:iconName\".\r\n * @param data - Set data with `icons` and optional defaults (width, height, left, top).\r\n */\r\n static registerLocalSet(prefix: string, data: IconifySetData): void {\r\n SkyIcon._localSets.set(prefix, data);\r\n for (const key of SkyIcon._iconCache.keys()) {\r\n if (key.startsWith(prefix + ':')) SkyIcon._iconCache.delete(key);\r\n }\r\n }\r\n\r\n /**\r\n * Register a single local icon (one-off custom icon without a full set).\r\n * @param fullName - Full icon name, e.g. \"ion:heart\".\r\n * @param icon - Icon data (body, width, height, viewBox, etc.).\r\n */\r\n static registerLocalIcon(fullName: string, icon: IconifyIcon): void {\r\n SkyIcon._localIcons.set(fullName, icon);\r\n SkyIcon._iconCache.delete(fullName);\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 styles = css`\r\n :host {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n vertical-align: middle;\r\n }\r\n .icon {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n line-height: 1;\r\n }\r\n .icon svg {\r\n display: block;\r\n width: 100%;\r\n height: 100%;\r\n flex-shrink: 0;\r\n }\r\n /* Custom SVG in slot: inherit size and color */\r\n .icon::slotted(svg) {\r\n display: block;\r\n width: 100%;\r\n height: 100%;\r\n flex-shrink: 0;\r\n fill: currentColor;\r\n }\r\n `;\r\n\r\n // Iconify-style public props\r\n\r\n @property({ type: String })\r\n icon = '';\r\n\r\n @property({ type: String })\r\n width: SkyIconSizeValue = '';\r\n\r\n @property({ type: String })\r\n height: SkyIconSizeValue = '';\r\n\r\n @property({ type: String })\r\n color = 'currentColor';\r\n\r\n @property({ type: Boolean })\r\n inline = false;\r\n\r\n @property({ type: String })\r\n flip: SkyIconFlip = '';\r\n\r\n @property({ type: Boolean })\r\n hFlip = false;\r\n\r\n @property({ type: Boolean })\r\n vFlip = false;\r\n\r\n @property({ type: String })\r\n rotate: SkyIconRotateValue = 0;\r\n\r\n @property({ type: Boolean })\r\n lazy = false;\r\n\r\n // Internal state\r\n\r\n @state()\r\n private _svgContent: string | null = null;\r\n\r\n @state()\r\n private _hasSlottedSvg = false;\r\n\r\n private _observer: IntersectionObserver | null = null;\r\n private _visible = false;\r\n\r\n // Lifecycle\r\n\r\n override connectedCallback(): void {\r\n super.connectedCallback();\r\n\r\n if (this.lazy) {\r\n this._startObserver();\r\n } else {\r\n this._visible = true;\r\n if (this.icon && !this._hasSlottedSvg) {\r\n this._loadIcon();\r\n }\r\n }\r\n }\r\n\r\n override disconnectedCallback(): void {\r\n super.disconnectedCallback();\r\n this._stopObserver();\r\n }\r\n\r\n override updated(changed: Map<string, unknown>): void {\r\n // Lazy flag changed: reconfigure observer / visibility\r\n if (changed.has('lazy')) {\r\n if (this.lazy) {\r\n this._startObserver();\r\n } else {\r\n this._stopObserver();\r\n this._visible = true;\r\n if (this.icon && !this._hasSlottedSvg) {\r\n this._loadIcon();\r\n }\r\n }\r\n }\r\n\r\n // Icon changed: reload if visible and no custom SVG, otherwise clear\r\n if (changed.has('icon')) {\r\n if (this._hasSlottedSvg) {\r\n this._setSvgContent(null);\r\n } else if (!this.lazy || this._visible) {\r\n this._loadIcon();\r\n } else {\r\n this._setSvgContent(null);\r\n }\r\n }\r\n }\r\n\r\n private _onSlotChange(e: Event): void {\r\n const slot = e.target as HTMLSlotElement;\r\n const nodes = slot.assignedNodes({ flatten: true });\r\n const hasSvg = nodes.some(\r\n (n) =>\r\n n.nodeType === Node.ELEMENT_NODE && (n as Element).tagName === 'SVG'\r\n );\r\n if (this._hasSlottedSvg !== hasSvg) {\r\n this._hasSlottedSvg = hasSvg;\r\n if (hasSvg && this.icon) {\r\n this._setSvgContent(null);\r\n } else if (!hasSvg && this.icon && (this._visible || !this.lazy)) {\r\n this._loadIcon();\r\n }\r\n }\r\n }\r\n\r\n // Lazy loading\r\n\r\n private _startObserver(): void {\r\n if (typeof window === 'undefined') return;\r\n if (this._observer || !('IntersectionObserver' in window)) return;\r\n\r\n this._observer = new IntersectionObserver((entries) => {\r\n if (entries.some((e) => e.isIntersecting)) {\r\n this._visible = true;\r\n if (!this._hasSlottedSvg && this.icon) {\r\n this._loadIcon();\r\n }\r\n this._stopObserver();\r\n }\r\n });\r\n\r\n this._observer.observe(this);\r\n }\r\n\r\n private _stopObserver(): void {\r\n if (this._observer) {\r\n this._observer.disconnect();\r\n this._observer = null;\r\n }\r\n }\r\n\r\n // State setter (avoids nested update warning)\r\n\r\n private _setSvgContent(svg: string | null): void {\r\n // Avoid unnecessary updates\r\n if (this._svgContent === svg) return;\r\n\r\n // Schedule after current update cycle\r\n if (typeof queueMicrotask === 'function') {\r\n queueMicrotask(() => {\r\n this._svgContent = svg;\r\n });\r\n } else {\r\n // Fallback for environments without queueMicrotask\r\n Promise.resolve().then(() => {\r\n this._svgContent = svg;\r\n });\r\n }\r\n }\r\n\r\n // Icon loading\r\n\r\n private async _loadIcon(): Promise<void> {\r\n const name = this.icon.trim();\r\n if (!name) {\r\n this._setSvgContent(null);\r\n return;\r\n }\r\n\r\n // Cached SVG → still set via microtask to avoid nested update warning\r\n const cached = SkyIcon._iconCache.get(name);\r\n if (cached) {\r\n this._setSvgContent(cached);\r\n return;\r\n }\r\n\r\n let promise = SkyIcon._iconPromiseCache.get(name);\r\n if (!promise) {\r\n promise = this._fetchAndBuild(name);\r\n SkyIcon._iconPromiseCache.set(name, promise);\r\n }\r\n\r\n try {\r\n const svg = await promise;\r\n this._setSvgContent(svg);\r\n if (SkyIcon._iconCache.size >= MAX_ICON_CACHE_SIZE) {\r\n const firstKey = SkyIcon._iconCache.keys().next().value;\r\n if (firstKey != null) SkyIcon._iconCache.delete(firstKey);\r\n }\r\n SkyIcon._iconCache.set(name, svg);\r\n } catch {\r\n this._setSvgContent(null);\r\n } finally {\r\n SkyIcon._iconPromiseCache.delete(name);\r\n }\r\n }\r\n\r\n private async _fetchAndBuild(full: string): Promise<string> {\r\n const [prefix, iconName] = full.split(':');\r\n if (!prefix || !iconName) throw new Error('Invalid icon name');\r\n\r\n // 1) Single local icon (e.g. registerLocalIcon('ion:heart', {...}))\r\n const singleLocal = SkyIcon._localIcons.get(full);\r\n if (singleLocal) {\r\n return this._buildSvg(singleLocal, {});\r\n }\r\n\r\n // 2) Local set (e.g. registerLocalSet('ion', { icons: { home: {...} } }))\r\n const localSet = SkyIcon._localSets.get(prefix);\r\n if (localSet?.icons?.[iconName]) {\r\n return this._buildSvg(localSet.icons[iconName], localSet);\r\n }\r\n\r\n // 3) Fetch from Iconify API\r\n const url = `https://api.iconify.design/${prefix}.json?icons=${iconName}`;\r\n const res = await fetch(url);\r\n if (!res.ok) throw new Error('Failed to fetch icon set');\r\n\r\n const json = (await res.json()) as {\r\n icons?: Record<string, IconifyIcon>;\r\n left?: number;\r\n top?: number;\r\n width?: number;\r\n height?: number;\r\n };\r\n\r\n const data = json.icons?.[iconName];\r\n if (!data) throw new Error('Icon not found');\r\n\r\n return this._buildSvg(data, json);\r\n }\r\n\r\n private _buildSvg(icon: IconifyIcon, set: IconifyCollection): string {\r\n const body = icon.body ?? '';\r\n const l = icon.left ?? set.left ?? 0;\r\n const t = icon.top ?? set.top ?? 0;\r\n const w = icon.width ?? set.width ?? 24;\r\n const h = icon.height ?? set.height ?? 24;\r\n const viewBox = icon.viewBox || `${l} ${t} ${w} ${h}`;\r\n\r\n return `\r\n <svg xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"${viewBox}\"\r\n width=\"100%\"\r\n height=\"100%\"\r\n preserveAspectRatio=\"xMidYMid meet\"\r\n fill=\"currentColor\">\r\n ${body}\r\n </svg>\r\n `;\r\n }\r\n\r\n // Style helpers\r\n\r\n private _normalize(v: string | number): string {\r\n if (typeof v === 'number') return `${v}px`;\r\n if (/^\\d+$/.test(v)) return `${v}px`;\r\n return v;\r\n }\r\n\r\n private _rotationDeg(): number {\r\n const v = this.rotate;\r\n if (typeof v === 'number') return v * 90;\r\n if (typeof v === 'string') {\r\n if (v.endsWith('deg')) return parseFloat(v);\r\n const n = parseInt(v, 10);\r\n return Number.isFinite(n) ? n * 90 : 0;\r\n }\r\n return 0;\r\n }\r\n\r\n private _flipHas(val: 'horizontal' | 'vertical'): boolean {\r\n return this.flip\r\n .split(',')\r\n .map((v) => v.trim().toLowerCase())\r\n .includes(val);\r\n }\r\n\r\n private _transform(): string {\r\n const deg = this._rotationDeg();\r\n const h = this.hFlip || this._flipHas('horizontal');\r\n const v = this.vFlip || this._flipHas('vertical');\r\n\r\n const tr: string[] = [];\r\n if (deg) tr.push(`rotate(${deg}deg)`);\r\n if (h || v) tr.push(`scale(${h ? -1 : 1}, ${v ? -1 : 1})`);\r\n\r\n return tr.join(' ');\r\n }\r\n\r\n private _baseStyle(): Record<string, string> {\r\n const style: Record<string, string> = { color: resolveColor(this.color) };\r\n\r\n if (this.width) style.width = this._normalize(this.width);\r\n if (this.height) style.height = this._normalize(this.height);\r\n\r\n if (!this.width && !this.height) {\r\n style.width = '1em';\r\n style.height = '1em';\r\n }\r\n if (this.inline) style.verticalAlign = '-0.125em';\r\n\r\n return style;\r\n }\r\n\r\n // Render\r\n\r\n override render() {\r\n const style = this._baseStyle();\r\n const tf = this._transform();\r\n if (tf) style.transform = tf;\r\n\r\n const showIconify = !this._hasSlottedSvg && this.icon && this._svgContent;\r\n\r\n /* Iconify (API) path: same structure as before — single .icon div with innerHTML, no wrapper */\r\n if (showIconify) {\r\n return html`\r\n <div\r\n class=\"icon\"\r\n style=${styleMap(style)}\r\n part=\"icon\"\r\n .innerHTML=${this._svgContent!}\r\n ></div>\r\n `;\r\n }\r\n\r\n /* Custom SVG slot or empty: render slot for detection and display */\r\n return html`\r\n <div class=\"icon\" style=${styleMap(style)} part=\"icon\">\r\n <slot @slotchange=${this._onSlotChange}></slot>\r\n </div>\r\n `;\r\n }\r\n}\r\n\r\n// Register default local set (ion from ion-local.json); users can add more via SkyIcon.registerLocalSet / registerLocalIcon\r\nconst defaultSet = skyLocalSetData as IconifySetData;\r\nif (defaultSet?.icons) {\r\n SkyIcon.registerLocalSet('ion', defaultSet);\r\n}\r\n"],"names":["SkyIcon","LitElement","constructor","super","arguments","this","preset","_presets","PresetController","icon","width","height","color","inline","flip","hFlip","vFlip","rotate","lazy","_svgContent","_hasSlottedSvg","_observer","_visible","registerLocalSet","prefix","data","_localSets","set","key","_iconCache","keys","startsWith","delete","registerLocalIcon","fullName","_localIcons","connectedCallback","_startObserver","_loadIcon","disconnectedCallback","_stopObserver","updated","changed","has","_setSvgContent","_onSlotChange","e","hasSvg","target","assignedNodes","flatten","some","n","nodeType","Node","ELEMENT_NODE","tagName","window","IntersectionObserver","entries","isIntersecting","observe","disconnect","svg","queueMicrotask","Promise","resolve","then","name","trim","cached","get","promise","_iconPromiseCache","_fetchAndBuild","size","firstKey","next","value","full","iconName","split","Error","singleLocal","_buildSvg","localSet","icons","url","res","fetch","ok","json","body","l","left","t","top","w","h","viewBox","_normalize","v","test","_rotationDeg","endsWith","parseFloat","parseInt","Number","isFinite","_flipHas","val","map","toLowerCase","includes","_transform","deg","tr","push","join","_baseStyle","style","resolveColor","verticalAlign","render","tf","transform","html","styleMap","Map","styles","css","__decorateClass","property","type","String","reflect","prototype","Boolean","state","customElement","defaultSet","skyLocalSetData"],"mappings":"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"}
|