@soave/ui 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build.config.d.ts +2 -0
- package/dist/build.config.mjs +14 -0
- package/dist/components/ui/Alert.vue +39 -0
- package/dist/components/ui/AlertDescription.vue +12 -0
- package/dist/components/ui/AlertTitle.vue +12 -0
- package/dist/components/ui/Button.vue +59 -0
- package/dist/components/ui/Card.vue +15 -0
- package/dist/components/ui/CardContent.vue +12 -0
- package/dist/components/ui/CardDescription.vue +12 -0
- package/dist/components/ui/CardFooter.vue +12 -0
- package/dist/components/ui/CardHeader.vue +12 -0
- package/dist/components/ui/CardTitle.vue +12 -0
- package/dist/components/ui/Checkbox.vue +73 -0
- package/dist/components/ui/Dialog.vue +93 -0
- package/dist/components/ui/DialogDescription.vue +12 -0
- package/dist/components/ui/DialogFooter.vue +12 -0
- package/dist/components/ui/DialogHeader.vue +12 -0
- package/dist/components/ui/DialogTitle.vue +12 -0
- package/dist/components/ui/DropdownMenu.vue +33 -0
- package/dist/components/ui/DropdownMenuContent.vue +66 -0
- package/dist/components/ui/DropdownMenuItem.vue +77 -0
- package/dist/components/ui/DropdownMenuLabel.vue +20 -0
- package/dist/components/ui/DropdownMenuSeparator.vue +16 -0
- package/dist/components/ui/DropdownMenuTrigger.vue +38 -0
- package/dist/components/ui/FileInput.vue +153 -0
- package/dist/components/ui/FormError.vue +20 -0
- package/dist/components/ui/FormField.vue +12 -0
- package/dist/components/ui/FormInput.vue +46 -0
- package/dist/components/ui/FormLabel.vue +19 -0
- package/dist/components/ui/FormTextarea.vue +39 -0
- package/dist/components/ui/Input.vue +49 -0
- package/dist/components/ui/Popover.vue +36 -0
- package/dist/components/ui/PopoverContent.vue +62 -0
- package/dist/components/ui/PopoverTrigger.vue +36 -0
- package/dist/components/ui/RadioGroup.vue +42 -0
- package/dist/components/ui/RadioItem.vue +41 -0
- package/dist/components/ui/Select.vue +55 -0
- package/dist/components/ui/SelectContent.vue +29 -0
- package/dist/components/ui/SelectItem.vue +51 -0
- package/dist/components/ui/SelectTrigger.vue +38 -0
- package/dist/components/ui/SelectValue.vue +16 -0
- package/dist/components/ui/Sheet.vue +140 -0
- package/dist/components/ui/SheetDescription.vue +15 -0
- package/dist/components/ui/SheetFooter.vue +15 -0
- package/dist/components/ui/SheetHeader.vue +15 -0
- package/dist/components/ui/SheetTitle.vue +15 -0
- package/dist/components/ui/Switch.vue +43 -0
- package/dist/components/ui/Textarea.vue +50 -0
- package/dist/components/ui/Toast.vue +107 -0
- package/dist/components/ui/Toaster.vue +80 -0
- package/dist/components/ui/Tooltip.vue +42 -0
- package/dist/components/ui/TooltipContent.vue +68 -0
- package/dist/components/ui/TooltipTrigger.vue +39 -0
- package/dist/components/ui/UIProvider.vue +19 -0
- package/dist/components/ui/index.d.ts +52 -0
- package/dist/components/ui/index.mjs +52 -0
- package/dist/composables/index.d.ts +17 -0
- package/dist/composables/index.mjs +17 -0
- package/dist/composables/useButton.d.ts +8 -0
- package/dist/composables/useButton.mjs +49 -0
- package/dist/composables/useCard.d.ts +8 -0
- package/dist/composables/useCard.mjs +24 -0
- package/dist/composables/useCheckbox.d.ts +7 -0
- package/dist/composables/useCheckbox.mjs +51 -0
- package/dist/composables/useDialog.d.ts +6 -0
- package/dist/composables/useDialog.mjs +19 -0
- package/dist/composables/useDropdown.d.ts +24 -0
- package/dist/composables/useDropdown.mjs +170 -0
- package/dist/composables/useFileInput.d.ts +6 -0
- package/dist/composables/useFileInput.mjs +152 -0
- package/dist/composables/useForm.d.ts +7 -0
- package/dist/composables/useForm.mjs +159 -0
- package/dist/composables/useInput.d.ts +8 -0
- package/dist/composables/useInput.mjs +52 -0
- package/dist/composables/usePopover.d.ts +20 -0
- package/dist/composables/usePopover.mjs +113 -0
- package/dist/composables/useRadio.d.ts +7 -0
- package/dist/composables/useRadio.mjs +55 -0
- package/dist/composables/useSelect.d.ts +17 -0
- package/dist/composables/useSelect.mjs +71 -0
- package/dist/composables/useSwitch.d.ts +7 -0
- package/dist/composables/useSwitch.mjs +50 -0
- package/dist/composables/useTextarea.d.ts +7 -0
- package/dist/composables/useTextarea.mjs +50 -0
- package/dist/composables/useTheme.d.ts +15 -0
- package/dist/composables/useTheme.mjs +89 -0
- package/dist/composables/useToast.d.ts +11 -0
- package/dist/composables/useToast.mjs +64 -0
- package/dist/composables/useTooltip.d.ts +23 -0
- package/dist/composables/useTooltip.mjs +125 -0
- package/dist/composables/useUIConfig.d.ts +28 -0
- package/dist/composables/useUIConfig.mjs +36 -0
- package/dist/constants/errors.d.ts +22 -0
- package/dist/constants/errors.mjs +18 -0
- package/dist/constants/index.d.ts +2 -0
- package/dist/constants/index.mjs +2 -0
- package/dist/constants/logs.d.ts +17 -0
- package/dist/constants/logs.mjs +17 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.mjs +5 -0
- package/dist/types/alert.d.ts +15 -0
- package/dist/types/alert.mjs +0 -0
- package/dist/types/button.d.ts +20 -0
- package/dist/types/button.mjs +0 -0
- package/dist/types/card.d.ts +23 -0
- package/dist/types/card.mjs +0 -0
- package/dist/types/checkbox.d.ts +19 -0
- package/dist/types/checkbox.mjs +0 -0
- package/dist/types/config.d.ts +30 -0
- package/dist/types/config.mjs +15 -0
- package/dist/types/dialog.d.ts +29 -0
- package/dist/types/dialog.mjs +0 -0
- package/dist/types/dropdown.d.ts +27 -0
- package/dist/types/dropdown.mjs +0 -0
- package/dist/types/file-input.d.ts +35 -0
- package/dist/types/file-input.mjs +0 -0
- package/dist/types/form.d.ts +70 -0
- package/dist/types/form.mjs +0 -0
- package/dist/types/index.d.ts +20 -0
- package/dist/types/index.mjs +20 -0
- package/dist/types/input.d.ts +27 -0
- package/dist/types/input.mjs +0 -0
- package/dist/types/popover.d.ts +15 -0
- package/dist/types/popover.mjs +0 -0
- package/dist/types/radio.d.ts +29 -0
- package/dist/types/radio.mjs +1 -0
- package/dist/types/select.d.ts +36 -0
- package/dist/types/select.mjs +1 -0
- package/dist/types/sheet.d.ts +11 -0
- package/dist/types/sheet.mjs +0 -0
- package/dist/types/switch.d.ts +17 -0
- package/dist/types/switch.mjs +0 -0
- package/dist/types/textarea.d.ts +25 -0
- package/dist/types/textarea.mjs +0 -0
- package/dist/types/theme.d.ts +43 -0
- package/dist/types/theme.mjs +42 -0
- package/dist/types/toast.d.ts +38 -0
- package/dist/types/toast.mjs +0 -0
- package/dist/types/tooltip.d.ts +25 -0
- package/dist/types/tooltip.mjs +0 -0
- package/dist/types/utils.d.ts +12 -0
- package/dist/types/utils.mjs +0 -0
- package/dist/utils/cn.d.ts +6 -0
- package/dist/utils/cn.mjs +5 -0
- package/dist/utils/deepMerge.d.ts +6 -0
- package/dist/utils/deepMerge.mjs +18 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.mjs +2 -0
- package/package.json +53 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<Transition name="tooltip">
|
|
3
|
+
<div
|
|
4
|
+
v-if="is_open"
|
|
5
|
+
ref="content_element"
|
|
6
|
+
:id="tooltip_id"
|
|
7
|
+
role="tooltip"
|
|
8
|
+
:style="position_styles"
|
|
9
|
+
:class="cn(base_classes, props.class)"
|
|
10
|
+
@mouseenter="handleContentMouseEnter"
|
|
11
|
+
@mouseleave="handleContentMouseLeave"
|
|
12
|
+
>
|
|
13
|
+
<slot />
|
|
14
|
+
</div>
|
|
15
|
+
</Transition>
|
|
16
|
+
</template>
|
|
17
|
+
|
|
18
|
+
<script setup lang="ts">
|
|
19
|
+
import { inject, ref, watchEffect } from "vue"
|
|
20
|
+
import { cn } from "../../utils/cn"
|
|
21
|
+
import { TOOLTIP_CONTEXT_KEY } from "./Tooltip.vue"
|
|
22
|
+
|
|
23
|
+
export interface Props {
|
|
24
|
+
class?: string
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const props = defineProps<Props>()
|
|
28
|
+
|
|
29
|
+
const context = inject(TOOLTIP_CONTEXT_KEY)
|
|
30
|
+
|
|
31
|
+
if (!context) {
|
|
32
|
+
throw new Error("TooltipContent must be used within a Tooltip component")
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const {
|
|
36
|
+
is_open,
|
|
37
|
+
content_ref,
|
|
38
|
+
tooltip_id,
|
|
39
|
+
position_styles,
|
|
40
|
+
handleMouseEnter,
|
|
41
|
+
handleMouseLeave
|
|
42
|
+
} = context
|
|
43
|
+
|
|
44
|
+
const content_element = ref<HTMLElement | null>(null)
|
|
45
|
+
|
|
46
|
+
watchEffect(() => {
|
|
47
|
+
content_ref.value = content_element.value
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
const handleContentMouseEnter = (): void => {
|
|
51
|
+
// Keep tooltip open when hovering over content
|
|
52
|
+
handleMouseEnter()
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const handleContentMouseLeave = (): void => {
|
|
56
|
+
handleMouseLeave()
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const base_classes = cn(
|
|
60
|
+
"z-50 overflow-hidden rounded-md bg-primary px-3 py-1.5",
|
|
61
|
+
"text-xs text-primary-foreground shadow-md",
|
|
62
|
+
"animate-in fade-in-0 zoom-in-95"
|
|
63
|
+
)
|
|
64
|
+
</script>
|
|
65
|
+
|
|
66
|
+
<style scoped>
|
|
67
|
+
.tooltip-enter-active,.tooltip-leave-active{transition:opacity .15s ease,transform .15s ease}.tooltip-enter-from,.tooltip-leave-to{opacity:0;transform:scale(.95)}
|
|
68
|
+
</style>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<span
|
|
3
|
+
ref="trigger_element"
|
|
4
|
+
:aria-describedby="is_open ? tooltip_id : undefined"
|
|
5
|
+
@mouseenter="handleMouseEnter"
|
|
6
|
+
@mouseleave="handleMouseLeave"
|
|
7
|
+
@focus="handleFocus"
|
|
8
|
+
@blur="handleBlur"
|
|
9
|
+
>
|
|
10
|
+
<slot />
|
|
11
|
+
</span>
|
|
12
|
+
</template>
|
|
13
|
+
|
|
14
|
+
<script setup lang="ts">
|
|
15
|
+
import { inject, ref, watchEffect } from "vue"
|
|
16
|
+
import { TOOLTIP_CONTEXT_KEY } from "./Tooltip.vue"
|
|
17
|
+
|
|
18
|
+
const context = inject(TOOLTIP_CONTEXT_KEY)
|
|
19
|
+
|
|
20
|
+
if (!context) {
|
|
21
|
+
throw new Error("TooltipTrigger must be used within a Tooltip component")
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const {
|
|
25
|
+
is_open,
|
|
26
|
+
trigger_ref,
|
|
27
|
+
tooltip_id,
|
|
28
|
+
handleMouseEnter,
|
|
29
|
+
handleMouseLeave,
|
|
30
|
+
handleFocus,
|
|
31
|
+
handleBlur
|
|
32
|
+
} = context
|
|
33
|
+
|
|
34
|
+
const trigger_element = ref<HTMLElement | null>(null)
|
|
35
|
+
|
|
36
|
+
watchEffect(() => {
|
|
37
|
+
trigger_ref.value = trigger_element.value
|
|
38
|
+
})
|
|
39
|
+
</script>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { DeepPartial } from "../../types/utils"
|
|
3
|
+
import type { UIConfig } from "../../types/config"
|
|
4
|
+
import { useUIProvider } from "../../composables/useUIConfig"
|
|
5
|
+
|
|
6
|
+
interface UIProviderProps {
|
|
7
|
+
config?: DeepPartial<UIConfig>
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const props = withDefaults(defineProps<UIProviderProps>(), {
|
|
11
|
+
config: () => ({})
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
useUIProvider(props.config)
|
|
15
|
+
</script>
|
|
16
|
+
|
|
17
|
+
<template>
|
|
18
|
+
<slot />
|
|
19
|
+
</template>
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export { default as UIProvider } from "./UIProvider.vue";
|
|
2
|
+
export { default as Button } from "./Button.vue";
|
|
3
|
+
export { default as Input } from "./Input.vue";
|
|
4
|
+
export { default as Card } from "./Card.vue";
|
|
5
|
+
export { default as CardHeader } from "./CardHeader.vue";
|
|
6
|
+
export { default as CardTitle } from "./CardTitle.vue";
|
|
7
|
+
export { default as CardDescription } from "./CardDescription.vue";
|
|
8
|
+
export { default as CardContent } from "./CardContent.vue";
|
|
9
|
+
export { default as CardFooter } from "./CardFooter.vue";
|
|
10
|
+
export { default as Alert } from "./Alert.vue";
|
|
11
|
+
export { default as AlertTitle } from "./AlertTitle.vue";
|
|
12
|
+
export { default as AlertDescription } from "./AlertDescription.vue";
|
|
13
|
+
export { default as Dialog } from "./Dialog.vue";
|
|
14
|
+
export { default as DialogHeader } from "./DialogHeader.vue";
|
|
15
|
+
export { default as DialogTitle } from "./DialogTitle.vue";
|
|
16
|
+
export { default as DialogDescription } from "./DialogDescription.vue";
|
|
17
|
+
export { default as DialogFooter } from "./DialogFooter.vue";
|
|
18
|
+
export { default as FormField } from "./FormField.vue";
|
|
19
|
+
export { default as FormLabel } from "./FormLabel.vue";
|
|
20
|
+
export { default as FormInput } from "./FormInput.vue";
|
|
21
|
+
export { default as FormError } from "./FormError.vue";
|
|
22
|
+
export { default as Checkbox } from "./Checkbox.vue";
|
|
23
|
+
export { default as RadioGroup } from "./RadioGroup.vue";
|
|
24
|
+
export { default as RadioItem } from "./RadioItem.vue";
|
|
25
|
+
export { default as Switch } from "./Switch.vue";
|
|
26
|
+
export { default as Textarea } from "./Textarea.vue";
|
|
27
|
+
export { default as Select } from "./Select.vue";
|
|
28
|
+
export { default as SelectTrigger } from "./SelectTrigger.vue";
|
|
29
|
+
export { default as SelectValue } from "./SelectValue.vue";
|
|
30
|
+
export { default as SelectContent } from "./SelectContent.vue";
|
|
31
|
+
export { default as SelectItem } from "./SelectItem.vue";
|
|
32
|
+
export { default as FileInput } from "./FileInput.vue";
|
|
33
|
+
export { default as FormTextarea } from "./FormTextarea.vue";
|
|
34
|
+
export { default as Toast } from "./Toast.vue";
|
|
35
|
+
export { default as Toaster } from "./Toaster.vue";
|
|
36
|
+
export { default as Tooltip } from "./Tooltip.vue";
|
|
37
|
+
export { default as TooltipTrigger } from "./TooltipTrigger.vue";
|
|
38
|
+
export { default as TooltipContent } from "./TooltipContent.vue";
|
|
39
|
+
export { default as Popover } from "./Popover.vue";
|
|
40
|
+
export { default as PopoverTrigger } from "./PopoverTrigger.vue";
|
|
41
|
+
export { default as PopoverContent } from "./PopoverContent.vue";
|
|
42
|
+
export { default as DropdownMenu } from "./DropdownMenu.vue";
|
|
43
|
+
export { default as DropdownMenuTrigger } from "./DropdownMenuTrigger.vue";
|
|
44
|
+
export { default as DropdownMenuContent } from "./DropdownMenuContent.vue";
|
|
45
|
+
export { default as DropdownMenuItem } from "./DropdownMenuItem.vue";
|
|
46
|
+
export { default as DropdownMenuSeparator } from "./DropdownMenuSeparator.vue";
|
|
47
|
+
export { default as DropdownMenuLabel } from "./DropdownMenuLabel.vue";
|
|
48
|
+
export { default as Sheet } from "./Sheet.vue";
|
|
49
|
+
export { default as SheetHeader } from "./SheetHeader.vue";
|
|
50
|
+
export { default as SheetTitle } from "./SheetTitle.vue";
|
|
51
|
+
export { default as SheetDescription } from "./SheetDescription.vue";
|
|
52
|
+
export { default as SheetFooter } from "./SheetFooter.vue";
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export { default as UIProvider } from "./UIProvider.vue";
|
|
2
|
+
export { default as Button } from "./Button.vue";
|
|
3
|
+
export { default as Input } from "./Input.vue";
|
|
4
|
+
export { default as Card } from "./Card.vue";
|
|
5
|
+
export { default as CardHeader } from "./CardHeader.vue";
|
|
6
|
+
export { default as CardTitle } from "./CardTitle.vue";
|
|
7
|
+
export { default as CardDescription } from "./CardDescription.vue";
|
|
8
|
+
export { default as CardContent } from "./CardContent.vue";
|
|
9
|
+
export { default as CardFooter } from "./CardFooter.vue";
|
|
10
|
+
export { default as Alert } from "./Alert.vue";
|
|
11
|
+
export { default as AlertTitle } from "./AlertTitle.vue";
|
|
12
|
+
export { default as AlertDescription } from "./AlertDescription.vue";
|
|
13
|
+
export { default as Dialog } from "./Dialog.vue";
|
|
14
|
+
export { default as DialogHeader } from "./DialogHeader.vue";
|
|
15
|
+
export { default as DialogTitle } from "./DialogTitle.vue";
|
|
16
|
+
export { default as DialogDescription } from "./DialogDescription.vue";
|
|
17
|
+
export { default as DialogFooter } from "./DialogFooter.vue";
|
|
18
|
+
export { default as FormField } from "./FormField.vue";
|
|
19
|
+
export { default as FormLabel } from "./FormLabel.vue";
|
|
20
|
+
export { default as FormInput } from "./FormInput.vue";
|
|
21
|
+
export { default as FormError } from "./FormError.vue";
|
|
22
|
+
export { default as Checkbox } from "./Checkbox.vue";
|
|
23
|
+
export { default as RadioGroup } from "./RadioGroup.vue";
|
|
24
|
+
export { default as RadioItem } from "./RadioItem.vue";
|
|
25
|
+
export { default as Switch } from "./Switch.vue";
|
|
26
|
+
export { default as Textarea } from "./Textarea.vue";
|
|
27
|
+
export { default as Select } from "./Select.vue";
|
|
28
|
+
export { default as SelectTrigger } from "./SelectTrigger.vue";
|
|
29
|
+
export { default as SelectValue } from "./SelectValue.vue";
|
|
30
|
+
export { default as SelectContent } from "./SelectContent.vue";
|
|
31
|
+
export { default as SelectItem } from "./SelectItem.vue";
|
|
32
|
+
export { default as FileInput } from "./FileInput.vue";
|
|
33
|
+
export { default as FormTextarea } from "./FormTextarea.vue";
|
|
34
|
+
export { default as Toast } from "./Toast.vue";
|
|
35
|
+
export { default as Toaster } from "./Toaster.vue";
|
|
36
|
+
export { default as Tooltip } from "./Tooltip.vue";
|
|
37
|
+
export { default as TooltipTrigger } from "./TooltipTrigger.vue";
|
|
38
|
+
export { default as TooltipContent } from "./TooltipContent.vue";
|
|
39
|
+
export { default as Popover } from "./Popover.vue";
|
|
40
|
+
export { default as PopoverTrigger } from "./PopoverTrigger.vue";
|
|
41
|
+
export { default as PopoverContent } from "./PopoverContent.vue";
|
|
42
|
+
export { default as DropdownMenu } from "./DropdownMenu.vue";
|
|
43
|
+
export { default as DropdownMenuTrigger } from "./DropdownMenuTrigger.vue";
|
|
44
|
+
export { default as DropdownMenuContent } from "./DropdownMenuContent.vue";
|
|
45
|
+
export { default as DropdownMenuItem } from "./DropdownMenuItem.vue";
|
|
46
|
+
export { default as DropdownMenuSeparator } from "./DropdownMenuSeparator.vue";
|
|
47
|
+
export { default as DropdownMenuLabel } from "./DropdownMenuLabel.vue";
|
|
48
|
+
export { default as Sheet } from "./Sheet.vue";
|
|
49
|
+
export { default as SheetHeader } from "./SheetHeader.vue";
|
|
50
|
+
export { default as SheetTitle } from "./SheetTitle.vue";
|
|
51
|
+
export { default as SheetDescription } from "./SheetDescription.vue";
|
|
52
|
+
export { default as SheetFooter } from "./SheetFooter.vue";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export { useButton } from "./useButton";
|
|
2
|
+
export { useInput } from "./useInput";
|
|
3
|
+
export { useCard } from "./useCard";
|
|
4
|
+
export { useDialog } from "./useDialog";
|
|
5
|
+
export { useForm } from "./useForm";
|
|
6
|
+
export { useUIProvider, useUI, useUIConfig, UI_CONFIG_KEY } from "./useUIConfig";
|
|
7
|
+
export { useCheckbox } from "./useCheckbox";
|
|
8
|
+
export { useRadioItem } from "./useRadio";
|
|
9
|
+
export { useSwitch } from "./useSwitch";
|
|
10
|
+
export { useTextarea } from "./useTextarea";
|
|
11
|
+
export { useSelectTrigger, useSelectContent, useSelectItem } from "./useSelect";
|
|
12
|
+
export { useFileInput } from "./useFileInput";
|
|
13
|
+
export { useToast, toast } from "./useToast";
|
|
14
|
+
export { useTooltip } from "./useTooltip";
|
|
15
|
+
export { usePopover } from "./usePopover";
|
|
16
|
+
export { useDropdown } from "./useDropdown";
|
|
17
|
+
export { useTheme, generateThemeCSS } from "./useTheme";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export { useButton } from "./useButton.mjs";
|
|
2
|
+
export { useInput } from "./useInput.mjs";
|
|
3
|
+
export { useCard } from "./useCard.mjs";
|
|
4
|
+
export { useDialog } from "./useDialog.mjs";
|
|
5
|
+
export { useForm } from "./useForm.mjs";
|
|
6
|
+
export { useUIProvider, useUI, useUIConfig, UI_CONFIG_KEY } from "./useUIConfig.mjs";
|
|
7
|
+
export { useCheckbox } from "./useCheckbox.mjs";
|
|
8
|
+
export { useRadioItem } from "./useRadio.mjs";
|
|
9
|
+
export { useSwitch } from "./useSwitch.mjs";
|
|
10
|
+
export { useTextarea } from "./useTextarea.mjs";
|
|
11
|
+
export { useSelectTrigger, useSelectContent, useSelectItem } from "./useSelect.mjs";
|
|
12
|
+
export { useFileInput } from "./useFileInput.mjs";
|
|
13
|
+
export { useToast, toast } from "./useToast.mjs";
|
|
14
|
+
export { useTooltip } from "./useTooltip.mjs";
|
|
15
|
+
export { usePopover } from "./usePopover.mjs";
|
|
16
|
+
export { useDropdown } from "./useDropdown.mjs";
|
|
17
|
+
export { useTheme, generateThemeCSS } from "./useTheme.mjs";
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type Ref } from "vue";
|
|
2
|
+
import type { ButtonProps, ButtonReturn } from "../types/button";
|
|
3
|
+
/**
|
|
4
|
+
* Buttonコンポーネントのロジックを提供するComposable
|
|
5
|
+
* variant, size, disabled, loadingに基づいてクラスとaria属性を生成
|
|
6
|
+
* Providerから設定されたデフォルト値を使用
|
|
7
|
+
*/
|
|
8
|
+
export declare const useButton: (props: Ref<ButtonProps>) => ButtonReturn;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { computed } from "vue";
|
|
2
|
+
import { cn } from "../utils/cn.mjs";
|
|
3
|
+
import { useUI } from "./useUIConfig.mjs";
|
|
4
|
+
export const useButton = (props) => {
|
|
5
|
+
const ui_config = useUI("button");
|
|
6
|
+
const is_disabled = computed(() => props.value.disabled ?? false);
|
|
7
|
+
const is_loading = computed(() => props.value.loading ?? false);
|
|
8
|
+
const variant_classes = computed(() => {
|
|
9
|
+
const variant_map = {
|
|
10
|
+
primary: "bg-primary text-primary-foreground hover:bg-primary/90",
|
|
11
|
+
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
12
|
+
ghost: "hover:bg-accent hover:text-accent-foreground",
|
|
13
|
+
outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
|
|
14
|
+
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90"
|
|
15
|
+
};
|
|
16
|
+
return variant_map[props.value.variant ?? ui_config.default_variant];
|
|
17
|
+
});
|
|
18
|
+
const size_classes = computed(() => {
|
|
19
|
+
const size_map = {
|
|
20
|
+
sm: "h-9 px-3 text-sm",
|
|
21
|
+
md: "h-10 px-4 py-2",
|
|
22
|
+
lg: "h-11 px-8"
|
|
23
|
+
};
|
|
24
|
+
return size_map[props.value.size ?? ui_config.default_size];
|
|
25
|
+
});
|
|
26
|
+
const base_classes = computed(
|
|
27
|
+
() => cn(
|
|
28
|
+
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium",
|
|
29
|
+
"ring-offset-background transition-colors",
|
|
30
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
|
31
|
+
"disabled:pointer-events-none disabled:opacity-50",
|
|
32
|
+
variant_classes.value,
|
|
33
|
+
size_classes.value,
|
|
34
|
+
is_disabled.value && "opacity-50 cursor-not-allowed",
|
|
35
|
+
is_loading.value && "cursor-wait"
|
|
36
|
+
)
|
|
37
|
+
);
|
|
38
|
+
const aria_attributes = computed(() => ({
|
|
39
|
+
"aria-disabled": is_disabled.value || void 0,
|
|
40
|
+
"aria-busy": is_loading.value || void 0,
|
|
41
|
+
role: "button"
|
|
42
|
+
}));
|
|
43
|
+
return {
|
|
44
|
+
base_classes,
|
|
45
|
+
is_disabled,
|
|
46
|
+
is_loading,
|
|
47
|
+
aria_attributes
|
|
48
|
+
};
|
|
49
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { computed } from "vue";
|
|
2
|
+
import { cn } from "../utils/cn.mjs";
|
|
3
|
+
import { useUI } from "./useUIConfig.mjs";
|
|
4
|
+
export const useCard = (props) => {
|
|
5
|
+
const ui_config = useUI("card");
|
|
6
|
+
const padding_classes = computed(() => {
|
|
7
|
+
const padding_map = {
|
|
8
|
+
none: "",
|
|
9
|
+
sm: "p-4",
|
|
10
|
+
md: "p-6",
|
|
11
|
+
lg: "p-8"
|
|
12
|
+
};
|
|
13
|
+
return padding_map[props.value.padding ?? ui_config.default_padding];
|
|
14
|
+
});
|
|
15
|
+
const base_classes = computed(
|
|
16
|
+
() => cn(
|
|
17
|
+
"rounded-lg border bg-card text-card-foreground shadow-sm",
|
|
18
|
+
padding_classes.value
|
|
19
|
+
)
|
|
20
|
+
);
|
|
21
|
+
return {
|
|
22
|
+
base_classes
|
|
23
|
+
};
|
|
24
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type Ref } from "vue";
|
|
2
|
+
import type { CheckboxProps, CheckboxReturn } from "../types/checkbox";
|
|
3
|
+
/**
|
|
4
|
+
* Checkboxコンポーネントのロジックを提供するComposable
|
|
5
|
+
* size, disabled, indeterminateに基づいてクラスとaria属性を生成
|
|
6
|
+
*/
|
|
7
|
+
export declare const useCheckbox: (props: Ref<CheckboxProps>, checked: Ref<boolean>) => CheckboxReturn;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { computed } from "vue";
|
|
2
|
+
import { cn } from "../utils/cn.mjs";
|
|
3
|
+
export const useCheckbox = (props, checked) => {
|
|
4
|
+
const is_disabled = computed(() => props.value.disabled ?? false);
|
|
5
|
+
const is_indeterminate = computed(() => props.value.indeterminate ?? false);
|
|
6
|
+
const size_classes = computed(() => {
|
|
7
|
+
const size_map = {
|
|
8
|
+
sm: "h-4 w-4",
|
|
9
|
+
md: "h-5 w-5",
|
|
10
|
+
lg: "h-6 w-6"
|
|
11
|
+
};
|
|
12
|
+
return size_map[props.value.size ?? "md"];
|
|
13
|
+
});
|
|
14
|
+
const base_classes = computed(
|
|
15
|
+
() => cn(
|
|
16
|
+
"peer shrink-0 rounded-sm border border-primary",
|
|
17
|
+
"ring-offset-background",
|
|
18
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
|
19
|
+
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
20
|
+
"data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
|
|
21
|
+
"data-[state=indeterminate]:bg-primary data-[state=indeterminate]:text-primary-foreground",
|
|
22
|
+
size_classes.value
|
|
23
|
+
)
|
|
24
|
+
);
|
|
25
|
+
const indicator_size_classes = computed(() => {
|
|
26
|
+
const size_map = {
|
|
27
|
+
sm: "h-3 w-3",
|
|
28
|
+
md: "h-4 w-4",
|
|
29
|
+
lg: "h-5 w-5"
|
|
30
|
+
};
|
|
31
|
+
return size_map[props.value.size ?? "md"];
|
|
32
|
+
});
|
|
33
|
+
const indicator_classes = computed(
|
|
34
|
+
() => cn(
|
|
35
|
+
"flex items-center justify-center text-current",
|
|
36
|
+
indicator_size_classes.value
|
|
37
|
+
)
|
|
38
|
+
);
|
|
39
|
+
const aria_attributes = computed(() => ({
|
|
40
|
+
role: "checkbox",
|
|
41
|
+
"aria-checked": is_indeterminate.value ? "mixed" : checked.value,
|
|
42
|
+
"aria-disabled": is_disabled.value || void 0
|
|
43
|
+
}));
|
|
44
|
+
return {
|
|
45
|
+
base_classes,
|
|
46
|
+
indicator_classes,
|
|
47
|
+
is_disabled,
|
|
48
|
+
is_indeterminate,
|
|
49
|
+
aria_attributes
|
|
50
|
+
};
|
|
51
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ref, readonly } from "vue";
|
|
2
|
+
export const useDialog = () => {
|
|
3
|
+
const is_open = ref(false);
|
|
4
|
+
const open = () => {
|
|
5
|
+
is_open.value = true;
|
|
6
|
+
};
|
|
7
|
+
const close = () => {
|
|
8
|
+
is_open.value = false;
|
|
9
|
+
};
|
|
10
|
+
const toggle = () => {
|
|
11
|
+
is_open.value = !is_open.value;
|
|
12
|
+
};
|
|
13
|
+
return {
|
|
14
|
+
is_open: readonly(is_open),
|
|
15
|
+
open,
|
|
16
|
+
close,
|
|
17
|
+
toggle
|
|
18
|
+
};
|
|
19
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type Ref, type ComputedRef } from "vue";
|
|
2
|
+
import type { DropdownSide, DropdownAlign } from "../types/dropdown";
|
|
3
|
+
export interface UseDropdownProps {
|
|
4
|
+
side?: DropdownSide;
|
|
5
|
+
align?: DropdownAlign;
|
|
6
|
+
}
|
|
7
|
+
export interface UseDropdownReturn {
|
|
8
|
+
is_open: Ref<boolean>;
|
|
9
|
+
trigger_ref: Ref<HTMLElement | null>;
|
|
10
|
+
content_ref: Ref<HTMLElement | null>;
|
|
11
|
+
dropdown_id: string;
|
|
12
|
+
active_item_index: Ref<number>;
|
|
13
|
+
items_count: Ref<number>;
|
|
14
|
+
position_styles: ComputedRef<Record<string, string>>;
|
|
15
|
+
open: () => void;
|
|
16
|
+
close: () => void;
|
|
17
|
+
toggle: () => void;
|
|
18
|
+
handleTriggerClick: () => void;
|
|
19
|
+
handleTriggerKeyDown: (event: KeyboardEvent) => void;
|
|
20
|
+
handleContentKeyDown: (event: KeyboardEvent) => void;
|
|
21
|
+
registerItem: () => number;
|
|
22
|
+
setActiveItem: (index: number) => void;
|
|
23
|
+
}
|
|
24
|
+
export declare function useDropdown(props: Ref<UseDropdownProps>): UseDropdownReturn;
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { ref, computed, onMounted, onUnmounted } from "vue";
|
|
2
|
+
let dropdown_counter = 0;
|
|
3
|
+
export function useDropdown(props) {
|
|
4
|
+
const is_open = ref(false);
|
|
5
|
+
const trigger_ref = ref(null);
|
|
6
|
+
const content_ref = ref(null);
|
|
7
|
+
const dropdown_id = `dropdown-${++dropdown_counter}`;
|
|
8
|
+
const active_item_index = ref(-1);
|
|
9
|
+
const items_count = ref(0);
|
|
10
|
+
let item_counter = 0;
|
|
11
|
+
const open = () => {
|
|
12
|
+
is_open.value = true;
|
|
13
|
+
active_item_index.value = 0;
|
|
14
|
+
};
|
|
15
|
+
const close = () => {
|
|
16
|
+
is_open.value = false;
|
|
17
|
+
active_item_index.value = -1;
|
|
18
|
+
};
|
|
19
|
+
const toggle = () => {
|
|
20
|
+
if (is_open.value) {
|
|
21
|
+
close();
|
|
22
|
+
} else {
|
|
23
|
+
open();
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
const handleTriggerClick = () => {
|
|
27
|
+
toggle();
|
|
28
|
+
};
|
|
29
|
+
const handleTriggerKeyDown = (event) => {
|
|
30
|
+
switch (event.key) {
|
|
31
|
+
case "Enter":
|
|
32
|
+
case " ":
|
|
33
|
+
case "ArrowDown":
|
|
34
|
+
event.preventDefault();
|
|
35
|
+
open();
|
|
36
|
+
break;
|
|
37
|
+
case "ArrowUp":
|
|
38
|
+
event.preventDefault();
|
|
39
|
+
open();
|
|
40
|
+
active_item_index.value = items_count.value - 1;
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
const handleContentKeyDown = (event) => {
|
|
45
|
+
switch (event.key) {
|
|
46
|
+
case "ArrowDown":
|
|
47
|
+
event.preventDefault();
|
|
48
|
+
active_item_index.value = Math.min(active_item_index.value + 1, items_count.value - 1);
|
|
49
|
+
break;
|
|
50
|
+
case "ArrowUp":
|
|
51
|
+
event.preventDefault();
|
|
52
|
+
active_item_index.value = Math.max(active_item_index.value - 1, 0);
|
|
53
|
+
break;
|
|
54
|
+
case "Home":
|
|
55
|
+
event.preventDefault();
|
|
56
|
+
active_item_index.value = 0;
|
|
57
|
+
break;
|
|
58
|
+
case "End":
|
|
59
|
+
event.preventDefault();
|
|
60
|
+
active_item_index.value = items_count.value - 1;
|
|
61
|
+
break;
|
|
62
|
+
case "Escape":
|
|
63
|
+
event.preventDefault();
|
|
64
|
+
close();
|
|
65
|
+
trigger_ref.value?.focus();
|
|
66
|
+
break;
|
|
67
|
+
case "Tab":
|
|
68
|
+
close();
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
const handleClickOutside = (event) => {
|
|
73
|
+
if (!is_open.value) return;
|
|
74
|
+
const target = event.target;
|
|
75
|
+
const trigger = trigger_ref.value;
|
|
76
|
+
const content = content_ref.value;
|
|
77
|
+
if (trigger && trigger.contains(target)) return;
|
|
78
|
+
if (content && content.contains(target)) return;
|
|
79
|
+
close();
|
|
80
|
+
};
|
|
81
|
+
const registerItem = () => {
|
|
82
|
+
const index = item_counter++;
|
|
83
|
+
items_count.value = item_counter;
|
|
84
|
+
return index;
|
|
85
|
+
};
|
|
86
|
+
const setActiveItem = (index) => {
|
|
87
|
+
active_item_index.value = index;
|
|
88
|
+
};
|
|
89
|
+
const position_styles = computed(() => {
|
|
90
|
+
if (!trigger_ref.value || !is_open.value) {
|
|
91
|
+
return {};
|
|
92
|
+
}
|
|
93
|
+
const side = props.value.side ?? "bottom";
|
|
94
|
+
const align = props.value.align ?? "start";
|
|
95
|
+
const offset = 4;
|
|
96
|
+
const styles = {
|
|
97
|
+
position: "absolute",
|
|
98
|
+
zIndex: "50"
|
|
99
|
+
};
|
|
100
|
+
switch (side) {
|
|
101
|
+
case "top":
|
|
102
|
+
styles.bottom = "100%";
|
|
103
|
+
styles.marginBottom = `${offset}px`;
|
|
104
|
+
break;
|
|
105
|
+
case "bottom":
|
|
106
|
+
styles.top = "100%";
|
|
107
|
+
styles.marginTop = `${offset}px`;
|
|
108
|
+
break;
|
|
109
|
+
case "left":
|
|
110
|
+
styles.right = "100%";
|
|
111
|
+
styles.marginRight = `${offset}px`;
|
|
112
|
+
break;
|
|
113
|
+
case "right":
|
|
114
|
+
styles.left = "100%";
|
|
115
|
+
styles.marginLeft = `${offset}px`;
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
if (side === "top" || side === "bottom") {
|
|
119
|
+
switch (align) {
|
|
120
|
+
case "start":
|
|
121
|
+
styles.left = "0";
|
|
122
|
+
break;
|
|
123
|
+
case "center":
|
|
124
|
+
styles.left = "50%";
|
|
125
|
+
styles.transform = "translateX(-50%)";
|
|
126
|
+
break;
|
|
127
|
+
case "end":
|
|
128
|
+
styles.right = "0";
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
} else {
|
|
132
|
+
switch (align) {
|
|
133
|
+
case "start":
|
|
134
|
+
styles.top = "0";
|
|
135
|
+
break;
|
|
136
|
+
case "center":
|
|
137
|
+
styles.top = "50%";
|
|
138
|
+
styles.transform = "translateY(-50%)";
|
|
139
|
+
break;
|
|
140
|
+
case "end":
|
|
141
|
+
styles.bottom = "0";
|
|
142
|
+
break;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return styles;
|
|
146
|
+
});
|
|
147
|
+
onMounted(() => {
|
|
148
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
149
|
+
});
|
|
150
|
+
onUnmounted(() => {
|
|
151
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
152
|
+
});
|
|
153
|
+
return {
|
|
154
|
+
is_open,
|
|
155
|
+
trigger_ref,
|
|
156
|
+
content_ref,
|
|
157
|
+
dropdown_id,
|
|
158
|
+
active_item_index,
|
|
159
|
+
items_count,
|
|
160
|
+
position_styles,
|
|
161
|
+
open,
|
|
162
|
+
close,
|
|
163
|
+
toggle,
|
|
164
|
+
handleTriggerClick,
|
|
165
|
+
handleTriggerKeyDown,
|
|
166
|
+
handleContentKeyDown,
|
|
167
|
+
registerItem,
|
|
168
|
+
setActiveItem
|
|
169
|
+
};
|
|
170
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type Ref } from "vue";
|
|
2
|
+
import type { FileInputProps, FileInputReturn } from "../types/file-input";
|
|
3
|
+
/**
|
|
4
|
+
* FileInputコンポーネントのロジックを提供するComposable
|
|
5
|
+
*/
|
|
6
|
+
export declare const useFileInput: (props: Ref<FileInputProps>, input_ref: Ref<HTMLInputElement | null>) => FileInputReturn;
|