@opentui/react
Advanced tools
| // @bun | ||
| import { | ||
| __require | ||
| } from "./chunk-2mx7fq49.js"; | ||
| // src/components/index.ts | ||
| import { | ||
| ASCIIFontRenderable, | ||
| BoxRenderable, | ||
| CodeRenderable, | ||
| DiffRenderable, | ||
| InputRenderable, | ||
| LineNumberRenderable, | ||
| MarkdownRenderable, | ||
| ScrollBoxRenderable, | ||
| SelectRenderable, | ||
| TabSelectRenderable, | ||
| TextareaRenderable, | ||
| TextRenderable | ||
| } from "@opentui/core"; | ||
| // src/components/text.ts | ||
| import { TextAttributes, TextNodeRenderable } from "@opentui/core"; | ||
| var textNodeKeys = ["span", "b", "strong", "i", "em", "u", "br", "a"]; | ||
| class SpanRenderable extends TextNodeRenderable { | ||
| ctx; | ||
| constructor(ctx, options) { | ||
| super(options); | ||
| this.ctx = ctx; | ||
| } | ||
| } | ||
| class TextModifierRenderable extends SpanRenderable { | ||
| constructor(options, modifier) { | ||
| super(null, options); | ||
| if (modifier === "b" || modifier === "strong") { | ||
| this.attributes = (this.attributes || 0) | TextAttributes.BOLD; | ||
| } else if (modifier === "i" || modifier === "em") { | ||
| this.attributes = (this.attributes || 0) | TextAttributes.ITALIC; | ||
| } else if (modifier === "u") { | ||
| this.attributes = (this.attributes || 0) | TextAttributes.UNDERLINE; | ||
| } | ||
| } | ||
| } | ||
| class BoldSpanRenderable extends TextModifierRenderable { | ||
| constructor(_ctx, options) { | ||
| super(options, "b"); | ||
| } | ||
| } | ||
| class ItalicSpanRenderable extends TextModifierRenderable { | ||
| constructor(_ctx, options) { | ||
| super(options, "i"); | ||
| } | ||
| } | ||
| class UnderlineSpanRenderable extends TextModifierRenderable { | ||
| constructor(_ctx, options) { | ||
| super(options, "u"); | ||
| } | ||
| } | ||
| class LineBreakRenderable extends SpanRenderable { | ||
| constructor(_ctx, options) { | ||
| super(null, options); | ||
| this.add(); | ||
| } | ||
| add() { | ||
| return super.add(` | ||
| `); | ||
| } | ||
| } | ||
| class LinkRenderable extends SpanRenderable { | ||
| constructor(_ctx, options) { | ||
| const linkOptions = { | ||
| ...options, | ||
| link: { url: options.href } | ||
| }; | ||
| super(null, linkOptions); | ||
| } | ||
| } | ||
| // src/components/index.ts | ||
| var baseComponents = { | ||
| box: BoxRenderable, | ||
| text: TextRenderable, | ||
| code: CodeRenderable, | ||
| diff: DiffRenderable, | ||
| markdown: MarkdownRenderable, | ||
| input: InputRenderable, | ||
| select: SelectRenderable, | ||
| textarea: TextareaRenderable, | ||
| scrollbox: ScrollBoxRenderable, | ||
| "ascii-font": ASCIIFontRenderable, | ||
| "tab-select": TabSelectRenderable, | ||
| "line-number": LineNumberRenderable, | ||
| span: SpanRenderable, | ||
| br: LineBreakRenderable, | ||
| b: BoldSpanRenderable, | ||
| strong: BoldSpanRenderable, | ||
| i: ItalicSpanRenderable, | ||
| em: ItalicSpanRenderable, | ||
| u: UnderlineSpanRenderable, | ||
| a: LinkRenderable | ||
| }; | ||
| var componentCatalogue = { ...baseComponents }; | ||
| function extend(objects) { | ||
| Object.assign(componentCatalogue, objects); | ||
| } | ||
| function getComponentCatalogue() { | ||
| return componentCatalogue; | ||
| } | ||
| // src/components/app.tsx | ||
| import { createContext, useContext } from "react"; | ||
| var AppContext = createContext({ | ||
| keyHandler: null, | ||
| renderer: null | ||
| }); | ||
| var useAppContext = () => { | ||
| return useContext(AppContext); | ||
| }; | ||
| // src/reconciler/renderer.ts | ||
| import { CliRenderEvents, engine } from "@opentui/core"; | ||
| import React2 from "react"; | ||
| // src/components/error-boundary.tsx | ||
| import React from "react"; | ||
| // jsx-dev-runtime.js | ||
| import { Fragment, jsxDEV } from "react/jsx-dev-runtime"; | ||
| // src/components/error-boundary.tsx | ||
| class ErrorBoundary extends React.Component { | ||
| constructor(props) { | ||
| super(props); | ||
| this.state = { hasError: false, error: null }; | ||
| } | ||
| static getDerivedStateFromError(error) { | ||
| return { hasError: true, error }; | ||
| } | ||
| render() { | ||
| if (this.state.hasError && this.state.error) { | ||
| return /* @__PURE__ */ jsxDEV("box", { | ||
| style: { flexDirection: "column", padding: 2 }, | ||
| children: /* @__PURE__ */ jsxDEV("text", { | ||
| fg: "red", | ||
| children: this.state.error.stack || this.state.error.message | ||
| }, undefined, false, undefined, this) | ||
| }, undefined, false, undefined, this); | ||
| } | ||
| return this.props.children; | ||
| } | ||
| } | ||
| // src/reconciler/reconciler.ts | ||
| import ReactReconciler from "react-reconciler"; | ||
| import { ConcurrentRoot } from "react-reconciler/constants"; | ||
| // src/reconciler/host-config.ts | ||
| import { TextNodeRenderable as TextNodeRenderable2 } from "@opentui/core"; | ||
| // package.json | ||
| var package_default = { | ||
| name: "@opentui/react", | ||
| version: "0.4.0", | ||
| description: "React renderer for building terminal user interfaces using OpenTUI core", | ||
| license: "MIT", | ||
| repository: { | ||
| type: "git", | ||
| url: "https://github.com/anomalyco/opentui", | ||
| directory: "packages/react" | ||
| }, | ||
| module: "src/index.ts", | ||
| type: "module", | ||
| private: true, | ||
| main: "src/index.ts", | ||
| exports: { | ||
| ".": { | ||
| import: "./src/index.ts", | ||
| types: "./src/index.ts" | ||
| }, | ||
| "./test-utils": { | ||
| import: "./src/test-utils.ts", | ||
| types: "./src/test-utils.d.ts" | ||
| }, | ||
| "./runtime-plugin-support": { | ||
| import: "./scripts/runtime-plugin-support.ts", | ||
| types: "./scripts/runtime-plugin-support.ts" | ||
| }, | ||
| "./runtime-plugin-support/configure": { | ||
| import: "./scripts/runtime-plugin-support-configure.ts", | ||
| types: "./scripts/runtime-plugin-support-configure.ts" | ||
| }, | ||
| "./jsx-runtime": { | ||
| import: "./jsx-runtime.js", | ||
| types: "./jsx-runtime.d.ts" | ||
| }, | ||
| "./jsx-dev-runtime": { | ||
| import: "./jsx-dev-runtime.js", | ||
| types: "./jsx-dev-runtime.d.ts" | ||
| } | ||
| }, | ||
| scripts: { | ||
| build: "bun run scripts/build.ts", | ||
| "build:examples": "bun examples/build.ts", | ||
| "build:dev": "bun run scripts/build.ts --dev", | ||
| publish: "bun run scripts/publish.ts", | ||
| test: "bun test" | ||
| }, | ||
| devDependencies: { | ||
| "@opentui/keymap": "workspace:*", | ||
| "@types/bun": "latest", | ||
| "@types/node": "^24.0.0", | ||
| "@types/react": "^19.2.0", | ||
| "@types/react-reconciler": "^0.33.0", | ||
| "@types/ws": "^8.18.1", | ||
| react: ">=19.2.0", | ||
| "react-devtools-core": "^7.0.1", | ||
| typescript: "^5", | ||
| ws: "^8.18.0" | ||
| }, | ||
| peerDependencies: { | ||
| react: ">=19.2.0", | ||
| "react-devtools-core": "^7.0.1", | ||
| ws: "^8.18.0" | ||
| }, | ||
| peerDependenciesMeta: { | ||
| "react-devtools-core": { | ||
| optional: true | ||
| }, | ||
| ws: { | ||
| optional: true | ||
| } | ||
| }, | ||
| dependencies: { | ||
| "@opentui/core": "workspace:*", | ||
| "react-reconciler": "^0.33.0" | ||
| } | ||
| }; | ||
| // src/reconciler/host-config.ts | ||
| import { createContext as createContext2 } from "react"; | ||
| import { DefaultEventPriority, NoEventPriority } from "react-reconciler/constants"; | ||
| // src/utils/id.ts | ||
| var idCounter = new Map; | ||
| function getNextId(type) { | ||
| if (!idCounter.has(type)) { | ||
| idCounter.set(type, 0); | ||
| } | ||
| const value = idCounter.get(type) + 1; | ||
| idCounter.set(type, value); | ||
| return `${type}-${value}`; | ||
| } | ||
| // src/utils/index.ts | ||
| import { | ||
| InputRenderable as InputRenderable2, | ||
| InputRenderableEvents, | ||
| isRenderable, | ||
| SelectRenderable as SelectRenderable2, | ||
| SelectRenderableEvents, | ||
| TabSelectRenderable as TabSelectRenderable2, | ||
| TabSelectRenderableEvents, | ||
| TextareaRenderable as TextareaRenderable2 | ||
| } from "@opentui/core"; | ||
| function initEventListeners(instance, eventName, listener, previousListener) { | ||
| if (previousListener) { | ||
| instance.off(eventName, previousListener); | ||
| } | ||
| if (listener) { | ||
| instance.on(eventName, listener); | ||
| } | ||
| } | ||
| function setStyle(instance, styles, oldStyles) { | ||
| if (oldStyles != null && typeof oldStyles === "object") { | ||
| for (const styleName in oldStyles) { | ||
| if (oldStyles.hasOwnProperty(styleName)) { | ||
| if (styles == null || !styles.hasOwnProperty(styleName)) { | ||
| instance[styleName] = null; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| if (styles != null && typeof styles === "object") { | ||
| for (const styleName in styles) { | ||
| if (styles.hasOwnProperty(styleName)) { | ||
| const value = styles[styleName]; | ||
| const oldValue = oldStyles?.[styleName]; | ||
| if (value !== oldValue) { | ||
| instance[styleName] = value; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| function setProperty(instance, type, propKey, propValue, oldPropValue) { | ||
| switch (propKey) { | ||
| case "onChange": | ||
| if (instance instanceof InputRenderable2) { | ||
| initEventListeners(instance, InputRenderableEvents.CHANGE, propValue, oldPropValue); | ||
| } else if (instance instanceof SelectRenderable2) { | ||
| initEventListeners(instance, SelectRenderableEvents.SELECTION_CHANGED, propValue, oldPropValue); | ||
| } else if (instance instanceof TabSelectRenderable2) { | ||
| initEventListeners(instance, TabSelectRenderableEvents.SELECTION_CHANGED, propValue, oldPropValue); | ||
| } | ||
| break; | ||
| case "onInput": | ||
| if (instance instanceof InputRenderable2) { | ||
| initEventListeners(instance, InputRenderableEvents.INPUT, propValue, oldPropValue); | ||
| } | ||
| break; | ||
| case "onSubmit": | ||
| if (instance instanceof InputRenderable2) { | ||
| initEventListeners(instance, InputRenderableEvents.ENTER, propValue, oldPropValue); | ||
| } else if (instance instanceof TextareaRenderable2) { | ||
| instance.onSubmit = propValue; | ||
| } | ||
| break; | ||
| case "onSelect": | ||
| if (instance instanceof SelectRenderable2) { | ||
| initEventListeners(instance, SelectRenderableEvents.ITEM_SELECTED, propValue, oldPropValue); | ||
| } else if (instance instanceof TabSelectRenderable2) { | ||
| initEventListeners(instance, TabSelectRenderableEvents.ITEM_SELECTED, propValue, oldPropValue); | ||
| } | ||
| break; | ||
| case "focused": | ||
| if (isRenderable(instance)) { | ||
| if (!!propValue) { | ||
| instance.focus(); | ||
| } else { | ||
| instance.blur(); | ||
| } | ||
| } | ||
| break; | ||
| case "style": | ||
| setStyle(instance, propValue, oldPropValue); | ||
| break; | ||
| case "children": | ||
| break; | ||
| default: | ||
| instance[propKey] = propValue; | ||
| } | ||
| } | ||
| function setInitialProperties(instance, type, props) { | ||
| for (const propKey in props) { | ||
| if (!props.hasOwnProperty(propKey)) { | ||
| continue; | ||
| } | ||
| const propValue = props[propKey]; | ||
| if (propValue == null) { | ||
| continue; | ||
| } | ||
| setProperty(instance, type, propKey, propValue); | ||
| } | ||
| } | ||
| function updateProperties(instance, type, oldProps, newProps) { | ||
| for (const propKey in oldProps) { | ||
| const oldProp = oldProps[propKey]; | ||
| if (oldProps.hasOwnProperty(propKey) && oldProp != null && !newProps.hasOwnProperty(propKey)) { | ||
| setProperty(instance, type, propKey, null, oldProp); | ||
| } | ||
| } | ||
| for (const propKey in newProps) { | ||
| const newProp = newProps[propKey]; | ||
| const oldProp = oldProps[propKey]; | ||
| if (newProps.hasOwnProperty(propKey) && newProp !== oldProp && (newProp != null || oldProp != null)) { | ||
| setProperty(instance, type, propKey, newProp, oldProp); | ||
| } | ||
| } | ||
| } | ||
| // src/reconciler/host-config.ts | ||
| var currentUpdatePriority = NoEventPriority; | ||
| var hostConfig = { | ||
| supportsMutation: true, | ||
| supportsPersistence: false, | ||
| supportsHydration: false, | ||
| supportsMicrotasks: true, | ||
| scheduleMicrotask: queueMicrotask, | ||
| createInstance(type, props, rootContainerInstance, hostContext) { | ||
| if (textNodeKeys.includes(type) && !hostContext.isInsideText) { | ||
| throw new Error(`Component of type "${type}" must be created inside of a text node`); | ||
| } | ||
| const id = getNextId(type); | ||
| const components = getComponentCatalogue(); | ||
| if (!components[type]) { | ||
| throw new Error(`Unknown component type: ${type}`); | ||
| } | ||
| return new components[type](rootContainerInstance.ctx, { | ||
| id, | ||
| ...props | ||
| }); | ||
| }, | ||
| appendChild(parent, child) { | ||
| parent.add(child); | ||
| }, | ||
| removeChild(parent, child) { | ||
| parent.remove(child.id); | ||
| }, | ||
| insertBefore(parent, child, beforeChild) { | ||
| parent.insertBefore(child, beforeChild); | ||
| }, | ||
| insertInContainerBefore(parent, child, beforeChild) { | ||
| parent.insertBefore(child, beforeChild); | ||
| }, | ||
| removeChildFromContainer(parent, child) { | ||
| parent.remove(child.id); | ||
| }, | ||
| prepareForCommit(containerInfo) { | ||
| return null; | ||
| }, | ||
| resetAfterCommit(containerInfo) { | ||
| containerInfo.requestRender(); | ||
| }, | ||
| getRootHostContext(rootContainerInstance) { | ||
| return { isInsideText: false }; | ||
| }, | ||
| getChildHostContext(parentHostContext, type, rootContainerInstance) { | ||
| const isInsideText = ["text", ...textNodeKeys].includes(type); | ||
| return { ...parentHostContext, isInsideText }; | ||
| }, | ||
| shouldSetTextContent(type, props) { | ||
| return false; | ||
| }, | ||
| createTextInstance(text, rootContainerInstance, hostContext) { | ||
| if (!hostContext.isInsideText) { | ||
| throw new Error("Text must be created inside of a text node"); | ||
| } | ||
| return TextNodeRenderable2.fromString(text); | ||
| }, | ||
| scheduleTimeout: setTimeout, | ||
| cancelTimeout: clearTimeout, | ||
| noTimeout: -1, | ||
| shouldAttemptEagerTransition() { | ||
| return true; | ||
| }, | ||
| finalizeInitialChildren(instance, type, props, rootContainerInstance, hostContext) { | ||
| setInitialProperties(instance, type, props); | ||
| return false; | ||
| }, | ||
| commitMount(instance, type, props, internalInstanceHandle) {}, | ||
| commitUpdate(instance, type, oldProps, newProps, internalInstanceHandle) { | ||
| updateProperties(instance, type, oldProps, newProps); | ||
| }, | ||
| commitTextUpdate(textInstance, oldText, newText) { | ||
| textInstance.children = [newText]; | ||
| }, | ||
| appendChildToContainer(container, child) { | ||
| container.add(child); | ||
| }, | ||
| appendInitialChild(parent, child) { | ||
| parent.add(child); | ||
| }, | ||
| hideInstance(instance) { | ||
| instance.visible = false; | ||
| }, | ||
| unhideInstance(instance, props) { | ||
| instance.visible = true; | ||
| }, | ||
| hideTextInstance(textInstance) { | ||
| textInstance.visible = false; | ||
| }, | ||
| unhideTextInstance(textInstance, text) { | ||
| textInstance.visible = true; | ||
| }, | ||
| clearContainer(container) { | ||
| const children = container.getChildren(); | ||
| children.forEach((child) => container.remove(child.id)); | ||
| }, | ||
| setCurrentUpdatePriority(newPriority) { | ||
| currentUpdatePriority = newPriority; | ||
| }, | ||
| getCurrentUpdatePriority: () => currentUpdatePriority, | ||
| resolveUpdatePriority() { | ||
| if (currentUpdatePriority !== NoEventPriority) { | ||
| return currentUpdatePriority; | ||
| } | ||
| return DefaultEventPriority; | ||
| }, | ||
| maySuspendCommit() { | ||
| return false; | ||
| }, | ||
| maySuspendCommitOnUpdate() { | ||
| return false; | ||
| }, | ||
| maySuspendCommitInSyncRender() { | ||
| return false; | ||
| }, | ||
| NotPendingTransition: null, | ||
| HostTransitionContext: createContext2(null), | ||
| resetFormInstance() {}, | ||
| requestPostPaintCallback() {}, | ||
| trackSchedulerEvent() {}, | ||
| resolveEventType() { | ||
| return null; | ||
| }, | ||
| resolveEventTimeStamp() { | ||
| return -1.1; | ||
| }, | ||
| preloadInstance() { | ||
| return true; | ||
| }, | ||
| startSuspendingCommit() {}, | ||
| suspendInstance() {}, | ||
| waitForCommitToBeReady() { | ||
| return null; | ||
| }, | ||
| detachDeletedInstance(instance) { | ||
| if (!instance.parent) { | ||
| instance.destroyRecursively(); | ||
| } | ||
| }, | ||
| getPublicInstance(instance) { | ||
| return instance; | ||
| }, | ||
| preparePortalMount(containerInfo) {}, | ||
| isPrimaryRenderer: true, | ||
| getInstanceFromNode() { | ||
| return null; | ||
| }, | ||
| beforeActiveInstanceBlur() {}, | ||
| afterActiveInstanceBlur() {}, | ||
| prepareScopeUpdate() {}, | ||
| getInstanceFromScope() { | ||
| return null; | ||
| }, | ||
| rendererPackageName: "@opentui/react", | ||
| rendererVersion: package_default.version | ||
| }; | ||
| // src/reconciler/reconciler.ts | ||
| var reconciler = ReactReconciler(hostConfig); | ||
| if (process.env["DEV"] === "true") { | ||
| try { | ||
| await import("./chunk-bdqvmfwv.js"); | ||
| } catch (error) { | ||
| if (error.code === "ERR_MODULE_NOT_FOUND") { | ||
| console.warn(` | ||
| The environment variable DEV is set to true, so opentui tried to import \`react-devtools-core\`, | ||
| but this failed as it was not installed. Debugging with React DevTools requires it. | ||
| To install use this command: | ||
| $ bun add react-devtools-core@7 -d | ||
| `.trim() + ` | ||
| `); | ||
| } else { | ||
| throw error; | ||
| } | ||
| } | ||
| } | ||
| reconciler.injectIntoDevTools(); | ||
| function _render(element, root) { | ||
| const container = reconciler.createContainer(root, ConcurrentRoot, null, false, null, "", console.error, console.error, console.error, () => {}); | ||
| reconciler.updateContainer(element, container, null, () => {}); | ||
| return container; | ||
| } | ||
| // src/reconciler/renderer.ts | ||
| var _r = reconciler; | ||
| var flushSync = _r.flushSyncFromReconciler ?? _r.flushSync; | ||
| var { createPortal } = reconciler; | ||
| function createRoot(renderer) { | ||
| let container = null; | ||
| const cleanup = () => { | ||
| if (container) { | ||
| reconciler.updateContainer(null, container, null, () => {}); | ||
| reconciler.flushSyncWork(); | ||
| container = null; | ||
| } | ||
| }; | ||
| renderer.once(CliRenderEvents.DESTROY, cleanup); | ||
| return { | ||
| render: (node) => { | ||
| engine.attach(renderer); | ||
| container = _render(React2.createElement(AppContext.Provider, { value: { keyHandler: renderer.keyInput, renderer } }, React2.createElement(ErrorBoundary, null, node)), renderer.root); | ||
| }, | ||
| unmount: cleanup | ||
| }; | ||
| } | ||
| export { baseComponents, componentCatalogue, extend, getComponentCatalogue, AppContext, useAppContext, Fragment, jsxDEV, flushSync, createPortal, createRoot }; |
| import { plugin as registerBunPlugin } from "bun"; | ||
| import * as coreRuntime from "@opentui/core"; | ||
| import { createRuntimePlugin, } from "@opentui/core/runtime-plugin"; | ||
| import * as reactRuntime from "react"; | ||
| import * as reactJsxRuntime from "react/jsx-runtime"; | ||
| import * as reactJsxDevRuntime from "react/jsx-dev-runtime"; | ||
| import * as opentuiReactRuntime from "../index.js"; | ||
| const runtimePluginSupportInstalledKey = "__opentuiReactRuntimePluginSupportInstalled__"; | ||
| const defaultRuntimeModules = { | ||
| "@opentui/react": opentuiReactRuntime, | ||
| "@opentui/react/jsx-runtime": reactJsxRuntime, | ||
| "@opentui/react/jsx-dev-runtime": reactJsxDevRuntime, | ||
| react: reactRuntime, | ||
| "react/jsx-runtime": reactJsxRuntime, | ||
| "react/jsx-dev-runtime": reactJsxDevRuntime, | ||
| }; | ||
| function normalizeRewriteKey(rewrite) { | ||
| return `${rewrite?.nodeModulesRuntimeSpecifiers ?? true}:${rewrite?.nodeModulesBareSpecifiers ?? false}`; | ||
| } | ||
| function createRuntimeModules(options) { | ||
| return { | ||
| ...defaultRuntimeModules, | ||
| ...(options?.additional ?? {}), | ||
| }; | ||
| } | ||
| function assertCompatibleInstall(install, modules, options) { | ||
| for (const specifier of Object.keys(modules)) { | ||
| if (!install.specifiers.has(specifier)) { | ||
| throw new Error(`OpenTUI React runtime plugin support is already installed without ${specifier}. Call ensureRuntimePluginSupport({ additional }) from @opentui/react/runtime-plugin-support/configure before importing @opentui/react/runtime-plugin-support.`); | ||
| } | ||
| } | ||
| if (options?.core && options.core !== install.core) { | ||
| throw new Error("OpenTUI React runtime plugin support is already installed with a different core runtime module."); | ||
| } | ||
| if (options?.rewrite && normalizeRewriteKey(options.rewrite) !== install.rewriteKey) { | ||
| throw new Error("OpenTUI React runtime plugin support is already installed with different rewrite options."); | ||
| } | ||
| } | ||
| export function ensureRuntimePluginSupport(options = {}) { | ||
| const state = globalThis; | ||
| const modules = createRuntimeModules(options); | ||
| const core = options.core ?? coreRuntime; | ||
| const rewriteKey = normalizeRewriteKey(options.rewrite); | ||
| const install = state[runtimePluginSupportInstalledKey]; | ||
| if (install) { | ||
| assertCompatibleInstall(install, modules, options); | ||
| return false; | ||
| } | ||
| registerBunPlugin(createRuntimePlugin({ | ||
| core, | ||
| additional: modules, | ||
| rewrite: options.rewrite, | ||
| })); | ||
| state[runtimePluginSupportInstalledKey] = { | ||
| specifiers: new Set(Object.keys(modules)), | ||
| core, | ||
| rewriteKey, | ||
| }; | ||
| return true; | ||
| } | ||
| //# sourceMappingURL=runtime-plugin-support-configure.js.map |
| {"version":3,"file":"runtime-plugin-support-configure.js","sourceRoot":"","sources":["runtime-plugin-support-configure.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,iBAAiB,EAAE,MAAM,KAAK,CAAA;AACjD,OAAO,KAAK,WAAW,MAAM,eAAe,CAAA;AAC5C,OAAO,EACL,mBAAmB,GAGpB,MAAM,8BAA8B,CAAA;AACrC,OAAO,KAAK,YAAY,MAAM,OAAO,CAAA;AACrC,OAAO,KAAK,eAAe,MAAM,mBAAmB,CAAA;AACpD,OAAO,KAAK,kBAAkB,MAAM,uBAAuB,CAAA;AAC3D,OAAO,KAAK,mBAAmB,MAAM,aAAa,CAAA;AAElD,MAAM,gCAAgC,GAAG,+CAA+C,CAAA;AAkBxF,MAAM,qBAAqB,GAAuC;IAChE,gBAAgB,EAAE,mBAA8C;IAChE,4BAA4B,EAAE,eAA0C;IACxE,gCAAgC,EAAE,kBAA6C;IAC/E,KAAK,EAAE,YAAuC;IAC9C,mBAAmB,EAAE,eAA0C;IAC/D,uBAAuB,EAAE,kBAA6C;CACvE,CAAA;AAED,SAAS,mBAAmB,CAAC,OAAgD;IAC3E,OAAO,GAAG,OAAO,EAAE,4BAA4B,IAAI,IAAI,IAAI,OAAO,EAAE,yBAAyB,IAAI,KAAK,EAAE,CAAA;AAC1G,CAAC;AAED,SAAS,oBAAoB,CAAC,OAA0C;IACtE,OAAO;QACL,GAAG,qBAAqB;QACxB,GAAG,CAAC,OAAO,EAAE,UAAU,IAAI,EAAE,CAAC;KAC/B,CAAA;AACH,CAAC;AAED,SAAS,uBAAuB,CAC9B,OAAoC,EACpC,OAA2C,EAC3C,OAA0C;IAE1C,KAAK,MAAM,SAAS,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QAC7C,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;YACvC,MAAM,IAAI,KAAK,CACb,qEAAqE,SAAS,gKAAgK,CAC/O,CAAA;QACH,CAAC;IACH,CAAC;IAED,IAAI,OAAO,EAAE,IAAI,IAAI,OAAO,CAAC,IAAI,KAAK,OAAO,CAAC,IAAI,EAAE,CAAC;QACnD,MAAM,IAAI,KAAK,CAAC,iGAAiG,CAAC,CAAA;IACpH,CAAC;IAED,IAAI,OAAO,EAAE,OAAO,IAAI,mBAAmB,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,OAAO,CAAC,UAAU,EAAE,CAAC;QACpF,MAAM,IAAI,KAAK,CAAC,2FAA2F,CAAC,CAAA;IAC9G,CAAC;AACH,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,UAA4C,EAAE;IACvF,MAAM,KAAK,GAAG,UAAuC,CAAA;IACrD,MAAM,OAAO,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAA;IAC7C,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAK,WAAuC,CAAA;IACrE,MAAM,UAAU,GAAG,mBAAmB,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;IAEvD,MAAM,OAAO,GAAG,KAAK,CAAC,gCAAgC,CAAC,CAAA;IACvD,IAAI,OAAO,EAAE,CAAC;QACZ,uBAAuB,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,CAAA;QAClD,OAAO,KAAK,CAAA;IACd,CAAC;IAED,iBAAiB,CACf,mBAAmB,CAAC;QAClB,IAAI;QACJ,UAAU,EAAE,OAAO;QACnB,OAAO,EAAE,OAAO,CAAC,OAAO;KACzB,CAAC,CACH,CAAA;IAED,KAAK,CAAC,gCAAgC,CAAC,GAAG;QACxC,UAAU,EAAE,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACzC,IAAI;QACJ,UAAU;KACX,CAAA;IACD,OAAO,IAAI,CAAA;AACb,CAAC"} |
| const errorMessage = "@opentui/react/runtime-plugin-support/configure is Bun-only and is not available in Node.js. Use Bun to import this entrypoint." | ||
| export function ensureRuntimePluginSupport() { | ||
| throw new Error(errorMessage) | ||
| } | ||
| throw new Error(errorMessage) |
| import { ensureRuntimePluginSupport } from "./runtime-plugin-support-configure.js"; | ||
| export { ensureRuntimePluginSupport }; | ||
| ensureRuntimePluginSupport(); | ||
| //# sourceMappingURL=runtime-plugin-support.js.map |
| {"version":3,"file":"runtime-plugin-support.js","sourceRoot":"","sources":["runtime-plugin-support.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,MAAM,uCAAuC,CAAA;AAElF,OAAO,EAAE,0BAA0B,EAAE,CAAA;AAGrC,0BAA0B,EAAE,CAAA"} |
| const errorMessage = "@opentui/react/runtime-plugin-support is Bun-only and is not available in Node.js. Use Bun to import this entrypoint." | ||
| export function ensureRuntimePluginSupport() { | ||
| throw new Error(errorMessage) | ||
| } | ||
| throw new Error(errorMessage) |
+1
-1
@@ -14,3 +14,3 @@ // @bun | ||
| useAppContext | ||
| } from "./chunk-52d5gdqd.js"; | ||
| } from "./chunk-h361mw37.js"; | ||
| import"./chunk-2mx7fq49.js"; | ||
@@ -17,0 +17,0 @@ // src/hooks/use-blur.ts |
+8
-4
@@ -7,3 +7,3 @@ { | ||
| "type": "module", | ||
| "version": "0.3.4", | ||
| "version": "0.4.0", | ||
| "description": "React renderer for building terminal user interfaces using OpenTUI core", | ||
@@ -34,7 +34,11 @@ "license": "MIT", | ||
| "types": "./scripts/runtime-plugin-support.d.ts", | ||
| "import": "./scripts/runtime-plugin-support.ts" | ||
| "bun": "./scripts/runtime-plugin-support.js", | ||
| "node": "./scripts/runtime-plugin-support.node.js", | ||
| "default": "./scripts/runtime-plugin-support.node.js" | ||
| }, | ||
| "./runtime-plugin-support/configure": { | ||
| "types": "./scripts/runtime-plugin-support-configure.d.ts", | ||
| "import": "./scripts/runtime-plugin-support-configure.ts" | ||
| "bun": "./scripts/runtime-plugin-support-configure.js", | ||
| "node": "./scripts/runtime-plugin-support-configure.node.js", | ||
| "default": "./scripts/runtime-plugin-support-configure.node.js" | ||
| }, | ||
@@ -53,3 +57,3 @@ "./jsx-runtime": { | ||
| "dependencies": { | ||
| "@opentui/core": "0.3.4", | ||
| "@opentui/core": "0.4.0", | ||
| "react-reconciler": "^0.33.0" | ||
@@ -56,0 +60,0 @@ }, |
+1
-1
| // @bun | ||
| import { | ||
| createRoot | ||
| } from "./chunk-52d5gdqd.js"; | ||
| } from "./chunk-h361mw37.js"; | ||
| import"./chunk-2mx7fq49.js"; | ||
@@ -6,0 +6,0 @@ |
| // @bun | ||
| import { | ||
| __require | ||
| } from "./chunk-2mx7fq49.js"; | ||
| // src/components/index.ts | ||
| import { | ||
| ASCIIFontRenderable, | ||
| BoxRenderable, | ||
| CodeRenderable, | ||
| DiffRenderable, | ||
| InputRenderable, | ||
| LineNumberRenderable, | ||
| MarkdownRenderable, | ||
| ScrollBoxRenderable, | ||
| SelectRenderable, | ||
| TabSelectRenderable, | ||
| TextareaRenderable, | ||
| TextRenderable | ||
| } from "@opentui/core"; | ||
| // src/components/text.ts | ||
| import { TextAttributes, TextNodeRenderable } from "@opentui/core"; | ||
| var textNodeKeys = ["span", "b", "strong", "i", "em", "u", "br", "a"]; | ||
| class SpanRenderable extends TextNodeRenderable { | ||
| ctx; | ||
| constructor(ctx, options) { | ||
| super(options); | ||
| this.ctx = ctx; | ||
| } | ||
| } | ||
| class TextModifierRenderable extends SpanRenderable { | ||
| constructor(options, modifier) { | ||
| super(null, options); | ||
| if (modifier === "b" || modifier === "strong") { | ||
| this.attributes = (this.attributes || 0) | TextAttributes.BOLD; | ||
| } else if (modifier === "i" || modifier === "em") { | ||
| this.attributes = (this.attributes || 0) | TextAttributes.ITALIC; | ||
| } else if (modifier === "u") { | ||
| this.attributes = (this.attributes || 0) | TextAttributes.UNDERLINE; | ||
| } | ||
| } | ||
| } | ||
| class BoldSpanRenderable extends TextModifierRenderable { | ||
| constructor(_ctx, options) { | ||
| super(options, "b"); | ||
| } | ||
| } | ||
| class ItalicSpanRenderable extends TextModifierRenderable { | ||
| constructor(_ctx, options) { | ||
| super(options, "i"); | ||
| } | ||
| } | ||
| class UnderlineSpanRenderable extends TextModifierRenderable { | ||
| constructor(_ctx, options) { | ||
| super(options, "u"); | ||
| } | ||
| } | ||
| class LineBreakRenderable extends SpanRenderable { | ||
| constructor(_ctx, options) { | ||
| super(null, options); | ||
| this.add(); | ||
| } | ||
| add() { | ||
| return super.add(` | ||
| `); | ||
| } | ||
| } | ||
| class LinkRenderable extends SpanRenderable { | ||
| constructor(_ctx, options) { | ||
| const linkOptions = { | ||
| ...options, | ||
| link: { url: options.href } | ||
| }; | ||
| super(null, linkOptions); | ||
| } | ||
| } | ||
| // src/components/index.ts | ||
| var baseComponents = { | ||
| box: BoxRenderable, | ||
| text: TextRenderable, | ||
| code: CodeRenderable, | ||
| diff: DiffRenderable, | ||
| markdown: MarkdownRenderable, | ||
| input: InputRenderable, | ||
| select: SelectRenderable, | ||
| textarea: TextareaRenderable, | ||
| scrollbox: ScrollBoxRenderable, | ||
| "ascii-font": ASCIIFontRenderable, | ||
| "tab-select": TabSelectRenderable, | ||
| "line-number": LineNumberRenderable, | ||
| span: SpanRenderable, | ||
| br: LineBreakRenderable, | ||
| b: BoldSpanRenderable, | ||
| strong: BoldSpanRenderable, | ||
| i: ItalicSpanRenderable, | ||
| em: ItalicSpanRenderable, | ||
| u: UnderlineSpanRenderable, | ||
| a: LinkRenderable | ||
| }; | ||
| var componentCatalogue = { ...baseComponents }; | ||
| function extend(objects) { | ||
| Object.assign(componentCatalogue, objects); | ||
| } | ||
| function getComponentCatalogue() { | ||
| return componentCatalogue; | ||
| } | ||
| // src/components/app.tsx | ||
| import { createContext, useContext } from "react"; | ||
| var AppContext = createContext({ | ||
| keyHandler: null, | ||
| renderer: null | ||
| }); | ||
| var useAppContext = () => { | ||
| return useContext(AppContext); | ||
| }; | ||
| // src/reconciler/renderer.ts | ||
| import { CliRenderEvents, engine } from "@opentui/core"; | ||
| import React2 from "react"; | ||
| // src/components/error-boundary.tsx | ||
| import React from "react"; | ||
| // jsx-dev-runtime.js | ||
| import { Fragment, jsxDEV } from "react/jsx-dev-runtime"; | ||
| // src/components/error-boundary.tsx | ||
| class ErrorBoundary extends React.Component { | ||
| constructor(props) { | ||
| super(props); | ||
| this.state = { hasError: false, error: null }; | ||
| } | ||
| static getDerivedStateFromError(error) { | ||
| return { hasError: true, error }; | ||
| } | ||
| render() { | ||
| if (this.state.hasError && this.state.error) { | ||
| return /* @__PURE__ */ jsxDEV("box", { | ||
| style: { flexDirection: "column", padding: 2 }, | ||
| children: /* @__PURE__ */ jsxDEV("text", { | ||
| fg: "red", | ||
| children: this.state.error.stack || this.state.error.message | ||
| }, undefined, false, undefined, this) | ||
| }, undefined, false, undefined, this); | ||
| } | ||
| return this.props.children; | ||
| } | ||
| } | ||
| // src/reconciler/reconciler.ts | ||
| import ReactReconciler from "react-reconciler"; | ||
| import { ConcurrentRoot } from "react-reconciler/constants"; | ||
| // src/reconciler/host-config.ts | ||
| import { TextNodeRenderable as TextNodeRenderable2 } from "@opentui/core"; | ||
| // package.json | ||
| var package_default = { | ||
| name: "@opentui/react", | ||
| version: "0.3.4", | ||
| description: "React renderer for building terminal user interfaces using OpenTUI core", | ||
| license: "MIT", | ||
| repository: { | ||
| type: "git", | ||
| url: "https://github.com/anomalyco/opentui", | ||
| directory: "packages/react" | ||
| }, | ||
| module: "src/index.ts", | ||
| type: "module", | ||
| private: true, | ||
| main: "src/index.ts", | ||
| exports: { | ||
| ".": { | ||
| import: "./src/index.ts", | ||
| types: "./src/index.ts" | ||
| }, | ||
| "./test-utils": { | ||
| import: "./src/test-utils.ts", | ||
| types: "./src/test-utils.d.ts" | ||
| }, | ||
| "./runtime-plugin-support": { | ||
| import: "./scripts/runtime-plugin-support.ts", | ||
| types: "./scripts/runtime-plugin-support.ts" | ||
| }, | ||
| "./runtime-plugin-support/configure": { | ||
| import: "./scripts/runtime-plugin-support-configure.ts", | ||
| types: "./scripts/runtime-plugin-support-configure.ts" | ||
| }, | ||
| "./jsx-runtime": { | ||
| import: "./jsx-runtime.js", | ||
| types: "./jsx-runtime.d.ts" | ||
| }, | ||
| "./jsx-dev-runtime": { | ||
| import: "./jsx-dev-runtime.js", | ||
| types: "./jsx-dev-runtime.d.ts" | ||
| } | ||
| }, | ||
| scripts: { | ||
| build: "bun run scripts/build.ts", | ||
| "build:examples": "bun examples/build.ts", | ||
| "build:dev": "bun run scripts/build.ts --dev", | ||
| publish: "bun run scripts/publish.ts", | ||
| test: "bun test" | ||
| }, | ||
| devDependencies: { | ||
| "@opentui/keymap": "workspace:*", | ||
| "@types/bun": "latest", | ||
| "@types/node": "^24.0.0", | ||
| "@types/react": "^19.2.0", | ||
| "@types/react-reconciler": "^0.33.0", | ||
| "@types/ws": "^8.18.1", | ||
| react: ">=19.2.0", | ||
| "react-devtools-core": "^7.0.1", | ||
| typescript: "^5", | ||
| ws: "^8.18.0" | ||
| }, | ||
| peerDependencies: { | ||
| react: ">=19.2.0", | ||
| "react-devtools-core": "^7.0.1", | ||
| ws: "^8.18.0" | ||
| }, | ||
| peerDependenciesMeta: { | ||
| "react-devtools-core": { | ||
| optional: true | ||
| }, | ||
| ws: { | ||
| optional: true | ||
| } | ||
| }, | ||
| dependencies: { | ||
| "@opentui/core": "workspace:*", | ||
| "react-reconciler": "^0.33.0" | ||
| } | ||
| }; | ||
| // src/reconciler/host-config.ts | ||
| import { createContext as createContext2 } from "react"; | ||
| import { DefaultEventPriority, NoEventPriority } from "react-reconciler/constants"; | ||
| // src/utils/id.ts | ||
| var idCounter = new Map; | ||
| function getNextId(type) { | ||
| if (!idCounter.has(type)) { | ||
| idCounter.set(type, 0); | ||
| } | ||
| const value = idCounter.get(type) + 1; | ||
| idCounter.set(type, value); | ||
| return `${type}-${value}`; | ||
| } | ||
| // src/utils/index.ts | ||
| import { | ||
| InputRenderable as InputRenderable2, | ||
| InputRenderableEvents, | ||
| isRenderable, | ||
| SelectRenderable as SelectRenderable2, | ||
| SelectRenderableEvents, | ||
| TabSelectRenderable as TabSelectRenderable2, | ||
| TabSelectRenderableEvents, | ||
| TextareaRenderable as TextareaRenderable2 | ||
| } from "@opentui/core"; | ||
| function initEventListeners(instance, eventName, listener, previousListener) { | ||
| if (previousListener) { | ||
| instance.off(eventName, previousListener); | ||
| } | ||
| if (listener) { | ||
| instance.on(eventName, listener); | ||
| } | ||
| } | ||
| function setStyle(instance, styles, oldStyles) { | ||
| if (oldStyles != null && typeof oldStyles === "object") { | ||
| for (const styleName in oldStyles) { | ||
| if (oldStyles.hasOwnProperty(styleName)) { | ||
| if (styles == null || !styles.hasOwnProperty(styleName)) { | ||
| instance[styleName] = null; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| if (styles != null && typeof styles === "object") { | ||
| for (const styleName in styles) { | ||
| if (styles.hasOwnProperty(styleName)) { | ||
| const value = styles[styleName]; | ||
| const oldValue = oldStyles?.[styleName]; | ||
| if (value !== oldValue) { | ||
| instance[styleName] = value; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| function setProperty(instance, type, propKey, propValue, oldPropValue) { | ||
| switch (propKey) { | ||
| case "onChange": | ||
| if (instance instanceof InputRenderable2) { | ||
| initEventListeners(instance, InputRenderableEvents.CHANGE, propValue, oldPropValue); | ||
| } else if (instance instanceof SelectRenderable2) { | ||
| initEventListeners(instance, SelectRenderableEvents.SELECTION_CHANGED, propValue, oldPropValue); | ||
| } else if (instance instanceof TabSelectRenderable2) { | ||
| initEventListeners(instance, TabSelectRenderableEvents.SELECTION_CHANGED, propValue, oldPropValue); | ||
| } | ||
| break; | ||
| case "onInput": | ||
| if (instance instanceof InputRenderable2) { | ||
| initEventListeners(instance, InputRenderableEvents.INPUT, propValue, oldPropValue); | ||
| } | ||
| break; | ||
| case "onSubmit": | ||
| if (instance instanceof InputRenderable2) { | ||
| initEventListeners(instance, InputRenderableEvents.ENTER, propValue, oldPropValue); | ||
| } else if (instance instanceof TextareaRenderable2) { | ||
| instance.onSubmit = propValue; | ||
| } | ||
| break; | ||
| case "onSelect": | ||
| if (instance instanceof SelectRenderable2) { | ||
| initEventListeners(instance, SelectRenderableEvents.ITEM_SELECTED, propValue, oldPropValue); | ||
| } else if (instance instanceof TabSelectRenderable2) { | ||
| initEventListeners(instance, TabSelectRenderableEvents.ITEM_SELECTED, propValue, oldPropValue); | ||
| } | ||
| break; | ||
| case "focused": | ||
| if (isRenderable(instance)) { | ||
| if (!!propValue) { | ||
| instance.focus(); | ||
| } else { | ||
| instance.blur(); | ||
| } | ||
| } | ||
| break; | ||
| case "style": | ||
| setStyle(instance, propValue, oldPropValue); | ||
| break; | ||
| case "children": | ||
| break; | ||
| default: | ||
| instance[propKey] = propValue; | ||
| } | ||
| } | ||
| function setInitialProperties(instance, type, props) { | ||
| for (const propKey in props) { | ||
| if (!props.hasOwnProperty(propKey)) { | ||
| continue; | ||
| } | ||
| const propValue = props[propKey]; | ||
| if (propValue == null) { | ||
| continue; | ||
| } | ||
| setProperty(instance, type, propKey, propValue); | ||
| } | ||
| } | ||
| function updateProperties(instance, type, oldProps, newProps) { | ||
| for (const propKey in oldProps) { | ||
| const oldProp = oldProps[propKey]; | ||
| if (oldProps.hasOwnProperty(propKey) && oldProp != null && !newProps.hasOwnProperty(propKey)) { | ||
| setProperty(instance, type, propKey, null, oldProp); | ||
| } | ||
| } | ||
| for (const propKey in newProps) { | ||
| const newProp = newProps[propKey]; | ||
| const oldProp = oldProps[propKey]; | ||
| if (newProps.hasOwnProperty(propKey) && newProp !== oldProp && (newProp != null || oldProp != null)) { | ||
| setProperty(instance, type, propKey, newProp, oldProp); | ||
| } | ||
| } | ||
| } | ||
| // src/reconciler/host-config.ts | ||
| var currentUpdatePriority = NoEventPriority; | ||
| var hostConfig = { | ||
| supportsMutation: true, | ||
| supportsPersistence: false, | ||
| supportsHydration: false, | ||
| supportsMicrotasks: true, | ||
| scheduleMicrotask: queueMicrotask, | ||
| createInstance(type, props, rootContainerInstance, hostContext) { | ||
| if (textNodeKeys.includes(type) && !hostContext.isInsideText) { | ||
| throw new Error(`Component of type "${type}" must be created inside of a text node`); | ||
| } | ||
| const id = getNextId(type); | ||
| const components = getComponentCatalogue(); | ||
| if (!components[type]) { | ||
| throw new Error(`Unknown component type: ${type}`); | ||
| } | ||
| return new components[type](rootContainerInstance.ctx, { | ||
| id, | ||
| ...props | ||
| }); | ||
| }, | ||
| appendChild(parent, child) { | ||
| parent.add(child); | ||
| }, | ||
| removeChild(parent, child) { | ||
| parent.remove(child.id); | ||
| }, | ||
| insertBefore(parent, child, beforeChild) { | ||
| parent.insertBefore(child, beforeChild); | ||
| }, | ||
| insertInContainerBefore(parent, child, beforeChild) { | ||
| parent.insertBefore(child, beforeChild); | ||
| }, | ||
| removeChildFromContainer(parent, child) { | ||
| parent.remove(child.id); | ||
| }, | ||
| prepareForCommit(containerInfo) { | ||
| return null; | ||
| }, | ||
| resetAfterCommit(containerInfo) { | ||
| containerInfo.requestRender(); | ||
| }, | ||
| getRootHostContext(rootContainerInstance) { | ||
| return { isInsideText: false }; | ||
| }, | ||
| getChildHostContext(parentHostContext, type, rootContainerInstance) { | ||
| const isInsideText = ["text", ...textNodeKeys].includes(type); | ||
| return { ...parentHostContext, isInsideText }; | ||
| }, | ||
| shouldSetTextContent(type, props) { | ||
| return false; | ||
| }, | ||
| createTextInstance(text, rootContainerInstance, hostContext) { | ||
| if (!hostContext.isInsideText) { | ||
| throw new Error("Text must be created inside of a text node"); | ||
| } | ||
| return TextNodeRenderable2.fromString(text); | ||
| }, | ||
| scheduleTimeout: setTimeout, | ||
| cancelTimeout: clearTimeout, | ||
| noTimeout: -1, | ||
| shouldAttemptEagerTransition() { | ||
| return true; | ||
| }, | ||
| finalizeInitialChildren(instance, type, props, rootContainerInstance, hostContext) { | ||
| setInitialProperties(instance, type, props); | ||
| return false; | ||
| }, | ||
| commitMount(instance, type, props, internalInstanceHandle) {}, | ||
| commitUpdate(instance, type, oldProps, newProps, internalInstanceHandle) { | ||
| updateProperties(instance, type, oldProps, newProps); | ||
| }, | ||
| commitTextUpdate(textInstance, oldText, newText) { | ||
| textInstance.children = [newText]; | ||
| }, | ||
| appendChildToContainer(container, child) { | ||
| container.add(child); | ||
| }, | ||
| appendInitialChild(parent, child) { | ||
| parent.add(child); | ||
| }, | ||
| hideInstance(instance) { | ||
| instance.visible = false; | ||
| }, | ||
| unhideInstance(instance, props) { | ||
| instance.visible = true; | ||
| }, | ||
| hideTextInstance(textInstance) { | ||
| textInstance.visible = false; | ||
| }, | ||
| unhideTextInstance(textInstance, text) { | ||
| textInstance.visible = true; | ||
| }, | ||
| clearContainer(container) { | ||
| const children = container.getChildren(); | ||
| children.forEach((child) => container.remove(child.id)); | ||
| }, | ||
| setCurrentUpdatePriority(newPriority) { | ||
| currentUpdatePriority = newPriority; | ||
| }, | ||
| getCurrentUpdatePriority: () => currentUpdatePriority, | ||
| resolveUpdatePriority() { | ||
| if (currentUpdatePriority !== NoEventPriority) { | ||
| return currentUpdatePriority; | ||
| } | ||
| return DefaultEventPriority; | ||
| }, | ||
| maySuspendCommit() { | ||
| return false; | ||
| }, | ||
| maySuspendCommitOnUpdate() { | ||
| return false; | ||
| }, | ||
| maySuspendCommitInSyncRender() { | ||
| return false; | ||
| }, | ||
| NotPendingTransition: null, | ||
| HostTransitionContext: createContext2(null), | ||
| resetFormInstance() {}, | ||
| requestPostPaintCallback() {}, | ||
| trackSchedulerEvent() {}, | ||
| resolveEventType() { | ||
| return null; | ||
| }, | ||
| resolveEventTimeStamp() { | ||
| return -1.1; | ||
| }, | ||
| preloadInstance() { | ||
| return true; | ||
| }, | ||
| startSuspendingCommit() {}, | ||
| suspendInstance() {}, | ||
| waitForCommitToBeReady() { | ||
| return null; | ||
| }, | ||
| detachDeletedInstance(instance) { | ||
| if (!instance.parent) { | ||
| instance.destroyRecursively(); | ||
| } | ||
| }, | ||
| getPublicInstance(instance) { | ||
| return instance; | ||
| }, | ||
| preparePortalMount(containerInfo) {}, | ||
| isPrimaryRenderer: true, | ||
| getInstanceFromNode() { | ||
| return null; | ||
| }, | ||
| beforeActiveInstanceBlur() {}, | ||
| afterActiveInstanceBlur() {}, | ||
| prepareScopeUpdate() {}, | ||
| getInstanceFromScope() { | ||
| return null; | ||
| }, | ||
| rendererPackageName: "@opentui/react", | ||
| rendererVersion: package_default.version | ||
| }; | ||
| // src/reconciler/reconciler.ts | ||
| var reconciler = ReactReconciler(hostConfig); | ||
| if (process.env["DEV"] === "true") { | ||
| try { | ||
| await import("./chunk-bdqvmfwv.js"); | ||
| } catch (error) { | ||
| if (error.code === "ERR_MODULE_NOT_FOUND") { | ||
| console.warn(` | ||
| The environment variable DEV is set to true, so opentui tried to import \`react-devtools-core\`, | ||
| but this failed as it was not installed. Debugging with React DevTools requires it. | ||
| To install use this command: | ||
| $ bun add react-devtools-core@7 -d | ||
| `.trim() + ` | ||
| `); | ||
| } else { | ||
| throw error; | ||
| } | ||
| } | ||
| } | ||
| reconciler.injectIntoDevTools(); | ||
| function _render(element, root) { | ||
| const container = reconciler.createContainer(root, ConcurrentRoot, null, false, null, "", console.error, console.error, console.error, () => {}); | ||
| reconciler.updateContainer(element, container, null, () => {}); | ||
| return container; | ||
| } | ||
| // src/reconciler/renderer.ts | ||
| var _r = reconciler; | ||
| var flushSync = _r.flushSyncFromReconciler ?? _r.flushSync; | ||
| var { createPortal } = reconciler; | ||
| function createRoot(renderer) { | ||
| let container = null; | ||
| const cleanup = () => { | ||
| if (container) { | ||
| reconciler.updateContainer(null, container, null, () => {}); | ||
| reconciler.flushSyncWork(); | ||
| container = null; | ||
| } | ||
| }; | ||
| renderer.once(CliRenderEvents.DESTROY, cleanup); | ||
| return { | ||
| render: (node) => { | ||
| engine.attach(renderer); | ||
| container = _render(React2.createElement(AppContext.Provider, { value: { keyHandler: renderer.keyInput, renderer } }, React2.createElement(ErrorBoundary, null, node)), renderer.root); | ||
| }, | ||
| unmount: cleanup | ||
| }; | ||
| } | ||
| export { baseComponents, componentCatalogue, extend, getComponentCatalogue, AppContext, useAppContext, Fragment, jsxDEV, flushSync, createPortal, createRoot }; |
| import { plugin as registerBunPlugin } from "bun" | ||
| import * as coreRuntime from "@opentui/core" | ||
| import { | ||
| createRuntimePlugin, | ||
| type RuntimeModuleEntry, | ||
| type RuntimePluginRewriteOptions, | ||
| } from "@opentui/core/runtime-plugin" | ||
| import * as reactRuntime from "react" | ||
| import * as reactJsxRuntime from "react/jsx-runtime" | ||
| import * as reactJsxDevRuntime from "react/jsx-dev-runtime" | ||
| import * as opentuiReactRuntime from "../index.js" | ||
| const runtimePluginSupportInstalledKey = "__opentuiReactRuntimePluginSupportInstalled__" | ||
| export interface ReactRuntimePluginSupportOptions { | ||
| additional?: Record<string, RuntimeModuleEntry> | ||
| core?: RuntimeModuleEntry | ||
| rewrite?: RuntimePluginRewriteOptions | ||
| } | ||
| interface RuntimePluginSupportInstall { | ||
| specifiers: ReadonlySet<string> | ||
| core: RuntimeModuleEntry | ||
| rewriteKey: string | ||
| } | ||
| type RuntimePluginSupportState = typeof globalThis & { | ||
| [runtimePluginSupportInstalledKey]?: RuntimePluginSupportInstall | ||
| } | ||
| const defaultRuntimeModules: Record<string, RuntimeModuleEntry> = { | ||
| "@opentui/react": opentuiReactRuntime as Record<string, unknown>, | ||
| "@opentui/react/jsx-runtime": reactJsxRuntime as Record<string, unknown>, | ||
| "@opentui/react/jsx-dev-runtime": reactJsxDevRuntime as Record<string, unknown>, | ||
| react: reactRuntime as Record<string, unknown>, | ||
| "react/jsx-runtime": reactJsxRuntime as Record<string, unknown>, | ||
| "react/jsx-dev-runtime": reactJsxDevRuntime as Record<string, unknown>, | ||
| } | ||
| function normalizeRewriteKey(rewrite: RuntimePluginRewriteOptions | undefined): string { | ||
| return `${rewrite?.nodeModulesRuntimeSpecifiers ?? true}:${rewrite?.nodeModulesBareSpecifiers ?? false}` | ||
| } | ||
| function createRuntimeModules(options?: ReactRuntimePluginSupportOptions): Record<string, RuntimeModuleEntry> { | ||
| return { | ||
| ...defaultRuntimeModules, | ||
| ...(options?.additional ?? {}), | ||
| } | ||
| } | ||
| function assertCompatibleInstall( | ||
| install: RuntimePluginSupportInstall, | ||
| modules: Record<string, RuntimeModuleEntry>, | ||
| options?: ReactRuntimePluginSupportOptions, | ||
| ): void { | ||
| for (const specifier of Object.keys(modules)) { | ||
| if (!install.specifiers.has(specifier)) { | ||
| throw new Error( | ||
| `OpenTUI React runtime plugin support is already installed without ${specifier}. Call ensureRuntimePluginSupport({ additional }) from @opentui/react/runtime-plugin-support/configure before importing @opentui/react/runtime-plugin-support.`, | ||
| ) | ||
| } | ||
| } | ||
| if (options?.core && options.core !== install.core) { | ||
| throw new Error("OpenTUI React runtime plugin support is already installed with a different core runtime module.") | ||
| } | ||
| if (options?.rewrite && normalizeRewriteKey(options.rewrite) !== install.rewriteKey) { | ||
| throw new Error("OpenTUI React runtime plugin support is already installed with different rewrite options.") | ||
| } | ||
| } | ||
| export function ensureRuntimePluginSupport(options: ReactRuntimePluginSupportOptions = {}): boolean { | ||
| const state = globalThis as RuntimePluginSupportState | ||
| const modules = createRuntimeModules(options) | ||
| const core = options.core ?? (coreRuntime as Record<string, unknown>) | ||
| const rewriteKey = normalizeRewriteKey(options.rewrite) | ||
| const install = state[runtimePluginSupportInstalledKey] | ||
| if (install) { | ||
| assertCompatibleInstall(install, modules, options) | ||
| return false | ||
| } | ||
| registerBunPlugin( | ||
| createRuntimePlugin({ | ||
| core, | ||
| additional: modules, | ||
| rewrite: options.rewrite, | ||
| }), | ||
| ) | ||
| state[runtimePluginSupportInstalledKey] = { | ||
| specifiers: new Set(Object.keys(modules)), | ||
| core, | ||
| rewriteKey, | ||
| } | ||
| return true | ||
| } |
| import { ensureRuntimePluginSupport } from "./runtime-plugin-support-configure.js" | ||
| export { ensureRuntimePluginSupport } | ||
| export type { ReactRuntimePluginSupportOptions } from "./runtime-plugin-support-configure.js" | ||
| ensureRuntimePluginSupport() |
87061
2.58%50
8.7%1554
-1.02%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
Updated