@invopop/popui 0.1.3 → 0.1.4-beta.2
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/AlertDialog.svelte +10 -11
- package/dist/BaseButton.svelte +29 -104
- package/dist/BaseCard.svelte +35 -30
- package/dist/BaseCounter.svelte +11 -8
- package/dist/BaseDropdown.svelte +5 -5
- package/dist/BaseFlag.svelte +5 -3
- package/dist/BaseFlag.svelte.d.ts +1 -0
- package/dist/BaseTable.svelte +16 -16
- package/dist/BaseTable.svelte.d.ts +1 -1
- package/dist/BaseTableActions.svelte +4 -6
- package/dist/BaseTableCellContent.svelte +9 -21
- package/dist/BaseTableCheckbox.svelte +9 -11
- package/dist/BaseTableHeaderContent.svelte +4 -4
- package/dist/BaseTableHeaderOrderBy.svelte +23 -12
- package/dist/BaseTableRow.svelte +12 -10
- package/dist/Breadcrumb.svelte +40 -0
- package/dist/Breadcrumb.svelte.d.ts +4 -0
- package/dist/Breadcrumbs.svelte +5 -30
- package/dist/ButtonFile.svelte +40 -30
- package/dist/ButtonUuidCopy.svelte +6 -3
- package/dist/CardCheckbox.svelte +45 -32
- package/dist/CardCheckbox.svelte.d.ts +1 -1
- package/dist/CardRelation.svelte +12 -13
- package/dist/CompanySelector.svelte +35 -7
- package/dist/CounterWidget.svelte +52 -0
- package/dist/CounterWidget.svelte.d.ts +4 -0
- package/dist/DataListItem.svelte +14 -10
- package/dist/DatePicker.svelte +20 -17
- package/dist/DrawerContext.svelte +207 -15
- package/dist/DrawerContextItem.svelte +50 -50
- package/dist/DrawerContextSeparator.svelte +1 -1
- package/dist/DropdownSelect.svelte +81 -22
- package/dist/DropdownSelectGroup.svelte +15 -0
- package/dist/DropdownSelectGroup.svelte.d.ts +7 -0
- package/dist/EmptyState.svelte +42 -0
- package/dist/EmptyState.svelte.d.ts +4 -0
- package/dist/FeedEvents.svelte +9 -5
- package/dist/FeedIconEvent.svelte +2 -2
- package/dist/FeedIconStatus.svelte +4 -4
- package/dist/FeedItem.svelte +10 -11
- package/dist/FeedItemDetail.svelte +32 -6
- package/dist/FeedViewer.svelte +1 -1
- package/dist/GlobalSearch.svelte +13 -12
- package/dist/InputCheckbox.svelte +2 -5
- package/dist/InputError.svelte +4 -9
- package/dist/InputLabel.svelte +3 -1
- package/dist/InputRadio.svelte +29 -13
- package/dist/InputRadio.svelte.d.ts +1 -1
- package/dist/InputSearch.svelte +8 -8
- package/dist/InputSelect.svelte +32 -31
- package/dist/InputText.svelte +32 -24
- package/dist/InputTextarea.svelte +25 -19
- package/dist/InputToggle.svelte +24 -18
- package/dist/MenuItem.svelte +16 -11
- package/dist/MenuItemCollapsible.svelte +7 -7
- package/dist/Notification.svelte +60 -25
- package/dist/ProfileAvatar.svelte +43 -14
- package/dist/ProgressBar.svelte +42 -0
- package/dist/ProgressBar.svelte.d.ts +4 -0
- package/dist/ProgressBarCircle.svelte +46 -0
- package/dist/ProgressBarCircle.svelte.d.ts +4 -0
- package/dist/SeparatorHorizontal.svelte +2 -2
- package/dist/ShortcutWrapper.svelte +14 -5
- package/dist/StatusLabel.svelte +4 -5
- package/dist/StepIconList.svelte +11 -9
- package/dist/TagBeta.svelte +26 -14
- package/dist/TagProgress.svelte +28 -0
- package/dist/TagProgress.svelte.d.ts +4 -0
- package/dist/TagSearch.svelte +4 -4
- package/dist/TagStatus.svelte +32 -34
- package/dist/TitleMain.svelte +1 -1
- package/dist/TitleSection.svelte +1 -1
- package/dist/UuidCopy.svelte +4 -4
- package/dist/alert-dialog/alert-dialog-action.svelte +8 -4
- package/dist/alert-dialog/alert-dialog-cancel.svelte +7 -3
- package/dist/alert-dialog/alert-dialog-content.svelte +1 -1
- package/dist/alert-dialog/alert-dialog-description.svelte +1 -1
- package/dist/alert-dialog/alert-dialog-footer.svelte +1 -1
- package/dist/alert-dialog/alert-dialog-header.svelte +1 -1
- package/dist/alert-dialog/alert-dialog-overlay.svelte +1 -1
- package/dist/alert-dialog/alert-dialog-title.svelte +1 -1
- package/dist/alert-dialog/alert-dialog-trigger.svelte +4 -2
- package/dist/button/button.svelte +224 -24
- package/dist/button/button.svelte.d.ts +77 -26
- package/dist/clickOutside.d.ts +5 -2
- package/dist/clickOutside.js +9 -3
- package/dist/data-table/cells/boolean-cell.svelte +16 -0
- package/dist/data-table/cells/boolean-cell.svelte.d.ts +8 -0
- package/dist/data-table/cells/currency-cell.svelte +10 -0
- package/dist/data-table/cells/currency-cell.svelte.d.ts +8 -0
- package/dist/data-table/cells/date-cell.svelte +10 -0
- package/dist/data-table/cells/date-cell.svelte.d.ts +8 -0
- package/dist/data-table/cells/tag-cell.svelte +12 -0
- package/dist/data-table/cells/tag-cell.svelte.d.ts +8 -0
- package/dist/data-table/cells/text-cell.svelte +10 -0
- package/dist/data-table/cells/text-cell.svelte.d.ts +8 -0
- package/dist/data-table/column-definitions.d.ts +12 -0
- package/dist/data-table/column-definitions.js +42 -0
- package/dist/data-table/column-sizing-helpers.d.ts +6 -0
- package/dist/data-table/column-sizing-helpers.js +24 -0
- package/dist/data-table/create-columns.d.ts +3 -0
- package/dist/data-table/create-columns.js +50 -0
- package/dist/data-table/data-table-pagination.svelte +173 -0
- package/dist/data-table/data-table-pagination.svelte.d.ts +4 -0
- package/dist/data-table/data-table-svelte.svelte.d.ts +40 -0
- package/dist/data-table/data-table-svelte.svelte.js +111 -0
- package/dist/data-table/data-table-toolbar.svelte +16 -0
- package/dist/data-table/data-table-toolbar.svelte.d.ts +29 -0
- package/dist/data-table/data-table-types.d.ts +75 -0
- package/dist/data-table/data-table-types.js +1 -0
- package/dist/data-table/data-table-view-options.svelte +88 -0
- package/dist/data-table/data-table-view-options.svelte.d.ts +27 -0
- package/dist/data-table/data-table.svelte +323 -0
- package/dist/data-table/data-table.svelte.d.ts +25 -0
- package/dist/data-table/flex-render.svelte +40 -0
- package/dist/data-table/flex-render.svelte.d.ts +33 -0
- package/dist/data-table/index.d.ts +13 -0
- package/dist/data-table/index.js +13 -0
- package/dist/data-table/render-helpers.d.ts +90 -0
- package/dist/data-table/render-helpers.js +99 -0
- package/dist/data-table/table-setup.d.ts +36 -0
- package/dist/data-table/table-setup.js +130 -0
- package/dist/data-table/table-styles.d.ts +17 -0
- package/dist/data-table/table-styles.js +49 -0
- package/dist/helpers.d.ts +1 -0
- package/dist/helpers.js +3 -0
- package/dist/index.d.ts +16 -7
- package/dist/index.js +33 -14
- package/dist/range-calendar/range-calendar-cell.svelte +1 -1
- package/dist/range-calendar/range-calendar-day.svelte +11 -12
- package/dist/range-calendar/range-calendar-head-cell.svelte +1 -1
- package/dist/range-calendar/range-calendar-header.svelte +1 -1
- package/dist/range-calendar/range-calendar-month-select.svelte +1 -1
- package/dist/range-calendar/range-calendar-next-button.svelte +3 -3
- package/dist/range-calendar/range-calendar-prev-button.svelte +3 -3
- package/dist/range-calendar/range-calendar.svelte +1 -1
- package/dist/sonner/index.d.ts +1 -0
- package/dist/sonner/index.js +1 -0
- package/dist/sonner/sonner.svelte +44 -0
- package/dist/sonner/sonner.svelte.d.ts +4 -0
- package/dist/svg/CheckBadge.svelte +18 -0
- package/dist/svg/CheckBadge.svelte.d.ts +26 -0
- package/dist/svg/IconDelivery.svelte +86 -0
- package/dist/svg/IconDelivery.svelte.d.ts +20 -0
- package/dist/svg/IconEmpty.svelte +113 -121
- package/dist/svg/IconOrder.svelte +81 -0
- package/dist/svg/IconOrder.svelte.d.ts +20 -0
- package/dist/svg/IconPayment.svelte +86 -0
- package/dist/svg/IconPayment.svelte.d.ts +20 -0
- package/dist/table/table-body.svelte +5 -1
- package/dist/table/table-cell.svelte +4 -2
- package/dist/table/table-footer.svelte +1 -1
- package/dist/table/table-head.svelte +4 -2
- package/dist/table/table-header.svelte +1 -1
- package/dist/table/table-row.svelte +4 -2
- package/dist/table/table.svelte +2 -2
- package/dist/tabs/tabs-list.svelte +8 -2
- package/dist/tabs/tabs-list.svelte.d.ts +4 -1
- package/dist/tabs/tabs-trigger.svelte +5 -3
- package/dist/tabs/tabs-trigger.svelte.d.ts +4 -1
- package/dist/tailwind.theme.css +998 -0
- package/dist/tooltip/tooltip-content.svelte +2 -2
- package/dist/types.d.ts +76 -50
- package/package.json +20 -10
- package/dist/CounterWorkflow.svelte +0 -19
- package/dist/CounterWorkflow.svelte.d.ts +0 -4
- package/dist/DrawerContextWorkspace.svelte +0 -126
- package/dist/DrawerContextWorkspace.svelte.d.ts +0 -4
- package/dist/EmptyStateIcon.svelte +0 -52
- package/dist/EmptyStateIcon.svelte.d.ts +0 -4
- package/dist/EmptyStateIllustration.svelte +0 -66
- package/dist/EmptyStateIllustration.svelte.d.ts +0 -4
- package/dist/FormLayoutModal.svelte +0 -14
- package/dist/FormLayoutModal.svelte.d.ts +0 -4
- package/dist/ProfileSelector.svelte +0 -41
- package/dist/ProfileSelector.svelte.d.ts +0 -4
- package/dist/SectionLayout.svelte +0 -13
- package/dist/SectionLayout.svelte.d.ts +0 -4
- package/dist/tw.theme.d.ts +0 -171
- package/dist/tw.theme.js +0 -188
package/dist/DatePicker.svelte
CHANGED
|
@@ -115,7 +115,7 @@
|
|
|
115
115
|
onSelect
|
|
116
116
|
}: DatePickerProps = $props()
|
|
117
117
|
|
|
118
|
-
let selectedPeriod = $state('
|
|
118
|
+
let selectedPeriod = $state('custom')
|
|
119
119
|
let value = $state<DateRange>({
|
|
120
120
|
start: undefined,
|
|
121
121
|
end: undefined
|
|
@@ -123,8 +123,8 @@
|
|
|
123
123
|
let isOpen = $state(false)
|
|
124
124
|
let styles = $derived(
|
|
125
125
|
clsx({
|
|
126
|
-
'border-
|
|
127
|
-
'border-
|
|
126
|
+
'border-border-selected-bold shadow-active': isOpen,
|
|
127
|
+
'border-border-secondary hover:border-border-default-secondary-hover': !isOpen
|
|
128
128
|
})
|
|
129
129
|
)
|
|
130
130
|
let selectedLabel = $state(label)
|
|
@@ -143,14 +143,15 @@
|
|
|
143
143
|
}
|
|
144
144
|
return
|
|
145
145
|
}
|
|
146
|
-
value = {
|
|
147
|
-
start: toCalendarDate(startOfThisWeek),
|
|
148
|
-
end: toCalendarDate(endOfThisWeek)
|
|
149
|
-
}
|
|
150
|
-
selectedPeriod = 'this-week'
|
|
151
146
|
})
|
|
152
147
|
|
|
153
148
|
function cancel() {
|
|
149
|
+
value = {
|
|
150
|
+
start: undefined,
|
|
151
|
+
end: undefined
|
|
152
|
+
}
|
|
153
|
+
selectedPeriod = 'custom'
|
|
154
|
+
selectedLabel = label
|
|
154
155
|
isOpen = false
|
|
155
156
|
onSelect?.({ from: '', to: '' })
|
|
156
157
|
}
|
|
@@ -187,11 +188,11 @@
|
|
|
187
188
|
onclick={() => {
|
|
188
189
|
isOpen = !isOpen
|
|
189
190
|
}}
|
|
190
|
-
class="{styles} datepicker-trigger w-full py-1.25 pl-7 pr-
|
|
191
|
+
class="{styles} datepicker-trigger w-full py-1.25 pl-7 pr-2 text-left border border-border-default-secondary rounded-lg text-foreground placeholder-foreground text-base cursor-pointer"
|
|
191
192
|
>
|
|
192
193
|
{selectedLabel}
|
|
193
194
|
</button>
|
|
194
|
-
<Icon src={Calendar} class="h-4 w-4 absolute top-2 left-2 text-
|
|
195
|
+
<Icon src={Calendar} class="h-4 w-4 absolute top-2 left-2 text-foreground-default-secondary" />
|
|
195
196
|
</div>
|
|
196
197
|
|
|
197
198
|
<div class="relative">
|
|
@@ -208,21 +209,21 @@
|
|
|
208
209
|
<div
|
|
209
210
|
class:left-0={position === 'left'}
|
|
210
211
|
class:right-0={position === 'right'}
|
|
211
|
-
class="bg-
|
|
212
|
+
class="bg-background inline-flex flex-col shadow-lg rounded-xl absolute right-0 top-2 z-40 border border-border"
|
|
212
213
|
use:clickOutside
|
|
213
214
|
onclick_outside={() => {
|
|
214
215
|
if (!isOpen) return
|
|
215
216
|
cancel()
|
|
216
217
|
}}
|
|
217
218
|
>
|
|
218
|
-
<div class="flex border-b border-
|
|
219
|
-
<div class="flex flex-col space-y-2 items-start p-3 border-r border-
|
|
219
|
+
<div class="flex border-b border-border min-h-[300px] shadow-calendar">
|
|
220
|
+
<div class="flex flex-col space-y-2 items-start p-3 border-r border-border">
|
|
220
221
|
{#each periods as period}
|
|
221
222
|
<button
|
|
222
223
|
onclick={period.action}
|
|
223
224
|
class="{selectedPeriod === period.slug
|
|
224
|
-
? 'selected-period text-
|
|
225
|
-
: 'text-
|
|
225
|
+
? 'selected-period text-foreground-selected bg-background-selected font-medium'
|
|
226
|
+
: 'text-foreground-default-secondary'} whitespace-nowrap text-base px-2 py-1 tracking-normal rounded-md cursor-pointer"
|
|
226
227
|
>
|
|
227
228
|
{period.label}
|
|
228
229
|
</button>
|
|
@@ -231,8 +232,10 @@
|
|
|
231
232
|
<RangeCalendar bind:value numberOfMonths={2} />
|
|
232
233
|
</div>
|
|
233
234
|
<div class="p-3 flex justify-end items-center space-x-3">
|
|
234
|
-
<BaseButton variant="secondary" onclick={cancel}>Cancel</BaseButton>
|
|
235
|
-
<BaseButton variant="primary" onclick={confirm} disabled={!value.end}
|
|
235
|
+
<BaseButton variant="secondary" size="lg" onclick={cancel}>Cancel</BaseButton>
|
|
236
|
+
<BaseButton variant="primary" size="lg" onclick={confirm} disabled={!value.end}
|
|
237
|
+
>Confirm</BaseButton
|
|
238
|
+
>
|
|
236
239
|
</div>
|
|
237
240
|
</div>
|
|
238
241
|
</Transition>
|
|
@@ -1,46 +1,238 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { DrawerContextProps, DrawerOption } from './types.ts'
|
|
3
3
|
import DrawerContextItem from './DrawerContextItem.svelte'
|
|
4
|
-
import InputSearch from './InputSearch.svelte'
|
|
5
4
|
import DrawerContextSeparator from './DrawerContextSeparator.svelte'
|
|
5
|
+
import EmptyState from './EmptyState.svelte'
|
|
6
|
+
import BaseCounter from './BaseCounter.svelte'
|
|
7
|
+
import { Icon } from '@steeze-ui/svelte-icon'
|
|
8
|
+
import { ChevronRight } from '@steeze-ui/heroicons'
|
|
9
|
+
import { slide } from 'svelte/transition'
|
|
10
|
+
import Sortable from 'sortablejs'
|
|
11
|
+
import { onMount } from 'svelte'
|
|
6
12
|
|
|
7
13
|
let {
|
|
8
14
|
items = $bindable([]),
|
|
9
15
|
multiple = false,
|
|
10
|
-
|
|
16
|
+
draggable = false,
|
|
11
17
|
widthClass = 'w-60',
|
|
12
18
|
onclick,
|
|
13
|
-
onselect
|
|
19
|
+
onselect,
|
|
20
|
+
onreorder,
|
|
21
|
+
children,
|
|
22
|
+
groups
|
|
14
23
|
}: DrawerContextProps = $props()
|
|
15
24
|
|
|
16
25
|
let selectedItems = $derived(items.filter((i) => i.selected))
|
|
26
|
+
let hasGroups = $derived(groups && groups.length > 0)
|
|
27
|
+
let { groupedItems, ungroupedItems } = $derived.by(() => {
|
|
28
|
+
if (!hasGroups) return { groupedItems: new Map(), ungroupedItems: items }
|
|
29
|
+
|
|
30
|
+
const grouped = new Map<string, DrawerOption[]>()
|
|
31
|
+
const ungrouped: DrawerOption[] = []
|
|
32
|
+
|
|
33
|
+
groups!.forEach((group) => {
|
|
34
|
+
grouped.set(group.slug, [])
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
items.forEach((item) => {
|
|
38
|
+
if (item.groupBy && grouped.has(item.groupBy)) {
|
|
39
|
+
grouped.get(item.groupBy)!.push(item)
|
|
40
|
+
} else {
|
|
41
|
+
ungrouped.push(item)
|
|
42
|
+
}
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
return { groupedItems: grouped, ungroupedItems: ungrouped }
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
let openGroups = $state<Record<string, boolean>>({})
|
|
49
|
+
let ungroupedContainer: HTMLElement | null = $state(null)
|
|
50
|
+
let groupContainers: Record<string, HTMLElement | null> = {}
|
|
51
|
+
|
|
52
|
+
$effect(() => {
|
|
53
|
+
if (hasGroups) {
|
|
54
|
+
const selectedItem = items.find((i) => i.selected)
|
|
55
|
+
if (selectedItem?.groupBy && Object.keys(openGroups).length === 0) {
|
|
56
|
+
openGroups = { [selectedItem.groupBy]: true }
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
})
|
|
60
|
+
|
|
17
61
|
$effect(() => {
|
|
18
62
|
onselect?.(selectedItems)
|
|
19
63
|
})
|
|
20
64
|
|
|
65
|
+
function initializeSortable() {
|
|
66
|
+
if (!draggable) return
|
|
67
|
+
|
|
68
|
+
// Initialize sortable for ungrouped items
|
|
69
|
+
if (ungroupedContainer && ungroupedItems.length > 0) {
|
|
70
|
+
Sortable.create(ungroupedContainer, {
|
|
71
|
+
animation: 150,
|
|
72
|
+
handle: '.draggable-item',
|
|
73
|
+
ghostClass: 'opacity-10',
|
|
74
|
+
dragClass: 'cursor-grabbing',
|
|
75
|
+
forceFallback: true,
|
|
76
|
+
onEnd: (event) => {
|
|
77
|
+
if (event.oldIndex !== undefined && event.newIndex !== undefined) {
|
|
78
|
+
const newItems = [...items]
|
|
79
|
+
const ungroupedIndices = items
|
|
80
|
+
.map((item, index) => (!item.groupBy ? index : -1))
|
|
81
|
+
.filter((i) => i !== -1)
|
|
82
|
+
|
|
83
|
+
const fromIndex = ungroupedIndices[event.oldIndex]
|
|
84
|
+
const toIndex = ungroupedIndices[event.newIndex]
|
|
85
|
+
|
|
86
|
+
const [removed] = newItems.splice(fromIndex, 1)
|
|
87
|
+
newItems.splice(toIndex, 0, removed)
|
|
88
|
+
|
|
89
|
+
items = newItems
|
|
90
|
+
onreorder?.(newItems)
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
})
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Initialize sortable for grouped items
|
|
97
|
+
if (hasGroups && groups) {
|
|
98
|
+
groups.forEach((group) => {
|
|
99
|
+
const container = groupContainers[group.slug]
|
|
100
|
+
const groupItems = groupedItems.get(group.slug) || []
|
|
101
|
+
|
|
102
|
+
if (container && groupItems.length > 0) {
|
|
103
|
+
Sortable.create(container, {
|
|
104
|
+
animation: 150,
|
|
105
|
+
handle: '.draggable-item',
|
|
106
|
+
ghostClass: 'opacity-10',
|
|
107
|
+
dragClass: 'cursor-grabbing',
|
|
108
|
+
forceFallback: true,
|
|
109
|
+
onEnd: (event) => {
|
|
110
|
+
if (event.oldIndex !== undefined && event.newIndex !== undefined) {
|
|
111
|
+
const newItems = [...items]
|
|
112
|
+
const groupedIndices = items
|
|
113
|
+
.map((item, index) => (item.groupBy === group.slug ? index : -1))
|
|
114
|
+
.filter((i) => i !== -1)
|
|
115
|
+
|
|
116
|
+
const fromIndex = groupedIndices[event.oldIndex]
|
|
117
|
+
const toIndex = groupedIndices[event.newIndex]
|
|
118
|
+
|
|
119
|
+
const [removed] = newItems.splice(fromIndex, 1)
|
|
120
|
+
newItems.splice(toIndex, 0, removed)
|
|
121
|
+
|
|
122
|
+
items = newItems
|
|
123
|
+
onreorder?.(newItems)
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
})
|
|
127
|
+
}
|
|
128
|
+
})
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
onMount(() => {
|
|
133
|
+
if (draggable) {
|
|
134
|
+
// Small delay to ensure DOM is ready
|
|
135
|
+
setTimeout(initializeSortable, 100)
|
|
136
|
+
}
|
|
137
|
+
})
|
|
138
|
+
|
|
21
139
|
function updateItem(item: DrawerOption) {
|
|
22
140
|
items = items.map((i) => {
|
|
23
141
|
if (i.value === item.value) return item
|
|
24
142
|
return i
|
|
25
143
|
})
|
|
26
144
|
}
|
|
145
|
+
|
|
146
|
+
function toggleGroup(groupSlug: string) {
|
|
147
|
+
openGroups = openGroups[groupSlug] ? {} : { [groupSlug]: true }
|
|
148
|
+
|
|
149
|
+
// Reinitialize sortable when a group is toggled
|
|
150
|
+
if (draggable) {
|
|
151
|
+
setTimeout(initializeSortable, 100)
|
|
152
|
+
}
|
|
153
|
+
}
|
|
27
154
|
</script>
|
|
28
155
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
{
|
|
33
|
-
<div class
|
|
34
|
-
<
|
|
156
|
+
{#snippet drawerItem(item: DrawerOption)}
|
|
157
|
+
{#if item.separator}
|
|
158
|
+
<DrawerContextSeparator />
|
|
159
|
+
{:else}
|
|
160
|
+
<div class:px-1={!item.groupBy} class:draggable-item={draggable} class:cursor-grab={draggable}>
|
|
161
|
+
<DrawerContextItem {item} {multiple} {onclick} onchange={updateItem} />
|
|
35
162
|
</div>
|
|
36
163
|
{/if}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
164
|
+
{/snippet}
|
|
165
|
+
|
|
166
|
+
<div
|
|
167
|
+
class="{widthClass} border border-border rounded-2xl shadow-lg bg-background flex flex-col py-1 max-h-[568px] list-none"
|
|
168
|
+
>
|
|
169
|
+
{@render children?.()}
|
|
170
|
+
|
|
171
|
+
{#if hasGroups}
|
|
172
|
+
{#each groups as group, index}
|
|
173
|
+
{@const groupItems = groupedItems.get(group.slug) || []}
|
|
174
|
+
{@const isLastGroup = index === groups!.length - 1}
|
|
175
|
+
{@const isOpen = openGroups[group.slug]}
|
|
176
|
+
{@const hasOpenGroup = Object.values(openGroups).some((v) => v)}
|
|
177
|
+
<div
|
|
178
|
+
class="px-1"
|
|
179
|
+
class:flex-1={isOpen}
|
|
180
|
+
class:flex={isOpen}
|
|
181
|
+
class:flex-col={isOpen}
|
|
182
|
+
class:min-h-0={isOpen}
|
|
183
|
+
class:flex-shrink-0={!isOpen && hasOpenGroup}
|
|
184
|
+
>
|
|
185
|
+
<button
|
|
186
|
+
class="cursor-pointer flex items-center justify-between h-8 pl-2.5 pr-2.5 py-2.5 text-base font-medium text-foreground-default-secondary w-full hover:bg-background-default-secondary rounded-lg overflow-clip flex-shrink-0"
|
|
187
|
+
onclick={() => toggleGroup(group.slug)}
|
|
188
|
+
>
|
|
189
|
+
<div class="flex items-center gap-1.5">
|
|
190
|
+
<span>{group.label}</span>
|
|
191
|
+
<Icon
|
|
192
|
+
src={ChevronRight}
|
|
193
|
+
class="size-3 text-icon-default-secondary transition-all transform {isOpen
|
|
194
|
+
? 'rotate-90'
|
|
195
|
+
: ''}"
|
|
196
|
+
/>
|
|
197
|
+
</div>
|
|
198
|
+
{#if groupItems.length}
|
|
199
|
+
<BaseCounter value={groupItems.length} />
|
|
200
|
+
{/if}
|
|
201
|
+
</button>
|
|
202
|
+
|
|
203
|
+
{#if isOpen}
|
|
204
|
+
<div
|
|
205
|
+
class="w-full overflow-y-auto flex-1 min-h-0"
|
|
206
|
+
transition:slide={{ duration: 200 }}
|
|
207
|
+
bind:this={groupContainers[group.slug]}
|
|
208
|
+
>
|
|
209
|
+
{#if !groupItems.length}
|
|
210
|
+
<div class="px-1 pt-1 pb-5">
|
|
211
|
+
<EmptyState
|
|
212
|
+
iconSource={group.emptyIcon}
|
|
213
|
+
title={group.emptyTitle || 'No items here'}
|
|
214
|
+
description={group.emptyDescription || 'Add items to get started'}
|
|
215
|
+
/>
|
|
216
|
+
</div>
|
|
217
|
+
{:else}
|
|
218
|
+
{#each groupItems as item}
|
|
219
|
+
{@render drawerItem(item)}
|
|
220
|
+
{/each}
|
|
221
|
+
{/if}
|
|
222
|
+
</div>
|
|
223
|
+
{/if}
|
|
224
|
+
</div>
|
|
225
|
+
{#if !isLastGroup}
|
|
40
226
|
<DrawerContextSeparator />
|
|
41
|
-
{:else}
|
|
42
|
-
<DrawerContextItem {item} {multiple} {onclick} onchange={updateItem} />
|
|
43
227
|
{/if}
|
|
44
228
|
{/each}
|
|
45
|
-
|
|
229
|
+
{/if}
|
|
230
|
+
|
|
231
|
+
{#if ungroupedItems.length}
|
|
232
|
+
<div class="flex-shrink-0 overflow-y-auto max-h-[564px]" bind:this={ungroupedContainer}>
|
|
233
|
+
{#each ungroupedItems as item (item.value)}
|
|
234
|
+
{@render drawerItem(item)}
|
|
235
|
+
{/each}
|
|
236
|
+
</div>
|
|
237
|
+
{/if}
|
|
46
238
|
</div>
|
|
@@ -2,57 +2,54 @@
|
|
|
2
2
|
import type { DrawerContextItemProps } from './types.ts'
|
|
3
3
|
import InputCheckbox from './InputCheckbox.svelte'
|
|
4
4
|
import { Icon } from '@steeze-ui/svelte-icon'
|
|
5
|
-
import { onMount } from 'svelte'
|
|
6
|
-
import { Success
|
|
7
|
-
import ProfileAvatar from './ProfileAvatar.svelte'
|
|
5
|
+
import { onMount, onDestroy } from 'svelte'
|
|
6
|
+
import { Success } from '@invopop/ui-icons'
|
|
8
7
|
import clsx from 'clsx'
|
|
9
8
|
import BaseFlag from './BaseFlag.svelte'
|
|
10
9
|
import { getCountryName } from './helpers.js'
|
|
11
10
|
import TagStatus from './TagStatus.svelte'
|
|
11
|
+
import ProfileAvatar from './ProfileAvatar.svelte'
|
|
12
12
|
|
|
13
13
|
let {
|
|
14
14
|
multiple = false,
|
|
15
15
|
item = $bindable(),
|
|
16
16
|
scrollIfSelected = false,
|
|
17
|
-
workspace = false,
|
|
18
17
|
onchange,
|
|
19
18
|
onclick
|
|
20
19
|
}: DrawerContextItemProps = $props()
|
|
21
20
|
|
|
22
21
|
let el: HTMLElement | undefined = $state()
|
|
23
22
|
|
|
24
|
-
let hasIcon = $derived(item.icon || workspace)
|
|
25
|
-
|
|
26
23
|
let styles = $derived(
|
|
27
24
|
clsx(
|
|
28
|
-
|
|
29
|
-
{ '
|
|
30
|
-
{
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
25
|
+
'px-2 py-1.5 space-x-1.5',
|
|
26
|
+
{ 'bg-background-selected': item?.selected && !multiple },
|
|
27
|
+
{
|
|
28
|
+
'group-hover:bg-background-default-secondary':
|
|
29
|
+
(!item?.selected && !item?.disabled) || multiple
|
|
30
|
+
}
|
|
34
31
|
)
|
|
35
32
|
)
|
|
33
|
+
|
|
36
34
|
let labelStyles = $derived(
|
|
37
35
|
clsx(
|
|
38
|
-
{ 'text-
|
|
39
|
-
{ 'text-
|
|
40
|
-
{ '
|
|
41
|
-
{ 'tracking-normal': !workspace }
|
|
36
|
+
{ 'text-foreground-critical': item?.destructive },
|
|
37
|
+
{ 'text-foreground': !item?.destructive },
|
|
38
|
+
{ 'opacity-30': item?.locked }
|
|
42
39
|
)
|
|
43
40
|
)
|
|
44
|
-
let title = $derived(item.label.length > 25 ? item.label : undefined)
|
|
41
|
+
let title = $derived(item?.label && item.label.length > 25 ? item.label : undefined)
|
|
45
42
|
|
|
46
43
|
onMount(() => {
|
|
47
|
-
if (
|
|
48
|
-
|
|
49
|
-
if (item.selected) {
|
|
44
|
+
if (scrollIfSelected && item?.selected) {
|
|
50
45
|
el?.scrollIntoView()
|
|
51
46
|
}
|
|
52
47
|
})
|
|
53
48
|
|
|
54
49
|
function handleClick(event: MouseEvent) {
|
|
55
50
|
event.stopPropagation()
|
|
51
|
+
if (!item) return
|
|
52
|
+
|
|
56
53
|
if (multiple) {
|
|
57
54
|
item.selected = !item.selected
|
|
58
55
|
onchange?.(item)
|
|
@@ -64,49 +61,52 @@
|
|
|
64
61
|
|
|
65
62
|
<button
|
|
66
63
|
bind:this={el}
|
|
67
|
-
class="w-full
|
|
68
|
-
disabled={item
|
|
64
|
+
class="cursor-pointer w-full disabled:opacity-30 group"
|
|
65
|
+
disabled={item?.disabled}
|
|
69
66
|
onclick={handleClick}
|
|
70
67
|
>
|
|
71
|
-
<div class="{styles} rounded pr-2 flex items-center justify-start w-full">
|
|
72
|
-
{#if
|
|
73
|
-
<ProfileAvatar name={item
|
|
74
|
-
{:else if item
|
|
68
|
+
<div class="{styles} rounded-md pr-2 flex items-center justify-start w-full">
|
|
69
|
+
{#if item?.useAvatar}
|
|
70
|
+
<ProfileAvatar name={item?.label || ''} picture={item?.picture || ''} variant="sm" />
|
|
71
|
+
{:else if item?.picture}
|
|
72
|
+
<ProfileAvatar name={item?.label || ''} picture={item?.picture} variant="sm" />
|
|
73
|
+
{:else if item?.icon}
|
|
75
74
|
<Icon
|
|
76
75
|
src={item.icon}
|
|
77
|
-
class="w-4 h-4 {item
|
|
78
|
-
? 'text-
|
|
79
|
-
: item
|
|
76
|
+
class="w-4 h-4 {item?.destructive
|
|
77
|
+
? 'text-icon-critical'
|
|
78
|
+
: item?.iconClass || 'text-icon'} {item?.locked ? 'opacity-30' : ''}"
|
|
80
79
|
/>
|
|
81
80
|
{/if}
|
|
82
|
-
<div class="whitespace-nowrap flex-1 text-left flex
|
|
83
|
-
|
|
84
|
-
{
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
<span class="{labelStyles} text-base font-medium truncate">{item.label}</span>
|
|
88
|
-
</span>
|
|
81
|
+
<div class="whitespace-nowrap flex-1 text-left flex items-center space-x-1.5 truncate" {title}>
|
|
82
|
+
{#if item?.color}
|
|
83
|
+
<TagStatus status={item.color} dot />
|
|
84
|
+
{/if}
|
|
85
|
+
<span class="{labelStyles} text-base font-medium truncate">{item?.label || ''}</span>
|
|
89
86
|
|
|
90
|
-
{#if item
|
|
91
|
-
<
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
>{getCountryName(item.country)}</span
|
|
95
|
-
>
|
|
87
|
+
{#if item?.country}
|
|
88
|
+
<BaseFlag country={item.country} />
|
|
89
|
+
<span class="text-xs font-medium text-foreground-default-secondary uppercase">
|
|
90
|
+
{item.country}
|
|
96
91
|
</span>
|
|
97
92
|
{/if}
|
|
98
93
|
</div>
|
|
99
|
-
{#if
|
|
94
|
+
{#if item?.action}
|
|
95
|
+
{@render item.action(item)}
|
|
96
|
+
{:else if multiple}
|
|
100
97
|
<InputCheckbox
|
|
101
|
-
|
|
102
|
-
onchange={() => {
|
|
103
|
-
|
|
98
|
+
checked={item?.selected ?? false}
|
|
99
|
+
onchange={(value) => {
|
|
100
|
+
if (item) {
|
|
101
|
+
item.selected = value
|
|
102
|
+
onchange?.(item)
|
|
103
|
+
}
|
|
104
104
|
}}
|
|
105
105
|
/>
|
|
106
|
-
{:else if item
|
|
107
|
-
<Icon src={Success} class="
|
|
108
|
-
{:else if item
|
|
109
|
-
<Icon src={item.rightIcon} class="
|
|
106
|
+
{:else if item?.selected}
|
|
107
|
+
<Icon src={Success} class="size-4 text-icon-selected" />
|
|
108
|
+
{:else if item?.rightIcon}
|
|
109
|
+
<Icon src={item.rightIcon} class="size-4 text-icon-default-secondary" />
|
|
110
110
|
{/if}
|
|
111
111
|
</div>
|
|
112
112
|
</button>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<li class="bg-
|
|
1
|
+
<li class="bg-border h-px min-h-px w-full my-1"></li>
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import clsx from 'clsx'
|
|
8
8
|
import TagStatus from './TagStatus.svelte'
|
|
9
9
|
import { resolveIcon } from './helpers.js'
|
|
10
|
+
import { buttonVariants } from './button/button.svelte'
|
|
10
11
|
|
|
11
12
|
let {
|
|
12
13
|
value = $bindable(''),
|
|
@@ -17,7 +18,10 @@
|
|
|
17
18
|
multiple = false,
|
|
18
19
|
fullWidth = false,
|
|
19
20
|
widthClass = 'min-w-[160px] max-w-[420px]',
|
|
20
|
-
onSelect
|
|
21
|
+
onSelect,
|
|
22
|
+
stackLeft = false,
|
|
23
|
+
stackRight = false,
|
|
24
|
+
multipleLabel = 'items'
|
|
21
25
|
}: DropdownSelectProps = $props()
|
|
22
26
|
|
|
23
27
|
let selectDropdown: BaseDropdown | undefined = $state()
|
|
@@ -39,20 +43,34 @@
|
|
|
39
43
|
|
|
40
44
|
let selectedItems = $derived(items.filter((i) => i.selected))
|
|
41
45
|
let selectedColor = $derived(!multiple && items.find((i) => i.selected)?.color)
|
|
46
|
+
let selectedColors = $derived(
|
|
47
|
+
multiple ? selectedItems.filter((i) => i.color).map((i) => i.color) : []
|
|
48
|
+
)
|
|
49
|
+
let hasMultipleColors = $derived(multiple && selectedColors.length > 0)
|
|
42
50
|
let selectedIcon = $derived(!multiple && items.find((i) => i.selected)?.icon)
|
|
43
51
|
let selectedIconColor = $derived(
|
|
44
|
-
(!multiple && items.find((i) => i.selected)?.iconClass) || 'text-
|
|
52
|
+
(!multiple && items.find((i) => i.selected)?.iconClass) || 'text-foreground-default-secondary'
|
|
45
53
|
)
|
|
46
54
|
let selectedLabel = $derived(
|
|
47
|
-
|
|
48
|
-
|
|
55
|
+
hasMultipleColors && selectedItems.length > 1
|
|
56
|
+
? `${selectedItems.length} ${multipleLabel}`
|
|
57
|
+
: `${selectedItems[0]?.label || ''}${selectedItems.length > 1 && multiple ? ' and more' : ''}` ||
|
|
58
|
+
placeholder
|
|
49
59
|
)
|
|
50
60
|
|
|
61
|
+
let isStacked = $derived(stackLeft || stackRight)
|
|
62
|
+
|
|
51
63
|
let styles = $derived(
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
64
|
+
isStacked
|
|
65
|
+
? buttonVariants({
|
|
66
|
+
variant: 'ghost',
|
|
67
|
+
stackedLeft: stackLeft,
|
|
68
|
+
stackedRight: stackRight
|
|
69
|
+
})
|
|
70
|
+
: clsx('border backdrop-blur-sm backdrop-filter dropdown-select', {
|
|
71
|
+
'border-border-selected-bold shadow-active': isOpen,
|
|
72
|
+
'border-border-default-secondary hover:border-border-default-secondary-hover': !isOpen
|
|
73
|
+
})
|
|
56
74
|
)
|
|
57
75
|
|
|
58
76
|
function handleClick(val: AnyProp) {
|
|
@@ -75,30 +93,71 @@
|
|
|
75
93
|
}
|
|
76
94
|
</script>
|
|
77
95
|
|
|
78
|
-
|
|
96
|
+
{#snippet label()}
|
|
97
|
+
<span
|
|
98
|
+
class="flex-1 text-base truncate {selectedItems.length
|
|
99
|
+
? 'text-foreground'
|
|
100
|
+
: 'text-foreground-default-secondary'}"
|
|
101
|
+
>
|
|
102
|
+
{selectedLabel}
|
|
103
|
+
</span>
|
|
104
|
+
{/snippet}
|
|
105
|
+
|
|
106
|
+
<BaseDropdown
|
|
107
|
+
bind:isOpen
|
|
108
|
+
placement="bottom-start"
|
|
109
|
+
{fullWidth}
|
|
110
|
+
bind:this={selectDropdown}
|
|
111
|
+
class={fullWidth || isStacked ? '' : widthClass}
|
|
112
|
+
>
|
|
79
113
|
{#snippet trigger()}
|
|
80
114
|
<div
|
|
81
|
-
class="{styles}
|
|
115
|
+
class="{styles} flex items-center rounded-lg py-1.5 pl-2 bg-background overflow-hidden w-full h-7"
|
|
116
|
+
class:pr-[28px]={!isStacked}
|
|
117
|
+
class:pr-2={isStacked}
|
|
82
118
|
>
|
|
83
|
-
{#if
|
|
84
|
-
<
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
119
|
+
{#if hasMultipleColors}
|
|
120
|
+
<div class="flex items-center gap-1 flex-1 min-w-0">
|
|
121
|
+
<div class="flex items-center -space-x-0.5">
|
|
122
|
+
{#each selectedColors.slice(0, 3) as color}
|
|
123
|
+
<span class="border-l border-background rounded-xs flex first:border-l-0">
|
|
124
|
+
<TagStatus dot status={color} />
|
|
125
|
+
</span>
|
|
126
|
+
{/each}
|
|
127
|
+
</div>
|
|
128
|
+
{@render label()}
|
|
129
|
+
</div>
|
|
130
|
+
{:else if selectedColor}
|
|
131
|
+
<div class="flex items-center gap-1 flex-1 min-w-0">
|
|
132
|
+
<TagStatus dot status={selectedColor} />
|
|
133
|
+
{@render label()}
|
|
134
|
+
</div>
|
|
135
|
+
{:else if selectedIcon || resolvedIcon}
|
|
136
|
+
<div class="flex items-center gap-1 flex-1 min-w-0">
|
|
137
|
+
{#if selectedIcon}
|
|
138
|
+
<Icon src={selectedIcon} {iconTheme} class="{selectedIconColor} size-4 flex-shrink-0" />
|
|
139
|
+
{:else if resolvedIcon}
|
|
140
|
+
<Icon src={resolvedIcon} {iconTheme} class="text-icon size-4 flex-shrink-0" />
|
|
141
|
+
{/if}
|
|
142
|
+
{@render label()}
|
|
143
|
+
</div>
|
|
144
|
+
{:else}
|
|
145
|
+
{@render label()}
|
|
89
146
|
{/if}
|
|
90
|
-
|
|
91
|
-
<span class="w-full pr-8 text-neutral-800 placeholder-neutral-800 text-base truncate">
|
|
92
|
-
{selectedLabel}
|
|
93
|
-
</span>
|
|
94
147
|
</div>
|
|
95
148
|
{/snippet}
|
|
96
|
-
<DrawerContext
|
|
149
|
+
<DrawerContext
|
|
150
|
+
widthClass="min-w-[256px]"
|
|
151
|
+
{multiple}
|
|
152
|
+
{items}
|
|
153
|
+
onclick={handleClick}
|
|
154
|
+
onselect={handleSelected}
|
|
155
|
+
/>
|
|
97
156
|
</BaseDropdown>
|
|
98
157
|
|
|
99
158
|
<style>
|
|
100
159
|
.dropdown-select {
|
|
101
|
-
background-image: url('data:image/svg+xml;base64,
|
|
160
|
+
background-image: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHJlY3Qgd2lkdGg9IjE2IiBoZWlnaHQ9IjE2IiByeD0iNCIgZmlsbD0icmdiYSg1LCA1LCAzNiwgMC4wNikiLz4KPHBhdGggZD0iTTQuNSA2LjVMOCAxMEwxMS41IDYuNSIgc3Ryb2tlPSIjMGIwYjEwIiBzdHJva2Utd2lkdGg9IjEuMSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+Cjwvc3ZnPg==');
|
|
102
161
|
background-repeat: no-repeat;
|
|
103
162
|
background-position: center right 8px;
|
|
104
163
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte'
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
children: Snippet
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
let { children }: Props = $props()
|
|
9
|
+
</script>
|
|
10
|
+
|
|
11
|
+
<div
|
|
12
|
+
class="flex items-center h-7 rounded-md border border-border-default-secondary divide-x divide-border-default-secondary"
|
|
13
|
+
>
|
|
14
|
+
{@render children()}
|
|
15
|
+
</div>
|