@furystack/shades-common-components 5.0.20 → 7.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/esm/components/command-palette/command-palette-input.d.ts.map +1 -1
- package/esm/components/command-palette/command-palette-input.js +26 -23
- package/esm/components/command-palette/command-palette-input.js.map +1 -1
- package/esm/components/command-palette/command-palette-suggestion-list.d.ts.map +1 -1
- package/esm/components/command-palette/command-palette-suggestion-list.js +33 -29
- package/esm/components/command-palette/command-palette-suggestion-list.js.map +1 -1
- package/esm/components/command-palette/index.d.ts.map +1 -1
- package/esm/components/command-palette/index.js +48 -44
- package/esm/components/command-palette/index.js.map +1 -1
- package/esm/components/data-grid/data-grid-row.d.ts.map +1 -1
- package/esm/components/data-grid/data-grid-row.js +37 -33
- package/esm/components/data-grid/data-grid-row.js.map +1 -1
- package/esm/components/data-grid/header.d.ts.map +1 -1
- package/esm/components/data-grid/header.js +28 -22
- package/esm/components/data-grid/header.js.map +1 -1
- package/esm/components/data-grid/selection-cell.d.ts.map +1 -1
- package/esm/components/data-grid/selection-cell.js +5 -3
- package/esm/components/data-grid/selection-cell.js.map +1 -1
- package/esm/components/inputs/input.js +1 -1
- package/esm/components/inputs/input.js.map +1 -1
- package/esm/components/noty-list.d.ts.map +1 -1
- package/esm/components/noty-list.js +6 -6
- package/esm/components/noty-list.js.map +1 -1
- package/esm/components/suggest/index.js +2 -2
- package/esm/components/suggest/index.js.map +1 -1
- package/esm/components/suggest/suggest-input.d.ts.map +1 -1
- package/esm/components/suggest/suggest-input.js +12 -9
- package/esm/components/suggest/suggest-input.js.map +1 -1
- package/esm/components/suggest/suggest-manager.d.ts +4 -3
- package/esm/components/suggest/suggest-manager.d.ts.map +1 -1
- package/esm/components/suggest/suggest-manager.js +7 -7
- package/esm/components/suggest/suggest-manager.js.map +1 -1
- package/esm/components/suggest/suggestion-list.js +32 -27
- package/esm/components/suggest/suggestion-list.js.map +1 -1
- package/esm/services/collection-service.d.ts.map +1 -1
- package/esm/services/collection-service.js +3 -2
- package/esm/services/collection-service.js.map +1 -1
- package/esm/services/collection-service.spec.d.ts +2 -0
- package/esm/services/collection-service.spec.d.ts.map +1 -0
- package/esm/services/collection-service.spec.js +28 -0
- package/esm/services/collection-service.spec.js.map +1 -0
- package/esm/services/noty-service.d.ts +11 -7
- package/esm/services/noty-service.d.ts.map +1 -1
- package/esm/services/noty-service.js +25 -14
- package/esm/services/noty-service.js.map +1 -1
- package/esm/services/noty-service.spec.d.ts +2 -0
- package/esm/services/noty-service.spec.d.ts.map +1 -0
- package/esm/services/noty-service.spec.js +20 -0
- package/esm/services/noty-service.spec.js.map +1 -0
- package/package.json +6 -6
- package/src/components/command-palette/command-palette-input.tsx +26 -28
- package/src/components/command-palette/command-palette-suggestion-list.tsx +42 -38
- package/src/components/command-palette/index.tsx +55 -51
- package/src/components/data-grid/data-grid-row.tsx +6 -7
- package/src/components/data-grid/header.tsx +27 -21
- package/src/components/data-grid/selection-cell.tsx +4 -2
- package/src/components/inputs/input.tsx +1 -1
- package/src/components/noty-list.tsx +16 -12
- package/src/components/suggest/index.tsx +2 -2
- package/src/components/suggest/suggest-input.tsx +4 -6
- package/src/components/suggest/suggest-manager.ts +7 -7
- package/src/components/suggest/suggestion-list.tsx +32 -32
- package/src/services/collection-service.spec.ts +37 -0
- package/src/services/collection-service.ts +3 -2
- package/src/services/noty-service.spec.ts +26 -0
- package/src/services/noty-service.ts +23 -11
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { NotyService } from './noty-service.js';
|
|
3
|
+
import { using } from '@furystack/utils';
|
|
4
|
+
describe('NotyService', () => {
|
|
5
|
+
it('Should add and removea noty', () => {
|
|
6
|
+
using(new NotyService(), (notyService) => {
|
|
7
|
+
expect(notyService.getNotyList()).toEqual([]);
|
|
8
|
+
const exampleNoty = {
|
|
9
|
+
type: 'info',
|
|
10
|
+
title: 'Test',
|
|
11
|
+
body: 'Test',
|
|
12
|
+
};
|
|
13
|
+
notyService.emit('onNotyAdded', exampleNoty);
|
|
14
|
+
expect(notyService.getNotyList()).toEqual([exampleNoty]);
|
|
15
|
+
notyService.emit('onNotyRemoved', exampleNoty);
|
|
16
|
+
expect(notyService.getNotyList()).toEqual([]);
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
//# sourceMappingURL=noty-service.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"noty-service.spec.js","sourceRoot":"","sources":["../../src/services/noty-service.spec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAE7C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AAExC,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC3B,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE;QACrC,KAAK,CAAC,IAAI,WAAW,EAAE,EAAE,CAAC,WAAW,EAAE,EAAE;YACvC,MAAM,CAAC,WAAW,CAAC,WAAW,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;YAE7C,MAAM,WAAW,GAAc;gBAC7B,IAAI,EAAE,MAAM;gBACZ,KAAK,EAAE,MAAM;gBACb,IAAI,EAAE,MAAM;aACb,CAAA;YAED,WAAW,CAAC,IAAI,CAAC,aAAa,EAAE,WAAW,CAAC,CAAA;YAE5C,MAAM,CAAC,WAAW,CAAC,WAAW,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,WAAW,CAAC,CAAC,CAAA;YAExD,WAAW,CAAC,IAAI,CAAC,eAAe,EAAE,WAAW,CAAC,CAAA;YAE9C,MAAM,CAAC,WAAW,CAAC,WAAW,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;QAC/C,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@furystack/shades-common-components",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "7.0.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -32,13 +32,13 @@
|
|
|
32
32
|
"license": "GPL-2.0",
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"typescript": "^5.4.2",
|
|
35
|
-
"vitest": "^1.
|
|
35
|
+
"vitest": "^1.4.0"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@furystack/core": "^
|
|
39
|
-
"@furystack/inject": "^
|
|
40
|
-
"@furystack/shades": "^
|
|
41
|
-
"@furystack/utils": "^
|
|
38
|
+
"@furystack/core": "^14.0.0",
|
|
39
|
+
"@furystack/inject": "^10.0.0",
|
|
40
|
+
"@furystack/shades": "^10.0.0",
|
|
41
|
+
"@furystack/utils": "^6.0.0",
|
|
42
42
|
"path-to-regexp": "^6.2.1",
|
|
43
43
|
"semaphore-async-await": "^1.5.1"
|
|
44
44
|
},
|
|
@@ -3,40 +3,38 @@ import { ThemeProviderService } from '../../services/theme-provider-service.js'
|
|
|
3
3
|
import { promisifyAnimation } from '../../utils/promisify-animation.js'
|
|
4
4
|
import type { CommandPaletteManager } from './command-palette-manager.js'
|
|
5
5
|
|
|
6
|
+
const updateComponent = async (element: HTMLElement, isOpened: boolean) => {
|
|
7
|
+
const input = element.firstChild as HTMLInputElement | null
|
|
8
|
+
if (input) {
|
|
9
|
+
if (isOpened) {
|
|
10
|
+
input.value = ''
|
|
11
|
+
await promisifyAnimation(element, [{ width: '0%' }, { width: '100%' }], {
|
|
12
|
+
duration: 300,
|
|
13
|
+
fill: 'forwards',
|
|
14
|
+
easing: 'cubic-bezier(0.595, 0.425, 0.415, 0.845)',
|
|
15
|
+
})
|
|
16
|
+
input.focus()
|
|
17
|
+
} else {
|
|
18
|
+
await promisifyAnimation(element, [{ width: '100%' }, { width: '0%' }], {
|
|
19
|
+
duration: 300,
|
|
20
|
+
fill: 'forwards',
|
|
21
|
+
easing: 'cubic-bezier(0.595, 0.425, 0.415, 0.845)',
|
|
22
|
+
})
|
|
23
|
+
input.value = ''
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
6
28
|
export const CommandPaletteInput = Shade<{ manager: CommandPaletteManager }>({
|
|
7
29
|
shadowDomName: 'shades-command-palette-input',
|
|
8
30
|
render: ({ element, props, injector, useObservable }) => {
|
|
9
31
|
const { theme } = injector.getInstance(ThemeProviderService)
|
|
10
32
|
const { manager } = props
|
|
11
33
|
|
|
12
|
-
useObservable(
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const input = element.firstChild as HTMLInputElement | null
|
|
17
|
-
if (input) {
|
|
18
|
-
if (isOpened) {
|
|
19
|
-
input.value = ''
|
|
20
|
-
await promisifyAnimation(element, [{ width: '0%' }, { width: '100%' }], {
|
|
21
|
-
duration: 300,
|
|
22
|
-
fill: 'forwards',
|
|
23
|
-
easing: 'cubic-bezier(0.595, 0.425, 0.415, 0.845)',
|
|
24
|
-
})
|
|
25
|
-
input.focus()
|
|
26
|
-
} else {
|
|
27
|
-
await promisifyAnimation(element, [{ width: '100%' }, { width: '0%' }], {
|
|
28
|
-
duration: 300,
|
|
29
|
-
fill: 'forwards',
|
|
30
|
-
easing: 'cubic-bezier(0.595, 0.425, 0.415, 0.845)',
|
|
31
|
-
})
|
|
32
|
-
input.value = ''
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
},
|
|
36
|
-
true,
|
|
37
|
-
)
|
|
38
|
-
|
|
39
|
-
element.style.width = manager.isOpened.getValue() ? '100%' : '0%'
|
|
34
|
+
const [isCurrentlyOpened] = useObservable('isOpened', manager.isOpened, {
|
|
35
|
+
onChange: (newValue) => updateComponent(element, newValue),
|
|
36
|
+
})
|
|
37
|
+
element.style.width = isCurrentlyOpened ? '100%' : '0%'
|
|
40
38
|
element.style.overflow = 'hidden'
|
|
41
39
|
return (
|
|
42
40
|
<input
|
|
@@ -10,46 +10,50 @@ export const CommandPaletteSuggestionList = Shade<{ manager: CommandPaletteManag
|
|
|
10
10
|
const { theme } = injector.getInstance(ThemeProviderService)
|
|
11
11
|
|
|
12
12
|
const [suggestions] = useObservable('suggestions', props.manager.currentSuggestions)
|
|
13
|
-
const [selectedIndex] = useObservable('selectedIndex', props.manager.selectedIndex,
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
13
|
+
const [selectedIndex] = useObservable('selectedIndex', props.manager.selectedIndex, {
|
|
14
|
+
onChange: (idx) => {
|
|
15
|
+
;([...element.querySelectorAll('.suggestion-item')] as HTMLDivElement[]).map((s, i) => {
|
|
16
|
+
if (i === idx) {
|
|
17
|
+
s.style.background = theme.background.paper
|
|
18
|
+
s.style.fontWeight = 'bolder'
|
|
19
|
+
} else {
|
|
20
|
+
s.style.background = theme.background.default
|
|
21
|
+
s.style.fontWeight = 'normal'
|
|
22
|
+
}
|
|
23
|
+
})
|
|
24
|
+
},
|
|
23
25
|
})
|
|
24
26
|
|
|
25
|
-
const [isOpenedAtRender] = useObservable('isOpenedAtRender', props.manager.isOpened,
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
27
|
+
const [isOpenedAtRender] = useObservable('isOpenedAtRender', props.manager.isOpened, {
|
|
28
|
+
onChange: async (isOpened) => {
|
|
29
|
+
const container = element.firstElementChild as HTMLDivElement
|
|
30
|
+
if (isOpened) {
|
|
31
|
+
container.style.display = 'initial'
|
|
32
|
+
container.style.zIndex = '1'
|
|
33
|
+
container.style.width = `calc(${Math.round(
|
|
34
|
+
element.parentElement?.getBoundingClientRect().width || 200,
|
|
35
|
+
)}px - 3em)`
|
|
36
|
+
await promisifyAnimation(
|
|
37
|
+
container,
|
|
38
|
+
[
|
|
39
|
+
{ opacity: 0, transform: 'translate(0, -50px)' },
|
|
40
|
+
{ opacity: 1, transform: 'translate(0, 0)' },
|
|
41
|
+
],
|
|
42
|
+
{ fill: 'forwards', duration: 500 },
|
|
43
|
+
)
|
|
44
|
+
} else {
|
|
45
|
+
await promisifyAnimation(
|
|
46
|
+
container,
|
|
47
|
+
[
|
|
48
|
+
{ opacity: 1, transform: 'translate(0, 0)' },
|
|
49
|
+
{ opacity: 0, transform: 'translate(0, -50px)' },
|
|
50
|
+
],
|
|
51
|
+
{ fill: 'forwards', duration: 200 },
|
|
52
|
+
)
|
|
53
|
+
container.style.zIndex = '-1'
|
|
54
|
+
container.style.display = 'none'
|
|
55
|
+
}
|
|
56
|
+
},
|
|
53
57
|
})
|
|
54
58
|
|
|
55
59
|
return (
|
|
@@ -29,69 +29,73 @@ export const CommandPalette = Shade<CommandPaletteProps>({
|
|
|
29
29
|
|
|
30
30
|
useDisposable('clickAwayService', () => new ClickAwayService(element, () => manager.isOpened.setValue(false)))
|
|
31
31
|
|
|
32
|
-
const [isLoadingAtRender] = useObservable('isLoading', manager.isLoading,
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
})
|
|
39
|
-
} else {
|
|
40
|
-
promisifyAnimation(loader, [{ opacity: 1 }, { opacity: 0 }], {
|
|
41
|
-
duration: 100,
|
|
42
|
-
fill: 'forwards',
|
|
43
|
-
})
|
|
44
|
-
}
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
const [isOpenedAtRender, setIsOpened] = useObservable('isOpened', manager.isOpened, (isOpened) => {
|
|
48
|
-
{
|
|
49
|
-
const suggestions = element.querySelector('.close-suggestions')
|
|
50
|
-
const postControls = element.querySelector('.post-controls')
|
|
51
|
-
const inputContainer = element.querySelector('.input-container') as HTMLDivElement
|
|
52
|
-
if (isOpened) {
|
|
53
|
-
promisifyAnimation(suggestions, [{ opacity: 0 }, { opacity: 1 }], {
|
|
54
|
-
duration: 500,
|
|
32
|
+
const [isLoadingAtRender] = useObservable('isLoading', manager.isLoading, {
|
|
33
|
+
onChange: async (isLoading) => {
|
|
34
|
+
const loader = element.querySelector('.loader-container')
|
|
35
|
+
if (isLoading) {
|
|
36
|
+
promisifyAnimation(loader, [{ opacity: 0 }, { opacity: 1 }], {
|
|
37
|
+
duration: 100,
|
|
55
38
|
fill: 'forwards',
|
|
56
39
|
})
|
|
57
|
-
|
|
58
|
-
promisifyAnimation(
|
|
40
|
+
} else {
|
|
41
|
+
promisifyAnimation(loader, [{ opacity: 1 }, { opacity: 0 }], {
|
|
59
42
|
duration: 100,
|
|
60
43
|
fill: 'forwards',
|
|
61
44
|
})
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
})
|
|
62
48
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
49
|
+
const [isOpenedAtRender, setIsOpened] = useObservable('isOpened', manager.isOpened, {
|
|
50
|
+
onChange: (isOpened) => {
|
|
51
|
+
{
|
|
52
|
+
const suggestions = element.querySelector('.close-suggestions')
|
|
53
|
+
const postControls = element.querySelector('.post-controls')
|
|
54
|
+
const inputContainer = element.querySelector('.input-container') as HTMLDivElement
|
|
55
|
+
if (isOpened) {
|
|
56
|
+
promisifyAnimation(suggestions, [{ opacity: 0 }, { opacity: 1 }], {
|
|
67
57
|
duration: 500,
|
|
68
58
|
fill: 'forwards',
|
|
69
|
-
|
|
70
|
-
},
|
|
71
|
-
)
|
|
72
|
-
} else {
|
|
73
|
-
promisifyAnimation(suggestions, [{ opacity: 1 }, { opacity: 0 }], {
|
|
74
|
-
duration: 500,
|
|
75
|
-
fill: 'forwards',
|
|
76
|
-
})
|
|
59
|
+
})
|
|
77
60
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
61
|
+
promisifyAnimation(postControls, [{ width: '0px' }, { width: '50px' }], {
|
|
62
|
+
duration: 100,
|
|
63
|
+
fill: 'forwards',
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
promisifyAnimation(
|
|
67
|
+
inputContainer,
|
|
68
|
+
[{ background: 'transparent' }, { background: theme.background.default }],
|
|
69
|
+
{
|
|
70
|
+
duration: 500,
|
|
71
|
+
fill: 'forwards',
|
|
72
|
+
easing: 'cubic-bezier(0.050, 0.570, 0.840, 1.005)',
|
|
73
|
+
},
|
|
74
|
+
)
|
|
75
|
+
} else {
|
|
76
|
+
promisifyAnimation(suggestions, [{ opacity: 1 }, { opacity: 0 }], {
|
|
77
|
+
duration: 500,
|
|
78
|
+
fill: 'forwards',
|
|
79
|
+
})
|
|
83
80
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
[{ background: theme.background.default }, { background: 'transparent' }],
|
|
87
|
-
{
|
|
88
|
-
duration: 300,
|
|
81
|
+
promisifyAnimation(postControls, [{ width: '50px' }, { width: '0px' }], {
|
|
82
|
+
duration: 500,
|
|
89
83
|
fill: 'forwards',
|
|
90
|
-
|
|
91
|
-
}
|
|
92
|
-
|
|
84
|
+
delay: 300,
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
promisifyAnimation(
|
|
88
|
+
inputContainer,
|
|
89
|
+
[{ background: theme.background.default }, { background: 'transparent' }],
|
|
90
|
+
{
|
|
91
|
+
duration: 300,
|
|
92
|
+
fill: 'forwards',
|
|
93
|
+
easing: 'cubic-bezier(0.000, 0.245, 0.190, 0.790)',
|
|
94
|
+
},
|
|
95
|
+
)
|
|
96
|
+
}
|
|
93
97
|
}
|
|
94
|
-
}
|
|
98
|
+
},
|
|
95
99
|
})
|
|
96
100
|
|
|
97
101
|
return (
|
|
@@ -39,14 +39,14 @@ export const DataGridRow: <T>(props: DataGridRowProps<T>, children: ChildrenList
|
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
// TODO: getLast is elmiminated, do we need it?
|
|
43
|
+
const [selection] = useObservable('isSelected', service.selection, { onChange: attachSelectedStyles })
|
|
43
44
|
|
|
44
45
|
attachSelectedStyles(selection)
|
|
45
46
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
(newEntry) => {
|
|
47
|
+
// TODO: getLast is elmiminated, do we need it?
|
|
48
|
+
const [focus] = useObservable('focus', service.focusedEntry, {
|
|
49
|
+
onChange: (newEntry) => {
|
|
50
50
|
if (newEntry === props.entry) {
|
|
51
51
|
attachStyles(element, {
|
|
52
52
|
style: props.focusedRowStyle || {
|
|
@@ -84,8 +84,7 @@ export const DataGridRow: <T>(props: DataGridRowProps<T>, children: ChildrenList
|
|
|
84
84
|
})
|
|
85
85
|
}
|
|
86
86
|
},
|
|
87
|
-
|
|
88
|
-
)
|
|
87
|
+
})
|
|
89
88
|
|
|
90
89
|
element.style.display = 'table-row'
|
|
91
90
|
element.style.cursor = 'default'
|
|
@@ -61,14 +61,16 @@ export const OrderButton = Shade<{ collectionService: CollectionService<any>; fi
|
|
|
61
61
|
const SearchButton = Shade<{ service: CollectionService<any>; fieldName: string; onclick: () => void }>({
|
|
62
62
|
shadowDomName: 'data-grid-search-button',
|
|
63
63
|
render: ({ props, useObservable, element }) => {
|
|
64
|
-
const [queryState] = useObservable('currentFilterState', props.service.querySettings,
|
|
65
|
-
|
|
64
|
+
const [queryState] = useObservable('currentFilterState', props.service.querySettings, {
|
|
65
|
+
onChange: (currentQueryState) => {
|
|
66
|
+
const currentValue = (currentQueryState.filter?.[props.fieldName] as any)?.$regex || ''
|
|
66
67
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
68
|
+
const button = element.querySelector('button') as HTMLInputElement
|
|
69
|
+
button.innerHTML = currentValue ? '🔍' : '🔎'
|
|
70
|
+
button.style.textShadow = currentValue
|
|
71
|
+
? '1px 1px 20px rgba(235,225,45,0.9), 1px 1px 12px rgba(235,225,45,0.9), 0px 0px 3px rgba(255,200,145,0.6)'
|
|
72
|
+
: 'none'
|
|
73
|
+
},
|
|
72
74
|
})
|
|
73
75
|
|
|
74
76
|
const filterValue = (queryState.filter as any)?.[props.fieldName]?.$regex || ''
|
|
@@ -100,9 +102,11 @@ const SearchForm = Shade<{
|
|
|
100
102
|
render: ({ props, useObservable, element }) => {
|
|
101
103
|
type SearchSubmitType = { searchValue: string }
|
|
102
104
|
|
|
103
|
-
const [queryState] = useObservable('currentFilterState', props.service.querySettings,
|
|
104
|
-
|
|
105
|
-
|
|
105
|
+
const [queryState] = useObservable('currentFilterState', props.service.querySettings, {
|
|
106
|
+
onChange: (currentQueryState) => {
|
|
107
|
+
const currentValue = (currentQueryState.filter?.[props.fieldName] as any)?.$regex || ''
|
|
108
|
+
;(element.querySelector('input') as HTMLInputElement).value = currentValue
|
|
109
|
+
},
|
|
106
110
|
})
|
|
107
111
|
|
|
108
112
|
return (
|
|
@@ -157,17 +161,19 @@ export const DataGridHeader: <T, K extends keyof T>(
|
|
|
157
161
|
) => JSX.Element<any> = Shade<DataGridHeaderProps<any, any>>({
|
|
158
162
|
shadowDomName: 'data-grid-header',
|
|
159
163
|
render: ({ props, element, useObservable }) => {
|
|
160
|
-
const [, setIsSearchOpened] = useObservable('isSearchOpened', new ObservableValue(false),
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
164
|
+
const [, setIsSearchOpened] = useObservable('isSearchOpened', new ObservableValue(false), {
|
|
165
|
+
onChange: (newValue) => {
|
|
166
|
+
const searchForm = element.querySelector('.search-form') as HTMLElement
|
|
167
|
+
const headerContent = element.querySelector('.header-content') as HTMLElement
|
|
168
|
+
if (!newValue) {
|
|
169
|
+
collapse(searchForm)
|
|
170
|
+
expand(headerContent)
|
|
171
|
+
} else {
|
|
172
|
+
searchForm.style.display = 'flex'
|
|
173
|
+
expand(searchForm).then(() => searchForm.querySelector('input')?.focus())
|
|
174
|
+
collapse(headerContent)
|
|
175
|
+
}
|
|
176
|
+
},
|
|
171
177
|
})
|
|
172
178
|
const updateSearchValue = (value?: string) => {
|
|
173
179
|
const currentSettings = props.collectionService.querySettings.getValue()
|
|
@@ -4,8 +4,10 @@ import type { CollectionService } from '../../services/collection-service.js'
|
|
|
4
4
|
export const SelectionCell = Shade<{ entry: any; service: CollectionService<any> }>({
|
|
5
5
|
shadowDomName: 'shades-data-grid-selection-cell',
|
|
6
6
|
render: ({ props, useObservable, element }) => {
|
|
7
|
-
const [selection] = useObservable('selection', props.service.selection,
|
|
8
|
-
|
|
7
|
+
const [selection] = useObservable('selection', props.service.selection, {
|
|
8
|
+
onChange: (newSelection) => {
|
|
9
|
+
;(element.querySelector('input') as HTMLInputElement).checked = newSelection.includes(props.entry)
|
|
10
|
+
},
|
|
9
11
|
})
|
|
10
12
|
const isSelected = selection.includes(props.entry)
|
|
11
13
|
|
|
@@ -139,27 +139,31 @@ export const NotyList = Shade({
|
|
|
139
139
|
display: 'flex',
|
|
140
140
|
flexDirection: 'column',
|
|
141
141
|
},
|
|
142
|
-
render: ({
|
|
142
|
+
render: ({ useDisposable, injector, element }) => {
|
|
143
143
|
const notyService = injector.getInstance(NotyService)
|
|
144
144
|
|
|
145
|
-
const currentNotys = notyService.
|
|
145
|
+
const currentNotys = notyService.getNotyList()
|
|
146
146
|
|
|
147
|
-
|
|
148
|
-
|
|
147
|
+
useDisposable('addNoty', () =>
|
|
148
|
+
notyService.subscribe('onNotyAdded', (n) =>
|
|
149
|
+
element.append(<NotyComponent model={n} onDismiss={() => notyService.emit('onNotyRemoved', n)} />),
|
|
150
|
+
),
|
|
149
151
|
)
|
|
150
152
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
e.
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
153
|
+
useDisposable('removeNoty', () =>
|
|
154
|
+
notyService.subscribe('onNotyRemoved', (n) => {
|
|
155
|
+
element.querySelectorAll('shade-noty').forEach((e) => {
|
|
156
|
+
if ((e as JSX.Element).props.model === n) {
|
|
157
|
+
e.remove()
|
|
158
|
+
}
|
|
159
|
+
})
|
|
160
|
+
}),
|
|
161
|
+
)
|
|
158
162
|
|
|
159
163
|
return (
|
|
160
164
|
<>
|
|
161
165
|
{currentNotys.map((n) => (
|
|
162
|
-
<NotyComponent model={n} onDismiss={() => injector.getInstance(NotyService).
|
|
166
|
+
<NotyComponent model={n} onDismiss={() => injector.getInstance(NotyService).emit('onNotyRemoved', n)} />
|
|
163
167
|
))}
|
|
164
168
|
</>
|
|
165
169
|
)
|
|
@@ -28,7 +28,7 @@ export const Suggest: <T>(props: SuggestProps<T>, children: ChildrenList) => JSX
|
|
|
28
28
|
style: {
|
|
29
29
|
flexGrow: '1',
|
|
30
30
|
},
|
|
31
|
-
render: ({ props, injector, element, useDisposable
|
|
31
|
+
render: ({ props, injector, element, useDisposable }) => {
|
|
32
32
|
const manager = useDisposable('manager', () => new SuggestManager(props.getEntries, props.getSuggestionEntry))
|
|
33
33
|
const { theme } = injector.getInstance(ThemeProviderService)
|
|
34
34
|
const inputContainer = element.querySelector('.input-container') as HTMLDivElement
|
|
@@ -85,7 +85,7 @@ export const Suggest: <T>(props: SuggestProps<T>, children: ChildrenList) => JSX
|
|
|
85
85
|
})
|
|
86
86
|
}
|
|
87
87
|
})
|
|
88
|
-
|
|
88
|
+
useDisposable('onSelectSuggestion', () => manager.subscribe('onSelectSuggestion', props.onSelectSuggestion))
|
|
89
89
|
return (
|
|
90
90
|
<div
|
|
91
91
|
style={{ display: 'flex', flexDirection: 'column' }}
|
|
@@ -11,10 +11,9 @@ export const SuggestInput = Shade<{ manager: SuggestManager<any> }>({
|
|
|
11
11
|
render: ({ element, props, useObservable, injector }) => {
|
|
12
12
|
const { theme } = injector.getInstance(ThemeProviderService)
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
(isOpened) => {
|
|
14
|
+
// todo: getLast is eliminated, do we need it?
|
|
15
|
+
useObservable('isOpened', props.manager.isOpened, {
|
|
16
|
+
onChange: (isOpened) => {
|
|
18
17
|
const input = element.firstChild as HTMLInputElement
|
|
19
18
|
if (isOpened) {
|
|
20
19
|
input.focus()
|
|
@@ -22,8 +21,7 @@ export const SuggestInput = Shade<{ manager: SuggestManager<any> }>({
|
|
|
22
21
|
input.value = ''
|
|
23
22
|
}
|
|
24
23
|
},
|
|
25
|
-
|
|
26
|
-
)
|
|
24
|
+
})
|
|
27
25
|
|
|
28
26
|
return (
|
|
29
27
|
<input
|
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
import type { Injector } from '@furystack/inject'
|
|
2
2
|
import { Injectable } from '@furystack/inject'
|
|
3
3
|
import type { Disposable } from '@furystack/utils'
|
|
4
|
-
import { debounce, ObservableValue } from '@furystack/utils'
|
|
4
|
+
import { debounce, EventHub, ObservableValue } from '@furystack/utils'
|
|
5
5
|
import type { SuggestionResult } from './suggestion-result.js'
|
|
6
6
|
|
|
7
7
|
@Injectable({ lifetime: 'singleton' })
|
|
8
|
-
export class SuggestManager<T> implements Disposable {
|
|
8
|
+
export class SuggestManager<T> extends EventHub<'onSelectSuggestion', { onSelectSuggestion: T }> implements Disposable {
|
|
9
9
|
public isOpened = new ObservableValue(false)
|
|
10
10
|
public isLoading = new ObservableValue(false)
|
|
11
11
|
public term = new ObservableValue('')
|
|
12
12
|
public selectedIndex = new ObservableValue(0)
|
|
13
13
|
public currentSuggestions = new ObservableValue<Array<{ entry: T; suggestion: SuggestionResult }>>([])
|
|
14
|
-
public onSelectSuggestion = new ObservableValue<T>()
|
|
15
14
|
|
|
16
15
|
public keyPressListener = ((ev: KeyboardEvent) => {
|
|
17
16
|
if (ev.key === 'Escape') {
|
|
@@ -31,20 +30,20 @@ export class SuggestManager<T> implements Disposable {
|
|
|
31
30
|
}).bind(this)
|
|
32
31
|
|
|
33
32
|
public dispose() {
|
|
34
|
-
window.removeEventListener('keyup', this.keyPressListener)
|
|
35
|
-
window.removeEventListener('click', this.clickOutsideListener)
|
|
33
|
+
window.removeEventListener('keyup', this.keyPressListener, true)
|
|
34
|
+
window.removeEventListener('click', this.clickOutsideListener, true)
|
|
36
35
|
this.isOpened.dispose()
|
|
37
36
|
this.isLoading.dispose()
|
|
38
37
|
this.term.dispose()
|
|
39
38
|
this.selectedIndex.dispose()
|
|
40
39
|
this.currentSuggestions.dispose()
|
|
41
|
-
|
|
40
|
+
super.dispose()
|
|
42
41
|
}
|
|
43
42
|
|
|
44
43
|
public selectSuggestion(index: number = this.selectedIndex.getValue()) {
|
|
45
44
|
const selectedSuggestion = this.currentSuggestions.getValue()[index]
|
|
46
45
|
this.isOpened.setValue(false)
|
|
47
|
-
this.onSelectSuggestion
|
|
46
|
+
this.emit('onSelectSuggestion', selectedSuggestion.entry)
|
|
48
47
|
}
|
|
49
48
|
|
|
50
49
|
private lastGetSuggestionOptions?: { injector: Injector; term: string }
|
|
@@ -74,6 +73,7 @@ export class SuggestManager<T> implements Disposable {
|
|
|
74
73
|
private readonly getEntries: (term: string) => Promise<T[]>,
|
|
75
74
|
private readonly getSuggestionEntry: (entry: T) => SuggestionResult,
|
|
76
75
|
) {
|
|
76
|
+
super()
|
|
77
77
|
window.addEventListener('keyup', this.keyPressListener, true)
|
|
78
78
|
window.addEventListener('click', this.clickOutsideListener, true)
|
|
79
79
|
}
|