@sybilion/uilib 1.0.21 → 1.0.23
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 +15 -42
- package/assets/favicon.svg +1 -0
- package/assets/fonts/Apparat-Black.woff2 +0 -0
- package/assets/fonts/Apparat-Book.woff2 +0 -0
- package/assets/fonts/Apparat-Heavy.woff2 +0 -0
- package/assets/fonts/Apparat-Light.woff2 +0 -0
- package/assets/fonts/Apparat-Medium.woff2 +0 -0
- package/assets/fonts/Apparat-Regular.woff2 +0 -0
- package/assets/fonts/Manrope-Bold.woff2 +0 -0
- package/assets/fonts/Manrope-Medium.woff2 +0 -0
- package/assets/fonts/Manrope-Regular.woff2 +0 -0
- package/assets/fonts/fonts.css +63 -0
- package/assets/globals.css +456 -0
- package/assets/index.html +18 -0
- package/assets/logo.svg +3 -0
- package/assets/mini-app-global.css +256 -0
- package/dist/esm/index.js +2 -0
- package/dist/esm/mini-app/MiniAppRoot.js +77 -0
- package/dist/esm/mini-app/miniAppProtocol.js +57 -0
- package/dist/esm/types/src/components/ui/Input/Input.d.ts +1 -1
- package/dist/esm/types/src/index.d.ts +1 -0
- package/dist/esm/types/src/mini-app/MiniAppRoot.d.ts +14 -0
- package/dist/esm/types/src/mini-app/index.d.ts +4 -0
- package/dist/esm/types/src/mini-app/miniAppProtocol.d.ts +30 -0
- package/docs/github-packages.md +106 -0
- package/docs/private-npm-registry.md +152 -0
- package/docs/workspace-mini-apps.md +21 -0
- package/package.json +5 -2
- package/src/index.ts +1 -0
- package/src/mini-app/MiniAppRoot.tsx +115 -0
- package/src/mini-app/index.ts +21 -0
- package/src/mini-app/miniAppProtocol.ts +79 -0
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mini-app token sheet — keep in sync with assets/globals.css (:root, breakpoints, .dark).
|
|
3
|
+
* Omits @theme inline and @layer base (Tailwind/@apply). For full parity use globals.css from this repo.
|
|
4
|
+
*/
|
|
5
|
+
@import './fonts/fonts.css';
|
|
6
|
+
|
|
7
|
+
* {
|
|
8
|
+
box-sizing: border-box;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
:root {
|
|
12
|
+
--sb-cyan-50: oklch(0.964 0.006 204);
|
|
13
|
+
--sb-cyan-100: oklch(0.933 0.011 204);
|
|
14
|
+
--sb-cyan-200: oklch(0.76 0.089 204);
|
|
15
|
+
--sb-cyan-300: oklch(0.7 0.098 204);
|
|
16
|
+
--sb-cyan-400: oklch(0.625 0.234 204);
|
|
17
|
+
--sb-cyan-500: oklch(0.518 0.258 204);
|
|
18
|
+
--sb-cyan-600: oklch(0.421 0.231 204);
|
|
19
|
+
--sb-cyan-700: oklch(0.388 0.042 204);
|
|
20
|
+
--sb-cyan-800: oklch(0.338 0.026 204);
|
|
21
|
+
--sb-cyan-900: oklch(0.23 0.017 204);
|
|
22
|
+
--sb-purple-50: oklch(0.964 0.021 304);
|
|
23
|
+
--sb-purple-100: oklch(0.933 0.039 303.4);
|
|
24
|
+
--sb-purple-200: oklch(0.76 0.148 301.5);
|
|
25
|
+
--sb-purple-300: oklch(0.719 0.174 300.6);
|
|
26
|
+
--sb-purple-400: oklch(0.625 0.234 297.8);
|
|
27
|
+
--sb-purple-500: oklch(0.518 0.258 292.6);
|
|
28
|
+
--sb-purple-600: oklch(0.421 0.231 289);
|
|
29
|
+
--sb-purple-700: oklch(0.33 0.179 289.7);
|
|
30
|
+
--sb-purple-800: oklch(0.238 0.123 292.3);
|
|
31
|
+
--sb-purple-900: oklch(0.23 0.049 301.1);
|
|
32
|
+
--sb-red-50: oklch(0.969 0.015 22.4);
|
|
33
|
+
--sb-red-100: oklch(0.942 0.029 23);
|
|
34
|
+
--sb-red-200: oklch(0.8 0.114 24.5);
|
|
35
|
+
--sb-red-300: oklch(0.769 0.137 25);
|
|
36
|
+
--sb-red-400: oklch(0.7 0.191 27.2);
|
|
37
|
+
--sb-red-500: oklch(0.606 0.194 28.6);
|
|
38
|
+
--sb-red-600: oklch(0.539 0.183 28.8);
|
|
39
|
+
--sb-red-700: oklch(0.427 0.155 29.5);
|
|
40
|
+
--sb-red-800: oklch(0.311 0.107 29.3);
|
|
41
|
+
--sb-red-900: oklch(0.232 0.019 24.1);
|
|
42
|
+
--sb-green-50: oklch(0.981 0.028 158.7);
|
|
43
|
+
--sb-green-100: oklch(0.949 0.08 157.2);
|
|
44
|
+
--sb-green-200: oklch(0.909 0.154 154.2);
|
|
45
|
+
--sb-green-300: oklch(0.859 0.196 151.7);
|
|
46
|
+
--sb-green-400: oklch(0.823 0.216 149.8);
|
|
47
|
+
--sb-green-500: oklch(0.748 0.208 148.6);
|
|
48
|
+
--sb-green-600: oklch(0.641 0.155 151.1);
|
|
49
|
+
--sb-green-700: oklch(0.482 0.107 152.1);
|
|
50
|
+
--sb-green-800: oklch(0.365 0.079 152.3);
|
|
51
|
+
--sb-green-900: oklch(0.254 0.023 157.2);
|
|
52
|
+
--sb-yellow-50: oklch(0.984 0.014 78.3);
|
|
53
|
+
--sb-yellow-100: oklch(0.956 0.025 78.9);
|
|
54
|
+
--sb-yellow-200: oklch(0.927 0.041 76.7);
|
|
55
|
+
--sb-yellow-300: oklch(0.844 0.1 75.5);
|
|
56
|
+
--sb-yellow-400: oklch(0.771 0.128 73.6);
|
|
57
|
+
--sb-yellow-500: oklch(0.691 0.128 71.8);
|
|
58
|
+
--sb-yellow-600: oklch(0.624 0.109 73.2);
|
|
59
|
+
--sb-yellow-700: oklch(0.481 0.083 73.3);
|
|
60
|
+
--sb-yellow-800: oklch(0.356 0.058 73.8);
|
|
61
|
+
--sb-yellow-900: oklch(0.251 0.016 79.5);
|
|
62
|
+
--sb-gray-50: oklch(0.98 0 0);
|
|
63
|
+
--sb-gray-100: oklch(0.949 0 0);
|
|
64
|
+
--sb-gray-200: oklch(0.909 0 0);
|
|
65
|
+
--sb-gray-300: oklch(0.859 0 0);
|
|
66
|
+
--sb-gray-400: oklch(0.823 0 0);
|
|
67
|
+
--sb-gray-500: oklch(0.748 0 0);
|
|
68
|
+
--sb-gray-600: oklch(0.641 0 0);
|
|
69
|
+
--sb-gray-700: oklch(0.482 0 0);
|
|
70
|
+
--sb-gray-800: oklch(0.365 0 0);
|
|
71
|
+
--sb-gray-900: oklch(0.254 0 0);
|
|
72
|
+
--sb-slate-50: oklch(0.9843 0.0011 197.14);
|
|
73
|
+
--sb-slate-100: oklch(0.9622 0.0035 219.53);
|
|
74
|
+
--sb-slate-200: oklch(0.8882 0.0101 212.52);
|
|
75
|
+
--sb-slate-300: oklch(0.8119 0.0139 214.37);
|
|
76
|
+
--sb-slate-400: oklch(0.7315 0.0168 216.72);
|
|
77
|
+
--sb-slate-500: oklch(0.6489 0.0179 211.06);
|
|
78
|
+
--sb-slate-600: oklch(0.5648 0.0184 211.07);
|
|
79
|
+
--sb-slate-700: oklch(0.4723 0.0152 208.74);
|
|
80
|
+
--sb-slate-800: oklch(0.3759 0.0107 205.8);
|
|
81
|
+
--sb-slate-900: oklch(0.2732 0.0061 214.4);
|
|
82
|
+
--sb-slate-950: oklch(0.1579 0.0017 196.99);
|
|
83
|
+
--bp-mobile: 384px;
|
|
84
|
+
--bp-tablet: 768px;
|
|
85
|
+
--bp-desktop: 1024px;
|
|
86
|
+
--p-24: 96px;
|
|
87
|
+
--p-23: 92px;
|
|
88
|
+
--p-20: 80px;
|
|
89
|
+
--p-19: 76px;
|
|
90
|
+
--p-18: 72px;
|
|
91
|
+
--p-17: 68px;
|
|
92
|
+
--p-16: 64px;
|
|
93
|
+
--p-12: 48px;
|
|
94
|
+
--p-11: 44px;
|
|
95
|
+
--p-10: 40px;
|
|
96
|
+
--p-9: 36px;
|
|
97
|
+
--p-8: 32px;
|
|
98
|
+
--p-7: 28px;
|
|
99
|
+
--p-6: 24px;
|
|
100
|
+
--p-5: 20px;
|
|
101
|
+
--p-4: 16px;
|
|
102
|
+
--p-3: 12px;
|
|
103
|
+
--p-2: 8px;
|
|
104
|
+
--p-1: 4px;
|
|
105
|
+
--text-xs: 12px;
|
|
106
|
+
--text-sm: 14px;
|
|
107
|
+
--text-base: 16px;
|
|
108
|
+
--text-lg: 18px;
|
|
109
|
+
--text-xl: 20px;
|
|
110
|
+
--text-2xl: 24px;
|
|
111
|
+
--text-3xl: 30px;
|
|
112
|
+
--text-4xl: 36px;
|
|
113
|
+
--text-5xl: 48px;
|
|
114
|
+
|
|
115
|
+
--spacing-3xs: 2px;
|
|
116
|
+
--spacing-2xs: 4px;
|
|
117
|
+
--spacing-xs: 6px;
|
|
118
|
+
--spacing-sm: 8px;
|
|
119
|
+
--spacing-md: 12px;
|
|
120
|
+
--spacing-lg: 16px;
|
|
121
|
+
--spacing-xl: 20px;
|
|
122
|
+
--spacing-2xl: 24px;
|
|
123
|
+
--spacing-3xl: 32px;
|
|
124
|
+
|
|
125
|
+
--font-family-heading: 'KMR Apparat', sans-serif;
|
|
126
|
+
--font-family-body: 'Manrope', sans-serif;
|
|
127
|
+
|
|
128
|
+
--brand-color: var(--sb-purple-400);
|
|
129
|
+
--brand-color-50: var(--sb-purple-50);
|
|
130
|
+
--brand-color-100: var(--sb-purple-100);
|
|
131
|
+
--brand-color-200: var(--sb-purple-200);
|
|
132
|
+
--brand-color-300: var(--sb-purple-300);
|
|
133
|
+
--brand-color-400: var(--sb-purple-400);
|
|
134
|
+
--brand-color-500: var(--sb-purple-500);
|
|
135
|
+
--brand-color-600: var(--sb-purple-600);
|
|
136
|
+
--brand-color-700: var(--sb-purple-700);
|
|
137
|
+
--brand-color-800: var(--sb-purple-800);
|
|
138
|
+
--brand-color-900: var(--sb-purple-900);
|
|
139
|
+
--header-height: 94px;
|
|
140
|
+
--page-x-padding: var(--p-16);
|
|
141
|
+
--page-y-padding: var(--p-12);
|
|
142
|
+
--page-color: oklch(1 0 0);
|
|
143
|
+
--page-color-alpha-800: oklch(0.99 0 0 / 0.8);
|
|
144
|
+
--background: var(--sb-slate-100);
|
|
145
|
+
--background-alpha-800: var(--sb-slate-100);
|
|
146
|
+
--background-alpha-700: oklch(0.9622 0.0035 219.53 / 0.7);
|
|
147
|
+
--background-alpha-500: oklch(0.9622 0.0035 219.53 / 0.5);
|
|
148
|
+
--foreground: oklch(0.15 0 0);
|
|
149
|
+
--card: oklch(1 0 0);
|
|
150
|
+
--card-foreground: oklch(0.15 0 0);
|
|
151
|
+
--popover: oklch(1 0 0);
|
|
152
|
+
--popover-foreground: oklch(0.15 0 0);
|
|
153
|
+
--primary: oklch(0.25 0 0);
|
|
154
|
+
--primary-foreground: oklch(0.99 0 0);
|
|
155
|
+
--secondary: oklch(0.96 0 0);
|
|
156
|
+
--secondary-800: oklch(0.96 0 0 / 0.8);
|
|
157
|
+
--secondary-foreground: oklch(0.25 0 0);
|
|
158
|
+
--muted: oklch(0.965 0 0);
|
|
159
|
+
--muted-50: oklch(0.98 0 0);
|
|
160
|
+
--muted-foreground: var(--sb-slate-600);
|
|
161
|
+
--muted-border: var(--sb-slate-400);
|
|
162
|
+
--accent: var(--sb-slate-100);
|
|
163
|
+
--accent-500: oklch(0.96 0 0 / 0.5);
|
|
164
|
+
--accent-foreground: oklch(0.25 0 0);
|
|
165
|
+
--destructive: oklch(0.577 0.245 27.325);
|
|
166
|
+
--destructive-100: oklch(0.577 0.245 27.325 / 0.1);
|
|
167
|
+
--destructive-200: oklch(0.577 0.245 27.325 / 0.2);
|
|
168
|
+
--destructive-400: oklch(0.577 0.245 27.325 / 0.4);
|
|
169
|
+
--destructive-600: oklch(0.577 0.245 27.325 / 0.6);
|
|
170
|
+
--destructive-900: oklch(0.577 0.245 27.325 / 0.9);
|
|
171
|
+
--border: oklch(0.9 0 0);
|
|
172
|
+
--input: oklch(0.94 0 0);
|
|
173
|
+
--input-30: oklch(0.94 0 0 / 0.3);
|
|
174
|
+
--ring: oklch(0.65 0 0);
|
|
175
|
+
--ring-50: oklch(0.65 0 0 / 0.5);
|
|
176
|
+
--sidebar: oklch(1 0 0);
|
|
177
|
+
--sidebar-foreground: oklch(0.2 0 0);
|
|
178
|
+
--sidebar-primary: oklch(0.25 0 0);
|
|
179
|
+
--sidebar-primary-foreground: oklch(0.99 0 0);
|
|
180
|
+
--sidebar-accent: var(--sb-slate-100);
|
|
181
|
+
--sidebar-accent-foreground: oklch(0.25 0 0);
|
|
182
|
+
--sidebar-border: oklch(0.9 0 0);
|
|
183
|
+
--sidebar-ring: oklch(0.65 0 0);
|
|
184
|
+
|
|
185
|
+
--sb-link-color: var(--brand-color-500);
|
|
186
|
+
--sb-link-visited-color: var(--brand-color-700);
|
|
187
|
+
--sb-link-color-hover: var(--brand-color-600);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
@media (max-width: var(--bp-mobile)) {
|
|
191
|
+
:root {
|
|
192
|
+
--header-height: 84px;
|
|
193
|
+
--page-x-padding: var(--p-6);
|
|
194
|
+
--page-y-padding: var(--p-6);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
.dark {
|
|
199
|
+
--page-color: oklch(0.14 0 0);
|
|
200
|
+
--page-color-alpha-800: oklch(0.14 0 0 / 0.95);
|
|
201
|
+
--background: oklch(0.22 0 0);
|
|
202
|
+
--background-alpha-800: oklch(0.2242 0 0 / 0.8);
|
|
203
|
+
--background-alpha-700: oklch(0.22 0 0 / 0.7);
|
|
204
|
+
--background-alpha-500: oklch(0.22 0 0 / 0.5);
|
|
205
|
+
--foreground: oklch(0.95 0 0);
|
|
206
|
+
--card: oklch(0.1 0 0);
|
|
207
|
+
--card-foreground: oklch(0.95 0 0);
|
|
208
|
+
--popover: oklch(0.16 0 0);
|
|
209
|
+
--popover-foreground: oklch(0.95 0 0);
|
|
210
|
+
--primary: oklch(0.9 0 0);
|
|
211
|
+
--primary-foreground: oklch(0.14 0 0);
|
|
212
|
+
--secondary: oklch(0.22 0 0);
|
|
213
|
+
--secondary-800: oklch(0.22 0 0 / 0.8);
|
|
214
|
+
--secondary-foreground: oklch(0.95 0 0);
|
|
215
|
+
--muted: oklch(0.2 0 0);
|
|
216
|
+
--muted-50: oklch(0.2 0 0);
|
|
217
|
+
--muted-foreground: oklch(0.6 0 0);
|
|
218
|
+
--muted-border: var(--sb-slate-600);
|
|
219
|
+
--accent: oklch(0.27 0 0);
|
|
220
|
+
--accent-500: oklch(0.27 0 0 / 0.5);
|
|
221
|
+
--accent-foreground: oklch(0.95 0 0);
|
|
222
|
+
--destructive: oklch(0.704 0.191 22.216);
|
|
223
|
+
--destructive-200: oklch(0.704 0.191 22.216 / 0.2);
|
|
224
|
+
--destructive-400: oklch(0.704 0.191 22.216 / 0.4);
|
|
225
|
+
--destructive-600: oklch(0.704 0.191 22.216 / 0.6);
|
|
226
|
+
--destructive-900: oklch(0.704 0.191 22.216 / 0.9);
|
|
227
|
+
--border: oklch(0.3 0 0 / 0.8);
|
|
228
|
+
--input: oklch(1 0 0 / 16%);
|
|
229
|
+
--input-30: oklch(1 0 0 / 0.3);
|
|
230
|
+
--ring: oklch(0.5 0 0);
|
|
231
|
+
--ring-50: oklch(0.5 0 0 / 0.5);
|
|
232
|
+
--sidebar: oklch(0.16 0 0);
|
|
233
|
+
--sidebar-foreground: oklch(0.9 0 0);
|
|
234
|
+
--sidebar-primary: oklch(0.9 0 0);
|
|
235
|
+
--sidebar-primary-foreground: oklch(0.14 0 0);
|
|
236
|
+
--sidebar-accent: oklch(0.22 0 0);
|
|
237
|
+
--sidebar-accent-foreground: oklch(0.95 0 0);
|
|
238
|
+
--sidebar-border: oklch(0.3 0 0);
|
|
239
|
+
--sidebar-ring: oklch(0.5 0 0);
|
|
240
|
+
--sb-link-color: var(--brand-color-400);
|
|
241
|
+
--sb-link-visited-color: var(--brand-color-600);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
html {
|
|
245
|
+
background-color: var(--background);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
body {
|
|
249
|
+
min-height: 100vh;
|
|
250
|
+
margin: 0;
|
|
251
|
+
background-color: var(--background);
|
|
252
|
+
color: var(--foreground);
|
|
253
|
+
font-family: var(--font-family-body);
|
|
254
|
+
font-size: var(--text-sm);
|
|
255
|
+
line-height: 1.6;
|
|
256
|
+
}
|
package/dist/esm/index.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
export { MINIAPP_CHANNEL, MINIAPP_VERSION, applyThemeToDocument, buildReadyMessage, parseThemeSyncMessage, resolveParentOriginFromReferrer } from './mini-app/miniAppProtocol.js';
|
|
2
|
+
export { MiniAppRoot, useMiniAppShellTheme } from './mini-app/MiniAppRoot.js';
|
|
1
3
|
export { ChatContext, ChatProvider, useChat, useChats, useChatsForDataset, useChatsForScopeId, useCurrentChat } from './contexts/chat-context.js';
|
|
2
4
|
export { AnalysesSelector } from './components/ui/AnalysesSelector/AnalysesSelector.js';
|
|
3
5
|
export { AnalysisLineIcon } from './components/ui/AnalysisLineIcon/AnalysisLineIcon.js';
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { createContext, useContext, useState, useRef, useCallback, useEffect, useMemo } from 'react';
|
|
3
|
+
import { resolveParentOriginFromReferrer, applyThemeToDocument, buildReadyMessage, parseThemeSyncMessage } from './miniAppProtocol.js';
|
|
4
|
+
|
|
5
|
+
const defaultTheme = {
|
|
6
|
+
mode: 'light',
|
|
7
|
+
isDarkMode: false,
|
|
8
|
+
};
|
|
9
|
+
const MiniAppShellContext = createContext(null);
|
|
10
|
+
function useMiniAppShellTheme() {
|
|
11
|
+
const v = useContext(MiniAppShellContext);
|
|
12
|
+
if (!v) {
|
|
13
|
+
throw new Error('useMiniAppShellTheme must be used within MiniAppRoot');
|
|
14
|
+
}
|
|
15
|
+
return v;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Accept only messages that appear to come from the real embedding parent:
|
|
19
|
+
* - `source` must be `window.parent` (same as shell’s iframe target).
|
|
20
|
+
* - When `document.referrer` is present, `origin` must match it (Sybilion page that loaded this iframe).
|
|
21
|
+
* If referrer was stripped (Referrer-Policy), we only rely on `source` matching `parent`.
|
|
22
|
+
*/
|
|
23
|
+
function isTrustedParentMessage(event) {
|
|
24
|
+
// Ignore messages from other windows (e.g. popups, other iframes).
|
|
25
|
+
if (event.source !== window.parent)
|
|
26
|
+
return false;
|
|
27
|
+
const fromReferrer = resolveParentOriginFromReferrer();
|
|
28
|
+
// Tighten to embedder origin when the browser exposes it.
|
|
29
|
+
if (fromReferrer && event.origin !== fromReferrer)
|
|
30
|
+
return false;
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
function MiniAppRoot({ children, appId, onThemeChange, }) {
|
|
34
|
+
const [theme, setTheme] = useState(defaultTheme);
|
|
35
|
+
const onThemeChangeRef = useRef(onThemeChange);
|
|
36
|
+
onThemeChangeRef.current = onThemeChange;
|
|
37
|
+
const sendReady = useCallback(() => {
|
|
38
|
+
if (!window.parent || window.parent === window)
|
|
39
|
+
return;
|
|
40
|
+
const payload = appId ? { appId } : {};
|
|
41
|
+
const msg = buildReadyMessage(payload);
|
|
42
|
+
const target = resolveParentOriginFromReferrer();
|
|
43
|
+
if (target) {
|
|
44
|
+
window.parent.postMessage(msg, target);
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
window.parent.postMessage(msg, '*');
|
|
48
|
+
}
|
|
49
|
+
}, [appId]);
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
applyThemeToDocument(theme.mode);
|
|
52
|
+
}, [theme.mode]);
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
const onMessage = (event) => {
|
|
55
|
+
if (!isTrustedParentMessage(event))
|
|
56
|
+
return;
|
|
57
|
+
const parsed = parseThemeSyncMessage(event.data);
|
|
58
|
+
if (!parsed)
|
|
59
|
+
return;
|
|
60
|
+
setTheme(parsed);
|
|
61
|
+
onThemeChangeRef.current?.(parsed);
|
|
62
|
+
};
|
|
63
|
+
window.addEventListener('message', onMessage);
|
|
64
|
+
return () => window.removeEventListener('message', onMessage);
|
|
65
|
+
}, []);
|
|
66
|
+
useEffect(() => {
|
|
67
|
+
sendReady();
|
|
68
|
+
if (document.readyState === 'complete')
|
|
69
|
+
return;
|
|
70
|
+
window.addEventListener('load', sendReady);
|
|
71
|
+
return () => window.removeEventListener('load', sendReady);
|
|
72
|
+
}, [sendReady]);
|
|
73
|
+
const ctx = useMemo(() => ({ theme }), [theme]);
|
|
74
|
+
return (jsx(MiniAppShellContext.Provider, { value: ctx, children: children }));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export { MiniAppRoot, useMiniAppShellTheme };
|
|
@@ -0,0 +1,57 @@
|
|
|
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
|
+
const MINIAPP_CHANNEL = 'sybilion.miniapp';
|
|
6
|
+
const MINIAPP_VERSION = 1;
|
|
7
|
+
function isRecord(v) {
|
|
8
|
+
return typeof v === 'object' && v !== null && !Array.isArray(v);
|
|
9
|
+
}
|
|
10
|
+
/** Parse parent → child THEME_SYNC (shell uses `buildThemeSyncMessage`). */
|
|
11
|
+
function parseThemeSyncMessage(data) {
|
|
12
|
+
if (!isRecord(data))
|
|
13
|
+
return null;
|
|
14
|
+
if (data.channel !== MINIAPP_CHANNEL)
|
|
15
|
+
return null;
|
|
16
|
+
if (data.version !== MINIAPP_VERSION)
|
|
17
|
+
return null;
|
|
18
|
+
if (data.type !== 'THEME_SYNC')
|
|
19
|
+
return null;
|
|
20
|
+
const payload = data.payload;
|
|
21
|
+
if (!isRecord(payload))
|
|
22
|
+
return null;
|
|
23
|
+
const mode = payload.mode === 'dark' ? 'dark' : 'light';
|
|
24
|
+
const isDarkMode = typeof payload.isDarkMode === 'boolean'
|
|
25
|
+
? payload.isDarkMode
|
|
26
|
+
: mode === 'dark';
|
|
27
|
+
return { mode, isDarkMode };
|
|
28
|
+
}
|
|
29
|
+
/** Child → parent READY (optional `appId` for telemetry). */
|
|
30
|
+
function buildReadyMessage(payload = {}) {
|
|
31
|
+
return {
|
|
32
|
+
channel: MINIAPP_CHANNEL,
|
|
33
|
+
version: MINIAPP_VERSION,
|
|
34
|
+
type: 'READY',
|
|
35
|
+
payload,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
function resolveParentOriginFromReferrer() {
|
|
39
|
+
try {
|
|
40
|
+
if (typeof document !== 'undefined' && document.referrer) {
|
|
41
|
+
return new URL(document.referrer).origin;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
/* invalid referrer */
|
|
46
|
+
}
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
function applyThemeToDocument(mode) {
|
|
50
|
+
if (typeof document === 'undefined')
|
|
51
|
+
return;
|
|
52
|
+
const root = document.documentElement;
|
|
53
|
+
root.classList.remove('light', 'dark');
|
|
54
|
+
root.classList.add(mode);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export { MINIAPP_CHANNEL, MINIAPP_VERSION, applyThemeToDocument, buildReadyMessage, parseThemeSyncMessage, resolveParentOriginFromReferrer };
|
|
@@ -3,7 +3,7 @@ declare const Input: React.ForwardRefExoticComponent<(Omit<Omit<React.DetailedHT
|
|
|
3
3
|
type?: React.ComponentProps<"input">["type"];
|
|
4
4
|
size?: "sm" | "md" | "lg";
|
|
5
5
|
variant?: "default" | "clean";
|
|
6
|
-
}, "ref"> | Omit<Omit<React.DetailedHTMLProps<React.TextareaHTMLAttributes<HTMLTextAreaElement>, HTMLTextAreaElement>, "
|
|
6
|
+
}, "ref"> | Omit<Omit<React.DetailedHTMLProps<React.TextareaHTMLAttributes<HTMLTextAreaElement>, HTMLTextAreaElement>, "type" | "size"> & {
|
|
7
7
|
type: "textarea";
|
|
8
8
|
size?: "sm" | "md" | "lg";
|
|
9
9
|
variant?: "default" | "clean";
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { type ThemeSyncPayload } from './miniAppProtocol';
|
|
4
|
+
export type MiniAppShellContextValue = {
|
|
5
|
+
theme: ThemeSyncPayload;
|
|
6
|
+
};
|
|
7
|
+
export declare function useMiniAppShellTheme(): MiniAppShellContextValue;
|
|
8
|
+
export type MiniAppRootProps = {
|
|
9
|
+
children: ReactNode;
|
|
10
|
+
/** Included in READY payload when set. */
|
|
11
|
+
appId?: string;
|
|
12
|
+
onThemeChange?: (theme: ThemeSyncPayload) => void;
|
|
13
|
+
};
|
|
14
|
+
export declare function MiniAppRoot({ children, appId, onThemeChange, }: MiniAppRootProps): React.ReactElement;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { applyThemeToDocument, buildReadyMessage, MINIAPP_CHANNEL, MINIAPP_VERSION, parseThemeSyncMessage, resolveParentOriginFromReferrer, } from './miniAppProtocol';
|
|
2
|
+
export type { MiniAppMessageReady, MiniAppMessageThemeSync, ThemeSyncPayload, } from './miniAppProtocol';
|
|
3
|
+
export { MiniAppRoot, useMiniAppShellTheme, } from './MiniAppRoot';
|
|
4
|
+
export type { MiniAppRootProps, MiniAppShellContextValue, } from './MiniAppRoot';
|
|
@@ -0,0 +1,30 @@
|
|
|
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
|
+
export declare const MINIAPP_CHANNEL: "sybilion.miniapp";
|
|
6
|
+
export declare const MINIAPP_VERSION: 1;
|
|
7
|
+
export type ThemeSyncPayload = {
|
|
8
|
+
mode: 'light' | 'dark';
|
|
9
|
+
isDarkMode: boolean;
|
|
10
|
+
};
|
|
11
|
+
export type MiniAppMessageReady = {
|
|
12
|
+
channel: typeof MINIAPP_CHANNEL;
|
|
13
|
+
version: typeof MINIAPP_VERSION;
|
|
14
|
+
type: 'READY';
|
|
15
|
+
payload: Record<string, unknown> | {
|
|
16
|
+
appId?: string;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
export type MiniAppMessageThemeSync = {
|
|
20
|
+
channel: typeof MINIAPP_CHANNEL;
|
|
21
|
+
version: typeof MINIAPP_VERSION;
|
|
22
|
+
type: 'THEME_SYNC';
|
|
23
|
+
payload: ThemeSyncPayload;
|
|
24
|
+
};
|
|
25
|
+
/** Parse parent → child THEME_SYNC (shell uses `buildThemeSyncMessage`). */
|
|
26
|
+
export declare function parseThemeSyncMessage(data: unknown): ThemeSyncPayload | null;
|
|
27
|
+
/** Child → parent READY (optional `appId` for telemetry). */
|
|
28
|
+
export declare function buildReadyMessage(payload?: Record<string, unknown>): MiniAppMessageReady;
|
|
29
|
+
export declare function resolveParentOriginFromReferrer(): string | null;
|
|
30
|
+
export declare function applyThemeToDocument(mode: 'light' | 'dark'): void;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# GitHub Packages (npm)
|
|
2
|
+
|
|
3
|
+
Use [GitHub Packages](https://docs.github.com/en/packages) as the npm registry for scoped packages such as `@Mir-Insight/uilib`. Public npm (`registry.npmjs.org`) stays the default for unscoped packages.
|
|
4
|
+
|
|
5
|
+
## 1. Enable Packages on the repository
|
|
6
|
+
|
|
7
|
+
- **Publishing**: in the package repo (e.g. `uilib`), use **Actions** permissions and `GITHUB_TOKEN` or a PAT with `write:packages` as documented by GitHub.
|
|
8
|
+
- **Installing in another repo**: the consumer needs **`read:packages`** on the package’s scope (org or user).
|
|
9
|
+
|
|
10
|
+
## 2. `package.json` in the library (publisher)
|
|
11
|
+
|
|
12
|
+
Use a **scoped** name under the org:
|
|
13
|
+
|
|
14
|
+
```json
|
|
15
|
+
{
|
|
16
|
+
"name": "@Mir-Insight/uilib",
|
|
17
|
+
"publishConfig": {
|
|
18
|
+
"registry": "https://npm.pkg.github.com"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Publish from CI or locally after `npm login` to `https://npm.pkg.github.com`.
|
|
24
|
+
|
|
25
|
+
## 3. Consumer `.npmrc` (app or library)
|
|
26
|
+
|
|
27
|
+
At the repo root (commit this; no token in git):
|
|
28
|
+
|
|
29
|
+
```ini
|
|
30
|
+
@Mir-Insight:registry=https://npm.pkg.github.com/
|
|
31
|
+
//npm.pkg.github.com/:_authToken=${NODE_AUTH_TOKEN}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Yarn/npm substitute `${NODE_AUTH_TOKEN}` at install time.
|
|
35
|
+
|
|
36
|
+
**Local machine**
|
|
37
|
+
|
|
38
|
+
- Create a [Personal Access Token](https://github.com/settings/tokens) (classic: `read:packages`; fine-grained: Packages read for the org).
|
|
39
|
+
- `export NODE_AUTH_TOKEN=ghp_...` before `yarn install`, or add the token line to your user `~/.npmrc` (never commit that file).
|
|
40
|
+
|
|
41
|
+
**Same repository as the package**
|
|
42
|
+
|
|
43
|
+
- A workflow can use `GITHUB_TOKEN` with `packages: read` for some same-repo cases; see GitHub’s current matrix for npm.
|
|
44
|
+
|
|
45
|
+
**Different repository than the package (typical for `design-demo` → `uilib`)**
|
|
46
|
+
|
|
47
|
+
- Use a **PAT** with `read:packages` stored as a repository/org secret. Name is arbitrary; examples below use `PACKAGES_READ_TOKEN` for clarity, or reuse an existing org secret like `PAT` if it already has `read:packages`.
|
|
48
|
+
- `GITHUB_TOKEN` alone often **cannot** install private packages published from another repository; use a PAT unless GitHub documents an exception for your setup.
|
|
49
|
+
|
|
50
|
+
## 4. GitHub Actions (install job)
|
|
51
|
+
|
|
52
|
+
```yaml
|
|
53
|
+
permissions:
|
|
54
|
+
contents: read
|
|
55
|
+
packages: read
|
|
56
|
+
|
|
57
|
+
jobs:
|
|
58
|
+
build:
|
|
59
|
+
runs-on: ubuntu-latest
|
|
60
|
+
steps:
|
|
61
|
+
- uses: actions/checkout@v4
|
|
62
|
+
- uses: actions/setup-node@v4
|
|
63
|
+
with:
|
|
64
|
+
node-version: '20'
|
|
65
|
+
registry-url: https://npm.pkg.github.com
|
|
66
|
+
scope: '@Mir-Insight'
|
|
67
|
+
- run: yarn install --frozen-lockfile
|
|
68
|
+
env:
|
|
69
|
+
NODE_AUTH_TOKEN: ${{ secrets.PACKAGES_READ_TOKEN || secrets.PAT }}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
`setup-node` can write `.npmrc`; if you already committed `.npmrc` with `${NODE_AUTH_TOKEN}`, passing `NODE_AUTH_TOKEN` in `env` is enough. Use whichever secret name your org uses for a PAT with `read:packages`.
|
|
73
|
+
|
|
74
|
+
## 5. Docker builds
|
|
75
|
+
|
|
76
|
+
Do **not** pass tokens as plain `ARG` (they can leak in image history). Use **BuildKit secrets** and export `NODE_AUTH_TOKEN` only inside the `RUN` that runs `yarn install` / `npm ci`.
|
|
77
|
+
|
|
78
|
+
`design-demo`’s `deployment/Dockerfile` mounts an optional secret `gh_token` and appends it to `.npmrc` before install. The workflow passes (first match wins):
|
|
79
|
+
|
|
80
|
+
```yaml
|
|
81
|
+
secrets: |
|
|
82
|
+
gh_token=${{ secrets.PACKAGES_READ_TOKEN || secrets.PAT || github.token }}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
If you are not using GitHub Packages yet, omit the PAT secrets; the mount stays optional (`required=false`) and installs that only use `github:` or public npm still work.
|
|
86
|
+
|
|
87
|
+
## 6. Migrating from `github:` dependency
|
|
88
|
+
|
|
89
|
+
Replace:
|
|
90
|
+
|
|
91
|
+
```json
|
|
92
|
+
"uilib": "github:Mir-Insight/uilib#<commit>"
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
with a **version** published to GitHub Packages:
|
|
96
|
+
|
|
97
|
+
```json
|
|
98
|
+
"uilib": "npm:@Mir-Insight/uilib@^1.2.3"
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
or, if the package name stays unscoped on GPR (unusual), follow your published name. Regenerate the lockfile after changing `package.json`.
|
|
102
|
+
|
|
103
|
+
## 7. References
|
|
104
|
+
|
|
105
|
+
- [Working with the npm registry](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-npm-registry)
|
|
106
|
+
- [Publishing and installing packages with GitHub Actions](https://docs.github.com/en/packages/managing-github-packages-using-github-actions-workflows/publishing-and-installing-a-package-with-github-actions)
|