@tenphi/tasty 0.12.0 → 0.13.1
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/chunks/cacheKey.js +16 -8
- package/dist/chunks/cacheKey.js.map +1 -1
- package/dist/chunks/renderChunk.js +31 -32
- package/dist/chunks/renderChunk.js.map +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.js +6 -3
- package/dist/config.js.map +1 -1
- package/dist/core/index.d.ts +3 -3
- package/dist/core/index.js +3 -3
- package/dist/hooks/useStyles.js +4 -3
- package/dist/hooks/useStyles.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -3
- package/dist/pipeline/index.d.ts +1 -1
- package/dist/pipeline/index.js +24 -14
- package/dist/pipeline/index.js.map +1 -1
- package/dist/pipeline/materialize.js +328 -79
- package/dist/pipeline/materialize.js.map +1 -1
- package/dist/pipeline/parseStateKey.d.ts +1 -1
- package/dist/pipeline/parseStateKey.js +2 -6
- package/dist/pipeline/parseStateKey.js.map +1 -1
- package/dist/states/index.js +10 -257
- package/dist/states/index.js.map +1 -1
- package/dist/tasty.d.ts +58 -58
- package/dist/tasty.js +23 -10
- package/dist/tasty.js.map +1 -1
- package/dist/utils/cache-wrapper.js +4 -8
- package/dist/utils/cache-wrapper.js.map +1 -1
- package/dist/utils/has-keys.js +13 -0
- package/dist/utils/has-keys.js.map +1 -0
- package/dist/utils/mod-attrs.js +1 -1
- package/dist/utils/styles.d.ts +1 -64
- package/dist/utils/styles.js +7 -319
- package/dist/utils/styles.js.map +1 -1
- package/dist/zero/babel.d.ts +8 -0
- package/dist/zero/babel.js +18 -3
- package/dist/zero/babel.js.map +1 -1
- package/dist/zero/next.js +14 -1
- package/dist/zero/next.js.map +1 -1
- package/docs/tasty-static.md +6 -7
- package/package.json +1 -1
package/dist/tasty.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tasty.js","names":["modAttrs"],"sources":["../src/tasty.tsx"],"sourcesContent":["import type {\n AllHTMLAttributes,\n ComponentType,\n ForwardRefExoticComponent,\n JSX,\n PropsWithoutRef,\n RefAttributes,\n} from 'react';\nimport { createElement, forwardRef, useMemo } from 'react';\nimport { useStyles } from './hooks/useStyles';\nimport { BASE_STYLES } from './styles/list';\nimport type { Styles, StylesInterface } from './styles/types';\nimport type {\n AllBaseProps,\n BaseProps,\n BaseStyleProps,\n Mods,\n Props,\n Tokens,\n} from './types';\nimport { getDisplayName } from './utils/get-display-name';\nimport { isValidElementType } from './utils/is-valid-element-type';\nimport { mergeStyles } from './utils/merge-styles';\nimport { isSelector } from './pipeline';\nimport { modAttrs } from './utils/mod-attrs';\nimport { processTokens, stringifyTokens } from './utils/process-tokens';\n\nimport type { StyleValue, StyleValueStateMap } from './utils/styles';\n\n/**\n * Mapping of is* properties to their corresponding HTML attributes\n */\nconst IS_PROPERTIES_MAP = {\n isDisabled: 'disabled',\n isHidden: 'hidden',\n isChecked: 'checked',\n} as const;\n\n/**\n * Precalculated entries for performance optimization\n */\nconst IS_PROPERTIES_ENTRIES = Object.entries(IS_PROPERTIES_MAP);\n\n/**\n * Helper function to handle is* properties consistently\n * Transforms is* props to HTML attributes and adds corresponding data-* attributes\n */\nfunction handleIsProperties(props: Record<string, unknown>) {\n for (const [isProperty, targetAttribute] of IS_PROPERTIES_ENTRIES) {\n if (isProperty in props) {\n props[targetAttribute] = props[isProperty];\n delete props[isProperty];\n }\n\n // Add data-* attribute if target attribute is truthy and doesn't already exist\n const dataAttribute = `data-${targetAttribute}`;\n if (!(dataAttribute in props) && props[targetAttribute]) {\n props[dataAttribute] = '';\n }\n }\n}\n\n/**\n * Creates a sub-element component for compound component patterns.\n * Sub-elements are lightweight components with data-element attribute for CSS targeting.\n */\nfunction createSubElement<Tag extends keyof JSX.IntrinsicElements>(\n elementName: string,\n definition: SubElementDefinition<Tag>,\n): ForwardRefExoticComponent<\n PropsWithoutRef<SubElementProps<Tag>> & RefAttributes<unknown>\n> {\n // Normalize definition to object form\n const config =\n typeof definition === 'string'\n ? { as: definition as Tag }\n : (definition as { as?: Tag; qa?: string; qaVal?: string | number });\n\n const tag = config.as ?? ('div' as Tag);\n const defaultQa = config.qa;\n const defaultQaVal = config.qaVal;\n\n const SubElement = forwardRef<unknown, SubElementProps<Tag>>((props, ref) => {\n const {\n qa,\n qaVal,\n mods,\n tokens,\n isDisabled,\n isHidden,\n isChecked,\n className,\n style,\n ...htmlProps\n } = props as SubElementProps<Tag> & {\n className?: string;\n style?: Record<string, unknown>;\n };\n\n // Build mod attributes\n let modProps: Record<string, unknown> | undefined;\n if (mods) {\n modProps = modAttrs(mods as Mods) as Record<string, unknown>;\n }\n\n // Process tokens into inline style properties\n const tokenStyle = tokens\n ? (processTokens(tokens) as Record<string, unknown>)\n : undefined;\n\n // Merge token styles with explicit style prop (style has priority)\n let mergedStyle: Record<string, unknown> | undefined;\n if (tokenStyle || style) {\n mergedStyle =\n tokenStyle && style\n ? { ...tokenStyle, ...style }\n : ((tokenStyle ?? style) as Record<string, unknown>);\n }\n\n const elementProps = {\n 'data-element': elementName,\n 'data-qa': qa ?? defaultQa,\n 'data-qaval': qaVal ?? defaultQaVal,\n ...(modProps || {}),\n ...htmlProps,\n className,\n style: mergedStyle,\n isDisabled,\n isHidden,\n isChecked,\n ref,\n } as Record<string, unknown>;\n\n // Handle is* properties (isDisabled -> disabled + data-disabled, etc.)\n handleIsProperties(elementProps);\n\n // Clean up undefined data attributes\n if (elementProps['data-qa'] === undefined) delete elementProps['data-qa'];\n if (elementProps['data-qaval'] === undefined)\n delete elementProps['data-qaval'];\n\n return createElement(tag, elementProps);\n });\n\n SubElement.displayName = `SubElement(${elementName})`;\n\n return SubElement as ForwardRefExoticComponent<\n PropsWithoutRef<SubElementProps<Tag>> & RefAttributes<unknown>\n >;\n}\n\ntype StyleList = readonly (keyof {\n [key in keyof StylesInterface]: StylesInterface[key];\n})[];\n\nexport type PropsWithStyles = {\n styles?: Styles;\n} & Omit<Props, 'styles'>;\n\nexport type VariantMap = Record<string, Styles>;\n\nexport interface WithVariant<V extends VariantMap> {\n variant?: keyof V;\n}\n\n// ============================================================================\n// Sub-element types for compound components\n// ============================================================================\n\n/**\n * Definition for a sub-element. Can be either:\n * - A tag name string (e.g., 'div', 'span')\n * - An object with configuration options\n */\nexport type SubElementDefinition<\n Tag extends keyof JSX.IntrinsicElements = 'div',\n> =\n | Tag\n | {\n as?: Tag;\n qa?: string;\n qaVal?: string | number;\n };\n\n/**\n * Map of sub-element definitions.\n * Keys become the sub-component names (e.g., { Icon: 'span' } -> Component.Icon)\n */\nexport type ElementsDefinition = Record<\n string,\n SubElementDefinition<keyof JSX.IntrinsicElements>\n>;\n\n/**\n * Resolves the tag from a SubElementDefinition\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype ResolveElementTag<T extends SubElementDefinition<any>> = T extends string\n ? T\n : T extends { as?: infer Tag }\n ? Tag extends keyof JSX.IntrinsicElements\n ? Tag\n : 'div'\n : 'div';\n\n/**\n * Props for sub-element components.\n * Combines HTML attributes with tasty-specific props (qa, qaVal, mods, tokens, isDisabled, etc.)\n */\nexport type SubElementProps<Tag extends keyof JSX.IntrinsicElements = 'div'> =\n Omit<\n JSX.IntrinsicElements[Tag],\n 'ref' | 'color' | 'content' | 'translate'\n > & {\n qa?: string;\n qaVal?: string | number;\n mods?: Mods;\n tokens?: Tokens;\n isDisabled?: boolean;\n isHidden?: boolean;\n isChecked?: boolean;\n };\n\n/**\n * Generates the sub-element component types from an ElementsDefinition\n */\ntype SubElementComponents<E extends ElementsDefinition> = {\n [K in keyof E]: ForwardRefExoticComponent<\n PropsWithoutRef<SubElementProps<ResolveElementTag<E[K]>>> &\n RefAttributes<\n ResolveElementTag<E[K]> extends keyof HTMLElementTagNameMap\n ? HTMLElementTagNameMap[ResolveElementTag<E[K]>]\n : Element\n >\n >;\n};\n\n/**\n * Base type containing common properties shared between TastyProps and TastyElementOptions.\n * Separated to avoid code duplication while allowing different type constraints.\n */\ntype TastyBaseProps<\n K extends StyleList,\n V extends VariantMap,\n E extends ElementsDefinition = Record<string, never>,\n> = {\n /** Default styles of the element. */\n styles?: Styles;\n /** The list of styles that can be provided by props */\n styleProps?: K;\n element?: BaseProps['element'];\n variants?: V;\n /** Default tokens for inline CSS custom properties */\n tokens?: Tokens;\n /** Sub-element definitions for compound components */\n elements?: E;\n} & Pick<BaseProps, 'qa' | 'qaVal'> &\n WithVariant<V>;\n\nexport type TastyProps<\n K extends StyleList,\n V extends VariantMap,\n E extends ElementsDefinition = Record<string, never>,\n DefaultProps = Props,\n> = TastyBaseProps<K, V, E> & {\n /** The tag name of the element or a React component. */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n as?: string | ComponentType<any>;\n} & Partial<Omit<DefaultProps, 'as' | 'styles' | 'styleProps' | 'tokens'>>;\n\n/**\n * TastyElementOptions is used for the element-creation overload of tasty().\n * It includes a Tag generic that allows TypeScript to infer the correct\n * HTML element type from the `as` prop.\n *\n * Note: Uses a separate index signature with `unknown` instead of inheriting\n * from Props (which has `any`) to ensure strict type checking for styles.\n */\nexport type TastyElementOptions<\n K extends StyleList,\n V extends VariantMap,\n E extends ElementsDefinition = Record<string, never>,\n Tag extends keyof JSX.IntrinsicElements = 'div',\n> = TastyBaseProps<K, V, E> & {\n /** The tag name of the element or a React component. */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n as?: Tag | ComponentType<any>;\n} & Record<string, unknown>;\n\nexport type AllBasePropsWithMods<K extends StyleList> = AllBaseProps & {\n [key in K[number]]?:\n | StyleValue<StylesInterface[key]>\n | StyleValueStateMap<StylesInterface[key]>;\n} & BaseStyleProps;\n\n/**\n * Keys from BasePropsWithoutChildren that should be omitted from HTML attributes.\n * This excludes event handlers so they can be properly typed from JSX.IntrinsicElements.\n */\ntype TastySpecificKeys =\n | 'as'\n | 'qa'\n | 'qaVal'\n | 'element'\n | 'styles'\n | 'breakpoints'\n | 'block'\n | 'inline'\n | 'mods'\n | 'isHidden'\n | 'isDisabled'\n | 'css'\n | 'style'\n | 'theme'\n | 'tokens'\n | 'ref'\n | 'color';\n\n/**\n * Props type for tasty elements that combines:\n * - AllBasePropsWithMods for style props with strict tokens type\n * - HTML attributes for flexibility (properly typed based on tag)\n * - Variant support\n *\n * Uses AllHTMLAttributes as base for common attributes (like disabled),\n * but overrides event handlers with tag-specific types from JSX.IntrinsicElements.\n */\nexport type TastyElementProps<\n K extends StyleList,\n V extends VariantMap,\n Tag extends keyof JSX.IntrinsicElements = 'div',\n> = AllBasePropsWithMods<K> &\n WithVariant<V> &\n Omit<\n Omit<AllHTMLAttributes<HTMLElement>, keyof JSX.IntrinsicElements[Tag]> &\n JSX.IntrinsicElements[Tag],\n TastySpecificKeys | K[number]\n >;\n\ntype TastyComponentPropsWithDefaults<\n Props extends PropsWithStyles,\n DefaultProps extends Partial<Props>,\n> = keyof DefaultProps extends never\n ? Props\n : {\n [key in Extract<keyof Props, keyof DefaultProps>]?: Props[key];\n } & {\n [key in keyof Omit<Props, keyof DefaultProps>]: Props[key];\n };\n\nexport function tasty<\n K extends StyleList,\n V extends VariantMap,\n E extends ElementsDefinition = Record<string, never>,\n Tag extends keyof JSX.IntrinsicElements = 'div',\n>(\n options: TastyElementOptions<K, V, E, Tag>,\n secondArg?: never,\n): ForwardRefExoticComponent<\n PropsWithoutRef<TastyElementProps<K, V, Tag>> & RefAttributes<unknown>\n> &\n SubElementComponents<E>;\nexport function tasty<\n Props extends PropsWithStyles,\n DefaultProps extends Partial<Props> = Partial<Props>,\n>(\n Component: ComponentType<Props>,\n options?: TastyProps<never, never, Record<string, never>, Props>,\n): ComponentType<TastyComponentPropsWithDefaults<Props, DefaultProps>>;\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n// Implementation\nexport function tasty<\n K extends StyleList,\n V extends VariantMap,\n _C = Record<string, unknown>,\n>(Component: any, options?: any) {\n if (isValidElementType(Component)) {\n return tastyWrap(Component as ComponentType<any>, options);\n }\n\n return tastyElement(Component as TastyProps<K, V>);\n}\n\nfunction tastyWrap<\n P extends PropsWithStyles,\n DefaultProps extends Partial<P> = Partial<P>,\n>(\n Component: ComponentType<P>,\n options?: TastyProps<never, never, P>,\n): ComponentType<TastyComponentPropsWithDefaults<P, DefaultProps>> {\n const {\n as: extendTag,\n element: extendElement,\n ...defaultProps\n } = (options ?? {}) as TastyProps<never, never, P>;\n\n const propsWithStyles = ['styles'].concat(\n Object.keys(defaultProps).filter((prop) => prop.endsWith('Styles')),\n );\n\n const _WrappedComponent = forwardRef<any, any>((props, ref) => {\n const { as, element, ...restProps } = props as Record<string, unknown>;\n const propsWithStylesValues = propsWithStyles.map(\n (prop) => (props as any)[prop],\n );\n\n const mergedStylesMap: Styles | undefined = useMemo(() => {\n return propsWithStyles.reduce((map, prop) => {\n const restValue = (restProps as any)[prop];\n const defaultValue = (defaultProps as any)[prop];\n\n if (restValue != null && defaultValue != null) {\n (map as any)[prop] = mergeStyles(defaultValue, restValue);\n } else {\n (map as any)[prop] = restValue ?? defaultValue;\n }\n\n return map;\n }, {} as Styles);\n }, [propsWithStylesValues]);\n\n const elementProps = {\n ...(defaultProps as unknown as Record<string, unknown>),\n ...(restProps as unknown as Record<string, unknown>),\n ...(mergedStylesMap as unknown as Record<string, unknown>),\n as: (as as string | undefined) ?? extendTag,\n element: (element as string | undefined) || extendElement,\n ref,\n } as unknown as P;\n\n return createElement(Component as ComponentType<P>, elementProps);\n });\n\n _WrappedComponent.displayName = `TastyWrappedComponent(${getDisplayName(\n Component,\n (defaultProps as any).qa ?? (extendTag as any) ?? 'Anonymous',\n )})`;\n\n return _WrappedComponent as unknown as ComponentType<\n TastyComponentPropsWithDefaults<P, DefaultProps>\n >;\n}\n\nfunction tastyElement<\n K extends StyleList,\n V extends VariantMap,\n E extends ElementsDefinition,\n>(tastyOptions: TastyProps<K, V, E>) {\n const {\n as: originalAs = 'div',\n element: defaultElement,\n styles: defaultStyles,\n styleProps,\n variants,\n tokens: defaultTokens,\n elements,\n ...defaultProps\n } = tastyOptions;\n\n // Pre-compute merged styles for each variant (if variants are defined)\n // This avoids creating separate component instances per variant\n let variantStylesMap: Record<string, Styles | undefined> | undefined;\n if (variants) {\n // Split defaultStyles: extend-mode state maps (no '' key, non-selector)\n // are pulled out and applied AFTER variant merge so they survive\n // replace-mode maps in variants.\n let baseStyles = defaultStyles;\n let extensionStyles: Styles | undefined;\n\n if (defaultStyles) {\n for (const key of Object.keys(defaultStyles)) {\n if (isSelector(key)) continue;\n\n const value = (defaultStyles as Record<string, unknown>)[key];\n\n if (\n typeof value === 'object' &&\n value !== null &&\n !Array.isArray(value) &&\n !('' in value)\n ) {\n if (!extensionStyles) {\n baseStyles = { ...defaultStyles } as Styles;\n extensionStyles = {} as Styles;\n }\n (extensionStyles as Record<string, unknown>)[key] = value;\n delete (baseStyles as Record<string, unknown>)[key];\n }\n }\n }\n\n const variantEntries = Object.entries(variants) as [string, Styles][];\n variantStylesMap = variantEntries.reduce(\n (map, [variant, variantStyles]) => {\n map[variant] = extensionStyles\n ? mergeStyles(baseStyles, variantStyles, extensionStyles)\n : mergeStyles(baseStyles, variantStyles);\n return map;\n },\n {} as Record<string, Styles | undefined>,\n );\n // Ensure 'default' variant always exists\n if (!variantStylesMap['default']) {\n variantStylesMap['default'] = defaultStyles;\n }\n }\n\n const {\n qa: defaultQa,\n qaVal: defaultQaVal,\n ...otherDefaultProps\n } = defaultProps ?? {};\n\n const _TastyComponent = forwardRef<\n unknown,\n AllBasePropsWithMods<K> & WithVariant<V>\n >((allProps, ref) => {\n const {\n as,\n styles: rawStyles,\n variant,\n mods,\n element,\n qa,\n qaVal,\n className: userClassName,\n tokens,\n style,\n ...otherProps\n } = allProps as Record<string, unknown> as AllBasePropsWithMods<K> &\n WithVariant<V> & {\n className?: string;\n tokens?: Tokens;\n style?: Record<string, unknown>;\n };\n\n let styles = rawStyles;\n\n // Optimize propStyles extraction - avoid creating empty objects\n let propStyles: Styles | null = null;\n const propsToCheck = styleProps\n ? (styleProps as StyleList).concat(BASE_STYLES)\n : BASE_STYLES;\n\n for (const prop of propsToCheck) {\n const key = prop as unknown as string;\n\n if (!propStyles) propStyles = {};\n\n if (key in otherProps) {\n (propStyles as any)[key] = (otherProps as any)[key];\n delete (otherProps as any)[key];\n }\n }\n\n if (\n !styles ||\n (styles && Object.keys(styles as Record<string, unknown>).length === 0)\n ) {\n styles = undefined as unknown as Styles;\n }\n\n // Determine base styles: use variant styles if available, otherwise default styles\n const baseStyles = variantStylesMap\n ? (variantStylesMap[(variant as string) || 'default'] ??\n variantStylesMap['default'])\n : defaultStyles;\n\n // Merge base styles with instance styles and prop styles\n const allStyles = useMemo(() => {\n const hasStyles =\n styles && Object.keys(styles as Record<string, unknown>).length > 0;\n const hasPropStyles = propStyles && Object.keys(propStyles).length > 0;\n\n if (!hasStyles && !hasPropStyles) {\n return baseStyles;\n }\n\n return mergeStyles(baseStyles, styles as Styles, propStyles as Styles);\n }, [baseStyles, styles, propStyles]);\n\n // Use the useStyles hook for style generation and injection\n const { className: stylesClassName } = useStyles(allStyles);\n\n // Merge default tokens with instance tokens (instance overrides defaults)\n const tokensKey = stringifyTokens(tokens as Tokens | undefined);\n const mergedTokens = useMemo(() => {\n if (!defaultTokens && !tokens) return undefined;\n if (!defaultTokens) return tokens as Tokens;\n if (!tokens) return defaultTokens;\n return { ...defaultTokens, ...tokens } as Tokens;\n }, [tokensKey]);\n\n // Process merged tokens into inline style properties\n const processedTokenStyle = useMemo(() => {\n return processTokens(mergedTokens);\n }, [mergedTokens]);\n\n // Merge processed tokens with explicit style prop (style has priority)\n const mergedStyle = useMemo(() => {\n if (!processedTokenStyle && !style) return undefined;\n if (!processedTokenStyle) return style;\n if (!style) return processedTokenStyle;\n return { ...processedTokenStyle, ...style };\n }, [processedTokenStyle, style]);\n\n let modProps: Record<string, unknown> | undefined;\n if (mods) {\n const modsObject = mods as unknown as Record<string, unknown>;\n modProps = modAttrs(modsObject as any) as Record<string, unknown>;\n }\n\n // Merge user className with generated className\n const finalClassName = [(userClassName as string) || '', stylesClassName]\n .filter(Boolean)\n .join(' ');\n\n const elementProps = {\n 'data-element': (element as string | undefined) || defaultElement,\n 'data-qa': (qa as string | undefined) || defaultQa,\n 'data-qaval': (qaVal as string | undefined) || defaultQaVal,\n ...(otherDefaultProps as unknown as Record<string, unknown>),\n ...(modProps || {}),\n ...(otherProps as unknown as Record<string, unknown>),\n className: finalClassName,\n style: mergedStyle,\n ref,\n } as Record<string, unknown>;\n\n // Apply the helper to handle is* properties\n handleIsProperties(elementProps);\n\n const renderedElement = createElement(\n (as as string | 'div') ?? originalAs,\n elementProps,\n );\n\n return renderedElement;\n });\n\n _TastyComponent.displayName = `TastyComponent(${\n (defaultProps as any).qa || originalAs\n })`;\n\n // Attach sub-element components if elements are defined\n if (elements) {\n const subElements = Object.entries(elements).reduce(\n (acc, [name, definition]) => {\n acc[name] = createSubElement(\n name,\n definition as SubElementDefinition<keyof JSX.IntrinsicElements>,\n );\n return acc;\n },\n {} as Record<string, ForwardRefExoticComponent<any>>,\n );\n\n return Object.assign(_TastyComponent, subElements);\n }\n\n return _TastyComponent;\n}\n\nexport const Element = tasty({});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"tasty.js","names":["modAttrs"],"sources":["../src/tasty.tsx"],"sourcesContent":["import type {\n AllHTMLAttributes,\n ComponentType,\n ForwardRefExoticComponent,\n JSX,\n PropsWithoutRef,\n RefAttributes,\n} from 'react';\nimport { createElement, forwardRef, useMemo, useRef } from 'react';\nimport { useStyles } from './hooks/useStyles';\nimport { BASE_STYLES } from './styles/list';\nimport type { Styles, StylesInterface } from './styles/types';\nimport type {\n AllBaseProps,\n BaseProps,\n BaseStyleProps,\n Mods,\n Props,\n Tokens,\n} from './types';\nimport { getDisplayName } from './utils/get-display-name';\nimport { isValidElementType } from './utils/is-valid-element-type';\nimport { mergeStyles } from './utils/merge-styles';\nimport { isSelector } from './pipeline';\nimport { hasKeys } from './utils/has-keys';\nimport { modAttrs } from './utils/mod-attrs';\nimport { processTokens, stringifyTokens } from './utils/process-tokens';\n\nimport type { StyleValue, StyleValueStateMap } from './utils/styles';\n\n/**\n * Mapping of is* properties to their corresponding HTML attributes\n */\nconst IS_PROPERTIES_MAP = {\n isDisabled: 'disabled',\n isHidden: 'hidden',\n isChecked: 'checked',\n} as const;\n\n/**\n * Precalculated entries for performance optimization\n */\nconst IS_PROPERTIES_ENTRIES = Object.entries(IS_PROPERTIES_MAP);\n\n/**\n * Helper function to handle is* properties consistently\n * Transforms is* props to HTML attributes and adds corresponding data-* attributes\n */\nfunction handleIsProperties(props: Record<string, unknown>) {\n for (const [isProperty, targetAttribute] of IS_PROPERTIES_ENTRIES) {\n if (isProperty in props) {\n props[targetAttribute] = props[isProperty];\n delete props[isProperty];\n }\n\n // Add data-* attribute if target attribute is truthy and doesn't already exist\n const dataAttribute = `data-${targetAttribute}`;\n if (!(dataAttribute in props) && props[targetAttribute]) {\n props[dataAttribute] = '';\n }\n }\n}\n\n/**\n * Creates a sub-element component for compound component patterns.\n * Sub-elements are lightweight components with data-element attribute for CSS targeting.\n */\nfunction createSubElement<Tag extends keyof JSX.IntrinsicElements>(\n elementName: string,\n definition: SubElementDefinition<Tag>,\n): ForwardRefExoticComponent<\n PropsWithoutRef<SubElementProps<Tag>> & RefAttributes<unknown>\n> {\n // Normalize definition to object form\n const config =\n typeof definition === 'string'\n ? { as: definition as Tag }\n : (definition as { as?: Tag; qa?: string; qaVal?: string | number });\n\n const tag = config.as ?? ('div' as Tag);\n const defaultQa = config.qa;\n const defaultQaVal = config.qaVal;\n\n const SubElement = forwardRef<unknown, SubElementProps<Tag>>((props, ref) => {\n const {\n qa,\n qaVal,\n mods,\n tokens,\n isDisabled,\n isHidden,\n isChecked,\n className,\n style,\n ...htmlProps\n } = props as SubElementProps<Tag> & {\n className?: string;\n style?: Record<string, unknown>;\n };\n\n // Build mod attributes\n let modProps: Record<string, unknown> | undefined;\n if (mods) {\n modProps = modAttrs(mods as Mods) as Record<string, unknown>;\n }\n\n // Process tokens into inline style properties\n const tokenStyle = tokens\n ? (processTokens(tokens) as Record<string, unknown>)\n : undefined;\n\n // Merge token styles with explicit style prop (style has priority)\n let mergedStyle: Record<string, unknown> | undefined;\n if (tokenStyle || style) {\n mergedStyle =\n tokenStyle && style\n ? { ...tokenStyle, ...style }\n : ((tokenStyle ?? style) as Record<string, unknown>);\n }\n\n const elementProps = {\n 'data-element': elementName,\n 'data-qa': qa ?? defaultQa,\n 'data-qaval': qaVal ?? defaultQaVal,\n ...(modProps || {}),\n ...htmlProps,\n className,\n style: mergedStyle,\n isDisabled,\n isHidden,\n isChecked,\n ref,\n } as Record<string, unknown>;\n\n // Handle is* properties (isDisabled -> disabled + data-disabled, etc.)\n handleIsProperties(elementProps);\n\n // Clean up undefined data attributes\n if (elementProps['data-qa'] === undefined) delete elementProps['data-qa'];\n if (elementProps['data-qaval'] === undefined)\n delete elementProps['data-qaval'];\n\n return createElement(tag, elementProps);\n });\n\n SubElement.displayName = `SubElement(${elementName})`;\n\n return SubElement as ForwardRefExoticComponent<\n PropsWithoutRef<SubElementProps<Tag>> & RefAttributes<unknown>\n >;\n}\n\ntype StyleList = readonly (keyof {\n [key in keyof StylesInterface]: StylesInterface[key];\n})[];\n\nexport type PropsWithStyles = {\n styles?: Styles;\n} & Omit<Props, 'styles'>;\n\nexport type VariantMap = Record<string, Styles>;\n\nexport interface WithVariant<V extends VariantMap> {\n variant?: keyof V;\n}\n\n// ============================================================================\n// Sub-element types for compound components\n// ============================================================================\n\n/**\n * Definition for a sub-element. Can be either:\n * - A tag name string (e.g., 'div', 'span')\n * - An object with configuration options\n */\nexport type SubElementDefinition<\n Tag extends keyof JSX.IntrinsicElements = 'div',\n> =\n | Tag\n | {\n as?: Tag;\n qa?: string;\n qaVal?: string | number;\n };\n\n/**\n * Map of sub-element definitions.\n * Keys become the sub-component names (e.g., { Icon: 'span' } -> Component.Icon)\n */\nexport type ElementsDefinition = Record<\n string,\n SubElementDefinition<keyof JSX.IntrinsicElements>\n>;\n\n/**\n * Resolves the tag from a SubElementDefinition\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype ResolveElementTag<T extends SubElementDefinition<any>> = T extends string\n ? T\n : T extends { as?: infer Tag }\n ? Tag extends keyof JSX.IntrinsicElements\n ? Tag\n : 'div'\n : 'div';\n\n/**\n * Props for sub-element components.\n * Combines HTML attributes with tasty-specific props (qa, qaVal, mods, tokens, isDisabled, etc.)\n */\nexport type SubElementProps<Tag extends keyof JSX.IntrinsicElements = 'div'> =\n Omit<\n JSX.IntrinsicElements[Tag],\n 'ref' | 'color' | 'content' | 'translate'\n > & {\n qa?: string;\n qaVal?: string | number;\n mods?: Mods;\n tokens?: Tokens;\n isDisabled?: boolean;\n isHidden?: boolean;\n isChecked?: boolean;\n };\n\n/**\n * Generates the sub-element component types from an ElementsDefinition\n */\ntype SubElementComponents<E extends ElementsDefinition> = {\n [K in keyof E]: ForwardRefExoticComponent<\n PropsWithoutRef<SubElementProps<ResolveElementTag<E[K]>>> &\n RefAttributes<\n ResolveElementTag<E[K]> extends keyof HTMLElementTagNameMap\n ? HTMLElementTagNameMap[ResolveElementTag<E[K]>]\n : Element\n >\n >;\n};\n\n/**\n * Base type containing common properties shared between TastyProps and TastyElementOptions.\n * Separated to avoid code duplication while allowing different type constraints.\n */\ntype TastyBaseProps<\n K extends StyleList,\n V extends VariantMap,\n E extends ElementsDefinition = Record<string, never>,\n> = {\n /** Default styles of the element. */\n styles?: Styles;\n /** The list of styles that can be provided by props */\n styleProps?: K;\n element?: BaseProps['element'];\n variants?: V;\n /** Default tokens for inline CSS custom properties */\n tokens?: Tokens;\n /** Sub-element definitions for compound components */\n elements?: E;\n} & Pick<BaseProps, 'qa' | 'qaVal'> &\n WithVariant<V>;\n\nexport type TastyProps<\n K extends StyleList,\n V extends VariantMap,\n E extends ElementsDefinition = Record<string, never>,\n DefaultProps = Props,\n> = TastyBaseProps<K, V, E> & {\n /** The tag name of the element or a React component. */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n as?: string | ComponentType<any>;\n} & Partial<Omit<DefaultProps, 'as' | 'styles' | 'styleProps' | 'tokens'>>;\n\n/**\n * TastyElementOptions is used for the element-creation overload of tasty().\n * It includes a Tag generic that allows TypeScript to infer the correct\n * HTML element type from the `as` prop.\n *\n * Note: Uses a separate index signature with `unknown` instead of inheriting\n * from Props (which has `any`) to ensure strict type checking for styles.\n */\nexport type TastyElementOptions<\n K extends StyleList,\n V extends VariantMap,\n E extends ElementsDefinition = Record<string, never>,\n Tag extends keyof JSX.IntrinsicElements = 'div',\n> = TastyBaseProps<K, V, E> & {\n /** The tag name of the element or a React component. */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n as?: Tag | ComponentType<any>;\n} & Record<string, unknown>;\n\nexport type AllBasePropsWithMods<K extends StyleList> = AllBaseProps & {\n [key in K[number]]?:\n | StyleValue<StylesInterface[key]>\n | StyleValueStateMap<StylesInterface[key]>;\n} & BaseStyleProps;\n\n/**\n * Keys from BasePropsWithoutChildren that should be omitted from HTML attributes.\n * This excludes event handlers so they can be properly typed from JSX.IntrinsicElements.\n */\ntype TastySpecificKeys =\n | 'as'\n | 'qa'\n | 'qaVal'\n | 'element'\n | 'styles'\n | 'breakpoints'\n | 'block'\n | 'inline'\n | 'mods'\n | 'isHidden'\n | 'isDisabled'\n | 'css'\n | 'style'\n | 'theme'\n | 'tokens'\n | 'ref'\n | 'color';\n\n/**\n * Props type for tasty elements that combines:\n * - AllBasePropsWithMods for style props with strict tokens type\n * - HTML attributes for flexibility (properly typed based on tag)\n * - Variant support\n *\n * Uses AllHTMLAttributes as base for common attributes (like disabled),\n * but overrides event handlers with tag-specific types from JSX.IntrinsicElements.\n */\nexport type TastyElementProps<\n K extends StyleList,\n V extends VariantMap,\n Tag extends keyof JSX.IntrinsicElements = 'div',\n> = AllBasePropsWithMods<K> &\n WithVariant<V> &\n Omit<\n Omit<AllHTMLAttributes<HTMLElement>, keyof JSX.IntrinsicElements[Tag]> &\n JSX.IntrinsicElements[Tag],\n TastySpecificKeys | K[number]\n >;\n\ntype TastyComponentPropsWithDefaults<\n Props extends PropsWithStyles,\n DefaultProps extends Partial<Props>,\n> = keyof DefaultProps extends never\n ? Props\n : {\n [key in Extract<keyof Props, keyof DefaultProps>]?: Props[key];\n } & {\n [key in keyof Omit<Props, keyof DefaultProps>]: Props[key];\n };\n\nexport function tasty<\n K extends StyleList,\n V extends VariantMap,\n E extends ElementsDefinition = Record<string, never>,\n Tag extends keyof JSX.IntrinsicElements = 'div',\n>(\n options: TastyElementOptions<K, V, E, Tag>,\n secondArg?: never,\n): ForwardRefExoticComponent<\n PropsWithoutRef<TastyElementProps<K, V, Tag>> & RefAttributes<unknown>\n> &\n SubElementComponents<E>;\nexport function tasty<\n Props extends PropsWithStyles,\n DefaultProps extends Partial<Props> = Partial<Props>,\n>(\n Component: ComponentType<Props>,\n options?: TastyProps<never, never, Record<string, never>, Props>,\n): ComponentType<TastyComponentPropsWithDefaults<Props, DefaultProps>>;\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n// Implementation\nexport function tasty<\n K extends StyleList,\n V extends VariantMap,\n _C = Record<string, unknown>,\n>(Component: any, options?: any) {\n if (isValidElementType(Component)) {\n return tastyWrap(Component as ComponentType<any>, options);\n }\n\n return tastyElement(Component as TastyProps<K, V>);\n}\n\nfunction tastyWrap<\n P extends PropsWithStyles,\n DefaultProps extends Partial<P> = Partial<P>,\n>(\n Component: ComponentType<P>,\n options?: TastyProps<never, never, P>,\n): ComponentType<TastyComponentPropsWithDefaults<P, DefaultProps>> {\n const {\n as: extendTag,\n element: extendElement,\n ...defaultProps\n } = (options ?? {}) as TastyProps<never, never, P>;\n\n const propsWithStyles = ['styles'].concat(\n Object.keys(defaultProps).filter((prop) => prop.endsWith('Styles')),\n );\n\n const _WrappedComponent = forwardRef<any, any>((props, ref) => {\n const { as, element, ...restProps } = props as Record<string, unknown>;\n const propsWithStylesValues = propsWithStyles.map(\n (prop) => (props as any)[prop],\n );\n\n const mergedStylesMap: Styles | undefined = useMemo(() => {\n return propsWithStyles.reduce((map, prop) => {\n const restValue = (restProps as any)[prop];\n const defaultValue = (defaultProps as any)[prop];\n\n if (restValue != null && defaultValue != null) {\n (map as any)[prop] = mergeStyles(defaultValue, restValue);\n } else {\n (map as any)[prop] = restValue ?? defaultValue;\n }\n\n return map;\n }, {} as Styles);\n }, [propsWithStylesValues]);\n\n const elementProps = {\n ...(defaultProps as unknown as Record<string, unknown>),\n ...(restProps as unknown as Record<string, unknown>),\n ...(mergedStylesMap as unknown as Record<string, unknown>),\n as: (as as string | undefined) ?? extendTag,\n element: (element as string | undefined) || extendElement,\n ref,\n } as unknown as P;\n\n return createElement(Component as ComponentType<P>, elementProps);\n });\n\n _WrappedComponent.displayName = `TastyWrappedComponent(${getDisplayName(\n Component,\n (defaultProps as any).qa ?? (extendTag as any) ?? 'Anonymous',\n )})`;\n\n return _WrappedComponent as unknown as ComponentType<\n TastyComponentPropsWithDefaults<P, DefaultProps>\n >;\n}\n\nfunction tastyElement<\n K extends StyleList,\n V extends VariantMap,\n E extends ElementsDefinition,\n>(tastyOptions: TastyProps<K, V, E>) {\n const {\n as: originalAs = 'div',\n element: defaultElement,\n styles: defaultStyles,\n styleProps,\n variants,\n tokens: defaultTokens,\n elements,\n ...defaultProps\n } = tastyOptions;\n\n // Pre-compute merged styles for each variant (if variants are defined)\n // This avoids creating separate component instances per variant\n let variantStylesMap: Record<string, Styles | undefined> | undefined;\n if (variants) {\n // Split defaultStyles: extend-mode state maps (no '' key, non-selector)\n // are pulled out and applied AFTER variant merge so they survive\n // replace-mode maps in variants.\n let baseStyles = defaultStyles;\n let extensionStyles: Styles | undefined;\n\n if (defaultStyles) {\n for (const key of Object.keys(defaultStyles)) {\n if (isSelector(key)) continue;\n\n const value = (defaultStyles as Record<string, unknown>)[key];\n\n if (\n typeof value === 'object' &&\n value !== null &&\n !Array.isArray(value) &&\n !('' in value)\n ) {\n if (!extensionStyles) {\n baseStyles = { ...defaultStyles } as Styles;\n extensionStyles = {} as Styles;\n }\n (extensionStyles as Record<string, unknown>)[key] = value;\n delete (baseStyles as Record<string, unknown>)[key];\n }\n }\n }\n\n const variantEntries = Object.entries(variants) as [string, Styles][];\n variantStylesMap = variantEntries.reduce(\n (map, [variant, variantStyles]) => {\n map[variant] = extensionStyles\n ? mergeStyles(baseStyles, variantStyles, extensionStyles)\n : mergeStyles(baseStyles, variantStyles);\n return map;\n },\n {} as Record<string, Styles | undefined>,\n );\n // Ensure 'default' variant always exists\n if (!variantStylesMap['default']) {\n variantStylesMap['default'] = defaultStyles;\n }\n }\n\n const {\n qa: defaultQa,\n qaVal: defaultQaVal,\n ...otherDefaultProps\n } = defaultProps ?? {};\n\n const propsToCheck = styleProps\n ? (styleProps as StyleList).concat(BASE_STYLES)\n : BASE_STYLES;\n\n const _TastyComponent = forwardRef<\n unknown,\n AllBasePropsWithMods<K> & WithVariant<V>\n >((allProps, ref) => {\n const {\n as,\n styles: rawStyles,\n variant,\n mods,\n element,\n qa,\n qaVal,\n className: userClassName,\n tokens,\n style,\n ...otherProps\n } = allProps as Record<string, unknown> as AllBasePropsWithMods<K> &\n WithVariant<V> & {\n className?: string;\n tokens?: Tokens;\n style?: Record<string, unknown>;\n };\n\n let styles = rawStyles;\n\n let propStyles: Styles | null = null;\n let propStylesKey = '';\n\n for (const prop of propsToCheck) {\n const key = prop as unknown as string;\n\n if (key in otherProps) {\n if (!propStyles) propStyles = {};\n const value = (otherProps as any)[key];\n (propStyles as any)[key] = value;\n delete (otherProps as any)[key];\n propStylesKey += key + '\\0' + value + '\\0';\n }\n }\n\n if (!styles || (styles && !hasKeys(styles as Record<string, unknown>))) {\n styles = undefined as unknown as Styles;\n }\n\n // Stabilize propStyles reference: only update when content actually changes\n const propStylesRef = useRef<{ key: string; styles: Styles | null }>({\n key: '',\n styles: null,\n });\n if (propStylesRef.current.key !== propStylesKey) {\n propStylesRef.current = { key: propStylesKey, styles: propStyles };\n }\n\n // Determine base styles: use variant styles if available, otherwise default styles\n const baseStyles = variantStylesMap\n ? (variantStylesMap[(variant as string) || 'default'] ??\n variantStylesMap['default'])\n : defaultStyles;\n\n // Merge base styles with instance styles and prop styles\n const allStyles = useMemo(() => {\n const currentPropStyles = propStylesRef.current.styles;\n const hasStyleProps =\n styles && hasKeys(styles as Record<string, unknown>);\n const hasPropStyles = currentPropStyles && hasKeys(currentPropStyles);\n\n if (!hasStyleProps && !hasPropStyles) {\n return baseStyles;\n }\n\n return mergeStyles(\n baseStyles,\n styles as Styles,\n currentPropStyles as Styles,\n );\n }, [baseStyles, styles, propStylesKey]);\n\n // Use the useStyles hook for style generation and injection\n const { className: stylesClassName } = useStyles(allStyles);\n\n // Merge default tokens with instance tokens (instance overrides defaults)\n const tokensKey = stringifyTokens(tokens as Tokens | undefined);\n const mergedTokens = useMemo(() => {\n if (!defaultTokens && !tokens) return undefined;\n if (!defaultTokens) return tokens as Tokens;\n if (!tokens) return defaultTokens;\n return { ...defaultTokens, ...tokens } as Tokens;\n }, [tokensKey]);\n\n // Process merged tokens into inline style properties\n const processedTokenStyle = useMemo(() => {\n return processTokens(mergedTokens);\n }, [mergedTokens]);\n\n // Merge processed tokens with explicit style prop (style has priority)\n const mergedStyle = useMemo(() => {\n if (!processedTokenStyle && !style) return undefined;\n if (!processedTokenStyle) return style;\n if (!style) return processedTokenStyle;\n return { ...processedTokenStyle, ...style };\n }, [processedTokenStyle, style]);\n\n let modProps: Record<string, unknown> | undefined;\n if (mods) {\n const modsObject = mods as unknown as Record<string, unknown>;\n modProps = modAttrs(modsObject as any) as Record<string, unknown>;\n }\n\n // Merge user className with generated className\n const finalClassName = [(userClassName as string) || '', stylesClassName]\n .filter(Boolean)\n .join(' ');\n\n const elementProps = {\n 'data-element': (element as string | undefined) || defaultElement,\n 'data-qa': (qa as string | undefined) || defaultQa,\n 'data-qaval': (qaVal as string | undefined) || defaultQaVal,\n ...(otherDefaultProps as unknown as Record<string, unknown>),\n ...(modProps || {}),\n ...(otherProps as unknown as Record<string, unknown>),\n className: finalClassName,\n style: mergedStyle,\n ref,\n } as Record<string, unknown>;\n\n // Apply the helper to handle is* properties\n handleIsProperties(elementProps);\n\n const renderedElement = createElement(\n (as as string | 'div') ?? originalAs,\n elementProps,\n );\n\n return renderedElement;\n });\n\n _TastyComponent.displayName = `TastyComponent(${\n (defaultProps as any).qa || originalAs\n })`;\n\n // Attach sub-element components if elements are defined\n if (elements) {\n const subElements = Object.entries(elements).reduce(\n (acc, [name, definition]) => {\n acc[name] = createSubElement(\n name,\n definition as SubElementDefinition<keyof JSX.IntrinsicElements>,\n );\n return acc;\n },\n {} as Record<string, ForwardRefExoticComponent<any>>,\n );\n\n return Object.assign(_TastyComponent, subElements);\n }\n\n return _TastyComponent;\n}\n\nexport const Element = tasty({});\n"],"mappings":"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"}
|
|
@@ -1,19 +1,15 @@
|
|
|
1
|
+
import { Lru } from "../parser/lru.js";
|
|
2
|
+
|
|
1
3
|
//#region src/utils/cache-wrapper.ts
|
|
2
4
|
/**
|
|
3
|
-
* Create a function that caches the result
|
|
5
|
+
* Create a function that caches the result with LRU eviction.
|
|
4
6
|
*/
|
|
5
7
|
function cacheWrapper(handler, limit = 1e3) {
|
|
6
|
-
const cache =
|
|
7
|
-
let count = 0;
|
|
8
|
+
const cache = new Lru(limit);
|
|
8
9
|
return (firstArg, secondArg) => {
|
|
9
10
|
const key = typeof firstArg === "string" && secondArg == null ? firstArg : JSON.stringify([firstArg, secondArg]);
|
|
10
11
|
let result = cache.get(key);
|
|
11
12
|
if (result === void 0) {
|
|
12
|
-
if (count > limit) {
|
|
13
|
-
cache.clear();
|
|
14
|
-
count = 0;
|
|
15
|
-
}
|
|
16
|
-
count++;
|
|
17
13
|
result = secondArg == null ? handler(firstArg) : handler(firstArg, secondArg);
|
|
18
14
|
cache.set(key, result);
|
|
19
15
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cache-wrapper.js","names":[],"sources":["../../src/utils/cache-wrapper.ts"],"sourcesContent":["/**\n * Create a function that caches the result
|
|
1
|
+
{"version":3,"file":"cache-wrapper.js","names":[],"sources":["../../src/utils/cache-wrapper.ts"],"sourcesContent":["import { Lru } from '../parser/lru';\n\n/**\n * Create a function that caches the result with LRU eviction.\n */\nexport function cacheWrapper<A, B, R>(\n handler: (firstArg: A, secondArg?: B) => R,\n limit = 1000,\n): (firstArg: A, secondArg?: B) => R {\n const cache = new Lru<string, R>(limit);\n\n return (firstArg: A, secondArg?: B) => {\n const key =\n typeof firstArg === 'string' && secondArg == null\n ? firstArg\n : JSON.stringify([firstArg, secondArg]);\n\n let result = cache.get(key);\n if (result === undefined) {\n result =\n secondArg == null ? handler(firstArg) : handler(firstArg, secondArg);\n cache.set(key, result);\n }\n return result;\n };\n}\n"],"mappings":";;;;;;AAKA,SAAgB,aACd,SACA,QAAQ,KAC2B;CACnC,MAAM,QAAQ,IAAI,IAAe,MAAM;AAEvC,SAAQ,UAAa,cAAkB;EACrC,MAAM,MACJ,OAAO,aAAa,YAAY,aAAa,OACzC,WACA,KAAK,UAAU,CAAC,UAAU,UAAU,CAAC;EAE3C,IAAI,SAAS,MAAM,IAAI,IAAI;AAC3B,MAAI,WAAW,QAAW;AACxB,YACE,aAAa,OAAO,QAAQ,SAAS,GAAG,QAAQ,UAAU,UAAU;AACtE,SAAM,IAAI,KAAK,OAAO;;AAExB,SAAO"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
//#region src/utils/has-keys.ts
|
|
2
|
+
/**
|
|
3
|
+
* Check if an object has any own enumerable keys.
|
|
4
|
+
* Avoids the array allocation of Object.keys(obj).length > 0.
|
|
5
|
+
*/
|
|
6
|
+
function hasKeys(obj) {
|
|
7
|
+
for (const _ in obj) return true;
|
|
8
|
+
return false;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
//#endregion
|
|
12
|
+
export { hasKeys };
|
|
13
|
+
//# sourceMappingURL=has-keys.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"has-keys.js","names":[],"sources":["../../src/utils/has-keys.ts"],"sourcesContent":["/**\n * Check if an object has any own enumerable keys.\n * Avoids the array allocation of Object.keys(obj).length > 0.\n */\nexport function hasKeys(obj: object): boolean {\n for (const _ in obj) return true;\n return false;\n}\n"],"mappings":";;;;;AAIA,SAAgB,QAAQ,KAAsB;AAC5C,MAAK,MAAM,KAAK,IAAK,QAAO;AAC5B,QAAO"}
|
package/dist/utils/mod-attrs.js
CHANGED
package/dist/utils/styles.d.ts
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { ProcessedStyle, StyleDetails } from "../parser/types.js";
|
|
2
2
|
import { StyleParser } from "../parser/parser.js";
|
|
3
|
-
import { AtRuleContext, ParsedAdvancedState, StateParserContext } from "../states/index.js";
|
|
4
|
-
import { Styles } from "../styles/types.js";
|
|
5
3
|
|
|
6
4
|
//#region src/utils/styles.d.ts
|
|
7
5
|
type StyleValue<T = string> = T | boolean | number | null | undefined;
|
|
@@ -21,7 +19,6 @@ type StyleValueStateMap<T = string> = Record<string, StyleValue<T> | '@inherit'>
|
|
|
21
19
|
* Use this for component props that accept style values.
|
|
22
20
|
*/
|
|
23
21
|
type StylePropValue<T = string> = StyleValue<T> | StyleValueStateMap<T>;
|
|
24
|
-
type ComputeModel = string | number;
|
|
25
22
|
type CSSMap = {
|
|
26
23
|
$?: string | string[];
|
|
27
24
|
} & Record<string, string | string[]>;
|
|
@@ -37,32 +34,12 @@ type StyleHandler = RawStyleHandler & {
|
|
|
37
34
|
* - Multi-property tuple: [['style1', 'style2'], handler]
|
|
38
35
|
*/
|
|
39
36
|
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
37
|
interface ParsedColor {
|
|
58
38
|
color?: string;
|
|
59
39
|
name?: string;
|
|
60
40
|
opacity?: number;
|
|
61
41
|
}
|
|
62
|
-
type StyleStateDataList = StyleStateData[];
|
|
63
|
-
type StyleStateDataListMap = Record<string, StyleStateDataList>;
|
|
64
42
|
type StyleMap = Record<string, StyleValue | StyleValueStateMap>;
|
|
65
|
-
type StyleStateMap = Record<string, StyleStateData>;
|
|
66
43
|
declare const CUSTOM_UNITS: {
|
|
67
44
|
r: string;
|
|
68
45
|
cr: string;
|
|
@@ -131,47 +108,7 @@ declare function strToRgb(color: string, _ignoreAlpha?: boolean): string | null
|
|
|
131
108
|
declare function getRgbValuesFromRgbaString(str: string): number[];
|
|
132
109
|
declare function hexToRgb(hex: string): string | null;
|
|
133
110
|
declare function filterMods(mods: string[], allowedMods: string[]): string[];
|
|
134
|
-
declare function extendStyles(defaultStyles?: Record<string, unknown> | null, newStyles?: Record<string, unknown> | null): Record<string, unknown>;
|
|
135
|
-
/**
|
|
136
|
-
* Split properties into style and non-style properties.
|
|
137
|
-
* @param props - Component prop map.
|
|
138
|
-
* @param [styleList] - List of all style properties.
|
|
139
|
-
* @param [defaultStyles] - Default style map of the component.
|
|
140
|
-
* @param [propMap] - Props to style alias map.
|
|
141
|
-
* @param [ignoreList] - A list of properties to ignore.
|
|
142
|
-
*/
|
|
143
|
-
declare function extractStyles(props: Record<string, unknown>, styleList?: readonly string[], defaultStyles?: Styles, propMap?: Record<string, string>, ignoreList?: readonly string[]): Styles;
|
|
144
|
-
/**
|
|
145
|
-
* Check if a token is an advanced state (starts with @)
|
|
146
|
-
*/
|
|
147
|
-
declare function isAdvancedStateToken(token: string): boolean;
|
|
148
|
-
declare const STATE_OPERATORS: {
|
|
149
|
-
NOT: string;
|
|
150
|
-
AND: string;
|
|
151
|
-
OR: string;
|
|
152
|
-
XOR: string;
|
|
153
|
-
};
|
|
154
|
-
declare const STATE_OPERATOR_LIST: string[];
|
|
155
|
-
declare const parseStateNotation: (firstArg: string, secondArg?: string | number | boolean | StyleValueStateMap<string> | StyleStateData | null | undefined) => StyleStateData;
|
|
156
|
-
/**
|
|
157
|
-
* Build an AtRuleContext from parsed advanced states
|
|
158
|
-
*/
|
|
159
|
-
declare function buildAtRuleContext(advancedStates: ParsedAdvancedState[], negatedStates: Set<string>): AtRuleContext | undefined;
|
|
160
|
-
/**
|
|
161
|
-
* Parse state notation and return tokens, modifiers and compute model.
|
|
162
|
-
* Enhanced to detect and extract advanced states.
|
|
163
|
-
*/
|
|
164
|
-
declare function styleStateMapToStyleStateDataList(styleStateMap: StyleStateMap | StyleValue | StyleValueStateMap, parserContext?: StateParserContext): {
|
|
165
|
-
states: StyleStateDataList;
|
|
166
|
-
mods: string[];
|
|
167
|
-
hasAdvancedStates: boolean;
|
|
168
|
-
};
|
|
169
|
-
declare const COMPUTE_FUNC_MAP: Record<string, (a: unknown, b?: unknown) => unknown>;
|
|
170
|
-
/**
|
|
171
|
-
* Compute a result based on a model and incoming map.
|
|
172
|
-
*/
|
|
173
|
-
declare function computeState(computeModel: ComputeModel, valueMap: (number | boolean)[] | Record<string, boolean> | ((...args: unknown[]) => unknown)): unknown;
|
|
174
111
|
declare function stringifyStyles(styles: unknown): string;
|
|
175
112
|
//#endregion
|
|
176
|
-
export {
|
|
113
|
+
export { CSSMap, CUSTOM_UNITS, DIRECTIONS, ParsedColor, RawStyleHandler, StyleHandler, StyleHandlerDefinition, StyleHandlerResult, StyleMap, StylePropValue, StyleValue, StyleValueStateMap, customFunc, filterMods, getGlobalFuncs, getGlobalParser, getGlobalPredefinedTokens, getRgbValuesFromRgbaString, hexToRgb, normalizeColorTokenValue, parseColor, parseStyle, resetGlobalPredefinedTokens, setGlobalPredefinedTokens, strToRgb, stringifyStyles };
|
|
177
114
|
//# sourceMappingURL=styles.d.ts.map
|
package/dist/utils/styles.js
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import { StyleParser } from "../parser/parser.js";
|
|
2
2
|
import { okhslFunc } from "../plugins/okhsl-plugin.js";
|
|
3
|
-
import { createStateParserContext, parseAdvancedState } from "../states/index.js";
|
|
4
|
-
import { cacheWrapper } from "./cache-wrapper.js";
|
|
5
|
-
import { camelToKebab } from "./case-converter.js";
|
|
6
3
|
import { okhslToRgb } from "./okhsl-to-rgb.js";
|
|
7
4
|
import { hslToRgb } from "./hsl-to-rgb.js";
|
|
8
5
|
|
|
@@ -380,323 +377,12 @@ function hexToRgb(hex) {
|
|
|
380
377
|
function filterMods(mods, allowedMods) {
|
|
381
378
|
return mods.filter((mod) => allowedMods.includes(mod));
|
|
382
379
|
}
|
|
383
|
-
function extendStyles(defaultStyles, newStyles) {
|
|
384
|
-
let styles = {};
|
|
385
|
-
if (!defaultStyles) {
|
|
386
|
-
if (!newStyles) return styles;
|
|
387
|
-
} else styles = Object.assign({}, defaultStyles);
|
|
388
|
-
if (newStyles) Object.keys(newStyles).forEach((key) => {
|
|
389
|
-
if (newStyles[key] != null) styles[key] = newStyles[key];
|
|
390
|
-
});
|
|
391
|
-
return styles;
|
|
392
|
-
}
|
|
393
|
-
/**
|
|
394
|
-
* Split properties into style and non-style properties.
|
|
395
|
-
* @param props - Component prop map.
|
|
396
|
-
* @param [styleList] - List of all style properties.
|
|
397
|
-
* @param [defaultStyles] - Default style map of the component.
|
|
398
|
-
* @param [propMap] - Props to style alias map.
|
|
399
|
-
* @param [ignoreList] - A list of properties to ignore.
|
|
400
|
-
*/
|
|
401
|
-
function extractStyles(props, styleList = [], defaultStyles, propMap, ignoreList = []) {
|
|
402
|
-
const styles = {
|
|
403
|
-
...defaultStyles,
|
|
404
|
-
...ignoreList.includes("styles") ? void 0 : props.styles && typeof props.styles === "object" ? props.styles : void 0
|
|
405
|
-
};
|
|
406
|
-
Object.keys(props).forEach((prop) => {
|
|
407
|
-
const propName = propMap ? propMap[prop] || prop : prop;
|
|
408
|
-
const value = props[prop];
|
|
409
|
-
if (ignoreList && ignoreList.includes(prop)) {} else if (styleList.includes(propName)) styles[propName] = value;
|
|
410
|
-
}, {});
|
|
411
|
-
return styles;
|
|
412
|
-
}
|
|
413
|
-
const STATES_REGEXP = /([&|!^])|([()])|(@media:[a-z]+)|(@media\([^)]+\))|(@root\([^)]+\))|(@own\([^)]+\))|(@\([^)]+\))|(@starting)|(@[A-Za-z][A-Za-z0-9-]*)|([a-z][a-z0-9-]+=(?:"[^"]*"|'[^']*'|[^\s&|!^()]+))|([a-z][a-z0-9-]+)|(:[a-z][a-z0-9-]+\([^)]+\)|:[a-z][a-z0-9-]+)|(\.[a-z][a-z0-9-]+)|(\[[^\]]+])/gi;
|
|
414
|
-
/**
|
|
415
|
-
* Check if a token is an advanced state (starts with @)
|
|
416
|
-
*/
|
|
417
|
-
function isAdvancedStateToken(token) {
|
|
418
|
-
return token.startsWith("@") || token.startsWith("!@");
|
|
419
|
-
}
|
|
420
|
-
const STATE_OPERATORS = {
|
|
421
|
-
NOT: "!",
|
|
422
|
-
AND: "&",
|
|
423
|
-
OR: "|",
|
|
424
|
-
XOR: "^"
|
|
425
|
-
};
|
|
426
|
-
const STATE_OPERATOR_LIST = [
|
|
427
|
-
"!",
|
|
428
|
-
"&",
|
|
429
|
-
"|",
|
|
430
|
-
"^"
|
|
431
|
-
];
|
|
432
|
-
/**
|
|
433
|
-
* Convert state notation tokens to a compute model (string, or nested [op, lhs, rhs]).
|
|
434
|
-
*/
|
|
435
|
-
function convertTokensToComputeUnits(tokens) {
|
|
436
|
-
if (tokens.length === 1) return tokens[0];
|
|
437
|
-
const hasLength = (x) => typeof x === "string" || Array.isArray(x);
|
|
438
|
-
STATE_OPERATOR_LIST.forEach((operator) => {
|
|
439
|
-
let i;
|
|
440
|
-
while ((i = tokens.indexOf(operator)) !== -1) {
|
|
441
|
-
const token = tokens[i];
|
|
442
|
-
if (token === "!") {
|
|
443
|
-
const next = tokens[i + 1];
|
|
444
|
-
if (next !== void 0 && hasLength(next) && next.length !== 1) tokens.splice(i, 2, ["!", next]);
|
|
445
|
-
else tokens.splice(i, 1);
|
|
446
|
-
} else {
|
|
447
|
-
const prev = tokens[i - 1];
|
|
448
|
-
const next = tokens[i + 1];
|
|
449
|
-
if (prev !== void 0 && next !== void 0 && hasLength(prev) && hasLength(next) && prev.length !== 1 && next.length !== 1) tokens.splice(i - 1, 3, [
|
|
450
|
-
token,
|
|
451
|
-
prev,
|
|
452
|
-
next
|
|
453
|
-
]);
|
|
454
|
-
else tokens.splice(i, 1);
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
});
|
|
458
|
-
return tokens.length === 1 ? tokens[0] : tokens;
|
|
459
|
-
}
|
|
460
|
-
/**
|
|
461
|
-
* Replace commas with | only outside of parentheses.
|
|
462
|
-
* This preserves commas in advanced states like @(card, w < 600px)
|
|
463
|
-
*/
|
|
464
|
-
function replaceCommasOutsideParens(str) {
|
|
465
|
-
let result = "";
|
|
466
|
-
let depth = 0;
|
|
467
|
-
for (const char of str) if (char === "(") {
|
|
468
|
-
depth++;
|
|
469
|
-
result += char;
|
|
470
|
-
} else if (char === ")") {
|
|
471
|
-
depth--;
|
|
472
|
-
result += char;
|
|
473
|
-
} else if (char === "," && depth === 0) result += "|";
|
|
474
|
-
else result += char;
|
|
475
|
-
return result;
|
|
476
|
-
}
|
|
477
|
-
/**
|
|
478
|
-
* Parse state notation and return tokens, modifiers and compute model.
|
|
479
|
-
*/
|
|
480
|
-
function parseStateNotationInner(notation, value) {
|
|
481
|
-
const tokens = replaceCommasOutsideParens(notation).match(STATES_REGEXP);
|
|
482
|
-
if (!tokens || !tokens.length) return {
|
|
483
|
-
model: void 0,
|
|
484
|
-
mods: [],
|
|
485
|
-
notMods: [],
|
|
486
|
-
tokens: [],
|
|
487
|
-
value
|
|
488
|
-
};
|
|
489
|
-
else if (tokens.length === 1) return {
|
|
490
|
-
model: tokens[0],
|
|
491
|
-
mods: tokens.slice(0),
|
|
492
|
-
notMods: [],
|
|
493
|
-
tokens,
|
|
494
|
-
value
|
|
495
|
-
};
|
|
496
|
-
const mods = [];
|
|
497
|
-
const operations = [[]];
|
|
498
|
-
let list = operations[0];
|
|
499
|
-
let position = 0;
|
|
500
|
-
let operation;
|
|
501
|
-
tokens.forEach((token) => {
|
|
502
|
-
switch (token) {
|
|
503
|
-
case "(":
|
|
504
|
-
operation = [];
|
|
505
|
-
position++;
|
|
506
|
-
list = operations[position] = operation;
|
|
507
|
-
break;
|
|
508
|
-
case ")":
|
|
509
|
-
position--;
|
|
510
|
-
operations[position].push(convertTokensToComputeUnits(list));
|
|
511
|
-
list = operations[position];
|
|
512
|
-
break;
|
|
513
|
-
default:
|
|
514
|
-
if (token.length > 1) {
|
|
515
|
-
if (!mods.includes(token)) mods.push(token);
|
|
516
|
-
}
|
|
517
|
-
list.push(token);
|
|
518
|
-
}
|
|
519
|
-
});
|
|
520
|
-
while (position) {
|
|
521
|
-
position--;
|
|
522
|
-
operations[position].push(convertTokensToComputeUnits(list));
|
|
523
|
-
list = operations[position];
|
|
524
|
-
}
|
|
525
|
-
return {
|
|
526
|
-
tokens,
|
|
527
|
-
mods,
|
|
528
|
-
notMods: [],
|
|
529
|
-
model: convertTokensToComputeUnits(operations[0]),
|
|
530
|
-
value
|
|
531
|
-
};
|
|
532
|
-
}
|
|
533
|
-
const parseStateNotation = cacheWrapper(parseStateNotationInner);
|
|
534
|
-
/**
|
|
535
|
-
* Build an AtRuleContext from parsed advanced states
|
|
536
|
-
*/
|
|
537
|
-
function buildAtRuleContext(advancedStates, negatedStates) {
|
|
538
|
-
if (advancedStates.length === 0) return void 0;
|
|
539
|
-
const ctx = {};
|
|
540
|
-
for (const state of advancedStates) {
|
|
541
|
-
const isNegated = negatedStates.has(state.raw);
|
|
542
|
-
switch (state.type) {
|
|
543
|
-
case "media": {
|
|
544
|
-
if (!ctx.media) ctx.media = [];
|
|
545
|
-
let mediaCondition = "";
|
|
546
|
-
if (state.mediaType) mediaCondition = state.mediaType;
|
|
547
|
-
else if (state.condition) mediaCondition = `(${state.condition})`;
|
|
548
|
-
if (mediaCondition) if (isNegated) ctx.media.push(`not ${mediaCondition}`);
|
|
549
|
-
else ctx.media.push(mediaCondition);
|
|
550
|
-
break;
|
|
551
|
-
}
|
|
552
|
-
case "container": {
|
|
553
|
-
if (!ctx.container) ctx.container = [];
|
|
554
|
-
let condition = state.condition;
|
|
555
|
-
if (isNegated) condition = `not (${condition})`;
|
|
556
|
-
ctx.container.push({
|
|
557
|
-
name: state.containerName,
|
|
558
|
-
condition
|
|
559
|
-
});
|
|
560
|
-
break;
|
|
561
|
-
}
|
|
562
|
-
case "root": {
|
|
563
|
-
if (!ctx.rootStates) ctx.rootStates = [];
|
|
564
|
-
const rootSelector = buildRootSelector(state.condition, isNegated);
|
|
565
|
-
ctx.rootStates.push(rootSelector);
|
|
566
|
-
break;
|
|
567
|
-
}
|
|
568
|
-
case "starting":
|
|
569
|
-
if (!isNegated) ctx.startingStyle = true;
|
|
570
|
-
break;
|
|
571
|
-
}
|
|
572
|
-
}
|
|
573
|
-
if (!ctx.media?.length && !ctx.container?.length && !ctx.rootStates?.length && !ctx.startingStyle) return;
|
|
574
|
-
return ctx;
|
|
575
|
-
}
|
|
576
|
-
/**
|
|
577
|
-
* Build a root state selector from a condition
|
|
578
|
-
*/
|
|
579
|
-
function buildRootSelector(condition, isNegated) {
|
|
580
|
-
let selector;
|
|
581
|
-
if (condition.startsWith(".")) selector = condition;
|
|
582
|
-
else if (condition.startsWith("[")) selector = condition;
|
|
583
|
-
else if (condition.includes("=")) {
|
|
584
|
-
const [key, value] = condition.split("=");
|
|
585
|
-
selector = `[data-${camelToKebab(key.trim())}="${value.trim()}"]`;
|
|
586
|
-
} else selector = `[data-${camelToKebab(condition)}]`;
|
|
587
|
-
if (isNegated) return `:not(${selector})`;
|
|
588
|
-
return selector;
|
|
589
|
-
}
|
|
590
|
-
/**
|
|
591
|
-
* Parse state notation and return tokens, modifiers and compute model.
|
|
592
|
-
* Enhanced to detect and extract advanced states.
|
|
593
|
-
*/
|
|
594
|
-
function styleStateMapToStyleStateDataList(styleStateMap, parserContext) {
|
|
595
|
-
if (typeof styleStateMap !== "object" || !styleStateMap) return {
|
|
596
|
-
states: [{
|
|
597
|
-
model: void 0,
|
|
598
|
-
mods: [],
|
|
599
|
-
notMods: [],
|
|
600
|
-
value: styleStateMap
|
|
601
|
-
}],
|
|
602
|
-
mods: [],
|
|
603
|
-
hasAdvancedStates: false
|
|
604
|
-
};
|
|
605
|
-
const stateDataList = [];
|
|
606
|
-
let hasAdvancedStates = false;
|
|
607
|
-
Object.keys(styleStateMap).forEach((stateNotation) => {
|
|
608
|
-
const state = parseStateNotation(stateNotation, styleStateMap[stateNotation]);
|
|
609
|
-
const advancedStates = [];
|
|
610
|
-
const negatedAdvancedStates = /* @__PURE__ */ new Set();
|
|
611
|
-
const regularMods = [];
|
|
612
|
-
const ownMods = [];
|
|
613
|
-
const negatedOwnMods = [];
|
|
614
|
-
if (state.tokens) {
|
|
615
|
-
let isNegated = false;
|
|
616
|
-
for (const token of state.tokens) {
|
|
617
|
-
if (token === "!") {
|
|
618
|
-
isNegated = true;
|
|
619
|
-
continue;
|
|
620
|
-
}
|
|
621
|
-
if (isAdvancedStateToken(token)) {
|
|
622
|
-
hasAdvancedStates = true;
|
|
623
|
-
const parsed = parseAdvancedState(token, parserContext || createStateParserContext(void 0));
|
|
624
|
-
advancedStates.push(parsed);
|
|
625
|
-
if (parsed.type === "own" && parsed.condition) if (isNegated) negatedOwnMods.push(parsed.condition);
|
|
626
|
-
else ownMods.push(parsed.condition);
|
|
627
|
-
else if (isNegated) negatedAdvancedStates.add(token);
|
|
628
|
-
isNegated = false;
|
|
629
|
-
} else if (token.length > 1 && ![
|
|
630
|
-
"&",
|
|
631
|
-
"|",
|
|
632
|
-
"^",
|
|
633
|
-
"(",
|
|
634
|
-
")"
|
|
635
|
-
].includes(token)) {
|
|
636
|
-
regularMods.push(token);
|
|
637
|
-
isNegated = false;
|
|
638
|
-
} else isNegated = false;
|
|
639
|
-
}
|
|
640
|
-
}
|
|
641
|
-
if (advancedStates.length > 0) {
|
|
642
|
-
state.advancedStates = advancedStates;
|
|
643
|
-
state.atRuleContext = buildAtRuleContext(advancedStates, negatedAdvancedStates);
|
|
644
|
-
state.mods = regularMods;
|
|
645
|
-
}
|
|
646
|
-
if (ownMods.length > 0) state.ownMods = ownMods;
|
|
647
|
-
if (negatedOwnMods.length > 0) state.negatedOwnMods = negatedOwnMods;
|
|
648
|
-
stateDataList.push(state);
|
|
649
|
-
});
|
|
650
|
-
stateDataList.reverse();
|
|
651
|
-
let initialState;
|
|
652
|
-
const allMods = stateDataList.reduce((all, state) => {
|
|
653
|
-
if (!state.mods.length && !state.advancedStates?.length) initialState = state;
|
|
654
|
-
else state.mods.forEach((mod) => {
|
|
655
|
-
if (!all.includes(mod)) all.push(mod);
|
|
656
|
-
});
|
|
657
|
-
return all;
|
|
658
|
-
}, []);
|
|
659
|
-
if (!initialState) stateDataList.push({
|
|
660
|
-
mods: [],
|
|
661
|
-
notMods: allMods,
|
|
662
|
-
value: true
|
|
663
|
-
});
|
|
664
|
-
return {
|
|
665
|
-
states: stateDataList,
|
|
666
|
-
mods: allMods,
|
|
667
|
-
hasAdvancedStates
|
|
668
|
-
};
|
|
669
|
-
}
|
|
670
|
-
const COMPUTE_FUNC_MAP = {
|
|
671
|
-
"!": (a) => !a,
|
|
672
|
-
"^": (a, b) => a && !b || !a && b,
|
|
673
|
-
"|": (a, b) => a || b,
|
|
674
|
-
"&": (a, b) => a && b
|
|
675
|
-
};
|
|
676
|
-
/**
|
|
677
|
-
* Compute a result based on a model and incoming map.
|
|
678
|
-
*/
|
|
679
|
-
function computeState(computeModel, valueMap) {
|
|
680
|
-
if (!computeModel) return true;
|
|
681
|
-
const map = valueMap;
|
|
682
|
-
if (!Array.isArray(computeModel)) if (typeof valueMap === "function") return !!valueMap(computeModel);
|
|
683
|
-
else return !!map[computeModel];
|
|
684
|
-
const func = COMPUTE_FUNC_MAP[computeModel[0]];
|
|
685
|
-
if (!func) console.warn("CubeUIKit: unexpected compute method in the model", computeModel);
|
|
686
|
-
let a = computeModel[1];
|
|
687
|
-
if (typeof a === "object") a = !!computeState(a, valueMap);
|
|
688
|
-
else if (typeof valueMap === "function") a = !!valueMap(a);
|
|
689
|
-
else a = !!map[a];
|
|
690
|
-
if (computeModel.length === 2) return func(a);
|
|
691
|
-
let b = computeModel[2];
|
|
692
|
-
if (typeof b === "object") b = !!computeState(b, valueMap);
|
|
693
|
-
else if (typeof valueMap === "function") b = !!valueMap(b);
|
|
694
|
-
else b = !!map[b];
|
|
695
|
-
return !!func(a, b);
|
|
696
|
-
}
|
|
697
380
|
const _innerCache = /* @__PURE__ */ new WeakMap();
|
|
381
|
+
const _topLevelCache = /* @__PURE__ */ new WeakMap();
|
|
698
382
|
function stringifyStyles(styles) {
|
|
699
383
|
if (styles == null || typeof styles !== "object") return "";
|
|
384
|
+
const cached = _topLevelCache.get(styles);
|
|
385
|
+
if (cached !== void 0) return cached;
|
|
700
386
|
const obj = styles;
|
|
701
387
|
const keys = Object.keys(obj).sort();
|
|
702
388
|
const parts = [];
|
|
@@ -722,9 +408,11 @@ function stringifyStyles(styles) {
|
|
|
722
408
|
} else sv = JSON.stringify(v);
|
|
723
409
|
parts.push(JSON.stringify(k) + ":" + sv);
|
|
724
410
|
}
|
|
725
|
-
|
|
411
|
+
const result = "{" + parts.join(",") + "}";
|
|
412
|
+
_topLevelCache.set(styles, result);
|
|
413
|
+
return result;
|
|
726
414
|
}
|
|
727
415
|
|
|
728
416
|
//#endregion
|
|
729
|
-
export {
|
|
417
|
+
export { CUSTOM_UNITS, DIRECTIONS, customFunc, filterMods, getGlobalFuncs, getGlobalParser, getGlobalPredefinedTokens, getRgbValuesFromRgbaString, hexToRgb, normalizeColorTokenValue, parseColor, parseStyle, resetGlobalPredefinedTokens, setGlobalPredefinedTokens, strToRgb, stringifyStyles };
|
|
730
418
|
//# sourceMappingURL=styles.js.map
|