@keenmate/pure-admin-core 2.4.0 → 2.5.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.
Files changed (44) hide show
  1. package/README.md +11 -6
  2. package/dist/css/main.css +47 -130
  3. package/package.json +1 -1
  4. package/snippets/AUDIT.md +94 -0
  5. package/snippets/alerts.html +264 -89
  6. package/snippets/badges.html +193 -61
  7. package/snippets/buttons.html +178 -0
  8. package/snippets/callouts.html +210 -129
  9. package/snippets/cards.html +383 -200
  10. package/snippets/checkbox-lists.html +199 -65
  11. package/snippets/code.html +55 -11
  12. package/snippets/command-palette.html +401 -111
  13. package/snippets/comparison.html +144 -93
  14. package/snippets/customization.html +311 -104
  15. package/snippets/data-display.html +584 -0
  16. package/snippets/detail-panel.html +470 -138
  17. package/snippets/filter-card.html +246 -0
  18. package/snippets/forms.html +408 -308
  19. package/snippets/grid.html +253 -141
  20. package/snippets/layout.html +379 -480
  21. package/snippets/lists.html +144 -47
  22. package/snippets/loaders.html +64 -39
  23. package/snippets/manifest.json +330 -280
  24. package/snippets/modal-dialogs.html +137 -64
  25. package/snippets/modals.html +221 -151
  26. package/snippets/notifications.html +285 -0
  27. package/snippets/popconfirm.html +213 -19
  28. package/snippets/profile.html +290 -330
  29. package/snippets/statistics.html +247 -0
  30. package/snippets/tables.html +359 -150
  31. package/snippets/tabs.html +129 -45
  32. package/snippets/timeline.html +123 -56
  33. package/snippets/toasts.html +179 -31
  34. package/snippets/tooltips.html +199 -81
  35. package/snippets/typography.html +183 -58
  36. package/snippets/utilities.html +511 -415
  37. package/snippets/virtual-scroll.html +201 -75
  38. package/snippets/web-daterangepicker.html +369 -189
  39. package/snippets/web-multiselect.html +360 -124
  40. package/src/scss/core-components/_alerts.scss +51 -12
  41. package/src/scss/core-components/_pagers.scss +1 -1
  42. package/src/scss/core-components/_popconfirm.scss +35 -13
  43. package/src/scss/core-components/_tables.scss +2 -134
  44. package/src/scss/variables/_components.scss +17 -2
@@ -1,9 +1,33 @@
1
- <!-- Web Multiselect Component
2
- Advanced multiselect web component from @keenmate/web-multiselect
3
- Framework-agnostic, TypeScript-based web component with excellent performance
4
- Repository: https://github.com/keenmate/web-multiselect
1
+ <!-- ================================
2
+ WEB MULTISELECT
3
+ A framework-agnostic web component from @keenmate/web-multiselect
4
+ (separate package; not part of pure-admin-core's CSS).
5
+
6
+ Pure Admin's role: themes export ~45 --base-* CSS variables (see
7
+ _base-css-variables.scss + _web-components-theme.scss bridge).
8
+ The component reads them via fallback chains:
9
+
10
+ 1. Page override : web-multiselect { --ms-accent-color: … }
11
+ 2. Theme base value: var(--base-accent-color)
12
+ 3. Hardcoded default: built into the component
13
+
14
+ So in a Pure Admin app you usually do NOT override --ms-* — the
15
+ theme already cascades. Override --ms-* only for one-off
16
+ instance-specific tweaks. Pure Admin also sets two group-label
17
+ overrides directly in _web-components-theme.scss:
18
+ web-multiselect {
19
+ --ms-group-label-color: var(--base-text-color-1);
20
+ --ms-group-label-font-weight: 600;
21
+ }
22
+
23
+ Note on the rem base: the component exposes --ms-rem (default 10px)
24
+ which matches Pure Admin's html { font-size: 10px } perfectly —
25
+ all internal sizing scales together with the surrounding UI.
26
+
5
27
  Package: npm install @keenmate/web-multiselect
6
- -->
28
+ Repo: https://github.com/keenmate/web-multiselect
29
+ Auto-registers as <web-multiselect> on import.
30
+ ================================ -->
7
31
 
