@soave/ui 0.2.1 → 0.3.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.
Files changed (109) hide show
  1. package/dist/adapters/types.d.ts +1 -1
  2. package/dist/components/Button.vue +36 -0
  3. package/dist/components/Card.vue +23 -0
  4. package/dist/components/Checkbox.vue +44 -0
  5. package/dist/components/Dialog.vue +99 -0
  6. package/dist/components/Input.vue +42 -0
  7. package/dist/components/RadioGroup.vue +35 -0
  8. package/dist/components/RadioItem.vue +55 -0
  9. package/dist/components/Select.vue +95 -0
  10. package/dist/components/SelectContent.vue +40 -0
  11. package/dist/components/SelectItem.vue +44 -0
  12. package/dist/components/SelectTrigger.vue +61 -0
  13. package/dist/components/Switch.vue +43 -0
  14. package/dist/components/Textarea.vue +49 -0
  15. package/dist/components/index.d.ts +13 -0
  16. package/dist/components/index.mjs +13 -0
  17. package/dist/composables/useButton.d.ts +2 -2
  18. package/dist/composables/useButton.mjs +14 -41
  19. package/dist/composables/useCard.d.ts +2 -2
  20. package/dist/composables/useCard.mjs +5 -18
  21. package/dist/composables/useCheckbox.d.ts +2 -1
  22. package/dist/composables/useCheckbox.mjs +11 -44
  23. package/dist/composables/useFileInput.d.ts +2 -0
  24. package/dist/composables/useFileInput.mjs +15 -30
  25. package/dist/composables/useForm.mjs +2 -2
  26. package/dist/composables/useInput.d.ts +2 -2
  27. package/dist/composables/useInput.mjs +12 -33
  28. package/dist/composables/useRadio.d.ts +2 -1
  29. package/dist/composables/useRadio.mjs +10 -42
  30. package/dist/composables/useSelect.d.ts +3 -0
  31. package/dist/composables/useSelect.mjs +20 -49
  32. package/dist/composables/useSwitch.d.ts +2 -1
  33. package/dist/composables/useSwitch.mjs +10 -43
  34. package/dist/composables/useTextarea.d.ts +2 -1
  35. package/dist/composables/useTextarea.mjs +12 -33
  36. package/dist/composables/useToast.mjs +1 -1
  37. package/dist/env.d.ts +11 -0
  38. package/dist/index.d.ts +1 -1
  39. package/dist/index.mjs +1 -1
  40. package/dist/types/button.d.ts +19 -5
  41. package/dist/types/card.d.ts +11 -2
  42. package/dist/types/checkbox.d.ts +15 -6
  43. package/dist/types/composables.d.ts +52 -24
  44. package/dist/types/config.d.ts +1 -0
  45. package/dist/types/file-input.d.ts +15 -5
  46. package/dist/types/form.d.ts +5 -5
  47. package/dist/types/input.d.ts +17 -6
  48. package/dist/types/radio.d.ts +14 -6
  49. package/dist/types/select.d.ts +25 -7
  50. package/dist/types/switch.d.ts +14 -5
  51. package/dist/types/textarea.d.ts +20 -7
  52. package/dist/types/toast.d.ts +2 -2
  53. package/dist/types/tooltip.d.ts +3 -0
  54. package/dist/types/tooltip.mjs +1 -0
  55. package/package.json +1 -9
  56. package/dist/components/ui/Alert.vue +0 -41
  57. package/dist/components/ui/AlertDescription.vue +0 -22
  58. package/dist/components/ui/AlertTitle.vue +0 -22
  59. package/dist/components/ui/Button.vue +0 -85
  60. package/dist/components/ui/Card.vue +0 -39
  61. package/dist/components/ui/CardContent.vue +0 -22
  62. package/dist/components/ui/CardDescription.vue +0 -22
  63. package/dist/components/ui/CardFooter.vue +0 -22
  64. package/dist/components/ui/CardHeader.vue +0 -22
  65. package/dist/components/ui/CardTitle.vue +0 -22
  66. package/dist/components/ui/Checkbox.vue +0 -94
  67. package/dist/components/ui/Dialog.vue +0 -110
  68. package/dist/components/ui/DialogDescription.vue +0 -22
  69. package/dist/components/ui/DialogFooter.vue +0 -22
  70. package/dist/components/ui/DialogHeader.vue +0 -22
  71. package/dist/components/ui/DialogTitle.vue +0 -22
  72. package/dist/components/ui/DropdownMenu.vue +0 -32
  73. package/dist/components/ui/DropdownMenuContent.vue +0 -69
  74. package/dist/components/ui/DropdownMenuItem.vue +0 -71
  75. package/dist/components/ui/DropdownMenuLabel.vue +0 -20
  76. package/dist/components/ui/DropdownMenuSeparator.vue +0 -16
  77. package/dist/components/ui/DropdownMenuTrigger.vue +0 -38
  78. package/dist/components/ui/FileInput.vue +0 -153
  79. package/dist/components/ui/FormError.vue +0 -20
  80. package/dist/components/ui/FormField.vue +0 -12
  81. package/dist/components/ui/FormInput.vue +0 -46
  82. package/dist/components/ui/FormLabel.vue +0 -19
  83. package/dist/components/ui/FormTextarea.vue +0 -39
  84. package/dist/components/ui/Input.vue +0 -72
  85. package/dist/components/ui/Popover.vue +0 -35
  86. package/dist/components/ui/PopoverContent.vue +0 -66
  87. package/dist/components/ui/PopoverTrigger.vue +0 -36
  88. package/dist/components/ui/RadioGroup.vue +0 -47
  89. package/dist/components/ui/RadioItem.vue +0 -62
  90. package/dist/components/ui/Select.vue +0 -62
  91. package/dist/components/ui/SelectContent.vue +0 -55
  92. package/dist/components/ui/SelectItem.vue +0 -55
  93. package/dist/components/ui/SelectTrigger.vue +0 -70
  94. package/dist/components/ui/SelectValue.vue +0 -27
  95. package/dist/components/ui/Sheet.vue +0 -148
  96. package/dist/components/ui/SheetDescription.vue +0 -22
  97. package/dist/components/ui/SheetFooter.vue +0 -22
  98. package/dist/components/ui/SheetHeader.vue +0 -22
  99. package/dist/components/ui/SheetTitle.vue +0 -22
  100. package/dist/components/ui/Switch.vue +0 -63
  101. package/dist/components/ui/Textarea.vue +0 -73
  102. package/dist/components/ui/Toast.vue +0 -116
  103. package/dist/components/ui/Toaster.vue +0 -76
  104. package/dist/components/ui/Tooltip.vue +0 -42
  105. package/dist/components/ui/TooltipContent.vue +0 -71
  106. package/dist/components/ui/TooltipTrigger.vue +0 -39
  107. package/dist/components/ui/UIProvider.vue +0 -23
  108. package/dist/components/ui/index.d.ts +0 -52
  109. package/dist/components/ui/index.mjs +0 -52
