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,244 @@
1
+ <script setup>
2
+ import { ref, computed, onMounted, watch } from "vue";
3
+ const props = defineProps({
4
+ modelValue: { type: String, default: "" },
5
+ defaultValue: { type: String, default: "#ff0000" },
6
+ showOpacity: { type: Boolean, default: false },
7
+ disabled: { type: Boolean, default: false },
8
+ readonly: { type: Boolean, default: false },
9
+ flat: { type: Boolean, default: false },
10
+ square: { type: Boolean, default: false },
11
+ bordered: { type: Boolean, default: false },
12
+ borderRadius: { type: [String, Number], default: "12px" }
13
+ });
14
+ const emit = defineEmits(["update:modelValue"]);
15
+ const hue = ref(0);
16
+ const opacity = ref(1);
17
+ const pickedColor = ref({ r: 255, g: 0, b: 0 });
18
+ const saturation = ref(100);
19
+ const lightness = ref(50);
20
+ const canvasRef = ref(null);
21
+ const clamp = (v, min, max) => Math.min(max, Math.max(min, v));
22
+ function rgbToHsl(r, g, b) {
23
+ r /= 255;
24
+ g /= 255;
25
+ b /= 255;
26
+ const max = Math.max(r, g, b);
27
+ const min = Math.min(r, g, b);
28
+ let h = 0, s = 0;
29
+ const l = (max + min) / 2;
30
+ if (max !== min) {
31
+ const d = max - min;
32
+ s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
33
+ switch (max) {
34
+ case r:
35
+ h = (g - b) / d + (g < b ? 6 : 0);
36
+ break;
37
+ case g:
38
+ h = (b - r) / d + 2;
39
+ break;
40
+ case b:
41
+ h = (r - g) / d + 4;
42
+ break;
43
+ }
44
+ h /= 6;
45
+ }
46
+ return {
47
+ h: Math.round(h * 360),
48
+ s: Math.round(s * 100),
49
+ l: Math.round(l * 100)
50
+ };
51
+ }
52
+ function applyColor(color) {
53
+ if (color.startsWith("#")) {
54
+ const hex = color.replace("#", "");
55
+ const r = parseInt(hex.substring(0, 2), 16);
56
+ const g = parseInt(hex.substring(2, 4), 16);
57
+ const b = parseInt(hex.substring(4, 6), 16);
58
+ pickedColor.value = { r, g, b };
59
+ const hsl = rgbToHsl(r, g, b);
60
+ hue.value = hsl.h;
61
+ saturation.value = hsl.s;
62
+ lightness.value = hsl.l;
63
+ }
64
+ }
65
+ function drawCanvas() {
66
+ const canvas = canvasRef.value;
67
+ if (!canvas) return;
68
+ const ctx = canvas.getContext("2d");
69
+ const w = canvas.width;
70
+ const h = canvas.height;
71
+ ctx.clearRect(0, 0, w, h);
72
+ ctx.fillStyle = `hsl(${hue.value}, 100%, 50%)`;
73
+ ctx.fillRect(0, 0, w, h);
74
+ const whiteGrad = ctx.createLinearGradient(0, 0, w, 0);
75
+ whiteGrad.addColorStop(0, "#fff");
76
+ whiteGrad.addColorStop(1, "transparent");
77
+ ctx.fillStyle = whiteGrad;
78
+ ctx.fillRect(0, 0, w, h);
79
+ const blackGrad = ctx.createLinearGradient(0, 0, 0, h);
80
+ blackGrad.addColorStop(0, "transparent");
81
+ blackGrad.addColorStop(1, "#000");
82
+ ctx.fillStyle = blackGrad;
83
+ ctx.fillRect(0, 0, w, h);
84
+ }
85
+ function sampleCanvasAt(sat, light) {
86
+ const canvas = canvasRef.value;
87
+ if (!canvas) return;
88
+ const ctx = canvas.getContext("2d");
89
+ if (!ctx) return;
90
+ const w = canvas.width;
91
+ const h = canvas.height;
92
+ const x = clamp(Math.floor(sat / 100 * w), 0, w - 1);
93
+ const y = clamp(Math.floor((100 - light) / 100 * h), 0, h - 1);
94
+ const pixel = ctx.getImageData(x, y, 1, 1).data;
95
+ pickedColor.value = {
96
+ r: pixel[0],
97
+ g: pixel[1],
98
+ b: pixel[2]
99
+ };
100
+ }
101
+ function emitColor() {
102
+ const { r, g, b } = pickedColor.value;
103
+ if (props.showOpacity) {
104
+ emit("update:modelValue", `rgba(${r}, ${g}, ${b}, ${opacity.value})`);
105
+ } else {
106
+ emit("update:modelValue", `rgb(${r}, ${g}, ${b})`);
107
+ }
108
+ }
109
+ function pickSquare(e) {
110
+ if (props.disabled || props.readonly) return;
111
+ const canvas = canvasRef.value;
112
+ if (!canvas) return;
113
+ const rect = canvas.getBoundingClientRect();
114
+ const x = clamp(e.clientX - rect.left, 0, rect.width);
115
+ const y = clamp(e.clientY - rect.top, 0, rect.height);
116
+ saturation.value = Math.round(x / rect.width * 100);
117
+ lightness.value = Math.round(100 - y / rect.height * 100);
118
+ sampleCanvasAt(saturation.value, lightness.value);
119
+ emitColor();
120
+ }
121
+ function pickHue(e) {
122
+ if (props.disabled || props.readonly) return;
123
+ const rect = e.target.getBoundingClientRect();
124
+ const y = clamp(e.clientY - rect.top, 0, rect.height);
125
+ hue.value = clamp(Math.round(y / rect.height * 360), 0, 359);
126
+ drawCanvas();
127
+ sampleCanvasAt(saturation.value, lightness.value);
128
+ emitColor();
129
+ }
130
+ const squareCursor = computed(() => ({
131
+ left: `${saturation.value}%`,
132
+ top: `${100 - lightness.value}%`
133
+ }));
134
+ const hueCursor = computed(() => ({
135
+ top: `${hue.value / 360 * 100}%`
136
+ }));
137
+ function toHex(v) {
138
+ return v.toString(16).padStart(2, "0");
139
+ }
140
+ const currentHex = computed(() => {
141
+ const { r, g, b } = pickedColor.value;
142
+ return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
143
+ });
144
+ const displayHex = computed(() => {
145
+ if (!props.showOpacity) return currentHex.value;
146
+ const alpha = Math.round(opacity.value * 255).toString(16).padStart(2, "0");
147
+ return currentHex.value + alpha;
148
+ });
149
+ const displayColor = computed(() => {
150
+ const { r, g, b } = pickedColor.value;
151
+ return props.showOpacity ? `rgba(${r}, ${g}, ${b}, ${opacity.value})` : `rgb(${r}, ${g}, ${b})`;
152
+ });
153
+ function copy(text) {
154
+ navigator.clipboard.writeText(text).catch(() => {
155
+ });
156
+ }
157
+ const containerClasses = computed(() => [
158
+ "p-4 w-fit space-y-4",
159
+ props.flat ? "" : "shadow-md bg-white",
160
+ props.bordered ? "border border-gray-300" : ""
161
+ ]);
162
+ const containerStyle = computed(() => ({
163
+ borderRadius: props.square ? "0px" : typeof props.borderRadius === "number" ? `${props.borderRadius}px` : props.borderRadius
164
+ }));
165
+ watch(
166
+ () => props.modelValue,
167
+ (val) => {
168
+ if (val) applyColor(val);
169
+ },
170
+ { immediate: true }
171
+ );
172
+ onMounted(() => {
173
+ const initial = props.modelValue || props.defaultValue;
174
+ if (initial) applyColor(initial);
175
+ drawCanvas();
176
+ sampleCanvasAt(saturation.value, lightness.value);
177
+ });
178
+ </script>
179
+
180
+ <template>
181
+ <div :class="containerClasses" :style="containerStyle" class="p-4 w-fit bg-white rounded-lg space-y-4">
182
+ <div class="flex gap-3">
183
+ <div class="relative">
184
+ <canvas
185
+ ref="canvasRef"
186
+ width="192"
187
+ height="192"
188
+ class="w-48 h-48 rounded cursor-crosshair border"
189
+ @click="pickSquare"
190
+ />
191
+ <div
192
+ class="absolute w-3 h-3 border-2 border-white rounded-full shadow -translate-x-1/2 -translate-y-1/2 pointer-events-none"
193
+ :style="squareCursor"
194
+ />
195
+ </div>
196
+
197
+ <div
198
+ class="relative w-6 h-48 rounded cursor-pointer"
199
+ style="background: linear-gradient(to bottom, red, yellow, lime, cyan, blue, magenta, red)"
200
+ @click="pickHue"
201
+ >
202
+ <div
203
+ class="absolute left-0 w-full h-1 bg-white shadow -translate-y-1/2 pointer-events-none"
204
+ :style="hueCursor"
205
+ />
206
+ </div>
207
+ </div>
208
+
209
+ <input
210
+ v-if="showOpacity"
211
+ type="range"
212
+ min="0"
213
+ max="1"
214
+ step="0.01"
215
+ v-model="opacity"
216
+ @input="emitColor"
217
+ class="w-full"
218
+ />
219
+
220
+ <div
221
+ class="h-12 rounded border"
222
+ :style="{ background: displayColor }"
223
+ />
224
+
225
+ <div class="text-sm space-y-2">
226
+
227
+ <div class="flex justify-between items-center">
228
+ <span>{{ displayHex }}</span>
229
+ <button @click="copy(displayHex)">Copy</button>
230
+ </div>
231
+
232
+ <div class="flex justify-between items-center">
233
+ <span>{{ displayColor }}</span>
234
+ <button @click="copy(displayColor)">Copy</button>
235
+ </div>
236
+
237
+ </div>
238
+
239
+ </div>
240
+ </template>
241
+
242
+ <style scoped>
243
+ button{border:1px solid #ccc;border-radius:4px;font-size:12px;padding:2px 6px}
244
+ </style>
@@ -0,0 +1,91 @@
1
+ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
2
+ modelValue: {
3
+ type: StringConstructor;
4
+ default: string;
5
+ };
6
+ defaultValue: {
7
+ type: StringConstructor;
8
+ default: string;
9
+ };
10
+ showOpacity: {
11
+ type: BooleanConstructor;
12
+ default: boolean;
13
+ };
14
+ disabled: {
15
+ type: BooleanConstructor;
16
+ default: boolean;
17
+ };
18
+ readonly: {
19
+ type: BooleanConstructor;
20
+ default: boolean;
21
+ };
22
+ flat: {
23
+ type: BooleanConstructor;
24
+ default: boolean;
25
+ };
26
+ square: {
27
+ type: BooleanConstructor;
28
+ default: boolean;
29
+ };
30
+ bordered: {
31
+ type: BooleanConstructor;
32
+ default: boolean;
33
+ };
34
+ borderRadius: {
35
+ type: (StringConstructor | NumberConstructor)[];
36
+ default: string;
37
+ };
38
+ }>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
39
+ "update:modelValue": (...args: any[]) => void;
40
+ }, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
41
+ modelValue: {
42
+ type: StringConstructor;
43
+ default: string;
44
+ };
45
+ defaultValue: {
46
+ type: StringConstructor;
47
+ default: string;
48
+ };
49
+ showOpacity: {
50
+ type: BooleanConstructor;
51
+ default: boolean;
52
+ };
53
+ disabled: {
54
+ type: BooleanConstructor;
55
+ default: boolean;
56
+ };
57
+ readonly: {
58
+ type: BooleanConstructor;
59
+ default: boolean;
60
+ };
61
+ flat: {
62
+ type: BooleanConstructor;
63
+ default: boolean;
64
+ };
65
+ square: {
66
+ type: BooleanConstructor;
67
+ default: boolean;
68
+ };
69
+ bordered: {
70
+ type: BooleanConstructor;
71
+ default: boolean;
72
+ };
73
+ borderRadius: {
74
+ type: (StringConstructor | NumberConstructor)[];
75
+ default: string;
76
+ };
77
+ }>> & Readonly<{
78
+ "onUpdate:modelValue"?: ((...args: any[]) => any) | undefined;
79
+ }>, {
80
+ modelValue: string;
81
+ disabled: boolean;
82
+ flat: boolean;
83
+ square: boolean;
84
+ bordered: boolean;
85
+ defaultValue: string;
86
+ showOpacity: boolean;
87
+ readonly: boolean;
88
+ borderRadius: string | number;
89
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
90
+ declare const _default: typeof __VLS_export;
91
+ export default _default;
@@ -0,0 +1,137 @@
1
+ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
2
+ modelValue: {
3
+ type: (StringConstructor | ArrayConstructor)[];
4
+ default: string;
5
+ };
6
+ multiDate: BooleanConstructor;
7
+ rangeDate: BooleanConstructor;
8
+ disabledDates: {
9
+ type: () => string[];
10
+ default: () => never[];
11
+ };
12
+ format: {
13
+ type: StringConstructor;
14
+ default: string;
15
+ };
16
+ showHeader: {
17
+ type: BooleanConstructor;
18
+ default: boolean;
19
+ };
20
+ backgroundColor: {
21
+ type: StringConstructor;
22
+ default: string;
23
+ };
24
+ bordered: {
25
+ type: BooleanConstructor;
26
+ default: boolean;
27
+ };
28
+ borderRadius: {
29
+ type: StringConstructor;
30
+ default: string;
31
+ acceptedValues: string[];
32
+ };
33
+ flat: {
34
+ type: BooleanConstructor;
35
+ default: boolean;
36
+ };
37
+ color: {
38
+ type: StringConstructor;
39
+ default: string;
40
+ };
41
+ textColor: {
42
+ readonly type: StringConstructor;
43
+ readonly default: "";
44
+ };
45
+ contentClass: {
46
+ readonly type: StringConstructor;
47
+ readonly default: "";
48
+ };
49
+ contentStyle: {
50
+ readonly type: StringConstructor;
51
+ readonly default: "";
52
+ };
53
+ disable: {
54
+ readonly type: BooleanConstructor;
55
+ readonly default: false;
56
+ };
57
+ }>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
58
+ "update:modelValue": (...args: any[]) => void;
59
+ change: (...args: any[]) => void;
60
+ }, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
61
+ modelValue: {
62
+ type: (StringConstructor | ArrayConstructor)[];
63
+ default: string;
64
+ };
65
+ multiDate: BooleanConstructor;
66
+ rangeDate: BooleanConstructor;
67
+ disabledDates: {
68
+ type: () => string[];
69
+ default: () => never[];
70
+ };
71
+ format: {
72
+ type: StringConstructor;
73
+ default: string;
74
+ };
75
+ showHeader: {
76
+ type: BooleanConstructor;
77
+ default: boolean;
78
+ };
79
+ backgroundColor: {
80
+ type: StringConstructor;
81
+ default: string;
82
+ };
83
+ bordered: {
84
+ type: BooleanConstructor;
85
+ default: boolean;
86
+ };
87
+ borderRadius: {
88
+ type: StringConstructor;
89
+ default: string;
90
+ acceptedValues: string[];
91
+ };
92
+ flat: {
93
+ type: BooleanConstructor;
94
+ default: boolean;
95
+ };
96
+ color: {
97
+ type: StringConstructor;
98
+ default: string;
99
+ };
100
+ textColor: {
101
+ readonly type: StringConstructor;
102
+ readonly default: "";
103
+ };
104
+ contentClass: {
105
+ readonly type: StringConstructor;
106
+ readonly default: "";
107
+ };
108
+ contentStyle: {
109
+ readonly type: StringConstructor;
110
+ readonly default: "";
111
+ };
112
+ disable: {
113
+ readonly type: BooleanConstructor;
114
+ readonly default: false;
115
+ };
116
+ }>> & Readonly<{
117
+ "onUpdate:modelValue"?: ((...args: any[]) => any) | undefined;
118
+ onChange?: ((...args: any[]) => any) | undefined;
119
+ }>, {
120
+ modelValue: string | unknown[];
121
+ contentClass: string;
122
+ contentStyle: string;
123
+ textColor: string;
124
+ disable: boolean;
125
+ color: string;
126
+ backgroundColor: string;
127
+ flat: boolean;
128
+ bordered: boolean;
129
+ borderRadius: string;
130
+ multiDate: boolean;
131
+ rangeDate: boolean;
132
+ disabledDates: string[];
133
+ format: string;
134
+ showHeader: boolean;
135
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
136
+ declare const _default: typeof __VLS_export;
137
+ export default _default;
@@ -0,0 +1,201 @@
1
+ <script setup>
2
+ import { ref, computed, watch } from "vue";
3
+ import { useUiClasses } from "./useUiClasses";
4
+ import { uiProps } from "./uiProps";
5
+ const props = defineProps({
6
+ modelValue: { type: [String, Array], default: "" },
7
+ multiDate: Boolean,
8
+ rangeDate: Boolean,
9
+ disabledDates: { type: Array, default: () => [] },
10
+ format: { type: String, default: "DD-MM-YYYY" },
11
+ showHeader: { type: Boolean, default: true },
12
+ backgroundColor: { type: String, default: "white" },
13
+ bordered: { type: Boolean, default: false },
14
+ borderRadius: { type: String, default: "rounded-md", acceptedValues: ["none", "sm", "md", "lg", "xl"] },
15
+ flat: { type: Boolean, default: false },
16
+ color: { type: String, default: "indigo" },
17
+ textColor: uiProps.textColor,
18
+ contentClass: uiProps.contentClass,
19
+ contentStyle: uiProps.contentStyle,
20
+ disable: uiProps.disable
21
+ });
22
+ const {
23
+ isHex
24
+ } = useUiClasses(props);
25
+ const emit = defineEmits(["update:modelValue", "change"]);
26
+ const today = /* @__PURE__ */ new Date();
27
+ const currentMonth = ref(today.getMonth());
28
+ const currentYear = ref(today.getFullYear());
29
+ const selectedDates = ref([]);
30
+ const rangeStart = ref(null);
31
+ const rangeEnd = ref(null);
32
+ const headerLabel = computed(() => {
33
+ const first = selectedDates.value[0];
34
+ if (!first) return "No date selected";
35
+ const date = new Date(first);
36
+ const dayName = date.toLocaleDateString("default", {
37
+ weekday: "long"
38
+ });
39
+ return dayName;
40
+ });
41
+ const daysInMonth = computed(() => {
42
+ return new Date(currentYear.value, currentMonth.value + 1, 0).getDate();
43
+ });
44
+ const blankDays = computed(() => {
45
+ return new Date(currentYear.value, currentMonth.value, 1).getDay();
46
+ });
47
+ const days = computed(
48
+ () => Array.from({ length: daysInMonth.value }, (_, i) => i + 1)
49
+ );
50
+ function formatDate(day) {
51
+ const d = new Date(currentYear.value, currentMonth.value, day);
52
+ const year = d.getFullYear();
53
+ const month = String(d.getMonth() + 1).padStart(2, "0");
54
+ const date = String(d.getDate()).padStart(2, "0");
55
+ return `${year}-${month}-${date}`;
56
+ }
57
+ function formatDateString(date, format) {
58
+ const map = {
59
+ YYYY: String(date.getFullYear()),
60
+ MM: String(date.getMonth() + 1).padStart(2, "0"),
61
+ DD: String(date.getDate()).padStart(2, "0"),
62
+ HH: String(date.getHours()).padStart(2, "0"),
63
+ mm: String(date.getMinutes()).padStart(2, "0"),
64
+ ss: String(date.getSeconds()).padStart(2, "0")
65
+ };
66
+ return format.replace(/YYYY|MM|DD|HH|mm|ss/g, (match) => {
67
+ return map[match];
68
+ });
69
+ }
70
+ function isDisabled(day) {
71
+ return props.disabledDates.includes(formatDate(day));
72
+ }
73
+ function isSelected(day) {
74
+ return selectedDates.value.includes(formatDate(day));
75
+ }
76
+ function isToday(day) {
77
+ const d = /* @__PURE__ */ new Date();
78
+ return day === d.getDate() && currentMonth.value === d.getMonth() && currentYear.value === d.getFullYear();
79
+ }
80
+ function isInRange(day) {
81
+ if (rangeStart.value === null || rangeEnd.value === null) return false;
82
+ const start = Math.min(rangeStart.value, rangeEnd.value);
83
+ const end = Math.max(rangeStart.value, rangeEnd.value);
84
+ return day >= start && day <= end;
85
+ }
86
+ function dayClasses(day) {
87
+ if (isDisabled(day)) return "text-gray-300 cursor-not-allowed";
88
+ if (isSelected(day))
89
+ return `bg-${props.color}-600 text-white font-medium`;
90
+ if (props.rangeDate && isInRange(day))
91
+ return `bg-${props.color}-100 text-${props.color}-700`;
92
+ if (isToday(day))
93
+ return `border border-${props.color}-500`;
94
+ return "hover:bg-gray-100";
95
+ }
96
+ function selectDate(day) {
97
+ if (isDisabled(day)) return;
98
+ const value = formatDate(day);
99
+ if (props.multiDate) {
100
+ if (selectedDates.value.includes(value)) {
101
+ selectedDates.value = selectedDates.value.filter((d) => d !== value);
102
+ } else {
103
+ selectedDates.value.push(value);
104
+ }
105
+ } else if (props.rangeDate) {
106
+ if (rangeStart.value === null) {
107
+ rangeStart.value = day;
108
+ rangeEnd.value = null;
109
+ } else {
110
+ rangeEnd.value = day;
111
+ selectedDates.value = buildRange();
112
+ }
113
+ } else {
114
+ selectedDates.value = [value];
115
+ }
116
+ emit("update:modelValue", selectedDates.value);
117
+ emit("change", selectedDates.value);
118
+ }
119
+ function buildRange() {
120
+ if (rangeStart.value === null || rangeEnd.value === null) return [];
121
+ const start = Math.min(rangeStart.value, rangeEnd.value);
122
+ const end = Math.max(rangeStart.value, rangeEnd.value);
123
+ const range = [];
124
+ for (let i = start; i <= end; i++) {
125
+ range.push(formatDate(i));
126
+ }
127
+ return range;
128
+ }
129
+ function nextMonth() {
130
+ if (currentMonth.value === 11) {
131
+ currentMonth.value = 0;
132
+ currentYear.value++;
133
+ } else currentMonth.value++;
134
+ }
135
+ function prevMonth() {
136
+ if (currentMonth.value === 0) {
137
+ currentMonth.value = 11;
138
+ currentYear.value--;
139
+ } else currentMonth.value--;
140
+ }
141
+ watch(
142
+ () => props.modelValue,
143
+ (val) => {
144
+ if (!val) return;
145
+ if (Array.isArray(val)) {
146
+ selectedDates.value = val;
147
+ } else {
148
+ selectedDates.value = [val];
149
+ }
150
+ },
151
+ { immediate: true }
152
+ );
153
+ </script>
154
+
155
+ <template>
156
+ <div class="w-80 min-w-80" :class="[
157
+ borderRadius ? `rounded-${borderRadius}` : '',
158
+ bordered ? 'border border-gray-200' : '',
159
+ flat ? '' : 'shadow-md',
160
+ textColor && !isHex(textColor) ? `text-${textColor}` : 'text-gray-800',
161
+ backgroundColor && !isHex(backgroundColor) ? `bg-${backgroundColor}` : ''
162
+ ]" :style="{
163
+ backgroundColor: isHex(backgroundColor) ? backgroundColor : '',
164
+ color: isHex(textColor) ? textColor : ''
165
+ }">
166
+ <div v-if="showHeader" class="px-4 py-3 flex justify-between items-center"
167
+ :class="bordered ? 'border-b border-gray-200' : ''">
168
+ <div class="text-sm font-semibold text-gray-700">
169
+ <div v-if="multiDate">{{ selectedDates.length }} selected</div>
170
+ <div v-else>
171
+ <div class="text-lg" :class="`text-${color}-600`">{{ headerLabel }}</div>
172
+ <div class="text-gray-700">
173
+ {{ selectedDates[0] ? formatDateString(new Date(selectedDates[0]), format) : "" }}
174
+ </div>
175
+ </div>
176
+ </div>
177
+ </div>
178
+ <div class="flex items-center justify-between px-4 py-2">
179
+ <button @click="prevMonth" class="p-1 rounded hover:bg-gray-100">‹</button>
180
+ <div class="text-sm font-medium text-gray-800">
181
+ {{ new Date(currentYear, currentMonth).toLocaleString("default", { month: "long" }) }}
182
+ {{ currentYear }}
183
+ </div>
184
+ <button @click="nextMonth" class="p-1 rounded hover:bg-gray-100">›</button>
185
+ </div>
186
+ <div class="grid grid-cols-7 text-xs font-medium text-center text-gray-500 px-3 mb-1">
187
+ <div v-for="d in ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']" :key="d">
188
+ {{ d }}
189
+ </div>
190
+ </div>
191
+ <div class="grid grid-cols-7 gap-1 px-3 pb-3">
192
+ <div v-for="n in blankDays" :key="'b' + n"></div>
193
+ <div v-for="day in days" :key="day" @click="selectDate(day)"
194
+ class="h-10 flex items-center justify-center text-sm rounded-lg cursor-pointer transition-all duration-150"
195
+ :class="dayClasses(day)">
196
+ {{ day }}
197
+ </div>
198
+ </div>
199
+
200
+ </div>
201
+ </template>