8
32
  <!-- ========================================
9
33
  BASIC USAGE
@@ -28,33 +52,35 @@
28
52
  DISPLAY MODES
29
53
  ======================================== -->
30
54
 
31
- <!-- Pills Mode (Default) - Individual badges -->
32
- <web-multiselect badges-display-mode="pills" placeholder="Select...">
55
+ <!-- badges (default) - one badge per selected item -->
56
+ <web-multiselect badges-display-mode="badges" placeholder="Select...">
33
57
  <option value="1" selected>Option 1</option>
34
58
  <option value="2" selected>Option 2</option>
35
59
  </web-multiselect>
36
60
 
37
- <!-- Count Mode - "X selected" counter -->
61
+ <!-- count - "X selected" counter only -->
38
62
  <web-multiselect badges-display-mode="count" placeholder="Select...">
39
63
  <option value="1" selected>Option 1</option>
40
64
  <option value="2" selected>Option 2</option>
41
65
  </web-multiselect>
42
66
 
43
- <!-- Compact Mode - First item + "+X more" -->
67
+ <!-- compact - first item + "+X more" -->
44
68
  <web-multiselect badges-display-mode="compact" placeholder="Select...">
45
69
  <option value="1" selected>First</option>
46
70
  <option value="2" selected>Second</option>
47
71
  <option value="3" selected>Third</option>
48
72
  </web-multiselect>
49
73
 
50
- <!-- Partial Mode - Limited badges + "+X more" -->
51
- <web-multiselect badges-display-mode="partial" placeholder="Select...">
74
+ <!-- partial - limited visible badges + "+X more"
75
+ Pair with badges-max-visible to control the cap; switch
76
+ thresholding logic with badges-threshold-mode="count" | "partial". -->
77
+ <web-multiselect badges-display-mode="partial" badges-max-visible="2" placeholder="Select...">
52
78
  <option value="1" selected>Alpha</option>
53
79
  <option value="2" selected>Beta</option>
54
80
  <option value="3" selected>Gamma</option>
55
81
  </web-multiselect>
56
82
 
57
- <!-- None Mode - Minimal UI, no badges -->
83
+ <!-- none - placeholder/input only, no badges UI -->
58
84
  <web-multiselect badges-display-mode="none" placeholder="Select...">
59
85
  <option value="1" selected>Option A</option>
60
86
  <option value="2" selected>Option B</option>
@@ -64,20 +90,34 @@
64
90
  SEARCH & FILTER
65
91
  ======================================== -->
66
92
 
67
- <!-- Search Mode: Filter (hides non-matching) -->
68
- <web-multiselect search-enabled="true" search-mode="filter" placeholder="Search...">
93
+ <!-- Search filter mode (hides non-matching).
94
+ Note: the attribute is `enable-search`, not `search-enabled`. -->
95
+ <web-multiselect enable-search="true" search-mode="filter" placeholder="Search...">
69
96
  <option value="apple">Apple</option>
70
97
  <option value="banana">Banana</option>
71
98
  <option value="cherry">Cherry</option>
72
99
  </web-multiselect>
73
100
 
74
- <!-- Search Mode: Navigate (jumps to matches, keeps all visible) -->
75
- <web-multiselect search-enabled="true" search-mode="navigate" placeholder="Search...">
101
+ <!-- Navigate mode (jumps focus to first match, keeps all options visible) -->
102
+ <web-multiselect enable-search="true" search-mode="navigate" placeholder="Search...">
76
103
  <option value="argentina">Argentina</option>
77
104
  <option value="brazil">Brazil</option>
78
105
  <option value="canada">Canada</option>
79
106
  </web-multiselect>
80
107
 
108
+ <!-- Tweak the search input itself with `search-input-mode` and
109
+ gate it behind a minimum search length: -->
110
+ <web-multiselect enable-search="true"
111
+ search-mode="filter"
112
+ search-input-mode="normal"
113
+ min-search-length="2"
114
+ search-placeholder="Type 2+ chars…"
115
+ placeholder="Search countries…">
116
+ <option value="ar">Argentina</option>
117
+ <option value="br">Brazil</option>
118
+ <option value="ca">Canada</option>
119
+ </web-multiselect>
120
+
81
121
  <!-- ========================================
