@joewinke/jatui 0.1.25 → 0.1.27
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/actions/collapse.d.ts +80 -0
- package/dist/actions/collapse.js +134 -0
- package/dist/actions/railNav.d.ts +167 -0
- package/dist/actions/railNav.js +351 -0
- package/dist/components/AnnotationLayer.svelte +108 -0
- package/dist/components/AnnotationLayer.svelte.d.ts +12 -0
- package/dist/components/AnnotationPanel.svelte +319 -0
- package/dist/components/AnnotationPanel.svelte.d.ts +13 -0
- package/dist/components/AudioWaveform.svelte +701 -0
- package/dist/components/AudioWaveform.svelte.d.ts +19 -0
- package/dist/components/AvailabilityModal.svelte +177 -0
- package/dist/components/AvailabilityModal.svelte.d.ts +14 -0
- package/dist/components/AvatarUpload.svelte +234 -0
- package/dist/components/AvatarUpload.svelte.d.ts +23 -0
- package/dist/components/Badge.svelte +38 -0
- package/dist/components/Badge.svelte.d.ts +14 -0
- package/dist/components/BookingForm.svelte +278 -0
- package/dist/components/BookingForm.svelte.d.ts +37 -0
- package/dist/components/BurndownChart.svelte +778 -0
- package/dist/components/BurndownChart.svelte.d.ts +17 -0
- package/dist/components/Button.svelte +81 -0
- package/dist/components/Button.svelte.d.ts +21 -0
- package/dist/components/CalendarPicker.svelte +284 -0
- package/dist/components/CalendarPicker.svelte.d.ts +22 -0
- package/dist/components/Card.svelte +67 -0
- package/dist/components/Card.svelte.d.ts +17 -0
- package/dist/components/CharacterCounter.svelte +82 -0
- package/dist/components/CharacterCounter.svelte.d.ts +10 -0
- package/dist/components/ChipInput.svelte +609 -0
- package/dist/components/ChipInput.svelte.d.ts +55 -0
- package/dist/components/Collapse.svelte +91 -0
- package/dist/components/Collapse.svelte.d.ts +18 -0
- package/dist/components/ColorSelector.svelte +167 -0
- package/dist/components/ColorSelector.svelte.d.ts +9 -0
- package/dist/components/CommentThread.svelte +773 -0
- package/dist/components/CommentThread.svelte.d.ts +32 -0
- package/dist/components/ConfirmDialog.svelte +348 -0
- package/dist/components/ConfirmDialog.svelte.d.ts +3 -0
- package/dist/components/ConfirmModal.svelte +142 -0
- package/dist/components/ConfirmModal.svelte.d.ts +15 -0
- package/dist/components/ContextMenu.svelte +188 -0
- package/dist/components/ContextMenu.svelte.d.ts +31 -0
- package/dist/components/CountdownTimer.svelte +94 -0
- package/dist/components/CountdownTimer.svelte.d.ts +10 -0
- package/dist/components/DateRangePicker.svelte +194 -0
- package/dist/components/DateRangePicker.svelte.d.ts +10 -0
- package/dist/components/Drawer.svelte +143 -0
- package/dist/components/Drawer.svelte.d.ts +33 -0
- package/dist/components/EmojiPicker.svelte +159 -0
- package/dist/components/EmojiPicker.svelte.d.ts +8 -0
- package/dist/components/EntityPreviewCard.svelte +104 -0
- package/dist/components/EntityPreviewCard.svelte.d.ts +9 -0
- package/dist/components/FileDropzone.svelte +493 -0
- package/dist/components/FileDropzone.svelte.d.ts +40 -0
- package/dist/components/FilePicker.svelte +488 -0
- package/dist/components/FilePicker.svelte.d.ts +20 -0
- package/dist/components/FileThumbnail.svelte +80 -0
- package/dist/components/FileThumbnail.svelte.d.ts +12 -0
- package/dist/components/FilterDropdown.svelte +203 -0
- package/dist/components/FilterDropdown.svelte.d.ts +48 -0
- package/dist/components/FloatingActionBar.svelte +354 -0
- package/dist/components/FloatingActionBar.svelte.d.ts +51 -0
- package/dist/components/GPSTracker.svelte +202 -0
- package/dist/components/GPSTracker.svelte.d.ts +34 -0
- package/dist/components/HunkDiffView.svelte +348 -0
- package/dist/components/HunkDiffView.svelte.d.ts +9 -0
- package/dist/components/ImageLightbox.svelte +274 -0
- package/dist/components/ImageLightbox.svelte.d.ts +25 -0
- package/dist/components/ImageUpload.svelte +147 -0
- package/dist/components/ImageUpload.svelte.d.ts +10 -0
- package/dist/components/InlineEdit.svelte +291 -0
- package/dist/components/InlineEdit.svelte.d.ts +45 -0
- package/dist/components/InputDialog.svelte +327 -0
- package/dist/components/InputDialog.svelte.d.ts +3 -0
- package/dist/components/KeyboardShortcutsOverlay.svelte +296 -0
- package/dist/components/KeyboardShortcutsOverlay.svelte.d.ts +42 -0
- package/dist/components/LazyImage.svelte +123 -0
- package/dist/components/LazyImage.svelte.d.ts +14 -0
- package/dist/components/LinkShortener.svelte +274 -0
- package/dist/components/LinkShortener.svelte.d.ts +27 -0
- package/dist/components/LoadingSpinner.svelte +106 -0
- package/dist/components/LoadingSpinner.svelte.d.ts +21 -0
- package/dist/components/LocationMap.svelte +186 -0
- package/dist/components/LocationMap.svelte.d.ts +11 -0
- package/dist/components/MapView.svelte +341 -0
- package/dist/components/MapView.svelte.d.ts +20 -0
- package/dist/components/MarkupEditor.svelte +485 -0
- package/dist/components/MarkupEditor.svelte.d.ts +10 -0
- package/dist/components/MarkupOverlay.svelte +55 -0
- package/dist/components/MarkupOverlay.svelte.d.ts +8 -0
- package/dist/components/MediaWorkbench.svelte +871 -0
- package/dist/components/MediaWorkbench.svelte.d.ts +9 -0
- package/dist/components/MilestoneCard.svelte +98 -0
- package/dist/components/MilestoneCard.svelte.d.ts +16 -0
- package/dist/components/MilestoneTimeline.svelte +91 -0
- package/dist/components/MilestoneTimeline.svelte.d.ts +15 -0
- package/dist/components/Modal.svelte +244 -0
- package/dist/components/Modal.svelte.d.ts +35 -0
- package/dist/components/PDFViewer.svelte +105 -0
- package/dist/components/PDFViewer.svelte.d.ts +9 -0
- package/dist/components/PdfThumbnail.svelte +63 -0
- package/dist/components/PdfThumbnail.svelte.d.ts +9 -0
- package/dist/components/PhoneInput.svelte +212 -0
- package/dist/components/PhoneInput.svelte.d.ts +25 -0
- package/dist/components/ResizableDivider.svelte +307 -0
- package/dist/components/ResizableDivider.svelte.d.ts +26 -0
- package/dist/components/ResizablePanel.svelte +305 -0
- package/dist/components/ResizablePanel.svelte.d.ts +18 -0
- package/dist/components/SearchDropdown.svelte +686 -0
- package/dist/components/SearchDropdown.svelte.d.ts +40 -0
- package/dist/components/SelectInput.svelte +237 -0
- package/dist/components/SelectInput.svelte.d.ts +26 -0
- package/dist/components/SidebarUserFooter.svelte +34 -0
- package/dist/components/SidebarUserFooter.svelte.d.ts +16 -0
- package/dist/components/SignaturePad.svelte +175 -0
- package/dist/components/SignaturePad.svelte.d.ts +17 -0
- package/dist/components/SmartImageEditor.svelte +720 -0
- package/dist/components/SmartImageEditor.svelte.d.ts +24 -0
- package/dist/components/SortDropdown.svelte +156 -0
- package/dist/components/SortDropdown.svelte.d.ts +40 -0
- package/dist/components/Sparkline.svelte +116 -0
- package/dist/components/Sparkline.svelte.d.ts +12 -0
- package/dist/components/SpeechForm.svelte +114 -0
- package/dist/components/SpeechForm.svelte.d.ts +17 -0
- package/dist/components/StatusBadge.svelte +157 -0
- package/dist/components/StatusBadge.svelte.d.ts +24 -0
- package/dist/components/TaskTypeIcon.svelte +54 -0
- package/dist/components/TaskTypeIcon.svelte.d.ts +17 -0
- package/dist/components/TextArea.svelte +162 -0
- package/dist/components/TextArea.svelte.d.ts +30 -0
- package/dist/components/TextInput.svelte +131 -0
- package/dist/components/TextInput.svelte.d.ts +29 -0
- package/dist/components/ThemeSelector.svelte +206 -0
- package/dist/components/ThemeSelector.svelte.d.ts +14 -0
- package/dist/components/TimeSlotPicker.svelte +162 -0
- package/dist/components/TimeSlotPicker.svelte.d.ts +18 -0
- package/dist/components/UserAvatar.svelte +72 -0
- package/dist/components/UserAvatar.svelte.d.ts +11 -0
- package/dist/components/VariablePicker.svelte +170 -0
- package/dist/components/VariablePicker.svelte.d.ts +40 -0
- package/dist/components/VoicePlayer.svelte +422 -0
- package/dist/components/VoicePlayer.svelte.d.ts +18 -0
- package/dist/components/linked-columns/LinkedColumns.svelte +526 -0
- package/dist/components/linked-columns/LinkedColumns.svelte.d.ts +130 -0
- package/dist/components/markup.d.ts +47 -0
- package/dist/components/markup.js +201 -0
- package/dist/components/messaging/Avatar.svelte +81 -0
- package/dist/components/messaging/Avatar.svelte.d.ts +11 -0
- package/dist/components/messaging/ChannelInfoModal.svelte +163 -0
- package/dist/components/messaging/ChannelInfoModal.svelte.d.ts +18 -0
- package/dist/components/messaging/ChannelList.svelte +107 -0
- package/dist/components/messaging/ChannelList.svelte.d.ts +11 -0
- package/dist/components/messaging/ChannelMemberAvatarStack.svelte +69 -0
- package/dist/components/messaging/ChannelMemberAvatarStack.svelte.d.ts +11 -0
- package/dist/components/messaging/ChannelMembersModal.svelte +182 -0
- package/dist/components/messaging/ChannelMembersModal.svelte.d.ts +16 -0
- package/dist/components/messaging/CreateChannelModal.svelte +190 -0
- package/dist/components/messaging/CreateChannelModal.svelte.d.ts +14 -0
- package/dist/components/messaging/DirectMessageList.svelte +145 -0
- package/dist/components/messaging/DirectMessageList.svelte.d.ts +12 -0
- package/dist/components/messaging/EmojiSelector.svelte +261 -0
- package/dist/components/messaging/EmojiSelector.svelte.d.ts +19 -0
- package/dist/components/messaging/MentionAutocomplete.svelte +193 -0
- package/dist/components/messaging/MentionAutocomplete.svelte.d.ts +17 -0
- package/dist/components/messaging/MessageAttachment.svelte +273 -0
- package/dist/components/messaging/MessageAttachment.svelte.d.ts +13 -0
- package/dist/components/messaging/MessageAttachmentUpload.svelte +243 -0
- package/dist/components/messaging/MessageAttachmentUpload.svelte.d.ts +19 -0
- package/dist/components/messaging/MessageInput.svelte +452 -0
- package/dist/components/messaging/MessageInput.svelte.d.ts +28 -0
- package/dist/components/messaging/MessageItem.svelte +341 -0
- package/dist/components/messaging/MessageItem.svelte.d.ts +41 -0
- package/dist/components/messaging/MessageThread.svelte +306 -0
- package/dist/components/messaging/MessageThread.svelte.d.ts +30 -0
- package/dist/components/messaging/NotificationSettingsModal.svelte +234 -0
- package/dist/components/messaging/NotificationSettingsModal.svelte.d.ts +13 -0
- package/dist/components/messaging/QuotedMessageDisplay.svelte +123 -0
- package/dist/components/messaging/QuotedMessageDisplay.svelte.d.ts +10 -0
- package/dist/components/messaging/StartDMModal.svelte +100 -0
- package/dist/components/messaging/StartDMModal.svelte.d.ts +14 -0
- package/dist/components/messaging/ThreadPanel.svelte +153 -0
- package/dist/components/messaging/ThreadPanel.svelte.d.ts +16 -0
- package/dist/components/pipeline/DESIGN.md +361 -0
- package/dist/components/pipeline/Pipeline.svelte +391 -0
- package/dist/components/pipeline/Pipeline.svelte.d.ts +28 -0
- package/dist/components/pipeline/PipelineCard.svelte +94 -0
- package/dist/components/pipeline/PipelineCard.svelte.d.ts +13 -0
- package/dist/components/pipeline/PipelineColumn.svelte +163 -0
- package/dist/components/pipeline/PipelineColumn.svelte.d.ts +30 -0
- package/dist/components/replay/ChapterTimeline.svelte +326 -0
- package/dist/components/replay/ChapterTimeline.svelte.d.ts +39 -0
- package/dist/components/session-nav/transcriptModel.d.ts +132 -0
- package/dist/components/session-nav/transcriptModel.js +285 -0
- package/dist/data/emojis.d.ts +18 -0
- package/dist/data/emojis.js +1196 -0
- package/dist/index.d.ts +142 -0
- package/dist/index.js +142 -0
- package/dist/stores/confirmDialog.svelte.d.ts +21 -0
- package/dist/stores/confirmDialog.svelte.js +31 -0
- package/dist/stores/inputDialog.svelte.d.ts +24 -0
- package/dist/stores/inputDialog.svelte.js +32 -0
- package/dist/styles/rail.css +63 -0
- package/dist/types/annotation.d.ts +32 -0
- package/dist/types/annotation.js +3 -0
- package/dist/types/booking.d.ts +115 -0
- package/dist/types/booking.js +24 -0
- package/dist/types/comments.d.ts +65 -0
- package/dist/types/comments.js +22 -0
- package/dist/types/entityPreview.d.ts +42 -0
- package/dist/types/entityPreview.js +10 -0
- package/dist/types/filePicker.d.ts +15 -0
- package/dist/types/filePicker.js +1 -0
- package/dist/types/googleMaps.d.ts +51 -0
- package/dist/types/maps.d.ts +43 -0
- package/dist/types/maps.js +4 -0
- package/dist/types/messaging.d.ts +282 -0
- package/dist/types/messaging.js +100 -0
- package/dist/types/milestone.d.ts +20 -0
- package/dist/types/milestone.js +7 -0
- package/dist/types/pipeline.d.ts +115 -0
- package/dist/types/pipeline.js +15 -0
- package/dist/types/smartImageEditor.d.ts +42 -0
- package/dist/types/smartImageEditor.js +1 -0
- package/dist/types/templateVars.d.ts +34 -0
- package/dist/types/templateVars.js +12 -0
- package/dist/utils/currency.d.ts +8 -0
- package/dist/utils/currency.js +17 -0
- package/dist/utils/daisyuiColors.d.ts +37 -0
- package/dist/utils/daisyuiColors.js +152 -0
- package/dist/utils/dateFormatters.d.ts +69 -0
- package/dist/utils/dateFormatters.js +199 -0
- package/dist/utils/googleMapsLoader.d.ts +19 -0
- package/dist/utils/googleMapsLoader.js +121 -0
- package/dist/utils/mentionParser.d.ts +67 -0
- package/dist/utils/mentionParser.js +132 -0
- package/dist/utils/phone.d.ts +13 -0
- package/dist/utils/phone.js +67 -0
- package/dist/utils/phoneFormat.d.ts +26 -0
- package/dist/utils/phoneFormat.js +69 -0
- package/dist/utils/taskUtils.d.ts +37 -0
- package/dist/utils/taskUtils.js +71 -0
- package/package.json +3 -2
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* FilterDropdown Component
|
|
4
|
+
* Reusable multi-select filter component for filter bars
|
|
5
|
+
*
|
|
6
|
+
* Supports two modes:
|
|
7
|
+
* - dropdown: Click button to show options in dropdown menu (default)
|
|
8
|
+
* - inline: Options displayed inline without dropdown wrapper
|
|
9
|
+
*
|
|
10
|
+
* Supports two styles:
|
|
11
|
+
* - badge: Clickable badge buttons (default, good for compact filters)
|
|
12
|
+
* - checkbox: Checkbox list in menu format (good for longer lists)
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
interface FilterOption {
|
|
16
|
+
value: string;
|
|
17
|
+
label: string;
|
|
18
|
+
count: number;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface Props {
|
|
22
|
+
/** Label shown on dropdown trigger button */
|
|
23
|
+
label: string;
|
|
24
|
+
/** Available options to select from */
|
|
25
|
+
options: FilterOption[];
|
|
26
|
+
/** Currently selected values */
|
|
27
|
+
selected: Set<string>;
|
|
28
|
+
/** Callback when option is toggled */
|
|
29
|
+
onToggle: (value: string) => void;
|
|
30
|
+
/** Function to get badge color class for a value */
|
|
31
|
+
colorFn?: (value: string, isSelected: boolean) => string;
|
|
32
|
+
/** Text to show when all options are selected */
|
|
33
|
+
allSelectedText?: string;
|
|
34
|
+
/** If true, empty selection means "all" (vs "none") */
|
|
35
|
+
emptyMeansAll?: boolean;
|
|
36
|
+
/** Display mode: 'dropdown' (default) or 'inline' */
|
|
37
|
+
mode?: 'dropdown' | 'inline';
|
|
38
|
+
/** Selection style: 'badge' (default) or 'checkbox' */
|
|
39
|
+
style?: 'badge' | 'checkbox';
|
|
40
|
+
/** Additional CSS class for the container */
|
|
41
|
+
class?: string;
|
|
42
|
+
/** Dropdown menu width class (e.g., 'w-44', 'w-52') */
|
|
43
|
+
menuWidth?: string;
|
|
44
|
+
/** Max height for scrollable content (e.g., 'max-h-60') */
|
|
45
|
+
maxHeight?: string;
|
|
46
|
+
/** Show hover effect on dropdown trigger */
|
|
47
|
+
hoverTrigger?: boolean;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
let {
|
|
51
|
+
label,
|
|
52
|
+
options,
|
|
53
|
+
selected,
|
|
54
|
+
onToggle,
|
|
55
|
+
colorFn = () => 'badge-primary',
|
|
56
|
+
allSelectedText = 'all',
|
|
57
|
+
emptyMeansAll = false,
|
|
58
|
+
mode = 'dropdown',
|
|
59
|
+
style = 'badge',
|
|
60
|
+
class: className = '',
|
|
61
|
+
menuWidth = 'min-w-48',
|
|
62
|
+
maxHeight = '',
|
|
63
|
+
hoverTrigger = true
|
|
64
|
+
}: Props = $props();
|
|
65
|
+
|
|
66
|
+
// Compute display text for the trigger button
|
|
67
|
+
const displayText = $derived.by(() => {
|
|
68
|
+
if (emptyMeansAll && selected.size === 0) {
|
|
69
|
+
return allSelectedText;
|
|
70
|
+
}
|
|
71
|
+
if (selected.size === options.length && options.length > 0) {
|
|
72
|
+
return allSelectedText;
|
|
73
|
+
}
|
|
74
|
+
return String(selected.size);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// Compute badge class for trigger (show primary when filters active)
|
|
78
|
+
const triggerBadgeClass = $derived.by(() => {
|
|
79
|
+
if (emptyMeansAll) {
|
|
80
|
+
return selected.size > 0 ? 'badge-primary' : 'badge-ghost';
|
|
81
|
+
}
|
|
82
|
+
return 'badge-primary';
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
// Handle option toggle
|
|
86
|
+
function handleToggle(value: string) {
|
|
87
|
+
onToggle(value);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Handle keyboard navigation
|
|
91
|
+
function handleKeydown(e: KeyboardEvent, value: string) {
|
|
92
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
93
|
+
e.preventDefault();
|
|
94
|
+
handleToggle(value);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
</script>
|
|
98
|
+
|
|
99
|
+
{#if mode === 'inline'}
|
|
100
|
+
<!-- Inline Mode: No dropdown wrapper, just badge/checkbox grid -->
|
|
101
|
+
<div class="flex flex-wrap gap-1.5 {className}">
|
|
102
|
+
{#each options as opt, index}
|
|
103
|
+
{#if style === 'checkbox'}
|
|
104
|
+
<label class="label cursor-pointer justify-start gap-2">
|
|
105
|
+
<input
|
|
106
|
+
type="checkbox"
|
|
107
|
+
class="checkbox checkbox-sm"
|
|
108
|
+
checked={selected.has(opt.value)}
|
|
109
|
+
onchange={() => handleToggle(opt.value)}
|
|
110
|
+
/>
|
|
111
|
+
<span>{opt.label}</span>
|
|
112
|
+
<span class="text-[0.75rem] opacity-60">({opt.count})</span>
|
|
113
|
+
</label>
|
|
114
|
+
{:else}
|
|
115
|
+
<button
|
|
116
|
+
class="badge badge-sm transition-all duration-200 cursor-pointer {selected.has(opt.value)
|
|
117
|
+
? colorFn(opt.value, true)
|
|
118
|
+
: 'badge-ghost hover:badge-primary/20'}"
|
|
119
|
+
onclick={() => handleToggle(opt.value)}
|
|
120
|
+
onkeydown={(e) => handleKeydown(e, opt.value)}
|
|
121
|
+
>
|
|
122
|
+
{opt.label}
|
|
123
|
+
<span class="ml-1 text-[0.75rem] opacity-60">({opt.count})</span>
|
|
124
|
+
</button>
|
|
125
|
+
{/if}
|
|
126
|
+
{/each}
|
|
127
|
+
</div>
|
|
128
|
+
{:else}
|
|
129
|
+
<!-- Dropdown Mode: Click to show options -->
|
|
130
|
+
<div class="dropdown {hoverTrigger ? 'dropdown-hover' : ''} {className}">
|
|
131
|
+
<!-- Trigger Button -->
|
|
132
|
+
<div
|
|
133
|
+
tabindex="0"
|
|
134
|
+
role="button"
|
|
135
|
+
class="px-2.5 py-1 rounded cursor-pointer transition-all flex items-center gap-1.5 text-[0.8125rem] bg-base-200 border border-base-300 text-base-content/60"
|
|
136
|
+
>
|
|
137
|
+
<span>{label}</span>
|
|
138
|
+
<span
|
|
139
|
+
class="px-1.5 py-0.5 rounded text-[0.75rem] {selected.size > 0 && !(emptyMeansAll && selected.size === 0) ? 'bg-primary/20 text-primary' : 'bg-base-300 text-base-content opacity-60'}"
|
|
140
|
+
>
|
|
141
|
+
{displayText}
|
|
142
|
+
</span>
|
|
143
|
+
<svg
|
|
144
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
145
|
+
fill="none"
|
|
146
|
+
viewBox="0 0 24 24"
|
|
147
|
+
stroke-width="1.5"
|
|
148
|
+
stroke="currentColor"
|
|
149
|
+
class="w-3.5 h-3.5 text-base-content/50"
|
|
150
|
+
>
|
|
151
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 8.25l-7.5 7.5-7.5-7.5" />
|
|
152
|
+
</svg>
|
|
153
|
+
</div>
|
|
154
|
+
|
|
155
|
+
<!-- Dropdown Content -->
|
|
156
|
+
{#if style === 'checkbox'}
|
|
157
|
+
<!-- Checkbox style: Menu with checkboxes -->
|
|
158
|
+
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
|
|
159
|
+
<ul
|
|
160
|
+
tabindex="0"
|
|
161
|
+
class="dropdown-content z-40 menu p-2 shadow rounded-box {menuWidth} {maxHeight ? maxHeight + ' overflow-y-auto' : ''} bg-base-200 border border-base-300"
|
|
162
|
+
>
|
|
163
|
+
{#each options as opt, index}
|
|
164
|
+
<li>
|
|
165
|
+
<label
|
|
166
|
+
class="label cursor-pointer justify-start gap-2 rounded text-base-content/70"
|
|
167
|
+
>
|
|
168
|
+
<input
|
|
169
|
+
type="checkbox"
|
|
170
|
+
class="checkbox checkbox-sm border-base-content/40"
|
|
171
|
+
checked={selected.has(opt.value)}
|
|
172
|
+
onchange={() => handleToggle(opt.value)}
|
|
173
|
+
/>
|
|
174
|
+
<span class="truncate text-[0.8125rem]">{opt.label}</span>
|
|
175
|
+
<span class="text-[0.75rem] text-base-content/45">({opt.count})</span>
|
|
176
|
+
</label>
|
|
177
|
+
</li>
|
|
178
|
+
{/each}
|
|
179
|
+
</ul>
|
|
180
|
+
{:else}
|
|
181
|
+
<!-- Badge style: Grid of clickable badges -->
|
|
182
|
+
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
|
|
183
|
+
<div
|
|
184
|
+
tabindex="0"
|
|
185
|
+
role="menu"
|
|
186
|
+
class="dropdown-content rounded-box p-2 z-40 {menuWidth} mt-1 {maxHeight ? maxHeight + ' overflow-y-auto' : ''} bg-base-200 border border-base-300"
|
|
187
|
+
>
|
|
188
|
+
<div class="flex flex-wrap gap-1.5">
|
|
189
|
+
{#each options as opt, index}
|
|
190
|
+
<button
|
|
191
|
+
class="px-2 py-0.5 rounded text-[0.75rem] transition-all cursor-pointer border {selected.has(opt.value) ? 'bg-primary/20 border-primary/40 text-primary' : 'bg-base-300 border-base-content/20 text-base-content opacity-70 hover:opacity-100'}"
|
|
192
|
+
onclick={() => handleToggle(opt.value)}
|
|
193
|
+
onkeydown={(e) => handleKeydown(e, opt.value)}
|
|
194
|
+
>
|
|
195
|
+
{opt.label}
|
|
196
|
+
<span class="ml-1 text-base-content/50">({opt.count})</span>
|
|
197
|
+
</button>
|
|
198
|
+
{/each}
|
|
199
|
+
</div>
|
|
200
|
+
</div>
|
|
201
|
+
{/if}
|
|
202
|
+
</div>
|
|
203
|
+
{/if}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FilterDropdown Component
|
|
3
|
+
* Reusable multi-select filter component for filter bars
|
|
4
|
+
*
|
|
5
|
+
* Supports two modes:
|
|
6
|
+
* - dropdown: Click button to show options in dropdown menu (default)
|
|
7
|
+
* - inline: Options displayed inline without dropdown wrapper
|
|
8
|
+
*
|
|
9
|
+
* Supports two styles:
|
|
10
|
+
* - badge: Clickable badge buttons (default, good for compact filters)
|
|
11
|
+
* - checkbox: Checkbox list in menu format (good for longer lists)
|
|
12
|
+
*/
|
|
13
|
+
interface FilterOption {
|
|
14
|
+
value: string;
|
|
15
|
+
label: string;
|
|
16
|
+
count: number;
|
|
17
|
+
}
|
|
18
|
+
interface Props {
|
|
19
|
+
/** Label shown on dropdown trigger button */
|
|
20
|
+
label: string;
|
|
21
|
+
/** Available options to select from */
|
|
22
|
+
options: FilterOption[];
|
|
23
|
+
/** Currently selected values */
|
|
24
|
+
selected: Set<string>;
|
|
25
|
+
/** Callback when option is toggled */
|
|
26
|
+
onToggle: (value: string) => void;
|
|
27
|
+
/** Function to get badge color class for a value */
|
|
28
|
+
colorFn?: (value: string, isSelected: boolean) => string;
|
|
29
|
+
/** Text to show when all options are selected */
|
|
30
|
+
allSelectedText?: string;
|
|
31
|
+
/** If true, empty selection means "all" (vs "none") */
|
|
32
|
+
emptyMeansAll?: boolean;
|
|
33
|
+
/** Display mode: 'dropdown' (default) or 'inline' */
|
|
34
|
+
mode?: 'dropdown' | 'inline';
|
|
35
|
+
/** Selection style: 'badge' (default) or 'checkbox' */
|
|
36
|
+
style?: 'badge' | 'checkbox';
|
|
37
|
+
/** Additional CSS class for the container */
|
|
38
|
+
class?: string;
|
|
39
|
+
/** Dropdown menu width class (e.g., 'w-44', 'w-52') */
|
|
40
|
+
menuWidth?: string;
|
|
41
|
+
/** Max height for scrollable content (e.g., 'max-h-60') */
|
|
42
|
+
maxHeight?: string;
|
|
43
|
+
/** Show hover effect on dropdown trigger */
|
|
44
|
+
hoverTrigger?: boolean;
|
|
45
|
+
}
|
|
46
|
+
declare const FilterDropdown: import("svelte").Component<Props, {}, "">;
|
|
47
|
+
type FilterDropdown = ReturnType<typeof FilterDropdown>;
|
|
48
|
+
export default FilterDropdown;
|
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* FloatingActionBar Component
|
|
4
|
+
* Fixed bottom-center bar for bulk selection actions on tables/lists.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* <FloatingActionBar
|
|
8
|
+
* count={selectedTasks.size}
|
|
9
|
+
* {actions}
|
|
10
|
+
* {dropdowns}
|
|
11
|
+
* loading={bulkActionLoading}
|
|
12
|
+
* onClear={clearSelection}
|
|
13
|
+
* />
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { fade } from 'svelte/transition';
|
|
17
|
+
|
|
18
|
+
export interface ActionButton {
|
|
19
|
+
/** Unique key */
|
|
20
|
+
id: string;
|
|
21
|
+
/** Button label */
|
|
22
|
+
label: string;
|
|
23
|
+
/** SVG path string for a 24×24 icon (optional) */
|
|
24
|
+
icon?: string;
|
|
25
|
+
/** Color variant */
|
|
26
|
+
variant?: 'default' | 'primary' | 'danger' | 'warning' | 'success';
|
|
27
|
+
/** Called when clicked */
|
|
28
|
+
onclick: () => void;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface DropdownItem {
|
|
32
|
+
/** Display label */
|
|
33
|
+
label: string;
|
|
34
|
+
/** Optional colored dot (oklch string) */
|
|
35
|
+
dotColor?: string;
|
|
36
|
+
/** Optional SVG snippet rendered before the label */
|
|
37
|
+
iconSnippet?: import('svelte').Snippet;
|
|
38
|
+
/** Called when this item is clicked */
|
|
39
|
+
onclick: () => void;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface ActionDropdown {
|
|
43
|
+
/** Unique key */
|
|
44
|
+
id: string;
|
|
45
|
+
/** Button label */
|
|
46
|
+
label: string;
|
|
47
|
+
/** SVG path string for a 24×24 icon (optional) */
|
|
48
|
+
icon?: string;
|
|
49
|
+
/** Color variant */
|
|
50
|
+
variant?: 'default' | 'primary' | 'info' | 'purple';
|
|
51
|
+
/** Items in the dropdown */
|
|
52
|
+
items: DropdownItem[];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
interface Props {
|
|
56
|
+
/** Number of selected items — bar is hidden when 0 */
|
|
57
|
+
count: number;
|
|
58
|
+
/** Primary action buttons */
|
|
59
|
+
actions?: ActionButton[];
|
|
60
|
+
/** Dropdown menus (open upward from the bar) */
|
|
61
|
+
dropdowns?: ActionDropdown[];
|
|
62
|
+
/** Disables all buttons while true and shows a spinner */
|
|
63
|
+
loading?: boolean;
|
|
64
|
+
/** Called when the "Clear" button is clicked */
|
|
65
|
+
onClear?: () => void;
|
|
66
|
+
/** Label for the selection count (default: "selected") */
|
|
67
|
+
countLabel?: string;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
let {
|
|
71
|
+
count,
|
|
72
|
+
actions = [],
|
|
73
|
+
dropdowns = [],
|
|
74
|
+
loading = false,
|
|
75
|
+
onClear,
|
|
76
|
+
countLabel = 'selected',
|
|
77
|
+
}: Props = $props();
|
|
78
|
+
|
|
79
|
+
let openDropdownId = $state<string | null>(null);
|
|
80
|
+
|
|
81
|
+
// Close dropdown on outside click
|
|
82
|
+
$effect(() => {
|
|
83
|
+
if (!openDropdownId) return;
|
|
84
|
+
function handleClick(e: MouseEvent) {
|
|
85
|
+
if (!(e.target as HTMLElement).closest('.fab-dropdown-wrapper')) {
|
|
86
|
+
openDropdownId = null;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
const timer = setTimeout(() => document.addEventListener('click', handleClick), 0);
|
|
90
|
+
return () => {
|
|
91
|
+
clearTimeout(timer);
|
|
92
|
+
document.removeEventListener('click', handleClick);
|
|
93
|
+
};
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
function variantClass(variant: ActionButton['variant'] | ActionDropdown['variant']): string {
|
|
97
|
+
switch (variant) {
|
|
98
|
+
case 'primary': return 'fab-btn-primary';
|
|
99
|
+
case 'danger': return 'fab-btn-danger';
|
|
100
|
+
case 'warning': return 'fab-btn-warning';
|
|
101
|
+
case 'success': return 'fab-btn-success';
|
|
102
|
+
case 'info': return 'fab-btn-info';
|
|
103
|
+
case 'purple': return 'fab-btn-purple';
|
|
104
|
+
default: return 'fab-btn-default';
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
</script>
|
|
108
|
+
|
|
109
|
+
{#if count > 0}
|
|
110
|
+
<div class="fab" transition:fade={{ duration: 150 }}>
|
|
111
|
+
<span class="fab-count">{count} {countLabel}</span>
|
|
112
|
+
|
|
113
|
+
{#if actions.length > 0}
|
|
114
|
+
<div class="fab-divider"></div>
|
|
115
|
+
{#each actions as action}
|
|
116
|
+
<button
|
|
117
|
+
type="button"
|
|
118
|
+
class="fab-btn {variantClass(action.variant)}"
|
|
119
|
+
onclick={action.onclick}
|
|
120
|
+
disabled={loading}
|
|
121
|
+
>
|
|
122
|
+
{#if action.icon}
|
|
123
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="14" height="14">
|
|
124
|
+
<!-- svelte-ignore a11y_consider_explicit_label -->
|
|
125
|
+
{@html action.icon}
|
|
126
|
+
</svg>
|
|
127
|
+
{/if}
|
|
128
|
+
{action.label}
|
|
129
|
+
</button>
|
|
130
|
+
{/each}
|
|
131
|
+
{/if}
|
|
132
|
+
|
|
133
|
+
{#if dropdowns.length > 0}
|
|
134
|
+
<div class="fab-divider"></div>
|
|
135
|
+
{#each dropdowns as dropdown}
|
|
136
|
+
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
|
|
137
|
+
<div
|
|
138
|
+
class="fab-dropdown-wrapper"
|
|
139
|
+
role="group"
|
|
140
|
+
onclick={(e) => e.stopPropagation()}
|
|
141
|
+
onkeydown={(e) => e.stopPropagation()}
|
|
142
|
+
>
|
|
143
|
+
<button
|
|
144
|
+
type="button"
|
|
145
|
+
class="fab-btn {variantClass(dropdown.variant)}"
|
|
146
|
+
onclick={() => openDropdownId = openDropdownId === dropdown.id ? null : dropdown.id}
|
|
147
|
+
disabled={loading}
|
|
148
|
+
>
|
|
149
|
+
{#if dropdown.icon}
|
|
150
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="14" height="14">
|
|
151
|
+
<!-- svelte-ignore a11y_consider_explicit_label -->
|
|
152
|
+
{@html dropdown.icon}
|
|
153
|
+
</svg>
|
|
154
|
+
{/if}
|
|
155
|
+
{dropdown.label}
|
|
156
|
+
</button>
|
|
157
|
+
{#if openDropdownId === dropdown.id}
|
|
158
|
+
<div class="fab-dropdown" transition:fade={{ duration: 100 }}>
|
|
159
|
+
{#each dropdown.items as item}
|
|
160
|
+
<button
|
|
161
|
+
class="fab-dropdown-item"
|
|
162
|
+
onclick={() => { item.onclick(); openDropdownId = null; }}
|
|
163
|
+
>
|
|
164
|
+
{#if item.dotColor}
|
|
165
|
+
<span class="fab-dot" style="background: {item.dotColor};"></span>
|
|
166
|
+
{/if}
|
|
167
|
+
{#if item.iconSnippet}
|
|
168
|
+
{@render item.iconSnippet()}
|
|
169
|
+
{/if}
|
|
170
|
+
{item.label}
|
|
171
|
+
</button>
|
|
172
|
+
{/each}
|
|
173
|
+
</div>
|
|
174
|
+
{/if}
|
|
175
|
+
</div>
|
|
176
|
+
{/each}
|
|
177
|
+
{/if}
|
|
178
|
+
|
|
179
|
+
{#if onClear}
|
|
180
|
+
<div class="fab-divider"></div>
|
|
181
|
+
<button type="button" class="fab-btn fab-btn-clear" onclick={onClear} disabled={loading}>
|
|
182
|
+
Clear
|
|
183
|
+
</button>
|
|
184
|
+
{/if}
|
|
185
|
+
|
|
186
|
+
{#if loading}
|
|
187
|
+
<div class="fab-spinner"></div>
|
|
188
|
+
{/if}
|
|
189
|
+
</div>
|
|
190
|
+
{/if}
|
|
191
|
+
|
|
192
|
+
<style>
|
|
193
|
+
.fab {
|
|
194
|
+
position: fixed;
|
|
195
|
+
bottom: 1.5rem;
|
|
196
|
+
left: 50%;
|
|
197
|
+
transform: translateX(-50%);
|
|
198
|
+
z-index: 50;
|
|
199
|
+
display: flex;
|
|
200
|
+
align-items: center;
|
|
201
|
+
gap: 0.5rem;
|
|
202
|
+
padding: 0.5rem 0.75rem;
|
|
203
|
+
background: oklch(0.16 0.02 250);
|
|
204
|
+
border: 1px solid oklch(0.30 0.02 250);
|
|
205
|
+
border-radius: 0.75rem;
|
|
206
|
+
box-shadow: 0 8px 32px oklch(0.05 0 0 / 0.6), 0 2px 8px oklch(0.05 0 0 / 0.3);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
.fab-count {
|
|
210
|
+
font-size: 0.8125rem;
|
|
211
|
+
font-weight: 600;
|
|
212
|
+
color: oklch(0.85 0.02 250);
|
|
213
|
+
white-space: nowrap;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
.fab-divider {
|
|
217
|
+
width: 1px;
|
|
218
|
+
height: 1.25rem;
|
|
219
|
+
background: oklch(0.30 0.02 250);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
.fab-btn {
|
|
223
|
+
display: flex;
|
|
224
|
+
align-items: center;
|
|
225
|
+
gap: 0.375rem;
|
|
226
|
+
padding: 0.375rem 0.625rem;
|
|
227
|
+
border: 1px solid transparent;
|
|
228
|
+
border-radius: 0.375rem;
|
|
229
|
+
font-size: 0.75rem;
|
|
230
|
+
font-weight: 500;
|
|
231
|
+
cursor: pointer;
|
|
232
|
+
transition: all 0.15s;
|
|
233
|
+
white-space: nowrap;
|
|
234
|
+
}
|
|
235
|
+
.fab-btn:disabled {
|
|
236
|
+
opacity: 0.5;
|
|
237
|
+
pointer-events: none;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/* Variants */
|
|
241
|
+
.fab-btn-default {
|
|
242
|
+
background: oklch(0.25 0.02 250 / 0.5);
|
|
243
|
+
color: oklch(0.75 0.02 250);
|
|
244
|
+
border-color: oklch(0.35 0.02 250);
|
|
245
|
+
}
|
|
246
|
+
.fab-btn-default:hover { background: oklch(0.30 0.02 250); }
|
|
247
|
+
|
|
248
|
+
.fab-btn-primary {
|
|
249
|
+
background: oklch(0.65 0.18 250 / 0.15);
|
|
250
|
+
color: oklch(0.82 0.14 250);
|
|
251
|
+
border-color: oklch(0.65 0.18 250 / 0.3);
|
|
252
|
+
}
|
|
253
|
+
.fab-btn-primary:hover { background: oklch(0.65 0.18 250 / 0.25); }
|
|
254
|
+
|
|
255
|
+
.fab-btn-danger {
|
|
256
|
+
background: oklch(0.55 0.18 30 / 0.15);
|
|
257
|
+
color: oklch(0.80 0.15 30);
|
|
258
|
+
border-color: oklch(0.55 0.18 30 / 0.3);
|
|
259
|
+
}
|
|
260
|
+
.fab-btn-danger:hover { background: oklch(0.55 0.18 30 / 0.25); }
|
|
261
|
+
|
|
262
|
+
.fab-btn-warning {
|
|
263
|
+
background: oklch(0.75 0.15 85 / 0.12);
|
|
264
|
+
color: oklch(0.80 0.12 85);
|
|
265
|
+
border-color: oklch(0.75 0.15 85 / 0.25);
|
|
266
|
+
}
|
|
267
|
+
.fab-btn-warning:hover { background: oklch(0.75 0.15 85 / 0.22); }
|
|
268
|
+
|
|
269
|
+
.fab-btn-success {
|
|
270
|
+
background: oklch(0.55 0.15 145 / 0.15);
|
|
271
|
+
color: oklch(0.80 0.12 145);
|
|
272
|
+
border-color: oklch(0.55 0.15 145 / 0.3);
|
|
273
|
+
}
|
|
274
|
+
.fab-btn-success:hover { background: oklch(0.55 0.15 145 / 0.25); }
|
|
275
|
+
|
|
276
|
+
.fab-btn-info {
|
|
277
|
+
background: oklch(0.55 0.15 200 / 0.15);
|
|
278
|
+
color: oklch(0.80 0.12 200);
|
|
279
|
+
border-color: oklch(0.55 0.15 200 / 0.3);
|
|
280
|
+
}
|
|
281
|
+
.fab-btn-info:hover { background: oklch(0.55 0.15 200 / 0.25); }
|
|
282
|
+
|
|
283
|
+
.fab-btn-purple {
|
|
284
|
+
background: oklch(0.55 0.15 300 / 0.15);
|
|
285
|
+
color: oklch(0.80 0.12 300);
|
|
286
|
+
border-color: oklch(0.55 0.15 300 / 0.3);
|
|
287
|
+
}
|
|
288
|
+
.fab-btn-purple:hover { background: oklch(0.55 0.15 300 / 0.25); }
|
|
289
|
+
|
|
290
|
+
.fab-btn-clear {
|
|
291
|
+
background: transparent;
|
|
292
|
+
color: oklch(0.65 0.02 250);
|
|
293
|
+
border-color: transparent;
|
|
294
|
+
}
|
|
295
|
+
.fab-btn-clear:hover {
|
|
296
|
+
background: oklch(0.25 0.02 250);
|
|
297
|
+
color: oklch(0.80 0.02 250);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
.fab-spinner {
|
|
301
|
+
width: 14px;
|
|
302
|
+
height: 14px;
|
|
303
|
+
border: 2px solid oklch(0.35 0.02 250);
|
|
304
|
+
border-top-color: oklch(0.70 0.15 240);
|
|
305
|
+
border-radius: 50%;
|
|
306
|
+
animation: fab-spin 0.6s linear infinite;
|
|
307
|
+
flex-shrink: 0;
|
|
308
|
+
}
|
|
309
|
+
@keyframes fab-spin {
|
|
310
|
+
to { transform: rotate(360deg); }
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/* Dropdown */
|
|
314
|
+
.fab-dropdown-wrapper {
|
|
315
|
+
position: relative;
|
|
316
|
+
}
|
|
317
|
+
.fab-dropdown {
|
|
318
|
+
position: absolute;
|
|
319
|
+
bottom: calc(100% + 8px);
|
|
320
|
+
left: 50%;
|
|
321
|
+
transform: translateX(-50%);
|
|
322
|
+
min-width: 160px;
|
|
323
|
+
background: oklch(0.18 0.02 250);
|
|
324
|
+
border: 1px solid oklch(0.30 0.02 250);
|
|
325
|
+
border-radius: 0.5rem;
|
|
326
|
+
padding: 0.375rem;
|
|
327
|
+
box-shadow: 0 8px 24px oklch(0.05 0 0 / 0.5);
|
|
328
|
+
z-index: 60;
|
|
329
|
+
}
|
|
330
|
+
.fab-dropdown-item {
|
|
331
|
+
display: flex;
|
|
332
|
+
align-items: center;
|
|
333
|
+
gap: 0.5rem;
|
|
334
|
+
width: 100%;
|
|
335
|
+
padding: 0.375rem 0.625rem;
|
|
336
|
+
border: none;
|
|
337
|
+
background: transparent;
|
|
338
|
+
color: oklch(0.80 0.02 250);
|
|
339
|
+
font-size: 0.75rem;
|
|
340
|
+
text-align: left;
|
|
341
|
+
border-radius: 0.375rem;
|
|
342
|
+
cursor: pointer;
|
|
343
|
+
transition: background 0.1s;
|
|
344
|
+
white-space: nowrap;
|
|
345
|
+
}
|
|
346
|
+
.fab-dropdown-item:hover { background: oklch(0.25 0.02 250); }
|
|
347
|
+
|
|
348
|
+
.fab-dot {
|
|
349
|
+
width: 8px;
|
|
350
|
+
height: 8px;
|
|
351
|
+
border-radius: 50%;
|
|
352
|
+
flex-shrink: 0;
|
|
353
|
+
}
|
|
354
|
+
</style>
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export interface ActionButton {
|
|
2
|
+
/** Unique key */
|
|
3
|
+
id: string;
|
|
4
|
+
/** Button label */
|
|
5
|
+
label: string;
|
|
6
|
+
/** SVG path string for a 24×24 icon (optional) */
|
|
7
|
+
icon?: string;
|
|
8
|
+
/** Color variant */
|
|
9
|
+
variant?: 'default' | 'primary' | 'danger' | 'warning' | 'success';
|
|
10
|
+
/** Called when clicked */
|
|
11
|
+
onclick: () => void;
|
|
12
|
+
}
|
|
13
|
+
export interface DropdownItem {
|
|
14
|
+
/** Display label */
|
|
15
|
+
label: string;
|
|
16
|
+
/** Optional colored dot (oklch string) */
|
|
17
|
+
dotColor?: string;
|
|
18
|
+
/** Optional SVG snippet rendered before the label */
|
|
19
|
+
iconSnippet?: import('svelte').Snippet;
|
|
20
|
+
/** Called when this item is clicked */
|
|
21
|
+
onclick: () => void;
|
|
22
|
+
}
|
|
23
|
+
export interface ActionDropdown {
|
|
24
|
+
/** Unique key */
|
|
25
|
+
id: string;
|
|
26
|
+
/** Button label */
|
|
27
|
+
label: string;
|
|
28
|
+
/** SVG path string for a 24×24 icon (optional) */
|
|
29
|
+
icon?: string;
|
|
30
|
+
/** Color variant */
|
|
31
|
+
variant?: 'default' | 'primary' | 'info' | 'purple';
|
|
32
|
+
/** Items in the dropdown */
|
|
33
|
+
items: DropdownItem[];
|
|
34
|
+
}
|
|
35
|
+
interface Props {
|
|
36
|
+
/** Number of selected items — bar is hidden when 0 */
|
|
37
|
+
count: number;
|
|
38
|
+
/** Primary action buttons */
|
|
39
|
+
actions?: ActionButton[];
|
|
40
|
+
/** Dropdown menus (open upward from the bar) */
|
|
41
|
+
dropdowns?: ActionDropdown[];
|
|
42
|
+
/** Disables all buttons while true and shows a spinner */
|
|
43
|
+
loading?: boolean;
|
|
44
|
+
/** Called when the "Clear" button is clicked */
|
|
45
|
+
onClear?: () => void;
|
|
46
|
+
/** Label for the selection count (default: "selected") */
|
|
47
|
+
countLabel?: string;
|
|
48
|
+
}
|
|
49
|
+
declare const FloatingActionBar: import("svelte").Component<Props, {}, "">;
|
|
50
|
+
type FloatingActionBar = ReturnType<typeof FloatingActionBar>;
|
|
51
|
+
export default FloatingActionBar;
|