├── .editorconfig ├── .github ├── CODEOWNERS ├── FUNDING.yml ├── ci.yml ├── issue_template.md └── pull_request_template.md ├── .gitignore ├── .husky ├── commit-msg └── pre-commit ├── .npmignore ├── .prettierrc ├── BACKLOG.md ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── __tests__ └── index.spec.ts ├── babel.config.js ├── commitlint.config.js ├── demo ├── .gitignore ├── index.html ├── package.json ├── src │ ├── App.vue │ ├── components │ │ └── Button.vue │ ├── env.d.ts │ └── main.ts ├── tsconfig.json └── vite.config.ts ├── jest.config.ts ├── package.json ├── rollup.config.ts ├── src ├── demo.ts ├── index.ts └── types.ts ├── tsconfig.json └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | max_line_length=120 12 | 13 | [*.md] 14 | trim_trailing_whitespace = false 15 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # More details are here: https://help.github.com/articles/about-codeowners/ 2 | 3 | * @lukasborawski 4 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [lukasborawski] 4 | buymeacoffee: [lukasborawski] 5 | -------------------------------------------------------------------------------- /.github/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - develop 7 | pull_request: 8 | branches: 9 | - main 10 | - master 11 | - develop 12 | 13 | jobs: 14 | CI: 15 | runs-on: ${{ matrix.os }} 16 | 17 | strategy: 18 | matrix: 19 | os: [ubuntu-latest] 20 | node: [14] 21 | 22 | steps: 23 | - name: Checkout 🛎 24 | uses: actions/checkout@master 25 | 26 | - name: Setup node env 🏗 27 | uses: actions/setup-node@v2.1.5 28 | with: 29 | node-version: ${{ matrix.node }} 30 | check-latest: true 31 | 32 | - name: Cache node_modules 📦 33 | uses: actions/cache@v2 34 | with: 35 | path: ~/.npm 36 | key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} 37 | restore-keys: | 38 | ${{ runner.os }}-node- 39 | 40 | - name: Install dependencies 👨🏻‍💻 41 | run: npm ci 42 | 43 | - name: Run tests 🧪 44 | run: npm run test --passWithNoTests 45 | -------------------------------------------------------------------------------- /.github/issue_template.md: -------------------------------------------------------------------------------- 1 | **Description**: 2 | --- 3 | Some issue description. 4 | 5 | **Tasks**: 6 | --- 7 | - [ ] task name 8 | 9 | **Research**: 10 | --- 11 | None 12 | 13 | **Screenshots**: 14 | --- 15 | None 16 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | Closing: #[issue number] 2 | 3 | **Tasks**: 4 | --- 5 | * [ ] issue connected 6 | * [ ] summary 7 | * [ ] self review 8 | 9 | **Summary**: 10 | --- 11 | * *write here some summary points* 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Node template 3 | # Logs 4 | /logs 5 | *.log 6 | npm-debug.log* 7 | yarn-debug.log* 8 | lerna-debug.log* 9 | yarn-error.log* 10 | 11 | # Runtime data 12 | pids 13 | *.pid 14 | *.seed 15 | *.pid.lock 16 | 17 | # Directory for instrumented libs generated by jscoverage/JSCover 18 | lib-cov 19 | 20 | # Coverage directory used by tools like istanbul 21 | coverage 22 | 23 | # nyc test coverage 24 | .nyc_output 25 | 26 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 27 | .grunt 28 | 29 | # Bower dependency directory (https://bower.io/) 30 | bower_components 31 | 32 | # node-waf configuration 33 | .lock-wscript 34 | 35 | # Compiled binary addons (https://nodejs.org/api/addons.html) 36 | build/Release 37 | 38 | # Dependency directories 39 | node_modules/ 40 | jspm_packages/ 41 | 42 | # TypeScript v1 declaration files 43 | typings/ 44 | 45 | # Optional npm cache directory 46 | .npm 47 | 48 | # Optional eslint cache 49 | .eslintcache 50 | 51 | # Optional REPL history 52 | .node_repl_history 53 | 54 | # Output of 'npm pack' 55 | *.tgz 56 | 57 | # Yarn Integrity file 58 | .yarn-integrity 59 | 60 | # dotenv environment variables file 61 | .env 62 | 63 | # parcel-bundler cache (https://parceljs.org/) 64 | .cache 65 | 66 | # next.js build output 67 | .next 68 | 69 | # nuxt.js build output 70 | .nuxt 71 | 72 | # Nuxt generate 73 | dist 74 | 75 | # vuepress build output 76 | .vuepress/dist 77 | 78 | # Serverless directories 79 | .serverless 80 | 81 | # IDE / Editor 82 | .idea 83 | 84 | # Service worker 85 | sw.* 86 | 87 | # macOS 88 | .DS_Store 89 | 90 | # Vim swap files 91 | *.swp 92 | 93 | # Server 94 | .reify-cache 95 | **/**/.reify-cache 96 | 97 | lib 98 | .husky/_ 99 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npx --no-install commitlint --edit "$1" --config ./commitlint.config.js 5 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npx npm run test 5 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | coverage 3 | src 4 | demo 5 | __tests__ 6 | .husky 7 | .github 8 | 9 | .editorconfig 10 | .idea 11 | .prettierrc 12 | babel.config.js 13 | commitlint.config.js 14 | jest.config.ts 15 | rollup.config.ts 16 | tsconfig.json 17 | yarn.lock 18 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "endOfLine": "lf", 3 | "semi": false, 4 | "singleQuote": true, 5 | "arrowParens": "always", 6 | "tabWidth": 2, 7 | "trailingComma": "all" 8 | } 9 | -------------------------------------------------------------------------------- /BACKLOG.md: -------------------------------------------------------------------------------- 1 | ### Missing features, things to do: 2 | 3 | - [ ] get variants of top of array `[base, primary]` 4 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ### 0.1.2 2 | 3 | - handling variants as an array of strings [#1] 4 | - add demo more examples 5 | - output terser 6 | - docs update 7 | 8 | ### 0.1.1 9 | 10 | - removed unnecessary dependencies 11 | - add the demo missing types 12 | - docs update 13 | 14 | ### 0.1.0 15 | 16 | - initial package state 17 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | ISC License (ISC) 2 | Copyright 2021 Lukas Borawski 3 | 4 | Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. 5 | 6 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Vue Use Variant 2 | 3 | npm version 4 | npm version 5 | npm version 6 | npm version 7 | 8 | Simple composable for **Vue.js*** to handle long and ugly CSS class chaining. 9 | 10 | Read the story behind this package [here](https://itnext.io/tailwind-class-madness-never-again-75ec6ebfd3a0). 11 | 12 | **you can use it with any other framework as well* 13 | 14 | ### Install 15 | 16 | --- 17 | 18 | Install the package: 19 | 20 | ```bash 21 | $ npm i vue-use-variant --save 22 | # or 23 | $ yarn add vue-use-variant 24 | ``` 25 | 26 | ### Motivation 27 | 28 | --- 29 | 30 | We all know that systems like [Tailwind](https://tailwindcss.com) are awesome, but we also know that defining styles by using utility classes can be hard ... Let's say you are using Tailwind and you want to style some button with provided classes. Probably the definition will look something like this: 31 | 32 | ```vue 33 | 48 | ``` 49 | 50 | ... and this is just a button. Imagine whole markup for even tiny component. 51 | Readability of it will be - easy talking - not so great. So what **problems** we're facing here: 52 | 53 | - very long class definition 54 | - poor readability 55 | - lack of scalability 56 | - hard to maintain 57 | 58 | ### Usage 59 | 60 | --- 61 | 62 | To resolve these problems you can try `useVariant` composable. 63 | 64 | First define some variants. You can crate regular JSON object for it or use Vue `Ref`. 65 | 66 | ```javascript 67 | import { ref } from 'vue' 68 | 69 | export const buttonVariants = { 70 | button: 'font-bold rounded border-0 bg-blue hover:opacity-80', 71 | buttonPrimary: 'p-4 text-lg', 72 | buttonSecondary: 'p-2 text-md', 73 | } 74 | 75 | // or use with Vue Ref (Composition API) 76 | export const buttonVariantsRef = ref(buttonVariants) 77 | ``` 78 | 79 | Now let's see how we can use it with some real component example. 80 | 81 | ```vue 82 | 85 | 86 | 108 | ``` 109 | 110 | As a result your button will get this set of classes: 111 | 112 | ```vue 113 | font-bold rounded border-0 bg-blue hover:opacity-80 p-4 text-lg 114 | ``` 115 | 116 | --- 117 | 118 | You can also use it with **props**. 119 | 120 | ```vue 121 | 145 | ``` 146 | 147 | Use as an Array. 148 | 149 | ```vue 150 | 164 | ``` 165 | 166 | Use straight without variant definitions. 167 | 168 | ```vue 169 | 181 | ``` 182 | 183 | Finally, you can define your variants as composable argument. 184 | 185 | ```vue 186 | 200 | ``` 201 | 202 | Of course, you can **combine and mix** variants and use them as a global variations for 203 | your base, global and reusable components. It's super easy and convenient. You can 204 | of course use it with any **other UI System** like for example Boostrap or Vuetify. 205 | And maybe it was built for vue you can use it for any o**ther frameworks** like React. 206 | 207 | --- 208 | 209 | ### Demo 210 | 211 | Want to check or test it in action? Check out the simple app in the `demo` folder. 212 | 213 | --- 214 | 215 | **API Reference**: Check out the [types](src/types.ts) for API definitions. 216 | 217 | **Contribution**: Please add Pull Request to introduce some changes or fixes. 218 | 219 | **Support**: Want to support? [Buy me a coffee](https://www.buymeacoffee.com/lukas.borawski). 220 | 221 | Buy Me a Coffee 222 | 223 | -------------------------------------------------------------------------------- /__tests__/index.spec.ts: -------------------------------------------------------------------------------- 1 | import { useVariant } from '~/lib/index.es' 2 | 3 | describe('vue-use-variant', () => { 4 | const variantsDefinitions = { 5 | button: 'button-class', 6 | buttonPrimary: 'button-class-primary', 7 | } 8 | 9 | it('Renders class string with regular configuration', () => { 10 | const { defineVariant } = useVariant() 11 | const variants = defineVariant({ button: true, buttonPrimary: true }, variantsDefinitions) 12 | // @ts-ignore 13 | expect(variants).toBe('button-class button-class-primary') 14 | }) 15 | it('Renders class string with composable passed definitions', () => { 16 | const { defineVariant } = useVariant(variantsDefinitions) 17 | const variants = defineVariant({ button: true, buttonPrimary: true }) 18 | // @ts-ignore 19 | expect(variants).toBe('button-class button-class-primary') 20 | }) 21 | it('Renders class string with custom value', () => { 22 | const { defineVariant } = useVariant() 23 | const variants = defineVariant({ button: 'button-class-primary' }) 24 | // @ts-ignore 25 | expect(variants).toBe('button-class-primary') 26 | }) 27 | it('Renders class string with Vue Ref object', () => { 28 | const { defineVariant } = useVariant() 29 | const variants = defineVariant( 30 | { 31 | value: { 32 | button: true, 33 | buttonPrimary: true, 34 | }, 35 | }, 36 | variantsDefinitions, 37 | ) 38 | // @ts-ignore 39 | expect(variants).toBe('button-class button-class-primary') 40 | }) 41 | it('Renders class string with Vue props', () => { 42 | const { defineVariant } = useVariant() 43 | const props = { 44 | button: true, 45 | buttonProp: 'button-class-primary', 46 | } 47 | const variants = defineVariant({ ...props }, variantsDefinitions) 48 | // @ts-ignore 49 | expect(variants).toBe('button-class button-class-primary') 50 | }) 51 | it('Renders class string with an array', () => { 52 | const { defineVariant } = useVariant() 53 | const variants = defineVariant(['button', 'buttonPrimary'], variantsDefinitions) 54 | // @ts-ignore 55 | expect(variants).toBe('button-class button-class-primary') 56 | }) 57 | it('Fails when using wrong variants data', () => { 58 | // @ts-ignore 59 | global.console = { warn: jest.fn() } 60 | const { defineVariant } = useVariant() 61 | defineVariant({ button: { test: true }, buttonPrimary: true }, variantsDefinitions) 62 | // @ts-ignore 63 | expect(console.warn).toBeCalled() 64 | }) 65 | }) 66 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | [ 4 | '@babel/preset-env', 5 | { targets: { node: 'current' } } 6 | ], 7 | '@babel/preset-typescript', 8 | ], 9 | } 10 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['@commitlint/config-conventional'], 3 | } 4 | -------------------------------------------------------------------------------- /demo/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | dist 4 | dist-ssr 5 | *.local 6 | yarn.lock 7 | -------------------------------------------------------------------------------- /demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vue Use Variant Demo 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /demo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-use-variant-demo", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "dev": "vite", 6 | "build": "vue-tsc --noEmit && vite build", 7 | "serve": "vite preview", 8 | "clean": "rm -rf node_modules" 9 | }, 10 | "dependencies": { 11 | "vue": "^3.2.13", 12 | "vue-use-variant": "^0.1.2" 13 | }, 14 | "devDependencies": { 15 | "@vitejs/plugin-vue": "^1.9.0", 16 | "typescript": "^4.4.3", 17 | "vite": "^2.5.10", 18 | "vue-tsc": "^0.3.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /demo/src/App.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 8 | -------------------------------------------------------------------------------- /demo/src/components/Button.vue: -------------------------------------------------------------------------------- 1 | 40 | 41 | 49 | -------------------------------------------------------------------------------- /demo/src/env.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.vue' { 2 | import { DefineComponent } from 'vue' 3 | // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types 4 | const component: DefineComponent<{}, {}, any> 5 | export default component 6 | } 7 | -------------------------------------------------------------------------------- /demo/src/main.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import App from './App.vue' 3 | 4 | createApp(App).mount('#app') 5 | -------------------------------------------------------------------------------- /demo/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "useDefineForClassFields": true, 5 | "module": "esnext", 6 | "moduleResolution": "node", 7 | "strict": true, 8 | "jsx": "preserve", 9 | "sourceMap": true, 10 | "resolveJsonModule": true, 11 | "esModuleInterop": true, 12 | "lib": ["esnext", "dom"] 13 | }, 14 | "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"] 15 | } 16 | -------------------------------------------------------------------------------- /demo/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import vue from '@vitejs/plugin-vue' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [vue()] 7 | }) 8 | -------------------------------------------------------------------------------- /jest.config.ts: -------------------------------------------------------------------------------- 1 | import { Config } from '@jest/types' 2 | 3 | const config: Config.InitialOptions = { 4 | moduleNameMapper: { 5 | '^@/(.*)$': '/$1', 6 | '^~/(.*)$': '/$1', 7 | '^#/(.*)$': '/__tests__/$1', 8 | }, 9 | moduleFileExtensions: ['js', 'ts'], 10 | transform: { 11 | '\\.[jt]sx?$': 'babel-jest', 12 | '^.+\\.ts$': 'ts-jest', 13 | }, 14 | collectCoverage: false, 15 | testPathIgnorePatterns: [ 16 | '__tests__/(mocks|utils|integration)/', 17 | '/(node_modules)/', 18 | ], 19 | } 20 | 21 | export default config 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-use-variant", 3 | "version": "0.1.2", 4 | "description": "Vue.js CSS class variant resolver. Presented as handy composable.", 5 | "main": "lib/index.cjs.js", 6 | "module": "lib/index.es.js", 7 | "types": "lib/index.d.ts", 8 | "scripts": { 9 | "prepare": "husky install", 10 | "build": "rimraf ./lib/ && rollup -c", 11 | "dev": "rollup -c -w", 12 | "test": "jest", 13 | "prepublish": "yarn build" 14 | }, 15 | "files": [ 16 | "lib" 17 | ], 18 | "repository": { 19 | "type": "git", 20 | "url": "git+https://github.com/lukasborawski/vue-use-variant.git" 21 | }, 22 | "keywords": [ 23 | "vue", 24 | "vue3", 25 | "nuxt", 26 | "nuxt3", 27 | "composable", 28 | "tailwind", 29 | "javascript", 30 | "typescript" 31 | ], 32 | "author": "lukasborawski", 33 | "license": "ISC", 34 | "bugs": { 35 | "url": "https://github.com/lukasborawski/vue-use-variant/issues" 36 | }, 37 | "homepage": "https://github.com/lukasborawski/vue-use-variant#readme", 38 | "dependencies": { 39 | "typescript": "^4.4.3" 40 | }, 41 | "devDependencies": { 42 | "@babel/preset-env": "^7.15.6", 43 | "@babel/preset-typescript": "^7.15.0", 44 | "@commitlint/cli": "^13.1.0", 45 | "@commitlint/config-conventional": "^13.1.0", 46 | "@jest/types": "^27.1.1", 47 | "@types/mocha": "^9.0.0", 48 | "@types/node": "^16.9.6", 49 | "babel-jest": "^27.2.2", 50 | "husky": "^7.0.2", 51 | "jest": "^27.2.2", 52 | "prettier": "^2.4.1", 53 | "rimraf": "^3.0.2", 54 | "rollup": "^2.71.1", 55 | "rollup-plugin-dts": "^4.0.0", 56 | "rollup-plugin-typescript2": "^0.30.0", 57 | "rollup-plugin-terser": "^7.0.2", 58 | "ts-jest": "^27.0.5", 59 | "ts-node": "^10.2.1" 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /rollup.config.ts: -------------------------------------------------------------------------------- 1 | import pkg from './package.json' 2 | import typescript from 'rollup-plugin-typescript2' 3 | import dts from 'rollup-plugin-dts' 4 | import { terser } from 'rollup-plugin-terser' 5 | 6 | export default [ 7 | { 8 | input: 'src/index.ts', 9 | output: [ 10 | { 11 | file: pkg.main, 12 | format: 'cjs', 13 | sourcemap: true, 14 | }, 15 | { 16 | file: pkg.module, 17 | format: 'es', 18 | sourcemap: true, 19 | }, 20 | ], 21 | external: [...Object.keys(pkg.dependencies || {})], 22 | plugins: [ 23 | terser(), 24 | typescript({ 25 | // eslint-disable-next-line global-require 26 | typescript: require('typescript'), 27 | }), 28 | ], 29 | }, 30 | { 31 | input: 'src/types.ts', 32 | output: [{ file: 'lib/index.d.ts', format: 'es' }], 33 | plugins: [dts()], 34 | }, 35 | ] 36 | -------------------------------------------------------------------------------- /src/demo.ts: -------------------------------------------------------------------------------- 1 | import { useVariant } from '~/lib/index.es' 2 | import { UseVariant } from '~/lib' 3 | 4 | const { defineVariant } = useVariant() as UseVariant 5 | 6 | console.log(defineVariant({ value: { shadow: true } }, { shadow: 'shadow' })) 7 | console.log(defineVariant({ value: { shadow: true } }, { value: { shadow: 'shadow' } })) 8 | console.log(defineVariant({ shadow: true }, { shadow: 'shadow' })) 9 | console.log(defineVariant(['shadow'], { shadow: 'shadow' })) 10 | console.log(defineVariant({ value: ['shadow'] }, { shadow: 'shadow' })) 11 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { DefineVariant, ObjectRecord, UseVariantReturn } from './types' 2 | 3 | export const useVariant: UseVariantReturn = (definitions) => { 4 | const defineVariant: typeof DefineVariant = ($variants, $definitions) => { 5 | let _variants = ($variants as { value: ObjectRecord | string[] }).value || $variants 6 | const _definitions = definitions?.value || definitions || $definitions?.value || $definitions || {} 7 | 8 | try { 9 | if (Array.isArray(_variants)) _variants = Object.fromEntries(_variants.map((key) => [key, true])) 10 | return Object.keys(_variants) 11 | .map((key) => { 12 | if (typeof (_variants as ObjectRecord)[key] === 'object') throw Error() 13 | const value: string = key.split('Prop')[0] 14 | return typeof (_variants as ObjectRecord)[key] === 'boolean' 15 | ? !(_variants as ObjectRecord)[key] 16 | ? '' 17 | : (_definitions as ObjectRecord)[value.length > 0 ? value : key] 18 | : (_variants as ObjectRecord)[key] 19 | }) 20 | .join(' ') 21 | } catch (error) { 22 | console.warn('[useVariant] Wrong format - use string or boolean.') 23 | } 24 | } 25 | 26 | return { 27 | defineVariant, 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | export type ObjectRecord = { [keyof in string]: string | boolean } 2 | 3 | /* Vue Ref Object */ 4 | export function DefineVariant( 5 | $variants: { value: ObjectRecord | string[] }, 6 | $definitions?: { value: ObjectRecord }, 7 | ): void | string 8 | /* Vue Ref Object */ 9 | export function DefineVariant($variants: { value: ObjectRecord | string[] }, $definitions?: ObjectRecord): void | string 10 | /* Regular Object */ 11 | export function DefineVariant($variants: ObjectRecord, $definitions?: ObjectRecord): void | string 12 | /* Proxy */ 13 | export function DefineVariant($variants: ProxyConstructor, $definitions?: ObjectRecord): void | string 14 | /* Array */ 15 | export function DefineVariant($variants: string[], $definitions?: ObjectRecord): void | string 16 | /* Array */ 17 | export function DefineVariant($variants: string[], $definitions?: { value: ObjectRecord }): void | string 18 | /* Overloaded Object */ 19 | export function DefineVariant($variants: any, $definitions?: any): void | string { 20 | console.log('DefineVariant', $variants, $definitions) 21 | } 22 | 23 | export interface UseVariant { 24 | defineVariant: typeof DefineVariant 25 | } 26 | export type UseVariantReturn = (definitions?: ObjectRecord | { value: ObjectRecord }) => UseVariant 27 | 28 | /* @ts-ignore */ 29 | export function useVariant() 30 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2018", 4 | "module": "ESNext", 5 | "moduleResolution": "Node", 6 | "resolveJsonModule": true, 7 | "allowSyntheticDefaultImports": true, 8 | "lib": ["ESNext", "ESNext.AsyncIterable", "DOM"], 9 | "esModuleInterop": true, 10 | "allowJs": true, 11 | "sourceMap": true, 12 | "skipLibCheck": true, 13 | "strict": true, 14 | "noEmit": true, 15 | "experimentalDecorators": true, 16 | "baseUrl": ".", 17 | "paths": { 18 | "~/*": ["./*"], 19 | "@/*": ["./*"] 20 | }, 21 | "types": ["@types/node", "@jest/types", "@types/mocha"] 22 | }, 23 | "exclude": ["node_modules"] 24 | } 25 | --------------------------------------------------------------------------------