@furystack/shades-common-components 13.4.0 → 13.4.1
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 +15 -0
- package/esm/components/alert.d.ts.map +1 -1
- package/esm/components/alert.js +7 -6
- package/esm/components/alert.js.map +1 -1
- package/esm/components/cache-view.spec.js +171 -170
- package/esm/components/cache-view.spec.js.map +1 -1
- package/esm/components/command-palette/command-palette-suggestion-list.js +1 -1
- package/esm/components/command-palette/command-palette-suggestion-list.js.map +1 -1
- package/esm/components/inputs/input.d.ts.map +1 -1
- package/esm/components/inputs/input.js +2 -0
- package/esm/components/inputs/input.js.map +1 -1
- package/esm/components/inputs/select.d.ts.map +1 -1
- package/esm/components/inputs/select.js +3 -1
- package/esm/components/inputs/select.js.map +1 -1
- package/esm/components/result.d.ts +4 -2
- package/esm/components/result.d.ts.map +1 -1
- package/esm/components/result.js +11 -10
- package/esm/components/result.js.map +1 -1
- package/esm/components/suggest/index.d.ts.map +1 -1
- package/esm/components/suggest/index.js +7 -3
- package/esm/components/suggest/index.js.map +1 -1
- package/esm/components/tree/tree.d.ts.map +1 -1
- package/esm/components/tree/tree.js +1 -0
- package/esm/components/tree/tree.js.map +1 -1
- package/package.json +6 -6
- package/src/components/alert.tsx +9 -6
- package/src/components/cache-view.spec.tsx +235 -219
- package/src/components/command-palette/command-palette-suggestion-list.tsx +1 -1
- package/src/components/inputs/input.tsx +2 -0
- package/src/components/inputs/select.tsx +3 -1
- package/src/components/result.tsx +17 -10
- package/src/components/suggest/index.tsx +18 -15
- package/src/components/tree/tree.tsx +1 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Cache } from '@furystack/cache'
|
|
2
2
|
import type { CacheResult, CacheWithValue } from '@furystack/cache'
|
|
3
3
|
import { Shade, createComponent, flushUpdates } from '@furystack/shades'
|
|
4
|
+
import { using, usingAsync } from '@furystack/utils'
|
|
4
5
|
|
|
5
6
|
import { describe, expect, it, vi } from 'vitest'
|
|
6
7
|
import { CacheView } from './cache-view.js'
|
|
@@ -45,232 +46,249 @@ describe('CacheView', () => {
|
|
|
45
46
|
})
|
|
46
47
|
|
|
47
48
|
it('should create a cache-view element', () => {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
49
|
+
using(new Cache<string, [string]>({ load: async (key) => key }), (cache) => {
|
|
50
|
+
const el = (<CacheView cache={cache} args={['test']} content={TestContent} />) as unknown as HTMLElement
|
|
51
|
+
expect(el).toBeDefined()
|
|
52
|
+
expect(el.tagName?.toLowerCase()).toBe('shade-cache-view')
|
|
53
|
+
})
|
|
53
54
|
})
|
|
54
55
|
|
|
55
56
|
describe('loading state', () => {
|
|
56
57
|
it('should render null by default when loading', async () => {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
58
|
+
await usingAsync(
|
|
59
|
+
new Cache<string, [string]>({
|
|
60
|
+
load: () => new Promise(() => {}),
|
|
61
|
+
}),
|
|
62
|
+
async (cache) => {
|
|
63
|
+
const { cacheView } = await renderCacheView(cache, ['test'])
|
|
64
|
+
expect(cacheView.querySelector('test-cache-content')).toBeNull()
|
|
65
|
+
expect(cacheView.querySelector('shade-result')).toBeNull()
|
|
66
|
+
},
|
|
67
|
+
)
|
|
64
68
|
})
|
|
65
69
|
|
|
66
70
|
it('should render custom loader when provided', async () => {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
71
|
+
await usingAsync(
|
|
72
|
+
new Cache<string, [string]>({
|
|
73
|
+
load: () => new Promise(() => {}),
|
|
74
|
+
}),
|
|
75
|
+
async (cache) => {
|
|
76
|
+
const { cacheView } = await renderCacheView(cache, ['test'], {
|
|
77
|
+
loader: (<span className="custom-loader">Loading...</span>) as unknown as JSX.Element,
|
|
78
|
+
})
|
|
79
|
+
const loader = cacheView.querySelector('.custom-loader')
|
|
80
|
+
expect(loader).not.toBeNull()
|
|
81
|
+
expect(loader?.textContent).toBe('Loading...')
|
|
82
|
+
},
|
|
83
|
+
)
|
|
77
84
|
})
|
|
78
85
|
})
|
|
79
86
|
|
|
80
87
|
describe('loaded state', () => {
|
|
81
88
|
it('should render content when cache has loaded value', async () => {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
89
|
+
await usingAsync(new Cache<string, [string]>({ load: async (key) => `Hello ${key}` }), async (cache) => {
|
|
90
|
+
await cache.get('world')
|
|
91
|
+
const { cacheView } = await renderCacheView(cache, ['world'])
|
|
92
|
+
const contentEl = cacheView.querySelector('test-cache-content')
|
|
93
|
+
expect(contentEl).not.toBeNull()
|
|
94
|
+
const contentComponent = contentEl as JSX.Element
|
|
95
|
+
contentComponent.updateComponent()
|
|
96
|
+
await flushUpdates()
|
|
97
|
+
const valueEl = contentComponent.querySelector('.content-value')
|
|
98
|
+
expect(valueEl?.textContent).toBe('Hello world')
|
|
99
|
+
})
|
|
93
100
|
})
|
|
94
101
|
})
|
|
95
102
|
|
|
96
103
|
describe('failed state', () => {
|
|
97
104
|
it('should render default error UI when cache has failed', async () => {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
105
|
+
await usingAsync(
|
|
106
|
+
new Cache<string, [string]>({
|
|
107
|
+
load: async () => {
|
|
108
|
+
throw new Error('Test failure')
|
|
109
|
+
},
|
|
110
|
+
}),
|
|
111
|
+
async (cache) => {
|
|
112
|
+
try {
|
|
113
|
+
await cache.get('test')
|
|
114
|
+
} catch {
|
|
115
|
+
// expected
|
|
116
|
+
}
|
|
117
|
+
const { cacheView } = await renderCacheView(cache, ['test'])
|
|
118
|
+
const resultEl = cacheView.querySelector('shade-result')
|
|
119
|
+
expect(resultEl).not.toBeNull()
|
|
120
|
+
const resultComponent = resultEl as JSX.Element
|
|
121
|
+
resultComponent.updateComponent()
|
|
122
|
+
await flushUpdates()
|
|
123
|
+
const titleEl = resultComponent.querySelector('.result-title') as JSX.Element
|
|
124
|
+
titleEl.updateComponent()
|
|
125
|
+
await flushUpdates()
|
|
126
|
+
expect(titleEl?.textContent).toBe('Something went wrong')
|
|
101
127
|
},
|
|
102
|
-
|
|
103
|
-
try {
|
|
104
|
-
await cache.get('test')
|
|
105
|
-
} catch {
|
|
106
|
-
// expected
|
|
107
|
-
}
|
|
108
|
-
const { cacheView } = await renderCacheView(cache, ['test'])
|
|
109
|
-
const resultEl = cacheView.querySelector('shade-result')
|
|
110
|
-
expect(resultEl).not.toBeNull()
|
|
111
|
-
const resultComponent = resultEl as JSX.Element
|
|
112
|
-
resultComponent.updateComponent()
|
|
113
|
-
await flushUpdates()
|
|
114
|
-
const titleEl = resultComponent.querySelector('.result-title') as JSX.Element
|
|
115
|
-
titleEl.updateComponent()
|
|
116
|
-
await flushUpdates()
|
|
117
|
-
expect(titleEl?.textContent).toBe('Something went wrong')
|
|
118
|
-
cache[Symbol.dispose]()
|
|
128
|
+
)
|
|
119
129
|
})
|
|
120
130
|
|
|
121
131
|
it('should render custom error UI when error prop is provided', async () => {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
132
|
+
await usingAsync(
|
|
133
|
+
new Cache<string, [string]>({
|
|
134
|
+
load: async () => {
|
|
135
|
+
throw new Error('Custom failure')
|
|
136
|
+
},
|
|
137
|
+
}),
|
|
138
|
+
async (cache) => {
|
|
139
|
+
try {
|
|
140
|
+
await cache.get('test')
|
|
141
|
+
} catch {
|
|
142
|
+
// expected
|
|
143
|
+
}
|
|
144
|
+
const customError = vi.fn(
|
|
145
|
+
(err: unknown, _retry: () => void) =>
|
|
146
|
+
(<span className="custom-error">{String(err)}</span>) as unknown as JSX.Element,
|
|
147
|
+
)
|
|
148
|
+
const { cacheView } = await renderCacheView(cache, ['test'], { error: customError })
|
|
149
|
+
expect(customError).toHaveBeenCalledOnce()
|
|
150
|
+
expect(customError.mock.calls[0][0]).toBeInstanceOf(Error)
|
|
151
|
+
const customErrorEl = cacheView.querySelector('.custom-error')
|
|
152
|
+
expect(customErrorEl).not.toBeNull()
|
|
125
153
|
},
|
|
126
|
-
})
|
|
127
|
-
try {
|
|
128
|
-
await cache.get('test')
|
|
129
|
-
} catch {
|
|
130
|
-
// expected
|
|
131
|
-
}
|
|
132
|
-
const customError = vi.fn(
|
|
133
|
-
(err: unknown, _retry: () => void) =>
|
|
134
|
-
(<span className="custom-error">{String(err)}</span>) as unknown as JSX.Element,
|
|
135
154
|
)
|
|
136
|
-
const { cacheView } = await renderCacheView(cache, ['test'], { error: customError })
|
|
137
|
-
expect(customError).toHaveBeenCalledOnce()
|
|
138
|
-
expect(customError.mock.calls[0][0]).toBeInstanceOf(Error)
|
|
139
|
-
const customErrorEl = cacheView.querySelector('.custom-error')
|
|
140
|
-
expect(customErrorEl).not.toBeNull()
|
|
141
|
-
cache[Symbol.dispose]()
|
|
142
155
|
})
|
|
143
156
|
|
|
144
157
|
it('should not render content when failed even if stale value exists', async () => {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
158
|
+
await usingAsync(new Cache<string, [string]>({ load: async (key) => key }), async (cache) => {
|
|
159
|
+
await cache.get('test')
|
|
160
|
+
cache.setExplicitValue({
|
|
161
|
+
loadArgs: ['test'],
|
|
162
|
+
value: { status: 'failed', error: new Error('fail'), value: 'stale', updatedAt: new Date() },
|
|
163
|
+
})
|
|
164
|
+
const { cacheView } = await renderCacheView(cache, ['test'])
|
|
165
|
+
expect(cacheView.querySelector('test-cache-content')).toBeNull()
|
|
166
|
+
expect(cacheView.querySelector('shade-result')).not.toBeNull()
|
|
150
167
|
})
|
|
151
|
-
const { cacheView } = await renderCacheView(cache, ['test'])
|
|
152
|
-
expect(cacheView.querySelector('test-cache-content')).toBeNull()
|
|
153
|
-
expect(cacheView.querySelector('shade-result')).not.toBeNull()
|
|
154
|
-
cache[Symbol.dispose]()
|
|
155
168
|
})
|
|
156
169
|
|
|
157
170
|
it('should call cache.reload when retry is invoked', async () => {
|
|
158
171
|
const loadFn = vi.fn<(key: string) => Promise<string>>(async () => {
|
|
159
172
|
throw new Error('fail')
|
|
160
173
|
})
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
174
|
+
await usingAsync(new Cache<string, [string]>({ load: loadFn }), async (cache) => {
|
|
175
|
+
try {
|
|
176
|
+
await cache.get('test')
|
|
177
|
+
} catch {
|
|
178
|
+
// expected
|
|
179
|
+
}
|
|
180
|
+
let capturedRetry: (() => void) | undefined
|
|
181
|
+
const customError = (_err: unknown, retry: () => void) => {
|
|
182
|
+
capturedRetry = retry
|
|
183
|
+
return (<span className="custom-error">Error</span>) as unknown as JSX.Element
|
|
184
|
+
}
|
|
185
|
+
await renderCacheView(cache, ['test'], { error: customError })
|
|
186
|
+
expect(capturedRetry).toBeDefined()
|
|
187
|
+
|
|
188
|
+
loadFn.mockResolvedValueOnce('recovered')
|
|
189
|
+
capturedRetry!()
|
|
190
|
+
await flushUpdates()
|
|
191
|
+
|
|
192
|
+
const observable = cache.getObservable('test')
|
|
193
|
+
const result = observable.getValue()
|
|
194
|
+
expect(result.status).toBe('loaded')
|
|
195
|
+
expect(result.value).toBe('recovered')
|
|
196
|
+
})
|
|
184
197
|
})
|
|
185
198
|
})
|
|
186
199
|
|
|
187
200
|
describe('obsolete state', () => {
|
|
188
201
|
it('should render content when obsolete and trigger reload', async () => {
|
|
189
202
|
const loadFn = vi.fn(async (key: string) => `Hello ${key}`)
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
203
|
+
await usingAsync(new Cache<string, [string]>({ load: loadFn }), async (cache) => {
|
|
204
|
+
await cache.get('test')
|
|
205
|
+
cache.setObsolete('test')
|
|
206
|
+
|
|
207
|
+
const { cacheView } = await renderCacheView(cache, ['test'])
|
|
208
|
+
const contentEl = cacheView.querySelector('test-cache-content')
|
|
209
|
+
expect(contentEl).not.toBeNull()
|
|
210
|
+
|
|
211
|
+
await flushUpdates()
|
|
212
|
+
// reload should have been called (initial load + obsolete reload)
|
|
213
|
+
expect(loadFn).toHaveBeenCalledTimes(2)
|
|
214
|
+
})
|
|
202
215
|
})
|
|
203
216
|
})
|
|
204
217
|
|
|
205
218
|
describe('error takes priority over value', () => {
|
|
206
219
|
it('should show error when failed with value, not content', async () => {
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
+
await usingAsync(new Cache<string, [string]>({ load: async (key) => key }), async (cache) => {
|
|
221
|
+
await cache.get('test')
|
|
222
|
+
const failedWithValue: CacheResult<string> = {
|
|
223
|
+
status: 'failed',
|
|
224
|
+
error: new Error('whoops'),
|
|
225
|
+
value: 'stale-data',
|
|
226
|
+
updatedAt: new Date(),
|
|
227
|
+
}
|
|
228
|
+
cache.setExplicitValue({ loadArgs: ['test'], value: failedWithValue })
|
|
229
|
+
const { cacheView } = await renderCacheView(cache, ['test'])
|
|
230
|
+
expect(cacheView.querySelector('test-cache-content')).toBeNull()
|
|
231
|
+
expect(cacheView.querySelector('shade-result')).not.toBeNull()
|
|
232
|
+
})
|
|
220
233
|
})
|
|
221
234
|
})
|
|
222
235
|
|
|
223
236
|
describe('contentProps', () => {
|
|
224
237
|
it('should forward contentProps to the content component', async () => {
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
238
|
+
await usingAsync(new Cache<string, [string]>({ load: async (key) => `Hello ${key}` }), async (cache) => {
|
|
239
|
+
await cache.get('world')
|
|
240
|
+
|
|
241
|
+
const el = (
|
|
242
|
+
<div>
|
|
243
|
+
<CacheView
|
|
244
|
+
cache={cache}
|
|
245
|
+
args={['world']}
|
|
246
|
+
content={TestContentWithLabel}
|
|
247
|
+
contentProps={{ label: 'Greeting' }}
|
|
248
|
+
/>
|
|
249
|
+
</div>
|
|
250
|
+
)
|
|
251
|
+
const cacheView = el.firstElementChild as JSX.Element
|
|
252
|
+
cacheView.updateComponent()
|
|
253
|
+
await flushUpdates()
|
|
254
|
+
|
|
255
|
+
const contentEl = cacheView.querySelector('test-cache-content-with-label') as JSX.Element
|
|
256
|
+
expect(contentEl).not.toBeNull()
|
|
257
|
+
contentEl.updateComponent()
|
|
258
|
+
await flushUpdates()
|
|
259
|
+
const valueEl = contentEl.querySelector('.content-value')
|
|
260
|
+
expect(valueEl?.textContent).toBe('Greeting: Hello world')
|
|
261
|
+
})
|
|
249
262
|
})
|
|
250
263
|
|
|
251
264
|
it('should forward contentProps when cache entry is obsolete', async () => {
|
|
252
265
|
const loadFn = vi.fn(async (key: string) => `Hello ${key}`)
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
266
|
+
await usingAsync(new Cache<string, [string]>({ load: loadFn }), async (cache) => {
|
|
267
|
+
await cache.get('world')
|
|
268
|
+
cache.setObsolete('world')
|
|
269
|
+
|
|
270
|
+
const el = (
|
|
271
|
+
<div>
|
|
272
|
+
<CacheView
|
|
273
|
+
cache={cache}
|
|
274
|
+
args={['world']}
|
|
275
|
+
content={TestContentWithLabel}
|
|
276
|
+
contentProps={{ label: 'Stale' }}
|
|
277
|
+
/>
|
|
278
|
+
</div>
|
|
279
|
+
)
|
|
280
|
+
const cacheView = el.firstElementChild as JSX.Element
|
|
281
|
+
cacheView.updateComponent()
|
|
282
|
+
await flushUpdates()
|
|
283
|
+
|
|
284
|
+
const contentEl = cacheView.querySelector('test-cache-content-with-label') as JSX.Element
|
|
285
|
+
expect(contentEl).not.toBeNull()
|
|
286
|
+
contentEl.updateComponent()
|
|
287
|
+
await flushUpdates()
|
|
288
|
+
const valueEl = contentEl.querySelector('.content-value')
|
|
289
|
+
expect(valueEl?.textContent).toBe('Stale: Hello world')
|
|
290
|
+
expect(loadFn).toHaveBeenCalledTimes(2)
|
|
291
|
+
})
|
|
274
292
|
})
|
|
275
293
|
})
|
|
276
294
|
|
|
@@ -292,61 +310,59 @@ describe('CacheView', () => {
|
|
|
292
310
|
|
|
293
311
|
it('should call startViewTransition when viewTransition is enabled and cache state category changes', async () => {
|
|
294
312
|
const spy = mockStartViewTransition()
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
spy.mockClear()
|
|
313
|
+
await usingAsync(new Cache<string, [string]>({ load: async (key) => `loaded-${key}` }), async (cache) => {
|
|
314
|
+
const el = (
|
|
315
|
+
<div>
|
|
316
|
+
<CacheView
|
|
317
|
+
cache={cache}
|
|
318
|
+
args={['test']}
|
|
319
|
+
content={TestContent}
|
|
320
|
+
loader={<span className="loader">Loading</span>}
|
|
321
|
+
viewTransition
|
|
322
|
+
/>
|
|
323
|
+
</div>
|
|
324
|
+
)
|
|
325
|
+
const cacheView = el.firstElementChild as JSX.Element
|
|
326
|
+
cacheView.updateComponent()
|
|
327
|
+
await flushUpdates()
|
|
328
|
+
|
|
329
|
+
expect(cacheView.querySelector('.loader')).toBeTruthy()
|
|
330
|
+
spy.mockClear()
|
|
314
331
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
332
|
+
await cache.get('test')
|
|
333
|
+
cacheView.updateComponent()
|
|
334
|
+
await flushUpdates()
|
|
318
335
|
|
|
319
|
-
|
|
320
|
-
|
|
336
|
+
expect(spy).toHaveBeenCalled()
|
|
337
|
+
})
|
|
321
338
|
delete (document as unknown as Record<string, unknown>).startViewTransition
|
|
322
339
|
})
|
|
323
340
|
|
|
324
341
|
it('should not call startViewTransition when viewTransition is not set', async () => {
|
|
325
342
|
const spy = mockStartViewTransition()
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
spy.mockClear()
|
|
343
|
+
await usingAsync(new Cache<string, [string]>({ load: async (key) => `loaded-${key}` }), async (cache) => {
|
|
344
|
+
const el = (
|
|
345
|
+
<div>
|
|
346
|
+
<CacheView
|
|
347
|
+
cache={cache}
|
|
348
|
+
args={['test']}
|
|
349
|
+
content={TestContent}
|
|
350
|
+
loader={<span className="loader">Loading</span>}
|
|
351
|
+
/>
|
|
352
|
+
</div>
|
|
353
|
+
)
|
|
354
|
+
const cacheView = el.firstElementChild as JSX.Element
|
|
355
|
+
cacheView.updateComponent()
|
|
356
|
+
await flushUpdates()
|
|
357
|
+
|
|
358
|
+
spy.mockClear()
|
|
343
359
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
360
|
+
await cache.get('test')
|
|
361
|
+
cacheView.updateComponent()
|
|
362
|
+
await flushUpdates()
|
|
347
363
|
|
|
348
|
-
|
|
349
|
-
|
|
364
|
+
expect(spy).not.toHaveBeenCalled()
|
|
365
|
+
})
|
|
350
366
|
delete (document as unknown as Record<string, unknown>).startViewTransition
|
|
351
367
|
})
|
|
352
368
|
})
|
|
@@ -95,7 +95,7 @@ export const CommandPaletteSuggestionList = Shade<{ manager: CommandPaletteManag
|
|
|
95
95
|
ref={containerRef}
|
|
96
96
|
className="suggestion-items-container"
|
|
97
97
|
style={{
|
|
98
|
-
opacity:
|
|
98
|
+
opacity: isOpenedAtRender ? '1' : '0',
|
|
99
99
|
maxHeight: `${window.innerHeight * 0.8}px`,
|
|
100
100
|
width: `calc(${Math.round(hostParentWidth)}px - 3em)`,
|
|
101
101
|
...(props.fullScreenSuggestions ? { left: '0', width: 'calc(100% - 42px)' } : {}),
|
|
@@ -243,6 +243,8 @@ export const Input = Shade<TextInputProps>({
|
|
|
243
243
|
|
|
244
244
|
const themeProvider = injector.getInstance(ThemeProviderService)
|
|
245
245
|
|
|
246
|
+
// We want to use the CSS state hooks for the focused and validity states, so we need to disable the rule
|
|
247
|
+
// eslint-disable-next-line furystack/no-css-state-hooks
|
|
246
248
|
const [focused, setFocused] = useState('focused', props.autofocus || false)
|
|
247
249
|
const [validity, setValidity] = useState('validity', inputRef.current?.validity || emptyValidity)
|
|
248
250
|
|
|
@@ -4,8 +4,8 @@ import { cssVariableTheme } from '../../services/css-variable-theme.js'
|
|
|
4
4
|
import type { Palette } from '../../services/theme-provider-service.js'
|
|
5
5
|
import { ThemeProviderService } from '../../services/theme-provider-service.js'
|
|
6
6
|
import { FormService } from '../form.js'
|
|
7
|
-
import { Icon } from '../icons/icon.js'
|
|
8
7
|
import { check, close } from '../icons/icon-definitions.js'
|
|
8
|
+
import { Icon } from '../icons/icon.js'
|
|
9
9
|
import type { InputValidationResult } from './input.js'
|
|
10
10
|
|
|
11
11
|
export type SelectOption = {
|
|
@@ -384,6 +384,8 @@ export const Select = Shade<SelectProps>({
|
|
|
384
384
|
}
|
|
385
385
|
|
|
386
386
|
const [state, setState] = useState<SelectState>('selectState', initialState)
|
|
387
|
+
// We want to use the CSS state hooks for the focused and dropdown direction states, so we need to disable the rule
|
|
388
|
+
// eslint-disable-next-line furystack/no-css-state-hooks
|
|
387
389
|
const [isFocused, setIsFocused] = useState('isFocused', false)
|
|
388
390
|
const [dropdownDirection, setDropdownDirection] = useState<'up' | 'down'>('dropdownDirection', 'down')
|
|
389
391
|
|
|
@@ -40,16 +40,19 @@ const statusColorMap: Record<ResultStatus, string> = {
|
|
|
40
40
|
'500': paletteMainColors.error.main,
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
const
|
|
44
|
-
success:
|
|
45
|
-
error:
|
|
46
|
-
warning:
|
|
47
|
-
info:
|
|
48
|
-
'403':
|
|
49
|
-
'404':
|
|
50
|
-
'500':
|
|
43
|
+
const defaultIconDefs: Record<ResultStatus, typeof checkCircle> = {
|
|
44
|
+
success: checkCircle,
|
|
45
|
+
error: errorCircle,
|
|
46
|
+
warning: warningIcon,
|
|
47
|
+
info: infoIcon,
|
|
48
|
+
'403': forbidden,
|
|
49
|
+
'404': searchOff,
|
|
50
|
+
'500': serverError,
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
const getDefaultIcon = (status: ResultStatus): JSX.Element =>
|
|
54
|
+
(<Icon icon={defaultIconDefs[status]} size={64} />) as unknown as JSX.Element
|
|
55
|
+
|
|
53
56
|
const defaultTitles: Record<ResultStatus, string> = {
|
|
54
57
|
success: 'Success',
|
|
55
58
|
error: 'Error',
|
|
@@ -114,7 +117,7 @@ export const Result = Shade<ResultProps>({
|
|
|
114
117
|
render: ({ props, children, useHostProps }) => {
|
|
115
118
|
const { status, title, subtitle, icon, style } = props
|
|
116
119
|
|
|
117
|
-
const displayIcon = icon ??
|
|
120
|
+
const displayIcon = icon ?? getDefaultIcon(status)
|
|
118
121
|
const statusColor = statusColorMap[status]
|
|
119
122
|
|
|
120
123
|
useHostProps({
|
|
@@ -146,4 +149,8 @@ export const Result = Shade<ResultProps>({
|
|
|
146
149
|
},
|
|
147
150
|
})
|
|
148
151
|
|
|
149
|
-
export {
|
|
152
|
+
export {
|
|
153
|
+
getDefaultIcon as resultGetDefaultIcon,
|
|
154
|
+
defaultIconDefs as resultDefaultIconDefs,
|
|
155
|
+
defaultTitles as resultDefaultTitles,
|
|
156
|
+
}
|