frappe-ui 1.0.0-beta.12 → 1.0.0-beta.13
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/package.json +1 -1
- package/src/components/DatePicker/CalendarPanel.vue +125 -83
- package/src/components/DatePicker/DatePicker.vue +0 -4
- package/src/components/DatePicker/DateRangePicker.vue +0 -6
- package/src/components/DatePicker/DateTimePicker.cy.ts +4 -2
- package/src/components/DatePicker/DateTimePicker.vue +0 -4
- package/src/components/DatePicker/composables.ts +15 -37
- package/src/components/DatePicker/types.ts +1 -1
- package/src/components/Popover/Popover.vue +3 -3
- package/src/components/TimePicker/TimePicker.vue +3 -1
- package/src/components/shared/picker/PickerShell.vue +3 -1
package/package.json
CHANGED
|
@@ -12,11 +12,7 @@
|
|
|
12
12
|
@click="emit('prev')"
|
|
13
13
|
/>
|
|
14
14
|
<span class="text-sm-medium text-ink-gray-7">
|
|
15
|
-
|
|
16
|
-
{{ months[currentMonth] }} {{ currentYear }}
|
|
17
|
-
</span>
|
|
18
|
-
<span v-else-if="view === 'month'">{{ currentYear }}</span>
|
|
19
|
-
<span v-else>{{ yearRangeStart }} - {{ yearRangeStart + 11 }}</span>
|
|
15
|
+
{{ months[currentMonth] }} {{ currentYear }}
|
|
20
16
|
</span>
|
|
21
17
|
<Button
|
|
22
18
|
:class="{ invisible: hideNext }"
|
|
@@ -34,13 +30,9 @@
|
|
|
34
30
|
label="cycle-calendar-view"
|
|
35
31
|
@click="emit('cycleView')"
|
|
36
32
|
>
|
|
37
|
-
|
|
38
|
-
{{ months[currentMonth] }} {{ currentYear }}
|
|
39
|
-
</span>
|
|
40
|
-
<span v-else-if="view === 'month'">{{ currentYear }}</span>
|
|
41
|
-
<span v-else>{{ yearRangeStart }} - {{ yearRangeStart + 11 }}</span>
|
|
33
|
+
{{ months[currentMonth] }} {{ currentYear }}
|
|
42
34
|
</Button>
|
|
43
|
-
<div class="flex items-center">
|
|
35
|
+
<div v-if="view === 'date'" class="flex items-center">
|
|
44
36
|
<Button
|
|
45
37
|
v-if="!hidePrev"
|
|
46
38
|
label="previous"
|
|
@@ -99,7 +91,7 @@
|
|
|
99
91
|
<button
|
|
100
92
|
v-else
|
|
101
93
|
type="button"
|
|
102
|
-
class="flex size-7 items-center justify-center text-sm transition-colors duration-100
|
|
94
|
+
class="flex size-7 items-center justify-center text-sm transition-colors duration-100"
|
|
103
95
|
:class="cellClass(cell)"
|
|
104
96
|
role="gridcell"
|
|
105
97
|
:aria-selected="ariaSelected(cell)"
|
|
@@ -112,9 +104,13 @@
|
|
|
112
104
|
:tabindex="isFocusedCell(cell) ? 0 : -1"
|
|
113
105
|
@mouseenter="emit('hoverCell', cell.date)"
|
|
114
106
|
@click="!cell.isUnavailable && emit('selectDate', cell.date)"
|
|
115
|
-
@keydown.left.prevent="
|
|
107
|
+
@keydown.left.prevent="
|
|
108
|
+
shiftFocus(cell.date.subtract(1, 'day'), -1)
|
|
109
|
+
"
|
|
116
110
|
@keydown.right.prevent="shiftFocus(cell.date.add(1, 'day'), 1)"
|
|
117
|
-
@keydown.up.prevent="
|
|
111
|
+
@keydown.up.prevent="
|
|
112
|
+
shiftFocus(cell.date.subtract(7, 'day'), -1)
|
|
113
|
+
"
|
|
118
114
|
@keydown.down.prevent="shiftFocus(cell.date.add(7, 'day'), 1)"
|
|
119
115
|
@keydown.home.prevent="
|
|
120
116
|
shiftFocus(cell.date.subtract(cell.date.day(), 'day'), -1)
|
|
@@ -151,54 +147,60 @@
|
|
|
151
147
|
</div>
|
|
152
148
|
</div>
|
|
153
149
|
</div>
|
|
154
|
-
<div
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
<button
|
|
161
|
-
v-for="(m, i) in months"
|
|
162
|
-
type="button"
|
|
163
|
-
:key="m"
|
|
164
|
-
class="py-2 text-sm rounded cursor-pointer text-center hover:bg-surface-gray-2 focus:outline-none focus:ring-2 focus:ring-brand-6"
|
|
165
|
-
:class="{
|
|
166
|
-
'bg-surface-gray-9 text-ink-base hover:bg-surface-gray-9':
|
|
167
|
-
i === currentMonth,
|
|
168
|
-
}"
|
|
169
|
-
:aria-selected="i === currentMonth ? 'true' : 'false'"
|
|
170
|
-
@click="emit('selectMonth', i)"
|
|
150
|
+
<div v-else class="flex h-52 w-52" aria-label="Select month and year">
|
|
151
|
+
<div
|
|
152
|
+
ref="yearListRef"
|
|
153
|
+
class="relative flex w-1/2 flex-col gap-0.5 overflow-y-auto"
|
|
154
|
+
role="listbox"
|
|
155
|
+
aria-label="Select year"
|
|
171
156
|
>
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
157
|
+
<button
|
|
158
|
+
v-for="y in years"
|
|
159
|
+
type="button"
|
|
160
|
+
:key="y"
|
|
161
|
+
class="w-full text-ink-gray-8 h-7 shrink-0 rounded py-1 text-sm text-center cursor-pointer transition-colors duration-100"
|
|
162
|
+
:class="
|
|
163
|
+
y === currentYear
|
|
164
|
+
? 'bg-surface-gray-2 hover:bg-surface-gray-3'
|
|
165
|
+
: ' hover:bg-surface-gray-1'
|
|
166
|
+
"
|
|
167
|
+
:data-selected="y === currentYear ? '' : undefined"
|
|
168
|
+
:aria-selected="y === currentYear ? 'true' : 'false'"
|
|
169
|
+
@click="emit('selectYear', y)"
|
|
170
|
+
>
|
|
171
|
+
{{ y }}
|
|
172
|
+
</button>
|
|
173
|
+
</div>
|
|
174
|
+
<div
|
|
175
|
+
ref="monthListRef"
|
|
176
|
+
class="relative flex w-1/2 flex-col gap-0.5 overflow-y-auto pl-1.5"
|
|
177
|
+
role="listbox"
|
|
178
|
+
aria-label="Select month"
|
|
192
179
|
>
|
|
193
|
-
|
|
194
|
-
|
|
180
|
+
<button
|
|
181
|
+
v-for="(m, i) in months"
|
|
182
|
+
type="button"
|
|
183
|
+
:key="m"
|
|
184
|
+
class="w-full text-ink-gray-8 shrink-0 h-7 rounded py-1 text-sm text-center cursor-pointer transition-colors duration-100"
|
|
185
|
+
:class="
|
|
186
|
+
i === currentMonth
|
|
187
|
+
? 'bg-surface-gray-2 hover:bg-surface-gray-3'
|
|
188
|
+
: ' hover:bg-surface-gray-1'
|
|
189
|
+
"
|
|
190
|
+
:data-selected="i === currentMonth ? '' : undefined"
|
|
191
|
+
:aria-selected="i === currentMonth ? 'true' : 'false'"
|
|
192
|
+
@click="emit('selectMonth', i)"
|
|
193
|
+
>
|
|
194
|
+
{{ m }}
|
|
195
|
+
</button>
|
|
196
|
+
</div>
|
|
195
197
|
</div>
|
|
196
198
|
</div>
|
|
197
199
|
</div>
|
|
198
200
|
</template>
|
|
199
201
|
|
|
200
202
|
<script setup lang="ts">
|
|
201
|
-
import { nextTick, ref, watch } from 'vue'
|
|
203
|
+
import { computed, nextTick, ref, watch } from 'vue'
|
|
202
204
|
import type { Dayjs } from 'dayjs/esm'
|
|
203
205
|
import { Button } from '../Button'
|
|
204
206
|
import { months } from './utils'
|
|
@@ -220,8 +222,6 @@ interface Props {
|
|
|
220
222
|
view: ViewMode
|
|
221
223
|
currentYear: number
|
|
222
224
|
currentMonth: number
|
|
223
|
-
yearRangeStart: number
|
|
224
|
-
yearRange: number[]
|
|
225
225
|
weeks: CalendarPanelCell[][]
|
|
226
226
|
/** Label for the optional Today/Now action button between prev/next. Empty/undefined hides it. */
|
|
227
227
|
todayLabel?: string
|
|
@@ -281,6 +281,44 @@ const emit = defineEmits<{
|
|
|
281
281
|
(e: 'update:focusedDate', d: Dayjs): void
|
|
282
282
|
}>()
|
|
283
283
|
|
|
284
|
+
// ── Month-year split view ────────────────────────────────────────────────────
|
|
285
|
+
// The year column is a scrollable list. We bound it to [min, max] when provided
|
|
286
|
+
// (so unreachable years aren't offered) and otherwise fall back to a wide window
|
|
287
|
+
// around the current year. The current year is always included.
|
|
288
|
+
const years = computed<number[]>(() => {
|
|
289
|
+
const current = props.currentYear
|
|
290
|
+
const minY = props.min ? Number(props.min.slice(0, 4)) : current - 100
|
|
291
|
+
const maxY = props.max ? Number(props.max.slice(0, 4)) : current + 10
|
|
292
|
+
const start = Math.min(minY, current)
|
|
293
|
+
const end = Math.max(maxY, current)
|
|
294
|
+
return Array.from({ length: end - start + 1 }, (_, i) => start + i)
|
|
295
|
+
})
|
|
296
|
+
|
|
297
|
+
const yearListRef = ref<HTMLElement | null>(null)
|
|
298
|
+
const monthListRef = ref<HTMLElement | null>(null)
|
|
299
|
+
|
|
300
|
+
// Center the active year/month when the split view opens. Manual scrollTop (vs
|
|
301
|
+
// scrollIntoView) keeps the scroll contained to each list and never nudges the
|
|
302
|
+
// popover or page. Relies on the list containers being `relative` so the
|
|
303
|
+
// buttons' `offsetTop` is measured against them.
|
|
304
|
+
function centerSelected(container: HTMLElement | null) {
|
|
305
|
+
const el = container?.querySelector<HTMLElement>('[data-selected]')
|
|
306
|
+
if (!container || !el) return
|
|
307
|
+
container.scrollTop =
|
|
308
|
+
el.offsetTop - container.clientHeight / 2 + el.clientHeight / 2
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
watch(
|
|
312
|
+
() => props.view,
|
|
313
|
+
(view) => {
|
|
314
|
+
if (view !== 'monthYear') return
|
|
315
|
+
nextTick(() => {
|
|
316
|
+
centerSelected(yearListRef.value)
|
|
317
|
+
centerSelected(monthListRef.value)
|
|
318
|
+
})
|
|
319
|
+
},
|
|
320
|
+
)
|
|
321
|
+
|
|
284
322
|
// ── Roving tabindex (Reka Calendar pattern) ──────────────────────────────────
|
|
285
323
|
// The focused date is *controlled* — the parent owns the value and feeds it
|
|
286
324
|
// in via `props.focusedDate`. Arrow keys compute a target, emit
|
|
@@ -295,9 +333,7 @@ function isFocusedCell(cell: CalendarPanelCell): boolean {
|
|
|
295
333
|
return !!props.focusedDate && cell.date.isSame(props.focusedDate, 'day')
|
|
296
334
|
}
|
|
297
335
|
|
|
298
|
-
function pickInitialFocusDate(
|
|
299
|
-
weeks: CalendarPanelCell[][],
|
|
300
|
-
): Dayjs | null {
|
|
336
|
+
function pickInitialFocusDate(weeks: CalendarPanelCell[][]): Dayjs | null {
|
|
301
337
|
const flat = weeks.flat()
|
|
302
338
|
const selected = flat.find(
|
|
303
339
|
(c) =>
|
|
@@ -343,12 +379,7 @@ watch(
|
|
|
343
379
|
// for an unbounded run of dates would otherwise spin forever.
|
|
344
380
|
const MAX_SKIP_DISABLED_STEPS = 366
|
|
345
381
|
|
|
346
|
-
function shiftFocus(
|
|
347
|
-
target: Dayjs,
|
|
348
|
-
dir: 1 | -1,
|
|
349
|
-
retried = false,
|
|
350
|
-
steps = 0,
|
|
351
|
-
) {
|
|
382
|
+
function shiftFocus(target: Dayjs, dir: 1 | -1, retried = false, steps = 0) {
|
|
352
383
|
// Bounds check first — if the target is outside [min, max], the arrow
|
|
353
384
|
// press is a no-op rather than trying to navigate into nothing. Matches
|
|
354
385
|
// Reka's CalendarCellTrigger behavior.
|
|
@@ -417,37 +448,48 @@ function ariaLabel(cell: CalendarPanelCell): string {
|
|
|
417
448
|
}
|
|
418
449
|
|
|
419
450
|
function cellClass(cell: CalendarPanelCell): Array<string | false> {
|
|
420
|
-
|
|
421
|
-
|
|
451
|
+
// "Today" stays bold whether or not it's selected; its gray text color is kept
|
|
452
|
+
// separate so it can be dropped on selected cells.
|
|
453
|
+
const todayFont = cell.isToday ? 'font-semibold' : ''
|
|
454
|
+
// Resting text color for non-selected cells. Omitted on selected/range cells:
|
|
455
|
+
// both are `text-*` utilities, so leaving them in would win the CSS source-order
|
|
456
|
+
// tie against `text-ink-base` and the selected date would render gray.
|
|
457
|
+
const restingText = [
|
|
458
|
+
cell.inMonth ? 'text-ink-gray-8' : 'text-ink-gray-3',
|
|
459
|
+
cell.isToday ? 'text-ink-gray-9' : '',
|
|
460
|
+
]
|
|
422
461
|
|
|
423
462
|
if (cell.isUnavailable) {
|
|
424
|
-
return [inMonthCls, todayCls, 'rounded opacity-30 cursor-not-allowed']
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
if (cell.isRangeStart || cell.isRangeEnd) {
|
|
428
463
|
return [
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
464
|
+
'rounded',
|
|
465
|
+
...restingText,
|
|
466
|
+
todayFont,
|
|
467
|
+
'opacity-30 cursor-not-allowed',
|
|
432
468
|
]
|
|
433
469
|
}
|
|
434
470
|
|
|
435
|
-
if (cell.
|
|
471
|
+
if (cell.isRangeStart || cell.isRangeEnd || cell.isSelected) {
|
|
436
472
|
return [
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
'
|
|
473
|
+
'rounded',
|
|
474
|
+
todayFont,
|
|
475
|
+
'bg-surface-gray-9 text-ink-base hover:bg-surface-gray-9 cursor-pointer',
|
|
440
476
|
]
|
|
441
477
|
}
|
|
442
478
|
|
|
443
|
-
if (cell.
|
|
479
|
+
if (cell.inRange) {
|
|
444
480
|
return [
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
481
|
+
'rounded',
|
|
482
|
+
...restingText,
|
|
483
|
+
todayFont,
|
|
484
|
+
'bg-surface-gray-3 hover:bg-surface-gray-3 cursor-pointer',
|
|
448
485
|
]
|
|
449
486
|
}
|
|
450
487
|
|
|
451
|
-
return [
|
|
488
|
+
return [
|
|
489
|
+
'rounded',
|
|
490
|
+
...restingText,
|
|
491
|
+
todayFont,
|
|
492
|
+
'hover:bg-surface-gray-2 cursor-pointer',
|
|
493
|
+
]
|
|
452
494
|
}
|
|
453
495
|
</script>
|
|
@@ -59,8 +59,6 @@
|
|
|
59
59
|
:view="view"
|
|
60
60
|
:current-year="currentYear"
|
|
61
61
|
:current-month="currentMonth"
|
|
62
|
-
:year-range-start="yearRangeStart"
|
|
63
|
-
:year-range="yearRange"
|
|
64
62
|
:weeks="weeks"
|
|
65
63
|
today-label="Today"
|
|
66
64
|
:min="props.min"
|
|
@@ -223,8 +221,6 @@ const {
|
|
|
223
221
|
view,
|
|
224
222
|
currentYear,
|
|
225
223
|
currentMonth,
|
|
226
|
-
yearRangeStart,
|
|
227
|
-
yearRange,
|
|
228
224
|
prev,
|
|
229
225
|
next,
|
|
230
226
|
cycleView,
|
|
@@ -65,8 +65,6 @@
|
|
|
65
65
|
:view="view"
|
|
66
66
|
:current-year="currentYear"
|
|
67
67
|
:current-month="currentMonth"
|
|
68
|
-
:year-range-start="yearRangeStart"
|
|
69
|
-
:year-range="yearRange"
|
|
70
68
|
:weeks="weeks"
|
|
71
69
|
:today-label="isDualPaneActive ? '' : 'Today'"
|
|
72
70
|
:hide-next="isDualPaneActive"
|
|
@@ -91,8 +89,6 @@
|
|
|
91
89
|
:view="view"
|
|
92
90
|
:current-year="rightYear"
|
|
93
91
|
:current-month="rightMonth"
|
|
94
|
-
:year-range-start="yearRangeStart"
|
|
95
|
-
:year-range="yearRange"
|
|
96
92
|
:weeks="rightWeeks"
|
|
97
93
|
hide-prev
|
|
98
94
|
hide-today
|
|
@@ -286,8 +282,6 @@ const {
|
|
|
286
282
|
view,
|
|
287
283
|
currentYear,
|
|
288
284
|
currentMonth,
|
|
289
|
-
yearRangeStart,
|
|
290
|
-
yearRange,
|
|
291
285
|
prev,
|
|
292
286
|
next,
|
|
293
287
|
cycleView,
|
|
@@ -184,10 +184,12 @@ describe('DateTimePicker', () => {
|
|
|
184
184
|
})
|
|
185
185
|
})
|
|
186
186
|
|
|
187
|
-
it('cycle-calendar-view button
|
|
187
|
+
it('cycle-calendar-view button opens the month-year split view', () => {
|
|
188
188
|
cy.mount(DateTimePicker)
|
|
189
189
|
cy.get('input').first().dblclick()
|
|
190
190
|
cy.get('[aria-label=cycle-calendar-view]').click()
|
|
191
|
-
|
|
191
|
+
// Split view: scrollable year list beside a scrollable month list.
|
|
192
|
+
cy.get('[role=listbox][aria-label="Select year"]').should('exist')
|
|
193
|
+
cy.get('[role=listbox][aria-label="Select month"]').should('exist')
|
|
192
194
|
})
|
|
193
195
|
})
|
|
@@ -61,8 +61,6 @@
|
|
|
61
61
|
:view="view"
|
|
62
62
|
:current-year="currentYear"
|
|
63
63
|
:current-month="currentMonth"
|
|
64
|
-
:year-range-start="yearRangeStart"
|
|
65
|
-
:year-range="yearRange"
|
|
66
64
|
:weeks="weeks"
|
|
67
65
|
today-label="Now"
|
|
68
66
|
:min="resolvedMin"
|
|
@@ -232,8 +230,6 @@ const {
|
|
|
232
230
|
view,
|
|
233
231
|
currentYear,
|
|
234
232
|
currentMonth,
|
|
235
|
-
yearRangeStart,
|
|
236
|
-
yearRange,
|
|
237
233
|
prev,
|
|
238
234
|
next,
|
|
239
235
|
cycleView,
|
|
@@ -16,57 +16,37 @@ export function useCalendarView() {
|
|
|
16
16
|
const currentYear = ref<number>(dayjs().year())
|
|
17
17
|
const currentMonth = ref<number>(dayjs().month())
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
)
|
|
22
|
-
const yearRange = computed<number[]>(() =>
|
|
23
|
-
Array.from({ length: 12 }, (_, i) => yearRangeStart.value + i),
|
|
24
|
-
)
|
|
25
|
-
|
|
19
|
+
// Prev/next only navigate months in the day grid. The month-year split view
|
|
20
|
+
// scrolls instead of paging, so it has no prev/next controls.
|
|
26
21
|
function prev(): void {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
currentMonth.value = m.month()
|
|
34
|
-
} else if (view.value === 'month') {
|
|
35
|
-
currentYear.value -= 1
|
|
36
|
-
} else {
|
|
37
|
-
currentYear.value -= 12
|
|
38
|
-
}
|
|
22
|
+
const m = monthStart(currentYear.value, currentMonth.value).subtract(
|
|
23
|
+
1,
|
|
24
|
+
'month',
|
|
25
|
+
)
|
|
26
|
+
currentYear.value = m.year()
|
|
27
|
+
currentMonth.value = m.month()
|
|
39
28
|
}
|
|
40
29
|
|
|
41
30
|
function next(): void {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
'month',
|
|
46
|
-
)
|
|
47
|
-
currentYear.value = m.year()
|
|
48
|
-
currentMonth.value = m.month()
|
|
49
|
-
} else if (view.value === 'month') {
|
|
50
|
-
currentYear.value += 1
|
|
51
|
-
} else {
|
|
52
|
-
currentYear.value += 12
|
|
53
|
-
}
|
|
31
|
+
const m = monthStart(currentYear.value, currentMonth.value).add(1, 'month')
|
|
32
|
+
currentYear.value = m.year()
|
|
33
|
+
currentMonth.value = m.month()
|
|
54
34
|
}
|
|
55
35
|
|
|
36
|
+
// Toggle between the day grid and the month-year split view.
|
|
56
37
|
function cycleView(): void {
|
|
57
|
-
|
|
58
|
-
else if (view.value === 'month') view.value = 'year'
|
|
59
|
-
else view.value = 'date'
|
|
38
|
+
view.value = view.value === 'date' ? 'monthYear' : 'date'
|
|
60
39
|
}
|
|
61
40
|
|
|
41
|
+
// Picking a month commits the choice and returns to the day grid.
|
|
62
42
|
function selectMonth(i: number): void {
|
|
63
43
|
currentMonth.value = i
|
|
64
44
|
view.value = 'date'
|
|
65
45
|
}
|
|
66
46
|
|
|
47
|
+
// Picking a year stays in the split view so the user can then pick a month.
|
|
67
48
|
function selectYear(y: number): void {
|
|
68
49
|
currentYear.value = y
|
|
69
|
-
view.value = 'month'
|
|
70
50
|
}
|
|
71
51
|
|
|
72
52
|
function focusOn(d: Dayjs): void {
|
|
@@ -82,8 +62,6 @@ export function useCalendarView() {
|
|
|
82
62
|
view,
|
|
83
63
|
currentYear,
|
|
84
64
|
currentMonth,
|
|
85
|
-
yearRangeStart,
|
|
86
|
-
yearRange,
|
|
87
65
|
prev,
|
|
88
66
|
next,
|
|
89
67
|
cycleView,
|
|
@@ -303,7 +303,7 @@ export interface DateTimePickerSlots {
|
|
|
303
303
|
actions?: (props: DateTimePickerActionsSlotProps) => any
|
|
304
304
|
}
|
|
305
305
|
|
|
306
|
-
export type DatePickerViewMode = 'date' | '
|
|
306
|
+
export type DatePickerViewMode = 'date' | 'monthYear'
|
|
307
307
|
|
|
308
308
|
export interface DatePickerDateObj {
|
|
309
309
|
date: Dayjs
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
<PopoverAnchor asChild>
|
|
4
4
|
<div
|
|
5
5
|
ref="anchorRef"
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
v-bind="$attrs"
|
|
7
|
+
class="flex"
|
|
8
8
|
@mouseover="onMouseover"
|
|
9
9
|
@mouseleave="onMouseleave"
|
|
10
10
|
>
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
</template>
|
|
66
66
|
|
|
67
67
|
<script setup lang="ts">
|
|
68
|
-
import { computed, ref, onUnmounted
|
|
68
|
+
import { computed, ref, onUnmounted } from 'vue'
|
|
69
69
|
import {
|
|
70
70
|
PopoverAnchor,
|
|
71
71
|
PopoverContent,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<PopoverRoot v-model:open="isOpen">
|
|
3
3
|
<PopoverAnchor :reference="anchorEl" as-child>
|
|
4
|
-
<div>
|
|
4
|
+
<div v-bind="$attrs">
|
|
5
5
|
<TextInput
|
|
6
6
|
ref="inputRef"
|
|
7
7
|
v-model="displayValue"
|
|
@@ -157,6 +157,8 @@ defineSlots<{
|
|
|
157
157
|
suffix?: (props: { togglePopover: () => void; isOpen: boolean }) => any
|
|
158
158
|
}>()
|
|
159
159
|
|
|
160
|
+
defineOptions({ inheritAttrs: false })
|
|
161
|
+
|
|
160
162
|
// ── Prop reconciliation (new wins; legacy aliases preserved with warnings) ──
|
|
161
163
|
|
|
162
164
|
const resolvedSide = computed<PopoverSide>(
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<PopoverRoot v-model:open="open">
|
|
3
3
|
<PopoverAnchor :reference="anchorEl" as-child>
|
|
4
|
-
<div @keydown.down.prevent="onArrowDown">
|
|
4
|
+
<div v-bind="$attrs" @keydown.down.prevent="onArrowDown">
|
|
5
5
|
<slot name="trigger" v-bind="triggerSlotProps">
|
|
6
6
|
<slot name="target" v-bind="triggerSlotProps">
|
|
7
7
|
<TextInput
|
|
@@ -145,6 +145,8 @@ const slots = defineSlots<{
|
|
|
145
145
|
default?: (props: { close: () => void }) => any
|
|
146
146
|
}>()
|
|
147
147
|
|
|
148
|
+
defineOptions({ inheritAttrs: false })
|
|
149
|
+
|
|
148
150
|
const open = defineModel<boolean>('open', { default: false })
|
|
149
151
|
const inputValue = defineModel<string>('inputValue', { default: '' })
|
|
150
152
|
const typing = defineModel<boolean>('typing', { default: false })
|