@soave/ui 0.3.2 → 0.4.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 (214) hide show
  1. package/dist/adapters/css-variables.d.ts +2 -1
  2. package/dist/adapters/css-variables.d.ts.map +1 -0
  3. package/dist/adapters/headless.d.ts +2 -1
  4. package/dist/adapters/headless.d.ts.map +1 -0
  5. package/dist/adapters/index.d.ts +6 -5
  6. package/dist/adapters/index.d.ts.map +1 -0
  7. package/dist/adapters/tailwind.d.ts +2 -1
  8. package/dist/adapters/tailwind.d.ts.map +1 -0
  9. package/dist/adapters/types.d.ts +2 -1
  10. package/dist/adapters/types.d.ts.map +1 -0
  11. package/dist/adapters.d.ts +2 -0
  12. package/dist/{adapters/css-variables.mjs → adapters.mjs} +33 -2
  13. package/dist/adapters.mjs.map +1 -0
  14. package/dist/components/Button.vue.d.ts +35 -0
  15. package/dist/components/Button.vue.d.ts.map +1 -0
  16. package/dist/components/Card.vue.d.ts +29 -0
  17. package/dist/components/Card.vue.d.ts.map +1 -0
  18. package/dist/components/Checkbox.vue.d.ts +39 -0
  19. package/dist/components/Checkbox.vue.d.ts.map +1 -0
  20. package/dist/components/Dialog.vue.d.ts +46 -0
  21. package/dist/components/Dialog.vue.d.ts.map +1 -0
  22. package/dist/components/Input.vue.d.ts +24 -0
  23. package/dist/components/Input.vue.d.ts.map +1 -0
  24. package/dist/components/RadioGroup.vue.d.ts +32 -0
  25. package/dist/components/RadioGroup.vue.d.ts.map +1 -0
  26. package/dist/components/RadioItem.vue.d.ts +40 -0
  27. package/dist/components/RadioItem.vue.d.ts.map +1 -0
  28. package/dist/components/Select.vue.d.ts +50 -0
  29. package/dist/components/Select.vue.d.ts.map +1 -0
  30. package/dist/components/SelectContent.vue.d.ts +25 -0
  31. package/dist/components/SelectContent.vue.d.ts.map +1 -0
  32. package/dist/components/SelectItem.vue.d.ts +36 -0
  33. package/dist/components/SelectItem.vue.d.ts.map +1 -0
  34. package/dist/components/SelectTrigger.vue.d.ts +36 -0
  35. package/dist/components/SelectTrigger.vue.d.ts.map +1 -0
  36. package/dist/components/Switch.vue.d.ts +46 -0
  37. package/dist/components/Switch.vue.d.ts.map +1 -0
  38. package/dist/components/Textarea.vue.d.ts +41 -0
  39. package/dist/components/Textarea.vue.d.ts.map +1 -0
  40. package/dist/components/index.d.ts +14 -13
  41. package/dist/components/index.d.ts.map +1 -0
  42. package/dist/composables/index.d.ts +18 -17
  43. package/dist/composables/index.d.ts.map +1 -0
  44. package/dist/composables/useButton.d.ts +3 -2
  45. package/dist/composables/useButton.d.ts.map +1 -0
  46. package/dist/composables/useCard.d.ts +3 -2
  47. package/dist/composables/useCard.d.ts.map +1 -0
  48. package/dist/composables/useCheckbox.d.ts +3 -2
  49. package/dist/composables/useCheckbox.d.ts.map +1 -0
  50. package/dist/composables/useDialog.d.ts +2 -1
  51. package/dist/composables/useDialog.d.ts.map +1 -0
  52. package/dist/composables/useDropdown.d.ts +3 -2
  53. package/dist/composables/useDropdown.d.ts.map +1 -0
  54. package/dist/composables/useFileInput.d.ts +3 -2
  55. package/dist/composables/useFileInput.d.ts.map +1 -0
  56. package/dist/composables/useForm.d.ts +3 -2
  57. package/dist/composables/useForm.d.ts.map +1 -0
  58. package/dist/composables/useInput.d.ts +3 -2
  59. package/dist/composables/useInput.d.ts.map +1 -0
  60. package/dist/composables/usePopover.d.ts +3 -2
  61. package/dist/composables/usePopover.d.ts.map +1 -0
  62. package/dist/composables/useRadio.d.ts +3 -2
  63. package/dist/composables/useRadio.d.ts.map +1 -0
  64. package/dist/composables/useSelect.d.ts +3 -2
  65. package/dist/composables/useSelect.d.ts.map +1 -0
  66. package/dist/composables/useSwitch.d.ts +3 -2
  67. package/dist/composables/useSwitch.d.ts.map +1 -0
  68. package/dist/composables/useTextarea.d.ts +3 -2
  69. package/dist/composables/useTextarea.d.ts.map +1 -0
  70. package/dist/composables/useTheme.d.ts +3 -2
  71. package/dist/composables/useTheme.d.ts.map +1 -0
  72. package/dist/composables/useToast.d.ts +2 -1
  73. package/dist/composables/useToast.d.ts.map +1 -0
  74. package/dist/composables/useTooltip.d.ts +3 -2
  75. package/dist/composables/useTooltip.d.ts.map +1 -0
  76. package/dist/composables/useUIConfig.d.ts +5 -4
  77. package/dist/composables/useUIConfig.d.ts.map +1 -0
  78. package/dist/composables.d.ts +2 -0
  79. package/dist/composables.mjs +30 -0
  80. package/dist/composables.mjs.map +1 -0
  81. package/dist/constants/errors.d.ts +1 -0
  82. package/dist/constants/errors.d.ts.map +1 -0
  83. package/dist/constants/index.d.ts +3 -2
  84. package/dist/constants/index.d.ts.map +1 -0
  85. package/dist/constants/logs.d.ts +1 -0
  86. package/dist/constants/logs.d.ts.map +1 -0
  87. package/dist/index.d.ts +7 -6
  88. package/dist/index.d.ts.map +1 -0
  89. package/dist/index.mjs +760 -6
  90. package/dist/index.mjs.map +1 -0
  91. package/dist/{adapters/tailwind.mjs → tailwind-B-R7fPT1.js} +16 -7
  92. package/dist/tailwind-B-R7fPT1.js.map +1 -0
  93. package/dist/types/alert.d.ts +2 -1
  94. package/dist/types/alert.d.ts.map +1 -0
  95. package/dist/types/button.d.ts +2 -1
  96. package/dist/types/button.d.ts.map +1 -0
  97. package/dist/types/card.d.ts +2 -1
  98. package/dist/types/card.d.ts.map +1 -0
  99. package/dist/types/checkbox.d.ts +2 -1
  100. package/dist/types/checkbox.d.ts.map +1 -0
  101. package/dist/types/composables.d.ts +10 -1
  102. package/dist/types/composables.d.ts.map +1 -0
  103. package/dist/types/config.d.ts +6 -5
  104. package/dist/types/config.d.ts.map +1 -0
  105. package/dist/types/dialog.d.ts +2 -1
  106. package/dist/types/dialog.d.ts.map +1 -0
  107. package/dist/types/dropdown.d.ts +3 -2
  108. package/dist/types/dropdown.d.ts.map +1 -0
  109. package/dist/types/file-input.d.ts +2 -1
  110. package/dist/types/file-input.d.ts.map +1 -0
  111. package/dist/types/form.d.ts +2 -1
  112. package/dist/types/form.d.ts.map +1 -0
  113. package/dist/types/index.d.ts +22 -21
  114. package/dist/types/index.d.ts.map +1 -0
  115. package/dist/types/input.d.ts +2 -1
  116. package/dist/types/input.d.ts.map +1 -0
  117. package/dist/types/popover.d.ts +3 -2
  118. package/dist/types/popover.d.ts.map +1 -0
  119. package/dist/types/radio.d.ts +2 -1
  120. package/dist/types/radio.d.ts.map +1 -0
  121. package/dist/types/select.d.ts +2 -1
  122. package/dist/types/select.d.ts.map +1 -0
  123. package/dist/types/sheet.d.ts +2 -1
  124. package/dist/types/sheet.d.ts.map +1 -0
  125. package/dist/types/switch.d.ts +2 -1
  126. package/dist/types/switch.d.ts.map +1 -0
  127. package/dist/types/textarea.d.ts +2 -1
  128. package/dist/types/textarea.d.ts.map +1 -0
  129. package/dist/types/theme.d.ts +1 -0
  130. package/dist/types/theme.d.ts.map +1 -0
  131. package/dist/types/toast.d.ts +1 -0
  132. package/dist/types/toast.d.ts.map +1 -0
  133. package/dist/types/tooltip.d.ts +3 -2
  134. package/dist/types/tooltip.d.ts.map +1 -0
  135. package/dist/types/utils.d.ts +1 -0
  136. package/dist/types/utils.d.ts.map +1 -0
  137. package/dist/useTheme-C2uPqAtQ.js +1175 -0
  138. package/dist/useTheme-C2uPqAtQ.js.map +1 -0
  139. package/dist/utils/cn.d.ts +2 -1
  140. package/dist/utils/cn.d.ts.map +1 -0
  141. package/dist/utils/deepMerge.d.ts +2 -1
  142. package/dist/utils/deepMerge.d.ts.map +1 -0
  143. package/dist/utils/index.d.ts +3 -2
  144. package/dist/utils/index.d.ts.map +1 -0
  145. package/package.json +6 -4
  146. package/dist/adapters/headless.mjs +0 -7
  147. package/dist/adapters/index.mjs +0 -11
  148. package/dist/adapters/types.mjs +0 -10
  149. package/dist/build.config.d.ts +0 -2
  150. package/dist/build.config.mjs +0 -14
  151. package/dist/components/Button.vue +0 -41
  152. package/dist/components/Card.vue +0 -24
  153. package/dist/components/Checkbox.vue +0 -47
  154. package/dist/components/Dialog.vue +0 -105
  155. package/dist/components/Input.vue +0 -48
  156. package/dist/components/RadioGroup.vue +0 -45
  157. package/dist/components/RadioItem.vue +0 -65
  158. package/dist/components/Select.vue +0 -114
  159. package/dist/components/SelectContent.vue +0 -54
  160. package/dist/components/SelectItem.vue +0 -61
  161. package/dist/components/SelectTrigger.vue +0 -75
  162. package/dist/components/Switch.vue +0 -45
  163. package/dist/components/Textarea.vue +0 -55
  164. package/dist/components/index.mjs +0 -13
  165. package/dist/composables/index.mjs +0 -17
  166. package/dist/composables/useButton.mjs +0 -22
  167. package/dist/composables/useCard.mjs +0 -11
  168. package/dist/composables/useCheckbox.mjs +0 -18
  169. package/dist/composables/useDialog.mjs +0 -19
  170. package/dist/composables/useDropdown.mjs +0 -170
  171. package/dist/composables/useFileInput.mjs +0 -137
  172. package/dist/composables/useForm.mjs +0 -159
  173. package/dist/composables/useInput.mjs +0 -31
  174. package/dist/composables/usePopover.mjs +0 -113
  175. package/dist/composables/useRadio.mjs +0 -23
  176. package/dist/composables/useSelect.mjs +0 -42
  177. package/dist/composables/useSwitch.mjs +0 -17
  178. package/dist/composables/useTextarea.mjs +0 -29
  179. package/dist/composables/useTheme.mjs +0 -89
  180. package/dist/composables/useToast.mjs +0 -64
  181. package/dist/composables/useTooltip.mjs +0 -125
  182. package/dist/composables/useUIConfig.mjs +0 -53
  183. package/dist/constants/errors.mjs +0 -18
  184. package/dist/constants/index.mjs +0 -2
  185. package/dist/constants/logs.mjs +0 -17
  186. package/dist/env.d.ts +0 -11
  187. package/dist/styles/css-variables.css +0 -1
  188. package/dist/styles/index.d.ts +0 -1
  189. package/dist/styles/index.mjs +0 -1
  190. package/dist/types/alert.mjs +0 -0
  191. package/dist/types/button.mjs +0 -0
  192. package/dist/types/card.mjs +0 -0
  193. package/dist/types/checkbox.mjs +0 -0
  194. package/dist/types/composables.mjs +0 -0
  195. package/dist/types/config.mjs +0 -15
  196. package/dist/types/dialog.mjs +0 -1
  197. package/dist/types/dropdown.mjs +0 -1
  198. package/dist/types/file-input.mjs +0 -0
  199. package/dist/types/form.mjs +0 -0
  200. package/dist/types/index.mjs +0 -21
  201. package/dist/types/input.mjs +0 -0
  202. package/dist/types/popover.mjs +0 -1
  203. package/dist/types/radio.mjs +0 -1
  204. package/dist/types/select.mjs +0 -1
  205. package/dist/types/sheet.mjs +0 -1
  206. package/dist/types/switch.mjs +0 -0
  207. package/dist/types/textarea.mjs +0 -0
  208. package/dist/types/theme.mjs +0 -42
  209. package/dist/types/toast.mjs +0 -0
  210. package/dist/types/tooltip.mjs +0 -1
  211. package/dist/types/utils.mjs +0 -0
  212. package/dist/utils/cn.mjs +0 -5
  213. package/dist/utils/deepMerge.mjs +0 -18
  214. package/dist/utils/index.mjs +0 -2
