@websline/system-components 1.0.11 → 1.0.13
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/components/atoms/actions/button/button.variants.d.ts +0 -9
- package/dist/components/atoms/actions/button/button.variants.js +10 -13
- package/dist/components/atoms/actions/closeButton/CloseButton.svelte +1 -1
- package/dist/components/atoms/actions/iconButton/iconButton.variants.js +3 -3
- package/dist/components/atoms/avatar/avatar.variants.js +2 -2
- package/dist/components/atoms/badge/badge.variants.js +1 -1
- package/dist/components/atoms/chip/chip.variants.js +2 -2
- package/dist/components/atoms/feedback/progressBar/progressBar.variants.js +2 -2
- package/dist/components/atoms/helperText/helperText.variants.d.ts +2 -2
- package/dist/components/atoms/helperText/helperText.variants.js +1 -1
- package/dist/components/atoms/icon/Icon.svelte +1 -1
- package/dist/components/atoms/input/input.variants.js +4 -4
- package/dist/components/atoms/label/label.variants.d.ts +2 -2
- package/dist/components/atoms/label/label.variants.js +1 -1
- package/dist/components/atoms/select/Select.svelte +0 -1
- package/dist/components/atoms/select/select.variants.js +2 -2
- package/dist/components/molecules/notification/notification.variants.js +4 -4
- package/dist/components/molecules/pickers/colorSwatch/colorSwatch.variants.js +2 -2
- package/dist/components/molecules/richTextEditor/richTextEditor.variants.js +1 -1
- package/dist/components/molecules/selectorCard/selectorCard.variants.js +6 -5
- package/dist/components/molecules/tagSelector/Dropdown.svelte +113 -0
- package/dist/components/molecules/tagSelector/Dropdown.svelte.d.ts +29 -0
- package/dist/components/molecules/tagSelector/TagSelector.svelte +241 -0
- package/dist/components/molecules/tagSelector/TagSelector.svelte.d.ts +87 -0
- package/dist/components/molecules/tagSelector/ValueList.svelte +52 -0
- package/dist/components/molecules/tagSelector/ValueList.svelte.d.ts +29 -0
- package/dist/components/molecules/tagSelector/tagSelector.variants.d.ts +79 -0
- package/dist/components/molecules/tagSelector/tagSelector.variants.js +44 -0
- package/dist/components/molecules/toggleGroup/ToggleGroupItem.svelte +16 -6
- package/dist/components/molecules/toggleGroup/ToggleGroupItem.svelte.d.ts +8 -0
- package/dist/components/molecules/toggleGroup/toggleGroup.variants.js +3 -3
- package/dist/components/molecules/toggleGroup/toggleGroupItem.variants.d.ts +6 -0
- package/dist/components/molecules/toggleGroup/toggleGroupItem.variants.js +11 -10
- package/dist/components/organisms/modal/modal.variants.js +4 -3
- package/dist/components/organisms/popover/popover.variants.js +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { getContext } from "svelte";
|
|
3
|
+
import Dropdown from "./Dropdown.svelte";
|
|
4
|
+
import ValueList from "./ValueList.svelte";
|
|
5
|
+
import { tagSelectorVariants } from "./tagSelector.variants.js";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @typedef {Object} Props
|
|
9
|
+
* @property {boolean} [autofocus=false] Whether the input should be autofocused on mount
|
|
10
|
+
* @property {string} [class=""] Additional CSS classes to apply to the component
|
|
11
|
+
* @property {boolean} [disabled=false] Whether the component is disabled
|
|
12
|
+
* @property {string} [id=""] The ID of the input element
|
|
13
|
+
* @property {string} [labelCreate=""] The label for the create new tag option
|
|
14
|
+
* @property {string} [name] The name of the input, used for form submission
|
|
15
|
+
* @property {Array<{id: string | number, label: string}>} [options=[]] The available tag options
|
|
16
|
+
* @property {string} [placeholder=""] The placeholder text for the input
|
|
17
|
+
* @property {Array<string | number>} [value=[]] The currently selected tags, bound to the component
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/** @type {Props} */
|
|
21
|
+
let {
|
|
22
|
+
autofocus = false,
|
|
23
|
+
class: className = "",
|
|
24
|
+
disabled = false,
|
|
25
|
+
id = "",
|
|
26
|
+
labelCreate = "",
|
|
27
|
+
name,
|
|
28
|
+
options = [],
|
|
29
|
+
placeholder = "",
|
|
30
|
+
value = $bindable([]),
|
|
31
|
+
...rest
|
|
32
|
+
} = $props();
|
|
33
|
+
|
|
34
|
+
let store = getContext("form-field-store");
|
|
35
|
+
|
|
36
|
+
let localValues = $derived.by(() => {
|
|
37
|
+
if (store) {
|
|
38
|
+
return {
|
|
39
|
+
...store(),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
disabled,
|
|
45
|
+
id,
|
|
46
|
+
};
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
let open = $state(false);
|
|
50
|
+
let query = $state("");
|
|
51
|
+
let highlighted = $state(-1);
|
|
52
|
+
|
|
53
|
+
let inputRef = $state();
|
|
54
|
+
let rootRef = $state();
|
|
55
|
+
|
|
56
|
+
let normalized = $derived(query.trim().toLowerCase());
|
|
57
|
+
|
|
58
|
+
let filtered = $derived(
|
|
59
|
+
options.filter((i) => i.label.toLowerCase().includes(normalized)),
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
let showCreate = $derived(
|
|
63
|
+
normalized.length > 0 &&
|
|
64
|
+
!filtered.some((i) => i.label.toLowerCase() === normalized),
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
$effect(() => {
|
|
68
|
+
if (autofocus && inputRef) inputRef.focus();
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
const openDropdown = () => {
|
|
72
|
+
open = true;
|
|
73
|
+
highlighted = -1;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const closeDropdown = () => {
|
|
77
|
+
open = false;
|
|
78
|
+
highlighted = -1;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const dispatchChange = () => {
|
|
82
|
+
rootRef.dispatchEvent(new CustomEvent("change", { detail: value }));
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const dispatchCreate = (item) => {
|
|
86
|
+
rootRef.dispatchEvent(new CustomEvent("create", { detail: item }));
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const refocusInput = () => {
|
|
90
|
+
query = "";
|
|
91
|
+
open = true;
|
|
92
|
+
requestAnimationFrame(() => inputRef?.focus());
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const removeItem = (id) => {
|
|
96
|
+
value = value.filter((vId) => vId !== id);
|
|
97
|
+
dispatchChange();
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const selectItem = (id) => {
|
|
101
|
+
if (value.includes(id)) {
|
|
102
|
+
removeItem(id);
|
|
103
|
+
} else {
|
|
104
|
+
value = [...value, id];
|
|
105
|
+
dispatchChange();
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
refocusInput();
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
const handleFocusOut = (e) => {
|
|
112
|
+
const next = e.relatedTarget;
|
|
113
|
+
|
|
114
|
+
if (next && rootRef.contains(next)) return;
|
|
115
|
+
if (document.activeElement === inputRef) return;
|
|
116
|
+
|
|
117
|
+
closeDropdown();
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
const createItem = () => {
|
|
121
|
+
const label = query.trim();
|
|
122
|
+
if (label === "") return; // also reset here?
|
|
123
|
+
|
|
124
|
+
const lower = label.toLowerCase();
|
|
125
|
+
|
|
126
|
+
const preset = options.find((i) => i.label.toLowerCase() === lower);
|
|
127
|
+
|
|
128
|
+
if (preset) {
|
|
129
|
+
const alreadySelected = value.includes(preset.id);
|
|
130
|
+
|
|
131
|
+
if (!alreadySelected) {
|
|
132
|
+
value = [...value, preset.id];
|
|
133
|
+
dispatchChange();
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
refocusInput();
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const selectedMatch = value.find(
|
|
141
|
+
(id) => typeof id === "string" && id.toLowerCase() === lower,
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
if (!selectedMatch) {
|
|
145
|
+
value = [...value, label];
|
|
146
|
+
dispatchChange();
|
|
147
|
+
dispatchCreate(label);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
refocusInput();
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
const handleKey = (e) => {
|
|
154
|
+
if (!open) return;
|
|
155
|
+
|
|
156
|
+
const total = filtered.length + (showCreate ? 1 : 0);
|
|
157
|
+
const presetHighlighted = highlighted >= 0 && highlighted < filtered.length;
|
|
158
|
+
|
|
159
|
+
if (e.key === "ArrowDown") {
|
|
160
|
+
e.preventDefault();
|
|
161
|
+
highlighted = (highlighted + 1) % total;
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (e.key === "ArrowUp") {
|
|
166
|
+
e.preventDefault();
|
|
167
|
+
highlighted = (highlighted - 1 + total) % total;
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (e.key === "Escape") {
|
|
172
|
+
e.preventDefault();
|
|
173
|
+
if (normalized === "") open = false;
|
|
174
|
+
else refocusInput();
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (e.key === "Enter" || (e.key === " " && presetHighlighted)) {
|
|
179
|
+
e.preventDefault();
|
|
180
|
+
|
|
181
|
+
if (presetHighlighted) {
|
|
182
|
+
selectItem(filtered[highlighted].id);
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (showCreate && highlighted === filtered.length) {
|
|
187
|
+
createItem();
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (normalized !== "") {
|
|
192
|
+
createItem();
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
let styles = $derived(tagSelectorVariants({ disabled: localValues.disabled }));
|
|
199
|
+
</script>
|
|
200
|
+
|
|
201
|
+
<div
|
|
202
|
+
bind:this={rootRef}
|
|
203
|
+
aria-expanded={open}
|
|
204
|
+
class={styles.base({ class: className })}
|
|
205
|
+
onfocusout={handleFocusOut}
|
|
206
|
+
role="combobox"
|
|
207
|
+
{...open
|
|
208
|
+
? {
|
|
209
|
+
"aria-controls": localValues.id,
|
|
210
|
+
"aria-haspopup": "listbox",
|
|
211
|
+
"aria-owns": localValues.id,
|
|
212
|
+
}
|
|
213
|
+
: {}}
|
|
214
|
+
{...rest}>
|
|
215
|
+
<input {name} readonly type="hidden" value={value.join(",")} />
|
|
216
|
+
<ValueList
|
|
217
|
+
bind:inputRef
|
|
218
|
+
{localValues}
|
|
219
|
+
onKeydown={handleKey}
|
|
220
|
+
onOpenDropdown={openDropdown}
|
|
221
|
+
onRemoveItem={removeItem}
|
|
222
|
+
{open}
|
|
223
|
+
{options}
|
|
224
|
+
{placeholder}
|
|
225
|
+
bind:query
|
|
226
|
+
{value} />
|
|
227
|
+
|
|
228
|
+
{#if open}
|
|
229
|
+
<Dropdown
|
|
230
|
+
{filtered}
|
|
231
|
+
{highlighted}
|
|
232
|
+
{inputRef}
|
|
233
|
+
{labelCreate}
|
|
234
|
+
{localValues}
|
|
235
|
+
onCreateItem={createItem}
|
|
236
|
+
onSelectItem={selectItem}
|
|
237
|
+
{query}
|
|
238
|
+
{showCreate}
|
|
239
|
+
{value} />
|
|
240
|
+
{/if}
|
|
241
|
+
</div>
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
export default TagSelector;
|
|
2
|
+
type TagSelector = {
|
|
3
|
+
$on?(type: string, callback: (e: any) => void): () => void;
|
|
4
|
+
$set?(props: Partial<Props>): void;
|
|
5
|
+
};
|
|
6
|
+
declare const TagSelector: import("svelte").Component<{
|
|
7
|
+
/**
|
|
8
|
+
* Whether the input should be autofocused on mount
|
|
9
|
+
*/
|
|
10
|
+
autofocus?: boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Additional CSS classes to apply to the component
|
|
13
|
+
*/
|
|
14
|
+
class?: string;
|
|
15
|
+
/**
|
|
16
|
+
* Whether the component is disabled
|
|
17
|
+
*/
|
|
18
|
+
disabled?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* The ID of the input element
|
|
21
|
+
*/
|
|
22
|
+
id?: string;
|
|
23
|
+
/**
|
|
24
|
+
* The label for the create new tag option
|
|
25
|
+
*/
|
|
26
|
+
labelCreate?: string;
|
|
27
|
+
/**
|
|
28
|
+
* The name of the input, used for form submission
|
|
29
|
+
*/
|
|
30
|
+
name?: string;
|
|
31
|
+
/**
|
|
32
|
+
* The available tag options
|
|
33
|
+
*/
|
|
34
|
+
options?: Array<{
|
|
35
|
+
id: string | number;
|
|
36
|
+
label: string;
|
|
37
|
+
}>;
|
|
38
|
+
/**
|
|
39
|
+
* The placeholder text for the input
|
|
40
|
+
*/
|
|
41
|
+
placeholder?: string;
|
|
42
|
+
/**
|
|
43
|
+
* The currently selected tags, bound to the component
|
|
44
|
+
*/
|
|
45
|
+
value?: Array<string | number>;
|
|
46
|
+
}, {}, "value">;
|
|
47
|
+
type Props = {
|
|
48
|
+
/**
|
|
49
|
+
* Whether the input should be autofocused on mount
|
|
50
|
+
*/
|
|
51
|
+
autofocus?: boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Additional CSS classes to apply to the component
|
|
54
|
+
*/
|
|
55
|
+
class?: string;
|
|
56
|
+
/**
|
|
57
|
+
* Whether the component is disabled
|
|
58
|
+
*/
|
|
59
|
+
disabled?: boolean;
|
|
60
|
+
/**
|
|
61
|
+
* The ID of the input element
|
|
62
|
+
*/
|
|
63
|
+
id?: string;
|
|
64
|
+
/**
|
|
65
|
+
* The label for the create new tag option
|
|
66
|
+
*/
|
|
67
|
+
labelCreate?: string;
|
|
68
|
+
/**
|
|
69
|
+
* The name of the input, used for form submission
|
|
70
|
+
*/
|
|
71
|
+
name?: string;
|
|
72
|
+
/**
|
|
73
|
+
* The available tag options
|
|
74
|
+
*/
|
|
75
|
+
options?: Array<{
|
|
76
|
+
id: string | number;
|
|
77
|
+
label: string;
|
|
78
|
+
}>;
|
|
79
|
+
/**
|
|
80
|
+
* The placeholder text for the input
|
|
81
|
+
*/
|
|
82
|
+
placeholder?: string;
|
|
83
|
+
/**
|
|
84
|
+
* The currently selected tags, bound to the component
|
|
85
|
+
*/
|
|
86
|
+
value?: Array<string | number>;
|
|
87
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { Chip } from "../../../index.js";
|
|
3
|
+
import { tagSelectorVariants } from "./tagSelector.variants.js";
|
|
4
|
+
|
|
5
|
+
let {
|
|
6
|
+
inputRef = $bindable(),
|
|
7
|
+
localValues,
|
|
8
|
+
onKeydown,
|
|
9
|
+
onOpenDropdown,
|
|
10
|
+
onRemoveItem,
|
|
11
|
+
open = false,
|
|
12
|
+
options = [],
|
|
13
|
+
placeholder,
|
|
14
|
+
query = $bindable(),
|
|
15
|
+
value = [],
|
|
16
|
+
} = $props();
|
|
17
|
+
|
|
18
|
+
let styles = $derived(tagSelectorVariants());
|
|
19
|
+
</script>
|
|
20
|
+
|
|
21
|
+
<div class={styles.valueList()}>
|
|
22
|
+
{#each value as s (s)}
|
|
23
|
+
{@const opt = options.find((i) => i.id === s)}
|
|
24
|
+
<Chip
|
|
25
|
+
class={styles.item()}
|
|
26
|
+
clickable
|
|
27
|
+
icon="closeSmall"
|
|
28
|
+
onclick={() => onRemoveItem(s)}>
|
|
29
|
+
{opt?.label ?? s}
|
|
30
|
+
</Chip>
|
|
31
|
+
{/each}
|
|
32
|
+
|
|
33
|
+
{#if !localValues.disabled}
|
|
34
|
+
<Chip class={styles.searchField()} icon="add" variant="outline">
|
|
35
|
+
<input
|
|
36
|
+
bind:this={inputRef}
|
|
37
|
+
bind:value={query}
|
|
38
|
+
autocomplete="off"
|
|
39
|
+
class={styles.searchInput()}
|
|
40
|
+
onfocus={onOpenDropdown}
|
|
41
|
+
oninput={onOpenDropdown}
|
|
42
|
+
onkeydown={onKeydown}
|
|
43
|
+
{...open
|
|
44
|
+
? {
|
|
45
|
+
"aria-controls": localValues.id,
|
|
46
|
+
}
|
|
47
|
+
: {}}
|
|
48
|
+
{placeholder}
|
|
49
|
+
role="searchbox" />
|
|
50
|
+
</Chip>
|
|
51
|
+
{/if}
|
|
52
|
+
</div>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export default ValueList;
|
|
2
|
+
type ValueList = {
|
|
3
|
+
$on?(type: string, callback: (e: any) => void): () => void;
|
|
4
|
+
$set?(props: Partial<$$ComponentProps>): void;
|
|
5
|
+
};
|
|
6
|
+
declare const ValueList: import("svelte").Component<{
|
|
7
|
+
inputRef?: any;
|
|
8
|
+
localValues: any;
|
|
9
|
+
onKeydown: any;
|
|
10
|
+
onOpenDropdown: any;
|
|
11
|
+
onRemoveItem: any;
|
|
12
|
+
open?: boolean;
|
|
13
|
+
options?: any[];
|
|
14
|
+
placeholder: any;
|
|
15
|
+
query?: any;
|
|
16
|
+
value?: any[];
|
|
17
|
+
}, {}, "inputRef" | "query">;
|
|
18
|
+
type $$ComponentProps = {
|
|
19
|
+
inputRef?: any;
|
|
20
|
+
localValues: any;
|
|
21
|
+
onKeydown: any;
|
|
22
|
+
onOpenDropdown: any;
|
|
23
|
+
onRemoveItem: any;
|
|
24
|
+
open?: boolean;
|
|
25
|
+
options?: any[];
|
|
26
|
+
placeholder: any;
|
|
27
|
+
query?: any;
|
|
28
|
+
value?: any[];
|
|
29
|
+
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
export const tagSelectorVariants: import("tailwind-variants").TVReturnType<{
|
|
2
|
+
dropdownPosition: {
|
|
3
|
+
bottom: {
|
|
4
|
+
dropdown: string;
|
|
5
|
+
};
|
|
6
|
+
top: {
|
|
7
|
+
dropdown: string;
|
|
8
|
+
};
|
|
9
|
+
};
|
|
10
|
+
showDropdown: {
|
|
11
|
+
true: {
|
|
12
|
+
dropdown: string;
|
|
13
|
+
};
|
|
14
|
+
false: {
|
|
15
|
+
dropdown: string;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
}, {
|
|
19
|
+
base: string;
|
|
20
|
+
valueList: string;
|
|
21
|
+
item: string;
|
|
22
|
+
searchField: string;
|
|
23
|
+
searchInput: string;
|
|
24
|
+
dropdown: string;
|
|
25
|
+
dropdownCheckmark: string;
|
|
26
|
+
dropdownItem: string[];
|
|
27
|
+
}, undefined, {
|
|
28
|
+
disabled: {
|
|
29
|
+
true: {
|
|
30
|
+
base: string;
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
error: {
|
|
34
|
+
true: {
|
|
35
|
+
base: string;
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
}, {
|
|
39
|
+
base: string[];
|
|
40
|
+
}, import("tailwind-variants").TVReturnType<{
|
|
41
|
+
disabled: {
|
|
42
|
+
true: {
|
|
43
|
+
base: string;
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
error: {
|
|
47
|
+
true: {
|
|
48
|
+
base: string;
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
}, {
|
|
52
|
+
base: string[];
|
|
53
|
+
}, undefined, {
|
|
54
|
+
disabled: {
|
|
55
|
+
true: {
|
|
56
|
+
base: string;
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
error: {
|
|
60
|
+
true: {
|
|
61
|
+
base: string;
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
}, {
|
|
65
|
+
base: string[];
|
|
66
|
+
}, import("tailwind-variants").TVReturnType<{
|
|
67
|
+
disabled: {
|
|
68
|
+
true: {
|
|
69
|
+
base: string;
|
|
70
|
+
};
|
|
71
|
+
};
|
|
72
|
+
error: {
|
|
73
|
+
true: {
|
|
74
|
+
base: string;
|
|
75
|
+
};
|
|
76
|
+
};
|
|
77
|
+
}, {
|
|
78
|
+
base: string[];
|
|
79
|
+
}, undefined, unknown, unknown, undefined>>>;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { tv } from "tailwind-variants";
|
|
2
|
+
import { inputBaseVariant } from "../../atoms/input/input.variants.js";
|
|
3
|
+
|
|
4
|
+
const tagSelectorVariants = tv({
|
|
5
|
+
extend: inputBaseVariant,
|
|
6
|
+
slots: {
|
|
7
|
+
base: "relative min-h-10 p-1",
|
|
8
|
+
valueList: "flex flex-wrap gap-1",
|
|
9
|
+
item: "h-7.5",
|
|
10
|
+
searchField: "relative h-7.5 w-30",
|
|
11
|
+
searchInput:
|
|
12
|
+
"absolute inset-0 appearance-none border-0 bg-transparent pr-1 pl-8 ui-tag-badge placeholder-current focus:ring-0",
|
|
13
|
+
dropdown:
|
|
14
|
+
"absolute w-full max-w-100 overflow-y-auto bg-white p-1 pr-5 shadow-sm dark:border-neutral-700 dark:bg-neutral-800",
|
|
15
|
+
dropdownCheckmark: "ml-auto shrink-0",
|
|
16
|
+
dropdownItem: [
|
|
17
|
+
"flex w-full grow items-center gap-2 rounded-sm p-2 ui-select-label",
|
|
18
|
+
"bg-white dark:bg-neutral-800",
|
|
19
|
+
"bg-linear-to-r to-transparent",
|
|
20
|
+
"cursor-pointer text-neutral-900 hover:from-black/15 dark:text-neutral-200 dark:hover:from-white/15",
|
|
21
|
+
"data-[highlighted=true]:from-black/15 dark:data-[highlighted=true]:from-white/15",
|
|
22
|
+
],
|
|
23
|
+
},
|
|
24
|
+
variants: {
|
|
25
|
+
dropdownPosition: {
|
|
26
|
+
bottom: {
|
|
27
|
+
dropdown: "top-full mt-1",
|
|
28
|
+
},
|
|
29
|
+
top: {
|
|
30
|
+
dropdown: "bottom-full mb-1",
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
showDropdown: {
|
|
34
|
+
true: {
|
|
35
|
+
dropdown: "block",
|
|
36
|
+
},
|
|
37
|
+
false: {
|
|
38
|
+
dropdown: "hidden",
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
export { tagSelectorVariants };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
import { getContext } from "svelte";
|
|
3
|
+
import { Icon } from "../../../index.js";
|
|
3
4
|
import {
|
|
4
5
|
toggleGroupItemVariants,
|
|
5
6
|
toggleGroupItemTabVariants,
|
|
@@ -9,15 +10,16 @@
|
|
|
9
10
|
* @typedef {Object} Props
|
|
10
11
|
* @property {import('svelte').Snippet} [children] Children content – can be text, HTML, or other Svelte components
|
|
11
12
|
* @property {string} [class=""] Additional CSS classes to apply to the component
|
|
13
|
+
* @property {string} [icon] The name of the icon to display alongside the content
|
|
12
14
|
* @property {string} [value=""] The value of the toggle group item
|
|
13
15
|
*/
|
|
14
16
|
|
|
15
17
|
/** @type {Props} */
|
|
16
|
-
let { children, class: className = "", value: localeValue } = $props();
|
|
18
|
+
let { children, class: className = "", icon, value: localeValue } = $props();
|
|
17
19
|
|
|
18
|
-
let store = getContext("toggle-group-store");
|
|
19
|
-
let { appearance, send, receive, size, variant } = $derived(store
|
|
20
|
-
let isActive = $derived(store
|
|
20
|
+
let store = $derived(getContext("toggle-group-store")());
|
|
21
|
+
let { appearance, send, receive, size, variant } = $derived(store);
|
|
22
|
+
let isActive = $derived(store.value === localeValue);
|
|
21
23
|
|
|
22
24
|
let stylesByVariant = $derived.by(() => {
|
|
23
25
|
if (variant === "tabs") {
|
|
@@ -33,10 +35,18 @@
|
|
|
33
35
|
class={stylesByVariant.button({ appearance, class: className, isActive, size })}
|
|
34
36
|
role="tab"
|
|
35
37
|
onclick={() => {
|
|
36
|
-
store
|
|
38
|
+
store.update(localeValue);
|
|
37
39
|
}}
|
|
38
40
|
type="button">
|
|
39
|
-
<span class={stylesByVariant.span()}>
|
|
41
|
+
<span class={stylesByVariant.span()}>
|
|
42
|
+
{#if icon}
|
|
43
|
+
<Icon
|
|
44
|
+
class={stylesByVariant.icon()}
|
|
45
|
+
name={icon}
|
|
46
|
+
size={variant === "tabs" || size === "small" ? 16 : 24} />
|
|
47
|
+
{/if}
|
|
48
|
+
{@render children?.()}
|
|
49
|
+
</span>
|
|
40
50
|
{#if isActive}
|
|
41
51
|
<div
|
|
42
52
|
class={stylesByVariant.trigger({ appearance })}
|
|
@@ -12,6 +12,10 @@ declare const ToggleGroupItem: import("svelte").Component<{
|
|
|
12
12
|
* Additional CSS classes to apply to the component
|
|
13
13
|
*/
|
|
14
14
|
class?: string;
|
|
15
|
+
/**
|
|
16
|
+
* The name of the icon to display alongside the content
|
|
17
|
+
*/
|
|
18
|
+
icon?: string;
|
|
15
19
|
/**
|
|
16
20
|
* The value of the toggle group item
|
|
17
21
|
*/
|
|
@@ -26,6 +30,10 @@ type Props = {
|
|
|
26
30
|
* Additional CSS classes to apply to the component
|
|
27
31
|
*/
|
|
28
32
|
class?: string;
|
|
33
|
+
/**
|
|
34
|
+
* The name of the icon to display alongside the content
|
|
35
|
+
*/
|
|
36
|
+
icon?: string;
|
|
29
37
|
/**
|
|
30
38
|
* The value of the toggle group item
|
|
31
39
|
*/
|
|
@@ -2,7 +2,7 @@ import { tv } from "tailwind-variants";
|
|
|
2
2
|
|
|
3
3
|
const toggleGroupVariants = tv({
|
|
4
4
|
slots: {
|
|
5
|
-
base: "overflow-hidden rounded-
|
|
5
|
+
base: "overflow-hidden rounded-lg bg-current",
|
|
6
6
|
tabs: "flex gap-1",
|
|
7
7
|
},
|
|
8
8
|
variants: {
|
|
@@ -12,7 +12,7 @@ const toggleGroupVariants = tv({
|
|
|
12
12
|
},
|
|
13
13
|
size: {
|
|
14
14
|
small: {
|
|
15
|
-
tabs: "h-
|
|
15
|
+
tabs: "h-9 p-1",
|
|
16
16
|
},
|
|
17
17
|
medium: {
|
|
18
18
|
tabs: "h-10 p-1",
|
|
@@ -24,7 +24,7 @@ const toggleGroupVariants = tv({
|
|
|
24
24
|
const toggleGroupTabVariants = tv({
|
|
25
25
|
slots: {
|
|
26
26
|
base: "",
|
|
27
|
-
tabs: "flex h-
|
|
27
|
+
tabs: "flex h-9 gap-4 border-b border-neutral-300 dark:border-neutral-700",
|
|
28
28
|
},
|
|
29
29
|
});
|
|
30
30
|
|
|
@@ -18,6 +18,7 @@ export const toggleGroupItemVariants: import("tailwind-variants").TVReturnType<{
|
|
|
18
18
|
}, {
|
|
19
19
|
base: string;
|
|
20
20
|
button: string;
|
|
21
|
+
icon: string;
|
|
21
22
|
span: string;
|
|
22
23
|
trigger: string;
|
|
23
24
|
}, undefined, {
|
|
@@ -40,6 +41,7 @@ export const toggleGroupItemVariants: import("tailwind-variants").TVReturnType<{
|
|
|
40
41
|
}, {
|
|
41
42
|
base: string;
|
|
42
43
|
button: string;
|
|
44
|
+
icon: string;
|
|
43
45
|
span: string;
|
|
44
46
|
trigger: string;
|
|
45
47
|
}, import("tailwind-variants").TVReturnType<{
|
|
@@ -62,6 +64,7 @@ export const toggleGroupItemVariants: import("tailwind-variants").TVReturnType<{
|
|
|
62
64
|
}, {
|
|
63
65
|
base: string;
|
|
64
66
|
button: string;
|
|
67
|
+
icon: string;
|
|
65
68
|
span: string;
|
|
66
69
|
trigger: string;
|
|
67
70
|
}, undefined, unknown, unknown, undefined>>;
|
|
@@ -77,6 +80,7 @@ export const toggleGroupItemTabVariants: import("tailwind-variants").TVReturnTyp
|
|
|
77
80
|
}, {
|
|
78
81
|
base: string;
|
|
79
82
|
button: string;
|
|
83
|
+
icon: string;
|
|
80
84
|
span: string;
|
|
81
85
|
trigger: string;
|
|
82
86
|
}, undefined, {
|
|
@@ -91,6 +95,7 @@ export const toggleGroupItemTabVariants: import("tailwind-variants").TVReturnTyp
|
|
|
91
95
|
}, {
|
|
92
96
|
base: string;
|
|
93
97
|
button: string;
|
|
98
|
+
icon: string;
|
|
94
99
|
span: string;
|
|
95
100
|
trigger: string;
|
|
96
101
|
}, import("tailwind-variants").TVReturnType<{
|
|
@@ -105,6 +110,7 @@ export const toggleGroupItemTabVariants: import("tailwind-variants").TVReturnTyp
|
|
|
105
110
|
}, {
|
|
106
111
|
base: string;
|
|
107
112
|
button: string;
|
|
113
|
+
icon: string;
|
|
108
114
|
span: string;
|
|
109
115
|
trigger: string;
|
|
110
116
|
}, undefined, unknown, unknown, undefined>>;
|