@afurgeri/crud-vue 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +46 -0
- package/src/__test__/CrudCards.test.ts +118 -0
- package/src/__test__/CrudEmptyState.test.ts +82 -0
- package/src/__test__/CrudForm.test.ts +101 -0
- package/src/__test__/CrudShow.test.ts +135 -0
- package/src/__test__/CrudTable.test.ts +111 -0
- package/src/__test__/CrudToolbar.test.ts +102 -0
- package/src/__test__/setup.ts +43 -0
- package/src/__test__/useCrud.test.ts +349 -0
- package/src/components/CrudCards.vue +105 -0
- package/src/components/CrudDeleteDialog.vue +80 -0
- package/src/components/CrudEmptyState.vue +58 -0
- package/src/components/CrudFilters.vue +194 -0
- package/src/components/CrudForm.vue +232 -0
- package/src/components/CrudPage.vue +206 -0
- package/src/components/CrudPagination.vue +130 -0
- package/src/components/CrudSearch.vue +42 -0
- package/src/components/CrudShow.vue +216 -0
- package/src/components/CrudTable.vue +146 -0
- package/src/components/CrudToolbar.vue +86 -0
- package/src/components/InputError.vue +13 -0
- package/src/components/ui/button/Button.vue +27 -0
- package/src/components/ui/button/index.ts +36 -0
- package/src/components/ui/card/Card.vue +22 -0
- package/src/components/ui/card/CardAction.vue +17 -0
- package/src/components/ui/card/CardContent.vue +17 -0
- package/src/components/ui/card/CardDescription.vue +17 -0
- package/src/components/ui/card/CardFooter.vue +17 -0
- package/src/components/ui/card/CardHeader.vue +17 -0
- package/src/components/ui/card/CardTitle.vue +17 -0
- package/src/components/ui/card/index.ts +7 -0
- package/src/components/ui/checkbox/Checkbox.vue +37 -0
- package/src/components/ui/checkbox/index.ts +1 -0
- package/src/components/ui/combobox/ComboboxInput.vue +83 -0
- package/src/components/ui/combobox/index.ts +1 -0
- package/src/components/ui/dialog/Dialog.vue +17 -0
- package/src/components/ui/dialog/DialogClose.vue +14 -0
- package/src/components/ui/dialog/DialogContent.vue +49 -0
- package/src/components/ui/dialog/DialogDescription.vue +25 -0
- package/src/components/ui/dialog/DialogFooter.vue +15 -0
- package/src/components/ui/dialog/DialogHeader.vue +17 -0
- package/src/components/ui/dialog/DialogOverlay.vue +23 -0
- package/src/components/ui/dialog/DialogScrollContent.vue +59 -0
- package/src/components/ui/dialog/DialogTitle.vue +25 -0
- package/src/components/ui/dialog/DialogTrigger.vue +14 -0
- package/src/components/ui/dialog/index.ts +10 -0
- package/src/components/ui/dropdown-menu/DropdownMenu.vue +17 -0
- package/src/components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue +41 -0
- package/src/components/ui/dropdown-menu/DropdownMenuContent.vue +39 -0
- package/src/components/ui/dropdown-menu/DropdownMenuGroup.vue +14 -0
- package/src/components/ui/dropdown-menu/DropdownMenuItem.vue +30 -0
- package/src/components/ui/dropdown-menu/DropdownMenuLabel.vue +22 -0
- package/src/components/ui/dropdown-menu/DropdownMenuRadioGroup.vue +22 -0
- package/src/components/ui/dropdown-menu/DropdownMenuRadioItem.vue +42 -0
- package/src/components/ui/dropdown-menu/DropdownMenuSeparator.vue +26 -0
- package/src/components/ui/dropdown-menu/DropdownMenuShortcut.vue +17 -0
- package/src/components/ui/dropdown-menu/DropdownMenuSub.vue +19 -0
- package/src/components/ui/dropdown-menu/DropdownMenuSubContent.vue +31 -0
- package/src/components/ui/dropdown-menu/DropdownMenuSubTrigger.vue +30 -0
- package/src/components/ui/dropdown-menu/DropdownMenuTrigger.vue +16 -0
- package/src/components/ui/dropdown-menu/index.ts +16 -0
- package/src/components/ui/input/Input.vue +33 -0
- package/src/components/ui/input/index.ts +1 -0
- package/src/components/ui/label/Label.vue +28 -0
- package/src/components/ui/label/index.ts +1 -0
- package/src/components/ui/select/Select.vue +15 -0
- package/src/components/ui/select/SelectContent.vue +49 -0
- package/src/components/ui/select/SelectGroup.vue +17 -0
- package/src/components/ui/select/SelectItem.vue +41 -0
- package/src/components/ui/select/SelectItemText.vue +12 -0
- package/src/components/ui/select/SelectLabel.vue +14 -0
- package/src/components/ui/select/SelectScrollDownButton.vue +22 -0
- package/src/components/ui/select/SelectScrollUpButton.vue +22 -0
- package/src/components/ui/select/SelectSeparator.vue +15 -0
- package/src/components/ui/select/SelectTrigger.vue +29 -0
- package/src/components/ui/select/SelectValue.vue +12 -0
- package/src/components/ui/select/index.ts +11 -0
- package/src/components/ui/separator/Separator.vue +28 -0
- package/src/components/ui/separator/index.ts +1 -0
- package/src/components/ui/spinner/Spinner.vue +17 -0
- package/src/components/ui/spinner/index.ts +1 -0
- package/src/components/ui/table/Table.vue +16 -0
- package/src/components/ui/table/TableBody.vue +14 -0
- package/src/components/ui/table/TableCaption.vue +14 -0
- package/src/components/ui/table/TableCell.vue +21 -0
- package/src/components/ui/table/TableEmpty.vue +34 -0
- package/src/components/ui/table/TableFooter.vue +14 -0
- package/src/components/ui/table/TableHead.vue +14 -0
- package/src/components/ui/table/TableHeader.vue +14 -0
- package/src/components/ui/table/TableRow.vue +14 -0
- package/src/components/ui/table/index.ts +9 -0
- package/src/composables/useCrud.ts +328 -0
- package/src/index.ts +33 -0
- package/src/lib/utils.ts +18 -0
- package/src/types/crud.ts +133 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { cn } from '../../../lib/utils'
|
|
3
|
+
import { DialogDescription, type DialogDescriptionProps, useForwardProps } from 'reka-ui'
|
|
4
|
+
import { computed, type HTMLAttributes } from 'vue'
|
|
5
|
+
|
|
6
|
+
const props = defineProps<DialogDescriptionProps & { class?: HTMLAttributes['class'] }>()
|
|
7
|
+
|
|
8
|
+
const delegatedProps = computed(() => {
|
|
9
|
+
const { class: _, ...delegated } = props
|
|
10
|
+
|
|
11
|
+
return delegated
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
const forwardedProps = useForwardProps(delegatedProps)
|
|
15
|
+
</script>
|
|
16
|
+
|
|
17
|
+
<template>
|
|
18
|
+
<DialogDescription
|
|
19
|
+
data-slot="dialog-description"
|
|
20
|
+
v-bind="forwardedProps"
|
|
21
|
+
:class="cn('text-muted-foreground text-sm', props.class)"
|
|
22
|
+
>
|
|
23
|
+
<slot />
|
|
24
|
+
</DialogDescription>
|
|
25
|
+
</template>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { HTMLAttributes } from 'vue'
|
|
3
|
+
import { cn } from '../../../lib/utils'
|
|
4
|
+
|
|
5
|
+
const props = defineProps<{ class?: HTMLAttributes['class'] }>()
|
|
6
|
+
</script>
|
|
7
|
+
|
|
8
|
+
<template>
|
|
9
|
+
<div
|
|
10
|
+
data-slot="dialog-footer"
|
|
11
|
+
:class="cn('flex flex-col-reverse gap-2 sm:flex-row sm:justify-end', props.class)"
|
|
12
|
+
>
|
|
13
|
+
<slot />
|
|
14
|
+
</div>
|
|
15
|
+
</template>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { HTMLAttributes } from 'vue'
|
|
3
|
+
import { cn } from '../../../lib/utils'
|
|
4
|
+
|
|
5
|
+
const props = defineProps<{
|
|
6
|
+
class?: HTMLAttributes['class']
|
|
7
|
+
}>()
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<template>
|
|
11
|
+
<div
|
|
12
|
+
data-slot="dialog-header"
|
|
13
|
+
:class="cn('flex flex-col gap-2 text-center sm:text-left', props.class)"
|
|
14
|
+
>
|
|
15
|
+
<slot />
|
|
16
|
+
</div>
|
|
17
|
+
</template>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { cn } from '../../../lib/utils'
|
|
3
|
+
import { DialogOverlay, type DialogOverlayProps } from 'reka-ui'
|
|
4
|
+
import { computed, type HTMLAttributes } from 'vue'
|
|
5
|
+
|
|
6
|
+
const props = defineProps<DialogOverlayProps & { class?: HTMLAttributes['class'] }>()
|
|
7
|
+
|
|
8
|
+
const delegatedProps = computed(() => {
|
|
9
|
+
const { class: _, ...delegated } = props
|
|
10
|
+
|
|
11
|
+
return delegated
|
|
12
|
+
})
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<template>
|
|
16
|
+
<DialogOverlay
|
|
17
|
+
data-slot="dialog-overlay"
|
|
18
|
+
v-bind="delegatedProps"
|
|
19
|
+
:class="cn('data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/80', props.class)"
|
|
20
|
+
>
|
|
21
|
+
<slot />
|
|
22
|
+
</DialogOverlay>
|
|
23
|
+
</template>
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { cn } from '../../../lib/utils'
|
|
3
|
+
import { X } from 'lucide-vue-next'
|
|
4
|
+
import {
|
|
5
|
+
DialogClose,
|
|
6
|
+
DialogContent,
|
|
7
|
+
type DialogContentEmits,
|
|
8
|
+
type DialogContentProps,
|
|
9
|
+
DialogOverlay,
|
|
10
|
+
DialogPortal,
|
|
11
|
+
useForwardPropsEmits,
|
|
12
|
+
} from 'reka-ui'
|
|
13
|
+
import { computed, type HTMLAttributes } from 'vue'
|
|
14
|
+
|
|
15
|
+
const props = defineProps<DialogContentProps & { class?: HTMLAttributes['class'] }>()
|
|
16
|
+
const emits = defineEmits<DialogContentEmits>()
|
|
17
|
+
|
|
18
|
+
const delegatedProps = computed(() => {
|
|
19
|
+
const { class: _, ...delegated } = props
|
|
20
|
+
|
|
21
|
+
return delegated
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
const forwarded = useForwardPropsEmits(delegatedProps, emits)
|
|
25
|
+
</script>
|
|
26
|
+
|
|
27
|
+
<template>
|
|
28
|
+
<DialogPortal>
|
|
29
|
+
<DialogOverlay
|
|
30
|
+
class="fixed inset-0 z-50 grid place-items-center overflow-y-auto bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0"
|
|
31
|
+
>
|
|
32
|
+
<DialogContent
|
|
33
|
+
:class="
|
|
34
|
+
cn(
|
|
35
|
+
'relative z-50 grid w-full max-w-lg my-8 gap-4 border border-border bg-background p-6 shadow-lg duration-200 sm:rounded-lg md:w-full',
|
|
36
|
+
props.class,
|
|
37
|
+
)
|
|
38
|
+
"
|
|
39
|
+
v-bind="forwarded"
|
|
40
|
+
@pointer-down-outside="(event) => {
|
|
41
|
+
const originalEvent = event.detail.originalEvent;
|
|
42
|
+
const target = originalEvent.target as HTMLElement;
|
|
43
|
+
if (originalEvent.offsetX > target.clientWidth || originalEvent.offsetY > target.clientHeight) {
|
|
44
|
+
event.preventDefault();
|
|
45
|
+
}
|
|
46
|
+
}"
|
|
47
|
+
>
|
|
48
|
+
<slot />
|
|
49
|
+
|
|
50
|
+
<DialogClose
|
|
51
|
+
class="absolute top-4 right-4 p-0.5 transition-colors rounded-md hover:bg-secondary"
|
|
52
|
+
>
|
|
53
|
+
<X class="w-4 h-4" />
|
|
54
|
+
<span class="sr-only">Close</span>
|
|
55
|
+
</DialogClose>
|
|
56
|
+
</DialogContent>
|
|
57
|
+
</DialogOverlay>
|
|
58
|
+
</DialogPortal>
|
|
59
|
+
</template>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { cn } from '../../../lib/utils'
|
|
3
|
+
import { DialogTitle, type DialogTitleProps, useForwardProps } from 'reka-ui'
|
|
4
|
+
import { computed, type HTMLAttributes } from 'vue'
|
|
5
|
+
|
|
6
|
+
const props = defineProps<DialogTitleProps & { class?: HTMLAttributes['class'] }>()
|
|
7
|
+
|
|
8
|
+
const delegatedProps = computed(() => {
|
|
9
|
+
const { class: _, ...delegated } = props
|
|
10
|
+
|
|
11
|
+
return delegated
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
const forwardedProps = useForwardProps(delegatedProps)
|
|
15
|
+
</script>
|
|
16
|
+
|
|
17
|
+
<template>
|
|
18
|
+
<DialogTitle
|
|
19
|
+
data-slot="dialog-title"
|
|
20
|
+
v-bind="forwardedProps"
|
|
21
|
+
:class="cn('text-lg leading-none font-semibold', props.class)"
|
|
22
|
+
>
|
|
23
|
+
<slot />
|
|
24
|
+
</DialogTitle>
|
|
25
|
+
</template>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { DialogTrigger, type DialogTriggerProps } from 'reka-ui'
|
|
3
|
+
|
|
4
|
+
const props = defineProps<DialogTriggerProps>()
|
|
5
|
+
</script>
|
|
6
|
+
|
|
7
|
+
<template>
|
|
8
|
+
<DialogTrigger
|
|
9
|
+
data-slot="dialog-trigger"
|
|
10
|
+
v-bind="props"
|
|
11
|
+
>
|
|
12
|
+
<slot />
|
|
13
|
+
</DialogTrigger>
|
|
14
|
+
</template>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { default as Dialog } from './Dialog.vue'
|
|
2
|
+
export { default as DialogClose } from './DialogClose.vue'
|
|
3
|
+
export { default as DialogContent } from './DialogContent.vue'
|
|
4
|
+
export { default as DialogDescription } from './DialogDescription.vue'
|
|
5
|
+
export { default as DialogFooter } from './DialogFooter.vue'
|
|
6
|
+
export { default as DialogHeader } from './DialogHeader.vue'
|
|
7
|
+
export { default as DialogOverlay } from './DialogOverlay.vue'
|
|
8
|
+
export { default as DialogScrollContent } from './DialogScrollContent.vue'
|
|
9
|
+
export { default as DialogTitle } from './DialogTitle.vue'
|
|
10
|
+
export { default as DialogTrigger } from './DialogTrigger.vue'
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { DropdownMenuRoot, type DropdownMenuRootEmits, type DropdownMenuRootProps, useForwardPropsEmits } from 'reka-ui'
|
|
3
|
+
|
|
4
|
+
const props = defineProps<DropdownMenuRootProps>()
|
|
5
|
+
const emits = defineEmits<DropdownMenuRootEmits>()
|
|
6
|
+
|
|
7
|
+
const forwarded = useForwardPropsEmits(props, emits)
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<template>
|
|
11
|
+
<DropdownMenuRoot
|
|
12
|
+
data-slot="dropdown-menu"
|
|
13
|
+
v-bind="forwarded"
|
|
14
|
+
>
|
|
15
|
+
<slot />
|
|
16
|
+
</DropdownMenuRoot>
|
|
17
|
+
</template>
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { cn } from '../../../lib/utils'
|
|
3
|
+
import { Check } from 'lucide-vue-next'
|
|
4
|
+
import {
|
|
5
|
+
DropdownMenuCheckboxItem,
|
|
6
|
+
type DropdownMenuCheckboxItemEmits,
|
|
7
|
+
type DropdownMenuCheckboxItemProps,
|
|
8
|
+
DropdownMenuItemIndicator,
|
|
9
|
+
useForwardPropsEmits,
|
|
10
|
+
} from 'reka-ui'
|
|
11
|
+
import { computed, type HTMLAttributes } from 'vue'
|
|
12
|
+
|
|
13
|
+
const props = defineProps<DropdownMenuCheckboxItemProps & { class?: HTMLAttributes['class'] }>()
|
|
14
|
+
const emits = defineEmits<DropdownMenuCheckboxItemEmits>()
|
|
15
|
+
|
|
16
|
+
const delegatedProps = computed(() => {
|
|
17
|
+
const { class: _, ...delegated } = props
|
|
18
|
+
|
|
19
|
+
return delegated
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
const forwarded = useForwardPropsEmits(delegatedProps, emits)
|
|
23
|
+
</script>
|
|
24
|
+
|
|
25
|
+
<template>
|
|
26
|
+
<DropdownMenuCheckboxItem
|
|
27
|
+
data-slot="dropdown-menu-checkbox-item"
|
|
28
|
+
v-bind="forwarded"
|
|
29
|
+
:class=" cn(
|
|
30
|
+
`focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4`,
|
|
31
|
+
props.class,
|
|
32
|
+
)"
|
|
33
|
+
>
|
|
34
|
+
<span class="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
|
|
35
|
+
<DropdownMenuItemIndicator>
|
|
36
|
+
<Check class="size-4" />
|
|
37
|
+
</DropdownMenuItemIndicator>
|
|
38
|
+
</span>
|
|
39
|
+
<slot />
|
|
40
|
+
</DropdownMenuCheckboxItem>
|
|
41
|
+
</template>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { cn } from '../../../lib/utils'
|
|
3
|
+
import {
|
|
4
|
+
DropdownMenuContent,
|
|
5
|
+
type DropdownMenuContentEmits,
|
|
6
|
+
type DropdownMenuContentProps,
|
|
7
|
+
DropdownMenuPortal,
|
|
8
|
+
useForwardPropsEmits,
|
|
9
|
+
} from 'reka-ui'
|
|
10
|
+
import { computed, type HTMLAttributes } from 'vue'
|
|
11
|
+
|
|
12
|
+
const props = withDefaults(
|
|
13
|
+
defineProps<DropdownMenuContentProps & { class?: HTMLAttributes['class'] }>(),
|
|
14
|
+
{
|
|
15
|
+
sideOffset: 4,
|
|
16
|
+
},
|
|
17
|
+
)
|
|
18
|
+
const emits = defineEmits<DropdownMenuContentEmits>()
|
|
19
|
+
|
|
20
|
+
const delegatedProps = computed(() => {
|
|
21
|
+
const { class: _, ...delegated } = props
|
|
22
|
+
|
|
23
|
+
return delegated
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
const forwarded = useForwardPropsEmits(delegatedProps, emits)
|
|
27
|
+
</script>
|
|
28
|
+
|
|
29
|
+
<template>
|
|
30
|
+
<DropdownMenuPortal>
|
|
31
|
+
<DropdownMenuContent
|
|
32
|
+
data-slot="dropdown-menu-content"
|
|
33
|
+
v-bind="forwarded"
|
|
34
|
+
:class="cn('bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-h-(--reka-dropdown-menu-content-available-height) min-w-[8rem] origin-(--reka-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md', props.class)"
|
|
35
|
+
>
|
|
36
|
+
<slot />
|
|
37
|
+
</DropdownMenuContent>
|
|
38
|
+
</DropdownMenuPortal>
|
|
39
|
+
</template>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { DropdownMenuGroup, type DropdownMenuGroupProps } from 'reka-ui'
|
|
3
|
+
|
|
4
|
+
const props = defineProps<DropdownMenuGroupProps>()
|
|
5
|
+
</script>
|
|
6
|
+
|
|
7
|
+
<template>
|
|
8
|
+
<DropdownMenuGroup
|
|
9
|
+
data-slot="dropdown-menu-group"
|
|
10
|
+
v-bind="props"
|
|
11
|
+
>
|
|
12
|
+
<slot />
|
|
13
|
+
</DropdownMenuGroup>
|
|
14
|
+
</template>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { HTMLAttributes } from 'vue'
|
|
3
|
+
import { cn } from '../../../lib/utils'
|
|
4
|
+
import { reactiveOmit } from '@vueuse/core'
|
|
5
|
+
import { DropdownMenuItem, type DropdownMenuItemProps, useForwardProps } from 'reka-ui'
|
|
6
|
+
|
|
7
|
+
const props = withDefaults(defineProps<DropdownMenuItemProps & {
|
|
8
|
+
class?: HTMLAttributes['class']
|
|
9
|
+
inset?: boolean
|
|
10
|
+
variant?: 'default' | 'destructive'
|
|
11
|
+
}>(), {
|
|
12
|
+
variant: 'default',
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
const delegatedProps = reactiveOmit(props, 'inset', 'variant')
|
|
16
|
+
|
|
17
|
+
const forwardedProps = useForwardProps(delegatedProps)
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
<template>
|
|
21
|
+
<DropdownMenuItem
|
|
22
|
+
data-slot="dropdown-menu-item"
|
|
23
|
+
:data-inset="inset ? '' : undefined"
|
|
24
|
+
:data-variant="variant"
|
|
25
|
+
v-bind="forwardedProps"
|
|
26
|
+
:class="cn(`focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive-foreground data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/40 data-[variant=destructive]:focus:text-destructive-foreground data-[variant=destructive]:*:[svg]:!text-destructive-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4`, props.class)"
|
|
27
|
+
>
|
|
28
|
+
<slot />
|
|
29
|
+
</DropdownMenuItem>
|
|
30
|
+
</template>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { HTMLAttributes } from 'vue'
|
|
3
|
+
import { cn } from '../../../lib/utils'
|
|
4
|
+
import { reactiveOmit } from '@vueuse/core'
|
|
5
|
+
import { DropdownMenuLabel, type DropdownMenuLabelProps, useForwardProps } from 'reka-ui'
|
|
6
|
+
|
|
7
|
+
const props = defineProps<DropdownMenuLabelProps & { class?: HTMLAttributes['class'], inset?: boolean }>()
|
|
8
|
+
|
|
9
|
+
const delegatedProps = reactiveOmit(props, 'class', 'inset')
|
|
10
|
+
const forwardedProps = useForwardProps(delegatedProps)
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<template>
|
|
14
|
+
<DropdownMenuLabel
|
|
15
|
+
data-slot="dropdown-menu-label"
|
|
16
|
+
:data-inset="inset ? '' : undefined"
|
|
17
|
+
v-bind="forwardedProps"
|
|
18
|
+
:class="cn('px-2 py-1.5 text-sm font-medium data-[inset]:pl-8', props.class)"
|
|
19
|
+
>
|
|
20
|
+
<slot />
|
|
21
|
+
</DropdownMenuLabel>
|
|
22
|
+
</template>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import {
|
|
3
|
+
DropdownMenuRadioGroup,
|
|
4
|
+
type DropdownMenuRadioGroupEmits,
|
|
5
|
+
type DropdownMenuRadioGroupProps,
|
|
6
|
+
useForwardPropsEmits,
|
|
7
|
+
} from 'reka-ui'
|
|
8
|
+
|
|
9
|
+
const props = defineProps<DropdownMenuRadioGroupProps>()
|
|
10
|
+
const emits = defineEmits<DropdownMenuRadioGroupEmits>()
|
|
11
|
+
|
|
12
|
+
const forwarded = useForwardPropsEmits(props, emits)
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<template>
|
|
16
|
+
<DropdownMenuRadioGroup
|
|
17
|
+
data-slot="dropdown-menu-radio-group"
|
|
18
|
+
v-bind="forwarded"
|
|
19
|
+
>
|
|
20
|
+
<slot />
|
|
21
|
+
</DropdownMenuRadioGroup>
|
|
22
|
+
</template>
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { cn } from '../../../lib/utils'
|
|
3
|
+
import { Circle } from 'lucide-vue-next'
|
|
4
|
+
import {
|
|
5
|
+
DropdownMenuItemIndicator,
|
|
6
|
+
DropdownMenuRadioItem,
|
|
7
|
+
type DropdownMenuRadioItemEmits,
|
|
8
|
+
type DropdownMenuRadioItemProps,
|
|
9
|
+
useForwardPropsEmits,
|
|
10
|
+
} from 'reka-ui'
|
|
11
|
+
import { computed, type HTMLAttributes } from 'vue'
|
|
12
|
+
|
|
13
|
+
const props = defineProps<DropdownMenuRadioItemProps & { class?: HTMLAttributes['class'] }>()
|
|
14
|
+
|
|
15
|
+
const emits = defineEmits<DropdownMenuRadioItemEmits>()
|
|
16
|
+
|
|
17
|
+
const delegatedProps = computed(() => {
|
|
18
|
+
const { class: _, ...delegated } = props
|
|
19
|
+
|
|
20
|
+
return delegated
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
const forwarded = useForwardPropsEmits(delegatedProps, emits)
|
|
24
|
+
</script>
|
|
25
|
+
|
|
26
|
+
<template>
|
|
27
|
+
<DropdownMenuRadioItem
|
|
28
|
+
data-slot="dropdown-menu-radio-item"
|
|
29
|
+
v-bind="forwarded"
|
|
30
|
+
:class="cn(
|
|
31
|
+
`focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4`,
|
|
32
|
+
props.class,
|
|
33
|
+
)"
|
|
34
|
+
>
|
|
35
|
+
<span class="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
|
|
36
|
+
<DropdownMenuItemIndicator>
|
|
37
|
+
<Circle class="size-2 fill-current" />
|
|
38
|
+
</DropdownMenuItemIndicator>
|
|
39
|
+
</span>
|
|
40
|
+
<slot />
|
|
41
|
+
</DropdownMenuRadioItem>
|
|
42
|
+
</template>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { cn } from '../../../lib/utils'
|
|
3
|
+
import {
|
|
4
|
+
DropdownMenuSeparator,
|
|
5
|
+
type DropdownMenuSeparatorProps,
|
|
6
|
+
} from 'reka-ui'
|
|
7
|
+
import { computed, type HTMLAttributes } from 'vue'
|
|
8
|
+
|
|
9
|
+
const props = defineProps<DropdownMenuSeparatorProps & {
|
|
10
|
+
class?: HTMLAttributes['class']
|
|
11
|
+
}>()
|
|
12
|
+
|
|
13
|
+
const delegatedProps = computed(() => {
|
|
14
|
+
const { class: _, ...delegated } = props
|
|
15
|
+
|
|
16
|
+
return delegated
|
|
17
|
+
})
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
<template>
|
|
21
|
+
<DropdownMenuSeparator
|
|
22
|
+
data-slot="dropdown-menu-separator"
|
|
23
|
+
v-bind="delegatedProps"
|
|
24
|
+
:class="cn('bg-border -mx-1 my-1 h-px', props.class)"
|
|
25
|
+
/>
|
|
26
|
+
</template>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { HTMLAttributes } from 'vue'
|
|
3
|
+
import { cn } from '../../../lib/utils'
|
|
4
|
+
|
|
5
|
+
const props = defineProps<{
|
|
6
|
+
class?: HTMLAttributes['class']
|
|
7
|
+
}>()
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<template>
|
|
11
|
+
<span
|
|
12
|
+
data-slot="dropdown-menu-shortcut"
|
|
13
|
+
:class="cn('text-muted-foreground ml-auto text-xs tracking-widest', props.class)"
|
|
14
|
+
>
|
|
15
|
+
<slot />
|
|
16
|
+
</span>
|
|
17
|
+
</template>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import {
|
|
3
|
+
DropdownMenuSub,
|
|
4
|
+
type DropdownMenuSubEmits,
|
|
5
|
+
type DropdownMenuSubProps,
|
|
6
|
+
useForwardPropsEmits,
|
|
7
|
+
} from 'reka-ui'
|
|
8
|
+
|
|
9
|
+
const props = defineProps<DropdownMenuSubProps>()
|
|
10
|
+
const emits = defineEmits<DropdownMenuSubEmits>()
|
|
11
|
+
|
|
12
|
+
const forwarded = useForwardPropsEmits(props, emits)
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<template>
|
|
16
|
+
<DropdownMenuSub data-slot="dropdown-menu-sub" v-bind="forwarded">
|
|
17
|
+
<slot />
|
|
18
|
+
</DropdownMenuSub>
|
|
19
|
+
</template>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { cn } from '../../../lib/utils'
|
|
3
|
+
import {
|
|
4
|
+
DropdownMenuSubContent,
|
|
5
|
+
type DropdownMenuSubContentEmits,
|
|
6
|
+
type DropdownMenuSubContentProps,
|
|
7
|
+
useForwardPropsEmits,
|
|
8
|
+
} from 'reka-ui'
|
|
9
|
+
import { computed, type HTMLAttributes } from 'vue'
|
|
10
|
+
|
|
11
|
+
const props = defineProps<DropdownMenuSubContentProps & { class?: HTMLAttributes['class'] }>()
|
|
12
|
+
const emits = defineEmits<DropdownMenuSubContentEmits>()
|
|
13
|
+
|
|
14
|
+
const delegatedProps = computed(() => {
|
|
15
|
+
const { class: _, ...delegated } = props
|
|
16
|
+
|
|
17
|
+
return delegated
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
const forwarded = useForwardPropsEmits(delegatedProps, emits)
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
<template>
|
|
24
|
+
<DropdownMenuSubContent
|
|
25
|
+
data-slot="dropdown-menu-sub-content"
|
|
26
|
+
v-bind="forwarded"
|
|
27
|
+
:class="cn('bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] origin-(--reka-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg', props.class)"
|
|
28
|
+
>
|
|
29
|
+
<slot />
|
|
30
|
+
</DropdownMenuSubContent>
|
|
31
|
+
</template>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { HTMLAttributes } from 'vue'
|
|
3
|
+
import { cn } from '../../../lib/utils'
|
|
4
|
+
import { reactiveOmit } from '@vueuse/core'
|
|
5
|
+
import { ChevronRight } from 'lucide-vue-next'
|
|
6
|
+
import {
|
|
7
|
+
DropdownMenuSubTrigger,
|
|
8
|
+
type DropdownMenuSubTriggerProps,
|
|
9
|
+
useForwardProps,
|
|
10
|
+
} from 'reka-ui'
|
|
11
|
+
|
|
12
|
+
const props = defineProps<DropdownMenuSubTriggerProps & { class?: HTMLAttributes['class'], inset?: boolean }>()
|
|
13
|
+
|
|
14
|
+
const delegatedProps = reactiveOmit(props, 'class', 'inset')
|
|
15
|
+
const forwardedProps = useForwardProps(delegatedProps)
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<template>
|
|
19
|
+
<DropdownMenuSubTrigger
|
|
20
|
+
data-slot="dropdown-menu-sub-trigger"
|
|
21
|
+
v-bind="forwardedProps"
|
|
22
|
+
:class="cn(
|
|
23
|
+
'focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[inset]:pl-8',
|
|
24
|
+
props.class,
|
|
25
|
+
)"
|
|
26
|
+
>
|
|
27
|
+
<slot />
|
|
28
|
+
<ChevronRight class="ml-auto size-4" />
|
|
29
|
+
</DropdownMenuSubTrigger>
|
|
30
|
+
</template>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { DropdownMenuTrigger, type DropdownMenuTriggerProps, useForwardProps } from 'reka-ui'
|
|
3
|
+
|
|
4
|
+
const props = defineProps<DropdownMenuTriggerProps>()
|
|
5
|
+
|
|
6
|
+
const forwardedProps = useForwardProps(props)
|
|
7
|
+
</script>
|
|
8
|
+
|
|
9
|
+
<template>
|
|
10
|
+
<DropdownMenuTrigger
|
|
11
|
+
data-slot="dropdown-menu-trigger"
|
|
12
|
+
v-bind="forwardedProps"
|
|
13
|
+
>
|
|
14
|
+
<slot />
|
|
15
|
+
</DropdownMenuTrigger>
|
|
16
|
+
</template>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export { default as DropdownMenu } from './DropdownMenu.vue'
|
|
2
|
+
|
|
3
|
+
export { default as DropdownMenuCheckboxItem } from './DropdownMenuCheckboxItem.vue'
|
|
4
|
+
export { default as DropdownMenuContent } from './DropdownMenuContent.vue'
|
|
5
|
+
export { default as DropdownMenuGroup } from './DropdownMenuGroup.vue'
|
|
6
|
+
export { default as DropdownMenuItem } from './DropdownMenuItem.vue'
|
|
7
|
+
export { default as DropdownMenuLabel } from './DropdownMenuLabel.vue'
|
|
8
|
+
export { default as DropdownMenuRadioGroup } from './DropdownMenuRadioGroup.vue'
|
|
9
|
+
export { default as DropdownMenuRadioItem } from './DropdownMenuRadioItem.vue'
|
|
10
|
+
export { default as DropdownMenuSeparator } from './DropdownMenuSeparator.vue'
|
|
11
|
+
export { default as DropdownMenuShortcut } from './DropdownMenuShortcut.vue'
|
|
12
|
+
export { default as DropdownMenuSub } from './DropdownMenuSub.vue'
|
|
13
|
+
export { default as DropdownMenuSubContent } from './DropdownMenuSubContent.vue'
|
|
14
|
+
export { default as DropdownMenuSubTrigger } from './DropdownMenuSubTrigger.vue'
|
|
15
|
+
export { default as DropdownMenuTrigger } from './DropdownMenuTrigger.vue'
|
|
16
|
+
export { DropdownMenuPortal } from 'reka-ui'
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { HTMLAttributes } from 'vue'
|
|
3
|
+
import { cn } from '../../../lib/utils'
|
|
4
|
+
import { useVModel } from '@vueuse/core'
|
|
5
|
+
|
|
6
|
+
const props = defineProps<{
|
|
7
|
+
defaultValue?: string | number
|
|
8
|
+
modelValue?: string | number
|
|
9
|
+
class?: HTMLAttributes['class']
|
|
10
|
+
}>()
|
|
11
|
+
|
|
12
|
+
const emits = defineEmits<{
|
|
13
|
+
(e: 'update:modelValue', payload: string | number): void
|
|
14
|
+
}>()
|
|
15
|
+
|
|
16
|
+
const modelValue = useVModel(props, 'modelValue', emits, {
|
|
17
|
+
passive: true,
|
|
18
|
+
defaultValue: props.defaultValue,
|
|
19
|
+
})
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<template>
|
|
23
|
+
<input
|
|
24
|
+
v-model="modelValue"
|
|
25
|
+
data-slot="input"
|
|
26
|
+
:class="cn(
|
|
27
|
+
'file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
|
|
28
|
+
'focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]',
|
|
29
|
+
'aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive',
|
|
30
|
+
props.class,
|
|
31
|
+
)"
|
|
32
|
+
>
|
|
33
|
+
</template>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as Input } from './Input.vue'
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { cn } from '../../../lib/utils'
|
|
3
|
+
import { Label, type LabelProps } from 'reka-ui'
|
|
4
|
+
import { computed, type HTMLAttributes } from 'vue'
|
|
5
|
+
|
|
6
|
+
const props = defineProps<LabelProps & { class?: HTMLAttributes['class'] }>()
|
|
7
|
+
|
|
8
|
+
const delegatedProps = computed(() => {
|
|
9
|
+
const { class: _, ...delegated } = props
|
|
10
|
+
|
|
11
|
+
return delegated
|
|
12
|
+
})
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<template>
|
|
16
|
+
<Label
|
|
17
|
+
data-slot="label"
|
|
18
|
+
v-bind="delegatedProps"
|
|
19
|
+
:class="
|
|
20
|
+
cn(
|
|
21
|
+
'flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50',
|
|
22
|
+
props.class,
|
|
23
|
+
)
|
|
24
|
+
"
|
|
25
|
+
>
|
|
26
|
+
<slot />
|
|
27
|
+
</Label>
|
|
28
|
+
</template>
|