82
122
  GROUPED OPTIONS
83
123
  ======================================== -->
@@ -109,7 +149,16 @@
109
149
  VIRTUAL SCROLLING (Large Datasets)
110
150
  ======================================== -->
111
151
 
112
- <web-multiselect id="large-dataset" search-enabled="true" placeholder="Search 10,000 items...">
152
+ <!-- Virtual scrolling auto-enables once the option count crosses
153
+ `virtual-scroll-threshold` (default ≈ a few hundred). To force
154
+ it on/off, set `enable-virtual-scroll="true" | "false"`.
155
+ `option-height` should match your actual rendered row height. -->
156
+ <web-multiselect id="large-dataset"
157
+ enable-search="true"
158
+ enable-virtual-scroll="true"
159
+ option-height="50"
160
+ virtual-scroll-buffer="10"
161
+ placeholder="Search 10,000 items...">
113
162
  <!-- Options added via JavaScript for large datasets -->
114
163
  </web-multiselect>
115
164
 
@@ -228,135 +277,322 @@ document.getElementById('myForm').addEventListener('submit', (e) => {
228
277
  ======================================== -->
229
278
 
230
279
  <!--
231
- Core Attributes:
232
- - placeholder: Placeholder text
233
- - multiple: "true" (default) or "false" for single-select
234
- - badges-display-mode: "pills" | "count" | "compact" | "partial" | "none"
235
- - badges-position: "bottom" | "top" | "left" | "right"
236
- - dir: "ltr" (default) | "rtl"
237
- - disabled: Disable the component
280
+ Source of truth: web-component.ts observedAttributes list. The full
281
+ set of attributes the web component accepts:
282
+
283
+ Core:
284
+ - placeholder Input placeholder
285
+ - multiple "true" (default) | "false" for single-select
286
+ - dir "ltr" (default) | "rtl"
287
+ - disabled Disable the entire component
288
+ - allow-groups "true" | "false" — render <optgroup> headers
289
+ - close-on-select Close dropdown on each pick
290
+ - lock-placement Pin dropdown placement (skip flip)
291
+ - dropdown-min-width CSS width
292
+ - dropdown-max-width CSS width
293
+ - max-height Dropdown max height
294
+ - empty-message Text when no options match
295
+ - loading-message Text shown during async load
296
+ - sticky-actions Pin the action bar at the bottom
297
+ - actions-layout Layout token for the action bar
298
+ - allow-add-new Let the user create options inline
299
+ - initial-values CSV / JSON initial selection
300
+ - show-debug-info Boolean — opt-in console logging
301
+
302
+ Badges (selection display):
303
+ - badges-display-mode "badges" (default) | "count" | "compact"
304
+ | "partial" | "none"
305
+ - badges-position "bottom" (default) | "top" | "left" | "right"
306
+ - badges-threshold Numeric trigger for threshold-mode collapse
307
+ - badges-threshold-mode "count" | "partial"
308
+ - badges-max-visible Cap on visible badges in partial mode
309
+ - show-counter Show "(N)" counter alongside badges
310
+ - enable-badge-tooltips Tooltip on each badge
311
+ - badge-tooltip-placement Floating UI placement for badge tooltip
312
+ - remove-button-tooltip-text Tooltip text on the × button
238
313
 
239
314
  Search:
240
- - search-enabled: "true" | "false" (default)
241
- - search-mode: "filter" | "navigate"
242
- - search-placeholder: Placeholder for search input
243
- - min-search-length: Minimum characters before search
315
+ - enable-search "true" | "false" (default false)
316
+ (NOT `search-enabled` common mistake)
317
+ - search-mode "filter" (default) | "navigate"
318
+ - search-input-mode "normal" | "readonly" | "hidden"
319
+ - search-placeholder Placeholder for the search input
320
+ - search-hint Helper text under the search input
321
+ - min-search-length Don't trigger filter until N characters typed
322
+ - keep-options-on-search Keep already-selected items at the top
323
+ - should-keep-search-on-close Preserve search query across opens
244
324
 
245
325
  Display:
246
- - show-checkboxes: Show checkboxes for options
247
- - partial-display-limit: Number of badges to show in partial mode
248
-
249
- Virtual Scrolling:
250
- - virtual-scroll-enabled: "true" | "false" (auto-enabled for large datasets)
251
- - virtual-scroll-buffer: Number of items to render outside viewport
252
- - option-height: Height of each option in pixels
326
+ - show-checkboxes Show checkboxes inside option rows
327
+
328
+ Virtual Scrolling (auto-enabled past virtual-scroll-threshold):
329
+ - enable-virtual-scroll "true" | "false"
330
+ (NOT `virtual-scroll-enabled` common mistake)
331
+ - virtual-scroll-threshold Item count that flips virtual scrolling on
332
+ - option-height Height of each option row in px (must match
333
+ your render — defaults to 50)
334
+ - badge-height Height of each badge row when virtual
335
+ - virtual-scroll-buffer Items rendered above/below viewport
336
+
337
+ Member Property Names (for plugging in foreign data shapes):
338
+ - value-member Default: 'value'
339
+ - display-value-member Default: 'label'
340
+ - search-value-member Default: same as display-value-member
341
+ - icon-member Default: 'icon'
342
+ - subtitle-member Default: 'subtitle'
343
+ - group-member Default: 'group'
344
+ - disabled-member Default: 'disabled'
345
+
346
+ Form Integration:
347
+ - name Field name; participates in <form> submission
348
+ - value-format "json" (default) | "csv" | "array"
253
349
  -->
254
350
 
255
351
  <!-- ========================================
256
- CSS THEMING (150+ Variables)
352
+ CSS CUSTOM PROPERTIES (--ms-*)
353
+ The component defines its variables on :host inside its shadow DOM,
354
+ so override them by targeting the element (NOT :root — :root inside
355
+ shadow DOM doesn't reach the component).
356
+
357
+ The actual prefix is --ms- (multiselect), not --ml-.
257
358
  ======================================== -->
258
359
 
259
360
  <style>
260
- /* Override CSS custom properties to match your theme */
261
- :root {
262
- /* Colors */
263
- --ml-accent-color: #007bff;
264
- --ml-text-primary: #2c3e50;
265
- --ml-text-secondary: #6c757d;
266
- --ml-bg-primary: #f8f9fa;
267
- --ml-border-color: #e1e5e9;
268
-
269
- /* Input */
270
- --ml-input-bg: #ffffff;
271
- --ml-input-border: #ced4da;
272
- --ml-input-padding-v: 0.5rem;
273
- --ml-input-padding-h: 0.75rem;
274
- --ml-input-font-size: 0.875rem;
275
- --ml-input-border-radius: 4px;
276
- --ml-input-focus-border: #007bff;
277
-
278
- /* Dropdown */
279
- --ml-dropdown-bg: #ffffff;
280
- --ml-dropdown-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
281
- --ml-dropdown-max-height: 300px;
282
-
283
- /* Options */
284
- --ml-option-padding-v: 0.5rem;
285
- --ml-option-padding-h: 0.75rem;
286
- --ml-option-hover-bg: #f8f9fa;
287
- --ml-option-selected-bg: rgba(0, 123, 255, 0.05);
288
- --ml-option-selected-color: #007bff;
289
-
290
- /* Badges */
291
- --ml-badge-bg: #007bff;
292
- --ml-badge-text: #ffffff;
293
- --ml-badge-padding-v: 0.125rem;
294
- --ml-badge-padding-h: 0.5rem;
295
- --ml-badge-font-size: 0.75rem;
296
- --ml-badge-border-radius: 2px;
297
- --ml-badge-gap: 0.5rem;
298
-
299
- /* Animations */
300
- --ml-transition-duration: 0.15s;
301
- --ml-timing-function: ease;
361
+ /* Override on the element so the variables cascade into the shadow root.
362
+ In a Pure Admin app this is rarely needed — the theme already cascades
363
+ via --base-* and the component falls back from --ms-* → var(--base-*,
364
+ hardcoded). Override only for one-off instance tweaks. */
365
+ web-multiselect {
366
+ --ms-accent-color: var(--pa-accent);
367
+ --ms-input-bg: var(--pa-input-bg);
368
+ --ms-text-color-1: var(--pa-text-color-1);
369
+ --ms-text-color-3: var(--pa-text-color-2);
370
+ --ms-border-color: var(--pa-border-color);
371
+ --ms-input-border-radius: var(--pa-border-radius);
302
372
  }
303
- </style>
304
373
 
305
- <!-- ========================================
306
- TYPESCRIPT TYPES
307
- ======================================== -->
374
+ /* Scoped instance override (e.g. a "compact" variant) */
375
+ web-multiselect.compact {
376
+ --ms-rem: 9px; /* shrinks every internal sizing unit */
377
+ --ms-accent-color: #10b981;
378
+ }
379
+ </style>
308
380
 
309
381
  <!--
310
- TypeScript usage:
311
-
312
- import '@keenmate/web-multiselect';
313
- import type { MultiSelectElement, MultiSelectOption } from '@keenmate/web-multiselect';
314
-
315
- const select = document.querySelector<MultiSelectElement>('web-multiselect');
316
-
317
- if (select) {
318
- // Type-safe API
319
- select.options = [
320
- { value: 'js', label: 'JavaScript' },
321
- { value: 'ts', label: 'TypeScript' }
322
- ];
323
-
324
- select.addEventListener('change', (e: CustomEvent<{
325
- selectedValues: string[];
326
- selectedOptions: MultiSelectOption[];
327
- }>) => {
328
- console.log(e.detail.selectedValues);
329
- });
330
- }
382
+ Variable groups (full list in src/css/_variables.css — 349 declarations):
383
+
384
+ Base sizing
385
+ --ms-rem Base sizing unit. Defaults 10px to match
386
+ Pure Admin's html { font-size: 10px }. All
387
+ internal sizes scale from this value.
388
+
389
+ Colors / theme
390
+ --ms-accent-color, --ms-accent-color-hover, --ms-accent-color-active
391
+ --ms-accent-color-light, --ms-accent-color-light-hover
392
+ --ms-text-color-1..-4, --ms-text-color-on-accent
393
+ --ms-text-primary, --ms-text-secondary (legacy aliases)
394
+ --ms-primary-bg, --ms-primary-bg-hover
395
+ --ms-border-color, --ms-border
396
+
397
+ Input
398
+ --ms-input-bg, --ms-input-color, --ms-input-border,
399
+ --ms-input-border-hover, --ms-input-border-focus,
400
+ --ms-input-placeholder-color, --ms-input-bg-disabled
401
+
402
+ Toggle / chevron
403
+ --ms-toggle-icon-color, --ms-toggle-icon-color-open
404
+
405
+ Dropdown
406
+ --ms-dropdown-bg, --ms-dropdown-shadow, --ms-dropdown-border,
407
+ --ms-dropdown-border-radius, --ms-dropdown-max-height
408
+
409
+ Options
410
+ --ms-option-bg, --ms-option-bg-hover, --ms-option-bg-selected,
411
+ --ms-option-text-color, --ms-option-text-color-hover, …
412
+
413
+ Badges
414
+ --ms-badge-bg, --ms-badge-text, --ms-badge-padding-v / -h,
415
+ --ms-badge-font-size, --ms-badge-border-radius, --ms-badge-gap
416
+
417
+ Group labels (set by Pure Admin's _web-components-theme.scss)
418
+ --ms-group-label-color, --ms-group-label-font-weight
419
+
420
+ Animations
421
+ --ms-transition-duration, --ms-timing-function
422
+
423
+ PURE ADMIN INTEGRATION:
424
+ packages/core/src/scss/core-components/_web-components-theme.scss
425
+ bridges --base-* → --ms-* automatically. So themes "just work" — no
426
+ manual --ms-* overrides needed in normal Pure Admin usage. The
427
+ bridge file also sets two group-label-specific overrides directly.
331
428
  -->
332
429
 
333
430
  <!-- ========================================
334
- KEY FEATURES
431
+ TYPESCRIPT TYPES
335
432
  ======================================== -->
336
433
 
337
434
  <!--
338
- Virtual Scrolling: Handles 15,000+ options efficiently
339
- Search: Filter or navigate modes with async support
340
- ✅ Display Modes: Pills, count, compact, partial, none
341
- Keyboard Navigation: Full arrow key support
342
- RTL Support: Arabic, Hebrew, Persian, etc.
343
- Grouped Options: Optgroup support with labels
344
- Disabled Options: Per-option disable state
345
- Form Integration: Native form submission support
346
- Framework Agnostic: Works with any framework or vanilla JS
347
- TypeScript: Full type definitions included
348
- Accessible: ARIA-friendly with focus management
349
- Customizable: 150+ CSS variables for theming
350
- ✅ Zero Dependencies: Only requires @floating-ui/dom for positioning
435
+ import '@keenmate/web-multiselect';
436
+ import type {
437
+ MultiSelectOption, // single option shape
438
+ MultiSelectOptions, // array of options
439
+ MultiSelectEventDetail, // shape of `change` event detail
440
+ BadgesDisplayMode, // 'badges' | 'count' | 'compact' | 'partial' | 'none'
441
+ BadgesPosition, // 'top' | 'bottom' | 'left' | 'right'
442
+ BadgesThresholdMode, // 'count' | 'partial'
443
+ SearchInputMode, // 'normal' | 'readonly' | 'hidden'
444
+ SearchMode, // 'filter' | 'navigate'
445
+ ValueFormat // 'json' | 'csv' | 'array'
446
+ } from '@keenmate/web-multiselect';
447
+
448
+ const select = document.querySelector('web-multiselect');
449
+
450
+ select.options = [
451
+ { value: 'js', label: 'JavaScript' },
452
+ { value: 'ts', label: 'TypeScript' }
453
+ ];
454
+
455
+ select.addEventListener('change', (e) => {
456
+ // e.detail: MultiSelectEventDetail
457
+ console.log(e.detail.selectedValues);
458
+ });
351
459
  -->
352
460
 
353
- <!-- ========================================
354
- RESOURCES
355
- ======================================== -->
461
+
462
+ <!-- ================================
463
+ COMPONENT REFERENCE
464
+ ================================ -->
356
465
 
357
466
  <!--
358
- npm Package: @keenmate/web-multiselect
359
- Repository: https://github.com/keenmate/web-multiselect
360
- Documentation: See package README and ../../web-multiselect/ai/ for AI instructions
361
- Pure Admin Integration: src/scss/core-components/_web-components-theme.scss
467
+ DECLARATIVE vs PROGRAMMATIC OPTIONS:
468
+
469
+ Declarative drop <option> / <optgroup> children, no JS needed:
470
+ <web-multiselect placeholder="Pick…">
471
+ <optgroup label="Frontend">
472
+ <option value="react" selected>React</option>
473
+ <option value="vue">Vue</option>
474
+ </optgroup>
475
+ </web-multiselect>
476
+
477
+ Programmatic — set the .options array (re-initializes the picker):
478
+ el.options = [
479
+ { value: 'react', label: 'React', icon: '⚛️' },
480
+ { value: 'vue', label: 'Vue', icon: '💚' }
481
+ ];
482
+
483
+ Foreign data shapes — re-map property names instead of transforming
484
+ the data:
485
+ el.valueMember = 'id';
486
+ el.displayValueMember = 'name';
487
+ el.iconMember = 'emoji';
488
+ el.options = [{ id: '1', name: 'React', emoji: '⚛️' }];
489
+
490
+ DISPLAY MODES (badges-display-mode):
491
+ badges (default) one badge per selected item
492
+ count "X selected" counter only
493
+ compact first item + "+X more"
494
+ partial visible badges capped by `badges-max-visible`,
495
+ threshold flip via `badges-threshold-mode`
496
+ none no badges UI; placeholder only
497
+
498
+ SEARCH (enable-search="true"):
499
+ search-mode="filter" hides non-matching options
500
+ search-mode="navigate" keeps all visible, jumps focus to match
501
+ search-input-mode normal | readonly | hidden
502
+ min-search-length delay filter until N characters typed
503
+
504
+ VIRTUAL SCROLL:
505
+ Auto-enabled past `virtual-scroll-threshold`. Force with
506
+ `enable-virtual-scroll="true" | "false"`. Tune with
507
+ `option-height` (must match real row height, default 50) and
508
+ `virtual-scroll-buffer`. Handles 10–15k options comfortably.
509
+
510
+ EVENTS:
511
+ change detail: { selectedValues, selectedOptions }
512
+ Bubbles + composed; works through shadow DOM boundaries.
513
+
514
+ PUBLIC METHODS:
515
+ el.setSelected(values: (string|number)[])
516
+ el.getValue() → values array
517
+ el.getSelected() → MultiSelectOption[]
518
+ el.options read/write the options array
519
+ el.{value,displayValue,…}Member re-map foreign-data property names
520
+ el.picker underlying engine for advanced calls
521
+
522
+ FORM INTEGRATION:
523
+ Add `name` to participate in <form> submission. `value-format`
524
+ controls the encoding the form receives:
525
+ json (default) — JSON.stringify(values)
526
+ csv — comma-separated string
527
+ array — multiple form fields with the same name
528
+ (FormData.getAll(name))
529
+
530
+ KEYBOARD:
531
+ ↓ / ↑ navigate options
532
+ Enter / Space toggle selection
533
+ Esc close dropdown / clear search
534
+ Backspace with empty search, removes last badge
535
+ Tab focus the action bar / next field
536
+ Type incremental search (when enable-search)
537
+
538
+ CSS VARIABLE NAMESPACES:
539
+ --ms-* Component runtime tokens. Set on the element (NOT
540
+ :root — :root inside shadow DOM doesn't reach the
541
+ component). Prefix is "ms" (multiselect), not "ml".
542
+ --base-* Pure Admin theme bridge. Themes export these via
543
+ output-base-css-variables; the component falls back
544
+ from --ms-* → var(--base-*, hardcoded).
545
+
546
+ LOAD ORDER:
547
+ Import the component once (auto-registers the custom element):
548
+ import '@keenmate/web-multiselect';
549
+ import '@keenmate/web-multiselect/style.css';
550
+ Pure Admin's CSS provides the --base-* values; the component picks
551
+ them up automatically.
552
+
553
+ STRUCTURE PATTERNS:
554
+
555
+ Tag-style multi-select with checkboxes:
556
+ <web-multiselect multiple="true"
557
+ enable-search="true"
558
+ show-checkboxes="true"
559
+ badges-display-mode="badges">
560
+
561
+ </web-multiselect>
562
+
563
+ Big dataset with virtual scrolling + filter search:
564
+ <web-multiselect enable-search="true"
565
+ enable-virtual-scroll="true"
566
+ option-height="44"
567
+ virtual-scroll-buffer="10"
568
+ max-height="40rem">
569
+
570
+ </web-multiselect>
571
+
572
+ Compact selection counter (saves vertical space in toolbars):
573
+ <web-multiselect badges-display-mode="count"
574
+ show-counter="true">
575
+
576
+ </web-multiselect>
577
+
578
+ RTL with logical badge position. NOTE: BadgesPosition is physical
579
+ ('top' | 'bottom' | 'left' | 'right') — pair `dir="rtl"` with the
580
+ appropriate physical side:
581
+ <web-multiselect dir="rtl" badges-position="right">…</web-multiselect>
582
+
583
+ Form-integrated CSV submission:
584
+ <form>
585
+ <web-multiselect name="tags" value-format="csv">
586
+
587
+ </web-multiselect>
588
+ </form>
589
+
590
+ RESOURCES:
591
+ npm @keenmate/web-multiselect
592
+ Repository https://github.com/keenmate/web-multiselect
593
+ AI guides ../../web-multiselect/ai/ (per-topic .txt files)
594
+ API docs ../../web-multiselect/docs/api-reference.html
595
+ Theming ../../web-multiselect/THEMING.md
596
+ Pure Admin src/scss/core-components/_web-components-theme.scss
597
+ bridges --base-* into the component's fallback chain.
362
598
  -->