@keenmate/web-multiselect 1.9.0 → 1.10.0
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 +25 -1
- package/component-variables.manifest.json +8 -5
- package/dist/index.d.ts +21 -2
- package/dist/multiselect.js +318 -269
- package/dist/multiselect.umd.js +7 -7
- package/dist/style.css +1 -1
- package/package.json +8 -3
- package/src/css/_badges-display.css +14 -4
- package/src/css/_input-dropdown.css +2 -2
- package/src/css/_tooltips-popover.css +11 -1
- package/src/css/_variables.css +9 -4
package/README.md
CHANGED
|
@@ -7,6 +7,28 @@ A lightweight, accessible multiselect web component with typeahead search, RTL l
|
|
|
7
7
|
|
|
8
8
|
> **⚠️ Security Notice:** This component intentionally allows raw HTML in rendering callbacks to give developers full control over content display. If you display user-generated content, you must sanitize it yourself. See [HTML Injection (XSS) Notice](#html-injection-xss-notice) for the complete list of affected callbacks.
|
|
9
9
|
|
|
10
|
+
## What's New in v1.10.0
|
|
11
|
+
|
|
12
|
+
- **`data-options` attribute on `<web-multiselect>`** — set options declaratively from HTML, no JS bootstrap required (works alongside `initial-values` for pure-HTML / server-rendered / SharePoint workbench scenarios).
|
|
13
|
+
- **`form.reset()` now clears the selection** — the element is now form-associated (`static formAssociated = true` + `ElementInternals` + `formResetCallback()`).
|
|
14
|
+
- **Dropdown / hint / selected popover no longer clipped inside scrollable ancestors** — Floating UI now uses `strategy: 'fixed'` for all three panels, so they escape `overflow: hidden|auto|scroll` containers (e.g. SharePoint Framework workbenches).
|
|
15
|
+
- **`initial-values` now works when options arrive after init** — values are reconciled on every `options` mutation, not just at construction.
|
|
16
|
+
- **Remove / close (×) buttons render as SVG masks** — pixel-centered regardless of font; color still flows through the existing `--ms-*-color` variables via `currentColor`; three new `--ms-*-icon-size` variables for theming.
|
|
17
|
+
- **Keyboard navigation now keeps working after a mouse click on an option** — previously, clicking an option moved focus from the search input to the option's checkbox (knocking the `keydown` listener offline) *and* left `focusedIndex` at its pre-click value, so subsequent ArrowDown / ArrowUp / Enter went nowhere visible. Click now anchors `focusedIndex` to the clicked option and refocuses the search input, so arrow keys continue from where you clicked and Enter toggles the option under the cursor.
|
|
18
|
+
- **Count-clear / popover-close hover backdrop now matches the rest of the component** — was a circle (`border-radius: 50%`), now a small rounded rectangle (`--ms-border-radius-sm`) consistent with every other interactive element. Themes that prefer the circle can set `--ms-count-clear-border-radius` and `--ms-selected-popover-close-border-radius` back to `50%`.
|
|
19
|
+
- **Keyboard `Enter` respects disabled options** — previously only the click handler did.
|
|
20
|
+
- **End-to-end test suite** — 114 Playwright specs across 19 fixture pages (`npm run test:e2e`).
|
|
21
|
+
- **`THEMING.md`** — new reference cataloguing every theme-able component state and the CSS variables that drive it.
|
|
22
|
+
|
|
23
|
+
## What's New in v1.9.0
|
|
24
|
+
|
|
25
|
+
- **Live attribute / callback updates no longer rebuild the DOM** — `updateOptions(partial)` merges in place; selection state, scroll position, focus, and tooltips are preserved across attribute changes.
|
|
26
|
+
- **9 previously-dead per-component CSS override hooks are now wired** — `--ms-hint-border-color`, `--ms-dropdown-border-color`, `--ms-actions-border-color`, `--ms-group-border-color`, `--ms-badge-counter-border-color`, `--ms-selected-popover-border-color`, `--ms-selected-popover-header-border-color`, `--ms-option-outline-color-focused`, `--ms-option-border-matched-color`.
|
|
27
|
+
- **`selectAll` / `clearAll` now fire per-item `selectCallback` / `deselectCallback`** — consumers wiring per-item analytics or side effects no longer silently miss bulk operations.
|
|
28
|
+
- **New `Tooltip` class** consolidating three previous tooltip implementations; fixes a handle leak and a popover-vs-main-container collision.
|
|
29
|
+
- **`--base-primary-bg` theming variable** — `--ms-primary-bg` reads it first, then `--base-main-bg`, then a hardcoded default.
|
|
30
|
+
- Plus many fixes across custom action buttons, grouped-option focus, badge cursors, focus rings, and logging.
|
|
31
|
+
|
|
10
32
|
## Features
|
|
11
33
|
|
|
12
34
|
- 📝 **Declarative HTML** - Use standard `<option>` and `<optgroup>` elements - no JavaScript required for simple cases!
|
|
@@ -1791,7 +1813,9 @@ For the complete list of all available CSS variables, see:
|
|
|
1791
1813
|
| `--ms-badge-font-size` | `0.75rem` | Badge font size |
|
|
1792
1814
|
| `--ms-badge-border-radius` | `0.375rem` | Badge border radius |
|
|
1793
1815
|
| `--ms-badge-remove-bg` | `var(--ms-accent-color)` | Remove button background |
|
|
1794
|
-
| `--ms-badge-remove-color` | `var(--ms-text-color-on-accent)` | Remove button color |
|
|
1816
|
+
| `--ms-badge-remove-color` | `var(--ms-text-color-on-accent)` | Remove button (X) color — applied to the SVG via `currentColor` |
|
|
1817
|
+
| `--ms-badge-remove-icon-size` | `calc(1.0 * var(--ms-rem))` | Size of the X glyph inside the remove button |
|
|
1818
|
+
| `--ms-icon-remove` | (inline SVG `url(...)`) | The X mask SVG; override to swap the glyph shape (alpha-only — color comes from `--ms-badge-remove-color`) |
|
|
1795
1819
|
| `--ms-badge-counter-text-bg` | `var(--ms-primary-bg)` | BadgeCounter text background ("+X more") |
|
|
1796
1820
|
| `--ms-badge-counter-text-color` | `var(--ms-text-color-3)` | BadgeCounter text color |
|
|
1797
1821
|
| `--ms-badge-counter-remove-bg` | `var(--ms-text-color-3)` | BadgeCounter remove button background |
|
|
@@ -270,10 +270,11 @@
|
|
|
270
270
|
{ "name": "ms-badge-remove-bg", "category": "badge", "usage": "Badge remove button background" },
|
|
271
271
|
{ "name": "ms-badge-remove-color", "category": "badge", "usage": "Badge remove button color" },
|
|
272
272
|
{ "name": "ms-badge-remove-border", "category": "badge", "usage": "Badge remove button border" },
|
|
273
|
-
{ "name": "ms-badge-remove-font-size", "category": "badge", "usage": "Badge remove button font size" },
|
|
273
|
+
{ "name": "ms-badge-remove-font-size", "category": "badge", "usage": "Badge remove button font size (unused since 1.10.0 — kept for backward-compat)" },
|
|
274
|
+
{ "name": "ms-badge-remove-icon-size", "category": "badge", "usage": "Badge remove X icon size (mask SVG)" },
|
|
274
275
|
{ "name": "ms-badge-remove-bg-hover", "category": "badge", "usage": "Badge remove button hover background" },
|
|
275
276
|
{ "name": "ms-badge-remove-box-shadow-focus", "category": "badge", "usage": "Badge remove button focus shadow" },
|
|
276
|
-
{ "name": "ms-icon-remove", "category": "badge", "usage": "Remove icon
|
|
277
|
+
{ "name": "ms-icon-remove", "category": "badge", "usage": "Remove icon as CSS url() to a mask-friendly SVG; color comes from currentColor" },
|
|
277
278
|
{ "name": "ms-badge-counter-bg", "category": "badge", "usage": "Counter badge background" },
|
|
278
279
|
{ "name": "ms-badge-counter-border", "category": "badge", "usage": "Counter badge border" },
|
|
279
280
|
{ "name": "ms-badge-counter-border-color", "category": "badge", "usage": "Counter badge border color" },
|
|
@@ -306,11 +307,12 @@
|
|
|
306
307
|
{ "name": "ms-count-clear-size", "category": "count", "usage": "Count clear button size" },
|
|
307
308
|
{ "name": "ms-count-clear-bg", "category": "count", "usage": "Count clear button background" },
|
|
308
309
|
{ "name": "ms-count-clear-color", "category": "count", "usage": "Count clear button color" },
|
|
309
|
-
{ "name": "ms-count-clear-font-size", "category": "count", "usage": "Count clear button font size" },
|
|
310
|
+
{ "name": "ms-count-clear-font-size", "category": "count", "usage": "Count clear button font size (unused since 1.10.0 — kept for backward-compat)" },
|
|
311
|
+
{ "name": "ms-count-clear-icon-size", "category": "count", "usage": "Count clear X icon size (mask SVG)" },
|
|
310
312
|
{ "name": "ms-count-clear-border-radius", "category": "count", "usage": "Count clear button border radius" },
|
|
311
313
|
{ "name": "ms-count-clear-bg-hover", "category": "count", "usage": "Count clear button hover background" },
|
|
312
314
|
{ "name": "ms-count-clear-color-hover", "category": "count", "usage": "Count clear button hover color" },
|
|
313
|
-
{ "name": "ms-icon-clear", "category": "count", "usage": "Clear icon
|
|
315
|
+
{ "name": "ms-icon-clear", "category": "count", "usage": "Clear icon as CSS url() to a mask-friendly SVG; defaults to var(--ms-icon-remove)" },
|
|
314
316
|
|
|
315
317
|
{ "name": "ms-tooltip-bg", "category": "tooltip", "usage": "Tooltip background" },
|
|
316
318
|
{ "name": "ms-tooltip-text-color", "category": "tooltip", "usage": "Tooltip text color" },
|
|
@@ -340,7 +342,8 @@
|
|
|
340
342
|
{ "name": "ms-popover-close-size", "category": "popover", "usage": "Popover close button size" },
|
|
341
343
|
{ "name": "ms-selected-popover-close-bg", "category": "popover", "usage": "Popover close button background" },
|
|
342
344
|
{ "name": "ms-selected-popover-close-color", "category": "popover", "usage": "Popover close button color" },
|
|
343
|
-
{ "name": "ms-selected-popover-close-font-size", "category": "popover", "usage": "Popover close button font size" },
|
|
345
|
+
{ "name": "ms-selected-popover-close-font-size", "category": "popover", "usage": "Popover close button font size (unused since 1.10.0 — kept for backward-compat)" },
|
|
346
|
+
{ "name": "ms-selected-popover-close-icon-size", "category": "popover", "usage": "Popover close X icon size (mask SVG)" },
|
|
344
347
|
{ "name": "ms-selected-popover-close-border-radius", "category": "popover", "usage": "Popover close button border radius" },
|
|
345
348
|
{ "name": "ms-selected-popover-close-bg-hover", "category": "popover", "usage": "Popover close button hover background" },
|
|
346
349
|
{ "name": "ms-selected-popover-close-color-hover", "category": "popover", "usage": "Popover close button hover color" },
|
package/dist/index.d.ts
CHANGED
|
@@ -194,7 +194,7 @@ declare interface MultiSelectConfig<T = any> {
|
|
|
194
194
|
isVirtualScrollEnabled?: boolean;
|
|
195
195
|
/** Vertical alignment of checkboxes relative to option content */
|
|
196
196
|
checkboxAlign?: 'top' | 'center' | 'bottom';
|
|
197
|
-
/** Hint text shown above the input
|
|
197
|
+
/** Hint text shown above the input while the dropdown is open. */
|
|
198
198
|
searchHint?: string;
|
|
199
199
|
/** Placeholder text for the search input */
|
|
200
200
|
searchPlaceholder?: string;
|
|
@@ -269,9 +269,11 @@ declare interface MultiSelectConfig<T = any> {
|
|
|
269
269
|
}
|
|
270
270
|
|
|
271
271
|
export declare class MultiSelectElement<T = any> extends BaseElement {
|
|
272
|
+
static formAssociated: boolean;
|
|
272
273
|
private picker?;
|
|
273
274
|
private containerElement?;
|
|
274
275
|
private shadow;
|
|
276
|
+
private internals?;
|
|
275
277
|
private _options?;
|
|
276
278
|
private _valueMember?;
|
|
277
279
|
private _getValueCallback?;
|
|
@@ -309,6 +311,14 @@ export declare class MultiSelectElement<T = any> extends BaseElement {
|
|
|
309
311
|
private _changeCallback?;
|
|
310
312
|
static get observedAttributes(): string[];
|
|
311
313
|
constructor();
|
|
314
|
+
/**
|
|
315
|
+
* Called by the browser when the surrounding <form> is reset. Clears the
|
|
316
|
+
* picker's selection so the multiselect actually participates in the
|
|
317
|
+
* standard reset lifecycle. (Before form-association, reset was a no-op
|
|
318
|
+
* because the hidden inputs were re-stamped from internal state on every
|
|
319
|
+
* render.)
|
|
320
|
+
*/
|
|
321
|
+
formResetCallback(): void;
|
|
312
322
|
connectedCallback(): void;
|
|
313
323
|
disconnectedCallback(): void;
|
|
314
324
|
attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void;
|
|
@@ -638,7 +648,7 @@ export declare class WebMultiSelect<T = any> {
|
|
|
638
648
|
private selectOption;
|
|
639
649
|
private deselectOption;
|
|
640
650
|
private selectAll;
|
|
641
|
-
|
|
651
|
+
clearAll(): void;
|
|
642
652
|
/**
|
|
643
653
|
* Re-render and fire callbacks after a selection state change.
|
|
644
654
|
* `added` / `removed` drive per-item select/deselect callbacks.
|
|
@@ -658,6 +668,15 @@ export declare class WebMultiSelect<T = any> {
|
|
|
658
668
|
private positionDropdown;
|
|
659
669
|
private positionHint;
|
|
660
670
|
private parseInitialSelection;
|
|
671
|
+
/**
|
|
672
|
+
* Resolve any `selectedValues` entries that don't yet have a matching
|
|
673
|
+
* `selectedOptions` object by looking them up in the current `allOptions`.
|
|
674
|
+
* Idempotent; safe to call after init *and* after `options` is replaced
|
|
675
|
+
* (e.g., async fetch, `searchCallback` result, or late `element.options =`
|
|
676
|
+
* assignment). Without this, `initial-values` declared before options
|
|
677
|
+
* arrive ends up with phantom values that `getValue()` can never report.
|
|
678
|
+
*/
|
|
679
|
+
private reconcileSelectedOptions;
|
|
661
680
|
private toggleSelectedPopover;
|
|
662
681
|
private showPopover;
|
|
663
682
|
private hideSelectedPopover;
|