UNPKG

vueless

Version:

Vue Styleless UI Component Library, powered by Tailwind CSS.

148 lines (123 loc) 3.98 kB
import { merge } from "lodash-es"; import { defineConfig } from "cva"; import { extendTailwindMerge } from "tailwind-merge"; import { isCSR, isSSR } from "./helper"; import { createGetMergedConfig } from "./node/mergeConfigs"; import { COMPONENT_NAME as U_ICON } from "../ui.image-icon/constants"; import { ICON_NON_PROPS_DEFAULTS, TAILWIND_MERGE_EXTENSION } from "../constants"; import type { Config, UnknownObject, ComponentNames, ComponentDefaults, ComponentCustomProps, } from "../types"; interface MergedConfigOptions { defaultConfig: unknown; globalConfig: unknown; propsConfig?: unknown; unstyled?: boolean; } type GetMergedConfig = (options: MergedConfigOptions) => unknown; /** * Load Vueless config from the project root. * Both for server and client side renderings. */ export let vuelessConfig: Config = {}; export function setVuelessConfig(config?: Config) { config = config || {}; vuelessConfig = Object.keys(config).length ? config : vuelessConfig; } if (isCSR) { vuelessConfig = Object.values( import.meta.glob(["/vueless.config.{js,ts}"], { eager: true, import: "default", }), )[0] || {}; } if (isSSR) { (async () => { try { // @ts-expect-error: vueless.config.{js,ts} is optional vuelessConfig = (await import(/* @vite-ignore */ "/vueless.config")).default; } catch { vuelessConfig = {}; } })(); } /** * Extend twMerge (tailwind merge) by vueless and user config: */ const twMerge = extendTailwindMerge(merge(TAILWIND_MERGE_EXTENSION, vuelessConfig.tailwindMerge)); /** * Export cva (class variance authority) methods: * – extended with tailwind-merge * – remove all Vueless nested component names ({U...} strings) from class list string. * Learn more here: https://beta.cva.style */ export const { cx, compose, cva: classVarianceAuthority, } = defineConfig({ hooks: { onComplete: (classNames) => twMerge(classNames), }, }); export const getMergedConfig = createGetMergedConfig(cx) as GetMergedConfig; /* This allows skipping some CVA config keys in vueless config. */ export const cva = ({ base = "", variants = {}, compoundVariants = [], defaultVariants = {} }) => classVarianceAuthority({ base, variants, compoundVariants, defaultVariants, }); /** * Return default values for component props, icons, etc.. */ export function getDefaults<Props, Config>(defaultConfig: Config, name: ComponentNames) { const componentDefaults = (defaultConfig as Config & UnknownObject).defaults || {}; const globalDefaults = vuelessConfig.components?.[name]?.defaults || {}; const customProps = vuelessConfig.components?.[name]?.props as ComponentCustomProps; const customPropsDefaults = getCustomPropsDefaults(customProps) || {}; const defaults = merge({}, componentDefaults, globalDefaults, customPropsDefaults) as Props & ComponentDefaults; /* Remove non a props defaults. */ for (const key in defaults) { const isNonPropIcon = /Icon/.test(key) && !/(leftIcon|rightIcon|toggleIcon|placeholderIcon)/.test(key); const isNonPropIconDefaults = ICON_NON_PROPS_DEFAULTS.includes(key) && name === U_ICON; if (isNonPropIcon || isNonPropIconDefaults) { delete defaults[key]; } } return { ...defaults, dataTest: "", config: () => ({}), }; } /** * Replace in tailwind classes `{color}` variable into given color. */ export function setColor(classes: string, color: string) { return classes?.replace(/{color}/g, color); } /** * Retrieves the default values from the provided component custom properties. */ export function getCustomPropsDefaults(props: ComponentCustomProps) { const customPropsDefaults: ComponentDefaults = {}; if (!props) { return customPropsDefaults; } for (const [key, value] of Object.entries(props)) { if (value.default) { customPropsDefaults[key] = value.default; } } return customPropsDefaults; }