diff --git a/.changeset/brave-lions-dance.md b/.changeset/brave-lions-dance.md new file mode 100644 index 000000000..7d17c9c81 --- /dev/null +++ b/.changeset/brave-lions-dance.md @@ -0,0 +1,8 @@ +--- +"tailwindcss-autocontrast": patch +"tailwindcss-with": patch +--- + +tailwindcss-autocontrast: Improved autocontrast plugin with updated type definitions and configuration + +tailwindcss-with: Initial release of class-based conditional variants plugin diff --git a/.changeset/config.json b/.changeset/config.json index 0eded5ae0..f0d15baf7 100644 --- a/.changeset/config.json +++ b/.changeset/config.json @@ -1,21 +1,21 @@ { - "$schema": "https://unpkg.com/@changesets/config@3.1.1/schema.json", - "changelog": ["@changesets/changelog-github", { "repo": "mehdibha/dotui" }], - "commit": false, - "fixed": [], - "linked": [], - "access": "public", - "baseBranch": "main", - "updateInternalDependencies": "patch", - "ignore": [ - "www", - "@dotui/ts-config", - "@dotui/api", - "@dotui/auth", - "@dotui/db", - "@dotui/registry", - "@dotui/colors", - "@dotui/style-system", - "@dotui/types" - ] + "$schema": "https://unpkg.com/@changesets/config@3.1.1/schema.json", + "changelog": ["@changesets/changelog-github", { "repo": "mehdibha/dotui" }], + "commit": false, + "fixed": [], + "linked": [], + "access": "public", + "baseBranch": "main", + "updateInternalDependencies": "patch", + "ignore": [ + "www", + "@dotui/ts-config", + "@dotui/api", + "@dotui/auth", + "@dotui/db", + "@dotui/registry", + "@dotui/colors", + "@dotui/types", + "@dotui/core" + ] } diff --git a/.github/version-script-beta.js b/.github/version-script-beta.js index 823b3283d..a075b4ac2 100644 --- a/.github/version-script-beta.js +++ b/.github/version-script-beta.js @@ -6,17 +6,17 @@ import fs from "node:fs"; const pkgJsonPath = "packages/tailwindcss-autocontrast/package.json"; try { - const pkg = JSON.parse(fs.readFileSync(pkgJsonPath)); - exec("git rev-parse --short HEAD", (err, stdout) => { - if (err) { - console.log(err); - process.exit(1); - } - const [major, minor, patch] = pkg.version.split(".").map(Number); - pkg.version = `${major}.${minor}.${patch + 1}-beta.${stdout.trim()}`; - fs.writeFileSync(pkgJsonPath, `${JSON.stringify(pkg, null, "\t")}\n`); - }); + const pkg = JSON.parse(fs.readFileSync(pkgJsonPath)); + exec("git rev-parse --short HEAD", (err, stdout) => { + if (err) { + console.log(err); + process.exit(1); + } + const [major, minor, patch] = pkg.version.split(".").map(Number); + pkg.version = `${major}.${minor}.${patch + 1}-beta.${stdout.trim()}`; + fs.writeFileSync(pkgJsonPath, `${JSON.stringify(pkg, null, "\t")}\n`); + }); } catch (error) { - console.error(error); - process.exit(1); + console.error(error); + process.exit(1); } diff --git a/.github/version-script-next.js b/.github/version-script-next.js index aa2585cfa..ad3d01b26 100644 --- a/.github/version-script-next.js +++ b/.github/version-script-next.js @@ -6,17 +6,17 @@ import fs from "node:fs"; const pkgJsonPath = "packages/tailwindcss-autocontrast/package.json"; try { - const pkg = JSON.parse(fs.readFileSync(pkgJsonPath)); - exec("git rev-parse --short HEAD", (err, stdout) => { - if (err) { - console.log(err); - process.exit(1); - } - const [major, minor, patch] = pkg.version.split(".").map(Number); - pkg.version = `${major}.${minor}.${patch + 1}-next.${stdout.trim()}`; - fs.writeFileSync(pkgJsonPath, `${JSON.stringify(pkg, null, "\t")}\n`); - }); + const pkg = JSON.parse(fs.readFileSync(pkgJsonPath)); + exec("git rev-parse --short HEAD", (err, stdout) => { + if (err) { + console.log(err); + process.exit(1); + } + const [major, minor, patch] = pkg.version.split(".").map(Number); + pkg.version = `${major}.${minor}.${patch + 1}-next.${stdout.trim()}`; + fs.writeFileSync(pkgJsonPath, `${JSON.stringify(pkg, null, "\t")}\n`); + }); } catch (error) { - console.error(error); - process.exit(1); + console.error(error); + process.exit(1); } diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ddbedae4a..025295d39 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,16 +9,16 @@ on: merge_group: jobs: - lint: + check: runs-on: ubuntu-latest - name: Run lint + name: Run checks steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - uses: ./.github/actions/setup - - run: pnpm lint + - run: pnpm check tsc: runs-on: ubuntu-latest @@ -70,7 +70,7 @@ jobs: check-registry: runs-on: ubuntu-latest - name: Check registry generated files + name: Check registry steps: - uses: actions/checkout@v4 with: @@ -88,28 +88,4 @@ jobs: git diff packages/core/src/__registry__/ exit 1 fi - echo "Registry files are in sync." - - check-migrations: - runs-on: ubuntu-latest - name: Check database migrations - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - uses: ./.github/actions/setup - - - name: Generate migrations - run: pnpm --filter=@dotui/db generate - env: - POSTGRES_URL: "postgresql://fake:fake@localhost:5432/fake" - - - name: Check for uncommitted migrations - run: | - if [[ -n $(git status --porcelain packages/db/drizzle/) ]]; then - echo "Error: Database migrations are out of sync!" - echo "Please run 'pnpm --filter=@dotui/db generate' and commit the changes." - git status packages/db/drizzle/ - exit 1 - fi - echo "Database migrations are in sync." + echo "Registry files are in sync." \ No newline at end of file diff --git a/.github/workflows/db-migrate.yml b/.github/workflows/db-migrate.yml deleted file mode 100644 index 8f37ea195..000000000 --- a/.github/workflows/db-migrate.yml +++ /dev/null @@ -1,27 +0,0 @@ -name: Database Migrations - -on: - push: - branches: - - main - paths: - - "packages/db/drizzle/**" - workflow_dispatch: # Allow manual trigger - -jobs: - migrate: - name: Run database migrations - runs-on: ubuntu-latest - # Only run in the main repo, not forks - if: ${{ github.repository_owner == 'mehdibha' }} - steps: - - uses: actions/checkout@v4 - - uses: ./.github/actions/setup - - - name: Run migrations - run: pnpm --filter=@dotui/db migrate - env: - POSTGRES_URL: ${{ secrets.POSTGRES_URL }} - - - name: Migration complete - run: echo "✅ Database migrations applied successfully" diff --git a/.gitignore b/.gitignore index 7f2aa21fe..eb287f0df 100644 --- a/.gitignore +++ b/.gitignore @@ -1,44 +1,37 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies +# Dependencies node_modules .pnp .pnp.js -# testing -coverage - -# next.js -.next/ -out/ -next-env.d.ts - -# production +# Build outputs +dist +dist-ssr build +.output +.cache -# misc -.DS_Store -*.pem +# Frameworks & tools +.tanstack +.nitro +.wrangler +.turbo +.source -# debug -npm-debug.log* -yarn-debug.log* -yarn-error.log* -.pnpm-debug.log* +# Testing +coverage -# local env files +# Environment .env .env*.local +*.local -# vercel -.vercel - -# typescript -dist/ -.cache +# Logs +*.log +.pnpm-debug.log* -# turbo -.turbo +# OS +.DS_Store +Thumbs.db -# fumadocs -.source \ No newline at end of file +# Security +*.pem \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 4a0afa9dd..069d8f9f8 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,47 +1,50 @@ { - "eslint.workingDirectories": [ - "www", - { - "pattern": "packages/*/" - }, - { - "pattern": "config/*/" - } - ], - "tailwindCSS.experimental.classRegex": [ - ["([\"'`][^\"'`]*.*?[\"'`])", "[\"'`]([^\"'`]*).*?[\"'`]"] - ], - "editor.defaultFormatter": "esbenp.prettier-vscode", - "[javascript]": { - "editor.defaultFormatter": "biomejs.biome" - }, - "[typescript]": { - "editor.defaultFormatter": "biomejs.biome" - }, - "[javascriptreact]": { - "editor.defaultFormatter": "biomejs.biome" - }, - "[typescriptreact]": { - "editor.defaultFormatter": "biomejs.biome" - }, - "[json]": { - "editor.defaultFormatter": "biomejs.biome" - }, - "[jsonc]": { - "editor.defaultFormatter": "biomejs.biome" - }, - "[css]": { - "editor.defaultFormatter": "biomejs.biome" - }, - "[graphql]": { - "editor.defaultFormatter": "biomejs.biome" - }, - "typescript.tsdk": "node_modules/typescript/lib", - "editor.formatOnSave": true, - "editor.formatOnPaste": true, - "emmet.showExpandedAbbreviation": "never", - "editor.codeActionsOnSave": { - "source.fixAll.biome": "explicit", - "source.organizeImports.biome": "explicit" - } + "files.watcherExclude": { + "**/routeTree.gen.ts": true + }, + "search.exclude": { + "**/routeTree.gen.ts": true + }, + "files.readonlyInclude": { + "**/routeTree.gen.ts": true + }, + "tailwindCSS.experimental.classRegex": [["([\"'`][^\"'`]*.*?[\"'`])", "[\"'`]([^\"'`]*).*?[\"'`]"]], + "[javascript]": { + "editor.defaultFormatter": "biomejs.biome" + }, + "[typescript]": { + "editor.defaultFormatter": "biomejs.biome" + }, + "[javascriptreact]": { + "editor.defaultFormatter": "biomejs.biome" + }, + "[typescriptreact]": { + "editor.defaultFormatter": "biomejs.biome" + }, + "[json]": { + "editor.defaultFormatter": "biomejs.biome" + }, + "[jsonc]": { + "editor.defaultFormatter": "biomejs.biome" + }, + "[css]": { + "editor.defaultFormatter": "biomejs.biome" + }, + "[graphql]": { + "editor.defaultFormatter": "biomejs.biome" + }, + "[markdown]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[mdx]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "typescript.tsdk": "node_modules/typescript/lib", + "editor.formatOnSave": true, + "editor.formatOnPaste": true, + "emmet.showExpandedAbbreviation": "never", + "editor.codeActionsOnSave": { + "source.fixAll.biome": "explicit", + "source.organizeImports.biome": "explicit" + } } diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8ad0b4a3c..c4a324f55 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,18 +10,18 @@ Please take a moment to review this document before starting your contribution. In order to not waste your time implementing a change that has already been declined, or is generally not needed, start by [opening an issue](https://github.com/mehdibha/dotUI/issues/new/choose) describing the problem you would like to solve. -This project uses [pnpm](https://pnpm.io) as its package manager. Install it if you haven't already: +This project requires: + +- [Node.js](https://nodejs.org) v24.11.1 or higher +- [pnpm](https://pnpm.io) v10.24.0 or higher ```bash -npm install -g pnpm +npm install -g pnpm@10.24.0 ``` ### Setup your environment locally -In order to contribute to this project, you will need to: - -1. Fork the repository - You can do it by clicking the fork button in the top right corner of this page. +1. Fork the repository by clicking the fork button in the top right corner of this page. 2. Clone the repository on your local machine @@ -29,7 +29,7 @@ In order to contribute to this project, you will need to: git clone https://github.com/your-username/dotui.git ``` -3. Create a new Branch +3. Create a new branch ```bash git checkout -b my-new-branch @@ -41,38 +41,46 @@ git checkout -b my-new-branch pnpm install ``` -### Implement your changes - -This project is a [Turborepo](https://turborepo.org/) monorepo. The code for the CLI is in the `packages/cli` directory, and the docs is in the `www` directory. Now you're all setup and can start implementing your changes. +### Project structure -Here are some useful scripts for when you are developing: +This project is a [Turborepo](https://turborepo.org/) monorepo: -| Command | Description | -| ---------------- | ------------------------------------------------------- | -| `pnpm dev:www` | Starts the development server for the docs website | -| `pnpm dev:cli` | Builds and starts the CLI in watch-mode | -| `pnpm build:cli` | Builds the CLI | -| `pnpm build:www` | Builds the docs | -| `pnpm build` | Builds CLI and docs | -| `pnpm format` | Formats the code | -| `pnpm lint` | Lints the code | -| `pnpm lint:fix` | Lints the code and fixes any errors | -| `pnpm check` | Checks your code for typeerrors, formatting and linting | +- `www/` - Documentation website +- `packages/` - Shared packages + - `api` - API utilities + - `auth` - Authentication + - `colors` - Color utilities + - `core` - Core functionality + - `db` - Database utilities + - `registry` - Component registry + - `tailwindcss-autocontrast` - Tailwind CSS plugin for auto contrast + - `tailwindcss-with` - Tailwind CSS plugin utilities + - `types` - Shared TypeScript types -When making commits, make sure to follow the [conventional commit](https://www.conventionalcommits.org/en/v1.0.0/) guidelines, i.e. prepending the message with `feat:`, `fix:`, `chore:`, `docs:`, etc... You can use `git status` to double check which files have not yet been staged for commit: +### Useful scripts -```bash -git add && git commit -m "feat/fix/chore/docs: commit message" -``` +| Command | Description | +| -------------------- | ------------------------------------------ | +| `pnpm dev` | Starts all packages in development mode | +| `pnpm dev:www` | Starts the documentation website | +| `pnpm build` | Builds all packages | +| `pnpm build:www` | Builds the documentation website | +| `pnpm build:registry`| Builds the component registry | +| `pnpm check` | Checks code for formatting and linting | +| `pnpm check:fix` | Fixes formatting and linting issues | +| `pnpm typecheck` | Runs TypeScript type checking | +| `pnpm test` | Runs tests | -### When you're done +### Before submitting -Check that your code follows the project's style guidelines by running: +Check that your code passes all checks: ```bash pnpm check +pnpm typecheck +pnpm test ``` ## Credits -This documented was inspired by the contributing guidelines for [t3-oss/create-t3-app](https://github.com/t3-oss/create-t3-app/blob/main/CONTRIBUTING.md). \ No newline at end of file +This document was inspired by the contributing guidelines for [t3-oss/create-t3-app](https://github.com/t3-oss/create-t3-app/blob/main/CONTRIBUTING.md). diff --git a/biome.json b/biome.json index 96c2d4506..4c0dff519 100644 --- a/biome.json +++ b/biome.json @@ -1,15 +1,15 @@ { - "$schema": "https://biomejs.dev/schemas/2.3.8/schema.json", - "root": true, - "linter": { - "enabled": true, - "rules": { - "recommended": true - } - }, - "formatter": { - "lineWidth": 120, - "indentStyle": "tab", - "indentWidth": 2 - } + "$schema": "https://biomejs.dev/schemas/2.3.8/schema.json", + "root": true, + "linter": { + "enabled": true, + "rules": { + "recommended": true + } + }, + "formatter": { + "lineWidth": 120, + "indentStyle": "tab", + "indentWidth": 2 + } } diff --git a/config/biome-config/base.json b/config/biome-config/base.json index 9295798aa..bd9475195 100644 --- a/config/biome-config/base.json +++ b/config/biome-config/base.json @@ -36,7 +36,8 @@ } }, "suspicious": { - "noExplicitAny": "warn" + "noExplicitAny": "warn", + "noArrayIndexKey": "warn" }, "correctness": { "useExhaustiveDependencies": "warn" @@ -60,6 +61,10 @@ "type": false, "source": ["react", "react/**", "react-dom", "react-dom/**", "react-native", "react-native/**"] }, + { + "type": false, + "source": ["@tanstack/**"] + }, ":NODE:", { "type": false, "source": [":PACKAGE:", "!@dotui/**"] }, { "type": true, "source": [":PACKAGE:", "!@dotui/**"] }, diff --git a/config/biome-config/next-js.json b/config/biome-config/next-js.json deleted file mode 100644 index 50836cf72..000000000 --- a/config/biome-config/next-js.json +++ /dev/null @@ -1,67 +0,0 @@ -{ - "$schema": "https://biomejs.dev/schemas/2.3.8/schema.json", - "root": false, - "vcs": { "enabled": true, "clientKind": "git", "useIgnoreFile": true }, - "files": { - "ignoreUnknown": true, - "includes": ["**", "!node_modules", "!.next", "!dist", "!build", "!.source"] - }, - "formatter": { "enabled": true, "indentStyle": "tab" }, - "linter": { - "enabled": true, - "rules": { - "recommended": true, - "correctness": { - "noChildrenProp": "error", - "useExhaustiveDependencies": "warn", - "useHookAtTopLevel": "error", - "useJsxKeyInIterable": "error" - }, - "security": { "noDangerouslySetInnerHtmlWithChildren": "error" }, - "style": { "useBlockStatements": "off" }, - "suspicious": { - "noCommentText": "error", - "noDuplicateJsxProps": "error", - "noUnknownAtRules": "off" - } - }, - - "domains": { - "next": "recommended", - "react": "recommended" - }, - "includes": ["**", "!.next/**", "!out/**", "!build/**", "!next-env.d.ts"] - }, - "javascript": { - "formatter": { "quoteStyle": "double" }, - "globals": [ - "onnotificationclose", - "onbackgroundfetchfail", - "onactivate", - "onerror", - "onpaymentrequest", - "onpushsubscriptionchange", - "onbackgroundfetchabort", - "onabortpayment", - "onsync", - "onpush", - "onfetch", - "oninstall", - "onbackgroundfetchsuccess", - "onmessage", - "onperiodicsync", - "oncanmakepayment", - "oncookiechange", - "onrejectionhandled", - "onbackgroundfetchclick", - "onmessageerror", - "onunhandledrejection", - "onnotificationclick", - "onlanguagechange" - ] - }, - "assist": { - "enabled": true, - "actions": { "source": { "organizeImports": "on" } } - } -} diff --git a/config/biome-config/package.json b/config/biome-config/package.json index 381adb954..2c8ddb20c 100644 --- a/config/biome-config/package.json +++ b/config/biome-config/package.json @@ -5,6 +5,7 @@ "exports": { "./base": "./base.json", "./next-js": "./next-js.json", - "./react-internal": "./react-internal.json" + "./react-internal": "./react-internal.json", + "./start": "./start.json" } } diff --git a/config/biome-config/start.json b/config/biome-config/start.json new file mode 100644 index 000000000..d2d966ec6 --- /dev/null +++ b/config/biome-config/start.json @@ -0,0 +1,19 @@ +{ + "$schema": "https://biomejs.dev/schemas/2.3.8/schema.json", + "files": { + "includes": ["**", "!**/routeTree.gen.ts", "!**/.nitro", "!**/.output", "!**/.source"] + }, + "linter": { + "domains": { + "react": "recommended" + }, + "rules": { + "security": { + "noDangerouslySetInnerHtml": "warn" + }, + "style": { + "noNonNullAssertion": "warn" + } + } + } +} diff --git a/config/ts-config/base.json b/config/ts-config/base.json index 7a2ccb585..d7a317823 100644 --- a/config/ts-config/base.json +++ b/config/ts-config/base.json @@ -1,26 +1,26 @@ { - "$schema": "https://json.schemastore.org/tsconfig", - "compilerOptions": { - "esModuleInterop": true, - "skipLibCheck": true, - "target": "ES2022", - "lib": ["ES2022"], - "allowJs": true, - "resolveJsonModule": true, - "moduleDetection": "force", - "isolatedModules": true, + "$schema": "https://json.schemastore.org/tsconfig", + "compilerOptions": { + "esModuleInterop": true, + "skipLibCheck": true, + "target": "ES2022", + "lib": ["ES2022"], + "allowJs": true, + "resolveJsonModule": true, + "moduleDetection": "force", + "isolatedModules": true, - "incremental": true, - "disableSourceOfProjectReferenceRedirect": true, - "tsBuildInfoFile": "${configDir}/.cache/tsbuildinfo.json", + "incremental": true, + "disableSourceOfProjectReferenceRedirect": true, + "tsBuildInfoFile": "${configDir}/.cache/tsbuildinfo.json", - "strict": true, - "noUncheckedIndexedAccess": true, - "checkJs": true, + "strict": true, + "noUncheckedIndexedAccess": true, + "checkJs": true, - "module": "Preserve", - "moduleResolution": "Bundler", - "noEmit": true - }, - "exclude": ["node_modules", "build", "dist", ".next", ".expo"] + "module": "Preserve", + "moduleResolution": "Bundler", + "noEmit": true + }, + "exclude": ["node_modules", "build", "dist", ".next", ".expo"] } diff --git a/config/ts-config/internal-package.json b/config/ts-config/internal-package.json index 495debeef..49fe2b18b 100644 --- a/config/ts-config/internal-package.json +++ b/config/ts-config/internal-package.json @@ -1,11 +1,11 @@ { - "$schema": "https://json.schemastore.org/tsconfig", - "extends": "./base.json", - "compilerOptions": { - "declaration": true, - "declarationMap": true, - "emitDeclarationOnly": true, - "noEmit": false, - "outDir": "${configDir}/dist" - } + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "./base.json", + "compilerOptions": { + "declaration": true, + "declarationMap": true, + "emitDeclarationOnly": true, + "noEmit": false, + "outDir": "${configDir}/dist" + } } diff --git a/config/ts-config/package.json b/config/ts-config/package.json index efede6d46..e404c7f5b 100644 --- a/config/ts-config/package.json +++ b/config/ts-config/package.json @@ -1,8 +1,8 @@ { - "name": "@dotui/ts-config", - "version": "0.0.0", - "private": true, - "publishConfig": { - "access": "public" - } + "name": "@dotui/ts-config", + "version": "0.0.0", + "private": true, + "publishConfig": { + "access": "public" + } } diff --git a/package.json b/package.json index adcb0ae24..73f8e23f7 100644 --- a/package.json +++ b/package.json @@ -1,58 +1,58 @@ { - "name": "dotui-monorepo", - "version": "0.0.0", - "private": true, - "license": "MIT", - "type": "module", - "author": { - "name": "mehdibha", - "url": "https://x.com/mehdibha" - }, - "keywords": [ - "dotui", - "next.js", - "react-aria", - "tailwind", - "typescript" - ], - "engines": { - "node": "^24.11.1", - "pnpm": "^10.24.0" - }, - "scripts": { - "build": "turbo run build", - "dev": "turbo run dev --parallel", - "dev:www": "pnpm --filter=www dev", - "start:www": "pnpm --filter=www start", - "build:www": "pnpm --filter=www build", - "build:registry": "pnpm --filter=@dotui/registry build", - "dev:registry": "chokidar 'packages/registry/src/ui/**/meta.ts' -c 'pnpm build:registry'", - "build:references": "pnpm --filter=www build:references", - "clean": "git clean -xdf node_modules", - "clean:workspaces": "turbo run clean", - "format": "turbo run format", - "lint": "turbo run lint", - "check": "turbo run check", - "lint:ws": "pnpm dlx sherif@latest", - "postinstall": "pnpm lint:ws", - "typecheck": "turbo run typecheck", - "test": "vitest run", - "release": "changeset version", - "pub:beta": "pnpm --filter=tailwindcss-autocontrast pub:beta", - "pub:release": "pnpm --filter=tailwindcss-autocontrast pub:release" - }, - "devDependencies": { - "@biomejs/biome": "^2.3.8", - "@changesets/changelog-github": "^0.5.1", - "@changesets/cli": "^2.27.3", - "@vitest/coverage-v8": "^4.0.1", - "chokidar-cli": "^3.0.0", - "puppeteer": "^24.26.0", - "tsx": "^4.21.0", - "turbo": "^2.5.8", - "typescript": "^5.8.3", - "vite-tsconfig-paths": "^5.1.4", - "vitest": "^4.0.1" - }, - "packageManager": "pnpm@10.24.0" + "name": "dotui-monorepo", + "version": "0.0.0", + "private": true, + "license": "MIT", + "type": "module", + "author": { + "name": "mehdibha", + "url": "https://x.com/mehdibha" + }, + "keywords": [ + "dotui", + "next.js", + "react-aria", + "tailwind", + "typescript" + ], + "engines": { + "node": "^24.11.1", + "pnpm": "^10.24.0" + }, + "scripts": { + "build": "turbo run build", + "dev": "turbo run dev --parallel", + "dev:www": "pnpm --filter=www dev", + "build:www": "pnpm --filter=www build", + "build:registry": "pnpm --filter=@dotui/registry build", + "preview:www": "pnpm --filter=www preview", + "dev:registry": "chokidar 'packages/registry/src/ui/**/meta.ts' -c 'pnpm build:registry'", + "build:references": "pnpm --filter=www build:references", + "clean": "git clean -xdf node_modules", + "clean:workspaces": "turbo run clean", + "check": "biome check", + "check:fix": "biome check --write", + "check:ci": "biome ci", + "lint:ws": "pnpm dlx sherif@latest", + "postinstall": "pnpm lint:ws", + "typecheck": "turbo run typecheck", + "test": "vitest run", + "release": "changeset version", + "pub:beta": "pnpm --filter=tailwindcss-autocontrast pub:beta", + "pub:release": "pnpm --filter=tailwindcss-autocontrast pub:release" + }, + "devDependencies": { + "@biomejs/biome": "^2.3.8", + "@changesets/changelog-github": "^0.5.2", + "@changesets/cli": "^2.29.8", + "@vitest/coverage-v8": "^4.0.16", + "chokidar-cli": "^3.0.0", + "puppeteer": "^24.26.0", + "tsx": "^4.21.0", + "turbo": "^2.5.8", + "typescript": "^5.8.3", + "vite-tsconfig-paths": "^6.0.3", + "vitest": "^4.0.16" + }, + "packageManager": "pnpm@10.24.0" } diff --git a/packages/api/biome.json b/packages/api/biome.json new file mode 100644 index 000000000..54d045b56 --- /dev/null +++ b/packages/api/biome.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://biomejs.dev/schemas/2.3.8/schema.json", + "root": false, + "extends": ["@dotui/biome-config/base"] +} diff --git a/packages/api/package.json b/packages/api/package.json index 393f6ebeb..dd6c1d41a 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -1,25 +1,26 @@ { - "name": "@dotui/api", - "version": "0.1.0", - "private": true, - "type": "module", - "exports": { - ".": "./src/index.ts" - }, - "license": "MIT", - "scripts": { - "clean": "git clean -xdf .cache .turbo dist node_modules", - "typecheck": "tsc --noEmit --emitDeclarationOnly false" - }, - "dependencies": { - "@dotui/auth": "workspace:*", - "@dotui/db": "workspace:*", - "@trpc/server": "^11.2.0", - "superjson": "2.2.3", - "zod": "^4.2.1" - }, - "devDependencies": { - "@dotui/ts-config": "workspace:*", - "typescript": "^5.8.3" - } + "name": "@dotui/api", + "version": "0.1.0", + "private": true, + "type": "module", + "exports": { + ".": "./src/index.ts" + }, + "license": "MIT", + "scripts": { + "clean": "git clean -xdf .cache .turbo dist node_modules", + "typecheck": "tsc --noEmit --emitDeclarationOnly false" + }, + "dependencies": { + "@dotui/auth": "workspace:*", + "@dotui/db": "workspace:*", + "@trpc/server": "^11.2.0", + "superjson": "2.2.3", + "zod": "^4.2.1" + }, + "devDependencies": { + "@dotui/biome-config": "workspace:*", + "@dotui/ts-config": "workspace:*", + "typescript": "^5.8.3" + } } diff --git a/packages/api/src/root.ts b/packages/api/src/root.ts index a875bf64b..6181533c8 100644 --- a/packages/api/src/root.ts +++ b/packages/api/src/root.ts @@ -3,8 +3,8 @@ import { styleRouter } from "./routers/style"; import { createTRPCRouter } from "./trpc"; export const appRouter = createTRPCRouter({ - auth: authRouter, - style: styleRouter, + auth: authRouter, + style: styleRouter, }); export type AppRouter = typeof appRouter; diff --git a/packages/api/src/routers/auth.ts b/packages/api/src/routers/auth.ts index a9f935f6b..02246ab5a 100644 --- a/packages/api/src/routers/auth.ts +++ b/packages/api/src/routers/auth.ts @@ -3,7 +3,7 @@ import type { TRPCRouterRecord } from "@trpc/server"; import { publicProcedure } from "../trpc"; export const authRouter = { - getSession: publicProcedure.query(({ ctx }) => { - return ctx.session; - }), + getSession: publicProcedure.query(({ ctx }) => { + return ctx.session; + }), } satisfies TRPCRouterRecord; diff --git a/packages/api/src/routers/style.ts b/packages/api/src/routers/style.ts index a51bf5345..0f0618d2d 100644 --- a/packages/api/src/routers/style.ts +++ b/packages/api/src/routers/style.ts @@ -3,358 +3,324 @@ import { z } from "zod"; import type { TRPCRouterRecord } from "@trpc/server"; import { and, eq } from "@dotui/db"; -import { createStyleSchema, updateStyleConfigSchema, style, user } from "@dotui/db/schemas"; +import { createStyleSchema, style, updateStyleConfigSchema, user } from "@dotui/db/schemas"; import { protectedProcedure, publicProcedure } from "../trpc"; const uuidSchema = z.string().uuid("Invalid UUID format"); const paginationSchema = z.object({ - limit: z.number().min(1).max(100).default(10), - offset: z.number().min(0).default(0), + limit: z.number().min(1).max(100).default(10), + offset: z.number().min(0).default(0), }); export const styleRouter = { - getActive: protectedProcedure.query(({ ctx }) => { - return ctx.session.user.activeStyleId; - }), - setActive: protectedProcedure - .input( - z.object({ - styleId: uuidSchema, - }), - ) - .mutation(async ({ ctx, input }) => { - // Verify style exists - const styleRecord = await ctx.db.query.style.findFirst({ - where: eq(style.id, input.styleId), - }); - - if (!styleRecord) { - throw new TRPCError({ - code: "NOT_FOUND", - message: "Style not found", - }); - } - - // Verify user has access (must own it or it must be public/unlisted) - const isOwner = styleRecord.userId === ctx.session.user.id; - const isPublicOrUnlisted = ["public", "unlisted"].includes( - styleRecord.visibility, - ); - - if (!isOwner && !isPublicOrUnlisted) { - throw new TRPCError({ - code: "FORBIDDEN", - message: "You don't have access to this style", - }); - } - - await ctx.db - .update(user) - .set({ - activeStyleId: input.styleId, - }) - .where(eq(user.id, ctx.session.user.id)); - - return input.styleId; - }), - getPublicStyles: publicProcedure - .input( - paginationSchema.extend({ - featured: z.boolean().optional(), - sortBy: z.enum(["newest", "oldest"]).default("newest"), - }), - ) - .query(async ({ ctx, input }) => { - const { featured, sortBy, ...pagination } = input; - - // Build where condition - const whereCondition = - featured === true - ? and(eq(style.visibility, "public"), eq(style.isFeatured, true)) - : eq(style.visibility, "public"); - - const styles = await ctx.db.query.style.findMany({ - where: whereCondition, - orderBy: (s, { desc, asc }) => [ - sortBy === "oldest" ? asc(s.createdAt) : desc(s.createdAt), - ], - limit: pagination.limit, - offset: pagination.offset, - with: { - user: { - columns: { - username: true, - image: true, - }, - }, - }, - }); - - return styles; - }), - getMyStyles: protectedProcedure - .input(paginationSchema) - .query(async ({ ctx, input }) => { - const styles = await ctx.db.query.style.findMany({ - where: eq(style.userId, ctx.session.user.id), - orderBy: (s, { desc }) => [desc(s.updatedAt)], - limit: input.limit, - offset: input.offset, - with: { - user: { - columns: { - username: true, - image: true, - }, - }, - }, - }); - - return styles; - }), - getById: publicProcedure - .input(z.object({ id: uuidSchema })) - .query(async ({ ctx, input }) => { - const styleRecord = await ctx.db.query.style.findFirst({ - where: eq(style.id, input.id), - with: { - user: { - columns: { - username: true, - image: true, - }, - }, - }, - }); - - if (!styleRecord) { - throw new TRPCError({ - code: "NOT_FOUND", - message: "Style not found", - }); - } - - // Check access permissions - const isOwner = ctx.session?.user.id === styleRecord.userId; - const isPublicOrUnlisted = ["public", "unlisted"].includes( - styleRecord.visibility, - ); - - if (!isOwner && !isPublicOrUnlisted) { - throw new TRPCError({ - code: "FORBIDDEN", - message: "You don't have access to this private style", - }); - } - - return styleRecord; - }), - getBySlug: publicProcedure - .input(z.object({ slug: z.string().min(1) })) - .query(async ({ ctx, input }) => { - const parts = input.slug.split("/"); - - // biome-ignore lint/suspicious/noImplicitAnyLet: styleRecord is conditionally assigned based on slug format - let styleRecord; - - if (parts.length === 2) { - // Format: "username/stylename" - const [username, styleName] = parts; - - if (!username || !styleName) { - throw new TRPCError({ - code: "BAD_REQUEST", - message: "Invalid slug format", - }); - } - - // Find user - const targetUser = await ctx.db.query.user.findFirst({ - where: eq(user.username, username), - }); - - if (!targetUser) { - throw new TRPCError({ - code: "NOT_FOUND", - message: "User not found", - }); - } - - // Find style - styleRecord = await ctx.db.query.style.findFirst({ - where: and( - eq(style.userId, targetUser.id), - eq(style.name, styleName), - ), - with: { - user: { - columns: { - username: true, - image: true, - }, - }, - }, - }); - } else if (parts.length === 1) { - // Format: "stylename" (public styles only) - styleRecord = await ctx.db.query.style.findFirst({ - where: and( - eq(style.name, input.slug), - eq(style.visibility, "public"), - ), - with: { - user: { - columns: { - username: true, - image: true, - }, - }, - }, - }); - } else { - throw new TRPCError({ - code: "BAD_REQUEST", - message: - "Invalid slug format. Use 'username/stylename' or 'stylename' for public styles", - }); - } - - if (!styleRecord) { - throw new TRPCError({ - code: "NOT_FOUND", - message: "Style not found", - }); - } - - // Check access permissions - const isOwner = ctx.session?.user.id === styleRecord.userId; - const isPublicOrUnlisted = ["public", "unlisted"].includes( - styleRecord.visibility, - ); - - if (!isOwner && !isPublicOrUnlisted) { - throw new TRPCError({ - code: "FORBIDDEN", - message: "You don't have access to this private style", - }); - } - - return styleRecord; - }), - create: protectedProcedure - .input(createStyleSchema) - .mutation(async ({ ctx, input }) => { - // Ensure public style names are globally unique - if (input.visibility === "public") { - const existingPublic = await ctx.db.query.style.findFirst({ - where: and( - eq(style.name, input.name), - eq(style.visibility, "public"), - ), - }); - - if (existingPublic) { - throw new TRPCError({ - code: "CONFLICT", - message: `Public style name '${input.name}' is already taken. Please choose another name.`, - }); - } - } - - // Ensure style names are unique per user regardless of visibility - const existing = await ctx.db.query.style.findFirst({ - where: and( - eq(style.userId, ctx.session.user.id), - eq(style.name, input.name), - ), - }); - - if (existing) { - throw new TRPCError({ - code: "CONFLICT", - message: ` Style ${input.name} already exists, please use a new name.`, - }); - } - - const [created] = await ctx.db - .insert(style) - .values({ - ...input, - userId: ctx.session.user.id, - }) - .returning(); - - return created; - }), - update: protectedProcedure - .input(updateStyleConfigSchema) - .mutation(async ({ ctx, input }) => { - return await ctx.db.transaction(async (tx) => { - const existingStyle = await tx.query.style.findFirst({ - where: eq(style.id, input.id), - }); - - if (!existingStyle) { - throw new TRPCError({ - code: "NOT_FOUND", - message: `Style with ID '${input.id}' not found.`, - }); - } - - if (existingStyle.userId !== ctx.session.user.id) { - throw new TRPCError({ - code: "FORBIDDEN", - message: "You can only update your own styles.", - }); - } - - const [updatedStyle] = await tx - .update(style) - .set({ - config: input.config, - updatedAt: new Date(), - }) - .where(eq(style.id, input.id)) - .returning(); - - return updatedStyle; - }); - }), - delete: protectedProcedure - .input(z.object({ id: uuidSchema })) - .mutation(async ({ ctx, input }) => { - return await ctx.db.transaction(async (tx) => { - const styleRecord = await tx.query.style.findFirst({ - where: eq(style.id, input.id), - }); - - if (!styleRecord) { - throw new TRPCError({ - code: "NOT_FOUND", - message: "Style not found", - }); - } - - if (styleRecord.userId !== ctx.session.user.id) { - throw new TRPCError({ - code: "FORBIDDEN", - message: "You can only delete your own styles", - }); - } - - // Prevent deleting active style - if (ctx.session.user.activeStyleId === input.id) { - throw new TRPCError({ - code: "BAD_REQUEST", - message: - "Cannot delete your active style. Please set a different active style first.", - }); - } - - await tx.delete(style).where(eq(style.id, input.id)); - - return { success: true }; - }); - }), + getActive: protectedProcedure.query(({ ctx }) => { + return ctx.session.user.activeStyleId; + }), + setActive: protectedProcedure + .input( + z.object({ + styleId: uuidSchema, + }), + ) + .mutation(async ({ ctx, input }) => { + // Verify style exists + const styleRecord = await ctx.db.query.style.findFirst({ + where: eq(style.id, input.styleId), + }); + + if (!styleRecord) { + throw new TRPCError({ + code: "NOT_FOUND", + message: "Style not found", + }); + } + + // Verify user has access (must own it or it must be public/unlisted) + const isOwner = styleRecord.userId === ctx.session.user.id; + const isPublicOrUnlisted = ["public", "unlisted"].includes(styleRecord.visibility); + + if (!isOwner && !isPublicOrUnlisted) { + throw new TRPCError({ + code: "FORBIDDEN", + message: "You don't have access to this style", + }); + } + + await ctx.db + .update(user) + .set({ + activeStyleId: input.styleId, + }) + .where(eq(user.id, ctx.session.user.id)); + + return input.styleId; + }), + getPublicStyles: publicProcedure + .input( + paginationSchema.extend({ + featured: z.boolean().optional(), + sortBy: z.enum(["newest", "oldest"]).default("newest"), + }), + ) + .query(async ({ ctx, input }) => { + const { featured, sortBy, ...pagination } = input; + + // Build where condition + const whereCondition = + featured === true + ? and(eq(style.visibility, "public"), eq(style.isFeatured, true)) + : eq(style.visibility, "public"); + + const styles = await ctx.db.query.style.findMany({ + where: whereCondition, + orderBy: (s, { desc, asc }) => [sortBy === "oldest" ? asc(s.createdAt) : desc(s.createdAt)], + limit: pagination.limit, + offset: pagination.offset, + with: { + user: { + columns: { + username: true, + image: true, + }, + }, + }, + }); + + return styles; + }), + getMyStyles: protectedProcedure.input(paginationSchema).query(async ({ ctx, input }) => { + const styles = await ctx.db.query.style.findMany({ + where: eq(style.userId, ctx.session.user.id), + orderBy: (s, { desc }) => [desc(s.updatedAt)], + limit: input.limit, + offset: input.offset, + with: { + user: { + columns: { + username: true, + image: true, + }, + }, + }, + }); + + return styles; + }), + getById: publicProcedure.input(z.object({ id: uuidSchema })).query(async ({ ctx, input }) => { + const styleRecord = await ctx.db.query.style.findFirst({ + where: eq(style.id, input.id), + with: { + user: { + columns: { + username: true, + image: true, + }, + }, + }, + }); + + if (!styleRecord) { + throw new TRPCError({ + code: "NOT_FOUND", + message: "Style not found", + }); + } + + // Check access permissions + const isOwner = ctx.session?.user.id === styleRecord.userId; + const isPublicOrUnlisted = ["public", "unlisted"].includes(styleRecord.visibility); + + if (!isOwner && !isPublicOrUnlisted) { + throw new TRPCError({ + code: "FORBIDDEN", + message: "You don't have access to this private style", + }); + } + + return styleRecord; + }), + getBySlug: publicProcedure.input(z.object({ slug: z.string().min(1) })).query(async ({ ctx, input }) => { + const parts = input.slug.split("/"); + + // biome-ignore lint/suspicious/noImplicitAnyLet: styleRecord is conditionally assigned based on slug format + let styleRecord; + + if (parts.length === 2) { + // Format: "username/stylename" + const [username, styleName] = parts; + + if (!username || !styleName) { + throw new TRPCError({ + code: "BAD_REQUEST", + message: "Invalid slug format", + }); + } + + // Find user + const targetUser = await ctx.db.query.user.findFirst({ + where: eq(user.username, username), + }); + + if (!targetUser) { + throw new TRPCError({ + code: "NOT_FOUND", + message: "User not found", + }); + } + + // Find style + styleRecord = await ctx.db.query.style.findFirst({ + where: and(eq(style.userId, targetUser.id), eq(style.name, styleName)), + with: { + user: { + columns: { + username: true, + image: true, + }, + }, + }, + }); + } else if (parts.length === 1) { + // Format: "stylename" (public styles only) + styleRecord = await ctx.db.query.style.findFirst({ + where: and(eq(style.name, input.slug), eq(style.visibility, "public")), + with: { + user: { + columns: { + username: true, + image: true, + }, + }, + }, + }); + } else { + throw new TRPCError({ + code: "BAD_REQUEST", + message: "Invalid slug format. Use 'username/stylename' or 'stylename' for public styles", + }); + } + + if (!styleRecord) { + throw new TRPCError({ + code: "NOT_FOUND", + message: "Style not found", + }); + } + + // Check access permissions + const isOwner = ctx.session?.user.id === styleRecord.userId; + const isPublicOrUnlisted = ["public", "unlisted"].includes(styleRecord.visibility); + + if (!isOwner && !isPublicOrUnlisted) { + throw new TRPCError({ + code: "FORBIDDEN", + message: "You don't have access to this private style", + }); + } + + return styleRecord; + }), + create: protectedProcedure.input(createStyleSchema).mutation(async ({ ctx, input }) => { + // Ensure public style names are globally unique + if (input.visibility === "public") { + const existingPublic = await ctx.db.query.style.findFirst({ + where: and(eq(style.name, input.name), eq(style.visibility, "public")), + }); + + if (existingPublic) { + throw new TRPCError({ + code: "CONFLICT", + message: `Public style name '${input.name}' is already taken. Please choose another name.`, + }); + } + } + + // Ensure style names are unique per user regardless of visibility + const existing = await ctx.db.query.style.findFirst({ + where: and(eq(style.userId, ctx.session.user.id), eq(style.name, input.name)), + }); + + if (existing) { + throw new TRPCError({ + code: "CONFLICT", + message: ` Style ${input.name} already exists, please use a new name.`, + }); + } + + const [created] = await ctx.db + .insert(style) + .values({ + ...input, + userId: ctx.session.user.id, + }) + .returning(); + + return created; + }), + update: protectedProcedure.input(updateStyleConfigSchema).mutation(async ({ ctx, input }) => { + return await ctx.db.transaction(async (tx) => { + const existingStyle = await tx.query.style.findFirst({ + where: eq(style.id, input.id), + }); + + if (!existingStyle) { + throw new TRPCError({ + code: "NOT_FOUND", + message: `Style with ID '${input.id}' not found.`, + }); + } + + if (existingStyle.userId !== ctx.session.user.id) { + throw new TRPCError({ + code: "FORBIDDEN", + message: "You can only update your own styles.", + }); + } + + const [updatedStyle] = await tx + .update(style) + .set({ + config: input.config, + updatedAt: new Date(), + }) + .where(eq(style.id, input.id)) + .returning(); + + return updatedStyle; + }); + }), + delete: protectedProcedure.input(z.object({ id: uuidSchema })).mutation(async ({ ctx, input }) => { + return await ctx.db.transaction(async (tx) => { + const styleRecord = await tx.query.style.findFirst({ + where: eq(style.id, input.id), + }); + + if (!styleRecord) { + throw new TRPCError({ + code: "NOT_FOUND", + message: "Style not found", + }); + } + + if (styleRecord.userId !== ctx.session.user.id) { + throw new TRPCError({ + code: "FORBIDDEN", + message: "You can only delete your own styles", + }); + } + + // Prevent deleting active style + if (ctx.session.user.activeStyleId === input.id) { + throw new TRPCError({ + code: "BAD_REQUEST", + message: "Cannot delete your active style. Please set a different active style first.", + }); + } + + await tx.delete(style).where(eq(style.id, input.id)); + + return { success: true }; + }); + }), } satisfies TRPCRouterRecord; diff --git a/packages/api/src/trpc.ts b/packages/api/src/trpc.ts index c7e5422de..ef5abd577 100644 --- a/packages/api/src/trpc.ts +++ b/packages/api/src/trpc.ts @@ -7,37 +7,35 @@ import type { Auth, Session } from "@dotui/auth"; /** CONTEXT **/ export const createTRPCContext = async (opts: { - headers: Headers; - auth: Auth; + headers: Headers; + auth: Auth; }): Promise<{ - authApi: Auth["api"]; - session: Session | null; - db: typeof db; + authApi: Auth["api"]; + session: Session | null; + db: typeof db; }> => { - const authApi = opts.auth.api; - const session = await authApi.getSession({ - headers: opts.headers, - }); - return { - authApi, - session, - db, - }; + const authApi = opts.auth.api; + const session = await authApi.getSession({ + headers: opts.headers, + }); + return { + authApi, + session, + db, + }; }; /** INITIALIZATION **/ const t = initTRPC.context().create({ - transformer: superjson, - errorFormatter: ({ shape, error }) => ({ - ...shape, - data: { - ...shape.data, - zodError: - error.cause instanceof ZodError - ? z.flattenError(error.cause as ZodError>) - : null, - }, - }), + transformer: superjson, + errorFormatter: ({ shape, error }) => ({ + ...shape, + data: { + ...shape.data, + zodError: + error.cause instanceof ZodError ? z.flattenError(error.cause as ZodError>) : null, + }, + }), }); /** ROUTER **/ @@ -47,23 +45,23 @@ export const createTRPCRouter = t.router; export const publicProcedure = t.procedure; export const protectedProcedure = t.procedure.use(({ ctx, next }) => { - if (!ctx.session?.user) { - throw new TRPCError({ code: "UNAUTHORIZED" }); - } - return next({ - ctx: { - session: { ...ctx.session, user: ctx.session.user }, - }, - }); + if (!ctx.session?.user) { + throw new TRPCError({ code: "UNAUTHORIZED" }); + } + return next({ + ctx: { + session: { ...ctx.session, user: ctx.session.user }, + }, + }); }); export const adminProcedure = protectedProcedure.use(({ ctx, next }) => { - if (ctx.session.user.role !== "admin") { - throw new TRPCError({ code: "UNAUTHORIZED" }); - } - return next({ - ctx: { - session: ctx.session, - }, - }); + if (ctx.session.user.role !== "admin") { + throw new TRPCError({ code: "UNAUTHORIZED" }); + } + return next({ + ctx: { + session: ctx.session, + }, + }); }); diff --git a/packages/api/tsconfig.json b/packages/api/tsconfig.json index 5f40ecf7b..b2cd12aac 100644 --- a/packages/api/tsconfig.json +++ b/packages/api/tsconfig.json @@ -1,13 +1,13 @@ { - "extends": "@dotui/ts-config/internal-package.json", - "compilerOptions": { - "baseUrl": ".", - "jsx": "preserve", - "paths": { - "@dotui/api/*": ["./src/*"], - "@dotui/core/*": ["../core/src/*"] - } - }, - "include": ["src"], - "exclude": ["node_modules"] + "extends": "@dotui/ts-config/internal-package.json", + "compilerOptions": { + "baseUrl": ".", + "jsx": "preserve", + "paths": { + "@dotui/api/*": ["./src/*"], + "@dotui/core/*": ["../core/src/*"] + } + }, + "include": ["src"], + "exclude": ["node_modules"] } diff --git a/packages/auth/biome.json b/packages/auth/biome.json new file mode 100644 index 000000000..54d045b56 --- /dev/null +++ b/packages/auth/biome.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://biomejs.dev/schemas/2.3.8/schema.json", + "root": false, + "extends": ["@dotui/biome-config/base"] +} diff --git a/packages/auth/env.ts b/packages/auth/env.ts index 10a2708ae..59f6a7b30 100644 --- a/packages/auth/env.ts +++ b/packages/auth/env.ts @@ -2,18 +2,14 @@ import { createEnv } from "@t3-oss/env-nextjs"; import { z } from "zod"; export function authEnv() { - return createEnv({ - server: { - GITHUB_CLIENT_ID: z.string().min(1), - GITHUB_CLIENT_SECRET: z.string().min(1), - AUTH_SECRET: - process.env.NODE_ENV === "production" - ? z.string().min(1) - : z.string().min(1).optional(), - NODE_ENV: z.enum(["development", "production"]).optional(), - }, - experimental__runtimeEnv: {}, - skipValidation: - !!process.env.CI || process.env.npm_lifecycle_event === "lint", - }); + return createEnv({ + server: { + GITHUB_CLIENT_ID: z.string().min(1), + GITHUB_CLIENT_SECRET: z.string().min(1), + AUTH_SECRET: process.env.NODE_ENV === "production" ? z.string().min(1) : z.string().min(1).optional(), + NODE_ENV: z.enum(["development", "production"]).optional(), + }, + experimental__runtimeEnv: {}, + skipValidation: !!process.env.CI || process.env.npm_lifecycle_event === "lint", + }); } diff --git a/packages/auth/package.json b/packages/auth/package.json index 78b2c13d5..9afb255cf 100644 --- a/packages/auth/package.json +++ b/packages/auth/package.json @@ -1,32 +1,33 @@ { - "name": "@dotui/auth", - "version": "0.1.0", - "private": true, - "type": "module", - "exports": { - ".": "./src/index.ts", - "./middleware": "./src/middleware.ts", - "./client": "./src/client.ts", - "./env": "./env.ts" - }, - "license": "MIT", - "scripts": { - "clean": "git clean -xdf .cache .turbo dist node_modules", - "generate": "dotenv -e ../../.env -- pnpx @better-auth/cli generate --config ./src/index.ts --output ../db/src/auth-schema.ts", - "typecheck": "tsc --noEmit" - }, - "dependencies": { - "@dotui/db": "workspace:*", - "@t3-oss/env-nextjs": "^0.13.6", - "better-auth": "^1.3.29", - "next": "^16.0.5", - "react": "^19.2.1", - "react-dom": "^19.2.1", - "zod": "^4.2.1" - }, - "devDependencies": { - "@dotui/ts-config": "workspace:*", - "@types/react": "^19.2.2", - "typescript": "^5.8.3" - } + "name": "@dotui/auth", + "version": "0.1.0", + "private": true, + "type": "module", + "exports": { + ".": "./src/index.ts", + "./middleware": "./src/middleware.ts", + "./client": "./src/client.ts", + "./env": "./env.ts" + }, + "license": "MIT", + "scripts": { + "clean": "git clean -xdf .cache .turbo dist node_modules", + "generate": "dotenv -e ../../.env -- pnpx @better-auth/cli generate --config ./src/index.ts --output ../db/src/auth-schema.ts", + "typecheck": "tsc --noEmit" + }, + "dependencies": { + "@dotui/db": "workspace:*", + "@t3-oss/env-nextjs": "^0.13.6", + "better-auth": "^1.3.29", + "next": "^16.0.5", + "react": "^19.2.1", + "react-dom": "^19.2.1", + "zod": "^4.2.1" + }, + "devDependencies": { + "@dotui/biome-config": "workspace:*", + "@dotui/ts-config": "workspace:*", + "@types/react": "^19.2.2", + "typescript": "^5.8.3" + } } diff --git a/packages/auth/src/index.ts b/packages/auth/src/index.ts index 5b97cba41..f8b9dd6e1 100644 --- a/packages/auth/src/index.ts +++ b/packages/auth/src/index.ts @@ -1,78 +1,80 @@ import { betterAuth } from "better-auth"; import { drizzleAdapter } from "better-auth/adapters/drizzle"; import { oAuthProxy } from "better-auth/plugins"; -import type { BetterAuthOptions } from "better-auth"; +import type { BetterAuthOptions, BetterAuthPlugin } from "better-auth"; import { db } from "@dotui/db/client"; -export function initAuth(options: { - baseUrl: string; - productionUrl: string; - secret: string | undefined; - githubClientId: string; - githubClientSecret: string; +export function initAuth(options: { + baseUrl: string; + productionUrl: string; + secret: string | undefined; + githubClientId: string; + githubClientSecret: string; + extraPlugins?: TExtraPlugins; }) { - const config = { - database: drizzleAdapter(db, { - provider: "pg", - }), - baseURL: options.baseUrl, - secret: options.secret, - user: { - additionalFields: { - username: { - type: "string", - required: false, - }, - activeStyleId: { - type: "string", - required: false, - }, - role: { - type: "string", - required: false, - defaultValue: "user", - input: false, - }, - banned: { - type: "boolean", - required: false, - defaultValue: false, - input: false, - }, - banReason: { - type: "string", - required: false, - input: false, - }, - banExpires: { - type: "date", - required: false, - input: false, - }, - }, - }, - plugins: [ - oAuthProxy({ - currentURL: options.baseUrl, - productionURL: options.productionUrl, - }), - ], - socialProviders: { - github: { - clientId: options.githubClientId, - clientSecret: options.githubClientSecret, - redirectURI: `${options.productionUrl}/api/auth/callback/github`, - mapProfileToUser: (profile) => { - return { - username: profile.login, - }; - }, - }, - }, - } satisfies BetterAuthOptions; + const config = { + database: drizzleAdapter(db, { + provider: "pg", + }), + baseURL: options.baseUrl, + secret: options.secret, + user: { + additionalFields: { + username: { + type: "string", + required: false, + }, + activeStyleId: { + type: "string", + required: false, + }, + role: { + type: "string", + required: false, + defaultValue: "user", + input: false, + }, + banned: { + type: "boolean", + required: false, + defaultValue: false, + input: false, + }, + banReason: { + type: "string", + required: false, + input: false, + }, + banExpires: { + type: "date", + required: false, + input: false, + }, + }, + }, + plugins: [ + oAuthProxy({ + currentURL: options.baseUrl, + productionURL: options.productionUrl, + }), + ...(options.extraPlugins ?? []), + ], + socialProviders: { + github: { + clientId: options.githubClientId, + clientSecret: options.githubClientSecret, + redirectURI: `${options.productionUrl}/api/auth/callback/github`, + mapProfileToUser: (profile) => { + return { + username: profile.login, + }; + }, + }, + }, + } satisfies BetterAuthOptions; - return betterAuth(config); + return betterAuth(config); } export type Auth = ReturnType; diff --git a/packages/auth/tsconfig.json b/packages/auth/tsconfig.json index 97ef78330..2f198af5a 100644 --- a/packages/auth/tsconfig.json +++ b/packages/auth/tsconfig.json @@ -1,11 +1,11 @@ { - "extends": "@dotui/ts-config/base.json", - "compilerOptions": { - "baseUrl": ".", - "paths": { - "@dotui/core/*": ["../core/src/*"] - } - }, - "include": ["src", "*.ts", "eslint.config.js"], - "exclude": ["node_modules"] + "extends": "@dotui/ts-config/base.json", + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@dotui/core/*": ["../core/src/*"] + } + }, + "include": ["src", "*.ts", "eslint.config.js"], + "exclude": ["node_modules"] } diff --git a/packages/colors/package.json b/packages/colors/package.json index ba8949507..f12f6e925 100644 --- a/packages/colors/package.json +++ b/packages/colors/package.json @@ -12,12 +12,7 @@ }, "scripts": { "clean": "git clean -xdf .cache .turbo dist node_modules", - "lint": "biome lint --write .", - "format": "biome format --write .", - "check": "biome check --write .", - "typecheck": "tsc --noEmit --emitDeclarationOnly false", - "test": "vitest run", - "test:watch": "vitest" + "typecheck": "tsc --noEmit --emitDeclarationOnly false" }, "dependencies": { "@material/material-color-utilities": "^0.3.0", @@ -27,7 +22,6 @@ "devDependencies": { "@dotui/biome-config": "workspace:*", "@dotui/ts-config": "workspace:*", - "typescript": "^5.8.3", - "vitest": "^4.0.1" + "typescript": "^5.8.3" } } diff --git a/packages/colors/src/contrast/index.ts b/packages/colors/src/contrast/index.ts index af2062e48..c56f98181 100644 --- a/packages/colors/src/contrast/index.ts +++ b/packages/colors/src/contrast/index.ts @@ -145,9 +145,8 @@ export function createContrastTheme(input: CreateThemeInput): CreateThemeOutput return result; } -// Re-export types -export type { Colorspace, ContrastFormula } from "./types"; - // New modes/palettes API (matches Material) export { createContrastThemeOptionsSchema } from "./schema"; export type { CreateContrastThemeOptions } from "./theme"; +// Re-export types +export type { Colorspace, ContrastFormula } from "./types"; diff --git a/packages/colors/src/index.ts b/packages/colors/src/index.ts index f3dc4177e..c358bc29a 100644 --- a/packages/colors/src/index.ts +++ b/packages/colors/src/index.ts @@ -1,18 +1,17 @@ // Unified API -export { createTheme } from "./theme"; -export { createThemeOptionsSchema, type CreateThemeOptions } from "./schema"; // Algorithm-specific exports export { + type CreateContrastThemeOptions, createContrastTheme, createContrastThemeOptionsSchema, - type CreateContrastThemeOptions, } from "./contrast"; export { + type CreateThemeOptions as CreateMaterialThemeOptions, createMaterialTheme, createMaterialThemeOptionsSchema, - type CreateThemeOptions as CreateMaterialThemeOptions, } from "./material"; - +export { type CreateThemeOptions, createThemeOptionsSchema } from "./schema"; +export { createTheme } from "./theme"; // Shared types export type { ColorScale, Theme, ThemeMode } from "./shared/types"; diff --git a/packages/colors/src/theme.ts b/packages/colors/src/theme.ts index 527337249..6d2e3cc6b 100644 --- a/packages/colors/src/theme.ts +++ b/packages/colors/src/theme.ts @@ -1,7 +1,7 @@ -import type { Theme } from "./shared/types"; import { createContrastTheme } from "./contrast/theme"; import { createMaterialTheme } from "./material"; import type { CreateThemeOptions } from "./schema"; +import type { Theme } from "./shared/types"; export function createTheme(options: CreateThemeOptions): Theme { if (options.algorithm === "material") { diff --git a/packages/core/biome.json b/packages/core/biome.json new file mode 100644 index 000000000..54d045b56 --- /dev/null +++ b/packages/core/biome.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://biomejs.dev/schemas/2.3.8/schema.json", + "root": false, + "extends": ["@dotui/biome-config/base"] +} diff --git a/packages/core/package.json b/packages/core/package.json index 2865c7f88..097df43b1 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -31,6 +31,7 @@ "zod": "^4.2.1" }, "devDependencies": { + "@dotui/biome-config": "workspace:*", "@dotui/ts-config": "workspace:*", "@types/node": "^22.15.3", "@types/react": "^19.2.2", diff --git a/packages/core/src/__registry__/base.ts b/packages/core/src/__registry__/base.ts index 3b7415302..e168a2a67 100644 --- a/packages/core/src/__registry__/base.ts +++ b/packages/core/src/__registry__/base.ts @@ -2,28 +2,24 @@ // Run "pnpm build" to regenerate export const base = [ - { - "name": "base", - "type": "registry:style", - "dependencies": [ - "tailwind-variants", - "clsx", - "tailwind-merge", - "react-aria-components", - "tailwindcss-react-aria-components", - "tw-animate-css", - "tailwindcss-autocontrast" - ], - "registryDependencies": [ - "utils", - "focus-styles", - "theme" - ], - "extends": "none", - "css": { - "@plugin tailwindcss-react-aria-components": {}, - "@plugin tailwindcss-autocontrast": {} - }, - "files": [] - } + { + name: "base", + type: "registry:style", + dependencies: [ + "tailwind-variants", + "clsx", + "tailwind-merge", + "react-aria-components", + "tailwindcss-react-aria-components", + "tw-animate-css", + "tailwindcss-autocontrast", + ], + registryDependencies: ["utils", "focus-styles", "theme"], + extends: "none", + css: { + "@plugin tailwindcss-react-aria-components": {}, + "@plugin tailwindcss-autocontrast": {}, + }, + files: [], + }, ] as const; diff --git a/packages/core/src/__registry__/blocks.ts b/packages/core/src/__registry__/blocks.ts index c4a6a348c..ec28332c9 100644 --- a/packages/core/src/__registry__/blocks.ts +++ b/packages/core/src/__registry__/blocks.ts @@ -2,157 +2,122 @@ // Run "pnpm build" to regenerate export const blocksCategories = [ - { - "name": "Featured", - "slug": "featured" - } + { + name: "Featured", + slug: "featured", + }, ] as const; export const blocks = [ - { - "name": "login", - "type": "registry:block", - "dependencies": [ - "@internationalized/date" - ], - "registryDependencies": [ - "button", - "text-field", - "card", - "link" - ], - "description": "A simple login form.", - "categories": [ - "featured", - "authentication" - ], - "meta": { - "containerHeight": 600 - }, - "files": [ - { - "type": "registry:page", - "path": "blocks/auth/login/page.tsx", - "target": "app/login/page.tsx", - "content": `import { LoginForm } from "@dotui/registry/blocks/auth/login/components/login-form"; + { + name: "login", + type: "registry:block", + dependencies: ["@internationalized/date"], + registryDependencies: ["button", "text-field", "card", "link"], + description: "A simple login form.", + categories: ["featured", "authentication"], + meta: { + containerHeight: 600, + }, + files: [ + { + type: "registry:page", + path: "blocks/auth/login/page.tsx", + target: "app/login/page.tsx", + content: `import { LoginForm } from "@dotui/registry/blocks/auth/login/components/login-form"; export default function Page() { - return ( -
- -
- ); + return ( +
+ +
+ ); } -` - }, - { - "type": "registry:component", - "path": "blocks/auth/login/components/login-form.tsx", - "target": "blocks/auth/login/components/login-form.tsx", - "content": `"use client"; +`, + }, + { + type: "registry:component", + path: "blocks/auth/login/components/login-form.tsx", + target: "blocks/auth/login/components/login-form.tsx", + content: `"use client"; import { cn } from "@dotui/registry/lib/utils"; import { Button } from "@dotui/registry/ui/button"; -import { - Card, - CardContent, - CardDescription, - CardHeader, - CardTitle, -} from "@dotui/registry/ui/card"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@dotui/registry/ui/card"; import { Label } from "@dotui/registry/ui/field"; import { Input } from "@dotui/registry/ui/input"; import { Link } from "@dotui/registry/ui/link"; import { TextField } from "@dotui/registry/ui/text-field"; export function LoginForm(props: React.ComponentProps<"div">) { - return ( - - - Login to your account - - Enter your email below to login to your account - - - -
- - - -
-
-
- -
-
- Or -
-
- - - - - -

