@soave/ui 0.2.2 → 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 (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 +42 -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 +49 -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,13 @@
1
+ export { default as Button } from "./Button.vue";
2
+ export { default as Input } from "./Input.vue";
3
+ export { default as Textarea } from "./Textarea.vue";
4
+ export { default as Card } from "./Card.vue";
5
+ export { default as Checkbox } from "./Checkbox.vue";
6
+ export { default as Switch } from "./Switch.vue";
7
+ export { default as Dialog } from "./Dialog.vue";
8
+ export { default as Select } from "./Select.vue";
9
+ export { default as SelectTrigger } from "./SelectTrigger.vue";
10
+ export { default as SelectContent } from "./SelectContent.vue";
11
+ export { default as SelectItem } from "./SelectItem.vue";
12
+ export { default as RadioGroup } from "./RadioGroup.vue";
13
+ export { default as RadioItem } from "./RadioItem.vue";
@@ -2,7 +2,7 @@ import { type Ref } from "vue";
2
2
  import type { ButtonProps, ButtonReturn } from "../types/button";
3
3
  /**
4
4
  * Buttonコンポーネントのロジックを提供するComposable
5
- * variant, size, disabled, loadingに基づいてクラスとaria属性を生成
6
- * Providerから設定されたデフォルト値を使用
5
+ * 状態とARIA属性のみを返す(スタイル情報なし)
6
+ * スタイルは StyleAdapter または外部のスタイルパッケージが担当
7
7
  */
8
8
  export declare const useButton: (props: Ref<ButtonProps>) => ButtonReturn;
@@ -1,49 +1,22 @@
1
- import { computed } from "vue";
2
- import { cn } from "../utils/cn.mjs";
1
+ import { computed, readonly } from "vue";
3
2
  import { useUI } from "./useUIConfig.mjs";
4
3
  export const useButton = (props) => {
5
4
  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
- );
5
+ const state = computed(() => ({
6
+ variant: props.value.variant ?? ui_config.default_variant,
7
+ size: props.value.size ?? ui_config.default_size,
8
+ disabled: props.value.disabled ?? false,
9
+ loading: props.value.loading ?? false,
10
+ type: props.value.type ?? "button"
11
+ }));
38
12
  const aria_attributes = computed(() => ({
39
- "aria-disabled": is_disabled.value || void 0,
40
- "aria-busy": is_loading.value || void 0,
41
- role: "button"
13
+ "aria-disabled": state.value.disabled || void 0,
14
+ "aria-busy": state.value.loading || void 0,
15
+ role: "button",
16
+ type: state.value.type
42
17
  }));
43
18
  return {
44
- base_classes,
45
- is_disabled,
46
- is_loading,
47
- aria_attributes
19
+ state: readonly(state),
20
+ aria_attributes: readonly(aria_attributes)
48
21
  };
49
22
  };
@@ -2,7 +2,7 @@ import { type Ref } from "vue";
2
2
  import type { CardProps, CardReturn } from "../types/card";
3
3
  /**
4
4
  * Cardコンポーネントのロジックを提供するComposable
5
- * paddingに基づいてクラスを生成
6
- * Providerから設定されたデフォルト値を使用
5
+ * 状態のみを返す(スタイル情報なし)
6
+ * スタイルは StyleAdapter または外部のスタイルパッケージが担当
7
7
  */
8
8
  export declare const useCard: (props: Ref<CardProps>) => CardReturn;
@@ -1,24 +1,11 @@
1
- import { computed } from "vue";
2
- import { cn } from "../utils/cn.mjs";
1
+ import { computed, readonly } from "vue";
3
2
  import { useUI } from "./useUIConfig.mjs";
4
3
  export const useCard = (props) => {
5
4
  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
- );
5
+ const state = computed(() => ({
6
+ padding: props.value.padding ?? ui_config.default_padding
7
+ }));
21
8
  return {
22
- base_classes
9
+ state: readonly(state)
23
10
  };
24
11
  };
@@ -2,6 +2,7 @@ import { type Ref } from "vue";
2
2
  import type { CheckboxProps, CheckboxReturn } from "../types/checkbox";
