@studiocms/ui 0.4.14 → 0.4.16
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.
|
@@ -6,91 +6,103 @@ import Input from '../Input/Input.astro';
|
|
|
6
6
|
import './searchselect.css';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
|
-
*
|
|
9
|
+
* Represents an option in the select component.
|
|
10
10
|
*/
|
|
11
|
-
interface
|
|
11
|
+
export interface SearchSelectOption {
|
|
12
12
|
/**
|
|
13
|
-
* The label of the option.
|
|
13
|
+
* The label of the option displayed to the user.
|
|
14
14
|
*/
|
|
15
15
|
label: string;
|
|
16
16
|
/**
|
|
17
|
-
* The value of the option.
|
|
17
|
+
* The value of the option used for form submission.
|
|
18
18
|
*/
|
|
19
19
|
value: string;
|
|
20
20
|
/**
|
|
21
|
-
* Whether the option is disabled.
|
|
21
|
+
* Whether the option is disabled. Defaults to `false`.
|
|
22
22
|
*/
|
|
23
23
|
disabled?: boolean;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
|
-
*
|
|
27
|
+
* Base properties shared by both single and multiple select components.
|
|
28
28
|
*/
|
|
29
|
-
|
|
29
|
+
export interface SearchSelectBaseProps {
|
|
30
30
|
/**
|
|
31
|
-
*
|
|
31
|
+
* The label of the select field.
|
|
32
32
|
*/
|
|
33
|
-
|
|
33
|
+
label?: string;
|
|
34
34
|
/**
|
|
35
|
-
*
|
|
35
|
+
* Additional classes to apply to the select component.
|
|
36
36
|
*/
|
|
37
|
-
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
type MultipleProps = {
|
|
37
|
+
class?: string;
|
|
41
38
|
/**
|
|
42
|
-
*
|
|
39
|
+
* The name of the select field, used for form submission.
|
|
43
40
|
*/
|
|
44
|
-
|
|
41
|
+
name?: string;
|
|
45
42
|
/**
|
|
46
|
-
*
|
|
43
|
+
* Whether the select field is required. Defaults to `false`.
|
|
47
44
|
*/
|
|
48
|
-
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* The props for the select component.
|
|
53
|
-
*/
|
|
54
|
-
type BaseProps = {
|
|
45
|
+
isRequired?: boolean;
|
|
55
46
|
/**
|
|
56
|
-
* The
|
|
47
|
+
* The options to display in the select dropdown.
|
|
57
48
|
*/
|
|
58
|
-
|
|
49
|
+
options: SearchSelectOption[];
|
|
59
50
|
/**
|
|
60
|
-
*
|
|
51
|
+
* Whether the select field is disabled. Defaults to `false`.
|
|
61
52
|
*/
|
|
62
|
-
|
|
53
|
+
disabled?: boolean;
|
|
63
54
|
/**
|
|
64
|
-
*
|
|
55
|
+
* Whether the select field should take up the full width of its container. Defaults to `false`.
|
|
65
56
|
*/
|
|
66
|
-
|
|
57
|
+
fullWidth?: boolean;
|
|
67
58
|
/**
|
|
68
|
-
*
|
|
59
|
+
* The placeholder text to display when no option is selected. Defaults to `Select`.
|
|
69
60
|
*/
|
|
70
|
-
|
|
61
|
+
placeholder?: string;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Properties specific to single-select mode.
|
|
66
|
+
*/
|
|
67
|
+
export interface SingleSearchSelectProps extends SearchSelectBaseProps {
|
|
71
68
|
/**
|
|
72
|
-
*
|
|
69
|
+
* Whether the select accepts multiple options.
|
|
73
70
|
*/
|
|
74
|
-
|
|
71
|
+
multiple?: false;
|
|
75
72
|
/**
|
|
76
|
-
*
|
|
73
|
+
* The default selected value.
|
|
77
74
|
*/
|
|
78
|
-
|
|
75
|
+
defaultValue?: string;
|
|
79
76
|
/**
|
|
80
|
-
*
|
|
77
|
+
* The maximum number of options that can be selected.
|
|
78
|
+
* This property has no effect in single-select mode.
|
|
81
79
|
*/
|
|
82
|
-
|
|
80
|
+
max?: never;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Properties specific to multi-select mode.
|
|
85
|
+
*/
|
|
86
|
+
export interface MultiSearchSelectProps extends SearchSelectBaseProps {
|
|
83
87
|
/**
|
|
84
|
-
*
|
|
88
|
+
* Whether the select accepts multiple options.
|
|
85
89
|
*/
|
|
86
|
-
|
|
90
|
+
multiple: true;
|
|
91
|
+
/**
|
|
92
|
+
* The default selected values.
|
|
93
|
+
*/
|
|
94
|
+
defaultValue?: string[];
|
|
87
95
|
/**
|
|
88
|
-
* The maximum number of options that can be selected.
|
|
96
|
+
* The maximum number of options that can be selected.
|
|
89
97
|
*/
|
|
90
98
|
max?: number;
|
|
91
|
-
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Union type representing all possible select component properties.
|
|
103
|
+
*/
|
|
104
|
+
export type Props = SingleSearchSelectProps | MultiSearchSelectProps;
|
|
92
105
|
|
|
93
|
-
type Props = BaseProps & (MultipleProps | NonMultipleProps);
|
|
94
106
|
const {
|
|
95
107
|
label,
|
|
96
108
|
defaultValue,
|
|
@@ -105,7 +117,7 @@ const {
|
|
|
105
117
|
max = undefined,
|
|
106
118
|
} = Astro.props;
|
|
107
119
|
|
|
108
|
-
let selected:
|
|
120
|
+
let selected: SearchSelectOption | (SearchSelectOption | undefined)[] | undefined;
|
|
109
121
|
|
|
110
122
|
if (multiple && Array.isArray(defaultValue)) {
|
|
111
123
|
selected = defaultValue.map((x) => options.find((y) => y.value === x));
|
|
@@ -136,6 +148,7 @@ const defaultLabel = selected
|
|
|
136
148
|
role='combobox'
|
|
137
149
|
aria-controls={`${name}-dropdown`}
|
|
138
150
|
aria-expanded="false"
|
|
151
|
+
tabindex={disabled ? -1 : 0}
|
|
139
152
|
label={label || ''}
|
|
140
153
|
isRequired={isRequired || false}
|
|
141
154
|
/>
|
|
@@ -174,7 +187,8 @@ const defaultLabel = selected
|
|
|
174
187
|
const isSelected = Array.isArray(selected)
|
|
175
188
|
? selected.map((y) => y && y.value).includes(x.value)
|
|
176
189
|
: selected?.value === x.value;
|
|
177
|
-
|
|
190
|
+
|
|
191
|
+
return (
|
|
178
192
|
<option
|
|
179
193
|
value={x.value}
|
|
180
194
|
selected={isSelected}
|
|
@@ -195,7 +209,7 @@ const defaultLabel = selected
|
|
|
195
209
|
multiple && Array.isArray(selected ?? []) && (
|
|
196
210
|
<div class="sui-search-select-badge-container">
|
|
197
211
|
{
|
|
198
|
-
((selected ?? []) as
|
|
212
|
+
((selected ?? []) as SearchSelectOption[]).map((s) => s &&
|
|
199
213
|
<Badge class="sui-search-select-badge" data-value={s.value} size="sm" label={s.label} iconPosition="right" icon="x-mark" />
|
|
200
214
|
)
|
|
201
215
|
}
|
|
@@ -82,12 +82,9 @@ function loadSearchSelects() {
|
|
|
82
82
|
);
|
|
83
83
|
if (option) {
|
|
84
84
|
option.classList.toggle("selected", forceState ?? !isCurrentlySelected);
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
);
|
|
89
|
-
if (selectOption) {
|
|
90
|
-
selectOption.selected = forceState ?? !isCurrentlySelected;
|
|
85
|
+
if (container && container.select) {
|
|
86
|
+
container.select.value = option.getAttribute("value");
|
|
87
|
+
}
|
|
91
88
|
}
|
|
92
89
|
const selectedCountEl = container.querySelector(
|
|
93
90
|
".sui-search-select-max-span .sui-search-select-select-count"
|
|
@@ -117,12 +114,12 @@ function loadSearchSelects() {
|
|
|
117
114
|
};
|
|
118
115
|
const reconstructOptions = (filteredOptions, state2, container) => {
|
|
119
116
|
container.dropdown.innerHTML = "";
|
|
120
|
-
let i = 0;
|
|
121
117
|
const selectedValues = state2.selectedOptionsMap[container.dataset.id] || [];
|
|
122
118
|
if (filteredOptions.length === 0) {
|
|
123
119
|
container.dropdown.innerHTML = '<li class="empty-search-results">No results found</li>';
|
|
124
120
|
return;
|
|
125
121
|
}
|
|
122
|
+
let i = 0;
|
|
126
123
|
for (const option of filteredOptions) {
|
|
127
124
|
const element = document.createElement("li");
|
|
128
125
|
element.classList.add("sui-search-select-option");
|
|
@@ -329,6 +326,7 @@ function loadSearchSelects() {
|
|
|
329
326
|
};
|
|
330
327
|
const selects = document.querySelectorAll(".sui-search-select-label");
|
|
331
328
|
for (const container of selects) {
|
|
329
|
+
if (container.dataset.initialized === "true") continue;
|
|
332
330
|
const id = container.dataset.id;
|
|
333
331
|
const specialContainer = Object.assign(container, {
|
|
334
332
|
input: container.querySelector("input"),
|
|
@@ -365,6 +363,7 @@ function loadSearchSelects() {
|
|
|
365
363
|
if (state.isMultipleMap[id]) {
|
|
366
364
|
recalculateBadges(state, specialContainer);
|
|
367
365
|
}
|
|
366
|
+
container.dataset.initialized = "true";
|
|
368
367
|
}
|
|
369
368
|
}
|
|
370
369
|
document.addEventListener("astro:page-load", loadSearchSelects);
|
|
@@ -5,15 +5,15 @@ import Icon from '../Icon/Icon.astro';
|
|
|
5
5
|
import './select.css';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
8
|
+
* Represents an option in the select component.
|
|
9
9
|
*/
|
|
10
|
-
interface
|
|
10
|
+
export interface SelectOption {
|
|
11
11
|
/**
|
|
12
|
-
* The label of the option.
|
|
12
|
+
* The label of the option displayed to the user.
|
|
13
13
|
*/
|
|
14
14
|
label: string;
|
|
15
15
|
/**
|
|
16
|
-
* The value of the option.
|
|
16
|
+
* The value of the option used for form submission.
|
|
17
17
|
*/
|
|
18
18
|
value: string;
|
|
19
19
|
/**
|
|
@@ -22,71 +22,85 @@ interface Option {
|
|
|
22
22
|
disabled?: boolean;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
type NonMultipleProps = {
|
|
26
|
-
/**
|
|
27
|
-
* Whether the select accepts multiple options. Defaults to `false`.
|
|
28
|
-
*/
|
|
29
|
-
multiple: false;
|
|
30
|
-
/**
|
|
31
|
-
* The default value of the select.
|
|
32
|
-
*/
|
|
33
|
-
defaultValue: string;
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
type MultipleProps = {
|
|
37
|
-
/**
|
|
38
|
-
* Whether the select accepts multiple options. Defaults to `false`.
|
|
39
|
-
*/
|
|
40
|
-
multiple: true;
|
|
41
|
-
/**
|
|
42
|
-
* The default value of the select.
|
|
43
|
-
*/
|
|
44
|
-
defaultValue: string[];
|
|
45
|
-
};
|
|
46
|
-
|
|
47
25
|
/**
|
|
48
|
-
*
|
|
26
|
+
* Base properties shared by both single and multiple select components.
|
|
49
27
|
*/
|
|
50
|
-
|
|
28
|
+
export interface SelectBaseProps {
|
|
51
29
|
/**
|
|
52
|
-
* The label of the select.
|
|
30
|
+
* The label of the select field.
|
|
53
31
|
*/
|
|
54
32
|
label?: string;
|
|
55
33
|
/**
|
|
56
|
-
* Additional classes to apply to the select.
|
|
34
|
+
* Additional classes to apply to the select component.
|
|
57
35
|
*/
|
|
58
36
|
class?: string;
|
|
59
37
|
/**
|
|
60
|
-
* The name of the select
|
|
38
|
+
* The name of the select field, used for form submission.
|
|
61
39
|
*/
|
|
62
40
|
name?: string;
|
|
63
41
|
/**
|
|
64
|
-
* Whether the select is required. Defaults to `false`.
|
|
42
|
+
* Whether the select field is required. Defaults to `false`.
|
|
65
43
|
*/
|
|
66
44
|
isRequired?: boolean;
|
|
67
45
|
/**
|
|
68
|
-
* The options to display in the select.
|
|
46
|
+
* The options to display in the select dropdown.
|
|
69
47
|
*/
|
|
70
|
-
options:
|
|
48
|
+
options: SelectOption[];
|
|
71
49
|
/**
|
|
72
|
-
* Whether the select is disabled. Defaults to `false`.
|
|
50
|
+
* Whether the select field is disabled. Defaults to `false`.
|
|
73
51
|
*/
|
|
74
52
|
disabled?: boolean;
|
|
75
53
|
/**
|
|
76
|
-
* Whether the select
|
|
54
|
+
* Whether the select field should take up the full width of its container. Defaults to `false`.
|
|
77
55
|
*/
|
|
78
56
|
fullWidth?: boolean;
|
|
79
57
|
/**
|
|
80
|
-
* The placeholder
|
|
58
|
+
* The placeholder text to display when no option is selected. Defaults to `Select`.
|
|
81
59
|
*/
|
|
82
60
|
placeholder?: string;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Properties specific to single-select mode.
|
|
65
|
+
*/
|
|
66
|
+
export interface SingleSelectProps extends SelectBaseProps {
|
|
67
|
+
/**
|
|
68
|
+
* Whether the select accepts multiple options.
|
|
69
|
+
*/
|
|
70
|
+
multiple?: false;
|
|
83
71
|
/**
|
|
84
|
-
* The
|
|
72
|
+
* The default selected value.
|
|
73
|
+
*/
|
|
74
|
+
defaultValue?: string;
|
|
75
|
+
/**
|
|
76
|
+
* The maximum number of options that can be selected.
|
|
77
|
+
* This property has no effect in single-select mode.
|
|
78
|
+
*/
|
|
79
|
+
max?: never;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Properties specific to multi-select mode.
|
|
84
|
+
*/
|
|
85
|
+
export interface MultiSelectProps extends SelectBaseProps {
|
|
86
|
+
/**
|
|
87
|
+
* Whether the select accepts multiple options.
|
|
88
|
+
*/
|
|
89
|
+
multiple: true;
|
|
90
|
+
/**
|
|
91
|
+
* The default selected values.
|
|
92
|
+
*/
|
|
93
|
+
defaultValue?: string[];
|
|
94
|
+
/**
|
|
95
|
+
* The maximum number of options that can be selected.
|
|
85
96
|
*/
|
|
86
97
|
max?: number;
|
|
87
|
-
}
|
|
98
|
+
}
|
|
88
99
|
|
|
89
|
-
|
|
100
|
+
/**
|
|
101
|
+
* Union type representing all possible select component properties.
|
|
102
|
+
*/
|
|
103
|
+
export type Props = SingleSelectProps | MultiSelectProps;
|
|
90
104
|
|
|
91
105
|
const {
|
|
92
106
|
label,
|
|
@@ -102,7 +116,7 @@ const {
|
|
|
102
116
|
max = undefined,
|
|
103
117
|
} = Astro.props;
|
|
104
118
|
|
|
105
|
-
let selected:
|
|
119
|
+
let selected: SelectOption | (SelectOption | undefined)[] | undefined;
|
|
106
120
|
|
|
107
121
|
if (multiple && Array.isArray(defaultValue)) {
|
|
108
122
|
selected = defaultValue.map((x) => options.find((y) => y.value === x));
|
|
@@ -139,6 +153,7 @@ const defaultLabel = selected
|
|
|
139
153
|
aria-controls={`${name}-dropdown`}
|
|
140
154
|
aria-expanded="false"
|
|
141
155
|
id={`${name}-select-btn`}
|
|
156
|
+
tabindex={disabled ? -1 : 0}
|
|
142
157
|
type="button"
|
|
143
158
|
aria-label={placeholder}
|
|
144
159
|
title={placeholder}
|
|
@@ -183,7 +198,8 @@ const defaultLabel = selected
|
|
|
183
198
|
const isSelected = Array.isArray(selected)
|
|
184
199
|
? selected.map((y) => y && y.value).includes(x.value)
|
|
185
200
|
: selected?.value === x.value;
|
|
186
|
-
|
|
201
|
+
|
|
202
|
+
return (
|
|
187
203
|
<option
|
|
188
204
|
value={x.value}
|
|
189
205
|
selected={isSelected}
|
|
@@ -188,20 +188,11 @@ function loadSelects() {
|
|
|
188
188
|
} else {
|
|
189
189
|
if (lastActive) {
|
|
190
190
|
lastActive.classList.remove("selected");
|
|
191
|
-
const lastSelectOpt = container?.select?.querySelector(
|
|
192
|
-
`option[value='${lastActive.getAttribute("value")}']`
|
|
193
|
-
);
|
|
194
|
-
if (lastSelectOpt) {
|
|
195
|
-
lastSelectOpt.selected = false;
|
|
196
|
-
}
|
|
197
191
|
}
|
|
198
192
|
if (option) {
|
|
199
193
|
option.classList.add("selected");
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
);
|
|
203
|
-
if (selectOpt) {
|
|
204
|
-
selectOpt.selected = true;
|
|
194
|
+
if (container && container.select) {
|
|
195
|
+
container.select.value = option.getAttribute("value");
|
|
205
196
|
}
|
|
206
197
|
updateLabel(state2, container);
|
|
207
198
|
}
|
|
@@ -328,6 +319,7 @@ function loadSelects() {
|
|
|
328
319
|
}
|
|
329
320
|
});
|
|
330
321
|
for (const container of selects) {
|
|
322
|
+
if (container.dataset.initialized === "true") continue;
|
|
331
323
|
const id = container.dataset.id;
|
|
332
324
|
const specialContainer = Object.assign(container, {
|
|
333
325
|
button: container.querySelector("button"),
|
|
@@ -351,6 +343,7 @@ function loadSelects() {
|
|
|
351
343
|
});
|
|
352
344
|
handleBadgeOverflow(state, specialContainer);
|
|
353
345
|
}
|
|
346
|
+
container.dataset.initialized = "true";
|
|
354
347
|
}
|
|
355
348
|
}
|
|
356
349
|
document.addEventListener("astro:page-load", loadSelects);
|