@furystack/shades-common-components 12.4.0 → 12.6.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 +119 -0
- package/esm/components/app-bar-link.spec.js +16 -19
- package/esm/components/app-bar-link.spec.js.map +1 -1
- package/esm/components/app-bar.spec.js +6 -4
- package/esm/components/app-bar.spec.js.map +1 -1
- package/esm/components/avatar.spec.js +9 -9
- package/esm/components/avatar.spec.js.map +1 -1
- package/esm/components/breadcrumb.spec.js +2 -2
- package/esm/components/breadcrumb.spec.js.map +1 -1
- package/esm/components/button-group.d.ts +32 -0
- package/esm/components/button-group.d.ts.map +1 -1
- package/esm/components/button-group.js +26 -2
- package/esm/components/button-group.js.map +1 -1
- package/esm/components/button-group.spec.js +127 -11
- package/esm/components/button-group.spec.js.map +1 -1
- package/esm/components/button.spec.js +4 -4
- package/esm/components/button.spec.js.map +1 -1
- package/esm/components/cache-view.spec.js +2 -3
- package/esm/components/cache-view.spec.js.map +1 -1
- package/esm/components/carousel.spec.js +47 -47
- package/esm/components/carousel.spec.js.map +1 -1
- package/esm/components/circular-progress.spec.js +2 -2
- package/esm/components/command-palette/command-palette-input.spec.js +23 -19
- package/esm/components/command-palette/command-palette-input.spec.js.map +1 -1
- package/esm/components/command-palette/command-palette-suggestion-list.spec.js +27 -27
- package/esm/components/command-palette/command-palette-suggestion-list.spec.js.map +1 -1
- package/esm/components/command-palette/index.spec.js +64 -51
- package/esm/components/command-palette/index.spec.js.map +1 -1
- package/esm/components/context-menu/context-menu.spec.js +33 -33
- package/esm/components/context-menu/context-menu.spec.js.map +1 -1
- package/esm/components/data-grid/body.spec.js +13 -13
- package/esm/components/data-grid/body.spec.js.map +1 -1
- package/esm/components/data-grid/data-grid-row.spec.js +8 -8
- package/esm/components/data-grid/data-grid-row.spec.js.map +1 -1
- package/esm/components/data-grid/data-grid.d.ts +47 -3
- package/esm/components/data-grid/data-grid.d.ts.map +1 -1
- package/esm/components/data-grid/data-grid.js +8 -11
- package/esm/components/data-grid/data-grid.js.map +1 -1
- package/esm/components/data-grid/data-grid.spec.js +71 -28
- package/esm/components/data-grid/data-grid.spec.js.map +1 -1
- package/esm/components/data-grid/filters/boolean-filter.d.ts +12 -0
- package/esm/components/data-grid/filters/boolean-filter.d.ts.map +1 -0
- package/esm/components/data-grid/filters/boolean-filter.js +27 -0
- package/esm/components/data-grid/filters/boolean-filter.js.map +1 -0
- package/esm/components/data-grid/filters/boolean-filter.spec.d.ts +2 -0
- package/esm/components/data-grid/filters/boolean-filter.spec.d.ts.map +1 -0
- package/esm/components/data-grid/filters/boolean-filter.spec.js +114 -0
- package/esm/components/data-grid/filters/boolean-filter.spec.js.map +1 -0
- package/esm/components/data-grid/filters/date-filter.d.ts +12 -0
- package/esm/components/data-grid/filters/date-filter.d.ts.map +1 -0
- package/esm/components/data-grid/filters/date-filter.js +109 -0
- package/esm/components/data-grid/filters/date-filter.js.map +1 -0
- package/esm/components/data-grid/filters/date-filter.spec.d.ts +2 -0
- package/esm/components/data-grid/filters/date-filter.spec.d.ts.map +1 -0
- package/esm/components/data-grid/filters/date-filter.spec.js +145 -0
- package/esm/components/data-grid/filters/date-filter.spec.js.map +1 -0
- package/esm/components/data-grid/filters/enum-filter.d.ts +16 -0
- package/esm/components/data-grid/filters/enum-filter.d.ts.map +1 -0
- package/esm/components/data-grid/filters/enum-filter.js +72 -0
- package/esm/components/data-grid/filters/enum-filter.js.map +1 -0
- package/esm/components/data-grid/filters/enum-filter.spec.d.ts +2 -0
- package/esm/components/data-grid/filters/enum-filter.spec.d.ts.map +1 -0
- package/esm/components/data-grid/filters/enum-filter.spec.js +136 -0
- package/esm/components/data-grid/filters/enum-filter.spec.js.map +1 -0
- package/esm/components/data-grid/filters/filter-dropdown.d.ts +6 -0
- package/esm/components/data-grid/filters/filter-dropdown.d.ts.map +1 -0
- package/esm/components/data-grid/filters/filter-dropdown.js +41 -0
- package/esm/components/data-grid/filters/filter-dropdown.js.map +1 -0
- package/esm/components/data-grid/filters/filter-dropdown.spec.d.ts +2 -0
- package/esm/components/data-grid/filters/filter-dropdown.spec.d.ts.map +1 -0
- package/esm/components/data-grid/filters/filter-dropdown.spec.js +69 -0
- package/esm/components/data-grid/filters/filter-dropdown.spec.js.map +1 -0
- package/esm/components/data-grid/filters/filter-styles.d.ts +24 -0
- package/esm/components/data-grid/filters/filter-styles.d.ts.map +1 -0
- package/esm/components/data-grid/filters/filter-styles.js +25 -0
- package/esm/components/data-grid/filters/filter-styles.js.map +1 -0
- package/esm/components/data-grid/filters/index.d.ts +7 -0
- package/esm/components/data-grid/filters/index.d.ts.map +1 -0
- package/esm/components/data-grid/filters/index.js +7 -0
- package/esm/components/data-grid/filters/index.js.map +1 -0
- package/esm/components/data-grid/filters/number-filter.d.ts +12 -0
- package/esm/components/data-grid/filters/number-filter.d.ts.map +1 -0
- package/esm/components/data-grid/filters/number-filter.js +65 -0
- package/esm/components/data-grid/filters/number-filter.js.map +1 -0
- package/esm/components/data-grid/filters/number-filter.spec.d.ts +2 -0
- package/esm/components/data-grid/filters/number-filter.spec.d.ts.map +1 -0
- package/esm/components/data-grid/filters/number-filter.spec.js +142 -0
- package/esm/components/data-grid/filters/number-filter.spec.js.map +1 -0
- package/esm/components/data-grid/filters/string-filter.d.ts +12 -0
- package/esm/components/data-grid/filters/string-filter.d.ts.map +1 -0
- package/esm/components/data-grid/filters/string-filter.js +63 -0
- package/esm/components/data-grid/filters/string-filter.js.map +1 -0
- package/esm/components/data-grid/filters/string-filter.spec.d.ts +2 -0
- package/esm/components/data-grid/filters/string-filter.spec.d.ts.map +1 -0
- package/esm/components/data-grid/filters/string-filter.spec.js +128 -0
- package/esm/components/data-grid/filters/string-filter.spec.js.map +1 -0
- package/esm/components/data-grid/footer.d.ts +1 -0
- package/esm/components/data-grid/footer.d.ts.map +1 -1
- package/esm/components/data-grid/footer.js +24 -16
- package/esm/components/data-grid/footer.js.map +1 -1
- package/esm/components/data-grid/footer.spec.js +111 -71
- package/esm/components/data-grid/footer.spec.js.map +1 -1
- package/esm/components/data-grid/header.d.ts +6 -9
- package/esm/components/data-grid/header.d.ts.map +1 -1
- package/esm/components/data-grid/header.js +51 -117
- package/esm/components/data-grid/header.js.map +1 -1
- package/esm/components/data-grid/header.spec.js +116 -187
- package/esm/components/data-grid/header.spec.js.map +1 -1
- package/esm/components/data-grid/index.d.ts +1 -0
- package/esm/components/data-grid/index.d.ts.map +1 -1
- package/esm/components/data-grid/index.js +1 -0
- package/esm/components/data-grid/index.js.map +1 -1
- package/esm/components/data-grid/selection-cell.spec.js +8 -8
- package/esm/components/data-grid/selection-cell.spec.js.map +1 -1
- package/esm/components/drawer/drawer-toggle-button.spec.js +22 -22
- package/esm/components/drawer/drawer-toggle-button.spec.js.map +1 -1
- package/esm/components/drawer/index.spec.js +36 -36
- package/esm/components/drawer/index.spec.js.map +1 -1
- package/esm/components/dropdown.spec.js +38 -30
- package/esm/components/dropdown.spec.js.map +1 -1
- package/esm/components/fab.spec.js +4 -4
- package/esm/components/fab.spec.js.map +1 -1
- package/esm/components/form.spec.js +37 -37
- package/esm/components/form.spec.js.map +1 -1
- package/esm/components/grid.d.ts +3 -0
- package/esm/components/grid.d.ts.map +1 -1
- package/esm/components/grid.js +3 -0
- package/esm/components/grid.js.map +1 -1
- package/esm/components/grid.spec.js +3 -3
- package/esm/components/grid.spec.js.map +1 -1
- package/esm/components/image.spec.js +55 -52
- package/esm/components/image.spec.js.map +1 -1
- package/esm/components/inputs/autocomplete.d.ts +3 -0
- package/esm/components/inputs/autocomplete.d.ts.map +1 -1
- package/esm/components/inputs/autocomplete.js +3 -0
- package/esm/components/inputs/autocomplete.js.map +1 -1
- package/esm/components/inputs/autocomplete.spec.js +7 -14
- package/esm/components/inputs/autocomplete.spec.js.map +1 -1
- package/esm/components/inputs/checkbox.spec.js +22 -22
- package/esm/components/inputs/checkbox.spec.js.map +1 -1
- package/esm/components/inputs/input-number.spec.js +47 -47
- package/esm/components/inputs/input-number.spec.js.map +1 -1
- package/esm/components/inputs/input.spec.js +53 -53
- package/esm/components/inputs/input.spec.js.map +1 -1
- package/esm/components/inputs/radio-group.spec.js +14 -14
- package/esm/components/inputs/radio-group.spec.js.map +1 -1
- package/esm/components/inputs/radio.spec.js +16 -16
- package/esm/components/inputs/radio.spec.js.map +1 -1
- package/esm/components/inputs/select.spec.js +74 -74
- package/esm/components/inputs/select.spec.js.map +1 -1
- package/esm/components/inputs/slider.spec.js +16 -16
- package/esm/components/inputs/slider.spec.js.map +1 -1
- package/esm/components/inputs/switch.spec.js +24 -24
- package/esm/components/inputs/switch.spec.js.map +1 -1
- package/esm/components/inputs/text-area.spec.js +17 -17
- package/esm/components/inputs/text-area.spec.js.map +1 -1
- package/esm/components/linear-progress.spec.js +2 -2
- package/esm/components/list/list.d.ts +10 -0
- package/esm/components/list/list.d.ts.map +1 -1
- package/esm/components/list/list.js +23 -2
- package/esm/components/list/list.js.map +1 -1
- package/esm/components/list/list.spec.js +137 -36
- package/esm/components/list/list.spec.js.map +1 -1
- package/esm/components/markdown/markdown-display.spec.js +15 -15
- package/esm/components/markdown/markdown-display.spec.js.map +1 -1
- package/esm/components/markdown/markdown-editor.spec.js +8 -8
- package/esm/components/markdown/markdown-editor.spec.js.map +1 -1
- package/esm/components/markdown/markdown-input.d.ts +14 -0
- package/esm/components/markdown/markdown-input.d.ts.map +1 -1
- package/esm/components/markdown/markdown-input.js +48 -2
- package/esm/components/markdown/markdown-input.js.map +1 -1
- package/esm/components/markdown/markdown-input.spec.js +114 -17
- package/esm/components/markdown/markdown-input.spec.js.map +1 -1
- package/esm/components/menu/menu.spec.js +28 -28
- package/esm/components/menu/menu.spec.js.map +1 -1
- package/esm/components/modal.spec.js +15 -18
- package/esm/components/modal.spec.js.map +1 -1
- package/esm/components/noty-list.spec.js +25 -23
- package/esm/components/noty-list.spec.js.map +1 -1
- package/esm/components/page-container/index.spec.js +16 -16
- package/esm/components/page-container/index.spec.js.map +1 -1
- package/esm/components/page-container/page-header.spec.js +16 -16
- package/esm/components/page-container/page-header.spec.js.map +1 -1
- package/esm/components/page-layout/index.spec.js +29 -29
- package/esm/components/page-layout/index.spec.js.map +1 -1
- package/esm/components/paper.spec.js +3 -3
- package/esm/components/paper.spec.js.map +1 -1
- package/esm/components/rating.spec.js +61 -61
- package/esm/components/rating.spec.js.map +1 -1
- package/esm/components/skeleton.spec.js +10 -6
- package/esm/components/skeleton.spec.js.map +1 -1
- package/esm/components/suggest/index.d.ts +10 -2
- package/esm/components/suggest/index.d.ts.map +1 -1
- package/esm/components/suggest/index.js +21 -1
- package/esm/components/suggest/index.js.map +1 -1
- package/esm/components/suggest/index.spec.js +50 -0
- package/esm/components/suggest/index.spec.js.map +1 -1
- package/esm/components/suggest/suggest-input.spec.js +4 -10
- package/esm/components/suggest/suggest-input.spec.js.map +1 -1
- package/esm/components/tabs.spec.js +30 -30
- package/esm/components/tabs.spec.js.map +1 -1
- package/esm/components/tree/tree.spec.js +27 -27
- package/esm/components/tree/tree.spec.js.map +1 -1
- package/esm/components/typography.spec.js +3 -3
- package/esm/components/typography.spec.js.map +1 -1
- package/esm/components/wizard/index.d.ts +8 -0
- package/esm/components/wizard/index.d.ts.map +1 -1
- package/esm/components/wizard/index.js +90 -0
- package/esm/components/wizard/index.js.map +1 -1
- package/esm/components/wizard/index.spec.js +84 -7
- package/esm/components/wizard/index.spec.js.map +1 -1
- package/esm/utils/promisify-animation.d.ts.map +1 -1
- package/esm/utils/promisify-animation.js +3 -0
- package/esm/utils/promisify-animation.js.map +1 -1
- package/package.json +3 -3
- package/src/components/app-bar-link.spec.tsx +16 -19
- package/src/components/app-bar.spec.tsx +6 -4
- package/src/components/avatar.spec.tsx +9 -9
- package/src/components/breadcrumb.spec.tsx +2 -2
- package/src/components/button-group.spec.tsx +155 -11
- package/src/components/button-group.tsx +49 -2
- package/src/components/button.spec.tsx +4 -4
- package/src/components/cache-view.spec.tsx +3 -3
- package/src/components/carousel.spec.tsx +47 -47
- package/src/components/circular-progress.spec.tsx +2 -2
- package/src/components/command-palette/command-palette-input.spec.tsx +23 -19
- package/src/components/command-palette/command-palette-suggestion-list.spec.tsx +27 -27
- package/src/components/command-palette/index.spec.tsx +64 -51
- package/src/components/context-menu/context-menu.spec.tsx +33 -33
- package/src/components/data-grid/body.spec.tsx +13 -13
- package/src/components/data-grid/data-grid-row.spec.tsx +8 -8
- package/src/components/data-grid/data-grid.spec.tsx +106 -28
- package/src/components/data-grid/data-grid.tsx +57 -13
- package/src/components/data-grid/filters/boolean-filter.spec.tsx +142 -0
- package/src/components/data-grid/filters/boolean-filter.tsx +45 -0
- package/src/components/data-grid/filters/date-filter.spec.tsx +181 -0
- package/src/components/data-grid/filters/date-filter.tsx +162 -0
- package/src/components/data-grid/filters/enum-filter.spec.tsx +168 -0
- package/src/components/data-grid/filters/enum-filter.tsx +119 -0
- package/src/components/data-grid/filters/filter-dropdown.spec.tsx +89 -0
- package/src/components/data-grid/filters/filter-dropdown.tsx +60 -0
- package/src/components/data-grid/filters/filter-styles.ts +26 -0
- package/src/components/data-grid/filters/index.ts +6 -0
- package/src/components/data-grid/filters/number-filter.spec.tsx +174 -0
- package/src/components/data-grid/filters/number-filter.tsx +115 -0
- package/src/components/data-grid/filters/string-filter.spec.tsx +157 -0
- package/src/components/data-grid/filters/string-filter.tsx +112 -0
- package/src/components/data-grid/footer.spec.tsx +130 -74
- package/src/components/data-grid/footer.tsx +41 -34
- package/src/components/data-grid/header.spec.tsx +128 -212
- package/src/components/data-grid/header.tsx +95 -183
- package/src/components/data-grid/index.tsx +1 -0
- package/src/components/data-grid/selection-cell.spec.tsx +8 -8
- package/src/components/drawer/drawer-toggle-button.spec.tsx +22 -22
- package/src/components/drawer/index.spec.tsx +36 -36
- package/src/components/dropdown.spec.tsx +38 -30
- package/src/components/fab.spec.tsx +4 -4
- package/src/components/form.spec.tsx +37 -37
- package/src/components/grid.spec.tsx +3 -3
- package/src/components/grid.tsx +3 -0
- package/src/components/image.spec.tsx +55 -52
- package/src/components/inputs/autocomplete.spec.tsx +7 -14
- package/src/components/inputs/autocomplete.tsx +3 -0
- package/src/components/inputs/checkbox.spec.tsx +22 -22
- package/src/components/inputs/input-number.spec.tsx +47 -47
- package/src/components/inputs/input.spec.tsx +53 -53
- package/src/components/inputs/radio-group.spec.tsx +14 -14
- package/src/components/inputs/radio.spec.tsx +16 -16
- package/src/components/inputs/select.spec.tsx +74 -74
- package/src/components/inputs/slider.spec.tsx +16 -16
- package/src/components/inputs/switch.spec.tsx +24 -24
- package/src/components/inputs/text-area.spec.tsx +17 -17
- package/src/components/linear-progress.spec.tsx +2 -2
- package/src/components/list/list.spec.tsx +209 -36
- package/src/components/list/list.tsx +56 -19
- package/src/components/markdown/markdown-display.spec.tsx +15 -15
- package/src/components/markdown/markdown-editor.spec.tsx +8 -8
- package/src/components/markdown/markdown-input.spec.tsx +159 -17
- package/src/components/markdown/markdown-input.tsx +65 -1
- package/src/components/menu/menu.spec.tsx +28 -28
- package/src/components/modal.spec.tsx +15 -18
- package/src/components/noty-list.spec.tsx +25 -23
- package/src/components/page-container/index.spec.tsx +16 -16
- package/src/components/page-container/page-header.spec.tsx +16 -16
- package/src/components/page-layout/index.spec.tsx +29 -29
- package/src/components/paper.spec.tsx +3 -3
- package/src/components/rating.spec.tsx +61 -61
- package/src/components/skeleton.spec.tsx +10 -6
- package/src/components/suggest/index.spec.tsx +83 -0
- package/src/components/suggest/index.tsx +36 -3
- package/src/components/suggest/suggest-input.spec.tsx +4 -10
- package/src/components/tabs.spec.tsx +30 -30
- package/src/components/tree/tree.spec.tsx +27 -27
- package/src/components/typography.spec.tsx +3 -3
- package/src/components/wizard/index.spec.tsx +123 -6
- package/src/components/wizard/index.tsx +125 -0
- package/src/utils/promisify-animation.ts +3 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Injector } from '@furystack/inject'
|
|
2
|
-
import { createComponent, initializeShadeRoot } from '@furystack/shades'
|
|
3
|
-
import {
|
|
2
|
+
import { createComponent, flushUpdates, initializeShadeRoot } from '@furystack/shades'
|
|
3
|
+
import { usingAsync } from '@furystack/utils'
|
|
4
4
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
5
5
|
import { MarkdownEditor } from './markdown-editor.js'
|
|
6
6
|
|
|
@@ -24,7 +24,7 @@ describe('MarkdownEditor', () => {
|
|
|
24
24
|
jsxElement: <MarkdownEditor value="# Hello" />,
|
|
25
25
|
})
|
|
26
26
|
|
|
27
|
-
await
|
|
27
|
+
await flushUpdates()
|
|
28
28
|
|
|
29
29
|
const el = document.querySelector('shade-markdown-editor')
|
|
30
30
|
expect(el).not.toBeNull()
|
|
@@ -42,7 +42,7 @@ describe('MarkdownEditor', () => {
|
|
|
42
42
|
jsxElement: <MarkdownEditor value="# Hello" />,
|
|
43
43
|
})
|
|
44
44
|
|
|
45
|
-
await
|
|
45
|
+
await flushUpdates()
|
|
46
46
|
|
|
47
47
|
const split = document.querySelector('.md-editor-split') as HTMLElement
|
|
48
48
|
expect(split).not.toBeNull()
|
|
@@ -68,7 +68,7 @@ describe('MarkdownEditor', () => {
|
|
|
68
68
|
jsxElement: <MarkdownEditor value="# Hello" layout="above-below" />,
|
|
69
69
|
})
|
|
70
70
|
|
|
71
|
-
await
|
|
71
|
+
await flushUpdates()
|
|
72
72
|
|
|
73
73
|
const split = document.querySelector('.md-editor-split') as HTMLElement
|
|
74
74
|
expect(split).not.toBeNull()
|
|
@@ -88,7 +88,7 @@ describe('MarkdownEditor', () => {
|
|
|
88
88
|
jsxElement: <MarkdownEditor value="# Hello" layout="tabs" />,
|
|
89
89
|
})
|
|
90
90
|
|
|
91
|
-
await
|
|
91
|
+
await flushUpdates()
|
|
92
92
|
|
|
93
93
|
const tabs = document.querySelector('shade-markdown-editor shade-tabs')
|
|
94
94
|
expect(tabs).not.toBeNull()
|
|
@@ -108,7 +108,7 @@ describe('MarkdownEditor', () => {
|
|
|
108
108
|
jsxElement: <MarkdownEditor value="# Hello" layout="tabs" />,
|
|
109
109
|
})
|
|
110
110
|
|
|
111
|
-
await
|
|
111
|
+
await flushUpdates()
|
|
112
112
|
|
|
113
113
|
const input = document.querySelector('shade-markdown-editor shade-markdown-input')
|
|
114
114
|
expect(input).not.toBeNull()
|
|
@@ -127,7 +127,7 @@ describe('MarkdownEditor', () => {
|
|
|
127
127
|
jsxElement: <MarkdownEditor value={mdContent} />,
|
|
128
128
|
})
|
|
129
129
|
|
|
130
|
-
await
|
|
130
|
+
await flushUpdates()
|
|
131
131
|
|
|
132
132
|
const textarea = document.querySelector('shade-markdown-editor textarea') as HTMLTextAreaElement
|
|
133
133
|
expect(textarea.value).toBe(mdContent)
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { Injector } from '@furystack/inject'
|
|
2
|
-
import { createComponent, initializeShadeRoot } from '@furystack/shades'
|
|
3
|
-
import {
|
|
2
|
+
import { createComponent, flushUpdates, initializeShadeRoot } from '@furystack/shades'
|
|
3
|
+
import { usingAsync } from '@furystack/utils'
|
|
4
4
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
5
|
+
import { Form } from '../form.js'
|
|
5
6
|
import { MarkdownInput } from './markdown-input.js'
|
|
6
7
|
|
|
7
8
|
describe('MarkdownInput', () => {
|
|
@@ -24,7 +25,7 @@ describe('MarkdownInput', () => {
|
|
|
24
25
|
jsxElement: <MarkdownInput value="" />,
|
|
25
26
|
})
|
|
26
27
|
|
|
27
|
-
await
|
|
28
|
+
await flushUpdates()
|
|
28
29
|
|
|
29
30
|
const el = document.querySelector('shade-markdown-input')
|
|
30
31
|
expect(el).not.toBeNull()
|
|
@@ -41,7 +42,7 @@ describe('MarkdownInput', () => {
|
|
|
41
42
|
jsxElement: <MarkdownInput value="# Hello" />,
|
|
42
43
|
})
|
|
43
44
|
|
|
44
|
-
await
|
|
45
|
+
await flushUpdates()
|
|
45
46
|
|
|
46
47
|
const textarea = document.querySelector('shade-markdown-input textarea') as HTMLTextAreaElement
|
|
47
48
|
expect(textarea).not.toBeNull()
|
|
@@ -59,7 +60,7 @@ describe('MarkdownInput', () => {
|
|
|
59
60
|
jsxElement: <MarkdownInput value="" labelTitle="Markdown Content" />,
|
|
60
61
|
})
|
|
61
62
|
|
|
62
|
-
await
|
|
63
|
+
await flushUpdates()
|
|
63
64
|
|
|
64
65
|
const label = document.querySelector('shade-markdown-input label')
|
|
65
66
|
expect(label?.textContent).toContain('Markdown Content')
|
|
@@ -76,7 +77,7 @@ describe('MarkdownInput', () => {
|
|
|
76
77
|
jsxElement: <MarkdownInput value="" placeholder="Type markdown..." />,
|
|
77
78
|
})
|
|
78
79
|
|
|
79
|
-
await
|
|
80
|
+
await flushUpdates()
|
|
80
81
|
|
|
81
82
|
const textarea = document.querySelector('shade-markdown-input textarea') as HTMLTextAreaElement
|
|
82
83
|
expect(textarea.placeholder).toBe('Type markdown...')
|
|
@@ -93,7 +94,7 @@ describe('MarkdownInput', () => {
|
|
|
93
94
|
jsxElement: <MarkdownInput value="" disabled />,
|
|
94
95
|
})
|
|
95
96
|
|
|
96
|
-
await
|
|
97
|
+
await flushUpdates()
|
|
97
98
|
|
|
98
99
|
const wrapper = document.querySelector('shade-markdown-input') as HTMLElement
|
|
99
100
|
expect(wrapper.hasAttribute('data-disabled')).toBe(true)
|
|
@@ -113,7 +114,7 @@ describe('MarkdownInput', () => {
|
|
|
113
114
|
jsxElement: <MarkdownInput value="" readOnly />,
|
|
114
115
|
})
|
|
115
116
|
|
|
116
|
-
await
|
|
117
|
+
await flushUpdates()
|
|
117
118
|
|
|
118
119
|
const textarea = document.querySelector('shade-markdown-input textarea') as HTMLTextAreaElement
|
|
119
120
|
expect(textarea.readOnly).toBe(true)
|
|
@@ -131,13 +132,13 @@ describe('MarkdownInput', () => {
|
|
|
131
132
|
jsxElement: <MarkdownInput value="" onValueChange={onValueChange} />,
|
|
132
133
|
})
|
|
133
134
|
|
|
134
|
-
await
|
|
135
|
+
await flushUpdates()
|
|
135
136
|
|
|
136
137
|
const textarea = document.querySelector('shade-markdown-input textarea') as HTMLTextAreaElement
|
|
137
138
|
textarea.value = '# New content'
|
|
138
139
|
textarea.dispatchEvent(new Event('input', { bubbles: true }))
|
|
139
140
|
|
|
140
|
-
await
|
|
141
|
+
await flushUpdates()
|
|
141
142
|
|
|
142
143
|
expect(onValueChange).toHaveBeenCalledWith('# New content')
|
|
143
144
|
})
|
|
@@ -153,13 +154,154 @@ describe('MarkdownInput', () => {
|
|
|
153
154
|
jsxElement: <MarkdownInput value="" rows={20} />,
|
|
154
155
|
})
|
|
155
156
|
|
|
156
|
-
await
|
|
157
|
+
await flushUpdates()
|
|
157
158
|
|
|
158
159
|
const textarea = document.querySelector('shade-markdown-input textarea') as HTMLTextAreaElement
|
|
159
160
|
expect(textarea.rows).toBe(20)
|
|
160
161
|
})
|
|
161
162
|
})
|
|
162
163
|
|
|
164
|
+
it('should set name attribute on textarea', async () => {
|
|
165
|
+
await usingAsync(new Injector(), async (injector) => {
|
|
166
|
+
const rootElement = document.getElementById('root') as HTMLDivElement
|
|
167
|
+
|
|
168
|
+
initializeShadeRoot({
|
|
169
|
+
injector,
|
|
170
|
+
rootElement,
|
|
171
|
+
jsxElement: <MarkdownInput value="" name="description" />,
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
await flushUpdates()
|
|
175
|
+
|
|
176
|
+
const textarea = document.querySelector('shade-markdown-input textarea') as HTMLTextAreaElement
|
|
177
|
+
expect(textarea.name).toBe('description')
|
|
178
|
+
})
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
it('should set required attribute on textarea', async () => {
|
|
182
|
+
await usingAsync(new Injector(), async (injector) => {
|
|
183
|
+
const rootElement = document.getElementById('root') as HTMLDivElement
|
|
184
|
+
|
|
185
|
+
initializeShadeRoot({
|
|
186
|
+
injector,
|
|
187
|
+
rootElement,
|
|
188
|
+
jsxElement: <MarkdownInput value="" required />,
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
await flushUpdates()
|
|
192
|
+
|
|
193
|
+
const textarea = document.querySelector('shade-markdown-input textarea') as HTMLTextAreaElement
|
|
194
|
+
expect(textarea.required).toBe(true)
|
|
195
|
+
})
|
|
196
|
+
})
|
|
197
|
+
|
|
198
|
+
it('should set data-invalid when required and value is empty', async () => {
|
|
199
|
+
await usingAsync(new Injector(), async (injector) => {
|
|
200
|
+
const rootElement = document.getElementById('root') as HTMLDivElement
|
|
201
|
+
|
|
202
|
+
initializeShadeRoot({
|
|
203
|
+
injector,
|
|
204
|
+
rootElement,
|
|
205
|
+
jsxElement: <MarkdownInput value="" required />,
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
await flushUpdates()
|
|
209
|
+
|
|
210
|
+
const wrapper = document.querySelector('shade-markdown-input') as HTMLElement
|
|
211
|
+
expect(wrapper.hasAttribute('data-invalid')).toBe(true)
|
|
212
|
+
})
|
|
213
|
+
})
|
|
214
|
+
|
|
215
|
+
it('should not set data-invalid when required and value is provided', async () => {
|
|
216
|
+
await usingAsync(new Injector(), async (injector) => {
|
|
217
|
+
const rootElement = document.getElementById('root') as HTMLDivElement
|
|
218
|
+
|
|
219
|
+
initializeShadeRoot({
|
|
220
|
+
injector,
|
|
221
|
+
rootElement,
|
|
222
|
+
jsxElement: <MarkdownInput value="some content" required />,
|
|
223
|
+
})
|
|
224
|
+
|
|
225
|
+
await flushUpdates()
|
|
226
|
+
|
|
227
|
+
const wrapper = document.querySelector('shade-markdown-input') as HTMLElement
|
|
228
|
+
expect(wrapper.hasAttribute('data-invalid')).toBe(false)
|
|
229
|
+
})
|
|
230
|
+
})
|
|
231
|
+
|
|
232
|
+
it('should show validation error message from getValidationResult', async () => {
|
|
233
|
+
await usingAsync(new Injector(), async (injector) => {
|
|
234
|
+
const rootElement = document.getElementById('root') as HTMLDivElement
|
|
235
|
+
|
|
236
|
+
initializeShadeRoot({
|
|
237
|
+
injector,
|
|
238
|
+
rootElement,
|
|
239
|
+
jsxElement: (
|
|
240
|
+
<MarkdownInput
|
|
241
|
+
value="short"
|
|
242
|
+
getValidationResult={({ value }) =>
|
|
243
|
+
value.length < 10 ? { isValid: false, message: 'Too short' } : { isValid: true }
|
|
244
|
+
}
|
|
245
|
+
/>
|
|
246
|
+
),
|
|
247
|
+
})
|
|
248
|
+
|
|
249
|
+
await flushUpdates()
|
|
250
|
+
|
|
251
|
+
const wrapper = document.querySelector('shade-markdown-input') as HTMLElement
|
|
252
|
+
expect(wrapper.hasAttribute('data-invalid')).toBe(true)
|
|
253
|
+
expect(wrapper.textContent).toContain('Too short')
|
|
254
|
+
})
|
|
255
|
+
})
|
|
256
|
+
|
|
257
|
+
it('should show helper text from getHelperText', async () => {
|
|
258
|
+
await usingAsync(new Injector(), async (injector) => {
|
|
259
|
+
const rootElement = document.getElementById('root') as HTMLDivElement
|
|
260
|
+
|
|
261
|
+
initializeShadeRoot({
|
|
262
|
+
injector,
|
|
263
|
+
rootElement,
|
|
264
|
+
jsxElement: <MarkdownInput value="" getHelperText={() => 'Write some markdown here'} />,
|
|
265
|
+
})
|
|
266
|
+
|
|
267
|
+
await flushUpdates()
|
|
268
|
+
|
|
269
|
+
const wrapper = document.querySelector('shade-markdown-input') as HTMLElement
|
|
270
|
+
expect(wrapper.textContent).toContain('Write some markdown here')
|
|
271
|
+
})
|
|
272
|
+
})
|
|
273
|
+
|
|
274
|
+
it('should render with validation inside a Form', async () => {
|
|
275
|
+
await usingAsync(new Injector(), async (injector) => {
|
|
276
|
+
const rootElement = document.getElementById('root') as HTMLDivElement
|
|
277
|
+
|
|
278
|
+
initializeShadeRoot({
|
|
279
|
+
injector,
|
|
280
|
+
rootElement,
|
|
281
|
+
jsxElement: (
|
|
282
|
+
<Form onSubmit={() => {}} validate={(_data): _data is { content: string } => true}>
|
|
283
|
+
<MarkdownInput
|
|
284
|
+
value="short"
|
|
285
|
+
name="content"
|
|
286
|
+
getValidationResult={({ value }) =>
|
|
287
|
+
value.length < 10 ? { isValid: false, message: 'Too short' } : { isValid: true }
|
|
288
|
+
}
|
|
289
|
+
/>
|
|
290
|
+
</Form>
|
|
291
|
+
),
|
|
292
|
+
})
|
|
293
|
+
|
|
294
|
+
await flushUpdates()
|
|
295
|
+
|
|
296
|
+
const wrapper = document.querySelector('shade-markdown-input') as HTMLElement
|
|
297
|
+
expect(wrapper.hasAttribute('data-invalid')).toBe(true)
|
|
298
|
+
expect(wrapper.textContent).toContain('Too short')
|
|
299
|
+
|
|
300
|
+
const textarea = wrapper.querySelector('textarea') as HTMLTextAreaElement
|
|
301
|
+
expect(textarea.name).toBe('content')
|
|
302
|
+
})
|
|
303
|
+
})
|
|
304
|
+
|
|
163
305
|
describe('image paste', () => {
|
|
164
306
|
const createPasteEvent = (items: Array<{ type: string; file: File | null }>) => {
|
|
165
307
|
const pasteEvent = new Event('paste', { bubbles: true, cancelable: true })
|
|
@@ -200,7 +342,7 @@ describe('MarkdownInput', () => {
|
|
|
200
342
|
jsxElement: <MarkdownInput value="Hello " onValueChange={onValueChange} />,
|
|
201
343
|
})
|
|
202
344
|
|
|
203
|
-
await
|
|
345
|
+
await flushUpdates()
|
|
204
346
|
|
|
205
347
|
const textarea = document.querySelector('shade-markdown-input textarea') as HTMLTextAreaElement
|
|
206
348
|
textarea.selectionStart = 6
|
|
@@ -210,7 +352,7 @@ describe('MarkdownInput', () => {
|
|
|
210
352
|
const pasteEvent = createPasteEvent([{ type: 'image/png', file }])
|
|
211
353
|
textarea.dispatchEvent(pasteEvent)
|
|
212
354
|
|
|
213
|
-
await
|
|
355
|
+
await flushUpdates()
|
|
214
356
|
|
|
215
357
|
expect(onValueChange).toHaveBeenCalledOnce()
|
|
216
358
|
const result = onValueChange.mock.calls[0][0] as string
|
|
@@ -233,14 +375,14 @@ describe('MarkdownInput', () => {
|
|
|
233
375
|
jsxElement: <MarkdownInput value="" onValueChange={onValueChange} maxImageSizeBytes={5} />,
|
|
234
376
|
})
|
|
235
377
|
|
|
236
|
-
await
|
|
378
|
+
await flushUpdates()
|
|
237
379
|
|
|
238
380
|
const textarea = document.querySelector('shade-markdown-input textarea') as HTMLTextAreaElement
|
|
239
381
|
const file = new File(['this-is-larger-than-5-bytes'], 'big.png', { type: 'image/png' })
|
|
240
382
|
const pasteEvent = createPasteEvent([{ type: 'image/png', file }])
|
|
241
383
|
textarea.dispatchEvent(pasteEvent)
|
|
242
384
|
|
|
243
|
-
await
|
|
385
|
+
await flushUpdates()
|
|
244
386
|
|
|
245
387
|
expect(onValueChange).not.toHaveBeenCalled()
|
|
246
388
|
})
|
|
@@ -257,14 +399,14 @@ describe('MarkdownInput', () => {
|
|
|
257
399
|
jsxElement: <MarkdownInput value="" onValueChange={onValueChange} />,
|
|
258
400
|
})
|
|
259
401
|
|
|
260
|
-
await
|
|
402
|
+
await flushUpdates()
|
|
261
403
|
|
|
262
404
|
const textarea = document.querySelector('shade-markdown-input textarea') as HTMLTextAreaElement
|
|
263
405
|
const file = new File(['text content'], 'note.txt', { type: 'text/plain' })
|
|
264
406
|
const pasteEvent = createPasteEvent([{ type: 'text/plain', file }])
|
|
265
407
|
const wasDefaultPrevented = !textarea.dispatchEvent(pasteEvent)
|
|
266
408
|
|
|
267
|
-
await
|
|
409
|
+
await flushUpdates()
|
|
268
410
|
|
|
269
411
|
expect(wasDefaultPrevented).toBe(false)
|
|
270
412
|
expect(onValueChange).not.toHaveBeenCalled()
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { Shade, createComponent } from '@furystack/shades'
|
|
2
2
|
import { cssVariableTheme } from '../../services/css-variable-theme.js'
|
|
3
|
+
import type { InputValidationResult } from '../inputs/input.js'
|
|
4
|
+
import { FormService } from '../form.js'
|
|
3
5
|
|
|
4
6
|
const DEFAULT_MAX_IMAGE_SIZE = 256 * 1024
|
|
5
7
|
|
|
@@ -20,6 +22,14 @@ export type MarkdownInputProps = {
|
|
|
20
22
|
labelTitle?: string
|
|
21
23
|
/** Number of visible text rows */
|
|
22
24
|
rows?: number
|
|
25
|
+
/** Form field name for FormService integration */
|
|
26
|
+
name?: string
|
|
27
|
+
/** Whether the field is required */
|
|
28
|
+
required?: boolean
|
|
29
|
+
/** Custom validation callback */
|
|
30
|
+
getValidationResult?: (options: { value: string }) => InputValidationResult
|
|
31
|
+
/** Optional helper text callback */
|
|
32
|
+
getHelperText?: (options: { value: string; validationResult?: InputValidationResult }) => JSX.Element | string
|
|
23
33
|
}
|
|
24
34
|
|
|
25
35
|
/**
|
|
@@ -53,6 +63,11 @@ export const MarkdownInput = Shade<MarkdownInputProps>({
|
|
|
53
63
|
color: cssVariableTheme.palette.primary.main,
|
|
54
64
|
},
|
|
55
65
|
|
|
66
|
+
'&[data-invalid] label': {
|
|
67
|
+
borderColor: cssVariableTheme.palette.error.main,
|
|
68
|
+
color: cssVariableTheme.palette.error.main,
|
|
69
|
+
},
|
|
70
|
+
|
|
56
71
|
'& textarea': {
|
|
57
72
|
border: 'none',
|
|
58
73
|
backgroundColor: 'transparent',
|
|
@@ -71,15 +86,61 @@ export const MarkdownInput = Shade<MarkdownInputProps>({
|
|
|
71
86
|
'&:focus-within textarea': {
|
|
72
87
|
boxShadow: `0px 3px 0px ${cssVariableTheme.palette.primary.main}`,
|
|
73
88
|
},
|
|
89
|
+
|
|
90
|
+
'&[data-invalid]:focus-within textarea': {
|
|
91
|
+
boxShadow: `0px 3px 0px ${cssVariableTheme.palette.error.main}`,
|
|
92
|
+
},
|
|
93
|
+
|
|
94
|
+
'& .helperText': {
|
|
95
|
+
fontSize: cssVariableTheme.typography.fontSize.xs,
|
|
96
|
+
marginTop: '6px',
|
|
97
|
+
opacity: '0.85',
|
|
98
|
+
lineHeight: '1.4',
|
|
99
|
+
},
|
|
74
100
|
},
|
|
75
|
-
render: ({ props, useHostProps, useRef }) => {
|
|
101
|
+
render: ({ props, injector, useDisposable, useHostProps, useRef }) => {
|
|
76
102
|
const maxSize = props.maxImageSizeBytes ?? DEFAULT_MAX_IMAGE_SIZE
|
|
77
103
|
const textareaRef = useRef<HTMLTextAreaElement>('textarea')
|
|
78
104
|
|
|
105
|
+
useDisposable('form-registration', () => {
|
|
106
|
+
const formService = injector.cachedSingletons.has(FormService) ? injector.getInstance(FormService) : null
|
|
107
|
+
if (formService) {
|
|
108
|
+
queueMicrotask(() => {
|
|
109
|
+
if (textareaRef.current) formService.inputs.add(textareaRef.current as unknown as HTMLInputElement)
|
|
110
|
+
})
|
|
111
|
+
}
|
|
112
|
+
return {
|
|
113
|
+
[Symbol.dispose]: () => {
|
|
114
|
+
if (textareaRef.current && formService)
|
|
115
|
+
formService.inputs.delete(textareaRef.current as unknown as HTMLInputElement)
|
|
116
|
+
},
|
|
117
|
+
}
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
const validationResult = props.getValidationResult?.({ value: props.value })
|
|
121
|
+
const isRequired = props.required && !props.value
|
|
122
|
+
const isInvalid = validationResult?.isValid === false || isRequired
|
|
123
|
+
|
|
124
|
+
if (injector.cachedSingletons.has(FormService) && props.name) {
|
|
125
|
+
const formService = injector.getInstance(FormService)
|
|
126
|
+
const fieldResult: InputValidationResult = isRequired
|
|
127
|
+
? { isValid: false, message: 'Value is required' }
|
|
128
|
+
: validationResult || { isValid: true }
|
|
129
|
+
const validity = textareaRef.current?.validity ?? ({} as ValidityState)
|
|
130
|
+
formService.setFieldState(props.name as keyof unknown, fieldResult, validity)
|
|
131
|
+
}
|
|
132
|
+
|
|
79
133
|
useHostProps({
|
|
80
134
|
'data-disabled': props.disabled ? '' : undefined,
|
|
135
|
+
'data-invalid': isInvalid ? '' : undefined,
|
|
81
136
|
})
|
|
82
137
|
|
|
138
|
+
const helperNode =
|
|
139
|
+
(validationResult?.isValid === false && validationResult?.message) ||
|
|
140
|
+
(isRequired && 'Value is required') ||
|
|
141
|
+
props.getHelperText?.({ value: props.value, validationResult }) ||
|
|
142
|
+
''
|
|
143
|
+
|
|
83
144
|
const handleInput = (ev: Event) => {
|
|
84
145
|
const target = ev.target as HTMLTextAreaElement
|
|
85
146
|
props.onValueChange?.(target.value)
|
|
@@ -129,6 +190,8 @@ export const MarkdownInput = Shade<MarkdownInputProps>({
|
|
|
129
190
|
{props.labelTitle ? <span>{props.labelTitle}</span> : null}
|
|
130
191
|
<textarea
|
|
131
192
|
ref={textareaRef}
|
|
193
|
+
name={props.name}
|
|
194
|
+
required={props.required}
|
|
132
195
|
value={props.value}
|
|
133
196
|
oninput={handleInput}
|
|
134
197
|
onpaste={handlePaste}
|
|
@@ -137,6 +200,7 @@ export const MarkdownInput = Shade<MarkdownInputProps>({
|
|
|
137
200
|
placeholder={props.placeholder}
|
|
138
201
|
rows={props.rows ?? 10}
|
|
139
202
|
/>
|
|
203
|
+
{helperNode ? <span className="helperText">{helperNode}</span> : null}
|
|
140
204
|
</label>
|
|
141
205
|
)
|
|
142
206
|
},
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Injector } from '@furystack/inject'
|
|
2
|
-
import { createComponent, initializeShadeRoot } from '@furystack/shades'
|
|
3
|
-
import {
|
|
2
|
+
import { createComponent, flushUpdates, initializeShadeRoot } from '@furystack/shades'
|
|
3
|
+
import { usingAsync } from '@furystack/utils'
|
|
4
4
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
5
5
|
import type { MenuEntry } from './menu-types.js'
|
|
6
6
|
import { Menu } from './menu.js'
|
|
@@ -29,7 +29,7 @@ describe('Menu', () => {
|
|
|
29
29
|
rootElement: root,
|
|
30
30
|
jsxElement: <Menu {...props} />,
|
|
31
31
|
})
|
|
32
|
-
await
|
|
32
|
+
await flushUpdates()
|
|
33
33
|
return {
|
|
34
34
|
injector,
|
|
35
35
|
menu: root.querySelector('shade-menu') as HTMLElement,
|
|
@@ -219,7 +219,7 @@ describe('Menu', () => {
|
|
|
219
219
|
const groupLabel = menu.querySelector('.menu-group-label-inline') as HTMLElement
|
|
220
220
|
expect(groupLabel).toBeTruthy()
|
|
221
221
|
groupLabel.click()
|
|
222
|
-
await
|
|
222
|
+
await flushUpdates()
|
|
223
223
|
|
|
224
224
|
const groupItems = menu.querySelectorAll('[role="menuitem"]')
|
|
225
225
|
expect(groupItems.length).toBe(1)
|
|
@@ -239,7 +239,7 @@ describe('Menu', () => {
|
|
|
239
239
|
await usingAsync(await renderMenu({ items: createTestItems() }), async ({ menu }) => {
|
|
240
240
|
menu.focus()
|
|
241
241
|
menu.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown', bubbles: true }))
|
|
242
|
-
await
|
|
242
|
+
await flushUpdates()
|
|
243
243
|
|
|
244
244
|
const focusedItem = menu.querySelector('.menu-item.focused')
|
|
245
245
|
expect(focusedItem).toBeTruthy()
|
|
@@ -251,7 +251,7 @@ describe('Menu', () => {
|
|
|
251
251
|
await usingAsync(await renderMenu({ items: createTestItems(), mode: 'horizontal' }), async ({ menu }) => {
|
|
252
252
|
menu.focus()
|
|
253
253
|
menu.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowRight', bubbles: true }))
|
|
254
|
-
await
|
|
254
|
+
await flushUpdates()
|
|
255
255
|
|
|
256
256
|
const focusedItem = menu.querySelector('.menu-item.focused')
|
|
257
257
|
expect(focusedItem).toBeTruthy()
|
|
@@ -265,10 +265,10 @@ describe('Menu', () => {
|
|
|
265
265
|
menu.focus()
|
|
266
266
|
// Navigate to first item
|
|
267
267
|
menu.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown', bubbles: true }))
|
|
268
|
-
await
|
|
268
|
+
await flushUpdates()
|
|
269
269
|
// Press Enter
|
|
270
270
|
menu.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true }))
|
|
271
|
-
await
|
|
271
|
+
await flushUpdates()
|
|
272
272
|
expect(handleSelect).toHaveBeenCalledWith('home')
|
|
273
273
|
})
|
|
274
274
|
})
|
|
@@ -277,7 +277,7 @@ describe('Menu', () => {
|
|
|
277
277
|
await usingAsync(await renderMenu({ items: createTestItems() }), async ({ menu }) => {
|
|
278
278
|
menu.focus()
|
|
279
279
|
menu.dispatchEvent(new KeyboardEvent('keydown', { key: 'End', bubbles: true }))
|
|
280
|
-
await
|
|
280
|
+
await flushUpdates()
|
|
281
281
|
|
|
282
282
|
const focusedItem = menu.querySelector('.menu-item.focused')
|
|
283
283
|
expect(focusedItem?.getAttribute('data-key')).toBe('settings')
|
|
@@ -289,10 +289,10 @@ describe('Menu', () => {
|
|
|
289
289
|
menu.focus()
|
|
290
290
|
// Go to end first
|
|
291
291
|
menu.dispatchEvent(new KeyboardEvent('keydown', { key: 'End', bubbles: true }))
|
|
292
|
-
await
|
|
292
|
+
await flushUpdates()
|
|
293
293
|
// Then Home
|
|
294
294
|
menu.dispatchEvent(new KeyboardEvent('keydown', { key: 'Home', bubbles: true }))
|
|
295
|
-
await
|
|
295
|
+
await flushUpdates()
|
|
296
296
|
|
|
297
297
|
const focusedItem = menu.querySelector('.menu-item.focused')
|
|
298
298
|
expect(focusedItem?.getAttribute('data-key')).toBe('home')
|
|
@@ -308,10 +308,10 @@ describe('Menu', () => {
|
|
|
308
308
|
menu.focus()
|
|
309
309
|
// Navigate to end
|
|
310
310
|
menu.dispatchEvent(new KeyboardEvent('keydown', { key: 'End', bubbles: true }))
|
|
311
|
-
await
|
|
311
|
+
await flushUpdates()
|
|
312
312
|
// One more down should wrap to first
|
|
313
313
|
menu.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown', bubbles: true }))
|
|
314
|
-
await
|
|
314
|
+
await flushUpdates()
|
|
315
315
|
|
|
316
316
|
const focusedItem = menu.querySelector('.menu-item.focused')
|
|
317
317
|
expect(focusedItem?.getAttribute('data-key')).toBe('a')
|
|
@@ -327,10 +327,10 @@ describe('Menu', () => {
|
|
|
327
327
|
menu.focus()
|
|
328
328
|
// Navigate to Home first
|
|
329
329
|
menu.dispatchEvent(new KeyboardEvent('keydown', { key: 'Home', bubbles: true }))
|
|
330
|
-
await
|
|
330
|
+
await flushUpdates()
|
|
331
331
|
// One more up should wrap to last
|
|
332
332
|
menu.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowUp', bubbles: true }))
|
|
333
|
-
await
|
|
333
|
+
await flushUpdates()
|
|
334
334
|
|
|
335
335
|
const focusedItem = menu.querySelector('.menu-item.focused')
|
|
336
336
|
expect(focusedItem?.getAttribute('data-key')).toBe('b')
|
|
@@ -342,9 +342,9 @@ describe('Menu', () => {
|
|
|
342
342
|
await usingAsync(await renderMenu({ items: createTestItems(), onSelect: handleSelect }), async ({ menu }) => {
|
|
343
343
|
menu.focus()
|
|
344
344
|
menu.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown', bubbles: true }))
|
|
345
|
-
await
|
|
345
|
+
await flushUpdates()
|
|
346
346
|
menu.dispatchEvent(new KeyboardEvent('keydown', { key: ' ', bubbles: true }))
|
|
347
|
-
await
|
|
347
|
+
await flushUpdates()
|
|
348
348
|
expect(handleSelect).toHaveBeenCalledWith('home')
|
|
349
349
|
})
|
|
350
350
|
})
|
|
@@ -354,11 +354,11 @@ describe('Menu', () => {
|
|
|
354
354
|
menu.focus()
|
|
355
355
|
// First go to end
|
|
356
356
|
menu.dispatchEvent(new KeyboardEvent('keydown', { key: 'End', bubbles: true }))
|
|
357
|
-
await
|
|
357
|
+
await flushUpdates()
|
|
358
358
|
|
|
359
359
|
// Then ArrowUp
|
|
360
360
|
menu.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowUp', bubbles: true }))
|
|
361
|
-
await
|
|
361
|
+
await flushUpdates()
|
|
362
362
|
|
|
363
363
|
const focusedItem = menu.querySelector('.menu-item.focused')
|
|
364
364
|
expect(focusedItem?.getAttribute('data-key')).toBe('about')
|
|
@@ -370,11 +370,11 @@ describe('Menu', () => {
|
|
|
370
370
|
menu.focus()
|
|
371
371
|
// First go to end
|
|
372
372
|
menu.dispatchEvent(new KeyboardEvent('keydown', { key: 'End', bubbles: true }))
|
|
373
|
-
await
|
|
373
|
+
await flushUpdates()
|
|
374
374
|
|
|
375
375
|
// Then ArrowLeft
|
|
376
376
|
menu.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowLeft', bubbles: true }))
|
|
377
|
-
await
|
|
377
|
+
await flushUpdates()
|
|
378
378
|
|
|
379
379
|
const focusedItem = menu.querySelector('.menu-item.focused')
|
|
380
380
|
expect(focusedItem?.getAttribute('data-key')).toBe('about')
|
|
@@ -386,7 +386,7 @@ describe('Menu', () => {
|
|
|
386
386
|
await usingAsync(await renderMenu({ items: createTestItems(), onSelect: handleSelect }), async ({ menu }) => {
|
|
387
387
|
menu.focus()
|
|
388
388
|
menu.dispatchEvent(new KeyboardEvent('keydown', { key: 'a', bubbles: true }))
|
|
389
|
-
await
|
|
389
|
+
await flushUpdates()
|
|
390
390
|
expect(handleSelect).not.toHaveBeenCalled()
|
|
391
391
|
})
|
|
392
392
|
})
|
|
@@ -397,7 +397,7 @@ describe('Menu', () => {
|
|
|
397
397
|
menu.focus()
|
|
398
398
|
// Press Enter without navigating to any item first
|
|
399
399
|
menu.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true }))
|
|
400
|
-
await
|
|
400
|
+
await flushUpdates()
|
|
401
401
|
expect(handleSelect).not.toHaveBeenCalled()
|
|
402
402
|
})
|
|
403
403
|
})
|
|
@@ -407,7 +407,7 @@ describe('Menu', () => {
|
|
|
407
407
|
await usingAsync(await renderMenu({ items }), async ({ menu }) => {
|
|
408
408
|
menu.focus()
|
|
409
409
|
menu.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown', bubbles: true }))
|
|
410
|
-
await
|
|
410
|
+
await flushUpdates()
|
|
411
411
|
const focusedItem = menu.querySelector('.menu-item.focused')
|
|
412
412
|
expect(focusedItem).toBeNull()
|
|
413
413
|
})
|
|
@@ -419,7 +419,7 @@ describe('Menu', () => {
|
|
|
419
419
|
await usingAsync(await renderMenu({ items: createTestItems() }), async ({ menu }) => {
|
|
420
420
|
const item = menu.querySelector('[data-key="about"]') as HTMLElement
|
|
421
421
|
item.dispatchEvent(new MouseEvent('mouseenter', { bubbles: true }))
|
|
422
|
-
await
|
|
422
|
+
await flushUpdates()
|
|
423
423
|
|
|
424
424
|
expect(item.classList.contains('focused')).toBe(true)
|
|
425
425
|
})
|
|
@@ -430,7 +430,7 @@ describe('Menu', () => {
|
|
|
430
430
|
await usingAsync(await renderMenu({ items }), async ({ menu }) => {
|
|
431
431
|
const item = menu.querySelector('[data-key="disabled-item"]') as HTMLElement
|
|
432
432
|
item.dispatchEvent(new MouseEvent('mouseenter', { bubbles: true }))
|
|
433
|
-
await
|
|
433
|
+
await flushUpdates()
|
|
434
434
|
|
|
435
435
|
expect(item.classList.contains('focused')).toBe(false)
|
|
436
436
|
})
|
|
@@ -452,13 +452,13 @@ describe('Menu', () => {
|
|
|
452
452
|
|
|
453
453
|
// Expand
|
|
454
454
|
groupLabel.click()
|
|
455
|
-
await
|
|
455
|
+
await flushUpdates()
|
|
456
456
|
const groupChildren = menu.querySelector('.menu-group-children') as HTMLElement
|
|
457
457
|
expect(groupChildren.style.display).toBe('')
|
|
458
458
|
|
|
459
459
|
// Collapse
|
|
460
460
|
groupLabel.click()
|
|
461
|
-
await
|
|
461
|
+
await flushUpdates()
|
|
462
462
|
expect(groupChildren.style.display).toBe('none')
|
|
463
463
|
})
|
|
464
464
|
})
|