pimelon-ui 0.1.155 → 0.1.168
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.
- package/melon/Billing/TrialBanner.vue +1 -2
- package/package.json +7 -4
- package/readme.md +0 -1
- package/src/components/Autocomplete/Autocomplete.vue +1 -1
- package/src/components/Charts/ECharts.vue +1 -1
- package/src/components/Charts/axisChartOptions.ts +1 -0
- package/src/components/Combobox/Combobox.story.vue +300 -0
- package/src/components/Combobox/Combobox.vue +16 -1
- package/src/components/DatePicker/DatePicker.vue +7 -6
- package/src/components/DatePicker/DateRangePicker.vue +35 -14
- package/src/components/DatePicker/DateTimePicker.vue +7 -7
- package/src/components/DatePicker/types.ts +3 -4
- package/src/components/FormControl/FormControl.vue +0 -7
- package/src/components/Select/types.ts +0 -1
- package/src/components/Sidebar/Sidebar.story.vue +79 -0
- package/src/components/Sidebar/Sidebar.vue +60 -0
- package/src/components/Sidebar/SidebarHeader.vue +55 -0
- package/src/components/Sidebar/SidebarItem.vue +94 -0
- package/src/components/Sidebar/SidebarSection.vue +69 -0
- package/src/components/Sidebar/index.ts +2 -0
- package/src/components/Sidebar/types.ts +31 -0
- package/src/components/Switch/Switch.vue +3 -3
- package/src/components/TabButtons/TabButtons.vue +1 -1
- package/src/components/TextEditor/InsertImage.vue +27 -5
- package/src/components/TextEditor/InsertVideo.vue +8 -91
- package/src/components/TextEditor/TextEditor.vue +198 -224
- package/src/components/TextEditor/extensions/content-paste-extension.ts +81 -0
- package/src/components/TextEditor/extensions/image/image-extension.ts +12 -10
- package/src/components/TextEditor/extensions/image-group/ImageGroupNodeView.vue +216 -0
- package/src/components/TextEditor/extensions/image-group/ImageGroupUploadDialog.vue +738 -0
- package/src/components/TextEditor/extensions/image-group/image-group-extension.ts +115 -0
- package/src/components/TextEditor/types.ts +23 -0
- package/src/components/TextEditor/video-extension.ts +4 -8
- package/src/components/TextInput/types.ts +0 -1
- package/src/components/Toast/Toast.vue +2 -3
- package/src/components/Toast/index.ts +8 -3
- package/src/directives/onOutsideClick.ts +36 -0
- package/src/directives/visibility.ts +40 -0
- package/src/index.ts +7 -5
- package/src/utils/config.ts +36 -0
- package/src/utils/{dayjs.js → dayjs.ts} +4 -4
- package/src/utils/fileUploadHandler.ts +1 -14
- package/src/utils/{markdown.js → markdown.ts} +9 -11
- package/src/utils/melonRequest.js +10 -0
- package/src/utils/pageMeta.ts +114 -0
- package/src/utils/useFileUpload.ts +23 -4
- package/src/directives/onOutsideClick.js +0 -34
- package/src/directives/visibility.js +0 -24
- package/src/utils/config.js +0 -9
- package/src/utils/pageMeta.js +0 -55
|
@@ -61,8 +61,7 @@ createResource({
|
|
|
61
61
|
trialEndDays.value = calculateTrialEndDays(data.trial_end_date)
|
|
62
62
|
baseEndpoint.value = data.base_url
|
|
63
63
|
siteName.value = data.site_name
|
|
64
|
-
showBanner.value =
|
|
65
|
-
data.setup_complete && data.plan.is_trial_plan && trialEndDays.value > 0
|
|
64
|
+
showBanner.value = data.plan.is_trial_plan && trialEndDays.value > 0
|
|
66
65
|
},
|
|
67
66
|
})
|
|
68
67
|
|
package/package.json
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pimelon-ui",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.168",
|
|
4
4
|
"description": "A set of components and utilities for rapid UI development",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"scripts": {
|
|
8
|
-
"test": "vitest",
|
|
8
|
+
"test": "vitest --run",
|
|
9
|
+
"type-check": "tsc --noEmit",
|
|
9
10
|
"prettier": "yarn prettier -w ./src",
|
|
10
|
-
"bump-and-release": "yarn
|
|
11
|
+
"bump-and-release": "yarn test && git pull --rebase origin main && yarn run release-patch",
|
|
12
|
+
"release-patch": "yarn version --patch && git push && git push --tags",
|
|
11
13
|
"dev": "vite",
|
|
12
14
|
"build": "vite build",
|
|
13
15
|
"preview": "vite preview",
|
|
@@ -56,6 +58,7 @@
|
|
|
56
58
|
"@tiptap/vue-3": "^2.0.3",
|
|
57
59
|
"@vueuse/core": "^10.4.1",
|
|
58
60
|
"dayjs": "^1.11.13",
|
|
61
|
+
"dompurify": "^3.2.6",
|
|
59
62
|
"echarts": "^5.6.0",
|
|
60
63
|
"feather-icons": "^4.28.0",
|
|
61
64
|
"highlight.js": "^11.11.1",
|
|
@@ -63,6 +66,7 @@
|
|
|
63
66
|
"idb-keyval": "^6.2.0",
|
|
64
67
|
"lowlight": "^3.3.0",
|
|
65
68
|
"lucide-static": "^0.479.0",
|
|
69
|
+
"marked": "^15.0.12",
|
|
66
70
|
"ora": "5.4.1",
|
|
67
71
|
"prettier": "^3.3.2",
|
|
68
72
|
"prosemirror-model": "^1.25.1",
|
|
@@ -70,7 +74,6 @@
|
|
|
70
74
|
"prosemirror-view": "^1.39.2",
|
|
71
75
|
"radix-vue": "^1.5.3",
|
|
72
76
|
"reka-ui": "^2.0.2",
|
|
73
|
-
"showdown": "^2.1.0",
|
|
74
77
|
"socket.io-client": "^4.5.1",
|
|
75
78
|
"tippy.js": "^6.3.7",
|
|
76
79
|
"typescript": "^5.0.2",
|
package/readme.md
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
## Pimelon UI
|
|
@@ -322,7 +322,7 @@ const makeOption = (option: AutocompleteOption) => {
|
|
|
322
322
|
|
|
323
323
|
const getLabel = (option: AutocompleteOption) => {
|
|
324
324
|
if (isOption(option)) {
|
|
325
|
-
return option?.label || option?.value
|
|
325
|
+
return option?.label || option?.value
|
|
326
326
|
}
|
|
327
327
|
return option
|
|
328
328
|
}
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref, reactive } from 'vue'
|
|
3
|
+
import Combobox from './Combobox.vue'
|
|
4
|
+
|
|
5
|
+
const simpleValue = ref('')
|
|
6
|
+
const objectValue = ref('')
|
|
7
|
+
const iconValue = ref('')
|
|
8
|
+
const groupedValue = ref('')
|
|
9
|
+
const disabledValue = ref('')
|
|
10
|
+
const preselectedValue = ref('john-doe')
|
|
11
|
+
const multipleSimpleValue = ref([])
|
|
12
|
+
const multipleObjectValue = ref([])
|
|
13
|
+
const multipleGroupedValue = ref(['apple', 'carrot'])
|
|
14
|
+
const complexObjectValue = ref(null)
|
|
15
|
+
const selectedOption = ref(null)
|
|
16
|
+
|
|
17
|
+
// Complex objects for displayValue demo
|
|
18
|
+
const complexObjects = [
|
|
19
|
+
{
|
|
20
|
+
label: 'John Doe (Admin)',
|
|
21
|
+
value: 'john-doe',
|
|
22
|
+
email: 'john@example.com',
|
|
23
|
+
role: 'Admin',
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
label: 'Jane Smith (User)',
|
|
27
|
+
value: 'jane-smith',
|
|
28
|
+
email: 'jane@example.com',
|
|
29
|
+
role: 'User',
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
label: 'Bob Johnson (Manager)',
|
|
33
|
+
value: 'bob-johnson',
|
|
34
|
+
email: 'bob@example.com',
|
|
35
|
+
role: 'Manager',
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
label: 'Alice Brown (User)',
|
|
39
|
+
value: 'alice-brown',
|
|
40
|
+
email: 'alice@example.com',
|
|
41
|
+
role: 'User',
|
|
42
|
+
},
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
const simpleOptions = [
|
|
46
|
+
'John Doe',
|
|
47
|
+
'Jane Doe',
|
|
48
|
+
'John Smith',
|
|
49
|
+
'Jane Smith',
|
|
50
|
+
'John Wayne',
|
|
51
|
+
'Jane Wayne',
|
|
52
|
+
'Alice Johnson',
|
|
53
|
+
'Bob Wilson',
|
|
54
|
+
'Charlie Brown',
|
|
55
|
+
'Diana Prince',
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
const objectOptions = [
|
|
59
|
+
{ label: 'John Doe', value: 'john-doe' },
|
|
60
|
+
{ label: 'Jane Doe', value: 'jane-doe' },
|
|
61
|
+
{ label: 'John Smith', value: 'john-smith' },
|
|
62
|
+
{ label: 'Jane Smith', value: 'jane-smith', disabled: true },
|
|
63
|
+
{ label: 'John Wayne', value: 'john-wayne' },
|
|
64
|
+
{ label: 'Jane Wayne', value: 'jane-wayne' },
|
|
65
|
+
{ label: 'Alice Johnson', value: 'alice-johnson' },
|
|
66
|
+
{ label: 'Bob Wilson', value: 'bob-wilson' },
|
|
67
|
+
]
|
|
68
|
+
|
|
69
|
+
const optionsWithIcons = [
|
|
70
|
+
{ label: 'Dashboard', value: 'dashboard', icon: '📊' },
|
|
71
|
+
{ label: 'Projects', value: 'projects', icon: '📁' },
|
|
72
|
+
{ label: 'Tasks', value: 'tasks', icon: '✅' },
|
|
73
|
+
{ label: 'Calendar', value: 'calendar', icon: '📅' },
|
|
74
|
+
{ label: 'Reports', value: 'reports', icon: '📈' },
|
|
75
|
+
{ label: 'Settings', value: 'settings', icon: '⚙️' },
|
|
76
|
+
]
|
|
77
|
+
|
|
78
|
+
const groupedOptions = [
|
|
79
|
+
{
|
|
80
|
+
group: 'Fruits',
|
|
81
|
+
options: [
|
|
82
|
+
{ label: 'Apple', value: 'apple', icon: '🍎' },
|
|
83
|
+
{ label: 'Banana', value: 'banana', icon: '🍌' },
|
|
84
|
+
{ label: 'Orange', value: 'orange', icon: '🍊' },
|
|
85
|
+
{ label: 'Grape', value: 'grape', icon: '🍇' },
|
|
86
|
+
],
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
group: 'Vegetables',
|
|
90
|
+
options: [
|
|
91
|
+
{ label: 'Carrot', value: 'carrot', icon: '🥕' },
|
|
92
|
+
{ label: 'Broccoli', value: 'broccoli', icon: '🥦' },
|
|
93
|
+
{ label: 'Tomato', value: 'tomato', icon: '🍅' },
|
|
94
|
+
{ label: 'Lettuce', value: 'lettuce', icon: '🥬' },
|
|
95
|
+
],
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
group: 'Proteins',
|
|
99
|
+
options: [
|
|
100
|
+
{ label: 'Chicken', value: 'chicken', icon: '🍗' },
|
|
101
|
+
{ label: 'Fish', value: 'fish', icon: '🐟' },
|
|
102
|
+
{ label: 'Beef', value: 'beef', icon: '🥩' },
|
|
103
|
+
{ label: 'Tofu', value: 'tofu', icon: '🪤', disabled: true },
|
|
104
|
+
],
|
|
105
|
+
},
|
|
106
|
+
]
|
|
107
|
+
|
|
108
|
+
const state = reactive({
|
|
109
|
+
disabled: false,
|
|
110
|
+
placeholder: 'Select an option...',
|
|
111
|
+
showCancel: true,
|
|
112
|
+
})
|
|
113
|
+
</script>
|
|
114
|
+
|
|
115
|
+
<template>
|
|
116
|
+
<Story title="Combobox" :layout="{ type: 'grid', width: 400 }">
|
|
117
|
+
<Variant title="Simple String Options">
|
|
118
|
+
<div class="p-4">
|
|
119
|
+
<label class="block text-sm font-medium mb-2">Simple Options</label>
|
|
120
|
+
<Combobox
|
|
121
|
+
:options="simpleOptions"
|
|
122
|
+
v-model="simpleValue"
|
|
123
|
+
:placeholder="state.placeholder"
|
|
124
|
+
:disabled="state.disabled"
|
|
125
|
+
:show-cancel="state.showCancel"
|
|
126
|
+
@update:selectedOption="selectedOption = $event"
|
|
127
|
+
/>
|
|
128
|
+
<div class="mt-2 text-sm text-gray-600">
|
|
129
|
+
Selected: {{ simpleValue || 'None' }}
|
|
130
|
+
</div>
|
|
131
|
+
</div>
|
|
132
|
+
</Variant>
|
|
133
|
+
|
|
134
|
+
<Variant title="Object Options">
|
|
135
|
+
<div class="p-4">
|
|
136
|
+
<label class="block text-sm font-medium mb-2">Object Options</label>
|
|
137
|
+
<Combobox
|
|
138
|
+
:options="objectOptions"
|
|
139
|
+
v-model="objectValue"
|
|
140
|
+
:placeholder="state.placeholder"
|
|
141
|
+
:disabled="state.disabled"
|
|
142
|
+
:show-cancel="state.showCancel"
|
|
143
|
+
/>
|
|
144
|
+
<div class="mt-2 text-sm text-gray-600">
|
|
145
|
+
Selected: {{ objectValue || 'None' }}
|
|
146
|
+
</div>
|
|
147
|
+
</div>
|
|
148
|
+
</Variant>
|
|
149
|
+
|
|
150
|
+
<Variant title="Options with Icons">
|
|
151
|
+
<div class="p-4">
|
|
152
|
+
<label class="block text-sm font-medium mb-2">Options with Icons</label>
|
|
153
|
+
<Combobox
|
|
154
|
+
:options="optionsWithIcons"
|
|
155
|
+
v-model="iconValue"
|
|
156
|
+
:placeholder="state.placeholder"
|
|
157
|
+
:disabled="state.disabled"
|
|
158
|
+
/>
|
|
159
|
+
<div class="mt-2 text-sm text-gray-600">
|
|
160
|
+
Selected: {{ iconValue || 'None' }}
|
|
161
|
+
</div>
|
|
162
|
+
</div>
|
|
163
|
+
</Variant>
|
|
164
|
+
|
|
165
|
+
<Variant title="Grouped Options">
|
|
166
|
+
<div class="p-4">
|
|
167
|
+
<label class="block text-sm font-medium mb-2">Grouped Options</label>
|
|
168
|
+
<Combobox
|
|
169
|
+
:options="groupedOptions"
|
|
170
|
+
v-model="groupedValue"
|
|
171
|
+
:placeholder="state.placeholder"
|
|
172
|
+
:disabled="state.disabled"
|
|
173
|
+
/>
|
|
174
|
+
<div class="mt-2 text-sm text-gray-600">
|
|
175
|
+
Selected: {{ groupedValue || 'None' }}
|
|
176
|
+
</div>
|
|
177
|
+
</div>
|
|
178
|
+
</Variant>
|
|
179
|
+
|
|
180
|
+
<Variant title="Disabled State">
|
|
181
|
+
<div class="p-4">
|
|
182
|
+
<label class="block text-sm font-medium mb-2">Disabled Combobox</label>
|
|
183
|
+
<Combobox
|
|
184
|
+
:options="simpleOptions"
|
|
185
|
+
v-model="disabledValue"
|
|
186
|
+
placeholder="This is disabled"
|
|
187
|
+
:disabled="true"
|
|
188
|
+
/>
|
|
189
|
+
</div>
|
|
190
|
+
</Variant>
|
|
191
|
+
|
|
192
|
+
<Variant title="Pre-selected Value">
|
|
193
|
+
<div class="p-4">
|
|
194
|
+
<label class="block text-sm font-medium mb-2">Pre-selected Value</label>
|
|
195
|
+
<Combobox
|
|
196
|
+
:options="objectOptions"
|
|
197
|
+
v-model="preselectedValue"
|
|
198
|
+
:placeholder="state.placeholder"
|
|
199
|
+
:disabled="state.disabled"
|
|
200
|
+
/>
|
|
201
|
+
<div class="mt-2 text-sm text-gray-600">
|
|
202
|
+
Selected: {{ preselectedValue || 'None' }}
|
|
203
|
+
</div>
|
|
204
|
+
</div>
|
|
205
|
+
</Variant>
|
|
206
|
+
|
|
207
|
+
<Variant title="Multiple Selection - Simple">
|
|
208
|
+
<div class="p-4">
|
|
209
|
+
<label class="block text-sm font-medium mb-2"
|
|
210
|
+
>Multiple Simple Options</label
|
|
211
|
+
>
|
|
212
|
+
<Combobox
|
|
213
|
+
:options="simpleOptions"
|
|
214
|
+
v-model="multipleSimpleValue"
|
|
215
|
+
:placeholder="state.placeholder"
|
|
216
|
+
:disabled="state.disabled"
|
|
217
|
+
:show-cancel="state.showCancel"
|
|
218
|
+
:multiple="true"
|
|
219
|
+
/>
|
|
220
|
+
<div class="mt-2 text-sm text-gray-600">
|
|
221
|
+
Selected:
|
|
222
|
+
{{
|
|
223
|
+
multipleSimpleValue.length > 0
|
|
224
|
+
? multipleSimpleValue.join(', ')
|
|
225
|
+
: 'None'
|
|
226
|
+
}}
|
|
227
|
+
</div>
|
|
228
|
+
</div>
|
|
229
|
+
</Variant>
|
|
230
|
+
|
|
231
|
+
<Variant title="Multiple Selection - Objects">
|
|
232
|
+
<div class="p-4">
|
|
233
|
+
<label class="block text-sm font-medium mb-2"
|
|
234
|
+
>Multiple Object Options</label
|
|
235
|
+
>
|
|
236
|
+
<Combobox
|
|
237
|
+
:options="objectOptions"
|
|
238
|
+
v-model="multipleObjectValue"
|
|
239
|
+
:placeholder="state.placeholder"
|
|
240
|
+
:disabled="state.disabled"
|
|
241
|
+
:multiple="true"
|
|
242
|
+
/>
|
|
243
|
+
<div class="mt-2 text-sm text-gray-600">
|
|
244
|
+
Selected:
|
|
245
|
+
{{
|
|
246
|
+
multipleObjectValue.length > 0
|
|
247
|
+
? multipleObjectValue.join(', ')
|
|
248
|
+
: 'None'
|
|
249
|
+
}}
|
|
250
|
+
</div>
|
|
251
|
+
</div>
|
|
252
|
+
</Variant>
|
|
253
|
+
|
|
254
|
+
<Variant title="Multiple Selection - Grouped">
|
|
255
|
+
<div class="p-4">
|
|
256
|
+
<label class="block text-sm font-medium mb-2"
|
|
257
|
+
>Multiple Grouped Options</label
|
|
258
|
+
>
|
|
259
|
+
<Combobox
|
|
260
|
+
:options="groupedOptions"
|
|
261
|
+
v-model="multipleGroupedValue"
|
|
262
|
+
:placeholder="state.placeholder"
|
|
263
|
+
:disabled="state.disabled"
|
|
264
|
+
:multiple="true"
|
|
265
|
+
/>
|
|
266
|
+
<div class="mt-2 text-sm text-gray-600">
|
|
267
|
+
Selected:
|
|
268
|
+
{{
|
|
269
|
+
multipleGroupedValue.length > 0
|
|
270
|
+
? multipleGroupedValue.join(', ')
|
|
271
|
+
: 'None'
|
|
272
|
+
}}
|
|
273
|
+
</div>
|
|
274
|
+
</div>
|
|
275
|
+
</Variant>
|
|
276
|
+
|
|
277
|
+
<Variant title="Complex Objects with Display Value">
|
|
278
|
+
<div class="p-4">
|
|
279
|
+
<label class="block text-sm font-medium mb-2">Complex Objects</label>
|
|
280
|
+
<Combobox
|
|
281
|
+
:options="complexObjects"
|
|
282
|
+
v-model="complexObjectValue"
|
|
283
|
+
:display-value="(obj) => (obj ? `${obj.label} - ${obj.email}` : '')"
|
|
284
|
+
:placeholder="state.placeholder"
|
|
285
|
+
:disabled="state.disabled"
|
|
286
|
+
:show-cancel="state.showCancel"
|
|
287
|
+
/>
|
|
288
|
+
<div class="mt-2 text-sm text-gray-600">
|
|
289
|
+
Selected: {{ complexObjectValue || 'None' }}
|
|
290
|
+
</div>
|
|
291
|
+
</div>
|
|
292
|
+
</Variant>
|
|
293
|
+
|
|
294
|
+
<template #controls>
|
|
295
|
+
<HstText v-model="state.placeholder" title="Placeholder" />
|
|
296
|
+
<HstCheckbox v-model="state.disabled" title="Disabled" />
|
|
297
|
+
<HstCheckbox v-model="state.showCancel" title="Show Cancel Button" />
|
|
298
|
+
</template>
|
|
299
|
+
</Story>
|
|
300
|
+
</template>
|
|
@@ -44,7 +44,12 @@ interface ComboboxProps {
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
const props = defineProps<ComboboxProps>()
|
|
47
|
-
const emit = defineEmits([
|
|
47
|
+
const emit = defineEmits([
|
|
48
|
+
'update:modelValue',
|
|
49
|
+
'update:selectedOption',
|
|
50
|
+
'focus',
|
|
51
|
+
'blur',
|
|
52
|
+
])
|
|
48
53
|
|
|
49
54
|
const searchTerm = ref(getDisplayValue(props.modelValue))
|
|
50
55
|
const internalModelValue = ref(props.modelValue)
|
|
@@ -196,6 +201,14 @@ const handleOpenChange = (open: boolean) => {
|
|
|
196
201
|
userHasTyped.value = false
|
|
197
202
|
}
|
|
198
203
|
}
|
|
204
|
+
|
|
205
|
+
const handleFocus = (event: FocusEvent) => {
|
|
206
|
+
emit('focus', event)
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const handleBlur = (event: FocusEvent) => {
|
|
210
|
+
emit('blur', event)
|
|
211
|
+
}
|
|
199
212
|
</script>
|
|
200
213
|
|
|
201
214
|
<template>
|
|
@@ -215,6 +228,8 @@ const handleOpenChange = (open: boolean) => {
|
|
|
215
228
|
<ComboboxInput
|
|
216
229
|
:value="searchTerm"
|
|
217
230
|
@input="handleInputChange"
|
|
231
|
+
@focus="handleFocus"
|
|
232
|
+
@blur="handleBlur"
|
|
218
233
|
class="bg-transparent p-0 focus:outline-0 border-0 focus:border-0 focus:ring-0 text-base text-ink-gray-8 h-full placeholder:text-ink-gray-4 w-full"
|
|
219
234
|
:placeholder="placeholder || ''"
|
|
220
235
|
:disabled="disabled"
|
|
@@ -15,7 +15,9 @@
|
|
|
15
15
|
:class="inputClass"
|
|
16
16
|
v-bind="$attrs"
|
|
17
17
|
>
|
|
18
|
-
<template v-if="
|
|
18
|
+
<template #prefix v-if="$slots.prefix">
|
|
19
|
+
<slot name="prefix" />
|
|
20
|
+
</template>
|
|
19
21
|
</TextInput>
|
|
20
22
|
</template>
|
|
21
23
|
|
|
@@ -128,16 +130,15 @@
|
|
|
128
130
|
import { computed, onMounted } from 'vue'
|
|
129
131
|
|
|
130
132
|
import { Button } from '../Button'
|
|
131
|
-
import { Popover } from '../Popover'
|
|
132
133
|
import FeatherIcon from '../FeatherIcon.vue'
|
|
134
|
+
import { Popover } from '../Popover'
|
|
133
135
|
import { TextInput } from '../TextInput'
|
|
134
|
-
import LucideCalendar from '~icons/lucide/calendar'
|
|
135
136
|
|
|
136
|
-
import { getDate, getDateValue } from './utils'
|
|
137
|
-
import { useDatePicker } from './useDatePicker'
|
|
138
137
|
import { dayjsLocal } from '../../utils/dayjs'
|
|
138
|
+
import { useDatePicker } from './useDatePicker'
|
|
139
|
+
import { getDate, getDateValue } from './utils'
|
|
139
140
|
|
|
140
|
-
import type {
|
|
141
|
+
import type { DatePickerEmits, DatePickerProps } from './types'
|
|
141
142
|
|
|
142
143
|
const props = defineProps<DatePickerProps>()
|
|
143
144
|
const emit = defineEmits<DatePickerEmits>()
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<Popover
|
|
3
|
+
ref="popoverRef"
|
|
3
4
|
@open="selectCurrentMonthYear"
|
|
4
5
|
class="flex w-full [&>div:first-child]:w-full"
|
|
5
6
|
:placement="placement"
|
|
@@ -8,14 +9,17 @@
|
|
|
8
9
|
<TextInput
|
|
9
10
|
readonly
|
|
10
11
|
type="text"
|
|
11
|
-
icon-left="calendar"
|
|
12
12
|
:placeholder="placeholder"
|
|
13
13
|
:value="dateValue && formatter ? formatDates(dateValue) : dateValue"
|
|
14
14
|
@focus="!readonly ? togglePopover() : null"
|
|
15
15
|
class="w-full"
|
|
16
16
|
:class="inputClass"
|
|
17
17
|
v-bind="$attrs"
|
|
18
|
-
|
|
18
|
+
>
|
|
19
|
+
<template #prefix v-if="$slots.prefix">
|
|
20
|
+
<slot name="prefix" />
|
|
21
|
+
</template>
|
|
22
|
+
</TextInput>
|
|
19
23
|
</template>
|
|
20
24
|
|
|
21
25
|
<template #body="{ togglePopover }">
|
|
@@ -120,15 +124,13 @@
|
|
|
120
124
|
</template>
|
|
121
125
|
|
|
122
126
|
<script setup lang="ts">
|
|
123
|
-
import { computed,
|
|
127
|
+
import { computed, onMounted, ref } from 'vue'
|
|
124
128
|
|
|
125
|
-
import { Button } from '../Button'
|
|
126
129
|
import { Popover } from '../Popover'
|
|
127
|
-
import FeatherIcon from '../FeatherIcon.vue'
|
|
128
130
|
import { TextInput } from '../TextInput'
|
|
129
131
|
|
|
130
|
-
import { getDate, getDateValue } from './utils'
|
|
131
132
|
import { useDatePicker } from './useDatePicker'
|
|
133
|
+
import { getDate, getDateValue } from './utils'
|
|
132
134
|
|
|
133
135
|
import type { DatePickerEmits, DatePickerProps } from './types'
|
|
134
136
|
|
|
@@ -161,8 +163,8 @@ const dateValue = computed(() => {
|
|
|
161
163
|
return props.value ? props.value : props.modelValue
|
|
162
164
|
})
|
|
163
165
|
|
|
164
|
-
const fromDate = ref<string>(
|
|
165
|
-
const toDate = ref<string>(
|
|
166
|
+
const fromDate = ref<string>('')
|
|
167
|
+
const toDate = ref<string>('')
|
|
166
168
|
|
|
167
169
|
function handleDateClick(date: Date) {
|
|
168
170
|
if (fromDate.value && toDate.value) {
|
|
@@ -215,13 +217,15 @@ function isInRange(date: Date) {
|
|
|
215
217
|
return date >= getDate(fromDate.value) && date <= getDate(toDate.value)
|
|
216
218
|
}
|
|
217
219
|
|
|
218
|
-
function formatDates(value: string) {
|
|
219
|
-
if (!value)
|
|
220
|
-
|
|
220
|
+
function formatDates(value: string | string[]) {
|
|
221
|
+
if (!value) return ''
|
|
222
|
+
|
|
223
|
+
if (typeof value === 'string') {
|
|
224
|
+
value = value.split(',')
|
|
221
225
|
}
|
|
222
|
-
|
|
226
|
+
|
|
223
227
|
return props.formatter
|
|
224
|
-
? props.formatter(
|
|
228
|
+
? props.formatter(value[0]) + ' to ' + props.formatter(value[1])
|
|
225
229
|
: value
|
|
226
230
|
}
|
|
227
231
|
|
|
@@ -231,5 +235,22 @@ function clearDates() {
|
|
|
231
235
|
selectDates()
|
|
232
236
|
}
|
|
233
237
|
|
|
234
|
-
|
|
238
|
+
const popoverRef = ref<InstanceType<typeof Popover>>()
|
|
239
|
+
|
|
240
|
+
onMounted(() => {
|
|
241
|
+
let dates: string | string[] | undefined =
|
|
242
|
+
typeof dateValue?.value === 'string'
|
|
243
|
+
? dateValue.value.split(',')
|
|
244
|
+
: dateValue.value
|
|
245
|
+
fromDate.value = dates?.[0] || ''
|
|
246
|
+
toDate.value = dates?.[1] || ''
|
|
247
|
+
|
|
248
|
+
selectCurrentMonthYear()
|
|
249
|
+
})
|
|
250
|
+
|
|
251
|
+
defineExpose({
|
|
252
|
+
open: () => {
|
|
253
|
+
popoverRef.value?.open()
|
|
254
|
+
},
|
|
255
|
+
})
|
|
235
256
|
</script>
|
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
<TextInput
|
|
9
9
|
readonly
|
|
10
10
|
type="text"
|
|
11
|
-
icon-left="calendar"
|
|
12
11
|
:placeholder="placeholder"
|
|
13
12
|
:value="dateValue && formatter ? formatter(dateValue) : dateValue"
|
|
14
13
|
@focus="!readonly ? togglePopover() : null"
|
|
@@ -16,7 +15,9 @@
|
|
|
16
15
|
:class="inputClass"
|
|
17
16
|
v-bind="$attrs"
|
|
18
17
|
>
|
|
19
|
-
<template v-if="
|
|
18
|
+
<template #prefix v-if="$slots.prefix">
|
|
19
|
+
<slot name="prefix" />
|
|
20
|
+
</template>
|
|
20
21
|
</TextInput>
|
|
21
22
|
</template>
|
|
22
23
|
|
|
@@ -189,17 +190,16 @@
|
|
|
189
190
|
</template>
|
|
190
191
|
|
|
191
192
|
<script setup lang="ts">
|
|
192
|
-
import {
|
|
193
|
+
import { computed, onMounted, ref } from 'vue'
|
|
193
194
|
|
|
194
195
|
import { Button } from '../Button'
|
|
195
|
-
import { Popover } from '../Popover'
|
|
196
196
|
import FeatherIcon from '../FeatherIcon.vue'
|
|
197
|
+
import { Popover } from '../Popover'
|
|
197
198
|
import { TextInput } from '../TextInput'
|
|
198
|
-
import LucideCalendar from '~icons/lucide/calendar'
|
|
199
199
|
|
|
200
|
-
import { getDate } from './utils'
|
|
201
|
-
import { useDatePicker } from './useDatePicker'
|
|
202
200
|
import { dayjs, dayjsLocal, dayjsSystem } from '../../utils/dayjs'
|
|
201
|
+
import { useDatePicker } from './useDatePicker'
|
|
202
|
+
import { getDate } from './utils'
|
|
203
203
|
|
|
204
204
|
import type { DatePickerEmits, DatePickerProps } from './types'
|
|
205
205
|
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
export interface DatePickerProps {
|
|
2
|
-
value?: string
|
|
3
|
-
modelValue?: string
|
|
2
|
+
value?: string | string[] // format: "YYYY-MM-DD,YYYY-MM-DD" or ["YYYY-MM-DD","YYYY-MM-DD"]
|
|
3
|
+
modelValue?: string | string[] // format: "YYYY-MM-DD,YYYY-MM-DD" or ["YYYY-MM-DD","YYYY-MM-DD"]
|
|
4
4
|
placeholder?: string
|
|
5
5
|
formatter?: (date: string) => string
|
|
6
6
|
readonly?: boolean
|
|
7
7
|
inputClass?: string | Array<string> | Record<string, boolean>
|
|
8
|
-
placement?: string
|
|
9
|
-
hideIcon?: boolean
|
|
8
|
+
placement?: string
|
|
10
9
|
}
|
|
11
10
|
|
|
12
11
|
export type DatePickerEmits = {
|
|
@@ -15,7 +15,6 @@
|
|
|
15
15
|
v-if="type === 'select'"
|
|
16
16
|
:id="id"
|
|
17
17
|
v-bind="{ ...controlAttrs, size, variant }"
|
|
18
|
-
v-model="model"
|
|
19
18
|
>
|
|
20
19
|
<template #prefix v-if="$slots.prefix">
|
|
21
20
|
<slot name="prefix" />
|
|
@@ -24,7 +23,6 @@
|
|
|
24
23
|
<Autocomplete
|
|
25
24
|
v-else-if="type === 'autocomplete'"
|
|
26
25
|
v-bind="{ ...controlAttrs }"
|
|
27
|
-
v-model="model"
|
|
28
26
|
>
|
|
29
27
|
<template #prefix v-if="$slots.prefix">
|
|
30
28
|
<slot name="prefix" />
|
|
@@ -37,13 +35,11 @@
|
|
|
37
35
|
v-else-if="type === 'textarea'"
|
|
38
36
|
:id="id"
|
|
39
37
|
v-bind="{ ...controlAttrs, size, variant }"
|
|
40
|
-
v-model="model"
|
|
41
38
|
/>
|
|
42
39
|
<TextInput
|
|
43
40
|
v-else
|
|
44
41
|
:id="id"
|
|
45
42
|
v-bind="{ ...controlAttrs, type, size, variant, required }"
|
|
46
|
-
v-model="model"
|
|
47
43
|
>
|
|
48
44
|
<template #prefix v-if="$slots.prefix">
|
|
49
45
|
<slot name="prefix" />
|
|
@@ -60,7 +56,6 @@
|
|
|
60
56
|
v-else
|
|
61
57
|
:id="id"
|
|
62
58
|
v-bind="{ ...controlAttrs, label, size, class: attrs.class }"
|
|
63
|
-
v-model="model"
|
|
64
59
|
/>
|
|
65
60
|
</template>
|
|
66
61
|
<script setup lang="ts">
|
|
@@ -81,8 +76,6 @@ const props = withDefaults(defineProps<FormControlProps>(), {
|
|
|
81
76
|
variant: 'subtle',
|
|
82
77
|
})
|
|
83
78
|
|
|
84
|
-
const model = defineModel()
|
|
85
|
-
|
|
86
79
|
const attrs = useAttrs()
|
|
87
80
|
const controlAttrs = computed(() => {
|
|
88
81
|
// pass everything except class and style
|