From d259361d4ed88bbc701ac3b1a34ce9537c8571c4 Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 21 Jan 2026 17:16:33 -0500 Subject: [PATCH 1/9] split out toolbar into v1 and v2 --- examples/guide-example/src/App.tsx | 1 + packages/client/src/clients/guide/client.ts | 56 +++++++-- packages/client/src/clients/guide/types.ts | 4 +- .../client/test/clients/guide/guide.test.ts | 12 +- .../guide/context/KnockGuideProvider.tsx | 7 ++ ...timestamp-1769027936090-215a58f55e0f58.mjs | 64 ++++++++++ packages/react/src/index.ts | 1 - .../guide/components/Toolbar/KnockButton.tsx | 51 ++++++++ .../guide/components/Toolbar/V1/V1.tsx | 93 +++++++++++++++ .../guide/components/Toolbar/V1/index.ts | 1 + .../guide/components/Toolbar/V2/V2.tsx | 109 ++++++++++++++++++ .../guide/components/Toolbar/V2/helpers.ts | 17 +++ .../guide/components/Toolbar/V2/index.ts | 1 + .../modules/guide/components/Toolbar/index.ts | 2 + .../guide/components/Toolbar/shared.ts | 3 + .../guide/components/Toolbar/styles.css | 2 + .../src/modules/guide/components/index.ts | 2 +- packages/react/src/modules/guide/index.ts | 3 +- .../guide/providers/KnockGuideProvider.tsx | 27 +++-- .../V1/ToolbarV1.test.tsx} | 10 +- 20 files changed, 436 insertions(+), 30 deletions(-) create mode 100644 packages/react-core/vite.config.mts.timestamp-1769027936090-215a58f55e0f58.mjs create mode 100644 packages/react/src/modules/guide/components/Toolbar/KnockButton.tsx create mode 100644 packages/react/src/modules/guide/components/Toolbar/V1/V1.tsx create mode 100644 packages/react/src/modules/guide/components/Toolbar/V1/index.ts create mode 100644 packages/react/src/modules/guide/components/Toolbar/V2/V2.tsx create mode 100644 packages/react/src/modules/guide/components/Toolbar/V2/helpers.ts create mode 100644 packages/react/src/modules/guide/components/Toolbar/V2/index.ts create mode 100644 packages/react/src/modules/guide/components/Toolbar/index.ts create mode 100644 packages/react/src/modules/guide/components/Toolbar/shared.ts create mode 100644 packages/react/src/modules/guide/components/Toolbar/styles.css rename packages/react/test/guide/{GuideToolbar.test.tsx => Toolbar/V1/ToolbarV1.test.tsx} (88%) diff --git a/examples/guide-example/src/App.tsx b/examples/guide-example/src/App.tsx index ab59a88ce..9d3204fe8 100644 --- a/examples/guide-example/src/App.tsx +++ b/examples/guide-example/src/App.tsx @@ -65,6 +65,7 @@ function App() { readyToTarget={true} listenForUpdates={true} colorMode={colorMode} + toolbar="v2" >

Knock In-App Guide Example

diff --git a/packages/client/src/clients/guide/client.ts b/packages/client/src/clients/guide/client.ts index a434eaa53..a1dfc9d9a 100644 --- a/packages/client/src/clients/guide/client.ts +++ b/packages/client/src/clients/guide/client.ts @@ -270,13 +270,15 @@ export class KnockGuideClient { ) { const { trackLocationFromWindow = true, + // TODO: Remove this option once we ship guide toolbar v2, and offload + // as much debugging specific logic and responsibilities to toolbar. + trackDebugParams = false, throttleCheckInterval = DEFAULT_COUNTER_INCREMENT_INTERVAL, } = options; const win = checkForWindow(); const location = trackLocationFromWindow ? win?.location?.href : undefined; - - const debug = detectDebugParams(); + const debug = trackDebugParams ? detectDebugParams() : undefined; this.store = new Store({ guideGroups: [], @@ -412,8 +414,8 @@ export class KnockGuideClient { const params = { ...this.targetParams, user_id: this.knock.userId, - force_all_guides: debugState.forcedGuideKey ? true : undefined, - preview_session_id: debugState.previewSessionId || undefined, + force_all_guides: debugState?.forcedGuideKey ? true : undefined, + preview_session_id: debugState?.previewSessionId || undefined, }; const newChannel = this.socket.channel(this.socketChannelTopic, params); @@ -561,6 +563,39 @@ export class KnockGuideClient { } } + setDebug(debugOpts?: Omit) { + this.knock.log("[Guide] .setDebug()"); + const shouldRefetch = !this.store.state.debug?.debugging; + + this.store.setState((state) => ({ + ...state, + debug: { ...debugOpts, debugging: true }, + })); + + if (shouldRefetch) { + this.knock.log( + `[Guide] Start debugging, refetching guides and resubscribing to the websocket channel`, + ); + this.fetch(); + this.subscribe(); + } + } + + unsetDebug() { + this.knock.log("[Guide] .unsetDebug()"); + const shouldRefetch = this.store.state.debug?.debugging; + + this.store.setState((state) => ({ ...state, debug: undefined })); + + if (shouldRefetch) { + this.knock.log( + `[Guide] Stop debugging, refetching guides and resubscribing to the websocket channel`, + ); + this.fetch(); + this.subscribe(); + } + } + // // Store selector // @@ -924,7 +959,7 @@ export class KnockGuideClient { // Get the next unarchived step. getStep() { // If debugging this guide, return the first step regardless of archive status - if (self.store.state.debug.forcedGuideKey === this.key) { + if (self.store.state.debug?.forcedGuideKey === this.key) { return this.steps[0]; } @@ -981,7 +1016,7 @@ export class KnockGuideClient { // Append debug params const debugState = this.store.state.debug; - if (debugState.forcedGuideKey) { + if (debugState?.forcedGuideKey || debugState?.debugging) { combinedParams.force_all_guides = true; } @@ -1150,8 +1185,15 @@ export class KnockGuideClient { this.knock.log(`[Guide] Detected a location change: ${href}`); + if (!this.options.trackDebugParams) { + this.setLocation(href); + return; + } + + // TODO: Remove below once we ship toolbar v2. + // If entering debug mode, fetch all guides. - const currentDebugParams = this.store.state.debug; + const currentDebugParams = this.store.state.debug || {}; const newDebugParams = detectDebugParams(); this.setLocation(href, { debug: newDebugParams }); diff --git a/packages/client/src/clients/guide/types.ts b/packages/client/src/clients/guide/types.ts index 47e5f2093..0327d8270 100644 --- a/packages/client/src/clients/guide/types.ts +++ b/packages/client/src/clients/guide/types.ts @@ -202,6 +202,7 @@ export type QueryStatus = { }; export type DebugState = { + debugging?: boolean; forcedGuideKey?: string | null; previewSessionId?: string | null; }; @@ -218,7 +219,7 @@ export type StoreState = { queries: Record; location: string | undefined; counter: number; - debug: DebugState; + debug?: DebugState; }; export type QueryFilterParams = Pick; @@ -241,6 +242,7 @@ export type TargetParams = { export type ConstructorOpts = { trackLocationFromWindow?: boolean; + trackDebugParams?: boolean; orderResolutionDuration?: number; throttleCheckInterval?: number; }; diff --git a/packages/client/test/clients/guide/guide.test.ts b/packages/client/test/clients/guide/guide.test.ts index 2c43dbf8c..cb46d5bb1 100644 --- a/packages/client/test/clients/guide/guide.test.ts +++ b/packages/client/test/clients/guide/guide.test.ts @@ -165,7 +165,7 @@ describe("KnockGuideClient", () => { queries: {}, location: undefined, counter: 0, - debug: { forcedGuideKey: null, previewSessionId: null }, + debug: undefined, }); }); @@ -194,7 +194,7 @@ describe("KnockGuideClient", () => { queries: {}, location: "https://example.com", counter: 0, - debug: { forcedGuideKey: null, previewSessionId: null }, + debug: undefined, }); }); @@ -211,7 +211,7 @@ describe("KnockGuideClient", () => { queries: {}, location: undefined, counter: 0, - debug: { forcedGuideKey: null, previewSessionId: null }, + debug: undefined, }); }); @@ -234,7 +234,7 @@ describe("KnockGuideClient", () => { }); expect(() => { - new KnockGuideClient(mockKnock, channelId); + new KnockGuideClient(mockKnock, channelId, {}, { trackDebugParams: true }); }).not.toThrow(); expect(mockLocalStorageWithErrors.setItem).toHaveBeenCalled(); @@ -2959,7 +2959,7 @@ describe("KnockGuideClient", () => { mockKnock, channelId, {}, - { trackLocationFromWindow: true }, + { trackLocationFromWindow: true, trackDebugParams: true }, ); client.store.state.debug = { forcedGuideKey: null }; @@ -3016,7 +3016,7 @@ describe("KnockGuideClient", () => { mockKnock, channelId, {}, - { trackLocationFromWindow: true }, + { trackLocationFromWindow: true, trackDebugParams: true }, ); client.store.state.debug = { forcedGuideKey: "test_guide" }; diff --git a/packages/react-core/src/modules/guide/context/KnockGuideProvider.tsx b/packages/react-core/src/modules/guide/context/KnockGuideProvider.tsx index 0d2de3354..768b166d6 100644 --- a/packages/react-core/src/modules/guide/context/KnockGuideProvider.tsx +++ b/packages/react-core/src/modules/guide/context/KnockGuideProvider.tsx @@ -23,6 +23,7 @@ export type KnockGuideProviderProps = { colorMode?: ColorMode; targetParams?: KnockGuideTargetParams; trackLocationFromWindow?: boolean; + trackDebugParams?: boolean; orderResolutionDuration?: number; // in milliseconds throttleCheckInterval?: number; // in milliseconds }; @@ -36,6 +37,10 @@ export const KnockGuideProvider: React.FC< colorMode = "light", targetParams = {}, trackLocationFromWindow = true, + // Whether the guide client should look for debug params from url or local + // storage to launch guide toolbar. Set to true when using toolbar v1, but + // plan to phase this out going forward with v2. + trackDebugParams = false, // Default to 0 which works well for react apps as this "yields" to react for // one render cyle first and close the group stage. orderResolutionDuration = 0, @@ -55,6 +60,7 @@ export const KnockGuideProvider: React.FC< const knockGuideClient = React.useMemo(() => { return new KnockGuideClient(knock, channelId, stableTargetParams, { trackLocationFromWindow, + trackDebugParams, orderResolutionDuration, throttleCheckInterval, }); @@ -63,6 +69,7 @@ export const KnockGuideProvider: React.FC< channelId, stableTargetParams, trackLocationFromWindow, + trackDebugParams, orderResolutionDuration, throttleCheckInterval, ]); diff --git a/packages/react-core/vite.config.mts.timestamp-1769027936090-215a58f55e0f58.mjs b/packages/react-core/vite.config.mts.timestamp-1769027936090-215a58f55e0f58.mjs new file mode 100644 index 000000000..b5a568e6a --- /dev/null +++ b/packages/react-core/vite.config.mts.timestamp-1769027936090-215a58f55e0f58.mjs @@ -0,0 +1,64 @@ +// vite.config.mts +import { codecovVitePlugin } from "file:///Users/tsyy/work/javascript/node_modules/@codecov/vite-plugin/dist/index.mjs"; +import react from "file:///Users/tsyy/work/javascript/node_modules/@vitejs/plugin-react/dist/index.mjs"; +import { resolve } from "path"; +import { defineConfig, loadEnv } from "file:///Users/tsyy/work/javascript/node_modules/vite/dist/node/index.js"; +import dts from "file:///Users/tsyy/work/javascript/node_modules/vite-plugin-dts/dist/index.mjs"; +import noBundlePlugin from "file:///Users/tsyy/work/javascript/node_modules/vite-plugin-no-bundle/dist/index.js"; +var __vite_injected_original_dirname = "/Users/tsyy/work/javascript/packages/react-core"; +var vite_config_default = defineConfig(({ mode }) => { + const env = loadEnv(mode, process.cwd(), ""); + const CJS = env.BUILD_TARGET?.toLocaleLowerCase()?.match("cjs"); + const formats = CJS ? ["cjs"] : ["es"]; + return { + plugins: [ + dts({ + outDir: "dist/types" + }), + react({ + jsxRuntime: "classic", + babel: { + plugins: ["react-require"] + } + }), + noBundlePlugin({ root: "./src" }), + codecovVitePlugin({ + enableBundleAnalysis: process.env.CODECOV_TOKEN !== void 0, + bundleName: "@knocklabs/react-core", + uploadToken: process.env.CODECOV_TOKEN + }) + ], + build: { + outDir: CJS ? "dist/cjs" : "dist/esm", + sourcemap: true, + lib: { + entry: resolve(__vite_injected_original_dirname, "src"), + fileName: `[name]`, + name: "react-core", + formats + }, + rollupOptions: { + // External packages that should not be bundled + external: ["react"], + output: { + interop: "compat", + globals: { + react: "React" + }, + entryFileNames: () => { + return `[name].${CJS ? "js" : "mjs"}`; + } + } + } + }, + test: { + global: true, + environment: "jsdom", + setupFiles: "./setupTest.ts" + } + }; +}); +export { + vite_config_default as default +}; +//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcubXRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyJjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZGlybmFtZSA9IFwiL1VzZXJzL3RzeXkvd29yay9qYXZhc2NyaXB0L3BhY2thZ2VzL3JlYWN0LWNvcmVcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZmlsZW5hbWUgPSBcIi9Vc2Vycy90c3l5L3dvcmsvamF2YXNjcmlwdC9wYWNrYWdlcy9yZWFjdC1jb3JlL3ZpdGUuY29uZmlnLm10c1wiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9pbXBvcnRfbWV0YV91cmwgPSBcImZpbGU6Ly8vVXNlcnMvdHN5eS93b3JrL2phdmFzY3JpcHQvcGFja2FnZXMvcmVhY3QtY29yZS92aXRlLmNvbmZpZy5tdHNcIjsvLy8gPHJlZmVyZW5jZSB0eXBlcz1cInZpdGVzdFwiIC8+XG5pbXBvcnQgeyBjb2RlY292Vml0ZVBsdWdpbiB9IGZyb20gXCJAY29kZWNvdi92aXRlLXBsdWdpblwiO1xuaW1wb3J0IHJlYWN0IGZyb20gXCJAdml0ZWpzL3BsdWdpbi1yZWFjdFwiO1xuaW1wb3J0IHsgcmVzb2x2ZSB9IGZyb20gXCJwYXRoXCI7XG5pbXBvcnQgeyBMaWJyYXJ5Rm9ybWF0cywgZGVmaW5lQ29uZmlnLCBsb2FkRW52IH0gZnJvbSBcInZpdGVcIjtcbmltcG9ydCBkdHMgZnJvbSBcInZpdGUtcGx1Z2luLWR0c1wiO1xuaW1wb3J0IG5vQnVuZGxlUGx1Z2luIGZyb20gXCJ2aXRlLXBsdWdpbi1uby1idW5kbGVcIjtcblxuLy8gaHR0cHM6Ly92aXRlanMuZGV2L2NvbmZpZy9cbmV4cG9ydCBkZWZhdWx0IGRlZmluZUNvbmZpZygoeyBtb2RlIH0pID0+IHtcbiAgY29uc3QgZW52ID0gbG9hZEVudihtb2RlLCBwcm9jZXNzLmN3ZCgpLCBcIlwiKTtcbiAgY29uc3QgQ0pTID0gZW52LkJVSUxEX1RBUkdFVD8udG9Mb2NhbGVMb3dlckNhc2UoKT8ubWF0Y2goXCJjanNcIik7XG4gIGNvbnN0IGZvcm1hdHM6IExpYnJhcnlGb3JtYXRzW10gPSBDSlMgPyBbXCJjanNcIl0gOiBbXCJlc1wiXTtcblxuICByZXR1cm4ge1xuICAgIHBsdWdpbnM6IFtcbiAgICAgIGR0cyh7XG4gICAgICAgIG91dERpcjogXCJkaXN0L3R5cGVzXCIsXG4gICAgICB9KSxcbiAgICAgIHJlYWN0KHtcbiAgICAgICAganN4UnVudGltZTogXCJjbGFzc2ljXCIsXG4gICAgICAgIGJhYmVsOiB7XG4gICAgICAgICAgcGx1Z2luczogW1wicmVhY3QtcmVxdWlyZVwiXSxcbiAgICAgICAgfSxcbiAgICAgIH0pLFxuICAgICAgbm9CdW5kbGVQbHVnaW4oeyByb290OiBcIi4vc3JjXCIgfSksXG4gICAgICBjb2RlY292Vml0ZVBsdWdpbih7XG4gICAgICAgIGVuYWJsZUJ1bmRsZUFuYWx5c2lzOiBwcm9jZXNzLmVudi5DT0RFQ09WX1RPS0VOICE9PSB1bmRlZmluZWQsXG4gICAgICAgIGJ1bmRsZU5hbWU6IFwiQGtub2NrbGFicy9yZWFjdC1jb3JlXCIsXG4gICAgICAgIHVwbG9hZFRva2VuOiBwcm9jZXNzLmVudi5DT0RFQ09WX1RPS0VOLFxuICAgICAgfSksXG4gICAgXSxcbiAgICBidWlsZDoge1xuICAgICAgb3V0RGlyOiBDSlMgPyBcImRpc3QvY2pzXCIgOiBcImRpc3QvZXNtXCIsXG4gICAgICBzb3VyY2VtYXA6IHRydWUsXG4gICAgICBsaWI6IHtcbiAgICAgICAgZW50cnk6IHJlc29sdmUoX19kaXJuYW1lLCBcInNyY1wiKSxcbiAgICAgICAgZmlsZU5hbWU6IGBbbmFtZV1gLFxuICAgICAgICBuYW1lOiBcInJlYWN0LWNvcmVcIixcbiAgICAgICAgZm9ybWF0cyxcbiAgICAgIH0sXG4gICAgICByb2xsdXBPcHRpb25zOiB7XG4gICAgICAgIC8vIEV4dGVybmFsIHBhY2thZ2VzIHRoYXQgc2hvdWxkIG5vdCBiZSBidW5kbGVkXG4gICAgICAgIGV4dGVybmFsOiBbXCJyZWFjdFwiXSxcbiAgICAgICAgb3V0cHV0OiB7XG4gICAgICAgICAgaW50ZXJvcDogXCJjb21wYXRcIixcbiAgICAgICAgICBnbG9iYWxzOiB7XG4gICAgICAgICAgICByZWFjdDogXCJSZWFjdFwiLFxuICAgICAgICAgIH0sXG4gICAgICAgICAgZW50cnlGaWxlTmFtZXM6ICgpID0+IHtcbiAgICAgICAgICAgIHJldHVybiBgW25hbWVdLiR7Q0pTID8gXCJqc1wiIDogXCJtanNcIn1gO1xuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgIH0sXG4gICAgdGVzdDoge1xuICAgICAgZ2xvYmFsOiB0cnVlLFxuICAgICAgZW52aXJvbm1lbnQ6IFwianNkb21cIixcbiAgICAgIHNldHVwRmlsZXM6IFwiLi9zZXR1cFRlc3QudHNcIixcbiAgICB9LFxuICB9O1xufSk7XG4iXSwKICAibWFwcGluZ3MiOiAiO0FBQ0EsU0FBUyx5QkFBeUI7QUFDbEMsT0FBTyxXQUFXO0FBQ2xCLFNBQVMsZUFBZTtBQUN4QixTQUF5QixjQUFjLGVBQWU7QUFDdEQsT0FBTyxTQUFTO0FBQ2hCLE9BQU8sb0JBQW9CO0FBTjNCLElBQU0sbUNBQW1DO0FBU3pDLElBQU8sc0JBQVEsYUFBYSxDQUFDLEVBQUUsS0FBSyxNQUFNO0FBQ3hDLFFBQU0sTUFBTSxRQUFRLE1BQU0sUUFBUSxJQUFJLEdBQUcsRUFBRTtBQUMzQyxRQUFNLE1BQU0sSUFBSSxjQUFjLGtCQUFrQixHQUFHLE1BQU0sS0FBSztBQUM5RCxRQUFNLFVBQTRCLE1BQU0sQ0FBQyxLQUFLLElBQUksQ0FBQyxJQUFJO0FBRXZELFNBQU87QUFBQSxJQUNMLFNBQVM7QUFBQSxNQUNQLElBQUk7QUFBQSxRQUNGLFFBQVE7QUFBQSxNQUNWLENBQUM7QUFBQSxNQUNELE1BQU07QUFBQSxRQUNKLFlBQVk7QUFBQSxRQUNaLE9BQU87QUFBQSxVQUNMLFNBQVMsQ0FBQyxlQUFlO0FBQUEsUUFDM0I7QUFBQSxNQUNGLENBQUM7QUFBQSxNQUNELGVBQWUsRUFBRSxNQUFNLFFBQVEsQ0FBQztBQUFBLE1BQ2hDLGtCQUFrQjtBQUFBLFFBQ2hCLHNCQUFzQixRQUFRLElBQUksa0JBQWtCO0FBQUEsUUFDcEQsWUFBWTtBQUFBLFFBQ1osYUFBYSxRQUFRLElBQUk7QUFBQSxNQUMzQixDQUFDO0FBQUEsSUFDSDtBQUFBLElBQ0EsT0FBTztBQUFBLE1BQ0wsUUFBUSxNQUFNLGFBQWE7QUFBQSxNQUMzQixXQUFXO0FBQUEsTUFDWCxLQUFLO0FBQUEsUUFDSCxPQUFPLFFBQVEsa0NBQVcsS0FBSztBQUFBLFFBQy9CLFVBQVU7QUFBQSxRQUNWLE1BQU07QUFBQSxRQUNOO0FBQUEsTUFDRjtBQUFBLE1BQ0EsZUFBZTtBQUFBO0FBQUEsUUFFYixVQUFVLENBQUMsT0FBTztBQUFBLFFBQ2xCLFFBQVE7QUFBQSxVQUNOLFNBQVM7QUFBQSxVQUNULFNBQVM7QUFBQSxZQUNQLE9BQU87QUFBQSxVQUNUO0FBQUEsVUFDQSxnQkFBZ0IsTUFBTTtBQUNwQixtQkFBTyxVQUFVLE1BQU0sT0FBTyxLQUFLO0FBQUEsVUFDckM7QUFBQSxRQUNGO0FBQUEsTUFDRjtBQUFBLElBQ0Y7QUFBQSxJQUNBLE1BQU07QUFBQSxNQUNKLFFBQVE7QUFBQSxNQUNSLGFBQWE7QUFBQSxNQUNiLFlBQVk7QUFBQSxJQUNkO0FBQUEsRUFDRjtBQUNGLENBQUM7IiwKICAibmFtZXMiOiBbXQp9Cg== diff --git a/packages/react/src/index.ts b/packages/react/src/index.ts index 80214ade0..97ee3fcfa 100644 --- a/packages/react/src/index.ts +++ b/packages/react/src/index.ts @@ -43,7 +43,6 @@ export { Card, CardView, KnockGuideProvider, - GuideToolbar as KnockGuideToolbar, Modal, ModalView, } from "./modules/guide"; diff --git a/packages/react/src/modules/guide/components/Toolbar/KnockButton.tsx b/packages/react/src/modules/guide/components/Toolbar/KnockButton.tsx new file mode 100644 index 000000000..e83066696 --- /dev/null +++ b/packages/react/src/modules/guide/components/Toolbar/KnockButton.tsx @@ -0,0 +1,51 @@ +import { Button } from "@telegraph/button"; + +import { MAX_Z_INDEX } from "./shared"; +import "./styles.css"; + +type Props = { + onClick: () => void; +}; + +export const KnockButton = ({ onClick }: Props) => { + return ( + + ); +}; diff --git a/packages/react/src/modules/guide/components/Toolbar/V1/V1.tsx b/packages/react/src/modules/guide/components/Toolbar/V1/V1.tsx new file mode 100644 index 000000000..c8f3e3f6c --- /dev/null +++ b/packages/react/src/modules/guide/components/Toolbar/V1/V1.tsx @@ -0,0 +1,93 @@ +import { useGuideContext, useStore } from "@knocklabs/react-core"; +import { Button } from "@telegraph/button"; +import { Stack } from "@telegraph/layout"; +import { Tag } from "@telegraph/tag"; +import { Text } from "@telegraph/typography"; +import { Minimize2, Undo2, Wrench } from "lucide-react"; +import { useState } from "react"; + +import { KnockButton } from "../KnockButton"; +import { MAX_Z_INDEX } from "../shared"; +import "../styles.css"; + +export const V1 = () => { + const [isCollapsed, setIsCollapsed] = useState(false); + + const { client } = useGuideContext(); + const debugState = useStore(client.store, (state) => state.debug); + + if (!debugState?.forcedGuideKey) { + return null; + } + + const handleExit = () => { + client.exitDebugMode(); + }; + + const handleToggleCollapse = () => { + setIsCollapsed(!isCollapsed); + }; + + if (isCollapsed) { + return ; + } + + return ( + + + + Debug + + + + {debugState.forcedGuideKey} + + + + + + - ); - } - - return ( - - - - Debug - - - - {debugState.forcedGuideKey} - - - - -