UNPKG

@oruga-ui/oruga-next

Version:

UI components for Vue.js and CSS framework agnostic

1 lines 15 kB
{"version":3,"file":"defineClasses-CEpmGBsu.cjs","sources":["../../src/composables/defineClasses.ts"],"sourcesContent":["import {\n ref,\n watch,\n isRef,\n toValue,\n getCurrentInstance,\n effectScope,\n onScopeDispose,\n getCurrentScope,\n type MaybeRefOrGetter,\n type Ref,\n type ComponentInternalInstance,\n type EffectScope,\n} from \"vue\";\n\nimport { getOptions } from \"@/utils/config\";\nimport { isDefined, blankIfUndefined, getValueByPath } from \"@/utils/helpers\";\n\nimport type {\n ClassBind,\n ComponentClass,\n ComponentProps,\n TransformFunction,\n} from \"@/types\";\n\n// named tuple as prop definition\ntype ComputedClass = readonly [\n className: string,\n defaultClass: string,\n suffix?: MaybeRefOrGetter<string | undefined> | null,\n apply?: MaybeRefOrGetter<boolean> | null,\n];\n\n/** Helper function to get all active classes from a class binding list */\nexport const getActiveClasses = (\n classes: MaybeRefOrGetter<ClassBind[]>,\n): string[] => {\n const values = toValue(classes);\n if (!values) return [];\n return values.flatMap((bind) =>\n Object.keys(bind)\n .filter((key) => key && bind[key])\n .flatMap((v) => v.split(\" \")),\n );\n};\n\ntype DefineClassesOptions = {\n /**\n * Pass a custom effect scope.\n * By default a new effect scope is created.\n * An error will be thrown if no current scope or a custom scope is given.\n * @default effectScope()\n */\n scope?: EffectScope;\n /**\n * Pass a custom props object which will be watched on additionaly to the current component instance props.\n * this will recompute the class bind property when the class property change.\n * @default vm.proxy?.$props\n */\n props?: Record<string, any>;\n};\n\nexport function defineClasses(\n ...args: [...ComputedClass[], DefineClassesOptions]\n): Ref<ClassBind[]>;\n\nexport function defineClasses(...args: [...ComputedClass[]]): Ref<ClassBind[]>;\n\n/**\n * Calculate dynamic classes based on class definitions\n */\nexport function defineClasses(\n ...args: ComputedClass[] | [...ComputedClass[], DefineClassesOptions]\n): Ref<ClassBind[]> {\n // extract last argument if its the option object\n const options = Array.isArray(args.at(-1))\n ? undefined\n : (args.at(-1) as DefineClassesOptions);\n\n // get class defintion list based on options are given or not\n const classDefinitions = (\n Array.isArray(args.at(-1)) ? args : args.slice(0, -1)\n ) as ComputedClass[];\n\n // getting a hold of the internal instance of the component in setup()\n const vm = getCurrentInstance();\n if (!vm)\n throw new Error(\n \"defineClasses must be called within a component setup function.\",\n );\n // check if there is no current active effect scope given\n if (!getCurrentScope() && !options?.scope)\n throw new Error(\n \"defineClasses must be called within a current active effect scope.\",\n );\n\n // create an effect scope object to capture reactive effects\n const scope = options?.scope || effectScope();\n\n // check if there is a current active effect scope\n if (getCurrentScope())\n // Registers a dispose callback on the current active effect scope.\n // The callback will be invoked when the associated effect scope is stopped.\n onScopeDispose(() => {\n // stop all effects when appropriate\n if (scope) scope.stop();\n });\n\n // reactive classes container\n const classes = ref<ClassBind[]>([]);\n\n classes.value = classDefinitions.map((defintion, index) => {\n const className = defintion[0];\n const defaultClass = defintion[1];\n const suffix = defintion[2];\n const apply = defintion[3];\n\n function getClassBind(): ClassBind {\n // compute class based on definition parameter\n const computedClass = computeClass(\n vm!,\n className,\n defaultClass,\n toValue(suffix) || undefined,\n );\n\n // if apply is not defined or true\n const applied = !isDefined(apply) || toValue(apply);\n\n // return class bind property\n return { [computedClass]: applied };\n }\n\n // run all watcher and computed properties in an active effect scope\n scope.run(() => {\n // recompute the class bind property when the class property change\n watch(\n [\n () => vm.proxy?.$props[className],\n () => (options?.props ? options?.props[className] : null),\n ],\n () => {\n // recompute the class bind property\n const classBind = getClassBind();\n // update class binding property by class index\n classes.value[index] = classBind;\n },\n );\n\n // if suffix is defined, watch suffix changed and recalculate class\n if (isDefined(suffix) && isRef(suffix)) {\n watch(suffix, (value, oldValue) => {\n // only recompute when value has really changed\n if (value === oldValue) return;\n // recompute the class bind property\n const classBind = getClassBind();\n // update class binding property by class index\n classes.value[index] = classBind;\n });\n }\n\n // if apply is defined, watch apply changed and update apply state (no need of recalculation here)\n if (isDefined(apply) && isRef(apply)) {\n watch(apply, (applied, oldValue) => {\n // only change apply when value has really changed\n if (applied === oldValue) return;\n // get class binding property by class index\n const classBind = classes.value[index];\n // update the apply class binding state\n Object.keys(classBind).forEach(\n (key) => (classBind[key] = applied),\n );\n // update the class binding property by class index\n classes.value[index] = classBind;\n });\n }\n });\n\n // return computed class based on parameter\n return getClassBind();\n });\n\n // return reactive classes\n return classes;\n}\n\n/**\n * Compute a class by a field name\n */\nfunction computeClass(\n vm: ComponentInternalInstance,\n field: string,\n defaultValue: string,\n suffix = \"\",\n): string {\n // get component props\n const props = getProps(vm);\n\n const componentKey: string = vm.proxy?.$options.configField;\n if (!componentKey)\n throw new Error(\"component must define the 'configField' option.\");\n\n // get component instance override property\n const config = props.override === true ? {} : getOptions();\n\n // --- Classes Definition ---\n\n // get component config class definition\n let globalClass: ComponentClass | undefined =\n getValueByPath(config, `${componentKey}.${field}.class`) ||\n getValueByPath(config, `${componentKey}.${field}`);\n\n // get instance class definition\n let localClass: ComponentClass | undefined = getValueByPath(props, field);\n\n // procsess local instance class\n if (Array.isArray(localClass)) {\n localClass = localClass.join(\" \");\n }\n if (typeof localClass === \"function\") {\n const props = getProps(vm);\n localClass = localClass(suffix, props);\n } else {\n localClass = suffixProcessor(localClass ?? \"\", suffix);\n }\n\n // process global config class\n if (Array.isArray(globalClass)) {\n globalClass = globalClass.join(\" \");\n }\n if (typeof globalClass === \"function\") {\n const props = getProps(vm);\n globalClass = globalClass(suffix, props);\n } else {\n globalClass = suffixProcessor(globalClass ?? \"\", suffix);\n }\n\n // process component instance default value\n if (defaultValue.includes(\"{*}\")) {\n defaultValue = defaultValue.replace(\n /\\{\\*\\}/g,\n blankIfUndefined(suffix),\n );\n } else {\n defaultValue = defaultValue + blankIfUndefined(suffix);\n }\n\n // --- Override Definition ---\n\n // get instance or global config override property\n const globalOverride =\n props.override || getValueByPath(config, \"override\", false);\n // get component config override property\n const localOverride = getValueByPath(\n config,\n `${componentKey}.override`,\n globalOverride,\n );\n // get component field config override property\n const overrideClass = getValueByPath(\n config,\n `${componentKey}.${field}.override`,\n localOverride,\n );\n\n // --- Define Applied Classes ---\n\n // if override is false add default value\n // add global config classes\n // add instance classes\n let appliedClasses = (\n `${!overrideClass ? defaultValue : \"\"} ` +\n `${blankIfUndefined(globalClass)} ` +\n `${blankIfUndefined(localClass)}`\n )\n .trim()\n .replace(/\\s\\s+/g, \" \");\n\n // --- Tranform Classes ---\n\n // get global config tranform class\n const globalTransformClasses: TransformFunction | undefined =\n getValueByPath(config, \"transformClasses\");\n // get component config tranform class\n const localTransformClasses: TransformFunction | undefined = getValueByPath(\n config,\n `${componentKey}.transformClasses`,\n );\n\n // apply component local transformclass if available\n if (localTransformClasses) {\n appliedClasses = localTransformClasses(appliedClasses);\n }\n // else apply global transformclass if available\n else if (globalTransformClasses) {\n appliedClasses = globalTransformClasses(appliedClasses);\n }\n\n return appliedClasses;\n}\n\nfunction suffixProcessor(input: string, suffix: string): string {\n return blankIfUndefined(input)\n .split(\" \")\n .filter((cls) => cls.length > 0)\n .map((cls) => cls + blankIfUndefined(suffix))\n .join(\" \");\n}\n\nconst getProps = (vm: ComponentInternalInstance): ComponentProps => {\n let props = vm.proxy?.$props || {};\n\n // get all props which ends with \"Props\", these are compressed parent props\n // append these parent props as root level prop\n props = Object.keys(props)\n .filter((key) => key.endsWith(\"Props\"))\n .map((key) => props[key])\n .reduce((a, b) => ({ ...a, ...b }), props);\n\n return props;\n};\n"],"names":["toValue","getCurrentInstance","getCurrentScope","effectScope","onScopeDispose","ref","isDefined","watch","isRef","config","getOptions","getValueByPath","props","blankIfUndefined"],"mappings":"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"}