@sky.ui/core 0.0.40 → 0.0.42
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 +2011 -1275
- package/dist/helper/controllers/animation-controller.d.ts +4 -4
- package/dist/helper/controllers/animation-controller.js.map +1 -1
- package/dist/helper/controllers/index.d.ts +1 -0
- package/dist/helper/controllers/index.js +1 -1
- package/dist/helper/controllers/popover-controller.d.ts +12 -12
- package/dist/helper/controllers/popover-controller.js.map +1 -1
- package/dist/helper/controllers/preset-controller.d.ts +55 -0
- package/dist/helper/controllers/preset-controller.js +2 -0
- package/dist/helper/controllers/preset-controller.js.map +1 -0
- package/dist/helper/iconify-offline.js.map +1 -1
- package/dist/helper/index.js +1 -1
- package/dist/helper/internals/form-control-base.d.ts +6 -6
- package/dist/helper/internals/form-control-base.js.map +1 -1
- package/dist/helper/styles/focus-ring.d.ts +10 -0
- package/dist/helper/styles/focus-ring.js +10 -0
- package/dist/helper/styles/focus-ring.js.map +1 -0
- package/dist/helper/utils/color-resolver.d.ts +0 -14
- package/dist/helper/utils/color-resolver.js +1 -1
- package/dist/helper/utils/color-resolver.js.map +1 -1
- package/dist/helper/utils/component-presets.d.ts +132 -0
- package/dist/helper/utils/component-presets.js +2 -0
- package/dist/helper/utils/component-presets.js.map +1 -0
- package/dist/helper/utils/contrast-color.d.ts +6 -6
- package/dist/helper/utils/contrast-color.js.map +1 -1
- package/dist/helper/utils/index.d.ts +1 -0
- package/dist/helper/utils/index.js +1 -1
- package/dist/helper/utils/size-resolver.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/sky-alert/sky-alert.d.ts +15 -7
- package/dist/sky-alert/sky-alert.js +10 -20
- package/dist/sky-alert/sky-alert.js.map +1 -1
- package/dist/sky-appbar/sky-appbar.d.ts +9 -3
- package/dist/sky-appbar/sky-appbar.js +27 -19
- package/dist/sky-appbar/sky-appbar.js.map +1 -1
- package/dist/sky-avatar/sky-avatar.d.ts +6 -2
- package/dist/sky-avatar/sky-avatar.js +17 -14
- package/dist/sky-avatar/sky-avatar.js.map +1 -1
- package/dist/sky-badge/sky-badge.d.ts +9 -5
- package/dist/sky-badge/sky-badge.js +12 -16
- package/dist/sky-badge/sky-badge.js.map +1 -1
- package/dist/sky-button/sky-button.d.ts +27 -7
- package/dist/sky-button/sky-button.js +24 -32
- package/dist/sky-button/sky-button.js.map +1 -1
- package/dist/sky-card/sky-card.d.ts +13 -5
- package/dist/sky-card/sky-card.js +24 -24
- package/dist/sky-card/sky-card.js.map +1 -1
- package/dist/sky-checkbox/sky-checkbox.d.ts +6 -3
- package/dist/sky-checkbox/sky-checkbox.js +43 -44
- package/dist/sky-checkbox/sky-checkbox.js.map +1 -1
- package/dist/sky-chip/sky-chip.d.ts +7 -3
- package/dist/sky-chip/sky-chip.js +35 -43
- package/dist/sky-chip/sky-chip.js.map +1 -1
- package/dist/sky-col/sky-col.d.ts +7 -3
- package/dist/sky-col/sky-col.js +6 -11
- package/dist/sky-col/sky-col.js.map +1 -1
- package/dist/sky-combobox/sky-combobox.d.ts +15 -8
- package/dist/sky-combobox/sky-combobox.js +193 -257
- package/dist/sky-combobox/sky-combobox.js.map +1 -1
- package/dist/sky-dialog/sky-dialog.d.ts +7 -3
- package/dist/sky-dialog/sky-dialog.js +22 -20
- package/dist/sky-dialog/sky-dialog.js.map +1 -1
- package/dist/sky-divider/sky-divider.d.ts +6 -2
- package/dist/sky-divider/sky-divider.js +5 -5
- package/dist/sky-divider/sky-divider.js.map +1 -1
- package/dist/sky-flexbox/sky-flexbox.d.ts +10 -6
- package/dist/sky-flexbox/sky-flexbox.js +6 -6
- package/dist/sky-flexbox/sky-flexbox.js.map +1 -1
- package/dist/sky-flexcol/sky-flexcol.d.ts +6 -2
- package/dist/sky-flexcol/sky-flexcol.js +2 -2
- package/dist/sky-flexcol/sky-flexcol.js.map +1 -1
- package/dist/sky-form/sky-form.d.ts +15 -11
- package/dist/sky-form/sky-form.js +14 -14
- package/dist/sky-form/sky-form.js.map +1 -1
- package/dist/sky-grid/sky-grid.d.ts +5 -1
- package/dist/sky-grid/sky-grid.js +3 -3
- package/dist/sky-grid/sky-grid.js.map +1 -1
- package/dist/sky-icon/sky-icon.d.ts +3 -0
- package/dist/sky-icon/sky-icon.js +4 -4
- package/dist/sky-icon/sky-icon.js.map +1 -1
- package/dist/sky-image/sky-image.d.ts +8 -4
- package/dist/sky-image/sky-image.js +5 -5
- 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.d.ts +9 -5
- package/dist/sky-input/sky-input.js +155 -170
- package/dist/sky-input/sky-input.js.map +1 -1
- package/dist/sky-list/sky-list.d.ts +7 -3
- package/dist/sky-list/sky-list.js +6 -4
- package/dist/sky-list/sky-list.js.map +1 -1
- package/dist/sky-listitem/sky-listitem.d.ts +5 -1
- package/dist/sky-listitem/sky-listitem.js +10 -7
- package/dist/sky-listitem/sky-listitem.js.map +1 -1
- package/dist/sky-radio/sky-radio.d.ts +9 -4
- package/dist/sky-radio/sky-radio.js +7 -9
- package/dist/sky-radio/sky-radio.js.map +1 -1
- package/dist/sky-row/sky-row.d.ts +4 -1
- package/dist/sky-row/sky-row.js +2 -2
- package/dist/sky-row/sky-row.js.map +1 -1
- package/dist/sky-sheet/sky-sheet.d.ts +11 -6
- package/dist/sky-sheet/sky-sheet.js +23 -23
- package/dist/sky-sheet/sky-sheet.js.map +1 -1
- package/dist/sky-simple-table/sky-simple-table.d.ts +7 -3
- package/dist/sky-simple-table/sky-simple-table.js +4 -7
- package/dist/sky-simple-table/sky-simple-table.js.map +1 -1
- package/dist/sky-theme-provider/sky-theme-provider.d.ts +26 -26
- package/dist/sky-theme-provider/sky-theme-provider.js +2 -2
- package/dist/sky-theme-provider/sky-theme-provider.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sky-grid.js","sources":["../../src/sky-grid/sky-grid.ts"],"sourcesContent":["import { LitElement, html, css } from
|
|
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"}
|
|
@@ -88,6 +88,9 @@ export declare class SkyIcon extends LitElement {
|
|
|
88
88
|
* @param icon - Icon data (body, width, height, viewBox, etc.).
|
|
89
89
|
*/
|
|
90
90
|
static registerLocalIcon(fullName: string, icon: IconifyIcon): void;
|
|
91
|
+
/** Named prop preset from nearest `sky-config-provider`. */
|
|
92
|
+
preset: string;
|
|
93
|
+
private _presets;
|
|
91
94
|
static styles: import("lit").CSSResult;
|
|
92
95
|
icon: string;
|
|
93
96
|
width: SkyIconSizeValue;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{css as t,LitElement as e,html as i}from"lit";import{property as s,state as o,customElement as n}from"lit/decorators.js";import{styleMap as r}from"lit/directives/style-map.js";import{resolveColor as h}from"../helper/utils/color-resolver.js";import l from"./ion-local.json.js";var
|
|
1
|
+
import{css as t,LitElement as e,html as i}from"lit";import{property as s,state as o,customElement as n}from"lit/decorators.js";import{styleMap as r}from"lit/directives/style-map.js";import{resolveColor as h}from"../helper/utils/color-resolver.js";import l from"./ion-local.json.js";import{PresetController as c}from"../helper/controllers/preset-controller.js";var a=Object.defineProperty,p=Object.getOwnPropertyDescriptor,_=(t,e,i,s)=>{for(var o,n=s>1?void 0:s?p(e,i):e,r=t.length-1;r>=0;r--)(o=t[r])&&(n=(s?o(e,i,n):o(n))||n);return s&&n&&a(e,i,n),n};let d=class extends e{constructor(){super(...arguments),this.preset="",this._presets=new c(this),this.icon="",this.width="",this.height="",this.color="currentColor",this.inline=!1,this.flip="",this.hFlip=!1,this.vFlip=!1,this.rotate=0,this.lazy=!1,this._svgContent=null,this._hasSlottedSvg=!1,this._observer=null,this._visible=!1}static registerLocalSet(t,e){d._localSets.set(t,e);for(const e of d._iconCache.keys())e.startsWith(t+":")&&d._iconCache.delete(e)}static registerLocalIcon(t,e){d._localIcons.set(t,e),d._iconCache.delete(t)}connectedCallback(){super.connectedCallback(),this.lazy?this._startObserver():(this._visible=!0,this.icon&&!this._hasSlottedSvg&&this._loadIcon())}disconnectedCallback(){super.disconnectedCallback(),this._stopObserver()}updated(t){t.has("lazy")&&(this.lazy?this._startObserver():(this._stopObserver(),this._visible=!0,this.icon&&!this._hasSlottedSvg&&this._loadIcon())),t.has("icon")&&(this._hasSlottedSvg?this._setSvgContent(null):!this.lazy||this._visible?this._loadIcon():this._setSvgContent(null))}_onSlotChange(t){const e=t.target.assignedNodes({flatten:!0}).some(t=>t.nodeType===Node.ELEMENT_NODE&&"SVG"===t.tagName);this._hasSlottedSvg!==e&&(this._hasSlottedSvg=e,e&&this.icon?this._setSvgContent(null):e||!this.icon||!this._visible&&this.lazy||this._loadIcon())}_startObserver(){"undefined"!=typeof window&&!this._observer&&"IntersectionObserver"in window&&(this._observer=new IntersectionObserver(t=>{t.some(t=>t.isIntersecting)&&(this._visible=!0,!this._hasSlottedSvg&&this.icon&&this._loadIcon(),this._stopObserver())}),this._observer.observe(this))}_stopObserver(){this._observer&&(this._observer.disconnect(),this._observer=null)}_setSvgContent(t){this._svgContent!==t&&("function"==typeof queueMicrotask?queueMicrotask(()=>{this._svgContent=t}):Promise.resolve().then(()=>{this._svgContent=t}))}async _loadIcon(){const t=this.icon.trim();if(!t)return void this._setSvgContent(null);const e=d._iconCache.get(t);if(e)return void this._setSvgContent(e);let i=d._iconPromiseCache.get(t);i||(i=this._fetchAndBuild(t),d._iconPromiseCache.set(t,i));try{const e=await i;if(this._setSvgContent(e),d._iconCache.size>=100){const t=d._iconCache.keys().next().value;null!=t&&d._iconCache.delete(t)}d._iconCache.set(t,e)}catch{this._setSvgContent(null)}finally{d._iconPromiseCache.delete(t)}}async _fetchAndBuild(t){const[e,i]=t.split(":");if(!e||!i)throw new Error("Invalid icon name");const s=d._localIcons.get(t);if(s)return this._buildSvg(s,{});const o=d._localSets.get(e);if(o?.icons?.[i])return this._buildSvg(o.icons[i],o);const n=`https://api.iconify.design/${e}.json?icons=${i}`,r=await fetch(n);if(!r.ok)throw new Error("Failed to fetch icon set");const h=await r.json(),l=h.icons?.[i];if(!l)throw new Error("Icon not found");return this._buildSvg(l,h)}_buildSvg(t,e){const i=t.body??"",s=t.left??e.left??0,o=t.top??e.top??0,n=t.width??e.width??24,r=t.height??e.height??24;return`\n <svg xmlns="http://www.w3.org/2000/svg"\n viewBox="${t.viewBox||`${s} ${o} ${n} ${r}`}"\n width="100%"\n height="100%"\n preserveAspectRatio="xMidYMid meet"\n fill="currentColor">\n ${i}\n </svg>\n `}_normalize(t){return"number"==typeof t||/^\d+$/.test(t)?`${t}px`:t}_rotationDeg(){const t=this.rotate;if("number"==typeof t)return 90*t;if("string"==typeof t){if(t.endsWith("deg"))return parseFloat(t);const e=parseInt(t,10);return Number.isFinite(e)?90*e:0}return 0}_flipHas(t){return this.flip.split(",").map(t=>t.trim().toLowerCase()).includes(t)}_transform(){const t=this._rotationDeg(),e=this.hFlip||this._flipHas("horizontal"),i=this.vFlip||this._flipHas("vertical"),s=[];return t&&s.push(`rotate(${t}deg)`),(e||i)&&s.push(`scale(${e?-1:1}, ${i?-1:1})`),s.join(" ")}_baseStyle(){const t={color:h(this.color)};return this.width&&(t.width=this._normalize(this.width)),this.height&&(t.height=this._normalize(this.height)),this.width||this.height||(t.width="1em",t.height="1em"),this.inline&&(t.verticalAlign="-0.125em"),t}render(){const t=this._baseStyle(),e=this._transform();e&&(t.transform=e);return!this._hasSlottedSvg&&this.icon&&this._svgContent?i`
|
|
2
2
|
<div
|
|
3
3
|
class="icon"
|
|
4
4
|
style=${r(t)}
|
|
@@ -9,14 +9,14 @@ import{css as t,LitElement as e,html as i}from"lit";import{property as s,state a
|
|
|
9
9
|
<div class="icon" style=${r(t)} part="icon">
|
|
10
10
|
<slot @slotchange=${this._onSlotChange}></slot>
|
|
11
11
|
</div>
|
|
12
|
-
`}};
|
|
12
|
+
`}};d._iconCache=new Map,d._iconPromiseCache=new Map,d._localSets=new Map,d._localIcons=new Map,d.styles=t`
|
|
13
13
|
:host {
|
|
14
14
|
display: inline-flex;
|
|
15
15
|
align-items: center;
|
|
16
16
|
justify-content: center;
|
|
17
17
|
vertical-align: middle;
|
|
18
18
|
}
|
|
19
|
-
|
|
19
|
+
.icon {
|
|
20
20
|
display: flex;
|
|
21
21
|
align-items: center;
|
|
22
22
|
justify-content: center;
|
|
@@ -36,5 +36,5 @@ import{css as t,LitElement as e,html as i}from"lit";import{property as s,state a
|
|
|
36
36
|
flex-shrink: 0;
|
|
37
37
|
fill: currentColor;
|
|
38
38
|
}
|
|
39
|
-
`,
|
|
39
|
+
`,_([s({type:String,reflect:!0})],d.prototype,"preset",2),_([s({type:String})],d.prototype,"icon",2),_([s({type:String})],d.prototype,"width",2),_([s({type:String})],d.prototype,"height",2),_([s({type:String})],d.prototype,"color",2),_([s({type:Boolean})],d.prototype,"inline",2),_([s({type:String})],d.prototype,"flip",2),_([s({type:Boolean})],d.prototype,"hFlip",2),_([s({type:Boolean})],d.prototype,"vFlip",2),_([s({type:String})],d.prototype,"rotate",2),_([s({type:Boolean})],d.prototype,"lazy",2),_([o()],d.prototype,"_svgContent",2),_([o()],d.prototype,"_hasSlottedSvg",2),d=_([n("sky-icon")],d);const g=l;g?.icons&&d.registerLocalSet("ion",g);export{d as SkyIcon};
|
|
40
40
|
//# sourceMappingURL=sky-icon.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sky-icon.js","sources":["../../src/sky-icon/sky-icon.ts"],"sourcesContent":["import { LitElement, html, css } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { styleMap } from 'lit/directives/style-map.js';\nimport { resolveColor } from '../helper/utils/color-resolver';\nimport skyLocalSetData from './ion-local.json';\n\nexport type SkyIconSizeValue = string | number;\nexport type SkyIconRotateValue = string | number;\nexport type SkyIconFlip =\n '' | 'horizontal' | 'vertical' | 'horizontal,vertical';\n\ninterface IconifyCollection {\n left?: number;\n top?: number;\n width?: number;\n height?: number;\n}\n\ninterface IconifySetData extends IconifyCollection {\n icons?: Record<string, IconifyIcon>;\n}\n\ninterface IconifyIcon {\n body?: string;\n left?: number;\n top?: number;\n width?: number;\n height?: number;\n viewBox?: string;\n}\n\nconst MAX_ICON_CACHE_SIZE = 100;\n\n/**\n * @element sky-icon\n *\n * @summary Icon renderer with Iconify fetch/caching, lazy loading, and optional slotted SVG fallback.\n *\n * @status stable\n * @since 1.0.0\n *\n * @documentation https://sky-ui.com/components/icon\n *\n * @slot - Optional fallback `<svg>` content when remote icon data is unavailable.\n * @property {string} icon - Icon name in `prefix:icon-name` format.\n * @property {SkyIconSizeValue} width - Icon width value.\n * @property {SkyIconSizeValue} height - Icon height value.\n * @property {string} color - Icon color value.\n * @property {boolean} inline - Applies inline alignment behavior for text contexts.\n * @property {SkyIconFlip} flip - Flip transform descriptor.\n * @property {boolean} hFlip - Horizontal flip shortcut.\n * @property {boolean} vFlip - Vertical flip shortcut.\n * @property {SkyIconRotateValue} rotate - Rotation descriptor.\n * @property {boolean} lazy - Defers loading until the icon is visible.\n *\n * @method registerLocalSet Registers a local Iconify set for offline/custom usage.\n * @method registerLocalIcon Registers a single local icon override.\n *\n * @csspart icon - The icon container element.\n * @csspart svg - The rendered SVG element.\n *\n * @Behavior\n * - Resolves icons from local registrations first, then Iconify API.\n * - Uses bounded in-memory caching for fetched SVG payloads.\n * - Supports custom slotted SVG fallback when external fetch fails or is blocked.\n *\n * @example\n * ```html\n * <sky-icon icon=\"ion:home\" width=\"24\" height=\"24\" color=\"#3b82f6\"></sky-icon>\n * ```\n * ```vue\n * <template>\n * <sky-icon icon=\"ion:home\" width=\"24\" height=\"24\" color=\"#3b82f6\"></sky-icon>\n * </template>\n * ```\n * ```jsx\n * export default function Demo() {\n * return <sky-icon icon=\"ion:home\" width=\"24\" height=\"24\" color=\"#3b82f6\"></sky-icon>;\n * }\n * ```\n */\n@customElement('sky-icon')\nexport class SkyIcon extends LitElement {\n /** Cache: icon name -> final SVG string (bounded by MAX_ICON_CACHE_SIZE, LRU eviction). */\n private static _iconCache = new Map<string, string>();\n\n /** Cache for in-flight fetches: icon name -> Promise<svg> */\n private static _iconPromiseCache = new Map<string, Promise<string>>();\n\n /** Local icon sets (prefix -> Iconify set data) for offline/custom icons */\n private static _localSets = new Map<string, IconifySetData>();\n\n /** Single local icons (full name -> icon data) */\n private static _localIcons = new Map<string, IconifyIcon>();\n\n /**\n * Register a local icon set (Iconify-compatible JSON) for offline or custom icons.\n * @param prefix - Set prefix (e.g. \"ion\", \"custom\"); use as icon=\"prefix:iconName\".\n * @param data - Set data with `icons` and optional defaults (width, height, left, top).\n */\n static registerLocalSet(prefix: string, data: IconifySetData): void {\n SkyIcon._localSets.set(prefix, data);\n for (const key of SkyIcon._iconCache.keys()) {\n if (key.startsWith(prefix + ':')) SkyIcon._iconCache.delete(key);\n }\n }\n\n /**\n * Register a single local icon (one-off custom icon without a full set).\n * @param fullName - Full icon name, e.g. \"ion:heart\".\n * @param icon - Icon data (body, width, height, viewBox, etc.).\n */\n static registerLocalIcon(fullName: string, icon: IconifyIcon): void {\n SkyIcon._localIcons.set(fullName, icon);\n SkyIcon._iconCache.delete(fullName);\n }\n\n static styles = css`\n :host {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n vertical-align: middle;\n }\n .icon {\n display: flex;\n align-items: center;\n justify-content: center;\n line-height: 1;\n }\n .icon svg {\n display: block;\n width: 100%;\n height: 100%;\n flex-shrink: 0;\n }\n /* Custom SVG in slot: inherit size and color */\n .icon::slotted(svg) {\n display: block;\n width: 100%;\n height: 100%;\n flex-shrink: 0;\n fill: currentColor;\n }\n `;\n\n // ========================================================================\n // Iconify-style public props\n // ========================================================================\n\n @property({ type: String })\n icon = '';\n\n @property({ type: String })\n width: SkyIconSizeValue = '';\n\n @property({ type: String })\n height: SkyIconSizeValue = '';\n\n @property({ type: String })\n color = 'currentColor';\n\n @property({ type: Boolean })\n inline = false;\n\n @property({ type: String })\n flip: SkyIconFlip = '';\n\n @property({ type: Boolean })\n hFlip = false;\n\n @property({ type: Boolean })\n vFlip = false;\n\n @property({ type: String })\n rotate: SkyIconRotateValue = 0;\n\n @property({ type: Boolean })\n lazy = false;\n\n // ========================================================================\n // Internal state\n // ========================================================================\n\n @state()\n private _svgContent: string | null = null;\n\n @state()\n private _hasSlottedSvg = false;\n\n private _observer: IntersectionObserver | null = null;\n private _visible = false;\n\n // ========================================================================\n // Lifecycle\n // ========================================================================\n\n override connectedCallback(): void {\n super.connectedCallback();\n\n if (this.lazy) {\n this._startObserver();\n } else {\n this._visible = true;\n if (this.icon && !this._hasSlottedSvg) {\n this._loadIcon();\n }\n }\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this._stopObserver();\n }\n\n override updated(changed: Map<string, unknown>): void {\n // Lazy flag changed: reconfigure observer / visibility\n if (changed.has('lazy')) {\n if (this.lazy) {\n this._startObserver();\n } else {\n this._stopObserver();\n this._visible = true;\n if (this.icon && !this._hasSlottedSvg) {\n this._loadIcon();\n }\n }\n }\n\n // Icon changed: reload if visible and no custom SVG, otherwise clear\n if (changed.has('icon')) {\n if (this._hasSlottedSvg) {\n this._setSvgContent(null);\n } else if (!this.lazy || this._visible) {\n this._loadIcon();\n } else {\n this._setSvgContent(null);\n }\n }\n }\n\n private _onSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n const nodes = slot.assignedNodes({ flatten: true });\n const hasSvg = nodes.some(\n (n) =>\n n.nodeType === Node.ELEMENT_NODE && (n as Element).tagName === 'SVG'\n );\n if (this._hasSlottedSvg !== hasSvg) {\n this._hasSlottedSvg = hasSvg;\n if (hasSvg && this.icon) {\n this._setSvgContent(null);\n } else if (!hasSvg && this.icon && (this._visible || !this.lazy)) {\n this._loadIcon();\n }\n }\n }\n\n // ========================================================================\n // Lazy loading\n // ========================================================================\n\n private _startObserver(): void {\n if (typeof window === 'undefined') return;\n if (this._observer || !('IntersectionObserver' in window)) return;\n\n this._observer = new IntersectionObserver((entries) => {\n if (entries.some((e) => e.isIntersecting)) {\n this._visible = true;\n if (!this._hasSlottedSvg && this.icon) {\n this._loadIcon();\n }\n this._stopObserver();\n }\n });\n\n this._observer.observe(this);\n }\n\n private _stopObserver(): void {\n if (this._observer) {\n this._observer.disconnect();\n this._observer = null;\n }\n }\n\n // ========================================================================\n // State setter (avoids nested update warning)\n // ========================================================================\n\n private _setSvgContent(svg: string | null): void {\n // Avoid unnecessary updates\n if (this._svgContent === svg) return;\n\n // Schedule after current update cycle\n if (typeof queueMicrotask === 'function') {\n queueMicrotask(() => {\n this._svgContent = svg;\n });\n } else {\n // Fallback for environments without queueMicrotask\n Promise.resolve().then(() => {\n this._svgContent = svg;\n });\n }\n }\n\n // ========================================================================\n // Icon loading\n // ========================================================================\n\n private async _loadIcon(): Promise<void> {\n const name = this.icon.trim();\n if (!name) {\n this._setSvgContent(null);\n return;\n }\n\n // Cached SVG → still set via microtask to avoid nested update warning\n const cached = SkyIcon._iconCache.get(name);\n if (cached) {\n this._setSvgContent(cached);\n return;\n }\n\n let promise = SkyIcon._iconPromiseCache.get(name);\n if (!promise) {\n promise = this._fetchAndBuild(name);\n SkyIcon._iconPromiseCache.set(name, promise);\n }\n\n try {\n const svg = await promise;\n this._setSvgContent(svg);\n if (SkyIcon._iconCache.size >= MAX_ICON_CACHE_SIZE) {\n const firstKey = SkyIcon._iconCache.keys().next().value;\n if (firstKey != null) SkyIcon._iconCache.delete(firstKey);\n }\n SkyIcon._iconCache.set(name, svg);\n } catch {\n this._setSvgContent(null);\n } finally {\n SkyIcon._iconPromiseCache.delete(name);\n }\n }\n\n private async _fetchAndBuild(full: string): Promise<string> {\n const [prefix, iconName] = full.split(':');\n if (!prefix || !iconName) throw new Error('Invalid icon name');\n\n // 1) Single local icon (e.g. registerLocalIcon('ion:heart', {...}))\n const singleLocal = SkyIcon._localIcons.get(full);\n if (singleLocal) {\n return this._buildSvg(singleLocal, {});\n }\n\n // 2) Local set (e.g. registerLocalSet('ion', { icons: { home: {...} } }))\n const localSet = SkyIcon._localSets.get(prefix);\n if (localSet?.icons?.[iconName]) {\n return this._buildSvg(localSet.icons[iconName], localSet);\n }\n\n // 3) Fetch from Iconify API\n const url = `https://api.iconify.design/${prefix}.json?icons=${iconName}`;\n const res = await fetch(url);\n if (!res.ok) throw new Error('Failed to fetch icon set');\n\n const json = (await res.json()) as {\n icons?: Record<string, IconifyIcon>;\n left?: number;\n top?: number;\n width?: number;\n height?: number;\n };\n\n const data = json.icons?.[iconName];\n if (!data) throw new Error('Icon not found');\n\n return this._buildSvg(data, json);\n }\n\n private _buildSvg(icon: IconifyIcon, set: IconifyCollection): string {\n const body = icon.body ?? '';\n const l = icon.left ?? set.left ?? 0;\n const t = icon.top ?? set.top ?? 0;\n const w = icon.width ?? set.width ?? 24;\n const h = icon.height ?? set.height ?? 24;\n const viewBox = icon.viewBox || `${l} ${t} ${w} ${h}`;\n\n return `\n <svg xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"${viewBox}\"\n width=\"100%\"\n height=\"100%\"\n preserveAspectRatio=\"xMidYMid meet\"\n fill=\"currentColor\">\n ${body}\n </svg>\n `;\n }\n\n // ========================================================================\n // Style helpers\n // ========================================================================\n\n private _normalize(v: string | number): string {\n if (typeof v === 'number') return `${v}px`;\n if (/^\\d+$/.test(v)) return `${v}px`;\n return v;\n }\n\n private _rotationDeg(): number {\n const v = this.rotate;\n if (typeof v === 'number') return v * 90;\n if (typeof v === 'string') {\n if (v.endsWith('deg')) return parseFloat(v);\n const n = parseInt(v, 10);\n return Number.isFinite(n) ? n * 90 : 0;\n }\n return 0;\n }\n\n private _flipHas(val: 'horizontal' | 'vertical'): boolean {\n return this.flip\n .split(',')\n .map((v) => v.trim().toLowerCase())\n .includes(val);\n }\n\n private _transform(): string {\n const deg = this._rotationDeg();\n const h = this.hFlip || this._flipHas('horizontal');\n const v = this.vFlip || this._flipHas('vertical');\n\n const tr: string[] = [];\n if (deg) tr.push(`rotate(${deg}deg)`);\n if (h || v) tr.push(`scale(${h ? -1 : 1}, ${v ? -1 : 1})`);\n\n return tr.join(' ');\n }\n\n private _baseStyle(): Record<string, string> {\n const style: Record<string, string> = { color: resolveColor(this.color) };\n\n if (this.width) style.width = this._normalize(this.width);\n if (this.height) style.height = this._normalize(this.height);\n\n if (!this.width && !this.height) {\n style.width = '1em';\n style.height = '1em';\n }\n if (this.inline) style.verticalAlign = '-0.125em';\n\n return style;\n }\n\n // ========================================================================\n // Render\n // ========================================================================\n\n override render() {\n const style = this._baseStyle();\n const tf = this._transform();\n if (tf) style.transform = tf;\n\n const showIconify = !this._hasSlottedSvg && this.icon && this._svgContent;\n\n /* Iconify (API) path: same structure as before — single .icon div with innerHTML, no wrapper */\n if (showIconify) {\n return html`\n <div\n class=\"icon\"\n style=${styleMap(style)}\n part=\"icon\"\n .innerHTML=${this._svgContent!}\n ></div>\n `;\n }\n\n /* Custom SVG slot or empty: render slot for detection and display */\n return html`\n <div class=\"icon\" style=${styleMap(style)} part=\"icon\">\n <slot @slotchange=${this._onSlotChange}></slot>\n </div>\n `;\n }\n}\n\n// Register default local set (ion from ion-local.json); users can add more via SkyIcon.registerLocalSet / registerLocalIcon\nconst defaultSet = skyLocalSetData as IconifySetData;\nif (defaultSet?.icons) {\n SkyIcon.registerLocalSet('ion', defaultSet);\n}\n"],"names":["SkyIcon","LitElement","constructor","super","arguments","this","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","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 = '' | '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,7 +1,7 @@
|
|
|
1
|
-
import { LitElement } from
|
|
2
|
-
import type { PropertyValues } from
|
|
3
|
-
export type SkyImageLoading =
|
|
4
|
-
export type SkyImageDecoding =
|
|
1
|
+
import { LitElement } from "lit";
|
|
2
|
+
import type { PropertyValues } from "lit";
|
|
3
|
+
export type SkyImageLoading = "lazy" | "eager";
|
|
4
|
+
export type SkyImageDecoding = "async" | "sync" | "auto";
|
|
5
5
|
/**
|
|
6
6
|
* @element sky-image
|
|
7
7
|
*
|
|
@@ -27,6 +27,7 @@ export type SkyImageDecoding = 'async' | 'sync' | 'auto';
|
|
|
27
27
|
* @property {boolean} autoSizes - Computes `sizes` from host width when true.
|
|
28
28
|
* @property {SkyImageLoading} loading - Native loading hint.
|
|
29
29
|
* @property {SkyImageDecoding} decoding - Native decoding hint.
|
|
30
|
+
* @property {string} preset - Named prop preset from nearest `sky-config-provider`. Default: `""`.
|
|
30
31
|
*
|
|
31
32
|
* @csspart img - The underlying `<img>` element.
|
|
32
33
|
*
|
|
@@ -93,6 +94,9 @@ export declare class SkyImage extends LitElement {
|
|
|
93
94
|
private _computedSizes;
|
|
94
95
|
loading: SkyImageLoading;
|
|
95
96
|
decoding: SkyImageDecoding;
|
|
97
|
+
/** Named prop preset from nearest `sky-config-provider`. */
|
|
98
|
+
preset: string;
|
|
99
|
+
private _presets;
|
|
96
100
|
static styles: import("lit").CSSResult;
|
|
97
101
|
private _ro?;
|
|
98
102
|
private _sizesRafId;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{css as t,LitElement as e,html as s,nothing as i}from"lit";import{property as r,state as o,customElement as
|
|
1
|
+
import{css as t,LitElement as e,html as s,nothing as i}from"lit";import{property as r,state as o,customElement as c}from"lit/decorators.js";import{styleMap as h}from"lit/directives/style-map.js";import{resolveImageFallbackSrc as a}from"./srcset-utils.js";import{PresetController as n}from"../helper/controllers/preset-controller.js";var d=Object.defineProperty,p=Object.getOwnPropertyDescriptor,l=(t,e,s,i)=>{for(var r,o=i>1?void 0:i?p(e,s):e,c=t.length-1;c>=0;c--)(r=t[c])&&(o=(i?r(e,s,o):r(o))||o);return i&&o&&d(e,s,o),o};let u=class extends e{constructor(){super(...arguments),this.src="",this.alt="Image",this.width="auto",this.height="auto",this.aspectRatio=null,this.borderRadius="0",this.boxShadow="none",this.objectFit="cover",this.objectPosition="center",this.srcset="",this.sizes="",this.autoSizes=!1,this._computedSizes="",this.loading="lazy",this.decoding="async",this.preset="",this._presets=new n(this),this._sizesRafId=null,this._updateSizes=()=>{null==this._sizesRafId&&(this._sizesRafId=requestAnimationFrame(()=>{this._sizesRafId=null;const t=Math.ceil(this.getBoundingClientRect().width);t>0&&(this._computedSizes=`${t}px`)}))}}connectedCallback(){super.connectedCallback(),this._ensureAutoSizesObserver()}firstUpdated(){this._ensureAutoSizesObserver()}_ensureAutoSizesObserver(){this.autoSizes&&(this._ro||(this._ro=new ResizeObserver(this._updateSizes),this._ro.observe(this)),this._updateSizes())}updated(t){super.updated(t),t.has("autoSizes")&&(this.autoSizes?this._ensureAutoSizesObserver():(this._ro?.disconnect(),this._ro=void 0,this._computedSizes="")),this._shouldResyncImageSource(t)&&this._resyncImageSource(t.has("srcset")&&void 0!==t.get("srcset"))}disconnectedCallback(){super.disconnectedCallback(),this._ro?.disconnect(),this._ro=void 0,null!=this._sizesRafId&&(cancelAnimationFrame(this._sizesRafId),this._sizesRafId=null)}_shouldResyncImageSource(t){const e=t;return!(!this.src?.trim()&&!this.srcset?.trim())&&(!(!t.has("src")||void 0===t.get("src"))||(!(!t.has("srcset")||void 0===t.get("srcset"))||(!(!t.has("sizes")||void 0===t.get("sizes"))||!(!this.autoSizes||!e.has("_computedSizes")||void 0===e.get("_computedSizes")))))}_resolvedSizesAttr(){return this.autoSizes?this._computedSizes:this.sizes||""}_displaySrc(){const t=this.src?.trim()??"",e=this.srcset?.trim()??"";return t||e?e?a(t,e):t:""}_applyImgAttrs(t,e){const s=this.srcset?.trim()??"",i=this._resolvedSizesAttr(),r=this._displaySrc();s?t.srcset=s:t.removeAttribute("srcset"),i?t.sizes=i:t.removeAttribute("sizes"),e&&t.removeAttribute("src"),t.src=r}_resyncImageSource(t=!1){const e=this.renderRoot.querySelector("img");if(!(e instanceof HTMLImageElement))return;const s=e.cloneNode(!1);s.alt=this.alt,s.loading=this.loading,s.decoding=this.decoding;const i=e.getAttribute("style");i&&s.setAttribute("style",i),s.setAttribute("part","img"),this._applyImgAttrs(s,t),e.replaceWith(s)}render(){const t=this._resolvedSizesAttr(),e=this._displaySrc(),r=""!==e,o={width:this.width,height:this.height,borderRadius:this.borderRadius,boxShadow:this.boxShadow,objectFit:this.objectFit,objectPosition:this.objectPosition,aspectRatio:this.aspectRatio??"auto"};return r?s`
|
|
2
2
|
<img
|
|
3
3
|
src=${e}
|
|
4
4
|
alt=${this.alt}
|
|
@@ -6,18 +6,18 @@ import{css as t,LitElement as e,html as s,nothing as i}from"lit";import{property
|
|
|
6
6
|
sizes=${t||i}
|
|
7
7
|
loading=${this.loading}
|
|
8
8
|
decoding=${this.decoding}
|
|
9
|
-
style=${
|
|
9
|
+
style=${h(o)}
|
|
10
10
|
part="img"
|
|
11
11
|
/>
|
|
12
12
|
`:s`
|
|
13
13
|
<div
|
|
14
14
|
class="placeholder"
|
|
15
15
|
part="img"
|
|
16
|
-
style=${
|
|
16
|
+
style=${h(o)}
|
|
17
17
|
aria-label=${this.alt}
|
|
18
18
|
role="img"
|
|
19
19
|
></div>
|
|
20
|
-
`}};
|
|
20
|
+
`}};u.styles=t`
|
|
21
21
|
:host {
|
|
22
22
|
display: inline-block;
|
|
23
23
|
max-width: 100%;
|
|
@@ -32,5 +32,5 @@ import{css as t,LitElement as e,html as s,nothing as i}from"lit";import{property
|
|
|
32
32
|
.placeholder {
|
|
33
33
|
background: var(--sky-hover-tertiary);
|
|
34
34
|
}
|
|
35
|
-
`,
|
|
35
|
+
`,l([r({type:String})],u.prototype,"src",2),l([r({type:String})],u.prototype,"alt",2),l([r({type:String})],u.prototype,"width",2),l([r({type:String})],u.prototype,"height",2),l([r({type:String})],u.prototype,"aspectRatio",2),l([r({type:String})],u.prototype,"borderRadius",2),l([r({type:String})],u.prototype,"boxShadow",2),l([r({type:String})],u.prototype,"objectFit",2),l([r({type:String})],u.prototype,"objectPosition",2),l([r({type:String})],u.prototype,"srcset",2),l([r({type:String})],u.prototype,"sizes",2),l([r({type:Boolean})],u.prototype,"autoSizes",2),l([o()],u.prototype,"_computedSizes",2),l([r({type:String})],u.prototype,"loading",2),l([r({type:String})],u.prototype,"decoding",2),l([r({type:String,reflect:!0})],u.prototype,"preset",2),u=l([c("sky-image")],u);export{u as SkyImage};
|
|
36
36
|
//# sourceMappingURL=sky-image.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sky-image.js","sources":["../../src/sky-image/sky-image.ts"],"sourcesContent":["import { LitElement, html, css, nothing } from 'lit';\nimport type { PropertyValues } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { styleMap } from 'lit/directives/style-map.js';\nimport { resolveImageFallbackSrc } from './srcset-utils.js';\n\nexport type SkyImageLoading = 'lazy' | 'eager';\nexport type SkyImageDecoding = 'async' | 'sync' | 'auto';\n\n/**\n * @element sky-image\n *\n * @summary Responsive image component with style controls, `srcset`, and optional auto `sizes`.\n *\n * @status stable\n * @since 1.0.0\n *\n * @documentation https://sky-ui.com/components/image\n *\n * @slot - No slots are exposed; image content is rendered internally.\n * @property {string} src - Primary image source URL.\n * @property {string} alt - Alternative text for accessibility.\n * @property {string} width - CSS width for the rendered image.\n * @property {string} height - CSS height for the rendered image.\n * @property {string | null} aspectRatio - CSS `aspect-ratio` value.\n * @property {string} borderRadius - CSS border radius.\n * @property {string} boxShadow - CSS box shadow.\n * @property {string} objectFit - CSS object-fit value.\n * @property {string} objectPosition - CSS object-position value.\n * @property {string} srcset - Responsive source set string.\n * @property {string} sizes - Responsive sizes string.\n * @property {boolean} autoSizes - Computes `sizes` from host width when true.\n * @property {SkyImageLoading} loading - Native loading hint.\n * @property {SkyImageDecoding} decoding - Native decoding hint.\n *\n * @csspart img - The underlying `<img>` element.\n *\n * @Behavior\n * - Renders a fallback visual placeholder when `src` is empty\n * - Supports automatic `sizes` updates using ResizeObserver\n * - Forwards native image loading and decoding hints\n *\n * @example\n * ```html\n * <sky-image\n * src=\"/images/photo-1280.jpg\"\n * srcset=\"/images/photo-640.jpg 640w, /images/photo-960.jpg 960w, /images/photo-1280.jpg 1280w\"\n * sizes=\"(max-width: 768px) 100vw, 50vw\"\n * alt=\"Responsive photo\"\n * width=\"100%\"\n * aspect-ratio=\"4/3\"\n * border-radius=\"8px\"\n * loading=\"lazy\"\n * ></sky-image>\n * ```\n * ```vue\n * <template>\n * <sky-image\n * src=\"/images/photo-1280.jpg\"\n * srcset=\"/images/photo-640.jpg 640w, /images/photo-960.jpg 960w, /images/photo-1280.jpg 1280w\"\n * sizes=\"(max-width: 768px) 100vw, 50vw\"\n * alt=\"Responsive photo\"\n * width=\"100%\"\n * aspect-ratio=\"4/3\"\n * border-radius=\"8px\"\n * ></sky-image>\n * </template>\n * ```\n * ```jsx\n * export default function Demo() {\n * return (\n * <sky-image\n * src=\"/images/photo-1280.jpg\"\n * srcset=\"/images/photo-640.jpg 640w, /images/photo-960.jpg 960w, /images/photo-1280.jpg 1280w\"\n * sizes=\"(max-width: 768px) 100vw, 50vw\"\n * alt=\"Responsive photo\"\n * width=\"100%\"\n * aspect-ratio=\"4/3\"\n * border-radius=\"8px\"\n * ></sky-image>\n * );\n * }\n * ```\n */\n@customElement('sky-image')\nexport class SkyImage extends LitElement {\n @property({ type: String }) src = '';\n @property({ type: String }) alt = 'Image';\n @property({ type: String }) width = 'auto';\n @property({ type: String }) height = 'auto';\n @property({ type: String }) aspectRatio: string | null = null;\n @property({ type: String }) borderRadius = '0';\n @property({ type: String }) boxShadow = 'none';\n @property({ type: String }) objectFit = 'cover';\n @property({ type: String }) objectPosition = 'center';\n\n @property({ type: String }) srcset = '';\n @property({ type: String }) sizes = '';\n\n @property({ type: Boolean }) autoSizes = false;\n @state() private _computedSizes = '';\n\n @property({ type: String }) loading: SkyImageLoading = 'lazy';\n @property({ type: String }) decoding: SkyImageDecoding = 'async';\n\n static override styles = css`\n :host {\n display: inline-block;\n max-width: 100%;\n }\n\n img,\n .placeholder {\n display: block;\n max-width: 100%;\n }\n\n .placeholder {\n background: var(--sky-hover-tertiary);\n }\n `;\n\n private _ro?: ResizeObserver;\n private _sizesRafId: number | null = null;\n private _updateSizes = () => {\n if (this._sizesRafId != null) return;\n this._sizesRafId = requestAnimationFrame(() => {\n this._sizesRafId = null;\n const w = Math.ceil(this.getBoundingClientRect().width);\n if (w > 0) this._computedSizes = `${w}px`;\n });\n };\n\n override connectedCallback(): void {\n super.connectedCallback();\n // firstUpdated runs only once; re-create the observer when the element\n // is moved back into the document after a disconnect.\n this._ensureAutoSizesObserver();\n }\n\n override firstUpdated(): void {\n this._ensureAutoSizesObserver();\n }\n\n private _ensureAutoSizesObserver(): void {\n if (!this.autoSizes) return;\n if (!this._ro) {\n this._ro = new ResizeObserver(this._updateSizes);\n this._ro.observe(this);\n }\n this._updateSizes();\n }\n\n override updated(changed: PropertyValues<this>): void {\n super.updated(changed);\n\n if (changed.has('autoSizes')) {\n if (this.autoSizes) {\n this._ensureAutoSizesObserver();\n } else {\n this._ro?.disconnect();\n this._ro = undefined;\n this._computedSizes = '';\n }\n }\n\n if (!this._shouldResyncImageSource(changed)) return;\n this._resyncImageSource(\n changed.has('srcset') && changed.get('srcset') !== undefined\n );\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this._ro?.disconnect();\n this._ro = undefined;\n if (this._sizesRafId != null) {\n cancelAnimationFrame(this._sizesRafId);\n this._sizesRafId = null;\n }\n }\n\n /** Browsers keep the resolved resource when only srcset/sizes attrs change on a live <img>. */\n private _shouldResyncImageSource(changed: PropertyValues<this>): boolean {\n // Lit's PropertyValues<this> excludes private reactive state from keyof this,\n // although @state changes are present in the runtime map.\n const allChanged = changed as unknown as Map<PropertyKey, unknown>;\n if (!this.src?.trim() && !this.srcset?.trim()) return false;\n if (changed.has('src') && changed.get('src') !== undefined) return true;\n if (changed.has('srcset') && changed.get('srcset') !== undefined)\n return true;\n if (changed.has('sizes') && changed.get('sizes') !== undefined) return true;\n if (\n this.autoSizes &&\n allChanged.has('_computedSizes') &&\n allChanged.get('_computedSizes') !== undefined\n ) {\n return true;\n }\n return false;\n }\n\n private _resolvedSizesAttr(): string {\n return this.autoSizes ? this._computedSizes : this.sizes || '';\n }\n\n /** `src` used on <img> — must stay in sync with `srcset` when the set changes. */\n private _displaySrc(): string {\n const explicit = this.src?.trim() ?? '';\n const srcset = this.srcset?.trim() ?? '';\n if (!explicit && !srcset) return '';\n if (!srcset) return explicit;\n return resolveImageFallbackSrc(explicit, srcset);\n }\n\n private _applyImgAttrs(img: HTMLImageElement, srcsetChanged: boolean): void {\n const srcset = this.srcset?.trim() ?? '';\n const sizesAttr = this._resolvedSizesAttr();\n const src = this._displaySrc();\n\n if (srcset) img.srcset = srcset;\n else img.removeAttribute('srcset');\n\n if (sizesAttr) img.sizes = sizesAttr;\n else img.removeAttribute('sizes');\n\n // When the candidate list changes, drop `src` first so the UA cannot keep the old resource.\n if (srcsetChanged) img.removeAttribute('src');\n img.src = src;\n }\n\n private _resyncImageSource(srcsetChanged = false): void {\n const img = this.renderRoot.querySelector('img');\n if (!(img instanceof HTMLImageElement)) return;\n\n const replacement = img.cloneNode(false) as HTMLImageElement;\n replacement.alt = this.alt;\n replacement.loading = this.loading;\n replacement.decoding = this.decoding;\n const style = img.getAttribute('style');\n if (style) replacement.setAttribute('style', style);\n replacement.setAttribute('part', 'img');\n\n this._applyImgAttrs(replacement, srcsetChanged);\n img.replaceWith(replacement);\n }\n\n override render() {\n const sizesAttr = this._resolvedSizesAttr();\n const displaySrc = this._displaySrc();\n const hasSrc = displaySrc !== '';\n\n const styleVars = {\n width: this.width,\n height: this.height,\n borderRadius: this.borderRadius,\n boxShadow: this.boxShadow,\n objectFit: this.objectFit,\n objectPosition: this.objectPosition,\n aspectRatio: this.aspectRatio ?? 'auto',\n };\n\n if (!hasSrc) {\n return html`\n <div\n class=\"placeholder\"\n part=\"img\"\n style=${styleMap(styleVars)}\n aria-label=${this.alt}\n role=\"img\"\n ></div>\n `;\n }\n\n return html`\n <img\n src=${displaySrc}\n alt=${this.alt}\n srcset=${this.srcset || nothing}\n sizes=${sizesAttr || nothing}\n loading=${this.loading}\n decoding=${this.decoding}\n style=${styleMap(styleVars)}\n part=\"img\"\n />\n `;\n }\n}\n"],"names":["SkyImage","LitElement","constructor","super","arguments","this","src","alt","width","height","aspectRatio","borderRadius","boxShadow","objectFit","objectPosition","srcset","sizes","autoSizes","_computedSizes","loading","decoding","_sizesRafId","_updateSizes","requestAnimationFrame","w","Math","ceil","getBoundingClientRect","connectedCallback","_ensureAutoSizesObserver","firstUpdated","_ro","ResizeObserver","observe","updated","changed","has","disconnect","_shouldResyncImageSource","_resyncImageSource","get","disconnectedCallback","cancelAnimationFrame","allChanged","trim","_resolvedSizesAttr","_displaySrc","explicit","resolveImageFallbackSrc","_applyImgAttrs","img","srcsetChanged","sizesAttr","removeAttribute","renderRoot","querySelector","HTMLImageElement","replacement","cloneNode","style","getAttribute","setAttribute","replaceWith","render","displaySrc","hasSrc","styleVars","html","nothing","styleMap","styles","css","__decorateClass","property","type","String","prototype","Boolean","state","customElement"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sky-image.js","sources":["../../src/sky-image/sky-image.ts"],"sourcesContent":["import { LitElement, html, css, nothing } from \"lit\";\r\nimport type { PropertyValues } from \"lit\";\r\nimport { customElement, property, state } from \"lit/decorators.js\";\r\nimport { styleMap } from \"lit/directives/style-map.js\";\r\nimport { resolveImageFallbackSrc } from \"./srcset-utils.js\";\r\nimport { PresetController } from \"../helper/controllers/preset-controller\";\n\r\nexport type SkyImageLoading = \"lazy\" | \"eager\";\r\nexport type SkyImageDecoding = \"async\" | \"sync\" | \"auto\";\r\n\r\n/**\r\n * @element sky-image\r\n *\r\n * @summary Responsive image component with style controls, `srcset`, and optional auto `sizes`.\r\n *\r\n * @status stable\r\n * @since 1.0.0\r\n *\r\n * @documentation https://sky-ui.com/components/image\r\n *\r\n * @slot - No slots are exposed; image content is rendered internally.\r\n * @property {string} src - Primary image source URL.\r\n * @property {string} alt - Alternative text for accessibility.\r\n * @property {string} width - CSS width for the rendered image.\r\n * @property {string} height - CSS height for the rendered image.\r\n * @property {string | null} aspectRatio - CSS `aspect-ratio` value.\r\n * @property {string} borderRadius - CSS border radius.\r\n * @property {string} boxShadow - CSS box shadow.\r\n * @property {string} objectFit - CSS object-fit value.\r\n * @property {string} objectPosition - CSS object-position value.\r\n * @property {string} srcset - Responsive source set string.\r\n * @property {string} sizes - Responsive sizes string.\r\n * @property {boolean} autoSizes - Computes `sizes` from host width when true.\r\n * @property {SkyImageLoading} loading - Native loading hint.\r\n * @property {SkyImageDecoding} decoding - Native decoding hint.\r\n * @property {string} preset - Named prop preset from nearest `sky-config-provider`. Default: `\"\"`.\n *\r\n * @csspart img - The underlying `<img>` element.\r\n *\r\n * @Behavior\r\n * - Renders a fallback visual placeholder when `src` is empty\r\n * - Supports automatic `sizes` updates using ResizeObserver\r\n * - Forwards native image loading and decoding hints\r\n *\r\n * @example\r\n * ```html\r\n * <sky-image\r\n * src=\"/images/photo-1280.jpg\"\r\n * srcset=\"/images/photo-640.jpg 640w, /images/photo-960.jpg 960w, /images/photo-1280.jpg 1280w\"\r\n * sizes=\"(max-width: 768px) 100vw, 50vw\"\r\n * alt=\"Responsive photo\"\r\n * width=\"100%\"\r\n * aspect-ratio=\"4/3\"\r\n * border-radius=\"8px\"\r\n * loading=\"lazy\"\r\n * ></sky-image>\r\n * ```\r\n * ```vue\r\n * <template>\r\n * <sky-image\r\n * src=\"/images/photo-1280.jpg\"\r\n * srcset=\"/images/photo-640.jpg 640w, /images/photo-960.jpg 960w, /images/photo-1280.jpg 1280w\"\r\n * sizes=\"(max-width: 768px) 100vw, 50vw\"\r\n * alt=\"Responsive photo\"\r\n * width=\"100%\"\r\n * aspect-ratio=\"4/3\"\r\n * border-radius=\"8px\"\r\n * ></sky-image>\r\n * </template>\r\n * ```\r\n * ```jsx\r\n * export default function Demo() {\r\n * return (\r\n * <sky-image\r\n * src=\"/images/photo-1280.jpg\"\r\n * srcset=\"/images/photo-640.jpg 640w, /images/photo-960.jpg 960w, /images/photo-1280.jpg 1280w\"\r\n * sizes=\"(max-width: 768px) 100vw, 50vw\"\r\n * alt=\"Responsive photo\"\r\n * width=\"100%\"\r\n * aspect-ratio=\"4/3\"\r\n * border-radius=\"8px\"\r\n * ></sky-image>\r\n * );\r\n * }\r\n * ```\r\n */\r\n@customElement(\"sky-image\")\r\nexport class SkyImage extends LitElement {\r\n @property({ type: String }) src = \"\";\r\n @property({ type: String }) alt = \"Image\";\r\n @property({ type: String }) width = \"auto\";\r\n @property({ type: String }) height = \"auto\";\r\n @property({ type: String }) aspectRatio: string | null = null;\r\n @property({ type: String }) borderRadius = \"0\";\r\n @property({ type: String }) boxShadow = \"none\";\r\n @property({ type: String }) objectFit = \"cover\";\r\n @property({ type: String }) objectPosition = \"center\";\r\n\r\n @property({ type: String }) srcset = \"\";\r\n @property({ type: String }) sizes = \"\";\r\n\r\n @property({ type: Boolean }) autoSizes = false;\r\n @state() private _computedSizes = \"\";\r\n\r\n @property({ type: String }) loading: SkyImageLoading = \"lazy\";\r\n @property({ type: String }) decoding: SkyImageDecoding = \"async\";\r\n\r\n\n /** Named prop preset from nearest `sky-config-provider`. */\n @property({ type: String, reflect: true }) preset = \"\";\n\n private _presets = new PresetController(this);\n\n static override styles = css`\r\n :host {\r\n display: inline-block;\r\n max-width: 100%;\r\n }\r\n\r\n img,\r\n .placeholder {\r\n display: block;\r\n max-width: 100%;\r\n }\r\n\r\n .placeholder {\r\n background: var(--sky-hover-tertiary);\r\n }\r\n `;\r\n\r\n private _ro?: ResizeObserver;\r\n private _sizesRafId: number | null = null;\r\n private _updateSizes = () => {\r\n if (this._sizesRafId != null) return;\r\n this._sizesRafId = requestAnimationFrame(() => {\r\n this._sizesRafId = null;\r\n const w = Math.ceil(this.getBoundingClientRect().width);\r\n if (w > 0) this._computedSizes = `${w}px`;\r\n });\r\n };\r\n\r\n override connectedCallback(): void {\r\n super.connectedCallback();\r\n // firstUpdated runs only once; re-create the observer when the element\r\n // is moved back into the document after a disconnect.\r\n this._ensureAutoSizesObserver();\r\n }\r\n\r\n override firstUpdated(): void {\r\n this._ensureAutoSizesObserver();\r\n }\r\n\r\n private _ensureAutoSizesObserver(): void {\r\n if (!this.autoSizes) return;\r\n if (!this._ro) {\r\n this._ro = new ResizeObserver(this._updateSizes);\r\n this._ro.observe(this);\r\n }\r\n this._updateSizes();\r\n }\r\n\r\n override updated(changed: PropertyValues<this>): void {\r\n super.updated(changed);\r\n\r\n if (changed.has(\"autoSizes\")) {\r\n if (this.autoSizes) {\r\n this._ensureAutoSizesObserver();\r\n } else {\r\n this._ro?.disconnect();\r\n this._ro = undefined;\r\n this._computedSizes = \"\";\r\n }\r\n }\r\n\r\n if (!this._shouldResyncImageSource(changed)) return;\r\n this._resyncImageSource(\r\n changed.has(\"srcset\") && changed.get(\"srcset\") !== undefined,\r\n );\r\n }\r\n\r\n override disconnectedCallback(): void {\r\n super.disconnectedCallback();\r\n this._ro?.disconnect();\r\n this._ro = undefined;\r\n if (this._sizesRafId != null) {\r\n cancelAnimationFrame(this._sizesRafId);\r\n this._sizesRafId = null;\r\n }\r\n }\r\n\r\n /** Browsers keep the resolved resource when only srcset/sizes attrs change on a live <img>. */\r\n private _shouldResyncImageSource(changed: PropertyValues<this>): boolean {\r\n // Lit's PropertyValues<this> excludes private reactive state from keyof this,\r\n // although @state changes are present in the runtime map.\r\n const allChanged = changed as unknown as Map<PropertyKey, unknown>;\r\n if (!this.src?.trim() && !this.srcset?.trim()) return false;\r\n if (changed.has(\"src\") && changed.get(\"src\") !== undefined) return true;\r\n if (changed.has(\"srcset\") && changed.get(\"srcset\") !== undefined) return true;\r\n if (changed.has(\"sizes\") && changed.get(\"sizes\") !== undefined) return true;\r\n if (\r\n this.autoSizes &&\r\n allChanged.has(\"_computedSizes\") &&\r\n allChanged.get(\"_computedSizes\") !== undefined\r\n ) {\r\n return true;\r\n }\r\n return false;\r\n }\r\n\r\n private _resolvedSizesAttr(): string {\r\n return this.autoSizes ? this._computedSizes : this.sizes || \"\";\r\n }\r\n\r\n /** `src` used on <img> — must stay in sync with `srcset` when the set changes. */\r\n private _displaySrc(): string {\r\n const explicit = this.src?.trim() ?? \"\";\r\n const srcset = this.srcset?.trim() ?? \"\";\r\n if (!explicit && !srcset) return \"\";\r\n if (!srcset) return explicit;\r\n return resolveImageFallbackSrc(explicit, srcset);\r\n }\r\n\r\n private _applyImgAttrs(img: HTMLImageElement, srcsetChanged: boolean): void {\r\n const srcset = this.srcset?.trim() ?? \"\";\r\n const sizesAttr = this._resolvedSizesAttr();\r\n const src = this._displaySrc();\r\n\r\n if (srcset) img.srcset = srcset;\r\n else img.removeAttribute(\"srcset\");\r\n\r\n if (sizesAttr) img.sizes = sizesAttr;\r\n else img.removeAttribute(\"sizes\");\r\n\r\n // When the candidate list changes, drop `src` first so the UA cannot keep the old resource.\r\n if (srcsetChanged) img.removeAttribute(\"src\");\r\n img.src = src;\r\n }\r\n\r\n private _resyncImageSource(srcsetChanged = false): void {\r\n const img = this.renderRoot.querySelector(\"img\");\r\n if (!(img instanceof HTMLImageElement)) return;\r\n\r\n const replacement = img.cloneNode(false) as HTMLImageElement;\r\n replacement.alt = this.alt;\r\n replacement.loading = this.loading;\r\n replacement.decoding = this.decoding;\r\n const style = img.getAttribute(\"style\");\r\n if (style) replacement.setAttribute(\"style\", style);\r\n replacement.setAttribute(\"part\", \"img\");\r\n\r\n this._applyImgAttrs(replacement, srcsetChanged);\r\n img.replaceWith(replacement);\r\n }\r\n\r\n override render() {\r\n const sizesAttr = this._resolvedSizesAttr();\r\n const displaySrc = this._displaySrc();\r\n const hasSrc = displaySrc !== \"\";\r\n\r\n const styleVars = {\r\n width: this.width,\r\n height: this.height,\r\n borderRadius: this.borderRadius,\r\n boxShadow: this.boxShadow,\r\n objectFit: this.objectFit,\r\n objectPosition: this.objectPosition,\r\n aspectRatio: this.aspectRatio ?? \"auto\",\r\n };\r\n\r\n if (!hasSrc) {\r\n return html`\r\n <div\r\n class=\"placeholder\"\r\n part=\"img\"\r\n style=${styleMap(styleVars)}\r\n aria-label=${this.alt}\r\n role=\"img\"\r\n ></div>\r\n `;\r\n }\r\n\r\n return html`\r\n <img\r\n src=${displaySrc}\r\n alt=${this.alt}\r\n srcset=${this.srcset || nothing}\r\n sizes=${sizesAttr || nothing}\r\n loading=${this.loading}\r\n decoding=${this.decoding}\r\n style=${styleMap(styleVars)}\r\n part=\"img\"\r\n />\r\n `;\r\n }\r\n}\r\n"],"names":["SkyImage","LitElement","constructor","super","arguments","this","src","alt","width","height","aspectRatio","borderRadius","boxShadow","objectFit","objectPosition","srcset","sizes","autoSizes","_computedSizes","loading","decoding","preset","_presets","PresetController","_sizesRafId","_updateSizes","requestAnimationFrame","w","Math","ceil","getBoundingClientRect","connectedCallback","_ensureAutoSizesObserver","firstUpdated","_ro","ResizeObserver","observe","updated","changed","has","disconnect","_shouldResyncImageSource","_resyncImageSource","get","disconnectedCallback","cancelAnimationFrame","allChanged","trim","_resolvedSizesAttr","_displaySrc","explicit","resolveImageFallbackSrc","_applyImgAttrs","img","srcsetChanged","sizesAttr","removeAttribute","renderRoot","querySelector","HTMLImageElement","replacement","cloneNode","style","getAttribute","setAttribute","replaceWith","render","displaySrc","hasSrc","styleVars","html","nothing","styleMap","styles","css","__decorateClass","property","type","String","prototype","Boolean","state","reflect","customElement"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"srcset-utils.js","sources":["../../src/sky-image/srcset-utils.ts"],"sourcesContent":["export type SrcsetCandidate = {\n url: string;\n width?: number;\n density?: number;\n};\n\n/** Parse a comma-separated `srcset` attribute into URL + descriptor pairs. */\nexport function parseSrcset(srcset: string): SrcsetCandidate[] {\n const trimmed = srcset.trim();\n if (!trimmed) return [];\n\n const out: SrcsetCandidate[] = [];\n for (const piece of trimmed.split(
|
|
1
|
+
{"version":3,"file":"srcset-utils.js","sources":["../../src/sky-image/srcset-utils.ts"],"sourcesContent":["export type SrcsetCandidate = {\r\n url: string;\r\n width?: number;\r\n density?: number;\r\n};\r\n\r\n/** Parse a comma-separated `srcset` attribute into URL + descriptor pairs. */\r\nexport function parseSrcset(srcset: string): SrcsetCandidate[] {\r\n const trimmed = srcset.trim();\r\n if (!trimmed) return [];\r\n\r\n const out: SrcsetCandidate[] = [];\r\n for (const piece of trimmed.split(\",\")) {\r\n const parts = piece.trim().split(/\\s+/).filter(Boolean);\r\n const url = parts[0];\r\n if (!url) continue;\r\n\r\n const descriptor = parts[1];\r\n if (!descriptor) {\r\n out.push({ url });\r\n continue;\r\n }\r\n if (descriptor.endsWith(\"w\")) {\r\n const width = Number.parseInt(descriptor.slice(0, -1), 10);\r\n out.push({ url, width: Number.isFinite(width) ? width : undefined });\r\n continue;\r\n }\r\n if (descriptor.endsWith(\"x\")) {\r\n const density = Number.parseFloat(descriptor.slice(0, -1));\r\n out.push({ url, density: Number.isFinite(density) ? density : undefined });\r\n continue;\r\n }\r\n out.push({ url });\r\n }\r\n return out;\r\n}\r\n\r\n/** Pick the `src` fallback the UA should use for a given `srcset`. */\r\nexport function resolveImageFallbackSrc(src: string, srcset: string): string {\r\n const explicit = src.trim();\r\n const candidates = parseSrcset(srcset);\r\n if (!candidates.length) return explicit;\r\n\r\n if (explicit && candidates.some((c) => c.url === explicit)) {\r\n return explicit;\r\n }\r\n\r\n const widthCandidates = candidates.filter(\r\n (c): c is SrcsetCandidate & { width: number } =>\r\n typeof c.width === \"number\" && c.width > 0,\r\n );\r\n if (widthCandidates.length) {\r\n return widthCandidates.reduce((best, c) =>\r\n c.width >= best.width ? c : best,\r\n ).url;\r\n }\r\n\r\n const densityCandidates = candidates.filter(\r\n (c): c is SrcsetCandidate & { density: number } =>\r\n typeof c.density === \"number\" && c.density > 0,\r\n );\r\n if (densityCandidates.length) {\r\n return densityCandidates.reduce((best, c) =>\r\n c.density >= best.density ? c : best,\r\n ).url;\r\n }\r\n\r\n return candidates[0]?.url ?? explicit;\r\n}\r\n"],"names":["parseSrcset","srcset","trimmed","trim","out","piece","split","parts","filter","Boolean","url","descriptor","endsWith","width","Number","parseInt","slice","push","isFinite","density","parseFloat","resolveImageFallbackSrc","src","explicit","candidates","length","some","c","widthCandidates","reduce","best","densityCandidates"],"mappings":"AAOO,SAASA,EAAYC,GAC1B,MAAMC,EAAUD,EAAOE,OACvB,IAAKD,EAAS,MAAO,GAErB,MAAME,EAAyB,GAC/B,IAAA,MAAWC,KAASH,EAAQI,MAAM,KAAM,CACtC,MAAMC,EAAQF,EAAMF,OAAOG,MAAM,OAAOE,OAAOC,SACzCC,EAAMH,EAAM,GAClB,IAAKG,EAAK,SAEV,MAAMC,EAAaJ,EAAM,GACzB,GAAKI,EAAL,CAIA,GAAIA,EAAWC,SAAS,KAAM,CAC5B,MAAMC,EAAQC,OAAOC,SAASJ,EAAWK,MAAM,MAAQ,IACvDZ,EAAIa,KAAK,CAAEP,MAAKG,MAAOC,OAAOI,SAASL,GAASA,OAAQ,IACxD,QACF,CACA,GAAIF,EAAWC,SAAS,KAAM,CAC5B,MAAMO,EAAUL,OAAOM,WAAWT,EAAWK,MAAM,GAAG,IACtDZ,EAAIa,KAAK,CAAEP,MAAKS,QAASL,OAAOI,SAASC,GAAWA,OAAU,IAC9D,QACF,CACAf,EAAIa,KAAK,CAAEP,OAXX,MAFEN,EAAIa,KAAK,CAAEP,OAcf,CACA,OAAON,CACT,CAGO,SAASiB,EAAwBC,EAAarB,GACnD,MAAMsB,EAAWD,EAAInB,OACfqB,EAAaxB,EAAYC,GAC/B,IAAKuB,EAAWC,OAAQ,OAAOF,EAE/B,GAAIA,GAAYC,EAAWE,KAAMC,GAAMA,EAAEjB,MAAQa,GAC/C,OAAOA,EAGT,MAAMK,EAAkBJ,EAAWhB,OAChCmB,GACoB,iBAAZA,EAAEd,OAAsBc,EAAEd,MAAQ,GAE7C,GAAIe,EAAgBH,OAClB,OAAOG,EAAgBC,OAAO,CAACC,EAAMH,IACnCA,EAAEd,OAASiB,EAAKjB,MAAQc,EAAIG,GAC5BpB,IAGJ,MAAMqB,EAAoBP,EAAWhB,OAClCmB,GACsB,iBAAdA,EAAER,SAAwBQ,EAAER,QAAU,GAEjD,OAAIY,EAAkBN,OACbM,EAAkBF,OAAO,CAACC,EAAMH,IACrCA,EAAER,SAAWW,EAAKX,QAAUQ,EAAIG,GAChCpB,IAGGc,EAAW,IAAId,KAAOa,CAC/B"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { FormControlBase } from
|
|
1
|
+
import { FormControlBase } from "../helper/internals/form-control-base";
|
|
2
2
|
export type SkyInputValue = string | number | File[] | null;
|
|
3
3
|
export type SkyInputType = string;
|
|
4
|
-
export type SkyInputErrorDisplayMode =
|
|
5
|
-
export type SkyInputIconPosition =
|
|
4
|
+
export type SkyInputErrorDisplayMode = "none" | "single" | "all";
|
|
5
|
+
export type SkyInputIconPosition = "left" | "right";
|
|
6
6
|
export type SkyInputValidation = (value: string | File[]) => true | string;
|
|
7
7
|
export type SkyInputValueChangedDetail = {
|
|
8
8
|
value: string | number;
|
|
@@ -51,6 +51,7 @@ export type SkyInputIconClickDetail = {
|
|
|
51
51
|
* @property {string} color - Accent color token/value.
|
|
52
52
|
* @property {SkyInputValidation[]} validations - Validation functions.
|
|
53
53
|
* @property {boolean} compact - Compact display mode.
|
|
54
|
+
* @property {string} preset - Named prop preset from nearest `sky-config-provider`. Default: `""`.
|
|
54
55
|
* @property {boolean} loading - Loading state.
|
|
55
56
|
* @property {boolean} showErrors - Enables error rendering.
|
|
56
57
|
* @property {boolean} clearable - Enables clear button.
|
|
@@ -178,7 +179,10 @@ export declare class SkyInput extends FormControlBase {
|
|
|
178
179
|
passwordHiddenIcon: string;
|
|
179
180
|
validationActive: boolean;
|
|
180
181
|
invalid: boolean;
|
|
181
|
-
variant:
|
|
182
|
+
variant: "default" | "highlight" | "fieldset" | "inside";
|
|
183
|
+
/** Named prop preset from nearest `sky-config-provider`. */
|
|
184
|
+
preset: string;
|
|
185
|
+
private _presets;
|
|
182
186
|
private selectedFileName;
|
|
183
187
|
private selectedFiles;
|
|
184
188
|
private focused;
|
|
@@ -301,7 +305,7 @@ export declare class SkyInput extends FormControlBase {
|
|
|
301
305
|
* @param {Event|null} event - The original event triggered by the click (optional).
|
|
302
306
|
* @public
|
|
303
307
|
*/
|
|
304
|
-
handleIconClick(position:
|
|
308
|
+
handleIconClick(position: "left" | "right", event?: Event | null): void;
|
|
305
309
|
/**
|
|
306
310
|
* Formats a file size in bytes into a human-readable string.
|
|
307
311
|
* @param {number} bytes - The file size in bytes.
|