@altertable/data-app 0.63.0 → 0.65.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/AGENTS.md +3 -0
- package/CONTRIBUTING.md +4 -0
- package/README.md +1 -1
- package/dist/chunks/{contract-tkc552ze.js → contract-a061yj6r.js} +2 -2
- package/dist/chunks/contract-awa2d5b1.js +272 -0
- package/dist/chunks/contract-awa2d5b1.js.map +12 -0
- package/dist/chunks/{contract-zr3jd7mr.js → contract-g6hky7x6.js} +93 -72
- package/dist/chunks/contract-g6hky7x6.js.map +12 -0
- package/dist/chunks/{contract-8wdybxj7.js → contract-sm7j7k95.js} +110 -74
- package/dist/chunks/contract-sm7j7k95.js.map +14 -0
- package/dist/chunks/{contract-farfe948.js → contract-txjy0en2.js} +31 -31
- package/dist/chunks/contract-txjy0en2.js.map +10 -0
- package/dist/chunks/contract-wz59z8pq.js.map +2 -2
- package/dist/chunks/{contract-wd8qe3mt.js → contract-yxbjea23.js} +8 -6
- package/dist/chunks/contract-yxbjea23.js.map +12 -0
- package/dist/client/index.js +3 -3
- package/dist/core/appearance.js +4 -2
- package/dist/core/appearance.js.map +1 -1
- package/dist/core/contract.js +1 -1
- package/dist/embed/index.js +20 -10
- package/dist/embed/index.js.map +3 -3
- package/dist/react/embed/index.js +5 -2
- package/dist/react/embed/index.js.map +3 -3
- package/dist/react/index.js +726 -454
- package/dist/react/index.js.map +17 -14
- package/dist/types/client/iframe.d.ts +2 -0
- package/dist/types/client/index.d.ts +1 -0
- package/dist/types/client/logger.d.ts +6 -0
- package/dist/types/core/appearance.d.ts +12 -1
- package/dist/types/core/bridge-endpoint.d.ts +21 -0
- package/dist/types/core/bridge.d.ts +137 -16
- package/dist/types/core/config.d.ts +2 -1
- package/dist/types/core/logger.d.ts +12 -0
- package/dist/types/embed/host.d.ts +6 -2
- package/dist/types/embed/index.d.ts +1 -0
- package/dist/types/embed/source.d.ts +1 -1
- package/dist/types/react/embed/bridge.d.ts +1 -1
- package/dist/types/react/index.d.ts +1 -0
- package/dist/types/react/ui/AppToolbar.d.ts +3 -1
- package/dist/types/react/ui/DataApp.d.ts +6 -1
- package/dist/types/react/ui/ExportControl.d.ts +4 -0
- package/dist/types/react/ui/Toast.d.ts +8 -0
- package/dist/types/react/ui/csv-export.d.ts +19 -0
- package/dist/types/react/ui/icons.d.ts +1 -0
- package/dist/types/react/ui/useAppAppearance.d.ts +2 -2
- package/dist/worker.js +382 -79
- package/docs/app-authoring.md +30 -3
- package/docs/embed.md +1 -1
- package/docs/hosted-apps.md +2 -2
- package/docs/layout.md +31 -0
- package/docs/local-data-apps.md +1 -1
- package/docs/react.md +64 -2
- package/examples/starter-data-app/index.tsx +50 -32
- package/package.json +2 -1
- package/dist/chunks/contract-8q35dcyh.js +0 -9
- package/dist/chunks/contract-8q35dcyh.js.map +0 -10
- package/dist/chunks/contract-8wdybxj7.js.map +0 -13
- package/dist/chunks/contract-cxr9t12b.js +0 -18
- package/dist/chunks/contract-cxr9t12b.js.map +0 -10
- package/dist/chunks/contract-farfe948.js.map +0 -10
- package/dist/chunks/contract-wd8qe3mt.js.map +0 -11
- package/dist/chunks/contract-zr3jd7mr.js.map +0 -12
- /package/dist/chunks/{contract-tkc552ze.js.map → contract-a061yj6r.js.map} +0 -0
|
@@ -8,6 +8,7 @@ export declare function createIframeTransport({ parentOrigin, window: frame, tim
|
|
|
8
8
|
mode?: 'url' | 'bundle';
|
|
9
9
|
loadScript?: (javascript: string) => void;
|
|
10
10
|
}): {
|
|
11
|
+
logger: import(".").DataAppLogger;
|
|
11
12
|
request: (message: RoutedMessage, signal?: AbortSignal) => Promise<unknown>;
|
|
12
13
|
transport: (operation: string, input: unknown, signal?: AbortSignal) => Promise<TransportResponse>;
|
|
13
14
|
lakehouse: {
|
|
@@ -34,6 +35,7 @@ export declare function localFrameBridge(window?: Window): LocalBridge | undefin
|
|
|
34
35
|
export declare function installDataAppTransport(bridge: ReturnType<typeof createIframeTransport>, frame?: Window): () => void;
|
|
35
36
|
/** The bootstrap installs this before executing app code. URL apps can install an explicit connection. */
|
|
36
37
|
export declare function getDataAppTransport(frame?: Window): {
|
|
38
|
+
logger: import(".").DataAppLogger;
|
|
37
39
|
request: (message: RoutedMessage, signal?: AbortSignal) => Promise<unknown>;
|
|
38
40
|
transport: (operation: string, input: unknown, signal?: AbortSignal) => Promise<TransportResponse>;
|
|
39
41
|
lakehouse: {
|
|
@@ -10,3 +10,4 @@ export { createDataAppNavigation, getDataAppNavigation, type DataAppNavigation,
|
|
|
10
10
|
export { createHttpTransport, DataAppError, type DataTransport, } from './transport.js';
|
|
11
11
|
export { createIframeTransport, installDataAppTransport, getDataAppTransport, type IframeTransport, } from './iframe.js';
|
|
12
12
|
export { createMessageClient } from './messages.js';
|
|
13
|
+
export type { DataAppLogger } from '../core/logger.js';
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { BridgeMessage } from '../core/bridge.js';
|
|
2
|
+
import { type DataAppLogger, type LogEntry } from '../core/logger.js';
|
|
3
|
+
/** Lazy arguments run in the iframe; only resolved values cross the bridge. */
|
|
4
|
+
export declare function createBridgeLogger(enabled: () => boolean, send: (entry: LogEntry) => void): DataAppLogger;
|
|
5
|
+
/** Log only delivery metadata; payloads and session credentials stay private. */
|
|
6
|
+
export declare function logBridgeMessage(logger: DataAppLogger, message: BridgeMessage): void;
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Brand settings; parsing is portable, while theme application requires the browser.
|
|
3
|
+
* @module @altertable/data-app/appearance
|
|
4
|
+
*/
|
|
1
5
|
export type Theme = 'light' | 'dark';
|
|
2
6
|
export type ThemePreference = Theme | 'system';
|
|
3
7
|
export type AppearanceSettings = {
|
|
@@ -14,16 +18,23 @@ export type AppearanceSettings = {
|
|
|
14
18
|
heading: string;
|
|
15
19
|
};
|
|
16
20
|
};
|
|
21
|
+
/** App-authored overrides; omitted fields use the package defaults. */
|
|
22
|
+
export type AppearanceOptions = Partial<Omit<AppearanceSettings, 'typography'>> & {
|
|
23
|
+
typography?: Partial<AppearanceSettings['typography']>;
|
|
24
|
+
};
|
|
17
25
|
export type ThemeController = {
|
|
18
26
|
getTheme: () => ThemePreference;
|
|
19
27
|
setTheme: (theme: ThemePreference) => void;
|
|
20
28
|
subscribe: (listener: () => void) => () => void;
|
|
21
29
|
};
|
|
30
|
+
/** Preserve supported external settings and use defaults for invalid fields. */
|
|
22
31
|
export declare function parseAppearance(value: unknown): AppearanceSettings;
|
|
32
|
+
/** Resolve typed app settings without repeating authoring checks at runtime. */
|
|
33
|
+
export declare function normalizeAppearance(value?: AppearanceOptions): AppearanceSettings;
|
|
23
34
|
/**
|
|
24
35
|
* Install semantic tokens on the document root, including portaled UI. Returns a cleanup for
|
|
25
36
|
* system-theme listening.
|
|
26
37
|
*/
|
|
27
|
-
export declare function applyAppearance(value
|
|
38
|
+
export declare function applyAppearance(value?: AppearanceOptions): () => void;
|
|
28
39
|
/** Persist a viewer theme preference. Applying appearance belongs to the UI owner. */
|
|
29
40
|
export declare function createThemeController(initialTheme?: ThemePreference): ThemeController;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type BridgeMessage, type BridgeRole, type BridgeEventsFrom, type BridgePayload, type BridgeEnvelope, type BridgeHandlers } from './bridge.js';
|
|
2
|
+
type ConnectionContext = Pick<BridgeEnvelope, 'sessionId' | 'token'> & {
|
|
3
|
+
documentId?: string;
|
|
4
|
+
};
|
|
5
|
+
/** The connection owns IDs and token rotation; callers can only supply event payloads. */
|
|
6
|
+
export declare function createBridgeEndpoint<const Role extends BridgeRole>({ role, origin, source, opaque, context, post, diagnostic, invalidRequest, handlers, }: {
|
|
7
|
+
role: Role;
|
|
8
|
+
handlers: BridgeHandlers<NoInfer<Role>>;
|
|
9
|
+
origin: string;
|
|
10
|
+
source: () => MessageEventSource | null;
|
|
11
|
+
opaque: boolean;
|
|
12
|
+
context: () => ConnectionContext;
|
|
13
|
+
post: (message: BridgeMessage) => void;
|
|
14
|
+
diagnostic?: (direction: 'send' | 'receive', type: BridgeMessage['type']) => void;
|
|
15
|
+
invalidRequest?: (id: string) => void;
|
|
16
|
+
}): {
|
|
17
|
+
send: <Name extends BridgeEventsFrom<Role>, const Payload extends BridgePayload<NoInfer<Name>>>(name: Name, payload: Payload & Record<Exclude<keyof Payload, keyof BridgePayload<NoInfer<Name>>>, never>) => void;
|
|
18
|
+
receive: (event: MessageEvent) => void;
|
|
19
|
+
dispose(): void;
|
|
20
|
+
};
|
|
21
|
+
export {};
|
|
@@ -6,24 +6,145 @@ export declare const PARENT_PARAM = "__altertable_parent";
|
|
|
6
6
|
export declare const MAX_PENDING = 128;
|
|
7
7
|
export declare const REQUEST_TIMEOUT_MS = 60000;
|
|
8
8
|
export type { TransportResponse } from './operation-types.js';
|
|
9
|
-
export
|
|
9
|
+
export declare function validId(value: unknown): value is string;
|
|
10
|
+
type Fields = Record<string, unknown>;
|
|
11
|
+
export type BridgeRole = 'host' | 'app';
|
|
12
|
+
/** Parsers project known fields; opaque values are validated by their owning route or adapter. */
|
|
13
|
+
export declare const bridgeProtocol: {
|
|
14
|
+
readonly channel: "altertable:data-app";
|
|
15
|
+
readonly version: 1;
|
|
16
|
+
readonly events: {
|
|
17
|
+
readonly connect: {
|
|
18
|
+
wire: "bridge:connect";
|
|
19
|
+
from: "host";
|
|
20
|
+
session: "none";
|
|
21
|
+
parse: (fields: Fields) => {};
|
|
22
|
+
};
|
|
23
|
+
readonly ready: {
|
|
24
|
+
wire: "bridge:ready";
|
|
25
|
+
from: "app";
|
|
26
|
+
session: "none";
|
|
27
|
+
parse: (fields: Fields) => {};
|
|
28
|
+
};
|
|
29
|
+
readonly initialize: {
|
|
30
|
+
wire: "bridge:initialize";
|
|
31
|
+
from: "host";
|
|
32
|
+
session: "establish";
|
|
33
|
+
parse: (fields: Fields) => {
|
|
34
|
+
state: unknown;
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
readonly request: {
|
|
38
|
+
wire: "bridge:request";
|
|
39
|
+
from: "app";
|
|
40
|
+
session: "current";
|
|
41
|
+
parse: (fields: Fields) => {
|
|
42
|
+
id: string;
|
|
43
|
+
route: string;
|
|
44
|
+
payload: unknown;
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
readonly result: {
|
|
48
|
+
wire: "bridge:result";
|
|
49
|
+
from: "host";
|
|
50
|
+
session: "current";
|
|
51
|
+
parse: (fields: Fields) => {
|
|
52
|
+
id: string;
|
|
53
|
+
response: unknown;
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
readonly error: {
|
|
57
|
+
wire: "bridge:error";
|
|
58
|
+
from: "host";
|
|
59
|
+
session: "current";
|
|
60
|
+
parse: (fields: Fields) => {
|
|
61
|
+
id: string;
|
|
62
|
+
code: string;
|
|
63
|
+
message: string;
|
|
64
|
+
requestId?: string | undefined;
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
readonly cancel: {
|
|
68
|
+
wire: "bridge:cancel";
|
|
69
|
+
from: "app";
|
|
70
|
+
session: "current";
|
|
71
|
+
parse: (fields: Fields) => {
|
|
72
|
+
id: string;
|
|
73
|
+
};
|
|
74
|
+
};
|
|
75
|
+
readonly disconnect: {
|
|
76
|
+
wire: "bridge:disconnect";
|
|
77
|
+
from: "app";
|
|
78
|
+
session: "current";
|
|
79
|
+
parse: (fields: Fields) => {};
|
|
80
|
+
};
|
|
81
|
+
readonly scriptLoad: {
|
|
82
|
+
wire: "script:load";
|
|
83
|
+
from: "host";
|
|
84
|
+
session: "current";
|
|
85
|
+
parse: (fields: Fields) => {
|
|
86
|
+
javascript: string;
|
|
87
|
+
};
|
|
88
|
+
};
|
|
89
|
+
readonly stateUpdate: {
|
|
90
|
+
wire: "state:update";
|
|
91
|
+
from: "host";
|
|
92
|
+
session: "current";
|
|
93
|
+
parse: (fields: Fields) => {
|
|
94
|
+
state: unknown;
|
|
95
|
+
};
|
|
96
|
+
};
|
|
97
|
+
readonly runtimeLog: {
|
|
98
|
+
wire: "runtime:log";
|
|
99
|
+
from: "app";
|
|
100
|
+
session: "current";
|
|
101
|
+
parse: (fields: Fields) => {
|
|
102
|
+
payload: import("./logger.js").LogEntry;
|
|
103
|
+
};
|
|
104
|
+
};
|
|
105
|
+
readonly runtimeReady: {
|
|
106
|
+
wire: "runtime:ready";
|
|
107
|
+
from: "app";
|
|
108
|
+
session: "current";
|
|
109
|
+
parse: (fields: Fields) => {};
|
|
110
|
+
};
|
|
111
|
+
readonly runtimeError: {
|
|
112
|
+
wire: "runtime:error";
|
|
113
|
+
from: "app";
|
|
114
|
+
session: "current";
|
|
115
|
+
parse: (fields: Fields) => {};
|
|
116
|
+
};
|
|
117
|
+
};
|
|
118
|
+
};
|
|
119
|
+
type Events = typeof bridgeProtocol.events;
|
|
120
|
+
export type BridgeEventName = keyof Events;
|
|
121
|
+
export type BridgePayload<Name extends BridgeEventName> = ReturnType<Events[Name]['parse']>;
|
|
122
|
+
export type BridgeEnvelope = {
|
|
10
123
|
channel: typeof BRIDGE;
|
|
11
|
-
version:
|
|
12
|
-
type: string;
|
|
124
|
+
version: typeof bridgeProtocol.version;
|
|
13
125
|
documentId: string;
|
|
14
126
|
sessionId?: string;
|
|
15
|
-
id?: string;
|
|
16
|
-
route?: string;
|
|
17
|
-
payload?: unknown;
|
|
18
|
-
response?: unknown;
|
|
19
|
-
code?: string;
|
|
20
|
-
message?: string;
|
|
21
|
-
/** Opaque host context, interpreted by optional app adapters. */
|
|
22
|
-
state?: unknown;
|
|
23
|
-
requestId?: string;
|
|
24
127
|
token?: string;
|
|
25
|
-
javascript?: string;
|
|
26
128
|
};
|
|
27
|
-
export
|
|
28
|
-
|
|
29
|
-
|
|
129
|
+
export type BridgeEventMessage<Name extends BridgeEventName> = Name extends BridgeEventName ? BridgeEnvelope & {
|
|
130
|
+
type: Events[Name]['wire'];
|
|
131
|
+
} & (Events[Name]['session'] extends 'none' ? {} : {
|
|
132
|
+
sessionId: string;
|
|
133
|
+
}) & BridgePayload<Name> : never;
|
|
134
|
+
export type BridgeMessage = {
|
|
135
|
+
[Name in BridgeEventName]: BridgeEventMessage<Name>;
|
|
136
|
+
}[BridgeEventName];
|
|
137
|
+
export type BridgeEventsFrom<Role extends BridgeRole> = {
|
|
138
|
+
[Name in BridgeEventName]: Events[Name]['from'] extends Role ? Name : never;
|
|
139
|
+
}[BridgeEventName];
|
|
140
|
+
export type BridgeHandlers<Role extends BridgeRole> = {
|
|
141
|
+
[Name in BridgeEventsFrom<Role extends 'host' ? 'app' : 'host'>]: (message: BridgeEventMessage<Name>) => void;
|
|
142
|
+
};
|
|
143
|
+
export declare function bridgeEventName(wire: string): "cancel" | "connect" | "disconnect" | "error" | "initialize" | "ready" | "request" | "result" | "runtimeError" | "runtimeLog" | "runtimeReady" | "scriptLoad" | "stateUpdate" | undefined;
|
|
144
|
+
/** Envelope parsing precedes authentication; event-specific fields remain untrusted. */
|
|
145
|
+
export declare function parseBridgeEnvelope(value: unknown): (BridgeEnvelope & Fields & {
|
|
146
|
+
type: string;
|
|
147
|
+
}) | undefined;
|
|
148
|
+
/** Project event fields after the caller has checked envelope eligibility. */
|
|
149
|
+
export declare function parseBridgePayload(envelope: NonNullable<ReturnType<typeof parseBridgeEnvelope>>, definition: Events[BridgeEventName]): BridgeMessage | undefined;
|
|
150
|
+
export declare function parseBridgeMessage(value: unknown): BridgeMessage | undefined;
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* App identity and display scope shared by browser and server.
|
|
3
3
|
* @module @altertable/data-app/config
|
|
4
4
|
*/
|
|
5
|
+
import type { AppearanceOptions } from './appearance.js';
|
|
5
6
|
export type DataAppConfig = {
|
|
6
7
|
title: string;
|
|
7
8
|
/** Display labels; scope does not grant data access. */
|
|
@@ -9,6 +10,6 @@ export type DataAppConfig = {
|
|
|
9
10
|
organization: string;
|
|
10
11
|
environment: string;
|
|
11
12
|
};
|
|
12
|
-
appearance:
|
|
13
|
+
appearance: AppearanceOptions;
|
|
13
14
|
};
|
|
14
15
|
export declare function dataAppTitle(config: Pick<DataAppConfig, 'title' | 'scope'>): string;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Host-owned log sink; compatible with console and frontend createLogger(). */
|
|
2
|
+
export type DataAppLogger = {
|
|
3
|
+
log: (...args: unknown[]) => void;
|
|
4
|
+
info: (...args: unknown[]) => void;
|
|
5
|
+
warn: (...args: unknown[]) => void;
|
|
6
|
+
error: (...args: unknown[]) => void;
|
|
7
|
+
};
|
|
8
|
+
export type LogEntry = {
|
|
9
|
+
method: keyof DataAppLogger;
|
|
10
|
+
args: unknown[];
|
|
11
|
+
};
|
|
12
|
+
export declare function isLogEntry(value: unknown): value is LogEntry;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { DataAppPresentation } from '../core/presentation.js';
|
|
2
|
+
import type { DataAppLogger } from '../core/logger.js';
|
|
3
|
+
import { type BridgeMessage } from '../core/bridge.js';
|
|
2
4
|
import { type MessageDispatcher } from '../core/messages.js';
|
|
3
5
|
export type DataAppConnection = {
|
|
4
6
|
type: 'origin';
|
|
@@ -10,15 +12,17 @@ export type DataAppConnection = {
|
|
|
10
12
|
export type DataAppStatus = 'connecting' | 'connected' | 'ready' | 'failed' | 'disconnected';
|
|
11
13
|
export type DataAppDiagnostic = {
|
|
12
14
|
direction: 'send' | 'receive';
|
|
13
|
-
type:
|
|
15
|
+
type: BridgeMessage['type'];
|
|
14
16
|
};
|
|
15
17
|
export type DataAppHost = {
|
|
16
18
|
dispose: () => void;
|
|
17
19
|
setPresentation: (presentation?: DataAppPresentation) => void;
|
|
20
|
+
setLogger: (logger?: DataAppLogger) => void;
|
|
18
21
|
};
|
|
19
22
|
export type DataAppHostOptions = {
|
|
20
23
|
iframe: HTMLIFrameElement;
|
|
21
24
|
presentation?: DataAppPresentation;
|
|
25
|
+
logger?: DataAppLogger;
|
|
22
26
|
onStatusChange?: (status: DataAppStatus) => void;
|
|
23
27
|
onDiagnostic?: (event: DataAppDiagnostic) => void;
|
|
24
28
|
onMessage: MessageDispatcher;
|
|
@@ -29,4 +33,4 @@ export type DataAppConnectionOptions = DataAppHostOptions & {
|
|
|
29
33
|
window?: Window;
|
|
30
34
|
};
|
|
31
35
|
/** The bridge owns delivery and cancellation; the routed handler owns validation, authorization and execution. */
|
|
32
|
-
export declare function attachDataAppConnection({ iframe, connection, javascript, presentation, onStatusChange, onDiagnostic, onMessage, window: host, }: DataAppConnectionOptions): DataAppHost;
|
|
36
|
+
export declare function attachDataAppConnection({ iframe, connection, javascript, presentation, logger, onStatusChange, onDiagnostic, onMessage, window: host, }: DataAppConnectionOptions): DataAppHost;
|
|
@@ -11,3 +11,4 @@ export { startDataAppBootstrap } from './bootstrap.js';
|
|
|
11
11
|
export { createNavigationHandler } from './navigation.js';
|
|
12
12
|
export { createSqlQueryHandler } from './sql.js';
|
|
13
13
|
export type { DataAppPresentation } from '../core/presentation.js';
|
|
14
|
+
export type { DataAppLogger } from '../core/logger.js';
|
|
@@ -12,4 +12,4 @@ export type DataAppSourceOptions = DataAppHostOptions & {
|
|
|
12
12
|
startupTimeoutMs?: number;
|
|
13
13
|
};
|
|
14
14
|
/** Owns loading and sandbox policy. Dispose before replacing the source or retrying. */
|
|
15
|
-
export declare function attachDataAppSource({ iframe, source, presentation, onMessage, onStatusChange, onDiagnostic, startupTimeoutMs, }: DataAppSourceOptions): DataAppHost;
|
|
15
|
+
export declare function attachDataAppSource({ iframe, source, presentation, logger, onMessage, onStatusChange, onDiagnostic, startupTimeoutMs, }: DataAppSourceOptions): DataAppHost;
|
|
@@ -2,7 +2,7 @@ import { type ComponentRef, type ComponentPropsWithoutRef } from 'react';
|
|
|
2
2
|
import { type DataAppBridgeOptions } from '../../embed/bridge.js';
|
|
3
3
|
import type { DataAppConnection } from '../../embed/host.js';
|
|
4
4
|
import type { DataAppSource } from '../../embed/source.js';
|
|
5
|
-
export type DataAppBridgeProps = Pick<DataAppBridgeOptions, 'onMessage' | 'onStatusChange' | 'onDiagnostic' | 'presentation'> & ({
|
|
5
|
+
export type DataAppBridgeProps = Pick<DataAppBridgeOptions, 'onMessage' | 'onStatusChange' | 'onDiagnostic' | 'presentation' | 'logger'> & ({
|
|
6
6
|
source: DataAppSource;
|
|
7
7
|
title: string;
|
|
8
8
|
startupTimeoutMs?: number;
|
|
@@ -11,6 +11,7 @@ export { createDataHooks } from './hooks.js';
|
|
|
11
11
|
export { defineDataContent } from './content.js';
|
|
12
12
|
export type { DataContentState } from './content.js';
|
|
13
13
|
export type { DataViewDefinition, ResolvedVariables, ViewBindings, } from './view.js';
|
|
14
|
+
export type { CsvCell, CsvTable, CsvExport } from './ui/csv-export.js';
|
|
14
15
|
export { DataApp } from './ui/DataApp.js';
|
|
15
16
|
export type { DataAppProps, DataAppRequest } from './ui/DataApp.js';
|
|
16
17
|
export { GettingStarted } from './ui/GettingStarted.js';
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ComponentProps, ComponentPropsWithRef, ReactNode } from 'react';
|
|
2
2
|
import type { DataView } from '../../core/data-view.js';
|
|
3
|
+
import type { CsvExport } from './csv-export.js';
|
|
3
4
|
import { type LiveControlProps } from './LiveControl.js';
|
|
4
5
|
import { PresentStory } from './PresentStory.js';
|
|
5
6
|
import { RefreshControl } from './RefreshControl.js';
|
|
@@ -22,10 +23,11 @@ export type AppToolbarProps = {
|
|
|
22
23
|
live?: LiveControlProps;
|
|
23
24
|
aboutData?: ReactNode;
|
|
24
25
|
story?: ComponentProps<typeof PresentStory>;
|
|
26
|
+
csvExport?: CsvExport;
|
|
25
27
|
} & Omit<ComponentPropsWithRef<'div'>, 'children'>;
|
|
26
28
|
/** Header actions only. Put reader-controlled inputs in DataApp.variables below the header.
|
|
27
29
|
* Observation time, or an initial loading status, sits before Refresh. Children prepend app controls in the right
|
|
28
30
|
* cluster; end follows the built-in actions. Live sits beside Refresh when supplied. Refresh also
|
|
29
31
|
* answers Alt/Option+R and uses the button to cancel a running request when onCancel is provided;
|
|
30
32
|
* refresh.tooltip overrides its static label. All built-in controls are optional. */
|
|
31
|
-
export declare function AppToolbar({ children, updatedAt, initialLoading, requestState, refresh, live, aboutData, story, end, controlsProps, className, role, 'aria-label': ariaLabel, ...props }: AppToolbarProps): import("react").JSX.Element;
|
|
33
|
+
export declare function AppToolbar({ children, updatedAt, initialLoading, requestState, refresh, live, aboutData, story, csvExport, end, controlsProps, className, role, 'aria-label': ariaLabel, ...props }: AppToolbarProps): import("react").JSX.Element;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { type ComponentProps, type ReactNode } from 'react';
|
|
2
2
|
import type { DisclosedQuery } from '../../core/contract.js';
|
|
3
3
|
import type { DataAppConfig } from '../../core/config.js';
|
|
4
|
+
import type { CsvExport } from './csv-export.js';
|
|
5
|
+
import { type DisplayedSnapshot } from '../../core/data-view.js';
|
|
4
6
|
import { type AboutEmpty } from './AboutData.js';
|
|
5
7
|
import { AppLayout } from './AppLayout.js';
|
|
6
8
|
import { type AppToolbarProps } from './AppToolbar.js';
|
|
@@ -31,7 +33,9 @@ export type DataAppRequest<Data, Input> = SectionResult<Data, Input> & {
|
|
|
31
33
|
export type DataAppProps<Data = unknown, Input = unknown> = DataAppBaseProps & ({
|
|
32
34
|
request: DataAppRequest<Data, Input>;
|
|
33
35
|
/** Findings are always derived from the result currently visible to the reader. */
|
|
34
|
-
story
|
|
36
|
+
story: BoundStory<Data, Input>;
|
|
37
|
+
/** Every analytical view exports every distinct dataset in its displayed result. */
|
|
38
|
+
csvExport: (snapshot: DisplayedSnapshot<Data, Input>) => CsvExport;
|
|
35
39
|
children: (data: Data, displayedInput: Input) => ReactNode;
|
|
36
40
|
loading?: ReactNode;
|
|
37
41
|
label?: string;
|
|
@@ -41,6 +45,7 @@ export type DataAppProps<Data = unknown, Input = unknown> = DataAppBaseProps & (
|
|
|
41
45
|
} | {
|
|
42
46
|
request?: never;
|
|
43
47
|
story?: never;
|
|
48
|
+
csvExport?: CsvExport;
|
|
44
49
|
children: ReactNode;
|
|
45
50
|
queries?: DisclosedQuery[];
|
|
46
51
|
refresh?: AppToolbarProps['refresh'];
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
/** Shared page-level feedback for requests and toolbar actions. */
|
|
3
|
+
export declare function Toast({ state, children, onRetry, position, }: {
|
|
4
|
+
state: 'updating' | 'error' | 'notice';
|
|
5
|
+
children: ReactNode;
|
|
6
|
+
onRetry?: () => void;
|
|
7
|
+
position?: 'top' | 'bottom';
|
|
8
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export type CsvCell = string | number | boolean | null | undefined;
|
|
2
|
+
/** One named dataset with ordered columns and raw displayed values. */
|
|
3
|
+
export type CsvTable = {
|
|
4
|
+
name: string;
|
|
5
|
+
columns: readonly string[];
|
|
6
|
+
rows: readonly (readonly CsvCell[])[];
|
|
7
|
+
};
|
|
8
|
+
/** All distinct datasets in the displayed result; filename names the download. */
|
|
9
|
+
export type CsvExport = {
|
|
10
|
+
filename: string;
|
|
11
|
+
tables: readonly [CsvTable, ...CsvTable[]];
|
|
12
|
+
};
|
|
13
|
+
export declare function formatCsv({ columns, rows, }: Pick<CsvTable, 'columns' | 'rows'>): string;
|
|
14
|
+
export declare function createCsvDownload(data: CsvExport, selectedTable?: CsvTable): {
|
|
15
|
+
filename: string;
|
|
16
|
+
blob: Blob;
|
|
17
|
+
route: 'export:csv' | 'export:zip';
|
|
18
|
+
};
|
|
19
|
+
export declare function exportCsv(data: CsvExport, table?: CsvTable): Promise<void>;
|
|
@@ -14,6 +14,7 @@ declare const brandedIcons: {
|
|
|
14
14
|
readonly info: import("lucide-react").LucideIcon;
|
|
15
15
|
readonly openDetails: import("lucide-react").LucideIcon;
|
|
16
16
|
readonly present: import("lucide-react").LucideIcon;
|
|
17
|
+
readonly export: import("lucide-react").LucideIcon;
|
|
17
18
|
readonly error: import("lucide-react").LucideIcon;
|
|
18
19
|
readonly close: import("lucide-react").LucideIcon;
|
|
19
20
|
readonly previous: import("lucide-react").LucideIcon;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { type Theme } from '../../core/appearance.js';
|
|
1
|
+
import { type Theme, type AppearanceOptions } from '../../core/appearance.js';
|
|
2
2
|
/** The parent theme takes precedence; only standalone viewers receive controls. */
|
|
3
|
-
export declare function useAppAppearance(appearance:
|
|
3
|
+
export declare function useAppAppearance(appearance: AppearanceOptions, hostTheme?: Theme): import("../../core/appearance.js").ThemeController | undefined;
|