@sigx/runtime-terminal 0.1.7 → 0.1.9

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/dist/index.d.ts CHANGED
@@ -13,7 +13,7 @@ export interface TerminalNode {
13
13
  children: TerminalNode[];
14
14
  parentNode?: TerminalNode | null;
15
15
  }
16
- export declare const render: import("@sigx/runtime-core").RootRenderFunction<TerminalNode, TerminalNode>;
16
+ export declare const render: import("@sigx/runtime-core/internals").RootRenderFunction<TerminalNode, TerminalNode>;
17
17
  export declare function renderNodeToLines(node: TerminalNode): string[];
18
18
  type KeyHandler = (key: string) => void;
19
19
  export declare function onKey(handler: KeyHandler): () => boolean;
package/dist/index.js CHANGED
@@ -1,8 +1,9 @@
1
- import { component as component$1, createRenderer, onMounted, onUnmounted, setDefaultMount, signal } from "@sigx/runtime-core";
2
- import { signal as signal$1 } from "@sigx/reactivity";
1
+ import { createRenderer, setDefaultMount } from "@sigx/runtime-core/internals";
2
+ import { signal } from "@sigx/reactivity";
3
+ import { component as component$1, onMounted, onUnmounted, signal as signal$1 } from "@sigx/runtime-core";
3
4
  import { jsx, jsxs } from "@sigx/runtime-core/jsx-runtime";
4
5
  var focusableIds = /* @__PURE__ */ new Set();
