├── .changeset ├── README.md ├── afraid-bottles-burn.md ├── chilly-apricots-repair.md ├── clean-radios-reply.md ├── clean-tigers-remain.md ├── config.json ├── cool-wolves-learn.md ├── cyan-frogs-pull.md ├── eighty-plants-tap.md ├── eleven-colts-run.md ├── fair-insects-dress.md ├── khaki-bees-rule.md ├── loud-eyes-search.md ├── lucky-gifts-do.md ├── moody-cougars-switch.md ├── odd-falcons-trade.md ├── old-shrimps-yawn.md ├── old-toes-sniff.md ├── poor-roses-attend.md ├── pre.json ├── proud-singers-shout.md ├── red-papayas-rescue.md ├── rotten-pants-reflect.md ├── short-guests-travel.md ├── sixty-rings-cross.md ├── sour-kids-enjoy.md ├── sweet-bags-confess.md ├── sweet-masks-return.md ├── swift-ties-sell.md ├── two-schools-dance.md ├── unlucky-bears-fry.md ├── warm-eels-search.md └── wicked-olives-drive.md ├── .gitignore ├── .husky └── pre-commit ├── .vscode ├── extensions.json └── settings.json ├── LICENSE ├── README.md ├── biome.json ├── package.json ├── packages ├── config.ts ├── core │ ├── .gitignore │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ │ ├── create.ts │ │ ├── group │ │ │ ├── create.ts │ │ │ ├── index.ts │ │ │ ├── types.ts │ │ │ └── utils.ts │ │ ├── index.ts │ │ ├── slots │ │ │ ├── create.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── types.ts │ │ └── utils.ts │ ├── tsconfig.json │ └── vite.config.ts ├── preact │ ├── .gitignore │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ │ ├── create.tsx │ │ ├── index.tsx │ │ ├── mono │ │ │ ├── create.tsx │ │ │ ├── index.tsx │ │ │ └── types.ts │ │ ├── types │ │ │ ├── index.ts │ │ │ ├── polymorphic.ts │ │ │ ├── preact.ts │ │ │ └── utils.ts │ │ └── utils.ts │ ├── tsconfig.json │ └── vite.config.ts ├── qwik │ ├── .gitignore │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ │ ├── create.tsx │ │ ├── index.tsx │ │ ├── mono │ │ │ ├── create.tsx │ │ │ ├── index.tsx │ │ │ └── types.ts │ │ ├── types │ │ │ ├── index.ts │ │ │ ├── polymorphic.ts │ │ │ ├── qwik.ts │ │ │ └── utils.ts │ │ └── utils.ts │ ├── tsconfig.json │ └── vite.config.ts ├── react │ ├── .gitignore │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ │ ├── create.tsx │ │ ├── index.tsx │ │ ├── mono │ │ │ ├── create.tsx │ │ │ ├── index.tsx │ │ │ └── types.ts │ │ ├── types │ │ │ ├── index.ts │ │ │ ├── polymorphic.ts │ │ │ ├── react.ts │ │ │ └── utils.ts │ │ └── utils.ts │ ├── tsconfig.json │ └── vite.config.ts ├── solid │ ├── .gitignore │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ │ ├── create.tsx │ │ ├── index.tsx │ │ ├── mono │ │ │ ├── create.tsx │ │ │ ├── index.tsx │ │ │ └── types.ts │ │ ├── types │ │ │ ├── index.ts │ │ │ ├── polymorphic.ts │ │ │ ├── solid.ts │ │ │ └── utils.ts │ │ └── utils.ts │ ├── tsconfig.json │ └── vite.config.ts └── vue │ ├── .gitignore │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ ├── create.tsx │ ├── index.tsx │ ├── mono │ │ ├── create.tsx │ │ ├── index.tsx │ │ └── types.ts │ ├── types │ │ ├── index.ts │ │ ├── polymorphic.ts │ │ ├── utils.ts │ │ └── vue.ts │ └── utils.ts │ ├── tsconfig.json │ └── vite.config.ts ├── pnpm-lock.yaml ├── pnpm-workspace.yaml ├── tests ├── config.ts ├── core │ ├── index.test.ts │ ├── package.json │ ├── tsconfig.json │ ├── utils.ts │ └── vitest.config.ts ├── preact │ ├── index.test.tsx │ ├── package.json │ ├── tsconfig.json │ ├── utils.ts │ └── vitest.config.ts ├── qwik │ ├── index.test.tsx │ ├── package.json │ ├── tsconfig.json │ ├── utils.ts │ └── vitest.config.ts ├── react-18 │ ├── index.test.tsx │ ├── package.json │ ├── tsconfig.json │ ├── utils.ts │ └── vitest.config.ts ├── react │ ├── ecosystem │ │ └── ark-ui.test.tsx │ ├── index.test.tsx │ ├── package.json │ ├── tsconfig.json │ ├── utils.ts │ └── vitest.config.ts ├── shared │ ├── fixtures │ │ ├── compose.ts │ │ ├── index.ts │ │ ├── klass.ts │ │ └── reklass.ts │ ├── package.json │ └── utils.ts ├── solid │ ├── ecosystem │ │ └── ark-ui.test.tsx │ ├── index.test.tsx │ ├── package.json │ ├── tsconfig.json │ ├── utils.ts │ └── vitest.config.ts └── vue │ ├── ecosystem │ └── ark-ui.test.tsx │ ├── index.test.tsx │ ├── package.json │ ├── tsconfig.json │ ├── utils.ts │ └── vitest.config.ts ├── tsconfig.json ├── turbo.json └── vitest.config.ts /.changeset/README.md: -------------------------------------------------------------------------------- 1 | # Changesets 2 | 3 | Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works 4 | with multi-package repos, or single-package repos to help you version and publish your code. You can 5 | find the full documentation for it [in our repository](https://github.com/changesets/changesets) 6 | 7 | We have a quick list of common questions to get you started engaging with this project in 8 | [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) 9 | -------------------------------------------------------------------------------- /.changeset/afraid-bottles-burn.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@klass/core": patch 3 | "@klass/preact": patch 4 | "@klass/qwik": patch 5 | "@klass/react": patch 6 | "@klass/solid": patch 7 | "@klass/vue": patch 8 | --- 9 | 10 | Optimizations 11 | -------------------------------------------------------------------------------- /.changeset/chilly-apricots-repair.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@klass/core": patch 3 | "@klass/preact": patch 4 | "@klass/qwik": patch 5 | "@klass/react": patch 6 | "@klass/solid": patch 7 | "@klass/vue": patch 8 | --- 9 | 10 | named import and base fn 11 | -------------------------------------------------------------------------------- /.changeset/clean-radios-reply.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@klass/core": patch 3 | "@klass/preact": patch 4 | "@klass/qwik": patch 5 | "@klass/react": patch 6 | "@klass/solid": patch 7 | "@klass/vue": patch 8 | --- 9 | 10 | initialization improvements 11 | -------------------------------------------------------------------------------- /.changeset/clean-tigers-remain.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@klass/core": major 3 | "@klass/preact": major 4 | "@klass/react": major 5 | "@klass/solid": major 6 | --- 7 | 8 | Enter prerelease mode for v4 9 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@3.1.1/schema.json", 3 | "changelog": "@changesets/cli/changelog", 4 | "commit": false, 5 | "fixed": [["@klass/core", "@klass/preact", "@klass/qwik", "@klass/react", "@klass/solid", "@klass/vue"]], 6 | "linked": [], 7 | "access": "restricted", 8 | "baseBranch": "main", 9 | "updateInternalDependencies": "patch", 10 | "ignore": ["@test/core", "@test/preact", "@test/qwik", "@test/react", "@test/react-18", "@test/shared", "@test/solid", "@test/vue"] 11 | } 12 | -------------------------------------------------------------------------------- /.changeset/cool-wolves-learn.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@klass/core": patch 3 | "@klass/preact": patch 4 | "@klass/qwik": patch 5 | "@klass/react": patch 6 | "@klass/solid": patch 7 | "@klass/vue": patch 8 | --- 9 | 10 | Update README.md 11 | -------------------------------------------------------------------------------- /.changeset/cyan-frogs-pull.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@klass/core": patch 3 | "@klass/preact": patch 4 | "@klass/qwik": patch 5 | "@klass/react": patch 6 | "@klass/solid": patch 7 | "@klass/vue": patch 8 | --- 9 | 10 | fix polymorphism 11 | -------------------------------------------------------------------------------- /.changeset/eighty-plants-tap.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@klass/core": patch 3 | "@klass/preact": patch 4 | "@klass/qwik": patch 5 | "@klass/react": patch 6 | "@klass/solid": patch 7 | "@klass/vue": patch 8 | --- 9 | 10 | Optimization 11 | -------------------------------------------------------------------------------- /.changeset/eleven-colts-run.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@klass/core": patch 3 | "@klass/preact": patch 4 | "@klass/qwik": patch 5 | "@klass/react": patch 6 | "@klass/solid": patch 7 | "@klass/vue": patch 8 | --- 9 | 10 | clean type, fix dts and feat new mono setup 11 | -------------------------------------------------------------------------------- /.changeset/fair-insects-dress.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@klass/core": patch 3 | "@klass/preact": patch 4 | "@klass/qwik": patch 5 | "@klass/react": patch 6 | "@klass/solid": patch 7 | "@klass/vue": patch 8 | --- 9 | 10 | compose with string 11 | -------------------------------------------------------------------------------- /.changeset/khaki-bees-rule.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@klass/core": patch 3 | "@klass/preact": patch 4 | "@klass/qwik": patch 5 | "@klass/react": patch 6 | "@klass/solid": patch 7 | "@klass/vue": patch 8 | --- 9 | 10 | Types improvements and new frameworks monomorphic feature 11 | -------------------------------------------------------------------------------- /.changeset/loud-eyes-search.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@klass/preact": patch 3 | "@klass/react": patch 4 | "@klass/solid": patch 5 | "@klass/core": patch 6 | "@klass/qwik": patch 7 | "@klass/vue": patch 8 | --- 9 | 10 | better workspaces 11 | -------------------------------------------------------------------------------- /.changeset/lucky-gifts-do.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@klass/core": patch 3 | "@klass/preact": patch 4 | "@klass/qwik": patch 5 | "@klass/react": patch 6 | "@klass/solid": patch 7 | "@klass/vue": patch 8 | --- 9 | 10 | README 11 | -------------------------------------------------------------------------------- /.changeset/moody-cougars-switch.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@klass/core": patch 3 | "@klass/preact": patch 4 | "@klass/qwik": patch 5 | "@klass/react": patch 6 | "@klass/solid": patch 7 | "@klass/vue": patch 8 | --- 9 | 10 | remove o property and rename component to fx property 11 | -------------------------------------------------------------------------------- /.changeset/odd-falcons-trade.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@klass/core": patch 3 | "@klass/preact": patch 4 | "@klass/qwik": patch 5 | "@klass/react": patch 6 | "@klass/solid": patch 7 | "@klass/vue": patch 8 | --- 9 | 10 | optimization 11 | -------------------------------------------------------------------------------- /.changeset/old-shrimps-yawn.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@klass/core": patch 3 | "@klass/preact": patch 4 | "@klass/qwik": patch 5 | "@klass/react": patch 6 | "@klass/solid": patch 7 | "@klass/vue": patch 8 | --- 9 | 10 | test improvements 11 | -------------------------------------------------------------------------------- /.changeset/old-toes-sniff.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@klass/core": patch 3 | "@klass/preact": patch 4 | "@klass/qwik": patch 5 | "@klass/react": patch 6 | "@klass/solid": patch 7 | "@klass/vue": patch 8 | --- 9 | 10 | fix build 11 | -------------------------------------------------------------------------------- /.changeset/poor-roses-attend.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@klass/core": patch 3 | "@klass/preact": patch 4 | "@klass/qwik": patch 5 | "@klass/react": patch 6 | "@klass/solid": patch 7 | "@klass/vue": patch 8 | --- 9 | 10 | klasses function options, setup API and utils entry 11 | -------------------------------------------------------------------------------- /.changeset/pre.json: -------------------------------------------------------------------------------- 1 | { 2 | "mode": "pre", 3 | "tag": "next", 4 | "initialVersions": { 5 | "@klass/core": "3.4.11", 6 | "@klass/preact": "3.4.11", 7 | "@klass/react": "3.4.11", 8 | "@klass/solid": "3.4.11", 9 | "@klass/qwik": "4.0.0-next.1", 10 | "@klass/vue": "4.0.0-next.1", 11 | "@klass/tests": "0.0.0", 12 | "@test/core": "0.0.0", 13 | "@test/preact": "0.0.0", 14 | "@test/qwik": "0.0.0", 15 | "@test/react": "0.0.0", 16 | "@test/react-18": "0.0.0", 17 | "@test/shared": "0.0.0", 18 | "@test/solid": "0.0.0", 19 | "@test/vue": "0.0.0" 20 | }, 21 | "changesets": [ 22 | "afraid-bottles-burn", 23 | "chilly-apricots-repair", 24 | "clean-radios-reply", 25 | "clean-tigers-remain", 26 | "cool-wolves-learn", 27 | "cyan-frogs-pull", 28 | "eighty-plants-tap", 29 | "eleven-colts-run", 30 | "fair-insects-dress", 31 | "khaki-bees-rule", 32 | "loud-eyes-search", 33 | "lucky-gifts-do", 34 | "moody-cougars-switch", 35 | "odd-falcons-trade", 36 | "old-shrimps-yawn", 37 | "old-toes-sniff", 38 | "poor-roses-attend", 39 | "proud-singers-shout", 40 | "red-papayas-rescue", 41 | "rotten-pants-reflect", 42 | "short-guests-travel", 43 | "sixty-rings-cross", 44 | "sour-kids-enjoy", 45 | "sweet-bags-confess", 46 | "sweet-masks-return", 47 | "swift-ties-sell", 48 | "two-schools-dance", 49 | "unlucky-bears-fry", 50 | "warm-eels-search", 51 | "wicked-olives-drive" 52 | ] 53 | } 54 | -------------------------------------------------------------------------------- /.changeset/proud-singers-shout.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@klass/core": patch 3 | "@klass/preact": patch 4 | "@klass/react": patch 5 | "@klass/solid": patch 6 | --- 7 | 8 | Performance improvement 9 | -------------------------------------------------------------------------------- /.changeset/red-papayas-rescue.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@klass/core": patch 3 | "@klass/preact": patch 4 | "@klass/qwik": patch 5 | "@klass/react": patch 6 | "@klass/solid": patch 7 | "@klass/vue": patch 8 | --- 9 | 10 | refactoring typescript features 11 | -------------------------------------------------------------------------------- /.changeset/rotten-pants-reflect.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@klass/core": patch 3 | "@klass/preact": patch 4 | "@klass/qwik": patch 5 | "@klass/react": patch 6 | "@klass/solid": patch 7 | "@klass/vue": patch 8 | --- 9 | 10 | fix types 11 | -------------------------------------------------------------------------------- /.changeset/short-guests-travel.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@klass/core": patch 3 | "@klass/preact": patch 4 | "@klass/qwik": patch 5 | "@klass/react": patch 6 | "@klass/solid": patch 7 | "@klass/vue": patch 8 | --- 9 | 10 | stricts customization only with top-level configurations 11 | -------------------------------------------------------------------------------- /.changeset/sixty-rings-cross.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@klass/core": patch 3 | "@klass/preact": patch 4 | "@klass/qwik": patch 5 | "@klass/react": patch 6 | "@klass/solid": patch 7 | "@klass/vue": patch 8 | --- 9 | 10 | New Vue and Qwik packages 11 | -------------------------------------------------------------------------------- /.changeset/sour-kids-enjoy.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@klass/core": patch 3 | "@klass/preact": patch 4 | "@klass/qwik": patch 5 | "@klass/react": patch 6 | "@klass/solid": patch 7 | "@klass/vue": patch 8 | --- 9 | 10 | frameworks compatibility 11 | -------------------------------------------------------------------------------- /.changeset/sweet-bags-confess.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@klass/core": patch 3 | "@klass/preact": patch 4 | "@klass/qwik": patch 5 | "@klass/react": patch 6 | "@klass/solid": patch 7 | "@klass/vue": patch 8 | --- 9 | 10 | Testing improvements 11 | -------------------------------------------------------------------------------- /.changeset/sweet-masks-return.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@klass/core": patch 3 | "@klass/preact": patch 4 | "@klass/qwik": patch 5 | "@klass/react": patch 6 | "@klass/solid": patch 7 | "@klass/vue": patch 8 | --- 9 | 10 | refactor modules fix types and feat setup 11 | -------------------------------------------------------------------------------- /.changeset/swift-ties-sell.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@klass/core": patch 3 | "@klass/preact": patch 4 | "@klass/qwik": patch 5 | "@klass/react": patch 6 | "@klass/solid": patch 7 | "@klass/vue": patch 8 | --- 9 | 10 | improves compatibility 11 | -------------------------------------------------------------------------------- /.changeset/two-schools-dance.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@klass/core": patch 3 | "@klass/preact": patch 4 | "@klass/qwik": patch 5 | "@klass/react": patch 6 | "@klass/solid": patch 7 | "@klass/vue": patch 8 | --- 9 | 10 | Optimization 11 | -------------------------------------------------------------------------------- /.changeset/unlucky-bears-fry.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@klass/core": patch 3 | "@klass/preact": patch 4 | "@klass/qwik": patch 5 | "@klass/react": patch 6 | "@klass/solid": patch 7 | "@klass/vue": patch 8 | --- 9 | 10 | experimental compose 11 | -------------------------------------------------------------------------------- /.changeset/warm-eels-search.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@klass/core": patch 3 | "@klass/preact": patch 4 | "@klass/qwik": patch 5 | "@klass/react": patch 6 | "@klass/solid": patch 7 | "@klass/vue": patch 8 | --- 9 | 10 | fix test & build and type improvements 11 | -------------------------------------------------------------------------------- /.changeset/wicked-olives-drive.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@klass/core": patch 3 | "@klass/preact": patch 4 | "@klass/qwik": patch 5 | "@klass/react": patch 6 | "@klass/solid": patch 7 | "@klass/vue": patch 8 | --- 9 | 10 | build improvements 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .turbo 3 | dist -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | pnpm test 2 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["biomejs.biome"] 3 | } 4 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.defaultFormatter": "biomejs.biome", 3 | "javascript.preferences.importModuleSpecifier": "non-relative", 4 | "typescript.preferences.importModuleSpecifier": "non-relative" 5 | } 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 flamrdevs 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /biome.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", 3 | "vcs": { 4 | "enabled": true, 5 | "clientKind": "git", 6 | "useIgnoreFile": true 7 | }, 8 | "formatter": { 9 | "enabled": true, 10 | "indentStyle": "tab", 11 | "lineWidth": 200 12 | }, 13 | "organizeImports": { 14 | "enabled": true 15 | }, 16 | "linter": { 17 | "enabled": false 18 | }, 19 | "javascript": { 20 | "formatter": { 21 | "quoteStyle": "double", 22 | "semicolons": "always", 23 | "trailingCommas": "es5" 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@klass/workspace", 3 | "type": "module", 4 | "private": true, 5 | "scripts": { 6 | "preinstall": "npx only-allow pnpm", 7 | "prepare": "husky", 8 | "build": "turbo run build", 9 | "pretest": "pnpm run build", 10 | "test": "vitest run", 11 | "pretestui": "pnpm run build", 12 | "testui": "vitest --ui", 13 | "prepublint": "pnpm run build", 14 | "publint": "pnpm --parallel --filter=\"@klass/*\" exec publint", 15 | "format": "biome check --write", 16 | "inspect": "pnpx node-modules-inspector" 17 | }, 18 | "devDependencies": { 19 | "@babel/plugin-transform-react-jsx": "7.25.9", 20 | "@babel/plugin-transform-react-jsx-development": "7.25.9", 21 | "@biomejs/biome": "1.9.4", 22 | "@builder.io/qwik": "1.13.0", 23 | "@changesets/cli": "2.29.2", 24 | "@preact/preset-vite": "2.10.1", 25 | "@preact/signals": "2.0.4", 26 | "@testing-library/dom": "10.4.0", 27 | "@testing-library/jest-dom": "6.6.3", 28 | "@types/node": "22.15.3", 29 | "@types/react": "19.1.2", 30 | "@types/react-dom": "19.1.2", 31 | "@vitejs/plugin-react": "4.4.1", 32 | "@vitejs/plugin-vue": "5.2.3", 33 | "@vitejs/plugin-vue-jsx": "4.1.2", 34 | "@vitest/ui": "3.1.2", 35 | "babel-plugin-transform-hook-names": "1.0.2", 36 | "husky": "9.1.7", 37 | "jsdom": "26.1.0", 38 | "preact": "10.26.5", 39 | "publint": "0.3.12", 40 | "react": "19.1.0", 41 | "react-dom": "19.1.0", 42 | "solid-js": "1.9.5", 43 | "terser": "5.39.0", 44 | "turbo": "2.5.2", 45 | "typescript": "5.8.3", 46 | "vite": "6.3.3", 47 | "vite-plugin-dts": "4.5.3", 48 | "vite-plugin-solid": "2.11.6", 49 | "vite-tsconfig-paths": "^5.1.4", 50 | "vitest": "3.1.2", 51 | "vue": "3.5.13" 52 | }, 53 | "packageManager": "pnpm@10.8.1", 54 | "engines": { 55 | "node": ">=23.0.0" 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /packages/config.ts: -------------------------------------------------------------------------------- 1 | import fs from "node:fs"; 2 | import path from "node:path"; 3 | 4 | import type { BuildEnvironmentOptions, LibraryOptions } from "vite"; 5 | 6 | import dtsPlugin, { type PluginOptions as dtsPluginOptions } from "vite-plugin-dts"; 7 | 8 | export const dts = (include: string[], options?: dtsPluginOptions) => dtsPlugin({ include, staticImport: true, ...options }); 9 | 10 | const cwd = process.cwd(); 11 | 12 | const packagedotjson = JSON.parse(fs.readFileSync(path.resolve(cwd, "package.json"), "utf-8")); 13 | 14 | type MutableOptions = { lib: LibraryOptions }; 15 | 16 | export const build = (src: string[], mutate?: (options: MutableOptions) => void) => { 17 | const options: Omit & MutableOptions = { 18 | target: "esnext", 19 | outDir: "dist", 20 | minify: "terser", 21 | lib: { 22 | entry: src.map((e) => `src/${e}`), 23 | fileName: (format, entry) => `${entry}.${format === "cjs" ? "cjs" : "js"}`, 24 | formats: ["es", "cjs"], 25 | }, 26 | rollupOptions: { 27 | external: (() => { 28 | return ((objects: (Record | undefined)[]) => { 29 | const result: RegExp[] = []; 30 | 31 | let deps: string[] = []; 32 | for (const object of objects) { 33 | if (typeof object === "object") { 34 | if ((deps = Object.keys(object)).length) for (const dep of deps) result.push(new RegExp(`^${dep}(?:/.+)?$`)); 35 | } 36 | } 37 | 38 | return result; 39 | })([packagedotjson.dependencies, packagedotjson.peerDependencies]); 40 | })(), 41 | output: { 42 | exports: "named", 43 | preserveModules: true, 44 | }, 45 | }, 46 | }; 47 | 48 | mutate?.(options); 49 | 50 | return options; 51 | }; 52 | -------------------------------------------------------------------------------- /packages/core/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | .turbo 4 | 5 | dist 6 | -------------------------------------------------------------------------------- /packages/core/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 |

4 |

klass

5 |

6 | 7 |

8 | 9 | license 10 | 11 | 12 | version 13 | 14 | 15 | size 16 | 17 | downloads 18 |

19 | 20 | # @klass/core 21 | 22 | ## Introduction 23 | 24 | Class variant utility 25 | 26 | ## Documentation 27 | 28 | 29 | license 30 | 31 | 32 | ## Installation 33 | 34 | ```sh 35 | npm install @klass/core 36 | # or 37 | yarn add @klass/core 38 | # or 39 | pnpm add @klass/core 40 | # or 41 | bun add @klass/core 42 | ``` 43 | 44 | ## Usage 45 | 46 | ```tsx 47 | import { klass, reklass } from "@klass/core"; 48 | 49 | const button = klass({ 50 | base: "inline-flex items-center justify-center rounded-md outline-none", 51 | variants: { 52 | color: { 53 | default: "bg-neutral-700 text-white", 54 | primary: "bg-indigo-700 text-white", 55 | secondary: "bg-orange-700 text-white", 56 | }, 57 | size: { 58 | sm: "px-3 py-0.5 h-7 text-sm font-medium", 59 | md: "px-4 py-1 h-8 text-base font-medium", 60 | lg: "px-5 py-1.5 h-9 text-lg font-semibold", 61 | }, 62 | block: { 63 | true: "w-full", 64 | }, 65 | }, 66 | defaults: { 67 | color: "default", 68 | size: "md", 69 | }, 70 | }); 71 | 72 | const box = reklass({ 73 | conditions: [ 74 | { 75 | base: "", 76 | sm: "sm:", 77 | md: "md:", 78 | lg: "lg:", 79 | xl: "xl:", 80 | "2xl": "2xl:", 81 | }, 82 | "base", 83 | ], 84 | variants: { 85 | m: { 86 | "0": "m-0", 87 | "1": "m-1", 88 | "2": "m-2", 89 | "3": "m-3", 90 | "4": "m-4", 91 | "5": "m-5", 92 | "6": "m-6", 93 | "7": "m-7", 94 | "8": "m-8", 95 | }, 96 | p: { 97 | "0": "p-0", 98 | "1": "p-1", 99 | "2": "p-2", 100 | "3": "p-3", 101 | "4": "p-4", 102 | "5": "p-5", 103 | "6": "p-6", 104 | "7": "p-7", 105 | "8": "p-8", 106 | }, 107 | }, 108 | }); 109 | 110 | button({ color: "primary", block: true }); // "inline-flex items-center justify-center rounded-md outline-none bg-indigo-700 text-white px-4 py-1 h-8 text-base font-medium w-full" 111 | // access variant 112 | button.g.color("primary"); // "bg-indigo-700 text-white" 113 | 114 | box({ m: "1", p: "2" }); // "m-1 p-1" 115 | box({ m: { base: "1", md: "2" }, p: { base: "1", md: "2" } }); // "m-1 md:m-2 p-1 md:p-2" 116 | // access revariant 117 | box.g.m("1"); // "m-1"; 118 | box.g.p({ base: "1", md: "2" }); // "p-1 md:p-2" 119 | ``` 120 | 121 | ## Authors 122 | 123 |

124 | 125 | 126 | 127 | github 128 | 129 | 130 |

