windly-ui 1.0.1 → 1.0.2

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 (39) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +57 -33
  3. package/package.json +47 -15
  4. package/ui-library/dist/module.d.mts +3 -0
  5. package/ui-library/dist/module.json +8 -0
  6. package/ui-library/dist/module.mjs +22 -0
  7. package/ui-library/dist/types.d.mts +7 -0
  8. package/ui-library/components/Accordion.vue +0 -118
  9. package/ui-library/components/Avatar.vue +0 -121
  10. package/ui-library/components/Badge.vue +0 -116
  11. package/ui-library/components/Breadcrumbs.vue +0 -138
  12. package/ui-library/components/Button.vue +0 -154
  13. package/ui-library/components/Card.vue +0 -84
  14. package/ui-library/components/Checkbox.vue +0 -148
  15. package/ui-library/components/CodeBlock.vue +0 -99
  16. package/ui-library/components/ColorPicker.vue +0 -302
  17. package/ui-library/components/Date.vue +0 -240
  18. package/ui-library/components/Dialog.vue +0 -187
  19. package/ui-library/components/Divider.vue +0 -78
  20. package/ui-library/components/Drawer.vue +0 -67
  21. package/ui-library/components/Dropdown.vue +0 -248
  22. package/ui-library/components/FileUploader.vue +0 -330
  23. package/ui-library/components/Icon.vue +0 -82
  24. package/ui-library/components/Image.vue +0 -78
  25. package/ui-library/components/Input.vue +0 -531
  26. package/ui-library/components/Radio.vue +0 -356
  27. package/ui-library/components/ScrollArea.vue +0 -43
  28. package/ui-library/components/Select.vue +0 -309
  29. package/ui-library/components/Stepper.vue +0 -361
  30. package/ui-library/components/TabPanel.vue +0 -25
  31. package/ui-library/components/Table.vue +0 -152
  32. package/ui-library/components/Tabs.vue +0 -71
  33. package/ui-library/components/Textarea.vue +0 -233
  34. package/ui-library/components/Toggle.vue +0 -319
  35. package/ui-library/components/Tooltip.vue +0 -200
  36. package/ui-library/components/plugin.ts +0 -8
  37. package/ui-library/components/uiProps.ts +0 -11
  38. package/ui-library/components/useUiClasses.ts +0 -159
  39. package/ui-library/module.ts +0 -20
