@invopop/popui 0.1.4-beta.5 → 0.1.4-beta.50
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/dist/BaseDropdown.svelte +42 -3
- package/dist/BaseDropdown.svelte.d.ts +1 -0
- package/dist/BaseTableHeaderContent.svelte +1 -1
- package/dist/BaseTableHeaderOrderBy.svelte +28 -16
- package/dist/ButtonSearch.svelte +82 -0
- package/dist/ButtonSearch.svelte.d.ts +4 -0
- package/dist/DatePicker.svelte +84 -27
- package/dist/DatePicker.svelte.d.ts +5 -1
- package/dist/DrawerContext.svelte +428 -108
- package/dist/DrawerContextItem.svelte +6 -2
- package/dist/DropdownSelect.svelte +25 -6
- package/dist/DropdownSelect.svelte.d.ts +4 -1
- package/dist/EmptyState.svelte +6 -2
- package/dist/InputSearch.svelte +45 -5
- package/dist/InputSelect.svelte +12 -3
- package/dist/InputText.svelte +25 -8
- package/dist/InputToggle.svelte +23 -6
- package/dist/StepIcon.svelte +50 -0
- package/dist/StepIcon.svelte.d.ts +4 -0
- package/dist/StepIconList.svelte +24 -31
- package/dist/button/button.svelte +7 -0
- package/dist/button/button.svelte.d.ts +3 -0
- package/dist/data-table/cells/boolean-cell.svelte +1 -1
- package/dist/data-table/cells/currency-cell.svelte +1 -1
- package/dist/data-table/cells/uuid-cell.svelte +17 -0
- package/dist/data-table/cells/uuid-cell.svelte.d.ts +8 -0
- package/dist/data-table/column-definitions.js +3 -3
- package/dist/data-table/create-columns.js +18 -3
- package/dist/data-table/data-table-pagination.svelte +83 -42
- package/dist/data-table/data-table-toolbar.svelte +6 -3
- package/dist/data-table/data-table-toolbar.svelte.d.ts +3 -0
- package/dist/data-table/data-table-types.d.ts +55 -8
- package/dist/data-table/data-table-view-options.svelte +69 -31
- package/dist/data-table/data-table-view-options.svelte.d.ts +2 -0
- package/dist/data-table/data-table.svelte +475 -90
- package/dist/data-table/table-setup.d.ts +4 -0
- package/dist/data-table/table-setup.js +24 -2
- package/dist/data-table/table-styles.d.ts +4 -4
- package/dist/data-table/table-styles.js +30 -11
- package/dist/drawer-dnd-helpers.d.ts +30 -0
- package/dist/drawer-dnd-helpers.js +72 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +4 -0
- package/dist/table/table-cell.svelte +1 -1
- package/dist/table/table-head.svelte +1 -1
- package/dist/table/table-header.svelte +1 -1
- package/dist/table/table-row.svelte +1 -1
- package/dist/table/table.svelte +2 -2
- package/dist/tailwind.theme.css +18 -4
- package/dist/types.d.ts +39 -1
- package/package.json +7 -5
package/dist/BaseDropdown.svelte
CHANGED
|
@@ -4,18 +4,23 @@
|
|
|
4
4
|
import { clickOutside } from './clickOutside.js'
|
|
5
5
|
import { portal } from 'svelte-portal'
|
|
6
6
|
import type { BaseDropdownProps } from './types.js'
|
|
7
|
+
import type { TransitionConfig } from 'svelte/transition'
|
|
7
8
|
|
|
8
9
|
let {
|
|
9
10
|
isOpen = $bindable(false),
|
|
10
11
|
fullWidth = false,
|
|
11
12
|
placement = 'bottom-start',
|
|
12
13
|
matchParentWidth = false,
|
|
14
|
+
usePortal = true,
|
|
13
15
|
class: className = '',
|
|
14
16
|
trigger,
|
|
15
17
|
children,
|
|
16
18
|
...rest
|
|
17
19
|
}: BaseDropdownProps = $props()
|
|
18
20
|
|
|
21
|
+
// Conditional portal action - noop if disabled
|
|
22
|
+
const conditionalPortal = usePortal ? portal : () => {}
|
|
23
|
+
|
|
19
24
|
const middleware = [offset(6), flip(), shift()]
|
|
20
25
|
|
|
21
26
|
if (matchParentWidth) {
|
|
@@ -31,18 +36,51 @@
|
|
|
31
36
|
)
|
|
32
37
|
}
|
|
33
38
|
|
|
39
|
+
let closedFromClickOutside = $state(false)
|
|
40
|
+
|
|
41
|
+
// Create floating actions with strategy based on usePortal
|
|
42
|
+
const strategy = usePortal ? 'absolute' : 'fixed'
|
|
34
43
|
const [floatingRef, floatingContent] = createFloatingActions({
|
|
35
|
-
strategy
|
|
44
|
+
strategy,
|
|
36
45
|
placement,
|
|
37
46
|
middleware
|
|
38
47
|
})
|
|
39
48
|
|
|
40
|
-
|
|
49
|
+
// Custom transition that mimics shadcn style
|
|
50
|
+
function dropdownTransition(
|
|
51
|
+
node: HTMLElement,
|
|
52
|
+
{ duration = 150 }: { duration?: number } = {}
|
|
53
|
+
): TransitionConfig {
|
|
54
|
+
const side = placement.split('-')[0]
|
|
55
|
+
|
|
56
|
+
// Calculate slide direction
|
|
57
|
+
let slideY = 0
|
|
58
|
+
let slideX = 0
|
|
59
|
+
if (side === 'bottom') slideY = -8
|
|
60
|
+
if (side === 'top') slideY = 8
|
|
61
|
+
if (side === 'left') slideX = 8
|
|
62
|
+
if (side === 'right') slideX = -8
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
duration,
|
|
66
|
+
css: (t) => {
|
|
67
|
+
const eased = t * (2 - t) // ease-out
|
|
68
|
+
return `
|
|
69
|
+
opacity: ${eased};
|
|
70
|
+
transform: scale(${0.95 + eased * 0.05}) translate(${slideX * (1 - eased)}px, ${slideY * (1 - eased)}px);
|
|
71
|
+
`
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
41
75
|
|
|
42
76
|
export const toggle = () => {
|
|
43
77
|
isOpen = !isOpen
|
|
44
78
|
}
|
|
45
79
|
|
|
80
|
+
export const close = () => {
|
|
81
|
+
isOpen = false
|
|
82
|
+
}
|
|
83
|
+
|
|
46
84
|
function handleClick(event: MouseEvent) {
|
|
47
85
|
event.stopPropagation()
|
|
48
86
|
if (closedFromClickOutside) return
|
|
@@ -62,7 +100,7 @@
|
|
|
62
100
|
{#if isOpen}
|
|
63
101
|
<div
|
|
64
102
|
class="max-h-40 absolute z-1001"
|
|
65
|
-
use:
|
|
103
|
+
use:conditionalPortal
|
|
66
104
|
use:floatingContent
|
|
67
105
|
use:clickOutside
|
|
68
106
|
onclick_outside={() => {
|
|
@@ -72,6 +110,7 @@
|
|
|
72
110
|
}, 100)
|
|
73
111
|
isOpen = false
|
|
74
112
|
}}
|
|
113
|
+
transition:dropdownTransition={{ duration: 150 }}
|
|
75
114
|
>
|
|
76
115
|
{@render children?.()}
|
|
77
116
|
</div>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { BaseDropdownProps } from './types.js';
|
|
2
2
|
declare const BaseDropdown: import("svelte").Component<BaseDropdownProps, {
|
|
3
3
|
toggle: () => void;
|
|
4
|
+
close: () => void;
|
|
4
5
|
}, "isOpen">;
|
|
5
6
|
type BaseDropdown = ReturnType<typeof BaseDropdown>;
|
|
6
7
|
export default BaseDropdown;
|
|
@@ -1,25 +1,33 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { SortAscending, SortDescending, Preview } from '@invopop/ui-icons'
|
|
2
|
+
import { SortAscending, SortDescending, Preview, Filter, Lock } from '@invopop/ui-icons'
|
|
3
3
|
import type { TableSortBy, DrawerOption, BaseTableHeaderOrderByProps } from './types.js'
|
|
4
4
|
import DrawerContext from './DrawerContext.svelte'
|
|
5
5
|
|
|
6
|
-
let { isActive = false, sortDirection, onOrderBy, onHide }: BaseTableHeaderOrderByProps = $props()
|
|
6
|
+
let { isActive = false, sortDirection, onOrderBy, onHide, onFilter, onFreeze, isFrozen = false, showSortOptions = true, showFilterOption = true }: BaseTableHeaderOrderByProps = $props()
|
|
7
7
|
|
|
8
8
|
let items = $derived([
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
9
|
+
...(showSortOptions ? [
|
|
10
|
+
{
|
|
11
|
+
icon: SortAscending,
|
|
12
|
+
label: 'Sort Ascending',
|
|
13
|
+
value: 'asc',
|
|
14
|
+
selected: isActive && sortDirection === 'asc'
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
icon: SortDescending,
|
|
18
|
+
label: 'Sort Descending',
|
|
19
|
+
value: 'desc',
|
|
20
|
+
selected: isActive && sortDirection === 'desc'
|
|
21
|
+
},
|
|
22
|
+
{ label: '', value: 'sep-1', separator: true }
|
|
23
|
+
] : []),
|
|
24
|
+
...(showFilterOption ? [
|
|
25
|
+
{ icon: Filter, label: 'Filter by column', value: 'filter' },
|
|
26
|
+
{ label: '', value: 'sep-2', separator: true }
|
|
27
|
+
] : []),
|
|
28
|
+
{ icon: Lock, label: isFrozen ? 'Unfreeze column' : 'Freeze column', value: 'freeze' },
|
|
29
|
+
{ label: '', value: 'sep-3', separator: true },
|
|
30
|
+
{ icon: Preview, label: 'Hide column', value: 'hide' }
|
|
23
31
|
] as DrawerOption[])
|
|
24
32
|
</script>
|
|
25
33
|
|
|
@@ -28,6 +36,10 @@
|
|
|
28
36
|
onclick={(e) => {
|
|
29
37
|
if (e === 'hide') {
|
|
30
38
|
onHide?.()
|
|
39
|
+
} else if (e === 'filter') {
|
|
40
|
+
onFilter?.()
|
|
41
|
+
} else if (e === 'freeze') {
|
|
42
|
+
onFreeze?.()
|
|
31
43
|
} else {
|
|
32
44
|
onOrderBy?.(e as TableSortBy)
|
|
33
45
|
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Search, Pulse } from '@invopop/ui-icons'
|
|
3
|
+
import BaseButton from './BaseButton.svelte'
|
|
4
|
+
import InputSearch from './InputSearch.svelte'
|
|
5
|
+
import { clickOutside } from './clickOutside.js'
|
|
6
|
+
import type { ButtonSearchProps } from './types.js'
|
|
7
|
+
|
|
8
|
+
let {
|
|
9
|
+
value = $bindable(''),
|
|
10
|
+
expanded = $bindable(false),
|
|
11
|
+
placeholder = 'Search...',
|
|
12
|
+
size = 'sm',
|
|
13
|
+
loading = false,
|
|
14
|
+
autofocus = false,
|
|
15
|
+
oninput,
|
|
16
|
+
onExpand,
|
|
17
|
+
onCollapse
|
|
18
|
+
}: ButtonSearchProps = $props()
|
|
19
|
+
|
|
20
|
+
let inputSearch: InputSearch | undefined = $state()
|
|
21
|
+
let isLoadingCollapsed = $derived(loading && !expanded)
|
|
22
|
+
|
|
23
|
+
function handleExpand() {
|
|
24
|
+
expanded = true
|
|
25
|
+
onExpand?.()
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function handleClickOutside() {
|
|
29
|
+
if (expanded && value.trim() === '') {
|
|
30
|
+
expanded = false
|
|
31
|
+
onCollapse?.()
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function handleInput(newValue: string) {
|
|
36
|
+
value = newValue
|
|
37
|
+
oninput?.(newValue)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
$effect(() => {
|
|
41
|
+
if (expanded && inputSearch) {
|
|
42
|
+
inputSearch.focus()
|
|
43
|
+
}
|
|
44
|
+
})
|
|
45
|
+
</script>
|
|
46
|
+
|
|
47
|
+
<div
|
|
48
|
+
class="overflow-hidden transition-all duration-150 ease-in-out relative rounded-md"
|
|
49
|
+
class:w-[280px]={expanded}
|
|
50
|
+
class:w-10={!expanded}
|
|
51
|
+
use:clickOutside
|
|
52
|
+
onclick_outside={handleClickOutside}
|
|
53
|
+
>
|
|
54
|
+
<div
|
|
55
|
+
class="w-[280px] transition-opacity duration-100 absolute left-0 top-0"
|
|
56
|
+
class:opacity-0={!expanded}
|
|
57
|
+
class:opacity-100={expanded}
|
|
58
|
+
class:pointer-events-none={!expanded}
|
|
59
|
+
>
|
|
60
|
+
<InputSearch
|
|
61
|
+
bind:this={inputSearch}
|
|
62
|
+
bind:value
|
|
63
|
+
{placeholder}
|
|
64
|
+
{size}
|
|
65
|
+
{loading}
|
|
66
|
+
{autofocus}
|
|
67
|
+
oninput={handleInput}
|
|
68
|
+
/>
|
|
69
|
+
</div>
|
|
70
|
+
<div
|
|
71
|
+
class="transition-opacity duration-100"
|
|
72
|
+
class:opacity-0={expanded}
|
|
73
|
+
class:opacity-100={!expanded}
|
|
74
|
+
class:pointer-events-none={expanded}
|
|
75
|
+
>
|
|
76
|
+
<BaseButton
|
|
77
|
+
icon={isLoadingCollapsed ? Pulse : Search}
|
|
78
|
+
class={isLoadingCollapsed ? 'pulse-icon' : ''}
|
|
79
|
+
onclick={handleExpand}
|
|
80
|
+
/>
|
|
81
|
+
</div>
|
|
82
|
+
</div>
|
package/dist/DatePicker.svelte
CHANGED
|
@@ -3,14 +3,17 @@
|
|
|
3
3
|
import RangeCalendar from './range-calendar/range-calendar.svelte'
|
|
4
4
|
import { parseDate, type DateValue } from '@internationalized/date'
|
|
5
5
|
import type { DateRange } from 'bits-ui'
|
|
6
|
-
import { Icon } from '@steeze-ui/svelte-icon'
|
|
7
|
-
import { Calendar } from '@invopop/ui-icons'
|
|
6
|
+
import { Icon, type IconSource } from '@steeze-ui/svelte-icon'
|
|
8
7
|
import Transition from 'svelte-transition'
|
|
9
8
|
import type { DatePickerProps } from './types'
|
|
10
9
|
import { clickOutside } from './clickOutside'
|
|
11
10
|
import BaseButton from './BaseButton.svelte'
|
|
12
|
-
import { datesFromToday, toCalendarDate } from './helpers'
|
|
11
|
+
import { datesFromToday, toCalendarDate, resolveIcon } from './helpers'
|
|
13
12
|
import { buttonVariants } from './button/button.svelte'
|
|
13
|
+
import { offset, flip, shift } from 'svelte-floating-ui/dom'
|
|
14
|
+
import { createFloatingActions } from 'svelte-floating-ui'
|
|
15
|
+
import { portal } from 'svelte-portal'
|
|
16
|
+
import { cn } from './utils'
|
|
14
17
|
|
|
15
18
|
const {
|
|
16
19
|
startOfThisWeek,
|
|
@@ -110,21 +113,38 @@
|
|
|
110
113
|
|
|
111
114
|
let {
|
|
112
115
|
label = 'Date',
|
|
113
|
-
|
|
116
|
+
placement = 'bottom-start',
|
|
114
117
|
from = '',
|
|
115
118
|
to = '',
|
|
116
119
|
onSelect,
|
|
117
120
|
stackLeft = false,
|
|
118
|
-
stackRight = false
|
|
121
|
+
stackRight = false,
|
|
122
|
+
icon = undefined,
|
|
123
|
+
iconTheme = 'default',
|
|
124
|
+
isOpen = $bindable(false)
|
|
119
125
|
}: DatePickerProps = $props()
|
|
120
126
|
|
|
127
|
+
const [floatingRef, floatingContent] = createFloatingActions({
|
|
128
|
+
strategy: 'absolute',
|
|
129
|
+
placement,
|
|
130
|
+
middleware: [offset(8), flip(), shift()]
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
let resolvedIcon: IconSource | undefined = $state()
|
|
134
|
+
|
|
135
|
+
$effect(() => {
|
|
136
|
+
resolveIcon(icon).then((res) => (resolvedIcon = res))
|
|
137
|
+
})
|
|
138
|
+
|
|
121
139
|
let selectedPeriod = $state('custom')
|
|
122
140
|
let value = $state<DateRange>({
|
|
123
141
|
start: undefined,
|
|
124
142
|
end: undefined
|
|
125
143
|
})
|
|
126
|
-
let
|
|
144
|
+
let selectedLabel = $state(label)
|
|
127
145
|
let isStacked = $derived(stackLeft || stackRight)
|
|
146
|
+
let hasSelectedDates = $derived(value.start !== undefined)
|
|
147
|
+
let hasConfirmedDates = $derived(selectedLabel !== label)
|
|
128
148
|
let styles = $derived(
|
|
129
149
|
isStacked
|
|
130
150
|
? buttonVariants({
|
|
@@ -132,12 +152,11 @@
|
|
|
132
152
|
stackedLeft: stackLeft,
|
|
133
153
|
stackedRight: stackRight
|
|
134
154
|
})
|
|
135
|
-
: clsx({
|
|
155
|
+
: clsx('border backdrop-blur-sm backdrop-filter', {
|
|
136
156
|
'border-border-selected-bold shadow-active': isOpen,
|
|
137
|
-
'border-border-secondary hover:border-border-default-secondary-hover': !isOpen
|
|
157
|
+
'border-border-default-secondary hover:border-border-default-secondary-hover': !isOpen
|
|
138
158
|
})
|
|
139
159
|
)
|
|
140
|
-
let selectedLabel = $state(label)
|
|
141
160
|
|
|
142
161
|
$effect(() => {
|
|
143
162
|
if (!value.end) {
|
|
@@ -147,9 +166,19 @@
|
|
|
147
166
|
|
|
148
167
|
$effect(() => {
|
|
149
168
|
if (from) {
|
|
169
|
+
const startDate = parseDate(from)
|
|
170
|
+
const endDate = to ? parseDate(to) : undefined
|
|
171
|
+
|
|
150
172
|
value = {
|
|
151
|
-
start:
|
|
152
|
-
end:
|
|
173
|
+
start: startDate,
|
|
174
|
+
end: endDate
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Update label directly without calling getLabel() to avoid circular dependency
|
|
178
|
+
if (startDate === endDate) {
|
|
179
|
+
selectedLabel = getDisplayFromValue(startDate)
|
|
180
|
+
} else {
|
|
181
|
+
selectedLabel = `${getDisplayFromValue(startDate)} → ${getDisplayFromValue(endDate)}`
|
|
153
182
|
}
|
|
154
183
|
return
|
|
155
184
|
}
|
|
@@ -190,24 +219,52 @@
|
|
|
190
219
|
|
|
191
220
|
onSelect?.({ from: value.start?.toString() || '', to: value.end?.toString() || '' })
|
|
192
221
|
}
|
|
222
|
+
|
|
223
|
+
// Exposed methods
|
|
224
|
+
export function open() {
|
|
225
|
+
isOpen = true
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
export function close() {
|
|
229
|
+
isOpen = false
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export function toggle() {
|
|
233
|
+
isOpen = !isOpen
|
|
234
|
+
}
|
|
193
235
|
</script>
|
|
194
236
|
|
|
195
237
|
<div>
|
|
196
|
-
<
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
238
|
+
<button
|
|
239
|
+
use:floatingRef
|
|
240
|
+
onclick={() => {
|
|
241
|
+
isOpen = !isOpen
|
|
242
|
+
}}
|
|
243
|
+
class="{styles} {isStacked
|
|
244
|
+
? 'h-7 py-1.5'
|
|
245
|
+
: 'py-1.5'} datepicker-trigger flex items-center w-full {resolvedIcon
|
|
246
|
+
? 'pl-7'
|
|
247
|
+
: 'pl-2'} pr-2 text-left rounded-lg bg-background cursor-pointer relative overflow-hidden"
|
|
248
|
+
>
|
|
249
|
+
{#if resolvedIcon}
|
|
250
|
+
<Icon
|
|
251
|
+
src={resolvedIcon}
|
|
252
|
+
theme={iconTheme}
|
|
253
|
+
class="h-4 w-4 absolute top-1.5 left-2 text-foreground-default-secondary"
|
|
254
|
+
/>
|
|
255
|
+
{/if}
|
|
256
|
+
<span
|
|
257
|
+
class={clsx('flex-1 text-base truncate', {
|
|
258
|
+
'text-foreground': hasConfirmedDates,
|
|
259
|
+
'text-foreground-default-secondary': !hasConfirmedDates,
|
|
260
|
+
'font-normal': isStacked && !hasConfirmedDates
|
|
261
|
+
})}
|
|
204
262
|
>
|
|
205
263
|
{selectedLabel}
|
|
206
|
-
</
|
|
207
|
-
|
|
208
|
-
</div>
|
|
264
|
+
</span>
|
|
265
|
+
</button>
|
|
209
266
|
|
|
210
|
-
|
|
267
|
+
{#if isOpen}
|
|
211
268
|
<Transition
|
|
212
269
|
show={isOpen}
|
|
213
270
|
enter="transition ease-out duration-100"
|
|
@@ -219,9 +276,9 @@
|
|
|
219
276
|
>
|
|
220
277
|
<!-- @ts-ignore -->
|
|
221
278
|
<div
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
class="bg-background inline-flex flex-col shadow-lg rounded-xl absolute
|
|
279
|
+
use:portal
|
|
280
|
+
use:floatingContent
|
|
281
|
+
class="bg-background inline-flex flex-col shadow-lg rounded-xl absolute z-1001 border border-border"
|
|
225
282
|
use:clickOutside
|
|
226
283
|
onclick_outside={() => {
|
|
227
284
|
if (!isOpen) return
|
|
@@ -251,5 +308,5 @@
|
|
|
251
308
|
</div>
|
|
252
309
|
</div>
|
|
253
310
|
</Transition>
|
|
254
|
-
|
|
311
|
+
{/if}
|
|
255
312
|
</div>
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import type { DatePickerProps } from './types';
|
|
2
|
-
declare const DatePicker: import("svelte").Component<DatePickerProps, {
|
|
2
|
+
declare const DatePicker: import("svelte").Component<DatePickerProps, {
|
|
3
|
+
open: () => void;
|
|
4
|
+
close: () => void;
|
|
5
|
+
toggle: () => void;
|
|
6
|
+
}, "isOpen">;
|
|
3
7
|
type DatePicker = ReturnType<typeof DatePicker>;
|
|
4
8
|
export default DatePicker;
|