5
- const focusState = signal$1({ activeId: null });
6
+ const focusState = signal({ activeId: null });
6
7
  function registerFocusable(id) {
7
8
  focusableIds.add(id);
8
9
  if (focusState.activeId === null) focusState.activeId = id;
@@ -128,7 +129,7 @@ const ProgressBar = component$1(({ props }) => {
128
129
  const Button = component$1(({ props, emit }) => {
129
130
  const id = Math.random().toString(36).slice(2);
130
131
  const isFocused = () => focusState.activeId === id;
131
- const pressed = signal({ value: false });
132
+ const pressed = signal$1({ value: false });
132
133
  const handleKey = (key) => {
133
134
  if (!isFocused()) return;
134
135
  if (key === "\r" || key === " ") {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/focus.ts","../src/utils.ts","../src/components/Input.tsx","../src/components/ProgressBar.tsx","../src/components/Button.tsx","../src/components/Checkbox.tsx","../src/components/Select.tsx","../src/index.ts"],"sourcesContent":["import { signal } from '@sigx/reactivity';\r\n\r\nconst focusableIds = new Set<string>();\r\nexport const focusState = signal({ activeId: null as string | null });\r\n\r\nexport function registerFocusable(id: string) {\r\n focusableIds.add(id);\r\n if (focusState.activeId === null) {\r\n focusState.activeId = id;\r\n }\r\n}\r\n\r\nexport function unregisterFocusable(id: string) {\r\n focusableIds.delete(id);\r\n if (focusState.activeId === id) {\r\n focusState.activeId = null;\r\n // Try to focus another one\r\n if (focusableIds.size > 0) {\r\n focusState.activeId = focusableIds.values().next().value || null;\r\n }\r\n }\r\n}\r\n\r\nexport function focus(id: string) {\r\n if (focusableIds.has(id)) {\r\n focusState.activeId = id;\r\n }\r\n}\r\n\r\nexport function focusNext() {\r\n if (focusableIds.size === 0) return;\r\n const ids = Array.from(focusableIds);\r\n const currentIndex = focusState.activeId ? ids.indexOf(focusState.activeId) : -1;\r\n const nextIndex = (currentIndex + 1) % ids.length;\r\n focusState.activeId = ids[nextIndex];\r\n}\r\n\r\nexport function focusPrev() {\r\n if (focusableIds.size === 0) return;\r\n const ids = Array.from(focusableIds);\r\n const currentIndex = focusState.activeId ? ids.indexOf(focusState.activeId) : -1;\r\n const prevIndex = (currentIndex - 1 + ids.length) % ids.length;\r\n focusState.activeId = ids[prevIndex];\r\n}\r\n","\r\nexport function getColorCode(color: string): string {\r\n switch (color) {\r\n case 'red': return '\\x1b[31m';\r\n case 'green': return '\\x1b[32m';\r\n case 'blue': return '\\x1b[34m';\r\n case 'yellow': return '\\x1b[33m';\r\n case 'cyan': return '\\x1b[36m';\r\n case 'white': return '\\x1b[37m';\r\n case 'black': return '\\x1b[30m';\r\n default: return '';\r\n }\r\n}\r\n\r\nexport function getBackgroundColorCode(color: string): string {\r\n switch (color) {\r\n case 'red': return '\\x1b[41m';\r\n case 'green': return '\\x1b[42m';\r\n case 'blue': return '\\x1b[44m';\r\n case 'yellow': return '\\x1b[43m';\r\n case 'cyan': return '\\x1b[46m';\r\n case 'white': return '\\x1b[47m';\r\n case 'black': return '\\x1b[40m';\r\n default: return '';\r\n }\r\n}\r\n\r\nexport function stripAnsi(str: string): string {\r\n return str.replace(/\\x1B\\[[0-9;]*[a-zA-Z]/g, '');\r\n}\r\n","/** @jsxImportSource @sigx/runtime-core */\r\nimport { component, onMounted, onUnmounted, type DefineProp, type DefineEvent, type DefineModel } from '@sigx/runtime-core';\r\nimport { onKey } from '../index';\r\nimport { registerFocusable, unregisterFocusable, focusState, focus } from '../focus';\r\n\r\nexport const Input = component<\r\n DefineModel<string> &\r\n DefineProp<\"placeholder\", string, false> &\r\n DefineProp<\"autofocus\", boolean, false> &\r\n DefineProp<\"label\", string, false> &\r\n DefineEvent<\"input\", string> &\r\n DefineEvent<\"submit\", string>\r\n>(({ props, emit }) => {\r\n const id = Math.random().toString(36).slice(2);\r\n let isReady = false; // Prevent immediate submit after mount\r\n\r\n const isFocused = () => focusState.activeId === id;\r\n\r\n const getValue = () => props.model?.value || '';\r\n\r\n const handleKey = (key: string) => {\r\n if (!isFocused()) return;\r\n if (!isReady) return; // Ignore keys until component is ready\r\n\r\n if (key === '\\r') { // Enter\r\n emit('submit', getValue());\r\n return;\r\n }\r\n\r\n if (key === '\\n') return;\r\n\r\n if (key === '\\u007F' || key === '\\b') { // Backspace\r\n const val = getValue();\r\n if (val.length > 0) {\r\n const newValue = val.slice(0, -1);\r\n if (props.model) props.model.value = newValue;\r\n emit('input', newValue);\r\n }\r\n return;\r\n }\r\n\r\n // Ignore control characters\r\n if (key.length > 1) return;\r\n\r\n const newValue = getValue() + key;\r\n if (props.model) props.model.value = newValue;\r\n emit('input', newValue);\r\n };\r\n\r\n let keyCleanup: (() => void) | null = null;\r\n\r\n onMounted(() => {\r\n registerFocusable(id);\r\n if (props.autofocus) {\r\n focus(id);\r\n }\r\n keyCleanup = onKey(handleKey);\r\n // Small delay to prevent immediate submit from previous Enter key\r\n setTimeout(() => { isReady = true; }, 50);\r\n });\r\n\r\n onUnmounted(() => {\r\n if (keyCleanup) keyCleanup();\r\n unregisterFocusable(id);\r\n });\r\n\r\n return () => {\r\n const val = getValue().replace(/[\\r\\n]+/g, ' ');\r\n const placeholder = (props.placeholder || '').replace(/[\\r\\n]+/g, ' ');\r\n const showCursor = isFocused();\r\n // console.log('Input render', { val, placeholder, showCursor });\r\n\r\n return (\r\n <box border=\"single\" borderColor={showCursor ? 'green' : 'white'} label={props.label}>\r\n <text>{val || placeholder}</text>\r\n {showCursor && <text color=\"cyan\">_</text>}\r\n </box>\r\n );\r\n };\r\n}, { name: 'Input' });\r\n","/** @jsxImportSource @sigx/runtime-core */\r\nimport { component, type DefineProp } from '@sigx/runtime-core';\r\nimport { getColorCode } from '../utils';\r\n\r\nexport const ProgressBar = component<\r\n DefineProp<\"value\", number, false> &\r\n DefineProp<\"max\", number, false> &\r\n DefineProp<\"width\", number, false> &\r\n DefineProp<\"char\", string, false> &\r\n DefineProp<\"emptyChar\", string, false> &\r\n DefineProp<\"color\", string, false>\r\n>(({ props }) => {\r\n return () => {\r\n const value = props.value || 0;\r\n const max = props.max || 100;\r\n const width = props.width || 20;\r\n const barChar = props.char || '█';\r\n const emptyChar = props.emptyChar || '░';\r\n const color = props.color;\r\n const colorCode = color ? getColorCode(color) : '';\r\n const reset = color ? '\\x1b[0m' : '';\r\n\r\n const percentage = Math.min(Math.max(value / max, 0), 1);\r\n const filledLen = Math.round(width * percentage);\r\n const emptyLen = width - filledLen;\r\n\r\n const bar = colorCode + barChar.repeat(filledLen) + emptyChar.repeat(emptyLen) + reset;\r\n const label = ` ${Math.round(percentage * 100)}%`;\r\n\r\n return (\r\n <box>\r\n <text>{bar + label}</text>\r\n </box>\r\n );\r\n };\r\n}, { name: 'ProgressBar' });\r\n","/** @jsxImportSource @sigx/runtime-core */\r\nimport { component, onMounted, onUnmounted, signal, type DefineProp, type DefineEvent } from '@sigx/runtime-core';\r\nimport { onKey } from '../index';\r\nimport { registerFocusable, unregisterFocusable, focusState } from '../focus';\r\n\r\nexport const Button = component<\r\n DefineProp<\"label\", string, false> &\r\n DefineProp<\"dropShadow\", boolean, false> &\r\n DefineEvent<\"click\">\r\n>(({ props, emit }) => {\r\n const id = Math.random().toString(36).slice(2);\r\n\r\n const isFocused = () => focusState.activeId === id;\r\n const pressed = signal({ value: false });\r\n\r\n const handleKey = (key: string) => {\r\n if (!isFocused()) return;\r\n\r\n if (key === '\\r' || key === ' ') { // Enter or Space\r\n // Visual press effect + emit click\r\n pressed.value = true as any;\r\n if (pressTimer) clearTimeout(pressTimer);\r\n pressTimer = setTimeout(() => {\r\n pressed.value = false as any;\r\n pressTimer = null;\r\n }, 120);\r\n emit('click');\r\n }\r\n };\r\n\r\n let keyCleanup: (() => void) | null = null;\r\n let pressTimer: ReturnType<typeof setTimeout> | null = null;\r\n\r\n onMounted(() => {\r\n registerFocusable(id);\r\n keyCleanup = onKey(handleKey);\r\n });\r\n\r\n onUnmounted(() => {\r\n if (keyCleanup) keyCleanup();\r\n unregisterFocusable(id);\r\n if (pressTimer) clearTimeout(pressTimer);\r\n });\r\n\r\n return () => {\r\n const focused = isFocused();\r\n const label = props.label || 'Button';\r\n const isPressed = pressed.value as boolean;\r\n\r\n return (\r\n <box\r\n border=\"single\"\r\n borderColor={isPressed ? 'yellow' : (focused ? 'green' : 'white')}\r\n backgroundColor={isPressed ? 'red' : (focused ? 'blue' : undefined)}\r\n dropShadow={props.dropShadow}\r\n >\r\n <text color={focused ? 'white' : undefined}>{label}</text>\r\n </box>\r\n );\r\n };\r\n}, { name: 'Button' });","/** @jsxImportSource @sigx/runtime-core */\r\nimport { component, onMounted, onUnmounted, signal, type DefineProp, type DefineEvent, type DefineModel } from '@sigx/runtime-core';\r\nimport { onKey } from '../index';\r\nimport { registerFocusable, unregisterFocusable, focusState, focus } from '../focus';\r\n\r\nexport const Checkbox = component<\r\n DefineModel<boolean> &\r\n DefineProp<\"label\", string, false> &\r\n DefineProp<\"autofocus\", boolean, false> &\r\n DefineProp<\"disabled\", boolean, false> &\r\n DefineEvent<\"change\", boolean>\r\n>(({ props, emit }) => {\r\n const id = Math.random().toString(36).slice(2);\r\n\r\n const isFocused = () => focusState.activeId === id;\r\n const checked = () => !!props.model?.value;\r\n\r\n const handleKey = (key: string) => {\r\n if (!isFocused()) return;\r\n if (props.disabled) return;\r\n\r\n if (key === '\\r' || key === ' ') { // Enter or Space toggles\r\n const next = !checked();\r\n if (props.model) props.model.value = next;\r\n emit('change', next);\r\n }\r\n };\r\n\r\n let keyCleanup: (() => void) | null = null;\r\n\r\n onMounted(() => {\r\n registerFocusable(id);\r\n if (props.autofocus) focus(id);\r\n keyCleanup = onKey(handleKey);\r\n });\r\n\r\n onUnmounted(() => {\r\n if (keyCleanup) keyCleanup();\r\n unregisterFocusable(id);\r\n });\r\n\r\n return () => {\r\n const label = props.label || '';\r\n const focused = isFocused();\r\n const isChecked = checked();\r\n const disabled = !!props.disabled;\r\n\r\n // Visual: [x] Label or [ ] Label\r\n // When focused, show a cursor indicator and highlight the label\r\n const boxColor = disabled ? 'white' : (isChecked ? 'green' : (focused ? 'cyan' : 'white'));\r\n const labelColor = disabled ? 'white' : (focused ? 'cyan' : undefined);\r\n const checkMark = isChecked ? 'x' : ' ';\r\n const focusIndicator = focused ? '>' : ' ';\r\n\r\n return (\r\n <box>\r\n <text color={focused ? 'cyan' : 'white'}>{focusIndicator}</text>\r\n <text color={boxColor}>[{checkMark}]</text>\r\n {label && <text color={labelColor}> {label}</text>}\r\n </box>\r\n );\r\n };\r\n}, { name: 'Checkbox' });\r\n\r\nexport default Checkbox;\r\n","/** @jsxImportSource @sigx/runtime-core */\r\nimport { component, onMounted, onUnmounted, type DefineProp, type DefineEvent, type DefineModel } from '@sigx/runtime-core';\r\nimport { onKey } from '../index';\r\nimport { registerFocusable, unregisterFocusable, focusState, focus } from '../focus';\r\n\r\nexport interface SelectOption<T = string> {\r\n label: string;\r\n value: T;\r\n description?: string;\r\n}\r\n\r\nexport const Select = component<\r\n DefineModel<string> &\r\n DefineProp<\"options\", SelectOption[], true> &\r\n DefineProp<\"label\", string, false> &\r\n DefineProp<\"autofocus\", boolean, false> &\r\n DefineProp<\"showDescription\", boolean, false> &\r\n DefineEvent<\"change\", string> &\r\n DefineEvent<\"submit\", string>\r\n>(({ props, emit }) => {\r\n const id = Math.random().toString(36).slice(2);\r\n let isReady = false; // Prevent immediate submit after mount\r\n\r\n const isFocused = () => focusState.activeId === id;\r\n\r\n const getCurrentIndex = () => {\r\n const options = props.options || [];\r\n const idx = options.findIndex(o => o.value === props.model?.value);\r\n return idx >= 0 ? idx : 0;\r\n };\r\n\r\n const handleKey = (key: string) => {\r\n if (!isFocused()) return;\r\n if (!isReady) return; // Ignore keys until component is ready\r\n\r\n const options = props.options || [];\r\n if (options.length === 0) return;\r\n\r\n const currentIndex = getCurrentIndex();\r\n\r\n // Arrow up or 'k'\r\n if (key === '\\x1B[A' || key === 'k') {\r\n const newIndex = currentIndex > 0 ? currentIndex - 1 : options.length - 1;\r\n const newValue = options[newIndex].value;\r\n if (props.model) props.model.value = newValue;\r\n emit('change', newValue);\r\n return;\r\n }\r\n\r\n // Arrow down or 'j'\r\n if (key === '\\x1B[B' || key === 'j') {\r\n const newIndex = currentIndex < options.length - 1 ? currentIndex + 1 : 0;\r\n const newValue = options[newIndex].value;\r\n if (props.model) props.model.value = newValue;\r\n emit('change', newValue);\r\n return;\r\n }\r\n\r\n // Enter to submit\r\n if (key === '\\r') {\r\n emit('submit', props.model?.value || options[0]?.value || '');\r\n return;\r\n }\r\n };\r\n\r\n let keyCleanup: (() => void) | null = null;\r\n\r\n onMounted(() => {\r\n registerFocusable(id);\r\n if (props.autofocus) {\r\n focus(id);\r\n }\r\n keyCleanup = onKey(handleKey);\r\n // Small delay to prevent immediate submit from previous Enter key\r\n setTimeout(() => { isReady = true; }, 50);\r\n });\r\n\r\n onUnmounted(() => {\r\n if (keyCleanup) keyCleanup();\r\n unregisterFocusable(id);\r\n });\r\n\r\n return () => {\r\n const options = props.options || [];\r\n const focused = isFocused();\r\n const currentValue = props.model?.value || options[0]?.value || '';\r\n const label = props.label;\r\n const selectedOption = options.find(o => o.value === currentValue);\r\n\r\n // Render options\r\n const optionElements = options.map((option) => {\r\n const isSelected = option.value === currentValue;\r\n const indicator = isSelected ? '❯' : ' ';\r\n const color = isSelected ? 'cyan' : 'white';\r\n\r\n return (\r\n <box>\r\n <text color={color}>{indicator} {option.label}</text>\r\n </box>\r\n );\r\n });\r\n\r\n // Description shown below the box (common pattern in CLI tools)\r\n const descriptionElement = props.showDescription && selectedOption?.description ? (\r\n <box>\r\n <text color=\"#666666\"> ↳ {selectedOption.description}</text>\r\n </box>\r\n ) : null;\r\n\r\n return (\r\n <box>\r\n <box border=\"single\" borderColor={focused ? 'green' : 'white'} label={label}>\r\n {optionElements}\r\n </box>\r\n {descriptionElement}\r\n </box>\r\n );\r\n };\r\n}, { name: 'Select' });\r\n\r\nexport default Select;\r\n","import { createRenderer, RendererOptions, VNode, setDefaultMount } from '@sigx/runtime-core';\r\nimport { focusNext, focusPrev } from './focus';\r\nimport { getColorCode, getBackgroundColorCode, stripAnsi } from './utils';\r\n\r\n// Import type augmentation\r\nimport './types.js';\r\n\r\nexport * from './focus';\r\nexport * from './components/Input';\r\nexport * from './components/ProgressBar';\r\nexport * from './components/Button';\r\nexport * from './components/Checkbox';\r\nexport * from './components/Select';\r\n\r\n// --- Terminal Node Types ---\r\n\r\nexport interface TerminalNode {\r\n type: 'root' | 'element' | 'text' | 'comment';\r\n tag?: string;\r\n text?: string;\r\n props: Record<string, any>;\r\n children: TerminalNode[];\r\n parentNode?: TerminalNode | null;\r\n}\r\n\r\n// --- Node Operations ---\r\n\r\nconst nodeOps: RendererOptions<TerminalNode, TerminalNode> = {\r\n patchProp: (el, key, prev, next) => {\r\n el.props[key] = next;\r\n scheduleRender();\r\n },\r\n insert: (child, parent, anchor) => {\r\n child.parentNode = parent;\r\n const index = anchor ? parent.children.indexOf(anchor) : -1;\r\n if (index > -1) {\r\n parent.children.splice(index, 0, child);\r\n } else {\r\n parent.children.push(child);\r\n }\r\n scheduleRender();\r\n },\r\n remove: (child) => {\r\n if (child.parentNode) {\r\n const index = child.parentNode.children.indexOf(child);\r\n if (index > -1) {\r\n child.parentNode.children.splice(index, 1);\r\n }\r\n child.parentNode = null;\r\n }\r\n scheduleRender();\r\n },\r\n createElement: (tag) => {\r\n return { type: 'element', tag, props: {}, children: [] };\r\n },\r\n createText: (text) => {\r\n return { type: 'text', text, props: {}, children: [] };\r\n },\r\n createComment: (text) => {\r\n return { type: 'comment', text, props: {}, children: [] };\r\n },\r\n setText: (node, text) => {\r\n node.text = text;\r\n scheduleRender();\r\n },\r\n setElementText: (node, text) => {\r\n node.children = [{ type: 'text', text, props: {}, children: [], parentNode: node }];\r\n scheduleRender();\r\n },\r\n parentNode: (node) => node.parentNode || null,\r\n nextSibling: (node) => {\r\n if (!node.parentNode) return null;\r\n const idx = node.parentNode.children.indexOf(node);\r\n return node.parentNode.children[idx + 1] || null;\r\n },\r\n cloneNode: (node) => {\r\n // Shallow clone for simplicity in this demo\r\n return { ...node, children: [] };\r\n }\r\n};\r\n\r\n// --- Renderer Creation ---\r\n\r\nconst renderer = createRenderer(nodeOps);\r\nexport const { render } = renderer;\r\n\r\n// --- Terminal Rendering Logic ---\r\n\r\nlet rootNode: TerminalNode | null = null;\r\nlet isRendering = false;\r\n\r\nfunction scheduleRender() {\r\n if (isRendering) return;\r\n isRendering = true;\r\n // Use setImmediate or setTimeout to batch updates\r\n setTimeout(() => {\r\n flushRender();\r\n isRendering = false;\r\n }, 10);\r\n}\r\n\r\nfunction flushRender() {\r\n if (!rootNode) return;\r\n\r\n // Move cursor to top-left\r\n process.stdout.write('\\x1B[H');\r\n\r\n // Render tree\r\n const lines = renderNodeToLines(rootNode);\r\n process.stdout.write(lines.join('\\x1B[K\\n') + '\\x1B[K');\r\n\r\n // Clear rest of screen\r\n process.stdout.write('\\x1B[J');\r\n}\r\n\r\n\r\n/**\r\n * Check if a node has a box element as an immediate child.\r\n * This is used to determine if a component wrapper should be treated as a block element.\r\n */\r\nfunction hasBoxChild(node: TerminalNode): boolean {\r\n for (const child of node.children) {\r\n if (child.tag === 'box') {\r\n return true;\r\n }\r\n }\r\n return false;\r\n}\r\n\r\nexport function renderNodeToLines(node: TerminalNode): string[] {\r\n // if (node.tag === 'box') console.log('Rendering box', node.props);\r\n if (node.type === 'text') {\r\n return [node.text || ''];\r\n }\r\n if (node.type === 'comment') {\r\n return [];\r\n }\r\n\r\n let lines: string[] = [''];\r\n\r\n // Simple styling based on props (e.g., color)\r\n const color = node.props.color;\r\n const reset = color ? '\\x1b[0m' : '';\r\n const colorCode = getColorCode(color);\r\n\r\n // Render children\r\n for (const child of node.children) {\r\n if (child.type === 'text') {\r\n // Append text to the last line\r\n lines[lines.length - 1] += colorCode + (child.text || '') + reset;\r\n } else if (child.tag === 'br') {\r\n // Start a new line\r\n lines.push('');\r\n } else {\r\n // Recursively render child\r\n const childLines = renderNodeToLines(child);\r\n\r\n // Check if this child contains a box element (making it a block)\r\n // A box is always a block element, and component wrappers that contain\r\n // a box should also be treated as blocks\r\n const isBlockElement = child.tag === 'box' || hasBoxChild(child);\r\n\r\n if (isBlockElement) {\r\n // Block element - start on a new line\r\n if (lines.length === 1 && lines[0] === '') {\r\n lines = childLines;\r\n } else {\r\n lines.push(...childLines);\r\n }\r\n } else {\r\n // Inline element (like text wrapper)\r\n // This is tricky. If child returns multiple lines, it breaks the flow.\r\n // For now, assume non-box elements are inline-ish or just append.\r\n if (childLines.length > 0) {\r\n // If the child has multiple lines, treat it as a block to avoid\r\n // appending a box top border to the end of a text line.\r\n if (childLines.length > 1) {\r\n if (lines.length === 1 && lines[0] === '') {\r\n lines = childLines;\r\n } else {\r\n lines.push(...childLines);\r\n }\r\n } else {\r\n lines[lines.length - 1] += childLines[0];\r\n for (let i = 1; i < childLines.length; i++) {\r\n lines.push(childLines[i]);\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Apply box borders if needed\r\n if (node.tag === 'box' && node.props.border) {\r\n return drawBox(lines, node.props.border, node.props.borderColor, node.props.backgroundColor, node.props.dropShadow, node.props.label);\r\n }\r\n\r\n return lines;\r\n}\r\n\r\nfunction drawBox(contentLines: string[], style: string, color?: string, backgroundColor?: string, dropShadow?: boolean, label?: string): string[] {\r\n const borderChars = getBorderChars(style);\r\n const colorCode = color ? getColorCode(color) : '';\r\n const bgCode = backgroundColor ? getBackgroundColorCode(backgroundColor) : '';\r\n const reset = (color || backgroundColor) ? '\\x1b[0m' : '';\r\n\r\n // Calculate width\r\n const width = contentLines.reduce((max, line) => Math.max(max, stripAnsi(line).length), 0);\r\n\r\n // If there's a label, ensure box is wide enough to accommodate it\r\n const labelText = label || '';\r\n const labelLength = stripAnsi(labelText).length;\r\n const boxInnerWidth = Math.max(width, labelLength + 2);\r\n\r\n // Build top border. If label exists, center it in the top border like a fieldset legend\r\n let topInner = '';\r\n if (labelText) {\r\n const spaceForLabel = boxInnerWidth - labelLength - 2; // remaining space for horiz lines\r\n const leftH = Math.floor(spaceForLabel / 2);\r\n const rightH = spaceForLabel - leftH;\r\n topInner = borderChars.h.repeat(leftH) + ' ' + labelText + ' ' + borderChars.h.repeat(rightH);\r\n } else {\r\n topInner = borderChars.h.repeat(boxInnerWidth);\r\n }\r\n\r\n const top = bgCode + colorCode + borderChars.tl + topInner + borderChars.tr + reset;\r\n const bottom = bgCode + colorCode + borderChars.bl + borderChars.h.repeat(boxInnerWidth) + borderChars.br + reset;\r\n\r\n const result: string[] = [];\r\n result.push(top);\r\n\r\n for (const line of contentLines) {\r\n const visibleLength = stripAnsi(line).length;\r\n const padding = ' '.repeat(boxInnerWidth - visibleLength);\r\n // We need to apply background to the content line as well, but be careful not to double apply if it already has it?\r\n // Actually, the content might have its own colors.\r\n // But the padding needs the background color.\r\n // And the border needs the background color.\r\n\r\n // If we wrap the whole line in bgCode, it should work, provided we reset at the end.\r\n // But `line` might have resets in it.\r\n // A simple approach: apply bgCode to the border chars and the padding.\r\n // For the content, if it doesn't have bg, we might want to apply it.\r\n // But `line` is already a string with ANSI codes.\r\n\r\n // Let's try wrapping the whole thing.\r\n // Note: `line` comes from `renderNodeToLines`, which might have resets.\r\n // If `line` has `\\x1b[0m`, it will reset the background too.\r\n // So we might need to replace `\\x1b[0m` with `\\x1b[0m` + bgCode + colorCode?\r\n // That's getting complicated.\r\n\r\n // For now, let's just apply bg to borders and padding.\r\n // And maybe prepend bgCode to the line?\r\n\r\n // If we just prepend bgCode to `line`, and `line` has a reset, the rest of the line will lose the bg.\r\n // So we should replace resets in `line` with `reset + bgCode + colorCode` (if we want to maintain the box style).\r\n // But `colorCode` is for the border. The content might have its own text color.\r\n\r\n // Let's assume content handles its own text color, but we want to enforce background.\r\n // We can replace `\\x1b[0m` with `\\x1b[0m${bgCode}`.\r\n\r\n const lineWithBg = bgCode + line.replace(/\\x1b\\[0m/g, `\\x1b[0m${bgCode}`);\r\n\r\n result.push(bgCode + colorCode + borderChars.v + reset + lineWithBg + bgCode + padding + colorCode + borderChars.v + reset);\r\n }\r\n\r\n result.push(bottom);\r\n\r\n if (dropShadow) {\r\n const shadowColor = '\\x1b[90m'; // Bright black (gray)\r\n const resetShadow = '\\x1b[0m';\r\n const shadowChar = '▒';\r\n const shadowBlock = shadowColor + shadowChar + resetShadow;\r\n\r\n // Apply to lines 1 to end (skipping top line 0)\r\n for (let i = 1; i < result.length; i++) {\r\n result[i] += shadowBlock;\r\n }\r\n\r\n // Add bottom shadow line\r\n // Width is boxWidth (width + 2)\r\n const bottomShadow = ' ' + shadowBlock.repeat(width + 2);\r\n result.push(bottomShadow);\r\n }\r\n\r\n return result;\r\n}\r\n\r\nfunction getBorderChars(style: string) {\r\n if (style === 'double') {\r\n return { tl: '╔', tr: '╗', bl: '╚', br: '╝', h: '═', v: '║' };\r\n }\r\n if (style === 'rounded') {\r\n return { tl: '╭', tr: '╮', bl: '╰', br: '╯', h: '─', v: '│' };\r\n }\r\n // Default single\r\n return { tl: '┌', tr: '┐', bl: '└', br: '┘', h: '─', v: '│' };\r\n}\r\n\r\nfunction renderNodeToString(node: TerminalNode, depth = 0): string {\r\n // Deprecated, but kept for compatibility if needed, or just redirect\r\n return renderNodeToLines(node).join('\\n');\r\n}\r\n\r\n\r\n// --- Public API for mounting ---\r\n\r\ntype KeyHandler = (key: string) => void;\r\nconst keyHandlers = new Set<KeyHandler>();\r\n\r\nexport function onKey(handler: KeyHandler) {\r\n keyHandlers.add(handler);\r\n return () => keyHandlers.delete(handler);\r\n}\r\n\r\nfunction handleInput(key: string) {\r\n // Ctrl+C to exit\r\n if (key === '\\u0003') {\r\n process.stdout.write('\\x1B[?25h'); // Show cursor\r\n process.exit();\r\n }\r\n\r\n // Tab navigation\r\n if (key === '\\t') {\r\n focusNext();\r\n return;\r\n }\r\n // Shift+Tab (often \\x1b[Z)\r\n if (key === '\\x1b[Z') {\r\n focusPrev();\r\n return;\r\n }\r\n\r\n for (const handler of keyHandlers) {\r\n handler(key);\r\n }\r\n}\r\n\r\nexport interface RenderTerminalOptions {\r\n clearConsole?: boolean;\r\n}\r\n\r\nexport function renderTerminal(app: any, options: RenderTerminalOptions = {}) {\r\n rootNode = { type: 'root', props: {}, children: [] };\r\n\r\n // Create a proxy container that looks like a HostElement\r\n const container = rootNode;\r\n\r\n // Setup input\r\n if (process.stdin.isTTY) {\r\n process.stdin.setRawMode(true);\r\n process.stdin.resume();\r\n process.stdin.setEncoding('utf8');\r\n process.stdin.on('data', handleInput);\r\n }\r\n\r\n // Clear console if requested\r\n if (options.clearConsole) {\r\n process.stdout.write('\\x1B[2J\\x1B[3J\\x1B[H');\r\n }\r\n\r\n // Hide cursor\r\n process.stdout.write('\\x1B[?25l');\r\n\r\n render(app, container);\r\n\r\n // Initial render\r\n flushRender();\r\n\r\n return {\r\n unmount: () => {\r\n render(null, container);\r\n // Show cursor\r\n process.stdout.write('\\x1B[?25h');\r\n\r\n if (process.stdin.isTTY) {\r\n process.stdin.setRawMode(false);\r\n process.stdin.pause();\r\n process.stdin.off('data', handleInput);\r\n }\r\n }\r\n };\r\n}\r\n\r\nlet unmountFn: (() => void) | null = null;\r\n\r\n/**\r\n * Helper function to mount the terminal for CLI apps.\r\n * Returns a mount target that can be passed to defineApp().mount().\r\n * \r\n * @example\r\n * ```tsx\r\n * defineApp(MyApp).mount(mountTerminal());\r\n * ```\r\n */\r\nexport function mountTerminal(options: RenderTerminalOptions = { clearConsole: true }) {\r\n return {\r\n mount: terminalMount,\r\n options,\r\n onMount: (unmount: () => void) => {\r\n unmountFn = unmount;\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Exit the terminal app cleanly, restoring terminal state.\r\n */\r\nexport function exitTerminal() {\r\n if (unmountFn) {\r\n unmountFn();\r\n unmountFn = null;\r\n }\r\n // Show cursor\r\n process.stdout.write('\\x1B[?25h');\r\n // Clear screen\r\n process.stdout.write('\\x1B[2J\\x1B[H');\r\n}\r\n\r\n/**\r\n * Mount function for Terminal environments.\r\n * Use this with defineApp().mount() to render to the terminal.\r\n * \r\n * @example\r\n * ```tsx\r\n * import { defineApp } from '@sigx/runtime-core';\r\n * import { terminalMount } from '@sigx/runtime-terminal';\r\n * \r\n * const app = defineApp(<Counter />);\r\n * app.use(loggingPlugin)\r\n * .mount({ clearConsole: true }, terminalMount);\r\n * ```\r\n */\r\nexport const terminalMount = (component: any, options: RenderTerminalOptions, appContext?: any): (() => void) => {\r\n rootNode = { type: 'root', props: {}, children: [] };\r\n\r\n const container = rootNode;\r\n\r\n // Setup input\r\n if (process.stdin.isTTY) {\r\n process.stdin.setRawMode(true);\r\n process.stdin.resume();\r\n process.stdin.setEncoding('utf8');\r\n process.stdin.on('data', handleInput);\r\n }\r\n\r\n // Clear console if requested\r\n if (options?.clearConsole) {\r\n process.stdout.write('\\x1B[2J\\x1B[3J\\x1B[H');\r\n }\r\n\r\n // Hide cursor\r\n process.stdout.write('\\x1B[?25l');\r\n\r\n // Render with app context support\r\n render(component, container, appContext);\r\n\r\n // Initial render\r\n flushRender();\r\n\r\n // Return unmount function\r\n return () => {\r\n render(null, container);\r\n // Show cursor\r\n process.stdout.write('\\x1B[?25h');\r\n\r\n if (process.stdin.isTTY) {\r\n process.stdin.setRawMode(false);\r\n process.stdin.pause();\r\n process.stdin.off('data', handleInput);\r\n }\r\n };\r\n};\r\n\r\n// Set terminalMount as the default mount function for this platform\r\nsetDefaultMount(terminalMount);\r\n\r\ndeclare global {\r\n namespace JSX {\r\n interface IntrinsicElements {\r\n box: TerminalAttributes;\r\n text: TerminalAttributes;\r\n br: TerminalAttributes;\r\n }\r\n\r\n interface TerminalAttributes {\r\n color?: 'red' | 'green' | 'blue' | 'yellow' | 'cyan' | 'white' | 'black' | string;\r\n backgroundColor?: 'red' | 'green' | 'blue' | 'yellow' | 'cyan' | 'white' | 'black' | string;\r\n border?: 'single' | 'double' | 'rounded' | 'none';\r\n borderColor?: 'red' | 'green' | 'blue' | 'yellow' | 'cyan' | 'white' | 'black' | string;\r\n dropShadow?: boolean;\r\n label?: string;\r\n children?: any;\r\n }\r\n\r\n }\r\n}\r\n\r\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/focus.ts","../src/utils.ts","../src/components/Input.tsx","../src/components/ProgressBar.tsx","../src/components/Button.tsx","../src/components/Checkbox.tsx","../src/components/Select.tsx","../src/index.ts"],"sourcesContent":["import { signal } from '@sigx/reactivity';\r\n\r\nconst focusableIds = new Set<string>();\r\nexport const focusState = signal({ activeId: null as string | null });\r\n\r\nexport function registerFocusable(id: string) {\r\n focusableIds.add(id);\r\n if (focusState.activeId === null) {\r\n focusState.activeId = id;\r\n }\r\n}\r\n\r\nexport function unregisterFocusable(id: string) {\r\n focusableIds.delete(id);\r\n if (focusState.activeId === id) {\r\n focusState.activeId = null;\r\n // Try to focus another one\r\n if (focusableIds.size > 0) {\r\n focusState.activeId = focusableIds.values().next().value || null;\r\n }\r\n }\r\n}\r\n\r\nexport function focus(id: string) {\r\n if (focusableIds.has(id)) {\r\n focusState.activeId = id;\r\n }\r\n}\r\n\r\nexport function focusNext() {\r\n if (focusableIds.size === 0) return;\r\n const ids = Array.from(focusableIds);\r\n const currentIndex = focusState.activeId ? ids.indexOf(focusState.activeId) : -1;\r\n const nextIndex = (currentIndex + 1) % ids.length;\r\n focusState.activeId = ids[nextIndex];\r\n}\r\n\r\nexport function focusPrev() {\r\n if (focusableIds.size === 0) return;\r\n const ids = Array.from(focusableIds);\r\n const currentIndex = focusState.activeId ? ids.indexOf(focusState.activeId) : -1;\r\n const prevIndex = (currentIndex - 1 + ids.length) % ids.length;\r\n focusState.activeId = ids[prevIndex];\r\n}\r\n","\r\nexport function getColorCode(color: string): string {\r\n switch (color) {\r\n case 'red': return '\\x1b[31m';\r\n case 'green': return '\\x1b[32m';\r\n case 'blue': return '\\x1b[34m';\r\n case 'yellow': return '\\x1b[33m';\r\n case 'cyan': return '\\x1b[36m';\r\n case 'white': return '\\x1b[37m';\r\n case 'black': return '\\x1b[30m';\r\n default: return '';\r\n }\r\n}\r\n\r\nexport function getBackgroundColorCode(color: string): string {\r\n switch (color) {\r\n case 'red': return '\\x1b[41m';\r\n case 'green': return '\\x1b[42m';\r\n case 'blue': return '\\x1b[44m';\r\n case 'yellow': return '\\x1b[43m';\r\n case 'cyan': return '\\x1b[46m';\r\n case 'white': return '\\x1b[47m';\r\n case 'black': return '\\x1b[40m';\r\n default: return '';\r\n }\r\n}\r\n\r\nexport function stripAnsi(str: string): string {\r\n return str.replace(/\\x1B\\[[0-9;]*[a-zA-Z]/g, '');\r\n}\r\n","/** @jsxImportSource @sigx/runtime-core */\r\nimport { component, onMounted, onUnmounted, type DefineProp, type DefineEvent, type DefineModel } from '@sigx/runtime-core';\r\nimport { onKey } from '../index';\r\nimport { registerFocusable, unregisterFocusable, focusState, focus } from '../focus';\r\n\r\nexport const Input = component<\r\n DefineModel<string> &\r\n DefineProp<\"placeholder\", string, false> &\r\n DefineProp<\"autofocus\", boolean, false> &\r\n DefineProp<\"label\", string, false> &\r\n DefineEvent<\"input\", string> &\r\n DefineEvent<\"submit\", string>\r\n>(({ props, emit }) => {\r\n const id = Math.random().toString(36).slice(2);\r\n let isReady = false; // Prevent immediate submit after mount\r\n\r\n const isFocused = () => focusState.activeId === id;\r\n\r\n const getValue = () => props.model?.value || '';\r\n\r\n const handleKey = (key: string) => {\r\n if (!isFocused()) return;\r\n if (!isReady) return; // Ignore keys until component is ready\r\n\r\n if (key === '\\r') { // Enter\r\n emit('submit', getValue());\r\n return;\r\n }\r\n\r\n if (key === '\\n') return;\r\n\r\n if (key === '\\u007F' || key === '\\b') { // Backspace\r\n const val = getValue();\r\n if (val.length > 0) {\r\n const newValue = val.slice(0, -1);\r\n if (props.model) props.model.value = newValue;\r\n emit('input', newValue);\r\n }\r\n return;\r\n }\r\n\r\n // Ignore control characters\r\n if (key.length > 1) return;\r\n\r\n const newValue = getValue() + key;\r\n if (props.model) props.model.value = newValue;\r\n emit('input', newValue);\r\n };\r\n\r\n let keyCleanup: (() => void) | null = null;\r\n\r\n onMounted(() => {\r\n registerFocusable(id);\r\n if (props.autofocus) {\r\n focus(id);\r\n }\r\n keyCleanup = onKey(handleKey);\r\n // Small delay to prevent immediate submit from previous Enter key\r\n setTimeout(() => { isReady = true; }, 50);\r\n });\r\n\r\n onUnmounted(() => {\r\n if (keyCleanup) keyCleanup();\r\n unregisterFocusable(id);\r\n });\r\n\r\n return () => {\r\n const val = getValue().replace(/[\\r\\n]+/g, ' ');\r\n const placeholder = (props.placeholder || '').replace(/[\\r\\n]+/g, ' ');\r\n const showCursor = isFocused();\r\n // console.log('Input render', { val, placeholder, showCursor });\r\n\r\n return (\r\n <box border=\"single\" borderColor={showCursor ? 'green' : 'white'} label={props.label}>\r\n <text>{val || placeholder}</text>\r\n {showCursor && <text color=\"cyan\">_</text>}\r\n </box>\r\n );\r\n };\r\n}, { name: 'Input' });\r\n","/** @jsxImportSource @sigx/runtime-core */\r\nimport { component, type DefineProp } from '@sigx/runtime-core';\r\nimport { getColorCode } from '../utils';\r\n\r\nexport const ProgressBar = component<\r\n DefineProp<\"value\", number, false> &\r\n DefineProp<\"max\", number, false> &\r\n DefineProp<\"width\", number, false> &\r\n DefineProp<\"char\", string, false> &\r\n DefineProp<\"emptyChar\", string, false> &\r\n DefineProp<\"color\", string, false>\r\n>(({ props }) => {\r\n return () => {\r\n const value = props.value || 0;\r\n const max = props.max || 100;\r\n const width = props.width || 20;\r\n const barChar = props.char || '█';\r\n const emptyChar = props.emptyChar || '░';\r\n const color = props.color;\r\n const colorCode = color ? getColorCode(color) : '';\r\n const reset = color ? '\\x1b[0m' : '';\r\n\r\n const percentage = Math.min(Math.max(value / max, 0), 1);\r\n const filledLen = Math.round(width * percentage);\r\n const emptyLen = width - filledLen;\r\n\r\n const bar = colorCode + barChar.repeat(filledLen) + emptyChar.repeat(emptyLen) + reset;\r\n const label = ` ${Math.round(percentage * 100)}%`;\r\n\r\n return (\r\n <box>\r\n <text>{bar + label}</text>\r\n </box>\r\n );\r\n };\r\n}, { name: 'ProgressBar' });\r\n","/** @jsxImportSource @sigx/runtime-core */\r\nimport { component, onMounted, onUnmounted, signal, type DefineProp, type DefineEvent } from '@sigx/runtime-core';\r\nimport { onKey } from '../index';\r\nimport { registerFocusable, unregisterFocusable, focusState } from '../focus';\r\n\r\nexport const Button = component<\r\n DefineProp<\"label\", string, false> &\r\n DefineProp<\"dropShadow\", boolean, false> &\r\n DefineEvent<\"click\">\r\n>(({ props, emit }) => {\r\n const id = Math.random().toString(36).slice(2);\r\n\r\n const isFocused = () => focusState.activeId === id;\r\n const pressed = signal({ value: false });\r\n\r\n const handleKey = (key: string) => {\r\n if (!isFocused()) return;\r\n\r\n if (key === '\\r' || key === ' ') { // Enter or Space\r\n // Visual press effect + emit click\r\n pressed.value = true as any;\r\n if (pressTimer) clearTimeout(pressTimer);\r\n pressTimer = setTimeout(() => {\r\n pressed.value = false as any;\r\n pressTimer = null;\r\n }, 120);\r\n emit('click');\r\n }\r\n };\r\n\r\n let keyCleanup: (() => void) | null = null;\r\n let pressTimer: ReturnType<typeof setTimeout> | null = null;\r\n\r\n onMounted(() => {\r\n registerFocusable(id);\r\n keyCleanup = onKey(handleKey);\r\n });\r\n\r\n onUnmounted(() => {\r\n if (keyCleanup) keyCleanup();\r\n unregisterFocusable(id);\r\n if (pressTimer) clearTimeout(pressTimer);\r\n });\r\n\r\n return () => {\r\n const focused = isFocused();\r\n const label = props.label || 'Button';\r\n const isPressed = pressed.value as boolean;\r\n\r\n return (\r\n <box\r\n border=\"single\"\r\n borderColor={isPressed ? 'yellow' : (focused ? 'green' : 'white')}\r\n backgroundColor={isPressed ? 'red' : (focused ? 'blue' : undefined)}\r\n dropShadow={props.dropShadow}\r\n >\r\n <text color={focused ? 'white' : undefined}>{label}</text>\r\n </box>\r\n );\r\n };\r\n}, { name: 'Button' });","/** @jsxImportSource @sigx/runtime-core */\r\nimport { component, onMounted, onUnmounted, signal, type DefineProp, type DefineEvent, type DefineModel } from '@sigx/runtime-core';\r\nimport { onKey } from '../index';\r\nimport { registerFocusable, unregisterFocusable, focusState, focus } from '../focus';\r\n\r\nexport const Checkbox = component<\r\n DefineModel<boolean> &\r\n DefineProp<\"label\", string, false> &\r\n DefineProp<\"autofocus\", boolean, false> &\r\n DefineProp<\"disabled\", boolean, false> &\r\n DefineEvent<\"change\", boolean>\r\n>(({ props, emit }) => {\r\n const id = Math.random().toString(36).slice(2);\r\n\r\n const isFocused = () => focusState.activeId === id;\r\n const checked = () => !!props.model?.value;\r\n\r\n const handleKey = (key: string) => {\r\n if (!isFocused()) return;\r\n if (props.disabled) return;\r\n\r\n if (key === '\\r' || key === ' ') { // Enter or Space toggles\r\n const next = !checked();\r\n if (props.model) props.model.value = next;\r\n emit('change', next);\r\n }\r\n };\r\n\r\n let keyCleanup: (() => void) | null = null;\r\n\r\n onMounted(() => {\r\n registerFocusable(id);\r\n if (props.autofocus) focus(id);\r\n keyCleanup = onKey(handleKey);\r\n });\r\n\r\n onUnmounted(() => {\r\n if (keyCleanup) keyCleanup();\r\n unregisterFocusable(id);\r\n });\r\n\r\n return () => {\r\n const label = props.label || '';\r\n const focused = isFocused();\r\n const isChecked = checked();\r\n const disabled = !!props.disabled;\r\n\r\n // Visual: [x] Label or [ ] Label\r\n // When focused, show a cursor indicator and highlight the label\r\n const boxColor = disabled ? 'white' : (isChecked ? 'green' : (focused ? 'cyan' : 'white'));\r\n const labelColor = disabled ? 'white' : (focused ? 'cyan' : undefined);\r\n const checkMark = isChecked ? 'x' : ' ';\r\n const focusIndicator = focused ? '>' : ' ';\r\n\r\n return (\r\n <box>\r\n <text color={focused ? 'cyan' : 'white'}>{focusIndicator}</text>\r\n <text color={boxColor}>[{checkMark}]</text>\r\n {label && <text color={labelColor}> {label}</text>}\r\n </box>\r\n );\r\n };\r\n}, { name: 'Checkbox' });\r\n\r\nexport default Checkbox;\r\n","/** @jsxImportSource @sigx/runtime-core */\r\nimport { component, onMounted, onUnmounted, type DefineProp, type DefineEvent, type DefineModel } from '@sigx/runtime-core';\r\nimport { onKey } from '../index';\r\nimport { registerFocusable, unregisterFocusable, focusState, focus } from '../focus';\r\n\r\nexport interface SelectOption<T = string> {\r\n label: string;\r\n value: T;\r\n description?: string;\r\n}\r\n\r\nexport const Select = component<\r\n DefineModel<string> &\r\n DefineProp<\"options\", SelectOption[], true> &\r\n DefineProp<\"label\", string, false> &\r\n DefineProp<\"autofocus\", boolean, false> &\r\n DefineProp<\"showDescription\", boolean, false> &\r\n DefineEvent<\"change\", string> &\r\n DefineEvent<\"submit\", string>\r\n>(({ props, emit }) => {\r\n const id = Math.random().toString(36).slice(2);\r\n let isReady = false; // Prevent immediate submit after mount\r\n\r\n const isFocused = () => focusState.activeId === id;\r\n\r\n const getCurrentIndex = () => {\r\n const options = props.options || [];\r\n const idx = options.findIndex(o => o.value === props.model?.value);\r\n return idx >= 0 ? idx : 0;\r\n };\r\n\r\n const handleKey = (key: string) => {\r\n if (!isFocused()) return;\r\n if (!isReady) return; // Ignore keys until component is ready\r\n\r\n const options = props.options || [];\r\n if (options.length === 0) return;\r\n\r\n const currentIndex = getCurrentIndex();\r\n\r\n // Arrow up or 'k'\r\n if (key === '\\x1B[A' || key === 'k') {\r\n const newIndex = currentIndex > 0 ? currentIndex - 1 : options.length - 1;\r\n const newValue = options[newIndex].value;\r\n if (props.model) props.model.value = newValue;\r\n emit('change', newValue);\r\n return;\r\n }\r\n\r\n // Arrow down or 'j'\r\n if (key === '\\x1B[B' || key === 'j') {\r\n const newIndex = currentIndex < options.length - 1 ? currentIndex + 1 : 0;\r\n const newValue = options[newIndex].value;\r\n if (props.model) props.model.value = newValue;\r\n emit('change', newValue);\r\n return;\r\n }\r\n\r\n // Enter to submit\r\n if (key === '\\r') {\r\n emit('submit', props.model?.value || options[0]?.value || '');\r\n return;\r\n }\r\n };\r\n\r\n let keyCleanup: (() => void) | null = null;\r\n\r\n onMounted(() => {\r\n registerFocusable(id);\r\n if (props.autofocus) {\r\n focus(id);\r\n }\r\n keyCleanup = onKey(handleKey);\r\n // Small delay to prevent immediate submit from previous Enter key\r\n setTimeout(() => { isReady = true; }, 50);\r\n });\r\n\r\n onUnmounted(() => {\r\n if (keyCleanup) keyCleanup();\r\n unregisterFocusable(id);\r\n });\r\n\r\n return () => {\r\n const options = props.options || [];\r\n const focused = isFocused();\r\n const currentValue = props.model?.value || options[0]?.value || '';\r\n const label = props.label;\r\n const selectedOption = options.find(o => o.value === currentValue);\r\n\r\n // Render options\r\n const optionElements = options.map((option) => {\r\n const isSelected = option.value === currentValue;\r\n const indicator = isSelected ? '❯' : ' ';\r\n const color = isSelected ? 'cyan' : 'white';\r\n\r\n return (\r\n <box>\r\n <text color={color}>{indicator} {option.label}</text>\r\n </box>\r\n );\r\n });\r\n\r\n // Description shown below the box (common pattern in CLI tools)\r\n const descriptionElement = props.showDescription && selectedOption?.description ? (\r\n <box>\r\n <text color=\"#666666\"> ↳ {selectedOption.description}</text>\r\n </box>\r\n ) : null;\r\n\r\n return (\r\n <box>\r\n <box border=\"single\" borderColor={focused ? 'green' : 'white'} label={label}>\r\n {optionElements}\r\n </box>\r\n {descriptionElement}\r\n </box>\r\n );\r\n };\r\n}, { name: 'Select' });\r\n\r\nexport default Select;\r\n","import { createRenderer, RendererOptions, setDefaultMount } from '@sigx/runtime-core/internals';\r\nimport { VNode } from '@sigx/runtime-core';\r\nimport { focusNext, focusPrev } from './focus';\r\nimport { getColorCode, getBackgroundColorCode, stripAnsi } from './utils';\r\n\r\n// Import type augmentation\r\nimport './types.js';\r\n\r\nexport * from './focus';\r\nexport * from './components/Input';\r\nexport * from './components/ProgressBar';\r\nexport * from './components/Button';\r\nexport * from './components/Checkbox';\r\nexport * from './components/Select';\r\n\r\n// --- Terminal Node Types ---\r\n\r\nexport interface TerminalNode {\r\n type: 'root' | 'element' | 'text' | 'comment';\r\n tag?: string;\r\n text?: string;\r\n props: Record<string, any>;\r\n children: TerminalNode[];\r\n parentNode?: TerminalNode | null;\r\n}\r\n\r\n// --- Node Operations ---\r\n\r\nconst nodeOps: RendererOptions<TerminalNode, TerminalNode> = {\r\n patchProp: (el, key, prev, next) => {\r\n el.props[key] = next;\r\n scheduleRender();\r\n },\r\n insert: (child, parent, anchor) => {\r\n child.parentNode = parent;\r\n const index = anchor ? parent.children.indexOf(anchor) : -1;\r\n if (index > -1) {\r\n parent.children.splice(index, 0, child);\r\n } else {\r\n parent.children.push(child);\r\n }\r\n scheduleRender();\r\n },\r\n remove: (child) => {\r\n if (child.parentNode) {\r\n const index = child.parentNode.children.indexOf(child);\r\n if (index > -1) {\r\n child.parentNode.children.splice(index, 1);\r\n }\r\n child.parentNode = null;\r\n }\r\n scheduleRender();\r\n },\r\n createElement: (tag) => {\r\n return { type: 'element', tag, props: {}, children: [] };\r\n },\r\n createText: (text) => {\r\n return { type: 'text', text, props: {}, children: [] };\r\n },\r\n createComment: (text) => {\r\n return { type: 'comment', text, props: {}, children: [] };\r\n },\r\n setText: (node, text) => {\r\n node.text = text;\r\n scheduleRender();\r\n },\r\n setElementText: (node, text) => {\r\n node.children = [{ type: 'text', text, props: {}, children: [], parentNode: node }];\r\n scheduleRender();\r\n },\r\n parentNode: (node) => node.parentNode || null,\r\n nextSibling: (node) => {\r\n if (!node.parentNode) return null;\r\n const idx = node.parentNode.children.indexOf(node);\r\n return node.parentNode.children[idx + 1] || null;\r\n },\r\n cloneNode: (node) => {\r\n // Shallow clone for simplicity in this demo\r\n return { ...node, children: [] };\r\n }\r\n};\r\n\r\n// --- Renderer Creation ---\r\n\r\nconst renderer = createRenderer(nodeOps);\r\nexport const { render } = renderer;\r\n\r\n// --- Terminal Rendering Logic ---\r\n\r\nlet rootNode: TerminalNode | null = null;\r\nlet isRendering = false;\r\n\r\nfunction scheduleRender() {\r\n if (isRendering) return;\r\n isRendering = true;\r\n // Use setImmediate or setTimeout to batch updates\r\n setTimeout(() => {\r\n flushRender();\r\n isRendering = false;\r\n }, 10);\r\n}\r\n\r\nfunction flushRender() {\r\n if (!rootNode) return;\r\n\r\n // Move cursor to top-left\r\n process.stdout.write('\\x1B[H');\r\n\r\n // Render tree\r\n const lines = renderNodeToLines(rootNode);\r\n process.stdout.write(lines.join('\\x1B[K\\n') + '\\x1B[K');\r\n\r\n // Clear rest of screen\r\n process.stdout.write('\\x1B[J');\r\n}\r\n\r\n\r\n/**\r\n * Check if a node has a box element as an immediate child.\r\n * This is used to determine if a component wrapper should be treated as a block element.\r\n */\r\nfunction hasBoxChild(node: TerminalNode): boolean {\r\n for (const child of node.children) {\r\n if (child.tag === 'box') {\r\n return true;\r\n }\r\n }\r\n return false;\r\n}\r\n\r\nexport function renderNodeToLines(node: TerminalNode): string[] {\r\n // if (node.tag === 'box') console.log('Rendering box', node.props);\r\n if (node.type === 'text') {\r\n return [node.text || ''];\r\n }\r\n if (node.type === 'comment') {\r\n return [];\r\n }\r\n\r\n let lines: string[] = [''];\r\n\r\n // Simple styling based on props (e.g., color)\r\n const color = node.props.color;\r\n const reset = color ? '\\x1b[0m' : '';\r\n const colorCode = getColorCode(color);\r\n\r\n // Render children\r\n for (const child of node.children) {\r\n if (child.type === 'text') {\r\n // Append text to the last line\r\n lines[lines.length - 1] += colorCode + (child.text || '') + reset;\r\n } else if (child.tag === 'br') {\r\n // Start a new line\r\n lines.push('');\r\n } else {\r\n // Recursively render child\r\n const childLines = renderNodeToLines(child);\r\n\r\n // Check if this child contains a box element (making it a block)\r\n // A box is always a block element, and component wrappers that contain\r\n // a box should also be treated as blocks\r\n const isBlockElement = child.tag === 'box' || hasBoxChild(child);\r\n\r\n if (isBlockElement) {\r\n // Block element - start on a new line\r\n if (lines.length === 1 && lines[0] === '') {\r\n lines = childLines;\r\n } else {\r\n lines.push(...childLines);\r\n }\r\n } else {\r\n // Inline element (like text wrapper)\r\n // This is tricky. If child returns multiple lines, it breaks the flow.\r\n // For now, assume non-box elements are inline-ish or just append.\r\n if (childLines.length > 0) {\r\n // If the child has multiple lines, treat it as a block to avoid\r\n // appending a box top border to the end of a text line.\r\n if (childLines.length > 1) {\r\n if (lines.length === 1 && lines[0] === '') {\r\n lines = childLines;\r\n } else {\r\n lines.push(...childLines);\r\n }\r\n } else {\r\n lines[lines.length - 1] += childLines[0];\r\n for (let i = 1; i < childLines.length; i++) {\r\n lines.push(childLines[i]);\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Apply box borders if needed\r\n if (node.tag === 'box' && node.props.border) {\r\n return drawBox(lines, node.props.border, node.props.borderColor, node.props.backgroundColor, node.props.dropShadow, node.props.label);\r\n }\r\n\r\n return lines;\r\n}\r\n\r\nfunction drawBox(contentLines: string[], style: string, color?: string, backgroundColor?: string, dropShadow?: boolean, label?: string): string[] {\r\n const borderChars = getBorderChars(style);\r\n const colorCode = color ? getColorCode(color) : '';\r\n const bgCode = backgroundColor ? getBackgroundColorCode(backgroundColor) : '';\r\n const reset = (color || backgroundColor) ? '\\x1b[0m' : '';\r\n\r\n // Calculate width\r\n const width = contentLines.reduce((max, line) => Math.max(max, stripAnsi(line).length), 0);\r\n\r\n // If there's a label, ensure box is wide enough to accommodate it\r\n const labelText = label || '';\r\n const labelLength = stripAnsi(labelText).length;\r\n const boxInnerWidth = Math.max(width, labelLength + 2);\r\n\r\n // Build top border. If label exists, center it in the top border like a fieldset legend\r\n let topInner = '';\r\n if (labelText) {\r\n const spaceForLabel = boxInnerWidth - labelLength - 2; // remaining space for horiz lines\r\n const leftH = Math.floor(spaceForLabel / 2);\r\n const rightH = spaceForLabel - leftH;\r\n topInner = borderChars.h.repeat(leftH) + ' ' + labelText + ' ' + borderChars.h.repeat(rightH);\r\n } else {\r\n topInner = borderChars.h.repeat(boxInnerWidth);\r\n }\r\n\r\n const top = bgCode + colorCode + borderChars.tl + topInner + borderChars.tr + reset;\r\n const bottom = bgCode + colorCode + borderChars.bl + borderChars.h.repeat(boxInnerWidth) + borderChars.br + reset;\r\n\r\n const result: string[] = [];\r\n result.push(top);\r\n\r\n for (const line of contentLines) {\r\n const visibleLength = stripAnsi(line).length;\r\n const padding = ' '.repeat(boxInnerWidth - visibleLength);\r\n // We need to apply background to the content line as well, but be careful not to double apply if it already has it?\r\n // Actually, the content might have its own colors.\r\n // But the padding needs the background color.\r\n // And the border needs the background color.\r\n\r\n // If we wrap the whole line in bgCode, it should work, provided we reset at the end.\r\n // But `line` might have resets in it.\r\n // A simple approach: apply bgCode to the border chars and the padding.\r\n // For the content, if it doesn't have bg, we might want to apply it.\r\n // But `line` is already a string with ANSI codes.\r\n\r\n // Let's try wrapping the whole thing.\r\n // Note: `line` comes from `renderNodeToLines`, which might have resets.\r\n // If `line` has `\\x1b[0m`, it will reset the background too.\r\n // So we might need to replace `\\x1b[0m` with `\\x1b[0m` + bgCode + colorCode?\r\n // That's getting complicated.\r\n\r\n // For now, let's just apply bg to borders and padding.\r\n // And maybe prepend bgCode to the line?\r\n\r\n // If we just prepend bgCode to `line`, and `line` has a reset, the rest of the line will lose the bg.\r\n // So we should replace resets in `line` with `reset + bgCode + colorCode` (if we want to maintain the box style).\r\n // But `colorCode` is for the border. The content might have its own text color.\r\n\r\n // Let's assume content handles its own text color, but we want to enforce background.\r\n // We can replace `\\x1b[0m` with `\\x1b[0m${bgCode}`.\r\n\r\n const lineWithBg = bgCode + line.replace(/\\x1b\\[0m/g, `\\x1b[0m${bgCode}`);\r\n\r\n result.push(bgCode + colorCode + borderChars.v + reset + lineWithBg + bgCode + padding + colorCode + borderChars.v + reset);\r\n }\r\n\r\n result.push(bottom);\r\n\r\n if (dropShadow) {\r\n const shadowColor = '\\x1b[90m'; // Bright black (gray)\r\n const resetShadow = '\\x1b[0m';\r\n const shadowChar = '▒';\r\n const shadowBlock = shadowColor + shadowChar + resetShadow;\r\n\r\n // Apply to lines 1 to end (skipping top line 0)\r\n for (let i = 1; i < result.length; i++) {\r\n result[i] += shadowBlock;\r\n }\r\n\r\n // Add bottom shadow line\r\n // Width is boxWidth (width + 2)\r\n const bottomShadow = ' ' + shadowBlock.repeat(width + 2);\r\n result.push(bottomShadow);\r\n }\r\n\r\n return result;\r\n}\r\n\r\nfunction getBorderChars(style: string) {\r\n if (style === 'double') {\r\n return { tl: '╔', tr: '╗', bl: '╚', br: '╝', h: '═', v: '║' };\r\n }\r\n if (style === 'rounded') {\r\n return { tl: '╭', tr: '╮', bl: '╰', br: '╯', h: '─', v: '│' };\r\n }\r\n // Default single\r\n return { tl: '┌', tr: '┐', bl: '└', br: '┘', h: '─', v: '│' };\r\n}\r\n\r\nfunction renderNodeToString(node: TerminalNode, depth = 0): string {\r\n // Deprecated, but kept for compatibility if needed, or just redirect\r\n return renderNodeToLines(node).join('\\n');\r\n}\r\n\r\n\r\n// --- Public API for mounting ---\r\n\r\ntype KeyHandler = (key: string) => void;\r\nconst keyHandlers = new Set<KeyHandler>();\r\n\r\nexport function onKey(handler: KeyHandler) {\r\n keyHandlers.add(handler);\r\n return () => keyHandlers.delete(handler);\r\n}\r\n\r\nfunction handleInput(key: string) {\r\n // Ctrl+C to exit\r\n if (key === '\\u0003') {\r\n process.stdout.write('\\x1B[?25h'); // Show cursor\r\n process.exit();\r\n }\r\n\r\n // Tab navigation\r\n if (key === '\\t') {\r\n focusNext();\r\n return;\r\n }\r\n // Shift+Tab (often \\x1b[Z)\r\n if (key === '\\x1b[Z') {\r\n focusPrev();\r\n return;\r\n }\r\n\r\n for (const handler of keyHandlers) {\r\n handler(key);\r\n }\r\n}\r\n\r\nexport interface RenderTerminalOptions {\r\n clearConsole?: boolean;\r\n}\r\n\r\nexport function renderTerminal(app: any, options: RenderTerminalOptions = {}) {\r\n rootNode = { type: 'root', props: {}, children: [] };\r\n\r\n // Create a proxy container that looks like a HostElement\r\n const container = rootNode;\r\n\r\n // Setup input\r\n if (process.stdin.isTTY) {\r\n process.stdin.setRawMode(true);\r\n process.stdin.resume();\r\n process.stdin.setEncoding('utf8');\r\n process.stdin.on('data', handleInput);\r\n }\r\n\r\n // Clear console if requested\r\n if (options.clearConsole) {\r\n process.stdout.write('\\x1B[2J\\x1B[3J\\x1B[H');\r\n }\r\n\r\n // Hide cursor\r\n process.stdout.write('\\x1B[?25l');\r\n\r\n render(app, container);\r\n\r\n // Initial render\r\n flushRender();\r\n\r\n return {\r\n unmount: () => {\r\n render(null, container);\r\n // Show cursor\r\n process.stdout.write('\\x1B[?25h');\r\n\r\n if (process.stdin.isTTY) {\r\n process.stdin.setRawMode(false);\r\n process.stdin.pause();\r\n process.stdin.off('data', handleInput);\r\n }\r\n }\r\n };\r\n}\r\n\r\nlet unmountFn: (() => void) | null = null;\r\n\r\n/**\r\n * Helper function to mount the terminal for CLI apps.\r\n * Returns a mount target that can be passed to defineApp().mount().\r\n * \r\n * @example\r\n * ```tsx\r\n * defineApp(MyApp).mount(mountTerminal());\r\n * ```\r\n */\r\nexport function mountTerminal(options: RenderTerminalOptions = { clearConsole: true }) {\r\n return {\r\n mount: terminalMount,\r\n options,\r\n onMount: (unmount: () => void) => {\r\n unmountFn = unmount;\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Exit the terminal app cleanly, restoring terminal state.\r\n */\r\nexport function exitTerminal() {\r\n if (unmountFn) {\r\n unmountFn();\r\n unmountFn = null;\r\n }\r\n // Show cursor\r\n process.stdout.write('\\x1B[?25h');\r\n // Clear screen\r\n process.stdout.write('\\x1B[2J\\x1B[H');\r\n}\r\n\r\n/**\r\n * Mount function for Terminal environments.\r\n * Use this with defineApp().mount() to render to the terminal.\r\n * \r\n * @example\r\n * ```tsx\r\n * import { defineApp } from '@sigx/runtime-core';\r\n * import { terminalMount } from '@sigx/runtime-terminal';\r\n * \r\n * const app = defineApp(<Counter />);\r\n * app.use(loggingPlugin)\r\n * .mount({ clearConsole: true }, terminalMount);\r\n * ```\r\n */\r\nexport const terminalMount = (component: any, options: RenderTerminalOptions, appContext?: any): (() => void) => {\r\n rootNode = { type: 'root', props: {}, children: [] };\r\n\r\n const container = rootNode;\r\n\r\n // Setup input\r\n if (process.stdin.isTTY) {\r\n process.stdin.setRawMode(true);\r\n process.stdin.resume();\r\n process.stdin.setEncoding('utf8');\r\n process.stdin.on('data', handleInput);\r\n }\r\n\r\n // Clear console if requested\r\n if (options?.clearConsole) {\r\n process.stdout.write('\\x1B[2J\\x1B[3J\\x1B[H');\r\n }\r\n\r\n // Hide cursor\r\n process.stdout.write('\\x1B[?25l');\r\n\r\n // Render with app context support\r\n render(component, container, appContext);\r\n\r\n // Initial render\r\n flushRender();\r\n\r\n // Return unmount function\r\n return () => {\r\n render(null, container);\r\n // Show cursor\r\n process.stdout.write('\\x1B[?25h');\r\n\r\n if (process.stdin.isTTY) {\r\n process.stdin.setRawMode(false);\r\n process.stdin.pause();\r\n process.stdin.off('data', handleInput);\r\n }\r\n };\r\n};\r\n\r\n// Set terminalMount as the default mount function for this platform\r\nsetDefaultMount(terminalMount);\r\n\r\ndeclare global {\r\n namespace JSX {\r\n interface IntrinsicElements {\r\n box: TerminalAttributes;\r\n text: TerminalAttributes;\r\n br: TerminalAttributes;\r\n }\r\n\r\n interface TerminalAttributes {\r\n color?: 'red' | 'green' | 'blue' | 'yellow' | 'cyan' | 'white' | 'black' | string;\r\n backgroundColor?: 'red' | 'green' | 'blue' | 'yellow' | 'cyan' | 'white' | 'black' | string;\r\n border?: 'single' | 'double' | 'rounded' | 'none';\r\n borderColor?: 'red' | 'green' | 'blue' | 'yellow' | 'cyan' | 'white' | 'black' | string;\r\n dropShadow?: boolean;\r\n label?: string;\r\n children?: any;\r\n }\r\n\r\n }\r\n}\r\n\r\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sigx/runtime-terminal",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "description": "Terminal renderer for SignalX",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -33,14 +33,14 @@
33
33
  "url": "https://github.com/signalxjs/core/issues"
34
34
  },
35
35
  "dependencies": {
36
- "@sigx/runtime-core": "^0.1.7",
37
- "@sigx/reactivity": "^0.1.7"
36
+ "@sigx/reactivity": "^0.1.9",
37
+ "@sigx/runtime-core": "^0.1.9"
38
38
  },
39
39
  "devDependencies": {
40
40
  "typescript": "^5.9.3",
41
41
  "@types/node": "^20.0.0",
42
42
  "vite": "^8.0.0-beta.9",
43
- "@sigx/vite": "^0.1.7"
43
+ "@sigx/vite": "^0.1.9"
44
44
  },
45
45
  "scripts": {
46
46
  "build": "vite build && tsc --emitDeclarationOnly",