Merge branch 'dev' into carousel-dot-buttons

This commit is contained in:
Sadegh Barati 2024-06-24 00:00:15 +03:30
commit 3f2dddfb74
254 changed files with 6593 additions and 4242 deletions

16
.github/actions/setup/action.yml vendored Normal file
View File

@ -0,0 +1,16 @@
name: Setup
description: Installs Node, Enables Corepack and caches pnpm.
runs:
using: composite
steps:
- name: Enable corepack
run: corepack enable
shell: bash
- name: Setup node & pnpm
uses: actions/setup-node@v4
with:
node-version: lts/*
cache: pnpm

View File

@ -48,32 +48,10 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
# Run a build step here
- name: Setup Node.js environment
uses: actions/setup-node@v2
with:
node-version: 18
- uses: pnpm/action-setup@v2
name: Install pnpm
with:
version: 9.0.5
run_install: false
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- uses: actions/cache@v3
name: Setup pnpm cache
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Setup (Install Node & pnpm)
uses: ./.github/actions/setup
- name: Install dependencies
run: pnpm i --frozen-lockfile

View File

@ -14,14 +14,13 @@ jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v3
with:
node-version: 18.x
- name: Setup (Install Node & pnpm)
uses: ./.github/actions/setup
- run: npx changelogithub
- run: pnpm dlx changelogithub
env:
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}

View File

@ -19,31 +19,10 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Setup Node.js environment
uses: actions/setup-node@v2
with:
node-version: 18
- uses: pnpm/action-setup@v2
name: Install pnpm
with:
version: 9.0.5
run_install: false
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- uses: actions/cache@v3
name: Setup pnpm cache
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Setup (Install Node & pnpm)
uses: ./.github/actions/setup
- name: Install dependencies
run: pnpm i --frozen-lockfile

View File

@ -1,5 +1,9 @@
{
"vue.server.hybridMode": true,
"vue.server.includeLanguages": [
"vue",
"markdown"
],
"prettier.enable": false,
"editor.formatOnSave": false,
"editor.codeActionsOnSave": {

View File

@ -3,9 +3,9 @@ import { defineConfig } from 'vitepress'
import Icons from 'unplugin-icons/vite'
import tailwind from 'tailwindcss'
import autoprefixer from 'autoprefixer'
import { transformerMetaWordHighlight } from '@shikijs/transformers'
import { cssVariables } from './theme/config/shiki'
// import { transformerMetaWordHighlight, transformerNotationWordHighlight } from '@shikijs/transformers'
import { siteConfig } from './theme/config/site'
import ComponentPreviewPlugin from './theme/plugins/previewer'
import CodeWrapperPlugin from './theme/plugins/codewrapper'
@ -56,8 +56,7 @@ export default defineConfig({
markdown: {
theme: cssVariables,
codeTransformers: [
// transformerMetaWordHighlight(),
// transformerNotationWordHighlight(),
transformerMetaWordHighlight(),
],
config(md) {
md.use(ComponentPreviewPlugin)
@ -77,7 +76,7 @@ export default defineConfig({
},
},
plugins: [
Icons({ compiler: 'vue3', autoInstall: true }),
Icons({ compiler: 'vue3', autoInstall: true }) as any,
],
resolve: {
alias: {

View File

@ -1,7 +1,8 @@
<script setup lang="ts">
import { ref, watch } from 'vue'
import { computed, ref, watch } from 'vue'
import { codeToHtml } from 'shiki'
import MagicString from 'magic-string'
import { useClipboard } from '@vueuse/core'
import { cssVariables } from '../config/shiki'
import StyleSwitcher from './StyleSwitcher.vue'
import ComponentLoader from './ComponentLoader.vue'
@ -24,6 +25,7 @@ const { style, codeConfig } = useConfigStore()
const rawString = ref('')
const codeHtml = ref('')
const transformedRawString = computed(() => transformImportPath(rawString.value))
function transformImportPath(code: string) {
const s = new MagicString(code)
@ -35,7 +37,7 @@ function transformImportPath(code: string) {
watch([style, codeConfig], async () => {
try {
rawString.value = await import(`../../../src/lib/registry/${style.value}/example/${props.name}.vue?raw`).then(res => res.default.trim())
codeHtml.value = await codeToHtml(transformImportPath(rawString.value), {
codeHtml.value = await codeToHtml(transformedRawString.value, {
lang: 'vue',
theme: cssVariables,
})
@ -44,6 +46,8 @@ watch([style, codeConfig], async () => {
console.error(err)
}
}, { immediate: true, deep: true })
const { copy, copied } = useClipboard()
</script>
<template>
@ -86,8 +90,12 @@ watch([style, codeConfig], async () => {
<ComponentLoader v-bind="$attrs" :key="style" :name="name" :type-name="'example'" />
</div>
</TabsContent>
<TabsContent value="code">
<div v-if="codeHtml" class="language-vue" style="flex: 1;" v-html="codeHtml" />
<TabsContent value="code" class="vp-doc">
<div v-if="codeHtml" class="language-vue" style="flex: 1;">
<button title="Copy Code" class="copy" :class="{ copied }" @click="copy(transformedRawString)" />
<div v-html="codeHtml" />
</div>
<slot v-else />
</TabsContent>
</Tabs>

View File

@ -6,7 +6,6 @@ import {
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbList,
BreadcrumbPage,
BreadcrumbSeparator,
} from '@/lib/registry/new-york/ui/breadcrumb'

View File

@ -35,7 +35,7 @@ const examples = [
},
{
name: 'Forms',
href: '/examples/forms/forms',
href: '/examples/forms',
code: 'https://github.com/radix-vue/shadcn-vue/tree/dev/apps/www/src/examples/forms',
},
{

View File

@ -8,7 +8,6 @@ import Announcement from '../components/Announcement.vue'
import GitHubIcon from '~icons/radix-icons/github-logo'
import { buttonVariants } from '@/lib/registry/new-york/ui/button'
import { Separator } from '@/lib/registry/new-york/ui/separator'
import { cn } from '@/lib/utils'
import MailExample from '@/examples/mail/Example.vue'

View File

@ -5,7 +5,6 @@ import Logo from './Logo.vue'
import { Sheet, SheetContent, SheetTrigger } from '@/lib/registry/default/ui/sheet'
import { Button } from '@/lib/registry/default/ui/button'
import { ScrollArea } from '@/lib/registry/default/ui/scroll-area'
import { Badge } from '@/lib/registry/new-york/ui/badge'
const open = ref(false)
</script>

View File

@ -4,7 +4,7 @@ import { cn } from '@/lib/utils'
</script>
<template>
<WrapBalancer :class="cn('max-w-[750px] text-center text-lg text-muted-foreground sm:text-xl', $attrs.class ?? '')" :prefer-native="false">
<WrapBalancer :class="cn('max-w-[750px] text-center text-lg font-light text-foreground', $attrs.class ?? '')" :prefer-native="false">
<slot />
</WrapBalancer>
</template>

View File

@ -5,7 +5,7 @@ import { cn } from '@/lib/utils'
<template>
<h1
:class="cn(
'text-center text-3xl font-bold leading-tight tracking-tighter md:text-6xl lg:leading-[1.1]',
'text-center text-3xl font-bold leading-tight tracking-tighter md:text-5xl lg:leading-[1.1]',
$attrs.class ?? '',
)"
>

View File

@ -24,7 +24,7 @@ function getHeadingsWithHierarchy(divId: string) {
const level = Number.parseInt(heading.tagName.charAt(1))
if (!heading.id) {
const newId = heading.textContent
.replaceAll(/[^a-zA-Z0-9 ]/g, '')
.replaceAll(/[^a-z0-9 ]/gi, '')
.replaceAll(' ', '-')
.toLowerCase()
heading.id = `${newId}`

View File

@ -32,11 +32,11 @@ export const allColors: Color[] = [
'violet',
]
interface Payment {
status: string
email: string
amount: number
}
// interface Payment {
// status: string
// email: string
// amount: number
// }
interface TeamMember {
name: string

View File

@ -256,12 +256,17 @@ export const docsConfig: DocsConfig = {
title: 'Navigation Menu',
href: '/docs/components/navigation-menu',
},
{
title: 'Number Field',
href: '/docs/components/number-field',
label: 'New Alpha',
},
{
title: 'Pagination',
href: '/docs/components/pagination',
},
{
title: 'Pin Input',
title: 'PIN Input',
href: '/docs/components/pin-input',
items: [],
},

View File

@ -7,7 +7,6 @@ import DocsBreadcrumb from '../components/DocsBreadcrumb.vue'
import { ScrollArea } from '@/lib/registry/default/ui/scroll-area'
import RadixIconsCode from '~icons/radix-icons/code'
import RadixIconsExternalLink from '~icons/radix-icons/external-link'
import ChevronRightIcon from '~icons/lucide/chevron-right'
const $route = useRoute()
const { frontmatter } = useData()

View File

@ -7,7 +7,6 @@ import ExamplesNav from '../components/ExamplesNav.vue'
import Announcement from '../components/Announcement.vue'
import { buttonVariants } from '@/lib/registry/new-york/ui/button'
import { Separator } from '@/lib/registry/new-york/ui/separator'
import { cn } from '@/lib/utils'
</script>

View File

@ -303,7 +303,7 @@ watch(() => $route.path, (n) => {
</DialogContent>
</Dialog>
<DefaultToaster />
<NewYorkSonner :theme="'system'" />
<NewYorkSonner class="pointer-events-auto" :theme="'system'" />
<NewYorkToaster />
</div>
</TooltipProvider>

View File

@ -167,12 +167,20 @@ pre code {
@apply relative font-mono text-sm ;
}
.line-numbers-wrapper, code {
--vp-code-line-height: 1.7;
}
.line-numbers-wrapper {
@apply font-mono;
}
pre code .line {
@apply px-4 min-h-6 !py-0.5 w-full inline-block;
@apply px-4 min-h-4 !py-0.5 w-full inline-block leading-[--vp-code-line-height];
}
.line-number {
@apply min-h-[1.375rem] !text-sm !inline-block text-muted-foreground;
@apply !text-[.75rem] !inline-block text-muted-foreground leading-[--vp-code-line-height];
}
::view-transition-old(root),

View File

@ -352,7 +352,7 @@
display: inline-block;
@apply bg-[hsl(var(--foreground))] dark:bg-[hsl(var(--background)_/_50%)]
}
hsl(var(--foreground) / 50%)
.vp-doc [class*='language-'] code .highlighted.error {
background-color: var(--vp-code-line-error-color);
}

View File

@ -2,7 +2,9 @@ import { getParameters } from 'codesandbox/lib/api/define'
import sdk from '@stackblitz/sdk'
import { dependencies as deps } from '../../../package.json'
import { Index as demoIndex } from '../../../../www/__registry__'
// @ts-expect-error ?raw
import tailwindConfigRaw from '../../../tailwind.config?raw'
// @ts-expect-error ?raw
import cssRaw from '../../../../../packages/cli/test/fixtures/nuxt/assets/css/tailwind.css?raw'
import type { Style } from '@/lib/registry/styles'
@ -35,7 +37,15 @@ const viteConfig = {
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import tailwind from 'tailwindcss';
import autoprefixer from 'autoprefixer';
export default defineConfig({
css: {
postcss: {
plugins: [tailwind(), autoprefixer()],
},
},
plugins: [vue()],
resolve: {
alias: {
@ -102,7 +112,6 @@ function constructFiles(componentName: string, style: Style, sources: Record<str
'@vitejs/plugin-vue': 'latest',
'vue-tsc': 'latest',
'tailwindcss': 'latest',
'postcss': 'latest',
'autoprefixer': 'latest',
}
@ -145,15 +154,6 @@ function constructFiles(componentName: string, style: Style, sources: Record<str
content: tailwindConfigRaw,
isBinary: false,
},
'postcss.config.js': {
content: `module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
}
}`,
isBinary: false,
},
'tsconfig.json': {
content: `{
"$schema": "https://json.schemastore.org/tsconfig",

View File

@ -759,6 +759,48 @@ export const Index = {
component: () => import("../src/lib/registry/default/example/NavigationMenuDemoItem.vue").then((m) => m.default),
files: ["../src/lib/registry/default/example/NavigationMenuDemoItem.vue"],
},
"NumberFieldCurrency": {
name: "NumberFieldCurrency",
type: "components:example",
registryDependencies: ["number-field","label"],
component: () => import("../src/lib/registry/default/example/NumberFieldCurrency.vue").then((m) => m.default),
files: ["../src/lib/registry/default/example/NumberFieldCurrency.vue"],
},
"NumberFieldDecimal": {
name: "NumberFieldDecimal",
type: "components:example",
registryDependencies: ["number-field","label"],
component: () => import("../src/lib/registry/default/example/NumberFieldDecimal.vue").then((m) => m.default),
files: ["../src/lib/registry/default/example/NumberFieldDecimal.vue"],
},
"NumberFieldDemo": {
name: "NumberFieldDemo",
type: "components:example",
registryDependencies: ["number-field","label"],
component: () => import("../src/lib/registry/default/example/NumberFieldDemo.vue").then((m) => m.default),
files: ["../src/lib/registry/default/example/NumberFieldDemo.vue"],
},
"NumberFieldDisabled": {
name: "NumberFieldDisabled",
type: "components:example",
registryDependencies: ["number-field","label"],
component: () => import("../src/lib/registry/default/example/NumberFieldDisabled.vue").then((m) => m.default),
files: ["../src/lib/registry/default/example/NumberFieldDisabled.vue"],
},
"NumberFieldForm": {
name: "NumberFieldForm",
type: "components:example",
registryDependencies: ["button","form","number-field","toast"],
component: () => import("../src/lib/registry/default/example/NumberFieldForm.vue").then((m) => m.default),
files: ["../src/lib/registry/default/example/NumberFieldForm.vue"],
},
"NumberFieldPercentage": {
name: "NumberFieldPercentage",
type: "components:example",
registryDependencies: ["number-field","label"],
component: () => import("../src/lib/registry/default/example/NumberFieldPercentage.vue").then((m) => m.default),
files: ["../src/lib/registry/default/example/NumberFieldPercentage.vue"],
},
"PaginationDemo": {
name: "PaginationDemo",
type: "components:example",
@ -948,6 +990,13 @@ export const Index = {
component: () => import("../src/lib/registry/default/example/SonnerDemo.vue").then((m) => m.default),
files: ["../src/lib/registry/default/example/SonnerDemo.vue"],
},
"SonnerWithDialog": {
name: "SonnerWithDialog",
type: "components:example",
registryDependencies: ["button","dialog"],
component: () => import("../src/lib/registry/default/example/SonnerWithDialog.vue").then((m) => m.default),
files: ["../src/lib/registry/default/example/SonnerWithDialog.vue"],
},
"SwitchDemo": {
name: "SwitchDemo",
type: "components:example",
@ -1308,7 +1357,7 @@ export const Index = {
"ActivityGoal": {
name: "ActivityGoal",
type: "components:example",
registryDependencies: ["button","card","themes","config"],
registryDependencies: ["button","card"],
component: () => import("../src/lib/registry/default/example/Cards/ActivityGoal.vue").then((m) => m.default),
files: ["../src/lib/registry/default/example/Cards/ActivityGoal.vue"],
},
@ -1322,7 +1371,7 @@ export const Index = {
"Metric": {
name: "Metric",
type: "components:example",
registryDependencies: ["card","config"],
registryDependencies: ["card"],
component: () => import("../src/lib/registry/default/example/Cards/Metric.vue").then((m) => m.default),
files: ["../src/lib/registry/default/example/Cards/Metric.vue"],
},
@ -2160,6 +2209,48 @@ export const Index = {
component: () => import("../src/lib/registry/new-york/example/NavigationMenuDemoItem.vue").then((m) => m.default),
files: ["../src/lib/registry/new-york/example/NavigationMenuDemoItem.vue"],
},
"NumberFieldCurrency": {
name: "NumberFieldCurrency",
type: "components:example",
registryDependencies: ["number-field","label"],
component: () => import("../src/lib/registry/new-york/example/NumberFieldCurrency.vue").then((m) => m.default),
files: ["../src/lib/registry/new-york/example/NumberFieldCurrency.vue"],
},
"NumberFieldDecimal": {
name: "NumberFieldDecimal",
type: "components:example",
registryDependencies: ["number-field","label"],
component: () => import("../src/lib/registry/new-york/example/NumberFieldDecimal.vue").then((m) => m.default),
files: ["../src/lib/registry/new-york/example/NumberFieldDecimal.vue"],
},
"NumberFieldDemo": {
name: "NumberFieldDemo",
type: "components:example",
registryDependencies: ["number-field","label"],
component: () => import("../src/lib/registry/new-york/example/NumberFieldDemo.vue").then((m) => m.default),
files: ["../src/lib/registry/new-york/example/NumberFieldDemo.vue"],
},
"NumberFieldDisabled": {
name: "NumberFieldDisabled",
type: "components:example",
registryDependencies: ["number-field","label"],
component: () => import("../src/lib/registry/new-york/example/NumberFieldDisabled.vue").then((m) => m.default),
files: ["../src/lib/registry/new-york/example/NumberFieldDisabled.vue"],
},
"NumberFieldForm": {
name: "NumberFieldForm",
type: "components:example",
registryDependencies: ["button","form","number-field","toast"],
component: () => import("../src/lib/registry/new-york/example/NumberFieldForm.vue").then((m) => m.default),
files: ["../src/lib/registry/new-york/example/NumberFieldForm.vue"],
},
"NumberFieldPercentage": {
name: "NumberFieldPercentage",
type: "components:example",
registryDependencies: ["number-field","label"],
component: () => import("../src/lib/registry/new-york/example/NumberFieldPercentage.vue").then((m) => m.default),
files: ["../src/lib/registry/new-york/example/NumberFieldPercentage.vue"],
},
"PaginationDemo": {
name: "PaginationDemo",
type: "components:example",
@ -2349,6 +2440,13 @@ export const Index = {
component: () => import("../src/lib/registry/new-york/example/SonnerDemo.vue").then((m) => m.default),
files: ["../src/lib/registry/new-york/example/SonnerDemo.vue"],
},
"SonnerWithDialog": {
name: "SonnerWithDialog",
type: "components:example",
registryDependencies: ["button","dialog"],
component: () => import("../src/lib/registry/new-york/example/SonnerWithDialog.vue").then((m) => m.default),
files: ["../src/lib/registry/new-york/example/SonnerWithDialog.vue"],
},
"SwitchDemo": {
name: "SwitchDemo",
type: "components:example",
@ -2709,7 +2807,7 @@ export const Index = {
"ActivityGoal": {
name: "ActivityGoal",
type: "components:example",
registryDependencies: ["button","card","themes","config"],
registryDependencies: ["button","card"],
component: () => import("../src/lib/registry/new-york/example/Cards/ActivityGoal.vue").then((m) => m.default),
files: ["../src/lib/registry/new-york/example/Cards/ActivityGoal.vue"],
},
@ -2723,7 +2821,7 @@ export const Index = {
"Metric": {
name: "Metric",
type: "components:example",
registryDependencies: ["card","config"],
registryDependencies: ["card"],
component: () => import("../src/lib/registry/new-york/example/Cards/Metric.vue").then((m) => m.default),
files: ["../src/lib/registry/new-york/example/Cards/Metric.vue"],
},

View File

@ -1,7 +1,7 @@
{
"name": "www",
"type": "module",
"version": "0.10.4",
"version": "0.10.5",
"files": [
"dist"
],
@ -17,66 +17,65 @@
},
"dependencies": {
"@formkit/auto-animate": "^0.8.2",
"@internationalized/date": "^3.5.2",
"@internationalized/date": "^3.5.4",
"@radix-icons/vue": "^1.0.0",
"@stackblitz/sdk": "^1.9.0",
"@tanstack/vue-table": "^8.16.0",
"@unovis/ts": "^1.4.0",
"@unovis/vue": "^1.4.0",
"@vee-validate/zod": "^4.12.6",
"@vueuse/core": "^10.9.0",
"@stackblitz/sdk": "^1.10.0",
"@tanstack/vue-table": "^8.17.3",
"@unovis/ts": "^1.4.1",
"@unovis/vue": "^1.4.1",
"@vee-validate/zod": "^4.13.1",
"@vueuse/core": "^10.11.0",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"codesandbox": "^2.2.3",
"date-fns": "^3.6.0",
"embla-carousel": "^8.0.2",
"embla-carousel-autoplay": "^8.0.2",
"embla-carousel-vue": "^8.0.2",
"lucide-vue-next": "^0.359.0",
"embla-carousel-autoplay": "^8.1.5",
"embla-carousel-vue": "^8.1.5",
"lucide-vue-next": "^0.383.0",
"magic-string": "^0.30.10",
"radix-vue": "^1.7.2",
"radix-vue": "^1.8.4",
"tailwindcss-animate": "^1.0.7",
"v-calendar": "^3.1.2",
"vaul-vue": "^0.1.0",
"vee-validate": "4.12.6",
"vue": "^3.4.24",
"vaul-vue": "^0.2.0",
"vee-validate": "4.13.1",
"vue": "^3.4.29",
"vue-sonner": "^1.1.2",
"vue-wrap-balancer": "^1.1.3",
"zod": "^3.23.3"
"zod": "^3.23.8"
},
"devDependencies": {
"@babel/traverse": "^7.24.1",
"@iconify-json/gravity-ui": "^1.1.2",
"@iconify-json/lucide": "^1.1.180",
"@iconify-json/ph": "^1.1.12",
"@babel/traverse": "^7.24.7",
"@iconify-json/gravity-ui": "^1.1.3",
"@iconify-json/lucide": "^1.1.190",
"@iconify-json/ph": "^1.1.13",
"@iconify-json/radix-icons": "^1.1.14",
"@iconify-json/ri": "^1.1.18",
"@iconify-json/simple-icons": "^1.1.94",
"@iconify-json/tabler": "^1.1.106",
"@iconify-json/ri": "^1.1.20",
"@iconify-json/simple-icons": "^1.1.104",
"@iconify-json/tabler": "^1.1.113",
"@iconify/vue": "^4.1.2",
"@oxc-parser/wasm": "^0.1.0",
"@shikijs/transformers": "^1.3.0",
"@oxc-parser/wasm": "^0.14.0",
"@shikijs/transformers": "^1.7.0",
"@types/lodash-es": "^4.17.12",
"@types/node": "^20.12.7",
"@vitejs/plugin-vue": "^5.0.4",
"@vitejs/plugin-vue-jsx": "^3.1.0",
"@vue/compiler-core": "^3.4.24",
"@vue/compiler-dom": "^3.4.24",
"@types/node": "^20.14.4",
"@vitejs/plugin-vue": "^5.0.5",
"@vitejs/plugin-vue-jsx": "^4.0.0",
"@vue/compiler-core": "^3.4.29",
"@vue/compiler-dom": "^3.4.29",
"@vue/tsconfig": "^0.5.1",
"autoprefixer": "^10.4.19",
"fast-glob": "^3.3.2",
"lodash-es": "^4.17.21",
"markdown-it": "^14.1.0",
"pathe": "^1.1.2",
"rimraf": "^5.0.5",
"shiki": "^1.3.0",
"rimraf": "^5.0.7",
"shiki": "^1.7.0",
"tailwind-merge": "^2.3.0",
"tailwindcss": "^3.4.3",
"tsx": "^4.7.2",
"tailwindcss": "^3.4.4",
"tsx": "^4.15.6",
"typescript": "^5.4.5",
"unplugin-icons": "^0.18.5",
"vitepress": "^1.1.3",
"vue-component-meta": "^2.0.13",
"vue-tsc": "^2.0.14"
"unplugin-icons": "^0.19.0",
"vitepress": "^1.2.3",
"vue-component-meta": "^2.0.21",
"vue-tsc": "^2.0.21"
}
}

View File

@ -282,7 +282,7 @@ for (const baseColor of ['slate', 'gray', 'zinc', 'neutral', 'stone', 'lime']) {
for (const [key, value] of Object.entries(values)) {
if (typeof value === 'string') {
const resolvedColor = value.replace(
/{{base}}-/g,
/\{\{base\}\}-/g,
`${baseColor}-`,
)
base.inlineColors[mode][key] = resolvedColor

10
apps/www/src/components.d.ts vendored Normal file
View File

@ -0,0 +1,10 @@
/* eslint-disable */
// @ts-nocheck
export {}
/* prettier-ignore */
declare module 'vue' {
export interface GlobalComponents {
ComponentPreview: typeof import('../.vitepress/theme/components/ComponentPreview.vue')['default']
}
}

