@sybilion/uilib 1.1.0 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/README.md +8 -8
  2. package/assets/{mini-app-global.css → standalone-global.css} +1 -1
  3. package/dist/esm/components/ui/Image/Image.styl.js +1 -1
  4. package/dist/esm/components/ui/NavUserHeader/NavUserHeader.js +28 -0
  5. package/dist/esm/components/ui/NavUserHeader/NavUserHeader.styl.js +7 -0
  6. package/dist/esm/components/ui/Sidebar/Sidebar.styl.js +2 -2
  7. package/dist/esm/components/widgets/SidebarDatasetsItemsGrouped/SidebarDatasetsItemsGrouped.js +48 -0
  8. package/dist/esm/components/widgets/SidebarDatasetsItemsGrouped/SidebarDatasetsItemsGrouped.styl.js +7 -0
  9. package/dist/esm/components/widgets/SidebarDatasetsItemsGrouped/groupSidebarDatasets.js +38 -0
  10. package/dist/esm/index.js +6 -5
  11. package/dist/esm/sybilion-auth/SybilionAuthProvider.js +208 -0
  12. package/dist/esm/sybilion-auth/authPaths.js +7 -0
  13. package/dist/esm/sybilion-auth/exchangeSybilionToken.js +44 -0
  14. package/dist/esm/types/src/components/ui/Input/Input.d.ts +1 -1
  15. package/dist/esm/types/src/components/ui/NavUserHeader/NavUserHeader.d.ts +2 -0
  16. package/dist/esm/types/src/components/ui/NavUserHeader/NavUserHeader.types.d.ts +25 -0
  17. package/dist/esm/types/src/components/ui/NavUserHeader/index.d.ts +2 -0
  18. package/dist/esm/types/src/components/widgets/SidebarDatasetsItemsGrouped/SidebarDatasetsItemsGrouped.d.ts +11 -0
  19. package/dist/esm/types/src/components/widgets/SidebarDatasetsItemsGrouped/groupSidebarDatasets.d.ts +8 -0
  20. package/dist/esm/types/src/components/widgets/SidebarDatasetsItemsGrouped/index.d.ts +3 -0
  21. package/dist/esm/types/src/docs/pages/NavUserHeaderPage.d.ts +1 -0
  22. package/dist/esm/types/src/docs/pages/SidebarDatasetsItemsGroupedPage.d.ts +1 -0
  23. package/dist/esm/types/src/docs/pages/SybilionAuthProviderPage.d.ts +1 -0
  24. package/dist/esm/types/src/index.d.ts +4 -1
  25. package/dist/esm/types/src/sybilion-auth/SybilionAuthProvider.d.ts +42 -0
  26. package/dist/esm/types/src/sybilion-auth/authPaths.d.ts +3 -0
  27. package/dist/esm/types/src/sybilion-auth/exchangeSybilionToken.d.ts +4 -0
  28. package/dist/esm/types/src/sybilion-auth/index.d.ts +4 -0
  29. package/dist/esm/types/src/{mini-app/miniAppDataTypes.d.ts → types/sybilionDatasetSnapshots.d.ts} +5 -8
  30. package/docs/standalone-apps.md +181 -0
  31. package/package.json +15 -3
  32. package/src/components/ui/Image/Image.styl +1 -0
  33. package/src/components/ui/NavUserHeader/NavUserHeader.styl +125 -0
  34. package/src/components/ui/NavUserHeader/NavUserHeader.styl.d.ts +28 -0
  35. package/src/components/ui/NavUserHeader/NavUserHeader.tsx +148 -0
  36. package/src/components/ui/NavUserHeader/NavUserHeader.types.ts +27 -0
  37. package/src/components/ui/NavUserHeader/avatar.svg +4 -0
  38. package/src/components/ui/NavUserHeader/index.ts +5 -0
  39. package/src/components/ui/Sidebar/Sidebar.styl +0 -25
  40. package/src/components/ui/Sidebar/Sidebar.styl.d.ts +0 -1
  41. package/src/components/widgets/SidebarDatasetsItemsGrouped/SidebarDatasetsItemsGrouped.styl +29 -0
  42. package/src/{mini-app/MiniAppRoot.styl.d.ts → components/widgets/SidebarDatasetsItemsGrouped/SidebarDatasetsItemsGrouped.styl.d.ts} +4 -2
  43. package/src/components/widgets/SidebarDatasetsItemsGrouped/SidebarDatasetsItemsGrouped.tsx +128 -0
  44. package/src/components/widgets/SidebarDatasetsItemsGrouped/groupSidebarDatasets.ts +51 -0
  45. package/src/components/widgets/SidebarDatasetsItemsGrouped/index.ts +10 -0
  46. package/src/docs/pages/NavUserHeaderPage.tsx +89 -0
  47. package/src/docs/pages/SidebarDatasetsItemsGroupedPage.tsx +136 -0
  48. package/src/docs/pages/SybilionAuthProviderPage.tsx +40 -0
  49. package/src/docs/registry.ts +15 -3
  50. package/src/index.ts +4 -1
  51. package/src/sybilion-auth/SybilionAuthProvider.tsx +344 -0
  52. package/src/sybilion-auth/authPaths.ts +6 -0
  53. package/src/sybilion-auth/exchangeSybilionToken.ts +51 -0
  54. package/src/sybilion-auth/index.ts +17 -0
  55. package/src/{mini-app/miniAppDataTypes.ts → types/sybilionDatasetSnapshots.ts} +5 -8
  56. package/dist/esm/mini-app/MiniAppRoot.js +0 -82
  57. package/dist/esm/mini-app/MiniAppRoot.styl.js +0 -7
  58. package/dist/esm/mini-app/miniAppChatBridge.js +0 -45
  59. package/dist/esm/mini-app/miniAppDataClient.js +0 -98
  60. package/dist/esm/mini-app/miniAppProtocol.js +0 -153
  61. package/dist/esm/mini-app/miniAppThemeConfig.js +0 -40
  62. package/dist/esm/types/src/docs/pages/MiniAppRootPage.d.ts +0 -1
  63. package/dist/esm/types/src/mini-app/MiniAppRoot.d.ts +0 -18
  64. package/dist/esm/types/src/mini-app/index.d.ts +0 -10
  65. package/dist/esm/types/src/mini-app/miniAppChatBridge.d.ts +0 -6
  66. package/dist/esm/types/src/mini-app/miniAppDataClient.d.ts +0 -16
  67. package/dist/esm/types/src/mini-app/miniAppProtocol.d.ts +0 -89
  68. package/dist/esm/types/src/mini-app/miniAppThemeConfig.d.ts +0 -3
  69. package/docs/workspace-mini-apps.md +0 -51
  70. package/src/docs/pages/MiniAppRootPage.tsx +0 -58
  71. package/src/mini-app/MiniAppRoot.styl +0 -24
  72. package/src/mini-app/MiniAppRoot.tsx +0 -150
  73. package/src/mini-app/index.ts +0 -43
  74. package/src/mini-app/miniAppChatBridge.ts +0 -55
  75. package/src/mini-app/miniAppDataClient.ts +0 -165
  76. package/src/mini-app/miniAppProtocol.ts +0 -247
  77. package/src/mini-app/miniAppThemeConfig.ts +0 -45
