@salmexio/ui 0.2.0 → 0.3.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 (42) hide show
  1. package/dist/dialogs/ContextMenu/ContextMenu.svelte +521 -0
  2. package/dist/dialogs/ContextMenu/ContextMenu.svelte.d.ts +53 -0
  3. package/dist/dialogs/ContextMenu/ContextMenu.svelte.d.ts.map +1 -0
  4. package/dist/dialogs/ContextMenu/index.d.ts +3 -0
  5. package/dist/dialogs/ContextMenu/index.d.ts.map +1 -0
  6. package/dist/dialogs/ContextMenu/index.js +1 -0
  7. package/dist/dialogs/index.d.ts +2 -0
  8. package/dist/dialogs/index.d.ts.map +1 -1
  9. package/dist/dialogs/index.js +1 -0
  10. package/dist/feedback/Alert/Alert.svelte +1 -62
  11. package/dist/feedback/Alert/Alert.svelte.d.ts +1 -1
  12. package/dist/feedback/Alert/Alert.svelte.d.ts.map +1 -1
  13. package/dist/forms/Select/Select.svelte +883 -0
  14. package/dist/forms/Select/Select.svelte.d.ts +68 -0
  15. package/dist/forms/Select/Select.svelte.d.ts.map +1 -0
  16. package/dist/forms/Select/index.d.ts +3 -0
  17. package/dist/forms/Select/index.d.ts.map +1 -0
  18. package/dist/forms/Select/index.js +1 -0
  19. package/dist/forms/index.d.ts +2 -0
  20. package/dist/forms/index.d.ts.map +1 -1
  21. package/dist/forms/index.js +1 -0
  22. package/dist/layout/Card/Card.svelte +29 -169
  23. package/dist/layout/Card/Card.svelte.d.ts +3 -9
  24. package/dist/layout/Card/Card.svelte.d.ts.map +1 -1
  25. package/dist/navigation/CommandPalette/CommandPalette.svelte +574 -0
  26. package/dist/navigation/CommandPalette/CommandPalette.svelte.d.ts +47 -0
  27. package/dist/navigation/CommandPalette/CommandPalette.svelte.d.ts.map +1 -0
  28. package/dist/navigation/CommandPalette/index.d.ts +3 -0
  29. package/dist/navigation/CommandPalette/index.d.ts.map +1 -0
  30. package/dist/navigation/CommandPalette/index.js +1 -0
  31. package/dist/navigation/index.d.ts +2 -0
  32. package/dist/navigation/index.d.ts.map +1 -1
  33. package/dist/navigation/index.js +1 -0
  34. package/dist/primitives/Badge/Badge.svelte +45 -9
  35. package/dist/primitives/Badge/Badge.svelte.d.ts +0 -2
  36. package/dist/primitives/Badge/Badge.svelte.d.ts.map +1 -1
  37. package/dist/primitives/Button/Button.svelte +40 -14
  38. package/dist/primitives/Button/Button.svelte.d.ts +1 -1
  39. package/dist/primitives/Button/Button.svelte.d.ts.map +1 -1
  40. package/dist/styles/tokens.css +4 -4
  41. package/dist/windowing/Window/Window.svelte +3 -3
  42. package/package.json +1 -1