131 | 132 | ## License 133 | 134 | [MIT License](https://github.com/flamrdevs/klass/blob/main/LICENSE) 135 | -------------------------------------------------------------------------------- /packages/core/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@klass/core", 3 | "version": "4.0.0-next.29", 4 | "description": "Class variant utility", 5 | "keywords": [ 6 | "class", 7 | "classname", 8 | "variant", 9 | "variants", 10 | "utility", 11 | "responsive", 12 | "typescript", 13 | "framework-agnostic", 14 | "preact", 15 | "qwik", 16 | "react", 17 | "solid", 18 | "vue" 19 | ], 20 | "license": "MIT", 21 | "author": { 22 | "name": "flamrdevs" 23 | }, 24 | "type": "module", 25 | "main": "./dist/index.cjs", 26 | "types": "./dist/index.d.ts", 27 | "exports": { 28 | ".": { 29 | "types": "./dist/index.d.ts", 30 | "import": "./dist/index.js", 31 | "require": "./dist/index.cjs" 32 | }, 33 | "./create": { 34 | "types": "./dist/create.d.ts", 35 | "import": "./dist/create.js", 36 | "require": "./dist/create.cjs" 37 | }, 38 | "./utils": { 39 | "types": "./dist/utils.d.ts", 40 | "import": "./dist/utils.js", 41 | "require": "./dist/utils.cjs" 42 | }, 43 | "./group": { 44 | "types": "./dist/group/index.d.ts", 45 | "import": "./dist/group/index.js", 46 | "require": "./dist/group/index.cjs" 47 | }, 48 | "./group/create": { 49 | "types": "./dist/group/create.d.ts", 50 | "import": "./dist/group/create.js", 51 | "require": "./dist/group/create.cjs" 52 | }, 53 | "./slots": { 54 | "types": "./dist/slots/index.d.ts", 55 | "import": "./dist/slots/index.js", 56 | "require": "./dist/slots/index.cjs" 57 | }, 58 | "./slots/create": { 59 | "types": "./dist/slots/create.d.ts", 60 | "import": "./dist/slots/create.js", 61 | "require": "./dist/slots/create.cjs" 62 | } 63 | }, 64 | "typesVersions": { 65 | ">=3.1": { 66 | "*": [ 67 | "./dist/*.d.ts", 68 | "./dist/index.d.ts" 69 | ], 70 | "group": [ 71 | "./dist/group/*.d.ts", 72 | "./dist/group/index.d.ts" 73 | ], 74 | "slots": [ 75 | "./dist/slots/*.d.ts", 76 | "./dist/slots/index.d.ts" 77 | ] 78 | } 79 | }, 80 | "files": [ 81 | "dist" 82 | ], 83 | "homepage": "https://klass.pages.dev", 84 | "repository": { 85 | "type": "git", 86 | "url": "git+https://github.com/flamrdevs/klass.git", 87 | "directory": "packages/core" 88 | }, 89 | "scripts": { 90 | "build": "vite build" 91 | }, 92 | "dependencies": { 93 | "clsx": "^2" 94 | }, 95 | "publishConfig": { 96 | "access": "public" 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /packages/core/src/group/create.ts: -------------------------------------------------------------------------------- 1 | import type { ClassValue, Klass } from "./../"; 2 | 3 | import type { Group, GroupOptions, GroupResult, StrictGroupVariantsSchema, ToVariantsSchema } from "./types"; 4 | 5 | const compoundsFilterFn = >(value: T) => typeof value[1] !== "undefined"; 6 | 7 | const createGroup = /* @__PURE__ */ (klass: Klass): Group => { 8 | return >(options: GroupOptions): GroupResult => { 9 | const { base: _base, variants: _variants, defaults: _defaults, compounds: _compounds } = options; 10 | 11 | const klasses = {} as GroupResult; 12 | 13 | const variantsTypesEntries: { v: keyof T; t: [string, { [key in B]?: ClassValue }][] }[] = []; 14 | for (const v in _variants) variantsTypesEntries.push({ v, t: Object.entries(_variants[v]) }); 15 | 16 | for (const base in _base) { 17 | klasses[base] = klass>({ 18 | base: _base[base], 19 | variants: variantsTypesEntries.reduce( 20 | (obj, { v, t }) => ((obj[v] = t.reduce((obj, [type, bases]) => ((obj[type] = bases[base]), obj), {} as { [type: string]: ClassValue })), obj), 21 | {} as { [variant in keyof T]: { [type: string]: ClassValue } } 22 | ) as any, 23 | defaults: _defaults, 24 | compounds: _compounds?.map(([variants, _class]) => [variants, _class?.[base]] as const).filter(compoundsFilterFn) as any, 25 | }); 26 | } 27 | 28 | return klasses; 29 | }; 30 | }; 31 | 32 | export { createGroup }; 33 | -------------------------------------------------------------------------------- /packages/core/src/group/index.ts: -------------------------------------------------------------------------------- 1 | import { createGroup } from "./create"; 2 | 3 | import { klass } from "./../"; 4 | 5 | const group = /* @__PURE__ */ createGroup(klass); 6 | 7 | export type * from "./types"; 8 | export * from "./utils"; 9 | export default group; 10 | -------------------------------------------------------------------------------- /packages/core/src/group/types.ts: -------------------------------------------------------------------------------- 1 | import type { ClassValue, KlassFn, TransformKey, VariantsOf } from "./../"; 2 | 3 | type StrictGroupVariantsSchema = { 4 | [variant: string]: { 5 | [type: string]: { [key in B]?: ClassValue }; 6 | }; 7 | }; 8 | 9 | type ToVariantsSchema> = { 10 | [variant in keyof T]: { 11 | [type in keyof T[variant]]: ClassValue; 12 | }; 13 | }; 14 | 15 | type GroupCompoundVariant> = [ 16 | { 17 | [K in keyof ToVariantsSchema]?: TransformKey[K]>; 18 | }, 19 | { 20 | [key in B]?: ClassValue; 21 | }, 22 | ]; 23 | 24 | type GroupOptions> = { 25 | base: { [key in B]: ClassValue }; 26 | variants: T; 27 | defaults?: { [K in keyof T]?: TransformKey }; 28 | compounds?: GroupCompoundVariant[]; 29 | }; 30 | 31 | type GroupResult> = { 32 | [key in B]: KlassFn>; 33 | }; 34 | 35 | type Group = >(options: GroupOptions) => GroupResult; 36 | 37 | type VariantsOfGroup = T extends GroupResult> ? VariantsOf : never; 38 | 39 | export type { StrictGroupVariantsSchema, ToVariantsSchema, GroupCompoundVariant, GroupOptions, GroupResult, Group, VariantsOfGroup }; 40 | -------------------------------------------------------------------------------- /packages/core/src/group/utils.ts: -------------------------------------------------------------------------------- 1 | import type { TransformKey } from "./../"; 2 | 3 | import { GroupResult, StrictGroupVariantsSchema } from "./types"; 4 | 5 | const simplify = 6 | /* @__PURE__ */ 7 | 8 | >(group: GroupResult) => 9 | (props?: { [K in keyof T]?: TransformKey }) => { 10 | const result = {} as { [key in B]: string }; 11 | for (const base in group) result[base] = group[base](props); 12 | return result; 13 | }; 14 | 15 | export { simplify }; 16 | -------------------------------------------------------------------------------- /packages/core/src/index.ts: -------------------------------------------------------------------------------- 1 | import { clsx } from "clsx"; 2 | 3 | import { createCompose, createKlass, createReklass } from "./create"; 4 | 5 | const klass = /* @__PURE__ */ createKlass(); 6 | const reklass = /* @__PURE__ */ createReklass(); 7 | const compose = /* @__PURE__ */ createCompose(); 8 | 9 | export type * from "./types"; 10 | export type { ClassValue } from "clsx"; 11 | export { clsx, klass, reklass, compose }; 12 | -------------------------------------------------------------------------------- /packages/core/src/slots/create.ts: -------------------------------------------------------------------------------- 1 | import type { Group, GroupOptions, StrictGroupVariantsSchema } from "./../group"; 2 | 3 | import type { KlassedOnly, Slots, SlotsFn } from "./types"; 4 | 5 | const createSlots = /* @__PURE__ */ (group: Group): Slots => { 6 | return >(options: GroupOptions): SlotsFn => { 7 | const klasses = group(options); 8 | 9 | const fn = ((props = {}) => { 10 | const klassesonly = {} as KlassedOnly; 11 | for (const base in klasses) klassesonly[base] = (_props = {}, classes) => klasses[base]({ ...props, ..._props }, classes); 12 | return klassesonly; 13 | }) as SlotsFn; 14 | 15 | fn.klass = klasses; 16 | 17 | return fn; 18 | }; 19 | }; 20 | 21 | export { createSlots }; 22 | -------------------------------------------------------------------------------- /packages/core/src/slots/index.ts: -------------------------------------------------------------------------------- 1 | import { createSlots } from "./create"; 2 | 3 | import group from "./../group"; 4 | 5 | const slots = /* @__PURE__ */ createSlots(group); 6 | 7 | export type * from "./types"; 8 | export default slots; 9 | -------------------------------------------------------------------------------- /packages/core/src/slots/types.ts: -------------------------------------------------------------------------------- 1 | import type { ClassValue, TransformKey, VariantsOf } from "./../"; 2 | 3 | import type { GroupOptions, GroupResult, StrictGroupVariantsSchema } from "./../group"; 4 | 5 | type KlassOnlyFn> = (props?: { [K in keyof T]?: TransformKey }, classes?: ClassValue) => string; 6 | 7 | type KlassedOnly> = { 8 | [key in B]: KlassOnlyFn; 9 | }; 10 | 11 | type SlotsFn> = { 12 | (props?: { [K in keyof T]?: TransformKey }): KlassedOnly; 13 | } & { 14 | klass: GroupResult; 15 | }; 16 | 17 | type Slots = >(options: GroupOptions) => SlotsFn; 18 | 19 | type VariantsOfSlots = T extends SlotsFn> ? VariantsOf : never; 20 | 21 | export type { KlassOnlyFn, KlassedOnly, SlotsFn, Slots, VariantsOfSlots }; 22 | -------------------------------------------------------------------------------- /packages/core/src/types.ts: -------------------------------------------------------------------------------- 1 | import type { ClassValue } from "clsx"; 2 | 3 | type TransformKey = T extends "true" ? true : T extends "false" ? false : Exclude; 4 | 5 | type VariantsSchema = { 6 | [variant: string]: { 7 | [type: string]: ClassValue; 8 | }; 9 | }; 10 | 11 | type StrictVariantsSchema = VariantsSchema & { [variant in E]?: undefined }; 12 | 13 | type VariantFn = (value?: TransformKey) => string | undefined; 14 | 15 | type VariantGroup = { 16 | [K in keyof T]: VariantFn; 17 | }; 18 | 19 | type CompoundVariant = [{ [K in keyof T]?: TransformKey }, ClassValue]; 20 | 21 | type BaseFn = { 22 | (props?: P, classes?: ClassValue): string; 23 | g: G; 24 | k: (keyof T)[]; 25 | }; 26 | 27 | type KlassOptions = { 28 | base?: ClassValue; 29 | variants: T; 30 | defaults?: { [K in keyof T]?: TransformKey }; 31 | compounds?: CompoundVariant[]; 32 | }; 33 | 34 | type KlassFn = BaseFn< 35 | T, 36 | { 37 | [K in keyof T]?: TransformKey; 38 | }, 39 | VariantGroup 40 | >; 41 | 42 | type Klass = (options: KlassOptions) => KlassFn; 43 | 44 | type ConditionSchema = { 45 | [type: string]: string; 46 | }; 47 | 48 | type RevariantFn = (value?: TransformKey | { [condition in keyof C]?: TransformKey }) => string | undefined; 49 | 50 | type RevariantGroup = { 51 | [K in keyof T]: RevariantFn; 52 | }; 53 | 54 | type ReklassOptions = { 55 | conditions: [C, keyof C]; 56 | variants: T; 57 | }; 58 | 59 | type ReklassFn = BaseFn< 60 | T, 61 | { 62 | [K in keyof T]?: 63 | | TransformKey 64 | | { 65 | [condition in keyof C]?: TransformKey; 66 | }; 67 | }, 68 | RevariantGroup 69 | >; 70 | 71 | type Reklass = (options: ReklassOptions) => ReklassFn; 72 | 73 | type VariantsOf any> = Exclude[0], undefined>; 74 | type RequiredVariantsFrom = Omit & { [k in K]-?: T[k] }; 75 | 76 | type EndFn = (className: string) => string; 77 | type AsFn = (condition: string, className: string) => string; 78 | 79 | type EndFnProps = { end?: EndFn }; 80 | type AsFnProps = { as?: AsFn }; 81 | 82 | type UnionToIntersection = (U extends unknown ? (dU: U) => void : never) extends (mI: infer I) => void ? I & U : never; 83 | 84 | type Fx = { 85 | (props?: Record): string; 86 | k: string[]; 87 | }; 88 | 89 | type Fxs = string | Fx; 90 | type FxFrom = Exclude; 91 | 92 | type ComposeFn = { 93 | (props?: UnionToIntersection>, classes?: ClassValue): string; 94 | k: Fn["k"][number][]; 95 | }; 96 | 97 | type Compose = (...fx: [...T]) => ComposeFn>; 98 | 99 | export type { 100 | TransformKey, 101 | EndFn, 102 | AsFn, 103 | EndFnProps, 104 | AsFnProps, 105 | VariantsSchema, 106 | StrictVariantsSchema, 107 | VariantsOf, 108 | RequiredVariantsFrom, 109 | BaseFn, 110 | VariantFn, 111 | VariantGroup, 112 | CompoundVariant, 113 | KlassOptions, 114 | KlassFn, 115 | Klass, 116 | ConditionSchema, 117 | RevariantFn, 118 | RevariantGroup, 119 | ReklassOptions, 120 | ReklassFn, 121 | Reklass, 122 | UnionToIntersection, 123 | Fx, 124 | Fxs, 125 | FxFrom, 126 | ComposeFn, 127 | Compose, 128 | }; 129 | -------------------------------------------------------------------------------- /packages/core/src/utils.ts: -------------------------------------------------------------------------------- 1 | import { clsx } from "clsx"; 2 | import type { ClassValue } from "clsx"; 3 | 4 | import type { AsFn, EndFn } from "./types"; 5 | 6 | export const defaultEndFn: EndFn = /* @__PURE__ */ (value) => value; 7 | export const defaultAsFn: AsFn = /* @__PURE__ */ (condition, className) => `${condition}${className}`; 8 | 9 | export const normalizeVariant = /* @__PURE__ */ (variant: T) => { 10 | let result = {} as { [key in keyof T]: string }, 11 | key: keyof T; 12 | for (key in variant) result[key] = clsx(variant[key]); 13 | return result; 14 | }; 15 | 16 | export const typeofFunction = /* @__PURE__ */ (value: unknown): value is Function => typeof value === "function"; 17 | -------------------------------------------------------------------------------- /packages/core/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "forceConsistentCasingInFileNames": true, 5 | "target": "ESNext", 6 | "module": "ESNext", 7 | "lib": ["ESNext", "DOM", "DOM.Iterable"], 8 | "moduleResolution": "bundler", 9 | "esModuleInterop": true, 10 | "allowImportingTsExtensions": true, 11 | "allowSyntheticDefaultImports": true, 12 | "allowJs": true, 13 | "resolveJsonModule": true, 14 | "skipLibCheck": true, 15 | "strictNullChecks": true, 16 | "declaration": true, 17 | "removeComments": false, 18 | "noUnusedLocals": true, 19 | "noUnusedParameters": true, 20 | "noEmit": true 21 | }, 22 | "include": ["src"], 23 | "exclude": ["node_modules", "dist"] 24 | } 25 | -------------------------------------------------------------------------------- /packages/core/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | 3 | import { build, dts } from "../config"; 4 | 5 | export default defineConfig({ 6 | plugins: [dts(["src/**/*.ts"])], 7 | build: build(["utils.ts", "index.ts", "create.ts", "group/index.ts", "group/create.ts", "slots/index.ts", "slots/create.ts"]), 8 | }); 9 | -------------------------------------------------------------------------------- /packages/preact/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | .turbo 4 | 5 | dist 6 | -------------------------------------------------------------------------------- /packages/preact/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 |

4 |

klass

5 |

6 | 7 |

8 | 9 | license 10 | 11 | 12 | version 13 | 14 | 15 | size 16 | 17 | downloads 18 |

19 | 20 | # @klass/preact 21 | 22 | ## Introduction 23 | 24 | Class variant utility for Preact. 25 | 26 | ## Documentation 27 | 28 | 29 | license 30 | 31 | 32 | ## Installation 33 | 34 | ```sh 35 | npm install @klass/core @klass/preact 36 | # or 37 | yarn add @klass/core @klass/preact 38 | # or 39 | pnpm add @klass/core @klass/preact 40 | # or 41 | bun add @klass/core @klass/preact 42 | ``` 43 | 44 | ## Usage 45 | 46 | ```tsx 47 | import { klassed, reklassed } from "@klass/preact"; 48 | 49 | const Button = klassed( 50 | "button", 51 | { 52 | base: "inline-flex items-center justify-center rounded-md outline-none", 53 | variants: { 54 | color: { 55 | default: "bg-neutral-700 text-white", 56 | primary: "bg-indigo-700 text-white", 57 | secondary: "bg-orange-700 text-white", 58 | }, 59 | size: { 60 | sm: "px-3 py-0.5 h-7 text-sm font-medium", 61 | md: "px-4 py-1 h-8 text-base font-medium", 62 | lg: "px-5 py-1.5 h-9 text-lg font-semibold", 63 | }, 64 | block: { 65 | true: "w-full", 66 | }, 67 | // "class" & "className" variants are not allowed 68 | }, 69 | defaults: { 70 | color: "default", 71 | size: "md", 72 | }, 73 | }, 74 | { 75 | // default props 76 | dp: { 77 | type: "button", 78 | }, 79 | } 80 | ); 81 | 82 | const Box = reklassed("div", { 83 | conditions: [ 84 | { 85 | base: "", 86 | sm: "sm:", 87 | md: "md:", 88 | lg: "lg:", 89 | xl: "xl:", 90 | "2xl": "2xl:", 91 | }, 92 | "base", 93 | ], 94 | variants: { 95 | m: { 96 | "0": "m-0", 97 | "1": "m-1", 98 | "2": "m-2", 99 | "3": "m-3", 100 | "4": "m-4", 101 | "5": "m-5", 102 | "6": "m-6", 103 | "7": "m-7", 104 | "8": "m-8", 105 | }, 106 | p: { 107 | "0": "p-0", 108 | "1": "p-1", 109 | "2": "p-2", 110 | "3": "p-3", 111 | "4": "p-4", 112 | "5": "p-5", 113 | "6": "p-6", 114 | "7": "p-7", 115 | "8": "p-8", 116 | }, 117 | }, 118 | }); 119 | 120 | const App = () => { 121 | return ( 122 | 123 | 124 | 127 | 128 | 129 | 130 | 133 | 134 | 135 | ); 136 | }; 137 | 138 | export default App; 139 | ``` 140 | 141 | ## Authors 142 | 143 |

144 | 145 | 146 | 147 | github 148 | 149 | 150 |

151 | 152 | ## License 153 | 154 | [MIT License](https://github.com/flamrdevs/klass/blob/main/LICENSE) 155 | -------------------------------------------------------------------------------- /packages/preact/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@klass/preact", 3 | "version": "4.0.0-next.29", 4 | "description": "Class variant utility for Preact", 5 | "keywords": [ 6 | "class", 7 | "classname", 8 | "variant", 9 | "variants", 10 | "utility", 11 | "responsive", 12 | "typescript", 13 | "preact", 14 | "component", 15 | "styled", 16 | "polymorphic" 17 | ], 18 | "license": "MIT", 19 | "author": { 20 | "name": "flamrdevs" 21 | }, 22 | "type": "module", 23 | "main": "./dist/index.cjs", 24 | "types": "./dist/index.d.ts", 25 | "exports": { 26 | ".": { 27 | "types": "./dist/index.d.ts", 28 | "import": "./dist/index.js", 29 | "require": "./dist/index.cjs" 30 | }, 31 | "./create": { 32 | "types": "./dist/create.d.ts", 33 | "import": "./dist/create.js", 34 | "require": "./dist/create.cjs" 35 | }, 36 | "./utils": { 37 | "types": "./dist/utils.d.ts", 38 | "import": "./dist/utils.js", 39 | "require": "./dist/utils.cjs" 40 | }, 41 | "./mono": { 42 | "types": "./dist/mono/index.d.ts", 43 | "import": "./dist/mono/index.js", 44 | "require": "./dist/mono/index.cjs" 45 | }, 46 | "./mono/create": { 47 | "types": "./dist/mono/create.d.ts", 48 | "import": "./dist/mono/create.js", 49 | "require": "./dist/mono/create.cjs" 50 | } 51 | }, 52 | "typesVersions": { 53 | ">=3.1": { 54 | "*": [ 55 | "./dist/*.d.ts", 56 | "./dist/index.d.ts" 57 | ], 58 | "mono": [ 59 | "./dist/mono/*.d.ts", 60 | "./dist/mono/index.d.ts" 61 | ] 62 | } 63 | }, 64 | "files": [ 65 | "dist" 66 | ], 67 | "homepage": "https://klass.pages.dev", 68 | "repository": { 69 | "type": "git", 70 | "url": "git+https://github.com/flamrdevs/klass.git", 71 | "directory": "packages/preact" 72 | }, 73 | "scripts": { 74 | "build": "vite build" 75 | }, 76 | "peerDependencies": { 77 | "@klass/core": "workspace:*", 78 | "preact": "^10" 79 | }, 80 | "devDependencies": { 81 | "@klass/core": "workspace:*", 82 | "preact": "^10" 83 | }, 84 | "publishConfig": { 85 | "access": "public" 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /packages/preact/src/create.tsx: -------------------------------------------------------------------------------- 1 | import type { Compose, ComposeFn, ConditionSchema, FxFrom, Fxs, Klass, KlassFn, Reklass, ReklassFn } from "@klass/core"; 2 | import { typeofFunction } from "@klass/core/utils"; 3 | 4 | import type { 5 | ComponentConfig, 6 | ComposedComponent, 7 | ComposedComponentConfig, 8 | ComposedOptions, 9 | DefaultPropsConfig, 10 | FinalVariantsSchema, 11 | ForwardPropsConfig, 12 | KlassedComponent, 13 | KlassedOptions, 14 | ReklassedComponent, 15 | ReklassedOptions, 16 | } from "./types"; 17 | import type { ClassesProps, SupportedElementType } from "./types/preact"; 18 | 19 | import { getVariantKeys, maybeSignal, splitRestProps } from "./utils"; 20 | 21 | function create(element: ET, fn: KlassFn> | ReklassFn> | ComposeFn, config: DefaultPropsConfig & ForwardPropsConfig = {}) { 22 | const { class: defaultClass, className: defaultClassName, ...defaultProps } = (config.dp ?? {}) as ClassesProps, 23 | keys = getVariantKeys(fn.k); 24 | 25 | const Comp = (({ as: As = element as any, class: _class = defaultClass, className = defaultClassName, ...rest }) => { 26 | const splitted = splitRestProps(rest, keys, config.fp); 27 | 28 | return ; 29 | }) as any; 30 | 31 | return (Comp.fx = fn), Comp; 32 | } 33 | 34 | type Klassed = (element: ET, options: KlassedOptions, config?: ComponentConfig | undefined) => KlassedComponent; 35 | type Reklassed = ( 36 | element: ET, 37 | options: ReklassedOptions, 38 | config?: ComponentConfig 39 | ) => ReklassedComponent; 40 | type Composed = (element: ET, options: ComposedOptions, config?: ComposedComponentConfig>) => ComposedComponent>; 41 | 42 | const createKlassed = 43 | (klass: Klass): Klassed => 44 | (element, options, config) => 45 | /* @__PURE__ */ create(element, typeofFunction(options) ? options : klass(options), config) as any; 46 | const createReklassed = 47 | (reklass: Reklass): Reklassed => 48 | (element, options, config) => 49 | /* @__PURE__ */ create(element, typeofFunction(options) ? options : reklass(options), config) as any; 50 | const createComposed = 51 | (compose: Compose): Composed => 52 | (element, options, config) => 53 | /* @__PURE__ */ create(element, typeofFunction(options) ? options : compose(...options), config) as any; 54 | 55 | export { createKlassed, createReklassed, createComposed }; 56 | -------------------------------------------------------------------------------- /packages/preact/src/index.tsx: -------------------------------------------------------------------------------- 1 | import { compose, klass, reklass } from "@klass/core"; 2 | import type { 3 | AsFn, 4 | AsFnProps, 5 | BaseFn, 6 | Compose, 7 | ComposeFn, 8 | CompoundVariant, 9 | ConditionSchema, 10 | EndFn, 11 | EndFnProps, 12 | Fx, 13 | FxFrom, 14 | Fxs, 15 | Klass, 16 | KlassFn, 17 | KlassOptions, 18 | Reklass, 19 | ReklassFn, 20 | ReklassOptions, 21 | RequiredVariantsFrom, 22 | RevariantFn, 23 | RevariantGroup, 24 | StrictVariantsSchema, 25 | TransformKey, 26 | UnionToIntersection, 27 | VariantFn, 28 | VariantGroup, 29 | VariantsOf, 30 | VariantsSchema, 31 | } from "@klass/core"; 32 | 33 | import { createComposed, createKlassed, createReklassed } from "./create"; 34 | 35 | const klassed = /* @__PURE__ */ createKlassed(klass); 36 | 37 | const reklassed = /* @__PURE__ */ createReklassed(reklass); 38 | 39 | const composed = /* @__PURE__ */ createComposed(compose); 40 | 41 | export type { 42 | TransformKey, 43 | EndFn, 44 | AsFn, 45 | EndFnProps, 46 | AsFnProps, 47 | VariantsSchema, 48 | StrictVariantsSchema, 49 | VariantsOf, 50 | RequiredVariantsFrom, 51 | BaseFn, 52 | VariantFn, 53 | VariantGroup, 54 | CompoundVariant, 55 | KlassOptions, 56 | KlassFn, 57 | Klass, 58 | ConditionSchema, 59 | RevariantFn, 60 | RevariantGroup, 61 | ReklassOptions, 62 | ReklassFn, 63 | Reklass, 64 | UnionToIntersection, 65 | Fx, 66 | Fxs, 67 | FxFrom, 68 | ComposeFn, 69 | Compose, 70 | }; 71 | export type { ClassesValueProps, WithClassesValueProps, KlassedComponent, ReklassedComponent, ComposedComponent } from "./types"; 72 | export { klassed, reklassed, composed }; 73 | -------------------------------------------------------------------------------- /packages/preact/src/mono/create.tsx: -------------------------------------------------------------------------------- 1 | import type { Compose, ComposeFn, ConditionSchema, FxFrom, Fxs, Klass, KlassFn, Reklass, ReklassFn } from "@klass/core"; 2 | import { typeofFunction } from "@klass/core/utils"; 3 | 4 | import { ComposedOptions, DefaultPropsConfig, FinalVariantsSchema, ForwardPropsConfig, KlassedOptions, ReklassedOptions } from "./../types"; 5 | import type { ClassesProps, SupportedElementType } from "./../types/preact"; 6 | 7 | import { getVariantKeys, maybeSignal, splitRestProps } from "./../utils"; 8 | 9 | import type { ComponentConfig, ComposedComponentConfig, MonoComposedComponent, MonoKlassedComponent, MonoReklassedComponent } from "./types"; 10 | 11 | function create(Element: ET, fn: KlassFn> | ReklassFn> | ComposeFn, config: DefaultPropsConfig & ForwardPropsConfig = {}) { 12 | const { class: defaultClass, className: defaultClassName, ...defaultProps } = (config.dp ?? {}) as ClassesProps, 13 | keys = getVariantKeys(fn.k); 14 | 15 | const Comp = (({ class: _class = defaultClass, className = defaultClassName, ...rest }) => { 16 | const splitted = splitRestProps(rest, keys, config.fp); 17 | 18 | return ; 19 | }) as any; 20 | 21 | return (Comp.fx = fn), Comp; 22 | } 23 | 24 | type Klassed = ( 25 | element: ET, 26 | options: KlassedOptions, 27 | config?: ComponentConfig | undefined 28 | ) => MonoKlassedComponent; 29 | type Reklassed = ( 30 | element: ET, 31 | options: ReklassedOptions, 32 | config?: ComponentConfig 33 | ) => MonoReklassedComponent; 34 | type Composed = (element: ET, options: ComposedOptions, config?: ComposedComponentConfig>) => MonoComposedComponent>; 35 | 36 | const createKlassed = 37 | (klass: Klass): Klassed => 38 | (element, options, config) => 39 | /* @__PURE__ */ create(element, typeofFunction(options) ? options : klass(options), config) as any; 40 | const createReklassed = 41 | (reklass: Reklass): Reklassed => 42 | (element, options, config) => 43 | /* @__PURE__ */ create(element, typeofFunction(options) ? options : reklass(options), config) as any; 44 | const createComposed = 45 | (compose: Compose): Composed => 46 | (element, options, config) => 47 | /* @__PURE__ */ create(element, typeofFunction(options) ? options : compose(...options), config) as any; 48 | 49 | export type { MonoKlassedComponent, MonoReklassedComponent, MonoComposedComponent }; 50 | export { createKlassed, createReklassed, createComposed }; 51 | -------------------------------------------------------------------------------- /packages/preact/src/mono/index.tsx: -------------------------------------------------------------------------------- 1 | import { compose, klass, reklass } from "@klass/core"; 2 | import type { 3 | AsFn, 4 | AsFnProps, 5 | BaseFn, 6 | Compose, 7 | ComposeFn, 8 | CompoundVariant, 9 | ConditionSchema, 10 | EndFn, 11 | EndFnProps, 12 | Fx, 13 | FxFrom, 14 | Fxs, 15 | Klass, 16 | KlassFn, 17 | KlassOptions, 18 | Reklass, 19 | ReklassFn, 20 | ReklassOptions, 21 | RequiredVariantsFrom, 22 | RevariantFn, 23 | RevariantGroup, 24 | StrictVariantsSchema, 25 | TransformKey, 26 | UnionToIntersection, 27 | VariantFn, 28 | VariantGroup, 29 | VariantsOf, 30 | VariantsSchema, 31 | } from "@klass/core"; 32 | 33 | import { createComposed, createKlassed, createReklassed } from "./create"; 34 | 35 | const klassed = /* @__PURE__ */ createKlassed(klass); 36 | 37 | const reklassed = /* @__PURE__ */ createReklassed(reklass); 38 | 39 | const composed = /* @__PURE__ */ createComposed(compose); 40 | 41 | export type { 42 | TransformKey, 43 | EndFn, 44 | AsFn, 45 | EndFnProps, 46 | AsFnProps, 47 | VariantsSchema, 48 | StrictVariantsSchema, 49 | VariantsOf, 50 | RequiredVariantsFrom, 51 | BaseFn, 52 | VariantFn, 53 | VariantGroup, 54 | CompoundVariant, 55 | KlassOptions, 56 | KlassFn, 57 | Klass, 58 | ConditionSchema, 59 | RevariantFn, 60 | RevariantGroup, 61 | ReklassOptions, 62 | ReklassFn, 63 | Reklass, 64 | UnionToIntersection, 65 | Fx, 66 | Fxs, 67 | FxFrom, 68 | ComposeFn, 69 | Compose, 70 | }; 71 | export type { MonoKlassedComponent, MonoReklassedComponent, MonoComposedComponent } from "./types"; 72 | export { klassed, reklassed, composed }; 73 | -------------------------------------------------------------------------------- /packages/preact/src/mono/types.ts: -------------------------------------------------------------------------------- 1 | import type { JSX } from "preact"; 2 | 3 | import type { ComposeFn, ConditionSchema, Fx, KlassFn, ReklassFn, VariantsOf } from "@klass/core"; 4 | 5 | import { Base, DefaultPropsConfig, FinalVariantsSchema, ForwardPropsConfig, WithClassesValueProps } from "./../types"; 6 | import type { SignalishRecord, SupportedComponentProps, SupportedElementType } from "./../types/preact"; 7 | import { OverrideProps } from "./../types/utils"; 8 | 9 | export type ComponentConfig = DefaultPropsConfig> & ForwardPropsConfig; 10 | export type ComposedComponentConfig = DefaultPropsConfig> & ForwardPropsConfig; 11 | 12 | export type MonoKlassedComponent = { 13 | (props: WithClassesValueProps, SignalishRecord>>>>): JSX.Element; 14 | } & Base>; 15 | 16 | export type MonoReklassedComponent = { 17 | (props: WithClassesValueProps, SignalishRecord>>>>): JSX.Element; 18 | } & Base>; 19 | 20 | export type MonoComposedComponent = { 21 | (props: WithClassesValueProps, SignalishRecord>>>>): JSX.Element; 22 | } & Base>; 23 | -------------------------------------------------------------------------------- /packages/preact/src/types/index.ts: -------------------------------------------------------------------------------- 1 | import type { JSX } from "preact"; 2 | 3 | import type { ClassValue, ComposeFn, ConditionSchema, Fx, FxFrom, Fxs, KlassFn, KlassOptions, ReklassFn, ReklassOptions, StrictVariantsSchema, VariantsOf } from "@klass/core"; 4 | 5 | import type { PolymorphicComponentProps } from "./polymorphic"; 6 | import type { BaseComponent, Classes, SignalishRecord, SupportedElementType } from "./preact"; 7 | 8 | export type FinalRestrictedVariantsKey = Classes; 9 | export type FinalVariantsSchema = StrictVariantsSchema; 10 | 11 | export type ClassesValueProps = Partial>>; 12 | export type WithClassesValueProps

