@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,146 @@
|
|
|
1
|
+
import { Injector } from '@furystack/inject'
|
|
2
|
+
import { createComponent, initializeShadeRoot } from '@furystack/shades'
|
|
3
|
+
import { sleepAsync, usingAsync } from '@furystack/utils'
|
|
4
|
+
import { afterEach, beforeEach, describe, expect, it } from 'vitest'
|
|
5
|
+
import { Avatar } from './avatar.js'
|
|
6
|
+
|
|
7
|
+
describe('Avatar component', () => {
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
document.body.innerHTML = '<div id="root"></div>'
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
afterEach(() => {
|
|
13
|
+
document.body.innerHTML = ''
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
it('should render an image with the provided avatarUrl', async () => {
|
|
17
|
+
await usingAsync(new Injector(), async (injector) => {
|
|
18
|
+
const rootElement = document.getElementById('root') as HTMLDivElement
|
|
19
|
+
const testUrl = 'https://example.com/avatar.png'
|
|
20
|
+
|
|
21
|
+
initializeShadeRoot({
|
|
22
|
+
injector,
|
|
23
|
+
rootElement,
|
|
24
|
+
jsxElement: <Avatar avatarUrl={testUrl} />,
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
await sleepAsync(50)
|
|
28
|
+
|
|
29
|
+
const avatar = document.querySelector('shade-avatar')
|
|
30
|
+
expect(avatar).not.toBeNull()
|
|
31
|
+
|
|
32
|
+
const img = avatar?.querySelector('img')
|
|
33
|
+
expect(img).not.toBeNull()
|
|
34
|
+
expect(img?.src).toBe(testUrl)
|
|
35
|
+
expect(img?.alt).toBe('avatar image')
|
|
36
|
+
})
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
it('should display default fallback emoji when image fails to load', async () => {
|
|
40
|
+
await usingAsync(new Injector(), async (injector) => {
|
|
41
|
+
const rootElement = document.getElementById('root') as HTMLDivElement
|
|
42
|
+
|
|
43
|
+
initializeShadeRoot({
|
|
44
|
+
injector,
|
|
45
|
+
rootElement,
|
|
46
|
+
jsxElement: <Avatar avatarUrl="invalid-url" />,
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
await sleepAsync(50)
|
|
50
|
+
|
|
51
|
+
const avatar = document.querySelector('shade-avatar')
|
|
52
|
+
expect(avatar).not.toBeNull()
|
|
53
|
+
|
|
54
|
+
const img = avatar?.querySelector('img')
|
|
55
|
+
expect(img).not.toBeNull()
|
|
56
|
+
|
|
57
|
+
// Trigger the error event
|
|
58
|
+
const errorEvent = new Event('error')
|
|
59
|
+
img?.dispatchEvent(errorEvent)
|
|
60
|
+
|
|
61
|
+
await sleepAsync(50)
|
|
62
|
+
|
|
63
|
+
// After error, img should be replaced with fallback div
|
|
64
|
+
const fallbackImg = avatar?.querySelector('img')
|
|
65
|
+
expect(fallbackImg).toBeNull()
|
|
66
|
+
|
|
67
|
+
// The fallback div should contain the default emoji
|
|
68
|
+
const fallbackContent = avatar?.textContent
|
|
69
|
+
expect(fallbackContent).toContain('🛑')
|
|
70
|
+
})
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
it('should display custom fallback when image fails to load and fallback prop is provided', async () => {
|
|
74
|
+
await usingAsync(new Injector(), async (injector) => {
|
|
75
|
+
const rootElement = document.getElementById('root') as HTMLDivElement
|
|
76
|
+
const customFallback = <span data-testid="custom-fallback">AB</span>
|
|
77
|
+
|
|
78
|
+
initializeShadeRoot({
|
|
79
|
+
injector,
|
|
80
|
+
rootElement,
|
|
81
|
+
jsxElement: <Avatar avatarUrl="invalid-url" fallback={customFallback} />,
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
await sleepAsync(50)
|
|
85
|
+
|
|
86
|
+
const avatar = document.querySelector('shade-avatar')
|
|
87
|
+
expect(avatar).not.toBeNull()
|
|
88
|
+
|
|
89
|
+
const img = avatar?.querySelector('img')
|
|
90
|
+
expect(img).not.toBeNull()
|
|
91
|
+
|
|
92
|
+
// Trigger the error event
|
|
93
|
+
const errorEvent = new Event('error')
|
|
94
|
+
img?.dispatchEvent(errorEvent)
|
|
95
|
+
|
|
96
|
+
await sleepAsync(50)
|
|
97
|
+
|
|
98
|
+
// After error, img should be replaced with fallback div
|
|
99
|
+
const fallbackImg = avatar?.querySelector('img')
|
|
100
|
+
expect(fallbackImg).toBeNull()
|
|
101
|
+
|
|
102
|
+
// The custom fallback should be rendered
|
|
103
|
+
const customElement = avatar?.querySelector('[data-testid="custom-fallback"]')
|
|
104
|
+
expect(customElement).not.toBeNull()
|
|
105
|
+
expect(customElement?.textContent).toBe('AB')
|
|
106
|
+
})
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
it('should apply custom style from props', async () => {
|
|
110
|
+
await usingAsync(new Injector(), async (injector) => {
|
|
111
|
+
const rootElement = document.getElementById('root') as HTMLDivElement
|
|
112
|
+
|
|
113
|
+
initializeShadeRoot({
|
|
114
|
+
injector,
|
|
115
|
+
rootElement,
|
|
116
|
+
jsxElement: <Avatar avatarUrl="https://example.com/avatar.png" style={{ width: '64px', height: '64px' }} />,
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
await sleepAsync(50)
|
|
120
|
+
|
|
121
|
+
const avatar = document.querySelector('shade-avatar') as HTMLElement
|
|
122
|
+
expect(avatar).not.toBeNull()
|
|
123
|
+
expect(avatar.style.width).toBe('64px')
|
|
124
|
+
expect(avatar.style.height).toBe('64px')
|
|
125
|
+
})
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
it('should pass through additional props to the container', async () => {
|
|
129
|
+
await usingAsync(new Injector(), async (injector) => {
|
|
130
|
+
const rootElement = document.getElementById('root') as HTMLDivElement
|
|
131
|
+
|
|
132
|
+
initializeShadeRoot({
|
|
133
|
+
injector,
|
|
134
|
+
rootElement,
|
|
135
|
+
jsxElement: <Avatar avatarUrl="https://example.com/avatar.png" className="custom-avatar" title="User Avatar" />,
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
await sleepAsync(50)
|
|
139
|
+
|
|
140
|
+
const avatar = document.querySelector('shade-avatar') as HTMLElement
|
|
141
|
+
expect(avatar).not.toBeNull()
|
|
142
|
+
expect(avatar.className).toBe('custom-avatar')
|
|
143
|
+
expect(avatar.title).toBe('User Avatar')
|
|
144
|
+
})
|
|
145
|
+
})
|
|
146
|
+
})
|
|
@@ -5,34 +5,31 @@ export type AvatarProps = { avatarUrl: string; fallback?: JSX.Element } & Partia
|
|
|
5
5
|
|
|
6
6
|
export const Avatar = Shade<AvatarProps>({
|
|
7
7
|
shadowDomName: 'shade-avatar',
|
|
8
|
+
css: {
|
|
9
|
+
width: '128px',
|
|
10
|
+
height: '128px',
|
|
11
|
+
overflow: 'hidden',
|
|
12
|
+
borderRadius: '50%',
|
|
13
|
+
boxShadow:
|
|
14
|
+
'0 0 0 3px rgba(255, 255, 255, 0.1), 0 4px 6px -1px rgba(0, 0, 0, 0.15), 0 2px 4px -1px rgba(0, 0, 0, 0.1)',
|
|
15
|
+
backgroundColor: 'linear-gradient(135deg, rgba(99, 102, 241, 0.1) 0%, rgba(168, 85, 247, 0.1) 100%)',
|
|
16
|
+
display: 'flex',
|
|
17
|
+
position: 'relative',
|
|
18
|
+
transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)',
|
|
19
|
+
'&:hover': {
|
|
20
|
+
transform: 'translateY(-2px) scale(1.02)',
|
|
21
|
+
boxShadow:
|
|
22
|
+
'0 0 0 3px rgba(255, 255, 255, 0.15), 0 10px 15px -3px rgba(0, 0, 0, 0.2), 0 4px 6px -2px rgba(0, 0, 0, 0.1)',
|
|
23
|
+
},
|
|
24
|
+
},
|
|
8
25
|
render: ({ props, element }) => {
|
|
9
26
|
const { avatarUrl, ...containerProps } = props
|
|
10
27
|
|
|
11
28
|
attachProps(element, {
|
|
12
29
|
...containerProps,
|
|
13
30
|
style: {
|
|
14
|
-
width: '128px',
|
|
15
|
-
height: '128px',
|
|
16
|
-
overflow: 'hidden',
|
|
17
|
-
borderRadius: '50%',
|
|
18
|
-
boxShadow:
|
|
19
|
-
'0 0 0 3px rgba(255, 255, 255, 0.1), 0 4px 6px -1px rgba(0, 0, 0, 0.15), 0 2px 4px -1px rgba(0, 0, 0, 0.1)',
|
|
20
|
-
backgroundColor: 'linear-gradient(135deg, rgba(99, 102, 241, 0.1) 0%, rgba(168, 85, 247, 0.1) 100%)',
|
|
21
|
-
display: 'flex',
|
|
22
|
-
position: 'relative',
|
|
23
|
-
transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)',
|
|
24
31
|
...containerProps?.style,
|
|
25
32
|
},
|
|
26
|
-
onmouseenter: () => {
|
|
27
|
-
element.style.transform = 'translateY(-2px) scale(1.02)'
|
|
28
|
-
element.style.boxShadow =
|
|
29
|
-
'0 0 0 3px rgba(255, 255, 255, 0.15), 0 10px 15px -3px rgba(0, 0, 0, 0.2), 0 4px 6px -2px rgba(0, 0, 0, 0.1)'
|
|
30
|
-
},
|
|
31
|
-
onmouseleave: () => {
|
|
32
|
-
element.style.transform = 'translateY(0) scale(1)'
|
|
33
|
-
element.style.boxShadow =
|
|
34
|
-
'0 0 0 3px rgba(255, 255, 255, 0.1), 0 4px 6px -1px rgba(0, 0, 0, 0.15), 0 2px 4px -1px rgba(0, 0, 0, 0.1)'
|
|
35
|
-
},
|
|
36
33
|
})
|
|
37
34
|
|
|
38
35
|
return (
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { Injector } from '@furystack/inject'
|
|
2
|
+
import { createComponent, initializeShadeRoot, Shade } from '@furystack/shades'
|
|
3
|
+
import { sleepAsync, usingAsync } from '@furystack/utils'
|
|
4
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
5
|
+
import { Button } from './button.js'
|
|
6
|
+
|
|
7
|
+
describe('Button', () => {
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
document.body.innerHTML = '<div id="root"></div>'
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
afterEach(() => {
|
|
13
|
+
document.body.innerHTML = ''
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
const renderButton = async (props: Parameters<typeof Button>[0] = {}, children?: JSX.Element[]) => {
|
|
17
|
+
const injector = new Injector()
|
|
18
|
+
const root = document.getElementById('root')!
|
|
19
|
+
initializeShadeRoot({
|
|
20
|
+
injector,
|
|
21
|
+
rootElement: root,
|
|
22
|
+
jsxElement: <Button {...props}>{children}</Button>,
|
|
23
|
+
})
|
|
24
|
+
await sleepAsync(50)
|
|
25
|
+
return {
|
|
26
|
+
injector,
|
|
27
|
+
button: root.querySelector('button[is="shade-button"]') as HTMLButtonElement,
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
describe('rendering', () => {
|
|
32
|
+
it('should render a button element', async () => {
|
|
33
|
+
const { button } = await renderButton()
|
|
34
|
+
expect(button).toBeTruthy()
|
|
35
|
+
expect(button.tagName.toLowerCase()).toBe('button')
|
|
36
|
+
expect(button.getAttribute('is')).toBe('shade-button')
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
it('should render children', async () => {
|
|
40
|
+
const { button } = await renderButton({}, ['Click me'] as unknown as JSX.Element[])
|
|
41
|
+
expect(button.textContent).toContain('Click me')
|
|
42
|
+
})
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
describe('variants', () => {
|
|
46
|
+
it('should have no data-variant attribute when variant is not specified (flat default)', async () => {
|
|
47
|
+
const { button } = await renderButton()
|
|
48
|
+
expect(button.getAttribute('data-variant')).toBeNull()
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
it('should set data-variant="contained" for contained variant', async () => {
|
|
52
|
+
const { button } = await renderButton({ variant: 'contained' })
|
|
53
|
+
expect(button.getAttribute('data-variant')).toBe('contained')
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
it('should set data-variant="outlined" for outlined variant', async () => {
|
|
57
|
+
const { button } = await renderButton({ variant: 'outlined' })
|
|
58
|
+
expect(button.getAttribute('data-variant')).toBe('outlined')
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
it('should remove data-variant attribute when variant changes to undefined', async () => {
|
|
62
|
+
await usingAsync(new Injector(), async (injector) => {
|
|
63
|
+
const root = document.getElementById('root')!
|
|
64
|
+
|
|
65
|
+
const TestComponent = Shade<{ variant?: 'contained' | 'outlined' }>({
|
|
66
|
+
shadowDomName: 'button-test-variant-wrapper',
|
|
67
|
+
render: ({ props }) => <Button variant={props.variant}>Test</Button>,
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
initializeShadeRoot({
|
|
71
|
+
injector,
|
|
72
|
+
rootElement: root,
|
|
73
|
+
jsxElement: <TestComponent variant="contained" />,
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
await sleepAsync(50)
|
|
77
|
+
const button = root.querySelector('button[is="shade-button"]') as HTMLButtonElement
|
|
78
|
+
expect(button.getAttribute('data-variant')).toBe('contained')
|
|
79
|
+
})
|
|
80
|
+
})
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
describe('colors', () => {
|
|
84
|
+
const colors = ['primary', 'secondary', 'error', 'warning', 'success', 'info'] as const
|
|
85
|
+
|
|
86
|
+
colors.forEach((color) => {
|
|
87
|
+
it(`should set CSS custom properties for ${color} color`, async () => {
|
|
88
|
+
const { button } = await renderButton({ color })
|
|
89
|
+
|
|
90
|
+
expect(button.style.getPropertyValue('--btn-color-main')).toBe(`var(--shades-theme-palette-${color}-main)`)
|
|
91
|
+
expect(button.style.getPropertyValue('--btn-color-main-contrast')).toBe(
|
|
92
|
+
`var(--shades-theme-palette-${color}-main-contrast)`,
|
|
93
|
+
)
|
|
94
|
+
expect(button.style.getPropertyValue('--btn-color-light')).toBe(`var(--shades-theme-palette-${color}-light)`)
|
|
95
|
+
expect(button.style.getPropertyValue('--btn-color-dark')).toBe(`var(--shades-theme-palette-${color}-dark)`)
|
|
96
|
+
expect(button.style.getPropertyValue('--btn-color-dark-contrast')).toBe(
|
|
97
|
+
`var(--shades-theme-palette-${color}-dark-contrast)`,
|
|
98
|
+
)
|
|
99
|
+
})
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
it('should set default color CSS custom properties when no color is specified', async () => {
|
|
103
|
+
const { button } = await renderButton()
|
|
104
|
+
|
|
105
|
+
expect(button.style.getPropertyValue('--btn-color-main')).toBe('var(--shades-theme-text-secondary)')
|
|
106
|
+
expect(button.style.getPropertyValue('--btn-color-main-contrast')).toBe('var(--shades-theme-background-default)')
|
|
107
|
+
expect(button.style.getPropertyValue('--btn-color-light')).toBe('var(--shades-theme-text-primary)')
|
|
108
|
+
expect(button.style.getPropertyValue('--btn-color-dark')).toBe('var(--shades-theme-button-disabled-background)')
|
|
109
|
+
expect(button.style.getPropertyValue('--btn-color-dark-contrast')).toBe('var(--shades-theme-text-primary)')
|
|
110
|
+
})
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
describe('variant and color combinations', () => {
|
|
114
|
+
it('should apply both contained variant and primary color', async () => {
|
|
115
|
+
const { button } = await renderButton({ variant: 'contained', color: 'primary' })
|
|
116
|
+
|
|
117
|
+
expect(button.getAttribute('data-variant')).toBe('contained')
|
|
118
|
+
expect(button.style.getPropertyValue('--btn-color-main')).toBe('var(--shades-theme-palette-primary-main)')
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
it('should apply both outlined variant and error color', async () => {
|
|
122
|
+
const { button } = await renderButton({ variant: 'outlined', color: 'error' })
|
|
123
|
+
|
|
124
|
+
expect(button.getAttribute('data-variant')).toBe('outlined')
|
|
125
|
+
expect(button.style.getPropertyValue('--btn-color-main')).toBe('var(--shades-theme-palette-error-main)')
|
|
126
|
+
})
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
describe('disabled state', () => {
|
|
130
|
+
it('should be enabled by default', async () => {
|
|
131
|
+
const { button } = await renderButton()
|
|
132
|
+
expect(button.disabled).toBe(false)
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
it('should be disabled when disabled prop is set', async () => {
|
|
136
|
+
const { button } = await renderButton({ disabled: true })
|
|
137
|
+
expect(button.disabled).toBe(true)
|
|
138
|
+
})
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
describe('custom styles', () => {
|
|
142
|
+
it('should apply custom styles from style prop', async () => {
|
|
143
|
+
const { button } = await renderButton({
|
|
144
|
+
style: { margin: '20px', padding: '15px' },
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
expect(button.style.margin).toBe('20px')
|
|
148
|
+
expect(button.style.padding).toBe('15px')
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
it('should merge custom styles with component defaults', async () => {
|
|
152
|
+
const { button } = await renderButton({
|
|
153
|
+
color: 'primary',
|
|
154
|
+
style: { fontSize: '18px' },
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
expect(button.style.fontSize).toBe('18px')
|
|
158
|
+
expect(button.style.getPropertyValue('--btn-color-main')).toBe('var(--shades-theme-palette-primary-main)')
|
|
159
|
+
})
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
describe('event handling', () => {
|
|
163
|
+
it('should trigger onclick handler when clicked', async () => {
|
|
164
|
+
const handleClick = vi.fn()
|
|
165
|
+
const { button } = await renderButton({ onclick: handleClick })
|
|
166
|
+
|
|
167
|
+
button.click()
|
|
168
|
+
|
|
169
|
+
expect(handleClick).toHaveBeenCalledTimes(1)
|
|
170
|
+
})
|
|
171
|
+
|
|
172
|
+
it('should not trigger onclick when disabled', async () => {
|
|
173
|
+
const handleClick = vi.fn()
|
|
174
|
+
const { button } = await renderButton({ onclick: handleClick, disabled: true })
|
|
175
|
+
|
|
176
|
+
button.click()
|
|
177
|
+
|
|
178
|
+
expect(handleClick).not.toHaveBeenCalled()
|
|
179
|
+
})
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
describe('HTML button attributes', () => {
|
|
183
|
+
it('should support type attribute', async () => {
|
|
184
|
+
const { button } = await renderButton({ type: 'submit' })
|
|
185
|
+
expect(button.type).toBe('submit')
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
it('should support name attribute', async () => {
|
|
189
|
+
const { button } = await renderButton({ name: 'my-button' })
|
|
190
|
+
expect(button.name).toBe('my-button')
|
|
191
|
+
})
|
|
192
|
+
})
|
|
193
|
+
})
|