@keenmate/pure-admin-core 2.3.2 → 2.3.4

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
@@ -2,19 +2,18 @@
2
2
 
3
3
  Lightweight, data-focused CSS/SCSS admin framework with Corporate theme as default.
4
4
 
5
- ## What's New in 2.3.2
5
+ ## What's New in 2.3.4
6
+
7
+ - **Command palette home screen & hotkeys** — Opens with categorized commands and search contexts. Alt+D/A/G/T hotkeys jump directly into commands. Global search finds commands alongside data. Form codes for quick `/go` navigation.
8
+ - **Dropdown z-index fix** — Split button menus no longer go under sidebar/header
9
+
10
+ ## What's New in 2.3.3
6
11
 
7
12
  - **Themeable border-radius via CSS variables** — All components now use `var(--pa-border-radius)`. Themes override in `:root` (same pattern as colors). Fixes long-standing issue where `@use` module isolation prevented theme control of border-radius
8
13
  - **Outline-secondary button contrast** — New `--pa-btn-secondary-outline-color` variable, readable on all dark themes
9
14
  - **Split button dropdown rework** — Two-container pattern (`__menu` + `__menu-inner`) matching web-multiselect. New `__item-row` element for rows with action buttons. Container handles `overflow: hidden` + `border-radius`
10
15
  - **Removed hover lift** — `translateY(-1px)` removed from buttons and stat cards for consistency
11
16
 
12
- ## What's New in 2.3.0
13
-
14
- - **Toast action buttons** — New `pa-toast__actions` element for action buttons inside toasts, separated by a border-top. Toast service supports `actions: [{ label, variant, onClick }]` with auto-dismiss on click
15
- - **Toast service improvements** — `filled`, `progressColor`, and `maxWidth` options. Container width ratchets up to the widest toast shown, preventing layout jitter when toasts dismiss
16
- - **Toast progress bar** — More visible: 5px height, 0.6 opacity (was 3px / 0.3)
17
-
18
17
  ## Installation
19
18
 