= Omit & ClassesValueProps; 13 | 14 | export type KlassedOptions = KlassOptions | KlassFn; 15 | export type ReklassedOptions = ReklassOptions | ReklassFn; 16 | export type ComposedOptions = Fn[] | ComposeFn>; 17 | 18 | export type DefaultPropsConfig> = { dp?: DP }; 19 | export type ForwardPropsConfig = { fp?: T[] }; 20 | export type ComponentConfig = DefaultPropsConfig> & ForwardPropsConfig; 21 | export type ComposedComponentConfig = DefaultPropsConfig> & ForwardPropsConfig; 22 | 23 | export type Base = BaseComponent & { fx: F }; 24 | 25 | export type KlassedComponent = { 26 | (props: PolymorphicComponentProps>>>>): JSX.Element; 27 | } & Base>; 28 | 29 | export type ReklassedComponent = { 30 | (props: PolymorphicComponentProps>>>>): JSX.Element; 31 | } & Base>; 32 | 33 | export type ComposedComponent = { 34 | (props: PolymorphicComponentProps>>>>): JSX.Element; 35 | } & Base>; 36 | -------------------------------------------------------------------------------- /packages/preact/src/types/polymorphic.ts: -------------------------------------------------------------------------------- 1 | import type { ComponentChildren } from "preact"; 2 | 3 | import type { SupportedComponentProps, SupportedElementType } from "./preact"; 4 | 5 | type ResolveRefProps

= Omit & { 6 | ref?: P extends { 7 | ref?: infer Ref; 8 | } 9 | ? Ref 10 | : unknown; 11 | }; 12 | 13 | export type PolymorphicComponentProps = (Props & { 14 | as?: ET; 15 | } & { 16 | children?: ComponentChildren; 17 | }) & 18 | Omit>, "as" | keyof Props>; 19 | -------------------------------------------------------------------------------- /packages/preact/src/types/preact.ts: -------------------------------------------------------------------------------- 1 | import type { FunctionComponent, JSX } from "preact"; 2 | 3 | export type SignalishRecord> = { 4 | [K in keyof T]: JSX.Signalish; 5 | }; 6 | 7 | export type SupportedComponentType

= FunctionComponent

; 8 | 9 | export type SupportedComponentProps = T extends SupportedComponentType 10 | ? P 11 | : T extends keyof JSX.IntrinsicElements 12 | ? JSX.IntrinsicElements[T] 13 | : {}; 14 | 15 | export type SupportedElementType

= 16 | | { 17 | [K in keyof JSX.IntrinsicElements]: P extends JSX.IntrinsicElements[K] ? K : never; 18 | }[keyof JSX.IntrinsicElements] 19 | | SupportedComponentType

; 20 | 21 | export type Classes = "class" | "className"; 22 | export type ClassesProps = Partial>>; 23 | 24 | export type BaseComponent = { 25 | displayName?: string; 26 | }; 27 | -------------------------------------------------------------------------------- /packages/preact/src/types/utils.ts: -------------------------------------------------------------------------------- 1 | export type OverrideProps = Omit & W; 2 | -------------------------------------------------------------------------------- /packages/preact/src/utils.ts: -------------------------------------------------------------------------------- 1 | import type { JSX } from "preact/jsx-runtime"; 2 | 3 | import type { FinalRestrictedVariantsKey, FinalVariantsSchema } from "./types"; 4 | 5 | const getVariantKeys__filterFn = /* @__PURE__ */ (el: keyof VS) => el !== "class" && el !== "className"; 6 | export const getVariantKeys = /* @__PURE__ */ (keys: (keyof VS)[]) => 7 | keys.filter(getVariantKeys__filterFn) as unknown as Exclude[]; 8 | 9 | export const splitRestProps = /* @__PURE__ */

>(props: P, keys: string[], fkeys?: string[]) => { 10 | const o: /** omited */ Record = {}, 11 | p: /** picked */ Record = {}; 12 | let key: string; 13 | for (key in props) { 14 | const value = maybeSignal(props[key]); 15 | if (keys.includes(key)) { 16 | p[key] = value; 17 | if (fkeys?.includes(key)) o[key] = value; 18 | } else { 19 | o[key] = value; 20 | } 21 | } 22 | return { o, p } as const; 23 | }; 24 | 25 | export const isSignal = /* @__PURE__ */ (obj: any): obj is JSX.SignalLike => obj !== null && typeof obj === "object" && obj.brand === Symbol.for("preact-signals"); 26 | 27 | export const maybeSignal = /* @__PURE__ */ (obj: any): obj is T => (isSignal(obj) ? obj.value : obj); 28 | -------------------------------------------------------------------------------- /packages/preact/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "forceConsistentCasingInFileNames": true, 5 | "target": "ESNext", 6 | "module": "ESNext", 7 | "lib": ["ESNext", "DOM", "DOM.Iterable"], 8 | "moduleResolution": "bundler", 9 | "esModuleInterop": true, 10 | "allowImportingTsExtensions": true, 11 | "allowSyntheticDefaultImports": true, 12 | "allowJs": true, 13 | "resolveJsonModule": true, 14 | "skipLibCheck": true, 15 | "strictNullChecks": true, 16 | "declaration": true, 17 | "removeComments": false, 18 | "noUnusedLocals": true, 19 | "noUnusedParameters": true, 20 | "noEmit": true, 21 | "jsx": "react-jsx", 22 | "jsxImportSource": "preact" 23 | }, 24 | "include": ["src"], 25 | "exclude": ["node_modules", "dist"] 26 | } 27 | -------------------------------------------------------------------------------- /packages/preact/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | 3 | import preact from "@preact/preset-vite"; 4 | 5 | import { build, dts } from "../config"; 6 | 7 | export default defineConfig({ 8 | plugins: [preact(), dts(["src/**/*.{ts,tsx}"])], 9 | build: build(["utils.ts", "index.tsx", "create.tsx", "mono/index.tsx", "mono/create.tsx"]), 10 | }); 11 | -------------------------------------------------------------------------------- /packages/qwik/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | .turbo 4 | 5 | dist 6 | -------------------------------------------------------------------------------- /packages/qwik/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @klass/qwik 2 | 3 | ## 4.0.0-next.29 4 | 5 | ### Patch Changes 6 | 7 | - 7867f62: better workspaces 8 | - Updated dependencies [7867f62] 9 | - @klass/core@4.0.0-next.29 10 | 11 | ## 4.0.0-next.28 12 | 13 | ### Patch Changes 14 | 15 | - fix types 16 | - Updated dependencies 17 | - @klass/core@4.0.0-next.28 18 | 19 | ## 4.0.0-next.27 20 | 21 | ### Patch Changes 22 | 23 | - compose with string 24 | - Updated dependencies 25 | - @klass/core@4.0.0-next.27 26 | 27 | ## 4.0.0-next.26 28 | 29 | ### Patch Changes 30 | 31 | - build improvements 32 | - Updated dependencies 33 | - @klass/core@4.0.0-next.26 34 | 35 | ## 4.0.0-next.25 36 | 37 | ### Patch Changes 38 | 39 | - stricts customization only with top-level configurations 40 | - Updated dependencies 41 | - @klass/core@4.0.0-next.25 42 | 43 | ## 4.0.0-next.24 44 | 45 | ### Patch Changes 46 | 47 | - experimental compose 48 | - Updated dependencies 49 | - @klass/core@4.0.0-next.24 50 | 51 | ## 4.0.0-next.23 52 | 53 | ### Patch Changes 54 | 55 | - remove o property and rename component to fx property 56 | - Updated dependencies 57 | - @klass/core@4.0.0-next.23 58 | 59 | ## 4.0.0-next.22 60 | 61 | ### Patch Changes 62 | 63 | - improves compatibility 64 | - Updated dependencies 65 | - @klass/core@4.0.0-next.22 66 | 67 | ## 4.0.0-next.21 68 | 69 | ### Patch Changes 70 | 71 | - test improvements 72 | - Updated dependencies 73 | - @klass/core@4.0.0-next.21 74 | 75 | ## 4.0.0-next.20 76 | 77 | ### Patch Changes 78 | 79 | - fix polymorphism 80 | - Updated dependencies 81 | - @klass/core@4.0.0-next.20 82 | 83 | ## 4.0.0-next.19 84 | 85 | ### Patch Changes 86 | 87 | - frameworks compatibility 88 | - Updated dependencies 89 | - @klass/core@4.0.0-next.19 90 | 91 | ## 4.0.0-next.18 92 | 93 | ### Patch Changes 94 | 95 | - fix build 96 | - Updated dependencies 97 | - @klass/core@4.0.0-next.18 98 | 99 | ## 4.0.0-next.17 100 | 101 | ### Patch Changes 102 | 103 | - optimization 104 | - Updated dependencies 105 | - @klass/core@4.0.0-next.17 106 | 107 | ## 4.0.0-next.16 108 | 109 | ### Patch Changes 110 | 111 | - refactor modules fix types and feat setup 112 | - Updated dependencies 113 | - @klass/core@4.0.0-next.16 114 | 115 | ## 4.0.0-next.15 116 | 117 | ### Patch Changes 118 | 119 | - initialization improvements 120 | - Updated dependencies 121 | - @klass/core@4.0.0-next.15 122 | 123 | ## 4.0.0-next.14 124 | 125 | ### Patch Changes 126 | 127 | - fix test & build and type improvements 128 | - Updated dependencies 129 | - @klass/core@4.0.0-next.14 130 | 131 | ## 4.0.0-next.13 132 | 133 | ### Patch Changes 134 | 135 | - refactoring typescript features 136 | - Updated dependencies 137 | - @klass/core@4.0.0-next.13 138 | 139 | ## 4.0.0-next.12 140 | 141 | ### Patch Changes 142 | 143 | - clean type, fix dts and feat new mono setup 144 | - Updated dependencies 145 | - @klass/core@4.0.0-next.12 146 | 147 | ## 4.0.0-next.11 148 | 149 | ### Patch Changes 150 | 151 | - named import and base fn 152 | - Updated dependencies 153 | - @klass/core@4.0.0-next.11 154 | 155 | ## 4.0.0-next.10 156 | 157 | ### Patch Changes 158 | 159 | - Update README.md 160 | - Updated dependencies 161 | - @klass/core@4.0.0-next.10 162 | 163 | ## 4.0.0-next.9 164 | 165 | ### Patch Changes 166 | 167 | - Testing improvements 168 | - Updated dependencies 169 | - @klass/core@4.0.0-next.9 170 | 171 | ## 4.0.0-next.8 172 | 173 | ### Patch Changes 174 | 175 | - README 176 | - Updated dependencies 177 | - @klass/core@4.0.0-next.8 178 | 179 | ## 4.0.0-next.7 180 | 181 | ### Patch Changes 182 | 183 | - Types improvements and new frameworks monomorphic feature 184 | - Updated dependencies 185 | - @klass/core@4.0.0-next.7 186 | 187 | ## 4.0.0-next.6 188 | 189 | ### Patch Changes 190 | 191 | - klasses function options, setup API and utils entry 192 | - Updated dependencies 193 | - @klass/core@4.0.0-next.6 194 | 195 | ## 4.0.0-next.5 196 | 197 | ### Patch Changes 198 | 199 | - Optimization 200 | - Updated dependencies 201 | - @klass/core@4.0.0-next.5 202 | 203 | ## 4.0.0-next.4 204 | 205 | ### Patch Changes 206 | 207 | - Optimization 208 | - Updated dependencies 209 | - @klass/core@4.0.0-next.4 210 | 211 | ## 4.0.0-next.3 212 | 213 | ### Patch Changes 214 | 215 | - Optimizations 216 | - Updated dependencies 217 | - @klass/core@4.0.0-next.3 218 | 219 | ## 4.0.0-next.2 220 | 221 | ### Patch Changes 222 | 223 | - New Vue and Qwik packages 224 | - Updated dependencies 225 | - @klass/core@4.0.0-next.2 226 | -------------------------------------------------------------------------------- /packages/qwik/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 |

4 |

klass

5 |

6 | 7 |

8 | 9 | license 10 | 11 | 12 | version 13 | 14 | 15 | size 16 | 17 | downloads 18 |

19 | 20 | # @klass/qwik 21 | 22 | ## Introduction 23 | 24 | Class variant utility for Qwik. 25 | 26 | ## Documentation 27 | 28 | 29 | license 30 | 31 | 32 | ## Installation 33 | 34 | ```sh 35 | npm install @klass/core @klass/qwik 36 | # or 37 | yarn add @klass/core @klass/qwik 38 | # or 39 | pnpm add @klass/core @klass/qwik 40 | # or 41 | bun add @klass/core @klass/qwik 42 | ``` 43 | 44 | ## Usage 45 | 46 | ```tsx 47 | import { klassed, reklassed } from "@klass/qwik"; 48 | 49 | const Button = klassed( 50 | "button", 51 | { 52 | base: "inline-flex items-center justify-center rounded-md outline-none", 53 | variants: { 54 | color: { 55 | default: "bg-neutral-700 text-white", 56 | primary: "bg-indigo-700 text-white", 57 | secondary: "bg-orange-700 text-white", 58 | }, 59 | size: { 60 | sm: "px-3 py-0.5 h-7 text-sm font-medium", 61 | md: "px-4 py-1 h-8 text-base font-medium", 62 | lg: "px-5 py-1.5 h-9 text-lg font-semibold", 63 | }, 64 | block: { 65 | true: "w-full", 66 | }, 67 | // "class" variants are not allowed 68 | }, 69 | defaults: { 70 | color: "default", 71 | size: "md", 72 | }, 73 | }, 74 | { 75 | // default props 76 | dp: { 77 | type: "button", 78 | }, 79 | } 80 | ); 81 | 82 | const Box = reklassed("div", { 83 | conditions: [ 84 | { 85 | base: "", 86 | sm: "sm:", 87 | md: "md:", 88 | lg: "lg:", 89 | xl: "xl:", 90 | "2xl": "2xl:", 91 | }, 92 | "base", 93 | ], 94 | variants: { 95 | m: { 96 | "0": "m-0", 97 | "1": "m-1", 98 | "2": "m-2", 99 | "3": "m-3", 100 | "4": "m-4", 101 | "5": "m-5", 102 | "6": "m-6", 103 | "7": "m-7", 104 | "8": "m-8", 105 | }, 106 | p: { 107 | "0": "p-0", 108 | "1": "p-1", 109 | "2": "p-2", 110 | "3": "p-3", 111 | "4": "p-4", 112 | "5": "p-5", 113 | "6": "p-6", 114 | "7": "p-7", 115 | "8": "p-8", 116 | }, 117 | }, 118 | }); 119 | 120 | const App = () => { 121 | return ( 122 | 123 | 124 | 127 | 128 | 129 | 130 | 133 | 134 | 135 | ); 136 | }; 137 | 138 | export default App; 139 | ``` 140 | 141 | ## Authors 142 | 143 |

144 | 145 | 146 | 147 | github 148 | 149 | 150 |

151 | 152 | ## License 153 | 154 | [MIT License](https://github.com/flamrdevs/klass/blob/main/LICENSE) 155 | -------------------------------------------------------------------------------- /packages/qwik/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@klass/qwik", 3 | "version": "4.0.0-next.29", 4 | "description": "Class variant utility for Qwik", 5 | "keywords": [ 6 | "class", 7 | "classname", 8 | "variant", 9 | "variants", 10 | "utility", 11 | "responsive", 12 | "typescript", 13 | "qwik", 14 | "component", 15 | "styled", 16 | "polymorphic" 17 | ], 18 | "license": "MIT", 19 | "author": { 20 | "name": "flamrdevs" 21 | }, 22 | "type": "module", 23 | "main": "./dist/index.qwik.cjs", 24 | "qwik": "./dist/index.qwik.mjs", 25 | "types": "./dist/index.d.ts", 26 | "exports": { 27 | ".": { 28 | "types": "./dist/index.d.ts", 29 | "import": "./dist/index.qwik.mjs", 30 | "require": "./dist/index.qwik.cjs" 31 | }, 32 | "./create": { 33 | "types": "./dist/create.d.ts", 34 | "import": "./dist/create.qwik.mjs", 35 | "require": "./dist/create.qwik.cjs" 36 | }, 37 | "./utils": { 38 | "types": "./dist/utils.d.ts", 39 | "import": "./dist/utils.qwik.mjs", 40 | "require": "./dist/utils.qwik.cjs" 41 | }, 42 | "./mono": { 43 | "types": "./dist/mono/index.d.ts", 44 | "import": "./dist/mono/index.qwik.mjs", 45 | "require": "./dist/mono/index.qwik.cjs" 46 | }, 47 | "./mono/create": { 48 | "types": "./dist/mono/create.d.ts", 49 | "import": "./dist/mono/create.qwik.mjs", 50 | "require": "./dist/mono/create.qwik.cjs" 51 | } 52 | }, 53 | "typesVersions": { 54 | ">=3.1": { 55 | "*": [ 56 | "./dist/*.d.ts", 57 | "./dist/index.d.ts" 58 | ], 59 | "mono": [ 60 | "./dist/mono/*.d.ts", 61 | "./dist/mono/index.d.ts" 62 | ] 63 | } 64 | }, 65 | "files": [ 66 | "dist" 67 | ], 68 | "homepage": "https://klass.pages.dev", 69 | "repository": { 70 | "type": "git", 71 | "url": "git+https://github.com/flamrdevs/klass.git", 72 | "directory": "packages/qwik" 73 | }, 74 | "scripts": { 75 | "build": "vite build" 76 | }, 77 | "peerDependencies": { 78 | "@builder.io/qwik": "^1", 79 | "@klass/core": "workspace:*" 80 | }, 81 | "devDependencies": { 82 | "@builder.io/qwik": "^1", 83 | "@klass/core": "workspace:*" 84 | }, 85 | "publishConfig": { 86 | "access": "public" 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /packages/qwik/src/create.tsx: -------------------------------------------------------------------------------- 1 | import { jsx } from "@builder.io/qwik"; 2 | 3 | import type { Compose, ComposeFn, ConditionSchema, FxFrom, Fxs, Klass, KlassFn, Reklass, ReklassFn } from "@klass/core"; 4 | import { typeofFunction } from "@klass/core/utils"; 5 | 6 | import type { 7 | ComponentConfig, 8 | ComposedComponent, 9 | ComposedComponentConfig, 10 | ComposedOptions, 11 | DefaultPropsConfig, 12 | FinalVariantsSchema, 13 | ForwardPropsConfig, 14 | KlassedComponent, 15 | KlassedOptions, 16 | ReklassedComponent, 17 | ReklassedOptions, 18 | } from "./types"; 19 | import type { ClassesProps, SupportedElementType } from "./types/qwik"; 20 | 21 | import { getVariantKeys, maybeSignal, splitRestProps } from "./utils"; 22 | 23 | function create(element: ET, fn: KlassFn> | ReklassFn> | ComposeFn, config: DefaultPropsConfig & ForwardPropsConfig = {}) { 24 | const { class: defaultClass, ...defaultProps } = (config.dp ?? {}) as ClassesProps, 25 | keys = getVariantKeys(fn.k); 26 | 27 | const Comp = (({ as: As = element as any, class: _class = defaultClass, ...rest }) => { 28 | const splitted = splitRestProps(rest, keys, config.fp); 29 | 30 | return jsx(As, { ...defaultProps, ...(splitted.o as any), class: fn(splitted.p, maybeSignal(_class)) }); 31 | }) as any; 32 | 33 | return (Comp.fx = fn), Comp; 34 | } 35 | 36 | type Klassed = (element: ET, options: KlassedOptions, config?: ComponentConfig | undefined) => KlassedComponent; 37 | type Reklassed = ( 38 | element: ET, 39 | options: ReklassedOptions, 40 | config?: ComponentConfig 41 | ) => ReklassedComponent; 42 | type Composed = (element: ET, options: ComposedOptions, config?: ComposedComponentConfig>) => ComposedComponent>; 43 | 44 | const createKlassed = 45 | (klass: Klass): Klassed => 46 | (element, options, config) => 47 | /* @__PURE__ */ create(element, typeofFunction(options) ? options : klass(options), config) as any; 48 | const createReklassed = 49 | (reklass: Reklass): Reklassed => 50 | (element, options, config) => 51 | /* @__PURE__ */ create(element, typeofFunction(options) ? options : reklass(options), config) as any; 52 | const createComposed = 53 | (compose: Compose): Composed => 54 | (element, options, config) => 55 | /* @__PURE__ */ create(element, typeofFunction(options) ? options : compose(...options), config) as any; 56 | 57 | export { createKlassed, createReklassed, createComposed }; 58 | -------------------------------------------------------------------------------- /packages/qwik/src/index.tsx: -------------------------------------------------------------------------------- 1 | import { compose, klass, reklass } from "@klass/core"; 2 | import type { 3 | AsFn, 4 | AsFnProps, 5 | BaseFn, 6 | Compose, 7 | ComposeFn, 8 | CompoundVariant, 9 | ConditionSchema, 10 | EndFn, 11 | EndFnProps, 12 | Fx, 13 | FxFrom, 14 | Fxs, 15 | Klass, 16 | KlassFn, 17 | KlassOptions, 18 | Reklass, 19 | ReklassFn, 20 | ReklassOptions, 21 | RequiredVariantsFrom, 22 | RevariantFn, 23 | RevariantGroup, 24 | StrictVariantsSchema, 25 | TransformKey, 26 | UnionToIntersection, 27 | VariantFn, 28 | VariantGroup, 29 | VariantsOf, 30 | VariantsSchema, 31 | } from "@klass/core"; 32 | 33 | import { createComposed, createKlassed, createReklassed } from "./create"; 34 | 35 | const klassed = /* @__PURE__ */ createKlassed(klass); 36 | 37 | const reklassed = /* @__PURE__ */ createReklassed(reklass); 38 | 39 | const composed = /* @__PURE__ */ createComposed(compose); 40 | 41 | export type { 42 | TransformKey, 43 | EndFn, 44 | AsFn, 45 | EndFnProps, 46 | AsFnProps, 47 | VariantsSchema, 48 | StrictVariantsSchema, 49 | VariantsOf, 50 | RequiredVariantsFrom, 51 | BaseFn, 52 | VariantFn, 53 | VariantGroup, 54 | CompoundVariant, 55 | KlassOptions, 56 | KlassFn, 57 | Klass, 58 | ConditionSchema, 59 | RevariantFn, 60 | RevariantGroup, 61 | ReklassOptions, 62 | ReklassFn, 63 | Reklass, 64 | UnionToIntersection, 65 | Fx, 66 | Fxs, 67 | FxFrom, 68 | ComposeFn, 69 | Compose, 70 | }; 71 | export type { ClassesValueProps, WithClassesValueProps, KlassedComponent, ReklassedComponent, ComposedComponent } from "./types"; 72 | export { klassed, reklassed, composed }; 73 | -------------------------------------------------------------------------------- /packages/qwik/src/mono/create.tsx: -------------------------------------------------------------------------------- 1 | import { jsx } from "@builder.io/qwik"; 2 | 3 | import type { Compose, ComposeFn, ConditionSchema, FxFrom, Fxs, Klass, KlassFn, Reklass, ReklassFn } from "@klass/core"; 4 | import { typeofFunction } from "@klass/core/utils"; 5 | 6 | import { ComposedOptions, DefaultPropsConfig, FinalVariantsSchema, ForwardPropsConfig, KlassedOptions, ReklassedOptions } from "./../types"; 7 | import type { ClassesProps, SupportedElementType } from "./../types/qwik"; 8 | 9 | import { getVariantKeys, maybeSignal, splitRestProps } from "./../utils"; 10 | 11 | import type { ComponentConfig, ComposedComponentConfig, MonoComposedComponent, MonoKlassedComponent, MonoReklassedComponent } from "./types"; 12 | 13 | function create(element: ET, fn: KlassFn> | ReklassFn> | ComposeFn, config: DefaultPropsConfig & ForwardPropsConfig = {}) { 14 | const { class: defaultClass, ...defaultProps } = (config.dp ?? {}) as ClassesProps, 15 | keys = getVariantKeys(fn.k); 16 | 17 | const Comp = (({ class: _class = defaultClass, ...rest }) => { 18 | const splitted = splitRestProps(rest, keys, config.fp); 19 | 20 | return jsx(element, { ...defaultProps, ...(splitted.o as any), class: fn(splitted.p, maybeSignal(_class)) }); 21 | }) as any; 22 | 23 | return (Comp.fx = fn), Comp; 24 | } 25 | 26 | type Klassed = ( 27 | element: ET, 28 | options: KlassedOptions, 29 | config?: ComponentConfig | undefined 30 | ) => MonoKlassedComponent; 31 | type Reklassed = ( 32 | element: ET, 33 | options: ReklassedOptions, 34 | config?: ComponentConfig 35 | ) => MonoReklassedComponent; 36 | type Composed = (element: ET, options: ComposedOptions, config?: ComposedComponentConfig>) => MonoComposedComponent>; 37 | 38 | const createKlassed = 39 | (klass: Klass): Klassed => 40 | (element, options, config) => 41 | /* @__PURE__ */ create(element, typeofFunction(options) ? options : klass(options), config) as any; 42 | const createReklassed = 43 | (reklass: Reklass): Reklassed => 44 | (element, options, config) => 45 | /* @__PURE__ */ create(element, typeofFunction(options) ? options : reklass(options), config) as any; 46 | const createComposed = 47 | (compose: Compose): Composed => 48 | (element, options, config) => 49 | /* @__PURE__ */ create(element, typeofFunction(options) ? options : compose(...options), config) as any; 50 | 51 | export type { MonoKlassedComponent, MonoReklassedComponent, MonoComposedComponent }; 52 | export { createKlassed, createReklassed, createComposed }; 53 | -------------------------------------------------------------------------------- /packages/qwik/src/mono/index.tsx: -------------------------------------------------------------------------------- 1 | import { compose, klass, reklass } from "@klass/core"; 2 | import type { 3 | AsFn, 4 | AsFnProps, 5 | BaseFn, 6 | Compose, 7 | ComposeFn, 8 | CompoundVariant, 9 | ConditionSchema, 10 | EndFn, 11 | EndFnProps, 12 | Fx, 13 | FxFrom, 14 | Fxs, 15 | Klass, 16 | KlassFn, 17 | KlassOptions, 18 | Reklass, 19 | ReklassFn, 20 | ReklassOptions, 21 | RequiredVariantsFrom, 22 | RevariantFn, 23 | RevariantGroup, 24 | StrictVariantsSchema, 25 | TransformKey, 26 | UnionToIntersection, 27 | VariantFn, 28 | VariantGroup, 29 | VariantsOf, 30 | VariantsSchema, 31 | } from "@klass/core"; 32 | 33 | import { createComposed, createKlassed, createReklassed } from "./create"; 34 | 35 | const klassed = /* @__PURE__ */ createKlassed(klass); 36 | 37 | const reklassed = /* @__PURE__ */ createReklassed(reklass); 38 | 39 | const composed = /* @__PURE__ */ createComposed(compose); 40 | 41 | export type { 42 | TransformKey, 43 | EndFn, 44 | AsFn, 45 | EndFnProps, 46 | AsFnProps, 47 | VariantsSchema, 48 | StrictVariantsSchema, 49 | VariantsOf, 50 | RequiredVariantsFrom, 51 | BaseFn, 52 | VariantFn, 53 | VariantGroup, 54 | CompoundVariant, 55 | KlassOptions, 56 | KlassFn, 57 | Klass, 58 | ConditionSchema, 59 | RevariantFn, 60 | RevariantGroup, 61 | ReklassOptions, 62 | ReklassFn, 63 | Reklass, 64 | UnionToIntersection, 65 | Fx, 66 | Fxs, 67 | FxFrom, 68 | ComposeFn, 69 | Compose, 70 | }; 71 | export type { MonoKlassedComponent, MonoReklassedComponent, MonoComposedComponent } from "./types"; 72 | export { klassed, reklassed, composed }; 73 | -------------------------------------------------------------------------------- /packages/qwik/src/mono/types.ts: -------------------------------------------------------------------------------- 1 | import type { JSX } from "@builder.io/qwik/jsx-runtime"; 2 | 3 | import type { ComposeFn, ConditionSchema, Fx, KlassFn, ReklassFn, VariantsOf } from "@klass/core"; 4 | 5 | import { Base, DefaultPropsConfig, FinalVariantsSchema, ForwardPropsConfig, WithClassesValueProps } from "./../types"; 6 | import type { SignalishRecord, SupportedComponentProps, SupportedElementType } from "./../types/qwik"; 7 | import { OverrideProps } from "./../types/utils"; 8 | 9 | export type ComponentConfig = DefaultPropsConfig> & ForwardPropsConfig; 10 | export type ComposedComponentConfig = DefaultPropsConfig> & ForwardPropsConfig; 11 | 12 | export type MonoKlassedComponent = { 13 | (props: WithClassesValueProps, SignalishRecord>>>>): JSX.Element; 14 | } & Base>; 15 | 16 | export type MonoReklassedComponent = { 17 | (props: WithClassesValueProps, SignalishRecord>>>>): JSX.Element; 18 | } & Base>; 19 | 20 | export type MonoComposedComponent = { 21 | (props: WithClassesValueProps, SignalishRecord>>>>): JSX.Element; 22 | } & Base>; 23 | -------------------------------------------------------------------------------- /packages/qwik/src/types/index.ts: -------------------------------------------------------------------------------- 1 | import type { JSX } from "@builder.io/qwik/jsx-runtime"; 2 | 3 | import type { ClassValue, ComposeFn, ConditionSchema, Fx, FxFrom, Fxs, KlassFn, KlassOptions, ReklassFn, ReklassOptions, StrictVariantsSchema, VariantsOf } from "@klass/core"; 4 | 5 | import type { PolymorphicComponentProps } from "./polymorphic"; 6 | import type { Classes, Signalish, SignalishRecord, SupportedElementType } from "./qwik"; 7 | 8 | export type FinalRestrictedVariantsKey = Classes; 9 | export type FinalVariantsSchema = StrictVariantsSchema; 10 | 11 | export type ClassesValueProps = Partial>>; 12 | export type WithClassesValueProps