@@ -0,0 +1,1175 @@
1
+ import { reactive, provide, inject, readonly, computed, ref, onUnmounted, onMounted, watch } from "vue";
2
+ import { t as tailwindAdapter } from "./tailwind-B-R7fPT1.js";
3
+ import { ZodError } from "zod";
4
+ const DEFAULT_UI_CONFIG = {
5
+ button: {
6
+ default_variant: "primary",
7
+ default_size: "md"
8
+ },
9
+ input: {
10
+ default_size: "md"
11
+ },
12
+ card: {
13
+ default_padding: "md"
14
+ },
15
+ alert: {
16
+ default_variant: "default"
17
+ }
18
+ };
19
+ const deepMerge = (target, source) => {
20
+ const output = { ...target };
21
+ for (const key in source) {
22
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
23
+ const source_value = source[key];
24
+ const target_value = target[key];
25
+ if (source_value !== null && typeof source_value === "object" && !Array.isArray(source_value) && target_value !== null && typeof target_value === "object" && !Array.isArray(target_value)) {
26
+ output[key] = deepMerge(
27
+ target_value,
28
+ source_value
29
+ );
30
+ } else if (source_value !== void 0) {
31
+ output[key] = source_value;
32
+ }
33
+ }
34
+ }
35
+ return output;
36
+ };
37
+ const FORM_ERRORS = {
38
+ FIELD_NOT_FOUND: "指定されたフィールドがスキーマに存在しません",
39
+ VALIDATION_FAILED: "バリデーションに失敗しました",
40
+ SUBMIT_FAILED: "フォームの送信に失敗しました",
41
+ SCHEMA_INVALID: "無効なスキーマが指定されました"
42
+ };
43
+ const COMPONENT_ERRORS = {
44
+ INVALID_VARIANT: "無効なvariantが指定されました",
45
+ INVALID_SIZE: "無効なsizeが指定されました",
46
+ PROVIDER_NOT_FOUND: "UIProviderが見つかりません。アプリケーションをUIProviderでラップしてください"
47
+ };
48
+ const DIALOG_ERRORS = {
49
+ ALREADY_OPEN: "ダイアログは既に開いています",
50
+ ALREADY_CLOSED: "ダイアログは既に閉じています"
51
+ };
52
+ const INPUT_ERRORS = {
53
+ INVALID_TYPE: "無効なinputタイプが指定されました"
54
+ };
55
+ const UI_PROVIDER_KEY = Symbol("ui-provider");
56
+ const UI_CONFIG_KEY = Symbol("ui-config");
57
+ const useUIProvider = (config = {}, adapter = tailwindAdapter) => {
58
+ const merged_config = reactive(
59
+ deepMerge(DEFAULT_UI_CONFIG, config)
60
+ );
61
+ const context = {
62
+ config: merged_config,
63
+ adapter
64
+ };
65
+ provide(UI_PROVIDER_KEY, context);
66
+ provide(UI_CONFIG_KEY, merged_config);
67
+ return context;
68
+ };
69
+ function useUI(component) {
70
+ const context = inject(UI_PROVIDER_KEY, null);
71
+ if (!context) {
72
+ return readonly(DEFAULT_UI_CONFIG[component]);
73
+ }
74
+ return readonly(context.config[component]);
75
+ }
76
+ const useUIConfig = () => {
77
+ const context = inject(UI_PROVIDER_KEY, null);
78
+ if (!context) {
79
+ return readonly(DEFAULT_UI_CONFIG);
80
+ }
81
+ return readonly(context.config);
82
+ };
83
+ const useStyleAdapter = () => {
84
+ const context = inject(UI_PROVIDER_KEY, null);
85
+ if (!context) {
86
+ return tailwindAdapter;
87
+ }
88
+ return context.adapter;
89
+ };
90
+ const useButton = (props) => {
91
+ const ui_config = useUI("button");
92
+ const state = computed(() => ({
93
+ variant: props.value.variant ?? ui_config.default_variant,
94
+ size: props.value.size ?? ui_config.default_size,
95
+ disabled: props.value.disabled ?? false,
96
+ loading: props.value.loading ?? false,
97
+ type: props.value.type ?? "button"
98
+ }));
99
+ const aria_attributes = computed(() => ({
100
+ "aria-disabled": state.value.disabled || void 0,
101
+ "aria-busy": state.value.loading || void 0,
102
+ role: "button",
103
+ type: state.value.type
104
+ }));
105
+ return {
106
+ state: readonly(state),
107
+ aria_attributes: readonly(aria_attributes)
108
+ };
109
+ };
110
+ const useInput = (props) => {
111
+ const ui_config = useUI("input");
112
+ const is_focused = ref(false);
113
+ const state = computed(() => ({
114
+ type: props.value.type ?? "text",
115
+ size: props.value.size ?? ui_config.default_size,
116
+ disabled: props.value.disabled ?? false,
117
+ readonly: props.value.readonly ?? false,
118
+ has_error: !!props.value.error
119
+ }));
120
+ const aria_attributes = computed(() => ({
121
+ "aria-invalid": state.value.has_error || void 0,
122
+ "aria-describedby": props.value.error_id,
123
+ "aria-readonly": state.value.readonly || void 0
124
+ }));
125
+ const handleFocus = () => {
126
+ is_focused.value = true;
127
+ };
128
+ const handleBlur = () => {
129
+ is_focused.value = false;
130
+ };
131
+ return {
132
+ state: readonly(state),
133
+ is_focused,
134
+ aria_attributes: readonly(aria_attributes),
135
+ handleFocus,
136
+ handleBlur
137
+ };
138
+ };
139
+ const useCard = (props) => {
140
+ const ui_config = useUI("card");
141
+ const state = computed(() => ({
142
+ padding: props.value.padding ?? ui_config.default_padding
143
+ }));
144
+ return {
145
+ state: readonly(state)
146
+ };
147
+ };
148
+ const useDialog = () => {
149
+ const is_open = ref(false);
150
+ const open = () => {
151
+ is_open.value = true;
152
+ };
153
+ const close = () => {
154
+ is_open.value = false;
155
+ };
156
+ const toggle = () => {
157
+ is_open.value = !is_open.value;
158
+ };
159
+ return {
160
+ is_open: readonly(is_open),
161
+ open,
162
+ close,
163
+ toggle
164
+ };
165
+ };
166
+ const useForm = (schema) => {
167
+ const form_state = reactive({
168
+ values: {},
169
+ errors: {},
170
+ touched: {},
171
+ is_submitting: false,
172
+ is_dirty: false
173
+ });
174
+ const is_valid = computed(() => {
175
+ const result = schema.safeParse(form_state.values);
176
+ return result.success;
177
+ });
178
+ const validateField = (field) => {
179
+ form_state.touched[field] = true;
180
+ form_state.is_dirty = true;
181
+ try {
182
+ const zod_object = schema;
183
+ const field_schema = zod_object.shape[field];
184
+ if (!field_schema) {
185
+ throw new Error(FORM_ERRORS.FIELD_NOT_FOUND);
186
+ }
187
+ field_schema.parse(form_state.values[field]);
188
+ form_state.errors[field] = void 0;
189
+ } catch (error) {
190
+ if (error instanceof ZodError) {
191
+ form_state.errors[field] = error.errors[0].message;
192
+ } else if (error instanceof Error) {
193
+ form_state.errors[field] = error.message;
194
+ }
195
+ }
196
+ };
197
+ const validateAll = () => {
198
+ try {
199
+ schema.parse(form_state.values);
200
+ form_state.errors = {};
201
+ return true;
202
+ } catch (error) {
203
+ if (error instanceof ZodError) {
204
+ form_state.errors = {};
205
+ error.errors.forEach((err) => {
206
+ const field = err.path[0];
207
+ form_state.errors[field] = err.message;
208
+ form_state.touched[field] = true;
209
+ });
210
+ }
211
+ return false;
212
+ }
213
+ };
214
+ const reset = () => {
215
+ form_state.values = {};
216
+ form_state.errors = {};
217
+ form_state.touched = {};
218
+ form_state.is_dirty = false;
219
+ };
220
+ const setValues = (values) => {
221
+ Object.assign(form_state.values, values);
222
+ form_state.is_dirty = true;
223
+ };
224
+ const setFieldValue = (field, value) => {
225
+ form_state.values[field] = value;
226
+ form_state.is_dirty = true;
227
+ };
228
+ const submit = async (on_submit) => {
229
+ if (!validateAll()) {
230
+ return;
231
+ }
232
+ form_state.is_submitting = true;
233
+ try {
234
+ const validated_data = schema.parse(form_state.values);
235
+ await on_submit(validated_data);
236
+ } catch (error) {
237
+ if (error instanceof ZodError) {
238
+ error.errors.forEach((err) => {
239
+ const field = err.path[0];
240
+ form_state.errors[field] = err.message;
241
+ });
242
+ }
243
+ throw error;
244
+ } finally {
245
+ form_state.is_submitting = false;
246
+ }
247
+ };
248
+ const getFieldArray = (field) => {
249
+ const getArray = () => {
250
+ const value = form_state.values[field];
251
+ if (!Array.isArray(value)) {
252
+ form_state.values[field] = [];
253
+ return [];
254
+ }
255
+ return value;
256
+ };
257
+ const helpers = {
258
+ get fields() {
259
+ return getArray();
260
+ },
261
+ append: (value) => {
262
+ const array = getArray();
263
+ array.push(value);
264
+ form_state.is_dirty = true;
265
+ },
266
+ prepend: (value) => {
267
+ const array = getArray();
268
+ array.unshift(value);
269
+ form_state.is_dirty = true;
270
+ },
271
+ insert: (index, value) => {
272
+ const array = getArray();
273
+ array.splice(index, 0, value);
274
+ form_state.is_dirty = true;
275
+ },
276
+ remove: (index) => {
277
+ const array = getArray();
278
+ array.splice(index, 1);
279
+ form_state.is_dirty = true;
280
+ },
281
+ move: (from_index, to_index) => {
282
+ const array = getArray();
283
+ const item = array.splice(from_index, 1)[0];
284
+ array.splice(to_index, 0, item);
285
+ form_state.is_dirty = true;
286
+ },
287
+ swap: (index_a, index_b) => {
288
+ const array = getArray();
289
+ const temp = array[index_a];
290
+ array[index_a] = array[index_b];
291
+ array[index_b] = temp;
292
+ form_state.is_dirty = true;
293
+ },
294
+ replace: (index, value) => {
295
+ const array = getArray();
296
+ array[index] = value;
297
+ form_state.is_dirty = true;
298
+ },
299
+ clear: () => {
300
+ form_state.values[field] = [];
301
+ form_state.is_dirty = true;
302
+ }
303
+ };
304
+ return helpers;
305
+ };
306
+ return {
307
+ values: form_state.values,
308
+ errors: readonly(form_state.errors),
309
+ touched: readonly(form_state.touched),
310
+ is_valid,
311
+ is_submitting: computed(() => form_state.is_submitting),
312
+ is_dirty: computed(() => form_state.is_dirty),
313
+ validateField,
314
+ validateAll,
315
+ reset,
316
+ setValues,
317
+ setFieldValue,
318
+ submit,
319
+ getFieldArray
320
+ };
321
+ };
322
+ const useCheckbox = (props, checked) => {
323
+ const state = computed(() => ({
324
+ size: props.value.size ?? "md",
325
+ disabled: props.value.disabled ?? false,
326
+ indeterminate: props.value.indeterminate ?? false,
327
+ checked: checked.value
328
+ }));
329
+ const aria_attributes = computed(() => ({
330
+ role: "checkbox",
331
+ "aria-checked": state.value.indeterminate ? "mixed" : state.value.checked,
332
+ "aria-disabled": state.value.disabled || void 0
333
+ }));
334
+ return {
335
+ state: readonly(state),
336
+ aria_attributes: readonly(aria_attributes)
337
+ };
338
+ };
339
+ const RADIO_GROUP_KEY = Symbol("radio-group");
340
+ const useRadioItem = (props) => {
341
+ const context = inject(RADIO_GROUP_KEY, null);
342
+ if (!context) {
343
+ throw new Error(COMPONENT_ERRORS.PROVIDER_NOT_FOUND);
344
+ }
345
+ const state = computed(() => ({
346
+ size: props.value.size ?? "md",
347
+ disabled: props.value.disabled ?? context.disabled.value,
348
+ checked: context.model_value.value === props.value.value
349
+ }));
350
+ const aria_attributes = computed(() => ({
351
+ role: "radio",
352
+ "aria-checked": state.value.checked,
353
+ "aria-disabled": state.value.disabled || void 0
354
+ }));
355
+ return {
356
+ state: readonly(state),
357
+ aria_attributes: readonly(aria_attributes)
358
+ };
359
+ };
360
+ const useSwitch = (props, checked) => {
361
+ const state = computed(() => ({
362
+ size: props.value.size ?? "md",
363
+ disabled: props.value.disabled ?? false,
364
+ checked: checked.value
365
+ }));
366
+ const aria_attributes = computed(() => ({
367
+ role: "switch",
368
+ "aria-checked": state.value.checked,
369
+ "aria-disabled": state.value.disabled || void 0
370
+ }));
371
+ return {
372
+ state: readonly(state),
373
+ aria_attributes: readonly(aria_attributes)
374
+ };
375
+ };
376
+ const useTextarea = (props) => {
377
+ const is_focused = ref(false);
378
+ const state = computed(() => ({
379
+ size: props.value.size ?? "md",
380
+ disabled: props.value.disabled ?? false,
381
+ readonly: props.value.readonly ?? false,
382
+ has_error: !!props.value.error,
383
+ resize: props.value.resize ?? "vertical"
384
+ }));
385
+ const aria_attributes = computed(() => ({
386
+ "aria-invalid": state.value.has_error || void 0,
387
+ "aria-describedby": props.value.error_id,
388
+ "aria-readonly": state.value.readonly || void 0
389
+ }));
390
+ const handleFocus = () => {
391
+ is_focused.value = true;
392
+ };
393
+ const handleBlur = () => {
394
+ is_focused.value = false;
395
+ };
396
+ return {
397
+ state: readonly(state),
398
+ is_focused,
399
+ aria_attributes: readonly(aria_attributes),
400
+ handleFocus,
401
+ handleBlur
402
+ };
403
+ };
404
+ const SELECT_KEY = Symbol("select");
405
+ const useSelectTrigger = () => {
406
+ const context = inject(SELECT_KEY, null);
407
+ if (!context) {
408
+ throw new Error(COMPONENT_ERRORS.PROVIDER_NOT_FOUND);
409
+ }
410
+ const state = computed(() => ({
411
+ size: context.size.value,
412
+ disabled: context.disabled.value,
413
+ is_open: context.is_open.value
414
+ }));
415
+ return {
416
+ state: readonly(state)
417
+ };
418
+ };
419
+ const useSelectContent = () => {
420
+ const context = inject(SELECT_KEY, null);
421
+ if (!context) {
422
+ throw new Error(COMPONENT_ERRORS.PROVIDER_NOT_FOUND);
423
+ }
424
+ const state = computed(() => ({
425
+ is_open: context.is_open.value
426
+ }));
427
+ return {
428
+ state: readonly(state)
429
+ };
430
+ };
431
+ const useSelectItem = (props) => {
432
+ const context = inject(SELECT_KEY, null);
433
+ if (!context) {
434
+ throw new Error(COMPONENT_ERRORS.PROVIDER_NOT_FOUND);
435
+ }
436
+ const state = computed(() => ({
437
+ selected: context.model_value.value === props.value.value,
438
+ disabled: props.value.disabled ?? false
439
+ }));
440
+ return {
441
+ state: readonly(state)
442
+ };
443
+ };
444
+ const FILE_ERRORS = {
445
+ MAX_SIZE_EXCEEDED: (max) => `ファイルサイズが${formatFileSize(max)}を超えています`,
446
+ MAX_FILES_EXCEEDED: (max) => `最大${max}ファイルまでアップロードできます`,
447
+ INVALID_TYPE: "許可されていないファイル形式です"
448
+ };
449
+ const formatFileSize = (bytes) => {
450
+ if (bytes < 1024) return `${bytes}B`;
451
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;
452
+ return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
453
+ };
454
+ const createPreviewUrl = (file) => {
455
+ if (file.type.startsWith("image/")) {
456
+ return URL.createObjectURL(file);
457
+ }
458
+ return null;
459
+ };
460
+ const useFileInput = (props, input_ref) => {
461
+ const is_dragging = ref(false);
462
+ const files = ref([]);
463
+ const error = ref(null);
464
+ const state = computed(() => ({
465
+ disabled: props.value.disabled ?? false,
466
+ is_dragging: is_dragging.value,
467
+ has_error: !!error.value,
468
+ has_files: files.value.length > 0
469
+ }));
470
+ const aria_attributes = computed(() => ({
471
+ "aria-disabled": state.value.disabled || void 0,
472
+ "aria-invalid": state.value.has_error || void 0
473
+ }));
474
+ const validateFile = (file) => {
475
+ const { accept, max_size } = props.value;
476
+ if (max_size && file.size > max_size) {
477
+ return FILE_ERRORS.MAX_SIZE_EXCEEDED(max_size);
478
+ }
479
+ if (accept) {
480
+ const accepted_types = accept.split(",").map((t) => t.trim());
481
+ const is_valid = accepted_types.some((type) => {
482
+ if (type.startsWith(".")) {
483
+ return file.name.toLowerCase().endsWith(type.toLowerCase());
484
+ }
485
+ if (type.endsWith("/*")) {
486
+ return file.type.startsWith(type.replace("/*", "/"));
487
+ }
488
+ return file.type === type;
489
+ });
490
+ if (!is_valid) {
491
+ return FILE_ERRORS.INVALID_TYPE;
492
+ }
493
+ }
494
+ return null;
495
+ };
496
+ const handleFiles = (file_list) => {
497
+ if (!file_list || state.value.disabled) return;
498
+ error.value = null;
499
+ const { multiple, max_files } = props.value;
500
+ const new_files = [];
501
+ const files_to_process = Array.from(file_list);
502
+ for (const file of files_to_process) {
503
+ const validation_error = validateFile(file);
504
+ if (validation_error) {
505
+ error.value = validation_error;
506
+ return;
507
+ }
508
+ new_files.push({
509
+ file,
510
+ name: file.name,
511
+ size: file.size,
512
+ type: file.type,
513
+ preview_url: createPreviewUrl(file)
514
+ });
515
+ }
516
+ if (multiple) {
517
+ const total = files.value.length + new_files.length;
518
+ if (max_files && total > max_files) {
519
+ error.value = FILE_ERRORS.MAX_FILES_EXCEEDED(max_files);
520
+ return;
521
+ }
522
+ files.value.push(...new_files);
523
+ } else {
524
+ files.value.forEach((f) => {
525
+ if (f.preview_url) URL.revokeObjectURL(f.preview_url);
526
+ });
527
+ files.value = new_files.slice(0, 1);
528
+ }
529
+ };
530
+ const handleDragEnter = (event) => {
531
+ event.preventDefault();
532
+ if (!state.value.disabled) {
533
+ is_dragging.value = true;
534
+ }
535
+ };
536
+ const handleDragLeave = (event) => {
537
+ event.preventDefault();
538
+ is_dragging.value = false;
539
+ };
540
+ const handleDrop = (event) => {
541
+ var _a;
542
+ event.preventDefault();
543
+ is_dragging.value = false;
544
+ if (!state.value.disabled) {
545
+ handleFiles(((_a = event.dataTransfer) == null ? void 0 : _a.files) ?? null);
546
+ }
547
+ };
548
+ const removeFile = (index) => {
549
+ const removed = files.value.splice(index, 1)[0];
550
+ if (removed == null ? void 0 : removed.preview_url) {
551
+ URL.revokeObjectURL(removed.preview_url);
552
+ }
553
+ };
554
+ const clearFiles = () => {
555
+ files.value.forEach((f) => {
556
+ if (f.preview_url) URL.revokeObjectURL(f.preview_url);
557
+ });
558
+ files.value = [];
559
+ error.value = null;
560
+ };
561
+ const openFilePicker = () => {
562
+ if (!state.value.disabled && input_ref.value) {
563
+ input_ref.value.click();
564
+ }
565
+ };
566
+ return {
567
+ state: readonly(state),
568
+ is_dragging,
569
+ files,
570
+ error,
571
+ aria_attributes: readonly(aria_attributes),
572
+ handleFiles,
573
+ handleDragEnter,
574
+ handleDragLeave,
575
+ handleDrop,
576
+ removeFile,
577
+ clearFiles,
578
+ openFilePicker
579
+ };
580
+ };
581
+ const toasts = ref([]);
582
+ let toast_counter = 0;
583
+ const generateId = () => {
584
+ toast_counter++;
585
+ return `toast-${toast_counter}-${Date.now()}`;
586
+ };
587
+ function useToast() {
588
+ const add = (props) => {
589
+ const id = props.id ?? generateId();
590
+ const toast2 = {
591
+ id,
592
+ title: props.title,
593
+ description: props.description,
594
+ variant: props.variant ?? "default",
595
+ duration: props.duration ?? 5e3,
596
+ dismissible: props.dismissible ?? true,
597
+ action: props.action,
598
+ created_at: Date.now()
599
+ };
600
+ toasts.value = [...toasts.value, toast2];
601
+ if (toast2.duration > 0) {
602
+ setTimeout(() => {
603
+ dismiss(id);
604
+ }, toast2.duration);
605
+ }
606
+ return id;
607
+ };
608
+ const dismiss = (id) => {
609
+ toasts.value = toasts.value.filter((t) => t.id !== id);
610
+ };
611
+ const dismissAll = () => {
612
+ toasts.value = [];
613
+ };
614
+ const update = (id, props) => {
615
+ toasts.value = toasts.value.map((toast2) => {
616
+ if (toast2.id === id) {
617
+ return {
618
+ ...toast2,
619
+ ...props,
620
+ id: toast2.id,
621
+ created_at: toast2.created_at
622
+ };
623
+ }
624
+ return toast2;
625
+ });
626
+ };
627
+ return {
628
+ toasts: [...toasts.value],
629
+ add,
630
+ dismiss,
631
+ dismissAll,
632
+ update
633
+ };
634
+ }
635
+ const toast = {
636
+ default: (props) => useToast().add({ ...props, variant: "default" }),
637
+ success: (props) => useToast().add({ ...props, variant: "success" }),
638
+ error: (props) => useToast().add({ ...props, variant: "error" }),
639
+ warning: (props) => useToast().add({ ...props, variant: "warning" }),
640
+ info: (props) => useToast().add({ ...props, variant: "info" }),
641
+ dismiss: (id) => useToast().dismiss(id),
642
+ dismissAll: () => useToast().dismissAll()
643
+ };
644
+ let tooltip_counter = 0;
645
+ function useTooltip(props) {
646
+ const is_open = ref(false);
647
+ const trigger_ref = ref(null);
648
+ const content_ref = ref(null);
649
+ const tooltip_id = `tooltip-${++tooltip_counter}`;
650
+ let show_timeout = null;
651
+ let hide_timeout = null;
652
+ const clearTimeouts = () => {
653
+ if (show_timeout) {
654
+ clearTimeout(show_timeout);
655
+ show_timeout = null;
656
+ }
657
+ if (hide_timeout) {
658
+ clearTimeout(hide_timeout);
659
+ hide_timeout = null;
660
+ }
661
+ };
662
+ const show = () => {
663
+ if (props.value.disabled) return;
664
+ clearTimeouts();
665
+ is_open.value = true;
666
+ };
667
+ const hide = () => {
668
+ clearTimeouts();
669
+ is_open.value = false;
670
+ };
671
+ const handleMouseEnter = () => {
672
+ if (props.value.disabled) return;
673
+ clearTimeouts();
674
+ const delay = props.value.delay_duration ?? 200;
675
+ show_timeout = setTimeout(() => {
676
+ is_open.value = true;
677
+ }, delay);
678
+ };
679
+ const handleMouseLeave = () => {
680
+ clearTimeouts();
681
+ const skip_delay = props.value.skip_delay_duration ?? 100;
682
+ hide_timeout = setTimeout(() => {
683
+ is_open.value = false;
684
+ }, skip_delay);
685
+ };
686
+ const handleFocus = () => {
687
+ if (props.value.disabled) return;
688
+ show();
689
+ };
690
+ const handleBlur = () => {
691
+ hide();
692
+ };
693
+ const position_styles = computed(() => {
694
+ if (!trigger_ref.value || !is_open.value) {
695
+ return {};
696
+ }
697
+ const side = props.value.side ?? "top";
698
+ const align = props.value.align ?? "center";
699
+ const offset = 8;
700
+ const styles = {
701
+ position: "absolute",
702
+ zIndex: "50"
703
+ };
704
+ switch (side) {
705
+ case "top":
706
+ styles.bottom = "100%";
707
+ styles.marginBottom = `${offset}px`;
708
+ break;
709
+ case "bottom":
710
+ styles.top = "100%";
711
+ styles.marginTop = `${offset}px`;
712
+ break;
713
+ case "left":
714
+ styles.right = "100%";
715
+ styles.marginRight = `${offset}px`;
716
+ break;
717
+ case "right":
718
+ styles.left = "100%";
719
+ styles.marginLeft = `${offset}px`;
720
+ break;
721
+ }
722
+ if (side === "top" || side === "bottom") {
723
+ switch (align) {
724
+ case "start":
725
+ styles.left = "0";
726
+ break;
727
+ case "center":
728
+ styles.left = "50%";
729
+ styles.transform = "translateX(-50%)";
730
+ break;
731
+ case "end":
732
+ styles.right = "0";
733
+ break;
734
+ }
735
+ } else {
736
+ switch (align) {
737
+ case "start":
738
+ styles.top = "0";
739
+ break;
740
+ case "center":
741
+ styles.top = "50%";
742
+ styles.transform = "translateY(-50%)";
743
+ break;
744
+ case "end":
745
+ styles.bottom = "0";
746
+ break;
747
+ }
748
+ }
749
+ return styles;
750
+ });
751
+ onUnmounted(() => {
752
+ clearTimeouts();
753
+ });
754
+ return {
755
+ is_open,
756
+ trigger_ref,
757
+ content_ref,
758
+ tooltip_id,
759
+ position_styles,
760
+ show,
761
+ hide,
762
+ handleMouseEnter,
763
+ handleMouseLeave,
764
+ handleFocus,
765
+ handleBlur
766
+ };
767
+ }
768
+ let popover_counter = 0;
769
+ function usePopover(props) {
770
+ const is_open = ref(false);
771
+ const trigger_ref = ref(null);
772
+ const content_ref = ref(null);
773
+ const popover_id = `popover-${++popover_counter}`;
774
+ const open = () => {
775
+ is_open.value = true;
776
+ };
777
+ const close = () => {
778
+ is_open.value = false;
779
+ };
780
+ const toggle = () => {
781
+ is_open.value = !is_open.value;
782
+ };
783
+ const handleTriggerClick = () => {
784
+ toggle();
785
+ };
786
+ const handleKeyDown = (event) => {
787
+ var _a;
788
+ if (event.key === "Escape" && is_open.value) {
789
+ close();
790
+ (_a = trigger_ref.value) == null ? void 0 : _a.focus();
791
+ }
792
+ };
793
+ const handleClickOutside = (event) => {
794
+ if (!is_open.value) return;
795
+ const target = event.target;
796
+ const trigger = trigger_ref.value;
797
+ const content = content_ref.value;
798
+ if (trigger && trigger.contains(target)) return;
799
+ if (content && content.contains(target)) return;
800
+ close();
801
+ };
802
+ const position_styles = computed(() => {
803
+ if (!trigger_ref.value || !is_open.value) {
804
+ return {};
805
+ }
806
+ const side = props.value.side ?? "bottom";
807
+ const align = props.value.align ?? "center";
808
+ const offset = 8;
809
+ const styles = {
810
+ position: "absolute",
811
+ zIndex: "50"
812
+ };
813
+ switch (side) {
814
+ case "top":
815
+ styles.bottom = "100%";
816
+ styles.marginBottom = `${offset}px`;
817
+ break;
818
+ case "bottom":
819
+ styles.top = "100%";
820
+ styles.marginTop = `${offset}px`;
821
+ break;
822
+ case "left":
823
+ styles.right = "100%";
824
+ styles.marginRight = `${offset}px`;
825
+ break;
826
+ case "right":
827
+ styles.left = "100%";
828
+ styles.marginLeft = `${offset}px`;
829
+ break;
830
+ }
831
+ if (side === "top" || side === "bottom") {
832
+ switch (align) {
833
+ case "start":
834
+ styles.left = "0";
835
+ break;
836
+ case "center":
837
+ styles.left = "50%";
838
+ styles.transform = "translateX(-50%)";
839
+ break;
840
+ case "end":
841
+ styles.right = "0";
842
+ break;
843
+ }
844
+ } else {
845
+ switch (align) {
846
+ case "start":
847
+ styles.top = "0";
848
+ break;
849
+ case "center":
850
+ styles.top = "50%";
851
+ styles.transform = "translateY(-50%)";
852
+ break;
853
+ case "end":
854
+ styles.bottom = "0";
855
+ break;
856
+ }
857
+ }
858
+ return styles;
859
+ });
860
+ onMounted(() => {
861
+ document.addEventListener("mousedown", handleClickOutside);
862
+ document.addEventListener("keydown", handleKeyDown);
863
+ });
864
+ onUnmounted(() => {
865
+ document.removeEventListener("mousedown", handleClickOutside);
866
+ document.removeEventListener("keydown", handleKeyDown);
867
+ });
868
+ return {
869
+ is_open,
870
+ trigger_ref,
871
+ content_ref,
872
+ popover_id,
873
+ position_styles,
874
+ open,
875
+ close,
876
+ toggle,
877
+ handleTriggerClick,
878
+ handleKeyDown
879
+ };
880
+ }
881
+ let dropdown_counter = 0;
882
+ function useDropdown(props) {
883
+ const is_open = ref(false);
884
+ const trigger_ref = ref(null);
885
+ const content_ref = ref(null);
886
+ const dropdown_id = `dropdown-${++dropdown_counter}`;
887
+ const active_item_index = ref(-1);
888
+ const items_count = ref(0);
889
+ let item_counter = 0;
890
+ const open = () => {
891
+ is_open.value = true;
892
+ active_item_index.value = 0;
893
+ };
894
+ const close = () => {
895
+ is_open.value = false;
896
+ active_item_index.value = -1;
897
+ };
898
+ const toggle = () => {
899
+ if (is_open.value) {
900
+ close();
901
+ } else {
902
+ open();
903
+ }
904
+ };
905
+ const handleTriggerClick = () => {
906
+ toggle();
907
+ };
908
+ const handleTriggerKeyDown = (event) => {
909
+ switch (event.key) {
910
+ case "Enter":
911
+ case " ":
912
+ case "ArrowDown":
913
+ event.preventDefault();
914
+ open();
915
+ break;
916
+ case "ArrowUp":
917
+ event.preventDefault();
918
+ open();
919
+ active_item_index.value = items_count.value - 1;
920
+ break;
921
+ }
922
+ };
923
+ const handleContentKeyDown = (event) => {
924
+ var _a;
925
+ switch (event.key) {
926
+ case "ArrowDown":
927
+ event.preventDefault();
928
+ active_item_index.value = Math.min(active_item_index.value + 1, items_count.value - 1);
929
+ break;
930
+ case "ArrowUp":
931
+ event.preventDefault();
932
+ active_item_index.value = Math.max(active_item_index.value - 1, 0);
933
+ break;
934
+ case "Home":
935
+ event.preventDefault();
936
+ active_item_index.value = 0;
937
+ break;
938
+ case "End":
939
+ event.preventDefault();
940
+ active_item_index.value = items_count.value - 1;
941
+ break;
942
+ case "Escape":
943
+ event.preventDefault();
944
+ close();
945
+ (_a = trigger_ref.value) == null ? void 0 : _a.focus();
946
+ break;
947
+ case "Tab":
948
+ close();
949
+ break;
950
+ }
951
+ };
952
+ const handleClickOutside = (event) => {
953
+ if (!is_open.value) return;
954
+ const target = event.target;
955
+ const trigger = trigger_ref.value;
956
+ const content = content_ref.value;
957
+ if (trigger && trigger.contains(target)) return;
958
+ if (content && content.contains(target)) return;
959
+ close();
960
+ };
961
+ const registerItem = () => {
962
+ const index = item_counter++;
963
+ items_count.value = item_counter;
964
+ return index;
965
+ };
966
+ const setActiveItem = (index) => {
967
+ active_item_index.value = index;
968
+ };
969
+ const position_styles = computed(() => {
970
+ if (!trigger_ref.value || !is_open.value) {
971
+ return {};
972
+ }
973
+ const side = props.value.side ?? "bottom";
974
+ const align = props.value.align ?? "start";
975
+ const offset = 4;
976
+ const styles = {
977
+ position: "absolute",
978
+ zIndex: "50"
979
+ };
980
+ switch (side) {
981
+ case "top":
982
+ styles.bottom = "100%";
983
+ styles.marginBottom = `${offset}px`;
984
+ break;
985
+ case "bottom":
986
+ styles.top = "100%";
987
+ styles.marginTop = `${offset}px`;
988
+ break;
989
+ case "left":
990
+ styles.right = "100%";
991
+ styles.marginRight = `${offset}px`;
992
+ break;
993
+ case "right":
994
+ styles.left = "100%";
995
+ styles.marginLeft = `${offset}px`;
996
+ break;
997
+ }
998
+ if (side === "top" || side === "bottom") {
999
+ switch (align) {
1000
+ case "start":
1001
+ styles.left = "0";
1002
+ break;
1003
+ case "center":
1004
+ styles.left = "50%";
1005
+ styles.transform = "translateX(-50%)";
1006
+ break;
1007
+ case "end":
1008
+ styles.right = "0";
1009
+ break;
1010
+ }
1011
+ } else {
1012
+ switch (align) {
1013
+ case "start":
1014
+ styles.top = "0";
1015
+ break;
1016
+ case "center":
1017
+ styles.top = "50%";
1018
+ styles.transform = "translateY(-50%)";
1019
+ break;
1020
+ case "end":
1021
+ styles.bottom = "0";
1022
+ break;
1023
+ }
1024
+ }
1025
+ return styles;
1026
+ });
1027
+ onMounted(() => {
1028
+ document.addEventListener("mousedown", handleClickOutside);
1029
+ });
1030
+ onUnmounted(() => {
1031
+ document.removeEventListener("mousedown", handleClickOutside);
1032
+ });
1033
+ return {
1034
+ is_open,
1035
+ trigger_ref,
1036
+ content_ref,
1037
+ dropdown_id,
1038
+ active_item_index,
1039
+ items_count,
1040
+ position_styles,
1041
+ open,
1042
+ close,
1043
+ toggle,
1044
+ handleTriggerClick,
1045
+ handleTriggerKeyDown,
1046
+ handleContentKeyDown,
1047
+ registerItem,
1048
+ setActiveItem
1049
+ };
1050
+ }
1051
+ const DEFAULT_OPTIONS = {
1052
+ default_mode: "system",
1053
+ storage_key: "soave-ui-theme",
1054
+ attribute: "data-theme"
1055
+ };
1056
+ function useTheme(options = {}) {
1057
+ const merged_options = { ...DEFAULT_OPTIONS, ...options };
1058
+ const mode = ref(merged_options.default_mode);
1059
+ let media_query = null;
1060
+ const getSystemTheme = () => {
1061
+ if (typeof window === "undefined") return "light";
1062
+ return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
1063
+ };
1064
+ const resolved_mode = computed(() => {
1065
+ if (mode.value === "system") {
1066
+ return getSystemTheme();
1067
+ }
1068
+ return mode.value;
1069
+ });
1070
+ const applyTheme = (theme) => {
1071
+ if (typeof document === "undefined") return;
1072
+ const root = document.documentElement;
1073
+ root.setAttribute(merged_options.attribute, theme);
1074
+ if (theme === "dark") {
1075
+ root.classList.add("dark");
1076
+ } else {
1077
+ root.classList.remove("dark");
1078
+ }
1079
+ };
1080
+ const setMode = (new_mode) => {
1081
+ mode.value = new_mode;
1082
+ if (typeof localStorage !== "undefined") {
1083
+ localStorage.setItem(merged_options.storage_key, new_mode);
1084
+ }
1085
+ applyTheme(resolved_mode.value);
1086
+ };
1087
+ const toggleMode = () => {
1088
+ const next_mode = resolved_mode.value === "light" ? "dark" : "light";
1089
+ setMode(next_mode);
1090
+ };
1091
+ const handleSystemThemeChange = (event) => {
1092
+ if (mode.value === "system") {
1093
+ applyTheme(event.matches ? "dark" : "light");
1094
+ }
1095
+ };
1096
+ onMounted(() => {
1097
+ if (typeof localStorage !== "undefined") {
1098
+ const stored = localStorage.getItem(merged_options.storage_key);
1099
+ if (stored && ["light", "dark", "system"].includes(stored)) {
1100
+ mode.value = stored;
1101
+ }
1102
+ }
1103
+ if (typeof window !== "undefined") {
1104
+ media_query = window.matchMedia("(prefers-color-scheme: dark)");
1105
+ media_query.addEventListener("change", handleSystemThemeChange);
1106
+ }
1107
+ applyTheme(resolved_mode.value);
1108
+ });
1109
+ onUnmounted(() => {
1110
+ if (media_query) {
1111
+ media_query.removeEventListener("change", handleSystemThemeChange);
1112
+ }
1113
+ });
1114
+ watch(mode, () => {
1115
+ applyTheme(resolved_mode.value);
1116
+ });
1117
+ return {
1118
+ mode,
1119
+ resolved_mode,
1120
+ setMode,
1121
+ toggleMode
1122
+ };
1123
+ }
1124
+ function generateThemeCSS(light, dark) {
1125
+ const formatColor = (key, value) => {
1126
+ const css_key = key.replace(/_/g, "-");
1127
+ return ` --${css_key}: ${value};`;
1128
+ };
1129
+ const lightCSS = Object.entries(light).map(([key, value]) => formatColor(key, value)).join("\n");
1130
+ const darkCSS = Object.entries(dark).map(([key, value]) => formatColor(key, value)).join("\n");
1131
+ return `:root {
1132
+ ${lightCSS}
1133
+ }
1134
+
1135
+ .dark {
1136
+ ${darkCSS}
1137
+ }`;
1138
+ }
1139
+ export {
1140
+ DIALOG_ERRORS as A,
1141
+ COMPONENT_ERRORS as C,
1142
+ DEFAULT_UI_CONFIG as D,
1143
+ FORM_ERRORS as F,
1144
+ INPUT_ERRORS as I,
1145
+ RADIO_GROUP_KEY as R,
1146
+ SELECT_KEY as S,
1147
+ UI_PROVIDER_KEY as U,
1148
+ useInput as a,
1149
+ useCard as b,
1150
+ useDialog as c,
1151
+ useForm as d,
1152
+ useUIProvider as e,
1153
+ useUI as f,
1154
+ useUIConfig as g,
1155
+ useStyleAdapter as h,
1156
+ UI_CONFIG_KEY as i,
1157
+ useCheckbox as j,
1158
+ useRadioItem as k,
1159
+ useSwitch as l,
1160
+ useTextarea as m,
1161
+ useSelectTrigger as n,
1162
+ useSelectContent as o,
1163
+ useSelectItem as p,
1164
+ useFileInput as q,
1165
+ useToast as r,
1166
+ useTooltip as s,
1167
+ toast as t,
1168
+ useButton as u,
1169
+ usePopover as v,
1170
+ useDropdown as w,
1171
+ useTheme as x,
1172
+ generateThemeCSS as y,
1173
+ deepMerge as z
1174
+ };
1175
+ //# sourceMappingURL=useTheme-C2uPqAtQ.js.map