UNPKG

@oruga-ui/oruga-next

Version:

UI components for Vue.js and CSS framework agnostic

1 lines 15 kB
{"version":3,"file":"defineClasses-Cqhbv-UT.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":";;;;;AAkCa,MAAA,mBAAmB,CAC5B,YACW;AACL,QAAA,SAASA,YAAQ,OAAO;AAC1B,MAAA,CAAC,OAAQ,QAAO,CAAC;AACrB,SAAO,OAAO;AAAA,IAAQ,CAAC,SACnB,OAAO,KAAK,IAAI,EACX,OAAO,CAAC,QAAQ,OAAO,KAAK,GAAG,CAAC,EAChC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,CAAC;AAAA,EACpC;AACJ;AA2BO,SAAS,iBACT,MACa;AAEV,QAAA,UAAU,MAAM,QAAQ,KAAK,GAAG,EAAE,CAAC,IACnC,SACC,KAAK,GAAG,EAAE;AAGjB,QAAM,mBACF,MAAM,QAAQ,KAAK,GAAG,EAAE,CAAC,IAAI,OAAO,KAAK,MAAM,GAAG,EAAE;AAIxD,QAAM,KAAKC,IAAAA,mBAAmB;AAC9B,MAAI,CAAC;AACD,UAAM,IAAI;AAAA,MACN;AAAA,IACJ;AAEJ,MAAI,CAACC,IAAA,gBAAA,KAAqB,EAAC,mCAAS;AAChC,UAAM,IAAI;AAAA,MACN;AAAA,IACJ;AAGE,QAAA,SAAQ,mCAAS,UAASC,gBAAY;AAG5C,MAAID,oBAAgB;AAGhBE,QAAAA,eAAe,MAAM;AAEb,UAAA,aAAa,KAAK;AAAA,IAAA,CACzB;AAGC,QAAA,UAAUC,IAAiB,IAAA,EAAE;AAEnC,UAAQ,QAAQ,iBAAiB,IAAI,CAAC,WAAW,UAAU;AACjD,UAAA,YAAY,UAAU,CAAC;AACvB,UAAA,eAAe,UAAU,CAAC;AAC1B,UAAA,SAAS,UAAU,CAAC;AACpB,UAAA,QAAQ,UAAU,CAAC;AAEzB,aAAS,eAA0B;AAE/B,YAAM,gBAAgB;AAAA,QAClB;AAAA,QACA;AAAA,QACA;AAAA,QACAL,IAAA,QAAQ,MAAM,KAAK;AAAA,MACvB;AAGA,YAAM,UAAU,CAACM,QAAA,UAAU,KAAK,KAAKN,IAAAA,QAAQ,KAAK;AAGlD,aAAO,EAAE,CAAC,aAAa,GAAG,QAAQ;AAAA,IAAA;AAItC,UAAM,IAAI,MAAM;AAEZO,UAAA;AAAA,QACI;AAAA,UACI,MAAA;;AAAM,4BAAG,UAAH,mBAAU,OAAO;AAAA;AAAA,UACvB,OAAO,mCAAS,SAAQ,mCAAS,MAAM,aAAa;AAAA,QACxD;AAAA,QACA,MAAM;AAEF,gBAAM,YAAY,aAAa;AAEvB,kBAAA,MAAM,KAAK,IAAI;AAAA,QAAA;AAAA,MAE/B;AAGA,UAAID,QAAU,UAAA,MAAM,KAAKE,IAAA,MAAM,MAAM,GAAG;AAC9BD,YAAAA,MAAA,QAAQ,CAAC,OAAO,aAAa;AAE/B,cAAI,UAAU,SAAU;AAExB,gBAAM,YAAY,aAAa;AAEvB,kBAAA,MAAM,KAAK,IAAI;AAAA,QAAA,CAC1B;AAAA,MAAA;AAIL,UAAID,QAAU,UAAA,KAAK,KAAKE,IAAA,MAAM,KAAK,GAAG;AAC5BD,YAAAA,MAAA,OAAO,CAAC,SAAS,aAAa;AAEhC,cAAI,YAAY,SAAU;AAEpB,gBAAA,YAAY,QAAQ,MAAM,KAAK;AAE9B,iBAAA,KAAK,SAAS,EAAE;AAAA,YACnB,CAAC,QAAS,UAAU,GAAG,IAAI;AAAA,UAC/B;AAEQ,kBAAA,MAAM,KAAK,IAAI;AAAA,QAAA,CAC1B;AAAA,MAAA;AAAA,IACL,CACH;AAGD,WAAO,aAAa;AAAA,EAAA,CACvB;AAGM,SAAA;AACX;AAKA,SAAS,aACL,IACA,OACA,cACA,SAAS,IACH;;AAEA,QAAA,QAAQ,SAAS,EAAE;AAEnB,QAAA,gBAAuB,QAAG,UAAH,mBAAU,SAAS;AAChD,MAAI,CAAC;AACK,UAAA,IAAI,MAAM,iDAAiD;AAGrE,QAAME,WAAS,MAAM,aAAa,OAAO,CAAA,IAAKC,OAAAA,WAAW;AAKzD,MAAI,cACAC,QAAAA,eAAeF,UAAQ,GAAG,YAAY,IAAI,KAAK,QAAQ,KACvDE,QAAAA,eAAeF,UAAQ,GAAG,YAAY,IAAI,KAAK,EAAE;AAGjD,MAAA,aAAyCE,QAAAA,eAAe,OAAO,KAAK;AAGpE,MAAA,MAAM,QAAQ,UAAU,GAAG;AACd,iBAAA,WAAW,KAAK,GAAG;AAAA,EAAA;AAEhC,MAAA,OAAO,eAAe,YAAY;AAC5BC,UAAAA,SAAQ,SAAS,EAAE;AACZ,iBAAA,WAAW,QAAQA,MAAK;AAAA,EAAA,OAClC;AACU,iBAAA,gBAAgB,cAAc,IAAI,MAAM;AAAA,EAAA;AAIrD,MAAA,MAAM,QAAQ,WAAW,GAAG;AACd,kBAAA,YAAY,KAAK,GAAG;AAAA,EAAA;AAElC,MAAA,OAAO,gBAAgB,YAAY;AAC7BA,UAAAA,SAAQ,SAAS,EAAE;AACX,kBAAA,YAAY,QAAQA,MAAK;AAAA,EAAA,OACpC;AACW,kBAAA,gBAAgB,eAAe,IAAI,MAAM;AAAA,EAAA;AAIvD,MAAA,aAAa,SAAS,KAAK,GAAG;AAC9B,mBAAe,aAAa;AAAA,MACxB;AAAA,MACAC,QAAAA,iBAAiB,MAAM;AAAA,IAC3B;AAAA,EAAA,OACG;AACY,mBAAA,eAAeA,yBAAiB,MAAM;AAAA,EAAA;AAMzD,QAAM,iBACF,MAAM,YAAYF,QAAe,eAAAF,UAAQ,YAAY,KAAK;AAE9D,QAAM,gBAAgBE,QAAA;AAAA,IAClBF;AAAAA,IACA,GAAG,YAAY;AAAA,IACf;AAAA,EACJ;AAEA,QAAM,gBAAgBE,QAAA;AAAA,IAClBF;AAAAA,IACA,GAAG,YAAY,IAAI,KAAK;AAAA,IACxB;AAAA,EACJ;AAOA,MAAI,iBACA,GAAG,CAAC,gBAAgB,eAAe,EAAE,IAClCI,QAAAA,iBAAiB,WAAW,CAAC,IAC7BA,QAAA,iBAAiB,UAAU,CAAC,GAE9B,OACA,QAAQ,UAAU,GAAG;AAKpB,QAAA,yBACFF,QAAAA,eAAeF,UAAQ,kBAAkB;AAE7C,QAAM,wBAAuDE,QAAA;AAAA,IACzDF;AAAAA,IACA,GAAG,YAAY;AAAA,EACnB;AAGA,MAAI,uBAAuB;AACvB,qBAAiB,sBAAsB,cAAc;AAAA,aAGhD,wBAAwB;AAC7B,qBAAiB,uBAAuB,cAAc;AAAA,EAAA;AAGnD,SAAA;AACX;AAEA,SAAS,gBAAgB,OAAe,QAAwB;AACrD,SAAAI,QAAA,iBAAiB,KAAK,EACxB,MAAM,GAAG,EACT,OAAO,CAAC,QAAQ,IAAI,SAAS,CAAC,EAC9B,IAAI,CAAC,QAAQ,MAAMA,yBAAiB,MAAM,CAAC,EAC3C,KAAK,GAAG;AACjB;AAEA,MAAM,WAAW,CAAC,OAAkD;;AAChE,MAAI,UAAQ,QAAG,UAAH,mBAAU,WAAU,CAAC;AAIjC,UAAQ,OAAO,KAAK,KAAK,EACpB,OAAO,CAAC,QAAQ,IAAI,SAAS,OAAO,CAAC,EACrC,IAAI,CAAC,QAAQ,MAAM,GAAG,CAAC,EACvB,OAAO,CAAC,GAAG,OAAO,EAAE,GAAG,GAAG,GAAG,MAAM,KAAK;AAEtC,SAAA;AACX;;;"}