= Omit & ClassesValueProps; 13 | 14 | export type KlassedOptions = KlassOptions | KlassFn; 15 | export type ReklassedOptions = ReklassOptions | ReklassFn; 16 | export type ComposedOptions = Fn[] | ComposeFn>; 17 | 18 | export type DefaultPropsConfig> = { dp?: DP }; 19 | export type ForwardPropsConfig = { fp?: T[] }; 20 | export type ComponentConfig = DefaultPropsConfig> & ForwardPropsConfig; 21 | export type ComposedComponentConfig = DefaultPropsConfig> & ForwardPropsConfig; 22 | 23 | export type Base = { fx: F }; 24 | 25 | export type KlassedComponent = { 26 | (props: PolymorphicComponentProps>>>>): JSX.Element; 27 | } & Base>; 28 | 29 | export type ReklassedComponent = { 30 | (props: PolymorphicComponentProps>>>>): JSX.Element; 31 | } & Base>; 32 | 33 | export type ComposedComponent = { 34 | (props: PolymorphicComponentProps>>>>): JSX.Element; 35 | } & Base>; 36 | -------------------------------------------------------------------------------- /packages/qwik/src/types/polymorphic.ts: -------------------------------------------------------------------------------- 1 | import type { JSXChildren } from "@builder.io/qwik"; 2 | 3 | import type { SupportedComponentProps, SupportedElementType } from "./qwik"; 4 | 5 | type ResolveRefProps

= Omit & { 6 | ref?: P extends { 7 | ref?: infer Ref; 8 | } 9 | ? Ref 10 | : unknown; 11 | }; 12 | 13 | export type PolymorphicComponentProps = (Props & { 14 | as?: ET; 15 | } & { 16 | children?: JSXChildren; 17 | }) & 18 | Omit>, "as" | keyof Props>; 19 | -------------------------------------------------------------------------------- /packages/qwik/src/types/qwik.ts: -------------------------------------------------------------------------------- 1 | import type { Component, FunctionComponent, Signal } from "@builder.io/qwik"; 2 | import type { JSX } from "@builder.io/qwik/jsx-runtime"; 3 | 4 | export type Signalish = T | Signal; 5 | export type SignalishRecord> = { 6 | [K in keyof T]: Signalish; 7 | }; 8 | 9 | export type SupportedComponentType

= Component

| FunctionComponent

; 10 | 11 | export type SupportedComponentProps = T extends SupportedComponentType 12 | ? P 13 | : T extends keyof JSX.IntrinsicElements 14 | ? JSX.IntrinsicElements[T] 15 | : {}; 16 | 17 | export type SupportedElementType

= 18 | | { 19 | [K in keyof JSX.IntrinsicElements]: P extends JSX.IntrinsicElements[K] ? K : never; 20 | }[keyof JSX.IntrinsicElements] 21 | | SupportedComponentType

; 22 | 23 | export type Classes = "class"; 24 | export type ClassesProps = Partial>>; 25 | -------------------------------------------------------------------------------- /packages/qwik/src/types/utils.ts: -------------------------------------------------------------------------------- 1 | export type OverrideProps = Omit & W; 2 | -------------------------------------------------------------------------------- /packages/qwik/src/utils.ts: -------------------------------------------------------------------------------- 1 | import { isSignal } from "@builder.io/qwik"; 2 | 3 | import type { FinalRestrictedVariantsKey, FinalVariantsSchema } from "./types"; 4 | 5 | const getVariantKeys__filterFn = /* @__PURE__ */ (el: keyof VS) => el !== "class"; 6 | export const getVariantKeys = /* @__PURE__ */ (keys: (keyof VS)[]) => 7 | keys.filter(getVariantKeys__filterFn) as unknown as Exclude[]; 8 | 9 | export const splitRestProps = /* @__PURE__ */

>(props: P, keys: string[], fkeys?: string[]) => { 10 | const o: /** omited */ Record = {}, 11 | p: /** picked */ Record = {}; 12 | let key: string; 13 | for (key in props) { 14 | const value = maybeSignal(props[key]); 15 | if (keys.includes(key)) { 16 | p[key] = value; 17 | if (fkeys?.includes(key)) o[key] = value; 18 | } else { 19 | o[key] = value; 20 | } 21 | } 22 | return { o, p } as const; 23 | }; 24 | 25 | export const maybeSignal = /* @__PURE__ */ (obj: any): obj is T => (isSignal(obj) ? obj.value : obj); 26 | -------------------------------------------------------------------------------- /packages/qwik/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "forceConsistentCasingInFileNames": true, 5 | "target": "ESNext", 6 | "module": "ESNext", 7 | "lib": ["ESNext", "DOM", "DOM.Iterable"], 8 | "moduleResolution": "bundler", 9 | "esModuleInterop": true, 10 | "allowImportingTsExtensions": true, 11 | "allowSyntheticDefaultImports": true, 12 | "allowJs": true, 13 | "resolveJsonModule": true, 14 | "skipLibCheck": true, 15 | "strictNullChecks": true, 16 | "declaration": true, 17 | "removeComments": false, 18 | "noUnusedLocals": true, 19 | "noUnusedParameters": true, 20 | "noEmit": true, 21 | "jsx": "react-jsx", 22 | "jsxImportSource": "@builder.io/qwik" 23 | }, 24 | "include": ["src"], 25 | "exclude": ["node_modules", "dist"] 26 | } 27 | -------------------------------------------------------------------------------- /packages/qwik/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | 3 | import { qwikVite as qwik } from "@builder.io/qwik/optimizer"; 4 | 5 | import { build, dts } from "../config"; 6 | 7 | const _build = build(["utils.ts", "index.tsx", "create.tsx", "mono/index.tsx", "mono/create.tsx"], (options) => { 8 | options.lib.fileName = (format, entry) => `${entry}.qwik.${format === "cjs" ? "cjs" : "mjs"}`; 9 | }); 10 | 11 | export default defineConfig({ 12 | mode: "lib", 13 | plugins: [ 14 | qwik(), 15 | { 16 | name: "minify", 17 | config: (config) => { 18 | config.build!.minify = _build.minify; 19 | }, 20 | }, 21 | dts(["src/**/*.{ts,tsx}"]), 22 | ], 23 | build: _build, 24 | }); 25 | -------------------------------------------------------------------------------- /packages/react/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | .turbo 4 | 5 | dist 6 | -------------------------------------------------------------------------------- /packages/react/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 |

4 |

klass

5 |

6 | 7 |

8 | 9 | license 10 | 11 | 12 | version 13 | 14 | 15 | size 16 | 17 | downloads 18 |

19 | 20 | # @klass/react 21 | 22 | ## Introduction 23 | 24 | Class variant utility for React. 25 | 26 | ## Documentation 27 | 28 | 29 | license 30 | 31 | 32 | ## Installation 33 | 34 | ```sh 35 | npm install @klass/core @klass/react 36 | # or 37 | yarn add @klass/core @klass/react 38 | # or 39 | pnpm add @klass/core @klass/react 40 | # or 41 | bun add @klass/core @klass/react 42 | ``` 43 | 44 | ## Usage 45 | 46 | ```tsx 47 | import { klassed, reklassed } from "@klass/react"; 48 | 49 | const Button = klassed( 50 | "button", 51 | { 52 | base: "inline-flex items-center justify-center rounded-md outline-none", 53 | variants: { 54 | color: { 55 | default: "bg-neutral-700 text-white", 56 | primary: "bg-indigo-700 text-white", 57 | secondary: "bg-orange-700 text-white", 58 | }, 59 | size: { 60 | sm: "px-3 py-0.5 h-7 text-sm font-medium", 61 | md: "px-4 py-1 h-8 text-base font-medium", 62 | lg: "px-5 py-1.5 h-9 text-lg font-semibold", 63 | }, 64 | block: { 65 | true: "w-full", 66 | }, 67 | // "className" variants are not allowed 68 | }, 69 | defaults: { 70 | color: "default", 71 | size: "md", 72 | }, 73 | }, 74 | { 75 | // default props 76 | dp: { 77 | type: "button", 78 | }, 79 | } 80 | ); 81 | 82 | const Box = reklassed("div", { 83 | conditions: [ 84 | { 85 | base: "", 86 | sm: "sm:", 87 | md: "md:", 88 | lg: "lg:", 89 | xl: "xl:", 90 | "2xl": "2xl:", 91 | }, 92 | "base", 93 | ], 94 | variants: { 95 | m: { 96 | "0": "m-0", 97 | "1": "m-1", 98 | "2": "m-2", 99 | "3": "m-3", 100 | "4": "m-4", 101 | "5": "m-5", 102 | "6": "m-6", 103 | "7": "m-7", 104 | "8": "m-8", 105 | }, 106 | p: { 107 | "0": "p-0", 108 | "1": "p-1", 109 | "2": "p-2", 110 | "3": "p-3", 111 | "4": "p-4", 112 | "5": "p-5", 113 | "6": "p-6", 114 | "7": "p-7", 115 | "8": "p-8", 116 | }, 117 | }, 118 | }); 119 | 120 | const App = () => { 121 | return ( 122 | 123 | 124 | 127 | 128 | 129 | 130 | 133 | 134 | 135 | ); 136 | }; 137 | 138 | export default App; 139 | ``` 140 | 141 | ## Authors 142 | 143 |

144 | 145 | 146 | 147 | github 148 | 149 | 150 |

151 | 152 | ## License 153 | 154 | [MIT License](https://github.com/flamrdevs/klass/blob/main/LICENSE) 155 | -------------------------------------------------------------------------------- /packages/react/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@klass/react", 3 | "version": "4.0.0-next.29", 4 | "description": "Class variant utility for React", 5 | "keywords": [ 6 | "class", 7 | "classname", 8 | "variant", 9 | "variants", 10 | "utility", 11 | "responsive", 12 | "typescript", 13 | "react", 14 | "component", 15 | "styled", 16 | "polymorphic" 17 | ], 18 | "license": "MIT", 19 | "author": { 20 | "name": "flamrdevs" 21 | }, 22 | "type": "module", 23 | "main": "./dist/index.cjs", 24 | "types": "./dist/index.d.ts", 25 | "exports": { 26 | ".": { 27 | "types": "./dist/index.d.ts", 28 | "import": "./dist/index.js", 29 | "require": "./dist/index.cjs" 30 | }, 31 | "./create": { 32 | "types": "./dist/create.d.ts", 33 | "import": "./dist/create.js", 34 | "require": "./dist/create.cjs" 35 | }, 36 | "./utils": { 37 | "types": "./dist/utils.d.ts", 38 | "import": "./dist/utils.js", 39 | "require": "./dist/utils.cjs" 40 | }, 41 | "./mono": { 42 | "types": "./dist/mono/index.d.ts", 43 | "import": "./dist/mono/index.js", 44 | "require": "./dist/mono/index.cjs" 45 | }, 46 | "./mono/create": { 47 | "types": "./dist/mono/create.d.ts", 48 | "import": "./dist/mono/create.js", 49 | "require": "./dist/mono/create.cjs" 50 | } 51 | }, 52 | "typesVersions": { 53 | ">=3.1": { 54 | "*": [ 55 | "./dist/*.d.ts", 56 | "./dist/index.d.ts" 57 | ], 58 | "mono": [ 59 | "./dist/mono/*.d.ts", 60 | "./dist/mono/index.d.ts" 61 | ] 62 | } 63 | }, 64 | "files": [ 65 | "dist" 66 | ], 67 | "homepage": "https://klass.pages.dev", 68 | "repository": { 69 | "type": "git", 70 | "url": "git+https://github.com/flamrdevs/klass.git", 71 | "directory": "packages/react" 72 | }, 73 | "scripts": { 74 | "build": "vite build" 75 | }, 76 | "peerDependencies": { 77 | "@klass/core": "workspace:*", 78 | "react": "^18 || ^19", 79 | "react-dom": "^18 || ^19" 80 | }, 81 | "devDependencies": { 82 | "@klass/core": "workspace:*", 83 | "@types/react": "^19", 84 | "@types/react-dom": "^19", 85 | "react": "^19", 86 | "react-dom": "^19" 87 | }, 88 | "publishConfig": { 89 | "access": "public" 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /packages/react/src/create.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | import type { Compose, ComposeFn, ConditionSchema, FxFrom, Fxs, Klass, KlassFn, Reklass, ReklassFn } from "@klass/core"; 4 | import { typeofFunction } from "@klass/core/utils"; 5 | 6 | import type { 7 | ComponentConfig, 8 | ComposedComponent, 9 | ComposedComponentConfig, 10 | ComposedOptions, 11 | DefaultPropsConfig, 12 | FinalVariantsSchema, 13 | ForwardPropsConfig, 14 | KlassedComponent, 15 | KlassedOptions, 16 | ReklassedComponent, 17 | ReklassedOptions, 18 | } from "./types"; 19 | import type { PolymorphicComponentProps, PolymorphicRef } from "./types/polymorphic"; 20 | import type { ClassesProps, SupportedElementType } from "./types/react"; 21 | 22 | import { getVariantKeys, splitRestProps } from "./utils"; 23 | 24 | function create(element: ET, fn: KlassFn> | ReklassFn> | ComposeFn, config: DefaultPropsConfig & ForwardPropsConfig = {}) { 25 | const { className: defaultClassName, ...defaultProps } = (config.dp ?? {}) as ClassesProps, 26 | keys = getVariantKeys(fn.k); 27 | 28 | const Comp = React.forwardRef>(({ as: As = element as any, className = defaultClassName, ...rest }, ref?: PolymorphicRef) => { 29 | const splitted = splitRestProps(rest, keys, config.fp); 30 | 31 | return ; 32 | }) as any; 33 | 34 | return (Comp.fx = fn), Comp; 35 | } 36 | 37 | type Klassed = (element: ET, options: KlassedOptions, config?: ComponentConfig | undefined) => KlassedComponent; 38 | type Reklassed = ( 39 | element: ET, 40 | options: ReklassedOptions, 41 | config?: ComponentConfig 42 | ) => ReklassedComponent; 43 | type Composed = (element: ET, options: ComposedOptions, config?: ComposedComponentConfig>) => ComposedComponent>; 44 | 45 | const createKlassed = 46 | (klass: Klass): Klassed => 47 | (element, options, config) => 48 | /* @__PURE__ */ create(element, typeofFunction(options) ? options : klass(options), config) as any; 49 | const createReklassed = 50 | (reklass: Reklass): Reklassed => 51 | (element, options, config) => 52 | /* @__PURE__ */ create(element, typeofFunction(options) ? options : reklass(options), config) as any; 53 | const createComposed = 54 | (compose: Compose): Composed => 55 | (element, options, config) => 56 | /* @__PURE__ */ create(element, typeofFunction(options) ? options : compose(...options), config) as any; 57 | 58 | export { createKlassed, createReklassed, createComposed }; 59 | -------------------------------------------------------------------------------- /packages/react/src/index.tsx: -------------------------------------------------------------------------------- 1 | import { compose, klass, reklass } from "@klass/core"; 2 | import type { 3 | AsFn, 4 | AsFnProps, 5 | BaseFn, 6 | Compose, 7 | ComposeFn, 8 | CompoundVariant, 9 | ConditionSchema, 10 | EndFn, 11 | EndFnProps, 12 | Fx, 13 | FxFrom, 14 | Fxs, 15 | Klass, 16 | KlassFn, 17 | KlassOptions, 18 | Reklass, 19 | ReklassFn, 20 | ReklassOptions, 21 | RequiredVariantsFrom, 22 | RevariantFn, 23 | RevariantGroup, 24 | StrictVariantsSchema, 25 | TransformKey, 26 | UnionToIntersection, 27 | VariantFn, 28 | VariantGroup, 29 | VariantsOf, 30 | VariantsSchema, 31 | } from "@klass/core"; 32 | 33 | import { createComposed, createKlassed, createReklassed } from "./create"; 34 | 35 | const klassed = /* @__PURE__ */ createKlassed(klass); 36 | 37 | const reklassed = /* @__PURE__ */ createReklassed(reklass); 38 | 39 | const composed = /* @__PURE__ */ createComposed(compose); 40 | 41 | export type { 42 | TransformKey, 43 | EndFn, 44 | AsFn, 45 | EndFnProps, 46 | AsFnProps, 47 | VariantsSchema, 48 | StrictVariantsSchema, 49 | VariantsOf, 50 | RequiredVariantsFrom, 51 | BaseFn, 52 | VariantFn, 53 | VariantGroup, 54 | CompoundVariant, 55 | KlassOptions, 56 | KlassFn, 57 | Klass, 58 | ConditionSchema, 59 | RevariantFn, 60 | RevariantGroup, 61 | ReklassOptions, 62 | ReklassFn, 63 | Reklass, 64 | UnionToIntersection, 65 | Fx, 66 | Fxs, 67 | FxFrom, 68 | ComposeFn, 69 | Compose, 70 | }; 71 | export type { ClassesValueProps, WithClassesValueProps, KlassedComponent, ReklassedComponent, ComposedComponent } from "./types"; 72 | export { klassed, reklassed, composed }; 73 | -------------------------------------------------------------------------------- /packages/react/src/mono/create.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | import type { Compose, ComposeFn, ConditionSchema, FxFrom, Fxs, Klass, KlassFn, Reklass, ReklassFn } from "@klass/core"; 4 | import { typeofFunction } from "@klass/core/utils"; 5 | 6 | import { ComposedOptions, DefaultPropsConfig, FinalVariantsSchema, ForwardPropsConfig, KlassedOptions, ReklassedOptions, WithClassesValueProps } from "./../types"; 7 | import type { ClassesProps, SupportedElementType } from "./../types/react"; 8 | 9 | import { getVariantKeys, splitRestProps } from "./../utils"; 10 | 11 | import type { ComponentConfig, ComposedComponentConfig, MonoComposedComponent, MonoKlassedComponent, MonoReklassedComponent } from "./types"; 12 | 13 | function create(Element: ET, fn: KlassFn> | ReklassFn> | ComposeFn, config: DefaultPropsConfig & ForwardPropsConfig = {}) { 14 | const { className: defaultClassName, ...defaultProps } = (config.dp ?? {}) as ClassesProps, 15 | keys = getVariantKeys(fn.k); 16 | 17 | const Comp = React.forwardRef>(({ className = defaultClassName, ...rest }, ref) => { 18 | const splitted = splitRestProps(rest, keys, config.fp); 19 | 20 | return ; 21 | }) as any; 22 | 23 | return (Comp.fx = fn), Comp; 24 | } 25 | 26 | type Klassed = ( 27 | element: ET, 28 | options: KlassedOptions, 29 | config?: ComponentConfig | undefined 30 | ) => MonoKlassedComponent; 31 | type Reklassed = ( 32 | element: ET, 33 | options: ReklassedOptions, 34 | config?: ComponentConfig 35 | ) => MonoReklassedComponent; 36 | type Composed = (element: ET, options: ComposedOptions, config?: ComposedComponentConfig>) => MonoComposedComponent>; 37 | 38 | const createKlassed = 39 | (klass: Klass): Klassed => 40 | (element, options, config) => 41 | /* @__PURE__ */ create(element, typeofFunction(options) ? options : klass(options), config) as any; 42 | const createReklassed = 43 | (reklass: Reklass): Reklassed => 44 | (element, options, config) => 45 | /* @__PURE__ */ create(element, typeofFunction(options) ? options : reklass(options), config) as any; 46 | const createComposed = 47 | (compose: Compose): Composed => 48 | (element, options, config) => 49 | /* @__PURE__ */ create(element, typeofFunction(options) ? options : compose(...options), config) as any; 50 | 51 | export type { MonoKlassedComponent, MonoReklassedComponent, MonoComposedComponent }; 52 | export { createKlassed, createReklassed, createComposed }; 53 | -------------------------------------------------------------------------------- /packages/react/src/mono/index.tsx: -------------------------------------------------------------------------------- 1 | import { compose, klass, reklass } from "@klass/core"; 2 | import type { 3 | AsFn, 4 | AsFnProps, 5 | BaseFn, 6 | Compose, 7 | ComposeFn, 8 | CompoundVariant, 9 | ConditionSchema, 10 | EndFn, 11 | EndFnProps, 12 | Fx, 13 | FxFrom, 14 | Fxs, 15 | Klass, 16 | KlassFn, 17 | KlassOptions, 18 | Reklass, 19 | ReklassFn, 20 | ReklassOptions, 21 | RequiredVariantsFrom, 22 | RevariantFn, 23 | RevariantGroup, 24 | StrictVariantsSchema, 25 | TransformKey, 26 | UnionToIntersection, 27 | VariantFn, 28 | VariantGroup, 29 | VariantsOf, 30 | VariantsSchema, 31 | } from "@klass/core"; 32 | 33 | import { createComposed, createKlassed, createReklassed } from "./create"; 34 | 35 | const klassed = /* @__PURE__ */ createKlassed(klass); 36 | 37 | const reklassed = /* @__PURE__ */ createReklassed(reklass); 38 | 39 | const composed = /* @__PURE__ */ createComposed(compose); 40 | 41 | export type { 42 | TransformKey, 43 | EndFn, 44 | AsFn, 45 | EndFnProps, 46 | AsFnProps, 47 | VariantsSchema, 48 | StrictVariantsSchema, 49 | VariantsOf, 50 | RequiredVariantsFrom, 51 | BaseFn, 52 | VariantFn, 53 | VariantGroup, 54 | CompoundVariant, 55 | KlassOptions, 56 | KlassFn, 57 | Klass, 58 | ConditionSchema, 59 | RevariantFn, 60 | RevariantGroup, 61 | ReklassOptions, 62 | ReklassFn, 63 | Reklass, 64 | UnionToIntersection, 65 | Fx, 66 | Fxs, 67 | FxFrom, 68 | ComposeFn, 69 | Compose, 70 | }; 71 | export type { MonoKlassedComponent, MonoReklassedComponent, MonoComposedComponent } from "./types"; 72 | export { klassed, reklassed, composed }; 73 | -------------------------------------------------------------------------------- /packages/react/src/mono/types.ts: -------------------------------------------------------------------------------- 1 | import type { JSX } from "react"; 2 | 3 | import type { ComposeFn, ConditionSchema, Fx, KlassFn, ReklassFn, VariantsOf } from "@klass/core"; 4 | 5 | import { Base, DefaultPropsConfig, FinalVariantsSchema, ForwardPropsConfig, WithClassesValueProps } from "./../types"; 6 | import type { SupportedComponentProps, SupportedElementType } from "./../types/react"; 7 | import { OverrideProps } from "./../types/utils"; 8 | 9 | export type ComponentConfig = DefaultPropsConfig> & ForwardPropsConfig; 10 | export type ComposedComponentConfig = DefaultPropsConfig> & ForwardPropsConfig; 11 | 12 | export type MonoKlassedComponent = { 13 | (props: WithClassesValueProps, VariantsOf>>>): JSX.Element; 14 | } & Base>; 15 | 16 | export type MonoReklassedComponent = { 17 | (props: WithClassesValueProps, VariantsOf>>>): JSX.Element; 18 | } & Base>; 19 | 20 | export type MonoComposedComponent = { 21 | (props: WithClassesValueProps, VariantsOf>>>): JSX.Element; 22 | } & Base>; 23 | -------------------------------------------------------------------------------- /packages/react/src/types/index.ts: -------------------------------------------------------------------------------- 1 | import type { JSX } from "react"; 2 | 3 | import type { ClassValue, ComposeFn, ConditionSchema, Fx, FxFrom, Fxs, KlassFn, KlassOptions, ReklassFn, ReklassOptions, StrictVariantsSchema, VariantsOf } from "@klass/core"; 4 | 5 | import type { PolymorphicComponentProps } from "./polymorphic"; 6 | import type { BaseComponent, Classes, SupportedElementType } from "./react"; 7 | 8 | export type FinalRestrictedVariantsKey = Classes; 9 | export type FinalVariantsSchema = StrictVariantsSchema; 10 | 11 | export type ClassesValueProps = Partial>; 12 | export type WithClassesValueProps

