@demokit-ai/react 0.2.0 → 0.4.0

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/index.cjs CHANGED
@@ -1,96 +1,257 @@
1
- 'use strict';
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
2
19
 
3
- var react = require('react');
4
- var core = require('@demokit-ai/core');
5
- var jsxRuntime = require('react/jsx-runtime');
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ DemoKitProvider: () => DemoKitProvider,
24
+ DemoModeBanner: () => DemoModeBanner,
25
+ DemoModeContext: () => DemoModeContext,
26
+ DemoModeToggle: () => DemoModeToggle,
27
+ PoweredByBadge: () => PoweredByBadge,
28
+ createRemoteSource: () => createRemoteSource,
29
+ useDemoGuard: () => useDemoGuard,
30
+ useDemoMode: () => useDemoMode,
31
+ useDemoSession: () => useDemoSession,
32
+ useIsDemoMode: () => useIsDemoMode,
33
+ useIsHydrated: () => useIsHydrated
34
+ });
35
+ module.exports = __toCommonJS(index_exports);
6
36
 
7
37
  // src/provider.tsx
8
- var DemoModeContext = react.createContext(void 0);
38
+ var import_react2 = require("react");
39
+ var import_core = require("@demokit-ai/core");
40
+
41
+ // src/context.ts
42
+ var import_react = require("react");
43
+ var DemoModeContext = (0, import_react.createContext)(void 0);
9
44
  DemoModeContext.displayName = "DemoModeContext";
