@demokit-ai/next 0.0.1

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.
@@ -0,0 +1,152 @@
1
+ 'use strict';
2
+
3
+ var react$1 = require('react');
4
+ var react = require('@demokit-ai/react');
5
+ var jsxRuntime = require('react/jsx-runtime');
6
+ var navigation = require('next/navigation');
7
+
8
+ // src/client/provider.tsx
9
+ function getDemoModeFromCookie(cookieName) {
10
+ if (typeof document === "undefined") return false;
11
+ const cookies = document.cookie.split(";");
12
+ const demoCookie = cookies.find((c) => c.trim().startsWith(`${cookieName}=`));
13
+ return demoCookie !== void 0;
14
+ }
15
+ function getScenarioFromCookie(cookieName) {
16
+ if (typeof document === "undefined") return null;
17
+ const cookies = document.cookie.split(";");
18
+ const demoCookie = cookies.find((c) => c.trim().startsWith(`${cookieName}=`));
19
+ if (!demoCookie) return null;
20
+ const value = demoCookie.split("=")[1]?.trim();
21
+ if (!value || value === "true") return null;
22
+ return value;
23
+ }
24
+ function DemoKitNextProvider({
25
+ children,
26
+ fixtures,
27
+ scenarios = {},
28
+ storageKey = "demokit-mode",
29
+ cookieName = "demokit-mode",
30
+ initialEnabled,
31
+ baseUrl
32
+ }) {
33
+ const [isHydrated, setIsHydrated] = react$1.useState(false);
34
+ const [scenario, setScenario] = react$1.useState(null);
35
+ react$1.useEffect(() => {
36
+ getDemoModeFromCookie(cookieName);
37
+ const cookieScenario = getScenarioFromCookie(cookieName);
38
+ setScenario(cookieScenario);
39
+ setIsHydrated(true);
40
+ }, [cookieName]);
41
+ const activeFixtures = react$1.useMemo(() => {
42
+ if (scenario && scenarios[scenario]) {
43
+ return { ...fixtures, ...scenarios[scenario] };
44
+ }
45
+ return fixtures;
46
+ }, [fixtures, scenarios, scenario]);
47
+ const enabled = react$1.useMemo(() => {
48
+ if (initialEnabled !== void 0) {
49
+ return initialEnabled;
50
+ }
51
+ if (!isHydrated) {
52
+ return false;
53
+ }
54
+ return getDemoModeFromCookie(cookieName);
55
+ }, [initialEnabled, isHydrated, cookieName]);
56
+ return /* @__PURE__ */ jsxRuntime.jsx(
57
+ react.DemoKitProvider,
58
+ {
59
+ fixtures: activeFixtures,
60
+ storageKey,
61
+ initialEnabled: enabled,
62
+ baseUrl,
63
+ children
64
+ }
65
+ );
66
+ }
67
+ function useNextDemoMode(options = {}) {
68
+ const { urlParam = "demo" } = options;
69
+ const demoMode = react.useDemoMode();
70
+ const router = navigation.useRouter();
71
+ const searchParams = navigation.useSearchParams();
72
+ const enableWithScenario = react$1.useCallback(
73
+ (scenario) => {
74
+ const params = new URLSearchParams(searchParams.toString());
75
+ params.set(urlParam, scenario);
76
+ router.push(`?${params.toString()}`);
77
+ },
78
+ [router, searchParams, urlParam]
79
+ );
80
+ const enableDemo = react$1.useCallback(() => {
81
+ const params = new URLSearchParams(searchParams.toString());
82
+ params.set(urlParam, "true");
83
+ router.push(`?${params.toString()}`);
84
+ }, [router, searchParams, urlParam]);
85
+ const disableDemo = react$1.useCallback(() => {
86
+ const params = new URLSearchParams(searchParams.toString());
87
+ params.set(urlParam, "false");
88
+ router.push(`?${params.toString()}`);
89
+ }, [router, searchParams, urlParam]);
90
+ const currentScenario = searchParams.get(urlParam);
91
+ const isScenario = currentScenario !== null && currentScenario !== "true" && currentScenario !== "false" && currentScenario !== "1" && currentScenario !== "0";
92
+ return {
93
+ ...demoMode,
94
+ enableWithScenario,
95
+ enableDemo,
96
+ disableDemo,
97
+ currentScenario: isScenario ? currentScenario : null
98
+ };
99
+ }
100
+ function useIsNextDemoMode() {
101
+ return useNextDemoMode().isDemoMode;
102
+ }
103
+ function NextDemoModeBanner({
104
+ showScenario = true,
105
+ onExit,
106
+ description,
107
+ ...props
108
+ }) {
109
+ const { currentScenario, disableDemo, isDemoMode, isHydrated } = useNextDemoMode();
110
+ if (!isHydrated || !isDemoMode) {
111
+ return null;
112
+ }
113
+ let bannerDescription = description ?? "Changes are simulated and not saved";
114
+ if (showScenario && currentScenario) {
115
+ bannerDescription = `Scenario: ${currentScenario} \u2022 ${bannerDescription}`;
116
+ }
117
+ return /* @__PURE__ */ jsxRuntime.jsx(
118
+ react.DemoModeBanner,
119
+ {
120
+ ...props,
121
+ description: bannerDescription,
122
+ onExit: onExit ?? disableDemo
123
+ }
124
+ );
125
+ }
126
+
127
+ Object.defineProperty(exports, "DemoModeBanner", {
128
+ enumerable: true,
129
+ get: function () { return react.DemoModeBanner; }
130
+ });
131
+ Object.defineProperty(exports, "useDemoMode", {
132
+ enumerable: true,
133
+ get: function () { return react.useDemoMode; }
134
+ });
135
+ Object.defineProperty(exports, "useDemoSession", {
136
+ enumerable: true,
137
+ get: function () { return react.useDemoSession; }
138
+ });
139
+ Object.defineProperty(exports, "useIsDemoMode", {
140
+ enumerable: true,
141
+ get: function () { return react.useIsDemoMode; }
142
+ });
143
+ Object.defineProperty(exports, "useIsHydrated", {
144
+ enumerable: true,
145
+ get: function () { return react.useIsHydrated; }
146
+ });
147
+ exports.DemoKitNextProvider = DemoKitNextProvider;
148
+ exports.NextDemoModeBanner = NextDemoModeBanner;
149
+ exports.useIsNextDemoMode = useIsNextDemoMode;
150
+ exports.useNextDemoMode = useNextDemoMode;
151
+ //# sourceMappingURL=client.cjs.map
152
+ //# sourceMappingURL=client.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/client/provider.tsx","../src/client/hooks.ts","../src/client/banner.tsx"],"names":["useState","useEffect","useMemo","jsx","DemoKitProvider","useDemoMode","useRouter","useSearchParams","useCallback","DemoModeBanner"],"mappings":"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","file":"client.cjs","sourcesContent":["'use client'\n\nimport { useEffect, useState, useMemo } from 'react'\nimport { DemoKitProvider, type DemoKitProviderProps } from '@demokit-ai/react'\nimport type { DemoKitNextProviderProps } from '../types'\n\n/**\n * Get initial demo mode state from cookie\n */\nfunction getDemoModeFromCookie(cookieName: string): boolean {\n if (typeof document === 'undefined') return false\n\n const cookies = document.cookie.split(';')\n const demoCookie = cookies.find((c) => c.trim().startsWith(`${cookieName}=`))\n\n return demoCookie !== undefined\n}\n\n/**\n * Get scenario from cookie\n */\nfunction getScenarioFromCookie(cookieName: string): string | null {\n if (typeof document === 'undefined') return null\n\n const cookies = document.cookie.split(';')\n const demoCookie = cookies.find((c) => c.trim().startsWith(`${cookieName}=`))\n\n if (!demoCookie) return null\n\n const value = demoCookie.split('=')[1]?.trim()\n if (!value || value === 'true') return null\n\n return value\n}\n\n/**\n * Next.js-aware DemoKit provider\n *\n * This provider:\n * - Reads initial state from cookies (set by middleware)\n * - Supports scenario switching\n * - Works with both App Router and Pages Router\n *\n * @example\n * // app/providers.tsx\n * 'use client'\n *\n * import { DemoKitNextProvider } from '@demokit-ai/next/client'\n * import { fixtures, scenarios } from '@/lib/demo-fixtures'\n *\n * export function Providers({ children }: { children: React.ReactNode }) {\n * return (\n * <DemoKitNextProvider\n * fixtures={fixtures}\n * scenarios={scenarios}\n * >\n * {children}\n * </DemoKitNextProvider>\n * )\n * }\n */\nexport function DemoKitNextProvider({\n children,\n fixtures,\n scenarios = {},\n storageKey = 'demokit-mode',\n cookieName = 'demokit-mode',\n initialEnabled,\n baseUrl,\n}: DemoKitNextProviderProps) {\n const [isHydrated, setIsHydrated] = useState(false)\n const [scenario, setScenario] = useState<string | null>(null)\n\n // Read initial state from cookie on mount\n useEffect(() => {\n const cookieEnabled = getDemoModeFromCookie(cookieName)\n const cookieScenario = getScenarioFromCookie(cookieName)\n setScenario(cookieScenario)\n setIsHydrated(true)\n }, [cookieName])\n\n // Merge fixtures with scenario fixtures\n const activeFixtures = useMemo(() => {\n if (scenario && scenarios[scenario]) {\n return { ...fixtures, ...scenarios[scenario] }\n }\n return fixtures\n }, [fixtures, scenarios, scenario])\n\n // Determine initial enabled state\n const enabled = useMemo(() => {\n if (initialEnabled !== undefined) {\n return initialEnabled\n }\n if (!isHydrated) {\n return false\n }\n return getDemoModeFromCookie(cookieName)\n }, [initialEnabled, isHydrated, cookieName])\n\n return (\n <DemoKitProvider\n fixtures={activeFixtures}\n storageKey={storageKey}\n initialEnabled={enabled}\n baseUrl={baseUrl}\n >\n {children}\n </DemoKitProvider>\n )\n}\n","'use client'\n\nimport { useCallback } from 'react'\nimport { useDemoMode } from '@demokit-ai/react'\nimport { useRouter, useSearchParams } from 'next/navigation'\n\n/**\n * Hook for Next.js-specific demo mode controls\n *\n * Extends useDemoMode with URL-based scenario switching\n *\n * @example\n * function DemoControls() {\n * const { isDemoMode, enableWithScenario, disableDemo, currentScenario } = useNextDemoMode()\n *\n * return (\n * <div>\n * <button onClick={() => enableWithScenario('empty-state')}>\n * Empty State Demo\n * </button>\n * <button onClick={() => enableWithScenario('error-state')}>\n * Error State Demo\n * </button>\n * <button onClick={disableDemo}>\n * Exit Demo\n * </button>\n * {currentScenario && <span>Scenario: {currentScenario}</span>}\n * </div>\n * )\n * }\n */\nexport function useNextDemoMode(options: { urlParam?: string } = {}) {\n const { urlParam = 'demo' } = options\n const demoMode = useDemoMode()\n const router = useRouter()\n const searchParams = useSearchParams()\n\n /**\n * Enable demo mode with a specific scenario via URL\n */\n const enableWithScenario = useCallback(\n (scenario: string) => {\n const params = new URLSearchParams(searchParams.toString())\n params.set(urlParam, scenario)\n router.push(`?${params.toString()}`)\n },\n [router, searchParams, urlParam]\n )\n\n /**\n * Enable demo mode without a scenario\n */\n const enableDemo = useCallback(() => {\n const params = new URLSearchParams(searchParams.toString())\n params.set(urlParam, 'true')\n router.push(`?${params.toString()}`)\n }, [router, searchParams, urlParam])\n\n /**\n * Disable demo mode via URL\n */\n const disableDemo = useCallback(() => {\n const params = new URLSearchParams(searchParams.toString())\n params.set(urlParam, 'false')\n router.push(`?${params.toString()}`)\n }, [router, searchParams, urlParam])\n\n /**\n * Get current scenario from URL\n */\n const currentScenario = searchParams.get(urlParam)\n const isScenario =\n currentScenario !== null &&\n currentScenario !== 'true' &&\n currentScenario !== 'false' &&\n currentScenario !== '1' &&\n currentScenario !== '0'\n\n return {\n ...demoMode,\n enableWithScenario,\n enableDemo,\n disableDemo,\n currentScenario: isScenario ? currentScenario : null,\n }\n}\n\n/**\n * Hook to check if we're in demo mode on the client\n * Shorthand for useNextDemoMode().isDemoMode\n */\nexport function useIsNextDemoMode(): boolean {\n return useNextDemoMode().isDemoMode\n}\n\n// Re-export base hooks from @demokit-ai/react\nexport { useDemoMode, useIsDemoMode, useIsHydrated, useDemoSession } from '@demokit-ai/react'\n","'use client'\n\nimport { DemoModeBanner, type DemoModeBannerProps } from '@demokit-ai/react'\nimport { useNextDemoMode } from './hooks'\n\nexport interface NextDemoModeBannerProps extends Omit<DemoModeBannerProps, 'onExit'> {\n /**\n * Whether to include the current scenario in the banner\n * @default true\n */\n showScenario?: boolean\n\n /**\n * Custom exit handler\n * If not provided, will use URL-based navigation\n */\n onExit?: () => void\n}\n\n/**\n * Demo mode banner for Next.js\n *\n * Extends DemoModeBanner with scenario display and URL-based exit\n *\n * @example\n * // In your layout\n * <NextDemoModeBanner />\n *\n * // With custom labels\n * <NextDemoModeBanner\n * demoLabel=\"Preview Mode\"\n * exitLabel=\"Exit Preview\"\n * showScenario={true}\n * />\n */\nexport function NextDemoModeBanner({\n showScenario = true,\n onExit,\n description,\n ...props\n}: NextDemoModeBannerProps) {\n const { currentScenario, disableDemo, isDemoMode, isHydrated } = useNextDemoMode()\n\n // Don't render if not hydrated or not in demo mode\n if (!isHydrated || !isDemoMode) {\n return null\n }\n\n // Build description with scenario\n let bannerDescription = description ?? 'Changes are simulated and not saved'\n if (showScenario && currentScenario) {\n bannerDescription = `Scenario: ${currentScenario} • ${bannerDescription}`\n }\n\n return (\n <DemoModeBanner\n {...props}\n description={bannerDescription}\n onExit={onExit ?? disableDemo}\n />\n )\n}\n\n// Re-export base banner\nexport { DemoModeBanner } from '@demokit-ai/react'\n"]}
@@ -0,0 +1,114 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { b as DemoKitNextProviderProps } from './types-Cvq5JUP1.cjs';
3
+ import * as _demokit_ai_core from '@demokit-ai/core';
4
+ import { DemoModeBannerProps } from '@demokit-ai/react';
5
+ export { DemoModeBanner, useDemoMode, useDemoSession, useIsDemoMode, useIsHydrated } from '@demokit-ai/react';
6
+ import 'react';
7
+ import 'next/server';
8
+
9
+ /**
10
+ * Next.js-aware DemoKit provider
11
+ *
12
+ * This provider:
13
+ * - Reads initial state from cookies (set by middleware)
14
+ * - Supports scenario switching
15
+ * - Works with both App Router and Pages Router
16
+ *
17
+ * @example
18
+ * // app/providers.tsx
19
+ * 'use client'
20
+ *
21
+ * import { DemoKitNextProvider } from '@demokit-ai/next/client'
22
+ * import { fixtures, scenarios } from '@/lib/demo-fixtures'
23
+ *
24
+ * export function Providers({ children }: { children: React.ReactNode }) {
25
+ * return (
26
+ * <DemoKitNextProvider
27
+ * fixtures={fixtures}
28
+ * scenarios={scenarios}
29
+ * >
30
+ * {children}
31
+ * </DemoKitNextProvider>
32
+ * )
33
+ * }
34
+ */
35
+ declare function DemoKitNextProvider({ children, fixtures, scenarios, storageKey, cookieName, initialEnabled, baseUrl, }: DemoKitNextProviderProps): react_jsx_runtime.JSX.Element;
36
+
37
+ /**
38
+ * Hook for Next.js-specific demo mode controls
39
+ *
40
+ * Extends useDemoMode with URL-based scenario switching
41
+ *
42
+ * @example
43
+ * function DemoControls() {
44
+ * const { isDemoMode, enableWithScenario, disableDemo, currentScenario } = useNextDemoMode()
45
+ *
46
+ * return (
47
+ * <div>
48
+ * <button onClick={() => enableWithScenario('empty-state')}>
49
+ * Empty State Demo
50
+ * </button>
51
+ * <button onClick={() => enableWithScenario('error-state')}>
52
+ * Error State Demo
53
+ * </button>
54
+ * <button onClick={disableDemo}>
55
+ * Exit Demo
56
+ * </button>
57
+ * {currentScenario && <span>Scenario: {currentScenario}</span>}
58
+ * </div>
59
+ * )
60
+ * }
61
+ */
62
+ declare function useNextDemoMode(options?: {
63
+ urlParam?: string;
64
+ }): {
65
+ enableWithScenario: (scenario: string) => void;
66
+ enableDemo: () => void;
67
+ disableDemo: () => void;
68
+ currentScenario: string | null;
69
+ isDemoMode: boolean;
70
+ isHydrated: boolean;
71
+ enable(): void;
72
+ disable(): void;
73
+ toggle(): void;
74
+ setDemoMode(enabled: boolean): void;
75
+ resetSession(): void;
76
+ getSession(): _demokit_ai_core.SessionState | null;
77
+ };
78
+ /**
79
+ * Hook to check if we're in demo mode on the client
80
+ * Shorthand for useNextDemoMode().isDemoMode
81
+ */
82
+ declare function useIsNextDemoMode(): boolean;
83
+
84
+ interface NextDemoModeBannerProps extends Omit<DemoModeBannerProps, 'onExit'> {
85
+ /**
86
+ * Whether to include the current scenario in the banner
87
+ * @default true
88
+ */
89
+ showScenario?: boolean;
90
+ /**
91
+ * Custom exit handler
92
+ * If not provided, will use URL-based navigation
93
+ */
94
+ onExit?: () => void;
95
+ }
96
+ /**
97
+ * Demo mode banner for Next.js
98
+ *
99
+ * Extends DemoModeBanner with scenario display and URL-based exit
100
+ *
101
+ * @example
102
+ * // In your layout
103
+ * <NextDemoModeBanner />
104
+ *
105
+ * // With custom labels
106
+ * <NextDemoModeBanner
107
+ * demoLabel="Preview Mode"
108
+ * exitLabel="Exit Preview"
109
+ * showScenario={true}
110
+ * />
111
+ */
112
+ declare function NextDemoModeBanner({ showScenario, onExit, description, ...props }: NextDemoModeBannerProps): react_jsx_runtime.JSX.Element | null;
113
+
114
+ export { DemoKitNextProvider, NextDemoModeBanner, type NextDemoModeBannerProps, useIsNextDemoMode, useNextDemoMode };
@@ -0,0 +1,114 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { b as DemoKitNextProviderProps } from './types-Cvq5JUP1.js';
3
+ import * as _demokit_ai_core from '@demokit-ai/core';
4
+ import { DemoModeBannerProps } from '@demokit-ai/react';
5
+ export { DemoModeBanner, useDemoMode, useDemoSession, useIsDemoMode, useIsHydrated } from '@demokit-ai/react';
6
+ import 'react';
7
+ import 'next/server';
8
+
9
+ /**
10
+ * Next.js-aware DemoKit provider
11
+ *
12
+ * This provider:
13
+ * - Reads initial state from cookies (set by middleware)
14
+ * - Supports scenario switching
15
+ * - Works with both App Router and Pages Router
16
+ *
17
+ * @example
18
+ * // app/providers.tsx
19
+ * 'use client'
20
+ *
21
+ * import { DemoKitNextProvider } from '@demokit-ai/next/client'
22
+ * import { fixtures, scenarios } from '@/lib/demo-fixtures'
23
+ *
24
+ * export function Providers({ children }: { children: React.ReactNode }) {
25
+ * return (
26
+ * <DemoKitNextProvider
27
+ * fixtures={fixtures}
28
+ * scenarios={scenarios}
29
+ * >
30
+ * {children}
31
+ * </DemoKitNextProvider>
32
+ * )
33
+ * }
34
+ */
35
+ declare function DemoKitNextProvider({ children, fixtures, scenarios, storageKey, cookieName, initialEnabled, baseUrl, }: DemoKitNextProviderProps): react_jsx_runtime.JSX.Element;
36
+
37
+ /**
38
+ * Hook for Next.js-specific demo mode controls
39
+ *
40
+ * Extends useDemoMode with URL-based scenario switching
41
+ *
42
+ * @example
43
+ * function DemoControls() {
44
+ * const { isDemoMode, enableWithScenario, disableDemo, currentScenario } = useNextDemoMode()
45
+ *
46
+ * return (
47
+ * <div>
48
+ * <button onClick={() => enableWithScenario('empty-state')}>
49
+ * Empty State Demo
50
+ * </button>
51
+ * <button onClick={() => enableWithScenario('error-state')}>
52
+ * Error State Demo
53
+ * </button>
54
+ * <button onClick={disableDemo}>
55
+ * Exit Demo
56
+ * </button>
57
+ * {currentScenario && <span>Scenario: {currentScenario}</span>}
58
+ * </div>
59
+ * )
60
+ * }
61
+ */
62
+ declare function useNextDemoMode(options?: {
63
+ urlParam?: string;
64
+ }): {
65
+ enableWithScenario: (scenario: string) => void;
66
+ enableDemo: () => void;
67
+ disableDemo: () => void;
68
+ currentScenario: string | null;
69
+ isDemoMode: boolean;
70
+ isHydrated: boolean;
71
+ enable(): void;
72
+ disable(): void;
73
+ toggle(): void;
74
+ setDemoMode(enabled: boolean): void;
75
+ resetSession(): void;
76
+ getSession(): _demokit_ai_core.SessionState | null;
77
+ };
78
+ /**
79
+ * Hook to check if we're in demo mode on the client
80
+ * Shorthand for useNextDemoMode().isDemoMode
81
+ */
82
+ declare function useIsNextDemoMode(): boolean;
83
+
84
+ interface NextDemoModeBannerProps extends Omit<DemoModeBannerProps, 'onExit'> {
85
+ /**
86
+ * Whether to include the current scenario in the banner
87
+ * @default true
88
+ */
89
+ showScenario?: boolean;
90
+ /**
91
+ * Custom exit handler
92
+ * If not provided, will use URL-based navigation
93
+ */
94
+ onExit?: () => void;
95
+ }
96
+ /**
97
+ * Demo mode banner for Next.js
98
+ *
99
+ * Extends DemoModeBanner with scenario display and URL-based exit
100
+ *
101
+ * @example
102
+ * // In your layout
103
+ * <NextDemoModeBanner />
104
+ *
105
+ * // With custom labels
106
+ * <NextDemoModeBanner
107
+ * demoLabel="Preview Mode"
108
+ * exitLabel="Exit Preview"
109
+ * showScenario={true}
110
+ * />
111
+ */
112
+ declare function NextDemoModeBanner({ showScenario, onExit, description, ...props }: NextDemoModeBannerProps): react_jsx_runtime.JSX.Element | null;
113
+
114
+ export { DemoKitNextProvider, NextDemoModeBanner, type NextDemoModeBannerProps, useIsNextDemoMode, useNextDemoMode };
package/dist/client.js ADDED
@@ -0,0 +1,128 @@
1
+ import { useState, useEffect, useMemo, useCallback } from 'react';
2
+ import { DemoKitProvider, useDemoMode, DemoModeBanner } from '@demokit-ai/react';
3
+ export { DemoModeBanner, useDemoMode, useDemoSession, useIsDemoMode, useIsHydrated } from '@demokit-ai/react';
4
+ import { jsx } from 'react/jsx-runtime';
5
+ import { useRouter, useSearchParams } from 'next/navigation';
6
+
7
+ // src/client/provider.tsx
8
+ function getDemoModeFromCookie(cookieName) {
9
+ if (typeof document === "undefined") return false;
10
+ const cookies = document.cookie.split(";");
11
+ const demoCookie = cookies.find((c) => c.trim().startsWith(`${cookieName}=`));
12
+ return demoCookie !== void 0;
13
+ }
14
+ function getScenarioFromCookie(cookieName) {
15
+ if (typeof document === "undefined") return null;
16
+ const cookies = document.cookie.split(";");
17
+ const demoCookie = cookies.find((c) => c.trim().startsWith(`${cookieName}=`));
18
+ if (!demoCookie) return null;
19
+ const value = demoCookie.split("=")[1]?.trim();
20
+ if (!value || value === "true") return null;
21
+ return value;
22
+ }
23
+ function DemoKitNextProvider({
24
+ children,
25
+ fixtures,
26
+ scenarios = {},
27
+ storageKey = "demokit-mode",
28
+ cookieName = "demokit-mode",
29
+ initialEnabled,
30
+ baseUrl
31
+ }) {
32
+ const [isHydrated, setIsHydrated] = useState(false);
33
+ const [scenario, setScenario] = useState(null);
34
+ useEffect(() => {
35
+ getDemoModeFromCookie(cookieName);
36
+ const cookieScenario = getScenarioFromCookie(cookieName);
37
+ setScenario(cookieScenario);
38
+ setIsHydrated(true);
39
+ }, [cookieName]);
40
+ const activeFixtures = useMemo(() => {
41
+ if (scenario && scenarios[scenario]) {
42
+ return { ...fixtures, ...scenarios[scenario] };
43
+ }
44
+ return fixtures;
45
+ }, [fixtures, scenarios, scenario]);
46
+ const enabled = useMemo(() => {
47
+ if (initialEnabled !== void 0) {
48
+ return initialEnabled;
49
+ }
50
+ if (!isHydrated) {
51
+ return false;
52
+ }
53
+ return getDemoModeFromCookie(cookieName);
54
+ }, [initialEnabled, isHydrated, cookieName]);
55
+ return /* @__PURE__ */ jsx(
56
+ DemoKitProvider,
57
+ {
58
+ fixtures: activeFixtures,
59
+ storageKey,
60
+ initialEnabled: enabled,
61
+ baseUrl,
62
+ children
63
+ }
64
+ );
65
+ }
66
+ function useNextDemoMode(options = {}) {
67
+ const { urlParam = "demo" } = options;
68
+ const demoMode = useDemoMode();
69
+ const router = useRouter();
70
+ const searchParams = useSearchParams();
71
+ const enableWithScenario = useCallback(
72
+ (scenario) => {
73
+ const params = new URLSearchParams(searchParams.toString());
74
+ params.set(urlParam, scenario);
75
+ router.push(`?${params.toString()}`);
76
+ },
77
+ [router, searchParams, urlParam]
78
+ );
79
+ const enableDemo = useCallback(() => {
80
+ const params = new URLSearchParams(searchParams.toString());
81
+ params.set(urlParam, "true");
82
+ router.push(`?${params.toString()}`);
83
+ }, [router, searchParams, urlParam]);
84
+ const disableDemo = useCallback(() => {
85
+ const params = new URLSearchParams(searchParams.toString());
86
+ params.set(urlParam, "false");
87
+ router.push(`?${params.toString()}`);
88
+ }, [router, searchParams, urlParam]);
89
+ const currentScenario = searchParams.get(urlParam);
90
+ const isScenario = currentScenario !== null && currentScenario !== "true" && currentScenario !== "false" && currentScenario !== "1" && currentScenario !== "0";
91
+ return {
92
+ ...demoMode,
93
+ enableWithScenario,
94
+ enableDemo,
95
+ disableDemo,
96
+ currentScenario: isScenario ? currentScenario : null
97
+ };
98
+ }
99
+ function useIsNextDemoMode() {
100
+ return useNextDemoMode().isDemoMode;
101
+ }
102
+ function NextDemoModeBanner({
103
+ showScenario = true,
104
+ onExit,
105
+ description,
106
+ ...props
107
+ }) {
108
+ const { currentScenario, disableDemo, isDemoMode, isHydrated } = useNextDemoMode();
109
+ if (!isHydrated || !isDemoMode) {
110
+ return null;
111
+ }
112
+ let bannerDescription = description ?? "Changes are simulated and not saved";
113
+ if (showScenario && currentScenario) {
114
+ bannerDescription = `Scenario: ${currentScenario} \u2022 ${bannerDescription}`;
115
+ }
116
+ return /* @__PURE__ */ jsx(
117
+ DemoModeBanner,
118
+ {
119
+ ...props,
120
+ description: bannerDescription,
121
+ onExit: onExit ?? disableDemo
122
+ }
123
+ );
124
+ }
125
+
126
+ export { DemoKitNextProvider, NextDemoModeBanner, useIsNextDemoMode, useNextDemoMode };
127
+ //# sourceMappingURL=client.js.map
128
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/client/provider.tsx","../src/client/hooks.ts","../src/client/banner.tsx"],"names":["jsx"],"mappings":"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","file":"client.js","sourcesContent":["'use client'\n\nimport { useEffect, useState, useMemo } from 'react'\nimport { DemoKitProvider, type DemoKitProviderProps } from '@demokit-ai/react'\nimport type { DemoKitNextProviderProps } from '../types'\n\n/**\n * Get initial demo mode state from cookie\n */\nfunction getDemoModeFromCookie(cookieName: string): boolean {\n if (typeof document === 'undefined') return false\n\n const cookies = document.cookie.split(';')\n const demoCookie = cookies.find((c) => c.trim().startsWith(`${cookieName}=`))\n\n return demoCookie !== undefined\n}\n\n/**\n * Get scenario from cookie\n */\nfunction getScenarioFromCookie(cookieName: string): string | null {\n if (typeof document === 'undefined') return null\n\n const cookies = document.cookie.split(';')\n const demoCookie = cookies.find((c) => c.trim().startsWith(`${cookieName}=`))\n\n if (!demoCookie) return null\n\n const value = demoCookie.split('=')[1]?.trim()\n if (!value || value === 'true') return null\n\n return value\n}\n\n/**\n * Next.js-aware DemoKit provider\n *\n * This provider:\n * - Reads initial state from cookies (set by middleware)\n * - Supports scenario switching\n * - Works with both App Router and Pages Router\n *\n * @example\n * // app/providers.tsx\n * 'use client'\n *\n * import { DemoKitNextProvider } from '@demokit-ai/next/client'\n * import { fixtures, scenarios } from '@/lib/demo-fixtures'\n *\n * export function Providers({ children }: { children: React.ReactNode }) {\n * return (\n * <DemoKitNextProvider\n * fixtures={fixtures}\n * scenarios={scenarios}\n * >\n * {children}\n * </DemoKitNextProvider>\n * )\n * }\n */\nexport function DemoKitNextProvider({\n children,\n fixtures,\n scenarios = {},\n storageKey = 'demokit-mode',\n cookieName = 'demokit-mode',\n initialEnabled,\n baseUrl,\n}: DemoKitNextProviderProps) {\n const [isHydrated, setIsHydrated] = useState(false)\n const [scenario, setScenario] = useState<string | null>(null)\n\n // Read initial state from cookie on mount\n useEffect(() => {\n const cookieEnabled = getDemoModeFromCookie(cookieName)\n const cookieScenario = getScenarioFromCookie(cookieName)\n setScenario(cookieScenario)\n setIsHydrated(true)\n }, [cookieName])\n\n // Merge fixtures with scenario fixtures\n const activeFixtures = useMemo(() => {\n if (scenario && scenarios[scenario]) {\n return { ...fixtures, ...scenarios[scenario] }\n }\n return fixtures\n }, [fixtures, scenarios, scenario])\n\n // Determine initial enabled state\n const enabled = useMemo(() => {\n if (initialEnabled !== undefined) {\n return initialEnabled\n }\n if (!isHydrated) {\n return false\n }\n return getDemoModeFromCookie(cookieName)\n }, [initialEnabled, isHydrated, cookieName])\n\n return (\n <DemoKitProvider\n fixtures={activeFixtures}\n storageKey={storageKey}\n initialEnabled={enabled}\n baseUrl={baseUrl}\n >\n {children}\n </DemoKitProvider>\n )\n}\n","'use client'\n\nimport { useCallback } from 'react'\nimport { useDemoMode } from '@demokit-ai/react'\nimport { useRouter, useSearchParams } from 'next/navigation'\n\n/**\n * Hook for Next.js-specific demo mode controls\n *\n * Extends useDemoMode with URL-based scenario switching\n *\n * @example\n * function DemoControls() {\n * const { isDemoMode, enableWithScenario, disableDemo, currentScenario } = useNextDemoMode()\n *\n * return (\n * <div>\n * <button onClick={() => enableWithScenario('empty-state')}>\n * Empty State Demo\n * </button>\n * <button onClick={() => enableWithScenario('error-state')}>\n * Error State Demo\n * </button>\n * <button onClick={disableDemo}>\n * Exit Demo\n * </button>\n * {currentScenario && <span>Scenario: {currentScenario}</span>}\n * </div>\n * )\n * }\n */\nexport function useNextDemoMode(options: { urlParam?: string } = {}) {\n const { urlParam = 'demo' } = options\n const demoMode = useDemoMode()\n const router = useRouter()\n const searchParams = useSearchParams()\n\n /**\n * Enable demo mode with a specific scenario via URL\n */\n const enableWithScenario = useCallback(\n (scenario: string) => {\n const params = new URLSearchParams(searchParams.toString())\n params.set(urlParam, scenario)\n router.push(`?${params.toString()}`)\n },\n [router, searchParams, urlParam]\n )\n\n /**\n * Enable demo mode without a scenario\n */\n const enableDemo = useCallback(() => {\n const params = new URLSearchParams(searchParams.toString())\n params.set(urlParam, 'true')\n router.push(`?${params.toString()}`)\n }, [router, searchParams, urlParam])\n\n /**\n * Disable demo mode via URL\n */\n const disableDemo = useCallback(() => {\n const params = new URLSearchParams(searchParams.toString())\n params.set(urlParam, 'false')\n router.push(`?${params.toString()}`)\n }, [router, searchParams, urlParam])\n\n /**\n * Get current scenario from URL\n */\n const currentScenario = searchParams.get(urlParam)\n const isScenario =\n currentScenario !== null &&\n currentScenario !== 'true' &&\n currentScenario !== 'false' &&\n currentScenario !== '1' &&\n currentScenario !== '0'\n\n return {\n ...demoMode,\n enableWithScenario,\n enableDemo,\n disableDemo,\n currentScenario: isScenario ? currentScenario : null,\n }\n}\n\n/**\n * Hook to check if we're in demo mode on the client\n * Shorthand for useNextDemoMode().isDemoMode\n */\nexport function useIsNextDemoMode(): boolean {\n return useNextDemoMode().isDemoMode\n}\n\n// Re-export base hooks from @demokit-ai/react\nexport { useDemoMode, useIsDemoMode, useIsHydrated, useDemoSession } from '@demokit-ai/react'\n","'use client'\n\nimport { DemoModeBanner, type DemoModeBannerProps } from '@demokit-ai/react'\nimport { useNextDemoMode } from './hooks'\n\nexport interface NextDemoModeBannerProps extends Omit<DemoModeBannerProps, 'onExit'> {\n /**\n * Whether to include the current scenario in the banner\n * @default true\n */\n showScenario?: boolean\n\n /**\n * Custom exit handler\n * If not provided, will use URL-based navigation\n */\n onExit?: () => void\n}\n\n/**\n * Demo mode banner for Next.js\n *\n * Extends DemoModeBanner with scenario display and URL-based exit\n *\n * @example\n * // In your layout\n * <NextDemoModeBanner />\n *\n * // With custom labels\n * <NextDemoModeBanner\n * demoLabel=\"Preview Mode\"\n * exitLabel=\"Exit Preview\"\n * showScenario={true}\n * />\n */\nexport function NextDemoModeBanner({\n showScenario = true,\n onExit,\n description,\n ...props\n}: NextDemoModeBannerProps) {\n const { currentScenario, disableDemo, isDemoMode, isHydrated } = useNextDemoMode()\n\n // Don't render if not hydrated or not in demo mode\n if (!isHydrated || !isDemoMode) {\n return null\n }\n\n // Build description with scenario\n let bannerDescription = description ?? 'Changes are simulated and not saved'\n if (showScenario && currentScenario) {\n bannerDescription = `Scenario: ${currentScenario} • ${bannerDescription}`\n }\n\n return (\n <DemoModeBanner\n {...props}\n description={bannerDescription}\n onExit={onExit ?? disableDemo}\n />\n )\n}\n\n// Re-export base banner\nexport { DemoModeBanner } from '@demokit-ai/react'\n"]}
package/dist/index.cjs ADDED
@@ -0,0 +1,31 @@
1
+ 'use strict';
2
+
3
+ // src/config.ts
4
+ function defineFixtures(fixtures) {
5
+ return fixtures;
6
+ }
7
+ function defineScenarios(scenarios) {
8
+ return scenarios;
9
+ }
10
+ function createScenario(scenario) {
11
+ return scenario;
12
+ }
13
+ function mergeFixtures(...fixtureMaps) {
14
+ return Object.assign({}, ...fixtureMaps);
15
+ }
16
+ function createDemoConfig(config) {
17
+ return {
18
+ storageKey: "demokit-mode",
19
+ cookieName: "demokit-mode",
20
+ urlParam: "demo",
21
+ ...config
22
+ };
23
+ }
24
+
25
+ exports.createDemoConfig = createDemoConfig;
26
+ exports.createScenario = createScenario;
27
+ exports.defineFixtures = defineFixtures;
28
+ exports.defineScenarios = defineScenarios;
29
+ exports.mergeFixtures = mergeFixtures;
30
+ //# sourceMappingURL=index.cjs.map
31
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/config.ts"],"names":[],"mappings":";;;AAqBO,SAAS,eAAqC,QAAA,EAAgB;AACnE,EAAA,OAAO,QAAA;AACT;AAuBO,SAAS,gBAAsD,SAAA,EAAiB;AACrF,EAAA,OAAO,SAAA;AACT;AAcO,SAAS,eAAe,QAAA,EAAsC;AACnE,EAAA,OAAO,QAAA;AACT;AAYO,SAAS,iBAAiB,WAAA,EAAuC;AACtE,EAAA,OAAO,MAAA,CAAO,MAAA,CAAO,EAAC,EAAG,GAAG,WAAW,CAAA;AACzC;AAkBO,SAAS,iBAAiB,MAAA,EAA8C;AAC7E,EAAA,OAAO;AAAA,IACL,UAAA,EAAY,cAAA;AAAA,IACZ,UAAA,EAAY,cAAA;AAAA,IACZ,QAAA,EAAU,MAAA;AAAA,IACV,GAAG;AAAA,GACL;AACF","file":"index.cjs","sourcesContent":["import type { FixtureMap, FixtureHandler } from '@demokit-ai/core'\nimport type { DemoKitNextConfig, DemoScenario } from './types'\n\n/**\n * Helper to define fixtures with type safety\n *\n * @example\n * const fixtures = defineFixtures({\n * 'GET /api/users': () => [\n * { id: '1', name: 'Demo User' },\n * ],\n * 'GET /api/users/:id': ({ params }) => ({\n * id: params.id,\n * name: `User ${params.id}`,\n * }),\n * 'POST /api/users': async ({ body }) => ({\n * id: crypto.randomUUID(),\n * ...body,\n * }),\n * })\n */\nexport function defineFixtures<T extends FixtureMap>(fixtures: T): T {\n return fixtures\n}\n\n/**\n * Helper to define scenarios with type safety\n *\n * @example\n * const scenarios = defineScenarios({\n * 'empty-state': {\n * 'GET /api/users': () => [],\n * 'GET /api/projects': () => [],\n * },\n * 'error-state': {\n * 'GET /api/users': () => {\n * throw new Error('API Error')\n * },\n * },\n * 'new-user': {\n * 'GET /api/users': () => [\n * { id: '1', name: 'Welcome, New User!', isNew: true },\n * ],\n * },\n * })\n */\nexport function defineScenarios<T extends Record<string, FixtureMap>>(scenarios: T): T {\n return scenarios\n}\n\n/**\n * Helper to create a scenario object\n *\n * @example\n * const emptyStateScenario = createScenario({\n * name: 'empty-state',\n * description: 'Shows the app with no data',\n * fixtures: {\n * 'GET /api/users': () => [],\n * },\n * })\n */\nexport function createScenario(scenario: DemoScenario): DemoScenario {\n return scenario\n}\n\n/**\n * Merge multiple fixture maps\n *\n * @example\n * const allFixtures = mergeFixtures(\n * baseFixtures,\n * usersFixtures,\n * projectsFixtures\n * )\n */\nexport function mergeFixtures(...fixtureMaps: FixtureMap[]): FixtureMap {\n return Object.assign({}, ...fixtureMaps)\n}\n\n/**\n * Create a complete DemoKit Next.js configuration\n *\n * @example\n * // lib/demo.ts\n * import { createDemoConfig, defineFixtures, defineScenarios } from '@demokit-ai/next'\n *\n * export const demoConfig = createDemoConfig({\n * fixtures: defineFixtures({\n * 'GET /api/users': () => [{ id: '1', name: 'Demo User' }],\n * }),\n * scenarios: defineScenarios({\n * 'empty': { 'GET /api/users': () => [] },\n * }),\n * })\n */\nexport function createDemoConfig(config: DemoKitNextConfig): DemoKitNextConfig {\n return {\n storageKey: 'demokit-mode',\n cookieName: 'demokit-mode',\n urlParam: 'demo',\n ...config,\n }\n}\n"]}