3
3
  /**
4
4
  * Checkboxコンポーネントのロジックを提供するComposable
5
- * size, disabled, indeterminateに基づいてクラスとaria属性を生成
5
+ * 状態とARIA属性のみを返す(スタイル情報なし)
6
+ * スタイルは StyleAdapter または外部のスタイルパッケージが担当
6
7
  */
7
8
  export declare const useCheckbox: (props: Ref<CheckboxProps>, checked: Ref<boolean>) => CheckboxReturn;
@@ -1,51 +1,18 @@
1
- import { computed } from "vue";
2
- import { cn } from "../utils/cn.mjs";
1
+ import { computed, readonly } from "vue";
3
2
  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
- );
3
+ const state = computed(() => ({
4
+ size: props.value.size ?? "md",
5
+ disabled: props.value.disabled ?? false,
6
+ indeterminate: props.value.indeterminate ?? false,
7
+ checked: checked.value
8
+ }));
39
9
  const aria_attributes = computed(() => ({
40
10
  role: "checkbox",
41
- "aria-checked": is_indeterminate.value ? "mixed" : checked.value,
42
- "aria-disabled": is_disabled.value || void 0
11
+ "aria-checked": state.value.indeterminate ? "mixed" : state.value.checked,
12
+ "aria-disabled": state.value.disabled || void 0
43
13
  }));
44
14
  return {
45
- base_classes,
46
- indicator_classes,
47
- is_disabled,
48
- is_indeterminate,
49
- aria_attributes
15
+ state: readonly(state),
16
+ aria_attributes: readonly(aria_attributes)
50
17
  };
51
18
  };
@@ -2,5 +2,7 @@ import { type Ref } from "vue";
2
2
  import type { FileInputProps, FileInputReturn } from "../types/file-input";
3
3
  /**
4
4
  * FileInputコンポーネントのロジックを提供するComposable
5
+ * 状態とARIA属性のみを返す(スタイル情報なし)
6
+ * スタイルは StyleAdapter または外部のスタイルパッケージが担当
5
7
  */
6
8
  export declare const useFileInput: (props: Ref<FileInputProps>, input_ref: Ref<HTMLInputElement | null>) => FileInputReturn;
