diff --git a/.nuxtrc b/.nuxtrc
new file mode 100644
index 00000000..7bfc3d5c
--- /dev/null
+++ b/.nuxtrc
@@ -0,0 +1 @@
+modules[]=nuxt-ui-dev-module
diff --git a/modules/dev/index.ts b/modules/dev/index.ts
new file mode 100644
index 00000000..768a345d
--- /dev/null
+++ b/modules/dev/index.ts
@@ -0,0 +1,22 @@
+import { createResolver, defineNuxtModule, useNuxt } from '@nuxt/kit'
+import { watch } from 'chokidar'
+import { debounce } from 'perfect-debounce'
+
+/**
+ * This is an internal module aiming to make the DX of developing Nuxt UI better.
+ */
+export default defineNuxtModule({
+ meta: {
+ name: 'nuxt-ui-dev-module'
+ },
+ setup () {
+ const nuxt = useNuxt()
+ const resolver = createResolver(import.meta.url)
+ const watcher = watch(resolver.resolve('../../src/theme'))
+
+ const generateApp = debounce(() => nuxt.hooks.callHook('builder:generateApp'))
+
+ watcher.on('all', generateApp)
+ nuxt.hook('close', () => watcher.close())
+ }
+})
diff --git a/modules/dev/package.json b/modules/dev/package.json
new file mode 100644
index 00000000..1bb61ad8
--- /dev/null
+++ b/modules/dev/package.json
@@ -0,0 +1,11 @@
+{
+ "name": "nuxt-ui-dev-module",
+ "exports": {
+ ".": "./index.ts"
+ },
+ "dependencies": {
+ "@nuxt/kit": "latest",
+ "chokidar": "^3.6.0",
+ "perfect-debounce": "^1.0.0"
+ }
+}
diff --git a/package.json b/package.json
index 3cfefb93..1ee83224 100644
--- a/package.json
+++ b/package.json
@@ -44,10 +44,14 @@
"eslint": "^8.57.0",
"happy-dom": "^13.6.2",
"nuxt": "npm:nuxt-nightly@latest",
+ "nuxt-ui-dev-module": "workspace:*",
"vitest": "^1.3.1",
"vitest-environment-nuxt": "^1.0.0",
"vue": "^3.4.21",
"vue-router": "^4.3.0",
"vue-tsc": "^2.0.6"
+ },
+ "resolutions": {
+ "nuxt-ui3": "workspace:*"
}
}
\ No newline at end of file
diff --git a/playground/app.vue b/playground/app.vue
index e59868ad..0add4645 100644
--- a/playground/app.vue
+++ b/playground/app.vue
@@ -5,7 +5,7 @@ useHead({
}
})
-const components = ['avatar', 'badge', 'button', 'collapsible', 'tooltip']
+const components = ['avatar', 'badge', 'button', 'collapsible', 'kbd', 'tooltip']
diff --git a/playground/package.json b/playground/package.json
new file mode 100644
index 00000000..183d1ed5
--- /dev/null
+++ b/playground/package.json
@@ -0,0 +1,16 @@
+{
+ "private": true,
+ "name": "nuxt-ui-playground",
+ "type": "module",
+ "scripts": {
+ "dev": "nuxi dev",
+ "build": "nuxi build",
+ "generate": "nuxi generate"
+ },
+ "dependencies": {
+ "nuxt-ui3": "latest",
+ "nuxt": "latest",
+ "vue": "latest",
+ "vue-router": "latest"
+ }
+}
diff --git a/playground/pages/collapsible.vue b/playground/pages/collapsible.vue
index 57e85e91..e6d13181 100644
--- a/playground/pages/collapsible.vue
+++ b/playground/pages/collapsible.vue
@@ -1,18 +1,16 @@
-
+
+
+
+
\ No newline at end of file
diff --git a/playground/pages/kbd.vue b/playground/pages/kbd.vue
new file mode 100644
index 00000000..8a2baaf6
--- /dev/null
+++ b/playground/pages/kbd.vue
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/playground/pages/tooltip.vue b/playground/pages/tooltip.vue
index 01dfe66e..03707795 100644
--- a/playground/pages/tooltip.vue
+++ b/playground/pages/tooltip.vue
@@ -1,7 +1,5 @@
-
-
-
-
-
+
+
+
\ No newline at end of file
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 5ee47f67..3508a8c3 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -4,78 +4,113 @@ settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
-dependencies:
- '@nuxt/kit':
- specifier: ^3.10.3
- version: 3.10.3(rollup@3.29.4)
- '@nuxt/schema':
- specifier: ^3.10.3
- version: 3.10.3(rollup@3.29.4)
- '@nuxtjs/color-mode':
- specifier: ^3.3.2
- version: 3.3.2(rollup@3.29.4)
- '@tailwindcss/vite':
- specifier: 4.0.0-alpha.8
- version: 4.0.0-alpha.8
- '@vueuse/core':
- specifier: ^10.9.0
- version: 10.9.0(vue@3.4.21)
- defu:
- specifier: ^6.1.4
- version: 6.1.4
- nuxt-icon:
- specifier: ^0.6.9
- version: 0.6.9(nuxt-nightly@3.11.0-28499911.8bb8d824)(rollup@3.29.4)(vite@5.1.5)(vue@3.4.21)
- ohash:
- specifier: ^1.1.3
- version: 1.1.3
- radix-vue:
- specifier: ^1.5.2
- version: 1.5.2(vue@3.4.21)
- tailwind-variants:
- specifier: ^0.2.0
- version: 0.2.0(tailwindcss@4.0.0-alpha.8)
- tailwindcss:
- specifier: 4.0.0-alpha.8
- version: 4.0.0-alpha.8
+overrides:
+ nuxt-ui3: workspace:*
-devDependencies:
- '@nuxt/eslint-config':
- specifier: ^0.2.0
- version: 0.2.0(eslint@8.57.0)
- '@nuxt/module-builder':
- specifier: ^0.5.5
- version: 0.5.5(@nuxt/kit@3.10.3)(nuxi@3.10.1)(typescript@5.4.2)
- '@nuxt/test-utils':
- specifier: ^3.11.0
- version: 3.11.0(@vue/test-utils@2.4.4)(h3@1.11.1)(happy-dom@13.7.1)(rollup@3.29.4)(vite@5.1.5)(vitest@1.3.1)(vue-router@4.3.0)(vue@3.4.21)
- '@vue/test-utils':
- specifier: ^2.4.4
- version: 2.4.4(vue@3.4.21)
- eslint:
- specifier: ^8.57.0
- version: 8.57.0
- happy-dom:
- specifier: ^13.6.2
- version: 13.7.1
- nuxt:
- specifier: npm:nuxt-nightly@latest
- version: /nuxt-nightly@3.11.0-28499911.8bb8d824(eslint@8.57.0)(nuxt-nightly@3.11.0-28499911.8bb8d824)(rollup@3.29.4)(typescript@5.4.2)(vite@5.1.5)(vue-tsc@2.0.6)
- vitest:
- specifier: ^1.3.1
- version: 1.3.1(happy-dom@13.7.1)
- vitest-environment-nuxt:
- specifier: ^1.0.0
- version: 1.0.0(@vue/test-utils@2.4.4)(h3@1.11.1)(happy-dom@13.7.1)(rollup@3.29.4)(vite@5.1.5)(vitest@1.3.1)(vue-router@4.3.0)(vue@3.4.21)
- vue:
- specifier: ^3.4.21
- version: 3.4.21(typescript@5.4.2)
- vue-router:
- specifier: ^4.3.0
- version: 4.3.0(vue@3.4.21)
- vue-tsc:
- specifier: ^2.0.6
- version: 2.0.6(typescript@5.4.2)
+importers:
+
+ .:
+ dependencies:
+ '@nuxt/kit':
+ specifier: ^3.10.3
+ version: 3.10.3(rollup@3.29.4)
+ '@nuxt/schema':
+ specifier: ^3.10.3
+ version: 3.10.3(rollup@3.29.4)
+ '@nuxtjs/color-mode':
+ specifier: ^3.3.2
+ version: 3.3.2(rollup@3.29.4)
+ '@tailwindcss/vite':
+ specifier: 4.0.0-alpha.8
+ version: 4.0.0-alpha.8
+ '@vueuse/core':
+ specifier: ^10.9.0
+ version: 10.9.0(vue@3.4.21)
+ defu:
+ specifier: ^6.1.4
+ version: 6.1.4
+ nuxt-icon:
+ specifier: ^0.6.9
+ version: 0.6.9(nuxt-nightly@3.11.0-28499911.8bb8d824)(rollup@3.29.4)(vite@5.1.5)(vue@3.4.21)
+ ohash:
+ specifier: ^1.1.3
+ version: 1.1.3
+ radix-vue:
+ specifier: ^1.5.2
+ version: 1.5.2(vue@3.4.21)
+ tailwind-variants:
+ specifier: ^0.2.0
+ version: 0.2.0(tailwindcss@4.0.0-alpha.8)
+ tailwindcss:
+ specifier: 4.0.0-alpha.8
+ version: 4.0.0-alpha.8
+ devDependencies:
+ '@nuxt/eslint-config':
+ specifier: ^0.2.0
+ version: 0.2.0(eslint@8.57.0)
+ '@nuxt/module-builder':
+ specifier: ^0.5.5
+ version: 0.5.5(@nuxt/kit@3.10.3)(nuxi@3.10.1)(typescript@5.4.2)
+ '@nuxt/test-utils':
+ specifier: ^3.11.0
+ version: 3.11.0(@vue/test-utils@2.4.4)(h3@1.11.1)(happy-dom@13.7.1)(rollup@3.29.4)(vite@5.1.5)(vitest@1.3.1)(vue-router@4.3.0)(vue@3.4.21)
+ '@vue/test-utils':
+ specifier: ^2.4.4
+ version: 2.4.4(vue@3.4.21)
+ eslint:
+ specifier: ^8.57.0
+ version: 8.57.0
+ happy-dom:
+ specifier: ^13.6.2
+ version: 13.7.1
+ nuxt:
+ specifier: npm:nuxt-nightly@latest
+ version: /nuxt-nightly@3.11.0-28499911.8bb8d824(eslint@8.57.0)(nuxt-nightly@3.11.0-28499911.8bb8d824)(rollup@3.29.4)(typescript@5.4.2)(vite@5.1.5)(vue-tsc@2.0.6)
+ nuxt-ui-dev-module:
+ specifier: workspace:*
+ version: link:modules/dev
+ vitest:
+ specifier: ^1.3.1
+ version: 1.3.1(happy-dom@13.7.1)
+ vitest-environment-nuxt:
+ specifier: ^1.0.0
+ version: 1.0.0(@vue/test-utils@2.4.4)(h3@1.11.1)(happy-dom@13.7.1)(rollup@3.29.4)(vite@5.1.5)(vitest@1.3.1)(vue-router@4.3.0)(vue@3.4.21)
+ vue:
+ specifier: ^3.4.21
+ version: 3.4.21(typescript@5.4.2)
+ vue-router:
+ specifier: ^4.3.0
+ version: 4.3.0(vue@3.4.21)
+ vue-tsc:
+ specifier: ^2.0.6
+ version: 2.0.6(typescript@5.4.2)
+
+ modules/dev:
+ dependencies:
+ '@nuxt/kit':
+ specifier: latest
+ version: 3.10.3(rollup@3.29.4)
+ chokidar:
+ specifier: ^3.6.0
+ version: 3.6.0
+ perfect-debounce:
+ specifier: ^1.0.0
+ version: 1.0.0
+
+ playground:
+ dependencies:
+ nuxt:
+ specifier: latest
+ version: 3.10.3(eslint@8.57.0)(rollup@3.29.4)(typescript@5.4.2)(vite@5.1.5)(vue-tsc@2.0.6)
+ nuxt-ui3:
+ specifier: workspace:*
+ version: link:..
+ vue:
+ specifier: latest
+ version: 3.4.21(typescript@5.4.2)
+ vue-router:
+ specifier: latest
+ version: 4.3.0(vue@3.4.21)
packages:
@@ -1088,6 +1123,22 @@ packages:
- rollup
- supports-color
+ /@nuxt/devtools-kit@1.0.8(nuxt@3.10.3)(rollup@3.29.4)(vite@5.1.5):
+ resolution: {integrity: sha512-j7bNZmoAXQ1a8qv6j6zk4c/aekrxYqYVQM21o/Hy4XHCUq4fajSgpoc8mjyWJSTfpkOmuLyEzMexpDWiIVSr6A==}
+ peerDependencies:
+ nuxt: ^3.9.0
+ vite: '*'
+ dependencies:
+ '@nuxt/kit': 3.10.3(rollup@3.29.4)
+ '@nuxt/schema': 3.10.3(rollup@3.29.4)
+ execa: 7.2.0
+ nuxt: 3.10.3(eslint@8.57.0)(rollup@3.29.4)(typescript@5.4.2)(vite@5.1.5)(vue-tsc@2.0.6)
+ vite: 5.1.5
+ transitivePeerDependencies:
+ - rollup
+ - supports-color
+ dev: false
+
/@nuxt/devtools-wizard@1.0.8:
resolution: {integrity: sha512-RxyOlM7Isk5npwXwDJ/rjm9ekX5sTNG0LS0VOBMdSx+D5nlRPMRr/r9yO+9WQDyzPLClLzHaXRHBWLPlRX3IMw==}
hasBin: true
@@ -1153,6 +1204,57 @@ packages:
- supports-color
- utf-8-validate
+ /@nuxt/devtools@1.0.8(nuxt@3.10.3)(rollup@3.29.4)(vite@5.1.5):
+ resolution: {integrity: sha512-o6aBFEBxc8OgVHV4OPe2g0q9tFIe9HiTxRiJnlTJ+jHvOQsBLS651ArdVtwLChf9UdMouFlpLLJ1HteZqTbtsQ==}
+ hasBin: true
+ peerDependencies:
+ nuxt: ^3.9.0
+ vite: '*'
+ dependencies:
+ '@antfu/utils': 0.7.7
+ '@nuxt/devtools-kit': 1.0.8(nuxt@3.10.3)(rollup@3.29.4)(vite@5.1.5)
+ '@nuxt/devtools-wizard': 1.0.8
+ '@nuxt/kit': 3.10.3(rollup@3.29.4)
+ birpc: 0.2.17
+ consola: 3.2.3
+ destr: 2.0.3
+ error-stack-parser-es: 0.1.1
+ execa: 7.2.0
+ fast-glob: 3.3.2
+ flatted: 3.3.1
+ get-port-please: 3.1.2
+ hookable: 5.5.3
+ image-meta: 0.2.0
+ is-installed-globally: 1.0.0
+ launch-editor: 2.6.1
+ local-pkg: 0.5.0
+ magicast: 0.3.3
+ nuxt: 3.10.3(eslint@8.57.0)(rollup@3.29.4)(typescript@5.4.2)(vite@5.1.5)(vue-tsc@2.0.6)
+ nypm: 0.3.8
+ ohash: 1.1.3
+ pacote: 17.0.6
+ pathe: 1.1.2
+ perfect-debounce: 1.0.0
+ pkg-types: 1.0.3
+ rc9: 2.1.1
+ scule: 1.3.0
+ semver: 7.6.0
+ simple-git: 3.22.0
+ sirv: 2.0.4
+ unimport: 3.7.1(rollup@3.29.4)
+ vite: 5.1.5
+ vite-plugin-inspect: 0.8.3(@nuxt/kit@3.10.3)(rollup@3.29.4)(vite@5.1.5)
+ vite-plugin-vue-inspector: 4.0.2(vite@5.1.5)
+ which: 3.0.1
+ ws: 8.16.0
+ transitivePeerDependencies:
+ - bluebird
+ - bufferutil
+ - rollup
+ - supports-color
+ - utf-8-validate
+ dev: false
+
/@nuxt/eslint-config@0.2.0(eslint@8.57.0):
resolution: {integrity: sha512-NeJX8TLcnNAjQFiDs3XhP+9CHKK8jaKsP7eUyCSrQdgY7nqWe7VJx64lwzx5FTT4cW3RHMEyH+Y0qzLGYYoa/A==}
peerDependencies:
@@ -1439,6 +1541,68 @@ packages:
- vti
- vue-tsc
+ /@nuxt/vite-builder@3.10.3(eslint@8.57.0)(rollup@3.29.4)(typescript@5.4.2)(vue-tsc@2.0.6)(vue@3.4.21):
+ resolution: {integrity: sha512-BqkbrYkEk1AVUJleofbqTRV+ltf2p1CDjGDK78zENPCgrSABlj4F4oK8rze8vmRY5qoH7kMZxgMa2dXVXCp6OA==}
+ engines: {node: ^14.18.0 || >=16.10.0}
+ peerDependencies:
+ vue: ^3.3.4
+ dependencies:
+ '@nuxt/kit': 3.10.3(rollup@3.29.4)
+ '@rollup/plugin-replace': 5.0.5(rollup@3.29.4)
+ '@vitejs/plugin-vue': 5.0.4(vite@5.1.5)(vue@3.4.21)
+ '@vitejs/plugin-vue-jsx': 3.1.0(vite@5.1.5)(vue@3.4.21)
+ autoprefixer: 10.4.18(postcss@8.4.35)
+ clear: 0.1.0
+ consola: 3.2.3
+ cssnano: 6.1.0(postcss@8.4.35)
+ defu: 6.1.4
+ esbuild: 0.20.1
+ escape-string-regexp: 5.0.0
+ estree-walker: 3.0.3
+ externality: 1.0.2
+ fs-extra: 11.2.0
+ get-port-please: 3.1.2
+ h3: 1.11.1
+ knitwork: 1.0.0
+ magic-string: 0.30.8
+ mlly: 1.6.1
+ ohash: 1.1.3
+ pathe: 1.1.2
+ perfect-debounce: 1.0.0
+ pkg-types: 1.0.3
+ postcss: 8.4.35
+ rollup-plugin-visualizer: 5.12.0(rollup@3.29.4)
+ std-env: 3.7.0
+ strip-literal: 2.0.0
+ ufo: 1.4.0
+ unenv: 1.9.0
+ unplugin: 1.9.0
+ vite: 5.1.5
+ vite-node: 1.3.1
+ vite-plugin-checker: 0.6.4(eslint@8.57.0)(typescript@5.4.2)(vite@5.1.5)(vue-tsc@2.0.6)
+ vue: 3.4.21(typescript@5.4.2)
+ vue-bundle-renderer: 2.0.0
+ transitivePeerDependencies:
+ - '@types/node'
+ - eslint
+ - less
+ - lightningcss
+ - meow
+ - optionator
+ - rollup
+ - sass
+ - stylelint
+ - stylus
+ - sugarss
+ - supports-color
+ - terser
+ - typescript
+ - uWebSockets.js
+ - vls
+ - vti
+ - vue-tsc
+ dev: false
+
/@nuxtjs/color-mode@3.3.2(rollup@3.29.4):
resolution: {integrity: sha512-BLpBfrYZngV2QWFQ4HNEFwAXa3Pno43Ge+2XHcZJTTa1Z4KzRLvOwku8yiyV3ovIaaXKGwduBdv3Z5Ocdp0/+g==}
dependencies:
@@ -4978,6 +5142,103 @@ packages:
- supports-color
- uWebSockets.js
+ /nitropack@2.9.3:
+ resolution: {integrity: sha512-k3wXlhxmTNkkFXnVyRYJ6CCdZmvlqjYJ4oaL8o9uTKIjg7A1udAle+3cVDxUWi2r9owwEysAP2+quNsAujZyTg==}
+ engines: {node: ^16.11.0 || >=17.0.0}
+ hasBin: true
+ peerDependencies:
+ xml2js: ^0.6.2
+ peerDependenciesMeta:
+ xml2js:
+ optional: true
+ dependencies:
+ '@cloudflare/kv-asset-handler': 0.3.1
+ '@netlify/functions': 2.6.0
+ '@rollup/plugin-alias': 5.1.0(rollup@4.12.1)
+ '@rollup/plugin-commonjs': 25.0.7(rollup@4.12.1)
+ '@rollup/plugin-inject': 5.0.5(rollup@4.12.1)
+ '@rollup/plugin-json': 6.1.0(rollup@4.12.1)
+ '@rollup/plugin-node-resolve': 15.2.3(rollup@4.12.1)
+ '@rollup/plugin-replace': 5.0.5(rollup@4.12.1)
+ '@rollup/plugin-terser': 0.4.4(rollup@4.12.1)
+ '@rollup/pluginutils': 5.1.0(rollup@4.12.1)
+ '@types/http-proxy': 1.17.14
+ '@vercel/nft': 0.26.4
+ archiver: 7.0.0
+ c12: 1.10.0
+ chalk: 5.3.0
+ chokidar: 3.6.0
+ citty: 0.1.6
+ consola: 3.2.3
+ cookie-es: 1.0.0
+ croner: 8.0.1
+ crossws: 0.2.4
+ db0: 0.1.4
+ defu: 6.1.4
+ destr: 2.0.3
+ dot-prop: 8.0.2
+ esbuild: 0.20.1
+ escape-string-regexp: 5.0.0
+ etag: 1.8.1
+ fs-extra: 11.2.0
+ globby: 14.0.1
+ gzip-size: 7.0.0
+ h3: 1.11.1
+ hookable: 5.5.3
+ httpxy: 0.1.5
+ is-primitive: 3.0.1
+ jiti: 1.21.0
+ klona: 2.0.6
+ knitwork: 1.0.0
+ listhen: 1.7.2
+ magic-string: 0.30.8
+ mime: 4.0.1
+ mlly: 1.6.1
+ mri: 1.2.0
+ node-fetch-native: 1.6.2
+ ofetch: 1.3.3
+ ohash: 1.1.3
+ openapi-typescript: 6.7.4
+ pathe: 1.1.2
+ perfect-debounce: 1.0.0
+ pkg-types: 1.0.3
+ pretty-bytes: 6.1.1
+ radix3: 1.1.1
+ rollup: 4.12.1
+ rollup-plugin-visualizer: 5.12.0(rollup@4.12.1)
+ scule: 1.3.0
+ semver: 7.6.0
+ serve-placeholder: 2.0.1
+ serve-static: 1.15.0
+ std-env: 3.7.0
+ ufo: 1.4.0
+ uncrypto: 0.1.3
+ unctx: 2.3.1
+ unenv: 1.9.0
+ unimport: 3.7.1(rollup@4.12.1)
+ unstorage: 1.10.1
+ unwasm: 0.3.7
+ transitivePeerDependencies:
+ - '@azure/app-configuration'
+ - '@azure/cosmos'
+ - '@azure/data-tables'
+ - '@azure/identity'
+ - '@azure/keyvault-secrets'
+ - '@azure/storage-blob'
+ - '@capacitor/preferences'
+ - '@libsql/client'
+ - '@netlify/blobs'
+ - '@planetscale/database'
+ - '@upstash/redis'
+ - '@vercel/kv'
+ - better-sqlite3
+ - drizzle-orm
+ - encoding
+ - idb-keyval
+ - supports-color
+ - uWebSockets.js
+ dev: false
+
/node-addon-api@7.1.0:
resolution: {integrity: sha512-mNcltoe1R8o7STTegSOHdnJNN7s5EUvhoS7ShnTHDyOSd+8H+UdWODq6qSv67PjC8Zc5JRT8+oLAMCr0SIXw7g==}
engines: {node: ^16 || ^18 || >= 20}
@@ -5148,7 +5409,6 @@ packages:
hasBin: true
optionalDependencies:
fsevents: 2.3.3
- dev: true
/nuxt-icon@0.6.9(nuxt-nightly@3.11.0-28499911.8bb8d824)(rollup@3.29.4)(vite@5.1.5)(vue@3.4.21):
resolution: {integrity: sha512-l80F5sIVdwlQPfw/9RFuhVE1Pi3NM3wbgePxDZkgYZe5XOpg4ZznhgObLRyAFFjCeU7XVbFMBe09uJBRM4tuvg==}
@@ -5275,6 +5535,115 @@ packages:
- vue-tsc
- xml2js
+ /nuxt@3.10.3(eslint@8.57.0)(rollup@3.29.4)(typescript@5.4.2)(vite@5.1.5)(vue-tsc@2.0.6):
+ resolution: {integrity: sha512-NchGNiiz9g/ErJAb462W/lpX2NqcXYb9hugySKWvLXNdrjeAPiJ2/7mhgwUSiZA9MpjuQg3saiEajr1zlRIOCg==}
+ engines: {node: ^14.18.0 || >=16.10.0}
+ hasBin: true
+ peerDependencies:
+ '@parcel/watcher': ^2.1.0
+ '@types/node': ^14.18.0 || >=16.10.0
+ peerDependenciesMeta:
+ '@parcel/watcher':
+ optional: true
+ '@types/node':
+ optional: true
+ dependencies:
+ '@nuxt/devalue': 2.0.2
+ '@nuxt/devtools': 1.0.8(nuxt@3.10.3)(rollup@3.29.4)(vite@5.1.5)
+ '@nuxt/kit': 3.10.3(rollup@3.29.4)
+ '@nuxt/schema': 3.10.3(rollup@3.29.4)
+ '@nuxt/telemetry': 2.5.3(rollup@3.29.4)
+ '@nuxt/ui-templates': 1.3.1
+ '@nuxt/vite-builder': 3.10.3(eslint@8.57.0)(rollup@3.29.4)(typescript@5.4.2)(vue-tsc@2.0.6)(vue@3.4.21)
+ '@unhead/dom': 1.8.12
+ '@unhead/ssr': 1.8.12
+ '@unhead/vue': 1.8.12(vue@3.4.21)
+ '@vue/shared': 3.4.21
+ acorn: 8.11.3
+ c12: 1.10.0
+ chokidar: 3.6.0
+ cookie-es: 1.0.0
+ defu: 6.1.4
+ destr: 2.0.3
+ devalue: 4.3.2
+ esbuild: 0.20.1
+ escape-string-regexp: 5.0.0
+ estree-walker: 3.0.3
+ fs-extra: 11.2.0
+ globby: 14.0.1
+ h3: 1.11.1
+ hookable: 5.5.3
+ jiti: 1.21.0
+ klona: 2.0.6
+ knitwork: 1.0.0
+ magic-string: 0.30.8
+ mlly: 1.6.1
+ nitropack: 2.9.3
+ nuxi: 3.10.1
+ nypm: 0.3.8
+ ofetch: 1.3.3
+ ohash: 1.1.3
+ pathe: 1.1.2
+ perfect-debounce: 1.0.0
+ pkg-types: 1.0.3
+ radix3: 1.1.1
+ scule: 1.3.0
+ std-env: 3.7.0
+ strip-literal: 2.0.0
+ ufo: 1.4.0
+ ultrahtml: 1.5.3
+ uncrypto: 0.1.3
+ unctx: 2.3.1
+ unenv: 1.9.0
+ unimport: 3.7.1(rollup@3.29.4)
+ unplugin: 1.9.0
+ unplugin-vue-router: 0.7.0(rollup@3.29.4)(vue-router@4.3.0)(vue@3.4.21)
+ untyped: 1.4.2
+ vue: 3.4.21(typescript@5.4.2)
+ vue-bundle-renderer: 2.0.0
+ vue-devtools-stub: 0.1.0
+ vue-router: 4.3.0(vue@3.4.21)
+ transitivePeerDependencies:
+ - '@azure/app-configuration'
+ - '@azure/cosmos'
+ - '@azure/data-tables'
+ - '@azure/identity'
+ - '@azure/keyvault-secrets'
+ - '@azure/storage-blob'
+ - '@capacitor/preferences'
+ - '@libsql/client'
+ - '@netlify/blobs'
+ - '@planetscale/database'
+ - '@upstash/redis'
+ - '@vercel/kv'
+ - better-sqlite3
+ - bluebird
+ - bufferutil
+ - drizzle-orm
+ - encoding
+ - eslint
+ - idb-keyval
+ - less
+ - lightningcss
+ - meow
+ - optionator
+ - rollup
+ - sass
+ - stylelint
+ - stylus
+ - sugarss
+ - supports-color
+ - terser
+ - typescript
+ - uWebSockets.js
+ - utf-8-validate
+ - vite
+ - vls
+ - vti
+ - vue-tsc
+ - xml2js
+ dev: false
+
/nypm@0.3.8:
resolution: {integrity: sha512-IGWlC6So2xv6V4cIDmoV0SwwWx7zLG086gyqkyumteH2fIgCAM4nDVFB2iDRszDvmdSVW9xb1N+2KjQ6C7d4og==}
engines: {node: ^14.16.0 || >=16.10.0}
diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml
new file mode 100644
index 00000000..c2ff44a1
--- /dev/null
+++ b/pnpm-workspace.yaml
@@ -0,0 +1,3 @@
+packages:
+ - "playground"
+ - "modules/*"
diff --git a/src/runtime/components/Badge.vue b/src/runtime/components/Badge.vue
index 9e3c4428..10aa9356 100644
--- a/src/runtime/components/Badge.vue
+++ b/src/runtime/components/Badge.vue
@@ -3,7 +3,6 @@ import { tv, type VariantProps } from 'tailwind-variants'
import type { AppConfig } from '@nuxt/schema'
import _appConfig from '#build/app.config'
import theme from '#build/ui/badge'
-import type { LinkProps } from '#ui/components/Link.vue'
const appConfig = _appConfig as AppConfig & { ui: { badge: Partial } }
@@ -11,7 +10,7 @@ const badge = tv({ extend: tv(theme), ...(appConfig.ui?.badge || {}) })
type BadgeVariants = VariantProps
-export interface BadgeProps extends LinkProps {
+export interface BadgeProps {
as?: string
label?: string
color?: BadgeVariants['color']
@@ -26,9 +25,7 @@ export interface BadgeSlots {
diff --git a/src/runtime/components/Collapsible.vue b/src/runtime/components/Collapsible.vue
index 94fca206..339da46a 100644
--- a/src/runtime/components/Collapsible.vue
+++ b/src/runtime/components/Collapsible.vue
@@ -10,7 +10,6 @@ const appConfig = _appConfig as AppConfig & { ui: { collapsible: Partial {
- content?: string
class?: any
ui?: Partial
}
@@ -44,9 +43,7 @@ const ui = computed(() => tv({ extend: collapsible, slots: props.ui })())
-
- {{ content }}
-
+
diff --git a/src/runtime/components/Container.vue b/src/runtime/components/Container.vue
index da292fb7..f3e63155 100644
--- a/src/runtime/components/Container.vue
+++ b/src/runtime/components/Container.vue
@@ -15,9 +15,7 @@ export interface ContainerProps {
diff --git a/src/runtime/components/Kbd.vue b/src/runtime/components/Kbd.vue
new file mode 100644
index 00000000..14cdb434
--- /dev/null
+++ b/src/runtime/components/Kbd.vue
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+ {{ value }}
+
+
+
\ No newline at end of file
diff --git a/src/runtime/components/Link.vue b/src/runtime/components/Link.vue
index 5473ae29..c5eebe52 100644
--- a/src/runtime/components/Link.vue
+++ b/src/runtime/components/Link.vue
@@ -21,10 +21,7 @@ import type { RouteLocation } from '#vue-router'
defineOptions({ inheritAttrs: false })
-const props = withDefaults(defineProps(), {
- as: 'button',
- type: 'button'
-})
+const props = withDefaults(defineProps(), { as: 'button', type: 'button' })
const forward = useForwardProps(reactiveOmit(props, 'as', 'type', 'disabled', 'active', 'exact', 'exactQuery', 'exactHash', 'inactiveClass'))
diff --git a/src/runtime/components/Tooltip.vue b/src/runtime/components/Tooltip.vue
index 32ac57d8..0fe97961 100644
--- a/src/runtime/components/Tooltip.vue
+++ b/src/runtime/components/Tooltip.vue
@@ -4,6 +4,7 @@ import type { TooltipRootProps, TooltipRootEmits, TooltipContentProps, TooltipAr
import type { AppConfig } from '@nuxt/schema'
import _appConfig from '#build/app.config'
import theme from '#build/ui/tooltip'
+import type { KbdProps } from '#ui/components/Kbd.vue'
const appConfig = _appConfig as AppConfig & { ui: { tooltip: Partial } }
@@ -11,6 +12,7 @@ const tooltip = tv({ extend: tv(theme), ...(appConfig.ui?.tooltip || {}) })
export interface TooltipProps extends TooltipRootProps {
text?: string
+ shortcuts?: string[] | KbdProps[]
content?: Omit
arrow?: boolean | Omit
portal?: boolean
@@ -22,7 +24,7 @@ export interface TooltipEmits extends TooltipRootEmits {}
export interface TooltipSlots {
default(): any
- text(): any
+ content(): any
}
@@ -31,6 +33,7 @@ import { computed, toRef } from 'vue'
import { defu } from 'defu'
import { TooltipRoot, TooltipTrigger, TooltipPortal, TooltipContent, TooltipArrow, useForwardPropsEmits } from 'radix-vue'
import { reactivePick } from '@vueuse/core'
+import UKbd from './Kbd.vue'
const props = defineProps()
const emits = defineEmits()
@@ -51,8 +54,12 @@ const ui = computed(() => tv({ extend: tooltip, slots: props.ui })())
-
- {{ text }}
+
+ {{ text }}
+
+
+
+
diff --git a/src/templates.ts b/src/templates.ts
index 250273b5..8733a784 100644
--- a/src/templates.ts
+++ b/src/templates.ts
@@ -34,21 +34,23 @@ export default function createTemplates (options: ModuleOptions, nuxt: Nuxt) {
nuxt.options.css.push(template.dst)
for (const component in theme) {
- const template = (theme as any)[component]
- const result = typeof template === 'function' ? template({ colors: options.colors }) : template
-
- const variants = Object.keys(result.variants || {})
-
- let json = JSON.stringify(result, null, 2)
-
- for (const variant of variants) {
- json = json.replaceAll(new RegExp(`("${variant}": "[0-9a-z]+")`, 'g'), '$1 as const')
- }
-
addTemplate({
filename: `ui/${component}.ts`,
write: true,
- getContents: () => `export default ${json}`
+ getContents: async () => {
+ const template = (theme as any)[component]
+ const result = typeof template === 'function' ? template({ colors: options.colors }) : template
+
+ const variants = Object.keys(result.variants || {})
+
+ let json = JSON.stringify(result, null, 2)
+
+ for (const variant of variants) {
+ json = json.replaceAll(new RegExp(`("${variant}": "[0-9a-z]+")`, 'g'), '$1 as const')
+ }
+
+ return `export default ${json}`
+ }
})
}
diff --git a/src/theme/avatar.ts b/src/theme/avatar.ts
index a82aef8a..74ea55c2 100644
--- a/src/theme/avatar.ts
+++ b/src/theme/avatar.ts
@@ -1,6 +1,6 @@
export default {
slots: {
- root: 'inline-flex items-center justify-center shrink-0 select-none overflow-hidden rounded-full align-middle bg-gray-100 dark:bg-gray-800',
+ root: 'inline-flex items-center justify-center shrink-0 select-none overflow-hidden rounded-full align-middle bg-gray-50 dark:bg-gray-800',
image: 'h-full w-full rounded-[inherit] object-cover',
fallback: 'font-medium leading-none text-gray-500 dark:text-gray-400 truncate',
icon: 'text-gray-500 dark:text-gray-400 shrink-0'
diff --git a/src/theme/index.ts b/src/theme/index.ts
index 792a88b3..aaf028c1 100644
--- a/src/theme/index.ts
+++ b/src/theme/index.ts
@@ -4,4 +4,5 @@ export { default as button } from './button'
export { default as collapsible } from './collapsible'
export { default as container } from './container'
export { default as icons } from './icons'
+export { default as kbd } from './kbd'
export { default as tooltip } from './tooltip'
\ No newline at end of file
diff --git a/src/theme/kbd.ts b/src/theme/kbd.ts
new file mode 100644
index 00000000..bd8d3ef4
--- /dev/null
+++ b/src/theme/kbd.ts
@@ -0,0 +1,13 @@
+export default {
+ base: 'inline-flex items-center justify-center text-gray-900 dark:text-white px-1 rounded font-medium font-sans bg-gray-50 dark:bg-gray-800 ring ring-gray-300 dark:ring-gray-700 ring-inset',
+ variants: {
+ size: {
+ xs: 'h-4 min-w-[16px] text-[10px]',
+ sm: 'h-5 min-w-[20px] text-[11px]',
+ md: 'h-6 min-w-[24px] text-[12px]'
+ }
+ },
+ defaultVariants: {
+ size: 'sm'
+ }
+}
\ No newline at end of file
diff --git a/src/theme/tooltip.ts b/src/theme/tooltip.ts
index 843a6585..33b459ee 100644
--- a/src/theme/tooltip.ts
+++ b/src/theme/tooltip.ts
@@ -1,6 +1,9 @@
export default {
slots: {
- content: 'bg-white dark:bg-gray-900 text-gray-900 dark:text-white shadow rounded ring ring-gray-200 dark:ring-gray-800 h-6 px-2 py-1 text-xs font-normal truncate relative data-[state=delayed-open]:data-[side=top]:animate-[tooltip-down_200ms_ease-out] data-[state=delayed-open]:data-[side=right]:animate-[tooltip-left_200ms_ease-out] data-[state=delayed-open]:data-[side=left]:animate-[tooltip-right_200ms_ease-out] data-[state=delayed-open]:data-[side=bottom]:animate-[tooltip-up_200ms_ease-out]',
- arrow: 'fill-white dark:fill-gray-700'
+ content: 'flex items-center gap-1 bg-white dark:bg-gray-900 text-gray-900 dark:text-white shadow rounded ring ring-gray-200 dark:ring-gray-800 h-6 px-2 py-1 text-xs select-none max-w-48 will-change-[transform,opacity] data-[state=delayed-open]:data-[side=top]:animate-[tooltip-down_200ms_ease-out] data-[state=delayed-open]:data-[side=right]:animate-[tooltip-left_200ms_ease-out] data-[state=delayed-open]:data-[side=left]:animate-[tooltip-right_200ms_ease-out] data-[state=delayed-open]:data-[side=bottom]:animate-[tooltip-up_200ms_ease-out]',
+ arrow: 'fill-gray-200 dark:fill-gray-800',
+ text: 'truncate',
+ // eslint-disable-next-line quotes
+ shortcuts: `hidden lg:inline-flex items-center shrink-0 gap-0.5 before:content-['·'] before:mr-0.5`
}
}
\ No newline at end of file
diff --git a/test/components/Badge.spec.ts b/test/components/Badge.spec.ts
index c23f53f7..017d7910 100644
--- a/test/components/Badge.spec.ts
+++ b/test/components/Badge.spec.ts
@@ -5,7 +5,7 @@ import ComponentRender from '../component-render'
describe('Badge', () => {
it.each([
['with label', { props: { label: 'Badge' } }],
- ['with class', { props: { class: 'rounded-full font-bold' } }],
+ ['with class', { props: { label: 'Badge', class: 'rounded-full font-bold' } }],
['with size xs', { props: { label: 'Badge', size: 'xs' as const } }],
['with size sm', { props: { label: 'Badge', size: 'sm' as const } }],
['with size md', { props: { label: 'Badge', size: 'md' as const } }],
diff --git a/test/components/Kbd.spec.ts b/test/components/Kbd.spec.ts
new file mode 100644
index 00000000..c4e877fe
--- /dev/null
+++ b/test/components/Kbd.spec.ts
@@ -0,0 +1,17 @@
+import { describe, it, expect } from 'vitest'
+import Kbd, { type KbdProps } from '../../src/runtime/components/Kbd.vue'
+import ComponentRender from '../component-render'
+
+describe('Kbd', () => {
+ it.each([
+ ['with value', { props: { value: 'K' } }],
+ ['with class', { props: { value: 'K', class: 'font-bold' } }],
+ ['with size xs', { props: { value: 'K', size: 'xs' as const } }],
+ ['with size sm', { props: { value: 'K', size: 'sm' as const } }],
+ ['with size md', { props: { value: 'K', size: 'md' as const } }],
+ ['with default slot', { slots: { default: () => 'Default slot' } }]
+ ])('renders %s correctly', async (nameOrHtml: string, options: { props?: KbdProps, slots?: any }) => {
+ const html = await ComponentRender(nameOrHtml, options, Kbd)
+ expect(html).toMatchSnapshot()
+ })
+})
diff --git a/test/components/__snapshots__/Avatar.spec.ts.snap b/test/components/__snapshots__/Avatar.spec.ts.snap
index 8decc896..141849db 100644
--- a/test/components/__snapshots__/Avatar.spec.ts.snap
+++ b/test/components/__snapshots__/Avatar.spec.ts.snap
@@ -1,31 +1,31 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
-exports[`Avatar > renders with alt correctly 1`] = `"BC "`;
+exports[`Avatar > renders with alt correctly 1`] = `"BC "`;
exports[`Avatar > renders with class correctly 1`] = `" "`;
-exports[`Avatar > renders with icon correctly 1`] = `" "`;
+exports[`Avatar > renders with icon correctly 1`] = `" "`;
-exports[`Avatar > renders with size 2xl correctly 1`] = `" "`;
+exports[`Avatar > renders with size 2xl correctly 1`] = `" "`;
-exports[`Avatar > renders with size 2xs correctly 1`] = `" "`;
+exports[`Avatar > renders with size 2xs correctly 1`] = `" "`;
-exports[`Avatar > renders with size 3xl correctly 1`] = `" "`;
+exports[`Avatar > renders with size 3xl correctly 1`] = `" "`;
-exports[`Avatar > renders with size 3xs correctly 1`] = `" "`;
+exports[`Avatar > renders with size 3xs correctly 1`] = `" "`;
-exports[`Avatar > renders with size lg correctly 1`] = `" "`;
+exports[`Avatar > renders with size lg correctly 1`] = `" "`;
-exports[`Avatar > renders with size md correctly 1`] = `" "`;
+exports[`Avatar > renders with size md correctly 1`] = `" "`;
-exports[`Avatar > renders with size sm correctly 1`] = `" "`;
+exports[`Avatar > renders with size sm correctly 1`] = `" "`;
-exports[`Avatar > renders with size xl correctly 1`] = `" "`;
+exports[`Avatar > renders with size xl correctly 1`] = `" "`;
-exports[`Avatar > renders with size xs correctly 1`] = `" "`;
+exports[`Avatar > renders with size xs correctly 1`] = `" "`;
-exports[`Avatar > renders with src correctly 1`] = `" "`;
+exports[`Avatar > renders with src correctly 1`] = `" "`;
-exports[`Avatar > renders with text correctly 1`] = `"+1 "`;
+exports[`Avatar > renders with text correctly 1`] = `"+1 "`;
-exports[`Avatar > renders with ui correctly 1`] = `" "`;
+exports[`Avatar > renders with ui correctly 1`] = `" "`;
diff --git a/test/components/__snapshots__/Badge.spec.ts.snap b/test/components/__snapshots__/Badge.spec.ts.snap
index 3d40f47c..9b752dce 100644
--- a/test/components/__snapshots__/Badge.spec.ts.snap
+++ b/test/components/__snapshots__/Badge.spec.ts.snap
@@ -1,6 +1,6 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
-exports[`Badge > renders with class correctly 1`] = `" "`;
+exports[`Badge > renders with class correctly 1`] = `"Badge "`;
exports[`Badge > renders with color black correctly 1`] = `"Badge "`;
diff --git a/test/components/__snapshots__/Kbd.spec.ts.snap b/test/components/__snapshots__/Kbd.spec.ts.snap
new file mode 100644
index 00000000..19e0a17c
--- /dev/null
+++ b/test/components/__snapshots__/Kbd.spec.ts.snap
@@ -0,0 +1,13 @@
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
+
+exports[`Kbd > renders with class correctly 1`] = `"K "`;
+
+exports[`Kbd > renders with default slot correctly 1`] = `"Default slot "`;
+
+exports[`Kbd > renders with size md correctly 1`] = `"K "`;
+
+exports[`Kbd > renders with size sm correctly 1`] = `"K "`;
+
+exports[`Kbd > renders with size xs correctly 1`] = `"K "`;
+
+exports[`Kbd > renders with value correctly 1`] = `"K "`;