Compare commits

..

42 Commits
sidebar ... dev

Author SHA1 Message Date
N1kl8s
47f53cb985 Migrate gitlab to gitea 2024-12-28 22:39:40 +01:00
1e1f335853 README.md aktualisiert 2024-12-28 22:32:52 +01:00
32d6b8b397 README.md aktualisiert 2024-12-28 22:26:05 +01:00
Boris
3eaef4a748
docs: fix broken link in footer (#950)
* Fix 404 link in footer

* Change link

Co-authored-by: zernonia <59365435+zernonia@users.noreply.github.com>

---------

Co-authored-by: zernonia <59365435+zernonia@users.noreply.github.com>
2024-12-17 16:35:47 +08:00
slow-groovin
5b1f952e0a
docs: missing .value for combobox usage (#947) 2024-12-17 12:32:11 +08:00
zernonia
693b0d2a08 fix(Sidebar): component import and registry dependencies 2024-12-17 12:21:45 +08:00
Fabian Bernhart
8a24d11a65
fix: add missing useMediaQuery in SidebarProvider.vue new-york style (#927) 2024-12-04 22:36:12 +03:30
Leo Chiu
e4fea78b33
docs: update code highlight and step configurations in vite.md (#936) 2024-12-04 10:22:52 +03:30
Stephan Koglin-Fischer
5869165a84
docs: added missing import in auto-form example (#919) 2024-12-03 12:36:41 +03:30
Damien Roche
857f10de51
docs: update responsive breadcrumb example (#933) 2024-12-03 12:26:41 +03:30
Thomas La Salmonie
5ada562803
build(cli): update proxy agent using undici agent to match ofetch requirements (#934) 2024-12-03 12:25:37 +03:30
zernonia
6c0ab55e92 chore: release v0.11.3 2024-11-19 16:13:22 +08:00
Fatih Solhan
3ddd70dd6b
docs: prevent shrinking theme customizer circles (#914)
* fix: prevent shrinking theme customizer circles

* use `shrink-0` instead of deprecated `flex-shrink-0`
2024-11-19 14:51:56 +08:00
Whbbit1999
2d5ad5b962
fix: mobile sidebar component #840 (#884)
* fix: sidebar component mobile #840

* chore: update new-york style too

* chore: run registry build

* revert: change in templates.ts

---------

Co-authored-by: zernonia <zernonia@gmail.com>
2024-11-19 14:51:24 +08:00
Leo Chiu
16f1d19460
fix(CLI): temporarily downgrade package to 3.2.0 due to TSInterfaceHeritage issue (#913)
Co-authored-by: leochiu <leochiu@hahow.in>
2024-11-19 14:31:12 +08:00
Louis Van Aken
ac69980ac9
fix: Error in the build of the auto form with Vite and TypeScript #870 (#896)
* fix: Error in the build of the auto form with Vite and TypeScript #870

* fix: new york registry
2024-11-16 17:40:29 +08:00
Titus Kirch
58fc125974
docs: fix primitive link in data-table.md (#898) 2024-11-16 17:34:26 +08:00
sinsky
383c846c02
docs: input components use "default-value" instead of "value" (#904)
* docs(example): input components used in SheetDemo use default-value instead of value

* docs(example): input components used in DialogDemo use default-value instead of value
2024-11-16 17:32:00 +08:00
sea
b7ef4653f7
docs: update * scrollbar style (#885) 2024-11-11 12:24:52 +03:30
Brian Le
384c87a91c
fix: add missing classes to button (#877) 2024-11-10 08:20:18 +03:30
Tony Zhang
75a5bce92f
docs: fix invisible code highlight in light mode (#875)
Signed-off-by: ZTL-UwU <zhangtianli2006@163.com>
2024-11-09 19:23:43 +03:30
Rhanlin
3d0db2de7b
docs: fix dialog form example onsubmit (#873) 2024-11-09 08:52:17 +03:30
Damien Roche
a5b25a9c43
fix: switch from placeholder: to data-placeholder: prefix class for SelectValue (#867) 2024-11-09 08:33:01 +03:30
zernonia
be888c80b6 chore: run changelogithub first 2024-11-04 15:20:54 +08:00
zernonia
93be758257 fix: module build 2024-11-04 15:17:59 +08:00
zernonia
26df827d33 chore: release v0.11.2 2024-11-04 14:53:22 +08:00
zernonia
f267b0ba4a chore: improve cd 2024-11-04 14:52:23 +08:00
zernonia
3c506ef188 chore: release v0.11.1 2024-11-04 14:45:18 +08:00
zernonia
df60e15a97 chore: improve cd 2024-11-04 14:43:40 +08:00
Selemon Brahanu
3646203d4f
refactor(CLI): base dependencies not installing when using shadcn-nuxt (#821)
* refactor: 815 shadcn-nuxt dependencies and CLI init

Closes: 815

* chore: remove unnecessary dependencies

* chore: update pnpm-lock.yaml file

* chore: cleanup

* chore: update pnpm-lock

---------

Co-authored-by: zernonia <zernonia@gmail.com>
2024-11-04 14:20:14 +08:00
zernonia
68c40f6908 chore: codegen 2024-11-03 23:52:53 +08:00
Hookin.
ff1b5f0a1b
fix(Sidebar): use open.value when setting the cookie (#862) 2024-11-03 17:11:46 +08:00
苗大
15f3eb305b
fix: missing NavigationMenuViewport component (#860) 2024-11-02 23:38:57 +08:00
Rnz Brngn
baceb4ce91
docs(blocks): correct tooltip prop for dynamic binding (#850) 2024-11-02 23:37:12 +08:00
IllustrisJack
2cb767122a
fix(Nuxt): component override warnings (#838) 2024-11-02 23:33:09 +08:00
Maxim Kim
eff3e75466
fix(Sidebar): missing slot into component (#847)
* fix(SidebarMenuAction): add slot into component

* fix(SidebarMenuAction): add changes in new-york style
2024-11-02 23:31:39 +08:00
xiaomo
83419c4dc3
docs: replace unexported cssVariables with highlight (#841) 2024-10-29 08:33:28 +03:30
xiaomo
52b9b20b3c
docs: add theme to highlight code block (#831) 2024-10-28 15:32:30 +03:30
zernonia
e0d4980e31
feat: Sidebar (1/2) (#827)
* feat: add default sidebar

* chore: add images, docs item

* refactor: rename and fix styling`

* feat: add new-york style

* chore: move typescript to catalog

* docs: fix block preview

* chore: build registry, add sidebar block

* docs: update sidebar demo

* chore: bump radix-vue

* chore: fix build
2024-10-28 01:05:55 +08:00
Mohammed Essam Helewa
6760ebb5ae
feat: enhance the behavior of Switch component (#835)
* Add named slot inside SwitchThumb

* Add documentation for switch thumb slot

* chore: re-build registry
2024-10-26 21:52:03 +03:30
Ciro Lo Sapio
d143272fb8
docs: update footer links (#820) 2024-10-22 20:17:17 +03:30
Otabek
4f3bb61283
docs: update vite.md for latest Vite configuration in Vue projects (#817) 2024-10-22 20:09:47 +03:30
89 changed files with 1273 additions and 1107 deletions

View File

@ -14,3 +14,4 @@ runs:
with:
node-version: lts/*
cache: pnpm
registry-url: 'https://registry.npmjs.org'

View File

@ -21,6 +21,19 @@ jobs:
- name: Setup (Install Node & pnpm)
uses: ./.github/actions/setup
- name: Install dependencies
run: pnpm i --frozen-lockfile
- run: pnpm dlx changelogithub
env:
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
- name: Build CLI & Publish to npm
run: pnpm --filter shadcn-vue pub:release
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Build Module & Publish to npm
run: pnpm --filter shadcn-nuxt pub:release
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

View File

@ -1,7 +1,7 @@
<p align="center">
<img align="center" src="https://raw.githubusercontent.com/radix-vue/shadcn-vue/dev/apps/www/src/public/android-chrome-192x192.png" height="96" />
<h1 align="center">
shadcn-vue
shadcn-vue by Niklas Hermanns
</h1>
</p>
@ -31,3 +31,7 @@ All credits go to these open-source works and resources
## License
Licensed under the [MIT license](https://github.com/shadcn/ui/blob/main/LICENSE.md).
## Actions
- Test

View File

@ -4,7 +4,6 @@ import autoprefixer from 'autoprefixer'
import tailwind from 'tailwindcss'
import Icons from 'unplugin-icons/vite'
import { defineConfig } from 'vitepress'
import { cssVariables } from './theme/config/shiki'
import { siteConfig } from './theme/config/site'
import CodeWrapperPlugin from './theme/plugins/codewrapper'
@ -31,7 +30,6 @@ export default defineConfig({
['meta', { name: 'og:site_name', content: siteConfig.name }],
['meta', { name: 'og:image', content: siteConfig.ogImage }],
['meta', { name: 'twitter:image', content: siteConfig.ogImage }],
],
sitemap: {
@ -58,7 +56,6 @@ export default defineConfig({
srcDir: path.resolve(__dirname, '../src'),
markdown: {
theme: cssVariables,
codeTransformers: [
transformerMetaWordHighlight(),
],

View File

@ -2,10 +2,9 @@
import { useConfigStore } from '@/stores/config'
import { CircleHelp, Info, Monitor, Smartphone, Tablet } from 'lucide-vue-next'
import MagicString from 'magic-string'
import { codeToHtml } from 'shiki'
import { reactive, ref, watch } from 'vue'
import { compileScript, parse, walk } from 'vue/compiler-sfc'
import { cssVariables } from '../config/shiki'
import { highlight } from '../config/shiki'
import BlockCopyButton from './BlockCopyButton.vue'
import StyleSwitcher from './StyleSwitcher.vue'
@ -79,10 +78,7 @@ watch([style, codeConfig], async () => {
})
}
codeHtml.value = await codeToHtml(rawString.value, {
lang: 'vue',
theme: cssVariables,
})
codeHtml.value = highlight(rawString.value, 'vue')
}
catch (err) {
console.error(err)

View File

@ -4,9 +4,8 @@ import { cn } from '@/lib/utils'
import { useConfigStore } from '@/stores/config'
import { useClipboard } from '@vueuse/core'
import MagicString from 'magic-string'
import { codeToHtml } from 'shiki'
import { computed, ref, watch } from 'vue'
import { cssVariables } from '../config/shiki'
import { highlight } from '../config/shiki'
import CodeSandbox from './CodeSandbox.vue'
import ComponentLoader from './ComponentLoader.vue'
import Stackblitz from './Stackblitz.vue'
@ -37,10 +36,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(transformedRawString.value, {
lang: 'vue',
theme: cssVariables,
})
codeHtml.value = highlight(transformedRawString.value, 'vue')
}
catch (err) {
console.error(err)

View File

@ -43,7 +43,7 @@ const { isDark } = useData()
@click="setTheme(color)"
>
<span
class="h-5 w-5 rounded-full flex items-center justify-center"
class="h-5 w-5 rounded-full flex items-center justify-center shrink-0"
:style="{ backgroundColor: colors[color][7].rgb }"
>
<RadixIconsCheck

View File

@ -1,6 +1,41 @@
import { createCssVariablesTheme } from 'shiki'
import type { HighlighterCore } from 'shiki/core'
import type { ThemeOptions } from 'vitepress'
import { computedAsync } from '@vueuse/core'
import { createHighlighterCore } from 'shiki/core'
import { createJavaScriptRegexEngine } from 'shiki/engine/javascript'
export const cssVariables = createCssVariablesTheme({
variablePrefix: '--shiki-',
variableDefaults: {},
export const shikiThemes: ThemeOptions = {
light: 'github-light-default',
dark: 'github-dark-default',
}
export const highlighter = computedAsync<HighlighterCore>(async (onCancel) => {
const shiki = await createHighlighterCore({
engine: createJavaScriptRegexEngine(),
themes: [
() => import('shiki/themes/github-dark-default.mjs'),
() => import('shiki/themes/github-light-default.mjs'),
],
langs: [
() => import('shiki/langs/javascript.mjs'),
() => import('shiki/langs/vue.mjs'),
],
})
onCancel(() => shiki?.dispose())
return shiki
})
export function highlight(code: string, lang: string) {
if (!highlighter.value)
return code
return highlighter.value.codeToHtml(code, {
lang,
defaultColor: false,
themes: {
dark: 'github-dark-default',
light: 'github-light-default',
},
})
}

View File

@ -41,7 +41,7 @@ const toggleDark = useToggle(isDark)
const links = [
{
name: 'GitHub',
href: 'https://github.com/radix-vue/shadcn-vue',
href: 'https://github.com/unovue/shadcn-vue',
icon: RadixIconsGithubLogo,
},
// {
@ -209,7 +209,7 @@ watch(() => $route.path, (n) => {
<span class="inline-block ml-2">
Ported to Vue by
<a
href="https://github.com/radix-vue"
href="https://github.com/unovue"
target="_blank"
class="underline underline-offset-4 font-bold decoration-foreground"
>
@ -220,7 +220,7 @@ watch(() => $route.path, (n) => {
<span class="inline-block ml-2">
The code source is available on
<a
href="https://github.com/radix-vue/shadcn-vue"
href="https://github.com/unovue/shadcn-vue"
target="_blank"
class="underline underline-offset-4 font-bold decoration-foreground"
>

View File

@ -88,6 +88,8 @@
* {
@apply border-border;
scrollbar-width: thin;
scrollbar-color: hsl(var(--border)) transparent;
}
html {
-webkit-text-size-adjust: 100%;
@ -127,6 +129,15 @@
scrollbar-color: hsl(215.4 16.3% 56.9% / 0.3);
}
html.dark .shiki,
html.dark .shiki span {
color: var(--shiki-dark);
}
html:not(.dark) .shiki,
html:not(.dark) .shiki span {
color: var(--shiki-light);
}
.antialised {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
@ -154,7 +165,7 @@
}
div[class^="language-"] {
@apply mb-4 mt-6 max-h-[650px] overflow-x-auto md:rounded-lg border !bg-secondary-foreground dark:!bg-secondary
@apply mb-4 mt-6 max-h-[650px] overflow-x-auto md:rounded-lg border
}
pre {
@apply py-4;

View File

@ -350,7 +350,7 @@
padding: 0 24px; */
width: calc(100% + 2 * 24px);
display: inline-block;
@apply bg-[hsl(var(--foreground))] dark:bg-[hsl(var(--background)_/_50%)]
@apply bg-[hsl(var(--muted))] dark:bg-[hsl(var(--muted))]
}
.vp-doc [class*='language-'] code .highlighted.error {

View File

@ -1,7 +1,7 @@
{
"name": "www",
"type": "module",
"version": "0.11.0",
"version": "0.11.3",
"files": [
"dist"
],
@ -68,7 +68,7 @@
"markdown-it": "^14.1.0",
"pathe": "^1.1.2",
"rimraf": "^6.0.1",
"shiki": "^1.17.7",
"shiki": "^1.22.1",
"tailwind-merge": "^2.5.2",
"tailwindcss": "^3.4.12",
"tsx": "^4.19.1",

View File

@ -15,7 +15,7 @@ npx shadcn-vue@latest init
You will be asked a few questions to configure `components.json`:
```txt:line-numbers
```ansi:line-numbers
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
@ -29,7 +29,7 @@ Configure the import alias for utils: @/lib/utils
### Options
```txt
```ansi
Usage: shadcn-vue init [options]
initialize your project and install dependencies
@ -50,7 +50,7 @@ npx shadcn-vue@latest add [component]
You will be presented with a list of components to choose from:
```txt
```ansi
Which components would you like to add? Space to select. Return to submit.
◯ accordion
@ -67,7 +67,7 @@ Which components would you like to add? Space to select. Return to submit.
### Options
```txt
```ansi
Usage: shadcn-vue add [options] [components...]
add components to your project
@ -90,7 +90,7 @@ Use the `update` command to update components in your project. This will overwri
We plan on improving this command in the future to improve the update experience.
```txt
```ansi
Usage: shadcn-vue update [options] [components...]
update components in your project

View File

@ -403,6 +403,7 @@ By passing the `form` as props, you can control and use the method provided by `
```vue
<script setup lang="ts">
import { AutoForm } from '@/components/ui/auto-form'
import { toTypedSchema } from '@vee-validate/zod'
import { useForm } from 'vee-validate'
import * as z from 'zod'

View File

@ -76,7 +76,7 @@ const value = ref('')
<CommandItem
v-for="framework in frameworks"
:key="framework.value"
:value="framework"
:value="framework.value"
@select="open = false"
>
<Check

View File

@ -1,7 +1,7 @@
---
title: Data Table
description: Powerful table and datagrids built using TanStack Table.
primitive: https://tanstack.com/table/v8/docs/guide/introduction
primitive: https://tanstack.com/table/v8/docs/introduction
---
<ComponentPreview name="DataTableDemo" />
@ -102,7 +102,7 @@ export const payments: Payment[] = [
Start by creating the following file structure:
```txt
```ansi
components
└── payments
├── columns.ts

View File

@ -48,6 +48,19 @@ import { Switch } from '@/components/ui/switch'
</template>
```
# Add icon inside switch thumb
```vue
<template>
<Switch :checked="isDark" @update:checked="toggleTheme">
<template #thumb>
<Icon v-if="isDark" icon="lucide:moon" class="size-3" />
<Icon v-else icon="lucide:sun" class="size-3" />
</template>
</Switch>
</template>
```
## Examples
### Form

View File

@ -101,13 +101,13 @@ You can use the `pnpm --filter=[WORKSPACE]` command to start the development pro
1. To run the `shadcn-vue.com` website:
```
```bash
pnpm dev
```
2. To run the `shadcn-vue` cli package:
```
```bash
pnpm dev:cli
```

View File

@ -17,7 +17,7 @@ npm create astro@latest
You will be asked a few questions to configure your project:
```txt:line-numbers
```ansi:line-numbers
- Where should we create your new project?
./your-app-name
- How would you like to start your new project?
@ -99,7 +99,7 @@ npx shadcn-vue@latest init
You will be asked a few questions to configure `components.json`:
```txt:line-numbers
```ansi:line-numbers
Would you like to use TypeScript (recommended)? no / yes
Which framework are you using? Astro
Which style would you like to use? Default

View File

@ -25,7 +25,7 @@ npx shadcn-vue@latest init
You will be asked a few questions to configure `components.json`:
```txt:line-numbers
```ansi:line-numbers
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

View File

@ -213,7 +213,7 @@ npx shadcn-vue@latest init
You will be asked a few questions to configure `components.json`:
```txt:line-numbers
```ansi:line-numbers
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
@ -231,7 +231,7 @@ Write configuration to components.json. Proceed? > Y/n
Here's the default structure of Nuxt app. You can use this as a reference:
```txt {6-16,20-21}
```ansi {6-16,20-21}
.
├── pages
│ ├── index.vue

View File

@ -44,28 +44,22 @@ Install `tailwindcss` and its peer dependencies, then generate your `tailwind.co
#### `vite.config`
```typescript {5,6,9-13}
import path from 'node:path'
import vue from '@vitejs/plugin-vue'
import autoprefixer from 'autoprefixer'
```typescript {2,3,8-12}
import vue from '@vitejs/plugin-vue'
import autoprefixer from 'autoprefixer'
import tailwind from 'tailwindcss'
import { defineConfig } from 'vite'
import tailwind from 'tailwindcss'
import { defineConfig } from 'vite'
export default defineConfig({
css: {
postcss: {
plugins: [tailwind(), autoprefixer()],
},
// https://vite.dev/config/
export default defineConfig({
css: {
postcss: {
plugins: [tailwind(), autoprefixer()],
},
plugins: [vue()],
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
},
},
})
```
},
plugins: [vue()],
})
```
</TabMarkdown>
@ -121,14 +115,14 @@ Add the code below to the vite.config.ts so your app can resolve paths without e
npm i -D @types/node
```
```typescript {15-19}
import path from 'node:path'
```typescript {1,15-19}
import { fileURLToPath, URL } from 'node:url'
import vue from '@vitejs/plugin-vue'
import autoprefixer from 'autoprefixer'
import tailwind from 'tailwindcss'
import { defineConfig } from 'vite'
// https://vite.dev/config/
export default defineConfig({
css: {
postcss: {
@ -138,9 +132,9 @@ export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
},
},
'@': fileURLToPath(new URL('./src', import.meta.url))
}
}
})
```
@ -160,7 +154,7 @@ npx shadcn-vue@latest init
You will be asked a few questions to configure `components.json`:
```txt:line-numbers
```ansi:line-numbers
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

View File

@ -289,7 +289,7 @@ function setActiveTeam(team: typeof data.teams[number]) {
>
<SidebarMenuItem>
<CollapsibleTrigger as-child>
<SidebarMenuButton tooltip="item.title">
<SidebarMenuButton :tooltip="item.title">
<component :is="item.icon" />
<span>{{ item.title }}</span>
<ChevronRight class="ml-auto transition-transform duration-200 group-data-[state=open]/collapsible:rotate-90" />

View File

@ -42,7 +42,7 @@ const itemsToDisplay = 3
const firstLabel = computed(() => items.value[0]?.label)
const allButLastTwoItems = computed(() => items.value.slice(1, -2))
const remainingItems = computed(() => items.value.slice(-itemsToDisplay + 1))
const remainingItems = computed(() => items.value.slice(-Math.min(itemsToDisplay, items.value.length) + 1))
</script>
<template>

View File

@ -32,13 +32,13 @@ import { Label } from '@/lib/registry/default/ui/label'
<Label for="name" class="text-right">
Name
</Label>
<Input id="name" value="Pedro Duarte" class="col-span-3" />
<Input id="name" default-value="Pedro Duarte" class="col-span-3" />
</div>
<div class="grid grid-cols-4 items-center gap-4">
<Label for="username" class="text-right">
Username
</Label>
<Input id="username" value="@peduarte" class="col-span-3" />
<Input id="username" default-value="@peduarte" class="col-span-3" />
</div>
</div>
<DialogFooter>

View File

@ -38,7 +38,7 @@ function onSubmit(values: any) {
</script>
<template>
<Form v-slot="{ submitForm }" as="" :validation-schema="formSchema" @submit="onSubmit">
<Form v-slot="{ handleSubmit }" as="" keep-values :validation-schema="formSchema">
<Dialog>
<DialogTrigger as-child>
<Button variant="outline">
@ -53,7 +53,7 @@ function onSubmit(values: any) {
</DialogDescription>
</DialogHeader>
<form @submit="submitForm">
<form id="dialogForm" @submit="handleSubmit($event, onSubmit)">
<FormField v-slot="{ componentField }" name="username">
<FormItem>
<FormLabel>Username</FormLabel>

View File

@ -33,13 +33,13 @@ import {
<Label for="name" class="text-right">
Name
</Label>
<Input id="name" value="Pedro Duarte" class="col-span-3" />
<Input id="name" default-value="Pedro Duarte" class="col-span-3" />
</div>
<div class="grid grid-cols-4 items-center gap-4">
<Label for="username" class="text-right">
Username
</Label>
<Input id="username" value="@peduarte" class="col-span-3" />
<Input id="username" default-value="@peduarte" class="col-span-3" />
</div>
</div>
<SheetFooter>

View File

@ -1,3 +1,4 @@
import type { InputComponents } from './interface'
import AutoFormFieldArray from './AutoFormFieldArray.vue'
import AutoFormFieldBoolean from './AutoFormFieldBoolean.vue'
import AutoFormFieldDate from './AutoFormFieldDate.vue'
@ -7,7 +8,7 @@ import AutoFormFieldInput from './AutoFormFieldInput.vue'
import AutoFormFieldNumber from './AutoFormFieldNumber.vue'
import AutoFormFieldObject from './AutoFormFieldObject.vue'
export const INPUT_COMPONENTS = {
export const INPUT_COMPONENTS: InputComponents = {
date: AutoFormFieldDate,
select: AutoFormFieldEnum,
radio: AutoFormFieldEnum,

View File

@ -18,6 +18,20 @@ export interface Shape {
schema?: ZodAny
}
export interface InputComponents {
date: Component;
select: Component;
radio: Component;
checkbox: Component;
switch: Component;
textarea: Component;
number: Component;
string: Component;
file: Component;
array: Component;
object: Component;
};
export interface ConfigItem {
/** Value for the `FormLabel` */
label?: string

View File

@ -3,7 +3,7 @@ import { cva, type VariantProps } from 'class-variance-authority'
export { default as Button } from './Button.vue'
export const buttonVariants = cva(
'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
{
variants: {
variant: {

View File

@ -6,6 +6,7 @@ export { default as NavigationMenuItem } from './NavigationMenuItem.vue'
export { default as NavigationMenuLink } from './NavigationMenuLink.vue'
export { default as NavigationMenuList } from './NavigationMenuList.vue'
export { default as NavigationMenuTrigger } from './NavigationMenuTrigger.vue'
export { default as NavigationMenuViewport } from './NavigationMenuViewport.vue'
export const navigationMenuTriggerStyle = cva(
'group inline-flex h-10 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[active]:bg-accent/50 data-[state=open]:bg-accent/50',

View File

@ -19,7 +19,7 @@ const forwardedProps = useForwardProps(delegatedProps)
<SelectTrigger
v-bind="forwardedProps"
:class="cn(
'flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:truncate text-start',
'flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background data-[placeholder]:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:truncate text-start',
props.class,
)"
>

View File

@ -1,7 +1,6 @@
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import Sheet from '@/lib/registry/default/ui/sheet/Sheet.vue'
import SheetContent from '@/lib/registry/default/ui/sheet/SheetContent.vue'
import type { SidebarProps } from '.'
import { Sheet, SheetContent } from '@/lib/registry/default/ui/sheet'
import { cn } from '@/lib/utils'
import { SIDEBAR_WIDTH_MOBILE, useSidebar } from './utils'
@ -9,12 +8,7 @@ defineOptions({
inheritAttrs: false,
})
const props = withDefaults(defineProps<{
side?: 'left' | 'right'
variant?: 'sidebar' | 'floating' | 'inset'
collapsible?: 'offcanvas' | 'icon' | 'none'
class?: HTMLAttributes['class']
}>(), {
const props = withDefaults(defineProps<SidebarProps>(), {
side: 'left',
variant: 'sidebar',
collapsible: 'offcanvas',
@ -36,6 +30,7 @@ const { isMobile, state, openMobile, setOpenMobile } = useSidebar()
<SheetContent
data-sidebar="sidebar"
data-mobile="true"
:side="side"
class="w-[--sidebar-width] bg-sidebar p-0 text-sidebar-foreground [&>button]:hidden"
:style="{
'--sidebar-width': SIDEBAR_WIDTH_MOBILE,

View File

@ -1,6 +1,6 @@
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import Input from '@/lib/registry/default/ui/input/Input.vue'
import { Input } from '@/lib/registry/default/ui/input'
import { cn } from '@/lib/utils'
const props = defineProps<{

View File

@ -28,5 +28,7 @@ const props = withDefaults(defineProps<PrimitiveProps & {
)"
:as="as"
:as-child="asChild"
/>
>
<slot />
</Primitive>
</template>

View File

@ -1,7 +1,5 @@
<script setup lang="ts">
import Tooltip from '@/lib/registry/default/ui/tooltip/Tooltip.vue'
import TooltipContent from '@/lib/registry/default/ui/tooltip/TooltipContent.vue'
import TooltipTrigger from '@/lib/registry/default/ui/tooltip/TooltipTrigger.vue'
import { Tooltip, TooltipContent, TooltipTrigger } from '@/lib/registry/default/ui/tooltip'
import { type Component, computed } from 'vue'
import SidebarMenuButtonChild, { type SidebarMenuButtonProps } from './SidebarMenuButtonChild.vue'
import { useSidebar } from './utils'

View File

@ -1,5 +1,5 @@
<script setup lang="ts">
import Skeleton from '@/lib/registry/default/ui/skeleton/Skeleton.vue'
import { Skeleton } from '@/lib/registry/default/ui/skeleton'
import { cn } from '@/lib/utils'
import { computed, type HTMLAttributes } from 'vue'

View File

@ -1,6 +1,6 @@
<script setup lang="ts">
import { cn } from '@/lib/utils'
import { useEventListener, useVModel } from '@vueuse/core'
import { useEventListener, useMediaQuery, useVModel } from '@vueuse/core'
import { TooltipProvider } from 'radix-vue'
import { computed, type HTMLAttributes, type Ref, ref } from 'vue'
import { provideSidebarContext, SIDEBAR_COOKIE_MAX_AGE, SIDEBAR_COOKIE_NAME, SIDEBAR_KEYBOARD_SHORTCUT, SIDEBAR_WIDTH, SIDEBAR_WIDTH_ICON } from './utils'
@ -18,7 +18,7 @@ const emits = defineEmits<{
'update:open': [open: boolean]
}>()
const isMobile = ref(false) // useIsMobile()
const isMobile = useMediaQuery('(max-width: 768px)')
const openMobile = ref(false)
const open = useVModel(props, 'open', emits, {
@ -30,7 +30,7 @@ function setOpen(value: boolean) {
open.value = value // emits('update:open', value)
// This sets the cookie to keep the sidebar state.
document.cookie = `${SIDEBAR_COOKIE_NAME}=${open}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`
document.cookie = `${SIDEBAR_COOKIE_NAME}=${open.value}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`
}
function setOpenMobile(value: boolean) {
@ -39,7 +39,7 @@ function setOpenMobile(value: boolean) {
// Helper to toggle the sidebar.
function toggleSidebar() {
return isMobile.value ? setOpenMobile(!open.value) : setOpen(!open.value)
return isMobile.value ? setOpenMobile(!openMobile.value) : setOpen(!open.value)
}
useEventListener('keydown', (event: KeyboardEvent) => {
@ -72,6 +72,7 @@ provideSidebarContext({
'--sidebar-width-icon': SIDEBAR_WIDTH_ICON,
}"
:class="cn('group/sidebar-wrapper flex min-h-svh w-full text-sidebar-foreground has-[[data-variant=inset]]:bg-sidebar', props.class)"
v-bind="$attrs"
>
<slot />
</div>

View File

@ -1,6 +1,6 @@
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import Separator from '@/lib/registry/default/ui/separator/Separator.vue'
import { Separator } from '@/lib/registry/default/ui/separator'
import { cn } from '@/lib/utils'
const props = defineProps<{

View File

@ -1,6 +1,6 @@
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import Button from '@/lib/registry/default/ui/button/Button.vue'
import { Button } from '@/lib/registry/default/ui/button'
import { cn } from '@/lib/utils'
import { PanelLeft } from 'lucide-vue-next'
import { useSidebar } from './utils'

View File

@ -1,5 +1,13 @@
import type { HTMLAttributes } from 'vue'
import { cva, type VariantProps } from 'class-variance-authority'
export interface SidebarProps {
side?: 'left' | 'right'
variant?: 'sidebar' | 'floating' | 'inset'
collapsible?: 'offcanvas' | 'icon' | 'none'
class?: HTMLAttributes['class']
}
export { default as Sidebar } from './Sidebar.vue'
export { default as SidebarContent } from './SidebarContent.vue'
export { default as SidebarFooter } from './SidebarFooter.vue'

View File

@ -31,7 +31,9 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits)
)"
>
<SwitchThumb
:class="cn('pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0')"
/>
:class="cn('pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5')"
>
<slot name="thumb" />
</SwitchThumb>
</SwitchRoot>
</template>

View File

@ -289,7 +289,7 @@ function setActiveTeam(team: typeof data.teams[number]) {
>
<SidebarMenuItem>
<CollapsibleTrigger as-child>
<SidebarMenuButton tooltip="item.title">
<SidebarMenuButton :tooltip="item.title">
<component :is="item.icon" />
<span>{{ item.title }}</span>
<ChevronRight class="ml-auto transition-transform duration-200 group-data-[state=open]/collapsible:rotate-90" />

View File

@ -42,7 +42,7 @@ const itemsToDisplay = 3
const firstLabel = computed(() => items.value[0]?.label)
const allButLastTwoItems = computed(() => items.value.slice(1, -2))
const remainingItems = computed(() => items.value.slice(-itemsToDisplay + 1))
const remainingItems = computed(() => items.value.slice(-Math.min(itemsToDisplay, items.value.length) + 1))
</script>
<template>

View File

@ -38,7 +38,7 @@ function onSubmit(values: any) {
</script>
<template>
<Form v-slot="{ submitForm }" as="" keep-values :validation-schema="formSchema" @submit="onSubmit">
<Form v-slot="{ handleSubmit }" as="" keep-values :validation-schema="formSchema">
<Dialog>
<DialogTrigger as-child>
<Button variant="outline">
@ -53,7 +53,7 @@ function onSubmit(values: any) {
</DialogDescription>
</DialogHeader>
<form @submit="submitForm">
<form id="dialogForm" @submit="handleSubmit($event, onSubmit)">
<FormField v-slot="{ componentField }" name="username">
<FormItem>
<FormLabel>Username</FormLabel>

View File

@ -1,3 +1,4 @@
import type { InputComponents } from './interface'
import AutoFormFieldArray from './AutoFormFieldArray.vue'
import AutoFormFieldBoolean from './AutoFormFieldBoolean.vue'
import AutoFormFieldDate from './AutoFormFieldDate.vue'
@ -7,7 +8,7 @@ import AutoFormFieldInput from './AutoFormFieldInput.vue'
import AutoFormFieldNumber from './AutoFormFieldNumber.vue'
import AutoFormFieldObject from './AutoFormFieldObject.vue'
export const INPUT_COMPONENTS = {
export const INPUT_COMPONENTS: InputComponents = {
date: AutoFormFieldDate,
select: AutoFormFieldEnum,
radio: AutoFormFieldEnum,

View File

@ -18,6 +18,20 @@ export interface Shape {
schema?: ZodAny
}
export interface InputComponents {
date: Component;
select: Component;
radio: Component;
checkbox: Component;
switch: Component;
textarea: Component;
number: Component;
string: Component;
file: Component;
array: Component;
object: Component;
};
export interface ConfigItem {
/** Value for the `FormLabel` */
label?: string

View File

@ -3,7 +3,7 @@ import { cva, type VariantProps } from 'class-variance-authority'
export { default as Button } from './Button.vue'
export const buttonVariants = cva(
'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50',
'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
{
variants: {
variant: {

View File

@ -6,6 +6,7 @@ export { default as NavigationMenuItem } from './NavigationMenuItem.vue'
export { default as NavigationMenuLink } from './NavigationMenuLink.vue'
export { default as NavigationMenuList } from './NavigationMenuList.vue'
export { default as NavigationMenuTrigger } from './NavigationMenuTrigger.vue'
export { default as NavigationMenuViewport } from './NavigationMenuViewport.vue'
export const navigationMenuTriggerStyle = cva(
'group inline-flex h-9 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[active]:bg-accent/50 data-[state=open]:bg-accent/50',

View File

@ -19,7 +19,7 @@ const forwardedProps = useForwardProps(delegatedProps)
<SelectTrigger
v-bind="forwardedProps"
:class="cn(
'flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:truncate text-start',
'flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background data-[placeholder]:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:truncate text-start',
props.class,
)"
>

View File

@ -1,7 +1,6 @@
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import Sheet from '@/lib/registry/new-york/ui/sheet/Sheet.vue'
import SheetContent from '@/lib/registry/new-york/ui/sheet/SheetContent.vue'
import type { SidebarProps } from '.'
import { Sheet, SheetContent } from '@/lib/registry/new-york/ui/sheet'
import { cn } from '@/lib/utils'
import { SIDEBAR_WIDTH_MOBILE, useSidebar } from './utils'
@ -9,12 +8,7 @@ defineOptions({
inheritAttrs: false,
})
const props = withDefaults(defineProps<{
side?: 'left' | 'right'
variant?: 'sidebar' | 'floating' | 'inset'
collapsible?: 'offcanvas' | 'icon' | 'none'
class?: HTMLAttributes['class']
}>(), {
const props = withDefaults(defineProps<SidebarProps>(), {
side: 'left',
variant: 'sidebar',
collapsible: 'offcanvas',
@ -36,6 +30,7 @@ const { isMobile, state, openMobile, setOpenMobile } = useSidebar()
<SheetContent
data-sidebar="sidebar"
data-mobile="true"
:side="side"
class="w-[--sidebar-width] bg-sidebar p-0 text-sidebar-foreground [&>button]:hidden"
:style="{
'--sidebar-width': SIDEBAR_WIDTH_MOBILE,

View File

@ -1,6 +1,6 @@
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import Input from '@/lib/registry/new-york/ui/input/Input.vue'
import { Input } from '@/lib/registry/new-york/ui/input'
import { cn } from '@/lib/utils'
const props = defineProps<{

View File

@ -28,5 +28,7 @@ const props = withDefaults(defineProps<PrimitiveProps & {
)"
:as="as"
:as-child="asChild"
/>
>
<slot />
</Primitive>
</template>

View File

@ -1,7 +1,5 @@
<script setup lang="ts">
import Tooltip from '@/lib/registry/new-york/ui/tooltip/Tooltip.vue'
import TooltipContent from '@/lib/registry/new-york/ui/tooltip/TooltipContent.vue'
import TooltipTrigger from '@/lib/registry/new-york/ui/tooltip/TooltipTrigger.vue'
import { Tooltip, TooltipContent, TooltipTrigger } from '@/lib/registry/new-york/ui/tooltip'
import { type Component, computed } from 'vue'
import SidebarMenuButtonChild, { type SidebarMenuButtonProps } from './SidebarMenuButtonChild.vue'
import { useSidebar } from './utils'

View File

@ -1,5 +1,5 @@
<script setup lang="ts">
import Skeleton from '@/lib/registry/new-york/ui/skeleton/Skeleton.vue'
import { Skeleton } from '@/lib/registry/new-york/ui/skeleton'
import { cn } from '@/lib/utils'
import { computed, type HTMLAttributes } from 'vue'

View File

@ -1,6 +1,6 @@
<script setup lang="ts">
import { cn } from '@/lib/utils'
import { useEventListener, useVModel } from '@vueuse/core'
import { useEventListener, useMediaQuery, useVModel } from '@vueuse/core'
import { TooltipProvider } from 'radix-vue'
import { computed, type HTMLAttributes, type Ref, ref } from 'vue'
import { provideSidebarContext, SIDEBAR_COOKIE_MAX_AGE, SIDEBAR_COOKIE_NAME, SIDEBAR_KEYBOARD_SHORTCUT, SIDEBAR_WIDTH, SIDEBAR_WIDTH_ICON } from './utils'
@ -18,7 +18,7 @@ const emits = defineEmits<{
'update:open': [open: boolean]
}>()
const isMobile = ref(false) // useIsMobile()
const isMobile = useMediaQuery('(max-width: 768px)')
const openMobile = ref(false)
const open = useVModel(props, 'open', emits, {
@ -30,7 +30,7 @@ function setOpen(value: boolean) {
open.value = value // emits('update:open', value)
// This sets the cookie to keep the sidebar state.
document.cookie = `${SIDEBAR_COOKIE_NAME}=${open}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`
document.cookie = `${SIDEBAR_COOKIE_NAME}=${open.value}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`
}
function setOpenMobile(value: boolean) {
@ -39,7 +39,7 @@ function setOpenMobile(value: boolean) {
// Helper to toggle the sidebar.
function toggleSidebar() {
return isMobile.value ? setOpenMobile(!open.value) : setOpen(!open.value)
return isMobile.value ? setOpenMobile(!openMobile.value) : setOpen(!open.value)
}
useEventListener('keydown', (event: KeyboardEvent) => {
@ -72,6 +72,7 @@ provideSidebarContext({
'--sidebar-width-icon': SIDEBAR_WIDTH_ICON,
}"
:class="cn('group/sidebar-wrapper flex min-h-svh w-full text-sidebar-foreground has-[[data-variant=inset]]:bg-sidebar', props.class)"
v-bind="$attrs"
>
<slot />
</div>

View File

@ -1,6 +1,6 @@
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import Separator from '@/lib/registry/new-york/ui/separator/Separator.vue'
import { Separator } from '@/lib/registry/new-york/ui/separator'
import { cn } from '@/lib/utils'
const props = defineProps<{

View File

@ -1,6 +1,6 @@
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import Button from '@/lib/registry/new-york/ui/button/Button.vue'
import { Button } from '@/lib/registry/new-york/ui/button'
import { cn } from '@/lib/utils'
import { PanelLeft } from 'lucide-vue-next'
import { useSidebar } from './utils'

View File

@ -1,5 +1,13 @@
import type { HTMLAttributes } from 'vue'
import { cva, type VariantProps } from 'class-variance-authority'
export interface SidebarProps {
side?: 'left' | 'right'
variant?: 'sidebar' | 'floating' | 'inset'
collapsible?: 'offcanvas' | 'icon' | 'none'
class?: HTMLAttributes['class']
}
export { default as Sidebar } from './Sidebar.vue'
export { default as SidebarContent } from './SidebarContent.vue'
export { default as SidebarFooter } from './SidebarFooter.vue'

View File

@ -32,6 +32,8 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits)
>
<SwitchThumb
:class="cn('pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0')"
/>
>
<slot name="thumb" />
</SwitchThumb>
</SwitchRoot>
</template>

View File

@ -749,16 +749,13 @@
"@vueuse/core"
],
"registryDependencies": [
"Sheet.vue",
"SheetContent.vue",
"sheet",
"utils",
"Input.vue",
"Tooltip.vue",
"TooltipContent.vue",
"TooltipTrigger.vue",
"Skeleton.vue",
"Separator.vue",
"Button.vue"
"input",
"tooltip",
"skeleton",
"separator",
"button"
],
"files": [
"ui/sidebar/Sidebar.vue",

View File

@ -68,7 +68,7 @@
},
{
"name": "constant.ts",
"content": "import AutoFormFieldArray from './AutoFormFieldArray.vue'\nimport AutoFormFieldBoolean from './AutoFormFieldBoolean.vue'\nimport AutoFormFieldDate from './AutoFormFieldDate.vue'\nimport AutoFormFieldEnum from './AutoFormFieldEnum.vue'\nimport AutoFormFieldFile from './AutoFormFieldFile.vue'\nimport AutoFormFieldInput from './AutoFormFieldInput.vue'\nimport AutoFormFieldNumber from './AutoFormFieldNumber.vue'\nimport AutoFormFieldObject from './AutoFormFieldObject.vue'\n\nexport const INPUT_COMPONENTS = {\n date: AutoFormFieldDate,\n select: AutoFormFieldEnum,\n radio: AutoFormFieldEnum,\n checkbox: AutoFormFieldBoolean,\n switch: AutoFormFieldBoolean,\n textarea: AutoFormFieldInput,\n number: AutoFormFieldNumber,\n string: AutoFormFieldInput,\n file: AutoFormFieldFile,\n array: AutoFormFieldArray,\n object: AutoFormFieldObject,\n}\n\n/**\n * Define handlers for specific Zod types.\n * You can expand this object to support more types.\n */\nexport const DEFAULT_ZOD_HANDLERS: {\n [key: string]: keyof typeof INPUT_COMPONENTS\n} = {\n ZodString: 'string',\n ZodBoolean: 'checkbox',\n ZodDate: 'date',\n ZodEnum: 'select',\n ZodNativeEnum: 'select',\n ZodNumber: 'number',\n ZodArray: 'array',\n ZodObject: 'object',\n}\n"
"content": "import type { InputComponents } from './interface'\nimport AutoFormFieldArray from './AutoFormFieldArray.vue'\nimport AutoFormFieldBoolean from './AutoFormFieldBoolean.vue'\nimport AutoFormFieldDate from './AutoFormFieldDate.vue'\nimport AutoFormFieldEnum from './AutoFormFieldEnum.vue'\nimport AutoFormFieldFile from './AutoFormFieldFile.vue'\nimport AutoFormFieldInput from './AutoFormFieldInput.vue'\nimport AutoFormFieldNumber from './AutoFormFieldNumber.vue'\nimport AutoFormFieldObject from './AutoFormFieldObject.vue'\n\nexport const INPUT_COMPONENTS: InputComponents = {\n date: AutoFormFieldDate,\n select: AutoFormFieldEnum,\n radio: AutoFormFieldEnum,\n checkbox: AutoFormFieldBoolean,\n switch: AutoFormFieldBoolean,\n textarea: AutoFormFieldInput,\n number: AutoFormFieldNumber,\n string: AutoFormFieldInput,\n file: AutoFormFieldFile,\n array: AutoFormFieldArray,\n object: AutoFormFieldObject,\n}\n\n/**\n * Define handlers for specific Zod types.\n * You can expand this object to support more types.\n */\nexport const DEFAULT_ZOD_HANDLERS: {\n [key: string]: keyof typeof INPUT_COMPONENTS\n} = {\n ZodString: 'string',\n ZodBoolean: 'checkbox',\n ZodDate: 'date',\n ZodEnum: 'select',\n ZodNativeEnum: 'select',\n ZodNumber: 'number',\n ZodArray: 'array',\n ZodObject: 'object',\n}\n"
},
{
"name": "dependencies.ts",
@ -80,7 +80,7 @@
},
{
"name": "interface.ts",
"content": "import type { Component, InputHTMLAttributes } from 'vue'\nimport type { z, ZodAny } from 'zod'\nimport type { INPUT_COMPONENTS } from './constant'\n\nexport interface FieldProps {\n fieldName: string\n label?: string\n required?: boolean\n config?: ConfigItem\n disabled?: boolean\n}\n\nexport interface Shape {\n type: string\n default?: any\n required?: boolean\n options?: string[]\n schema?: ZodAny\n}\n\nexport interface ConfigItem {\n /** Value for the `FormLabel` */\n label?: string\n /** Value for the `FormDescription` */\n description?: string\n /** Pick which component to be rendered. */\n component?: keyof typeof INPUT_COMPONENTS | Component\n /** Hide `FormLabel`. */\n hideLabel?: boolean\n inputProps?: InputHTMLAttributes\n}\n\n// Define a type to unwrap an array\ntype UnwrapArray<T> = T extends (infer U)[] ? U : never\n\nexport type Config<SchemaType extends object> = {\n // If SchemaType.key is an object, create a nested Config, otherwise ConfigItem\n [Key in keyof SchemaType]?:\n SchemaType[Key] extends any[]\n ? UnwrapArray<Config<SchemaType[Key]>>\n : SchemaType[Key] extends object\n ? Config<SchemaType[Key]>\n : ConfigItem;\n}\n\nexport enum DependencyType {\n DISABLES,\n REQUIRES,\n HIDES,\n SETS_OPTIONS,\n}\n\ninterface BaseDependency<SchemaType extends z.infer<z.ZodObject<any, any>>> {\n sourceField: keyof SchemaType\n type: DependencyType\n targetField: keyof SchemaType\n when: (sourceFieldValue: any, targetFieldValue: any) => boolean\n}\n\nexport type ValueDependency<SchemaType extends z.infer<z.ZodObject<any, any>>> =\n BaseDependency<SchemaType> & {\n type:\n | DependencyType.DISABLES\n | DependencyType.REQUIRES\n | DependencyType.HIDES\n }\n\nexport type EnumValues = readonly [string, ...string[]]\n\nexport type OptionsDependency<\n SchemaType extends z.infer<z.ZodObject<any, any>>,\n> = BaseDependency<SchemaType> & {\n type: DependencyType.SETS_OPTIONS\n\n // Partial array of values from sourceField that will trigger the dependency\n options: EnumValues\n}\n\nexport type Dependency<SchemaType extends z.infer<z.ZodObject<any, any>>> =\n | ValueDependency<SchemaType>\n | OptionsDependency<SchemaType>\n"
"content": "import type { Component, InputHTMLAttributes } from 'vue'\nimport type { z, ZodAny } from 'zod'\nimport type { INPUT_COMPONENTS } from './constant'\n\nexport interface FieldProps {\n fieldName: string\n label?: string\n required?: boolean\n config?: ConfigItem\n disabled?: boolean\n}\n\nexport interface Shape {\n type: string\n default?: any\n required?: boolean\n options?: string[]\n schema?: ZodAny\n}\n\nexport interface InputComponents {\n date: Component;\n select: Component;\n radio: Component;\n checkbox: Component;\n switch: Component;\n textarea: Component;\n number: Component;\n string: Component;\n file: Component;\n array: Component;\n object: Component;\n};\n\nexport interface ConfigItem {\n /** Value for the `FormLabel` */\n label?: string\n /** Value for the `FormDescription` */\n description?: string\n /** Pick which component to be rendered. */\n component?: keyof typeof INPUT_COMPONENTS | Component\n /** Hide `FormLabel`. */\n hideLabel?: boolean\n inputProps?: InputHTMLAttributes\n}\n\n// Define a type to unwrap an array\ntype UnwrapArray<T> = T extends (infer U)[] ? U : never\n\nexport type Config<SchemaType extends object> = {\n // If SchemaType.key is an object, create a nested Config, otherwise ConfigItem\n [Key in keyof SchemaType]?:\n SchemaType[Key] extends any[]\n ? UnwrapArray<Config<SchemaType[Key]>>\n : SchemaType[Key] extends object\n ? Config<SchemaType[Key]>\n : ConfigItem;\n}\n\nexport enum DependencyType {\n DISABLES,\n REQUIRES,\n HIDES,\n SETS_OPTIONS,\n}\n\ninterface BaseDependency<SchemaType extends z.infer<z.ZodObject<any, any>>> {\n sourceField: keyof SchemaType\n type: DependencyType\n targetField: keyof SchemaType\n when: (sourceFieldValue: any, targetFieldValue: any) => boolean\n}\n\nexport type ValueDependency<SchemaType extends z.infer<z.ZodObject<any, any>>> =\n BaseDependency<SchemaType> & {\n type:\n | DependencyType.DISABLES\n | DependencyType.REQUIRES\n | DependencyType.HIDES\n }\n\nexport type EnumValues = readonly [string, ...string[]]\n\nexport type OptionsDependency<\n SchemaType extends z.infer<z.ZodObject<any, any>>,\n> = BaseDependency<SchemaType> & {\n type: DependencyType.SETS_OPTIONS\n\n // Partial array of values from sourceField that will trigger the dependency\n options: EnumValues\n}\n\nexport type Dependency<SchemaType extends z.infer<z.ZodObject<any, any>>> =\n | ValueDependency<SchemaType>\n | OptionsDependency<SchemaType>\n"
},
{
"name": "utils.ts",

View File

@ -11,7 +11,7 @@
},
{
"name": "index.ts",
"content": "import { cva, type VariantProps } from 'class-variance-authority'\n\nexport { default as Button } from './Button.vue'\n\nexport const buttonVariants = cva(\n 'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',\n {\n variants: {\n variant: {\n default:\n 'bg-primary text-primary-foreground shadow hover:bg-primary/90',\n destructive:\n 'bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90',\n outline:\n 'border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground',\n secondary:\n 'bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80',\n ghost: 'hover:bg-accent hover:text-accent-foreground',\n link: 'text-primary underline-offset-4 hover:underline',\n },\n size: {\n default: 'h-9 px-4 py-2',\n sm: 'h-8 rounded-md px-3 text-xs',\n lg: 'h-10 rounded-md px-8',\n icon: 'h-9 w-9',\n },\n },\n defaultVariants: {\n variant: 'default',\n size: 'default',\n },\n },\n)\n\nexport type ButtonVariants = VariantProps<typeof buttonVariants>\n"
"content": "import { cva, type VariantProps } from 'class-variance-authority'\n\nexport { default as Button } from './Button.vue'\n\nexport const buttonVariants = cva(\n 'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',\n {\n variants: {\n variant: {\n default:\n 'bg-primary text-primary-foreground shadow hover:bg-primary/90',\n destructive:\n 'bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90',\n outline:\n 'border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground',\n secondary:\n 'bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80',\n ghost: 'hover:bg-accent hover:text-accent-foreground',\n link: 'text-primary underline-offset-4 hover:underline',\n },\n size: {\n default: 'h-9 px-4 py-2',\n sm: 'h-8 rounded-md px-3 text-xs',\n lg: 'h-10 rounded-md px-8',\n icon: 'h-9 w-9',\n },\n },\n defaultVariants: {\n variant: 'default',\n size: 'default',\n },\n },\n)\n\nexport type ButtonVariants = VariantProps<typeof buttonVariants>\n"
}
],
"type": "components:ui"

View File

@ -39,7 +39,7 @@
},
{
"name": "index.ts",
"content": "import { cva } from 'class-variance-authority'\n\nexport { default as NavigationMenu } from './NavigationMenu.vue'\nexport { default as NavigationMenuContent } from './NavigationMenuContent.vue'\nexport { default as NavigationMenuItem } from './NavigationMenuItem.vue'\nexport { default as NavigationMenuLink } from './NavigationMenuLink.vue'\nexport { default as NavigationMenuList } from './NavigationMenuList.vue'\nexport { default as NavigationMenuTrigger } from './NavigationMenuTrigger.vue'\n\nexport const navigationMenuTriggerStyle = cva(\n 'group inline-flex h-10 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[active]:bg-accent/50 data-[state=open]:bg-accent/50',\n)\n"
"content": "import { cva } from 'class-variance-authority'\n\nexport { default as NavigationMenu } from './NavigationMenu.vue'\nexport { default as NavigationMenuContent } from './NavigationMenuContent.vue'\nexport { default as NavigationMenuItem } from './NavigationMenuItem.vue'\nexport { default as NavigationMenuLink } from './NavigationMenuLink.vue'\nexport { default as NavigationMenuList } from './NavigationMenuList.vue'\nexport { default as NavigationMenuTrigger } from './NavigationMenuTrigger.vue'\nexport { default as NavigationMenuViewport } from './NavigationMenuViewport.vue'\n\nexport const navigationMenuTriggerStyle = cva(\n 'group inline-flex h-10 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[active]:bg-accent/50 data-[state=open]:bg-accent/50',\n)\n"
}
],
"type": "components:ui"

View File

@ -43,7 +43,7 @@
},
{
"name": "SelectTrigger.vue",
"content": "<script setup lang=\"ts\">\nimport { cn } from '@/lib/utils'\nimport { ChevronDown } from 'lucide-vue-next'\nimport { SelectIcon, SelectTrigger, type SelectTriggerProps, useForwardProps } from 'radix-vue'\nimport { computed, type HTMLAttributes } from 'vue'\n\nconst props = defineProps<SelectTriggerProps & { class?: HTMLAttributes['class'] }>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwardedProps = useForwardProps(delegatedProps)\n</script>\n\n<template>\n <SelectTrigger\n v-bind=\"forwardedProps\"\n :class=\"cn(\n 'flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:truncate text-start',\n props.class,\n )\"\n >\n <slot />\n <SelectIcon as-child>\n <ChevronDown class=\"w-4 h-4 opacity-50 shrink-0\" />\n </SelectIcon>\n </SelectTrigger>\n</template>\n"
"content": "<script setup lang=\"ts\">\nimport { cn } from '@/lib/utils'\nimport { ChevronDown } from 'lucide-vue-next'\nimport { SelectIcon, SelectTrigger, type SelectTriggerProps, useForwardProps } from 'radix-vue'\nimport { computed, type HTMLAttributes } from 'vue'\n\nconst props = defineProps<SelectTriggerProps & { class?: HTMLAttributes['class'] }>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwardedProps = useForwardProps(delegatedProps)\n</script>\n\n<template>\n <SelectTrigger\n v-bind=\"forwardedProps\"\n :class=\"cn(\n 'flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background data-[placeholder]:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:truncate text-start',\n props.class,\n )\"\n >\n <slot />\n <SelectIcon as-child>\n <ChevronDown class=\"w-4 h-4 opacity-50 shrink-0\" />\n </SelectIcon>\n </SelectTrigger>\n</template>\n"
},
{
"name": "SelectValue.vue",

View File

@ -4,21 +4,18 @@
"@vueuse/core"
],
"registryDependencies": [
"Sheet.vue",
"SheetContent.vue",
"sheet",
"utils",
"Input.vue",
"Tooltip.vue",
"TooltipContent.vue",
"TooltipTrigger.vue",
"Skeleton.vue",
"Separator.vue",
"Button.vue"
"input",
"tooltip",
"skeleton",
"separator",
"button"
],
"files": [
{
"name": "Sidebar.vue",
"content": "<script setup lang=\"ts\">\nimport type { HTMLAttributes } from 'vue'\nimport Sheet from '@/lib/registry/default/ui/sheet/Sheet.vue'\nimport SheetContent from '@/lib/registry/default/ui/sheet/SheetContent.vue'\nimport { cn } from '@/lib/utils'\nimport { SIDEBAR_WIDTH_MOBILE, useSidebar } from './utils'\n\ndefineOptions({\n inheritAttrs: false,\n})\n\nconst props = withDefaults(defineProps<{\n side?: 'left' | 'right'\n variant?: 'sidebar' | 'floating' | 'inset'\n collapsible?: 'offcanvas' | 'icon' | 'none'\n class?: HTMLAttributes['class']\n}>(), {\n side: 'left',\n variant: 'sidebar',\n collapsible: 'offcanvas',\n})\n\nconst { isMobile, state, openMobile, setOpenMobile } = useSidebar()\n</script>\n\n<template>\n <div\n v-if=\"collapsible === 'none'\"\n :class=\"cn('flex h-full w-[--sidebar-width] flex-col bg-sidebar text-sidebar-foreground', props.class)\"\n v-bind=\"$attrs\"\n >\n <slot />\n </div>\n\n <Sheet v-else-if=\"isMobile\" :open=\"openMobile\" v-bind=\"$attrs\" @update:open=\"setOpenMobile\">\n <SheetContent\n data-sidebar=\"sidebar\"\n data-mobile=\"true\"\n class=\"w-[--sidebar-width] bg-sidebar p-0 text-sidebar-foreground [&>button]:hidden\"\n :style=\"{\n '--sidebar-width': SIDEBAR_WIDTH_MOBILE,\n }\"\n >\n <div class=\"flex h-full w-full flex-col\">\n <slot />\n </div>\n </SheetContent>\n </Sheet>\n\n <div\n v-else class=\"group peer hidden md:block\"\n :data-state=\"state\"\n :data-collapsible=\"state === 'collapsed' ? collapsible : ''\"\n :data-variant=\"variant\"\n :data-side=\"side\"\n >\n <!-- This is what handles the sidebar gap on desktop -->\n <div\n :class=\"cn(\n 'duration-200 relative h-svh w-[--sidebar-width] bg-transparent transition-[width] ease-linear',\n 'group-data-[collapsible=offcanvas]:w-0',\n 'group-data-[side=right]:rotate-180',\n variant === 'floating' || variant === 'inset'\n ? 'group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4))]'\n : 'group-data-[collapsible=icon]:w-[--sidebar-width-icon]',\n )\"\n />\n <div\n :class=\"cn(\n 'duration-200 fixed inset-y-0 z-10 hidden h-svh w-[--sidebar-width] transition-[left,right,width] ease-linear md:flex',\n side === 'left'\n ? 'left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]'\n : 'right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]',\n // Adjust the padding for floating and inset variants.\n variant === 'floating' || variant === 'inset'\n ? 'p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4)_+2px)]'\n : 'group-data-[collapsible=icon]:w-[--sidebar-width-icon] group-data-[side=left]:border-r group-data-[side=right]:border-l',\n props.class,\n )\"\n v-bind=\"$attrs\"\n >\n <div\n data-sidebar=\"sidebar\"\n class=\"flex h-full w-full flex-col bg-sidebar group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:border-sidebar-border group-data-[variant=floating]:shadow\"\n >\n <slot />\n </div>\n </div>\n </div>\n</template>\n"
"content": "<script setup lang=\"ts\">\nimport type { SidebarProps } from '.'\nimport { Sheet, SheetContent } from '@/lib/registry/default/ui/sheet'\nimport { cn } from '@/lib/utils'\nimport { SIDEBAR_WIDTH_MOBILE, useSidebar } from './utils'\n\ndefineOptions({\n inheritAttrs: false,\n})\n\nconst props = withDefaults(defineProps<SidebarProps>(), {\n side: 'left',\n variant: 'sidebar',\n collapsible: 'offcanvas',\n})\n\nconst { isMobile, state, openMobile, setOpenMobile } = useSidebar()\n</script>\n\n<template>\n <div\n v-if=\"collapsible === 'none'\"\n :class=\"cn('flex h-full w-[--sidebar-width] flex-col bg-sidebar text-sidebar-foreground', props.class)\"\n v-bind=\"$attrs\"\n >\n <slot />\n </div>\n\n <Sheet v-else-if=\"isMobile\" :open=\"openMobile\" v-bind=\"$attrs\" @update:open=\"setOpenMobile\">\n <SheetContent\n data-sidebar=\"sidebar\"\n data-mobile=\"true\"\n :side=\"side\"\n class=\"w-[--sidebar-width] bg-sidebar p-0 text-sidebar-foreground [&>button]:hidden\"\n :style=\"{\n '--sidebar-width': SIDEBAR_WIDTH_MOBILE,\n }\"\n >\n <div class=\"flex h-full w-full flex-col\">\n <slot />\n </div>\n </SheetContent>\n </Sheet>\n\n <div\n v-else class=\"group peer hidden md:block\"\n :data-state=\"state\"\n :data-collapsible=\"state === 'collapsed' ? collapsible : ''\"\n :data-variant=\"variant\"\n :data-side=\"side\"\n >\n <!-- This is what handles the sidebar gap on desktop -->\n <div\n :class=\"cn(\n 'duration-200 relative h-svh w-[--sidebar-width] bg-transparent transition-[width] ease-linear',\n 'group-data-[collapsible=offcanvas]:w-0',\n 'group-data-[side=right]:rotate-180',\n variant === 'floating' || variant === 'inset'\n ? 'group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4))]'\n : 'group-data-[collapsible=icon]:w-[--sidebar-width-icon]',\n )\"\n />\n <div\n :class=\"cn(\n 'duration-200 fixed inset-y-0 z-10 hidden h-svh w-[--sidebar-width] transition-[left,right,width] ease-linear md:flex',\n side === 'left'\n ? 'left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]'\n : 'right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]',\n // Adjust the padding for floating and inset variants.\n variant === 'floating' || variant === 'inset'\n ? 'p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4)_+2px)]'\n : 'group-data-[collapsible=icon]:w-[--sidebar-width-icon] group-data-[side=left]:border-r group-data-[side=right]:border-l',\n props.class,\n )\"\n v-bind=\"$attrs\"\n >\n <div\n data-sidebar=\"sidebar\"\n class=\"flex h-full w-full flex-col bg-sidebar group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:border-sidebar-border group-data-[variant=floating]:shadow\"\n >\n <slot />\n </div>\n </div>\n </div>\n</template>\n"
},
{
"name": "SidebarContent.vue",
@ -50,7 +47,7 @@
},
{
"name": "SidebarInput.vue",
"content": "<script setup lang=\"ts\">\nimport type { HTMLAttributes } from 'vue'\nimport Input from '@/lib/registry/default/ui/input/Input.vue'\nimport { cn } from '@/lib/utils'\n\nconst props = defineProps<{\n class?: HTMLAttributes['class']\n}>()\n</script>\n\n<template>\n <Input\n data-sidebar=\"input\"\n :class=\"cn(\n 'h-8 w-full bg-background shadow-none focus-visible:ring-2 focus-visible:ring-sidebar-ring',\n props.class,\n )\"\n >\n <slot />\n </Input>\n</template>\n"
"content": "<script setup lang=\"ts\">\nimport type { HTMLAttributes } from 'vue'\nimport { Input } from '@/lib/registry/default/ui/input'\nimport { cn } from '@/lib/utils'\n\nconst props = defineProps<{\n class?: HTMLAttributes['class']\n}>()\n</script>\n\n<template>\n <Input\n data-sidebar=\"input\"\n :class=\"cn(\n 'h-8 w-full bg-background shadow-none focus-visible:ring-2 focus-visible:ring-sidebar-ring',\n props.class,\n )\"\n >\n <slot />\n </Input>\n</template>\n"
},
{
"name": "SidebarInset.vue",
@ -62,7 +59,7 @@
},
{
"name": "SidebarMenuAction.vue",
"content": "<script setup lang=\"ts\">\nimport type { HTMLAttributes } from 'vue'\nimport { cn } from '@/lib/utils'\nimport { Primitive, type PrimitiveProps } from 'radix-vue'\n\nconst props = withDefaults(defineProps<PrimitiveProps & {\n showOnHover?: boolean\n class?: HTMLAttributes['class']\n}>(), {\n as: 'button',\n})\n</script>\n\n<template>\n <Primitive\n data-sidebar=\"menu-action\"\n :class=\"cn(\n 'absolute right-1 top-1.5 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground outline-none ring-sidebar-ring transition-transform hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 peer-hover/menu-button:text-sidebar-accent-foreground [&>svg]:size-4 [&>svg]:shrink-0',\n // Increases the hit area of the button on mobile.\n 'after:absolute after:-inset-2 after:md:hidden',\n 'peer-data-[size=sm]/menu-button:top-1',\n 'peer-data-[size=default]/menu-button:top-1.5',\n 'peer-data-[size=lg]/menu-button:top-2.5',\n 'group-data-[collapsible=icon]:hidden',\n showOnHover\n && 'group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 data-[state=open]:opacity-100 peer-data-[active=true]/menu-button:text-sidebar-accent-foreground md:opacity-0',\n props.class,\n )\"\n :as=\"as\"\n :as-child=\"asChild\"\n />\n</template>\n"
"content": "<script setup lang=\"ts\">\nimport type { HTMLAttributes } from 'vue'\nimport { cn } from '@/lib/utils'\nimport { Primitive, type PrimitiveProps } from 'radix-vue'\n\nconst props = withDefaults(defineProps<PrimitiveProps & {\n showOnHover?: boolean\n class?: HTMLAttributes['class']\n}>(), {\n as: 'button',\n})\n</script>\n\n<template>\n <Primitive\n data-sidebar=\"menu-action\"\n :class=\"cn(\n 'absolute right-1 top-1.5 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground outline-none ring-sidebar-ring transition-transform hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 peer-hover/menu-button:text-sidebar-accent-foreground [&>svg]:size-4 [&>svg]:shrink-0',\n // Increases the hit area of the button on mobile.\n 'after:absolute after:-inset-2 after:md:hidden',\n 'peer-data-[size=sm]/menu-button:top-1',\n 'peer-data-[size=default]/menu-button:top-1.5',\n 'peer-data-[size=lg]/menu-button:top-2.5',\n 'group-data-[collapsible=icon]:hidden',\n showOnHover\n && 'group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 data-[state=open]:opacity-100 peer-data-[active=true]/menu-button:text-sidebar-accent-foreground md:opacity-0',\n props.class,\n )\"\n :as=\"as\"\n :as-child=\"asChild\"\n >\n <slot />\n </Primitive>\n</template>\n"
},
{
"name": "SidebarMenuBadge.vue",
@ -70,7 +67,7 @@
},
{
"name": "SidebarMenuButton.vue",
"content": "<script setup lang=\"ts\">\nimport Tooltip from '@/lib/registry/default/ui/tooltip/Tooltip.vue'\nimport TooltipContent from '@/lib/registry/default/ui/tooltip/TooltipContent.vue'\nimport TooltipTrigger from '@/lib/registry/default/ui/tooltip/TooltipTrigger.vue'\nimport { type Component, computed } from 'vue'\nimport SidebarMenuButtonChild, { type SidebarMenuButtonProps } from './SidebarMenuButtonChild.vue'\nimport { useSidebar } from './utils'\n\ndefineOptions({\n inheritAttrs: false,\n})\n\nconst props = withDefaults(defineProps<SidebarMenuButtonProps & {\n tooltip?: string | Component\n}>(), {\n as: 'button',\n variant: 'default',\n size: 'default',\n})\n\nconst { isMobile, state } = useSidebar()\n\nconst delegatedProps = computed(() => {\n const { tooltip, ...delegated } = props\n return delegated\n})\n</script>\n\n<template>\n <SidebarMenuButtonChild v-if=\"!tooltip\" v-bind=\"{ ...delegatedProps, ...$attrs }\">\n <slot />\n </SidebarMenuButtonChild>\n\n <Tooltip v-else>\n <TooltipTrigger as-child>\n <SidebarMenuButtonChild v-bind=\"{ ...delegatedProps, ...$attrs }\">\n <slot />\n </SidebarMenuButtonChild>\n </TooltipTrigger>\n <TooltipContent\n side=\"right\"\n align=\"center\"\n :hidden=\"state !== 'collapsed' || isMobile\"\n >\n <template v-if=\"typeof tooltip === 'string'\">\n {{ tooltip }}\n </template>\n <component :is=\"tooltip\" v-else />\n </TooltipContent>\n </Tooltip>\n</template>\n"
"content": "<script setup lang=\"ts\">\nimport { Tooltip, TooltipContent, TooltipTrigger } from '@/lib/registry/default/ui/tooltip'\nimport { type Component, computed } from 'vue'\nimport SidebarMenuButtonChild, { type SidebarMenuButtonProps } from './SidebarMenuButtonChild.vue'\nimport { useSidebar } from './utils'\n\ndefineOptions({\n inheritAttrs: false,\n})\n\nconst props = withDefaults(defineProps<SidebarMenuButtonProps & {\n tooltip?: string | Component\n}>(), {\n as: 'button',\n variant: 'default',\n size: 'default',\n})\n\nconst { isMobile, state } = useSidebar()\n\nconst delegatedProps = computed(() => {\n const { tooltip, ...delegated } = props\n return delegated\n})\n</script>\n\n<template>\n <SidebarMenuButtonChild v-if=\"!tooltip\" v-bind=\"{ ...delegatedProps, ...$attrs }\">\n <slot />\n </SidebarMenuButtonChild>\n\n <Tooltip v-else>\n <TooltipTrigger as-child>\n <SidebarMenuButtonChild v-bind=\"{ ...delegatedProps, ...$attrs }\">\n <slot />\n </SidebarMenuButtonChild>\n </TooltipTrigger>\n <TooltipContent\n side=\"right\"\n align=\"center\"\n :hidden=\"state !== 'collapsed' || isMobile\"\n >\n <template v-if=\"typeof tooltip === 'string'\">\n {{ tooltip }}\n </template>\n <component :is=\"tooltip\" v-else />\n </TooltipContent>\n </Tooltip>\n</template>\n"
},
{
"name": "SidebarMenuButtonChild.vue",
@ -82,7 +79,7 @@
},
{
"name": "SidebarMenuSkeleton.vue",
"content": "<script setup lang=\"ts\">\nimport Skeleton from '@/lib/registry/default/ui/skeleton/Skeleton.vue'\nimport { cn } from '@/lib/utils'\nimport { computed, type HTMLAttributes } from 'vue'\n\nconst props = defineProps<{\n showIcon?: boolean\n class?: HTMLAttributes['class']\n}>()\n\nconst width = computed(() => {\n return `${Math.floor(Math.random() * 40) + 50}%`\n})\n</script>\n\n<template>\n <div\n data-sidebar=\"menu-skeleton\"\n :class=\"cn('rounded-md h-8 flex gap-2 px-2 items-center', props.class)\"\n >\n <Skeleton\n v-if=\"showIcon\"\n class=\"size-4 rounded-md\"\n data-sidebar=\"menu-skeleton-icon\"\n />\n\n <Skeleton\n class=\"h-4 flex-1 max-w-[--skeleton-width]\"\n data-sidebar=\"menu-skeleton-text\"\n :style=\"{ '--skeleton-width': width }\"\n />\n </div>\n</template>\n"
"content": "<script setup lang=\"ts\">\nimport { Skeleton } from '@/lib/registry/default/ui/skeleton'\nimport { cn } from '@/lib/utils'\nimport { computed, type HTMLAttributes } from 'vue'\n\nconst props = defineProps<{\n showIcon?: boolean\n class?: HTMLAttributes['class']\n}>()\n\nconst width = computed(() => {\n return `${Math.floor(Math.random() * 40) + 50}%`\n})\n</script>\n\n<template>\n <div\n data-sidebar=\"menu-skeleton\"\n :class=\"cn('rounded-md h-8 flex gap-2 px-2 items-center', props.class)\"\n >\n <Skeleton\n v-if=\"showIcon\"\n class=\"size-4 rounded-md\"\n data-sidebar=\"menu-skeleton-icon\"\n />\n\n <Skeleton\n class=\"h-4 flex-1 max-w-[--skeleton-width]\"\n data-sidebar=\"menu-skeleton-text\"\n :style=\"{ '--skeleton-width': width }\"\n />\n </div>\n</template>\n"
},
{
"name": "SidebarMenuSub.vue",
@ -98,7 +95,7 @@
},
{
"name": "SidebarProvider.vue",
"content": "<script setup lang=\"ts\">\nimport { cn } from '@/lib/utils'\nimport { useEventListener, useVModel } from '@vueuse/core'\nimport { TooltipProvider } from 'radix-vue'\nimport { computed, type HTMLAttributes, type Ref, ref } from 'vue'\nimport { provideSidebarContext, SIDEBAR_COOKIE_MAX_AGE, SIDEBAR_COOKIE_NAME, SIDEBAR_KEYBOARD_SHORTCUT, SIDEBAR_WIDTH, SIDEBAR_WIDTH_ICON } from './utils'\n\nconst props = withDefaults(defineProps<{\n defaultOpen?: boolean\n open?: boolean\n class?: HTMLAttributes['class']\n}>(), {\n defaultOpen: true,\n open: undefined,\n})\n\nconst emits = defineEmits<{\n 'update:open': [open: boolean]\n}>()\n\nconst isMobile = ref(false) // useIsMobile()\nconst openMobile = ref(false)\n\nconst open = useVModel(props, 'open', emits, {\n defaultValue: props.defaultOpen ?? false,\n passive: (props.open === undefined) as false,\n}) as Ref<boolean>\n\nfunction setOpen(value: boolean) {\n open.value = value // emits('update:open', value)\n\n // This sets the cookie to keep the sidebar state.\n document.cookie = `${SIDEBAR_COOKIE_NAME}=${open}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`\n}\n\nfunction setOpenMobile(value: boolean) {\n openMobile.value = value\n}\n\n// Helper to toggle the sidebar.\nfunction toggleSidebar() {\n return isMobile.value ? setOpenMobile(!open.value) : setOpen(!open.value)\n}\n\nuseEventListener('keydown', (event: KeyboardEvent) => {\n if (event.key === SIDEBAR_KEYBOARD_SHORTCUT && (event.metaKey || event.ctrlKey)) {\n event.preventDefault()\n toggleSidebar()\n }\n})\n\n// We add a state so that we can do data-state=\"expanded\" or \"collapsed\".\n// This makes it easier to style the sidebar with Tailwind classes.\nconst state = computed(() => open.value ? 'expanded' : 'collapsed')\n\nprovideSidebarContext({\n state,\n open,\n setOpen,\n isMobile,\n openMobile,\n setOpenMobile,\n toggleSidebar,\n})\n</script>\n\n<template>\n <TooltipProvider :delay-duration=\"0\">\n <div\n :style=\"{\n '--sidebar-width': SIDEBAR_WIDTH,\n '--sidebar-width-icon': SIDEBAR_WIDTH_ICON,\n }\"\n :class=\"cn('group/sidebar-wrapper flex min-h-svh w-full text-sidebar-foreground has-[[data-variant=inset]]:bg-sidebar', props.class)\"\n >\n <slot />\n </div>\n </TooltipProvider>\n</template>\n"
"content": "<script setup lang=\"ts\">\nimport { cn } from '@/lib/utils'\nimport { useEventListener, useMediaQuery, useVModel } from '@vueuse/core'\nimport { TooltipProvider } from 'radix-vue'\nimport { computed, type HTMLAttributes, type Ref, ref } from 'vue'\nimport { provideSidebarContext, SIDEBAR_COOKIE_MAX_AGE, SIDEBAR_COOKIE_NAME, SIDEBAR_KEYBOARD_SHORTCUT, SIDEBAR_WIDTH, SIDEBAR_WIDTH_ICON } from './utils'\n\nconst props = withDefaults(defineProps<{\n defaultOpen?: boolean\n open?: boolean\n class?: HTMLAttributes['class']\n}>(), {\n defaultOpen: true,\n open: undefined,\n})\n\nconst emits = defineEmits<{\n 'update:open': [open: boolean]\n}>()\n\nconst isMobile = useMediaQuery('(max-width: 768px)')\nconst openMobile = ref(false)\n\nconst open = useVModel(props, 'open', emits, {\n defaultValue: props.defaultOpen ?? false,\n passive: (props.open === undefined) as false,\n}) as Ref<boolean>\n\nfunction setOpen(value: boolean) {\n open.value = value // emits('update:open', value)\n\n // This sets the cookie to keep the sidebar state.\n document.cookie = `${SIDEBAR_COOKIE_NAME}=${open.value}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`\n}\n\nfunction setOpenMobile(value: boolean) {\n openMobile.value = value\n}\n\n// Helper to toggle the sidebar.\nfunction toggleSidebar() {\n return isMobile.value ? setOpenMobile(!openMobile.value) : setOpen(!open.value)\n}\n\nuseEventListener('keydown', (event: KeyboardEvent) => {\n if (event.key === SIDEBAR_KEYBOARD_SHORTCUT && (event.metaKey || event.ctrlKey)) {\n event.preventDefault()\n toggleSidebar()\n }\n})\n\n// We add a state so that we can do data-state=\"expanded\" or \"collapsed\".\n// This makes it easier to style the sidebar with Tailwind classes.\nconst state = computed(() => open.value ? 'expanded' : 'collapsed')\n\nprovideSidebarContext({\n state,\n open,\n setOpen,\n isMobile,\n openMobile,\n setOpenMobile,\n toggleSidebar,\n})\n</script>\n\n<template>\n <TooltipProvider :delay-duration=\"0\">\n <div\n :style=\"{\n '--sidebar-width': SIDEBAR_WIDTH,\n '--sidebar-width-icon': SIDEBAR_WIDTH_ICON,\n }\"\n :class=\"cn('group/sidebar-wrapper flex min-h-svh w-full text-sidebar-foreground has-[[data-variant=inset]]:bg-sidebar', props.class)\"\n v-bind=\"$attrs\"\n >\n <slot />\n </div>\n </TooltipProvider>\n</template>\n"
},
{
"name": "SidebarRail.vue",
@ -106,15 +103,15 @@
},
{
"name": "SidebarSeparator.vue",
"content": "<script setup lang=\"ts\">\nimport type { HTMLAttributes } from 'vue'\nimport Separator from '@/lib/registry/default/ui/separator/Separator.vue'\nimport { cn } from '@/lib/utils'\n\nconst props = defineProps<{\n class?: HTMLAttributes['class']\n}>()\n</script>\n\n<template>\n <Separator\n data-sidebar=\"separator\"\n :class=\"cn('mx-2 w-auto bg-sidebar-border', props.class)\"\n >\n <slot />\n </Separator>\n</template>\n"
"content": "<script setup lang=\"ts\">\nimport type { HTMLAttributes } from 'vue'\nimport { Separator } from '@/lib/registry/default/ui/separator'\nimport { cn } from '@/lib/utils'\n\nconst props = defineProps<{\n class?: HTMLAttributes['class']\n}>()\n</script>\n\n<template>\n <Separator\n data-sidebar=\"separator\"\n :class=\"cn('mx-2 w-auto bg-sidebar-border', props.class)\"\n >\n <slot />\n </Separator>\n</template>\n"
},
{
"name": "SidebarTrigger.vue",
"content": "<script setup lang=\"ts\">\nimport type { HTMLAttributes } from 'vue'\nimport Button from '@/lib/registry/default/ui/button/Button.vue'\nimport { cn } from '@/lib/utils'\nimport { PanelLeft } from 'lucide-vue-next'\nimport { useSidebar } from './utils'\n\nconst props = defineProps<{\n class?: HTMLAttributes['class']\n}>()\n\nconst { toggleSidebar } = useSidebar()\n</script>\n\n<template>\n <Button\n data-sidebar=\"trigger\"\n variant=\"ghost\"\n size=\"icon\"\n :class=\"cn('h-7 w-7', props.class)\"\n @click=\"toggleSidebar\"\n >\n <PanelLeft />\n <span class=\"sr-only\">Toggle Sidebar</span>\n </Button>\n</template>\n"
"content": "<script setup lang=\"ts\">\nimport type { HTMLAttributes } from 'vue'\nimport { Button } from '@/lib/registry/default/ui/button'\nimport { cn } from '@/lib/utils'\nimport { PanelLeft } from 'lucide-vue-next'\nimport { useSidebar } from './utils'\n\nconst props = defineProps<{\n class?: HTMLAttributes['class']\n}>()\n\nconst { toggleSidebar } = useSidebar()\n</script>\n\n<template>\n <Button\n data-sidebar=\"trigger\"\n variant=\"ghost\"\n size=\"icon\"\n :class=\"cn('h-7 w-7', props.class)\"\n @click=\"toggleSidebar\"\n >\n <PanelLeft />\n <span class=\"sr-only\">Toggle Sidebar</span>\n </Button>\n</template>\n"
},
{
"name": "index.ts",
"content": "import { cva, type VariantProps } from 'class-variance-authority'\n\nexport { default as Sidebar } from './Sidebar.vue'\nexport { default as SidebarContent } from './SidebarContent.vue'\nexport { default as SidebarFooter } from './SidebarFooter.vue'\nexport { default as SidebarGroup } from './SidebarGroup.vue'\nexport { default as SidebarGroupAction } from './SidebarGroupAction.vue'\nexport { default as SidebarGroupContent } from './SidebarGroupContent.vue'\nexport { default as SidebarGroupLabel } from './SidebarGroupLabel.vue'\nexport { default as SidebarHeader } from './SidebarHeader.vue'\nexport { default as SidebarInput } from './SidebarInput.vue'\nexport { default as SidebarInset } from './SidebarInset.vue'\nexport { default as SidebarMenu } from './SidebarMenu.vue'\nexport { default as SidebarMenuAction } from './SidebarMenuAction.vue'\nexport { default as SidebarMenuBadge } from './SidebarMenuBadge.vue'\nexport { default as SidebarMenuButton } from './SidebarMenuButton.vue'\nexport { default as SidebarMenuItem } from './SidebarMenuItem.vue'\nexport { default as SidebarMenuSkeleton } from './SidebarMenuSkeleton.vue'\nexport { default as SidebarMenuSub } from './SidebarMenuSub.vue'\nexport { default as SidebarMenuSubButton } from './SidebarMenuSubButton.vue'\nexport { default as SidebarMenuSubItem } from './SidebarMenuSubItem.vue'\nexport { default as SidebarProvider } from './SidebarProvider.vue'\nexport { default as SidebarRail } from './SidebarRail.vue'\nexport { default as SidebarSeparator } from './SidebarSeparator.vue'\nexport { default as SidebarTrigger } from './SidebarTrigger.vue'\n\nexport { useSidebar } from './utils'\n\nexport const sidebarMenuButtonVariants = cva(\n 'peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-none ring-sidebar-ring transition-[width,height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-[[data-sidebar=menu-action]]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground group-data-[collapsible=icon]:!size-8 group-data-[collapsible=icon]:!p-2 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0',\n {\n variants: {\n variant: {\n default: 'hover:bg-sidebar-accent hover:text-sidebar-accent-foreground',\n outline:\n 'bg-background shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))]',\n },\n size: {\n default: 'h-8 text-sm',\n sm: 'h-7 text-xs',\n lg: 'h-12 text-sm group-data-[collapsible=icon]:!p-0',\n },\n },\n defaultVariants: {\n variant: 'default',\n size: 'default',\n },\n },\n)\n\nexport type SidebarMenuButtonVariants = VariantProps<typeof sidebarMenuButtonVariants>\n"
"content": "import type { HTMLAttributes } from 'vue'\nimport { cva, type VariantProps } from 'class-variance-authority'\n\nexport interface SidebarProps {\n side?: 'left' | 'right'\n variant?: 'sidebar' | 'floating' | 'inset'\n collapsible?: 'offcanvas' | 'icon' | 'none'\n class?: HTMLAttributes['class']\n}\n\nexport { default as Sidebar } from './Sidebar.vue'\nexport { default as SidebarContent } from './SidebarContent.vue'\nexport { default as SidebarFooter } from './SidebarFooter.vue'\nexport { default as SidebarGroup } from './SidebarGroup.vue'\nexport { default as SidebarGroupAction } from './SidebarGroupAction.vue'\nexport { default as SidebarGroupContent } from './SidebarGroupContent.vue'\nexport { default as SidebarGroupLabel } from './SidebarGroupLabel.vue'\nexport { default as SidebarHeader } from './SidebarHeader.vue'\nexport { default as SidebarInput } from './SidebarInput.vue'\nexport { default as SidebarInset } from './SidebarInset.vue'\nexport { default as SidebarMenu } from './SidebarMenu.vue'\nexport { default as SidebarMenuAction } from './SidebarMenuAction.vue'\nexport { default as SidebarMenuBadge } from './SidebarMenuBadge.vue'\nexport { default as SidebarMenuButton } from './SidebarMenuButton.vue'\nexport { default as SidebarMenuItem } from './SidebarMenuItem.vue'\nexport { default as SidebarMenuSkeleton } from './SidebarMenuSkeleton.vue'\nexport { default as SidebarMenuSub } from './SidebarMenuSub.vue'\nexport { default as SidebarMenuSubButton } from './SidebarMenuSubButton.vue'\nexport { default as SidebarMenuSubItem } from './SidebarMenuSubItem.vue'\nexport { default as SidebarProvider } from './SidebarProvider.vue'\nexport { default as SidebarRail } from './SidebarRail.vue'\nexport { default as SidebarSeparator } from './SidebarSeparator.vue'\nexport { default as SidebarTrigger } from './SidebarTrigger.vue'\n\nexport { useSidebar } from './utils'\n\nexport const sidebarMenuButtonVariants = cva(\n 'peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-none ring-sidebar-ring transition-[width,height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-[[data-sidebar=menu-action]]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground group-data-[collapsible=icon]:!size-8 group-data-[collapsible=icon]:!p-2 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0',\n {\n variants: {\n variant: {\n default: 'hover:bg-sidebar-accent hover:text-sidebar-accent-foreground',\n outline:\n 'bg-background shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))]',\n },\n size: {\n default: 'h-8 text-sm',\n sm: 'h-7 text-xs',\n lg: 'h-12 text-sm group-data-[collapsible=icon]:!p-0',\n },\n },\n defaultVariants: {\n variant: 'default',\n size: 'default',\n },\n },\n)\n\nexport type SidebarMenuButtonVariants = VariantProps<typeof sidebarMenuButtonVariants>\n"
},
{
"name": "utils.ts",

View File

@ -7,7 +7,7 @@
"files": [
{
"name": "Switch.vue",
"content": "<script setup lang=\"ts\">\nimport { cn } from '@/lib/utils'\nimport {\n SwitchRoot,\n type SwitchRootEmits,\n type SwitchRootProps,\n SwitchThumb,\n useForwardPropsEmits,\n} from 'radix-vue'\nimport { computed, type HTMLAttributes } from 'vue'\n\nconst props = defineProps<SwitchRootProps & { class?: HTMLAttributes['class'] }>()\n\nconst emits = defineEmits<SwitchRootEmits>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits)\n</script>\n\n<template>\n <SwitchRoot\n v-bind=\"forwarded\"\n :class=\"cn(\n 'peer inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input',\n props.class,\n )\"\n >\n <SwitchThumb\n :class=\"cn('pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0')\"\n />\n </SwitchRoot>\n</template>\n"
"content": "<script setup lang=\"ts\">\nimport { cn } from '@/lib/utils'\nimport {\n SwitchRoot,\n type SwitchRootEmits,\n type SwitchRootProps,\n SwitchThumb,\n useForwardPropsEmits,\n} from 'radix-vue'\nimport { computed, type HTMLAttributes } from 'vue'\n\nconst props = defineProps<SwitchRootProps & { class?: HTMLAttributes['class'] }>()\n\nconst emits = defineEmits<SwitchRootEmits>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits)\n</script>\n\n<template>\n <SwitchRoot\n v-bind=\"forwarded\"\n :class=\"cn(\n 'peer inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input',\n props.class,\n )\"\n >\n <SwitchThumb\n :class=\"cn('pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5')\"\n >\n <slot name=\"thumb\" />\n </SwitchThumb>\n </SwitchRoot>\n</template>\n"
},
{
"name": "index.ts",

View File

@ -68,7 +68,7 @@
},
{
"name": "constant.ts",
"content": "import AutoFormFieldArray from './AutoFormFieldArray.vue'\nimport AutoFormFieldBoolean from './AutoFormFieldBoolean.vue'\nimport AutoFormFieldDate from './AutoFormFieldDate.vue'\nimport AutoFormFieldEnum from './AutoFormFieldEnum.vue'\nimport AutoFormFieldFile from './AutoFormFieldFile.vue'\nimport AutoFormFieldInput from './AutoFormFieldInput.vue'\nimport AutoFormFieldNumber from './AutoFormFieldNumber.vue'\nimport AutoFormFieldObject from './AutoFormFieldObject.vue'\n\nexport const INPUT_COMPONENTS = {\n date: AutoFormFieldDate,\n select: AutoFormFieldEnum,\n radio: AutoFormFieldEnum,\n checkbox: AutoFormFieldBoolean,\n switch: AutoFormFieldBoolean,\n textarea: AutoFormFieldInput,\n number: AutoFormFieldNumber,\n string: AutoFormFieldInput,\n file: AutoFormFieldFile,\n array: AutoFormFieldArray,\n object: AutoFormFieldObject,\n}\n\n/**\n * Define handlers for specific Zod types.\n * You can expand this object to support more types.\n */\nexport const DEFAULT_ZOD_HANDLERS: {\n [key: string]: keyof typeof INPUT_COMPONENTS\n} = {\n ZodString: 'string',\n ZodBoolean: 'checkbox',\n ZodDate: 'date',\n ZodEnum: 'select',\n ZodNativeEnum: 'select',\n ZodNumber: 'number',\n ZodArray: 'array',\n ZodObject: 'object',\n}\n"
"content": "import type { InputComponents } from './interface'\nimport AutoFormFieldArray from './AutoFormFieldArray.vue'\nimport AutoFormFieldBoolean from './AutoFormFieldBoolean.vue'\nimport AutoFormFieldDate from './AutoFormFieldDate.vue'\nimport AutoFormFieldEnum from './AutoFormFieldEnum.vue'\nimport AutoFormFieldFile from './AutoFormFieldFile.vue'\nimport AutoFormFieldInput from './AutoFormFieldInput.vue'\nimport AutoFormFieldNumber from './AutoFormFieldNumber.vue'\nimport AutoFormFieldObject from './AutoFormFieldObject.vue'\n\nexport const INPUT_COMPONENTS: InputComponents = {\n date: AutoFormFieldDate,\n select: AutoFormFieldEnum,\n radio: AutoFormFieldEnum,\n checkbox: AutoFormFieldBoolean,\n switch: AutoFormFieldBoolean,\n textarea: AutoFormFieldInput,\n number: AutoFormFieldNumber,\n string: AutoFormFieldInput,\n file: AutoFormFieldFile,\n array: AutoFormFieldArray,\n object: AutoFormFieldObject,\n}\n\n/**\n * Define handlers for specific Zod types.\n * You can expand this object to support more types.\n */\nexport const DEFAULT_ZOD_HANDLERS: {\n [key: string]: keyof typeof INPUT_COMPONENTS\n} = {\n ZodString: 'string',\n ZodBoolean: 'checkbox',\n ZodDate: 'date',\n ZodEnum: 'select',\n ZodNativeEnum: 'select',\n ZodNumber: 'number',\n ZodArray: 'array',\n ZodObject: 'object',\n}\n"
},
{
"name": "dependencies.ts",
@ -80,7 +80,7 @@
},
{
"name": "interface.ts",
"content": "import type { Component, InputHTMLAttributes } from 'vue'\nimport type { z, ZodAny } from 'zod'\nimport type { INPUT_COMPONENTS } from './constant'\n\nexport interface FieldProps {\n fieldName: string\n label?: string\n required?: boolean\n config?: ConfigItem\n disabled?: boolean\n}\n\nexport interface Shape {\n type: string\n default?: any\n required?: boolean\n options?: string[]\n schema?: ZodAny\n}\n\nexport interface ConfigItem {\n /** Value for the `FormLabel` */\n label?: string\n /** Value for the `FormDescription` */\n description?: string\n /** Pick which component to be rendered. */\n component?: keyof typeof INPUT_COMPONENTS | Component\n /** Hide `FormLabel`. */\n hideLabel?: boolean\n inputProps?: InputHTMLAttributes\n}\n\n// Define a type to unwrap an array\ntype UnwrapArray<T> = T extends (infer U)[] ? U : never\n\nexport type Config<SchemaType extends object> = {\n // If SchemaType.key is an object, create a nested Config, otherwise ConfigItem\n [Key in keyof SchemaType]?:\n SchemaType[Key] extends any[]\n ? UnwrapArray<Config<SchemaType[Key]>>\n : SchemaType[Key] extends object\n ? Config<SchemaType[Key]>\n : ConfigItem;\n}\n\nexport enum DependencyType {\n DISABLES,\n REQUIRES,\n HIDES,\n SETS_OPTIONS,\n}\n\ninterface BaseDependency<SchemaType extends z.infer<z.ZodObject<any, any>>> {\n sourceField: keyof SchemaType\n type: DependencyType\n targetField: keyof SchemaType\n when: (sourceFieldValue: any, targetFieldValue: any) => boolean\n}\n\nexport type ValueDependency<SchemaType extends z.infer<z.ZodObject<any, any>>> =\n BaseDependency<SchemaType> & {\n type:\n | DependencyType.DISABLES\n | DependencyType.REQUIRES\n | DependencyType.HIDES\n }\n\nexport type EnumValues = readonly [string, ...string[]]\n\nexport type OptionsDependency<\n SchemaType extends z.infer<z.ZodObject<any, any>>,\n> = BaseDependency<SchemaType> & {\n type: DependencyType.SETS_OPTIONS\n\n // Partial array of values from sourceField that will trigger the dependency\n options: EnumValues\n}\n\nexport type Dependency<SchemaType extends z.infer<z.ZodObject<any, any>>> =\n | ValueDependency<SchemaType>\n | OptionsDependency<SchemaType>\n"
"content": "import type { Component, InputHTMLAttributes } from 'vue'\nimport type { z, ZodAny } from 'zod'\nimport type { INPUT_COMPONENTS } from './constant'\n\nexport interface FieldProps {\n fieldName: string\n label?: string\n required?: boolean\n config?: ConfigItem\n disabled?: boolean\n}\n\nexport interface Shape {\n type: string\n default?: any\n required?: boolean\n options?: string[]\n schema?: ZodAny\n}\n\nexport interface InputComponents {\n date: Component;\n select: Component;\n radio: Component;\n checkbox: Component;\n switch: Component;\n textarea: Component;\n number: Component;\n string: Component;\n file: Component;\n array: Component;\n object: Component;\n};\n\nexport interface ConfigItem {\n /** Value for the `FormLabel` */\n label?: string\n /** Value for the `FormDescription` */\n description?: string\n /** Pick which component to be rendered. */\n component?: keyof typeof INPUT_COMPONENTS | Component\n /** Hide `FormLabel`. */\n hideLabel?: boolean\n inputProps?: InputHTMLAttributes\n}\n\n// Define a type to unwrap an array\ntype UnwrapArray<T> = T extends (infer U)[] ? U : never\n\nexport type Config<SchemaType extends object> = {\n // If SchemaType.key is an object, create a nested Config, otherwise ConfigItem\n [Key in keyof SchemaType]?:\n SchemaType[Key] extends any[]\n ? UnwrapArray<Config<SchemaType[Key]>>\n : SchemaType[Key] extends object\n ? Config<SchemaType[Key]>\n : ConfigItem;\n}\n\nexport enum DependencyType {\n DISABLES,\n REQUIRES,\n HIDES,\n SETS_OPTIONS,\n}\n\ninterface BaseDependency<SchemaType extends z.infer<z.ZodObject<any, any>>> {\n sourceField: keyof SchemaType\n type: DependencyType\n targetField: keyof SchemaType\n when: (sourceFieldValue: any, targetFieldValue: any) => boolean\n}\n\nexport type ValueDependency<SchemaType extends z.infer<z.ZodObject<any, any>>> =\n BaseDependency<SchemaType> & {\n type:\n | DependencyType.DISABLES\n | DependencyType.REQUIRES\n | DependencyType.HIDES\n }\n\nexport type EnumValues = readonly [string, ...string[]]\n\nexport type OptionsDependency<\n SchemaType extends z.infer<z.ZodObject<any, any>>,\n> = BaseDependency<SchemaType> & {\n type: DependencyType.SETS_OPTIONS\n\n // Partial array of values from sourceField that will trigger the dependency\n options: EnumValues\n}\n\nexport type Dependency<SchemaType extends z.infer<z.ZodObject<any, any>>> =\n | ValueDependency<SchemaType>\n | OptionsDependency<SchemaType>\n"
},
{
"name": "utils.ts",

View File

@ -11,7 +11,7 @@
},
{
"name": "index.ts",
"content": "import { cva, type VariantProps } from 'class-variance-authority'\n\nexport { default as Button } from './Button.vue'\n\nexport const buttonVariants = cva(\n 'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50',\n {\n variants: {\n variant: {\n default: 'bg-primary text-primary-foreground shadow hover:bg-primary/90',\n destructive:\n 'bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90',\n outline:\n 'border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground',\n secondary:\n 'bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80',\n ghost: 'hover:bg-accent hover:text-accent-foreground',\n link: 'text-primary underline-offset-4 hover:underline',\n },\n size: {\n default: 'h-9 px-4 py-2',\n xs: 'h-7 rounded px-2',\n sm: 'h-8 rounded-md px-3 text-xs',\n lg: 'h-10 rounded-md px-8',\n icon: 'h-9 w-9',\n },\n },\n defaultVariants: {\n variant: 'default',\n size: 'default',\n },\n },\n)\n\nexport type ButtonVariants = VariantProps<typeof buttonVariants>\n"
"content": "import { cva, type VariantProps } from 'class-variance-authority'\n\nexport { default as Button } from './Button.vue'\n\nexport const buttonVariants = cva(\n 'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',\n {\n variants: {\n variant: {\n default: 'bg-primary text-primary-foreground shadow hover:bg-primary/90',\n destructive:\n 'bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90',\n outline:\n 'border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground',\n secondary:\n 'bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80',\n ghost: 'hover:bg-accent hover:text-accent-foreground',\n link: 'text-primary underline-offset-4 hover:underline',\n },\n size: {\n default: 'h-9 px-4 py-2',\n xs: 'h-7 rounded px-2',\n sm: 'h-8 rounded-md px-3 text-xs',\n lg: 'h-10 rounded-md px-8',\n icon: 'h-9 w-9',\n },\n },\n defaultVariants: {\n variant: 'default',\n size: 'default',\n },\n },\n)\n\nexport type ButtonVariants = VariantProps<typeof buttonVariants>\n"
}
],
"type": "components:ui"

View File

@ -39,7 +39,7 @@
},
{
"name": "index.ts",
"content": "import { cva } from 'class-variance-authority'\n\nexport { default as NavigationMenu } from './NavigationMenu.vue'\nexport { default as NavigationMenuContent } from './NavigationMenuContent.vue'\nexport { default as NavigationMenuItem } from './NavigationMenuItem.vue'\nexport { default as NavigationMenuLink } from './NavigationMenuLink.vue'\nexport { default as NavigationMenuList } from './NavigationMenuList.vue'\nexport { default as NavigationMenuTrigger } from './NavigationMenuTrigger.vue'\n\nexport const navigationMenuTriggerStyle = cva(\n 'group inline-flex h-9 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[active]:bg-accent/50 data-[state=open]:bg-accent/50',\n)\n"
"content": "import { cva } from 'class-variance-authority'\n\nexport { default as NavigationMenu } from './NavigationMenu.vue'\nexport { default as NavigationMenuContent } from './NavigationMenuContent.vue'\nexport { default as NavigationMenuItem } from './NavigationMenuItem.vue'\nexport { default as NavigationMenuLink } from './NavigationMenuLink.vue'\nexport { default as NavigationMenuList } from './NavigationMenuList.vue'\nexport { default as NavigationMenuTrigger } from './NavigationMenuTrigger.vue'\nexport { default as NavigationMenuViewport } from './NavigationMenuViewport.vue'\n\nexport const navigationMenuTriggerStyle = cva(\n 'group inline-flex h-9 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[active]:bg-accent/50 data-[state=open]:bg-accent/50',\n)\n"
}
],
"type": "components:ui"

View File

@ -43,7 +43,7 @@
},
{
"name": "SelectTrigger.vue",
"content": "<script setup lang=\"ts\">\nimport { cn } from '@/lib/utils'\nimport { CaretSortIcon } from '@radix-icons/vue'\nimport { SelectIcon, SelectTrigger, type SelectTriggerProps, useForwardProps } from 'radix-vue'\nimport { computed, type HTMLAttributes } from 'vue'\n\nconst props = defineProps<SelectTriggerProps & { class?: HTMLAttributes['class'] }>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwardedProps = useForwardProps(delegatedProps)\n</script>\n\n<template>\n <SelectTrigger\n v-bind=\"forwardedProps\"\n :class=\"cn(\n 'flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:truncate text-start',\n props.class,\n )\"\n >\n <slot />\n <SelectIcon as-child>\n <CaretSortIcon class=\"w-4 h-4 opacity-50 shrink-0\" />\n </SelectIcon>\n </SelectTrigger>\n</template>\n"
"content": "<script setup lang=\"ts\">\nimport { cn } from '@/lib/utils'\nimport { CaretSortIcon } from '@radix-icons/vue'\nimport { SelectIcon, SelectTrigger, type SelectTriggerProps, useForwardProps } from 'radix-vue'\nimport { computed, type HTMLAttributes } from 'vue'\n\nconst props = defineProps<SelectTriggerProps & { class?: HTMLAttributes['class'] }>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwardedProps = useForwardProps(delegatedProps)\n</script>\n\n<template>\n <SelectTrigger\n v-bind=\"forwardedProps\"\n :class=\"cn(\n 'flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background data-[placeholder]:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:truncate text-start',\n props.class,\n )\"\n >\n <slot />\n <SelectIcon as-child>\n <CaretSortIcon class=\"w-4 h-4 opacity-50 shrink-0\" />\n </SelectIcon>\n </SelectTrigger>\n</template>\n"
},
{
"name": "SelectValue.vue",

View File

@ -4,21 +4,18 @@
"@vueuse/core"
],
"registryDependencies": [
"Sheet.vue",
"SheetContent.vue",
"sheet",
"utils",
"Input.vue",
"Tooltip.vue",
"TooltipContent.vue",
"TooltipTrigger.vue",
"Skeleton.vue",
"Separator.vue",
"Button.vue"
"input",
"tooltip",
"skeleton",
"separator",
"button"
],
"files": [
{
"name": "Sidebar.vue",
"content": "<script setup lang=\"ts\">\nimport type { HTMLAttributes } from 'vue'\nimport Sheet from '@/lib/registry/new-york/ui/sheet/Sheet.vue'\nimport SheetContent from '@/lib/registry/new-york/ui/sheet/SheetContent.vue'\nimport { cn } from '@/lib/utils'\nimport { SIDEBAR_WIDTH_MOBILE, useSidebar } from './utils'\n\ndefineOptions({\n inheritAttrs: false,\n})\n\nconst props = withDefaults(defineProps<{\n side?: 'left' | 'right'\n variant?: 'sidebar' | 'floating' | 'inset'\n collapsible?: 'offcanvas' | 'icon' | 'none'\n class?: HTMLAttributes['class']\n}>(), {\n side: 'left',\n variant: 'sidebar',\n collapsible: 'offcanvas',\n})\n\nconst { isMobile, state, openMobile, setOpenMobile } = useSidebar()\n</script>\n\n<template>\n <div\n v-if=\"collapsible === 'none'\"\n :class=\"cn('flex h-full w-[--sidebar-width] flex-col bg-sidebar text-sidebar-foreground', props.class)\"\n v-bind=\"$attrs\"\n >\n <slot />\n </div>\n\n <Sheet v-else-if=\"isMobile\" :open=\"openMobile\" v-bind=\"$attrs\" @update:open=\"setOpenMobile\">\n <SheetContent\n data-sidebar=\"sidebar\"\n data-mobile=\"true\"\n class=\"w-[--sidebar-width] bg-sidebar p-0 text-sidebar-foreground [&>button]:hidden\"\n :style=\"{\n '--sidebar-width': SIDEBAR_WIDTH_MOBILE,\n }\"\n >\n <div class=\"flex h-full w-full flex-col\">\n <slot />\n </div>\n </SheetContent>\n </Sheet>\n\n <div\n v-else class=\"group peer hidden md:block\"\n :data-state=\"state\"\n :data-collapsible=\"state === 'collapsed' ? collapsible : ''\"\n :data-variant=\"variant\"\n :data-side=\"side\"\n >\n <!-- This is what handles the sidebar gap on desktop -->\n <div\n :class=\"cn(\n 'duration-200 relative h-svh w-[--sidebar-width] bg-transparent transition-[width] ease-linear',\n 'group-data-[collapsible=offcanvas]:w-0',\n 'group-data-[side=right]:rotate-180',\n variant === 'floating' || variant === 'inset'\n ? 'group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4))]'\n : 'group-data-[collapsible=icon]:w-[--sidebar-width-icon]',\n )\"\n />\n <div\n :class=\"cn(\n 'duration-200 fixed inset-y-0 z-10 hidden h-svh w-[--sidebar-width] transition-[left,right,width] ease-linear md:flex',\n side === 'left'\n ? 'left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]'\n : 'right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]',\n // Adjust the padding for floating and inset variants.\n variant === 'floating' || variant === 'inset'\n ? 'p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4)_+2px)]'\n : 'group-data-[collapsible=icon]:w-[--sidebar-width-icon] group-data-[side=left]:border-r group-data-[side=right]:border-l',\n props.class,\n )\"\n v-bind=\"$attrs\"\n >\n <div\n data-sidebar=\"sidebar\"\n class=\"flex h-full w-full flex-col bg-sidebar group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:border-sidebar-border group-data-[variant=floating]:shadow\"\n >\n <slot />\n </div>\n </div>\n </div>\n</template>\n"
"content": "<script setup lang=\"ts\">\nimport type { SidebarProps } from '.'\nimport { Sheet, SheetContent } from '@/lib/registry/new-york/ui/sheet'\nimport { cn } from '@/lib/utils'\nimport { SIDEBAR_WIDTH_MOBILE, useSidebar } from './utils'\n\ndefineOptions({\n inheritAttrs: false,\n})\n\nconst props = withDefaults(defineProps<SidebarProps>(), {\n side: 'left',\n variant: 'sidebar',\n collapsible: 'offcanvas',\n})\n\nconst { isMobile, state, openMobile, setOpenMobile } = useSidebar()\n</script>\n\n<template>\n <div\n v-if=\"collapsible === 'none'\"\n :class=\"cn('flex h-full w-[--sidebar-width] flex-col bg-sidebar text-sidebar-foreground', props.class)\"\n v-bind=\"$attrs\"\n >\n <slot />\n </div>\n\n <Sheet v-else-if=\"isMobile\" :open=\"openMobile\" v-bind=\"$attrs\" @update:open=\"setOpenMobile\">\n <SheetContent\n data-sidebar=\"sidebar\"\n data-mobile=\"true\"\n :side=\"side\"\n class=\"w-[--sidebar-width] bg-sidebar p-0 text-sidebar-foreground [&>button]:hidden\"\n :style=\"{\n '--sidebar-width': SIDEBAR_WIDTH_MOBILE,\n }\"\n >\n <div class=\"flex h-full w-full flex-col\">\n <slot />\n </div>\n </SheetContent>\n </Sheet>\n\n <div\n v-else class=\"group peer hidden md:block\"\n :data-state=\"state\"\n :data-collapsible=\"state === 'collapsed' ? collapsible : ''\"\n :data-variant=\"variant\"\n :data-side=\"side\"\n >\n <!-- This is what handles the sidebar gap on desktop -->\n <div\n :class=\"cn(\n 'duration-200 relative h-svh w-[--sidebar-width] bg-transparent transition-[width] ease-linear',\n 'group-data-[collapsible=offcanvas]:w-0',\n 'group-data-[side=right]:rotate-180',\n variant === 'floating' || variant === 'inset'\n ? 'group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4))]'\n : 'group-data-[collapsible=icon]:w-[--sidebar-width-icon]',\n )\"\n />\n <div\n :class=\"cn(\n 'duration-200 fixed inset-y-0 z-10 hidden h-svh w-[--sidebar-width] transition-[left,right,width] ease-linear md:flex',\n side === 'left'\n ? 'left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]'\n : 'right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]',\n // Adjust the padding for floating and inset variants.\n variant === 'floating' || variant === 'inset'\n ? 'p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4)_+2px)]'\n : 'group-data-[collapsible=icon]:w-[--sidebar-width-icon] group-data-[side=left]:border-r group-data-[side=right]:border-l',\n props.class,\n )\"\n v-bind=\"$attrs\"\n >\n <div\n data-sidebar=\"sidebar\"\n class=\"flex h-full w-full flex-col bg-sidebar group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:border-sidebar-border group-data-[variant=floating]:shadow\"\n >\n <slot />\n </div>\n </div>\n </div>\n</template>\n"
},
{
"name": "SidebarContent.vue",
@ -50,7 +47,7 @@
},
{
"name": "SidebarInput.vue",
"content": "<script setup lang=\"ts\">\nimport type { HTMLAttributes } from 'vue'\nimport Input from '@/lib/registry/new-york/ui/input/Input.vue'\nimport { cn } from '@/lib/utils'\n\nconst props = defineProps<{\n class?: HTMLAttributes['class']\n}>()\n</script>\n\n<template>\n <Input\n data-sidebar=\"input\"\n :class=\"cn(\n 'h-8 w-full bg-background shadow-none focus-visible:ring-2 focus-visible:ring-sidebar-ring',\n props.class,\n )\"\n >\n <slot />\n </Input>\n</template>\n"
"content": "<script setup lang=\"ts\">\nimport type { HTMLAttributes } from 'vue'\nimport { Input } from '@/lib/registry/new-york/ui/input'\nimport { cn } from '@/lib/utils'\n\nconst props = defineProps<{\n class?: HTMLAttributes['class']\n}>()\n</script>\n\n<template>\n <Input\n data-sidebar=\"input\"\n :class=\"cn(\n 'h-8 w-full bg-background shadow-none focus-visible:ring-2 focus-visible:ring-sidebar-ring',\n props.class,\n )\"\n >\n <slot />\n </Input>\n</template>\n"
},
{
"name": "SidebarInset.vue",
@ -62,7 +59,7 @@
},
{
"name": "SidebarMenuAction.vue",
"content": "<script setup lang=\"ts\">\nimport type { HTMLAttributes } from 'vue'\nimport { cn } from '@/lib/utils'\nimport { Primitive, type PrimitiveProps } from 'radix-vue'\n\nconst props = withDefaults(defineProps<PrimitiveProps & {\n showOnHover?: boolean\n class?: HTMLAttributes['class']\n}>(), {\n as: 'button',\n})\n</script>\n\n<template>\n <Primitive\n data-sidebar=\"menu-action\"\n :class=\"cn(\n 'absolute right-1 top-1.5 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground outline-none ring-sidebar-ring transition-transform hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 peer-hover/menu-button:text-sidebar-accent-foreground [&>svg]:size-4 [&>svg]:shrink-0',\n // Increases the hit area of the button on mobile.\n 'after:absolute after:-inset-2 after:md:hidden',\n 'peer-data-[size=sm]/menu-button:top-1',\n 'peer-data-[size=default]/menu-button:top-1.5',\n 'peer-data-[size=lg]/menu-button:top-2.5',\n 'group-data-[collapsible=icon]:hidden',\n showOnHover\n && 'group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 data-[state=open]:opacity-100 peer-data-[active=true]/menu-button:text-sidebar-accent-foreground md:opacity-0',\n props.class,\n )\"\n :as=\"as\"\n :as-child=\"asChild\"\n />\n</template>\n"
"content": "<script setup lang=\"ts\">\nimport type { HTMLAttributes } from 'vue'\nimport { cn } from '@/lib/utils'\nimport { Primitive, type PrimitiveProps } from 'radix-vue'\n\nconst props = withDefaults(defineProps<PrimitiveProps & {\n showOnHover?: boolean\n class?: HTMLAttributes['class']\n}>(), {\n as: 'button',\n})\n</script>\n\n<template>\n <Primitive\n data-sidebar=\"menu-action\"\n :class=\"cn(\n 'absolute right-1 top-1.5 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground outline-none ring-sidebar-ring transition-transform hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 peer-hover/menu-button:text-sidebar-accent-foreground [&>svg]:size-4 [&>svg]:shrink-0',\n // Increases the hit area of the button on mobile.\n 'after:absolute after:-inset-2 after:md:hidden',\n 'peer-data-[size=sm]/menu-button:top-1',\n 'peer-data-[size=default]/menu-button:top-1.5',\n 'peer-data-[size=lg]/menu-button:top-2.5',\n 'group-data-[collapsible=icon]:hidden',\n showOnHover\n && 'group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 data-[state=open]:opacity-100 peer-data-[active=true]/menu-button:text-sidebar-accent-foreground md:opacity-0',\n props.class,\n )\"\n :as=\"as\"\n :as-child=\"asChild\"\n >\n <slot />\n </Primitive>\n</template>\n"
},
{
"name": "SidebarMenuBadge.vue",
@ -70,7 +67,7 @@
},
{
"name": "SidebarMenuButton.vue",
"content": "<script setup lang=\"ts\">\nimport Tooltip from '@/lib/registry/new-york/ui/tooltip/Tooltip.vue'\nimport TooltipContent from '@/lib/registry/new-york/ui/tooltip/TooltipContent.vue'\nimport TooltipTrigger from '@/lib/registry/new-york/ui/tooltip/TooltipTrigger.vue'\nimport { type Component, computed } from 'vue'\nimport SidebarMenuButtonChild, { type SidebarMenuButtonProps } from './SidebarMenuButtonChild.vue'\nimport { useSidebar } from './utils'\n\ndefineOptions({\n inheritAttrs: false,\n})\n\nconst props = withDefaults(defineProps<SidebarMenuButtonProps & {\n tooltip?: string | Component\n}>(), {\n as: 'button',\n variant: 'default',\n size: 'default',\n})\n\nconst { isMobile, state } = useSidebar()\n\nconst delegatedProps = computed(() => {\n const { tooltip, ...delegated } = props\n return delegated\n})\n</script>\n\n<template>\n <SidebarMenuButtonChild v-if=\"!tooltip\" v-bind=\"{ ...delegatedProps, ...$attrs }\">\n <slot />\n </SidebarMenuButtonChild>\n\n <Tooltip v-else>\n <TooltipTrigger as-child>\n <SidebarMenuButtonChild v-bind=\"{ ...delegatedProps, ...$attrs }\">\n <slot />\n </SidebarMenuButtonChild>\n </TooltipTrigger>\n <TooltipContent\n side=\"right\"\n align=\"center\"\n :hidden=\"state !== 'collapsed' || isMobile\"\n >\n <template v-if=\"typeof tooltip === 'string'\">\n {{ tooltip }}\n </template>\n <component :is=\"tooltip\" v-else />\n </TooltipContent>\n </Tooltip>\n</template>\n"
"content": "<script setup lang=\"ts\">\nimport { Tooltip, TooltipContent, TooltipTrigger } from '@/lib/registry/new-york/ui/tooltip'\nimport { type Component, computed } from 'vue'\nimport SidebarMenuButtonChild, { type SidebarMenuButtonProps } from './SidebarMenuButtonChild.vue'\nimport { useSidebar } from './utils'\n\ndefineOptions({\n inheritAttrs: false,\n})\n\nconst props = withDefaults(defineProps<SidebarMenuButtonProps & {\n tooltip?: string | Component\n}>(), {\n as: 'button',\n variant: 'default',\n size: 'default',\n})\n\nconst { isMobile, state } = useSidebar()\n\nconst delegatedProps = computed(() => {\n const { tooltip, ...delegated } = props\n return delegated\n})\n</script>\n\n<template>\n <SidebarMenuButtonChild v-if=\"!tooltip\" v-bind=\"{ ...delegatedProps, ...$attrs }\">\n <slot />\n </SidebarMenuButtonChild>\n\n <Tooltip v-else>\n <TooltipTrigger as-child>\n <SidebarMenuButtonChild v-bind=\"{ ...delegatedProps, ...$attrs }\">\n <slot />\n </SidebarMenuButtonChild>\n </TooltipTrigger>\n <TooltipContent\n side=\"right\"\n align=\"center\"\n :hidden=\"state !== 'collapsed' || isMobile\"\n >\n <template v-if=\"typeof tooltip === 'string'\">\n {{ tooltip }}\n </template>\n <component :is=\"tooltip\" v-else />\n </TooltipContent>\n </Tooltip>\n</template>\n"
},
{
"name": "SidebarMenuButtonChild.vue",
@ -82,7 +79,7 @@
},
{
"name": "SidebarMenuSkeleton.vue",
"content": "<script setup lang=\"ts\">\nimport Skeleton from '@/lib/registry/new-york/ui/skeleton/Skeleton.vue'\nimport { cn } from '@/lib/utils'\nimport { computed, type HTMLAttributes } from 'vue'\n\nconst props = defineProps<{\n showIcon?: boolean\n class?: HTMLAttributes['class']\n}>()\n\nconst width = computed(() => {\n return `${Math.floor(Math.random() * 40) + 50}%`\n})\n</script>\n\n<template>\n <div\n data-sidebar=\"menu-skeleton\"\n :class=\"cn('rounded-md h-8 flex gap-2 px-2 items-center', props.class)\"\n >\n <Skeleton\n v-if=\"showIcon\"\n class=\"size-4 rounded-md\"\n data-sidebar=\"menu-skeleton-icon\"\n />\n\n <Skeleton\n class=\"h-4 flex-1 max-w-[--skeleton-width]\"\n data-sidebar=\"menu-skeleton-text\"\n :style=\"{ '--skeleton-width': width }\"\n />\n </div>\n</template>\n"
"content": "<script setup lang=\"ts\">\nimport { Skeleton } from '@/lib/registry/new-york/ui/skeleton'\nimport { cn } from '@/lib/utils'\nimport { computed, type HTMLAttributes } from 'vue'\n\nconst props = defineProps<{\n showIcon?: boolean\n class?: HTMLAttributes['class']\n}>()\n\nconst width = computed(() => {\n return `${Math.floor(Math.random() * 40) + 50}%`\n})\n</script>\n\n<template>\n <div\n data-sidebar=\"menu-skeleton\"\n :class=\"cn('rounded-md h-8 flex gap-2 px-2 items-center', props.class)\"\n >\n <Skeleton\n v-if=\"showIcon\"\n class=\"size-4 rounded-md\"\n data-sidebar=\"menu-skeleton-icon\"\n />\n\n <Skeleton\n class=\"h-4 flex-1 max-w-[--skeleton-width]\"\n data-sidebar=\"menu-skeleton-text\"\n :style=\"{ '--skeleton-width': width }\"\n />\n </div>\n</template>\n"
},
{
"name": "SidebarMenuSub.vue",
@ -98,7 +95,7 @@
},
{
"name": "SidebarProvider.vue",
"content": "<script setup lang=\"ts\">\nimport { cn } from '@/lib/utils'\nimport { useEventListener, useVModel } from '@vueuse/core'\nimport { TooltipProvider } from 'radix-vue'\nimport { computed, type HTMLAttributes, type Ref, ref } from 'vue'\nimport { provideSidebarContext, SIDEBAR_COOKIE_MAX_AGE, SIDEBAR_COOKIE_NAME, SIDEBAR_KEYBOARD_SHORTCUT, SIDEBAR_WIDTH, SIDEBAR_WIDTH_ICON } from './utils'\n\nconst props = withDefaults(defineProps<{\n defaultOpen?: boolean\n open?: boolean\n class?: HTMLAttributes['class']\n}>(), {\n defaultOpen: true,\n open: undefined,\n})\n\nconst emits = defineEmits<{\n 'update:open': [open: boolean]\n}>()\n\nconst isMobile = ref(false) // useIsMobile()\nconst openMobile = ref(false)\n\nconst open = useVModel(props, 'open', emits, {\n defaultValue: props.defaultOpen ?? false,\n passive: (props.open === undefined) as false,\n}) as Ref<boolean>\n\nfunction setOpen(value: boolean) {\n open.value = value // emits('update:open', value)\n\n // This sets the cookie to keep the sidebar state.\n document.cookie = `${SIDEBAR_COOKIE_NAME}=${open}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`\n}\n\nfunction setOpenMobile(value: boolean) {\n openMobile.value = value\n}\n\n// Helper to toggle the sidebar.\nfunction toggleSidebar() {\n return isMobile.value ? setOpenMobile(!open.value) : setOpen(!open.value)\n}\n\nuseEventListener('keydown', (event: KeyboardEvent) => {\n if (event.key === SIDEBAR_KEYBOARD_SHORTCUT && (event.metaKey || event.ctrlKey)) {\n event.preventDefault()\n toggleSidebar()\n }\n})\n\n// We add a state so that we can do data-state=\"expanded\" or \"collapsed\".\n// This makes it easier to style the sidebar with Tailwind classes.\nconst state = computed(() => open.value ? 'expanded' : 'collapsed')\n\nprovideSidebarContext({\n state,\n open,\n setOpen,\n isMobile,\n openMobile,\n setOpenMobile,\n toggleSidebar,\n})\n</script>\n\n<template>\n <TooltipProvider :delay-duration=\"0\">\n <div\n :style=\"{\n '--sidebar-width': SIDEBAR_WIDTH,\n '--sidebar-width-icon': SIDEBAR_WIDTH_ICON,\n }\"\n :class=\"cn('group/sidebar-wrapper flex min-h-svh w-full text-sidebar-foreground has-[[data-variant=inset]]:bg-sidebar', props.class)\"\n >\n <slot />\n </div>\n </TooltipProvider>\n</template>\n"
"content": "<script setup lang=\"ts\">\nimport { cn } from '@/lib/utils'\nimport { useEventListener, useMediaQuery, useVModel } from '@vueuse/core'\nimport { TooltipProvider } from 'radix-vue'\nimport { computed, type HTMLAttributes, type Ref, ref } from 'vue'\nimport { provideSidebarContext, SIDEBAR_COOKIE_MAX_AGE, SIDEBAR_COOKIE_NAME, SIDEBAR_KEYBOARD_SHORTCUT, SIDEBAR_WIDTH, SIDEBAR_WIDTH_ICON } from './utils'\n\nconst props = withDefaults(defineProps<{\n defaultOpen?: boolean\n open?: boolean\n class?: HTMLAttributes['class']\n}>(), {\n defaultOpen: true,\n open: undefined,\n})\n\nconst emits = defineEmits<{\n 'update:open': [open: boolean]\n}>()\n\nconst isMobile = useMediaQuery('(max-width: 768px)')\nconst openMobile = ref(false)\n\nconst open = useVModel(props, 'open', emits, {\n defaultValue: props.defaultOpen ?? false,\n passive: (props.open === undefined) as false,\n}) as Ref<boolean>\n\nfunction setOpen(value: boolean) {\n open.value = value // emits('update:open', value)\n\n // This sets the cookie to keep the sidebar state.\n document.cookie = `${SIDEBAR_COOKIE_NAME}=${open.value}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`\n}\n\nfunction setOpenMobile(value: boolean) {\n openMobile.value = value\n}\n\n// Helper to toggle the sidebar.\nfunction toggleSidebar() {\n return isMobile.value ? setOpenMobile(!openMobile.value) : setOpen(!open.value)\n}\n\nuseEventListener('keydown', (event: KeyboardEvent) => {\n if (event.key === SIDEBAR_KEYBOARD_SHORTCUT && (event.metaKey || event.ctrlKey)) {\n event.preventDefault()\n toggleSidebar()\n }\n})\n\n// We add a state so that we can do data-state=\"expanded\" or \"collapsed\".\n// This makes it easier to style the sidebar with Tailwind classes.\nconst state = computed(() => open.value ? 'expanded' : 'collapsed')\n\nprovideSidebarContext({\n state,\n open,\n setOpen,\n isMobile,\n openMobile,\n setOpenMobile,\n toggleSidebar,\n})\n</script>\n\n<template>\n <TooltipProvider :delay-duration=\"0\">\n <div\n :style=\"{\n '--sidebar-width': SIDEBAR_WIDTH,\n '--sidebar-width-icon': SIDEBAR_WIDTH_ICON,\n }\"\n :class=\"cn('group/sidebar-wrapper flex min-h-svh w-full text-sidebar-foreground has-[[data-variant=inset]]:bg-sidebar', props.class)\"\n v-bind=\"$attrs\"\n >\n <slot />\n </div>\n </TooltipProvider>\n</template>\n"
},
{
"name": "SidebarRail.vue",
@ -106,15 +103,15 @@
},
{
"name": "SidebarSeparator.vue",
"content": "<script setup lang=\"ts\">\nimport type { HTMLAttributes } from 'vue'\nimport Separator from '@/lib/registry/new-york/ui/separator/Separator.vue'\nimport { cn } from '@/lib/utils'\n\nconst props = defineProps<{\n class?: HTMLAttributes['class']\n}>()\n</script>\n\n<template>\n <Separator\n data-sidebar=\"separator\"\n :class=\"cn('mx-2 w-auto bg-sidebar-border', props.class)\"\n >\n <slot />\n </Separator>\n</template>\n"
"content": "<script setup lang=\"ts\">\nimport type { HTMLAttributes } from 'vue'\nimport { Separator } from '@/lib/registry/new-york/ui/separator'\nimport { cn } from '@/lib/utils'\n\nconst props = defineProps<{\n class?: HTMLAttributes['class']\n}>()\n</script>\n\n<template>\n <Separator\n data-sidebar=\"separator\"\n :class=\"cn('mx-2 w-auto bg-sidebar-border', props.class)\"\n >\n <slot />\n </Separator>\n</template>\n"
},
{
"name": "SidebarTrigger.vue",
"content": "<script setup lang=\"ts\">\nimport type { HTMLAttributes } from 'vue'\nimport Button from '@/lib/registry/new-york/ui/button/Button.vue'\nimport { cn } from '@/lib/utils'\nimport { PanelLeft } from 'lucide-vue-next'\nimport { useSidebar } from './utils'\n\nconst props = defineProps<{\n class?: HTMLAttributes['class']\n}>()\n\nconst { toggleSidebar } = useSidebar()\n</script>\n\n<template>\n <Button\n data-sidebar=\"trigger\"\n variant=\"ghost\"\n size=\"icon\"\n :class=\"cn('h-7 w-7', props.class)\"\n @click=\"toggleSidebar\"\n >\n <PanelLeft />\n <span class=\"sr-only\">Toggle Sidebar</span>\n </Button>\n</template>\n"
"content": "<script setup lang=\"ts\">\nimport type { HTMLAttributes } from 'vue'\nimport { Button } from '@/lib/registry/new-york/ui/button'\nimport { cn } from '@/lib/utils'\nimport { PanelLeft } from 'lucide-vue-next'\nimport { useSidebar } from './utils'\n\nconst props = defineProps<{\n class?: HTMLAttributes['class']\n}>()\n\nconst { toggleSidebar } = useSidebar()\n</script>\n\n<template>\n <Button\n data-sidebar=\"trigger\"\n variant=\"ghost\"\n size=\"icon\"\n :class=\"cn('h-7 w-7', props.class)\"\n @click=\"toggleSidebar\"\n >\n <PanelLeft />\n <span class=\"sr-only\">Toggle Sidebar</span>\n </Button>\n</template>\n"
},
{
"name": "index.ts",
"content": "import { cva, type VariantProps } from 'class-variance-authority'\n\nexport { default as Sidebar } from './Sidebar.vue'\nexport { default as SidebarContent } from './SidebarContent.vue'\nexport { default as SidebarFooter } from './SidebarFooter.vue'\nexport { default as SidebarGroup } from './SidebarGroup.vue'\nexport { default as SidebarGroupAction } from './SidebarGroupAction.vue'\nexport { default as SidebarGroupContent } from './SidebarGroupContent.vue'\nexport { default as SidebarGroupLabel } from './SidebarGroupLabel.vue'\nexport { default as SidebarHeader } from './SidebarHeader.vue'\nexport { default as SidebarInput } from './SidebarInput.vue'\nexport { default as SidebarInset } from './SidebarInset.vue'\nexport { default as SidebarMenu } from './SidebarMenu.vue'\nexport { default as SidebarMenuAction } from './SidebarMenuAction.vue'\nexport { default as SidebarMenuBadge } from './SidebarMenuBadge.vue'\nexport { default as SidebarMenuButton } from './SidebarMenuButton.vue'\nexport { default as SidebarMenuItem } from './SidebarMenuItem.vue'\nexport { default as SidebarMenuSkeleton } from './SidebarMenuSkeleton.vue'\nexport { default as SidebarMenuSub } from './SidebarMenuSub.vue'\nexport { default as SidebarMenuSubButton } from './SidebarMenuSubButton.vue'\nexport { default as SidebarMenuSubItem } from './SidebarMenuSubItem.vue'\nexport { default as SidebarProvider } from './SidebarProvider.vue'\nexport { default as SidebarRail } from './SidebarRail.vue'\nexport { default as SidebarSeparator } from './SidebarSeparator.vue'\nexport { default as SidebarTrigger } from './SidebarTrigger.vue'\n\nexport { useSidebar } from './utils'\n\nexport const sidebarMenuButtonVariants = cva(\n 'peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-none ring-sidebar-ring transition-[width,height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-[[data-sidebar=menu-action]]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground group-data-[collapsible=icon]:!size-8 group-data-[collapsible=icon]:!p-2 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0',\n {\n variants: {\n variant: {\n default: 'hover:bg-sidebar-accent hover:text-sidebar-accent-foreground',\n outline:\n 'bg-background shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))]',\n },\n size: {\n default: 'h-8 text-sm',\n sm: 'h-7 text-xs',\n lg: 'h-12 text-sm group-data-[collapsible=icon]:!p-0',\n },\n },\n defaultVariants: {\n variant: 'default',\n size: 'default',\n },\n },\n)\n\nexport type SidebarMenuButtonVariants = VariantProps<typeof sidebarMenuButtonVariants>\n"
"content": "import type { HTMLAttributes } from 'vue'\nimport { cva, type VariantProps } from 'class-variance-authority'\n\nexport interface SidebarProps {\n side?: 'left' | 'right'\n variant?: 'sidebar' | 'floating' | 'inset'\n collapsible?: 'offcanvas' | 'icon' | 'none'\n class?: HTMLAttributes['class']\n}\n\nexport { default as Sidebar } from './Sidebar.vue'\nexport { default as SidebarContent } from './SidebarContent.vue'\nexport { default as SidebarFooter } from './SidebarFooter.vue'\nexport { default as SidebarGroup } from './SidebarGroup.vue'\nexport { default as SidebarGroupAction } from './SidebarGroupAction.vue'\nexport { default as SidebarGroupContent } from './SidebarGroupContent.vue'\nexport { default as SidebarGroupLabel } from './SidebarGroupLabel.vue'\nexport { default as SidebarHeader } from './SidebarHeader.vue'\nexport { default as SidebarInput } from './SidebarInput.vue'\nexport { default as SidebarInset } from './SidebarInset.vue'\nexport { default as SidebarMenu } from './SidebarMenu.vue'\nexport { default as SidebarMenuAction } from './SidebarMenuAction.vue'\nexport { default as SidebarMenuBadge } from './SidebarMenuBadge.vue'\nexport { default as SidebarMenuButton } from './SidebarMenuButton.vue'\nexport { default as SidebarMenuItem } from './SidebarMenuItem.vue'\nexport { default as SidebarMenuSkeleton } from './SidebarMenuSkeleton.vue'\nexport { default as SidebarMenuSub } from './SidebarMenuSub.vue'\nexport { default as SidebarMenuSubButton } from './SidebarMenuSubButton.vue'\nexport { default as SidebarMenuSubItem } from './SidebarMenuSubItem.vue'\nexport { default as SidebarProvider } from './SidebarProvider.vue'\nexport { default as SidebarRail } from './SidebarRail.vue'\nexport { default as SidebarSeparator } from './SidebarSeparator.vue'\nexport { default as SidebarTrigger } from './SidebarTrigger.vue'\n\nexport { useSidebar } from './utils'\n\nexport const sidebarMenuButtonVariants = cva(\n 'peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-none ring-sidebar-ring transition-[width,height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-[[data-sidebar=menu-action]]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground group-data-[collapsible=icon]:!size-8 group-data-[collapsible=icon]:!p-2 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0',\n {\n variants: {\n variant: {\n default: 'hover:bg-sidebar-accent hover:text-sidebar-accent-foreground',\n outline:\n 'bg-background shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))]',\n },\n size: {\n default: 'h-8 text-sm',\n sm: 'h-7 text-xs',\n lg: 'h-12 text-sm group-data-[collapsible=icon]:!p-0',\n },\n },\n defaultVariants: {\n variant: 'default',\n size: 'default',\n },\n },\n)\n\nexport type SidebarMenuButtonVariants = VariantProps<typeof sidebarMenuButtonVariants>\n"
},
{
"name": "utils.ts",

View File

@ -7,7 +7,7 @@
"files": [
{
"name": "Switch.vue",
"content": "<script setup lang=\"ts\">\nimport { cn } from '@/lib/utils'\nimport {\n SwitchRoot,\n type SwitchRootEmits,\n type SwitchRootProps,\n SwitchThumb,\n useForwardPropsEmits,\n} from 'radix-vue'\nimport { computed, type HTMLAttributes } from 'vue'\n\nconst props = defineProps<SwitchRootProps & { class?: HTMLAttributes['class'] }>()\n\nconst emits = defineEmits<SwitchRootEmits>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits)\n</script>\n\n<template>\n <SwitchRoot\n v-bind=\"forwarded\"\n :class=\"cn(\n 'peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input',\n props.class,\n )\"\n >\n <SwitchThumb\n :class=\"cn('pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0')\"\n />\n </SwitchRoot>\n</template>\n"
"content": "<script setup lang=\"ts\">\nimport { cn } from '@/lib/utils'\nimport {\n SwitchRoot,\n type SwitchRootEmits,\n type SwitchRootProps,\n SwitchThumb,\n useForwardPropsEmits,\n} from 'radix-vue'\nimport { computed, type HTMLAttributes } from 'vue'\n\nconst props = defineProps<SwitchRootProps & { class?: HTMLAttributes['class'] }>()\n\nconst emits = defineEmits<SwitchRootEmits>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits)\n</script>\n\n<template>\n <SwitchRoot\n v-bind=\"forwarded\"\n :class=\"cn(\n 'peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input',\n props.class,\n )\"\n >\n <SwitchThumb\n :class=\"cn('pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0')\"\n >\n <slot name=\"thumb\" />\n </SwitchThumb>\n </SwitchRoot>\n</template>\n"
},
{
"name": "index.ts",

View File

@ -1,7 +1,7 @@
{
"name": "shadcn-vue",
"type": "module",
"version": "0.11.0",
"version": "0.11.3",
"private": true,
"packageManager": "pnpm@9.10.0",
"license": "MIT",

View File

@ -1,7 +1,7 @@
{
"name": "shadcn-vue",
"type": "module",
"version": "0.11.0",
"version": "0.11.3",
"description": "Add components to your apps.",
"publishConfig": {
"access": "public"
@ -57,7 +57,6 @@
"consola": "^3.2.3",
"diff": "^7.0.0",
"fs-extra": "^11.2.0",
"https-proxy-agent": "^7.0.5",
"lodash-es": "^4.17.21",
"magic-string": "^0.30.12",
"nypm": "^0.3.12",
@ -69,7 +68,8 @@
"radix-vue": "catalog:",
"semver": "^7.6.3",
"tsconfig-paths": "^4.2.0",
"vue-metamorph": "^3.2.0",
"undici": "^7.0.0",
"vue-metamorph": "3.2.0",
"zod": "^3.23.8"
},
"devDependencies": {

View File

@ -4,11 +4,10 @@ import { Command } from 'commander'
import { consola } from 'consola'
import { colors } from 'consola/utils'
import { template } from 'lodash-es'
import { addDependency, addDevDependency } from 'nypm'
import { addDependency } from 'nypm'
import ora from 'ora'
import path from 'pathe'
import prompts from 'prompts'
import { gte } from 'semver'
import { z } from 'zod'
import {
type Config,
@ -40,9 +39,6 @@ const PROJECT_DEPENDENCIES = {
'tailwind-merge',
'radix-vue',
],
nuxt: [
'@nuxtjs/tailwindcss',
],
}
const initOptionsSchema = z.object({
@ -310,23 +306,13 @@ export async function runInit(cwd: string, config: Config) {
// Install dependencies.
const dependenciesSpinner = ora('Installing dependencies...')?.start()
// Starting from `shadcn-nuxt` version 0.10.4, Base dependencies are handled by the module so no need to re-add them by the CLI
const baseDeps = gte(shadcnNuxt?.version || '0.0.0', '0.10.4') ? [] : PROJECT_DEPENDENCIES.base
const iconsDep = config.style === 'new-york' ? ['@radix-icons/vue'] : ['lucide-vue-next']
const deps = baseDeps.concat(iconsDep).filter(Boolean)
const deps = PROJECT_DEPENDENCIES.base.concat(iconsDep).filter(Boolean)
await Promise.allSettled(
[
config.framework === 'nuxt' && await addDevDependency(PROJECT_DEPENDENCIES.nuxt, {
cwd,
silent: true,
}),
await addDependency(deps, {
cwd,
silent: true,
}),
],
)
await addDependency(deps, {
cwd,
silent: true,
})
dependenciesSpinner?.succeed()
}

View File

@ -9,13 +9,13 @@ import {
stylesSchema,
} from '@/src/utils/registry/schema'
import consola from 'consola'
import { HttpsProxyAgent } from 'https-proxy-agent'
import { ofetch } from 'ofetch'
import path from 'pathe'
import { ProxyAgent } from 'undici'
const baseUrl = process.env.COMPONENTS_REGISTRY_URL ?? 'https://www.shadcn-vue.com'
const agent = process.env.https_proxy
? new HttpsProxyAgent(process.env.https_proxy)
? new ProxyAgent(process.env.https_proxy)
: undefined
export async function getRegistryIndex() {
@ -144,8 +144,7 @@ async function fetchRegistry(paths: string[]) {
const results = await Promise.all(
paths.map(async (path) => {
const response = await ofetch(`${baseUrl}/registry/${path}`, {
// @ts-expect-error agent type
agent,
dispatcher: agent,
})
return response

View File

@ -1,7 +1,7 @@
{
"name": "shadcn-nuxt",
"type": "module",
"version": "0.11.0",
"version": "0.11.3",
"description": "Add shadcn-vue module to Nuxt",
"publishConfig": {
"access": "public"
@ -25,29 +25,28 @@
"dist"
],
"scripts": {
"prepack": "nuxt-module-build build",
"prepack": "nuxt-module-build prepare && nuxt-module-build build",
"dev": "nuxi dev playground",
"dev:build": "nuxi build playground",
"dev:prepare": "nuxt-module-build build --stub && nuxt-module-build prepare && nuxi prepare playground",
"lint": "eslint .",
"test": "vitest run",
"test:watch": "vitest watch",
"release": "pnpm run prepack && pnpm publish && git push --follow-tags"
"release": "pnpm run prepack && pnpm publish && git push --follow-tags",
"pub:release": "pnpm prepack && pnpm publish --no-git-checks --access public"
},
"dependencies": {
"@nuxt/kit": "^3.12.4",
"@oxc-parser/wasm": "catalog:",
"class-variance-authority": "^0.7.0",
"tailwind-merge": "^2.5.2",
"tailwindcss-animate": "^1.0.7"
"typescript": "catalog:"
},
"devDependencies": {
"@nuxt/eslint-config": "^0.5.0",
"@nuxt/module-builder": "^0.8.2",
"@nuxt/schema": "^3.12.4",
"@nuxt/test-utils": "^3.14.0",
"@nuxtjs/color-mode": "^3.4.4",
"@nuxtjs/tailwindcss": "^6.12.1",
"@nuxtjs/color-mode": "^3.5.1",
"@nuxtjs/tailwindcss": "^6.12.2",
"@types/node": "^20.14.15",
"nuxt": "^3.12.4"
}

View File

@ -2,11 +2,13 @@
"$schema": "https://shadcn-vue.com/schema.json",
"style": "default",
"typescript": true,
"tsConfigPath": ".nuxt/tsconfig.json",
"tailwind": {
"config": "tailwind.config.js",
"css": "assets/css/tailwind.css",
"baseColor": "slate",
"cssVariables": true
"cssVariables": true,
"prefix": ""
},
"framework": "nuxt",
"aliases": {

View File

@ -1,7 +1,8 @@
export default defineNuxtConfig({
modules: ['@nuxtjs/tailwindcss', 'shadcn-nuxt'],
modules: ['shadcn-nuxt'],
shadcn: {
prefix: 'Ui',
},
devtools: { enabled: true },
compatibilityDate: '2024-11-04',
})

View File

@ -8,13 +8,17 @@
"generate": "nuxi generate"
},
"dependencies": {
"@nuxtjs/tailwindcss": "^6.10.1",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"embla-carousel-vue": "8.0.0-rc19",
"lucide-vue-next": "^0.276.0"
"lucide-vue-next": "^0.276.0",
"radix-vue": "^1.9.8",
"shadcn-nuxt": "^0.10.4",
"tailwind-merge": "^2.5.2",
"tailwindcss-animate": "^1.0.7"
},
"devDependencies": {
"@nuxtjs/tailwindcss": "^6.12.0",
"nuxt": "latest",
"shadcn-nuxt": "file:.."
"@nuxtjs/tailwindcss": "^6.12.2",
"nuxt": "latest"
}
}

View File

@ -59,13 +59,11 @@ export default defineNuxtModule<ModuleOptions>({
})
})
// Installs the `@nuxtjs/color-mode` module.
// Install the `@nuxtjs/tailwindcss` module.
await installModule('@nuxtjs/tailwindcss')
await installModule('@nuxtjs/color-mode', {
colorMode: {
classSuffix: '',
},
})
// Installs the `@nuxtjs/color-mode` module.
await installModule('@nuxtjs/color-mode')
// Manually scan `componentsDir` for components and register them for auto imports
try {
@ -90,6 +88,7 @@ export default defineNuxtModule<ModuleOptions>({
name: `${prefix}${key}`, // name of the component to be used in vue templates
export: key, // (optional) if the component is a named (rather than default) export
filePath: resolve(filePath),
priority: 1,
})
})
}

File diff suppressed because it is too large Load Diff