45
+
46
+ // src/provider.tsx
47
+ var import_jsx_runtime = require("react/jsx-runtime");
10
48
  function DemoKitProvider({
11
49
  children,
12
50
  fixtures,
51
+ // Remote config
52
+ source,
53
+ onRemoteLoad,
54
+ onRemoteError,
55
+ loadingFallback = null,
56
+ errorFallback,
57
+ // Standard props
13
58
  storageKey = "demokit-mode",
14
59
  initialEnabled = false,
15
60
  onDemoModeChange,
16
- baseUrl
61
+ baseUrl,
62
+ // Detection & guards
63
+ detection,
64
+ canDisable,
65
+ onMutationIntercepted
17
66
  }) {
18
- const [isDemoMode, setIsDemoMode] = react.useState(initialEnabled);
19
- const [isHydrated, setIsHydrated] = react.useState(false);
20
- const interceptorRef = react.useRef(null);
21
- const initializedRef = react.useRef(false);
22
- react.useEffect(() => {
67
+ const [isDemoMode, setIsDemoMode] = (0, import_react2.useState)(initialEnabled);
68
+ const [isHydrated, setIsHydrated] = (0, import_react2.useState)(false);
69
+ const [isPublicDemo, setIsPublicDemo] = (0, import_react2.useState)(false);
70
+ const [isLoading, setIsLoading] = (0, import_react2.useState)(!!source?.apiKey);
71
+ const [remoteError, setRemoteError] = (0, import_react2.useState)(null);
72
+ const [remoteVersion, setRemoteVersion] = (0, import_react2.useState)(null);
73
+ const interceptorRef = (0, import_react2.useRef)(null);
74
+ const initializedRef = (0, import_react2.useRef)(false);
75
+ const remoteFixturesRef = (0, import_react2.useRef)(null);
76
+ const refetchFnRef = (0, import_react2.useRef)(null);
77
+ const setupInterceptor = (0, import_react2.useCallback)(
78
+ (mergedFixtures) => {
79
+ interceptorRef.current?.destroy();
80
+ interceptorRef.current = (0, import_core.createDemoInterceptor)({
81
+ fixtures: mergedFixtures,
82
+ storageKey,
83
+ initialEnabled,
84
+ baseUrl,
85
+ detection,
86
+ canDisable,
87
+ onMutationIntercepted,
88
+ onEnable: () => {
89
+ setIsDemoMode(true);
90
+ onDemoModeChange?.(true);
91
+ },
92
+ onDisable: () => {
93
+ setIsDemoMode(false);
94
+ onDemoModeChange?.(false);
95
+ }
96
+ });
97
+ const storedState = interceptorRef.current.isEnabled();
98
+ setIsDemoMode(storedState);
99
+ setIsPublicDemo(interceptorRef.current.isPublicDemo());
100
+ setIsHydrated(true);
101
+ },
102
+ [storageKey, initialEnabled, baseUrl, onDemoModeChange, detection, canDisable, onMutationIntercepted]
103
+ );
104
+ const fetchAndSetup = (0, import_react2.useCallback)(async () => {
105
+ if (!source?.apiKey) return;
106
+ setIsLoading(true);
107
+ setRemoteError(null);
108
+ try {
109
+ const response = await (0, import_core.fetchCloudFixtures)({
110
+ apiKey: source.apiKey,
111
+ apiUrl: source.apiUrl,
112
+ timeout: source.timeout,
113
+ retry: source.retry,
114
+ maxRetries: source.maxRetries,
115
+ onLoad: onRemoteLoad,
116
+ onError: onRemoteError
117
+ });
118
+ const remoteFixtures = (0, import_core.createRemoteFixtures)(response, fixtures);
119
+ remoteFixturesRef.current = remoteFixtures;
120
+ setRemoteVersion(response.version);
121
+ setupInterceptor(remoteFixtures);
122
+ } catch (error) {
123
+ const err = error instanceof Error ? error : new Error(String(error));
124
+ setRemoteError(err);
125
+ onRemoteError?.(err);
126
+ if (fixtures && Object.keys(fixtures).length > 0) {
127
+ setupInterceptor(fixtures);
128
+ } else {
129
+ setIsHydrated(true);
130
+ }
131
+ } finally {
132
+ setIsLoading(false);
133
+ }
134
+ }, [
135
+ source,
136
+ fixtures,
137
+ onRemoteLoad,
138
+ onRemoteError,
139
+ setupInterceptor
140
+ ]);
141
+ refetchFnRef.current = fetchAndSetup;
142
+ (0, import_react2.useEffect)(() => {
23
143
  if (initializedRef.current) {
24
144
  return;
25
145
  }
26
146
  initializedRef.current = true;
27
- interceptorRef.current = core.createDemoInterceptor({
28
- fixtures,
29
- storageKey,
30
- initialEnabled,
31
- baseUrl,
32
- onEnable: () => {
33
- setIsDemoMode(true);
34
- onDemoModeChange?.(true);
35
- },
36
- onDisable: () => {
37
- setIsDemoMode(false);
38
- onDemoModeChange?.(false);
39
- }
40
- });
41
- const storedState = interceptorRef.current.isEnabled();
42
- setIsDemoMode(storedState);
43
- setIsHydrated(true);
147
+ if (source?.apiKey) {
148
+ fetchAndSetup();
149
+ } else if (fixtures) {
150
+ setupInterceptor(fixtures);
151
+ } else {
152
+ setIsHydrated(true);
153
+ setIsLoading(false);
154
+ }
44
155
  return () => {
45
156
  interceptorRef.current?.destroy();
46
157
  interceptorRef.current = null;
47
158
  initializedRef.current = false;
48
159
  };
49
160
  }, []);
50
- react.useEffect(() => {
51
- if (interceptorRef.current && isHydrated) {
52
- interceptorRef.current.setFixtures(fixtures);
161
+ (0, import_react2.useEffect)(() => {
162
+ if (!isHydrated || isLoading) return;
163
+ if (source?.apiKey && remoteFixturesRef.current) {
164
+ const merged = { ...remoteFixturesRef.current, ...fixtures };
165
+ interceptorRef.current?.setFixtures(merged);
166
+ } else if (fixtures) {
167
+ interceptorRef.current?.setFixtures(fixtures);
53
168
  }
54
- }, [fixtures, isHydrated]);
55
- const enable = react.useCallback(() => {
169
+ }, [fixtures, isHydrated, isLoading, source]);
170
+ const enable = (0, import_react2.useCallback)(() => {
56
171
  interceptorRef.current?.enable();
57
172
  }, []);
58
- const disable = react.useCallback(() => {
59
- interceptorRef.current?.disable();
173
+ const disable = (0, import_react2.useCallback)(() => {
174
+ return interceptorRef.current?.disable() ?? true;
60
175
  }, []);
61
- const toggle = react.useCallback(() => {
176
+ const toggle = (0, import_react2.useCallback)(() => {
62
177
  interceptorRef.current?.toggle();
63
178
  }, []);
64
- const setDemoMode = react.useCallback((enabled) => {
179
+ const setDemoMode = (0, import_react2.useCallback)((enabled) => {
65
180
  if (enabled) {
66
181
  interceptorRef.current?.enable();
67
182
  } else {
68
183
  interceptorRef.current?.disable();
69
184
  }
70
185
  }, []);
71
- const resetSession = react.useCallback(() => {
186
+ const resetSession = (0, import_react2.useCallback)(() => {
72
187
  interceptorRef.current?.resetSession();
73
188
  }, []);
74
- const getSession = react.useCallback(() => {
189
+ const getSession = (0, import_react2.useCallback)(() => {
75
190
  return interceptorRef.current?.getSession() ?? null;
76
191
  }, []);
77
- const value = react.useMemo(
192
+ const refetch = (0, import_react2.useCallback)(async () => {
193
+ if (!source?.apiKey) {
194
+ console.warn("[DemoKit] refetch() called but no source provided");
195
+ return;
196
+ }
197
+ await refetchFnRef.current?.();
198
+ }, [source]);
199
+ const value = (0, import_react2.useMemo)(
78
200
  () => ({
79
201
  isDemoMode,
80
202
  isHydrated,
203
+ isPublicDemo,
204
+ isLoading,
205
+ remoteError,
206
+ remoteVersion,
81
207
  enable,
82
208
  disable,
83
209
  toggle,
84
210
  setDemoMode,
85
211
  resetSession,
86
- getSession
212
+ getSession,
213
+ refetch
87
214
  }),
88
- [isDemoMode, isHydrated, enable, disable, toggle, setDemoMode, resetSession, getSession]
215
+ [
216
+ isDemoMode,
217
+ isHydrated,
218
+ isPublicDemo,
219
+ isLoading,
220
+ remoteError,
221
+ remoteVersion,
222
+ enable,
223
+ disable,
224
+ toggle,
225
+ setDemoMode,
226
+ resetSession,
227
+ getSession,
228
+ refetch
229
+ ]
89
230
  );
90
- return /* @__PURE__ */ jsxRuntime.jsx(DemoModeContext.Provider, { value, children });
231
+ if (isLoading && source?.apiKey) {
232
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DemoModeContext.Provider, { value, children: loadingFallback });
233
+ }
234
+ if (remoteError && errorFallback) {
235
+ const errorContent = typeof errorFallback === "function" ? errorFallback(remoteError) : errorFallback;
236
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DemoModeContext.Provider, { value, children: errorContent });
237
+ }
238
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DemoModeContext.Provider, { value, children });
91
239
  }
240
+
241
+ // src/config.ts
242
+ function createRemoteSource(config) {
243
+ return {
244
+ timeout: 1e4,
245
+ retry: true,
246
+ maxRetries: 3,
247
+ ...config
248
+ };
249
+ }
250
+
251
+ // src/hooks.ts
252
+ var import_react3 = require("react");
92
253
  function useDemoMode() {
93
- const context = react.useContext(DemoModeContext);
254
+ const context = (0, import_react3.useContext)(DemoModeContext);
94
255
  if (context === void 0) {
95
256
  throw new Error(
96
257
  "useDemoMode must be used within a DemoKitProvider. Make sure to wrap your app with <DemoKitProvider>."
@@ -107,8 +268,139 @@ function useIsHydrated() {
107
268
  function useDemoSession() {
108
269
  return useDemoMode().getSession();
109
270
  }
271
+
272
+ // src/guard.ts
273
+ var import_react4 = require("react");
274
+ function useDemoGuard(options = {}) {
275
+ const { isDemoMode } = useDemoMode();
276
+ const { onBlocked } = options;
277
+ const guardMutation = (0, import_react4.useCallback)(
278
+ (action, actionName) => {
279
+ if (isDemoMode) {
280
+ const message = actionName ? `${actionName} (simulated in demo mode)` : "Action simulated in demo mode";
281
+ onBlocked?.(message);
282
+ return false;
283
+ }
284
+ action();
285
+ return true;
286
+ },
287
+ [isDemoMode, onBlocked]
288
+ );
289
+ return {
290
+ guardMutation,
291
+ isDemoMode
292
+ };
293
+ }
294
+
295
+ // src/powered-by.tsx
296
+ var import_jsx_runtime2 = require("react/jsx-runtime");
297
+ function ExternalLinkIcon({ size }) {
298
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
299
+ "svg",
300
+ {
301
+ width: size,
302
+ height: size,
303
+ viewBox: "0 0 24 24",
304
+ fill: "none",
305
+ stroke: "currentColor",
306
+ strokeWidth: "2",
307
+ strokeLinecap: "round",
308
+ strokeLinejoin: "round",
309
+ "aria-hidden": "true",
310
+ children: [
311
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" }),
312
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("polyline", { points: "15 3 21 3 21 9" }),
313
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: "10", y1: "14", x2: "21", y2: "3" })
314
+ ]
315
+ }
316
+ );
317
+ }
318
+ var sizeConfig = {
319
+ xs: {
320
+ fontSize: "10px",
321
+ padding: "2px 6px",
322
+ gap: "3px",
323
+ iconSize: 8
324
+ },
325
+ sm: {
326
+ fontSize: "11px",
327
+ padding: "3px 8px",
328
+ gap: "4px",
329
+ iconSize: 10
330
+ },
331
+ md: {
332
+ fontSize: "12px",
333
+ padding: "4px 10px",
334
+ gap: "5px",
335
+ iconSize: 12
336
+ }
337
+ };
338
+ var variantStyles = {
339
+ light: {
340
+ color: "rgba(120, 53, 15, 0.7)",
341
+ hoverColor: "rgba(120, 53, 15, 0.9)",
342
+ backgroundColor: "transparent",
343
+ hoverBackgroundColor: "rgba(217, 119, 6, 0.08)"
344
+ },
345
+ dark: {
346
+ color: "rgba(255, 255, 255, 0.6)",
347
+ hoverColor: "rgba(255, 255, 255, 0.9)",
348
+ backgroundColor: "transparent",
349
+ hoverBackgroundColor: "rgba(255, 255, 255, 0.1)"
350
+ }
351
+ };
352
+ function PoweredByBadge({
353
+ url = "https://demokit.ai",
354
+ variant = "light",
355
+ size = "sm",
356
+ className = "",
357
+ style
358
+ }) {
359
+ const config = sizeConfig[size];
360
+ const colors = variantStyles[variant === "auto" ? "light" : variant];
361
+ const baseStyles = {
362
+ display: "inline-flex",
363
+ alignItems: "center",
364
+ gap: config.gap,
365
+ fontSize: config.fontSize,
366
+ padding: config.padding,
367
+ color: colors.color,
368
+ textDecoration: "none",
369
+ borderRadius: "4px",
370
+ fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',
371
+ fontWeight: 500,
372
+ transition: "color 0.15s ease, background-color 0.15s ease",
373
+ whiteSpace: "nowrap",
374
+ ...style
375
+ };
376
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
377
+ "a",
378
+ {
379
+ href: url,
380
+ target: "_blank",
381
+ rel: "noopener noreferrer",
382
+ className: `demokit-powered-by ${className}`.trim(),
383
+ style: baseStyles,
384
+ onMouseOver: (e) => {
385
+ e.currentTarget.style.color = colors.hoverColor;
386
+ e.currentTarget.style.backgroundColor = colors.hoverBackgroundColor;
387
+ },
388
+ onMouseOut: (e) => {
389
+ e.currentTarget.style.color = colors.color;
390
+ e.currentTarget.style.backgroundColor = "transparent";
391
+ },
392
+ children: [
393
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: "Powered by DemoKit" }),
394
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ExternalLinkIcon, { size: config.iconSize })
395
+ ]
396
+ }
397
+ );
398
+ }
399
+
400
+ // src/banner.tsx
401
+ var import_jsx_runtime3 = require("react/jsx-runtime");
110
402
  function EyeIcon() {
111
- return /* @__PURE__ */ jsxRuntime.jsxs(
403
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
112
404
  "svg",
113
405
  {
114
406
  width: "20",
@@ -121,8 +413,8 @@ function EyeIcon() {
121
413
  strokeLinejoin: "round",
122
414
  "aria-hidden": "true",
123
415
  children: [
124
- /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z" }),
125
- /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "3" })
416
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z" }),
417
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("circle", { cx: "12", cy: "12", r: "3" })
126
418
  ]
127
419
  }
128
420
  );
@@ -173,6 +465,8 @@ function DemoModeBanner({
173
465
  demoLabel = "Demo Mode Active",
174
466
  description = "Changes are simulated and not saved",
175
467
  showIcon = true,
468
+ showPoweredBy = true,
469
+ poweredByUrl = "https://demokit.ai",
176
470
  style,
177
471
  onExit
178
472
  }) {
@@ -187,45 +481,224 @@ function DemoModeBanner({
187
481
  disable();
188
482
  }
189
483
  };
190
- return /* @__PURE__ */ jsxRuntime.jsxs(
484
+ const effectiveShowPoweredBy = showPoweredBy;
485
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
191
486
  "div",
192
487
  {
193
488
  className: `demokit-banner ${className}`.trim(),
194
- style: { ...defaultStyles.container, ...style },
489
+ style: { ...defaultStyles.container, flexDirection: "column", gap: "4px", ...style },
195
490
  role: "status",
196
491
  "aria-live": "polite",
197
492
  children: [
198
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: defaultStyles.content, children: [
199
- showIcon && /* @__PURE__ */ jsxRuntime.jsx("span", { style: defaultStyles.icon, children: /* @__PURE__ */ jsxRuntime.jsx(EyeIcon, {}) }),
200
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: defaultStyles.label, children: demoLabel }),
201
- description && /* @__PURE__ */ jsxRuntime.jsx("span", { style: defaultStyles.description, children: description })
493
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", width: "100%" }, children: [
494
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: defaultStyles.content, children: [
495
+ showIcon && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: defaultStyles.icon, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(EyeIcon, {}) }),
496
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: defaultStyles.label, children: demoLabel }),
497
+ description && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: defaultStyles.description, children: description })
498
+ ] }),
499
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
500
+ "button",
501
+ {
502
+ onClick: handleExit,
503
+ style: defaultStyles.button,
504
+ onMouseOver: (e) => {
505
+ e.currentTarget.style.backgroundColor = "rgba(217, 119, 6, 0.1)";
506
+ },
507
+ onMouseOut: (e) => {
508
+ e.currentTarget.style.backgroundColor = "transparent";
509
+ },
510
+ type: "button",
511
+ children: exitLabel
512
+ }
513
+ )
202
514
  ] }),
203
- /* @__PURE__ */ jsxRuntime.jsx(
204
- "button",
205
- {
206
- onClick: handleExit,
207
- style: defaultStyles.button,
208
- onMouseOver: (e) => {
209
- e.currentTarget.style.backgroundColor = "rgba(217, 119, 6, 0.1)";
210
- },
211
- onMouseOut: (e) => {
212
- e.currentTarget.style.backgroundColor = "transparent";
213
- },
214
- type: "button",
215
- children: exitLabel
216
- }
217
- )
515
+ effectiveShowPoweredBy && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { display: "flex", justifyContent: "flex-end", width: "100%" }, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(PoweredByBadge, { url: poweredByUrl, size: "xs" }) })
218
516
  ]