@@ -1,5 +1,4 @@
1
- import { computed, ref } from "vue";
2
- import { cn } from "../utils/cn.mjs";
1
+ import { computed, ref, readonly } from "vue";
3
2
  const FILE_ERRORS = {
4
3
  MAX_SIZE_EXCEEDED: (max) => `\u30D5\u30A1\u30A4\u30EB\u30B5\u30A4\u30BA\u304C${formatFileSize(max)}\u3092\u8D85\u3048\u3066\u3044\u307E\u3059`,
5
4
  MAX_FILES_EXCEEDED: (max) => `\u6700\u5927${max}\u30D5\u30A1\u30A4\u30EB\u307E\u3067\u30A2\u30C3\u30D7\u30ED\u30FC\u30C9\u3067\u304D\u307E\u3059`,
@@ -17,30 +16,18 @@ const createPreviewUrl = (file) => {
17
16
  return null;
18
17
  };
19
18
  export const useFileInput = (props, input_ref) => {
20
- const is_disabled = computed(() => props.value.disabled ?? false);
21
19
  const is_dragging = ref(false);
22
20
  const files = ref([]);
23
21
  const error = ref(null);
24
- const base_classes = computed(
25
- () => cn(
26
- "relative",
27
- is_disabled.value && "opacity-50 cursor-not-allowed"
28
- )
29
- );
30
- const dropzone_classes = computed(
31
- () => cn(
32
- "flex flex-col items-center justify-center w-full p-6",
33
- "border-2 border-dashed rounded-lg",
34
- "transition-colors cursor-pointer",
35
- "hover:border-primary hover:bg-primary/5",
36
- is_dragging.value && "border-primary bg-primary/10",
37
- error.value && "border-destructive",
38
- is_disabled.value && "pointer-events-none"
39
- )
40
- );
22
+ const state = computed(() => ({
23
+ disabled: props.value.disabled ?? false,
24
+ is_dragging: is_dragging.value,
25
+ has_error: !!error.value,
26
+ has_files: files.value.length > 0
27
+ }));
41
28
  const aria_attributes = computed(() => ({
42
- "aria-disabled": is_disabled.value || void 0,
43
- "aria-invalid": !!error.value || void 0
29
+ "aria-disabled": state.value.disabled || void 0,
30
+ "aria-invalid": state.value.has_error || void 0
44
31
  }));
45
32
  const validateFile = (file) => {
46
33
  const { accept, max_size } = props.value;
@@ -65,7 +52,7 @@ export const useFileInput = (props, input_ref) => {
65
52
  return null;
66
53
  };
67
54
  const handleFiles = (file_list) => {
68
- if (!file_list || is_disabled.value) return;
55
+ if (!file_list || state.value.disabled) return;
69
56
  error.value = null;
70
57
  const { multiple, max_files } = props.value;
71
58
  const new_files = [];
@@ -100,7 +87,7 @@ export const useFileInput = (props, input_ref) => {
100
87
  };
101
88
  const handleDragEnter = (event) => {
102
89
  event.preventDefault();
103
- if (!is_disabled.value) {
90
+ if (!state.value.disabled) {
104
91
  is_dragging.value = true;
105
92
  }
106
93
  };
@@ -111,7 +98,7 @@ export const useFileInput = (props, input_ref) => {
111
98
  const handleDrop = (event) => {
112
99
  event.preventDefault();
113
100
  is_dragging.value = false;
114
- if (!is_disabled.value) {
101
+ if (!state.value.disabled) {
115
102
  handleFiles(event.dataTransfer?.files ?? null);
116
103
  }
117
104
  };
@@ -129,18 +116,16 @@ export const useFileInput = (props, input_ref) => {
129
116
  error.value = null;
130
117
  };
131
118
  const openFilePicker = () => {
132
- if (!is_disabled.value && input_ref.value) {
119
+ if (!state.value.disabled && input_ref.value) {
133
120
  input_ref.value.click();
134
121
  }
135
122
  };
136
123
  return {
137
- base_classes,
138
- dropzone_classes,
139
- is_disabled,
124
+ state: readonly(state),
140
125
  is_dragging,
141
126
  files,
142
127
  error,
143
- aria_attributes,
128
+ aria_attributes: readonly(aria_attributes),
144
129
  handleFiles,
145
130
  handleDragEnter,
146
131
  handleDragLeave,
@@ -2,7 +2,7 @@ import { type Ref } from "vue";
2
2
  import type { InputProps, InputReturn } from "../types/input";
3
3
  /**
4
4
  * Inputコンポーネントのロジックを提供するComposable
5
- * size, error, disabled, readonlyに基づいてクラスとaria属性を生成
6
- * Providerから設定されたデフォルト値を使用
5
+ * 状態とARIA属性のみを返す(スタイル情報なし)
6
+ * スタイルは StyleAdapter または外部のスタイルパッケージが担当
7
7
  */
8
8
  export declare const useInput: (props: Ref<InputProps>) => InputReturn;
@@ -1,37 +1,19 @@
1
- import { computed, ref } from "vue";
2
- import { cn } from "../utils/cn.mjs";
1
+ import { computed, ref, readonly } from "vue";
3
2
  import { useUI } from "./useUIConfig.mjs";
4
3
  export const useInput = (props) => {
5
4
  const ui_config = useUI("input");
6
5
  const is_focused = ref(false);
7
- const has_error = computed(() => !!props.value.error);
8
- const is_disabled = computed(() => props.value.disabled ?? false);
9
- const is_readonly = computed(() => props.value.readonly ?? false);
10
- const size_classes = computed(() => {
11
- const size_map = {
12
- sm: "h-9 text-sm",
13
- md: "h-10",
14
- lg: "h-11 text-lg"
15
- };
16
- return size_map[props.value.size ?? ui_config.default_size];
17
- });
18
- const base_classes = computed(
19
- () => cn(
20
- "flex w-full rounded-md border border-input bg-background px-3 py-2",
21
- "text-sm ring-offset-background",
22
- "file:border-0 file:bg-transparent file:text-sm file:font-medium",
23
- "placeholder:text-muted-foreground",
24
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
25
- "disabled:cursor-not-allowed disabled:opacity-50",
26
- size_classes.value,
27
- has_error.value && "border-destructive focus-visible:ring-destructive",
28
- is_readonly.value && "bg-muted"
29
- )
30
- );
6
+ const state = computed(() => ({
7
+ type: props.value.type ?? "text",
8
+ size: props.value.size ?? ui_config.default_size,
9
+ disabled: props.value.disabled ?? false,
10
+ readonly: props.value.readonly ?? false,
11
+ has_error: !!props.value.error
12
+ }));
31
13
  const aria_attributes = computed(() => ({
32
- "aria-invalid": has_error.value || void 0,
14
+ "aria-invalid": state.value.has_error || void 0,
33
15
  "aria-describedby": props.value.error_id,
34
- "aria-readonly": is_readonly.value || void 0
16
+ "aria-readonly": state.value.readonly || void 0
35
17
  }));
36
18
  const handleFocus = () => {
37
19
  is_focused.value = true;
@@ -40,12 +22,9 @@ export const useInput = (props) => {
40
22
  is_focused.value = false;
41
23
  };
42
24
  return {
43
- base_classes,
25
+ state: readonly(state),
44
26
  is_focused,
45
- has_error,
46
- is_disabled,
47
- is_readonly,
48
- aria_attributes,
27
+ aria_attributes: readonly(aria_attributes),
49
28
  handleFocus,
50
29
  handleBlur
51
30
  };
@@ -2,6 +2,7 @@ import { type Ref } from "vue";
2
2
  import type { RadioItemProps, RadioItemReturn } from "../types/radio";
3
3
  /**
4
4
  * RadioItemコンポーネントのロジックを提供するComposable
5
- * size, disabled, valueに基づいてクラスとaria属性を生成
5
+ * 状態とARIA属性のみを返す(スタイル情報なし)
6
+ * スタイルは StyleAdapter または外部のスタイルパッケージが担当
6
7
  */
7
8
  export declare const useRadioItem: (props: Ref<RadioItemProps>) => RadioItemReturn;
@@ -1,5 +1,4 @@
1
- import { computed, inject } from "vue";
2
- import { cn } from "../utils/cn.mjs";
1
+ import { computed, inject, readonly } from "vue";
3
2
  import { RADIO_GROUP_KEY } from "../types/radio.mjs";
4
3
  import { COMPONENT_ERRORS } from "../constants/errors.mjs";
5
4
  export const useRadioItem = (props) => {
@@ -7,49 +6,18 @@ export const useRadioItem = (props) => {
7
6
  if (!context) {
8
7
  throw new Error(COMPONENT_ERRORS.PROVIDER_NOT_FOUND);
9
8
  }
10
- const is_disabled = computed(() => props.value.disabled ?? context.disabled.value);
11
- const is_checked = computed(() => context.model_value.value === props.value.value);
12
- const size_classes = computed(() => {
13
- const size_map = {
14
- sm: "h-4 w-4",
15
- md: "h-5 w-5",
16
- lg: "h-6 w-6"
17
- };
18
- return size_map[props.value.size ?? "md"];
19
- });
20
- const base_classes = computed(
21
- () => cn(
22
- "aspect-square rounded-full border border-primary text-primary",
23
- "ring-offset-background",
24
- "focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
25
- "disabled:cursor-not-allowed disabled:opacity-50",
26
- size_classes.value
27
- )
28
- );
29
- const indicator_size_classes = computed(() => {
30
- const size_map = {
31
- sm: "h-2 w-2",
32
- md: "h-2.5 w-2.5",
33
- lg: "h-3 w-3"
34
- };
35
- return size_map[props.value.size ?? "md"];
36
- });
37
- const indicator_classes = computed(
38
- () => cn(
39
- "flex items-center justify-center",
40
- indicator_size_classes.value
41
- )
42
- );
9
+ const state = computed(() => ({
10
+ size: props.value.size ?? "md",
11
+ disabled: props.value.disabled ?? context.disabled.value,
12
+ checked: context.model_value.value === props.value.value
13
+ }));
43
14
  const aria_attributes = computed(() => ({
44
15
  role: "radio",
45
- "aria-checked": is_checked.value,
46
- "aria-disabled": is_disabled.value || void 0
16
+ "aria-checked": state.value.checked,
17
+ "aria-disabled": state.value.disabled || void 0
47
18
  }));
48
19
  return {
49
- base_classes,
50
- indicator_classes,
51
- is_checked,
52
- is_disabled,
53
- aria_attributes
20
+ state: readonly(state),
21
+ aria_attributes: readonly(aria_attributes)
54
22
  };
55
23
  };
@@ -2,14 +2,17 @@ import { type Ref } from "vue";
2
2
  import type { SelectTriggerReturn, SelectContentReturn, SelectItemReturn } from "../types/select";
3
3
  /**
4
4
  * SelectTriggerコンポーネントのロジックを提供するComposable
5
+ * 状態のみを返す(スタイル情報なし)
5
6
  */
6
7
  export declare const useSelectTrigger: () => SelectTriggerReturn;
7
8
  /**
8
9
  * SelectContentコンポーネントのロジックを提供するComposable
10
+ * 状態のみを返す(スタイル情報なし)
9
11
  */
10
12
  export declare const useSelectContent: () => SelectContentReturn;
11
13
  /**
12
14
  * SelectItemコンポーネントのロジックを提供するComposable
15
+ * 状態のみを返す(スタイル情報なし)
13
16
  */
14
17
  export declare const useSelectItem: (props: Ref<{
15
18
  value: string;
@@ -1,5 +1,4 @@
1
- import { computed, inject } from "vue";
2
- import { cn } from "../utils/cn.mjs";
1
+ import { computed, inject, readonly } from "vue";
3
2
  import { SELECT_KEY } from "../types/select.mjs";
4
3
  import { COMPONENT_ERRORS } from "../constants/errors.mjs";
5
4
  export const useSelectTrigger = () => {
@@ -7,44 +6,25 @@ export const useSelectTrigger = () => {
7
6
  if (!context) {
8
7
  throw new Error(COMPONENT_ERRORS.PROVIDER_NOT_FOUND);
9
8
  }
10
- const is_disabled = computed(() => context.disabled.value);
11
- const size_classes = computed(() => {
12
- const size_map = {
13
- sm: "h-9 text-sm",
14
- md: "h-10",
15
- lg: "h-11 text-lg"
16
- };
17
- return size_map[context.size.value];
18
- });
19
- const base_classes = computed(
20
- () => cn(
21
- "flex w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2",
22
- "text-sm ring-offset-background",
23
- "placeholder:text-muted-foreground",
24
- "focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
25
- "disabled:cursor-not-allowed disabled:opacity-50",
26
- "[&>span]:line-clamp-1",
27
- size_classes.value
28
- )
29
- );
9
+ const state = computed(() => ({
10
+ size: context.size.value,
11
+ disabled: context.disabled.value,
12
+ is_open: context.is_open.value
13
+ }));
30
14
  return {
31
- base_classes,
32
- is_disabled
15
+ state: readonly(state)
33
16
  };
34
17
  };
35
18
  export const useSelectContent = () => {
36
- const base_classes = computed(
37
- () => cn(
38
- "relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md",
39
- "data-[state=open]:animate-in data-[state=closed]:animate-out",
40
- "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
41
- "data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
42
- "data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2",
43
- "data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2"
44
- )
45
- );
19
+ const context = inject(SELECT_KEY, null);
20
+ if (!context) {
21
+ throw new Error(COMPONENT_ERRORS.PROVIDER_NOT_FOUND);
22
+ }
23
+ const state = computed(() => ({
24
+ is_open: context.is_open.value
25
+ }));
46
26
  return {
47
- base_classes
27
+ state: readonly(state)
48
28
  };
49
29
  };
50
30
  export const useSelectItem = (props) => {
@@ -52,20 +32,11 @@ export const useSelectItem = (props) => {
52
32
  if (!context) {
53
33
  throw new Error(COMPONENT_ERRORS.PROVIDER_NOT_FOUND);
54
34
  }
55
- const is_selected = computed(() => context.model_value.value === props.value.value);
56
- const is_disabled = computed(() => props.value.disabled ?? false);
57
- const base_classes = computed(
58
- () => cn(
59
- "relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2",
60
- "text-sm outline-none",
61
- "focus:bg-accent focus:text-accent-foreground",
62
- "data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
63
- is_selected.value && "bg-accent text-accent-foreground"
64
- )
65
- );
35
+ const state = computed(() => ({
36
+ selected: context.model_value.value === props.value.value,
37
+ disabled: props.value.disabled ?? false
38
+ }));
66
39
  return {
67
- base_classes,
68
- is_selected,
69
- is_disabled
40
+ state: readonly(state)
70
41
  };
71
42
  };
@@ -2,6 +2,7 @@ import { type Ref } from "vue";
2
2
  import type { SwitchProps, SwitchReturn } from "../types/switch";
3
3
  /**
4
4
  * Switchコンポーネントのロジックを提供するComposable
5
- * size, disabledに基づいてクラスとaria属性を生成
5
+ * 状態とARIA属性のみを返す(スタイル情報なし)
6
+ * スタイルは StyleAdapter または外部のスタイルパッケージが担当
6
7
  */
7
8
  export declare const useSwitch: (props: Ref<SwitchProps>, checked: Ref<boolean>) => SwitchReturn;
@@ -1,50 +1,17 @@
1
- import { computed } from "vue";
2
- import { cn } from "../utils/cn.mjs";
1
+ import { computed, readonly } from "vue";
3
2
  export const useSwitch = (props, checked) => {
4
- const is_disabled = computed(() => props.value.disabled ?? false);
5
- const track_size_classes = computed(() => {
6
- const size_map = {
7
- sm: "h-5 w-9",
8
- md: "h-6 w-11",
9
- lg: "h-7 w-14"
10
- };
11
- return size_map[props.value.size ?? "md"];
12
- });
13
- const track_classes = computed(
14
- () => cn(
15
- "peer inline-flex shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent",
16
- "transition-colors",
17
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
18
- "disabled:cursor-not-allowed disabled:opacity-50",
19
- "data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",
20
- track_size_classes.value
21
- )
22
- );
23
- const thumb_size_classes = computed(() => {
24
- const size_map = {
25
- sm: "h-4 w-4 data-[state=checked]:translate-x-4",
26
- md: "h-5 w-5 data-[state=checked]:translate-x-5",
27
- lg: "h-6 w-6 data-[state=checked]:translate-x-7"
28
- };
29
- return size_map[props.value.size ?? "md"];
30
- });
31
- const thumb_classes = computed(
32
- () => cn(
33
- "pointer-events-none block rounded-full bg-background shadow-lg ring-0",
34
- "transition-transform",
35
- "data-[state=unchecked]:translate-x-0",
36
- thumb_size_classes.value
37
- )
38
- );
3
+ const state = computed(() => ({
4
+ size: props.value.size ?? "md",
5
+ disabled: props.value.disabled ?? false,
6
+ checked: checked.value
7
+ }));
39
8
  const aria_attributes = computed(() => ({
40
9
  role: "switch",
41
- "aria-checked": checked.value,
42
- "aria-disabled": is_disabled.value || void 0
10
+ "aria-checked": state.value.checked,
11
+ "aria-disabled": state.value.disabled || void 0
43
12
  }));
44
13
  return {
45
- track_classes,
46
- thumb_classes,
47
- is_disabled,
48
- aria_attributes
14
+ state: readonly(state),
15
+ aria_attributes: readonly(aria_attributes)
49
16
  };
50
17
  };
@@ -2,6 +2,7 @@ import { type Ref } from "vue";
2
2
  import type { TextareaProps, TextareaReturn } from "../types/textarea";
3
3
  /**
4
4
  * Textareaコンポーネントのロジックを提供するComposable
5
- * error, disabled, readonly, resizeに基づいてクラスとaria属性を生成
5
+ * 状態とARIA属性のみを返す(スタイル情報なし)
6
+ * スタイルは StyleAdapter または外部のスタイルパッケージが担当
6
7
  */
7
8
  export declare const useTextarea: (props: Ref<TextareaProps>) => TextareaReturn;