mirror of
https://github.com/LukeHagar/better-auth.git
synced 2025-12-09 12:27:43 +00:00
chore: ad release label
This commit is contained in:
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@@ -11,7 +11,7 @@
|
|||||||
"editor.defaultFormatter": "biomejs.biome"
|
"editor.defaultFormatter": "biomejs.biome"
|
||||||
},
|
},
|
||||||
"[vue]": {
|
"[vue]": {
|
||||||
"editor.defaultFormatter": "Vue.volar"
|
"editor.defaultFormatter": "biomejs.biome"
|
||||||
},
|
},
|
||||||
"[json]": {
|
"[json]": {
|
||||||
"editor.defaultFormatter": "biomejs.biome"
|
"editor.defaultFormatter": "biomejs.biome"
|
||||||
|
|||||||
11
README.md
11
README.md
@@ -20,10 +20,12 @@
|
|||||||
·
|
·
|
||||||
<a href="https://github.com/better-auth/better-auth/issues">Issues</a>
|
<a href="https://github.com/better-auth/better-auth/issues">Issues</a>
|
||||||
</p>
|
</p>
|
||||||
</p>
|
|
||||||
|
|
||||||
[](https://www.npmjs.com/package/better-auth)
|
[](https://www.npmjs.com/package/better-auth)
|
||||||
|
[](https://www.npmjs.com/package/better-auth)
|
||||||
[](https://github.com/better-auth/better-auth/stargazers)
|
[](https://github.com/better-auth/better-auth/stargazers)
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
> [!IMPORTANT]
|
> [!IMPORTANT]
|
||||||
> **Note:** 🚧 This project is currently in beta. Features and APIs may change.
|
> **Note:** 🚧 This project is currently in beta. Features and APIs may change.
|
||||||
@@ -52,10 +54,7 @@ Better Auth was built to tackle these frustrations. It offers a robust core auth
|
|||||||
- **JWT-Based Authentication**: We won’t support JWT-based auth unless provided by a third-party plugin.
|
- **JWT-Based Authentication**: We won’t support JWT-based auth unless provided by a third-party plugin.
|
||||||
- **Support for Non-Relational Databases**: No plans to support MongoDB or other non-relational databases.
|
- **Support for Non-Relational Databases**: No plans to support MongoDB or other non-relational databases.
|
||||||
- **Deep Customization**: Our focus is on delivering opinionated, best-practice defaults, rather than enabling deep customization.
|
- **Deep Customization**: Our focus is on delivering opinionated, best-practice defaults, rather than enabling deep customization.
|
||||||
- **Frontend UI Components**: We don’t provide frontend UI components. However, feel free to use our examples for quick UI integration.
|
|
||||||
|
|
||||||
> Some of these non-goals might change after we hit v1
|
|
||||||
|
|
||||||
## Contribution
|
## Contribution
|
||||||
|
|
||||||
Better Auth is free and open source project licensed under the [MIT License](./LICENSE.md). You are free to do whatever you want with it.
|
Better Auth is free and open source project licensed under the [MIT License](./LICENSE.md). You are free to do whatever you want with it.
|
||||||
@@ -66,6 +65,6 @@ You could help continuing its development by:
|
|||||||
- [Suggest new features and report issues](https://github.com/better-auth/better-auth/issues)
|
- [Suggest new features and report issues](https://github.com/better-auth/better-auth/issues)
|
||||||
|
|
||||||
## Security
|
## Security
|
||||||
If you discover a security vulnerability within Better AUth, please send an e-mail to support at better-auth.com.
|
If you discover a security vulnerability within Better Auth, please send an e-mail to security@better-auth.com.
|
||||||
|
|
||||||
All reports will be promptly addressed, and you'll be credited accordingly.
|
All reports will be promptly addressed, and you'll be credited accordingly.
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const router = useRouter()
|
const router = useRouter();
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {
|
import {
|
||||||
AccordionRoot,
|
AccordionRoot,
|
||||||
type AccordionRootEmits,
|
type AccordionRootEmits,
|
||||||
type AccordionRootProps,
|
type AccordionRootProps,
|
||||||
useForwardPropsEmits,
|
useForwardPropsEmits,
|
||||||
} from 'radix-vue'
|
} from "radix-vue";
|
||||||
|
|
||||||
const props = defineProps<AccordionRootProps>()
|
const props = defineProps<AccordionRootProps>();
|
||||||
const emits = defineEmits<AccordionRootEmits>()
|
const emits = defineEmits<AccordionRootEmits>();
|
||||||
|
|
||||||
const forwarded = useForwardPropsEmits(props, emits)
|
const forwarded = useForwardPropsEmits(props, emits);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { type HTMLAttributes, computed } from 'vue'
|
import { type HTMLAttributes, computed } from "vue";
|
||||||
import { AccordionContent, type AccordionContentProps } from 'radix-vue'
|
import { AccordionContent, type AccordionContentProps } from "radix-vue";
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const props = defineProps<AccordionContentProps & { class?: HTMLAttributes['class'] }>()
|
const props = defineProps<
|
||||||
|
AccordionContentProps & { class?: HTMLAttributes["class"] }
|
||||||
|
>();
|
||||||
|
|
||||||
const delegatedProps = computed(() => {
|
const delegatedProps = computed(() => {
|
||||||
const { class: _, ...delegated } = props
|
const { class: _, ...delegated } = props;
|
||||||
|
|
||||||
return delegated
|
return delegated;
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,17 +1,23 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { type HTMLAttributes, computed } from 'vue'
|
import { type HTMLAttributes, computed } from "vue";
|
||||||
import { AccordionItem, type AccordionItemProps, useForwardProps } from 'radix-vue'
|
import {
|
||||||
import { cn } from '@/lib/utils'
|
AccordionItem,
|
||||||
|
type AccordionItemProps,
|
||||||
|
useForwardProps,
|
||||||
|
} from "radix-vue";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const props = defineProps<AccordionItemProps & { class?: HTMLAttributes['class'] }>()
|
const props = defineProps<
|
||||||
|
AccordionItemProps & { class?: HTMLAttributes["class"] }
|
||||||
|
>();
|
||||||
|
|
||||||
const delegatedProps = computed(() => {
|
const delegatedProps = computed(() => {
|
||||||
const { class: _, ...delegated } = props
|
const { class: _, ...delegated } = props;
|
||||||
|
|
||||||
return delegated
|
return delegated;
|
||||||
})
|
});
|
||||||
|
|
||||||
const forwardedProps = useForwardProps(delegatedProps)
|
const forwardedProps = useForwardProps(delegatedProps);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,20 +1,22 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { type HTMLAttributes, computed } from 'vue'
|
import { type HTMLAttributes, computed } from "vue";
|
||||||
import {
|
import {
|
||||||
AccordionHeader,
|
AccordionHeader,
|
||||||
AccordionTrigger,
|
AccordionTrigger,
|
||||||
type AccordionTriggerProps,
|
type AccordionTriggerProps,
|
||||||
} from 'radix-vue'
|
} from "radix-vue";
|
||||||
import { ChevronDownIcon } from '@radix-icons/vue'
|
import { ChevronDownIcon } from "@radix-icons/vue";
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const props = defineProps<AccordionTriggerProps & { class?: HTMLAttributes['class'] }>()
|
const props = defineProps<
|
||||||
|
AccordionTriggerProps & { class?: HTMLAttributes["class"] }
|
||||||
|
>();
|
||||||
|
|
||||||
const delegatedProps = computed(() => {
|
const delegatedProps = computed(() => {
|
||||||
const { class: _, ...delegated } = props
|
const { class: _, ...delegated } = props;
|
||||||
|
|
||||||
return delegated
|
return delegated;
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
export { default as Accordion } from './Accordion.vue'
|
export { default as Accordion } from "./Accordion.vue";
|
||||||
export { default as AccordionContent } from './AccordionContent.vue'
|
export { default as AccordionContent } from "./AccordionContent.vue";
|
||||||
export { default as AccordionItem } from './AccordionItem.vue'
|
export { default as AccordionItem } from "./AccordionItem.vue";
|
||||||
export { default as AccordionTrigger } from './AccordionTrigger.vue'
|
export { default as AccordionTrigger } from "./AccordionTrigger.vue";
|
||||||
|
|||||||
@@ -1,10 +1,15 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { type AlertDialogEmits, type AlertDialogProps, AlertDialogRoot, useForwardPropsEmits } from 'radix-vue'
|
import {
|
||||||
|
type AlertDialogEmits,
|
||||||
|
type AlertDialogProps,
|
||||||
|
AlertDialogRoot,
|
||||||
|
useForwardPropsEmits,
|
||||||
|
} from "radix-vue";
|
||||||
|
|
||||||
const props = defineProps<AlertDialogProps>()
|
const props = defineProps<AlertDialogProps>();
|
||||||
const emits = defineEmits<AlertDialogEmits>()
|
const emits = defineEmits<AlertDialogEmits>();
|
||||||
|
|
||||||
const forwarded = useForwardPropsEmits(props, emits)
|
const forwarded = useForwardPropsEmits(props, emits);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,16 +1,18 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { type HTMLAttributes, computed } from 'vue'
|
import { type HTMLAttributes, computed } from "vue";
|
||||||
import { AlertDialogAction, type AlertDialogActionProps } from 'radix-vue'
|
import { AlertDialogAction, type AlertDialogActionProps } from "radix-vue";
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from "@/lib/utils";
|
||||||
import { buttonVariants } from '@/components/ui/button'
|
import { buttonVariants } from "@/components/ui/button";
|
||||||
|
|
||||||
const props = defineProps<AlertDialogActionProps & { class?: HTMLAttributes['class'] }>()
|
const props = defineProps<
|
||||||
|
AlertDialogActionProps & { class?: HTMLAttributes["class"] }
|
||||||
|
>();
|
||||||
|
|
||||||
const delegatedProps = computed(() => {
|
const delegatedProps = computed(() => {
|
||||||
const { class: _, ...delegated } = props
|
const { class: _, ...delegated } = props;
|
||||||
|
|
||||||
return delegated
|
return delegated;
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,16 +1,18 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { type HTMLAttributes, computed } from 'vue'
|
import { type HTMLAttributes, computed } from "vue";
|
||||||
import { AlertDialogCancel, type AlertDialogCancelProps } from 'radix-vue'
|
import { AlertDialogCancel, type AlertDialogCancelProps } from "radix-vue";
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from "@/lib/utils";
|
||||||
import { buttonVariants } from '@/components/ui/button'
|
import { buttonVariants } from "@/components/ui/button";
|
||||||
|
|
||||||
const props = defineProps<AlertDialogCancelProps & { class?: HTMLAttributes['class'] }>()
|
const props = defineProps<
|
||||||
|
AlertDialogCancelProps & { class?: HTMLAttributes["class"] }
|
||||||
|
>();
|
||||||
|
|
||||||
const delegatedProps = computed(() => {
|
const delegatedProps = computed(() => {
|
||||||
const { class: _, ...delegated } = props
|
const { class: _, ...delegated } = props;
|
||||||
|
|
||||||
return delegated
|
return delegated;
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,25 +1,27 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { type HTMLAttributes, computed } from 'vue'
|
import { type HTMLAttributes, computed } from "vue";
|
||||||
import {
|
import {
|
||||||
AlertDialogContent,
|
AlertDialogContent,
|
||||||
type AlertDialogContentEmits,
|
type AlertDialogContentEmits,
|
||||||
type AlertDialogContentProps,
|
type AlertDialogContentProps,
|
||||||
AlertDialogOverlay,
|
AlertDialogOverlay,
|
||||||
AlertDialogPortal,
|
AlertDialogPortal,
|
||||||
useForwardPropsEmits,
|
useForwardPropsEmits,
|
||||||
} from 'radix-vue'
|
} from "radix-vue";
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const props = defineProps<AlertDialogContentProps & { class?: HTMLAttributes['class'] }>()
|
const props = defineProps<
|
||||||
const emits = defineEmits<AlertDialogContentEmits>()
|
AlertDialogContentProps & { class?: HTMLAttributes["class"] }
|
||||||
|
>();
|
||||||
|
const emits = defineEmits<AlertDialogContentEmits>();
|
||||||
|
|
||||||
const delegatedProps = computed(() => {
|
const delegatedProps = computed(() => {
|
||||||
const { class: _, ...delegated } = props
|
const { class: _, ...delegated } = props;
|
||||||
|
|
||||||
return delegated
|
return delegated;
|
||||||
})
|
});
|
||||||
|
|
||||||
const forwarded = useForwardPropsEmits(delegatedProps, emits)
|
const forwarded = useForwardPropsEmits(delegatedProps, emits);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,18 +1,20 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { type HTMLAttributes, computed } from 'vue'
|
import { type HTMLAttributes, computed } from "vue";
|
||||||
import {
|
import {
|
||||||
AlertDialogDescription,
|
AlertDialogDescription,
|
||||||
type AlertDialogDescriptionProps,
|
type AlertDialogDescriptionProps,
|
||||||
} from 'radix-vue'
|
} from "radix-vue";
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const props = defineProps<AlertDialogDescriptionProps & { class?: HTMLAttributes['class'] }>()
|
const props = defineProps<
|
||||||
|
AlertDialogDescriptionProps & { class?: HTMLAttributes["class"] }
|
||||||
|
>();
|
||||||
|
|
||||||
const delegatedProps = computed(() => {
|
const delegatedProps = computed(() => {
|
||||||
const { class: _, ...delegated } = props
|
const { class: _, ...delegated } = props;
|
||||||
|
|
||||||
return delegated
|
return delegated;
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { HTMLAttributes } from 'vue'
|
import type { HTMLAttributes } from "vue";
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
class?: HTMLAttributes['class']
|
class?: HTMLAttributes["class"];
|
||||||
}>()
|
}>();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { HTMLAttributes } from 'vue'
|
import type { HTMLAttributes } from "vue";
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
class?: HTMLAttributes['class']
|
class?: HTMLAttributes["class"];
|
||||||
}>()
|
}>();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { type HTMLAttributes, computed } from 'vue'
|
import { type HTMLAttributes, computed } from "vue";
|
||||||
import { AlertDialogTitle, type AlertDialogTitleProps } from 'radix-vue'
|
import { AlertDialogTitle, type AlertDialogTitleProps } from "radix-vue";
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const props = defineProps<AlertDialogTitleProps & { class?: HTMLAttributes['class'] }>()
|
const props = defineProps<
|
||||||
|
AlertDialogTitleProps & { class?: HTMLAttributes["class"] }
|
||||||
|
>();
|
||||||
|
|
||||||
const delegatedProps = computed(() => {
|
const delegatedProps = computed(() => {
|
||||||
const { class: _, ...delegated } = props
|
const { class: _, ...delegated } = props;
|
||||||
|
|
||||||
return delegated
|
return delegated;
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { AlertDialogTrigger, type AlertDialogTriggerProps } from 'radix-vue'
|
import { AlertDialogTrigger, type AlertDialogTriggerProps } from "radix-vue";
|
||||||
|
|
||||||
const props = defineProps<AlertDialogTriggerProps>()
|
const props = defineProps<AlertDialogTriggerProps>();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
export { default as AlertDialog } from './AlertDialog.vue'
|
export { default as AlertDialog } from "./AlertDialog.vue";
|
||||||
export { default as AlertDialogTrigger } from './AlertDialogTrigger.vue'
|
export { default as AlertDialogTrigger } from "./AlertDialogTrigger.vue";
|
||||||
export { default as AlertDialogContent } from './AlertDialogContent.vue'
|
export { default as AlertDialogContent } from "./AlertDialogContent.vue";
|
||||||
export { default as AlertDialogHeader } from './AlertDialogHeader.vue'
|
export { default as AlertDialogHeader } from "./AlertDialogHeader.vue";
|
||||||
export { default as AlertDialogTitle } from './AlertDialogTitle.vue'
|
export { default as AlertDialogTitle } from "./AlertDialogTitle.vue";
|
||||||
export { default as AlertDialogDescription } from './AlertDialogDescription.vue'
|
export { default as AlertDialogDescription } from "./AlertDialogDescription.vue";
|
||||||
export { default as AlertDialogFooter } from './AlertDialogFooter.vue'
|
export { default as AlertDialogFooter } from "./AlertDialogFooter.vue";
|
||||||
export { default as AlertDialogAction } from './AlertDialogAction.vue'
|
export { default as AlertDialogAction } from "./AlertDialogAction.vue";
|
||||||
export { default as AlertDialogCancel } from './AlertDialogCancel.vue'
|
export { default as AlertDialogCancel } from "./AlertDialogCancel.vue";
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { HTMLAttributes } from 'vue'
|
import type { HTMLAttributes } from "vue";
|
||||||
import { type AlertVariants, alertVariants } from '.'
|
import { type AlertVariants, alertVariants } from ".";
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
class?: HTMLAttributes['class']
|
class?: HTMLAttributes["class"];
|
||||||
variant?: AlertVariants['variant']
|
variant?: AlertVariants["variant"];
|
||||||
}>()
|
}>();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { HTMLAttributes } from 'vue'
|
import type { HTMLAttributes } from "vue";
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
class?: HTMLAttributes['class']
|
class?: HTMLAttributes["class"];
|
||||||
}>()
|
}>();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { HTMLAttributes } from 'vue'
|
import type { HTMLAttributes } from "vue";
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
class?: HTMLAttributes['class']
|
class?: HTMLAttributes["class"];
|
||||||
}>()
|
}>();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,23 +1,23 @@
|
|||||||
import { type VariantProps, cva } from 'class-variance-authority'
|
import { type VariantProps, cva } from "class-variance-authority";
|
||||||
|
|
||||||
export { default as Alert } from './Alert.vue'
|
export { default as Alert } from "./Alert.vue";
|
||||||
export { default as AlertTitle } from './AlertTitle.vue'
|
export { default as AlertTitle } from "./AlertTitle.vue";
|
||||||
export { default as AlertDescription } from './AlertDescription.vue'
|
export { default as AlertDescription } from "./AlertDescription.vue";
|
||||||
|
|
||||||
export const alertVariants = cva(
|
export const alertVariants = cva(
|
||||||
'relative w-full rounded-lg border px-4 py-3 text-sm [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground [&>svg~*]:pl-7',
|
"relative w-full rounded-lg border px-4 py-3 text-sm [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground [&>svg~*]:pl-7",
|
||||||
{
|
{
|
||||||
variants: {
|
variants: {
|
||||||
variant: {
|
variant: {
|
||||||
default: 'bg-background text-foreground',
|
default: "bg-background text-foreground",
|
||||||
destructive:
|
destructive:
|
||||||
'border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive',
|
"border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
defaultVariants: {
|
defaultVariants: {
|
||||||
variant: 'default',
|
variant: "default",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)
|
);
|
||||||
|
|
||||||
export type AlertVariants = VariantProps<typeof alertVariants>
|
export type AlertVariants = VariantProps<typeof alertVariants>;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { AspectRatio, type AspectRatioProps } from 'radix-vue'
|
import { AspectRatio, type AspectRatioProps } from "radix-vue";
|
||||||
|
|
||||||
const props = defineProps<AspectRatioProps>()
|
const props = defineProps<AspectRatioProps>();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
export { default as AspectRatio } from './AspectRatio.vue'
|
export { default as AspectRatio } from "./AspectRatio.vue";
|
||||||
|
|||||||
@@ -1,81 +1,95 @@
|
|||||||
<script setup lang="ts" generic="T extends ZodObjectOrWrapped">
|
<script setup lang="ts" generic="T extends ZodObjectOrWrapped">
|
||||||
import { computed, toRefs } from 'vue'
|
import { computed, toRefs } from "vue";
|
||||||
import type { ZodAny, z } from 'zod'
|
import type { ZodAny, z } from "zod";
|
||||||
import { toTypedSchema } from '@vee-validate/zod'
|
import { toTypedSchema } from "@vee-validate/zod";
|
||||||
import type { FormContext, GenericObject } from 'vee-validate'
|
import type { FormContext, GenericObject } from "vee-validate";
|
||||||
import { type ZodObjectOrWrapped, getBaseSchema, getBaseType, getDefaultValueInZodStack, getObjectFormSchema } from './utils'
|
import {
|
||||||
import type { Config, ConfigItem, Dependency, Shape } from './interface'
|
type ZodObjectOrWrapped,
|
||||||
import AutoFormField from './AutoFormField.vue'
|
getBaseSchema,
|
||||||
import { provideDependencies } from './dependencies'
|
getBaseType,
|
||||||
import { Form } from '@/components/ui/form'
|
getDefaultValueInZodStack,
|
||||||
|
getObjectFormSchema,
|
||||||
|
} from "./utils";
|
||||||
|
import type { Config, ConfigItem, Dependency, Shape } from "./interface";
|
||||||
|
import AutoFormField from "./AutoFormField.vue";
|
||||||
|
import { provideDependencies } from "./dependencies";
|
||||||
|
import { Form } from "@/components/ui/form";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
schema: T
|
schema: T;
|
||||||
form?: FormContext<GenericObject>
|
form?: FormContext<GenericObject>;
|
||||||
fieldConfig?: Config<z.infer<T>>
|
fieldConfig?: Config<z.infer<T>>;
|
||||||
dependencies?: Dependency<z.infer<T>>[]
|
dependencies?: Dependency<z.infer<T>>[];
|
||||||
}>()
|
}>();
|
||||||
|
|
||||||
const emits = defineEmits<{
|
const emits = defineEmits<{
|
||||||
submit: [event: z.infer<T>]
|
submit: [event: z.infer<T>];
|
||||||
}>()
|
}>();
|
||||||
|
|
||||||
const { dependencies } = toRefs(props)
|
const { dependencies } = toRefs(props);
|
||||||
provideDependencies(dependencies)
|
provideDependencies(dependencies);
|
||||||
|
|
||||||
const shapes = computed(() => {
|
const shapes = computed(() => {
|
||||||
// @ts-expect-error ignore {} not assignable to object
|
// @ts-expect-error ignore {} not assignable to object
|
||||||
const val: { [key in keyof T]: Shape } = {}
|
const val: { [key in keyof T]: Shape } = {};
|
||||||
const baseSchema = getObjectFormSchema(props.schema)
|
const baseSchema = getObjectFormSchema(props.schema);
|
||||||
const shape = baseSchema.shape
|
const shape = baseSchema.shape;
|
||||||
Object.keys(shape).forEach((name) => {
|
Object.keys(shape).forEach((name) => {
|
||||||
const item = shape[name] as ZodAny
|
const item = shape[name] as ZodAny;
|
||||||
const baseItem = getBaseSchema(item) as ZodAny
|
const baseItem = getBaseSchema(item) as ZodAny;
|
||||||
let options = (baseItem && 'values' in baseItem._def) ? baseItem._def.values as string[] : undefined
|
let options =
|
||||||
if (!Array.isArray(options) && typeof options === 'object')
|
baseItem && "values" in baseItem._def
|
||||||
options = Object.values(options)
|
? (baseItem._def.values as string[])
|
||||||
|
: undefined;
|
||||||
|
if (!Array.isArray(options) && typeof options === "object")
|
||||||
|
options = Object.values(options);
|
||||||
|
|
||||||
val[name as keyof T] = {
|
val[name as keyof T] = {
|
||||||
type: getBaseType(item),
|
type: getBaseType(item),
|
||||||
default: getDefaultValueInZodStack(item),
|
default: getDefaultValueInZodStack(item),
|
||||||
options,
|
options,
|
||||||
required: !['ZodOptional', 'ZodNullable'].includes(item._def.typeName),
|
required: !["ZodOptional", "ZodNullable"].includes(item._def.typeName),
|
||||||
schema: baseItem,
|
schema: baseItem,
|
||||||
}
|
};
|
||||||
})
|
});
|
||||||
return val
|
return val;
|
||||||
})
|
});
|
||||||
|
|
||||||
const fields = computed(() => {
|
const fields = computed(() => {
|
||||||
// @ts-expect-error ignore {} not assignable to object
|
// @ts-expect-error ignore {} not assignable to object
|
||||||
const val: { [key in keyof z.infer<T>]: { shape: Shape, fieldName: string, config: ConfigItem } } = {}
|
const val: {
|
||||||
for (const key in shapes.value) {
|
[key in keyof z.infer<T>]: {
|
||||||
const shape = shapes.value[key]
|
shape: Shape;
|
||||||
val[key as keyof z.infer<T>] = {
|
fieldName: string;
|
||||||
shape,
|
config: ConfigItem;
|
||||||
config: props.fieldConfig?.[key] as ConfigItem,
|
};
|
||||||
fieldName: key,
|
} = {};
|
||||||
}
|
for (const key in shapes.value) {
|
||||||
}
|
const shape = shapes.value[key];
|
||||||
return val
|
val[key as keyof z.infer<T>] = {
|
||||||
})
|
shape,
|
||||||
|
config: props.fieldConfig?.[key] as ConfigItem,
|
||||||
|
fieldName: key,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
});
|
||||||
|
|
||||||
const formComponent = computed(() => props.form ? 'form' : Form)
|
const formComponent = computed(() => (props.form ? "form" : Form));
|
||||||
const formComponentProps = computed(() => {
|
const formComponentProps = computed(() => {
|
||||||
if (props.form) {
|
if (props.form) {
|
||||||
return {
|
return {
|
||||||
onSubmit: props.form.handleSubmit(val => emits('submit', val)),
|
onSubmit: props.form.handleSubmit((val) => emits("submit", val)),
|
||||||
}
|
};
|
||||||
}
|
} else {
|
||||||
else {
|
const formSchema = toTypedSchema(props.schema);
|
||||||
const formSchema = toTypedSchema(props.schema)
|
return {
|
||||||
return {
|
keepValues: true,
|
||||||
keepValues: true,
|
validationSchema: formSchema,
|
||||||
validationSchema: formSchema,
|
onSubmit: (val: GenericObject) => emits("submit", val),
|
||||||
onSubmit: (val: GenericObject) => emits('submit', val),
|
};
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,27 +1,29 @@
|
|||||||
<script setup lang="ts" generic="U extends ZodAny">
|
<script setup lang="ts" generic="U extends ZodAny">
|
||||||
import type { ZodAny } from 'zod'
|
import type { ZodAny } from "zod";
|
||||||
import { computed } from 'vue'
|
import { computed } from "vue";
|
||||||
import type { Config, ConfigItem, Shape } from './interface'
|
import type { Config, ConfigItem, Shape } from "./interface";
|
||||||
import { DEFAULT_ZOD_HANDLERS, INPUT_COMPONENTS } from './constant'
|
import { DEFAULT_ZOD_HANDLERS, INPUT_COMPONENTS } from "./constant";
|
||||||
import useDependencies from './dependencies'
|
import useDependencies from "./dependencies";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
fieldName: string
|
fieldName: string;
|
||||||
shape: Shape
|
shape: Shape;
|
||||||
config?: ConfigItem | Config<U>
|
config?: ConfigItem | Config<U>;
|
||||||
}>()
|
}>();
|
||||||
|
|
||||||
function isValidConfig(config: any): config is ConfigItem {
|
function isValidConfig(config: any): config is ConfigItem {
|
||||||
return !!config?.component
|
return !!config?.component;
|
||||||
}
|
}
|
||||||
|
|
||||||
const delegatedProps = computed(() => {
|
const delegatedProps = computed(() => {
|
||||||
if (['ZodObject', 'ZodArray'].includes(props.shape?.type))
|
if (["ZodObject", "ZodArray"].includes(props.shape?.type))
|
||||||
return { schema: props.shape?.schema }
|
return { schema: props.shape?.schema };
|
||||||
return undefined
|
return undefined;
|
||||||
})
|
});
|
||||||
|
|
||||||
const { isDisabled, isHidden, isRequired, overrideOptions } = useDependencies(props.fieldName)
|
const { isDisabled, isHidden, isRequired, overrideOptions } = useDependencies(
|
||||||
|
props.fieldName,
|
||||||
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,57 +1,61 @@
|
|||||||
<script setup lang="ts" generic="T extends z.ZodAny">
|
<script setup lang="ts" generic="T extends z.ZodAny">
|
||||||
import * as z from 'zod'
|
import * as z from "zod";
|
||||||
import { computed, provide } from 'vue'
|
import { computed, provide } from "vue";
|
||||||
import { PlusIcon, TrashIcon } from 'lucide-vue-next'
|
import { PlusIcon, TrashIcon } from "lucide-vue-next";
|
||||||
import { FieldArray, FieldContextKey, useField } from 'vee-validate'
|
import { FieldArray, FieldContextKey, useField } from "vee-validate";
|
||||||
import type { Config, ConfigItem } from './interface'
|
import type { Config, ConfigItem } from "./interface";
|
||||||
import { beautifyObjectName, getBaseType } from './utils'
|
import { beautifyObjectName, getBaseType } from "./utils";
|
||||||
import AutoFormField from './AutoFormField.vue'
|
import AutoFormField from "./AutoFormField.vue";
|
||||||
import AutoFormLabel from './AutoFormLabel.vue'
|
import AutoFormLabel from "./AutoFormLabel.vue";
|
||||||
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@/components/ui/accordion'
|
import {
|
||||||
import { Button } from '@/components/ui/button'
|
Accordion,
|
||||||
import { Separator } from '@/components/ui/separator'
|
AccordionContent,
|
||||||
import { FormItem, FormMessage } from '@/components/ui/form'
|
AccordionItem,
|
||||||
|
AccordionTrigger,
|
||||||
|
} from "@/components/ui/accordion";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { Separator } from "@/components/ui/separator";
|
||||||
|
import { FormItem, FormMessage } from "@/components/ui/form";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
fieldName: string
|
fieldName: string;
|
||||||
required?: boolean
|
required?: boolean;
|
||||||
config?: Config<T>
|
config?: Config<T>;
|
||||||
schema?: z.ZodArray<T>
|
schema?: z.ZodArray<T>;
|
||||||
disabled?: boolean
|
disabled?: boolean;
|
||||||
}>()
|
}>();
|
||||||
|
|
||||||
function isZodArray(
|
function isZodArray(
|
||||||
item: z.ZodArray<any> | z.ZodDefault<any>,
|
item: z.ZodArray<any> | z.ZodDefault<any>,
|
||||||
): item is z.ZodArray<any> {
|
): item is z.ZodArray<any> {
|
||||||
return item instanceof z.ZodArray
|
return item instanceof z.ZodArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isZodDefault(
|
function isZodDefault(
|
||||||
item: z.ZodArray<any> | z.ZodDefault<any>,
|
item: z.ZodArray<any> | z.ZodDefault<any>,
|
||||||
): item is z.ZodDefault<any> {
|
): item is z.ZodDefault<any> {
|
||||||
return item instanceof z.ZodDefault
|
return item instanceof z.ZodDefault;
|
||||||
}
|
}
|
||||||
|
|
||||||
const itemShape = computed(() => {
|
const itemShape = computed(() => {
|
||||||
if (!props.schema)
|
if (!props.schema) return;
|
||||||
return
|
|
||||||
|
|
||||||
const schema: z.ZodAny = isZodArray(props.schema)
|
const schema: z.ZodAny = isZodArray(props.schema)
|
||||||
? props.schema._def.type
|
? props.schema._def.type
|
||||||
: isZodDefault(props.schema)
|
: isZodDefault(props.schema)
|
||||||
// @ts-expect-error missing schema
|
? // @ts-expect-error missing schema
|
||||||
? props.schema._def.innerType._def.type
|
props.schema._def.innerType._def.type
|
||||||
: null
|
: null;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
type: getBaseType(schema),
|
type: getBaseType(schema),
|
||||||
schema,
|
schema,
|
||||||
}
|
};
|
||||||
})
|
});
|
||||||
|
|
||||||
const fieldContext = useField(props.fieldName)
|
const fieldContext = useField(props.fieldName);
|
||||||
// @ts-expect-error ignore missing `id`
|
// @ts-expect-error ignore missing `id`
|
||||||
provide(FieldContextKey, fieldContext)
|
provide(FieldContextKey, fieldContext);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,15 +1,23 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed } from 'vue'
|
import { computed } from "vue";
|
||||||
import { beautifyObjectName } from './utils'
|
import { beautifyObjectName } from "./utils";
|
||||||
import type { FieldProps } from './interface'
|
import type { FieldProps } from "./interface";
|
||||||
import AutoFormLabel from './AutoFormLabel.vue'
|
import AutoFormLabel from "./AutoFormLabel.vue";
|
||||||
import { FormControl, FormDescription, FormField, FormItem, FormMessage } from '@/components/ui/form'
|
import {
|
||||||
import { Switch } from '@/components/ui/switch'
|
FormControl,
|
||||||
import { Checkbox } from '@/components/ui/checkbox'
|
FormDescription,
|
||||||
|
FormField,
|
||||||
|
FormItem,
|
||||||
|
FormMessage,
|
||||||
|
} from "@/components/ui/form";
|
||||||
|
import { Switch } from "@/components/ui/switch";
|
||||||
|
import { Checkbox } from "@/components/ui/checkbox";
|
||||||
|
|
||||||
const props = defineProps<FieldProps>()
|
const props = defineProps<FieldProps>();
|
||||||
|
|
||||||
const booleanComponent = computed(() => props.config?.component === 'switch' ? Switch : Checkbox)
|
const booleanComponent = computed(() =>
|
||||||
|
props.config?.component === "switch" ? Switch : Checkbox,
|
||||||
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,21 +1,31 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { DateFormatter, getLocalTimeZone } from '@internationalized/date'
|
import { DateFormatter, getLocalTimeZone } from "@internationalized/date";
|
||||||
import { CalendarIcon } from '@radix-icons/vue'
|
import { CalendarIcon } from "@radix-icons/vue";
|
||||||
import { beautifyObjectName } from './utils'
|
import { beautifyObjectName } from "./utils";
|
||||||
import AutoFormLabel from './AutoFormLabel.vue'
|
import AutoFormLabel from "./AutoFormLabel.vue";
|
||||||
import type { FieldProps } from './interface'
|
import type { FieldProps } from "./interface";
|
||||||
import { FormControl, FormDescription, FormField, FormItem, FormMessage } from '@/components/ui/form'
|
import {
|
||||||
|
FormControl,
|
||||||
|
FormDescription,
|
||||||
|
FormField,
|
||||||
|
FormItem,
|
||||||
|
FormMessage,
|
||||||
|
} from "@/components/ui/form";
|
||||||
|
|
||||||
import { Calendar } from '@/components/ui/calendar'
|
import { Calendar } from "@/components/ui/calendar";
|
||||||
import { Button } from '@/components/ui/button'
|
import { Button } from "@/components/ui/button";
|
||||||
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'
|
import {
|
||||||
import { cn } from '@/lib/utils'
|
Popover,
|
||||||
|
PopoverContent,
|
||||||
|
PopoverTrigger,
|
||||||
|
} from "@/components/ui/popover";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
defineProps<FieldProps>()
|
defineProps<FieldProps>();
|
||||||
|
|
||||||
const df = new DateFormatter('en-US', {
|
const df = new DateFormatter("en-US", {
|
||||||
dateStyle: 'long',
|
dateStyle: "long",
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,15 +1,29 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import AutoFormLabel from './AutoFormLabel.vue'
|
import AutoFormLabel from "./AutoFormLabel.vue";
|
||||||
import { beautifyObjectName } from './utils'
|
import { beautifyObjectName } from "./utils";
|
||||||
import type { FieldProps } from './interface'
|
import type { FieldProps } from "./interface";
|
||||||
import { FormControl, FormDescription, FormField, FormItem, FormMessage } from '@/components/ui/form'
|
import {
|
||||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'
|
FormControl,
|
||||||
import { Label } from '@/components/ui/label'
|
FormDescription,
|
||||||
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group'
|
FormField,
|
||||||
|
FormItem,
|
||||||
|
FormMessage,
|
||||||
|
} from "@/components/ui/form";
|
||||||
|
import {
|
||||||
|
Select,
|
||||||
|
SelectContent,
|
||||||
|
SelectItem,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectValue,
|
||||||
|
} from "@/components/ui/select";
|
||||||
|
import { Label } from "@/components/ui/label";
|
||||||
|
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
|
||||||
|
|
||||||
defineProps<FieldProps & {
|
defineProps<
|
||||||
options?: string[]
|
FieldProps & {
|
||||||
}>()
|
options?: string[];
|
||||||
|
}
|
||||||
|
>();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,29 +1,35 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from 'vue'
|
import { ref } from "vue";
|
||||||
import { TrashIcon } from '@radix-icons/vue'
|
import { TrashIcon } from "@radix-icons/vue";
|
||||||
import { beautifyObjectName } from './utils'
|
import { beautifyObjectName } from "./utils";
|
||||||
import type { FieldProps } from './interface'
|
import type { FieldProps } from "./interface";
|
||||||
import AutoFormLabel from './AutoFormLabel.vue'
|
import AutoFormLabel from "./AutoFormLabel.vue";
|
||||||
import { FormControl, FormDescription, FormField, FormItem, FormMessage } from '@/components/ui/form'
|
import {
|
||||||
import { Input } from '@/components/ui/input'
|
FormControl,
|
||||||
import { Button } from '@/components/ui/button'
|
FormDescription,
|
||||||
|
FormField,
|
||||||
|
FormItem,
|
||||||
|
FormMessage,
|
||||||
|
} from "@/components/ui/form";
|
||||||
|
import { Input } from "@/components/ui/input";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
|
||||||
defineProps<FieldProps>()
|
defineProps<FieldProps>();
|
||||||
|
|
||||||
const inputFile = ref<File>()
|
const inputFile = ref<File>();
|
||||||
async function parseFileAsString(file: File | undefined): Promise<string> {
|
async function parseFileAsString(file: File | undefined): Promise<string> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (file) {
|
if (file) {
|
||||||
const reader = new FileReader()
|
const reader = new FileReader();
|
||||||
reader.onloadend = () => {
|
reader.onloadend = () => {
|
||||||
resolve(reader.result as string)
|
resolve(reader.result as string);
|
||||||
}
|
};
|
||||||
reader.onerror = (err) => {
|
reader.onerror = (err) => {
|
||||||
reject(err)
|
reject(err);
|
||||||
}
|
};
|
||||||
reader.readAsDataURL(file)
|
reader.readAsDataURL(file);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,22 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed } from 'vue'
|
import { computed } from "vue";
|
||||||
import AutoFormLabel from './AutoFormLabel.vue'
|
import AutoFormLabel from "./AutoFormLabel.vue";
|
||||||
import { beautifyObjectName } from './utils'
|
import { beautifyObjectName } from "./utils";
|
||||||
import type { FieldProps } from './interface'
|
import type { FieldProps } from "./interface";
|
||||||
import { FormControl, FormDescription, FormField, FormItem, FormMessage } from '@/components/ui/form'
|
import {
|
||||||
import { Input } from '@/components/ui/input'
|
FormControl,
|
||||||
import { Textarea } from '@/components/ui/textarea'
|
FormDescription,
|
||||||
|
FormField,
|
||||||
|
FormItem,
|
||||||
|
FormMessage,
|
||||||
|
} from "@/components/ui/form";
|
||||||
|
import { Input } from "@/components/ui/input";
|
||||||
|
import { Textarea } from "@/components/ui/textarea";
|
||||||
|
|
||||||
const props = defineProps<FieldProps>()
|
const props = defineProps<FieldProps>();
|
||||||
const inputComponent = computed(() => props.config?.component === 'textarea' ? Textarea : Input)
|
const inputComponent = computed(() =>
|
||||||
|
props.config?.component === "textarea" ? Textarea : Input,
|
||||||
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,15 +1,21 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import AutoFormLabel from './AutoFormLabel.vue'
|
import AutoFormLabel from "./AutoFormLabel.vue";
|
||||||
import { beautifyObjectName } from './utils'
|
import { beautifyObjectName } from "./utils";
|
||||||
import type { FieldProps } from './interface'
|
import type { FieldProps } from "./interface";
|
||||||
import { FormControl, FormDescription, FormField, FormItem, FormMessage } from '@/components/ui/form'
|
import {
|
||||||
import { Input } from '@/components/ui/input'
|
FormControl,
|
||||||
|
FormDescription,
|
||||||
|
FormField,
|
||||||
|
FormItem,
|
||||||
|
FormMessage,
|
||||||
|
} from "@/components/ui/form";
|
||||||
|
import { Input } from "@/components/ui/input";
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
inheritAttrs: false,
|
inheritAttrs: false,
|
||||||
})
|
});
|
||||||
|
|
||||||
defineProps<FieldProps>()
|
defineProps<FieldProps>();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,52 +1,63 @@
|
|||||||
<script setup lang="ts" generic="T extends ZodRawShape">
|
<script setup lang="ts" generic="T extends ZodRawShape">
|
||||||
import type { ZodAny, ZodObject, ZodRawShape } from 'zod'
|
import type { ZodAny, ZodObject, ZodRawShape } from "zod";
|
||||||
import { computed, provide } from 'vue'
|
import { computed, provide } from "vue";
|
||||||
import { FieldContextKey, useField } from 'vee-validate'
|
import { FieldContextKey, useField } from "vee-validate";
|
||||||
import AutoFormField from './AutoFormField.vue'
|
import AutoFormField from "./AutoFormField.vue";
|
||||||
import type { Config, ConfigItem, Shape } from './interface'
|
import type { Config, ConfigItem, Shape } from "./interface";
|
||||||
import { beautifyObjectName, getBaseSchema, getBaseType, getDefaultValueInZodStack } from './utils'
|
import {
|
||||||
import AutoFormLabel from './AutoFormLabel.vue'
|
beautifyObjectName,
|
||||||
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@/components/ui/accordion'
|
getBaseSchema,
|
||||||
import { FormItem } from '@/components/ui/form'
|
getBaseType,
|
||||||
|
getDefaultValueInZodStack,
|
||||||
|
} from "./utils";
|
||||||
|
import AutoFormLabel from "./AutoFormLabel.vue";
|
||||||
|
import {
|
||||||
|
Accordion,
|
||||||
|
AccordionContent,
|
||||||
|
AccordionItem,
|
||||||
|
AccordionTrigger,
|
||||||
|
} from "@/components/ui/accordion";
|
||||||
|
import { FormItem } from "@/components/ui/form";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
fieldName: string
|
fieldName: string;
|
||||||
required?: boolean
|
required?: boolean;
|
||||||
config?: Config<T>
|
config?: Config<T>;
|
||||||
schema?: ZodObject<T>
|
schema?: ZodObject<T>;
|
||||||
disabled?: boolean
|
disabled?: boolean;
|
||||||
}>()
|
}>();
|
||||||
|
|
||||||
const shapes = computed(() => {
|
const shapes = computed(() => {
|
||||||
// @ts-expect-error ignore {} not assignable to object
|
// @ts-expect-error ignore {} not assignable to object
|
||||||
const val: { [key in keyof T]: Shape } = {}
|
const val: { [key in keyof T]: Shape } = {};
|
||||||
|
|
||||||
if (!props.schema)
|
if (!props.schema) return;
|
||||||
return
|
const shape = getBaseSchema(props.schema)?.shape;
|
||||||
const shape = getBaseSchema(props.schema)?.shape
|
if (!shape) return;
|
||||||
if (!shape)
|
Object.keys(shape).forEach((name) => {
|
||||||
return
|
const item = shape[name] as ZodAny;
|
||||||
Object.keys(shape).forEach((name) => {
|
const baseItem = getBaseSchema(item) as ZodAny;
|
||||||
const item = shape[name] as ZodAny
|
let options =
|
||||||
const baseItem = getBaseSchema(item) as ZodAny
|
baseItem && "values" in baseItem._def
|
||||||
let options = (baseItem && 'values' in baseItem._def) ? baseItem._def.values as string[] : undefined
|
? (baseItem._def.values as string[])
|
||||||
if (!Array.isArray(options) && typeof options === 'object')
|
: undefined;
|
||||||
options = Object.values(options)
|
if (!Array.isArray(options) && typeof options === "object")
|
||||||
|
options = Object.values(options);
|
||||||
|
|
||||||
val[name as keyof T] = {
|
val[name as keyof T] = {
|
||||||
type: getBaseType(item),
|
type: getBaseType(item),
|
||||||
default: getDefaultValueInZodStack(item),
|
default: getDefaultValueInZodStack(item),
|
||||||
options,
|
options,
|
||||||
required: !['ZodOptional', 'ZodNullable'].includes(item._def.typeName),
|
required: !["ZodOptional", "ZodNullable"].includes(item._def.typeName),
|
||||||
schema: item,
|
schema: item,
|
||||||
}
|
};
|
||||||
})
|
});
|
||||||
return val
|
return val;
|
||||||
})
|
});
|
||||||
|
|
||||||
const fieldContext = useField(props.fieldName)
|
const fieldContext = useField(props.fieldName);
|
||||||
// @ts-expect-error ignore missing `id`
|
// @ts-expect-error ignore missing `id`
|
||||||
provide(FieldContextKey, fieldContext)
|
provide(FieldContextKey, fieldContext);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { FormLabel } from '@/components/ui/form'
|
import { FormLabel } from "@/components/ui/form";
|
||||||
|
|
||||||
defineProps<{
|
defineProps<{
|
||||||
required?: boolean
|
required?: boolean;
|
||||||
}>()
|
}>();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,39 +1,39 @@
|
|||||||
import AutoFormFieldArray from './AutoFormFieldArray.vue'
|
import AutoFormFieldArray from "./AutoFormFieldArray.vue";
|
||||||
import AutoFormFieldBoolean from './AutoFormFieldBoolean.vue'
|
import AutoFormFieldBoolean from "./AutoFormFieldBoolean.vue";
|
||||||
import AutoFormFieldDate from './AutoFormFieldDate.vue'
|
import AutoFormFieldDate from "./AutoFormFieldDate.vue";
|
||||||
import AutoFormFieldEnum from './AutoFormFieldEnum.vue'
|
import AutoFormFieldEnum from "./AutoFormFieldEnum.vue";
|
||||||
import AutoFormFieldFile from './AutoFormFieldFile.vue'
|
import AutoFormFieldFile from "./AutoFormFieldFile.vue";
|
||||||
import AutoFormFieldInput from './AutoFormFieldInput.vue'
|
import AutoFormFieldInput from "./AutoFormFieldInput.vue";
|
||||||
import AutoFormFieldNumber from './AutoFormFieldNumber.vue'
|
import AutoFormFieldNumber from "./AutoFormFieldNumber.vue";
|
||||||
import AutoFormFieldObject from './AutoFormFieldObject.vue'
|
import AutoFormFieldObject from "./AutoFormFieldObject.vue";
|
||||||
|
|
||||||
export const INPUT_COMPONENTS = {
|
export const INPUT_COMPONENTS = {
|
||||||
date: AutoFormFieldDate,
|
date: AutoFormFieldDate,
|
||||||
select: AutoFormFieldEnum,
|
select: AutoFormFieldEnum,
|
||||||
radio: AutoFormFieldEnum,
|
radio: AutoFormFieldEnum,
|
||||||
checkbox: AutoFormFieldBoolean,
|
checkbox: AutoFormFieldBoolean,
|
||||||
switch: AutoFormFieldBoolean,
|
switch: AutoFormFieldBoolean,
|
||||||
textarea: AutoFormFieldInput,
|
textarea: AutoFormFieldInput,
|
||||||
number: AutoFormFieldNumber,
|
number: AutoFormFieldNumber,
|
||||||
string: AutoFormFieldInput,
|
string: AutoFormFieldInput,
|
||||||
file: AutoFormFieldFile,
|
file: AutoFormFieldFile,
|
||||||
array: AutoFormFieldArray,
|
array: AutoFormFieldArray,
|
||||||
object: AutoFormFieldObject,
|
object: AutoFormFieldObject,
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Define handlers for specific Zod types.
|
* Define handlers for specific Zod types.
|
||||||
* You can expand this object to support more types.
|
* You can expand this object to support more types.
|
||||||
*/
|
*/
|
||||||
export const DEFAULT_ZOD_HANDLERS: {
|
export const DEFAULT_ZOD_HANDLERS: {
|
||||||
[key: string]: keyof typeof INPUT_COMPONENTS
|
[key: string]: keyof typeof INPUT_COMPONENTS;
|
||||||
} = {
|
} = {
|
||||||
ZodString: 'string',
|
ZodString: "string",
|
||||||
ZodBoolean: 'checkbox',
|
ZodBoolean: "checkbox",
|
||||||
ZodDate: 'date',
|
ZodDate: "date",
|
||||||
ZodEnum: 'select',
|
ZodEnum: "select",
|
||||||
ZodNativeEnum: 'select',
|
ZodNativeEnum: "select",
|
||||||
ZodNumber: 'number',
|
ZodNumber: "number",
|
||||||
ZodArray: 'array',
|
ZodArray: "array",
|
||||||
ZodObject: 'object',
|
ZodObject: "object",
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -1,92 +1,100 @@
|
|||||||
import type * as z from 'zod'
|
import type * as z from "zod";
|
||||||
import type { Ref } from 'vue'
|
import type { Ref } from "vue";
|
||||||
import { computed, ref, watch } from 'vue'
|
import { computed, ref, watch } from "vue";
|
||||||
import { useFieldValue, useFormValues } from 'vee-validate'
|
import { useFieldValue, useFormValues } from "vee-validate";
|
||||||
import { createContext } from 'radix-vue'
|
import { createContext } from "radix-vue";
|
||||||
import { type Dependency, DependencyType, type EnumValues } from './interface'
|
import { type Dependency, DependencyType, type EnumValues } from "./interface";
|
||||||
import { getFromPath, getIndexIfArray } from './utils'
|
import { getFromPath, getIndexIfArray } from "./utils";
|
||||||
|
|
||||||
export const [injectDependencies, provideDependencies] = createContext<Ref<Dependency<z.infer<z.ZodObject<any>>>[] | undefined>>('AutoFormDependencies')
|
export const [injectDependencies, provideDependencies] = createContext<
|
||||||
|
Ref<Dependency<z.infer<z.ZodObject<any>>>[] | undefined>
|
||||||
|
>("AutoFormDependencies");
|
||||||
|
|
||||||
export default function useDependencies(
|
export default function useDependencies(fieldName: string) {
|
||||||
fieldName: string,
|
const form = useFormValues();
|
||||||
) {
|
// parsed test[0].age => test.age
|
||||||
const form = useFormValues()
|
const currentFieldName = fieldName.replace(/\[\d+\]/g, "");
|
||||||
// parsed test[0].age => test.age
|
const currentFieldValue = useFieldValue<any>(fieldName);
|
||||||
const currentFieldName = fieldName.replace(/\[\d+\]/g, '')
|
|
||||||
const currentFieldValue = useFieldValue<any>(fieldName)
|
|
||||||
|
|
||||||
if (!form)
|
if (!form)
|
||||||
throw new Error('useDependencies should be used within <AutoForm>')
|
throw new Error("useDependencies should be used within <AutoForm>");
|
||||||
|
|
||||||
const dependencies = injectDependencies()
|
const dependencies = injectDependencies();
|
||||||
const isDisabled = ref(false)
|
const isDisabled = ref(false);
|
||||||
const isHidden = ref(false)
|
const isHidden = ref(false);
|
||||||
const isRequired = ref(false)
|
const isRequired = ref(false);
|
||||||
const overrideOptions = ref<EnumValues | undefined>()
|
const overrideOptions = ref<EnumValues | undefined>();
|
||||||
|
|
||||||
const currentFieldDependencies = computed(() => dependencies.value?.filter(
|
const currentFieldDependencies = computed(() =>
|
||||||
dependency => dependency.targetField === currentFieldName,
|
dependencies.value?.filter(
|
||||||
))
|
(dependency) => dependency.targetField === currentFieldName,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
function getSourceValue(dep: Dependency<any>) {
|
function getSourceValue(dep: Dependency<any>) {
|
||||||
const source = dep.sourceField as string
|
const source = dep.sourceField as string;
|
||||||
const index = getIndexIfArray(fieldName) ?? -1
|
const index = getIndexIfArray(fieldName) ?? -1;
|
||||||
const [sourceLast, ...sourceInitial] = source.split('.').toReversed()
|
const [sourceLast, ...sourceInitial] = source.split(".").toReversed();
|
||||||
const [_targetLast, ...targetInitial] = (dep.targetField as string).split('.').toReversed()
|
const [_targetLast, ...targetInitial] = (dep.targetField as string)
|
||||||
|
.split(".")
|
||||||
|
.toReversed();
|
||||||
|
|
||||||
if (index >= 0 && sourceInitial.join(',') === targetInitial.join(',')) {
|
if (index >= 0 && sourceInitial.join(",") === targetInitial.join(",")) {
|
||||||
const [_currentLast, ...currentInitial] = fieldName.split('.').toReversed()
|
const [_currentLast, ...currentInitial] = fieldName
|
||||||
return getFromPath(form.value, currentInitial.join('.') + sourceLast)
|
.split(".")
|
||||||
}
|
.toReversed();
|
||||||
|
return getFromPath(form.value, currentInitial.join(".") + sourceLast);
|
||||||
|
}
|
||||||
|
|
||||||
return getFromPath(form.value, source)
|
return getFromPath(form.value, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
const sourceFieldValues = computed(() => currentFieldDependencies.value?.map(dep => getSourceValue(dep)))
|
const sourceFieldValues = computed(() =>
|
||||||
|
currentFieldDependencies.value?.map((dep) => getSourceValue(dep)),
|
||||||
|
);
|
||||||
|
|
||||||
const resetConditionState = () => {
|
const resetConditionState = () => {
|
||||||
isDisabled.value = false
|
isDisabled.value = false;
|
||||||
isHidden.value = false
|
isHidden.value = false;
|
||||||
isRequired.value = false
|
isRequired.value = false;
|
||||||
overrideOptions.value = undefined
|
overrideOptions.value = undefined;
|
||||||
}
|
};
|
||||||
|
|
||||||
watch([sourceFieldValues, dependencies], () => {
|
watch(
|
||||||
resetConditionState()
|
[sourceFieldValues, dependencies],
|
||||||
currentFieldDependencies.value?.forEach((dep) => {
|
() => {
|
||||||
const sourceValue = getSourceValue(dep)
|
resetConditionState();
|
||||||
const conditionMet = dep.when(sourceValue, currentFieldValue.value)
|
currentFieldDependencies.value?.forEach((dep) => {
|
||||||
|
const sourceValue = getSourceValue(dep);
|
||||||
|
const conditionMet = dep.when(sourceValue, currentFieldValue.value);
|
||||||
|
|
||||||
switch (dep.type) {
|
switch (dep.type) {
|
||||||
case DependencyType.DISABLES:
|
case DependencyType.DISABLES:
|
||||||
if (conditionMet)
|
if (conditionMet) isDisabled.value = true;
|
||||||
isDisabled.value = true
|
|
||||||
|
|
||||||
break
|
break;
|
||||||
case DependencyType.REQUIRES:
|
case DependencyType.REQUIRES:
|
||||||
if (conditionMet)
|
if (conditionMet) isRequired.value = true;
|
||||||
isRequired.value = true
|
|
||||||
|
|
||||||
break
|
break;
|
||||||
case DependencyType.HIDES:
|
case DependencyType.HIDES:
|
||||||
if (conditionMet)
|
if (conditionMet) isHidden.value = true;
|
||||||
isHidden.value = true
|
|
||||||
|
|
||||||
break
|
break;
|
||||||
case DependencyType.SETS_OPTIONS:
|
case DependencyType.SETS_OPTIONS:
|
||||||
if (conditionMet)
|
if (conditionMet) overrideOptions.value = dep.options;
|
||||||
overrideOptions.value = dep.options
|
|
||||||
|
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}, { immediate: true, deep: true })
|
},
|
||||||
|
{ immediate: true, deep: true },
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isDisabled,
|
isDisabled,
|
||||||
isHidden,
|
isHidden,
|
||||||
isRequired,
|
isRequired,
|
||||||
overrideOptions,
|
overrideOptions,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
export { getObjectFormSchema, getBaseSchema, getBaseType } from './utils'
|
export { getObjectFormSchema, getBaseSchema, getBaseType } from "./utils";
|
||||||
export type { Config, ConfigItem, FieldProps } from './interface'
|
export type { Config, ConfigItem, FieldProps } from "./interface";
|
||||||
|
|
||||||
export { default as AutoForm } from './AutoForm.vue'
|
export { default as AutoForm } from "./AutoForm.vue";
|
||||||
export { default as AutoFormField } from './AutoFormField.vue'
|
export { default as AutoFormField } from "./AutoFormField.vue";
|
||||||
export { default as AutoFormLabel } from './AutoFormLabel.vue'
|
export { default as AutoFormLabel } from "./AutoFormLabel.vue";
|
||||||
|
|
||||||
export { default as AutoFormFieldArray } from './AutoFormFieldArray.vue'
|
export { default as AutoFormFieldArray } from "./AutoFormFieldArray.vue";
|
||||||
export { default as AutoFormFieldBoolean } from './AutoFormFieldBoolean.vue'
|
export { default as AutoFormFieldBoolean } from "./AutoFormFieldBoolean.vue";
|
||||||
export { default as AutoFormFieldDate } from './AutoFormFieldDate.vue'
|
export { default as AutoFormFieldDate } from "./AutoFormFieldDate.vue";
|
||||||
export { default as AutoFormFieldEnum } from './AutoFormFieldEnum.vue'
|
export { default as AutoFormFieldEnum } from "./AutoFormFieldEnum.vue";
|
||||||
export { default as AutoFormFieldFile } from './AutoFormFieldFile.vue'
|
export { default as AutoFormFieldFile } from "./AutoFormFieldFile.vue";
|
||||||
export { default as AutoFormFieldInput } from './AutoFormFieldInput.vue'
|
export { default as AutoFormFieldInput } from "./AutoFormFieldInput.vue";
|
||||||
export { default as AutoFormFieldNumber } from './AutoFormFieldNumber.vue'
|
export { default as AutoFormFieldNumber } from "./AutoFormFieldNumber.vue";
|
||||||
export { default as AutoFormFieldObject } from './AutoFormFieldObject.vue'
|
export { default as AutoFormFieldObject } from "./AutoFormFieldObject.vue";
|
||||||
|
|||||||
@@ -1,81 +1,80 @@
|
|||||||
import type { Component, InputHTMLAttributes } from 'vue'
|
import type { Component, InputHTMLAttributes } from "vue";
|
||||||
import type { ZodAny, z } from 'zod'
|
import type { ZodAny, z } from "zod";
|
||||||
import type { INPUT_COMPONENTS } from './constant'
|
import type { INPUT_COMPONENTS } from "./constant";
|
||||||
|
|
||||||
export interface FieldProps {
|
export interface FieldProps {
|
||||||
fieldName: string
|
fieldName: string;
|
||||||
label?: string
|
label?: string;
|
||||||
required?: boolean
|
required?: boolean;
|
||||||
config?: ConfigItem
|
config?: ConfigItem;
|
||||||
disabled?: boolean
|
disabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Shape {
|
export interface Shape {
|
||||||
type: string
|
type: string;
|
||||||
default?: any
|
default?: any;
|
||||||
required?: boolean
|
required?: boolean;
|
||||||
options?: string[]
|
options?: string[];
|
||||||
schema?: ZodAny
|
schema?: ZodAny;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ConfigItem {
|
export interface ConfigItem {
|
||||||
/** Value for the `FormLabel` */
|
/** Value for the `FormLabel` */
|
||||||
label?: string
|
label?: string;
|
||||||
/** Value for the `FormDescription` */
|
/** Value for the `FormDescription` */
|
||||||
description?: string
|
description?: string;
|
||||||
/** Pick which component to be rendered. */
|
/** Pick which component to be rendered. */
|
||||||
component?: keyof typeof INPUT_COMPONENTS | Component
|
component?: keyof typeof INPUT_COMPONENTS | Component;
|
||||||
/** Hide `FormLabel`. */
|
/** Hide `FormLabel`. */
|
||||||
hideLabel?: boolean
|
hideLabel?: boolean;
|
||||||
inputProps?: InputHTMLAttributes
|
inputProps?: InputHTMLAttributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Define a type to unwrap an array
|
// Define a type to unwrap an array
|
||||||
type UnwrapArray<T> = T extends (infer U)[] ? U : never
|
type UnwrapArray<T> = T extends (infer U)[] ? U : never;
|
||||||
|
|
||||||
export type Config<SchemaType extends object> = {
|
export type Config<SchemaType extends object> = {
|
||||||
// If SchemaType.key is an object, create a nested Config, otherwise ConfigItem
|
// If SchemaType.key is an object, create a nested Config, otherwise ConfigItem
|
||||||
[Key in keyof SchemaType]?:
|
[Key in keyof SchemaType]?: SchemaType[Key] extends any[]
|
||||||
SchemaType[Key] extends any[]
|
? UnwrapArray<Config<SchemaType[Key]>>
|
||||||
? UnwrapArray<Config<SchemaType[Key]>>
|
: SchemaType[Key] extends object
|
||||||
: SchemaType[Key] extends object
|
? Config<SchemaType[Key]>
|
||||||
? Config<SchemaType[Key]>
|
: ConfigItem;
|
||||||
: ConfigItem;
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export enum DependencyType {
|
export enum DependencyType {
|
||||||
DISABLES,
|
DISABLES,
|
||||||
REQUIRES,
|
REQUIRES,
|
||||||
HIDES,
|
HIDES,
|
||||||
SETS_OPTIONS,
|
SETS_OPTIONS,
|
||||||
}
|
}
|
||||||
|
|
||||||
interface BaseDependency<SchemaType extends z.infer<z.ZodObject<any, any>>> {
|
interface BaseDependency<SchemaType extends z.infer<z.ZodObject<any, any>>> {
|
||||||
sourceField: keyof SchemaType
|
sourceField: keyof SchemaType;
|
||||||
type: DependencyType
|
type: DependencyType;
|
||||||
targetField: keyof SchemaType
|
targetField: keyof SchemaType;
|
||||||
when: (sourceFieldValue: any, targetFieldValue: any) => boolean
|
when: (sourceFieldValue: any, targetFieldValue: any) => boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ValueDependency<SchemaType extends z.infer<z.ZodObject<any, any>>> =
|
export type ValueDependency<SchemaType extends z.infer<z.ZodObject<any, any>>> =
|
||||||
BaseDependency<SchemaType> & {
|
BaseDependency<SchemaType> & {
|
||||||
type:
|
type:
|
||||||
| DependencyType.DISABLES
|
| DependencyType.DISABLES
|
||||||
| DependencyType.REQUIRES
|
| DependencyType.REQUIRES
|
||||||
| DependencyType.HIDES
|
| DependencyType.HIDES;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type EnumValues = readonly [string, ...string[]]
|
export type EnumValues = readonly [string, ...string[]];
|
||||||
|
|
||||||
export type OptionsDependency<
|
export type OptionsDependency<
|
||||||
SchemaType extends z.infer<z.ZodObject<any, any>>,
|
SchemaType extends z.infer<z.ZodObject<any, any>>,
|
||||||
> = BaseDependency<SchemaType> & {
|
> = BaseDependency<SchemaType> & {
|
||||||
type: DependencyType.SETS_OPTIONS
|
type: DependencyType.SETS_OPTIONS;
|
||||||
|
|
||||||
// Partial array of values from sourceField that will trigger the dependency
|
// Partial array of values from sourceField that will trigger the dependency
|
||||||
options: EnumValues
|
options: EnumValues;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type Dependency<SchemaType extends z.infer<z.ZodObject<any, any>>> =
|
export type Dependency<SchemaType extends z.infer<z.ZodObject<any, any>>> =
|
||||||
| ValueDependency<SchemaType>
|
| ValueDependency<SchemaType>
|
||||||
| OptionsDependency<SchemaType>
|
| OptionsDependency<SchemaType>;
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
import type { z } from 'zod'
|
import type { z } from "zod";
|
||||||
|
|
||||||
// TODO: This should support recursive ZodEffects but TypeScript doesn't allow circular type definitions.
|
// TODO: This should support recursive ZodEffects but TypeScript doesn't allow circular type definitions.
|
||||||
export type ZodObjectOrWrapped =
|
export type ZodObjectOrWrapped =
|
||||||
| z.ZodObject<any, any>
|
| z.ZodObject<any, any>
|
||||||
| z.ZodEffects<z.ZodObject<any, any>>
|
| z.ZodEffects<z.ZodObject<any, any>>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Beautify a camelCase string.
|
* Beautify a camelCase string.
|
||||||
* e.g. "myString" -> "My String"
|
* e.g. "myString" -> "My String"
|
||||||
*/
|
*/
|
||||||
export function beautifyObjectName(string: string) {
|
export function beautifyObjectName(string: string) {
|
||||||
// Remove bracketed indices
|
// Remove bracketed indices
|
||||||
// if numbers only return the string
|
// if numbers only return the string
|
||||||
let output = string.replace(/\[\d+\]/g, '').replace(/([A-Z])/g, ' $1')
|
let output = string.replace(/\[\d+\]/g, "").replace(/([A-Z])/g, " $1");
|
||||||
output = output.charAt(0).toUpperCase() + output.slice(1)
|
output = output.charAt(0).toUpperCase() + output.slice(1);
|
||||||
return output
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -23,12 +23,12 @@ export function beautifyObjectName(string: string) {
|
|||||||
* @returns index or undefined
|
* @returns index or undefined
|
||||||
*/
|
*/
|
||||||
export function getIndexIfArray(string: string) {
|
export function getIndexIfArray(string: string) {
|
||||||
const indexRegex = /\[(\d+)\]/
|
const indexRegex = /\[(\d+)\]/;
|
||||||
// Match the index
|
// Match the index
|
||||||
const match = string.match(indexRegex)
|
const match = string.match(indexRegex);
|
||||||
// Extract the index (number)
|
// Extract the index (number)
|
||||||
const index = match ? Number.parseInt(match[1]) : undefined
|
const index = match ? Number.parseInt(match[1]) : undefined;
|
||||||
return index
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -36,17 +36,16 @@ export function getIndexIfArray(string: string) {
|
|||||||
* This will unpack optionals, refinements, etc.
|
* This will unpack optionals, refinements, etc.
|
||||||
*/
|
*/
|
||||||
export function getBaseSchema<
|
export function getBaseSchema<
|
||||||
ChildType extends z.ZodAny | z.AnyZodObject = z.ZodAny,
|
ChildType extends z.ZodAny | z.AnyZodObject = z.ZodAny,
|
||||||
>(schema: ChildType | z.ZodEffects<ChildType>): ChildType | null {
|
>(schema: ChildType | z.ZodEffects<ChildType>): ChildType | null {
|
||||||
if (!schema)
|
if (!schema) return null;
|
||||||
return null
|
if ("innerType" in schema._def)
|
||||||
if ('innerType' in schema._def)
|
return getBaseSchema(schema._def.innerType as ChildType);
|
||||||
return getBaseSchema(schema._def.innerType as ChildType)
|
|
||||||
|
|
||||||
if ('schema' in schema._def)
|
if ("schema" in schema._def)
|
||||||
return getBaseSchema(schema._def.schema as ChildType)
|
return getBaseSchema(schema._def.schema as ChildType);
|
||||||
|
|
||||||
return schema as ChildType
|
return schema as ChildType;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -54,118 +53,119 @@ export function getBaseSchema<
|
|||||||
* This will unpack optionals, refinements, etc.
|
* This will unpack optionals, refinements, etc.
|
||||||
*/
|
*/
|
||||||
export function getBaseType(schema: z.ZodAny) {
|
export function getBaseType(schema: z.ZodAny) {
|
||||||
const baseSchema = getBaseSchema(schema)
|
const baseSchema = getBaseSchema(schema);
|
||||||
return baseSchema ? baseSchema._def.typeName : ''
|
return baseSchema ? baseSchema._def.typeName : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Search for a "ZodDefault" in the Zod stack and return its value.
|
* Search for a "ZodDefault" in the Zod stack and return its value.
|
||||||
*/
|
*/
|
||||||
export function getDefaultValueInZodStack(schema: z.ZodAny): any {
|
export function getDefaultValueInZodStack(schema: z.ZodAny): any {
|
||||||
const typedSchema = schema as unknown as z.ZodDefault<
|
const typedSchema = schema as unknown as z.ZodDefault<
|
||||||
z.ZodNumber | z.ZodString
|
z.ZodNumber | z.ZodString
|
||||||
>
|
>;
|
||||||
|
|
||||||
if (typedSchema._def.typeName === 'ZodDefault')
|
if (typedSchema._def.typeName === "ZodDefault")
|
||||||
return typedSchema._def.defaultValue()
|
return typedSchema._def.defaultValue();
|
||||||
|
|
||||||
if ('innerType' in typedSchema._def) {
|
if ("innerType" in typedSchema._def) {
|
||||||
return getDefaultValueInZodStack(
|
return getDefaultValueInZodStack(
|
||||||
typedSchema._def.innerType as unknown as z.ZodAny,
|
typedSchema._def.innerType as unknown as z.ZodAny,
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
if ('schema' in typedSchema._def) {
|
if ("schema" in typedSchema._def) {
|
||||||
return getDefaultValueInZodStack(
|
return getDefaultValueInZodStack(
|
||||||
(typedSchema._def as any).schema as z.ZodAny,
|
(typedSchema._def as any).schema as z.ZodAny,
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return undefined
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getObjectFormSchema(
|
export function getObjectFormSchema(
|
||||||
schema: ZodObjectOrWrapped,
|
schema: ZodObjectOrWrapped,
|
||||||
): z.ZodObject<any, any> {
|
): z.ZodObject<any, any> {
|
||||||
if (schema?._def.typeName === 'ZodEffects') {
|
if (schema?._def.typeName === "ZodEffects") {
|
||||||
const typedSchema = schema as z.ZodEffects<z.ZodObject<any, any>>
|
const typedSchema = schema as z.ZodEffects<z.ZodObject<any, any>>;
|
||||||
return getObjectFormSchema(typedSchema._def.schema)
|
return getObjectFormSchema(typedSchema._def.schema);
|
||||||
}
|
}
|
||||||
return schema as z.ZodObject<any, any>
|
return schema as z.ZodObject<any, any>;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isIndex(value: unknown): value is number {
|
function isIndex(value: unknown): value is number {
|
||||||
return Number(value) >= 0
|
return Number(value) >= 0;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Constructs a path with dot paths for arrays to use brackets to be compatible with vee-validate path syntax
|
* Constructs a path with dot paths for arrays to use brackets to be compatible with vee-validate path syntax
|
||||||
*/
|
*/
|
||||||
export function normalizeFormPath(path: string): string {
|
export function normalizeFormPath(path: string): string {
|
||||||
const pathArr = path.split('.')
|
const pathArr = path.split(".");
|
||||||
if (!pathArr.length)
|
if (!pathArr.length) return "";
|
||||||
return ''
|
|
||||||
|
|
||||||
let fullPath = String(pathArr[0])
|
let fullPath = String(pathArr[0]);
|
||||||
for (let i = 1; i < pathArr.length; i++) {
|
for (let i = 1; i < pathArr.length; i++) {
|
||||||
if (isIndex(pathArr[i])) {
|
if (isIndex(pathArr[i])) {
|
||||||
fullPath += `[${pathArr[i]}]`
|
fullPath += `[${pathArr[i]}]`;
|
||||||
continue
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
fullPath += `.${pathArr[i]}`
|
fullPath += `.${pathArr[i]}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return fullPath
|
return fullPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
type NestedRecord = Record<string, unknown> | { [k: string]: NestedRecord }
|
type NestedRecord = Record<string, unknown> | { [k: string]: NestedRecord };
|
||||||
/**
|
/**
|
||||||
* Checks if the path opted out of nested fields using `[fieldName]` syntax
|
* Checks if the path opted out of nested fields using `[fieldName]` syntax
|
||||||
*/
|
*/
|
||||||
export function isNotNestedPath(path: string) {
|
export function isNotNestedPath(path: string) {
|
||||||
return /^\[.+\]$/.test(path)
|
return /^\[.+\]$/.test(path);
|
||||||
}
|
}
|
||||||
function isObject(obj: unknown): obj is Record<string, unknown> {
|
function isObject(obj: unknown): obj is Record<string, unknown> {
|
||||||
return obj !== null && !!obj && typeof obj === 'object' && !Array.isArray(obj)
|
return (
|
||||||
|
obj !== null && !!obj && typeof obj === "object" && !Array.isArray(obj)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
function isContainerValue(value: unknown): value is Record<string, unknown> {
|
function isContainerValue(value: unknown): value is Record<string, unknown> {
|
||||||
return isObject(value) || Array.isArray(value)
|
return isObject(value) || Array.isArray(value);
|
||||||
}
|
}
|
||||||
function cleanupNonNestedPath(path: string) {
|
function cleanupNonNestedPath(path: string) {
|
||||||
if (isNotNestedPath(path))
|
if (isNotNestedPath(path)) return path.replace(/\[|\]/g, "");
|
||||||
return path.replace(/\[|\]/g, '')
|
|
||||||
|
|
||||||
return path
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a nested property value from an object
|
* Gets a nested property value from an object
|
||||||
*/
|
*/
|
||||||
export function getFromPath<TValue = unknown>(object: NestedRecord | undefined, path: string): TValue | undefined
|
export function getFromPath<TValue = unknown>(
|
||||||
|
object: NestedRecord | undefined,
|
||||||
|
path: string,
|
||||||
|
): TValue | undefined;
|
||||||
export function getFromPath<TValue = unknown, TFallback = TValue>(
|
export function getFromPath<TValue = unknown, TFallback = TValue>(
|
||||||
object: NestedRecord | undefined,
|
object: NestedRecord | undefined,
|
||||||
path: string,
|
path: string,
|
||||||
fallback?: TFallback,
|
fallback?: TFallback,
|
||||||
): TValue | TFallback
|
): TValue | TFallback;
|
||||||
export function getFromPath<TValue = unknown, TFallback = TValue>(
|
export function getFromPath<TValue = unknown, TFallback = TValue>(
|
||||||
object: NestedRecord | undefined,
|
object: NestedRecord | undefined,
|
||||||
path: string,
|
path: string,
|
||||||
fallback?: TFallback,
|
fallback?: TFallback,
|
||||||
): TValue | TFallback | undefined {
|
): TValue | TFallback | undefined {
|
||||||
if (!object)
|
if (!object) return fallback;
|
||||||
return fallback
|
|
||||||
|
|
||||||
if (isNotNestedPath(path))
|
if (isNotNestedPath(path))
|
||||||
return object[cleanupNonNestedPath(path)] as TValue | undefined
|
return object[cleanupNonNestedPath(path)] as TValue | undefined;
|
||||||
|
|
||||||
const resolvedValue = (path || '')
|
const resolvedValue = (path || "")
|
||||||
.split(/\.|\[(\d+)\]/)
|
.split(/\.|\[(\d+)\]/)
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
.reduce((acc, propKey) => {
|
.reduce((acc, propKey) => {
|
||||||
if (isContainerValue(acc) && propKey in acc)
|
if (isContainerValue(acc) && propKey in acc) return acc[propKey];
|
||||||
return acc[propKey]
|
|
||||||
|
|
||||||
return fallback
|
return fallback;
|
||||||
}, object as unknown)
|
}, object as unknown);
|
||||||
|
|
||||||
return resolvedValue as TValue | undefined
|
return resolvedValue as TValue | undefined;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,20 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { HTMLAttributes } from 'vue'
|
import type { HTMLAttributes } from "vue";
|
||||||
import { AvatarRoot } from 'radix-vue'
|
import { AvatarRoot } from "radix-vue";
|
||||||
import { type AvatarVariants, avatarVariant } from '.'
|
import { type AvatarVariants, avatarVariant } from ".";
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(
|
||||||
class?: HTMLAttributes['class']
|
defineProps<{
|
||||||
size?: AvatarVariants['size']
|
class?: HTMLAttributes["class"];
|
||||||
shape?: AvatarVariants['shape']
|
size?: AvatarVariants["size"];
|
||||||
}>(), {
|
shape?: AvatarVariants["shape"];
|
||||||
size: 'sm',
|
}>(),
|
||||||
shape: 'circle',
|
{
|
||||||
})
|
size: "sm",
|
||||||
|
shape: "circle",
|
||||||
|
},
|
||||||
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { AvatarFallback, type AvatarFallbackProps } from 'radix-vue'
|
import { AvatarFallback, type AvatarFallbackProps } from "radix-vue";
|
||||||
|
|
||||||
const props = defineProps<AvatarFallbackProps>()
|
const props = defineProps<AvatarFallbackProps>();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { AvatarImage, type AvatarImageProps } from 'radix-vue'
|
import { AvatarImage, type AvatarImageProps } from "radix-vue";
|
||||||
|
|
||||||
const props = defineProps<AvatarImageProps>()
|
const props = defineProps<AvatarImageProps>();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,24 +1,24 @@
|
|||||||
import { type VariantProps, cva } from 'class-variance-authority'
|
import { type VariantProps, cva } from "class-variance-authority";
|
||||||
|
|
||||||
export { default as Avatar } from './Avatar.vue'
|
export { default as Avatar } from "./Avatar.vue";
|
||||||
export { default as AvatarImage } from './AvatarImage.vue'
|
export { default as AvatarImage } from "./AvatarImage.vue";
|
||||||
export { default as AvatarFallback } from './AvatarFallback.vue'
|
export { default as AvatarFallback } from "./AvatarFallback.vue";
|
||||||
|
|
||||||
export const avatarVariant = cva(
|
export const avatarVariant = cva(
|
||||||
'inline-flex items-center justify-center font-normal text-foreground select-none shrink-0 bg-secondary overflow-hidden',
|
"inline-flex items-center justify-center font-normal text-foreground select-none shrink-0 bg-secondary overflow-hidden",
|
||||||
{
|
{
|
||||||
variants: {
|
variants: {
|
||||||
size: {
|
size: {
|
||||||
sm: 'h-10 w-10 text-xs',
|
sm: "h-10 w-10 text-xs",
|
||||||
base: 'h-16 w-16 text-2xl',
|
base: "h-16 w-16 text-2xl",
|
||||||
lg: 'h-32 w-32 text-5xl',
|
lg: "h-32 w-32 text-5xl",
|
||||||
},
|
},
|
||||||
shape: {
|
shape: {
|
||||||
circle: 'rounded-full',
|
circle: "rounded-full",
|
||||||
square: 'rounded-md',
|
square: "rounded-md",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)
|
);
|
||||||
|
|
||||||
export type AvatarVariants = VariantProps<typeof avatarVariant>
|
export type AvatarVariants = VariantProps<typeof avatarVariant>;
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { HTMLAttributes } from 'vue'
|
import type { HTMLAttributes } from "vue";
|
||||||
import { type BadgeVariants, badgeVariants } from '.'
|
import { type BadgeVariants, badgeVariants } from ".";
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
variant?: BadgeVariants['variant']
|
variant?: BadgeVariants["variant"];
|
||||||
class?: HTMLAttributes['class']
|
class?: HTMLAttributes["class"];
|
||||||
}>()
|
}>();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,25 +1,25 @@
|
|||||||
import { type VariantProps, cva } from 'class-variance-authority'
|
import { type VariantProps, cva } from "class-variance-authority";
|
||||||
|
|
||||||
export { default as Badge } from './Badge.vue'
|
export { default as Badge } from "./Badge.vue";
|
||||||
|
|
||||||
export const badgeVariants = cva(
|
export const badgeVariants = cva(
|
||||||
'inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2',
|
"inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
|
||||||
{
|
{
|
||||||
variants: {
|
variants: {
|
||||||
variant: {
|
variant: {
|
||||||
default:
|
default:
|
||||||
'border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80',
|
"border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80",
|
||||||
secondary:
|
secondary:
|
||||||
'border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80',
|
"border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
||||||
destructive:
|
destructive:
|
||||||
'border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80',
|
"border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80",
|
||||||
outline: 'text-foreground',
|
outline: "text-foreground",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
defaultVariants: {
|
defaultVariants: {
|
||||||
variant: 'default',
|
variant: "default",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)
|
);
|
||||||
|
|
||||||
export type BadgeVariants = VariantProps<typeof badgeVariants>
|
export type BadgeVariants = VariantProps<typeof badgeVariants>;
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { HTMLAttributes } from 'vue'
|
import type { HTMLAttributes } from "vue";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
class?: HTMLAttributes['class']
|
class?: HTMLAttributes["class"];
|
||||||
}>()
|
}>();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { HTMLAttributes } from 'vue'
|
import type { HTMLAttributes } from "vue";
|
||||||
import { DotsHorizontalIcon } from '@radix-icons/vue'
|
import { DotsHorizontalIcon } from "@radix-icons/vue";
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
class?: HTMLAttributes['class']
|
class?: HTMLAttributes["class"];
|
||||||
}>()
|
}>();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { HTMLAttributes } from 'vue'
|
import type { HTMLAttributes } from "vue";
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
class?: HTMLAttributes['class']
|
class?: HTMLAttributes["class"];
|
||||||
}>()
|
}>();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { HTMLAttributes } from 'vue'
|
import type { HTMLAttributes } from "vue";
|
||||||
import { Primitive, type PrimitiveProps } from 'radix-vue'
|
import { Primitive, type PrimitiveProps } from "radix-vue";
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const props = withDefaults(defineProps<PrimitiveProps & { class?: HTMLAttributes['class'] }>(), {
|
const props = withDefaults(
|
||||||
as: 'a',
|
defineProps<PrimitiveProps & { class?: HTMLAttributes["class"] }>(),
|
||||||
})
|
{
|
||||||
|
as: "a",
|
||||||
|
},
|
||||||
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { HTMLAttributes } from 'vue'
|
import type { HTMLAttributes } from "vue";
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
class?: HTMLAttributes['class']
|
class?: HTMLAttributes["class"];
|
||||||
}>()
|
}>();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { HTMLAttributes } from 'vue'
|
import type { HTMLAttributes } from "vue";
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
class?: HTMLAttributes['class']
|
class?: HTMLAttributes["class"];
|
||||||
}>()
|
}>();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { HTMLAttributes } from 'vue'
|
import type { HTMLAttributes } from "vue";
|
||||||
import { ChevronRightIcon } from '@radix-icons/vue'
|
import { ChevronRightIcon } from "@radix-icons/vue";
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
class?: HTMLAttributes['class']
|
class?: HTMLAttributes["class"];
|
||||||
}>()
|
}>();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
export { default as Breadcrumb } from './Breadcrumb.vue'
|
export { default as Breadcrumb } from "./Breadcrumb.vue";
|
||||||
export { default as BreadcrumbEllipsis } from './BreadcrumbEllipsis.vue'
|
export { default as BreadcrumbEllipsis } from "./BreadcrumbEllipsis.vue";
|
||||||
export { default as BreadcrumbItem } from './BreadcrumbItem.vue'
|
export { default as BreadcrumbItem } from "./BreadcrumbItem.vue";
|
||||||
export { default as BreadcrumbLink } from './BreadcrumbLink.vue'
|
export { default as BreadcrumbLink } from "./BreadcrumbLink.vue";
|
||||||
export { default as BreadcrumbList } from './BreadcrumbList.vue'
|
export { default as BreadcrumbList } from "./BreadcrumbList.vue";
|
||||||
export { default as BreadcrumbPage } from './BreadcrumbPage.vue'
|
export { default as BreadcrumbPage } from "./BreadcrumbPage.vue";
|
||||||
export { default as BreadcrumbSeparator } from './BreadcrumbSeparator.vue'
|
export { default as BreadcrumbSeparator } from "./BreadcrumbSeparator.vue";
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { HTMLAttributes } from 'vue'
|
import type { HTMLAttributes } from "vue";
|
||||||
import { Primitive, type PrimitiveProps } from 'radix-vue'
|
import { Primitive, type PrimitiveProps } from "radix-vue";
|
||||||
import { type ButtonVariants, buttonVariants } from '.'
|
import { type ButtonVariants, buttonVariants } from ".";
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
interface Props extends PrimitiveProps {
|
interface Props extends PrimitiveProps {
|
||||||
variant?: ButtonVariants['variant']
|
variant?: ButtonVariants["variant"];
|
||||||
size?: ButtonVariants['size']
|
size?: ButtonVariants["size"];
|
||||||
class?: HTMLAttributes['class']
|
class?: HTMLAttributes["class"];
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
as: 'button',
|
as: "button",
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,35 +1,36 @@
|
|||||||
import { type VariantProps, cva } from 'class-variance-authority'
|
import { type VariantProps, cva } from "class-variance-authority";
|
||||||
|
|
||||||
export { default as Button } from './Button.vue'
|
export { default as Button } from "./Button.vue";
|
||||||
|
|
||||||
export const buttonVariants = cva(
|
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 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",
|
||||||
{
|
{
|
||||||
variants: {
|
variants: {
|
||||||
variant: {
|
variant: {
|
||||||
default: 'bg-primary text-primary-foreground shadow hover:bg-primary/90',
|
default:
|
||||||
destructive:
|
"bg-primary text-primary-foreground shadow hover:bg-primary/90",
|
||||||
'bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90',
|
destructive:
|
||||||
outline:
|
"bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
|
||||||
'border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground',
|
outline:
|
||||||
secondary:
|
"border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
|
||||||
'bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80',
|
secondary:
|
||||||
ghost: 'hover:bg-accent hover:text-accent-foreground',
|
"bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
|
||||||
link: 'text-primary underline-offset-4 hover:underline',
|
ghost: "hover:bg-accent hover:text-accent-foreground",
|
||||||
},
|
link: "text-primary underline-offset-4 hover:underline",
|
||||||
size: {
|
},
|
||||||
default: 'h-9 px-4 py-2',
|
size: {
|
||||||
xs: 'h-7 rounded px-2',
|
default: "h-9 px-4 py-2",
|
||||||
sm: 'h-8 rounded-md px-3 text-xs',
|
xs: "h-7 rounded px-2",
|
||||||
lg: 'h-10 rounded-md px-8',
|
sm: "h-8 rounded-md px-3 text-xs",
|
||||||
icon: 'h-9 w-9',
|
lg: "h-10 rounded-md px-8",
|
||||||
},
|
icon: "h-9 w-9",
|
||||||
},
|
},
|
||||||
defaultVariants: {
|
},
|
||||||
variant: 'default',
|
defaultVariants: {
|
||||||
size: 'default',
|
variant: "default",
|
||||||
},
|
size: "default",
|
||||||
},
|
},
|
||||||
)
|
},
|
||||||
|
);
|
||||||
|
|
||||||
export type ButtonVariants = VariantProps<typeof buttonVariants>
|
export type ButtonVariants = VariantProps<typeof buttonVariants>;
|
||||||
|
|||||||
@@ -1,20 +1,39 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { type HTMLAttributes, computed } from 'vue'
|
import { type HTMLAttributes, computed } from "vue";
|
||||||
import { CalendarRoot, type CalendarRootEmits, type CalendarRootProps, useForwardPropsEmits } from 'radix-vue'
|
import {
|
||||||
import { CalendarCell, CalendarCellTrigger, CalendarGrid, CalendarGridBody, CalendarGridHead, CalendarGridRow, CalendarHeadCell, CalendarHeader, CalendarHeading, CalendarNextButton, CalendarPrevButton } from '.'
|
CalendarRoot,
|
||||||
import { cn } from '@/lib/utils'
|
type CalendarRootEmits,
|
||||||
|
type CalendarRootProps,
|
||||||
|
useForwardPropsEmits,
|
||||||
|
} from "radix-vue";
|
||||||
|
import {
|
||||||
|
CalendarCell,
|
||||||
|
CalendarCellTrigger,
|
||||||
|
CalendarGrid,
|
||||||
|
CalendarGridBody,
|
||||||
|
CalendarGridHead,
|
||||||
|
CalendarGridRow,
|
||||||
|
CalendarHeadCell,
|
||||||
|
CalendarHeader,
|
||||||
|
CalendarHeading,
|
||||||
|
CalendarNextButton,
|
||||||
|
CalendarPrevButton,
|
||||||
|
} from ".";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const props = defineProps<CalendarRootProps & { class?: HTMLAttributes['class'] }>()
|
const props = defineProps<
|
||||||
|
CalendarRootProps & { class?: HTMLAttributes["class"] }
|
||||||
|
>();
|
||||||
|
|
||||||
const emits = defineEmits<CalendarRootEmits>()
|
const emits = defineEmits<CalendarRootEmits>();
|
||||||
|
|
||||||
const delegatedProps = computed(() => {
|
const delegatedProps = computed(() => {
|
||||||
const { class: _, ...delegated } = props
|
const { class: _, ...delegated } = props;
|
||||||
|
|
||||||
return delegated
|
return delegated;
|
||||||
})
|
});
|
||||||
|
|
||||||
const forwarded = useForwardPropsEmits(delegatedProps, emits)
|
const forwarded = useForwardPropsEmits(delegatedProps, emits);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,17 +1,23 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { type HTMLAttributes, computed } from 'vue'
|
import { type HTMLAttributes, computed } from "vue";
|
||||||
import { CalendarCell, type CalendarCellProps, useForwardProps } from 'radix-vue'
|
import {
|
||||||
import { cn } from '@/lib/utils'
|
CalendarCell,
|
||||||
|
type CalendarCellProps,
|
||||||
|
useForwardProps,
|
||||||
|
} from "radix-vue";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const props = defineProps<CalendarCellProps & { class?: HTMLAttributes['class'] }>()
|
const props = defineProps<
|
||||||
|
CalendarCellProps & { class?: HTMLAttributes["class"] }
|
||||||
|
>();
|
||||||
|
|
||||||
const delegatedProps = computed(() => {
|
const delegatedProps = computed(() => {
|
||||||
const { class: _, ...delegated } = props
|
const { class: _, ...delegated } = props;
|
||||||
|
|
||||||
return delegated
|
return delegated;
|
||||||
})
|
});
|
||||||
|
|
||||||
const forwardedProps = useForwardProps(delegatedProps)
|
const forwardedProps = useForwardProps(delegatedProps);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,18 +1,24 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { type HTMLAttributes, computed } from 'vue'
|
import { type HTMLAttributes, computed } from "vue";
|
||||||
import { CalendarCellTrigger, type CalendarCellTriggerProps, useForwardProps } from 'radix-vue'
|
import {
|
||||||
import { buttonVariants } from '@/components/ui/button'
|
CalendarCellTrigger,
|
||||||
import { cn } from '@/lib/utils'
|
type CalendarCellTriggerProps,
|
||||||
|
useForwardProps,
|
||||||
|
} from "radix-vue";
|
||||||
|
import { buttonVariants } from "@/components/ui/button";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const props = defineProps<CalendarCellTriggerProps & { class?: HTMLAttributes['class'] }>()
|
const props = defineProps<
|
||||||
|
CalendarCellTriggerProps & { class?: HTMLAttributes["class"] }
|
||||||
|
>();
|
||||||
|
|
||||||
const delegatedProps = computed(() => {
|
const delegatedProps = computed(() => {
|
||||||
const { class: _, ...delegated } = props
|
const { class: _, ...delegated } = props;
|
||||||
|
|
||||||
return delegated
|
return delegated;
|
||||||
})
|
});
|
||||||
|
|
||||||
const forwardedProps = useForwardProps(delegatedProps)
|
const forwardedProps = useForwardProps(delegatedProps);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,17 +1,23 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { type HTMLAttributes, computed } from 'vue'
|
import { type HTMLAttributes, computed } from "vue";
|
||||||
import { CalendarGrid, type CalendarGridProps, useForwardProps } from 'radix-vue'
|
import {
|
||||||
import { cn } from '@/lib/utils'
|
CalendarGrid,
|
||||||
|
type CalendarGridProps,
|
||||||
|
useForwardProps,
|
||||||
|
} from "radix-vue";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const props = defineProps<CalendarGridProps & { class?: HTMLAttributes['class'] }>()
|
const props = defineProps<
|
||||||
|
CalendarGridProps & { class?: HTMLAttributes["class"] }
|
||||||
|
>();
|
||||||
|
|
||||||
const delegatedProps = computed(() => {
|
const delegatedProps = computed(() => {
|
||||||
const { class: _, ...delegated } = props
|
const { class: _, ...delegated } = props;
|
||||||
|
|
||||||
return delegated
|
return delegated;
|
||||||
})
|
});
|
||||||
|
|
||||||
const forwardedProps = useForwardProps(delegatedProps)
|
const forwardedProps = useForwardProps(delegatedProps);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { CalendarGridBody, type CalendarGridBodyProps } from 'radix-vue'
|
import { CalendarGridBody, type CalendarGridBodyProps } from "radix-vue";
|
||||||
|
|
||||||
const props = defineProps<CalendarGridBodyProps>()
|
const props = defineProps<CalendarGridBodyProps>();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { HTMLAttributes } from 'vue'
|
import type { HTMLAttributes } from "vue";
|
||||||
import { CalendarGridHead, type CalendarGridHeadProps } from 'radix-vue'
|
import { CalendarGridHead, type CalendarGridHeadProps } from "radix-vue";
|
||||||
|
|
||||||
const props = defineProps<CalendarGridHeadProps & { class?: HTMLAttributes['class'] }>()
|
const props = defineProps<
|
||||||
|
CalendarGridHeadProps & { class?: HTMLAttributes["class"] }
|
||||||
|
>();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,17 +1,23 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { type HTMLAttributes, computed } from 'vue'
|
import { type HTMLAttributes, computed } from "vue";
|
||||||
import { CalendarGridRow, type CalendarGridRowProps, useForwardProps } from 'radix-vue'
|
import {
|
||||||
import { cn } from '@/lib/utils'
|
CalendarGridRow,
|
||||||
|
type CalendarGridRowProps,
|
||||||
|
useForwardProps,
|
||||||
|
} from "radix-vue";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const props = defineProps<CalendarGridRowProps & { class?: HTMLAttributes['class'] }>()
|
const props = defineProps<
|
||||||
|
CalendarGridRowProps & { class?: HTMLAttributes["class"] }
|
||||||
|
>();
|
||||||
|
|
||||||
const delegatedProps = computed(() => {
|
const delegatedProps = computed(() => {
|
||||||
const { class: _, ...delegated } = props
|
const { class: _, ...delegated } = props;
|
||||||
|
|
||||||
return delegated
|
return delegated;
|
||||||
})
|
});
|
||||||
|
|
||||||
const forwardedProps = useForwardProps(delegatedProps)
|
const forwardedProps = useForwardProps(delegatedProps);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,17 +1,23 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { type HTMLAttributes, computed } from 'vue'
|
import { type HTMLAttributes, computed } from "vue";
|
||||||
import { CalendarHeadCell, type CalendarHeadCellProps, useForwardProps } from 'radix-vue'
|
import {
|
||||||
import { cn } from '@/lib/utils'
|
CalendarHeadCell,
|
||||||
|
type CalendarHeadCellProps,
|
||||||
|
useForwardProps,
|
||||||
|
} from "radix-vue";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const props = defineProps<CalendarHeadCellProps & { class?: HTMLAttributes['class'] }>()
|
const props = defineProps<
|
||||||
|
CalendarHeadCellProps & { class?: HTMLAttributes["class"] }
|
||||||
|
>();
|
||||||
|
|
||||||
const delegatedProps = computed(() => {
|
const delegatedProps = computed(() => {
|
||||||
const { class: _, ...delegated } = props
|
const { class: _, ...delegated } = props;
|
||||||
|
|
||||||
return delegated
|
return delegated;
|
||||||
})
|
});
|
||||||
|
|
||||||
const forwardedProps = useForwardProps(delegatedProps)
|
const forwardedProps = useForwardProps(delegatedProps);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,17 +1,23 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { type HTMLAttributes, computed } from 'vue'
|
import { type HTMLAttributes, computed } from "vue";
|
||||||
import { CalendarHeader, type CalendarHeaderProps, useForwardProps } from 'radix-vue'
|
import {
|
||||||
import { cn } from '@/lib/utils'
|
CalendarHeader,
|
||||||
|
type CalendarHeaderProps,
|
||||||
|
useForwardProps,
|
||||||
|
} from "radix-vue";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const props = defineProps<CalendarHeaderProps & { class?: HTMLAttributes['class'] }>()
|
const props = defineProps<
|
||||||
|
CalendarHeaderProps & { class?: HTMLAttributes["class"] }
|
||||||
|
>();
|
||||||
|
|
||||||
const delegatedProps = computed(() => {
|
const delegatedProps = computed(() => {
|
||||||
const { class: _, ...delegated } = props
|
const { class: _, ...delegated } = props;
|
||||||
|
|
||||||
return delegated
|
return delegated;
|
||||||
})
|
});
|
||||||
|
|
||||||
const forwardedProps = useForwardProps(delegatedProps)
|
const forwardedProps = useForwardProps(delegatedProps);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,17 +1,23 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { type HTMLAttributes, computed } from 'vue'
|
import { type HTMLAttributes, computed } from "vue";
|
||||||
import { CalendarHeading, type CalendarHeadingProps, useForwardProps } from 'radix-vue'
|
import {
|
||||||
import { cn } from '@/lib/utils'
|
CalendarHeading,
|
||||||
|
type CalendarHeadingProps,
|
||||||
|
useForwardProps,
|
||||||
|
} from "radix-vue";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const props = defineProps<CalendarHeadingProps & { class?: HTMLAttributes['class'] }>()
|
const props = defineProps<
|
||||||
|
CalendarHeadingProps & { class?: HTMLAttributes["class"] }
|
||||||
|
>();
|
||||||
|
|
||||||
const delegatedProps = computed(() => {
|
const delegatedProps = computed(() => {
|
||||||
const { class: _, ...delegated } = props
|
const { class: _, ...delegated } = props;
|
||||||
|
|
||||||
return delegated
|
return delegated;
|
||||||
})
|
});
|
||||||
|
|
||||||
const forwardedProps = useForwardProps(delegatedProps)
|
const forwardedProps = useForwardProps(delegatedProps);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,19 +1,25 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { type HTMLAttributes, computed } from 'vue'
|
import { type HTMLAttributes, computed } from "vue";
|
||||||
import { CalendarNext, type CalendarNextProps, useForwardProps } from 'radix-vue'
|
import {
|
||||||
import { ChevronRightIcon } from '@radix-icons/vue'
|
CalendarNext,
|
||||||
import { cn } from '@/lib/utils'
|
type CalendarNextProps,
|
||||||
import { buttonVariants } from '@/components/ui/button'
|
useForwardProps,
|
||||||
|
} from "radix-vue";
|
||||||
|
import { ChevronRightIcon } from "@radix-icons/vue";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
import { buttonVariants } from "@/components/ui/button";
|
||||||
|
|
||||||
const props = defineProps<CalendarNextProps & { class?: HTMLAttributes['class'] }>()
|
const props = defineProps<
|
||||||
|
CalendarNextProps & { class?: HTMLAttributes["class"] }
|
||||||
|
>();
|
||||||
|
|
||||||
const delegatedProps = computed(() => {
|
const delegatedProps = computed(() => {
|
||||||
const { class: _, ...delegated } = props
|
const { class: _, ...delegated } = props;
|
||||||
|
|
||||||
return delegated
|
return delegated;
|
||||||
})
|
});
|
||||||
|
|
||||||
const forwardedProps = useForwardProps(delegatedProps)
|
const forwardedProps = useForwardProps(delegatedProps);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,19 +1,25 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { type HTMLAttributes, computed } from 'vue'
|
import { type HTMLAttributes, computed } from "vue";
|
||||||
import { CalendarPrev, type CalendarPrevProps, useForwardProps } from 'radix-vue'
|
import {
|
||||||
import { ChevronLeftIcon } from '@radix-icons/vue'
|
CalendarPrev,
|
||||||
import { cn } from '@/lib/utils'
|
type CalendarPrevProps,
|
||||||
import { buttonVariants } from '@/components/ui/button'
|
useForwardProps,
|
||||||
|
} from "radix-vue";
|
||||||
|
import { ChevronLeftIcon } from "@radix-icons/vue";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
import { buttonVariants } from "@/components/ui/button";
|
||||||
|
|
||||||
const props = defineProps<CalendarPrevProps & { class?: HTMLAttributes['class'] }>()
|
const props = defineProps<
|
||||||
|
CalendarPrevProps & { class?: HTMLAttributes["class"] }
|
||||||
|
>();
|
||||||
|
|
||||||
const delegatedProps = computed(() => {
|
const delegatedProps = computed(() => {
|
||||||
const { class: _, ...delegated } = props
|
const { class: _, ...delegated } = props;
|
||||||
|
|
||||||
return delegated
|
return delegated;
|
||||||
})
|
});
|
||||||
|
|
||||||
const forwardedProps = useForwardProps(delegatedProps)
|
const forwardedProps = useForwardProps(delegatedProps);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
export { default as Calendar } from './Calendar.vue'
|
export { default as Calendar } from "./Calendar.vue";
|
||||||
export { default as CalendarCell } from './CalendarCell.vue'
|
export { default as CalendarCell } from "./CalendarCell.vue";
|
||||||
export { default as CalendarCellTrigger } from './CalendarCellTrigger.vue'
|
export { default as CalendarCellTrigger } from "./CalendarCellTrigger.vue";
|
||||||
export { default as CalendarGrid } from './CalendarGrid.vue'
|
export { default as CalendarGrid } from "./CalendarGrid.vue";
|
||||||
export { default as CalendarGridBody } from './CalendarGridBody.vue'
|
export { default as CalendarGridBody } from "./CalendarGridBody.vue";
|
||||||
export { default as CalendarGridHead } from './CalendarGridHead.vue'
|
export { default as CalendarGridHead } from "./CalendarGridHead.vue";
|
||||||
export { default as CalendarGridRow } from './CalendarGridRow.vue'
|
export { default as CalendarGridRow } from "./CalendarGridRow.vue";
|
||||||
export { default as CalendarHeadCell } from './CalendarHeadCell.vue'
|
export { default as CalendarHeadCell } from "./CalendarHeadCell.vue";
|
||||||
export { default as CalendarHeader } from './CalendarHeader.vue'
|
export { default as CalendarHeader } from "./CalendarHeader.vue";
|
||||||
export { default as CalendarHeading } from './CalendarHeading.vue'
|
export { default as CalendarHeading } from "./CalendarHeading.vue";
|
||||||
export { default as CalendarNextButton } from './CalendarNextButton.vue'
|
export { default as CalendarNextButton } from "./CalendarNextButton.vue";
|
||||||
export { default as CalendarPrevButton } from './CalendarPrevButton.vue'
|
export { default as CalendarPrevButton } from "./CalendarPrevButton.vue";
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { HTMLAttributes } from 'vue'
|
import type { HTMLAttributes } from "vue";
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
class?: HTMLAttributes['class']
|
class?: HTMLAttributes["class"];
|
||||||
}>()
|
}>();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { HTMLAttributes } from 'vue'
|
import type { HTMLAttributes } from "vue";
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
class?: HTMLAttributes['class']
|
class?: HTMLAttributes["class"];
|
||||||
}>()
|
}>();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { HTMLAttributes } from 'vue'
|
import type { HTMLAttributes } from "vue";
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
class?: HTMLAttributes['class']
|
class?: HTMLAttributes["class"];
|
||||||
}>()
|
}>();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { HTMLAttributes } from 'vue'
|
import type { HTMLAttributes } from "vue";
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
class?: HTMLAttributes['class']
|
class?: HTMLAttributes["class"];
|
||||||
}>()
|
}>();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { HTMLAttributes } from 'vue'
|
import type { HTMLAttributes } from "vue";
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
class?: HTMLAttributes['class']
|
class?: HTMLAttributes["class"];
|
||||||
}>()
|
}>();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { HTMLAttributes } from 'vue'
|
import type { HTMLAttributes } from "vue";
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
class?: HTMLAttributes['class']
|
class?: HTMLAttributes["class"];
|
||||||
}>()
|
}>();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
export { default as Card } from './Card.vue'
|
export { default as Card } from "./Card.vue";
|
||||||
export { default as CardHeader } from './CardHeader.vue'
|
export { default as CardHeader } from "./CardHeader.vue";
|
||||||
export { default as CardTitle } from './CardTitle.vue'
|
export { default as CardTitle } from "./CardTitle.vue";
|
||||||
export { default as CardDescription } from './CardDescription.vue'
|
export { default as CardDescription } from "./CardDescription.vue";
|
||||||
export { default as CardContent } from './CardContent.vue'
|
export { default as CardContent } from "./CardContent.vue";
|
||||||
export { default as CardFooter } from './CardFooter.vue'
|
export { default as CardFooter } from "./CardFooter.vue";
|
||||||
|
|||||||
@@ -1,41 +1,53 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useProvideCarousel } from './useCarousel'
|
import { useProvideCarousel } from "./useCarousel";
|
||||||
import type { CarouselEmits, CarouselProps, WithClassAsProps } from './interface'
|
import type {
|
||||||
import { cn } from '@/lib/utils'
|
CarouselEmits,
|
||||||
|
CarouselProps,
|
||||||
|
WithClassAsProps,
|
||||||
|
} from "./interface";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const props = withDefaults(defineProps<CarouselProps & WithClassAsProps>(), {
|
const props = withDefaults(defineProps<CarouselProps & WithClassAsProps>(), {
|
||||||
orientation: 'horizontal',
|
orientation: "horizontal",
|
||||||
})
|
});
|
||||||
|
|
||||||
const emits = defineEmits<CarouselEmits>()
|
const emits = defineEmits<CarouselEmits>();
|
||||||
|
|
||||||
const { canScrollNext, canScrollPrev, carouselApi, carouselRef, orientation, scrollNext, scrollPrev } = useProvideCarousel(props, emits)
|
const {
|
||||||
|
canScrollNext,
|
||||||
|
canScrollPrev,
|
||||||
|
carouselApi,
|
||||||
|
carouselRef,
|
||||||
|
orientation,
|
||||||
|
scrollNext,
|
||||||
|
scrollPrev,
|
||||||
|
} = useProvideCarousel(props, emits);
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
canScrollNext,
|
canScrollNext,
|
||||||
canScrollPrev,
|
canScrollPrev,
|
||||||
carouselApi,
|
carouselApi,
|
||||||
carouselRef,
|
carouselRef,
|
||||||
orientation,
|
orientation,
|
||||||
scrollNext,
|
scrollNext,
|
||||||
scrollPrev,
|
scrollPrev,
|
||||||
})
|
});
|
||||||
|
|
||||||
function onKeyDown(event: KeyboardEvent) {
|
function onKeyDown(event: KeyboardEvent) {
|
||||||
const prevKey = props.orientation === 'vertical' ? 'ArrowUp' : 'ArrowLeft'
|
const prevKey = props.orientation === "vertical" ? "ArrowUp" : "ArrowLeft";
|
||||||
const nextKey = props.orientation === 'vertical' ? 'ArrowDown' : 'ArrowRight'
|
const nextKey = props.orientation === "vertical" ? "ArrowDown" : "ArrowRight";
|
||||||
|
|
||||||
if (event.key === prevKey) {
|
if (event.key === prevKey) {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
scrollPrev()
|
scrollPrev();
|
||||||
|
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.key === nextKey) {
|
if (event.key === nextKey) {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
scrollNext()
|
scrollNext();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useCarousel } from './useCarousel'
|
import { useCarousel } from "./useCarousel";
|
||||||
import type { WithClassAsProps } from './interface'
|
import type { WithClassAsProps } from "./interface";
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
inheritAttrs: false,
|
inheritAttrs: false,
|
||||||
})
|
});
|
||||||
|
|
||||||
const props = defineProps<WithClassAsProps>()
|
const props = defineProps<WithClassAsProps>();
|
||||||
|
|
||||||
const { carouselRef, orientation } = useCarousel()
|
const { carouselRef, orientation } = useCarousel();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useCarousel } from './useCarousel'
|
import { useCarousel } from "./useCarousel";
|
||||||
import type { WithClassAsProps } from './interface'
|
import type { WithClassAsProps } from "./interface";
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const props = defineProps<WithClassAsProps>()
|
const props = defineProps<WithClassAsProps>();
|
||||||
|
|
||||||
const { orientation } = useCarousel()
|
const { orientation } = useCarousel();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ArrowRightIcon } from '@radix-icons/vue'
|
import { ArrowRightIcon } from "@radix-icons/vue";
|
||||||
import { useCarousel } from './useCarousel'
|
import { useCarousel } from "./useCarousel";
|
||||||
import type { WithClassAsProps } from './interface'
|
import type { WithClassAsProps } from "./interface";
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from "@/lib/utils";
|
||||||
import { Button } from '@/components/ui/button'
|
import { Button } from "@/components/ui/button";
|
||||||
|
|
||||||
const props = defineProps<WithClassAsProps>()
|
const props = defineProps<WithClassAsProps>();
|
||||||
|
|
||||||
const { orientation, canScrollNext, scrollNext } = useCarousel()
|
const { orientation, canScrollNext, scrollNext } = useCarousel();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ArrowLeftIcon } from '@radix-icons/vue'
|
import { ArrowLeftIcon } from "@radix-icons/vue";
|
||||||
import { useCarousel } from './useCarousel'
|
import { useCarousel } from "./useCarousel";
|
||||||
import type { WithClassAsProps } from './interface'
|
import type { WithClassAsProps } from "./interface";
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from "@/lib/utils";
|
||||||
import { Button } from '@/components/ui/button'
|
import { Button } from "@/components/ui/button";
|
||||||
|
|
||||||
const props = defineProps<WithClassAsProps>()
|
const props = defineProps<WithClassAsProps>();
|
||||||
|
|
||||||
const { orientation, canScrollPrev, scrollPrev } = useCarousel()
|
const { orientation, canScrollPrev, scrollPrev } = useCarousel();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
export { default as Carousel } from './Carousel.vue'
|
export { default as Carousel } from "./Carousel.vue";
|
||||||
export { default as CarouselContent } from './CarouselContent.vue'
|
export { default as CarouselContent } from "./CarouselContent.vue";
|
||||||
export { default as CarouselItem } from './CarouselItem.vue'
|
export { default as CarouselItem } from "./CarouselItem.vue";
|
||||||
export { default as CarouselPrevious } from './CarouselPrevious.vue'
|
export { default as CarouselPrevious } from "./CarouselPrevious.vue";
|
||||||
export { default as CarouselNext } from './CarouselNext.vue'
|
export { default as CarouselNext } from "./CarouselNext.vue";
|
||||||
export { useCarousel } from './useCarousel'
|
export { useCarousel } from "./useCarousel";
|
||||||
|
|
||||||
export type {
|
export type { UnwrapRefCarouselApi as CarouselApi } from "./interface";
|
||||||
UnwrapRefCarouselApi as CarouselApi,
|
|
||||||
} from './interface'
|
|
||||||
|
|||||||
@@ -1,26 +1,24 @@
|
|||||||
import type { HTMLAttributes, UnwrapRef } from 'vue'
|
import type { HTMLAttributes, UnwrapRef } from "vue";
|
||||||
import type useEmblaCarousel from 'embla-carousel-vue'
|
import type useEmblaCarousel from "embla-carousel-vue";
|
||||||
import type {
|
import type { EmblaCarouselVueType } from "embla-carousel-vue";
|
||||||
EmblaCarouselVueType,
|
|
||||||
} from 'embla-carousel-vue'
|
|
||||||
|
|
||||||
type CarouselApi = EmblaCarouselVueType[1]
|
type CarouselApi = EmblaCarouselVueType[1];
|
||||||
type UseCarouselParameters = Parameters<typeof useEmblaCarousel>
|
type UseCarouselParameters = Parameters<typeof useEmblaCarousel>;
|
||||||
type CarouselOptions = UseCarouselParameters[0]
|
type CarouselOptions = UseCarouselParameters[0];
|
||||||
type CarouselPlugin = UseCarouselParameters[1]
|
type CarouselPlugin = UseCarouselParameters[1];
|
||||||
|
|
||||||
export type UnwrapRefCarouselApi = UnwrapRef<CarouselApi>
|
export type UnwrapRefCarouselApi = UnwrapRef<CarouselApi>;
|
||||||
|
|
||||||
export interface CarouselProps {
|
export interface CarouselProps {
|
||||||
opts?: CarouselOptions
|
opts?: CarouselOptions;
|
||||||
plugins?: CarouselPlugin
|
plugins?: CarouselPlugin;
|
||||||
orientation?: 'horizontal' | 'vertical'
|
orientation?: "horizontal" | "vertical";
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CarouselEmits {
|
export interface CarouselEmits {
|
||||||
(e: 'init-api', payload: UnwrapRefCarouselApi): void
|
(e: "init-api", payload: UnwrapRefCarouselApi): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface WithClassAsProps {
|
export interface WithClassAsProps {
|
||||||
class?: HTMLAttributes['class']
|
class?: HTMLAttributes["class"];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,56 +1,66 @@
|
|||||||
import { createInjectionState } from '@vueuse/core'
|
import { createInjectionState } from "@vueuse/core";
|
||||||
import emblaCarouselVue from 'embla-carousel-vue'
|
import emblaCarouselVue from "embla-carousel-vue";
|
||||||
import { onMounted, ref } from 'vue'
|
import { onMounted, ref } from "vue";
|
||||||
import type { UnwrapRefCarouselApi as CarouselApi, CarouselEmits, CarouselProps } from './interface'
|
import type {
|
||||||
|
UnwrapRefCarouselApi as CarouselApi,
|
||||||
|
CarouselEmits,
|
||||||
|
CarouselProps,
|
||||||
|
} from "./interface";
|
||||||
|
|
||||||
const [useProvideCarousel, useInjectCarousel] = createInjectionState(
|
const [useProvideCarousel, useInjectCarousel] = createInjectionState(
|
||||||
({
|
({ opts, orientation, plugins }: CarouselProps, emits: CarouselEmits) => {
|
||||||
opts,
|
const [emblaNode, emblaApi] = emblaCarouselVue(
|
||||||
orientation,
|
{
|
||||||
plugins,
|
...opts,
|
||||||
}: CarouselProps, emits: CarouselEmits) => {
|
axis: orientation === "horizontal" ? "x" : "y",
|
||||||
const [emblaNode, emblaApi] = emblaCarouselVue({
|
},
|
||||||
...opts,
|
plugins,
|
||||||
axis: orientation === 'horizontal' ? 'x' : 'y',
|
);
|
||||||
}, plugins)
|
|
||||||
|
|
||||||
function scrollPrev() {
|
function scrollPrev() {
|
||||||
emblaApi.value?.scrollPrev()
|
emblaApi.value?.scrollPrev();
|
||||||
}
|
}
|
||||||
function scrollNext() {
|
function scrollNext() {
|
||||||
emblaApi.value?.scrollNext()
|
emblaApi.value?.scrollNext();
|
||||||
}
|
}
|
||||||
|
|
||||||
const canScrollNext = ref(false)
|
const canScrollNext = ref(false);
|
||||||
const canScrollPrev = ref(false)
|
const canScrollPrev = ref(false);
|
||||||
|
|
||||||
function onSelect(api: CarouselApi) {
|
function onSelect(api: CarouselApi) {
|
||||||
canScrollNext.value = api?.canScrollNext() || false
|
canScrollNext.value = api?.canScrollNext() || false;
|
||||||
canScrollPrev.value = api?.canScrollPrev() || false
|
canScrollPrev.value = api?.canScrollPrev() || false;
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (!emblaApi.value)
|
if (!emblaApi.value) return;
|
||||||
return
|
|
||||||
|
|
||||||
emblaApi.value?.on('init', onSelect)
|
emblaApi.value?.on("init", onSelect);
|
||||||
emblaApi.value?.on('reInit', onSelect)
|
emblaApi.value?.on("reInit", onSelect);
|
||||||
emblaApi.value?.on('select', onSelect)
|
emblaApi.value?.on("select", onSelect);
|
||||||
|
|
||||||
emits('init-api', emblaApi.value)
|
emits("init-api", emblaApi.value);
|
||||||
})
|
});
|
||||||
|
|
||||||
return { carouselRef: emblaNode, carouselApi: emblaApi, canScrollPrev, canScrollNext, scrollPrev, scrollNext, orientation }
|
return {
|
||||||
},
|
carouselRef: emblaNode,
|
||||||
)
|
carouselApi: emblaApi,
|
||||||
|
canScrollPrev,
|
||||||
|
canScrollNext,
|
||||||
|
scrollPrev,
|
||||||
|
scrollNext,
|
||||||
|
orientation,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
function useCarousel() {
|
function useCarousel() {
|
||||||
const carouselState = useInjectCarousel()
|
const carouselState = useInjectCarousel();
|
||||||
|
|
||||||
if (!carouselState)
|
if (!carouselState)
|
||||||
throw new Error('useCarousel must be used within a <Carousel />')
|
throw new Error("useCarousel must be used within a <Carousel />");
|
||||||
|
|
||||||
return carouselState
|
return carouselState;
|
||||||
}
|
}
|
||||||
|
|
||||||
export { useCarousel, useProvideCarousel }
|
export { useCarousel, useProvideCarousel };
|
||||||
|
|||||||
@@ -1,62 +1,75 @@
|
|||||||
<script setup lang="ts" generic="T extends Record<string, any>">
|
<script setup lang="ts" generic="T extends Record<string, any>">
|
||||||
import { type BulletLegendItemInterface, CurveType } from '@unovis/ts'
|
import { type BulletLegendItemInterface, CurveType } from "@unovis/ts";
|
||||||
import { VisArea, VisAxis, VisLine, VisXYContainer } from '@unovis/vue'
|
import { VisArea, VisAxis, VisLine, VisXYContainer } from "@unovis/vue";
|
||||||
import { Area, Axis, Line } from '@unovis/ts'
|
import { Area, Axis, Line } from "@unovis/ts";
|
||||||
import { type Component, computed, ref } from 'vue'
|
import { type Component, computed, ref } from "vue";
|
||||||
import { useMounted } from '@vueuse/core'
|
import { useMounted } from "@vueuse/core";
|
||||||
import { useId } from 'radix-vue'
|
import { useId } from "radix-vue";
|
||||||
import type { BaseChartProps } from '.'
|
import type { BaseChartProps } from ".";
|
||||||
import { ChartCrosshair, ChartLegend, defaultColors } from '@/components/ui/chart'
|
import {
|
||||||
import { cn } from '@/lib/utils'
|
ChartCrosshair,
|
||||||
|
ChartLegend,
|
||||||
|
defaultColors,
|
||||||
|
} from "@/components/ui/chart";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const props = withDefaults(defineProps<BaseChartProps<T> & {
|
const props = withDefaults(
|
||||||
/**
|
defineProps<
|
||||||
* Render custom tooltip component.
|
BaseChartProps<T> & {
|
||||||
*/
|
/**
|
||||||
customTooltip?: Component
|
* Render custom tooltip component.
|
||||||
/**
|
*/
|
||||||
* Type of curve
|
customTooltip?: Component;
|
||||||
*/
|
/**
|
||||||
curveType?: CurveType
|
* Type of curve
|
||||||
/**
|
*/
|
||||||
* Controls the visibility of gradient.
|
curveType?: CurveType;
|
||||||
* @default true
|
/**
|
||||||
*/
|
* Controls the visibility of gradient.
|
||||||
showGradiant?: boolean
|
* @default true
|
||||||
}>(), {
|
*/
|
||||||
curveType: CurveType.MonotoneX,
|
showGradiant?: boolean;
|
||||||
filterOpacity: 0.2,
|
}
|
||||||
margin: () => ({ top: 0, bottom: 0, left: 0, right: 0 }),
|
>(),
|
||||||
showXAxis: true,
|
{
|
||||||
showYAxis: true,
|
curveType: CurveType.MonotoneX,
|
||||||
showTooltip: true,
|
filterOpacity: 0.2,
|
||||||
showLegend: true,
|
margin: () => ({ top: 0, bottom: 0, left: 0, right: 0 }),
|
||||||
showGridLine: true,
|
showXAxis: true,
|
||||||
showGradiant: true,
|
showYAxis: true,
|
||||||
})
|
showTooltip: true,
|
||||||
|
showLegend: true,
|
||||||
|
showGridLine: true,
|
||||||
|
showGradiant: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
const emits = defineEmits<{
|
const emits = defineEmits<{
|
||||||
legendItemClick: [d: BulletLegendItemInterface, i: number]
|
legendItemClick: [d: BulletLegendItemInterface, i: number];
|
||||||
}>()
|
}>();
|
||||||
|
|
||||||
type KeyOfT = Extract<keyof T, string>
|
type KeyOfT = Extract<keyof T, string>;
|
||||||
type Data = typeof props.data[number]
|
type Data = (typeof props.data)[number];
|
||||||
|
|
||||||
const chartRef = useId()
|
const chartRef = useId();
|
||||||
|
|
||||||
const index = computed(() => props.index as KeyOfT)
|
const index = computed(() => props.index as KeyOfT);
|
||||||
const colors = computed(() => props.colors?.length ? props.colors : defaultColors(props.categories.length))
|
const colors = computed(() =>
|
||||||
|
props.colors?.length ? props.colors : defaultColors(props.categories.length),
|
||||||
|
);
|
||||||
|
|
||||||
const legendItems = ref<BulletLegendItemInterface[]>(props.categories.map((category, i) => ({
|
const legendItems = ref<BulletLegendItemInterface[]>(
|
||||||
name: category,
|
props.categories.map((category, i) => ({
|
||||||
color: colors.value[i],
|
name: category,
|
||||||
inactive: false,
|
color: colors.value[i],
|
||||||
})))
|
inactive: false,
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
|
||||||
const isMounted = useMounted()
|
const isMounted = useMounted();
|
||||||
|
|
||||||
function handleLegendItemClick(d: BulletLegendItemInterface, i: number) {
|
function handleLegendItemClick(d: BulletLegendItemInterface, i: number) {
|
||||||
emits('legendItemClick', d, i)
|
emits("legendItemClick", d, i);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,66 +1,74 @@
|
|||||||
export { default as AreaChart } from './AreaChart.vue'
|
export { default as AreaChart } from "./AreaChart.vue";
|
||||||
|
|
||||||
import type { Spacing } from '@unovis/ts'
|
import type { Spacing } from "@unovis/ts";
|
||||||
|
|
||||||
type KeyOf<T extends Record<string, any>> = Extract<keyof T, string>
|
type KeyOf<T extends Record<string, any>> = Extract<keyof T, string>;
|
||||||
|
|
||||||
export interface BaseChartProps<T extends Record<string, any>> {
|
export interface BaseChartProps<T extends Record<string, any>> {
|
||||||
/**
|
/**
|
||||||
* The source data, in which each entry is a dictionary.
|
* The source data, in which each entry is a dictionary.
|
||||||
*/
|
*/
|
||||||
data: T[]
|
data: T[];
|
||||||
/**
|
/**
|
||||||
* Select the categories from your data. Used to populate the legend and toolip.
|
* Select the categories from your data. Used to populate the legend and toolip.
|
||||||
*/
|
*/
|
||||||
categories: KeyOf<T>[]
|
categories: KeyOf<T>[];
|
||||||
/**
|
/**
|
||||||
* Sets the key to map the data to the axis.
|
* Sets the key to map the data to the axis.
|
||||||
*/
|
*/
|
||||||
index: KeyOf<T>
|
index: KeyOf<T>;
|
||||||
/**
|
/**
|
||||||
* Change the default colors.
|
* Change the default colors.
|
||||||
*/
|
*/
|
||||||
colors?: string[]
|
colors?: string[];
|
||||||
/**
|
/**
|
||||||
* Margin of each the container
|
* Margin of each the container
|
||||||
*/
|
*/
|
||||||
margin?: Spacing
|
margin?: Spacing;
|
||||||
/**
|
/**
|
||||||
* Change the opacity of the non-selected field
|
* Change the opacity of the non-selected field
|
||||||
* @default 0.2
|
* @default 0.2
|
||||||
*/
|
*/
|
||||||
filterOpacity?: number
|
filterOpacity?: number;
|
||||||
/**
|
/**
|
||||||
* Function to format X label
|
* Function to format X label
|
||||||
*/
|
*/
|
||||||
xFormatter?: (tick: number | Date, i: number, ticks: number[] | Date[]) => string
|
xFormatter?: (
|
||||||
/**
|
tick: number | Date,
|
||||||
* Function to format Y label
|
i: number,
|
||||||
*/
|
ticks: number[] | Date[],
|
||||||
yFormatter?: (tick: number | Date, i: number, ticks: number[] | Date[]) => string
|
) => string;
|
||||||
/**
|
/**
|
||||||
* Controls the visibility of the X axis.
|
* Function to format Y label
|
||||||
* @default true
|
*/
|
||||||
*/
|
yFormatter?: (
|
||||||
showXAxis?: boolean
|
tick: number | Date,
|
||||||
/**
|
i: number,
|
||||||
* Controls the visibility of the Y axis.
|
ticks: number[] | Date[],
|
||||||
* @default true
|
) => string;
|
||||||
*/
|
/**
|
||||||
showYAxis?: boolean
|
* Controls the visibility of the X axis.
|
||||||
/**
|
* @default true
|
||||||
* Controls the visibility of tooltip.
|
*/
|
||||||
* @default true
|
showXAxis?: boolean;
|
||||||
*/
|
/**
|
||||||
showTooltip?: boolean
|
* Controls the visibility of the Y axis.
|
||||||
/**
|
* @default true
|
||||||
* Controls the visibility of legend.
|
*/
|
||||||
* @default true
|
showYAxis?: boolean;
|
||||||
*/
|
/**
|
||||||
showLegend?: boolean
|
* Controls the visibility of tooltip.
|
||||||
/**
|
* @default true
|
||||||
* Controls the visibility of gridline.
|
*/
|
||||||
* @default true
|
showTooltip?: boolean;
|
||||||
*/
|
/**
|
||||||
showGridLine?: boolean
|
* Controls the visibility of legend.
|
||||||
|
* @default true
|
||||||
|
*/
|
||||||
|
showLegend?: boolean;
|
||||||
|
/**
|
||||||
|
* Controls the visibility of gridline.
|
||||||
|
* @default true
|
||||||
|
*/
|
||||||
|
showGridLine?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,62 +1,86 @@
|
|||||||
<script setup lang="ts" generic="T extends Record<string, any>">
|
<script setup lang="ts" generic="T extends Record<string, any>">
|
||||||
import type { BulletLegendItemInterface } from '@unovis/ts'
|
import type { BulletLegendItemInterface } from "@unovis/ts";
|
||||||
import { VisAxis, VisGroupedBar, VisStackedBar, VisXYContainer } from '@unovis/vue'
|
import {
|
||||||
import { Axis, GroupedBar, StackedBar } from '@unovis/ts'
|
VisAxis,
|
||||||
import { type Component, computed, ref } from 'vue'
|
VisGroupedBar,
|
||||||
import { useMounted } from '@vueuse/core'
|
VisStackedBar,
|
||||||
import type { BaseChartProps } from '.'
|
VisXYContainer,
|
||||||
import { ChartCrosshair, ChartLegend, defaultColors } from '@/components/ui/chart'
|
} from "@unovis/vue";
|
||||||
import { cn } from '@/lib/utils'
|
import { Axis, GroupedBar, StackedBar } from "@unovis/ts";
|
||||||
|
import { type Component, computed, ref } from "vue";
|
||||||
|
import { useMounted } from "@vueuse/core";
|
||||||
|
import type { BaseChartProps } from ".";
|
||||||
|
import {
|
||||||
|
ChartCrosshair,
|
||||||
|
ChartLegend,
|
||||||
|
defaultColors,
|
||||||
|
} from "@/components/ui/chart";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const props = withDefaults(defineProps<BaseChartProps<T> & {
|
const props = withDefaults(
|
||||||
/**
|
defineProps<
|
||||||
* Render custom tooltip component.
|
BaseChartProps<T> & {
|
||||||
*/
|
/**
|
||||||
customTooltip?: Component
|
* Render custom tooltip component.
|
||||||
/**
|
*/
|
||||||
* Change the type of the chart
|
customTooltip?: Component;
|
||||||
* @default "grouped"
|
/**
|
||||||
*/
|
* Change the type of the chart
|
||||||
type?: 'stacked' | 'grouped'
|
* @default "grouped"
|
||||||
/**
|
*/
|
||||||
* Rounded bar corners
|
type?: "stacked" | "grouped";
|
||||||
* @default 0
|
/**
|
||||||
*/
|
* Rounded bar corners
|
||||||
roundedCorners?: number
|
* @default 0
|
||||||
}>(), {
|
*/
|
||||||
type: 'grouped',
|
roundedCorners?: number;
|
||||||
margin: () => ({ top: 0, bottom: 0, left: 0, right: 0 }),
|
}
|
||||||
filterOpacity: 0.2,
|
>(),
|
||||||
roundedCorners: 0,
|
{
|
||||||
showXAxis: true,
|
type: "grouped",
|
||||||
showYAxis: true,
|
margin: () => ({ top: 0, bottom: 0, left: 0, right: 0 }),
|
||||||
showTooltip: true,
|
filterOpacity: 0.2,
|
||||||
showLegend: true,
|
roundedCorners: 0,
|
||||||
showGridLine: true,
|
showXAxis: true,
|
||||||
})
|
showYAxis: true,
|
||||||
|
showTooltip: true,
|
||||||
|
showLegend: true,
|
||||||
|
showGridLine: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
const emits = defineEmits<{
|
const emits = defineEmits<{
|
||||||
legendItemClick: [d: BulletLegendItemInterface, i: number]
|
legendItemClick: [d: BulletLegendItemInterface, i: number];
|
||||||
}>()
|
}>();
|
||||||
|
|
||||||
type KeyOfT = Extract<keyof T, string>
|
type KeyOfT = Extract<keyof T, string>;
|
||||||
type Data = typeof props.data[number]
|
type Data = (typeof props.data)[number];
|
||||||
|
|
||||||
const index = computed(() => props.index as KeyOfT)
|
const index = computed(() => props.index as KeyOfT);
|
||||||
const colors = computed(() => props.colors?.length ? props.colors : defaultColors(props.categories.length))
|
const colors = computed(() =>
|
||||||
const legendItems = ref<BulletLegendItemInterface[]>(props.categories.map((category, i) => ({
|
props.colors?.length ? props.colors : defaultColors(props.categories.length),
|
||||||
name: category,
|
);
|
||||||
color: colors.value[i],
|
const legendItems = ref<BulletLegendItemInterface[]>(
|
||||||
inactive: false,
|
props.categories.map((category, i) => ({
|
||||||
})))
|
name: category,
|
||||||
|
color: colors.value[i],
|
||||||
|
inactive: false,
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
|
||||||
const isMounted = useMounted()
|
const isMounted = useMounted();
|
||||||
|
|
||||||
function handleLegendItemClick(d: BulletLegendItemInterface, i: number) {
|
function handleLegendItemClick(d: BulletLegendItemInterface, i: number) {
|
||||||
emits('legendItemClick', d, i)
|
emits("legendItemClick", d, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
const VisBarComponent = computed(() => props.type === 'grouped' ? VisGroupedBar : VisStackedBar)
|
const VisBarComponent = computed(() =>
|
||||||
const selectorsBar = computed(() => props.type === 'grouped' ? GroupedBar.selectors.bar : StackedBar.selectors.bar)
|
props.type === "grouped" ? VisGroupedBar : VisStackedBar,
|
||||||
|
);
|
||||||
|
const selectorsBar = computed(() =>
|
||||||
|
props.type === "grouped"
|
||||||
|
? GroupedBar.selectors.bar
|
||||||
|
: StackedBar.selectors.bar,
|
||||||
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,66 +1,74 @@
|
|||||||
export { default as BarChart } from './BarChart.vue'
|
export { default as BarChart } from "./BarChart.vue";
|
||||||
|
|
||||||
import type { Spacing } from '@unovis/ts'
|
import type { Spacing } from "@unovis/ts";
|
||||||
|
|
||||||
type KeyOf<T extends Record<string, any>> = Extract<keyof T, string>
|
type KeyOf<T extends Record<string, any>> = Extract<keyof T, string>;
|
||||||
|
|
||||||
export interface BaseChartProps<T extends Record<string, any>> {
|
export interface BaseChartProps<T extends Record<string, any>> {
|
||||||
/**
|
/**
|
||||||
* The source data, in which each entry is a dictionary.
|
* The source data, in which each entry is a dictionary.
|
||||||
*/
|
*/
|
||||||
data: T[]
|
data: T[];
|
||||||
/**
|
/**
|
||||||
* Select the categories from your data. Used to populate the legend and toolip.
|
* Select the categories from your data. Used to populate the legend and toolip.
|
||||||
*/
|
*/
|
||||||
categories: KeyOf<T>[]
|
categories: KeyOf<T>[];
|
||||||
/**
|
/**
|
||||||
* Sets the key to map the data to the axis.
|
* Sets the key to map the data to the axis.
|
||||||
*/
|
*/
|
||||||
index: KeyOf<T>
|
index: KeyOf<T>;
|
||||||
/**
|
/**
|
||||||
* Change the default colors.
|
* Change the default colors.
|
||||||
*/
|
*/
|
||||||
colors?: string[]
|
colors?: string[];
|
||||||
/**
|
/**
|
||||||
* Margin of each the container
|
* Margin of each the container
|
||||||
*/
|
*/
|
||||||
margin?: Spacing
|
margin?: Spacing;
|
||||||
/**
|
/**
|
||||||
* Change the opacity of the non-selected field
|
* Change the opacity of the non-selected field
|
||||||
* @default 0.2
|
* @default 0.2
|
||||||
*/
|
*/
|
||||||
filterOpacity?: number
|
filterOpacity?: number;
|
||||||
/**
|
/**
|
||||||
* Function to format X label
|
* Function to format X label
|
||||||
*/
|
*/
|
||||||
xFormatter?: (tick: number | Date, i: number, ticks: number[] | Date[]) => string
|
xFormatter?: (
|
||||||
/**
|
tick: number | Date,
|
||||||
* Function to format Y label
|
i: number,
|
||||||
*/
|
ticks: number[] | Date[],
|
||||||
yFormatter?: (tick: number | Date, i: number, ticks: number[] | Date[]) => string
|
) => string;
|
||||||
/**
|
/**
|
||||||
* Controls the visibility of the X axis.
|
* Function to format Y label
|
||||||
* @default true
|
*/
|
||||||
*/
|
yFormatter?: (
|
||||||
showXAxis?: boolean
|
tick: number | Date,
|
||||||
/**
|
i: number,
|
||||||
* Controls the visibility of the Y axis.
|
ticks: number[] | Date[],
|
||||||
* @default true
|
) => string;
|
||||||
*/
|
/**
|
||||||
showYAxis?: boolean
|
* Controls the visibility of the X axis.
|
||||||
/**
|
* @default true
|
||||||
* Controls the visibility of tooltip.
|
*/
|
||||||
* @default true
|
showXAxis?: boolean;
|
||||||
*/
|
/**
|
||||||
showTooltip?: boolean
|
* Controls the visibility of the Y axis.
|
||||||
/**
|
* @default true
|
||||||
* Controls the visibility of legend.
|
*/
|
||||||
* @default true
|
showYAxis?: boolean;
|
||||||
*/
|
/**
|
||||||
showLegend?: boolean
|
* Controls the visibility of tooltip.
|
||||||
/**
|
* @default true
|
||||||
* Controls the visibility of gridline.
|
*/
|
||||||
* @default true
|
showTooltip?: boolean;
|
||||||
*/
|
/**
|
||||||
showGridLine?: boolean
|
* Controls the visibility of legend.
|
||||||
|
* @default true
|
||||||
|
*/
|
||||||
|
showLegend?: boolean;
|
||||||
|
/**
|
||||||
|
* Controls the visibility of gridline.
|
||||||
|
* @default true
|
||||||
|
*/
|
||||||
|
showGridLine?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,62 +1,86 @@
|
|||||||
<script setup lang="ts" generic="T extends Record<string, any>">
|
<script setup lang="ts" generic="T extends Record<string, any>">
|
||||||
import { VisDonut, VisSingleContainer } from '@unovis/vue'
|
import { VisDonut, VisSingleContainer } from "@unovis/vue";
|
||||||
import { Donut } from '@unovis/ts'
|
import { Donut } from "@unovis/ts";
|
||||||
import { type Component, computed, ref } from 'vue'
|
import { type Component, computed, ref } from "vue";
|
||||||
import { useMounted } from '@vueuse/core'
|
import { useMounted } from "@vueuse/core";
|
||||||
import type { BaseChartProps } from '.'
|
import type { BaseChartProps } from ".";
|
||||||
import { ChartSingleTooltip, defaultColors } from '@/components/ui/chart'
|
import { ChartSingleTooltip, defaultColors } from "@/components/ui/chart";
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Pick<BaseChartProps<T>, 'data' | 'colors' | 'index' | 'margin' | 'showLegend' | 'showTooltip' | 'filterOpacity'> & {
|
const props = withDefaults(
|
||||||
/**
|
defineProps<
|
||||||
* Sets the name of the key containing the quantitative chart values.
|
Pick<
|
||||||
*/
|
BaseChartProps<T>,
|
||||||
category: KeyOfT
|
| "data"
|
||||||
/**
|
| "colors"
|
||||||
* Change the type of the chart
|
| "index"
|
||||||
* @default "donut"
|
| "margin"
|
||||||
*/
|
| "showLegend"
|
||||||
type?: 'donut' | 'pie'
|
| "showTooltip"
|
||||||
/**
|
| "filterOpacity"
|
||||||
* Function to sort the segment
|
> & {
|
||||||
*/
|
/**
|
||||||
sortFunction?: (a: any, b: any) => number | undefined
|
* Sets the name of the key containing the quantitative chart values.
|
||||||
/**
|
*/
|
||||||
* Controls the formatting for the label.
|
category: KeyOfT;
|
||||||
*/
|
/**
|
||||||
valueFormatter?: (tick: number, i?: number, ticks?: number[]) => string
|
* Change the type of the chart
|
||||||
/**
|
* @default "donut"
|
||||||
* Render custom tooltip component.
|
*/
|
||||||
*/
|
type?: "donut" | "pie";
|
||||||
customTooltip?: Component
|
/**
|
||||||
}>(), {
|
* Function to sort the segment
|
||||||
margin: () => ({ top: 0, bottom: 0, left: 0, right: 0 }),
|
*/
|
||||||
sortFunction: () => undefined,
|
sortFunction?: (a: any, b: any) => number | undefined;
|
||||||
valueFormatter: (tick: number) => `${tick}`,
|
/**
|
||||||
type: 'donut',
|
* Controls the formatting for the label.
|
||||||
filterOpacity: 0.2,
|
*/
|
||||||
showTooltip: true,
|
valueFormatter?: (tick: number, i?: number, ticks?: number[]) => string;
|
||||||
showLegend: true,
|
/**
|
||||||
})
|
* Render custom tooltip component.
|
||||||
|
*/
|
||||||
|
customTooltip?: Component;
|
||||||
|
}
|
||||||
|
>(),
|
||||||
|
{
|
||||||
|
margin: () => ({ top: 0, bottom: 0, left: 0, right: 0 }),
|
||||||
|
sortFunction: () => undefined,
|
||||||
|
valueFormatter: (tick: number) => `${tick}`,
|
||||||
|
type: "donut",
|
||||||
|
filterOpacity: 0.2,
|
||||||
|
showTooltip: true,
|
||||||
|
showLegend: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
type KeyOfT = Extract<keyof T, string>
|
type KeyOfT = Extract<keyof T, string>;
|
||||||
type Data = typeof props.data[number]
|
type Data = (typeof props.data)[number];
|
||||||
|
|
||||||
const category = computed(() => props.category as KeyOfT)
|
const category = computed(() => props.category as KeyOfT);
|
||||||
const index = computed(() => props.index as KeyOfT)
|
const index = computed(() => props.index as KeyOfT);
|
||||||
|
|
||||||
const isMounted = useMounted()
|
const isMounted = useMounted();
|
||||||
const activeSegmentKey = ref<string>()
|
const activeSegmentKey = ref<string>();
|
||||||
const colors = computed(() => props.colors?.length ? props.colors : defaultColors(props.data.filter(d => d[props.category]).filter(Boolean).length))
|
const colors = computed(() =>
|
||||||
const legendItems = computed(() => props.data.map((item, i) => ({
|
props.colors?.length
|
||||||
name: item[props.index],
|
? props.colors
|
||||||
color: colors.value[i],
|
: defaultColors(
|
||||||
inactive: false,
|
props.data.filter((d) => d[props.category]).filter(Boolean).length,
|
||||||
})))
|
),
|
||||||
|
);
|
||||||
|
const legendItems = computed(() =>
|
||||||
|
props.data.map((item, i) => ({
|
||||||
|
name: item[props.index],
|
||||||
|
color: colors.value[i],
|
||||||
|
inactive: false,
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
|
||||||
const totalValue = computed(() => props.data.reduce((prev, curr) => {
|
const totalValue = computed(() =>
|
||||||
return prev + curr[props.category]
|
props.data.reduce((prev, curr) => {
|
||||||
}, 0))
|
return prev + curr[props.category];
|
||||||
|
}, 0),
|
||||||
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,39 +1,39 @@
|
|||||||
export { default as DonutChart } from './DonutChart.vue'
|
export { default as DonutChart } from "./DonutChart.vue";
|
||||||
|
|
||||||
import type { Spacing } from '@unovis/ts'
|
import type { Spacing } from "@unovis/ts";
|
||||||
|
|
||||||
type KeyOf<T extends Record<string, any>> = Extract<keyof T, string>
|
type KeyOf<T extends Record<string, any>> = Extract<keyof T, string>;
|
||||||
|
|
||||||
export interface BaseChartProps<T extends Record<string, any>> {
|
export interface BaseChartProps<T extends Record<string, any>> {
|
||||||
/**
|
/**
|
||||||
* The source data, in which each entry is a dictionary.
|
* The source data, in which each entry is a dictionary.
|
||||||
*/
|
*/
|
||||||
data: T[]
|
data: T[];
|
||||||
/**
|
/**
|
||||||
* Sets the key to map the data to the axis.
|
* Sets the key to map the data to the axis.
|
||||||
*/
|
*/
|
||||||
index: KeyOf<T>
|
index: KeyOf<T>;
|
||||||
/**
|
/**
|
||||||
* Change the default colors.
|
* Change the default colors.
|
||||||
*/
|
*/
|
||||||
colors?: string[]
|
colors?: string[];
|
||||||
/**
|
/**
|
||||||
* Margin of each the container
|
* Margin of each the container
|
||||||
*/
|
*/
|
||||||
margin?: Spacing
|
margin?: Spacing;
|
||||||
/**
|
/**
|
||||||
* Change the opacity of the non-selected field
|
* Change the opacity of the non-selected field
|
||||||
* @default 0.2
|
* @default 0.2
|
||||||
*/
|
*/
|
||||||
filterOpacity?: number
|
filterOpacity?: number;
|
||||||
/**
|
/**
|
||||||
* Controls the visibility of tooltip.
|
* Controls the visibility of tooltip.
|
||||||
* @default true
|
* @default true
|
||||||
*/
|
*/
|
||||||
showTooltip?: boolean
|
showTooltip?: boolean;
|
||||||
/**
|
/**
|
||||||
* Controls the visibility of legend.
|
* Controls the visibility of legend.
|
||||||
* @default true
|
* @default true
|
||||||
*/
|
*/
|
||||||
showLegend?: boolean
|
showLegend?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,53 +1,66 @@
|
|||||||
<script setup lang="ts" generic="T extends Record<string, any>">
|
<script setup lang="ts" generic="T extends Record<string, any>">
|
||||||
import { type BulletLegendItemInterface, CurveType } from '@unovis/ts'
|
import { type BulletLegendItemInterface, CurveType } from "@unovis/ts";
|
||||||
import { VisAxis, VisLine, VisXYContainer } from '@unovis/vue'
|
import { VisAxis, VisLine, VisXYContainer } from "@unovis/vue";
|
||||||
import { Axis, Line } from '@unovis/ts'
|
import { Axis, Line } from "@unovis/ts";
|
||||||
import { type Component, computed, ref } from 'vue'
|
import { type Component, computed, ref } from "vue";
|
||||||
import { useMounted } from '@vueuse/core'
|
import { useMounted } from "@vueuse/core";
|
||||||
import type { BaseChartProps } from '.'
|
import type { BaseChartProps } from ".";
|
||||||
import { ChartCrosshair, ChartLegend, defaultColors } from '@/components/ui/chart'
|
import {
|
||||||
import { cn } from '@/lib/utils'
|
ChartCrosshair,
|
||||||
|
ChartLegend,
|
||||||
|
defaultColors,
|
||||||
|
} from "@/components/ui/chart";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const props = withDefaults(defineProps<BaseChartProps<T> & {
|
const props = withDefaults(
|
||||||
/**
|
defineProps<
|
||||||
* Render custom tooltip component.
|
BaseChartProps<T> & {
|
||||||
*/
|
/**
|
||||||
customTooltip?: Component
|
* Render custom tooltip component.
|
||||||
/**
|
*/
|
||||||
* Type of curve
|
customTooltip?: Component;
|
||||||
*/
|
/**
|
||||||
curveType?: CurveType
|
* Type of curve
|
||||||
}>(), {
|
*/
|
||||||
curveType: CurveType.MonotoneX,
|
curveType?: CurveType;
|
||||||
filterOpacity: 0.2,
|
}
|
||||||
margin: () => ({ top: 0, bottom: 0, left: 0, right: 0 }),
|
>(),
|
||||||
showXAxis: true,
|
{
|
||||||
showYAxis: true,
|
curveType: CurveType.MonotoneX,
|
||||||
showTooltip: true,
|
filterOpacity: 0.2,
|
||||||
showLegend: true,
|
margin: () => ({ top: 0, bottom: 0, left: 0, right: 0 }),
|
||||||
showGridLine: true,
|
showXAxis: true,
|
||||||
})
|
showYAxis: true,
|
||||||
|
showTooltip: true,
|
||||||
|
showLegend: true,
|
||||||
|
showGridLine: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
const emits = defineEmits<{
|
const emits = defineEmits<{
|
||||||
legendItemClick: [d: BulletLegendItemInterface, i: number]
|
legendItemClick: [d: BulletLegendItemInterface, i: number];
|
||||||
}>()
|
}>();
|
||||||
|
|
||||||
type KeyOfT = Extract<keyof T, string>
|
type KeyOfT = Extract<keyof T, string>;
|
||||||
type Data = typeof props.data[number]
|
type Data = (typeof props.data)[number];
|
||||||
|
|
||||||
const index = computed(() => props.index as KeyOfT)
|
const index = computed(() => props.index as KeyOfT);
|
||||||
const colors = computed(() => props.colors?.length ? props.colors : defaultColors(props.categories.length))
|
const colors = computed(() =>
|
||||||
|
props.colors?.length ? props.colors : defaultColors(props.categories.length),
|
||||||
|
);
|
||||||
|
|
||||||
const legendItems = ref<BulletLegendItemInterface[]>(props.categories.map((category, i) => ({
|
const legendItems = ref<BulletLegendItemInterface[]>(
|
||||||
name: category,
|
props.categories.map((category, i) => ({
|
||||||
color: colors.value[i],
|
name: category,
|
||||||
inactive: false,
|
color: colors.value[i],
|
||||||
})))
|
inactive: false,
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
|
||||||
const isMounted = useMounted()
|
const isMounted = useMounted();
|
||||||
|
|
||||||
function handleLegendItemClick(d: BulletLegendItemInterface, i: number) {
|
function handleLegendItemClick(d: BulletLegendItemInterface, i: number) {
|
||||||
emits('legendItemClick', d, i)
|
emits("legendItemClick", d, i);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,66 +1,74 @@
|
|||||||
export { default as LineChart } from './LineChart.vue'
|
export { default as LineChart } from "./LineChart.vue";
|
||||||
|
|
||||||
import type { Spacing } from '@unovis/ts'
|
import type { Spacing } from "@unovis/ts";
|
||||||
|
|
||||||
type KeyOf<T extends Record<string, any>> = Extract<keyof T, string>
|
type KeyOf<T extends Record<string, any>> = Extract<keyof T, string>;
|
||||||
|
|
||||||
export interface BaseChartProps<T extends Record<string, any>> {
|
export interface BaseChartProps<T extends Record<string, any>> {
|
||||||
/**
|
/**
|
||||||
* The source data, in which each entry is a dictionary.
|
* The source data, in which each entry is a dictionary.
|
||||||
*/
|
*/
|
||||||
data: T[]
|
data: T[];
|
||||||
/**
|
/**
|
||||||
* Select the categories from your data. Used to populate the legend and toolip.
|
* Select the categories from your data. Used to populate the legend and toolip.
|
||||||
*/
|
*/
|
||||||
categories: KeyOf<T>[]
|
categories: KeyOf<T>[];
|
||||||
/**
|
/**
|
||||||
* Sets the key to map the data to the axis.
|
* Sets the key to map the data to the axis.
|
||||||
*/
|
*/
|
||||||
index: KeyOf<T>
|
index: KeyOf<T>;
|
||||||
/**
|
/**
|
||||||
* Change the default colors.
|
* Change the default colors.
|
||||||
*/
|
*/
|
||||||
colors?: string[]
|
colors?: string[];
|
||||||
/**
|
/**
|
||||||
* Margin of each the container
|
* Margin of each the container
|
||||||
*/
|
*/
|
||||||
margin?: Spacing
|
margin?: Spacing;
|
||||||
/**
|
/**
|
||||||
* Change the opacity of the non-selected field
|
* Change the opacity of the non-selected field
|
||||||
* @default 0.2
|
* @default 0.2
|
||||||
*/
|
*/
|
||||||
filterOpacity?: number
|
filterOpacity?: number;
|
||||||
/**
|
/**
|
||||||
* Function to format X label
|
* Function to format X label
|
||||||
*/
|
*/
|
||||||
xFormatter?: (tick: number | Date, i: number, ticks: number[] | Date[]) => string
|
xFormatter?: (
|
||||||
/**
|
tick: number | Date,
|
||||||
* Function to format Y label
|
i: number,
|
||||||
*/
|
ticks: number[] | Date[],
|
||||||
yFormatter?: (tick: number | Date, i: number, ticks: number[] | Date[]) => string
|
) => string;
|
||||||
/**
|
/**
|
||||||
* Controls the visibility of the X axis.
|
* Function to format Y label
|
||||||
* @default true
|
*/
|
||||||
*/
|
yFormatter?: (
|
||||||
showXAxis?: boolean
|
tick: number | Date,
|
||||||
/**
|
i: number,
|
||||||
* Controls the visibility of the Y axis.
|
ticks: number[] | Date[],
|
||||||
* @default true
|
) => string;
|
||||||
*/
|
/**
|
||||||
showYAxis?: boolean
|
* Controls the visibility of the X axis.
|
||||||
/**
|
* @default true
|
||||||
* Controls the visibility of tooltip.
|
*/
|
||||||
* @default true
|
showXAxis?: boolean;
|
||||||
*/
|
/**
|
||||||
showTooltip?: boolean
|
* Controls the visibility of the Y axis.
|
||||||
/**
|
* @default true
|
||||||
* Controls the visibility of legend.
|
*/
|
||||||
* @default true
|
showYAxis?: boolean;
|
||||||
*/
|
/**
|
||||||
showLegend?: boolean
|
* Controls the visibility of tooltip.
|
||||||
/**
|
* @default true
|
||||||
* Controls the visibility of gridline.
|
*/
|
||||||
* @default true
|
showTooltip?: boolean;
|
||||||
*/
|
/**
|
||||||
showGridLine?: boolean
|
* Controls the visibility of legend.
|
||||||
|
* @default true
|
||||||
|
*/
|
||||||
|
showLegend?: boolean;
|
||||||
|
/**
|
||||||
|
* Controls the visibility of gridline.
|
||||||
|
* @default true
|
||||||
|
*/
|
||||||
|
showGridLine?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,40 +1,47 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { VisCrosshair, VisTooltip } from '@unovis/vue'
|
import { VisCrosshair, VisTooltip } from "@unovis/vue";
|
||||||
import type { BulletLegendItemInterface } from '@unovis/ts'
|
import type { BulletLegendItemInterface } from "@unovis/ts";
|
||||||
import { omit } from '@unovis/ts'
|
import { omit } from "@unovis/ts";
|
||||||
import { type Component, createApp } from 'vue'
|
import { type Component, createApp } from "vue";
|
||||||
import { ChartTooltip } from '.'
|
import { ChartTooltip } from ".";
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(
|
||||||
colors: string[]
|
defineProps<{
|
||||||
index: string
|
colors: string[];
|
||||||
items: BulletLegendItemInterface[]
|
index: string;
|
||||||
customTooltip?: Component
|
items: BulletLegendItemInterface[];
|
||||||
}>(), {
|
customTooltip?: Component;
|
||||||
colors: () => [],
|
}>(),
|
||||||
})
|
{
|
||||||
|
colors: () => [],
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
// Use weakmap to store reference to each datapoint for Tooltip
|
// Use weakmap to store reference to each datapoint for Tooltip
|
||||||
const wm = new WeakMap()
|
const wm = new WeakMap();
|
||||||
function template(d: any) {
|
function template(d: any) {
|
||||||
if (wm.has(d)) {
|
if (wm.has(d)) {
|
||||||
return wm.get(d)
|
return wm.get(d);
|
||||||
}
|
} else {
|
||||||
else {
|
const componentDiv = document.createElement("div");
|
||||||
const componentDiv = document.createElement('div')
|
const omittedData = Object.entries(omit(d, [props.index])).map(
|
||||||
const omittedData = Object.entries(omit(d, [props.index])).map(([key, value]) => {
|
([key, value]) => {
|
||||||
const legendReference = props.items.find(i => i.name === key)
|
const legendReference = props.items.find((i) => i.name === key);
|
||||||
return { ...legendReference, value }
|
return { ...legendReference, value };
|
||||||
})
|
},
|
||||||
const TooltipComponent = props.customTooltip ?? ChartTooltip
|
);
|
||||||
createApp(TooltipComponent, { title: d[props.index].toString(), data: omittedData }).mount(componentDiv)
|
const TooltipComponent = props.customTooltip ?? ChartTooltip;
|
||||||
wm.set(d, componentDiv.innerHTML)
|
createApp(TooltipComponent, {
|
||||||
return componentDiv.innerHTML
|
title: d[props.index].toString(),
|
||||||
}
|
data: omittedData,
|
||||||
|
}).mount(componentDiv);
|
||||||
|
wm.set(d, componentDiv.innerHTML);
|
||||||
|
return componentDiv.innerHTML;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function color(d: unknown, i: number) {
|
function color(d: unknown, i: number) {
|
||||||
return props.colors[i] ?? 'transparent'
|
return props.colors[i] ?? "transparent";
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,43 +1,57 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { VisBulletLegend } from '@unovis/vue'
|
import { VisBulletLegend } from "@unovis/vue";
|
||||||
import type { BulletLegendItemInterface } from '@unovis/ts'
|
import type { BulletLegendItemInterface } from "@unovis/ts";
|
||||||
import { BulletLegend } from '@unovis/ts'
|
import { BulletLegend } from "@unovis/ts";
|
||||||
import { nextTick, onMounted, ref } from 'vue'
|
import { nextTick, onMounted, ref } from "vue";
|
||||||
import { buttonVariants } from '@/components/ui/button'
|
import { buttonVariants } from "@/components/ui/button";
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{ items: BulletLegendItemInterface[] }>(), {
|
const props = withDefaults(
|
||||||
items: () => [],
|
defineProps<{ items: BulletLegendItemInterface[] }>(),
|
||||||
})
|
{
|
||||||
|
items: () => [],
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
const emits = defineEmits<{
|
const emits = defineEmits<{
|
||||||
'legendItemClick': [d: BulletLegendItemInterface, i: number]
|
legendItemClick: [d: BulletLegendItemInterface, i: number];
|
||||||
'update:items': [payload: BulletLegendItemInterface[]]
|
"update:items": [payload: BulletLegendItemInterface[]];
|
||||||
}>()
|
}>();
|
||||||
|
|
||||||
const elRef = ref<HTMLElement>()
|
const elRef = ref<HTMLElement>();
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
const selector = `.${BulletLegend.selectors.item}`
|
const selector = `.${BulletLegend.selectors.item}`;
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
const elements = elRef.value?.querySelectorAll(selector)
|
const elements = elRef.value?.querySelectorAll(selector);
|
||||||
const classes = buttonVariants({ variant: 'ghost', size: 'xs' }).split(' ')
|
const classes = buttonVariants({ variant: "ghost", size: "xs" }).split(" ");
|
||||||
|
|
||||||
elements?.forEach(el => el.classList.add(...classes, '!inline-flex', '!mr-2'))
|
elements?.forEach((el) =>
|
||||||
})
|
el.classList.add(...classes, "!inline-flex", "!mr-2"),
|
||||||
})
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
function onLegendItemClick(d: BulletLegendItemInterface, i: number) {
|
function onLegendItemClick(d: BulletLegendItemInterface, i: number) {
|
||||||
emits('legendItemClick', d, i)
|
emits("legendItemClick", d, i);
|
||||||
const isBulletActive = !props.items[i].inactive
|
const isBulletActive = !props.items[i].inactive;
|
||||||
const isFilterApplied = props.items.some(i => i.inactive)
|
const isFilterApplied = props.items.some((i) => i.inactive);
|
||||||
if (isFilterApplied && isBulletActive) {
|
if (isFilterApplied && isBulletActive) {
|
||||||
// reset filter
|
// reset filter
|
||||||
emits('update:items', props.items.map(item => ({ ...item, inactive: false })))
|
emits(
|
||||||
}
|
"update:items",
|
||||||
else {
|
props.items.map((item) => ({ ...item, inactive: false })),
|
||||||
// apply selection, set other item as inactive
|
);
|
||||||
emits('update:items', props.items.map(item => item.name === d.name ? ({ ...d, inactive: false }) : { ...item, inactive: true }))
|
} else {
|
||||||
}
|
// apply selection, set other item as inactive
|
||||||
|
emits(
|
||||||
|
"update:items",
|
||||||
|
props.items.map((item) =>
|
||||||
|
item.name === d.name
|
||||||
|
? { ...d, inactive: false }
|
||||||
|
: { ...item, inactive: true },
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,56 +1,69 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { VisTooltip } from '@unovis/vue'
|
import { VisTooltip } from "@unovis/vue";
|
||||||
import type { BulletLegendItemInterface } from '@unovis/ts'
|
import type { BulletLegendItemInterface } from "@unovis/ts";
|
||||||
import { omit } from '@unovis/ts'
|
import { omit } from "@unovis/ts";
|
||||||
import { type Component, createApp } from 'vue'
|
import { type Component, createApp } from "vue";
|
||||||
import { ChartTooltip } from '.'
|
import { ChartTooltip } from ".";
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(
|
||||||
selector: string
|
defineProps<{
|
||||||
index: string
|
selector: string;
|
||||||
items?: BulletLegendItemInterface[]
|
index: string;
|
||||||
valueFormatter?: (tick: number, i?: number, ticks?: number[]) => string
|
items?: BulletLegendItemInterface[];
|
||||||
customTooltip?: Component
|
valueFormatter?: (tick: number, i?: number, ticks?: number[]) => string;
|
||||||
}>(), {
|
customTooltip?: Component;
|
||||||
valueFormatter: (tick: number) => `${tick}`,
|
}>(),
|
||||||
})
|
{
|
||||||
|
valueFormatter: (tick: number) => `${tick}`,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
// Use weakmap to store reference to each datapoint for Tooltip
|
// Use weakmap to store reference to each datapoint for Tooltip
|
||||||
const wm = new WeakMap()
|
const wm = new WeakMap();
|
||||||
function template(d: any, i: number, elements: (HTMLElement | SVGElement)[]) {
|
function template(d: any, i: number, elements: (HTMLElement | SVGElement)[]) {
|
||||||
if (props.index in d) {
|
if (props.index in d) {
|
||||||
if (wm.has(d)) {
|
if (wm.has(d)) {
|
||||||
return wm.get(d)
|
return wm.get(d);
|
||||||
}
|
} else {
|
||||||
else {
|
const componentDiv = document.createElement("div");
|
||||||
const componentDiv = document.createElement('div')
|
const omittedData = Object.entries(omit(d, [props.index])).map(
|
||||||
const omittedData = Object.entries(omit(d, [props.index])).map(([key, value]) => {
|
([key, value]) => {
|
||||||
const legendReference = props.items?.find(i => i.name === key)
|
const legendReference = props.items?.find((i) => i.name === key);
|
||||||
return { ...legendReference, value: props.valueFormatter(value) }
|
return { ...legendReference, value: props.valueFormatter(value) };
|
||||||
})
|
},
|
||||||
const TooltipComponent = props.customTooltip ?? ChartTooltip
|
);
|
||||||
createApp(TooltipComponent, { title: d[props.index], data: omittedData }).mount(componentDiv)
|
const TooltipComponent = props.customTooltip ?? ChartTooltip;
|
||||||
wm.set(d, componentDiv.innerHTML)
|
createApp(TooltipComponent, {
|
||||||
return componentDiv.innerHTML
|
title: d[props.index],
|
||||||
}
|
data: omittedData,
|
||||||
}
|
}).mount(componentDiv);
|
||||||
|
wm.set(d, componentDiv.innerHTML);
|
||||||
|
return componentDiv.innerHTML;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const data = d.data;
|
||||||
|
|
||||||
else {
|
if (wm.has(data)) {
|
||||||
const data = d.data
|
return wm.get(data);
|
||||||
|
} else {
|
||||||
if (wm.has(data)) {
|
const style = getComputedStyle(elements[i]);
|
||||||
return wm.get(data)
|
const omittedData = [
|
||||||
}
|
{
|
||||||
else {
|
name: data.name,
|
||||||
const style = getComputedStyle(elements[i])
|
value: props.valueFormatter(data[props.index]),
|
||||||
const omittedData = [{ name: data.name, value: props.valueFormatter(data[props.index]), color: style.fill }]
|
color: style.fill,
|
||||||
const componentDiv = document.createElement('div')
|
},
|
||||||
const TooltipComponent = props.customTooltip ?? ChartTooltip
|
];
|
||||||
createApp(TooltipComponent, { title: d[props.index], data: omittedData }).mount(componentDiv)
|
const componentDiv = document.createElement("div");
|
||||||
wm.set(d, componentDiv.innerHTML)
|
const TooltipComponent = props.customTooltip ?? ChartTooltip;
|
||||||
return componentDiv.innerHTML
|
createApp(TooltipComponent, {
|
||||||
}
|
title: d[props.index],
|
||||||
}
|
data: omittedData,
|
||||||
|
}).mount(componentDiv);
|
||||||
|
wm.set(d, componentDiv.innerHTML);
|
||||||
|
return componentDiv.innerHTML;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||||
|
|
||||||
defineProps<{
|
defineProps<{
|
||||||
title?: string
|
title?: string;
|
||||||
data: {
|
data: {
|
||||||
name: string
|
name: string;
|
||||||
color: string
|
color: string;
|
||||||
value: any
|
value: any;
|
||||||
}[]
|
}[];
|
||||||
}>()
|
}>();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,18 +1,23 @@
|
|||||||
export { default as ChartTooltip } from './ChartTooltip.vue'
|
export { default as ChartTooltip } from "./ChartTooltip.vue";
|
||||||
export { default as ChartSingleTooltip } from './ChartSingleTooltip.vue'
|
export { default as ChartSingleTooltip } from "./ChartSingleTooltip.vue";
|
||||||
export { default as ChartLegend } from './ChartLegend.vue'
|
export { default as ChartLegend } from "./ChartLegend.vue";
|
||||||
export { default as ChartCrosshair } from './ChartCrosshair.vue'
|
export { default as ChartCrosshair } from "./ChartCrosshair.vue";
|
||||||
|
|
||||||
export function defaultColors(count: number = 3) {
|
export function defaultColors(count: number = 3) {
|
||||||
const quotient = Math.floor(count / 2)
|
const quotient = Math.floor(count / 2);
|
||||||
const remainder = count % 2
|
const remainder = count % 2;
|
||||||
|
|
||||||
const primaryCount = quotient + remainder
|
const primaryCount = quotient + remainder;
|
||||||
const secondaryCount = quotient
|
const secondaryCount = quotient;
|
||||||
return [
|
return [
|
||||||
...Array.from(Array(primaryCount).keys()).map(i => `hsl(var(--vis-primary-color) / ${1 - (1 / primaryCount) * i})`),
|
...Array.from(Array(primaryCount).keys()).map(
|
||||||
...Array.from(Array(secondaryCount).keys()).map(i => `hsl(var(--vis-secondary-color) / ${1 - (1 / secondaryCount) * i})`),
|
(i) => `hsl(var(--vis-primary-color) / ${1 - (1 / primaryCount) * i})`,
|
||||||
]
|
),
|
||||||
|
...Array.from(Array(secondaryCount).keys()).map(
|
||||||
|
(i) =>
|
||||||
|
`hsl(var(--vis-secondary-color) / ${1 - (1 / secondaryCount) * i})`,
|
||||||
|
),
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
export * from './interface'
|
export * from "./interface";
|
||||||
|
|||||||
@@ -1,64 +1,72 @@
|
|||||||
import type { Spacing } from '@unovis/ts'
|
import type { Spacing } from "@unovis/ts";
|
||||||
|
|
||||||
type KeyOf<T extends Record<string, any>> = Extract<keyof T, string>
|
type KeyOf<T extends Record<string, any>> = Extract<keyof T, string>;
|
||||||
|
|
||||||
export interface BaseChartProps<T extends Record<string, any>> {
|
export interface BaseChartProps<T extends Record<string, any>> {
|
||||||
/**
|
/**
|
||||||
* The source data, in which each entry is a dictionary.
|
* The source data, in which each entry is a dictionary.
|
||||||
*/
|
*/
|
||||||
data: T[]
|
data: T[];
|
||||||
/**
|
/**
|
||||||
* Select the categories from your data. Used to populate the legend and toolip.
|
* Select the categories from your data. Used to populate the legend and toolip.
|
||||||
*/
|
*/
|
||||||
categories: KeyOf<T>[]
|
categories: KeyOf<T>[];
|
||||||
/**
|
/**
|
||||||
* Sets the key to map the data to the axis.
|
* Sets the key to map the data to the axis.
|
||||||
*/
|
*/
|
||||||
index: KeyOf<T>
|
index: KeyOf<T>;
|
||||||
/**
|
/**
|
||||||
* Change the default colors.
|
* Change the default colors.
|
||||||
*/
|
*/
|
||||||
colors?: string[]
|
colors?: string[];
|
||||||
/**
|
/**
|
||||||
* Margin of each the container
|
* Margin of each the container
|
||||||
*/
|
*/
|
||||||
margin?: Spacing
|
margin?: Spacing;
|
||||||
/**
|
/**
|
||||||
* Change the opacity of the non-selected field
|
* Change the opacity of the non-selected field
|
||||||
* @default 0.2
|
* @default 0.2
|
||||||
*/
|
*/
|
||||||
filterOpacity?: number
|
filterOpacity?: number;
|
||||||
/**
|
/**
|
||||||
* Function to format X label
|
* Function to format X label
|
||||||
*/
|
*/
|
||||||
xFormatter?: (tick: number | Date, i: number, ticks: number[] | Date[]) => string
|
xFormatter?: (
|
||||||
/**
|
tick: number | Date,
|
||||||
* Function to format Y label
|
i: number,
|
||||||
*/
|
ticks: number[] | Date[],
|
||||||
yFormatter?: (tick: number | Date, i: number, ticks: number[] | Date[]) => string
|
) => string;
|
||||||
/**
|
/**
|
||||||
* Controls the visibility of the X axis.
|
* Function to format Y label
|
||||||
* @default true
|
*/
|
||||||
*/
|
yFormatter?: (
|
||||||
showXAxis?: boolean
|
tick: number | Date,
|
||||||
/**
|
i: number,
|
||||||
* Controls the visibility of the Y axis.
|
ticks: number[] | Date[],
|
||||||
* @default true
|
) => string;
|
||||||
*/
|
/**
|
||||||
showYAxis?: boolean
|
* Controls the visibility of the X axis.
|
||||||
/**
|
* @default true
|
||||||
* Controls the visibility of tooltip.
|
*/
|
||||||
* @default true
|
showXAxis?: boolean;
|
||||||
*/
|
/**
|
||||||
showTooltip?: boolean
|
* Controls the visibility of the Y axis.
|
||||||
/**
|
* @default true
|
||||||
* Controls the visibility of legend.
|
*/
|
||||||
* @default true
|
showYAxis?: boolean;
|
||||||
*/
|
/**
|
||||||
showLegend?: boolean
|
* Controls the visibility of tooltip.
|
||||||
/**
|
* @default true
|
||||||
* Controls the visibility of gridline.
|
*/
|
||||||
* @default true
|
showTooltip?: boolean;
|
||||||
*/
|
/**
|
||||||
showGridLine?: boolean
|
* Controls the visibility of legend.
|
||||||
|
* @default true
|
||||||
|
*/
|
||||||
|
showLegend?: boolean;
|
||||||
|
/**
|
||||||
|
* Controls the visibility of gridline.
|
||||||
|
* @default true
|
||||||
|
*/
|
||||||
|
showGridLine?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,26 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { type HTMLAttributes, computed } from 'vue'
|
import { type HTMLAttributes, computed } from "vue";
|
||||||
import type { CheckboxRootEmits, CheckboxRootProps } from 'radix-vue'
|
import type { CheckboxRootEmits, CheckboxRootProps } from "radix-vue";
|
||||||
import { CheckboxIndicator, CheckboxRoot, useForwardPropsEmits } from 'radix-vue'
|
import {
|
||||||
import { CheckIcon } from '@radix-icons/vue'
|
CheckboxIndicator,
|
||||||
import { cn } from '@/lib/utils'
|
CheckboxRoot,
|
||||||
|
useForwardPropsEmits,
|
||||||
|
} from "radix-vue";
|
||||||
|
import { CheckIcon } from "@radix-icons/vue";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const props = defineProps<CheckboxRootProps & { class?: HTMLAttributes['class'] }>()
|
const props = defineProps<
|
||||||
const emits = defineEmits<CheckboxRootEmits>()
|
CheckboxRootProps & { class?: HTMLAttributes["class"] }
|
||||||
|
>();
|
||||||
|
const emits = defineEmits<CheckboxRootEmits>();
|
||||||
|
|
||||||
const delegatedProps = computed(() => {
|
const delegatedProps = computed(() => {
|
||||||
const { class: _, ...delegated } = props
|
const { class: _, ...delegated } = props;
|
||||||
|
|
||||||
return delegated
|
return delegated;
|
||||||
})
|
});
|
||||||
|
|
||||||
const forwarded = useForwardPropsEmits(delegatedProps, emits)
|
const forwarded = useForwardPropsEmits(delegatedProps, emits);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
export { default as Checkbox } from './Checkbox.vue'
|
export { default as Checkbox } from "./Checkbox.vue";
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user