219
517
  }
220
518
  );
221
519
  }
222
520
 
223
- exports.DemoKitProvider = DemoKitProvider;
224
- exports.DemoModeBanner = DemoModeBanner;
225
- exports.DemoModeContext = DemoModeContext;
226
- exports.useDemoMode = useDemoMode;
227
- exports.useDemoSession = useDemoSession;
228
- exports.useIsDemoMode = useIsDemoMode;
229
- exports.useIsHydrated = useIsHydrated;
230
- //# sourceMappingURL=index.cjs.map
521
+ // src/toggle.tsx
522
+ var import_jsx_runtime4 = require("react/jsx-runtime");
523
+ var sizeConfig2 = {
524
+ sm: {
525
+ trackWidth: 36,
526
+ trackHeight: 20,
527
+ thumbSize: 16,
528
+ thumbOffset: 2,
529
+ fontSize: "12px",
530
+ padding: "8px 12px",
531
+ gap: "8px"
532
+ },
533
+ md: {
534
+ trackWidth: 44,
535
+ trackHeight: 24,
536
+ thumbSize: 20,
537
+ thumbOffset: 2,
538
+ fontSize: "14px",
539
+ padding: "12px 16px",
540
+ gap: "10px"
541
+ },
542
+ lg: {
543
+ trackWidth: 52,
544
+ trackHeight: 28,
545
+ thumbSize: 24,
546
+ thumbOffset: 2,
547
+ fontSize: "16px",
548
+ padding: "16px 20px",
549
+ gap: "12px"
550
+ }
551
+ };
552
+ var positionStyles = {
553
+ inline: {},
554
+ floating: {
555
+ position: "fixed",
556
+ zIndex: 9999,
557
+ boxShadow: "0 4px 12px rgba(0, 0, 0, 0.15)",
558
+ borderRadius: "8px"
559
+ },
560
+ corner: {
561
+ position: "fixed",
562
+ bottom: "20px",
563
+ right: "20px",
564
+ zIndex: 9999,
565
+ boxShadow: "0 4px 12px rgba(0, 0, 0, 0.15)",
566
+ borderRadius: "8px"
567
+ }
568
+ };
569
+ var defaultStyles2 = {
570
+ container: {
571
+ display: "inline-flex",
572
+ flexDirection: "column",
573
+ alignItems: "flex-start",
574
+ gap: "4px",
575
+ backgroundColor: "#ffffff",
576
+ border: "1px solid rgba(0, 0, 0, 0.1)",
577
+ fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif'
578
+ },
579
+ row: {
580
+ display: "flex",
581
+ alignItems: "center",
582
+ width: "100%"
583
+ },
584
+ label: {
585
+ fontWeight: 500,
586
+ color: "#1f2937",
587
+ userSelect: "none"
588
+ },
589
+ track: {
590
+ position: "relative",
591
+ borderRadius: "9999px",
592
+ cursor: "pointer",
593
+ transition: "background-color 0.2s ease",
594
+ flexShrink: 0
595
+ },
596
+ trackOff: {
597
+ backgroundColor: "#d1d5db"
598
+ },
599
+ trackOn: {
600
+ backgroundColor: "#d97706"
601
+ },
602
+ thumb: {
603
+ position: "absolute",
604
+ top: "50%",
605
+ transform: "translateY(-50%)",
606
+ backgroundColor: "#ffffff",
607
+ borderRadius: "50%",
608
+ boxShadow: "0 1px 3px rgba(0, 0, 0, 0.2)",
609
+ transition: "left 0.2s ease"
610
+ },
611
+ poweredByContainer: {
612
+ display: "flex",
613
+ justifyContent: "flex-end",
614
+ width: "100%"
615
+ }
616
+ };
617
+ function DemoModeToggle({
618
+ showLabel = true,
619
+ label = "Demo Mode",
620
+ showPoweredBy = true,
621
+ poweredByUrl = "https://demokit.ai",
622
+ position = "inline",
623
+ size = "md",
624
+ className = "",
625
+ style,
626
+ onChange
627
+ }) {
628
+ const { isDemoMode, isHydrated, toggle } = useDemoMode();
629
+ if (!isHydrated) {
630
+ return null;
631
+ }
632
+ const config = sizeConfig2[size];
633
+ const posStyle = positionStyles[position];
634
+ const handleToggle = () => {
635
+ toggle();
636
+ onChange?.(!isDemoMode);
637
+ };
638
+ const thumbLeft = isDemoMode ? config.trackWidth - config.thumbSize - config.thumbOffset : config.thumbOffset;
639
+ const effectiveShowPoweredBy = showPoweredBy;
640
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
641
+ "div",
642
+ {
643
+ className: `demokit-toggle ${className}`.trim(),
644
+ style: {
645
+ ...defaultStyles2.container,
646
+ padding: config.padding,
647
+ ...posStyle,
648
+ ...style
649
+ },
650
+ role: "group",
651
+ "aria-label": "Demo mode toggle",
652
+ children: [
653
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { ...defaultStyles2.row, gap: config.gap }, children: [
654
+ showLabel && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { ...defaultStyles2.label, fontSize: config.fontSize }, children: label }),
655
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
656
+ "button",
657
+ {
658
+ type: "button",
659
+ role: "switch",
660
+ "aria-checked": isDemoMode,
661
+ "aria-label": `${label}: ${isDemoMode ? "On" : "Off"}`,
662
+ onClick: handleToggle,
663
+ style: {
664
+ ...defaultStyles2.track,
665
+ ...isDemoMode ? defaultStyles2.trackOn : defaultStyles2.trackOff,
666
+ width: config.trackWidth,
667
+ height: config.trackHeight,
668
+ border: "none",
669
+ padding: 0
670
+ },
671
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
672
+ "span",
673
+ {
674
+ style: {
675
+ ...defaultStyles2.thumb,
676
+ width: config.thumbSize,
677
+ height: config.thumbSize,
678
+ left: thumbLeft
679
+ }
680
+ }
681
+ )
682
+ }
683
+ )
684
+ ] }),
685
+ effectiveShowPoweredBy && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: defaultStyles2.poweredByContainer, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(PoweredByBadge, { url: poweredByUrl, size: "xs" }) })
686
+ ]
687
+ }
688
+ );
689
+ }
690
+ // Annotate the CommonJS export names for ESM import in node:
691
+ 0 && (module.exports = {
692
+ DemoKitProvider,
693
+ DemoModeBanner,
694
+ DemoModeContext,
695
+ DemoModeToggle,
696
+ PoweredByBadge,
697
+ createRemoteSource,
698
+ useDemoGuard,
699
+ useDemoMode,
700
+ useDemoSession,
701
+ useIsDemoMode,
702
+ useIsHydrated
703
+ });
231
704
  //# sourceMappingURL=index.cjs.map