20
19
  ```bash
@@ -338,6 +337,67 @@ Works with both `pa-table` and `web-grid` component. First/last columns automati
338
337
  - `.pa-modal__container--sm/md/lg/xl/xxl` - Sizes
339
338
  - `.pa-modal--primary/success/danger/warning` - Themed headers
340
339
 
340
+ ### Command Palette
341
+
342
+ macOS Spotlight-style search with multi-step commands, context search, and global search. Opens with `Ctrl+K` / `Cmd+K`.
343
+
344
+ #### Behavior
345
+
346
+ **Home Screen** — On open, displays a categorized list of available commands (with hotkey badges) and search contexts. Items are clickable. Typing immediately filters or switches to the appropriate mode.
347
+
348
+ **Three Input Modes:**
349
+
350
+ | Prefix | Mode | Behavior |
351
+ |--------|------|----------|
352
+ | `/` | Commands | Shows matching commands. Exact match + space enters the command wizard. |
353
+ | `:` | Context search | Shows matching search contexts. Exact match + space enters scoped search with debounced filtering. |
354
+ | (none) | Global search | Searches across all categories (commands, contexts, and data). Results limited to ~3 per category. |
355
+
356
+ **Multi-step Commands** — Commands define an array of `steps`. Each step has `getOptions(query, previousSelections)` returning filterable options. Steps can be conditional (`shouldShow(selections)`), support free-text entry (`freeText: true`), and have prompts displayed between selections (e.g., "in", "to", "as"). The command's `onComplete(selections)` fires after all steps.
357
+
358
+ **Fuzzy Matching** — Commands and contexts match on `shortcut`, `aliases`, and `name`. Matching is bidirectional: typing `/d` finds `/deploy`, and typing `/deploy` finds `/d`.
359
+
360
+ **Form Codes** — Step options can have a `code` property (e.g., `"24"` for Alerts). The `filterOpts` helper matches on `label`, `description`, and exact `code` — enabling quick navigation by numeric codes common in business applications.
361
+
362
+ **Display Styles:**
363
+
364
+ - **Inline** — Everything in one input: `/deploy in Production branch main`. The input shows the full command string with prompts and selected values concatenated.
365
+ - **Tokens** — Selections render as `pa-badge` chips in `__tokens` container above the input. Each badge has a `×` remove button to rewind to that step. The input only contains the current step's query. The command shortcut is the first badge.
366
+
367
+ **Hotkeys** — Commands can define a `hotkey` (e.g., `"Alt+D"`). These work globally (palette closed) and inside the palette (on the home screen). The hotkey opens the palette and enters the command directly, skipping the command list.
368
+
369
+ **Context Label** — `__context` element shows the active command name (e.g., "Assign to User") or search context (e.g., "Searching in Products"). Positioned inside `__input-wrapper` relative to the input.
370
+
371
+ **Search Highlighting** — Matching text in result titles is wrapped in `<mark>` elements, styled with `--pa-command-palette-highlight-bg` and `--pa-command-palette-highlight-text`. Highlights persist during keyboard navigation.
372
+
373
+ **Keyboard:** `↑↓` navigate, `Enter`/`Tab` select (or submit free text), `Esc` close, `Alt+key` command hotkeys.
374
+
375
+ #### CSS Classes
376
+
377
+ - `.pa-command-palette` - Base container (`--active` to show)
378
+ - `.pa-command-palette__backdrop` - Overlay backdrop
379
+ - `.pa-command-palette__container` - Modal dialog
380
+ - `.pa-command-palette__search` - Search area (tokens + input-wrapper)
381
+ - `.pa-command-palette__tokens` - Token badges container (hidden when empty via `:empty`)
382
+ - `.pa-command-palette__input-wrapper` - Wraps input + context label (positioning anchor)
383
+ - `.pa-command-palette__input` - Search input
384
+ - `.pa-command-palette__context` - Context label (`--visible` to show)
385
+ - `.pa-command-palette__results` - Scrollable results area (`--loading` for overlay)
386
+ - `.pa-command-palette__home` - Home screen container
387
+ - `.pa-command-palette__home-section` - Section with border-top separator
388
+ - `.pa-command-palette__home-heading` - Uppercase section heading
389
+ - `.pa-command-palette__item` - Result row (`--active` for keyboard highlight)
390
+ - `.pa-command-palette__item-icon` - Item icon
391
+ - `.pa-command-palette__item-content` - Title + subtitle wrapper
392
+ - `.pa-command-palette__item-title` - Title (supports `<mark>` for highlights)
393
+ - `.pa-command-palette__item-meta` - Subtitle/metadata (shows `[code]` prefix when present)
394
+ - `.pa-command-palette__shortcut` - Hotkey badge group (flex container)
395
+ - `.pa-command-palette__key` - Keyboard key badge (themeable via `--pa-command-palette-key-bg/key-text`)
396
+ - `.pa-command-palette__token-prompt` - Step prompt text between token badges
397
+ - `.pa-command-palette__footer` - Keyboard hints bar
398
+ - `.pa-command-palette__empty` - Empty state message
399
+ - `.pa-command-palette__loader` - Loading spinner + text
400
+
341
401
  ### Toasts
342
402
  - `.pa-toast` - Base toast
343
403
  - `.pa-toast--primary/success/danger/warning/info` - Variants
package/dist/css/main.css CHANGED
@@ -6230,7 +6230,7 @@ a.pa-card p {
6230
6230
  border: 1px solid var(--pa-border-color);
6231
6231
  border-radius: var(--pa-border-radius);
6232
6232
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
6233
- z-index: 1000;
6233
+ z-index: 7500;
6234
6234
  display: none;
6235
6235
  flex-direction: column;
6236
6236
  padding: 0.4rem 0;
@@ -7819,7 +7819,7 @@ a.pa-card p {
7819
7819
  border: 1px solid var(--pa-border-color);
7820
7820
  border-radius: var(--pa-border-radius);
7821
7821
  box-shadow: 0 0 80px rgba(0, 0, 0, 0.15);
7822
- z-index: 1000;
7822
+ z-index: 7500;
7823
7823
  overflow: hidden;
7824
7824
  }
7825
7825
  .pa-btn-split__menu--open {
@@ -8594,7 +8594,7 @@ a.pa-card p {
8594
8594
  border: 1px solid var(--pa-border-color);
8595
8595
  border-radius: var(--pa-border-radius);
8596
8596
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
8597
- z-index: 1060;
8597
+ z-index: 7600;
8598
8598
  }
8599
8599
  .pa-popover__content[data-show] {
8600
8600
  display: block;
@@ -13824,6 +13824,11 @@ code {
13824
13824
  flex-wrap: wrap;
13825
13825
  gap: 0.4rem;
13826
13826
  align-items: center;
13827
+ margin-bottom: 0.8rem;
13828
+ }
13829
+ .pa-command-palette__tokens:empty {
13830
+ display: none;
13831
+ margin-bottom: 0;
13827
13832
  }
13828
13833
  .pa-command-palette__tokens .pa-badge {
13829
13834
  display: inline-flex;
@@ -13845,6 +13850,14 @@ code {
13845
13850
  .pa-command-palette__tokens .pa-badge__remove:hover {
13846
13851
  opacity: 1;
13847
13852
  }
13853
+ .pa-command-palette__token-prompt {
13854
+ font-size: 1.2rem;
13855
+ color: var(--pa-text-color-2);
13856
+ font-style: italic;
13857
+ }
13858
+ .pa-command-palette__input-wrapper {
13859
+ position: relative;
13860
+ }
13848
13861
  .pa-command-palette__input {
13849
13862
  width: 100%;
13850
13863
  height: 3.8rem;
@@ -13867,7 +13880,7 @@ code {
13867
13880
  }
13868
13881
  .pa-command-palette__context {
13869
13882
  position: absolute;
13870
- inset-inline-end: calc(0.8rem + 0.8rem);
13883
+ inset-inline-end: 0.8rem;
13871
13884
  top: 50%;
13872
13885
  transform: translateY(-50%);
13873
13886
  font-size: 1.2rem;
@@ -13892,10 +13905,32 @@ code {
13892
13905
  content: "";
13893
13906
  position: absolute;
13894
13907
  inset: 0;
13895
- background-color: rgba(255, 255, 255, 0.7);
13908
+ background-color: color-mix(in srgb, var(--pa-modal-content-bg) 70%, transparent);
13896
13909
  pointer-events: none;
13897
13910
  z-index: 1;
13898
13911
  }
13912
+ .pa-command-palette__home {
13913
+ padding: 0.8rem 0;
13914
+ }
13915
+ .pa-command-palette__home-section:not(:first-child) {
13916
+ border-top: 1px solid var(--pa-border-color);
13917
+ margin-top: 0.4rem;
13918
+ padding-top: 0.4rem;
13919
+ }
13920
+ .pa-command-palette__home-heading {
13921
+ padding: 0.4rem 0.8rem;
13922
+ font-size: 1rem;
13923
+ font-weight: 600;
13924
+ color: var(--pa-text-color-2);
13925
+ text-transform: uppercase;
13926
+ letter-spacing: 0.05em;
13927
+ }
13928
+ .pa-command-palette__shortcut {
13929
+ display: flex;
13930
+ align-items: center;
13931
+ gap: 0.4rem;
13932
+ flex-shrink: 0;
13933
+ }
13899
13934
  .pa-command-palette__empty {
13900
13935
  padding: 4.8rem 0.8rem;
13901
13936
  text-align: center;
@@ -13970,14 +14005,6 @@ code {
13970
14005
  overflow: hidden;
13971
14006
  text-overflow: ellipsis;
13972
14007
  }
13973
- .pa-command-palette__item-badge {
13974
- flex-shrink: 0;
13975
- font-size: 1.2rem;
13976
- padding: 2px 0.4rem;
13977
- background-color: #e9ecef;
13978
- color: var(--pa-text-color-2);
13979
- border-radius: var(--pa-border-radius-sm);
13980
- }
13981
14008
  .pa-command-palette__footer {
13982
14009
  border-top: 1px solid var(--pa-border-color);
13983
14010
  padding: 0.8rem 0.8rem;
@@ -13993,12 +14020,13 @@ code {
13993
14020
  }
13994
14021
  .pa-command-palette__key {
13995
14022
  padding: 2px 0.4rem;
13996
- background-color: #e9ecef;
14023
+ background-color: var(--pa-command-palette-key-bg);
14024
+ color: var(--pa-command-palette-key-text);
13997
14025
  border: 1px solid var(--pa-border-color);
13998
14026
  border-radius: var(--pa-border-radius-sm);
13999
14027
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
14000
- font-weight: 500;
14001
- font-size: 1rem;
14028
+ font-weight: var(--pa-command-palette-key-font-weight);
14029
+ font-size: var(--pa-command-palette-key-font-size);
14002
14030
  line-height: 1;
14003
14031
  }
14004
14032
  .pa-command-palette__section {
@@ -14117,7 +14145,7 @@ code {
14117
14145
  font-size: 1rem;
14118
14146
  font-weight: 500;
14119
14147
  color: var(--pa-text-color-2);
14120
- background-color: #e9ecef;
14148
+ background-color: var(--pa-subtle-bg);
14121
14149
  border: 1px solid var(--pa-border-color);
14122
14150
  border-radius: var(--pa-border-radius-sm);
14123
14151
  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);
@@ -14190,7 +14218,7 @@ code {
14190
14218
  font-size: 1rem;
14191
14219
  font-weight: 500;
14192
14220
  color: var(--pa-text-color-1);
14193
- background-color: #e9ecef;
14221
+ background-color: var(--pa-subtle-bg);
14194
14222
  border: 1px solid var(--pa-border-color);
14195
14223
  border-radius: var(--pa-border-radius-sm);
14196
14224
  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@keenmate/pure-admin-core",
3
- "version": "2.3.2",
3
+ "version": "2.3.4",
4
4
  "description": "Lightweight, data-focused HTML/CSS admin framework built with PureCSS foundation and comprehensive component system",
5
5
  "style": "dist/css/main.css",
6
6
  "exports": {
@@ -20,16 +20,18 @@
20
20
  <div class="pa-command-palette__container">
21
21
  <!-- Search input -->
22
22
  <div class="pa-command-palette__search">
23
- <input
24
- type="text"
25
- class="pa-command-palette__input"
26
- id="commandPaletteInput"
27
- placeholder="Search products, orders, users... (try /p, /o, /u)"
28
- autocomplete="off"
29
- spellcheck="false"
30
- >
31
- <!-- Context label (hidden by default, shown when prefix detected) -->
32
- <div class="pa-command-palette__context" id="commandPaletteContext"></div>
23
+ <div class="pa-command-palette__tokens" id="commandPaletteTokens"></div>
24
+ <div class="pa-command-palette__input-wrapper">
25
+ <input
26
+ type="text"
27
+ class="pa-command-palette__input"
28
+ id="commandPaletteInput"
29
+ placeholder="Type / for commands, : to search, or just start typing..."
30
+ autocomplete="off"
31
+ spellcheck="false"
32
+ >
33
+ <div class="pa-command-palette__context" id="commandPaletteContext"></div>
34
+ </div>
33
35
  </div>
34
36
 
35
37
  <!-- Results container -->
@@ -79,7 +81,7 @@
79
81
  <div class="pa-command-palette__item-title">MacBook Pro 16"</div>
80
82
  <div class="pa-command-palette__item-meta">SKU: MBP-16-001 • $2,499.00</div>
81
83
  </div>
82
- <div class="pa-command-palette__item-badge">In Stock</div>
84
+ <span class="pa-badge">In Stock</span>
83
85
  </div>
84
86
 
85
87
  <!-- Active result item -->
@@ -89,7 +91,7 @@
89
91
  <div class="pa-command-palette__item-title">iPhone 15 Pro</div>
90
92
  <div class="pa-command-palette__item-meta">SKU: IP15P-256 • $999.00</div>
91
93
  </div>
92
- <div class="pa-command-palette__item-badge">New</div>
94
+ <span class="pa-badge">New</span>
93
95
  </div>
94
96
 
95
97
  <!-- Result with highlighted search match -->
@@ -99,7 +101,7 @@
99
101
  <div class="pa-command-palette__item-title">Air<mark>Pods</mark> Pro</div>
100
102
  <div class="pa-command-palette__item-meta">SKU: APP-GEN2 • $249.00</div>
101
103
  </div>
102
- <div class="pa-command-palette__item-badge">Popular</div>
104
+ <span class="pa-badge">Popular</span>
103
105
  </div>
104
106
 
105
107
  <!-- Pagination indicator (shown when multiple pages) -->
@@ -459,6 +459,10 @@
459
459
  --pa-command-palette-item-active-bg: #{$command-palette-item-active-bg};
460
460
  --pa-command-palette-highlight-bg: #{$command-palette-highlight-bg};
461
461
  --pa-command-palette-highlight-text: #{$command-palette-highlight-text};
462
+ --pa-command-palette-key-bg: #{$subtle-bg};
463
+ --pa-command-palette-key-text: #{$text-color-1};
464
+ --pa-command-palette-key-font-size: #{$font-size-xs};
465
+ --pa-command-palette-key-font-weight: #{$font-weight-semibold};
462
466
 
463
467
  // =========================================================================
464
468
  // MULTISELECT COLORS
@@ -51,6 +51,12 @@
51
51
  flex-wrap: wrap;
52
52
  gap: $spacing-xs;
53
53
  align-items: center;
54
+ margin-bottom: $spacing-sm;
55
+
56
+ &:empty {
57
+ display: none;
58
+ margin-bottom: 0;
59
+ }
54
60
 
55
61
  .pa-badge {
56
62
  display: inline-flex;
@@ -77,6 +83,16 @@
77
83
  }
78
84
  }
79
85
 
86
+ &__token-prompt {
87
+ font-size: $font-size-xs;
88
+ color: var(--pa-text-color-2);
89
+ font-style: italic;
90
+ }
91
+
92
+ &__input-wrapper {
93
+ position: relative;
94
+ }
95
+
80
96
  &__input {
81
97
  width: 100%;
82
98
  height: $command-palette-input-height;
@@ -100,10 +116,10 @@
100
116
  }
101
117
  }
102
118
 
103
- // Context label (e.g., "Searching in Products")
119
+ // Context label (e.g., "Searching in Products") — positioned relative to input-wrapper
104
120
  &__context {
105
121
  position: absolute;
106
- inset-inline-end: calc(#{$spacing-sm} + #{$command-palette-input-padding-h}); // RTL: flips to left
122
+ inset-inline-end: $command-palette-input-padding-h; // RTL: flips to left
107
123
  top: 50%;
108
124
  transform: translateY(-50%);
109
125
  font-size: $font-size-xs;
@@ -133,13 +149,42 @@
133
149
  content: '';
134
150
  position: absolute;
135
151
  inset: 0; // RTL: full overlay works in both directions
136
- background-color: rgba($modal-content-bg, 0.7);
152
+ background-color: color-mix(in srgb, var(--pa-modal-content-bg) 70%, transparent);
137
153
  pointer-events: none;
138
154
  z-index: 1;
139
155
  }
140
156
  }
141
157
  }
142
158
 
159
+ // Home screen (idle state)
160
+ &__home {
161
+ padding: $spacing-sm 0;
162
+ }
163
+
164
+ &__home-section {
165
+ &:not(:first-child) {
166
+ border-top: $border-width-base solid var(--pa-border-color);
167
+ margin-top: $spacing-xs;
168
+ padding-top: $spacing-xs;
169
+ }
170
+ }
171
+
172
+ &__home-heading {
173
+ padding: $spacing-xs $command-palette-input-padding-h;
174
+ font-size: $font-size-2xs;
175
+ font-weight: $font-weight-semibold;
176
+ color: var(--pa-text-color-2);
177
+ text-transform: uppercase;
178
+ letter-spacing: 0.05em;
179
+ }
180
+
181
+ &__shortcut {
182
+ display: flex;
183
+ align-items: center;
184
+ gap: $spacing-xs;
185
+ flex-shrink: 0;
186
+ }
187
+
143
188
  // Empty state
144
189
  &__empty {
145
190
  padding: $command-palette-empty-padding-v $command-palette-input-padding-h;
@@ -231,14 +276,6 @@
231
276
  }
232
277
 
233
278
  // Item badge (e.g., category, status)
234
- &__item-badge {
235
- flex-shrink: 0;
236
- font-size: $font-size-xs;
237
- padding: 2px $spacing-xs;
238
- background-color: $secondary-light-bg;
239
- color: var(--pa-text-color-2);
240
- border-radius: var(--pa-border-radius-sm);
241
- }
242
279
 
243
280
  // Footer with keyboard hints
244
281
  &__footer {
@@ -258,12 +295,13 @@
258
295
 
259
296
  &__key {
260
297
  padding: 2px $spacing-xs;
261
- background-color: $secondary-light-bg;
298
+ background-color: var(--pa-command-palette-key-bg);
299
+ color: var(--pa-command-palette-key-text);
262
300
  border: $border-width-base solid var(--pa-border-color);
263
301
  border-radius: var(--pa-border-radius-sm);
264
302
  font-family: $body-font-family;
265
- font-weight: $font-weight-medium;
266
- font-size: $font-size-2xs;
303
+ font-weight: var(--pa-command-palette-key-font-weight);
304
+ font-size: var(--pa-command-palette-key-font-size);
267
305
  line-height: 1;
268
306
  }
269
307
 
@@ -405,7 +443,7 @@
405
443
  font-size: $font-size-2xs;
406
444
  font-weight: $font-weight-medium;
407
445
  color: var(--pa-text-color-2);
408
- background-color: $secondary-light-bg;
446
+ background-color: var(--pa-subtle-bg);
409
447
  border: $border-width-base solid var(--pa-border-color);
410
448
  border-radius: var(--pa-border-radius-sm);
411
449
  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);
@@ -486,7 +524,7 @@
486
524
  font-size: $font-size-2xs;
487
525
  font-weight: $font-weight-medium;
488
526
  color: var(--pa-text-color-1);
489
- background-color: $secondary-light-bg;
527
+ background-color: var(--pa-subtle-bg);
490
528
  border: $border-width-base solid var(--pa-border-color);
491
529
  border-radius: var(--pa-border-radius-sm);
492
530
  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);
@@ -17,8 +17,8 @@ $z-index-toast: 8000 !default;
17
17
  $z-index-tooltip: 9000 !default;
18
18
 
19
19
  // Additional z-index values
20
- $z-index-dropdown: 1000 !default;
21
- $z-index-popover: 1060 !default;
20
+ $z-index-dropdown: 7500 !default;
21
+ $z-index-popover: 7600 !default;
22
22
  $z-index-loader: 10 !default;
23
23
  $z-index-command-palette: 10500 !default;
24
24
  $z-index-settings-panel: 10000 !default;