@@ -1,98 +0,0 @@
1
- import { buildDataRequestMessage, resolveParentOriginFromReferrer, isTrustedMiniAppParentMessage, parseDataResponseMessage } from './miniAppProtocol.js';
2
-
3
- const DEFAULT_TIMEOUT_MS = 10_000;
4
- /** One listener per browsing context; tracks in-flight bridge requests by `requestId`. */
5
- function createMiniAppDataClient(options) {
6
- const timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
7
- const pending = new Map();
8
- let listening = false;
9
- const settle = (rid, fn) => {
10
- const p = pending.get(rid);
11
- if (!p)
12
- return;
13
- clearTimeout(p.timer);
14
- pending.delete(rid);
15
- fn(p);
16
- };
17
- function ensureListener() {
18
- if (listening || typeof window === 'undefined')
19
- return;
20
- listening = true;
21
- window.addEventListener('message', (event) => {
22
- if (!isTrustedMiniAppParentMessage(event))
23
- return;
24
- const msg = parseDataResponseMessage(event.data);
25
- if (!msg)
26
- return;
27
- settle(msg.requestId, p => {
28
- if (msg.ok) {
29
- p.resolve(msg.result);
30
- }
31
- else {
32
- p.reject(new Error(typeof msg.error === 'string'
33
- ? msg.error
34
- : 'Mini-app data request failed'));
35
- }
36
- });
37
- });
38
- }
39
- function request(payload) {
40
- if (typeof window === 'undefined' || window.parent === window) {
41
- throw new Error('MiniAppDataClient works only inside an iframe embed');
42
- }
43
- ensureListener();
44
- const requestId = typeof crypto !== 'undefined' && 'randomUUID' in crypto
45
- ? crypto.randomUUID()
46
- : `miniapp-${Date.now()}-${Math.random().toString(36).slice(2)}`;
47
- const envelope = buildDataRequestMessage({
48
- ...payload,
49
- requestId,
50
- });
51
- const target = resolveParentOriginFromReferrer();
52
- return new Promise((resolve, reject) => {
53
- const timer = setTimeout(() => {
54
- settle(requestId, p => {
55
- p.reject(new Error('Mini-app data request timed out'));
56
- });
57
- }, timeoutMs);
58
- pending.set(requestId, {
59
- resolve,
60
- reject,
61
- timer,
62
- });
63
- try {
64
- if (target) {
65
- window.parent.postMessage(envelope, target);
66
- }
67
- else {
68
- window.parent.postMessage(envelope, '*');
69
- }
70
- }
71
- catch (e) {
72
- settle(requestId, p => {
73
- p.reject(e instanceof Error ? e : new Error('Mini-app postMessage failed'));
74
- });
75
- }
76
- });
77
- }
78
- async function rq(op, params) {
79
- return request({ op, params });
80
- }
81
- return {
82
- getDatasets: () => rq('getDatasets'),
83
- getDataset: id => rq('getDataset', { id }),
84
- getForecasts: datasetId => rq('getForecasts', { datasetId }),
85
- getForecast: (datasetId, analysisId) => rq('getForecast', { datasetId, analysisId }),
86
- getDrivers: (datasetId, analysisId) => rq('getDrivers', { datasetId, analysisId }),
87
- getPerformanceData: (datasetId, analysisId) => rq('getPerformanceData', {
88
- datasetId,
89
- analysisId,
90
- }),
91
- getDriversComparisonData: (datasetId, analysisId) => rq('getDriversComparisonData', {
92
- datasetId,
93
- analysisId,
94
- }),
95
- };
96
- }
97
-
98
- export { createMiniAppDataClient };
@@ -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,3 +0,0 @@
1
- /** Homecode `<Theme config={...}>` shape for workspace mini-apps (generic palette). */
2
- export declare function getDefaultMiniAppThemeConfig(isDarkMode: boolean): any;
3
- export type MiniAppThemeConfig = ReturnType<typeof getDefaultMiniAppThemeConfig>;
@@ -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)