- Don't have an account?{" "} - - register - -

-
-
- ); + return ( + + + Login to your account + Enter your email below to login to your account + + +
+ + + +
+
+
+ +
+
+ Or +
+
+ + + + + +

+ Don't have an account?{" "} + + register + +

+
+
+ ); } -` - } - ] - }, - { - "name": "cards", - "type": "registry:block", - "registryDependencies": [ - "all" - ], - "description": "A set of cards.", - "categories": [ - "featured", - "showcase" - ], - "meta": { - "containerHeight": 600 - }, - "files": [ - { - "type": "registry:component", - "path": "blocks/showcase/cards/components/cards.tsx", - "target": "blocks/showcase/cards/components/cards.tsx", - "content": `import { AccountMenu } from "@dotui/registry/blocks/showcase/cards/components/account-menu"; +`, + }, + ], + }, + { + name: "cards", + type: "registry:block", + registryDependencies: ["all"], + description: "A set of cards.", + categories: ["featured", "showcase"], + meta: { + containerHeight: 600, + }, + files: [ + { + type: "registry:component", + path: "blocks/showcase/cards/components/cards.tsx", + target: "blocks/showcase/cards/components/cards.tsx", + content: `import { AccountMenu } from "@dotui/registry/blocks/showcase/cards/components/account-menu"; import { Backlog } from "@dotui/registry/blocks/showcase/cards/components/backlog"; import { Booking } from "@dotui/registry/blocks/showcase/cards/components/booking"; import { ColorEditorCard } from "@dotui/registry/blocks/showcase/cards/components/color-editor"; @@ -164,606 +129,512 @@ import { TeamName } from "@dotui/registry/blocks/showcase/cards/components/team- import { cn } from "@dotui/registry/lib/utils"; export function Cards(props: React.ComponentProps<"div">) { - return ( -
-
- - -
- - - - -
- - -
- - -
- -
-
- ); + return ( +
+
+ + +
+ + + + +
+ + +
+ + +
+ +
+
+ ); } export default Cards; -` - }, - { - "type": "registry:component", - "path": "blocks/showcase/cards/components/account-menu.tsx", - "target": "blocks/showcase/cards/components/account-menu.tsx", - "content": `"use client"; +`, + }, + { + type: "registry:component", + path: "blocks/showcase/cards/components/account-menu.tsx", + target: "blocks/showcase/cards/components/account-menu.tsx", + content: `"use client"; -import { - BookIcon, - ContrastIcon, - LanguagesIcon, - LogOutIcon, - SettingsIcon, - User2Icon, - Users2Icon, -} from "lucide-react"; +import { BookIcon, ContrastIcon, LanguagesIcon, LogOutIcon, SettingsIcon, User2Icon, Users2Icon } from "lucide-react"; import { cn } from "@dotui/registry/lib/utils"; import { Avatar } from "@dotui/registry/ui/avatar"; import { Card, CardContent, CardHeader } from "@dotui/registry/ui/card"; -import { - ListBox, - ListBoxItem, - ListBoxSection, - ListBoxSectionHeader, -} from "@dotui/registry/ui/list-box"; +import { ListBox, ListBoxItem, ListBoxSection, ListBoxSectionHeader } from "@dotui/registry/ui/list-box"; import { Separator } from "@dotui/registry/ui/separator"; -export function AccountMenu({ - className, - ...props -}: React.ComponentProps<"div">) { - return ( - - - -
-

mehdibha

-

- hello@mehdibha.com -

-
-
- - - - - Profile - - - - Settings - - - - Documentation - - - - Community - - - - Preferences - - - Theme - - - - Language - - - - - - Log out - - - -
- ); +export function AccountMenu({ className, ...props }: React.ComponentProps<"div">) { + return ( + + + +
+

mehdibha

+

+ hello@mehdibha.com +

+
+
+ + + + + Profile + + + + Settings + + + + Documentation + + + + Community + + + + Preferences + + + Theme + + + + Language + + + + + + Log out + + + +
+ ); } -` - }, - { - "type": "registry:component", - "path": "blocks/showcase/cards/components/backlog.tsx", - "target": "blocks/showcase/cards/components/backlog.tsx", - "content": `"use client"; +`, + }, + { + type: "registry:component", + path: "blocks/showcase/cards/components/backlog.tsx", + target: "blocks/showcase/cards/components/backlog.tsx", + content: `"use client"; -import { - RiCheckboxCircleFill, - RiProgress4Line, - RiProgress6Line, -} from "@remixicon/react"; -import { - AlertTriangle, - Circle, - CircleDashedIcon, - MoreHorizontal, - Settings2Icon, - Zap, -} from "lucide-react"; +import { RiCheckboxCircleFill, RiProgress4Line, RiProgress6Line } from "@remixicon/react"; +import { AlertTriangle, Circle, CircleDashedIcon, MoreHorizontal, Settings2Icon, Zap } from "lucide-react"; import { Badge } from "@dotui/registry/ui/badge"; import { Button } from "@dotui/registry/ui/button"; -import { - Card, - CardContent, - CardDescription, - CardHeader, - CardTitle, -} from "@dotui/registry/ui/card"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@dotui/registry/ui/card"; import { Input } from "@dotui/registry/ui/input"; import { Menu, MenuContent, MenuItem } from "@dotui/registry/ui/menu"; import { Overlay } from "@dotui/registry/ui/overlay"; import { SearchField } from "@dotui/registry/ui/search-field"; -import { - Table, - TableBody, - TableCell, - TableColumn, - TableHeader, - TableRow, -} from "@dotui/registry/ui/table"; +import { Table, TableBody, TableCell, TableColumn, TableHeader, TableRow } from "@dotui/registry/ui/table"; export const statuses = [ - { - value: "draft", - label: "Draft", - variant: "default", - icon: CircleDashedIcon, - }, - { - value: "in progress", - label: "In progress", - variant: "info", - icon: RiProgress4Line, - }, - { - value: "in review", - label: "In review", - variant: "warning", - icon: RiProgress6Line, - }, - { - value: "done", - label: "Done", - variant: "success", - icon: RiCheckboxCircleFill, - }, + { + value: "draft", + label: "Draft", + variant: "default", + icon: CircleDashedIcon, + }, + { + value: "in progress", + label: "In progress", + variant: "info", + icon: RiProgress4Line, + }, + { + value: "in review", + label: "In review", + variant: "warning", + icon: RiProgress6Line, + }, + { + value: "done", + label: "Done", + variant: "success", + icon: RiCheckboxCircleFill, + }, ] as const; export const priorities = [ - { - value: "P0", - label: "P0", - variant: "danger", - icon: AlertTriangle, - }, - { - value: "P1", - label: "P1", - variant: "warning", - icon: Zap, - }, - { - value: "P2", - label: "P2", - variant: "info", - icon: Circle, - }, - { - value: "P3", - label: "P3", - variant: "default", - icon: Circle, - }, + { + value: "P0", + label: "P0", + variant: "danger", + icon: AlertTriangle, + }, + { + value: "P1", + label: "P1", + variant: "warning", + icon: Zap, + }, + { + value: "P2", + label: "P2", + variant: "info", + icon: Circle, + }, + { + value: "P3", + label: "P3", + variant: "default", + icon: Circle, + }, ] as const; export const types = [ - { - value: "feature", - label: "Feature", - variant: "info", - }, - { - value: "bug", - label: "Bug", - variant: "danger", - }, - { - value: "tech debt", - label: "Tech Debt", - variant: "warning", - }, - { - value: "spike", - label: "Spike", - variant: "info", - }, - { - value: "chore", - label: "Chore", - variant: "neutral", - }, - { - value: "performance", - label: "Performance", - variant: "success", - }, + { + value: "feature", + label: "Feature", + variant: "info", + }, + { + value: "bug", + label: "Bug", + variant: "danger", + }, + { + value: "tech debt", + label: "Tech Debt", + variant: "warning", + }, + { + value: "spike", + label: "Spike", + variant: "info", + }, + { + value: "chore", + label: "Chore", + variant: "neutral", + }, + { + value: "performance", + label: "Performance", + variant: "success", + }, ] as const; interface Column { - id: keyof Omit | "actions"; - name: string; - isRowHeader?: boolean; + id: keyof Omit | "actions"; + name: string; + isRowHeader?: boolean; } const columns: Column[] = [ - { name: "Title", id: "title", isRowHeader: true }, - { name: "Priority", id: "priority" }, - { name: "Status", id: "status" }, - { name: "Assignee", id: "assignee" }, - { name: "Story Points", id: "storyPoints" }, - { name: "", id: "actions" }, + { name: "Title", id: "title", isRowHeader: true }, + { name: "Priority", id: "priority" }, + { name: "Status", id: "status" }, + { name: "Assignee", id: "assignee" }, + { name: "Story Points", id: "storyPoints" }, + { name: "", id: "actions" }, ]; interface Item { - id: number; - title: string; - priority: string; - status: string; - assignee: string; - storyPoints: string; - type: string; + id: number; + title: string; + priority: string; + status: string; + assignee: string; + storyPoints: string; + type: string; } interface User { - username: string; - name: string; - avatar: string; + username: string; + name: string; + avatar: string; } export const users: User[] = [ - { - username: "shadcn", - name: "shadcn", - avatar: "https://github.com/shadcn.png", - }, - { - username: "tannerlinsley", - name: "Tanner Linsley", - avatar: "https://github.com/tannerlinsley.png", - }, - { - username: "t3dotgg", - name: "Theo Browne", - avatar: "https://github.com/t3dotgg.png", - }, - { - username: "rauchg", - name: "Guillermo Rauch", - avatar: "https://github.com/rauchg.png", - }, - { - username: "leerob", - name: "Lee Robinson", - avatar: "https://github.com/leerob.png", - }, - { - username: "steventey", - name: "Steven Tey", - avatar: "https://github.com/steventey.png", - }, + { + username: "shadcn", + name: "shadcn", + avatar: "https://github.com/shadcn.png", + }, + { + username: "tannerlinsley", + name: "Tanner Linsley", + avatar: "https://github.com/tannerlinsley.png", + }, + { + username: "t3dotgg", + name: "Theo Browne", + avatar: "https://github.com/t3dotgg.png", + }, + { + username: "rauchg", + name: "Guillermo Rauch", + avatar: "https://github.com/rauchg.png", + }, + { + username: "leerob", + name: "Lee Robinson", + avatar: "https://github.com/leerob.png", + }, + { + username: "steventey", + name: "Steven Tey", + avatar: "https://github.com/steventey.png", + }, ] as const; const data: Item[] = [ - { - id: 1, - title: "Refactor AuthProvider to support SSO + 2FA", - priority: "P0", - status: "in progress", - assignee: "shadcn", - storyPoints: "13", - type: "feature", - }, - { - id: 2, - title: "Fix race condition in payment webhooks", - priority: "P1", - status: "in review", - assignee: "tannerlinsley", - storyPoints: "5", - type: "bug", - }, - { - id: 3, - title: "Migrate legacy API from REST to GraphQL", - priority: "P2", - status: "draft", - assignee: "t3dotgg", - storyPoints: "21", - type: "tech debt", - }, - { - id: 4, - title: "Add Storybook stories for Button variants", - priority: "P3", - status: "done", - assignee: "rauchg", - storyPoints: "3", - type: "chore", - }, - { - id: 5, - title: "Spike: Evaluate Redis vs Kafka for event streaming", - priority: "P2", - status: "in progress", - assignee: "leerob", - storyPoints: "8", - type: "spike", - }, - { - id: 6, - title: "Implement lazy loading for ProductGrid component", - priority: "P1", - status: "draft", - assignee: "steventey", - storyPoints: "5", - type: "performance", - }, + { + id: 1, + title: "Refactor AuthProvider to support SSO + 2FA", + priority: "P0", + status: "in progress", + assignee: "shadcn", + storyPoints: "13", + type: "feature", + }, + { + id: 2, + title: "Fix race condition in payment webhooks", + priority: "P1", + status: "in review", + assignee: "tannerlinsley", + storyPoints: "5", + type: "bug", + }, + { + id: 3, + title: "Migrate legacy API from REST to GraphQL", + priority: "P2", + status: "draft", + assignee: "t3dotgg", + storyPoints: "21", + type: "tech debt", + }, + { + id: 4, + title: "Add Storybook stories for Button variants", + priority: "P3", + status: "done", + assignee: "rauchg", + storyPoints: "3", + type: "chore", + }, + { + id: 5, + title: "Spike: Evaluate Redis vs Kafka for event streaming", + priority: "P2", + status: "in progress", + assignee: "leerob", + storyPoints: "8", + type: "spike", + }, + { + id: 6, + title: "Implement lazy loading for ProductGrid component", + priority: "P1", + status: "draft", + assignee: "steventey", + storyPoints: "5", + type: "performance", + }, ]; export function Backlog(props: React.ComponentProps<"div">) { - return ( - - - Backlog - - Here's a list of your tasks for this month. - - - -
-
- - - -
-
- - -
-
- - - {(column) => ( - - {column.name} - - )} - - - {(item) => ( - - - {() => { - const type = types.find((t) => t.value === item.type); - if (!type) return null; - return ( -
- - {type?.label || item.type} - - {item.title} -
- ); - }} -
- - {(() => { - const priority = priorities.find( - (p) => p.value === item.priority, - ); - if (!priority) return null; - return ( - {priority.label} - ); - })()} - - - {(() => { - const status = statuses.find( - (s) => s.value === item.status, - ); - if (!status) return null; - const StatusIcon = status.icon || Circle; - return ( - - - {status?.label || item.status} - - ); - })()} - - - {(() => { - const user = users.find( - (u) => u.username === item.assignee, - ); - if (!user) return null; - return ( -
- {user.name} - {user.name} -
- ); - })()} -
- - - {item.storyPoints} - - - - - - - - Edit - Duplicate - Archive - Delete - - - - -
- )} -
-
-
-
- ); + return ( + + + Backlog + Here's a list of your tasks for this month. + + +
+
+ + + +
+
+ + +
+
+ + + {(column) => {column.name}} + + + {(item) => ( + + + {() => { + const type = types.find((t) => t.value === item.type); + if (!type) return null; + return ( +
+ {type?.label || item.type} + {item.title} +
+ ); + }} +
+ + {(() => { + const priority = priorities.find((p) => p.value === item.priority); + if (!priority) return null; + return {priority.label}; + })()} + + + {(() => { + const status = statuses.find((s) => s.value === item.status); + if (!status) return null; + const StatusIcon = status.icon || Circle; + return ( + + + {status?.label || item.status} + + ); + })()} + + + {(() => { + const user = users.find((u) => u.username === item.assignee); + if (!user) return null; + return ( +
+ {user.name} + {user.name} +
+ ); + })()} +
+ + {item.storyPoints} + + + + + + + Edit + Duplicate + Archive + Delete + + + + +
+ )} +
+
+
+
+ ); } -` - }, - { - "type": "registry:component", - "path": "blocks/showcase/cards/components/booking.tsx", - "target": "blocks/showcase/cards/components/booking.tsx", - "content": `"use client"; +`, + }, + { + type: "registry:component", + path: "blocks/showcase/cards/components/booking.tsx", + target: "blocks/showcase/cards/components/booking.tsx", + content: `"use client"; import { parseDate } from "@internationalized/date"; import { cn } from "@dotui/registry/lib/utils"; import { Button } from "@dotui/registry/ui/button"; import { Calendar } from "@dotui/registry/ui/calendar"; -import { - Card, - CardContent, - CardDescription, - CardFooter, - CardHeader, - CardTitle, -} from "@dotui/registry/ui/card"; +import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@dotui/registry/ui/card"; import { Label } from "@dotui/registry/ui/field"; import { Input } from "@dotui/registry/ui/input"; import { TimeField } from "@dotui/registry/ui/time-field"; export function Booking({ className, ...props }: React.ComponentProps<"div">) { - return ( - - - Booking - Pick a time for your meeting. - - - -
- - - - - - - - -
-
- - - - -
- ); + return ( + + + Booking + Pick a time for your meeting. + + + +
+ + + + + + + + +
+
+ + + + +
+ ); } -` - }, - { - "type": "registry:component", - "path": "blocks/showcase/cards/components/color-editor.tsx", - "target": "blocks/showcase/cards/components/color-editor.tsx", - "content": `"use client"; +`, + }, + { + type: "registry:component", + path: "blocks/showcase/cards/components/color-editor.tsx", + target: "blocks/showcase/cards/components/color-editor.tsx", + content: `"use client"; import { cn } from "@dotui/registry/lib/utils"; -import { - Card, - CardContent, - CardDescription, - CardHeader, - CardTitle, -} from "@dotui/registry/ui/card"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@dotui/registry/ui/card"; import { ColorEditor } from "@dotui/registry/ui/color-editor"; -export function ColorEditorCard({ - className, - ...props -}: React.ComponentProps<"div">) { - return ( - - - Accent color - Edit the accent color of the app. - - - - - - ); +export function ColorEditorCard({ className, ...props }: React.ComponentProps<"div">) { + return ( + + + Accent color + Edit the accent color of the app. + + + + + + ); } -` - }, - { - "type": "registry:component", - "path": "blocks/showcase/cards/components/filters.tsx", - "target": "blocks/showcase/cards/components/filters.tsx", - "content": `"use client"; +`, + }, + { + type: "registry:component", + path: "blocks/showcase/cards/components/filters.tsx", + target: "blocks/showcase/cards/components/filters.tsx", + content: `"use client"; // import { ZapIcon } from "lucide-react"; import { cn } from "@dotui/registry/lib/utils"; import { Button } from "@dotui/registry/ui/button"; -import { - Card, - CardContent, - CardFooter, - CardHeader, - CardTitle, -} from "@dotui/registry/ui/card"; +import { Card, CardContent, CardFooter, CardHeader, CardTitle } from "@dotui/registry/ui/card"; import { Description, Label } from "@dotui/registry/ui/field"; import { Slider, SliderControl, SliderOutput } from "@dotui/registry/ui/slider"; import { Switch } from "@dotui/registry/ui/switch"; @@ -772,80 +643,75 @@ import { ToggleButton } from "@dotui/registry/ui/toggle-button"; import { ToggleButtonGroup } from "@dotui/registry/ui/toggle-button-group"; export function Filters({ className, ...props }: React.ComponentProps<"div">) { - return ( - - - Filters - - -
- - - Any type - Room - Entire home - -
- -
- - -
- - Trip price, includes all fees -
- - - - Wifi - TV - Kitchen - Pool - Washer - Dryer - Heating - Hair dryer - EV charger - Gym - BBQ grill - Breakfast - - - - - {/* */} - Instant booking - - -
- - - - -
- ); + return ( + + + Filters + + +
+ + + Any type + Room + Entire home + +
+ +
+ + +
+ + Trip price, includes all fees +
+ + + + Wifi + TV + Kitchen + Pool + Washer + Dryer + Heating + Hair dryer + EV charger + Gym + BBQ grill + Breakfast + + + + + {/* */} + Instant booking + + +
+ + + + +
+ ); } -` - }, - { - "type": "registry:component", - "path": "blocks/showcase/cards/components/invite-members.tsx", - "target": "blocks/showcase/cards/components/invite-members.tsx", - "content": `"use client"; +`, + }, + { + type: "registry:component", + path: "blocks/showcase/cards/components/invite-members.tsx", + target: "blocks/showcase/cards/components/invite-members.tsx", + content: `"use client"; import { PlusCircleIcon } from "lucide-react"; @@ -853,526 +719,404 @@ import { ExternalLinkIcon } from "@dotui/registry/icons"; import { Avatar } from "@dotui/registry/ui/avatar"; import { Button } from "@dotui/registry/ui/button"; import { - Card, - CardAction, - CardContent, - CardDescription, - CardFooter, - CardHeader, - CardTitle, + Card, + CardAction, + CardContent, + CardDescription, + CardFooter, + CardHeader, + CardTitle, } from "@dotui/registry/ui/card"; import { Label } from "@dotui/registry/ui/field"; import { Input } from "@dotui/registry/ui/input"; -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, -} from "@dotui/registry/ui/select"; +import { Select, SelectContent, SelectItem, SelectTrigger } from "@dotui/registry/ui/select"; import { Separator } from "@dotui/registry/ui/separator"; import { TextField } from "@dotui/registry/ui/text-field"; const teamMembers = [ - { - name: "shadcn", - email: "shadcn@vercel.com", - avatar: "https://github.com/shadcn.png", - role: "owner", - }, - { - name: "rauchg", - email: "rauchg@vercel.com", - avatar: "https://github.com/rauchg.png", - role: "member", - }, - { - name: "Lee Robinson", - email: "lee@cursor.com", - avatar: "https://github.com/leerob.png", - role: "member", - }, + { + name: "shadcn", + email: "shadcn@vercel.com", + avatar: "https://github.com/shadcn.png", + role: "owner", + }, + { + name: "rauchg", + email: "rauchg@vercel.com", + avatar: "https://github.com/rauchg.png", + role: "member", + }, + { + name: "Lee Robinson", + email: "lee@cursor.com", + avatar: "https://github.com/leerob.png", + role: "member", + }, ]; export function InviteMembers(props: React.ComponentProps<"div">) { - return ( - - - Invite Members - - Collaborate with members on this project. - - - - - - - -
-
- - - - - -
- -
-

Team members

-
- {teamMembers.map((member) => ( -
-
- -
-

{member.name}

-

{member.role}

-
-
- -
- ))} -
-
-
-
- - -

- Learn more about{" "} - - inviting members - - . -

- -
-
- ); + return ( + + + Invite Members + Collaborate with members on this project. + + + + + + +
+
+ + + + + +
+ +
+

Team members

+
+ {teamMembers.map((member) => ( +
+
+ +
+

{member.name}

+

{member.role}

+
+
+ +
+ ))} +
+
+
+
+ + +

+ Learn more about{" "} + + inviting members + + . +

+ +
+
+ ); } -` - }, - { - "type": "registry:component", - "path": "blocks/showcase/cards/components/login-form.tsx", - "target": "blocks/showcase/cards/components/login-form.tsx", - "content": `"use client"; +`, + }, + { + type: "registry:component", + path: "blocks/showcase/cards/components/login-form.tsx", + target: "blocks/showcase/cards/components/login-form.tsx", + content: `"use client"; import { cn } from "@dotui/registry/lib/utils"; import { Button } from "@dotui/registry/ui/button"; -import { - Card, - CardContent, - CardDescription, - CardHeader, - CardTitle, -} from "@dotui/registry/ui/card"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@dotui/registry/ui/card"; import { Label } from "@dotui/registry/ui/field"; import { Input } from "@dotui/registry/ui/input"; import { Link } from "@dotui/registry/ui/link"; import { TextField } from "@dotui/registry/ui/text-field"; export function LoginForm(props: React.ComponentProps<"div">) { - return ( - - - Login to your account - - Enter your email below to login to your account - - - -
- - - -
-
-
- -
-
- Or -
-
- - - - - -