View File

@ -1,3 +1,139 @@
---
title: Changelog
description: Latest updates and announcements.
---
## June 2024
### New Component - Number Field
A new component has been added to the project [`NumberField`](/docs/components/number-field.html).
A number field allows a user to enter a number and increment or decrement the value using stepper buttons.
<ComponentPreview name="NumberFieldDemo" class="max-w-[180px]" />
## May 2024
### New Component - Charts
Several kinds of chart components has been added to the project.
Charts are versatile visualization tools, allowing users to represent data using various options for effective analysis.
1. [`Area Chart`](/docs/charts/area) - An area chart visually represents data over time, displaying trends and patterns through filled-in areas under a line graph.
<ComponentPreview name="AreaChartDemo" />
2. [`Bar Chart`](/docs/charts/bar) - A line chart visually represents data using rectangular bars of varying lengths to compare quantities across different categories or groups.
<ComponentPreview name="BarChartDemo" />
3. [`Donut Chart`](/docs/charts/donut) - A line chart visually represents data in a circular form, similar to a pie chart but with a central void, emphasizing proportions within categories.
<ComponentPreview name="DonutChartDemo" />
4. [`Line Chart`](/docs/charts/line) - A line chart visually displays data points connected by straight lines, illustrating trends or relationships over a continuous axis.
<ComponentPreview name="LineChartDemo" />
### New Component - Auto Form
[`Auto Form`](/docs/components/auto-form.html) is a drop-in form builder for your internal and low-priority forms with existing zod schemas.
For example, if you already have zod schemas for your API and want to create a simple admin panel to edit user profiles, simply pass the schema to AutoForm and you're done.
The following form has been created by passing a `zod` schema object to our `AutoForm` component.
<ComponentPreview name="AutoFormBasic" />
## April 2024
### Component Updated - Calendar
The [`Calendar`](/docs/components/calendar.html) component has been updated and is now built on top of the [RadixVue Calendar](https://www.radix-vue.com/components/calendar.html) component, which uses the [@internationalized/date](https://react-spectrum.adobe.com/internationalized/date/index.html) package to handle dates.
If you're looking for a range calendar, check out the [`Range Calendar`](/docs/components/range-calendar.html) component.
And if you're looking for a date picker input, check out the [`Date Picker`](/docs/components/date-picker.html) component.
<ComponentPreview name="CalendarDemo" />
<ComponentPreview name="RangeCalendarDemo" />
<ComponentPreview name="DatePickerDemo" />
### Building Blocks for the Web
[`Blocks`](/blocks) are composed of different components that can be used to build your apps, with each block being a standalone section of your application. These blocks are fully responsive, accessible, and composable, and are built using the same principles as the other components in `shadcn-vue`.
<div>
<image
src="/examples/block-dark.png"
:width="1280"
:height="727"
alt="Building Blocks"
class="hidden dark:block"
/>
<image
src="/examples/block-light.png"
:width="1280"
:height="727"
alt="Building Blocks"
class="block dark:hidden"
/>
</div>
## March 2024
### New Component - Breadcrumb
[`Breadcrumb`](/docs/components/breadcrumb.html) displays the path to the current resource using a hierarchy of links.
<ComponentPreview name="BreadcrumbDemo" />
### New Component - Pin Input (OTP Input)
[`Pin Input`](/docs/components/pin-input.html) allows users to input a sequence of one-character alphanumeric inputs.
<ComponentPreview name="PinInputDemo" />
### New Component - Resizable
[`Resizable`](/docs/components/resizable.html) - Accessible resizable panel groups and layouts with keyboard support.
<ComponentPreview name="ResizableDemo" />
### New Component - Drawer
[`Drawer`](/docs/components/drawer.html) - A drawer component for vue that is built on top of [Vaul Vue](https://github.com/radix-vue/vaul-vue).
<ComponentPreview name="DrawerDemo" />
## February 2024
### New Component - Tag Inputs
[`Tag inputs`](/docs/components/tags-input.html) render tags inside an input, followed by an actual text input.
<ComponentPreview name="TagsInputDemo" />
## January 2024
### New Component - Sonner
[`Sonner`](/docs/components/sonner.html) is an opinionated toast component for Vue.
The Sonner component is provided by [vue-sonner](https://vue-sonner.vercel.app/), which is a Vue port of Sonner, originally created by [Emil Kowalski](https://twitter.com/emilkowalski_) for React.
<ComponentPreview name="SonnerDemo" />
### New Component - Toggle Group
[`Toggle Group`](/docs/components/toggle-group.html) - A set of two-state buttons that can be toggled on or off.
<ComponentPreview name="ToggleGroupDemo" />
### New Component - Carousel
[`Carousel`](/docs/components/toggle-group.html) - A carousel with motion and swipe built using [Embla](https://www.embla-carousel.com/) library.
<ComponentPreview name="CarouselDemo" />

View File

@ -1,6 +1,6 @@
---
title: Bar
description: An line chart visually represents data using rectangular bars of varying lengths to compare quantities across different categories or groups.
description: A line chart visually represents data using rectangular bars of varying lengths to compare quantities across different categories or groups.
source: apps/www/src/lib/registry/default/ui/chart-bar
label: Alpha
---

View File

@ -1,6 +1,6 @@
---
title: Donut
description: An line chart visually represents data in a circular form, similar to a pie chart but with a central void, emphasizing proportions within categories.
description: A line chart visually represents data in a circular form, similar to a pie chart but with a central void, emphasizing proportions within categories.
source: apps/www/src/lib/registry/default/ui/chart-donut
label: Alpha
---

View File

@ -1,6 +1,6 @@
---
title: Line
description: An line chart visually displays data points connected by straight lines, illustrating trends or relationships over a continuous axis.
description: A line chart visually displays data points connected by straight lines, illustrating trends or relationships over a continuous axis.
source: apps/www/src/lib/registry/default/ui/chart-line
label: Alpha
---

View File

@ -414,9 +414,7 @@ const form = useForm({
validationSchema: toTypedSchema(schema),
})
form.setValues({
username: 'foo'
})
form.setFieldValue('username', 'bar')
</script>
<template>

View File

@ -22,7 +22,7 @@ import {
BreadcrumbList,
BreadcrumbPage,
BreadcrumbSeparator,
} from '@/lib/components/ui/breadcrumb'
} from '@/components/ui/breadcrumb'
</script>
<template>
@ -65,7 +65,7 @@ import {
BreadcrumbLink,
BreadcrumbList,
BreadcrumbSeparator,
} from '@/lib/components/ui/breadcrumb'
} from '@/components/ui/breadcrumb'
</script>
<template>
@ -106,7 +106,7 @@ import {
DropdownMenuTrigger,
} from '@/lib/components/ui/dropdown-menu'
import { BreadcrumbItem } from '@/lib/components/ui/breadcrumb'
import { BreadcrumbItem } from '@/components/ui/breadcrumb'
import ChevronDownIcon from '~icons/radix-icons/chevron-down'
</script>
@ -143,7 +143,7 @@ import {
BreadcrumbEllipsis,
BreadcrumbItem,
BreadcrumbList,
} from '@/lib/components/ui/breadcrumb'
} from '@/components/ui/breadcrumb'
</script>
<template>
@ -175,7 +175,7 @@ import {
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbList,
} from '@/lib/components/ui/breadcrumb'
} from '@/components/ui/breadcrumb'
</script>
<template>