@@ -0,0 +1,574 @@
1
+ <!--
2
+ @component CommandPalette
3
+
4
+ Win2K × Basquiat — Keyboard-first command launcher with sunken search field,
5
+ categorised result list, fuzzy matching, and shortcut display.
6
+
7
+ @example
8
+ <CommandPalette
9
+ commands={[
10
+ { id: 'save', label: 'Save File', shortcut: 'Ctrl+S', group: 'File', action: handleSave },
11
+ { id: 'open', label: 'Open File', shortcut: 'Ctrl+O', group: 'File', action: handleOpen },
12
+ ]}
13
+ bind:open={showPalette}
14
+ />
15
+ -->
16
+ <script lang="ts" module>
17
+ export interface CommandItem {
18
+ id: string;
19
+ label: string;
20
+ shortcut?: string;
21
+ group?: string;
22
+ icon?: string;
23
+ description?: string;
24
+ disabled?: boolean;
25
+ action: () => void;
26
+ }
27
+
28
+ export interface CommandGroup {
29
+ label: string;
30
+ items: CommandItem[];
31
+ }
32
+ </script>
33
+
34
+ <script lang="ts">
35
+ import { cn } from '../../utils/cn.js';
36
+ import { Keys, createFocusTrap } from '../../utils/keyboard.js';
37
+ import { onMount, tick } from 'svelte';
38
+ import type { FocusTrap } from '../../utils/keyboard.js';
39
+
40
+ interface Props {
41
+ /** All available commands */
42
+ commands: CommandItem[];
43
+ /** Whether the palette is open */
44
+ open?: boolean;
45
+ /** Placeholder for the search field */
46
+ placeholder?: string;
47
+ /** Additional CSS class */
48
+ class?: string;
49
+ /** Called when palette closes */
50
+ onclose?: () => void;
51
+ /** Test ID */
52
+ testId?: string;
53
+ }
54
+
55
+ let {
56
+ commands,
57
+ open = $bindable(false),
58
+ placeholder = 'Type a command...',
59
+ class: className = '',
60
+ onclose,
61
+ testId
62
+ }: Props = $props();
63
+
64
+ let query = $state('');
65
+ let activeIndex = $state(0);
66
+ let inputEl = $state<HTMLInputElement | null>(null);
67
+ let panelEl = $state<HTMLDivElement | null>(null);
68
+ let listEl = $state<HTMLDivElement | null>(null);
69
+ let backdropEl = $state<HTMLDivElement | null>(null);
70
+ let wrapperEl = $state<HTMLDivElement | null>(null);
71
+ let focusTrap: FocusTrap | null = null;
72
+
73
+ // Fuzzy match: check if query chars appear in order in the label
74
+ function fuzzyMatch(text: string, search: string): boolean {
75
+ if (!search) return true;
76
+ const lower = text.toLowerCase();
77
+ const searchLower = search.toLowerCase();
78
+ let si = 0;
79
+ for (let ti = 0; ti < lower.length && si < searchLower.length; ti++) {
80
+ if (lower[ti] === searchLower[si]) si++;
81
+ }
82
+ return si === searchLower.length;
83
+ }
84
+
85
+ // Score: prefer starts-with and shorter labels
86
+ function fuzzyScore(text: string, search: string): number {
87
+ if (!search) return 0;
88
+ const lower = text.toLowerCase();
89
+ const searchLower = search.toLowerCase();
90
+ let score = 0;
91
+ if (lower.startsWith(searchLower)) score += 100;
92
+ if (lower.includes(searchLower)) score += 50;
93
+ score -= text.length;
94
+ return score;
95
+ }
96
+
97
+ const filteredCommands = $derived<CommandItem[]>(
98
+ commands
99
+ .filter((c) => fuzzyMatch(c.label, query) || (c.description && fuzzyMatch(c.description, query)))
100
+ .sort((a, b) => fuzzyScore(b.label, query) - fuzzyScore(a.label, query))
101
+ );
102
+
103
+ // Group filtered results
104
+ const groupedResults = $derived.by(() => {
105
+ const groups = new Map<string, CommandItem[]>();
106
+ for (const item of filteredCommands) {
107
+ const key = item.group ?? '';
108
+ if (!groups.has(key)) groups.set(key, []);
109
+ groups.get(key)!.push(item);
110
+ }
111
+ return Array.from(groups.entries()).map(([label, items]) => ({ label, items })) as CommandGroup[];
112
+ });
113
+
114
+ // Flat list for keyboard navigation
115
+ const flatFiltered = $derived(filteredCommands);
116
+
117
+ function openPalette() {
118
+ open = true;
119
+ query = '';
120
+ activeIndex = 0;
121
+ requestAnimationFrame(() => {
122
+ inputEl?.focus();
123
+ if (panelEl) {
124
+ focusTrap = createFocusTrap(panelEl);
125
+ focusTrap.activate();
126
+ }
127
+ });
128
+ }
129
+
130
+ function closePalette() {
131
+ open = false;
132
+ query = '';
133
+ activeIndex = 0;
134
+ focusTrap?.deactivate();
135
+ focusTrap = null;
136
+ onclose?.();
137
+ }
138
+
139
+ function executeItem(item: CommandItem) {
140
+ if (item.disabled) return;
141
+ closePalette();
142
+ item.action();
143
+ }
144
+
145
+ function scrollActiveIntoView() {
146
+ requestAnimationFrame(() => {
147
+ if (!listEl) return;
148
+ const active = listEl.querySelector('[data-active="true"]') as HTMLElement;
149
+ if (!active) return;
150
+ const listTop = listEl.scrollTop;
151
+ const listHeight = listEl.clientHeight;
152
+ const elTop = active.offsetTop;
153
+ const elHeight = active.offsetHeight;
154
+ if (elTop < listTop) {
155
+ listEl.scrollTop = elTop;
156
+ } else if (elTop + elHeight > listTop + listHeight) {
157
+ listEl.scrollTop = elTop + elHeight - listHeight;
158
+ }
159
+ });
160
+ }
161
+
162
+ function handleKeydown(e: KeyboardEvent) {
163
+ switch (e.key) {
164
+ case Keys.ArrowDown:
165
+ e.preventDefault();
166
+ activeIndex = Math.min(activeIndex + 1, flatFiltered.length - 1);
167
+ scrollActiveIntoView();
168
+ break;
169
+ case Keys.ArrowUp:
170
+ e.preventDefault();
171
+ activeIndex = Math.max(activeIndex - 1, 0);
172
+ scrollActiveIntoView();
173
+ break;
174
+ case Keys.Enter:
175
+ e.preventDefault();
176
+ if (flatFiltered[activeIndex]) executeItem(flatFiltered[activeIndex]);
177
+ break;
178
+ case Keys.Escape:
179
+ e.preventDefault();
180
+ closePalette();
181
+ break;
182
+ case Keys.Home:
183
+ e.preventDefault();
184
+ activeIndex = 0;
185
+ scrollActiveIntoView();
186
+ break;
187
+ case Keys.End:
188
+ e.preventDefault();
189
+ activeIndex = Math.max(flatFiltered.length - 1, 0);
190
+ scrollActiveIntoView();
191
+ break;
192
+ }
193
+ }
194
+
195
+ function handleInput() {
196
+ activeIndex = 0;
197
+ }
198
+
199
+ function handleBackdropClick() {
200
+ closePalette();
201
+ }
202
+
203
+ // Watch for external open changes
204
+ $effect(() => {
205
+ if (open) openPalette();
206
+ });
207
+
208
+ // Portal: move wrapper to document.body to escape transform/overflow ancestors
209
+ $effect(() => {
210
+ if (wrapperEl && open) {
211
+ document.body.appendChild(wrapperEl);
212
+ return () => {
213
+ if (wrapperEl?.parentNode === document.body) {
214
+ document.body.removeChild(wrapperEl);
215
+ }
216
+ };
217
+ }
218
+ });
219
+
220
+ // Global keyboard shortcut: Ctrl+K / Cmd+K
221
+ onMount(() => {
222
+ function onGlobalKey(e: KeyboardEvent) {
223
+ if ((e.ctrlKey || e.metaKey) && e.key === 'k') {
224
+ e.preventDefault();
225
+ if (open) closePalette();
226
+ else openPalette();
227
+ }
228
+ }
229
+ document.addEventListener('keydown', onGlobalKey);
230
+ return () => {
231
+ document.removeEventListener('keydown', onGlobalKey);
232
+ focusTrap?.deactivate();
233
+ };
234
+ });
235
+
236
+ // Track cumulative index for items within grouped display
237
+ function getCumulativeIndex(groupIdx: number, itemIdx: number): number {
238
+ let offset = 0;
239
+ for (let g = 0; g < groupIdx; g++) {
240
+ offset += groupedResults[g].items.length;
241
+ }
242
+ return offset + itemIdx;
243
+ }
244
+ </script>
245
+
246
+ {#if open}
247
+ <div bind:this={wrapperEl}>
248
+ <!-- Backdrop -->
249
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
250
+ <div bind:this={backdropEl} class="salmex-cmd-backdrop" onclick={handleBackdropClick} onkeydown={() => {}}></div>
251
+
252
+ <!-- Panel -->
253
+ <div
254
+ bind:this={panelEl}
255
+ class={cn('salmex-cmd', className)}
256
+ role="dialog"
257
+ tabindex="-1"
258
+ aria-label="Command palette"
259
+ data-testid={testId}
260
+ onkeydown={handleKeydown}
261
+ >
262
+ <!-- Search field -->
263
+ <div class="salmex-cmd-search">
264
+ <span class="salmex-cmd-search-icon" aria-hidden="true">
265
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2">
266
+ <circle cx="6.5" cy="6.5" r="5" />
267
+ <path d="M10 10L14.5 14.5" />
268
+ </svg>
269
+ </span>
270
+ <input
271
+ bind:this={inputEl}
272
+ type="text"
273
+ class="salmex-cmd-input"
274
+ {placeholder}
275
+ bind:value={query}
276
+ oninput={handleInput}
277
+ aria-label="Search commands"
278
+ aria-controls="cmd-results"
279
+ aria-activedescendant={flatFiltered[activeIndex] ? `cmd-item-${flatFiltered[activeIndex].id}` : undefined}
280
+ autocomplete="off"
281
+ spellcheck="false"
282
+ />
283
+ <span class="salmex-cmd-shortcut-hint" aria-hidden="true">ESC</span>
284
+ </div>
285
+
286
+ <!-- Results -->
287
+ <div bind:this={listEl} id="cmd-results" class="salmex-cmd-results" role="listbox">
288
+ {#if flatFiltered.length === 0}
289
+ <div class="salmex-cmd-empty">No commands found.</div>
290
+ {:else}
291
+ {#each groupedResults as group, gi}
292
+ {#if group.label}
293
+ <div class="salmex-cmd-group-label">{group.label}</div>
294
+ {/if}
295
+ {#each group.items as item, ii}
296
+ {@const globalIdx = getCumulativeIndex(gi, ii)}
297
+ {@const isActive = globalIdx === activeIndex}
298
+ <!-- svelte-ignore a11y_no_noninteractive_element_interactions a11y_click_events_have_key_events -->
299
+ <div
300
+ id="cmd-item-{item.id}"
301
+ class={cn(
302
+ 'salmex-cmd-item',
303
+ isActive && 'salmex-cmd-item-active',
304
+ item.disabled && 'salmex-cmd-item-disabled'
305
+ )}
306
+ role="option"
307
+ tabindex="-1"
308
+ aria-selected={isActive}
309
+ aria-disabled={item.disabled || undefined}
310
+ data-active={isActive}
311
+ onmouseenter={() => { activeIndex = globalIdx; }}
312
+ onclick={() => executeItem(item)}
313
+ onkeydown={handleKeydown}
314
+ >
315
+ {#if item.icon}
316
+ <span class="salmex-cmd-item-icon" aria-hidden="true">{item.icon}</span>
317
+ {/if}
318
+ <div class="salmex-cmd-item-content">
319
+ <span class="salmex-cmd-item-label">{item.label}</span>
320
+ {#if item.description}
321
+ <span class="salmex-cmd-item-desc">{item.description}</span>
322
+ {/if}
323
+ </div>
324
+ {#if item.shortcut}
325
+ <span class="salmex-cmd-item-shortcut">{item.shortcut}</span>
326
+ {/if}
327
+ </div>
328
+ {/each}
329
+ {/each}
330
+ {/if}
331
+ </div>
332
+
333
+ <!-- Footer hint -->
334
+ <div class="salmex-cmd-footer">
335
+ <span><kbd>&#8593;&#8595;</kbd> navigate</span>
336
+ <span><kbd>&#8629;</kbd> select</span>
337
+ <span><kbd>esc</kbd> close</span>
338
+ </div>
339
+ </div>
340
+ </div>
341
+ {/if}
342
+
343
+ <style>
344
+ /* ========================================
345
+ BACKDROP
346
+ ======================================== */
347
+ .salmex-cmd-backdrop {
348
+ position: fixed;
349
+ inset: 0;
350
+ z-index: var(--salmex-z-modal-backdrop);
351
+ background: rgb(0 0 0 / 0.4);
352
+ }
353
+
354
+ /* ========================================
355
+ PANEL
356
+ ======================================== */
357
+ .salmex-cmd {
358
+ position: fixed;
359
+ top: 20%;
360
+ left: 50%;
361
+ transform: translateX(-50%);
362
+ z-index: var(--salmex-z-modal);
363
+ width: min(560px, calc(100vw - 32px));
364
+ max-height: 420px;
365
+ display: flex;
366
+ flex-direction: column;
367
+ background: rgb(var(--salmex-window-surface));
368
+ border: 3px solid rgb(var(--salmex-border-dark));
369
+ box-shadow:
370
+ inset 1px 1px 0 rgb(var(--salmex-button-highlight)),
371
+ inset -1px -1px 0 rgb(var(--salmex-button-shadow)),
372
+ 8px 8px 0 rgb(0 0 0 / 0.4);
373
+ font-family: var(--salmex-font-system);
374
+ overflow: hidden;
375
+ }
376
+
377
+ :global([data-theme='dark']) .salmex-cmd {
378
+ box-shadow:
379
+ inset 1px 1px 0 rgb(var(--salmex-button-highlight)),
380
+ inset -1px -1px 0 rgb(var(--salmex-button-shadow)),
381
+ 8px 8px 0 rgb(0 0 0 / 0.7);
382
+ }
383
+
384
+ /* ========================================
385
+ SEARCH FIELD — Sunken, prominent
386
+ ======================================== */
387
+ .salmex-cmd-search {
388
+ display: flex;
389
+ align-items: center;
390
+ gap: var(--salmex-space-3);
391
+ padding: var(--salmex-space-4) var(--salmex-space-5);
392
+ border-bottom: 1px solid rgb(var(--salmex-border-default));
393
+ }
394
+
395
+ .salmex-cmd-search-icon {
396
+ flex-shrink: 0;
397
+ display: flex;
398
+ color: rgb(var(--salmex-text-secondary));
399
+ }
400
+
401
+ .salmex-cmd-input {
402
+ flex: 1;
403
+ border: none;
404
+ background: transparent;
405
+ outline: none;
406
+ font-family: var(--salmex-font-system);
407
+ font-size: var(--salmex-font-size-md);
408
+ font-weight: 600;
409
+ color: rgb(var(--salmex-text-primary));
410
+ }
411
+
412
+ .salmex-cmd-input::placeholder {
413
+ color: rgb(var(--salmex-text-disabled));
414
+ }
415
+
416
+ .salmex-cmd-shortcut-hint {
417
+ flex-shrink: 0;
418
+ font-family: var(--salmex-font-mono);
419
+ font-size: var(--salmex-font-size-xs);
420
+ font-weight: 700;
421
+ padding: 2px 6px;
422
+ border: 2px solid rgb(var(--salmex-border-default));
423
+ background: rgb(var(--salmex-button-face));
424
+ color: rgb(var(--salmex-text-secondary));
425
+ box-shadow:
426
+ inset 1px 1px 0 rgb(var(--salmex-button-highlight)),
427
+ inset -1px -1px 0 rgb(var(--salmex-button-shadow));
428
+ }
429
+
430
+ /* ========================================
431
+ RESULTS LIST
432
+ ======================================== */
433
+ .salmex-cmd-results {
434
+ flex: 1;
435
+ overflow-y: auto;
436
+ padding: var(--salmex-space-1) 0;
437
+ max-height: 300px;
438
+ }
439
+
440
+ .salmex-cmd-empty {
441
+ padding: var(--salmex-space-6) var(--salmex-space-5);
442
+ text-align: center;
443
+ font-size: var(--salmex-font-size-sm);
444
+ color: rgb(var(--salmex-text-disabled));
445
+ font-weight: 600;
446
+ }
447
+
448
+ /* ========================================
449
+ GROUP LABEL
450
+ ======================================== */
451
+ .salmex-cmd-group-label {
452
+ padding: var(--salmex-space-2) var(--salmex-space-5) var(--salmex-space-1);
453
+ margin-top: var(--salmex-space-1);
454
+ font-family: var(--salmex-font-mono);
455
+ font-size: 10px;
456
+ font-weight: 600;
457
+ text-transform: uppercase;
458
+ letter-spacing: 0.8px;
459
+ color: rgb(var(--salmex-text-disabled));
460
+ border-top: 1px solid rgb(var(--salmex-border-light));
461
+ user-select: none;
462
+ }
463
+
464
+ .salmex-cmd-group-label:first-child {
465
+ border-top: none;
466
+ margin-top: 0;
467
+ }
468
+
469
+ /* ========================================
470
+ COMMAND ITEM
471
+ ======================================== */
472
+ .salmex-cmd-item {
473
+ display: flex;
474
+ align-items: center;
475
+ gap: var(--salmex-space-3);
476
+ padding: var(--salmex-space-2) var(--salmex-space-5);
477
+ cursor: pointer;
478
+ user-select: none;
479
+ transition: background var(--salmex-transition-fast);
480
+ }
481
+
482
+ .salmex-cmd-item-active {
483
+ background: rgb(var(--salmex-electric-blue));
484
+ color: rgb(var(--salmex-chalk-white));
485
+ }
486
+
487
+ :global([data-theme='dark']) .salmex-cmd-item-active {
488
+ background: rgb(var(--salmex-primary-light));
489
+ color: rgb(var(--salmex-midnight-black));
490
+ }
491
+
492
+ .salmex-cmd-item-disabled {
493
+ opacity: 0.4;
494
+ cursor: not-allowed;
495
+ }
496
+
497
+ .salmex-cmd-item-icon {
498
+ flex-shrink: 0;
499
+ width: 20px;
500
+ text-align: center;
501
+ font-size: 16px;
502
+ }
503
+
504
+ .salmex-cmd-item-content {
505
+ flex: 1;
506
+ min-width: 0;
507
+ display: flex;
508
+ flex-direction: column;
509
+ }
510
+
511
+ .salmex-cmd-item-label {
512
+ font-size: var(--salmex-font-size-sm);
513
+ font-weight: 700;
514
+ overflow: hidden;
515
+ text-overflow: ellipsis;
516
+ white-space: nowrap;
517
+ }
518
+
519
+ .salmex-cmd-item-desc {
520
+ font-size: var(--salmex-font-size-xs);
521
+ opacity: 0.7;
522
+ overflow: hidden;
523
+ text-overflow: ellipsis;
524
+ white-space: nowrap;
525
+ }
526
+
527
+ .salmex-cmd-item-active .salmex-cmd-item-desc {
528
+ opacity: 0.85;
529
+ }
530
+
531
+ .salmex-cmd-item-shortcut {
532
+ flex-shrink: 0;
533
+ font-family: var(--salmex-font-mono);
534
+ font-size: var(--salmex-font-size-xs);
535
+ font-weight: 600;
536
+ opacity: 0.6;
537
+ }
538
+
539
+ .salmex-cmd-item-active .salmex-cmd-item-shortcut {
540
+ opacity: 0.85;
541
+ }
542
+
543
+ /* ========================================
544
+ FOOTER
545
+ ======================================== */
546
+ .salmex-cmd-footer {
547
+ display: flex;
548
+ align-items: center;
549
+ gap: var(--salmex-space-5);
550
+ padding: var(--salmex-space-2) var(--salmex-space-5);
551
+ border-top: 1px solid rgb(var(--salmex-border-default));
552
+ font-size: var(--salmex-font-size-xs);
553
+ color: rgb(var(--salmex-text-secondary));
554
+ background: rgb(var(--salmex-window-surface));
555
+ }
556
+
557
+ .salmex-cmd-footer kbd {
558
+ font-family: var(--salmex-font-mono);
559
+ font-weight: 700;
560
+ padding: 1px 4px;
561
+ border: 1px solid rgb(var(--salmex-border-default));
562
+ background: rgb(var(--salmex-button-face));
563
+ font-size: 0.9em;
564
+ }
565
+
566
+ /* ========================================
567
+ REDUCED MOTION
568
+ ======================================== */
569
+ @media (prefers-reduced-motion: reduce) {
570
+ .salmex-cmd-item {
571
+ transition: none;
572
+ }
573
+ }
574
+ </style>
@@ -0,0 +1,47 @@
1
+ export interface CommandItem {
2
+ id: string;
3
+ label: string;
4
+ shortcut?: string;
5
+ group?: string;
6
+ icon?: string;
7
+ description?: string;
8
+ disabled?: boolean;
9
+ action: () => void;
10
+ }
11
+ export interface CommandGroup {
12
+ label: string;
13
+ items: CommandItem[];
14
+ }
15
+ interface Props {
16
+ /** All available commands */
17
+ commands: CommandItem[];
18
+ /** Whether the palette is open */
19
+ open?: boolean;
20
+ /** Placeholder for the search field */
21
+ placeholder?: string;
22
+ /** Additional CSS class */
23
+ class?: string;
24
+ /** Called when palette closes */
25
+ onclose?: () => void;
26
+ /** Test ID */
27
+ testId?: string;
28
+ }
29
+ /**
30
+ * CommandPalette
31
+ *
32
+ * Win2K × Basquiat — Keyboard-first command launcher with sunken search field,
33
+ * categorised result list, fuzzy matching, and shortcut display.
34
+ *
35
+ * @example
36
+ * <CommandPalette
37
+ * commands={[
38
+ * { id: 'save', label: 'Save File', shortcut: 'Ctrl+S', group: 'File', action: handleSave },
39
+ * { id: 'open', label: 'Open File', shortcut: 'Ctrl+O', group: 'File', action: handleOpen },
40
+ * ]}
41
+ * bind:open={showPalette}
42
+ * />
43
+ */
44
+ declare const CommandPalette: import("svelte").Component<Props, {}, "open">;
45
+ type CommandPalette = ReturnType<typeof CommandPalette>;
46
+ export default CommandPalette;
47
+ //# sourceMappingURL=CommandPalette.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CommandPalette.svelte.d.ts","sourceRoot":"","sources":["../../../src/navigation/CommandPalette/CommandPalette.svelte.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,WAAW;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,MAAM,IAAI,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,WAAW,EAAE,CAAC;CACrB;AASD,UAAU,KAAK;IACd,6BAA6B;IAC7B,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,kCAAkC;IAClC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,uCAAuC;IACvC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,2BAA2B;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iCAAiC;IACjC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,cAAc;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AAgRD;;;;;;;;;;;;;;GAcG;AACH,QAAA,MAAM,cAAc,+CAAwC,CAAC;AAC7D,KAAK,cAAc,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AACxD,eAAe,cAAc,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { default as CommandPalette } from './CommandPalette.svelte';
2
+ export type { CommandItem, CommandGroup } from './CommandPalette.svelte';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/navigation/CommandPalette/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACpE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC"}
@@ -0,0 +1 @@
1
+ export { default as CommandPalette } from './CommandPalette.svelte';
@@ -1,3 +1,5 @@
1
1
  export { Tabs } from './Tabs/index.js';
2
2
  export type { TabOption } from './Tabs/index.js';
3
+ export { CommandPalette } from './CommandPalette/index.js';
4
+ export type { CommandItem, CommandGroup } from './CommandPalette/index.js';
3
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/navigation/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AACvC,YAAY,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/navigation/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AACvC,YAAY,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC"}
@@ -1 +1,2 @@
1
1
  export { Tabs } from './Tabs/index.js';
2
+ export { CommandPalette } from './CommandPalette/index.js';