- {/* TODO */} - Don't have an account?{" "} - - register - -

-
-
- ); + return ( + + + Login to your account + Enter your email below to login to your account + + +
+ + + +
+
+
+ +
+
+ Or +
+
+ + + + + +

+ {/* TODO */} + Don't have an account?{" "} + + register + +

+
+
+ ); } -` - }, - { - "type": "registry:component", - "path": "blocks/showcase/cards/components/notifications.tsx", - "target": "blocks/showcase/cards/components/notifications.tsx", - "content": `import React from "react"; +`, + }, + { + type: "registry:component", + path: "blocks/showcase/cards/components/notifications.tsx", + target: "blocks/showcase/cards/components/notifications.tsx", + content: `import React from "react"; import { cn } from "@dotui/registry/lib/utils"; import { Avatar } from "@dotui/registry/ui/avatar"; import { Badge } from "@dotui/registry/ui/badge"; import { Button } from "@dotui/registry/ui/button"; -import { - Card, - CardAction, - CardContent, - CardHeader, - CardTitle, -} from "@dotui/registry/ui/card"; +import { Card, CardAction, CardContent, CardHeader, CardTitle } from "@dotui/registry/ui/card"; import { ListBox, ListBoxItem } from "@dotui/registry/ui/list-box"; import { Separator } from "@dotui/registry/ui/separator"; import { Tab, TabList, TabPanel, Tabs } from "@dotui/registry/ui/tabs"; -export function Notifications({ - className, - ...props -}: React.ComponentProps<"div">) { - return ( - - - - Notifications - 12 - - - - - - - - - All - Unread - Read - - {["all", "unread", "read"].map((tab) => ( - - - {notifications - .filter((notification) => { - if (tab === "all") return true; - if (tab === "unread") return !notification.read; - if (tab === "read") return notification.read; - return false; - }) - .map((notification, index) => ( - - - -
- n[0]) - .join("")} - size="md" - /> -
-

- - {notification.user.name} - {" "} - {notification.content ? ( - notification.content - ) : ( - {notification.text} - )} -

-
-

- {notification.timestamp} -

- {notification.action && ( -
- -
- )} -
-
-
-
-
- ))} -
-
- ))} -
-
-
- ); +export function Notifications({ className, ...props }: React.ComponentProps<"div">) { + return ( + + + + Notifications + 12 + + + + + + + + + All + Unread + Read + + {["all", "unread", "read"].map((tab) => ( + + + {notifications + .filter((notification) => { + if (tab === "all") return true; + if (tab === "unread") return !notification.read; + if (tab === "read") return notification.read; + return false; + }) + .map((notification, index) => ( + + + +
+ n[0]) + .join("")} + size="md" + /> +
+

+ {notification.user.name}{" "} + {notification.content ? notification.content : {notification.text}} +

+
+

{notification.timestamp}

+ {notification.action && ( +
+ +
+ )} +
+
+
+
+
+ ))} +
+
+ ))} +
+
+
+ ); } const notifications = [ - { - user: { - name: "Guillermo Rauch", - avatar: "https://avatars.githubusercontent.com/rauchg", - }, - text: "starred your repository dotUI.", - content: ( - <> - starred mehdibha/dotUI. - - ), - read: false, - timestamp: "2 hours ago", - }, - { - user: { - name: "Lee Robinson", - avatar: "https://avatars.githubusercontent.com/leerob", - }, - text: "invited you to the Vercel GitHub organization.", - content: ( - <> - invited you to join Cursor on - GitHub. - - ), - read: false, - action: { label: "View invite" }, - timestamp: "7 hours ago", - }, - { - user: { - name: "Tim Neutkens", - avatar: "https://avatars.githubusercontent.com/timneutkens", - }, - text: "published a new release v14.2.0-canary on vercel/next.js.", - content: ( - <> - published v14.2.0-canary on - vercel/next.js. - - ), - read: false, - action: { label: "See release" }, - timestamp: "Yesterday", - }, - { - user: { - name: "Steven Tey", - avatar: "https://avatars.githubusercontent.com/steven-tey", - }, - text: "opened a pull request: Improve docs.", - content: ( - <> - opened PR: - Improve docs in - mehdibha/dotUI. - - ), - read: true, - action: { label: "Review PR" }, - timestamp: "Yesterday", - }, - { - user: { - name: "Shu Ding", - avatar: "https://avatars.githubusercontent.com/shuding", - }, - text: "starred your repository dotUI.", - content: ( - <> - starred mehdibha/dotUI. - - ), - read: true, - timestamp: "2 days ago", - }, - { - user: { - name: "Delba de Oliveira", - avatar: "https://avatars.githubusercontent.com/delbaoliveira", - }, - text: "commented on issue: Add theme presets.", - content: ( - <> - commented on #128: - Add theme presets. - - ), - read: false, - action: { label: "Reply" }, - timestamp: "3 days ago", - }, + { + user: { + name: "Guillermo Rauch", + avatar: "https://avatars.githubusercontent.com/rauchg", + }, + text: "starred your repository dotUI.", + content: ( + <> + starred mehdibha/dotUI. + + ), + read: false, + timestamp: "2 hours ago", + }, + { + user: { + name: "Lee Robinson", + avatar: "https://avatars.githubusercontent.com/leerob", + }, + text: "invited you to the Vercel GitHub organization.", + content: ( + <> + invited you to join Cursor on GitHub. + + ), + read: false, + action: { label: "View invite" }, + timestamp: "7 hours ago", + }, + { + user: { + name: "Tim Neutkens", + avatar: "https://avatars.githubusercontent.com/timneutkens", + }, + text: "published a new release v14.2.0-canary on vercel/next.js.", + content: ( + <> + published v14.2.0-canary on + vercel/next.js. + + ), + read: false, + action: { label: "See release" }, + timestamp: "Yesterday", + }, + { + user: { + name: "Steven Tey", + avatar: "https://avatars.githubusercontent.com/steven-tey", + }, + text: "opened a pull request: Improve docs.", + content: ( + <> + opened PR: Improve docs in + mehdibha/dotUI. + + ), + read: true, + action: { label: "Review PR" }, + timestamp: "Yesterday", + }, + { + user: { + name: "Shu Ding", + avatar: "https://avatars.githubusercontent.com/shuding", + }, + text: "starred your repository dotUI.", + content: ( + <> + starred mehdibha/dotUI. + + ), + read: true, + timestamp: "2 days ago", + }, + { + user: { + name: "Delba de Oliveira", + avatar: "https://avatars.githubusercontent.com/delbaoliveira", + }, + text: "commented on issue: Add theme presets.", + content: ( + <> + commented on #128: + Add theme presets. + + ), + read: false, + action: { label: "Reply" }, + timestamp: "3 days ago", + }, ]; -` - }, - { - "type": "registry:component", - "path": "blocks/showcase/cards/components/team-name.tsx", - "target": "blocks/showcase/cards/components/team-name.tsx", - "content": `"use client"; +`, + }, + { + type: "registry:component", + path: "blocks/showcase/cards/components/team-name.tsx", + target: "blocks/showcase/cards/components/team-name.tsx", + content: `"use client"; import { cn } from "@dotui/registry/lib/utils"; import { Button } from "@dotui/registry/ui/button"; -import { - Card, - CardContent, - CardDescription, - CardFooter, - CardHeader, - CardTitle, -} from "@dotui/registry/ui/card"; +import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@dotui/registry/ui/card"; import { Input } from "@dotui/registry/ui/input"; import { TextField } from "@dotui/registry/ui/text-field"; export function TeamName({ className, ...props }: React.ComponentProps<"div">) { - return ( - - - Team Name - - This is your team's visible name within the platform. For example, the - name of your company or department. - - - - - - - - -

- Please use 32 characters at maximum. -

- -
-
- ); + return ( + + + Team Name + + This is your team's visible name within the platform. For example, the name of your company or department. + + + + + + + + +

Please use 32 characters at maximum.

+ +
+
+ ); } -` - } - ] - }, - { - "name": "animation", - "type": "registry:block", - "registryDependencies": [ - "all" - ], - "categories": [ - "featured", - "showcase" - ], - "meta": { - "containerHeight": 600 - }, - "files": [ - { - "type": "registry:component", - "path": "blocks/showcase/animation/components/animation.tsx", - "target": "blocks/showcase/animation/components/animation.tsx", - "content": `"use client"; - -import React from "react"; - -import { Select, SelectItem } from "@dotui/registry/ui/select"; - -export function Animation({ - className: _className, -}: React.ComponentProps<"div">) { - const [isOpen, setIsOpen] = React.useState(false); - - React.useEffect(() => { - const interval = setInterval(() => { - setIsOpen((prev) => !prev); - }, 1000); - return () => clearInterval(interval); - }, []); - - return ( -
- -
- ); -} - -export default Animation; -` - } - ] - } +`, + }, + ], + }, ] as const; diff --git a/packages/core/src/__registry__/hooks.ts b/packages/core/src/__registry__/hooks.ts index 6010b5fe8..a38f5d889 100644 --- a/packages/core/src/__registry__/hooks.ts +++ b/packages/core/src/__registry__/hooks.ts @@ -2,37 +2,35 @@ // Run "pnpm build" to regenerate export const hooks = [ - { - "name": "use-mobile", - "type": "registry:hook", - "files": [ - { - "type": "registry:hook", - "path": "hooks/use-mobile.ts", - "target": "hooks/use-mobile.ts", - "content": `import * as React from "react"; + { + name: "use-mobile", + type: "registry:hook", + files: [ + { + type: "registry:hook", + path: "hooks/use-mobile.ts", + target: "hooks/use-mobile.ts", + content: `import * as React from "react"; const MOBILE_BREAKPOINT = 768; export function useIsMobile() { - const [isMobile, setIsMobile] = React.useState( - undefined, - ); + const [isMobile, setIsMobile] = React.useState(undefined); - React.useEffect(() => { - const mql = window.matchMedia(\`(max-width: \${MOBILE_BREAKPOINT - 1}px)\`); - const onChange = () => { - setIsMobile(window.innerWidth < MOBILE_BREAKPOINT); - }; - mql.addEventListener("change", onChange); - setIsMobile(window.innerWidth < MOBILE_BREAKPOINT); - return () => mql.removeEventListener("change", onChange); - }, []); + React.useEffect(() => { + const mql = window.matchMedia(\`(max-width: \${MOBILE_BREAKPOINT - 1}px)\`); + const onChange = () => { + setIsMobile(window.innerWidth < MOBILE_BREAKPOINT); + }; + mql.addEventListener("change", onChange); + setIsMobile(window.innerWidth < MOBILE_BREAKPOINT); + return () => mql.removeEventListener("change", onChange); + }, []); - return !!isMobile; + return !!isMobile; } -` - } - ] - } +`, + }, + ], + }, ] as const; diff --git a/packages/core/src/__registry__/icons.ts b/packages/core/src/__registry__/icons.ts index 9d155d53e..d0407bd6e 100644 --- a/packages/core/src/__registry__/icons.ts +++ b/packages/core/src/__registry__/icons.ts @@ -2,975 +2,975 @@ // Run "pnpm build" to regenerate export const iconLibraries = [ - { - "name": "lucide", - "label": "Lucide icons", - "package": "lucide-react", - "import": "lucide-react" - }, - { - "name": "remix", - "label": "Remix icons", - "package": "@remixicon/react", - "import": "@remixicon/react" - }, - { - "name": "tabler", - "label": "Tabler icons", - "package": "@tabler/icons-react", - "import": "@tabler/icons-react" - }, - { - "name": "hugeicons", - "label": "Huge icons", - "package": "@hugeicons/react", - "import": "@hugeicons/react" - } + { + name: "lucide", + label: "Lucide icons", + package: "lucide-react", + import: "lucide-react", + }, + { + name: "remix", + label: "Remix icons", + package: "@remixicon/react", + import: "@remixicon/react", + }, + { + name: "tabler", + label: "Tabler icons", + package: "@tabler/icons-react", + import: "@tabler/icons-react", + }, + { + name: "hugeicons", + label: "Huge icons", + package: "@hugeicons/react", + import: "@hugeicons/react", + }, ] as const; export type IconLibraryName = (typeof iconLibraries)[number]["name"]; export const icons = { - "PlusIcon": { - "lucide": "PlusIcon", - "remix": "RiAddLine", - "tabler": "IconPlus", - "hugeicons": "PlusSignIcon" - }, - "PaperclipIcon": { - "lucide": "PaperclipIcon", - "remix": "RiAttachmentLine", - "tabler": "IconPaperclip", - "hugeicons": "AttachmentIcon" - }, - "SparklesIcon": { - "lucide": "SparklesIcon", - "remix": "RiSparklingLine", - "tabler": "IconSparkles", - "hugeicons": "SparklesIcon" - }, - "ShoppingBagIcon": { - "lucide": "ShoppingBagIcon", - "remix": "RiShoppingBagLine", - "tabler": "IconShoppingBag", - "hugeicons": "ShoppingBag01Icon" - }, - "WandIcon": { - "lucide": "WandIcon", - "remix": "RiMagicLine", - "tabler": "IconWand", - "hugeicons": "MagicWand01Icon" - }, - "MousePointerIcon": { - "lucide": "MousePointerIcon", - "remix": "RiCursorLine", - "tabler": "IconPointer", - "hugeicons": "Cursor01Icon" - }, - "MoreHorizontalIcon": { - "lucide": "MoreHorizontalIcon", - "remix": "RiMoreLine", - "tabler": "IconDots", - "hugeicons": "MoreHorizontalCircle01Icon" - }, - "ShareIcon": { - "lucide": "ShareIcon", - "remix": "RiShareLine", - "tabler": "IconShare", - "hugeicons": "Share03Icon" - }, - "BookOpenIcon": { - "lucide": "BookOpenIcon", - "remix": "RiBookOpenLine", - "tabler": "IconBook", - "hugeicons": "BookOpen01Icon" - }, - "GlobeIcon": { - "lucide": "GlobeIcon", - "remix": "RiGlobalLine", - "tabler": "IconWorld", - "hugeicons": "GlobalIcon" - }, - "PenToolIcon": { - "lucide": "PenToolIcon", - "remix": "RiPenNibLine", - "tabler": "IconPencil", - "hugeicons": "QuillWrite01Icon" - }, - "AudioLinesIcon": { - "lucide": "AudioLinesIcon", - "remix": "RiSoundModuleLine", - "tabler": "IconMicrophone", - "hugeicons": "Mic01Icon" - }, - "ArrowUpIcon": { - "lucide": "ArrowUpIcon", - "remix": "RiArrowUpLine", - "tabler": "IconArrowUp", - "hugeicons": "ArrowUp01Icon" - }, - "ChevronDownIcon": { - "lucide": "ChevronDownIcon", - "remix": "RiArrowDownSLine", - "tabler": "IconChevronDown", - "hugeicons": "ArrowDown01Icon" - }, - "SettingsIcon": { - "lucide": "SettingsIcon", - "remix": "RiSettings3Line", - "tabler": "IconSettings", - "hugeicons": "Settings01Icon" - }, - "FolderIcon": { - "lucide": "FolderIcon", - "remix": "RiFolderLine", - "tabler": "IconFolder", - "hugeicons": "Folder01Icon" - }, - "CircleCheckIcon": { - "lucide": "CircleCheckIcon", - "remix": "RiCheckboxCircleLine", - "tabler": "IconCircleCheck", - "hugeicons": "CheckmarkCircle02Icon" - }, - "LightbulbIcon": { - "lucide": "LightbulbIcon", - "remix": "RiLightbulbLine", - "tabler": "IconBulb", - "hugeicons": "BulbIcon" - }, - "ContainerIcon": { - "lucide": "ContainerIcon", - "remix": "RiBox3Line", - "tabler": "IconBox", - "hugeicons": "CubeIcon" - }, - "ZapIcon": { - "lucide": "ZapIcon", - "remix": "RiFlashlightLine", - "tabler": "IconBolt", - "hugeicons": "ZapIcon" - }, - "ServerIcon": { - "lucide": "ServerIcon", - "remix": "RiServerLine", - "tabler": "IconServer", - "hugeicons": "DatabaseIcon" - }, - "InfoIcon": { - "lucide": "InfoIcon", - "remix": "RiInformationLine", - "tabler": "IconInfoCircle", - "hugeicons": "InformationCircleIcon" - }, - "TerminalIcon": { - "lucide": "TerminalIcon", - "remix": "RiTerminalBoxLine", - "tabler": "IconTerminal", - "hugeicons": "SourceCodeIcon" - }, - "CopyIcon": { - "lucide": "CopyIcon", - "remix": "RiFileCopyLine", - "tabler": "IconCopy", - "hugeicons": "Copy01Icon" - }, - "MonitorIcon": { - "lucide": "MonitorIcon", - "remix": "RiComputerLine", - "tabler": "IconDeviceDesktop", - "hugeicons": "ComputerIcon" - }, - "DownloadIcon": { - "lucide": "DownloadIcon", - "remix": "RiDownloadLine", - "tabler": "IconDownload", - "hugeicons": "Download01Icon" - }, - "SearchIcon": { - "lucide": "SearchIcon", - "remix": "RiSearchLine", - "tabler": "IconSearch", - "hugeicons": "Search01Icon" - }, - "UploadIcon": { - "lucide": "UploadIcon", - "remix": "RiUpload2Line", - "tabler": "IconUpload", - "hugeicons": "Upload01Icon" - }, - "CloudCogIcon": { - "lucide": "CloudCogIcon", - "remix": "RiCloudLine", - "tabler": "IconCloudCog", - "hugeicons": "AiCloud01Icon" - }, - "GitBranchIcon": { - "lucide": "GitBranchIcon", - "remix": "RiGitBranchLine", - "tabler": "IconGitBranch", - "hugeicons": "GitBranchIcon" - }, - "BotIcon": { - "lucide": "BotIcon", - "remix": "RiRobotLine", - "tabler": "IconRobot", - "hugeicons": "RoboticIcon" - }, - "SendIcon": { - "lucide": "SendIcon", - "remix": "RiSendPlaneLine", - "tabler": "IconSend", - "hugeicons": "SentIcon" - }, - "MenuIcon": { - "lucide": "MenuIcon", - "remix": "RiMenuLine", - "tabler": "IconMenu", - "hugeicons": "Menu09Icon" - }, - "XIcon": { - "lucide": "XIcon", - "remix": "RiCloseLine", - "tabler": "IconX", - "hugeicons": "Cancel01Icon" - }, - "HomeIcon": { - "lucide": "HomeIcon", - "remix": "RiHomeLine", - "tabler": "IconHome", - "hugeicons": "Home01Icon" - }, - "CircleIcon": { - "lucide": "CircleIcon", - "remix": "RiCircleLine", - "tabler": "IconCircle", - "hugeicons": "CircleIcon" - }, - "LayoutGridIcon": { - "lucide": "LayoutGridIcon", - "remix": "RiLayoutGridLine", - "tabler": "IconLayoutGrid", - "hugeicons": "GridIcon" - }, - "MailIcon": { - "lucide": "MailIcon", - "remix": "RiMailLine", - "tabler": "IconMail", - "hugeicons": "Mail01Icon" - }, - "LinkIcon": { - "lucide": "LinkIcon", - "remix": "RiLinkM", - "tabler": "IconLink", - "hugeicons": "Link01Icon" - }, - "SmileIcon": { - "lucide": "SmileIcon", - "remix": "RiEmotionLine", - "tabler": "IconMoodSmile", - "hugeicons": "SmileIcon" - }, - "CircleAlertIcon": { - "lucide": "CircleAlertIcon", - "remix": "RiErrorWarningLine", - "tabler": "IconExclamationCircle", - "hugeicons": "Alert01Icon" - }, - "UserIcon": { - "lucide": "UserIcon", - "remix": "RiUserLine", - "tabler": "IconUser", - "hugeicons": "UserIcon" - }, - "StarIcon": { - "lucide": "StarIcon", - "remix": "RiStarLine", - "tabler": "IconStar", - "hugeicons": "StarIcon" - }, - "CodeIcon": { - "lucide": "CodeIcon", - "remix": "RiCodeLine", - "tabler": "IconCode", - "hugeicons": "CodeIcon" - }, - "HeartIcon": { - "lucide": "HeartIcon", - "remix": "RiHeartLine", - "tabler": "IconHeart", - "hugeicons": "FavouriteIcon" - }, - "LogOutIcon": { - "lucide": "LogOutIcon", - "remix": "RiLogoutBoxLine", - "tabler": "IconLogout", - "hugeicons": "Logout01Icon" - }, - "MinusIcon": { - "lucide": "MinusIcon", - "remix": "RiSubtractLine", - "tabler": "IconMinus", - "hugeicons": "MinusSignIcon" - }, - "ArrowLeftIcon": { - "lucide": "ArrowLeftIcon", - "remix": "RiArrowLeftLine", - "tabler": "IconArrowLeft", - "hugeicons": "ArrowLeft01Icon" - }, - "MailCheckIcon": { - "lucide": "MailCheckIcon", - "remix": "RiMailCheckLine", - "tabler": "IconMailCheck", - "hugeicons": "MailValidation01Icon" - }, - "ArchiveIcon": { - "lucide": "ArchiveIcon", - "remix": "RiArchiveLine", - "tabler": "IconArchive", - "hugeicons": "Archive02Icon" - }, - "ClockIcon": { - "lucide": "ClockIcon", - "remix": "RiTimeLine", - "tabler": "IconClock", - "hugeicons": "Clock01Icon" - }, - "CalendarPlusIcon": { - "lucide": "CalendarPlusIcon", - "remix": "RiCalendarEventLine", - "tabler": "IconCalendarPlus", - "hugeicons": "CalendarAdd01Icon" - }, - "ListFilterIcon": { - "lucide": "ListFilterIcon", - "remix": "RiFilterLine", - "tabler": "IconFilterPlus", - "hugeicons": "FilterIcon" - }, - "TagIcon": { - "lucide": "TagIcon", - "remix": "RiPriceTag3Line", - "tabler": "IconTag", - "hugeicons": "Tag01Icon" - }, - "Trash2Icon": { - "lucide": "Trash2Icon", - "remix": "RiDeleteBin6Line", - "tabler": "IconTrash", - "hugeicons": "Delete02Icon" - }, - "ArrowRightIcon": { - "lucide": "ArrowRightIcon", - "remix": "RiArrowRightLine", - "tabler": "IconArrowRight", - "hugeicons": "ArrowRight02Icon" - }, - "VolumeX": { - "lucide": "VolumeX", - "remix": "RiVolumeMuteLine", - "tabler": "IconVolume", - "hugeicons": "VolumeOffIcon" - }, - "CheckIcon": { - "lucide": "CheckIcon", - "remix": "RiCheckLine", - "tabler": "IconCheck", - "hugeicons": "Tick02Icon" - }, - "UserRoundXIcon": { - "lucide": "UserRoundXIcon", - "remix": "RiUserUnfollowLine", - "tabler": "IconUserX", - "hugeicons": "UserRemove01Icon" - }, - "AlertTriangleIcon": { - "lucide": "AlertTriangleIcon", - "remix": "RiAlertLine", - "tabler": "IconAlertTriangle", - "hugeicons": "Alert02Icon" - }, - "TrashIcon": { - "lucide": "TrashIcon", - "remix": "RiDeleteBinLine", - "tabler": "IconTrash", - "hugeicons": "Delete01Icon" - }, - "BluetoothIcon": { - "lucide": "BluetoothIcon", - "remix": "RiBluetoothLine", - "tabler": "IconBluetooth", - "hugeicons": "BluetoothIcon" - }, - "MoreVerticalIcon": { - "lucide": "MoreVerticalIcon", - "remix": "RiMore2Line", - "tabler": "IconDotsVertical", - "hugeicons": "MoreVerticalCircle01Icon" - }, - "FileIcon": { - "lucide": "FileIcon", - "remix": "RiFileLine", - "tabler": "IconFile", - "hugeicons": "File01Icon" - }, - "FolderOpenIcon": { - "lucide": "FolderOpenIcon", - "remix": "RiFolderOpenLine", - "tabler": "IconFolderOpen", - "hugeicons": "FolderOpenIcon" - }, - "FileCodeIcon": { - "lucide": "FileCodeIcon", - "remix": "RiFileCodeLine", - "tabler": "IconFileCode", - "hugeicons": "CodeIcon" - }, - "FolderSearchIcon": { - "lucide": "FolderSearchIcon", - "remix": "RiFileSearchLine", - "tabler": "IconFolderSearch", - "hugeicons": "Search01Icon" - }, - "SaveIcon": { - "lucide": "SaveIcon", - "remix": "RiSaveLine", - "tabler": "IconDeviceFloppy", - "hugeicons": "FloppyDiskIcon" - }, - "EyeIcon": { - "lucide": "EyeIcon", - "remix": "RiEyeLine", - "tabler": "IconEye", - "hugeicons": "EyeIcon" - }, - "LayoutIcon": { - "lucide": "LayoutIcon", - "remix": "RiLayoutLine", - "tabler": "IconLayout", - "hugeicons": "Layout01Icon" - }, - "PaletteIcon": { - "lucide": "PaletteIcon", - "remix": "RiPaletteLine", - "tabler": "IconPalette", - "hugeicons": "PaintBoardIcon" - }, - "SunIcon": { - "lucide": "SunIcon", - "remix": "RiSunLine", - "tabler": "IconSun", - "hugeicons": "Sun01Icon" - }, - "MoonIcon": { - "lucide": "MoonIcon", - "remix": "RiMoonLine", - "tabler": "IconMoon", - "hugeicons": "MoonIcon" - }, - "HelpCircleIcon": { - "lucide": "HelpCircleIcon", - "remix": "RiQuestionLine", - "tabler": "IconHelpCircle", - "hugeicons": "HelpCircleIcon" - }, - "FileTextIcon": { - "lucide": "FileTextIcon", - "remix": "RiFileTextLine", - "tabler": "IconFileText", - "hugeicons": "File01Icon" - }, - "CalendarIcon": { - "lucide": "CalendarIcon", - "remix": "RiCalendarLine", - "tabler": "IconCalendar", - "hugeicons": "Calendar01Icon" - }, - "Search": { - "lucide": "Search", - "remix": "RiSearchLine", - "tabler": "IconSearch", - "hugeicons": "Search01Icon" - }, - "CheckCircle2Icon": { - "lucide": "CheckCircle2Icon", - "remix": "RiCheckboxCircleLine", - "tabler": "IconCircleCheckFilled", - "hugeicons": "CheckmarkCircle02Icon" - }, - "CircleDollarSignIcon": { - "lucide": "CircleDollarSignIcon", - "remix": "RiMoneyDollarCircleLine", - "tabler": "IconCoin", - "hugeicons": "DollarCircleIcon" - }, - "ArrowUpRightIcon": { - "lucide": "ArrowUpRightIcon", - "remix": "RiArrowRightUpLine", - "tabler": "IconArrowUpRight", - "hugeicons": "ArrowUpRight01Icon" - }, - "BadgeCheck": { - "lucide": "BadgeCheck", - "remix": "RiVerifiedBadgeLine", - "tabler": "IconRosetteDiscountCheck", - "hugeicons": "CheckmarkBadge02Icon" - }, - "ArrowLeftCircleIcon": { - "lucide": "ArrowLeftCircleIcon", - "remix": "RiArrowLeftCircleLine", - "tabler": "IconCircleArrowLeft", - "hugeicons": "CircleArrowLeft02Icon" - }, - "FlipHorizontalIcon": { - "lucide": "FlipHorizontalIcon", - "remix": "RiFlipHorizontalLine", - "tabler": "IconFlipHorizontal", - "hugeicons": "FlipHorizontalIcon" - }, - "FlipVerticalIcon": { - "lucide": "FlipVerticalIcon", - "remix": "RiFlipVerticalLine", - "tabler": "IconFlipVertical", - "hugeicons": "FlipVerticalIcon" - }, - "RotateCwIcon": { - "lucide": "RotateCwIcon", - "remix": "RiRestartLine", - "tabler": "IconRotateClockwise2", - "hugeicons": "Rotate01Icon" - }, - "Clock2Icon": { - "lucide": "Clock2Icon", - "remix": "RiTimeLine", - "tabler": "IconClockHour2", - "hugeicons": "Clock03Icon" - }, - "CaptionsIcon": { - "lucide": "CaptionsIcon", - "remix": "RiClosedCaptioningLine", - "tabler": "IconTextCaption", - "hugeicons": "ClosedCaptionIcon" - }, - "TrendingUpIcon": { - "lucide": "TrendingUpIcon", - "remix": "RiArrowRightUpLine", - "tabler": "IconTrendingUp", - "hugeicons": "Analytics01Icon" - }, - "ChevronRightIcon": { - "lucide": "ChevronRightIcon", - "remix": "RiArrowRightSLine", - "tabler": "IconChevronRight", - "hugeicons": "ArrowRight01Icon" - }, - "MinimizeIcon": { - "lucide": "MinimizeIcon", - "remix": "RiContractLeftRightLine", - "tabler": "IconMinimize", - "hugeicons": "MinusSignIcon" - }, - "MaximizeIcon": { - "lucide": "MaximizeIcon", - "remix": "RiExpandLeftRightLine", - "tabler": "IconMaximize", - "hugeicons": "PlusSignIcon" - }, - "CreditCardIcon": { - "lucide": "CreditCardIcon", - "remix": "RiBankCardLine", - "tabler": "IconCreditCard", - "hugeicons": "CreditCardIcon" - }, - "CalculatorIcon": { - "lucide": "CalculatorIcon", - "remix": "RiCalculatorLine", - "tabler": "IconCalculator", - "hugeicons": "CalculatorIcon" - }, - "InboxIcon": { - "lucide": "InboxIcon", - "remix": "RiInboxLine", - "tabler": "IconArchive", - "hugeicons": "Archive02Icon" - }, - "FolderPlusIcon": { - "lucide": "FolderPlusIcon", - "remix": "RiFolderAddLine", - "tabler": "IconFolderPlus", - "hugeicons": "FolderAddIcon" - }, - "ScissorsIcon": { - "lucide": "ScissorsIcon", - "remix": "RiScissorsLine", - "tabler": "IconCut", - "hugeicons": "ScissorIcon" - }, - "ClipboardPasteIcon": { - "lucide": "ClipboardPasteIcon", - "remix": "RiClipboardLine", - "tabler": "IconClipboard", - "hugeicons": "ClipboardIcon" - }, - "ListIcon": { - "lucide": "ListIcon", - "remix": "RiListUnordered", - "tabler": "IconList", - "hugeicons": "Menu05Icon" - }, - "ZoomInIcon": { - "lucide": "ZoomInIcon", - "remix": "RiZoomInLine", - "tabler": "IconZoomIn", - "hugeicons": "ZoomInAreaIcon" - }, - "ZoomOutIcon": { - "lucide": "ZoomOutIcon", - "remix": "RiZoomOutLine", - "tabler": "IconZoomOut", - "hugeicons": "ZoomOutAreaIcon" - }, - "BellIcon": { - "lucide": "BellIcon", - "remix": "RiNotification3Line", - "tabler": "IconBell", - "hugeicons": "Notification01Icon" - }, - "ImageIcon": { - "lucide": "ImageIcon", - "remix": "RiImageLine", - "tabler": "IconPhoto", - "hugeicons": "Image01Icon" - }, - "KeyboardIcon": { - "lucide": "KeyboardIcon", - "remix": "RiKeyboardLine", - "tabler": "IconKeyboard", - "hugeicons": "KeyboardIcon" - }, - "LanguagesIcon": { - "lucide": "LanguagesIcon", - "remix": "RiTranslate", - "tabler": "IconLanguage", - "hugeicons": "LanguageCircleIcon" - }, - "ShieldIcon": { - "lucide": "ShieldIcon", - "remix": "RiShieldLine", - "tabler": "IconShield", - "hugeicons": "SecurityIcon" - }, - "PencilIcon": { - "lucide": "PencilIcon", - "remix": "RiPencilLine", - "tabler": "IconPencil", - "hugeicons": "Edit01Icon" - }, - "ActivityIcon": { - "lucide": "ActivityIcon", - "remix": "RiPulseLine", - "tabler": "IconActivity", - "hugeicons": "Cardiogram01Icon" - }, - "PanelLeftIcon": { - "lucide": "PanelLeftIcon", - "remix": "RiLayoutLeftLine", - "tabler": "IconLayoutSidebar", - "hugeicons": "LayoutLeftIcon" - }, - "ArrowDownIcon": { - "lucide": "ArrowDownIcon", - "remix": "RiArrowDownLine", - "tabler": "IconArrowDown", - "hugeicons": "ArrowDown01Icon" - }, - "MessageSquareIcon": { - "lucide": "MessageSquareIcon", - "remix": "RiChat1Line", - "tabler": "IconMessage", - "hugeicons": "Message01Icon" - }, - "WalletIcon": { - "lucide": "WalletIcon", - "remix": "RiWalletLine", - "tabler": "IconWallet", - "hugeicons": "Wallet01Icon" - }, - "Building2Icon": { - "lucide": "Building2Icon", - "remix": "RiBankLine", - "tabler": "IconBuildingBank", - "hugeicons": "BankIcon" - }, - "BadgeCheckIcon": { - "lucide": "BadgeCheckIcon", - "remix": "RiVerifiedBadgeLine", - "tabler": "IconRosetteDiscountCheck", - "hugeicons": "CheckmarkBadge01Icon" - }, - "ChevronsUpDownIcon": { - "lucide": "ChevronsUpDownIcon", - "remix": "RiExpandUpDownLine", - "tabler": "IconSelector", - "hugeicons": "UnfoldMoreIcon" - }, - "CircleDashedIcon": { - "lucide": "CircleDashedIcon", - "remix": "RiLoader3Line", - "tabler": "IconCircleDashed", - "hugeicons": "Loading01Icon" - }, - "EyeOffIcon": { - "lucide": "EyeOffIcon", - "remix": "RiEyeOffLine", - "tabler": "IconEyeClosed", - "hugeicons": "ViewOffIcon" - }, - "MicIcon": { - "lucide": "MicIcon", - "remix": "RiMicLine", - "tabler": "IconMicrophone", - "hugeicons": "VoiceIcon" - }, - "RadioIcon": { - "lucide": "RadioIcon", - "remix": "RiRadioButtonLine", - "tabler": "IconPlayerRecordFilled", - "hugeicons": "RecordIcon" - }, - "ExternalLinkIcon": { - "lucide": "ExternalLinkIcon", - "remix": "RiExternalLinkLine", - "tabler": "IconExternalLink", - "hugeicons": "LinkSquare02Icon" - }, - "RefreshCwIcon": { - "lucide": "RefreshCwIcon", - "remix": "RiRefreshLine", - "tabler": "IconRefresh", - "hugeicons": "RefreshIcon" - }, - "BoldIcon": { - "lucide": "BoldIcon", - "remix": "RiBold", - "tabler": "IconBold", - "hugeicons": "TextBoldIcon" - }, - "ItalicIcon": { - "lucide": "ItalicIcon", - "remix": "RiItalic", - "tabler": "IconItalic", - "hugeicons": "TextItalicIcon" - }, - "UnderlineIcon": { - "lucide": "UnderlineIcon", - "remix": "RiUnderline", - "tabler": "IconUnderline", - "hugeicons": "TextUnderlineIcon" - }, - "TableIcon": { - "lucide": "TableIcon", - "remix": "RiTable2", - "tabler": "IconTable", - "hugeicons": "Table01Icon" - }, - "ChartLineIcon": { - "lucide": "ChartLineIcon", - "remix": "RiLineChartLine", - "tabler": "IconChartLine", - "hugeicons": "ChartLineData01Icon" - }, - "ChartBarIcon": { - "lucide": "ChartBarIcon", - "remix": "RiBarChartLine", - "tabler": "IconChartBar", - "hugeicons": "ChartColumnIcon" - }, - "ChartPieIcon": { - "lucide": "ChartPieIcon", - "remix": "RiPieChartLine", - "tabler": "IconChartPie", - "hugeicons": "PieChartIcon" - }, - "TerminalSquareIcon": { - "lucide": "TerminalSquareIcon", - "remix": "RiTerminalLine", - "tabler": "IconTerminal2", - "hugeicons": "SourceCodeSquareIcon" - }, - "BookOpen": { - "lucide": "BookOpen", - "remix": "RiBookOpenLine", - "tabler": "IconBook", - "hugeicons": "BookOpen02Icon" - }, - "Settings2Icon": { - "lucide": "Settings2Icon", - "remix": "RiSettings4Line", - "tabler": "IconSettings", - "hugeicons": "Settings05Icon" - }, - "FrameIcon": { - "lucide": "FrameIcon", - "remix": "RiCropLine", - "tabler": "IconFrame", - "hugeicons": "CropIcon" - }, - "PieChartIcon": { - "lucide": "PieChartIcon", - "remix": "RiPieChartLine", - "tabler": "IconChartPie", - "hugeicons": "PieChartIcon" - }, - "MapIcon": { - "lucide": "MapIcon", - "remix": "RiMapLine", - "tabler": "IconMap", - "hugeicons": "MapsIcon" - }, - "ShoppingCartIcon": { - "lucide": "ShoppingCartIcon", - "remix": "RiShoppingCartLine", - "tabler": "IconShoppingCart", - "hugeicons": "ShoppingCart01Icon" - }, - "LifeBuoy": { - "lucide": "LifeBuoy", - "remix": "RiLifebuoyLine", - "tabler": "IconLifebuoy", - "hugeicons": "ChartRingIcon" - }, - "Send": { - "lucide": "Send", - "remix": "RiSendPlaneLine", - "tabler": "IconSend", - "hugeicons": "SentIcon" - }, - "AppWindowIcon": { - "lucide": "AppWindowIcon", - "remix": "RiWindowLine", - "tabler": "IconAppWindow", - "hugeicons": "CursorInWindowIcon" - }, - "BookmarkIcon": { - "lucide": "BookmarkIcon", - "remix": "RiBookmarkLine", - "tabler": "IconBookmark", - "hugeicons": "Bookmark01Icon" - }, - "ChevronUpIcon": { - "lucide": "ChevronUpIcon", - "remix": "RiArrowUpSLine", - "tabler": "IconChevronUp", - "hugeicons": "ArrowUp01Icon" - }, - "ChevronLeftIcon": { - "lucide": "ChevronLeftIcon", - "remix": "RiArrowLeftSLine", - "tabler": "IconChevronLeft", - "hugeicons": "ArrowLeft01Icon" - }, - "TriangleAlertIcon": { - "lucide": "TriangleAlertIcon", - "remix": "RiAlertLine", - "tabler": "IconAlertTriangle", - "hugeicons": "Alert02Icon" - }, - "OctagonXIcon": { - "lucide": "OctagonXIcon", - "remix": "RiCloseCircleLine", - "tabler": "IconAlertOctagon", - "hugeicons": "MultiplicationSignCircleIcon" - }, - "Loader2Icon": { - "lucide": "Loader2Icon", - "remix": "RiLoader4Line", - "tabler": "IconLoader", - "hugeicons": "Loading03Icon" - }, - "VolumeOffIcon": { - "lucide": "VolumeOffIcon", - "remix": "RiVolumeMuteLine", - "tabler": "IconVolume", - "hugeicons": "VolumeOffIcon" - }, - "AlertCircleIcon": { - "lucide": "AlertCircleIcon", - "remix": "RiAlertLine", - "tabler": "IconAlertCircle", - "hugeicons": "Alert01Icon" - }, - "User2Icon": { - "lucide": "User2Icon", - "remix": "RiUserLine", - "tabler": "IconUser", - "hugeicons": "UserIcon" - }, - "ArrowRightCircleIcon": { - "lucide": "ArrowRightCircleIcon", - "remix": "RiArrowRightCircleLine", - "tabler": "IconCircleArrowRight", - "hugeicons": "CircleArrowRight02Icon" - }, - "LogInIcon": { - "lucide": "LogInIcon", - "remix": "RiLoginBoxLine", - "tabler": "IconLogin", - "hugeicons": "Login01Icon" - }, - "PenSquareIcon": { - "lucide": "PenSquareIcon", - "remix": "RiEditLine", - "tabler": "IconEdit", - "hugeicons": "Edit02Icon" - }, - "CameraIcon": { - "lucide": "CameraIcon", - "remix": "RiCameraLine", - "tabler": "IconCamera", - "hugeicons": "Camera01Icon" - }, - "PlusSquareIcon": { - "lucide": "PlusSquareIcon", - "remix": "RiAddBoxLine", - "tabler": "IconSquarePlus", - "hugeicons": "PlusSignSquareIcon" - }, - "SquarePenIcon": { - "lucide": "SquarePenIcon", - "remix": "RiEdit2Line", - "tabler": "IconEdit", - "hugeicons": "Edit02Icon" - }, - "Volume1Icon": { - "lucide": "Volume1Icon", - "remix": "RiVolumeDownLine", - "tabler": "IconVolume2", - "hugeicons": "VolumeLowIcon" - }, - "Volume2Icon": { - "lucide": "Volume2Icon", - "remix": "RiVolumeUpLine", - "tabler": "IconVolume", - "hugeicons": "VolumeHighIcon" - }, - "XCircleIcon": { - "lucide": "XCircleIcon", - "remix": "RiCloseCircleLine", - "tabler": "IconCircleX", - "hugeicons": "Cancel01Icon" - }, - "TimerIcon": { - "lucide": "TimerIcon", - "remix": "RiTimerLine", - "tabler": "IconAlarm", - "hugeicons": "Time01Icon" - }, - "PinIcon": { - "lucide": "PinIcon", - "remix": "RiPushpinLine", - "tabler": "IconPinned", - "hugeicons": "PinIcon" - } + PlusIcon: { + lucide: "PlusIcon", + remix: "RiAddLine", + tabler: "IconPlus", + hugeicons: "PlusSignIcon", + }, + PaperclipIcon: { + lucide: "PaperclipIcon", + remix: "RiAttachmentLine", + tabler: "IconPaperclip", + hugeicons: "AttachmentIcon", + }, + SparklesIcon: { + lucide: "SparklesIcon", + remix: "RiSparklingLine", + tabler: "IconSparkles", + hugeicons: "SparklesIcon", + }, + ShoppingBagIcon: { + lucide: "ShoppingBagIcon", + remix: "RiShoppingBagLine", + tabler: "IconShoppingBag", + hugeicons: "ShoppingBag01Icon", + }, + WandIcon: { + lucide: "WandIcon", + remix: "RiMagicLine", + tabler: "IconWand", + hugeicons: "MagicWand01Icon", + }, + MousePointerIcon: { + lucide: "MousePointerIcon", + remix: "RiCursorLine", + tabler: "IconPointer", + hugeicons: "Cursor01Icon", + }, + MoreHorizontalIcon: { + lucide: "MoreHorizontalIcon", + remix: "RiMoreLine", + tabler: "IconDots", + hugeicons: "MoreHorizontalCircle01Icon", + }, + ShareIcon: { + lucide: "ShareIcon", + remix: "RiShareLine", + tabler: "IconShare", + hugeicons: "Share03Icon", + }, + BookOpenIcon: { + lucide: "BookOpenIcon", + remix: "RiBookOpenLine", + tabler: "IconBook", + hugeicons: "BookOpen01Icon", + }, + GlobeIcon: { + lucide: "GlobeIcon", + remix: "RiGlobalLine", + tabler: "IconWorld", + hugeicons: "GlobalIcon", + }, + PenToolIcon: { + lucide: "PenToolIcon", + remix: "RiPenNibLine", + tabler: "IconPencil", + hugeicons: "QuillWrite01Icon", + }, + AudioLinesIcon: { + lucide: "AudioLinesIcon", + remix: "RiSoundModuleLine", + tabler: "IconMicrophone", + hugeicons: "Mic01Icon", + }, + ArrowUpIcon: { + lucide: "ArrowUpIcon", + remix: "RiArrowUpLine", + tabler: "IconArrowUp", + hugeicons: "ArrowUp01Icon", + }, + ChevronDownIcon: { + lucide: "ChevronDownIcon", + remix: "RiArrowDownSLine", + tabler: "IconChevronDown", + hugeicons: "ArrowDown01Icon", + }, + SettingsIcon: { + lucide: "SettingsIcon", + remix: "RiSettings3Line", + tabler: "IconSettings", + hugeicons: "Settings01Icon", + }, + FolderIcon: { + lucide: "FolderIcon", + remix: "RiFolderLine", + tabler: "IconFolder", + hugeicons: "Folder01Icon", + }, + CircleCheckIcon: { + lucide: "CircleCheckIcon", + remix: "RiCheckboxCircleLine", + tabler: "IconCircleCheck", + hugeicons: "CheckmarkCircle02Icon", + }, + LightbulbIcon: { + lucide: "LightbulbIcon", + remix: "RiLightbulbLine", + tabler: "IconBulb", + hugeicons: "BulbIcon", + }, + ContainerIcon: { + lucide: "ContainerIcon", + remix: "RiBox3Line", + tabler: "IconBox", + hugeicons: "CubeIcon", + }, + ZapIcon: { + lucide: "ZapIcon", + remix: "RiFlashlightLine", + tabler: "IconBolt", + hugeicons: "ZapIcon", + }, + ServerIcon: { + lucide: "ServerIcon", + remix: "RiServerLine", + tabler: "IconServer", + hugeicons: "DatabaseIcon", + }, + InfoIcon: { + lucide: "InfoIcon", + remix: "RiInformationLine", + tabler: "IconInfoCircle", + hugeicons: "InformationCircleIcon", + }, + TerminalIcon: { + lucide: "TerminalIcon", + remix: "RiTerminalBoxLine", + tabler: "IconTerminal", + hugeicons: "SourceCodeIcon", + }, + CopyIcon: { + lucide: "CopyIcon", + remix: "RiFileCopyLine", + tabler: "IconCopy", + hugeicons: "Copy01Icon", + }, + MonitorIcon: { + lucide: "MonitorIcon", + remix: "RiComputerLine", + tabler: "IconDeviceDesktop", + hugeicons: "ComputerIcon", + }, + DownloadIcon: { + lucide: "DownloadIcon", + remix: "RiDownloadLine", + tabler: "IconDownload", + hugeicons: "Download01Icon", + }, + SearchIcon: { + lucide: "SearchIcon", + remix: "RiSearchLine", + tabler: "IconSearch", + hugeicons: "Search01Icon", + }, + UploadIcon: { + lucide: "UploadIcon", + remix: "RiUpload2Line", + tabler: "IconUpload", + hugeicons: "Upload01Icon", + }, + CloudCogIcon: { + lucide: "CloudCogIcon", + remix: "RiCloudLine", + tabler: "IconCloudCog", + hugeicons: "AiCloud01Icon", + }, + GitBranchIcon: { + lucide: "GitBranchIcon", + remix: "RiGitBranchLine", + tabler: "IconGitBranch", + hugeicons: "GitBranchIcon", + }, + BotIcon: { + lucide: "BotIcon", + remix: "RiRobotLine", + tabler: "IconRobot", + hugeicons: "RoboticIcon", + }, + SendIcon: { + lucide: "SendIcon", + remix: "RiSendPlaneLine", + tabler: "IconSend", + hugeicons: "SentIcon", + }, + MenuIcon: { + lucide: "MenuIcon", + remix: "RiMenuLine", + tabler: "IconMenu", + hugeicons: "Menu09Icon", + }, + XIcon: { + lucide: "XIcon", + remix: "RiCloseLine", + tabler: "IconX", + hugeicons: "Cancel01Icon", + }, + HomeIcon: { + lucide: "HomeIcon", + remix: "RiHomeLine", + tabler: "IconHome", + hugeicons: "Home01Icon", + }, + CircleIcon: { + lucide: "CircleIcon", + remix: "RiCircleLine", + tabler: "IconCircle", + hugeicons: "CircleIcon", + }, + LayoutGridIcon: { + lucide: "LayoutGridIcon", + remix: "RiLayoutGridLine", + tabler: "IconLayoutGrid", + hugeicons: "GridIcon", + }, + MailIcon: { + lucide: "MailIcon", + remix: "RiMailLine", + tabler: "IconMail", + hugeicons: "Mail01Icon", + }, + LinkIcon: { + lucide: "LinkIcon", + remix: "RiLinkM", + tabler: "IconLink", + hugeicons: "Link01Icon", + }, + SmileIcon: { + lucide: "SmileIcon", + remix: "RiEmotionLine", + tabler: "IconMoodSmile", + hugeicons: "SmileIcon", + }, + CircleAlertIcon: { + lucide: "CircleAlertIcon", + remix: "RiErrorWarningLine", + tabler: "IconExclamationCircle", + hugeicons: "Alert01Icon", + }, + UserIcon: { + lucide: "UserIcon", + remix: "RiUserLine", + tabler: "IconUser", + hugeicons: "UserIcon", + }, + StarIcon: { + lucide: "StarIcon", + remix: "RiStarLine", + tabler: "IconStar", + hugeicons: "StarIcon", + }, + CodeIcon: { + lucide: "CodeIcon", + remix: "RiCodeLine", + tabler: "IconCode", + hugeicons: "CodeIcon", + }, + HeartIcon: { + lucide: "HeartIcon", + remix: "RiHeartLine", + tabler: "IconHeart", + hugeicons: "FavouriteIcon", + }, + LogOutIcon: { + lucide: "LogOutIcon", + remix: "RiLogoutBoxLine", + tabler: "IconLogout", + hugeicons: "Logout01Icon", + }, + MinusIcon: { + lucide: "MinusIcon", + remix: "RiSubtractLine", + tabler: "IconMinus", + hugeicons: "MinusSignIcon", + }, + ArrowLeftIcon: { + lucide: "ArrowLeftIcon", + remix: "RiArrowLeftLine", + tabler: "IconArrowLeft", + hugeicons: "ArrowLeft01Icon", + }, + MailCheckIcon: { + lucide: "MailCheckIcon", + remix: "RiMailCheckLine", + tabler: "IconMailCheck", + hugeicons: "MailValidation01Icon", + }, + ArchiveIcon: { + lucide: "ArchiveIcon", + remix: "RiArchiveLine", + tabler: "IconArchive", + hugeicons: "Archive02Icon", + }, + ClockIcon: { + lucide: "ClockIcon", + remix: "RiTimeLine", + tabler: "IconClock", + hugeicons: "Clock01Icon", + }, + CalendarPlusIcon: { + lucide: "CalendarPlusIcon", + remix: "RiCalendarEventLine", + tabler: "IconCalendarPlus", + hugeicons: "CalendarAdd01Icon", + }, + ListFilterIcon: { + lucide: "ListFilterIcon", + remix: "RiFilterLine", + tabler: "IconFilterPlus", + hugeicons: "FilterIcon", + }, + TagIcon: { + lucide: "TagIcon", + remix: "RiPriceTag3Line", + tabler: "IconTag", + hugeicons: "Tag01Icon", + }, + Trash2Icon: { + lucide: "Trash2Icon", + remix: "RiDeleteBin6Line", + tabler: "IconTrash", + hugeicons: "Delete02Icon", + }, + ArrowRightIcon: { + lucide: "ArrowRightIcon", + remix: "RiArrowRightLine", + tabler: "IconArrowRight", + hugeicons: "ArrowRight02Icon", + }, + VolumeX: { + lucide: "VolumeX", + remix: "RiVolumeMuteLine", + tabler: "IconVolume", + hugeicons: "VolumeOffIcon", + }, + CheckIcon: { + lucide: "CheckIcon", + remix: "RiCheckLine", + tabler: "IconCheck", + hugeicons: "Tick02Icon", + }, + UserRoundXIcon: { + lucide: "UserRoundXIcon", + remix: "RiUserUnfollowLine", + tabler: "IconUserX", + hugeicons: "UserRemove01Icon", + }, + AlertTriangleIcon: { + lucide: "AlertTriangleIcon", + remix: "RiAlertLine", + tabler: "IconAlertTriangle", + hugeicons: "Alert02Icon", + }, + TrashIcon: { + lucide: "TrashIcon", + remix: "RiDeleteBinLine", + tabler: "IconTrash", + hugeicons: "Delete01Icon", + }, + BluetoothIcon: { + lucide: "BluetoothIcon", + remix: "RiBluetoothLine", + tabler: "IconBluetooth", + hugeicons: "BluetoothIcon", + }, + MoreVerticalIcon: { + lucide: "MoreVerticalIcon", + remix: "RiMore2Line", + tabler: "IconDotsVertical", + hugeicons: "MoreVerticalCircle01Icon", + }, + FileIcon: { + lucide: "FileIcon", + remix: "RiFileLine", + tabler: "IconFile", + hugeicons: "File01Icon", + }, + FolderOpenIcon: { + lucide: "FolderOpenIcon", + remix: "RiFolderOpenLine", + tabler: "IconFolderOpen", + hugeicons: "FolderOpenIcon", + }, + FileCodeIcon: { + lucide: "FileCodeIcon", + remix: "RiFileCodeLine", + tabler: "IconFileCode", + hugeicons: "CodeIcon", + }, + FolderSearchIcon: { + lucide: "FolderSearchIcon", + remix: "RiFileSearchLine", + tabler: "IconFolderSearch", + hugeicons: "Search01Icon", + }, + SaveIcon: { + lucide: "SaveIcon", + remix: "RiSaveLine", + tabler: "IconDeviceFloppy", + hugeicons: "FloppyDiskIcon", + }, + EyeIcon: { + lucide: "EyeIcon", + remix: "RiEyeLine", + tabler: "IconEye", + hugeicons: "EyeIcon", + }, + LayoutIcon: { + lucide: "LayoutIcon", + remix: "RiLayoutLine", + tabler: "IconLayout", + hugeicons: "Layout01Icon", + }, + PaletteIcon: { + lucide: "PaletteIcon", + remix: "RiPaletteLine", + tabler: "IconPalette", + hugeicons: "PaintBoardIcon", + }, + SunIcon: { + lucide: "SunIcon", + remix: "RiSunLine", + tabler: "IconSun", + hugeicons: "Sun01Icon", + }, + MoonIcon: { + lucide: "MoonIcon", + remix: "RiMoonLine", + tabler: "IconMoon", + hugeicons: "MoonIcon", + }, + HelpCircleIcon: { + lucide: "HelpCircleIcon", + remix: "RiQuestionLine", + tabler: "IconHelpCircle", + hugeicons: "HelpCircleIcon", + }, + FileTextIcon: { + lucide: "FileTextIcon", + remix: "RiFileTextLine", + tabler: "IconFileText", + hugeicons: "File01Icon", + }, + CalendarIcon: { + lucide: "CalendarIcon", + remix: "RiCalendarLine", + tabler: "IconCalendar", + hugeicons: "Calendar01Icon", + }, + Search: { + lucide: "Search", + remix: "RiSearchLine", + tabler: "IconSearch", + hugeicons: "Search01Icon", + }, + CheckCircle2Icon: { + lucide: "CheckCircle2Icon", + remix: "RiCheckboxCircleLine", + tabler: "IconCircleCheckFilled", + hugeicons: "CheckmarkCircle02Icon", + }, + CircleDollarSignIcon: { + lucide: "CircleDollarSignIcon", + remix: "RiMoneyDollarCircleLine", + tabler: "IconCoin", + hugeicons: "DollarCircleIcon", + }, + ArrowUpRightIcon: { + lucide: "ArrowUpRightIcon", + remix: "RiArrowRightUpLine", + tabler: "IconArrowUpRight", + hugeicons: "ArrowUpRight01Icon", + }, + BadgeCheck: { + lucide: "BadgeCheck", + remix: "RiVerifiedBadgeLine", + tabler: "IconRosetteDiscountCheck", + hugeicons: "CheckmarkBadge02Icon", + }, + ArrowLeftCircleIcon: { + lucide: "ArrowLeftCircleIcon", + remix: "RiArrowLeftCircleLine", + tabler: "IconCircleArrowLeft", + hugeicons: "CircleArrowLeft02Icon", + }, + FlipHorizontalIcon: { + lucide: "FlipHorizontalIcon", + remix: "RiFlipHorizontalLine", + tabler: "IconFlipHorizontal", + hugeicons: "FlipHorizontalIcon", + }, + FlipVerticalIcon: { + lucide: "FlipVerticalIcon", + remix: "RiFlipVerticalLine", + tabler: "IconFlipVertical", + hugeicons: "FlipVerticalIcon", + }, + RotateCwIcon: { + lucide: "RotateCwIcon", + remix: "RiRestartLine", + tabler: "IconRotateClockwise2", + hugeicons: "Rotate01Icon", + }, + Clock2Icon: { + lucide: "Clock2Icon", + remix: "RiTimeLine", + tabler: "IconClockHour2", + hugeicons: "Clock03Icon", + }, + CaptionsIcon: { + lucide: "CaptionsIcon", + remix: "RiClosedCaptioningLine", + tabler: "IconTextCaption", + hugeicons: "ClosedCaptionIcon", + }, + TrendingUpIcon: { + lucide: "TrendingUpIcon", + remix: "RiArrowRightUpLine", + tabler: "IconTrendingUp", + hugeicons: "Analytics01Icon", + }, + ChevronRightIcon: { + lucide: "ChevronRightIcon", + remix: "RiArrowRightSLine", + tabler: "IconChevronRight", + hugeicons: "ArrowRight01Icon", + }, + MinimizeIcon: { + lucide: "MinimizeIcon", + remix: "RiContractLeftRightLine", + tabler: "IconMinimize", + hugeicons: "MinusSignIcon", + }, + MaximizeIcon: { + lucide: "MaximizeIcon", + remix: "RiExpandLeftRightLine", + tabler: "IconMaximize", + hugeicons: "PlusSignIcon", + }, + CreditCardIcon: { + lucide: "CreditCardIcon", + remix: "RiBankCardLine", + tabler: "IconCreditCard", + hugeicons: "CreditCardIcon", + }, + CalculatorIcon: { + lucide: "CalculatorIcon", + remix: "RiCalculatorLine", + tabler: "IconCalculator", + hugeicons: "CalculatorIcon", + }, + InboxIcon: { + lucide: "InboxIcon", + remix: "RiInboxLine", + tabler: "IconArchive", + hugeicons: "Archive02Icon", + }, + FolderPlusIcon: { + lucide: "FolderPlusIcon", + remix: "RiFolderAddLine", + tabler: "IconFolderPlus", + hugeicons: "FolderAddIcon", + }, + ScissorsIcon: { + lucide: "ScissorsIcon", + remix: "RiScissorsLine", + tabler: "IconCut", + hugeicons: "ScissorIcon", + }, + ClipboardPasteIcon: { + lucide: "ClipboardPasteIcon", + remix: "RiClipboardLine", + tabler: "IconClipboard", + hugeicons: "ClipboardIcon", + }, + ListIcon: { + lucide: "ListIcon", + remix: "RiListUnordered", + tabler: "IconList", + hugeicons: "Menu05Icon", + }, + ZoomInIcon: { + lucide: "ZoomInIcon", + remix: "RiZoomInLine", + tabler: "IconZoomIn", + hugeicons: "ZoomInAreaIcon", + }, + ZoomOutIcon: { + lucide: "ZoomOutIcon", + remix: "RiZoomOutLine", + tabler: "IconZoomOut", + hugeicons: "ZoomOutAreaIcon", + }, + BellIcon: { + lucide: "BellIcon", + remix: "RiNotification3Line", + tabler: "IconBell", + hugeicons: "Notification01Icon", + }, + ImageIcon: { + lucide: "ImageIcon", + remix: "RiImageLine", + tabler: "IconPhoto", + hugeicons: "Image01Icon", + }, + KeyboardIcon: { + lucide: "KeyboardIcon", + remix: "RiKeyboardLine", + tabler: "IconKeyboard", + hugeicons: "KeyboardIcon", + }, + LanguagesIcon: { + lucide: "LanguagesIcon", + remix: "RiTranslate", + tabler: "IconLanguage", + hugeicons: "LanguageCircleIcon", + }, + ShieldIcon: { + lucide: "ShieldIcon", + remix: "RiShieldLine", + tabler: "IconShield", + hugeicons: "SecurityIcon", + }, + PencilIcon: { + lucide: "PencilIcon", + remix: "RiPencilLine", + tabler: "IconPencil", + hugeicons: "Edit01Icon", + }, + ActivityIcon: { + lucide: "ActivityIcon", + remix: "RiPulseLine", + tabler: "IconActivity", + hugeicons: "Cardiogram01Icon", + }, + PanelLeftIcon: { + lucide: "PanelLeftIcon", + remix: "RiLayoutLeftLine", + tabler: "IconLayoutSidebar", + hugeicons: "LayoutLeftIcon", + }, + ArrowDownIcon: { + lucide: "ArrowDownIcon", + remix: "RiArrowDownLine", + tabler: "IconArrowDown", + hugeicons: "ArrowDown01Icon", + }, + MessageSquareIcon: { + lucide: "MessageSquareIcon", + remix: "RiChat1Line", + tabler: "IconMessage", + hugeicons: "Message01Icon", + }, + WalletIcon: { + lucide: "WalletIcon", + remix: "RiWalletLine", + tabler: "IconWallet", + hugeicons: "Wallet01Icon", + }, + Building2Icon: { + lucide: "Building2Icon", + remix: "RiBankLine", + tabler: "IconBuildingBank", + hugeicons: "BankIcon", + }, + BadgeCheckIcon: { + lucide: "BadgeCheckIcon", + remix: "RiVerifiedBadgeLine", + tabler: "IconRosetteDiscountCheck", + hugeicons: "CheckmarkBadge01Icon", + }, + ChevronsUpDownIcon: { + lucide: "ChevronsUpDownIcon", + remix: "RiExpandUpDownLine", + tabler: "IconSelector", + hugeicons: "UnfoldMoreIcon", + }, + CircleDashedIcon: { + lucide: "CircleDashedIcon", + remix: "RiLoader3Line", + tabler: "IconCircleDashed", + hugeicons: "Loading01Icon", + }, + EyeOffIcon: { + lucide: "EyeOffIcon", + remix: "RiEyeOffLine", + tabler: "IconEyeClosed", + hugeicons: "ViewOffIcon", + }, + MicIcon: { + lucide: "MicIcon", + remix: "RiMicLine", + tabler: "IconMicrophone", + hugeicons: "VoiceIcon", + }, + RadioIcon: { + lucide: "RadioIcon", + remix: "RiRadioButtonLine", + tabler: "IconPlayerRecordFilled", + hugeicons: "RecordIcon", + }, + ExternalLinkIcon: { + lucide: "ExternalLinkIcon", + remix: "RiExternalLinkLine", + tabler: "IconExternalLink", + hugeicons: "LinkSquare02Icon", + }, + RefreshCwIcon: { + lucide: "RefreshCwIcon", + remix: "RiRefreshLine", + tabler: "IconRefresh", + hugeicons: "RefreshIcon", + }, + BoldIcon: { + lucide: "BoldIcon", + remix: "RiBold", + tabler: "IconBold", + hugeicons: "TextBoldIcon", + }, + ItalicIcon: { + lucide: "ItalicIcon", + remix: "RiItalic", + tabler: "IconItalic", + hugeicons: "TextItalicIcon", + }, + UnderlineIcon: { + lucide: "UnderlineIcon", + remix: "RiUnderline", + tabler: "IconUnderline", + hugeicons: "TextUnderlineIcon", + }, + TableIcon: { + lucide: "TableIcon", + remix: "RiTable2", + tabler: "IconTable", + hugeicons: "Table01Icon", + }, + ChartLineIcon: { + lucide: "ChartLineIcon", + remix: "RiLineChartLine", + tabler: "IconChartLine", + hugeicons: "ChartLineData01Icon", + }, + ChartBarIcon: { + lucide: "ChartBarIcon", + remix: "RiBarChartLine", + tabler: "IconChartBar", + hugeicons: "ChartColumnIcon", + }, + ChartPieIcon: { + lucide: "ChartPieIcon", + remix: "RiPieChartLine", + tabler: "IconChartPie", + hugeicons: "PieChartIcon", + }, + TerminalSquareIcon: { + lucide: "TerminalSquareIcon", + remix: "RiTerminalLine", + tabler: "IconTerminal2", + hugeicons: "SourceCodeSquareIcon", + }, + BookOpen: { + lucide: "BookOpen", + remix: "RiBookOpenLine", + tabler: "IconBook", + hugeicons: "BookOpen02Icon", + }, + Settings2Icon: { + lucide: "Settings2Icon", + remix: "RiSettings4Line", + tabler: "IconSettings", + hugeicons: "Settings05Icon", + }, + FrameIcon: { + lucide: "FrameIcon", + remix: "RiCropLine", + tabler: "IconFrame", + hugeicons: "CropIcon", + }, + PieChartIcon: { + lucide: "PieChartIcon", + remix: "RiPieChartLine", + tabler: "IconChartPie", + hugeicons: "PieChartIcon", + }, + MapIcon: { + lucide: "MapIcon", + remix: "RiMapLine", + tabler: "IconMap", + hugeicons: "MapsIcon", + }, + ShoppingCartIcon: { + lucide: "ShoppingCartIcon", + remix: "RiShoppingCartLine", + tabler: "IconShoppingCart", + hugeicons: "ShoppingCart01Icon", + }, + LifeBuoy: { + lucide: "LifeBuoy", + remix: "RiLifebuoyLine", + tabler: "IconLifebuoy", + hugeicons: "ChartRingIcon", + }, + Send: { + lucide: "Send", + remix: "RiSendPlaneLine", + tabler: "IconSend", + hugeicons: "SentIcon", + }, + AppWindowIcon: { + lucide: "AppWindowIcon", + remix: "RiWindowLine", + tabler: "IconAppWindow", + hugeicons: "CursorInWindowIcon", + }, + BookmarkIcon: { + lucide: "BookmarkIcon", + remix: "RiBookmarkLine", + tabler: "IconBookmark", + hugeicons: "Bookmark01Icon", + }, + ChevronUpIcon: { + lucide: "ChevronUpIcon", + remix: "RiArrowUpSLine", + tabler: "IconChevronUp", + hugeicons: "ArrowUp01Icon", + }, + ChevronLeftIcon: { + lucide: "ChevronLeftIcon", + remix: "RiArrowLeftSLine", + tabler: "IconChevronLeft", + hugeicons: "ArrowLeft01Icon", + }, + TriangleAlertIcon: { + lucide: "TriangleAlertIcon", + remix: "RiAlertLine", + tabler: "IconAlertTriangle", + hugeicons: "Alert02Icon", + }, + OctagonXIcon: { + lucide: "OctagonXIcon", + remix: "RiCloseCircleLine", + tabler: "IconAlertOctagon", + hugeicons: "MultiplicationSignCircleIcon", + }, + Loader2Icon: { + lucide: "Loader2Icon", + remix: "RiLoader4Line", + tabler: "IconLoader", + hugeicons: "Loading03Icon", + }, + VolumeOffIcon: { + lucide: "VolumeOffIcon", + remix: "RiVolumeMuteLine", + tabler: "IconVolume", + hugeicons: "VolumeOffIcon", + }, + AlertCircleIcon: { + lucide: "AlertCircleIcon", + remix: "RiAlertLine", + tabler: "IconAlertCircle", + hugeicons: "Alert01Icon", + }, + User2Icon: { + lucide: "User2Icon", + remix: "RiUserLine", + tabler: "IconUser", + hugeicons: "UserIcon", + }, + ArrowRightCircleIcon: { + lucide: "ArrowRightCircleIcon", + remix: "RiArrowRightCircleLine", + tabler: "IconCircleArrowRight", + hugeicons: "CircleArrowRight02Icon", + }, + LogInIcon: { + lucide: "LogInIcon", + remix: "RiLoginBoxLine", + tabler: "IconLogin", + hugeicons: "Login01Icon", + }, + PenSquareIcon: { + lucide: "PenSquareIcon", + remix: "RiEditLine", + tabler: "IconEdit", + hugeicons: "Edit02Icon", + }, + CameraIcon: { + lucide: "CameraIcon", + remix: "RiCameraLine", + tabler: "IconCamera", + hugeicons: "Camera01Icon", + }, + PlusSquareIcon: { + lucide: "PlusSquareIcon", + remix: "RiAddBoxLine", + tabler: "IconSquarePlus", + hugeicons: "PlusSignSquareIcon", + }, + SquarePenIcon: { + lucide: "SquarePenIcon", + remix: "RiEdit2Line", + tabler: "IconEdit", + hugeicons: "Edit02Icon", + }, + Volume1Icon: { + lucide: "Volume1Icon", + remix: "RiVolumeDownLine", + tabler: "IconVolume2", + hugeicons: "VolumeLowIcon", + }, + Volume2Icon: { + lucide: "Volume2Icon", + remix: "RiVolumeUpLine", + tabler: "IconVolume", + hugeicons: "VolumeHighIcon", + }, + XCircleIcon: { + lucide: "XCircleIcon", + remix: "RiCloseCircleLine", + tabler: "IconCircleX", + hugeicons: "Cancel01Icon", + }, + TimerIcon: { + lucide: "TimerIcon", + remix: "RiTimerLine", + tabler: "IconAlarm", + hugeicons: "Time01Icon", + }, + PinIcon: { + lucide: "PinIcon", + remix: "RiPushpinLine", + tabler: "IconPinned", + hugeicons: "PinIcon", + }, } as const; diff --git a/packages/core/src/__registry__/index.ts b/packages/core/src/__registry__/index.ts index 3b8d8ccfa..d5c901eb0 100644 --- a/packages/core/src/__registry__/index.ts +++ b/packages/core/src/__registry__/index.ts @@ -13,6 +13,6 @@ export const registry = [...base, ...ui, ...lib, ...hooks]; export { base } from "./base"; export { hooks } from "./hooks"; +export { iconLibraries, icons } from "./icons"; export { lib } from "./lib"; export { ui } from "./ui"; -export { icons, iconLibraries } from "./icons"; diff --git a/packages/core/src/__registry__/lib.ts b/packages/core/src/__registry__/lib.ts index 527e5afac..ef864e2b3 100644 --- a/packages/core/src/__registry__/lib.ts +++ b/packages/core/src/__registry__/lib.ts @@ -2,53 +2,53 @@ // Run "pnpm build" to regenerate export const lib = [ - { - "name": "utils", - "type": "registry:lib", - "files": [ - { - "type": "registry:lib", - "path": "lib/utils/index.ts", - "target": "lib/utils.ts", - "content": `import { clsx } from "clsx"; + { + name: "utils", + type: "registry:lib", + files: [ + { + type: "registry:lib", + path: "lib/utils/index.ts", + target: "lib/utils.ts", + content: `import { clsx } from "clsx"; import { twMerge } from "tailwind-merge"; import type { ClassValue } from "clsx"; export function cn(...inputs: ClassValue[]) { - return twMerge(clsx(inputs)); + return twMerge(clsx(inputs)); } -` - } - ] - }, - { - "name": "focus-styles", - "type": "registry:lib", - "defaultVariant": "basic", - "variants": { - "basic": { - "files": [ - { - "type": "registry:lib", - "path": "lib/focus-styles/basic.ts", - "target": "lib/focus-styles.ts", - "content": `import { tv } from "tailwind-variants"; +`, + }, + ], + }, + { + name: "focus-styles", + type: "registry:lib", + defaultVariant: "basic", + variants: { + basic: { + files: [ + { + type: "registry:lib", + path: "lib/focus-styles/basic.ts", + target: "lib/focus-styles.ts", + content: `import { tv } from "tailwind-variants"; export const focusRing = tv({ - base: "outline-hidden ring-0 ring-border-focus focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-offset-bg", + base: "outline-hidden ring-0 ring-border-focus focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-offset-bg", }); export const focusInput = tv({ - base: "ring-0 focus-within:ring-2 focus-within:ring-border-focus", + base: "ring-0 focus-within:ring-2 focus-within:ring-border-focus", }); export const focusRingGroup = tv({ - base: "outline-hidden ring-0 ring-border-focus group-focus-visible:ring-2 group-focus-visible:ring-offset-2 group-focus-visible:ring-offset-bg", + base: "outline-hidden ring-0 ring-border-focus group-focus-visible:ring-2 group-focus-visible:ring-offset-2 group-focus-visible:ring-offset-bg", }); -` - } - ] - } - } - } +`, + }, + ], + }, + }, + }, ] as const; diff --git a/packages/core/src/__registry__/ui.ts b/packages/core/src/__registry__/ui.ts index c45703bb2..f4c639c10 100644 --- a/packages/core/src/__registry__/ui.ts +++ b/packages/core/src/__registry__/ui.ts @@ -2,115 +2,99 @@ // Run "pnpm build" to regenerate export const ui = [ - { - "name": "accordion", - "type": "registry:ui", - "defaultVariant": "basic", - "variants": { - "basic": { - "files": [ - { - "type": "registry:ui", - "path": "ui/accordion/basic.tsx", - "target": "ui/accordion.tsx", - "content": `"use client"; - -import { - DisclosureGroup as AriaDisclosureGroup, - composeRenderProps, -} from "react-aria-components"; + { + name: "accordion", + type: "registry:ui", + defaultVariant: "basic", + variants: { + basic: { + files: [ + { + type: "registry:ui", + path: "ui/accordion/basic.tsx", + target: "ui/accordion.tsx", + content: `"use client"; + +import { DisclosureGroup as AriaDisclosureGroup, composeRenderProps } from "react-aria-components"; import { tv } from "tailwind-variants"; const accordionStyles = tv({ - base: "**:data-disclosure:not-last:border-b", + base: "**:data-disclosure:not-last:border-b", }); -interface AccordionProps - extends React.ComponentProps {} +interface AccordionProps extends React.ComponentProps {} function Accordion({ className, ...props }: AccordionProps) { - return ( - - accordionStyles({ className: c }), - )} - {...props} - /> - ); + return ( + accordionStyles({ className: c }))} + {...props} + /> + ); } export { Accordion }; export type { AccordionProps }; -` - } - ] - } - } - }, - { - "name": "alert", - "type": "registry:ui", - "defaultVariant": "basic", - "variants": { - "basic": { - "files": [ - { - "type": "registry:ui", - "path": "ui/alert/basic.tsx", - "target": "ui/alert.tsx", - "content": `import { tv } from "tailwind-variants"; +`, + }, + ], + }, + }, + }, + { + name: "alert", + type: "registry:ui", + defaultVariant: "basic", + variants: { + basic: { + files: [ + { + type: "registry:ui", + path: "ui/alert/basic.tsx", + target: "ui/alert.tsx", + content: `import { tv } from "tailwind-variants"; import type * as React from "react"; import type { VariantProps } from "tailwind-variants"; const alertVariants = tv({ - slots: { - base: "relative grid w-full grid-cols-[0_1fr] items-start gap-y-0.5 rounded-lg border bg-card px-4 py-3 text-sm has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] has-[>svg]:gap-x-3 [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current", - title: "col-start-2 line-clamp-1 min-h-4 font-medium tracking-tight", - description: - "col-start-2 grid justify-items-start gap-1 text-muted-foreground text-sm [&_p]:leading-relaxed", - }, - variants: { - variant: { - neutral: { - base: "text-fg", - }, - danger: { - base: "bg-danger-muted text-fg-danger *:data-[slot=alert-description]:text-fg-danger/90 [&>svg]:text-current", - }, - warning: { - base: "text-fg-warning *:data-[slot=alert-description]:text-fg-warning/90 [&>svg]:text-current", - }, - info: { - base: "text-fg-info *:data-[slot=alert-description]:text-fg-info/90 [&>svg]:text-current", - }, - success: { - base: "text-fg-success *:data-[slot=alert-description]:text-fg-success/90 [&>svg]:text-current", - }, - }, - }, - defaultVariants: { - variant: "neutral", - }, + slots: { + base: "relative grid w-full grid-cols-[0_1fr] items-start gap-y-0.5 rounded-lg border bg-card px-4 py-3 text-sm has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] has-[>svg]:gap-x-3 [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current", + title: "col-start-2 line-clamp-1 min-h-4 font-medium tracking-tight", + description: "col-start-2 grid justify-items-start gap-1 text-muted-foreground text-sm [&_p]:leading-relaxed", + }, + variants: { + variant: { + neutral: { + base: "text-fg", + }, + danger: { + base: "bg-danger-muted text-fg-danger *:data-[slot=alert-description]:text-fg-danger/90 [&>svg]:text-current", + }, + warning: { + base: "text-fg-warning *:data-[slot=alert-description]:text-fg-warning/90 [&>svg]:text-current", + }, + info: { + base: "text-fg-info *:data-[slot=alert-description]:text-fg-info/90 [&>svg]:text-current", + }, + success: { + base: "text-fg-success *:data-[slot=alert-description]:text-fg-success/90 [&>svg]:text-current", + }, + }, + }, + defaultVariants: { + variant: "neutral", + }, }); const { base, title, description } = alertVariants(); /* -----------------------------------------------------------------------------------------------*/ -interface AlertProps - extends React.ComponentProps<"div">, - VariantProps {} +interface AlertProps extends React.ComponentProps<"div">, VariantProps {} function Alert({ className, variant, ...props }: AlertProps) { - return ( -
- ); + return
; } /* -----------------------------------------------------------------------------------------------*/ @@ -118,9 +102,7 @@ function Alert({ className, variant, ...props }: AlertProps) { interface AlertTitleProps extends React.ComponentProps<"div"> {} function AlertTitle({ className, ...props }: AlertTitleProps) { - return ( -
- ); + return
; } /* -----------------------------------------------------------------------------------------------*/ @@ -128,13 +110,7 @@ function AlertTitle({ className, ...props }: AlertTitleProps) { interface AlertDescriptionProps extends React.ComponentProps<"div"> {} function AlertDescription({ className, ...props }: AlertDescriptionProps) { - return ( -
- ); + return
; } /* -----------------------------------------------------------------------------------------------*/ @@ -142,37 +118,32 @@ function AlertDescription({ className, ...props }: AlertDescriptionProps) { interface AlertActionProps extends React.ComponentProps<"div"> {} function AlertAction({ className, ...props }: AlertActionProps) { - return
; + return
; } /* -----------------------------------------------------------------------------------------------*/ export { Alert, AlertTitle, AlertDescription, AlertAction }; -export type { - AlertProps, - AlertTitleProps, - AlertDescriptionProps, - AlertActionProps, -}; -` - } - ] - } - } - }, - { - "name": "avatar", - "type": "registry:ui", - "defaultVariant": "basic", - "variants": { - "basic": { - "files": [ - { - "type": "registry:ui", - "path": "ui/avatar/basic.tsx", - "target": "ui/avatar.tsx", - "content": `"use client"; +export type { AlertProps, AlertTitleProps, AlertDescriptionProps, AlertActionProps }; +`, + }, + ], + }, + }, + }, + { + name: "avatar", + type: "registry:ui", + defaultVariant: "basic", + variants: { + basic: { + files: [ + { + type: "registry:ui", + path: "ui/avatar/basic.tsx", + target: "ui/avatar.tsx", + content: `"use client"; import * as React from "react"; import { tv } from "tailwind-variants"; @@ -183,124 +154,91 @@ import { createContext } from "@dotui/registry/lib/context"; import type { ImageLoadingStatus } from "@dotui/registry/hooks/use-image-loading-status"; const avatarStyles = tv({ - slots: { - group: - "-space-x-2 flex flex-wrap *:data-[slot=avatar]:ring-2 *:data-[slot=avatar]:ring-bg", - root: "relative inline-flex shrink-0 overflow-hidden rounded-full bg-bg align-middle", - image: "aspect-square size-full", - fallback: "flex size-full select-none items-center justify-center bg-muted", - placeholder: - "flex size-full h-full animate-pulse items-center justify-center bg-muted", - }, - variants: { - size: { - sm: { group: "*:data-[slot=avatar]:size-8", root: "size-8" }, - md: { group: "*:data-[slot=avatar]:size-10", root: "size-10" }, - lg: { group: "*:data-[slot=avatar]:size-12", root: "size-12" }, - }, - }, - defaultVariants: { - size: "md", - }, + slots: { + group: "-space-x-2 flex flex-wrap *:data-[slot=avatar]:ring-2 *:data-[slot=avatar]:ring-bg", + root: "relative inline-flex shrink-0 overflow-hidden rounded-full bg-bg align-middle", + image: "aspect-square size-full", + fallback: "flex size-full select-none items-center justify-center bg-muted", + placeholder: "flex size-full h-full animate-pulse items-center justify-center bg-muted", + }, + variants: { + size: { + sm: { group: "*:data-[slot=avatar]:size-8", root: "size-8" }, + md: { group: "*:data-[slot=avatar]:size-10", root: "size-10" }, + lg: { group: "*:data-[slot=avatar]:size-12", root: "size-12" }, + }, + }, + defaultVariants: { + size: "md", + }, }); const { group, root, image, fallback, placeholder } = avatarStyles(); /* -----------------------------------------------------------------------------------------------*/ -interface AvatarGroupProps - extends React.ComponentProps<"div">, - VariantProps {} +interface AvatarGroupProps extends React.ComponentProps<"div">, VariantProps {} const AvatarGroup = ({ className, size, ...props }: AvatarGroupProps) => { - return
; + return
; }; /* -----------------------------------------------------------------------------------------------*/ -interface AvatarProps - extends AvatarImageProps, - VariantProps { - fallback?: React.ReactNode; +interface AvatarProps extends AvatarImageProps, VariantProps { + fallback?: React.ReactNode; } -const Avatar = ({ - className, - style, - fallback, - size, - ...props -}: AvatarProps) => { - return ( - - - {fallback} - - - ); +const Avatar = ({ className, style, fallback, size, ...props }: AvatarProps) => { + return ( + + + {fallback} + + + ); }; /* -----------------------------------------------------------------------------------------------*/ const [AvatarInternalContext, useAvatarInternalContext] = createContext<{ - status: ImageLoadingStatus; - setStatus: (status: ImageLoadingStatus) => void; + status: ImageLoadingStatus; + setStatus: (status: ImageLoadingStatus) => void; }>({ - name: "AvatarRoot", - strict: true, + name: "AvatarRoot", + strict: true, }); -interface AvatarRootProps - extends React.ComponentProps<"span">, - VariantProps {} +interface AvatarRootProps extends React.ComponentProps<"span">, VariantProps {} function AvatarRoot({ className, size, ...props }: AvatarRootProps) { - const [status, setStatus] = React.useState("idle"); - - return ( - - - - ); + const [status, setStatus] = React.useState("idle"); + + return ( + + + + ); } /* -----------------------------------------------------------------------------------------------*/ interface AvatarImageProps extends Omit, "src"> { - src?: string; + src?: string; } -function AvatarImage({ - src, - alt, - className, - referrerPolicy, - crossOrigin, - ...props -}: AvatarImageProps) { - const status = useImageLoadingStatus(src, { referrerPolicy, crossOrigin }); - const { setStatus } = useAvatarInternalContext("AvatarImage"); - - React.useLayoutEffect(() => { - if (status !== "idle") { - setStatus(status); - } - }, [status, setStatus]); - - if (status === "loaded") - return ( - {alt} - ); - - return null; +function AvatarImage({ src, alt, className, referrerPolicy, crossOrigin, ...props }: AvatarImageProps) { + const status = useImageLoadingStatus(src, { referrerPolicy, crossOrigin }); + const { setStatus } = useAvatarInternalContext("AvatarImage"); + + React.useLayoutEffect(() => { + if (status !== "idle") { + setStatus(status); + } + }, [status, setStatus]); + + if (status === "loaded") + return {alt}; + + return null; } /* -----------------------------------------------------------------------------------------------*/ @@ -308,16 +246,9 @@ function AvatarImage({ type AvatarFallbackProps = React.HTMLAttributes; const AvatarFallback = ({ className, ...props }: AvatarFallbackProps) => { - const { status } = useAvatarInternalContext("AvatarFallback"); - if (status === "error") - return ( - - ); - return null; + const { status } = useAvatarInternalContext("AvatarFallback"); + if (status === "error") return ; + return null; }; /* -----------------------------------------------------------------------------------------------*/ @@ -325,214 +256,176 @@ const AvatarFallback = ({ className, ...props }: AvatarFallbackProps) => { interface AvatarPlaceholderProps extends React.ComponentProps<"span"> {} const AvatarPlaceholder = ({ className, ...props }: AvatarPlaceholderProps) => { - const { status } = useAvatarInternalContext("AvatarPlaceholder"); - if (["idle", "loading"].includes(status)) - return ; - return null; + const { status } = useAvatarInternalContext("AvatarPlaceholder"); + if (["idle", "loading"].includes(status)) return ; + return null; }; /* -----------------------------------------------------------------------------------------------*/ const CompoundAvatar = Object.assign(Avatar, { - Group: AvatarGroup, - Root: AvatarRoot, - Image: AvatarImage, - Fallback: AvatarFallback, - Placeholder: AvatarPlaceholder, + Group: AvatarGroup, + Root: AvatarRoot, + Image: AvatarImage, + Fallback: AvatarFallback, + Placeholder: AvatarPlaceholder, }); -export { - CompoundAvatar as Avatar, - AvatarGroup, - AvatarRoot, - AvatarImage, - AvatarFallback, - AvatarPlaceholder, -}; +export { CompoundAvatar as Avatar, AvatarGroup, AvatarRoot, AvatarImage, AvatarFallback, AvatarPlaceholder }; export type { - AvatarGroupProps, - AvatarProps, - AvatarRootProps, - AvatarImageProps, - AvatarFallbackProps, - AvatarPlaceholderProps, -}; -` - } - ] - } - } - }, - { - "name": "badge", - "type": "registry:ui", - "defaultVariant": "basic", - "variants": { - "basic": { - "files": [ - { - "type": "registry:ui", - "path": "ui/badge/basic.tsx", - "target": "ui/badge.tsx", - "content": `import { tv } from "tailwind-variants"; + AvatarGroupProps, + AvatarProps, + AvatarRootProps, + AvatarImageProps, + AvatarFallbackProps, + AvatarPlaceholderProps, +}; +`, + }, + ], + }, + }, + }, + { + name: "badge", + type: "registry:ui", + defaultVariant: "basic", + variants: { + basic: { + files: [ + { + type: "registry:ui", + path: "ui/badge/basic.tsx", + target: "ui/badge.tsx", + content: `import { tv } from "tailwind-variants"; import type * as React from "react"; import type { VariantProps } from "tailwind-variants"; const badgeStyles = tv({ - base: "inline-flex w-fit shrink-0 items-center justify-center gap-1 whitespace-nowrap rounded-md px-2 py-0.5 font-medium text-xs [&>svg]:pointer-events-none [&>svg]:size-3", - variants: { - variant: { - default: "bg-neutral text-fg-on-neutral", - danger: "bg-danger text-fg-on-danger", - success: "bg-success text-fg-on-success", - warning: "bg-warning text-fg-on-warning", - info: "bg-info text-fg-on-info", - }, - }, - defaultVariants: { - variant: "default", - }, + base: "inline-flex w-fit shrink-0 items-center justify-center gap-1 whitespace-nowrap rounded-md px-2 py-0.5 font-medium text-xs [&>svg]:pointer-events-none [&>svg]:size-3", + variants: { + variant: { + default: "bg-neutral text-fg-on-neutral", + danger: "bg-danger text-fg-on-danger", + success: "bg-success text-fg-on-success", + warning: "bg-warning text-fg-on-warning", + info: "bg-info text-fg-on-info", + }, + }, + defaultVariants: { + variant: "default", + }, }); -interface BadgeProps - extends React.ComponentProps<"span">, - VariantProps {} +interface BadgeProps extends React.ComponentProps<"span">, VariantProps {} const Badge = ({ className, variant, ...props }: BadgeProps) => { - return ( - - ); + return ; }; export type { BadgeProps }; export { Badge }; -` - } - ] - } - } - }, - { - "name": "breadcrumbs", - "type": "registry:ui", - "defaultVariant": "basic", - "variants": { - "basic": { - "files": [ - { - "type": "registry:ui", - "path": "ui/breadcrumbs/basic.tsx", - "target": "ui/breadcrumbs.tsx", - "content": `"use client"; +`, + }, + ], + }, + }, + }, + { + name: "breadcrumbs", + type: "registry:ui", + defaultVariant: "basic", + variants: { + basic: { + files: [ + { + type: "registry:ui", + path: "ui/breadcrumbs/basic.tsx", + target: "ui/breadcrumbs.tsx", + content: `"use client"; import { ChevronRightIcon } from "lucide-react"; import { - Breadcrumb as AriaBreadcrumb, - Breadcrumbs as AriaBreadcrumbs, - Link as AriaLink, - composeRenderProps, + Breadcrumb as AriaBreadcrumb, + Breadcrumbs as AriaBreadcrumbs, + Link as AriaLink, + composeRenderProps, } from "react-aria-components"; import { tv } from "tailwind-variants"; import type { BreadcrumbsProps as AriaBreadcrumbsProps } from "react-aria-components"; const breadcrumbsStyles = tv({ - slots: { - root: "wrap-break-word flex flex-wrap items-center gap-1.5 text-fg-muted text-sm [&_svg]:size-4", - item: "inline-flex items-center gap-1", - link: [ - "focus-reset focus-visible:focus-ring", - "inline-flex items-center gap-1 rounded px-0.5 current:text-fg leading-none transition-colors disabled:cursor-default disabled:not-current:text-fg-disabled hover:[a]:text-fg", - ], - }, + slots: { + root: "wrap-break-word flex flex-wrap items-center gap-1.5 text-fg-muted text-sm [&_svg]:size-4", + item: "inline-flex items-center gap-1", + link: [ + "focus-reset focus-visible:focus-ring", + "inline-flex items-center gap-1 rounded px-0.5 current:text-fg leading-none transition-colors disabled:cursor-default disabled:not-current:text-fg-disabled hover:[a]:text-fg", + ], + }, }); const { root, item, link } = breadcrumbsStyles(); interface BreadcrumbsProps extends AriaBreadcrumbsProps { - ref?: React.RefObject; + ref?: React.RefObject; } -const Breadcrumbs = ({ - className, - ...props -}: BreadcrumbsProps) => { - return ; +const Breadcrumbs = ({ className, ...props }: BreadcrumbsProps) => { + return ; }; -type BreadcrumbProps = BreadcrumbItemProps & - Omit; +type BreadcrumbProps = BreadcrumbItemProps & Omit; const Breadcrumb = ({ ref, children, ...props }: BreadcrumbProps) => { - return ( - - {composeRenderProps(children, (children, { isCurrent }) => ( - <> - {children} - {!isCurrent && } - - ))} - - ); -}; - -interface BreadcrumbItemProps - extends React.ComponentProps {} + return ( + + {composeRenderProps(children, (children, { isCurrent }) => ( + <> + {children} + {!isCurrent && } + + ))} + + ); +}; + +interface BreadcrumbItemProps extends React.ComponentProps {} const BreadcrumbItem = ({ className, ...props }: BreadcrumbItemProps) => ( - - item({ className }), - )} - {...props} - /> + item({ className }))} {...props} /> ); interface BreadcrumbLinkProps extends React.ComponentProps {} const BreadcrumbLink = ({ className, ...props }: BreadcrumbLinkProps) => ( - - link({ className }), - )} - {...props} - /> + link({ className }))} {...props} /> ); export { Breadcrumbs, Breadcrumb, BreadcrumbItem, BreadcrumbLink }; -export type { - BreadcrumbsProps, - BreadcrumbProps, - BreadcrumbItemProps, - BreadcrumbLinkProps, -}; -` - } - ], - "registryDependencies": [ - "focus-styles" - ] - } - } - }, - { - "name": "button", - "type": "registry:ui", - "defaultVariant": "basic", - "variants": { - "basic": { - "files": [ - { - "type": "registry:ui", - "path": "ui/button/basic.tsx", - "target": "ui/button.tsx", - "content": `"use client"; +export type { BreadcrumbsProps, BreadcrumbProps, BreadcrumbItemProps, BreadcrumbLinkProps }; +`, + }, + ], + registryDependencies: ["focus-styles"], + }, + }, + }, + { + name: "button", + type: "registry:ui", + defaultVariant: "basic", + variants: { + basic: { + files: [ + { + type: "registry:ui", + path: "ui/button/basic.tsx", + target: "ui/button.tsx", + content: `"use client"; import { - Button as AriaButton, - ButtonContext as AriaButtonContext, - Link as AriaLink, - composeRenderProps, + Button as AriaButton, + ButtonContext as AriaButtonContext, + Link as AriaLink, + composeRenderProps, } from "react-aria-components"; import { tv } from "tailwind-variants"; import type * as React from "react"; @@ -543,149 +436,111 @@ import { createVariantsContext } from "@dotui/registry/lib/context"; import { Loader } from "@dotui/registry/ui/loader"; const buttonStyles = tv({ - base: [ - "relative box-border inline-flex shrink-0 cursor-pointer items-center justify-center gap-2 whitespace-nowrap rounded-md font-medium text-sm leading-normal transition-[background-color,border-color,color,box-shadow] data-icon-only:px-0", - "*:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2", - // svg - "[&_svg]:pointer-events-none [&_svg]:not-with-[size]:size-4 [&_svg]:shrink-0", - // focus state - "focus-reset focus-visible:focus-ring", - // disabled state - "disabled:cursor-default disabled:border-border-disabled disabled:bg-disabled disabled:text-fg-disabled", - // pending state - "pending:cursor-default pending:border-border-disabled pending:bg-disabled pending:text-transparent pending:**:not-data-[slot=spinner]:not-in-data-[slot=spinner]:opacity-0 pending:**:data-[slot=spinner]:text-fg-muted", - ], - variants: { - variant: { - default: - "border pressed:border-border-active bg-neutral pressed:bg-neutral-active text-fg-on-neutral hover:border-border-hover hover:bg-neutral-hover", - primary: - "pending:border-0 bg-primary pressed:bg-primary-active text-fg-on-primary [--color-disabled:var(--neutral-500)] [--color-fg-disabled:var(--neutral-300)] hover:bg-primary-hover disabled:border-0", - quiet: "bg-transparent pressed:bg-inverse/20 text-fg hover:bg-inverse/10", - link: "text-fg underline-offset-4 hover:underline", - warning: - "bg-warning pressed:bg-warning-active text-fg-on-warning hover:bg-warning-hover", - danger: - "bg-danger pressed:bg-danger-active text-fg-on-danger hover:bg-danger-hover", - }, - size: { - sm: "h-8 px-3 has-[>svg]:px-2.5 data-icon-only:not-with-[size]:not-with-[w]:w-8", - md: "h-9 px-4 has-[>svg]:px-3 data-icon-only:not-with-[size]:not-with-[w]:w-9", - lg: "h-10 px-5 has-[>svg]:px-4 data-icon-only:not-with-[size]:not-with-[w]:w-10", - }, - }, - defaultVariants: { - variant: "default", - size: "md", - }, + base: [ + "relative box-border inline-flex shrink-0 cursor-pointer items-center justify-center gap-2 whitespace-nowrap rounded-md font-medium text-sm leading-normal transition-[background-color,border-color,color,box-shadow] data-icon-only:px-0", + "*:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2", + // svg + "[&_svg]:pointer-events-none [&_svg]:not-with-[size]:size-4 [&_svg]:shrink-0", + // focus state + "focus-reset focus-visible:focus-ring", + // disabled state + "disabled:cursor-default disabled:border-border-disabled disabled:bg-disabled disabled:text-fg-disabled", + // pending state + "pending:cursor-default pending:border-border-disabled pending:bg-disabled pending:text-transparent pending:**:not-data-[slot=spinner]:not-in-data-[slot=spinner]:opacity-0 pending:**:data-[slot=spinner]:text-fg-muted", + ], + variants: { + variant: { + default: + "border pressed:border-border-active bg-neutral pressed:bg-neutral-active text-fg-on-neutral hover:border-border-hover hover:bg-neutral-hover", + primary: + "pending:border-0 bg-primary pressed:bg-primary-active text-fg-on-primary [--color-disabled:var(--neutral-500)] [--color-fg-disabled:var(--neutral-300)] hover:bg-primary-hover disabled:border-0", + quiet: "bg-transparent pressed:bg-inverse/20 text-fg hover:bg-inverse/10", + link: "text-fg underline-offset-4 hover:underline", + warning: "bg-warning pressed:bg-warning-active text-fg-on-warning hover:bg-warning-hover", + danger: "bg-danger pressed:bg-danger-active text-fg-on-danger hover:bg-danger-hover", + }, + size: { + sm: "h-8 px-3 has-[>svg]:px-2.5 data-icon-only:not-with-[size]:not-with-[w]:w-8", + md: "h-9 px-4 has-[>svg]:px-3 data-icon-only:not-with-[size]:not-with-[w]:w-9", + lg: "h-10 px-5 has-[>svg]:px-4 data-icon-only:not-with-[size]:not-with-[w]:w-10", + }, + }, + defaultVariants: { + variant: "default", + size: "md", + }, }); type ButtonVariants = VariantProps; const [ButtonProvider, useContextProps] = createVariantsContext< - ButtonVariants, - React.ComponentProps + ButtonVariants, + React.ComponentProps >(AriaButtonContext); /* -----------------------------------------------------------------------------------------------*/ -interface ButtonProps - extends React.ComponentProps, - ButtonVariants { - aspect?: "default" | "square" | "auto"; +interface ButtonProps extends React.ComponentProps, ButtonVariants { + aspect?: "default" | "square" | "auto"; } const Button = (localProps: ButtonProps) => { - const { - variant, - size, - aspect = "auto", - className, - slot, - style, - children, - ...props - } = useContextProps(localProps); - - const isIconOnly = useButtonAspect(children, aspect); - - return ( - - buttonStyles({ variant, size, className: cn }), - )} - slot={slot} - style={style} - {...props} - > - {composeRenderProps(children, (children, { isPending }) => ( - <> - {isPending && ( - - )} - {typeof children === "string" ? ( - {children} - ) : ( - children - )} - - ))} - - ); -}; - -/* -----------------------------------------------------------------------------------------------*/ - -interface LinkButtonProps - extends React.ComponentProps, - VariantProps { - aspect?: "default" | "square" | "auto"; + const { variant, size, aspect = "auto", className, slot, style, children, ...props } = useContextProps(localProps); + + const isIconOnly = useButtonAspect(children, aspect); + + return ( + buttonStyles({ variant, size, className: cn }))} + slot={slot} + style={style} + {...props} + > + {composeRenderProps(children, (children, { isPending }) => ( + <> + {isPending && ( + + )} + {typeof children === "string" ? {children} : children} + + ))} + + ); +}; + +/* -----------------------------------------------------------------------------------------------*/ + +interface LinkButtonProps extends React.ComponentProps, VariantProps { + aspect?: "default" | "square" | "auto"; } const LinkButton = (localProps: LinkButtonProps) => { - const { - variant, - size, - aspect = "auto", - className, - slot, - style, - children, - ...props - } = useContextProps(localProps); - - const isIconOnly = useButtonAspect(children, aspect); - - return ( - - buttonStyles({ variant, size, className: cn }), - )} - slot={slot} - style={style} - {...props} - > - {composeRenderProps(children, (children) => ( - <> - {typeof children === "string" ? ( - {children} - ) : ( - children - )} - - ))} - - ); + const { variant, size, aspect = "auto", className, slot, style, children, ...props } = useContextProps(localProps); + + const isIconOnly = useButtonAspect(children, aspect); + + return ( + buttonStyles({ variant, size, className: cn }))} + slot={slot} + style={style} + {...props} + > + {composeRenderProps(children, (children) => ( + <>{typeof children === "string" ? {children} : children} + ))} + + ); }; /* -----------------------------------------------------------------------------------------------*/ @@ -693,27 +548,24 @@ const LinkButton = (localProps: LinkButtonProps) => { export type { ButtonProps, LinkButtonProps }; export { Button, LinkButton, ButtonProvider, buttonStyles }; -` - } - ], - "registryDependencies": [ - "loader", - "focus-styles" - ] - }, - "ripple": { - "files": [ - { - "type": "registry:ui", - "path": "ui/button/ripple.tsx", - "target": "ui/button.tsx", - "content": `"use client"; +`, + }, + ], + registryDependencies: ["loader", "focus-styles"], + }, + ripple: { + files: [ + { + type: "registry:ui", + path: "ui/button/ripple.tsx", + target: "ui/button.tsx", + content: `"use client"; import { - Button as AriaButton, - ButtonContext as AriaButtonContext, - Link as AriaLink, - composeRenderProps, + Button as AriaButton, + ButtonContext as AriaButtonContext, + Link as AriaLink, + composeRenderProps, } from "react-aria-components"; import { tv } from "tailwind-variants"; import type * as React from "react"; @@ -724,148 +576,110 @@ import { createVariantsContext } from "@dotui/registry/lib/context"; import { Loader } from "@dotui/registry/ui/loader"; const buttonStyles = tv({ - base: [ - "ripple relative box-border inline-flex shrink-0 cursor-pointer items-center justify-center gap-2 whitespace-nowrap rounded-md font-medium text-sm leading-normal transition-[background-color,border-color,color,box-shadow] data-icon-only:px-0", - "*:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2", - // focus state - "focus-reset focus-visible:focus-ring", - // disabled state - "disabled:cursor-default disabled:border-border-disabled disabled:bg-disabled disabled:text-fg-disabled", - // pending state - "pending:cursor-default pending:border-border-disabled pending:bg-disabled pending:text-transparent pending:**:not-data-[slot=spinner]:not-in-data-[slot=spinner]:opacity-0 pending:**:data-[slot=spinner]:text-fg-muted", - ], - variants: { - variant: { - default: - "border pressed:border-border-active bg-neutral pressed:bg-neutral-active text-fg-on-neutral hover:border-border-hover hover:bg-neutral-hover", - primary: - "pending:border-0 bg-primary pressed:bg-primary-active text-fg-on-primary [--color-disabled:var(--neutral-500)] [--color-fg-disabled:var(--neutral-300)] hover:bg-primary-hover disabled:border-0", - quiet: "bg-transparent pressed:bg-inverse/20 text-fg hover:bg-inverse/10", - link: "text-fg underline-offset-4 hover:underline", - warning: - "bg-warning pressed:bg-warning-active text-fg-on-warning hover:bg-warning-hover", - danger: - "bg-danger pressed:bg-danger-active text-fg-on-danger hover:bg-danger-hover", - }, - size: { - sm: "h-8 px-3 data-icon-only:not-with-[size]:not-with-[w]:w-8 [&_svg]:size-4", - md: "h-9 px-4 data-icon-only:not-with-[size]:not-with-[w]:w-9 [&_svg]:size-4", - lg: "h-10 px-5 data-icon-only:not-with-[size]:not-with-[w]:w-10 [&_svg]:size-5", - }, - }, - defaultVariants: { - variant: "default", - size: "md", - }, + base: [ + "ripple relative box-border inline-flex shrink-0 cursor-pointer items-center justify-center gap-2 whitespace-nowrap rounded-md font-medium text-sm leading-normal transition-[background-color,border-color,color,box-shadow] data-icon-only:px-0", + "*:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2", + // focus state + "focus-reset focus-visible:focus-ring", + // disabled state + "disabled:cursor-default disabled:border-border-disabled disabled:bg-disabled disabled:text-fg-disabled", + // pending state + "pending:cursor-default pending:border-border-disabled pending:bg-disabled pending:text-transparent pending:**:not-data-[slot=spinner]:not-in-data-[slot=spinner]:opacity-0 pending:**:data-[slot=spinner]:text-fg-muted", + ], + variants: { + variant: { + default: + "border pressed:border-border-active bg-neutral pressed:bg-neutral-active text-fg-on-neutral hover:border-border-hover hover:bg-neutral-hover", + primary: + "pending:border-0 bg-primary pressed:bg-primary-active text-fg-on-primary [--color-disabled:var(--neutral-500)] [--color-fg-disabled:var(--neutral-300)] hover:bg-primary-hover disabled:border-0", + quiet: "bg-transparent pressed:bg-inverse/20 text-fg hover:bg-inverse/10", + link: "text-fg underline-offset-4 hover:underline", + warning: "bg-warning pressed:bg-warning-active text-fg-on-warning hover:bg-warning-hover", + danger: "bg-danger pressed:bg-danger-active text-fg-on-danger hover:bg-danger-hover", + }, + size: { + sm: "h-8 px-3 data-icon-only:not-with-[size]:not-with-[w]:w-8 [&_svg]:size-4", + md: "h-9 px-4 data-icon-only:not-with-[size]:not-with-[w]:w-9 [&_svg]:size-4", + lg: "h-10 px-5 data-icon-only:not-with-[size]:not-with-[w]:w-10 [&_svg]:size-5", + }, + }, + defaultVariants: { + variant: "default", + size: "md", + }, }); type ButtonVariants = VariantProps; const [ButtonProvider, useContextProps] = createVariantsContext< - ButtonVariants, - React.ComponentProps + ButtonVariants, + React.ComponentProps >(AriaButtonContext); /* -----------------------------------------------------------------------------------------------*/ -interface ButtonProps - extends React.ComponentProps, - ButtonVariants { - aspect?: "default" | "square" | "auto"; +interface ButtonProps extends React.ComponentProps, ButtonVariants { + aspect?: "default" | "square" | "auto"; } const Button = (localProps: ButtonProps) => { - const { - variant, - size, - aspect = "auto", - className, - slot, - style, - children, - ...props - } = useContextProps(localProps); - - const isIconOnly = useButtonAspect(children, aspect); - - return ( - - buttonStyles({ variant, size, className: cn }), - )} - slot={slot} - style={style} - {...props} - > - {composeRenderProps(children, (children, { isPending }) => ( - <> - {isPending && ( - - )} - {typeof children === "string" ? ( - {children} - ) : ( - children - )} - - ))} - - ); -}; - -/* -----------------------------------------------------------------------------------------------*/ - -interface LinkButtonProps - extends React.ComponentProps, - VariantProps { - aspect?: "default" | "square" | "auto"; + const { variant, size, aspect = "auto", className, slot, style, children, ...props } = useContextProps(localProps); + + const isIconOnly = useButtonAspect(children, aspect); + + return ( + buttonStyles({ variant, size, className: cn }))} + slot={slot} + style={style} + {...props} + > + {composeRenderProps(children, (children, { isPending }) => ( + <> + {isPending && ( + + )} + {typeof children === "string" ? {children} : children} + + ))} + + ); +}; + +/* -----------------------------------------------------------------------------------------------*/ + +interface LinkButtonProps extends React.ComponentProps, VariantProps { + aspect?: "default" | "square" | "auto"; } const LinkButton = (localProps: LinkButtonProps) => { - const { - variant, - size, - aspect = "auto", - className, - slot, - style, - children, - ...props - } = useContextProps(localProps); - - const isIconOnly = useButtonAspect(children, aspect); - - return ( - - buttonStyles({ variant, size, className: cn }), - )} - slot={slot} - style={style} - {...props} - > - {composeRenderProps(children, (children) => ( - <> - {typeof children === "string" ? ( - {children} - ) : ( - children - )} - - ))} - - ); + const { variant, size, aspect = "auto", className, slot, style, children, ...props } = useContextProps(localProps); + + const isIconOnly = useButtonAspect(children, aspect); + + return ( + buttonStyles({ variant, size, className: cn }))} + slot={slot} + style={style} + {...props} + > + {composeRenderProps(children, (children) => ( + <>{typeof children === "string" ? {children} : children} + ))} + + ); }; /* -----------------------------------------------------------------------------------------------*/ @@ -873,198 +687,190 @@ const LinkButton = (localProps: LinkButtonProps) => { export type { ButtonProps, LinkButtonProps }; export { Button, LinkButton, ButtonProvider, buttonStyles }; -` - } - ] - } - } - }, - { - "name": "calendar", - "type": "registry:ui", - "defaultVariant": "basic", - "variants": { - "basic": { - "files": [ - { - "type": "registry:ui", - "path": "ui/calendar/basic.tsx", - "target": "ui/calendar.tsx", - "content": `"use client"; +`, + }, + ], + }, + }, + }, + { + name: "calendar", + type: "registry:ui", + defaultVariant: "basic", + variants: { + basic: { + files: [ + { + type: "registry:ui", + path: "ui/calendar/basic.tsx", + target: "ui/calendar.tsx", + content: `"use client"; import React from "react"; import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react"; import { - Calendar as AriaCalendar, - CalendarCell as AriaCalendarCell, - CalendarContext as AriaCalendarContext, - CalendarGrid as AriaCalendarGrid, - CalendarGridBody as AriaCalendarGridBody, - CalendarGridHeader as AriaCalendarGridHeader, - CalendarHeaderCell as AriaCalendarHeaderCell, - Heading as AriaHeading, - RangeCalendar as AriaRangeCalendar, - RangeCalendarContext as AriaRangeCalendarContext, - RangeCalendarStateContext as AriaRangeCalendarStateContext, - composeRenderProps, - useSlottedContext, + Calendar as AriaCalendar, + CalendarCell as AriaCalendarCell, + CalendarContext as AriaCalendarContext, + CalendarGrid as AriaCalendarGrid, + CalendarGridBody as AriaCalendarGridBody, + CalendarGridHeader as AriaCalendarGridHeader, + CalendarHeaderCell as AriaCalendarHeaderCell, + Heading as AriaHeading, + RangeCalendar as AriaRangeCalendar, + RangeCalendarContext as AriaRangeCalendarContext, + RangeCalendarStateContext as AriaRangeCalendarStateContext, + composeRenderProps, + useSlottedContext, } from "react-aria-components"; import { tv } from "tailwind-variants"; import type { - CalendarProps as AriaCalendarProps, - RangeCalendarProps as AriaRangeCalendarProps, - DateValue, + CalendarProps as AriaCalendarProps, + RangeCalendarProps as AriaRangeCalendarProps, + DateValue, } from "react-aria-components"; import type { VariantProps } from "tailwind-variants"; import { Button } from "@dotui/registry/ui/button"; const calendarStyles = tv({ - slots: { - root: "flex flex-col gap-4", - header: "flex items-center justify-between gap-2", - grid: "w-full border-collapse", - gridHeader: "", - gridHeaderCell: "font-normal text-fg-muted text-xs", - gridBody: "", - }, - variants: { - standalone: { - true: { - root: "rounded-md border bg-bg p-3", - }, - }, - }, + slots: { + root: "flex flex-col gap-4", + header: "flex items-center justify-between gap-2", + grid: "w-full border-collapse", + gridHeader: "", + gridHeaderCell: "font-normal text-fg-muted text-xs", + gridBody: "", + }, + variants: { + standalone: { + true: { + root: "rounded-md border bg-bg p-3", + }, + }, + }, }); const calendarCellStyles = tv({ - slots: { - cellRoot: - "flex outside-month:hidden items-center justify-center outline-none selection-end:rounded-r-md selection-start:rounded-l-md", - cell: [ - "focus-reset focus-visible:focus-ring", - "my-1 flex size-8 cursor-pointer unavailable:cursor-default items-center justify-center rounded-md pressed:bg-inverse/20 text-sm unavailable:text-fg-disabled unavailable:not-data-disabled:line-through transition-colors read-only:cursor-default hover:bg-inverse/10 hover:unavailable:bg-transparent hover:read-only:bg-transparent disabled:cursor-default disabled:bg-transparent disabled:text-fg-disabled", - ], - }, - variants: { - variant: { - primary: {}, - accent: {}, - }, - range: { - true: { - cellRoot: - "selected: selected:bg-inverse/10 selected:invalid:bg-danger-muted selected:invalid:text-fg-danger", - cell: "selection-end:invalid:bg-danger selection-start:invalid:bg-danger selection-end:invalid:text-fg-on-danger selection-start:invalid:text-fg-on-danger", - }, - false: { - cell: "selected:invalid:bg-danger selected:invalid:text-fg-on-danger", - }, - }, - }, - compoundVariants: [ - { - variant: "primary", - range: false, - className: { - cell: "selected:bg-primary selected:text-fg-on-primary", - }, - }, - { - variant: "accent", - range: false, - className: { - cell: "selected:bg-accent selected:text-fg-on-accent", - }, - }, - { - variant: "primary", - range: true, - className: { - cell: "selection-end:bg-primary selection-start:bg-primary selection-end:text-fg-on-primary selection-start:text-fg-on-primary", - }, - }, - { - variant: "accent", - range: true, - className: { - cell: "selection-end:bg-accent selection-start:bg-accent selection-end:text-fg-on-accent selection-start:text-fg-on-accent", - }, - }, - ], - defaultVariants: { - variant: "accent", - }, + slots: { + cellRoot: + "flex outside-month:hidden items-center justify-center outline-none selection-end:rounded-r-md selection-start:rounded-l-md", + cell: [ + "focus-reset focus-visible:focus-ring", + "my-1 flex size-8 cursor-pointer unavailable:cursor-default items-center justify-center rounded-md pressed:bg-inverse/20 text-sm unavailable:text-fg-disabled unavailable:not-data-disabled:line-through transition-colors read-only:cursor-default hover:bg-inverse/10 hover:unavailable:bg-transparent hover:read-only:bg-transparent disabled:cursor-default disabled:bg-transparent disabled:text-fg-disabled", + ], + }, + variants: { + variant: { + primary: {}, + accent: {}, + }, + range: { + true: { + cellRoot: "selected: selected:bg-inverse/10 selected:invalid:bg-danger-muted selected:invalid:text-fg-danger", + cell: "selection-end:invalid:bg-danger selection-start:invalid:bg-danger selection-end:invalid:text-fg-on-danger selection-start:invalid:text-fg-on-danger", + }, + false: { + cell: "selected:invalid:bg-danger selected:invalid:text-fg-on-danger", + }, + }, + }, + compoundVariants: [ + { + variant: "primary", + range: false, + className: { + cell: "selected:bg-primary selected:text-fg-on-primary", + }, + }, + { + variant: "accent", + range: false, + className: { + cell: "selected:bg-accent selected:text-fg-on-accent", + }, + }, + { + variant: "primary", + range: true, + className: { + cell: "selection-end:bg-primary selection-start:bg-primary selection-end:text-fg-on-primary selection-start:text-fg-on-primary", + }, + }, + { + variant: "accent", + range: true, + className: { + cell: "selection-end:bg-accent selection-start:bg-accent selection-end:text-fg-on-accent selection-start:text-fg-on-accent", + }, + }, + ], + defaultVariants: { + variant: "accent", + }, }); -const { root, header, grid, gridHeader, gridHeaderCell, gridBody } = - calendarStyles(); +const { root, header, grid, gridHeader, gridHeaderCell, gridBody } = calendarStyles(); const { cellRoot, cell } = calendarCellStyles(); /* -----------------------------------------------------------------------------------------------*/ type CalendarProps = - | ({ - mode?: "single"; - } & AriaCalendarProps) - | ({ - mode: "range"; - } & AriaRangeCalendarProps); - -const Calendar = ({ - mode, - className, - ...props -}: CalendarProps) => { - const rangeCalendarContext = useSlottedContext(AriaRangeCalendarContext); - const calendarContext = useSlottedContext(AriaCalendarContext); - - if (mode === "range" || rangeCalendarContext) { - const standalone = Object.keys(rangeCalendarContext ?? {}).length === 0; - return ( - ["className"], - (className) => root({ standalone, className }), - )} - {...(props as AriaRangeCalendarProps)} - > - {composeRenderProps( - props.children as AriaRangeCalendarProps["children"], - (children) => - children ?? ( - <> - - - - ), - )} - - ); - } - - const standalone = !!calendarContext; - return ( - ["className"], - (className) => root({ standalone, className }), - )} - {...(props as AriaCalendarProps)} - > - {composeRenderProps( - props.children as AriaCalendarProps["children"], - (children) => - children ?? ( - <> - - - - ), - )} - - ); + | ({ + mode?: "single"; + } & AriaCalendarProps) + | ({ + mode: "range"; + } & AriaRangeCalendarProps); + +const Calendar = ({ mode, className, ...props }: CalendarProps) => { + const rangeCalendarContext = useSlottedContext(AriaRangeCalendarContext); + const calendarContext = useSlottedContext(AriaCalendarContext); + + if (mode === "range" || rangeCalendarContext) { + const standalone = Object.keys(rangeCalendarContext ?? {}).length === 0; + return ( + ["className"], (className) => + root({ standalone, className }), + )} + {...(props as AriaRangeCalendarProps)} + > + {composeRenderProps( + props.children as AriaRangeCalendarProps["children"], + (children) => + children ?? ( + <> + + + + ), + )} + + ); + } + + const standalone = !!calendarContext; + return ( + ["className"], (className) => + root({ standalone, className }), + )} + {...(props as AriaCalendarProps)} + > + {composeRenderProps( + props.children as AriaCalendarProps["children"], + (children) => + children ?? ( + <> + + + + ), + )} + + ); }; /* -----------------------------------------------------------------------------------------------*/ @@ -1072,224 +878,191 @@ const Calendar = ({ interface CalendarHeaderProps extends React.ComponentProps<"header"> {} const CalendarHeader = ({ className, ...props }: CalendarHeaderProps) => { - return ( -
- {props.children ?? ( - <> - - - - - )} -
- ); + return ( +
+ {props.children ?? ( + <> + + + + + )} +
+ ); }; /* -----------------------------------------------------------------------------------------------*/ -interface CalendarGridProps - extends React.ComponentProps {} +interface CalendarGridProps extends React.ComponentProps {} const CalendarGrid = ({ className, ...props }: CalendarGridProps) => { - return ( - - {props.children ?? ( - <> - - {(day) => {day}} - - - {(date) => } - - - )} - - ); + return ( + + {props.children ?? ( + <> + {(day) => {day}} + {(date) => } + + )} + + ); }; /* -----------------------------------------------------------------------------------------------*/ -interface CalendarGridHeaderProps - extends React.ComponentProps {} -const CalendarGridHeader = ({ - className, - ...props -}: CalendarGridHeaderProps) => { - return ( - - ); +interface CalendarGridHeaderProps extends React.ComponentProps {} +const CalendarGridHeader = ({ className, ...props }: CalendarGridHeaderProps) => { + return ; }; /* -----------------------------------------------------------------------------------------------*/ -interface CalendarHeaderCellProps - extends React.ComponentProps {} -const CalendarHeaderCell = ({ - className, - ...props -}: CalendarHeaderCellProps) => { - return ( - - ); +interface CalendarHeaderCellProps extends React.ComponentProps {} +const CalendarHeaderCell = ({ className, ...props }: CalendarHeaderCellProps) => { + return ; }; /* -----------------------------------------------------------------------------------------------*/ -interface CalendarGridBodyProps - extends React.ComponentProps {} +interface CalendarGridBodyProps extends React.ComponentProps {} const CalendarGridBody = ({ className, ...props }: CalendarGridBodyProps) => { - return ( - - ); + return ; }; /* -----------------------------------------------------------------------------------------------*/ interface CalendarCellProps - extends React.ComponentProps, - Omit, "range"> {} -const CalendarCell = ({ - variant = "accent", - children, - className, - ...props -}: CalendarCellProps) => { - const rangeCalendarState = React.use(AriaRangeCalendarStateContext); - const range = !!rangeCalendarState; - - return ( - - cellRoot({ - range, - variant, - className, - }), - )} - > - {composeRenderProps( - children, - ( - _, - { - isSelected, - isFocused, - isHovered, - isPressed, - isUnavailable, - isDisabled, - isFocusVisible, - isInvalid, - isOutsideMonth, - isOutsideVisibleRange, - isSelectionEnd, - isSelectionStart, - formattedDate, - }, - ) => ( - - {formattedDate} - - ), - )} - - ); + extends React.ComponentProps, + Omit, "range"> {} +const CalendarCell = ({ variant = "accent", children, className, ...props }: CalendarCellProps) => { + const rangeCalendarState = React.use(AriaRangeCalendarStateContext); + const range = !!rangeCalendarState; + + return ( + + cellRoot({ + range, + variant, + className, + }), + )} + > + {composeRenderProps( + children, + ( + _, + { + isSelected, + isFocused, + isHovered, + isPressed, + isUnavailable, + isDisabled, + isFocusVisible, + isInvalid, + isOutsideMonth, + isOutsideVisibleRange, + isSelectionEnd, + isSelectionStart, + formattedDate, + }, + ) => ( + + {formattedDate} + + ), + )} + + ); }; export { - Calendar, - CalendarHeader, - CalendarGrid, - CalendarGridHeader, - CalendarHeaderCell, - CalendarGridBody, - CalendarCell, - calendarStyles, + Calendar, + CalendarHeader, + CalendarGrid, + CalendarGridHeader, + CalendarHeaderCell, + CalendarGridBody, + CalendarCell, + calendarStyles, }; export type { - CalendarProps, - CalendarHeaderProps, - CalendarGridProps, - CalendarGridHeaderProps, - CalendarHeaderCellProps, - CalendarGridBodyProps, - CalendarCellProps, -}; -` - } - ], - "registryDependencies": [ - "button", - "text", - "focus-styles" - ] - } - } - }, - { - "name": "card", - "type": "registry:ui", - "defaultVariant": "basic", - "variants": { - "basic": { - "files": [ - { - "type": "registry:ui", - "path": "ui/card/basic.tsx", - "target": "ui/card.tsx", - "content": `import { tv } from "tailwind-variants"; + CalendarProps, + CalendarHeaderProps, + CalendarGridProps, + CalendarGridHeaderProps, + CalendarHeaderCellProps, + CalendarGridBodyProps, + CalendarCellProps, +}; +`, + }, + ], + registryDependencies: ["button", "text", "focus-styles"], + }, + }, + }, + { + name: "card", + type: "registry:ui", + defaultVariant: "basic", + variants: { + basic: { + files: [ + { + type: "registry:ui", + path: "ui/card/basic.tsx", + target: "ui/card.tsx", + content: `import { tv } from "tailwind-variants"; import type * as React from "react"; const cardStyles = tv({ - slots: { - root: "flex flex-col gap-6 rounded-xl border bg-card py-6 text-fg shadow-sm", - header: - "@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-2 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6", - title: "font-semibold leading-none", - description: "text-fg-muted text-sm", - action: "col-start-2 row-span-2 row-start-1 self-start justify-self-end", - content: "flex-1 px-6", - footer: "flex items-center px-6 [.border-t]:pt-6", - }, + slots: { + root: "flex flex-col gap-6 rounded-xl border bg-card py-6 text-fg shadow-sm", + header: + "@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-2 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6", + title: "font-semibold leading-none", + description: "text-fg-muted text-sm", + action: "col-start-2 row-span-2 row-start-1 self-start justify-self-end", + content: "flex-1 px-6", + footer: "flex items-center px-6 [.border-t]:pt-6", + }, }); -const { root, header, title, description, action, content, footer } = - cardStyles(); +const { root, header, title, description, action, content, footer } = cardStyles(); /* -----------------------------------------------------------------------------------------------*/ interface CardProps extends React.ComponentProps<"div"> {} function Card({ className, ...props }: CardProps) { - return
; + return
; } /* -----------------------------------------------------------------------------------------------*/ @@ -1297,9 +1070,7 @@ function Card({ className, ...props }: CardProps) { interface CardHeaderProps extends React.ComponentProps<"div"> {} function CardHeader({ className, ...props }: CardHeaderProps) { - return ( -
- ); + return
; } /* -----------------------------------------------------------------------------------------------*/ @@ -1307,9 +1078,7 @@ function CardHeader({ className, ...props }: CardHeaderProps) { interface CardTitleProps extends React.ComponentProps<"div"> {} function CardTitle({ className, ...props }: CardTitleProps) { - return ( -
- ); + return
; } /* -----------------------------------------------------------------------------------------------*/ @@ -1317,13 +1086,7 @@ function CardTitle({ className, ...props }: CardTitleProps) { interface CardDescriptionProps extends React.ComponentProps<"div"> {} function CardDescription({ className, ...props }: CardDescriptionProps) { - return ( -
- ); + return
; } /* -----------------------------------------------------------------------------------------------*/ @@ -1331,9 +1094,7 @@ function CardDescription({ className, ...props }: CardDescriptionProps) { interface CardActionProps extends React.ComponentProps<"div"> {} function CardAction({ className, ...props }: CardActionProps) { - return ( -
- ); + return
; } /* -----------------------------------------------------------------------------------------------*/ @@ -1341,13 +1102,7 @@ function CardAction({ className, ...props }: CardActionProps) { interface CardContentProps extends React.ComponentProps<"div"> {} function CardContent({ className, ...props }: CardContentProps) { - return ( -
- ); + return
; } /* -----------------------------------------------------------------------------------------------*/ @@ -1355,60 +1110,43 @@ function CardContent({ className, ...props }: CardContentProps) { interface CardFooterProps extends React.ComponentProps<"div"> {} function CardFooter({ className, ...props }: CardFooterProps) { - return ( -
- ); + return
; } /* -----------------------------------------------------------------------------------------------*/ -export { - Card, - CardHeader, - CardFooter, - CardTitle, - CardAction, - CardDescription, - CardContent, -}; +export { Card, CardHeader, CardFooter, CardTitle, CardAction, CardDescription, CardContent }; export type { - CardProps, - CardHeaderProps, - CardTitleProps, - CardDescriptionProps, - CardActionProps, - CardContentProps, - CardFooterProps, -}; -` - } - ], - "registryDependencies": [ - "button", - "text", - "focus-styles" - ] - } - } - }, - { - "name": "checkbox-group", - "type": "registry:ui", - "defaultVariant": "basic", - "variants": { - "basic": { - "files": [ - { - "type": "registry:ui", - "path": "ui/checkbox-group/basic.tsx", - "target": "ui/checkbox-group.tsx", - "content": `"use client"; - -import { - CheckboxGroup as AriaCheckboxGroup, - composeRenderProps, -} from "react-aria-components"; + CardProps, + CardHeaderProps, + CardTitleProps, + CardDescriptionProps, + CardActionProps, + CardContentProps, + CardFooterProps, +}; +`, + }, + ], + registryDependencies: ["button", "text", "focus-styles"], + }, + }, + }, + { + name: "checkbox-group", + type: "registry:ui", + defaultVariant: "basic", + variants: { + basic: { + files: [ + { + type: "registry:ui", + path: "ui/checkbox-group/basic.tsx", + target: "ui/checkbox-group.tsx", + content: `"use client"; + +import { CheckboxGroup as AriaCheckboxGroup, composeRenderProps } from "react-aria-components"; import type { CheckboxGroupProps } from "react-aria-components"; import { fieldStyles } from "@dotui/registry/ui/field"; @@ -1416,46 +1154,35 @@ import { fieldStyles } from "@dotui/registry/ui/field"; const { field } = fieldStyles(); const CheckboxGroup = ({ className, ...props }: CheckboxGroupProps) => { - return ( - - field({ className }), - )} - {...props} - /> - ); + return ( + field({ className }))} {...props} /> + ); }; export type { CheckboxGroupProps }; export { CheckboxGroup }; -` - } - ], - "registryDependencies": [ - "field", - "checkbox" - ] - } - } - }, - { - "name": "checkbox", - "type": "registry:ui", - "defaultVariant": "basic", - "variants": { - "basic": { - "files": [ - { - "type": "registry:ui", - "path": "ui/checkbox/basic.tsx", - "target": "ui/checkbox.tsx", - "content": `"use client"; +`, + }, + ], + registryDependencies: ["field", "checkbox"], + }, + }, + }, + { + name: "checkbox", + type: "registry:ui", + defaultVariant: "basic", + variants: { + basic: { + files: [ + { + type: "registry:ui", + path: "ui/checkbox/basic.tsx", + target: "ui/checkbox.tsx", + content: `"use client"; import { CheckIcon, MinusIcon } from "lucide-react"; -import { - Checkbox as AriaCheckbox, - composeRenderProps, -} from "react-aria-components"; +import { Checkbox as AriaCheckbox, composeRenderProps } from "react-aria-components"; import { tv } from "tailwind-variants"; import type * as React from "react"; import type { CheckboxRenderProps } from "react-aria-components"; @@ -1464,66 +1191,63 @@ import { createContext } from "@dotui/registry/lib/context"; import { cn } from "@dotui/registry/lib/utils"; const checkboxStyles = tv({ - slots: { - root: [ - "focus-reset focus-visible:focus-ring", - "flex items-center gap-2 text-sm leading-none has-data-[slot=description]:items-start", - "disabled:cursor-not-allowed disabled:text-fg-disabled", - ], - indicator: [ - "flex size-4 shrink-0 items-center justify-center rounded-sm border border-border-control bg-transparent text-transparent", - "transition-[background-color,border-color,box-shadow,color] duration-75", - // selected state - "selected:border-transparent selected:bg-primary selected:text-fg-on-primary", - // read-only state - "read-only:cursor-default", - // disabled state - "disabled:cursor-not-allowed disabled:border-border-disabled selected:disabled:bg-disabled selected:disabled:text-fg-disabled indeterminate:disabled:bg-disabled", - // invalid state - "invalid:border-border-danger invalid:selected:bg-danger-muted invalid:selected:text-fg-onMutedDanger", - // indeterminate state - "indeterminate:border-transparent indeterminate:bg-primary indeterminate:text-fg-on-primary", - ], - }, + slots: { + root: [ + "focus-reset focus-visible:focus-ring", + "flex items-center gap-2 text-sm leading-none has-data-[slot=description]:items-start", + "disabled:cursor-not-allowed disabled:text-fg-disabled", + ], + indicator: [ + "flex size-4 shrink-0 items-center justify-center rounded-sm border border-border-control bg-transparent text-transparent", + "transition-[background-color,border-color,box-shadow,color] duration-75", + // selected state + "selected:border-transparent selected:bg-primary selected:text-fg-on-primary", + // read-only state + "read-only:cursor-default", + // disabled state + "disabled:cursor-not-allowed disabled:border-border-disabled selected:disabled:bg-disabled selected:disabled:text-fg-disabled indeterminate:disabled:bg-disabled", + // invalid state + "invalid:border-border-danger invalid:selected:bg-danger-muted invalid:selected:text-fg-onMutedDanger", + // indeterminate state + "indeterminate:border-transparent indeterminate:bg-primary indeterminate:text-fg-on-primary", + ], + }, }); const { root, indicator } = checkboxStyles(); -const [InternalCheckboxProvider, useInternalCheckbox] = - createContext({ - strict: true, - }); +const [InternalCheckboxProvider, useInternalCheckbox] = createContext({ + strict: true, +}); /* -----------------------------------------------------------------------------------------------*/ interface CheckboxProps extends React.ComponentProps {} const Checkbox = ({ className, ...props }: CheckboxProps) => { - return ( - - props.children - ? root({ className }) - : indicator({ - className: cn(className, "focus-reset focus-visible:focus-ring"), - }), - )} - {...props} - > - {composeRenderProps(props.children, (children, renderProps) => { - return children ? ( - - {children} - - ) : renderProps.isIndeterminate ? ( - - ) : ( - - ); - })} - - ); + return ( + + props.children + ? root({ className }) + : indicator({ + className: cn(className, "focus-reset focus-visible:focus-ring"), + }), + )} + {...props} + > + {composeRenderProps(props.children, (children, renderProps) => { + return children ? ( + {children} + ) : renderProps.isIndeterminate ? ( + + ) : ( + + ); + })} + + ); }; /* -----------------------------------------------------------------------------------------------*/ @@ -1531,30 +1255,26 @@ const Checkbox = ({ className, ...props }: CheckboxProps) => { interface CheckboxIndicatorProps extends React.ComponentProps<"div"> {} const CheckboxIndicator = ({ className, ...props }: CheckboxIndicatorProps) => { - const ctx = useInternalCheckbox("CheckboxIndicator"); - return ( -
- {ctx.isIndeterminate ? ( - - ) : ( - - )} -
- ); + const ctx = useInternalCheckbox("CheckboxIndicator"); + return ( +
+ {ctx.isIndeterminate ? : } +
+ ); }; /* -----------------------------------------------------------------------------------------------*/ @@ -1562,38 +1282,33 @@ const CheckboxIndicator = ({ className, ...props }: CheckboxIndicatorProps) => { export { Checkbox, CheckboxIndicator }; export type { CheckboxProps, CheckboxIndicatorProps }; -` - } - ], - "registryDependencies": [ - "focus-styles" - ] - } - } - }, - { - "name": "color-area", - "type": "registry:ui", - "defaultVariant": "basic", - "variants": { - "basic": { - "files": [ - { - "type": "registry:ui", - "path": "ui/color-area/basic.tsx", - "target": "ui/color-area.tsx", - "content": `"use client"; - -import { - ColorArea as AriaColorArea, - composeRenderProps, -} from "react-aria-components"; +`, + }, + ], + registryDependencies: ["focus-styles"], + }, + }, + }, + { + name: "color-area", + type: "registry:ui", + defaultVariant: "basic", + variants: { + basic: { + files: [ + { + type: "registry:ui", + path: "ui/color-area/basic.tsx", + target: "ui/color-area.tsx", + content: `"use client"; + +import { ColorArea as AriaColorArea, composeRenderProps } from "react-aria-components"; import { tv } from "tailwind-variants"; import { ColorThumb } from "@dotui/registry/ui/color-thumb"; const colorAreaStyles = tv({ - base: "block size-48 min-w-20 rounded-md disabled:[background:var(--color-disabled)]!", + base: "block size-48 min-w-20 rounded-md disabled:[background:var(--color-disabled)]!", }); /* -----------------------------------------------------------------------------------------------*/ @@ -1601,16 +1316,11 @@ const colorAreaStyles = tv({ type ColorAreaProps = React.ComponentProps; const ColorArea = ({ className, ...props }: ColorAreaProps) => { - return ( - - colorAreaStyles({ className }), - )} - {...props} - > - {props.children || } - - ); + return ( + colorAreaStyles({ className }))} {...props}> + {props.children || } + + ); }; /* -----------------------------------------------------------------------------------------------*/ @@ -1618,27 +1328,25 @@ const ColorArea = ({ className, ...props }: ColorAreaProps) => { export { ColorArea }; export type { ColorAreaProps }; -` - } - ], - "registryDependencies": [ - "color-thumb" - ] - } - } - }, - { - "name": "color-editor", - "type": "registry:ui", - "defaultVariant": "basic", - "variants": { - "basic": { - "files": [ - { - "type": "registry:ui", - "path": "ui/color-editor/basic.tsx", - "target": "ui/color-editor.tsx", - "content": `import React from "react"; +`, + }, + ], + registryDependencies: ["color-thumb"], + }, + }, + }, + { + name: "color-editor", + type: "registry:ui", + defaultVariant: "basic", + variants: { + basic: { + files: [ + { + type: "registry:ui", + path: "ui/color-editor/basic.tsx", + target: "ui/color-editor.tsx", + content: `import React from "react"; import { getColorChannels } from "react-aria-components"; import { cn } from "@dotui/registry/lib/utils"; @@ -1646,438 +1354,345 @@ import { ColorArea } from "@dotui/registry/ui/color-area"; import { ColorField } from "@dotui/registry/ui/color-field"; import { ColorSlider } from "@dotui/registry/ui/color-slider"; import { Input } from "@dotui/registry/ui/input"; -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, -} from "@dotui/registry/ui/select"; +import { Select, SelectContent, SelectItem, SelectTrigger } from "@dotui/registry/ui/select"; type ColorFormat = "hex" | "rgb" | "hsl" | "hsb"; interface ColorEditorProps extends React.ComponentProps<"div"> { - colorFormat?: ColorFormat; - showAlphaChannel?: boolean; - showFormatSelector?: boolean; + colorFormat?: ColorFormat; + showAlphaChannel?: boolean; + showFormatSelector?: boolean; } const ColorEditor = ({ - colorFormat: ColorFormatProp = "hex", - showAlphaChannel = false, - showFormatSelector = true, - className, - ...props + colorFormat: ColorFormatProp = "hex", + showAlphaChannel = false, + showFormatSelector = true, + className, + ...props }: ColorEditorProps) => { - const [colorFormat, setColorFormat] = - React.useState(ColorFormatProp); - - return ( -
-
- - - {showAlphaChannel && ( - - )} -
-
- {showFormatSelector && ( - - )} -
- {colorFormat === "hex" ? ( - - - - ) : ( - getColorChannels(colorFormat).map((channel) => ( - - - - )) - )} -
-
-
- ); + const [colorFormat, setColorFormat] = React.useState(ColorFormatProp); + + return ( +
+
+ + + {showAlphaChannel && ( + + )} +
+
+ {showFormatSelector && ( + + )} +
+ {colorFormat === "hex" ? ( + + + + ) : ( + getColorChannels(colorFormat).map((channel) => ( + + + + )) + )} +
+
+
+ ); }; export { ColorEditor }; export type { ColorEditorProps }; -` - } - ], - "registryDependencies": [ - "color-area", - "color-slider", - "select" - ] - } - } - }, - { - "name": "color-field", - "type": "registry:ui", - "defaultVariant": "basic", - "variants": { - "basic": { - "files": [ - { - "type": "registry:ui", - "path": "ui/color-field/basic.tsx", - "target": "ui/color-field.tsx", - "content": `"use client"; - -import { - ColorField as AriaColorField, - composeRenderProps, -} from "react-aria-components"; +`, + }, + ], + registryDependencies: ["color-area", "color-slider", "select"], + }, + }, + }, + { + name: "color-field", + type: "registry:ui", + defaultVariant: "basic", + variants: { + basic: { + files: [ + { + type: "registry:ui", + path: "ui/color-field/basic.tsx", + target: "ui/color-field.tsx", + content: `"use client"; + +import { ColorField as AriaColorField, composeRenderProps } from "react-aria-components"; import { tv } from "tailwind-variants"; import type * as React from "react"; import { fieldStyles } from "@dotui/registry/ui/field/basic"; const colorFieldStyles = tv({ - base: [fieldStyles().field({ orientation: "vertical" }), ""], + base: [fieldStyles().field({ orientation: "vertical" }), ""], }); interface ColorFieldProps extends React.ComponentProps {} const ColorField = ({ className, ...props }: ColorFieldProps) => { - return ( - - colorFieldStyles({ className }), - )} - {...props} - /> - ); + return ( + colorFieldStyles({ className }))} + {...props} + /> + ); }; export { ColorField }; export type { ColorFieldProps }; -` - } - ], - "registryDependencies": [ - "field", - "input" - ] - } - } - }, - { - "name": "color-picker", - "type": "registry:ui", - "defaultVariant": "basic", - "variants": { - "basic": { - "files": [ - { - "type": "registry:ui", - "path": "ui/color-picker/basic.tsx", - "target": "ui/color-picker.tsx", - "content": `"use client"; +`, + }, + ], + registryDependencies: ["field", "input"], + }, + }, + }, + { + name: "color-picker", + type: "registry:ui", + defaultVariant: "basic", + variants: { + basic: { + files: [ + { + type: "registry:ui", + path: "ui/color-picker/basic.tsx", + target: "ui/color-picker.tsx", + content: `"use client"; import { useContext } from "react"; import { - ColorPicker as AriaColorPicker, - ColorPickerStateContext as AriaColorPickerStateContext, - composeRenderProps, -} from "react-aria-components"; -import type { - ColorPickerProps as AriaColorPickerProps, - ColorPickerState, + ColorPicker as AriaColorPicker, + ColorPickerStateContext as AriaColorPickerStateContext, + composeRenderProps, } from "react-aria-components"; +import type { ColorPickerProps as AriaColorPickerProps, ColorPickerState } from "react-aria-components"; import { Button } from "@dotui/registry/ui/button"; import { ColorSwatch } from "@dotui/registry/ui/color-swatch"; import { Dialog, DialogContent } from "@dotui/registry/ui/dialog"; import { Overlay } from "@dotui/registry/ui/overlay"; import type { ButtonProps } from "@dotui/registry/ui/button"; -import type { - DialogContentProps, - DialogProps, -} from "@dotui/registry/ui/dialog"; - -interface ColorPickerProps - extends AriaColorPickerProps, - Omit {} - -const ColorPicker = ({ - defaultOpen, - isOpen, - onOpenChange, - ...props -}: ColorPickerProps) => { - return ( - - {composeRenderProps(props.children, (children) => ( - - {children} - - ))} - - ); +import type { DialogContentProps, DialogProps } from "@dotui/registry/ui/dialog"; + +interface ColorPickerProps extends AriaColorPickerProps, Omit {} + +const ColorPicker = ({ defaultOpen, isOpen, onOpenChange, ...props }: ColorPickerProps) => { + return ( + + {composeRenderProps(props.children, (children) => ( + + {children} + + ))} + + ); }; /* -----------------------------------------------------------------------------------------------*/ interface ColorPickerTriggerProps extends Omit { - children?: React.ReactNode | ((props: ColorPickerState) => React.ReactNode); + children?: React.ReactNode | ((props: ColorPickerState) => React.ReactNode); } -const ColorPickerTrigger = ({ - children, - ...props -}: ColorPickerTriggerProps) => { - const state = useContext(AriaColorPickerStateContext)!; - return ( - - ); +const ColorPickerTrigger = ({ children, ...props }: ColorPickerTriggerProps) => { + const state = useContext(AriaColorPickerStateContext)!; + return ( + + ); }; /* -----------------------------------------------------------------------------------------------*/ interface ColorPickerContentProps extends DialogContentProps {} -const ColorPickerContent = ({ - children, - ...props -}: ColorPickerContentProps) => { - return ( - - {children} - - ); +const ColorPickerContent = ({ children, ...props }: ColorPickerContentProps) => { + return ( + + {children} + + ); }; /* -----------------------------------------------------------------------------------------------*/ export { ColorPicker, ColorPickerTrigger, ColorPickerContent }; -export type { - ColorPickerProps, - ColorPickerTriggerProps, - ColorPickerContentProps, -}; -` - } - ], - "registryDependencies": [ - "button", - "color-area", - "color-field", - "color-slider", - "color-swatch", - "dialog", - "select" - ] - } - } - }, - { - "name": "color-slider", - "type": "registry:ui", - "defaultVariant": "basic", - "variants": { - "basic": { - "files": [ - { - "type": "registry:ui", - "path": "ui/color-slider/basic.tsx", - "target": "ui/color-slider.tsx", - "content": `"use client"; +export type { ColorPickerProps, ColorPickerTriggerProps, ColorPickerContentProps }; +`, + }, + ], + registryDependencies: [ + "button", + "color-area", + "color-field", + "color-slider", + "color-swatch", + "dialog", + "select", + ], + }, + }, + }, + { + name: "color-slider", + type: "registry:ui", + defaultVariant: "basic", + variants: { + basic: { + files: [ + { + type: "registry:ui", + path: "ui/color-slider/basic.tsx", + target: "ui/color-slider.tsx", + content: `"use client"; import { useSlotId } from "@react-aria/utils"; import { - ColorSlider as AriaColorSlider, - SliderOutput as AriaSliderOutput, - SliderTrack as AriaSliderTrack, - composeRenderProps, - Provider, - TextContext, + ColorSlider as AriaColorSlider, + SliderOutput as AriaSliderOutput, + SliderTrack as AriaSliderTrack, + composeRenderProps, + Provider, + TextContext, } from "react-aria-components"; import { tv } from "tailwind-variants"; import { ColorThumb } from "@dotui/registry/ui/color-thumb"; const colorSliderStyles = tv({ - slots: { - root: "flex flex-col gap-2", - output: "text-fg-muted text-sm", - track: - "relative rounded-md before:absolute before:inset-0 before:z-[-1] before:rounded-[inherit] before:bg-[repeating-conic-gradient(#e6e6e6_0%_25%,#fff_0%_50%)] before:bg-center before:bg-size-[16px_16px] before:content-[''] orientation-horizontal:**:data-[slot=color-thumb]:top-1/2 orientation-vertical:**:data-[slot=color-thumb]:left-1/2 disabled:[background:var(--color-disabled)]!", - }, - variants: { - orientation: { - horizontal: { - root: "w-48", - track: "h-6 w-full", - }, - vertical: { - root: "h-48 items-center", - track: "w-6 flex-1", - }, - }, - }, - defaultVariants: { - orientation: "horizontal", - }, + slots: { + root: "flex flex-col gap-2", + output: "text-fg-muted text-sm", + track: + "relative rounded-md before:absolute before:inset-0 before:z-[-1] before:rounded-[inherit] before:bg-[repeating-conic-gradient(#e6e6e6_0%_25%,#fff_0%_50%)] before:bg-center before:bg-size-[16px_16px] before:content-[''] orientation-horizontal:**:data-[slot=color-thumb]:top-1/2 orientation-vertical:**:data-[slot=color-thumb]:left-1/2 disabled:[background:var(--color-disabled)]!", + }, + variants: { + orientation: { + horizontal: { + root: "w-48", + track: "h-6 w-full", + }, + vertical: { + root: "h-48 items-center", + track: "w-6 flex-1", + }, + }, + }, + defaultVariants: { + orientation: "horizontal", + }, }); const { root, track, output } = colorSliderStyles(); /* -----------------------------------------------------------------------------------------------*/ -interface ColorSliderProps - extends React.ComponentProps {} +interface ColorSliderProps extends React.ComponentProps {} const ColorSlider = ({ className, ...props }: ColorSliderProps) => { - const descriptionId = useSlotId(); - return ( - - - root({ orientation, className: cn }), - )} - aria-describedby={descriptionId} - {...props} - > - {props.children ?? } - - - ); -}; - -/* -----------------------------------------------------------------------------------------------*/ - -interface ColorSliderControlProps - extends React.ComponentProps {} - -const ColorSliderControl = ({ - className, - ...props -}: ColorSliderControlProps) => { - return ( - - track({ orientation, className: cn }), - )} - {...props} - > - {props.children ?? } - - ); -}; - -/* -----------------------------------------------------------------------------------------------*/ - -interface ColorSliderOutputProps - extends React.ComponentProps {} + const descriptionId = useSlotId(); + return ( + + root({ orientation, className: cn }))} + aria-describedby={descriptionId} + {...props} + > + {props.children ?? } + + + ); +}; + +/* -----------------------------------------------------------------------------------------------*/ + +interface ColorSliderControlProps extends React.ComponentProps {} + +const ColorSliderControl = ({ className, ...props }: ColorSliderControlProps) => { + return ( + track({ orientation, className: cn }))} + {...props} + > + {props.children ?? } + + ); +}; + +/* -----------------------------------------------------------------------------------------------*/ + +interface ColorSliderOutputProps extends React.ComponentProps {} const ColorSliderOutput = ({ className, ...props }: ColorSliderOutputProps) => { - return ( - - output({ className }), - )} - {...props} - /> - ); + return ( + output({ className }))} {...props} /> + ); }; /* -----------------------------------------------------------------------------------------------*/ export { ColorSlider, ColorSliderControl, ColorSliderOutput }; -export type { - ColorSliderProps, - ColorSliderControlProps, - ColorSliderOutputProps, -}; -` - } - ], - "registryDependencies": [ - "field", - "color-thumb" - ] - } - } - }, - { - "name": "color-swatch-picker", - "type": "registry:ui", - "defaultVariant": "basic", - "variants": { - "basic": { - "files": [ - { - "type": "registry:ui", - "path": "ui/color-swatch-picker/basic.tsx", - "target": "ui/color-swatch-picker.tsx", - "content": `"use client"; +export type { ColorSliderProps, ColorSliderControlProps, ColorSliderOutputProps }; +`, + }, + ], + registryDependencies: ["field", "color-thumb"], + }, + }, + }, + { + name: "color-swatch-picker", + type: "registry:ui", + defaultVariant: "basic", + variants: { + basic: { + files: [ + { + type: "registry:ui", + path: "ui/color-swatch-picker/basic.tsx", + target: "ui/color-swatch-picker.tsx", + content: `"use client"; import { - ColorSwatchPicker as AriaColorSwatchPicker, - ColorSwatchPickerItem as AriaColorSwatchPickerItem, - composeRenderProps, + ColorSwatchPicker as AriaColorSwatchPicker, + ColorSwatchPickerItem as AriaColorSwatchPickerItem, + composeRenderProps, } from "react-aria-components"; import { tv } from "tailwind-variants"; import type React from "react"; @@ -2085,210 +1700,177 @@ import type React from "react"; import { ColorSwatch } from "@dotui/registry/ui/color-swatch"; const colorSwatchPickerStyles = tv({ - slots: { - root: "flex flex-wrap gap-1", - item: [ - "relative size-8 rounded-md transition-shadow focus:z-10 *:data-[slot=color-swatch]:size-full *:data-[slot=color-swatch]:rounded-[inherit]", - // focus state - "focus-reset focus-visible:focus-ring", - // disabled state - "disabled:cursor-not-allowed disabled:*:data-[slot=color-swatch]:[background:color-mix(in_oklab,var(--color-disabled)_90%,var(--color))]!", - // selected state - "before:absolute before:inset-0 before:scale-90 selected:before:scale-100 before:rounded-[inherit] before:bg-bg before:opacity-0 selected:before:opacity-100 before:outline-2 before:outline-inverse before:transition-[opacity,scale] before:duration-100 before:content-['']", - ], - }, + slots: { + root: "flex flex-wrap gap-1", + item: [ + "relative size-8 rounded-md transition-shadow focus:z-10 *:data-[slot=color-swatch]:size-full *:data-[slot=color-swatch]:rounded-[inherit]", + // focus state + "focus-reset focus-visible:focus-ring", + // disabled state + "disabled:cursor-not-allowed disabled:*:data-[slot=color-swatch]:[background:color-mix(in_oklab,var(--color-disabled)_90%,var(--color))]!", + // selected state + "before:absolute before:inset-0 before:scale-90 selected:before:scale-100 before:rounded-[inherit] before:bg-bg before:opacity-0 selected:before:opacity-100 before:outline-2 before:outline-inverse before:transition-[opacity,scale] before:duration-100 before:content-['']", + ], + }, }); const { root, item } = colorSwatchPickerStyles(); /* -----------------------------------------------------------------------------------------------*/ -interface ColorSwatchPickerProps - extends React.ComponentProps {} +interface ColorSwatchPickerProps extends React.ComponentProps {} const ColorSwatchPicker = ({ className, ...props }: ColorSwatchPickerProps) => { - return ( - - root({ className }), - )} - {...props} - /> - ); -}; - -/* -----------------------------------------------------------------------------------------------*/ - -interface ColorSwatchPickerItemProps - extends React.ComponentProps {} -const ColorSwatchPickerItem = ({ - className, - style, - ...props -}: ColorSwatchPickerItemProps) => { - return ( - - item({ className }), - )} - style={composeRenderProps( - style, - (style, { color }) => - ({ - "--color": color.toString(), - ...style, - }) as React.CSSProperties, - )} - {...props} - > - - - ); + return ( + root({ className }))} {...props} /> + ); +}; + +/* -----------------------------------------------------------------------------------------------*/ + +interface ColorSwatchPickerItemProps extends React.ComponentProps {} +const ColorSwatchPickerItem = ({ className, style, ...props }: ColorSwatchPickerItemProps) => { + return ( + item({ className }))} + style={composeRenderProps( + style, + (style, { color }) => + ({ + "--color": color.toString(), + ...style, + }) as React.CSSProperties, + )} + {...props} + > + + + ); }; /* -----------------------------------------------------------------------------------------------*/ const CompoundColorSwatchPicker = Object.assign(ColorSwatchPicker, { - Item: ColorSwatchPickerItem, + Item: ColorSwatchPickerItem, }); export type { ColorSwatchPickerProps, ColorSwatchPickerItemProps }; -export { - CompoundColorSwatchPicker as ColorSwatchPicker, - ColorSwatchPickerItem, -}; -` - } - ], - "registryDependencies": [ - "focus-styles", - "color-swatch" - ] - } - } - }, - { - "name": "color-swatch", - "type": "registry:ui", - "defaultVariant": "basic", - "variants": { - "basic": { - "files": [ - { - "type": "registry:ui", - "path": "ui/color-swatch/basic.tsx", - "target": "ui/color-swatch.tsx", - "content": `"use client"; - -import { - ColorSwatch as AriaColorSwatch, - composeRenderProps, -} from "react-aria-components"; +export { CompoundColorSwatchPicker as ColorSwatchPicker, ColorSwatchPickerItem }; +`, + }, + ], + registryDependencies: ["focus-styles", "color-swatch"], + }, + }, + }, + { + name: "color-swatch", + type: "registry:ui", + defaultVariant: "basic", + variants: { + basic: { + files: [ + { + type: "registry:ui", + path: "ui/color-swatch/basic.tsx", + target: "ui/color-swatch.tsx", + content: `"use client"; + +import { ColorSwatch as AriaColorSwatch, composeRenderProps } from "react-aria-components"; import { tv } from "tailwind-variants"; const colorSwatchStyles = tv({ - base: "relative size-5 rounded-sm border", + base: "relative size-5 rounded-sm border", }); -interface ColorSwatchProps - extends React.ComponentProps {} +interface ColorSwatchProps extends React.ComponentProps {} const ColorSwatch = ({ className, style, ...props }: ColorSwatchProps) => { - return ( - - colorSwatchStyles({ className }), - )} - style={composeRenderProps(style, (style, { color }) => ({ - ...style, - background: \`linear-gradient(\${color}, \${color}), + return ( + colorSwatchStyles({ className }))} + style={composeRenderProps(style, (style, { color }) => ({ + ...style, + background: \`linear-gradient(\${color}, \${color}), repeating-conic-gradient(#CCC 0% 25%, white 0% 50%) 50% / 16px 16px\`, - }))} - {...props} - /> - ); + }))} + {...props} + /> + ); }; export type { ColorSwatchProps }; export { ColorSwatch }; -` - } - ] - } - } - }, - { - "name": "color-thumb", - "type": "registry:ui", - "defaultVariant": "basic", - "variants": { - "basic": { - "files": [ - { - "type": "registry:ui", - "path": "ui/color-thumb/basic.tsx", - "target": "ui/color-thumb.tsx", - "content": `"use client"; +`, + }, + ], + }, + }, + }, + { + name: "color-thumb", + type: "registry:ui", + defaultVariant: "basic", + variants: { + basic: { + files: [ + { + type: "registry:ui", + path: "ui/color-thumb/basic.tsx", + target: "ui/color-thumb.tsx", + content: `"use client"; import { ColorThumb as AriaColorThumb } from "react-aria-components"; import { tv } from "tailwind-variants"; import type { ColorThumbProps as AriaColorThumbProps } from "react-aria-components"; const colorThumbStyles = tv({ - base: [ - "focus-reset focus-visible:focus-ring", - "z-30 size-6 rounded-full border-2 border-white ring-1 ring-black/40 disabled:border-border-disabled disabled:bg-disabled!", - "group-orientation-horizontal/color-slider:top-1/2 group-orientation-vertical/color-slider:left-1/2", - ], + base: [ + "focus-reset focus-visible:focus-ring", + "z-30 size-6 rounded-full border-2 border-white ring-1 ring-black/40 disabled:border-border-disabled disabled:bg-disabled!", + "group-orientation-horizontal/color-slider:top-1/2 group-orientation-vertical/color-slider:left-1/2", + ], }); interface ColorThumbProps extends Omit { - className?: string; + className?: string; } const ColorThumb = ({ className, ...props }: ColorThumbProps) => { - return ( - - ); + return ; }; export type { ColorThumbProps }; export { ColorThumb }; -` - } - ], - "registryDependencies": [ - "focus-styles" - ] - } - } - }, - { - "name": "combobox", - "type": "registry:ui", - "defaultVariant": "basic", - "variants": { - "basic": { - "files": [ - { - "type": "registry:ui", - "path": "ui/combobox/basic.tsx", - "target": "ui/combobox.tsx", - "content": `"use client"; +`, + }, + ], + registryDependencies: ["focus-styles"], + }, + }, + }, + { + name: "combobox", + type: "registry:ui", + defaultVariant: "basic", + variants: { + basic: { + files: [ + { + type: "registry:ui", + path: "ui/combobox/basic.tsx", + target: "ui/combobox.tsx", + content: `"use client"; import React from "react"; import { useResizeObserver } from "@react-aria/utils"; import { ChevronDownIcon } from "lucide-react"; import { mergeProps } from "react-aria"; import { - ComboBox as AriaCombobox, - GroupContext as AriaGroupContext, - PopoverContext as AriaPopoverContext, - composeRenderProps, - Provider, + ComboBox as AriaCombobox, + GroupContext as AriaGroupContext, + PopoverContext as AriaPopoverContext, + composeRenderProps, + Provider, } from "react-aria-components"; import type { ComboBoxProps as AriaComboboxProps } from "react-aria-components"; @@ -2297,11 +1879,11 @@ import { Button } from "@dotui/registry/ui/button"; import { fieldStyles } from "@dotui/registry/ui/field"; import { Input, InputAddon, InputGroup } from "@dotui/registry/ui/input"; import { - ListBox, - ListBoxItem, - ListBoxSection, - ListBoxSectionHeader, - ListBoxVirtualizer, + ListBox, + ListBoxItem, + ListBoxSection, + ListBoxSectionHeader, + ListBoxVirtualizer, } from "@dotui/registry/ui/list-box"; import { Popover } from "@dotui/registry/ui/popover"; import type { InputGroupProps } from "@dotui/registry/ui/input"; @@ -2310,28 +1892,23 @@ import type { PopoverProps } from "@dotui/registry/ui/popover"; /* -----------------------------------------------------------------------------------------------*/ -interface ComboboxProps - extends Omit, "className"> { - className?: string; +interface ComboboxProps extends Omit, "className"> { + className?: string; } -const Combobox = ({ - menuTrigger = "focus", - className, - ...props -}: ComboboxProps) => { - return ( - - {composeRenderProps(props.children, (children) => ( - {children} - ))} - - ); +const Combobox = ({ menuTrigger = "focus", className, ...props }: ComboboxProps) => { + return ( + + {composeRenderProps(props.children, (children) => ( + {children} + ))} + + ); }; /* -----------------------------------------------------------------------------------------------*/ @@ -2342,163 +1919,149 @@ const Combobox = ({ */ const ComboboxInner = ({ children }: { children: React.ReactNode }) => { - const [menuWidth, setMenuWidth] = React.useState( - undefined, - ); - - const groupProps = React.use(AriaGroupContext); - const popoverProps = React.use(AriaPopoverContext); - const triggerRef = React.useRef(null); - - const onResize = React.useCallback(() => { - if (triggerRef.current) { - const triggerWidth = triggerRef.current.getBoundingClientRect().width; - setMenuWidth(\`\${triggerWidth}px\`); - } - }, []); - - useResizeObserver({ - ref: triggerRef, - onResize: onResize, - }); - - return ( - - {children} - - ); + const [menuWidth, setMenuWidth] = React.useState(undefined); + + const groupProps = React.use(AriaGroupContext); + const popoverProps = React.use(AriaPopoverContext); + const triggerRef = React.useRef(null); + + const onResize = React.useCallback(() => { + if (triggerRef.current) { + const triggerWidth = triggerRef.current.getBoundingClientRect().width; + setMenuWidth(\`\${triggerWidth}px\`); + } + }, []); + + useResizeObserver({ + ref: triggerRef, + onResize: onResize, + }); + + return ( + + {children} + + ); }; /* -----------------------------------------------------------------------------------------------*/ interface ComboboxInputProps extends InputGroupProps { - placeholder?: string; + placeholder?: string; } const ComboboxInput = ({ placeholder, ...props }: ComboboxInputProps) => { - return ( - - - - - - - ); + return ( + + + + + + + ); }; /* -----------------------------------------------------------------------------------------------*/ interface ComboboxContentProps - extends ListBoxProps, - Pick< - PopoverProps, - "placement" | "defaultOpen" | "isOpen" | "onOpenChange" - > { - virtulized?: boolean; + extends ListBoxProps, + Pick { + virtulized?: boolean; } const ComboboxContent = ({ - virtulized, - placement, - defaultOpen, - isOpen, - onOpenChange, - ...props + virtulized, + placement, + defaultOpen, + isOpen, + onOpenChange, + ...props }: ComboboxContentProps) => { - if (virtulized) { - return ( - - - - - - ); - } - - return ( - - - - ); + if (virtulized) { + return ( + + + + + + ); + } + + return ( + + + + ); }; /* -----------------------------------------------------------------------------------------------*/ export { - Combobox, - ComboboxInput, - ComboboxContent, - ListBoxItem as ComboboxItem, - ListBoxSection as ComboboxSection, - ListBoxSectionHeader as ComboboxSectionHeader, + Combobox, + ComboboxInput, + ComboboxContent, + ListBoxItem as ComboboxItem, + ListBoxSection as ComboboxSection, + ListBoxSectionHeader as ComboboxSectionHeader, }; export type { ComboboxProps, ComboboxInputProps, ComboboxContentProps }; -` - } - ], - "registryDependencies": [ - "field", - "button", - "input", - "list-box", - "overlay" - ] - } - } - }, - { - "name": "command", - "type": "registry:ui", - "defaultVariant": "basic", - "variants": { - "basic": { - "files": [ - { - "type": "registry:ui", - "path": "ui/command/basic.tsx", - "target": "ui/command.tsx", - "content": `"use client"; +`, + }, + ], + registryDependencies: ["field", "button", "input", "list-box", "overlay"], + }, + }, + }, + { + name: "command", + type: "registry:ui", + defaultVariant: "basic", + variants: { + basic: { + files: [ + { + type: "registry:ui", + path: "ui/command/basic.tsx", + target: "ui/command.tsx", + content: `"use client"; import { SearchIcon } from "lucide-react"; -import { - Autocomplete as AriaAutocomplete, - useFilter, -} from "react-aria-components"; +import { Autocomplete as AriaAutocomplete, useFilter } from "react-aria-components"; import { tv } from "tailwind-variants"; import { Input, InputAddon, InputGroup } from "@dotui/registry/ui/input"; import { - ListBox, - ListBoxItem, - ListBoxSection, - ListBoxSectionHeader, - ListBoxVirtualizer, + ListBox, + ListBoxItem, + ListBoxSection, + ListBoxSectionHeader, + ListBoxVirtualizer, } from "@dotui/registry/ui/list-box"; import { SearchField } from "@dotui/registry/ui/search-field"; import type { ListBoxProps } from "@dotui/registry/ui/list-box"; @@ -2506,14 +2069,14 @@ import type { PopoverProps } from "@dotui/registry/ui/popover"; import type { SearchFieldProps } from "@dotui/registry/ui/search-field"; const commandStyles = tv({ - slots: { - base: [ - "in-drawer:rounded-[inherit] in-modal:rounded-[inherit] in-popover:rounded-[inherit] rounded-lg not-in-popover:not-in-modal:not-in-drawer:border not-in-popover:not-in-modal:not-in-drawer:bg-card", - "**:data-[slot=list-box]:w-full **:data-[slot=list-box]:border-0 **:data-[slot=list-box]:bg-transparent", - "**:data-[slot=search-field]:w-full **:data-[slot=search-field]:outline-none [&_[data-slot=search-field]_[data-slot=input-group]]:rounded-b-none [&_[data-slot=search-field]_[data-slot=input-group]]:border-0 [&_[data-slot=search-field]_[data-slot=input-group]]:border-b [&_[data-slot=search-field]_[data-slot=input-group]]:bg-transparent", - "in-modal:w-full", - ], - }, + slots: { + base: [ + "in-drawer:rounded-[inherit] in-modal:rounded-[inherit] in-popover:rounded-[inherit] rounded-lg not-in-popover:not-in-modal:not-in-drawer:border not-in-popover:not-in-modal:not-in-drawer:bg-card", + "**:data-[slot=list-box]:w-full **:data-[slot=list-box]:border-0 **:data-[slot=list-box]:bg-transparent", + "**:data-[slot=search-field]:w-full **:data-[slot=search-field]:outline-none [&_[data-slot=search-field]_[data-slot=input-group]]:rounded-b-none [&_[data-slot=search-field]_[data-slot=input-group]]:border-0 [&_[data-slot=search-field]_[data-slot=input-group]]:border-b [&_[data-slot=search-field]_[data-slot=input-group]]:bg-transparent", + "in-modal:w-full", + ], + }, }); const { base } = commandStyles(); @@ -2523,213 +2086,186 @@ const { base } = commandStyles(); interface CommandProps extends React.ComponentProps<"div"> {} function Command({ className, ...props }: CommandProps) { - const { contains } = useFilter({ - sensitivity: "base", - ignorePunctuation: true, - }); - - return ( - -
-
- ); + const { contains } = useFilter({ + sensitivity: "base", + ignorePunctuation: true, + }); + + return ( + +
+
+ ); } /* -----------------------------------------------------------------------------------------------*/ interface CommandInputProps extends SearchFieldProps { - placeholder?: string; + placeholder?: string; } const CommandInput = ({ placeholder, ...props }: CommandInputProps) => { - return ( - - {/* TODO: Remove this */} - - - - - - - - ); + return ( + + {/* TODO: Remove this */} + + + + + + + + ); }; /* -----------------------------------------------------------------------------------------------*/ interface CommandContentProps extends ListBoxProps { - placement?: PopoverProps["placement"]; - virtulized?: boolean; + placement?: PopoverProps["placement"]; + virtulized?: boolean; } -const CommandContent = ({ - virtulized, - placement, - ...props -}: CommandContentProps) => { - if (virtulized) { - return ( - - - - ); - } +const CommandContent = ({ virtulized, placement, ...props }: CommandContentProps) => { + if (virtulized) { + return ( + + + + ); + } - return ; + return ; }; /* -----------------------------------------------------------------------------------------------*/ export { - Command, - CommandInput, - CommandContent, - ListBoxItem as CommandItem, - ListBoxSection as CommandSection, - ListBoxSectionHeader as CommandSectionHeader, + Command, + CommandInput, + CommandContent, + ListBoxItem as CommandItem, + ListBoxSection as CommandSection, + ListBoxSectionHeader as CommandSectionHeader, }; export type { CommandProps, CommandContentProps, CommandInputProps }; -` - } - ] - } - } - }, - { - "name": "date-field", - "type": "registry:ui", - "defaultVariant": "basic", - "variants": { - "basic": { - "files": [ - { - "type": "registry:ui", - "path": "ui/date-field/basic.tsx", - "target": "ui/date-field.tsx", - "content": `"use client"; - -import { - DateField as AriaDateField, - composeRenderProps, -} from "react-aria-components"; +`, + }, + ], + }, + }, + }, + { + name: "date-field", + type: "registry:ui", + defaultVariant: "basic", + variants: { + basic: { + files: [ + { + type: "registry:ui", + path: "ui/date-field/basic.tsx", + target: "ui/date-field.tsx", + content: `"use client"; + +import { DateField as AriaDateField, composeRenderProps } from "react-aria-components"; import { tv } from "tailwind-variants"; -import type { - DateFieldProps as AriaDateFieldProps, - DateValue, -} from "react-aria-components"; +import type { DateFieldProps as AriaDateFieldProps, DateValue } from "react-aria-components"; import { fieldStyles } from "@dotui/registry/ui/field"; const dateFieldStyles = tv({ - base: [fieldStyles().field({ orientation: "vertical" })], + base: [fieldStyles().field({ orientation: "vertical" })], }); /* -----------------------------------------------------------------------------------------------*/ interface DateFieldProps extends AriaDateFieldProps {} -const DateField = ({ - className, - ...props -}: DateFieldProps) => { - return ( - - dateFieldStyles({ className }), - )} - {...props} - /> - ); +const DateField = ({ className, ...props }: DateFieldProps) => { + return ( + dateFieldStyles({ className }))} + {...props} + /> + ); }; export type { DateFieldProps }; export { DateField }; -` - } - ], - "registryDependencies": [ - "field", - "input" - ] - } - } - }, - { - "name": "date-picker", - "type": "registry:ui", - "defaultVariant": "basic", - "variants": { - "basic": { - "files": [ - { - "type": "registry:ui", - "path": "ui/date-picker/basic.tsx", - "target": "ui/date-picker.tsx", - "content": `"use client"; +`, + }, + ], + registryDependencies: ["field", "input"], + }, + }, + }, + { + name: "date-picker", + type: "registry:ui", + defaultVariant: "basic", + variants: { + basic: { + files: [ + { + type: "registry:ui", + path: "ui/date-picker/basic.tsx", + target: "ui/date-picker.tsx", + content: `"use client"; import { useContext } from "react"; import { CalendarIcon } from "lucide-react"; import { - DateRangePicker as AriaDataRangePicker, - DatePicker as AriaDatePicker, - RangeCalendarContext as AriaRangeCalendarContext, - composeRenderProps, + DateRangePicker as AriaDataRangePicker, + DatePicker as AriaDatePicker, + RangeCalendarContext as AriaRangeCalendarContext, + composeRenderProps, } from "react-aria-components"; import { tv } from "tailwind-variants"; import type { - DateRangePickerProps as AriaDataRangePickerProps, - DatePickerProps as AriaDatePickerProps, - DateValue, + DateRangePickerProps as AriaDataRangePickerProps, + DatePickerProps as AriaDatePickerProps, + DateValue, } from "react-aria-components"; import { Button } from "@dotui/registry/ui/button"; -import { - DialogContent, - type DialogContentProps, -} from "@dotui/registry/ui/dialog"; +import { DialogContent, type DialogContentProps } from "@dotui/registry/ui/dialog"; import { DateInput, InputAddon, InputGroup } from "@dotui/registry/ui/input"; import { Overlay, type OverlayProps } from "@dotui/registry/ui/overlay"; import type { InputGroupProps } from "@dotui/registry/ui/input"; const datePickerStyles = tv({ - base: "flex flex-col items-start gap-2", + base: "flex flex-col items-start gap-2", }); type DatePickerProps = - | ({ - mode?: "single"; - } & AriaDatePickerProps) - | ({ - mode: "range"; - } & AriaDataRangePickerProps); - -const DatePicker = ({ - mode = "single", - className, - ...props -}: DatePickerProps) => { - if (mode === "range") { - return ( - ["className"], - (className) => datePickerStyles({ className }), - )} - {...(props as AriaDataRangePickerProps)} - /> - ); - } - - return ( - ["className"], - (className) => datePickerStyles({ className }), - )} - {...(props as AriaDatePickerProps)} - /> - ); + | ({ + mode?: "single"; + } & AriaDatePickerProps) + | ({ + mode: "range"; + } & AriaDataRangePickerProps); + +const DatePicker = ({ mode = "single", className, ...props }: DatePickerProps) => { + if (mode === "range") { + return ( + ["className"], (className) => + datePickerStyles({ className }), + )} + {...(props as AriaDataRangePickerProps)} + /> + ); + } + + return ( + ["className"], (className) => + datePickerStyles({ className }), + )} + {...(props as AriaDatePickerProps)} + /> + ); }; /* -----------------------------------------------------------------------------------------------*/ @@ -2737,109 +2273,100 @@ const DatePicker = ({ interface DatePickerInputProps extends InputGroupProps {} const DatePickerInput = (props: DatePickerInputProps) => { - const rangeCalendarContext = useContext(AriaRangeCalendarContext); - const mode = rangeCalendarContext ? "range" : "single"; - - return ( - - {mode === "single" ? ( - - ) : ( - <> - - - - - )} - - - - - ); + const rangeCalendarContext = useContext(AriaRangeCalendarContext); + const mode = rangeCalendarContext ? "range" : "single"; + + return ( + + {mode === "single" ? ( + + ) : ( + <> + + + + + )} + + + + + ); }; /* -----------------------------------------------------------------------------------------------*/ interface DatePickerContentProps - extends DialogContentProps, - Pick {} + extends DialogContentProps, + Pick {} const DatePickerContent = ({ - children, - type = "popover", - mobileType, - popoverProps, - ...props + children, + type = "popover", + mobileType, + popoverProps, + ...props }: DatePickerContentProps) => { - return ( - - {children} - - ); + return ( + + {children} + + ); }; export type { DatePickerProps, DatePickerContentProps, DatePickerInputProps }; export { DatePicker, DatePickerContent, DatePickerInput }; -` - } - ], - "registryDependencies": [ - "button", - "calendar", - "field", - "input", - "dialog" - ] - } - } - }, - { - "name": "dialog", - "type": "registry:ui", - "defaultVariant": "basic", - "variants": { - "basic": { - "files": [ - { - "type": "registry:ui", - "path": "ui/dialog/basic.tsx", - "target": "ui/dialog.tsx", - "content": `"use client"; +`, + }, + ], + registryDependencies: ["button", "calendar", "field", "input", "dialog"], + }, + }, + }, + { + name: "dialog", + type: "registry:ui", + defaultVariant: "basic", + variants: { + basic: { + files: [ + { + type: "registry:ui", + path: "ui/dialog/basic.tsx", + target: "ui/dialog.tsx", + content: `"use client"; import { - Dialog as AriaDialog, - DialogTrigger as AriaDialogTrigger, - Heading as AriaHeading, - Text as AriaText, + Dialog as AriaDialog, + DialogTrigger as AriaDialogTrigger, + Heading as AriaHeading, + Text as AriaText, } from "react-aria-components"; import { tv } from "tailwind-variants"; import type * as React from "react"; const dialogStyles = tv({ - slots: { - content: - "relative flex flex-col gap-4 in-data-popover:p-4 p-6 outline-none", - header: "flex flex-col gap-2 text-left", - heading: - "font-semibold in-popover:font-medium in-popover:text-base text-lg leading-none", - description: "text-fg-muted text-sm", - body: "flex flex-1 flex-col gap-2", - inset: "-mx-6 in-popover:-mx-4 border bg-muted in-popover:px-4 px-6 py-4", - footer: "flex flex-col-reverse gap-2 sm:flex-row sm:justify-end", - }, + slots: { + content: "relative flex flex-col gap-4 in-data-popover:p-4 p-6 outline-none", + header: "flex flex-col gap-2 text-left", + heading: "font-semibold in-popover:font-medium in-popover:text-base text-lg leading-none", + description: "text-fg-muted text-sm", + body: "flex flex-1 flex-col gap-2", + inset: "-mx-6 in-popover:-mx-4 border bg-muted in-popover:px-4 px-6 py-4", + footer: "flex flex-col-reverse gap-2 sm:flex-row sm:justify-end", + }, }); -const { content, header, heading, description, body, footer, inset } = - dialogStyles(); +const { content, header, heading, description, body, footer, inset } = dialogStyles(); /* -----------------------------------------------------------------------------------------------*/ interface DialogProps extends React.ComponentProps {} const Dialog = (props: DialogProps) => { - return ; + return ; }; /* -----------------------------------------------------------------------------------------------*/ @@ -2847,13 +2374,7 @@ const Dialog = (props: DialogProps) => { interface DialogContentProps extends React.ComponentProps {} const DialogContent = ({ className, ...props }: DialogContentProps) => { - return ( - - ); + return ; }; /* -----------------------------------------------------------------------------------------------*/ @@ -2861,7 +2382,7 @@ const DialogContent = ({ className, ...props }: DialogContentProps) => { interface DialogHeaderProps extends React.ComponentProps<"header"> {} const DialogHeader = ({ className, ...props }: DialogHeaderProps) => { - return
; + return
; }; /* -----------------------------------------------------------------------------------------------*/ @@ -2869,22 +2390,15 @@ const DialogHeader = ({ className, ...props }: DialogHeaderProps) => { interface DialogHeadingProps extends React.ComponentProps {} const DialogHeading = ({ className, ...props }: DialogHeadingProps) => { - return ; + return ; }; /* -----------------------------------------------------------------------------------------------*/ -interface DialogDescriptionProps - extends Omit, "slot"> {} +interface DialogDescriptionProps extends Omit, "slot"> {} const DialogDescription = ({ className, ...props }: DialogDescriptionProps) => { - return ( - - ); + return ; }; /* -----------------------------------------------------------------------------------------------*/ @@ -2892,7 +2406,7 @@ const DialogDescription = ({ className, ...props }: DialogDescriptionProps) => { interface DialogBodyProps extends React.ComponentProps<"div"> {} const DialogBody = ({ className, ...props }: DialogBodyProps) => { - return
; + return
; }; /* -----------------------------------------------------------------------------------------------*/ @@ -2900,7 +2414,7 @@ const DialogBody = ({ className, ...props }: DialogBodyProps) => { type DialogFooterProps = React.ComponentProps<"footer">; const DialogFooter = ({ className, ...props }: DialogFooterProps) => { - return