@soave/ui 0.2.2 → 0.3.1

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 (100) hide show
  1. package/dist/components/Button.vue +36 -0
  2. package/dist/components/Card.vue +23 -0
  3. package/dist/components/Checkbox.vue +44 -0
  4. package/dist/components/Dialog.vue +99 -0
  5. package/dist/components/Input.vue +48 -0
  6. package/dist/components/RadioGroup.vue +35 -0
  7. package/dist/components/RadioItem.vue +55 -0
  8. package/dist/components/Select.vue +95 -0
  9. package/dist/components/SelectContent.vue +40 -0
  10. package/dist/components/SelectItem.vue +44 -0
  11. package/dist/components/SelectTrigger.vue +61 -0
  12. package/dist/components/Switch.vue +43 -0
  13. package/dist/components/Textarea.vue +55 -0
  14. package/dist/components/index.d.ts +13 -0
  15. package/dist/components/index.mjs +13 -0
  16. package/dist/composables/useButton.d.ts +2 -2
  17. package/dist/composables/useButton.mjs +14 -41
  18. package/dist/composables/useCard.d.ts +2 -2
  19. package/dist/composables/useCard.mjs +5 -18
  20. package/dist/composables/useCheckbox.d.ts +2 -1
  21. package/dist/composables/useCheckbox.mjs +11 -44
  22. package/dist/composables/useFileInput.d.ts +2 -0
  23. package/dist/composables/useFileInput.mjs +15 -30
  24. package/dist/composables/useInput.d.ts +2 -2
  25. package/dist/composables/useInput.mjs +12 -33
  26. package/dist/composables/useRadio.d.ts +2 -1
  27. package/dist/composables/useRadio.mjs +10 -42
  28. package/dist/composables/useSelect.d.ts +3 -0
  29. package/dist/composables/useSelect.mjs +20 -49
  30. package/dist/composables/useSwitch.d.ts +2 -1
  31. package/dist/composables/useSwitch.mjs +10 -43
  32. package/dist/composables/useTextarea.d.ts +2 -1
  33. package/dist/composables/useTextarea.mjs +12 -33
  34. package/dist/index.d.ts +1 -1
  35. package/dist/index.mjs +1 -1
  36. package/dist/types/button.d.ts +19 -5
  37. package/dist/types/card.d.ts +11 -2
  38. package/dist/types/checkbox.d.ts +15 -6
  39. package/dist/types/composables.d.ts +33 -5
  40. package/dist/types/file-input.d.ts +15 -5
  41. package/dist/types/input.d.ts +17 -6
  42. package/dist/types/radio.d.ts +14 -6
  43. package/dist/types/select.d.ts +25 -7
  44. package/dist/types/switch.d.ts +14 -5
  45. package/dist/types/textarea.d.ts +18 -7
  46. package/package.json +1 -9
  47. package/dist/components/ui/Alert.vue +0 -41
  48. package/dist/components/ui/AlertDescription.vue +0 -22
  49. package/dist/components/ui/AlertTitle.vue +0 -22
  50. package/dist/components/ui/Button.vue +0 -85
  51. package/dist/components/ui/Card.vue +0 -39
  52. package/dist/components/ui/CardContent.vue +0 -22
  53. package/dist/components/ui/CardDescription.vue +0 -22
  54. package/dist/components/ui/CardFooter.vue +0 -22
  55. package/dist/components/ui/CardHeader.vue +0 -22
  56. package/dist/components/ui/CardTitle.vue +0 -22
  57. package/dist/components/ui/Checkbox.vue +0 -94
  58. package/dist/components/ui/Dialog.vue +0 -110
  59. package/dist/components/ui/DialogDescription.vue +0 -22
  60. package/dist/components/ui/DialogFooter.vue +0 -22
  61. package/dist/components/ui/DialogHeader.vue +0 -22
  62. package/dist/components/ui/DialogTitle.vue +0 -22
  63. package/dist/components/ui/DropdownMenu.vue +0 -32
  64. package/dist/components/ui/DropdownMenuContent.vue +0 -69
  65. package/dist/components/ui/DropdownMenuItem.vue +0 -71
  66. package/dist/components/ui/DropdownMenuLabel.vue +0 -20
  67. package/dist/components/ui/DropdownMenuSeparator.vue +0 -16
  68. package/dist/components/ui/DropdownMenuTrigger.vue +0 -38
  69. package/dist/components/ui/FileInput.vue +0 -153
  70. package/dist/components/ui/FormError.vue +0 -20
  71. package/dist/components/ui/FormField.vue +0 -12
  72. package/dist/components/ui/FormInput.vue +0 -46
  73. package/dist/components/ui/FormLabel.vue +0 -19
  74. package/dist/components/ui/FormTextarea.vue +0 -39
  75. package/dist/components/ui/Input.vue +0 -72
  76. package/dist/components/ui/Popover.vue +0 -35
  77. package/dist/components/ui/PopoverContent.vue +0 -66
  78. package/dist/components/ui/PopoverTrigger.vue +0 -36
  79. package/dist/components/ui/RadioGroup.vue +0 -47
  80. package/dist/components/ui/RadioItem.vue +0 -62
  81. package/dist/components/ui/Select.vue +0 -62
  82. package/dist/components/ui/SelectContent.vue +0 -55
  83. package/dist/components/ui/SelectItem.vue +0 -55
  84. package/dist/components/ui/SelectTrigger.vue +0 -70
  85. package/dist/components/ui/SelectValue.vue +0 -27
  86. package/dist/components/ui/Sheet.vue +0 -148
  87. package/dist/components/ui/SheetDescription.vue +0 -22
  88. package/dist/components/ui/SheetFooter.vue +0 -22
  89. package/dist/components/ui/SheetHeader.vue +0 -22
  90. package/dist/components/ui/SheetTitle.vue +0 -22
  91. package/dist/components/ui/Switch.vue +0 -63
  92. package/dist/components/ui/Textarea.vue +0 -73
  93. package/dist/components/ui/Toast.vue +0 -116
  94. package/dist/components/ui/Toaster.vue +0 -76
  95. package/dist/components/ui/Tooltip.vue +0 -41
  96. package/dist/components/ui/TooltipContent.vue +0 -71
  97. package/dist/components/ui/TooltipTrigger.vue +0 -39
  98. package/dist/components/ui/UIProvider.vue +0 -23
  99. package/dist/components/ui/index.d.ts +0 -52
  100. package/dist/components/ui/index.mjs +0 -52
