fix(ui): defer select options and omit unused selection tags
This commit is contained in:
1 parent
61a4f01321
commit
9d90418490
4 files changed
+62
-6
No files matched your search
@@ -688,7 +688,7 @@
|
|||||||
},
|
},
|
||||||
"packages/ui": {
|
"packages/ui": {
|
||||||
"name": "@wrnexus/ui",
|
"name": "@wrnexus/ui",
|
||||||
"version": "0.8.63",
|
"version": "0.8.64",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@wrnexus/core": "workspace:*",
|
"@wrnexus/core": "workspace:*",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -304,7 +304,7 @@ component AdvancedSelect {
|
|||||||
aria-label="{selectedOptionsLabel}"
|
aria-label="{selectedOptionsLabel}"
|
||||||
data-show="multiple && selectedTemplate !== 'count' && selectedTemplate !== 'text' && selectedCount() > 0"
|
data-show="multiple && selectedTemplate !== 'count' && selectedTemplate !== 'text' && selectedCount() > 0"
|
||||||
>
|
>
|
||||||
{#each allOptions() as option}
|
{#each multiple && selectedTemplate !== 'count' && selectedTemplate !== 'text' ? selectedOptions() : [] as option}
|
||||||
<span data-show="isSelected(option)">
|
<span data-show="isSelected(option)">
|
||||||
{#if optionTemplate === "icon" && option.icon}<i class="{option.icon}" aria-hidden="true"></i>{/if}
|
{#if optionTemplate === "icon" && option.icon}<i class="{option.icon}" aria-hidden="true"></i>{/if}
|
||||||
{#if optionTemplate === "avatar" && option.avatar}<img src="{option.avatar}" alt="" />{/if}
|
{#if optionTemplate === "avatar" && option.avatar}<img src="{option.avatar}" alt="" />{/if}
|
||||||
@@ -371,7 +371,7 @@ component AdvancedSelect {
|
|||||||
role="listbox"
|
role="listbox"
|
||||||
aria-multiselectable="{multiple}"
|
aria-multiselectable="{multiple}"
|
||||||
>
|
>
|
||||||
{#each groups as group}
|
{#each open ? groups : [] as group}
|
||||||
{#if visibleOptions(group.options || []).length}
|
{#if visibleOptions(group.options || []).length}
|
||||||
<div class="wrn-next__option-group" role="group" aria-label="{group.label}">
|
<div class="wrn-next__option-group" role="group" aria-label="{group.label}">
|
||||||
<div class="wrn-next__group-label">{group.label}</div>
|
<div class="wrn-next__group-label">{group.label}</div>
|
||||||
@@ -402,7 +402,7 @@ component AdvancedSelect {
|
|||||||
{/if}
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
{#each visibleOptions(options) as option}
|
{#each open ? visibleOptions(options) : [] as option}
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="wrn-next__select-option {isSelected(option) ? 'wrn-next__select-option--selected' : ''} {optionIndex(option) === activeIndex ? 'wrn-next__select-option--active' : ''}"
|
class="wrn-next__select-option {isSelected(option) ? 'wrn-next__select-option--selected' : ''} {optionIndex(option) === activeIndex ? 'wrn-next__select-option--active' : ''}"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/ui",
|
"name": "@wrnexus/ui",
|
||||||
"version": "0.8.63",
|
"version": "0.8.64",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
|
|||||||
@@ -1910,6 +1910,61 @@ test("input number increments, decrements, applies steps, and respects limits",
|
|||||||
expect(decrement().disabled).toBe(true);
|
expect(decrement().disabled).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("advanced select keeps large closed lists compact and renders only selected tags", async () => {
|
||||||
|
const source = readFileSync(uiComponentPath("AdvancedSelect"), "utf8");
|
||||||
|
const options = Array.from({ length: 420 }, (_, i) => ({
|
||||||
|
value: String(i),
|
||||||
|
label: "Option " + i,
|
||||||
|
}));
|
||||||
|
const html = await renderComponent(source, {
|
||||||
|
name: "large",
|
||||||
|
value: "419",
|
||||||
|
options,
|
||||||
|
searchResultLimit: 40,
|
||||||
|
});
|
||||||
|
expect(Buffer.byteLength(html)).toBeLessThan(120_000);
|
||||||
|
const dom = mountHtml(html);
|
||||||
|
expect(dom.querySelectorAll(".wrn-next__select-option")).toHaveLength(0);
|
||||||
|
expect(dom.querySelectorAll(".wrn-next__select-tags > span")).toHaveLength(0);
|
||||||
|
expect(dom.querySelector(".wrn-next__select-value")?.textContent).toContain("Option 419");
|
||||||
|
(dom.querySelector(".wrn-next__select-trigger") as HTMLButtonElement).click();
|
||||||
|
expect(dom.querySelectorAll(".wrn-next__select-option")).toHaveLength(40);
|
||||||
|
(dom.querySelector(".wrn-next__select-trigger") as HTMLButtonElement).click();
|
||||||
|
expect(dom.querySelectorAll(".wrn-next__select-option")).toHaveLength(0);
|
||||||
|
|
||||||
|
const multi = mountHtml(
|
||||||
|
await renderComponent(source, {
|
||||||
|
name: "selected-tags",
|
||||||
|
multiple: true,
|
||||||
|
values: ["419"],
|
||||||
|
options,
|
||||||
|
searchResultLimit: 4,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
expect(multi.querySelectorAll(".wrn-next__select-tags > span")).toHaveLength(1);
|
||||||
|
expect(multi.querySelector(".wrn-next__select-tags")?.textContent).toContain("Option 419");
|
||||||
|
(multi.querySelector(".wrn-next__select-trigger") as HTMLButtonElement).click();
|
||||||
|
(multi.querySelector(".wrn-next__select-option") as HTMLButtonElement).click();
|
||||||
|
expect(multi.querySelectorAll(".wrn-next__select-tags > span")).toHaveLength(2);
|
||||||
|
(multi.querySelector(".wrn-next__clear-select") as HTMLButtonElement).click();
|
||||||
|
expect(multi.querySelectorAll(".wrn-next__select-tags > span")).toHaveLength(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("advanced select lazily opens grouped options and honors defaultOpen", async () => {
|
||||||
|
const source = readFileSync(uiComponentPath("AdvancedSelect"), "utf8");
|
||||||
|
const groups = [{ label: "Regions", options: [{ value: "in", label: "India" }] }];
|
||||||
|
const dom = mountHtml(await renderComponent(source, { name: "grouped", groups }));
|
||||||
|
expect(dom.querySelectorAll(".wrn-next__option-group")).toHaveLength(0);
|
||||||
|
(dom.querySelector(".wrn-next__select-trigger") as HTMLButtonElement).click();
|
||||||
|
expect(dom.querySelectorAll(".wrn-next__option-group")).toHaveLength(1);
|
||||||
|
(dom.querySelector(".wrn-next__select-option") as HTMLButtonElement).click();
|
||||||
|
expect((dom.querySelector('input[type="hidden"]') as HTMLInputElement).value).toBe("in");
|
||||||
|
const opened = mountHtml(
|
||||||
|
await renderComponent(source, { name: "opened", groups, defaultOpen: true }),
|
||||||
|
);
|
||||||
|
expect(opened.querySelectorAll(".wrn-next__select-option")).toHaveLength(1);
|
||||||
|
});
|
||||||
|
|
||||||
test("advanced select limits rendered options but searches the full dataset and retains saved values", async () => {
|
test("advanced select limits rendered options but searches the full dataset and retains saved values", async () => {
|
||||||
const source = readFileSync(uiComponentPath("AdvancedSelect"), "utf8");
|
const source = readFileSync(uiComponentPath("AdvancedSelect"), "utf8");
|
||||||
const dom = mountHtml(
|
const dom = mountHtml(
|
||||||
@@ -1921,8 +1976,9 @@ test("advanced select limits rendered options but searches the full dataset and
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
expect(dom.querySelector(".wrn-next__select-value")?.textContent).toContain("Region 99");
|
expect(dom.querySelector(".wrn-next__select-value")?.textContent).toContain("Region 99");
|
||||||
expect(dom.querySelectorAll(".wrn-next__select-option")).toHaveLength(4);
|
expect(dom.querySelectorAll(".wrn-next__select-option")).toHaveLength(0);
|
||||||
(dom.querySelector(".wrn-next__select-trigger") as HTMLButtonElement).click();
|
(dom.querySelector(".wrn-next__select-trigger") as HTMLButtonElement).click();
|
||||||
|
expect(dom.querySelectorAll(".wrn-next__select-option")).toHaveLength(4);
|
||||||
const search = dom.querySelector('input[type="search"]') as HTMLInputElement;
|
const search = dom.querySelector('input[type="search"]') as HTMLInputElement;
|
||||||
search.value = "Region 99";
|
search.value = "Region 99";
|
||||||
search.dispatchEvent(new (dom.window as any).Event("input", { bubbles: true }));
|
search.dispatchEvent(new (dom.window as any).Event("input", { bubbles: true }));
|
||||||
|
|||||||
Reference in new issue
Block a user