= Omit & ClassesValueProps; 13 | 14 | export type KlassedOptions = KlassOptions | KlassFn; 15 | export type ReklassedOptions = ReklassOptions | ReklassFn; 16 | export type ComposedOptions = Fn[] | ComposeFn>; 17 | 18 | export type DefaultPropsConfig> = { dp?: DP }; 19 | export type ForwardPropsConfig = { fp?: T[] }; 20 | export type ComponentConfig = DefaultPropsConfig> & ForwardPropsConfig; 21 | export type ComposedComponentConfig = DefaultPropsConfig> & ForwardPropsConfig; 22 | 23 | export type Base = BaseComponent & { fx: F }; 24 | 25 | export type KlassedComponent = { 26 | (props: PolymorphicComponentProps>>>): JSX.Element; 27 | } & Base>; 28 | 29 | export type ReklassedComponent = { 30 | (props: PolymorphicComponentProps>>>): JSX.Element; 31 | } & Base>; 32 | 33 | export type ComposedComponent = { 34 | (props: PolymorphicComponentProps>>>): JSX.Element; 35 | } & Base>; 36 | -------------------------------------------------------------------------------- /packages/react/src/types/polymorphic.ts: -------------------------------------------------------------------------------- 1 | import type { ForwardedRef, ReactNode } from "react"; 2 | 3 | import type { SupportedComponentProps, SupportedElementType } from "./react"; 4 | 5 | type ResolveRefProps

= Omit & { 6 | ref?: P extends { 7 | ref?: infer Ref; 8 | } 9 | ? Ref 10 | : unknown; 11 | }; 12 | 13 | export type PolymorphicComponentProps = (Props & { 14 | as?: ET; 15 | } & { 16 | children?: ReactNode; 17 | }) & 18 | Omit>, "as" | keyof Props>; 19 | 20 | type ResolvePolymorphicRef

= ForwardedRef< 21 | P extends { 22 | ref?: infer Ref; 23 | } 24 | ? Ref 25 | : any 26 | >; 27 | 28 | export type PolymorphicRef = ResolvePolymorphicRef>; 29 | -------------------------------------------------------------------------------- /packages/react/src/types/react.ts: -------------------------------------------------------------------------------- 1 | import type { ComponentType, JSX } from "react"; 2 | 3 | export type SupportedComponentType

= ComponentType

; 4 | 5 | export type SupportedComponentProps = T extends SupportedComponentType 6 | ? P 7 | : T extends keyof JSX.IntrinsicElements 8 | ? JSX.IntrinsicElements[T] 9 | : {}; 10 | 11 | export type SupportedElementType

= 12 | | { 13 | [K in keyof JSX.IntrinsicElements]: P extends JSX.IntrinsicElements[K] ? K : never; 14 | }[keyof JSX.IntrinsicElements] 15 | | SupportedComponentType

; 16 | 17 | export type Classes = "className"; 18 | export type ClassesProps = Partial>; 19 | 20 | export type BaseComponent = { 21 | displayName?: string; 22 | }; 23 | -------------------------------------------------------------------------------- /packages/react/src/types/utils.ts: -------------------------------------------------------------------------------- 1 | export type OverrideProps = Omit & W; 2 | -------------------------------------------------------------------------------- /packages/react/src/utils.ts: -------------------------------------------------------------------------------- 1 | import type { FinalRestrictedVariantsKey, FinalVariantsSchema } from "./types"; 2 | 3 | const getVariantKeys__filterFn = /* @__PURE__ */ (el: keyof VS) => el !== "className"; 4 | export const getVariantKeys = /* @__PURE__ */ (keys: (keyof VS)[]) => 5 | keys.filter(getVariantKeys__filterFn) as unknown as Exclude[]; 6 | 7 | export const splitRestProps = /* @__PURE__ */

>(props: P, keys: string[], fkeys?: string[]) => { 8 | const o: /** omited */ Record = {}, 9 | p: /** picked */ Record = {}; 10 | let key: string; 11 | for (key in props) { 12 | const value = props[key]; 13 | if (keys.includes(key)) { 14 | p[key] = value; 15 | if (fkeys?.includes(key)) o[key] = value; 16 | } else { 17 | o[key] = value; 18 | } 19 | } 20 | return { o, p } as const; 21 | }; 22 | -------------------------------------------------------------------------------- /packages/react/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "forceConsistentCasingInFileNames": true, 5 | "target": "ESNext", 6 | "module": "ESNext", 7 | "lib": ["ESNext", "DOM", "DOM.Iterable"], 8 | "moduleResolution": "bundler", 9 | "esModuleInterop": true, 10 | "allowImportingTsExtensions": true, 11 | "allowSyntheticDefaultImports": true, 12 | "allowJs": true, 13 | "resolveJsonModule": true, 14 | "skipLibCheck": true, 15 | "strictNullChecks": true, 16 | "declaration": true, 17 | "removeComments": false, 18 | "noUnusedLocals": true, 19 | "noUnusedParameters": true, 20 | "noEmit": true, 21 | "jsx": "react-jsx", 22 | "jsxImportSource": "react" 23 | }, 24 | "include": ["src"], 25 | "exclude": ["node_modules", "dist"] 26 | } 27 | -------------------------------------------------------------------------------- /packages/react/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | 3 | import react from "@vitejs/plugin-react"; 4 | 5 | import { build, dts } from "../config"; 6 | 7 | export default defineConfig({ 8 | plugins: [react(), dts(["src/**/*.{ts,tsx}"])], 9 | build: build(["utils.ts", "index.tsx", "create.tsx", "mono/index.tsx", "mono/create.tsx"]), 10 | }); 11 | -------------------------------------------------------------------------------- /packages/solid/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | .turbo 4 | 5 | dist 6 | -------------------------------------------------------------------------------- /packages/solid/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 |

4 |

klass

5 |

6 | 7 |

8 | 9 | license 10 | 11 | 12 | version 13 | 14 | 15 | size 16 | 17 | downloads 18 |

19 | 20 | # @klass/solid 21 | 22 | ## Introduction 23 | 24 | Class variant utility for Solid. 25 | 26 | ## Documentation 27 | 28 | 29 | license 30 | 31 | 32 | ## Installation 33 | 34 | ```sh 35 | npm install @klass/core @klass/solid 36 | # or 37 | yarn add @klass/core @klass/solid 38 | # or 39 | pnpm add @klass/core @klass/solid 40 | # or 41 | bun add @klass/core @klass/solid 42 | ``` 43 | 44 | ## Usage 45 | 46 | ```tsx 47 | import { klassed, reklassed } from "@klass/solid"; 48 | 49 | const Button = klassed( 50 | "button", 51 | { 52 | base: "inline-flex items-center justify-center rounded-md outline-none", 53 | variants: { 54 | color: { 55 | default: "bg-neutral-700 text-white", 56 | primary: "bg-indigo-700 text-white", 57 | secondary: "bg-orange-700 text-white", 58 | }, 59 | size: { 60 | sm: "px-3 py-0.5 h-7 text-sm font-medium", 61 | md: "px-4 py-1 h-8 text-base font-medium", 62 | lg: "px-5 py-1.5 h-9 text-lg font-semibold", 63 | }, 64 | block: { 65 | true: "w-full", 66 | }, 67 | // "class" & "classList" variants are not allowed 68 | }, 69 | defaults: { 70 | color: "default", 71 | size: "md", 72 | }, 73 | }, 74 | { 75 | // default props 76 | dp: { 77 | type: "button", 78 | }, 79 | } 80 | ); 81 | 82 | const Box = reklassed("div", { 83 | conditions: [ 84 | { 85 | base: "", 86 | sm: "sm:", 87 | md: "md:", 88 | lg: "lg:", 89 | xl: "xl:", 90 | "2xl": "2xl:", 91 | }, 92 | "base", 93 | ], 94 | variants: { 95 | m: { 96 | "0": "m-0", 97 | "1": "m-1", 98 | "2": "m-2", 99 | "3": "m-3", 100 | "4": "m-4", 101 | "5": "m-5", 102 | "6": "m-6", 103 | "7": "m-7", 104 | "8": "m-8", 105 | }, 106 | p: { 107 | "0": "p-0", 108 | "1": "p-1", 109 | "2": "p-2", 110 | "3": "p-3", 111 | "4": "p-4", 112 | "5": "p-5", 113 | "6": "p-6", 114 | "7": "p-7", 115 | "8": "p-8", 116 | }, 117 | }, 118 | }); 119 | 120 | const App = () => { 121 | return ( 122 | 123 | 124 | 127 | 128 | 129 | 130 | 133 | 134 | 135 | ); 136 | }; 137 | 138 | export default App; 139 | ``` 140 | 141 | ## Authors 142 | 143 |

144 | 145 | 146 | 147 | github 148 | 149 | 150 |

151 | 152 | ## License 153 | 154 | [MIT License](https://github.com/flamrdevs/klass/blob/main/LICENSE) 155 | -------------------------------------------------------------------------------- /packages/solid/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@klass/solid", 3 | "version": "4.0.0-next.29", 4 | "description": "Class variant utility for Solid", 5 | "keywords": [ 6 | "class", 7 | "classname", 8 | "variant", 9 | "variants", 10 | "utility", 11 | "responsive", 12 | "typescript", 13 | "solid", 14 | "component", 15 | "styled", 16 | "polymorphic" 17 | ], 18 | "license": "MIT", 19 | "author": { 20 | "name": "flamrdevs" 21 | }, 22 | "type": "module", 23 | "main": "./dist/index.cjs", 24 | "types": "./dist/index.d.ts", 25 | "exports": { 26 | ".": { 27 | "types": "./dist/index.d.ts", 28 | "import": "./dist/index.js", 29 | "require": "./dist/index.cjs" 30 | }, 31 | "./create": { 32 | "types": "./dist/create.d.ts", 33 | "import": "./dist/create.js", 34 | "require": "./dist/create.cjs" 35 | }, 36 | "./utils": { 37 | "types": "./dist/utils.d.ts", 38 | "import": "./dist/utils.js", 39 | "require": "./dist/utils.cjs" 40 | }, 41 | "./mono": { 42 | "types": "./dist/mono/index.d.ts", 43 | "import": "./dist/mono/index.js", 44 | "require": "./dist/mono/index.cjs" 45 | }, 46 | "./mono/create": { 47 | "types": "./dist/mono/create.d.ts", 48 | "import": "./dist/mono/create.js", 49 | "require": "./dist/mono/create.cjs" 50 | } 51 | }, 52 | "typesVersions": { 53 | ">=3.1": { 54 | "*": [ 55 | "./dist/*.d.ts", 56 | "./dist/index.d.ts" 57 | ], 58 | "mono": [ 59 | "./dist/mono/*.d.ts", 60 | "./dist/mono/index.d.ts" 61 | ] 62 | } 63 | }, 64 | "files": [ 65 | "dist" 66 | ], 67 | "homepage": "https://klass.pages.dev", 68 | "repository": { 69 | "type": "git", 70 | "url": "git+https://github.com/flamrdevs/klass.git", 71 | "directory": "packages/solid" 72 | }, 73 | "scripts": { 74 | "build": "vite build" 75 | }, 76 | "peerDependencies": { 77 | "@klass/core": "workspace:*", 78 | "solid-js": "^1" 79 | }, 80 | "devDependencies": { 81 | "@klass/core": "workspace:*", 82 | "solid-js": "^1" 83 | }, 84 | "publishConfig": { 85 | "access": "public" 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /packages/solid/src/create.tsx: -------------------------------------------------------------------------------- 1 | import { mergeProps, splitProps } from "solid-js"; 2 | import { Dynamic } from "solid-js/web"; 3 | 4 | import type { Compose, ComposeFn, ConditionSchema, FxFrom, Fxs, Klass, KlassFn, Reklass, ReklassFn } from "@klass/core"; 5 | import { typeofFunction } from "@klass/core/utils"; 6 | 7 | import type { 8 | ComponentConfig, 9 | ComposedComponent, 10 | ComposedComponentConfig, 11 | ComposedOptions, 12 | DefaultPropsConfig, 13 | FinalVariantsSchema, 14 | ForwardPropsConfig, 15 | KlassedComponent, 16 | KlassedOptions, 17 | ReklassedComponent, 18 | ReklassedOptions, 19 | } from "./types"; 20 | import type { ClassesProps, SupportedElementType } from "./types/solid"; 21 | 22 | import { ClassesKeysSplitter, PolymorphicKeysSplitter, classesProps, getVariantKeys } from "./utils"; 23 | 24 | function create(element: ET, fn: KlassFn> | ReklassFn> | ComposeFn, config: DefaultPropsConfig & ForwardPropsConfig = {}) { 25 | const { class: defaultClass, classList: defaultClassList, ...defaultProps } = (config.dp ?? {}) as ClassesProps, 26 | keys = getVariantKeys(fn.k), 27 | fp = config.fp ?? []; 28 | 29 | const Comp = ((props: any) => { 30 | const [polymorphic, classes, picked, omited] = splitProps(props, PolymorphicKeysSplitter, ClassesKeysSplitter, keys as any); 31 | const [forward] = splitProps(picked, fp); 32 | 33 | return ( 34 | 35 | ); 36 | }) as any; 37 | 38 | return (Comp.fx = fn), Comp; 39 | } 40 | 41 | type Klassed = (element: ET, options: KlassedOptions, config?: ComponentConfig | undefined) => KlassedComponent; 42 | type Reklassed = ( 43 | element: ET, 44 | options: ReklassedOptions, 45 | config?: ComponentConfig 46 | ) => ReklassedComponent; 47 | type Composed = (element: ET, options: ComposedOptions, config?: ComposedComponentConfig>) => ComposedComponent>; 48 | 49 | const createKlassed = 50 | (klass: Klass): Klassed => 51 | (element, options, config) => 52 | /* @__PURE__ */ create(element, typeofFunction(options) ? options : klass(options), config) as any; 53 | const createReklassed = 54 | (reklass: Reklass): Reklassed => 55 | (element, options, config) => 56 | /* @__PURE__ */ create(element, typeofFunction(options) ? options : reklass(options), config) as any; 57 | const createComposed = 58 | (compose: Compose): Composed => 59 | (element, options, config) => 60 | /* @__PURE__ */ create(element, typeofFunction(options) ? options : compose(...options), config) as any; 61 | 62 | export { createKlassed, createReklassed, createComposed }; 63 | -------------------------------------------------------------------------------- /packages/solid/src/index.tsx: -------------------------------------------------------------------------------- 1 | import { compose, klass, reklass } from "@klass/core"; 2 | import type { 3 | AsFn, 4 | AsFnProps, 5 | BaseFn, 6 | Compose, 7 | ComposeFn, 8 | CompoundVariant, 9 | ConditionSchema, 10 | EndFn, 11 | EndFnProps, 12 | Fx, 13 | FxFrom, 14 | Fxs, 15 | Klass, 16 | KlassFn, 17 | KlassOptions, 18 | Reklass, 19 | ReklassFn, 20 | ReklassOptions, 21 | RequiredVariantsFrom, 22 | RevariantFn, 23 | RevariantGroup, 24 | StrictVariantsSchema, 25 | TransformKey, 26 | UnionToIntersection, 27 | VariantFn, 28 | VariantGroup, 29 | VariantsOf, 30 | VariantsSchema, 31 | } from "@klass/core"; 32 | 33 | import { createComposed, createKlassed, createReklassed } from "./create"; 34 | 35 | const klassed = /* @__PURE__ */ createKlassed(klass); 36 | 37 | const reklassed = /* @__PURE__ */ createReklassed(reklass); 38 | 39 | const composed = /* @__PURE__ */ createComposed(compose); 40 | 41 | export type { 42 | TransformKey, 43 | EndFn, 44 | AsFn, 45 | EndFnProps, 46 | AsFnProps, 47 | VariantsSchema, 48 | StrictVariantsSchema, 49 | VariantsOf, 50 | RequiredVariantsFrom, 51 | BaseFn, 52 | VariantFn, 53 | VariantGroup, 54 | CompoundVariant, 55 | KlassOptions, 56 | KlassFn, 57 | Klass, 58 | ConditionSchema, 59 | RevariantFn, 60 | RevariantGroup, 61 | ReklassOptions, 62 | ReklassFn, 63 | Reklass, 64 | UnionToIntersection, 65 | Fx, 66 | Fxs, 67 | FxFrom, 68 | ComposeFn, 69 | Compose, 70 | }; 71 | export type { ClassesValueProps, WithClassesValueProps, KlassedComponent, ReklassedComponent, ComposedComponent } from "./types"; 72 | export { klassed, reklassed, composed }; 73 | -------------------------------------------------------------------------------- /packages/solid/src/mono/create.tsx: -------------------------------------------------------------------------------- 1 | import { mergeProps, splitProps } from "solid-js"; 2 | import { Dynamic } from "solid-js/web"; 3 | 4 | import type { Compose, ComposeFn, ConditionSchema, FxFrom, Fxs, Klass, KlassFn, Reklass, ReklassFn } from "@klass/core"; 5 | import { typeofFunction } from "@klass/core/utils"; 6 | 7 | import { ComposedOptions, DefaultPropsConfig, FinalVariantsSchema, ForwardPropsConfig, KlassedOptions, ReklassedOptions } from "./../types"; 8 | import type { ClassesProps, SupportedElementType } from "./../types/solid"; 9 | 10 | import { ClassesKeysSplitter, classesProps, getVariantKeys } from "./../utils"; 11 | 12 | import type { ComponentConfig, ComposedComponentConfig, MonoComposedComponent, MonoKlassedComponent, MonoReklassedComponent } from "./types"; 13 | 14 | function create(element: ET, fn: KlassFn> | ReklassFn> | ComposeFn, config: DefaultPropsConfig & ForwardPropsConfig = {}) { 15 | const { class: defaultClass, classList: defaultClassList, ...defaultProps } = (config.dp ?? {}) as ClassesProps, 16 | keys = getVariantKeys(fn.k), 17 | fp = config.fp ?? []; 18 | 19 | const Comp = ((props: any) => { 20 | const [classes, picked, omited] = splitProps(props, ClassesKeysSplitter, keys as any); 21 | const [forward] = splitProps(picked, fp); 22 | 23 | return ; 24 | }) as any; 25 | 26 | return (Comp.fx = fn), Comp; 27 | } 28 | 29 | type Klassed = ( 30 | element: ET, 31 | options: KlassedOptions, 32 | config?: ComponentConfig | undefined 33 | ) => MonoKlassedComponent; 34 | type Reklassed = ( 35 | element: ET, 36 | options: ReklassedOptions, 37 | config?: ComponentConfig 38 | ) => MonoReklassedComponent; 39 | type Composed = (element: ET, options: ComposedOptions, config?: ComposedComponentConfig>) => MonoComposedComponent>; 40 | 41 | const createKlassed = 42 | (klass: Klass): Klassed => 43 | (element, options, config) => 44 | /* @__PURE__ */ create(element, typeofFunction(options) ? options : klass(options), config) as any; 45 | const createReklassed = 46 | (reklass: Reklass): Reklassed => 47 | (element, options, config) => 48 | /* @__PURE__ */ create(element, typeofFunction(options) ? options : reklass(options), config) as any; 49 | const createComposed = 50 | (compose: Compose): Composed => 51 | (element, options, config) => 52 | /* @__PURE__ */ create(element, typeofFunction(options) ? options : compose(...options), config) as any; 53 | 54 | export type { MonoKlassedComponent, MonoReklassedComponent, MonoComposedComponent }; 55 | export { createKlassed, createReklassed, createComposed }; 56 | -------------------------------------------------------------------------------- /packages/solid/src/mono/index.tsx: -------------------------------------------------------------------------------- 1 | import { compose, klass, reklass } from "@klass/core"; 2 | import type { 3 | AsFn, 4 | AsFnProps, 5 | BaseFn, 6 | Compose, 7 | ComposeFn, 8 | CompoundVariant, 9 | ConditionSchema, 10 | EndFn, 11 | EndFnProps, 12 | Fx, 13 | FxFrom, 14 | Fxs, 15 | Klass, 16 | KlassFn, 17 | KlassOptions, 18 | Reklass, 19 | ReklassFn, 20 | ReklassOptions, 21 | RequiredVariantsFrom, 22 | RevariantFn, 23 | RevariantGroup, 24 | StrictVariantsSchema, 25 | TransformKey, 26 | UnionToIntersection, 27 | VariantFn, 28 | VariantGroup, 29 | VariantsOf, 30 | VariantsSchema, 31 | } from "@klass/core"; 32 | 33 | import { createComposed, createKlassed, createReklassed } from "./create"; 34 | 35 | const klassed = /* @__PURE__ */ createKlassed(klass); 36 | 37 | const reklassed = /* @__PURE__ */ createReklassed(reklass); 38 | 39 | const composed = /* @__PURE__ */ createComposed(compose); 40 | 41 | export type { 42 | TransformKey, 43 | EndFn, 44 | AsFn, 45 | EndFnProps, 46 | AsFnProps, 47 | VariantsSchema, 48 | StrictVariantsSchema, 49 | VariantsOf, 50 | RequiredVariantsFrom, 51 | BaseFn, 52 | VariantFn, 53 | VariantGroup, 54 | CompoundVariant, 55 | KlassOptions, 56 | KlassFn, 57 | Klass, 58 | ConditionSchema, 59 | RevariantFn, 60 | RevariantGroup, 61 | ReklassOptions, 62 | ReklassFn, 63 | Reklass, 64 | UnionToIntersection, 65 | Fx, 66 | Fxs, 67 | FxFrom, 68 | ComposeFn, 69 | Compose, 70 | }; 71 | export type { MonoKlassedComponent, MonoReklassedComponent, MonoComposedComponent } from "./types"; 72 | export { klassed, reklassed, composed }; 73 | -------------------------------------------------------------------------------- /packages/solid/src/mono/types.ts: -------------------------------------------------------------------------------- 1 | import type { JSX } from "solid-js"; 2 | 3 | import type { ComposeFn, ConditionSchema, Fx, KlassFn, ReklassFn, VariantsOf } from "@klass/core"; 4 | 5 | import { Base, DefaultPropsConfig, FinalVariantsSchema, ForwardPropsConfig, WithClassesValueProps } from "./../types"; 6 | import type { SupportedComponentProps, SupportedElementType } from "./../types/solid"; 7 | import { OverrideProps } from "./../types/utils"; 8 | 9 | export type ComponentConfig = DefaultPropsConfig> & ForwardPropsConfig; 10 | export type ComposedComponentConfig = DefaultPropsConfig> & ForwardPropsConfig; 11 | 12 | export type MonoKlassedComponent = { 13 | (props: WithClassesValueProps, VariantsOf>>>): JSX.Element; 14 | } & Base>; 15 | 16 | export type MonoReklassedComponent = { 17 | (props: WithClassesValueProps, VariantsOf>>>): JSX.Element; 18 | } & Base>; 19 | 20 | export type MonoComposedComponent = { 21 | (props: WithClassesValueProps, VariantsOf>>>): JSX.Element; 22 | } & Base>; 23 | -------------------------------------------------------------------------------- /packages/solid/src/types/index.ts: -------------------------------------------------------------------------------- 1 | import type { JSX } from "solid-js"; 2 | 3 | import type { ClassValue, ComposeFn, ConditionSchema, Fx, FxFrom, Fxs, KlassFn, KlassOptions, ReklassFn, ReklassOptions, StrictVariantsSchema, VariantsOf } from "@klass/core"; 4 | 5 | import type { PolymorphicComponentProps } from "./polymorphic"; 6 | import type { Classes, SupportedElementType } from "./solid"; 7 | 8 | export type FinalRestrictedVariantsKey = Classes; 9 | export type FinalVariantsSchema = StrictVariantsSchema; 10 | 11 | export type ClassesValueProps = Partial>; 12 | export type WithClassesValueProps

= Omit & ClassesValueProps; 13 | 14 | export type KlassedOptions = KlassOptions | KlassFn; 15 | export type ReklassedOptions = ReklassOptions | ReklassFn; 16 | export type ComposedOptions = Fn[] | ComposeFn>; 17 | 18 | export type DefaultPropsConfig> = { dp?: DP }; 19 | export type ForwardPropsConfig = { fp?: T[] }; 20 | export type ComponentConfig = DefaultPropsConfig> & ForwardPropsConfig; 21 | export type ComposedComponentConfig = DefaultPropsConfig> & ForwardPropsConfig; 22 | 23 | export type Base = { fx: F }; 24 | 25 | export type KlassedComponent = { 26 | (props: PolymorphicComponentProps>>>): JSX.Element; 27 | } & Base>; 28 | 29 | export type ReklassedComponent = { 30 | (props: PolymorphicComponentProps>>>): JSX.Element; 31 | } & Base>; 32 | 33 | export type ComposedComponent = { 34 | (props: PolymorphicComponentProps>>>): JSX.Element; 35 | } & Base>; 36 | -------------------------------------------------------------------------------- /packages/solid/src/types/polymorphic.ts: -------------------------------------------------------------------------------- 1 | import type { JSX } from "solid-js"; 2 | 3 | import type { SupportedComponentProps, SupportedElementType } from "./solid"; 4 | 5 | type ResolveRefProps

= Omit & { 6 | ref?: P extends { 7 | ref?: infer Ref; 8 | } 9 | ? Ref 10 | : unknown; 11 | }; 12 | 13 | export type PolymorphicComponentProps = (Props & { 14 | as?: ET; 15 | } & { 16 | children?: JSX.Element; 17 | }) & 18 | Omit>, "as" | keyof Props>; 19 | -------------------------------------------------------------------------------- /packages/solid/src/types/solid.ts: -------------------------------------------------------------------------------- 1 | import type { Component, JSX } from "solid-js"; 2 | 3 | export type SupportedComponentType

= Component

; 4 | 5 | export type SupportedComponentProps = T extends SupportedComponentType 6 | ? P 7 | : T extends keyof JSX.IntrinsicElements 8 | ? JSX.IntrinsicElements[T] 9 | : {}; 10 | 11 | export type SupportedElementType

= 12 | | { 13 | [K in keyof JSX.IntrinsicElements]: P extends JSX.IntrinsicElements[K] ? K : never; 14 | }[keyof JSX.IntrinsicElements] 15 | | SupportedComponentType

