@adea-ai/ui 0.72.2 → 0.72.4
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/dist/components/composites/update-dialog/update-dialog.d.ts +7 -3
- package/dist/components/composites/update-dialog/update-dialog.d.ts.map +1 -1
- package/dist/components/composites/update-dialog/update-dialog.js +48 -13
- package/dist/components/composites/update-dialog/update-dialog.js.map +1 -1
- package/dist/components/ui/alert-dialog/alert-dialog.d.ts +2 -2
- package/dist/components/ui/alert-dialog/alert-dialog.d.ts.map +1 -1
- package/dist/components/ui/alert-dialog/alert-dialog.js +2 -2
- package/dist/components/ui/alert-dialog/alert-dialog.js.map +1 -1
- package/dist/components/ui/dialog/dialog.d.ts +5 -5
- package/dist/components/ui/dialog/dialog.d.ts.map +1 -1
- package/dist/components/ui/dialog/dialog.js +3 -3
- package/dist/components/ui/dialog/dialog.js.map +1 -1
- package/dist/components/ui/sheet/sheet.d.ts +2 -2
- package/dist/components/ui/sheet/sheet.d.ts.map +1 -1
- package/dist/components/ui/sheet/sheet.js +2 -2
- package/dist/components/ui/sheet/sheet.js.map +1 -1
- package/dist/r/src/components/composites/update-dialog/update-dialog.tsx +70 -16
- package/dist/r/src/components/ui/alert-dialog/alert-dialog.tsx +7 -3
- package/dist/r/src/components/ui/dialog/dialog.tsx +13 -8
- package/dist/r/src/components/ui/sheet/sheet.tsx +5 -4
- package/package.json +1 -1
- package/src/components/composites/update-dialog/update-dialog.tsx +70 -16
- package/src/components/ui/alert-dialog/alert-dialog.tsx +7 -3
- package/src/components/ui/dialog/dialog.tsx +13 -8
- package/src/components/ui/sheet/sheet.tsx +5 -4
|
@@ -56,9 +56,13 @@ import { formatBytes, formatReleaseDate, plainTextFromMarkdown } from '#lib/vers
|
|
|
56
56
|
* the other order leaves the dialog blank for as long as the check takes, on a
|
|
57
57
|
* dialog whose first question is always "what am I running?".
|
|
58
58
|
*
|
|
59
|
-
* **
|
|
60
|
-
*
|
|
61
|
-
*
|
|
59
|
+
* **A failed check is not a current result.** A cached `current` status can only
|
|
60
|
+
* be shown as up to date after the latest check succeeds; a failed check remains
|
|
61
|
+
* retryable and suppresses that claim.
|
|
62
|
+
*
|
|
63
|
+
* **Errors are not always `Error`s.** An adapter can reject with a string or a
|
|
64
|
+
* structured safe message. Unknown object fields are never serialized into the
|
|
65
|
+
* UI; a generic fallback is shown instead.
|
|
62
66
|
*
|
|
63
67
|
* The adapter's `isDesktopRuntime` gate exists because an update is a desktop
|
|
64
68
|
* concern: a browser build has no installer, and the honest thing to show is that
|
|
@@ -151,10 +155,22 @@ export type UpdateDialogProps = {
|
|
|
151
155
|
class?: string
|
|
152
156
|
}
|
|
153
157
|
|
|
158
|
+
function messageText(value: unknown): string | undefined {
|
|
159
|
+
if (typeof value !== 'string') return undefined
|
|
160
|
+
const message = value.trim()
|
|
161
|
+
return message && message !== '[object Object]' ? message : undefined
|
|
162
|
+
}
|
|
163
|
+
|
|
154
164
|
function errorMessage(caught: unknown, fallback: string): string {
|
|
155
|
-
if (caught instanceof Error
|
|
156
|
-
|
|
157
|
-
return
|
|
165
|
+
if (caught instanceof Error) return messageText(caught.message) ?? fallback
|
|
166
|
+
const plainMessage = messageText(caught)
|
|
167
|
+
if (plainMessage) return plainMessage
|
|
168
|
+
if (!caught || typeof caught !== 'object') return fallback
|
|
169
|
+
|
|
170
|
+
const record = caught as { error?: unknown; safe?: unknown }
|
|
171
|
+
const safe = record.safe as { message?: unknown } | null | undefined
|
|
172
|
+
const nestedError = record.error as { safe?: { message?: unknown } | null } | null | undefined
|
|
173
|
+
return messageText(safe?.message) ?? messageText(nestedError?.safe?.message) ?? fallback
|
|
158
174
|
}
|
|
159
175
|
|
|
160
176
|
/**
|
|
@@ -199,6 +215,7 @@ export function UpdateDialog(props: UpdateDialogProps) {
|
|
|
199
215
|
const [state, setState] = createSignal<UpdateState | null>(null)
|
|
200
216
|
const [busy, setBusy] = createSignal(false)
|
|
201
217
|
const [error, setError] = createSignal('')
|
|
218
|
+
const [checkFailed, setCheckFailed] = createSignal(false)
|
|
202
219
|
let lifecycleEpoch = 0
|
|
203
220
|
let activeOpenEpoch: number | undefined
|
|
204
221
|
let disposed = false
|
|
@@ -213,7 +230,19 @@ export function UpdateDialog(props: UpdateDialogProps) {
|
|
|
213
230
|
if (!desktop() || !isCurrent()) return
|
|
214
231
|
try {
|
|
215
232
|
const status = await local.adapter.getStatus()
|
|
216
|
-
|
|
233
|
+
const previous = state()
|
|
234
|
+
const hasActionableSnapshot = (candidate: UpdateState | null) =>
|
|
235
|
+
candidate?.phase === 'available' || isBusy(candidate)
|
|
236
|
+
const preservesSnapshot =
|
|
237
|
+
previous?.phase === 'available'
|
|
238
|
+
? status.phase === 'available' || isBusy(status)
|
|
239
|
+
: isBusy(previous) && isBusy(status)
|
|
240
|
+
if (
|
|
241
|
+
isCurrent() &&
|
|
242
|
+
!(checkFailed() && hasActionableSnapshot(previous) && !preservesSnapshot)
|
|
243
|
+
) {
|
|
244
|
+
setState(status)
|
|
245
|
+
}
|
|
217
246
|
} catch (caught) {
|
|
218
247
|
if (isCurrent()) setError(errorMessage(caught, 'Version status is unavailable'))
|
|
219
248
|
}
|
|
@@ -226,6 +255,24 @@ export function UpdateDialog(props: UpdateDialogProps) {
|
|
|
226
255
|
}
|
|
227
256
|
})
|
|
228
257
|
|
|
258
|
+
const failCheck = (caught: unknown, fallback: string) => {
|
|
259
|
+
const message = errorMessage(caught, fallback)
|
|
260
|
+
setCheckFailed(true)
|
|
261
|
+
setError(message)
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const applyCheckResult = (next: UpdateState) => {
|
|
265
|
+
if (next.phase === 'failed') {
|
|
266
|
+
const current = state()
|
|
267
|
+
if (!current) setState(next)
|
|
268
|
+
failCheck(next.error, 'Could not check for updates')
|
|
269
|
+
return
|
|
270
|
+
}
|
|
271
|
+
setState(next)
|
|
272
|
+
setCheckFailed(false)
|
|
273
|
+
setError('')
|
|
274
|
+
}
|
|
275
|
+
|
|
229
276
|
const check = async () => {
|
|
230
277
|
if (!desktop()) {
|
|
231
278
|
setError(local.desktopOnlyMessage ?? `Update checks are available from the desktop app.`)
|
|
@@ -241,13 +288,15 @@ export function UpdateDialog(props: UpdateDialogProps) {
|
|
|
241
288
|
if (!isCurrent()) return
|
|
242
289
|
setBusy(true)
|
|
243
290
|
setError('')
|
|
291
|
+
setCheckFailed(false)
|
|
244
292
|
try {
|
|
245
293
|
const checked = await local.adapter.check()
|
|
246
|
-
if (isCurrent())
|
|
294
|
+
if (isCurrent()) applyCheckResult(checked)
|
|
247
295
|
} catch (caught) {
|
|
248
|
-
if (
|
|
249
|
-
|
|
250
|
-
|
|
296
|
+
if (isCurrent()) {
|
|
297
|
+
failCheck(caught, 'Could not check for updates')
|
|
298
|
+
await loadStatus(isCurrent)
|
|
299
|
+
}
|
|
251
300
|
} finally {
|
|
252
301
|
if (isCurrent()) setBusy(false)
|
|
253
302
|
}
|
|
@@ -279,6 +328,7 @@ export function UpdateDialog(props: UpdateDialogProps) {
|
|
|
279
328
|
}
|
|
280
329
|
})
|
|
281
330
|
setError('')
|
|
331
|
+
setCheckFailed(false)
|
|
282
332
|
setBusy(true)
|
|
283
333
|
void (async () => {
|
|
284
334
|
try {
|
|
@@ -286,9 +336,9 @@ export function UpdateDialog(props: UpdateDialogProps) {
|
|
|
286
336
|
if (!isCurrent()) return
|
|
287
337
|
setState(current)
|
|
288
338
|
const checked = await local.adapter.check()
|
|
289
|
-
if (isCurrent())
|
|
339
|
+
if (isCurrent()) applyCheckResult(checked)
|
|
290
340
|
} catch (caught) {
|
|
291
|
-
if (isCurrent())
|
|
341
|
+
if (isCurrent()) failCheck(caught, 'Could not check for updates')
|
|
292
342
|
} finally {
|
|
293
343
|
if (isCurrent()) setBusy(false)
|
|
294
344
|
}
|
|
@@ -315,6 +365,8 @@ export function UpdateDialog(props: UpdateDialogProps) {
|
|
|
315
365
|
// Without this the click looked like nothing happened.
|
|
316
366
|
if (next.phase === 'failed') {
|
|
317
367
|
setError(errorMessage(next.error, 'Update installation failed'))
|
|
368
|
+
} else {
|
|
369
|
+
setCheckFailed(false)
|
|
318
370
|
}
|
|
319
371
|
} catch (caught) {
|
|
320
372
|
if (!isCurrent()) return
|
|
@@ -331,10 +383,12 @@ export function UpdateDialog(props: UpdateDialogProps) {
|
|
|
331
383
|
return value ? plainTextFromMarkdown(value) : ''
|
|
332
384
|
}
|
|
333
385
|
const working = () => busy() || isBusy(state())
|
|
386
|
+
const isCurrent = () => state()?.phase === 'current' && !error() && !checkFailed() && !working()
|
|
334
387
|
|
|
335
388
|
const triggerLabel = () => {
|
|
336
389
|
const current = state()
|
|
337
390
|
const fallback = `v${local.fallbackVersion ?? '0.1.0'}`
|
|
391
|
+
if (checkFailed()) return `Version ${current?.currentVersion || fallback} · Retry`
|
|
338
392
|
if (!current) return `${appName()} ${fallback}`
|
|
339
393
|
switch (current.phase) {
|
|
340
394
|
case 'checking':
|
|
@@ -410,7 +464,7 @@ export function UpdateDialog(props: UpdateDialogProps) {
|
|
|
410
464
|
</p>
|
|
411
465
|
<p class="text-sm text-muted-foreground">
|
|
412
466
|
<Show
|
|
413
|
-
when={
|
|
467
|
+
when={isCurrent()}
|
|
414
468
|
fallback={
|
|
415
469
|
<Show
|
|
416
470
|
when={state()?.phase === 'available' && state()?.availableVersion}
|
|
@@ -439,7 +493,7 @@ export function UpdateDialog(props: UpdateDialogProps) {
|
|
|
439
493
|
<Show when={working()} fallback={<RefreshCw aria-hidden="true" />}>
|
|
440
494
|
<LoaderCircle class="animate-spin" aria-hidden="true" />
|
|
441
495
|
</Show>
|
|
442
|
-
Check latest version
|
|
496
|
+
{checkFailed() ? 'Retry update check' : 'Check latest version'}
|
|
443
497
|
</Button>
|
|
444
498
|
</div>
|
|
445
499
|
</section>
|
|
@@ -503,7 +557,7 @@ export function UpdateDialog(props: UpdateDialogProps) {
|
|
|
503
557
|
</section>
|
|
504
558
|
</Show>
|
|
505
559
|
|
|
506
|
-
<Show when={
|
|
560
|
+
<Show when={isCurrent()}>
|
|
507
561
|
<p class="text-foreground flex items-center gap-2 text-sm" role="status">
|
|
508
562
|
<Check class="size-4 text-success" aria-hidden="true" />
|
|
509
563
|
{appName()} is up to date.
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
AlertDialog as KobalteAlertDialog,
|
|
3
|
+
Content as KobalteAlertDialogContent,
|
|
4
|
+
} from '@kobalte/core/alert-dialog'
|
|
5
|
+
// Use the alert-specific export rather than DialogRoot.Content, which other imports can replace.
|
|
2
6
|
import type { ComponentProps } from 'solid-js'
|
|
3
7
|
import { createEffect, createSignal, splitProps } from 'solid-js'
|
|
4
8
|
import { overlayMotion, overlayPositioner, overlayScrim, overlaySurface } from '#lib/overlay'
|
|
@@ -70,14 +74,14 @@ const blockDismissal = {
|
|
|
70
74
|
onInteractOutside: (event: Event) => event.preventDefault(),
|
|
71
75
|
} as const
|
|
72
76
|
|
|
73
|
-
export function AlertDialogContent(props: ComponentProps<typeof
|
|
77
|
+
export function AlertDialogContent(props: ComponentProps<typeof KobalteAlertDialogContent>) {
|
|
74
78
|
const [local, rest] = splitProps(props, ['class'])
|
|
75
79
|
|
|
76
80
|
return (
|
|
77
81
|
<KobalteAlertDialog.Portal>
|
|
78
82
|
<AlertDialogOverlay />
|
|
79
83
|
<div class={overlayPositioner}>
|
|
80
|
-
<
|
|
84
|
+
<KobalteAlertDialogContent
|
|
81
85
|
{...blockDismissal}
|
|
82
86
|
class={cn(overlaySurface, overlayMotion, 'grid w-full max-w-md gap-4 p-5', local.class)}
|
|
83
87
|
{...rest}
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
Dialog as KobalteDialog,
|
|
3
|
+
Content as KobalteDialogContent,
|
|
4
|
+
Overlay as KobalteDialogOverlay,
|
|
5
|
+
} from '@kobalte/core/dialog'
|
|
6
|
+
// AlertDialog assigns to the shared DialogRoot.Content object, so these named exports stay role-stable.
|
|
2
7
|
import { X } from 'lucide-solid'
|
|
3
8
|
import type { Accessor, ComponentProps, JSX } from 'solid-js'
|
|
4
9
|
import { createRenderEffect, onCleanup, Show, splitProps } from 'solid-js'
|
|
@@ -43,8 +48,8 @@ function hasOtherOverlay(content: HTMLElement, opener: HTMLElement): boolean {
|
|
|
43
48
|
type DialogFocusRestorationOptions = {
|
|
44
49
|
open: Accessor<boolean>
|
|
45
50
|
restoreFocusRef?: Accessor<HTMLElement | undefined>
|
|
46
|
-
onOpenAutoFocus?: ComponentProps<typeof
|
|
47
|
-
onCloseAutoFocus?: ComponentProps<typeof
|
|
51
|
+
onOpenAutoFocus?: ComponentProps<typeof KobalteDialogContent>['onOpenAutoFocus']
|
|
52
|
+
onCloseAutoFocus?: ComponentProps<typeof KobalteDialogContent>['onCloseAutoFocus']
|
|
48
53
|
}
|
|
49
54
|
|
|
50
55
|
/**
|
|
@@ -231,10 +236,10 @@ export function DialogPortal(props: ComponentProps<typeof KobalteDialog.Portal>)
|
|
|
231
236
|
return <KobalteDialog.Portal {...props} />
|
|
232
237
|
}
|
|
233
238
|
|
|
234
|
-
export function DialogOverlay(props: ComponentProps<typeof
|
|
239
|
+
export function DialogOverlay(props: ComponentProps<typeof KobalteDialogOverlay>) {
|
|
235
240
|
const [local, rest] = splitProps(props, ['class'])
|
|
236
241
|
return (
|
|
237
|
-
<
|
|
242
|
+
<KobalteDialogOverlay
|
|
238
243
|
class={cn(
|
|
239
244
|
overlayScrim,
|
|
240
245
|
'data-expanded:animate-in data-expanded:fade-in-0 data-closed:animate-out data-closed:fade-out-0',
|
|
@@ -245,7 +250,7 @@ export function DialogOverlay(props: ComponentProps<typeof KobalteDialog.Overlay
|
|
|
245
250
|
)
|
|
246
251
|
}
|
|
247
252
|
|
|
248
|
-
export type DialogContentProps = ComponentProps<typeof
|
|
253
|
+
export type DialogContentProps = ComponentProps<typeof KobalteDialogContent> & {
|
|
249
254
|
/**
|
|
250
255
|
* Replaces the default close button. Pass `false` to remove it — only for a
|
|
251
256
|
* dialog that cannot be dismissed (an update that must finish); anything the
|
|
@@ -261,7 +266,7 @@ export function DialogContent(props: DialogContentProps) {
|
|
|
261
266
|
<KobalteDialog.Portal>
|
|
262
267
|
<DialogOverlay />
|
|
263
268
|
<div class={overlayPositioner}>
|
|
264
|
-
<
|
|
269
|
+
<KobalteDialogContent
|
|
265
270
|
class={cn(
|
|
266
271
|
overlaySurface,
|
|
267
272
|
overlayMotion,
|
|
@@ -283,7 +288,7 @@ export function DialogContent(props: DialogContentProps) {
|
|
|
283
288
|
{local.closeButton ?? <X class="size-4" />}
|
|
284
289
|
</KobalteDialog.CloseButton>
|
|
285
290
|
</Show>
|
|
286
|
-
</
|
|
291
|
+
</KobalteDialogContent>
|
|
287
292
|
</div>
|
|
288
293
|
</KobalteDialog.Portal>
|
|
289
294
|
)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { Dialog as KobalteDialog } from '@kobalte/core/dialog'
|
|
1
|
+
import { Dialog as KobalteDialog, Content as KobalteDialogContent } from '@kobalte/core/dialog'
|
|
2
|
+
// AlertDialog shares DialogRoot.Content; Sheet uses the stable named primitive.
|
|
2
3
|
import { X } from 'lucide-solid'
|
|
3
4
|
import type { ComponentProps, JSX } from 'solid-js'
|
|
4
5
|
import { Show, splitProps } from 'solid-js'
|
|
@@ -35,7 +36,7 @@ const sheetVariants = cva(
|
|
|
35
36
|
}
|
|
36
37
|
)
|
|
37
38
|
|
|
38
|
-
export type SheetContentProps = ComponentProps<typeof
|
|
39
|
+
export type SheetContentProps = ComponentProps<typeof KobalteDialogContent> &
|
|
39
40
|
VariantProps<typeof sheetVariants> & {
|
|
40
41
|
closeButton?: JSX.Element | false
|
|
41
42
|
}
|
|
@@ -46,7 +47,7 @@ export function SheetContent(props: SheetContentProps) {
|
|
|
46
47
|
return (
|
|
47
48
|
<KobalteDialog.Portal>
|
|
48
49
|
<DialogOverlay />
|
|
49
|
-
<
|
|
50
|
+
<KobalteDialogContent
|
|
50
51
|
class={cn(
|
|
51
52
|
sheetVariants({ side: local.side }),
|
|
52
53
|
'data-expanded:animate-in data-expanded:fade-in-0 data-expanded:duration-200',
|
|
@@ -64,7 +65,7 @@ export function SheetContent(props: SheetContentProps) {
|
|
|
64
65
|
{local.closeButton ?? <X class="size-4" />}
|
|
65
66
|
</KobalteDialog.CloseButton>
|
|
66
67
|
</Show>
|
|
67
|
-
</
|
|
68
|
+
</KobalteDialogContent>
|
|
68
69
|
</KobalteDialog.Portal>
|
|
69
70
|
)
|
|
70
71
|
}
|