@hypertools/sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +443 -0
- package/dist/capture/CaptureManager.d.ts +55 -0
- package/dist/capture/CaptureManager.d.ts.map +1 -0
- package/dist/capture/index.d.ts +27 -0
- package/dist/capture/index.d.ts.map +1 -0
- package/dist/capture/index.js +11 -0
- package/dist/capture/index.js.map +10 -0
- package/dist/capture/types.d.ts +76 -0
- package/dist/capture/types.d.ts.map +1 -0
- package/dist/codegen/index.d.ts +6 -0
- package/dist/codegen/index.d.ts.map +1 -0
- package/dist/codegen/index.js +800 -0
- package/dist/codegen/index.js.map +13 -0
- package/dist/controls/HypertoolControls.d.ts +84 -0
- package/dist/controls/HypertoolControls.d.ts.map +1 -0
- package/dist/controls/index.d.ts +11 -0
- package/dist/controls/index.d.ts.map +1 -0
- package/dist/controls/index.js +28 -0
- package/dist/controls/index.js.map +12 -0
- package/dist/controls/simple-api.d.ts +43 -0
- package/dist/controls/simple-api.d.ts.map +1 -0
- package/dist/controls/theme.d.ts +80 -0
- package/dist/controls/theme.d.ts.map +1 -0
- package/dist/controls/types.d.ts +178 -0
- package/dist/controls/types.d.ts.map +1 -0
- package/dist/core/EventEmitter.d.ts +76 -0
- package/dist/core/EventEmitter.d.ts.map +1 -0
- package/dist/core/Experience.d.ts +128 -0
- package/dist/core/Experience.d.ts.map +1 -0
- package/dist/core/ObjectRegistry.d.ts +76 -0
- package/dist/core/ObjectRegistry.d.ts.map +1 -0
- package/dist/core/ParamStore.d.ts +66 -0
- package/dist/core/ParamStore.d.ts.map +1 -0
- package/dist/core/index.d.ts +12 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +3 -0
- package/dist/core/index.js.map +13 -0
- package/dist/export/bundler.d.ts +55 -0
- package/dist/export/bundler.d.ts.map +1 -0
- package/dist/export/generators/index.d.ts +6 -0
- package/dist/export/generators/index.d.ts.map +1 -0
- package/dist/export/generators/webComponent.d.ts +29 -0
- package/dist/export/generators/webComponent.d.ts.map +1 -0
- package/dist/export/index.d.ts +19 -0
- package/dist/export/index.d.ts.map +1 -0
- package/dist/export/index.js +800 -0
- package/dist/export/index.js.map +13 -0
- package/dist/export/runtime.d.ts +46 -0
- package/dist/export/runtime.d.ts.map +1 -0
- package/dist/frame/cssBridge.d.ts +34 -0
- package/dist/frame/cssBridge.d.ts.map +1 -0
- package/dist/frame/index.d.ts +9 -0
- package/dist/frame/index.d.ts.map +1 -0
- package/dist/frame/index.js +3 -0
- package/dist/frame/index.js.map +24 -0
- package/dist/frame/runtime.d.ts +39 -0
- package/dist/frame/runtime.d.ts.map +1 -0
- package/dist/frame/types.d.ts +119 -0
- package/dist/frame/types.d.ts.map +1 -0
- package/dist/frame/utils/dom.d.ts +11 -0
- package/dist/frame/utils/dom.d.ts.map +1 -0
- package/dist/frame/wrapper-app/WrapperApp.d.ts +16 -0
- package/dist/frame/wrapper-app/WrapperApp.d.ts.map +1 -0
- package/dist/frame/wrapper-app/components/CanvasSizeWidget.d.ts +17 -0
- package/dist/frame/wrapper-app/components/CanvasSizeWidget.d.ts.map +1 -0
- package/dist/frame/wrapper-app/components/ControlsPanel.d.ts +11 -0
- package/dist/frame/wrapper-app/components/ControlsPanel.d.ts.map +1 -0
- package/dist/frame/wrapper-app/components/ExportWidget.d.ts +16 -0
- package/dist/frame/wrapper-app/components/ExportWidget.d.ts.map +1 -0
- package/dist/frame/wrapper-app/components/ResizeHandles.d.ts +19 -0
- package/dist/frame/wrapper-app/components/ResizeHandles.d.ts.map +1 -0
- package/dist/frame/wrapper-app/components/SandboxContainer.d.ts +16 -0
- package/dist/frame/wrapper-app/components/SandboxContainer.d.ts.map +1 -0
- package/dist/frame/wrapper-app/components/index.d.ts +5 -0
- package/dist/frame/wrapper-app/components/index.d.ts.map +1 -0
- package/dist/frame/wrapper-app/context/CanvasContext.d.ts +37 -0
- package/dist/frame/wrapper-app/context/CanvasContext.d.ts.map +1 -0
- package/dist/frame/wrapper-app/context/index.d.ts +2 -0
- package/dist/frame/wrapper-app/context/index.d.ts.map +1 -0
- package/dist/frame/wrapper-app/index.d.ts +9 -0
- package/dist/frame/wrapper-app/index.d.ts.map +1 -0
- package/dist/frame/wrapper-app/types.d.ts +38 -0
- package/dist/frame/wrapper-app/types.d.ts.map +1 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +189 -0
- package/dist/index.js.map +35 -0
- package/dist/react/ExperienceView.d.ts +53 -0
- package/dist/react/ExperienceView.d.ts.map +1 -0
- package/dist/react/index.d.ts +8 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +3 -0
- package/dist/react/index.js.map +15 -0
- package/dist/react/useExperience.d.ts +55 -0
- package/dist/react/useExperience.d.ts.map +1 -0
- package/dist/recording/ImageCapture.d.ts +46 -0
- package/dist/recording/ImageCapture.d.ts.map +1 -0
- package/dist/recording/Timeline.d.ts +105 -0
- package/dist/recording/Timeline.d.ts.map +1 -0
- package/dist/recording/VideoRecorder.d.ts +64 -0
- package/dist/recording/VideoRecorder.d.ts.map +1 -0
- package/dist/recording/index.d.ts +10 -0
- package/dist/recording/index.d.ts.map +1 -0
- package/dist/recording/index.js +3 -0
- package/dist/recording/index.js.map +12 -0
- package/package.json +141 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/export/bundler.ts", "../../src/export/generators/webComponent.ts", "../../src/controls/theme.ts", "../../src/export/runtime.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"/**\n * Bundle generation using esbuild\n */\n\nexport interface BundleOptions {\n /** Entry file path or inline code */\n entry: string | { code: string; filename?: string };\n\n /** Additional files for bundling */\n files?: Record<string, string>;\n\n /** Output format (default: 'iife') */\n format?: 'iife' | 'esm' | 'cjs';\n\n /** Minify output (default: true) */\n minify?: boolean;\n\n /** Generate source maps */\n sourcemap?: boolean;\n\n /** Global name for IIFE format */\n globalName?: string;\n\n /** External packages to exclude from bundle */\n external?: string[];\n\n /** Target environment (default: 'browser') */\n target?: 'browser' | 'node';\n\n /** Define replacements */\n define?: Record<string, string>;\n}\n\nexport interface BundleResult {\n /** Bundled code */\n code: string;\n\n /** Source map (if requested) */\n map?: string;\n\n /** Build warnings */\n warnings: string[];\n\n /** Output size in bytes */\n size: number;\n}\n\n/**\n * Bundle code using esbuild\n *\n * This function is designed to run in Node.js/Bun server environment\n * (e.g., backend export service)\n */\nexport async function generateBundle(options: BundleOptions): Promise<BundleResult> {\n // Dynamic import esbuild (only available server-side)\n let esbuild: typeof import('esbuild');\n try {\n esbuild = await import('esbuild');\n } catch {\n throw new Error(\n 'esbuild is not available. This function is meant to run server-side.'\n );\n }\n\n const { mkdtemp, writeFile, readFile, rm, mkdir } = await import('fs/promises');\n const { tmpdir } = await import('os');\n const { join, dirname } = await import('path');\n\n const tempDir = await mkdtemp(join(tmpdir(), 'hypertool-bundle-'));\n\n try {\n // Write files to temp directory\n if (options.files) {\n for (const [filePath, content] of Object.entries(options.files)) {\n const fullPath = join(tempDir, filePath.replace(/^\\//, ''));\n const dir = dirname(fullPath);\n await mkdir(dir, { recursive: true });\n await writeFile(fullPath, content);\n }\n }\n\n // Determine entry\n let entryPath: string;\n if (typeof options.entry === 'string') {\n entryPath = join(tempDir, options.entry.replace(/^\\//, ''));\n } else {\n const filename = options.entry.filename ?? 'entry.ts';\n entryPath = join(tempDir, filename);\n await writeFile(entryPath, options.entry.code);\n }\n\n // Bundle with esbuild\n const result = await esbuild.build({\n entryPoints: [entryPath],\n bundle: true,\n outfile: join(tempDir, 'out.js'),\n platform: options.target === 'node' ? 'node' : 'browser',\n format: options.format ?? 'iife',\n minify: options.minify ?? true,\n sourcemap: options.sourcemap ? 'external' : false,\n globalName: options.globalName,\n external: options.external,\n define: options.define,\n write: true,\n metafile: true,\n });\n\n // Read output\n const code = await readFile(join(tempDir, 'out.js'), 'utf-8');\n let map: string | undefined;\n\n if (options.sourcemap) {\n try {\n map = await readFile(join(tempDir, 'out.js.map'), 'utf-8');\n } catch {\n // Source map might not exist\n }\n }\n\n return {\n code,\n map,\n warnings: result.warnings.map((w: { text: string }) => w.text),\n size: Buffer.byteLength(code, 'utf-8'),\n };\n } finally {\n // Cleanup\n await rm(tempDir, { recursive: true, force: true });\n }\n}\n\n/**\n * Extract param definitions from code using regex\n */\nexport function extractParamDefs(\n code: string\n): Record<string, { type: string; value: unknown }> | null {\n // Match export const paramDefs = { ... }\n const match = code.match(\n /export\\s+(?:const|let|var)\\s+(?:paramDefs|controlDefinitions)\\s*=\\s*(\\{[\\s\\S]*?\\});?/\n );\n\n if (!match) return null;\n\n try {\n // This is a simplified extraction - in production you'd use AST parsing\n // For now, we'll return null and let the backend handle it\n return null;\n } catch {\n return null;\n }\n}\n\n/**\n * Wrap user code to expose setup function globally\n */\nexport function wrapSetupCode(code: string): string {\n return `\n${code}\n\n// Expose setup function globally for web component\nif (typeof setup === 'function') {\n window.__hypertool_setup__ = setup;\n}\nif (typeof paramDefs !== 'undefined') {\n window.__hypertool_paramDefs__ = paramDefs;\n}\n`;\n}\n",
|
|
6
|
+
"/**\n * Web component generator for exports\n */\n\nimport type { ParamDefinitions } from '../../core/ParamStore';\n\nexport interface WebComponentOptions {\n /** Component tag name (e.g., 'my-experience') */\n tagName: string;\n\n /** Class name (e.g., 'MyExperience') */\n className: string;\n\n /** Bundled experience code */\n bundledCode: string;\n\n /** Parameter definitions */\n paramDefs: ParamDefinitions;\n\n /** Current parameter values */\n currentParams?: Record<string, unknown>;\n\n /** Include Tweakpane controls */\n showControls?: boolean;\n\n /** Background color */\n background?: string;\n}\n\n/**\n * Escape string for safe embedding in JavaScript\n */\nfunction escapeForJS(str: string): string {\n return str\n .replace(/\\\\/g, '\\\\\\\\')\n .replace(/`/g, '\\\\`')\n .replace(/\\$/g, '\\\\$')\n .replace(/<\\/script>/gi, '<\\\\/script>');\n}\n\n/**\n * Generate a self-contained web component\n */\nexport function generateWebComponent(options: WebComponentOptions): string {\n const {\n tagName,\n className,\n bundledCode,\n paramDefs,\n currentParams = {},\n showControls = false,\n background = 'transparent',\n } = options;\n\n // Escape JSON for embedding\n const paramsJson = JSON.stringify(currentParams)\n .replace(/</g, '\\\\u003c')\n .replace(/>/g, '\\\\u003e');\n\n const defsJson = JSON.stringify(paramDefs)\n .replace(/</g, '\\\\u003c')\n .replace(/>/g, '\\\\u003e');\n\n const controlsScript = showControls\n ? `\n // Load Tweakpane for controls\n async function loadTweakpane() {\n if (window.Tweakpane) return window.Tweakpane;\n return new Promise((resolve, reject) => {\n const script = document.createElement('script');\n script.src = 'https://cdn.jsdelivr.net/npm/tweakpane@4.0.5/dist/tweakpane.min.js';\n script.onload = () => resolve(window.Tweakpane);\n script.onerror = reject;\n document.head.appendChild(script);\n });\n }\n\n async function createControls(params, defs, container) {\n try {\n const Tweakpane = await loadTweakpane();\n const pane = new Tweakpane.Pane({\n title: '${className} Controls',\n container,\n });\n\n for (const [key, def] of Object.entries(defs)) {\n const config = { label: def.label || key };\n if (def.type === 'number') {\n if (def.min !== undefined) config.min = def.min;\n if (def.max !== undefined) config.max = def.max;\n if (def.step !== undefined) config.step = def.step;\n }\n if (def.type === 'select' && def.options) {\n config.options = def.options.reduce((acc, opt) => {\n const val = typeof opt === 'object' ? opt.value : opt;\n const label = typeof opt === 'object' ? opt.label : opt;\n acc[label] = val;\n return acc;\n }, {});\n }\n try {\n pane.addBinding(params, key, config);\n } catch (e) {\n console.warn('Failed to add control:', key, e);\n }\n }\n\n return pane;\n } catch (e) {\n console.warn('Failed to load Tweakpane:', e);\n return null;\n }\n }\n `\n : '';\n\n return `\n/**\n * ${className} Web Component\n * Generated by HyperTool SDK\n */\n\n(function() {\n 'use strict';\n\n const __PARAMS__ = ${paramsJson};\n const __PARAM_DEFS__ = ${defsJson};\n const __SHOW_CONTROLS__ = ${showControls};\n const __BACKGROUND__ = '${background}';\n\n ${controlsScript}\n\n class ${className}Element extends HTMLElement {\n #mount = null;\n #params = null;\n #cleanup = null;\n #resizeObserver = null;\n #pane = null;\n #isReady = false;\n\n constructor() {\n super();\n this.attachShadow({ mode: 'open' });\n }\n\n static get observedAttributes() {\n return ['autoplay', 'background', ...Object.keys(__PARAM_DEFS__)];\n }\n\n connectedCallback() {\n this.#render();\n this.#initialize();\n }\n\n disconnectedCallback() {\n this.#destroy();\n }\n\n attributeChangedCallback(name, oldValue, newValue) {\n if (oldValue === newValue) return;\n\n if (name === 'background') {\n if (this.#mount) {\n this.#mount.style.background = newValue || __BACKGROUND__;\n }\n return;\n }\n\n if (name in __PARAM_DEFS__ && this.#params) {\n this.#params[name] = this.#parseAttribute(newValue, __PARAM_DEFS__[name].type);\n }\n }\n\n #render() {\n this.shadowRoot.innerHTML = \\`\n <style>\n :host {\n display: block;\n width: 100%;\n height: 100%;\n position: relative;\n }\n .mount {\n width: 100%;\n height: 100%;\n position: relative;\n overflow: hidden;\n background: \\${__BACKGROUND__};\n }\n .controls-container {\n position: absolute;\n top: 8px;\n right: 8px;\n z-index: 1000;\n }\n </style>\n <div class=\"mount\"></div>\n \\${__SHOW_CONTROLS__ ? '<div class=\"controls-container\"></div>' : ''}\n \\`;\n\n this.#mount = this.shadowRoot.querySelector('.mount');\n }\n\n async #initialize() {\n // Initialize params from defaults + attributes\n this.#params = { ...__PARAMS__ };\n\n for (const [key, def] of Object.entries(__PARAM_DEFS__)) {\n const attrValue = this.getAttribute(key);\n if (attrValue !== null) {\n this.#params[key] = this.#parseAttribute(attrValue, def.type);\n }\n }\n\n // Create reactive proxy\n const self = this;\n this.#params = new Proxy(this.#params, {\n set(target, prop, value) {\n const previous = target[prop];\n target[prop] = value;\n if (previous !== value) {\n self.dispatchEvent(new CustomEvent('paramchange', {\n detail: { key: prop, value, previousValue: previous },\n bubbles: true,\n }));\n }\n return true;\n }\n });\n\n // Setup resize observer\n this.#resizeObserver = new ResizeObserver(() => {\n this.dispatchEvent(new CustomEvent('resize', {\n detail: {\n width: this.#mount.clientWidth,\n height: this.#mount.clientHeight\n },\n bubbles: true,\n }));\n });\n this.#resizeObserver.observe(this.#mount);\n\n // Setup controls if enabled\n if (__SHOW_CONTROLS__) {\n const controlsContainer = this.shadowRoot.querySelector('.controls-container');\n if (controlsContainer && typeof createControls === 'function') {\n this.#pane = await createControls(this.#params, __PARAM_DEFS__, controlsContainer);\n }\n }\n\n // Run experience setup\n try {\n const context = {\n mount: this.#mount,\n params: this.#params,\n exports: {\n captureImage: (format) => this.captureImage(format),\n setFilename: () => {},\n useDefaultCanvasCapture: () => {},\n },\n environment: {\n window,\n document,\n onResize: (cb) => {\n const handler = () => cb(this.#mount.clientWidth, this.#mount.clientHeight);\n handler();\n const ro = new ResizeObserver(handler);\n ro.observe(this.#mount);\n return () => ro.disconnect();\n },\n },\n registerObject: () => {},\n };\n\n // Execute bundled code\n ${escapeForJS(bundledCode)}\n\n // Call setup if defined\n if (typeof window.__hypertool_setup__ === 'function') {\n this.#cleanup = await window.__hypertool_setup__(context);\n } else if (typeof setup === 'function') {\n this.#cleanup = await setup(context);\n }\n\n this.#isReady = true;\n this.dispatchEvent(new CustomEvent('ready', { bubbles: true }));\n\n // Autoplay by default\n if (this.getAttribute('autoplay') !== 'false') {\n this.play();\n }\n } catch (error) {\n console.error('[${className}] Setup error:', error);\n this.dispatchEvent(new CustomEvent('error', {\n detail: { error },\n bubbles: true,\n }));\n }\n }\n\n #destroy() {\n if (this.#cleanup && typeof this.#cleanup === 'function') {\n try {\n this.#cleanup();\n } catch (e) {\n console.error('[${className}] Cleanup error:', e);\n }\n }\n this.#resizeObserver?.disconnect();\n this.#pane?.dispose();\n this.#cleanup = null;\n this.#params = null;\n this.#isReady = false;\n }\n\n #parseAttribute(value, type) {\n switch (type) {\n case 'number':\n return parseFloat(value);\n case 'boolean':\n return value === 'true' || value === '';\n case 'color':\n return value;\n default:\n return value;\n }\n }\n\n // Public API\n get isReady() { return this.#isReady; }\n\n setParam(key, value) {\n if (this.#params && key in __PARAM_DEFS__) {\n this.#params[key] = value;\n this.#pane?.refresh();\n }\n }\n\n setParams(params) {\n if (!this.#params) return;\n for (const [key, value] of Object.entries(params)) {\n if (key in __PARAM_DEFS__) {\n this.#params[key] = value;\n }\n }\n this.#pane?.refresh();\n }\n\n getParams() {\n return this.#params ? { ...this.#params } : {};\n }\n\n getParamDefs() {\n return __PARAM_DEFS__;\n }\n\n async captureImage(format = 'png') {\n const canvas = this.#mount?.querySelector('canvas');\n if (!canvas) return null;\n\n return new Promise((resolve) => {\n canvas.toBlob(resolve, \\`image/\\${format}\\`, format === 'jpeg' ? 0.92 : undefined);\n });\n }\n\n play() {\n this.dispatchEvent(new CustomEvent('play', { bubbles: true }));\n }\n\n pause() {\n this.dispatchEvent(new CustomEvent('pause', { bubbles: true }));\n }\n }\n\n // Register custom element\n if (!customElements.get('${tagName}')) {\n customElements.define('${tagName}', ${className}Element);\n }\n})();\n`;\n}\n\n/**\n * Generate TypeScript definitions for the web component\n */\nexport function generateTypeDefinitions(options: WebComponentOptions): string {\n const { className, tagName, paramDefs } = options;\n\n const paramTypes = Object.entries(paramDefs)\n .map(([key, def]) => {\n let type: string;\n switch (def.type) {\n case 'number':\n type = 'number';\n break;\n case 'boolean':\n type = 'boolean';\n break;\n case 'color':\n case 'string':\n type = 'string';\n break;\n case 'select':\n if (def.options) {\n type = def.options\n .map((opt) => `'${typeof opt === 'object' ? opt.value : opt}'`)\n .join(' | ');\n } else {\n type = 'string';\n }\n break;\n default:\n type = 'unknown';\n }\n return ` ${key}?: ${type};`;\n })\n .join('\\n');\n\n return `/**\n * TypeScript definitions for ${className}\n * Generated by HyperTool SDK\n */\n\ndeclare namespace JSX {\n interface IntrinsicElements {\n '${tagName}': ${className}Attributes;\n }\n}\n\ninterface ${className}Attributes {\n autoplay?: boolean | 'true' | 'false';\n background?: string;\n${paramTypes}\n}\n\ninterface ${className}Element extends HTMLElement {\n readonly isReady: boolean;\n setParam(key: string, value: unknown): void;\n setParams(params: Record<string, unknown>): void;\n getParams(): Record<string, unknown>;\n getParamDefs(): Record<string, { type: string; value: unknown; [key: string]: unknown }>;\n captureImage(format?: 'png' | 'jpeg' | 'webp'): Promise<Blob | null>;\n play(): void;\n pause(): void;\n}\n\ninterface ${className}Events {\n ready: CustomEvent<void>;\n error: CustomEvent<{ error: Error }>;\n paramchange: CustomEvent<{ key: string; value: unknown; previousValue: unknown }>;\n resize: CustomEvent<{ width: number; height: number }>;\n play: CustomEvent<void>;\n pause: CustomEvent<void>;\n}\n`;\n}\n",
|
|
7
|
+
"/**\n * Design tokens inherited from the parent Studio application\n * These CSS variables are defined in src/app/globals.css\n */\nexport const studioTheme = {\n // CSS variables that should be available in the iframe\n cssVariables: {\n '--bg': '#0a0e14',\n '--bg-elevated': '#0f1419',\n '--muted': '#1a2332',\n '--text': '#e6edf3',\n '--text-secondary': '#8b949e',\n '--accent': '#58d5ff',\n '--accent-2': '#42a5cc',\n '--border': '#21262d',\n '--border-hover': '#30363d',\n '--success': '#3fb950',\n '--error': '#f85149',\n\n // Hypertool-specific variables\n '--ht-text-color-main-200': '#00ffd4',\n '--ht-text-color-main-300': '#6ff3dd',\n '--ht-text-color-main-500': '#4b8e85',\n '--ht-text-color-grey-200': '#8c8d8f',\n\n '--ht-bg-color-200': '#8c8d8f',\n '--ht-bg-color-200-active': '#7a7b7d',\n '--ht-bg-color-200-focus': '#7e7f81',\n '--ht-bg-color-200-hover': '#828384',\n\n '--ht-bg-color-300': '#5e6068',\n '--ht-bg-color-300-active': '#4c4e56',\n '--ht-bg-color-300-focus': '#55575f',\n '--ht-bg-color-300-hover': '#595b63',\n\n '--ht-bg-color-400': '#cccccc',\n '--ht-bg-color-400-active': '#b3b3b3',\n '--ht-bg-color-400-focus': '#c0c0c0',\n '--ht-bg-color-400-hover': '#c6c6c6',\n\n '--ht-bg-color-500': '#1C1D20',\n '--ht-bg-color-500-active': '#0a0b0e',\n '--ht-bg-color-500-focus': '#131417',\n '--ht-bg-color-500-hover': '#16171a',\n\n '--ht-bg-color-600': '#37383D',\n '--ht-bg-color-600-active': '#25262b',\n '--ht-bg-color-600-focus': '#2e2f34',\n '--ht-bg-color-600-hover': '#323338',\n\n '--ht-bg-color-700': '#0f1419',\n '--ht-bg-color-700-active': '#16171c',\n '--ht-bg-color-700-focus': '#1f2025',\n '--ht-bg-color-700-hover': '#232429',\n\n '--ht-border-radius': '8px',\n\n '--ht-base-font-family-base': '\"HydrogenType400\", ui-sans-serif, system-ui, sans-serif',\n '--ht-base-font-family-display': '\"Departure Mono\", Roboto Mono, Source Code Pro, Menlo, Courier, monospace',\n '--ht-base-font-family-sans': '\"Routed Gothic\", ui-sans-serif, system-ui, sans-serif',\n '--ht-base-font-family-mono': '\"Routed Gothic Narrow\", ui-monospace, SFMono-Regular, SF Mono, Consolas, Liberation Mono, Menlo, monospace',\n },\n\n // Tweakpane-specific theme variables\n tweakpane: {\n '--tp-base-background-color': 'var(--ht-bg-color-700)',\n '--tp-base-shadow-color': 'hsla(0, 0%, 0%, 0.2)',\n\n '--tp-container-background-color': 'var(--ht-bg-color-600)',\n '--tp-container-background-color-active': 'var(--ht-bg-color-600-active)',\n '--tp-container-background-color-focus': 'var(--ht-bg-color-600-focus)',\n '--tp-container-background-color-hover': 'var(--ht-bg-color-600-hover)',\n '--tp-container-foreground-color': 'var(--ht-text-color-main-300)',\n\n '--tp-button-background-color': 'var(--ht-bg-color-400)',\n '--tp-button-background-color-active': 'color-mix(in srgb, var(--ht-bg-color-400-active) 80%, white)',\n '--tp-button-background-color-focus': 'color-mix(in srgb, var(--ht-bg-color-400-focus) 85%, white)',\n '--tp-button-background-color-hover': 'color-mix(in srgb, var(--ht-bg-color-400-hover) 90%, white)',\n '--tp-button-foreground-color': 'var(--ht-text-color-main-300)',\n\n '--tp-groove-foreground-color': 'var(--ht-bg-color-300)',\n\n '--tp-input-background-color': 'var(--ht-bg-color-500)',\n '--tp-input-background-color-active': 'var(--ht-bg-color-500-active)',\n '--tp-input-background-color-focus': 'var(--ht-bg-color-500-focus)',\n '--tp-input-background-color-hover': 'var(--ht-bg-color-500-hover)',\n '--tp-input-foreground-color': 'var(--ht-text-color-main-300)',\n\n '--tp-label-foreground-color': 'var(--ht-text-color-main-300)',\n\n '--tp-monitor-background-color': 'var(--ht-bg-color-500)',\n '--tp-monitor-foreground-color': 'var(--ht-text-color-main-300)',\n }\n};\n\n/**\n * Inject CSS variables into the document\n */\nexport function injectThemeVariables() {\n const style = document.createElement('style');\n style.id = 'hypertool-theme';\n\n const cssVars = Object.entries({\n ...studioTheme.cssVariables,\n ...studioTheme.tweakpane\n })\n .map(([key, value]) => ` ${key}: ${value};`)\n .join('\\n');\n\n style.textContent = `\n body {\n margin: 0;\n padding: 0;\n }\n\n:root {\n${cssVars}\n}\n\n/* Controls panel positioning and styling */\n.controls-container {\n position: fixed;\n top: 8px;\n right: 8px;\n z-index: 1000;\n max-height: calc(100vh - 16px);\n overflow-y: auto;\n}\n\n/* Ensure Tweakpane pane has background */\n.tp-dfwv {\n background-color: var(--tp-base-background-color, #0f1419) !important;\n}\n`;\n\n document.head.appendChild(style);\n}",
|
|
8
|
+
"/**\n * Export Runtime Generator\n *\n * Generates the __hypertool__ runtime replacement for standalone exports.\n * This provides the same API as the studio runtime but creates a web component\n * instead of connecting to studio controls.\n *\n * Used by both export and preview endpoints.\n */\n\nexport interface ExportRuntimeOptions {\n /** Component tag name (kebab-case, e.g., 'my-experience') */\n tagName: string;\n\n /** Current parameter values to bake into the export */\n currentParams?: Record<string, unknown>;\n\n /** Whether to include Tweakpane controls panel */\n showControls?: boolean;\n\n /** Controls panel title (defaults to tagName) */\n controlsTitle?: string;\n\n /** Background color for the component */\n background?: string;\n}\n\n/**\n * Safely serialize params for injection into JavaScript code\n * Escapes characters that could break script context\n */\nfunction safeJsonStringify(obj: unknown): string {\n const json = JSON.stringify(obj);\n return json\n .replace(/</g, '\\\\u003c') // Prevent </script> injection\n .replace(/>/g, '\\\\u003e') // Prevent tag injection\n .replace(/\\u2028/g, '\\\\u2028') // Line separator\n .replace(/\\u2029/g, '\\\\u2029'); // Paragraph separator\n}\n\n// Import theme from controls module - single source of truth\nimport { studioTheme } from '../controls/theme';\n\n/**\n * Generate theme CSS string from studioTheme object\n * Converts the theme variables to CSS that works in Shadow DOM\n */\nfunction generateThemeCSS(): string {\n const cssVars = Object.entries({\n ...studioTheme.cssVariables,\n ...studioTheme.tweakpane\n })\n .map(([key, value]) => ` ${key}: ${value};`)\n .join('\\n');\n\n return `\n/* Hypertool Theme - generated from studioTheme */\n:host {\n${cssVars}\n}\n\n/* Ensure Tweakpane uses our theme */\n.tp-dfwv {\n background-color: var(--tp-base-background-color) !important;\n border-radius: 8px;\n}\n`;\n}\n\n/**\n * Generate controls-related code (Tweakpane loaded from esm.sh CDN)\n */\nfunction generateControlsCode(controlsTitle: string): string {\n const themeCSS = generateThemeCSS();\n\n return `\n// Tweakpane loaded dynamically from esm.sh CDN at runtime\nlet __Pane__: any = null;\n\nasync function __loadTweakpane__(): Promise<void> {\n if (__Pane__) return;\n try {\n const module = await import('https://esm.sh/tweakpane@4');\n __Pane__ = module.Pane;\n } catch (e) {\n console.warn('[Controls] Failed to load Tweakpane from CDN:', e);\n }\n}\n\nconst __THEME_CSS__ = \\`${themeCSS}\\`;\n\nasync function __createControls__(params: Record<string, unknown>, defs: Record<string, any>, container: HTMLElement, shadowRoot: ShadowRoot) {\n await __loadTweakpane__();\n if (!__Pane__) return null;\n\n try {\n const pane = new __Pane__({\n title: '${controlsTitle}',\n container,\n });\n\n for (const [key, def] of Object.entries(defs)) {\n if (!def || def.type === 'folder') continue;\n\n const config: Record<string, unknown> = { label: def.label || key };\n\n if (def.type === 'number') {\n if (def.min !== undefined) config.min = def.min;\n if (def.max !== undefined) config.max = def.max;\n if (def.step !== undefined) config.step = def.step;\n }\n\n if (def.type === 'select' && def.options) {\n config.options = def.options.reduce((acc: Record<string, unknown>, opt: unknown) => {\n const val = typeof opt === 'object' && opt !== null ? (opt as any).value : opt;\n const label = typeof opt === 'object' && opt !== null ? (opt as any).label : String(opt);\n acc[label] = val;\n return acc;\n }, {});\n }\n\n try {\n pane.addBinding(params, key, config);\n } catch (e) {\n console.warn('[Controls] Failed to add binding for:', key, e);\n }\n }\n\n // Tweakpane injects CSS into document.head - copy it to shadow root for isolation\n setTimeout(() => {\n const tpStyles = document.querySelectorAll('style');\n tpStyles.forEach(style => {\n if (style.textContent?.includes('.tp-') || style.textContent?.includes('tp-dfwv')) {\n const clone = style.cloneNode(true) as HTMLStyleElement;\n shadowRoot.appendChild(clone);\n }\n });\n }, 0);\n\n return pane;\n } catch (e) {\n console.warn('[Controls] Failed to create controls:', e);\n return null;\n }\n}\n`;\n}\n\n/**\n * Generate draggable controls functionality\n */\nfunction generateDraggableCode(): string {\n return `\n// Make controls panel draggable\nfunction __setupDraggable__(container, pane) {\n if (!pane || !pane.element) return;\n\n const titleEl = pane.element.querySelector('.tp-rotv_t');\n if (!titleEl) return;\n\n let isDragging = false;\n let startX = 0;\n let startY = 0;\n let initialRight = 8;\n let initialTop = 8;\n\n titleEl.style.cursor = 'grab';\n\n titleEl.addEventListener('mousedown', (e) => {\n if (e.button !== 0) return;\n isDragging = true;\n startX = e.clientX;\n startY = e.clientY;\n\n const style = getComputedStyle(container);\n initialRight = parseInt(style.right) || 8;\n initialTop = parseInt(style.top) || 8;\n\n titleEl.style.cursor = 'grabbing';\n e.preventDefault();\n });\n\n document.addEventListener('mousemove', (e) => {\n if (!isDragging) return;\n\n const deltaX = e.clientX - startX;\n const deltaY = e.clientY - startY;\n\n container.style.right = Math.max(0, initialRight - deltaX) + 'px';\n container.style.top = Math.max(0, initialTop + deltaY) + 'px';\n });\n\n document.addEventListener('mouseup', () => {\n if (isDragging) {\n isDragging = false;\n titleEl.style.cursor = 'grab';\n }\n });\n}\n`;\n}\n\n/**\n * Generate the export-friendly __hypertool__ runtime\n *\n * This provides the same API as the studio runtime but creates a web component\n * instead of connecting to studio controls.\n */\nexport function generateExportRuntime(options: ExportRuntimeOptions): string {\n const {\n tagName,\n currentParams = {},\n showControls = false,\n controlsTitle,\n background = 'transparent',\n } = options;\n\n const currentParamsJson = safeJsonStringify(currentParams);\n const title = controlsTitle || tagName.split('-').map(s => s.charAt(0).toUpperCase() + s.slice(1)).join(' ');\n\n const controlsCode = showControls ? generateControlsCode(title) : '';\n const draggableCode = showControls ? generateDraggableCode() : '';\n const controlsContainerHtml = showControls\n ? `<div class=\"controls-container\"></div>`\n : '';\n const controlsContainerStyle = showControls\n ? `\n .controls-container {\n position: absolute;\n top: 8px;\n right: 8px;\n z-index: 1000;\n max-height: calc(100% - 16px);\n overflow-y: auto;\n }\n /* Tweakpane theme overrides */\n .controls-container .tp-dfwv {\n background-color: rgba(15, 20, 25, 0.95) !important;\n }\n `\n : '';\n\n return `\n// Export-friendly HyperTool Runtime\n// Generated by @hypertool/sdk\n// Controls: ${showControls ? 'enabled' : 'disabled'}\n\n// Baked-in current params from export\nconst __BAKED_PARAMS__ = ${currentParamsJson};\nconst __SHOW_CONTROLS__ = ${showControls};\nconst __BACKGROUND__ = '${background}';\n\n${controlsCode}\n${draggableCode}\n\nexport type ControlDefinitions = Record<string, {\n type: string;\n value: unknown;\n label?: string;\n min?: number;\n max?: number;\n step?: number;\n options?: unknown[];\n}>;\n\nexport interface SandboxContext {\n mount: HTMLElement;\n params: Record<string, unknown>;\n exports: {\n setFilename: (name: string) => void;\n useDefaultCanvasCapture: (use: boolean) => void;\n captureImage: () => Promise<Blob>;\n };\n environment: {\n onResize: (callback: () => void) => () => void;\n window: Window;\n document: Document;\n };\n controls: null;\n}\n\ninterface SandboxConfig {\n controls?: {\n definitions?: ControlDefinitions;\n options?: { title?: string };\n };\n exportWidget?: {\n filename?: string;\n useCanvasCapture?: boolean;\n enabled?: boolean;\n };\n setup: (context: SandboxContext) => (() => void) | void;\n}\n\n// Store for the experience definition\nlet __experienceDef__: SandboxConfig | null = null;\n\n/**\n * createSandbox - Export version\n * Instead of connecting to studio, registers a web component\n */\nexport async function createSandbox(config: SandboxConfig): Promise<void> {\n __experienceDef__ = config;\n\n // Create the web component\n class HypertoolElement extends HTMLElement {\n private _mount: HTMLElement | null = null;\n private _controlsContainer: HTMLElement | null = null;\n private _cleanup: (() => void) | void = undefined;\n private _params: Record<string, unknown> = {};\n private _pane: any = null;\n\n constructor() {\n super();\n this.attachShadow({ mode: 'open' });\n }\n\n connectedCallback() {\n if (!this.shadowRoot || !__experienceDef__) return;\n\n // Setup styles (includes theme CSS when controls enabled)\n const style = document.createElement('style');\n style.textContent = \\`\n \\${__SHOW_CONTROLS__ && typeof __THEME_CSS__ !== 'undefined' ? __THEME_CSS__ : ''}\n :host { display: block; width: 100%; height: 100%; }\n .mount {\n width: 100%;\n height: 100%;\n position: relative;\n overflow: hidden;\n background: \\${__BACKGROUND__};\n }\n ${controlsContainerStyle}\n \\`;\n this.shadowRoot.appendChild(style);\n\n // Create mount\n this._mount = document.createElement('div');\n this._mount.className = 'mount';\n this.shadowRoot.appendChild(this._mount);\n\n // Create controls container if enabled\n if (__SHOW_CONTROLS__) {\n this._controlsContainer = document.createElement('div');\n this._controlsContainer.className = 'controls-container';\n this.shadowRoot.appendChild(this._controlsContainer);\n }\n\n // Initialize params: baked params > HTML attributes > definition defaults\n const defs = __experienceDef__.controls?.definitions || {};\n for (const [key, def] of Object.entries(defs)) {\n // Priority: HTML attribute > baked param > definition default\n if (this.getAttribute(key) !== null) {\n this._params[key] = this._parseAttr(key, this.getAttribute(key)!, def);\n } else if (key in __BAKED_PARAMS__) {\n this._params[key] = __BAKED_PARAMS__[key];\n } else {\n this._params[key] = def.value;\n }\n }\n\n // Make params reactive\n const self = this;\n this._params = new Proxy(this._params, {\n set: (target, prop, value) => {\n const previous = target[prop as string];\n target[prop as string] = value;\n if (previous !== value) {\n self.dispatchEvent(new CustomEvent('paramchange', {\n detail: { key: prop, value, previousValue: previous },\n bubbles: true,\n }));\n }\n return true;\n }\n });\n\n // Create context\n const context: SandboxContext = {\n mount: this._mount,\n params: this._params,\n exports: {\n setFilename: () => {},\n useDefaultCanvasCapture: () => {},\n captureImage: async () => {\n const canvas = this._mount?.querySelector('canvas');\n if (!canvas) throw new Error('No canvas found');\n return new Promise((res, rej) => {\n canvas.toBlob(b => b ? res(b) : rej(new Error('Failed to capture')));\n });\n },\n },\n environment: {\n onResize: (callback) => {\n const ro = new ResizeObserver(() => callback());\n ro.observe(this._mount!);\n return () => ro.disconnect();\n },\n window,\n document,\n },\n controls: null,\n };\n\n // Run setup\n this._cleanup = __experienceDef__.setup(context);\n\n // Setup controls if enabled (async - loads Tweakpane from CDN)\n if (__SHOW_CONTROLS__ && this._controlsContainer && typeof __createControls__ === 'function') {\n __createControls__(this._params, defs, this._controlsContainer, this.shadowRoot!).then((pane: any) => {\n this._pane = pane;\n if (this._pane && typeof __setupDraggable__ === 'function') {\n __setupDraggable__(this._controlsContainer, this._pane);\n }\n });\n }\n\n // Dispatch ready event\n this.dispatchEvent(new CustomEvent('ready', { bubbles: true }));\n }\n\n disconnectedCallback() {\n if (this._cleanup) this._cleanup();\n if (this._pane?.dispose) this._pane.dispose();\n }\n\n private _parseAttr(key: string, value: string, def: { type: string }): unknown {\n switch (def.type) {\n case 'number': return parseFloat(value);\n case 'boolean': return value === 'true' || value === '';\n default: return value;\n }\n }\n\n // Public API\n setParam(key: string, value: unknown) {\n this._params[key] = value;\n this._pane?.refresh();\n }\n setParams(params: Record<string, unknown>) {\n for (const [k, v] of Object.entries(params)) this._params[k] = v;\n this._pane?.refresh();\n }\n getParams() { return { ...this._params }; }\n getParamDefs() { return __experienceDef__?.controls?.definitions || {}; }\n }\n\n // Register the component\n if (!customElements.get('${tagName}')) {\n customElements.define('${tagName}', HypertoolElement);\n }\n}\n`;\n}\n\n/**\n * Generate HTML with external script reference\n */\nexport function generateExportHtml(tagName: string): string {\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>${tagName}</title>\n <style>\n * { margin: 0; padding: 0; box-sizing: border-box; }\n html, body { width: 100%; height: 100%; overflow: hidden; background: #0a0a0a; }\n ${tagName} { display: block; width: 100%; height: 100%; }\n </style>\n</head>\n<body>\n <${tagName}></${tagName}>\n <script src=\"./${tagName}.js\"></script>\n</body>\n</html>`;\n}\n\n/**\n * Generate HTML with inline script (for preview)\n * Includes permissive CSP for external library loading\n */\nexport function generatePreviewHtml(tagName: string, code: string): string {\n const cdnHosts = [\n 'https://cdnjs.cloudflare.com',\n 'https://cdn.jsdelivr.net',\n 'https://unpkg.com',\n 'https://esm.sh',\n 'https://cdn.skypack.dev',\n ].join(' ');\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'self' blob: data: ${cdnHosts}; script-src 'self' 'unsafe-inline' 'unsafe-eval' blob: data: ${cdnHosts}; style-src 'self' 'unsafe-inline' ${cdnHosts}; img-src 'self' blob: data: *; media-src 'self' blob: data: *; connect-src *; font-src 'self' data: ${cdnHosts};\">\n <title>${tagName}</title>\n <style>\n * { margin: 0; padding: 0; box-sizing: border-box; }\n html, body { width: 100%; height: 100%; overflow: hidden; background: #0a0a0a; }\n ${tagName} { display: block; width: 100%; height: 100%; }\n </style>\n</head>\n<body>\n <${tagName}></${tagName}>\n <script>\n${code}\n </script>\n</body>\n</html>`;\n}\n\n/**\n * Generate README for the exported component\n */\nexport function generateExportReadme(tagName: string, className: string): string {\n return `# ${className}\n\n## Usage\n\n\\`\\`\\`html\n<script src=\"${tagName}.js\"></script>\n<${tagName}></${tagName}>\n\\`\\`\\`\n\n## API\n\n\\`\\`\\`javascript\nconst el = document.querySelector('${tagName}');\n\n// Set parameters\nel.setParam('paramName', value);\nel.setParams({ param1: value1, param2: value2 });\n\n// Get current parameters\nconst params = el.getParams();\n\n// Get parameter definitions\nconst defs = el.getParamDefs();\n\\`\\`\\`\n\n## Events\n\n\\`\\`\\`javascript\nel.addEventListener('ready', () => console.log('Ready!'));\nel.addEventListener('paramchange', (e) => {\n console.log('Param changed:', e.detail.key, e.detail.value);\n});\n\\`\\`\\`\n\n## Files\n\n- \\`${tagName}.js\\` - The bundled component\n- \\`index.html\\` - Example page (loads external JS)\n- \\`preview.html\\` - Standalone preview (inline JS)\n`;\n}\n\n/**\n * Generate TypeScript type definitions\n */\nexport function generateExportTypes(tagName: string, className: string): string {\n return `export interface ${className}Element extends HTMLElement {\n setParam(key: string, value: unknown): void;\n setParams(params: Record<string, unknown>): void;\n getParams(): Record<string, unknown>;\n getParamDefs(): Record<string, { type: string; value: unknown; [key: string]: unknown }>;\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n '${tagName}': ${className}Element;\n }\n}\n`;\n}\n"
|
|
9
|
+
],
|
|
10
|
+
"mappings": "4XAqDA,eAAsB,CAAc,CAAC,EAA+C,CAElF,IAAI,EACJ,GAAI,CACF,EAAU,KAAa,mBACvB,KAAM,CACN,MAAU,MACR,sEACF,EAGF,IAAQ,UAAS,YAAW,WAAU,KAAI,SAAU,KAAa,wBACzD,UAAW,KAAa,eACxB,OAAM,WAAY,KAAa,gBAEjC,EAAU,MAAM,EAAQ,EAAK,EAAO,EAAG,mBAAmB,CAAC,EAEjE,GAAI,CAEF,GAAI,EAAQ,MACV,QAAY,EAAU,KAAY,OAAO,QAAQ,EAAQ,KAAK,EAAG,CAC/D,IAAM,EAAW,EAAK,EAAS,EAAS,QAAQ,MAAO,EAAE,CAAC,EACpD,EAAM,EAAQ,CAAQ,EAC5B,MAAM,EAAM,EAAK,CAAE,UAAW,EAAK,CAAC,EACpC,MAAM,EAAU,EAAU,CAAO,EAKrC,IAAI,EACJ,GAAI,OAAO,EAAQ,QAAU,SAC3B,EAAY,EAAK,EAAS,EAAQ,MAAM,QAAQ,MAAO,EAAE,CAAC,EACrD,KACL,IAAM,EAAW,EAAQ,MAAM,UAAY,WAC3C,EAAY,EAAK,EAAS,CAAQ,EAClC,MAAM,EAAU,EAAW,EAAQ,MAAM,IAAI,EAI/C,IAAM,EAAS,MAAM,EAAQ,MAAM,CACjC,YAAa,CAAC,CAAS,EACvB,OAAQ,GACR,QAAS,EAAK,EAAS,QAAQ,EAC/B,SAAU,EAAQ,SAAW,OAAS,OAAS,UAC/C,OAAQ,EAAQ,QAAU,OAC1B,OAAQ,EAAQ,QAAU,GAC1B,UAAW,EAAQ,UAAY,WAAa,GAC5C,WAAY,EAAQ,WACpB,SAAU,EAAQ,SAClB,OAAQ,EAAQ,OAChB,MAAO,GACP,SAAU,EACZ,CAAC,EAGK,EAAO,MAAM,EAAS,EAAK,EAAS,QAAQ,EAAG,OAAO,EACxD,EAEJ,GAAI,EAAQ,UACV,GAAI,CACF,EAAM,MAAM,EAAS,EAAK,EAAS,YAAY,EAAG,OAAO,EACzD,KAAM,EAKV,MAAO,CACL,OACA,MACA,SAAU,EAAO,SAAS,IAAI,CAAC,IAAwB,EAAE,IAAI,EAC7D,KAAM,OAAO,WAAW,EAAM,OAAO,CACvC,SACA,CAEA,MAAM,EAAG,EAAS,CAAE,UAAW,GAAM,MAAO,EAAK,CAAC,GAO/C,SAAS,CAAgB,CAC9B,EACyD,CAMzD,GAAI,CAJU,EAAK,MACjB,sFACF,EAEY,OAAO,KAEnB,GAAI,CAGF,OAAO,KACP,KAAM,CACN,OAAO,MAOJ,SAAS,CAAa,CAAC,EAAsB,CAClD,MAAO;AAAA,EACP;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EC9HF,SAAS,CAAW,CAAC,EAAqB,CACxC,OAAO,EACJ,QAAQ,MAAO,MAAM,EACrB,QAAQ,KAAM,KAAK,EACnB,QAAQ,MAAO,KAAK,EACpB,QAAQ,eAAgB,aAAa,EAMnC,SAAS,CAAoB,CAAC,EAAsC,CACzE,IACE,UACA,YACA,cACA,YACA,gBAAgB,CAAC,EACjB,eAAe,GACf,aAAa,eACX,EAGE,EAAa,KAAK,UAAU,CAAa,EAC5C,QAAQ,KAAM,SAAS,EACvB,QAAQ,KAAM,SAAS,EAEpB,EAAW,KAAK,UAAU,CAAS,EACtC,QAAQ,KAAM,SAAS,EACvB,QAAQ,KAAM,SAAS,EAEpB,EAAiB,EACnB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAiBc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAiCd,GAEJ,MAAO;AAAA;AAAA,KAEJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,uBAOkB;AAAA,2BACI;AAAA,8BACG;AAAA,4BACF;AAAA;AAAA,IAExB;AAAA;AAAA,UAEM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,UA+IA,EAAY,CAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,0BAiBP;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,4BAaE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,6BAsEC;AAAA,6BACA,OAAa;AAAA;AAAA;AAAA,EASnC,SAAS,CAAuB,CAAC,EAAsC,CAC5E,IAAQ,YAAW,UAAS,aAAc,EAEpC,EAAa,OAAO,QAAQ,CAAS,EACxC,IAAI,EAAE,EAAK,KAAS,CACnB,IAAI,EACJ,OAAQ,EAAI,UACL,SACH,EAAO,SACP,UACG,UACH,EAAO,UACP,UACG,YACA,SACH,EAAO,SACP,UACG,SACH,GAAI,EAAI,QACN,EAAO,EAAI,QACR,IAAI,CAAC,IAAQ,IAAI,OAAO,IAAQ,SAAW,EAAI,MAAQ,IAAM,EAC7D,KAAK,KAAK,EAEb,OAAO,SAET,cAEA,EAAO,UAEX,MAAO,KAAK,OAAS,KACtB,EACA,KAAK;AAAA,CAAI,EAEZ,MAAO;AAAA,gCACuB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,OAMzB,OAAa;AAAA;AAAA;AAAA;AAAA,YAIR;AAAA;AAAA;AAAA,EAGV;AAAA;AAAA;AAAA,YAGU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YAWA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EC1bL,IAAM,EAAc,CAEzB,aAAc,CACZ,OAAQ,UACR,gBAAiB,UACjB,UAAW,UACX,SAAU,UACV,mBAAoB,UACpB,WAAY,UACZ,aAAc,UACd,WAAY,UACZ,iBAAkB,UAClB,YAAa,UACb,UAAW,UAGX,2BAA4B,UAC5B,2BAA4B,UAC5B,2BAA4B,UAC5B,2BAA4B,UAE5B,oBAAqB,UACrB,2BAA4B,UAC5B,0BAA2B,UAC3B,0BAA2B,UAE3B,oBAAqB,UACrB,2BAA4B,UAC5B,0BAA2B,UAC3B,0BAA2B,UAE3B,oBAAqB,UACrB,2BAA4B,UAC5B,0BAA2B,UAC3B,0BAA2B,UAE3B,oBAAqB,UACrB,2BAA4B,UAC5B,0BAA2B,UAC3B,0BAA2B,UAE3B,oBAAqB,UACrB,2BAA4B,UAC5B,0BAA2B,UAC3B,0BAA2B,UAE3B,oBAAqB,UACrB,2BAA4B,UAC5B,0BAA2B,UAC3B,0BAA2B,UAE3B,qBAAsB,MAEtB,6BAA8B,0DAC9B,gCAAiC,4EACjC,6BAA8B,wDAC9B,6BAA8B,4GAChC,EAGA,UAAW,CACT,6BAA8B,yBAC9B,yBAA0B,uBAE1B,kCAAmC,yBACnC,yCAA0C,gCAC1C,wCAAyC,+BACzC,wCAAyC,+BACzC,kCAAmC,gCAEnC,+BAAgC,yBAChC,sCAAuC,+DACvC,qCAAsC,8DACtC,qCAAsC,8DACtC,+BAAgC,gCAEhC,+BAAgC,yBAEhC,8BAA+B,yBAC/B,qCAAsC,gCACtC,oCAAqC,+BACrC,oCAAqC,+BACrC,8BAA+B,gCAE/B,8BAA+B,gCAE/B,gCAAiC,yBACjC,gCAAiC,+BACnC,CACF,EC9DA,SAAS,CAAiB,CAAC,EAAsB,CAE/C,OADa,KAAK,UAAU,CAAG,EAE5B,QAAQ,KAAM,SAAS,EACvB,QAAQ,KAAM,SAAS,EACvB,QAAQ,UAAW,SAAS,EAC5B,QAAQ,UAAW,SAAS,EAUjC,SAAS,CAAgB,EAAW,CAQlC,MAAO;AAAA;AAAA;AAAA,EAPS,OAAO,QAAQ,IAC1B,EAAY,gBACZ,EAAY,SACjB,CAAC,EACE,IAAI,EAAE,EAAK,KAAW,KAAK,MAAQ,IAAQ,EAC3C,KAAK;AAAA,CAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmBd,SAAS,CAAoB,CAAC,EAA+B,CAG3D,MAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,0BAFU,EAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAwBpB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAsDhB,SAAS,CAAqB,EAAW,CACvC,MAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAwDF,SAAS,CAAqB,CAAC,EAAuC,CAC3E,IACE,UACA,gBAAgB,CAAC,EACjB,eAAe,GACf,gBACA,aAAa,eACX,EAEE,EAAoB,EAAkB,CAAa,EACnD,EAAQ,GAAiB,EAAQ,MAAM,GAAG,EAAE,IAAI,KAAK,EAAE,OAAO,CAAC,EAAE,YAAY,EAAI,EAAE,MAAM,CAAC,CAAC,EAAE,KAAK,GAAG,EAErG,EAAe,EAAe,EAAqB,CAAK,EAAI,GAC5D,EAAgB,EAAe,EAAsB,EAAI,GACzD,EAAwB,EAC1B,yCACA,GAkBJ,MAAO;AAAA;AAAA;AAAA,eAGM,EAAe,UAAY;AAAA;AAAA;AAAA,2BAGf;AAAA,4BACC;AAAA,0BACF;AAAA;AAAA,EAExB;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,UA5B+B,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAcA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,6BAgNuB;AAAA,6BACA;AAAA;AAAA;AAAA,EAStB,SAAS,CAAkB,CAAC,EAAyB,CAC1D,MAAO;AAAA;AAAA;AAAA;AAAA;AAAA,WAKE;AAAA;AAAA;AAAA;AAAA,MAIL;AAAA;AAAA;AAAA;AAAA,KAID,OAAa;AAAA,mBACC;AAAA;AAAA,SASZ,SAAS,CAAmB,CAAC,EAAiB,EAAsB,CACzE,IAAM,EAAW,CACf,+BACA,2BACA,oBACA,iBACA,yBACF,EAAE,KAAK,GAAG,EAEV,MAAO;AAAA;AAAA;AAAA;AAAA;AAAA,uFAK8E,kEAAyE,uCAA8C,yGAAgH;AAAA,WACnT;AAAA;AAAA;AAAA;AAAA,MAIL;AAAA;AAAA;AAAA;AAAA,KAID,OAAa;AAAA;AAAA,EAEhB;AAAA;AAAA;AAAA,SASK,SAAS,CAAoB,CAAC,EAAiB,EAA2B,CAC/E,MAAO,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA,eAKC;AAAA,GACZ,OAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qCAMqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAwB/B;AAAA;AAAA;AAAA,EASC,SAAS,CAAmB,CAAC,EAAiB,EAA2B,CAC9E,MAAO,oBAAoB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,OAStB,OAAa;AAAA;AAAA;",
|
|
11
|
+
"debugId": "8BED4B1E577CB55764756E2164756E21",
|
|
12
|
+
"names": []
|
|
13
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import type { ControlDefinitions, HypertoolControlsOptions, ParameterValues } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* HypertoolControls - A styled Tweakpane wrapper that inherits Studio theme
|
|
4
|
+
*/
|
|
5
|
+
export declare class HypertoolControls<T extends ControlDefinitions = ControlDefinitions> {
|
|
6
|
+
private pane;
|
|
7
|
+
private definitions;
|
|
8
|
+
private options;
|
|
9
|
+
params: ParameterValues<T>;
|
|
10
|
+
constructor(definitions: T, options?: HypertoolControlsOptions<T>);
|
|
11
|
+
/**
|
|
12
|
+
* Check if a definition is a folder
|
|
13
|
+
*/
|
|
14
|
+
private isFolder;
|
|
15
|
+
/**
|
|
16
|
+
* Check if a definition is a button
|
|
17
|
+
*/
|
|
18
|
+
private isButton;
|
|
19
|
+
/**
|
|
20
|
+
* Check if a definition is a tab
|
|
21
|
+
*/
|
|
22
|
+
private isTab;
|
|
23
|
+
/**
|
|
24
|
+
* Check if a definition is a file upload
|
|
25
|
+
*/
|
|
26
|
+
private isFile;
|
|
27
|
+
/**
|
|
28
|
+
* Extract initial parameter values from control definitions
|
|
29
|
+
*/
|
|
30
|
+
private extractInitialValues;
|
|
31
|
+
/**
|
|
32
|
+
* Initialize Tweakpane with theme and controls
|
|
33
|
+
*/
|
|
34
|
+
private init;
|
|
35
|
+
/**
|
|
36
|
+
* Create the Tweakpane instance
|
|
37
|
+
*/
|
|
38
|
+
private createPane;
|
|
39
|
+
/**
|
|
40
|
+
* Resolve the container element if provided
|
|
41
|
+
*/
|
|
42
|
+
private resolveContainer;
|
|
43
|
+
/**
|
|
44
|
+
* Add controls to the pane based on definitions
|
|
45
|
+
*/
|
|
46
|
+
private addControls;
|
|
47
|
+
/**
|
|
48
|
+
* Add controls to a specific target (pane or folder)
|
|
49
|
+
*/
|
|
50
|
+
private addControlsToTarget;
|
|
51
|
+
/**
|
|
52
|
+
* Add a single control to a target (pane or folder)
|
|
53
|
+
*/
|
|
54
|
+
private addControlToTarget;
|
|
55
|
+
/**
|
|
56
|
+
* Add a custom file upload control
|
|
57
|
+
*/
|
|
58
|
+
private addFileControl;
|
|
59
|
+
/**
|
|
60
|
+
* Add a folder to organize controls
|
|
61
|
+
*/
|
|
62
|
+
addFolder(title: string): any;
|
|
63
|
+
/**
|
|
64
|
+
* Update a parameter value programmatically
|
|
65
|
+
*/
|
|
66
|
+
set(key: keyof T, value: any): void;
|
|
67
|
+
/**
|
|
68
|
+
* Get current parameter values
|
|
69
|
+
*/
|
|
70
|
+
get values(): ParameterValues<T>;
|
|
71
|
+
/**
|
|
72
|
+
* Destroy the control panel
|
|
73
|
+
*/
|
|
74
|
+
destroy(): void;
|
|
75
|
+
/**
|
|
76
|
+
* Show/hide the control panel
|
|
77
|
+
*/
|
|
78
|
+
setVisible(visible: boolean): void;
|
|
79
|
+
/**
|
|
80
|
+
* Refresh the control panel UI
|
|
81
|
+
*/
|
|
82
|
+
refresh(): void;
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=HypertoolControls.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HypertoolControls.d.ts","sourceRoot":"","sources":["../../src/controls/HypertoolControls.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,kBAAkB,EAClB,wBAAwB,EAExB,eAAe,EAMhB,MAAM,SAAS,CAAC;AAGjB;;GAEG;AACH,qBAAa,iBAAiB,CAAC,CAAC,SAAS,kBAAkB,GAAG,kBAAkB;IAC9E,QAAgB,IAAI,CAAc;IAClC,QAAgB,WAAW,CAAI;IAC/B,QAAgB,OAAO,CAAwC;IAChD,MAAM,EAAE,eAAe,CAAC,CAAC,CAAC,CAAC;gBAE9B,WAAW,EAAE,CAAC,EAAE,OAAO,GAAE,wBAAwB,CAAC,CAAC,CAAM;IAmBrE;;OAEG;IACH,OAAO,CAAC,QAAQ;IAIhB;;OAEG;IACH,OAAO,CAAC,QAAQ;IAIhB;;OAEG;IACH,OAAO,CAAC,KAAK;IAIb;;OAEG;IACH,OAAO,CAAC,MAAM;IAId;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAoB5B;;OAEG;YACW,IAAI;IAyBlB;;OAEG;IACH,OAAO,CAAC,UAAU;IAgBlB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAqBxB;;OAEG;IACH,OAAO,CAAC,WAAW;IAKnB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAqD3B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAkI1B;;OAEG;IACH,OAAO,CAAC,cAAc;IA2PtB;;OAEG;IACI,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG;IAKpC;;OAEG;IACI,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,KAAK,EAAE,GAAG;IASnC;;OAEG;IACH,IAAW,MAAM,IAAI,eAAe,CAAC,CAAC,CAAC,CAEtC;IAED;;OAEG;IACI,OAAO;IAad;;OAEG;IACI,UAAU,CAAC,OAAO,EAAE,OAAO;IAKlC;;OAEG;IACI,OAAO;CAKf"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @hypertool/runtime/controls
|
|
3
|
+
*
|
|
4
|
+
* A beautifully styled controls library for creative coding
|
|
5
|
+
* Built with Tweakpane and inherits Hypertool Studio theme
|
|
6
|
+
*/
|
|
7
|
+
export { HypertoolControls } from './HypertoolControls';
|
|
8
|
+
export { createControls, createControlPanel } from './simple-api';
|
|
9
|
+
export { injectThemeVariables, studioTheme } from './theme';
|
|
10
|
+
export type { ControlType, BaseControlDefinition, ControlDefinition, ControlDefinitions, NumberControlDefinition, ColorControlDefinition, BooleanControlDefinition, StringControlDefinition, SelectControlDefinition, HypertoolControlsOptions, ControlPosition, ParameterValues, ControlChangeContext, } from './types';
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/controls/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAClE,OAAO,EAAE,oBAAoB,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAG5D,YAAY,EAEV,WAAW,EACX,qBAAqB,EACrB,iBAAiB,EACjB,kBAAkB,EAClB,uBAAuB,EACvB,sBAAsB,EACtB,wBAAwB,EACxB,uBAAuB,EACvB,uBAAuB,EAGvB,wBAAwB,EACxB,eAAe,EAGf,eAAe,EACf,oBAAoB,GACrB,MAAM,SAAS,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import{Pane as k}from"tweakpane";var b={cssVariables:{"--bg":"#0a0e14","--bg-elevated":"#0f1419","--muted":"#1a2332","--text":"#e6edf3","--text-secondary":"#8b949e","--accent":"#58d5ff","--accent-2":"#42a5cc","--border":"#21262d","--border-hover":"#30363d","--success":"#3fb950","--error":"#f85149","--ht-text-color-main-200":"#00ffd4","--ht-text-color-main-300":"#6ff3dd","--ht-text-color-main-500":"#4b8e85","--ht-text-color-grey-200":"#8c8d8f","--ht-bg-color-200":"#8c8d8f","--ht-bg-color-200-active":"#7a7b7d","--ht-bg-color-200-focus":"#7e7f81","--ht-bg-color-200-hover":"#828384","--ht-bg-color-300":"#5e6068","--ht-bg-color-300-active":"#4c4e56","--ht-bg-color-300-focus":"#55575f","--ht-bg-color-300-hover":"#595b63","--ht-bg-color-400":"#cccccc","--ht-bg-color-400-active":"#b3b3b3","--ht-bg-color-400-focus":"#c0c0c0","--ht-bg-color-400-hover":"#c6c6c6","--ht-bg-color-500":"#1C1D20","--ht-bg-color-500-active":"#0a0b0e","--ht-bg-color-500-focus":"#131417","--ht-bg-color-500-hover":"#16171a","--ht-bg-color-600":"#37383D","--ht-bg-color-600-active":"#25262b","--ht-bg-color-600-focus":"#2e2f34","--ht-bg-color-600-hover":"#323338","--ht-bg-color-700":"#0f1419","--ht-bg-color-700-active":"#16171c","--ht-bg-color-700-focus":"#1f2025","--ht-bg-color-700-hover":"#232429","--ht-border-radius":"8px","--ht-base-font-family-base":'"HydrogenType400", ui-sans-serif, system-ui, sans-serif',"--ht-base-font-family-display":'"Departure Mono", Roboto Mono, Source Code Pro, Menlo, Courier, monospace',"--ht-base-font-family-sans":'"Routed Gothic", ui-sans-serif, system-ui, sans-serif',"--ht-base-font-family-mono":'"Routed Gothic Narrow", ui-monospace, SFMono-Regular, SF Mono, Consolas, Liberation Mono, Menlo, monospace'},tweakpane:{"--tp-base-background-color":"var(--ht-bg-color-700)","--tp-base-shadow-color":"hsla(0, 0%, 0%, 0.2)","--tp-container-background-color":"var(--ht-bg-color-600)","--tp-container-background-color-active":"var(--ht-bg-color-600-active)","--tp-container-background-color-focus":"var(--ht-bg-color-600-focus)","--tp-container-background-color-hover":"var(--ht-bg-color-600-hover)","--tp-container-foreground-color":"var(--ht-text-color-main-300)","--tp-button-background-color":"var(--ht-bg-color-400)","--tp-button-background-color-active":"color-mix(in srgb, var(--ht-bg-color-400-active) 80%, white)","--tp-button-background-color-focus":"color-mix(in srgb, var(--ht-bg-color-400-focus) 85%, white)","--tp-button-background-color-hover":"color-mix(in srgb, var(--ht-bg-color-400-hover) 90%, white)","--tp-button-foreground-color":"var(--ht-text-color-main-300)","--tp-groove-foreground-color":"var(--ht-bg-color-300)","--tp-input-background-color":"var(--ht-bg-color-500)","--tp-input-background-color-active":"var(--ht-bg-color-500-active)","--tp-input-background-color-focus":"var(--ht-bg-color-500-focus)","--tp-input-background-color-hover":"var(--ht-bg-color-500-hover)","--tp-input-foreground-color":"var(--ht-text-color-main-300)","--tp-label-foreground-color":"var(--ht-text-color-main-300)","--tp-monitor-background-color":"var(--ht-bg-color-500)","--tp-monitor-foreground-color":"var(--ht-text-color-main-300)"}};function h(){let D=document.createElement("style");D.id="hypertool-theme";let z=Object.entries({...b.cssVariables,...b.tweakpane}).map(([T,J])=>` ${T}: ${J};`).join(`
|
|
2
|
+
`);D.textContent=`
|
|
3
|
+
body {
|
|
4
|
+
margin: 0;
|
|
5
|
+
padding: 0;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
:root {
|
|
9
|
+
${z}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/* Controls panel positioning and styling */
|
|
13
|
+
.controls-container {
|
|
14
|
+
position: fixed;
|
|
15
|
+
top: 8px;
|
|
16
|
+
right: 8px;
|
|
17
|
+
z-index: 1000;
|
|
18
|
+
max-height: calc(100vh - 16px);
|
|
19
|
+
overflow-y: auto;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/* Ensure Tweakpane pane has background */
|
|
23
|
+
.tp-dfwv {
|
|
24
|
+
background-color: var(--tp-base-background-color, #0f1419) !important;
|
|
25
|
+
}
|
|
26
|
+
`,document.head.appendChild(D)}class E{constructor(D,z={}){this.pane=null,this.definitions=D,this.options={title:z.title||"Controls",position:z.position||"top-right",expanded:z.expanded!==void 0?z.expanded:!0,container:z.container!==void 0?z.container:null,onChange:z.onChange||(()=>{}),onReady:z.onReady||(()=>{})},this.params=this.extractInitialValues(D),this.init()}isFolder(D){return D&&typeof D==="object"&&(D.type==="folder"||D.type==="group")}isButton(D){return D&&typeof D==="object"&&D.type==="button"}isTab(D){return D&&typeof D==="object"&&D.type==="tab"}isFile(D){return D&&typeof D==="object"&&D.type==="file"}extractInitialValues(D){let z={};for(let[T,J]of Object.entries(D)){let F=J;if(this.isFolder(F))z[T]=this.extractInitialValues(F.controls);else if(this.isTab(F))z[T]=F.pages.map((L)=>this.extractInitialValues(L.controls));else if(this.isButton(F))continue;else z[T]=F.value}return z}async init(){try{h(),await new Promise((D)=>setTimeout(D,50)),this.createPane(),this.addControls(),this.options.onReady()}catch(D){console.error("[HypertoolControls] Initialization error:",D)}}createPane(){let D=this.resolveContainer(),z={title:this.options.title,expanded:this.options.expanded};if(D)z.container=D;this.pane=new k(z),this.pane.element.parentElement?.classList.add("controls-container")}resolveContainer(){if(typeof document>"u")return null;let D=this.options.container;if(!D)return null;if(D instanceof HTMLElement)return D;let z=document.querySelector(D);if(!z)return console.warn(`[HypertoolControls] Container selector "${D}" did not match any elements`),null;return z}addControls(){if(!this.pane)return;this.addControlsToTarget(this.pane,this.definitions,this.params)}addControlsToTarget(D,z,T){for(let[J,F]of Object.entries(z))try{if(this.isFolder(F)){let L={title:F.label||J};if(F.expanded!==void 0)L.expanded=F.expanded;let W=D.addFolder(L);this.addControlsToTarget(W,F.controls,T[J])}else if(this.isButton(F)){let L={title:F.title};if(F.label)L.label=F.label;let W=D.addButton(L);if(F.onClick)W.on("click",F.onClick)}else if(this.isTab(F)){let L={pages:F.pages.map((G)=>({title:G.title}))},W=D.addTab(L);F.pages.forEach((G,X)=>{this.addControlsToTarget(W.pages[X],G.controls,T[J][X])})}else if(this.isFile(F))this.addFileControl(D,J,F,T);else this.addControlToTarget(D,J,F,T)}catch(L){console.error(`[HypertoolControls] Error adding control/folder/button/tab "${J}":`,L)}}addControlToTarget(D,z,T,J){if(this.isFolder(T))return;let F={label:T.label||z};if(T.readonly!==void 0)F.readonly=T.readonly;if(T.interval!==void 0)F.interval=T.interval;if(T.bufferSize!==void 0)F.bufferSize=T.bufferSize;if(T.multiline!==void 0)F.multiline=T.multiline;if(T.rows!==void 0)F.rows=T.rows;if(T.view!==void 0)F.view=T.view;switch(T.type){case"number":if(T.min!==void 0)F.min=T.min;if(T.max!==void 0)F.max=T.max;if(T.step!==void 0)F.step=T.step;break;case"point":case"point2d":case"point3d":case"point4d":if(T.min!==void 0)F.min=T.min;if(T.max!==void 0)F.max=T.max;if(T.step!==void 0)F.step=T.step;let W=["x","y","z","w"];for(let G of W)if(T[G]&&typeof T[G]==="object")F[G]=T[G];break;case"select":case"selector":if(Array.isArray(T.options))F.options=T.options.map((G)=>{if(typeof G==="object"&&G!==null)return{text:G.label||G.text||String(G.value),value:G.value};return{text:String(G),value:G}});else F.options=Object.entries(T.options).map(([G,X])=>({text:G,value:X}));break;case"color":case"boolean":case"string":case"text":break;case"folder":case"group":console.warn("[HypertoolControls] Folder/Group encountered in addControlToTarget (should be handled earlier)");return;case"button":console.warn("[HypertoolControls] Button encountered in addControlToTarget (should be handled earlier)");return;case"tab":console.warn("[HypertoolControls] Tab encountered in addControlToTarget (should be handled earlier)");return;default:console.warn(`[HypertoolControls] Unknown control type: ${T.type}`);return}D.addBinding(J,z,F).on("change",(W)=>{J[z]=W.value;let G={key:z,value:W.value,event:W};this.options.onChange(this.values,G)})}addFileControl(D,z,T,J){let F=T.label||z,L=T.accept||"*/*",W=T.placeholder||"Choose file...",G=T.preview!==!1,X=document.createElement("div");X.className="tp-lblv ht-file-control-row";let x=document.createElement("div");x.className="tp-lblv_l ht-file-control-label",x.textContent=F;let V=document.createElement("div");V.className="tp-lblv_v ht-file-control-value";let Y=document.createElement("input");Y.type="file",Y.accept=L,Y.style.display="none";let A=document.createElement("div");A.className="ht-file-control-buttons";let M=document.createElement("button");M.className="tp-btnv_b ht-file-control-button",M.textContent=J[z]?"Change":"Upload",M.style.display=J[z]?"none":"inline-flex";let $=document.createElement("button");$.className="tp-btnv_b ht-file-control-button ht-file-control-button--muted",$.textContent="✕",$.style.display="none";let j=document.createElement("div");j.className="ht-file-control-preview",j.style.display=J[z]&&G?"block":"none";let U=document.createElement("div");U.className="ht-file-control-preview-bar";let S=document.createElement("span");S.className="ht-file-control-preview-name",S.textContent=J[z]?"File":"No file selected";let C=document.createElement("div");C.className="ht-file-control-preview-actions";let q=document.createElement("button");q.type="button",q.className="ht-file-control-preview-action",q.title="Replace file",q.textContent="↻",q.onclick=(K)=>{K.preventDefault(),Y.click()};let H=document.createElement("button");H.type="button",H.className="ht-file-control-preview-action",H.title="Remove file",H.textContent="✕",H.onclick=(K)=>{K.preventDefault(),$.click()},C.appendChild(q),C.appendChild(H),U.appendChild(S),U.appendChild(C);let O=document.createElement("img");O.className="ht-file-control-preview-img";let N=document.createElement("div");N.className="ht-file-control-placeholder",N.style.display="none",Y.onchange=async()=>{let K=Y.files?.[0];if(!K)return;if(T.maxSize&&K.size>T.maxSize){console.warn(`[HypertoolControls] File size exceeds limit: ${K.size} > ${T.maxSize}`);return}M.textContent="Uploading...",M.disabled=!0;let R=`file-upload-${Date.now()}-${Math.random().toString(36).slice(2)}`,w=new Promise((Z)=>{let _=(Q)=>{if(Q.data?.type!=="UPLOAD_CONTROL_FILE_RESULT")return;if(Q.data?.requestId!==R)return;if(window.removeEventListener("message",_),Q.data.error)console.error("[HypertoolControls] File upload failed:",Q.data.error),Z(null);else Z({url:Q.data.url,originalUrl:Q.data.originalUrl||Q.data.url})};window.addEventListener("message",_),setTimeout(()=>{window.removeEventListener("message",_),console.warn("[HypertoolControls] File upload timed out"),Z(null)},30000)}),P=null;if(G&&K.type.startsWith("image/")){let Z=new FileReader;Z.onload=(_)=>{P=_.target?.result},Z.readAsDataURL(K)}let B=new FileReader;B.onload=async(Z)=>{let _=Z.target?.result;window.parent.postMessage({type:"UPLOAD_CONTROL_FILE",source:"hypertool-iframe",requestId:R,data:{fileName:K.name,fileType:K.type,fileSize:K.size,fileData:_,controlKey:z}},"*",[_]);let Q=await w;if(M.disabled=!1,Q){if(J[z]=Q.url,M.textContent="Change",M.style.display="none",S.textContent=K.name||"File",G&&K.type.startsWith("image/")&&P)N.style.display="none",O.src=P,j.style.display="flex";let g={key:z,value:Q.originalUrl,event:{value:Q.originalUrl,proxyUrl:Q.url,file:K}};this.options.onChange(this.values,g)}else M.textContent=J[z]?"Change":"Upload",console.error("[HypertoolControls] Failed to upload file to storage")},B.readAsArrayBuffer(K)},M.onclick=()=>{Y.click()},$.onclick=()=>{J[z]=null,Y.value="",M.textContent="Upload",M.style.display="inline-flex",$.style.display="none",j.style.display="none",N.style.display="none",S.textContent="No file selected";let K={key:z,value:null,event:{value:null}};this.options.onChange(this.values,K)},A.appendChild(M),A.appendChild($),j.appendChild(O),j.appendChild(U),V.appendChild(Y),V.appendChild(A),V.appendChild(N),V.appendChild(j),X.appendChild(x),X.appendChild(V);let I=D.element;(I.querySelector(".tp-rotv_c")||I).appendChild(X)}addFolder(D){if(!this.pane)return null;return this.pane.addFolder({title:D})}set(D,z){if(D in this.params){if(this.params[D]=z,this.pane)this.pane.refresh()}}get values(){return{...this.params}}destroy(){if(this.pane)this.pane.dispose(),this.pane=null;let D=document.getElementById("hypertool-theme");if(D)D.remove()}setVisible(D){if(!this.pane)return;this.pane.element.style.display=D?"block":"none"}refresh(){if(this.pane)this.pane.refresh()}}function m(D,z){return new E(D,z).params}function u(D,z){return new E(D,z)}export{b as studioTheme,h as injectThemeVariables,m as createControls,u as createControlPanel,E as HypertoolControls};
|
|
27
|
+
|
|
28
|
+
//# debugId=9B4AE28FA320332164756E2164756E21
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/controls/HypertoolControls.ts", "../../src/controls/theme.ts", "../../src/controls/simple-api.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"import { Pane } from 'tweakpane';\nimport type {\n ControlDefinitions,\n HypertoolControlsOptions,\n ControlPosition,\n ParameterValues,\n ControlChangeContext,\n FolderDefinition,\n ButtonDefinition,\n TabDefinition,\n FileControlDefinition,\n} from './types';\nimport { injectThemeVariables } from './theme';\n\n/**\n * HypertoolControls - A styled Tweakpane wrapper that inherits Studio theme\n */\nexport class HypertoolControls<T extends ControlDefinitions = ControlDefinitions> {\n private declare pane: Pane | null;\n private declare definitions: T;\n private declare options: Required<HypertoolControlsOptions<T>>;\n public declare params: ParameterValues<T>;\n\n constructor(definitions: T, options: HypertoolControlsOptions<T> = {}) {\n this.pane = null;\n this.definitions = definitions;\n this.options = {\n title: options.title || 'Controls',\n position: options.position || 'top-right',\n expanded: options.expanded !== undefined ? options.expanded : true,\n container: options.container !== undefined ? options.container : null,\n onChange: options.onChange || (() => {}),\n onReady: options.onReady || (() => {}),\n } satisfies Required<HypertoolControlsOptions<T>>;\n\n // Initialize params from definitions\n this.params = this.extractInitialValues(definitions);\n\n // Initialize the control panel\n this.init();\n }\n\n /**\n * Check if a definition is a folder\n */\n private isFolder(definition: any): definition is FolderDefinition {\n return definition && typeof definition === 'object' && (definition.type === 'folder' || definition.type === 'group');\n }\n\n /**\n * Check if a definition is a button\n */\n private isButton(definition: any): definition is ButtonDefinition {\n return definition && typeof definition === 'object' && definition.type === 'button';\n }\n\n /**\n * Check if a definition is a tab\n */\n private isTab(definition: any): definition is TabDefinition {\n return definition && typeof definition === 'object' && definition.type === 'tab';\n }\n\n /**\n * Check if a definition is a file upload\n */\n private isFile(definition: any): definition is FileControlDefinition {\n return definition && typeof definition === 'object' && definition.type === 'file';\n }\n\n /**\n * Extract initial parameter values from control definitions\n */\n private extractInitialValues(definitions: any): any {\n const params: any = {};\n for (const [key, definition] of Object.entries(definitions)) {\n const def = definition as any;\n if (this.isFolder(def)) {\n // Recursively extract values from folder controls\n params[key] = this.extractInitialValues(def.controls);\n } else if (this.isTab(def)) {\n // Extract values from each tab page\n params[key] = def.pages.map((page: any) => this.extractInitialValues(page.controls));\n } else if (this.isButton(def)) {\n // Buttons don't have values, skip\n continue;\n } else {\n params[key] = def.value;\n }\n }\n return params;\n }\n\n /**\n * Initialize Tweakpane with theme and controls\n */\n private async init() {\n try {\n // Inject theme CSS variables\n injectThemeVariables();\n\n // Small delay to ensure theme is applied\n await new Promise(resolve => setTimeout(resolve, 50));\n\n // Create Tweakpane instance\n this.createPane();\n\n // // Position the pane\n // this.positionPane();\n\n // Add controls\n this.addControls();\n\n // Notify ready\n this.options.onReady();\n\n } catch (error) {\n console.error('[HypertoolControls] Initialization error:', error);\n }\n }\n\n /**\n * Create the Tweakpane instance\n */\n private createPane() {\n const container = this.resolveContainer();\n const paneOptions: Record<string, unknown> = {\n title: this.options.title,\n expanded: this.options.expanded,\n };\n\n if (container) {\n paneOptions.container = container;\n }\n\n this.pane = new Pane(paneOptions);\n // Add controls-container class for styling\n this.pane.element.parentElement?.classList.add('controls-container');\n }\n\n /**\n * Resolve the container element if provided\n */\n private resolveContainer(): HTMLElement | null {\n if (typeof document === 'undefined') return null;\n\n const containerOption = this.options.container;\n\n if (!containerOption) return null;\n\n if (containerOption instanceof HTMLElement) {\n return containerOption;\n }\n\n const element = document.querySelector(containerOption);\n\n if (!element) {\n console.warn(`[HypertoolControls] Container selector \"${containerOption}\" did not match any elements`);\n return null;\n }\n\n return element as HTMLElement;\n }\n \n /**\n * Add controls to the pane based on definitions\n */\n private addControls() {\n if (!this.pane) return;\n this.addControlsToTarget(this.pane, this.definitions, this.params);\n }\n\n /**\n * Add controls to a specific target (pane or folder)\n */\n private addControlsToTarget(target: any, definitions: ControlDefinitions, params: any) {\n for (const [key, definition] of Object.entries(definitions)) {\n try {\n if (this.isFolder(definition)) {\n // Create folder\n const folderConfig: any = {\n title: definition.label || key,\n };\n if (definition.expanded !== undefined) {\n folderConfig.expanded = definition.expanded;\n }\n const folder = target.addFolder(folderConfig);\n \n // Recursively add controls to folder\n this.addControlsToTarget(folder, definition.controls, params[key]);\n } else if (this.isButton(definition)) {\n // Create button\n const buttonConfig: any = {\n title: definition.title,\n };\n if (definition.label) {\n buttonConfig.label = definition.label;\n }\n const button = target.addButton(buttonConfig);\n \n // Attach click handler\n if (definition.onClick) {\n button.on('click', definition.onClick);\n }\n } else if (this.isTab(definition)) {\n // Create tab\n const tabConfig: any = {\n pages: definition.pages.map((page: any) => ({ title: page.title })),\n };\n const tab = target.addTab(tabConfig);\n\n // Add controls to each page\n definition.pages.forEach((page: any, index: number) => {\n this.addControlsToTarget(tab.pages[index], page.controls, params[key][index]);\n });\n } else if (this.isFile(definition)) {\n // Create custom file upload blade\n this.addFileControl(target, key, definition, params);\n } else {\n // Add regular control\n this.addControlToTarget(target, key, definition, params);\n }\n } catch (error) {\n console.error(`[HypertoolControls] Error adding control/folder/button/tab \"${key}\":`, error);\n }\n }\n }\n\n /**\n * Add a single control to a target (pane or folder)\n */\n private addControlToTarget(target: any, key: string, definition: any, params: any) {\n // Skip if it's a folder (should not be called with folders)\n if (this.isFolder(definition)) return;\n\n const config: any = {\n label: definition.label || key,\n };\n // Monitor-specific configuration (readonly: true makes it a monitor)\n if (definition.readonly !== undefined) {\n config.readonly = definition.readonly;\n }\n if (definition.interval !== undefined) {\n config.interval = definition.interval;\n }\n if (definition.bufferSize !== undefined) {\n config.bufferSize = definition.bufferSize;\n }\n \n // String monitor options\n if (definition.multiline !== undefined) {\n config.multiline = definition.multiline;\n }\n if (definition.rows !== undefined) {\n config.rows = definition.rows;\n }\n \n // Number monitor options (graph view)\n if (definition.view !== undefined) {\n config.view = definition.view;\n }\n\n // Type-specific configuration\n switch (definition.type) {\n case 'number':\n if (definition.min !== undefined) config.min = definition.min;\n if (definition.max !== undefined) config.max = definition.max;\n if (definition.step !== undefined) config.step = definition.step;\n break;\n\n case 'point':\n case 'point2d':\n case 'point3d':\n case 'point4d':\n // Explicit point type - handle constraints\n if (definition.min !== undefined) config.min = definition.min;\n if (definition.max !== undefined) config.max = definition.max;\n if (definition.step !== undefined) config.step = definition.step;\n\n // Per-axis constraints\n const axes = ['x', 'y', 'z', 'w'];\n for (const axis of axes) {\n if ((definition as any)[axis] && typeof (definition as any)[axis] === 'object') {\n config[axis] = (definition as any)[axis];\n }\n }\n break;\n\n case 'select':\n case 'selector':\n // Always convert to Tweakpane array format: [{text: 'Label', value: 'value'}, ...]\n if (Array.isArray(definition.options)) {\n config.options = definition.options.map((opt: any) => {\n // Handle array of objects: [{label: 'X', value: 'x'}] or [{text: 'X', value: 'x'}]\n if (typeof opt === 'object' && opt !== null) {\n return {\n text: opt.label || opt.text || String(opt.value),\n value: opt.value\n };\n }\n // Handle simple array: ['x', 'y', 'z']\n return {\n text: String(opt),\n value: opt\n };\n });\n } else {\n // Convert object format {Label: 'value'} to array format\n config.options = Object.entries(definition.options).map(([text, value]) => ({\n text,\n value\n }));\n }\n break;\n\n case 'color':\n case 'boolean':\n case 'string':\n case 'text':\n // No additional config needed - Tweakpane handles these automatically\n break;\n\n case 'folder':\n case 'group':\n // Folders are handled by addControlsToTarget, this should not be reached\n console.warn(`[HypertoolControls] Folder/Group encountered in addControlToTarget (should be handled earlier)`);\n return;\n\n case 'button':\n // Buttons are handled by addControlsToTarget, this should not be reached\n console.warn(`[HypertoolControls] Button encountered in addControlToTarget (should be handled earlier)`);\n return;\n\n case 'tab':\n // Tabs are handled by addControlsToTarget, this should not be reached\n console.warn(`[HypertoolControls] Tab encountered in addControlToTarget (should be handled earlier)`);\n return;\n\n default:\n console.warn(`[HypertoolControls] Unknown control type: ${(definition as any).type}`);\n return;\n }\n\n // Add binding to the target (pane or folder)\n const binding = target.addBinding(params, key, config);\n\n // Listen for changes\n binding.on('change', (event: any) => {\n // Update the nested params object\n params[key] = event.value;\n \n // Notify onChange callback with full params\n const context: ControlChangeContext<T> = {\n key: key as keyof T,\n value: event.value,\n event,\n };\n this.options.onChange(this.values, context);\n });\n }\n\n /**\n * Add a custom file upload control\n */\n private addFileControl(target: any, key: string, definition: FileControlDefinition, params: any) {\n const label = definition.label || key;\n const accept = definition.accept || '*/*';\n const placeholder = definition.placeholder || 'Choose file...';\n const showPreview = definition.preview !== false;\n\n // Create custom row element (matching Tweakpane's structure)\n const row = document.createElement('div');\n row.className = 'tp-lblv ht-file-control-row';\n\n // Create label element\n const labelEl = document.createElement('div');\n labelEl.className = 'tp-lblv_l ht-file-control-label';\n labelEl.textContent = label;\n\n // Create value container\n const valueContainer = document.createElement('div');\n valueContainer.className = 'tp-lblv_v ht-file-control-value';\n\n // Create file input (hidden)\n const fileInput = document.createElement('input');\n fileInput.type = 'file';\n fileInput.accept = accept;\n fileInput.style.display = 'none';\n\n // Create button row\n const buttonRow = document.createElement('div');\n buttonRow.className = 'ht-file-control-buttons';\n\n // Create upload button\n const uploadBtn = document.createElement('button');\n uploadBtn.className = 'tp-btnv_b ht-file-control-button';\n uploadBtn.textContent = params[key] ? 'Change' : 'Upload';\n uploadBtn.style.display = params[key] ? 'none' : 'inline-flex';\n\n // Create clear button (initially hidden)\n const clearBtn = document.createElement('button');\n clearBtn.className = 'tp-btnv_b ht-file-control-button ht-file-control-button--muted';\n clearBtn.textContent = '✕';\n clearBtn.style.display = 'none';\n\n // Create preview container\n const previewContainer = document.createElement('div');\n previewContainer.className = 'ht-file-control-preview';\n previewContainer.style.display = params[key] && showPreview ? 'block' : 'none';\n\n // Preview overlay (filename + actions)\n const previewOverlay = document.createElement('div');\n previewOverlay.className = 'ht-file-control-preview-bar';\n\n const previewName = document.createElement('span');\n previewName.className = 'ht-file-control-preview-name';\n previewName.textContent = params[key] ? 'File' : 'No file selected';\n\n const overlayActions = document.createElement('div');\n overlayActions.className = 'ht-file-control-preview-actions';\n\n const overlayReplaceBtn = document.createElement('button');\n overlayReplaceBtn.type = 'button';\n overlayReplaceBtn.className = 'ht-file-control-preview-action';\n overlayReplaceBtn.title = 'Replace file';\n overlayReplaceBtn.textContent = '↻';\n overlayReplaceBtn.onclick = (e) => {\n e.preventDefault();\n fileInput.click();\n };\n\n const overlayRemoveBtn = document.createElement('button');\n overlayRemoveBtn.type = 'button';\n overlayRemoveBtn.className = 'ht-file-control-preview-action';\n overlayRemoveBtn.title = 'Remove file';\n overlayRemoveBtn.textContent = '✕';\n overlayRemoveBtn.onclick = (e) => {\n e.preventDefault();\n clearBtn.click();\n };\n\n overlayActions.appendChild(overlayReplaceBtn);\n overlayActions.appendChild(overlayRemoveBtn);\n previewOverlay.appendChild(previewName);\n previewOverlay.appendChild(overlayActions);\n\n // Create preview image\n const previewImg = document.createElement('img');\n previewImg.className = 'ht-file-control-preview-img';\n\n // Placeholder intentionally hidden\n const filePlaceholder = document.createElement('div');\n filePlaceholder.className = 'ht-file-control-placeholder';\n filePlaceholder.style.display = 'none';\n\n // Handle file selection\n fileInput.onchange = async () => {\n const file = fileInput.files?.[0];\n if (!file) return;\n\n // Check max size\n if (definition.maxSize && file.size > definition.maxSize) {\n console.warn(`[HypertoolControls] File size exceeds limit: ${file.size} > ${definition.maxSize}`);\n return;\n }\n\n // Show loading state\n uploadBtn.textContent = 'Uploading...';\n uploadBtn.disabled = true;\n\n // Generate unique request ID for this upload\n const requestId = `file-upload-${Date.now()}-${Math.random().toString(36).slice(2)}`;\n\n // Create a promise that resolves when we get the upload response\n const uploadPromise = new Promise<{ url: string; originalUrl: string } | null>((resolve) => {\n const handleUploadResponse = (event: MessageEvent) => {\n if (event.data?.type !== 'UPLOAD_CONTROL_FILE_RESULT') return;\n if (event.data?.requestId !== requestId) return;\n\n window.removeEventListener('message', handleUploadResponse);\n\n if (event.data.error) {\n console.error('[HypertoolControls] File upload failed:', event.data.error);\n resolve(null);\n } else {\n resolve({\n url: event.data.url, // Proxy URL for iframe use\n originalUrl: event.data.originalUrl || event.data.url, // Original for storage\n });\n }\n };\n\n window.addEventListener('message', handleUploadResponse);\n\n // Timeout after 30 seconds\n setTimeout(() => {\n window.removeEventListener('message', handleUploadResponse);\n console.warn('[HypertoolControls] File upload timed out');\n resolve(null);\n }, 30000);\n });\n\n // First, create a data URL for local preview (bypasses COEP)\n let localDataUrl: string | null = null;\n if (showPreview && file.type.startsWith('image/')) {\n const previewReader = new FileReader();\n previewReader.onload = (pe) => {\n localDataUrl = pe.target?.result as string;\n };\n previewReader.readAsDataURL(file);\n }\n\n // Read file and send to parent for Convex upload\n const reader = new FileReader();\n reader.onload = async (e) => {\n const arrayBuffer = e.target?.result as ArrayBuffer;\n\n // Send file data to parent for Convex storage upload\n window.parent.postMessage({\n type: 'UPLOAD_CONTROL_FILE',\n source: 'hypertool-iframe',\n requestId,\n data: {\n fileName: file.name,\n fileType: file.type,\n fileSize: file.size,\n fileData: arrayBuffer,\n controlKey: key, // Include control key for asset naming\n },\n }, '*', [arrayBuffer]);\n\n // Wait for upload response\n const uploadResult = await uploadPromise;\n\n // Reset button state\n uploadBtn.disabled = false;\n\n if (uploadResult) {\n // Update params with proxy URL (for use in visualization - COEP safe)\n params[key] = uploadResult.url;\n\n // Update UI\n uploadBtn.textContent = 'Change';\n uploadBtn.style.display = 'none';\n previewName.textContent = file.name || 'File';\n\n // Update preview using local data URL (bypasses COEP restrictions)\n if (showPreview && file.type.startsWith('image/') && localDataUrl) {\n filePlaceholder.style.display = 'none'; // Hide placeholder\n previewImg.src = localDataUrl;\n previewContainer.style.display = 'flex';\n }\n\n // Notify onChange with original URL for storage (export needs the Convex URL)\n const context: ControlChangeContext<T> = {\n key: key as keyof T,\n value: uploadResult.originalUrl, // Send original URL for storage\n event: { value: uploadResult.originalUrl, proxyUrl: uploadResult.url, file },\n };\n this.options.onChange(this.values, context);\n } else {\n // Upload failed, revert UI\n uploadBtn.textContent = params[key] ? 'Change' : 'Upload';\n console.error('[HypertoolControls] Failed to upload file to storage');\n }\n };\n reader.readAsArrayBuffer(file);\n };\n\n // Handle upload button click\n uploadBtn.onclick = () => {\n fileInput.click();\n };\n\n // Handle clear button click\n clearBtn.onclick = () => {\n params[key] = null;\n fileInput.value = '';\n uploadBtn.textContent = 'Upload';\n uploadBtn.style.display = 'inline-flex';\n clearBtn.style.display = 'none';\n previewContainer.style.display = 'none';\n filePlaceholder.style.display = 'none';\n previewName.textContent = 'No file selected';\n\n // Notify onChange\n const context: ControlChangeContext<T> = {\n key: key as keyof T,\n value: null,\n event: { value: null },\n };\n this.options.onChange(this.values, context);\n };\n\n // Assemble UI\n buttonRow.appendChild(uploadBtn);\n buttonRow.appendChild(clearBtn);\n previewContainer.appendChild(previewImg);\n previewContainer.appendChild(previewOverlay);\n valueContainer.appendChild(fileInput);\n valueContainer.appendChild(buttonRow);\n valueContainer.appendChild(filePlaceholder);\n valueContainer.appendChild(previewContainer);\n\n // Assemble the row\n row.appendChild(labelEl);\n row.appendChild(valueContainer);\n\n // Append to Tweakpane's container element\n // target.element gives us the pane/folder element\n const paneElement = target.element as HTMLElement;\n const containerElement = paneElement.querySelector('.tp-rotv_c') || paneElement;\n containerElement.appendChild(row);\n }\n\n /**\n * Add a folder to organize controls\n */\n public addFolder(title: string): any {\n if (!this.pane) return null;\n return (this.pane as any).addFolder({ title });\n }\n\n /**\n * Update a parameter value programmatically\n */\n public set(key: keyof T, value: any) {\n if (key in this.params) {\n this.params[key] = value;\n if (this.pane) {\n (this.pane as any).refresh();\n }\n }\n }\n\n /**\n * Get current parameter values\n */\n public get values(): ParameterValues<T> {\n return { ...this.params };\n }\n\n /**\n * Destroy the control panel\n */\n public destroy() {\n if (this.pane) {\n this.pane.dispose();\n this.pane = null;\n }\n\n // Remove theme styles\n const themeStyle = document.getElementById('hypertool-theme');\n if (themeStyle) {\n themeStyle.remove();\n }\n }\n\n /**\n * Show/hide the control panel\n */\n public setVisible(visible: boolean) {\n if (!this.pane) return;\n this.pane.element.style.display = visible ? 'block' : 'none';\n }\n\n /**\n * Refresh the control panel UI\n */\n public refresh() {\n if (this.pane) {\n (this.pane as any).refresh();\n }\n }\n}\n",
|
|
6
|
+
"/**\n * Design tokens inherited from the parent Studio application\n * These CSS variables are defined in src/app/globals.css\n */\nexport const studioTheme = {\n // CSS variables that should be available in the iframe\n cssVariables: {\n '--bg': '#0a0e14',\n '--bg-elevated': '#0f1419',\n '--muted': '#1a2332',\n '--text': '#e6edf3',\n '--text-secondary': '#8b949e',\n '--accent': '#58d5ff',\n '--accent-2': '#42a5cc',\n '--border': '#21262d',\n '--border-hover': '#30363d',\n '--success': '#3fb950',\n '--error': '#f85149',\n\n // Hypertool-specific variables\n '--ht-text-color-main-200': '#00ffd4',\n '--ht-text-color-main-300': '#6ff3dd',\n '--ht-text-color-main-500': '#4b8e85',\n '--ht-text-color-grey-200': '#8c8d8f',\n\n '--ht-bg-color-200': '#8c8d8f',\n '--ht-bg-color-200-active': '#7a7b7d',\n '--ht-bg-color-200-focus': '#7e7f81',\n '--ht-bg-color-200-hover': '#828384',\n\n '--ht-bg-color-300': '#5e6068',\n '--ht-bg-color-300-active': '#4c4e56',\n '--ht-bg-color-300-focus': '#55575f',\n '--ht-bg-color-300-hover': '#595b63',\n\n '--ht-bg-color-400': '#cccccc',\n '--ht-bg-color-400-active': '#b3b3b3',\n '--ht-bg-color-400-focus': '#c0c0c0',\n '--ht-bg-color-400-hover': '#c6c6c6',\n\n '--ht-bg-color-500': '#1C1D20',\n '--ht-bg-color-500-active': '#0a0b0e',\n '--ht-bg-color-500-focus': '#131417',\n '--ht-bg-color-500-hover': '#16171a',\n\n '--ht-bg-color-600': '#37383D',\n '--ht-bg-color-600-active': '#25262b',\n '--ht-bg-color-600-focus': '#2e2f34',\n '--ht-bg-color-600-hover': '#323338',\n\n '--ht-bg-color-700': '#0f1419',\n '--ht-bg-color-700-active': '#16171c',\n '--ht-bg-color-700-focus': '#1f2025',\n '--ht-bg-color-700-hover': '#232429',\n\n '--ht-border-radius': '8px',\n\n '--ht-base-font-family-base': '\"HydrogenType400\", ui-sans-serif, system-ui, sans-serif',\n '--ht-base-font-family-display': '\"Departure Mono\", Roboto Mono, Source Code Pro, Menlo, Courier, monospace',\n '--ht-base-font-family-sans': '\"Routed Gothic\", ui-sans-serif, system-ui, sans-serif',\n '--ht-base-font-family-mono': '\"Routed Gothic Narrow\", ui-monospace, SFMono-Regular, SF Mono, Consolas, Liberation Mono, Menlo, monospace',\n },\n\n // Tweakpane-specific theme variables\n tweakpane: {\n '--tp-base-background-color': 'var(--ht-bg-color-700)',\n '--tp-base-shadow-color': 'hsla(0, 0%, 0%, 0.2)',\n\n '--tp-container-background-color': 'var(--ht-bg-color-600)',\n '--tp-container-background-color-active': 'var(--ht-bg-color-600-active)',\n '--tp-container-background-color-focus': 'var(--ht-bg-color-600-focus)',\n '--tp-container-background-color-hover': 'var(--ht-bg-color-600-hover)',\n '--tp-container-foreground-color': 'var(--ht-text-color-main-300)',\n\n '--tp-button-background-color': 'var(--ht-bg-color-400)',\n '--tp-button-background-color-active': 'color-mix(in srgb, var(--ht-bg-color-400-active) 80%, white)',\n '--tp-button-background-color-focus': 'color-mix(in srgb, var(--ht-bg-color-400-focus) 85%, white)',\n '--tp-button-background-color-hover': 'color-mix(in srgb, var(--ht-bg-color-400-hover) 90%, white)',\n '--tp-button-foreground-color': 'var(--ht-text-color-main-300)',\n\n '--tp-groove-foreground-color': 'var(--ht-bg-color-300)',\n\n '--tp-input-background-color': 'var(--ht-bg-color-500)',\n '--tp-input-background-color-active': 'var(--ht-bg-color-500-active)',\n '--tp-input-background-color-focus': 'var(--ht-bg-color-500-focus)',\n '--tp-input-background-color-hover': 'var(--ht-bg-color-500-hover)',\n '--tp-input-foreground-color': 'var(--ht-text-color-main-300)',\n\n '--tp-label-foreground-color': 'var(--ht-text-color-main-300)',\n\n '--tp-monitor-background-color': 'var(--ht-bg-color-500)',\n '--tp-monitor-foreground-color': 'var(--ht-text-color-main-300)',\n }\n};\n\n/**\n * Inject CSS variables into the document\n */\nexport function injectThemeVariables() {\n const style = document.createElement('style');\n style.id = 'hypertool-theme';\n\n const cssVars = Object.entries({\n ...studioTheme.cssVariables,\n ...studioTheme.tweakpane\n })\n .map(([key, value]) => ` ${key}: ${value};`)\n .join('\\n');\n\n style.textContent = `\n body {\n margin: 0;\n padding: 0;\n }\n\n:root {\n${cssVars}\n}\n\n/* Controls panel positioning and styling */\n.controls-container {\n position: fixed;\n top: 8px;\n right: 8px;\n z-index: 1000;\n max-height: calc(100vh - 16px);\n overflow-y: auto;\n}\n\n/* Ensure Tweakpane pane has background */\n.tp-dfwv {\n background-color: var(--tp-base-background-color, #0f1419) !important;\n}\n`;\n\n document.head.appendChild(style);\n}",
|
|
7
|
+
"import { HypertoolControls } from './HypertoolControls';\nimport type { ControlDefinitions, HypertoolControlsOptions, ParameterValues } from './types';\n\n/**\n * Simple API for quick setup - returns params object directly\n *\n * @example\n * ```typescript\n * const params = createControls({\n * speed: { type: 'number', value: 1, min: 0, max: 10, step: 0.1 },\n * color: { type: 'color', value: '#ff0000' },\n * enabled: { type: 'boolean', value: true }\n * });\n *\n * // Use params directly in your code\n * circle.speed = params.speed;\n * circle.color = params.color;\n * ```\n */\nexport function createControls<T extends ControlDefinitions>(\n definitions: T,\n options?: HypertoolControlsOptions<T>\n): ParameterValues<T> {\n const controls = new HypertoolControls(definitions, options);\n return controls.params;\n}\n\n/**\n * Advanced API for full control - returns HypertoolControls instance\n *\n * @example\n * ```typescript\n * const controls = createControlPanel({\n * speed: { type: 'number', value: 1, min: 0, max: 10 }\n * }, {\n * title: 'Simulation',\n * onChange: (params) => console.log('Changed:', params)\n * });\n *\n * // Access params\n * const params = controls.params;\n *\n * // Programmatically update\n * controls.set('speed', 5);\n *\n * // Hide/show\n * controls.setVisible(false);\n * ```\n */\nexport function createControlPanel<T extends ControlDefinitions>(\n definitions: T,\n options?: HypertoolControlsOptions<T>\n): HypertoolControls<T> {\n return new HypertoolControls(definitions, options);\n}\n"
|
|
8
|
+
],
|
|
9
|
+
"mappings": "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",
|
|
10
|
+
"debugId": "9B4AE28FA320332164756E2164756E21",
|
|
11
|
+
"names": []
|
|
12
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { HypertoolControls } from './HypertoolControls';
|
|
2
|
+
import type { ControlDefinitions, HypertoolControlsOptions, ParameterValues } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Simple API for quick setup - returns params object directly
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* const params = createControls({
|
|
9
|
+
* speed: { type: 'number', value: 1, min: 0, max: 10, step: 0.1 },
|
|
10
|
+
* color: { type: 'color', value: '#ff0000' },
|
|
11
|
+
* enabled: { type: 'boolean', value: true }
|
|
12
|
+
* });
|
|
13
|
+
*
|
|
14
|
+
* // Use params directly in your code
|
|
15
|
+
* circle.speed = params.speed;
|
|
16
|
+
* circle.color = params.color;
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export declare function createControls<T extends ControlDefinitions>(definitions: T, options?: HypertoolControlsOptions<T>): ParameterValues<T>;
|
|
20
|
+
/**
|
|
21
|
+
* Advanced API for full control - returns HypertoolControls instance
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```typescript
|
|
25
|
+
* const controls = createControlPanel({
|
|
26
|
+
* speed: { type: 'number', value: 1, min: 0, max: 10 }
|
|
27
|
+
* }, {
|
|
28
|
+
* title: 'Simulation',
|
|
29
|
+
* onChange: (params) => console.log('Changed:', params)
|
|
30
|
+
* });
|
|
31
|
+
*
|
|
32
|
+
* // Access params
|
|
33
|
+
* const params = controls.params;
|
|
34
|
+
*
|
|
35
|
+
* // Programmatically update
|
|
36
|
+
* controls.set('speed', 5);
|
|
37
|
+
*
|
|
38
|
+
* // Hide/show
|
|
39
|
+
* controls.setVisible(false);
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export declare function createControlPanel<T extends ControlDefinitions>(definitions: T, options?: HypertoolControlsOptions<T>): HypertoolControls<T>;
|
|
43
|
+
//# sourceMappingURL=simple-api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"simple-api.d.ts","sourceRoot":"","sources":["../../src/controls/simple-api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE7F;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,kBAAkB,EACzD,WAAW,EAAE,CAAC,EACd,OAAO,CAAC,EAAE,wBAAwB,CAAC,CAAC,CAAC,GACpC,eAAe,CAAC,CAAC,CAAC,CAGpB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,kBAAkB,EAC7D,WAAW,EAAE,CAAC,EACd,OAAO,CAAC,EAAE,wBAAwB,CAAC,CAAC,CAAC,GACpC,iBAAiB,CAAC,CAAC,CAAC,CAEtB"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Design tokens inherited from the parent Studio application
|
|
3
|
+
* These CSS variables are defined in src/app/globals.css
|
|
4
|
+
*/
|
|
5
|
+
export declare const studioTheme: {
|
|
6
|
+
cssVariables: {
|
|
7
|
+
'--bg': string;
|
|
8
|
+
'--bg-elevated': string;
|
|
9
|
+
'--muted': string;
|
|
10
|
+
'--text': string;
|
|
11
|
+
'--text-secondary': string;
|
|
12
|
+
'--accent': string;
|
|
13
|
+
'--accent-2': string;
|
|
14
|
+
'--border': string;
|
|
15
|
+
'--border-hover': string;
|
|
16
|
+
'--success': string;
|
|
17
|
+
'--error': string;
|
|
18
|
+
'--ht-text-color-main-200': string;
|
|
19
|
+
'--ht-text-color-main-300': string;
|
|
20
|
+
'--ht-text-color-main-500': string;
|
|
21
|
+
'--ht-text-color-grey-200': string;
|
|
22
|
+
'--ht-bg-color-200': string;
|
|
23
|
+
'--ht-bg-color-200-active': string;
|
|
24
|
+
'--ht-bg-color-200-focus': string;
|
|
25
|
+
'--ht-bg-color-200-hover': string;
|
|
26
|
+
'--ht-bg-color-300': string;
|
|
27
|
+
'--ht-bg-color-300-active': string;
|
|
28
|
+
'--ht-bg-color-300-focus': string;
|
|
29
|
+
'--ht-bg-color-300-hover': string;
|
|
30
|
+
'--ht-bg-color-400': string;
|
|
31
|
+
'--ht-bg-color-400-active': string;
|
|
32
|
+
'--ht-bg-color-400-focus': string;
|
|
33
|
+
'--ht-bg-color-400-hover': string;
|
|
34
|
+
'--ht-bg-color-500': string;
|
|
35
|
+
'--ht-bg-color-500-active': string;
|
|
36
|
+
'--ht-bg-color-500-focus': string;
|
|
37
|
+
'--ht-bg-color-500-hover': string;
|
|
38
|
+
'--ht-bg-color-600': string;
|
|
39
|
+
'--ht-bg-color-600-active': string;
|
|
40
|
+
'--ht-bg-color-600-focus': string;
|
|
41
|
+
'--ht-bg-color-600-hover': string;
|
|
42
|
+
'--ht-bg-color-700': string;
|
|
43
|
+
'--ht-bg-color-700-active': string;
|
|
44
|
+
'--ht-bg-color-700-focus': string;
|
|
45
|
+
'--ht-bg-color-700-hover': string;
|
|
46
|
+
'--ht-border-radius': string;
|
|
47
|
+
'--ht-base-font-family-base': string;
|
|
48
|
+
'--ht-base-font-family-display': string;
|
|
49
|
+
'--ht-base-font-family-sans': string;
|
|
50
|
+
'--ht-base-font-family-mono': string;
|
|
51
|
+
};
|
|
52
|
+
tweakpane: {
|
|
53
|
+
'--tp-base-background-color': string;
|
|
54
|
+
'--tp-base-shadow-color': string;
|
|
55
|
+
'--tp-container-background-color': string;
|
|
56
|
+
'--tp-container-background-color-active': string;
|
|
57
|
+
'--tp-container-background-color-focus': string;
|
|
58
|
+
'--tp-container-background-color-hover': string;
|
|
59
|
+
'--tp-container-foreground-color': string;
|
|
60
|
+
'--tp-button-background-color': string;
|
|
61
|
+
'--tp-button-background-color-active': string;
|
|
62
|
+
'--tp-button-background-color-focus': string;
|
|
63
|
+
'--tp-button-background-color-hover': string;
|
|
64
|
+
'--tp-button-foreground-color': string;
|
|
65
|
+
'--tp-groove-foreground-color': string;
|
|
66
|
+
'--tp-input-background-color': string;
|
|
67
|
+
'--tp-input-background-color-active': string;
|
|
68
|
+
'--tp-input-background-color-focus': string;
|
|
69
|
+
'--tp-input-background-color-hover': string;
|
|
70
|
+
'--tp-input-foreground-color': string;
|
|
71
|
+
'--tp-label-foreground-color': string;
|
|
72
|
+
'--tp-monitor-background-color': string;
|
|
73
|
+
'--tp-monitor-foreground-color': string;
|
|
74
|
+
};
|
|
75
|
+
};
|
|
76
|
+
/**
|
|
77
|
+
* Inject CSS variables into the document
|
|
78
|
+
*/
|
|
79
|
+
export declare function injectThemeVariables(): void;
|
|
80
|
+
//# sourceMappingURL=theme.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../../src/controls/theme.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyFvB,CAAC;AAEF;;GAEG;AACH,wBAAgB,oBAAoB,SAsCnC"}
|