@tenphi/tasty 0.0.0-snapshot.c8bdaeb → 0.0.0-snapshot.c8c7b2a
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/README.md +309 -159
- package/dist/_virtual/_rolldown/runtime.js +1 -2
- package/dist/chunks/cacheKey.d.ts +1 -0
- package/dist/chunks/cacheKey.js +17 -10
- package/dist/chunks/cacheKey.js.map +1 -1
- package/dist/chunks/definitions.d.ts +1 -1
- package/dist/chunks/definitions.js +3 -5
- package/dist/chunks/definitions.js.map +1 -1
- package/dist/chunks/index.d.ts +1 -0
- package/dist/chunks/renderChunk.d.ts +1 -0
- package/dist/chunks/renderChunk.js +32 -34
- package/dist/chunks/renderChunk.js.map +1 -1
- package/dist/compute-styles.d.ts +31 -0
- package/dist/compute-styles.js +322 -0
- package/dist/compute-styles.js.map +1 -0
- package/dist/config.d.ts +157 -30
- package/dist/config.js +233 -45
- package/dist/config.js.map +1 -1
- package/dist/core/index.d.ts +12 -11
- package/dist/core/index.js +12 -11
- package/dist/counter-style/index.js +51 -0
- package/dist/counter-style/index.js.map +1 -0
- package/dist/debug.d.ts +26 -141
- package/dist/debug.js +359 -639
- package/dist/debug.js.map +1 -1
- package/dist/font-face/index.js +63 -0
- package/dist/font-face/index.js.map +1 -0
- package/dist/hooks/index.d.ts +7 -0
- package/dist/hooks/useCounterStyle.d.ts +36 -0
- package/dist/hooks/useCounterStyle.js +65 -0
- package/dist/hooks/useCounterStyle.js.map +1 -0
- package/dist/hooks/useFontFace.d.ts +45 -0
- package/dist/hooks/useFontFace.js +66 -0
- package/dist/hooks/useFontFace.js.map +1 -0
- package/dist/hooks/useGlobalStyles.d.ts +21 -2
- package/dist/hooks/useGlobalStyles.js +60 -28
- package/dist/hooks/useGlobalStyles.js.map +1 -1
- package/dist/hooks/useKeyframes.d.ts +4 -2
- package/dist/hooks/useKeyframes.js +44 -43
- package/dist/hooks/useKeyframes.js.map +1 -1
- package/dist/hooks/useProperty.d.ts +4 -2
- package/dist/hooks/useProperty.js +36 -31
- package/dist/hooks/useProperty.js.map +1 -1
- package/dist/hooks/useRawCSS.d.ts +13 -44
- package/dist/hooks/useRawCSS.js +91 -16
- package/dist/hooks/useRawCSS.js.map +1 -1
- package/dist/hooks/useStyles.d.ts +3 -3
- package/dist/hooks/useStyles.js +8 -146
- package/dist/hooks/useStyles.js.map +1 -1
- package/dist/index.d.ts +15 -12
- package/dist/index.js +15 -12
- package/dist/injector/index.d.ts +36 -11
- package/dist/injector/index.js +43 -12
- package/dist/injector/index.js.map +1 -1
- package/dist/injector/injector.d.ts +62 -3
- package/dist/injector/injector.js +293 -46
- package/dist/injector/injector.js.map +1 -1
- package/dist/injector/sheet-manager.d.ts +22 -17
- package/dist/injector/sheet-manager.js +64 -79
- package/dist/injector/sheet-manager.js.map +1 -1
- package/dist/injector/types.d.ts +121 -21
- package/dist/keyframes/index.js +1 -1
- package/dist/parser/classify.js +6 -6
- package/dist/parser/classify.js.map +1 -1
- package/dist/parser/const.js +30 -3
- package/dist/parser/const.js.map +1 -1
- package/dist/parser/lru.js +1 -1
- package/dist/parser/lru.js.map +1 -1
- package/dist/parser/parser.js +2 -3
- package/dist/parser/parser.js.map +1 -1
- package/dist/parser/tokenizer.js +1 -1
- package/dist/parser/tokenizer.js.map +1 -1
- package/dist/parser/types.js +1 -1
- package/dist/parser/types.js.map +1 -1
- package/dist/pipeline/conditions.js +1 -1
- package/dist/pipeline/conditions.js.map +1 -1
- package/dist/pipeline/exclusive.js +58 -4
- package/dist/pipeline/exclusive.js.map +1 -1
- package/dist/pipeline/index.d.ts +3 -1
- package/dist/pipeline/index.js +82 -34
- package/dist/pipeline/index.js.map +1 -1
- package/dist/pipeline/materialize.js +436 -123
- package/dist/pipeline/materialize.js.map +1 -1
- package/dist/pipeline/parseStateKey.d.ts +1 -1
- package/dist/pipeline/parseStateKey.js +21 -13
- package/dist/pipeline/parseStateKey.js.map +1 -1
- package/dist/pipeline/simplify.js +181 -7
- package/dist/pipeline/simplify.js.map +1 -1
- package/dist/pipeline/warnings.js +1 -1
- package/dist/plugins/index.d.ts +2 -0
- package/dist/plugins/okhsl-plugin.js +3 -277
- package/dist/plugins/okhsl-plugin.js.map +1 -1
- package/dist/plugins/types.d.ts +20 -2
- package/dist/properties/index.js +83 -19
- package/dist/properties/index.js.map +1 -1
- package/dist/properties/property-type-resolver.d.ts +24 -0
- package/dist/properties/property-type-resolver.js +90 -0
- package/dist/properties/property-type-resolver.js.map +1 -0
- package/dist/rsc-cache.js +79 -0
- package/dist/rsc-cache.js.map +1 -0
- package/dist/ssr/astro-client.d.ts +1 -0
- package/dist/ssr/astro-client.js +19 -0
- package/dist/ssr/astro-client.js.map +1 -0
- package/dist/ssr/astro-middleware.d.ts +15 -0
- package/dist/ssr/astro-middleware.js +19 -0
- package/dist/ssr/astro-middleware.js.map +1 -0
- package/dist/ssr/astro.d.ts +108 -0
- package/dist/ssr/astro.js +149 -0
- package/dist/ssr/astro.js.map +1 -0
- package/dist/ssr/async-storage.d.ts +17 -0
- package/dist/ssr/async-storage.js +44 -0
- package/dist/ssr/async-storage.js.map +1 -0
- package/dist/ssr/collect-auto-properties.js +58 -0
- package/dist/ssr/collect-auto-properties.js.map +1 -0
- package/dist/ssr/collector.d.ts +98 -0
- package/dist/ssr/collector.js +235 -0
- package/dist/ssr/collector.js.map +1 -0
- package/dist/ssr/context.js +16 -0
- package/dist/ssr/context.js.map +1 -0
- package/dist/ssr/format-global-rules.js +22 -0
- package/dist/ssr/format-global-rules.js.map +1 -0
- package/dist/ssr/format-keyframes.js +69 -0
- package/dist/ssr/format-keyframes.js.map +1 -0
- package/dist/ssr/format-property.js +49 -0
- package/dist/ssr/format-property.js.map +1 -0
- package/dist/ssr/format-rules.js +73 -0
- package/dist/ssr/format-rules.js.map +1 -0
- package/dist/ssr/hydrate.d.ts +29 -0
- package/dist/ssr/hydrate.js +45 -0
- package/dist/ssr/hydrate.js.map +1 -0
- package/dist/ssr/index.d.ts +4 -0
- package/dist/ssr/index.js +10 -0
- package/dist/ssr/index.js.map +1 -0
- package/dist/ssr/next.d.ts +46 -0
- package/dist/ssr/next.js +75 -0
- package/dist/ssr/next.js.map +1 -0
- package/dist/ssr/ssr-collector-ref.js +29 -0
- package/dist/ssr/ssr-collector-ref.js.map +1 -0
- package/dist/states/index.js +13 -259
- package/dist/states/index.js.map +1 -1
- package/dist/static/index.js +1 -2
- package/dist/static/inject.d.ts +5 -0
- package/dist/static/inject.js +17 -0
- package/dist/static/inject.js.map +1 -0
- package/dist/static/tastyStatic.js +1 -2
- package/dist/static/tastyStatic.js.map +1 -1
- package/dist/static/types.js +1 -1
- package/dist/styles/border.d.ts +1 -1
- package/dist/styles/border.js +30 -24
- package/dist/styles/border.js.map +1 -1
- package/dist/styles/color.d.ts +1 -1
- package/dist/styles/color.js +11 -8
- package/dist/styles/color.js.map +1 -1
- package/dist/styles/const.js +17 -0
- package/dist/styles/const.js.map +1 -0
- package/dist/styles/createStyle.js +28 -26
- package/dist/styles/createStyle.js.map +1 -1
- package/dist/styles/dimension.js +15 -3
- package/dist/styles/dimension.js.map +1 -1
- package/dist/styles/directional.js +133 -0
- package/dist/styles/directional.js.map +1 -0
- package/dist/styles/display.d.ts +3 -10
- package/dist/styles/display.js +45 -39
- package/dist/styles/display.js.map +1 -1
- package/dist/styles/fade.d.ts +1 -1
- package/dist/styles/fade.js +9 -5
- package/dist/styles/fade.js.map +1 -1
- package/dist/styles/fill.d.ts +2 -2
- package/dist/styles/fill.js +9 -9
- package/dist/styles/fill.js.map +1 -1
- package/dist/styles/flow.js +1 -1
- package/dist/styles/gap.d.ts +1 -1
- package/dist/styles/gap.js +4 -3
- package/dist/styles/gap.js.map +1 -1
- package/dist/styles/height.d.ts +1 -1
- package/dist/styles/height.js +1 -2
- package/dist/styles/height.js.map +1 -1
- package/dist/styles/index.d.ts +0 -1
- package/dist/styles/index.js +3 -4
- package/dist/styles/index.js.map +1 -1
- package/dist/styles/inset.d.ts +1 -29
- package/dist/styles/inset.js +19 -135
- package/dist/styles/inset.js.map +1 -1
- package/dist/styles/list.d.ts +5 -5
- package/dist/styles/list.js +4 -2
- package/dist/styles/list.js.map +1 -1
- package/dist/styles/margin.d.ts +1 -1
- package/dist/styles/margin.js +17 -89
- package/dist/styles/margin.js.map +1 -1
- package/dist/styles/outline.d.ts +1 -1
- package/dist/styles/outline.js +6 -16
- package/dist/styles/outline.js.map +1 -1
- package/dist/styles/padding.d.ts +1 -1
- package/dist/styles/padding.js +17 -89
- package/dist/styles/padding.js.map +1 -1
- package/dist/styles/placement.d.ts +37 -0
- package/dist/styles/placement.js +74 -0
- package/dist/styles/placement.js.map +1 -0
- package/dist/styles/predefined.d.ts +4 -6
- package/dist/styles/predefined.js +9 -13
- package/dist/styles/predefined.js.map +1 -1
- package/dist/styles/preset.d.ts +6 -1
- package/dist/styles/preset.js +54 -53
- package/dist/styles/preset.js.map +1 -1
- package/dist/styles/radius.d.ts +1 -3
- package/dist/styles/radius.js +38 -6
- package/dist/styles/radius.js.map +1 -1
- package/dist/styles/scrollMargin.d.ts +24 -0
- package/dist/styles/scrollMargin.js +32 -0
- package/dist/styles/scrollMargin.js.map +1 -0
- package/dist/styles/scrollbar.d.ts +9 -5
- package/dist/styles/scrollbar.js +31 -92
- package/dist/styles/scrollbar.js.map +1 -1
- package/dist/styles/shadow.d.ts +1 -1
- package/dist/styles/shadow.js +4 -3
- package/dist/styles/shadow.js.map +1 -1
- package/dist/styles/shared.js +17 -0
- package/dist/styles/shared.js.map +1 -0
- package/dist/styles/transition.d.ts +1 -1
- package/dist/styles/transition.js +6 -5
- package/dist/styles/transition.js.map +1 -1
- package/dist/styles/types.d.ts +94 -28
- package/dist/styles/width.d.ts +1 -1
- package/dist/styles/width.js +1 -2
- package/dist/styles/width.js.map +1 -1
- package/dist/tasty.d.ts +46 -894
- package/dist/tasty.js +101 -59
- package/dist/tasty.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/utils/cache-wrapper.js +4 -9
- package/dist/utils/cache-wrapper.js.map +1 -1
- package/dist/utils/case-converter.js +1 -1
- package/dist/utils/color-math.d.ts +46 -0
- package/dist/utils/color-math.js +749 -0
- package/dist/utils/color-math.js.map +1 -0
- package/dist/utils/color-space.d.ts +5 -0
- package/dist/utils/color-space.js +228 -0
- package/dist/utils/color-space.js.map +1 -0
- package/dist/utils/colors.js +3 -2
- package/dist/utils/colors.js.map +1 -1
- package/dist/utils/deps-equal.js +15 -0
- package/dist/utils/deps-equal.js.map +1 -0
- package/dist/utils/dotize.js +1 -1
- package/dist/utils/dotize.js.map +1 -1
- package/dist/utils/filter-base-props.d.ts +1 -1
- package/dist/utils/filter-base-props.js +1 -1
- package/dist/utils/filter-base-props.js.map +1 -1
- package/dist/utils/get-display-name.js +1 -1
- package/dist/utils/has-keys.js +13 -0
- package/dist/utils/has-keys.js.map +1 -0
- package/dist/utils/hash.js +14 -0
- package/dist/utils/hash.js.map +1 -0
- package/dist/utils/is-dev-env.js +1 -1
- package/dist/utils/is-dev-env.js.map +1 -1
- package/dist/utils/is-valid-element-type.js +1 -1
- package/dist/utils/merge-styles.js +1 -2
- package/dist/utils/merge-styles.js.map +1 -1
- package/dist/utils/mod-attrs.d.ts +0 -2
- package/dist/utils/mod-attrs.js +3 -4
- package/dist/utils/mod-attrs.js.map +1 -1
- package/dist/utils/process-tokens.d.ts +3 -17
- package/dist/utils/process-tokens.js +19 -107
- package/dist/utils/process-tokens.js.map +1 -1
- package/dist/utils/resolve-recipes.js +1 -2
- package/dist/utils/resolve-recipes.js.map +1 -1
- package/dist/utils/selector-transform.js +32 -0
- package/dist/utils/selector-transform.js.map +1 -0
- package/dist/utils/string.js +1 -1
- package/dist/utils/styles.d.ts +3 -82
- package/dist/utils/styles.js +29 -399
- package/dist/utils/styles.js.map +1 -1
- package/dist/utils/typography.d.ts +35 -13
- package/dist/utils/typography.js +16 -18
- package/dist/utils/typography.js.map +1 -1
- package/dist/utils/warnings.js +1 -1
- package/dist/zero/babel.d.ts +57 -84
- package/dist/zero/babel.js +217 -37
- package/dist/zero/babel.js.map +1 -1
- package/dist/zero/css-writer.js +1 -2
- package/dist/zero/css-writer.js.map +1 -1
- package/dist/zero/extractor.js +119 -3
- package/dist/zero/extractor.js.map +1 -1
- package/dist/zero/index.js +1 -2
- package/dist/zero/next.d.ts +56 -30
- package/dist/zero/next.js +105 -40
- package/dist/zero/next.js.map +1 -1
- package/docs/README.md +31 -0
- package/docs/adoption.md +298 -0
- package/docs/comparison.md +419 -0
- package/docs/configuration.md +394 -0
- package/docs/debug.md +320 -0
- package/docs/design-system.md +436 -0
- package/docs/dsl.md +688 -0
- package/docs/getting-started.md +217 -0
- package/docs/injector.md +544 -0
- package/docs/methodology.md +616 -0
- package/docs/pipeline.md +519 -0
- package/docs/react-api.md +557 -0
- package/docs/ssr.md +442 -0
- package/docs/styles.md +596 -0
- package/docs/tasty-static.md +532 -0
- package/package.json +68 -36
- package/dist/styles/align.d.ts +0 -15
- package/dist/styles/align.js +0 -14
- package/dist/styles/align.js.map +0 -1
- package/dist/styles/justify.d.ts +0 -15
- package/dist/styles/justify.js +0 -14
- package/dist/styles/justify.js.map +0 -1
- package/dist/styles/styledScrollbar.d.ts +0 -47
- package/dist/styles/styledScrollbar.js +0 -38
- package/dist/styles/styledScrollbar.js.map +0 -1
- package/dist/tokens/typography.d.ts +0 -19
- package/dist/tokens/typography.js +0 -237
- package/dist/tokens/typography.js.map +0 -1
- package/dist/utils/hsl-to-rgb.js +0 -38
- package/dist/utils/hsl-to-rgb.js.map +0 -1
- package/dist/utils/okhsl-to-rgb.js +0 -296
- package/dist/utils/okhsl-to-rgb.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"merge-styles.js","names":[],"sources":["../../src/utils/merge-styles.ts"],"sourcesContent":["import { isSelector } from '../pipeline';\nimport type { Styles, StylesWithoutSelectors } from '../styles/types';\n\nimport { isDevEnv } from './is-dev-env';\n\nconst devMode = isDevEnv();\n\nconst INHERIT_VALUE = '@inherit';\n\n/**\n * Check if a value is a state map (object, not array).\n */\nfunction isStateMap(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/**\n * Normalize a parent value to a state map.\n * - Already a state map → return as-is\n * - Non-null, non-false primitive → wrap as `{ '': value }`\n * - null / undefined / false → return null (no parent to merge with)\n */\nfunction normalizeToStateMap(value: unknown): Record<string, unknown> | null {\n if (isStateMap(value)) return value as Record<string, unknown>;\n if (value != null && value !== false) return { '': value };\n return null;\n}\n\n/**\n * Resolve a child state map against a parent value.\n *\n * Mode is determined by whether the child contains a `''` (default) key:\n * - No `''` → extend mode: parent entries preserved, child adds/overrides/repositions\n * - Has `''` → replace mode: child defines everything, `@inherit` cherry-picks from parent\n *\n * In both modes:\n * - `@inherit` value → resolve from parent state map\n * - `null` value → remove this state from the result\n * - `false` value → tombstone, persists through all layers, blocks recipe\n */\nfunction resolveStateMap(\n parentValue: unknown,\n childMap: Record<string, unknown>,\n): Record<string, unknown> {\n const isExtend = !('' in childMap);\n const parentMap = normalizeToStateMap(parentValue);\n\n if (!parentMap) {\n // No parent to merge with — strip nulls and @inherit, return child entries\n const result: Record<string, unknown> = {};\n for (const key of Object.keys(childMap)) {\n const val = childMap[key];\n if (val === null || val === INHERIT_VALUE) continue;\n result[key] = val;\n }\n return result;\n }\n\n if (isExtend) {\n return resolveExtendMode(parentMap, childMap);\n }\n\n return resolveReplaceMode(parentMap, childMap);\n}\n\n/**\n * Extend mode: parent entries are preserved, child entries add/override/reposition.\n */\nfunction resolveExtendMode(\n parentMap: Record<string, unknown>,\n childMap: Record<string, unknown>,\n): Record<string, unknown> {\n const inheritKeys = new Set<string>();\n const removeKeys = new Set<string>();\n const overrideKeys = new Map<string, unknown>();\n\n for (const key of Object.keys(childMap)) {\n const val = childMap[key];\n if (val === INHERIT_VALUE) {\n if (key in parentMap) {\n inheritKeys.add(key);\n } else if (devMode) {\n console.warn(\n `[Tasty] @inherit used for state '${key}' that does not exist in the parent style map. Entry skipped.`,\n );\n }\n } else if (val === null) {\n removeKeys.add(key);\n } else if (key in parentMap) {\n overrideKeys.set(key, val);\n }\n }\n\n // 1. Parent entries in order (skip removed, skip repositioned, apply overrides)\n const result: Record<string, unknown> = {};\n for (const key of Object.keys(parentMap)) {\n if (removeKeys.has(key)) continue;\n if (inheritKeys.has(key)) continue;\n if (overrideKeys.has(key)) {\n result[key] = overrideKeys.get(key);\n } else {\n result[key] = parentMap[key];\n }\n }\n\n // 2. Append new + repositioned entries in child declaration order\n for (const key of Object.keys(childMap)) {\n if (inheritKeys.has(key)) {\n result[key] = parentMap[key];\n } else if (\n !removeKeys.has(key) &&\n !overrideKeys.has(key) &&\n // Skip @inherit for keys that weren't in the parent (already warned above)\n childMap[key] !== INHERIT_VALUE\n ) {\n result[key] = childMap[key];\n }\n }\n\n return result;\n}\n\n/**\n * Replace mode: child entries define the result, `@inherit` pulls from parent.\n */\nfunction resolveReplaceMode(\n parentMap: Record<string, unknown>,\n childMap: Record<string, unknown>,\n): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n\n for (const key of Object.keys(childMap)) {\n const val = childMap[key];\n if (val === INHERIT_VALUE) {\n if (key in parentMap) {\n result[key] = parentMap[key];\n } else if (devMode) {\n console.warn(\n `[Tasty] @inherit used for state '${key}' that does not exist in the parent style map. Entry skipped.`,\n );\n }\n } else if (val !== null) {\n result[key] = val;\n }\n }\n\n return result;\n}\n\n/**\n * Merge sub-element properties with state map / null / undefined support.\n */\nfunction mergeSubElementStyles(\n parentSub: StylesWithoutSelectors | undefined,\n childSub: StylesWithoutSelectors,\n): StylesWithoutSelectors {\n const parent = parentSub as Record<string, unknown> | undefined;\n const child = childSub as Record<string, unknown>;\n const merged: Record<string, unknown> = { ...parent, ...child };\n\n for (const key of Object.keys(child)) {\n const val = child[key];\n\n if (val === undefined) {\n if (parent && key in parent) {\n merged[key] = parent[key];\n }\n } else if (val === null) {\n delete merged[key];\n } else if (isStateMap(val)) {\n merged[key] = resolveStateMap(\n parent ? parent[key] : undefined,\n val as Record<string, unknown>,\n );\n }\n }\n\n return merged as StylesWithoutSelectors;\n}\n\nexport function mergeStyles(...objects: (Styles | undefined | null)[]): Styles {\n let styles: Styles = objects[0] ? { ...objects[0] } : {};\n let pos = 1;\n\n while (pos in objects) {\n const selectorKeys = Object.keys(styles).filter(\n (key) => isSelector(key) && styles[key],\n );\n const newStyles = objects[pos];\n\n if (newStyles) {\n const resultStyles = { ...styles, ...newStyles };\n\n // Collect all selector keys from both parent and child\n const newSelectorKeys = Object.keys(newStyles).filter(isSelector);\n const allSelectorKeys = new Set([...selectorKeys, ...newSelectorKeys]);\n\n for (const key of allSelectorKeys) {\n const newValue = newStyles?.[key];\n\n if (newValue === false || newValue === null) {\n delete resultStyles[key];\n } else if (newValue === undefined) {\n resultStyles[key] = styles[key];\n } else if (newValue) {\n resultStyles[key] = mergeSubElementStyles(\n styles[key] as StylesWithoutSelectors,\n newValue as StylesWithoutSelectors,\n );\n }\n }\n\n // Handle non-selector properties: state maps, null, undefined\n for (const key of Object.keys(newStyles)) {\n if (isSelector(key)) continue;\n\n const newValue = newStyles[key];\n\n if (newValue === undefined) {\n if (key in styles) {\n resultStyles[key] = styles[key];\n } else {\n delete resultStyles[key];\n }\n } else if (newValue === null) {\n delete resultStyles[key];\n } else if (isStateMap(newValue)) {\n (resultStyles as Record<string, unknown>)[key] = resolveStateMap(\n styles[key],\n newValue as Record<string, unknown>,\n );\n }\n }\n\n styles = resultStyles;\n }\n\n pos++;\n }\n\n return styles;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"merge-styles.js","names":[],"sources":["../../src/utils/merge-styles.ts"],"sourcesContent":["import { isSelector } from '../pipeline';\nimport type { Styles, StylesWithoutSelectors } from '../styles/types';\n\nimport { isDevEnv } from './is-dev-env';\n\nconst devMode = isDevEnv();\n\nconst INHERIT_VALUE = '@inherit';\n\n/**\n * Check if a value is a state map (object, not array).\n */\nfunction isStateMap(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/**\n * Normalize a parent value to a state map.\n * - Already a state map → return as-is\n * - Non-null, non-false primitive → wrap as `{ '': value }`\n * - null / undefined / false → return null (no parent to merge with)\n */\nfunction normalizeToStateMap(value: unknown): Record<string, unknown> | null {\n if (isStateMap(value)) return value as Record<string, unknown>;\n if (value != null && value !== false) return { '': value };\n return null;\n}\n\n/**\n * Resolve a child state map against a parent value.\n *\n * Mode is determined by whether the child contains a `''` (default) key:\n * - No `''` → extend mode: parent entries preserved, child adds/overrides/repositions\n * - Has `''` → replace mode: child defines everything, `@inherit` cherry-picks from parent\n *\n * In both modes:\n * - `@inherit` value → resolve from parent state map\n * - `null` value → remove this state from the result\n * - `false` value → tombstone, persists through all layers, blocks recipe\n */\nfunction resolveStateMap(\n parentValue: unknown,\n childMap: Record<string, unknown>,\n): Record<string, unknown> {\n const isExtend = !('' in childMap);\n const parentMap = normalizeToStateMap(parentValue);\n\n if (!parentMap) {\n // No parent to merge with — strip nulls and @inherit, return child entries\n const result: Record<string, unknown> = {};\n for (const key of Object.keys(childMap)) {\n const val = childMap[key];\n if (val === null || val === INHERIT_VALUE) continue;\n result[key] = val;\n }\n return result;\n }\n\n if (isExtend) {\n return resolveExtendMode(parentMap, childMap);\n }\n\n return resolveReplaceMode(parentMap, childMap);\n}\n\n/**\n * Extend mode: parent entries are preserved, child entries add/override/reposition.\n */\nfunction resolveExtendMode(\n parentMap: Record<string, unknown>,\n childMap: Record<string, unknown>,\n): Record<string, unknown> {\n const inheritKeys = new Set<string>();\n const removeKeys = new Set<string>();\n const overrideKeys = new Map<string, unknown>();\n\n for (const key of Object.keys(childMap)) {\n const val = childMap[key];\n if (val === INHERIT_VALUE) {\n if (key in parentMap) {\n inheritKeys.add(key);\n } else if (devMode) {\n console.warn(\n `[Tasty] @inherit used for state '${key}' that does not exist in the parent style map. Entry skipped.`,\n );\n }\n } else if (val === null) {\n removeKeys.add(key);\n } else if (key in parentMap) {\n overrideKeys.set(key, val);\n }\n }\n\n // 1. Parent entries in order (skip removed, skip repositioned, apply overrides)\n const result: Record<string, unknown> = {};\n for (const key of Object.keys(parentMap)) {\n if (removeKeys.has(key)) continue;\n if (inheritKeys.has(key)) continue;\n if (overrideKeys.has(key)) {\n result[key] = overrideKeys.get(key);\n } else {\n result[key] = parentMap[key];\n }\n }\n\n // 2. Append new + repositioned entries in child declaration order\n for (const key of Object.keys(childMap)) {\n if (inheritKeys.has(key)) {\n result[key] = parentMap[key];\n } else if (\n !removeKeys.has(key) &&\n !overrideKeys.has(key) &&\n // Skip @inherit for keys that weren't in the parent (already warned above)\n childMap[key] !== INHERIT_VALUE\n ) {\n result[key] = childMap[key];\n }\n }\n\n return result;\n}\n\n/**\n * Replace mode: child entries define the result, `@inherit` pulls from parent.\n */\nfunction resolveReplaceMode(\n parentMap: Record<string, unknown>,\n childMap: Record<string, unknown>,\n): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n\n for (const key of Object.keys(childMap)) {\n const val = childMap[key];\n if (val === INHERIT_VALUE) {\n if (key in parentMap) {\n result[key] = parentMap[key];\n } else if (devMode) {\n console.warn(\n `[Tasty] @inherit used for state '${key}' that does not exist in the parent style map. Entry skipped.`,\n );\n }\n } else if (val !== null) {\n result[key] = val;\n }\n }\n\n return result;\n}\n\n/**\n * Merge sub-element properties with state map / null / undefined support.\n */\nfunction mergeSubElementStyles(\n parentSub: StylesWithoutSelectors | undefined,\n childSub: StylesWithoutSelectors,\n): StylesWithoutSelectors {\n const parent = parentSub as Record<string, unknown> | undefined;\n const child = childSub as Record<string, unknown>;\n const merged: Record<string, unknown> = { ...parent, ...child };\n\n for (const key of Object.keys(child)) {\n const val = child[key];\n\n if (val === undefined) {\n if (parent && key in parent) {\n merged[key] = parent[key];\n }\n } else if (val === null) {\n delete merged[key];\n } else if (isStateMap(val)) {\n merged[key] = resolveStateMap(\n parent ? parent[key] : undefined,\n val as Record<string, unknown>,\n );\n }\n }\n\n return merged as StylesWithoutSelectors;\n}\n\nexport function mergeStyles(...objects: (Styles | undefined | null)[]): Styles {\n let styles: Styles = objects[0] ? { ...objects[0] } : {};\n let pos = 1;\n\n while (pos in objects) {\n const selectorKeys = Object.keys(styles).filter(\n (key) => isSelector(key) && styles[key],\n );\n const newStyles = objects[pos];\n\n if (newStyles) {\n const resultStyles = { ...styles, ...newStyles };\n\n // Collect all selector keys from both parent and child\n const newSelectorKeys = Object.keys(newStyles).filter(isSelector);\n const allSelectorKeys = new Set([...selectorKeys, ...newSelectorKeys]);\n\n for (const key of allSelectorKeys) {\n const newValue = newStyles?.[key];\n\n if (newValue === false || newValue === null) {\n delete resultStyles[key];\n } else if (newValue === undefined) {\n resultStyles[key] = styles[key];\n } else if (newValue) {\n resultStyles[key] = mergeSubElementStyles(\n styles[key] as StylesWithoutSelectors,\n newValue as StylesWithoutSelectors,\n );\n }\n }\n\n // Handle non-selector properties: state maps, null, undefined\n for (const key of Object.keys(newStyles)) {\n if (isSelector(key)) continue;\n\n const newValue = newStyles[key];\n\n if (newValue === undefined) {\n if (key in styles) {\n resultStyles[key] = styles[key];\n } else {\n delete resultStyles[key];\n }\n } else if (newValue === null) {\n delete resultStyles[key];\n } else if (isStateMap(newValue)) {\n (resultStyles as Record<string, unknown>)[key] = resolveStateMap(\n styles[key],\n newValue as Record<string, unknown>,\n );\n }\n }\n\n styles = resultStyles;\n }\n\n pos++;\n }\n\n return styles;\n}\n"],"mappings":"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"}
|
package/dist/utils/mod-attrs.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { cacheWrapper } from "./cache-wrapper.js";
|
|
2
1
|
import { camelToKebab } from "./case-converter.js";
|
|
3
|
-
|
|
2
|
+
import { cacheWrapper } from "./cache-wrapper.js";
|
|
4
3
|
//#region src/utils/mod-attrs.ts
|
|
5
4
|
function modAttrs(map) {
|
|
6
5
|
return map ? Object.keys(map).reduce((attrs, key) => {
|
|
@@ -10,12 +9,12 @@ function modAttrs(map) {
|
|
|
10
9
|
if (value === true) attrs[attrName] = "";
|
|
11
10
|
else if (typeof value === "string") attrs[attrName] = value;
|
|
12
11
|
else if (typeof value === "number") attrs[attrName] = String(value);
|
|
13
|
-
else console.warn(`
|
|
12
|
+
else console.warn(`Tasty: Invalid mod value for "${key}". Expected boolean, string, or number, got ${typeof value}`);
|
|
14
13
|
return attrs;
|
|
15
14
|
}, {}) : null;
|
|
16
15
|
}
|
|
17
16
|
const _modAttrs = cacheWrapper(modAttrs);
|
|
18
|
-
|
|
19
17
|
//#endregion
|
|
20
18
|
export { _modAttrs };
|
|
19
|
+
|
|
21
20
|
//# sourceMappingURL=mod-attrs.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mod-attrs.js","names":[],"sources":["../../src/utils/mod-attrs.ts"],"sourcesContent":["/**\n * Generate data DOM attributes from modifier map.\n */\nimport type { AllBaseProps } from '../types';\n\nimport { cacheWrapper } from './cache-wrapper';\nimport { camelToKebab } from './case-converter';\n\nfunction modAttrs(map: AllBaseProps['mods']): Record<string, string> | null {\n return map\n ? Object.keys(map).reduce(\n (attrs, key) => {\n const value = map[key];\n\n // Skip null, undefined, false\n if (value == null || value === false) {\n return attrs;\n }\n\n const attrName = `data-${camelToKebab(key)}`;\n\n if (value === true) {\n // Boolean true: data-{name}=\"\"\n attrs[attrName] = '';\n } else if (typeof value === 'string') {\n // String value: data-{name}=\"value\"\n attrs[attrName] = value;\n } else if (typeof value === 'number') {\n // Number: convert to string\n attrs[attrName] = String(value);\n } else {\n // Reject other types (objects, arrays, functions)\n if (process.env.NODE_ENV !== 'production') {\n console.warn(\n `
|
|
1
|
+
{"version":3,"file":"mod-attrs.js","names":[],"sources":["../../src/utils/mod-attrs.ts"],"sourcesContent":["/**\n * Generate data DOM attributes from modifier map.\n */\nimport type { AllBaseProps } from '../types';\n\nimport { cacheWrapper } from './cache-wrapper';\nimport { camelToKebab } from './case-converter';\n\nfunction modAttrs(map: AllBaseProps['mods']): Record<string, string> | null {\n return map\n ? Object.keys(map).reduce(\n (attrs, key) => {\n const value = map[key];\n\n // Skip null, undefined, false\n if (value == null || value === false) {\n return attrs;\n }\n\n const attrName = `data-${camelToKebab(key)}`;\n\n if (value === true) {\n // Boolean true: data-{name}=\"\"\n attrs[attrName] = '';\n } else if (typeof value === 'string') {\n // String value: data-{name}=\"value\"\n attrs[attrName] = value;\n } else if (typeof value === 'number') {\n // Number: convert to string\n attrs[attrName] = String(value);\n } else {\n // Reject other types (objects, arrays, functions)\n if (process.env.NODE_ENV !== 'production') {\n console.warn(\n `Tasty: Invalid mod value for \"${key}\". Expected boolean, string, or number, got ${typeof value}`,\n );\n }\n }\n\n return attrs;\n },\n {} as Record<string, string>,\n )\n : null;\n}\n\nconst _modAttrs = cacheWrapper(modAttrs);\n\nexport { _modAttrs as modAttrs };\n"],"mappings":";;;AAQA,SAAS,SAAS,KAA0D;AAC1E,QAAO,MACH,OAAO,KAAK,IAAI,CAAC,QACd,OAAO,QAAQ;EACd,MAAM,QAAQ,IAAI;AAGlB,MAAI,SAAS,QAAQ,UAAU,MAC7B,QAAO;EAGT,MAAM,WAAW,QAAQ,aAAa,IAAI;AAE1C,MAAI,UAAU,KAEZ,OAAM,YAAY;WACT,OAAO,UAAU,SAE1B,OAAM,YAAY;WACT,OAAO,UAAU,SAE1B,OAAM,YAAY,OAAO,MAAM;MAI7B,SAAQ,KACN,iCAAiC,IAAI,8CAA8C,OAAO,QAC3F;AAIL,SAAO;IAET,EAAE,CACH,GACD;;AAGN,MAAM,YAAY,aAAa,SAAS"}
|
|
@@ -1,31 +1,17 @@
|
|
|
1
1
|
import { CSSProperties } from "./css-types.js";
|
|
2
|
+
import { hslToRgbValues } from "./color-math.js";
|
|
2
3
|
import { Tokens } from "../types.js";
|
|
3
4
|
|
|
4
5
|
//#region src/utils/process-tokens.d.ts
|
|
5
|
-
/**
|
|
6
|
-
* Convert HSL to RGB (sRGB).
|
|
7
|
-
* Algorithm from: https://en.wikipedia.org/wiki/HSL_and_HSV#HSL_to_RGB_alternative
|
|
8
|
-
* Same as used in CSS Color 4 spec.
|
|
9
|
-
*
|
|
10
|
-
* @param h - Hue in degrees (0-360)
|
|
11
|
-
* @param s - Saturation (0-1)
|
|
12
|
-
* @param l - Lightness (0-1)
|
|
13
|
-
* @returns RGB values in 0-255 range (may have fractional values)
|
|
14
|
-
*/
|
|
15
|
-
declare function hslToRgbValues(h: number, s: number, l: number): [number, number, number];
|
|
16
6
|
/**
|
|
17
7
|
* Process tokens object into inline style properties.
|
|
18
8
|
* - $name -> --name with parsed value
|
|
19
|
-
* - #name -> --name-color AND --name-color-
|
|
9
|
+
* - #name -> --name-color AND --name-color-{colorSpace} with parsed values
|
|
20
10
|
*
|
|
21
11
|
* @param tokens - The tokens object to process
|
|
22
12
|
* @returns CSSProperties object or undefined if no tokens to process
|
|
23
13
|
*/
|
|
24
14
|
declare function processTokens(tokens: Tokens | undefined): CSSProperties | undefined;
|
|
25
|
-
/**
|
|
26
|
-
* Stringify tokens for memoization key.
|
|
27
|
-
*/
|
|
28
|
-
declare function stringifyTokens(tokens: Tokens | undefined): string;
|
|
29
15
|
//#endregion
|
|
30
|
-
export {
|
|
16
|
+
export { processTokens };
|
|
31
17
|
//# sourceMappingURL=process-tokens.d.ts.map
|
|
@@ -1,102 +1,20 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
|
|
1
|
+
import "./color-math.js";
|
|
2
|
+
import { getColorSpaceComponents, getColorSpaceSuffix } from "./color-space.js";
|
|
3
|
+
import { normalizeColorTokenValue, parseStyle } from "./styles.js";
|
|
4
4
|
//#region src/utils/process-tokens.ts
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* hsl(200 40% 50%)
|
|
10
|
-
* hsl(200 40% 50% / 0.5)
|
|
11
|
-
*
|
|
12
|
-
* Returns [h, s, l] where h is 0-360, s and l are 0-1, or null if parsing fails.
|
|
13
|
-
*/
|
|
14
|
-
function parseHslValues(str) {
|
|
15
|
-
const match = str.match(/hsla?\(([^)]+)\)/i);
|
|
16
|
-
if (!match) return null;
|
|
17
|
-
const [colorPart] = match[1].trim().split("/");
|
|
18
|
-
const parts = colorPart.trim().split(/[,\s]+/).filter(Boolean);
|
|
19
|
-
if (parts.length < 3) return null;
|
|
20
|
-
let h = parseFloat(parts[0]);
|
|
21
|
-
const hueStr = parts[0].toLowerCase();
|
|
22
|
-
if (hueStr.endsWith("turn")) h = parseFloat(hueStr) * 360;
|
|
23
|
-
else if (hueStr.endsWith("rad")) h = parseFloat(hueStr) * 180 / Math.PI;
|
|
24
|
-
else if (hueStr.endsWith("grad")) h = parseFloat(hueStr) * .9;
|
|
25
|
-
h = h % 360;
|
|
26
|
-
if (h < 0) h += 360;
|
|
27
|
-
const parsePercent = (val) => {
|
|
28
|
-
const num = parseFloat(val);
|
|
29
|
-
return val.includes("%") ? num / 100 : num;
|
|
30
|
-
};
|
|
31
|
-
const s = Math.max(0, Math.min(1, parsePercent(parts[1])));
|
|
32
|
-
const l = Math.max(0, Math.min(1, parsePercent(parts[2])));
|
|
33
|
-
return [
|
|
34
|
-
h,
|
|
35
|
-
s,
|
|
36
|
-
l
|
|
37
|
-
];
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* Convert HSL to RGB (sRGB).
|
|
41
|
-
* Algorithm from: https://en.wikipedia.org/wiki/HSL_and_HSV#HSL_to_RGB_alternative
|
|
42
|
-
* Same as used in CSS Color 4 spec.
|
|
43
|
-
*
|
|
44
|
-
* @param h - Hue in degrees (0-360)
|
|
45
|
-
* @param s - Saturation (0-1)
|
|
46
|
-
* @param l - Lightness (0-1)
|
|
47
|
-
* @returns RGB values in 0-255 range (may have fractional values)
|
|
48
|
-
*/
|
|
49
|
-
function hslToRgbValues(h, s, l) {
|
|
50
|
-
const a = s * Math.min(l, 1 - l);
|
|
51
|
-
const f = (n) => {
|
|
52
|
-
const k = (n + h / 30) % 12;
|
|
53
|
-
return l - a * Math.max(-1, Math.min(k - 3, 9 - k, 1));
|
|
54
|
-
};
|
|
55
|
-
return [
|
|
56
|
-
f(0) * 255,
|
|
57
|
-
f(8) * 255,
|
|
58
|
-
f(4) * 255
|
|
59
|
-
];
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
|
-
* Format a number to a string with up to 1 decimal place, removing trailing zeros.
|
|
63
|
-
*/
|
|
64
|
-
function formatRgbComponent(n) {
|
|
65
|
-
return parseFloat(n.toFixed(1)).toString();
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Extract RGB triplet from a color value.
|
|
69
|
-
* Returns the RGB values as a space-separated string (e.g., "255 128 0")
|
|
70
|
-
* or a CSS variable reference for token colors.
|
|
6
|
+
* Extract color components in the configured color space.
|
|
7
|
+
* Returns a CSS variable reference for token colors, or decomposed
|
|
8
|
+
* components as a space-separated string.
|
|
71
9
|
*/
|
|
72
|
-
function
|
|
10
|
+
function extractColorSpaceValue(colorValue, parsedOutput) {
|
|
11
|
+
const suffix = getColorSpaceSuffix();
|
|
73
12
|
const varMatch = parsedOutput.match(/var\(--([a-z0-9-]+)-color\)/);
|
|
74
|
-
if (varMatch) return `var(--${varMatch[1]}-color
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
if (parsedOutput.startsWith("hsl(") || parsedOutput.startsWith("hsla(") || colorValue.startsWith("hsl(") || colorValue.startsWith("hsla(")) {
|
|
80
|
-
const hslValues = parseHslValues(parsedOutput) || parseHslValues(colorValue);
|
|
81
|
-
if (hslValues) {
|
|
82
|
-
const [r, g, b] = hslToRgbValues(hslValues[0], hslValues[1], hslValues[2]);
|
|
83
|
-
return `${formatRgbComponent(r)} ${formatRgbComponent(g)} ${formatRgbComponent(b)}`;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
if (parsedOutput.startsWith("okhsl(") || colorValue.startsWith("okhsl(")) {
|
|
87
|
-
const rgbResult = okhslToRgb(parsedOutput) || okhslToRgb(colorValue);
|
|
88
|
-
if (rgbResult) {
|
|
89
|
-
const rgbValues = getRgbValuesFromRgbaString(rgbResult);
|
|
90
|
-
if (rgbValues && rgbValues.length >= 3) return rgbValues.join(" ");
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
if (colorValue.startsWith("#") && /^#[0-9a-fA-F]{3,8}$/.test(colorValue)) {
|
|
94
|
-
const rgbResult = hexToRgb(colorValue);
|
|
95
|
-
if (rgbResult) {
|
|
96
|
-
const rgbValues = getRgbValuesFromRgbaString(rgbResult);
|
|
97
|
-
if (rgbValues && rgbValues.length >= 3) return rgbValues.join(" ");
|
|
98
|
-
}
|
|
99
|
-
}
|
|
13
|
+
if (varMatch) return `var(--${varMatch[1]}-color-${suffix})`;
|
|
14
|
+
const components = getColorSpaceComponents(colorValue);
|
|
15
|
+
if (components !== colorValue) return components;
|
|
16
|
+
const componentsFromParsed = getColorSpaceComponents(parsedOutput);
|
|
17
|
+
if (componentsFromParsed !== parsedOutput) return componentsFromParsed;
|
|
100
18
|
return parsedOutput;
|
|
101
19
|
}
|
|
102
20
|
/**
|
|
@@ -106,7 +24,7 @@ function extractRgbValue(colorValue, parsedOutput) {
|
|
|
106
24
|
function isValidTokenValue(value) {
|
|
107
25
|
if (value === void 0 || value === null || value === false) return false;
|
|
108
26
|
if (typeof value === "object") {
|
|
109
|
-
console.warn("
|
|
27
|
+
console.warn("Tasty: Object values are not allowed in tokens prop. Tokens do not support state-based styling. Use a primitive value instead.");
|
|
110
28
|
return false;
|
|
111
29
|
}
|
|
112
30
|
return typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
@@ -125,7 +43,7 @@ function processTokenValue(value) {
|
|
|
125
43
|
/**
|
|
126
44
|
* Process tokens object into inline style properties.
|
|
127
45
|
* - $name -> --name with parsed value
|
|
128
|
-
* - #name -> --name-color AND --name-color-
|
|
46
|
+
* - #name -> --name-color AND --name-color-{colorSpace} with parsed values
|
|
129
47
|
*
|
|
130
48
|
* @param tokens - The tokens object to process
|
|
131
49
|
* @returns CSSProperties object or undefined if no tokens to process
|
|
@@ -145,6 +63,7 @@ function processTokens(tokens) {
|
|
|
145
63
|
result[propName] = processedValue;
|
|
146
64
|
} else if (key.startsWith("#")) {
|
|
147
65
|
const colorName = key.slice(1);
|
|
66
|
+
const suffix = getColorSpaceSuffix();
|
|
148
67
|
const effectiveValue = normalizeColorTokenValue(value);
|
|
149
68
|
if (effectiveValue === null) continue;
|
|
150
69
|
const originalValue = typeof effectiveValue === "number" ? String(effectiveValue) : effectiveValue;
|
|
@@ -153,19 +72,12 @@ function processTokens(tokens) {
|
|
|
153
72
|
if (!result) result = {};
|
|
154
73
|
result[`--${colorName}-color`] = processedValue;
|
|
155
74
|
if (/^#current(?:\.|$)/i.test(lowerValue)) continue;
|
|
156
|
-
result[`--${colorName}-color
|
|
75
|
+
result[`--${colorName}-color-${suffix}`] = extractColorSpaceValue(originalValue, processedValue);
|
|
157
76
|
}
|
|
158
77
|
}
|
|
159
78
|
return result;
|
|
160
79
|
}
|
|
161
|
-
/**
|
|
162
|
-
* Stringify tokens for memoization key.
|
|
163
|
-
*/
|
|
164
|
-
function stringifyTokens(tokens) {
|
|
165
|
-
if (!tokens) return "";
|
|
166
|
-
return JSON.stringify(tokens);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
80
|
//#endregion
|
|
170
|
-
export {
|
|
81
|
+
export { processTokens };
|
|
82
|
+
|
|
171
83
|
//# sourceMappingURL=process-tokens.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"process-tokens.js","names":[],"sources":["../../src/utils/process-tokens.ts"],"sourcesContent":["import type { Tokens, TokenValue } from '../types';\n\nimport type { CSSProperties } from './css-types';\n\nimport { okhslToRgb } from './okhsl-to-rgb';\nimport {\n getRgbValuesFromRgbaString,\n hexToRgb,\n normalizeColorTokenValue,\n parseStyle,\n} from './styles';\n\nconst devMode = process.env.NODE_ENV !== 'production';\n\n/**\n * Parse HSL values from an hsl()/hsla() string.\n * Supports both comma-separated (legacy) and space-separated (modern) syntax:\n * hsl(200, 40%, 50%)\n * hsl(200 40% 50%)\n * hsl(200 40% 50% / 0.5)\n *\n * Returns [h, s, l] where h is 0-360, s and l are 0-1, or null if parsing fails.\n */\nfunction parseHslValues(str: string): [number, number, number] | null {\n const match = str.match(/hsla?\\(([^)]+)\\)/i);\n if (!match) return null;\n\n const inner = match[1].trim();\n // Split by slash first (for alpha), then handle color components\n const [colorPart] = inner.split('/');\n // Split by comma or whitespace\n const parts = colorPart\n .trim()\n .split(/[,\\s]+/)\n .filter(Boolean);\n\n if (parts.length < 3) return null;\n\n // Parse hue (can be unitless degrees, deg, turn, rad, or grad)\n let h = parseFloat(parts[0]);\n const hueStr = parts[0].toLowerCase();\n if (hueStr.endsWith('turn')) {\n h = parseFloat(hueStr) * 360;\n } else if (hueStr.endsWith('rad')) {\n h = (parseFloat(hueStr) * 180) / Math.PI;\n } else if (hueStr.endsWith('grad')) {\n h = parseFloat(hueStr) * 0.9; // 400 grad = 360 deg\n }\n // deg or unitless are already in degrees\n\n // Normalize hue to 0-360 range\n h = h % 360;\n if (h < 0) h += 360;\n\n // Parse saturation and lightness (percentages)\n const parsePercent = (val: string): number => {\n const num = parseFloat(val);\n return val.includes('%') ? num / 100 : num;\n };\n\n const s = Math.max(0, Math.min(1, parsePercent(parts[1])));\n const l = Math.max(0, Math.min(1, parsePercent(parts[2])));\n\n return [h, s, l];\n}\n\n/**\n * Convert HSL to RGB (sRGB).\n * Algorithm from: https://en.wikipedia.org/wiki/HSL_and_HSV#HSL_to_RGB_alternative\n * Same as used in CSS Color 4 spec.\n *\n * @param h - Hue in degrees (0-360)\n * @param s - Saturation (0-1)\n * @param l - Lightness (0-1)\n * @returns RGB values in 0-255 range (may have fractional values)\n */\nexport function hslToRgbValues(\n h: number,\n s: number,\n l: number,\n): [number, number, number] {\n const a = s * Math.min(l, 1 - l);\n\n const f = (n: number): number => {\n const k = (n + h / 30) % 12;\n return l - a * Math.max(-1, Math.min(k - 3, 9 - k, 1));\n };\n\n // Convert 0-1 range to 0-255\n return [f(0) * 255, f(8) * 255, f(4) * 255];\n}\n\n/**\n * Format a number to a string with up to 1 decimal place, removing trailing zeros.\n */\nfunction formatRgbComponent(n: number): string {\n return parseFloat(n.toFixed(1)).toString();\n}\n\n/**\n * Extract RGB triplet from a color value.\n * Returns the RGB values as a space-separated string (e.g., \"255 128 0\")\n * or a CSS variable reference for token colors.\n */\nfunction extractRgbValue(colorValue: string, parsedOutput: string): string {\n // If the parsed output references a color variable, use the -rgb variant\n const varMatch = parsedOutput.match(/var\\(--([a-z0-9-]+)-color\\)/);\n if (varMatch) {\n return `var(--${varMatch[1]}-color-rgb)`;\n }\n\n // For rgb(...) values, extract the triplet\n if (parsedOutput.startsWith('rgb(')) {\n const rgbValues = getRgbValuesFromRgbaString(parsedOutput);\n if (rgbValues && rgbValues.length >= 3) {\n return rgbValues.join(' ');\n }\n }\n\n // For hsl(...) values, convert to RGB triplet\n if (\n parsedOutput.startsWith('hsl(') ||\n parsedOutput.startsWith('hsla(') ||\n colorValue.startsWith('hsl(') ||\n colorValue.startsWith('hsla(')\n ) {\n // Try parsedOutput first, then original colorValue\n const hslValues =\n parseHslValues(parsedOutput) || parseHslValues(colorValue);\n if (hslValues) {\n const [r, g, b] = hslToRgbValues(\n hslValues[0],\n hslValues[1],\n hslValues[2],\n );\n return `${formatRgbComponent(r)} ${formatRgbComponent(g)} ${formatRgbComponent(b)}`;\n }\n }\n\n // For okhsl(...) values, convert to RGB triplet\n if (parsedOutput.startsWith('okhsl(') || colorValue.startsWith('okhsl(')) {\n // Try parsedOutput first, then original colorValue\n const rgbResult = okhslToRgb(parsedOutput) || okhslToRgb(colorValue);\n if (rgbResult) {\n const rgbValues = getRgbValuesFromRgbaString(rgbResult);\n if (rgbValues && rgbValues.length >= 3) {\n return rgbValues.join(' ');\n }\n }\n }\n\n // For hex values, convert to RGB triplet\n if (colorValue.startsWith('#') && /^#[0-9a-fA-F]{3,8}$/.test(colorValue)) {\n const rgbResult = hexToRgb(colorValue);\n if (rgbResult) {\n const rgbValues = getRgbValuesFromRgbaString(rgbResult);\n if (rgbValues && rgbValues.length >= 3) {\n return rgbValues.join(' ');\n }\n }\n }\n\n // Fallback: return the parsed output (may not be ideal but covers edge cases)\n return parsedOutput;\n}\n\n/**\n * Check if a value is a valid token value (string, number, or boolean - not object).\n * Returns false for `false` values (they mean \"skip this token\").\n */\nfunction isValidTokenValue(\n value: unknown,\n): value is Exclude<TokenValue, undefined | null | false> {\n if (value === undefined || value === null || value === false) {\n return false;\n }\n\n if (typeof value === 'object') {\n if (devMode) {\n console.warn(\n 'CubeUIKit: Object values are not allowed in tokens prop. ' +\n 'Tokens do not support state-based styling. Use a primitive value instead.',\n );\n }\n return false;\n }\n\n return (\n typeof value === 'string' ||\n typeof value === 'number' ||\n typeof value === 'boolean'\n );\n}\n\n/**\n * Process a single token value through the tasty parser.\n * Numbers are converted to strings; 0 stays as \"0\".\n */\nfunction processTokenValue(value: string | number): string {\n if (typeof value === 'number') {\n // 0 should remain as \"0\", not converted to any unit\n if (value === 0) {\n return '0';\n }\n return parseStyle(String(value)).output;\n }\n return parseStyle(value).output;\n}\n\n/**\n * Process tokens object into inline style properties.\n * - $name -> --name with parsed value\n * - #name -> --name-color AND --name-color-rgb with parsed values\n *\n * @param tokens - The tokens object to process\n * @returns CSSProperties object or undefined if no tokens to process\n */\nexport function processTokens(\n tokens: Tokens | undefined,\n): CSSProperties | undefined {\n if (!tokens) {\n return undefined;\n }\n\n const keys = Object.keys(tokens);\n if (keys.length === 0) {\n return undefined;\n }\n\n let result: Record<string, string> | undefined;\n\n for (const key of keys) {\n const value = tokens[key as keyof Tokens];\n\n // Skip undefined/null values\n if (!isValidTokenValue(value)) {\n continue;\n }\n\n if (key.startsWith('$')) {\n // Custom property token: $name -> --name\n const propName = `--${key.slice(1)}`;\n // Boolean true for custom properties converts to empty string (valid CSS value)\n const effectiveValue = value === true ? '' : value;\n const processedValue = processTokenValue(effectiveValue);\n\n if (!result) result = {};\n result[propName] = processedValue;\n } else if (key.startsWith('#')) {\n // Color token: #name -> --name-color and --name-color-rgb\n const colorName = key.slice(1);\n\n // Normalize color token value (true → 'transparent', false is already filtered by isValidTokenValue)\n const effectiveValue = normalizeColorTokenValue(value);\n // Skip if normalized to null (shouldn't happen since false is filtered by isValidTokenValue)\n if (effectiveValue === null) continue;\n\n const originalValue =\n typeof effectiveValue === 'number'\n ? String(effectiveValue)\n : effectiveValue;\n const lowerValue = originalValue.toLowerCase();\n const processedValue = processTokenValue(effectiveValue);\n\n if (!result) result = {};\n result[`--${colorName}-color`] = processedValue;\n\n // Skip RGB generation for #current values (currentcolor is dynamic, cannot extract RGB)\n // Match only #current or #current.opacity, not #current-theme or #currently-used\n if (/^#current(?:\\.|$)/i.test(lowerValue)) {\n continue;\n }\n\n result[`--${colorName}-color-rgb`] = extractRgbValue(\n originalValue,\n processedValue,\n );\n }\n }\n\n return result as CSSProperties | undefined;\n}\n\n/**\n * Stringify tokens for memoization key.\n */\nexport function stringifyTokens(tokens: Tokens | undefined): string {\n if (!tokens) return '';\n return JSON.stringify(tokens);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"process-tokens.js","names":[],"sources":["../../src/utils/process-tokens.ts"],"sourcesContent":["import type { Tokens, TokenValue } from '../types';\n\nimport type { CSSProperties } from './css-types';\n\nimport { getColorSpaceComponents, getColorSpaceSuffix } from './color-space';\nimport { normalizeColorTokenValue, parseStyle } from './styles';\n\nexport { hslToRgbValues } from './color-math';\n\nconst devMode = process.env.NODE_ENV !== 'production';\n\n/**\n * Extract color components in the configured color space.\n * Returns a CSS variable reference for token colors, or decomposed\n * components as a space-separated string.\n */\nfunction extractColorSpaceValue(\n colorValue: string,\n parsedOutput: string,\n): string {\n const suffix = getColorSpaceSuffix();\n\n // If the parsed output references a color variable, use the companion variant\n const varMatch = parsedOutput.match(/var\\(--([a-z0-9-]+)-color\\)/);\n if (varMatch) {\n return `var(--${varMatch[1]}-color-${suffix})`;\n }\n\n // Try the original color value first, then parsed output\n const components = getColorSpaceComponents(colorValue);\n if (components !== colorValue) return components;\n\n const componentsFromParsed = getColorSpaceComponents(parsedOutput);\n if (componentsFromParsed !== parsedOutput) return componentsFromParsed;\n\n // Fallback: return the parsed output\n return parsedOutput;\n}\n\n/**\n * Check if a value is a valid token value (string, number, or boolean - not object).\n * Returns false for `false` values (they mean \"skip this token\").\n */\nfunction isValidTokenValue(\n value: unknown,\n): value is Exclude<TokenValue, undefined | null | false> {\n if (value === undefined || value === null || value === false) {\n return false;\n }\n\n if (typeof value === 'object') {\n if (devMode) {\n console.warn(\n 'Tasty: Object values are not allowed in tokens prop. ' +\n 'Tokens do not support state-based styling. Use a primitive value instead.',\n );\n }\n return false;\n }\n\n return (\n typeof value === 'string' ||\n typeof value === 'number' ||\n typeof value === 'boolean'\n );\n}\n\n/**\n * Process a single token value through the tasty parser.\n * Numbers are converted to strings; 0 stays as \"0\".\n */\nfunction processTokenValue(value: string | number): string {\n if (typeof value === 'number') {\n // 0 should remain as \"0\", not converted to any unit\n if (value === 0) {\n return '0';\n }\n return parseStyle(String(value)).output;\n }\n return parseStyle(value).output;\n}\n\n/**\n * Process tokens object into inline style properties.\n * - $name -> --name with parsed value\n * - #name -> --name-color AND --name-color-{colorSpace} with parsed values\n *\n * @param tokens - The tokens object to process\n * @returns CSSProperties object or undefined if no tokens to process\n */\nexport function processTokens(\n tokens: Tokens | undefined,\n): CSSProperties | undefined {\n if (!tokens) {\n return undefined;\n }\n\n const keys = Object.keys(tokens);\n if (keys.length === 0) {\n return undefined;\n }\n\n let result: Record<string, string> | undefined;\n\n for (const key of keys) {\n const value = tokens[key as keyof Tokens];\n\n // Skip undefined/null values\n if (!isValidTokenValue(value)) {\n continue;\n }\n\n if (key.startsWith('$')) {\n // Custom property token: $name -> --name\n const propName = `--${key.slice(1)}`;\n // Boolean true for custom properties converts to empty string (valid CSS value)\n const effectiveValue = value === true ? '' : value;\n const processedValue = processTokenValue(effectiveValue);\n\n if (!result) result = {};\n result[propName] = processedValue;\n } else if (key.startsWith('#')) {\n const colorName = key.slice(1);\n const suffix = getColorSpaceSuffix();\n\n // Normalize color token value (true → 'transparent', false is already filtered by isValidTokenValue)\n const effectiveValue = normalizeColorTokenValue(value);\n // Skip if normalized to null (shouldn't happen since false is filtered by isValidTokenValue)\n if (effectiveValue === null) continue;\n\n const originalValue =\n typeof effectiveValue === 'number'\n ? String(effectiveValue)\n : effectiveValue;\n const lowerValue = originalValue.toLowerCase();\n const processedValue = processTokenValue(effectiveValue);\n\n if (!result) result = {};\n result[`--${colorName}-color`] = processedValue;\n\n // Skip component generation for #current values (currentcolor is dynamic, cannot decompose)\n if (/^#current(?:\\.|$)/i.test(lowerValue)) {\n continue;\n }\n\n result[`--${colorName}-color-${suffix}`] = extractColorSpaceValue(\n originalValue,\n processedValue,\n );\n }\n }\n\n return result as CSSProperties | undefined;\n}\n"],"mappings":";;;;;;;;;AAgBA,SAAS,uBACP,YACA,cACQ;CACR,MAAM,SAAS,qBAAqB;CAGpC,MAAM,WAAW,aAAa,MAAM,8BAA8B;AAClE,KAAI,SACF,QAAO,SAAS,SAAS,GAAG,SAAS,OAAO;CAI9C,MAAM,aAAa,wBAAwB,WAAW;AACtD,KAAI,eAAe,WAAY,QAAO;CAEtC,MAAM,uBAAuB,wBAAwB,aAAa;AAClE,KAAI,yBAAyB,aAAc,QAAO;AAGlD,QAAO;;;;;;AAOT,SAAS,kBACP,OACwD;AACxD,KAAI,UAAU,KAAA,KAAa,UAAU,QAAQ,UAAU,MACrD,QAAO;AAGT,KAAI,OAAO,UAAU,UAAU;AAE3B,UAAQ,KACN,iIAED;AAEH,SAAO;;AAGT,QACE,OAAO,UAAU,YACjB,OAAO,UAAU,YACjB,OAAO,UAAU;;;;;;AAQrB,SAAS,kBAAkB,OAAgC;AACzD,KAAI,OAAO,UAAU,UAAU;AAE7B,MAAI,UAAU,EACZ,QAAO;AAET,SAAO,WAAW,OAAO,MAAM,CAAC,CAAC;;AAEnC,QAAO,WAAW,MAAM,CAAC;;;;;;;;;;AAW3B,SAAgB,cACd,QAC2B;AAC3B,KAAI,CAAC,OACH;CAGF,MAAM,OAAO,OAAO,KAAK,OAAO;AAChC,KAAI,KAAK,WAAW,EAClB;CAGF,IAAI;AAEJ,MAAK,MAAM,OAAO,MAAM;EACtB,MAAM,QAAQ,OAAO;AAGrB,MAAI,CAAC,kBAAkB,MAAM,CAC3B;AAGF,MAAI,IAAI,WAAW,IAAI,EAAE;GAEvB,MAAM,WAAW,KAAK,IAAI,MAAM,EAAE;GAGlC,MAAM,iBAAiB,kBADA,UAAU,OAAO,KAAK,MACW;AAExD,OAAI,CAAC,OAAQ,UAAS,EAAE;AACxB,UAAO,YAAY;aACV,IAAI,WAAW,IAAI,EAAE;GAC9B,MAAM,YAAY,IAAI,MAAM,EAAE;GAC9B,MAAM,SAAS,qBAAqB;GAGpC,MAAM,iBAAiB,yBAAyB,MAAM;AAEtD,OAAI,mBAAmB,KAAM;GAE7B,MAAM,gBACJ,OAAO,mBAAmB,WACtB,OAAO,eAAe,GACtB;GACN,MAAM,aAAa,cAAc,aAAa;GAC9C,MAAM,iBAAiB,kBAAkB,eAAe;AAExD,OAAI,CAAC,OAAQ,UAAS,EAAE;AACxB,UAAO,KAAK,UAAU,WAAW;AAGjC,OAAI,qBAAqB,KAAK,WAAW,CACvC;AAGF,UAAO,KAAK,UAAU,SAAS,YAAY,uBACzC,eACA,eACD;;;AAIL,QAAO"}
|
|
@@ -2,7 +2,6 @@ import { isDevEnv } from "./is-dev-env.js";
|
|
|
2
2
|
import { isSelector } from "../pipeline/index.js";
|
|
3
3
|
import { getGlobalRecipes } from "../config.js";
|
|
4
4
|
import { mergeStyles } from "./merge-styles.js";
|
|
5
|
-
|
|
6
5
|
//#region src/utils/resolve-recipes.ts
|
|
7
6
|
/**
|
|
8
7
|
* Recipe resolution utility.
|
|
@@ -141,7 +140,7 @@ function resolveRecipes(styles) {
|
|
|
141
140
|
}
|
|
142
141
|
return changed ? result : styles;
|
|
143
142
|
}
|
|
144
|
-
|
|
145
143
|
//#endregion
|
|
146
144
|
export { resolveRecipes };
|
|
145
|
+
|
|
147
146
|
//# sourceMappingURL=resolve-recipes.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve-recipes.js","names":[],"sources":["../../src/utils/resolve-recipes.ts"],"sourcesContent":["/**\n * Recipe resolution utility.\n *\n * Resolves `recipe` style properties by looking up predefined recipe styles\n * from global configuration and merging them with the component's own styles.\n *\n * Resolution order per level (top-level and each sub-element independently):\n * base_recipe_1 base_recipe_2 → component styles → post_recipe_1 post_recipe_2\n *\n * The `/` separator splits base recipes (before component styles)\n * from post recipes (after component styles). All merges use mergeStyles\n * semantics: primitives and state maps with '' key fully replace;\n * state maps without '' key extend the existing value.\n *\n * Returns the same object reference if no recipes are present (zero overhead).\n */\n\nimport { getGlobalRecipes } from '../config';\nimport { isSelector } from '../pipeline';\nimport type { RecipeStyles, Styles } from '../styles/types';\n\nimport { isDevEnv } from './is-dev-env';\nimport { mergeStyles } from './merge-styles';\n\nconst devMode = isDevEnv();\n\ninterface ParsedRecipeGroups {\n base: string[] | null;\n post: string[] | null;\n}\n\n/**\n * Parse a recipe string into base and post recipe name groups.\n *\n * Syntax: `'base1 base2 / post1 post2'`\n * - Names are space-separated within each group\n * - `/` separates base (before component) from post (after component) groups\n * - `/` is optional; if absent, all names are base\n * - `none` as the sole base value means \"no base recipes\"\n *\n * Returns `{ base: null, post: null }` if the string is empty or invalid.\n */\nfunction parseRecipeNames(value: unknown): ParsedRecipeGroups {\n const empty: ParsedRecipeGroups = { base: null, post: null };\n\n if (typeof value !== 'string') return empty;\n const trimmed = value.trim();\n if (trimmed === '') return empty;\n\n const slashIndex = trimmed.indexOf('/');\n\n if (slashIndex === -1) {\n if (trimmed === 'none') return empty;\n const names = splitNames(trimmed);\n return { base: names, post: null };\n }\n\n const basePart = trimmed.slice(0, slashIndex);\n const postPart = trimmed.slice(slashIndex + 1);\n\n return {\n base: basePart.trim() === 'none' ? null : splitNames(basePart),\n post: splitNames(postPart),\n };\n}\n\nfunction splitNames(s: string): string[] | null {\n const names = s.split(/\\s+/).filter(Boolean);\n return names.length > 0 ? names : null;\n}\n\n/**\n * Collect merged styles for a list of recipe names.\n * Each recipe is flat-spread on top of the previous.\n */\nfunction collectRecipeStyles(\n names: string[],\n recipes: Record<string, RecipeStyles>,\n): Record<string, unknown> {\n let merged: Record<string, unknown> = {};\n\n for (const name of names) {\n const recipeStyles = recipes[name];\n\n if (!recipeStyles) {\n if (devMode) {\n console.warn(\n `[Tasty] Recipe \"${name}\" not found. ` +\n `Make sure it is defined in configure({ recipes: { ... } }).`,\n );\n }\n continue;\n }\n\n merged = { ...merged, ...(recipeStyles as Record<string, unknown>) };\n }\n\n return merged;\n}\n\n/**\n * Resolve recipe references in a flat styles object (no sub-elements).\n * Returns null if no `recipe` key is present.\n *\n * Resolution: base recipes → component styles → post recipes (all via mergeStyles)\n */\nfunction resolveRecipesForLevel(\n styles: Record<string, unknown>,\n recipes: Record<string, RecipeStyles>,\n): Record<string, unknown> | null {\n if (!('recipe' in styles)) return null;\n\n const { base, post } = parseRecipeNames(styles.recipe);\n\n // Separate selector keys (sub-elements) from flat style properties.\n // mergeStyles handles selectors with its own semantics (e.g. false = delete),\n // but at this level we only want recipe merging on flat properties.\n\n const { recipe: _recipe, ...allRest } = styles;\n const flatStyles: Record<string, unknown> = {};\n const selectorStyles: Record<string, unknown> = {};\n\n for (const key of Object.keys(allRest)) {\n if (isSelector(key)) {\n selectorStyles[key] = allRest[key];\n } else {\n flatStyles[key] = allRest[key];\n }\n }\n\n if (!base && !post) {\n return allRest;\n }\n\n // 1. Merge base recipes, then component styles on top (via mergeStyles)\n let result: Record<string, unknown>;\n\n if (base) {\n const baseStyles = collectRecipeStyles(base, recipes);\n result = mergeStyles(baseStyles as Styles, flatStyles as Styles) as Record<\n string,\n unknown\n >;\n } else {\n result = { ...flatStyles };\n }\n\n // 2. Apply post recipes via mergeStyles (state map extend semantics)\n if (post) {\n const postStyles = collectRecipeStyles(post, recipes);\n result = mergeStyles(result as Styles, postStyles as Styles) as Record<\n string,\n unknown\n >;\n }\n\n // Re-attach selector keys unchanged\n for (const key of Object.keys(selectorStyles)) {\n result[key] = selectorStyles[key];\n }\n\n return result;\n}\n\n/**\n * Resolve all `recipe` style properties in a styles object.\n *\n * Handles both top-level and sub-element recipe references.\n * Returns the same object reference if no recipes are present anywhere\n * (zero overhead for the common case).\n *\n * @param styles - The styles object potentially containing `recipe` keys\n * @returns Resolved styles with recipe values merged in, or the original object if unchanged\n */\nexport function resolveRecipes(styles: Styles): Styles {\n const recipes = getGlobalRecipes();\n\n // Fast path: no recipes configured globally\n if (!recipes) return styles;\n\n let changed = false;\n\n // Resolve top-level recipe\n const topResolved = resolveRecipesForLevel(\n styles as Record<string, unknown>,\n recipes,\n );\n\n let result: Record<string, unknown>;\n\n if (topResolved) {\n changed = true;\n result = topResolved;\n } else {\n // Keep reference; a shallow copy is deferred until a sub-element actually changes\n result = styles as Record<string, unknown>;\n }\n\n // Resolve sub-element recipes\n const keys = Object.keys(result);\n\n for (const key of keys) {\n if (!isSelector(key)) continue;\n\n const subStyles = result[key];\n\n if (\n !subStyles ||\n typeof subStyles !== 'object' ||\n Array.isArray(subStyles)\n ) {\n continue;\n }\n\n const subRecord = subStyles as Record<string, unknown>;\n\n if (!('recipe' in subRecord)) continue;\n\n const subResolved = resolveRecipesForLevel(subRecord, recipes);\n\n if (subResolved) {\n if (!changed) {\n // First change in sub-elements -- need to shallow-copy the top level\n changed = true;\n result = { ...(styles as Record<string, unknown>) };\n }\n result[key] = subResolved;\n }\n }\n\n return changed ? (result as Styles) : styles;\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"resolve-recipes.js","names":[],"sources":["../../src/utils/resolve-recipes.ts"],"sourcesContent":["/**\n * Recipe resolution utility.\n *\n * Resolves `recipe` style properties by looking up predefined recipe styles\n * from global configuration and merging them with the component's own styles.\n *\n * Resolution order per level (top-level and each sub-element independently):\n * base_recipe_1 base_recipe_2 → component styles → post_recipe_1 post_recipe_2\n *\n * The `/` separator splits base recipes (before component styles)\n * from post recipes (after component styles). All merges use mergeStyles\n * semantics: primitives and state maps with '' key fully replace;\n * state maps without '' key extend the existing value.\n *\n * Returns the same object reference if no recipes are present (zero overhead).\n */\n\nimport { getGlobalRecipes } from '../config';\nimport { isSelector } from '../pipeline';\nimport type { RecipeStyles, Styles } from '../styles/types';\n\nimport { isDevEnv } from './is-dev-env';\nimport { mergeStyles } from './merge-styles';\n\nconst devMode = isDevEnv();\n\ninterface ParsedRecipeGroups {\n base: string[] | null;\n post: string[] | null;\n}\n\n/**\n * Parse a recipe string into base and post recipe name groups.\n *\n * Syntax: `'base1 base2 / post1 post2'`\n * - Names are space-separated within each group\n * - `/` separates base (before component) from post (after component) groups\n * - `/` is optional; if absent, all names are base\n * - `none` as the sole base value means \"no base recipes\"\n *\n * Returns `{ base: null, post: null }` if the string is empty or invalid.\n */\nfunction parseRecipeNames(value: unknown): ParsedRecipeGroups {\n const empty: ParsedRecipeGroups = { base: null, post: null };\n\n if (typeof value !== 'string') return empty;\n const trimmed = value.trim();\n if (trimmed === '') return empty;\n\n const slashIndex = trimmed.indexOf('/');\n\n if (slashIndex === -1) {\n if (trimmed === 'none') return empty;\n const names = splitNames(trimmed);\n return { base: names, post: null };\n }\n\n const basePart = trimmed.slice(0, slashIndex);\n const postPart = trimmed.slice(slashIndex + 1);\n\n return {\n base: basePart.trim() === 'none' ? null : splitNames(basePart),\n post: splitNames(postPart),\n };\n}\n\nfunction splitNames(s: string): string[] | null {\n const names = s.split(/\\s+/).filter(Boolean);\n return names.length > 0 ? names : null;\n}\n\n/**\n * Collect merged styles for a list of recipe names.\n * Each recipe is flat-spread on top of the previous.\n */\nfunction collectRecipeStyles(\n names: string[],\n recipes: Record<string, RecipeStyles>,\n): Record<string, unknown> {\n let merged: Record<string, unknown> = {};\n\n for (const name of names) {\n const recipeStyles = recipes[name];\n\n if (!recipeStyles) {\n if (devMode) {\n console.warn(\n `[Tasty] Recipe \"${name}\" not found. ` +\n `Make sure it is defined in configure({ recipes: { ... } }).`,\n );\n }\n continue;\n }\n\n merged = { ...merged, ...(recipeStyles as Record<string, unknown>) };\n }\n\n return merged;\n}\n\n/**\n * Resolve recipe references in a flat styles object (no sub-elements).\n * Returns null if no `recipe` key is present.\n *\n * Resolution: base recipes → component styles → post recipes (all via mergeStyles)\n */\nfunction resolveRecipesForLevel(\n styles: Record<string, unknown>,\n recipes: Record<string, RecipeStyles>,\n): Record<string, unknown> | null {\n if (!('recipe' in styles)) return null;\n\n const { base, post } = parseRecipeNames(styles.recipe);\n\n // Separate selector keys (sub-elements) from flat style properties.\n // mergeStyles handles selectors with its own semantics (e.g. false = delete),\n // but at this level we only want recipe merging on flat properties.\n\n const { recipe: _recipe, ...allRest } = styles;\n const flatStyles: Record<string, unknown> = {};\n const selectorStyles: Record<string, unknown> = {};\n\n for (const key of Object.keys(allRest)) {\n if (isSelector(key)) {\n selectorStyles[key] = allRest[key];\n } else {\n flatStyles[key] = allRest[key];\n }\n }\n\n if (!base && !post) {\n return allRest;\n }\n\n // 1. Merge base recipes, then component styles on top (via mergeStyles)\n let result: Record<string, unknown>;\n\n if (base) {\n const baseStyles = collectRecipeStyles(base, recipes);\n result = mergeStyles(baseStyles as Styles, flatStyles as Styles) as Record<\n string,\n unknown\n >;\n } else {\n result = { ...flatStyles };\n }\n\n // 2. Apply post recipes via mergeStyles (state map extend semantics)\n if (post) {\n const postStyles = collectRecipeStyles(post, recipes);\n result = mergeStyles(result as Styles, postStyles as Styles) as Record<\n string,\n unknown\n >;\n }\n\n // Re-attach selector keys unchanged\n for (const key of Object.keys(selectorStyles)) {\n result[key] = selectorStyles[key];\n }\n\n return result;\n}\n\n/**\n * Resolve all `recipe` style properties in a styles object.\n *\n * Handles both top-level and sub-element recipe references.\n * Returns the same object reference if no recipes are present anywhere\n * (zero overhead for the common case).\n *\n * @param styles - The styles object potentially containing `recipe` keys\n * @returns Resolved styles with recipe values merged in, or the original object if unchanged\n */\nexport function resolveRecipes(styles: Styles): Styles {\n const recipes = getGlobalRecipes();\n\n // Fast path: no recipes configured globally\n if (!recipes) return styles;\n\n let changed = false;\n\n // Resolve top-level recipe\n const topResolved = resolveRecipesForLevel(\n styles as Record<string, unknown>,\n recipes,\n );\n\n let result: Record<string, unknown>;\n\n if (topResolved) {\n changed = true;\n result = topResolved;\n } else {\n // Keep reference; a shallow copy is deferred until a sub-element actually changes\n result = styles as Record<string, unknown>;\n }\n\n // Resolve sub-element recipes\n const keys = Object.keys(result);\n\n for (const key of keys) {\n if (!isSelector(key)) continue;\n\n const subStyles = result[key];\n\n if (\n !subStyles ||\n typeof subStyles !== 'object' ||\n Array.isArray(subStyles)\n ) {\n continue;\n }\n\n const subRecord = subStyles as Record<string, unknown>;\n\n if (!('recipe' in subRecord)) continue;\n\n const subResolved = resolveRecipesForLevel(subRecord, recipes);\n\n if (subResolved) {\n if (!changed) {\n // First change in sub-elements -- need to shallow-copy the top level\n changed = true;\n result = { ...(styles as Record<string, unknown>) };\n }\n result[key] = subResolved;\n }\n }\n\n return changed ? (result as Styles) : styles;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAwBA,MAAM,UAAU,UAAU;;;;;;;;;;;;AAkB1B,SAAS,iBAAiB,OAAoC;CAC5D,MAAM,QAA4B;EAAE,MAAM;EAAM,MAAM;EAAM;AAE5D,KAAI,OAAO,UAAU,SAAU,QAAO;CACtC,MAAM,UAAU,MAAM,MAAM;AAC5B,KAAI,YAAY,GAAI,QAAO;CAE3B,MAAM,aAAa,QAAQ,QAAQ,IAAI;AAEvC,KAAI,eAAe,IAAI;AACrB,MAAI,YAAY,OAAQ,QAAO;AAE/B,SAAO;GAAE,MADK,WAAW,QAAQ;GACX,MAAM;GAAM;;CAGpC,MAAM,WAAW,QAAQ,MAAM,GAAG,WAAW;CAC7C,MAAM,WAAW,QAAQ,MAAM,aAAa,EAAE;AAE9C,QAAO;EACL,MAAM,SAAS,MAAM,KAAK,SAAS,OAAO,WAAW,SAAS;EAC9D,MAAM,WAAW,SAAS;EAC3B;;AAGH,SAAS,WAAW,GAA4B;CAC9C,MAAM,QAAQ,EAAE,MAAM,MAAM,CAAC,OAAO,QAAQ;AAC5C,QAAO,MAAM,SAAS,IAAI,QAAQ;;;;;;AAOpC,SAAS,oBACP,OACA,SACyB;CACzB,IAAI,SAAkC,EAAE;AAExC,MAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,eAAe,QAAQ;AAE7B,MAAI,CAAC,cAAc;AACjB,OAAI,QACF,SAAQ,KACN,mBAAmB,KAAK,0EAEzB;AAEH;;AAGF,WAAS;GAAE,GAAG;GAAQ,GAAI;GAA0C;;AAGtE,QAAO;;;;;;;;AAST,SAAS,uBACP,QACA,SACgC;AAChC,KAAI,EAAE,YAAY,QAAS,QAAO;CAElC,MAAM,EAAE,MAAM,SAAS,iBAAiB,OAAO,OAAO;CAMtD,MAAM,EAAE,QAAQ,SAAS,GAAG,YAAY;CACxC,MAAM,aAAsC,EAAE;CAC9C,MAAM,iBAA0C,EAAE;AAElD,MAAK,MAAM,OAAO,OAAO,KAAK,QAAQ,CACpC,KAAI,WAAW,IAAI,CACjB,gBAAe,OAAO,QAAQ;KAE9B,YAAW,OAAO,QAAQ;AAI9B,KAAI,CAAC,QAAQ,CAAC,KACZ,QAAO;CAIT,IAAI;AAEJ,KAAI,KAEF,UAAS,YADU,oBAAoB,MAAM,QAAQ,EACV,WAAqB;KAKhE,UAAS,EAAE,GAAG,YAAY;AAI5B,KAAI,MAAM;EACR,MAAM,aAAa,oBAAoB,MAAM,QAAQ;AACrD,WAAS,YAAY,QAAkB,WAAqB;;AAO9D,MAAK,MAAM,OAAO,OAAO,KAAK,eAAe,CAC3C,QAAO,OAAO,eAAe;AAG/B,QAAO;;;;;;;;;;;;AAaT,SAAgB,eAAe,QAAwB;CACrD,MAAM,UAAU,kBAAkB;AAGlC,KAAI,CAAC,QAAS,QAAO;CAErB,IAAI,UAAU;CAGd,MAAM,cAAc,uBAClB,QACA,QACD;CAED,IAAI;AAEJ,KAAI,aAAa;AACf,YAAU;AACV,WAAS;OAGT,UAAS;CAIX,MAAM,OAAO,OAAO,KAAK,OAAO;AAEhC,MAAK,MAAM,OAAO,MAAM;AACtB,MAAI,CAAC,WAAW,IAAI,CAAE;EAEtB,MAAM,YAAY,OAAO;AAEzB,MACE,CAAC,aACD,OAAO,cAAc,YACrB,MAAM,QAAQ,UAAU,CAExB;EAGF,MAAM,YAAY;AAElB,MAAI,EAAE,YAAY,WAAY;EAE9B,MAAM,cAAc,uBAAuB,WAAW,QAAQ;AAE9D,MAAI,aAAa;AACf,OAAI,CAAC,SAAS;AAEZ,cAAU;AACV,aAAS,EAAE,GAAI,QAAoC;;AAErD,UAAO,OAAO;;;AAIlB,QAAO,UAAW,SAAoB"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
//#region src/utils/selector-transform.ts
|
|
2
|
+
/**
|
|
3
|
+
* Shared utility for transforming capitalized PascalCase element names
|
|
4
|
+
* in CSS selector content to `[data-element="..."]` attribute selectors.
|
|
5
|
+
*
|
|
6
|
+
* Lowercase words are treated as HTML tags and left unchanged.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Matches a capitalized PascalCase word at the start of the string
|
|
10
|
+
* or after a CSS combinator/separator character.
|
|
11
|
+
*/
|
|
12
|
+
const ELEMENT_NAME_RE = /(^|[\s>+~,(])([A-Z][a-zA-Z0-9]*)/g;
|
|
13
|
+
/**
|
|
14
|
+
* Replace capitalized PascalCase words with `[data-element="Name"]` selectors.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* transformSelectorContent('> Field + input:checked')
|
|
18
|
+
* // → '> [data-element="Field"] + input:checked'
|
|
19
|
+
*
|
|
20
|
+
* transformSelectorContent('Body > Row')
|
|
21
|
+
* // → '[data-element="Body"] > [data-element="Row"]'
|
|
22
|
+
*
|
|
23
|
+
* transformSelectorContent('button')
|
|
24
|
+
* // → 'button' (lowercase = HTML tag, unchanged)
|
|
25
|
+
*/
|
|
26
|
+
function transformSelectorContent(content) {
|
|
27
|
+
return content.replace(ELEMENT_NAME_RE, (_, prefix, name) => `${prefix}[data-element="${name}"]`);
|
|
28
|
+
}
|
|
29
|
+
//#endregion
|
|
30
|
+
export { transformSelectorContent };
|
|
31
|
+
|
|
32
|
+
//# sourceMappingURL=selector-transform.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selector-transform.js","names":[],"sources":["../../src/utils/selector-transform.ts"],"sourcesContent":["/**\n * Shared utility for transforming capitalized PascalCase element names\n * in CSS selector content to `[data-element=\"...\"]` attribute selectors.\n *\n * Lowercase words are treated as HTML tags and left unchanged.\n */\n\n/**\n * Matches a capitalized PascalCase word at the start of the string\n * or after a CSS combinator/separator character.\n */\nconst ELEMENT_NAME_RE = /(^|[\\s>+~,(])([A-Z][a-zA-Z0-9]*)/g;\n\n/**\n * Replace capitalized PascalCase words with `[data-element=\"Name\"]` selectors.\n *\n * @example\n * transformSelectorContent('> Field + input:checked')\n * // → '> [data-element=\"Field\"] + input:checked'\n *\n * transformSelectorContent('Body > Row')\n * // → '[data-element=\"Body\"] > [data-element=\"Row\"]'\n *\n * transformSelectorContent('button')\n * // → 'button' (lowercase = HTML tag, unchanged)\n */\nexport function transformSelectorContent(content: string): string {\n return content.replace(\n ELEMENT_NAME_RE,\n (_, prefix, name) => `${prefix}[data-element=\"${name}\"]`,\n );\n}\n"],"mappings":";;;;;;;;;;;AAWA,MAAM,kBAAkB;;;;;;;;;;;;;;AAexB,SAAgB,yBAAyB,SAAyB;AAChE,QAAO,QAAQ,QACb,kBACC,GAAG,QAAQ,SAAS,GAAG,OAAO,iBAAiB,KAAK,IACtD"}
|
package/dist/utils/string.js
CHANGED
package/dist/utils/styles.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { ProcessedStyle, StyleDetails } from "../parser/types.js";
|
|
2
2
|
import { StyleParser } from "../parser/parser.js";
|
|
3
|
-
import {
|
|
4
|
-
import { Styles } from "../styles/types.js";
|
|
3
|
+
import { getNamedColorHex, getRgbValuesFromRgbaString, hexToRgb, strToRgb } from "./color-math.js";
|
|
5
4
|
|
|
6
5
|
//#region src/utils/styles.d.ts
|
|
7
6
|
type StyleValue<T = string> = T | boolean | number | null | undefined;
|
|
@@ -21,11 +20,10 @@ type StyleValueStateMap<T = string> = Record<string, StyleValue<T> | '@inherit'>
|
|
|
21
20
|
* Use this for component props that accept style values.
|
|
22
21
|
*/
|
|
23
22
|
type StylePropValue<T = string> = StyleValue<T> | StyleValueStateMap<T>;
|
|
24
|
-
type ComputeModel = string | number;
|
|
25
23
|
type CSSMap = {
|
|
26
24
|
$?: string | string[];
|
|
27
25
|
} & Record<string, string | string[]>;
|
|
28
|
-
type StyleHandlerResult = CSSMap | CSSMap[] | void;
|
|
26
|
+
type StyleHandlerResult = CSSMap | CSSMap[] | null | void;
|
|
29
27
|
type RawStyleHandler = (value: StyleValueStateMap) => StyleHandlerResult;
|
|
30
28
|
type StyleHandler = RawStyleHandler & {
|
|
31
29
|
__lookupStyles: string[];
|
|
@@ -37,44 +35,21 @@ type StyleHandler = RawStyleHandler & {
|
|
|
37
35
|
* - Multi-property tuple: [['style1', 'style2'], handler]
|
|
38
36
|
*/
|
|
39
37
|
type StyleHandlerDefinition = RawStyleHandler | [string, RawStyleHandler] | [string[], RawStyleHandler];
|
|
40
|
-
interface StyleStateData {
|
|
41
|
-
model?: ComputeModel;
|
|
42
|
-
tokens?: string[];
|
|
43
|
-
value: StyleValue | StyleValueStateMap | StyleStateData;
|
|
44
|
-
/** The list of mods to apply */
|
|
45
|
-
mods: string[];
|
|
46
|
-
/** The list of **not** mods to apply (e.g. `:not(:hover)`) */
|
|
47
|
-
notMods: string[];
|
|
48
|
-
/** Advanced states (media queries, container queries, etc.) */
|
|
49
|
-
advancedStates?: ParsedAdvancedState[];
|
|
50
|
-
/** At-rule context for CSS generation */
|
|
51
|
-
atRuleContext?: AtRuleContext;
|
|
52
|
-
/** Own mods for sub-element states (from @own()) - applied to sub-element selector */
|
|
53
|
-
ownMods?: string[];
|
|
54
|
-
/** Negated own mods for sub-element states */
|
|
55
|
-
negatedOwnMods?: string[];
|
|
56
|
-
}
|
|
57
38
|
interface ParsedColor {
|
|
58
39
|
color?: string;
|
|
59
40
|
name?: string;
|
|
60
41
|
opacity?: number;
|
|
61
42
|
}
|
|
62
|
-
type StyleStateDataList = StyleStateData[];
|
|
63
|
-
type StyleStateDataListMap = Record<string, StyleStateDataList>;
|
|
64
43
|
type StyleMap = Record<string, StyleValue | StyleValueStateMap>;
|
|
65
|
-
type StyleStateMap = Record<string, StyleStateData>;
|
|
66
44
|
declare const CUSTOM_UNITS: {
|
|
67
45
|
r: string;
|
|
68
46
|
cr: string;
|
|
69
47
|
bw: string;
|
|
70
48
|
ow: string;
|
|
71
49
|
x: string;
|
|
72
|
-
fs: string;
|
|
73
|
-
lh: string;
|
|
74
50
|
sf: (num: number) => string;
|
|
75
51
|
};
|
|
76
52
|
declare const DIRECTIONS: string[];
|
|
77
|
-
declare function getModSelector(modName: string): string;
|
|
78
53
|
declare function customFunc(name: string, fn: (groups: StyleDetails[]) => string): void;
|
|
79
54
|
/**
|
|
80
55
|
* Get the global StyleParser instance.
|
|
@@ -117,62 +92,8 @@ declare function parseStyle(value: StyleValue): ProcessedStyle;
|
|
|
117
92
|
* Optimized to avoid heavy parseStyle calls for simple color patterns.
|
|
118
93
|
*/
|
|
119
94
|
declare function parseColor(val: string, ignoreError?: boolean): ParsedColor;
|
|
120
|
-
declare function strToRgb(color: string, _ignoreAlpha?: boolean): string | null | undefined;
|
|
121
|
-
/**
|
|
122
|
-
* Extract RGB values from an rgb()/rgba() string.
|
|
123
|
-
* Supports all modern CSS syntax variations:
|
|
124
|
-
* - Comma-separated: rgb(255, 128, 0)
|
|
125
|
-
* - Space-separated: rgb(255 128 0)
|
|
126
|
-
* - Fractional: rgb(128.5, 64.3, 32.1)
|
|
127
|
-
* - Percentages: rgb(50%, 25%, 75%)
|
|
128
|
-
* - Slash alpha notation: rgb(255 128 0 / 0.5)
|
|
129
|
-
*
|
|
130
|
-
* Returns array of RGB values (0-255 range), converting percentages as needed.
|
|
131
|
-
*/
|
|
132
|
-
declare function getRgbValuesFromRgbaString(str: string): number[];
|
|
133
|
-
declare function hexToRgb(hex: string): string | null;
|
|
134
95
|
declare function filterMods(mods: string[], allowedMods: string[]): string[];
|
|
135
|
-
declare function extendStyles(defaultStyles?: Record<string, unknown> | null, newStyles?: Record<string, unknown> | null): Record<string, unknown>;
|
|
136
|
-
/**
|
|
137
|
-
* Split properties into style and non-style properties.
|
|
138
|
-
* @param props - Component prop map.
|
|
139
|
-
* @param [styleList] - List of all style properties.
|
|
140
|
-
* @param [defaultStyles] - Default style map of the component.
|
|
141
|
-
* @param [propMap] - Props to style alias map.
|
|
142
|
-
* @param [ignoreList] - A list of properties to ignore.
|
|
143
|
-
*/
|
|
144
|
-
declare function extractStyles(props: Record<string, unknown>, styleList?: readonly string[], defaultStyles?: Styles, propMap?: Record<string, string>, ignoreList?: readonly string[]): Styles;
|
|
145
|
-
/**
|
|
146
|
-
* Check if a token is an advanced state (starts with @)
|
|
147
|
-
*/
|
|
148
|
-
declare function isAdvancedStateToken(token: string): boolean;
|
|
149
|
-
declare const STATE_OPERATORS: {
|
|
150
|
-
NOT: string;
|
|
151
|
-
AND: string;
|
|
152
|
-
OR: string;
|
|
153
|
-
XOR: string;
|
|
154
|
-
};
|
|
155
|
-
declare const STATE_OPERATOR_LIST: string[];
|
|
156
|
-
declare const parseStateNotation: (firstArg: string, secondArg?: string | number | boolean | StyleValueStateMap<string> | StyleStateData | null | undefined) => StyleStateData;
|
|
157
|
-
/**
|
|
158
|
-
* Build an AtRuleContext from parsed advanced states
|
|
159
|
-
*/
|
|
160
|
-
declare function buildAtRuleContext(advancedStates: ParsedAdvancedState[], negatedStates: Set<string>): AtRuleContext | undefined;
|
|
161
|
-
/**
|
|
162
|
-
* Parse state notation and return tokens, modifiers and compute model.
|
|
163
|
-
* Enhanced to detect and extract advanced states.
|
|
164
|
-
*/
|
|
165
|
-
declare function styleStateMapToStyleStateDataList(styleStateMap: StyleStateMap | StyleValue | StyleValueStateMap, parserContext?: StateParserContext): {
|
|
166
|
-
states: StyleStateDataList;
|
|
167
|
-
mods: string[];
|
|
168
|
-
hasAdvancedStates: boolean;
|
|
169
|
-
};
|
|
170
|
-
declare const COMPUTE_FUNC_MAP: Record<string, (a: unknown, b?: unknown) => unknown>;
|
|
171
|
-
/**
|
|
172
|
-
* Compute a result based on a model and incoming map.
|
|
173
|
-
*/
|
|
174
|
-
declare function computeState(computeModel: ComputeModel, valueMap: (number | boolean)[] | Record<string, boolean> | ((...args: unknown[]) => unknown)): unknown;
|
|
175
96
|
declare function stringifyStyles(styles: unknown): string;
|
|
176
97
|
//#endregion
|
|
177
|
-
export {
|
|
98
|
+
export { CSSMap, CUSTOM_UNITS, DIRECTIONS, ParsedColor, RawStyleHandler, StyleHandler, StyleHandlerDefinition, StyleHandlerResult, StyleMap, StylePropValue, StyleValue, StyleValueStateMap, customFunc, filterMods, getGlobalFuncs, getGlobalParser, getGlobalPredefinedTokens, normalizeColorTokenValue, parseColor, parseStyle, resetGlobalPredefinedTokens, setGlobalPredefinedTokens, stringifyStyles };
|
|
178
99
|
//# sourceMappingURL=styles.d.ts.map
|