@furystack/shades-common-components 10.0.35 → 11.0.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/CHANGELOG.md +66 -0
- package/esm/components/animations.spec.d.ts +2 -0
- package/esm/components/animations.spec.d.ts.map +1 -0
- package/esm/components/animations.spec.js +201 -0
- package/esm/components/animations.spec.js.map +1 -0
- package/esm/components/app-bar-link.js +21 -20
- package/esm/components/app-bar-link.js.map +1 -1
- package/esm/components/app-bar-link.spec.d.ts +2 -0
- package/esm/components/app-bar-link.spec.d.ts.map +1 -0
- package/esm/components/app-bar-link.spec.js +252 -0
- package/esm/components/app-bar-link.spec.js.map +1 -0
- package/esm/components/app-bar.js +21 -21
- package/esm/components/app-bar.js.map +1 -1
- package/esm/components/app-bar.spec.d.ts +2 -0
- package/esm/components/app-bar.spec.d.ts.map +1 -0
- package/esm/components/app-bar.spec.js +117 -0
- package/esm/components/app-bar.spec.js.map +1 -0
- package/esm/components/avatar.d.ts.map +1 -1
- package/esm/components/avatar.js +15 -19
- package/esm/components/avatar.js.map +1 -1
- package/esm/components/avatar.spec.d.ts +2 -0
- package/esm/components/avatar.spec.d.ts.map +1 -0
- package/esm/components/avatar.spec.js +114 -0
- package/esm/components/avatar.spec.js.map +1 -0
- package/esm/components/button.d.ts.map +1 -1
- package/esm/components/button.js +145 -156
- package/esm/components/button.js.map +1 -1
- package/esm/components/button.spec.d.ts +2 -0
- package/esm/components/button.spec.d.ts.map +1 -0
- package/esm/components/button.spec.js +155 -0
- package/esm/components/button.spec.js.map +1 -0
- package/esm/components/command-palette/command-palette-input.d.ts.map +1 -1
- package/esm/components/command-palette/command-palette-input.js +18 -16
- package/esm/components/command-palette/command-palette-input.js.map +1 -1
- package/esm/components/command-palette/command-palette-input.spec.d.ts +2 -0
- package/esm/components/command-palette/command-palette-input.spec.d.ts.map +1 -0
- package/esm/components/command-palette/command-palette-input.spec.js +233 -0
- package/esm/components/command-palette/command-palette-input.spec.js.map +1 -0
- package/esm/components/command-palette/command-palette-manager.spec.d.ts +2 -0
- package/esm/components/command-palette/command-palette-manager.spec.d.ts.map +1 -0
- package/esm/components/command-palette/command-palette-manager.spec.js +362 -0
- package/esm/components/command-palette/command-palette-manager.spec.js.map +1 -0
- package/esm/components/command-palette/command-palette-suggestion-list.d.ts.map +1 -1
- package/esm/components/command-palette/command-palette-suggestion-list.js +42 -46
- package/esm/components/command-palette/command-palette-suggestion-list.js.map +1 -1
- package/esm/components/command-palette/command-palette-suggestion-list.spec.d.ts +2 -0
- package/esm/components/command-palette/command-palette-suggestion-list.spec.d.ts.map +1 -0
- package/esm/components/command-palette/command-palette-suggestion-list.spec.js +376 -0
- package/esm/components/command-palette/command-palette-suggestion-list.spec.js.map +1 -0
- package/esm/components/command-palette/index.d.ts.map +1 -1
- package/esm/components/command-palette/index.js +100 -110
- package/esm/components/command-palette/index.js.map +1 -1
- package/esm/components/command-palette/index.spec.d.ts +2 -0
- package/esm/components/command-palette/index.spec.d.ts.map +1 -0
- package/esm/components/command-palette/index.spec.js +509 -0
- package/esm/components/command-palette/index.spec.js.map +1 -0
- package/esm/components/data-grid/body.js +1 -1
- package/esm/components/data-grid/body.js.map +1 -1
- package/esm/components/data-grid/body.spec.d.ts +2 -0
- package/esm/components/data-grid/body.spec.d.ts.map +1 -0
- package/esm/components/data-grid/body.spec.js +228 -0
- package/esm/components/data-grid/body.spec.js.map +1 -0
- package/esm/components/data-grid/data-grid-row.d.ts.map +1 -1
- package/esm/components/data-grid/data-grid-row.js +49 -73
- package/esm/components/data-grid/data-grid-row.js.map +1 -1
- package/esm/components/data-grid/data-grid-row.spec.d.ts +2 -0
- package/esm/components/data-grid/data-grid-row.spec.d.ts.map +1 -0
- package/esm/components/data-grid/data-grid-row.spec.js +296 -0
- package/esm/components/data-grid/data-grid-row.spec.js.map +1 -0
- package/esm/components/data-grid/data-grid.d.ts.map +1 -1
- package/esm/components/data-grid/data-grid.js +35 -28
- package/esm/components/data-grid/data-grid.js.map +1 -1
- package/esm/components/data-grid/data-grid.spec.d.ts +2 -0
- package/esm/components/data-grid/data-grid.spec.d.ts.map +1 -0
- package/esm/components/data-grid/data-grid.spec.js +544 -0
- package/esm/components/data-grid/data-grid.spec.js.map +1 -0
- package/esm/components/data-grid/footer.js +21 -15
- package/esm/components/data-grid/footer.js.map +1 -1
- package/esm/components/data-grid/footer.spec.d.ts +2 -0
- package/esm/components/data-grid/footer.spec.d.ts.map +1 -0
- package/esm/components/data-grid/footer.spec.js +264 -0
- package/esm/components/data-grid/footer.spec.js.map +1 -0
- package/esm/components/data-grid/header.d.ts.map +1 -1
- package/esm/components/data-grid/header.js +55 -33
- package/esm/components/data-grid/header.js.map +1 -1
- package/esm/components/data-grid/header.spec.d.ts +2 -0
- package/esm/components/data-grid/header.spec.d.ts.map +1 -0
- package/esm/components/data-grid/header.spec.js +421 -0
- package/esm/components/data-grid/header.spec.js.map +1 -0
- package/esm/components/data-grid/selection-cell.d.ts.map +1 -1
- package/esm/components/data-grid/selection-cell.js +13 -6
- package/esm/components/data-grid/selection-cell.js.map +1 -1
- package/esm/components/data-grid/selection-cell.spec.d.ts +2 -0
- package/esm/components/data-grid/selection-cell.spec.d.ts.map +1 -0
- package/esm/components/data-grid/selection-cell.spec.js +118 -0
- package/esm/components/data-grid/selection-cell.spec.js.map +1 -0
- package/esm/components/fab.d.ts.map +1 -1
- package/esm/components/fab.js +10 -1
- package/esm/components/fab.js.map +1 -1
- package/esm/components/fab.spec.d.ts +2 -0
- package/esm/components/fab.spec.d.ts.map +1 -0
- package/esm/components/fab.spec.js +95 -0
- package/esm/components/fab.spec.js.map +1 -0
- package/esm/components/form.spec.d.ts +2 -0
- package/esm/components/form.spec.d.ts.map +1 -0
- package/esm/components/form.spec.js +314 -0
- package/esm/components/form.spec.js.map +1 -0
- package/esm/components/grid.d.ts.map +1 -1
- package/esm/components/grid.js +40 -37
- package/esm/components/grid.js.map +1 -1
- package/esm/components/grid.spec.d.ts +2 -0
- package/esm/components/grid.spec.d.ts.map +1 -0
- package/esm/components/grid.spec.js +316 -0
- package/esm/components/grid.spec.js.map +1 -0
- package/esm/components/inputs/autocomplete.spec.d.ts +2 -0
- package/esm/components/inputs/autocomplete.spec.d.ts.map +1 -0
- package/esm/components/inputs/autocomplete.spec.js +194 -0
- package/esm/components/inputs/autocomplete.spec.js.map +1 -0
- package/esm/components/inputs/input.d.ts.map +1 -1
- package/esm/components/inputs/input.js +141 -109
- package/esm/components/inputs/input.js.map +1 -1
- package/esm/components/inputs/input.spec.d.ts +2 -0
- package/esm/components/inputs/input.spec.d.ts.map +1 -0
- package/esm/components/inputs/input.spec.js +577 -0
- package/esm/components/inputs/input.spec.js.map +1 -0
- package/esm/components/inputs/text-area.d.ts.map +1 -1
- package/esm/components/inputs/text-area.js +54 -58
- package/esm/components/inputs/text-area.js.map +1 -1
- package/esm/components/inputs/text-area.spec.d.ts +2 -0
- package/esm/components/inputs/text-area.spec.d.ts.map +1 -0
- package/esm/components/inputs/text-area.spec.js +214 -0
- package/esm/components/inputs/text-area.spec.js.map +1 -0
- package/esm/components/loader.js +1 -1
- package/esm/components/loader.js.map +1 -1
- package/esm/components/loader.spec.d.ts +2 -0
- package/esm/components/loader.spec.d.ts.map +1 -0
- package/esm/components/loader.spec.js +251 -0
- package/esm/components/loader.spec.js.map +1 -0
- package/esm/components/modal.d.ts.map +1 -1
- package/esm/components/modal.js +11 -9
- package/esm/components/modal.js.map +1 -1
- package/esm/components/modal.spec.d.ts +2 -0
- package/esm/components/modal.spec.d.ts.map +1 -0
- package/esm/components/modal.spec.js +227 -0
- package/esm/components/modal.spec.js.map +1 -0
- package/esm/components/noty-list.d.ts.map +1 -1
- package/esm/components/noty-list.js +39 -40
- package/esm/components/noty-list.js.map +1 -1
- package/esm/components/noty-list.spec.d.ts +2 -0
- package/esm/components/noty-list.spec.d.ts.map +1 -0
- package/esm/components/noty-list.spec.js +486 -0
- package/esm/components/noty-list.spec.js.map +1 -0
- package/esm/components/paper.d.ts.map +1 -1
- package/esm/components/paper.js +15 -12
- package/esm/components/paper.js.map +1 -1
- package/esm/components/paper.spec.d.ts +2 -0
- package/esm/components/paper.spec.d.ts.map +1 -0
- package/esm/components/paper.spec.js +63 -0
- package/esm/components/paper.spec.js.map +1 -0
- package/esm/components/skeleton.js +1 -1
- package/esm/components/skeleton.js.map +1 -1
- package/esm/components/skeleton.spec.d.ts +2 -0
- package/esm/components/skeleton.spec.d.ts.map +1 -0
- package/esm/components/skeleton.spec.js +159 -0
- package/esm/components/skeleton.spec.js.map +1 -0
- package/esm/components/styles.spec.d.ts +2 -0
- package/esm/components/styles.spec.d.ts.map +1 -0
- package/esm/components/styles.spec.js +56 -0
- package/esm/components/styles.spec.js.map +1 -0
- package/esm/components/suggest/index.d.ts.map +1 -1
- package/esm/components/suggest/index.js +74 -83
- package/esm/components/suggest/index.js.map +1 -1
- package/esm/components/suggest/index.spec.d.ts +2 -0
- package/esm/components/suggest/index.spec.d.ts.map +1 -0
- package/esm/components/suggest/index.spec.js +515 -0
- package/esm/components/suggest/index.spec.js.map +1 -0
- package/esm/components/suggest/suggest-input.d.ts.map +1 -1
- package/esm/components/suggest/suggest-input.js +16 -17
- package/esm/components/suggest/suggest-input.js.map +1 -1
- package/esm/components/suggest/suggest-input.spec.d.ts +2 -0
- package/esm/components/suggest/suggest-input.spec.d.ts.map +1 -0
- package/esm/components/suggest/suggest-input.spec.js +138 -0
- package/esm/components/suggest/suggest-input.spec.js.map +1 -0
- package/esm/components/suggest/suggest-manager.spec.d.ts +2 -0
- package/esm/components/suggest/suggest-manager.spec.d.ts.map +1 -0
- package/esm/components/suggest/suggest-manager.spec.js +308 -0
- package/esm/components/suggest/suggest-manager.spec.js.map +1 -0
- package/esm/components/suggest/suggestion-list.d.ts.map +1 -1
- package/esm/components/suggest/suggestion-list.js +43 -48
- package/esm/components/suggest/suggestion-list.js.map +1 -1
- package/esm/components/suggest/suggestion-list.spec.d.ts +2 -0
- package/esm/components/suggest/suggestion-list.spec.d.ts.map +1 -0
- package/esm/components/suggest/suggestion-list.spec.js +252 -0
- package/esm/components/suggest/suggestion-list.spec.js.map +1 -0
- package/esm/components/tabs.d.ts.map +1 -1
- package/esm/components/tabs.js +32 -18
- package/esm/components/tabs.js.map +1 -1
- package/esm/components/tabs.spec.d.ts +2 -0
- package/esm/components/tabs.spec.d.ts.map +1 -0
- package/esm/components/tabs.spec.js +187 -0
- package/esm/components/tabs.spec.js.map +1 -0
- package/esm/components/wizard/index.d.ts.map +1 -1
- package/esm/components/wizard/index.js +10 -7
- package/esm/components/wizard/index.js.map +1 -1
- package/esm/components/wizard/index.spec.d.ts +2 -0
- package/esm/components/wizard/index.spec.d.ts.map +1 -0
- package/esm/components/wizard/index.spec.js +171 -0
- package/esm/components/wizard/index.spec.js.map +1 -0
- package/esm/services/collection-service.spec.js +391 -2
- package/esm/services/collection-service.spec.js.map +1 -1
- package/esm/services/css-variable-theme.d.ts.map +1 -1
- package/esm/services/css-variable-theme.js +21 -1
- package/esm/services/css-variable-theme.js.map +1 -1
- package/esm/services/css-variable-theme.spec.d.ts +2 -0
- package/esm/services/css-variable-theme.spec.d.ts.map +1 -0
- package/esm/services/css-variable-theme.spec.js +169 -0
- package/esm/services/css-variable-theme.spec.js.map +1 -0
- package/esm/services/default-palette.d.ts +4 -0
- package/esm/services/default-palette.d.ts.map +1 -1
- package/esm/services/default-palette.js +22 -0
- package/esm/services/default-palette.js.map +1 -1
- package/esm/services/theme-provider-service.d.ts +59 -1
- package/esm/services/theme-provider-service.d.ts.map +1 -1
- package/esm/services/theme-provider-service.js.map +1 -1
- package/esm/services/theme-provider-service.spec.d.ts +2 -0
- package/esm/services/theme-provider-service.spec.d.ts.map +1 -0
- package/esm/services/theme-provider-service.spec.js +166 -0
- package/esm/services/theme-provider-service.spec.js.map +1 -0
- package/package.json +2 -2
- package/src/components/animations.spec.ts +299 -0
- package/src/components/app-bar-link.spec.tsx +341 -0
- package/src/components/app-bar-link.tsx +21 -21
- package/src/components/app-bar.spec.tsx +142 -0
- package/src/components/app-bar.tsx +22 -22
- package/src/components/avatar.spec.tsx +146 -0
- package/src/components/avatar.tsx +17 -20
- package/src/components/button.spec.tsx +193 -0
- package/src/components/button.tsx +162 -197
- package/src/components/command-palette/command-palette-input.spec.tsx +320 -0
- package/src/components/command-palette/command-palette-input.tsx +19 -22
- package/src/components/command-palette/command-palette-manager.spec.ts +470 -0
- package/src/components/command-palette/command-palette-suggestion-list.spec.tsx +499 -0
- package/src/components/command-palette/command-palette-suggestion-list.tsx +42 -46
- package/src/components/command-palette/index.spec.tsx +684 -0
- package/src/components/command-palette/index.tsx +107 -136
- package/src/components/data-grid/body.spec.tsx +340 -0
- package/src/components/data-grid/body.tsx +1 -1
- package/src/components/data-grid/data-grid-row.spec.tsx +382 -0
- package/src/components/data-grid/data-grid-row.tsx +50 -82
- package/src/components/data-grid/data-grid.spec.tsx +939 -0
- package/src/components/data-grid/data-grid.tsx +38 -35
- package/src/components/data-grid/footer.spec.tsx +344 -0
- package/src/components/data-grid/footer.tsx +19 -19
- package/src/components/data-grid/header.spec.tsx +563 -0
- package/src/components/data-grid/header.tsx +53 -44
- package/src/components/data-grid/selection-cell.spec.tsx +150 -0
- package/src/components/data-grid/selection-cell.tsx +12 -6
- package/src/components/fab.spec.tsx +108 -0
- package/src/components/fab.tsx +10 -1
- package/src/components/form.spec.tsx +481 -0
- package/src/components/grid.spec.tsx +334 -0
- package/src/components/grid.tsx +57 -63
- package/src/components/inputs/autocomplete.spec.tsx +258 -0
- package/src/components/inputs/input.spec.tsx +808 -0
- package/src/components/inputs/input.tsx +153 -139
- package/src/components/inputs/text-area.spec.tsx +285 -0
- package/src/components/inputs/text-area.tsx +53 -79
- package/src/components/loader.spec.tsx +346 -0
- package/src/components/loader.tsx +1 -1
- package/src/components/modal.spec.tsx +304 -0
- package/src/components/modal.tsx +11 -9
- package/src/components/noty-list.spec.tsx +631 -0
- package/src/components/noty-list.tsx +39 -50
- package/src/components/paper.spec.tsx +72 -0
- package/src/components/paper.tsx +15 -13
- package/src/components/skeleton.spec.tsx +219 -0
- package/src/components/skeleton.tsx +1 -1
- package/src/components/styles.spec.ts +70 -0
- package/src/components/suggest/index.spec.tsx +861 -0
- package/src/components/suggest/index.tsx +74 -101
- package/src/components/suggest/suggest-input.spec.tsx +181 -0
- package/src/components/suggest/suggest-input.tsx +16 -24
- package/src/components/suggest/suggest-manager.spec.ts +409 -0
- package/src/components/suggest/suggestion-list.spec.tsx +334 -0
- package/src/components/suggest/suggestion-list.tsx +43 -48
- package/src/components/tabs.spec.tsx +236 -0
- package/src/components/tabs.tsx +33 -21
- package/src/components/wizard/index.spec.tsx +224 -0
- package/src/components/wizard/index.tsx +10 -9
- package/src/services/collection-service.spec.ts +492 -3
- package/src/services/css-variable-theme.spec.ts +204 -0
- package/src/services/css-variable-theme.ts +21 -1
- package/src/services/default-palette.ts +22 -0
- package/src/services/theme-provider-service.spec.ts +195 -0
- package/src/services/theme-provider-service.ts +60 -2
|
@@ -0,0 +1,470 @@
|
|
|
1
|
+
import { Injector } from '@furystack/inject'
|
|
2
|
+
import { using, usingAsync } from '@furystack/utils'
|
|
3
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
4
|
+
import { CommandPaletteManager } from './command-palette-manager.js'
|
|
5
|
+
import type { CommandPaletteSuggestionResult, CommandProvider } from './command-provider.js'
|
|
6
|
+
|
|
7
|
+
const createMockSuggestion = (name: string, score: number): CommandPaletteSuggestionResult => ({
|
|
8
|
+
element: { tagName: 'div', textContent: name } as unknown as JSX.Element,
|
|
9
|
+
score,
|
|
10
|
+
onSelected: vi.fn(),
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
const createCommandProvider = (suggestions: CommandPaletteSuggestionResult[]): CommandProvider => {
|
|
14
|
+
return vi.fn().mockResolvedValue(suggestions)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
describe('CommandPaletteManager', () => {
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
vi.useFakeTimers()
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
afterEach(() => {
|
|
23
|
+
vi.useRealTimers()
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
describe('Construction and disposal', () => {
|
|
27
|
+
it('Should be constructed with command providers', () => {
|
|
28
|
+
const providers: CommandProvider[] = []
|
|
29
|
+
|
|
30
|
+
using(new CommandPaletteManager(providers), (manager) => {
|
|
31
|
+
expect(manager.isOpened.getValue()).toBe(false)
|
|
32
|
+
expect(manager.isLoading.getValue()).toBe(false)
|
|
33
|
+
expect(manager.term.getValue()).toBe('')
|
|
34
|
+
expect(manager.selectedIndex.getValue()).toBe(0)
|
|
35
|
+
expect(manager.currentSuggestions.getValue()).toEqual([])
|
|
36
|
+
})
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
it('Should register keyboard listener on construction', () => {
|
|
40
|
+
const addEventListenerSpy = vi.spyOn(window, 'addEventListener')
|
|
41
|
+
const providers: CommandProvider[] = []
|
|
42
|
+
|
|
43
|
+
using(new CommandPaletteManager(providers), () => {
|
|
44
|
+
expect(addEventListenerSpy).toHaveBeenCalledWith('keyup', expect.any(Function), true)
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
addEventListenerSpy.mockRestore()
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
it('Should dispose all observables and remove event listeners', () => {
|
|
51
|
+
const removeEventListenerSpy = vi.spyOn(window, 'removeEventListener')
|
|
52
|
+
const providers: CommandProvider[] = []
|
|
53
|
+
|
|
54
|
+
const manager = new CommandPaletteManager(providers)
|
|
55
|
+
|
|
56
|
+
const isOpenedDisposeSpy = vi.spyOn(manager.isOpened, Symbol.dispose)
|
|
57
|
+
const isLoadingDisposeSpy = vi.spyOn(manager.isLoading, Symbol.dispose)
|
|
58
|
+
const termDisposeSpy = vi.spyOn(manager.term, Symbol.dispose)
|
|
59
|
+
const selectedIndexDisposeSpy = vi.spyOn(manager.selectedIndex, Symbol.dispose)
|
|
60
|
+
const currentSuggestionsDisposeSpy = vi.spyOn(manager.currentSuggestions, Symbol.dispose)
|
|
61
|
+
|
|
62
|
+
manager[Symbol.dispose]()
|
|
63
|
+
|
|
64
|
+
expect(isOpenedDisposeSpy).toHaveBeenCalled()
|
|
65
|
+
expect(isLoadingDisposeSpy).toHaveBeenCalled()
|
|
66
|
+
expect(termDisposeSpy).toHaveBeenCalled()
|
|
67
|
+
expect(selectedIndexDisposeSpy).toHaveBeenCalled()
|
|
68
|
+
expect(currentSuggestionsDisposeSpy).toHaveBeenCalled()
|
|
69
|
+
|
|
70
|
+
expect(removeEventListenerSpy).toHaveBeenCalledWith('keyup', manager.keyPressListener)
|
|
71
|
+
|
|
72
|
+
removeEventListenerSpy.mockRestore()
|
|
73
|
+
})
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
describe('Keyboard shortcuts', () => {
|
|
77
|
+
it('Should open command palette on Ctrl+P', () => {
|
|
78
|
+
const providers: CommandProvider[] = []
|
|
79
|
+
|
|
80
|
+
using(new CommandPaletteManager(providers), (manager) => {
|
|
81
|
+
expect(manager.isOpened.getValue()).toBe(false)
|
|
82
|
+
|
|
83
|
+
manager.keyPressListener({ key: 'p', ctrlKey: true } as KeyboardEvent)
|
|
84
|
+
|
|
85
|
+
expect(manager.isOpened.getValue()).toBe(true)
|
|
86
|
+
})
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
it('Should open command palette on Ctrl+P (uppercase P)', () => {
|
|
90
|
+
const providers: CommandProvider[] = []
|
|
91
|
+
|
|
92
|
+
using(new CommandPaletteManager(providers), (manager) => {
|
|
93
|
+
expect(manager.isOpened.getValue()).toBe(false)
|
|
94
|
+
|
|
95
|
+
manager.keyPressListener({ key: 'P', ctrlKey: true } as KeyboardEvent)
|
|
96
|
+
|
|
97
|
+
expect(manager.isOpened.getValue()).toBe(true)
|
|
98
|
+
})
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
it('Should clear suggestions when opening with Ctrl+P', () => {
|
|
102
|
+
const suggestions = [createMockSuggestion('test', 1)]
|
|
103
|
+
const providers: CommandProvider[] = []
|
|
104
|
+
|
|
105
|
+
using(new CommandPaletteManager(providers), (manager) => {
|
|
106
|
+
manager.currentSuggestions.setValue(suggestions)
|
|
107
|
+
|
|
108
|
+
manager.keyPressListener({ key: 'p', ctrlKey: true } as KeyboardEvent)
|
|
109
|
+
|
|
110
|
+
expect(manager.currentSuggestions.getValue()).toEqual([])
|
|
111
|
+
})
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
it('Should not open command palette on P without Ctrl', () => {
|
|
115
|
+
const providers: CommandProvider[] = []
|
|
116
|
+
|
|
117
|
+
using(new CommandPaletteManager(providers), (manager) => {
|
|
118
|
+
manager.keyPressListener({ key: 'p', ctrlKey: false } as KeyboardEvent)
|
|
119
|
+
|
|
120
|
+
expect(manager.isOpened.getValue()).toBe(false)
|
|
121
|
+
})
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
it('Should not open command palette on Ctrl without P', () => {
|
|
125
|
+
const providers: CommandProvider[] = []
|
|
126
|
+
|
|
127
|
+
using(new CommandPaletteManager(providers), (manager) => {
|
|
128
|
+
manager.keyPressListener({ key: 'a', ctrlKey: true } as KeyboardEvent)
|
|
129
|
+
|
|
130
|
+
expect(manager.isOpened.getValue()).toBe(false)
|
|
131
|
+
})
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
it('Should close command palette on Escape', () => {
|
|
135
|
+
const providers: CommandProvider[] = []
|
|
136
|
+
|
|
137
|
+
using(new CommandPaletteManager(providers), (manager) => {
|
|
138
|
+
manager.isOpened.setValue(true)
|
|
139
|
+
expect(manager.isOpened.getValue()).toBe(true)
|
|
140
|
+
|
|
141
|
+
manager.keyPressListener({ key: 'Escape' } as KeyboardEvent)
|
|
142
|
+
|
|
143
|
+
expect(manager.isOpened.getValue()).toBe(false)
|
|
144
|
+
})
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
it('Should not close command palette for other keys', () => {
|
|
148
|
+
const providers: CommandProvider[] = []
|
|
149
|
+
|
|
150
|
+
using(new CommandPaletteManager(providers), (manager) => {
|
|
151
|
+
manager.isOpened.setValue(true)
|
|
152
|
+
|
|
153
|
+
manager.keyPressListener({ key: 'Enter' } as KeyboardEvent)
|
|
154
|
+
expect(manager.isOpened.getValue()).toBe(true)
|
|
155
|
+
|
|
156
|
+
manager.keyPressListener({ key: 'ArrowDown' } as KeyboardEvent)
|
|
157
|
+
expect(manager.isOpened.getValue()).toBe(true)
|
|
158
|
+
})
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
it('Should handle undefined key gracefully', () => {
|
|
162
|
+
const providers: CommandProvider[] = []
|
|
163
|
+
|
|
164
|
+
using(new CommandPaletteManager(providers), (manager) => {
|
|
165
|
+
manager.keyPressListener({ key: undefined, ctrlKey: true } as unknown as KeyboardEvent)
|
|
166
|
+
|
|
167
|
+
expect(manager.isOpened.getValue()).toBe(false)
|
|
168
|
+
})
|
|
169
|
+
})
|
|
170
|
+
})
|
|
171
|
+
|
|
172
|
+
describe('getSuggestion (debounced search)', () => {
|
|
173
|
+
it('Should load suggestions after debounce delay', async () => {
|
|
174
|
+
const suggestions = [createMockSuggestion('test', 1)]
|
|
175
|
+
const provider = createCommandProvider(suggestions)
|
|
176
|
+
const injector = new Injector()
|
|
177
|
+
|
|
178
|
+
await usingAsync(new CommandPaletteManager([provider]), async (manager) => {
|
|
179
|
+
void manager.getSuggestion({ injector, term: 'test' })
|
|
180
|
+
|
|
181
|
+
expect(provider).not.toHaveBeenCalled()
|
|
182
|
+
expect(manager.isLoading.getValue()).toBe(false)
|
|
183
|
+
|
|
184
|
+
await vi.advanceTimersByTimeAsync(250)
|
|
185
|
+
|
|
186
|
+
expect(provider).toHaveBeenCalledWith({ injector, term: 'test' })
|
|
187
|
+
expect(manager.currentSuggestions.getValue()).toHaveLength(1)
|
|
188
|
+
})
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
it('Should set isLoading while fetching', async () => {
|
|
192
|
+
let resolveProvider: (value: CommandPaletteSuggestionResult[]) => void
|
|
193
|
+
const providerPromise = new Promise<CommandPaletteSuggestionResult[]>((resolve) => {
|
|
194
|
+
resolveProvider = resolve
|
|
195
|
+
})
|
|
196
|
+
const provider = vi.fn().mockReturnValue(providerPromise)
|
|
197
|
+
const injector = new Injector()
|
|
198
|
+
|
|
199
|
+
await usingAsync(new CommandPaletteManager([provider]), async (manager) => {
|
|
200
|
+
void manager.getSuggestion({ injector, term: 'test' })
|
|
201
|
+
await vi.advanceTimersByTimeAsync(250)
|
|
202
|
+
|
|
203
|
+
expect(manager.isLoading.getValue()).toBe(true)
|
|
204
|
+
|
|
205
|
+
resolveProvider!([])
|
|
206
|
+
await vi.advanceTimersByTimeAsync(0)
|
|
207
|
+
|
|
208
|
+
expect(manager.isLoading.getValue()).toBe(false)
|
|
209
|
+
})
|
|
210
|
+
})
|
|
211
|
+
|
|
212
|
+
it('Should debounce multiple rapid calls', async () => {
|
|
213
|
+
const suggestions = [createMockSuggestion('test', 1)]
|
|
214
|
+
const provider = createCommandProvider(suggestions)
|
|
215
|
+
const injector = new Injector()
|
|
216
|
+
|
|
217
|
+
await usingAsync(new CommandPaletteManager([provider]), async (manager) => {
|
|
218
|
+
void manager.getSuggestion({ injector, term: 'a' })
|
|
219
|
+
await vi.advanceTimersByTimeAsync(100)
|
|
220
|
+
|
|
221
|
+
void manager.getSuggestion({ injector, term: 'ab' })
|
|
222
|
+
await vi.advanceTimersByTimeAsync(100)
|
|
223
|
+
|
|
224
|
+
void manager.getSuggestion({ injector, term: 'abc' })
|
|
225
|
+
await vi.advanceTimersByTimeAsync(250)
|
|
226
|
+
|
|
227
|
+
expect(provider).toHaveBeenCalledTimes(1)
|
|
228
|
+
expect(provider).toHaveBeenCalledWith({ injector, term: 'abc' })
|
|
229
|
+
})
|
|
230
|
+
})
|
|
231
|
+
|
|
232
|
+
it('Should not fetch again if term is unchanged', async () => {
|
|
233
|
+
const suggestions = [createMockSuggestion('test', 1)]
|
|
234
|
+
const provider = createCommandProvider(suggestions)
|
|
235
|
+
const injector = new Injector()
|
|
236
|
+
|
|
237
|
+
await usingAsync(new CommandPaletteManager([provider]), async (manager) => {
|
|
238
|
+
void manager.getSuggestion({ injector, term: 'test' })
|
|
239
|
+
await vi.advanceTimersByTimeAsync(250)
|
|
240
|
+
|
|
241
|
+
expect(provider).toHaveBeenCalledTimes(1)
|
|
242
|
+
|
|
243
|
+
void manager.getSuggestion({ injector, term: 'test' })
|
|
244
|
+
await vi.advanceTimersByTimeAsync(250)
|
|
245
|
+
|
|
246
|
+
expect(provider).toHaveBeenCalledTimes(1)
|
|
247
|
+
})
|
|
248
|
+
})
|
|
249
|
+
|
|
250
|
+
it('Should reset selectedIndex when fetching new suggestions', async () => {
|
|
251
|
+
const suggestions = [createMockSuggestion('test', 1)]
|
|
252
|
+
const provider = createCommandProvider(suggestions)
|
|
253
|
+
const injector = new Injector()
|
|
254
|
+
|
|
255
|
+
await usingAsync(new CommandPaletteManager([provider]), async (manager) => {
|
|
256
|
+
manager.selectedIndex.setValue(5)
|
|
257
|
+
|
|
258
|
+
void manager.getSuggestion({ injector, term: 'test' })
|
|
259
|
+
await vi.advanceTimersByTimeAsync(250)
|
|
260
|
+
|
|
261
|
+
expect(manager.selectedIndex.getValue()).toBe(0)
|
|
262
|
+
})
|
|
263
|
+
})
|
|
264
|
+
|
|
265
|
+
it('Should clear suggestions when starting new search', async () => {
|
|
266
|
+
const suggestions = [createMockSuggestion('test', 1)]
|
|
267
|
+
const provider = createCommandProvider(suggestions)
|
|
268
|
+
const injector = new Injector()
|
|
269
|
+
|
|
270
|
+
await usingAsync(new CommandPaletteManager([provider]), async (manager) => {
|
|
271
|
+
void manager.getSuggestion({ injector, term: 'test' })
|
|
272
|
+
await vi.advanceTimersByTimeAsync(250)
|
|
273
|
+
|
|
274
|
+
expect(manager.currentSuggestions.getValue()).toHaveLength(1)
|
|
275
|
+
|
|
276
|
+
void manager.getSuggestion({ injector, term: 'test2' })
|
|
277
|
+
await vi.advanceTimersByTimeAsync(250)
|
|
278
|
+
|
|
279
|
+
expect(manager.currentSuggestions.getValue()).toHaveLength(1)
|
|
280
|
+
})
|
|
281
|
+
})
|
|
282
|
+
|
|
283
|
+
it('Should set isLoading to false even when error occurs', async () => {
|
|
284
|
+
const provider = vi.fn().mockImplementation(async () => {
|
|
285
|
+
throw new Error('Network error')
|
|
286
|
+
})
|
|
287
|
+
const injector = new Injector()
|
|
288
|
+
|
|
289
|
+
// Suppress expected unhandled rejection from debounced async error
|
|
290
|
+
const errorHandler = (reason: unknown) => {
|
|
291
|
+
if ((reason as Error)?.message === 'Network error') {
|
|
292
|
+
return
|
|
293
|
+
}
|
|
294
|
+
throw reason
|
|
295
|
+
}
|
|
296
|
+
process.on('unhandledRejection', errorHandler)
|
|
297
|
+
|
|
298
|
+
try {
|
|
299
|
+
await usingAsync(new CommandPaletteManager([provider]), async (manager) => {
|
|
300
|
+
void manager.getSuggestion({ injector, term: 'test' })
|
|
301
|
+
await vi.advanceTimersByTimeAsync(250)
|
|
302
|
+
// Wait for promise rejection to be handled
|
|
303
|
+
await vi.advanceTimersByTimeAsync(0)
|
|
304
|
+
|
|
305
|
+
expect(manager.isLoading.getValue()).toBe(false)
|
|
306
|
+
})
|
|
307
|
+
} finally {
|
|
308
|
+
process.removeListener('unhandledRejection', errorHandler)
|
|
309
|
+
}
|
|
310
|
+
})
|
|
311
|
+
})
|
|
312
|
+
|
|
313
|
+
describe('Multiple command providers', () => {
|
|
314
|
+
it('Should call all providers when getting suggestions', async () => {
|
|
315
|
+
const provider1 = createCommandProvider([createMockSuggestion('cmd1', 1)])
|
|
316
|
+
const provider2 = createCommandProvider([createMockSuggestion('cmd2', 2)])
|
|
317
|
+
const provider3 = createCommandProvider([createMockSuggestion('cmd3', 3)])
|
|
318
|
+
const injector = new Injector()
|
|
319
|
+
|
|
320
|
+
await usingAsync(new CommandPaletteManager([provider1, provider2, provider3]), async (manager) => {
|
|
321
|
+
void manager.getSuggestion({ injector, term: 'test' })
|
|
322
|
+
await vi.advanceTimersByTimeAsync(250)
|
|
323
|
+
|
|
324
|
+
expect(provider1).toHaveBeenCalledWith({ injector, term: 'test' })
|
|
325
|
+
expect(provider2).toHaveBeenCalledWith({ injector, term: 'test' })
|
|
326
|
+
expect(provider3).toHaveBeenCalledWith({ injector, term: 'test' })
|
|
327
|
+
})
|
|
328
|
+
})
|
|
329
|
+
|
|
330
|
+
it('Should aggregate suggestions from all providers', async () => {
|
|
331
|
+
const provider1 = createCommandProvider([createMockSuggestion('cmd1', 1)])
|
|
332
|
+
const provider2 = createCommandProvider([createMockSuggestion('cmd2', 2), createMockSuggestion('cmd3', 3)])
|
|
333
|
+
const injector = new Injector()
|
|
334
|
+
|
|
335
|
+
await usingAsync(new CommandPaletteManager([provider1, provider2]), async (manager) => {
|
|
336
|
+
void manager.getSuggestion({ injector, term: 'test' })
|
|
337
|
+
await vi.advanceTimersByTimeAsync(250)
|
|
338
|
+
|
|
339
|
+
expect(manager.currentSuggestions.getValue()).toHaveLength(3)
|
|
340
|
+
})
|
|
341
|
+
})
|
|
342
|
+
|
|
343
|
+
it('Should sort suggestions by score', async () => {
|
|
344
|
+
const provider1 = createCommandProvider([createMockSuggestion('low', 1)])
|
|
345
|
+
const provider2 = createCommandProvider([createMockSuggestion('high', 10)])
|
|
346
|
+
const provider3 = createCommandProvider([createMockSuggestion('medium', 5)])
|
|
347
|
+
const injector = new Injector()
|
|
348
|
+
|
|
349
|
+
await usingAsync(new CommandPaletteManager([provider1, provider2, provider3]), async (manager) => {
|
|
350
|
+
void manager.getSuggestion({ injector, term: 'test' })
|
|
351
|
+
await vi.advanceTimersByTimeAsync(250)
|
|
352
|
+
|
|
353
|
+
const suggestions = manager.currentSuggestions.getValue()
|
|
354
|
+
expect(suggestions[0].score).toBe(1)
|
|
355
|
+
expect(suggestions[1].score).toBe(5)
|
|
356
|
+
expect(suggestions[2].score).toBe(10)
|
|
357
|
+
})
|
|
358
|
+
})
|
|
359
|
+
|
|
360
|
+
it('Should handle providers returning empty arrays', async () => {
|
|
361
|
+
const provider1 = createCommandProvider([createMockSuggestion('cmd1', 1)])
|
|
362
|
+
const provider2 = createCommandProvider([])
|
|
363
|
+
const injector = new Injector()
|
|
364
|
+
|
|
365
|
+
await usingAsync(new CommandPaletteManager([provider1, provider2]), async (manager) => {
|
|
366
|
+
void manager.getSuggestion({ injector, term: 'test' })
|
|
367
|
+
await vi.advanceTimersByTimeAsync(250)
|
|
368
|
+
|
|
369
|
+
expect(manager.currentSuggestions.getValue()).toHaveLength(1)
|
|
370
|
+
})
|
|
371
|
+
})
|
|
372
|
+
|
|
373
|
+
it('Should work with no providers', async () => {
|
|
374
|
+
const injector = new Injector()
|
|
375
|
+
|
|
376
|
+
await usingAsync(new CommandPaletteManager([]), async (manager) => {
|
|
377
|
+
void manager.getSuggestion({ injector, term: 'test' })
|
|
378
|
+
await vi.advanceTimersByTimeAsync(250)
|
|
379
|
+
|
|
380
|
+
expect(manager.currentSuggestions.getValue()).toHaveLength(0)
|
|
381
|
+
expect(manager.isLoading.getValue()).toBe(false)
|
|
382
|
+
})
|
|
383
|
+
})
|
|
384
|
+
|
|
385
|
+
it('Should handle provider errors gracefully', async () => {
|
|
386
|
+
const provider1 = createCommandProvider([createMockSuggestion('cmd1', 1)])
|
|
387
|
+
const provider2 = vi.fn().mockImplementation(async () => {
|
|
388
|
+
throw new Error('Provider failed')
|
|
389
|
+
})
|
|
390
|
+
const injector = new Injector()
|
|
391
|
+
|
|
392
|
+
// Suppress expected unhandled rejection from debounced async error
|
|
393
|
+
const errorHandler = (reason: unknown) => {
|
|
394
|
+
if ((reason as Error)?.message === 'Provider failed') {
|
|
395
|
+
return
|
|
396
|
+
}
|
|
397
|
+
throw reason
|
|
398
|
+
}
|
|
399
|
+
process.on('unhandledRejection', errorHandler)
|
|
400
|
+
|
|
401
|
+
try {
|
|
402
|
+
await usingAsync(new CommandPaletteManager([provider1, provider2]), async (manager) => {
|
|
403
|
+
void manager.getSuggestion({ injector, term: 'test' })
|
|
404
|
+
await vi.advanceTimersByTimeAsync(250)
|
|
405
|
+
// Wait for promise rejection to be handled
|
|
406
|
+
await vi.advanceTimersByTimeAsync(0)
|
|
407
|
+
|
|
408
|
+
expect(manager.isLoading.getValue()).toBe(false)
|
|
409
|
+
})
|
|
410
|
+
} finally {
|
|
411
|
+
process.removeListener('unhandledRejection', errorHandler)
|
|
412
|
+
}
|
|
413
|
+
})
|
|
414
|
+
})
|
|
415
|
+
|
|
416
|
+
describe('selectSuggestion', () => {
|
|
417
|
+
it('Should call onSelected callback with injector', async () => {
|
|
418
|
+
const suggestion = createMockSuggestion('cmd', 1)
|
|
419
|
+
const provider = createCommandProvider([suggestion])
|
|
420
|
+
const injector = new Injector()
|
|
421
|
+
|
|
422
|
+
await usingAsync(new CommandPaletteManager([provider]), async (manager) => {
|
|
423
|
+
void manager.getSuggestion({ injector, term: 'test' })
|
|
424
|
+
await vi.advanceTimersByTimeAsync(250)
|
|
425
|
+
|
|
426
|
+
manager.selectSuggestion(injector, 0)
|
|
427
|
+
|
|
428
|
+
expect(suggestion.onSelected).toHaveBeenCalledWith({ injector })
|
|
429
|
+
})
|
|
430
|
+
})
|
|
431
|
+
|
|
432
|
+
it('Should use current selectedIndex when no index provided', async () => {
|
|
433
|
+
const suggestions = [
|
|
434
|
+
createMockSuggestion('cmd1', 1),
|
|
435
|
+
createMockSuggestion('cmd2', 2),
|
|
436
|
+
createMockSuggestion('cmd3', 3),
|
|
437
|
+
]
|
|
438
|
+
const provider = createCommandProvider(suggestions)
|
|
439
|
+
const injector = new Injector()
|
|
440
|
+
|
|
441
|
+
await usingAsync(new CommandPaletteManager([provider]), async (manager) => {
|
|
442
|
+
void manager.getSuggestion({ injector, term: 'test' })
|
|
443
|
+
await vi.advanceTimersByTimeAsync(250)
|
|
444
|
+
|
|
445
|
+
manager.selectedIndex.setValue(2)
|
|
446
|
+
manager.selectSuggestion(injector)
|
|
447
|
+
|
|
448
|
+
expect(suggestions[2].onSelected).toHaveBeenCalledWith({ injector })
|
|
449
|
+
})
|
|
450
|
+
})
|
|
451
|
+
|
|
452
|
+
it('Should close the command palette after selection', async () => {
|
|
453
|
+
const suggestion = createMockSuggestion('cmd', 1)
|
|
454
|
+
const provider = createCommandProvider([suggestion])
|
|
455
|
+
const injector = new Injector()
|
|
456
|
+
|
|
457
|
+
await usingAsync(new CommandPaletteManager([provider]), async (manager) => {
|
|
458
|
+
void manager.getSuggestion({ injector, term: 'test' })
|
|
459
|
+
await vi.advanceTimersByTimeAsync(250)
|
|
460
|
+
|
|
461
|
+
manager.isOpened.setValue(true)
|
|
462
|
+
expect(manager.isOpened.getValue()).toBe(true)
|
|
463
|
+
|
|
464
|
+
manager.selectSuggestion(injector, 0)
|
|
465
|
+
|
|
466
|
+
expect(manager.isOpened.getValue()).toBe(false)
|
|
467
|
+
})
|
|
468
|
+
})
|
|
469
|
+
})
|
|
470
|
+
})
|