@makolabs/ripple 0.0.1-dev.60 → 0.0.1-dev.61
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.
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { cn } from '../index.js';
|
|
3
|
+
import type { ClassValue } from 'tailwind-variants';
|
|
4
|
+
import type { Component } from 'svelte';
|
|
5
|
+
import type { FilterTab, FilterGroup, CompactFiltersProps } from '../index.js';
|
|
6
|
+
|
|
7
|
+
// Props definition
|
|
8
|
+
let {
|
|
9
|
+
filterGroups = [],
|
|
10
|
+
isExpanded = $bindable(false),
|
|
11
|
+
title = 'Filters',
|
|
12
|
+
class: className,
|
|
13
|
+
summaryClass,
|
|
14
|
+
expandedClass,
|
|
15
|
+
ChevronDownIcon,
|
|
16
|
+
ChevronUpIcon,
|
|
17
|
+
FilterIcon
|
|
18
|
+
}: CompactFiltersProps = $props();
|
|
19
|
+
|
|
20
|
+
// Toggle expanded state
|
|
21
|
+
function toggleExpanded() {
|
|
22
|
+
isExpanded = !isExpanded;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Helper to get the label of the selected filter
|
|
26
|
+
function getSelectedLabel(tabs: FilterTab[], selectedValue: string): string {
|
|
27
|
+
const tab = tabs.find((tab) => tab.value === selectedValue);
|
|
28
|
+
return tab ? tab.label : 'All';
|
|
29
|
+
}
|
|
30
|
+
</script>
|
|
31
|
+
|
|
32
|
+
{#snippet DefaultFilterIcon()}
|
|
33
|
+
<svg
|
|
34
|
+
width="16"
|
|
35
|
+
height="16"
|
|
36
|
+
viewBox="0 0 24 24"
|
|
37
|
+
fill="none"
|
|
38
|
+
stroke="currentColor"
|
|
39
|
+
stroke-width="2"
|
|
40
|
+
stroke-linecap="round"
|
|
41
|
+
stroke-linejoin="round"
|
|
42
|
+
>
|
|
43
|
+
<polygon points="22,3 2,3 10,12.46 10,19 14,21 14,12.46"></polygon>
|
|
44
|
+
</svg>
|
|
45
|
+
{/snippet}
|
|
46
|
+
|
|
47
|
+
{#snippet DefaultChevronDown()}
|
|
48
|
+
<svg
|
|
49
|
+
width="18"
|
|
50
|
+
height="18"
|
|
51
|
+
viewBox="0 0 24 24"
|
|
52
|
+
fill="none"
|
|
53
|
+
stroke="currentColor"
|
|
54
|
+
stroke-width="2"
|
|
55
|
+
stroke-linecap="round"
|
|
56
|
+
stroke-linejoin="round"
|
|
57
|
+
>
|
|
58
|
+
<polyline points="6,9 12,15 18,9"></polyline>
|
|
59
|
+
</svg>
|
|
60
|
+
{/snippet}
|
|
61
|
+
|
|
62
|
+
{#snippet DefaultChevronUp()}
|
|
63
|
+
<svg
|
|
64
|
+
width="18"
|
|
65
|
+
height="18"
|
|
66
|
+
viewBox="0 0 24 24"
|
|
67
|
+
fill="none"
|
|
68
|
+
stroke="currentColor"
|
|
69
|
+
stroke-width="2"
|
|
70
|
+
stroke-linecap="round"
|
|
71
|
+
stroke-linejoin="round"
|
|
72
|
+
>
|
|
73
|
+
<polyline points="18,15 12,9 6,15"></polyline>
|
|
74
|
+
</svg>
|
|
75
|
+
{/snippet}
|
|
76
|
+
|
|
77
|
+
<div class={cn('rounded-lg border border-gray-200 bg-white p-3 shadow-sm', className)}>
|
|
78
|
+
<button
|
|
79
|
+
onclick={toggleExpanded}
|
|
80
|
+
class="mb-2 flex min-w-full cursor-pointer items-center justify-between"
|
|
81
|
+
>
|
|
82
|
+
<div class="flex items-center gap-2">
|
|
83
|
+
{#if FilterIcon}
|
|
84
|
+
<FilterIcon size={16} class="text-gray-500" />
|
|
85
|
+
{:else}
|
|
86
|
+
<span class="text-gray-500">
|
|
87
|
+
{@render DefaultFilterIcon()}
|
|
88
|
+
</span>
|
|
89
|
+
{/if}
|
|
90
|
+
<span class="text-sm font-medium">{title}</span>
|
|
91
|
+
</div>
|
|
92
|
+
<div
|
|
93
|
+
class="rounded-md p-1 text-gray-500 hover:bg-gray-100 hover:text-gray-700"
|
|
94
|
+
aria-label={isExpanded ? `Collapse ${title.toLowerCase()}` : `Expand ${title.toLowerCase()}`}
|
|
95
|
+
>
|
|
96
|
+
{#if isExpanded}
|
|
97
|
+
{#if ChevronUpIcon}
|
|
98
|
+
<ChevronUpIcon size={18} />
|
|
99
|
+
{:else}
|
|
100
|
+
<span>{@render DefaultChevronUp()}</span>
|
|
101
|
+
{/if}
|
|
102
|
+
{:else if ChevronDownIcon}
|
|
103
|
+
<ChevronDownIcon size={18} />
|
|
104
|
+
{:else}
|
|
105
|
+
<span>{@render DefaultChevronDown()}></span>
|
|
106
|
+
{/if}
|
|
107
|
+
</div>
|
|
108
|
+
</button>
|
|
109
|
+
|
|
110
|
+
{#if !isExpanded}
|
|
111
|
+
<!-- Summary of selected filters when collapsed -->
|
|
112
|
+
<div class={cn('flex flex-wrap gap-2', summaryClass)}>
|
|
113
|
+
{#each filterGroups as group}
|
|
114
|
+
{#if group.tabs.length > 0}
|
|
115
|
+
<div
|
|
116
|
+
class="bg-primary-50 text-primary-700 border-primary-200 flex items-center gap-1 rounded-full border px-3 py-1 text-xs"
|
|
117
|
+
>
|
|
118
|
+
<span class="font-medium">{group.label}:</span>
|
|
119
|
+
{getSelectedLabel(group.tabs, group.selectedValue)}
|
|
120
|
+
</div>
|
|
121
|
+
{/if}
|
|
122
|
+
{/each}
|
|
123
|
+
</div>
|
|
124
|
+
{:else}
|
|
125
|
+
<div class={cn('flex flex-col gap-2', expandedClass)}>
|
|
126
|
+
{#each filterGroups as group, index}
|
|
127
|
+
{#if group.tabs.length > 0}
|
|
128
|
+
<div
|
|
129
|
+
class={cn(
|
|
130
|
+
'flex items-center gap-2 pb-2',
|
|
131
|
+
index > 0 ? 'border-t border-gray-100 pt-2' : ''
|
|
132
|
+
)}
|
|
133
|
+
>
|
|
134
|
+
<div class={cn('text-xs font-medium text-gray-500', group.minWidth || 'min-w-[70px]')}>
|
|
135
|
+
{group.label}
|
|
136
|
+
</div>
|
|
137
|
+
<div class="flex flex-wrap gap-2">
|
|
138
|
+
{#each group.tabs as tab}
|
|
139
|
+
<button
|
|
140
|
+
onclick={() => group.onChange(tab.value)}
|
|
141
|
+
class={cn(
|
|
142
|
+
'rounded-full border px-3 py-1 text-xs font-medium whitespace-nowrap',
|
|
143
|
+
group.selectedValue === tab.value
|
|
144
|
+
? 'bg-primary-50 text-primary-700 border-primary-200'
|
|
145
|
+
: 'border-gray-200 text-gray-700 hover:bg-gray-50'
|
|
146
|
+
)}
|
|
147
|
+
>
|
|
148
|
+
{tab.label}
|
|
149
|
+
</button>
|
|
150
|
+
{/each}
|
|
151
|
+
</div>
|
|
152
|
+
</div>
|
|
153
|
+
{/if}
|
|
154
|
+
{/each}
|
|
155
|
+
</div>
|
|
156
|
+
{/if}
|
|
157
|
+
</div>
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Component } from 'svelte';
|
|
2
|
+
import type { CompactFiltersProps } from '../index.js';
|
|
3
|
+
declare const CompactFilters: Component<CompactFiltersProps, {}, "isExpanded">;
|
|
4
|
+
type CompactFilters = ReturnType<typeof CompactFilters>;
|
|
5
|
+
export default CompactFilters;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as CompactFilters } from './CompactFilters.svelte';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as CompactFilters } from './CompactFilters.svelte';
|
package/dist/index.d.ts
CHANGED
|
@@ -342,12 +342,6 @@ export { default as Select } from './elements/dropdown/Select.svelte';
|
|
|
342
342
|
export { default as Card } from './layout/card/Card.svelte';
|
|
343
343
|
export { default as StatsCard } from './layout/card/StatsCard.svelte';
|
|
344
344
|
export { default as Alert } from './elements/alert/Alert.svelte';
|
|
345
|
-
export type TabItem = {
|
|
346
|
-
value: string;
|
|
347
|
-
label: string;
|
|
348
|
-
icon?: Component;
|
|
349
|
-
disabled?: boolean;
|
|
350
|
-
};
|
|
351
345
|
export type TabProps = {
|
|
352
346
|
value: string;
|
|
353
347
|
label: string;
|
|
@@ -810,3 +804,27 @@ export type RadioPillProps = {
|
|
|
810
804
|
errors?: string[];
|
|
811
805
|
onchange?: (value: string) => void;
|
|
812
806
|
};
|
|
807
|
+
export type FilterTab = {
|
|
808
|
+
value: string;
|
|
809
|
+
label: string;
|
|
810
|
+
};
|
|
811
|
+
export type FilterGroup = {
|
|
812
|
+
key: string;
|
|
813
|
+
label: string;
|
|
814
|
+
tabs: FilterTab[];
|
|
815
|
+
selectedValue: string;
|
|
816
|
+
onChange: (value: string) => void;
|
|
817
|
+
minWidth?: string;
|
|
818
|
+
};
|
|
819
|
+
export type CompactFiltersProps = {
|
|
820
|
+
filterGroups: FilterGroup[];
|
|
821
|
+
isExpanded?: boolean;
|
|
822
|
+
title?: string;
|
|
823
|
+
class?: ClassValue;
|
|
824
|
+
summaryClass?: ClassValue;
|
|
825
|
+
expandedClass?: ClassValue;
|
|
826
|
+
ChevronDownIcon?: Component;
|
|
827
|
+
ChevronUpIcon?: Component;
|
|
828
|
+
FilterIcon?: Component;
|
|
829
|
+
};
|
|
830
|
+
export { CompactFilters } from './filters/index.js';
|
package/dist/index.js
CHANGED
|
@@ -69,3 +69,5 @@ export { default as RadioPill } from './forms/RadioPill.svelte';
|
|
|
69
69
|
export { default as Progress } from './elements/progress/Progress.svelte';
|
|
70
70
|
export { default as Accordion } from './elements/accordion/Accordion.svelte';
|
|
71
71
|
export { default as Timeline } from './elements/timeline/Timeline.svelte';
|
|
72
|
+
// Re-export filters
|
|
73
|
+
export { CompactFilters } from './filters/index.js';
|