@@ -1,35 +0,0 @@
1
- <template>
2
- <div class="relative inline-block" :class="props.class">
3
- <slot />
4
- </div>
5
- </template>
6
-
7
- <script setup lang="ts">
8
- import { provide, ref, type Ref } from "vue"
9
- import { usePopover } from "../../composables/usePopover"
10
- import type { PopoverSide, PopoverAlign } from "../../types/popover"
11
- import { POPOVER_CONTEXT_KEY } from "../../types/popover"
12
-
13
- interface Props {
14
- side?: PopoverSide
15
- align?: PopoverAlign
16
- modal?: boolean
17
- class?: string
18
- }
19
-
20
- const props = withDefaults(defineProps<Props>(), {
21
- side: "bottom",
22
- align: "center",
23
- modal: false
24
- })
25
-
26
- const popover_props = ref({
27
- side: props.side,
28
- align: props.align,
29
- modal: props.modal
30
- })
31
-
32
- const popover = usePopover(popover_props as Ref<typeof popover_props.value>)
33
-
34
- provide(POPOVER_CONTEXT_KEY, popover)
35
- </script>
@@ -1,66 +0,0 @@
1
- <template>
2
- <Transition name="popover">
3
- <div
4
- v-if="is_open"
5
- ref="content_element"
6
- :id="popover_id"
7
- role="dialog"
8
- aria-modal="false"
9
- :style="position_styles"
10
- :class="[computed_classes, props.class]"
11
- tabindex="-1"
12
- >
13
- <slot />
14
- </div>
15
- </Transition>
16
- </template>
17
-
18
- <script setup lang="ts">
19
- import { inject, ref, computed, watchEffect, onMounted } from "vue"
20
- import { useStyleAdapter } from "../../composables"
21
- import type { PopoverContentProps } from "../../types/popover"
22
- import { POPOVER_CONTEXT_KEY } from "../../types/popover"
23
- import type { PopoverState } from "../../types/composables"
24
-
25
- const props = withDefaults(defineProps<PopoverContentProps>(), {
26
- unstyled: false
27
- })
28
-
29
- const context = inject(POPOVER_CONTEXT_KEY)
30
-
31
- if (!context) {
32
- throw new Error("PopoverContent must be used within a Popover component")
33
- }
34
-
35
- const {
36
- is_open,
37
- content_ref,
38
- popover_id,
39
- position_styles
40
- } = context
41
-
42
- const style_adapter = useStyleAdapter()
43
- const content_element = ref<HTMLElement | null>(null)
44
-
45
- watchEffect(() => {
46
- content_ref.value = content_element.value
47
- })
48
-
49
- onMounted(() => {
50
- if (is_open.value && content_element.value) {
51
- content_element.value.focus()
52
- }
53
- })
54
-
55
- const computed_classes = computed(() => {
56
- if (props.unstyled) return ""
57
- const state: PopoverState = {
58
- is_open: is_open.value
59
- }
60
- return style_adapter.getClasses("popover", state)
61
- })
62
- </script>
63
-
64
- <style scoped>
65
- .popover-enter-active,.popover-leave-active{transition:opacity .2s ease,transform .2s ease}.popover-enter-from,.popover-leave-to{opacity:0;transform:scale(.95)}
66
- </style>
@@ -1,36 +0,0 @@
1
- <template>
2
- <button
3
- ref="trigger_element"
4
- type="button"
5
- :aria-expanded="is_open"
6
- :aria-controls="popover_id"
7
- :aria-haspopup="true"
8
- @click="handleTriggerClick"
9
- >
10
- <slot />
11
- </button>
12
- </template>
13
-
14
- <script setup lang="ts">
15
- import { inject, ref, watchEffect } from "vue"
16
- import { POPOVER_CONTEXT_KEY } from "../../types/popover"
17
-
18
- const context = inject(POPOVER_CONTEXT_KEY)
19
-
20
- if (!context) {
21
- throw new Error("PopoverTrigger must be used within a Popover component")
22
- }
23
-
24
- const {
25
- is_open,
26
- trigger_ref,
27
- popover_id,
28
- handleTriggerClick
29
- } = context
30
-
31
- const trigger_element = ref<HTMLElement | null>(null)
32
-
33
- watchEffect(() => {
34
- trigger_ref.value = trigger_element.value
35
- })
36
- </script>
@@ -1,47 +0,0 @@
1
- <template>
2
- <div
3
- role="radiogroup"
4
- :class="[computed_classes, props.class]"
5
- >
6
- <slot />
7
- </div>
8
- </template>
9
-
10
- <script setup lang="ts">
11
- import { provide, toRef, computed } from "vue"
12
- import { useStyleAdapter } from "../../composables"
13
- import type { RadioGroupProps, RadioGroupContext } from "../../types/radio"
14
- import { RADIO_GROUP_KEY } from "../../types/radio"
15
-
16
- interface Props extends RadioGroupProps {
17
- modelValue?: string
18
- }
19
-
20
- const props = withDefaults(defineProps<Props>(), {
21
- modelValue: "",
22
- disabled: false,
23
- orientation: "vertical",
24
- unstyled: false
25
- })
26
-
27
- const emit = defineEmits<{
28
- "update:modelValue": [value: string]
29
- }>()
30
-
31
- const style_adapter = useStyleAdapter()
32
-
33
- const computed_classes = computed(() => {
34
- if (props.unstyled) return ""
35
- return style_adapter.getClasses("radio-group", { orientation: props.orientation })
36
- })
37
-
38
- const context: RadioGroupContext = {
39
- model_value: toRef(() => props.modelValue),
40
- disabled: toRef(() => props.disabled),
41
- updateValue: (value: string) => {
42
- emit("update:modelValue", value)
43
- }
44
- }
45
-
46
- provide(RADIO_GROUP_KEY, context)
47
- </script>
@@ -1,62 +0,0 @@
1
- <template>
2
- <button
3
- type="button"
4
- :class="[computed_classes, props.class]"
5
- :disabled="is_disabled"
6
- role="radio"
7
- :aria-checked="is_checked"
8
- :aria-disabled="is_disabled || undefined"
9
- @click="handleClick"
10
- >
11
- <span
12
- v-if="is_checked"
13
- :class="indicator_classes"
14
- >
15
- <svg
16
- class="fill-current"
17
- viewBox="0 0 24 24"
18
- >
19
- <circle cx="12" cy="12" r="6" />
20
- </svg>
21
- </span>
22
- </button>
23
- </template>
24
-
25
- <script setup lang="ts">
26
- import { inject, computed } from "vue"
27
- import { useStyleAdapter } from "../../composables"
28
- import type { RadioItemProps, RadioGroupContext } from "../../types/radio"
29
- import { RADIO_GROUP_KEY } from "../../types/radio"
30
- import type { RadioState } from "../../types/composables"
31
-
32
- const props = withDefaults(defineProps<RadioItemProps>(), {
33
- disabled: false,
34
- unstyled: false
35
- })
36
-
37
- const context = inject<RadioGroupContext>(RADIO_GROUP_KEY)
38
- const style_adapter = useStyleAdapter()
39
-
40
- const is_checked = computed(() => context?.model_value.value === props.value)
41
- const is_disabled = computed(() => props.disabled || context?.disabled.value || false)
42
-
43
- const computed_classes = computed(() => {
44
- if (props.unstyled) return ""
45
- const state: RadioState = {
46
- checked: is_checked.value,
47
- disabled: is_disabled.value
48
- }
49
- return style_adapter.getClasses("radio", state)
50
- })
51
-
52
- const indicator_classes = computed(() => {
53
- if (props.unstyled) return ""
54
- return style_adapter.getClasses("radio-indicator", {})
55
- })
56
-
57
- const handleClick = () => {
58
- if (!is_disabled.value && context) {
59
- context.updateValue(props.value)
60
- }
61
- }
62
- </script>
@@ -1,62 +0,0 @@
1
- <template>
2
- <div class="relative">
3
- <slot />
4
- </div>
5
- </template>
6
-
7
- <script setup lang="ts">
8
- import { provide, ref, toRef } from "vue"
9
- import type { SelectProps, SelectContext, SelectSize } from "../../types/select"
10
- import { SELECT_KEY } from "../../types/select"
11
-
12
- interface Props extends SelectProps {
13
- modelValue?: string
14
- class?: string
15
- }
16
-
17
- const props = withDefaults(defineProps<Props>(), {
18
- modelValue: "",
19
- size: "md" as SelectSize,
20
- disabled: false,
21
- placeholder: "Select...",
22
- unstyled: false
23
- })
24
-
25
- const emit = defineEmits<{
26
- "update:modelValue": [value: string]
27
- }>()
28
-
29
- const is_open = ref(false)
30
- const trigger_ref = ref<HTMLElement | null>(null)
31
-
32
- const context: SelectContext = {
33
- model_value: toRef(() => props.modelValue),
34
- is_open,
35
- disabled: toRef(() => props.disabled),
36
- size: toRef(() => props.size ?? "md"),
37
- placeholder: toRef(() => props.placeholder ?? "Select..."),
38
- trigger_ref,
39
- updateValue: (value: string) => {
40
- emit("update:modelValue", value)
41
- is_open.value = false
42
- },
43
- open: () => {
44
- if (!props.disabled) {
45
- is_open.value = true
46
- }
47
- },
48
- close: () => {
49
- is_open.value = false
50
- },
51
- toggle: () => {
52
- if (!props.disabled) {
53
- is_open.value = !is_open.value
54
- }
55
- },
56
- setTriggerRef: (element: HTMLElement | null) => {
57
- trigger_ref.value = element
58
- }
59
- }
60
-
61
- provide(SELECT_KEY, context)
62
- </script>
@@ -1,55 +0,0 @@
1
- <template>
2
- <Teleport to="body">
3
- <div
4
- v-if="context?.is_open.value"
5
- class="fixed inset-0 z-40"
6
- @click="context?.close()"
7
- />
8
- <div
9
- v-if="context?.is_open.value"
10
- :class="[computed_classes, props.class]"
11
- :style="content_style"
12
- :data-state="context?.is_open.value ? 'open' : 'closed'"
13
- data-side="bottom"
14
- role="listbox"
15
- >
16
- <div class="p-1">
17
- <slot />
18
- </div>
19
- </div>
20
- </Teleport>
21
- </template>
22
-
23
- <script setup lang="ts">
24
- import { inject, computed } from "vue"
25
- import { useStyleAdapter } from "../../composables"
26
- import type { SelectContext, SelectContentProps } from "../../types/select"
27
- import { SELECT_KEY } from "../../types/select"
28
-
29
- const props = withDefaults(defineProps<SelectContentProps>(), {
30
- unstyled: false
31
- })
32
-
33
- const context = inject<SelectContext>(SELECT_KEY)
34
- const style_adapter = useStyleAdapter()
35
-
36
- const computed_classes = computed(() => {
37
- if (props.unstyled) return ""
38
- return style_adapter.getClasses("select-content", {})
39
- })
40
-
41
- const content_style = computed(() => {
42
- const trigger_element = context?.trigger_ref.value
43
- if (!trigger_element) {
44
- return {}
45
- }
46
-
47
- const rect = trigger_element.getBoundingClientRect()
48
- return {
49
- position: "fixed" as const,
50
- top: `${rect.bottom + 4}px`,
51
- left: `${rect.left}px`,
52
- width: `${rect.width}px`
53
- }
54
- })
55
- </script>
@@ -1,55 +0,0 @@
1
- <template>
2
- <div
3
- :class="[computed_classes, props.class]"
4
- :data-disabled="is_disabled ? '' : undefined"
5
- role="option"
6
- :aria-selected="is_selected"
7
- @click="handleClick"
8
- >
9
- <span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
10
- <svg
11
- v-if="is_selected"
12
- class="h-4 w-4"
13
- xmlns="http://www.w3.org/2000/svg"
14
- viewBox="0 0 24 24"
15
- fill="none"
16
- stroke="currentColor"
17
- stroke-width="2"
18
- stroke-linecap="round"
19
- stroke-linejoin="round"
20
- >
21
- <polyline points="20 6 9 17 4 12" />
22
- </svg>
23
- </span>
24
- <slot />
25
- </div>
26
- </template>
27
-
28
- <script setup lang="ts">
29
- import { inject, computed } from "vue"
30
- import { useStyleAdapter } from "../../composables"
31
- import type { SelectContext, SelectItemProps } from "../../types/select"
32
- import { SELECT_KEY } from "../../types/select"
33
-
34
- const props = withDefaults(defineProps<SelectItemProps>(), {
35
- disabled: false,
36
- unstyled: false
37
- })
38
-
39
- const context = inject<SelectContext>(SELECT_KEY)
40
- const style_adapter = useStyleAdapter()
41
-
42
- const is_selected = computed(() => context?.model_value.value === props.value)
43
- const is_disabled = computed(() => props.disabled)
44
-
45
- const computed_classes = computed(() => {
46
- if (props.unstyled) return ""
47
- return style_adapter.getClasses("select-item", {})
48
- })
49
-
50
- const handleClick = () => {
51
- if (!is_disabled.value && context) {
52
- context.updateValue(props.value)
53
- }
54
- }
55
- </script>
@@ -1,70 +0,0 @@
1
- <template>
2
- <button
3
- ref="button_ref"
4
- type="button"
5
- :class="[computed_classes, props.class]"
6
- :disabled="is_disabled"
7
- :aria-expanded="context?.is_open.value"
8
- aria-haspopup="listbox"
9
- @click="handleClick"
10
- >
11
- <slot />
12
- <svg
13
- :class="icon_classes"
14
- xmlns="http://www.w3.org/2000/svg"
15
- viewBox="0 0 24 24"
16
- fill="none"
17
- stroke="currentColor"
18
- stroke-width="2"
19
- stroke-linecap="round"
20
- stroke-linejoin="round"
21
- >
22
- <path d="m6 9 6 6 6-6" />
23
- </svg>
24
- </button>
25
- </template>
26
-
27
- <script setup lang="ts">
28
- import { inject, ref, computed, onMounted, onUnmounted } from "vue"
29
- import { useStyleAdapter } from "../../composables"
30
- import type { SelectContext, SelectTriggerProps } from "../../types/select"
31
- import { SELECT_KEY } from "../../types/select"
32
- import type { SelectState } from "../../types/composables"
33
-
34
- const props = withDefaults(defineProps<SelectTriggerProps>(), {
35
- unstyled: false
36
- })
37
-
38
- const context = inject<SelectContext>(SELECT_KEY)
39
- const style_adapter = useStyleAdapter()
40
- const button_ref = ref<HTMLButtonElement | null>(null)
41
-
42
- const is_disabled = computed(() => context?.disabled.value ?? false)
43
-
44
- const computed_classes = computed(() => {
45
- if (props.unstyled) return ""
46
- const state: SelectState = {
47
- size: context?.size.value ?? "md",
48
- disabled: is_disabled.value,
49
- is_open: context?.is_open.value ?? false
50
- }
51
- return style_adapter.getClasses("select", state)
52
- })
53
-
54
- const icon_classes = computed(() => {
55
- if (props.unstyled) return ""
56
- return style_adapter.getClasses("select-trigger-icon", {})
57
- })
58
-
59
- onMounted(() => {
60
- context?.setTriggerRef(button_ref.value)
61
- })
62
-
63
- onUnmounted(() => {
64
- context?.setTriggerRef(null)
65
- })
66
-
67
- const handleClick = () => {
68
- context?.toggle()
69
- }
70
- </script>
@@ -1,27 +0,0 @@
1
- <template>
2
- <span :class="[computed_classes, props.class]">
3
- <slot v-if="hasValue" />
4
- <template v-else>{{ context?.placeholder.value }}</template>
5
- </span>
6
- </template>
7
-
8
- <script setup lang="ts">
9
- import { computed, inject } from "vue"
10
- import { useStyleAdapter } from "../../composables"
11
- import type { SelectContext, SelectValueProps } from "../../types/select"
12
- import { SELECT_KEY } from "../../types/select"
13
-
14
- const props = withDefaults(defineProps<SelectValueProps>(), {
15
- unstyled: false
16
- })
17
-
18
- const context = inject<SelectContext>(SELECT_KEY)
19
- const style_adapter = useStyleAdapter()
20
-
21
- const hasValue = computed(() => !!context?.model_value.value)
22
-
23
- const computed_classes = computed(() => {
24
- if (props.unstyled) return ""
25
- return style_adapter.getClasses("select-value", { hasValue: hasValue.value })
26
- })
27
- </script>
@@ -1,148 +0,0 @@
1
- <template>
2
- <Teleport to="body">
3
- <Transition name="sheet-overlay">
4
- <div
5
- v-if="is_open"
6
- :class="overlay_classes"
7
- @click="handleOverlayClick"
8
- />
9
- </Transition>
10
-
11
- <Transition :name="transition_name">
12
- <div
13
- v-if="is_open"
14
- ref="sheet_element"
15
- role="dialog"
16
- aria-modal="true"
17
- :class="[computed_classes, props.class]"
18
- tabindex="-1"
19
- @keydown.escape="close"
20
- >
21
- <slot />
22
-
23
- <button
24
- v-if="show_close_button"
25
- type="button"
26
- :class="close_button_classes"
27
- aria-label="Close"
28
- @click="close"
29
- >
30
- <svg
31
- xmlns="http://www.w3.org/2000/svg"
32
- width="24"
33
- height="24"
34
- viewBox="0 0 24 24"
35
- fill="none"
36
- stroke="currentColor"
37
- stroke-width="2"
38
- stroke-linecap="round"
39
- stroke-linejoin="round"
40
- >
41
- <path d="M18 6 6 18" />
42
- <path d="m6 6 12 12" />
43
- </svg>
44
- </button>
45
- </div>
46
- </Transition>
47
- </Teleport>
48
- </template>
49
-
50
- <script setup lang="ts">
51
- import { ref, computed, watch, provide, onMounted, onUnmounted } from "vue"
52
- import { useStyleAdapter } from "../../composables"
53
- import type { SheetSide, SheetContext, SheetProps } from "../../types/sheet"
54
- import { SHEET_CONTEXT_KEY } from "../../types/sheet"
55
- import type { SheetState } from "../../types/composables"
56
-
57
- interface Props extends SheetProps {}
58
-
59
- const props = withDefaults(defineProps<Props>(), {
60
- open: false,
61
- side: "right",
62
- showCloseButton: true,
63
- unstyled: false
64
- })
65
-
66
- const emit = defineEmits<{
67
- "update:open": [value: boolean]
68
- }>()
69
-
70
-
71
- const style_adapter = useStyleAdapter()
72
- const is_open = ref(props.open)
73
- const sheet_element = ref<HTMLElement | null>(null)
74
-
75
- watch(() => props.open, (value) => {
76
- is_open.value = value
77
- })
78
-
79
- const open = (): void => {
80
- is_open.value = true
81
- emit("update:open", true)
82
- }
83
-
84
- const close = (): void => {
85
- is_open.value = false
86
- emit("update:open", false)
87
- }
88
-
89
- const handleOverlayClick = (): void => {
90
- close()
91
- }
92
-
93
- const handleKeyDown = (event: KeyboardEvent): void => {
94
- if (event.key === "Escape" && is_open.value) {
95
- close()
96
- }
97
- }
98
-
99
- onMounted(() => {
100
- document.addEventListener("keydown", handleKeyDown)
101
- })
102
-
103
- onUnmounted(() => {
104
- document.removeEventListener("keydown", handleKeyDown)
105
- })
106
-
107
- watch(is_open, (open) => {
108
- if (open) {
109
- document.body.style.overflow = "hidden"
110
- } else {
111
- document.body.style.overflow = ""
112
- }
113
- })
114
-
115
- const side = computed(() => props.side ?? "right")
116
- const show_close_button = computed(() => props.showCloseButton)
117
- const transition_name = computed(() => `sheet-${side.value}`)
118
-
119
- const computed_classes = computed(() => {
120
- if (props.unstyled) return ""
121
- const state: SheetState = {
122
- is_open: is_open.value,
123
- side: side.value
124
- }
125
- return style_adapter.getClasses("sheet", state)
126
- })
127
-
128
- const overlay_classes = computed(() => {
129
- if (props.unstyled) return ""
130
- return style_adapter.getClasses("sheet-overlay", {})
131
- })
132
-
133
- const close_button_classes = computed(() => {
134
- if (props.unstyled) return ""
135
- return style_adapter.getClasses("sheet-close", {})
136
- })
137
-
138
- provide(SHEET_CONTEXT_KEY, {
139
- is_open: is_open.value,
140
- side: side.value,
141
- open,
142
- close
143
- })
144
- </script>
145
-
146
- <style scoped>
147
- .sheet-overlay-enter-active,.sheet-overlay-leave-active{transition:opacity .3s ease}.sheet-overlay-enter-from,.sheet-overlay-leave-to{opacity:0}.sheet-bottom-enter-active,.sheet-bottom-leave-active,.sheet-left-enter-active,.sheet-left-leave-active,.sheet-right-enter-active,.sheet-right-leave-active,.sheet-top-enter-active,.sheet-top-leave-active{transition:transform .3s ease}.sheet-right-enter-from,.sheet-right-leave-to{transform:translateX(100%)}.sheet-left-enter-from,.sheet-left-leave-to{transform:translateX(-100%)}.sheet-top-enter-from,.sheet-top-leave-to{transform:translateY(-100%)}.sheet-bottom-enter-from,.sheet-bottom-leave-to{transform:translateY(100%)}
148
- </style>
@@ -1,22 +0,0 @@
1
- <template>
2
- <p :class="[computed_classes, props.class]">
3
- <slot />
4
- </p>
5
- </template>
6
-
7
- <script setup lang="ts">
8
- import { computed } from "vue"
9
- import { useStyleAdapter } from "../../composables"
10
- import type { SheetDescriptionProps } from "../../types/sheet"
11
-
12
- const props = withDefaults(defineProps<SheetDescriptionProps>(), {
13
- unstyled: false
14
- })
15
-
16
- const style_adapter = useStyleAdapter()
17
-
18
- const computed_classes = computed(() => {
19
- if (props.unstyled) return ""
20
- return style_adapter.getClasses("sheet-description", {})
21
- })
22
- </script>