; 16 | 17 | export type Classes = "class" | "classList"; 18 | export type ClassesProps = { 19 | class?: string; 20 | classList?: { 21 | [k: string]: boolean | undefined; 22 | }; 23 | }; 24 | -------------------------------------------------------------------------------- /packages/solid/src/types/utils.ts: -------------------------------------------------------------------------------- 1 | export type OverrideProps = Omit & W; 2 | -------------------------------------------------------------------------------- /packages/solid/src/utils.ts: -------------------------------------------------------------------------------- 1 | import type { ClassValue } from "@klass/core"; 2 | 3 | import type { ClassesValueProps, FinalRestrictedVariantsKey, FinalVariantsSchema } from "./types"; 4 | import type { ClassesProps } from "./types/solid"; 5 | 6 | const getVariantKeys__filterFn = /* @__PURE__ */ (el: keyof VS) => el !== "class" && el !== "classList"; 7 | export const getVariantKeys = /* @__PURE__ */ (keys: (keyof VS)[]) => 8 | keys.filter(getVariantKeys__filterFn) as unknown as Exclude[]; 9 | 10 | export const PolymorphicKeysSplitter = ["as"] as const; 11 | export const ClassesKeysSplitter = ["class", "classList"] as const; 12 | 13 | export const classesProps: (props: ClassesValueProps, defaultClass?: ClassesProps["class"], defaultClassList?: ClassesProps["classList"]) => [ClassValue, ClassValue] = /* @__PURE__ */ ( 14 | props, 15 | defaultClass, 16 | defaultClassList 17 | ) => [props.class ?? defaultClass, props.classList ?? defaultClassList]; 18 | -------------------------------------------------------------------------------- /packages/solid/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "forceConsistentCasingInFileNames": true, 5 | "target": "ESNext", 6 | "module": "ESNext", 7 | "lib": ["ESNext", "DOM", "DOM.Iterable"], 8 | "moduleResolution": "bundler", 9 | "esModuleInterop": true, 10 | "allowImportingTsExtensions": true, 11 | "allowSyntheticDefaultImports": true, 12 | "allowJs": true, 13 | "resolveJsonModule": true, 14 | "skipLibCheck": true, 15 | "strictNullChecks": true, 16 | "declaration": true, 17 | "removeComments": false, 18 | "noUnusedLocals": true, 19 | "noUnusedParameters": true, 20 | "noEmit": true, 21 | "jsx": "preserve", 22 | "jsxImportSource": "solid-js" 23 | }, 24 | "include": ["src"], 25 | "exclude": ["node_modules", "dist"] 26 | } 27 | -------------------------------------------------------------------------------- /packages/solid/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | 3 | import solid from "vite-plugin-solid"; 4 | 5 | import { build, dts } from "../config"; 6 | 7 | export default defineConfig({ 8 | plugins: [solid(), dts(["src/**/*.{ts,tsx}"])], 9 | build: build(["utils.ts", "index.tsx", "create.tsx", "mono/index.tsx", "mono/create.tsx"]), 10 | }); 11 | -------------------------------------------------------------------------------- /packages/vue/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | .turbo 4 | 5 | dist 6 | -------------------------------------------------------------------------------- /packages/vue/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @klass/vue 2 | 3 | ## 4.0.0-next.29 4 | 5 | ### Patch Changes 6 | 7 | - 7867f62: better workspaces 8 | - Updated dependencies [7867f62] 9 | - @klass/core@4.0.0-next.29 10 | 11 | ## 4.0.0-next.28 12 | 13 | ### Patch Changes 14 | 15 | - fix types 16 | - Updated dependencies 17 | - @klass/core@4.0.0-next.28 18 | 19 | ## 4.0.0-next.27 20 | 21 | ### Patch Changes 22 | 23 | - compose with string 24 | - Updated dependencies 25 | - @klass/core@4.0.0-next.27 26 | 27 | ## 4.0.0-next.26 28 | 29 | ### Patch Changes 30 | 31 | - build improvements 32 | - Updated dependencies 33 | - @klass/core@4.0.0-next.26 34 | 35 | ## 4.0.0-next.25 36 | 37 | ### Patch Changes 38 | 39 | - stricts customization only with top-level configurations 40 | - Updated dependencies 41 | - @klass/core@4.0.0-next.25 42 | 43 | ## 4.0.0-next.24 44 | 45 | ### Patch Changes 46 | 47 | - experimental compose 48 | - Updated dependencies 49 | - @klass/core@4.0.0-next.24 50 | 51 | ## 4.0.0-next.23 52 | 53 | ### Patch Changes 54 | 55 | - remove o property and rename component to fx property 56 | - Updated dependencies 57 | - @klass/core@4.0.0-next.23 58 | 59 | ## 4.0.0-next.22 60 | 61 | ### Patch Changes 62 | 63 | - improves compatibility 64 | - Updated dependencies 65 | - @klass/core@4.0.0-next.22 66 | 67 | ## 4.0.0-next.21 68 | 69 | ### Patch Changes 70 | 71 | - test improvements 72 | - Updated dependencies 73 | - @klass/core@4.0.0-next.21 74 | 75 | ## 4.0.0-next.20 76 | 77 | ### Patch Changes 78 | 79 | - fix polymorphism 80 | - Updated dependencies 81 | - @klass/core@4.0.0-next.20 82 | 83 | ## 4.0.0-next.19 84 | 85 | ### Patch Changes 86 | 87 | - frameworks compatibility 88 | - Updated dependencies 89 | - @klass/core@4.0.0-next.19 90 | 91 | ## 4.0.0-next.18 92 | 93 | ### Patch Changes 94 | 95 | - fix build 96 | - Updated dependencies 97 | - @klass/core@4.0.0-next.18 98 | 99 | ## 4.0.0-next.17 100 | 101 | ### Patch Changes 102 | 103 | - optimization 104 | - Updated dependencies 105 | - @klass/core@4.0.0-next.17 106 | 107 | ## 4.0.0-next.16 108 | 109 | ### Patch Changes 110 | 111 | - refactor modules fix types and feat setup 112 | - Updated dependencies 113 | - @klass/core@4.0.0-next.16 114 | 115 | ## 4.0.0-next.15 116 | 117 | ### Patch Changes 118 | 119 | - initialization improvements 120 | - Updated dependencies 121 | - @klass/core@4.0.0-next.15 122 | 123 | ## 4.0.0-next.14 124 | 125 | ### Patch Changes 126 | 127 | - fix test & build and type improvements 128 | - Updated dependencies 129 | - @klass/core@4.0.0-next.14 130 | 131 | ## 4.0.0-next.13 132 | 133 | ### Patch Changes 134 | 135 | - refactoring typescript features 136 | - Updated dependencies 137 | - @klass/core@4.0.0-next.13 138 | 139 | ## 4.0.0-next.12 140 | 141 | ### Patch Changes 142 | 143 | - clean type, fix dts and feat new mono setup 144 | - Updated dependencies 145 | - @klass/core@4.0.0-next.12 146 | 147 | ## 4.0.0-next.11 148 | 149 | ### Patch Changes 150 | 151 | - named import and base fn 152 | - Updated dependencies 153 | - @klass/core@4.0.0-next.11 154 | 155 | ## 4.0.0-next.10 156 | 157 | ### Patch Changes 158 | 159 | - Update README.md 160 | - Updated dependencies 161 | - @klass/core@4.0.0-next.10 162 | 163 | ## 4.0.0-next.9 164 | 165 | ### Patch Changes 166 | 167 | - Testing improvements 168 | - Updated dependencies 169 | - @klass/core@4.0.0-next.9 170 | 171 | ## 4.0.0-next.8 172 | 173 | ### Patch Changes 174 | 175 | - README 176 | - Updated dependencies 177 | - @klass/core@4.0.0-next.8 178 | 179 | ## 4.0.0-next.7 180 | 181 | ### Patch Changes 182 | 183 | - Types improvements and new frameworks monomorphic feature 184 | - Updated dependencies 185 | - @klass/core@4.0.0-next.7 186 | 187 | ## 4.0.0-next.6 188 | 189 | ### Patch Changes 190 | 191 | - klasses function options, setup API and utils entry 192 | - Updated dependencies 193 | - @klass/core@4.0.0-next.6 194 | 195 | ## 4.0.0-next.5 196 | 197 | ### Patch Changes 198 | 199 | - Optimization 200 | - Updated dependencies 201 | - @klass/core@4.0.0-next.5 202 | 203 | ## 4.0.0-next.4 204 | 205 | ### Patch Changes 206 | 207 | - Optimization 208 | - Updated dependencies 209 | - @klass/core@4.0.0-next.4 210 | 211 | ## 4.0.0-next.3 212 | 213 | ### Patch Changes 214 | 215 | - Optimizations 216 | - Updated dependencies 217 | - @klass/core@4.0.0-next.3 218 | 219 | ## 4.0.0-next.2 220 | 221 | ### Patch Changes 222 | 223 | - New Vue and Qwik packages 224 | - Updated dependencies 225 | - @klass/core@4.0.0-next.2 226 | -------------------------------------------------------------------------------- /packages/vue/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 |

4 |

klass

5 |

6 | 7 |

8 | 9 | license 10 | 11 | 12 | version 13 | 14 | 15 | size 16 | 17 | downloads 18 |

19 | 20 | # @klass/vue 21 | 22 | ## Introduction 23 | 24 | Class variant utility for Vue. 25 | 26 | ## Documentation 27 | 28 | 29 | license 30 | 31 | 32 | ## Installation 33 | 34 | ```sh 35 | npm install @klass/core @klass/vue 36 | # or 37 | yarn add @klass/core @klass/vue 38 | # or 39 | pnpm add @klass/core @klass/vue 40 | # or 41 | bun add @klass/core @klass/vue 42 | ``` 43 | 44 | ## Usage 45 | 46 | ```tsx 47 | import { klassed, reklassed } from "@klass/vue"; 48 | 49 | const Button = klassed( 50 | "button", 51 | { 52 | base: "inline-flex items-center justify-center rounded-md outline-none", 53 | variants: { 54 | color: { 55 | default: "bg-neutral-700 text-white", 56 | primary: "bg-indigo-700 text-white", 57 | secondary: "bg-orange-700 text-white", 58 | }, 59 | size: { 60 | sm: "px-3 py-0.5 h-7 text-sm font-medium", 61 | md: "px-4 py-1 h-8 text-base font-medium", 62 | lg: "px-5 py-1.5 h-9 text-lg font-semibold", 63 | }, 64 | block: { 65 | true: "w-full", 66 | }, 67 | // "class" variants are not allowed 68 | }, 69 | defaults: { 70 | color: "default", 71 | size: "md", 72 | }, 73 | }, 74 | { 75 | // default props 76 | dp: { 77 | type: "button", 78 | }, 79 | } 80 | ); 81 | 82 | const Box = reklassed("div", { 83 | conditions: [ 84 | { 85 | base: "", 86 | sm: "sm:", 87 | md: "md:", 88 | lg: "lg:", 89 | xl: "xl:", 90 | "2xl": "2xl:", 91 | }, 92 | "base", 93 | ], 94 | variants: { 95 | m: { 96 | "0": "m-0", 97 | "1": "m-1", 98 | "2": "m-2", 99 | "3": "m-3", 100 | "4": "m-4", 101 | "5": "m-5", 102 | "6": "m-6", 103 | "7": "m-7", 104 | "8": "m-8", 105 | }, 106 | p: { 107 | "0": "p-0", 108 | "1": "p-1", 109 | "2": "p-2", 110 | "3": "p-3", 111 | "4": "p-4", 112 | "5": "p-5", 113 | "6": "p-6", 114 | "7": "p-7", 115 | "8": "p-8", 116 | }, 117 | }, 118 | }); 119 | 120 | const App = () => { 121 | return ( 122 | 123 | 124 | 127 | 128 | 129 | 130 | 133 | 134 | 135 | ); 136 | }; 137 | 138 | export default App; 139 | ``` 140 | 141 | ## Authors 142 | 143 |

144 | 145 | 146 | 147 | github 148 | 149 | 150 |

151 | 152 | ## License 153 | 154 | [MIT License](https://github.com/flamrdevs/klass/blob/main/LICENSE) 155 | -------------------------------------------------------------------------------- /packages/vue/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@klass/vue", 3 | "version": "4.0.0-next.29", 4 | "description": "Class variant utility for Vue", 5 | "keywords": [ 6 | "class", 7 | "classname", 8 | "variant", 9 | "variants", 10 | "utility", 11 | "responsive", 12 | "typescript", 13 | "vue", 14 | "component", 15 | "styled", 16 | "polymorphic" 17 | ], 18 | "license": "MIT", 19 | "author": { 20 | "name": "flamrdevs" 21 | }, 22 | "type": "module", 23 | "main": "./dist/index.cjs", 24 | "types": "./dist/index.d.ts", 25 | "exports": { 26 | ".": { 27 | "types": "./dist/index.d.ts", 28 | "import": "./dist/index.js", 29 | "require": "./dist/index.cjs" 30 | }, 31 | "./create": { 32 | "types": "./dist/create.d.ts", 33 | "import": "./dist/create.js", 34 | "require": "./dist/create.cjs" 35 | }, 36 | "./utils": { 37 | "types": "./dist/utils.d.ts", 38 | "import": "./dist/utils.js", 39 | "require": "./dist/utils.cjs" 40 | }, 41 | "./mono": { 42 | "types": "./dist/mono/index.d.ts", 43 | "import": "./dist/mono/index.js", 44 | "require": "./dist/mono/index.cjs" 45 | }, 46 | "./mono/create": { 47 | "types": "./dist/mono/create.d.ts", 48 | "import": "./dist/mono/create.js", 49 | "require": "./dist/mono/create.cjs" 50 | } 51 | }, 52 | "typesVersions": { 53 | ">=3.1": { 54 | "*": [ 55 | "./dist/*.d.ts", 56 | "./dist/index.d.ts" 57 | ], 58 | "mono": [ 59 | "./dist/mono/*.d.ts", 60 | "./dist/mono/index.d.ts" 61 | ] 62 | } 63 | }, 64 | "files": [ 65 | "dist" 66 | ], 67 | "homepage": "https://klass.pages.dev", 68 | "repository": { 69 | "type": "git", 70 | "url": "git+https://github.com/flamrdevs/klass.git", 71 | "directory": "packages/vue" 72 | }, 73 | "scripts": { 74 | "build": "vite build" 75 | }, 76 | "peerDependencies": { 77 | "@klass/core": "workspace:*", 78 | "vue": "^3" 79 | }, 80 | "devDependencies": { 81 | "@klass/core": "workspace:*", 82 | "vue": "^3" 83 | }, 84 | "publishConfig": { 85 | "access": "public" 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /packages/vue/src/create.tsx: -------------------------------------------------------------------------------- 1 | import { computed, defineComponent, h } from "vue"; 2 | 3 | import type { Compose, ComposeFn, ConditionSchema, FxFrom, Fxs, Klass, KlassFn, Reklass, ReklassFn } from "@klass/core"; 4 | import { typeofFunction } from "@klass/core/utils"; 5 | 6 | import type { 7 | ComponentConfig, 8 | ComposedComponent, 9 | ComposedComponentConfig, 10 | ComposedOptions, 11 | DefaultPropsConfig, 12 | FinalVariantsSchema, 13 | ForwardPropsConfig, 14 | KlassedComponent, 15 | KlassedOptions, 16 | ReklassedComponent, 17 | ReklassedOptions, 18 | } from "./types"; 19 | import type { PolymorphicComponentProps } from "./types/polymorphic"; 20 | import type { ClassesProps, SupportedElementType } from "./types/vue"; 21 | 22 | import { getVariantKeys, splitRestProps } from "./utils"; 23 | 24 | const defaultComponentOptions = { props: ["as", "class"] as any, inheritAttrs: false }; 25 | 26 | function create(element: ET, fn: KlassFn> | ReklassFn> | ComposeFn, config: DefaultPropsConfig & ForwardPropsConfig = {}) { 27 | const { class: defaultClass, ...defaultProps } = (config.dp ?? {}) as ClassesProps, 28 | keys = getVariantKeys(fn.k); 29 | 30 | const Comp = defineComponent>((props, { attrs, slots }) => { 31 | const splitted = computed(() => splitRestProps(attrs, keys, config.fp)); 32 | 33 | return () => h(props.as ?? element, { ...defaultProps, ...(splitted.value.o as any), class: fn(splitted.value.p, (props.class ?? defaultClass) as any) }, slots); 34 | }, defaultComponentOptions) as any; 35 | 36 | return (Comp.fx = fn), Comp; 37 | } 38 | 39 | type Klassed = (element: ET, options: KlassedOptions, config?: ComponentConfig | undefined) => KlassedComponent; 40 | type Reklassed = ( 41 | element: ET, 42 | options: ReklassedOptions, 43 | config?: ComponentConfig 44 | ) => ReklassedComponent; 45 | type Composed = (element: ET, options: ComposedOptions, config?: ComposedComponentConfig>) => ComposedComponent>; 46 | 47 | const createKlassed = 48 | (klass: Klass): Klassed => 49 | (element, options, config) => 50 | /* @__PURE__ */ create(element, typeofFunction(options) ? options : klass(options), config) as any; 51 | const createReklassed = 52 | (reklass: Reklass): Reklassed => 53 | (element, options, config) => 54 | /* @__PURE__ */ create(element, typeofFunction(options) ? options : reklass(options), config) as any; 55 | const createComposed = 56 | (compose: Compose): Composed => 57 | (element, options, config) => 58 | /* @__PURE__ */ create(element, typeofFunction(options) ? options : compose(...options), config) as any; 59 | 60 | export { createKlassed, createReklassed, createComposed }; 61 | -------------------------------------------------------------------------------- /packages/vue/src/index.tsx: -------------------------------------------------------------------------------- 1 | import { compose, klass, reklass } from "@klass/core"; 2 | import type { 3 | AsFn, 4 | AsFnProps, 5 | BaseFn, 6 | Compose, 7 | ComposeFn, 8 | CompoundVariant, 9 | ConditionSchema, 10 | EndFn, 11 | EndFnProps, 12 | Fx, 13 | FxFrom, 14 | Fxs, 15 | Klass, 16 | KlassFn, 17 | KlassOptions, 18 | Reklass, 19 | ReklassFn, 20 | ReklassOptions, 21 | RequiredVariantsFrom, 22 | RevariantFn, 23 | RevariantGroup, 24 | StrictVariantsSchema, 25 | TransformKey, 26 | UnionToIntersection, 27 | VariantFn, 28 | VariantGroup, 29 | VariantsOf, 30 | VariantsSchema, 31 | } from "@klass/core"; 32 | 33 | import { createComposed, createKlassed, createReklassed } from "./create"; 34 | 35 | const klassed = /* @__PURE__ */ createKlassed(klass); 36 | 37 | const reklassed = /* @__PURE__ */ createReklassed(reklass); 38 | 39 | const composed = /* @__PURE__ */ createComposed(compose); 40 | 41 | export type { 42 | TransformKey, 43 | EndFn, 44 | AsFn, 45 | EndFnProps, 46 | AsFnProps, 47 | VariantsSchema, 48 | StrictVariantsSchema, 49 | VariantsOf, 50 | RequiredVariantsFrom, 51 | BaseFn, 52 | VariantFn, 53 | VariantGroup, 54 | CompoundVariant, 55 | KlassOptions, 56 | KlassFn, 57 | Klass, 58 | ConditionSchema, 59 | RevariantFn, 60 | RevariantGroup, 61 | ReklassOptions, 62 | ReklassFn, 63 | Reklass, 64 | UnionToIntersection, 65 | Fx, 66 | Fxs, 67 | FxFrom, 68 | ComposeFn, 69 | Compose, 70 | }; 71 | export type { ClassesValueProps, WithClassesValueProps, KlassedComponent, ReklassedComponent, ComposedComponent } from "./types"; 72 | export { klassed, reklassed, composed }; 73 | -------------------------------------------------------------------------------- /packages/vue/src/mono/create.tsx: -------------------------------------------------------------------------------- 1 | import { computed, defineComponent, h } from "vue"; 2 | 3 | import type { Compose, ComposeFn, ConditionSchema, FxFrom, Fxs, Klass, KlassFn, Reklass, ReklassFn } from "@klass/core"; 4 | import { typeofFunction } from "@klass/core/utils"; 5 | 6 | import { ComposedOptions, DefaultPropsConfig, FinalVariantsSchema, ForwardPropsConfig, KlassedOptions, ReklassedOptions, WithClassesValueProps } from "./../types"; 7 | import type { ClassesProps, SupportedElementType } from "./../types/vue"; 8 | 9 | import { getVariantKeys, splitRestProps } from "./../utils"; 10 | 11 | import type { ComponentConfig, ComposedComponentConfig, MonoComposedComponent, MonoKlassedComponent, MonoReklassedComponent } from "./types"; 12 | 13 | const defaultComponentOptions = { 14 | props: ["class"] as any, 15 | inheritAttrs: false, 16 | }; 17 | 18 | function create(element: ET, fn: KlassFn> | ReklassFn> | ComposeFn, config: DefaultPropsConfig & ForwardPropsConfig = {}) { 19 | const { class: defaultClass, ...defaultProps } = (config.dp ?? {}) as ClassesProps, 20 | keys = getVariantKeys(fn.k); 21 | 22 | const Comp = defineComponent>((props, { attrs, slots }) => { 23 | const splitted = computed(() => splitRestProps(attrs, keys, config.fp)); 24 | 25 | return () => h(element, { ...defaultProps, ...(splitted.value.o as any), class: fn(splitted.value.p, (props.class ?? defaultClass) as any) }, slots); 26 | }, defaultComponentOptions) as any; 27 | 28 | return (Comp.fx = fn), Comp; 29 | } 30 | 31 | type Klassed = ( 32 | element: ET, 33 | options: KlassedOptions, 34 | config?: ComponentConfig | undefined 35 | ) => MonoKlassedComponent; 36 | type Reklassed = ( 37 | element: ET, 38 | options: ReklassedOptions, 39 | config?: ComponentConfig 40 | ) => MonoReklassedComponent; 41 | type Composed = (element: ET, options: ComposedOptions, config?: ComposedComponentConfig>) => MonoComposedComponent>; 42 | 43 | const createKlassed = 44 | (klass: Klass): Klassed => 45 | (element, options, config) => 46 | /* @__PURE__ */ create(element, typeofFunction(options) ? options : klass(options), config) as any; 47 | const createReklassed = 48 | (reklass: Reklass): Reklassed => 49 | (element, options, config) => 50 | /* @__PURE__ */ create(element, typeofFunction(options) ? options : reklass(options), config) as any; 51 | const createComposed = 52 | (compose: Compose): Composed => 53 | (element, options, config) => 54 | /* @__PURE__ */ create(element, typeofFunction(options) ? options : compose(...options), config) as any; 55 | 56 | export type { MonoKlassedComponent, MonoReklassedComponent, MonoComposedComponent }; 57 | export { createKlassed, createReklassed, createComposed }; 58 | -------------------------------------------------------------------------------- /packages/vue/src/mono/index.tsx: -------------------------------------------------------------------------------- 1 | import { compose, klass, reklass } from "@klass/core"; 2 | import type { 3 | AsFn, 4 | AsFnProps, 5 | BaseFn, 6 | Compose, 7 | ComposeFn, 8 | CompoundVariant, 9 | ConditionSchema, 10 | EndFn, 11 | EndFnProps, 12 | Fx, 13 | FxFrom, 14 | Fxs, 15 | Klass, 16 | KlassFn, 17 | KlassOptions, 18 | Reklass, 19 | ReklassFn, 20 | ReklassOptions, 21 | RequiredVariantsFrom, 22 | RevariantFn, 23 | RevariantGroup, 24 | StrictVariantsSchema, 25 | TransformKey, 26 | UnionToIntersection, 27 | VariantFn, 28 | VariantGroup, 29 | VariantsOf, 30 | VariantsSchema, 31 | } from "@klass/core"; 32 | 33 | import { createComposed, createKlassed, createReklassed } from "./create"; 34 | 35 | const klassed = /* @__PURE__ */ createKlassed(klass); 36 | 37 | const reklassed = /* @__PURE__ */ createReklassed(reklass); 38 | 39 | const composed = /* @__PURE__ */ createComposed(compose); 40 | 41 | export type { 42 | TransformKey, 43 | EndFn, 44 | AsFn, 45 | EndFnProps, 46 | AsFnProps, 47 | VariantsSchema, 48 | StrictVariantsSchema, 49 | VariantsOf, 50 | RequiredVariantsFrom, 51 | BaseFn, 52 | VariantFn, 53 | VariantGroup, 54 | CompoundVariant, 55 | KlassOptions, 56 | KlassFn, 57 | Klass, 58 | ConditionSchema, 59 | RevariantFn, 60 | RevariantGroup, 61 | ReklassOptions, 62 | ReklassFn, 63 | Reklass, 64 | UnionToIntersection, 65 | Fx, 66 | Fxs, 67 | FxFrom, 68 | ComposeFn, 69 | Compose, 70 | }; 71 | export type { MonoKlassedComponent, MonoReklassedComponent, MonoComposedComponent } from "./types"; 72 | export { klassed, reklassed, composed }; 73 | -------------------------------------------------------------------------------- /packages/vue/src/mono/types.ts: -------------------------------------------------------------------------------- 1 | import type { ComposeFn, ConditionSchema, Fx, KlassFn, ReklassFn, VariantsOf } from "@klass/core"; 2 | 3 | import { Base, DefaultPropsConfig, FinalVariantsSchema, ForwardPropsConfig, WithClassesValueProps } from "./../types"; 4 | import { OverrideProps } from "./../types/utils"; 5 | import type { SupportedComponentProps, SupportedElementType } from "./../types/vue"; 6 | 7 | export type ComponentConfig = DefaultPropsConfig> & ForwardPropsConfig; 8 | export type ComposedComponentConfig = DefaultPropsConfig> & ForwardPropsConfig; 9 | 10 | export type MonoKlassedComponent = { 11 | (props: WithClassesValueProps, VariantsOf>>>): any; 12 | } & Base>; 13 | 14 | export type MonoReklassedComponent = { 15 | (props: WithClassesValueProps, VariantsOf>>>): any; 16 | } & Base>; 17 | 18 | export type MonoComposedComponent = { 19 | (props: WithClassesValueProps, VariantsOf>>>): any; 20 | } & Base>; 21 | -------------------------------------------------------------------------------- /packages/vue/src/types/index.ts: -------------------------------------------------------------------------------- 1 | import type { ClassValue, ComposeFn, ConditionSchema, Fx, FxFrom, Fxs, KlassFn, KlassOptions, ReklassFn, ReklassOptions, StrictVariantsSchema, VariantsOf } from "@klass/core"; 2 | 3 | import type { PolymorphicComponentProps } from "./polymorphic"; 4 | import type { BaseComponent, Classes, SupportedElementType } from "./vue"; 5 | 6 | export type FinalRestrictedVariantsKey = Classes; 7 | export type FinalVariantsSchema = StrictVariantsSchema; 8 | 9 | export type ClassesValueProps = Partial>; 10 | export type WithClassesValueProps

= Omit & ClassesValueProps; 11 | 12 | export type KlassedOptions = KlassOptions | KlassFn; 13 | export type ReklassedOptions = ReklassOptions | ReklassFn; 14 | export type ComposedOptions = Fn[] | ComposeFn>; 15 | 16 | export type DefaultPropsConfig> = { dp?: DP }; 17 | export type ForwardPropsConfig = { fp?: T[] }; 18 | export type ComponentConfig = DefaultPropsConfig> & ForwardPropsConfig; 19 | export type ComposedComponentConfig = DefaultPropsConfig> & ForwardPropsConfig; 20 | 21 | export type Base = BaseComponent & { fx: F }; 22 | 23 | export type KlassedComponent = { 24 | (props: PolymorphicComponentProps>>>): any; 25 | } & Base>; 26 | 27 | export type ReklassedComponent = { 28 | (props: PolymorphicComponentProps>>>): any; 29 | } & Base>; 30 | 31 | export type ComposedComponent = { 32 | (props: PolymorphicComponentProps>>>): any; 33 | } & Base>; 34 | -------------------------------------------------------------------------------- /packages/vue/src/types/polymorphic.ts: -------------------------------------------------------------------------------- 1 | import type { SupportedComponentProps, SupportedElementType } from "./vue"; 2 | 3 | type ResolveRefProps

= Omit & { 4 | ref?: P extends { 5 | ref?: infer Ref; 6 | } 7 | ? Ref 8 | : unknown; 9 | }; 10 | 11 | type PolymorphicComponentProps = (Props & { 12 | as?: ET; 13 | }) & 14 | Omit>, "as" | keyof Props>; 15 | 16 | export type { PolymorphicComponentProps }; 17 | -------------------------------------------------------------------------------- /packages/vue/src/types/utils.ts: -------------------------------------------------------------------------------- 1 | export type OverrideProps = Omit & W; 2 | -------------------------------------------------------------------------------- /packages/vue/src/types/vue.ts: -------------------------------------------------------------------------------- 1 | import type { DefineSetupFnComponent, FunctionalComponent } from "vue"; 2 | import type { JSX } from "vue/jsx-runtime"; 3 | 4 | type SimpleComponent

= new () => { $props: P }; 5 | 6 | export type SupportedComponentType

= SimpleComponent

| FunctionalComponent

| (P extends Record ? DefineSetupFnComponent

: never); 7 | 8 | export type SupportedComponentProps = T extends SupportedComponentType 9 | ? P 10 | : T extends keyof JSX.IntrinsicElements 11 | ? JSX.IntrinsicElements[T] 12 | : {}; 13 | 14 | export type SupportedElementType

= 15 | | { 16 | [K in keyof JSX.IntrinsicElements]: P extends JSX.IntrinsicElements[K] ? K : never; 17 | }[keyof JSX.IntrinsicElements] 18 | | SupportedComponentType

; 19 | 20 | export type Classes = "class"; 21 | export type ClassesProps = Partial>; 22 | 23 | export type BaseComponent = { 24 | displayName?: string; 25 | }; 26 | -------------------------------------------------------------------------------- /packages/vue/src/utils.ts: -------------------------------------------------------------------------------- 1 | import type { FinalRestrictedVariantsKey, FinalVariantsSchema } from "./types"; 2 | 3 | const getVariantKeys__filterFn = /* @__PURE__ */ (el: keyof VS) => el !== "class"; 4 | export const getVariantKeys = /* @__PURE__ */ (keys: (keyof VS)[]) => 5 | keys.filter(getVariantKeys__filterFn) as unknown as Exclude[]; 6 | 7 | export const splitRestProps = /* @__PURE__ */

