windly-ui 1.0.2 → 1.0.3

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/{ui-library/dist → dist}/module.json +2 -2
  2. package/dist/module.mjs +26 -0
  3. package/dist/runtime/components/Accordion.d.vue.ts +39 -0
  4. package/dist/runtime/components/Accordion.vue +92 -0
  5. package/dist/runtime/components/Accordion.vue.d.ts +39 -0
  6. package/dist/runtime/components/Avatar.d.vue.ts +141 -0
  7. package/dist/runtime/components/Avatar.vue +72 -0
  8. package/dist/runtime/components/Avatar.vue.d.ts +141 -0
  9. package/dist/runtime/components/Badge.d.vue.ts +133 -0
  10. package/dist/runtime/components/Badge.vue +99 -0
  11. package/dist/runtime/components/Badge.vue.d.ts +133 -0
  12. package/dist/runtime/components/Breadcrumbs.d.vue.ts +83 -0
  13. package/dist/runtime/components/Breadcrumbs.vue +116 -0
  14. package/dist/runtime/components/Breadcrumbs.vue.d.ts +83 -0
  15. package/dist/runtime/components/Button.d.vue.ts +199 -0
  16. package/dist/runtime/components/Button.vue +125 -0
  17. package/dist/runtime/components/Button.vue.d.ts +199 -0
  18. package/dist/runtime/components/Card.d.vue.ts +83 -0
  19. package/dist/runtime/components/Card.vue +71 -0
  20. package/dist/runtime/components/Card.vue.d.ts +83 -0
  21. package/dist/runtime/components/Checkbox.d.vue.ts +190 -0
  22. package/dist/runtime/components/Checkbox.vue +125 -0
  23. package/dist/runtime/components/Checkbox.vue.d.ts +190 -0
  24. package/dist/runtime/components/CodeBlock.d.vue.ts +16 -0
  25. package/dist/runtime/components/CodeBlock.vue +75 -0
  26. package/dist/runtime/components/CodeBlock.vue.d.ts +16 -0
  27. package/dist/runtime/components/ColorPicker.d.vue.ts +91 -0
  28. package/dist/runtime/components/ColorPicker.vue +244 -0
  29. package/dist/runtime/components/ColorPicker.vue.d.ts +91 -0
  30. package/dist/runtime/components/Date.d.vue.ts +137 -0
  31. package/dist/runtime/components/Date.vue +201 -0
  32. package/dist/runtime/components/Date.vue.d.ts +137 -0
  33. package/dist/runtime/components/Dialog.d.vue.ts +103 -0
  34. package/dist/runtime/components/Dialog.vue +152 -0
  35. package/dist/runtime/components/Dialog.vue.d.ts +103 -0
  36. package/dist/runtime/components/Divider.d.vue.ts +51 -0
  37. package/dist/runtime/components/Divider.vue +52 -0
  38. package/dist/runtime/components/Divider.vue.d.ts +51 -0
  39. package/dist/runtime/components/Drawer.d.vue.ts +30 -0
  40. package/dist/runtime/components/Drawer.vue +43 -0
  41. package/dist/runtime/components/Drawer.vue.d.ts +30 -0
  42. package/dist/runtime/components/Dropdown.d.vue.ts +34 -0
  43. package/dist/runtime/components/Dropdown.vue +127 -0
  44. package/dist/runtime/components/Dropdown.vue.d.ts +34 -0
  45. package/dist/runtime/components/FileUploader.d.vue.ts +58 -0
  46. package/dist/runtime/components/FileUploader.vue +202 -0
  47. package/dist/runtime/components/FileUploader.vue.d.ts +58 -0
  48. package/dist/runtime/components/Icon.d.vue.ts +41 -0
  49. package/dist/runtime/components/Icon.vue +66 -0
  50. package/dist/runtime/components/Icon.vue.d.ts +41 -0
  51. package/dist/runtime/components/Image.d.vue.ts +77 -0
  52. package/dist/runtime/components/Image.vue +61 -0
  53. package/dist/runtime/components/Image.vue.d.ts +77 -0
  54. package/dist/runtime/components/Input.d.vue.ts +66 -0
  55. package/dist/runtime/components/Input.vue +233 -0
  56. package/dist/runtime/components/Input.vue.d.ts +66 -0
  57. package/dist/runtime/components/Radio.d.vue.ts +41 -0
  58. package/dist/runtime/components/Radio.vue +222 -0
  59. package/dist/runtime/components/Radio.vue.d.ts +41 -0
  60. package/dist/runtime/components/ScrollArea.d.vue.ts +79 -0
  61. package/dist/runtime/components/ScrollArea.vue +36 -0
  62. package/dist/runtime/components/ScrollArea.vue.d.ts +79 -0
  63. package/dist/runtime/components/Select.d.vue.ts +43 -0
  64. package/dist/runtime/components/Select.vue +200 -0
  65. package/dist/runtime/components/Select.vue.d.ts +43 -0
  66. package/dist/runtime/components/Stepper.d.vue.ts +46 -0
  67. package/dist/runtime/components/Stepper.vue +218 -0
  68. package/dist/runtime/components/Stepper.vue.d.ts +46 -0
  69. package/dist/runtime/components/TabPanel.d.vue.ts +17 -0
  70. package/dist/runtime/components/TabPanel.vue +21 -0
  71. package/dist/runtime/components/TabPanel.vue.d.ts +17 -0
  72. package/dist/runtime/components/Table.d.vue.ts +40 -0
  73. package/dist/runtime/components/Table.vue +92 -0
  74. package/dist/runtime/components/Table.vue.d.ts +40 -0
  75. package/dist/runtime/components/Tabs.d.vue.ts +20 -0
  76. package/dist/runtime/components/Tabs.vue +62 -0
  77. package/dist/runtime/components/Tabs.vue.d.ts +20 -0
  78. package/dist/runtime/components/Textarea.d.vue.ts +208 -0
  79. package/dist/runtime/components/Textarea.vue +185 -0
  80. package/dist/runtime/components/Textarea.vue.d.ts +208 -0
  81. package/dist/runtime/components/Toggle.d.vue.ts +36 -0
  82. package/dist/runtime/components/Toggle.vue +173 -0
  83. package/dist/runtime/components/Toggle.vue.d.ts +36 -0
  84. package/dist/runtime/components/Tooltip.d.vue.ts +63 -0
  85. package/dist/runtime/components/Tooltip.vue +144 -0
  86. package/dist/runtime/components/Tooltip.vue.d.ts +63 -0
  87. package/dist/runtime/components/uiProps.d.ts +38 -0
  88. package/dist/runtime/components/uiProps.js +11 -0
  89. package/dist/runtime/components/useUiClasses.d.ts +43 -0
  90. package/dist/runtime/components/useUiClasses.js +124 -0
  91. package/dist/runtime/composables/plugin.d.ts +2 -0
  92. package/dist/runtime/composables/plugin.js +3 -0
  93. package/dist/runtime/tailwind-color.d.ts +2 -0
  94. package/dist/runtime/tailwind-color.js +5859 -0
  95. package/package.json +12 -46
  96. package/LICENSE +0 -21
  97. package/README.md +0 -232
  98. package/ui-library/dist/module.mjs +0 -22
  99. /package/{ui-library/dist → dist}/module.d.mts +0 -0
  100. /package/{ui-library/dist → dist}/types.d.mts +0 -0
