@xemahq/ui-kernel 0.9.1 → 0.10.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/README.md +2 -2
- package/dist/lib/biome-host/biome-builders.d.ts.map +1 -1
- package/dist/lib/biome-host/biome-builders.js +3 -1
- package/dist/lib/biome-host/biome-builders.js.map +1 -1
- package/dist/lib/biome-host/biome-registry.d.ts.map +1 -1
- package/dist/lib/biome-host/biome-registry.js.map +1 -1
- package/dist/lib/biome-host/biome-scope-hooks.d.ts +11 -0
- package/dist/lib/biome-host/biome-scope-hooks.d.ts.map +1 -0
- package/dist/lib/biome-host/biome-scope-hooks.js +25 -0
- package/dist/lib/biome-host/biome-scope-hooks.js.map +1 -0
- package/dist/lib/biome-host/biome-scope.d.ts +1 -10
- package/dist/lib/biome-host/biome-scope.d.ts.map +1 -1
- package/dist/lib/biome-host/biome-scope.js +1 -24
- package/dist/lib/biome-host/biome-scope.js.map +1 -1
- package/dist/lib/biome-host/biome-scoped-query.d.ts +1 -1
- package/dist/lib/biome-host/biome-scoped-query.d.ts.map +1 -1
- package/dist/lib/biome-host/biome-scoped-query.js +1 -1
- package/dist/lib/biome-host/biome-scoped-query.js.map +1 -1
- package/dist/lib/biome-host/create-biome-orval-config.js +2 -2
- package/dist/lib/biome-host/create-biome-orval-config.js.map +1 -1
- package/dist/lib/biome-host/errors.js.map +1 -1
- package/dist/lib/biome-host/index.d.ts +1 -2
- package/dist/lib/biome-host/index.d.ts.map +1 -1
- package/dist/lib/biome-host/index.js +1 -2
- package/dist/lib/biome-host/index.js.map +1 -1
- package/dist/lib/biome-host/session-contributions.d.ts +9 -4
- package/dist/lib/biome-host/session-contributions.d.ts.map +1 -1
- package/dist/lib/capabilities/capability-context.d.ts +9 -0
- package/dist/lib/capabilities/capability-context.d.ts.map +1 -0
- package/dist/lib/capabilities/capability-context.js +13 -0
- package/dist/lib/capabilities/capability-context.js.map +1 -0
- package/dist/lib/capabilities/capability-provider.d.ts +2 -8
- package/dist/lib/capabilities/capability-provider.d.ts.map +1 -1
- package/dist/lib/capabilities/capability-provider.js +1 -12
- package/dist/lib/capabilities/capability-provider.js.map +1 -1
- package/dist/lib/capabilities/index.d.ts +1 -0
- package/dist/lib/capabilities/index.d.ts.map +1 -1
- package/dist/lib/capabilities/index.js +1 -0
- package/dist/lib/capabilities/index.js.map +1 -1
- package/dist/lib/capabilities/use-capability.d.ts.map +1 -1
- package/dist/lib/capabilities/use-capability.js +1 -1
- package/dist/lib/capabilities/use-capability.js.map +1 -1
- package/dist/lib/system-bus/deeplink.js.map +1 -1
- package/dist/lib/system-bus/host-ports.d.ts +2 -1
- package/dist/lib/system-bus/host-ports.d.ts.map +1 -1
- package/dist/lib/system-bus/intent-registry.d.ts.map +1 -1
- package/dist/lib/system-bus/intent-registry.js.map +1 -1
- package/dist/offline/index.d.ts +2 -1
- package/dist/offline/index.d.ts.map +1 -1
- package/dist/offline/index.js +2 -1
- package/dist/offline/index.js.map +1 -1
- package/dist/offline/offline-status-badge.js +1 -1
- package/dist/offline/offline-status-badge.js.map +1 -1
- package/dist/offline/outbox.js.map +1 -1
- package/dist/offline/react-hooks.d.ts +7 -0
- package/dist/offline/react-hooks.d.ts.map +1 -0
- package/dist/offline/react-hooks.js +25 -0
- package/dist/offline/react-hooks.js.map +1 -0
- package/dist/offline/react.d.ts +0 -4
- package/dist/offline/react.d.ts.map +1 -1
- package/dist/offline/react.js +2 -24
- package/dist/offline/react.js.map +1 -1
- package/dist/offline/storage.d.ts.map +1 -1
- package/dist/offline/storage.js +8 -5
- package/dist/offline/storage.js.map +1 -1
- package/dist/registry/index.d.ts +1 -0
- package/dist/registry/index.d.ts.map +1 -1
- package/dist/registry/index.js +1 -0
- package/dist/registry/index.js.map +1 -1
- package/dist/registry/lib/primitives/SessionEventCard.d.ts.map +1 -1
- package/dist/registry/lib/primitives/SessionEventCard.js +1 -1
- package/dist/registry/lib/primitives/SessionEventCard.js.map +1 -1
- package/dist/registry/lib/session-context-builder.d.ts +10 -2
- package/dist/registry/lib/session-context-builder.d.ts.map +1 -1
- package/dist/registry/lib/session-context-builder.js +14 -7
- package/dist/registry/lib/session-context-builder.js.map +1 -1
- package/dist/registry/lib/session-context-provider.d.ts +1 -3
- package/dist/registry/lib/session-context-provider.d.ts.map +1 -1
- package/dist/registry/lib/session-context-provider.js +2 -15
- package/dist/registry/lib/session-context-provider.js.map +1 -1
- package/dist/registry/lib/session-context.d.ts +5 -0
- package/dist/registry/lib/session-context.d.ts.map +1 -0
- package/dist/registry/lib/session-context.js +15 -0
- package/dist/registry/lib/session-context.js.map +1 -0
- package/dist/registry/lib/session-selectors.d.ts.map +1 -1
- package/dist/registry/lib/session-selectors.js +3 -1
- package/dist/registry/lib/session-selectors.js.map +1 -1
- package/dist/ui/branding/app-branding-context.d.ts +9 -0
- package/dist/ui/branding/app-branding-context.d.ts.map +1 -0
- package/dist/ui/branding/app-branding-context.js +10 -0
- package/dist/ui/branding/app-branding-context.js.map +1 -0
- package/dist/ui/branding/app-branding-provider.d.ts +0 -6
- package/dist/ui/branding/app-branding-provider.d.ts.map +1 -1
- package/dist/ui/branding/app-branding-provider.js +1 -8
- package/dist/ui/branding/app-branding-provider.js.map +1 -1
- package/dist/ui/capture/schema-field-input.js +1 -1
- package/dist/ui/capture/schema-field-input.js.map +1 -1
- package/dist/ui/capture/use-prefill.d.ts.map +1 -1
- package/dist/ui/capture/use-prefill.js +3 -1
- package/dist/ui/capture/use-prefill.js.map +1 -1
- package/dist/ui/capture/use-wizard.d.ts +1 -1
- package/dist/ui/capture/use-wizard.d.ts.map +1 -1
- package/dist/ui/capture/use-wizard.js +1 -1
- package/dist/ui/capture/use-wizard.js.map +1 -1
- package/dist/ui/capture/wizard.d.ts.map +1 -1
- package/dist/ui/capture/wizard.js.map +1 -1
- package/dist/ui/index.d.ts +5 -1
- package/dist/ui/index.d.ts.map +1 -1
- package/dist/ui/index.js +5 -1
- package/dist/ui/index.js.map +1 -1
- package/dist/ui/primitives/alert-dialog.js +1 -1
- package/dist/ui/primitives/alert-dialog.js.map +1 -1
- package/dist/ui/primitives/badge-variants.d.ts +4 -0
- package/dist/ui/primitives/badge-variants.d.ts.map +1 -0
- package/dist/ui/primitives/badge-variants.js +15 -0
- package/dist/ui/primitives/badge-variants.js.map +1 -0
- package/dist/ui/primitives/badge.d.ts +3 -5
- package/dist/ui/primitives/badge.d.ts.map +1 -1
- package/dist/ui/primitives/badge.js +2 -15
- package/dist/ui/primitives/badge.js.map +1 -1
- package/dist/ui/primitives/button-variants.d.ts +5 -0
- package/dist/ui/primitives/button-variants.d.ts.map +1 -0
- package/dist/ui/primitives/button-variants.js +24 -0
- package/dist/ui/primitives/button-variants.js.map +1 -0
- package/dist/ui/primitives/button.d.ts +3 -6
- package/dist/ui/primitives/button.d.ts.map +1 -1
- package/dist/ui/primitives/button.js +2 -24
- package/dist/ui/primitives/button.js.map +1 -1
- package/dist/ui/primitives/form-stepper.d.ts +1 -13
- package/dist/ui/primitives/form-stepper.d.ts.map +1 -1
- package/dist/ui/primitives/form-stepper.js +1 -6
- package/dist/ui/primitives/form-stepper.js.map +1 -1
- package/dist/ui/primitives/form-stepper.types.d.ts +14 -0
- package/dist/ui/primitives/form-stepper.types.d.ts.map +1 -0
- package/dist/ui/primitives/form-stepper.types.js +7 -0
- package/dist/ui/primitives/form-stepper.types.js.map +1 -0
- package/dist/ui/primitives/preview-device-frame.js +1 -1
- package/dist/ui/primitives/preview-device-frame.js.map +1 -1
- package/dist/ui/primitives/tag-multi-select.d.ts.map +1 -1
- package/dist/ui/primitives/tag-multi-select.js +1 -1
- package/dist/ui/primitives/tag-multi-select.js.map +1 -1
- package/dist/vista/index.d.ts +4 -0
- package/dist/vista/index.d.ts.map +1 -1
- package/dist/vista/index.js +4 -0
- package/dist/vista/index.js.map +1 -1
- package/dist/vista/surfaces/FilesSurface.d.ts +1 -12
- package/dist/vista/surfaces/FilesSurface.d.ts.map +1 -1
- package/dist/vista/surfaces/FilesSurface.js +2 -46
- package/dist/vista/surfaces/FilesSurface.js.map +1 -1
- package/dist/vista/surfaces/FormSurface.d.ts.map +1 -1
- package/dist/vista/surfaces/FormSurface.js +39 -12
- package/dist/vista/surfaces/FormSurface.js.map +1 -1
- package/dist/vista/surfaces/elicitation-transport.d.ts +12 -3
- package/dist/vista/surfaces/elicitation-transport.d.ts.map +1 -1
- package/dist/vista/surfaces/elicitation-transport.js +96 -3
- package/dist/vista/surfaces/elicitation-transport.js.map +1 -1
- package/dist/vista/surfaces/file-surface-utils.d.ts +13 -0
- package/dist/vista/surfaces/file-surface-utils.d.ts.map +1 -0
- package/dist/vista/surfaces/file-surface-utils.js +46 -0
- package/dist/vista/surfaces/file-surface-utils.js.map +1 -0
- package/dist/vista/surfaces/index.d.ts +4 -3
- package/dist/vista/surfaces/index.d.ts.map +1 -1
- package/dist/vista/surfaces/index.js +4 -81
- package/dist/vista/surfaces/index.js.map +1 -1
- package/dist/vista/surfaces/register-surfaces.d.ts +2 -0
- package/dist/vista/surfaces/register-surfaces.d.ts.map +1 -0
- package/dist/vista/surfaces/register-surfaces.js +80 -0
- package/dist/vista/surfaces/register-surfaces.js.map +1 -0
- package/dist/vista/surfaces/text-surfaces.js +1 -1
- package/dist/vista/surfaces/text-surfaces.js.map +1 -1
- package/dist/vista/vista-code-renderer-context.d.ts +9 -0
- package/dist/vista/vista-code-renderer-context.d.ts.map +1 -0
- package/dist/vista/vista-code-renderer-context.js +6 -0
- package/dist/vista/vista-code-renderer-context.js.map +1 -0
- package/dist/vista/vista-code-renderer.d.ts +1 -6
- package/dist/vista/vista-code-renderer.d.ts.map +1 -1
- package/dist/vista/vista-code-renderer.js +1 -5
- package/dist/vista/vista-code-renderer.js.map +1 -1
- package/dist/vista/vista-file-context.d.ts +8 -0
- package/dist/vista/vista-file-context.d.ts.map +1 -0
- package/dist/vista/vista-file-context.js +6 -0
- package/dist/vista/vista-file-context.js.map +1 -0
- package/dist/vista/vista-file-source.d.ts +1 -6
- package/dist/vista/vista-file-source.d.ts.map +1 -1
- package/dist/vista/vista-file-source.js +2 -5
- package/dist/vista/vista-file-source.js.map +1 -1
- package/dist/vista/vista-form-context.d.ts +13 -0
- package/dist/vista/vista-form-context.d.ts.map +1 -0
- package/dist/vista/vista-form-context.js +6 -0
- package/dist/vista/vista-form-context.js.map +1 -0
- package/dist/vista/vista-form-host.d.ts +1 -10
- package/dist/vista/vista-form-host.d.ts.map +1 -1
- package/dist/vista/vista-form-host.js +1 -5
- package/dist/vista/vista-form-host.js.map +1 -1
- package/dist/vista/vista-open-context.d.ts +1 -3
- package/dist/vista/vista-open-context.d.ts.map +1 -1
- package/dist/vista/vista-open-context.js +1 -5
- package/dist/vista/vista-open-context.js.map +1 -1
- package/dist/vista/vista-open-state.d.ts +5 -0
- package/dist/vista/vista-open-state.d.ts.map +1 -0
- package/dist/vista/vista-open-state.js +6 -0
- package/dist/vista/vista-open-state.js.map +1 -0
- package/dist/vista/vista-payloads.d.ts +2 -3
- package/dist/vista/vista-payloads.d.ts.map +1 -1
- package/dist/vista/vista-payloads.js +18 -21
- package/dist/vista/vista-payloads.js.map +1 -1
- package/dist/vista/vista-tools.d.ts.map +1 -1
- package/dist/vista/vista-tools.js.map +1 -1
- package/package.json +3 -3
- package/src/lib/biome-host/biome-builders.ts +4 -1
- package/src/lib/biome-host/biome-registry.ts +0 -1
- package/src/lib/biome-host/biome-scope-hooks.ts +39 -0
- package/src/lib/biome-host/biome-scope.tsx +1 -68
- package/src/lib/biome-host/biome-scoped-query.ts +4 -1
- package/src/lib/biome-host/create-biome-orval-config.ts +2 -2
- package/src/lib/biome-host/errors.ts +1 -1
- package/src/lib/biome-host/index.ts +1 -2
- package/src/lib/biome-host/session-contributions.ts +21 -18
- package/src/lib/capabilities/capability-context.ts +25 -0
- package/src/lib/capabilities/capability-provider.tsx +5 -34
- package/src/lib/capabilities/index.ts +1 -0
- package/src/lib/capabilities/use-capability.ts +4 -1
- package/src/lib/system-bus/deeplink.ts +1 -1
- package/src/lib/system-bus/host-ports.ts +2 -1
- package/src/lib/system-bus/intent-registry.ts +1 -2
- package/src/offline/index.ts +4 -2
- package/src/offline/offline-status-badge.tsx +1 -1
- package/src/offline/outbox.test.ts +23 -16
- package/src/offline/outbox.ts +1 -1
- package/src/offline/react-hooks.ts +37 -0
- package/src/offline/react.tsx +1 -40
- package/src/offline/storage.ts +11 -6
- package/src/registry/index.ts +1 -0
- package/src/registry/lib/primitives/SessionEventCard.tsx +4 -2
- package/src/registry/lib/session-context-builder.ts +33 -17
- package/src/registry/lib/session-context-provider.tsx +8 -25
- package/src/registry/lib/session-context.ts +21 -0
- package/src/registry/lib/session-selectors.ts +3 -1
- package/src/ui/branding/app-branding-context.ts +20 -0
- package/src/ui/branding/app-branding-provider.tsx +5 -27
- package/src/ui/capture/schema-field-input.tsx +7 -1
- package/src/ui/capture/use-prefill.ts +4 -1
- package/src/ui/capture/use-wizard.ts +2 -2
- package/src/ui/capture/wizard.tsx +2 -1
- package/src/ui/index.ts +7 -2
- package/src/ui/primitives/alert-dialog.tsx +1 -1
- package/src/ui/primitives/badge-variants.ts +21 -0
- package/src/ui/primitives/badge.tsx +3 -19
- package/src/ui/primitives/button-variants.ts +31 -0
- package/src/ui/primitives/button.tsx +3 -28
- package/src/ui/primitives/form-stepper.tsx +1 -16
- package/src/ui/primitives/form-stepper.types.ts +15 -0
- package/src/ui/primitives/preview-device-frame.tsx +1 -1
- package/src/ui/primitives/tag-multi-select.tsx +3 -4
- package/src/vista/form-payload.spec.ts +71 -25
- package/src/vista/index.ts +4 -0
- package/src/vista/surfaces/FilesSurface.tsx +2 -68
- package/src/vista/surfaces/FormSurface.tsx +125 -26
- package/src/vista/surfaces/elicitation-transport.spec.ts +205 -23
- package/src/vista/surfaces/elicitation-transport.ts +192 -14
- package/src/vista/surfaces/file-surface-utils.ts +62 -0
- package/src/vista/surfaces/index.ts +24 -0
- package/src/vista/surfaces/{index.tsx → register-surfaces.tsx} +1 -21
- package/src/vista/surfaces/text-surfaces.tsx +1 -1
- package/src/vista/vista-code-renderer-context.ts +16 -0
- package/src/vista/vista-code-renderer.tsx +4 -16
- package/src/vista/vista-file-context.ts +14 -0
- package/src/vista/vista-file-source.tsx +5 -28
- package/src/vista/vista-form-context.ts +20 -0
- package/src/vista/vista-form-host.tsx +11 -36
- package/src/vista/vista-open-context.tsx +4 -14
- package/src/vista/vista-open-state.ts +11 -0
- package/src/vista/vista-payloads.ts +44 -46
- package/src/vista/vista-tools.ts +2 -2
- package/dist/lib/biome-host/response-envelope.d.ts +0 -3
- package/dist/lib/biome-host/response-envelope.d.ts.map +0 -1
- package/dist/lib/biome-host/response-envelope.js +0 -21
- package/dist/lib/biome-host/response-envelope.js.map +0 -1
- package/dist/lib/biome-host/session-profiles.d.ts +0 -18
- package/dist/lib/biome-host/session-profiles.d.ts.map +0 -1
- package/dist/lib/biome-host/session-profiles.js +0 -35
- package/dist/lib/biome-host/session-profiles.js.map +0 -1
- package/src/lib/biome-host/response-envelope.ts +0 -69
- package/src/lib/biome-host/session-profiles.ts +0 -99
|
@@ -3,6 +3,7 @@ import type {
|
|
|
3
3
|
CapabilityInvokeMeta,
|
|
4
4
|
CapabilityInvokeResult,
|
|
5
5
|
} from './capability-invoke';
|
|
6
|
+
import type { ParsedDeeplink } from './deeplink';
|
|
6
7
|
import type { PaletteEntry, PaletteQuery } from './palette';
|
|
7
8
|
import type {
|
|
8
9
|
OpenWindowRequest,
|
|
@@ -92,5 +93,5 @@ export interface WindowManager {
|
|
|
92
93
|
* window) — fail-fast, never a silent no-op.
|
|
93
94
|
*/
|
|
94
95
|
export interface DeeplinkResolver {
|
|
95
|
-
resolve(target:
|
|
96
|
+
resolve(target: ParsedDeeplink): Promise<void>;
|
|
96
97
|
}
|
|
@@ -5,7 +5,6 @@ import {
|
|
|
5
5
|
} from '@xemahq/kernel-contracts/object';
|
|
6
6
|
import { ActionRefKind } from './enums';
|
|
7
7
|
import type {
|
|
8
|
-
ActionRef,
|
|
9
8
|
IntentBus,
|
|
10
9
|
IntentRegistration,
|
|
11
10
|
ResolvedIntent,
|
|
@@ -24,7 +23,7 @@ function assertValidRegistration(registration: IntentRegistration): void {
|
|
|
24
23
|
if (!VALID_ACTION_KINDS.has(action.kind)) {
|
|
25
24
|
throw new Error(
|
|
26
25
|
`[xema-ui-kernel] IntentRegistration from "${registration.biomeId}" ` +
|
|
27
|
-
`has an ActionRef with unknown kind "${
|
|
26
|
+
`has an ActionRef with unknown kind "${action.kind}". ` +
|
|
28
27
|
`Expected one of: ${[...VALID_ACTION_KINDS].join(', ')}.`,
|
|
29
28
|
);
|
|
30
29
|
}
|
package/src/offline/index.ts
CHANGED
|
@@ -41,11 +41,13 @@ export {
|
|
|
41
41
|
} from './mutation';
|
|
42
42
|
export {
|
|
43
43
|
OutboxProvider,
|
|
44
|
+
type OutboxProviderProps,
|
|
45
|
+
} from './react';
|
|
46
|
+
export {
|
|
44
47
|
useOutbox,
|
|
45
48
|
useOutboxSnapshot,
|
|
46
49
|
useOnlineStatus,
|
|
47
|
-
|
|
48
|
-
} from './react';
|
|
50
|
+
} from './react-hooks';
|
|
49
51
|
export {
|
|
50
52
|
OfflineStatusBadge,
|
|
51
53
|
type OfflineStatusBadgeProps,
|
|
@@ -25,7 +25,7 @@ function makeOutbox(overrides: Partial<OutboxOptions> = {}): {
|
|
|
25
25
|
describe('Outbox', () => {
|
|
26
26
|
it('queues while offline and delivers on reconnect', async () => {
|
|
27
27
|
const { outbox, online } = makeOutbox();
|
|
28
|
-
const send = vi.fn(
|
|
28
|
+
const send = vi.fn(() => Promise.resolve());
|
|
29
29
|
outbox.registerExecutor(KIND, send);
|
|
30
30
|
|
|
31
31
|
online.reportOffline();
|
|
@@ -42,8 +42,9 @@ describe('Outbox', () => {
|
|
|
42
42
|
it('delivers immediately when online and removes the entry; idempotency key is stable', async () => {
|
|
43
43
|
const { outbox } = makeOutbox();
|
|
44
44
|
const keys: string[] = [];
|
|
45
|
-
outbox.registerExecutor(KIND,
|
|
45
|
+
outbox.registerExecutor(KIND, (_p, ctx: OutboxExecuteContext) => {
|
|
46
46
|
keys.push(ctx.idempotencyKey);
|
|
47
|
+
return Promise.resolve();
|
|
47
48
|
});
|
|
48
49
|
await outbox.enqueue(KIND, { a: 1 });
|
|
49
50
|
await outbox.drain();
|
|
@@ -55,11 +56,12 @@ describe('Outbox', () => {
|
|
|
55
56
|
it('retries a 5xx and eventually succeeds', async () => {
|
|
56
57
|
const { outbox } = makeOutbox();
|
|
57
58
|
let calls = 0;
|
|
58
|
-
outbox.registerExecutor(KIND,
|
|
59
|
+
outbox.registerExecutor(KIND, () => {
|
|
59
60
|
calls += 1;
|
|
60
61
|
if (calls < 3) {
|
|
61
|
-
|
|
62
|
+
return Promise.reject({ status: 503, message: 'unavailable' });
|
|
62
63
|
}
|
|
64
|
+
return Promise.resolve();
|
|
63
65
|
});
|
|
64
66
|
await outbox.enqueue(KIND, { a: 1 });
|
|
65
67
|
await outbox.drain();
|
|
@@ -69,29 +71,29 @@ describe('Outbox', () => {
|
|
|
69
71
|
|
|
70
72
|
it('dead-letters a 4xx immediately (no pointless retries)', async () => {
|
|
71
73
|
const { outbox } = makeOutbox();
|
|
72
|
-
const send = vi.fn(
|
|
73
|
-
|
|
74
|
-
|
|
74
|
+
const send = vi.fn(() =>
|
|
75
|
+
Promise.reject({ status: 400, message: 'bad request' }),
|
|
76
|
+
);
|
|
75
77
|
outbox.registerExecutor(KIND, send);
|
|
76
78
|
await outbox.enqueue(KIND, { a: 1 });
|
|
77
79
|
await outbox.drain();
|
|
78
80
|
expect(send).toHaveBeenCalledTimes(1);
|
|
79
81
|
const snap = outbox.getSnapshot();
|
|
80
82
|
expect(snap.failedCount).toBe(1);
|
|
81
|
-
expect(snap.entries[0]
|
|
83
|
+
expect(snap.entries[0].status).toBe(OutboxEntryStatus.Failed);
|
|
82
84
|
});
|
|
83
85
|
|
|
84
86
|
it('dead-letters after exhausting retries on persistent 5xx', async () => {
|
|
85
87
|
const { outbox } = makeOutbox({ maxAttempts: 3 });
|
|
86
88
|
let calls = 0;
|
|
87
|
-
outbox.registerExecutor(KIND,
|
|
89
|
+
outbox.registerExecutor(KIND, () => {
|
|
88
90
|
calls += 1;
|
|
89
|
-
|
|
91
|
+
return Promise.reject({ status: 503 });
|
|
90
92
|
});
|
|
91
93
|
await outbox.enqueue(KIND, { a: 1 });
|
|
92
94
|
await outbox.drain();
|
|
93
95
|
expect(calls).toBe(3);
|
|
94
|
-
expect(outbox.getSnapshot().entries[0]
|
|
96
|
+
expect(outbox.getSnapshot().entries[0].status).toBe(OutboxEntryStatus.Failed);
|
|
95
97
|
});
|
|
96
98
|
|
|
97
99
|
it('a network failure never advances the attempt counter or dead-letters', async () => {
|
|
@@ -99,15 +101,19 @@ describe('Outbox', () => {
|
|
|
99
101
|
const timers: Array<() => void> = [];
|
|
100
102
|
const { outbox } = makeOutbox({ scheduler: (fn) => void timers.push(fn) });
|
|
101
103
|
let succeed = false;
|
|
102
|
-
outbox.registerExecutor(KIND,
|
|
104
|
+
outbox.registerExecutor(KIND, () => {
|
|
103
105
|
if (!succeed) {
|
|
104
|
-
|
|
106
|
+
return Promise.reject({
|
|
107
|
+
name: 'TypeError',
|
|
108
|
+
message: 'Failed to fetch',
|
|
109
|
+
});
|
|
105
110
|
}
|
|
111
|
+
return Promise.resolve();
|
|
106
112
|
});
|
|
107
113
|
|
|
108
114
|
await outbox.enqueue(KIND, { a: 1 });
|
|
109
115
|
await outbox.drain();
|
|
110
|
-
const parked = outbox.getSnapshot().entries[0]
|
|
116
|
+
const parked = outbox.getSnapshot().entries[0];
|
|
111
117
|
expect(parked.status).toBe(OutboxEntryStatus.Pending);
|
|
112
118
|
expect(parked.attempts).toBe(0); // offline is not the payload's fault
|
|
113
119
|
expect(outbox.getSnapshot().failedCount).toBe(0);
|
|
@@ -121,8 +127,9 @@ describe('Outbox', () => {
|
|
|
121
127
|
it('delivers queued entries in FIFO order', async () => {
|
|
122
128
|
const { outbox, online } = makeOutbox();
|
|
123
129
|
const order: number[] = [];
|
|
124
|
-
outbox.registerExecutor(KIND,
|
|
130
|
+
outbox.registerExecutor(KIND, (p: { n: number }) => {
|
|
125
131
|
order.push(p.n);
|
|
132
|
+
return Promise.resolve();
|
|
126
133
|
});
|
|
127
134
|
online.reportOffline();
|
|
128
135
|
await outbox.enqueue(KIND, { n: 1 });
|
|
@@ -150,7 +157,7 @@ describe('Outbox', () => {
|
|
|
150
157
|
online.reportOffline(); // keep it queued so we can observe the recovery
|
|
151
158
|
const outbox = new Outbox({ storage, online, scheduler: (fn) => fn() });
|
|
152
159
|
await outbox.start();
|
|
153
|
-
expect(outbox.getSnapshot().entries[0]
|
|
160
|
+
expect(outbox.getSnapshot().entries[0].status).toBe(OutboxEntryStatus.Pending);
|
|
154
161
|
outbox.stop();
|
|
155
162
|
});
|
|
156
163
|
});
|
package/src/offline/outbox.ts
CHANGED
|
@@ -159,7 +159,7 @@ export class Outbox {
|
|
|
159
159
|
updatedAt: ts,
|
|
160
160
|
...(opts.label !== undefined ? { label: opts.label } : {}),
|
|
161
161
|
};
|
|
162
|
-
await this.storage.put(entry
|
|
162
|
+
await this.storage.put(entry);
|
|
163
163
|
await this.refresh();
|
|
164
164
|
void this.drain();
|
|
165
165
|
return entry;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { createContext, useContext, useSyncExternalStore } from 'react';
|
|
2
|
+
|
|
3
|
+
import { Outbox } from './outbox';
|
|
4
|
+
|
|
5
|
+
import type { OutboxSnapshot } from './types';
|
|
6
|
+
|
|
7
|
+
export const OutboxContext = createContext<Outbox | null>(null);
|
|
8
|
+
|
|
9
|
+
export function useOutbox(): Outbox {
|
|
10
|
+
const ctx = useContext(OutboxContext);
|
|
11
|
+
if (!ctx) {
|
|
12
|
+
throw new Error('useOutbox must be used within an <OutboxProvider>.');
|
|
13
|
+
}
|
|
14
|
+
return ctx;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function resolveOutbox(explicit: Outbox | undefined, ctx: Outbox | null): Outbox {
|
|
18
|
+
const instance = explicit ?? ctx;
|
|
19
|
+
if (!instance) {
|
|
20
|
+
throw new Error('An <OutboxProvider> or an explicit outbox is required.');
|
|
21
|
+
}
|
|
22
|
+
return instance;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function useOutboxSnapshot(outbox?: Outbox): OutboxSnapshot {
|
|
26
|
+
const ctx = useContext(OutboxContext);
|
|
27
|
+
const instance = resolveOutbox(outbox, ctx);
|
|
28
|
+
return useSyncExternalStore(
|
|
29
|
+
(cb) => instance.subscribe(cb),
|
|
30
|
+
() => instance.getSnapshot(),
|
|
31
|
+
() => instance.getSnapshot(),
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function useOnlineStatus(outbox?: Outbox): boolean {
|
|
36
|
+
return useOutboxSnapshot(outbox).online;
|
|
37
|
+
}
|
package/src/offline/react.tsx
CHANGED
|
@@ -1,18 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
|
-
createContext,
|
|
3
|
-
useContext,
|
|
4
2
|
useEffect,
|
|
5
3
|
useMemo,
|
|
6
4
|
useRef,
|
|
7
|
-
useSyncExternalStore,
|
|
8
5
|
type ReactNode,
|
|
9
6
|
} from 'react';
|
|
10
7
|
|
|
11
8
|
import { Outbox, type OutboxOptions } from './outbox';
|
|
12
|
-
|
|
13
|
-
import type { OutboxSnapshot } from './types';
|
|
14
|
-
|
|
15
|
-
const OutboxContext = createContext<Outbox | null>(null);
|
|
9
|
+
import { OutboxContext } from './react-hooks';
|
|
16
10
|
|
|
17
11
|
export interface OutboxProviderProps {
|
|
18
12
|
/** Bring your own Outbox, or let the provider create one from `options`. */
|
|
@@ -36,36 +30,3 @@ export function OutboxProvider({ outbox, options, children }: OutboxProviderProp
|
|
|
36
30
|
|
|
37
31
|
return <OutboxContext.Provider value={instance}>{children}</OutboxContext.Provider>;
|
|
38
32
|
}
|
|
39
|
-
|
|
40
|
-
export function useOutbox(): Outbox {
|
|
41
|
-
const ctx = useContext(OutboxContext);
|
|
42
|
-
if (!ctx) {
|
|
43
|
-
throw new Error('useOutbox must be used within an <OutboxProvider>.');
|
|
44
|
-
}
|
|
45
|
-
return ctx;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
function resolveOutbox(explicit: Outbox | undefined, ctx: Outbox | null): Outbox {
|
|
49
|
-
const instance = explicit ?? ctx;
|
|
50
|
-
if (!instance) {
|
|
51
|
-
throw new Error('An <OutboxProvider> or an explicit outbox is required.');
|
|
52
|
-
}
|
|
53
|
-
return instance;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/** Subscribe to the outbox state (offline badge, pending count, dead-letter
|
|
57
|
-
* list). Re-renders only when the snapshot changes. */
|
|
58
|
-
export function useOutboxSnapshot(outbox?: Outbox): OutboxSnapshot {
|
|
59
|
-
const ctx = useContext(OutboxContext);
|
|
60
|
-
const instance = resolveOutbox(outbox, ctx);
|
|
61
|
-
return useSyncExternalStore(
|
|
62
|
-
(cb) => instance.subscribe(cb),
|
|
63
|
-
() => instance.getSnapshot(),
|
|
64
|
-
() => instance.getSnapshot(),
|
|
65
|
-
);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/** Current connectivity as tracked by the outbox. */
|
|
69
|
-
export function useOnlineStatus(outbox?: Outbox): boolean {
|
|
70
|
-
return useOutboxSnapshot(outbox).online;
|
|
71
|
-
}
|
package/src/offline/storage.ts
CHANGED
|
@@ -4,20 +4,25 @@ import type { OutboxEntry, OutboxStorage } from './types';
|
|
|
4
4
|
export class InMemoryOutboxStorage implements OutboxStorage {
|
|
5
5
|
private readonly map = new Map<string, OutboxEntry>();
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
return
|
|
7
|
+
getAll(): Promise<OutboxEntry[]> {
|
|
8
|
+
return Promise.resolve(
|
|
9
|
+
[...this.map.values()].sort((a, b) => a.createdAt - b.createdAt),
|
|
10
|
+
);
|
|
9
11
|
}
|
|
10
12
|
|
|
11
|
-
|
|
13
|
+
put(entry: OutboxEntry): Promise<void> {
|
|
12
14
|
this.map.set(entry.id, { ...entry });
|
|
15
|
+
return Promise.resolve();
|
|
13
16
|
}
|
|
14
17
|
|
|
15
|
-
|
|
18
|
+
delete(id: string): Promise<void> {
|
|
16
19
|
this.map.delete(id);
|
|
20
|
+
return Promise.resolve();
|
|
17
21
|
}
|
|
18
22
|
|
|
19
|
-
|
|
23
|
+
clear(): Promise<void> {
|
|
20
24
|
this.map.clear();
|
|
25
|
+
return Promise.resolve();
|
|
21
26
|
}
|
|
22
27
|
}
|
|
23
28
|
|
|
@@ -69,7 +74,7 @@ export class IndexedDbOutboxStorage implements OutboxStorage {
|
|
|
69
74
|
transaction.onabort = () =>
|
|
70
75
|
reject(transaction.error ?? new Error('indexedDB tx aborted'));
|
|
71
76
|
transaction.oncomplete = () =>
|
|
72
|
-
resolve(request ?
|
|
77
|
+
resolve(request ? request.result : undefined);
|
|
73
78
|
transaction.onerror = () =>
|
|
74
79
|
reject(transaction.error ?? new Error('indexedDB tx error'));
|
|
75
80
|
});
|
package/src/registry/index.ts
CHANGED
|
@@ -4,5 +4,6 @@ export * from './lib/biome-slot';
|
|
|
4
4
|
export * from './lib/biomes-enabled-context';
|
|
5
5
|
export * from './lib/session-selectors';
|
|
6
6
|
export * from './lib/session-context-builder';
|
|
7
|
+
export * from './lib/session-context';
|
|
7
8
|
export * from './lib/session-context-provider';
|
|
8
9
|
export * from './lib/primitives';
|
|
@@ -125,13 +125,15 @@ export function SessionEventCard({
|
|
|
125
125
|
<span style={{ color: 'hsl(var(--ink, 228 14% 11%))', wordBreak: 'break-word' }}>
|
|
126
126
|
{title}
|
|
127
127
|
</span>
|
|
128
|
-
{detail
|
|
128
|
+
{detail !== null && detail !== undefined && (
|
|
129
129
|
<span style={{ color: 'hsl(var(--ink-3, 228 6% 40%))', wordBreak: 'break-word' }}>
|
|
130
130
|
{detail}
|
|
131
131
|
</span>
|
|
132
132
|
)}
|
|
133
133
|
</div>
|
|
134
|
-
{children
|
|
134
|
+
{children !== null && children !== undefined && (
|
|
135
|
+
<div style={{ marginTop: 4 }}>{children}</div>
|
|
136
|
+
)}
|
|
135
137
|
</div>
|
|
136
138
|
</div>
|
|
137
139
|
);
|
|
@@ -2,11 +2,9 @@
|
|
|
2
2
|
* Single helper hook the host's session shell calls once per render to
|
|
3
3
|
* build the `SessionContext` it passes into every contribution selector.
|
|
4
4
|
*
|
|
5
|
-
* Inputs are the
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* `SessionContext`. Memoised by the underlying selectors — callers can
|
|
9
|
-
* pass the result as a dep without worrying about identity churn.
|
|
5
|
+
* Inputs are the host's session fields plus the resolved Agent projection.
|
|
6
|
+
* The helper freezes capability refs and returns a stable `SessionContext`.
|
|
7
|
+
* It never fabricates a profile or capability fallback.
|
|
10
8
|
*
|
|
11
9
|
* Keeping this helper in the SDK (rather than the host) is what lets
|
|
12
10
|
* biomes also build a context — e.g. from inside a slash command
|
|
@@ -14,17 +12,23 @@
|
|
|
14
12
|
*/
|
|
15
13
|
import { useMemo } from 'react';
|
|
16
14
|
|
|
17
|
-
import {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
import type { SessionContext } from '../../index';
|
|
16
|
+
|
|
17
|
+
export interface SessionResolvedAgentInput {
|
|
18
|
+
readonly ref: string;
|
|
19
|
+
readonly requiredCapabilities: readonly string[];
|
|
20
|
+
readonly mayEditRepositories: boolean;
|
|
21
|
+
readonly mayWriteKnowledgeBase: boolean;
|
|
22
|
+
readonly hasOutputSurface: boolean;
|
|
23
|
+
}
|
|
21
24
|
|
|
22
25
|
export interface BuildSessionContextInput {
|
|
23
26
|
readonly sessionId: string;
|
|
24
27
|
readonly orgId: string;
|
|
25
28
|
readonly projectId: string;
|
|
26
29
|
readonly biomeId?: string;
|
|
27
|
-
readonly
|
|
30
|
+
readonly repositoryId?: string;
|
|
31
|
+
readonly agent?: SessionResolvedAgentInput;
|
|
28
32
|
readonly status: string;
|
|
29
33
|
readonly isActive: boolean;
|
|
30
34
|
}
|
|
@@ -41,17 +45,29 @@ export function isStatusActive(status: string): boolean {
|
|
|
41
45
|
return !TERMINAL_STATUSES.has(status);
|
|
42
46
|
}
|
|
43
47
|
|
|
44
|
-
export function useSessionContext(
|
|
45
|
-
|
|
48
|
+
export function useSessionContext(
|
|
49
|
+
input: BuildSessionContextInput,
|
|
50
|
+
): SessionContext {
|
|
46
51
|
return useMemo<SessionContext>(
|
|
47
52
|
() => ({
|
|
48
53
|
sessionId: input.sessionId,
|
|
49
54
|
orgId: input.orgId,
|
|
50
55
|
projectId: input.projectId,
|
|
51
|
-
biomeId: input.biomeId
|
|
52
|
-
|
|
56
|
+
...(input.biomeId !== undefined ? { biomeId: input.biomeId } : {}),
|
|
57
|
+
...(input.repositoryId !== undefined
|
|
58
|
+
? { repositoryId: input.repositoryId }
|
|
59
|
+
: {}),
|
|
60
|
+
...(input.agent !== undefined
|
|
61
|
+
? {
|
|
62
|
+
agent: {
|
|
63
|
+
...input.agent,
|
|
64
|
+
requiredCapabilities: Object.freeze(
|
|
65
|
+
new Set(input.agent.requiredCapabilities),
|
|
66
|
+
),
|
|
67
|
+
},
|
|
68
|
+
}
|
|
69
|
+
: {}),
|
|
53
70
|
status: input.status,
|
|
54
|
-
capabilities: Object.freeze(new Set(descriptor.capabilities)),
|
|
55
71
|
isActive: input.isActive,
|
|
56
72
|
}),
|
|
57
73
|
[
|
|
@@ -59,10 +75,10 @@ export function useSessionContext(input: BuildSessionContextInput): SessionConte
|
|
|
59
75
|
input.orgId,
|
|
60
76
|
input.projectId,
|
|
61
77
|
input.biomeId,
|
|
62
|
-
input.
|
|
78
|
+
input.repositoryId,
|
|
79
|
+
input.agent,
|
|
63
80
|
input.status,
|
|
64
81
|
input.isActive,
|
|
65
|
-
descriptor,
|
|
66
82
|
],
|
|
67
83
|
);
|
|
68
84
|
}
|
|
@@ -10,12 +10,11 @@
|
|
|
10
10
|
* stable, importable hook — `import { useCurrentSessionContext } from
|
|
11
11
|
* '@xemahq/ui-kernel/registry'`.
|
|
12
12
|
*/
|
|
13
|
-
import
|
|
13
|
+
import type { ReactElement, ReactNode } from 'react';
|
|
14
14
|
|
|
15
|
-
import
|
|
15
|
+
import { SessionContextValue } from './session-context';
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
Ctx.displayName = 'SessionContext';
|
|
17
|
+
import type { SessionContext } from '../../index';
|
|
19
18
|
|
|
20
19
|
export interface SessionContextProviderProps {
|
|
21
20
|
readonly value: SessionContext;
|
|
@@ -26,25 +25,9 @@ export function SessionContextProvider({
|
|
|
26
25
|
value,
|
|
27
26
|
children,
|
|
28
27
|
}: SessionContextProviderProps): ReactElement {
|
|
29
|
-
return
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
if (!ctx) {
|
|
35
|
-
throw new Error(
|
|
36
|
-
'[biome-registry-web] useCurrentSessionContext() called outside <SessionContextProvider>. ' +
|
|
37
|
-
'The host shell must wrap session UI with the provider before any biome reads it.',
|
|
38
|
-
);
|
|
39
|
-
}
|
|
40
|
-
return ctx;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Non-throwing variant for components that may render outside a session
|
|
45
|
-
* context (e.g. shared primitives reused on the design-system-builder page).
|
|
46
|
-
* Returns `null` instead of throwing.
|
|
47
|
-
*/
|
|
48
|
-
export function useOptionalSessionContext(): SessionContext | null {
|
|
49
|
-
return useContext(Ctx);
|
|
28
|
+
return (
|
|
29
|
+
<SessionContextValue.Provider value={value}>
|
|
30
|
+
{children}
|
|
31
|
+
</SessionContextValue.Provider>
|
|
32
|
+
);
|
|
50
33
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { createContext, useContext } from 'react';
|
|
2
|
+
|
|
3
|
+
import type { SessionContext } from '../../index';
|
|
4
|
+
|
|
5
|
+
export const SessionContextValue = createContext<SessionContext | null>(null);
|
|
6
|
+
SessionContextValue.displayName = 'SessionContext';
|
|
7
|
+
|
|
8
|
+
export function useCurrentSessionContext(): SessionContext {
|
|
9
|
+
const ctx = useContext(SessionContextValue);
|
|
10
|
+
if (!ctx) {
|
|
11
|
+
throw new Error(
|
|
12
|
+
'[biome-registry-web] useCurrentSessionContext() called outside <SessionContextProvider>. ' +
|
|
13
|
+
'The host shell must wrap session UI with the provider before any biome reads it.',
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
return ctx;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function useOptionalSessionContext(): SessionContext | null {
|
|
20
|
+
return useContext(SessionContextValue);
|
|
21
|
+
}
|
|
@@ -52,7 +52,9 @@ function applies<T extends { readonly appliesTo?: (...args: never[]) => boolean
|
|
|
52
52
|
args: Parameters<PredicateOf<T>>,
|
|
53
53
|
): boolean {
|
|
54
54
|
const predicate = item.appliesTo as PredicateOf<T> | undefined;
|
|
55
|
-
return predicate
|
|
55
|
+
return predicate === null || predicate === undefined
|
|
56
|
+
? true
|
|
57
|
+
: predicate(...args);
|
|
56
58
|
}
|
|
57
59
|
|
|
58
60
|
// ── Slash commands ────────────────────────────────────────────────────
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
export interface AppBrandingContextValue {
|
|
4
|
+
readonly displayName: string;
|
|
5
|
+
readonly logoUrl?: string;
|
|
6
|
+
readonly primaryColor?: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const AppBrandingContext =
|
|
10
|
+
React.createContext<AppBrandingContextValue | null>(null);
|
|
11
|
+
|
|
12
|
+
export function useAppBranding(): AppBrandingContextValue {
|
|
13
|
+
const ctx = React.useContext(AppBrandingContext);
|
|
14
|
+
if (ctx === null) {
|
|
15
|
+
throw new Error(
|
|
16
|
+
'useAppBranding must be used within an <AppBrandingProvider>.',
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
return ctx;
|
|
20
|
+
}
|
|
@@ -23,6 +23,10 @@ import * as React from 'react';
|
|
|
23
23
|
import type { BrandingConfig } from '@xemahq/kernel-contracts/app-platform';
|
|
24
24
|
|
|
25
25
|
import { cn } from '../cn';
|
|
26
|
+
import {
|
|
27
|
+
AppBrandingContext,
|
|
28
|
+
type AppBrandingContextValue,
|
|
29
|
+
} from './app-branding-context';
|
|
26
30
|
|
|
27
31
|
import {
|
|
28
32
|
sanitizeCssCustomPropertyName,
|
|
@@ -33,32 +37,6 @@ import {
|
|
|
33
37
|
/** CSS custom property carrying the app's resolved primary brand color. */
|
|
34
38
|
export const APP_PRIMARY_COLOR_VAR = '--app-primary-color';
|
|
35
39
|
|
|
36
|
-
/** Values a branded header needs — sanitized, safe to render. */
|
|
37
|
-
export interface AppBrandingContextValue {
|
|
38
|
-
readonly displayName: string;
|
|
39
|
-
readonly logoUrl?: string;
|
|
40
|
-
readonly primaryColor?: string;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const AppBrandingContext = React.createContext<AppBrandingContextValue | null>(
|
|
44
|
-
null,
|
|
45
|
-
);
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Resolved branding for the nearest enclosing {@link AppBrandingProvider}.
|
|
49
|
-
* Throws when used outside one — a header that assumes branding must not
|
|
50
|
-
* silently render an unbranded surface.
|
|
51
|
-
*/
|
|
52
|
-
export function useAppBranding(): AppBrandingContextValue {
|
|
53
|
-
const ctx = React.useContext(AppBrandingContext);
|
|
54
|
-
if (ctx === null) {
|
|
55
|
-
throw new Error(
|
|
56
|
-
'useAppBranding must be used within an <AppBrandingProvider>.',
|
|
57
|
-
);
|
|
58
|
-
}
|
|
59
|
-
return ctx;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
40
|
export interface AppBrandingProviderProps {
|
|
63
41
|
/** The app's base branding (from the App definition / release). */
|
|
64
42
|
readonly branding: BrandingConfig;
|
|
@@ -137,7 +115,7 @@ export function AppBrandingProvider({
|
|
|
137
115
|
className={cn(className)}
|
|
138
116
|
// Custom properties are not part of `React.CSSProperties`; the cast is
|
|
139
117
|
// the standard way to set `--*` vars inline.
|
|
140
|
-
style={cssVars
|
|
118
|
+
style={cssVars}
|
|
141
119
|
>
|
|
142
120
|
{children}
|
|
143
121
|
</div>
|
|
@@ -347,7 +347,13 @@ function AudioFieldInput({ value, onChange, disabled, path }: SchemaFieldInputPr
|
|
|
347
347
|
) : null}
|
|
348
348
|
</div>
|
|
349
349
|
{error ? <p className="text-body-2 text-destructive">{error}</p> : null}
|
|
350
|
-
{current && !recording ?
|
|
350
|
+
{current && !recording ? (
|
|
351
|
+
<Button asChild variant="outline" size="sm">
|
|
352
|
+
<a id={inputId} href={current} target="_blank" rel="noreferrer">
|
|
353
|
+
Open recorded audio
|
|
354
|
+
</a>
|
|
355
|
+
</Button>
|
|
356
|
+
) : null}
|
|
351
357
|
</div>
|
|
352
358
|
);
|
|
353
359
|
}
|
|
@@ -81,7 +81,10 @@ export function usePrefill<T extends CaptureValues = CaptureValues>(
|
|
|
81
81
|
|
|
82
82
|
const setValues = useCallback((updater: Partial<T> | ((prev: T) => T)) => {
|
|
83
83
|
setValuesState((prev) => {
|
|
84
|
-
const next =
|
|
84
|
+
const next =
|
|
85
|
+
typeof updater === 'function'
|
|
86
|
+
? updater(prev)
|
|
87
|
+
: { ...prev, ...updater };
|
|
85
88
|
const changed = new Set<string>();
|
|
86
89
|
for (const k of Object.keys(next)) {
|
|
87
90
|
if (next[k] !== prev[k]) {
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
9
9
|
import { useCallback, useMemo, useState } from 'react';
|
|
10
10
|
|
|
11
|
-
import { FormStepStatus } from '../primitives/form-stepper';
|
|
11
|
+
import { FormStepStatus } from '../primitives/form-stepper.types';
|
|
12
12
|
|
|
13
13
|
export interface WizardStepDef {
|
|
14
14
|
readonly key: string;
|
|
@@ -68,7 +68,7 @@ export function useWizard(options: UseWizardOptions): WizardApi {
|
|
|
68
68
|
|
|
69
69
|
const isControlled = step !== undefined;
|
|
70
70
|
const [internal, setInternal] = useState(() => clamp(initialStep));
|
|
71
|
-
const activeIndex = clamp(isControlled ?
|
|
71
|
+
const activeIndex = clamp(isControlled ? step : internal);
|
|
72
72
|
|
|
73
73
|
const gate = useCallback((i: number) => (canAdvance ? canAdvance(i) : true), [canAdvance]);
|
|
74
74
|
|
|
@@ -10,7 +10,8 @@ import { Children, isValidElement, type ReactElement, type ReactNode } from 'rea
|
|
|
10
10
|
|
|
11
11
|
import { cn } from '../cn';
|
|
12
12
|
import { Button } from '../primitives/button';
|
|
13
|
-
import { FormStepper
|
|
13
|
+
import { FormStepper } from '../primitives/form-stepper';
|
|
14
|
+
import type { FormStep } from '../primitives/form-stepper.types';
|
|
14
15
|
|
|
15
16
|
import type { WizardApi } from './use-wizard';
|
|
16
17
|
|