@coxwave/tap-kit 4.5.0 → 4.8.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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/react/types.ts","../src/react/TapKit.tsx","../src/loader.ts","../src/react/useTapKit.ts"],"names":["TapKit","script","useRef","useEffect","useCallback"],"mappings":"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","file":"react.mjs","sourcesContent":["/**\n * React-specific type definitions for TapKit\n *\n * Defines event handler types and control patterns for React integration.\n */\n\nimport type { AlarmMessageInstanceType, TapKitElement } from \"@coxwave/tap-kit-types\";\n\n/**\n * Video player adapter interface for timeline synchronization\n *\n * Supports custom video players (YouTube, Vimeo, etc.) that don't use HTMLVideoElement.\n */\nexport interface VideoAdapter {\n /** Get current playback time in seconds */\n getCurrentTime: () => number;\n /** Set playback time in seconds */\n setCurrentTime: (time: number, clipId?: string) => void;\n}\n\n/**\n * Event handler type definitions for TapKit Web Component\n *\n * Maps CustomEvent types to React callback signatures.\n */\nexport interface TapKitEventHandlers {\n /**\n * Called when TapKit SDK is ready\n * @example onReady={() => console.log('TapKit ready!')}\n */\n onReady?: () => void;\n\n /**\n * Called when initialization or runtime error occurs\n * @example onError={(error) => console.error('TapKit error:', error)}\n */\n onError?: (error: Error) => void;\n\n /**\n * Called when timeline seek event occurs\n * @example onTimelineSeek={(clipPlayHead, clipId) => console.log('Seek:', clipPlayHead)}\n */\n onTimelineSeek?: (clipPlayHead: number, clipId: string) => void;\n\n /**\n * Called when alarm fade-in occurs\n * @example onAlarmFadeIn={(messageInfo) => console.log('Alarm:', messageInfo)}\n */\n onAlarmFadeIn?: (messageInfo: AlarmMessageInstanceType) => void;\n\n /**\n * 학습자가 취약점 진단의 근거 문항을 눌렀을 때 (EXAM 모드, 디지틀조선 TOEFL 첨삭).\n * 호스트 시험 플레이어를 `clipId`(= 채점 API의 `problem_id`) 문항으로 옮기면 된다.\n * @example onExamQuestionNavigate={(clipId) => goToQuestion(clipId)}\n */\n onExamQuestionNavigate?: (clipId: string, questionNo?: number) => void;\n}\n\n/**\n * Control object pattern for managing TapKit instance\n *\n * Separates instance management (setInstance) from configuration (options)\n * and event handling (handlers). Inspired by ChatKit's control pattern.\n *\n * @example\n * ```tsx\n * const tapkit = useTapKit({ apiKey: 'key', onReady: () => {} });\n * <TapKit control={tapkit.control} />\n * ```\n */\nexport interface TapKitControl<T> {\n /**\n * Set the TapKit element instance reference\n *\n * Called by TapKit component to register the element instance.\n * Enables imperative control via useTapKit methods.\n */\n setInstance: (instance: TapKitElement | null) => void;\n\n /**\n * Configuration options (non-function values)\n *\n * All options except event handlers.\n */\n options: T;\n\n /**\n * Event handler callbacks (function values)\n *\n * Separated from options for easier event listener management.\n */\n handlers: TapKitEventHandlers;\n\n /**\n * Whether CDN is loaded and Web Component is available\n *\n * @internal Used by TapKit component to delay rendering\n */\n isCdnLoaded: boolean;\n}\n\n/**\n * Map of TapKit event names to their handler keys\n *\n * Used for automatic event listener binding in TapKit component.\n *\n * @internal\n */\nexport const EVENT_HANDLER_MAP = {\n \"tap-kit:ready\": \"onReady\",\n \"tap-kit:error\": \"onError\",\n} as const;\n\n/**\n * List of TapKit event names\n *\n * @internal\n */\nexport const EVENT_NAMES = Object.keys(EVENT_HANDLER_MAP) as (keyof typeof EVENT_HANDLER_MAP)[];\n","/**\n * TapKit React Component\n *\n * Declarative React wrapper for <tap-kit> Web Component.\n * Use this with useTapKit hook for a clean separation of control and rendering.\n *\n * @example\n * ```tsx\n * 'use client';\n *\n * import { TapKit, useTapKit } from '@coxwave/tap-kit/react';\n *\n * function MyApp() {\n * const tapkit = useTapKit({\n * apiKey: 'your-key',\n * userId: 'user-123',\n * courseId: 'course-456',\n * clipId: 'clip-789',\n * onReady: () => console.log('TapKit ready!'),\n * onError: (error) => console.error('Error:', error),\n * });\n *\n * return (\n * <div>\n * <button onClick={tapkit.show} disabled={!tapkit.isReady}>\n * Show Chat\n * </button>\n * <TapKit control={tapkit.control} style={{ height: '600px' }} />\n * </div>\n * );\n * }\n * ```\n *\n * **Note for Next.js App Router users:**\n * Make sure to add 'use client' at the top of your component file.\n *\n * @see https://edutap-ai-docs.vercel.app/docs/guides/react\n */\n\nimport type { TapKitElement } from \"@coxwave/tap-kit-types\";\nimport React, { useCallback, useEffect, useImperativeHandle, useRef } from \"react\";\nimport type { TapKitControl } from \"./types\";\nimport { EVENT_HANDLER_MAP, EVENT_NAMES } from \"./types\";\nimport type { TapKitOptions } from \"./useTapKit\";\n\n/**\n * Props for TapKit React component\n */\nexport interface TapKitProps extends Omit<React.HTMLAttributes<TapKitElement>, \"children\" | \"dangerouslySetInnerHTML\"> {\n /**\n * Control object from useTapKit hook\n *\n * Provides instance management, configuration, and event handlers.\n */\n control: TapKitControl<TapKitOptions>;\n}\n\n// Note: JSX IntrinsicElements augmentation is provided by @coxwave/tap-kit-types\n// See: packages/tap-kit-types/src/tap-kit.d.ts\n\n/**\n * TapKit React Component\n *\n * Renders <tap-kit> Web Component with React integration.\n * Automatically manages instance lifecycle and event listeners.\n *\n * **Ref Access**: The forwarded ref provides direct access to the TapKitElement:\n * ```tsx\n * const tapkitRef = useRef<TapKitElement>(null);\n * <TapKit ref={tapkitRef} control={...} />\n * // tapkitRef.current?.show()\n * ```\n */\nexport const TapKit = React.forwardRef<TapKitElement, TapKitProps>(function TapKit({ control, ...htmlProps }, forwardedRef) {\n const elementRef = useRef<TapKitElement | null>(null);\n\n // Forward TapKitElement to parent\n useImperativeHandle(forwardedRef, () => elementRef.current as TapKitElement, []);\n\n // Callback ref to register element when mounted\n const setElementRef = useCallback(\n (element: TapKitElement | null) => {\n elementRef.current = element;\n\n if (element) {\n // Set apiKey as property (not attribute) - required for LitElement\n // apiKey has { attribute: false } so it won't work via HTML attribute\n if (control.options.apiKey) {\n element.apiKey = control.options.apiKey;\n }\n\n // Set videoTarget as property (not attribute) - object type\n // videoTarget has { attribute: false } for lifecycle-safe video binding\n if (control.options.videoTarget) {\n element.videoTarget = control.options.videoTarget;\n }\n\n // Set userInputCodeTarget as property (not attribute) - object type\n // Same pattern as videoTarget: declarative adapter for host code editor sync\n if (control.options.userInputCodeTarget) {\n element.userInputCodeTarget = control.options.userInputCodeTarget;\n }\n\n // Set rowDataForCodeEditor as property (not attribute) - object type\n // Auto-extracted 5 fields are attached to chat stream requests\n if (control.options.rowDataForCodeEditor) {\n element.rowDataForCodeEditor = control.options.rowDataForCodeEditor;\n }\n\n // Set allowLayoutToggle as property (not attribute) - Boolean type\n // HTML boolean attributes treat any string value (including \"false\") as true\n // Must be set via property to correctly handle false values\n if (control.options.allowLayoutToggle !== undefined) {\n element.allowLayoutToggle = control.options.allowLayoutToggle;\n }\n\n // Set grading as property (not attribute) - SPEAK contains a File\n // Delivered to iframe via dedicated grading:setup message\n if (control.options.grading) {\n element.grading = control.options.grading;\n }\n\n // Note: root is NOT set here - declarative API uses auto-detected parent\n // The element will detect declarative mode in connectedCallback\n }\n\n control.setInstance(element);\n },\n [\n control.setInstance,\n control.options.apiKey,\n control.options.videoTarget,\n control.options.userInputCodeTarget,\n control.options.rowDataForCodeEditor,\n control.options.allowLayoutToggle,\n control.options.grading,\n ]\n );\n\n // Store handlers in ref to avoid effect re-runs on handler reference changes\n // Handlers are stable via useMemo in useTapKit, but use ref for extra safety\n const handlersRef = useRef(control.handlers);\n handlersRef.current = control.handlers;\n\n // Register event listeners (only once per element mount)\n useEffect(() => {\n const element = elementRef.current;\n if (!element) return;\n\n const listeners: Array<{\n event: string;\n handler: EventListener;\n }> = [];\n\n // Bind CustomEvent listeners (tap-kit:ready, tap-kit:error)\n for (const eventName of EVENT_NAMES) {\n const handlerKey = EVENT_HANDLER_MAP[eventName as keyof typeof EVENT_HANDLER_MAP];\n\n // Use closure over handlersRef to always get latest handler\n const listener = (e: Event) => {\n const handler = handlersRef.current[handlerKey];\n if (!handler) return;\n\n const customEvent = e as CustomEvent;\n if (handlerKey === \"onError\" && customEvent.detail?.error) {\n // onError receives error directly\n // biome-ignore lint/suspicious/noExplicitAny: Handler type is validated at runtime\n (handler as any)(customEvent.detail.error);\n } else if (handlerKey === \"onReady\") {\n // onReady receives no arguments\n // biome-ignore lint/suspicious/noExplicitAny: Handler type is validated at runtime\n (handler as any)();\n }\n };\n\n element.addEventListener(eventName, listener);\n listeners.push({ event: eventName, handler: listener });\n }\n\n return () => {\n // Cleanup all event listeners\n for (const { event, handler } of listeners) {\n element.removeEventListener(event, handler);\n }\n };\n }, []); // Empty deps - listeners use ref for handlers\n\n // Sync videoTarget property when it changes\n // (property-only, not attribute - must be set imperatively)\n useEffect(() => {\n const element = elementRef.current;\n if (!element) return;\n\n element.videoTarget = control.options.videoTarget;\n }, [control.options.videoTarget]);\n\n // Sync userInputCodeTarget property when it changes\n // (property-only, not attribute - must be set imperatively)\n useEffect(() => {\n const element = elementRef.current;\n if (!element) return;\n\n element.userInputCodeTarget = control.options.userInputCodeTarget;\n }, [control.options.userInputCodeTarget]);\n\n // Sync rowDataForCodeEditor property when it changes\n // (property-only, not attribute - must be set imperatively)\n useEffect(() => {\n const element = elementRef.current;\n if (!element) return;\n\n element.rowDataForCodeEditor = control.options.rowDataForCodeEditor;\n }, [control.options.rowDataForCodeEditor]);\n\n // Sync allowLayoutToggle property when it changes\n // (Boolean attributes don't work correctly with \"false\" string)\n useEffect(() => {\n const element = elementRef.current;\n if (!element || control.options.allowLayoutToggle === undefined) return;\n\n element.allowLayoutToggle = control.options.allowLayoutToggle;\n }, [control.options.allowLayoutToggle]);\n\n // Sync grading property when it changes\n // (property-only, SPEAK contains a File - must be set imperatively)\n useEffect(() => {\n const element = elementRef.current;\n if (!element || !control.options.grading) return;\n\n element.grading = control.options.grading;\n }, [control.options.grading]);\n\n // Note: root sync removed - declarative API uses auto-detected parent\n // The element stays in its declared position\n\n const { options, isCdnLoaded } = control;\n\n // Wait for CDN to load before rendering Web Component\n // Without this, <tap-kit> is just an HTMLUnknownElement without methods\n if (!isCdnLoaded) {\n return null;\n }\n\n // Render <tap-kit> Web Component directly\n // Note: apiKey, videoTarget, allowLayoutToggle are set via ref callback (property-only)\n return (\n <tap-kit\n ref={setElementRef}\n user-id={options.userId}\n course-id={options.courseId}\n clip-id={options.clipId}\n section-id={options.sectionId}\n clip-play-head={options.clipPlayHead}\n external-reference-id={options.externalReferenceId}\n user-input-code={options.userInputCode}\n language={options.language}\n button-id={options.buttonId}\n mode={options.mode}\n chat-mode={options.chatMode}\n debug={options.debug}\n tap-url={options.tapUrl}\n api-url={options.apiUrl}\n environment={options.environment}\n {...htmlProps}\n />\n );\n});\n","/**\n * CDN loader for TapKit\n * Dynamically loads the TapKit SDK from CDN\n *\n * For local testing, you can override the loader URL:\n * window.__TAP_KIT_LOADER_URL__ = '/tap-kit-core/loader.js';\n *\n * For local development (bypass loader, load IIFE directly):\n * window.__TAP_KIT_CORE_URL__ = '/packages/tap-kit-core/dist/index.global.js';\n */\n\n// Build-time constant injected by tsup define\ndeclare const __DEFAULT_CDN_LOADER_URL__: string;\n\nconst DEFAULT_CDN_LOADER_URL =\n typeof __DEFAULT_CDN_LOADER_URL__ !== \"undefined\" ? __DEFAULT_CDN_LOADER_URL__ : \"https://files.edutap.ai/tap-sdk/loader.js\";\nconst DEFAULT_TIMEOUT_MS = 4000; // 4 seconds total timeout\nconst IDLE_CALLBACK_TIMEOUT_MS = 500; // 500ms for requestIdleCallback\n\n/**\n * Get the loader URL from window override or default CDN\n */\nfunction getLoaderURL(): string {\n return window?.__TAP_KIT_LOADER_URL__ ? window.__TAP_KIT_LOADER_URL__ : DEFAULT_CDN_LOADER_URL;\n}\n\n/**\n * Check if local core mode is enabled\n * When __TAP_KIT_CORE_URL__ is set, directly load the IIFE bundle\n * This bypasses the loader.js and loads tap-kit-core directly\n */\nfunction isLocalCoreMode(): boolean {\n return typeof window !== \"undefined\" && !!window.__TAP_KIT_CORE_URL__;\n}\n\n/**\n * Get the local core URL\n */\nfunction getLocalCoreURL(): string {\n return window.__TAP_KIT_CORE_URL__ || \"\";\n}\n\n/**\n * Creates a SDK checker function with timeout and retry logic\n * Uses requestIdleCallback to avoid blocking browser rendering\n * @param resolve - Promise resolve function\n * @param reject - Promise reject function\n * @param timeoutMs - Maximum time to wait for SDK to load (milliseconds)\n * @returns Checker function to be called repeatedly\n */\nfunction createSDKChecker(\n resolve: (value: void | PromiseLike<void>) => void,\n reject: (reason?: unknown) => void,\n timeoutMs: number\n): () => void {\n const startTime = Date.now();\n\n const checkSDK = (): void => {\n // Check if real TapKit is loaded (not just stub)\n // Stub has TapKitLoaded flag set to true by loader.js after real SDK loads\n if (window.TapKit && window.TapKitLoaded === true) {\n window.__TAP_KIT_LOADER_LOADED__ = true;\n window.__TAP_KIT_LOADER_LOADING__ = undefined;\n resolve();\n return;\n }\n\n const elapsed = Date.now() - startTime;\n\n // Check if exceeded timeout\n if (elapsed > timeoutMs) {\n window.__TAP_KIT_LOADER_LOADING__ = undefined;\n reject(new Error(`TapKit loader timeout: SDK not available after ${timeoutMs}ms`));\n return;\n }\n\n // Use requestIdleCallback for better performance\n // Falls back to setTimeout if not available\n if (typeof requestIdleCallback !== \"undefined\") {\n requestIdleCallback(checkSDK, { timeout: IDLE_CALLBACK_TIMEOUT_MS });\n } else {\n setTimeout(checkSDK, IDLE_CALLBACK_TIMEOUT_MS);\n }\n };\n\n return checkSDK;\n}\n\n/**\n * Loads the CDN loader script\n * The loader will then fetch versions.json and load the appropriate SDK version\n *\n * If __TAP_KIT_CORE_URL__ is set, bypasses loader and loads IIFE directly\n *\n * @param timeoutMs - Maximum time to wait for SDK to load (default: 4000ms)\n * @returns Promise that resolves when SDK is loaded\n * @throws {Error} If loader fails to load or times out\n */\nexport function loadCDNLoader(timeoutMs: number = DEFAULT_TIMEOUT_MS): Promise<void> {\n // If already loaded, return immediately\n if (window.__TAP_KIT_LOADER_LOADED__ && window.TapKit) {\n return Promise.resolve();\n }\n\n // If currently loading, return the existing promise\n if (window.__TAP_KIT_LOADER_LOADING__) {\n return window.__TAP_KIT_LOADER_LOADING__;\n }\n\n // Create loading promise\n const loadingPromise = new Promise<void>((resolve, reject) => {\n if (typeof document === \"undefined\") {\n reject(new Error(\"TapKit requires browser environment (document is undefined)\"));\n return;\n }\n\n // Local core mode: Load IIFE directly\n if (isLocalCoreMode()) {\n // Check if TapKit is already loaded (from other pages in playground)\n if (window.TapKit && window.TapKitLoaded === true) {\n window.__TAP_KIT_LOADER_LOADED__ = true;\n window.__TAP_KIT_LOADER_LOADING__ = undefined;\n resolve();\n return;\n }\n\n const coreURL = getLocalCoreURL();\n\n const script = document.createElement(\"script\");\n script.src = coreURL;\n script.async = true;\n\n script.onload = () => {\n // IIFE directly sets window.TapKit\n // Set the loaded flag manually since we bypass loader.js\n if (window.TapKit) {\n window.TapKitLoaded = true;\n window.__TAP_KIT_LOADER_LOADED__ = true;\n window.__TAP_KIT_LOADER_LOADING__ = undefined;\n resolve();\n } else {\n window.__TAP_KIT_LOADER_LOADING__ = undefined;\n reject(new Error(\"TapKit not available after loading local core\"));\n }\n };\n\n script.onerror = () => {\n window.__TAP_KIT_LOADER_LOADING__ = undefined;\n reject(new Error(`Failed to load local TapKit core: ${coreURL}`));\n };\n\n document.head.appendChild(script);\n return;\n }\n\n // CDN mode: Load loader.js\n const loaderURL = getLoaderURL();\n const script = document.createElement(\"script\");\n script.src = loaderURL;\n script.async = true;\n\n script.onload = () => {\n // The loader script will load the actual SDK\n // We need to wait a bit for the loader to fetch and load the SDK\n const checkSDK = createSDKChecker(resolve, reject, timeoutMs);\n checkSDK();\n };\n\n script.onerror = () => {\n window.__TAP_KIT_LOADER_LOADING__ = undefined;\n reject(new Error(`Failed to load TapKit CDN loader: ${loaderURL}`));\n };\n\n // Check if script already exists\n const existingScript = document.querySelector(`script[src=\"${loaderURL}\"]`);\n\n if (existingScript) {\n // Script already added but not yet loaded\n existingScript.addEventListener(\"load\", () => {\n const checkSDK = createSDKChecker(resolve, reject, timeoutMs);\n checkSDK();\n });\n existingScript.addEventListener(\"error\", () => reject(new Error(`Failed to load TapKit CDN loader: ${loaderURL}`)));\n } else {\n document.head.appendChild(script);\n }\n });\n\n window.__TAP_KIT_LOADER_LOADING__ = loadingPromise;\n return loadingPromise;\n}\n","/**\n * useTapKit Hook - ChatKit-style control for TapKit Web Component\n *\n * This hook provides a control object to manage TapKit through the\n * <TapKit /> component. Inspired by OpenAI's ChatKit pattern.\n *\n * @example\n * ```tsx\n * 'use client';\n *\n * import { TapKit, useTapKit } from '@coxwave/tap-kit/react';\n *\n * function MyApp() {\n * const tapkit = useTapKit({\n * apiKey: 'your-key',\n * userId: 'user-123',\n * courseId: 'course-456',\n * clipId: 'clip-789',\n * onReady: () => console.log('Ready!'),\n * onError: (error) => console.error(error),\n * });\n *\n * return (\n * <div>\n * <button onClick={tapkit.show} disabled={!tapkit.isReady}>\n * Ask AI Tutor\n * </button>\n * <TapKit control={tapkit.control} />\n * </div>\n * );\n * }\n * ```\n */\n\nimport type {\n ChatMode,\n CodingRowDataInput,\n GradingOption,\n TapKitElement,\n UserInputCodeAdapter,\n VideoPlayerConfig,\n} from \"@coxwave/tap-kit-types\";\nimport { normalizeCodingRowData } from \"@coxwave/tap-kit-types\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { loadCDNLoader } from \"../loader\";\nimport type { TapKitControl, TapKitEventHandlers, VideoAdapter } from \"./types\";\n\nexport interface UseTapKitOptions extends TapKitEventHandlers {\n /** API Key (required) */\n apiKey: string;\n /** User ID */\n userId?: string;\n /** Course ID */\n courseId?: string;\n /** Clip ID */\n clipId?: string;\n /** Section ID (course 내 섹션 식별자) */\n sectionId?: string;\n /** Clip playhead position */\n clipPlayHead?: number;\n /** External reference ID (외부 시스템에서 부여한 참조 식별자) */\n externalReferenceId?: string;\n /** External reference data (외부 시스템에서 부여한 참조 데이터) */\n userInputCode?: string;\n /**\n * Raw coding exercise metadata from host LMS/platform.\n *\n * 5 required string fields are auto-extracted and attached to chat stream\n * requests as `coding_language`, `coding_testcase`, `coding_content`,\n * `coding_example`, `coding_restriction`. Additional fields on the object\n * are ignored.\n *\n * If provided, all 5 fields must be non-empty strings — otherwise the hook\n * throws on render (treated as init failure).\n *\n * **Tip**: Wrap in `useMemo` to keep object reference stable across renders.\n *\n * @example\n * ```tsx\n * const rowData = useMemo(() => ({\n * language_id_nm: \"C++ (GCC 9.2.0)\",\n * d_test_case: \"<p>...</p>\",\n * content: \"...\",\n * io_example: \"...\",\n * restriction: \"...\",\n * }), []);\n *\n * const tapkit = useTapKit({ apiKey, userId, courseId, rowDataForCodeEditor: rowData });\n * ```\n */\n rowDataForCodeEditor?: CodingRowDataInput;\n /** Language */\n language?: \"ko\" | \"en\" | \"ja\";\n /** Custom button element ID */\n buttonId?: string;\n /** Display mode */\n mode?: \"inline\" | \"floating\" | \"sidebar\";\n /** Chat interaction mode (staging feature: per-message override) */\n chatMode?: ChatMode;\n /**\n * Allow user to toggle between floating and sidebar layouts\n * Only applies when mode is \"floating\" or \"sidebar\"\n * @default true\n */\n allowLayoutToggle?: boolean;\n /**\n * Video player target for timeline synchronization (recommended)\n *\n * Supports HTMLVideoElement or VideoPlayerAdapter.\n * Survives lifecycle changes (mode change, reconnect).\n *\n * @example\n * ```tsx\n * // HTMLVideoElement\n * const tapkit = useTapKit({ videoTarget: videoRef.current, ... });\n *\n * // VideoPlayerAdapter\n * const tapkit = useTapKit({\n * videoTarget: {\n * getCurrentTime: () => player.currentTime,\n * setCurrentTime: (t) => player.currentTime = t\n * },\n * ...\n * });\n * ```\n */\n videoTarget?: VideoPlayerConfig;\n /**\n * User input code adapter for bidirectional sync with a host code editor.\n *\n * 호스트 페이지의 코드 에디터(Monaco, CodeMirror, iframe IDE 등)와 SDK를\n * 양방향 동기화하는 어댑터. videoTarget과 동일한 패턴.\n *\n * - SDK가 폴링 주기로 `getCode()` 호출 → 채팅 컨텍스트에 최신 코드 반영\n * - 채팅의 \"에디터에 적용\" 모달 → SDK가 `setCode(code)` 호출 (Optional)\n *\n * @example\n * ```tsx\n * const tapkit = useTapKit({\n * userInputCodeTarget: {\n * getCode: () => monacoEditor.getValue(),\n * setCode: (code) => monacoEditor.setValue(code),\n * },\n * ...\n * });\n * ```\n */\n userInputCodeTarget?: UserInputCodeAdapter;\n /**\n * Grading session — single grading problem (Speaking 또는 Writing).\n *\n * 호스트가 SDK에 넘기는 채점 셋업. `gradeType`으로 판별한다. config:update가 아닌\n * 전용 `grading:setup` 메시지로 iframe에 전달된다. SPEAK은 edutap이 음성 파일을\n * 업로드한 뒤 홈에서 프리셋 질문 버튼을 노출하고, WRITE는 학습자가 채팅 입력창에\n * 답안을 작성한다. (SPEAK은) File을 포함하므로 객체 참조가 바뀔 때마다 재전송된다\n * — 안정적인 참조를 위해 `useMemo`로 감싸는 것을 권장.\n *\n * @example\n * ```tsx\n * // Speaking\n * const grading = useMemo(() => ({\n * gradeType: \"SPEAK\" as const,\n * audioFile,\n * problemText: \"Describe your hometown\",\n * problemType: \"INTERVIEW\" as const,\n * referenceAnswer: \"...\",\n * hint: \"장소 묘사\",\n * }), [audioFile]);\n *\n * // Writing (음성 없음, 학습자가 채팅 입력창에 답안 작성)\n * const grading = { gradeType: \"WRITE\" as const, problemText, problemType: \"MSOM\" as const };\n *\n * const tapkit = useTapKit({ apiKey, userId, courseId, grading });\n * ```\n */\n grading?: GradingOption;\n /** Debug mode */\n debug?: boolean;\n /** TAP Frontend URL */\n tapUrl?: string;\n /** API Backend URL */\n apiUrl?: string;\n /** Environment */\n environment?: \"dev\" | \"prod\" | \"staging\";\n // Note: `root` option removed - declarative API (<TapKit />) stays in declared position\n // For imperative control over position, use createTapKit() with root option\n}\n\n/**\n * Configuration options type (non-function values)\n */\nexport type TapKitOptions = Omit<UseTapKitOptions, keyof TapKitEventHandlers>;\n\n/**\n * Extract event handlers from options (pure function)\n */\nfunction extractHandlers(options: UseTapKitOptions): TapKitEventHandlers {\n return {\n onReady: options.onReady,\n onError: options.onError,\n onTimelineSeek: options.onTimelineSeek,\n onAlarmFadeIn: options.onAlarmFadeIn,\n onExamQuestionNavigate: options.onExamQuestionNavigate,\n };\n}\n\nexport interface UseTapKitReturn {\n /** Control object for <TapKit /> component */\n control: TapKitControl<TapKitOptions>;\n /** Whether TapKit is ready */\n isReady: boolean;\n /** Error during initialization */\n error: Error | null;\n /** Show chat interface */\n show: () => void;\n /** Hide chat interface */\n hide: () => void;\n /** Set course information */\n setCourse: (course: { courseId: string; clipId?: string; userId?: string; clipPlayHead?: number }) => void;\n /** Update external reference ID at runtime (pass undefined to clear) */\n setExternalReferenceId: (id?: string) => void;\n /** Update external reference data at runtime (pass undefined to clear) */\n setExternalReferenceData: (data?: string) => void;\n /** Send contextual data from host to iframe (AI tutor) */\n sendContext: (contextType: string, payload: Record<string, unknown>) => void;\n /**\n * Video adapter control\n *\n * @deprecated Use `videoTarget` option in useTapKit instead for declarative binding.\n *\n * ```tsx\n * // ✅ Recommended (declarative)\n * const tapkit = useTapKit({ videoTarget: adapter, ... });\n *\n * // ❌ Deprecated (imperative)\n * tapkit.video.bind(adapter);\n * ```\n */\n video: {\n bind: (adapter: VideoAdapter, clipId?: string) => void;\n unbind: () => void;\n };\n}\n\n/**\n * Hook for managing TapKit Web Component (ChatKit Pattern)\n *\n * Returns a control object to pass to <TapKit /> component.\n * The component handles rendering, this hook handles state and methods.\n */\nexport function useTapKit(options: UseTapKitOptions): UseTapKitReturn {\n // Normalize rowDataForCodeEditor — accepts both `CodingRowData` and JSON string.\n // Throws synchronously on render if partial/invalid so the caller's React error\n // boundary catches config errors before the SDK is initialized.\n const normalizedRowData = useMemo(\n () => (options.rowDataForCodeEditor === undefined ? undefined : normalizeCodingRowData(options.rowDataForCodeEditor)),\n [options.rowDataForCodeEditor]\n );\n\n // Element ref - set by <TapKit /> component via control.setInstance\n const elementRef = useRef<TapKitElement | null>(null);\n\n // Pending video bind request (queued until ready)\n const pendingVideoBind = useRef<{\n adapter: VideoAdapter;\n clipId?: string;\n } | null>(null);\n\n // State\n const [isCdnLoaded, setIsCdnLoaded] = useState(false);\n const [isReady, setIsReady] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n // Store handlers in refs to avoid stale closures\n const handlersRef = useRef(extractHandlers(options));\n handlersRef.current = extractHandlers(options);\n\n // Load CDN on mount (defines <tap-kit> Web Component)\n useEffect(() => {\n loadCDNLoader()\n .then(() => {\n setIsCdnLoaded(true);\n })\n .catch((err) => {\n const loadError = err instanceof Error ? err : new Error(\"Failed to load TapKit CDN\");\n setError(loadError);\n handlersRef.current.onError?.(loadError);\n });\n }, []);\n\n // Set instance callback - called by <TapKit /> component\n const setInstance = useCallback((instance: TapKitElement | null) => {\n elementRef.current = instance;\n\n if (!instance) {\n setIsReady(false);\n return;\n }\n\n // Listen for ready event\n const handleReady = () => {\n setIsReady(true);\n handlersRef.current.onReady?.();\n };\n\n const handleError = (e: Event) => {\n const customEvent = e as CustomEvent<{ error: Error }>;\n const err = customEvent.detail?.error ?? new Error(\"Unknown error\");\n setError(err);\n handlersRef.current.onError?.(err);\n };\n\n instance.addEventListener(\"tap-kit:ready\", handleReady);\n instance.addEventListener(\"tap-kit:error\", handleError);\n\n // Check if already ready\n if (instance.isInitialized) {\n setIsReady(true);\n }\n\n // Setup EventManager callbacks when ready\n // Use stable wrappers that call handlersRef.current to always get latest handlers\n const setupEventHandlers = () => {\n if (instance.events && typeof instance.events.onTimelineSeek === \"function\") {\n // Register stable wrappers instead of direct refs\n // This ensures handler updates are reflected without re-registration\n instance.events.onTimelineSeek((clipPlayHead, clipId) => {\n handlersRef.current.onTimelineSeek?.(clipPlayHead, clipId);\n });\n instance.events.onAlarmFadeIn((messageInfo) => {\n handlersRef.current.onAlarmFadeIn?.(messageInfo);\n });\n instance.events.onExamQuestionNavigate((clipId, questionNo) => {\n handlersRef.current.onExamQuestionNavigate?.(clipId, questionNo);\n });\n }\n\n // Execute pending video bind if queued\n if (pendingVideoBind.current && instance.video) {\n instance.video.bind(pendingVideoBind.current.adapter, pendingVideoBind.current.clipId);\n pendingVideoBind.current = null;\n }\n };\n\n // Check if ready property exists (may not be available immediately)\n if (instance.ready && typeof instance.ready.then === \"function\") {\n instance.ready.then(setupEventHandlers).catch(() => {\n // Ignore - error already handled by tap-kit:error event\n });\n } else if (instance.isInitialized) {\n // Already initialized, setup handlers immediately\n setupEventHandlers();\n } else {\n // Fallback: wait for ready event then setup handlers\n instance.addEventListener(\"tap-kit:ready\", setupEventHandlers, {\n once: true,\n });\n }\n }, []);\n\n // Memoize config options using individual values to prevent infinite re-renders\n // (options object is recreated on every render, so we must depend on primitives)\n // Note: videoTarget is object reference - changes trigger re-render intentionally\n const configOptions = useMemo(\n () => ({\n apiKey: options.apiKey,\n userId: options.userId,\n courseId: options.courseId,\n clipId: options.clipId,\n sectionId: options.sectionId,\n clipPlayHead: options.clipPlayHead,\n externalReferenceId: options.externalReferenceId,\n userInputCode: options.userInputCode,\n rowDataForCodeEditor: normalizedRowData,\n language: options.language,\n buttonId: options.buttonId,\n mode: options.mode,\n chatMode: options.chatMode,\n allowLayoutToggle: options.allowLayoutToggle,\n videoTarget: options.videoTarget,\n userInputCodeTarget: options.userInputCodeTarget,\n grading: options.grading,\n debug: options.debug,\n tapUrl: options.tapUrl,\n apiUrl: options.apiUrl,\n environment: options.environment,\n // Note: root removed - declarative API stays in declared position\n }),\n [\n options.apiKey,\n options.userId,\n options.courseId,\n options.clipId,\n options.sectionId,\n options.clipPlayHead,\n options.externalReferenceId,\n options.userInputCode,\n normalizedRowData,\n options.language,\n options.buttonId,\n options.mode,\n options.chatMode,\n options.allowLayoutToggle,\n options.videoTarget,\n options.userInputCodeTarget,\n options.grading,\n options.debug,\n options.tapUrl,\n options.apiUrl,\n options.environment,\n ]\n );\n\n // Create stable handlers object for control\n // NOTE: This object is intentionally created once (empty deps) and appears to capture\n // stale values. However, the actual handler invocations in TapKit.tsx use handlersRef.current\n // which always has the latest handlers. This object is just a stable reference marker\n // that tells TapKit.tsx which handlers exist - not the actual handlers to call.\n const handlers = useMemo<TapKitEventHandlers>(\n () => ({\n onReady: handlersRef.current.onReady,\n onError: handlersRef.current.onError,\n onTimelineSeek: handlersRef.current.onTimelineSeek,\n onAlarmFadeIn: handlersRef.current.onAlarmFadeIn,\n onExamQuestionNavigate: handlersRef.current.onExamQuestionNavigate,\n }),\n []\n );\n\n // Create control object\n const control = useMemo<TapKitControl<TapKitOptions>>(\n () => ({\n setInstance,\n options: configOptions,\n handlers,\n isCdnLoaded,\n }),\n [setInstance, configOptions, handlers, isCdnLoaded]\n );\n\n // Methods\n const show = useCallback(() => {\n if (!elementRef.current) {\n console.warn(\"[useTapKit] Cannot show: element not mounted\");\n return;\n }\n elementRef.current.show();\n }, []);\n\n const hide = useCallback(() => {\n if (!elementRef.current) {\n console.warn(\"[useTapKit] Cannot hide: element not mounted\");\n return;\n }\n elementRef.current.hide();\n }, []);\n\n const setCourse = useCallback((course: { courseId: string; clipId?: string; userId?: string; clipPlayHead?: number }) => {\n if (!elementRef.current) {\n console.warn(\"[useTapKit] Cannot setCourse: element not mounted\");\n return;\n }\n elementRef.current.setCourse(course);\n }, []);\n\n const setExternalReferenceId = useCallback((id?: string) => {\n if (!elementRef.current) {\n console.warn(\"[useTapKit] Cannot setExternalReferenceId: element not mounted\");\n return;\n }\n elementRef.current.externalReferenceId = id;\n }, []);\n\n const setExternalReferenceData = useCallback((data?: string) => {\n if (!elementRef.current) {\n console.warn(\"[useTapKit] Cannot setExternalReferenceData: element not mounted\");\n return;\n }\n elementRef.current.userInputCode = data;\n }, []);\n\n const sendContext = useCallback((contextType: string, payload: Record<string, unknown>) => {\n if (!elementRef.current) {\n console.warn(\"[useTapKit] Cannot sendContext: element not mounted\");\n return;\n }\n elementRef.current.sendContext(contextType, payload);\n }, []);\n\n // Video adapter control\n const video = useMemo(\n () => ({\n bind: (adapter: VideoAdapter, clipId?: string) => {\n // If video controller is ready, bind immediately\n if (elementRef.current?.video) {\n elementRef.current.video.bind(adapter, clipId);\n return;\n }\n\n // Queue for later execution when ready\n pendingVideoBind.current = { adapter, clipId };\n },\n unbind: () => {\n // Clear pending request\n pendingVideoBind.current = null;\n elementRef.current?.video?.unbind();\n },\n }),\n []\n );\n\n return {\n control,\n isReady,\n error,\n show,\n hide,\n setCourse,\n setExternalReferenceId,\n setExternalReferenceData,\n sendContext,\n video,\n };\n}\n"]}
1
+ {"version":3,"sources":["../src/react/types.ts","../src/react/TapKit.tsx","../src/loader.ts","../src/react/useTapKit.ts"],"names":["TapKit","script","useRef","useEffect","useCallback"],"mappings":"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","file":"react.mjs","sourcesContent":["/**\n * React-specific type definitions for TapKit\n *\n * Defines event handler types and control patterns for React integration.\n */\n\nimport type { AlarmMessageInstanceType, TapKitElement } from \"@coxwave/tap-kit-types\";\n\n/**\n * Video player adapter interface for timeline synchronization\n *\n * Supports custom video players (YouTube, Vimeo, etc.) that don't use HTMLVideoElement.\n */\nexport interface VideoAdapter {\n /** Get current playback time in seconds */\n getCurrentTime: () => number;\n /** Set playback time in seconds */\n setCurrentTime: (time: number, clipId?: string) => void;\n}\n\n/**\n * Event handler type definitions for TapKit Web Component\n *\n * Maps CustomEvent types to React callback signatures.\n */\nexport interface TapKitEventHandlers {\n /**\n * Called when TapKit SDK is ready\n * @example onReady={() => console.log('TapKit ready!')}\n */\n onReady?: () => void;\n\n /**\n * Called when initialization or runtime error occurs\n * @example onError={(error) => console.error('TapKit error:', error)}\n */\n onError?: (error: Error) => void;\n\n /**\n * Called when timeline seek event occurs\n * @example onTimelineSeek={(clipPlayHead, clipId) => console.log('Seek:', clipPlayHead)}\n */\n onTimelineSeek?: (clipPlayHead: number, clipId: string) => void;\n\n /**\n * Called when alarm fade-in occurs\n * @example onAlarmFadeIn={(messageInfo) => console.log('Alarm:', messageInfo)}\n */\n onAlarmFadeIn?: (messageInfo: AlarmMessageInstanceType) => void;\n\n /**\n * 학습자가 취약점 진단의 근거 문항을 눌렀을 때 (EXAM 모드, 디지틀조선 TOEFL 첨삭).\n * 호스트 시험 플레이어를 `clipId`(= 채점 API의 `problem_id`) 문항으로 옮기면 된다.\n * @example onExamQuestionNavigate={(clipId) => goToQuestion(clipId)}\n */\n onExamQuestionNavigate?: (clipId: string, questionNo?: number) => void;\n}\n\n/**\n * Control object pattern for managing TapKit instance\n *\n * Separates instance management (setInstance) from configuration (options)\n * and event handling (handlers). Inspired by ChatKit's control pattern.\n *\n * @example\n * ```tsx\n * const tapkit = useTapKit({ apiKey: 'key', onReady: () => {} });\n * <TapKit control={tapkit.control} />\n * ```\n */\nexport interface TapKitControl<T> {\n /**\n * Set the TapKit element instance reference\n *\n * Called by TapKit component to register the element instance.\n * Enables imperative control via useTapKit methods.\n */\n setInstance: (instance: TapKitElement | null) => void;\n\n /**\n * Configuration options (non-function values)\n *\n * All options except event handlers.\n */\n options: T;\n\n /**\n * Event handler callbacks (function values)\n *\n * Separated from options for easier event listener management.\n */\n handlers: TapKitEventHandlers;\n\n /**\n * Whether CDN is loaded and Web Component is available\n *\n * @internal Used by TapKit component to delay rendering\n */\n isCdnLoaded: boolean;\n}\n\n/**\n * Map of TapKit event names to their handler keys\n *\n * Used for automatic event listener binding in TapKit component.\n *\n * @internal\n */\nexport const EVENT_HANDLER_MAP = {\n \"tap-kit:ready\": \"onReady\",\n \"tap-kit:error\": \"onError\",\n} as const;\n\n/**\n * List of TapKit event names\n *\n * @internal\n */\nexport const EVENT_NAMES = Object.keys(EVENT_HANDLER_MAP) as (keyof typeof EVENT_HANDLER_MAP)[];\n","/**\n * TapKit React Component\n *\n * Declarative React wrapper for <tap-kit> Web Component.\n * Use this with useTapKit hook for a clean separation of control and rendering.\n *\n * @example\n * ```tsx\n * 'use client';\n *\n * import { TapKit, useTapKit } from '@coxwave/tap-kit/react';\n *\n * function MyApp() {\n * const tapkit = useTapKit({\n * apiKey: 'your-key',\n * userId: 'user-123',\n * courseId: 'course-456',\n * clipId: 'clip-789',\n * onReady: () => console.log('TapKit ready!'),\n * onError: (error) => console.error('Error:', error),\n * });\n *\n * return (\n * <div>\n * <button onClick={tapkit.show} disabled={!tapkit.isReady}>\n * Show Chat\n * </button>\n * <TapKit control={tapkit.control} style={{ height: '600px' }} />\n * </div>\n * );\n * }\n * ```\n *\n * **Note for Next.js App Router users:**\n * Make sure to add 'use client' at the top of your component file.\n *\n * @see https://edutap-ai-docs.vercel.app/docs/guides/react\n */\n\nimport type { TapKitElement } from \"@coxwave/tap-kit-types\";\nimport React, { useCallback, useEffect, useImperativeHandle, useRef } from \"react\";\nimport type { TapKitControl } from \"./types\";\nimport { EVENT_HANDLER_MAP, EVENT_NAMES } from \"./types\";\nimport type { TapKitOptions } from \"./useTapKit\";\n\n/**\n * Props for TapKit React component\n */\nexport interface TapKitProps extends Omit<React.HTMLAttributes<TapKitElement>, \"children\" | \"dangerouslySetInnerHTML\"> {\n /**\n * Control object from useTapKit hook\n *\n * Provides instance management, configuration, and event handlers.\n */\n control: TapKitControl<TapKitOptions>;\n}\n\n// Note: JSX IntrinsicElements augmentation is provided by @coxwave/tap-kit-types\n// See: packages/tap-kit-types/src/tap-kit.d.ts\n\n/**\n * TapKit React Component\n *\n * Renders <tap-kit> Web Component with React integration.\n * Automatically manages instance lifecycle and event listeners.\n *\n * **Ref Access**: The forwarded ref provides direct access to the TapKitElement:\n * ```tsx\n * const tapkitRef = useRef<TapKitElement>(null);\n * <TapKit ref={tapkitRef} control={...} />\n * // tapkitRef.current?.show()\n * ```\n */\nexport const TapKit = React.forwardRef<TapKitElement, TapKitProps>(function TapKit({ control, ...htmlProps }, forwardedRef) {\n const elementRef = useRef<TapKitElement | null>(null);\n\n // Forward TapKitElement to parent\n useImperativeHandle(forwardedRef, () => elementRef.current as TapKitElement, []);\n\n // Callback ref to register element when mounted\n const setElementRef = useCallback(\n (element: TapKitElement | null) => {\n elementRef.current = element;\n\n if (element) {\n // Set apiKey as property (not attribute) - required for LitElement\n // apiKey has { attribute: false } so it won't work via HTML attribute\n if (control.options.apiKey) {\n element.apiKey = control.options.apiKey;\n }\n\n // Set videoTarget as property (not attribute) - object type\n // videoTarget has { attribute: false } for lifecycle-safe video binding\n if (control.options.videoTarget) {\n element.videoTarget = control.options.videoTarget;\n }\n\n // Set userInputCodeTarget as property (not attribute) - object type\n // Same pattern as videoTarget: declarative adapter for host code editor sync\n if (control.options.userInputCodeTarget) {\n element.userInputCodeTarget = control.options.userInputCodeTarget;\n }\n\n // Set rowDataForCodeEditor as property (not attribute) - object type\n // Auto-extracted 5 fields are attached to chat stream requests\n if (control.options.rowDataForCodeEditor) {\n element.rowDataForCodeEditor = control.options.rowDataForCodeEditor;\n }\n\n // Set allowLayoutToggle as property (not attribute) - Boolean type\n // HTML boolean attributes treat any string value (including \"false\") as true\n // Must be set via property to correctly handle false values\n if (control.options.allowLayoutToggle !== undefined) {\n element.allowLayoutToggle = control.options.allowLayoutToggle;\n }\n\n // Set grading as property (not attribute) - SPEAK contains a File\n // Delivered to iframe via dedicated grading:setup message\n if (control.options.grading) {\n element.grading = control.options.grading;\n }\n\n // Note: root is NOT set here - declarative API uses auto-detected parent\n // The element will detect declarative mode in connectedCallback\n }\n\n control.setInstance(element);\n },\n [\n control.setInstance,\n control.options.apiKey,\n control.options.videoTarget,\n control.options.userInputCodeTarget,\n control.options.rowDataForCodeEditor,\n control.options.allowLayoutToggle,\n control.options.grading,\n ]\n );\n\n // Store handlers in ref to avoid effect re-runs on handler reference changes\n // Handlers are stable via useMemo in useTapKit, but use ref for extra safety\n const handlersRef = useRef(control.handlers);\n handlersRef.current = control.handlers;\n\n // Register event listeners (only once per element mount)\n useEffect(() => {\n const element = elementRef.current;\n if (!element) return;\n\n const listeners: Array<{\n event: string;\n handler: EventListener;\n }> = [];\n\n // Bind CustomEvent listeners (tap-kit:ready, tap-kit:error)\n for (const eventName of EVENT_NAMES) {\n const handlerKey = EVENT_HANDLER_MAP[eventName as keyof typeof EVENT_HANDLER_MAP];\n\n // Use closure over handlersRef to always get latest handler\n const listener = (e: Event) => {\n const handler = handlersRef.current[handlerKey];\n if (!handler) return;\n\n const customEvent = e as CustomEvent;\n if (handlerKey === \"onError\" && customEvent.detail?.error) {\n // onError receives error directly\n // biome-ignore lint/suspicious/noExplicitAny: Handler type is validated at runtime\n (handler as any)(customEvent.detail.error);\n } else if (handlerKey === \"onReady\") {\n // onReady receives no arguments\n // biome-ignore lint/suspicious/noExplicitAny: Handler type is validated at runtime\n (handler as any)();\n }\n };\n\n element.addEventListener(eventName, listener);\n listeners.push({ event: eventName, handler: listener });\n }\n\n return () => {\n // Cleanup all event listeners\n for (const { event, handler } of listeners) {\n element.removeEventListener(event, handler);\n }\n };\n }, []); // Empty deps - listeners use ref for handlers\n\n // Sync videoTarget property when it changes\n // (property-only, not attribute - must be set imperatively)\n useEffect(() => {\n const element = elementRef.current;\n if (!element) return;\n\n element.videoTarget = control.options.videoTarget;\n }, [control.options.videoTarget]);\n\n // Sync userInputCodeTarget property when it changes\n // (property-only, not attribute - must be set imperatively)\n useEffect(() => {\n const element = elementRef.current;\n if (!element) return;\n\n element.userInputCodeTarget = control.options.userInputCodeTarget;\n }, [control.options.userInputCodeTarget]);\n\n // Sync rowDataForCodeEditor property when it changes\n // (property-only, not attribute - must be set imperatively)\n useEffect(() => {\n const element = elementRef.current;\n if (!element) return;\n\n element.rowDataForCodeEditor = control.options.rowDataForCodeEditor;\n }, [control.options.rowDataForCodeEditor]);\n\n // Sync allowLayoutToggle property when it changes\n // (Boolean attributes don't work correctly with \"false\" string)\n useEffect(() => {\n const element = elementRef.current;\n if (!element || control.options.allowLayoutToggle === undefined) return;\n\n element.allowLayoutToggle = control.options.allowLayoutToggle;\n }, [control.options.allowLayoutToggle]);\n\n // Sync grading property when it changes\n // (property-only, SPEAK contains a File - must be set imperatively)\n useEffect(() => {\n const element = elementRef.current;\n if (!element || !control.options.grading) return;\n\n element.grading = control.options.grading;\n }, [control.options.grading]);\n\n // Note: root sync removed - declarative API uses auto-detected parent\n // The element stays in its declared position\n\n const { options, isCdnLoaded } = control;\n\n // Wait for CDN to load before rendering Web Component\n // Without this, <tap-kit> is just an HTMLUnknownElement without methods\n if (!isCdnLoaded) {\n return null;\n }\n\n // Render <tap-kit> Web Component directly\n // Note: apiKey, videoTarget, allowLayoutToggle are set via ref callback (property-only)\n return (\n <tap-kit\n ref={setElementRef}\n user-id={options.userId}\n course-id={options.courseId}\n clip-id={options.clipId}\n section-id={options.sectionId}\n clip-play-head={options.clipPlayHead}\n external-reference-id={options.externalReferenceId}\n user-input-code={options.userInputCode}\n language={options.language}\n button-id={options.buttonId}\n mode={options.mode}\n chat-mode={options.chatMode}\n exam-skill={options.examSkill ?? undefined}\n debug={options.debug}\n tap-url={options.tapUrl}\n api-url={options.apiUrl}\n environment={options.environment}\n {...htmlProps}\n />\n );\n});\n","/**\n * CDN loader for TapKit\n * Dynamically loads the TapKit SDK from CDN\n *\n * For local testing, you can override the loader URL:\n * window.__TAP_KIT_LOADER_URL__ = '/tap-kit-core/loader.js';\n *\n * For local development (bypass loader, load IIFE directly):\n * window.__TAP_KIT_CORE_URL__ = '/packages/tap-kit-core/dist/index.global.js';\n */\n\n// Build-time constant injected by tsup define\ndeclare const __DEFAULT_CDN_LOADER_URL__: string;\n\nconst DEFAULT_CDN_LOADER_URL =\n typeof __DEFAULT_CDN_LOADER_URL__ !== \"undefined\" ? __DEFAULT_CDN_LOADER_URL__ : \"https://files.edutap.ai/tap-sdk/loader.js\";\nconst DEFAULT_TIMEOUT_MS = 4000; // 4 seconds total timeout\nconst IDLE_CALLBACK_TIMEOUT_MS = 500; // 500ms for requestIdleCallback\n\n/**\n * Get the loader URL from window override or default CDN\n */\nfunction getLoaderURL(): string {\n return window?.__TAP_KIT_LOADER_URL__ ? window.__TAP_KIT_LOADER_URL__ : DEFAULT_CDN_LOADER_URL;\n}\n\n/**\n * Check if local core mode is enabled\n * When __TAP_KIT_CORE_URL__ is set, directly load the IIFE bundle\n * This bypasses the loader.js and loads tap-kit-core directly\n */\nfunction isLocalCoreMode(): boolean {\n return typeof window !== \"undefined\" && !!window.__TAP_KIT_CORE_URL__;\n}\n\n/**\n * Get the local core URL\n */\nfunction getLocalCoreURL(): string {\n return window.__TAP_KIT_CORE_URL__ || \"\";\n}\n\n/**\n * Creates a SDK checker function with timeout and retry logic\n * Uses requestIdleCallback to avoid blocking browser rendering\n * @param resolve - Promise resolve function\n * @param reject - Promise reject function\n * @param timeoutMs - Maximum time to wait for SDK to load (milliseconds)\n * @returns Checker function to be called repeatedly\n */\nfunction createSDKChecker(\n resolve: (value: void | PromiseLike<void>) => void,\n reject: (reason?: unknown) => void,\n timeoutMs: number\n): () => void {\n const startTime = Date.now();\n\n const checkSDK = (): void => {\n // Check if real TapKit is loaded (not just stub)\n // Stub has TapKitLoaded flag set to true by loader.js after real SDK loads\n if (window.TapKit && window.TapKitLoaded === true) {\n window.__TAP_KIT_LOADER_LOADED__ = true;\n window.__TAP_KIT_LOADER_LOADING__ = undefined;\n resolve();\n return;\n }\n\n const elapsed = Date.now() - startTime;\n\n // Check if exceeded timeout\n if (elapsed > timeoutMs) {\n window.__TAP_KIT_LOADER_LOADING__ = undefined;\n reject(new Error(`TapKit loader timeout: SDK not available after ${timeoutMs}ms`));\n return;\n }\n\n // Use requestIdleCallback for better performance\n // Falls back to setTimeout if not available\n if (typeof requestIdleCallback !== \"undefined\") {\n requestIdleCallback(checkSDK, { timeout: IDLE_CALLBACK_TIMEOUT_MS });\n } else {\n setTimeout(checkSDK, IDLE_CALLBACK_TIMEOUT_MS);\n }\n };\n\n return checkSDK;\n}\n\n/**\n * Loads the CDN loader script\n * The loader will then fetch versions.json and load the appropriate SDK version\n *\n * If __TAP_KIT_CORE_URL__ is set, bypasses loader and loads IIFE directly\n *\n * @param timeoutMs - Maximum time to wait for SDK to load (default: 4000ms)\n * @returns Promise that resolves when SDK is loaded\n * @throws {Error} If loader fails to load or times out\n */\nexport function loadCDNLoader(timeoutMs: number = DEFAULT_TIMEOUT_MS): Promise<void> {\n // If already loaded, return immediately\n if (window.__TAP_KIT_LOADER_LOADED__ && window.TapKit) {\n return Promise.resolve();\n }\n\n // If currently loading, return the existing promise\n if (window.__TAP_KIT_LOADER_LOADING__) {\n return window.__TAP_KIT_LOADER_LOADING__;\n }\n\n // Create loading promise\n const loadingPromise = new Promise<void>((resolve, reject) => {\n if (typeof document === \"undefined\") {\n reject(new Error(\"TapKit requires browser environment (document is undefined)\"));\n return;\n }\n\n // Local core mode: Load IIFE directly\n if (isLocalCoreMode()) {\n // Check if TapKit is already loaded (from other pages in playground)\n if (window.TapKit && window.TapKitLoaded === true) {\n window.__TAP_KIT_LOADER_LOADED__ = true;\n window.__TAP_KIT_LOADER_LOADING__ = undefined;\n resolve();\n return;\n }\n\n const coreURL = getLocalCoreURL();\n\n const script = document.createElement(\"script\");\n script.src = coreURL;\n script.async = true;\n\n script.onload = () => {\n // IIFE directly sets window.TapKit\n // Set the loaded flag manually since we bypass loader.js\n if (window.TapKit) {\n window.TapKitLoaded = true;\n window.__TAP_KIT_LOADER_LOADED__ = true;\n window.__TAP_KIT_LOADER_LOADING__ = undefined;\n resolve();\n } else {\n window.__TAP_KIT_LOADER_LOADING__ = undefined;\n reject(new Error(\"TapKit not available after loading local core\"));\n }\n };\n\n script.onerror = () => {\n window.__TAP_KIT_LOADER_LOADING__ = undefined;\n reject(new Error(`Failed to load local TapKit core: ${coreURL}`));\n };\n\n document.head.appendChild(script);\n return;\n }\n\n // CDN mode: Load loader.js\n const loaderURL = getLoaderURL();\n const script = document.createElement(\"script\");\n script.src = loaderURL;\n script.async = true;\n\n script.onload = () => {\n // The loader script will load the actual SDK\n // We need to wait a bit for the loader to fetch and load the SDK\n const checkSDK = createSDKChecker(resolve, reject, timeoutMs);\n checkSDK();\n };\n\n script.onerror = () => {\n window.__TAP_KIT_LOADER_LOADING__ = undefined;\n reject(new Error(`Failed to load TapKit CDN loader: ${loaderURL}`));\n };\n\n // Check if script already exists\n const existingScript = document.querySelector(`script[src=\"${loaderURL}\"]`);\n\n if (existingScript) {\n // Script already added but not yet loaded\n existingScript.addEventListener(\"load\", () => {\n const checkSDK = createSDKChecker(resolve, reject, timeoutMs);\n checkSDK();\n });\n existingScript.addEventListener(\"error\", () => reject(new Error(`Failed to load TapKit CDN loader: ${loaderURL}`)));\n } else {\n document.head.appendChild(script);\n }\n });\n\n window.__TAP_KIT_LOADER_LOADING__ = loadingPromise;\n return loadingPromise;\n}\n","/**\n * useTapKit Hook - ChatKit-style control for TapKit Web Component\n *\n * This hook provides a control object to manage TapKit through the\n * <TapKit /> component. Inspired by OpenAI's ChatKit pattern.\n *\n * @example\n * ```tsx\n * 'use client';\n *\n * import { TapKit, useTapKit } from '@coxwave/tap-kit/react';\n *\n * function MyApp() {\n * const tapkit = useTapKit({\n * apiKey: 'your-key',\n * userId: 'user-123',\n * courseId: 'course-456',\n * clipId: 'clip-789',\n * onReady: () => console.log('Ready!'),\n * onError: (error) => console.error(error),\n * });\n *\n * return (\n * <div>\n * <button onClick={tapkit.show} disabled={!tapkit.isReady}>\n * Ask AI Tutor\n * </button>\n * <TapKit control={tapkit.control} />\n * </div>\n * );\n * }\n * ```\n */\n\nimport type {\n ChatMode,\n TapExamSkill,\n CodingRowDataInput,\n GradingOption,\n TapKitElement,\n UserInputCodeAdapter,\n VideoPlayerConfig,\n} from \"@coxwave/tap-kit-types\";\nimport { normalizeCodingRowData } from \"@coxwave/tap-kit-types\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { loadCDNLoader } from \"../loader\";\nimport type { TapKitControl, TapKitEventHandlers, VideoAdapter } from \"./types\";\n\nexport interface UseTapKitOptions extends TapKitEventHandlers {\n /** API Key (required) */\n apiKey: string;\n /** User ID */\n userId?: string;\n /** Course ID */\n courseId?: string;\n /** Clip ID */\n clipId?: string;\n /** Section ID (course 내 섹션 식별자) */\n sectionId?: string;\n /** Clip playhead position */\n clipPlayHead?: number;\n /** External reference ID (외부 시스템에서 부여한 참조 식별자) */\n externalReferenceId?: string;\n /** External reference data (외부 시스템에서 부여한 참조 데이터) */\n userInputCode?: string;\n /**\n * Raw coding exercise metadata from host LMS/platform.\n *\n * 5 required string fields are auto-extracted and attached to chat stream\n * requests as `coding_language`, `coding_testcase`, `coding_content`,\n * `coding_example`, `coding_restriction`. Additional fields on the object\n * are ignored.\n *\n * If provided, all 5 fields must be non-empty strings — otherwise the hook\n * throws on render (treated as init failure).\n *\n * **Tip**: Wrap in `useMemo` to keep object reference stable across renders.\n *\n * @example\n * ```tsx\n * const rowData = useMemo(() => ({\n * language_id_nm: \"C++ (GCC 9.2.0)\",\n * d_test_case: \"<p>...</p>\",\n * content: \"...\",\n * io_example: \"...\",\n * restriction: \"...\",\n * }), []);\n *\n * const tapkit = useTapKit({ apiKey, userId, courseId, rowDataForCodeEditor: rowData });\n * ```\n */\n rowDataForCodeEditor?: CodingRowDataInput;\n /** Language */\n language?: \"ko\" | \"en\" | \"ja\";\n /** Custom button element ID */\n buttonId?: string;\n /** Display mode */\n mode?: \"inline\" | \"floating\" | \"sidebar\";\n /** Chat interaction mode (staging feature: per-message override) */\n chatMode?: ChatMode;\n /**\n * 호스트 시험 플레이어의 현재 섹션 (Writing / Speaking).\n * 취약점 진단 결과의 탭이 이 값에 따라 초기값·동기화된다 (ClickUp z90uw3mm72).\n */\n examSkill?: TapExamSkill | null;\n /**\n * Allow user to toggle between floating and sidebar layouts\n * Only applies when mode is \"floating\" or \"sidebar\"\n * @default true\n */\n allowLayoutToggle?: boolean;\n /**\n * Video player target for timeline synchronization (recommended)\n *\n * Supports HTMLVideoElement or VideoPlayerAdapter.\n * Survives lifecycle changes (mode change, reconnect).\n *\n * @example\n * ```tsx\n * // HTMLVideoElement\n * const tapkit = useTapKit({ videoTarget: videoRef.current, ... });\n *\n * // VideoPlayerAdapter\n * const tapkit = useTapKit({\n * videoTarget: {\n * getCurrentTime: () => player.currentTime,\n * setCurrentTime: (t) => player.currentTime = t\n * },\n * ...\n * });\n * ```\n */\n videoTarget?: VideoPlayerConfig;\n /**\n * User input code adapter for bidirectional sync with a host code editor.\n *\n * 호스트 페이지의 코드 에디터(Monaco, CodeMirror, iframe IDE 등)와 SDK를\n * 양방향 동기화하는 어댑터. videoTarget과 동일한 패턴.\n *\n * - SDK가 폴링 주기로 `getCode()` 호출 → 채팅 컨텍스트에 최신 코드 반영\n * - 채팅의 \"에디터에 적용\" 모달 → SDK가 `setCode(code)` 호출 (Optional)\n *\n * @example\n * ```tsx\n * const tapkit = useTapKit({\n * userInputCodeTarget: {\n * getCode: () => monacoEditor.getValue(),\n * setCode: (code) => monacoEditor.setValue(code),\n * },\n * ...\n * });\n * ```\n */\n userInputCodeTarget?: UserInputCodeAdapter;\n /**\n * Grading session — single grading problem (Speaking 또는 Writing).\n *\n * 호스트가 SDK에 넘기는 채점 셋업. `gradeType`으로 판별한다. config:update가 아닌\n * 전용 `grading:setup` 메시지로 iframe에 전달된다. SPEAK은 edutap이 음성 파일을\n * 업로드한 뒤 홈에서 프리셋 질문 버튼을 노출하고, WRITE는 학습자가 채팅 입력창에\n * 답안을 작성한다. (SPEAK은) File을 포함하므로 객체 참조가 바뀔 때마다 재전송된다\n * — 안정적인 참조를 위해 `useMemo`로 감싸는 것을 권장.\n *\n * @example\n * ```tsx\n * // Speaking\n * const grading = useMemo(() => ({\n * gradeType: \"SPEAK\" as const,\n * audioFile,\n * problemText: \"Describe your hometown\",\n * problemType: \"INTERVIEW\" as const,\n * referenceAnswer: \"...\",\n * hint: \"장소 묘사\",\n * }), [audioFile]);\n *\n * // Writing (음성 없음, 학습자가 채팅 입력창에 답안 작성)\n * const grading = { gradeType: \"WRITE\" as const, problemText, problemType: \"MSOM\" as const };\n *\n * const tapkit = useTapKit({ apiKey, userId, courseId, grading });\n * ```\n */\n grading?: GradingOption;\n /** Debug mode */\n debug?: boolean;\n /** TAP Frontend URL */\n tapUrl?: string;\n /** API Backend URL */\n apiUrl?: string;\n /** Environment */\n environment?: \"dev\" | \"prod\" | \"staging\";\n // Note: `root` option removed - declarative API (<TapKit />) stays in declared position\n // For imperative control over position, use createTapKit() with root option\n}\n\n/**\n * Configuration options type (non-function values)\n */\nexport type TapKitOptions = Omit<UseTapKitOptions, keyof TapKitEventHandlers>;\n\n/**\n * Extract event handlers from options (pure function)\n */\nfunction extractHandlers(options: UseTapKitOptions): TapKitEventHandlers {\n return {\n onReady: options.onReady,\n onError: options.onError,\n onTimelineSeek: options.onTimelineSeek,\n onAlarmFadeIn: options.onAlarmFadeIn,\n onExamQuestionNavigate: options.onExamQuestionNavigate,\n };\n}\n\nexport interface UseTapKitReturn {\n /** Control object for <TapKit /> component */\n control: TapKitControl<TapKitOptions>;\n /** Whether TapKit is ready */\n isReady: boolean;\n /** Error during initialization */\n error: Error | null;\n /** Show chat interface */\n show: () => void;\n /** Hide chat interface */\n hide: () => void;\n /** Set course information */\n setCourse: (course: { courseId: string; clipId?: string; userId?: string; clipPlayHead?: number }) => void;\n /** Update external reference ID at runtime (pass undefined to clear) */\n setExternalReferenceId: (id?: string) => void;\n /** Update external reference data at runtime (pass undefined to clear) */\n setExternalReferenceData: (data?: string) => void;\n /** Send contextual data from host to iframe (AI tutor) */\n sendContext: (contextType: string, payload: Record<string, unknown>) => void;\n /**\n * Video adapter control\n *\n * @deprecated Use `videoTarget` option in useTapKit instead for declarative binding.\n *\n * ```tsx\n * // ✅ Recommended (declarative)\n * const tapkit = useTapKit({ videoTarget: adapter, ... });\n *\n * // ❌ Deprecated (imperative)\n * tapkit.video.bind(adapter);\n * ```\n */\n video: {\n bind: (adapter: VideoAdapter, clipId?: string) => void;\n unbind: () => void;\n };\n}\n\n/**\n * Hook for managing TapKit Web Component (ChatKit Pattern)\n *\n * Returns a control object to pass to <TapKit /> component.\n * The component handles rendering, this hook handles state and methods.\n */\nexport function useTapKit(options: UseTapKitOptions): UseTapKitReturn {\n // Normalize rowDataForCodeEditor — accepts both `CodingRowData` and JSON string.\n // Throws synchronously on render if partial/invalid so the caller's React error\n // boundary catches config errors before the SDK is initialized.\n const normalizedRowData = useMemo(\n () => (options.rowDataForCodeEditor === undefined ? undefined : normalizeCodingRowData(options.rowDataForCodeEditor)),\n [options.rowDataForCodeEditor]\n );\n\n // Element ref - set by <TapKit /> component via control.setInstance\n const elementRef = useRef<TapKitElement | null>(null);\n\n // Pending video bind request (queued until ready)\n const pendingVideoBind = useRef<{\n adapter: VideoAdapter;\n clipId?: string;\n } | null>(null);\n\n // State\n const [isCdnLoaded, setIsCdnLoaded] = useState(false);\n const [isReady, setIsReady] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n // Store handlers in refs to avoid stale closures\n const handlersRef = useRef(extractHandlers(options));\n handlersRef.current = extractHandlers(options);\n\n // Load CDN on mount (defines <tap-kit> Web Component)\n useEffect(() => {\n loadCDNLoader()\n .then(() => {\n setIsCdnLoaded(true);\n })\n .catch((err) => {\n const loadError = err instanceof Error ? err : new Error(\"Failed to load TapKit CDN\");\n setError(loadError);\n handlersRef.current.onError?.(loadError);\n });\n }, []);\n\n // Set instance callback - called by <TapKit /> component\n const setInstance = useCallback((instance: TapKitElement | null) => {\n elementRef.current = instance;\n\n if (!instance) {\n setIsReady(false);\n return;\n }\n\n // Listen for ready event\n const handleReady = () => {\n setIsReady(true);\n handlersRef.current.onReady?.();\n };\n\n const handleError = (e: Event) => {\n const customEvent = e as CustomEvent<{ error: Error }>;\n const err = customEvent.detail?.error ?? new Error(\"Unknown error\");\n setError(err);\n handlersRef.current.onError?.(err);\n };\n\n instance.addEventListener(\"tap-kit:ready\", handleReady);\n instance.addEventListener(\"tap-kit:error\", handleError);\n\n // Check if already ready\n if (instance.isInitialized) {\n setIsReady(true);\n }\n\n // Setup EventManager callbacks when ready\n // Use stable wrappers that call handlersRef.current to always get latest handlers\n const setupEventHandlers = () => {\n if (instance.events && typeof instance.events.onTimelineSeek === \"function\") {\n // Register stable wrappers instead of direct refs\n // This ensures handler updates are reflected without re-registration\n instance.events.onTimelineSeek((clipPlayHead, clipId) => {\n handlersRef.current.onTimelineSeek?.(clipPlayHead, clipId);\n });\n instance.events.onAlarmFadeIn((messageInfo) => {\n handlersRef.current.onAlarmFadeIn?.(messageInfo);\n });\n instance.events.onExamQuestionNavigate((clipId, questionNo) => {\n handlersRef.current.onExamQuestionNavigate?.(clipId, questionNo);\n });\n }\n\n // Execute pending video bind if queued\n if (pendingVideoBind.current && instance.video) {\n instance.video.bind(pendingVideoBind.current.adapter, pendingVideoBind.current.clipId);\n pendingVideoBind.current = null;\n }\n };\n\n // Check if ready property exists (may not be available immediately)\n if (instance.ready && typeof instance.ready.then === \"function\") {\n instance.ready.then(setupEventHandlers).catch(() => {\n // Ignore - error already handled by tap-kit:error event\n });\n } else if (instance.isInitialized) {\n // Already initialized, setup handlers immediately\n setupEventHandlers();\n } else {\n // Fallback: wait for ready event then setup handlers\n instance.addEventListener(\"tap-kit:ready\", setupEventHandlers, {\n once: true,\n });\n }\n }, []);\n\n // Memoize config options using individual values to prevent infinite re-renders\n // (options object is recreated on every render, so we must depend on primitives)\n // Note: videoTarget is object reference - changes trigger re-render intentionally\n const configOptions = useMemo(\n () => ({\n apiKey: options.apiKey,\n userId: options.userId,\n courseId: options.courseId,\n clipId: options.clipId,\n sectionId: options.sectionId,\n clipPlayHead: options.clipPlayHead,\n externalReferenceId: options.externalReferenceId,\n userInputCode: options.userInputCode,\n rowDataForCodeEditor: normalizedRowData,\n language: options.language,\n buttonId: options.buttonId,\n mode: options.mode,\n chatMode: options.chatMode,\n examSkill: options.examSkill,\n allowLayoutToggle: options.allowLayoutToggle,\n videoTarget: options.videoTarget,\n userInputCodeTarget: options.userInputCodeTarget,\n grading: options.grading,\n debug: options.debug,\n tapUrl: options.tapUrl,\n apiUrl: options.apiUrl,\n environment: options.environment,\n // Note: root removed - declarative API stays in declared position\n }),\n [\n options.apiKey,\n options.userId,\n options.courseId,\n options.clipId,\n options.sectionId,\n options.clipPlayHead,\n options.externalReferenceId,\n options.userInputCode,\n normalizedRowData,\n options.language,\n options.buttonId,\n options.mode,\n options.chatMode,\n options.examSkill,\n options.allowLayoutToggle,\n options.videoTarget,\n options.userInputCodeTarget,\n options.grading,\n options.debug,\n options.tapUrl,\n options.apiUrl,\n options.environment,\n ]\n );\n\n // Create stable handlers object for control\n // NOTE: This object is intentionally created once (empty deps) and appears to capture\n // stale values. However, the actual handler invocations in TapKit.tsx use handlersRef.current\n // which always has the latest handlers. This object is just a stable reference marker\n // that tells TapKit.tsx which handlers exist - not the actual handlers to call.\n const handlers = useMemo<TapKitEventHandlers>(\n () => ({\n onReady: handlersRef.current.onReady,\n onError: handlersRef.current.onError,\n onTimelineSeek: handlersRef.current.onTimelineSeek,\n onAlarmFadeIn: handlersRef.current.onAlarmFadeIn,\n onExamQuestionNavigate: handlersRef.current.onExamQuestionNavigate,\n }),\n []\n );\n\n // Create control object\n const control = useMemo<TapKitControl<TapKitOptions>>(\n () => ({\n setInstance,\n options: configOptions,\n handlers,\n isCdnLoaded,\n }),\n [setInstance, configOptions, handlers, isCdnLoaded]\n );\n\n // Methods\n const show = useCallback(() => {\n if (!elementRef.current) {\n console.warn(\"[useTapKit] Cannot show: element not mounted\");\n return;\n }\n elementRef.current.show();\n }, []);\n\n const hide = useCallback(() => {\n if (!elementRef.current) {\n console.warn(\"[useTapKit] Cannot hide: element not mounted\");\n return;\n }\n elementRef.current.hide();\n }, []);\n\n const setCourse = useCallback((course: { courseId: string; clipId?: string; userId?: string; clipPlayHead?: number }) => {\n if (!elementRef.current) {\n console.warn(\"[useTapKit] Cannot setCourse: element not mounted\");\n return;\n }\n elementRef.current.setCourse(course);\n }, []);\n\n const setExternalReferenceId = useCallback((id?: string) => {\n if (!elementRef.current) {\n console.warn(\"[useTapKit] Cannot setExternalReferenceId: element not mounted\");\n return;\n }\n elementRef.current.externalReferenceId = id;\n }, []);\n\n const setExternalReferenceData = useCallback((data?: string) => {\n if (!elementRef.current) {\n console.warn(\"[useTapKit] Cannot setExternalReferenceData: element not mounted\");\n return;\n }\n elementRef.current.userInputCode = data;\n }, []);\n\n const sendContext = useCallback((contextType: string, payload: Record<string, unknown>) => {\n if (!elementRef.current) {\n console.warn(\"[useTapKit] Cannot sendContext: element not mounted\");\n return;\n }\n elementRef.current.sendContext(contextType, payload);\n }, []);\n\n // Video adapter control\n const video = useMemo(\n () => ({\n bind: (adapter: VideoAdapter, clipId?: string) => {\n // If video controller is ready, bind immediately\n if (elementRef.current?.video) {\n elementRef.current.video.bind(adapter, clipId);\n return;\n }\n\n // Queue for later execution when ready\n pendingVideoBind.current = { adapter, clipId };\n },\n unbind: () => {\n // Clear pending request\n pendingVideoBind.current = null;\n elementRef.current?.video?.unbind();\n },\n }),\n []\n );\n\n return {\n control,\n isReady,\n error,\n show,\n hide,\n setCourse,\n setExternalReferenceId,\n setExternalReferenceData,\n sendContext,\n video,\n };\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coxwave/tap-kit",
3
- "version": "4.5.0",
3
+ "version": "4.8.0",
4
4
  "description": "EduTAP SDK with React support",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -23,7 +23,7 @@
23
23
  "README.md"
24
24
  ],
25
25
  "dependencies": {
26
- "@coxwave/tap-kit-types": "3.5.0"
26
+ "@coxwave/tap-kit-types": "3.8.0"
27
27
  },
28
28
  "peerDependencies": {
29
29
  "react": "^18.0.0 || ^19.0.0"