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.
Files changed (50) hide show
  1. package/melon/Billing/TrialBanner.vue +1 -2
  2. package/package.json +7 -4
  3. package/readme.md +0 -1
  4. package/src/components/Autocomplete/Autocomplete.vue +1 -1
  5. package/src/components/Charts/ECharts.vue +1 -1
  6. package/src/components/Charts/axisChartOptions.ts +1 -0
  7. package/src/components/Combobox/Combobox.story.vue +300 -0
  8. package/src/components/Combobox/Combobox.vue +16 -1
  9. package/src/components/DatePicker/DatePicker.vue +7 -6
  10. package/src/components/DatePicker/DateRangePicker.vue +35 -14
  11. package/src/components/DatePicker/DateTimePicker.vue +7 -7
  12. package/src/components/DatePicker/types.ts +3 -4
  13. package/src/components/FormControl/FormControl.vue +0 -7
  14. package/src/components/Select/types.ts +0 -1
  15. package/src/components/Sidebar/Sidebar.story.vue +79 -0
  16. package/src/components/Sidebar/Sidebar.vue +60 -0
  17. package/src/components/Sidebar/SidebarHeader.vue +55 -0
  18. package/src/components/Sidebar/SidebarItem.vue +94 -0
  19. package/src/components/Sidebar/SidebarSection.vue +69 -0
  20. package/src/components/Sidebar/index.ts +2 -0
  21. package/src/components/Sidebar/types.ts +31 -0
  22. package/src/components/Switch/Switch.vue +3 -3
  23. package/src/components/TabButtons/TabButtons.vue +1 -1
  24. package/src/components/TextEditor/InsertImage.vue +27 -5
  25. package/src/components/TextEditor/InsertVideo.vue +8 -91
  26. package/src/components/TextEditor/TextEditor.vue +198 -224
  27. package/src/components/TextEditor/extensions/content-paste-extension.ts +81 -0
  28. package/src/components/TextEditor/extensions/image/image-extension.ts +12 -10
  29. package/src/components/TextEditor/extensions/image-group/ImageGroupNodeView.vue +216 -0
  30. package/src/components/TextEditor/extensions/image-group/ImageGroupUploadDialog.vue +738 -0
  31. package/src/components/TextEditor/extensions/image-group/image-group-extension.ts +115 -0
  32. package/src/components/TextEditor/types.ts +23 -0
  33. package/src/components/TextEditor/video-extension.ts +4 -8
  34. package/src/components/TextInput/types.ts +0 -1
  35. package/src/components/Toast/Toast.vue +2 -3
  36. package/src/components/Toast/index.ts +8 -3
  37. package/src/directives/onOutsideClick.ts +36 -0
  38. package/src/directives/visibility.ts +40 -0
  39. package/src/index.ts +7 -5
  40. package/src/utils/config.ts +36 -0
  41. package/src/utils/{dayjs.js → dayjs.ts} +4 -4
  42. package/src/utils/fileUploadHandler.ts +1 -14
  43. package/src/utils/{markdown.js → markdown.ts} +9 -11
  44. package/src/utils/melonRequest.js +10 -0
  45. package/src/utils/pageMeta.ts +114 -0
  46. package/src/utils/useFileUpload.ts +23 -4
  47. package/src/directives/onOutsideClick.js +0 -34
  48. package/src/directives/visibility.js +0 -24
  49. package/src/utils/config.js +0 -9
  50. 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.155",
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 vitest && git pull --rebase origin main && yarn version --patch && git push && git push --tags",
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 || 'No label'
325
+ return option?.label || option?.value
326
326
  }
327
327
  return option
328
328
  }
@@ -52,7 +52,7 @@ watch(
52
52
  <div
53
53
  ref="chartDiv"
54
54
  v-show="!error"
55
- class="h-full w-full min-w-[400px] min-h-[300px] px-4 py-2"
55
+ class="h-full w-full min-w-[300px] md:min-w-[400px] min-h-[300px] px-4 py-2"
56
56
  ></div>
57
57
  <div
58
58
  v-show="error"
@@ -118,6 +118,7 @@ function getLineSeriesOptions(
118
118
  ) {
119
119
  const showSymbol = series.showDataPoints || series.showDataLabels
120
120
  return {
121
+ connectNulls: true,
121
122
  symbol: 'circle',
122
123
  symbolSize: 7,
123
124
  showSymbol: showSymbol,
@@ -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(['update:modelValue', 'update:selectedOption'])
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="!hideIcon" #prefix><LucideCalendar class="size-4" /></template>
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 { DatePickerProps, DatePickerEmits } from './types'
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, ref, onMounted } from 'vue'
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>(dateValue.value ? dateValue.value[0] : '')
165
- const toDate = ref<string>(dateValue.value ? dateValue.value[1] : '')
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
- return ''
220
+ function formatDates(value: string | string[]) {
221
+ if (!value) return ''
222
+
223
+ if (typeof value === 'string') {
224
+ value = value.split(',')
221
225
  }
222
- const values = value.split(',')
226
+
223
227
  return props.formatter
224
- ? props.formatter(values[0]) + ' to ' + props.formatter(values[1])
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
- onMounted(() => selectCurrentMonthYear())
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="!hideIcon" #prefix><LucideCalendar class="size-4" /></template>
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 { ref, computed, onMounted } from 'vue'
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
@@ -12,7 +12,6 @@ export interface SelectProps {
12
12
  placeholder?: string
13
13
  disabled?: boolean
14
14
  id?: string
15
- value?: string | number
16
15
  modelValue?: string | number
17
16
  options?: SelectOption[]
18
17
  }