@invopop/popui 0.1.4-beta.4 → 0.1.4-beta.40
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 +16 -4
- package/dist/BaseDropdown.svelte.d.ts +1 -0
- package/dist/BaseTableHeaderContent.svelte +1 -1
- package/dist/BaseTableHeaderOrderBy.svelte +28 -16
- package/dist/ButtonSearch.svelte +81 -0
- package/dist/ButtonSearch.svelte.d.ts +4 -0
- package/dist/DatePicker.svelte +82 -26
- package/dist/DrawerContext.svelte +231 -109
- package/dist/DrawerContextItem.svelte +6 -2
- package/dist/DropdownSelect.svelte +10 -6
- 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/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 +15 -0
- package/dist/data-table/cells/uuid-cell.svelte.d.ts +8 -0
- package/dist/data-table/create-columns.js +17 -3
- package/dist/data-table/data-table-pagination.svelte +83 -42
- package/dist/data-table/data-table-svelte.svelte.js +4 -0
- 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 +37 -7
- 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 +457 -93
- package/dist/data-table/table-setup.d.ts +7 -4
- package/dist/data-table/table-setup.js +29 -8
- package/dist/data-table/table-styles.d.ts +4 -4
- package/dist/data-table/table-styles.js +30 -11
- 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-row.svelte +1 -1
- package/dist/table/table.svelte +2 -2
- package/dist/tailwind.theme.css +14 -0
- package/dist/types.d.ts +38 -1
- package/package.json +4 -5
package/dist/BaseDropdown.svelte
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import { createFloatingActions } from 'svelte-floating-ui'
|
|
4
4
|
import { clickOutside } from './clickOutside.js'
|
|
5
5
|
import { portal } from 'svelte-portal'
|
|
6
|
+
import { slide } from 'svelte/transition'
|
|
6
7
|
import type { BaseDropdownProps } from './types.js'
|
|
7
8
|
|
|
8
9
|
let {
|
|
@@ -10,12 +11,16 @@
|
|
|
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,24 @@
|
|
|
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
|
-
let closedFromClickOutside = $state(false)
|
|
41
|
-
|
|
42
49
|
export const toggle = () => {
|
|
43
50
|
isOpen = !isOpen
|
|
44
51
|
}
|
|
45
52
|
|
|
53
|
+
export const close = () => {
|
|
54
|
+
isOpen = false
|
|
55
|
+
}
|
|
56
|
+
|
|
46
57
|
function handleClick(event: MouseEvent) {
|
|
47
58
|
event.stopPropagation()
|
|
48
59
|
if (closedFromClickOutside) return
|
|
@@ -62,7 +73,7 @@
|
|
|
62
73
|
{#if isOpen}
|
|
63
74
|
<div
|
|
64
75
|
class="max-h-40 absolute z-1001"
|
|
65
|
-
use:
|
|
76
|
+
use:conditionalPortal
|
|
66
77
|
use:floatingContent
|
|
67
78
|
use:clickOutside
|
|
68
79
|
onclick_outside={() => {
|
|
@@ -72,6 +83,7 @@
|
|
|
72
83
|
}, 100)
|
|
73
84
|
isOpen = false
|
|
74
85
|
}}
|
|
86
|
+
transition:slide={{ duration: 100 }}
|
|
75
87
|
>
|
|
76
88
|
{@render children?.()}
|
|
77
89
|
</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,81 @@
|
|
|
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-300 ease-in-out relative rounded-md"
|
|
49
|
+
style={expanded ? 'width: 12rem;' : 'width: 2.5rem;'}
|
|
50
|
+
use:clickOutside
|
|
51
|
+
onclick_outside={handleClickOutside}
|
|
52
|
+
>
|
|
53
|
+
<div
|
|
54
|
+
class="w-48 transition-opacity duration-200 absolute left-0 top-0"
|
|
55
|
+
class:opacity-0={!expanded}
|
|
56
|
+
class:opacity-100={expanded}
|
|
57
|
+
class:pointer-events-none={!expanded}
|
|
58
|
+
>
|
|
59
|
+
<InputSearch
|
|
60
|
+
bind:this={inputSearch}
|
|
61
|
+
bind:value
|
|
62
|
+
{placeholder}
|
|
63
|
+
{size}
|
|
64
|
+
{loading}
|
|
65
|
+
{autofocus}
|
|
66
|
+
oninput={handleInput}
|
|
67
|
+
/>
|
|
68
|
+
</div>
|
|
69
|
+
<div
|
|
70
|
+
class="transition-opacity duration-200"
|
|
71
|
+
class:opacity-0={expanded}
|
|
72
|
+
class:opacity-100={!expanded}
|
|
73
|
+
class:pointer-events-none={expanded}
|
|
74
|
+
>
|
|
75
|
+
<BaseButton
|
|
76
|
+
icon={isLoadingCollapsed ? Pulse : Search}
|
|
77
|
+
class={isLoadingCollapsed ? 'pulse-icon' : ''}
|
|
78
|
+
onclick={handleExpand}
|
|
79
|
+
/>
|
|
80
|
+
</div>
|
|
81
|
+
</div>
|
package/dist/DatePicker.svelte
CHANGED
|
@@ -3,13 +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'
|
|
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'
|
|
13
17
|
|
|
14
18
|
const {
|
|
15
19
|
startOfThisWeek,
|
|
@@ -109,25 +113,50 @@
|
|
|
109
113
|
|
|
110
114
|
let {
|
|
111
115
|
label = 'Date',
|
|
112
|
-
|
|
116
|
+
placement = 'bottom-start',
|
|
113
117
|
from = '',
|
|
114
118
|
to = '',
|
|
115
|
-
onSelect
|
|
119
|
+
onSelect,
|
|
120
|
+
stackLeft = false,
|
|
121
|
+
stackRight = false,
|
|
122
|
+
icon = undefined,
|
|
123
|
+
iconTheme = 'default'
|
|
116
124
|
}: DatePickerProps = $props()
|
|
117
125
|
|
|
126
|
+
const [floatingRef, floatingContent] = createFloatingActions({
|
|
127
|
+
strategy: 'absolute',
|
|
128
|
+
placement,
|
|
129
|
+
middleware: [offset(8), flip(), shift()]
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
let resolvedIcon: IconSource | undefined = $state()
|
|
133
|
+
|
|
134
|
+
$effect(() => {
|
|
135
|
+
resolveIcon(icon).then((res) => (resolvedIcon = res))
|
|
136
|
+
})
|
|
137
|
+
|
|
118
138
|
let selectedPeriod = $state('custom')
|
|
119
139
|
let value = $state<DateRange>({
|
|
120
140
|
start: undefined,
|
|
121
141
|
end: undefined
|
|
122
142
|
})
|
|
123
143
|
let isOpen = $state(false)
|
|
144
|
+
let selectedLabel = $state(label)
|
|
145
|
+
let isStacked = $derived(stackLeft || stackRight)
|
|
146
|
+
let hasSelectedDates = $derived(value.start !== undefined)
|
|
147
|
+
let hasConfirmedDates = $derived(selectedLabel !== label)
|
|
124
148
|
let styles = $derived(
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
149
|
+
isStacked
|
|
150
|
+
? buttonVariants({
|
|
151
|
+
variant: 'ghost',
|
|
152
|
+
stackedLeft: stackLeft,
|
|
153
|
+
stackedRight: stackRight
|
|
154
|
+
})
|
|
155
|
+
: clsx('border backdrop-blur-sm backdrop-filter', {
|
|
156
|
+
'border-border-selected-bold shadow-active': isOpen,
|
|
157
|
+
'border-border-default-secondary hover:border-border-default-secondary-hover': !isOpen
|
|
158
|
+
})
|
|
129
159
|
)
|
|
130
|
-
let selectedLabel = $state(label)
|
|
131
160
|
|
|
132
161
|
$effect(() => {
|
|
133
162
|
if (!value.end) {
|
|
@@ -137,9 +166,19 @@
|
|
|
137
166
|
|
|
138
167
|
$effect(() => {
|
|
139
168
|
if (from) {
|
|
169
|
+
const startDate = parseDate(from)
|
|
170
|
+
const endDate = to ? parseDate(to) : undefined
|
|
171
|
+
|
|
140
172
|
value = {
|
|
141
|
-
start:
|
|
142
|
-
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)}`
|
|
143
182
|
}
|
|
144
183
|
return
|
|
145
184
|
}
|
|
@@ -183,19 +222,36 @@
|
|
|
183
222
|
</script>
|
|
184
223
|
|
|
185
224
|
<div>
|
|
186
|
-
<
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
225
|
+
<button
|
|
226
|
+
use:floatingRef
|
|
227
|
+
onclick={() => {
|
|
228
|
+
isOpen = !isOpen
|
|
229
|
+
}}
|
|
230
|
+
class="{styles} {isStacked
|
|
231
|
+
? 'h-7 py-1.5'
|
|
232
|
+
: 'py-1.5'} datepicker-trigger flex items-center w-full {resolvedIcon
|
|
233
|
+
? 'pl-7'
|
|
234
|
+
: 'pl-2'} pr-2 text-left rounded-lg bg-background cursor-pointer relative overflow-hidden"
|
|
235
|
+
>
|
|
236
|
+
{#if resolvedIcon}
|
|
237
|
+
<Icon
|
|
238
|
+
src={resolvedIcon}
|
|
239
|
+
theme={iconTheme}
|
|
240
|
+
class="h-4 w-4 absolute top-1.5 left-2 text-foreground-default-secondary"
|
|
241
|
+
/>
|
|
242
|
+
{/if}
|
|
243
|
+
<span
|
|
244
|
+
class={clsx('flex-1 text-base truncate', {
|
|
245
|
+
'text-foreground': hasConfirmedDates,
|
|
246
|
+
'text-foreground-default-secondary': !hasConfirmedDates,
|
|
247
|
+
'font-normal': isStacked && !hasConfirmedDates
|
|
248
|
+
})}
|
|
192
249
|
>
|
|
193
250
|
{selectedLabel}
|
|
194
|
-
</
|
|
195
|
-
|
|
196
|
-
</div>
|
|
251
|
+
</span>
|
|
252
|
+
</button>
|
|
197
253
|
|
|
198
|
-
|
|
254
|
+
{#if isOpen}
|
|
199
255
|
<Transition
|
|
200
256
|
show={isOpen}
|
|
201
257
|
enter="transition ease-out duration-100"
|
|
@@ -207,9 +263,9 @@
|
|
|
207
263
|
>
|
|
208
264
|
<!-- @ts-ignore -->
|
|
209
265
|
<div
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
class="bg-background inline-flex flex-col shadow-lg rounded-xl absolute
|
|
266
|
+
use:portal
|
|
267
|
+
use:floatingContent
|
|
268
|
+
class="bg-background inline-flex flex-col shadow-lg rounded-xl absolute z-1001 border border-border"
|
|
213
269
|
use:clickOutside
|
|
214
270
|
onclick_outside={() => {
|
|
215
271
|
if (!isOpen) return
|
|
@@ -239,5 +295,5 @@
|
|
|
239
295
|
</div>
|
|
240
296
|
</div>
|
|
241
297
|
</Transition>
|
|
242
|
-
|
|
298
|
+
{/if}
|
|
243
299
|
</div>
|