@studiocms/ui 0.4.16 → 0.4.17

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.
@@ -154,31 +154,33 @@ const defaultLabel = selected
154
154
  />
155
155
  <Icon name="chevron-up-down" class="sui-search-select-indicator" width={24} height={24} />
156
156
  </div>
157
- <ul class="sui-search-select-dropdown" role="listbox" id={`${name}-dropdown`}>
158
- {
159
- options.map((x, i) => {
160
- const isSelected = Array.isArray(selected)
161
- ? selected.map((y) => y && y.value).includes(x.value)
162
- : selected?.value === x.value;
163
- return (
164
- <li
165
- class="sui-search-select-option"
166
- role="option"
167
- value={x.value}
168
- class:list={[
169
- isSelected && `selected`,
170
- x.disabled && "disabled"
171
- ]}
172
- id={isSelected ? `${name}-selected` : ""}
173
- data-option-index={i}
174
- data-value={x.value}
175
- >
176
- {x.label}
177
- </li>
178
- )
179
- })
180
- }
181
- </ul>
157
+ <div class="sui-search-select-dropdown">
158
+ <ul class="sui-search-select-dropdown-list" role="listbox" id={`${name}-dropdown`}>
159
+ {
160
+ options.map((x, i) => {
161
+ const isSelected = Array.isArray(selected)
162
+ ? selected.map((y) => y && y.value).includes(x.value)
163
+ : selected?.value === x.value;
164
+ return (
165
+ <li
166
+ class="sui-search-select-option"
167
+ role="option"
168
+ value={x.value}
169
+ class:list={[
170
+ isSelected && `selected`,
171
+ x.disabled && "disabled"
172
+ ]}
173
+ id={isSelected ? `${name}-selected` : ""}
174
+ data-option-index={i}
175
+ data-value={x.value}
176
+ >
177
+ {x.label}
178
+ </li>
179
+ )
180
+ })
181
+ }
182
+ </ul>
183
+ </div>
182
184
  </div>
183
185
  <select class="sui-hidden-search-select" id={name} name={name} required={isRequired} multiple={multiple ? "" : undefined} hidden tabindex="-1">
184
186
  <option value={""}> Select </option>
@@ -32,19 +32,25 @@
32
32
  .sui-search-select-dropdown {
33
33
  position: absolute;
34
34
  width: 100%;
35
- border: 1px solid hsl(var(--border));
36
- list-style: none;
37
- margin: 0;
38
- padding: 0;
39
- flex-direction: column;
40
- border-radius: var(--radius-md);
41
- background-color: hsl(var(--background-step-2));
42
- overflow: hidden;
43
35
  top: calc(100% + 0.25rem);
44
36
  left: 0;
45
37
  display: none;
38
+ max-height: 300px;
39
+ border: 1px solid hsl(var(--border));
40
+ border-radius: var(--radius-md);
41
+ background-color: hsl(var(--background-step-2));
46
42
  z-index: 90;
47
43
  box-shadow: 0px 4px 8px hsl(var(--shadow), 0.5);
44
+ overflow: hidden;
45
+ }
46
+ .sui-search-select-dropdown-list {
47
+ width: 100%;
48
+ list-style: none;
49
+ margin: 0;
50
+ padding: 0;
51
+ flex-direction: column;
52
+ overflow-y: auto;
53
+ scrollbar-color: hsl(var(--border)) hsl(var(--background-step-2));
48
54
  }
49
55
  .sui-search-select-dropdown.above {
50
56
  top: auto;
@@ -105,7 +111,6 @@
105
111
  position: absolute;
106
112
  bottom: .675rem;
107
113
  right: .675rem;
108
- pointer-events: none;
109
114
  }
