Let a multi-select say what a capped list left out, inside the panel
CI / full-gate (push) Successful in 2m52s

This commit is contained in:
2026-08-25 09:15:30 +02:00
parent c702a347dc
commit f4693af3df
2 changed files with 7 additions and 3 deletions
+2 -1
View File
@@ -41,6 +41,7 @@ const config = {
type: "multiselect",
name: "owner",
legend: "Owner",
note: "30 of 45",
value: ["ann"],
options: [{ value: "ann", label: "Ann Berg" }, { value: "bo", label: "Bo Falk" }],
},
@@ -75,7 +76,7 @@ test("filter-bar renders a GET form with every control type, reflecting current
// multiselect — a disclosure: the trigger names the filter and counts what is chosen, the options
// are checkboxes in a fieldset the popover holds, so a long list costs one line of the bar.
assert.match(html, /<div class="menu"><button class="btn btn-menu" type="button" popovertarget="f-owner-menu" aria-label="Owner, 1 selected">Owner<span class="badge">1<\/span><\/button><div id="f-owner-menu" class="menu-pop left" popover>/);
assert.match(html, /<fieldset class="menu-field"><legend class="menu-head">Owner<\/legend><label class="menu-check"><input type="checkbox" name="owner" value="ann" checked>Ann Berg<\/label><label class="menu-check"><input type="checkbox" name="owner" value="bo">Bo Falk<\/label><\/fieldset>/);
assert.match(html, /popover><div class="menu-head">30 of 45<\/div><fieldset class="menu-field"><legend class="menu-head">Owner<\/legend><label class="menu-check"><input type="checkbox" name="owner" value="ann" checked>Ann Berg<\/label><label class="menu-check"><input type="checkbox" name="owner" value="bo">Bo Falk<\/label><\/fieldset>/);
// Nothing chosen — no badge and no count in the accessible name.
assert.match(html, /<button class="btn btn-menu" type="button" popovertarget="f-room-menu">Room<\/button>/);
+5 -2
View File
@@ -7,7 +7,7 @@
segmented { name, legend?, value?, options:{value,label,count?}[] } (radios)
select { name, label, value?, options:{value,label}[] }
chips { name, legend?, value?:string[], options:{value,label}[] } (checkboxes)
multiselect { name, legend?, value?:string[], options:{value,label}[] } (checkboxes in a popover)
multiselect { name, legend?, note?, value?:string[], options:{value,label}[] } (checkboxes in a popover)
daterange { legend?, from:{name,value?,label?}, to:{name,value?,label?} }
The form is a GET, which replaces the whole query string — so the visitor's chosen language rides
along as a hidden input, and every href here (pills, clear) is run through localeHref.
@@ -40,7 +40,10 @@
id: "f-" + c.name + "-menu",
align: "left", kebab: false, up: false, width: null, // explicit: EJS would otherwise inherit the page's own
trigger: { class: "btn btn-menu", count: on.length || null, label: on.length ? t("filter.selected", { count: on.length, label: legend }) : null, text: legend },
items: [{ group: { legend, name: c.name, options: c.options.map((o) => ({ checked: on.includes(String(o.value)), label: o.label, value: o.value })) } }],
items: [
...(c.note ? [{ head: c.note }] : []),
{ group: { legend, name: c.name, options: c.options.map((o) => ({ checked: on.includes(String(o.value)), label: o.label, value: o.value })) } },
],
}) %>
<% } else if (c.type === "daterange") { -%>
<fieldset class="filter-field"><legend class="sr-only"><%= c.legend || t("filter.dateRange") %></legend><span class="filter-legend" aria-hidden="true"><%= c.legend || t("filter.dateRange") %></span><div class="daterange"><svg class="ico ico-sm" aria-hidden="true"><use href="#i-cal"/></svg><label class="sr-only" for="f-<%= c.from.name %>"><%= c.from.label || t("filter.from") %></label><input type="date" id="f-<%= c.from.name %>" name="<%= c.from.name %>"<% if (c.from.value) { %> value="<%= c.from.value %>"<% } %>><span class="to" aria-hidden="true"><%= t("filter.toSeparator") %></span><label class="sr-only" for="f-<%= c.to.name %>"><%= c.to.label || t("filter.to") %></label><input type="date" id="f-<%= c.to.name %>" name="<%= c.to.name %>"<% if (c.to.value) { %> value="<%= c.to.value %>"<% } %>></div></fieldset>