>(props: P, keys: string[], fkeys?: string[]) => { 8 | const o: /** omited */ Record = {}, 9 | p: /** picked */ Record = {}; 10 | let key: string; 11 | for (key in props) { 12 | const value = props[key]; 13 | if (keys.includes(key)) { 14 | p[key] = value; 15 | if (fkeys?.includes(key)) o[key] = value; 16 | } else { 17 | o[key] = value; 18 | } 19 | } 20 | return { o, p } as const; 21 | }; 22 | -------------------------------------------------------------------------------- /packages/vue/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "forceConsistentCasingInFileNames": true, 5 | "target": "ESNext", 6 | "module": "ESNext", 7 | "lib": ["ESNext", "DOM", "DOM.Iterable"], 8 | "moduleResolution": "bundler", 9 | "esModuleInterop": true, 10 | "allowImportingTsExtensions": true, 11 | "allowSyntheticDefaultImports": true, 12 | "allowJs": true, 13 | "resolveJsonModule": true, 14 | "skipLibCheck": true, 15 | "strictNullChecks": true, 16 | "declaration": true, 17 | "removeComments": false, 18 | "noUnusedLocals": true, 19 | "noUnusedParameters": true, 20 | "noEmit": true, 21 | "jsx": "preserve", 22 | "jsxImportSource": "vue" 23 | }, 24 | "include": ["src"], 25 | "exclude": ["node_modules", "dist"] 26 | } 27 | -------------------------------------------------------------------------------- /packages/vue/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | 3 | import jsx from "@vitejs/plugin-vue-jsx"; 4 | 5 | import { build, dts } from "../config"; 6 | 7 | export default defineConfig({ 8 | plugins: [jsx(), dts(["src/**/*.{ts,tsx}"])], 9 | build: build(["utils.ts", "index.tsx", "create.tsx", "mono/index.tsx", "mono/create.tsx"]), 10 | }); 11 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - packages/* 3 | - tests/* 4 | 5 | onlyBuiltDependencies: 6 | - '@biomejs/biome' 7 | -------------------------------------------------------------------------------- /tests/config.ts: -------------------------------------------------------------------------------- 1 | import fs from "node:fs"; 2 | import path from "node:path"; 3 | 4 | import type { ViteUserConfig } from "vitest/config"; 5 | 6 | import paths from "vite-tsconfig-paths"; 7 | 8 | export const custom = (__dirname: string) => { 9 | const { name } = JSON.parse(fs.readFileSync(path.resolve(__dirname, "package.json"), "utf-8")) as { 10 | name: string; 11 | }; 12 | 13 | return { 14 | define: {}, 15 | plugins: [paths()], 16 | test: { 17 | name, 18 | environment: "jsdom", 19 | }, 20 | } satisfies ViteUserConfig; 21 | }; 22 | -------------------------------------------------------------------------------- /tests/core/index.test.ts: -------------------------------------------------------------------------------- 1 | import * as vt from "vitest"; 2 | 3 | import * as fixtures from "@test/shared/fixtures"; 4 | 5 | import { klass, reklass, compose } from "@klass/core"; 6 | 7 | vt.describe("klass", () => { 8 | vt.describe("basic", () => { 9 | vt.it("should work", () => { 10 | const fx = klass(fixtures.klass.basic.options); 11 | 12 | vt.expect(fx.g).toEqual({ string: vt.expect.any(Function), boolean: vt.expect.any(Function), number: vt.expect.any(Function) }); 13 | vt.expect(fx.k).toEqual(["string", "boolean", "number"]); 14 | 15 | for (const { props, equal } of fixtures.klass.basic.test) { 16 | vt.expect(fx(props as any)).toEqual(equal); 17 | vt.expect(fx(props as any, ["extra"])).toEqual(equal ? `${equal} extra` : "extra"); 18 | } 19 | }); 20 | }); 21 | 22 | vt.describe("withBase", () => { 23 | vt.it("should work", () => { 24 | const fx = klass(fixtures.klass.withBase.options); 25 | 26 | vt.expect(fx.g).toEqual({ string: vt.expect.any(Function), boolean: vt.expect.any(Function), number: vt.expect.any(Function) }); 27 | vt.expect(fx.k).toEqual(["string", "boolean", "number"]); 28 | 29 | for (const { props, equal } of fixtures.klass.withBase.test) { 30 | vt.expect(fx(props as any)).toEqual(equal); 31 | vt.expect(fx(props as any, ["extra"])).toEqual(equal ? `${equal} extra` : "extra"); 32 | } 33 | }); 34 | }); 35 | 36 | vt.describe("withBaseDefaults", () => { 37 | vt.it("should work", () => { 38 | const fx = klass(fixtures.klass.withBaseDefaults.options); 39 | 40 | vt.expect(fx.g).toEqual({ string: vt.expect.any(Function), boolean: vt.expect.any(Function), number: vt.expect.any(Function) }); 41 | vt.expect(fx.k).toEqual(["string", "boolean", "number"]); 42 | 43 | for (const { props, equal } of fixtures.klass.withBaseDefaults.test) { 44 | vt.expect(fx(props as any)).toEqual(equal); 45 | vt.expect(fx(props as any, ["extra"])).toEqual(equal ? `${equal} extra` : "extra"); 46 | } 47 | }); 48 | }); 49 | 50 | vt.describe("withBaseDefaultsCompounds", () => { 51 | vt.it("should work", () => { 52 | const fx = klass(fixtures.klass.withBaseDefaultsCompounds.options); 53 | 54 | vt.expect(fx.g).toEqual({ string: vt.expect.any(Function), boolean: vt.expect.any(Function), number: vt.expect.any(Function) }); 55 | vt.expect(fx.k).toEqual(["string", "boolean", "number"]); 56 | 57 | for (const { props, equal } of fixtures.klass.withBaseDefaultsCompounds.test) { 58 | vt.expect(fx(props as any)).toEqual(equal); 59 | vt.expect(fx(props as any, ["extra"])).toEqual(equal ? `${equal} extra` : "extra"); 60 | } 61 | }); 62 | }); 63 | }); 64 | 65 | vt.describe("reklass", () => { 66 | vt.describe("basic", () => { 67 | vt.it("should work", () => { 68 | const fx = reklass(fixtures.reklass.basic.options); 69 | 70 | vt.expect(fx.g).toEqual({ string: vt.expect.any(Function), boolean: vt.expect.any(Function), number: vt.expect.any(Function) }); 71 | vt.expect(fx.k).toEqual(["string", "boolean", "number"]); 72 | 73 | for (const { props, equal } of fixtures.reklass.basic.test) { 74 | vt.expect(fx(props as any)).toEqual(equal); 75 | vt.expect(fx(props as any, ["extra"])).toEqual(equal ? `${equal} extra` : "extra"); 76 | } 77 | }); 78 | }); 79 | }); 80 | 81 | vt.describe("compose", () => { 82 | vt.it("should work", () => { 83 | const fx = compose(fixtures.compose.fx.color, fixtures.compose.fx.disabled, fixtures.compose.fx.weight, fixtures.compose.fx.box, fixtures.compose.fx.spacing); 84 | 85 | vt.expect(fx.k).toEqual(["color", "disabled", "weight", "block", "flex", "hidden", "margin", "padding"]); 86 | 87 | for (const { props, equal } of fixtures.compose.test) { 88 | vt.expect(fx(props as any)).toEqual(equal); 89 | vt.expect(fx(props as any, ["extra"])).toEqual(equal ? `${equal} extra` : "extra"); 90 | } 91 | }); 92 | }); 93 | -------------------------------------------------------------------------------- /tests/core/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@test/core", 3 | "version": "0.0.0", 4 | "type": "module", 5 | "private": true, 6 | "dependencies": { 7 | "@klass/core": "workspace:*", 8 | "@test/shared": "workspace:*" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tests/core/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "forceConsistentCasingInFileNames": true, 5 | "target": "ESNext", 6 | "module": "ESNext", 7 | "lib": ["ESNext", "DOM", "DOM.Iterable"], 8 | "moduleResolution": "bundler", 9 | "esModuleInterop": true, 10 | "allowImportingTsExtensions": true, 11 | "allowSyntheticDefaultImports": true, 12 | "allowJs": true, 13 | "resolveJsonModule": true, 14 | "skipLibCheck": true, 15 | "strictNullChecks": true, 16 | "noUnusedLocals": true, 17 | "noUnusedParameters": true, 18 | "noEmit": true, 19 | "baseUrl": "./", 20 | "paths": { 21 | "~/*": ["./*"] 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/core/utils.ts: -------------------------------------------------------------------------------- 1 | export const render = (element: HTMLElement) => { 2 | document.body.appendChild(element); 3 | 4 | return () => { 5 | document.body.removeChild(element); 6 | }; 7 | }; 8 | -------------------------------------------------------------------------------- /tests/core/vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { defineProject } from "vitest/config"; 2 | 3 | import { custom } from "../config"; 4 | 5 | const config = custom(__dirname); 6 | 7 | export default defineProject({ 8 | ...config, 9 | define: { 10 | ...config.define, 11 | }, 12 | plugins: [config.plugins], 13 | test: { 14 | include: ["**/*.test.ts"], 15 | ...config.test, 16 | }, 17 | }); 18 | -------------------------------------------------------------------------------- /tests/preact/index.test.tsx: -------------------------------------------------------------------------------- 1 | import * as vt from "vitest"; 2 | 3 | import * as fixtures from "@test/shared/fixtures"; 4 | import { cleanupable, expectGetElementToBeInTheDocument } from "@test/shared/utils"; 5 | 6 | import { klassed, reklassed, composed } from "@klass/preact"; 7 | 8 | import { render } from "~/utils"; 9 | 10 | const cleanup = cleanupable(); 11 | 12 | vt.beforeEach(() => { 13 | cleanup(); 14 | }); 15 | 16 | vt.describe("klassed", () => { 17 | vt.describe("basic", () => { 18 | vt.it("should work", async () => { 19 | const Component = klassed("div", fixtures.klass.basic.options); 20 | 21 | vt.expect(Component.fx.g).toEqual({ string: vt.expect.any(Function), boolean: vt.expect.any(Function), number: vt.expect.any(Function) }); 22 | vt.expect(Component.fx.k).toEqual(["string", "boolean", "number"]); 23 | 24 | for await (const { props, equal } of fixtures.klass.basic.test) { 25 | let ref: HTMLDivElement | null = null; 26 | 27 | const clean = render( 28 | { 30 | if (element) ref = element; 31 | }} 32 | data-testid="component" 33 | data-custom="attribute" 34 | {...(props as any)} 35 | class="extra" 36 | > 37 | children 38 | 39 | ); 40 | cleanup(clean); 41 | 42 | await vt.vi.waitFor(() => { 43 | if (ref === null) throw new Error("Ref is null"); 44 | }); 45 | 46 | const component = expectGetElementToBeInTheDocument((screen) => screen.getByTestId("component")); 47 | 48 | vt.assert(typeof component! !== "undefined"); 49 | 50 | vt.expect(component.className).toEqual(equal ? `${equal} extra` : "extra"); 51 | vt.expect(component.innerHTML).toEqual("children"); 52 | 53 | clean(); 54 | } 55 | }); 56 | }); 57 | }); 58 | 59 | vt.describe("reklassed", () => { 60 | vt.describe("basic", () => { 61 | vt.it("should work", async () => { 62 | const Component = reklassed("div", fixtures.reklass.basic.options); 63 | 64 | vt.expect(Component.fx.g).toEqual({ string: vt.expect.any(Function), boolean: vt.expect.any(Function), number: vt.expect.any(Function) }); 65 | vt.expect(Component.fx.k).toEqual(["string", "boolean", "number"]); 66 | 67 | for await (const { props, equal } of fixtures.reklass.basic.test) { 68 | let ref: HTMLDivElement | null = null; 69 | 70 | const clean = render( 71 | { 73 | if (element) ref = element; 74 | }} 75 | data-testid="component" 76 | data-custom="attribute" 77 | {...(props as any)} 78 | class="extra" 79 | > 80 | children 81 | 82 | ); 83 | cleanup(clean); 84 | 85 | await vt.vi.waitFor(() => { 86 | if (ref === null) throw new Error("Ref is null"); 87 | }); 88 | 89 | const component = expectGetElementToBeInTheDocument((screen) => screen.getByTestId("component")); 90 | 91 | vt.assert(typeof component! !== "undefined"); 92 | 93 | vt.expect(component.className).toEqual(equal ? `${equal} extra` : "extra"); 94 | vt.expect(component.innerHTML).toEqual("children"); 95 | 96 | clean(); 97 | } 98 | }); 99 | }); 100 | }); 101 | 102 | vt.describe("composed", () => { 103 | vt.it("should work", async () => { 104 | const Component = composed("div", [fixtures.compose.fx.color, fixtures.compose.fx.disabled, fixtures.compose.fx.weight, fixtures.compose.fx.box, fixtures.compose.fx.spacing]); 105 | 106 | vt.expect(Component.fx.k).toEqual(["color", "disabled", "weight", "block", "flex", "hidden", "margin", "padding"]); 107 | 108 | for await (const { props, equal } of fixtures.compose.test) { 109 | let ref: HTMLDivElement | null = null; 110 | 111 | const clean = render( 112 | { 114 | if (element) ref = element; 115 | }} 116 | data-testid="component" 117 | data-custom="attribute" 118 | {...(props as any)} 119 | class="extra" 120 | > 121 | children 122 | 123 | ); 124 | cleanup(clean); 125 | 126 | await vt.vi.waitFor(() => { 127 | if (ref === null) throw new Error("Ref is null"); 128 | }); 129 | 130 | const component = expectGetElementToBeInTheDocument((screen) => screen.getByTestId("component")); 131 | 132 | vt.assert(typeof component! !== "undefined"); 133 | 134 | vt.expect(component.className).toEqual(equal ? `${equal} extra` : "extra"); 135 | vt.expect(component.innerHTML).toEqual("children"); 136 | 137 | clean(); 138 | } 139 | }); 140 | }); 141 | -------------------------------------------------------------------------------- /tests/preact/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@test/preact", 3 | "version": "0.0.0", 4 | "type": "module", 5 | "private": true, 6 | "dependencies": { 7 | "@klass/core": "workspace:*", 8 | "@klass/preact": "workspace:*", 9 | "@test/shared": "workspace:*" 10 | }, 11 | "devDependencies": { 12 | "preact": "^10" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tests/preact/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "forceConsistentCasingInFileNames": true, 5 | "target": "ESNext", 6 | "module": "ESNext", 7 | "lib": ["ESNext", "DOM", "DOM.Iterable"], 8 | "moduleResolution": "bundler", 9 | "esModuleInterop": true, 10 | "allowImportingTsExtensions": true, 11 | "allowSyntheticDefaultImports": true, 12 | "allowJs": true, 13 | "resolveJsonModule": true, 14 | "skipLibCheck": true, 15 | "strictNullChecks": true, 16 | "noUnusedLocals": true, 17 | "noUnusedParameters": true, 18 | "noEmit": true, 19 | "jsx": "react-jsx", 20 | "jsxImportSource": "preact", 21 | "baseUrl": "./", 22 | "paths": { 23 | "~/*": ["./*"] 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/preact/utils.ts: -------------------------------------------------------------------------------- 1 | import { render as _render } from "preact"; 2 | import type { ComponentChild } from "preact"; 3 | 4 | export const render = (vnode: ComponentChild) => { 5 | const container = document.createElement("div"); 6 | document.body.appendChild(container); 7 | 8 | _render(vnode, container); 9 | 10 | let removed = false; 11 | return () => { 12 | if (!removed) { 13 | removed = true; 14 | _render(null, container); 15 | document.body.removeChild(container); 16 | } 17 | }; 18 | }; 19 | -------------------------------------------------------------------------------- /tests/preact/vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { defineProject } from "vitest/config"; 2 | 3 | import preact from "@preact/preset-vite"; 4 | 5 | import { custom } from "../config"; 6 | 7 | const config = custom(__dirname); 8 | 9 | export default defineProject({ 10 | ...config, 11 | define: { 12 | ...config.define, 13 | }, 14 | plugins: [config.plugins, preact()], 15 | test: { 16 | include: ["**/*.test.{ts,tsx}"], 17 | ...config.test, 18 | }, 19 | }); 20 | -------------------------------------------------------------------------------- /tests/qwik/index.test.tsx: -------------------------------------------------------------------------------- 1 | import * as vt from "vitest"; 2 | 3 | import * as fixtures from "@test/shared/fixtures"; 4 | import { cleanupable, expectGetElementToBeInTheDocument } from "@test/shared/utils"; 5 | 6 | import { klassed, reklassed, composed } from "@klass/qwik"; 7 | 8 | import { render } from "~/utils"; 9 | 10 | const cleanup = cleanupable(); 11 | 12 | vt.beforeEach(() => { 13 | cleanup(); 14 | }); 15 | 16 | vt.describe("klassed", () => { 17 | vt.describe("basic", () => { 18 | vt.it("should work", async () => { 19 | const Component = klassed("div", fixtures.klass.basic.options); 20 | 21 | vt.expect(Component.fx.g).toEqual({ string: vt.expect.any(Function), boolean: vt.expect.any(Function), number: vt.expect.any(Function) }); 22 | vt.expect(Component.fx.k).toEqual(["string", "boolean", "number"]); 23 | 24 | for await (const { props, equal } of fixtures.klass.basic.test) { 25 | let ref: HTMLDivElement | null = null; 26 | 27 | const clean = await render( 28 | { 30 | if (element) ref = element; 31 | }} 32 | data-testid="component" 33 | data-custom="attribute" 34 | {...(props as any)} 35 | class="extra" 36 | > 37 | children 38 | 39 | ); 40 | cleanup(clean); 41 | 42 | await vt.vi.waitFor(() => { 43 | if (ref === null) throw new Error("Ref is null"); 44 | }); 45 | 46 | const component = expectGetElementToBeInTheDocument((screen) => screen.getByTestId("component")); 47 | 48 | vt.assert(typeof component! !== "undefined"); 49 | 50 | vt.expect(component.className).toEqual(equal ? `${equal} extra` : "extra"); 51 | vt.expect(component.innerHTML).toEqual("children"); 52 | 53 | clean(); 54 | } 55 | }); 56 | }); 57 | }); 58 | 59 | vt.describe("reklassed", () => { 60 | vt.describe("basic", () => { 61 | vt.it("should work", async () => { 62 | const Component = reklassed("div", fixtures.reklass.basic.options); 63 | 64 | vt.expect(Component.fx.g).toEqual({ string: vt.expect.any(Function), boolean: vt.expect.any(Function), number: vt.expect.any(Function) }); 65 | vt.expect(Component.fx.k).toEqual(["string", "boolean", "number"]); 66 | 67 | for await (const { props, equal } of fixtures.reklass.basic.test) { 68 | let ref: HTMLDivElement | null = null; 69 | 70 | const clean = await render( 71 | { 73 | if (element) ref = element; 74 | }} 75 | data-testid="component" 76 | data-custom="attribute" 77 | {...(props as any)} 78 | class="extra" 79 | > 80 | children 81 | 82 | ); 83 | cleanup(clean); 84 | 85 | await vt.vi.waitFor(() => { 86 | if (ref === null) throw new Error("Ref is null"); 87 | }); 88 | 89 | const component = expectGetElementToBeInTheDocument((screen) => screen.getByTestId("component")); 90 | 91 | vt.assert(typeof component! !== "undefined"); 92 | 93 | vt.expect(component.className).toEqual(equal ? `${equal} extra` : "extra"); 94 | vt.expect(component.innerHTML).toEqual("children"); 95 | 96 | clean(); 97 | } 98 | }); 99 | }); 100 | }); 101 | 102 | vt.describe("composed", () => { 103 | vt.it("should work", async () => { 104 | const Component = composed("div", [fixtures.compose.fx.color, fixtures.compose.fx.disabled, fixtures.compose.fx.weight, fixtures.compose.fx.box, fixtures.compose.fx.spacing]); 105 | 106 | vt.expect(Component.fx.k).toEqual(["color", "disabled", "weight", "block", "flex", "hidden", "margin", "padding"]); 107 | 108 | for await (const { props, equal } of fixtures.compose.test) { 109 | let ref: HTMLDivElement | null = null; 110 | 111 | const clean = await render( 112 | { 114 | if (element) ref = element; 115 | }} 116 | data-testid="component" 117 | data-custom="attribute" 118 | {...(props as any)} 119 | class="extra" 120 | > 121 | children 122 | 123 | ); 124 | cleanup(clean); 125 | 126 | await vt.vi.waitFor(() => { 127 | if (ref === null) throw new Error("Ref is null"); 128 | }); 129 | 130 | const component = expectGetElementToBeInTheDocument((screen) => screen.getByTestId("component")); 131 | 132 | vt.assert(typeof component! !== "undefined"); 133 | 134 | vt.expect(component.className).toEqual(equal ? `${equal} extra` : "extra"); 135 | vt.expect(component.innerHTML).toEqual("children"); 136 | 137 | clean(); 138 | } 139 | }); 140 | }); 141 | -------------------------------------------------------------------------------- /tests/qwik/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@test/qwik", 3 | "version": "0.0.0", 4 | "type": "module", 5 | "private": true, 6 | "dependencies": { 7 | "@klass/core": "workspace:*", 8 | "@klass/qwik": "workspace:*", 9 | "@test/shared": "workspace:*" 10 | }, 11 | "devDependencies": { 12 | "@builder.io/qwik": "^1" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tests/qwik/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "forceConsistentCasingInFileNames": true, 5 | "target": "ESNext", 6 | "module": "ESNext", 7 | "lib": ["ESNext", "DOM", "DOM.Iterable"], 8 | "moduleResolution": "bundler", 9 | "esModuleInterop": true, 10 | "allowImportingTsExtensions": true, 11 | "allowSyntheticDefaultImports": true, 12 | "allowJs": true, 13 | "resolveJsonModule": true, 14 | "skipLibCheck": true, 15 | "strictNullChecks": true, 16 | "noUnusedLocals": true, 17 | "noUnusedParameters": true, 18 | "noEmit": true, 19 | "jsx": "react-jsx", 20 | "jsxImportSource": "@builder.io/qwik", 21 | "baseUrl": "./", 22 | "paths": { 23 | "~/*": ["./*"] 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/qwik/utils.ts: -------------------------------------------------------------------------------- 1 | import { render as _render } from "@builder.io/qwik"; 2 | import type { FunctionComponent, JSXOutput } from "@builder.io/qwik"; 3 | 4 | export const render = async (jsxOutput: JSXOutput | FunctionComponent) => { 5 | const container = document.createElement("div"); 6 | document.body.appendChild(container); 7 | 8 | const result = await _render(container, jsxOutput); 9 | 10 | let removed = false; 11 | return () => { 12 | if (!removed) { 13 | removed = true; 14 | result.cleanup(); 15 | document.body.removeChild(container); 16 | } 17 | }; 18 | }; 19 | -------------------------------------------------------------------------------- /tests/qwik/vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { defineProject } from "vitest/config"; 2 | 3 | import { qwikVite as qwik } from "@builder.io/qwik/optimizer"; 4 | 5 | import { custom } from "../config"; 6 | 7 | const config = custom(__dirname); 8 | 9 | export default defineProject({ 10 | ...config, 11 | define: { 12 | ...config.define, 13 | }, 14 | plugins: [config.plugins, qwik({ csr: true })], 15 | test: { 16 | include: ["**/*.test.{ts,tsx}"], 17 | ...config.test, 18 | }, 19 | }); 20 | -------------------------------------------------------------------------------- /tests/react-18/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@test/react-18", 3 | "version": "0.0.0", 4 | "type": "module", 5 | "private": true, 6 | "dependencies": { 7 | "@klass/core": "workspace:*", 8 | "@klass/react": "workspace:*", 9 | "@test/shared": "workspace:*" 10 | }, 11 | "devDependencies": { 12 | "@types/react": "^18", 13 | "@types/react-dom": "^18", 14 | "react": "^18", 15 | "react-dom": "^18" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/react-18/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "forceConsistentCasingInFileNames": true, 5 | "target": "ESNext", 6 | "module": "ESNext", 7 | "lib": ["ESNext", "DOM", "DOM.Iterable"], 8 | "moduleResolution": "bundler", 9 | "esModuleInterop": true, 10 | "allowImportingTsExtensions": true, 11 | "allowSyntheticDefaultImports": true, 12 | "allowJs": true, 13 | "resolveJsonModule": true, 14 | "skipLibCheck": true, 15 | "strictNullChecks": true, 16 | "noUnusedLocals": true, 17 | "noUnusedParameters": true, 18 | "noEmit": true, 19 | "jsx": "react-jsx", 20 | "jsxImportSource": "react", 21 | "baseUrl": "./", 22 | "paths": { 23 | "~/*": ["./*"] 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/react-18/utils.ts: -------------------------------------------------------------------------------- 1 | import { act, type ReactNode } from "react"; 2 | import { createRoot } from "react-dom/client"; 3 | 4 | let init = false; 5 | 6 | export const render = (children: ReactNode) => { 7 | if (!init) { 8 | init = true; 9 | (global as any).IS_REACT_ACT_ENVIRONMENT = true; 10 | } 11 | 12 | const container = document.createElement("div"); 13 | document.body.appendChild(container); 14 | 15 | const root = createRoot(container); 16 | act(() => { 17 | root.render(children); 18 | }); 19 | 20 | let removed = false; 21 | return () => { 22 | if (!removed) { 23 | removed = true; 24 | act(() => { 25 | root.unmount(); 26 | }); 27 | document.body.removeChild(container); 28 | } 29 | }; 30 | }; 31 | -------------------------------------------------------------------------------- /tests/react-18/vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { defineProject } from "vitest/config"; 2 | 3 | import react from "@vitejs/plugin-react"; 4 | 5 | import { custom } from "../config"; 6 | 7 | const config = custom(__dirname); 8 | 9 | export default defineProject({ 10 | ...config, 11 | define: { 12 | ...config.define, 13 | }, 14 | plugins: [config.plugins, react()], 15 | test: { 16 | include: ["**/*.test.{ts,tsx}"], 17 | ...config.test, 18 | }, 19 | }); 20 | -------------------------------------------------------------------------------- /tests/react/ecosystem/ark-ui.test.tsx: -------------------------------------------------------------------------------- 1 | import * as vt from "vitest"; 2 | 3 | import * as fixtures from "@test/shared/fixtures"; 4 | import { cleanupable, expectGetElementsToBeInTheDocument } from "@test/shared/utils"; 5 | 6 | import * as mono from "@klass/react/mono"; 7 | 8 | import { Avatar } from "@ark-ui/react/avatar"; 9 | 10 | import { render } from "./../utils"; 11 | 12 | const cleanup = cleanupable(); 13 | 14 | vt.beforeEach(() => { 15 | cleanup(); 16 | }); 17 | 18 | vt.describe("klassed/mono", () => { 19 | vt.describe("abstract", () => { 20 | vt.it("should work", async () => { 21 | const ComponentRoot = mono.klassed(Avatar.Root, fixtures.klass.abstract.options); 22 | const ComponentFallback = mono.klassed(Avatar.Fallback, fixtures.klass.abstract.options); 23 | const ComponentImage = mono.klassed(Avatar.Image, fixtures.klass.abstract.options); 24 | 25 | for await (const { props, equal } of fixtures.klass.abstract.test) { 26 | let ref: HTMLDivElement | null = null; 27 | 28 | const clean = render( 29 | { 31 | if (element) ref = element; 32 | }} 33 | data-testid="component-root" 34 | data-custom="attribute" 35 | {...(props as any)} 36 | className="extra" 37 | > 38 | 39 | fallback 40 | 41 | 42 | 43 | ); 44 | cleanup(clean); 45 | 46 | await vt.vi.waitFor(() => { 47 | if (ref === null) throw new Error("Ref is null"); 48 | }); 49 | 50 | const [componentRoot] = expectGetElementsToBeInTheDocument((screen) => [screen.getByTestId("component-root"), screen.getByTestId("component-root"), screen.getByTestId("component-root")]); 51 | 52 | vt.expect(componentRoot.className).toEqual(equal ? `${equal} extra` : "extra"); 53 | 54 | clean(); 55 | } 56 | }); 57 | }); 58 | }); 59 | -------------------------------------------------------------------------------- /tests/react/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@test/react", 3 | "version": "0.0.0", 4 | "type": "module", 5 | "private": true, 6 | "dependencies": { 7 | "@klass/core": "workspace:*", 8 | "@klass/react": "workspace:*", 9 | "@test/shared": "workspace:*" 10 | }, 11 | "devDependencies": { 12 | "@ariakit/react": "0.4.17", 13 | "@ark-ui/react": "5.7.0", 14 | "@base-ui-components/react": "1.0.0-alpha.8", 15 | "@headlessui/react": "2.2.2", 16 | "@radix-ui/react-separator": "1.1.4", 17 | "@radix-ui/react-slot": "1.2.0", 18 | "@radix-ui/react-switch": "1.2.2", 19 | "@types/react": "^19", 20 | "@types/react-dom": "^19", 21 | "react": "^19", 22 | "react-aria-components": "1.8.0", 23 | "react-dom": "^19" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tests/react/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "forceConsistentCasingInFileNames": true, 5 | "target": "ESNext", 6 | "module": "ESNext", 7 | "lib": ["ESNext", "DOM", "DOM.Iterable"], 8 | "moduleResolution": "bundler", 9 | "esModuleInterop": true, 10 | "allowImportingTsExtensions": true, 11 | "allowSyntheticDefaultImports": true, 12 | "allowJs": true, 13 | "resolveJsonModule": true, 14 | "skipLibCheck": true, 15 | "strictNullChecks": true, 16 | "noUnusedLocals": true, 17 | "noUnusedParameters": true, 18 | "noEmit": true, 19 | "jsx": "react-jsx", 20 | "jsxImportSource": "react", 21 | "baseUrl": "./", 22 | "paths": { 23 | "~/*": ["./*"] 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/react/utils.ts: -------------------------------------------------------------------------------- 1 | import { act, type ReactNode } from "react"; 2 | import { createRoot } from "react-dom/client"; 3 | 4 | let init = false; 5 | 6 | export const render = (children: ReactNode) => { 7 | if (!init) { 8 | init = true; 9 | (global as any).IS_REACT_ACT_ENVIRONMENT = true; 10 | } 11 | 12 | const container = document.createElement("div"); 13 | document.body.appendChild(container); 14 | 15 | const root = createRoot(container); 16 | act(() => { 17 | root.render(children); 18 | }); 19 | 20 | let removed = false; 21 | return () => { 22 | if (!removed) { 23 | removed = true; 24 | act(() => { 25 | root.unmount(); 26 | }); 27 | document.body.removeChild(container); 28 | } 29 | }; 30 | }; 31 | -------------------------------------------------------------------------------- /tests/react/vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { defineProject } from "vitest/config"; 2 | 3 | import react from "@vitejs/plugin-react"; 4 | 5 | import { custom } from "../config"; 6 | 7 | const config = custom(__dirname); 8 | 9 | export default defineProject({ 10 | ...config, 11 | define: { 12 | ...config.define, 13 | }, 14 | plugins: [config.plugins, react()], 15 | test: { 16 | include: ["**/*.test.{ts,tsx}"], 17 | ...config.test, 18 | }, 19 | }); 20 | -------------------------------------------------------------------------------- /tests/shared/fixtures/compose.ts: -------------------------------------------------------------------------------- 1 | import { klass, reklass } from "@klass/core"; 2 | import type { KlassOptions, ReklassOptions } from "@klass/core"; 3 | 4 | type Options = KlassOptions>> | ReklassOptions, Record>>; 5 | 6 | type Test = { 7 | props: { 8 | [key in keyof O["variants"]]?: any; 9 | }; 10 | equal: string; 11 | }; 12 | 13 | const options = { 14 | color: { 15 | variants: { 16 | color: { 17 | red: "color-red", 18 | green: "color-green", 19 | blue: "color-blue", 20 | }, 21 | }, 22 | defaults: { 23 | color: "red" as any, 24 | }, 25 | } satisfies Options, 26 | disabled: { 27 | variants: { 28 | disabled: { 29 | true: "disabled-true", 30 | false: "disabled-false", 31 | }, 32 | }, 33 | } satisfies Options, 34 | weight: { 35 | variants: { 36 | weight: { 37 | 300: "weight-300", 38 | 400: "weight-400", 39 | 500: "weight-500", 40 | }, 41 | }, 42 | } satisfies Options, 43 | box: { 44 | base: "box", 45 | variants: { 46 | block: { 47 | true: "", 48 | inline: "", 49 | }, 50 | flex: { 51 | true: "", 52 | inline: "", 53 | }, 54 | hidden: { 55 | true: "", 56 | false: "", 57 | }, 58 | }, 59 | defaults: { 60 | hidden: false as any, 61 | }, 62 | compounds: [ 63 | [ 64 | { 65 | block: true as any, 66 | hidden: false as any, 67 | }, 68 | "box-block", 69 | ], 70 | [ 71 | { 72 | block: "inline" as any, 73 | hidden: false as any, 74 | }, 75 | "box-block-inline", 76 | ], 77 | [ 78 | { 79 | flex: true as any, 80 | hidden: false as any, 81 | }, 82 | "box-flex", 83 | ], 84 | [ 85 | { 86 | flex: "inline" as any, 87 | hidden: false as any, 88 | }, 89 | "box-flex-inline", 90 | ], 91 | ], 92 | } satisfies Options, 93 | spacing: { 94 | conditions: [ 95 | { 96 | initial: "", 97 | sm: "sm:", 98 | md: "md:", 99 | lg: "lg:", 100 | }, 101 | "initial", 102 | ], 103 | variants: { 104 | margin: { 105 | sm: "margin-sm", 106 | md: "margin-md", 107 | lg: "margin-lg", 108 | }, 109 | padding: { 110 | sm: "padding-sm", 111 | md: "padding-md", 112 | lg: "padding-lg", 113 | }, 114 | }, 115 | } satisfies Options, 116 | }; 117 | 118 | const fx = { 119 | color: klass(options.color), 120 | disabled: klass(options.disabled), 121 | weight: klass(options.weight), 122 | box: klass(options.box), 123 | spacing: reklass(options.spacing), 124 | }; 125 | 126 | export const compose = { 127 | options, 128 | fx, 129 | test: [ 130 | { 131 | props: {}, 132 | equal: "color-red box", 133 | }, 134 | { 135 | props: { 136 | color: "green", 137 | disabled: false, 138 | weight: 500, 139 | flex: "inline", 140 | margin: "md", 141 | padding: { 142 | initial: "sm", 143 | md: "lg", 144 | }, 145 | }, 146 | equal: "color-green disabled-false weight-500 box box-flex-inline margin-md padding-sm md:padding-lg", 147 | }, 148 | ] satisfies Test[], 149 | }; 150 | -------------------------------------------------------------------------------- /tests/shared/fixtures/index.ts: -------------------------------------------------------------------------------- 1 | export { klass } from "./klass"; 2 | export { reklass } from "./reklass"; 3 | export { compose } from "./compose"; 4 | -------------------------------------------------------------------------------- /tests/shared/fixtures/klass.ts: -------------------------------------------------------------------------------- 1 | import type { KlassOptions } from "@klass/core"; 2 | 3 | type Options = KlassOptions>>; 4 | 5 | type Test = { 6 | props: { 7 | [key in keyof O["variants"]]?: any; 8 | }; 9 | equal: string; 10 | }; 11 | 12 | const abstract = { 13 | variants: { 14 | print: { 15 | foo: "print-foo", 16 | bar: "print-bar", 17 | baz: "print-baz", 18 | }, 19 | }, 20 | } satisfies Options; 21 | 22 | const shared = { 23 | variants: { 24 | string: { 25 | one: "string-one", 26 | two: "string-two", 27 | three: "string-three", 28 | }, 29 | boolean: { 30 | true: "boolean-true", 31 | false: "boolean-false", 32 | }, 33 | number: { 34 | 1: "number-1", 35 | 2: "number-2", 36 | 3: "number-3", 37 | }, 38 | }, 39 | } satisfies Options; 40 | 41 | export const klass = { 42 | abstract: { 43 | options: { 44 | variants: abstract.variants, 45 | } satisfies Options, 46 | test: [ 47 | { 48 | props: {}, 49 | equal: "", 50 | }, 51 | { 52 | props: { 53 | print: "foo", 54 | }, 55 | equal: "print-foo", 56 | }, 57 | { props: { print: undefined }, equal: "" }, 58 | ] satisfies Test[], 59 | }, 60 | basic: { 61 | options: { 62 | variants: shared.variants, 63 | } satisfies Options, 64 | test: [ 65 | { 66 | props: {}, 67 | equal: "", 68 | }, 69 | { 70 | props: { 71 | string: "one", 72 | boolean: false, 73 | number: 3, 74 | }, 75 | equal: "string-one boolean-false number-3", 76 | }, 77 | { props: { string: undefined, boolean: undefined, number: undefined }, equal: "" }, 78 | ] satisfies Test[], 79 | }, 80 | withBase: { 81 | options: { 82 | base: "base", 83 | variants: shared.variants, 84 | } satisfies Options, 85 | test: [ 86 | { 87 | props: {}, 88 | equal: "base", 89 | }, 90 | { 91 | props: { 92 | string: "one", 93 | boolean: false, 94 | number: 3, 95 | }, 96 | equal: "base string-one boolean-false number-3", 97 | }, 98 | { props: { string: undefined, boolean: undefined, number: undefined }, equal: "base" }, 99 | ] satisfies Test[], 100 | }, 101 | withBaseDefaults: { 102 | options: { 103 | base: "base", 104 | variants: shared.variants, 105 | defaults: { 106 | string: "two" as any, 107 | }, 108 | } satisfies Options, 109 | test: [ 110 | { 111 | props: {}, 112 | equal: "base string-two", 113 | }, 114 | { 115 | props: { 116 | string: "one", 117 | boolean: false, 118 | number: 3, 119 | }, 120 | equal: "base string-one boolean-false number-3", 121 | }, 122 | { props: { string: undefined, boolean: undefined, number: undefined }, equal: "base string-two" }, 123 | ] satisfies Test[], 124 | }, 125 | withBaseDefaultsCompounds: { 126 | options: { 127 | base: "base", 128 | variants: shared.variants, 129 | defaults: { 130 | string: "two" as any, 131 | }, 132 | compounds: [ 133 | [ 134 | { 135 | string: "one" as any, 136 | boolean: true as any, 137 | }, 138 | "one-true", 139 | ], 140 | [ 141 | { 142 | string: "one" as any, 143 | boolean: false as any, 144 | }, 145 | "one-false", 146 | ], 147 | ], 148 | } satisfies Options, 149 | test: [ 150 | { 151 | props: {}, 152 | equal: "base string-two", 153 | }, 154 | { 155 | props: { 156 | string: "three", 157 | boolean: true, 158 | number: 2, 159 | }, 160 | equal: "base string-three boolean-true number-2", 161 | }, 162 | { 163 | props: { 164 | string: "three", 165 | boolean: false, 166 | number: 2, 167 | }, 168 | equal: "base string-three boolean-false number-2", 169 | }, 170 | { 171 | props: { 172 | string: "one", 173 | boolean: true, 174 | number: 3, 175 | }, 176 | equal: "base string-one boolean-true number-3 one-true", 177 | }, 178 | { 179 | props: { 180 | string: "one", 181 | boolean: false, 182 | number: 3, 183 | }, 184 | equal: "base string-one boolean-false number-3 one-false", 185 | }, 186 | { props: { string: undefined, boolean: undefined, number: undefined }, equal: "base string-two" }, 187 | ] satisfies Test[], 188 | }, 189 | }; 190 | -------------------------------------------------------------------------------- /tests/shared/fixtures/reklass.ts: -------------------------------------------------------------------------------- 1 | import type { ReklassOptions } from "@klass/core"; 2 | 3 | type Options = ReklassOptions, Record>>; 4 | 5 | type Test = { 6 | props: { 7 | [key in keyof O["variants"]]?: any; 8 | }; 9 | equal: string; 10 | }; 11 | 12 | const shared = { 13 | conditions: [ 14 | { 15 | initial: "", 16 | sm: "sm:", 17 | md: "md:", 18 | lg: "lg:", 19 | }, 20 | "initial", 21 | ], 22 | variants: { 23 | string: { 24 | one: "string-one", 25 | two: "string-two", 26 | three: "string-three", 27 | }, 28 | boolean: { 29 | true: "boolean-true", 30 | false: "boolean-false", 31 | }, 32 | number: { 33 | 1: "number-1", 34 | 2: "number-2", 35 | 3: "number-3", 36 | }, 37 | }, 38 | } satisfies Options; 39 | 40 | export const reklass = { 41 | basic: { 42 | options: shared satisfies Options, 43 | test: [ 44 | { 45 | props: {}, 46 | equal: "", 47 | }, 48 | { 49 | props: { 50 | string: "one", 51 | boolean: false, 52 | number: 3, 53 | }, 54 | equal: "string-one boolean-false number-3", 55 | }, 56 | { 57 | props: { 58 | string: { 59 | initial: "one", 60 | sm: "two", 61 | }, 62 | boolean: { 63 | md: false, 64 | }, 65 | number: { 66 | lg: 3, 67 | }, 68 | }, 69 | equal: "string-one sm:string-two md:boolean-false lg:number-3", 70 | }, 71 | { props: { string: {}, boolean: {}, number: {} }, equal: "" }, 72 | { props: { string: undefined, boolean: undefined, number: undefined }, equal: "" }, 73 | ] satisfies Test[], 74 | }, 75 | }; 76 | -------------------------------------------------------------------------------- /tests/shared/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@test/shared", 3 | "version": "0.0.0", 4 | "type": "module", 5 | "private": true, 6 | "dependencies": { 7 | "@klass/core": "workspace:*" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /tests/shared/utils.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "vitest"; 2 | 3 | import { screen } from "@testing-library/dom"; 4 | 5 | import "@testing-library/jest-dom/vitest"; 6 | 7 | type Screen = typeof screen; 8 | 9 | export const cleanupable = () => { 10 | type Fn = () => void; 11 | 12 | const sets = new Set(); 13 | 14 | return (fn?: Fn) => { 15 | if (typeof fn === "undefined") { 16 | for (const set of sets) { 17 | set(); 18 | sets.delete(set); 19 | } 20 | } else { 21 | sets.add(fn); 22 | } 23 | }; 24 | }; 25 | 26 | export { screen }; 27 | 28 | export const expectElementToBeInTheDocument = (element: Element) => { 29 | expect(element).toBeInTheDocument(); 30 | return element; 31 | }; 32 | 33 | export const expectGetElementToBeInTheDocument = (get: (screen: Screen) => Element) => expectElementToBeInTheDocument(get(screen)); 34 | 35 | export const expectElementsToBeInTheDocument = (elements: Element[]) => { 36 | for (const element of elements) expectElementToBeInTheDocument(element); 37 | return elements; 38 | }; 39 | 40 | export const expectGetElementsToBeInTheDocument = (get: (screen: Screen) => Element[]) => expectElementsToBeInTheDocument(get(screen)); 41 | -------------------------------------------------------------------------------- /tests/solid/ecosystem/ark-ui.test.tsx: -------------------------------------------------------------------------------- 1 | import * as vt from "vitest"; 2 | 3 | import * as fixtures from "@test/shared/fixtures"; 4 | import { cleanupable, expectGetElementsToBeInTheDocument } from "@test/shared/utils"; 5 | 6 | import * as mono from "@klass/solid/mono"; 7 | 8 | import { Avatar } from "@ark-ui/solid/avatar"; 9 | 10 | import { render } from "./../utils"; 11 | 12 | const cleanup = cleanupable(); 13 | 14 | vt.beforeEach(() => { 15 | cleanup(); 16 | }); 17 | 18 | vt.describe("klassed/mono", () => { 19 | vt.describe("abstract", () => { 20 | vt.it("should work", async () => { 21 | const ComponentRoot = mono.klassed(Avatar.Root, fixtures.klass.abstract.options); 22 | const ComponentFallback = mono.klassed(Avatar.Fallback, fixtures.klass.abstract.options); 23 | const ComponentImage = mono.klassed(Avatar.Image, fixtures.klass.abstract.options); 24 | 25 | for await (const { props, equal } of fixtures.klass.abstract.test) { 26 | let ref: HTMLDivElement | null = null; 27 | 28 | const clean = render(() => ( 29 | { 31 | if (element) ref = element; 32 | }} 33 | data-testid="component-root" 34 | data-custom="attribute" 35 | {...(props as any)} 36 | class="extra" 37 | > 38 | fallback} /> 39 | 40 | 41 | )); 42 | cleanup(clean); 43 | 44 | await vt.vi.waitFor(() => { 45 | if (ref === null) throw new Error("Ref is null"); 46 | }); 47 | 48 | const [componentRoot] = expectGetElementsToBeInTheDocument((screen) => [screen.getByTestId("component-root"), screen.getByTestId("component-root"), screen.getByTestId("component-root")]); 49 | 50 | vt.expect(componentRoot.className).toEqual(equal ? `${equal} extra` : "extra"); 51 | 52 | clean(); 53 | } 54 | }); 55 | }); 56 | }); 57 | -------------------------------------------------------------------------------- /tests/solid/index.test.tsx: -------------------------------------------------------------------------------- 1 | import * as vt from "vitest"; 2 | 3 | import * as fixtures from "@test/shared/fixtures"; 4 | import { cleanupable, expectGetElementToBeInTheDocument } from "@test/shared/utils"; 5 | 6 | import { klassed, reklassed, composed } from "@klass/solid"; 7 | 8 | import { render } from "~/utils"; 9 | 10 | const cleanup = cleanupable(); 11 | 12 | vt.beforeEach(() => { 13 | cleanup(); 14 | }); 15 | 16 | vt.describe("klassed", () => { 17 | vt.describe("basic", () => { 18 | vt.it("should work", async () => { 19 | const Component = klassed("div", fixtures.klass.basic.options); 20 | 21 | vt.expect(Component.fx.g).toEqual({ string: vt.expect.any(Function), boolean: vt.expect.any(Function), number: vt.expect.any(Function) }); 22 | vt.expect(Component.fx.k).toEqual(["string", "boolean", "number"]); 23 | 24 | for await (const { props, equal } of fixtures.klass.basic.test) { 25 | let ref: HTMLDivElement | null = null; 26 | 27 | const clean = render(() => ( 28 | { 30 | ref = element; 31 | }} 32 | data-testid="component" 33 | data-custom="attribute" 34 | {...(props as any)} 35 | class="extra" 36 | > 37 | children 38 | 39 | )); 40 | cleanup(clean); 41 | 42 | await vt.vi.waitFor(() => { 43 | if (ref === null) throw new Error("Ref is null"); 44 | }); 45 | 46 | const component = expectGetElementToBeInTheDocument((screen) => screen.getByTestId("component")); 47 | 48 | vt.assert(typeof component! !== "undefined"); 49 | 50 | vt.expect(component.className).toEqual(equal ? `${equal} extra` : "extra"); 51 | vt.expect(component.innerHTML).toEqual("children"); 52 | 53 | clean(); 54 | } 55 | }); 56 | }); 57 | }); 58 | 59 | vt.describe("reklassed", () => { 60 | vt.describe("basic", () => { 61 | vt.it("should work", async () => { 62 | const Component = reklassed("div", fixtures.reklass.basic.options); 63 | 64 | vt.expect(Component.fx.g).toEqual({ string: vt.expect.any(Function), boolean: vt.expect.any(Function), number: vt.expect.any(Function) }); 65 | vt.expect(Component.fx.k).toEqual(["string", "boolean", "number"]); 66 | 67 | for await (const { props, equal } of fixtures.reklass.basic.test) { 68 | let ref: HTMLDivElement | null = null; 69 | 70 | const clean = render(() => ( 71 | { 73 | ref = element; 74 | }} 75 | data-testid="component" 76 | data-custom="attribute" 77 | {...(props as any)} 78 | class="extra" 79 | > 80 | children 81 | 82 | )); 83 | cleanup(clean); 84 | 85 | await vt.vi.waitFor(() => { 86 | if (ref === null) throw new Error("Ref is null"); 87 | }); 88 | 89 | const component = expectGetElementToBeInTheDocument((screen) => screen.getByTestId("component")); 90 | 91 | vt.assert(typeof component! !== "undefined"); 92 | 93 | vt.expect(component.className).toEqual(equal ? `${equal} extra` : "extra"); 94 | vt.expect(component.innerHTML).toEqual("children"); 95 | 96 | clean(); 97 | } 98 | }); 99 | }); 100 | }); 101 | 102 | vt.describe("composed", () => { 103 | vt.it("should work", async () => { 104 | const Component = composed("div", [fixtures.compose.fx.color, fixtures.compose.fx.disabled, fixtures.compose.fx.weight, fixtures.compose.fx.box, fixtures.compose.fx.spacing]); 105 | 106 | vt.expect(Component.fx.k).toEqual(["color", "disabled", "weight", "block", "flex", "hidden", "margin", "padding"]); 107 | 108 | for await (const { props, equal } of fixtures.compose.test) { 109 | let ref: HTMLDivElement | null = null; 110 | 111 | const clean = render(() => ( 112 | { 114 | ref = element; 115 | }} 116 | data-testid="component" 117 | data-custom="attribute" 118 | {...(props as any)} 119 | class="extra" 120 | > 121 | children 122 | 123 | )); 124 | cleanup(clean); 125 | 126 | await vt.vi.waitFor(() => { 127 | if (ref === null) throw new Error("Ref is null"); 128 | }); 129 | 130 | const component = expectGetElementToBeInTheDocument((screen) => screen.getByTestId("component")); 131 | 132 | vt.assert(typeof component! !== "undefined"); 133 | 134 | vt.expect(component.className).toEqual(equal ? `${equal} extra` : "extra"); 135 | vt.expect(component.innerHTML).toEqual("children"); 136 | 137 | clean(); 138 | } 139 | }); 140 | }); 141 | -------------------------------------------------------------------------------- /tests/solid/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@test/solid", 3 | "version": "0.0.0", 4 | "type": "module", 5 | "private": true, 6 | "dependencies": { 7 | "@klass/core": "workspace:*", 8 | "@klass/solid": "workspace:*", 9 | "@test/shared": "workspace:*" 10 | }, 11 | "devDependencies": { 12 | "@ark-ui/solid": "5.7.0", 13 | "@kobalte/core": "0.13.9", 14 | "solid-js": "^1" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tests/solid/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "forceConsistentCasingInFileNames": true, 5 | "target": "ESNext", 6 | "module": "ESNext", 7 | "lib": ["ESNext", "DOM", "DOM.Iterable"], 8 | "moduleResolution": "bundler", 9 | "esModuleInterop": true, 10 | "allowImportingTsExtensions": true, 11 | "allowSyntheticDefaultImports": true, 12 | "allowJs": true, 13 | "resolveJsonModule": true, 14 | "skipLibCheck": true, 15 | "strictNullChecks": true, 16 | "noUnusedLocals": true, 17 | "noUnusedParameters": true, 18 | "noEmit": true, 19 | "jsx": "preserve", 20 | "jsxImportSource": "solid-js", 21 | "baseUrl": "./", 22 | "paths": { 23 | "~/*": ["./*"] 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/solid/utils.ts: -------------------------------------------------------------------------------- 1 | import type { JSX } from "solid-js"; 2 | import { render as _render } from "solid-js/web"; 3 | 4 | export const render = (code: () => JSX.Element) => { 5 | const container = document.createElement("div"); 6 | document.body.appendChild(container); 7 | 8 | const dispose = _render(code, container); 9 | 10 | let removed = false; 11 | return () => { 12 | if (!removed) { 13 | removed = true; 14 | dispose(); 15 | document.body.removeChild(container); 16 | } 17 | }; 18 | }; 19 | -------------------------------------------------------------------------------- /tests/solid/vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { defineProject } from "vitest/config"; 2 | 3 | import solid from "vite-plugin-solid"; 4 | 5 | import { custom } from "../config"; 6 | 7 | const config = custom(__dirname); 8 | 9 | export default defineProject({ 10 | ...config, 11 | define: { 12 | ...config.define, 13 | }, 14 | plugins: [config.plugins, solid()], 15 | test: { 16 | include: ["**/*.test.{ts,tsx}"], 17 | ...config.test, 18 | }, 19 | }); 20 | -------------------------------------------------------------------------------- /tests/vue/ecosystem/ark-ui.test.tsx: -------------------------------------------------------------------------------- 1 | import * as vt from "vitest"; 2 | 3 | import type { ComponentPublicInstance } from "vue"; 4 | 5 | import * as fixtures from "@test/shared/fixtures"; 6 | import { cleanupable, expectGetElementsToBeInTheDocument } from "@test/shared/utils"; 7 | 8 | import * as mono from "@klass/vue/mono"; 9 | 10 | import { Avatar } from "@ark-ui/vue/avatar"; 11 | 12 | import { mount } from "./../utils"; 13 | 14 | const cleanup = cleanupable(); 15 | 16 | vt.beforeEach(() => { 17 | cleanup(); 18 | }); 19 | 20 | vt.describe("klassed/mono", () => { 21 | vt.describe("abstract", () => { 22 | vt.it("should work", async () => { 23 | const ComponentRoot = mono.klassed(Avatar.Root, fixtures.klass.abstract.options); 24 | const ComponentFallback = mono.klassed(Avatar.Fallback, fixtures.klass.abstract.options); 25 | const ComponentImage = mono.klassed(Avatar.Image, fixtures.klass.abstract.options); 26 | 27 | for await (const { props, equal } of fixtures.klass.abstract.test) { 28 | let ref: Element | ComponentPublicInstance | null = null; 29 | 30 | const clean = mount(() => ( 31 | { 33 | if (element) ref = element; 34 | }} 35 | data-testid="component-root" 36 | data-custom="attribute" 37 | {...(props as any)} 38 | class="extra" 39 | > 40 | 41 | fallback 42 | 43 | 44 | 45 | )); 46 | cleanup(clean); 47 | 48 | await vt.vi.waitFor(() => { 49 | if (ref === null) throw new Error("Ref is null"); 50 | }); 51 | 52 | const [componentRoot] = expectGetElementsToBeInTheDocument((screen) => [screen.getByTestId("component-root"), screen.getByTestId("component-root"), screen.getByTestId("component-root")]); 53 | 54 | vt.expect(componentRoot.className).toEqual(equal ? `${equal} extra` : "extra"); 55 | 56 | clean(); 57 | } 58 | }); 59 | }); 60 | }); 61 | -------------------------------------------------------------------------------- /tests/vue/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@test/vue", 3 | "version": "0.0.0", 4 | "type": "module", 5 | "private": true, 6 | "dependencies": { 7 | "@klass/core": "workspace:*", 8 | "@klass/vue": "workspace:*", 9 | "@test/shared": "workspace:*" 10 | }, 11 | "devDependencies": { 12 | "@ark-ui/vue": "5.7.0", 13 | "reka-ui": "2.2.0", 14 | "vue": "^3" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tests/vue/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "forceConsistentCasingInFileNames": true, 5 | "target": "ESNext", 6 | "module": "ESNext", 7 | "lib": ["ESNext", "DOM", "DOM.Iterable"], 8 | "moduleResolution": "bundler", 9 | "esModuleInterop": true, 10 | "allowImportingTsExtensions": true, 11 | "allowSyntheticDefaultImports": true, 12 | "allowJs": true, 13 | "resolveJsonModule": true, 14 | "skipLibCheck": true, 15 | "strictNullChecks": true, 16 | "noUnusedLocals": true, 17 | "noUnusedParameters": true, 18 | "noEmit": true, 19 | "jsx": "preserve", 20 | "jsxImportSource": "vue", 21 | "baseUrl": "./", 22 | "paths": { 23 | "~/*": ["./*"] 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/vue/utils.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from "vue"; 2 | import type { Component } from "vue"; 3 | 4 | export const mount = (component: Component) => { 5 | const container = document.createElement("div"); 6 | document.body.appendChild(container); 7 | 8 | const app = createApp(component); 9 | app.mount(container); 10 | 11 | let removed = false; 12 | return () => { 13 | if (!removed) { 14 | removed = true; 15 | app.unmount(); 16 | document.body.removeChild(container); 17 | } 18 | }; 19 | }; 20 | -------------------------------------------------------------------------------- /tests/vue/vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { defineProject } from "vitest/config"; 2 | 3 | import vue from "@vitejs/plugin-vue"; 4 | import jsx from "@vitejs/plugin-vue-jsx"; 5 | 6 | import { custom } from "../config"; 7 | 8 | const config = custom(__dirname); 9 | 10 | export default defineProject({ 11 | ...config, 12 | define: { 13 | ...config.define, 14 | }, 15 | plugins: [config.plugins, vue(), jsx()], 16 | test: { 17 | include: ["**/*.test.{ts,tsx}"], 18 | ...config.test, 19 | }, 20 | }); 21 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "forceConsistentCasingInFileNames": true, 5 | "target": "ESNext", 6 | "module": "ESNext", 7 | "lib": ["ESNext"], 8 | "moduleResolution": "bundler", 9 | "esModuleInterop": true, 10 | "allowImportingTsExtensions": true, 11 | "allowSyntheticDefaultImports": true, 12 | "allowJs": true, 13 | "resolveJsonModule": true, 14 | "skipLibCheck": true, 15 | "strictNullChecks": true, 16 | "noUnusedLocals": true, 17 | "noUnusedParameters": true, 18 | "noEmit": true 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /turbo.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://turborepo.com/schema.json", 3 | "tasks": { 4 | "build": { 5 | "dependsOn": ["^build"], 6 | "outputs": ["dist/**"] 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vitest/config"; 2 | 3 | export default defineConfig({ 4 | test: { 5 | workspace: ["tests/*/vitest.config.ts"], 6 | pool: "threads", 7 | testTimeout: 10000, 8 | }, 9 | }); 10 | --------------------------------------------------------------------------------