@@ -0,0 +1,222 @@
1
+ <script setup>
2
+ defineOptions({
3
+ name: "UIRadio"
4
+ });
5
+ import { computed } from "vue";
6
+ const props = defineProps({
7
+ modelValue: { type: [String, Number, Boolean], required: false, default: "" },
8
+ value: { type: [String, Number, Boolean], required: true },
9
+ label: { type: String, required: true },
10
+ id: { type: String, required: false, default: void 0 },
11
+ name: { type: String, required: false, default: "" },
12
+ hint: { type: String, required: false, default: "" },
13
+ icon: { type: String, required: false, default: "" },
14
+ disable: { type: Boolean, required: false, default: false },
15
+ color: { type: String, required: false, default: "blue-500" },
16
+ size: { type: String, required: false, default: "md" },
17
+ rounded: { type: String, required: false, default: "full" },
18
+ flat: { type: Boolean, required: false, default: false },
19
+ bordered: { type: Boolean, required: false, default: true },
20
+ borderColor: { type: String, required: false, default: "gray-300" },
21
+ labelPosition: { type: String, required: false, default: "right" }
22
+ });
23
+ const emit = defineEmits(["update:modelValue"]);
24
+ const isHex = (val) => {
25
+ return val.startsWith("#") || val.startsWith("rgb") || val.startsWith("hsl");
26
+ };
27
+ const isChecked = computed(
28
+ () => props.modelValue === props.value
29
+ );
30
+ const sizeClasses = computed(
31
+ () => {
32
+ switch (props.size) {
33
+ case "sm":
34
+ return {
35
+ radio: "w-4 h-4",
36
+ icon: "text-sm"
37
+ };
38
+ case "lg":
39
+ return {
40
+ radio: "w-6 h-6",
41
+ icon: "text-lg"
42
+ };
43
+ case "md":
44
+ default:
45
+ return {
46
+ radio: "w-5 h-5",
47
+ icon: "text-base"
48
+ };
49
+ }
50
+ }
51
+ );
52
+ const roundedClass = computed(
53
+ () => {
54
+ const map = {
55
+ none: "rounded-none",
56
+ sm: "rounded-sm",
57
+ md: "rounded-md",
58
+ lg: "rounded-lg",
59
+ full: "rounded-full"
60
+ };
61
+ return map[props.rounded];
62
+ }
63
+ );
64
+ const labelPositionClass = computed(() => {
65
+ const map = {
66
+ top: "flex-col-reverse",
67
+ bottom: "flex-col",
68
+ left: "flex-row-reverse",
69
+ right: "flex-row"
70
+ };
71
+ return map[props.labelPosition];
72
+ });
73
+ const radioClasses = computed(
74
+ () => [
75
+ "inline-flex items-center justify-center border-2 transition-all duration-200 bg-white dark:bg-gray-900",
76
+ sizeClasses.value.radio,
77
+ roundedClass.value,
78
+ props.flat ? "shadow-none" : "shadow-sm",
79
+ props.disable ? "opacity-50" : "",
80
+ props.bordered && !isHex(
81
+ props.borderColor
82
+ ) ? `border-${props.borderColor}` : "",
83
+ isChecked.value && !isHex(props.color) ? `border-${props.color} text-${props.color}` : "",
84
+ !isChecked.value ? "border-gray-300" : ""
85
+ ]
86
+ );
87
+ const radioStyle = computed(
88
+ () => {
89
+ const style = {};
90
+ if (props.bordered && isHex(
91
+ props.borderColor
92
+ )) {
93
+ style.borderColor = props.borderColor;
94
+ }
95
+ if (isChecked.value && isHex(props.color)) {
96
+ style.borderColor = props.color;
97
+ style.color = props.color;
98
+ }
99
+ return style;
100
+ }
101
+ );
102
+ const iconClasses = computed(
103
+ () => [
104
+ "material-icons transition-opacity duration-200",
105
+ sizeClasses.value.icon,
106
+ isChecked.value ? "opacity-100" : "opacity-0",
107
+ !isHex(props.color) ? `text-${props.color}` : ""
108
+ ]
109
+ );
110
+ const iconStyle = computed(
111
+ () => {
112
+ const style = {};
113
+ if (isHex(props.color)) {
114
+ style.color = props.color;
115
+ }
116
+ return style;
117
+ }
118
+ );
119
+ const toggle = () => {
120
+ if (props.disable)
121
+ return;
122
+ emit(
123
+ "update:modelValue",
124
+ props.value
125
+ );
126
+ };
127
+ </script>
128
+
129
+ <template>
130
+ <div
131
+ class="radio-container flex items-center"
132
+ >
133
+ <input
134
+ :id="id"
135
+ type="radio"
136
+ :name="name"
137
+ :value="value"
138
+ :checked="
139
+ isChecked
140
+ "
141
+ :disabled="
142
+ disable
143
+ "
144
+ class="sr-only"
145
+ @change="toggle"
146
+ >
147
+
148
+ <label
149
+ :for="id"
150
+ tabindex="0"
151
+ role="radio"
152
+ :aria-checked="
153
+ isChecked
154
+ "
155
+ :aria-disabled="
156
+ disable
157
+ "
158
+ :class="[
159
+ 'flex items-center cursor-pointer select-none',
160
+ labelPositionClass,
161
+ {
162
+ 'opacity-50 pointer-events-none': disable
163
+ }
164
+ ]"
165
+ @click.prevent="
166
+ toggle
167
+ "
168
+ @keydown.enter.prevent="
169
+ toggle
170
+ "
171
+ @keydown.space.prevent="
172
+ toggle
173
+ "
174
+ >
175
+ <!-- Radio -->
176
+ <span
177
+ :class="
178
+ radioClasses
179
+ "
180
+ :style="
181
+ radioStyle
182
+ "
183
+ >
184
+ <i
185
+ v-if="
186
+ icon && isChecked
187
+ "
188
+ :class="
189
+ iconClasses
190
+ "
191
+ :style="
192
+ iconStyle
193
+ "
194
+ >
195
+ {{ icon }}
196
+ </i>
197
+ <span
198
+ v-else
199
+ class="block m-auto rounded-full"
200
+ :class="
201
+ [
202
+ !isHex(props.color) && isChecked ? `bg-${props.color}` : '',
203
+ size === 'sm' ? 'w-2 h-2' : size === 'lg' ? 'w-3 h-3' : 'w-2.5 h-2.5'
204
+ ]
205
+ "
206
+ :style="isHex(props.color) ? { backgroundColor: props.color } : {}"
207
+ />
208
+ </span>
209
+
210
+ <!-- Label -->
211
+ <span
212
+ class="mx-2 font-medium text-gray-700 dark:text-gray-300"
213
+ >
214
+ {{ label }}
215
+ </span>
216
+ </label>
217
+ </div>
218
+ </template>
219
+
220
+ <style scoped>
221
+ .radio-container{-webkit-user-select:none;-moz-user-select:none;user-select:none}
222
+ </style>
@@ -0,0 +1,41 @@
1
+ type LabelPosition = 'top' | 'bottom' | 'left' | 'right';
2
+ type RadioSize = 'sm' | 'md' | 'lg';
3
+ type Rounded = 'none' | 'sm' | 'md' | 'lg' | 'full';
4
+ type __VLS_Props = {
5
+ modelValue?: string | number | boolean;
6
+ value: string | number | boolean;
7
+ label: string;
8
+ id?: string;
9
+ name?: string;
10
+ hint?: string;
11
+ icon?: string;
12
+ disable?: boolean;
13
+ color?: string;
14
+ size?: RadioSize;
15
+ rounded?: Rounded;
16
+ flat?: boolean;
17
+ bordered?: boolean;
18
+ borderColor?: string;
19
+ labelPosition?: LabelPosition;
20
+ };
21
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
22
+ "update:modelValue": (value: string | number | boolean) => any;
23
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
24
+ "onUpdate:modelValue"?: ((value: string | number | boolean) => any) | undefined;
25
+ }>, {
26
+ modelValue: string | number | boolean;
27
+ name: string;
28
+ disable: boolean;
29
+ color: string;
30
+ rounded: Rounded;
31
+ size: RadioSize;
32
+ borderColor: string;
33
+ icon: string;
34
+ flat: boolean;
35
+ id: string;
36
+ bordered: boolean;
37
+ hint: string;
38
+ labelPosition: LabelPosition;
39
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
40
+ declare const _default: typeof __VLS_export;
41
+ export default _default;
@@ -0,0 +1,79 @@
1
+ declare var __VLS_1: {};
2
+ type __VLS_Slots = {} & {
3
+ default?: (props: typeof __VLS_1) => any;
4
+ };
5
+ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
6
+ width: {
7
+ type: StringConstructor;
8
+ default: string;
9
+ };
10
+ height: {
11
+ type: StringConstructor;
12
+ default: string;
13
+ };
14
+ maxWidth: {
15
+ type: StringConstructor;
16
+ default: string;
17
+ };
18
+ maxHeight: {
19
+ type: StringConstructor;
20
+ default: string;
21
+ };
22
+ horizontal: {
23
+ type: BooleanConstructor;
24
+ default: boolean;
25
+ };
26
+ vertical: {
27
+ type: BooleanConstructor;
28
+ default: boolean;
29
+ };
30
+ hideScrollbar: {
31
+ type: BooleanConstructor;
32
+ default: boolean;
33
+ };
34
+ }>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
35
+ width: {
36
+ type: StringConstructor;
37
+ default: string;
38
+ };
39
+ height: {
40
+ type: StringConstructor;
41
+ default: string;
42
+ };
43
+ maxWidth: {
44
+ type: StringConstructor;
45
+ default: string;
46
+ };
47
+ maxHeight: {
48
+ type: StringConstructor;
49
+ default: string;
50
+ };
51
+ horizontal: {
52
+ type: BooleanConstructor;
53
+ default: boolean;
54
+ };
55
+ vertical: {
56
+ type: BooleanConstructor;
57
+ default: boolean;
58
+ };
59
+ hideScrollbar: {
60
+ type: BooleanConstructor;
61
+ default: boolean;
62
+ };
63
+ }>> & Readonly<{}>, {
64
+ horizontal: boolean;
65
+ vertical: boolean;
66
+ width: string;
67
+ maxWidth: string;
68
+ height: string;
69
+ maxHeight: string;
70
+ hideScrollbar: boolean;
71
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
72
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
73
+ declare const _default: typeof __VLS_export;
74
+ export default _default;
75
+ type __VLS_WithSlots<T, S> = T & {
76
+ new (): {
77
+ $slots: S;
78
+ };
79
+ };
@@ -0,0 +1,36 @@
1
+ <script setup>
2
+ defineOptions({
3
+ inheritAttrs: false
4
+ });
5
+ import { computed } from "vue";
6
+ const props = defineProps({
7
+ width: { type: String, default: "100%" },
8
+ height: { type: String, default: "300px" },
9
+ maxWidth: { type: String, default: "" },
10
+ maxHeight: { type: String, default: "" },
11
+ horizontal: { type: Boolean, default: false },
12
+ vertical: { type: Boolean, default: true },
13
+ hideScrollbar: { type: Boolean, default: false }
14
+ });
15
+ const scrollStyle = computed(() => ({
16
+ width: props.width,
17
+ height: props.height,
18
+ maxWidth: props.maxWidth || void 0,
19
+ maxHeight: props.maxHeight || void 0
20
+ }));
21
+ const scrollClass = computed(() => [
22
+ props.vertical ? "overflow-y-auto" : "overflow-y-hidden",
23
+ props.horizontal ? "overflow-x-auto" : "overflow-x-hidden",
24
+ props.hideScrollbar ? "scrollbar-hide" : ""
25
+ ]);
26
+ </script>
27
+
28
+ <template>
29
+ <div
30
+ :class="scrollClass"
31
+ :style="scrollStyle"
32
+ v-bind="$attrs"
33
+ >
34
+ <slot />
35
+ </div>
36
+ </template>
@@ -0,0 +1,79 @@
1
+ declare var __VLS_1: {};
2
+ type __VLS_Slots = {} & {
3
+ default?: (props: typeof __VLS_1) => any;
4
+ };
5
+ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
6
+ width: {
7
+ type: StringConstructor;
8
+ default: string;
9
+ };
10
+ height: {
11
+ type: StringConstructor;
12
+ default: string;
13
+ };
14
+ maxWidth: {
15
+ type: StringConstructor;
16
+ default: string;
17
+ };
18
+ maxHeight: {
19
+ type: StringConstructor;
20
+ default: string;
21
+ };
22
+ horizontal: {
23
+ type: BooleanConstructor;
24
+ default: boolean;
25
+ };
26
+ vertical: {
27
+ type: BooleanConstructor;
28
+ default: boolean;
29
+ };
30
+ hideScrollbar: {
31
+ type: BooleanConstructor;
32
+ default: boolean;
33
+ };
34
+ }>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
35
+ width: {
36
+ type: StringConstructor;
37
+ default: string;
38
+ };
39
+ height: {
40
+ type: StringConstructor;
41
+ default: string;
42
+ };
43
+ maxWidth: {
44
+ type: StringConstructor;
45
+ default: string;
46
+ };
47
+ maxHeight: {
48
+ type: StringConstructor;
49
+ default: string;
50
+ };
51
+ horizontal: {
52
+ type: BooleanConstructor;
53
+ default: boolean;
54
+ };
55
+ vertical: {
56
+ type: BooleanConstructor;
57
+ default: boolean;
58
+ };
59
+ hideScrollbar: {
60
+ type: BooleanConstructor;
61
+ default: boolean;
62
+ };
63
+ }>> & Readonly<{}>, {
64
+ horizontal: boolean;
65
+ vertical: boolean;
66
+ width: string;
67
+ maxWidth: string;
68
+ height: string;
69
+ maxHeight: string;
70
+ hideScrollbar: boolean;
71
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
72
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
73
+ declare const _default: typeof __VLS_export;
74
+ export default _default;
75
+ type __VLS_WithSlots<T, S> = T & {
76
+ new (): {
77
+ $slots: S;
78
+ };
79
+ };
@@ -0,0 +1,43 @@
1
+ interface SelectOption {
2
+ text: string;
3
+ value: string | number | boolean;
4
+ }
5
+ type Rounded = 'none' | 'sm' | 'md' | 'lg' | 'xl' | 'full';
6
+ type __VLS_Props = {
7
+ filter?: boolean;
8
+ modelValue?: string | number | boolean;
9
+ label: string;
10
+ id?: string;
11
+ options: SelectOption[];
12
+ placeholder?: string;
13
+ disabled?: boolean;
14
+ required?: boolean;
15
+ hint?: string;
16
+ flat?: boolean;
17
+ bordered?: boolean;
18
+ rounded?: Rounded;
19
+ borderColor?: string;
20
+ bgColor?: string;
21
+ textColor?: string;
22
+ };
23
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
24
+ "update:modelValue": (value: string | number | boolean) => any;
25
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
26
+ "onUpdate:modelValue"?: ((value: string | number | boolean) => any) | undefined;
27
+ }>, {
28
+ modelValue: string | number | boolean;
29
+ disabled: boolean;
30
+ filter: boolean;
31
+ textColor: string;
32
+ rounded: Rounded;
33
+ borderColor: string;
34
+ required: boolean;
35
+ flat: boolean;
36
+ id: string;
37
+ placeholder: string;
38
+ bordered: boolean;
39
+ bgColor: string;
40
+ hint: string;
41
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
42
+ declare const _default: typeof __VLS_export;
43
+ export default _default;
@@ -0,0 +1,200 @@
1
+ <script setup>
2
+ defineOptions({
3
+ name: "UISelect"
4
+ });
5
+ import {
6
+ computed,
7
+ ref,
8
+ watch
9
+ } from "vue";
10
+ const props = defineProps({
11
+ filter: { type: Boolean, required: false, default: false },
12
+ modelValue: { type: [String, Number, Boolean], required: false, default: "" },
13
+ label: { type: String, required: true },
14
+ id: { type: String, required: false, default: void 0 },
15
+ options: { type: Array, required: true },
16
+ placeholder: { type: String, required: false, default: "Search or select..." },
17
+ disabled: { type: Boolean, required: false, default: false },
18
+ required: { type: Boolean, required: false, default: false },
19
+ hint: { type: String, required: false, default: "" },
20
+ flat: { type: Boolean, required: false, default: false },
21
+ bordered: { type: Boolean, required: false, default: true },
22
+ rounded: { type: String, required: false, default: "md" },
23
+ borderColor: { type: String, required: false, default: "gray-300" },
24
+ bgColor: { type: String, required: false, default: "white" },
25
+ textColor: { type: String, required: false, default: "black" }
26
+ });
27
+ const emit = defineEmits(["update:modelValue"]);
28
+ const searchQuery = ref("");
29
+ const showDropdown = ref(false);
30
+ const isHex = (val) => {
31
+ return val.startsWith("#") || val.startsWith("rgb") || val.startsWith("hsl");
32
+ };
33
+ const roundedClass = computed(() => {
34
+ const map = {
35
+ none: "rounded-none",
36
+ sm: "rounded-sm",
37
+ md: "rounded-md",
38
+ lg: "rounded-lg",
39
+ xl: "rounded-xl",
40
+ full: "rounded-full"
41
+ };
42
+ return map[props.rounded];
43
+ });
44
+ const selectClasses = computed(() => [
45
+ "block w-full px-3 py-2 transition-all focus:outline-none",
46
+ roundedClass.value,
47
+ props.flat ? "shadow-none" : "shadow-sm",
48
+ props.bordered ? !isHex(
49
+ props.borderColor
50
+ ) ? `border border-${props.borderColor}` : "border" : "border-0",
51
+ !isHex(props.bgColor) ? `bg-${props.bgColor}` : "",
52
+ !isHex(
53
+ props.textColor
54
+ ) ? `text-${props.textColor}` : "",
55
+ props.disabled ? "opacity-50 cursor-not-allowed" : ""
56
+ ]);
57
+ const selectStyles = computed(() => {
58
+ const style = {};
59
+ if (isHex(props.bgColor)) {
60
+ style.backgroundColor = props.bgColor;
61
+ }
62
+ if (isHex(
63
+ props.borderColor
64
+ )) {
65
+ style.borderColor = props.borderColor;
66
+ }
67
+ if (isHex(
68
+ props.textColor
69
+ )) {
70
+ style.color = props.textColor;
71
+ }
72
+ return style;
73
+ });
74
+ const filteredOptions = computed(() => {
75
+ const query = searchQuery.value.toLowerCase();
76
+ return props.options.filter(
77
+ (option) => option.text.toLowerCase().includes(query)
78
+ );
79
+ });
80
+ watch(
81
+ () => props.modelValue,
82
+ (val) => {
83
+ const selected = props.options.find(
84
+ (opt) => opt.value === val
85
+ );
86
+ if (selected) {
87
+ searchQuery.value = selected.text;
88
+ }
89
+ },
90
+ {
91
+ immediate: true
92
+ }
93
+ );
94
+ const selectOption = (option) => {
95
+ searchQuery.value = option.text;
96
+ emit(
97
+ "update:modelValue",
98
+ option.value
99
+ );
100
+ showDropdown.value = false;
101
+ };
102
+ const handleChange = (event) => {
103
+ const target = event.target;
104
+ emit(
105
+ "update:modelValue",
106
+ target.value
107
+ );
108
+ };
109
+ const handleBlur = () => {
110
+ setTimeout(() => {
111
+ showDropdown.value = false;
112
+ }, 100);
113
+ };
114
+ </script>
115
+
116
+ <template>
117
+ <div class="relative my-5">
118
+ <!-- Label -->
119
+ <label v-if="label" :for="id" class="block mb-2 text-sm font-medium text-gray-600 dark:text-gray-300">
120
+ {{ label }}
121
+ </label>
122
+
123
+ <!-- Filterable Select -->
124
+ <div v-if="filter" class="relative">
125
+ <input v-model="
126
+ searchQuery
127
+ " :placeholder="
128
+ placeholder
129
+ " :disabled="
130
+ disabled
131
+ " :required="
132
+ required
133
+ " :class="
134
+ selectClasses
135
+ " :style="
136
+ selectStyles
137
+ " @focus="
138
+ showDropdown = true
139
+ " @blur="
140
+ handleBlur
141
+ " @input="
142
+ showDropdown = true
143
+ ">
144
+
145
+ <!-- Dropdown -->
146
+ <ul v-if="
147
+ showDropdown
148
+ "
149
+ class="absolute z-10 mt-1 w-full max-h-48 overflow-y-auto bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-md shadow-lg">
150
+ <li v-for="option in filteredOptions" :key="
151
+ option.value.toString()
152
+ " class="px-4 py-2 cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-700" @mousedown.prevent="
153
+ selectOption(
154
+ option
155
+ )
156
+ ">
157
+ {{ option.text }}
158
+ </li>
159
+
160
+ <li v-if="
161
+ filteredOptions.length === 0
162
+ " class="px-4 py-2 text-gray-500">
163
+ No results found
164
+ </li>
165
+ </ul>
166
+ </div>
167
+
168
+ <!-- Native Select -->
169
+ <select v-else :id="id" :value="
170
+ modelValue
171
+ " :disabled="
172
+ disabled
173
+ " :required="
174
+ required
175
+ " :class="
176
+ selectClasses
177
+ " :style="
178
+ selectStyles
179
+ " @change="
180
+ handleChange
181
+ ">
182
+ <option disabled value="">
183
+ {{ placeholder }}
184
+ </option>
185
+
186
+ <option v-for="option in options" :key="
187
+ option.value.toString()
188
+ " :value="
189
+ option.value
190
+ ">
191
+ {{ option.text }}
192
+ </option>
193
+ </select>
194
+
195
+ <!-- Hint -->
196
+ <p v-if="hint" class="mt-1 text-sm text-gray-500">
197
+ {{ hint }}
198
+ </p>
199
+ </div>
200
+ </template>