@sky.ui/core 0.0.41 → 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 +1277 -541
- 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 +1 -1
- 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 +2 -2
- 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 +2 -2
- 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 +12 -4
- package/dist/sky-alert/sky-alert.js +4 -4
- 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 +4 -4
- package/dist/sky-appbar/sky-appbar.js.map +1 -1
- package/dist/sky-avatar/sky-avatar.d.ts +5 -1
- package/dist/sky-avatar/sky-avatar.js +7 -7
- package/dist/sky-avatar/sky-avatar.js.map +1 -1
- package/dist/sky-badge/sky-badge.d.ts +6 -2
- package/dist/sky-badge/sky-badge.js +6 -6
- package/dist/sky-badge/sky-badge.js.map +1 -1
- package/dist/sky-button/sky-button.d.ts +24 -4
- package/dist/sky-button/sky-button.js +9 -8
- package/dist/sky-button/sky-button.js.map +1 -1
- package/dist/sky-card/sky-card.d.ts +10 -2
- package/dist/sky-card/sky-card.js +4 -4
- 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 +47 -40
- package/dist/sky-checkbox/sky-checkbox.js.map +1 -1
- package/dist/sky-chip/sky-chip.d.ts +6 -2
- package/dist/sky-chip/sky-chip.js +10 -9
- package/dist/sky-chip/sky-chip.js.map +1 -1
- package/dist/sky-col/sky-col.d.ts +5 -1
- package/dist/sky-col/sky-col.js +4 -4
- package/dist/sky-col/sky-col.js.map +1 -1
- package/dist/sky-combobox/sky-combobox.d.ts +9 -2
- package/dist/sky-combobox/sky-combobox.js +27 -58
- package/dist/sky-combobox/sky-combobox.js.map +1 -1
- package/dist/sky-dialog/sky-dialog.d.ts +5 -1
- package/dist/sky-dialog/sky-dialog.js +3 -3
- package/dist/sky-dialog/sky-dialog.js.map +1 -1
- package/dist/sky-divider/sky-divider.d.ts +5 -1
- 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 +5 -1
- package/dist/sky-flexbox/sky-flexbox.js +4 -4
- package/dist/sky-flexbox/sky-flexbox.js.map +1 -1
- package/dist/sky-flexcol/sky-flexcol.d.ts +5 -1
- 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 +5 -1
- package/dist/sky-form/sky-form.js +2 -2
- 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 +4 -1
- 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 +5 -1
- 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 +5 -1
- package/dist/sky-input/sky-input.js +111 -111
- package/dist/sky-input/sky-input.js.map +1 -1
- package/dist/sky-list/sky-list.d.ts +5 -1
- package/dist/sky-list/sky-list.js +3 -3
- 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 +3 -3
- package/dist/sky-listitem/sky-listitem.js.map +1 -1
- package/dist/sky-radio/sky-radio.d.ts +8 -3
- package/dist/sky-radio/sky-radio.js +4 -3
- 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 +7 -2
- package/dist/sky-sheet/sky-sheet.js +2 -2
- package/dist/sky-sheet/sky-sheet.js.map +1 -1
- package/dist/sky-simple-table/sky-simple-table.d.ts +5 -1
- package/dist/sky-simple-table/sky-simple-table.js +3 -3
- package/dist/sky-simple-table/sky-simple-table.js.map +1 -1
- package/dist/sky-theme-provider/sky-theme-provider.d.ts +1 -1
- 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":"iconify-offline.js","sources":["../../src/helper/iconify-offline.ts"],"sourcesContent":["/**\r\n * Iconify/sky-icon helpers: extract icon names from code and fetch icon data for offline use.\r\n *\r\n * Usage (browser or Node):\r\n * import { extractIconNames, fetchIconsForOffline, registerOfflineIcons } from '~/components/helper/iconify-offline';\r\n * import { SkyIcon } from '~/components/sky-icon/sky-icon';\r\n *\r\n * // Extract icon names from a code page string\r\n * const names = extractIconNames('<sky-icon icon=\"ion:home\"></sky-icon>'); // ['ion:home']\r\n *\r\n * // Fetch and then register in SkyIcon (directly pass generated JSON)\r\n * const combined = await fetchIconsForOffline(['ion:home', 'mdi:bell']);\r\n * registerOfflineIcons(combined, (prefix, data) => SkyIcon.registerLocalSet(prefix, data));\r\n *\r\n * // Or from saved JSON string:\r\n * const combined = JSON.parse(savedJson);\r\n * registerOfflineIcons(combined, (prefix, data) => SkyIcon.registerLocalSet(prefix, data));\r\n */\r\n\r\nconst ICONIFY_API_BASE = 'https://api.iconify.design';\r\n\r\n/** Matches quoted \"prefix:icon-name\" (prefix must start with a letter so \"1:3\" etc. are ignored). */\r\nconst QUOTED_ICON_PATTERN = /([\"'`])([a-z][a-z0-9-]*:[a-zA-Z0-9_.-]+)\\1/g;\r\n\r\nexport interface IconifyIconData {\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 hidden?: boolean;\r\n}\r\n\r\nexport interface IconifySetData {\r\n prefix?: string;\r\n icons: Record<string, IconifyIconData>;\r\n width?: number;\r\n height?: number;\r\n left?: number;\r\n top?: number;\r\n /** Icon names requested but not in API response; add manually if needed. Omit when registering with SkyIcon. */\r\n _notFound?: string[];\r\n}\r\n\r\n/** Combined offline data: prefix -> Iconify set data (ready for SkyIcon.registerLocalSet). Skip keys starting with _ when registering. */\r\nexport type CombinedOfflineIcons = Record<string, IconifySetData>;\r\n\r\nexport interface FetchIconsForOfflineOptions {\r\n /** Iconify API base URL (default: https://api.iconify.design) */\r\n baseUrl?: string;\r\n}\r\n\r\n/**\r\n * Extracts all icon names in \"prefix:icon-name\" format from a code page string.\r\n * Looks for icon names inside single, double, or backtick quotes (e.g. in attributes\r\n * like icon=\"ion:home\", iconL='mdi:bell', or :icon=\"`ion:person`\").\r\n *\r\n * @param codePageString - Source code string (HTML, Vue, TS, JS, etc.)\r\n * @returns Array of unique icon names (e.g. [\"ion:home\", \"mdi:bell\"])\r\n */\r\nexport function extractIconNames(codePageString: string): string[] {\r\n if (!codePageString || typeof codePageString !== 'string') {\r\n return [];\r\n }\r\n const seen = new Set<string>();\r\n const result: string[] = [];\r\n let match: RegExpExecArray | null;\r\n QUOTED_ICON_PATTERN.lastIndex = 0;\r\n while ((match = QUOTED_ICON_PATTERN.exec(codePageString)) !== null) {\r\n const full = match[2];\r\n if (full && full.includes(':') && !seen.has(full)) {\r\n seen.add(full);\r\n result.push(full);\r\n }\r\n }\r\n return result;\r\n}\r\n\r\n/**\r\n * Fetches icon data from the Iconify API for the given icon names, groups by prefix,\r\n * and returns a combined JSON object keyed by prefix for offline use.\r\n *\r\n * @param iconNames - List of icon names in \"prefix:icon-name\" format (e.g. [\"ion:home\", \"mdi:bell\"])\r\n * @param options - Optional baseUrl for the Iconify API\r\n * @returns Combined object: { \"ion\": { prefix, icons, width, height }, \"mdi\": { ... }, ... }\r\n * Use with SkyIcon.registerLocalSet(prefix, combined[prefix]) for each prefix.\r\n */\r\nexport async function fetchIconsForOffline(\r\n iconNames: string[],\r\n options: FetchIconsForOfflineOptions = {}\r\n): Promise<CombinedOfflineIcons> {\r\n const baseUrl = (options.baseUrl || ICONIFY_API_BASE).replace(/\\/$/, '');\r\n const byPrefix = new Map<string, string[]>();\r\n\r\n for (const full of iconNames) {\r\n const trimmed = full.trim();\r\n if (!trimmed || !trimmed.includes(':')) continue;\r\n const [prefix, name] = trimmed.split(':');\r\n const iconName = name?.trim();\r\n if (!prefix || !iconName) continue;\r\n // Ignore non-icon patterns (e.g. \"1:3\"); Iconify prefixes start with a letter\r\n if (!/^[a-z]/.test(prefix)) continue;\r\n if (!byPrefix.has(prefix)) {\r\n byPrefix.set(prefix, []);\r\n }\r\n const list = byPrefix.get(prefix)!;\r\n if (!list.includes(iconName)) {\r\n list.push(iconName);\r\n }\r\n }\r\n\r\n const combined: CombinedOfflineIcons = {};\r\n\r\n await Promise.all(\r\n Array.from(byPrefix.entries()).map(async ([prefix, names]) => {\r\n const iconsParam = names.join(',');\r\n const url = `${baseUrl}/${prefix}.json?icons=${encodeURIComponent(iconsParam)}`;\r\n const res = await fetch(url);\r\n if (!res.ok) {\r\n throw new Error(`Iconify API error for ${prefix}: ${res.status} ${res.statusText}
|
|
1
|
+
{"version":3,"file":"iconify-offline.js","sources":["../../src/helper/iconify-offline.ts"],"sourcesContent":["/**\r\n * Iconify/sky-icon helpers: extract icon names from code and fetch icon data for offline use.\r\n *\r\n * Usage (browser or Node):\r\n * import { extractIconNames, fetchIconsForOffline, registerOfflineIcons } from '~/components/helper/iconify-offline';\r\n * import { SkyIcon } from '~/components/sky-icon/sky-icon';\r\n *\r\n * // Extract icon names from a code page string\r\n * const names = extractIconNames('<sky-icon icon=\"ion:home\"></sky-icon>'); // ['ion:home']\r\n *\r\n * // Fetch and then register in SkyIcon (directly pass generated JSON)\r\n * const combined = await fetchIconsForOffline(['ion:home', 'mdi:bell']);\r\n * registerOfflineIcons(combined, (prefix, data) => SkyIcon.registerLocalSet(prefix, data));\r\n *\r\n * // Or from saved JSON string:\r\n * const combined = JSON.parse(savedJson);\r\n * registerOfflineIcons(combined, (prefix, data) => SkyIcon.registerLocalSet(prefix, data));\r\n */\r\n\r\nconst ICONIFY_API_BASE = 'https://api.iconify.design';\r\n\r\n/** Matches quoted \"prefix:icon-name\" (prefix must start with a letter so \"1:3\" etc. are ignored). */\r\nconst QUOTED_ICON_PATTERN = /([\"'`])([a-z][a-z0-9-]*:[a-zA-Z0-9_.-]+)\\1/g;\r\n\r\nexport interface IconifyIconData {\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 hidden?: boolean;\r\n}\r\n\r\nexport interface IconifySetData {\r\n prefix?: string;\r\n icons: Record<string, IconifyIconData>;\r\n width?: number;\r\n height?: number;\r\n left?: number;\r\n top?: number;\r\n /** Icon names requested but not in API response; add manually if needed. Omit when registering with SkyIcon. */\r\n _notFound?: string[];\r\n}\r\n\r\n/** Combined offline data: prefix -> Iconify set data (ready for SkyIcon.registerLocalSet). Skip keys starting with _ when registering. */\r\nexport type CombinedOfflineIcons = Record<string, IconifySetData>;\r\n\r\nexport interface FetchIconsForOfflineOptions {\r\n /** Iconify API base URL (default: https://api.iconify.design) */\r\n baseUrl?: string;\r\n}\r\n\r\n/**\r\n * Extracts all icon names in \"prefix:icon-name\" format from a code page string.\r\n * Looks for icon names inside single, double, or backtick quotes (e.g. in attributes\r\n * like icon=\"ion:home\", iconL='mdi:bell', or :icon=\"`ion:person`\").\r\n *\r\n * @param codePageString - Source code string (HTML, Vue, TS, JS, etc.)\r\n * @returns Array of unique icon names (e.g. [\"ion:home\", \"mdi:bell\"])\r\n */\r\nexport function extractIconNames(codePageString: string): string[] {\r\n if (!codePageString || typeof codePageString !== 'string') {\r\n return [];\r\n }\r\n const seen = new Set<string>();\r\n const result: string[] = [];\r\n let match: RegExpExecArray | null;\r\n QUOTED_ICON_PATTERN.lastIndex = 0;\r\n while ((match = QUOTED_ICON_PATTERN.exec(codePageString)) !== null) {\r\n const full = match[2];\r\n if (full && full.includes(':') && !seen.has(full)) {\r\n seen.add(full);\r\n result.push(full);\r\n }\r\n }\r\n return result;\r\n}\r\n\r\n/**\r\n * Fetches icon data from the Iconify API for the given icon names, groups by prefix,\r\n * and returns a combined JSON object keyed by prefix for offline use.\r\n *\r\n * @param iconNames - List of icon names in \"prefix:icon-name\" format (e.g. [\"ion:home\", \"mdi:bell\"])\r\n * @param options - Optional baseUrl for the Iconify API\r\n * @returns Combined object: { \"ion\": { prefix, icons, width, height }, \"mdi\": { ... }, ... }\r\n * Use with SkyIcon.registerLocalSet(prefix, combined[prefix]) for each prefix.\r\n */\r\nexport async function fetchIconsForOffline(\r\n iconNames: string[],\r\n options: FetchIconsForOfflineOptions = {}\r\n): Promise<CombinedOfflineIcons> {\r\n const baseUrl = (options.baseUrl || ICONIFY_API_BASE).replace(/\\/$/, '');\r\n const byPrefix = new Map<string, string[]>();\r\n\r\n for (const full of iconNames) {\r\n const trimmed = full.trim();\r\n if (!trimmed || !trimmed.includes(':')) continue;\r\n const [prefix, name] = trimmed.split(':');\r\n const iconName = name?.trim();\r\n if (!prefix || !iconName) continue;\r\n // Ignore non-icon patterns (e.g. \"1:3\"); Iconify prefixes start with a letter\r\n if (!/^[a-z]/.test(prefix)) continue;\r\n if (!byPrefix.has(prefix)) {\r\n byPrefix.set(prefix, []);\r\n }\r\n const list = byPrefix.get(prefix)!;\r\n if (!list.includes(iconName)) {\r\n list.push(iconName);\r\n }\r\n }\r\n\r\n const combined: CombinedOfflineIcons = {};\r\n\r\n await Promise.all(\r\n Array.from(byPrefix.entries()).map(async ([prefix, names]) => {\r\n const iconsParam = names.join(',');\r\n const url = `${baseUrl}/${prefix}.json?icons=${encodeURIComponent(iconsParam)}`;\r\n const res = await fetch(url);\r\n if (!res.ok) {\r\n throw new Error(\r\n `Iconify API error for ${prefix}: ${res.status} ${res.statusText}`\r\n );\r\n }\r\n const json = (await res.json()) as IconifySetData & {\r\n icons?: Record<string, IconifyIconData>;\r\n };\r\n const returnedIcons = json.icons || {};\r\n const notFound = names.filter((name) => !returnedIcons[name]);\r\n const setData: IconifySetData = {\r\n prefix,\r\n icons: returnedIcons,\r\n width: json.width,\r\n height: json.height,\r\n left: json.left,\r\n top: json.top,\r\n };\r\n if (notFound.length > 0) {\r\n setData._notFound = notFound;\r\n }\r\n combined[prefix] = setData;\r\n })\r\n );\r\n\r\n const hasAnyNotFound = Object.values(combined).some(\r\n (set) => set._notFound && set._notFound.length > 0\r\n );\r\n if (hasAnyNotFound) {\r\n (combined as Record<string, unknown>)['_comment_notFound'] =\r\n 'Icons listed in _notFound (per set) were not in the API response; add manually if needed.';\r\n }\r\n\r\n return combined;\r\n}\r\n\r\n/** Set data without _notFound / _comment (suitable for SkyIcon.registerLocalSet). */\r\ntype SetDataForRegister = Omit<IconifySetData, '_notFound'>;\r\n\r\n/**\r\n * Registers the generated offline JSON with SkyIcon. Pass the object returned by fetchIconsForOffline\r\n * (or parsed from saved JSON). Skips top-level keys starting with \"_\" and strips _notFound from each set.\r\n *\r\n * @param combined - The combined object (from fetchIconsForOffline or JSON.parse of saved output)\r\n * @param register - Callback to register each set, e.g. (prefix, data) => SkyIcon.registerLocalSet(prefix, data)\r\n */\r\nexport function registerOfflineIcons(\r\n combined: CombinedOfflineIcons & Record<string, unknown>,\r\n register: (prefix: string, data: SetDataForRegister) => void\r\n): void {\r\n for (const [key, set] of Object.entries(combined)) {\r\n if (key.startsWith('_')) continue;\r\n if (!set || typeof set !== 'object' || !('icons' in set)) continue;\r\n const { _notFound: _unused, ...data } = set as IconifySetData;\r\n register(key, data as SetDataForRegister);\r\n }\r\n}\r\n"],"names":["QUOTED_ICON_PATTERN","extractIconNames","codePageString","seen","Set","result","match","lastIndex","exec","full","includes","has","add","push","async","fetchIconsForOffline","iconNames","options","baseUrl","replace","byPrefix","Map","trimmed","trim","prefix","name","split","iconName","test","set","list","get","combined","Promise","all","Array","from","entries","map","names","iconsParam","join","url","encodeURIComponent","res","fetch","ok","Error","status","statusText","json","returnedIcons","icons","notFound","filter","setData","width","height","left","top","length","_notFound","Object","values","some","registerOfflineIcons","register","key","startsWith","_unused","data"],"mappings":"AAmBA,MAGMA,EAAsB,8CAuCrB,SAASC,EAAiBC,GAC/B,IAAKA,GAA4C,iBAAnBA,EAC5B,MAAO,GAET,MAAMC,MAAWC,IACXC,EAAmB,GACzB,IAAIC,EAEJ,IADAN,EAAoBO,UAAY,EAC8B,QAAtDD,EAAQN,EAAoBQ,KAAKN,KAA2B,CAClE,MAAMO,EAAOH,EAAM,GACfG,GAAQA,EAAKC,SAAS,OAASP,EAAKQ,IAAIF,KAC1CN,EAAKS,IAAIH,GACTJ,EAAOQ,KAAKJ,GAEhB,CACA,OAAOJ,CACT,CAWAS,eAAsBC,EACpBC,EACAC,EAAuC,IAEvC,MAAMC,GAAWD,EAAQC,SAzEF,8BAyE+BC,QAAQ,MAAO,IAC/DC,MAAeC,IAErB,IAAA,MAAWZ,KAAQO,EAAW,CAC5B,MAAMM,EAAUb,EAAKc,OACrB,IAAKD,IAAYA,EAAQZ,SAAS,KAAM,SACxC,MAAOc,EAAQC,GAAQH,EAAQI,MAAM,KAC/BC,EAAWF,GAAMF,OACvB,IAAKC,IAAWG,EAAU,SAE1B,IAAK,SAASC,KAAKJ,GAAS,SACvBJ,EAAST,IAAIa,IAChBJ,EAASS,IAAIL,EAAQ,IAEvB,MAAMM,EAAOV,EAASW,IAAIP,GACrBM,EAAKpB,SAASiB,IACjBG,EAAKjB,KAAKc,EAEd,CAEA,MAAMK,EAAiC,CAAA,QAEjCC,QAAQC,IACZC,MAAMC,KAAKhB,EAASiB,WAAWC,IAAIxB,OAAQU,EAAQe,MACjD,MAAMC,EAAaD,EAAME,KAAK,KACxBC,EAAM,GAAGxB,KAAWM,gBAAqBmB,mBAAmBH,KAC5DI,QAAYC,MAAMH,GACxB,IAAKE,EAAIE,GACP,MAAM,IAAIC,MACR,yBAAyBvB,MAAWoB,EAAII,UAAUJ,EAAIK,cAG1D,MAAMC,QAAcN,EAAIM,OAGlBC,EAAgBD,EAAKE,OAAS,CAAA,EAC9BC,EAAWd,EAAMe,OAAQ7B,IAAU0B,EAAc1B,IACjD8B,EAA0B,CAC9B/B,SACA4B,MAAOD,EACPK,MAAON,EAAKM,MACZC,OAAQP,EAAKO,OACbC,KAAMR,EAAKQ,KACXC,IAAKT,EAAKS,KAERN,EAASO,OAAS,IACpBL,EAAQM,UAAYR,GAEtBrB,EAASR,GAAU+B,KAYvB,OARuBO,OAAOC,OAAO/B,GAAUgC,KAC5CnC,GAAQA,EAAIgC,WAAahC,EAAIgC,UAAUD,OAAS,KAGhD5B,EAAwD,kBACvD,6FAGGA,CACT,CAYO,SAASiC,EACdjC,EACAkC,GAEA,IAAA,MAAYC,EAAKtC,KAAQiC,OAAOzB,QAAQL,GAAW,CACjD,GAAImC,EAAIC,WAAW,KAAM,SACzB,IAAKvC,GAAsB,iBAARA,KAAsB,UAAWA,GAAM,SAC1D,MAAQgC,UAAWQ,KAAYC,GAASzC,EACxCqC,EAASC,EAAKG,EAChB,CACF"}
|
package/dist/helper/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export{extractIconNames,fetchIconsForOffline,registerOfflineIcons}from"./iconify-offline.js";export{AnimationController}from"./controllers/animation-controller.js";export{CONTRAST_COLOR_SUPPORT_QUERY,ON_COLOR_FALLBACK_DARK,ON_COLOR_FALLBACK_LIGHT,contrastOnFill,contrastOverlay,contrastThemeInk,cssContrastColor,cssOnFill,cssOnFillEnhance,isLightFill,parseCssRgb,perceivedLuminance,relativeLuminance}from"./utils/contrast-color.js";export{ColorResolver,DEFAULT_COLOR_TOKENS,colorResolver,createGradient,darkShade,fadeMix,hoverShade,isDefaultColorToken,lightShade,parseGradientSpec,resolveAccentColorForToken,resolveColor,resolveGradientStop,resolveInkColorForToken,resolveSemanticSurfaceKey,
|
|
1
|
+
export{extractIconNames,fetchIconsForOffline,registerOfflineIcons}from"./iconify-offline.js";export{AnimationController}from"./controllers/animation-controller.js";export{CONTRAST_COLOR_SUPPORT_QUERY,ON_COLOR_FALLBACK_DARK,ON_COLOR_FALLBACK_LIGHT,contrastOnFill,contrastOverlay,contrastThemeInk,cssContrastColor,cssOnFill,cssOnFillEnhance,isLightFill,parseCssRgb,perceivedLuminance,relativeLuminance}from"./utils/contrast-color.js";export{ColorResolver,DEFAULT_COLOR_TOKENS,colorResolver,createGradient,darkShade,fadeMix,hoverShade,isDefaultColorToken,lightShade,parseGradientSpec,resolveAccentColorForToken,resolveColor,resolveGradientStop,resolveInkColorForToken,resolveSemanticSurfaceKey,semanticSoftSurfaceTokens,skyBorderPrimaryShorthand,skyBorderWidthSolid,tuneSurfaceVariantForDefaultColor}from"./utils/color-resolver.js";export{FormControlBase}from"./internals/form-control-base.js";export{PopoverController}from"./controllers/popover-controller.js";export{PresetController}from"./controllers/preset-controller.js";export{applyPresetLayer,camelToKebab,captureInitialUserAttributes,clearAppliedPresetLayer,configContext,findNearestPresetsConfig,getPresetLayer,isUserSetProp,lookupPresetSection,markUserSetProp,mergePresetsConfig,presetKeyAliases,refreshUserAttributes,resolveComponentProps,toPresetTagKey}from"./utils/component-presets.js";export{resolveRadius}from"./utils/size-resolver.js";
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
|
@@ -30,7 +30,7 @@ export declare abstract class FormControlBase extends LitElement {
|
|
|
30
30
|
protected abstract getValidityAnchor(): HTMLElement | undefined;
|
|
31
31
|
/** Must return true if empty (for required) */
|
|
32
32
|
protected abstract isEmpty(): boolean;
|
|
33
|
-
/**
|
|
33
|
+
/** Must return the native control you want to proxy to (input/textarea/select/...) */
|
|
34
34
|
protected abstract getNativeControl(): HTMLElement | null;
|
|
35
35
|
/** Optional: return first custom error message (or empty string) */
|
|
36
36
|
protected getCustomErrorMessage(): string;
|
|
@@ -42,7 +42,7 @@ export declare abstract class FormControlBase extends LitElement {
|
|
|
42
42
|
/** Optional: handle BFCache restore */
|
|
43
43
|
protected onFormStateRestore(state: FormState): void;
|
|
44
44
|
/**
|
|
45
|
-
*
|
|
45
|
+
* Called by base after a proxy method mutates the native control.
|
|
46
46
|
* Subclasses should pull native.value into their state and optionally validate.
|
|
47
47
|
*/
|
|
48
48
|
protected onNativeValueMutated(_native: any): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"form-control-base.js","sources":["../../../src/helper/internals/form-control-base.ts"],"sourcesContent":["import { LitElement } from \"lit\";\r\nimport { property } from \"lit/decorators.js\";\r\n\r\nexport type FormState = string | File | FormData | null | string;\r\n\r\nexport abstract class FormControlBase extends LitElement {\r\n /** Enables form-associated custom element behavior */\r\n static formAssociated = true;\r\n\r\n protected internals: ElementInternals;\r\n protected defaultValue = \"\";\r\n\r\n /** Native form attributes you’ll reuse everywhere */\r\n @property({ type: String, reflect: true }) name = \"\";\r\n @property({ type: String, reflect: true })\r\n formId: string | null = null;\r\n @property({ type: Boolean, reflect: true }) disabled = false;\r\n @property({ type: Boolean, reflect: true }) readonly = false;\r\n @property({ type: Boolean, reflect: true }) required = false;\r\n @property({ type: String }) requiredMessage = \"This field is required.\";\r\n\r\n constructor() {\r\n super();\r\n\r\n if (typeof (this as any).attachInternals === \"function\") {\r\n // @ts-ignore\r\n this.internals = this.attachInternals();\r\n } else {\r\n throw new Error(\r\n \"ElementInternals / form-associated custom elements not supported in this browser.\"\r\n );\r\n }\r\n }\r\n\r\n // ---- Native form APIs (pass-through)\r\n get form() {\r\n return this.internals.form;\r\n }\r\n get validity() {\r\n return this.internals.validity;\r\n }\r\n get validationMessage() {\r\n return this.internals.validationMessage;\r\n }\r\n get willValidate() {\r\n return this.internals.willValidate;\r\n }\r\n checkValidity() {\r\n return this.internals.checkValidity();\r\n }\r\n reportValidity() {\r\n return this.internals.reportValidity();\r\n }\r\n\r\n // ---- Form callbacks\r\n formResetCallback() {\r\n this.onFormReset();\r\n this.syncFormValue();\r\n this.syncValidity();\r\n }\r\n\r\n formDisabledCallback(disabled: boolean) {\r\n this.disabled = disabled;\r\n this.onFormDisabled(disabled);\r\n this.syncValidity();\r\n }\r\n\r\n formStateRestoreCallback(state: FormState) {\r\n this.onFormStateRestore(state);\r\n this.syncFormValue();\r\n this.syncValidity();\r\n }\r\n\r\n // ============================================================\r\n // ✅ Hooks for subclasses\r\n // ============================================================\r\n\r\n /** Must return current “submission value” (string/file/formdata) */\r\n protected abstract getFormValue(): FormState;\r\n\r\n /** Must set the component state from restored state (usually string) */\r\n protected abstract setValueFromFormState(state: FormState): void;\r\n\r\n /** Must return the internal focusable control to anchor validity bubbles */\r\n protected abstract getValidityAnchor(): HTMLElement | undefined;\r\n\r\n /** Must return true if empty (for required) */\r\n protected abstract isEmpty(): boolean;\r\n\r\n /** ✅ Must return the native control you want to proxy to (input/textarea/select/...) */\r\n protected abstract getNativeControl(): HTMLElement | null;\r\n\r\n /** Optional: return first custom error message (or empty string) */\r\n protected getCustomErrorMessage(): string {\r\n return \"\";\r\n }\r\n\r\n protected validateForForm(): string {\r\n // return \"\" if OK, otherwise return error message\r\n return \"\";\r\n }\r\n\r\n /** Optional: reset component to default */\r\n protected onFormReset() {\r\n this.setValueFromFormState(this.defaultValue);\r\n }\r\n\r\n /** Optional: react to fieldset disabled */\r\n protected onFormDisabled(_disabled: boolean) { }\r\n\r\n /** Optional: handle BFCache restore */\r\n protected onFormStateRestore(state: FormState) {\r\n this.setValueFromFormState(state);\r\n }\r\n\r\n /**\r\n * ✅ Called by base after a proxy method mutates the native control.\r\n * Subclasses should pull native.value into their state and optionally validate.\r\n */\r\n protected onNativeValueMutated(_native: any): void { }\r\n\r\n // ============================================================\r\n // ✅ Shared utilities (form value + validity)\r\n // ============================================================\r\n\r\n protected syncFormValue() {\r\n if (!this.name || this.disabled) {\r\n this.internals.setFormValue(null);\r\n return;\r\n }\r\n\r\n const v = this.getFormValue();\r\n\r\n if (v === null) {\r\n this.internals.setFormValue(null);\r\n return;\r\n }\r\n\r\n this.internals.setFormValue(v);\r\n }\r\n\r\n protected syncValidity() {\r\n if (this.disabled) {\r\n this.internals.setValidity({});\r\n return;\r\n }\r\n\r\n // Required\r\n if (this.required && this.isEmpty()) {\r\n this.internals.setValidity(\r\n { valueMissing: true },\r\n this.requiredMessage || \"This field is required.\",\r\n this.getValidityAnchor()\r\n );\r\n return;\r\n }\r\n\r\n // Custom error (subclass)\r\n const msg = this.validateForForm();\r\n if (msg) {\r\n this.internals.setValidity(\r\n { customError: true },\r\n msg,\r\n this.getValidityAnchor()\r\n );\r\n return;\r\n }\r\n\r\n this.internals.setValidity({});\r\n }\r\n\r\n protected reemitNativeEvent(\r\n type: string,\r\n originalEvent: Event,\r\n init?: Partial<EventInit> & { detail?: any }\r\n ) {\r\n const cancelable = [\"submit\"].includes(type) ? true : false;\r\n const common: EventInit = { bubbles: true, composed: true, cancelable };\r\n\r\n const ev =\r\n init?.detail !== undefined\r\n ? new CustomEvent(type, { ...common, ...init })\r\n : new Event(type, { ...common, ...init });\r\n\r\n (ev as any).__originalEvent = originalEvent;\r\n\r\n this.dispatchEvent(ev);\r\n }\r\n\r\n /** Call once after initial render */\r\n protected captureDefaultValue(initial: string) {\r\n this.defaultValue = initial ?? \"\";\r\n }\r\n\r\n\r\n\r\n // ============================================================\r\n // ✅ Native proxy helpers (shared across all controls)\r\n // ============================================================\r\n\r\n protected get nativeControl(): any | null {\r\n return this.getNativeControl() as any;\r\n }\r\n\r\n protected get nativeInput(): HTMLInputElement | null {\r\n const el = this.getNativeControl();\r\n return el instanceof HTMLInputElement ? el : null;\r\n }\r\n\r\n protected get nativeTextarea(): HTMLTextAreaElement | null {\r\n const el = this.getNativeControl();\r\n return el instanceof HTMLTextAreaElement ? el : null;\r\n }\r\n\r\n /** Central sync after proxy calls */\r\n protected syncFromNative(runValidity = true) {\r\n const native = this.nativeControl;\r\n if (!native) return;\r\n\r\n this.onNativeValueMutated(native);\r\n this.syncFormValue();\r\n if (runValidity) this.syncValidity();\r\n }\r\n\r\n // ---- focus/blur/click/showPicker\r\n focus(options?: FocusOptions) {\r\n this.nativeControl?.focus?.(options);\r\n }\r\n\r\n blur() {\r\n this.nativeControl?.blur?.();\r\n }\r\n\r\n click() {\r\n this.nativeControl?.click?.();\r\n }\r\n\r\n showPicker(): boolean {\r\n const input = this.nativeInput as any;\r\n if (!input || typeof input.showPicker !== \"function\") return false;\r\n\r\n try {\r\n input.showPicker();\r\n return true;\r\n } catch (err) {\r\n // Chromium throws NotAllowedError if not called from a user gesture\r\n // We intentionally swallow it because this is often used programmatically.\r\n return false;\r\n }\r\n }\r\n\r\n protected getSelectionTarget(): HTMLInputElement | HTMLTextAreaElement | null {\r\n const el = this.getNativeControl();\r\n if (!el) return null;\r\n\r\n // textarea always supports selection\r\n if (el instanceof HTMLTextAreaElement) return el;\r\n\r\n if (el instanceof HTMLInputElement) {\r\n const t = (el.type || \"\").toLowerCase();\r\n\r\n // types that don't support selection APIs\r\n if (\r\n t === \"date\" ||\r\n t === \"time\" ||\r\n t === \"week\" ||\r\n t === \"month\" ||\r\n t === \"datetime-local\" ||\r\n t === \"number\" ||\r\n t === \"file\"\r\n ) {\r\n return null;\r\n }\r\n\r\n return el;\r\n }\r\n\r\n return null;\r\n }\r\n\r\n get selectionStart(): number | null {\r\n return this.getSelectionTarget()?.selectionStart ?? null;\r\n }\r\n set selectionStart(v: number | null) {\r\n const t = this.getSelectionTarget();\r\n if (!t) return;\r\n t.selectionStart = v;\r\n }\r\n\r\n get selectionEnd(): number | null {\r\n return this.getSelectionTarget()?.selectionEnd ?? null;\r\n }\r\n set selectionEnd(v: number | null) {\r\n const t = this.getSelectionTarget();\r\n if (!t) return;\r\n t.selectionEnd = v;\r\n }\r\n\r\n get selectionDirection(): \"forward\" | \"backward\" | \"none\" | null {\r\n return this.getSelectionTarget()?.selectionDirection ?? null;\r\n }\r\n\r\n select() {\r\n this.getSelectionTarget()?.select?.();\r\n }\r\n\r\n setSelectionRange(start: number, end: number, direction?: \"forward\" | \"backward\" | \"none\") {\r\n this.getSelectionTarget()?.setSelectionRange?.(start, end, direction);\r\n }\r\n\r\n setRangeText(\r\n replacement: string,\r\n start?: number,\r\n end?: number,\r\n selectionMode?: \"select\" | \"start\" | \"end\" | \"preserve\"\r\n ) {\r\n const el = this.getSelectionTarget();\r\n if (!el || this.disabled || this.readonly) return;\r\n\r\n if (start !== undefined && end !== undefined) {\r\n el.setRangeText(replacement, start, end, selectionMode);\r\n } else {\r\n el.setRangeText(replacement);\r\n }\r\n\r\n this.syncFromNative(true);\r\n }\r\n\r\n // ---- valueAsNumber/valueAsDate (input only)\r\n get valueAsNumber(): number {\r\n return this.nativeInput?.valueAsNumber ?? Number.NaN;\r\n }\r\n set valueAsNumber(v: number) {\r\n const input = this.nativeInput;\r\n if (!input || this.disabled || this.readonly) return;\r\n input.valueAsNumber = v;\r\n this.syncFromNative(true);\r\n }\r\n\r\n get valueAsDate(): Date | null {\r\n return this.nativeInput?.valueAsDate ?? null;\r\n }\r\n set valueAsDate(v: Date | null) {\r\n const input = this.nativeInput;\r\n if (!input || this.disabled || this.readonly) return;\r\n input.valueAsDate = v;\r\n this.syncFromNative(true);\r\n }\r\n\r\n // ---- stepping (input only)\r\n stepUp(n?: number) {\r\n const input = this.nativeInput;\r\n if (!input || this.disabled || this.readonly) return;\r\n input.stepUp(n);\r\n this.syncFromNative(true);\r\n }\r\n\r\n stepDown(n?: number) {\r\n const input = this.nativeInput;\r\n if (!input || this.disabled || this.readonly) return;\r\n input.stepDown(n);\r\n this.syncFromNative(true);\r\n }\r\n\r\n // ---- native-ish validity API\r\n setCustomValidity(message: string) {\r\n if (this.disabled) return;\r\n\r\n if (message) {\r\n this.internals.setValidity(\r\n { customError: true },\r\n message,\r\n this.getValidityAnchor()\r\n );\r\n } else {\r\n this.internals.setValidity({});\r\n this.syncValidity();\r\n }\r\n }\r\n}\r\n"],"names":["FormControlBase","LitElement","constructor","super","this","defaultValue","name","formId","disabled","readonly","required","requiredMessage","attachInternals","Error","internals","formAssociated","form","validity","validationMessage","willValidate","checkValidity","reportValidity","formResetCallback","onFormReset","syncFormValue","syncValidity","formDisabledCallback","onFormDisabled","formStateRestoreCallback","state","onFormStateRestore","getCustomErrorMessage","validateForForm","setValueFromFormState","_disabled","onNativeValueMutated","_native","setFormValue","v","getFormValue","setValidity","isEmpty","valueMissing","getValidityAnchor","msg","customError","reemitNativeEvent","type","originalEvent","init","common","bubbles","composed","cancelable","includes","ev","detail","CustomEvent","Event","__originalEvent","dispatchEvent","captureDefaultValue","initial","nativeControl","getNativeControl","nativeInput","el","HTMLInputElement","nativeTextarea","HTMLTextAreaElement","syncFromNative","runValidity","native","focus","options","blur","click","showPicker","input","err","getSelectionTarget","t","toLowerCase","selectionStart","selectionEnd","selectionDirection","select","setSelectionRange","start","end","direction","setRangeText","replacement","selectionMode","valueAsNumber","Number","NaN","valueAsDate","stepUp","n","stepDown","setCustomValidity","message","__decorateClass","property","String","reflect","prototype","Boolean"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"form-control-base.js","sources":["../../../src/helper/internals/form-control-base.ts"],"sourcesContent":["import { LitElement } from \"lit\";\r\nimport { property } from \"lit/decorators.js\";\r\n\r\nexport type FormState = string | File | FormData | null | string;\r\n\r\nexport abstract class FormControlBase extends LitElement {\r\n /** Enables form-associated custom element behavior */\r\n static formAssociated = true;\r\n\r\n protected internals: ElementInternals;\r\n protected defaultValue = \"\";\r\n\r\n /** Native form attributes you’ll reuse everywhere */\r\n @property({ type: String, reflect: true }) name = \"\";\r\n @property({ type: String, reflect: true })\r\n formId: string | null = null;\r\n @property({ type: Boolean, reflect: true }) disabled = false;\r\n @property({ type: Boolean, reflect: true }) readonly = false;\r\n @property({ type: Boolean, reflect: true }) required = false;\r\n @property({ type: String }) requiredMessage = \"This field is required.\";\r\n\r\n constructor() {\r\n super();\r\n\r\n if (typeof (this as any).attachInternals === \"function\") {\r\n // @ts-ignore\r\n this.internals = this.attachInternals();\r\n } else {\r\n throw new Error(\r\n \"ElementInternals / form-associated custom elements not supported in this browser.\"\r\n );\r\n }\r\n }\r\n\r\n // Native form APIs (pass-through)\r\n get form() {\r\n return this.internals.form;\r\n }\r\n get validity() {\r\n return this.internals.validity;\r\n }\r\n get validationMessage() {\r\n return this.internals.validationMessage;\r\n }\r\n get willValidate() {\r\n return this.internals.willValidate;\r\n }\r\n checkValidity() {\r\n return this.internals.checkValidity();\r\n }\r\n reportValidity() {\r\n return this.internals.reportValidity();\r\n }\r\n\r\n // Form callbacks\r\n formResetCallback() {\r\n this.onFormReset();\r\n this.syncFormValue();\r\n this.syncValidity();\r\n }\r\n\r\n formDisabledCallback(disabled: boolean) {\r\n this.disabled = disabled;\r\n this.onFormDisabled(disabled);\r\n this.syncValidity();\r\n }\r\n\r\n formStateRestoreCallback(state: FormState) {\r\n this.onFormStateRestore(state);\r\n this.syncFormValue();\r\n this.syncValidity();\r\n }\r\n\r\n // Hooks for subclasses\r\n\r\n /** Must return current “submission value” (string/file/formdata) */\r\n protected abstract getFormValue(): FormState;\r\n\r\n /** Must set the component state from restored state (usually string) */\r\n protected abstract setValueFromFormState(state: FormState): void;\r\n\r\n /** Must return the internal focusable control to anchor validity bubbles */\r\n protected abstract getValidityAnchor(): HTMLElement | undefined;\r\n\r\n /** Must return true if empty (for required) */\r\n protected abstract isEmpty(): boolean;\r\n\r\n /** Must return the native control you want to proxy to (input/textarea/select/...) */\r\n protected abstract getNativeControl(): HTMLElement | null;\r\n\r\n /** Optional: return first custom error message (or empty string) */\r\n protected getCustomErrorMessage(): string {\r\n return \"\";\r\n }\r\n\r\n protected validateForForm(): string {\r\n // return \"\" if OK, otherwise return error message\r\n return \"\";\r\n }\r\n\r\n /** Optional: reset component to default */\r\n protected onFormReset() {\r\n this.setValueFromFormState(this.defaultValue);\r\n }\r\n\r\n /** Optional: react to fieldset disabled */\r\n protected onFormDisabled(_disabled: boolean) { }\r\n\r\n /** Optional: handle BFCache restore */\r\n protected onFormStateRestore(state: FormState) {\r\n this.setValueFromFormState(state);\r\n }\r\n\r\n /**\r\n * Called by base after a proxy method mutates the native control.\r\n * Subclasses should pull native.value into their state and optionally validate.\r\n */\r\n protected onNativeValueMutated(_native: any): void { }\r\n\r\n // Shared utilities (form value and validity)\r\n\r\n protected syncFormValue() {\r\n if (!this.name || this.disabled) {\r\n this.internals.setFormValue(null);\r\n return;\r\n }\r\n\r\n const v = this.getFormValue();\r\n\r\n if (v === null) {\r\n this.internals.setFormValue(null);\r\n return;\r\n }\r\n\r\n this.internals.setFormValue(v);\r\n }\r\n\r\n protected syncValidity() {\r\n if (this.disabled) {\r\n this.internals.setValidity({});\r\n return;\r\n }\r\n\r\n // Required\r\n if (this.required && this.isEmpty()) {\r\n this.internals.setValidity(\r\n { valueMissing: true },\r\n this.requiredMessage || \"This field is required.\",\r\n this.getValidityAnchor()\r\n );\r\n return;\r\n }\r\n\r\n // Custom error (subclass)\r\n const msg = this.validateForForm();\r\n if (msg) {\r\n this.internals.setValidity(\r\n { customError: true },\r\n msg,\r\n this.getValidityAnchor()\r\n );\r\n return;\r\n }\r\n\r\n this.internals.setValidity({});\r\n }\r\n\r\n protected reemitNativeEvent(\r\n type: string,\r\n originalEvent: Event,\r\n init?: Partial<EventInit> & { detail?: any }\r\n ) {\r\n const cancelable = [\"submit\"].includes(type) ? true : false;\r\n const common: EventInit = { bubbles: true, composed: true, cancelable };\r\n\r\n const ev =\r\n init?.detail !== undefined\r\n ? new CustomEvent(type, { ...common, ...init })\r\n : new Event(type, { ...common, ...init });\r\n\r\n (ev as any).__originalEvent = originalEvent;\r\n\r\n this.dispatchEvent(ev);\r\n }\r\n\r\n /** Call once after initial render */\r\n protected captureDefaultValue(initial: string) {\r\n this.defaultValue = initial ?? \"\";\r\n }\r\n\r\n\r\n\r\n // Native proxy helpers (shared across all controls)\r\n\r\n protected get nativeControl(): any | null {\r\n return this.getNativeControl() as any;\r\n }\r\n\r\n protected get nativeInput(): HTMLInputElement | null {\r\n const el = this.getNativeControl();\r\n return el instanceof HTMLInputElement ? el : null;\r\n }\r\n\r\n protected get nativeTextarea(): HTMLTextAreaElement | null {\r\n const el = this.getNativeControl();\r\n return el instanceof HTMLTextAreaElement ? el : null;\r\n }\r\n\r\n /** Central sync after proxy calls */\r\n protected syncFromNative(runValidity = true) {\r\n const native = this.nativeControl;\r\n if (!native) return;\r\n\r\n this.onNativeValueMutated(native);\r\n this.syncFormValue();\r\n if (runValidity) this.syncValidity();\r\n }\r\n\r\n // focus/blur/click/showPicker\r\n focus(options?: FocusOptions) {\r\n this.nativeControl?.focus?.(options);\r\n }\r\n\r\n blur() {\r\n this.nativeControl?.blur?.();\r\n }\r\n\r\n click() {\r\n this.nativeControl?.click?.();\r\n }\r\n\r\n showPicker(): boolean {\r\n const input = this.nativeInput as any;\r\n if (!input || typeof input.showPicker !== \"function\") return false;\r\n\r\n try {\r\n input.showPicker();\r\n return true;\r\n } catch (err) {\r\n // Chromium throws NotAllowedError if not called from a user gesture\r\n // We intentionally swallow it because this is often used programmatically.\r\n return false;\r\n }\r\n }\r\n\r\n protected getSelectionTarget(): HTMLInputElement | HTMLTextAreaElement | null {\r\n const el = this.getNativeControl();\r\n if (!el) return null;\r\n\r\n // textarea always supports selection\r\n if (el instanceof HTMLTextAreaElement) return el;\r\n\r\n if (el instanceof HTMLInputElement) {\r\n const t = (el.type || \"\").toLowerCase();\r\n\r\n // types that don't support selection APIs\r\n if (\r\n t === \"date\" ||\r\n t === \"time\" ||\r\n t === \"week\" ||\r\n t === \"month\" ||\r\n t === \"datetime-local\" ||\r\n t === \"number\" ||\r\n t === \"file\"\r\n ) {\r\n return null;\r\n }\r\n\r\n return el;\r\n }\r\n\r\n return null;\r\n }\r\n\r\n get selectionStart(): number | null {\r\n return this.getSelectionTarget()?.selectionStart ?? null;\r\n }\r\n set selectionStart(v: number | null) {\r\n const t = this.getSelectionTarget();\r\n if (!t) return;\r\n t.selectionStart = v;\r\n }\r\n\r\n get selectionEnd(): number | null {\r\n return this.getSelectionTarget()?.selectionEnd ?? null;\r\n }\r\n set selectionEnd(v: number | null) {\r\n const t = this.getSelectionTarget();\r\n if (!t) return;\r\n t.selectionEnd = v;\r\n }\r\n\r\n get selectionDirection(): \"forward\" | \"backward\" | \"none\" | null {\r\n return this.getSelectionTarget()?.selectionDirection ?? null;\r\n }\r\n\r\n select() {\r\n this.getSelectionTarget()?.select?.();\r\n }\r\n\r\n setSelectionRange(start: number, end: number, direction?: \"forward\" | \"backward\" | \"none\") {\r\n this.getSelectionTarget()?.setSelectionRange?.(start, end, direction);\r\n }\r\n\r\n setRangeText(\r\n replacement: string,\r\n start?: number,\r\n end?: number,\r\n selectionMode?: \"select\" | \"start\" | \"end\" | \"preserve\"\r\n ) {\r\n const el = this.getSelectionTarget();\r\n if (!el || this.disabled || this.readonly) return;\r\n\r\n if (start !== undefined && end !== undefined) {\r\n el.setRangeText(replacement, start, end, selectionMode);\r\n } else {\r\n el.setRangeText(replacement);\r\n }\r\n\r\n this.syncFromNative(true);\r\n }\r\n\r\n // valueAsNumber/valueAsDate (input only)\r\n get valueAsNumber(): number {\r\n return this.nativeInput?.valueAsNumber ?? Number.NaN;\r\n }\r\n set valueAsNumber(v: number) {\r\n const input = this.nativeInput;\r\n if (!input || this.disabled || this.readonly) return;\r\n input.valueAsNumber = v;\r\n this.syncFromNative(true);\r\n }\r\n\r\n get valueAsDate(): Date | null {\r\n return this.nativeInput?.valueAsDate ?? null;\r\n }\r\n set valueAsDate(v: Date | null) {\r\n const input = this.nativeInput;\r\n if (!input || this.disabled || this.readonly) return;\r\n input.valueAsDate = v;\r\n this.syncFromNative(true);\r\n }\r\n\r\n // stepping (input only)\r\n stepUp(n?: number) {\r\n const input = this.nativeInput;\r\n if (!input || this.disabled || this.readonly) return;\r\n input.stepUp(n);\r\n this.syncFromNative(true);\r\n }\r\n\r\n stepDown(n?: number) {\r\n const input = this.nativeInput;\r\n if (!input || this.disabled || this.readonly) return;\r\n input.stepDown(n);\r\n this.syncFromNative(true);\r\n }\r\n\r\n // native-ish validity API\r\n setCustomValidity(message: string) {\r\n if (this.disabled) return;\r\n\r\n if (message) {\r\n this.internals.setValidity(\r\n { customError: true },\r\n message,\r\n this.getValidityAnchor()\r\n );\r\n } else {\r\n this.internals.setValidity({});\r\n this.syncValidity();\r\n }\r\n }\r\n}\r\n"],"names":["FormControlBase","LitElement","constructor","super","this","defaultValue","name","formId","disabled","readonly","required","requiredMessage","attachInternals","Error","internals","formAssociated","form","validity","validationMessage","willValidate","checkValidity","reportValidity","formResetCallback","onFormReset","syncFormValue","syncValidity","formDisabledCallback","onFormDisabled","formStateRestoreCallback","state","onFormStateRestore","getCustomErrorMessage","validateForForm","setValueFromFormState","_disabled","onNativeValueMutated","_native","setFormValue","v","getFormValue","setValidity","isEmpty","valueMissing","getValidityAnchor","msg","customError","reemitNativeEvent","type","originalEvent","init","common","bubbles","composed","cancelable","includes","ev","detail","CustomEvent","Event","__originalEvent","dispatchEvent","captureDefaultValue","initial","nativeControl","getNativeControl","nativeInput","el","HTMLInputElement","nativeTextarea","HTMLTextAreaElement","syncFromNative","runValidity","native","focus","options","blur","click","showPicker","input","err","getSelectionTarget","t","toLowerCase","selectionStart","selectionEnd","selectionDirection","select","setSelectionRange","start","end","direction","setRangeText","replacement","selectionMode","valueAsNumber","Number","NaN","valueAsDate","stepUp","n","stepDown","setCustomValidity","message","__decorateClass","property","String","reflect","prototype","Boolean"],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Focus ring box-shadow using `--sky-focus-ring-color` (falls back to active-primary).
|
|
3
|
+
*
|
|
4
|
+
* Theme-level `--sky-focus-ring` resolves nested `var()` on the theme host before
|
|
5
|
+
* inheritance, so local color overrides do not retint an inherited ring. Redeclare
|
|
6
|
+
* this formula on the same element that sets `--sky-focus-ring-color`.
|
|
7
|
+
*/
|
|
8
|
+
export declare const SKY_FOCUS_RING_SHADOW = "0 0 0 3px color-mix(in oklch, var(--sky-focus-ring-color, var(--sky-active-primary)) 42%, transparent)";
|
|
9
|
+
/** Redeclare `--sky-focus-ring` on `:host` so local `--sky-focus-ring-color` applies. */
|
|
10
|
+
export declare const skyFocusRingHostStyles: import("lit").CSSResult;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import{css as r}from"lit";const o="0 0 0 3px color-mix(in oklch, var(--sky-focus-ring-color, var(--sky-active-primary)) 42%, transparent)",i=r`
|
|
2
|
+
:host {
|
|
3
|
+
--sky-focus-ring: 0 0 0 3px color-mix(
|
|
4
|
+
in oklch,
|
|
5
|
+
var(--sky-focus-ring-color, var(--sky-active-primary)) 42%,
|
|
6
|
+
transparent
|
|
7
|
+
);
|
|
8
|
+
}
|
|
9
|
+
`;export{o as SKY_FOCUS_RING_SHADOW,i as skyFocusRingHostStyles};
|
|
10
|
+
//# sourceMappingURL=focus-ring.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"focus-ring.js","sources":["../../../src/helper/styles/focus-ring.ts"],"sourcesContent":["import { css } from \"lit\";\n\n/**\n * Focus ring box-shadow using `--sky-focus-ring-color` (falls back to active-primary).\n *\n * Theme-level `--sky-focus-ring` resolves nested `var()` on the theme host before\n * inheritance, so local color overrides do not retint an inherited ring. Redeclare\n * this formula on the same element that sets `--sky-focus-ring-color`.\n */\nexport const SKY_FOCUS_RING_SHADOW =\n \"0 0 0 3px color-mix(in oklch, var(--sky-focus-ring-color, var(--sky-active-primary)) 42%, transparent)\";\n\n/** Redeclare `--sky-focus-ring` on `:host` so local `--sky-focus-ring-color` applies. */\nexport const skyFocusRingHostStyles = css`\n :host {\n --sky-focus-ring: 0 0 0 3px color-mix(\n in oklch,\n var(--sky-focus-ring-color, var(--sky-active-primary)) 42%,\n transparent\n );\n }\n`;\n"],"names":["SKY_FOCUS_RING_SHADOW","skyFocusRingHostStyles","css"],"mappings":"0BASO,MAAMA,EACX,yGAGWC,EAAyBC,CAAA;;;;;;;;"}
|
|
@@ -20,20 +20,6 @@ export declare const DEFAULT_COLOR_TOKENS: Record<string, string>;
|
|
|
20
20
|
* @returns CSS color value
|
|
21
21
|
*/
|
|
22
22
|
export declare function resolveColor(input: string, customMap?: Record<string, string>): string;
|
|
23
|
-
/**
|
|
24
|
-
* Determines fallback text color for a given background color token.
|
|
25
|
-
*
|
|
26
|
-
* Prefer CSS `contrast-color()` against the **actual fill custom property**
|
|
27
|
-
* for solid surfaces (see `./contrast-color.ts`). Keep using this helper as the
|
|
28
|
-
* pre-`@supports` / inline-var fallback so older browsers stay readable.
|
|
29
|
-
*
|
|
30
|
-
* Soft / tinted surfaces should use ink / soft-semantic tokens instead —
|
|
31
|
-
* do not pair them with `contrast-color()`.
|
|
32
|
-
*
|
|
33
|
-
* @param input - Color token (e.g., 'primary')
|
|
34
|
-
* @returns CSS color value for text
|
|
35
|
-
*/
|
|
36
|
-
export declare function resolveTextColorForToken(input: string): string;
|
|
37
23
|
/** True when the token is the neutral glass surface (`default`), not a brand accent. */
|
|
38
24
|
export declare function isDefaultColorToken(input: string): boolean;
|
|
39
25
|
/** Foreground ink (labels, borders) — never use glass-solid as text. */
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const r={primary:"var(--sky-active-primary)",active:"var(--sky-active-primary)",secondary:"var(--sky-info-primary)",success:"var(--sky-success-primary)",danger:"var(--sky-danger-primary)",warning:"var(--sky-warning-primary)",info:"var(--sky-info-primary)",light:"var(--sky-text-light)",dark:"var(--sky-text-dark)",muted:"var(--sky-text-tertiary)","border-light":"var(--sky-border-light)",default:"var(--sky-glass-solid)"};function a(a,t={}){const o={...r,...t};return o[a]||a||o.primary}function t(r){return
|
|
1
|
+
const r={primary:"var(--sky-active-primary)",active:"var(--sky-active-primary)",secondary:"var(--sky-info-primary)",success:"var(--sky-success-primary)",danger:"var(--sky-danger-primary)",warning:"var(--sky-warning-primary)",info:"var(--sky-info-primary)",light:"var(--sky-text-light)",dark:"var(--sky-text-dark)",muted:"var(--sky-text-tertiary)","border-light":"var(--sky-border-light)",default:"var(--sky-glass-solid)"};function a(a,t={}){const o={...r,...t};return o[a]||a||o.primary}function t(r){return"default"===r}function o(r){return t(r)?"var(--sky-text-primary)":a(r)}function e(r){return t(r)?"var(--sky-active-primary)":a(r)}const i={primary:"active",active:"active",success:"success",danger:"danger",warning:"warning",info:"info",secondary:"info"};function s(r){return i[r]??null}function n(r,a={}){return{bg:`var(--sky-${r}-quinary)`,color:`var(--sky-${r}-primary-dark)`,border:a.bordered?`1px solid var(--sky-${r}-g1)`:"none"}}function y(){return"var(--sky-border-primary)"}function v(r){return`${r}px solid var(--sky-border-light)`}const c={shadow:{bg:"var(--sky-glass-solid)",hoverBg:"var(--sky-glass-solid)",color:"var(--sky-text-primary)",hoverColor:"var(--sky-active-primary)",shadow:"none",hoverShadow:"var(--sky-box-shadow-hover)",arrow:"var(--sky-glass-solid)"},solid:{color:"var(--sky-text-primary)",hoverColor:"var(--sky-text-primary)",hoverShadow:"var(--sky-box-shadow-hover)"},faded:{color:"var(--sky-text-primary)",hoverColor:"var(--sky-text-primary)",arrow:"var(--sky-hover-tertiary)"},bordered:{color:"var(--sky-text-primary)",border:v(2),hoverColor:"var(--sky-text-primary)",hoverBorder:"2px solid var(--sky-text-tertiary)",arrow:"var(--sky-border-light)"},transparent:{color:"var(--sky-text-primary)",hoverBg:"var(--sky-hover-tertiary)",hoverColor:"var(--sky-text-primary)"},flat:{bg:"var(--sky-hover-tertiary)",color:"var(--sky-text-primary)",hoverBg:"var(--sky-hover-secondary)",hoverColor:"var(--sky-active-primary)",arrow:"var(--sky-hover-tertiary)"},ghost:{color:"var(--sky-text-primary)",border:v(2),hoverBg:"var(--sky-hover-secondary)",hoverColor:"var(--sky-text-primary)"},link:{color:"var(--sky-text-primary)",hoverColor:"var(--sky-active-primary)"},light:{color:"var(--sky-text-primary)"}};function l(r,a,o){if(!t(r))return o;const e=c[a];return e?{...o,...e}:o}function k(r,a=20){return`color-mix(in srgb, ${r} ${100-a}%, var(--sky-text-dark))`}function d(r,a=20){return`color-mix(in srgb, ${r} ${100-a}%, var(--sky-text-black))`}function u(r,a=20){return`color-mix(in srgb, ${r} ${100-a}%, var(--sky-text-white))`}function h(r,a=15){return`color-mix(in srgb, ${r} ${a}%, transparent)`}function p(a){const t=a.match(/^([^\s]+)(\s+.+)?$/),o=t?.[1]??a;return`${r[o]||o}${t?.[2]??""}`}function g(r){const a=(r||"").trim(),t=a.indexOf(":");let o="",e=a;-1!==t&&(o=a.slice(0,t).trim(),e=a.slice(t+1).trim());let i="linear",s="90deg";if(o){const[r,t]=o.split("@").map(r=>r.trim()),n=(r||"").toLowerCase();"linear"===n||"radial"===n||"conic"===n?(i=n,s=t||("linear"===i?"90deg":"radial"===i?"circle":"from 0deg at 50% 50%")):e=a}return{kind:i,args:s,stops:e.split(",").map(r=>r.trim()).filter(Boolean)}}function m(r,a="var(--sky-active-primary)"){const t=g(r),o=(t.stops.length?t.stops:[a,a]).map(r=>p(r)),{kind:e,args:i}=t;switch(e){case"linear":return`linear-gradient(${i}, ${o.join(", ")})`;case"radial":return`radial-gradient(${i}, ${o.join(", ")})`;case"conic":return`conic-gradient(${i}, ${o.join(", ")})`;default:return`linear-gradient(90deg, ${o.join(", ")})`}}class f{constructor(r={}){this.config={prefix:r.prefix||"sky",useColorMix:r.useColorMix??!0}}resolve(a){if(a.startsWith("#"))return a;if(a.startsWith("rgb")||a.startsWith("hsl"))return a;if(a.startsWith("var("))return a;const t=`var(--${this.config.prefix}-${a})`;return r[a]||t||r.primary}getTextColor(r){return"default"===r?"var(--sky-text-primary)":"var(--sky-on-color-fallback-light, var(--sky-text-white))"}getHoverColor(r,a=20){return this.config.useColorMix?k(r,a):r}}const x=new f;export{f as ColorResolver,r as DEFAULT_COLOR_TOKENS,x as colorResolver,m as createGradient,d as darkShade,h as fadeMix,k as hoverShade,t as isDefaultColorToken,u as lightShade,g as parseGradientSpec,e as resolveAccentColorForToken,a as resolveColor,p as resolveGradientStop,o as resolveInkColorForToken,s as resolveSemanticSurfaceKey,n as semanticSoftSurfaceTokens,y as skyBorderPrimaryShorthand,v as skyBorderWidthSolid,l as tuneSurfaceVariantForDefaultColor};
|
|
2
2
|
//# sourceMappingURL=color-resolver.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"color-resolver.js","sources":["../../../src/helper/utils/color-resolver.ts"],"sourcesContent":["/**\r\n * Color resolution utilities for Sky Design System\r\n * Provides consistent color token mapping across components\r\n */\r\n\r\nexport type ColorToken =\r\n | 'primary'\r\n | 'secondary'\r\n | 'success'\r\n | 'danger'\r\n | 'warning'\r\n | 'light'\r\n | 'dark'\r\n | 'default'\r\n | string; // Custom CSS color\r\n\r\nexport interface ColorResolverConfig {\r\n /** CSS variable prefix (default: 'sky') */\r\n prefix?: string;\r\n /** Whether to use color-mix for hover states */\r\n useColorMix?: boolean;\r\n}\r\n\r\n/**\r\n * Default color token mapping to CSS variables\r\n */\r\nexport const DEFAULT_COLOR_TOKENS: Record<string, string> = {\r\n primary: 'var(--sky-active-primary)',\r\n active: 'var(--sky-active-primary)',\r\n secondary: 'var(--sky-info-primary)',\r\n success: 'var(--sky-success-primary)',\r\n danger: 'var(--sky-danger-primary)',\r\n warning: 'var(--sky-warning-primary)',\r\n info: 'var(--sky-info-primary)',\r\n light: 'var(--sky-text-light)',\r\n dark: 'var(--sky-text-dark)',\r\n /** Muted line/text (e.g. dividers); maps to `--sky-text-tertiary`. */\r\n muted: 'var(--sky-text-tertiary)',\r\n /** Light border tone; maps to `--sky-border-light`. */\r\n 'border-light': 'var(--sky-border-light)',\r\n default: 'var(--sky-glass-solid)',\r\n} as const;\r\n\r\n/**\r\n * Resolves a color token to its CSS value\r\n * @param input - Color token (e.g., 'primary') or custom CSS color\r\n * @param customMap - Optional custom token mapping (overrides defaults)\r\n * @returns CSS color value\r\n */\r\nexport function resolveColor(\r\n input: string,\r\n customMap: Record<string, string> = {}\r\n): string {\r\n const map = { ...DEFAULT_COLOR_TOKENS, ...customMap };\r\n return map[input] || input || map.primary;\r\n}\r\n\r\n/**\r\n * Determines fallback text color for a given background color token.\r\n *\r\n * Prefer CSS `contrast-color()` against the **actual fill custom property**\r\n * for solid surfaces (see `./contrast-color.ts`). Keep using this helper as the\r\n * pre-`@supports` / inline-var fallback so older browsers stay readable.\r\n *\r\n * Soft / tinted surfaces should use ink / soft-semantic tokens instead —\r\n * do not pair them with `contrast-color()`.\r\n *\r\n * @param input - Color token (e.g., 'primary')\r\n * @returns CSS color value for text\r\n */\r\nexport function resolveTextColorForToken(input: string): string {\r\n const tokenMap: Record<string, string> = {\r\n dark: 'var(--sky-text-light)',\r\n light: 'var(--sky-text-dark)',\r\n warning: 'var(--sky-on-color-fallback-dark, var(--sky-text-black))',\r\n success: 'var(--sky-on-color-fallback-dark, var(--sky-text-black))',\r\n default: 'var(--sky-text-primary)',\r\n };\r\n\r\n return tokenMap[input] || 'var(--sky-on-color-fallback-light, var(--sky-text-white))';\r\n}\r\n\r\n/** True when the token is the neutral glass surface (`default`), not a brand accent. */\r\nexport function isDefaultColorToken(input: string): boolean {\r\n return input === 'default';\r\n}\r\n\r\n/** Foreground ink (labels, borders) — never use glass-solid as text. */\r\nexport function resolveInkColorForToken(input: string): string {\r\n return isDefaultColorToken(input)\r\n ? 'var(--sky-text-primary)'\r\n : resolveColor(input);\r\n}\r\n\r\n/** Accent for hover/focus on neutral surfaces. */\r\nexport function resolveAccentColorForToken(input: string): string {\r\n return isDefaultColorToken(input)\r\n ? 'var(--sky-active-primary)'\r\n : resolveColor(input);\r\n}\r\n\r\n/** Maps component color tokens to theme semantic keys (`active`, `success`, …). */\r\nconst SEMANTIC_SURFACE_KEYS: Record<string, string> = {\r\n primary: \"active\",\r\n active: \"active\",\r\n success: \"success\",\r\n danger: \"danger\",\r\n warning: \"warning\",\r\n info: \"info\",\r\n secondary: \"info\",\r\n};\r\n\r\n/**\r\n * Resolves a color token to a theme semantic surface key, if one exists.\r\n */\r\nexport function resolveSemanticSurfaceKey(colorToken: string): string | null {\r\n return SEMANTIC_SURFACE_KEYS[colorToken] ?? null;\r\n}\r\n\r\n/** Soft semantic surface tokens for alerts, badges, and subtle status blocks. */\r\nexport function semanticSoftSurfaceTokens(\r\n semanticKey: string,\r\n options: { bordered?: boolean } = {},\r\n): { bg: string; color: string; border: string } {\r\n return {\r\n bg: `var(--sky-${semanticKey}-quinary)`,\r\n color: `var(--sky-${semanticKey}-primary-dark)`,\r\n border: options.bordered\r\n ? `1px solid var(--sky-${semanticKey}-g1)`\r\n : \"none\",\r\n };\r\n}\r\n\r\n/**\r\n * Theme glass border shorthand (`1px solid …` from `--sky-border-primary`).\r\n * Use as a full `border` value — do not wrap in `Npx solid var(--sky-border-primary)`.\r\n */\r\nexport function skyBorderPrimaryShorthand(): string {\r\n return 'var(--sky-border-primary)';\r\n}\r\n\r\n/**\r\n * Separator stroke for custom widths (`--sky-border-light` is a color, not shorthand).\r\n */\r\nexport function skyBorderWidthSolid(widthPx: number): string {\r\n return `${widthPx}px solid var(--sky-border-light)`;\r\n}\r\n\r\n/** Partial variant overrides when `color=\"default\"` (surface token, not ink). */\r\nexport type DefaultColorVariantPatch = Partial<{\r\n bg: string;\r\n color: string;\r\n border: string;\r\n shadow: string;\r\n hoverBg: string;\r\n hoverColor: string;\r\n hoverShadow: string;\r\n hoverBorder: string;\r\n arrow: string;\r\n}>;\r\n\r\nconst DEFAULT_COLOR_VARIANT_PATCHES: Record<string, DefaultColorVariantPatch> = {\r\n shadow: {\r\n bg: 'var(--sky-glass-solid)',\r\n hoverBg: 'var(--sky-glass-solid)',\r\n color: 'var(--sky-text-primary)',\r\n hoverColor: 'var(--sky-active-primary)',\r\n shadow: 'none',\r\n hoverShadow: 'var(--sky-box-shadow-hover)',\r\n arrow: 'var(--sky-glass-solid)',\r\n },\r\n solid: {\r\n hoverShadow: 'var(--sky-box-shadow-hover)',\r\n },\r\n faded: {\r\n color: 'var(--sky-text-primary)',\r\n hoverColor: 'var(--sky-text-primary)',\r\n arrow: 'var(--sky-hover-tertiary)',\r\n },\r\n bordered: {\r\n color: 'var(--sky-text-primary)',\r\n border: skyBorderWidthSolid(2),\r\n hoverColor: 'var(--sky-text-primary)',\r\n hoverBorder: '2px solid var(--sky-text-tertiary)',\r\n arrow: 'var(--sky-border-light)',\r\n },\r\n transparent: {\r\n color: 'var(--sky-text-primary)',\r\n hoverBg: 'var(--sky-hover-tertiary)',\r\n hoverColor: 'var(--sky-text-primary)',\r\n },\r\n flat: {\r\n bg: 'var(--sky-hover-tertiary)',\r\n color: 'var(--sky-text-primary)',\r\n hoverBg: 'var(--sky-hover-secondary)',\r\n hoverColor: 'var(--sky-active-primary)',\r\n arrow: 'var(--sky-hover-tertiary)',\r\n },\r\n ghost: {\r\n color: 'var(--sky-text-primary)',\r\n border: skyBorderWidthSolid(2),\r\n hoverBg: 'var(--sky-hover-secondary)',\r\n hoverColor: 'var(--sky-text-primary)',\r\n },\r\n link: {\r\n color: 'var(--sky-text-primary)',\r\n hoverColor: 'var(--sky-active-primary)',\r\n },\r\n light: {\r\n color: 'var(--sky-text-primary)',\r\n },\r\n};\r\n\r\n/**\r\n * Applies variant style overrides for `color=\"default\"` so glass tokens are not\r\n * used as text/border/hover ink on translucent surfaces.\r\n */\r\nexport function tuneSurfaceVariantForDefaultColor<T extends DefaultColorVariantPatch>(\r\n colorToken: string,\r\n variant: string,\r\n styles: T,\r\n): T {\r\n if (!isDefaultColorToken(colorToken)) return styles;\r\n const patch = DEFAULT_COLOR_VARIANT_PATCHES[variant];\r\n if (!patch) return styles;\r\n return { ...styles, ...patch };\r\n}\r\n\r\n/**\r\n * Creates a hover shade using color-mix\r\n * @param color - Base CSS color\r\n * @param amount - Percentage of black to mix (0-100)\r\n * @returns CSS color-mix() value\r\n */\r\nexport function hoverShade(color: string, amount: number = 20): string {\r\n return `color-mix(in srgb, ${color} ${100 - amount}%, var(--sky-text-dark))`;\r\n}\r\n/**\r\n * Creates a hover shade using color-mix\r\n * @param color - Base CSS color\r\n * @param amount - Percentage of black to mix (0-100)\r\n * @returns CSS color-mix() value\r\n */\r\nexport function darkShade(color: string, amount: number = 20): string {\r\n return `color-mix(in srgb, ${color} ${100 - amount}%, var(--sky-text-black))`;\r\n}\r\n/**\r\n * Creates a hover shade using color-mix\r\n * @param color - Base CSS color\r\n * @param amount - Percentage of black to mix (0-100)\r\n * @returns CSS color-mix() value\r\n */\r\nexport function lightShade(color: string, amount: number = 20): string {\r\n return `color-mix(in srgb, ${color} ${100 - amount}%, var(--sky-text-white))`;\r\n}\r\n\r\n\r\n/**\r\n * Creates a faded/transparent version of a color\r\n * @param color - Base CSS color\r\n * @param amount - Percentage of transparency (0-100)\r\n * @returns CSS color-mix() value with transparency\r\n */\r\nexport function fadeMix(color: string, amount: number = 15): string {\r\n return `color-mix(in srgb, ${color} ${amount}%, transparent)`;\r\n}\r\n\r\n/**\r\n * Resolves gradient stop tokens to CSS colors\r\n * @param stop - Gradient stop token (e.g., 'primary 30%')\r\n * @returns CSS gradient stop value\r\n */\r\nexport function resolveGradientStop(stop: string): string {\r\n const match = stop.match(/^([^\\s]+)(\\s+.+)?$/);\r\n const head = match?.[1] ?? stop;\r\n const tail = match?.[2] ?? '';\r\n\r\n const resolved = DEFAULT_COLOR_TOKENS[head] || head;\r\n return `${resolved}${tail}`;\r\n}\r\n\r\n/**\r\n * Parses a gradient specification string\r\n */\r\nexport interface GradientSpec {\r\n kind: 'linear' | 'radial' | 'conic';\r\n args: string;\r\n stops: string[];\r\n}\r\n\r\n/**\r\n * Parses gradient specification string\r\n * Format: \"kind@args: stop1, stop2, stop3\"\r\n * Example: \"linear@90deg: primary, secondary 50%, danger\"\r\n * Example: \"radial@circle: primary, transparent\"\r\n */\r\nexport function parseGradientSpec(input: string): GradientSpec {\r\n const raw = (input || '').trim();\r\n const idx = raw.indexOf(':');\r\n let prefix = '';\r\n let stopsStr = raw;\r\n\r\n if (idx !== -1) {\r\n prefix = raw.slice(0, idx).trim();\r\n stopsStr = raw.slice(idx + 1).trim();\r\n }\r\n\r\n let kind: 'linear' | 'radial' | 'conic' = 'linear';\r\n let args = '90deg';\r\n\r\n if (prefix) {\r\n const [k, a] = prefix.split('@').map(s => s.trim());\r\n const kLower = (k || '').toLowerCase();\r\n if (kLower === 'linear' || kLower === 'radial' || kLower === 'conic') {\r\n kind = kLower;\r\n args = a || (kind === 'linear'\r\n ? '90deg'\r\n : kind === 'radial'\r\n ? 'circle'\r\n : 'from 0deg at 50% 50%');\r\n } else {\r\n stopsStr = raw;\r\n }\r\n }\r\n\r\n const stops = stopsStr\r\n .split(',')\r\n .map(s => s.trim())\r\n .filter(Boolean);\r\n\r\n return { kind, args, stops };\r\n}\r\n\r\n/**\r\n * Creates a CSS gradient from a specification string\r\n * @param specStr - Gradient specification string\r\n * @param fallbackColor - Fallback color if no stops provided\r\n * @returns CSS gradient value\r\n */\r\nexport function createGradient(\r\n specStr: string,\r\n fallbackColor: string = 'var(--sky-active-primary)'\r\n): string {\r\n const spec = parseGradientSpec(specStr);\r\n const stops = (\r\n spec.stops.length\r\n ? spec.stops\r\n : [fallbackColor, fallbackColor]\r\n ).map(st => resolveGradientStop(st));\r\n\r\n const { kind, args } = spec;\r\n\r\n switch (kind) {\r\n case 'linear':\r\n return `linear-gradient(${args}, ${stops.join(', ')})`;\r\n case 'radial':\r\n return `radial-gradient(${args}, ${stops.join(', ')})`;\r\n case 'conic':\r\n return `conic-gradient(${args}, ${stops.join(', ')})`;\r\n default:\r\n return `linear-gradient(90deg, ${stops.join(', ')})`;\r\n }\r\n}\r\n\r\n/**\r\n * Color resolver with configuration support\r\n */\r\nexport class ColorResolver {\r\n private config: Required<ColorResolverConfig>;\r\n\r\n constructor(config: ColorResolverConfig = {}) {\r\n this.config = {\r\n prefix: config.prefix || 'sky',\r\n useColorMix: config.useColorMix ?? true,\r\n };\r\n }\r\n\r\n /**\r\n * Resolves a color with prefix-aware variable names\r\n */\r\n resolve(input: string): string {\r\n if (input.startsWith('#')) return input;\r\n if (input.startsWith('rgb') || input.startsWith('hsl')) return input;\r\n if (input.startsWith('var(')) return input;\r\n\r\n const customVar = `var(--${this.config.prefix}-${input})`;\r\n const defaultResolved = DEFAULT_COLOR_TOKENS[input];\r\n\r\n return defaultResolved || customVar || DEFAULT_COLOR_TOKENS.primary;\r\n }\r\n\r\n /**\r\n * Gets text color for a background color\r\n */\r\n getTextColor(backgroundColor: string): string {\r\n // If it's a token, use the token-based logic\r\n if (backgroundColor in DEFAULT_COLOR_TOKENS) {\r\n return resolveTextColorForToken(backgroundColor);\r\n }\r\n\r\n // For custom colors, return a sensible default\r\n return 'var(--sky-text-white)';\r\n }\r\n\r\n /**\r\n * Creates a hover state color\r\n */\r\n getHoverColor(baseColor: string, darkenAmount: number = 20): string {\r\n if (!this.config.useColorMix) {\r\n // Fallback for browsers without color-mix support\r\n return baseColor;\r\n }\r\n\r\n return hoverShade(baseColor, darkenAmount);\r\n }\r\n}\r\n\r\n/**\r\n * Singleton instance for convenience\r\n */\r\nexport const colorResolver = new ColorResolver();\r\n\r\n"],"names":["DEFAULT_COLOR_TOKENS","primary","active","secondary","success","danger","warning","info","light","dark","muted","default","resolveColor","input","customMap","map","resolveTextColorForToken","isDefaultColorToken","resolveInkColorForToken","resolveAccentColorForToken","SEMANTIC_SURFACE_KEYS","resolveSemanticSurfaceKey","colorToken","semanticSoftSurfaceTokens","semanticKey","options","bg","color","border","bordered","skyBorderPrimaryShorthand","skyBorderWidthSolid","widthPx","DEFAULT_COLOR_VARIANT_PATCHES","shadow","hoverBg","hoverColor","hoverShadow","arrow","solid","faded","hoverBorder","transparent","flat","ghost","link","tuneSurfaceVariantForDefaultColor","variant","styles","patch","hoverShade","amount","darkShade","lightShade","fadeMix","resolveGradientStop","stop","match","head","parseGradientSpec","raw","trim","idx","indexOf","prefix","stopsStr","slice","kind","args","k","a","split","s","kLower","toLowerCase","stops","filter","Boolean","createGradient","specStr","fallbackColor","spec","length","st","join","ColorResolver","constructor","config","this","useColorMix","resolve","startsWith","customVar","getTextColor","backgroundColor","getHoverColor","baseColor","darkenAmount","colorResolver"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"color-resolver.js","sources":["../../../src/helper/utils/color-resolver.ts"],"sourcesContent":["/**\r\n * Color resolution utilities for Sky Design System\r\n * Provides consistent color token mapping across components\r\n */\r\n\r\nexport type ColorToken =\r\n | 'primary'\r\n | 'secondary'\r\n | 'success'\r\n | 'danger'\r\n | 'warning'\r\n | 'light'\r\n | 'dark'\r\n | 'default'\r\n | string; // Custom CSS color\r\n\r\nexport interface ColorResolverConfig {\r\n /** CSS variable prefix (default: 'sky') */\r\n prefix?: string;\r\n /** Whether to use color-mix for hover states */\r\n useColorMix?: boolean;\r\n}\r\n\r\n/**\r\n * Default color token mapping to CSS variables\r\n */\r\nexport const DEFAULT_COLOR_TOKENS: Record<string, string> = {\r\n primary: 'var(--sky-active-primary)',\r\n active: 'var(--sky-active-primary)',\r\n secondary: 'var(--sky-info-primary)',\r\n success: 'var(--sky-success-primary)',\r\n danger: 'var(--sky-danger-primary)',\r\n warning: 'var(--sky-warning-primary)',\r\n info: 'var(--sky-info-primary)',\r\n light: 'var(--sky-text-light)',\r\n dark: 'var(--sky-text-dark)',\r\n /** Muted line/text (e.g. dividers); maps to `--sky-text-tertiary`. */\r\n muted: 'var(--sky-text-tertiary)',\r\n /** Light border tone; maps to `--sky-border-light`. */\r\n 'border-light': 'var(--sky-border-light)',\r\n default: 'var(--sky-glass-solid)',\r\n} as const;\r\n\r\n/**\r\n * Resolves a color token to its CSS value\r\n * @param input - Color token (e.g., 'primary') or custom CSS color\r\n * @param customMap - Optional custom token mapping (overrides defaults)\r\n * @returns CSS color value\r\n */\r\nexport function resolveColor(\r\n input: string,\r\n customMap: Record<string, string> = {}\r\n): string {\r\n const map = { ...DEFAULT_COLOR_TOKENS, ...customMap };\r\n return map[input] || input || map.primary;\r\n}\r\n\r\n/** True when the token is the neutral glass surface (`default`), not a brand accent. */\r\nexport function isDefaultColorToken(input: string): boolean {\r\n return input === 'default';\r\n}\r\n\r\n/** Foreground ink (labels, borders) — never use glass-solid as text. */\r\nexport function resolveInkColorForToken(input: string): string {\r\n return isDefaultColorToken(input)\r\n ? 'var(--sky-text-primary)'\r\n : resolveColor(input);\r\n}\r\n\r\n/** Accent for hover/focus on neutral surfaces. */\r\nexport function resolveAccentColorForToken(input: string): string {\r\n return isDefaultColorToken(input)\r\n ? 'var(--sky-active-primary)'\r\n : resolveColor(input);\r\n}\r\n\r\n/** Maps component color tokens to theme semantic keys (`active`, `success`, …). */\r\nconst SEMANTIC_SURFACE_KEYS: Record<string, string> = {\r\n primary: \"active\",\r\n active: \"active\",\r\n success: \"success\",\r\n danger: \"danger\",\r\n warning: \"warning\",\r\n info: \"info\",\r\n secondary: \"info\",\r\n};\r\n\r\n/**\r\n * Resolves a color token to a theme semantic surface key, if one exists.\r\n */\r\nexport function resolveSemanticSurfaceKey(colorToken: string): string | null {\r\n return SEMANTIC_SURFACE_KEYS[colorToken] ?? null;\r\n}\r\n\r\n/** Soft semantic surface tokens for alerts, badges, and subtle status blocks. */\r\nexport function semanticSoftSurfaceTokens(\r\n semanticKey: string,\r\n options: { bordered?: boolean } = {},\r\n): { bg: string; color: string; border: string } {\r\n return {\r\n bg: `var(--sky-${semanticKey}-quinary)`,\r\n color: `var(--sky-${semanticKey}-primary-dark)`,\r\n border: options.bordered\r\n ? `1px solid var(--sky-${semanticKey}-g1)`\r\n : \"none\",\r\n };\r\n}\r\n\r\n/**\r\n * Theme glass border shorthand (`1px solid …` from `--sky-border-primary`).\r\n * Use as a full `border` value — do not wrap in `Npx solid var(--sky-border-primary)`.\r\n */\r\nexport function skyBorderPrimaryShorthand(): string {\r\n return 'var(--sky-border-primary)';\r\n}\r\n\r\n/**\r\n * Separator stroke for custom widths (`--sky-border-light` is a color, not shorthand).\r\n */\r\nexport function skyBorderWidthSolid(widthPx: number): string {\r\n return `${widthPx}px solid var(--sky-border-light)`;\r\n}\r\n\r\n/** Partial variant overrides when `color=\"default\"` (surface token, not ink). */\r\nexport type DefaultColorVariantPatch = Partial<{\r\n bg: string;\r\n color: string;\r\n border: string;\r\n shadow: string;\r\n hoverBg: string;\r\n hoverColor: string;\r\n hoverShadow: string;\r\n hoverBorder: string;\r\n arrow: string;\r\n}>;\r\n\r\nconst DEFAULT_COLOR_VARIANT_PATCHES: Record<string, DefaultColorVariantPatch> = {\r\n shadow: {\r\n bg: 'var(--sky-glass-solid)',\r\n hoverBg: 'var(--sky-glass-solid)',\r\n color: 'var(--sky-text-primary)',\r\n hoverColor: 'var(--sky-active-primary)',\r\n shadow: 'none',\r\n hoverShadow: 'var(--sky-box-shadow-hover)',\r\n arrow: 'var(--sky-glass-solid)',\r\n },\r\n solid: {\r\n color: 'var(--sky-text-primary)',\r\n hoverColor: 'var(--sky-text-primary)',\r\n hoverShadow: 'var(--sky-box-shadow-hover)',\r\n },\r\n faded: {\r\n color: 'var(--sky-text-primary)',\r\n hoverColor: 'var(--sky-text-primary)',\r\n arrow: 'var(--sky-hover-tertiary)',\r\n },\r\n bordered: {\r\n color: 'var(--sky-text-primary)',\r\n border: skyBorderWidthSolid(2),\r\n hoverColor: 'var(--sky-text-primary)',\r\n hoverBorder: '2px solid var(--sky-text-tertiary)',\r\n arrow: 'var(--sky-border-light)',\r\n },\r\n transparent: {\r\n color: 'var(--sky-text-primary)',\r\n hoverBg: 'var(--sky-hover-tertiary)',\r\n hoverColor: 'var(--sky-text-primary)',\r\n },\r\n flat: {\r\n bg: 'var(--sky-hover-tertiary)',\r\n color: 'var(--sky-text-primary)',\r\n hoverBg: 'var(--sky-hover-secondary)',\r\n hoverColor: 'var(--sky-active-primary)',\r\n arrow: 'var(--sky-hover-tertiary)',\r\n },\r\n ghost: {\r\n color: 'var(--sky-text-primary)',\r\n border: skyBorderWidthSolid(2),\r\n hoverBg: 'var(--sky-hover-secondary)',\r\n hoverColor: 'var(--sky-text-primary)',\r\n },\r\n link: {\r\n color: 'var(--sky-text-primary)',\r\n hoverColor: 'var(--sky-active-primary)',\r\n },\r\n light: {\r\n color: 'var(--sky-text-primary)',\r\n },\r\n};\r\n\r\n/**\r\n * Applies variant style overrides for `color=\"default\"` so glass tokens are not\r\n * used as text/border/hover ink on translucent surfaces.\r\n */\r\nexport function tuneSurfaceVariantForDefaultColor<T extends DefaultColorVariantPatch>(\r\n colorToken: string,\r\n variant: string,\r\n styles: T,\r\n): T {\r\n if (!isDefaultColorToken(colorToken)) return styles;\r\n const patch = DEFAULT_COLOR_VARIANT_PATCHES[variant];\r\n if (!patch) return styles;\r\n return { ...styles, ...patch };\r\n}\r\n\r\n/**\r\n * Creates a hover shade using color-mix\r\n * @param color - Base CSS color\r\n * @param amount - Percentage of black to mix (0-100)\r\n * @returns CSS color-mix() value\r\n */\r\nexport function hoverShade(color: string, amount: number = 20): string {\r\n return `color-mix(in srgb, ${color} ${100 - amount}%, var(--sky-text-dark))`;\r\n}\r\n/**\r\n * Creates a hover shade using color-mix\r\n * @param color - Base CSS color\r\n * @param amount - Percentage of black to mix (0-100)\r\n * @returns CSS color-mix() value\r\n */\r\nexport function darkShade(color: string, amount: number = 20): string {\r\n return `color-mix(in srgb, ${color} ${100 - amount}%, var(--sky-text-black))`;\r\n}\r\n/**\r\n * Creates a hover shade using color-mix\r\n * @param color - Base CSS color\r\n * @param amount - Percentage of black to mix (0-100)\r\n * @returns CSS color-mix() value\r\n */\r\nexport function lightShade(color: string, amount: number = 20): string {\r\n return `color-mix(in srgb, ${color} ${100 - amount}%, var(--sky-text-white))`;\r\n}\r\n\r\n\r\n/**\r\n * Creates a faded/transparent version of a color\r\n * @param color - Base CSS color\r\n * @param amount - Percentage of transparency (0-100)\r\n * @returns CSS color-mix() value with transparency\r\n */\r\nexport function fadeMix(color: string, amount: number = 15): string {\r\n return `color-mix(in srgb, ${color} ${amount}%, transparent)`;\r\n}\r\n\r\n/**\r\n * Resolves gradient stop tokens to CSS colors\r\n * @param stop - Gradient stop token (e.g., 'primary 30%')\r\n * @returns CSS gradient stop value\r\n */\r\nexport function resolveGradientStop(stop: string): string {\r\n const match = stop.match(/^([^\\s]+)(\\s+.+)?$/);\r\n const head = match?.[1] ?? stop;\r\n const tail = match?.[2] ?? '';\r\n\r\n const resolved = DEFAULT_COLOR_TOKENS[head] || head;\r\n return `${resolved}${tail}`;\r\n}\r\n\r\n/**\r\n * Parses a gradient specification string\r\n */\r\nexport interface GradientSpec {\r\n kind: 'linear' | 'radial' | 'conic';\r\n args: string;\r\n stops: string[];\r\n}\r\n\r\n/**\r\n * Parses gradient specification string\r\n * Format: \"kind@args: stop1, stop2, stop3\"\r\n * Example: \"linear@90deg: primary, secondary 50%, danger\"\r\n * Example: \"radial@circle: primary, transparent\"\r\n */\r\nexport function parseGradientSpec(input: string): GradientSpec {\r\n const raw = (input || '').trim();\r\n const idx = raw.indexOf(':');\r\n let prefix = '';\r\n let stopsStr = raw;\r\n\r\n if (idx !== -1) {\r\n prefix = raw.slice(0, idx).trim();\r\n stopsStr = raw.slice(idx + 1).trim();\r\n }\r\n\r\n let kind: 'linear' | 'radial' | 'conic' = 'linear';\r\n let args = '90deg';\r\n\r\n if (prefix) {\r\n const [k, a] = prefix.split('@').map(s => s.trim());\r\n const kLower = (k || '').toLowerCase();\r\n if (kLower === 'linear' || kLower === 'radial' || kLower === 'conic') {\r\n kind = kLower;\r\n args = a || (kind === 'linear'\r\n ? '90deg'\r\n : kind === 'radial'\r\n ? 'circle'\r\n : 'from 0deg at 50% 50%');\r\n } else {\r\n stopsStr = raw;\r\n }\r\n }\r\n\r\n const stops = stopsStr\r\n .split(',')\r\n .map(s => s.trim())\r\n .filter(Boolean);\r\n\r\n return { kind, args, stops };\r\n}\r\n\r\n/**\r\n * Creates a CSS gradient from a specification string\r\n * @param specStr - Gradient specification string\r\n * @param fallbackColor - Fallback color if no stops provided\r\n * @returns CSS gradient value\r\n */\r\nexport function createGradient(\r\n specStr: string,\r\n fallbackColor: string = 'var(--sky-active-primary)'\r\n): string {\r\n const spec = parseGradientSpec(specStr);\r\n const stops = (\r\n spec.stops.length\r\n ? spec.stops\r\n : [fallbackColor, fallbackColor]\r\n ).map(st => resolveGradientStop(st));\r\n\r\n const { kind, args } = spec;\r\n\r\n switch (kind) {\r\n case 'linear':\r\n return `linear-gradient(${args}, ${stops.join(', ')})`;\r\n case 'radial':\r\n return `radial-gradient(${args}, ${stops.join(', ')})`;\r\n case 'conic':\r\n return `conic-gradient(${args}, ${stops.join(', ')})`;\r\n default:\r\n return `linear-gradient(90deg, ${stops.join(', ')})`;\r\n }\r\n}\r\n\r\n/**\r\n * Color resolver with configuration support\r\n */\r\nexport class ColorResolver {\r\n private config: Required<ColorResolverConfig>;\r\n\r\n constructor(config: ColorResolverConfig = {}) {\r\n this.config = {\r\n prefix: config.prefix || 'sky',\r\n useColorMix: config.useColorMix ?? true,\r\n };\r\n }\r\n\r\n /**\r\n * Resolves a color with prefix-aware variable names\r\n */\r\n resolve(input: string): string {\r\n if (input.startsWith('#')) return input;\r\n if (input.startsWith('rgb') || input.startsWith('hsl')) return input;\r\n if (input.startsWith('var(')) return input;\r\n\r\n const customVar = `var(--${this.config.prefix}-${input})`;\r\n const defaultResolved = DEFAULT_COLOR_TOKENS[input];\r\n\r\n return defaultResolved || customVar || DEFAULT_COLOR_TOKENS.primary;\r\n }\r\n\r\n /**\r\n * Gets text color for a background color\r\n */\r\n getTextColor(backgroundColor: string): string {\r\n if (backgroundColor === \"default\") {\r\n return \"var(--sky-text-primary)\";\r\n }\r\n // Solid fills: no-@supports fallback; prefer contrast-color() in CSS.\r\n return \"var(--sky-on-color-fallback-light, var(--sky-text-white))\";\r\n }\r\n\r\n /**\r\n * Creates a hover state color\r\n */\r\n getHoverColor(baseColor: string, darkenAmount: number = 20): string {\r\n if (!this.config.useColorMix) {\r\n // Fallback for browsers without color-mix support\r\n return baseColor;\r\n }\r\n\r\n return hoverShade(baseColor, darkenAmount);\r\n }\r\n}\r\n\r\n/**\r\n * Singleton instance for convenience\r\n */\r\nexport const colorResolver = new ColorResolver();\r\n\r\n"],"names":["DEFAULT_COLOR_TOKENS","primary","active","secondary","success","danger","warning","info","light","dark","muted","default","resolveColor","input","customMap","map","isDefaultColorToken","resolveInkColorForToken","resolveAccentColorForToken","SEMANTIC_SURFACE_KEYS","resolveSemanticSurfaceKey","colorToken","semanticSoftSurfaceTokens","semanticKey","options","bg","color","border","bordered","skyBorderPrimaryShorthand","skyBorderWidthSolid","widthPx","DEFAULT_COLOR_VARIANT_PATCHES","shadow","hoverBg","hoverColor","hoverShadow","arrow","solid","faded","hoverBorder","transparent","flat","ghost","link","tuneSurfaceVariantForDefaultColor","variant","styles","patch","hoverShade","amount","darkShade","lightShade","fadeMix","resolveGradientStop","stop","match","head","parseGradientSpec","raw","trim","idx","indexOf","prefix","stopsStr","slice","kind","args","k","a","split","s","kLower","toLowerCase","stops","filter","Boolean","createGradient","specStr","fallbackColor","spec","length","st","join","ColorResolver","constructor","config","this","useColorMix","resolve","startsWith","customVar","getTextColor","backgroundColor","getHoverColor","baseColor","darkenAmount","colorResolver"],"mappings":"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"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Component prop presets — global defaults + named bundles for sky-* CEs.
|
|
3
|
+
*
|
|
4
|
+
* Precedence (highest wins):
|
|
5
|
+
* explicit user prop (attribute or marked/diverged property) → named `preset`
|
|
6
|
+
* → provider `defaults` → built-in class default
|
|
7
|
+
*
|
|
8
|
+
* A named preset overlays `defaults` unless it sets `$inheritDefaults: false`,
|
|
9
|
+
* in which case it is used standalone (keys it omits fall to the built-in).
|
|
10
|
+
*
|
|
11
|
+
* User-owned detection:
|
|
12
|
+
* - attributes present before Lit's first reflect (and any attrs added later)
|
|
13
|
+
* - props marked via `markUserSetProp`
|
|
14
|
+
* - props the consumer changed after presets applied (divergence)
|
|
15
|
+
*
|
|
16
|
+
* @see sky-config-provider
|
|
17
|
+
*/
|
|
18
|
+
/** Prop bag applied to a single component instance. */
|
|
19
|
+
export type ComponentPropBag = Record<string, unknown> & {
|
|
20
|
+
/**
|
|
21
|
+
* Named presets only: set `false` to ignore `defaults[component]` and use
|
|
22
|
+
* this bag standalone. Omitted / `true` keeps the default layering.
|
|
23
|
+
*/
|
|
24
|
+
$inheritDefaults?: boolean;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Config keys are custom element tag names (`sky-button`).
|
|
28
|
+
* Short aliases without the `sky-` prefix (`button`) are also accepted.
|
|
29
|
+
*/
|
|
30
|
+
export type ComponentPresetKey = string;
|
|
31
|
+
export type ComponentPresetsConfig = {
|
|
32
|
+
/** Applied when the instance does not set the prop (no matching attribute). */
|
|
33
|
+
defaults?: Partial<Record<ComponentPresetKey, ComponentPropBag>>;
|
|
34
|
+
/** Named bundles selected via `preset="name"` on the instance. */
|
|
35
|
+
presets?: Partial<Record<ComponentPresetKey, Record<string, ComponentPropBag>>>;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Lookup aliases for a component key: tag name and short name.
|
|
39
|
+
* `sky-button` ↔ `button`, `sky-button-group` ↔ `button-group`.
|
|
40
|
+
*/
|
|
41
|
+
export declare function presetKeyAliases(key: string): string[];
|
|
42
|
+
/** First matching bag under `defaults` / `presets` for any alias of `key`. */
|
|
43
|
+
export declare function lookupPresetSection<T>(section: Partial<Record<string, T>> | null | undefined, key: string): T | undefined;
|
|
44
|
+
/**
|
|
45
|
+
* Canonical tag form for storage/docs: `button` → `sky-button`.
|
|
46
|
+
* Already-tagged names are unchanged.
|
|
47
|
+
*/
|
|
48
|
+
export declare function toPresetTagKey(key: string): string;
|
|
49
|
+
/** Lit context provided by `<sky-config-provider>`. */
|
|
50
|
+
export declare const configContext: {
|
|
51
|
+
__context__: ComponentPresetsConfig | null;
|
|
52
|
+
};
|
|
53
|
+
/** camelCase / PascalCase → kebab-case attribute name. */
|
|
54
|
+
export declare function camelToKebab(name: string): string;
|
|
55
|
+
/**
|
|
56
|
+
* Snapshot host attributes once (call from controller `hostConnected`, before first update).
|
|
57
|
+
* Declarative HTML / early `setAttribute` calls are treated as user-owned thereafter.
|
|
58
|
+
*/
|
|
59
|
+
export declare function captureInitialUserAttributes(host: HTMLElement): void;
|
|
60
|
+
/**
|
|
61
|
+
* Merge any attributes that appeared after connect (late framework bindings)
|
|
62
|
+
* into the user-owned attribute snapshot.
|
|
63
|
+
*/
|
|
64
|
+
export declare function refreshUserAttributes(host: HTMLElement): void;
|
|
65
|
+
/**
|
|
66
|
+
* Mark a prop as consumer-owned so presets will not overwrite it.
|
|
67
|
+
* Use for property-only bindings (no attribute) when needed.
|
|
68
|
+
*/
|
|
69
|
+
export declare function markUserSetProp(host: HTMLElement, prop: string): void;
|
|
70
|
+
/**
|
|
71
|
+
* True when the host had an attribute for this prop before/at apply time,
|
|
72
|
+
* or the prop was marked user-owned (explicit mark or post-apply divergence).
|
|
73
|
+
*/
|
|
74
|
+
export declare function isUserSetProp(host: HTMLElement, prop: string): boolean;
|
|
75
|
+
/**
|
|
76
|
+
* Deep-merge parent + child preset configs.
|
|
77
|
+
* Inner provider wins per component key, then per prop / named preset.
|
|
78
|
+
*/
|
|
79
|
+
export declare function mergePresetsConfig(parent: ComponentPresetsConfig | null | undefined, child: ComponentPresetsConfig | null | undefined): ComponentPresetsConfig;
|
|
80
|
+
export type ResolveComponentPropsOptions<T extends Record<string, unknown>> = {
|
|
81
|
+
host: HTMLElement;
|
|
82
|
+
componentKey: ComponentPresetKey;
|
|
83
|
+
/** Value of the instance `preset` attribute/prop. */
|
|
84
|
+
presetName?: string | null;
|
|
85
|
+
config?: ComponentPresetsConfig | null;
|
|
86
|
+
/** Current instance values (class built-ins already applied). */
|
|
87
|
+
values: T;
|
|
88
|
+
/**
|
|
89
|
+
* Keys eligible for preset / default substitution.
|
|
90
|
+
* Omit to apply every key present in the preset layer.
|
|
91
|
+
*/
|
|
92
|
+
keys?: Array<keyof T & string>;
|
|
93
|
+
};
|
|
94
|
+
/**
|
|
95
|
+
* Walk ancestors for `<sky-config-provider>` and deep-merge outer → inner.
|
|
96
|
+
* Used when Lit context has not delivered a value yet (or as a reliable fallback).
|
|
97
|
+
*/
|
|
98
|
+
export declare function findNearestPresetsConfig(host: HTMLElement): ComponentPresetsConfig | null;
|
|
99
|
+
/**
|
|
100
|
+
* Resolve the active prop bag for a component: `defaults[key]` ← `presets[key][name]`.
|
|
101
|
+
* Any prop key present in that bag can be applied to the instance.
|
|
102
|
+
*
|
|
103
|
+
* A named preset with `$inheritDefaults: false` is used standalone, so keys it
|
|
104
|
+
* omits fall through to the component built-in instead of `defaults`.
|
|
105
|
+
*/
|
|
106
|
+
export declare function getPresetLayer(config: ComponentPresetsConfig | null | undefined, componentKey: ComponentPresetKey, presetName?: string | null): ComponentPropBag;
|
|
107
|
+
export type ApplyPresetLayerOptions = {
|
|
108
|
+
/** Extra keys never written from presets. */
|
|
109
|
+
skipKeys?: string[];
|
|
110
|
+
};
|
|
111
|
+
/**
|
|
112
|
+
* Write every key from the preset layer onto the host (any component prop).
|
|
113
|
+
* Skips user-owned attributes / props. Remembers prior values so removing a
|
|
114
|
+
* key from the provider config restores the built-in / prior value.
|
|
115
|
+
*
|
|
116
|
+
* Before writing, detects divergence: if the host value no longer matches the
|
|
117
|
+
* last preset-applied value, that prop is marked user-owned (property-only
|
|
118
|
+
* overrides after first apply).
|
|
119
|
+
*
|
|
120
|
+
* @returns true if any host property changed
|
|
121
|
+
*/
|
|
122
|
+
export declare function applyPresetLayer(host: HTMLElement, layer: ComponentPropBag, options?: ApplyPresetLayerOptions): boolean;
|
|
123
|
+
/**
|
|
124
|
+
* Clear preset-applied props and restore saved built-ins (e.g. when paused in a group).
|
|
125
|
+
*/
|
|
126
|
+
export declare function clearAppliedPresetLayer(host: HTMLElement): boolean;
|
|
127
|
+
/**
|
|
128
|
+
* Resolve effective props for styling / behavior without mutating the host.
|
|
129
|
+
* When `keys` is omitted, every key in the preset layer is considered.
|
|
130
|
+
* Skips keys the user set via attributes.
|
|
131
|
+
*/
|
|
132
|
+
export declare function resolveComponentProps<T extends Record<string, unknown>>(options: ResolveComponentPropsOptions<T>): T;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{createContext as t}from"@lit/context";const e=new Set(["$inheritDefaults"]);function n(t){const e=String(t||"").trim();if(!e)return[];const n=new Set([e]);return e.startsWith("sky-")?n.add(e.slice(4)):n.add(`sky-${e}`),[...n]}function o(t,e){if(t)for(const o of n(e))if(Object.prototype.hasOwnProperty.call(t,o))return t[o]}function s(t){const e=String(t||"").trim();return e?e.startsWith("sky-")?e:`sky-${e}`:e}const r=t("sky/component-presets");function c(t){return t.replace(/([a-z0-9])([A-Z])/g,"$1-$2").replace(/_/g,"-").toLowerCase()}const f=new WeakMap,i=new WeakMap,u=new WeakMap;function a(t){f.has(t)||f.set(t,new Set(t.getAttributeNames()))}function l(t){const e=f.get(t)??new Set;for(const n of t.getAttributeNames())e.add(n);f.set(t,e)}function p(t,e){const n=i.get(t)??new Set;n.add(e),i.set(t,n)}function g(t,e){if(i.get(t)?.has(e))return!0;const n=c(e),o=f.get(t);return o?o.has(n)||n!==e&&o.has(e):t.hasAttribute(n)||n!==e&&t.hasAttribute(e)}function d(t,e){const n=t??{},o=e??{},r={};for(const t of[n.defaults,o.defaults])for(const[e,n]of Object.entries(t??{})){const t=s(e);r[t]={...r[t]??{},...n??{}}}const c={};for(const t of[n.presets,o.presets])for(const[e,n]of Object.entries(t??{})){const t=s(e),o={...c[t]??{}};for(const[t,e]of Object.entries(n??{}))o[t]={...o[t]??{},...e??{}};c[t]=o}return{defaults:r,presets:c}}function h(t){const e=[];let n=t.parentElement;for(;n;){if("sky-config-provider"===n.localName){const t=n;if(t.mergedConfig)return t.mergedConfig;t.presets&&e.push(t.presets)}n=n.parentElement}return e.length?e.reduceRight((t,e)=>d(t,e),{}):null}function w(t,o,s){const r=function(t,e){if(!t)return{};let o={};for(const s of n(e)){const e=t[s];e&&(o={...o,...e})}return o}(t?.defaults,o),c=function(t,e){if(!t)return{};const o={};for(const s of n(e)){const e=t[s];if(e)for(const[t,n]of Object.entries(e))o[t]={...o[t]??{},...n??{}}}return o}(t?.presets,o),f=s&&c[s]?c[s]:null,i=f&&!1===f.$inheritDefaults?{...f}:{...r,...f??{}};for(const t of e)delete i[t];return i}const y=new WeakMap,k=new Set(["preset",...e]);function m(t,e,n){l(t),function(t){const e=u.get(t);if(!e?.size)return;const n=t;for(const[o,s]of e)g(t,o)||n[o]!==s&&p(t,o)}(t);const o=new Set([...k,...n?.skipKeys??[]]),s=y.get(t)??new Map,r=u.get(t)??new Map;let c=!1;const f=t;for(const n of[...s.keys()])if(!Object.prototype.hasOwnProperty.call(e,n)||void 0===e[n]){if(!g(t,n)&&s.has(n)){const t=s.get(n);f[n]!==t&&(f[n]=t,c=!0)}s.delete(n),r.delete(n)}for(const[n,i]of Object.entries(e))o.has(n)||void 0===i||(g(t,n)?r.delete(n):(s.has(n)||s.set(n,f[n]),f[n]!==i&&(f[n]=i,c=!0),r.set(n,i)));return y.set(t,s),u.set(t,r),c}function b(t){const e=y.get(t);if(!e?.size)return!1;const n=t;let o=!1;for(const[s,r]of e)g(t,s)||n[s]!==r&&(n[s]=r,o=!0);return e.clear(),u.get(t)?.clear(),o}function O(t){const{host:e,componentKey:n,presetName:o,config:s,values:r,keys:c}=t,f=w(s,n,o),i=c??Object.keys(f),u={...r};for(const t of i){const n=t;g(e,n)||Object.prototype.hasOwnProperty.call(f,n)&&void 0!==f[n]&&(u[n]=f[n])}return u}export{m as applyPresetLayer,c as camelToKebab,a as captureInitialUserAttributes,b as clearAppliedPresetLayer,r as configContext,h as findNearestPresetsConfig,w as getPresetLayer,g as isUserSetProp,o as lookupPresetSection,p as markUserSetProp,d as mergePresetsConfig,n as presetKeyAliases,l as refreshUserAttributes,O as resolveComponentProps,s as toPresetTagKey};
|
|
2
|
+
//# sourceMappingURL=component-presets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"component-presets.js","sources":["../../../src/helper/utils/component-presets.ts"],"sourcesContent":["/**\n * Component prop presets — global defaults + named bundles for sky-* CEs.\n *\n * Precedence (highest wins):\n * explicit user prop (attribute or marked/diverged property) → named `preset`\n * → provider `defaults` → built-in class default\n *\n * A named preset overlays `defaults` unless it sets `$inheritDefaults: false`,\n * in which case it is used standalone (keys it omits fall to the built-in).\n *\n * User-owned detection:\n * - attributes present before Lit's first reflect (and any attrs added later)\n * - props marked via `markUserSetProp`\n * - props the consumer changed after presets applied (divergence)\n *\n * @see sky-config-provider\n */\n\nimport { createContext } from \"@lit/context\";\n\n/** Prop bag applied to a single component instance. */\nexport type ComponentPropBag = Record<string, unknown> & {\n /**\n * Named presets only: set `false` to ignore `defaults[component]` and use\n * this bag standalone. Omitted / `true` keeps the default layering.\n */\n $inheritDefaults?: boolean;\n};\n\n/** Reserved bag keys that configure resolution instead of naming a prop. */\nconst RESERVED_BAG_KEYS = new Set([\"$inheritDefaults\"]);\n\n/**\n * Config keys are custom element tag names (`sky-button`).\n * Short aliases without the `sky-` prefix (`button`) are also accepted.\n */\nexport type ComponentPresetKey = string;\n\nexport type ComponentPresetsConfig = {\n /** Applied when the instance does not set the prop (no matching attribute). */\n defaults?: Partial<Record<ComponentPresetKey, ComponentPropBag>>;\n /** Named bundles selected via `preset=\"name\"` on the instance. */\n presets?: Partial<\n Record<ComponentPresetKey, Record<string, ComponentPropBag>>\n >;\n};\n\n/**\n * Lookup aliases for a component key: tag name and short name.\n * `sky-button` ↔ `button`, `sky-button-group` ↔ `button-group`.\n */\nexport function presetKeyAliases(key: string): string[] {\n const k = String(key || \"\").trim();\n if (!k) return [];\n const aliases = new Set<string>([k]);\n if (k.startsWith(\"sky-\")) aliases.add(k.slice(4));\n else aliases.add(`sky-${k}`);\n return [...aliases];\n}\n\n/** First matching bag under `defaults` / `presets` for any alias of `key`. */\nexport function lookupPresetSection<T>(\n section: Partial<Record<string, T>> | null | undefined,\n key: string,\n): T | undefined {\n if (!section) return undefined;\n for (const alias of presetKeyAliases(key)) {\n if (Object.prototype.hasOwnProperty.call(section, alias)) {\n return section[alias];\n }\n }\n return undefined;\n}\n\n/** Merge all alias bags (short + tag) under a section key. Later aliases win. */\nfunction mergeAliasBags(\n section: Partial<Record<string, ComponentPropBag>> | null | undefined,\n key: string,\n): ComponentPropBag {\n if (!section) return {};\n let out: ComponentPropBag = {};\n for (const alias of presetKeyAliases(key)) {\n const bag = section[alias];\n if (bag) out = { ...out, ...bag };\n }\n return out;\n}\n\nfunction mergeAliasNamedMaps(\n section:\n | Partial<Record<string, Record<string, ComponentPropBag>>>\n | null\n | undefined,\n key: string,\n): Record<string, ComponentPropBag> {\n if (!section) return {};\n const out: Record<string, ComponentPropBag> = {};\n for (const alias of presetKeyAliases(key)) {\n const named = section[alias];\n if (!named) continue;\n for (const [name, bag] of Object.entries(named)) {\n out[name] = { ...(out[name] ?? {}), ...(bag ?? {}) };\n }\n }\n return out;\n}\n\n/**\n * Canonical tag form for storage/docs: `button` → `sky-button`.\n * Already-tagged names are unchanged.\n */\nexport function toPresetTagKey(key: string): string {\n const k = String(key || \"\").trim();\n if (!k) return k;\n return k.startsWith(\"sky-\") ? k : `sky-${k}`;\n}\n\n/** Lit context provided by `<sky-config-provider>`. */\nexport const configContext = createContext<ComponentPresetsConfig | null>(\n \"sky/component-presets\",\n);\n\n/** camelCase / PascalCase → kebab-case attribute name. */\nexport function camelToKebab(name: string): string {\n return name\n .replace(/([a-z0-9])([A-Z])/g, \"$1-$2\")\n .replace(/_/g, \"-\")\n .toLowerCase();\n}\n\n/**\n * Attributes present before Lit's first reflect (captured in `PresetController`).\n * Needed so reflected class defaults (e.g. `variant=\"solid\"`) do not look user-owned.\n */\nconst initialUserAttrs = new WeakMap<HTMLElement, Set<string>>();\n\n/** Props explicitly marked user-owned (property-only writes / divergence). */\nconst userOwnedProps = new WeakMap<HTMLElement, Set<string>>();\n\n/** Last values written by `applyPresetLayer` (for divergence detection). */\nconst lastPresetApplied = new WeakMap<HTMLElement, Map<string, unknown>>();\n\n/**\n * Snapshot host attributes once (call from controller `hostConnected`, before first update).\n * Declarative HTML / early `setAttribute` calls are treated as user-owned thereafter.\n */\nexport function captureInitialUserAttributes(host: HTMLElement): void {\n if (initialUserAttrs.has(host)) return;\n initialUserAttrs.set(host, new Set(host.getAttributeNames()));\n}\n\n/**\n * Merge any attributes that appeared after connect (late framework bindings)\n * into the user-owned attribute snapshot.\n */\nexport function refreshUserAttributes(host: HTMLElement): void {\n const set = initialUserAttrs.get(host) ?? new Set<string>();\n for (const name of host.getAttributeNames()) set.add(name);\n initialUserAttrs.set(host, set);\n}\n\n/**\n * Mark a prop as consumer-owned so presets will not overwrite it.\n * Use for property-only bindings (no attribute) when needed.\n */\nexport function markUserSetProp(host: HTMLElement, prop: string): void {\n const set = userOwnedProps.get(host) ?? new Set<string>();\n set.add(prop);\n userOwnedProps.set(host, set);\n}\n\n/**\n * True when the host had an attribute for this prop before/at apply time,\n * or the prop was marked user-owned (explicit mark or post-apply divergence).\n */\nexport function isUserSetProp(host: HTMLElement, prop: string): boolean {\n if (userOwnedProps.get(host)?.has(prop)) return true;\n const kebab = camelToKebab(prop);\n const initial = initialUserAttrs.get(host);\n if (initial) {\n return initial.has(kebab) || (kebab !== prop && initial.has(prop));\n }\n return host.hasAttribute(kebab) || (kebab !== prop && host.hasAttribute(prop));\n}\n\n/**\n * If the consumer changed a prop after we applied a preset value, mark it\n * user-owned so later re-applies leave it alone.\n */\nfunction detectDivergedUserProps(host: HTMLElement): void {\n const applied = lastPresetApplied.get(host);\n if (!applied?.size) return;\n const record = host as HTMLElement & Record<string, unknown>;\n for (const [key, appliedValue] of applied) {\n if (isUserSetProp(host, key)) continue;\n if (record[key] !== appliedValue) {\n markUserSetProp(host, key);\n }\n }\n}\n\n/**\n * Deep-merge parent + child preset configs.\n * Inner provider wins per component key, then per prop / named preset.\n */\nexport function mergePresetsConfig(\n parent: ComponentPresetsConfig | null | undefined,\n child: ComponentPresetsConfig | null | undefined,\n): ComponentPresetsConfig {\n const p = parent ?? {};\n const c = child ?? {};\n\n const defaults: NonNullable<ComponentPresetsConfig[\"defaults\"]> = {};\n for (const source of [p.defaults, c.defaults]) {\n for (const [key, bag] of Object.entries(source ?? {})) {\n const tag = toPresetTagKey(key);\n defaults[tag] = { ...(defaults[tag] ?? {}), ...(bag ?? {}) };\n }\n }\n\n const presets: NonNullable<ComponentPresetsConfig[\"presets\"]> = {};\n for (const source of [p.presets, c.presets]) {\n for (const [comp, named] of Object.entries(source ?? {})) {\n const tag = toPresetTagKey(comp);\n const mergedNamed: Record<string, ComponentPropBag> = {\n ...(presets[tag] ?? {}),\n };\n for (const [name, bag] of Object.entries(named ?? {})) {\n mergedNamed[name] = { ...(mergedNamed[name] ?? {}), ...(bag ?? {}) };\n }\n presets[tag] = mergedNamed;\n }\n }\n\n return { defaults, presets };\n}\n\nexport type ResolveComponentPropsOptions<T extends Record<string, unknown>> = {\n host: HTMLElement;\n componentKey: ComponentPresetKey;\n /** Value of the instance `preset` attribute/prop. */\n presetName?: string | null;\n config?: ComponentPresetsConfig | null;\n /** Current instance values (class built-ins already applied). */\n values: T;\n /**\n * Keys eligible for preset / default substitution.\n * Omit to apply every key present in the preset layer.\n */\n keys?: Array<keyof T & string>;\n};\n\n/**\n * Walk ancestors for `<sky-config-provider>` and deep-merge outer → inner.\n * Used when Lit context has not delivered a value yet (or as a reliable fallback).\n */\nexport function findNearestPresetsConfig(\n host: HTMLElement,\n): ComponentPresetsConfig | null {\n const layers: ComponentPresetsConfig[] = [];\n let el: HTMLElement | null = host.parentElement;\n while (el) {\n if (el.localName === \"sky-config-provider\") {\n const provider = el as HTMLElement & {\n presets?: ComponentPresetsConfig;\n mergedConfig?: ComponentPresetsConfig;\n };\n // Prefer live `presets` so we do not depend on context publish timing.\n if (provider.mergedConfig) {\n // Nearest provider already merged its ancestors — use it and stop.\n return provider.mergedConfig;\n }\n if (provider.presets) layers.push(provider.presets);\n }\n el = el.parentElement;\n }\n if (!layers.length) return null;\n // layers collected inner→outer while walking up; merge outer first, inner last.\n return layers.reduceRight(\n (acc, layer) => mergePresetsConfig(acc, layer),\n {} as ComponentPresetsConfig,\n );\n}\n\n/**\n * Resolve the active prop bag for a component: `defaults[key]` ← `presets[key][name]`.\n * Any prop key present in that bag can be applied to the instance.\n *\n * A named preset with `$inheritDefaults: false` is used standalone, so keys it\n * omits fall through to the component built-in instead of `defaults`.\n */\nexport function getPresetLayer(\n config: ComponentPresetsConfig | null | undefined,\n componentKey: ComponentPresetKey,\n presetName?: string | null,\n): ComponentPropBag {\n const defaults = mergeAliasBags(config?.defaults, componentKey);\n const namedMap = mergeAliasNamedMaps(config?.presets, componentKey);\n const named =\n presetName && namedMap[presetName] ? namedMap[presetName]! : null;\n\n const merged =\n named && named.$inheritDefaults === false\n ? { ...named }\n : { ...defaults, ...(named ?? {}) };\n\n for (const key of RESERVED_BAG_KEYS) delete merged[key];\n return merged;\n}\n\n/** Per-host map of prop → value before presets overwrote it (for revert). */\nconst presetRestoreValues = new WeakMap<HTMLElement, Map<string, unknown>>();\n\nconst PRESET_SKIP_KEYS = new Set([\"preset\", ...RESERVED_BAG_KEYS]);\n\nexport type ApplyPresetLayerOptions = {\n /** Extra keys never written from presets. */\n skipKeys?: string[];\n};\n\n/**\n * Write every key from the preset layer onto the host (any component prop).\n * Skips user-owned attributes / props. Remembers prior values so removing a\n * key from the provider config restores the built-in / prior value.\n *\n * Before writing, detects divergence: if the host value no longer matches the\n * last preset-applied value, that prop is marked user-owned (property-only\n * overrides after first apply).\n *\n * @returns true if any host property changed\n */\nexport function applyPresetLayer(\n host: HTMLElement,\n layer: ComponentPropBag,\n options?: ApplyPresetLayerOptions,\n): boolean {\n refreshUserAttributes(host);\n detectDivergedUserProps(host);\n\n const skip = new Set([\n ...PRESET_SKIP_KEYS,\n ...(options?.skipKeys ?? []),\n ]);\n const restore = presetRestoreValues.get(host) ?? new Map<string, unknown>();\n const applied = lastPresetApplied.get(host) ?? new Map<string, unknown>();\n let changed = false;\n const record = host as HTMLElement & Record<string, unknown>;\n\n // Drop / revert keys no longer provided by the layer.\n for (const key of [...restore.keys()]) {\n if (\n Object.prototype.hasOwnProperty.call(layer, key) &&\n layer[key] !== undefined\n ) {\n continue;\n }\n if (!isUserSetProp(host, key) && restore.has(key)) {\n const prev = restore.get(key);\n if (record[key] !== prev) {\n record[key] = prev;\n changed = true;\n }\n }\n restore.delete(key);\n applied.delete(key);\n }\n\n // Apply all keys in the layer (full prop surface — not a whitelist).\n for (const [key, value] of Object.entries(layer)) {\n if (skip.has(key) || value === undefined) continue;\n if (isUserSetProp(host, key)) {\n applied.delete(key);\n continue;\n }\n if (!restore.has(key)) {\n restore.set(key, record[key]);\n }\n if (record[key] !== value) {\n record[key] = value;\n changed = true;\n }\n applied.set(key, value);\n }\n\n presetRestoreValues.set(host, restore);\n lastPresetApplied.set(host, applied);\n return changed;\n}\n\n/**\n * Clear preset-applied props and restore saved built-ins (e.g. when paused in a group).\n */\nexport function clearAppliedPresetLayer(host: HTMLElement): boolean {\n const restore = presetRestoreValues.get(host);\n if (!restore?.size) return false;\n const record = host as HTMLElement & Record<string, unknown>;\n let changed = false;\n for (const [key, prev] of restore) {\n if (isUserSetProp(host, key)) continue;\n if (record[key] !== prev) {\n record[key] = prev;\n changed = true;\n }\n }\n restore.clear();\n lastPresetApplied.get(host)?.clear();\n return changed;\n}\n\n/**\n * Resolve effective props for styling / behavior without mutating the host.\n * When `keys` is omitted, every key in the preset layer is considered.\n * Skips keys the user set via attributes.\n */\nexport function resolveComponentProps<T extends Record<string, unknown>>(\n options: ResolveComponentPropsOptions<T>,\n): T {\n const { host, componentKey, presetName, config, values, keys } = options;\n const layer = getPresetLayer(config, componentKey, presetName);\n const keysToApply =\n keys ?? (Object.keys(layer) as Array<keyof T & string>);\n\n const out = { ...values };\n for (const key of keysToApply) {\n const k = key as string;\n if (isUserSetProp(host, k)) continue;\n if (Object.prototype.hasOwnProperty.call(layer, k) && layer[k] !== undefined) {\n (out as Record<string, unknown>)[k] = layer[k];\n }\n }\n return out;\n}\n"],"names":["RESERVED_BAG_KEYS","Set","presetKeyAliases","key","k","String","trim","aliases","startsWith","add","slice","lookupPresetSection","section","alias","Object","prototype","hasOwnProperty","call","toPresetTagKey","configContext","createContext","camelToKebab","name","replace","toLowerCase","initialUserAttrs","WeakMap","userOwnedProps","lastPresetApplied","captureInitialUserAttributes","host","has","set","getAttributeNames","refreshUserAttributes","get","markUserSetProp","prop","isUserSetProp","kebab","initial","hasAttribute","mergePresetsConfig","parent","child","p","c","defaults","source","bag","entries","tag","presets","comp","named","mergedNamed","findNearestPresetsConfig","layers","el","parentElement","localName","provider","mergedConfig","push","length","reduceRight","acc","layer","getPresetLayer","config","componentKey","presetName","out","mergeAliasBags","namedMap","mergeAliasNamedMaps","merged","$inheritDefaults","presetRestoreValues","PRESET_SKIP_KEYS","applyPresetLayer","options","applied","size","record","appliedValue","detectDivergedUserProps","skip","skipKeys","restore","Map","changed","keys","prev","delete","value","clearAppliedPresetLayer","clear","resolveComponentProps","values","keysToApply"],"mappings":"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"}
|
|
@@ -59,9 +59,9 @@ export declare function contrastOverlay(color: string, options?: ContrastOnFillO
|
|
|
59
59
|
export declare function contrastThemeInk(color: string, options?: ContrastOnFillOptions): string;
|
|
60
60
|
/** Feature query used by every `@supports` enhance block. */
|
|
61
61
|
export declare const CONTRAST_COLOR_SUPPORT_QUERY: "(color: contrast-color(red))";
|
|
62
|
-
/** Fallback FG when the fill is assumed dark (most brand solids). */
|
|
62
|
+
/** Fallback FG when the fill is assumed dark (most brand solids / no-@supports). */
|
|
63
63
|
export declare const ON_COLOR_FALLBACK_LIGHT: "var(--sky-on-color-fallback-light, var(--sky-text-white))";
|
|
64
|
-
/** Fallback FG when
|
|
64
|
+
/** Fallback FG when a JS luminance check finds a light fill (canvas / SVG only). */
|
|
65
65
|
export declare const ON_COLOR_FALLBACK_DARK: "var(--sky-on-color-fallback-dark, var(--sky-text-black))";
|
|
66
66
|
/**
|
|
67
67
|
* Returns `contrast-color(var(--fill))` (or `contrast-color(<color>)`).
|