@keenmate/web-multiselect 1.10.0 → 1.11.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 CHANGED
@@ -7,6 +7,17 @@ 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.11.0
11
+
12
+ - **OS-aware light/dark defaults via `light-dark()`** — set `color-scheme: dark` on your page (`:root`, `body`, etc.) and the multiselect picks readable dark text/background colors automatically. No more enumerating ~15 `--base-*` overrides just to get usable defaults on a dark theme.
13
+ - **Drift-detection warning for positioning edge cases** — if an exotic ancestor CSS property (e.g. `contain: paint`, or `container-type` in certain shadow-DOM layouts) makes the dropdown land somewhere other than where the library told the browser to put it, a `console.warn` fires once with the likely culprit element and an actionable fix suggestion.
14
+ - **Dropdown no longer stranded to the side when an ancestor uses `container-type`** — Floating UI was walking up to a `container-type: inline-size` ancestor (notably pure-admin's `.pa-layout__main`), but the browser wouldn't actually anchor the fixed panel there. The library now uses a custom `getOffsetParent` that only walks up properties browsers reliably honor for fixed positioning.
15
+ - **Dropdown no longer opens shifted to the side of its input** — when the dropdown's natural content was wider than the input, Floating UI's `shift()` middleware was measuring the unclamped panel and pushing it left, then the subsequent width clamp left it stranded next to the input. Panel sizing now happens before positioning. Same fix applies to the selected-items popover.
16
+ - **`--base-*` taxonomy aligned with KeenMate cross-component naming** (theming change — see CHANGELOG migration table): `--base-primary-bg` → `--base-hover-bg`, `--base-primary-bg-hover` → `--base-active-bg`. `--base-dropdown-bg` and `--base-tooltip-bg` continue to work; new chain fallbacks to `--base-elevated-bg` / `--base-inverse-bg`.
17
+ - **Option hover stays visible on dark themes** — `--ms-primary-bg` now mixes 8% of the text color into the main background by default, so the hover is always a visible step toward the text. No more invisible hover when the consumer forgets to override `--base-hover-bg`.
18
+ - **New `examples-positioning.html`** — walks through baseline / transformed-ancestor / container-type / drift-detection scenarios.
19
+ - **New dark-mode e2e suite** — 4 specs verifying WCAG-AA option contrast on a dark page across fully-themed, minimal-override, and pure OS-inheritance configurations.
20
+
10
21
  ## What's New in v1.10.0
11
22
 
12
23
  - **`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).
@@ -20,15 +31,6 @@ A lightweight, accessible multiselect web component with typeahead search, RTL l
20
31
  - **End-to-end test suite** — 114 Playwright specs across 19 fixture pages (`npm run test:e2e`).
21
32
  - **`THEMING.md`** — new reference cataloguing every theme-able component state and the CSS variables that drive it.
22
33
 
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
-
32
34
  ## Features
33
35
 
34
36
  - 📝 **Declarative HTML** - Use standard `<option>` and `<optgroup>` elements - no JavaScript required for simple cases!
@@ -1662,8 +1664,9 @@ KeenMate components support a **two-layer theming architecture**:
1662
1664
  :root {
1663
1665
  /* Base layer - single source of truth */
1664
1666
  --base-accent-color: #3b82f6;
1665
- --base-primary-bg: #ffffff;
1666
- --base-text-primary: #111827;
1667
+ --base-main-bg: #ffffff;
1668
+ --base-hover-bg: #f3f4f6;
1669
+ --base-text-color-1: #111827;
1667
1670
 
1668
1671
  /* Components reference base layer */
1669
1672
  --ms-accent-color: var(--base-accent-color);
@@ -1788,7 +1791,7 @@ For the complete list of all available CSS variables, see:
1788
1791
 
1789
1792
  | Variable | Default | Description |
1790
1793
  |----------|---------|-------------|
1791
- | `--ms-dropdown-bg` | `var(--base-dropdown-bg, #ffffff)` | Dropdown background |
1794
+ | `--ms-dropdown-bg` | `var(--base-dropdown-bg, var(--base-elevated-bg, light-dark(#ffffff, #1a1a1a)))` | Dropdown background (auto-adapts to OS dark mode) |
1792
1795
  | `--ms-dropdown-border` | `var(--ms-border-color)` | Dropdown border color |
1793
1796
  | `--ms-dropdown-shadow` | (box shadow) | Dropdown shadow |
1794
1797
  | `--ms-dropdown-max-height` | `20rem` | Max height of dropdown |
@@ -1860,7 +1863,7 @@ For the complete list of all available CSS variables, see:
1860
1863
 
1861
1864
  | Variable | Default | Description |
1862
1865
  |----------|---------|-------------|
1863
- | `--ms-tooltip-bg` | `var(--base-tooltip-bg, #333333)` | Tooltip background color |
1866
+ | `--ms-tooltip-bg` | `var(--base-tooltip-bg, var(--base-inverse-bg, light-dark(#333333, #f5f5f5)))` | Tooltip background (auto-adapts to OS dark mode) |
1864
1867
  | `--ms-tooltip-color` | `var(--ms-tooltip-text-color)` | Tooltip text color |
1865
1868
  | `--ms-tooltip-padding` | `0.5rem 0.75rem` | Tooltip padding |
1866
1869
  | `--ms-tooltip-border-radius` | `0.375rem` | Tooltip border radius |
@@ -14,7 +14,8 @@
14
14
  { "name": "base-text-color-4", "required": false, "usage": "Quaternary text (placeholders)" },
15
15
  { "name": "base-text-color-on-accent", "required": false, "usage": "Text on accent backgrounds (badges, checkboxes)" },
16
16
  { "name": "base-main-bg", "required": true, "usage": "Primary background, hint background, actions background" },
17
- { "name": "base-hover-bg", "required": false, "usage": "Hover states for options, badges, buttons" },
17
+ { "name": "base-hover-bg", "required": false, "usage": "Hover background (drives --ms-primary-bg: option hover/focus, action-button hover, counter hover)" },
18
+ { "name": "base-active-bg", "required": false, "usage": "Active/pressed background (drives --ms-primary-bg-hover: selected-active, counter badge)" },
18
19
  { "name": "base-disabled-bg", "required": false, "usage": "Disabled/readonly surface backgrounds" },
19
20
  { "name": "base-border-color", "required": true, "usage": "Input, dropdown, action button borders" },
20
21
  { "name": "base-border", "required": false, "usage": "Full border shorthand" },
@@ -25,10 +26,12 @@
25
26
  { "name": "base-input-border-focus", "required": false, "usage": "Input border when focused" },
26
27
  { "name": "base-input-placeholder-color", "required": false, "usage": "Placeholder text color" },
27
28
  { "name": "base-input-bg-disabled", "required": false, "usage": "Disabled input background" },
28
- { "name": "base-dropdown-bg", "required": false, "usage": "Dropdown and popover backgrounds" },
29
+ { "name": "base-dropdown-bg", "required": false, "usage": "Dropdown and popover backgrounds (primary; falls back to base-elevated-bg)" },
30
+ { "name": "base-elevated-bg", "required": false, "usage": "Elevated surface (fallback for dropdown and popover backgrounds)" },
29
31
  { "name": "base-dropdown-border", "required": false, "usage": "Dropdown border" },
30
32
  { "name": "base-dropdown-box-shadow", "required": false, "usage": "Dropdown shadow" },
31
- { "name": "base-tooltip-bg", "required": false, "usage": "Tooltip background" },
33
+ { "name": "base-tooltip-bg", "required": false, "usage": "Tooltip background (primary; falls back to base-inverse-bg)" },
34
+ { "name": "base-inverse-bg", "required": false, "usage": "Inverse surface (fallback for tooltip background)" },
32
35
  { "name": "base-tooltip-text-color", "required": false, "usage": "Tooltip text color" },
33
36
  { "name": "base-font-family", "required": false, "usage": "All text in component" },
34
37
  { "name": "base-font-size-2xs", "required": false, "usage": "Smallest text (multiplier)" },
@@ -69,8 +72,8 @@
69
72
  { "name": "ms-text-primary", "category": "text", "usage": "Legacy alias for text-color-1" },
70
73
  { "name": "ms-text-secondary", "category": "text", "usage": "Legacy alias for text-color-3" },
71
74
 
72
- { "name": "ms-primary-bg", "category": "surface", "usage": "Primary background color" },
73
- { "name": "ms-primary-bg-hover", "category": "surface", "usage": "Primary background hover" },
75
+ { "name": "ms-primary-bg", "category": "surface", "usage": "Hover/focus background (options, action buttons, counter); reads --base-hover-bg" },
76
+ { "name": "ms-primary-bg-hover", "category": "surface", "usage": "Active/stronger background (counter badge text); reads --base-active-bg" },
74
77
 
75
78
  { "name": "ms-border-color", "category": "border", "usage": "Default border color" },
76
79
  { "name": "ms-border", "category": "border", "usage": "Full border shorthand" },
package/dist/index.d.ts CHANGED
@@ -553,6 +553,7 @@ export declare class WebMultiSelect<T = any> {
553
553
  private isRTL;
554
554
  private effectiveBadgesPosition;
555
555
  private justClosedViaClick;
556
+ private positioningDriftWarned;
556
557
  private dropdownCleanup;
557
558
  private hintCleanup;
558
559
  private selectedPopoverCleanup;
@@ -665,6 +666,18 @@ export declare class WebMultiSelect<T = any> {
665
666
  * compute then lock the resulting placement, optionally clamp by dropdownMin/MaxWidth.
666
667
  */
667
668
  private anchorFloatingPanel;
669
+ /**
670
+ * Sanity-check that the browser placed the panel where we told it to. With `position: fixed`
671
+ * and no transformed/perspective/filter ancestor, `left: ${x}px` must render at viewport-x = x.
672
+ * If the rendered position drifts, the consumer has an ancestor that establishes a fixed
673
+ * containing block but isn't on our reliable-anchors list (likely `contain: paint|layout|strict`
674
+ * or `container-type` — which the spec says creates a CB but the browser's actual behavior
675
+ * varies across shadow-DOM scenarios). We can't fix it from inside the library, but we can
676
+ * surface a clear warning so the developer knows where to look.
677
+ *
678
+ * Fires at most once per multiselect instance to avoid flooding the console during autoUpdate.
679
+ */
680
+ private verifyPanelLanded;
668
681
  private positionDropdown;
669
682
  private positionHint;
670
683
  private parseInitialSelection;