View File

@ -44,7 +44,7 @@ import {
const frameworks = [
{ value: 'next.js', label: 'Next.js' },
{ value: 'sveltekit', label: 'SvelteKit' },
{ value: 'nuxt.js', label: 'Nuxt.js' },
{ value: 'nuxt', label: 'Nuxt' },
{ value: 'remix', label: 'Remix' },
{ value: 'astro', label: 'Astro' },
]

View File

@ -101,7 +101,7 @@ watch(CmdJ, (v) => {
<span class="text-xs"></span>J
</kbd>
</p>
<CommandDialog :open="open" :on-open-change="handleOpenChange">
<CommandDialog :open="open" @update:open="handleOpenChange">
<CommandInput placeholder="Type a command or search..." />
<CommandList>
<CommandEmpty>No results found.</CommandEmpty>

View File

@ -97,7 +97,7 @@ Start by creating the following file structure:
└── app.vue
```
I'm using a Nuxt.js example here but this works for any other Vue framework.
I'm using a Nuxt example here but this works for any other Vue framework.
- `columns.ts` It will contain our column definitions.
- `data-table.vue` It will contain our `<DataTable />` component.
@ -114,7 +114,7 @@ Let's start by building a basic table.
First, we'll define our columns in the `columns.ts` file.
```ts:line-numbers {1,12-27}
```ts:line-numbers
import { h } from 'vue'
export const columns: ColumnDef<Payment>[] = [
@ -146,14 +146,14 @@ formatted, sorted and filtered.
Next, we'll create a `<DataTable />` component to render our table.
```vue:line-numbers
```vue
<script setup lang="ts" generic="TData, TValue">
import type { ColumnDef } from '@tanstack/vue-table'
import {
FlexRender,
getCoreRowModel,
useVueTable,
} from "@tanstack/vue-table"
} from '@tanstack/vue-table'
import {
Table,
@ -162,7 +162,7 @@ import {
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table"
} from '@/components/ui/table'
const props = defineProps<{
columns: ColumnDef<TData, TValue>[]
@ -182,15 +182,19 @@ const table = useVueTable({
<TableHeader>
<TableRow v-for="headerGroup in table.getHeaderGroups()" :key="headerGroup.id">
<TableHead v-for="header in headerGroup.headers" :key="header.id">
<FlexRender v-if="!header.isPlaceholder" :render="header.column.columnDef.header"
:props="header.getContext()" />
<FlexRender
v-if="!header.isPlaceholder" :render="header.column.columnDef.header"
:props="header.getContext()"
/>
</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<template v-if="table.getRowModel().rows?.length">
<TableRow v-for="row in table.getRowModel().rows" :key="row.id"
:data-state="row.getIsSelected() ? 'selected' : undefined">
<TableRow
v-for="row in table.getRowModel().rows" :key="row.id"
:data-state="row.getIsSelected() ? 'selected' : undefined"
>
<TableCell v-for="cell in row.getVisibleCells()" :key="cell.id">
<FlexRender :render="cell.column.columnDef.cell" :props="cell.getContext()" />
</TableCell>
@ -198,7 +202,7 @@ const table = useVueTable({
</template>
<template v-else>
<TableRow>
<TableCell :colSpan="columns.length" class="h-24 text-center">
<TableCell :colspan="columns.length" class="h-24 text-center">
No results.
</TableCell>
</TableRow>
@ -221,12 +225,12 @@ const table = useVueTable({
Finally, we'll render our table in our index component.
```vue:line-numbers {28}
```vue
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { columns } from "./components/columns"
import type { Payment } from './components/columns';
import DataTable from "./components/DataTable.vue"
import { onMounted, ref } from 'vue'
import { columns } from './components/columns'
import type { Payment } from './components/columns'
import DataTable from './components/DataTable.vue'
const data = ref<Payment[]>([])
@ -234,18 +238,18 @@ async function getData(): Promise<Payment[]> {
// Fetch data from your API here.
return [
{
id: "728ed52f",
id: '728ed52f',
amount: 100,
status: "pending",
email: "m@example.com",
status: 'pending',
email: 'm@example.com',
},
// ...
]
}
onMounted(async () => {
data.value = await getData();
});
data.value = await getData()
})
</script>
<template>
@ -267,18 +271,18 @@ Let's format the amount cell to display the dollar amount. We'll also align the
Update the `header` and `cell` definitions for amount as follows:
```ts:line-numbers title="components/payments/columns.ts" {5-17}
```ts
import { h } from 'vue'
export const columns: ColumnDef<Payment>[] = [
{
accessorKey: "amount",
accessorKey: 'amount',
header: () => h('div', { class: 'text-right' }, 'Amount'),
cell: ({ row }) => {
const amount = parseFloat(row.getValue("amount"))
const formatted = new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
const amount = Number.parseFloat(row.getValue('amount'))
const formatted = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
}).format(amount)
return h('div', { class: 'text-right font-medium' }, formatted)
@ -295,10 +299,9 @@ Let's add row actions to our table. We'll use a `<Dropdown />` component for thi
<Steps>
### Add the following into your `DataTableDropDown.vue` component:
### Add the following into your `DataTableDropDown.vue` component
```vue:line-numbers
// DataTableDropDown.vue
```vue
<script setup lang="ts">
import { MoreHorizontal } from 'lucide-vue-next'
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger } from '@/components/ui/dropdown-menu'
@ -334,15 +337,14 @@ function copy(id: string) {
</DropdownMenuContent>
</DropdownMenu>
</template>
```
### Update columns definition
Update our columns definition to add a new `actions` column. The `actions` cell returns a `<Dropdown />` component.
```ts:line-numbers showLineNumber{2,6-16}
import { ColumnDef } from "@tanstack/vue-table"
```ts
import { ColumnDef } from '@tanstack/vue-table'
import DropdownAction from '@/components/DataTableDropDown.vue'
export const columns: ColumnDef<Payment>[] = [
@ -359,7 +361,6 @@ export const columns: ColumnDef<Payment>[] = [
},
},
]
```
You can access the row data using `row.original` in the `cell` function. Use this to handle actions for your row eg. use the `id` to make a DELETE call to your API.
@ -396,9 +397,9 @@ This will automatically paginate your rows into pages of 10. See the [pagination
We can add pagination controls to our table using the `<Button />` component and the `table.previousPage()`, `table.nextPage()` API methods.
```vue:line-numbers {3,15,21-39}
```vue
<script lang="ts" generic="TData, TValue">
import { Button } from "@/components/ui/button"
import { Button } from '@/components/ui/button'
const table = useVueTable({
get data() { return props.data },
@ -406,7 +407,6 @@ const table = useVueTable({
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
})
</script>
<template>
@ -436,7 +436,6 @@ const table = useVueTable({
</div>
</div>
</template>
```
See [Reusable Components](#reusable-components) section for a more advanced pagination component.
@ -449,22 +448,21 @@ Let's make the email column sortable.
<Steps>
### Add the following into your `utils` file:
### Add the following into your `utils` file
```ts:line-numbers {5,6,12-17}
```ts
import { type ClassValue, clsx } from 'clsx'
import { twMerge } from 'tailwind-merge'
import type { Updater } from '@tanstack/vue-table'
import { type Ref } from 'vue'
import type { Ref } from 'vue'
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}
export function valueUpdater<T extends Updater<any>>(updaterOrValue: T, ref: Ref) {
ref.value
= typeof updaterOrValue === 'function'
ref.value = typeof updaterOrValue === 'function'
? updaterOrValue(ref.value)
: updaterOrValue
}
@ -474,15 +472,13 @@ The `valueUpdater` function updates a Vue `ref` object's value. It handles both
### Update `<DataTable>`
```vue:line-numbers {4,7,16,34,41-44}
```vue:line-numbers {4,14,17,33,40-44}
<script setup lang="ts" generic="TData, TValue">
import type {
ColumnDef,
SortingState,
} from '@tanstack/vue-table'
import { valueUpdater } from '@/lib/utils'
import { ArrowUpDown, ChevronDown } from 'lucide-vue-next'
import { h, ref } from 'vue'
@ -492,7 +488,8 @@ import {
getPaginationRowModel,
getSortedRowModel,
useVueTable,
} from "@tanstack/vue-table"
} from '@tanstack/vue-table'
import { valueUpdater } from '@/lib/utils'
import {
Table,
@ -501,7 +498,7 @@ import {
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table"
} from '@/components/ui/table'
const props = defineProps<{
columns: ColumnDef<TData, TValue>[]
@ -521,7 +518,6 @@ const table = useVueTable({
get sorting() { return sorting.value },
},
})
</script>
<template>

View File

@ -47,7 +47,7 @@ import {
### Link Component
When using the Nuxt.js `<NuxtLink />` component, you can use `navigationMenuTriggerStyle()` to apply the correct styles to the trigger.
When using the Nuxt `<NuxtLink />` component, you can use `navigationMenuTriggerStyle()` to apply the correct styles to the trigger.
```ts
import { navigationMenuTriggerStyle } from '@/components/ui/navigation-menu'

View File

@ -0,0 +1,71 @@
---
title: Number Field
description: A number field allows a user to enter a number and increment or decrement the value using stepper buttons.
source: apps/www/src/lib/registry/default/ui/number-field
primitive: https://www.radix-vue.com/components/number-field.html
---
<ComponentPreview name="NumberFieldDemo" class="max-w-[180px]" />
## Installation
<TabPreview name="CLI">
<template #CLI>
```bash
npx shadcn-vue@latest add number-field
```
</template>
</TabPreview>
## Usage
```vue
<script setup lang="ts">
import {
NumberField,
NumberFieldContent,
NumberFieldDecrement,
NumberFieldIncrement,
NumberFieldInput,
} from '@/lib/registry/default/ui/number-field'
import { Label } from '@/lib/registry/default/ui/label'
</script>
<template>
<NumberField>
<Label>Age</Label>
<NumberFieldContent>
<NumberFieldDecrement />
<NumberFieldInput />
<NumberFieldIncrement />
</NumberFieldContent>
</NumberField>
</template>
```
## Examples
### Default
<ComponentPreview name="NumberFieldDemo" class="max-w-[180px]" />
### Disabled
<ComponentPreview name="NumberFieldDisabled" class="max-w-[180px]" />
### Decimal
<ComponentPreview name="NumberFieldDecimal" class="max-w-[180px]" />
### Percentage
<ComponentPreview name="NumberFieldPercentage" class="max-w-[180px]" />
### Currency
<ComponentPreview name="NumberFieldCurrency" class="max-w-[220px]" />
### Form
<ComponentPreview name="NumberFieldForm" class="max-w-xs" />

View File

@ -44,6 +44,6 @@ import { Separator } from '@/components/ui/separator'
</script>
<template>
<Separator />
<Separator label="Or" />
</template>
```

View File

@ -32,7 +32,7 @@ import {
<SheetTrigger>Open</SheetTrigger>
<SheetContent>
<SheetHeader>
<SheetTitle>Are you sure absolutely sure?</SheetTitle>
<SheetTitle>Are you absolutely sure?</SheetTitle>
<SheetDescription>
This action cannot be undone. This will permanently delete your account
and remove your data from our servers.
@ -61,7 +61,7 @@ You can adjust the size of the sheet using CSS classes:
<SheetTrigger>Open</SheetTrigger>
<SheetContent class="w-[400px] sm:w-[540px]">
<SheetHeader>
<SheetTitle>Are you sure absolutely sure?</SheetTitle>
<SheetTitle>Are you absolutely sure?</SheetTitle>
<SheetDescription>
This action cannot be undone. This will permanently delete your account
and remove your data from our servers.

View File

@ -61,3 +61,23 @@ import { Button } from '@/components/ui/button'
</Button>
</template>
```
## Examples
### Sonner with Dialog
Related issue https://github.com/radix-vue/shadcn-vue/issues/462
Add `pointer-events-auto` class to Toaster component in your `App.vue` file:
```vue {6}
<script setup lang="ts">
import { Toaster } from '@/components/ui/sonner'
</script>
<template>
<Toaster class="pointer-events-auto" />
</template>
```
<ComponentPreview name="SonnerWithDialog" />

View File

@ -104,6 +104,7 @@ Would you like to use TypeScript (recommended)? no / yes
Which framework are you using? Astro
Which style would you like to use? Default
Which color would you like to use as base color? Slate
Where is your tsconfig.json or jsconfig.json file? ./tsconfig.json
Where is your global CSS file? src/styles/globals.css
Do you want to use CSS variables for colors? no / yes
Where is your tailwind.config located? tailwind.config.mjs

View File

@ -30,11 +30,13 @@ Would you like to use TypeScript (recommended)? no / yes
Which framework are you using? Vite / Nuxt / Laravel
Which style would you like to use? Default
Which color would you like to use as base color? Slate
Where is your tsconfig.json or jsconfig.json file? ./tsconfig.json
Where is your global CSS file? resources/css/app.css
Do you want to use CSS variables for colors? no / yes
Where is your tailwind.config.js located? tailwind.config.js
Configure the import alias for components: @/Components
Configure the import alias for utils: @/lib/utils
Write configuration to components.json. Proceed? > Y/n
```
### Update tailwind.config.js

View File

@ -20,6 +20,7 @@ If you encounter the error `ERROR: Cannot read properties of undefined (reading
```bash
npm install -D typescript
```
### Install TailwindCSS module
```bash
@ -76,7 +77,7 @@ export default defineNuxtModule<ShadcnVueOptions>({
configKey: 'shadcn',
version: '0.0.1',
compatibility: {
nuxt: '^3.9.0',
nuxt: '>=3.9.0',
bridge: false,
},
},
@ -183,11 +184,13 @@ Would you like to use TypeScript (recommended)? no / yes
Which framework are you using? Vite / Nuxt / Laravel
Which style would you like to use? Default
Which color would you like to use as base color? Slate
Where is your tsconfig.json or jsconfig.json file? ./tsconfig.json
Where is your global CSS file? src/index.css
Do you want to use CSS variables for colors? no / yes
Where is your tailwind.config.js located? tailwind.config.js
Configure the import alias for components: @/components
Configure the import alias for utils: @/lib/utils
Write configuration to components.json. Proceed? > Y/n
```
### App structure

View File

@ -45,12 +45,12 @@ Install `tailwindcss` and its peer dependencies, then generate your `tailwind.co
#### `vite.config`
```typescript {5,6,9-13}
import path from "path"
import { defineConfig } from "vite"
import vue from "@vitejs/plugin-vue"
import path from 'node:path'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import tailwind from "tailwindcss"
import autoprefixer from "autoprefixer"
import tailwind from 'tailwindcss'
import autoprefixer from 'autoprefixer'
export default defineConfig({
css: {
@ -61,7 +61,7 @@ Install `tailwindcss` and its peer dependencies, then generate your `tailwind.co
plugins: [vue()],
resolve: {
alias: {
"@": path.resolve(__dirname, "./src"),
'@': path.resolve(__dirname, './src'),
},
},
})
@ -116,12 +116,12 @@ npm i -D @types/node
```
```typescript {15-19}
import path from "path"
import vue from "@vitejs/plugin-vue"
import { defineConfig } from "vite"
import path from 'node:path'
import vue from '@vitejs/plugin-vue'
import { defineConfig } from 'vite'
import tailwind from "tailwindcss"
import autoprefixer from "autoprefixer"
import tailwind from 'tailwindcss'
import autoprefixer from 'autoprefixer'
export default defineConfig({
css: {
@ -132,7 +132,7 @@ export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
"@": path.resolve(__dirname, "./src"),
'@': path.resolve(__dirname, './src'),
},
},
})
@ -159,11 +159,13 @@ Would you like to use TypeScript (recommended)? no / yes
Which framework are you using? Vite / Nuxt / Laravel
Which style would you like to use? Default
Which color would you like to use as base color? Slate
Where is your global CSS file? src/index.css
Where is your tsconfig.json or jsconfig.json file? ./tsconfig.json
Where is your global CSS file? src/assets/index.css
Do you want to use CSS variables for colors? no / yes
Where is your tailwind.config.js located? tailwind.config.js
Configure the import alias for components: @/components
Configure the import alias for utils: @/lib/utils
Write configuration to components.json. Proceed? > Y/n
```
### Update main.ts

View File

@ -27,7 +27,7 @@ import { Label } from '@/lib/registry/new-york/ui/label'
<div class="grid grid-cols-2 gap-6">
<Button variant="outline">
<GitHubIcon class="mr-2 h-4 w-4" />
Github
GitHub
</Button>
<Button variant="outline">
<svg role="img" viewBox="0 0 24 24" class="mr-2 h-4 w-4">

View File

@ -84,7 +84,7 @@ async function onSubmit(values: any) {
</p>
</div>
<Separator />
<Form v-slot="{ setValues }" :validation-schema="accountFormSchema" class="space-y-8" @submit="onSubmit">
<Form v-slot="{ setFieldValue }" :validation-schema="accountFormSchema" class="space-y-8" @submit="onSubmit">
<FormField v-slot="{ componentField }" name="name">
<FormItem>
<FormLabel>Name</FormLabel>
@ -126,15 +126,11 @@ async function onSubmit(values: any) {
@update:model-value="(v) => {
if (v) {
dateValue = v
setValues({
dob: toDate(v).toISOString(),
}, false)
setFieldValue('dob', toDate(v).toISOString())
}
else {
dateValue = undefined
setValues({
dob: undefined,
}, false)
setFieldValue('dob', undefined)
}
}"
/>
@ -178,9 +174,7 @@ async function onSubmit(values: any) {
<CommandItem
v-for="language in languages" :key="language.value" :value="language.label"
@select="() => {
setValues({
language: language.value,
}, false)
setFieldValue('language', language.value)
open = false
}"
>

View File

@ -57,7 +57,7 @@ const onSubmit = handleSubmit((values) => {
<select
:class="cn(
buttonVariants({ variant: 'outline' }),
'w-[200px] appearance-none bg-transparent font-normal',
'w-[200px] appearance-none font-normal',
)"
v-bind="field"
>

View File

@ -33,7 +33,7 @@ const { handleSubmit } = useForm({
},
})
const onSubmit = handleSubmit((values, { resetForm }) => {
const onSubmit = handleSubmit((values) => {
toast({
title: 'You submitted the following values:',
description: h('pre', { class: 'mt-2 w-[340px] rounded-md bg-slate-950 p-4' }, h('code', { class: 'text-white' }, JSON.stringify(values, null, 2))),

View File

@ -13,7 +13,7 @@ const $route = useRoute()
const sidebarNavItems: Item[] = [
{
title: 'Profile',
href: '/examples/forms/forms',
href: '/examples/forms',
},
{
title: 'Account',

View File

@ -94,7 +94,7 @@ const showDeleteDialog = ref(false)
<AlertDialog v-model:open="showDeleteDialog">
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Are you sure absolutely sure?</AlertDialogTitle>
<AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>
<AlertDialogDescription>
This action cannot be undone. This preset will no longer be
accessible by you or others you&apos;ve shared it with.

View File

@ -36,7 +36,7 @@ export const models: Model<ModelType>[] = [
strengths: 'Moderate classification, semantic search',
},
{
id: ' be638fb1-973b-4471-a49c-290325085802',
id: 'be638fb1-973b-4471-a49c-290325085802',
name: 'text-ada-001',
description:
'Capable of very simple tasks, usually the fastest model in the GPT-3 series, and lowest cost.',

View File

@ -53,18 +53,18 @@ export const statuses = [
export const priorities = [
{
label: 'Low',
value: 'low',
label: 'Low',
icon: h(ArrowDownIcon),
},
{
label: 'Medium',
value: 'medium',
label: 'Medium',
icon: h(ArrowRightIcon),
},
{
label: 'High',
value: 'high',
label: 'High',
icon: h(ArrowUpIcon),
},
]

View File

@ -14,11 +14,11 @@ import { Input } from '@/lib/registry/default/ui/input'
import { Label } from '@/lib/registry/default/ui/label'
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/lib/registry/default/ui/select'
import { Textarea } from '@/lib/registry/default/ui/textarea'
import { Tooltip, TooltipContent, TooltipTrigger } from '@/lib/registry/default/ui/tooltip'
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/lib/registry/default/ui/tooltip'
</script>
<template>
<div class="grid h-screen w-full pl-[53px]">
<div class="grid h-screen w-full pl-[56px]">
<aside class="inset-y fixed left-0 z-20 flex h-full flex-col border-r">
<div class="border-b p-2">
<Button variant="outline" size="icon" aria-label="Home">
@ -26,6 +26,7 @@ import { Tooltip, TooltipContent, TooltipTrigger } from '@/lib/registry/default/
</Button>
</div>
<nav class="grid gap-1 p-2">
<TooltipProvider>
<Tooltip>
<TooltipTrigger as-child>
<Button
@ -41,6 +42,8 @@ import { Tooltip, TooltipContent, TooltipTrigger } from '@/lib/registry/default/
Playground
</TooltipContent>
</Tooltip>
</TooltipProvider>
<TooltipProvider>
<Tooltip>
<TooltipTrigger as-child>
<Button
@ -56,6 +59,8 @@ import { Tooltip, TooltipContent, TooltipTrigger } from '@/lib/registry/default/
Models
</TooltipContent>
</Tooltip>
</TooltipProvider>
<TooltipProvider>
<Tooltip>
<TooltipTrigger as-child>
<Button
@ -71,6 +76,8 @@ import { Tooltip, TooltipContent, TooltipTrigger } from '@/lib/registry/default/
API
</TooltipContent>
</Tooltip>
</TooltipProvider>
<TooltipProvider>
<Tooltip>
<TooltipTrigger as-child>
<Button
@ -86,6 +93,8 @@ import { Tooltip, TooltipContent, TooltipTrigger } from '@/lib/registry/default/
Documentation
</TooltipContent>
</Tooltip>
</TooltipProvider>
<TooltipProvider>
<Tooltip>
<TooltipTrigger as-child>
<Button
@ -101,8 +110,10 @@ import { Tooltip, TooltipContent, TooltipTrigger } from '@/lib/registry/default/
Settings
</TooltipContent>
</Tooltip>
</TooltipProvider>
</nav>
<nav class="mt-auto grid gap-1 p-2">
<TooltipProvider>
<Tooltip>
<TooltipTrigger as-child>
<Button
@ -118,6 +129,8 @@ import { Tooltip, TooltipContent, TooltipTrigger } from '@/lib/registry/default/
Help
</TooltipContent>
</Tooltip>
</TooltipProvider>
<TooltipProvider>
<Tooltip>
<TooltipTrigger as-child>
<Button
@ -133,6 +146,7 @@ import { Tooltip, TooltipContent, TooltipTrigger } from '@/lib/registry/default/
Account
</TooltipContent>
</Tooltip>
</TooltipProvider>
</nav>
</aside>
<div class="flex flex-col">
@ -406,6 +420,7 @@ import { Tooltip, TooltipContent, TooltipTrigger } from '@/lib/registry/default/
class="min-h-12 resize-none border-0 p-3 shadow-none focus-visible:ring-0"
/>
<div class="flex items-center p-3 pt-0">
<TooltipProvider>
<Tooltip>
<TooltipTrigger as-child>
<Button variant="ghost" size="icon">
@ -417,6 +432,8 @@ import { Tooltip, TooltipContent, TooltipTrigger } from '@/lib/registry/default/
Attach File
</TooltipContent>
</Tooltip>
</TooltipProvider>
<TooltipProvider>
<Tooltip>
<TooltipTrigger as-child>
<Button variant="ghost" size="icon">
@ -428,6 +445,7 @@ import { Tooltip, TooltipContent, TooltipTrigger } from '@/lib/registry/default/
Use Microphone
</TooltipContent>
</Tooltip>
</TooltipProvider>
<Button type="submit" size="sm" class="ml-auto gap-1.5">
Send Message
<CornerDownLeft class="size-3.5" />

View File

@ -6,8 +6,6 @@ export const containerClass = 'w-full h-full'
<script setup lang="ts">
import {
ChevronLeft,
ChevronRight,
CircleUser,
Copy,
CreditCard,
@ -42,11 +40,7 @@ import {
import { Sheet, SheetContent, SheetTrigger } from '@/lib/registry/default/ui/sheet'
import {
Pagination,
PaginationEllipsis,
PaginationFirst,
PaginationLast,
PaginationList,
PaginationListItem,
PaginationNext,
PaginationPrev,
} from '@/lib/registry/default/ui/pagination'
@ -69,6 +63,7 @@ import {
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from '@/lib/registry/default/ui/tooltip'
import { Checkbox } from '@/lib/registry/default/ui/checkbox'
@ -85,6 +80,7 @@ import { Checkbox } from '@/lib/registry/default/ui/checkbox'
<Package2 class="h-4 w-4 transition-all group-hover:scale-110" />
<span class="sr-only">Acme Inc</span>
</a>
<TooltipProvider>
<Tooltip>
<TooltipTrigger as-child>
<a
@ -99,6 +95,8 @@ import { Checkbox } from '@/lib/registry/default/ui/checkbox'
Dashboard
</TooltipContent>
</Tooltip>
</TooltipProvider>
<TooltipProvider>
<Tooltip>
<TooltipTrigger as-child>
<a
@ -113,6 +111,9 @@ import { Checkbox } from '@/lib/registry/default/ui/checkbox'
Orders
</TooltipContent>
</Tooltip>
</TooltipProvider>
<TooltipProvider>
<Tooltip>
<TooltipTrigger as-child>
<a
@ -127,6 +128,9 @@ import { Checkbox } from '@/lib/registry/default/ui/checkbox'
Products
</TooltipContent>
</Tooltip>
</TooltipProvider>
<TooltipProvider>
<Tooltip>
<TooltipTrigger as-child>
<a
@ -141,6 +145,9 @@ import { Checkbox } from '@/lib/registry/default/ui/checkbox'
Customers
</TooltipContent>
</Tooltip>
</TooltipProvider>
<TooltipProvider>
<Tooltip>
<TooltipTrigger as-child>
<a
@ -155,8 +162,10 @@ import { Checkbox } from '@/lib/registry/default/ui/checkbox'
Analytics
</TooltipContent>
</Tooltip>
</TooltipProvider>
</nav>
<nav class="mt-auto flex flex-col items-center gap-4 px-2 sm:py-5">
<TooltipProvider>
<Tooltip>
<TooltipTrigger as-child>
<a
@ -171,6 +180,7 @@ import { Checkbox } from '@/lib/registry/default/ui/checkbox'
Settings
</TooltipContent>
</Tooltip>
</TooltipProvider>
</nav>
</aside>
<div class="flex flex-col sm:gap-4 sm:py-4 sm:pl-14">

View File

@ -53,6 +53,7 @@ import {
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from '@/lib/registry/default/ui/tooltip'
</script>
@ -68,6 +69,7 @@ import {
<Package2 class="h-4 w-4 transition-all group-hover:scale-110" />
<span class="sr-only">Acme Inc</span>
</a>
<TooltipProvider>
<Tooltip>
<TooltipTrigger as-child>
<a
@ -82,6 +84,8 @@ import {
Dashboard
</TooltipContent>
</Tooltip>
</TooltipProvider>
<TooltipProvider>
<Tooltip>
<TooltipTrigger as-child>
<a
@ -96,6 +100,8 @@ import {
Orders
</TooltipContent>
</Tooltip>
</TooltipProvider>
<TooltipProvider>
<Tooltip>
<TooltipTrigger as-child>
<a
@ -110,6 +116,8 @@ import {
Products
</TooltipContent>
</Tooltip>
</TooltipProvider>
<TooltipProvider>
<Tooltip>
<TooltipTrigger as-child>
<a
@ -124,6 +132,8 @@ import {
Customers
</TooltipContent>
</Tooltip>
</TooltipProvider>
<TooltipProvider>
<Tooltip>
<TooltipTrigger as-child>
<a
@ -138,8 +148,10 @@ import {
Analytics
</TooltipContent>
</Tooltip>
</TooltipProvider>
</nav>
<nav class="mt-auto flex flex-col items-center gap-4 px-2 py-4">
<TooltipProvider>
<Tooltip>
<TooltipTrigger as-child>
<a
@ -154,6 +166,7 @@ import {
Settings
</TooltipContent>
</Tooltip>
</TooltipProvider>
</nav>
</aside>
<div class="flex flex-col sm:gap-4 sm:py-4 sm:pl-14">

View File

@ -56,6 +56,7 @@ import {
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from '@/lib/registry/default/ui/tooltip'
</script>
@ -71,6 +72,7 @@ import {
<Package2 class="h-4 w-4 transition-all group-hover:scale-110" />
<span class="sr-only">Acme Inc</span>
</a>
<TooltipProvider>
<Tooltip>
<TooltipTrigger as-child>
<a
@ -85,6 +87,8 @@ import {
Dashboard
</TooltipContent>
</Tooltip>
</TooltipProvider>
<TooltipProvider>
<Tooltip>
<TooltipTrigger as-child>
<a
@ -99,6 +103,8 @@ import {
Orders
</TooltipContent>
</Tooltip>
</TooltipProvider>
<TooltipProvider>
<Tooltip>
<TooltipTrigger as-child>
<a
@ -113,6 +119,8 @@ import {
Products
</TooltipContent>
</Tooltip>
</TooltipProvider>
<TooltipProvider>
<Tooltip>
<TooltipTrigger as-child>
<a
@ -127,6 +135,8 @@ import {
Customers
</TooltipContent>
</Tooltip>
</TooltipProvider>
<TooltipProvider>
<Tooltip>
<TooltipTrigger as-child>
<a
@ -141,8 +151,10 @@ import {
Analytics
</TooltipContent>
</Tooltip>
</TooltipProvider>
</nav>
<nav class="mt-auto flex flex-col items-center gap-4 px-2 sm:py-5">
<TooltipProvider>
<Tooltip>
<TooltipTrigger as-child>
<a
@ -157,6 +169,7 @@ import {
Settings
</TooltipContent>
</Tooltip>
</TooltipProvider>
</nav>
</aside>
<div class="flex flex-col sm:gap-4 sm:py-4 sm:pl-14">

View File

@ -1,6 +1,6 @@
<script setup lang="ts">
import * as z from 'zod'
import { h, onMounted, ref, shallowRef } from 'vue'
import { h, onMounted, shallowRef } from 'vue'
import { Button } from '@/lib/registry/default/ui/button'
import { toast } from '@/lib/registry/default/ui/toast'
import { AutoForm } from '@/lib/registry/default/ui/auto-form'

View File

@ -1,12 +1,8 @@
<script setup lang="ts">
import * as z from 'zod'
import { h, reactive, ref } from 'vue'
import { useForm } from 'vee-validate'
import { toTypedSchema } from '@vee-validate/zod'
import { DependencyType } from '../ui/auto-form/interface'
import { h } from 'vue'
import { Button } from '@/lib/registry/default/ui/button'
import { toast } from '@/lib/registry/default/ui/toast'
import type { Config } from '@/lib/registry/default/ui/auto-form'
import { AutoForm, AutoFormField } from '@/lib/registry/default/ui/auto-form'
enum Sports {

View File

@ -3,7 +3,7 @@ import * as z from 'zod'
import { h } from 'vue'
import { Button } from '@/lib/registry/default/ui/button'
import { toast } from '@/lib/registry/default/ui/toast'
import { AutoForm, AutoFormField } from '@/lib/registry/default/ui/auto-form'
import { AutoForm } from '@/lib/registry/default/ui/auto-form'
const schema = z.object({
subObject: z.object({

View File

@ -32,7 +32,7 @@ const formSchema = toTypedSchema(z.object({
const placeholder = ref()
const { handleSubmit, setValues, values } = useForm({
const { handleSubmit, setFieldValue, values } = useForm({
validationSchema: formSchema,
})
@ -79,14 +79,10 @@ const onSubmit = handleSubmit((values) => {
:max-value="today(getLocalTimeZone())"
@update:model-value="(v) => {
if (v) {
setValues({
dob: v.toString(),
})
setFieldValue('dob', v.toString())
}
else {
setValues({
dob: '',
})
setFieldValue('dob', undefined)
}
}"
/>

View File

@ -1,5 +1,5 @@
<script setup lang="ts">
import { type HTMLAttributes, type Ref, computed, toRef } from 'vue'
import { type HTMLAttributes, type Ref, computed } from 'vue'
import { CalendarRoot, type CalendarRootEmits, type CalendarRootProps, useDateFormatter, useForwardPropsEmits } from 'radix-vue'
import { createDecade, createYear, toDate } from 'radix-vue/date'
import { type DateValue, getLocalTimeZone, today } from '@internationalized/date'

View File

@ -40,7 +40,7 @@ import { Button } from '@/lib/registry/default/ui/button'
</SelectTrigger>
<SelectContent position="popper">
<SelectItem value="nuxt">
Nuxt.js
Nuxt
</SelectItem>
<SelectItem value="next">
Next.js

View File

@ -49,7 +49,7 @@ import {
Astro
</SelectItem>
<SelectItem value="nuxt">
Nuxt.js
Nuxt
</SelectItem>
</SelectContent>
</Select>

View File

@ -1,8 +1,7 @@
<script setup lang="ts">
import { computed, ref } from 'vue'
import { ref } from 'vue'
import { Minus, Plus } from 'lucide-vue-next'
import { VisStackedBar, VisXYContainer } from '@unovis/vue'
import { useData } from 'vitepress'
import { Button } from '@/lib/registry/default/ui/button'
import {
@ -13,8 +12,6 @@ import {
CardHeader,
CardTitle,
} from '@/lib/registry/default/ui/card'
import { themes } from '@/lib/registry/themes'
import { useConfigStore } from '@/stores/config'
const goal = ref(350)

View File

@ -8,7 +8,6 @@ import {
CardHeader,
CardTitle,
} from '@/lib/registry/default/ui/card'
import { useConfigStore } from '@/stores/config'
type Data = typeof data[number]
const data = [

View File

@ -21,7 +21,7 @@ import {
const frameworks = [
{ value: 'next.js', label: 'Next.js' },
{ value: 'sveltekit', label: 'SvelteKit' },
{ value: 'nuxt.js', label: 'Nuxt.js' },
{ value: 'nuxt', label: 'Nuxt' },
{ value: 'remix', label: 'Remix' },
{ value: 'astro', label: 'Astro' },
]

View File

@ -48,7 +48,7 @@ const formSchema = toTypedSchema(z.object({
}),
}))
const { handleSubmit, setValues, values } = useForm({
const { handleSubmit, setFieldValue, values } = useForm({
validationSchema: formSchema,
})
@ -91,9 +91,7 @@ const onSubmit = handleSubmit((values) => {
:key="language.value"
:value="language.label"
@select="() => {
setValues({
language: language.value,
})
setFieldValue('language', language.value)
}"
>
<Check

View File

@ -60,7 +60,7 @@ const statuses: Status[] = [
]
const open = ref(false)
const value = ref<typeof statuses[number]>()
// const value = ref<typeof statuses[number]>()
const selectedStatus = ref<Status>()
</script>

View File

@ -32,7 +32,7 @@ const formSchema = toTypedSchema(z.object({
const placeholder = ref()
const { handleSubmit, setValues, values } = useForm({
const { handleSubmit, setFieldValue, values } = useForm({
validationSchema: formSchema,
initialValues: {
@ -82,14 +82,10 @@ const onSubmit = handleSubmit((values) => {
:max-value="today(getLocalTimeZone())"
@update:model-value="(v) => {
if (v) {
setValues({
dob: v.toString(),
})
setFieldValue('dob', v.toString())
}
else {
setValues({
dob: '',
})
setFieldValue('dob', undefined)
}
}"

View File

@ -1,5 +1,5 @@
<script setup lang="ts">
import { DonutChart } from '@/lib/registry/new-york/ui/chart-donut'
import { DonutChart } from '@/lib/registry/default/ui/chart-donut'
const data = [
{ name: 'Jan', total: Math.floor(Math.random() * 2000) + 500, predicted: Math.floor(Math.random() * 2000) + 500 },

View File

@ -0,0 +1,30 @@
<script setup lang="ts">
import {
NumberField,
NumberFieldContent,
NumberFieldDecrement,
NumberFieldIncrement,
NumberFieldInput,
} from '@/lib/registry/default/ui/number-field'
import { Label } from '@/lib/registry/default/ui/label'
</script>
<template>
<NumberField
id="balance"
:default-value="1500"
:format-options="{
style: 'currency',
currency: 'EUR',
currencyDisplay: 'code',
currencySign: 'accounting',
}"
>
<Label for="balance">Balance</Label>
<NumberFieldContent>
<NumberFieldDecrement />
<NumberFieldInput />
<NumberFieldIncrement />
</NumberFieldContent>
</NumberField>
</template>

View File

@ -0,0 +1,28 @@
<script setup lang="ts">
import {
NumberField,
NumberFieldContent,
NumberFieldDecrement,
NumberFieldIncrement,
NumberFieldInput,
} from '@/lib/registry/default/ui/number-field'
import { Label } from '@/lib/registry/default/ui/label'
</script>
<template>
<NumberField
id="number"
:default-value="5"
:format-options="{
signDisplay: 'exceptZero',
minimumFractionDigits: 1,
}"
>
<Label for="number">Number</Label>
<NumberFieldContent>
<NumberFieldDecrement />
<NumberFieldInput />
<NumberFieldIncrement />
</NumberFieldContent>
</NumberField>
</template>

View File

@ -0,0 +1,21 @@
<script setup lang="ts">
import {
NumberField,
NumberFieldContent,
NumberFieldDecrement,
NumberFieldIncrement,
NumberFieldInput,
} from '@/lib/registry/default/ui/number-field'
import { Label } from '@/lib/registry/default/ui/label'
</script>
<template>
<NumberField id="age" :default-value="18" :min="0">
<Label for="age">Age</Label>
<NumberFieldContent>
<NumberFieldDecrement />
<NumberFieldInput />
<NumberFieldIncrement />
</NumberFieldContent>
</NumberField>
</template>

View File

@ -0,0 +1,21 @@
<script setup lang="ts">
import {
NumberField,
NumberFieldContent,
NumberFieldDecrement,
NumberFieldIncrement,
NumberFieldInput,
} from '@/lib/registry/default/ui/number-field'
import { Label } from '@/lib/registry/default/ui/label'
</script>
<template>
<NumberField id="age-disabled" :default-value="18" disabled>
<Label for="age-disabled">Age</Label>
<NumberFieldContent>
<NumberFieldDecrement />
<NumberFieldInput />
<NumberFieldIncrement />
</NumberFieldContent>
</NumberField>
</template>

View File

@ -0,0 +1,85 @@
<script setup lang="ts">
import { h } from 'vue'
import { useForm } from 'vee-validate'
import { toTypedSchema } from '@vee-validate/zod'
import * as z from 'zod'
import { Button } from '@/lib/registry/default/ui/button'
import {
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@/lib/registry/default/ui/form'
import {
NumberField,
NumberFieldContent,
NumberFieldDecrement,
NumberFieldIncrement,
NumberFieldInput,
} from '@/lib/registry/default/ui/number-field'
import { toast } from '@/lib/registry/default/ui/toast'
const formSchema = toTypedSchema(z.object({
payment: z.number().min(10, 'Min 10 euros to send payment').max(5000, 'Max 5000 euros to send payment'),
}))
const { handleSubmit, setFieldValue } = useForm({
validationSchema: formSchema,
initialValues: {
payment: 10,
},
})
const onSubmit = handleSubmit((values) => {
toast({
title: 'You submitted the following values:',
description: h('pre', { class: 'mt-2 w-[340px] rounded-md bg-slate-950 p-4' }, h('code', { class: 'text-white' }, JSON.stringify(values, null, 2))),
})
})
</script>
<template>
<form class="w-2/3 space-y-6" @submit="onSubmit">
<FormField name="payment">
<FormItem>
<FormLabel>Payment</FormLabel>
<NumberField
class="gap-2"
:min="0"
:format-options="{
style: 'currency',
currency: 'EUR',
currencyDisplay: 'code',
currencySign: 'accounting',
}"
@update:model-value="(v) => {
if (v) {
setFieldValue('payment', v)
}
else {
setFieldValue('payment', undefined)
}
}"
>
<NumberFieldContent>
<NumberFieldDecrement />
<FormControl>
<NumberFieldInput />
</FormControl>
<NumberFieldIncrement />
</NumberFieldContent>
</NumberField>
<FormDescription>
Enter value between 10 and 5000.
</FormDescription>
<FormMessage />
</FormItem>
</FormField>
<Button type="submit">
Submit
</Button>
</form>
</template>

View File

@ -0,0 +1,28 @@
<script setup lang="ts">
import {
NumberField,
NumberFieldContent,
NumberFieldDecrement,
NumberFieldIncrement,
NumberFieldInput,
} from '@/lib/registry/default/ui/number-field'
import { Label } from '@/lib/registry/default/ui/label'
</script>
<template>
<NumberField
id="percent"
:default-value="0.05"
:step="0.01"
:format-options="{
style: 'percent',
}"
>
<Label for="percent">Percent</Label>
<NumberFieldContent>
<NumberFieldDecrement />
<NumberFieldInput />
<NumberFieldIncrement />
</NumberFieldContent>
</NumberField>
</template>

View File

@ -23,7 +23,7 @@ const formSchema = toTypedSchema(z.object({
pin: z.array(z.coerce.string()).length(5, { message: 'Invalid input' }),
}))
const { handleSubmit, setValues } = useForm({
const { handleSubmit, setFieldValue } = useForm({
validationSchema: formSchema,
initialValues: {
pin: ['1', '2', '3'],
@ -56,9 +56,7 @@ const handleComplete = (e: string[]) => console.log(e.join(''))
:name="componentField.name"
@complete="handleComplete"
@update:model-value="(arrStr) => {
setValues({
pin: arrStr.filter(Boolean),
})
setFieldValue('pin', arrStr.filter(Boolean))
}"
>
<PinInputGroup>

View File

@ -12,7 +12,7 @@ import { Separator } from '@/lib/registry/default/ui/separator'
An open-source UI component library.
</p>
</div>
<Separator class="my-4" />
<Separator class="my-4" label="Or" />
<div class="flex h-5 items-center space-x-4 text-sm">
<div>Blog</div>
<Separator orientation="vertical" />

View File

@ -0,0 +1,53 @@
<script setup lang="ts">
import { toast } from 'vue-sonner'
import { Button } from '@/lib/registry/default/ui/button'
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
} from '@/lib/registry/default/ui/dialog'
</script>
<template>
<Dialog>
<DialogTrigger as-child>
<Button variant="outline">
Dialog with toast
</Button>
</DialogTrigger>
<DialogContent
class="sm:max-w-md"
@interact-outside="event => {
const target = event.target as HTMLElement;
if (target?.closest('[data-sonner-toaster]')) return event.preventDefault()
}"
>
<DialogHeader>
<DialogTitle>Vue Sonner Toast</DialogTitle>
<DialogDescription> Dialog with toast </DialogDescription>
</DialogHeader>
<div class="grid gap-4">
<Button
size="sm"
class="px-3"
@click="
() => {
toast('Event has been created', {
description: 'Sunday, December 03, 2023 at 9:00 AM',
action: {
label: 'Undo',
onClick: () => console.log('Undo'),
},
});
}
"
>
Toast
</Button>
</div>
</DialogContent>
</Dialog>
</template>

View File

@ -7,7 +7,7 @@ import { TagsInput, TagsInputInput, TagsInputItem, TagsInputItemDelete, TagsInpu
const frameworks = [
{ value: 'next.js', label: 'Next.js' },
{ value: 'sveltekit', label: 'SvelteKit' },
{ value: 'nuxt.js', label: 'Nuxt.js' },
{ value: 'nuxt', label: 'Nuxt' },
{ value: 'remix', label: 'Remix' },
{ value: 'astro', label: 'Astro' },
]

View File

@ -5,7 +5,7 @@ import { Toggle } from '@/lib/registry/default/ui/toggle'
</script>
<template>
<Toggle aria-label="Toggle italic">
<Toggle aria-label="Toggle bold">
<Bold class="h-4 w-4" />
</Toggle>
</template>

View File

@ -5,7 +5,7 @@ import { Toggle } from '@/lib/registry/default/ui/toggle'
</script>
<template>
<Toggle aria-label="Toggle italic" disabled>
<Toggle aria-label="Toggle underline" disabled>
<Underline class="w-4 h-4" />
</Toggle>
</template>

View File

@ -1,5 +1,5 @@
<template>
<div class="text-lg font-semibold">
Are you sure absolutely sure?
Are you absolutely sure?
</div>
</template>

View File

@ -26,7 +26,7 @@ const date = ref({
id="date"
:variant="'outline'"
:class="cn(
'w-[300px] justify-start text-left font-normal',
'w-[280px] justify-start text-left font-normal',
!date && 'text-muted-foreground',
)"
>

View File

@ -26,7 +26,7 @@ const date = ref({
id="date"
:variant="'outline'"
:class="cn(
'w-[300px] justify-start text-left font-normal',
'w-[280px] justify-start text-left font-normal',
!date && 'text-muted-foreground',
)"
>

View File

@ -1,5 +1,4 @@
<script setup lang="ts">
import { computed } from 'vue'
import AutoFormLabel from './AutoFormLabel.vue'
import { beautifyObjectName } from './utils'
import type { FieldProps } from './interface'

View File

@ -28,7 +28,8 @@ const shapes = computed(() => {
return
Object.keys(shape).forEach((name) => {
const item = shape[name] as ZodAny
let options = 'values' in item._def ? item._def.values as string[] : undefined
const baseItem = getBaseSchema(item) as ZodAny
let options = (baseItem && 'values' in baseItem._def) ? baseItem._def.values as string[] : undefined
if (!Array.isArray(options) && typeof options === 'object')
options = Object.values(options)

View File

@ -1,4 +1,4 @@
import type { Component, InputHTMLAttributes, SelectHTMLAttributes } from 'vue'
import type { Component, InputHTMLAttributes } from 'vue'
import type { ZodAny, z } from 'zod'
import type { INPUT_COMPONENTS } from './constant'

View File

@ -122,7 +122,7 @@ type NestedRecord = Record<string, unknown> | { [k: string]: NestedRecord }
* Checks if the path opted out of nested fields using `[fieldName]` syntax
*/
export function isNotNestedPath(path: string) {
return /^\[.+\]$/i.test(path)
return /^\[.+\]$/.test(path)
}
function isObject(obj: unknown): obj is Record<string, unknown> {
return obj !== null && !!obj && typeof obj === 'object' && !Array.isArray(obj)
@ -132,7 +132,7 @@ function isContainerValue(value: unknown): value is Record<string, unknown> {
}
function cleanupNonNestedPath(path: string) {
if (isNotNestedPath(path))
return path.replace(/\[|\]/gi, '')
return path.replace(/\[|\]/g, '')
return path
}

View File

@ -12,9 +12,8 @@ const { scrollTo, selectedIndex, scrollSnaps, orientation } = useCarousel()
:class="cn('flex gap-2 justify-center relative -translate-x-1/2 left-1/2', { 'top-10': orientation === 'vertical' }, props.class)"
>
<div
v-for="(_, index) in scrollSnaps" :key="index" class="border-1 w-4 h-4 rounded-full"
:class="cn(index === selectedIndex ? 'border-transparent bg-primary' : 'bg-border', props.class)"
@click="scrollTo(index)"
v-for="(_, index) in scrollSnaps" :key="index" class="w-2 h-2 rounded-full"
:class="cn(index === selectedIndex ? 'border-transparent bg-primary' : 'bg-border')" @click="scrollTo(index)"
/>
</div>
</template>

View File

@ -25,6 +25,7 @@ const { orientation, canScrollNext, scrollNext } = useCarousel()
>
<slot>
<ArrowRight class="h-4 w-4 text-current" />
<span class="sr-only">Next Slide</span>
</slot>
</Button>
</template>

View File

@ -25,6 +25,7 @@ const { orientation, canScrollPrev, scrollPrev } = useCarousel()
>
<slot>
<ArrowLeft class="h-4 w-4 text-current" />
<span class="sr-only">Previous Slide</span>
</slot>
</Button>
</template>

View File

@ -7,5 +7,5 @@ export { default as CarouselDotButtons } from './CarouselDotButtons.vue'
export { useCarousel } from './useCarousel'
export type {
EmblaCarouselType as CarouselApi,
} from 'embla-carousel'
UnwrapRefCarouselApi as CarouselApi,
} from './interface'

View File

@ -1,18 +1,24 @@
import type { HTMLAttributes, UnwrapRef } from 'vue'
import type useEmblaCarousel from 'embla-carousel-vue'
import type {
EmblaCarouselType as CarouselApi,
EmblaOptionsType as CarouselOptions,
EmblaPluginType as CarouselPlugin,
} from 'embla-carousel'
import type { HTMLAttributes, Ref } from 'vue'
EmblaCarouselVueType,
} from 'embla-carousel-vue'
type CarouselApi = EmblaCarouselVueType[1]
type UseCarouselParameters = Parameters<typeof useEmblaCarousel>
type CarouselOptions = UseCarouselParameters[0]
type CarouselPlugin = UseCarouselParameters[1]
export type UnwrapRefCarouselApi = UnwrapRef<CarouselApi>
export interface CarouselProps {
opts?: CarouselOptions | Ref<CarouselOptions>
plugins?: CarouselPlugin[] | Ref<CarouselPlugin[]>
opts?: CarouselOptions
plugins?: CarouselPlugin
orientation?: 'horizontal' | 'vertical'
}
export interface CarouselEmits {
(e: 'init-api', payload: CarouselApi): void
(e: 'init-api', payload: UnwrapRefCarouselApi): void
}
export interface WithClassAsProps {

View File

@ -1,10 +1,7 @@
import { createInjectionState } from '@vueuse/core'
import emblaCarouselVue from 'embla-carousel-vue'
import { onMounted, ref } from 'vue'
import type {
EmblaCarouselType as CarouselApi,
} from 'embla-carousel'
import type { CarouselEmits, CarouselProps } from './interface'
import type { UnwrapRefCarouselApi as CarouselApi, CarouselEmits, CarouselProps } from './interface'
const [useProvideCarousel, useInjectCarousel] = createInjectionState(
({
@ -27,16 +24,16 @@ const [useProvideCarousel, useInjectCarousel] = createInjectionState(
emblaApi.value?.scrollTo(index)
}
const canScrollNext = ref(true)
const canScrollPrev = ref(true)
const canScrollNext = ref(false)
const canScrollPrev = ref(false)
const selectedIndex = ref(0)
const scrollSnaps = ref([])
const scrollSnaps = ref<number[]>([])
function onSelect(api: CarouselApi) {
canScrollNext.value = api.canScrollNext()
canScrollPrev.value = api.canScrollPrev()
selectedIndex.value = api.selectedScrollSnap()
scrollSnaps.value = api.scrollSnapList()
canScrollNext.value = api?.canScrollNext() || false
canScrollPrev.value = api?.canScrollPrev() || false
selectedIndex.value = api?.selectedScrollSnap() || 0
scrollSnaps.value = api?.scrollSnapList() || []
}
onMounted(() => {

View File

@ -4,7 +4,8 @@ import { VisArea, VisAxis, VisLine, VisXYContainer } from '@unovis/vue'
import { Area, Axis, Line } from '@unovis/ts'
import { type Component, computed, ref } from 'vue'
import { useMounted } from '@vueuse/core'
import { type BaseChartProps, ChartCrosshair, ChartLegend, defaultColors } from '@/lib/registry/default/ui/chart'
import type { BaseChartProps } from '.'
import { ChartCrosshair, ChartLegend, defaultColors } from '@/lib/registry/default/ui/chart'
import { cn } from '@/lib/utils'
const props = withDefaults(defineProps<BaseChartProps<T> & {

View File

@ -1 +1,66 @@
export { default as AreaChart } from './AreaChart.vue'
import type { Spacing } from '@unovis/ts'
type KeyOf<T extends Record<string, any>> = Extract<keyof T, string>
export interface BaseChartProps<T extends Record<string, any>> {
/**
* The source data, in which each entry is a dictionary.
*/
data: T[]
/**
* Select the categories from your data. Used to populate the legend and toolip.
*/
categories: KeyOf<T>[]
/**
* Sets the key to map the data to the axis.
*/
index: KeyOf<T>
/**
* Change the default colors.
*/
colors?: string[]
/**
* Margin of each the container
*/
margin?: Spacing
/**
* Change the opacity of the non-selected field
* @default 0.2
*/
filterOpacity?: number
/**
* Function to format X label
*/
xFormatter?: (tick: number | Date, i: number, ticks: number[] | Date[]) => string
/**
* Function to format Y label
*/
yFormatter?: (tick: number | Date, i: number, ticks: number[] | Date[]) => string
/**
* Controls the visibility of the X axis.
* @default true
*/
showXAxis?: boolean
/**
* Controls the visibility of the Y axis.
* @default true
*/
showYAxis?: boolean
/**
* Controls the visibility of tooltip.
* @default true
*/
showTooltip?: boolean
/**
* Controls the visibility of legend.
* @default true
*/
showLegend?: boolean
/**
* Controls the visibility of gridline.
* @default true
*/
showGridLine?: boolean
}

View File

@ -1,10 +1,11 @@
<script setup lang="ts" generic="T extends Record<string, any>">
import type { BulletLegendItemInterface, Spacing } from '@unovis/ts'
import type { BulletLegendItemInterface } from '@unovis/ts'
import { VisAxis, VisGroupedBar, VisStackedBar, VisXYContainer } from '@unovis/vue'
import { Axis, GroupedBar, StackedBar } from '@unovis/ts'
import { type Component, computed, ref } from 'vue'
import { useMounted } from '@vueuse/core'
import { type BaseChartProps, ChartCrosshair, ChartLegend, defaultColors } from '@/lib/registry/default/ui/chart'
import type { BaseChartProps } from '.'
import { ChartCrosshair, ChartLegend, defaultColors } from '@/lib/registry/default/ui/chart'
import { cn } from '@/lib/utils'
const props = withDefaults(defineProps<BaseChartProps<T> & {

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