dynim-react 1.0.7 → 1.0.9

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.
@@ -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
- }