UNPKG

minitel-react

Version:

A react renderer for the french Minitel

137 lines (136 loc) 5.31 kB
var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; import { jsx as _jsx } from "react/jsx-runtime"; import Reconciler from 'react-reconciler'; import { createContext, useContext, useEffect } from 'react'; import { DefaultEventPriority, } from 'react-reconciler/constants.js'; import { Container, Display, Focusable, Input, Minitel, Paragraph, Scrollable, Span, TextNode, XJoin, YJoin, ZJoin } from 'minitel-standalone'; import { Duplex } from 'node:stream'; const elements = { 'mt-para': Paragraph, 'mt-yjoin': YJoin, 'mt-xjoin': XJoin, 'mt-cont': Container, 'mt-disp': Display, 'mt-zjoin': ZJoin, 'mt-input': Input, 'mt-span': Span, 'mt-scroll': Scrollable, 'mt-focus': Focusable, }; let lastImmediate = null; const MiniRenderer = Reconciler({ supportsMutation: true, supportsHydration: false, createInstance(type, props, rootContainer) { const InstanceConstructor = elements[type]; let { children } = props, attributes = __rest(props, ["children"]); // if (children != null && !Array.isArray(children)) children = [children]; const instance = new InstanceConstructor([], attributes, rootContainer); return instance; }, createTextInstance(text, rootContainer) { return new TextNode(text, {}, rootContainer); }, appendInitialChild(parentInstance, child) { parentInstance.appendChild(child); }, appendChild(parentInstance, child) { const newChild = typeof child === 'string' ? new TextNode(child, {}, parentInstance.minitel) : child; parentInstance.appendChild(newChild); }, appendChildToContainer(container, child) { const newChild = typeof child === 'string' ? new TextNode(child, {}, container.minitel) : child; container.appendChild(newChild); }, insertBefore(parentInstance, child, beforeChild) { const newChild = typeof child === 'string' ? new TextNode(child, {}, parentInstance.minitel) : child; parentInstance.insertBeforeChild(newChild, beforeChild); }, removeChild(parentInstance, child) { parentInstance.removeChild(child); }, removeChildFromContainer(container, child) { container.removeChild(child); }, commitTextUpdate(textInstance, prevText, nextText) { textInstance.text = nextText; }, prepareUpdate() { return {}; }, commitUpdate(instance, _, __, ___, newContent) { const { children: newChildren } = newContent, newProps = __rest(newContent, ["children"]); instance.attributes = newProps; instance.minitel.queueImmediateRenderToStream(); }, clearContainer(container) { if (container.children[0]) container.removeChild(container.children[0]); }, finalizeInitialChildren: () => true, commitMount(instance) { instance.minitel.queueImmediateRenderToStream(); }, shouldSetTextContent: () => false, getRootHostContext: () => null, resetAfterCommit: () => { }, getChildHostContext: (parentHostContext) => parentHostContext, getPublicInstance: (instance) => instance, prepareForCommit: (containerInfo) => null, // TODO: Store focus and whatnot scheduleTimeout: setTimeout, cancelTimeout: clearTimeout, scheduleMicrotask: queueMicrotask, noTimeout: -1, supportsMicrotasks: true, supportsPersistence: false, getCurrentEventPriority() { return DefaultEventPriority; }, isPrimaryRenderer: true, // for typescript preparePortalMount() { }, beforeActiveInstanceBlur() { }, afterActiveInstanceBlur() { }, prepareScopeUpdate() { }, getInstanceFromNode(node) { return undefined; }, getInstanceFromScope(scopeInstance) { return null; }, detachDeletedInstance(node) { } }); const minitelContext = createContext(undefined); export const render = (reactElement, rootEl, callback) => { // Create a root Container if it doesnt exist if (!rootEl._rootContainer) { rootEl._rootContainer = MiniRenderer.createContainer(rootEl, 0, null, true, null, '', () => { }, null); } const contextProvider = _jsx(minitelContext.Provider, { value: rootEl, children: reactElement }); // update the root Container MiniRenderer.updateContainer(contextProvider, rootEl._rootContainer, null, callback); const unrender = () => { rootEl.unmountWrapper(); MiniRenderer.updateContainer(null, rootEl._rootContainer, null, callback); rootEl.stream = new Duplex(); }; rootEl.stream.on('close', unrender); }; export function useKeyboard(callback, deps) { const minitel = useContext(minitelContext); useEffect(() => { minitel.on('key', callback); return () => void minitel.off('key', callback); }, deps); } export { Minitel, minitelContext };