@@ -0,0 +1,36 @@
1
+ <template>
2
+ <button
3
+ :disabled="composable.state.value.disabled || composable.state.value.loading"
4
+ :type="composable.state.value.type"
5
+ v-bind="composable.aria_attributes.value"
6
+ @click="handleClick"
7
+ >
8
+ <slot />
9
+ </button>
10
+ </template>
11
+
12
+ <script setup lang="ts">
13
+ import { toRef } from "vue"
14
+ import { useButton } from "../../composables/useButton"
15
+ import type { ButtonProps } from "../../types/button"
16
+
17
+ const props = withDefaults(defineProps<ButtonProps>(), {
18
+ variant: "primary",
19
+ size: "md",
20
+ disabled: false,
21
+ loading: false,
22
+ type: "button"
23
+ })
24
+
25
+ const emit = defineEmits<{
26
+ click: [event: MouseEvent]
27
+ }>()
28
+
29
+ const composable = useButton(toRef(() => props))
30
+
31
+ const handleClick = (event: MouseEvent) => {
32
+ if (!composable.state.value.disabled && !composable.state.value.loading) {
33
+ emit("click", event)
34
+ }
35
+ }
36
+ </script>
@@ -0,0 +1,23 @@
1
+ <template>
2
+ <div>
3
+ <slot />
4
+ </div>
5
+ </template>
6
+
7
+ <script setup lang="ts">
8
+ import { toRef } from "vue"
9
+ import { useCard } from "../../composables/useCard"
10
+ import type { CardProps } from "../../types/card"
11
+
12
+ const props = withDefaults(defineProps<CardProps>(), {
13
+ padding: "md"
14
+ })
15
+
16
+ // Composable is available for state access if needed
17
+ const composable = useCard(toRef(() => props))
18
+
19
+ // Export state for external access
20
+ defineExpose({
21
+ state: composable.state
22
+ })
23
+ </script>
@@ -0,0 +1,44 @@
1
+ <template>
2
+ <button
3
+ type="button"
4
+ :disabled="composable.state.value.disabled"
5
+ :data-state="dataState"
6
+ v-bind="composable.aria_attributes.value"
7
+ @click="handleClick"
8
+ @keydown.space.prevent="handleClick"
9
+ >
10
+ <slot :checked="model" :indeterminate="composable.state.value.indeterminate" />
11
+ </button>
12
+ </template>
13
+
14
+ <script setup lang="ts">
15
+ import { toRef, computed } from "vue"
16
+ import { useCheckbox } from "../../composables/useCheckbox"
17
+ import type { CheckboxProps } from "../../types/checkbox"
18
+
19
+ const props = withDefaults(defineProps<CheckboxProps>(), {
20
+ size: "md",
21
+ disabled: false,
22
+ indeterminate: false
23
+ })
24
+
25
+ const model = defineModel<boolean>({ default: false })
26
+
27
+ const emit = defineEmits<{
28
+ change: [checked: boolean]
29
+ }>()
30
+
31
+ const composable = useCheckbox(toRef(() => props), model)
32
+
33
+ const dataState = computed(() => {
34
+ if (composable.state.value.indeterminate) return "indeterminate"
35
+ return model.value ? "checked" : "unchecked"
36
+ })
37
+
38
+ const handleClick = () => {
39
+ if (!composable.state.value.disabled) {
40
+ model.value = !model.value
41
+ emit("change", model.value)
42
+ }
43
+ }
44
+ </script>
@@ -0,0 +1,99 @@
1
+ <template>
2
+ <Teleport to="body">
3
+ <div
4
+ v-if="is_open"
5
+ role="dialog"
6
+ aria-modal="true"
7
+ :aria-labelledby="titleId"
8
+ :aria-describedby="descriptionId"
9
+ >
10
+ <!-- Overlay -->
11
+ <div
12
+ @click="handleOverlayClick"
13
+ @keydown.escape="close"
14
+ />
15
+ <!-- Content -->
16
+ <div
17
+ ref="content_ref"
18
+ tabindex="-1"
19
+ @keydown.escape="close"
20
+ >
21
+ <slot :close="close" />
22
+ </div>
23
+ </div>
24
+ </Teleport>
25
+ </template>
26
+
27
+ <script setup lang="ts">
28
+ import { ref, watch, onMounted, onUnmounted, provide } from "vue"
29
+ import { useDialog } from "../../composables/useDialog"
30
+ import { DIALOG_KEY } from "../../types/dialog"
31
+ import type { DialogContext } from "../../types/dialog"
32
+
33
+ interface HeadlessDialogProps {
34
+ closeOnOverlay?: boolean
35
+ closeOnEscape?: boolean
36
+ titleId?: string
37
+ descriptionId?: string
38
+ }
39
+
40
+ const props = withDefaults(defineProps<HeadlessDialogProps>(), {
41
+ closeOnOverlay: true,
42
+ closeOnEscape: true
43
+ })
44
+
45
+ const model = defineModel<boolean>("open", { default: false })
46
+
47
+ const content_ref = ref<HTMLElement | null>(null)
48
+ const dialog = useDialog()
49
+ const { is_open, open, close, toggle } = dialog
50
+
51
+ // Sync with v-model
52
+ watch(model, (value) => {
53
+ if (value) {
54
+ open()
55
+ } else {
56
+ close()
57
+ }
58
+ }, { immediate: true })
59
+
60
+ watch(is_open, (value) => {
61
+ model.value = value
62
+ })
63
+
64
+ const handleOverlayClick = () => {
65
+ if (props.closeOnOverlay) {
66
+ close()
67
+ }
68
+ }
69
+
70
+ const handleKeyDown = (event: KeyboardEvent) => {
71
+ if (event.key === "Escape" && props.closeOnEscape && is_open.value) {
72
+ close()
73
+ }
74
+ }
75
+
76
+ // Provide context for child components
77
+ const context: DialogContext = {
78
+ is_open,
79
+ close,
80
+ titleId: props.titleId,
81
+ descriptionId: props.descriptionId
82
+ }
83
+ provide(DIALOG_KEY, context)
84
+
85
+ onMounted(() => {
86
+ document.addEventListener("keydown", handleKeyDown)
87
+ })
88
+
89
+ onUnmounted(() => {
90
+ document.removeEventListener("keydown", handleKeyDown)
91
+ })
92
+
93
+ defineExpose({
94
+ is_open,
95
+ open,
96
+ close,
97
+ toggle
98
+ })
99
+ </script>
@@ -0,0 +1,48 @@
1
+ <template>
2
+ <input
3
+ :type="composable.state.value.type"
4
+ :value="modelValue"
5
+ :disabled="composable.state.value.disabled"
6
+ :readonly="composable.state.value.readonly"
7
+ :placeholder="placeholder"
8
+ :id="id"
9
+ v-bind="composable.aria_attributes.value"
10
+ @input="handleInput"
11
+ @focus="composable.handleFocus"
12
+ @blur="composable.handleBlur"
13
+ />
14
+ </template>
15
+
16
+ <script setup lang="ts">
17
+ import { toRef } from "vue"
18
+ import { useInput } from "../../composables/useInput"
19
+ import type { InputType, InputSize } from "../../types/input"
20
+
21
+ const props = withDefaults(defineProps<{
22
+ type?: InputType
23
+ size?: InputSize
24
+ placeholder?: string
25
+ disabled?: boolean
26
+ readonly?: boolean
27
+ error?: string
28
+ error_id?: string
29
+ id?: string
30
+ modelValue?: string
31
+ }>(), {
32
+ type: "text",
33
+ size: "md",
34
+ disabled: false,
35
+ readonly: false
36
+ })
37
+
38
+ const emit = defineEmits<{
39
+ "update:modelValue": [value: string]
40
+ }>()
41
+
42
+ const composable = useInput(toRef(() => props))
43
+
44
+ const handleInput = (event: Event) => {
45
+ const target = event.target as HTMLInputElement
46
+ emit("update:modelValue", target.value)
47
+ }
48
+ </script>
@@ -0,0 +1,35 @@
1
+ <template>
2
+ <div
3
+ role="radiogroup"
4
+ :aria-orientation="orientation"
5
+ >
6
+ <slot />
7
+ </div>
8
+ </template>
9
+
10
+ <script setup lang="ts">
11
+ import { provide, computed } from "vue"
12
+ import type { RadioGroupProps, RadioGroupContext } from "../../types/radio"
13
+ import { RADIO_GROUP_KEY } from "../../types/radio"
14
+
15
+ const props = withDefaults(defineProps<RadioGroupProps>(), {
16
+ disabled: false,
17
+ orientation: "vertical"
18
+ })
19
+
20
+ const model = defineModel<string>({ default: "" })
21
+
22
+ const updateValue = (value: string) => {
23
+ if (!props.disabled) {
24
+ model.value = value
25
+ }
26
+ }
27
+
28
+ const context: RadioGroupContext = {
29
+ model_value: model,
30
+ disabled: computed(() => props.disabled),
31
+ updateValue
32
+ }
33
+
34
+ provide(RADIO_GROUP_KEY, context)
35
+ </script>
@@ -0,0 +1,55 @@
1
+ <template>
2
+ <button
3
+ type="button"
4
+ :disabled="composable.state.value.disabled"
5
+ :data-state="composable.state.value.checked ? 'checked' : 'unchecked'"
6
+ v-bind="composable.aria_attributes.value"
7
+ @click="handleClick"
8
+ @keydown="handleKeyDown"
9
+ >
10
+ <slot :checked="composable.state.value.checked" :disabled="composable.state.value.disabled" />
11
+ </button>
12
+ </template>
13
+
14
+ <script setup lang="ts">
15
+ import { inject, toRef } from "vue"
16
+ import { useRadioItem } from "../../composables/useRadio"
17
+ import type { RadioItemProps, RadioGroupContext } from "../../types/radio"
18
+ import { RADIO_GROUP_KEY } from "../../types/radio"
19
+ import { COMPONENT_ERRORS } from "../../constants/errors"
20
+
21
+ const props = withDefaults(defineProps<RadioItemProps>(), {
22
+ size: "md",
23
+ disabled: false
24
+ })
25
+
26
+ const context = inject<RadioGroupContext | null>(RADIO_GROUP_KEY, null)
27
+
28
+ if (!context) {
29
+ throw new Error(COMPONENT_ERRORS.PROVIDER_NOT_FOUND)
30
+ }
31
+
32
+ const composable = useRadioItem(toRef(() => props))
33
+
34
+ const handleClick = () => {
35
+ if (!composable.state.value.disabled) {
36
+ context.updateValue(props.value)
37
+ }
38
+ }
39
+
40
+ const handleKeyDown = (event: KeyboardEvent) => {
41
+ if (composable.state.value.disabled) return
42
+
43
+ switch (event.key) {
44
+ case "Enter":
45
+ case " ":
46
+ event.preventDefault()
47
+ context.updateValue(props.value)
48
+ break
49
+ }
50
+ }
51
+
52
+ defineExpose({
53
+ state: composable.state
54
+ })
55
+ </script>
@@ -0,0 +1,95 @@
1
+ <template>
2
+ <div ref="root_ref">
3
+ <slot
4
+ :is_open="context.is_open.value"
5
+ :selected_value="model"
6
+ :open="context.open"
7
+ :close="context.close"
8
+ :toggle="context.toggle"
9
+ />
10
+ </div>
11
+ </template>
12
+
13
+ <script setup lang="ts">
14
+ import { ref, provide, watch, onMounted, onUnmounted, computed } from "vue"
15
+ import type { SelectProps, SelectContext } from "../../types/select"
16
+ import { SELECT_KEY } from "../../types/select"
17
+
18
+ const props = withDefaults(defineProps<SelectProps>(), {
19
+ size: "md",
20
+ disabled: false,
21
+ placeholder: ""
22
+ })
23
+
24
+ const model = defineModel<string>({ default: "" })
25
+
26
+ const root_ref = ref<HTMLElement | null>(null)
27
+ const trigger_ref = ref<HTMLElement | null>(null)
28
+ const is_open = ref(false)
29
+
30
+ const open = () => {
31
+ if (!props.disabled) {
32
+ is_open.value = true
33
+ }
34
+ }
35
+
36
+ const close = () => {
37
+ is_open.value = false
38
+ }
39
+
40
+ const toggle = () => {
41
+ if (is_open.value) {
42
+ close()
43
+ } else {
44
+ open()
45
+ }
46
+ }
47
+
48
+ const updateValue = (value: string) => {
49
+ model.value = value
50
+ close()
51
+ }
52
+
53
+ const setTriggerRef = (element: HTMLElement | null) => {
54
+ trigger_ref.value = element
55
+ }
56
+
57
+ const handleClickOutside = (event: MouseEvent) => {
58
+ if (!is_open.value) return
59
+ const target = event.target as Node
60
+ if (root_ref.value && !root_ref.value.contains(target)) {
61
+ close()
62
+ }
63
+ }
64
+
65
+ const context: SelectContext = {
66
+ model_value: model,
67
+ is_open,
68
+ disabled: computed(() => props.disabled),
69
+ size: computed(() => props.size ?? "md"),
70
+ placeholder: computed(() => props.placeholder ?? ""),
71
+ trigger_ref,
72
+ updateValue,
73
+ open,
74
+ close,
75
+ toggle,
76
+ setTriggerRef
77
+ }
78
+
79
+ provide(SELECT_KEY, context)
80
+
81
+ onMounted(() => {
82
+ document.addEventListener("mousedown", handleClickOutside)
83
+ })
84
+
85
+ onUnmounted(() => {
86
+ document.removeEventListener("mousedown", handleClickOutside)
87
+ })
88
+
89
+ defineExpose({
90
+ is_open,
91
+ open,
92
+ close,
93
+ toggle
94
+ })
95
+ </script>
@@ -0,0 +1,40 @@
1
+ <template>
2
+ <div
3
+ v-if="composable.state.value.is_open"
4
+ role="listbox"
5
+ tabindex="-1"
6
+ @keydown="handleKeyDown"
7
+ >
8
+ <slot />
9
+ </div>
10
+ </template>
11
+
12
+ <script setup lang="ts">
13
+ import { inject } from "vue"
14
+ import { useSelectContent } from "../../composables/useSelect"
15
+ import type { SelectContext } from "../../types/select"
16
+ import { SELECT_KEY } from "../../types/select"
17
+ import { COMPONENT_ERRORS } from "../../constants/errors"
18
+
19
+ const context = inject<SelectContext | null>(SELECT_KEY, null)
20
+
21
+ if (!context) {
22
+ throw new Error(COMPONENT_ERRORS.PROVIDER_NOT_FOUND)
23
+ }
24
+
25
+ const composable = useSelectContent()
26
+
27
+ const handleKeyDown = (event: KeyboardEvent) => {
28
+ switch (event.key) {
29
+ case "Escape":
30
+ event.preventDefault()
31
+ context.close()
32
+ context.trigger_ref.value?.focus()
33
+ break
34
+ }
35
+ }
36
+
37
+ defineExpose({
38
+ state: composable.state
39
+ })
40
+ </script>
@@ -0,0 +1,44 @@
1
+ <template>
2
+ <div
3
+ role="option"
4
+ :aria-selected="composable.state.value.selected"
5
+ :aria-disabled="composable.state.value.disabled"
6
+ :data-state="composable.state.value.selected ? 'selected' : undefined"
7
+ :data-disabled="composable.state.value.disabled ? '' : undefined"
8
+ @click="handleClick"
9
+ @keydown.enter="handleClick"
10
+ @keydown.space.prevent="handleClick"
11
+ >
12
+ <slot :selected="composable.state.value.selected" :disabled="composable.state.value.disabled" />
13
+ </div>
14
+ </template>
15
+
16
+ <script setup lang="ts">
17
+ import { inject, toRef } from "vue"
18
+ import { useSelectItem } from "../../composables/useSelect"
19
+ import type { SelectContext, SelectItemProps } from "../../types/select"
20
+ import { SELECT_KEY } from "../../types/select"
21
+ import { COMPONENT_ERRORS } from "../../constants/errors"
22
+
23
+ const props = withDefaults(defineProps<SelectItemProps>(), {
24
+ disabled: false
25
+ })
26
+
27
+ const context = inject<SelectContext | null>(SELECT_KEY, null)
28
+
29
+ if (!context) {
30
+ throw new Error(COMPONENT_ERRORS.PROVIDER_NOT_FOUND)
31
+ }
32
+
33
+ const composable = useSelectItem(toRef(() => ({ value: props.value, disabled: props.disabled })))
34
+
35
+ const handleClick = () => {
36
+ if (!composable.state.value.disabled) {
37
+ context.updateValue(props.value)
38
+ }
39
+ }
40
+
41
+ defineExpose({
42
+ state: composable.state
43
+ })
44
+ </script>
@@ -0,0 +1,61 @@
1
+ <template>
2
+ <button
3
+ ref="trigger_element"
4
+ type="button"
5
+ :disabled="composable.state.value.disabled"
6
+ :aria-expanded="composable.state.value.is_open"
7
+ aria-haspopup="listbox"
8
+ @click="handleClick"
9
+ @keydown="handleKeyDown"
10
+ >
11
+ <slot :is_open="composable.state.value.is_open" :disabled="composable.state.value.disabled" />
12
+ </button>
13
+ </template>
14
+
15
+ <script setup lang="ts">
16
+ import { ref, inject, onMounted } from "vue"
17
+ import { useSelectTrigger } from "../../composables/useSelect"
18
+ import type { SelectContext } from "../../types/select"
19
+ import { SELECT_KEY } from "../../types/select"
20
+ import { COMPONENT_ERRORS } from "../../constants/errors"
21
+
22
+ const trigger_element = ref<HTMLElement | null>(null)
23
+ const context = inject<SelectContext | null>(SELECT_KEY, null)
24
+
25
+ if (!context) {
26
+ throw new Error(COMPONENT_ERRORS.PROVIDER_NOT_FOUND)
27
+ }
28
+
29
+ const composable = useSelectTrigger()
30
+
31
+ const handleClick = () => {
32
+ if (!composable.state.value.disabled) {
33
+ context.toggle()
34
+ }
35
+ }
36
+
37
+ const handleKeyDown = (event: KeyboardEvent) => {
38
+ if (composable.state.value.disabled) return
39
+
40
+ switch (event.key) {
41
+ case "Enter":
42
+ case " ":
43
+ case "ArrowDown":
44
+ event.preventDefault()
45
+ context.open()
46
+ break
47
+ case "ArrowUp":
48
+ event.preventDefault()
49
+ context.open()
50
+ break
51
+ }
52
+ }
53
+
54
+ onMounted(() => {
55
+ context.setTriggerRef(trigger_element.value)
56
+ })
57
+
58
+ defineExpose({
59
+ state: composable.state
60
+ })
61
+ </script>
@@ -0,0 +1,43 @@
1
+ <template>
2
+ <button
3
+ type="button"
4
+ :disabled="composable.state.value.disabled"
5
+ :data-state="model ? 'checked' : 'unchecked'"
6
+ v-bind="composable.aria_attributes.value"
7
+ @click="handleClick"
8
+ >
9
+ <slot :checked="model">
10
+ <span :data-state="model ? 'checked' : 'unchecked'" />
11
+ </slot>
12
+ </button>
13
+ </template>
14
+
15
+ <script setup lang="ts">
16
+ import { toRef } from "vue"
17
+ import { useSwitch } from "../../composables/useSwitch"
18
+ import type { SwitchProps } from "../../types/switch"
19
+
20
+ const props = withDefaults(defineProps<SwitchProps>(), {
21
+ size: "md",
22
+ disabled: false
23
+ })
24
+
25
+ const model = defineModel<boolean>({ default: false })
26
+
27
+ const emit = defineEmits<{
28
+ change: [checked: boolean]
29
+ }>()
30
+
31
+ const composable = useSwitch(toRef(() => props), model)
32
+
33
+ const handleClick = () => {
34
+ if (!composable.state.value.disabled) {
35
+ model.value = !model.value
36
+ emit("change", model.value)
37
+ }
38
+ }
39
+
40
+ defineExpose({
41
+ state: composable.state
42
+ })
43
+ </script>
@@ -0,0 +1,55 @@
1
+ <template>
2
+ <textarea
3
+ :value="modelValue"
4
+ :disabled="composable.state.value.disabled"
5
+ :readonly="composable.state.value.readonly"
6
+ :placeholder="placeholder"
7
+ :rows="rows"
8
+ :id="id"
9
+ v-bind="composable.aria_attributes.value"
10
+ @input="handleInput"
11
+ @focus="composable.handleFocus"
12
+ @blur="composable.handleBlur"
13
+ />
14
+ </template>
15
+
16
+ <script setup lang="ts">
17
+ import { toRef } from "vue"
18
+ import { useTextarea } from "../../composables/useTextarea"
19
+ import type { TextareaSize, TextareaResize } from "../../types/textarea"
20
+
21
+ const props = withDefaults(defineProps<{
22
+ size?: TextareaSize
23
+ placeholder?: string
24
+ disabled?: boolean
25
+ readonly?: boolean
26
+ error?: string
27
+ error_id?: string
28
+ rows?: number
29
+ resize?: TextareaResize
30
+ modelValue?: string
31
+ id?: string
32
+ }>(), {
33
+ size: "md",
34
+ disabled: false,
35
+ readonly: false,
36
+ rows: 3,
37
+ resize: "vertical"
38
+ })
39
+
40
+ const emit = defineEmits<{
41
+ "update:modelValue": [value: string]
42
+ }>()
43
+
44
+ const composable = useTextarea(toRef(() => props))
45
+
46
+ const handleInput = (event: Event) => {
47
+ const target = event.target as HTMLTextAreaElement
48
+ emit("update:modelValue", target.value)
49
+ }
50
+
51
+ defineExpose({
52
+ state: composable.state,
53
+ is_focused: composable.is_focused
54
+ })
55
+ </script>