110
115
  .sui-search-input-wrapper:has(input:focus) + .sui-search-select-dropdown {
111
116
  display: flex;
@@ -82,7 +82,7 @@ function loadSearchSelects() {
82
82
  );
83
83
  if (option) {
84
84
  option.classList.toggle("selected", forceState ?? !isCurrentlySelected);
85
- if (container && container.select) {
85
+ if (container?.select) {
86
86
  container.select.value = option.getAttribute("value");
87
87
  }
88
88
  }
@@ -150,6 +150,26 @@ function loadSearchSelects() {
150
150
  if (!target.closest("input")) {
151
151
  e.preventDefault();
152
152
  }
153
+ if (container.input?.value.length === 0) {
154
+ reconstructOptions(state2.optionsMap[container.dataset.id] ?? [], state2, container);
155
+ }
156
+ if (target.closest(".sui-search-select-indicator")) {
157
+ if (container.dropdown?.parentElement?.classList.contains("active")) {
158
+ container.dropdown?.parentElement?.classList.remove("active", "above");
159
+ container.input?.blur();
160
+ container.input.value = "";
161
+ } else {
162
+ container.dropdown?.parentElement?.classList.add("active");
163
+ container.input?.focus();
164
+ container.input.value = "";
165
+ }
166
+ return;
167
+ }
168
+ if (target.closest(".sui-search-select-badge-container")) {
169
+ container.dropdown?.parentElement?.classList.remove("active", "above");
170
+ container.input?.blur();
171
+ container.input.value = "";
172
+ }
153
173
  state2.isSelectingOption = true;
154
174
  setTimeout(() => {
155
175
  state2.isSelectingOption = false;
@@ -182,7 +202,7 @@ function loadSearchSelects() {
182
202
  }
183
203
  updateOptionSelection(opt.dataset.value, container, state2, true);
184
204
  updateLabel(false, state2, container);
185
- container.dropdown?.classList.remove("active", "above");
205
+ container.dropdown?.parentElement?.classList.remove("active", "above");
186
206
  container.input?.blur();
187
207
  container.input.value = "";
188
208
  }
@@ -191,7 +211,7 @@ function loadSearchSelects() {
191
211
  const focusedElement = document.activeElement;
192
212
  if (e.key === "Escape" || e.key === "Tab") {
193
213
  container.input?.blur();
194
- container.dropdown?.classList.remove("active", "above");
214
+ container.dropdown?.parentElement?.classList.remove("active", "above");
195
215
  return;
196
216
  }
197
217
  if ((e.key === "Enter" || e.key === " ") && focusedElement?.tagName.toLowerCase() === "svg") {
@@ -278,7 +298,7 @@ function loadSearchSelects() {
278
298
  }
279
299
  updateOptionSelection(value, container, state2, true);
280
300
  updateLabel(false, state2, container);
281
- container.dropdown?.classList.remove("active", "above");
301
+ container.dropdown?.parentElement?.classList.remove("active", "above");
282
302
  container.input.value = "";
283
303
  }
284
304
  }
@@ -301,20 +321,20 @@ function loadSearchSelects() {
301
321
  if (state2.isSelectingOption) return;
302
322
  container.input.value = "";
303
323
  reconstructOptions(state2.optionsMap[container.dataset.id] ?? [], state2, container);
304
- container.dropdown?.classList.remove("active", "above");
324
+ container.dropdown?.parentElement?.classList.remove("active", "above");
305
325
  };
306
326
  const handleContainerFocusIn = (state2, container) => {
307
- const allDropdowns = document.querySelectorAll(".sui-search-select-dropdown");
327
+ const allDropdowns = document.querySelectorAll(".sui-search-select-dropdown-list");
308
328
  for (const dropdown of allDropdowns) {
309
329
  if (dropdown !== container.dropdown) {
310
- dropdown.classList.remove("active", "above");
330
+ dropdown.parentElement?.classList.remove("active", "above");
311
331
  }
312
332
  }
313
333
  const { isAbove } = getDropdownPosition(
314
334
  container.input,
315
335
  state2.optionsMap[container.dataset.id]?.length ?? 0
316
336
  );
317
- container.dropdown?.classList.add("active", ...isAbove ? [] : ["above"]);
337
+ container.dropdown?.parentElement?.classList.add("active", ...isAbove ? [] : ["above"]);
318
338
  };
319
339
  const state = {
320
340
  optionsMap: {},
@@ -330,7 +350,7 @@ function loadSearchSelects() {
330
350
  const id = container.dataset.id;
331
351
  const specialContainer = Object.assign(container, {
332
352
  input: container.querySelector("input"),
333
- dropdown: container.querySelector(".sui-search-select-dropdown"),
353
+ dropdown: container.querySelector(".sui-search-select-dropdown-list"),
334
354
  select: container.querySelector("select")
335
355
  });
336
356
  const selectedOptions = Array.from(
@@ -166,30 +166,32 @@ const defaultLabel = selected
166
166
  </span>
167
167
  <Icon name="chevron-up-down" width={24} height={24} class="sui-select-chevron" />
168
168
  </button>
169
- <ul class="sui-select-dropdown" role="listbox" id={`${name}-dropdown`}>
170
- {
171
- options.map((x, i) => {
172
- const isSelected = Array.isArray(selected)
173
- ? selected.map((y) => y && y.value).includes(x.value)
174
- : selected?.value === x.value;
175
- return (
176
- <li
177
- class="sui-select-option"
178
- role="option"
179
- value={x.value}
180
- class:list={[
181
- isSelected && `selected`,
182
- x.disabled && "disabled",
183
- ]}
184
- id={isSelected ? `${name}-selected` : ""}
185
- data-option-index={i}
186
- >
187
- {x.label}
188
- </li>
189
- )
190
- })
191
- }
192
- </ul>
169
+ <div class="sui-select-dropdown">
170
+ <ul class="sui-select-dropdown-list" role="listbox" id={`${name}-dropdown`}>
171
+ {
172
+ options.map((x, i) => {
173
+ const isSelected = Array.isArray(selected)
174
+ ? selected.map((y) => y && y.value).includes(x.value)
175
+ : selected?.value === x.value;
176
+ return (
177
+ <li
178
+ class="sui-select-option"
179
+ role="option"
180
+ value={x.value}
181
+ class:list={[
182
+ isSelected && `selected`,
183
+ x.disabled && "disabled",
184
+ ]}
185
+ id={isSelected ? `${name}-selected` : ""}
186
+ data-option-index={i}
187
+ >
188
+ {x.label}
189
+ </li>
190
+ )
191
+ })
192
+ }
193
+ </ul>
194
+ </div>
193
195
  </div>
194
196
  <select class="sui-hidden-select" id={name} name={name} required={isRequired} multiple={multiple ? "" : undefined} hidden tabindex="-1">
195
197
  <option value={""}> Select </option>
@@ -70,19 +70,25 @@
70
70
  .sui-select-dropdown {
71
71
  position: absolute;
72
72
  width: 100%;
73
- border: 1px solid hsl(var(--border));
74
- list-style: none;
75
- margin: 0;
76
- padding: 0;
77
- flex-direction: column;
78
- border-radius: var(--radius-md);
79
- background-color: hsl(var(--background-step-2));
80
- overflow: hidden;
81
73
  top: calc(100% + 0.25rem);
82
74
  left: 0;
83
75
  display: none;
76
+ max-height: 300px;
77
+ border: 1px solid hsl(var(--border));
78
+ border-radius: var(--radius-md);
79
+ background-color: hsl(var(--background-step-2));
84
80
  z-index: 90;
85
81
  box-shadow: 0px 4px 8px hsl(var(--shadow), 0.5);
82
+ overflow: hidden;
83
+ }
84
+ .sui-select-dropdown-list {
85
+ width: 100%;
86
+ list-style: none;
87
+ margin: 0;
88
+ padding: 0;
89
+ flex-direction: column;
90
+ overflow-y: auto;
91
+ scrollbar-color: hsl(var(--border)) hsl(var(--background-step-2));
86
92
  }
87
93
  .sui-select-dropdown.active {
88
94
  display: flex;
@@ -191,7 +191,7 @@ function loadSelects() {
191
191
  }
192
192
  if (option) {
193
193
  option.classList.add("selected");
194
- if (container && container.select) {
194
+ if (container?.select) {
195
195
  container.select.value = option.getAttribute("value");
196
196
  }
197
197
  updateLabel(state2, container);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@studiocms/ui",
3
- "version": "0.4.16",
3
+ "version": "0.4.17",
4
4
  "description": "The UI library for StudioCMS. Includes the layouts & components we use to build StudioCMS.",
5
5
  "repository": {
6
6
  "type": "git",