@@ -1,361 +0,0 @@
1
- <script setup lang="ts">
2
- import { computed } from 'vue'
3
-
4
- interface StepItem {
5
- label: string
6
- name?: string
7
- icon?: string
8
- iconColor?: string
9
- }
10
-
11
- type Step = string | StepItem
12
-
13
- const props = withDefaults(
14
- defineProps<{
15
- steps: Step[]
16
- modelValue?: number
17
- vertical?: boolean
18
- completedColor?: string
19
- activeColor?: string
20
- inactiveColor?: string
21
- connectorCompletedColor?: string
22
- connectorInactiveColor?: string
23
- inactiveSteps?: number[]
24
- }>(),
25
- {
26
- modelValue: 0,
27
- vertical: false,
28
- completedColor: 'green-500',
29
- activeColor: 'blue-500',
30
- inactiveColor: 'gray-300',
31
- connectorCompletedColor: 'green-500',
32
- connectorInactiveColor: 'gray-300',
33
- inactiveSteps: () => [],
34
- },
35
- )
36
-
37
- const emit = defineEmits<{
38
- (
39
- e: 'update:modelValue',
40
- value: number,
41
- ): void
42
- }>()
43
-
44
- const currentStep = computed(
45
- () => props.modelValue,
46
- )
47
-
48
- const normalizedSteps = computed<
49
- StepItem[]
50
- >(() =>
51
- props.steps.map((step) => {
52
- if (typeof step === 'string') {
53
- return {
54
- label: step,
55
- }
56
- }
57
-
58
- return step
59
- }),
60
- )
61
-
62
- const isHex = (val: string) =>
63
- val.startsWith('#')
64
-
65
- const isInactiveStep = (
66
- index: number,
67
- ): boolean => {
68
- return props.inactiveSteps.includes(
69
- index,
70
- )
71
- }
72
-
73
- const stepState = (
74
- index: number,
75
- ) => {
76
- if (isInactiveStep(index)) {
77
- return 'inactive'
78
- }
79
-
80
- if (index < currentStep.value) {
81
- return 'completed'
82
- }
83
-
84
- if (index === currentStep.value) {
85
- return 'active'
86
- }
87
-
88
- return 'pending'
89
- }
90
-
91
- const stepClasses = (
92
- index: number,
93
- ) => {
94
- const state =
95
- stepState(index)
96
-
97
- switch (state) {
98
- case 'completed':
99
- return [
100
- !isHex(
101
- props.completedColor,
102
- )
103
- ? `bg-${props.completedColor}`
104
- : '',
105
-
106
- 'text-white',
107
- ]
108
-
109
- case 'active':
110
- return [
111
- !isHex(
112
- props.activeColor,
113
- )
114
- ? `bg-${props.activeColor}`
115
- : '',
116
-
117
- 'text-white',
118
- ]
119
-
120
- case 'inactive':
121
- return [
122
- !isHex(
123
- props.inactiveColor,
124
- )
125
- ? `bg-${props.inactiveColor}`
126
- : '',
127
-
128
- 'text-gray-500 opacity-60 cursor-not-allowed',
129
- ]
130
-
131
- case 'pending':
132
- default:
133
- return [
134
- !isHex(
135
- props.inactiveColor,
136
- )
137
- ? `bg-${props.inactiveColor}`
138
- : '',
139
-
140
- 'text-gray-600',
141
- ]
142
- }
143
- }
144
-
145
- const stepStyle = (
146
- index: number,
147
- ) => {
148
- const style: Record<
149
- string,
150
- string
151
- > = {}
152
-
153
- const state =
154
- stepState(index)
155
-
156
- const colorMap = {
157
- completed:
158
- props.completedColor,
159
-
160
- active:
161
- props.activeColor,
162
-
163
- inactive:
164
- props.inactiveColor,
165
-
166
- pending:
167
- props.inactiveColor,
168
- }
169
-
170
- const color =
171
- colorMap[state]
172
-
173
- if (isHex(color)) {
174
- style.backgroundColor =
175
- color
176
- }
177
-
178
- return style
179
- }
180
-
181
- const connectorClasses = (
182
- index: number,
183
- ) => {
184
- const completed =
185
- index < currentStep.value &&
186
- !isInactiveStep(index + 1)
187
-
188
- const color = completed
189
- ? props.connectorCompletedColor
190
- : props.connectorInactiveColor
191
-
192
- return [
193
- !isHex(color)
194
- ? `bg-${color}`
195
- : '',
196
- ]
197
- }
198
-
199
- const connectorStyle = (
200
- index: number,
201
- ) => {
202
- const style: Record<
203
- string,
204
- string
205
- > = {}
206
-
207
- const completed =
208
- index < currentStep.value &&
209
- !isInactiveStep(index + 1)
210
-
211
- const color = completed
212
- ? props.connectorCompletedColor
213
- : props.connectorInactiveColor
214
-
215
- if (isHex(color)) {
216
- style.backgroundColor =
217
- color
218
- }
219
-
220
- return style
221
- }
222
-
223
- const labelClasses = (
224
- index: number,
225
- ) => {
226
- if (isInactiveStep(index)) {
227
- return 'text-gray-400 opacity-60 cursor-not-allowed'
228
- }
229
-
230
- if (
231
- index === currentStep.value
232
- ) {
233
- return 'text-black dark:text-white'
234
- }
235
-
236
- return 'text-gray-500'
237
- }
238
-
239
- const navigate = (
240
- index: number,
241
- ): void => {
242
- if (
243
- isInactiveStep(index)
244
- ) {
245
- return
246
- }
247
-
248
- emit(
249
- 'update:modelValue',
250
- index,
251
- )
252
- }
253
- </script>
254
- <template>
255
- <div :class="{
256
- flex: vertical,
257
- block: !vertical,
258
- }">
259
- <!-- Steps -->
260
- <div :class="{
261
- 'flex flex-col items-start':
262
- vertical,
263
-
264
- 'flex items-start justify-between':
265
- !vertical,
266
- }">
267
- <div v-for="(
268
- step, index
269
- ) in normalizedSteps" :key="index" :class="{
270
- 'relative flex-1 flex items-start':
271
- !vertical,
272
-
273
- 'relative flex flex-col items-start':
274
- vertical,
275
- }">
276
- <div :class="{
277
- 'flex items-center':
278
- vertical,
279
-
280
- 'flex flex-col items-center':
281
- !vertical,
282
- }">
283
- <!-- Step Indicator -->
284
- <div @click="
285
- navigate(index)
286
- " :class="[
287
- 'flex items-center justify-center w-10 h-10 rounded-full font-bold z-10 transition-colors',
288
- stepClasses(index),
289
- ]" :style="stepStyle(index)
290
- ">
291
- <template v-if="step.icon">
292
- <span class="material-icons">
293
- {{ step.icon }}
294
- </span>
295
- </template>
296
-
297
- <template v-else>
298
- {{ index + 1 }}
299
- </template>
300
- </div>
301
-
302
- <!-- Label -->
303
- <div class="text-center text-sm font-medium mx-2" :class="[
304
- vertical
305
- ? 'ml-4'
306
- : 'mt-2',
307
-
308
- labelClasses(index),
309
- ]" @click="
310
- navigate(index)
311
- ">
312
- {{ step.label }}
313
- </div>
314
- </div>
315
-
316
- <!-- Connector -->
317
- <div v-if="
318
- index !==
319
- normalizedSteps.length -
320
- 1
321
- " :class="{
322
- 'flex-1 h-[1px] mt-5 relative':
323
- !vertical,
324
-
325
- 'w-[1px] h-16 ml-5 relative':
326
- vertical,
327
- }">
328
- <div class="absolute w-full h-full" :class="connectorClasses(
329
- index,
330
- )
331
- " :style="[
332
- connectorStyle(
333
- index,
334
- ),
335
- {
336
- top: vertical
337
- ? '50%'
338
- : '',
339
-
340
- transform:
341
- 'translateY(-50%)',
342
- },
343
- ]" />
344
- </div>
345
- </div>
346
- </div>
347
-
348
- <!-- Content -->
349
- <div :class="{
350
- 'ml-4': vertical,
351
- 'mt-4': !vertical,
352
- }">
353
- <slot :step="currentStep" />
354
- </div>
355
- </div>
356
- </template>
357
- <style scoped>
358
- .material-icons {
359
- font-size: 1.5rem;
360
- }
361
- </style>
@@ -1,25 +0,0 @@
1
- <template>
2
- <div v-show="isActive">
3
- <slot />
4
- </div>
5
- </template>
6
-
7
- <script setup lang="ts">
8
- import { inject, computed, onMounted } from 'vue'
9
-
10
- const props = defineProps<{
11
- name: string
12
- label: string
13
- }>()
14
-
15
- const tabs = inject<any>('tabs')
16
-
17
- onMounted(() => {
18
- tabs?.registerTab({
19
- name: props.name,
20
- label: props.label,
21
- })
22
- })
23
-
24
- const isActive = computed(() => tabs?.modelValue.value === props.name)
25
- </script>
@@ -1,152 +0,0 @@
1
- <script setup lang="ts">
2
- import { computed } from "vue";
3
-
4
- type Separator =
5
- | "none"
6
- | "horizontal"
7
- | "vertical"
8
- | "cell";
9
-
10
- type Rounded =
11
- | "none"
12
- | "sm"
13
- | "md"
14
- | "lg"
15
- | "xl";
16
-
17
- const props = withDefaults(
18
- defineProps<{
19
- flat?: boolean;
20
- bordered?: boolean;
21
- striped?: boolean;
22
- dense?: boolean;
23
- hover?: boolean;
24
-
25
- rounded?: Rounded;
26
-
27
- separator?: Separator;
28
-
29
- borderColor?: string;
30
- bgColor?: string;
31
- }>(),
32
- {
33
- flat: false,
34
- bordered: false,
35
- striped: false,
36
- dense: false,
37
- hover: true,
38
-
39
- rounded: "md",
40
-
41
- separator: "horizontal",
42
-
43
- borderColor: "border-gray-200 dark:border-gray-700",
44
-
45
- bgColor: "bg-white dark:bg-gray-900",
46
- }
47
- );
48
-
49
- const roundedClass = computed(() => {
50
- const map: Record<Rounded, string> = {
51
- none: "",
52
- sm: "rounded-sm",
53
- md: "rounded-md",
54
- lg: "rounded-lg",
55
- xl: "rounded-xl",
56
- };
57
-
58
- return map[props.rounded];
59
- });
60
-
61
- const wrapperClass = computed(() => [
62
- "w-full overflow-x-auto",
63
-
64
- roundedClass.value,
65
-
66
- props.bordered
67
- ? `border ${props.borderColor}`
68
- : "",
69
-
70
- props.flat
71
- ? "shadow-none"
72
- : "shadow-sm",
73
-
74
- props.bgColor,
75
- ]);
76
-
77
- const separatorClass = computed(() => {
78
- switch (props.separator) {
79
- case "vertical":
80
- return [
81
- "[&_th]:border-r",
82
- "[&_td]:border-r",
83
- props.borderColor,
84
- ];
85
-
86
- case "cell":
87
- return [
88
- "[&_th]:border",
89
- "[&_td]:border",
90
- props.borderColor,
91
- ];
92
-
93
- case "none":
94
- return [];
95
-
96
- case "horizontal":
97
- default:
98
- return [
99
- "[&_tr]:border-b",
100
- props.borderColor,
101
- ];
102
- }
103
- });
104
-
105
- const tableClass = computed(() => [
106
- "w-full border-collapse",
107
- separatorClass.value,
108
- ]);
109
-
110
- const headerClass = computed(() => [
111
- "bg-gray-50 dark:bg-gray-800",
112
- ]);
113
-
114
- const bodyClass = computed(() => [
115
- props.striped
116
- ? "[&_tr:nth-child(even)]:bg-gray-50 dark:[&_tr:nth-child(even)]:bg-gray-800/40"
117
- : "",
118
-
119
- props.hover
120
- ? "[&_tr:hover]:bg-gray-100 dark:[&_tr:hover]:bg-gray-700"
121
- : "",
122
-
123
- props.dense
124
- ? "[&_td]:py-2 [&_th]:py-2"
125
- : "[&_td]:py-3 [&_th]:py-3",
126
- ]);
127
-
128
- const footerClass = computed(() => [
129
- "bg-gray-50 dark:bg-gray-900",
130
- ]);
131
- </script>
132
- <template>
133
- <div :class="wrapperClass">
134
- <table :class="tableClass">
135
- <thead
136
- v-if="$slots.header"
137
- :class="headerClass"
138
- >
139
- <slot name="header" />
140
- </thead>
141
- <tbody :class="bodyClass">
142
- <slot />
143
- </tbody>
144
- <tfoot
145
- v-if="$slots.footer"
146
- :class="footerClass"
147
- >
148
- <slot name="footer" />
149
- </tfoot>
150
- </table>
151
- </div>
152
- </template>
@@ -1,71 +0,0 @@
1
- <script setup lang="ts">
2
- import { ref, reactive, watch, nextTick, provide, computed, onMounted } from 'vue'
3
-
4
- const props = defineProps<{ modelValue: string }>()
5
- const emit = defineEmits<{ (e: 'update:modelValue', value: string): void }>()
6
-
7
- const tabs = ref<{ name: string; label: string }[]>([])
8
- const tabRefs = ref<HTMLElement[]>([])
9
- const tabsEl = ref<HTMLElement | null>(null)
10
-
11
- const indicatorStyle = ref({
12
- width: '0px',
13
- transform: 'translateX(0px)',
14
- })
15
-
16
- function updateIndicator(index: number) {
17
- const tab = tabRefs.value[index]
18
- if (!tab || !tabsEl.value) return
19
-
20
- indicatorStyle.value = {
21
- width: `${tab.offsetWidth}px`,
22
- transform: `translateX(${tab.offsetLeft}px)`,
23
- }
24
- }
25
-
26
- function setActive(name: string, index: number) {
27
- emit('update:modelValue', name)
28
- nextTick(() => updateIndicator(index))
29
- }
30
-
31
- function registerTab(tab: { name: string; label: string }) {
32
- tabs.value.push(tab)
33
- }
34
-
35
- onMounted(() => {
36
- watch(
37
- () => props.modelValue,
38
- async () => {
39
- await nextTick()
40
- const index = tabs.value.findIndex(t => t.name === props.modelValue)
41
- if (index !== -1) updateIndicator(index)
42
- },
43
- { immediate: true }
44
- )
45
- })
46
-
47
- provide('tabs', {
48
- modelValue: computed(() => props.modelValue),
49
- registerTab,
50
- })
51
- </script>
52
-
53
- <template>
54
- <!-- Tabs Header -->
55
- <div ref="tabsEl" class="relative flex border-b bg-gray-100">
56
- <span class="absolute bottom-0 h-0.5 bg-blue-600 transition-all duration-300 ease-out"
57
- :style="indicatorStyle" />
58
-
59
- <button v-for="(tab, index) in tabs" :key="tab.name" :ref="el => (tabRefs[index] = el as HTMLElement)"
60
- @click="setActive(tab.name, index)" class="relative px-4 py-2 text-sm font-medium transition-colors" :class="modelValue === tab.name
61
- ? 'text-blue-600'
62
- : 'text-gray-600 hover:text-gray-800'">
63
- {{ tab.label }}
64
- </button>
65
- </div>
66
-
67
- <!-- Content -->
68
- <div class="relative">
69
- <slot />
70
- </div>
71
- </template>