dynim-react 1.0.59 → 1.0.63
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/dist/DynimProvider.d.ts +38 -7
- package/dist/DynimProvider.d.ts.map +1 -1
- package/dist/DynimProvider.js +387 -45
- package/dist/plugins/vite/plugin.d.ts +52 -2
- package/dist/plugins/vite/plugin.d.ts.map +1 -1
- package/dist/plugins/vite/plugin.js +81 -2
- package/dist/theme.d.ts +57 -1
- package/dist/theme.d.ts.map +1 -1
- package/dist/theme.js +97 -1
- package/package.json +2 -2
package/dist/DynimProvider.d.ts
CHANGED
|
@@ -1,42 +1,73 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* DynimProvider -
|
|
2
|
+
* DynimProvider - Single provider for all Dynim functionality
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* -
|
|
6
|
-
* -
|
|
7
|
-
* -
|
|
8
|
-
* - Theme <style> injection
|
|
4
|
+
* Handles:
|
|
5
|
+
* - Loading tenant bundles
|
|
6
|
+
* - Visual builder UI (when user has edit permissions)
|
|
7
|
+
* - Shared context for bundles to access React, packages, etc.
|
|
9
8
|
*/
|
|
10
9
|
import { type ReactNode } from 'react';
|
|
11
|
-
import {
|
|
10
|
+
import type { CodeMessage, Checkpoint, RestoreResult } from 'dynim-core';
|
|
12
11
|
export interface DynimConfig {
|
|
12
|
+
/** Function to fetch a session token for authentication */
|
|
13
13
|
getSession?: () => Promise<{
|
|
14
14
|
token: string;
|
|
15
15
|
refreshToken?: string;
|
|
16
16
|
}>;
|
|
17
|
+
/** Called when an error occurs */
|
|
17
18
|
onError?: (error: Event | Error) => void;
|
|
19
|
+
/** NPM packages to expose to bundles (e.g., { 'react-router-dom': ReactRouterDOM }) */
|
|
18
20
|
packages?: Record<string, unknown>;
|
|
21
|
+
/** Custom hooks to expose to bundles */
|
|
19
22
|
hooks?: Record<string, unknown>;
|
|
23
|
+
/** React contexts to expose to bundles */
|
|
20
24
|
contexts?: Record<string, unknown>;
|
|
21
25
|
}
|
|
22
26
|
export interface DynimContextValue {
|
|
27
|
+
/** Enter edit mode (shows builder UI) */
|
|
23
28
|
enterBuilder: () => void;
|
|
29
|
+
/** Exit edit mode */
|
|
24
30
|
exitBuilder: () => void;
|
|
31
|
+
/** Whether builder/edit mode is active */
|
|
25
32
|
isEditing: boolean;
|
|
33
|
+
/** Send a code edit request to AI */
|
|
26
34
|
sendCode: (query: string) => Promise<void>;
|
|
35
|
+
/** Save current edits */
|
|
27
36
|
saveCode: () => Promise<void>;
|
|
37
|
+
/** Abandon/discard current edits */
|
|
28
38
|
abandonCode: () => Promise<void>;
|
|
39
|
+
/** Get active checkpoints for the project */
|
|
29
40
|
getCheckpoints: () => Promise<Checkpoint[]>;
|
|
41
|
+
/** Restore to a specific checkpoint (reloads bundle on success) */
|
|
30
42
|
restoreCheckpoint: (checkpointId: string) => Promise<RestoreResult>;
|
|
43
|
+
/** Whether a checkpoint restore is in progress */
|
|
31
44
|
isRestoring: boolean;
|
|
45
|
+
/** Current code message state (thinking, edits, etc.) */
|
|
32
46
|
codeMessage: CodeMessage;
|
|
47
|
+
/** Whether a bundle is currently loaded */
|
|
33
48
|
isBundleLoaded: boolean;
|
|
49
|
+
/** Whether bundle is loading */
|
|
34
50
|
isBundleLoading: boolean;
|
|
35
51
|
}
|
|
36
52
|
export interface DynimProviderProps {
|
|
37
53
|
children: ReactNode;
|
|
38
54
|
config?: DynimConfig;
|
|
39
55
|
}
|
|
56
|
+
/**
|
|
57
|
+
* DynimProvider - Wrap your app with this to enable Dynim functionality
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```tsx
|
|
61
|
+
* import { DynimProvider } from 'dynim-react';
|
|
62
|
+
*
|
|
63
|
+
* <DynimProvider>
|
|
64
|
+
* <App />
|
|
65
|
+
* </DynimProvider>
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
40
68
|
export declare function DynimProvider({ children, config, }: DynimProviderProps): JSX.Element;
|
|
69
|
+
/**
|
|
70
|
+
* Hook to access Dynim functionality
|
|
71
|
+
*/
|
|
41
72
|
export declare function useDynim(): DynimContextValue;
|
|
42
73
|
//# sourceMappingURL=DynimProvider.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DynimProvider.d.ts","sourceRoot":"","sources":["../src/DynimProvider.tsx"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"DynimProvider.d.ts","sourceRoot":"","sources":["../src/DynimProvider.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAc,EAQZ,KAAK,SAAS,EAEf,MAAM,OAAO,CAAC;AAWf,OAAO,KAAK,EAKV,WAAW,EACX,UAAU,EACV,aAAa,EAGd,MAAM,YAAY,CAAC;AAIpB,MAAM,WAAW,WAAW;IAC1B,2DAA2D;IAC3D,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACrE,kCAAkC;IAClC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK,KAAK,IAAI,CAAC;IACzC,uFAAuF;IACvF,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,wCAAwC;IACxC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,0CAA0C;IAC1C,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,iBAAiB;IAChC,yCAAyC;IACzC,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,qBAAqB;IACrB,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,0CAA0C;IAC1C,SAAS,EAAE,OAAO,CAAC;IACnB,qCAAqC;IACrC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C,yBAAyB;IACzB,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,oCAAoC;IACpC,WAAW,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,6CAA6C;IAC7C,cAAc,EAAE,MAAM,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;IAC5C,mEAAmE;IACnE,iBAAiB,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,aAAa,CAAC,CAAC;IACpE,kDAAkD;IAClD,WAAW,EAAE,OAAO,CAAC;IACrB,yDAAyD;IACzD,WAAW,EAAE,WAAW,CAAC;IACzB,2CAA2C;IAC3C,cAAc,EAAE,OAAO,CAAC;IACxB,gCAAgC;IAChC,eAAe,EAAE,OAAO,CAAC;CAC1B;AAID,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,SAAS,CAAC;IACpB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,EAC5B,QAAQ,EACR,MAAW,GACZ,EAAE,kBAAkB,GAAG,GAAG,CAAC,OAAO,CAkdlC;AAED;;GAEG;AACH,wBAAgB,QAAQ,IAAI,iBAAiB,CAM5C"}
|
package/dist/DynimProvider.js
CHANGED
|
@@ -1,36 +1,76 @@
|
|
|
1
1
|
import { jsxs as _jsxs, Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
/**
|
|
3
|
-
* DynimProvider -
|
|
3
|
+
* DynimProvider - Single provider for all Dynim functionality
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
* -
|
|
7
|
-
* -
|
|
8
|
-
* -
|
|
9
|
-
* - Theme <style> injection
|
|
5
|
+
* Handles:
|
|
6
|
+
* - Loading tenant bundles
|
|
7
|
+
* - Visual builder UI (when user has edit permissions)
|
|
8
|
+
* - Shared context for bundles to access React, packages, etc.
|
|
10
9
|
*/
|
|
11
|
-
import React, { createContext, useContext, useEffect, useMemo, useState, } from 'react';
|
|
10
|
+
import React, { createContext, useContext, useEffect, useRef, useCallback, useMemo, useState, } from 'react';
|
|
12
11
|
import ReactDOM from 'react-dom';
|
|
13
|
-
import {
|
|
12
|
+
import { createBuilderClient, createBuilder, createCodeClient, createBundleLoader, createCSSLoader, BundleNotFoundError, BundleAuthError, } from 'dynim-core';
|
|
14
13
|
import { createSharedContext, updateSharedContext, isSharedContextReady } from './inference/sharedContext';
|
|
14
|
+
import { generateThemeCSS } from './theme';
|
|
15
15
|
const DynimContext = createContext(null);
|
|
16
|
+
/**
|
|
17
|
+
* DynimProvider - Wrap your app with this to enable Dynim functionality
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```tsx
|
|
21
|
+
* import { DynimProvider } from 'dynim-react';
|
|
22
|
+
*
|
|
23
|
+
* <DynimProvider>
|
|
24
|
+
* <App />
|
|
25
|
+
* </DynimProvider>
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
16
28
|
export function DynimProvider({ children, config = {}, }) {
|
|
17
|
-
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
//
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const
|
|
29
|
+
const builderClientRef = useRef(null);
|
|
30
|
+
const builderRef = useRef(null);
|
|
31
|
+
const codeClientRef = useRef(null);
|
|
32
|
+
const bundleLoaderRef = useRef(null);
|
|
33
|
+
const cssLoaderRef = useRef(null);
|
|
34
|
+
// Track when we're exiting to prevent auto-load from re-triggering
|
|
35
|
+
const isExitingRef = useRef(false);
|
|
36
|
+
const hasAttemptedInitialLoadRef = useRef(false);
|
|
37
|
+
const isBuilderActiveRef = useRef(false);
|
|
38
|
+
const [isEditing, setIsEditing] = useState(false);
|
|
39
|
+
const [isBundleLoaded, setIsBundleLoaded] = useState(false);
|
|
40
|
+
const [isBundleLoading, setIsBundleLoading] = useState(false);
|
|
41
|
+
const [isInitialLoadComplete, setIsInitialLoadComplete] = useState(false);
|
|
42
|
+
const [TenantApp, setTenantApp] = useState(null);
|
|
43
|
+
const [bundleError, setBundleError] = useState(null);
|
|
44
|
+
const [isRestoring, setIsRestoring] = useState(false);
|
|
45
|
+
const [codeMessage, setCodeMessage] = useState({
|
|
46
|
+
thinking: '',
|
|
47
|
+
text: '',
|
|
48
|
+
edits: [],
|
|
49
|
+
status: 'idle',
|
|
50
|
+
bundleReady: false,
|
|
51
|
+
bundleError: undefined,
|
|
52
|
+
});
|
|
53
|
+
// Cached auth token
|
|
54
|
+
const cachedTokenRef = useRef(null);
|
|
55
|
+
const tokenPromiseRef = useRef(null);
|
|
56
|
+
// Bundle load signal
|
|
57
|
+
const [bundleLoadSignal, setBundleLoadSignal] = useState(0);
|
|
58
|
+
const pendingBundleProjectIdRef = useRef(null);
|
|
59
|
+
// Theme state (fetched from API per project)
|
|
60
|
+
const [theme, setTheme] = useState(null);
|
|
61
|
+
const hasAttemptedThemeLoadRef = useRef(false);
|
|
62
|
+
// Keep config in ref to avoid re-triggering effects on every render
|
|
63
|
+
const configRef = useRef(config);
|
|
64
|
+
configRef.current = config;
|
|
65
|
+
// Set up shared context for bundles (only once on mount)
|
|
26
66
|
useEffect(() => {
|
|
27
|
-
|
|
28
|
-
const { packages = {}, hooks = {}, contexts = {} } = config;
|
|
67
|
+
const { packages = {}, hooks = {}, contexts = {} } = configRef.current;
|
|
29
68
|
const sdkPackages = {
|
|
30
69
|
'dynim-react': { DynimProvider, useDynim },
|
|
31
70
|
...packages,
|
|
32
71
|
};
|
|
33
72
|
if (!isSharedContextReady()) {
|
|
73
|
+
// Create fresh shared context
|
|
34
74
|
createSharedContext({
|
|
35
75
|
React,
|
|
36
76
|
ReactDOM,
|
|
@@ -40,57 +80,359 @@ export function DynimProvider({ children, config = {}, }) {
|
|
|
40
80
|
});
|
|
41
81
|
}
|
|
42
82
|
else {
|
|
83
|
+
// Update existing context with packages (handles HMR)
|
|
43
84
|
updateSharedContext({
|
|
44
85
|
packages: sdkPackages,
|
|
45
86
|
hooks,
|
|
46
87
|
contexts,
|
|
47
88
|
});
|
|
48
89
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
90
|
+
}, []);
|
|
91
|
+
// Get auth token (cached after first call)
|
|
92
|
+
const getAuthToken = useCallback(async () => {
|
|
93
|
+
const { getSession } = configRef.current;
|
|
94
|
+
// Return cached token if available
|
|
95
|
+
if (cachedTokenRef.current)
|
|
96
|
+
return cachedTokenRef.current;
|
|
97
|
+
// Reuse in-flight promise if one exists
|
|
98
|
+
if (tokenPromiseRef.current)
|
|
99
|
+
return tokenPromiseRef.current;
|
|
100
|
+
if (getSession) {
|
|
101
|
+
tokenPromiseRef.current = (async () => {
|
|
102
|
+
try {
|
|
103
|
+
const session = await getSession();
|
|
104
|
+
cachedTokenRef.current = session.token;
|
|
105
|
+
return session.token;
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
finally {
|
|
111
|
+
tokenPromiseRef.current = null;
|
|
112
|
+
}
|
|
113
|
+
})();
|
|
114
|
+
return tokenPromiseRef.current;
|
|
115
|
+
}
|
|
116
|
+
return null;
|
|
117
|
+
}, []);
|
|
118
|
+
// Initialize code client (only once on mount)
|
|
119
|
+
useEffect(() => {
|
|
120
|
+
const { getSession, onError } = configRef.current;
|
|
121
|
+
codeClientRef.current = createCodeClient({
|
|
122
|
+
getSession,
|
|
123
|
+
onMessageUpdate: setCodeMessage,
|
|
124
|
+
onError: (error) => {
|
|
125
|
+
console.error('[DynimProvider] Code error:', error);
|
|
126
|
+
configRef.current.onError?.(error);
|
|
127
|
+
},
|
|
128
|
+
});
|
|
129
|
+
}, []);
|
|
130
|
+
// Load bundle ref
|
|
131
|
+
const loadBundleRef = useRef(null);
|
|
132
|
+
// Initialize builder (only once on mount)
|
|
133
|
+
useEffect(() => {
|
|
134
|
+
const { getSession } = configRef.current;
|
|
135
|
+
builderRef.current = createBuilder({
|
|
136
|
+
getSession,
|
|
137
|
+
codeClient: codeClientRef.current ?? undefined,
|
|
138
|
+
onExitStart: () => {
|
|
139
|
+
isExitingRef.current = true;
|
|
140
|
+
isBuilderActiveRef.current = false;
|
|
141
|
+
codeClientRef.current?.abort();
|
|
142
|
+
codeClientRef.current?.resetMessage();
|
|
143
|
+
},
|
|
144
|
+
loadBundle: (bundleUrl) => {
|
|
145
|
+
// Note: isExitingRef is already set by onExitStart for the exit flow.
|
|
146
|
+
// Don't set it here — this callback is also used by checkpoint restore
|
|
147
|
+
// while the builder is still active.
|
|
148
|
+
return loadBundleRef.current?.(bundleUrl) ?? Promise.resolve();
|
|
149
|
+
},
|
|
150
|
+
onEnter: () => {
|
|
151
|
+
isExitingRef.current = false;
|
|
152
|
+
isBuilderActiveRef.current = true;
|
|
153
|
+
setIsEditing(true);
|
|
154
|
+
},
|
|
155
|
+
onExit: () => {
|
|
156
|
+
setIsEditing(false);
|
|
157
|
+
},
|
|
158
|
+
});
|
|
53
159
|
return () => {
|
|
54
|
-
|
|
55
|
-
|
|
160
|
+
builderRef.current?.destroy();
|
|
161
|
+
// Clean up CSS link element on unmount
|
|
162
|
+
cssLoaderRef.current?.unload();
|
|
163
|
+
};
|
|
164
|
+
}, []);
|
|
165
|
+
// Initialize builder client (only once on mount)
|
|
166
|
+
useEffect(() => {
|
|
167
|
+
const { getSession } = configRef.current;
|
|
168
|
+
builderClientRef.current = createBuilderClient({
|
|
169
|
+
getSession,
|
|
170
|
+
onError: (error) => {
|
|
171
|
+
console.error('[DynimProvider] Error:', error);
|
|
172
|
+
configRef.current.onError?.(error);
|
|
173
|
+
},
|
|
174
|
+
});
|
|
175
|
+
}, []);
|
|
176
|
+
// Get bundle loader
|
|
177
|
+
const getBundleLoader = useCallback(() => {
|
|
178
|
+
if (!bundleLoaderRef.current) {
|
|
179
|
+
bundleLoaderRef.current = createBundleLoader({
|
|
180
|
+
getAuthToken,
|
|
181
|
+
includeCredentials: true,
|
|
182
|
+
onError: (error) => {
|
|
183
|
+
console.error('[DynimProvider] Bundle load failed:', error);
|
|
184
|
+
configRef.current.onError?.(error);
|
|
185
|
+
},
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
return bundleLoaderRef.current;
|
|
189
|
+
}, [getAuthToken]);
|
|
190
|
+
// Get CSS loader
|
|
191
|
+
const getCSSLoader = useCallback(() => {
|
|
192
|
+
if (!cssLoaderRef.current) {
|
|
193
|
+
cssLoaderRef.current = createCSSLoader({
|
|
194
|
+
linkId: 'dynim-bundle-css',
|
|
195
|
+
onError: (error) => {
|
|
196
|
+
console.warn('[DynimProvider] CSS load failed:', error);
|
|
197
|
+
},
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
return cssLoaderRef.current;
|
|
201
|
+
}, []);
|
|
202
|
+
// Load bundle (JS + CSS)
|
|
203
|
+
const loadBundle = useCallback(async (bundleUrl, loadCSS = true) => {
|
|
204
|
+
const loader = getBundleLoader();
|
|
205
|
+
if (loader.isLoading())
|
|
206
|
+
return;
|
|
207
|
+
setIsBundleLoading(true);
|
|
208
|
+
setBundleError(null);
|
|
209
|
+
try {
|
|
210
|
+
const { App, cleanup } = await loader.load(bundleUrl);
|
|
211
|
+
setTenantApp(() => App);
|
|
212
|
+
setIsBundleLoaded(true);
|
|
213
|
+
cleanup();
|
|
214
|
+
// Load CSS alongside JS bundle
|
|
215
|
+
if (loadCSS) {
|
|
216
|
+
const cssLoader = getCSSLoader();
|
|
217
|
+
const isTemp = bundleUrl.includes('temp=true');
|
|
218
|
+
const cssUrl = isTemp ? '/api/code/css?temp=true' : '/api/code/css';
|
|
219
|
+
if (isTemp) {
|
|
220
|
+
// Temp/preview CSS - bust cache to get latest
|
|
221
|
+
cssLoader.loadWithCacheBust(cssUrl);
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
// Saved CSS - let browser cache
|
|
225
|
+
cssLoader.load(cssUrl);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
catch (error) {
|
|
230
|
+
// 404 = no bundle, 401 = not authenticated - show children
|
|
231
|
+
if (error instanceof BundleNotFoundError || error instanceof BundleAuthError) {
|
|
232
|
+
setTenantApp(null);
|
|
233
|
+
setIsBundleLoaded(false);
|
|
234
|
+
// Also unload any CSS
|
|
235
|
+
getCSSLoader().unload();
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
setBundleError(error);
|
|
239
|
+
}
|
|
240
|
+
finally {
|
|
241
|
+
setIsBundleLoading(false);
|
|
242
|
+
}
|
|
243
|
+
}, [getBundleLoader, getCSSLoader]);
|
|
244
|
+
// Keep ref updated
|
|
245
|
+
useEffect(() => {
|
|
246
|
+
loadBundleRef.current = loadBundle;
|
|
247
|
+
}, [loadBundle]);
|
|
248
|
+
// Theme is fetched lazily when entering builder mode
|
|
249
|
+
// This avoids making HTTP requests on mount that could trigger auth redirects
|
|
250
|
+
const fetchTheme = useCallback(async () => {
|
|
251
|
+
if (hasAttemptedThemeLoadRef.current)
|
|
252
|
+
return;
|
|
253
|
+
if (!configRef.current.getSession)
|
|
254
|
+
return;
|
|
255
|
+
hasAttemptedThemeLoadRef.current = true;
|
|
256
|
+
try {
|
|
257
|
+
const token = await getAuthToken();
|
|
258
|
+
const headers = {};
|
|
259
|
+
if (token) {
|
|
260
|
+
headers['Authorization'] = `Bearer ${token}`;
|
|
261
|
+
}
|
|
262
|
+
const response = await fetch('/api/code/theme', {
|
|
263
|
+
headers,
|
|
264
|
+
credentials: 'include',
|
|
265
|
+
});
|
|
266
|
+
if (response.ok) {
|
|
267
|
+
const data = await response.json();
|
|
268
|
+
setTheme(data);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
catch (error) {
|
|
272
|
+
// Theme fetch failed - use defaults (non-critical)
|
|
273
|
+
console.warn('[DynimProvider] Failed to fetch theme:', error);
|
|
274
|
+
}
|
|
275
|
+
}, [getAuthToken]);
|
|
276
|
+
// Auto-load saved bundle on mount if auth is available
|
|
277
|
+
useEffect(() => {
|
|
278
|
+
if (hasAttemptedInitialLoadRef.current)
|
|
279
|
+
return;
|
|
280
|
+
hasAttemptedInitialLoadRef.current = true;
|
|
281
|
+
const { getSession } = configRef.current;
|
|
282
|
+
// No auth configured = skip bundle load
|
|
283
|
+
if (!getSession) {
|
|
284
|
+
setIsInitialLoadComplete(true);
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
// Load bundle with the provided token
|
|
288
|
+
const doInitialLoad = async () => {
|
|
289
|
+
try {
|
|
290
|
+
await loadBundleRef.current?.('/api/code/bundle');
|
|
291
|
+
}
|
|
292
|
+
catch (error) {
|
|
293
|
+
// Errors handled in loadBundle (404 = no bundle, etc.)
|
|
294
|
+
console.log('[DynimProvider] Initial bundle load:', error.message);
|
|
295
|
+
}
|
|
296
|
+
finally {
|
|
297
|
+
setIsInitialLoadComplete(true);
|
|
298
|
+
}
|
|
56
299
|
};
|
|
57
|
-
|
|
300
|
+
doInitialLoad();
|
|
301
|
+
// Prefetch theme after 3s delay (non-blocking, so it's ready when builder opens)
|
|
302
|
+
const themeTimeout = setTimeout(() => {
|
|
303
|
+
fetchTheme();
|
|
304
|
+
}, 3000);
|
|
305
|
+
return () => clearTimeout(themeTimeout);
|
|
306
|
+
}, [fetchTheme]);
|
|
307
|
+
// Load saved bundle
|
|
308
|
+
const loadSavedBundle = useCallback(async () => {
|
|
309
|
+
// Note: CSS is loaded separately by saveCode/abandonCode with cache busting
|
|
310
|
+
await loadBundle('/api/code/bundle', false);
|
|
311
|
+
}, [loadBundle]);
|
|
312
|
+
// Watch for bundleReady
|
|
313
|
+
useEffect(() => {
|
|
314
|
+
if (codeMessage.bundleReady && codeMessage.projectId) {
|
|
315
|
+
if (isBuilderActiveRef.current && !isExitingRef.current) {
|
|
316
|
+
pendingBundleProjectIdRef.current = codeMessage.projectId;
|
|
317
|
+
setBundleLoadSignal(s => s + 1);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}, [codeMessage.bundleReady, codeMessage.projectId]);
|
|
321
|
+
// Load temp bundle on signal (JS + CSS with cache busting)
|
|
322
|
+
useEffect(() => {
|
|
323
|
+
if (bundleLoadSignal === 0)
|
|
324
|
+
return;
|
|
325
|
+
const projectId = pendingBundleProjectIdRef.current;
|
|
326
|
+
if (!projectId || isExitingRef.current) {
|
|
327
|
+
pendingBundleProjectIdRef.current = null;
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
// Load JS bundle with cache busting
|
|
331
|
+
const bundleUrl = `/api/code/bundle?temp=true&_t=${Date.now()}`;
|
|
332
|
+
loadBundleRef.current?.(bundleUrl, true); // true = also load CSS
|
|
333
|
+
pendingBundleProjectIdRef.current = null;
|
|
334
|
+
}, [bundleLoadSignal]);
|
|
335
|
+
// Public methods
|
|
336
|
+
const enterBuilder = useCallback(() => {
|
|
337
|
+
if (builderRef.current && !builderRef.current.isActive()) {
|
|
338
|
+
builderRef.current.enter();
|
|
339
|
+
// Fetch theme lazily when entering builder
|
|
340
|
+
fetchTheme();
|
|
341
|
+
}
|
|
342
|
+
}, [fetchTheme]);
|
|
343
|
+
const exitBuilder = useCallback(() => {
|
|
344
|
+
if (builderRef.current && builderRef.current.isActive()) {
|
|
345
|
+
builderRef.current.exit();
|
|
346
|
+
}
|
|
347
|
+
}, []);
|
|
348
|
+
const sendCode = useCallback(async (query) => {
|
|
349
|
+
await codeClientRef.current?.sendCode(query);
|
|
350
|
+
}, []);
|
|
351
|
+
const saveCode = useCallback(async () => {
|
|
352
|
+
await codeClientRef.current?.saveCode();
|
|
353
|
+
await loadSavedBundle();
|
|
354
|
+
// Force reload CSS with cache bust since saved CSS has changed
|
|
355
|
+
getCSSLoader().loadWithCacheBust('/api/code/css');
|
|
356
|
+
}, [loadSavedBundle, getCSSLoader]);
|
|
357
|
+
const abandonCode = useCallback(async () => {
|
|
358
|
+
await codeClientRef.current?.abandonCode();
|
|
359
|
+
await loadSavedBundle();
|
|
360
|
+
// Reload saved CSS (may have been showing temp CSS)
|
|
361
|
+
getCSSLoader().loadWithCacheBust('/api/code/css');
|
|
362
|
+
}, [loadSavedBundle, getCSSLoader]);
|
|
363
|
+
const getCheckpoints = useCallback(async () => {
|
|
364
|
+
return codeClientRef.current?.getCheckpoints() ?? [];
|
|
365
|
+
}, []);
|
|
366
|
+
const restoreCheckpoint = useCallback(async (checkpointId) => {
|
|
367
|
+
if (!codeClientRef.current) {
|
|
368
|
+
throw new Error('Code client not initialized');
|
|
369
|
+
}
|
|
370
|
+
setIsRestoring(true);
|
|
371
|
+
try {
|
|
372
|
+
const result = await codeClientRef.current.restoreCheckpoint(checkpointId);
|
|
373
|
+
// Reload bundle + CSS on success (loadBundle handles CSS when loadCSS=true)
|
|
374
|
+
if (result.bundle_ready) {
|
|
375
|
+
const bundleUrl = `/api/code/bundle?temp=true&_t=${Date.now()}`;
|
|
376
|
+
await loadBundleRef.current?.(bundleUrl, true);
|
|
377
|
+
}
|
|
378
|
+
return result;
|
|
379
|
+
}
|
|
380
|
+
finally {
|
|
381
|
+
setIsRestoring(false);
|
|
382
|
+
}
|
|
58
383
|
}, []);
|
|
59
384
|
const contextValue = useMemo(() => ({
|
|
60
|
-
enterBuilder
|
|
61
|
-
exitBuilder
|
|
62
|
-
isEditing
|
|
63
|
-
sendCode
|
|
64
|
-
saveCode
|
|
65
|
-
abandonCode
|
|
66
|
-
getCheckpoints
|
|
67
|
-
restoreCheckpoint
|
|
68
|
-
isRestoring
|
|
69
|
-
codeMessage
|
|
70
|
-
isBundleLoaded
|
|
71
|
-
isBundleLoading
|
|
72
|
-
}), [
|
|
385
|
+
enterBuilder,
|
|
386
|
+
exitBuilder,
|
|
387
|
+
isEditing,
|
|
388
|
+
sendCode,
|
|
389
|
+
saveCode,
|
|
390
|
+
abandonCode,
|
|
391
|
+
getCheckpoints,
|
|
392
|
+
restoreCheckpoint,
|
|
393
|
+
isRestoring,
|
|
394
|
+
codeMessage,
|
|
395
|
+
isBundleLoaded,
|
|
396
|
+
isBundleLoading,
|
|
397
|
+
}), [
|
|
398
|
+
enterBuilder,
|
|
399
|
+
exitBuilder,
|
|
400
|
+
isEditing,
|
|
401
|
+
sendCode,
|
|
402
|
+
saveCode,
|
|
403
|
+
abandonCode,
|
|
404
|
+
getCheckpoints,
|
|
405
|
+
restoreCheckpoint,
|
|
406
|
+
isRestoring,
|
|
407
|
+
codeMessage,
|
|
408
|
+
isBundleLoaded,
|
|
409
|
+
isBundleLoading,
|
|
410
|
+
]);
|
|
73
411
|
// Render content
|
|
74
412
|
const renderContent = () => {
|
|
75
|
-
if (!
|
|
413
|
+
if (!isInitialLoadComplete)
|
|
76
414
|
return null;
|
|
77
|
-
if (
|
|
415
|
+
if (bundleError) {
|
|
78
416
|
return (_jsxs(_Fragment, { children: [_jsxs("div", { style: {
|
|
79
417
|
padding: 12,
|
|
80
418
|
background: '#fef3c7',
|
|
81
419
|
borderBottom: '1px solid #fcd34d',
|
|
82
420
|
fontSize: 13,
|
|
83
421
|
color: '#92400e',
|
|
84
|
-
}, children: ["Bundle error: ",
|
|
422
|
+
}, children: ["Bundle error: ", bundleError.message] }), children] }));
|
|
85
423
|
}
|
|
86
|
-
if (
|
|
87
|
-
const TenantApp = state.tenantApp;
|
|
424
|
+
if (TenantApp) {
|
|
88
425
|
return _jsx(TenantApp, {});
|
|
89
426
|
}
|
|
90
427
|
return children;
|
|
91
428
|
};
|
|
92
|
-
|
|
429
|
+
// Generate theme CSS from API-fetched theme
|
|
430
|
+
const themeCSS = useMemo(() => generateThemeCSS(theme ?? undefined), [theme]);
|
|
431
|
+
return (_jsxs(DynimContext.Provider, { value: contextValue, children: [_jsx("style", { children: themeCSS }), renderContent()] }));
|
|
93
432
|
}
|
|
433
|
+
/**
|
|
434
|
+
* Hook to access Dynim functionality
|
|
435
|
+
*/
|
|
94
436
|
export function useDynim() {
|
|
95
437
|
const context = useContext(DynimContext);
|
|
96
438
|
if (!context) {
|
|
@@ -1,4 +1,54 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Vite plugin for Dynim package exposure
|
|
3
|
+
*
|
|
4
|
+
* Generates a virtual module that exports all specified packages,
|
|
5
|
+
* so you don't have to manually import and map each one.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* ```ts
|
|
9
|
+
* // vite.config.ts
|
|
10
|
+
* import { dynimPackages } from 'dynim-react/vite'
|
|
11
|
+
*
|
|
12
|
+
* export default {
|
|
13
|
+
* plugins: [
|
|
14
|
+
* dynimPackages([
|
|
15
|
+
* 'react-router-dom',
|
|
16
|
+
* '@tanstack/react-query',
|
|
17
|
+
* 'axios',
|
|
18
|
+
* ])
|
|
19
|
+
* ]
|
|
20
|
+
* }
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* Then in your app:
|
|
24
|
+
* ```tsx
|
|
25
|
+
* import packages from 'virtual:dynim-packages'
|
|
26
|
+
*
|
|
27
|
+
* <DynimProvider config={{ packages }}>
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
import type { Plugin } from 'vite';
|
|
31
|
+
export interface DynimPackagesOptions {
|
|
32
|
+
/**
|
|
33
|
+
* List of package names to expose to dynim bundles.
|
|
34
|
+
* These must be installed in your project's node_modules.
|
|
35
|
+
*/
|
|
36
|
+
packages: string[];
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Vite plugin that generates a virtual module exporting all specified packages.
|
|
40
|
+
*
|
|
41
|
+
* @param packages - Array of package names, or options object
|
|
42
|
+
* @returns Vite plugin
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* // Simple usage - array of package names
|
|
46
|
+
* dynimPackages(['react-router-dom', 'axios'])
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* // Options object
|
|
50
|
+
* dynimPackages({ packages: ['react-router-dom', 'axios'] })
|
|
51
|
+
*/
|
|
52
|
+
export declare function dynimPackages(packagesOrOptions: string[] | DynimPackagesOptions): Plugin;
|
|
3
53
|
export default dynimPackages;
|
|
4
54
|
//# sourceMappingURL=plugin.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../src/plugins/vite/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../src/plugins/vite/plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAKlC,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,QAAQ,EAAE,MAAM,EAAE,CAAA;CACnB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAC3B,iBAAiB,EAAE,MAAM,EAAE,GAAG,oBAAoB,GACjD,MAAM,CAwCR;AAED,eAAe,aAAa,CAAA"}
|
|
@@ -1,3 +1,82 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Vite plugin for Dynim package exposure
|
|
3
|
+
*
|
|
4
|
+
* Generates a virtual module that exports all specified packages,
|
|
5
|
+
* so you don't have to manually import and map each one.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* ```ts
|
|
9
|
+
* // vite.config.ts
|
|
10
|
+
* import { dynimPackages } from 'dynim-react/vite'
|
|
11
|
+
*
|
|
12
|
+
* export default {
|
|
13
|
+
* plugins: [
|
|
14
|
+
* dynimPackages([
|
|
15
|
+
* 'react-router-dom',
|
|
16
|
+
* '@tanstack/react-query',
|
|
17
|
+
* 'axios',
|
|
18
|
+
* ])
|
|
19
|
+
* ]
|
|
20
|
+
* }
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* Then in your app:
|
|
24
|
+
* ```tsx
|
|
25
|
+
* import packages from 'virtual:dynim-packages'
|
|
26
|
+
*
|
|
27
|
+
* <DynimProvider config={{ packages }}>
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
const VIRTUAL_MODULE_ID = 'virtual:dynim-packages';
|
|
31
|
+
const RESOLVED_VIRTUAL_MODULE_ID = '\0' + VIRTUAL_MODULE_ID;
|
|
32
|
+
/**
|
|
33
|
+
* Vite plugin that generates a virtual module exporting all specified packages.
|
|
34
|
+
*
|
|
35
|
+
* @param packages - Array of package names, or options object
|
|
36
|
+
* @returns Vite plugin
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* // Simple usage - array of package names
|
|
40
|
+
* dynimPackages(['react-router-dom', 'axios'])
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* // Options object
|
|
44
|
+
* dynimPackages({ packages: ['react-router-dom', 'axios'] })
|
|
45
|
+
*/
|
|
46
|
+
export function dynimPackages(packagesOrOptions) {
|
|
47
|
+
const packageNames = Array.isArray(packagesOrOptions)
|
|
48
|
+
? packagesOrOptions
|
|
49
|
+
: packagesOrOptions.packages;
|
|
50
|
+
return {
|
|
51
|
+
name: 'dynim-packages',
|
|
52
|
+
resolveId(id) {
|
|
53
|
+
if (id === VIRTUAL_MODULE_ID) {
|
|
54
|
+
return RESOLVED_VIRTUAL_MODULE_ID;
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
load(id) {
|
|
58
|
+
if (id === RESOLVED_VIRTUAL_MODULE_ID) {
|
|
59
|
+
// Generate import statements for each package
|
|
60
|
+
const imports = packageNames
|
|
61
|
+
.map((name, i) => `import * as _pkg${i} from '${name}'`)
|
|
62
|
+
.join('\n');
|
|
63
|
+
// Generate the packages object entries
|
|
64
|
+
// Spread namespace objects into plain objects so exports are enumerable
|
|
65
|
+
const entries = packageNames
|
|
66
|
+
.map((name, i) => ` '${name}': { ..._pkg${i} }`)
|
|
67
|
+
.join(',\n');
|
|
68
|
+
// Return the generated module code
|
|
69
|
+
return `${imports}
|
|
70
|
+
|
|
71
|
+
const packages = {
|
|
72
|
+
${entries}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export default packages
|
|
76
|
+
export { packages }
|
|
77
|
+
`;
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
}
|
|
3
82
|
export default dynimPackages;
|
package/dist/theme.d.ts
CHANGED
|
@@ -1,2 +1,58 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Dynim Theme System
|
|
3
|
+
*
|
|
4
|
+
* Theme is automatically fetched from the API per project.
|
|
5
|
+
* CSS variables are injected with defaults matching the original design.
|
|
6
|
+
*/
|
|
7
|
+
export interface DynimTheme {
|
|
8
|
+
accent?: string;
|
|
9
|
+
accentHover?: string;
|
|
10
|
+
builderBg?: string;
|
|
11
|
+
builderText?: string;
|
|
12
|
+
builderFont?: string;
|
|
13
|
+
builderRadius?: string;
|
|
14
|
+
builderOpacity?: string;
|
|
15
|
+
chatAccent?: string;
|
|
16
|
+
chatBg?: string;
|
|
17
|
+
chatText?: string;
|
|
18
|
+
chatFont?: string;
|
|
19
|
+
chatRadius?: string;
|
|
20
|
+
chatOpacity?: string;
|
|
21
|
+
selectionColor?: string;
|
|
22
|
+
hoverColor?: string;
|
|
23
|
+
selectionRadius?: string;
|
|
24
|
+
selectionOpacity?: string;
|
|
25
|
+
hoverOpacity?: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Default theme values - matches original SDK styling exactly
|
|
29
|
+
*/
|
|
30
|
+
export declare const defaultTheme: Required<DynimTheme>;
|
|
31
|
+
/**
|
|
32
|
+
* Generates CSS variable declarations from a theme object
|
|
33
|
+
*/
|
|
34
|
+
export declare function generateThemeCSS(theme?: DynimTheme): string;
|
|
35
|
+
/**
|
|
36
|
+
* CSS variable references for use in styles
|
|
37
|
+
*/
|
|
38
|
+
export declare const themeVars: {
|
|
39
|
+
readonly accent: "var(--dynim-accent)";
|
|
40
|
+
readonly accentHover: "var(--dynim-accent-hover)";
|
|
41
|
+
readonly builderBg: "var(--dynim-builder-bg)";
|
|
42
|
+
readonly builderText: "var(--dynim-builder-text)";
|
|
43
|
+
readonly builderFont: "var(--dynim-builder-font)";
|
|
44
|
+
readonly builderRadius: "var(--dynim-builder-radius)";
|
|
45
|
+
readonly builderOpacity: "var(--dynim-builder-opacity)";
|
|
46
|
+
readonly chatAccent: "var(--dynim-chat-accent)";
|
|
47
|
+
readonly chatBg: "var(--dynim-chat-bg)";
|
|
48
|
+
readonly chatText: "var(--dynim-chat-text)";
|
|
49
|
+
readonly chatFont: "var(--dynim-chat-font)";
|
|
50
|
+
readonly chatRadius: "var(--dynim-chat-radius)";
|
|
51
|
+
readonly chatOpacity: "var(--dynim-chat-opacity)";
|
|
52
|
+
readonly selectionColor: "var(--dynim-selection-color)";
|
|
53
|
+
readonly hoverColor: "var(--dynim-hover-color)";
|
|
54
|
+
readonly selectionRadius: "var(--dynim-selection-radius)";
|
|
55
|
+
readonly selectionOpacity: "var(--dynim-selection-opacity)";
|
|
56
|
+
readonly hoverOpacity: "var(--dynim-hover-opacity)";
|
|
57
|
+
};
|
|
2
58
|
//# sourceMappingURL=theme.d.ts.map
|
package/dist/theme.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../src/theme.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../src/theme.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,UAAU;IAEzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IAGxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IAGrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,eAAO,MAAM,YAAY,EAAE,QAAQ,CAAC,UAAU,CAwB7C,CAAC;AA+BF;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,GAAE,UAAe,GAAG,MAAM,CAW/D;AAED;;GAEG;AACH,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;CAwBZ,CAAC"}
|
package/dist/theme.js
CHANGED
|
@@ -1 +1,97 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Dynim Theme System
|
|
3
|
+
*
|
|
4
|
+
* Theme is automatically fetched from the API per project.
|
|
5
|
+
* CSS variables are injected with defaults matching the original design.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Default theme values - matches original SDK styling exactly
|
|
9
|
+
*/
|
|
10
|
+
export const defaultTheme = {
|
|
11
|
+
// Builder Bar - original values
|
|
12
|
+
accent: '#3b82f6',
|
|
13
|
+
accentHover: '#2563eb',
|
|
14
|
+
builderBg: '#000000',
|
|
15
|
+
builderText: '#ffffff',
|
|
16
|
+
builderFont: 'system-ui, -apple-system, BlinkMacSystemFont, \'Segoe UI\', Roboto, sans-serif',
|
|
17
|
+
builderRadius: '22px',
|
|
18
|
+
builderOpacity: '0.08',
|
|
19
|
+
// Chat Widget - original values
|
|
20
|
+
chatAccent: '#3b82f6',
|
|
21
|
+
chatBg: '#ffffff',
|
|
22
|
+
chatText: '#1f2937',
|
|
23
|
+
chatFont: 'system-ui, -apple-system, BlinkMacSystemFont, \'Segoe UI\', Roboto, sans-serif',
|
|
24
|
+
chatRadius: '16px',
|
|
25
|
+
chatOpacity: '0.08',
|
|
26
|
+
// Selection - original values
|
|
27
|
+
selectionColor: '#8b5cf6',
|
|
28
|
+
hoverColor: '#0ea5e9',
|
|
29
|
+
selectionRadius: '0',
|
|
30
|
+
selectionOpacity: '0.1',
|
|
31
|
+
hoverOpacity: '0.1',
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* CSS variable names mapped to theme keys
|
|
35
|
+
*/
|
|
36
|
+
const cssVarMap = {
|
|
37
|
+
// Builder Bar
|
|
38
|
+
accent: '--dynim-accent',
|
|
39
|
+
accentHover: '--dynim-accent-hover',
|
|
40
|
+
builderBg: '--dynim-builder-bg',
|
|
41
|
+
builderText: '--dynim-builder-text',
|
|
42
|
+
builderFont: '--dynim-builder-font',
|
|
43
|
+
builderRadius: '--dynim-builder-radius',
|
|
44
|
+
builderOpacity: '--dynim-builder-opacity',
|
|
45
|
+
// Chat Widget
|
|
46
|
+
chatAccent: '--dynim-chat-accent',
|
|
47
|
+
chatBg: '--dynim-chat-bg',
|
|
48
|
+
chatText: '--dynim-chat-text',
|
|
49
|
+
chatFont: '--dynim-chat-font',
|
|
50
|
+
chatRadius: '--dynim-chat-radius',
|
|
51
|
+
chatOpacity: '--dynim-chat-opacity',
|
|
52
|
+
// Selection
|
|
53
|
+
selectionColor: '--dynim-selection-color',
|
|
54
|
+
hoverColor: '--dynim-hover-color',
|
|
55
|
+
selectionRadius: '--dynim-selection-radius',
|
|
56
|
+
selectionOpacity: '--dynim-selection-opacity',
|
|
57
|
+
hoverOpacity: '--dynim-hover-opacity',
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Generates CSS variable declarations from a theme object
|
|
61
|
+
*/
|
|
62
|
+
export function generateThemeCSS(theme = {}) {
|
|
63
|
+
const merged = { ...defaultTheme, ...theme };
|
|
64
|
+
const vars = Object.entries(merged)
|
|
65
|
+
.map(([key, value]) => {
|
|
66
|
+
const cssVar = cssVarMap[key];
|
|
67
|
+
return `${cssVar}: ${value};`;
|
|
68
|
+
})
|
|
69
|
+
.join('\n ');
|
|
70
|
+
return `:root {\n ${vars}\n}`;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* CSS variable references for use in styles
|
|
74
|
+
*/
|
|
75
|
+
export const themeVars = {
|
|
76
|
+
// Builder Bar
|
|
77
|
+
accent: 'var(--dynim-accent)',
|
|
78
|
+
accentHover: 'var(--dynim-accent-hover)',
|
|
79
|
+
builderBg: 'var(--dynim-builder-bg)',
|
|
80
|
+
builderText: 'var(--dynim-builder-text)',
|
|
81
|
+
builderFont: 'var(--dynim-builder-font)',
|
|
82
|
+
builderRadius: 'var(--dynim-builder-radius)',
|
|
83
|
+
builderOpacity: 'var(--dynim-builder-opacity)',
|
|
84
|
+
// Chat Widget
|
|
85
|
+
chatAccent: 'var(--dynim-chat-accent)',
|
|
86
|
+
chatBg: 'var(--dynim-chat-bg)',
|
|
87
|
+
chatText: 'var(--dynim-chat-text)',
|
|
88
|
+
chatFont: 'var(--dynim-chat-font)',
|
|
89
|
+
chatRadius: 'var(--dynim-chat-radius)',
|
|
90
|
+
chatOpacity: 'var(--dynim-chat-opacity)',
|
|
91
|
+
// Selection
|
|
92
|
+
selectionColor: 'var(--dynim-selection-color)',
|
|
93
|
+
hoverColor: 'var(--dynim-hover-color)',
|
|
94
|
+
selectionRadius: 'var(--dynim-selection-radius)',
|
|
95
|
+
selectionOpacity: 'var(--dynim-selection-opacity)',
|
|
96
|
+
hoverOpacity: 'var(--dynim-hover-opacity)',
|
|
97
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dynim-react",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.63",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"dev": "tsc --watch"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"dynim-core": "^1.0.
|
|
30
|
+
"dynim-core": "^1.0.37"
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|
|
33
33
|
"react": ">=17.0.0",
|