dynim-react 1.0.8 → 1.0.10
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 +11 -439
- package/dist/builder/BuilderProvider.d.ts +2 -4
- package/dist/builder/BuilderProvider.d.ts.map +1 -1
- package/dist/builder/BuilderProvider.js +3 -15
- package/dist/builder/index.d.ts +0 -2
- package/dist/builder/index.d.ts.map +1 -1
- package/dist/builder/index.js +0 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -3
- package/package.json +2 -2
- package/dist/builder/EditableZone.d.ts +0 -73
- package/dist/builder/EditableZone.d.ts.map +0 -1
- package/dist/builder/EditableZone.js +0 -83
- package/dist/inference/DynimProvider.d.ts +0 -23
- package/dist/inference/DynimProvider.d.ts.map +0 -1
- package/dist/inference/DynimProvider.js +0 -231
- package/dist/inference/createDynimSDK.d.ts +0 -39
- package/dist/inference/createDynimSDK.d.ts.map +0 -1
- package/dist/inference/createDynimSDK.js +0 -61
package/README.md
CHANGED
|
@@ -1,447 +1,19 @@
|
|
|
1
1
|
# dynim-react
|
|
2
2
|
|
|
3
|
-
React components
|
|
3
|
+
React components for visual page building and tenant customization.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Documentation
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
npm install dynim-react
|
|
9
|
-
# dynim-core is included as a dependency
|
|
10
|
-
```
|
|
11
|
-
|
|
12
|
-
**Peer Dependencies:**
|
|
13
|
-
- `react` >= 17.0.0
|
|
14
|
-
- `react-dom` >= 17.0.0
|
|
15
|
-
|
|
16
|
-
## Overview
|
|
17
|
-
|
|
18
|
-
This package has two main modules:
|
|
19
|
-
|
|
20
|
-
1. **Builder** - Visual builder integration for editing pages/components with AI chat and code generation
|
|
21
|
-
2. **Inference** - Dynamic loading of tenant-specific customization bundles
|
|
22
|
-
|
|
23
|
-
## Folder Structure
|
|
24
|
-
|
|
25
|
-
```
|
|
26
|
-
src/
|
|
27
|
-
├── index.ts # Main entry point
|
|
28
|
-
├── builder/
|
|
29
|
-
│ ├── BuilderProvider.tsx # Visual builder React provider
|
|
30
|
-
│ ├── EditableZone.tsx # Zone wrappers for customization control
|
|
31
|
-
│ ├── ChatContext.tsx # Chat state context
|
|
32
|
-
│ ├── useChatbot.ts # Headless chat hook
|
|
33
|
-
│ ├── MessageList.tsx # Message display component
|
|
34
|
-
│ └── ChatInput.tsx # Chat input component
|
|
35
|
-
└── inference/
|
|
36
|
-
├── types.ts # TypeScript definitions
|
|
37
|
-
├── sharedContext.ts # Shared context registration
|
|
38
|
-
└── InferenceProvider.tsx # Tenant bundle loader
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
## Builder Module
|
|
42
|
-
|
|
43
|
-
### BuilderProvider
|
|
44
|
-
|
|
45
|
-
Main provider component that integrates the visual builder UI into your app.
|
|
46
|
-
|
|
47
|
-
```tsx
|
|
48
|
-
import { BuilderProvider, useBuilder } from 'dynim-react';
|
|
49
|
-
|
|
50
|
-
function App() {
|
|
51
|
-
return (
|
|
52
|
-
<BuilderProvider
|
|
53
|
-
config={{
|
|
54
|
-
apiBase: 'https://api.example.com',
|
|
55
|
-
pageId: '/dashboard',
|
|
56
|
-
sessionToken: jwtToken,
|
|
57
|
-
onCodeEdit: (edit) => console.log('Code changed:', edit),
|
|
58
|
-
}}
|
|
59
|
-
onBuilderReady={(ctx) => console.log('Builder ready!')}
|
|
60
|
-
>
|
|
61
|
-
<YourApp />
|
|
62
|
-
</BuilderProvider>
|
|
63
|
-
);
|
|
64
|
-
}
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
**Config Options:**
|
|
68
|
-
|
|
69
|
-
```tsx
|
|
70
|
-
interface BuilderConfig {
|
|
71
|
-
apiBase?: string; // Default: 'http://localhost:8080'
|
|
72
|
-
pageId?: string; // Default: window.location.pathname
|
|
73
|
-
logo?: string; // Builder UI logo text
|
|
74
|
-
contentRoot?: HTMLElement; // Default: document.body
|
|
75
|
-
sessionToken?: string; // JWT authentication token
|
|
76
|
-
refreshToken?: string; // For token renewal
|
|
77
|
-
getSession?: () => Promise<{ token: string }>; // Dynamic token fetching
|
|
78
|
-
onMessage?: (data: BuilderMessage) => void; // Chat message callback
|
|
79
|
-
onError?: (error: Error) => void; // Error callback
|
|
80
|
-
onCodeMessage?: (event: CodeEvent) => void; // Code generation events
|
|
81
|
-
onCodeEdit?: (edit: CodeEdit) => void; // Code edit callback
|
|
82
|
-
}
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
### useBuilder Hook
|
|
86
|
-
|
|
87
|
-
Access builder controls from any child component:
|
|
88
|
-
|
|
89
|
-
```tsx
|
|
90
|
-
function EditorToolbar() {
|
|
91
|
-
const {
|
|
92
|
-
// Builder controls
|
|
93
|
-
enterBuilder, // () => void - Enter edit mode
|
|
94
|
-
exitBuilder, // () => void - Exit without saving
|
|
95
|
-
saveBuilder, // () => Promise<void> - Save and exit
|
|
96
|
-
isBuilderActive, // boolean - Current edit state
|
|
97
|
-
|
|
98
|
-
// Chat
|
|
99
|
-
sendChat, // (message: string) => Promise<void>
|
|
100
|
-
sendElementChat, // (message: string, element: HTMLElement) => Promise<void>
|
|
101
|
-
|
|
102
|
-
// Code generation (Flexcode)
|
|
103
|
-
sendCode, // (projectId: string, prompt: string) => Promise<void>
|
|
104
|
-
saveCode, // (projectId: string) => Promise<void>
|
|
105
|
-
abandonCode, // (projectId: string) => Promise<void>
|
|
106
|
-
codeEdits, // CodeEdit[] - Pending code changes
|
|
107
|
-
|
|
108
|
-
// Builder instance
|
|
109
|
-
getBuilder, // () => Builder - Get underlying builder instance
|
|
110
|
-
} = useBuilder();
|
|
7
|
+
See [SDK React Documentation](../../utils/docs/sdk/REACT.md)
|
|
111
8
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
<button onClick={saveBuilder} disabled={!isBuilderActive}>
|
|
118
|
-
Save Changes
|
|
119
|
-
</button>
|
|
120
|
-
</div>
|
|
121
|
-
);
|
|
122
|
-
}
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
### Chat Components
|
|
126
|
-
|
|
127
|
-
Pre-built chat UI components:
|
|
128
|
-
|
|
129
|
-
```tsx
|
|
130
|
-
import { ChatProvider, MessageList, ChatInput } from 'dynim-react';
|
|
131
|
-
|
|
132
|
-
function BuilderChat() {
|
|
133
|
-
return (
|
|
134
|
-
<ChatProvider endpoint="/api/chat" apiKey="...">
|
|
135
|
-
<MessageList showAvatars showTimestamps={false} />
|
|
136
|
-
<ChatInput placeholder="Ask the builder..." />
|
|
137
|
-
</ChatProvider>
|
|
138
|
-
);
|
|
139
|
-
}
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
### useChatbot Hook
|
|
143
|
-
|
|
144
|
-
Headless hook for building custom chat UIs:
|
|
145
|
-
|
|
146
|
-
```tsx
|
|
147
|
-
import { useChatbot } from 'dynim-react';
|
|
148
|
-
|
|
149
|
-
function CustomChat() {
|
|
150
|
-
const {
|
|
151
|
-
messages, // Message[] - Array of chat messages
|
|
152
|
-
isLoading, // boolean - Response being fetched
|
|
153
|
-
isTyping, // boolean - AI typing indicator
|
|
154
|
-
sendMessage, // (text: string) => Promise<void>
|
|
155
|
-
clearMessages, // () => void - Clear history
|
|
156
|
-
} = useChatbot({
|
|
157
|
-
endpoint: '/api/chat',
|
|
158
|
-
apiKey: 'your-api-key',
|
|
159
|
-
onError: (error) => console.error(error),
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
return (
|
|
163
|
-
<div>
|
|
164
|
-
{messages.map(msg => (
|
|
165
|
-
<div key={msg.id} className={msg.role}>
|
|
166
|
-
{msg.text}
|
|
167
|
-
</div>
|
|
168
|
-
))}
|
|
169
|
-
<form onSubmit={(e) => {
|
|
170
|
-
e.preventDefault();
|
|
171
|
-
sendMessage(e.target.message.value);
|
|
172
|
-
e.target.reset();
|
|
173
|
-
}}>
|
|
174
|
-
<input name="message" disabled={isLoading} />
|
|
175
|
-
<button type="submit">Send</button>
|
|
176
|
-
</form>
|
|
177
|
-
</div>
|
|
178
|
-
);
|
|
179
|
-
}
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
**Message Type:**
|
|
183
|
-
|
|
184
|
-
```tsx
|
|
185
|
-
interface Message {
|
|
186
|
-
id: string;
|
|
187
|
-
role: 'user' | 'assistant';
|
|
188
|
-
text: string;
|
|
189
|
-
timestamp: Date;
|
|
190
|
-
}
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
### Zone Components
|
|
194
|
-
|
|
195
|
-
Control which parts of your UI can be customized in the builder:
|
|
196
|
-
|
|
197
|
-
```tsx
|
|
198
|
-
import { LockedZone, EditableZone } from 'dynim-react';
|
|
199
|
-
|
|
200
|
-
function App() {
|
|
201
|
-
return (
|
|
202
|
-
<div>
|
|
203
|
-
<LockedZone>
|
|
204
|
-
<Navigation /> {/* Protected - cannot be modified */}
|
|
205
|
-
</LockedZone>
|
|
206
|
-
|
|
207
|
-
<main>
|
|
208
|
-
{/* Editable by default */}
|
|
209
|
-
<Hero />
|
|
210
|
-
<Features />
|
|
211
|
-
</main>
|
|
212
|
-
|
|
213
|
-
<LockedZone>
|
|
214
|
-
<Sidebar>
|
|
215
|
-
<Logo /> {/* Locked */}
|
|
216
|
-
<EditableZone>
|
|
217
|
-
<CustomWidgets /> {/* Editable island inside locked zone */}
|
|
218
|
-
</EditableZone>
|
|
219
|
-
</Sidebar>
|
|
220
|
-
</LockedZone>
|
|
221
|
-
</div>
|
|
222
|
-
);
|
|
223
|
-
}
|
|
224
|
-
```
|
|
225
|
-
|
|
226
|
-
**Zone Props:**
|
|
227
|
-
|
|
228
|
-
```tsx
|
|
229
|
-
// Custom wrapper element
|
|
230
|
-
<EditableZone as="section" className="content">
|
|
231
|
-
<Content />
|
|
232
|
-
</EditableZone>
|
|
233
|
-
|
|
234
|
-
// Aliases
|
|
235
|
-
<NonCustomizable> {/* Same as LockedZone */}
|
|
236
|
-
<Customizable> {/* Same as EditableZone */}
|
|
237
|
-
```
|
|
9
|
+
Related:
|
|
10
|
+
- [SDK Overview](../../utils/docs/sdk/README.md)
|
|
11
|
+
- [SDK Core](../../utils/docs/sdk/CORE.md)
|
|
12
|
+
- [UI Builder](../../utils/docs/ui-builder/README.md)
|
|
13
|
+
- [Inference Server](../../utils/docs/inference-server/README.md)
|
|
238
14
|
|
|
239
|
-
|
|
240
|
-
- `EditableZone` / `Customizable` - Creates editable areas (sets `vis="true"`)
|
|
15
|
+
## Install
|
|
241
16
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
### InferenceProvider
|
|
245
|
-
|
|
246
|
-
Dynamically loads and renders tenant-specific customization bundles.
|
|
247
|
-
|
|
248
|
-
```tsx
|
|
249
|
-
import { InferenceProvider } from 'dynim-react';
|
|
250
|
-
|
|
251
|
-
function App() {
|
|
252
|
-
const { tenantId } = useAuth();
|
|
253
|
-
|
|
254
|
-
return (
|
|
255
|
-
<InferenceProvider
|
|
256
|
-
tenantId={tenantId}
|
|
257
|
-
bundleUrl={(id) => `https://cdn.example.com/bundles/${id}.js`}
|
|
258
|
-
checkCustomizations={async (id) => {
|
|
259
|
-
const res = await fetch(`/api/customizations/${id}`);
|
|
260
|
-
return res.ok;
|
|
261
|
-
}}
|
|
262
|
-
loadingComponent={<Spinner />}
|
|
263
|
-
errorBanner={true}
|
|
264
|
-
onLoad={(id) => console.log(`Loaded for ${id}`)}
|
|
265
|
-
onError={(err, id) => console.error(`Failed for ${id}:`, err)}
|
|
266
|
-
>
|
|
267
|
-
<BaseApp />
|
|
268
|
-
</InferenceProvider>
|
|
269
|
-
);
|
|
270
|
-
}
|
|
271
|
-
```
|
|
272
|
-
|
|
273
|
-
**Props:**
|
|
274
|
-
|
|
275
|
-
```tsx
|
|
276
|
-
interface InferenceProviderProps {
|
|
277
|
-
tenantId: string | null; // Current tenant (null = no customization)
|
|
278
|
-
bundleUrl: string | ((id: string) => string); // Bundle URL or URL builder
|
|
279
|
-
bundleToken?: string; // Auth token for bundle fetch
|
|
280
|
-
checkCustomizations?: (id: string) => Promise<bool>; // Pre-check if tenant has bundle
|
|
281
|
-
loadingComponent?: ReactNode; // Custom loading UI
|
|
282
|
-
errorBanner?: boolean | ReactNode; // Show errors (default: false)
|
|
283
|
-
onError?: (error: Error, tenantId: string) => void;
|
|
284
|
-
onLoad?: (tenantId: string) => void;
|
|
285
|
-
children: ReactNode; // Fallback/default app
|
|
286
|
-
}
|
|
287
|
-
```
|
|
288
|
-
|
|
289
|
-
**Loading States:**
|
|
290
|
-
|
|
291
|
-
`idle` → `checking` → `loading` → `loaded` / `error` / `no-customization`
|
|
292
|
-
|
|
293
|
-
### Shared Context
|
|
294
|
-
|
|
295
|
-
Tenant bundles access the host app's React and custom hooks via a shared context on `window.__DYNIM__`:
|
|
296
|
-
|
|
297
|
-
```tsx
|
|
298
|
-
import { createSharedContext, getSharedContext, isSharedContextReady } from 'dynim-react';
|
|
299
|
-
|
|
300
|
-
// Register shared context (call once at app initialization)
|
|
301
|
-
createSharedContext({
|
|
302
|
-
React,
|
|
303
|
-
ReactDOM,
|
|
304
|
-
hooks: { useAuth, useTheme, useNotifications },
|
|
305
|
-
contexts: { AuthContext, ThemeContext },
|
|
306
|
-
globals: { utils: myUtils },
|
|
307
|
-
});
|
|
308
|
-
|
|
309
|
-
// Check if ready
|
|
310
|
-
if (isSharedContextReady()) {
|
|
311
|
-
const ctx = getSharedContext();
|
|
312
|
-
// ...
|
|
313
|
-
}
|
|
314
|
-
```
|
|
315
|
-
|
|
316
|
-
**Writing a Tenant Bundle:**
|
|
317
|
-
|
|
318
|
-
```typescript
|
|
319
|
-
// tenant-bundle.ts
|
|
320
|
-
const { React, ReactDOM, hooks, contexts } = window.__DYNIM__;
|
|
321
|
-
const { useAuth, useTheme } = hooks;
|
|
322
|
-
|
|
323
|
-
function TenantCustomization() {
|
|
324
|
-
const { user } = useAuth();
|
|
325
|
-
const { theme } = useTheme();
|
|
326
|
-
|
|
327
|
-
return (
|
|
328
|
-
<div style={{ background: theme.bg }}>
|
|
329
|
-
<h1>Welcome, {user.name}!</h1>
|
|
330
|
-
<p>Custom content for {user.tenantId}</p>
|
|
331
|
-
</div>
|
|
332
|
-
);
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
// Render into the designated root
|
|
336
|
-
const root = document.getElementById('dynim-root');
|
|
337
|
-
ReactDOM.render(<TenantCustomization />, root);
|
|
338
|
-
```
|
|
339
|
-
|
|
340
|
-
## Architecture
|
|
341
|
-
|
|
342
|
-
```
|
|
343
|
-
Application
|
|
344
|
-
│
|
|
345
|
-
├── BuilderProvider (visual editing)
|
|
346
|
-
│ ├── Creates builder instance (dynim-core)
|
|
347
|
-
│ ├── Manages SSE streaming for chat/code
|
|
348
|
-
│ ├── Handles drag-and-drop, history, diffs
|
|
349
|
-
│ └── Exposes useBuilder hook
|
|
350
|
-
│
|
|
351
|
-
└── InferenceProvider (tenant customization)
|
|
352
|
-
├── Registers global SDK (window.__DYNIM__)
|
|
353
|
-
├── Loads tenant bundle script
|
|
354
|
-
├── Renders bundle into #dynim-root
|
|
355
|
-
└── Falls back to children if no customizations
|
|
356
|
-
```
|
|
357
|
-
|
|
358
|
-
## Exports
|
|
359
|
-
|
|
360
|
-
```tsx
|
|
361
|
-
// Builder
|
|
362
|
-
export { BuilderProvider, useBuilder } from './builder';
|
|
363
|
-
export { ChatProvider, useChatContext } from './builder';
|
|
364
|
-
export { MessageList, ChatInput, useChatbot } from './builder';
|
|
365
|
-
export { LockedZone, EditableZone, NonCustomizable, Customizable } from './builder';
|
|
366
|
-
|
|
367
|
-
// Inference
|
|
368
|
-
export { InferenceProvider } from './inference';
|
|
369
|
-
export { createSharedContext, getSharedContext, isSharedContextReady } from './inference';
|
|
370
|
-
|
|
371
|
-
// Re-exports everything from dynim-core
|
|
372
|
-
export * from 'dynim-core';
|
|
373
|
-
```
|
|
374
|
-
|
|
375
|
-
## Re-exports from dynim-core
|
|
376
|
-
|
|
377
|
-
For convenience, `dynim-react` re-exports all of `dynim-core`:
|
|
378
|
-
|
|
379
|
-
```tsx
|
|
380
|
-
import {
|
|
381
|
-
// State
|
|
382
|
-
createState,
|
|
383
|
-
|
|
384
|
-
// Clients
|
|
385
|
-
createClient,
|
|
386
|
-
createBuilderClient,
|
|
387
|
-
createCodeClient,
|
|
388
|
-
|
|
389
|
-
// Builder
|
|
390
|
-
createBuilder,
|
|
391
|
-
createEditorState,
|
|
392
|
-
createHistoryState,
|
|
393
|
-
createTreeState,
|
|
394
|
-
createDiffState,
|
|
395
|
-
|
|
396
|
-
// UI
|
|
397
|
-
createWidget,
|
|
398
|
-
createOverlays,
|
|
399
|
-
createFreezeOverlay,
|
|
400
|
-
createDragEngine,
|
|
401
|
-
createAIPromptPopover,
|
|
402
|
-
|
|
403
|
-
// DOM utilities
|
|
404
|
-
scanDOM,
|
|
405
|
-
getStableId,
|
|
406
|
-
findByStableId,
|
|
407
|
-
buildElementIdentifier,
|
|
408
|
-
|
|
409
|
-
// Classifier
|
|
410
|
-
createClassifier,
|
|
411
|
-
} from 'dynim-react';
|
|
412
|
-
```
|
|
413
|
-
|
|
414
|
-
## TypeScript
|
|
415
|
-
|
|
416
|
-
Full TypeScript support with exported types:
|
|
417
|
-
|
|
418
|
-
```tsx
|
|
419
|
-
import type {
|
|
420
|
-
// Config
|
|
421
|
-
BuilderConfig,
|
|
422
|
-
BuilderContextValue,
|
|
423
|
-
ChatbotConfig,
|
|
424
|
-
InferenceProviderProps,
|
|
425
|
-
DynimSDKConfig,
|
|
426
|
-
|
|
427
|
-
// Props
|
|
428
|
-
ZoneProps,
|
|
429
|
-
MessageListProps,
|
|
430
|
-
ChatInputProps,
|
|
431
|
-
|
|
432
|
-
// Data
|
|
433
|
-
Message,
|
|
434
|
-
ChatState,
|
|
435
|
-
CodeEdit,
|
|
436
|
-
CodeEvent,
|
|
437
|
-
DiffEntry,
|
|
438
|
-
BuilderMessage,
|
|
439
|
-
|
|
440
|
-
// Global
|
|
441
|
-
DynimGlobal,
|
|
442
|
-
} from 'dynim-react';
|
|
17
|
+
```bash
|
|
18
|
+
npm install dynim-react
|
|
443
19
|
```
|
|
444
|
-
|
|
445
|
-
## License
|
|
446
|
-
|
|
447
|
-
MIT
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* BuilderProvider - React integration for the visual builder
|
|
3
3
|
*
|
|
4
|
-
* Integrates the visual builder UI (floating bar,
|
|
5
|
-
*
|
|
6
|
-
* them as React components.
|
|
4
|
+
* Integrates the visual builder UI (floating bar, overlays) from dynim-core.
|
|
5
|
+
* Loads tenant bundles via dynamic import() and renders them as React components.
|
|
7
6
|
*/
|
|
8
7
|
import { type ReactNode } from 'react';
|
|
9
8
|
import type { BuilderInstance, CodeEdit, CodeEvent, CodeMessage } from 'dynim-core';
|
|
@@ -44,7 +43,6 @@ export interface BuilderConfig {
|
|
|
44
43
|
export interface BuilderContextValue {
|
|
45
44
|
enterBuilder: () => void;
|
|
46
45
|
exitBuilder: () => void;
|
|
47
|
-
saveBuilder: () => Promise<void>;
|
|
48
46
|
isBuilderActive: boolean;
|
|
49
47
|
getBuilder: () => BuilderInstance | null;
|
|
50
48
|
sendCode: (query: string) => Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BuilderProvider.d.ts","sourceRoot":"","sources":["../../src/builder/BuilderProvider.tsx"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"BuilderProvider.d.ts","sourceRoot":"","sources":["../../src/builder/BuilderProvider.tsx"],"names":[],"mappings":"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"}
|
|
@@ -2,9 +2,8 @@ import { jsxs as _jsxs, Fragment as _Fragment, jsx as _jsx } from "react/jsx-run
|
|
|
2
2
|
/**
|
|
3
3
|
* BuilderProvider - React integration for the visual builder
|
|
4
4
|
*
|
|
5
|
-
* Integrates the visual builder UI (floating bar,
|
|
6
|
-
*
|
|
7
|
-
* them as React components.
|
|
5
|
+
* Integrates the visual builder UI (floating bar, overlays) from dynim-core.
|
|
6
|
+
* Loads tenant bundles via dynamic import() and renders them as React components.
|
|
8
7
|
*/
|
|
9
8
|
import React, { createContext, useContext, useEffect, useRef, useCallback, useMemo, useState, } from 'react';
|
|
10
9
|
import ReactDOM from 'react-dom';
|
|
@@ -107,15 +106,12 @@ export function BuilderProvider({ children, config = {}, onBuilderReady, }) {
|
|
|
107
106
|
console.log('[BuilderProvider] Visual builder exited');
|
|
108
107
|
setIsBuilderActive(false);
|
|
109
108
|
},
|
|
110
|
-
onSave: (diffs) => {
|
|
111
|
-
console.log('[BuilderProvider] Changes saved:', diffs);
|
|
112
|
-
},
|
|
113
109
|
});
|
|
114
110
|
return () => {
|
|
115
111
|
builderRef.current?.destroy();
|
|
116
112
|
};
|
|
117
113
|
}, [config]);
|
|
118
|
-
// Initialize builder client for visual builder operations (
|
|
114
|
+
// Initialize builder client for visual builder operations (preview, exit)
|
|
119
115
|
useEffect(() => {
|
|
120
116
|
const { apiBase = 'http://localhost:8080', sessionToken, refreshToken, getSession, onError, } = config;
|
|
121
117
|
builderClientRef.current = createBuilderClient({
|
|
@@ -141,12 +137,6 @@ export function BuilderProvider({ children, config = {}, onBuilderReady, }) {
|
|
|
141
137
|
builderRef.current.exit();
|
|
142
138
|
}
|
|
143
139
|
}, []);
|
|
144
|
-
// Save and exit builder mode
|
|
145
|
-
const saveBuilder = useCallback(async () => {
|
|
146
|
-
if (builderRef.current && builderRef.current.isActive()) {
|
|
147
|
-
await builderRef.current.save();
|
|
148
|
-
}
|
|
149
|
-
}, []);
|
|
150
140
|
/**
|
|
151
141
|
* Get auth token for bundle requests
|
|
152
142
|
*/
|
|
@@ -313,7 +303,6 @@ export function BuilderProvider({ children, config = {}, onBuilderReady, }) {
|
|
|
313
303
|
const contextValue = useMemo(() => ({
|
|
314
304
|
enterBuilder,
|
|
315
305
|
exitBuilder,
|
|
316
|
-
saveBuilder,
|
|
317
306
|
isBuilderActive,
|
|
318
307
|
getBuilder: () => builderRef.current,
|
|
319
308
|
// Code client methods
|
|
@@ -335,7 +324,6 @@ export function BuilderProvider({ children, config = {}, onBuilderReady, }) {
|
|
|
335
324
|
}), [
|
|
336
325
|
enterBuilder,
|
|
337
326
|
exitBuilder,
|
|
338
|
-
saveBuilder,
|
|
339
327
|
isBuilderActive,
|
|
340
328
|
sendCode,
|
|
341
329
|
saveCode,
|
package/dist/builder/index.d.ts
CHANGED
|
@@ -13,6 +13,4 @@ export { CodeChatPanel } from './CodeChatPanel';
|
|
|
13
13
|
export type { CodeChatPanelProps } from './CodeChatPanel';
|
|
14
14
|
export { useChatbot } from './useChatbot';
|
|
15
15
|
export type { UseChatbotConfig, UseChatbotReturn } from './useChatbot';
|
|
16
|
-
export { LockedZone, EditableZone, NonCustomizable, Customizable, } from './EditableZone';
|
|
17
|
-
export type { ZoneProps } from './EditableZone';
|
|
18
16
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/builder/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAChE,YAAY,EAAE,aAAa,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAGlG,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC7D,YAAY,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAGvD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,YAAY,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEtD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,YAAY,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAG1D,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,YAAY,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/builder/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAChE,YAAY,EAAE,aAAa,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAGlG,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC7D,YAAY,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAGvD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,YAAY,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEtD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,YAAY,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAG1D,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,YAAY,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/builder/index.js
CHANGED
|
@@ -11,5 +11,3 @@ export { ChatInput } from './ChatInput';
|
|
|
11
11
|
export { CodeChatPanel } from './CodeChatPanel';
|
|
12
12
|
// Headless hook for custom UI
|
|
13
13
|
export { useChatbot } from './useChatbot';
|
|
14
|
-
// Zone wrappers for builder customization control
|
|
15
|
-
export { LockedZone, EditableZone, NonCustomizable, Customizable, } from './EditableZone';
|
package/dist/index.d.ts
CHANGED
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
* - Inference SDK for tenant customization loading
|
|
8
8
|
*/
|
|
9
9
|
export * from 'dynim-core';
|
|
10
|
-
export { BuilderProvider, useBuilder, ChatProvider, useChatContext, MessageList, ChatInput, CodeChatPanel, useChatbot,
|
|
11
|
-
export type { BuilderConfig, BuilderContextValue, BuilderProviderProps, ChatProviderProps, MessageListProps, ChatInputProps, CodeChatPanelProps, UseChatbotConfig, UseChatbotReturn,
|
|
10
|
+
export { BuilderProvider, useBuilder, ChatProvider, useChatContext, MessageList, ChatInput, CodeChatPanel, useChatbot, } from './builder';
|
|
11
|
+
export type { BuilderConfig, BuilderContextValue, BuilderProviderProps, ChatProviderProps, MessageListProps, ChatInputProps, CodeChatPanelProps, UseChatbotConfig, UseChatbotReturn, } from './builder';
|
|
12
12
|
export { InferenceProvider, InferenceProviderDefault, createSharedContext, getSharedContext, isSharedContextReady, } from './inference';
|
|
13
13
|
export type { DynimSDKConfig, InferenceProviderProps, InferenceState, DynimGlobal, } from './inference';
|
|
14
14
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,cAAc,YAAY,CAAC;AAG3B,OAAO,EAEL,eAAe,EACf,UAAU,EAEV,YAAY,EACZ,cAAc,EAEd,WAAW,EACX,SAAS,EACT,aAAa,EAEb,UAAU,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,cAAc,YAAY,CAAC;AAG3B,OAAO,EAEL,eAAe,EACf,UAAU,EAEV,YAAY,EACZ,cAAc,EAEd,WAAW,EACX,SAAS,EACT,aAAa,EAEb,UAAU,GACX,MAAM,WAAW,CAAC;AAEnB,YAAY,EACV,aAAa,EACb,mBAAmB,EACnB,oBAAoB,EACpB,iBAAiB,EACjB,gBAAgB,EAChB,cAAc,EACd,kBAAkB,EAClB,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,WAAW,CAAC;AAGnB,OAAO,EACL,iBAAiB,EACjB,wBAAwB,EACxB,mBAAmB,EACnB,gBAAgB,EAChB,oBAAoB,GACrB,MAAM,aAAa,CAAC;AAErB,YAAY,EACV,cAAc,EACd,sBAAsB,EACtB,cAAc,EACd,WAAW,GACZ,MAAM,aAAa,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -17,8 +17,6 @@ ChatProvider, useChatContext,
|
|
|
17
17
|
// Components
|
|
18
18
|
MessageList, ChatInput, CodeChatPanel,
|
|
19
19
|
// Headless hook
|
|
20
|
-
useChatbot,
|
|
21
|
-
// Zone wrappers for customization control
|
|
22
|
-
LockedZone, EditableZone, NonCustomizable, Customizable, } from './builder';
|
|
20
|
+
useChatbot, } from './builder';
|
|
23
21
|
// Inference exports
|
|
24
22
|
export { InferenceProvider, InferenceProviderDefault, createSharedContext, getSharedContext, isSharedContextReady, } from './inference';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dynim-react",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.10",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"dev": "tsc --watch"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"dynim-core": "^1.0.
|
|
16
|
+
"dynim-core": "^1.0.6"
|
|
17
17
|
},
|
|
18
18
|
"peerDependencies": {
|
|
19
19
|
"react": ">=17.0.0",
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import { type ReactNode, type HTMLAttributes } from 'react';
|
|
2
|
-
/**
|
|
3
|
-
* Props for zone wrapper components
|
|
4
|
-
*/
|
|
5
|
-
export interface ZoneProps extends HTMLAttributes<HTMLDivElement> {
|
|
6
|
-
/** Content to wrap */
|
|
7
|
-
children: ReactNode;
|
|
8
|
-
/** HTML tag to render (default: 'div') */
|
|
9
|
-
as?: keyof JSX.IntrinsicElements;
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* LockedZone - Wraps content to prevent builder customization
|
|
13
|
-
*
|
|
14
|
-
* Elements inside a LockedZone cannot be:
|
|
15
|
-
* - Dragged/moved by the builder
|
|
16
|
-
* - Used as drop targets
|
|
17
|
-
*
|
|
18
|
-
* Use this to protect parts of your UI that should not be editable,
|
|
19
|
-
* like navigation, footers, or critical UI elements.
|
|
20
|
-
*
|
|
21
|
-
* @example
|
|
22
|
-
* ```tsx
|
|
23
|
-
* <LockedZone>
|
|
24
|
-
* <Navigation /> {/* Cannot be moved or modified *\/}
|
|
25
|
-
* </LockedZone>
|
|
26
|
-
*
|
|
27
|
-
* <div>
|
|
28
|
-
* {/* This content is editable *\/}
|
|
29
|
-
* </div>
|
|
30
|
-
* ```
|
|
31
|
-
*
|
|
32
|
-
* @example Nested zones
|
|
33
|
-
* ```tsx
|
|
34
|
-
* <LockedZone>
|
|
35
|
-
* <Sidebar>
|
|
36
|
-
* <Logo /> {/* Locked *\/}
|
|
37
|
-
* <EditableZone>
|
|
38
|
-
* <CustomWidgets /> {/* Editable "island" inside locked zone *\/}
|
|
39
|
-
* </EditableZone>
|
|
40
|
-
* </Sidebar>
|
|
41
|
-
* </LockedZone>
|
|
42
|
-
* ```
|
|
43
|
-
*/
|
|
44
|
-
export declare const LockedZone: import("react").ForwardRefExoticComponent<ZoneProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
45
|
-
/**
|
|
46
|
-
* EditableZone - Explicitly marks content as editable in the builder
|
|
47
|
-
*
|
|
48
|
-
* Use this to:
|
|
49
|
-
* - Create editable "islands" inside a LockedZone
|
|
50
|
-
* - Explicitly mark content as editable (though content is editable by default)
|
|
51
|
-
*
|
|
52
|
-
* @example Create editable area inside locked zone
|
|
53
|
-
* ```tsx
|
|
54
|
-
* <LockedZone>
|
|
55
|
-
* <Header>
|
|
56
|
-
* <Logo /> {/* Locked *\/}
|
|
57
|
-
* <EditableZone>
|
|
58
|
-
* <UserMenu /> {/* Editable despite being inside LockedZone *\/}
|
|
59
|
-
* </EditableZone>
|
|
60
|
-
* </Header>
|
|
61
|
-
* </LockedZone>
|
|
62
|
-
* ```
|
|
63
|
-
*/
|
|
64
|
-
export declare const EditableZone: import("react").ForwardRefExoticComponent<ZoneProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
65
|
-
/**
|
|
66
|
-
* Alias for LockedZone - more explicit naming
|
|
67
|
-
*/
|
|
68
|
-
export declare const NonCustomizable: import("react").ForwardRefExoticComponent<ZoneProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
69
|
-
/**
|
|
70
|
-
* Alias for EditableZone - more explicit naming
|
|
71
|
-
*/
|
|
72
|
-
export declare const Customizable: import("react").ForwardRefExoticComponent<ZoneProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
73
|
-
//# sourceMappingURL=EditableZone.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"EditableZone.d.ts","sourceRoot":"","sources":["../../src/builder/EditableZone.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,cAAc,EAAc,MAAM,OAAO,CAAC;AAGxE;;GAEG;AACH,MAAM,WAAW,SAAU,SAAQ,cAAc,CAAC,cAAc,CAAC;IAC/D,sBAAsB;IACtB,QAAQ,EAAE,SAAS,CAAC;IACpB,0CAA0C;IAC1C,EAAE,CAAC,EAAE,MAAM,GAAG,CAAC,iBAAiB,CAAC;CAClC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,eAAO,MAAM,UAAU,sGAYtB,CAAC;AAEF;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,YAAY,sGAYxB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,eAAe,sGAAa,CAAC;AAE1C;;GAEG;AACH,eAAO,MAAM,YAAY,sGAAe,CAAC"}
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { forwardRef } from 'react';
|
|
3
|
-
import { VISIBILITY_ATTR } from 'dynim-core';
|
|
4
|
-
/**
|
|
5
|
-
* LockedZone - Wraps content to prevent builder customization
|
|
6
|
-
*
|
|
7
|
-
* Elements inside a LockedZone cannot be:
|
|
8
|
-
* - Dragged/moved by the builder
|
|
9
|
-
* - Used as drop targets
|
|
10
|
-
*
|
|
11
|
-
* Use this to protect parts of your UI that should not be editable,
|
|
12
|
-
* like navigation, footers, or critical UI elements.
|
|
13
|
-
*
|
|
14
|
-
* @example
|
|
15
|
-
* ```tsx
|
|
16
|
-
* <LockedZone>
|
|
17
|
-
* <Navigation /> {/* Cannot be moved or modified *\/}
|
|
18
|
-
* </LockedZone>
|
|
19
|
-
*
|
|
20
|
-
* <div>
|
|
21
|
-
* {/* This content is editable *\/}
|
|
22
|
-
* </div>
|
|
23
|
-
* ```
|
|
24
|
-
*
|
|
25
|
-
* @example Nested zones
|
|
26
|
-
* ```tsx
|
|
27
|
-
* <LockedZone>
|
|
28
|
-
* <Sidebar>
|
|
29
|
-
* <Logo /> {/* Locked *\/}
|
|
30
|
-
* <EditableZone>
|
|
31
|
-
* <CustomWidgets /> {/* Editable "island" inside locked zone *\/}
|
|
32
|
-
* </EditableZone>
|
|
33
|
-
* </Sidebar>
|
|
34
|
-
* </LockedZone>
|
|
35
|
-
* ```
|
|
36
|
-
*/
|
|
37
|
-
export const LockedZone = forwardRef(function LockedZone({ children, as: Component = 'div', ...props }, ref) {
|
|
38
|
-
const zoneProps = {
|
|
39
|
-
...props,
|
|
40
|
-
[VISIBILITY_ATTR]: 'false',
|
|
41
|
-
ref,
|
|
42
|
-
};
|
|
43
|
-
// Use createElement to support dynamic tag
|
|
44
|
-
const Element = Component;
|
|
45
|
-
return _jsx(Element, { ...zoneProps, children: children });
|
|
46
|
-
});
|
|
47
|
-
/**
|
|
48
|
-
* EditableZone - Explicitly marks content as editable in the builder
|
|
49
|
-
*
|
|
50
|
-
* Use this to:
|
|
51
|
-
* - Create editable "islands" inside a LockedZone
|
|
52
|
-
* - Explicitly mark content as editable (though content is editable by default)
|
|
53
|
-
*
|
|
54
|
-
* @example Create editable area inside locked zone
|
|
55
|
-
* ```tsx
|
|
56
|
-
* <LockedZone>
|
|
57
|
-
* <Header>
|
|
58
|
-
* <Logo /> {/* Locked *\/}
|
|
59
|
-
* <EditableZone>
|
|
60
|
-
* <UserMenu /> {/* Editable despite being inside LockedZone *\/}
|
|
61
|
-
* </EditableZone>
|
|
62
|
-
* </Header>
|
|
63
|
-
* </LockedZone>
|
|
64
|
-
* ```
|
|
65
|
-
*/
|
|
66
|
-
export const EditableZone = forwardRef(function EditableZone({ children, as: Component = 'div', ...props }, ref) {
|
|
67
|
-
const zoneProps = {
|
|
68
|
-
...props,
|
|
69
|
-
[VISIBILITY_ATTR]: 'true',
|
|
70
|
-
ref,
|
|
71
|
-
};
|
|
72
|
-
// Use createElement to support dynamic tag
|
|
73
|
-
const Element = Component;
|
|
74
|
-
return _jsx(Element, { ...zoneProps, children: children });
|
|
75
|
-
});
|
|
76
|
-
/**
|
|
77
|
-
* Alias for LockedZone - more explicit naming
|
|
78
|
-
*/
|
|
79
|
-
export const NonCustomizable = LockedZone;
|
|
80
|
-
/**
|
|
81
|
-
* Alias for EditableZone - more explicit naming
|
|
82
|
-
*/
|
|
83
|
-
export const Customizable = EditableZone;
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import type { DynimProviderProps } from './types';
|
|
2
|
-
/**
|
|
3
|
-
* DynimProvider - A React component that dynamically loads tenant-specific bundles.
|
|
4
|
-
*
|
|
5
|
-
* This provider handles the lifecycle of loading, rendering, and cleaning up
|
|
6
|
-
* tenant customization bundles. It supports optional pre-checks to determine
|
|
7
|
-
* if a tenant has customizations before attempting to load them.
|
|
8
|
-
*
|
|
9
|
-
* @example
|
|
10
|
-
* ```tsx
|
|
11
|
-
* <DynimProvider
|
|
12
|
-
* tenantId={user?.tenantId}
|
|
13
|
-
* bundleUrl={(id) => `https://cdn.example.com/bundles/${id}.js`}
|
|
14
|
-
* loadingComponent={<Spinner />}
|
|
15
|
-
* errorBanner={true}
|
|
16
|
-
* >
|
|
17
|
-
* <YourBaseApp />
|
|
18
|
-
* </DynimProvider>
|
|
19
|
-
* ```
|
|
20
|
-
*/
|
|
21
|
-
export declare function DynimProvider({ tenantId, bundleUrl, checkCustomizations, loadingComponent, errorBanner, onError, onLoad, children, }: DynimProviderProps): JSX.Element;
|
|
22
|
-
export default DynimProvider;
|
|
23
|
-
//# sourceMappingURL=DynimProvider.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"DynimProvider.d.ts","sourceRoot":"","sources":["../../src/inference/DynimProvider.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAc,MAAM,SAAS,CAAC;AA8E9D;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,aAAa,CAAC,EAC5B,QAAQ,EACR,SAAS,EACT,mBAAmB,EACnB,gBAAgB,EAChB,WAAmB,EACnB,OAAO,EACP,MAAM,EACN,QAAQ,GACT,EAAE,kBAAkB,GAAG,GAAG,CAAC,OAAO,CAuLlC;AAED,eAAe,aAAa,CAAC"}
|
|
@@ -1,231 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { useState, useEffect, useCallback, useRef } from 'react';
|
|
3
|
-
/**
|
|
4
|
-
* Default loading component shown while bundle is loading
|
|
5
|
-
*/
|
|
6
|
-
function DefaultLoadingComponent() {
|
|
7
|
-
return (_jsx("div", { style: {
|
|
8
|
-
display: 'flex',
|
|
9
|
-
justifyContent: 'center',
|
|
10
|
-
alignItems: 'center',
|
|
11
|
-
padding: '20px',
|
|
12
|
-
}, children: _jsx("span", { children: "Loading customizations..." }) }));
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* Default error banner component
|
|
16
|
-
*/
|
|
17
|
-
function DefaultErrorBanner({ error }) {
|
|
18
|
-
return (_jsxs("div", { style: {
|
|
19
|
-
background: '#fee2e2',
|
|
20
|
-
border: '1px solid #ef4444',
|
|
21
|
-
borderRadius: '4px',
|
|
22
|
-
padding: '12px 16px',
|
|
23
|
-
marginBottom: '16px',
|
|
24
|
-
color: '#991b1b',
|
|
25
|
-
}, children: [_jsx("strong", { children: "Customization Error:" }), " ", error.message] }));
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Container for rendering tenant bundle content
|
|
29
|
-
*/
|
|
30
|
-
function BundleContainer() {
|
|
31
|
-
return _jsx("div", { id: "dynim-root" });
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Loads a script from a URL and returns a promise that resolves when loaded
|
|
35
|
-
*/
|
|
36
|
-
function loadScript(url) {
|
|
37
|
-
return new Promise((resolve, reject) => {
|
|
38
|
-
// Check if script already exists
|
|
39
|
-
const existingScript = document.querySelector(`script[src="${url}"]`);
|
|
40
|
-
if (existingScript) {
|
|
41
|
-
resolve();
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
44
|
-
const script = document.createElement('script');
|
|
45
|
-
script.src = url;
|
|
46
|
-
script.async = true;
|
|
47
|
-
script.onload = () => resolve();
|
|
48
|
-
script.onerror = () => reject(new Error(`Failed to load bundle from ${url}`));
|
|
49
|
-
document.head.appendChild(script);
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Removes a previously loaded script
|
|
54
|
-
*/
|
|
55
|
-
function removeScript(url) {
|
|
56
|
-
const script = document.querySelector(`script[src="${url}"]`);
|
|
57
|
-
if (script) {
|
|
58
|
-
script.remove();
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
|
-
* DynimProvider - A React component that dynamically loads tenant-specific bundles.
|
|
63
|
-
*
|
|
64
|
-
* This provider handles the lifecycle of loading, rendering, and cleaning up
|
|
65
|
-
* tenant customization bundles. It supports optional pre-checks to determine
|
|
66
|
-
* if a tenant has customizations before attempting to load them.
|
|
67
|
-
*
|
|
68
|
-
* @example
|
|
69
|
-
* ```tsx
|
|
70
|
-
* <DynimProvider
|
|
71
|
-
* tenantId={user?.tenantId}
|
|
72
|
-
* bundleUrl={(id) => `https://cdn.example.com/bundles/${id}.js`}
|
|
73
|
-
* loadingComponent={<Spinner />}
|
|
74
|
-
* errorBanner={true}
|
|
75
|
-
* >
|
|
76
|
-
* <YourBaseApp />
|
|
77
|
-
* </DynimProvider>
|
|
78
|
-
* ```
|
|
79
|
-
*/
|
|
80
|
-
export function DynimProvider({ tenantId, bundleUrl, checkCustomizations, loadingComponent, errorBanner = false, onError, onLoad, children, }) {
|
|
81
|
-
const [state, setState] = useState({
|
|
82
|
-
status: 'idle',
|
|
83
|
-
error: null,
|
|
84
|
-
currentTenantId: null,
|
|
85
|
-
});
|
|
86
|
-
const loadedUrlRef = useRef(null);
|
|
87
|
-
/**
|
|
88
|
-
* Resolves the bundle URL for a given tenant ID
|
|
89
|
-
*/
|
|
90
|
-
const resolveBundleUrl = useCallback((id) => {
|
|
91
|
-
if (typeof bundleUrl === 'function') {
|
|
92
|
-
return bundleUrl(id);
|
|
93
|
-
}
|
|
94
|
-
// If bundleUrl is a string template, replace {tenantId} placeholder
|
|
95
|
-
return bundleUrl.replace('{tenantId}', id);
|
|
96
|
-
}, [bundleUrl]);
|
|
97
|
-
/**
|
|
98
|
-
* Cleans up previously loaded bundle
|
|
99
|
-
*/
|
|
100
|
-
const cleanup = useCallback(() => {
|
|
101
|
-
if (loadedUrlRef.current) {
|
|
102
|
-
removeScript(loadedUrlRef.current);
|
|
103
|
-
loadedUrlRef.current = null;
|
|
104
|
-
}
|
|
105
|
-
// Clear the bundle render target
|
|
106
|
-
const root = document.getElementById('dynim-root');
|
|
107
|
-
if (root) {
|
|
108
|
-
root.innerHTML = '';
|
|
109
|
-
}
|
|
110
|
-
}, []);
|
|
111
|
-
/**
|
|
112
|
-
* Main effect to handle tenant bundle loading
|
|
113
|
-
*/
|
|
114
|
-
useEffect(() => {
|
|
115
|
-
// No tenant - reset to idle and show children
|
|
116
|
-
if (!tenantId) {
|
|
117
|
-
cleanup();
|
|
118
|
-
setState({
|
|
119
|
-
status: 'idle',
|
|
120
|
-
error: null,
|
|
121
|
-
currentTenantId: null,
|
|
122
|
-
});
|
|
123
|
-
return;
|
|
124
|
-
}
|
|
125
|
-
// Same tenant already loaded - do nothing
|
|
126
|
-
if (state.currentTenantId === tenantId && state.status === 'loaded') {
|
|
127
|
-
return;
|
|
128
|
-
}
|
|
129
|
-
let cancelled = false;
|
|
130
|
-
async function loadBundle() {
|
|
131
|
-
try {
|
|
132
|
-
// Step 1: Check if tenant has customizations (if check function provided)
|
|
133
|
-
if (checkCustomizations) {
|
|
134
|
-
setState((prev) => ({ ...prev, status: 'checking' }));
|
|
135
|
-
const hasCustomizations = await checkCustomizations(tenantId);
|
|
136
|
-
if (cancelled)
|
|
137
|
-
return;
|
|
138
|
-
if (!hasCustomizations) {
|
|
139
|
-
cleanup();
|
|
140
|
-
setState({
|
|
141
|
-
status: 'no-customization',
|
|
142
|
-
error: null,
|
|
143
|
-
currentTenantId: tenantId,
|
|
144
|
-
});
|
|
145
|
-
return;
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
// Step 2: Load the bundle
|
|
149
|
-
setState((prev) => ({ ...prev, status: 'loading' }));
|
|
150
|
-
// Clean up previous bundle
|
|
151
|
-
cleanup();
|
|
152
|
-
const url = resolveBundleUrl(tenantId);
|
|
153
|
-
await loadScript(url);
|
|
154
|
-
if (cancelled) {
|
|
155
|
-
removeScript(url);
|
|
156
|
-
return;
|
|
157
|
-
}
|
|
158
|
-
loadedUrlRef.current = url;
|
|
159
|
-
setState({
|
|
160
|
-
status: 'loaded',
|
|
161
|
-
error: null,
|
|
162
|
-
currentTenantId: tenantId,
|
|
163
|
-
});
|
|
164
|
-
onLoad?.(tenantId);
|
|
165
|
-
}
|
|
166
|
-
catch (err) {
|
|
167
|
-
if (cancelled)
|
|
168
|
-
return;
|
|
169
|
-
const error = err instanceof Error ? err : new Error(String(err));
|
|
170
|
-
setState({
|
|
171
|
-
status: 'error',
|
|
172
|
-
error,
|
|
173
|
-
currentTenantId: tenantId,
|
|
174
|
-
});
|
|
175
|
-
onError?.(error, tenantId);
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
loadBundle();
|
|
179
|
-
return () => {
|
|
180
|
-
cancelled = true;
|
|
181
|
-
};
|
|
182
|
-
}, [
|
|
183
|
-
tenantId,
|
|
184
|
-
checkCustomizations,
|
|
185
|
-
resolveBundleUrl,
|
|
186
|
-
cleanup,
|
|
187
|
-
onError,
|
|
188
|
-
onLoad,
|
|
189
|
-
state.currentTenantId,
|
|
190
|
-
state.status,
|
|
191
|
-
]);
|
|
192
|
-
/**
|
|
193
|
-
* Cleanup on unmount
|
|
194
|
-
*/
|
|
195
|
-
useEffect(() => {
|
|
196
|
-
return () => {
|
|
197
|
-
cleanup();
|
|
198
|
-
};
|
|
199
|
-
}, [cleanup]);
|
|
200
|
-
// Render error banner if enabled and there's an error
|
|
201
|
-
const renderErrorBanner = () => {
|
|
202
|
-
if (!errorBanner || state.status !== 'error' || !state.error) {
|
|
203
|
-
return null;
|
|
204
|
-
}
|
|
205
|
-
if (errorBanner === true) {
|
|
206
|
-
return _jsx(DefaultErrorBanner, { error: state.error });
|
|
207
|
-
}
|
|
208
|
-
return errorBanner;
|
|
209
|
-
};
|
|
210
|
-
// Determine what to render based on state
|
|
211
|
-
const renderContent = () => {
|
|
212
|
-
switch (state.status) {
|
|
213
|
-
case 'checking':
|
|
214
|
-
case 'loading':
|
|
215
|
-
return loadingComponent ?? _jsx(DefaultLoadingComponent, {});
|
|
216
|
-
case 'loaded':
|
|
217
|
-
// Bundle is loaded and will render itself into #dynim-root
|
|
218
|
-
return _jsx(BundleContainer, {});
|
|
219
|
-
case 'error':
|
|
220
|
-
// Show children as fallback with optional error banner
|
|
221
|
-
return (_jsxs(_Fragment, { children: [renderErrorBanner(), children] }));
|
|
222
|
-
case 'no-customization':
|
|
223
|
-
case 'idle':
|
|
224
|
-
default:
|
|
225
|
-
// No customizations or no tenant - render base app
|
|
226
|
-
return children;
|
|
227
|
-
}
|
|
228
|
-
};
|
|
229
|
-
return _jsx(_Fragment, { children: renderContent() });
|
|
230
|
-
}
|
|
231
|
-
export default DynimProvider;
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import type { DynimSDKConfig, DynimGlobal } from './types';
|
|
2
|
-
/**
|
|
3
|
-
* Creates and registers the Dynim SDK on the window object.
|
|
4
|
-
* This makes React, ReactDOM, hooks, and contexts available to tenant bundles.
|
|
5
|
-
*
|
|
6
|
-
* @param config - Configuration object containing React, ReactDOM, hooks, and contexts
|
|
7
|
-
* @returns The created SDK object
|
|
8
|
-
*
|
|
9
|
-
* @example
|
|
10
|
-
* ```tsx
|
|
11
|
-
* import { createDynimSDK } from 'dynim-react';
|
|
12
|
-
* import React from 'react';
|
|
13
|
-
* import ReactDOM from 'react-dom';
|
|
14
|
-
* import { useAuth, useNotifications } from './hooks';
|
|
15
|
-
* import { AuthContext, NotificationContext } from './contexts';
|
|
16
|
-
*
|
|
17
|
-
* createDynimSDK({
|
|
18
|
-
* React,
|
|
19
|
-
* ReactDOM,
|
|
20
|
-
* hooks: { useAuth, useNotifications },
|
|
21
|
-
* contexts: { AuthContext, NotificationContext }
|
|
22
|
-
* });
|
|
23
|
-
* ```
|
|
24
|
-
*/
|
|
25
|
-
export declare function createDynimSDK(config: DynimSDKConfig): DynimGlobal;
|
|
26
|
-
/**
|
|
27
|
-
* Gets the current Dynim SDK instance from the window object.
|
|
28
|
-
* Useful for tenant bundles to access the SDK.
|
|
29
|
-
*
|
|
30
|
-
* @returns The SDK instance or undefined if not initialized
|
|
31
|
-
*/
|
|
32
|
-
export declare function getDynimSDK(): DynimGlobal | undefined;
|
|
33
|
-
/**
|
|
34
|
-
* Checks if the Dynim SDK has been initialized.
|
|
35
|
-
*
|
|
36
|
-
* @returns true if the SDK is available
|
|
37
|
-
*/
|
|
38
|
-
export declare function isDynimSDKReady(): boolean;
|
|
39
|
-
//# sourceMappingURL=createDynimSDK.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"createDynimSDK.d.ts","sourceRoot":"","sources":["../../src/inference/createDynimSDK.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE3D;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,cAAc,GAAG,WAAW,CAqBlE;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,IAAI,WAAW,GAAG,SAAS,CAKrD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,IAAI,OAAO,CAEzC"}
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Creates and registers the Dynim SDK on the window object.
|
|
3
|
-
* This makes React, ReactDOM, hooks, and contexts available to tenant bundles.
|
|
4
|
-
*
|
|
5
|
-
* @param config - Configuration object containing React, ReactDOM, hooks, and contexts
|
|
6
|
-
* @returns The created SDK object
|
|
7
|
-
*
|
|
8
|
-
* @example
|
|
9
|
-
* ```tsx
|
|
10
|
-
* import { createDynimSDK } from 'dynim-react';
|
|
11
|
-
* import React from 'react';
|
|
12
|
-
* import ReactDOM from 'react-dom';
|
|
13
|
-
* import { useAuth, useNotifications } from './hooks';
|
|
14
|
-
* import { AuthContext, NotificationContext } from './contexts';
|
|
15
|
-
*
|
|
16
|
-
* createDynimSDK({
|
|
17
|
-
* React,
|
|
18
|
-
* ReactDOM,
|
|
19
|
-
* hooks: { useAuth, useNotifications },
|
|
20
|
-
* contexts: { AuthContext, NotificationContext }
|
|
21
|
-
* });
|
|
22
|
-
* ```
|
|
23
|
-
*/
|
|
24
|
-
export function createDynimSDK(config) {
|
|
25
|
-
const { React, ReactDOM, hooks = {}, contexts = {}, globals = {} } = config;
|
|
26
|
-
const sdk = {
|
|
27
|
-
React,
|
|
28
|
-
ReactDOM,
|
|
29
|
-
hooks,
|
|
30
|
-
contexts,
|
|
31
|
-
...globals,
|
|
32
|
-
};
|
|
33
|
-
// Register on window for tenant bundles to access
|
|
34
|
-
if (typeof window !== 'undefined') {
|
|
35
|
-
window.__DYNIM__ = sdk;
|
|
36
|
-
// Also expose React and ReactDOM directly on window for bundles using standard imports
|
|
37
|
-
window.React = React;
|
|
38
|
-
window.ReactDOM = ReactDOM;
|
|
39
|
-
}
|
|
40
|
-
return sdk;
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* Gets the current Dynim SDK instance from the window object.
|
|
44
|
-
* Useful for tenant bundles to access the SDK.
|
|
45
|
-
*
|
|
46
|
-
* @returns The SDK instance or undefined if not initialized
|
|
47
|
-
*/
|
|
48
|
-
export function getDynimSDK() {
|
|
49
|
-
if (typeof window !== 'undefined') {
|
|
50
|
-
return window.__DYNIM__;
|
|
51
|
-
}
|
|
52
|
-
return undefined;
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Checks if the Dynim SDK has been initialized.
|
|
56
|
-
*
|
|
57
|
-
* @returns true if the SDK is available
|
|
58
|
-
*/
|
|
59
|
-
export function isDynimSDKReady() {
|
|
60
|
-
return typeof window !== 'undefined' && window.__DYNIM__ !== undefined;
|
|
61
|
-
}
|