@sybilion/uilib 1.1.0 → 1.2.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 +8 -8
- package/assets/{mini-app-global.css → standalone-global.css} +1 -1
- package/dist/esm/components/ui/Sidebar/Sidebar.styl.js +2 -2
- package/dist/esm/components/widgets/SidebarDatasetsItemsGrouped/SidebarDatasetsItemsGrouped.js +48 -0
- package/dist/esm/components/widgets/SidebarDatasetsItemsGrouped/SidebarDatasetsItemsGrouped.styl.js +7 -0
- package/dist/esm/components/widgets/SidebarDatasetsItemsGrouped/groupSidebarDatasets.js +38 -0
- package/dist/esm/index.js +5 -5
- package/dist/esm/sybilion-auth/SybilionAuthProvider.js +185 -0
- package/dist/esm/sybilion-auth/authPaths.js +7 -0
- package/dist/esm/sybilion-auth/exchangeSybilionToken.js +40 -0
- package/dist/esm/types/src/components/ui/Input/Input.d.ts +1 -1
- package/dist/esm/types/src/components/widgets/SidebarDatasetsItemsGrouped/SidebarDatasetsItemsGrouped.d.ts +11 -0
- package/dist/esm/types/src/components/widgets/SidebarDatasetsItemsGrouped/groupSidebarDatasets.d.ts +8 -0
- package/dist/esm/types/src/components/widgets/SidebarDatasetsItemsGrouped/index.d.ts +3 -0
- package/dist/esm/types/src/docs/pages/SidebarDatasetsItemsGroupedPage.d.ts +1 -0
- package/dist/esm/types/src/docs/pages/SybilionAuthProviderPage.d.ts +1 -0
- package/dist/esm/types/src/index.d.ts +3 -1
- package/dist/esm/types/src/sybilion-auth/SybilionAuthProvider.d.ts +39 -0
- package/dist/esm/types/src/sybilion-auth/authPaths.d.ts +3 -0
- package/dist/esm/types/src/sybilion-auth/exchangeSybilionToken.d.ts +2 -0
- package/dist/esm/types/src/sybilion-auth/index.d.ts +4 -0
- package/dist/esm/types/src/{mini-app/miniAppDataTypes.d.ts → types/sybilionDatasetSnapshots.d.ts} +5 -8
- package/docs/standalone-apps.md +65 -0
- package/package.json +10 -3
- package/src/components/ui/Sidebar/Sidebar.styl +0 -25
- package/src/components/ui/Sidebar/Sidebar.styl.d.ts +0 -1
- package/src/components/widgets/SidebarDatasetsItemsGrouped/SidebarDatasetsItemsGrouped.styl +29 -0
- package/src/{mini-app/MiniAppRoot.styl.d.ts → components/widgets/SidebarDatasetsItemsGrouped/SidebarDatasetsItemsGrouped.styl.d.ts} +4 -2
- package/src/components/widgets/SidebarDatasetsItemsGrouped/SidebarDatasetsItemsGrouped.tsx +128 -0
- package/src/components/widgets/SidebarDatasetsItemsGrouped/groupSidebarDatasets.ts +51 -0
- package/src/components/widgets/SidebarDatasetsItemsGrouped/index.ts +10 -0
- package/src/docs/pages/SidebarDatasetsItemsGroupedPage.tsx +136 -0
- package/src/docs/pages/SybilionAuthProviderPage.tsx +37 -0
- package/src/docs/registry.ts +9 -3
- package/src/index.ts +3 -1
- package/src/sybilion-auth/SybilionAuthProvider.tsx +322 -0
- package/src/sybilion-auth/authPaths.ts +6 -0
- package/src/sybilion-auth/exchangeSybilionToken.ts +47 -0
- package/src/sybilion-auth/index.ts +16 -0
- package/src/{mini-app/miniAppDataTypes.ts → types/sybilionDatasetSnapshots.ts} +5 -8
- package/dist/esm/mini-app/MiniAppRoot.js +0 -82
- package/dist/esm/mini-app/MiniAppRoot.styl.js +0 -7
- package/dist/esm/mini-app/miniAppChatBridge.js +0 -45
- package/dist/esm/mini-app/miniAppDataClient.js +0 -98
- package/dist/esm/mini-app/miniAppProtocol.js +0 -153
- package/dist/esm/mini-app/miniAppThemeConfig.js +0 -40
- package/dist/esm/types/src/docs/pages/MiniAppRootPage.d.ts +0 -1
- package/dist/esm/types/src/mini-app/MiniAppRoot.d.ts +0 -18
- package/dist/esm/types/src/mini-app/index.d.ts +0 -10
- package/dist/esm/types/src/mini-app/miniAppChatBridge.d.ts +0 -6
- package/dist/esm/types/src/mini-app/miniAppDataClient.d.ts +0 -16
- package/dist/esm/types/src/mini-app/miniAppProtocol.d.ts +0 -89
- package/dist/esm/types/src/mini-app/miniAppThemeConfig.d.ts +0 -3
- package/docs/workspace-mini-apps.md +0 -51
- package/src/docs/pages/MiniAppRootPage.tsx +0 -58
- package/src/mini-app/MiniAppRoot.styl +0 -24
- package/src/mini-app/MiniAppRoot.tsx +0 -150
- package/src/mini-app/index.ts +0 -43
- package/src/mini-app/miniAppChatBridge.ts +0 -55
- package/src/mini-app/miniAppDataClient.ts +0 -165
- package/src/mini-app/miniAppProtocol.ts +0 -247
- package/src/mini-app/miniAppThemeConfig.ts +0 -45
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
const MINIAPP_CHANNEL = 'sybilion.miniapp';
|
|
2
|
-
const MINIAPP_VERSION = 1;
|
|
3
|
-
function isRecord(v) {
|
|
4
|
-
return typeof v === 'object' && v !== null && !Array.isArray(v);
|
|
5
|
-
}
|
|
6
|
-
/** Parse parent → child THEME_SYNC (shell uses `buildThemeSyncMessage`). */
|
|
7
|
-
function parseThemeSyncMessage(data) {
|
|
8
|
-
if (!isRecord(data))
|
|
9
|
-
return null;
|
|
10
|
-
if (data.channel !== MINIAPP_CHANNEL)
|
|
11
|
-
return null;
|
|
12
|
-
if (data.version !== MINIAPP_VERSION)
|
|
13
|
-
return null;
|
|
14
|
-
if (data.type !== 'THEME_SYNC')
|
|
15
|
-
return null;
|
|
16
|
-
const payload = data.payload;
|
|
17
|
-
if (!isRecord(payload))
|
|
18
|
-
return null;
|
|
19
|
-
const mode = payload.mode === 'dark' ? 'dark' : 'light';
|
|
20
|
-
const isDarkMode = typeof payload.isDarkMode === 'boolean'
|
|
21
|
-
? payload.isDarkMode
|
|
22
|
-
: mode === 'dark';
|
|
23
|
-
return { mode, isDarkMode };
|
|
24
|
-
}
|
|
25
|
-
/** Child → parent READY (optional `appId` for telemetry). */
|
|
26
|
-
function buildReadyMessage(payload = {}) {
|
|
27
|
-
return {
|
|
28
|
-
channel: MINIAPP_CHANNEL,
|
|
29
|
-
version: MINIAPP_VERSION,
|
|
30
|
-
type: 'READY',
|
|
31
|
-
payload,
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
function resolveParentOriginFromReferrer() {
|
|
35
|
-
try {
|
|
36
|
-
if (typeof document !== 'undefined' && document.referrer) {
|
|
37
|
-
return new URL(document.referrer).origin;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
catch {
|
|
41
|
-
/* invalid referrer */
|
|
42
|
-
}
|
|
43
|
-
return null;
|
|
44
|
-
}
|
|
45
|
-
function applyThemeToDocument(mode) {
|
|
46
|
-
if (typeof document === 'undefined')
|
|
47
|
-
return;
|
|
48
|
-
const root = document.documentElement;
|
|
49
|
-
root.classList.remove('light', 'dark');
|
|
50
|
-
root.classList.add(mode);
|
|
51
|
-
}
|
|
52
|
-
/** Only accept shell messages that appear to come from the real embedding parent. */
|
|
53
|
-
function isTrustedMiniAppParentMessage(event) {
|
|
54
|
-
if (event.source !== window.parent)
|
|
55
|
-
return false;
|
|
56
|
-
const fromReferrer = resolveParentOriginFromReferrer();
|
|
57
|
-
if (fromReferrer && event.origin !== fromReferrer)
|
|
58
|
-
return false;
|
|
59
|
-
return true;
|
|
60
|
-
}
|
|
61
|
-
function buildDataRequestMessage(payload) {
|
|
62
|
-
return {
|
|
63
|
-
channel: MINIAPP_CHANNEL,
|
|
64
|
-
version: MINIAPP_VERSION,
|
|
65
|
-
type: 'DATA_REQUEST',
|
|
66
|
-
payload,
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
function buildChatSendMessage(payload) {
|
|
70
|
-
return {
|
|
71
|
-
channel: MINIAPP_CHANNEL,
|
|
72
|
-
version: MINIAPP_VERSION,
|
|
73
|
-
type: 'CHAT_SEND',
|
|
74
|
-
payload,
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
/** Parse parent → child DATA_RESPONSE. */
|
|
78
|
-
function parseDataResponseMessage(data) {
|
|
79
|
-
if (!isRecord(data))
|
|
80
|
-
return null;
|
|
81
|
-
if (data.channel !== MINIAPP_CHANNEL)
|
|
82
|
-
return null;
|
|
83
|
-
if (data.version !== MINIAPP_VERSION)
|
|
84
|
-
return null;
|
|
85
|
-
if (data.type !== 'DATA_RESPONSE')
|
|
86
|
-
return null;
|
|
87
|
-
const payload = data.payload;
|
|
88
|
-
if (!isRecord(payload))
|
|
89
|
-
return null;
|
|
90
|
-
const requestId = payload.requestId;
|
|
91
|
-
if (typeof requestId !== 'string' || requestId.length === 0)
|
|
92
|
-
return null;
|
|
93
|
-
const ok = payload.ok === true;
|
|
94
|
-
const errOk = payload.ok === false;
|
|
95
|
-
if (!ok && !errOk)
|
|
96
|
-
return null;
|
|
97
|
-
const base = {
|
|
98
|
-
requestId,
|
|
99
|
-
ok,
|
|
100
|
-
};
|
|
101
|
-
if ('result' in payload) {
|
|
102
|
-
base.result = payload.result;
|
|
103
|
-
}
|
|
104
|
-
if (typeof payload.error === 'string') {
|
|
105
|
-
base.error = payload.error;
|
|
106
|
-
}
|
|
107
|
-
return base;
|
|
108
|
-
}
|
|
109
|
-
/** Parse parent → child CHAT_SEND_RESULT (shell uses `buildChatSendResultMessage`). */
|
|
110
|
-
function parseChatSendResultMessage(data) {
|
|
111
|
-
if (!isRecord(data))
|
|
112
|
-
return null;
|
|
113
|
-
if (data.channel !== MINIAPP_CHANNEL)
|
|
114
|
-
return null;
|
|
115
|
-
if (data.version !== MINIAPP_VERSION)
|
|
116
|
-
return null;
|
|
117
|
-
if (data.type !== 'CHAT_SEND_RESULT')
|
|
118
|
-
return null;
|
|
119
|
-
const payload = data.payload;
|
|
120
|
-
if (!isRecord(payload))
|
|
121
|
-
return null;
|
|
122
|
-
const requestId = payload.requestId;
|
|
123
|
-
if (typeof requestId !== 'string' || requestId.length === 0)
|
|
124
|
-
return null;
|
|
125
|
-
if (payload.ok === true) {
|
|
126
|
-
const result = payload.result;
|
|
127
|
-
if (!isRecord(result))
|
|
128
|
-
return null;
|
|
129
|
-
const responseText = result.response;
|
|
130
|
-
if (typeof responseText !== 'string')
|
|
131
|
-
return null;
|
|
132
|
-
const sidRaw = result.session_id;
|
|
133
|
-
if (sidRaw !== undefined && sidRaw !== null && typeof sidRaw !== 'string')
|
|
134
|
-
return null;
|
|
135
|
-
const session_id = typeof sidRaw === 'string' ? sidRaw : null;
|
|
136
|
-
return {
|
|
137
|
-
requestId,
|
|
138
|
-
ok: true,
|
|
139
|
-
result: {
|
|
140
|
-
response: responseText,
|
|
141
|
-
session_id,
|
|
142
|
-
},
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
|
-
if (payload.ok === false) {
|
|
146
|
-
if (typeof payload.error !== 'string')
|
|
147
|
-
return null;
|
|
148
|
-
return { requestId, ok: false, error: payload.error };
|
|
149
|
-
}
|
|
150
|
-
return null;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
export { MINIAPP_CHANNEL, MINIAPP_VERSION, applyThemeToDocument, buildChatSendMessage, buildDataRequestMessage, buildReadyMessage, isTrustedMiniAppParentMessage, parseChatSendResultMessage, parseDataResponseMessage, parseThemeSyncMessage, resolveParentOriginFromReferrer };
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { ThemeHelpers, ThemeDefaults } from '@homecode/ui';
|
|
2
|
-
|
|
3
|
-
const { colors, getColors, getConfig } = ThemeDefaults;
|
|
4
|
-
const defaultPalette = getColors();
|
|
5
|
-
const colorsConfig = {
|
|
6
|
-
light: {
|
|
7
|
-
...ThemeHelpers.colorsConfigToVars({
|
|
8
|
-
...getColors({
|
|
9
|
-
accent: colors.dark,
|
|
10
|
-
decent: colors.light,
|
|
11
|
-
}),
|
|
12
|
-
}),
|
|
13
|
-
},
|
|
14
|
-
dark: {
|
|
15
|
-
...ThemeHelpers.colorsConfigToVars({
|
|
16
|
-
...getColors({
|
|
17
|
-
accent: colors.light,
|
|
18
|
-
decent: colors.dark,
|
|
19
|
-
}),
|
|
20
|
-
}),
|
|
21
|
-
},
|
|
22
|
-
};
|
|
23
|
-
/** Homecode `<Theme config={...}>` shape for workspace mini-apps (generic palette). */
|
|
24
|
-
function getDefaultMiniAppThemeConfig(isDarkMode) {
|
|
25
|
-
return {
|
|
26
|
-
...getConfig(),
|
|
27
|
-
...colorsConfig[isDarkMode ? 'dark' : 'light'],
|
|
28
|
-
...ThemeHelpers.colorsConfigToVars({
|
|
29
|
-
active: {
|
|
30
|
-
color: '#00a9c7',
|
|
31
|
-
mods: {
|
|
32
|
-
// @ts-ignore — extend defaults so --active-color-alpha-* variants match Homecode
|
|
33
|
-
alpha: [0, 50, 100, 200, ...defaultPalette.active.mods.alpha],
|
|
34
|
-
},
|
|
35
|
-
},
|
|
36
|
-
}),
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export { getDefaultMiniAppThemeConfig };
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export default function MiniAppRootPage(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import type { ReactNode } from 'react';
|
|
2
|
-
import React from 'react';
|
|
3
|
-
import { type ThemeSyncPayload } from './miniAppProtocol';
|
|
4
|
-
import { type MiniAppThemeConfig } from './miniAppThemeConfig';
|
|
5
|
-
export type MiniAppShellContextValue = {
|
|
6
|
-
theme: ThemeSyncPayload;
|
|
7
|
-
};
|
|
8
|
-
export declare function useMiniAppShellTheme(): MiniAppShellContextValue;
|
|
9
|
-
export type MiniAppRootProps = {
|
|
10
|
-
children: ReactNode;
|
|
11
|
-
className?: string;
|
|
12
|
-
/** Included in READY payload when set. */
|
|
13
|
-
appId?: string;
|
|
14
|
-
onThemeChange?: (theme: ThemeSyncPayload) => void;
|
|
15
|
-
/** Overrides `@homecode/ui` `<Theme config>` builder (defaults to generic mini-app palette). */
|
|
16
|
-
getThemeConfig?: (isDarkMode: boolean) => MiniAppThemeConfig;
|
|
17
|
-
};
|
|
18
|
-
export declare function MiniAppRoot({ children, className, appId, onThemeChange, getThemeConfig, }: MiniAppRootProps): React.ReactElement;
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
export { applyThemeToDocument, buildChatSendMessage, buildDataRequestMessage, buildReadyMessage, MINIAPP_CHANNEL, MINIAPP_VERSION, parseChatSendResultMessage, parseDataResponseMessage, parseThemeSyncMessage, isTrustedMiniAppParentMessage, resolveParentOriginFromReferrer, } from './miniAppProtocol';
|
|
2
|
-
export type { MiniAppMessageReady, MiniAppMessageThemeSync, MiniAppMessageDataRequest, MiniAppMessageDataResponse, MiniAppMessageChatSend, MiniAppMessageChatSendResult, MiniAppDataRequestPayload, MiniAppDataResponsePayload, MiniAppChatSendPayload, MiniAppChatSendResultPayload, MiniAppDataOp, ThemeSyncPayload, } from './miniAppProtocol';
|
|
3
|
-
export { createMiniAppDataClient } from './miniAppDataClient';
|
|
4
|
-
export type { MiniAppDataClientOptions, MiniAppDataClient, } from './miniAppDataClient';
|
|
5
|
-
export type { MiniAppDataset, MiniAppDriversComparisonSnapshot, MiniAppForecastMap, MiniAppPerformanceBundle, } from './miniAppDataTypes';
|
|
6
|
-
export { getDefaultMiniAppThemeConfig } from './miniAppThemeConfig';
|
|
7
|
-
export type { MiniAppThemeConfig } from './miniAppThemeConfig';
|
|
8
|
-
export { sendChatMessage } from './miniAppChatBridge';
|
|
9
|
-
export { MiniAppRoot, useMiniAppShellTheme } from './MiniAppRoot';
|
|
10
|
-
export type { MiniAppRootProps, MiniAppShellContextValue } from './MiniAppRoot';
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import type { ChatResponse } from '#uilib/types/chat-api.types';
|
|
2
|
-
/**
|
|
3
|
-
* Ask the Sybilion host to send a chat message with its auth token.
|
|
4
|
-
* Does not update host ChatSheet state — same session as `chatId` on the agent only.
|
|
5
|
-
*/
|
|
6
|
-
export declare function sendChatMessage(chatId: string, message: string): Promise<ChatResponse>;
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import type { MiniAppDataset, MiniAppDriversComparisonSnapshot, MiniAppForecastMap, MiniAppPerformanceBundle } from './miniAppDataTypes';
|
|
2
|
-
export type MiniAppDataClientOptions = {
|
|
3
|
-
/** Default 10000 ms. */
|
|
4
|
-
timeoutMs?: number;
|
|
5
|
-
};
|
|
6
|
-
export type MiniAppDataClient = {
|
|
7
|
-
getDatasets(): Promise<MiniAppDataset[]>;
|
|
8
|
-
getDataset(id: number): Promise<MiniAppDataset | null>;
|
|
9
|
-
getForecasts(datasetId: number): Promise<MiniAppForecastMap>;
|
|
10
|
-
getForecast(datasetId: number, analysisId: number): Promise<unknown | null>;
|
|
11
|
-
getDrivers(datasetId: number, analysisId: number): Promise<unknown[]>;
|
|
12
|
-
getPerformanceData(datasetId: number, analysisId: number): Promise<MiniAppPerformanceBundle>;
|
|
13
|
-
getDriversComparisonData(datasetId: number, analysisId: number): Promise<MiniAppDriversComparisonSnapshot>;
|
|
14
|
-
};
|
|
15
|
-
/** One listener per browsing context; tracks in-flight bridge requests by `requestId`. */
|
|
16
|
-
export declare function createMiniAppDataClient(options?: MiniAppDataClientOptions): MiniAppDataClient;
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* postMessage protocol for Sybilion workspace mini-apps (iframe child).
|
|
3
|
-
* Keep in sync with sybilion-client `src/workspace/miniAppBridge.ts` (channel, version, payloads).
|
|
4
|
-
*/
|
|
5
|
-
import type { ChatResponse } from '#uilib/types/chat-api.types';
|
|
6
|
-
export declare const MINIAPP_CHANNEL: "sybilion.miniapp";
|
|
7
|
-
export declare const MINIAPP_VERSION: 1;
|
|
8
|
-
export type ThemeSyncPayload = {
|
|
9
|
-
mode: 'light' | 'dark';
|
|
10
|
-
isDarkMode: boolean;
|
|
11
|
-
};
|
|
12
|
-
export type MiniAppMessageReady = {
|
|
13
|
-
channel: typeof MINIAPP_CHANNEL;
|
|
14
|
-
version: typeof MINIAPP_VERSION;
|
|
15
|
-
type: 'READY';
|
|
16
|
-
payload: Record<string, unknown> | {
|
|
17
|
-
appId?: string;
|
|
18
|
-
};
|
|
19
|
-
};
|
|
20
|
-
export type MiniAppMessageThemeSync = {
|
|
21
|
-
channel: typeof MINIAPP_CHANNEL;
|
|
22
|
-
version: typeof MINIAPP_VERSION;
|
|
23
|
-
type: 'THEME_SYNC';
|
|
24
|
-
payload: ThemeSyncPayload;
|
|
25
|
-
};
|
|
26
|
-
export type MiniAppDataOp = 'getDatasets' | 'getDataset' | 'getForecasts' | 'getForecast' | 'getDrivers' | 'getPerformanceData' | 'getDriversComparisonData';
|
|
27
|
-
export type MiniAppDataRequestPayload = {
|
|
28
|
-
requestId: string;
|
|
29
|
-
op: MiniAppDataOp;
|
|
30
|
-
params?: Record<string, number>;
|
|
31
|
-
};
|
|
32
|
-
export type MiniAppMessageDataRequest = {
|
|
33
|
-
channel: typeof MINIAPP_CHANNEL;
|
|
34
|
-
version: typeof MINIAPP_VERSION;
|
|
35
|
-
type: 'DATA_REQUEST';
|
|
36
|
-
payload: MiniAppDataRequestPayload;
|
|
37
|
-
};
|
|
38
|
-
export type MiniAppDataResponsePayload = {
|
|
39
|
-
requestId: string;
|
|
40
|
-
ok: boolean;
|
|
41
|
-
result?: unknown;
|
|
42
|
-
error?: string;
|
|
43
|
-
};
|
|
44
|
-
export type MiniAppMessageDataResponse = {
|
|
45
|
-
channel: typeof MINIAPP_CHANNEL;
|
|
46
|
-
version: typeof MINIAPP_VERSION;
|
|
47
|
-
type: 'DATA_RESPONSE';
|
|
48
|
-
payload: MiniAppDataResponsePayload;
|
|
49
|
-
};
|
|
50
|
-
export type MiniAppChatSendPayload = {
|
|
51
|
-
requestId: string;
|
|
52
|
-
chatId: string;
|
|
53
|
-
message: string;
|
|
54
|
-
};
|
|
55
|
-
export type MiniAppMessageChatSend = {
|
|
56
|
-
channel: typeof MINIAPP_CHANNEL;
|
|
57
|
-
version: typeof MINIAPP_VERSION;
|
|
58
|
-
type: 'CHAT_SEND';
|
|
59
|
-
payload: MiniAppChatSendPayload;
|
|
60
|
-
};
|
|
61
|
-
export type MiniAppChatSendResultPayload = {
|
|
62
|
-
requestId: string;
|
|
63
|
-
ok: true;
|
|
64
|
-
result: ChatResponse;
|
|
65
|
-
} | {
|
|
66
|
-
requestId: string;
|
|
67
|
-
ok: false;
|
|
68
|
-
error: string;
|
|
69
|
-
};
|
|
70
|
-
export type MiniAppMessageChatSendResult = {
|
|
71
|
-
channel: typeof MINIAPP_CHANNEL;
|
|
72
|
-
version: typeof MINIAPP_VERSION;
|
|
73
|
-
type: 'CHAT_SEND_RESULT';
|
|
74
|
-
payload: MiniAppChatSendResultPayload;
|
|
75
|
-
};
|
|
76
|
-
/** Parse parent → child THEME_SYNC (shell uses `buildThemeSyncMessage`). */
|
|
77
|
-
export declare function parseThemeSyncMessage(data: unknown): ThemeSyncPayload | null;
|
|
78
|
-
/** Child → parent READY (optional `appId` for telemetry). */
|
|
79
|
-
export declare function buildReadyMessage(payload?: Record<string, unknown>): MiniAppMessageReady;
|
|
80
|
-
export declare function resolveParentOriginFromReferrer(): string | null;
|
|
81
|
-
export declare function applyThemeToDocument(mode: 'light' | 'dark'): void;
|
|
82
|
-
/** Only accept shell messages that appear to come from the real embedding parent. */
|
|
83
|
-
export declare function isTrustedMiniAppParentMessage(event: MessageEvent): boolean;
|
|
84
|
-
export declare function buildDataRequestMessage(payload: MiniAppDataRequestPayload): MiniAppMessageDataRequest;
|
|
85
|
-
export declare function buildChatSendMessage(payload: MiniAppChatSendPayload): MiniAppMessageChatSend;
|
|
86
|
-
/** Parse parent → child DATA_RESPONSE. */
|
|
87
|
-
export declare function parseDataResponseMessage(data: unknown): MiniAppDataResponsePayload | null;
|
|
88
|
-
/** Parse parent → child CHAT_SEND_RESULT (shell uses `buildChatSendResultMessage`). */
|
|
89
|
-
export declare function parseChatSendResultMessage(data: unknown): MiniAppChatSendResultPayload | null;
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
# Workspace mini-apps (Sybilion iframe)
|
|
2
|
-
|
|
3
|
-
The Sybilion client embeds mini-apps in an **iframe** and syncs theme with `postMessage`. Use **`MiniAppRoot`** so this document’s `<html>` gets **`light` / `dark`** (uilib uses `.dark { … }` for tokens), and so **`@homecode/ui`’s `<Theme />`** runs with vars matching that mode (`getDefaultMiniAppThemeConfig`; override via props if needed).
|
|
4
|
-
|
|
5
|
-
## Design system (`@sybilion/uilib`)
|
|
6
|
-
|
|
7
|
-
**Prefer exported components from `@sybilion/uilib`** for structure, typography, forms, feedback, data display, and charts **when they fit the need**. That keeps spacing, tokens, and behavior aligned with Sybilion and avoids one-off layouts. Use custom markup or CSS **only** when uilib has no suitable primitive.
|
|
8
|
-
|
|
9
|
-
**For humans and coding agents:** Default to uilib as the component library—do not invent new layout patterns or duplicate design tokens when an existing uilib component (or composition of a few) can do the job. Browse the uilib docs app / package exports before building bespoke UI.
|
|
10
|
-
|
|
11
|
-
**Page inset:** Do **not** add your own **left/right** padding or margin on the root page or a full-viewport wrapper (no random `px-*` / `mx-*` / `container` max-width hacks for “page margins”). Use uilib layout primitives and spacing tokens—or patterns documented for mini-apps—so horizontal gutters and max width stay consistent with the shell.
|
|
12
|
-
|
|
13
|
-
1. Import **`@sybilion/uilib/mini-app-global.css`** (slim tokens + font imports; ships in this package).
|
|
14
|
-
2. Wrap the React root:
|
|
15
|
-
|
|
16
|
-
```tsx
|
|
17
|
-
import { MiniAppRoot } from '@sybilion/uilib';
|
|
18
|
-
import '@sybilion/uilib/mini-app-global.css';
|
|
19
|
-
|
|
20
|
-
createRoot(document.getElementById('root')!).render(
|
|
21
|
-
<MiniAppRoot appId="my-mini-app">
|
|
22
|
-
<App />
|
|
23
|
-
</MiniAppRoot>,
|
|
24
|
-
);
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
3. Optional: **`useMiniAppShellTheme()`** for **`{ theme: { mode, isDarkMode } }`** under the provider (object leaves room for more shell fields later).
|
|
28
|
-
|
|
29
|
-
4. Optional: **`getThemeConfig`** on **`MiniAppRoot`** — passed **`(isDarkMode) => config`** like the Sybilion app’s **`getThemeConfig`** from **`src/lib/theme.ts`**, so iframe UI matches host accent/danger tokens.
|
|
30
|
-
|
|
31
|
-
**Bridge:** `MiniAppRoot` handles `THEME_SYNC`, sends `READY` on mount/load, and checks `event.source === window.parent` plus `document.referrer` origin when present. If the referrer is missing (strict `Referrer-Policy`), `READY` may use `targetOrigin` `*` — document that for your host.
|
|
32
|
-
|
|
33
|
-
## Cached data from the host (no extra APIs)
|
|
34
|
-
|
|
35
|
-
The Sybilion shell can answer read-only **data getters** over the same `postMessage` channel (`DATA_REQUEST` / `DATA_RESPONSE`). Use this when a mini-app should render **the user’s existing Sybilion data** (datasets, forecasts, drivers, performance, drivers comparison) **without** building duplicate backend calls.
|
|
36
|
-
|
|
37
|
-
- **Cache-only:** The shell returns whatever is **already in memory** (dataset context) or in the **same localStorage cache** the main app uses for Performance (e.g. `performance-<analysisId>`). It does **not** trigger network fetches. If the user never opened a dataset tab or the blob was never loaded, you get **empty objects, `null`, or `[]`** — handle that in UI.
|
|
38
|
-
- **Performance bundle:** `getPerformanceData` returns `{ table, spaghetti }`. `table` is the cached Performance-tab payload (often `null` until the user has opened Performance for that analysis). `spaghetti` is in-memory backtest lines from the host when present.
|
|
39
|
-
- **Usage:** Create one client (e.g. module singleton) with **`createMiniAppDataClient()`** from `@sybilion/uilib`. It only works **inside the iframe** (throws if `window.parent === window`). Methods: **`getDatasets()`**, **`getDataset(id)`**, **`getForecasts(datasetId)`**, **`getForecast(datasetId, analysisId)`**, **`getDrivers(datasetId, analysisId)`**, **`getPerformanceData(datasetId, analysisId)`**, **`getDriversComparisonData(datasetId, analysisId)`**. Types **`MiniAppDataset`**, **`MiniAppForecastMap`**, **`MiniAppPerformanceBundle`**, **`MiniAppDriversComparisonSnapshot`** describe the returned JSON loosely.
|
|
40
|
-
|
|
41
|
-
**For coding agents:** Prefer these getters when the task is “show the user’s current Sybilion data in the mini-app” so the iframe stays aligned with the host session and avoids inventing parallel data loading.
|
|
42
|
-
|
|
43
|
-
```tsx
|
|
44
|
-
import { createMiniAppDataClient } from '@sybilion/uilib';
|
|
45
|
-
|
|
46
|
-
const data = createMiniAppDataClient();
|
|
47
|
-
|
|
48
|
-
// inside an effect or loader (iframe only)
|
|
49
|
-
const datasets = await data.getDatasets();
|
|
50
|
-
const forecasts = await data.getForecasts(datasetId);
|
|
51
|
-
```
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import { PageContentSection } from '#uilib/components/ui/Page';
|
|
2
|
-
import { getThemeConfig } from '#uilib/docs/lib/theme';
|
|
3
|
-
import { MiniAppRoot, useMiniAppShellTheme } from '#uilib/mini-app';
|
|
4
|
-
|
|
5
|
-
import { AppPageHeader } from '../components/AppPageHeader/AppPageHeader';
|
|
6
|
-
import { DocsHeaderActions } from '../docsHeaderActions';
|
|
7
|
-
|
|
8
|
-
function MiniAppThemeDemo() {
|
|
9
|
-
const { theme } = useMiniAppShellTheme();
|
|
10
|
-
|
|
11
|
-
return (
|
|
12
|
-
<>
|
|
13
|
-
<p style={{ margin: 0 }}>
|
|
14
|
-
Context theme: <code>{theme.mode}</code>, isDarkMode:{' '}
|
|
15
|
-
<code>{String(theme.isDarkMode)}</code>
|
|
16
|
-
</p>
|
|
17
|
-
<p style={{ margin: 0, color: 'var(--muted-foreground)' }}>
|
|
18
|
-
Long content below — scroll should stay inside the mini-app shell (not
|
|
19
|
-
only the docs page), matching iframe workspace apps.
|
|
20
|
-
</p>
|
|
21
|
-
{Array.from({ length: 36 }, (_, i) => (
|
|
22
|
-
<p key={i} style={{ margin: 0, lineHeight: 1.6 }}>
|
|
23
|
-
Block {i + 1}: Lorem ipsum dolor sit amet, consectetur adipiscing
|
|
24
|
-
elit. Sed do eiusmod tempor incididunt ut labore et dolore magna
|
|
25
|
-
aliqua.
|
|
26
|
-
</p>
|
|
27
|
-
))}
|
|
28
|
-
</>
|
|
29
|
-
);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export default function MiniAppRootPage() {
|
|
33
|
-
return (
|
|
34
|
-
<>
|
|
35
|
-
<AppPageHeader
|
|
36
|
-
breadcrumbs={[{ label: 'MiniAppRoot' }]}
|
|
37
|
-
title="MiniAppRoot"
|
|
38
|
-
subheader="Workspace mini-app shell: syncs document light/dark from parent THEME_SYNC postMessage, exposes theme via useMiniAppShellTheme. When embedded in Sybilion, child posts READY to parent; on this top-level docs page READY is skipped (no iframe parent)."
|
|
39
|
-
actions={<DocsHeaderActions />}
|
|
40
|
-
/>
|
|
41
|
-
<style>{`
|
|
42
|
-
.mini-app-root-page {
|
|
43
|
-
box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.1);
|
|
44
|
-
border-radius: var(--p-4);
|
|
45
|
-
}
|
|
46
|
-
`}</style>
|
|
47
|
-
<PageContentSection style={{ maxHeight: '500px' }}>
|
|
48
|
-
<MiniAppRoot
|
|
49
|
-
appId="uilib-docs"
|
|
50
|
-
className="mini-app-root-page"
|
|
51
|
-
getThemeConfig={isDarkMode => getThemeConfig(isDarkMode)}
|
|
52
|
-
>
|
|
53
|
-
<MiniAppThemeDemo />
|
|
54
|
-
</MiniAppRoot>
|
|
55
|
-
</PageContentSection>
|
|
56
|
-
</>
|
|
57
|
-
);
|
|
58
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
@import 'lib/theme.styl'
|
|
2
|
-
|
|
3
|
-
// Scroll root must stay flex row: [scrollable inner | y-bar]. column stacks inner
|
|
4
|
-
// + scrollbar → inner grows with content → overflow-y never engages (clips via overflow:hidden).
|
|
5
|
-
.root
|
|
6
|
-
overflow hidden
|
|
7
|
-
|
|
8
|
-
position relative
|
|
9
|
-
width 100%
|
|
10
|
-
height 100vh
|
|
11
|
-
min-height 0
|
|
12
|
-
|
|
13
|
-
@media (max-width MOBILE)
|
|
14
|
-
height auto
|
|
15
|
-
flex 1
|
|
16
|
-
min-height 0
|
|
17
|
-
|
|
18
|
-
// Match PageScroll: constrain inner so homecode Scroll max-height:100% + overflow-y work
|
|
19
|
-
.inner
|
|
20
|
-
width 100%
|
|
21
|
-
// min-height 0
|
|
22
|
-
max-height 100%
|
|
23
|
-
box-sizing border-box
|
|
24
|
-
padding var(--page-y-padding) var(--page-x-padding)
|
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
import cn from 'classnames';
|
|
2
|
-
import type { ReactNode } from 'react';
|
|
3
|
-
import React, {
|
|
4
|
-
createContext,
|
|
5
|
-
useCallback,
|
|
6
|
-
useContext,
|
|
7
|
-
useEffect,
|
|
8
|
-
useMemo,
|
|
9
|
-
useRef,
|
|
10
|
-
useState,
|
|
11
|
-
} from 'react';
|
|
12
|
-
|
|
13
|
-
import { Scroll, Theme } from '@homecode/ui';
|
|
14
|
-
|
|
15
|
-
import S from './MiniAppRoot.styl';
|
|
16
|
-
import {
|
|
17
|
-
type ThemeSyncPayload,
|
|
18
|
-
applyThemeToDocument,
|
|
19
|
-
buildReadyMessage,
|
|
20
|
-
isTrustedMiniAppParentMessage,
|
|
21
|
-
parseThemeSyncMessage,
|
|
22
|
-
resolveParentOriginFromReferrer,
|
|
23
|
-
} from './miniAppProtocol';
|
|
24
|
-
import {
|
|
25
|
-
type MiniAppThemeConfig,
|
|
26
|
-
getDefaultMiniAppThemeConfig,
|
|
27
|
-
} from './miniAppThemeConfig';
|
|
28
|
-
|
|
29
|
-
const defaultTheme: ThemeSyncPayload = {
|
|
30
|
-
mode: 'light',
|
|
31
|
-
isDarkMode: false,
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
function isEmbeddedMiniApp(): boolean {
|
|
35
|
-
return typeof window !== 'undefined' && window.parent !== window;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function themeFromDocument(): ThemeSyncPayload {
|
|
39
|
-
if (typeof document === 'undefined') return defaultTheme;
|
|
40
|
-
const isDark = document.documentElement.classList.contains('dark');
|
|
41
|
-
return {
|
|
42
|
-
mode: isDark ? 'dark' : 'light',
|
|
43
|
-
isDarkMode: isDark,
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export type MiniAppShellContextValue = {
|
|
48
|
-
theme: ThemeSyncPayload;
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
const MiniAppShellContext = createContext<MiniAppShellContextValue | null>(
|
|
52
|
-
null,
|
|
53
|
-
);
|
|
54
|
-
|
|
55
|
-
export function useMiniAppShellTheme(): MiniAppShellContextValue {
|
|
56
|
-
const v = useContext(MiniAppShellContext);
|
|
57
|
-
if (!v) {
|
|
58
|
-
throw new Error('useMiniAppShellTheme must be used within MiniAppRoot');
|
|
59
|
-
}
|
|
60
|
-
return v;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export type MiniAppRootProps = {
|
|
64
|
-
children: ReactNode;
|
|
65
|
-
className?: string;
|
|
66
|
-
/** Included in READY payload when set. */
|
|
67
|
-
appId?: string;
|
|
68
|
-
onThemeChange?: (theme: ThemeSyncPayload) => void;
|
|
69
|
-
/** Overrides `@homecode/ui` `<Theme config>` builder (defaults to generic mini-app palette). */
|
|
70
|
-
getThemeConfig?: (isDarkMode: boolean) => MiniAppThemeConfig;
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
export function MiniAppRoot({
|
|
74
|
-
children,
|
|
75
|
-
className,
|
|
76
|
-
appId,
|
|
77
|
-
onThemeChange,
|
|
78
|
-
getThemeConfig,
|
|
79
|
-
}: MiniAppRootProps): React.ReactElement {
|
|
80
|
-
const [theme, setTheme] = useState<ThemeSyncPayload>(() =>
|
|
81
|
-
isEmbeddedMiniApp() ? defaultTheme : themeFromDocument(),
|
|
82
|
-
);
|
|
83
|
-
const onThemeChangeRef = useRef(onThemeChange);
|
|
84
|
-
onThemeChangeRef.current = onThemeChange;
|
|
85
|
-
|
|
86
|
-
const getThemeConfigRef = useRef(
|
|
87
|
-
getThemeConfig ?? getDefaultMiniAppThemeConfig,
|
|
88
|
-
);
|
|
89
|
-
getThemeConfigRef.current = getThemeConfig ?? getDefaultMiniAppThemeConfig;
|
|
90
|
-
|
|
91
|
-
const currThemeConfig = useMemo(
|
|
92
|
-
() => getThemeConfigRef.current(theme.isDarkMode),
|
|
93
|
-
[theme.isDarkMode],
|
|
94
|
-
);
|
|
95
|
-
|
|
96
|
-
const sendReady = useCallback(() => {
|
|
97
|
-
if (!window.parent || window.parent === window) return;
|
|
98
|
-
const payload = appId ? { appId } : {};
|
|
99
|
-
const msg = buildReadyMessage(payload);
|
|
100
|
-
const target = resolveParentOriginFromReferrer();
|
|
101
|
-
|
|
102
|
-
if (target) {
|
|
103
|
-
window.parent.postMessage(msg, target);
|
|
104
|
-
} else {
|
|
105
|
-
window.parent.postMessage(msg, '*');
|
|
106
|
-
}
|
|
107
|
-
}, [appId]);
|
|
108
|
-
|
|
109
|
-
useEffect(() => {
|
|
110
|
-
if (!isEmbeddedMiniApp()) return;
|
|
111
|
-
applyThemeToDocument(theme.mode);
|
|
112
|
-
}, [theme.mode]);
|
|
113
|
-
|
|
114
|
-
useEffect(() => {
|
|
115
|
-
const onMessage = (event: MessageEvent) => {
|
|
116
|
-
if (!isTrustedMiniAppParentMessage(event)) return;
|
|
117
|
-
const parsed = parseThemeSyncMessage(event.data);
|
|
118
|
-
if (!parsed) return;
|
|
119
|
-
setTheme(parsed);
|
|
120
|
-
onThemeChangeRef.current?.(parsed);
|
|
121
|
-
};
|
|
122
|
-
window.addEventListener('message', onMessage);
|
|
123
|
-
return () => window.removeEventListener('message', onMessage);
|
|
124
|
-
}, []);
|
|
125
|
-
|
|
126
|
-
useEffect(() => {
|
|
127
|
-
sendReady();
|
|
128
|
-
if (document.readyState === 'complete') return;
|
|
129
|
-
window.addEventListener('load', sendReady);
|
|
130
|
-
return () => window.removeEventListener('load', sendReady);
|
|
131
|
-
}, [sendReady]);
|
|
132
|
-
|
|
133
|
-
const ctx = useMemo((): MiniAppShellContextValue => ({ theme }), [theme]);
|
|
134
|
-
|
|
135
|
-
return (
|
|
136
|
-
<MiniAppShellContext.Provider value={ctx}>
|
|
137
|
-
<Theme config={currThemeConfig} />
|
|
138
|
-
<Scroll
|
|
139
|
-
y
|
|
140
|
-
fadeSize="l"
|
|
141
|
-
className={cn(S.root, className)}
|
|
142
|
-
innerClassName={S.inner}
|
|
143
|
-
offset={{ y: { before: 50, after: 50 } }}
|
|
144
|
-
autoHide
|
|
145
|
-
>
|
|
146
|
-
{children}
|
|
147
|
-
</Scroll>
|
|
148
|
-
</MiniAppShellContext.Provider>
|
|
149
|
-
);
|
|
150
|
-
}
|
package/src/mini-app/index.ts
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
export {
|
|
2
|
-
applyThemeToDocument,
|
|
3
|
-
buildChatSendMessage,
|
|
4
|
-
buildDataRequestMessage,
|
|
5
|
-
buildReadyMessage,
|
|
6
|
-
MINIAPP_CHANNEL,
|
|
7
|
-
MINIAPP_VERSION,
|
|
8
|
-
parseChatSendResultMessage,
|
|
9
|
-
parseDataResponseMessage,
|
|
10
|
-
parseThemeSyncMessage,
|
|
11
|
-
isTrustedMiniAppParentMessage,
|
|
12
|
-
resolveParentOriginFromReferrer,
|
|
13
|
-
} from './miniAppProtocol';
|
|
14
|
-
export type {
|
|
15
|
-
MiniAppMessageReady,
|
|
16
|
-
MiniAppMessageThemeSync,
|
|
17
|
-
MiniAppMessageDataRequest,
|
|
18
|
-
MiniAppMessageDataResponse,
|
|
19
|
-
MiniAppMessageChatSend,
|
|
20
|
-
MiniAppMessageChatSendResult,
|
|
21
|
-
MiniAppDataRequestPayload,
|
|
22
|
-
MiniAppDataResponsePayload,
|
|
23
|
-
MiniAppChatSendPayload,
|
|
24
|
-
MiniAppChatSendResultPayload,
|
|
25
|
-
MiniAppDataOp,
|
|
26
|
-
ThemeSyncPayload,
|
|
27
|
-
} from './miniAppProtocol';
|
|
28
|
-
export { createMiniAppDataClient } from './miniAppDataClient';
|
|
29
|
-
export type {
|
|
30
|
-
MiniAppDataClientOptions,
|
|
31
|
-
MiniAppDataClient,
|
|
32
|
-
} from './miniAppDataClient';
|
|
33
|
-
export type {
|
|
34
|
-
MiniAppDataset,
|
|
35
|
-
MiniAppDriversComparisonSnapshot,
|
|
36
|
-
MiniAppForecastMap,
|
|
37
|
-
MiniAppPerformanceBundle,
|
|
38
|
-
} from './miniAppDataTypes';
|
|
39
|
-
export { getDefaultMiniAppThemeConfig } from './miniAppThemeConfig';
|
|
40
|
-
export type { MiniAppThemeConfig } from './miniAppThemeConfig';
|
|
41
|
-
export { sendChatMessage } from './miniAppChatBridge';
|
|
42
|
-
export { MiniAppRoot, useMiniAppShellTheme } from './MiniAppRoot';
|
|
43
|
-
export type { MiniAppRootProps, MiniAppShellContextValue } from './MiniAppRoot';
|