diff --git a/src/components/APIExplorer.tsx b/src/components/APIExplorer.tsx index 67a9a38..9e8cc25 100644 --- a/src/components/APIExplorer.tsx +++ b/src/components/APIExplorer.tsx @@ -1,4 +1,4 @@ -import React, { useState, useEffect, useRef } from 'react' +import React, { useState, useEffect } from 'react' import { useQuery } from '@tanstack/react-query' import Prism from 'prismjs' import 'prismjs/components/prism-typescript.js' @@ -36,13 +36,21 @@ import designerExtensionTypings from '@/designer-extension-typings/index.d.ts?ra const examples: { [key: string]: any } = examplesImport as any -const APIExplorer: React.FC = () => { - const [selectedExampleCategory, setSelectedExampleCategory] = useState('') - const [selectedFunctionName, setSelectedFunctionName] = useState('') +interface APIExplorerProps { + selectedExampleCategory: string + setSelectedExampleCategory: (value: string) => void + selectedFunctionName: string + setSelectedFunctionName: (value: string) => void +} + +const APIExplorer: React.FC = ({ + selectedExampleCategory, + setSelectedExampleCategory, + selectedFunctionName, + setSelectedFunctionName, +}) => { const [functionParameters, setFunctionParameters] = useState({}) const [apiOutput, setApiOutput] = useState('') - const hasAutoExecutedRef = useRef(false) - const hasInitializedRef = useRef(false) // Fetch function code and parameters const { functionCode, parameterNames, parameterTypes, setParameterNames } = @@ -106,41 +114,6 @@ const APIExplorer: React.FC = () => { setApiOutput('') }, [selectedFunctionName, selectedExampleCategory]) - // Auto-initialize first example and function - useEffect(() => { - if (!hasInitializedRef.current) { - hasInitializedRef.current = true - const firstCategory = Object.keys(examples)[0] - setSelectedExampleCategory(firstCategory) - - const categoryContent = examples[firstCategory] || {} - const firstSubcategory = Object.keys(categoryContent)[0] - - if ( - typeof categoryContent[firstSubcategory] === 'object' && - !('type' in (categoryContent[firstSubcategory] || {})) - ) { - const firstFunction = Object.keys(categoryContent[firstSubcategory])[0] - setSelectedFunctionName(`${firstSubcategory}.${firstFunction}`) - } else { - setSelectedFunctionName(firstSubcategory) - } - } - }, []) - - // Auto-run function if no parameters needed - useEffect(() => { - if ( - selectedFunctionName && - parameterNames.length === 0 && - selectedExampleCategory && - !hasAutoExecutedRef.current - ) { - hasAutoExecutedRef.current = true - handleFunctionExecution() - } - }, [selectedFunctionName, selectedExampleCategory, parameterNames]) - const exampleCategories: CategoryOption[] = Object.keys(examples).map( (key) => ({ value: key, @@ -181,7 +154,6 @@ const APIExplorer: React.FC = () => { const handleFunctionChange = (value: string) => { setSelectedFunctionName(value) - hasAutoExecutedRef.current = false } const handleParameterChange = (name: string, value: any) => { @@ -202,8 +174,8 @@ const APIExplorer: React.FC = () => { : topCategory[selectedFunctionName] if (funcToExecute) { - // Save original console before try block so it's accessible in finally const originalConsole = { ...console } + try { setApiOutput('') @@ -245,13 +217,19 @@ const APIExplorer: React.FC = () => { if (typeof funcToExecute === 'function') { const result = funcToExecute(...paramValues) if (result && typeof result.then === 'function') { - result.catch(apiConsole.error) + // Restore console after the async function completes, not before + result + .catch(apiConsole.error) + .finally(() => Object.assign(console, originalConsole)) + } else { + Object.assign(console, originalConsole) } + } else { + Object.assign(console, originalConsole) } } catch (error) { - console.error('Error executing function:', error) - } finally { Object.assign(console, originalConsole) + console.error('Error executing function:', error) } } } @@ -331,7 +309,7 @@ const APIExplorer: React.FC = () => { {METHOD_DESCRIPTIONS[selectedExampleCategory][selectedFunctionName]} )} - {parameterNames.length > 0 && ( + {selectedFunctionName && (
{parameterNames.map((name: string, index: number) => @@ -359,9 +337,8 @@ const APIExplorer: React.FC = () => {
setApiOutput('')} code={apiOutput || '// Run the method to see output'} - language="javascript" + language="none" />
)} diff --git a/src/main.jsx b/src/main.jsx index 1bebbf9..cd9d814 100644 --- a/src/main.jsx +++ b/src/main.jsx @@ -9,6 +9,9 @@ import { loader } from '@monaco-editor/react' import Playground from './components/Playground' import TabNavigation from './components/TabNavigation' import APIExplorer from './components/APIExplorer' +import examplesImport from './examples/examples' + +const examples = examplesImport const TABS = [ { key: 'api', label: 'API Explorer' }, @@ -26,13 +29,38 @@ const queryClient = new QueryClient({ const App = () => { const [activeTab, setActiveTab] = useState('api') + const [selectedExampleCategory, setSelectedExampleCategory] = useState('') + const [selectedFunctionName, setSelectedFunctionName] = useState('') const containerRef = useRef(null) + const hasInitializedRef = useRef(false) useEffect(() => { // Set initial size webflow.setExtensionSize({ height: 425, width: 500 }) }, []) + // Auto-initialize first example and function + useEffect(() => { + if (!hasInitializedRef.current) { + hasInitializedRef.current = true + const firstCategory = Object.keys(examples)[0] + setSelectedExampleCategory(firstCategory) + + const categoryContent = examples[firstCategory] || {} + const firstSubcategory = Object.keys(categoryContent)[0] + + if ( + typeof categoryContent[firstSubcategory] === 'object' && + !('type' in (categoryContent[firstSubcategory] || {})) + ) { + const firstFunction = Object.keys(categoryContent[firstSubcategory])[0] + setSelectedFunctionName(`${firstSubcategory}.${firstFunction}`) + } else { + setSelectedFunctionName(firstSubcategory) + } + } + }, []) + // Global error handler for Monaco Editor cancellation errors useEffect(() => { // Pre-initialize Monaco to avoid first-load cancellation during StrictMode double-mount @@ -133,7 +161,14 @@ const App = () => { activeTab={activeTab} setActiveTab={setActiveTab} /> - {activeTab === 'api' && } + {activeTab === 'api' && ( + + )} {activeTab === 'code' && }