Compare commits

..

2 Commits

Author SHA1 Message Date
Benjamin Canac
49498d53a2 Merge branch 'v3' into feat/update-playground-form 2024-11-12 14:18:35 +01:00
Romain Hamel
8b975de35e feat(playground): update form examples 2024-11-12 13:44:09 +01:00
223 changed files with 3440 additions and 20134 deletions

View File

@@ -61,8 +61,5 @@ jobs:
- name: Build - name: Build
run: pnpm run build run: pnpm run build
- name: Build vue fixture
run: pnpm run test:vue:build
- name: Publish - name: Publish
run: pnpx pkg-pr-new publish --compact --no-template --pnpm run: pnpx pkg-pr-new publish --compact --no-template --pnpm

View File

@@ -1,67 +1,5 @@
# Changelog # Changelog
## [3.0.0-alpha.9](https://github.com/nuxt/ui/compare/v3.0.0-alpha.8...v3.0.0-alpha.9) (2024-11-19)
### Features
* **cli:** add locale command ([#2586](https://github.com/nuxt/ui/issues/2586)) ([824ba56](https://github.com/nuxt/ui/commit/824ba5629183bc4cd59321213558770db211f6e5))
* **css:** add `--ui-bg-muted` / `--ui-border-muted` variables ([7f6db45](https://github.com/nuxt/ui/commit/7f6db45f1e15ef39cda9b732cb601c552f29570a))
* **Form:** apply transformations ([#2550](https://github.com/nuxt/ui/issues/2550)) ([75c5e87](https://github.com/nuxt/ui/commit/75c5e87724e7abdf0a6751d7a1dbbafb947f373f))
* **FormField:** add `error-pattern` prop ([#2601](https://github.com/nuxt/ui/issues/2601)) ([143612e](https://github.com/nuxt/ui/commit/143612ec737d1c7571398601c3222f2eed37996e))
* **InputMenu/SelectMenu:** add `create-item` prop ([#2472](https://github.com/nuxt/ui/issues/2472)) ([f516d7b](https://github.com/nuxt/ui/commit/f516d7b36da51565f4ab05a4c9cfe5e5b4015124))
* **InputNumber:** implement component ([#2577](https://github.com/nuxt/ui/issues/2577)) ([bd2f077](https://github.com/nuxt/ui/commit/bd2f077fe8e645d5fce8b1eb5a6eb1068b3e8f7c))
* **Link:** allow partial query match for its active state ([#2664](https://github.com/nuxt/ui/issues/2664)) ([7329900](https://github.com/nuxt/ui/commit/7329900ae549430b88567a09cbb585d3cf0a6d32))
* **locale:** add Persian language ([#2682](https://github.com/nuxt/ui/issues/2682)) ([14fb21b](https://github.com/nuxt/ui/commit/14fb21be0034ffc0ba5d213734c00f12e0d6bea8))
* **locale:** add Polish language ([#2678](https://github.com/nuxt/ui/issues/2678)) ([2fc36c8](https://github.com/nuxt/ui/commit/2fc36c878c67967ec91e4f6999575bad45521d44))
* **locale:** add support for Arabic ([#2582](https://github.com/nuxt/ui/issues/2582)) ([602a667](https://github.com/nuxt/ui/commit/602a667343be22b72383ab3cf42f36ec9e135082))
* **locale:** add support for Czech translation ([#2593](https://github.com/nuxt/ui/issues/2593)) ([4889d30](https://github.com/nuxt/ui/commit/4889d30b448296de42e146dc5771738837c31f8c))
* **locale:** add support for Italian ([#2583](https://github.com/nuxt/ui/issues/2583)) ([4fbbb25](https://github.com/nuxt/ui/commit/4fbbb25f68b0b5ee76e50f2da776a74d54acc041))
* **locale:** provide `code` ([#2611](https://github.com/nuxt/ui/issues/2611)) ([8a8b1ee](https://github.com/nuxt/ui/commit/8a8b1ee2e1628bc5439ef109d3c68b69bf631f81))
* **locale:** provide `dir` on `defineLocale` ([#2620](https://github.com/nuxt/ui/issues/2620)) ([937585c](https://github.com/nuxt/ui/commit/937585cb3f8bc902d60a4b5904711598204aee2d))
* **locale:** translate chinese ([#2580](https://github.com/nuxt/ui/issues/2580)) ([febda5c](https://github.com/nuxt/ui/commit/febda5c2b67374d1358a66694543b77037d239c6))
* **locale:** translate Spanish ([#2644](https://github.com/nuxt/ui/issues/2644)) ([8ed434c](https://github.com/nuxt/ui/commit/8ed434c105b75ae02aa7493a235cebb64d518d09))
* **locale:** typing `dir` ([#2643](https://github.com/nuxt/ui/issues/2643)) ([e55c0e2](https://github.com/nuxt/ui/commit/e55c0e25947e7bcef931b26dafaad120f488a627))
* **module:** support i18n in components ([#2553](https://github.com/nuxt/ui/issues/2553)) ([2636240](https://github.com/nuxt/ui/commit/26362408b161108487b889ff001bec9166059c79))
* **NavigationMenu:** control items `open` & `defaultOpen` on vertical ([30218f1](https://github.com/nuxt/ui/commit/30218f1b5b0a56207fd4db224ffa0401ac194a04)), closes [#2608](https://github.com/nuxt/ui/issues/2608)
* **PinInput:** implement component ([#2570](https://github.com/nuxt/ui/issues/2570)) ([95aa6f6](https://github.com/nuxt/ui/commit/95aa6f68b316d02c28d1124d9a826bca55cde81f))
* **Popover:** add `prevent-close` prop ([ea97759](https://github.com/nuxt/ui/commit/ea97759c2c219bdf5c48b652b47d293ddf513a00)), closes [#2245](https://github.com/nuxt/ui/issues/2245)
* **SelectMenu:** use `UInput` in search to handle props like icon ([ff1e079](https://github.com/nuxt/ui/commit/ff1e0798d384d40ad82a95fe5faa16acb080efe3)), closes [#2021](https://github.com/nuxt/ui/issues/2021)
* **Table:** add `caption` prop ([446f9c1](https://github.com/nuxt/ui/commit/446f9c1085e96187afdc5c1d7ce3450f8df1a2e1))
### Bug Fixes
* **App:** missing `vue` imports ([ddb4690](https://github.com/nuxt/ui/commit/ddb46905e7e3480ab578bcd8a478f25dff60081a))
* **App:** remove `dir` prop ([#2630](https://github.com/nuxt/ui/issues/2630)) ([7cc26d0](https://github.com/nuxt/ui/commit/7cc26d098dff70923bcd9d414d675018951b1967))
* **Breadcrumb/Carousel/Pagination:** handle icons in RTL mode ([#2633](https://github.com/nuxt/ui/issues/2633)) ([e5119a9](https://github.com/nuxt/ui/commit/e5119a9ca4e217ef769904323c16bd8c0cbc02d9))
* **Breadcrumb:** render as `nav` ([756f791](https://github.com/nuxt/ui/commit/756f791a1a8dd3a4a88c212b4e4f775584decb55)), closes [#2649](https://github.com/nuxt/ui/issues/2649)
* **Button:** improve neutral solid variant hover ([8d85498](https://github.com/nuxt/ui/commit/8d85498ee197ec0b26cdd7c4b08f84fec45ddd8f))
* **Carousel:** use `dir` from locale ([#2647](https://github.com/nuxt/ui/issues/2647)) ([1fbbfe8](https://github.com/nuxt/ui/commit/1fbbfe8df06b3b8b294615ac328d582c5230aa8b))
* **ContextMenu/DropdownMenu:** relative imports with prefix ([47f58f5](https://github.com/nuxt/ui/commit/47f58f52ef2d03176a184a3ca2154f5cea655edb))
* **css:** `--font-family-sans` renamed to `--font-sans` ([#2680](https://github.com/nuxt/ui/issues/2680)) ([b2fa657](https://github.com/nuxt/ui/commit/b2fa65734bb59186520c985f7c73fc34a0cb8b37))
* **css:** remove useless spacing override ([8d00265](https://github.com/nuxt/ui/commit/8d0026558a21efbbca08e9939844f7479a0d6cce))
* **FormField:** missing conditions to apply container classes ([#2631](https://github.com/nuxt/ui/issues/2631)) ([9241ba1](https://github.com/nuxt/ui/commit/9241ba1230b0fde41595634362d83c92c66b7699))
* **Form:** match `error-pattern` on input validation ([#2606](https://github.com/nuxt/ui/issues/2606)) ([3584a33](https://github.com/nuxt/ui/commit/3584a3328b8588f024557c9908242bc374853419))
* **InputMenu/SelectMenu:** init `filter` with `labelKey` ([18931ac](https://github.com/nuxt/ui/commit/18931acdb316bc72a3e5ed6d20985688ad5c8d99))
* **InputMenu/SelectMenu:** look in `items` only with `value-attribute` ([0ceafe1](https://github.com/nuxt/ui/commit/0ceafe1d54000f3eb49562b00c188d82fa23c4ee)), closes [#2464](https://github.com/nuxt/ui/issues/2464)
* **InputMenu/SelectMenu:** multiple not working with generic boolean casting ([503f701](https://github.com/nuxt/ui/commit/503f701c7ecdfe27e9057e5ddebfc7e03889d61b)), closes [#2541](https://github.com/nuxt/ui/issues/2541)
* **InputMenu/SelectMenu:** use `isEqual` from `ohash` ([f943f88](https://github.com/nuxt/ui/commit/f943f88fcc9f4678d8f7bd224799e289a0c57dd8))
* **Link:** missing relative import ([#2588](https://github.com/nuxt/ui/issues/2588)) ([95a0bbc](https://github.com/nuxt/ui/commit/95a0bbc581a40677f620eed3170f9a423976214b))
* **locale:** Improve German translation ([#2676](https://github.com/nuxt/ui/issues/2676)) ([992be91](https://github.com/nuxt/ui/commit/992be91823fe1877254ccd092c71c77dd3ff42f7))
* **locale:** it translation ([#2623](https://github.com/nuxt/ui/issues/2623)) ([73e25ed](https://github.com/nuxt/ui/commit/73e25ed23562f755ea4c66e6c5fb06dd18caac1e))
* **locale:** Italian translation ([#2584](https://github.com/nuxt/ui/issues/2584)) ([d167c9b](https://github.com/nuxt/ui/commit/d167c9b807a82fdf0fd280ce8417a66f86d7ed72))
* **Modal/Slideover:** prevent `esc` with `prevent-close` prop ([9e2cc5b](https://github.com/nuxt/ui/commit/9e2cc5b12567472044726924a3896b4b0e7993a1)), closes [#2501](https://github.com/nuxt/ui/issues/2501)
* **module:** remove `fast-deep-equal` in favor of custom `isEqual` ([37a3597](https://github.com/nuxt/ui/commit/37a359701f4b2ce4a9b0727b64c0e3eea6be00b4))
* **module:** skip devtools renderer page injection if router integration is disabled ([#2571](https://github.com/nuxt/ui/issues/2571)) ([afe4003](https://github.com/nuxt/ui/commit/afe40033b088d8aedb73fa8387a0284ef78444e4))
* **PinInput:** missing `useFormField` import ([601f4b2](https://github.com/nuxt/ui/commit/601f4b2cd2027817b935e02a0b4584dc3dce655f))
* **Textarea:** `autoresize` does not work when initializing `modelValue` ([#2681](https://github.com/nuxt/ui/issues/2681)) ([d3a079a](https://github.com/nuxt/ui/commit/d3a079a644db3dfe2f4e9567973550d74b3ba905))
* **Toaster:** teleport to `body` ([b0be26d](https://github.com/nuxt/ui/commit/b0be26d67feab467ac5862edd82e52df03a5091c)), closes [#2404](https://github.com/nuxt/ui/issues/2404)
* **Toast:** unreachable behind overlays ([#2650](https://github.com/nuxt/ui/issues/2650)) ([0daac5b](https://github.com/nuxt/ui/commit/0daac5bafb756c3a2dfaf2bf166c30c0eb476e08))
* **useLocale:** missing import in various components ([#2603](https://github.com/nuxt/ui/issues/2603)) ([df7a61a](https://github.com/nuxt/ui/commit/df7a61a97a14b3d7943baee6a74686134dfdb10b))
### Reverts
* Revert "docs(ComponentCode/ComponentExample): use relative imports" ([5deadc7](https://github.com/nuxt/ui/commit/5deadc709640bbfd3ec14c1c9363deb55e765d6a))
## [3.0.0-alpha.8](https://github.com/nuxt/ui/compare/v3.0.0-alpha.7...v3.0.0-alpha.8) (2024-11-07) ## [3.0.0-alpha.8](https://github.com/nuxt/ui/compare/v3.0.0-alpha.7...v3.0.0-alpha.8) (2024-11-07)
### ⚠ BREAKING CHANGES ### ⚠ BREAKING CHANGES

View File

@@ -1,4 +1,4 @@
[![nuxt-ui.png](https://volta.s3.fr-par.scw.cloud/nuxt_ui_social_card_531d133fa2.png)](https://ui.nuxt.com) [![nuxt-ui.png](https://repository-images.githubusercontent.com/428329515/43fec891-9030-4601-8233-5d45ba5c6013)](https://ui.nuxt.com)
# Nuxt UI # Nuxt UI
@@ -7,7 +7,7 @@
[![License][license-src]][license-href] [![License][license-src]][license-href]
[![Nuxt][nuxt-src]][nuxt-href] [![Nuxt][nuxt-src]][nuxt-href]
We're thrilled to introduce Nuxt UI v3, a significant upgrade to our UI library that delivers extensive improvements and robust new capabilities. This major update harnesses the combined strengths of [Radix Vue](https://www.radix-vue.com/), [Tailwind CSS v4](https://tailwindcss.com/docs/v4-beta), and [Tailwind Variants](https://www.tailwind-variants.org/) to offer developers an unparalleled set of tools for creating sophisticated, accessible, and highly performant user interfaces. We're thrilled to introduce Nuxt UI v3, a significant upgrade to our UI library that delivers extensive improvements and robust new capabilities. This major update harnesses the combined strengths of [Radix Vue](https://www.radix-vue.com/), [Tailwind CSS v4](https://tailwindcss.com/blog/tailwindcss-v4-alpha), and [Tailwind Variants](https://www.tailwind-variants.org/) to offer developers an unparalleled set of tools for creating sophisticated, accessible, and highly performant user interfaces.
> [!NOTE] > [!NOTE]
> You are on the `v3` development branch, check out the [dev branch](https://github.com/nuxt/ui) for Nuxt UI v2. > You are on the `v3` development branch, check out the [dev branch](https://github.com/nuxt/ui) for Nuxt UI v2.
@@ -105,7 +105,7 @@ Learn more in the [installation guide](https://ui3.nuxt.dev/getting-started/inst
## License ## License
Licensed under the [MIT license](https://github.com/nuxt/ui/blob/v3/LICENSE.md). Licensed under the [MIT license](https://github.com/nuxt/ui/blob/dev/LICENSE.md).
<!-- Badges --> <!-- Badges -->
[npm-version-src]: https://img.shields.io/npm/v/@nuxt/ui/next.svg?style=flat&colorA=18181B&colorB=28CF8D [npm-version-src]: https://img.shields.io/npm/v/@nuxt/ui/next.svg?style=flat&colorA=18181B&colorB=28CF8D
@@ -115,7 +115,7 @@ Licensed under the [MIT license](https://github.com/nuxt/ui/blob/v3/LICENSE.md).
[npm-downloads-href]: https://npm.chart.dev/@nuxt/ui [npm-downloads-href]: https://npm.chart.dev/@nuxt/ui
[license-src]: https://img.shields.io/github/license/nuxt/ui.svg?style=flat&colorA=18181B&colorB=28CF8D [license-src]: https://img.shields.io/github/license/nuxt/ui.svg?style=flat&colorA=18181B&colorB=28CF8D
[license-href]: https://github.com/nuxt/ui/blob/v3/LICENSE.md [license-href]: https://github.com/nuxt/ui/blob/main/LICENSE.md
[nuxt-src]: https://img.shields.io/badge/Nuxt-18181B?logo=nuxt.js [nuxt-src]: https://img.shields.io/badge/Nuxt-18181B?logo=nuxt.js
[nuxt-href]: https://nuxt.com [nuxt-href]: https://nuxt.com

View File

@@ -17,10 +17,6 @@ export default defineCommand({
name: { name: {
description: 'Locale name to create. For example: English.', description: 'Locale name to create. For example: English.',
required: true required: true
},
dir: {
description: 'Locale direction. For example: rtl.',
default: 'ltr'
} }
}, },
async setup({ args }) { async setup({ args }) {
@@ -36,11 +32,6 @@ export default defineCommand({
process.exit(1) process.exit(1)
} }
if (!['ltr', 'rtl'].includes(args.dir)) {
consola.error(`🚨 Direction ${args.dir} not supported!`)
process.exit(1)
}
if (!args.code.match(/^[a-z]{2}(?:_[a-z]{2,4})?$/)) { if (!args.code.match(/^[a-z]{2}(?:_[a-z]{2,4})?$/)) {
consola.error(`🚨 ${args.code} is not a valid locale code!\nExample: en or en_us`) consola.error(`🚨 ${args.code} is not a valid locale code!\nExample: en or en_us`)
process.exit(1) process.exit(1)
@@ -54,9 +45,7 @@ export default defineCommand({
// Create new locale file // Create new locale file
await fsp.copyFile(originLocaleFilePath, newLocaleFilePath) await fsp.copyFile(originLocaleFilePath, newLocaleFilePath)
const localeFile = await fsp.readFile(newLocaleFilePath, 'utf-8') const localeFile = await fsp.readFile(newLocaleFilePath, 'utf-8')
const rewrittenLocaleFile = localeFile const rewrittenLocaleFile = localeFile.replace(/defineLocale\('(.*)'/, `defineLocale('${args.name}', '${normalizeLocale(args.code)}'`)
.replace(/name: '(.*)',/, `name: '${args.name}',`)
.replace(/code: '(.*)',/, `code: '${normalizeLocale(args.code)}',${(args.dir && args.dir !== 'ltr') ? `\n dir: '${args.dir}',` : ''}`)
await fsp.writeFile(newLocaleFilePath, rewrittenLocaleFile) await fsp.writeFile(newLocaleFilePath, rewrittenLocaleFile)
consola.success(`🪄 Generated ${newLocaleFilePath}`) consola.success(`🪄 Generated ${newLocaleFilePath}`)

View File

@@ -163,54 +163,9 @@ describe('${upperName}', () => {
} }
} }
const doc = ({ name, pro }) => {
const kebabName = kebabCase(name)
const upperName = splitByCase(name).map(p => upperFirst(p)).join('')
return {
filename: `docs/content/${pro ? 'pro' : '3.components'}/${kebabName}.md`,
contents: `---
description:
links: ${pro
? ''
: `
- label: ${upperName}
icon: i-custom-radix-vue
to: https://www.radix-vue.com/components/${kebabName}.html`}
- label: GitHub
icon: i-simple-icons-github
to: https://github.com/nuxt/${pro ? 'ui-pro' : 'ui'}/tree/v3/src/runtime/components/${upperName}.vue
---
## Usage
## Examples
## API
### Props
:component-props
### Slots
:component-slots
### Emits
:component-emits
## Theme
:component-theme
`
}
}
export default { export default {
playground, playground,
component, component,
theme, theme,
test, test
doc
} }

View File

@@ -168,7 +168,7 @@ const isDark = computed({
@import '@nuxt/ui'; @import '@nuxt/ui';
@theme { @theme {
--font-sans: 'DM Sans', sans-serif; --font-family-sans: 'DM Sans', sans-serif;
--color-primary-50: var(--ui-color-primary-50); --color-primary-50: var(--ui-color-primary-50);
--color-primary-100: var(--ui-color-primary-100); --color-primary-100: var(--ui-color-primary-100);

View File

@@ -12,7 +12,7 @@
"dependencies": { "dependencies": {
"@nuxt/ui": "latest", "@nuxt/ui": "latest",
"knitwork": "^1.1.0", "knitwork": "^1.1.0",
"nuxt": "^3.14.1592", "nuxt": "^3.14.159",
"prettier": "^3.3.3", "prettier": "^3.3.3",
"zod": "^3.23.8" "zod": "^3.23.8"
} }

View File

@@ -73,41 +73,24 @@ useServerSeoMeta({
twitterCard: 'summary_large_image' twitterCard: 'summary_large_image'
}) })
const { framework, frameworks } = useSharedData() const updatedNavigation = computed(() => navigation.value?.map(item => ({
...item,
children: item.children?.map((child: typeof item) => ({
...child,
...(child.path === '/getting-started/installation' && {
title: 'Installation',
active: route.path.startsWith('/getting-started/installation'),
children: []
}),
...(child.path === '/getting-started/i18n' && {
title: 'I18n',
active: route.path.startsWith('/getting-started/i18n'),
children: []
})
})) || []
})))
const groups = computed(() => { provide('navigation', updatedNavigation)
return [{
id: 'framework',
label: 'Framework',
items: frameworks.value
}]
})
function filterFrameworkItems(items: any[]) {
return items?.filter(item => !item.framework || item.framework === framework.value)
}
function processNavigationItem(item: any): any {
if (item.shadow) {
const matchingChild = filterFrameworkItems(item.children)?.[0]
return matchingChild
? {
...matchingChild,
title: item.title,
children: matchingChild.children ? processNavigationItem(matchingChild) : undefined
}
: item
}
return {
...item,
children: item.children?.length ? filterFrameworkItems(item.children)?.map(processNavigationItem) : undefined
}
}
const filteredNavigation = computed(() => navigation.value?.map(processNavigationItem))
provide('navigation', filteredNavigation)
</script> </script>
<template> <template>
@@ -128,13 +111,7 @@ provide('navigation', filteredNavigation)
<Footer /> <Footer />
<ClientOnly> <ClientOnly>
<LazyUContentSearch <LazyUContentSearch v-model:search-term="searchTerm" :files="files" :navigation="navigation" :fuse="{ resultLimit: 42 }" />
v-model:search-term="searchTerm"
:files="files"
:groups="groups"
:navigation="filteredNavigation"
:fuse="{ resultLimit: 42 }"
/>
</ClientOnly> </ClientOnly>
</template> </template>
</UApp> </UApp>
@@ -144,12 +121,12 @@ provide('navigation', filteredNavigation)
@import "tailwindcss"; @import "tailwindcss";
@import "@nuxt/ui-pro"; @import "@nuxt/ui-pro";
@source "../content"; @source "../content/**/*.md";
@theme { @theme {
--container-8xl: 90rem; --container-8xl: 90rem;
--font-sans: 'Public Sans', sans-serif; --font-family-sans: 'Public Sans', sans-serif;
--color-green-50: #EFFDF5; --color-green-50: #EFFDF5;
--color-green-100: #D9FBE8; --color-green-100: #D9FBE8;

View File

@@ -1,10 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 283.46 283.46">
<defs>
<style>
.cls-1{fill:#231815;}
@media (prefers-color-scheme: dark) { .cls-1{fill:#ffffff;} }
</style>
</defs>
<path class="cls-1" d="M144.89,89.86c-33.46,0-54.44,14.56-66.14,26.76a86,86,0,0,0-23.69,58.94c0,22.64,8.81,43.48,24.8,58.67,15.7,14.92,36.9,23.14,59.68,23.14,23.81,0,46-8.49,62.49-23.91,17-15.9,26.37-37.93,26.37-62C228.4,120.37,185.94,89.86,144.89,89.86Zm.49,153.67a61.49,61.49,0,0,1-46.45-20.4c-12.33-13.76-18.85-32.64-18.85-54.62,0-20.7,6.07-37.67,17.57-49.07,10.11-10,24.39-15.62,40.19-15.74,19,0,35.22,6.56,46.76,19,12.6,13.58,19.27,34,19.27,58.95C203.87,224.39,174.49,243.53,145.38,243.53Z"/>
<polygon class="cls-1" points="198.75 74.96 179.45 74.96 142.09 37.83 104.51 74.96 86.14 74.96 138.09 24.25 146.81 24.25 198.75 74.96"/>
</svg>

Before

Width:  |  Height:  |  Size: 855 B

View File

@@ -1,25 +0,0 @@
<script setup lang="ts">
const { framework, frameworks } = useSharedData()
</script>
<template>
<UDropdownMenu
v-slot="{ open }"
:modal="false"
:items="frameworks"
:ui="{ content: 'w-(--radix-dropdown-menu-trigger-width)' }"
>
<UButton
color="neutral"
variant="outline"
v-bind="frameworks.find(f => f.value === framework)"
block
trailing-icon="i-lucide-chevron-down"
:class="[open && 'bg-[var(--ui-bg-elevated)]']"
:ui="{
trailingIcon: ['transition-transform duration-200', open ? 'rotate-180' : undefined].filter(Boolean).join(' ')
}"
class="-mx-2 w-[calc(100%+1rem)]"
/>
</UDropdownMenu>
</template>

View File

@@ -42,7 +42,7 @@ defineShortcuts({
<UButton <UButton
color="neutral" color="neutral"
variant="ghost" variant="ghost"
to="https://github.com/nuxt/ui" to="https://github.com/nuxt/ui/tree/v3"
target="_blank" target="_blank"
icon="i-simple-icons-github" icon="i-simple-icons-github"
aria-label="GitHub" aria-label="GitHub"
@@ -55,8 +55,6 @@ defineShortcuts({
<USeparator type="dashed" class="my-4" /> <USeparator type="dashed" class="my-4" />
<FrameworkSelect class="mb-4" />
<UContentNavigation :navigation="navigation" highlight /> <UContentNavigation :navigation="navigation" highlight />
</template> </template>
</UHeader> </UHeader>

View File

@@ -3,42 +3,9 @@
import json5 from 'json5' import json5 from 'json5'
import { upperFirst, camelCase, kebabCase } from 'scule' import { upperFirst, camelCase, kebabCase } from 'scule'
import { hash } from 'ohash' import { hash } from 'ohash'
import { CalendarDate } from '@internationalized/date'
import * as theme from '#build/ui' import * as theme from '#build/ui'
import { get, set } from '#ui/utils' import { get, set } from '#ui/utils'
interface Cast {
get: (args: any) => any
template: (args: any) => string
}
type CastDateValue = [number, number, number]
const castMap: Record<string, Cast> = {
'DateValue': {
get: (args: CastDateValue) => new CalendarDate(...args),
template: (value: CalendarDate) => {
return value ? `new CalendarDate(${value.year}, ${value.month}, ${value.day})` : 'null'
}
},
'DateValue[]': {
get: (args: CastDateValue[]) => args.map(date => new CalendarDate(...date)),
template: (value: CalendarDate[]) => {
return value ? `[${value.map(date => `new CalendarDate(${date.year}, ${date.month}, ${date.day})`).join(', ')}]` : '[]'
}
},
'DateRange': {
get: (args: { start: CastDateValue, end: CastDateValue }) => ({ start: new CalendarDate(...args.start), end: new CalendarDate(...args.end) }),
template: (value: { start: CalendarDate, end: CalendarDate }) => {
if (!value.start || !value.end) {
return `{ start: null, end: null }`
}
return `{ start: new CalendarDate(${value.start.year}, ${value.start.month}, ${value.start.day}), end: new CalendarDate(${value.end.year}, ${value.end.month}, ${value.end.day}) }`
}
}
}
const props = defineProps<{ const props = defineProps<{
/** Override the slug taken from the route */ /** Override the slug taken from the route */
slug?: string slug?: string
@@ -51,8 +18,6 @@ const props = defineProps<{
external?: string[] external?: string[]
/** List of props to use with `v-model` */ /** List of props to use with `v-model` */
model?: string[] model?: string[]
/** List of props to cast from code and selection */
cast?: { [key: string]: string }
/** List of items for each prop */ /** List of items for each prop */
items?: { [key: string]: string[] } items?: { [key: string]: string[] }
props?: { [key: string]: any } props?: { [key: string]: any }
@@ -80,17 +45,7 @@ const camelName = camelCase(props.slug ?? route.params.slug?.[route.params.slug.
const name = `U${upperFirst(camelName)}` const name = `U${upperFirst(camelName)}`
const component = defineAsyncComponent(() => import(`#ui/components/${upperFirst(camelName)}.vue`)) const component = defineAsyncComponent(() => import(`#ui/components/${upperFirst(camelName)}.vue`))
const componentProps = reactive({ const componentProps = reactive({ ...(props.props || {}) })
...Object.fromEntries(Object.entries(props.props || {}).map(([key, value]) => {
const cast = props.cast?.[key]
if (cast && !castMap[cast]) {
throw new Error(`Unknown cast: ${cast}`)
}
return [key, cast ? castMap[cast]!.get(value) : value]
}))
})
const componentEvents = reactive({ const componentEvents = reactive({
...Object.fromEntries((props.model || []).map(key => [`onUpdate:${key}`, (e: any) => setComponentProp(key, e)])), ...Object.fromEntries((props.model || []).map(key => [`onUpdate:${key}`, (e: any) => setComponentProp(key, e)])),
...(componentProps.modelValue ? { [`onUpdate:modelValue`]: (e: any) => setComponentProp('modelValue', e) } : {}) ...(componentProps.modelValue ? { [`onUpdate:modelValue`]: (e: any) => setComponentProp('modelValue', e) } : {})
@@ -141,7 +96,7 @@ const options = computed(() => {
return { return {
name: key, name: key,
label: key, label: key,
type: props?.cast?.[key] ?? prop?.type, type: prop?.type,
items items
} }
}) })
@@ -162,10 +117,7 @@ const code = computed(() => {
<script setup lang="ts"> <script setup lang="ts">
` `
for (const key of props.external) { for (const key of props.external) {
const cast = props.cast?.[key] code += `const ${key === 'modelValue' ? 'value' : key} = ref(${json5.stringify(componentProps[key], null, 2).replace(/,([ |\t\n]+[}|\]])/g, '$1')})
const value = cast ? castMap[cast]!.template(componentProps[key]) : json5.stringify(componentProps[key], null, 2).replace(/,([ |\t\n]+[}|\]])/g, '$1')
code += `const ${key === 'modelValue' ? 'value' : key} = ref(${value})
` `
} }
code += `<\/script> code += `<\/script>
@@ -212,7 +164,7 @@ const code = computed(() => {
continue continue
} }
code += ` ${typeof value === 'number' ? ':' : ''}${name}="${value}"` code += ` ${prop?.type.includes('number') ? ':' : ''}${name}="${value}"`
} }
} }
@@ -268,7 +220,7 @@ const { data: ast } = await useAsyncData(`component-code-${name}-${hash({ props:
<template> <template>
<div class="my-5"> <div class="my-5">
<div> <div>
<div v-if="options.length" class="flex items-center gap-2.5 border border-[var(--ui-border-muted)] border-b-0 relative rounded-t-[calc(var(--ui-radius)*1.5)] px-4 py-2.5 overflow-x-auto"> <div v-if="options.length" class="flex items-center gap-2.5 border border-[var(--ui-color-neutral-200)] dark:border-[var(--ui-color-neutral-700)] border-b-0 relative rounded-t-[calc(var(--ui-radius)*1.5)] px-4 py-2.5 overflow-x-auto">
<template v-for="option in options" :key="option.name"> <template v-for="option in options" :key="option.name">
<UFormField <UFormField
:label="option.label" :label="option.label"
@@ -317,7 +269,7 @@ const { data: ast } = await useAsyncData(`component-code-${name}-${hash({ props:
</template> </template>
</div> </div>
<div v-if="component" class="flex justify-center border border-b-0 border-[var(--ui-border-muted)] relative p-4 z-[1]" :class="[!options.length && 'rounded-t-[calc(var(--ui-radius)*1.5)]', props.class]"> <div v-if="component" class="flex justify-center border border-b-0 border-[var(--ui-color-neutral-200)] dark:border-[var(--ui-color-neutral-700)] relative p-4 z-[1]" :class="[!options.length && 'rounded-t-[calc(var(--ui-radius)*1.5)]', props.class]">
<component :is="component" v-bind="{ ...componentProps, ...componentEvents }"> <component :is="component" v-bind="{ ...componentProps, ...componentEvents }">
<template v-for="slot in Object.keys(slots || {})" :key="slot" #[slot]> <template v-for="slot in Object.keys(slots || {})" :key="slot" #[slot]>
<MDCSlot :name="slot" unwrap="p"> <MDCSlot :name="slot" unwrap="p">

View File

@@ -117,8 +117,8 @@ const optionsValues = ref(props.options?.reduce((acc, option) => {
<template> <template>
<div class="my-5"> <div class="my-5">
<template v-if="preview"> <template v-if="preview">
<div class="border border-[var(--ui-border-muted)] relative z-[1]" :class="[{ 'border-b-0 rounded-t-[calc(var(--ui-radius)*1.5)]': props.source, 'rounded-[calc(var(--ui-radius)*1.5)]': !props.source }]"> <div class="border border-[var(--ui-color-neutral-200)] dark:border-[var(--ui-color-neutral-700)] relative z-[1]" :class="[{ 'border-b-0 rounded-t-[calc(var(--ui-radius)*1.5)]': props.source, 'rounded-[calc(var(--ui-radius)*1.5)]': !props.source }]">
<div v-if="props.options?.length || !!slots.options" class="flex gap-4 p-4 border-b border-[var(--ui-border-muted)]"> <div v-if="props.options?.length || !!slots.options" class="flex gap-4 p-4 border-b border-[var(--ui-color-neutral-200)] dark:border-[var(--ui-color-neutral-700)]">
<slot name="options" /> <slot name="options" />
<UFormField <UFormField

View File

@@ -35,7 +35,7 @@ const schemaProps = computed(() => {
</script> </script>
<template> <template>
<ProseCollapsible v-if="schemaProps?.length" class="mt-1"> <Collapsible v-if="schemaProps?.length" class="mt-1">
<ProseUl> <ProseUl>
<ProseLi v-for="schemaProp in schemaProps" :key="schemaProp.name"> <ProseLi v-for="schemaProp in schemaProps" :key="schemaProp.name">
<HighlightInlineType :type="`${schemaProp.name}${schemaProp.required === false ? '?' : ''}: ${schemaProp.type}`" /> <HighlightInlineType :type="`${schemaProp.name}${schemaProp.required === false ? '?' : ''}: ${schemaProp.type}`" />
@@ -43,5 +43,5 @@ const schemaProps = computed(() => {
<MDC v-if="schemaProp.description" :value="schemaProp.description" class="text-[var(--ui-text-muted)] my-1" /> <MDC v-if="schemaProp.description" :value="schemaProp.description" class="text-[var(--ui-text-muted)] my-1" />
</ProseLi> </ProseLi>
</ProseUl> </ProseUl>
</ProseCollapsible> </Collapsible>
</template> </template>

View File

@@ -4,19 +4,14 @@ import { camelCase } from 'scule'
import * as theme from '#build/ui' import * as theme from '#build/ui'
const route = useRoute() const route = useRoute()
const { framework } = useSharedData()
const name = camelCase(route.params.slug?.[route.params.slug.length - 1] ?? '') const name = camelCase(route.params.slug?.[route.params.slug.length - 1] ?? '')
const strippedCompoundVariants = ref(false) const strippedCompoundVariants = ref(false)
const strippedTheme = computed(() => { function stripCompoundVariants(component?: any) {
const strippedTheme = { if (component?.compoundVariants) {
...(theme as any)[name] component.compoundVariants = component.compoundVariants.filter((compoundVariant: any) => {
}
if (strippedTheme?.compoundVariants) {
strippedTheme.compoundVariants = strippedTheme.compoundVariants.filter((compoundVariant: any) => {
if (compoundVariant.color) { if (compoundVariant.color) {
if (!['primary', 'neutral'].includes(compoundVariant.color)) { if (!['primary', 'neutral'].includes(compoundVariant.color)) {
strippedCompoundVariants.value = true strippedCompoundVariants.value = true
@@ -45,43 +40,24 @@ const strippedTheme = computed(() => {
}) })
} }
return strippedTheme return component
}) }
const component = computed(() => { const component = computed(() => {
return { return {
ui: { ui: {
[name]: strippedTheme.value [name]: stripCompoundVariants((theme as any)[name])
} }
} }
}) })
const { data: ast } = await useAsyncData(`component-theme-${name}-${framework.value}`, async () => { const { data: ast } = await useAsyncData(`component-theme-${name}`, async () => {
const md = ` const md = `
::code-collapse ::code-collapse
${framework.value === 'nuxt'
? `
\`\`\`ts [app.config.ts] \`\`\`ts [app.config.ts]
export default defineAppConfig(${json5.stringify(component.value, null, 2).replace(/,([ |\t\n]+[}|\])])/g, '$1')}) export default defineAppConfig(${json5.stringify(component.value, null, 2).replace(/,([ |\t\n]+[}|\])])/g, '$1')})
\`\`\`\ \`\`\`\
`
: `
\`\`\`ts [vite.config.ts]
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import ui from '@nuxt/ui/vite'
export default defineConfig({
plugins: [
vue(),
ui(${json5.stringify(component.value, null, 2).replace(/,([ |\t\n]+[}|\])])/g, '$1')
.split('\n')
.map((line, i) => i === 0 ? line : ` ${line}`)
.join('\n')})
]
})
\`\`\`
`}
:: ::
${strippedCompoundVariants.value ${strippedCompoundVariants.value
@@ -93,7 +69,7 @@ Some colors in \`compoundVariants\` are omitted for readability. Check out the s
` `
return parseMarkdown(md) return parseMarkdown(md)
}, { watch: [framework] }) })
</script> </script>
<template> <template>

View File

@@ -1,7 +0,0 @@
<script setup lang="ts">
const { framework } = useSharedData()
</script>
<template>
<slot :name="framework" />
</template>

View File

@@ -2,13 +2,8 @@
import json5 from 'json5' import json5 from 'json5'
import icons from '../../../../src/theme/icons' import icons from '../../../../src/theme/icons'
const { framework } = useSharedData() const { data: ast } = await useAsyncData(`icons-theme`, async () => {
const { data: ast } = await useAsyncData(`icons-theme-${framework.value}`, async () => {
const md = ` const md = `
::code-collapse
${framework.value === 'nuxt'
? `
\`\`\`ts [app.config.ts] \`\`\`ts [app.config.ts]
export default defineAppConfig(${json5.stringify({ export default defineAppConfig(${json5.stringify({
ui: { ui: {
@@ -16,33 +11,10 @@ export default defineAppConfig(${json5.stringify({
} }
}, null, 2).replace(/,([ |\t\n]+[}|\])])/g, '$1')}) }, null, 2).replace(/,([ |\t\n]+[}|\])])/g, '$1')})
\`\`\`\ \`\`\`\
`
: `
\`\`\`ts [vite.config.ts]
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import ui from '@nuxt/ui/vite'
export default defineConfig({
plugins: [
vue(),
ui(${json5.stringify({
ui: {
icons
}
}, null, 2).replace(/,([ |\t\n]+[}|\])])/g, '$1')
.split('\n')
.map((line, i) => i === 0 ? line : ` ${line}`)
.join('\n')})
]
})
\`\`\`
`}
::
` `
return parseMarkdown(md) return parseMarkdown(md)
}, { watch: [framework] }) })
</script> </script>
<template> <template>

View File

@@ -1,53 +1,34 @@
<script setup lang="ts"> <script setup lang="ts">
import type { Locale } from '@nuxt/ui'
import * as locales from '@nuxt/ui/locale' import * as locales from '@nuxt/ui/locale'
type LocaleKey = keyof typeof locales
type LocaleComputed = Locale & { flag: string }
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
default?: string default?: string
}>(), { }>(), {
default: 'en' default: 'en'
}) })
const countries = await $fetch('/api/locales.json') const getLocaleKeys = () => Object.keys(locales) as Array<keyof typeof locales>
const localesList = getLocaleKeys().map(locale => [locale, locales[locale].name])
const getLocaleKeys = Object.keys(locales) as LocaleKey[]
const localesList = getLocaleKeys.map<LocaleComputed>((code) => {
const locale: Locale = locales[code]
return {
...locale,
flag: countries[locale.code] || ''
}
})
</script> </script>
<!-- eslint-disable vue/singleline-html-element-content-newline --> <!-- eslint-disable vue/singleline-html-element-content-newline -->
<template> <template>
<div> <div>
<ProseP> <ProseUl>
By default, the <ProseCode>{{ props.default }}</ProseCode> locale is used. <ProseLi v-for="[key, label] in localesList" :key="key">
</ProseP> <ProseCode>{{ key }}</ProseCode> - {{ label }}
<div class="grid gap-6 grid-cols-2 md:grid-cols-3"> <template v-if="key === props.default">
<div v-for="locale in localesList" :key="locale.code"> (default)
<div class="flex gap-3 items-center"> </template>
<UAvatar :text="locale.flag" size="xl" /> </ProseLi>
<div class="text-sm"> </ProseUl>
<div class="font-semibold">{{ locale.name }}</div> <Note to="https://github.com/nuxt/ui/tree/v3/src/runtime/locale" target="_blank">
<div class="mt-1">Code: <ProseCode class="text-xs">{{ locale.code }}</ProseCode></div>
</div>
</div>
</div>
</div>
<ProseNote to="https://github.com/nuxt/ui/tree/v3/src/runtime/locale" target="_blank">
If you need additional languages, you can contribute by creating a PR to add a new locale in <ProseCode>src/runtime/locale/</ProseCode>. If you need additional languages, you can contribute by creating a PR to add a new locale in <ProseCode>src/runtime/locale/</ProseCode>.
</ProseNote> </Note>
<ProseTip> <Tip>
You can use the <ProseCode>nuxt-ui</ProseCode> CLI to create a new locale: You can use the <ProseCode>nuxt-ui</ProseCode> CLI to create a new locale:
<ProsePre language="bash">nuxt-ui make locale --code "en" --name "English"</ProsePre> <ProsePre language="bash">nuxt-ui make locale --code "en" --name "English"</ProsePre>
</ProseTip> </Tip>
</div> </div>
</template> </template>

View File

@@ -1,21 +0,0 @@
<script setup lang="ts">
import { CalendarDate, DateFormatter, getLocalTimeZone } from '@internationalized/date'
const df = new DateFormatter('en-US', {
dateStyle: 'medium'
})
const modelValue = shallowRef(new CalendarDate(2022, 1, 10))
</script>
<template>
<UPopover>
<UButton color="neutral" variant="subtle" icon="i-lucide-calendar">
{{ df.format(modelValue.toDate(getLocalTimeZone())) }}
</UButton>
<template #content>
<UCalendar v-model="modelValue" class="p-2" />
</template>
</UPopover>
</template>

View File

@@ -1,35 +0,0 @@
<script setup lang="ts">
import { CalendarDate, DateFormatter, getLocalTimeZone } from '@internationalized/date'
const df = new DateFormatter('en-US', {
dateStyle: 'medium'
})
const modelValue = shallowRef({
start: new CalendarDate(2022, 1, 20),
end: new CalendarDate(2022, 2, 10)
})
</script>
<template>
<UPopover>
<UButton color="neutral" variant="subtle" icon="i-lucide-calendar">
<template v-if="modelValue.start">
<template v-if="modelValue.end">
{{ df.format(modelValue.start.toDate(getLocalTimeZone())) }} - {{ df.format(modelValue.end.toDate(getLocalTimeZone())) }}
</template>
<template v-else>
{{ df.format(modelValue.start.toDate(getLocalTimeZone())) }}
</template>
</template>
<template v-else>
Pick a date
</template>
</UButton>
<template #content>
<UCalendar v-model="modelValue" class="p-2" :number-of-months="2" range />
</template>
</UPopover>
</template>

View File

@@ -1,17 +0,0 @@
<script setup lang="ts">
import { CalendarDate } from '@internationalized/date'
import type { Matcher } from 'radix-vue/date'
const modelValue = shallowRef({
start: new CalendarDate(2022, 1, 1),
end: new CalendarDate(2022, 1, 9)
})
const isDateDisabled: Matcher = (date) => {
return date.day >= 10 && date.day <= 16
}
</script>
<template>
<UCalendar v-model="modelValue" :is-date-disabled="isDateDisabled" range />
</template>

View File

@@ -1,30 +0,0 @@
<script setup lang="ts">
import { CalendarDate } from '@internationalized/date'
const modelValue = shallowRef(new CalendarDate(2022, 1, 10))
function getColorByDate(date: Date) {
const isWeekend = date.getDay() % 6 == 0
const isDayMeeting = date.getDay() % 3 == 0
if (isWeekend) {
return undefined
}
if (isDayMeeting) {
return 'error'
}
return 'success'
}
</script>
<template>
<UCalendar v-model="modelValue">
<template #day="{ day }">
<UChip :show="!!getColorByDate(day.toDate('UTC'))" :color="getColorByDate(day.toDate('UTC'))" size="2xs">
{{ day.day }}
</UChip>
</template>
</UCalendar>
</template>

View File

@@ -1,11 +0,0 @@
<script setup lang="ts">
import { CalendarDate } from '@internationalized/date'
const modelValue = shallowRef(new CalendarDate(2023, 9, 10))
const minDate = new CalendarDate(2023, 9, 1)
const maxDate = new CalendarDate(2023, 9, 30)
</script>
<template>
<UCalendar v-model="modelValue" :min-value="minDate" :max-value="maxDate" />
</template>

View File

@@ -1,17 +0,0 @@
<script setup lang="ts">
import { CalendarDate } from '@internationalized/date'
import type { Matcher } from 'radix-vue/date'
const modelValue = shallowRef({
start: new CalendarDate(2022, 1, 1),
end: new CalendarDate(2022, 1, 9)
})
const isDateUnavailable: Matcher = (date) => {
return date.day >= 10 && date.day <= 16
}
</script>
<template>
<UCalendar v-model="modelValue" :is-date-unavailable="isDateUnavailable" range />
</template>

View File

@@ -32,7 +32,7 @@ const items = computed(() => [{
</script> </script>
<template> <template>
<UContextMenu :items="items" :ui="{ content: 'w-48' }"> <UContextMenu :items="items" class="w-48">
<div class="flex items-center justify-center rounded-md border border-dashed border-[var(--ui-border-accented)] text-sm aspect-video w-72"> <div class="flex items-center justify-center rounded-md border border-dashed border-[var(--ui-border-accented)] text-sm aspect-video w-72">
Right click here Right click here
</div> </div>

View File

@@ -25,7 +25,7 @@ const items = [
</script> </script>
<template> <template>
<UContextMenu :items="items" :ui="{ content: 'w-48' }"> <UContextMenu :items="items" class="w-48">
<div class="flex items-center justify-center rounded-md border border-dashed border-[var(--ui-border-accented)] text-sm aspect-video w-72"> <div class="flex items-center justify-center rounded-md border border-dashed border-[var(--ui-border-accented)] text-sm aspect-video w-72">
Right click here Right click here
</div> </div>

View File

@@ -12,7 +12,7 @@ const items = [{
</script> </script>
<template> <template>
<UContextMenu :items="items" :ui="{ content: 'w-48' }"> <UContextMenu :items="items" class="w-48">
<div class="flex items-center justify-center rounded-md border border-dashed border-[var(--ui-border-accented)] text-sm aspect-video w-72"> <div class="flex items-center justify-center rounded-md border border-dashed border-[var(--ui-border-accented)] text-sm aspect-video w-72">
Right click here Right click here
</div> </div>

View File

@@ -40,7 +40,7 @@ const items = computed(() => [{
</script> </script>
<template> <template>
<UDropdownMenu :items="items" :content="{ align: 'start' }" :ui="{ content: 'w-48' }"> <UDropdownMenu :items="items" :content="{ align: 'start' }" class="w-48">
<UButton label="Open" color="neutral" variant="outline" icon="i-lucide-menu" /> <UButton label="Open" color="neutral" variant="outline" icon="i-lucide-menu" />
</UDropdownMenu> </UDropdownMenu>
</template> </template>

View File

@@ -25,7 +25,7 @@ const items = [
</script> </script>
<template> <template>
<UDropdownMenu :items="items" :ui="{ content: 'w-48' }"> <UDropdownMenu :items="items" class="w-48">
<UButton label="Open" color="neutral" variant="outline" icon="i-lucide-menu" /> <UButton label="Open" color="neutral" variant="outline" icon="i-lucide-menu" />
<template #profile-trailing> <template #profile-trailing>

View File

@@ -13,7 +13,7 @@ const items = [{
</script> </script>
<template> <template>
<UDropdownMenu :items="items" :ui="{ content: 'w-48' }"> <UDropdownMenu :items="items" class="w-48">
<UButton label="Open" color="neutral" variant="outline" icon="i-lucide-menu" /> <UButton label="Open" color="neutral" variant="outline" icon="i-lucide-menu" />
<template #profile-trailing> <template #profile-trailing>

View File

@@ -18,7 +18,7 @@ const items = [{
</script> </script>
<template> <template>
<UDropdownMenu v-model:open="open" :items="items" :ui="{ content: 'w-48' }"> <UDropdownMenu v-model:open="open" :items="items" class="w-48">
<UButton label="Open" color="neutral" variant="outline" icon="i-lucide-menu" /> <UButton label="Open" color="neutral" variant="outline" icon="i-lucide-menu" />
</UDropdownMenu> </UDropdownMenu>
</template> </template>

View File

@@ -4,7 +4,6 @@ import type { FormSubmitEvent } from '@nuxt/ui'
const schema = z.object({ const schema = z.object({
input: z.string().min(10), input: z.string().min(10),
inputNumber: z.number().min(10),
inputMenu: z.any().refine(option => option?.value === 'option-2', { inputMenu: z.any().refine(option => option?.value === 'option-2', {
message: 'Select Option 2' message: 'Select Option 2'
}), }),
@@ -30,11 +29,10 @@ const schema = z.object({
radioGroup: z.string().refine(value => value === 'option-2', { radioGroup: z.string().refine(value => value === 'option-2', {
message: 'Select Option 2' message: 'Select Option 2'
}), }),
slider: z.number().max(20, { message: 'Must be less than 20' }), slider: z.number().max(20, { message: 'Must be less than 20' })
pin: z.string().regex(/^\d$/).array().length(5)
}) })
type Schema = z.input<typeof schema> type Schema = z.output<typeof schema>
const state = reactive<Partial<Schema>>({}) const state = reactive<Partial<Schema>>({})
@@ -54,10 +52,10 @@ async function onSubmit(event: FormSubmitEvent<any>) {
</script> </script>
<template> <template>
<UForm ref="form" :state="state" :schema="schema" class="w-full" @submit="onSubmit"> <UForm ref="form" :state="state" :schema="schema" @submit="onSubmit">
<div class="grid grid-cols-3 gap-4"> <div class="grid grid-cols-3 gap-4">
<UFormField label="Input" name="input"> <UFormField label="Input" name="input">
<UInput v-model="state.input" placeholder="john@lennon.com" class="w-full" /> <UInput v-model="state.input" placeholder="john@lennon.com" class="w-40" />
</UFormField> </UFormField>
<div class="flex flex-col gap-4"> <div class="flex flex-col gap-4">
@@ -75,40 +73,34 @@ async function onSubmit(event: FormSubmitEvent<any>) {
</UFormField> </UFormField>
<UFormField name="select" label="Select"> <UFormField name="select" label="Select">
<USelect v-model="state.select" :items="items" class="w-full" /> <USelect v-model="state.select" :items="items" class="w-48" />
</UFormField> </UFormField>
<UFormField name="selectMenu" label="Select Menu"> <UFormField name="selectMenu" label="Select Menu">
<USelectMenu v-model="state.selectMenu" :items="items" class="w-full" /> <USelectMenu v-model="state.selectMenu" :items="items" class="w-48" />
</UFormField> </UFormField>
<UFormField name="selectMenuMultiple" label="Select Menu (Multiple)"> <UFormField name="selectMenuMultiple" label="Select Menu (Multiple)">
<USelectMenu v-model="state.selectMenuMultiple" multiple :items="items" class="w-full" /> <USelectMenu v-model="state.selectMenuMultiple" multiple :items="items" class="w-48" />
</UFormField> </UFormField>
<UFormField name="inputMenu" label="Input Menu"> <UFormField name="inputMenu" label="Input Menu">
<UInputMenu v-model="state.inputMenu" :items="items" class="w-full" /> <UInputMenu v-model="state.inputMenu" :items="items" />
</UFormField> </UFormField>
<UFormField name="inputMenuMultiple" label="Input Menu (Multiple)"> <UFormField name="inputMenuMultiple" label="Input Menu (Multiple)">
<UInputMenu v-model="state.inputMenuMultiple" multiple :items="items" class="w-full" /> <UInputMenu v-model="state.inputMenuMultiple" multiple :items="items" />
</UFormField> </UFormField>
<UFormField name="inputNumber" label="Input Number"> <span />
<UInputNumber v-model="state.inputNumber" class="w-full" />
</UFormField>
<UFormField label="Textarea" name="textarea"> <UFormField label="Textarea" name="textarea">
<UTextarea v-model="state.textarea" class="w-full" /> <UTextarea v-model="state.textarea" />
</UFormField> </UFormField>
<UFormField name="radioGroup"> <UFormField name="radioGroup">
<URadioGroup v-model="state.radioGroup" legend="Radio group" :items="items" /> <URadioGroup v-model="state.radioGroup" legend="Radio group" :items="items" />
</UFormField> </UFormField>
<UFormField name="pin" label="Pin Input" :error-pattern="/(pin)\..*/">
<UPinInput v-model="state.pin" />
</UFormField>
</div> </div>
<div class="flex gap-2 mt-8"> <div class="flex gap-2 mt-8">

View File

@@ -1,15 +0,0 @@
<script setup lang="ts">
const value = ref(1500)
</script>
<template>
<UInputNumber
v-model="value"
:format-options="{
style: 'currency',
currency: 'EUR',
currencyDisplay: 'code',
currencySign: 'accounting'
}"
/>
</template>

View File

@@ -1,13 +0,0 @@
<script setup lang="ts">
const value = ref(5)
</script>
<template>
<UInputNumber
v-model="value"
:format-options="{
signDisplay: 'exceptZero',
minimumFractionDigits: 1
}"
/>
</template>

View File

@@ -1,9 +0,0 @@
<script setup lang="ts">
const retries = ref(0)
</script>
<template>
<UFormField label="Retries" help="Specify number of attempts" required>
<UInputNumber v-model="retries" placeholder="Enter retries" />
</UFormField>
</template>

View File

@@ -1,13 +0,0 @@
<script setup lang="ts">
const value = ref(0.05)
</script>
<template>
<UInputNumber
v-model="value"
:step="0.01"
:format-options="{
style: 'percent'
}"
/>
</template>

View File

@@ -1,15 +0,0 @@
<script setup lang="ts">
const value = ref(5)
</script>
<template>
<UInputNumber v-model="value">
<template #decrement>
<UButton size="xs" icon="i-lucide-minus" />
</template>
<template #increment>
<UButton size="xs" icon="i-lucide-plus" />
</template>
</UInputNumber>
</template>

View File

@@ -6,7 +6,7 @@ const value = ref('Click to clear')
<UInput <UInput
v-model="value" v-model="value"
placeholder="Type something..." placeholder="Type something..."
:ui="{ trailing: 'pe-1' }" :ui="{ trailing: 'pr-0.5' }"
> >
<template v-if="value?.length" #trailing> <template v-if="value?.length" #trailing>
<UButton <UButton

View File

@@ -1,33 +0,0 @@
<script setup lang="ts">
const value = ref('npx nuxi module add ui')
const copied = ref(false)
function copy() {
navigator.clipboard.writeText(value.value)
copied.value = true
setTimeout(() => {
copied.value = false
}, 2000)
}
</script>
<template>
<UInput
v-model="value"
:ui="{ trailing: 'pr-0.5' }"
>
<template v-if="value?.length" #trailing>
<UTooltip text="Copy to clipboard" :content="{ side: 'right' }">
<UButton
:color="copied ? 'success' : 'neutral'"
variant="link"
size="sm"
:icon="copied ? 'i-lucide-copy-check' : 'i-lucide-copy'"
aria-label="Copy to clipboard"
@click="copy"
/>
</UTooltip>
</template>
</UInput>
</template>

View File

@@ -1,21 +0,0 @@
<script setup lang="ts">
const input = useTemplateRef('input')
defineShortcuts({
'/': () => {
input.value?.inputRef?.focus()
}
})
</script>
<template>
<UInput
ref="input"
icon="i-lucide-search"
placeholder="Search..."
>
<template #trailing>
<UKbd value="/" />
</template>
</UInput>
</template>

View File

@@ -40,7 +40,7 @@ const text = computed(() => {
placeholder="Password" placeholder="Password"
:color="color" :color="color"
:type="show ? 'text' : 'password'" :type="show ? 'text' : 'password'"
:ui="{ trailing: 'pe-1' }" :ui="{ trailing: 'pr-0.5' }"
:aria-invalid="score < 4" :aria-invalid="score < 4"
aria-describedby="password-strength" aria-describedby="password-strength"
class="w-full" class="w-full"

View File

@@ -8,7 +8,7 @@ const password = ref('password')
v-model="password" v-model="password"
placeholder="Password" placeholder="Password"
:type="show ? 'text' : 'password'" :type="show ? 'text' : 'password'"
:ui="{ trailing: 'pe-1' }" :ui="{ trailing: 'pr-0.5' }"
> >
<template #trailing> <template #trailing>
<UButton <UButton

View File

@@ -56,7 +56,7 @@ defineProps({
<h1 class="m-0 text-[75px] font-semibold mb-2 text-white flex items-center"> <h1 class="m-0 text-[75px] font-semibold mb-2 text-white flex items-center">
<span>{{ title }}</span> <span>{{ title }}</span>
</h1> </h1>
<p v-if="description" class="text-[32px] text-[#94a3b8] leading-tight text-balance"> <p v-if="description" class="text-[32px] text-[#94a3b8] leading-tight">
{{ description.slice(0, 200) }} {{ description.slice(0, 200) }}
</p> </p>
</div> </div>

View File

@@ -1,23 +0,0 @@
import { createSharedComposable } from '@vueuse/core'
function _useSharedData() {
const framework = useCookie('nuxt-ui-framework', { default: () => 'nuxt' })
const frameworks = computed(() => [{
label: 'Nuxt',
icon: 'i-logos-nuxt-icon',
value: 'nuxt',
onSelect: () => framework.value = 'nuxt'
}, {
label: 'Vue',
icon: 'i-logos-vue',
value: 'vue',
onSelect: () => framework.value = 'vue'
}].map(f => ({ ...f, active: framework.value === f.value })))
return {
framework,
frameworks
}
}
export const useSharedData = createSharedComposable(_useSharedData)

View File

@@ -10,10 +10,6 @@ const navigation = inject<Ref<ContentNavigationItem[]>>('navigation')
<UPage> <UPage>
<template #left> <template #left>
<UPageAside> <UPageAside>
<template #top>
<FrameworkSelect />
</template>
<UContentNavigation :navigation="navigation" highlight /> <UContentNavigation :navigation="navigation" highlight />
</UPageAside> </UPageAside>
</template> </template>

View File

@@ -21,32 +21,10 @@ const navigation = inject<Ref<ContentNavigationItem[]>>('navigation')
const breadcrumb = computed(() => mapContentNavigation(findPageBreadcrumb(navigation?.value, page.value)).map(({ icon, ...link }) => link)) const breadcrumb = computed(() => mapContentNavigation(findPageBreadcrumb(navigation?.value, page.value)).map(({ icon, ...link }) => link))
const { framework } = useSharedData()
// Redirect to the correct framework version if the page is not the current framework
if (!import.meta.prerender) {
watch(framework, () => {
if (page.value?.navigation?.framework && page.value?.navigation?.framework !== framework.value) {
if (route.path.endsWith(`/${page.value?.navigation?.framework}`)) {
navigateTo(`${route.path.split('/').slice(0, -1).join('/')}/${framework.value}`)
} else {
navigateTo(`/getting-started`)
}
}
})
}
// Update the framework if the page has a different framework
watch(page, () => {
if (page.value?.navigation?.framework && page.value?.navigation?.framework !== framework.value) {
framework.value = page.value?.navigation?.framework as string
}
}, { immediate: true })
useSeoMeta({ useSeoMeta({
titleTemplate: '%s - Nuxt UI v3', titleTemplate: '%s - Nuxt UI v3',
title: typeof page.value.navigation === 'object' && page.value.navigation.title ? page.value.navigation.title : page.value.title, title: typeof page.value.navigation === 'object' ? page.value.navigation.title : page.value.title,
ogTitle: `${typeof page.value.navigation === 'object' && page.value.navigation.title ? page.value.navigation.title : page.value.title} - Nuxt UI v3`, ogTitle: `${typeof page.value.navigation === 'object' ? page.value.navigation.title : page.value.title} - Nuxt UI v3`,
description: page.value.description, description: page.value.description,
ogDescription: page.value.description ogDescription: page.value.description
}) })
@@ -97,6 +75,21 @@ const communityLinks = computed(() => [{
</template> </template>
<template #links> <template #links>
<UDropdownMenu v-if="page.select" v-slot="{ open }" :items="page.select.items" :content="{ align: 'end' }">
<UButton
color="neutral"
variant="subtle"
v-bind="page.select.items.find((item: any) => item.to === route.path)"
block
trailing-icon="i-lucide-chevron-down"
:class="[open && 'bg-[var(--ui-bg-accented)]/75']"
:ui="{
trailingIcon: ['transition-transform duration-200', open ? 'rotate-180' : undefined].filter(Boolean).join(' ')
}"
class="w-[128px]"
/>
</UDropdownMenu>
<UButton <UButton
v-for="link in page.links" v-for="link in page.links"
:key="link.label" :key="link.label"

View File

@@ -5,10 +5,6 @@ export const collections = {
type: 'page', type: 'page',
source: '**/*', source: '**/*',
schema: z.object({ schema: z.object({
navigation: z.object({
title: z.string().optional(),
framework: z.string().optional()
}),
links: z.array(z.object({ links: z.array(z.object({
label: z.string(), label: z.string(),
icon: z.string(), icon: z.string(),
@@ -18,7 +14,14 @@ export const collections = {
}).optional(), }).optional(),
to: z.string(), to: z.string(),
target: z.string().optional() target: z.string().optional()
})) })),
select: z.object({
items: z.array(z.object({
label: z.string(),
icon: z.string(),
to: z.string()
}))
})
}) })
}) })
} }

View File

@@ -21,15 +21,15 @@ This transition empowers Nuxt UI to become a more comprehensive and flexible UI
### Tailwind CSS v4 ### Tailwind CSS v4
Nuxt UI v3 integrates the latest Tailwind CSS v4 beta (released Nov 21, 2024), bringing significant improvements: Nuxt UI v3 integrates the latest Tailwind CSS v4 alpha (announced March 6, 2024), bringing significant improvements:
- **Built for performance**: Full builds in the new engine are up to 5x faster, and incremental builds are over 100x faster — and measured in microseconds. - **Faster Builds**: Up to 10x faster, especially for larger projects.
- **Unified toolchain**: Built-in import handling, vendor prefixing, and syntax transforms, with no additional tooling required. - **Unified Toolchain**: Built-in features like vendor prefixing, nesting support, and modern CSS transforms.
- **CSS-first configuration**: A reimagined developer experience where you customize and extend the framework directly in CSS instead of a JavaScript configuration file. - **CSS-First Configuration**: New `@theme` directive for easy customization without JavaScript.
- **Designed for the modern web**: Built on native cascade layers, wide-gamut colors, and including first-class support for modern CSS features like container queries, @starting-style, popovers, and more. - **Optimized Performance**: Smaller engine footprint and more efficient processing.
::note ::note
For a comprehensive overview of Tailwind CSS v4 beta features, read the [prerelease documentation](https://tailwindcss.com/docs/v4-beta). For a comprehensive overview of Tailwind CSS v4 alpha features, visit the [official announcement](https://tailwindcss.com/blog/tailwindcss-v4-alpha).
:: ::
### Tailwind Variants ### Tailwind Variants
@@ -71,7 +71,7 @@ You can now use Nuxt UI in any Vue project without Nuxt by adding the Vite and V
- **Developer Experience**: Complete TypeScript support with IntelliSense and auto-completion - **Developer Experience**: Complete TypeScript support with IntelliSense and auto-completion
::tip{to="/getting-started/installation/vue"} ::tip{to="/getting-started/installation/vue"}
Learn how to install and configure Nuxt UI in a Vue project in the **Vue installation guide**. Learn how to install and configure Nuxt UI in a Vue project in the [Vue installation guide](/getting-started/installation/vue).
:: ::
## Migration ## Migration
@@ -90,10 +90,6 @@ Key points to consider:
The transition to v3 involves significant changes, including new component structures, updated theming approaches, and revised TypeScript definitions. We recommend a careful, incremental upgrade process, starting with thorough testing in a development environment. The transition to v3 involves significant changes, including new component structures, updated theming approaches, and revised TypeScript definitions. We recommend a careful, incremental upgrade process, starting with thorough testing in a development environment.
:: ::
::accordion-item{label="Is Nuxt UI v3 compatible with standalone Vue projects?"}
Nuxt UI is now compatible with Vue! You can follow the [installation guide](/getting-started/installation/vue) to get started.
::
::accordion-item{label="What about Nuxt UI Pro?"} ::accordion-item{label="What about Nuxt UI Pro?"}
We've also rebuilt Nuxt UI Pro from scratch and released a `v3.0.0-alpha.x` package but it only contains the components to build this documentation yet. This will be a free update, so the license you buy now will be valid for v3. We're actively working to finish the rewrite of all Nuxt UI Pro components. We've also rebuilt Nuxt UI Pro from scratch and released a `v3.0.0-alpha.x` package but it only contains the components to build this documentation yet. This will be a free update, so the license you buy now will be valid for v3. We're actively working to finish the rewrite of all Nuxt UI Pro components.
:: ::
@@ -102,12 +98,16 @@ Key points to consider:
Nuxt UI v3 is currently designed to work exclusively with Tailwind CSS. While there's interest in UnoCSS support, implementing it would require significant changes to the theme structure due to differences in class naming conventions. As a result, we don't have plans to add UnoCSS support in v3. Nuxt UI v3 is currently designed to work exclusively with Tailwind CSS. While there's interest in UnoCSS support, implementing it would require significant changes to the theme structure due to differences in class naming conventions. As a result, we don't have plans to add UnoCSS support in v3.
:: ::
::accordion-item{label="Is Nuxt UI v3 compatible with standalone Vue projects?"}
We're planning to add Vue support in the near future. For now, Nuxt UI v3 is only available for Nuxt. Track progress on Vue compatibility [in this issue](https://github.com/nuxt/ui/issues/2129).
::
::accordion-item{label="How does Nuxt UI v3 handle accessibility?"} ::accordion-item{label="How does Nuxt UI v3 handle accessibility?"}
Nuxt UI v3 enhances accessibility through Radix Vue integration. This provides automatic ARIA attributes, keyboard navigation support, intelligent focus management, and screen reader announcements. While offering a strong foundation, proper implementation and testing in your specific use case remains crucial for full accessibility compliance. For more detailed information, refer to [Radix Vue's accessibility documentation](https://www.radix-vue.com/overview/accessibility.html). Nuxt UI v3 enhances accessibility through Radix Vue integration. This provides automatic ARIA attributes, keyboard navigation support, intelligent focus management, and screen reader announcements. While offering a strong foundation, proper implementation and testing in your specific use case remains crucial for full accessibility compliance. For more detailed information, refer to [Radix Vue's accessibility documentation](https://www.radix-vue.com/overview/accessibility.html).
:: ::
::accordion-item{label="What is the testing approach for Nuxt UI v3?"} ::accordion-item{label="What is the testing approach for Nuxt UI v3?"}
Nuxt UI v3 ensures reliability with 1000+ Vitest tests, covering core functionality and accessibility. This robust testing suite supports the library's stability and serves as a reference for developers. Nuxt UI v3 ensures reliability with 800+ Vitest tests, covering core functionality and accessibility. This robust testing suite supports the library's stability and serves as a reference for developers.
:: ::
::accordion-item{label="Is this version stable and suitable for production use?"} ::accordion-item{label="Is this version stable and suitable for production use?"}

View File

@@ -1 +0,0 @@
shadow: true

View File

@@ -1,13 +1,17 @@
--- ---
title: Installation title: Install in a Nuxt app
navigation.title: Nuxt
description: 'Learn how to install and configure Nuxt UI in your Nuxt application.' description: 'Learn how to install and configure Nuxt UI in your Nuxt application.'
navigation.framework: nuxt select:
items:
- label: Nuxt
icon: i-logos-nuxt-icon
to: /getting-started/installation/nuxt
- label: Vue
icon: i-logos-vue
to: /getting-started/installation/vue
--- ---
::callout{to="/getting-started/installation/vue" icon="i-logos-vue" class="hidden"}
Looking for the **Vue** version?
::
## Setup ## Setup
::steps{level="4"} ::steps{level="4"}

View File

@@ -1,13 +1,17 @@
--- ---
title: Installation navigation.title: Vue
title: Install in a Vue app
description: 'Learn how to install and configure Nuxt UI in your Vue application.' description: 'Learn how to install and configure Nuxt UI in your Vue application.'
navigation.framework: vue select:
items:
- label: Nuxt
icon: i-logos-nuxt-icon
to: /getting-started/installation/nuxt
- label: Vue
icon: i-logos-vue
to: /getting-started/installation/vue
--- ---
::callout{to="/getting-started/installation/nuxt" icon="i-logos-nuxt-icon" class="hidden"}
Looking for the **Nuxt** version?
::
## Setup ## Setup
::steps{level="4"} ::steps{level="4"}
@@ -152,6 +156,10 @@ export default defineConfig({
Use the `ui` option to provide configuration for Nuxt UI. Use the `ui` option to provide configuration for Nuxt UI.
::warning
In the rest of the docs, there are references to the `app.config.ts` file (which is a Nuxt feature). When using Nuxt UI in a project without Nuxt, this configuration is passed in this `ui` option instead.
::
```ts [vite.config.ts] ```ts [vite.config.ts]
import { defineConfig } from 'vite' import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue' import vue from '@vitejs/plugin-vue'

View File

@@ -5,7 +5,7 @@ description: 'Learn how to customize Nuxt UI components using Tailwind CSS v4, C
## Tailwind CSS ## Tailwind CSS
Nuxt UI v3 uses Tailwind CSS v4 beta, you can read the [prerelease documentation](https://tailwindcss.com/docs/v4-beta) for more information. Nuxt UI v3 uses Tailwind CSS v4 alpha which doesn't have a documentation yet, let's have a look on how to use it.
### `@theme` ### `@theme`
@@ -16,7 +16,7 @@ Tailwind CSS v4 takes a CSS-first configuration approach, you now customize your
@import "@nuxt/ui"; @import "@nuxt/ui";
@theme { @theme {
--font-sans: 'Public Sans', sans-serif; --font-family-sans: 'Public Sans', sans-serif;
--breakpoint-3xl: 1920px; --breakpoint-3xl: 1920px;
@@ -36,8 +36,8 @@ Tailwind CSS v4 takes a CSS-first configuration approach, you now customize your
The `@theme` directive tells Tailwind to make new utilities and variants available based on these variables. It's the equivalent of the `theme.extend` key in Tailwind CSS v3 `tailwind.config.ts` file. The `@theme` directive tells Tailwind to make new utilities and variants available based on these variables. It's the equivalent of the `theme.extend` key in Tailwind CSS v3 `tailwind.config.ts` file.
::note{to="https://tailwindcss.com/docs/v4-beta#css-first-configuration" target="_blank"} ::note
Learn more about Tailwind CSS v4 CSS-first configuration approach. You can learn more about this on [https://tailwindcss.com/blog/tailwindcss-v4-alpha](https://tailwindcss.com/blog/tailwindcss-v4-alpha#css-first-configuration).
:: ::
### `@source` ### `@source`
@@ -50,11 +50,11 @@ This can be useful when writing Tailwind classes in markdown files with [`@nuxt/
@import "tailwindcss"; @import "tailwindcss";
@import "@nuxt/ui"; @import "@nuxt/ui";
@source "../content"; @source "../content/**/*.md";
``` ```
::note{to="https://tailwindcss.com/docs/v4-beta#adding-content-sources"} ::note{to="https://github.com/tailwindlabs/tailwindcss/pull/14078"}
Learn how to add content sources in Tailwind CSS v4. You can learn more about the `@source` directive in this pull request.
:: ::
### `@plugin` ### `@plugin`
@@ -68,8 +68,8 @@ You can use the `@plugin` directive to import Tailwind CSS plugins.
@plugin "@tailwindcss/typography"; @plugin "@tailwindcss/typography";
``` ```
::note{to="https://tailwindcss.com/docs/v4-beta#using-plugins"} ::note{to="https://github.com/tailwindlabs/tailwindcss/pull/14264"}
Learn more about using plugins in Tailwind CSS v4. You can learn more about the `@plugin` directive in this pull request.
:: ::
## Design system ## Design system
@@ -78,14 +78,8 @@ Nuxt UI extends Tailwind CSS's theming capabilities, providing a flexible design
### Colors ### Colors
::framework-only
#nuxt
Nuxt UI leverages Nuxt [App Config](https://nuxt.com/docs/guide/directory-structure/app-config#app-config-file) to provide customizable color aliases based on [Tailwind CSS colors](https://tailwindcss.com/docs/customizing-colors#color-palette-reference): Nuxt UI leverages Nuxt [App Config](https://nuxt.com/docs/guide/directory-structure/app-config#app-config-file) to provide customizable color aliases based on [Tailwind CSS colors](https://tailwindcss.com/docs/customizing-colors#color-palette-reference):
#vue
Nuxt UI leverages Vite config to provide customizable color aliases based on [Tailwind CSS colors](https://tailwindcss.com/docs/customizing-colors#color-palette-reference):
::
| Color | Default | Description | | Color | Default | Description |
| --- | --- | --- | | --- | --- | --- |
| `primary`{color="primary"} | `green` | Main brand color, used as the default color for components. | | `primary`{color="primary"} | `green` | Main brand color, used as the default color for components. |
@@ -96,8 +90,6 @@ Nuxt UI leverages Vite config to provide customizable color aliases based on [Ta
| `error`{color="error"} | `red` | Used for form error validation states. | | `error`{color="error"} | `red` | Used for form error validation states. |
| `neutral` | `slate` | Neutral color for backgrounds, text, etc. | | `neutral` | `slate` | Neutral color for backgrounds, text, etc. |
::framework-only
#nuxt
You can configure these color aliases at runtime in your `app.config.ts` file under the `ui.colors` key, allowing for dynamic theme customization without requiring an application rebuild: You can configure these color aliases at runtime in your `app.config.ts` file under the `ui.colors` key, allowing for dynamic theme customization without requiring an application rebuild:
```ts [app.config.ts] ```ts [app.config.ts]
@@ -111,30 +103,6 @@ export default defineAppConfig({
}) })
``` ```
#vue
You can configure these color aliases at runtime in your `vite.config.ts` file under the `ui.colors` key:
```ts [vite.config.ts]
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import ui from '@nuxt/ui/vite'
export default defineConfig({
plugins: [
vue(),
ui({
ui: {
colors: {
primary: 'blue',
neutral: 'zinc'
}
}
})
]
})
```
::
::note ::note
Try the :prose-icon{name="i-lucide-swatch-book" class="text-[var(--ui-primary)]"} theme picker in the header above to change `primary` and `neutral` colors. Try the :prose-icon{name="i-lucide-swatch-book" class="text-[var(--ui-primary)]"} theme picker in the header above to change `primary` and `neutral` colors.
:: ::
@@ -150,10 +118,8 @@ slots:
--- ---
:: ::
::framework-only ::tip
#nuxt You can add you own dynamic color aliases in your `app.config.ts`, you just have to make sure to define them in the [`ui.theme.colors`](/getting-started/installation#themecolors) option in your `nuxt.config.ts` file.
:::tip
You can add you own dynamic color aliases in your `app.config.ts`, you just have to make sure to define them in the [`ui.theme.colors`](/getting-started/installation/nuxt#themecolors) option in your `nuxt.config.ts` file.
```ts [app.config.ts] ```ts [app.config.ts]
export default defineAppConfig({ export default defineAppConfig({
@@ -174,34 +140,7 @@ export default defineNuxtConfig({
} }
}) })
``` ```
:::
#vue
:::tip
You can add you own dynamic color aliases in your `vite.config.ts`, you just have to make sure to also define them in the [`theme.colors`](/getting-started/installation/vue#themecolors) option of the `ui` plugin.
```ts [vite.config.ts]
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import ui from '@nuxt/ui/vite'
export default defineConfig({
plugins: [
vue(),
ui({
ui: {
colors: {
tertiary: 'indigo'
}
},
theme: {
colors: ['primary', 'secondary', 'tertiary', 'info', 'success', 'warning', 'error']
}
})
]
})
```
:::
:: ::
::warning ::warning
@@ -551,19 +490,7 @@ props:
--- ---
:: ::
The `defaultVariants` property specifies the default values for each variant. It determines how a component looks and behaves when no prop is provided. The `defaultVariants` property specifies the default values for each variant. It determines how a component looks and behaves when no prop is provided. These default values can be customized in your [`app.config.ts`](#appconfigts) to adjust the standard appearance of components throughout your application.
::framework-only
#nuxt
:::tip
These default values can be customized in your [`app.config.ts`](#config) to adjust the standard appearance of components throughout your application.
:::
#vue
:::tip
These default values can be customized in your [`vite.config.ts`](#config) to adjust the standard appearance of components throughout your application.
:::
::
## Customize theme ## Customize theme
@@ -580,11 +507,9 @@ You can explore the theme for each component in two ways:
- Browse the source code directly in the GitHub repository at https://github.com/nuxt/ui/tree/v3/src/theme. - Browse the source code directly in the GitHub repository at https://github.com/nuxt/ui/tree/v3/src/theme.
:: ::
### Config ### `app.config.ts`
::framework-only You can override the theme of components inside your `app.config.ts` by using the exact same structure as the theme object.
#nuxt
You can override the theme of components globally inside your `app.config.ts` by using the exact same structure as the theme object.
Let's say you want to change the font weight of all your buttons, you can do it like this: Let's say you want to change the font weight of all your buttons, you can do it like this:
@@ -600,42 +525,13 @@ export default defineAppConfig({
}) })
``` ```
#vue
You can override the theme of components globally inside your `vite.config.ts` by using the exact same structure as the theme object.
Let's say you want to change the font weight of all your buttons, you can do it like this:
```ts [vite.config.ts]
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import ui from '@nuxt/ui/vite'
export default defineConfig({
plugins: [
vue(),
ui({
ui: {
button: {
slots: {
base: 'font-bold'
}
}
}
})
]
})
```
::
::note ::note
In this example, the `font-bold` class will override the default `font-medium` class on all buttons. In this example, the `font-bold` class will override the default `font-medium` class on all buttons.
:: ::
### Props ### `ui` prop
#### `ui` prop You can also override a component's **slots** using the `ui` prop. This has priority over the `app.config.ts` configuration and `variants` resolution.
You can also override a component's **slots** using the `ui` prop. This has priority over the global configuration and `variants` resolution.
::component-code{slug="button"} ::component-code{slug="button"}
--- ---
@@ -664,9 +560,9 @@ slots:
In this example, the `trailingIcon` slot is overwritten with `size-3` even though the `md` size variant would apply a `size-5` class to it. In this example, the `trailingIcon` slot is overwritten with `size-3` even though the `md` size variant would apply a `size-5` class to it.
:: ::
#### `class` prop ### `class` prop
The `class` prop allows you to override the classes of the `root` or `base` slot. This has priority over the global configuration and `variants` resolution. The `class` prop allows you to override the classes of the `root` or `base` slot. This has priority over the `app.config.ts` configuration and `variants` resolution.
::component-code{slug="button"} ::component-code{slug="button"}
--- ---

View File

@@ -1,7 +1,6 @@
--- ---
title: Icons title: Icons
description: 'Nuxt UI integrates with Nuxt Icon to access over 200,000+ icons from Iconify.' description: 'Nuxt UI integrates with Nuxt Icon to access over 200,000+ icons from Iconify.'
navigation.framework: nuxt
links: links:
- label: 'Iconify' - label: 'Iconify'
to: https://iconify.design/ to: https://iconify.design/
@@ -13,14 +12,14 @@ links:
icon: i-simple-icons-github icon: i-simple-icons-github
--- ---
::callout{to="/getting-started/icons/vue" icon="i-logos-vue" class="hidden"}
Looking for the **Vue** version?
::
## Usage ## Usage
Nuxt UI automatically registers the [`@nuxt/icon`](https://github.com/nuxt/icon) module for you, so there's no additional setup required. Nuxt UI automatically registers the [`@nuxt/icon`](https://github.com/nuxt/icon) module for you, so there's no additional setup required.
::note
You can use any name from the https://icones.js.org collection.
::
### Icon Component ### Icon Component
You can use the [Icon](/components/icon) component with a `name` prop to display an icon: You can use the [Icon](/components/icon) component with a `name` prop to display an icon:
@@ -33,10 +32,6 @@ props:
--- ---
:: ::
::note
You can use any name from the https://icones.js.org collection.
::
### Component Props ### Component Props
Some components also have an `icon` prop to display an icon, like the [Button](/components/button) for example: Some components also have an `icon` prop to display an icon, like the [Button](/components/button) for example:

View File

@@ -1 +0,0 @@
shadow: true

View File

@@ -1,55 +0,0 @@
---
title: Icons
description: 'Nuxt UI integrates with Iconify to access over 200,000+ icons.'
navigation.framework: vue
links:
- label: 'Iconify'
to: https://iconify.design/
target: _blank
icon: i-simple-icons-iconify
---
::callout{to="/getting-started/icons/nuxt" icon="i-logos-nuxt-icon" class="hidden"}
Looking for the **Nuxt** version?
::
## Usage
### Icon Component
You can use the [Icon](/components/icon) component with a `name` prop to display an icon:
::component-code{slug="icon"}
---
props:
name: 'i-lucide-lightbulb'
class: 'size-5'
---
::
::note
You can use any name from the https://icones.js.org collection.
::
### Component Props
Some components also have an `icon` prop to display an icon, like the [Button](/components/button) for example:
::component-code{slug="button"}
---
ignore:
- color
- variant
props:
icon: i-lucide-sun
variant: subtle
slots:
default: Button
---
::
## Theme
You can change the default icons used by Nuxt UI components in your `vite.config.ts`:
:icons-theme

View File

@@ -1,7 +1,6 @@
--- ---
title: Fonts title: Fonts
description: 'Nuxt UI integrates with Nuxt Fonts to provide plug-and-play font optimization.' description: 'Nuxt UI integrates with Nuxt Fonts to provide plug-and-play font optimization.'
navigation.framework: nuxt
links: links:
- label: 'nuxt/fonts' - label: 'nuxt/fonts'
to: https://github.com/nuxt/fonts to: https://github.com/nuxt/fonts
@@ -11,23 +10,19 @@ links:
## Usage ## Usage
Nuxt UI automatically registers the [`@nuxt/fonts`](https://github.com/nuxt/fonts) module for you, so there's no additional setup required. To use a font in your Nuxt UI application, you can simply declare it in your CSS. It will be automatically loaded and optimized for you. Nuxt UI automatically registers the [`@nuxt/fonts`](https://github.com/nuxt/fonts) module for you, so there's no additional setup required. To use a font in your Nuxt UI application, you can simply declare it in your CSS:
```css [main.css] ```css [main.css]
@import "tailwindcss"; @import "tailwindcss";
@import "@nuxt/ui"; @import "@nuxt/ui";
@theme { @theme {
--font-sans: 'Public Sans', sans-serif; --font-family-sans: 'Public Sans', sans-serif;
} }
``` ```
You can disable the `@nuxt/fonts` module with the `ui.fonts` option in your `nuxt.config.ts`: That's it! Nuxt Fonts will detect this and you should immediately see the web font loaded in your browser.
```ts [nuxt.config.ts] ::note{to="https://fonts.nuxt.com/advanced" target="_blank"}
export default defineNuxtConfig({ Read more about how `@nuxt/fonts` work behind the scenes to optimize your fonts.
ui: { ::
fonts: false
}
})
```

View File

@@ -0,0 +1,27 @@
---
title: Color Mode
description: 'Nuxt UI integrates with Nuxt Color Mode to allow for easy switching between light and dark themes.'
links:
- label: 'nuxtjs/color-mode'
to: https://github.com/nuxt-modules/color-mode
target: _blank
icon: i-simple-icons-github
---
## Usage
Nuxt UI automatically registers the [`@nuxtjs/color-mode`](https://github.com/nuxt-modules/color-mode) module for you, so there's no additional setup required.
You can disable dark mode by setting the `preference` to `light` instead of `system` in your `nuxt.config.ts`.
```ts [nuxt.config.ts]
export default defineNuxtConfig({
colorMode: {
preference: 'light'
}
})
```
::tip
If you're stuck in dark mode even after changing this setting, you might need to remove the `nuxt-color-mode` entry from your browser's local storage.
::

View File

@@ -1 +0,0 @@
shadow: true

View File

@@ -1,58 +0,0 @@
---
title: Color Mode
description: 'Nuxt UI integrates with Nuxt Color Mode to allow for easy switching between light and dark themes.'
navigation.framework: nuxt
links:
- label: 'nuxtjs/color-mode'
to: https://github.com/nuxt-modules/color-mode
target: _blank
icon: i-simple-icons-github
---
::callout{to="/getting-started/color-mode/vue" icon="i-logos-vue" class="hidden"}
Looking for the **Vue** version?
::
## Usage
Nuxt UI automatically registers the [`@nuxtjs/color-mode`](https://github.com/nuxt-modules/color-mode) module for you, so there's no additional setup required. You can simply use the `useColorMode` composable to switch between light and dark modes:
```vue [ColorModeButton.vue]
<script setup>
const colorMode = useColorMode()
const isDark = computed({
get() {
return colorMode.value === 'dark'
},
set() {
colorMode.preference = colorMode.value === 'dark' ? 'light' : 'dark'
}
})
</script>
<template>
<ClientOnly v-if="!colorMode?.forced">
<UButton
:icon="isDark ? 'i-lucide-moon' : 'i-lucide-sun'"
color="neutral"
variant="ghost"
@click="isDark = !isDark"
/>
<template #fallback>
<div class="size-8" />
</template>
</ClientOnly>
</template>
```
You can disable the `@nuxtjs/color-mode` module with the `ui.colorMode` option in your `nuxt.config.ts`:
```ts [nuxt.config.ts]
export default defineNuxtConfig({
ui: {
colorMode: false
}
})
```

View File

@@ -1,47 +0,0 @@
---
title: Color Mode
description: 'Nuxt UI integrates with VueUse to allow for easy switching between light and dark themes.'
navigation.framework: vue
---
::callout{to="/getting-started/color-mode/nuxt" icon="i-logos-nuxt-icon" class="hidden"}
Looking for the **Nuxt** version?
::
## Usage
Nuxt UI automatically registers the [useDark](https://vueuse.org/core/useDark) composable as a Vue plugin, so there's no additional setup required. You can simply use it to switch between light and dark modes:
```vue [ColorModeButton.vue]
<script setup>
import { useColorMode } from '@vueuse/core'
const mode = useColorMode()
</script>
<template>
<UButton
:icon="mode === 'dark' ? 'i-lucide-moon' : 'i-lucide-sun'"
color="neutral"
variant="ghost"
@click="mode = mode === 'dark' ? 'light' : 'dark'"
/>
</template>
```
You can disable this plugin with the `colorMode` option in your `vite.config.ts`:
```ts [vite.config.ts]
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import ui from '@nuxt/ui/vite'
export default defineConfig({
plugins: [
vue(),
ui({
colorMode: false
})
]
})
```

View File

@@ -1,2 +0,0 @@
badge: New
shadow: true

View File

@@ -1,20 +1,22 @@
--- ---
title: Internationalization (i18n) navigation.title: Nuxt
description: 'Learn how to internationalize your Nuxt app with multi-directional support (LTR/RTL).' title: Internationalization (i18n) in a Nuxt app
navigation.framework: nuxt description: 'Learn how to internationalize your Nuxt app and support multi-directional support (LTR/RTL).'
select:
items:
- label: Nuxt
icon: i-logos-nuxt-icon
to: /getting-started/i18n/nuxt
- label: Vue
icon: i-logos-vue
to: /getting-started/i18n/vue
--- ---
::callout{to="/getting-started/i18n/vue" icon="i-logos-vue" class="hidden"}
Looking for the **Vue** version?
::
## Usage
::note{to="/components/app"} ::note{to="/components/app"}
Nuxt UI provides an **App** component that wraps your app to provide global configurations. Nuxt UI provides an [App](/components/app) component that wraps your app to provide global configurations.
:: ::
### Locale ## Locale
Use the `locale` prop with the locale you want to use from `@nuxt/ui/locale`: Use the `locale` prop with the locale you want to use from `@nuxt/ui/locale`:
@@ -36,13 +38,8 @@ You also have the option to add your own locale using `defineLocale`:
```vue [app.vue] ```vue [app.vue]
<script setup lang="ts"> <script setup lang="ts">
const locale = defineLocale({ const locale = defineLocale('My custom locale', 'en', {
name: 'My custom locale', // implement pairs
code: 'en',
dir: 'ltr',
messages: {
// implement pairs
}
}) })
</script> </script>
@@ -54,7 +51,7 @@ const locale = defineLocale({
``` ```
::tip ::tip
Look at the `code` parameter, there you need to pass the iso code of the language. Example: Look at the second parameter, there you need to pass the iso code of the language. Example:
* `hi` Hindi (language) * `hi` Hindi (language)
* `de-AT`: German (language) as used in Austria (region) * `de-AT`: German (language) as used in Austria (region)
:: ::
@@ -128,36 +125,65 @@ const { locale } = useI18n()
:: ::
### Dynamic direction ### Supported languages
Each locale has a `dir` property which will be used by the `App` component to set the directionality of all components. :supported-languages
In a multilingual application, you might want to set the `lang` and `dir` attributes on the `<html>` element dynamically based on the user's locale, which you can do with the [useHead](https://nuxt.com/docs/api/composables/use-head) composable: ## Direction
Use the `dir` prop with `ltr` or `rtl` to set the global reading direction of your app:
```vue [app.vue] ```vue [app.vue]
<script setup lang="ts">
import * as locales from '@nuxt/ui/locale'
const { locale } = useI18n()
const lang = computed(() => locales[locale.value].code)
const dir = computed(() => locales[locale.value].dir)
useHead({
htmlAttrs: {
lang,
dir
}
})
</script>
<template> <template>
<UApp :locale="locales[locale]"> <UApp dir="rtl">
<NuxtPage /> <NuxtPage />
</UApp> </UApp>
</template> </template>
``` ```
## Supported languages ### Dynamic direction
:supported-languages To dynamically change the global reading direction of your app, you can use VueUse's [useTextDirection](https://vueuse.org/core/useTextDirection/) composable to detect and switch between LTR and RTL text directions.
::steps{level="4"}
#### Install the `@vueuse/core` package
::code-group{sync="pm"}
```bash [pnpm]
pnpm add @vueuse/core
```
```bash [yarn]
yarn add @vueuse/core
```
```bash [npm]
npm install @vueuse/core
```
```bash [bun]
bun add @vueuse/core
```
::
#### Set the `dir` prop using `useTextDirection`
```vue [app.vue]
<script setup lang="ts">
import { useTextDirection } from '@vueuse/core'
const textDirection = useTextDirection({ initialValue: 'ltr' })
const dir = computed(() => textDirection.value === 'rtl' ? 'rtl' : 'ltr')
</script>
<template>
<UApp :dir="dir">
<NuxtPage />
</UApp>
</template>
```
::

View File

@@ -1,20 +1,22 @@
--- ---
title: Internationalization (i18n) navigation.title: Vue
description: 'Learn how to internationalize your Vue app with multi-directional support (LTR/RTL).' title: Internationalization (i18n) in a Vue app
navigation.framework: vue description: 'Learn how to internationalize your Vue app and support multi-directional support (LTR/RTL).'
select:
items:
- label: Nuxt
icon: i-logos-nuxt-icon
to: /getting-started/i18n/nuxt
- label: Vue
icon: i-logos-vue
to: /getting-started/i18n/vue
--- ---
::callout{to="/getting-started/i18n/nuxt" icon="i-logos-nuxt-icon" class="hidden"}
Looking for the **Nuxt** version?
::
## Usage
::note{to="/components/app"} ::note{to="/components/app"}
Nuxt UI provides an **App** component that wraps your app to provide global configurations. Nuxt UI provides an [App](/components/app) component that wraps your app to provide global configurations.
:: ::
### Locale ## Locale
Use the `locale` prop with the locale you want to use from `@nuxt/ui/locale`: Use the `locale` prop with the locale you want to use from `@nuxt/ui/locale`:
@@ -38,13 +40,8 @@ You also have the option to add your locale using `defineLocale`:
<script setup lang="ts"> <script setup lang="ts">
import { defineLocale } from '@nuxt/ui/runtime/composables/defineLocale' import { defineLocale } from '@nuxt/ui/runtime/composables/defineLocale'
const locale = defineLocale({ const locale = defineLocale('My custom locale', 'en', {
name: 'My custom locale', // implement pairs
code: 'en',
dir: 'ltr',
messages: {
// implement pairs
}
}) })
</script> </script>
@@ -56,7 +53,7 @@ const locale = defineLocale({
``` ```
::tip ::tip
Look at the `code` parameter, there you need to pass the iso code of the language. Example: Look at the second parameter, there you need to pass the iso code of the language. Example:
* `hi` Hindi (language) * `hi` Hindi (language)
* `de-AT`: German (language) as used in Austria (region) * `de-AT`: German (language) as used in Austria (region)
:: ::
@@ -138,39 +135,64 @@ const { locale } = useI18n()
:: ::
### Dynamic direction ## Supported languages
Each locale has a `dir` property which will be used by the `App` component to set the directionality of all components. :supported-languages
In a multilingual application, you might want to set the `lang` and `dir` attributes on the `<html>` element dynamically based on the user's locale, which you can do with the [useHead](https://unhead.unjs.io/usage/composables/use-head) composable: ## Direction
Use the `dir` prop with `ltr` or `rtl` to set the global reading direction of your app:
```vue [App.vue] ```vue [App.vue]
<script setup lang="ts">
import { computed } from 'vue'
import { useI18n } from 'vue-i18n'
import { useHead } from '@unhead/vue'
import * as locales from '@nuxt/ui/locale'
const { locale } = useI18n()
const lang = computed(() => locales[locale.value].code)
const dir = computed(() => locales[locale.value].dir)
useHead({
htmlAttrs: {
lang,
dir
}
})
</script>
<template> <template>
<UApp :locale="locales[locale]"> <UApp dir="rtl">
<RouterView /> <NuxtPage />
</UApp> </UApp>
</template> </template>
``` ```
## Supported languages ### Dynamic direction
:supported-languages To dynamically change the global reading direction of your app, you can use VueUse's [useTextDirection](https://vueuse.org/core/useTextDirection/) composable to detect and switch between LTR and RTL text directions.
::steps{level="4"}
#### Install the `@vueuse/core` package
::code-group{sync="pm"}
```bash [pnpm]
pnpm add @vueuse/core
```
```bash [yarn]
yarn add @vueuse/core
```
```bash [npm]
npm install @vueuse/core
```
```bash [bun]
bun add @vueuse/core
```
::
#### Set the `dir` prop using `useTextDirection`
```vue [App.vue]
<script setup lang="ts">
import { computed } from 'vue'
import { useTextDirection } from '@vueuse/core'
const textDirection = useTextDirection()
const dir = computed(() => textDirection.value === 'rtl' ? 'rtl' : 'ltr')
</script>
<template>
<UApp :dir="dir">
<RouterView />
</UApp>
</template>
```

View File

@@ -27,16 +27,12 @@ Use it as at the root of your app:
</template> </template>
``` ```
::framework-only ::tip{to="/getting-started/i18n/nuxt#locale"}
#nuxt
:::tip{to="/getting-started/i18n/nuxt#locale"}
Learn how to use the `locale` prop to change the locale of your app. Learn how to use the `locale` prop to change the locale of your app.
::: ::
#vue ::tip{to="/getting-started/i18n/nuxt#direction"}
:::tip{to="/getting-started/i18n/vue#locale"} Learn how to use the `dir` prop to change the global reading direction of your app.
Learn how to use the `locale` prop to change the locale of your app.
:::
:: ::
## API ## API

View File

@@ -168,16 +168,8 @@ props:
--- ---
:: ::
::framework-only ::tip{to="/getting-started/icons#theme"}
#nuxt
:::tip{to="/getting-started/icons/nuxt#theme"}
You can customize this icon globally in your `app.config.ts` under `ui.icons.chevronDown` key. You can customize this icon globally in your `app.config.ts` under `ui.icons.chevronDown` key.
:::
#vue
:::tip{to="/getting-started/icons/vue#theme"}
You can customize this icon globally in your `vite.config.ts` under `ui.icons.chevronDown` key.
:::
:: ::
## Examples ## Examples

View File

@@ -178,16 +178,8 @@ props:
--- ---
:: ::
::framework-only ::tip{to="/getting-started/icons#theme"}
#nuxt
:::tip{to="/getting-started/icons/nuxt#theme"}
You can customize this icon globally in your `app.config.ts` under `ui.icons.close` key. You can customize this icon globally in your `app.config.ts` under `ui.icons.close` key.
:::
#vue
:::tip{to="/getting-started/icons/vue#theme"}
You can customize this icon globally in your `vite.config.ts` under `ui.icons.close` key.
:::
:: ::
### Actions ### Actions

View File

@@ -67,16 +67,8 @@ props:
--- ---
:: ::
::framework-only ::tip{to="/getting-started/icons#theme"}
#nuxt
:::tip{to="/getting-started/icons/nuxt#theme"}
You can customize this icon globally in your `app.config.ts` under `ui.icons.chevronRight` key. You can customize this icon globally in your `app.config.ts` under `ui.icons.chevronRight` key.
:::
#vue
:::tip{to="/getting-started/icons/vue#theme"}
You can customize this icon globally in your `vite.config.ts` under `ui.icons.chevronRight` key.
:::
:: ::
## Examples ## Examples

View File

@@ -197,16 +197,8 @@ slots:
Button Button
:: ::
::framework-only ::tip{to="/getting-started/icons#theme"}
#nuxt
:::tip{to="/getting-started/icons/nuxt#theme"}
You can customize this icon globally in your `app.config.ts` under `ui.icons.loading` key. You can customize this icon globally in your `app.config.ts` under `ui.icons.loading` key.
:::
#vue
:::tip{to="/getting-started/icons/vue#theme"}
You can customize this icon globally in your `vite.config.ts` under `ui.icons.loading` key.
:::
:: ::
### Disabled ### Disabled

View File

@@ -1,248 +0,0 @@
---
title: Calendar
description: A calendar component for selecting single dates, multiple dates or date ranges.
links:
- label: Calendar
icon: i-custom-radix-vue
to: https://www.radix-vue.com/components/calendar.html
- label: GitHub
icon: i-simple-icons-github
to: https://github.com/nuxt/ui/tree/v3/src/runtime/components/Calendar.vue
navigation.badge: New
---
::note
This component relies on the [@internationalized/date](https://react-spectrum.adobe.com/internationalized/date/index.html) package which provides objects and functions for representing and manipulating dates and times in a locale-aware manner.
::
## Usage
Use the `v-model` directive to control the selected date.
::component-code
---
cast:
modelValue: DateValue
ignore:
- modelValue
external:
- modelValue
props:
modelValue: [2022, 2, 3]
---
::
Use the `default-value` prop to set the initial value when you do not need to control its state.
::component-code
---
cast:
defaultValue: DateValue
ignore:
- defaultValue
external:
- defaultValue
props:
defaultValue: [2022, 2, 6]
---
::
### Multiple
Use the `multiple` prop to allow multiple selections.
::component-code
---
prettier: true
cast:
modelValue: DateValue[]
ignore:
- multiple
- modelValue
external:
- modelValue
props:
multiple: true
modelValue: [[2022, 2, 4], [2022, 2, 6], [2022, 2, 8]]
---
::
### Range
Use the `range` prop to select a range of dates.
::component-code
---
prettier: true
cast:
modelValue: DateRange
ignore:
- range
- modelValue.start
- modelValue.end
external:
- modelValue
props:
range: true
modelValue:
start: [2022, 2, 3]
end: [2022, 2, 20]
---
::
### Color
Use the `color` prop to change the color of the calendar.
::component-code
---
props:
color: neutral
---
::
### Size
Use the `size` prop to change the size of the calendar.
::component-code
---
props:
size: xl
---
::
### Disabled
Use the `disabled` prop to disable the calendar.
::component-code
---
props:
disabled: true
---
::
### Number Of Months
Use the `numberOfMonths` prop to change the number of months in the calendar.
::component-code
---
props:
numberOfMonths: 3
---
::
### Month Controls
Use the `month-controls` prop to show the month controls. Defaults to `true`.
::component-code
---
props:
monthControls: false
---
::
### Year Controls
Use the `year-controls` prop to show the year controls. Defaults to `true`.
::component-code
---
props:
yearControls: false
---
::
### Fixed Weeks
Use the `fixed-weeks` prop to display the calendar with fixed weeks.
::component-code
---
props:
fixedWeeks: false
---
::
## Examples
### With chip events
Use the [Chip](/components/chip) component to add events to specific days.
::component-example
---
name: 'calendar-events-example'
---
::
### With disabled dates
Use the `is-date-disabled` prop with a function to mark specific dates as disabled.
::component-example
---
name: 'calendar-disabled-dates-example'
---
::
### With unavailable dates
Use the `is-date-unavailable` prop with a function to mark specific dates as unavailable.
::component-example
---
name: 'calendar-unavailable-dates-example'
---
::
### With min/max dates
Use the `min-value` and `max-value` props to limit the dates.
::component-example
---
name: 'calendar-min-max-dates-example'
---
::
### As a DatePicker
Use a [Button](/components/button) and a [Popover](/components/popover) component to create a date picker.
::component-example
---
name: 'calendar-date-picker-example'
---
::
### As a DateRangePicker
Use a [Button](/components/button) and a [Popover](/components/popover) component to create a date range picker.
::component-example
---
name: 'calendar-date-range-picker-example'
---
::
## API
### Props
:component-props
### Slots
:component-slots
### Emits
:component-emits
## Theme
:component-theme

View File

@@ -67,7 +67,7 @@ class: 'p-8'
### Prev / Next ### Prev / Next
Use the `prev` and `next` props to customize the prev and next buttons with any [Button](/components/button) props. Use the `prev` and `next` props to customize the prev and next buttons.
::component-example ::component-example
--- ---
@@ -76,7 +76,7 @@ class: 'p-8'
--- ---
:: ::
### Prev / Next Icons ### Prev Icon / Next Icon
Use the `prev-icon` and `next-icon` props to customize the buttons [Icon](/components/icon). Defaults to `i-lucide-arrow-left` / `i-lucide-arrow-right`. Use the `prev-icon` and `next-icon` props to customize the buttons [Icon](/components/icon). Defaults to `i-lucide-arrow-left` / `i-lucide-arrow-right`.
@@ -94,16 +94,8 @@ options:
--- ---
:: ::
::framework-only ::tip{to="/getting-started/icons#theme"}
#nuxt
:::tip{to="/getting-started/icons/nuxt#theme"}
You can customize these icons globally in your `app.config.ts` under `ui.icons.arrowLeft` / `ui.icons.arrowRight` key. You can customize these icons globally in your `app.config.ts` under `ui.icons.arrowLeft` / `ui.icons.arrowRight` key.
:::
#vue
:::tip{to="/getting-started/icons/vue#theme"}
You can customize these icons globally in your `vite.config.ts` under `ui.icons.arrowLeft` / `ui.icons.arrowRight` key.
:::
:: ::
### Dots ### Dots

View File

@@ -58,16 +58,8 @@ props:
--- ---
:: ::
::framework-only ::tip{to="/getting-started/icons#theme"}
#nuxt
:::tip{to="/getting-started/icons/nuxt#theme"}
You can customize this icon globally in your `app.config.ts` under `ui.icons.minus` key. You can customize this icon globally in your `app.config.ts` under `ui.icons.minus` key.
:::
#vue
:::tip{to="/getting-started/icons/vue#theme"}
You can customize this icon globally in your `vite.config.ts` under `ui.icons.minus` key.
:::
:: ::
### Label ### Label
@@ -123,16 +115,8 @@ props:
--- ---
:: ::
::framework-only ::tip{to="/getting-started/icons#theme"}
#nuxt
:::tip{to="/getting-started/icons/nuxt#theme"}
You can customize this icon globally in your `app.config.ts` under `ui.icons.check` key. You can customize this icon globally in your `app.config.ts` under `ui.icons.check` key.
:::
#vue
:::tip{to="/getting-started/icons/vue#theme"}
You can customize this icon globally in your `vite.config.ts` under `ui.icons.check` key.
:::
:: ::
### Color ### Color

View File

@@ -42,7 +42,6 @@ Each group takes some `items` as an array of objects with the following properti
- `avatar?: AvatarProps`{lang="ts-type"} - `avatar?: AvatarProps`{lang="ts-type"}
- `chip?: ChipProps`{lang="ts-type"} - `chip?: ChipProps`{lang="ts-type"}
- `kbds?: string[] | KbdProps[]`{lang="ts-type"} - `kbds?: string[] | KbdProps[]`{lang="ts-type"}
- `active?: boolean`{lang="ts-type"}
- `loading?: boolean`{lang="ts-type"} - `loading?: boolean`{lang="ts-type"}
- `disabled?: boolean`{lang="ts-type"} - `disabled?: boolean`{lang="ts-type"}
- [`slot?: string`{lang="ts-type"}](#with-custom-slot) - [`slot?: string`{lang="ts-type"}](#with-custom-slot)
@@ -216,16 +215,8 @@ props:
--- ---
:: ::
::framework-only ::tip{to="/getting-started/icons#theme"}
#nuxt
:::tip{to="/getting-started/icons/nuxt#theme"}
You can customize this icon globally in your `app.config.ts` under `ui.icons.search` key. You can customize this icon globally in your `app.config.ts` under `ui.icons.search` key.
:::
#vue
:::tip{to="/getting-started/icons/vue#theme"}
You can customize this icon globally in your `vite.config.ts` under `ui.icons.search` key.
:::
:: ::
### Loading ### Loading
@@ -285,16 +276,8 @@ props:
--- ---
:: ::
::framework-only ::tip{to="/getting-started/icons#theme"}
#nuxt
:::tip{to="/getting-started/icons/nuxt#theme"}
You can customize this icon globally in your `app.config.ts` under `ui.icons.loading` key. You can customize this icon globally in your `app.config.ts` under `ui.icons.loading` key.
:::
#vue
:::tip{to="/getting-started/icons/vue#theme"}
You can customize this icon globally in your `vite.config.ts` under `ui.icons.loading` key.
:::
:: ::
### Disabled ### Disabled
@@ -420,16 +403,8 @@ props:
--- ---
:: ::
::framework-only ::tip{to="/getting-started/icons#theme"}
#nuxt
:::tip{to="/getting-started/icons/nuxt#theme"}
You can customize this icon globally in your `app.config.ts` under `ui.icons.close` key. You can customize this icon globally in your `app.config.ts` under `ui.icons.close` key.
:::
#vue
:::tip{to="/getting-started/icons/vue#theme"}
You can customize this icon globally in your `vite.config.ts` under `ui.icons.close` key.
:::
:: ::
## Examples ## Examples

View File

@@ -40,7 +40,7 @@ prettier: true
collapse: true collapse: true
ignore: ignore:
- items - items
- ui.content - class
external: external:
- items - items
props: props:
@@ -90,8 +90,7 @@ props:
- option - option
- meta - meta
- j - j
ui: class: 'w-48'
content: 'w-48'
slots: slots:
default: | default: |
@@ -120,7 +119,7 @@ Use the `size` prop to change the size of the ContextMenu.
prettier: true prettier: true
ignore: ignore:
- items - items
- ui.content - class
external: external:
- items - items
props: props:
@@ -132,8 +131,7 @@ props:
icon: i-lucide-sun icon: i-lucide-sun
- label: Dark - label: Dark
icon: i-lucide-moon icon: i-lucide-moon
ui: class: 'w-48'
content: 'w-48'
slots: slots:
default: | default: |
@@ -154,7 +152,7 @@ Use the `disabled` prop to disable the ContextMenu.
prettier: true prettier: true
ignore: ignore:
- items - items
- ui.content - class
external: external:
- items - items
props: props:
@@ -166,8 +164,7 @@ props:
icon: i-lucide-sun icon: i-lucide-sun
- label: Dark - label: Dark
icon: i-lucide-moon icon: i-lucide-moon
ui: class: 'w-48'
content: 'w-48'
slots: slots:
default: | default: |

View File

@@ -40,7 +40,7 @@ prettier: true
collapse: true collapse: true
ignore: ignore:
- items - items
- ui.content - class
external: external:
- items - items
props: props:
@@ -91,8 +91,7 @@ props:
- shift - shift
- meta - meta
- q - q
ui: class: 'w-48'
content: 'w-48'
slots: slots:
default: | default: |
@@ -119,7 +118,7 @@ Use the `content` prop to control how the DropdownMenu content is rendered, like
prettier: true prettier: true
ignore: ignore:
- items - items
- ui.content - class
external: external:
- items - items
items: items:
@@ -144,8 +143,7 @@ props:
align: start align: start
side: bottom side: bottom
sideOffset: 8 sideOffset: 8
ui: class: 'w-48'
content: 'w-48'
slots: slots:
default: | default: |
@@ -165,7 +163,7 @@ prettier: true
ignore: ignore:
- arrow - arrow
- items - items
- ui.content - class
external: external:
- items - items
props: props:
@@ -177,8 +175,7 @@ props:
icon: i-lucide-credit-card icon: i-lucide-credit-card
- label: Settings - label: Settings
icon: i-lucide-cog icon: i-lucide-cog
ui: class: 'w-48'
content: 'w-48'
slots: slots:
default: | default: |
@@ -197,8 +194,8 @@ Use the `size` prop to control the size of the DropdownMenu.
prettier: true prettier: true
ignore: ignore:
- items - items
- class
- content.align - content.align
- ui.content
external: external:
- items - items
props: props:
@@ -212,8 +209,7 @@ props:
icon: i-lucide-cog icon: i-lucide-cog
content: content:
align: start align: start
ui: class: 'w-48'
content: 'w-48'
slots: slots:
default: | default: |
@@ -240,7 +236,7 @@ Use the `disabled` prop to disable the DropdownMenu.
prettier: true prettier: true
ignore: ignore:
- items - items
- ui.content - class
external: external:
- items - items
props: props:
@@ -252,8 +248,7 @@ props:
icon: i-lucide-credit-card icon: i-lucide-credit-card
- label: Settings - label: Settings
icon: i-lucide-cog icon: i-lucide-cog
ui: class: 'w-48'
content: 'w-48'
slots: slots:
default: | default: |

View File

@@ -1,15 +1,14 @@
--- ---
description: A component to display any icon from Iconify. description: A wrapper around Nuxt Icon component to display icons.
links: links:
- label: Icônes - label: Nuxt Icon
to: https://icones.js.org/ icon: i-simple-icons-github
target: _blank to: https://github.com/nuxt/icon
icon: i-custom-icones-js
--- ---
## Usage ## Usage
Use the `name` prop to display an icon: You can use any name from the https://icones.js.org collection:
::component-code ::component-code
--- ---
@@ -19,15 +18,6 @@ props:
--- ---
:: ::
::framework-only ::tip
#nuxt It's highly recommended to install the icons collections you need, read more about this in [Icons](/getting-started/icons#collections).
:::caution{to="/getting-started/icons/nuxt#collections"}
It's highly recommended to install the icons collections you need, read more about this.
:::
:: ::
## API
### Props
:component-props

View File

@@ -189,16 +189,8 @@ props:
--- ---
:: ::
::framework-only ::tip{to="/getting-started/icons#theme"}
#nuxt
:::tip{to="/getting-started/icons/nuxt#theme"}
You can customize this icon globally in your `app.config.ts` under `ui.icons.close` key. You can customize this icon globally in your `app.config.ts` under `ui.icons.close` key.
:::
#vue
:::tip{to="/getting-started/icons/vue#theme"}
You can customize this icon globally in your `vite.config.ts` under `ui.icons.close` key.
:::
:: ::
### Placeholder ### Placeholder
@@ -222,42 +214,6 @@ props:
--- ---
:: ::
### Create Item
Use the `create-item` prop to allow user input.
::component-code
---
prettier: true
ignore:
- modelValue
- items
external:
- items
- modelValue
items:
createItem:
- true
- 'always'
props:
modelValue: 'Backlog'
items:
- Backlog
- Todo
- In Progress
- Done
createItem: true
---
::
::note
The create option shows when no match is found by default. Set it to `always` to show it even when similar values exist.
::
::tip{to="#emits"}
Use the `@create` event to handle the creation of the item. You will receive the event and the item as arguments.
::
### Content ### Content
Use the `content` prop to control how the InputMenu content is rendered, like its `align` or `side` for example. Use the `content` prop to control how the InputMenu content is rendered, like its `align` or `side` for example.
@@ -449,16 +405,8 @@ props:
--- ---
:: ::
::framework-only ::tip{to="/getting-started/icons#theme"}
#nuxt
:::tip{to="/getting-started/icons/nuxt#theme"}
You can customize this icon globally in your `app.config.ts` under `ui.icons.chevronDown` key. You can customize this icon globally in your `app.config.ts` under `ui.icons.chevronDown` key.
:::
#vue
:::tip{to="/getting-started/icons/vue#theme"}
You can customize this icon globally in your `vite.config.ts` under `ui.icons.chevronDown` key.
:::
:: ::
### Selected Icon ### Selected Icon
@@ -486,16 +434,8 @@ props:
--- ---
:: ::
::framework-only ::tip{to="/getting-started/icons#theme"}
#nuxt
:::tip{to="/getting-started/icons/nuxt#theme"}
You can customize this icon globally in your `app.config.ts` under `ui.icons.check` key. You can customize this icon globally in your `app.config.ts` under `ui.icons.check` key.
:::
#vue
:::tip{to="/getting-started/icons/vue#theme"}
You can customize this icon globally in your `vite.config.ts` under `ui.icons.check` key.
:::
:: ::
### Avatar ### Avatar
@@ -574,16 +514,8 @@ props:
--- ---
:: ::
::framework-only ::tip{to="/getting-started/icons#theme"}
#nuxt
:::tip{to="/getting-started/icons/nuxt#theme"}
You can customize this icon globally in your `app.config.ts` under `ui.icons.loading` key. You can customize this icon globally in your `app.config.ts` under `ui.icons.loading` key.
:::
#vue
:::tip{to="/getting-started/icons/vue#theme"}
You can customize this icon globally in your `vite.config.ts` under `ui.icons.loading` key.
:::
:: ::
### Disabled ### Disabled
@@ -771,7 +703,7 @@ name: 'input-menu-filter-fields-example'
--- ---
:: ::
### As a CountryPicker ### As a country picker
This example demonstrates using the InputMenu as a country picker with lazy loading - countries are only fetched when the menu is opened. This example demonstrates using the InputMenu as a country picker with lazy loading - countries are only fetched when the menu is opened.

View File

@@ -1,295 +0,0 @@
---
title: InputNumber
description: Input numerical values with a customizable range.
links:
- label: Number Field
icon: i-custom-radix-vue
to: https://www.radix-vue.com/components/number-field
- label: GitHub
icon: i-simple-icons-github
to: https://github.com/nuxt/ui/tree/v3/src/runtime/components/InputNumber.vue
navigation.badge: New
---
::note
This component relies on the [@internationalized/number](https://react-spectrum.adobe.com/internationalized/number/index.html) package which provides utilities for formatting and parsing numbers across locales and numbering systems.
::
## Usage
Use the `v-model` directive to control the value of the InputNumber.
::component-code
---
ignore:
- modelValue
external:
- modelValue
props:
modelValue: 5
---
::
Use the `default-value` prop to set the initial value when you do not need to control its state.
::component-code
---
ignore:
- defaultValue
props:
defaultValue: 5
---
::
### Min / Max
Use the `min` and `max` props to set the minimum and maximum values of the InputNumber.
::component-code
---
ignore:
- modelValue
external:
- modelValue
props:
modelValue: 5
min: 0
max: 10
---
::
### Step
Use the `step` prop to set the step value of the InputNumber.
::component-code
---
ignore:
- modelValue
external:
- modelValue
props:
modelValue: 5
step: 2
---
::
### Orientation
Use the `orientation` prop to change the orientation of the InputNumber.
::component-code
---
ignore:
- modelValue
external:
- modelValue
props:
modelValue: 5
orientation: vertical
---
::
### Placeholder
Use the `placeholder` prop to set a placeholder text.
::component-code
---
props:
placeholder: 'Enter a number'
---
::
### Color
Use the `color` prop to change the ring color when the InputNumber is focused.
::component-code
---
ignore:
- modelValue
external:
- modelValue
props:
modelValue: 5
color: neutral
highlight: true
---
::
### Variant
Use the `variant` prop to change the variant of the InputNumber.
::component-code
---
ignore:
- modelValue
external:
- modelValue
props:
modelValue: 5
variant: subtle
color: neutral
highlight: false
---
::
### Size
Use the `size` prop to change the size of the InputNumber.
::component-code
---
ignore:
- modelValue
external:
- modelValue
props:
modelValue: 5
size: xl
---
::
### Disabled
Use the `disabled` prop to disable the InputNumber.
::component-code
---
ignore:
- modelValue
external:
- modelValue
props:
modelValue: 5
disabled: true
---
::
### Increment / Decrement
Use the `increment` and `decrement` props to customize the increment and decrement buttons with any [Button](/components/button) props. Defaults to `{ variant: 'link' }`{lang="ts-type"}.
::component-code
---
prettier: true
ignore:
- modelValue
- increment.size
- increment.color
- increment.variant
- decrement.size
- decrement.color
- decrement.variant
external:
- modelValue
props:
modelValue: 5
increment:
color: neutral
variant: solid
size: xs
decrement:
color: neutral
variant: solid
size: xs
---
::
### Increment / Decrement Icons
Use the `increment-icon` and `decrement-icon` props to customize the buttons [Icon](/components/icon). Defaults to `i-lucide-plus` / `i-lucide-minus`.
::component-code
---
prettier: true
ignore:
- modelValue
external:
- modelValue
props:
modelValue: 5
incrementIcon: 'i-lucide-arrow-right'
decrementIcon: 'i-lucide-arrow-left'
---
::
## Examples
### With decimal format
Use the `format-options` prop to customize the format of the value.
::component-example
---
name: 'input-number-decimal-example'
---
::
### With percentage format
Use the `format-options` prop with `style: 'percent'` to customize the format of the value.
::component-example
---
name: 'input-number-percentage-example'
---
::
### With currency format
Use the `format-options` prop with `style: 'currency'` to customize the format of the value.
::component-example
---
name: 'input-number-currency-example'
---
::
### Within a FormField
You can use the InputNumber within a [FormField](/components/form-field) component to display a label, help text, required indicator, etc.
::component-example
---
name: 'input-number-form-field-example'
---
::
### With slots
Use the `#increment` and `#decrement` slots to customize the buttons.
::component-example
---
name: 'input-number-slots-example'
---
::
## API
### Props
:component-props
### Slots
:component-slots
### Emits
:component-emits
### Expose
When accessing the component via a template ref, you can use the following:
| Name | Type |
|----------------------------|-------------------------------------------------|
| `inputRef`{lang="ts-type"} | `Ref<HTMLInputElement \| null>`{lang="ts-type"} |
## Theme
:component-theme

View File

@@ -25,15 +25,15 @@ props:
Use the `type` prop to change the input type. Defaults to `text`. Use the `type` prop to change the input type. Defaults to `text`.
Some types have been implemented in their own components such as [Checkbox](/components/checkbox), [Radio](/components/radio-group), [InputNumber](/components/input-number) etc. and others have been styled like `file` for example. Some types have been implemented in their own components such as [Checkbox](/components/checkbox), [Radio](/components/radio-group), etc. and others have been styled like `file` for example.
::component-code ::component-code
--- ---
items: items:
type: type:
- text - text
- number
- password - password
- number
- search - search
- file - file
props: props:
@@ -184,16 +184,8 @@ props:
--- ---
:: ::
::framework-only ::tip{to="/getting-started/icons#theme"}
#nuxt
:::tip{to="/getting-started/icons/nuxt#theme"}
You can customize this icon globally in your `app.config.ts` under `ui.icons.loading` key. You can customize this icon globally in your `app.config.ts` under `ui.icons.loading` key.
:::
#vue
:::tip{to="/getting-started/icons/vue#theme"}
You can customize this icon globally in your `vite.config.ts` under `ui.icons.loading` key.
:::
:: ::
### Disabled ### Disabled
@@ -222,16 +214,6 @@ name: 'input-clear-button-example'
--- ---
:: ::
### With copy button
You can put a [Button](/components/button) inside the `#trailing` slot to copy the value to the clipboard.
::component-example
---
name: 'input-copy-button-example'
---
::
### With password toggle ### With password toggle
You can put a [Button](/components/button) inside the `#trailing` slot to toggle the password visibility. You can put a [Button](/components/button) inside the `#trailing` slot to toggle the password visibility.
@@ -263,20 +245,6 @@ name: 'input-character-limit-example'
--- ---
:: ::
### With keyboard shortcut
You can use the [Kbd](/components/kbd) component inside the `#trailing` slot to add a keyboard shortcut to the Input.
::component-example
---
name: 'input-kbd-example'
---
::
::note{to="/composables/define-shortcuts"}
This example uses the `defineShortcuts` composable to focus the Input when the :kbd{value="/"} key is pressed.
::
### With floating label ### With floating label
You can use the `#default` slot to add a floating label to the Input. You can use the `#default` slot to add a floating label to the Input.
@@ -298,7 +266,7 @@ name: 'input-form-field-example'
:: ::
::tip{to="/components/form"} ::tip{to="/components/form"}
It also provides validation and error handling when used within a **Form** component. It also provides validation and error handling when used within a [Form](/components/form) component.
:: ::
### Within a ButtonGroup ### Within a ButtonGroup

View File

@@ -13,7 +13,6 @@ The Link component is a wrapper around [`<NuxtLink>`](https://nuxt.com/docs/api/
- `inactive-class` prop to set a class when the link is inactive, `active-class` is used when active. - `inactive-class` prop to set a class when the link is inactive, `active-class` is used when active.
- `exact` prop to style with `active-class` when the link is active and the route is exactly the same as the current route. - `exact` prop to style with `active-class` when the link is active and the route is exactly the same as the current route.
- `exact-query` and `exact-hash` props to style with `active-class` when the link is active and the query or hash is exactly the same as the current query or hash. - `exact-query` and `exact-hash` props to style with `active-class` when the link is active and the query or hash is exactly the same as the current query or hash.
- use `exact-query="partial"` to style with `active-class` when the link is active and the query partially match the current query.
The incentive behind this is to provide the same API as NuxtLink back in Nuxt 2 / Vue 2. You can read more about it in the Vue Router [migration from Vue 2](https://router.vuejs.org/guide/migration/#removal-of-the-exact-prop-in-router-link) guide. The incentive behind this is to provide the same API as NuxtLink back in Nuxt 2 / Vue 2. You can read more about it in the Vue Router [migration from Vue 2](https://router.vuejs.org/guide/migration/#removal-of-the-exact-prop-in-router-link) guide.

View File

@@ -156,16 +156,8 @@ slots:
:placeholder{class="h-48"} :placeholder{class="h-48"}
:: ::
::framework-only ::tip{to="/getting-started/icons#theme"}
#nuxt
:::tip{to="/getting-started/icons/nuxt#theme"}
You can customize this icon globally in your `app.config.ts` under `ui.icons.close` key. You can customize this icon globally in your `app.config.ts` under `ui.icons.close` key.
:::
#vue
:::tip{to="/getting-started/icons/vue#theme"}
You can customize this icon globally in your `vite.config.ts` under `ui.icons.close` key.
:::
:: ::
### Overlay ### Overlay

View File

@@ -434,16 +434,8 @@ props:
--- ---
:: ::
::framework-only ::tip{to="/getting-started/icons#theme"}
#nuxt
:::tip{to="/getting-started/icons/nuxt#theme"}
You can customize this icon globally in your `app.config.ts` under `ui.icons.chevronDown` key. You can customize this icon globally in your `app.config.ts` under `ui.icons.chevronDown` key.
:::
#vue
:::tip{to="/getting-started/icons/vue#theme"}
You can customize this icon globally in your `vite.config.ts` under `ui.icons.chevronDown` key.
:::
:: ::
### Arrow ### Arrow

View File

@@ -1,182 +0,0 @@
---
title: PinInput
description: An input element to enter a pin.
links:
- label: GitHub
icon: i-simple-icons-github
to: https://github.com/nuxt/ui/tree/v3/src/runtime/components/PinInput.vue
navigation.badge: New
---
## Usage
Use the `v-model` directive to control the value of the PinInput.
::component-code
---
prettier: true
ignore:
- modelValue
external:
- modelValue
props:
modelValue: []
---
::
Use the `default-value` prop to set the initial value when you do not need to control its state.
::component-code
---
prettier: true
ignore:
- defaultValue
props:
defaultValue: ['1','2','3']
---
::
### Type
Use the `type` prop to change the input type. Defaults to `text`.
::component-code
---
items:
type:
- text
- number
props:
type: 'number'
---
::
::note
When `type` is set to `number`, it will only accept numeric characters.
::
### Mask
Use the `mask` prop to treat the input like a password.
::component-code
---
prettier: true
ignore:
- placeholder
- defaultValue
props:
mask: true
defaultValue: ['1','2','3','4','5']
---
::
### OTP
Use the `otp` prop to enable One-Time Password functionality. When enabled, mobile devices can automatically detect and fill OTP codes from SMS messages or clipboard content, with autocomplete support.
::component-code
---
props:
otp: true
---
::
### Length
Use the `length` prop to change the amount of inputs.
::component-code
---
props:
length: 6
---
::
### Placeholder
Use the `placeholder` prop to set a placeholder text.
::component-code
---
props:
placeholder: '○'
---
::
### Color
Use the `color` prop to change the ring color when the PinInput is focused.
::component-code
---
ignore:
- placeholder
props:
color: neutral
highlight: true
placeholder: '○'
---
::
::note
The `highlight` prop is used here to show the focus state. It's used internally when a validation error occurs.
::
### Variant
Use the `variant` prop to change the variant of the PinInput.
::component-code
---
ignore:
- placeholder
props:
color: neutral
variant: subtle
highlight: false
placeholder: '○'
---
::
### Size
Use the `size` prop to change the size of the PinInput.
::component-code
---
ignore:
- placeholder
props:
size: xl
placeholder: '○'
---
::
### Disabled
Use the `disabled` prop to disable the PinInput.
::component-code
---
ignore:
- placeholder
props:
disabled: true
placeholder: '○'
---
::
## API
### Props
:component-props
### Emits
:component-emits
## Theme
:component-theme

View File

@@ -235,48 +235,6 @@ props:
--- ---
:: ::
::tip
You can set the `search-input` prop to `false` to hide the search input.
::
### Create Item
Use the `create-item` prop to allow user input.
::component-code
---
prettier: true
ignore:
- modelValue
- items
- class
external:
- items
- modelValue
items:
createItem:
- true
- 'always'
props:
modelValue: 'Backlog'
createItem: true
items:
- Backlog
- Todo
- In Progress
- Done
class: 'w-48'
---
::
::note
The create option shows when no match is found by default. Set it to `always` to show it even when similar values exist.
::
::tip{to="#emits"}
Use the `@create` event to handle the creation of the item. You will receive the event and the item as arguments.
::
### Content ### Content
Use the `content` prop to control how the SelectMenu content is rendered, like its `align` or `side` for example. Use the `content` prop to control how the SelectMenu content is rendered, like its `align` or `side` for example.
@@ -482,16 +440,8 @@ props:
--- ---
:: ::
::framework-only ::tip{to="/getting-started/icons#theme"}
#nuxt
:::tip{to="/getting-started/icons/nuxt#theme"}
You can customize this icon globally in your `app.config.ts` under `ui.icons.chevronDown` key. You can customize this icon globally in your `app.config.ts` under `ui.icons.chevronDown` key.
:::
#vue
:::tip{to="/getting-started/icons/vue#theme"}
You can customize this icon globally in your `vite.config.ts` under `ui.icons.chevronDown` key.
:::
:: ::
### Selected Icon ### Selected Icon
@@ -521,16 +471,8 @@ props:
--- ---
:: ::
::framework-only ::tip{to="/getting-started/icons#theme"}
#nuxt
:::tip{to="/getting-started/icons/nuxt#theme"}
You can customize this icon globally in your `app.config.ts` under `ui.icons.check` key. You can customize this icon globally in your `app.config.ts` under `ui.icons.check` key.
:::
#vue
:::tip{to="/getting-started/icons/vue#theme"}
You can customize this icon globally in your `vite.config.ts` under `ui.icons.check` key.
:::
:: ::
### Avatar ### Avatar
@@ -615,16 +557,8 @@ props:
--- ---
:: ::
::framework-only ::tip{to="/getting-started/icons#theme"}
#nuxt
:::tip{to="/getting-started/icons/nuxt#theme"}
You can customize this icon globally in your `app.config.ts` under `ui.icons.loading` key. You can customize this icon globally in your `app.config.ts` under `ui.icons.loading` key.
:::
#vue
:::tip{to="/getting-started/icons/vue#theme"}
You can customize this icon globally in your `vite.config.ts` under `ui.icons.loading` key.
:::
:: ::
### Disabled ### Disabled
@@ -806,7 +740,7 @@ name: 'select-menu-filter-fields-example'
--- ---
:: ::
### As a CountryPicker ### As a country picker
This example demonstrates using the SelectMenu as a country picker with lazy loading - countries are only fetched when the menu is opened. This example demonstrates using the SelectMenu as a country picker with lazy loading - countries are only fetched when the menu is opened.

View File

@@ -206,7 +206,7 @@ props:
:: ::
::note{to="https://www.radix-vue.com/components/select.html#change-the-positioning-mode"} ::note{to="https://www.radix-vue.com/components/select.html#change-the-positioning-mode"}
Read more about the `content.position` prop in the **Radix Vue** documentation. Read more about the `content.position` prop in the [Radix Vue documentation](https://www.radix-vue.com/components/select.html#change-the-positioning-mode).
:: ::
<!-- <!--
@@ -378,16 +378,8 @@ props:
--- ---
:: ::
::framework-only ::tip{to="/getting-started/icons#theme"}
#nuxt
:::tip{to="/getting-started/icons/nuxt#theme"}
You can customize this icon globally in your `app.config.ts` under `ui.icons.chevronDown` key. You can customize this icon globally in your `app.config.ts` under `ui.icons.chevronDown` key.
:::
#vue
:::tip{to="/getting-started/icons/vue#theme"}
You can customize this icon globally in your `vite.config.ts` under `ui.icons.chevronDown` key.
:::
:: ::
### Selected Icon ### Selected Icon
@@ -417,16 +409,8 @@ props:
--- ---
:: ::
::framework-only ::tip{to="/getting-started/icons#theme"}
#nuxt
:::tip{to="/getting-started/icons/nuxt#theme"}
You can customize this icon globally in your `app.config.ts` under `ui.icons.check` key. You can customize this icon globally in your `app.config.ts` under `ui.icons.check` key.
:::
#vue
:::tip{to="/getting-started/icons/vue#theme"}
You can customize this icon globally in your `vite.config.ts` under `ui.icons.check` key.
:::
:: ::
### Avatar ### Avatar
@@ -511,16 +495,8 @@ props:
--- ---
:: ::
::framework-only ::tip{to="/getting-started/icons#theme"}
#nuxt
:::tip{to="/getting-started/icons/nuxt#theme"}
You can customize this icon globally in your `app.config.ts` under `ui.icons.loading` key. You can customize this icon globally in your `app.config.ts` under `ui.icons.loading` key.
:::
#vue
:::tip{to="/getting-started/icons/vue#theme"}
You can customize this icon globally in your `vite.config.ts` under `ui.icons.loading` key.
:::
:: ::
### Disabled ### Disabled

View File

@@ -156,16 +156,8 @@ slots:
:placeholder{class="h-full"} :placeholder{class="h-full"}
:: ::
::framework-only ::tip{to="/getting-started/icons#theme"}
#nuxt
:::tip{to="/getting-started/icons/nuxt#theme"}
You can customize this icon globally in your `app.config.ts` under `ui.icons.close` key. You can customize this icon globally in your `app.config.ts` under `ui.icons.close` key.
:::
#vue
:::tip{to="/getting-started/icons/vue#theme"}
You can customize this icon globally in your `vite.config.ts` under `ui.icons.close` key.
:::
:: ::
### Side ### Side

View File

@@ -123,16 +123,8 @@ props:
--- ---
:: ::
::framework-only ::tip{to="/getting-started/icons#theme"}
#nuxt
:::tip{to="/getting-started/icons/nuxt#theme"}
You can customize this icon globally in your `app.config.ts` under `ui.icons.loading` key. You can customize this icon globally in your `app.config.ts` under `ui.icons.loading` key.
:::
#vue
:::tip{to="/getting-started/icons/vue#theme"}
You can customize this icon globally in your `vite.config.ts` under `ui.icons.loading` key.
:::
:: ::
### Color ### Color

View File

@@ -128,16 +128,8 @@ name: 'toast-close-icon-example'
--- ---
:: ::
::framework-only ::tip{to="/getting-started/icons#theme"}
#nuxt
:::tip{to="/getting-started/icons/nuxt#theme"}
You can customize this icon globally in your `app.config.ts` under `ui.icons.close` key. You can customize this icon globally in your `app.config.ts` under `ui.icons.close` key.
:::
#vue
:::tip{to="/getting-started/icons/vue#theme"}
You can customize this icon globally in your `vite.config.ts` under `ui.icons.close` key.
:::
:: ::
### Actions ### Actions

View File

@@ -17,12 +17,7 @@ export default defineNuxtConfig({
'@nuxtjs/plausible', '@nuxtjs/plausible',
'@vueuse/nuxt', '@vueuse/nuxt',
'nuxt-component-meta', 'nuxt-component-meta',
'nuxt-og-image', 'nuxt-og-image'
(_, nuxt) => {
nuxt.hook('components:dirs', (dirs) => {
dirs.unshift({ path: resolve('./app/components/content/examples'), pathPrefix: false, prefix: '', global: true })
})
}
], ],
app: { app: {
@@ -37,24 +32,10 @@ export default defineNuxtConfig({
}, },
content: { content: {
database: {
type: 'd1',
binding: 'DB'
},
build: { build: {
markdown: { markdown: {
highlight: { highlight: {
langs: ['bash', 'ts', 'typescript', 'diff', 'vue', 'json', 'yml', 'css', 'mdc'] langs: ['bash', 'ts', 'typescript', 'diff', 'vue', 'json', 'yml', 'css', 'mdc']
},
remarkPlugins: {
'remark-mdc': {
options: {
experimental: {
autoUnwrap: false
}
}
}
} }
} }
} }
@@ -75,8 +56,6 @@ export default defineNuxtConfig({
routeRules: { routeRules: {
'/': { redirect: '/getting-started', prerender: false }, '/': { redirect: '/getting-started', prerender: false },
'/getting-started/installation': { redirect: '/getting-started/installation/nuxt', prerender: false }, '/getting-started/installation': { redirect: '/getting-started/installation/nuxt', prerender: false },
'/getting-started/icons': { redirect: '/getting-started/icons/nuxt', prerender: false },
'/getting-started/color-mode': { redirect: '/getting-started/color-mode/nuxt', prerender: false },
'/getting-started/i18n': { redirect: '/getting-started/i18n/nuxt', prerender: false }, '/getting-started/i18n': { redirect: '/getting-started/i18n/nuxt', prerender: false },
'/composables': { redirect: '/composables/define-shortcuts', prerender: false }, '/composables': { redirect: '/composables/define-shortcuts', prerender: false },
'/components': { redirect: '/components/app', prerender: false } '/components': { redirect: '/components/app', prerender: false }
@@ -91,28 +70,31 @@ export default defineNuxtConfig({
nitro: { nitro: {
prerender: { prerender: {
routes: [ routes: [
// '/getting-started', '/getting-started',
'/api/countries.json', '/api/countries.json'
'/api/locales.json'
// '/api/releases.json', // '/api/releases.json',
// '/api/pulls.json' // '/api/pulls.json'
] ],
// crawlLinks: true, crawlLinks: true,
// autoSubfolderIndex: false autoSubfolderIndex: false
// ignore: !process.env.NUXT_GITHUB_TOKEN ? ['/pro'] : [] // ignore: !process.env.NUXT_GITHUB_TOKEN ? ['/pro'] : []
}, },
cloudflare: { cloudflare: {
pages: { pages: {
routes: { routes: {
exclude: [] exclude: [
'/components/*',
'/getting-started/*',
'/composables/*',
'/api/*'
]
} }
} }
} }
}, },
hub: { hub: {
cache: true, cache: true
database: true
}, },
componentMeta: { componentMeta: {

View File

@@ -3,22 +3,21 @@
"name": "@nuxt/ui-docs", "name": "@nuxt/ui-docs",
"type": "module", "type": "module",
"dependencies": { "dependencies": {
"@iconify-json/logos": "^1.2.3", "@iconify-json/lucide": "^1.2.13",
"@iconify-json/lucide": "^1.2.16", "@iconify-json/simple-icons": "^1.2.11",
"@iconify-json/simple-icons": "^1.2.13",
"@iconify-json/vscode-icons": "^1.2.2", "@iconify-json/vscode-icons": "^1.2.2",
"@nuxt/content": "3.0.0-alpha.7", "@nuxt/content": "3.0.0-alpha.6",
"@nuxt/image": "^1.8.1", "@nuxt/image": "^1.8.1",
"@nuxt/ui": "latest", "@nuxt/ui": "latest",
"@nuxt/ui-pro": "https://pkg.pr.new/@nuxt/ui-pro@1408077", "@nuxt/ui-pro": "https://pkg.pr.new/@nuxt/ui-pro@7c62edd",
"@nuxthub/core": "^0.8.7", "@nuxthub/core": "^0.8.6",
"@nuxtjs/plausible": "^1.1.1", "@nuxtjs/plausible": "^1.0.3",
"@octokit/rest": "^21.0.2", "@octokit/rest": "^21.0.2",
"@vueuse/nuxt": "^11.3.0", "@vueuse/nuxt": "^11.2.0",
"joi": "^17.13.3", "joi": "^17.13.3",
"nuxt": "^3.14.1592", "nuxt": "^3.14.159",
"nuxt-component-meta": "^0.9.0", "nuxt-component-meta": "^0.9.0",
"nuxt-og-image": "^3.1.1", "nuxt-og-image": "^3.0.8",
"prettier": "^3.3.3", "prettier": "^3.3.3",
"shiki-transformer-color-highlight": "^0.2.0", "shiki-transformer-color-highlight": "^0.2.0",
"superstruct": "^2.0.2", "superstruct": "^2.0.2",
@@ -28,6 +27,6 @@
"zod": "^3.23.8" "zod": "^3.23.8"
}, },
"devDependencies": { "devDependencies": {
"wrangler": "^3.90.0" "wrangler": "^3.86.1"
} }
} }

View File

@@ -1 +1,2 @@
user-agent: * user-agent: *
disallow: /dev/*

View File

@@ -1,505 +0,0 @@
const locales: Record<string, string> = {
'aa': '🇪🇷',
'aa-ER': '🇪🇷',
'af': '🇳🇦',
'af-NA': '🇳🇦',
'af-ZA': '🇿🇦',
'am': '🇪🇹',
'am-ET': '🇪🇹',
'ar': '🇪🇬',
'ar-AE': '🇦🇪',
'ar-BH': '🇧🇭',
'ar-DJ': '🇩🇯',
'ar-DZ': '🇩🇿',
'ar-EG': '🇪🇬',
'ar-ER': '🇪🇷',
'ar-IL': '🇮🇱',
'ar-IQ': '🇮🇶',
'ar-JO': '🇯🇴',
'ar-KM': '🇰🇲',
'ar-KW': '🇰🇼',
'ar-LB': '🇱🇧',
'ar-LY': '🇱🇾',
'ar-MA': '🇲🇦',
'ar-MR': '🇲🇷',
'ar-OM': '🇴🇲',
'ar-PS': '🇵🇸',
'ar-QA': '🇶🇦',
'ar-SA': '🇸🇦',
'ar-SD': '🇸🇩',
'ar-SO': '🇸🇴',
'ar-SY': '🇸🇾',
'ar-TD': '🇹🇩',
'ar-TN': '🇹🇳',
'ar-YE': '🇾🇪',
'ay': '🇧🇴',
'ay-BO': '🇧🇴',
'az': '🇦🇿',
'az-AZ': '🇦🇿',
'be': '🇧🇾',
'be-BY': '🇧🇾',
'bg': '🇧🇬',
'bg-BG': '🇧🇬',
'bi': '🇻🇺',
'bi-VU': '🇻🇺',
'bn': '🇧🇩',
'bn-BD': '🇧🇩',
'bs': '🇧🇦',
'bs-BA': '🇧🇦',
'bs-ME': '🇲🇪',
'byn': '🇪🇷',
'byn-ER': '🇪🇷',
'ca': '🇦🇩',
'ca-AD': '🇦🇩',
'ch': '🇬🇺',
'ch-GU': '🇬🇺',
'ch-MP': '🇲🇵',
'cs': '🇨🇿',
'cs-CZ': '🇨🇿',
'da': '🇩🇰',
'da-DK': '🇩🇰',
'de': '🇩🇪',
'de-AT': '🇦🇹',
'de-BE': '🇧🇪',
'de-CH': '🇨🇭',
'de-DE': '🇩🇪',
'de-LI': '🇱🇮',
'de-LU': '🇱🇺',
'de-VA': '🇻🇦',
'dv': '🇲🇻',
'dv-MV': '🇲🇻',
'dz': '🇧🇹',
'dz-BT': '🇧🇹',
'el': '🇬🇷',
'el-CY': '🇨🇾',
'el-GR': '🇬🇷',
'en': '🇬🇧',
'en-AG': '🇦🇬',
'en-AI': '🇦🇮',
'en-AQ': '🇦🇶',
'en-AS': '🇦🇸',
'en-AU': '🇦🇺',
'en-BB': '🇧🇧',
'en-BM': '🇧🇲',
'en-BS': '🇧🇸',
'en-BW': '🇧🇼',
'en-BZ': '🇧🇿',
'en-CA': '🇨🇦',
'en-CC': '🇨🇨',
'en-CK': '🇨🇰',
'en-CM': '🇨🇲',
'en-CW': '🇨🇼',
'en-CX': '🇨🇽',
'en-DM': '🇩🇲',
'en-ER': '🇪🇷',
'en-FJ': '🇫🇯',
'en-FK': '🇫🇰',
'en-FM': '🇫🇲',
'en-GB': '🇬🇧',
'en-GD': '🇬🇩',
'en-GG': '🇬🇬',
'en-GH': '🇬🇭',
'en-GI': '🇬🇮',
'en-GM': '🇬🇲',
'en-GS': '🇬🇸',
'en-GU': '🇬🇺',
'en-GY': '🇬🇾',
'en-HK': '🇭🇰',
'en-HM': '🇭🇲',
'en-IE': '🇮🇪',
'en-IM': '🇮🇲',
'en-IN': '🇮🇳',
'en-IO': '🇮🇴',
'en-JE': '🇯🇪',
'en-JM': '🇯🇲',
'en-KE': '🇰🇪',
'en-KI': '🇰🇮',
'en-KN': '🇰🇳',
'en-KY': '🇰🇾',
'en-LC': '🇱🇨',
'en-LR': '🇱🇷',
'en-LS': '🇱🇸',
'en-MF': '🇲🇫',
'en-MH': '🇲🇭',
'en-MP': '🇲🇵',
'en-MS': '🇲🇸',
'en-MT': '🇲🇹',
'en-MU': '🇲🇺',
'en-MW': '🇲🇼',
'en-NA': '🇳🇦',
'en-NF': '🇳🇫',
'en-NG': '🇳🇬',
'en-NR': '🇳🇷',
'en-NU': '🇳🇺',
'en-NZ': '🇳🇿',
'en-PG': '🇵🇬',
'en-PH': '🇵🇭',
'en-PK': '🇵🇰',
'en-PN': '🇵🇳',
'en-PR': '🇵🇷',
'en-PW': '🇵🇼',
'en-RW': '🇷🇼',
'en-SB': '🇸🇧',
'en-SC': '🇸🇨',
'en-SD': '🇸🇩',
'en-SG': '🇸🇬',
'en-SH': '🇸🇭',
'en-SL': '🇸🇱',
'en-SS': '🇸🇸',
'en-SX': '🇸🇽',
'en-SZ': '🇸🇿',
'en-TC': '🇹🇨',
'en-TK': '🇹🇰',
'en-TO': '🇹🇴',
'en-TT': '🇹🇹',
'en-TV': '🇹🇻',
'en-TZ': '🇹🇿',
'en-UG': '🇺🇬',
'en-UM': '🇺🇲',
'en-US': '🇺🇸',
'en-VC': '🇻🇨',
'en-VG': '🇻🇬',
'en-VI': '🇻🇮',
'en-VU': '🇻🇺',
'en-WS': '🇼🇸',
'en-ZA': '🇿🇦',
'en-ZM': '🇿🇲',
'en-ZW': '🇿🇼',
'es': '🇪🇸',
'es-AR': '🇦🇷',
'es-BO': '🇧🇴',
'es-BZ': '🇧🇿',
'es-CL': '🇨🇱',
'es-CO': '🇨🇴',
'es-CR': '🇨🇷',
'es-CU': '🇨🇺',
'es-DO': '🇩🇴',
'es-EC': '🇪🇨',
'es-EH': '🇪🇭',
'es-ES': '🇪🇸',
'es-GQ': '🇬🇶',
'es-GT': '🇬🇹',
'es-GU': '🇬🇺',
'es-HN': '🇭🇳',
'es-MX': '🇲🇽',
'es-NI': '🇳🇮',
'es-PA': '🇵🇦',
'es-PE': '🇵🇪',
'es-PR': '🇵🇷',
'es-PY': '🇵🇾',
'es-SV': '🇸🇻',
'es-UY': '🇺🇾',
'es-VE': '🇻🇪',
'et': '🇪🇪',
'et-EE': '🇪🇪',
'fa': '🇮🇷',
'fa-IR': '🇮🇷',
'fan': '🇬🇶',
'fan-GQ': '🇬🇶',
'ff': '🇧🇫',
'ff-BF': '🇧🇫',
'ff-GN': '🇬🇳',
'fi': '🇫🇮',
'fi-FI': '🇫🇮',
'fj': '🇫🇯',
'fj-FJ': '🇫🇯',
'fo': '🇫🇴',
'fo-FO': '🇫🇴',
'fr': '🇫🇷',
'fr-BE': '🇧🇪',
'fr-BF': '🇧🇫',
'fr-BI': '🇧🇮',
'fr-BJ': '🇧🇯',
'fr-BL': '🇧🇱',
'fr-CA': '🇨🇦',
'fr-CD': '🇨🇩',
'fr-CF': '🇨🇫',
'fr-CG': '🇨🇬',
'fr-CH': '🇨🇭',
'fr-CI': '🇨🇮',
'fr-CM': '🇨🇲',
'fr-DJ': '🇩🇯',
'fr-FR': '🇫🇷',
'fr-GA': '🇬🇦',
'fr-GF': '🇬🇫',
'fr-GG': '🇬🇬',
'fr-GN': '🇬🇳',
'fr-GP': '🇬🇵',
'fr-GQ': '🇬🇶',
'fr-HT': '🇭🇹',
'fr-JE': '🇯🇪',
'fr-KM': '🇰🇲',
'fr-LB': '🇱🇧',
'fr-LU': '🇱🇺',
'fr-MC': '🇲🇨',
'fr-MF': '🇲🇫',
'fr-MG': '🇲🇬',
'fr-ML': '🇲🇱',
'fr-MQ': '🇲🇶',
'fr-NC': '🇳🇨',
'fr-NE': '🇳🇪',
'fr-PF': '🇵🇫',
'fr-PM': '🇵🇲',
'fr-RE': '🇷🇪',
'fr-RW': '🇷🇼',
'fr-SC': '🇸🇨',
'fr-SN': '🇸🇳',
'fr-TD': '🇹🇩',
'fr-TF': '🇹🇫',
'fr-TG': '🇹🇬',
'fr-VA': '🇻🇦',
'fr-VU': '🇻🇺',
'fr-WF': '🇼🇫',
'fr-YT': '🇾🇹',
'ga': '🇮🇪',
'ga-IE': '🇮🇪',
'gn': '🇦🇷',
'gn-AR': '🇦🇷',
'gn-PY': '🇵🇾',
'gv': '🇮🇲',
'gv-IM': '🇮🇲',
'he': '🇮🇱',
'he-IL': '🇮🇱',
'hi': '🇮🇳',
'hi-IN': '🇮🇳',
'hif': '🇫🇯',
'hif-FJ': '🇫🇯',
'hr': '🇭🇷',
'hr-BA': '🇧🇦',
'hr-HR': '🇭🇷',
'hr-ME': '🇲🇪',
'ht': '🇭🇹',
'ht-HT': '🇭🇹',
'hu': '🇭🇺',
'hu-HU': '🇭🇺',
'hy': '🇦🇲',
'hy-AM': '🇦🇲',
'hy-CY': '🇨🇾',
'id': '🇮🇩',
'id-ID': '🇮🇩',
'is': '🇮🇸',
'is-IS': '🇮🇸',
'it': '🇮🇹',
'it-CH': '🇨🇭',
'it-IT': '🇮🇹',
'it-SM': '🇸🇲',
'it-VA': '🇻🇦',
'ja': '🇯🇵',
'ja-JP': '🇯🇵',
'ka': '🇬🇪',
'ka-GE': '🇬🇪',
'kg': '🇨🇩',
'kg-CD': '🇨🇩',
'kk': '🇰🇿',
'kk-KZ': '🇰🇿',
'kl': '🇬🇱',
'kl-GL': '🇬🇱',
'km': '🇰🇭',
'km-KH': '🇰🇭',
'ko': '🇰🇵',
'ko-KP': '🇰🇵',
'ko-KR': '🇰🇷',
'ku': '🇮🇶',
'ku-IQ': '🇮🇶',
'kun': '🇪🇷',
'kun-ER': '🇪🇷',
'ky': '🇰🇬',
'ky-KG': '🇰🇬',
'la': '🇻🇦',
'la-VA': '🇻🇦',
'lb': '🇱🇺',
'lb-LU': '🇱🇺',
'ln': '🇨🇩',
'ln-CD': '🇨🇩',
'ln-CG': '🇨🇬',
'lo': '🇱🇦',
'lo-LA': '🇱🇦',
'lt': '🇱🇹',
'lt-LT': '🇱🇹',
'lu': '🇨🇩',
'lu-CD': '🇨🇩',
'lv': '🇱🇻',
'lv-LV': '🇱🇻',
'mg': '🇲🇬',
'mg-MG': '🇲🇬',
'mh': '🇲🇭',
'mh-MH': '🇲🇭',
'mi': '🇳🇿',
'mi-NZ': '🇳🇿',
'mk': '🇲🇰',
'mk-MK': '🇲🇰',
'mn': '🇲🇳',
'mn-MN': '🇲🇳',
'ms': '🇧🇳',
'ms-BN': '🇧🇳',
'ms-MY': '🇲🇾',
'ms-SG': '🇸🇬',
'mt': '🇲🇹',
'mt-MT': '🇲🇹',
'my': '🇲🇲',
'my-MM': '🇲🇲',
'na': '🇳🇷',
'na-NR': '🇳🇷',
'nb': '🇧🇻',
'nb-BV': '🇧🇻',
'nb-NO': '🇳🇴',
'nd': '🇿🇼',
'nd-ZW': '🇿🇼',
'ne': '🇳🇵',
'ne-NP': '🇳🇵',
'nl': '🇳🇱',
'nl-AW': '🇦🇼',
'nl-BE': '🇧🇪',
'nl-BQ': '🇧🇶',
'nl-CW': '🇨🇼',
'nl-MF': '🇲🇫',
'nl-NL': '🇳🇱',
'nl-SR': '🇸🇷',
'nl-SX': '🇸🇽',
'nn': '🇧🇻',
'nn-BV': '🇧🇻',
'nn-NO': '🇳🇴',
'no': '🇳🇴',
'no-BV': '🇧🇻',
'no-NO': '🇳🇴',
'no-SJ': '🇸🇯',
'nr': '🇿🇦',
'nr-ZA': '🇿🇦',
'nrb': '🇪🇷',
'nrb-ER': '🇪🇷',
'ny': '🇲🇼',
'ny-MW': '🇲🇼',
'pa': '🇦🇼',
'pa-AW': '🇦🇼',
'pa-CW': '🇨🇼',
'pl': '🇵🇱',
'pl-PL': '🇵🇱',
'ps': '🇦🇫',
'ps-AF': '🇦🇫',
'pt': '🇵🇹',
'pt-AO': '🇦🇴',
'pt-BR': '🇧🇷',
'pt-CV': '🇨🇻',
'pt-GQ': '🇬🇶',
'pt-GW': '🇬🇼',
'pt-MO': '🇲🇴',
'pt-MZ': '🇲🇿',
'pt-PT': '🇵🇹',
'pt-ST': '🇸🇹',
'pt-TL': '🇹🇱',
'qu': '🇧🇴',
'qu-BO': '🇧🇴',
'rar': '🇨🇰',
'rar-CK': '🇨🇰',
'rm': '🇨🇭',
'rm-CH': '🇨🇭',
'rn': '🇧🇮',
'rn-BI': '🇧🇮',
'ro': '🇷🇴',
'ro-MD': '🇲🇩',
'ro-RO': '🇷🇴',
'rtm': '🇫🇯',
'rtm-FJ': '🇫🇯',
'ru': '🇷🇺',
'ru-AQ': '🇦🇶',
'ru-BY': '🇧🇾',
'ru-KG': '🇰🇬',
'ru-KZ': '🇰🇿',
'ru-RU': '🇷🇺',
'ru-TJ': '🇹🇯',
'ru-TM': '🇹🇲',
'ru-UZ': '🇺🇿',
'rw': '🇷🇼',
'rw-RW': '🇷🇼',
'sg': '🇨🇫',
'sg-CF': '🇨🇫',
'si': '🇱🇰',
'si-LK': '🇱🇰',
'sk': '🇸🇰',
'sk-CZ': '🇨🇿',
'sk-SK': '🇸🇰',
'sl': '🇸🇮',
'sl-SI': '🇸🇮',
'sm': '🇦🇸',
'sm-AS': '🇦🇸',
'sm-WS': '🇼🇸',
'sn': '🇿🇼',
'sn-ZW': '🇿🇼',
'so': '🇸🇴',
'so-SO': '🇸🇴',
'sq': '🇦🇱',
'sq-AL': '🇦🇱',
'sq-ME': '🇲🇪',
'sq-XK': '🇽🇰',
'sr': '🇧🇦',
'sr-BA': '🇧🇦',
'sr-ME': '🇲🇪',
'sr-RS': '🇷🇸',
'sr-XK': '🇽🇰',
'ss': '🇸🇿',
'ss-SZ': '🇸🇿',
'ss-ZA': '🇿🇦',
'ssy': '🇪🇷',
'ssy-ER': '🇪🇷',
'st': '🇱🇸',
'st-LS': '🇱🇸',
'st-ZA': '🇿🇦',
'sv': '🇦🇽',
'sv-AX': '🇦🇽',
'sv-FI': '🇫🇮',
'sv-SE': '🇸🇪',
'sw': '🇨🇩',
'sw-CD': '🇨🇩',
'sw-KE': '🇰🇪',
'sw-TZ': '🇹🇿',
'sw-UG': '🇺🇬',
'ta': '🇸🇬',
'ta-LK': '🇱🇰',
'ta-SG': '🇸🇬',
'tg': '🇹🇯',
'tg-TJ': '🇹🇯',
'th': '🇹🇭',
'th-TH': '🇹🇭',
'ti': '🇪🇷',
'ti-ER': '🇪🇷',
'tig': '🇪🇷',
'tig-ER': '🇪🇷',
'tk': '🇦🇫',
'tk-AF': '🇦🇫',
'tk-TM': '🇹🇲',
'tn': '🇧🇼',
'tn-BW': '🇧🇼',
'tn-ZA': '🇿🇦',
'to': '🇹🇴',
'to-TO': '🇹🇴',
'tr': '🇹🇷',
'tr-CY': '🇨🇾',
'tr-TR': '🇹🇷',
'ts': '🇿🇦',
'ts-ZA': '🇿🇦',
'uk': '🇺🇦',
'uk-UA': '🇺🇦',
'ur': '🇵🇰',
'ur-PK': '🇵🇰',
'uz': '🇺🇿',
'uz-AF': '🇦🇫',
'uz-UZ': '🇺🇿',
've': '🇿🇦',
've-ZA': '🇿🇦',
'vi': '🇻🇳',
'vi-VN': '🇻🇳',
'xh': '🇿🇦',
'xh-ZA': '🇿🇦',
'zh': '🇨🇳',
'zh-CN': '🇨🇳',
'zh-HK': '🇭🇰',
'zh-Hans': '🇨🇳',
'zh-Hant': '🇨🇳',
'zh-MO': '🇲🇴',
'zh-SG': '🇸🇬',
'zh-TW': '🇹🇼',
'zu': '🇿🇦',
'zu-ZA': '🇿🇦'
}
export default eventHandler(async () => locales)

View File

@@ -1,8 +1,8 @@
{ {
"name": "@nuxt/ui", "name": "@nuxt/ui",
"description": "A UI Library for Modern Web Apps, powered by Vue & Tailwind CSS.", "description": "A UI Library for Modern Web Apps, powered by Vue & Tailwind CSS.",
"version": "3.0.0-alpha.9", "version": "3.0.0-alpha.8",
"packageManager": "pnpm@9.14.2", "packageManager": "pnpm@9.12.3",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git+https://github.com/nuxt/ui.git" "url": "git+https://github.com/nuxt/ui.git"
@@ -55,7 +55,6 @@
"build": "nuxt-module-build build && pnpm devtools:build", "build": "nuxt-module-build build && pnpm devtools:build",
"prepack": "pnpm build", "prepack": "pnpm build",
"dev": "DEV=true nuxi dev playground", "dev": "DEV=true nuxi dev playground",
"dev:vue": "DEV=true vite playground-vue",
"dev:build": "nuxi build playground", "dev:build": "nuxi build playground",
"dev:prepare": "nuxt-module-build build --stub && nuxt-module-build prepare && nuxi prepare playground && nuxi prepare docs && nuxi prepare devtools && vite build playground-vue", "dev:prepare": "nuxt-module-build build --stub && nuxt-module-build prepare && nuxi prepare playground && nuxi prepare docs && nuxi prepare devtools && vite build playground-vue",
"devtools": "NUXT_UI_DEVTOOLS_LOCAL=true nuxi dev playground", "devtools": "NUXT_UI_DEVTOOLS_LOCAL=true nuxi dev playground",
@@ -69,70 +68,67 @@
"typecheck": "vue-tsc --noEmit && nuxi typecheck playground && nuxi typecheck docs && nuxi typecheck devtools && cd playground-vue && vue-tsc --noEmit", "typecheck": "vue-tsc --noEmit && nuxi typecheck playground && nuxi typecheck docs && nuxi typecheck devtools && cd playground-vue && vue-tsc --noEmit",
"test": "vitest", "test": "vitest",
"test:vue": "vitest -c vitest.vue.config.ts", "test:vue": "vitest -c vitest.vue.config.ts",
"test:vue:build": "vite build playground-vue",
"release": "release-it --preRelease=alpha --npm.tag=next" "release": "release-it --preRelease=alpha --npm.tag=next"
}, },
"dependencies": { "dependencies": {
"@iconify/vue": "^4.1.2", "@iconify/vue": "^4.1.2",
"@internationalized/date": "^3.6.0", "@nuxt/devtools-kit": "^1.6.0",
"@internationalized/number": "^3.6.0",
"@nuxt/devtools-kit": "^1.6.1",
"@nuxt/fonts": "^0.10.2", "@nuxt/fonts": "^0.10.2",
"@nuxt/icon": "^1.8.2", "@nuxt/icon": "^1.7.2",
"@nuxt/kit": "^3.14.1592", "@nuxt/kit": "^3.14.159",
"@nuxt/schema": "^3.14.1592", "@nuxt/schema": "^3.14.159",
"@nuxtjs/color-mode": "^3.5.2", "@nuxtjs/color-mode": "^3.5.2",
"@tailwindcss/postcss": "4.0.0-beta.2", "@tailwindcss/postcss": "4.0.0-alpha.33",
"@tailwindcss/vite": "4.0.0-beta.2", "@tailwindcss/vite": "4.0.0-alpha.33",
"@tanstack/vue-table": "^8.20.5", "@tanstack/vue-table": "^8.20.5",
"@unhead/vue": "^1.11.11", "@unhead/vue": "^1.11.11",
"@vueuse/core": "^11.3.0", "@vueuse/core": "^11.2.0",
"@vueuse/integrations": "^11.3.0", "@vueuse/integrations": "^11.2.0",
"consola": "^3.2.3", "consola": "^3.2.3",
"defu": "^6.1.4", "defu": "^6.1.4",
"embla-carousel-auto-height": "^8.5.1", "embla-carousel-auto-height": "^8.3.1",
"embla-carousel-auto-scroll": "^8.5.1", "embla-carousel-auto-scroll": "^8.3.1",
"embla-carousel-autoplay": "^8.5.1", "embla-carousel-autoplay": "^8.3.1",
"embla-carousel-class-names": "^8.5.1", "embla-carousel-class-names": "^8.3.1",
"embla-carousel-fade": "^8.5.1", "embla-carousel-fade": "^8.3.1",
"embla-carousel-vue": "^8.5.1", "embla-carousel-vue": "^8.3.1",
"embla-carousel-wheel-gestures": "^8.0.1", "embla-carousel-wheel-gestures": "^8.0.1",
"fuse.js": "^7.0.0", "fuse.js": "^7.0.0",
"get-port-please": "^3.1.2", "get-port-please": "^3.1.2",
"knitwork": "^1.1.0", "knitwork": "^1.1.0",
"magic-string": "^0.30.13", "magic-string": "^0.30.12",
"mlly": "^1.7.3", "mlly": "^1.7.2",
"ohash": "^1.1.4", "ohash": "^1.1.4",
"pathe": "^1.1.2", "pathe": "^1.1.2",
"radix-vue": "^1.9.10", "radix-vue": "^1.9.9",
"scule": "^1.3.0", "scule": "^1.3.0",
"sirv": "^3.0.0", "sirv": "^3.0.0",
"tailwind-variants": "^0.3.0", "tailwind-variants": "^0.2.1",
"tailwindcss": "4.0.0-beta.2", "tailwindcss": "4.0.0-alpha.33",
"tinyglobby": "^0.2.10", "tinyglobby": "^0.2.10",
"unplugin": "^1.16.0", "unplugin": "^1.15.0",
"unplugin-auto-import": "^0.18.5", "unplugin-auto-import": "^0.18.3",
"unplugin-vue-components": "^0.27.4", "unplugin-vue-components": "^0.27.4",
"vaul-vue": "^0.2.0" "vaul-vue": "^0.2.0"
}, },
"devDependencies": { "devDependencies": {
"@nuxt/eslint-config": "^0.7.1", "@nuxt/eslint-config": "^0.6.1",
"@nuxt/module-builder": "^0.8.4", "@nuxt/module-builder": "^0.8.4",
"@nuxt/test-utils": "^3.14.4", "@nuxt/test-utils": "^3.14.4",
"@release-it/conventional-changelog": "^9.0.3", "@release-it/conventional-changelog": "^9.0.2",
"@standard-schema/spec": "1.0.0-beta.3", "@standard-schema/spec": "1.0.0-beta.3",
"@vue/test-utils": "^2.4.6", "@vue/test-utils": "^2.4.6",
"embla-carousel": "^8.5.1", "embla-carousel": "^8.3.1",
"eslint": "^9.15.0", "eslint": "^9.14.0",
"happy-dom": "^15.7.4", "happy-dom": "^15.7.4",
"joi": "^17.13.3", "joi": "^17.13.3",
"knitwork": "^1.1.0", "knitwork": "^1.1.0",
"nuxt": "^3.14.1592", "nuxt": "^3.14.159",
"nuxt-component-meta": "^0.9.0", "nuxt-component-meta": "^0.9.0",
"release-it": "^17.10.0", "release-it": "^17.10.0",
"superstruct": "^2.0.2", "superstruct": "^2.0.2",
"valibot": "^0.42.1", "valibot": "^0.42.1",
"vitest": "^2.1.5", "vitest": "^2.1.4",
"vitest-environment-nuxt": "^1.0.1", "vitest-environment-nuxt": "^1.0.1",
"vue-tsc": "^2.1.10", "vue-tsc": "^2.1.10",
"yup": "^1.4.0", "yup": "^1.4.0",
@@ -143,8 +139,8 @@
}, },
"resolutions": { "resolutions": {
"@nuxt/ui": "workspace:*", "@nuxt/ui": "workspace:*",
"@nuxt/content": "3.0.0-alpha.5",
"happy-dom": "14.12.3", "happy-dom": "14.12.3",
"rollup": "^4.24.0", "rollup": "^4.24.0"
"typescript": "5.6.3"
} }
} }

View File

@@ -10,13 +10,13 @@
}, },
"dependencies": { "dependencies": {
"@nuxt/ui": "latest", "@nuxt/ui": "latest",
"vue": "^3.5.13", "vue": "^3.5.12",
"vue-router": "^4.4.5" "vue-router": "^4.4.5"
}, },
"devDependencies": { "devDependencies": {
"@vitejs/plugin-vue": "^5.2.0", "@vitejs/plugin-vue": "^5.1.5",
"typescript": "^5.7.2", "typescript": "^5.6.3",
"unplugin-auto-import": "^0.18.5", "unplugin-auto-import": "^0.18.3",
"unplugin-vue-components": "^0.27.4", "unplugin-vue-components": "^0.27.4",
"vite": "^5.4.11", "vite": "^5.4.11",
"vue-tsc": "^2.1.10" "vue-tsc": "^2.1.10"

View File

@@ -2,14 +2,12 @@
import { splitByCase, upperFirst } from 'scule' import { splitByCase, upperFirst } from 'scule'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { reactive, ref } from 'vue' import { reactive, ref } from 'vue'
import { useColorMode } from '@vueuse/core'
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore included for compatibility with Nuxt playground // @ts-ignore included for compatibility with Nuxt playground
import { useAppConfig } from '#imports' import { useAppConfig } from '#imports'
const appConfig = useAppConfig() const appConfig = useAppConfig()
const mode = useColorMode()
appConfig.toaster = reactive({ appConfig.toaster = reactive({
position: 'bottom-right' as const, position: 'bottom-right' as const,
@@ -45,7 +43,6 @@ const components = [
'modal', 'modal',
'navigation-menu', 'navigation-menu',
'pagination', 'pagination',
'pin-input',
'popover', 'popover',
'progress', 'progress',
'radio-group', 'radio-group',
@@ -84,19 +81,9 @@ defineShortcuts({
<UApp :toaster="(appConfig.toaster as any)"> <UApp :toaster="(appConfig.toaster as any)">
<div class="h-screen w-screen overflow-hidden flex min-h-0 bg-[var(--ui-bg)]" vaul-drawer-wrapper> <div class="h-screen w-screen overflow-hidden flex min-h-0 bg-[var(--ui-bg)]" vaul-drawer-wrapper>
<UNavigationMenu :items="items" orientation="vertical" class="hidden lg:flex border-e border-[var(--ui-border)] overflow-y-auto w-48 p-4" /> <UNavigationMenu :items="items" orientation="vertical" class="hidden lg:flex border-e border-[var(--ui-border)] overflow-y-auto w-48 p-4" />
<UNavigationMenu :items="items" orientation="horizontal" class="lg:hidden border-b border-[var(--ui-border)] [&>div]:min-w-min overflow-x-auto" /> <UNavigationMenu :items="items" orientation="horizontal" class="lg:hidden border-b border-[var(--ui-border)] overflow-x-auto" />
<div class="fixed top-15 lg:top-3 right-4 flex items-center gap-2"> <div class="flex-1 flex flex-col items-center justify-around overflow-y-auto w-full py-12 px-4">
<UButton
:icon="mode === 'dark' ? 'i-lucide-moon' : 'i-lucide-sun'"
color="neutral"
variant="ghost"
:aria-label="`Switch to ${mode === 'dark' ? 'light' : 'dark'} mode`"
@click="mode = mode === 'dark' ? 'light' : 'dark'"
/>
</div>
<div class="flex-1 flex flex-col items-center justify-around overflow-y-auto w-full py-14 px-4">
<Suspense> <Suspense>
<RouterView /> <RouterView />
</Suspense> </Suspense>
@@ -116,7 +103,7 @@ defineShortcuts({
@import "@nuxt/ui"; @import "@nuxt/ui";
@theme { @theme {
--font-sans: 'Public Sans', sans-serif; --font-family-sans: 'Public Sans', sans-serif;
--color-green-50: #EFFDF5; --color-green-50: #EFFDF5;
--color-green-100: #D9FBE8; --color-green-100: #D9FBE8;

View File

@@ -1,19 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { splitByCase, upperFirst } from 'scule' import { splitByCase, upperFirst } from 'scule'
import { useColorMode } from '#imports'
const router = useRouter()
const appConfig = useAppConfig() const appConfig = useAppConfig()
const colorMode = useColorMode() const router = useRouter()
const isDark = computed({
get() {
return colorMode.value === 'dark'
},
set() {
colorMode.preference = colorMode.value === 'dark' ? 'light' : 'dark'
}
})
const components = [ const components = [
'accordion', 'accordion',
@@ -24,7 +13,6 @@ const components = [
'button', 'button',
'button-group', 'button-group',
'card', 'card',
'calendar',
'carousel', 'carousel',
'checkbox', 'checkbox',
'chip', 'chip',
@@ -37,13 +25,11 @@ const components = [
'form-field', 'form-field',
'input', 'input',
'input-menu', 'input-menu',
'input-number',
'kbd', 'kbd',
'link', 'link',
'modal', 'modal',
'navigation-menu', 'navigation-menu',
'pagination', 'pagination',
'pin-input',
'popover', 'popover',
'progress', 'progress',
'radio-group', 'radio-group',
@@ -84,25 +70,9 @@ defineShortcuts({
<UApp :toaster="appConfig.toaster"> <UApp :toaster="appConfig.toaster">
<div class="h-screen w-screen overflow-hidden flex flex-col lg:flex-row min-h-0 bg-[var(--ui-bg)]" vaul-drawer-wrapper> <div class="h-screen w-screen overflow-hidden flex flex-col lg:flex-row min-h-0 bg-[var(--ui-bg)]" vaul-drawer-wrapper>
<UNavigationMenu :items="items" orientation="vertical" class="hidden lg:flex border-e border-[var(--ui-border)] overflow-y-auto w-48 p-4" /> <UNavigationMenu :items="items" orientation="vertical" class="hidden lg:flex border-e border-[var(--ui-border)] overflow-y-auto w-48 p-4" />
<UNavigationMenu :items="items" orientation="horizontal" class="lg:hidden border-b border-[var(--ui-border)] [&>div]:min-w-min overflow-x-auto" /> <UNavigationMenu :items="items" orientation="horizontal" class="lg:hidden border-b border-[var(--ui-border)] overflow-x-auto" />
<div class="fixed top-15 lg:top-3 right-4 flex items-center gap-2"> <div class="flex-1 flex flex-col items-center justify-around overflow-y-auto w-full py-12 px-4">
<ClientOnly v-if="!colorMode?.forced">
<UButton
:icon="isDark ? 'i-lucide-moon' : 'i-lucide-sun'"
color="neutral"
variant="ghost"
:aria-label="`Switch to ${isDark ? 'light' : 'dark'} mode`"
@click="isDark = !isDark"
/>
<template #fallback>
<div class="size-8" />
</template>
</ClientOnly>
</div>
<div class="flex-1 flex flex-col items-center justify-around overflow-y-auto w-full py-14 px-4">
<NuxtPage /> <NuxtPage />
</div> </div>
@@ -124,7 +94,7 @@ defineShortcuts({
@import "@nuxt/ui"; @import "@nuxt/ui";
@theme { @theme {
--font-sans: 'Public Sans', sans-serif; --font-family-sans: 'Public Sans', sans-serif;
--color-green-50: #EFFDF5; --color-green-50: #EFFDF5;
--color-green-100: #D9FBE8; --color-green-100: #D9FBE8;

View File

@@ -1,20 +0,0 @@
<script setup lang="ts">
import { CalendarDate } from '@internationalized/date'
const singleValue = shallowRef(new CalendarDate(2022, 1, 10))
const multipleValue = shallowRef({
start: new CalendarDate(2022, 1, 10),
end: new CalendarDate(2022, 1, 20)
})
</script>
<template>
<div class="flex flex-col gap-4">
<div class="flex justify-center gap-2">
<UCalendar v-model="singleValue" />
</div>
<div class="flex justify-center gap-2">
<UCalendar v-model="multipleValue" range />
</div>
</div>
</template>

View File

@@ -105,13 +105,13 @@ defineShortcuts(extractShortcuts(items.value))
<USelect v-model="size" :items="sizes" placeholder="Size" /> <USelect v-model="size" :items="sizes" placeholder="Size" />
</div> </div>
<UContextMenu :items="items" :ui="{ content: 'w-48' }" :size="size"> <UContextMenu :items="items" class="min-w-48" :size="size">
<div class="flex items-center justify-center rounded-md border border-dashed border-[var(--ui-border-accented)] text-sm aspect-video w-72"> <div class="flex items-center justify-center rounded-md border border-dashed border-[var(--ui-border-accented)] text-sm aspect-video w-72">
Right click here Right click here
</div> </div>
</UContextMenu> </UContextMenu>
<UContextMenu :items="itemsWithColor" :ui="{ content: 'w-48' }" :size="size"> <UContextMenu :items="itemsWithColor" class="min-w-48" :size="size">
<div class="flex items-center justify-center rounded-md border border-dashed border-[var(--ui-border-accented)] text-sm aspect-video w-72"> <div class="flex items-center justify-center rounded-md border border-dashed border-[var(--ui-border-accented)] text-sm aspect-video w-72">
Color right click here Color right click here
</div> </div>

View File

@@ -140,7 +140,7 @@ defineShortcuts(extractShortcuts(items.value))
<div class="flex flex-col items-center gap-8"> <div class="flex flex-col items-center gap-8">
<USelectMenu v-model="size" :items="sizes" placeholder="Size" /> <USelectMenu v-model="size" :items="sizes" placeholder="Size" />
<UDropdownMenu :items="items" :size="size" arrow :content="{ side: 'bottom', align: 'start' }" :ui="{ content: 'w-48' }"> <UDropdownMenu :items="items" :size="size" arrow :content="{ side: 'bottom', align: 'start' }" class="min-w-48">
<UButton label="Open" color="neutral" variant="outline" icon="i-lucide-menu" /> <UButton label="Open" color="neutral" variant="outline" icon="i-lucide-menu" />
<template #custom-trailing> <template #custom-trailing>
@@ -148,7 +148,7 @@ defineShortcuts(extractShortcuts(items.value))
</template> </template>
</UDropdownMenu> </UDropdownMenu>
<UDropdownMenu :items="itemsWithColor" :size="size" arrow :content="{ side: 'bottom', align: 'start' }" :ui="{ content: 'w-48' }"> <UDropdownMenu :items="itemsWithColor" :size="size" arrow :content="{ side: 'bottom', align: 'start' }" class="min-w-48">
<UButton label="Color" color="neutral" variant="outline" icon="i-lucide-menu" /> <UButton label="Color" color="neutral" variant="outline" icon="i-lucide-menu" />
<template #custom-trailing> <template #custom-trailing>

View File

@@ -1,68 +0,0 @@
<template>
<div class="flex flex-col items-center gap-4">
<div class="flex flex-col gap-4 w-48">
<UInputNumber />
</div>
<div class="flex items-center gap-2">
<UInputNumber
v-for="variant in variants"
:key="variant"
:placeholder="upperFirst(variant)"
:variant="variant"
class="w-48"
/>
</div>
<div class="flex items-center gap-2">
<UInputNumber
v-for="variant in variants"
:key="variant"
:placeholder="upperFirst(variant)"
:variant="variant"
color="neutral"
class="w-48"
/>
</div>
<div class="flex items-center gap-2">
<UInputNumber
v-for="variant in variants"
:key="variant"
:placeholder="upperFirst(variant)"
:variant="variant"
color="error"
highlight
class="w-48"
/>
</div>
<div class="flex flex-col gap-4 w-48">
<UInputNumber placeholder="Disabled" disabled />
<UInputNumber placeholder="Required" required />
</div>
<div class="flex items-center gap-4">
<UInputNumber
v-for="size in sizes"
:key="size"
:size="size"
:placeholder="`Horizontal ${size}`"
class="w-48"
/>
</div>
<div class="flex items-center gap-4">
<UInputNumber
v-for="size in sizes"
:key="size"
:size="size"
class="w-48"
:placeholder="`Vertical ${size}`"
orientation="vertical"
/>
</div>
</div>
</template>
<script setup lang="ts">
import { upperFirst } from 'scule'
import theme from '#build/ui/input-number'
const sizes = Object.keys(theme.variants.size) as Array<keyof typeof theme.variants.size>
const variants = Object.keys(theme.variants.variant) as Array<keyof typeof theme.variants.variant>
</script>

View File

@@ -1,52 +0,0 @@
<script setup lang="ts">
import theme from '#build/ui/pin-input'
const sizes = Object.keys(theme.variants.size) as Array<keyof typeof theme.variants.size>
const variants = Object.keys(theme.variants.variant) as Array<keyof typeof theme.variants.variant>
const onComplete = (e: string[]) => {
alert(e.join(''))
}
</script>
<template>
<div class="flex flex-col items-center gap-4">
<div class="flex gap-4">
<UPinInput placeholder="○" autofocus @complete="onComplete" />
</div>
<div class="flex items-center gap-4">
<UPinInput v-for="variant in variants" :key="variant" placeholder="○" :variant="variant" />
</div>
<div class="flex items-center gap-4">
<UPinInput
v-for="variant in variants"
:key="variant"
placeholder="○"
:variant="variant"
color="neutral"
/>
</div>
<div class="flex items-center gap-4">
<UPinInput
v-for="variant in variants"
:key="variant"
placeholder="○"
:variant="variant"
color="error"
highlight
/>
</div>
<div class="flex flex-col gap-4">
<UPinInput placeholder="○" disabled />
<UPinInput placeholder="○" required />
</div>
<div class="flex items-center gap-4">
<UPinInput
v-for="size in sizes"
:key="size"
placeholder="○"
:size="size"
/>
</div>
</div>
</template>

Some files were not shown because too many files have changed in this diff Show More