@keenmate/web-multiselect 2.0.1 → 2.2.0-rc01
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/README.md +15 -41
- package/component-variables.manifest.json +2 -1
- package/custom-elements.json +391 -28
- package/dist/index.d.ts +197 -14
- package/dist/multiselect.js +1444 -1209
- package/dist/multiselect.umd.js +12 -12
- package/dist/style.css +1 -1
- package/docs/examples.md +69 -0
- package/docs/usage.md +4 -0
- package/package.json +1 -1
- package/src/css/base.css +10 -0
- package/src/css/controls.css +6 -3
- package/src/css/options.css +55 -7
- package/src/css/variables.css +7 -0
- package/vscode.css-custom-data.json +5 -0
- package/vscode.html-custom-data.json +28 -2
- package/web-types.json +90 -11
package/README.md
CHANGED
|
@@ -21,50 +21,24 @@ Reads `--base-*` variables from the page if [`@keenmate/theme-designer`](https:/
|
|
|
21
21
|
- Custom rendering callbacks for options, badges, and group headers.
|
|
22
22
|
- Form integration via standard hidden inputs (FormData-compatible).
|
|
23
23
|
|
|
24
|
-
## What's New in v2.0
|
|
25
|
-
|
|
26
|
-
- **
|
|
27
|
-
- **
|
|
28
|
-
- **
|
|
29
|
-
- **
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
`null`/`undefined` to abort after a confirm dialog or server round-trip) and may return a
|
|
38
|
-
**rich option** that renders like any other. While it runs the prompt shows a spinner +
|
|
39
|
-
`add-new-pending-text`. Creation also works with no callback — handle it entirely off the `add`
|
|
40
|
-
event. See `examples-events-callbacks.html` §EV4b/EV4c.
|
|
41
|
-
|
|
42
|
-
- **Scroll-to imperative API — jump to any option or group.** New `scrollToIndex()` /
|
|
43
|
-
`scrollToValue()` / `scrollToGroup()` on the element and picker bring a row into view — pair with
|
|
44
|
-
`open()` for an "open + jump" gesture. Mode-aware (virtual scroll, tree, mobile fullscreen sheet),
|
|
45
|
-
they align to the top by default (`{ block: 'center' }` to center) and return `false` when the
|
|
46
|
-
target isn't in the current filtered list. A companion public `clearSearch()` reveals a
|
|
47
|
-
filtered-out option so you can then scroll to it, plus a `searchText` getter and a `search(term)`
|
|
48
|
-
method to read and programmatically drive the query. See §BU06b, §VS03, §TR09b.
|
|
49
|
-
|
|
50
|
-
- **Checkbox check/dash + filter funnel now flow from the shared `--base-icon-*` contract.** The
|
|
51
|
-
checkmark and indeterminate dash are now `currentColor` mask glyphs (not CSS-border shapes) reading
|
|
52
|
-
`--base-icon-check` / `--base-icon-indeterminate`, and the search-mode funnel reads
|
|
53
|
-
`--base-icon-filter` — so one base override reskins them across every Keenmate component. Inline
|
|
54
|
-
Lucide fallbacks keep the default look unchanged.
|
|
55
|
-
|
|
56
|
-
- **`--ms-rem` now bridges to the shared `--base-rem` knob.** The global sizing unit resolves
|
|
57
|
-
`var(--base-rem, 10px)`, so a theme that sets `--base-rem` rescales the whole component from one
|
|
58
|
-
variable (the `10px` fallback and per-instance overrides still work with no base layer loaded).
|
|
59
|
-
|
|
60
|
-
- **Fixed: the count-chip clear ✕ and popover close ✕ vanished on hover.** Both derived their hover
|
|
61
|
-
background *and* glyph colour from the same accent, so the ✕ melted into its own hover state
|
|
62
|
-
(fully invisible on near-white accents like Minimal dark). They now fill with a solid accent
|
|
63
|
-
background and flip the glyph to the on-accent colour, matching the badge remove button.
|
|
24
|
+
## What's New in v2.2.0-rc01
|
|
25
|
+
|
|
26
|
+
- **Tree cascade is now the default — check a branch, check its subtree** — In a multi-select tree, `checkbox-mode` now defaults to `cascade` (previously `independent`), so ticking a branch selects its whole subtree and branches render a tristate (checked / indeterminate / unchecked) box — what most tree-select UIs do. The emitted selection follows `cascade-select-policy` (default `rolled-up`: a fully-checked subtree collapses to its root value). This is a behavior change for existing tree consumers — set `checkbox-mode="independent"` to keep the old per-node toggling. Flat and single-select lists are unaffected, since there's no subtree to cascade into.
|
|
27
|
+
- **Per-group select-all in flat grouped lists — `group-select-mode="cascade"`** — A new attribute puts a tristate checkbox on each group header in a flat, multi-select, grouped list; clicking it checks or unchecks all of that group's currently-visible members. The group name itself is never a selected value — `getValue()`, badges, and form output carry member values only — a partially-selected group reads indeterminate, and a header toggle fires a single `change`. Disabled members are excluded from the select-all. Default `none` leaves headers inert, as before.
|
|
28
|
+
- **Per-group selected counts + one shared count formatter** — Every group header now shows a count of that group's selected members, rendered as the same small chip as the in-input `[N]` counter (not a new badge style). A new `getCountLabelCallback((selected, total) => string)` formats both the in-input counter and the group chip together so they always read the same way — default `[3]`, or return `` `${s}/${t}` `` for an "x / y of total" style, where `total` is the whole option list for the counter and the group's member count for a header.
|
|
29
|
+
- **Order the selected items — `selected-order`** — Control the sequence chosen items appear in across badges, partial "+N more", and the selected-items popover: `as-selected` (default), `label-asc` / `label-desc`, `member` (by a `selected-order-member` property or `getSelectedOrderCallback`), or `custom` (a comparator). It's display-only — `getValue()`, form output, and `getSelected()` keep insertion order — and because the ordering runs in one shared place, the partial "+N more" split and its remove button always act on the items sorted *after* the visible slice.
|
|
30
|
+
- **Every render callback now receives a context** — `renderGroupLabelContentCallback` gains a second `GroupLabelRenderContext` argument (the group's members and selection, e.g. `selectedCount`), and `renderSelectedItemContentCallback` / `renderSelectedContentCallback` now also receive a context carrying the presentation (`isFullscreen` / `isModal`) — matching the option and badge callbacks. Everything is additive, so existing one-argument callbacks keep working; branch on `isFullscreen` to render leaner content in the phone overlay.
|
|
31
|
+
- **Fixes — selection preservation, hidden search field, "+N more" ✕** — Changing a cosmetic attribute (`badges-display-mode` / `badges-position`) no longer wipes the current selection (it's applied in place, and genuine rebuilds now preserve the runtime selection); `search-input-mode="hidden"` no longer collapses the input row, so the toggle stays at the trailing edge; and the "+N more" badge's ✕ now removes exactly the hidden items instead of silently opening the popover.
|
|
32
|
+
|
|
33
|
+
## What's New in v2.1.0
|
|
34
|
+
|
|
35
|
+
- **Render gate — `defer` / `ready()` for flash-free initialization** — A custom element upgrades the instant its script loads and paints with the component's *default* styles, so anything you wire in afterward — a `customStylesCallback`, a framework's shared stylesheet, your options array — lands a beat too late and the badges visibly restyle: the classic custom-element flash. The new boolean `defer` attribute holds the entire first render: while it's set the element builds nothing (it only reserves space via `:host([defer]:not([is-ready]))`), so you assign options, callbacks and listeners first, then call `el.ready()` — or simply remove the attribute, which suits server-driven frameworks like Phoenix LiveView — to build once with everything already in place. The gate is latched, exposes an `el.isReady` getter reflected as an `is-ready` attribute, and fires a one-time `ready` event right after the first build. Elements without `defer` behave exactly as before.
|
|
36
|
+
- **External controls no longer close the dropdown they just re-drove** — Driving an already-open panel from your *own* button — a repeat `open()`/`toggle()`, or a `scrollToIndex()`/`scrollToValue()`/`scrollToGroup()` command — used to let that click bubble to the component's outside-click listener and immediately re-close the panel (the "every second click closes it" symptom). `open()` armed a one-tick guard against exactly this but bailed early when already open, and the `scrollTo*` methods never armed it at all. The guard is now centralized in `armClickGuard()` and armed by `open()` before its early-return and by every `scrollTo*` entry point. Consumers who worked around this with `stopPropagation()` can drop it.
|
|
64
37
|
|
|
65
38
|
## Demos & docs
|
|
66
39
|
|
|
67
|
-
- 🚀 [
|
|
40
|
+
- 🚀 [Showcase](https://web-multiselect.keenmate.dev)
|
|
41
|
+
- 🧪 [Live demo](https://examples.web-multiselect.keenmate.dev)
|
|
68
42
|
- 📘 [Usage / API reference](./docs/usage.md) — attributes, properties, methods, events.
|
|
69
43
|
- 🎨 [Theming](./docs/theming.md) — `--ms-*` variables, dark mode, cascade layers, Theme Designer integration.
|
|
70
44
|
- 📚 [Examples / cookbook](./docs/examples.md) — rich content, async search, virtual scroll, custom rendering, forms.
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
{ "name": "base-icon-plus", "required": false, "usage": "Plus glyph for the \"add new\" empty-state prompt; chained by --ms-icon-add-new; falls back to base-icon-add then inline Lucide SVG" },
|
|
65
65
|
{ "name": "base-icon-add", "required": false, "usage": "Alternate add glyph (fallback for base-icon-plus in the \"add new\" prompt)" },
|
|
66
66
|
{ "name": "base-icon-check", "required": false, "usage": "Checkbox/option checkmark glyph; chained by --ms-icon-check; inline Lucide SVG fallback" },
|
|
67
|
-
{ "name": "base-icon-check-size", "required": false, "usage": "mask-size for the checkbox glyph inside its box (shared with pure-admin's .pa-checkbox); default 68%. Also sizes the indeterminate dash (shares the mask box)" },
|
|
67
|
+
{ "name": "base-icon-check-size", "required": false, "usage": "mask-size for the checkbox glyph inside its box (shared with pure-admin's .pa-checkbox); default 68%. Chained by --ms-icon-check-size. Also sizes the indeterminate dash (shares the mask box)" },
|
|
68
68
|
{ "name": "base-icon-indeterminate", "required": false, "usage": "Tri-state (partial) checkbox dash glyph; chained by --ms-icon-indeterminate; inline Lucide SVG fallback" },
|
|
69
69
|
{ "name": "base-danger-bg", "required": false, "usage": "Error message background" },
|
|
70
70
|
{ "name": "base-danger-color", "required": false, "usage": "Error message text color" },
|
|
@@ -277,6 +277,7 @@
|
|
|
277
277
|
{ "name": "ms-icon-filter", "category": "icon", "usage": "Funnel glyph (fullscreen search-mode toggle); chains to --base-icon-filter" },
|
|
278
278
|
{ "name": "ms-icon-check", "category": "checkbox", "usage": "Checkmark glyph (mask) for a checked checkbox/option; chains to --base-icon-check" },
|
|
279
279
|
{ "name": "ms-icon-indeterminate", "category": "checkbox", "usage": "Dash glyph (mask) for a tri-state/partial checkbox; chains to --base-icon-indeterminate" },
|
|
280
|
+
{ "name": "ms-icon-check-size", "category": "checkbox", "usage": "mask-size for the checkmark/dash glyph inside the checkbox box; chains to --base-icon-check-size (default 68%, the same knob as pure-admin's .pa-checkbox)" },
|
|
280
281
|
{ "name": "ms-badge-counter-bg", "category": "badge", "usage": "Counter badge background" },
|
|
281
282
|
{ "name": "ms-badge-counter-border", "category": "badge", "usage": "Counter badge border" },
|
|
282
283
|
{ "name": "ms-badge-counter-border-color", "category": "badge", "usage": "Counter badge border color" },
|