@ai-matrx/terminal 0.1.1 → 0.1.3

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/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.3
4
+
5
+ AP-2 (2026-10-07) — the kit and Alchemy doors are the only doors in this package (aidream guard `apps/shared/scripts/check-shared-doors.mjs`). New dependency `@ai-matrx/kit`: the accessory bar's paste reads through kit `readText` and selection copy writes through kit `copyText` (async API + textarea fallback) instead of raw `navigator.clipboard`. No consumer action.
6
+
7
+ ## 0.1.2
8
+
9
+ Automatic changed-only republish (docs/metadata drift since the last tag — see
10
+ `git diff npm/terminal/v0.1.1..npm/terminal/v0.1.2 -- apps/shared/terminal`).
11
+ No source changes intended and no consumer action required.
12
+
3
13
  ## 0.1.1
4
14
 
5
15
  From the first independent phone walk.
@@ -28,3 +38,4 @@ First release — Matrx 2 lane E (the phone console), extracted from AI Matrx we
28
38
  prompt, cursor editing, ↑/↓ history, Ctrl-A/E/K/U/L/C, multi-line paste run line by line,
29
39
  typeahead kept while a command runs, `setLine` for text staged from outside.
30
40
  - Stylesheets ship in the package and `<Terminal>` imports them; `tokens.css` holds defaults.
41
+
package/dist/react.cjs CHANGED
@@ -40,6 +40,7 @@ module.exports = __toCommonJS(react_exports);
40
40
  var import_xterm = require("@xterm/xterm/css/xterm.css");
41
41
  var import_styles = require("@ai-matrx/terminal/styles.css");
42
42
  var import_react = require("react");
43
+ var import_clipboard = require("@ai-matrx/kit/clipboard");
43
44
 
44
45
  // src/core/keys.ts
45
46
  var ACCESSORY_KEYS = [
@@ -800,14 +801,9 @@ function Terminal(props) {
800
801
  return;
801
802
  }
802
803
  if (id === "paste") {
803
- if (!navigator.clipboard?.readText) return;
804
- navigator.clipboard.readText().then(
805
- (text) => {
806
- if (text) term.paste(text);
807
- },
808
- () => void 0
809
- // permission refused: the system paste menu still works on the input
810
- );
804
+ void (0, import_clipboard.readText)().then((text) => {
805
+ if (text) term.paste(text);
806
+ });
811
807
  return;
812
808
  }
813
809
  const current = latchRef.current;
@@ -821,7 +817,7 @@ function Terminal(props) {
821
817
  const term = termRef.current;
822
818
  if (!term) return;
823
819
  const text = term.getSelection();
824
- if (text && navigator.clipboard?.writeText) void navigator.clipboard.writeText(text);
820
+ if (text) void (0, import_clipboard.copyText)(text);
825
821
  term.clearSelection();
826
822
  setCopyVisible(false);
827
823
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/react.ts","../src/react/Terminal.tsx","../src/core/keys.ts","../src/core/modifiers.ts","../src/core/gesture.ts","../src/core/selection.ts","../src/core/theme.ts","../src/core/viewport.ts","../src/react/AccessoryBar.tsx"],"sourcesContent":["/**\n * @ai-matrx/terminal/react — <Terminal> (xterm 6 + fit + theme + phone touch + accessory bar)\n * and the bar on its own.\n */\nexport { Terminal } from \"./react/Terminal\";\nexport type { TerminalHandle, TerminalProps, TerminalSize } from \"./react/Terminal\";\nexport { AccessoryBar } from \"./react/AccessoryBar\";\nexport type { AccessoryBarProps } from \"./react/AccessoryBar\";\n","\"use client\";\n\n/**\n * <Terminal> — xterm 6 (DOM renderer) with everything a host would otherwise rebuild: fit to its\n * box or to the visual viewport, theme that follows the app's `.dark` class, Ctrl-C hook, phone\n * touch (momentum scroll, long-press word select, copy), and the keyboard accessory bar with\n * one-shot / locked Ctrl and Alt. Transport-free: bytes in through the handle's `write`, keys\n * out through `onData`, size out through `onResize`. Any PTY (desktop relay, cloud sandbox,\n * local process) plugs in with three lines.\n */\n// The package ships its stylesheets; importing them here means a host never forgets them. Both\n// stay as imports in the built bundle (tsup externals) for the host's bundler to place.\nimport \"@xterm/xterm/css/xterm.css\";\nimport \"@ai-matrx/terminal/styles.css\";\nimport { useEffect, useRef, useState } from \"react\";\nimport type { CSSProperties, ReactNode } from \"react\";\nimport type { ITerminalOptions, Terminal as XTerm } from \"@xterm/xterm\";\nimport type { FitAddon } from \"@xterm/addon-fit\";\n\nimport { ACCESSORY_KEYS, applyModifiers, keySequence } from \"../core/keys\";\nimport type { AccessoryKeyId } from \"../core/keys\";\nimport { MODIFIER_OFF, afterKey, isActive, tapModifier } from \"../core/modifiers\";\nimport type { ModifierLatch } from \"../core/modifiers\";\nimport { LONG_PRESS_MS, createGestureRecognizer, flingStep } from \"../core/gesture\";\nimport type { GestureAction } from \"../core/gesture\";\nimport { cellAt, spanBetween, wordBounds } from \"../core/selection\";\nimport type { Cell } from \"../core/selection\";\nimport { TERMINAL_DEFAULTS, TERMINAL_FONT_FAMILY, pinchFontSize, stepFontSize, terminalTheme } from \"../core/theme\";\nimport { visibleHeightBelow } from \"../core/viewport\";\nimport { AccessoryBar } from \"./AccessoryBar\";\n\nexport interface TerminalSize {\n cols: number;\n rows: number;\n}\n\n/** What a host drives the terminal with. Stable for the terminal's life. */\nexport interface TerminalHandle {\n /** Write output; resolves once xterm has parsed it (use it to pace credit-based streams). */\n write(data: string | Uint8Array): Promise<void>;\n /** Clear screen, scrollback and modes — before writing a fresh screen snapshot. */\n reset(): void;\n /** Clear the scrollback, keep the prompt line. */\n clear(): void;\n focus(): void;\n blur(): void;\n /** Visible text of the whole buffer (scrollback included), lines joined with \\n. */\n getText(): string;\n readonly cols: number;\n readonly rows: number;\n /** The underlying xterm, for what this package does not wrap (read-mostly use). */\n readonly xterm: XTerm;\n}\n\nexport interface TerminalProps {\n /** Keystrokes and pastes, already modified by the accessory bar's Ctrl / Alt. */\n onData?: (data: string) => void;\n /** Grid size after every fit (and once at start). */\n onResize?: (size: TerminalSize) => void;\n /**\n * The person zoomed the text: a pinch on touch, ⌘+ / ⌘− / ⌘0 with a keyboard. Pass it (and feed\n * the value back as `fontSize`) to turn zoom on; the host decides where the size is remembered.\n */\n onFontSizeChange?: (fontSize: number) => void;\n onReady?: (handle: TerminalHandle) => void;\n /**\n * Hardware Ctrl-C (no Shift/Alt/Meta). Return true to consume it — e.g. send a SIGINT frame\n * because the page's own shortcuts eat the key. Default: xterm sends ETX (0x03) through onData.\n */\n onInterrupt?: () => boolean;\n /** \"auto\" follows the `dark` class on <html>. */\n theme?: \"auto\" | \"dark\" | \"light\";\n fontSize?: number;\n lineHeight?: number;\n scrollback?: number;\n /** Side padding, px. */\n padding?: number;\n /** Translate bare \\n to \\r\\n (for line-oriented output that is not a PTY). */\n convertEol?: boolean;\n cursorBlink?: boolean;\n disableStdin?: boolean;\n /** Clickable URLs. Default true. */\n links?: boolean;\n /** Phone touch gestures. \"auto\" = when the primary pointer is coarse. */\n touch?: \"auto\" | \"on\" | \"off\";\n /** The keyboard accessory bar. \"auto\" = when the primary pointer is coarse. */\n accessory?: \"auto\" | \"on\" | \"off\";\n /**\n * \"container\": fill the parent box (it must have a height). \"viewport\": grow from where the\n * terminal starts down to the bottom of the VISUAL viewport, so the last row and the accessory\n * bar sit right above the on-screen keyboard.\n */\n fit?: \"container\" | \"viewport\";\n autoFocus?: boolean;\n className?: string;\n style?: CSSProperties;\n \"aria-label\"?: string;\n /** Rendered over the terminal (e.g. a reconnecting veil). */\n children?: ReactNode;\n}\n\ninterface Latches {\n ctrl: ModifierLatch;\n alt: ModifierLatch;\n}\n\nfunction prefersDark(): boolean {\n return typeof document !== \"undefined\" && document.documentElement.classList.contains(\"dark\");\n}\n\nfunction coarsePointer(): boolean {\n return typeof window !== \"undefined\" && typeof window.matchMedia === \"function\" && window.matchMedia(\"(pointer: coarse)\").matches;\n}\n\nexport function Terminal(props: TerminalProps) {\n const {\n theme = \"auto\",\n fontSize = TERMINAL_DEFAULTS.fontSize,\n lineHeight = TERMINAL_DEFAULTS.lineHeight,\n scrollback = TERMINAL_DEFAULTS.scrollback,\n padding = TERMINAL_DEFAULTS.padding,\n convertEol = false,\n cursorBlink = true,\n disableStdin = false,\n links = true,\n touch = \"auto\",\n accessory = \"auto\",\n fit = \"container\",\n autoFocus = false,\n } = props;\n\n const rootRef = useRef<HTMLDivElement | null>(null);\n const hostRef = useRef<HTMLDivElement | null>(null);\n const termRef = useRef<XTerm | null>(null);\n const fitRef = useRef<FitAddon | null>(null);\n const handleRef = useRef<TerminalHandle | null>(null);\n const latchRef = useRef<Latches>({ ctrl: MODIFIER_OFF, alt: MODIFIER_OFF });\n const callbacksRef = useRef({\n onData: props.onData,\n onResize: props.onResize,\n onReady: props.onReady,\n onInterrupt: props.onInterrupt,\n onFontSizeChange: props.onFontSizeChange,\n });\n const fontSizeRef = useRef(fontSize);\n\n const [latches, setLatches] = useState<Latches>({ ctrl: MODIFIER_OFF, alt: MODIFIER_OFF });\n const [coarse, setCoarse] = useState(false);\n const [dark, setDark] = useState(theme === \"dark\");\n const [copyVisible, setCopyVisible] = useState(false);\n const [viewportHeight, setViewportHeight] = useState<number | null>(null);\n const [booted, setBooted] = useState(false);\n\n useEffect(() => {\n callbacksRef.current = {\n onData: props.onData,\n onResize: props.onResize,\n onReady: props.onReady,\n onInterrupt: props.onInterrupt,\n onFontSizeChange: props.onFontSizeChange,\n };\n fontSizeRef.current = fontSize;\n });\n\n // Pointer class and theme are browser facts: read after mount (SSR renders the neutral frame).\n useEffect(() => {\n setCoarse(coarsePointer());\n const mq = typeof window.matchMedia === \"function\" ? window.matchMedia(\"(pointer: coarse)\") : null;\n const onChange = () => setCoarse(coarsePointer());\n mq?.addEventListener(\"change\", onChange);\n return () => mq?.removeEventListener(\"change\", onChange);\n }, []);\n\n useEffect(() => {\n if (theme !== \"auto\") {\n setDark(theme === \"dark\");\n return undefined;\n }\n setDark(prefersDark());\n if (typeof MutationObserver === \"undefined\") return undefined;\n const observer = new MutationObserver(() => setDark(prefersDark()));\n observer.observe(document.documentElement, { attributes: true, attributeFilter: [\"class\"] });\n return () => observer.disconnect();\n }, [theme]);\n\n const touchOn = touch === \"on\" || (touch === \"auto\" && coarse);\n const barOn = accessory === \"on\" || (accessory === \"auto\" && coarse);\n\n function setLatchState(next: Latches): void {\n latchRef.current = next;\n setLatches(next);\n }\n\n /** Keyboard input → accessory modifiers → host. */\n function emit(data: string): void {\n const current = latchRef.current;\n const mods = { ctrl: isActive(current.ctrl), alt: isActive(current.alt) };\n const { data: out, consumed } = applyModifiers(data, mods);\n if (consumed) setLatchState({ ctrl: afterKey(current.ctrl), alt: afterKey(current.alt) });\n callbacksRef.current.onData?.(out);\n }\n\n // ── boot xterm once ───────────────────────────────────────────────────────\n useEffect(() => {\n let cancelled = false;\n let disposeAll: (() => void) | null = null;\n void (async () => {\n const [{ Terminal: XTermCtor }, { FitAddon: FitCtor }, linksModule] = await Promise.all([\n import(\"@xterm/xterm\"),\n import(\"@xterm/addon-fit\"),\n import(\"@xterm/addon-web-links\"),\n ]);\n const host = hostRef.current;\n if (cancelled || !host) return;\n const options: ITerminalOptions = {\n fontFamily: TERMINAL_FONT_FAMILY,\n fontSize,\n lineHeight,\n scrollback,\n convertEol,\n cursorBlink,\n cursorStyle: \"bar\",\n disableStdin,\n allowProposedApi: false,\n theme: terminalTheme(theme === \"auto\" ? prefersDark() : theme === \"dark\"),\n };\n const term = new XTermCtor(options);\n const fitAddon = new FitCtor();\n term.loadAddon(fitAddon);\n if (links) term.loadAddon(new linksModule.WebLinksAddon());\n term.open(host);\n const textarea = term.textarea;\n if (textarea) {\n // iOS: no autocorrect/capitalisation in a shell; 16px stops the focus zoom (styles.css).\n textarea.setAttribute(\"autocorrect\", \"off\");\n textarea.setAttribute(\"autocapitalize\", \"off\");\n textarea.setAttribute(\"autocomplete\", \"off\");\n textarea.setAttribute(\"spellcheck\", \"false\");\n textarea.setAttribute(\"aria-label\", props[\"aria-label\"] ?? \"Terminal input\");\n }\n termRef.current = term;\n fitRef.current = fitAddon;\n\n const dataSub = term.onData((data) => emit(data));\n const resizeSub = term.onResize(({ cols, rows }) => callbacksRef.current.onResize?.({ cols, rows }));\n term.attachCustomKeyEventHandler((event) => {\n // ⌘+ / ⌘− / ⌘0 zoom the text (only when the host takes the size: onFontSizeChange).\n const zoom = callbacksRef.current.onFontSizeChange;\n if (zoom && event.type === \"keydown\" && event.metaKey && !event.altKey && !event.ctrlKey) {\n const delta = event.key === \"=\" || event.key === \"+\" ? 1 : event.key === \"-\" ? -1 : event.key === \"0\" ? 0 : null;\n if (delta !== null) {\n event.preventDefault();\n zoom(delta === 0 ? TERMINAL_DEFAULTS.fontSize : stepFontSize(fontSizeRef.current, delta));\n return false;\n }\n }\n if (\n event.type === \"keydown\" &&\n event.ctrlKey &&\n !event.shiftKey &&\n !event.altKey &&\n !event.metaKey &&\n event.key.toLowerCase() === \"c\" &&\n !term.hasSelection()\n ) {\n const consumed = callbacksRef.current.onInterrupt?.() ?? false;\n if (consumed) return false;\n }\n return true;\n });\n const selectionSub = term.onSelectionChange(() => setCopyVisible(term.hasSelection()));\n\n const handle: TerminalHandle = {\n write: (data) => new Promise<void>((resolve) => term.write(data, resolve)),\n reset: () => term.reset(),\n clear: () => term.clear(),\n focus: () => term.focus(),\n blur: () => term.blur(),\n getText: () => {\n const buffer = term.buffer.active;\n const lines: string[] = [];\n for (let y = 0; y < buffer.length; y++) lines.push(buffer.getLine(y)?.translateToString(true) ?? \"\");\n while (lines.length > 0 && lines[lines.length - 1] === \"\") lines.pop();\n return lines.join(\"\\n\");\n },\n get cols() {\n return term.cols;\n },\n get rows() {\n return term.rows;\n },\n xterm: term,\n };\n handleRef.current = handle;\n try {\n fitAddon.fit();\n } catch {\n // The box may not be laid out yet; the resize observer fits it when it is.\n }\n setBooted(true);\n callbacksRef.current.onResize?.({ cols: term.cols, rows: term.rows });\n callbacksRef.current.onReady?.(handle);\n if (autoFocus) term.focus();\n\n disposeAll = () => {\n dataSub.dispose();\n resizeSub.dispose();\n selectionSub.dispose();\n term.dispose();\n };\n })();\n return () => {\n cancelled = true;\n disposeAll?.();\n termRef.current = null;\n fitRef.current = null;\n handleRef.current = null;\n };\n // Boot exactly once per mount; later option changes are applied by the effects below.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // ── live options ──────────────────────────────────────────────────────────\n useEffect(() => {\n const term = termRef.current;\n if (!term) return;\n term.options.theme = terminalTheme(dark);\n }, [dark, booted]);\n\n useEffect(() => {\n const term = termRef.current;\n if (!term) return;\n term.options.disableStdin = disableStdin;\n term.options.fontSize = fontSize;\n term.options.lineHeight = lineHeight;\n try {\n fitRef.current?.fit();\n } catch {\n // between frames\n }\n }, [disableStdin, fontSize, lineHeight, booted]);\n\n // ── fit to the box ────────────────────────────────────────────────────────\n useEffect(() => {\n const host = hostRef.current;\n if (!host) return undefined;\n const refit = () => {\n const term = termRef.current;\n if (!term || host.clientWidth <= 0 || host.clientHeight <= 0) return;\n try {\n fitRef.current?.fit();\n // A DOM renderer mounted while hidden measured zero-width glyphs; refresh re-measures.\n term.refresh(0, term.rows - 1);\n } catch {\n // xterm is mid-paint\n }\n };\n refit();\n if (typeof ResizeObserver === \"undefined\") return undefined; // non-browser hosts (jsdom)\n const ro = new ResizeObserver(refit);\n ro.observe(host);\n return () => ro.disconnect();\n }, [booted]);\n\n // ── fit to the visual viewport (phones: stop exactly at the keyboard) ─────\n useEffect(() => {\n if (fit !== \"viewport\") {\n setViewportHeight(null);\n return undefined;\n }\n const root = rootRef.current;\n if (!root) return undefined;\n const vv = window.visualViewport;\n const measure = () => {\n // The console owns the screen: a page scrolled by iOS to \"reveal\" the input only hides the top.\n if (window.scrollY !== 0) window.scrollTo(0, 0);\n const top = root.getBoundingClientRect().top + window.scrollY;\n setViewportHeight(visibleHeightBelow(top, vv ? { height: vv.height, offsetTop: vv.offsetTop } : null, window.innerHeight));\n };\n measure();\n vv?.addEventListener(\"resize\", measure);\n vv?.addEventListener(\"scroll\", measure);\n window.addEventListener(\"resize\", measure);\n window.addEventListener(\"orientationchange\", measure);\n return () => {\n vv?.removeEventListener(\"resize\", measure);\n vv?.removeEventListener(\"scroll\", measure);\n window.removeEventListener(\"resize\", measure);\n window.removeEventListener(\"orientationchange\", measure);\n };\n }, [fit]);\n\n // ── touch: tap focuses, drag scrolls with momentum, hold selects ──────────\n useEffect(() => {\n const host = hostRef.current;\n const term = termRef.current;\n if (!touchOn || !host || !term) return undefined;\n // Re-created at each touch so a zoom (pinch, ⌘±) is already in the row height it scrolls by.\n let recognizer = createGestureRecognizer({ lineHeight: fontSizeRef.current * lineHeight });\n let holdTimer: ReturnType<typeof setTimeout> | null = null;\n let flingFrame: number | null = null;\n let flingCarry = 0;\n let anchor: Cell | null = null;\n\n const screen = () => (term.element?.querySelector(\".xterm-screen\") as HTMLElement | null) ?? host;\n const cellFor = (x: number, y: number): Cell => {\n const r = screen().getBoundingClientRect();\n return cellAt({ x, y }, { left: r.left, top: r.top, width: r.width, height: r.height }, { cols: term.cols, rows: term.rows, viewportY: term.buffer.active.viewportY });\n };\n const scrollLines = (lines: number) => {\n if (lines === 0) return;\n if (term.buffer.active.type === \"alternate\") {\n // Full-screen programs (less, vim, htop) own their screen: a drag pages them with arrows.\n const key = lines > 0 ? \"down\" : \"up\";\n const seq = keySequence(key, { ctrl: false, alt: false }, { applicationCursor: term.modes.applicationCursorKeysMode });\n if (seq) callbacksRef.current.onData?.(seq.repeat(Math.min(Math.abs(lines), 50)));\n return;\n }\n term.scrollLines(lines);\n };\n const stopFling = () => {\n if (flingFrame !== null) cancelAnimationFrame(flingFrame);\n flingFrame = null;\n flingCarry = 0;\n };\n const startFling = (velocity: number) => {\n stopFling();\n let v = velocity;\n let last = performance.now();\n const step = (now: number) => {\n const res = flingStep(v, now - last);\n last = now;\n v = res.velocity;\n flingCarry += res.lines;\n const whole = flingCarry > 0 ? Math.floor(flingCarry) : Math.ceil(flingCarry);\n if (whole !== 0) {\n flingCarry -= whole;\n scrollLines(whole);\n }\n flingFrame = v === 0 ? null : requestAnimationFrame(step);\n };\n flingFrame = requestAnimationFrame(step);\n };\n const act = (actions: GestureAction[]) => {\n for (const a of actions) {\n switch (a.kind) {\n case \"tap\":\n term.clearSelection();\n term.focus();\n break;\n case \"scroll\":\n scrollLines(a.lines);\n break;\n case \"fling\":\n startFling(a.velocity);\n break;\n case \"select-start\": {\n const cell = cellFor(a.x, a.y);\n const line = term.buffer.active.getLine(cell.row)?.translateToString(false) ?? \"\";\n const word = wordBounds(line, cell.col);\n anchor = { col: word.start, row: cell.row };\n term.select(word.start, cell.row, Math.max(1, word.end - word.start));\n navigator.vibrate?.(10);\n break;\n }\n case \"select-extend\": {\n if (!anchor) break;\n const span = spanBetween(anchor, cellFor(a.x, a.y), term.cols);\n term.select(span.col, span.row, span.length);\n break;\n }\n case \"select-end\":\n anchor = null;\n setCopyVisible(term.hasSelection());\n break;\n }\n }\n };\n const clearHold = () => {\n if (holdTimer !== null) clearTimeout(holdTimer);\n holdTimer = null;\n };\n /** Two fingers: pinch-zoom the TEXT (when the host takes the size), never the page. */\n let pinch: { startDistance: number; startSize: number } | null = null;\n const fingerDistance = (e: TouchEvent) => {\n const a = e.touches[0]!;\n const b = e.touches[1]!;\n return Math.hypot(a.clientX - b.clientX, a.clientY - b.clientY);\n };\n const onStart = (e: TouchEvent) => {\n if (e.touches.length === 2 && callbacksRef.current.onFontSizeChange) {\n e.preventDefault();\n clearHold();\n stopFling();\n act(recognizer.cancel());\n pinch = { startDistance: fingerDistance(e), startSize: fontSizeRef.current };\n return;\n }\n if (e.touches.length !== 1) {\n clearHold();\n act(recognizer.cancel());\n return; // more fingers, or no zoom wanted: leave it to the browser\n }\n const t = e.touches[0]!;\n e.preventDefault();\n stopFling();\n recognizer = createGestureRecognizer({ lineHeight: fontSizeRef.current * lineHeight });\n act(recognizer.down({ x: t.clientX, y: t.clientY, t: e.timeStamp }));\n clearHold();\n holdTimer = setTimeout(() => act(recognizer.longPress()), LONG_PRESS_MS);\n };\n const onMove = (e: TouchEvent) => {\n if (pinch && e.touches.length === 2) {\n e.preventDefault();\n const size = pinchFontSize(pinch.startSize, pinch.startDistance, fingerDistance(e));\n if (size !== fontSizeRef.current) {\n fontSizeRef.current = size;\n callbacksRef.current.onFontSizeChange?.(size);\n }\n return;\n }\n if (e.touches.length !== 1 || recognizer.phase === \"idle\") return;\n const t = e.touches[0]!;\n e.preventDefault();\n act(recognizer.move({ x: t.clientX, y: t.clientY, t: e.timeStamp }));\n if (recognizer.phase !== \"pressed\") clearHold();\n };\n const onEnd = (e: TouchEvent) => {\n if (pinch) {\n if (e.touches.length < 2) pinch = null;\n e.preventDefault();\n return;\n }\n clearHold();\n if (recognizer.phase === \"idle\") return;\n const t = e.changedTouches[0];\n e.preventDefault();\n act(recognizer.up({ x: t?.clientX ?? 0, y: t?.clientY ?? 0, t: e.timeStamp }));\n };\n const onCancel = () => {\n clearHold();\n act(recognizer.cancel());\n };\n host.addEventListener(\"touchstart\", onStart, { passive: false });\n host.addEventListener(\"touchmove\", onMove, { passive: false });\n host.addEventListener(\"touchend\", onEnd, { passive: false });\n host.addEventListener(\"touchcancel\", onCancel);\n return () => {\n clearHold();\n stopFling();\n host.removeEventListener(\"touchstart\", onStart);\n host.removeEventListener(\"touchmove\", onMove);\n host.removeEventListener(\"touchend\", onEnd);\n host.removeEventListener(\"touchcancel\", onCancel);\n };\n }, [touchOn, booted, lineHeight]);\n\n // ── accessory bar ─────────────────────────────────────────────────────────\n function onAccessoryKey(id: AccessoryKeyId): void {\n const term = termRef.current;\n if (!term) return;\n const def = ACCESSORY_KEYS.find((k) => k.id === id);\n if (!def) return;\n if (def.kind === \"modifier\") {\n const now = performance.now();\n const current = latchRef.current;\n setLatchState(id === \"ctrl\" ? { ...current, ctrl: tapModifier(current.ctrl, now) } : { ...current, alt: tapModifier(current.alt, now) });\n return;\n }\n if (id === \"hide\") {\n term.blur();\n term.textarea?.blur();\n return;\n }\n if (id === \"paste\") {\n if (!navigator.clipboard?.readText) return;\n navigator.clipboard.readText().then(\n (text) => {\n if (text) term.paste(text);\n },\n () => undefined, // permission refused: the system paste menu still works on the input\n );\n return;\n }\n const current = latchRef.current;\n const mods = { ctrl: isActive(current.ctrl), alt: isActive(current.alt) };\n const seq = keySequence(id, mods, { applicationCursor: term.modes.applicationCursorKeysMode });\n if (seq === null) return;\n if (mods.ctrl || mods.alt) setLatchState({ ctrl: afterKey(current.ctrl), alt: afterKey(current.alt) });\n callbacksRef.current.onData?.(seq);\n }\n\n function copySelection(): void {\n const term = termRef.current;\n if (!term) return;\n const text = term.getSelection();\n if (text && navigator.clipboard?.writeText) void navigator.clipboard.writeText(text);\n term.clearSelection();\n setCopyVisible(false);\n }\n\n const rootStyle: CSSProperties = { ...props.style };\n if (viewportHeight !== null) rootStyle.height = viewportHeight;\n\n return (\n <div\n ref={rootRef}\n className={[\"mxt-root\", props.className].filter(Boolean).join(\" \")}\n style={rootStyle}\n data-touch={touchOn ? \"on\" : \"off\"}\n data-theme={dark ? \"dark\" : \"light\"}\n >\n <div className=\"mxt-frame\" style={{ background: terminalTheme(dark).background }}>\n <div ref={hostRef} className=\"mxt-host\" style={{ paddingLeft: padding, paddingRight: padding }} />\n {copyVisible ? (\n <button type=\"button\" className=\"mxt-copy\" onPointerDown={(e) => e.preventDefault()} onClick={copySelection}>\n Copy\n </button>\n ) : null}\n {props.children}\n </div>\n {barOn ? <AccessoryBar ctrl={latches.ctrl.state} alt={latches.alt.state} onKey={onAccessoryKey} /> : null}\n </div>\n );\n}\n","/**\n * The keyboard accessory bar's keys and the bytes each sends — the keys a phone keyboard lacks.\n * Pure: no DOM, no xterm. Sequences follow xterm's own encoding (CSI 1;<mod> for modified cursor\n * keys, SS3 in application cursor mode), so full-screen programs (vim, less, htop) read them\n * exactly as they read a desktop keyboard.\n */\n\nexport type AccessoryKeyId =\n | \"esc\"\n | \"tab\"\n | \"ctrl\"\n | \"alt\"\n | \"left\"\n | \"down\"\n | \"up\"\n | \"right\"\n | \"pipe\"\n | \"slash\"\n | \"tilde\"\n | \"dash\"\n | \"home\"\n | \"end\"\n | \"pgup\"\n | \"pgdn\"\n | \"paste\"\n | \"hide\";\n\nexport interface AccessoryKeyDef {\n id: AccessoryKeyId;\n /** What the key shows. */\n label: string;\n /** What a screen reader says. */\n aria: string;\n /** send = bytes to the PTY; modifier = Ctrl/Alt state; action = paste / hide keyboard. */\n kind: \"send\" | \"modifier\" | \"action\";\n /** Keys sharing a group sit together; a divider separates groups. */\n group: number;\n}\n\n/** Termius order: Esc Tab Ctrl Alt | ← ↓ ↑ → | | / ~ - | Home End PgUp PgDn | Paste, hide. */\nexport const ACCESSORY_KEYS: readonly AccessoryKeyDef[] = [\n { id: \"esc\", label: \"Esc\", aria: \"Escape\", kind: \"send\", group: 0 },\n { id: \"tab\", label: \"Tab\", aria: \"Tab\", kind: \"send\", group: 0 },\n { id: \"ctrl\", label: \"Ctrl\", aria: \"Control\", kind: \"modifier\", group: 0 },\n { id: \"alt\", label: \"Alt\", aria: \"Alt\", kind: \"modifier\", group: 0 },\n { id: \"left\", label: \"←\", aria: \"Left arrow\", kind: \"send\", group: 1 },\n { id: \"down\", label: \"↓\", aria: \"Down arrow\", kind: \"send\", group: 1 },\n { id: \"up\", label: \"↑\", aria: \"Up arrow\", kind: \"send\", group: 1 },\n { id: \"right\", label: \"→\", aria: \"Right arrow\", kind: \"send\", group: 1 },\n { id: \"pipe\", label: \"|\", aria: \"Pipe\", kind: \"send\", group: 2 },\n { id: \"slash\", label: \"/\", aria: \"Slash\", kind: \"send\", group: 2 },\n { id: \"tilde\", label: \"~\", aria: \"Tilde\", kind: \"send\", group: 2 },\n { id: \"dash\", label: \"-\", aria: \"Dash\", kind: \"send\", group: 2 },\n { id: \"home\", label: \"Home\", aria: \"Home\", kind: \"send\", group: 3 },\n { id: \"end\", label: \"End\", aria: \"End\", kind: \"send\", group: 3 },\n { id: \"pgup\", label: \"PgUp\", aria: \"Page up\", kind: \"send\", group: 3 },\n { id: \"pgdn\", label: \"PgDn\", aria: \"Page down\", kind: \"send\", group: 3 },\n { id: \"paste\", label: \"Paste\", aria: \"Paste\", kind: \"action\", group: 4 },\n { id: \"hide\", label: \"Hide\", aria: \"Hide keyboard\", kind: \"action\", group: 4 },\n];\n\nexport interface ActiveModifiers {\n ctrl: boolean;\n alt: boolean;\n}\n\nexport interface KeyModes {\n /** DECCKM — xterm's `modes.applicationCursorKeysMode`. */\n applicationCursor: boolean;\n}\n\nconst ESC = \"\\x1b\";\nconst CURSOR: Partial<Record<AccessoryKeyId, string>> = { up: \"A\", down: \"B\", right: \"C\", left: \"D\", home: \"H\", end: \"F\" };\nconst TILDE: Partial<Record<AccessoryKeyId, string>> = { pgup: \"5\", pgdn: \"6\" };\nconst LITERAL: Partial<Record<AccessoryKeyId, string>> = { pipe: \"|\", slash: \"/\", tilde: \"~\", dash: \"-\", tab: \"\\t\", esc: ESC };\n\n/** xterm's modifier parameter: 1 + shift(1) + alt(2) + ctrl(4). */\nfunction modParam(mods: ActiveModifiers): number {\n return 1 + (mods.alt ? 2 : 0) + (mods.ctrl ? 4 : 0);\n}\n\n/**\n * Bytes for a \"send\" key with the active modifiers applied, or null for a modifier/action key.\n * Modifiers on literal keys go through `applyModifiers` (Ctrl+/ → 0x1f, Alt+| → ESC |).\n */\nexport function keySequence(id: AccessoryKeyId, mods: ActiveModifiers, modes: KeyModes): string | null {\n const cursor = CURSOR[id];\n if (cursor !== undefined) {\n const m = modParam(mods);\n if (m > 1) return `${ESC}[1;${m}${cursor}`;\n return modes.applicationCursor ? `${ESC}O${cursor}` : `${ESC}[${cursor}`;\n }\n const tilde = TILDE[id];\n if (tilde !== undefined) {\n const m = modParam(mods);\n return m > 1 ? `${ESC}[${tilde};${m}~` : `${ESC}[${tilde}~`;\n }\n const literal = LITERAL[id];\n if (literal !== undefined) {\n if (id === \"tab\" && mods.ctrl === false && mods.alt === false) return literal;\n if (id === \"esc\") return mods.alt ? ESC + ESC : ESC;\n return applyModifiers(literal, mods).data;\n }\n return null;\n}\n\n/** Ctrl applied to one character, as a terminal keyboard encodes it; null when Ctrl has no code. */\nexport function controlCode(char: string): string | null {\n if (char.length !== 1) return null;\n const code = char.charCodeAt(0);\n if (code >= 0x61 && code <= 0x7a) return String.fromCharCode(code - 0x60); // a-z\n if (code >= 0x40 && code <= 0x5f) return String.fromCharCode(code - 0x40); // @ A-Z [ \\ ] ^ _\n switch (char) {\n case \" \":\n case \"2\":\n return \"\\x00\";\n case \"3\":\n return \"\\x1b\";\n case \"4\":\n return \"\\x1c\";\n case \"5\":\n return \"\\x1d\";\n case \"6\":\n return \"\\x1e\";\n case \"7\":\n case \"/\":\n case \"-\":\n return \"\\x1f\";\n case \"8\":\n case \"?\":\n return \"\\x7f\";\n default:\n return null;\n }\n}\n\n/**\n * Apply one-shot or locked modifiers to what the keyboard typed. Only a single key press is\n * modified — a paste or a multi-character IME commit passes through and does NOT consume the\n * modifier, so \"Ctrl, then paste\" never mangles the paste.\n */\nexport function applyModifiers(data: string, mods: ActiveModifiers): { data: string; consumed: boolean } {\n if (!mods.ctrl && !mods.alt) return { data, consumed: false };\n const chars = Array.from(data);\n if (chars.length !== 1) {\n // A cursor key typed on a hardware keyboard while Ctrl/Alt are latched: re-encode it.\n const m = /^\\x1b(?:\\[|O)([ABCDHF])$/.exec(data);\n if (m) return { data: `${ESC}[1;${modParam(mods)}${m[1]}`, consumed: true };\n return { data, consumed: false };\n }\n let out = data;\n if (mods.ctrl) {\n const ctl = controlCode(data);\n if (ctl !== null) out = ctl;\n }\n if (mods.alt) out = ESC + out;\n return { data: out, consumed: true };\n}\n","/**\n * Ctrl / Alt on the accessory bar: tap once = the next key only; tap twice quickly = locked until\n * tapped again. Pure state machine; the clock is passed in.\n */\n\nexport type ModifierState = \"off\" | \"once\" | \"locked\";\n\nexport interface ModifierLatch {\n state: ModifierState;\n /** When the latch was last tapped (ms), for double-tap detection. */\n tappedAt: number | null;\n}\n\n/** Two taps within this window lock the modifier (iOS's own double-tap timing for Shift lock). */\nexport const DOUBLE_TAP_MS = 350;\n\nexport const MODIFIER_OFF: ModifierLatch = { state: \"off\", tappedAt: null };\n\nexport function tapModifier(latch: ModifierLatch, now: number): ModifierLatch {\n switch (latch.state) {\n case \"off\":\n return { state: \"once\", tappedAt: now };\n case \"once\":\n return latch.tappedAt !== null && now - latch.tappedAt <= DOUBLE_TAP_MS\n ? { state: \"locked\", tappedAt: now }\n : { state: \"off\", tappedAt: now };\n case \"locked\":\n return { state: \"off\", tappedAt: now };\n }\n}\n\n/** After a key used the modifier: a one-shot latch releases, a locked one holds. */\nexport function afterKey(latch: ModifierLatch): ModifierLatch {\n return latch.state === \"once\" ? { state: \"off\", tappedAt: latch.tappedAt } : latch;\n}\n\nexport function isActive(latch: ModifierLatch): boolean {\n return latch.state !== \"off\";\n}\n","/**\n * One-finger gestures on a terminal, as iOS terminals (Termius, Blink) read them:\n *\n * tap → focus (opens the keyboard)\n * drag up / down → scroll the scrollback, by whole lines, with momentum on release\n * press and hold, no move → select the word under the finger; keep dragging to extend\n *\n * Pure: the host feeds pointer samples and the long-press timeout, and acts on what comes back.\n */\n\nexport interface GestureSample {\n x: number;\n y: number;\n /** ms */\n t: number;\n}\n\nexport type GestureAction =\n | { kind: \"tap\"; x: number; y: number }\n /** Positive = toward newer output (finger moved up). Whole lines only; the remainder is kept. */\n | { kind: \"scroll\"; lines: number }\n /** Finger lifted mid-scroll: continue with `flingStep` from this velocity (lines/ms, same sign as scroll). */\n | { kind: \"fling\"; velocity: number }\n | { kind: \"select-start\"; x: number; y: number }\n | { kind: \"select-extend\"; x: number; y: number }\n | { kind: \"select-end\" };\n\nexport interface GestureOptions {\n /** Row height in px (font size × line height). */\n lineHeight: number;\n /** Movement under this many px is still a tap / hold. */\n slopPx?: number;\n}\n\n/** Press-and-hold time before selection starts (iOS text selection is ~500 ms; terminals use less). */\nexport const LONG_PRESS_MS = 450;\n/** Momentum decay per 16 ms frame. */\nexport const FLING_FRICTION = 0.95;\n/** Below this (lines/ms) momentum stops. */\nexport const FLING_STOP = 0.002;\n/** Releases slower than this (lines/ms) do not fling. */\nconst FLING_MIN = 0.01;\n\ntype Phase = \"idle\" | \"pressed\" | \"scrolling\" | \"selecting\";\n\nexport interface GestureRecognizer {\n down(s: GestureSample): GestureAction[];\n move(s: GestureSample): GestureAction[];\n up(s: GestureSample): GestureAction[];\n cancel(): GestureAction[];\n /** The host's long-press timer fired (LONG_PRESS_MS after down). */\n longPress(): GestureAction[];\n readonly phase: Phase;\n}\n\nexport function createGestureRecognizer(options: GestureOptions): GestureRecognizer {\n const slop = options.slopPx ?? 8;\n const lineHeight = Math.max(1, options.lineHeight);\n let phase: Phase = \"idle\";\n let start: GestureSample = { x: 0, y: 0, t: 0 };\n let last: GestureSample = start;\n let carryPx = 0;\n /** Recent samples for release velocity. */\n let trail: GestureSample[] = [];\n\n function scrollBy(fromY: number, toY: number): GestureAction[] {\n carryPx += fromY - toY;\n const lines = carryPx > 0 ? Math.floor(carryPx / lineHeight) : Math.ceil(carryPx / lineHeight);\n if (lines === 0) return [];\n carryPx -= lines * lineHeight;\n return [{ kind: \"scroll\", lines }];\n }\n\n return {\n get phase() {\n return phase;\n },\n down(s) {\n phase = \"pressed\";\n start = s;\n last = s;\n carryPx = 0;\n trail = [s];\n return [];\n },\n move(s) {\n if (phase === \"idle\") return [];\n const out: GestureAction[] = [];\n if (phase === \"pressed\") {\n if (Math.hypot(s.x - start.x, s.y - start.y) <= slop) return [];\n phase = \"scrolling\";\n }\n if (phase === \"scrolling\") {\n out.push(...scrollBy(last.y, s.y));\n trail.push(s);\n while (trail.length > 2 && s.t - trail[0]!.t > 100) trail.shift();\n } else if (phase === \"selecting\") {\n out.push({ kind: \"select-extend\", x: s.x, y: s.y });\n }\n last = s;\n return out;\n },\n up(s) {\n const was = phase;\n phase = \"idle\";\n if (was === \"pressed\") return [{ kind: \"tap\", x: start.x, y: start.y }];\n if (was === \"selecting\") return [{ kind: \"select-end\" }];\n if (was === \"scrolling\") {\n const out = scrollBy(last.y, s.y);\n trail.push(s);\n const first = trail[0]!;\n const dt = s.t - first.t;\n const velocity = dt > 0 ? (first.y - s.y) / dt / lineHeight : 0;\n if (Math.abs(velocity) >= FLING_MIN) out.push({ kind: \"fling\", velocity });\n return out;\n }\n return [];\n },\n cancel() {\n const was = phase;\n phase = \"idle\";\n return was === \"selecting\" ? [{ kind: \"select-end\" }] : [];\n },\n longPress() {\n if (phase !== \"pressed\") return [];\n phase = \"selecting\";\n return [{ kind: \"select-start\", x: start.x, y: start.y }];\n },\n };\n}\n\n/**\n * One momentum frame: how far to move (lines, fractional) and the decayed velocity. The host\n * accumulates the fractional lines and scrolls whole ones until `velocity` is 0.\n */\nexport function flingStep(velocity: number, dtMs: number): { lines: number; velocity: number } {\n const lines = velocity * dtMs;\n const next = velocity * Math.pow(FLING_FRICTION, dtMs / 16);\n return { lines, velocity: Math.abs(next) < FLING_STOP ? 0 : next };\n}\n","/**\n * Long-press selection math in buffer cells. Pure; the React layer maps touch points to cells.\n */\n\nexport interface Cell {\n col: number;\n /** Absolute buffer row (scrollback included). */\n row: number;\n}\n\n/** Characters that belong to a \"word\" for a long press: paths, URLs, flags and hosts select whole. */\nconst WORD = /[A-Za-z0-9_\\-./~:@%+=,?&#]/;\n\n/** [start, end) of the word at `col` in `line`; a one-cell range on a separator. */\nexport function wordBounds(line: string, col: number): { start: number; end: number } {\n const chars = Array.from(line);\n if (col < 0 || col >= chars.length || !WORD.test(chars[col] ?? \" \")) return { start: col, end: col + 1 };\n let start = col;\n let end = col + 1;\n while (start > 0 && WORD.test(chars[start - 1]!)) start--;\n while (end < chars.length && WORD.test(chars[end]!)) end++;\n return { start, end };\n}\n\n/**\n * xterm's `select(column, row, length)` for the span between two cells (either order), where a\n * span wraps at `cols`. `anchor` is the first selected cell; `focus` is included too.\n */\nexport function spanBetween(anchor: Cell, focus: Cell, cols: number): { col: number; row: number; length: number } {\n const a = anchor.row * cols + anchor.col;\n const b = focus.row * cols + focus.col;\n const from = Math.min(a, b);\n const to = Math.max(a, b);\n return { col: from % cols, row: Math.floor(from / cols), length: to - from + 1 };\n}\n\n/** The cell under a point, given the screen element's box and the grid size; clamped to the grid. */\nexport function cellAt(\n point: { x: number; y: number },\n box: { left: number; top: number; width: number; height: number },\n grid: { cols: number; rows: number; viewportY: number },\n): Cell {\n const cw = box.width / Math.max(1, grid.cols);\n const ch = box.height / Math.max(1, grid.rows);\n const col = Math.min(grid.cols - 1, Math.max(0, Math.floor((point.x - box.left) / cw)));\n const screenRow = Math.min(grid.rows - 1, Math.max(0, Math.floor((point.y - box.top) / ch)));\n return { col, row: grid.viewportY + screenRow };\n}\n","/**\n * Terminal look: font, metrics and the two palettes. One place, so every terminal in every app\n * renders the same.\n */\nimport type { ITheme } from \"@xterm/xterm\";\n\n/** The system monospace first: SF Mono on Apple platforms, then the usual fallbacks. */\nexport const TERMINAL_FONT_FAMILY = 'ui-monospace, \"SF Mono\", SFMono-Regular, Menlo, Consolas, \"Liberation Mono\", monospace';\n\nexport const TERMINAL_DEFAULTS = {\n fontSize: 13,\n lineHeight: 1.2,\n scrollback: 5000,\n /** Side padding inside the terminal box, px. */\n padding: 8,\n} as const;\n\n/** The keyboard accessory bar's height, px (styles.css .mxt-bar: 44px keys + 4px above and below). */\nexport const ACCESSORY_BAR_HEIGHT = 52;\n\n/** The range a person can zoom the terminal text to (pinch, ⌘+ / ⌘−). */\nexport const FONT_SIZE_MIN = 9;\nexport const FONT_SIZE_MAX = 24;\n\n/** ⌘+ / ⌘− steps one point; the result stays in range. */\nexport function stepFontSize(current: number, delta: number): number {\n return Math.min(FONT_SIZE_MAX, Math.max(FONT_SIZE_MIN, Math.round(current) + delta));\n}\n\n/** A pinch scales the size it started from by the change in finger distance, to whole points. */\nexport function pinchFontSize(startSize: number, startDistance: number, distance: number): number {\n if (startDistance <= 0) return startSize;\n return Math.min(FONT_SIZE_MAX, Math.max(FONT_SIZE_MIN, Math.round((startSize * distance) / startDistance)));\n}\n\nexport function terminalTheme(dark: boolean): ITheme {\n return dark\n ? {\n background: \"#1e1e1e\",\n foreground: \"#e4e4e7\",\n cursor: \"#e4e4e7\",\n cursorAccent: \"#1e1e1e\",\n black: \"#1e1e1e\",\n red: \"#f87171\",\n green: \"#4ade80\",\n yellow: \"#facc15\",\n blue: \"#60a5fa\",\n magenta: \"#c084fc\",\n cyan: \"#22d3ee\",\n white: \"#e5e7eb\",\n brightBlack: \"#71717a\",\n brightRed: \"#fca5a5\",\n brightGreen: \"#86efac\",\n brightYellow: \"#fde047\",\n brightBlue: \"#93c5fd\",\n brightMagenta: \"#d8b4fe\",\n brightCyan: \"#67e8f9\",\n brightWhite: \"#f4f4f5\",\n selectionBackground: \"#3b82f680\",\n }\n : {\n background: \"#ffffff\",\n foreground: \"#18181b\",\n cursor: \"#18181b\",\n cursorAccent: \"#ffffff\",\n black: \"#18181b\",\n red: \"#b91c1c\",\n green: \"#15803d\",\n yellow: \"#b45309\",\n blue: \"#1d4ed8\",\n magenta: \"#7c3aed\",\n cyan: \"#0e7490\",\n white: \"#d4d4d8\",\n brightBlack: \"#71717a\",\n brightRed: \"#dc2626\",\n brightGreen: \"#16a34a\",\n brightYellow: \"#d97706\",\n brightBlue: \"#2563eb\",\n brightMagenta: \"#9333ea\",\n brightCyan: \"#0891b2\",\n brightWhite: \"#a1a1aa\",\n selectionBackground: \"#93c5fd99\",\n };\n}\n","/**\n * Visual-viewport arithmetic: where the on-screen keyboard is, and how tall a terminal anchored\n * at `top` may be so its last row and the accessory bar sit exactly above the keyboard. iOS\n * Safari shrinks only the VISUAL viewport when the keyboard opens; the layout viewport (and every\n * `100dvh`) stays full height, so a `bottom: 0` element ends up behind the keyboard.\n */\n\nexport interface ViewportBox {\n height: number;\n offsetTop: number;\n}\n\n/**\n * Below this the difference is browser chrome (Safari's collapsing toolbar), not a keyboard.\n * The smallest phone keyboard (iPhone SE landscape) is ~160px.\n */\nexport const KEYBOARD_MIN_PX = 120;\n\n/** Height the keyboard (or any bottom overlay) takes out of the layout viewport; 0 when closed. */\nexport function keyboardInset(layoutHeight: number, vv: ViewportBox | null): number {\n if (!vv) return 0;\n const inset = Math.round(layoutHeight - vv.height - vv.offsetTop);\n return inset >= KEYBOARD_MIN_PX ? inset : 0;\n}\n\n/** Height from `top` (layout px) down to the bottom of what is visible. Never negative. */\nexport function visibleHeightBelow(top: number, vv: ViewportBox | null, layoutHeight: number): number {\n const bottom = vv ? vv.offsetTop + vv.height : layoutHeight;\n return Math.max(0, Math.floor(bottom - top));\n}\n","\"use client\";\n\n/**\n * The keyboard accessory bar: one 44px row of the keys a phone keyboard lacks, scrolling\n * sideways. Every key keeps the terminal focused (pointerdown is cancelled), so the keyboard\n * stays up while you tap Esc, arrows or Ctrl. Ctrl / Alt: tap = next key only, double-tap = locked.\n */\nimport type { ReactNode } from \"react\";\n\nimport { ACCESSORY_KEYS } from \"../core/keys\";\nimport type { AccessoryKeyDef, AccessoryKeyId } from \"../core/keys\";\nimport type { ModifierState } from \"../core/modifiers\";\n\nfunction PasteIcon() {\n return (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <rect x=\"8\" y=\"2\" width=\"8\" height=\"4\" rx=\"1\" />\n <path d=\"M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2\" />\n </svg>\n );\n}\n\nfunction HideKeyboardIcon() {\n return (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <rect x=\"2\" y=\"3\" width=\"20\" height=\"12\" rx=\"2\" />\n <path d=\"M6 7h.01M10 7h.01M14 7h.01M18 7h.01M7 11h10\" />\n <path d=\"m8 19 4 3 4-3\" />\n </svg>\n );\n}\n\nconst ICONS: Partial<Record<AccessoryKeyId, () => ReactNode>> = { paste: PasteIcon, hide: HideKeyboardIcon };\n\nexport interface AccessoryBarProps {\n ctrl: ModifierState;\n alt: ModifierState;\n onKey: (id: AccessoryKeyId) => void;\n}\n\nexport function AccessoryBar({ ctrl, alt, onKey }: AccessoryBarProps) {\n const groups: AccessoryKeyDef[][] = [];\n for (const key of ACCESSORY_KEYS) (groups[key.group] ??= []).push(key);\n return (\n <div className=\"mxt-bar\" role=\"toolbar\" aria-label=\"Terminal keys\">\n {groups.map((group, gi) => (\n <div key={gi} className=\"mxt-bar-group\">\n {gi > 0 ? <span className=\"mxt-bar-divider\" aria-hidden=\"true\" /> : null}\n {group.map((key) => {\n const state = key.id === \"ctrl\" ? ctrl : key.id === \"alt\" ? alt : null;\n const Icon = ICONS[key.id];\n return (\n <button\n key={key.id}\n type=\"button\"\n className=\"mxt-key\"\n data-state={state ?? undefined}\n aria-label={key.aria}\n aria-pressed={state === null ? undefined : state !== \"off\"}\n // Keep focus (and the keyboard) on the terminal.\n onPointerDown={(e) => e.preventDefault()}\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => onKey(key.id)}\n >\n {Icon ? <Icon /> : key.label}\n </button>\n );\n })}\n </div>\n ))}\n </div>\n );\n}\n"],"mappings":"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","names":["import_jsx_runtime","current"]}
1
+ {"version":3,"sources":["../src/react.ts","../src/react/Terminal.tsx","../src/core/keys.ts","../src/core/modifiers.ts","../src/core/gesture.ts","../src/core/selection.ts","../src/core/theme.ts","../src/core/viewport.ts","../src/react/AccessoryBar.tsx"],"sourcesContent":["/**\n * @ai-matrx/terminal/react — <Terminal> (xterm 6 + fit + theme + phone touch + accessory bar)\n * and the bar on its own.\n */\nexport { Terminal } from \"./react/Terminal\";\nexport type { TerminalHandle, TerminalProps, TerminalSize } from \"./react/Terminal\";\nexport { AccessoryBar } from \"./react/AccessoryBar\";\nexport type { AccessoryBarProps } from \"./react/AccessoryBar\";\n","\"use client\";\n\n/**\n * <Terminal> — xterm 6 (DOM renderer) with everything a host would otherwise rebuild: fit to its\n * box or to the visual viewport, theme that follows the app's `.dark` class, Ctrl-C hook, phone\n * touch (momentum scroll, long-press word select, copy), and the keyboard accessory bar with\n * one-shot / locked Ctrl and Alt. Transport-free: bytes in through the handle's `write`, keys\n * out through `onData`, size out through `onResize`. Any PTY (desktop relay, cloud sandbox,\n * local process) plugs in with three lines.\n */\n// The package ships its stylesheets; importing them here means a host never forgets them. Both\n// stay as imports in the built bundle (tsup externals) for the host's bundler to place.\nimport \"@xterm/xterm/css/xterm.css\";\nimport \"@ai-matrx/terminal/styles.css\";\nimport { useEffect, useRef, useState } from \"react\";\nimport { copyText, readText } from \"@ai-matrx/kit/clipboard\";\nimport type { CSSProperties, ReactNode } from \"react\";\nimport type { ITerminalOptions, Terminal as XTerm } from \"@xterm/xterm\";\nimport type { FitAddon } from \"@xterm/addon-fit\";\n\nimport { ACCESSORY_KEYS, applyModifiers, keySequence } from \"../core/keys\";\nimport type { AccessoryKeyId } from \"../core/keys\";\nimport { MODIFIER_OFF, afterKey, isActive, tapModifier } from \"../core/modifiers\";\nimport type { ModifierLatch } from \"../core/modifiers\";\nimport { LONG_PRESS_MS, createGestureRecognizer, flingStep } from \"../core/gesture\";\nimport type { GestureAction } from \"../core/gesture\";\nimport { cellAt, spanBetween, wordBounds } from \"../core/selection\";\nimport type { Cell } from \"../core/selection\";\nimport { TERMINAL_DEFAULTS, TERMINAL_FONT_FAMILY, pinchFontSize, stepFontSize, terminalTheme } from \"../core/theme\";\nimport { visibleHeightBelow } from \"../core/viewport\";\nimport { AccessoryBar } from \"./AccessoryBar\";\n\nexport interface TerminalSize {\n cols: number;\n rows: number;\n}\n\n/** What a host drives the terminal with. Stable for the terminal's life. */\nexport interface TerminalHandle {\n /** Write output; resolves once xterm has parsed it (use it to pace credit-based streams). */\n write(data: string | Uint8Array): Promise<void>;\n /** Clear screen, scrollback and modes — before writing a fresh screen snapshot. */\n reset(): void;\n /** Clear the scrollback, keep the prompt line. */\n clear(): void;\n focus(): void;\n blur(): void;\n /** Visible text of the whole buffer (scrollback included), lines joined with \\n. */\n getText(): string;\n readonly cols: number;\n readonly rows: number;\n /** The underlying xterm, for what this package does not wrap (read-mostly use). */\n readonly xterm: XTerm;\n}\n\nexport interface TerminalProps {\n /** Keystrokes and pastes, already modified by the accessory bar's Ctrl / Alt. */\n onData?: (data: string) => void;\n /** Grid size after every fit (and once at start). */\n onResize?: (size: TerminalSize) => void;\n /**\n * The person zoomed the text: a pinch on touch, ⌘+ / ⌘− / ⌘0 with a keyboard. Pass it (and feed\n * the value back as `fontSize`) to turn zoom on; the host decides where the size is remembered.\n */\n onFontSizeChange?: (fontSize: number) => void;\n onReady?: (handle: TerminalHandle) => void;\n /**\n * Hardware Ctrl-C (no Shift/Alt/Meta). Return true to consume it — e.g. send a SIGINT frame\n * because the page's own shortcuts eat the key. Default: xterm sends ETX (0x03) through onData.\n */\n onInterrupt?: () => boolean;\n /** \"auto\" follows the `dark` class on <html>. */\n theme?: \"auto\" | \"dark\" | \"light\";\n fontSize?: number;\n lineHeight?: number;\n scrollback?: number;\n /** Side padding, px. */\n padding?: number;\n /** Translate bare \\n to \\r\\n (for line-oriented output that is not a PTY). */\n convertEol?: boolean;\n cursorBlink?: boolean;\n disableStdin?: boolean;\n /** Clickable URLs. Default true. */\n links?: boolean;\n /** Phone touch gestures. \"auto\" = when the primary pointer is coarse. */\n touch?: \"auto\" | \"on\" | \"off\";\n /** The keyboard accessory bar. \"auto\" = when the primary pointer is coarse. */\n accessory?: \"auto\" | \"on\" | \"off\";\n /**\n * \"container\": fill the parent box (it must have a height). \"viewport\": grow from where the\n * terminal starts down to the bottom of the VISUAL viewport, so the last row and the accessory\n * bar sit right above the on-screen keyboard.\n */\n fit?: \"container\" | \"viewport\";\n autoFocus?: boolean;\n className?: string;\n style?: CSSProperties;\n \"aria-label\"?: string;\n /** Rendered over the terminal (e.g. a reconnecting veil). */\n children?: ReactNode;\n}\n\ninterface Latches {\n ctrl: ModifierLatch;\n alt: ModifierLatch;\n}\n\nfunction prefersDark(): boolean {\n return typeof document !== \"undefined\" && document.documentElement.classList.contains(\"dark\");\n}\n\nfunction coarsePointer(): boolean {\n return typeof window !== \"undefined\" && typeof window.matchMedia === \"function\" && window.matchMedia(\"(pointer: coarse)\").matches;\n}\n\nexport function Terminal(props: TerminalProps) {\n const {\n theme = \"auto\",\n fontSize = TERMINAL_DEFAULTS.fontSize,\n lineHeight = TERMINAL_DEFAULTS.lineHeight,\n scrollback = TERMINAL_DEFAULTS.scrollback,\n padding = TERMINAL_DEFAULTS.padding,\n convertEol = false,\n cursorBlink = true,\n disableStdin = false,\n links = true,\n touch = \"auto\",\n accessory = \"auto\",\n fit = \"container\",\n autoFocus = false,\n } = props;\n\n const rootRef = useRef<HTMLDivElement | null>(null);\n const hostRef = useRef<HTMLDivElement | null>(null);\n const termRef = useRef<XTerm | null>(null);\n const fitRef = useRef<FitAddon | null>(null);\n const handleRef = useRef<TerminalHandle | null>(null);\n const latchRef = useRef<Latches>({ ctrl: MODIFIER_OFF, alt: MODIFIER_OFF });\n const callbacksRef = useRef({\n onData: props.onData,\n onResize: props.onResize,\n onReady: props.onReady,\n onInterrupt: props.onInterrupt,\n onFontSizeChange: props.onFontSizeChange,\n });\n const fontSizeRef = useRef(fontSize);\n\n const [latches, setLatches] = useState<Latches>({ ctrl: MODIFIER_OFF, alt: MODIFIER_OFF });\n const [coarse, setCoarse] = useState(false);\n const [dark, setDark] = useState(theme === \"dark\");\n const [copyVisible, setCopyVisible] = useState(false);\n const [viewportHeight, setViewportHeight] = useState<number | null>(null);\n const [booted, setBooted] = useState(false);\n\n useEffect(() => {\n callbacksRef.current = {\n onData: props.onData,\n onResize: props.onResize,\n onReady: props.onReady,\n onInterrupt: props.onInterrupt,\n onFontSizeChange: props.onFontSizeChange,\n };\n fontSizeRef.current = fontSize;\n });\n\n // Pointer class and theme are browser facts: read after mount (SSR renders the neutral frame).\n useEffect(() => {\n setCoarse(coarsePointer());\n const mq = typeof window.matchMedia === \"function\" ? window.matchMedia(\"(pointer: coarse)\") : null;\n const onChange = () => setCoarse(coarsePointer());\n mq?.addEventListener(\"change\", onChange);\n return () => mq?.removeEventListener(\"change\", onChange);\n }, []);\n\n useEffect(() => {\n if (theme !== \"auto\") {\n setDark(theme === \"dark\");\n return undefined;\n }\n setDark(prefersDark());\n if (typeof MutationObserver === \"undefined\") return undefined;\n const observer = new MutationObserver(() => setDark(prefersDark()));\n observer.observe(document.documentElement, { attributes: true, attributeFilter: [\"class\"] });\n return () => observer.disconnect();\n }, [theme]);\n\n const touchOn = touch === \"on\" || (touch === \"auto\" && coarse);\n const barOn = accessory === \"on\" || (accessory === \"auto\" && coarse);\n\n function setLatchState(next: Latches): void {\n latchRef.current = next;\n setLatches(next);\n }\n\n /** Keyboard input → accessory modifiers → host. */\n function emit(data: string): void {\n const current = latchRef.current;\n const mods = { ctrl: isActive(current.ctrl), alt: isActive(current.alt) };\n const { data: out, consumed } = applyModifiers(data, mods);\n if (consumed) setLatchState({ ctrl: afterKey(current.ctrl), alt: afterKey(current.alt) });\n callbacksRef.current.onData?.(out);\n }\n\n // ── boot xterm once ───────────────────────────────────────────────────────\n useEffect(() => {\n let cancelled = false;\n let disposeAll: (() => void) | null = null;\n void (async () => {\n const [{ Terminal: XTermCtor }, { FitAddon: FitCtor }, linksModule] = await Promise.all([\n import(\"@xterm/xterm\"),\n import(\"@xterm/addon-fit\"),\n import(\"@xterm/addon-web-links\"),\n ]);\n const host = hostRef.current;\n if (cancelled || !host) return;\n const options: ITerminalOptions = {\n fontFamily: TERMINAL_FONT_FAMILY,\n fontSize,\n lineHeight,\n scrollback,\n convertEol,\n cursorBlink,\n cursorStyle: \"bar\",\n disableStdin,\n allowProposedApi: false,\n theme: terminalTheme(theme === \"auto\" ? prefersDark() : theme === \"dark\"),\n };\n const term = new XTermCtor(options);\n const fitAddon = new FitCtor();\n term.loadAddon(fitAddon);\n if (links) term.loadAddon(new linksModule.WebLinksAddon());\n term.open(host);\n const textarea = term.textarea;\n if (textarea) {\n // iOS: no autocorrect/capitalisation in a shell; 16px stops the focus zoom (styles.css).\n textarea.setAttribute(\"autocorrect\", \"off\");\n textarea.setAttribute(\"autocapitalize\", \"off\");\n textarea.setAttribute(\"autocomplete\", \"off\");\n textarea.setAttribute(\"spellcheck\", \"false\");\n textarea.setAttribute(\"aria-label\", props[\"aria-label\"] ?? \"Terminal input\");\n }\n termRef.current = term;\n fitRef.current = fitAddon;\n\n const dataSub = term.onData((data) => emit(data));\n const resizeSub = term.onResize(({ cols, rows }) => callbacksRef.current.onResize?.({ cols, rows }));\n term.attachCustomKeyEventHandler((event) => {\n // ⌘+ / ⌘− / ⌘0 zoom the text (only when the host takes the size: onFontSizeChange).\n const zoom = callbacksRef.current.onFontSizeChange;\n if (zoom && event.type === \"keydown\" && event.metaKey && !event.altKey && !event.ctrlKey) {\n const delta = event.key === \"=\" || event.key === \"+\" ? 1 : event.key === \"-\" ? -1 : event.key === \"0\" ? 0 : null;\n if (delta !== null) {\n event.preventDefault();\n zoom(delta === 0 ? TERMINAL_DEFAULTS.fontSize : stepFontSize(fontSizeRef.current, delta));\n return false;\n }\n }\n if (\n event.type === \"keydown\" &&\n event.ctrlKey &&\n !event.shiftKey &&\n !event.altKey &&\n !event.metaKey &&\n event.key.toLowerCase() === \"c\" &&\n !term.hasSelection()\n ) {\n const consumed = callbacksRef.current.onInterrupt?.() ?? false;\n if (consumed) return false;\n }\n return true;\n });\n const selectionSub = term.onSelectionChange(() => setCopyVisible(term.hasSelection()));\n\n const handle: TerminalHandle = {\n write: (data) => new Promise<void>((resolve) => term.write(data, resolve)),\n reset: () => term.reset(),\n clear: () => term.clear(),\n focus: () => term.focus(),\n blur: () => term.blur(),\n getText: () => {\n const buffer = term.buffer.active;\n const lines: string[] = [];\n for (let y = 0; y < buffer.length; y++) lines.push(buffer.getLine(y)?.translateToString(true) ?? \"\");\n while (lines.length > 0 && lines[lines.length - 1] === \"\") lines.pop();\n return lines.join(\"\\n\");\n },\n get cols() {\n return term.cols;\n },\n get rows() {\n return term.rows;\n },\n xterm: term,\n };\n handleRef.current = handle;\n try {\n fitAddon.fit();\n } catch {\n // The box may not be laid out yet; the resize observer fits it when it is.\n }\n setBooted(true);\n callbacksRef.current.onResize?.({ cols: term.cols, rows: term.rows });\n callbacksRef.current.onReady?.(handle);\n if (autoFocus) term.focus();\n\n disposeAll = () => {\n dataSub.dispose();\n resizeSub.dispose();\n selectionSub.dispose();\n term.dispose();\n };\n })();\n return () => {\n cancelled = true;\n disposeAll?.();\n termRef.current = null;\n fitRef.current = null;\n handleRef.current = null;\n };\n // Boot exactly once per mount; later option changes are applied by the effects below.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // ── live options ──────────────────────────────────────────────────────────\n useEffect(() => {\n const term = termRef.current;\n if (!term) return;\n term.options.theme = terminalTheme(dark);\n }, [dark, booted]);\n\n useEffect(() => {\n const term = termRef.current;\n if (!term) return;\n term.options.disableStdin = disableStdin;\n term.options.fontSize = fontSize;\n term.options.lineHeight = lineHeight;\n try {\n fitRef.current?.fit();\n } catch {\n // between frames\n }\n }, [disableStdin, fontSize, lineHeight, booted]);\n\n // ── fit to the box ────────────────────────────────────────────────────────\n useEffect(() => {\n const host = hostRef.current;\n if (!host) return undefined;\n const refit = () => {\n const term = termRef.current;\n if (!term || host.clientWidth <= 0 || host.clientHeight <= 0) return;\n try {\n fitRef.current?.fit();\n // A DOM renderer mounted while hidden measured zero-width glyphs; refresh re-measures.\n term.refresh(0, term.rows - 1);\n } catch {\n // xterm is mid-paint\n }\n };\n refit();\n if (typeof ResizeObserver === \"undefined\") return undefined; // non-browser hosts (jsdom)\n const ro = new ResizeObserver(refit);\n ro.observe(host);\n return () => ro.disconnect();\n }, [booted]);\n\n // ── fit to the visual viewport (phones: stop exactly at the keyboard) ─────\n useEffect(() => {\n if (fit !== \"viewport\") {\n setViewportHeight(null);\n return undefined;\n }\n const root = rootRef.current;\n if (!root) return undefined;\n const vv = window.visualViewport;\n const measure = () => {\n // The console owns the screen: a page scrolled by iOS to \"reveal\" the input only hides the top.\n if (window.scrollY !== 0) window.scrollTo(0, 0);\n const top = root.getBoundingClientRect().top + window.scrollY;\n setViewportHeight(visibleHeightBelow(top, vv ? { height: vv.height, offsetTop: vv.offsetTop } : null, window.innerHeight));\n };\n measure();\n vv?.addEventListener(\"resize\", measure);\n vv?.addEventListener(\"scroll\", measure);\n window.addEventListener(\"resize\", measure);\n window.addEventListener(\"orientationchange\", measure);\n return () => {\n vv?.removeEventListener(\"resize\", measure);\n vv?.removeEventListener(\"scroll\", measure);\n window.removeEventListener(\"resize\", measure);\n window.removeEventListener(\"orientationchange\", measure);\n };\n }, [fit]);\n\n // ── touch: tap focuses, drag scrolls with momentum, hold selects ──────────\n useEffect(() => {\n const host = hostRef.current;\n const term = termRef.current;\n if (!touchOn || !host || !term) return undefined;\n // Re-created at each touch so a zoom (pinch, ⌘±) is already in the row height it scrolls by.\n let recognizer = createGestureRecognizer({ lineHeight: fontSizeRef.current * lineHeight });\n let holdTimer: ReturnType<typeof setTimeout> | null = null;\n let flingFrame: number | null = null;\n let flingCarry = 0;\n let anchor: Cell | null = null;\n\n const screen = () => (term.element?.querySelector(\".xterm-screen\") as HTMLElement | null) ?? host;\n const cellFor = (x: number, y: number): Cell => {\n const r = screen().getBoundingClientRect();\n return cellAt({ x, y }, { left: r.left, top: r.top, width: r.width, height: r.height }, { cols: term.cols, rows: term.rows, viewportY: term.buffer.active.viewportY });\n };\n const scrollLines = (lines: number) => {\n if (lines === 0) return;\n if (term.buffer.active.type === \"alternate\") {\n // Full-screen programs (less, vim, htop) own their screen: a drag pages them with arrows.\n const key = lines > 0 ? \"down\" : \"up\";\n const seq = keySequence(key, { ctrl: false, alt: false }, { applicationCursor: term.modes.applicationCursorKeysMode });\n if (seq) callbacksRef.current.onData?.(seq.repeat(Math.min(Math.abs(lines), 50)));\n return;\n }\n term.scrollLines(lines);\n };\n const stopFling = () => {\n if (flingFrame !== null) cancelAnimationFrame(flingFrame);\n flingFrame = null;\n flingCarry = 0;\n };\n const startFling = (velocity: number) => {\n stopFling();\n let v = velocity;\n let last = performance.now();\n const step = (now: number) => {\n const res = flingStep(v, now - last);\n last = now;\n v = res.velocity;\n flingCarry += res.lines;\n const whole = flingCarry > 0 ? Math.floor(flingCarry) : Math.ceil(flingCarry);\n if (whole !== 0) {\n flingCarry -= whole;\n scrollLines(whole);\n }\n flingFrame = v === 0 ? null : requestAnimationFrame(step);\n };\n flingFrame = requestAnimationFrame(step);\n };\n const act = (actions: GestureAction[]) => {\n for (const a of actions) {\n switch (a.kind) {\n case \"tap\":\n term.clearSelection();\n term.focus();\n break;\n case \"scroll\":\n scrollLines(a.lines);\n break;\n case \"fling\":\n startFling(a.velocity);\n break;\n case \"select-start\": {\n const cell = cellFor(a.x, a.y);\n const line = term.buffer.active.getLine(cell.row)?.translateToString(false) ?? \"\";\n const word = wordBounds(line, cell.col);\n anchor = { col: word.start, row: cell.row };\n term.select(word.start, cell.row, Math.max(1, word.end - word.start));\n navigator.vibrate?.(10);\n break;\n }\n case \"select-extend\": {\n if (!anchor) break;\n const span = spanBetween(anchor, cellFor(a.x, a.y), term.cols);\n term.select(span.col, span.row, span.length);\n break;\n }\n case \"select-end\":\n anchor = null;\n setCopyVisible(term.hasSelection());\n break;\n }\n }\n };\n const clearHold = () => {\n if (holdTimer !== null) clearTimeout(holdTimer);\n holdTimer = null;\n };\n /** Two fingers: pinch-zoom the TEXT (when the host takes the size), never the page. */\n let pinch: { startDistance: number; startSize: number } | null = null;\n const fingerDistance = (e: TouchEvent) => {\n const a = e.touches[0]!;\n const b = e.touches[1]!;\n return Math.hypot(a.clientX - b.clientX, a.clientY - b.clientY);\n };\n const onStart = (e: TouchEvent) => {\n if (e.touches.length === 2 && callbacksRef.current.onFontSizeChange) {\n e.preventDefault();\n clearHold();\n stopFling();\n act(recognizer.cancel());\n pinch = { startDistance: fingerDistance(e), startSize: fontSizeRef.current };\n return;\n }\n if (e.touches.length !== 1) {\n clearHold();\n act(recognizer.cancel());\n return; // more fingers, or no zoom wanted: leave it to the browser\n }\n const t = e.touches[0]!;\n e.preventDefault();\n stopFling();\n recognizer = createGestureRecognizer({ lineHeight: fontSizeRef.current * lineHeight });\n act(recognizer.down({ x: t.clientX, y: t.clientY, t: e.timeStamp }));\n clearHold();\n holdTimer = setTimeout(() => act(recognizer.longPress()), LONG_PRESS_MS);\n };\n const onMove = (e: TouchEvent) => {\n if (pinch && e.touches.length === 2) {\n e.preventDefault();\n const size = pinchFontSize(pinch.startSize, pinch.startDistance, fingerDistance(e));\n if (size !== fontSizeRef.current) {\n fontSizeRef.current = size;\n callbacksRef.current.onFontSizeChange?.(size);\n }\n return;\n }\n if (e.touches.length !== 1 || recognizer.phase === \"idle\") return;\n const t = e.touches[0]!;\n e.preventDefault();\n act(recognizer.move({ x: t.clientX, y: t.clientY, t: e.timeStamp }));\n if (recognizer.phase !== \"pressed\") clearHold();\n };\n const onEnd = (e: TouchEvent) => {\n if (pinch) {\n if (e.touches.length < 2) pinch = null;\n e.preventDefault();\n return;\n }\n clearHold();\n if (recognizer.phase === \"idle\") return;\n const t = e.changedTouches[0];\n e.preventDefault();\n act(recognizer.up({ x: t?.clientX ?? 0, y: t?.clientY ?? 0, t: e.timeStamp }));\n };\n const onCancel = () => {\n clearHold();\n act(recognizer.cancel());\n };\n host.addEventListener(\"touchstart\", onStart, { passive: false });\n host.addEventListener(\"touchmove\", onMove, { passive: false });\n host.addEventListener(\"touchend\", onEnd, { passive: false });\n host.addEventListener(\"touchcancel\", onCancel);\n return () => {\n clearHold();\n stopFling();\n host.removeEventListener(\"touchstart\", onStart);\n host.removeEventListener(\"touchmove\", onMove);\n host.removeEventListener(\"touchend\", onEnd);\n host.removeEventListener(\"touchcancel\", onCancel);\n };\n }, [touchOn, booted, lineHeight]);\n\n // ── accessory bar ─────────────────────────────────────────────────────────\n function onAccessoryKey(id: AccessoryKeyId): void {\n const term = termRef.current;\n if (!term) return;\n const def = ACCESSORY_KEYS.find((k) => k.id === id);\n if (!def) return;\n if (def.kind === \"modifier\") {\n const now = performance.now();\n const current = latchRef.current;\n setLatchState(id === \"ctrl\" ? { ...current, ctrl: tapModifier(current.ctrl, now) } : { ...current, alt: tapModifier(current.alt, now) });\n return;\n }\n if (id === \"hide\") {\n term.blur();\n term.textarea?.blur();\n return;\n }\n if (id === \"paste\") {\n // null = permission refused / unsupported: the system paste menu still works on the input.\n void readText().then((text) => {\n if (text) term.paste(text);\n });\n return;\n }\n const current = latchRef.current;\n const mods = { ctrl: isActive(current.ctrl), alt: isActive(current.alt) };\n const seq = keySequence(id, mods, { applicationCursor: term.modes.applicationCursorKeysMode });\n if (seq === null) return;\n if (mods.ctrl || mods.alt) setLatchState({ ctrl: afterKey(current.ctrl), alt: afterKey(current.alt) });\n callbacksRef.current.onData?.(seq);\n }\n\n function copySelection(): void {\n const term = termRef.current;\n if (!term) return;\n const text = term.getSelection();\n if (text) void copyText(text);\n term.clearSelection();\n setCopyVisible(false);\n }\n\n const rootStyle: CSSProperties = { ...props.style };\n if (viewportHeight !== null) rootStyle.height = viewportHeight;\n\n return (\n <div\n ref={rootRef}\n className={[\"mxt-root\", props.className].filter(Boolean).join(\" \")}\n style={rootStyle}\n data-touch={touchOn ? \"on\" : \"off\"}\n data-theme={dark ? \"dark\" : \"light\"}\n >\n <div className=\"mxt-frame\" style={{ background: terminalTheme(dark).background }}>\n <div ref={hostRef} className=\"mxt-host\" style={{ paddingLeft: padding, paddingRight: padding }} />\n {copyVisible ? (\n <button type=\"button\" className=\"mxt-copy\" onPointerDown={(e) => e.preventDefault()} onClick={copySelection}>\n Copy\n </button>\n ) : null}\n {props.children}\n </div>\n {barOn ? <AccessoryBar ctrl={latches.ctrl.state} alt={latches.alt.state} onKey={onAccessoryKey} /> : null}\n </div>\n );\n}\n","/**\n * The keyboard accessory bar's keys and the bytes each sends — the keys a phone keyboard lacks.\n * Pure: no DOM, no xterm. Sequences follow xterm's own encoding (CSI 1;<mod> for modified cursor\n * keys, SS3 in application cursor mode), so full-screen programs (vim, less, htop) read them\n * exactly as they read a desktop keyboard.\n */\n\nexport type AccessoryKeyId =\n | \"esc\"\n | \"tab\"\n | \"ctrl\"\n | \"alt\"\n | \"left\"\n | \"down\"\n | \"up\"\n | \"right\"\n | \"pipe\"\n | \"slash\"\n | \"tilde\"\n | \"dash\"\n | \"home\"\n | \"end\"\n | \"pgup\"\n | \"pgdn\"\n | \"paste\"\n | \"hide\";\n\nexport interface AccessoryKeyDef {\n id: AccessoryKeyId;\n /** What the key shows. */\n label: string;\n /** What a screen reader says. */\n aria: string;\n /** send = bytes to the PTY; modifier = Ctrl/Alt state; action = paste / hide keyboard. */\n kind: \"send\" | \"modifier\" | \"action\";\n /** Keys sharing a group sit together; a divider separates groups. */\n group: number;\n}\n\n/** Termius order: Esc Tab Ctrl Alt | ← ↓ ↑ → | | / ~ - | Home End PgUp PgDn | Paste, hide. */\nexport const ACCESSORY_KEYS: readonly AccessoryKeyDef[] = [\n { id: \"esc\", label: \"Esc\", aria: \"Escape\", kind: \"send\", group: 0 },\n { id: \"tab\", label: \"Tab\", aria: \"Tab\", kind: \"send\", group: 0 },\n { id: \"ctrl\", label: \"Ctrl\", aria: \"Control\", kind: \"modifier\", group: 0 },\n { id: \"alt\", label: \"Alt\", aria: \"Alt\", kind: \"modifier\", group: 0 },\n { id: \"left\", label: \"←\", aria: \"Left arrow\", kind: \"send\", group: 1 },\n { id: \"down\", label: \"↓\", aria: \"Down arrow\", kind: \"send\", group: 1 },\n { id: \"up\", label: \"↑\", aria: \"Up arrow\", kind: \"send\", group: 1 },\n { id: \"right\", label: \"→\", aria: \"Right arrow\", kind: \"send\", group: 1 },\n { id: \"pipe\", label: \"|\", aria: \"Pipe\", kind: \"send\", group: 2 },\n { id: \"slash\", label: \"/\", aria: \"Slash\", kind: \"send\", group: 2 },\n { id: \"tilde\", label: \"~\", aria: \"Tilde\", kind: \"send\", group: 2 },\n { id: \"dash\", label: \"-\", aria: \"Dash\", kind: \"send\", group: 2 },\n { id: \"home\", label: \"Home\", aria: \"Home\", kind: \"send\", group: 3 },\n { id: \"end\", label: \"End\", aria: \"End\", kind: \"send\", group: 3 },\n { id: \"pgup\", label: \"PgUp\", aria: \"Page up\", kind: \"send\", group: 3 },\n { id: \"pgdn\", label: \"PgDn\", aria: \"Page down\", kind: \"send\", group: 3 },\n { id: \"paste\", label: \"Paste\", aria: \"Paste\", kind: \"action\", group: 4 },\n { id: \"hide\", label: \"Hide\", aria: \"Hide keyboard\", kind: \"action\", group: 4 },\n];\n\nexport interface ActiveModifiers {\n ctrl: boolean;\n alt: boolean;\n}\n\nexport interface KeyModes {\n /** DECCKM — xterm's `modes.applicationCursorKeysMode`. */\n applicationCursor: boolean;\n}\n\nconst ESC = \"\\x1b\";\nconst CURSOR: Partial<Record<AccessoryKeyId, string>> = { up: \"A\", down: \"B\", right: \"C\", left: \"D\", home: \"H\", end: \"F\" };\nconst TILDE: Partial<Record<AccessoryKeyId, string>> = { pgup: \"5\", pgdn: \"6\" };\nconst LITERAL: Partial<Record<AccessoryKeyId, string>> = { pipe: \"|\", slash: \"/\", tilde: \"~\", dash: \"-\", tab: \"\\t\", esc: ESC };\n\n/** xterm's modifier parameter: 1 + shift(1) + alt(2) + ctrl(4). */\nfunction modParam(mods: ActiveModifiers): number {\n return 1 + (mods.alt ? 2 : 0) + (mods.ctrl ? 4 : 0);\n}\n\n/**\n * Bytes for a \"send\" key with the active modifiers applied, or null for a modifier/action key.\n * Modifiers on literal keys go through `applyModifiers` (Ctrl+/ → 0x1f, Alt+| → ESC |).\n */\nexport function keySequence(id: AccessoryKeyId, mods: ActiveModifiers, modes: KeyModes): string | null {\n const cursor = CURSOR[id];\n if (cursor !== undefined) {\n const m = modParam(mods);\n if (m > 1) return `${ESC}[1;${m}${cursor}`;\n return modes.applicationCursor ? `${ESC}O${cursor}` : `${ESC}[${cursor}`;\n }\n const tilde = TILDE[id];\n if (tilde !== undefined) {\n const m = modParam(mods);\n return m > 1 ? `${ESC}[${tilde};${m}~` : `${ESC}[${tilde}~`;\n }\n const literal = LITERAL[id];\n if (literal !== undefined) {\n if (id === \"tab\" && mods.ctrl === false && mods.alt === false) return literal;\n if (id === \"esc\") return mods.alt ? ESC + ESC : ESC;\n return applyModifiers(literal, mods).data;\n }\n return null;\n}\n\n/** Ctrl applied to one character, as a terminal keyboard encodes it; null when Ctrl has no code. */\nexport function controlCode(char: string): string | null {\n if (char.length !== 1) return null;\n const code = char.charCodeAt(0);\n if (code >= 0x61 && code <= 0x7a) return String.fromCharCode(code - 0x60); // a-z\n if (code >= 0x40 && code <= 0x5f) return String.fromCharCode(code - 0x40); // @ A-Z [ \\ ] ^ _\n switch (char) {\n case \" \":\n case \"2\":\n return \"\\x00\";\n case \"3\":\n return \"\\x1b\";\n case \"4\":\n return \"\\x1c\";\n case \"5\":\n return \"\\x1d\";\n case \"6\":\n return \"\\x1e\";\n case \"7\":\n case \"/\":\n case \"-\":\n return \"\\x1f\";\n case \"8\":\n case \"?\":\n return \"\\x7f\";\n default:\n return null;\n }\n}\n\n/**\n * Apply one-shot or locked modifiers to what the keyboard typed. Only a single key press is\n * modified — a paste or a multi-character IME commit passes through and does NOT consume the\n * modifier, so \"Ctrl, then paste\" never mangles the paste.\n */\nexport function applyModifiers(data: string, mods: ActiveModifiers): { data: string; consumed: boolean } {\n if (!mods.ctrl && !mods.alt) return { data, consumed: false };\n const chars = Array.from(data);\n if (chars.length !== 1) {\n // A cursor key typed on a hardware keyboard while Ctrl/Alt are latched: re-encode it.\n const m = /^\\x1b(?:\\[|O)([ABCDHF])$/.exec(data);\n if (m) return { data: `${ESC}[1;${modParam(mods)}${m[1]}`, consumed: true };\n return { data, consumed: false };\n }\n let out = data;\n if (mods.ctrl) {\n const ctl = controlCode(data);\n if (ctl !== null) out = ctl;\n }\n if (mods.alt) out = ESC + out;\n return { data: out, consumed: true };\n}\n","/**\n * Ctrl / Alt on the accessory bar: tap once = the next key only; tap twice quickly = locked until\n * tapped again. Pure state machine; the clock is passed in.\n */\n\nexport type ModifierState = \"off\" | \"once\" | \"locked\";\n\nexport interface ModifierLatch {\n state: ModifierState;\n /** When the latch was last tapped (ms), for double-tap detection. */\n tappedAt: number | null;\n}\n\n/** Two taps within this window lock the modifier (iOS's own double-tap timing for Shift lock). */\nexport const DOUBLE_TAP_MS = 350;\n\nexport const MODIFIER_OFF: ModifierLatch = { state: \"off\", tappedAt: null };\n\nexport function tapModifier(latch: ModifierLatch, now: number): ModifierLatch {\n switch (latch.state) {\n case \"off\":\n return { state: \"once\", tappedAt: now };\n case \"once\":\n return latch.tappedAt !== null && now - latch.tappedAt <= DOUBLE_TAP_MS\n ? { state: \"locked\", tappedAt: now }\n : { state: \"off\", tappedAt: now };\n case \"locked\":\n return { state: \"off\", tappedAt: now };\n }\n}\n\n/** After a key used the modifier: a one-shot latch releases, a locked one holds. */\nexport function afterKey(latch: ModifierLatch): ModifierLatch {\n return latch.state === \"once\" ? { state: \"off\", tappedAt: latch.tappedAt } : latch;\n}\n\nexport function isActive(latch: ModifierLatch): boolean {\n return latch.state !== \"off\";\n}\n","/**\n * One-finger gestures on a terminal, as iOS terminals (Termius, Blink) read them:\n *\n * tap → focus (opens the keyboard)\n * drag up / down → scroll the scrollback, by whole lines, with momentum on release\n * press and hold, no move → select the word under the finger; keep dragging to extend\n *\n * Pure: the host feeds pointer samples and the long-press timeout, and acts on what comes back.\n */\n\nexport interface GestureSample {\n x: number;\n y: number;\n /** ms */\n t: number;\n}\n\nexport type GestureAction =\n | { kind: \"tap\"; x: number; y: number }\n /** Positive = toward newer output (finger moved up). Whole lines only; the remainder is kept. */\n | { kind: \"scroll\"; lines: number }\n /** Finger lifted mid-scroll: continue with `flingStep` from this velocity (lines/ms, same sign as scroll). */\n | { kind: \"fling\"; velocity: number }\n | { kind: \"select-start\"; x: number; y: number }\n | { kind: \"select-extend\"; x: number; y: number }\n | { kind: \"select-end\" };\n\nexport interface GestureOptions {\n /** Row height in px (font size × line height). */\n lineHeight: number;\n /** Movement under this many px is still a tap / hold. */\n slopPx?: number;\n}\n\n/** Press-and-hold time before selection starts (iOS text selection is ~500 ms; terminals use less). */\nexport const LONG_PRESS_MS = 450;\n/** Momentum decay per 16 ms frame. */\nexport const FLING_FRICTION = 0.95;\n/** Below this (lines/ms) momentum stops. */\nexport const FLING_STOP = 0.002;\n/** Releases slower than this (lines/ms) do not fling. */\nconst FLING_MIN = 0.01;\n\ntype Phase = \"idle\" | \"pressed\" | \"scrolling\" | \"selecting\";\n\nexport interface GestureRecognizer {\n down(s: GestureSample): GestureAction[];\n move(s: GestureSample): GestureAction[];\n up(s: GestureSample): GestureAction[];\n cancel(): GestureAction[];\n /** The host's long-press timer fired (LONG_PRESS_MS after down). */\n longPress(): GestureAction[];\n readonly phase: Phase;\n}\n\nexport function createGestureRecognizer(options: GestureOptions): GestureRecognizer {\n const slop = options.slopPx ?? 8;\n const lineHeight = Math.max(1, options.lineHeight);\n let phase: Phase = \"idle\";\n let start: GestureSample = { x: 0, y: 0, t: 0 };\n let last: GestureSample = start;\n let carryPx = 0;\n /** Recent samples for release velocity. */\n let trail: GestureSample[] = [];\n\n function scrollBy(fromY: number, toY: number): GestureAction[] {\n carryPx += fromY - toY;\n const lines = carryPx > 0 ? Math.floor(carryPx / lineHeight) : Math.ceil(carryPx / lineHeight);\n if (lines === 0) return [];\n carryPx -= lines * lineHeight;\n return [{ kind: \"scroll\", lines }];\n }\n\n return {\n get phase() {\n return phase;\n },\n down(s) {\n phase = \"pressed\";\n start = s;\n last = s;\n carryPx = 0;\n trail = [s];\n return [];\n },\n move(s) {\n if (phase === \"idle\") return [];\n const out: GestureAction[] = [];\n if (phase === \"pressed\") {\n if (Math.hypot(s.x - start.x, s.y - start.y) <= slop) return [];\n phase = \"scrolling\";\n }\n if (phase === \"scrolling\") {\n out.push(...scrollBy(last.y, s.y));\n trail.push(s);\n while (trail.length > 2 && s.t - trail[0]!.t > 100) trail.shift();\n } else if (phase === \"selecting\") {\n out.push({ kind: \"select-extend\", x: s.x, y: s.y });\n }\n last = s;\n return out;\n },\n up(s) {\n const was = phase;\n phase = \"idle\";\n if (was === \"pressed\") return [{ kind: \"tap\", x: start.x, y: start.y }];\n if (was === \"selecting\") return [{ kind: \"select-end\" }];\n if (was === \"scrolling\") {\n const out = scrollBy(last.y, s.y);\n trail.push(s);\n const first = trail[0]!;\n const dt = s.t - first.t;\n const velocity = dt > 0 ? (first.y - s.y) / dt / lineHeight : 0;\n if (Math.abs(velocity) >= FLING_MIN) out.push({ kind: \"fling\", velocity });\n return out;\n }\n return [];\n },\n cancel() {\n const was = phase;\n phase = \"idle\";\n return was === \"selecting\" ? [{ kind: \"select-end\" }] : [];\n },\n longPress() {\n if (phase !== \"pressed\") return [];\n phase = \"selecting\";\n return [{ kind: \"select-start\", x: start.x, y: start.y }];\n },\n };\n}\n\n/**\n * One momentum frame: how far to move (lines, fractional) and the decayed velocity. The host\n * accumulates the fractional lines and scrolls whole ones until `velocity` is 0.\n */\nexport function flingStep(velocity: number, dtMs: number): { lines: number; velocity: number } {\n const lines = velocity * dtMs;\n const next = velocity * Math.pow(FLING_FRICTION, dtMs / 16);\n return { lines, velocity: Math.abs(next) < FLING_STOP ? 0 : next };\n}\n","/**\n * Long-press selection math in buffer cells. Pure; the React layer maps touch points to cells.\n */\n\nexport interface Cell {\n col: number;\n /** Absolute buffer row (scrollback included). */\n row: number;\n}\n\n/** Characters that belong to a \"word\" for a long press: paths, URLs, flags and hosts select whole. */\nconst WORD = /[A-Za-z0-9_\\-./~:@%+=,?&#]/;\n\n/** [start, end) of the word at `col` in `line`; a one-cell range on a separator. */\nexport function wordBounds(line: string, col: number): { start: number; end: number } {\n const chars = Array.from(line);\n if (col < 0 || col >= chars.length || !WORD.test(chars[col] ?? \" \")) return { start: col, end: col + 1 };\n let start = col;\n let end = col + 1;\n while (start > 0 && WORD.test(chars[start - 1]!)) start--;\n while (end < chars.length && WORD.test(chars[end]!)) end++;\n return { start, end };\n}\n\n/**\n * xterm's `select(column, row, length)` for the span between two cells (either order), where a\n * span wraps at `cols`. `anchor` is the first selected cell; `focus` is included too.\n */\nexport function spanBetween(anchor: Cell, focus: Cell, cols: number): { col: number; row: number; length: number } {\n const a = anchor.row * cols + anchor.col;\n const b = focus.row * cols + focus.col;\n const from = Math.min(a, b);\n const to = Math.max(a, b);\n return { col: from % cols, row: Math.floor(from / cols), length: to - from + 1 };\n}\n\n/** The cell under a point, given the screen element's box and the grid size; clamped to the grid. */\nexport function cellAt(\n point: { x: number; y: number },\n box: { left: number; top: number; width: number; height: number },\n grid: { cols: number; rows: number; viewportY: number },\n): Cell {\n const cw = box.width / Math.max(1, grid.cols);\n const ch = box.height / Math.max(1, grid.rows);\n const col = Math.min(grid.cols - 1, Math.max(0, Math.floor((point.x - box.left) / cw)));\n const screenRow = Math.min(grid.rows - 1, Math.max(0, Math.floor((point.y - box.top) / ch)));\n return { col, row: grid.viewportY + screenRow };\n}\n","/**\n * Terminal look: font, metrics and the two palettes. One place, so every terminal in every app\n * renders the same.\n */\nimport type { ITheme } from \"@xterm/xterm\";\n\n/** The system monospace first: SF Mono on Apple platforms, then the usual fallbacks. */\nexport const TERMINAL_FONT_FAMILY = 'ui-monospace, \"SF Mono\", SFMono-Regular, Menlo, Consolas, \"Liberation Mono\", monospace';\n\nexport const TERMINAL_DEFAULTS = {\n fontSize: 13,\n lineHeight: 1.2,\n scrollback: 5000,\n /** Side padding inside the terminal box, px. */\n padding: 8,\n} as const;\n\n/** The keyboard accessory bar's height, px (styles.css .mxt-bar: 44px keys + 4px above and below). */\nexport const ACCESSORY_BAR_HEIGHT = 52;\n\n/** The range a person can zoom the terminal text to (pinch, ⌘+ / ⌘−). */\nexport const FONT_SIZE_MIN = 9;\nexport const FONT_SIZE_MAX = 24;\n\n/** ⌘+ / ⌘− steps one point; the result stays in range. */\nexport function stepFontSize(current: number, delta: number): number {\n return Math.min(FONT_SIZE_MAX, Math.max(FONT_SIZE_MIN, Math.round(current) + delta));\n}\n\n/** A pinch scales the size it started from by the change in finger distance, to whole points. */\nexport function pinchFontSize(startSize: number, startDistance: number, distance: number): number {\n if (startDistance <= 0) return startSize;\n return Math.min(FONT_SIZE_MAX, Math.max(FONT_SIZE_MIN, Math.round((startSize * distance) / startDistance)));\n}\n\nexport function terminalTheme(dark: boolean): ITheme {\n return dark\n ? {\n background: \"#1e1e1e\",\n foreground: \"#e4e4e7\",\n cursor: \"#e4e4e7\",\n cursorAccent: \"#1e1e1e\",\n black: \"#1e1e1e\",\n red: \"#f87171\",\n green: \"#4ade80\",\n yellow: \"#facc15\",\n blue: \"#60a5fa\",\n magenta: \"#c084fc\",\n cyan: \"#22d3ee\",\n white: \"#e5e7eb\",\n brightBlack: \"#71717a\",\n brightRed: \"#fca5a5\",\n brightGreen: \"#86efac\",\n brightYellow: \"#fde047\",\n brightBlue: \"#93c5fd\",\n brightMagenta: \"#d8b4fe\",\n brightCyan: \"#67e8f9\",\n brightWhite: \"#f4f4f5\",\n selectionBackground: \"#3b82f680\",\n }\n : {\n background: \"#ffffff\",\n foreground: \"#18181b\",\n cursor: \"#18181b\",\n cursorAccent: \"#ffffff\",\n black: \"#18181b\",\n red: \"#b91c1c\",\n green: \"#15803d\",\n yellow: \"#b45309\",\n blue: \"#1d4ed8\",\n magenta: \"#7c3aed\",\n cyan: \"#0e7490\",\n white: \"#d4d4d8\",\n brightBlack: \"#71717a\",\n brightRed: \"#dc2626\",\n brightGreen: \"#16a34a\",\n brightYellow: \"#d97706\",\n brightBlue: \"#2563eb\",\n brightMagenta: \"#9333ea\",\n brightCyan: \"#0891b2\",\n brightWhite: \"#a1a1aa\",\n selectionBackground: \"#93c5fd99\",\n };\n}\n","/**\n * Visual-viewport arithmetic: where the on-screen keyboard is, and how tall a terminal anchored\n * at `top` may be so its last row and the accessory bar sit exactly above the keyboard. iOS\n * Safari shrinks only the VISUAL viewport when the keyboard opens; the layout viewport (and every\n * `100dvh`) stays full height, so a `bottom: 0` element ends up behind the keyboard.\n */\n\nexport interface ViewportBox {\n height: number;\n offsetTop: number;\n}\n\n/**\n * Below this the difference is browser chrome (Safari's collapsing toolbar), not a keyboard.\n * The smallest phone keyboard (iPhone SE landscape) is ~160px.\n */\nexport const KEYBOARD_MIN_PX = 120;\n\n/** Height the keyboard (or any bottom overlay) takes out of the layout viewport; 0 when closed. */\nexport function keyboardInset(layoutHeight: number, vv: ViewportBox | null): number {\n if (!vv) return 0;\n const inset = Math.round(layoutHeight - vv.height - vv.offsetTop);\n return inset >= KEYBOARD_MIN_PX ? inset : 0;\n}\n\n/** Height from `top` (layout px) down to the bottom of what is visible. Never negative. */\nexport function visibleHeightBelow(top: number, vv: ViewportBox | null, layoutHeight: number): number {\n const bottom = vv ? vv.offsetTop + vv.height : layoutHeight;\n return Math.max(0, Math.floor(bottom - top));\n}\n","\"use client\";\n\n/**\n * The keyboard accessory bar: one 44px row of the keys a phone keyboard lacks, scrolling\n * sideways. Every key keeps the terminal focused (pointerdown is cancelled), so the keyboard\n * stays up while you tap Esc, arrows or Ctrl. Ctrl / Alt: tap = next key only, double-tap = locked.\n */\nimport type { ReactNode } from \"react\";\n\nimport { ACCESSORY_KEYS } from \"../core/keys\";\nimport type { AccessoryKeyDef, AccessoryKeyId } from \"../core/keys\";\nimport type { ModifierState } from \"../core/modifiers\";\n\nfunction PasteIcon() {\n return (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <rect x=\"8\" y=\"2\" width=\"8\" height=\"4\" rx=\"1\" />\n <path d=\"M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2\" />\n </svg>\n );\n}\n\nfunction HideKeyboardIcon() {\n return (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <rect x=\"2\" y=\"3\" width=\"20\" height=\"12\" rx=\"2\" />\n <path d=\"M6 7h.01M10 7h.01M14 7h.01M18 7h.01M7 11h10\" />\n <path d=\"m8 19 4 3 4-3\" />\n </svg>\n );\n}\n\nconst ICONS: Partial<Record<AccessoryKeyId, () => ReactNode>> = { paste: PasteIcon, hide: HideKeyboardIcon };\n\nexport interface AccessoryBarProps {\n ctrl: ModifierState;\n alt: ModifierState;\n onKey: (id: AccessoryKeyId) => void;\n}\n\nexport function AccessoryBar({ ctrl, alt, onKey }: AccessoryBarProps) {\n const groups: AccessoryKeyDef[][] = [];\n for (const key of ACCESSORY_KEYS) (groups[key.group] ??= []).push(key);\n return (\n <div className=\"mxt-bar\" role=\"toolbar\" aria-label=\"Terminal keys\">\n {groups.map((group, gi) => (\n <div key={gi} className=\"mxt-bar-group\">\n {gi > 0 ? <span className=\"mxt-bar-divider\" aria-hidden=\"true\" /> : null}\n {group.map((key) => {\n const state = key.id === \"ctrl\" ? ctrl : key.id === \"alt\" ? alt : null;\n const Icon = ICONS[key.id];\n return (\n <button\n key={key.id}\n type=\"button\"\n className=\"mxt-key\"\n data-state={state ?? undefined}\n aria-label={key.aria}\n aria-pressed={state === null ? undefined : state !== \"off\"}\n // Keep focus (and the keyboard) on the terminal.\n onPointerDown={(e) => e.preventDefault()}\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => onKey(key.id)}\n >\n {Icon ? <Icon /> : key.label}\n </button>\n );\n })}\n </div>\n ))}\n </div>\n );\n}\n"],"mappings":"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","names":["import_jsx_runtime","current"]}
package/dist/react.js CHANGED
@@ -4,6 +4,7 @@
4
4
  import "@xterm/xterm/css/xterm.css";
5
5
  import "@ai-matrx/terminal/styles.css";
6
6
  import { useEffect, useRef, useState } from "react";
7
+ import { copyText, readText } from "@ai-matrx/kit/clipboard";
7
8
 
8
9
  // src/core/keys.ts
9
10
  var ACCESSORY_KEYS = [
@@ -764,14 +765,9 @@ function Terminal(props) {
764
765
  return;
765
766
  }
766
767
  if (id === "paste") {
767
- if (!navigator.clipboard?.readText) return;
768
- navigator.clipboard.readText().then(
769
- (text) => {
770
- if (text) term.paste(text);
771
- },
772
- () => void 0
773
- // permission refused: the system paste menu still works on the input
774
- );
768
+ void readText().then((text) => {
769
+ if (text) term.paste(text);
770
+ });
775
771
  return;
776
772
  }
777
773
  const current = latchRef.current;
@@ -785,7 +781,7 @@ function Terminal(props) {
785
781
  const term = termRef.current;
786
782
  if (!term) return;
787
783
  const text = term.getSelection();
788
- if (text && navigator.clipboard?.writeText) void navigator.clipboard.writeText(text);
784
+ if (text) void copyText(text);
789
785
  term.clearSelection();
790
786
  setCopyVisible(false);
791
787
  }
package/dist/react.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/react/Terminal.tsx","../src/core/keys.ts","../src/core/modifiers.ts","../src/core/gesture.ts","../src/core/selection.ts","../src/core/theme.ts","../src/core/viewport.ts","../src/react/AccessoryBar.tsx"],"sourcesContent":["\"use client\";\n\n/**\n * <Terminal> — xterm 6 (DOM renderer) with everything a host would otherwise rebuild: fit to its\n * box or to the visual viewport, theme that follows the app's `.dark` class, Ctrl-C hook, phone\n * touch (momentum scroll, long-press word select, copy), and the keyboard accessory bar with\n * one-shot / locked Ctrl and Alt. Transport-free: bytes in through the handle's `write`, keys\n * out through `onData`, size out through `onResize`. Any PTY (desktop relay, cloud sandbox,\n * local process) plugs in with three lines.\n */\n// The package ships its stylesheets; importing them here means a host never forgets them. Both\n// stay as imports in the built bundle (tsup externals) for the host's bundler to place.\nimport \"@xterm/xterm/css/xterm.css\";\nimport \"@ai-matrx/terminal/styles.css\";\nimport { useEffect, useRef, useState } from \"react\";\nimport type { CSSProperties, ReactNode } from \"react\";\nimport type { ITerminalOptions, Terminal as XTerm } from \"@xterm/xterm\";\nimport type { FitAddon } from \"@xterm/addon-fit\";\n\nimport { ACCESSORY_KEYS, applyModifiers, keySequence } from \"../core/keys\";\nimport type { AccessoryKeyId } from \"../core/keys\";\nimport { MODIFIER_OFF, afterKey, isActive, tapModifier } from \"../core/modifiers\";\nimport type { ModifierLatch } from \"../core/modifiers\";\nimport { LONG_PRESS_MS, createGestureRecognizer, flingStep } from \"../core/gesture\";\nimport type { GestureAction } from \"../core/gesture\";\nimport { cellAt, spanBetween, wordBounds } from \"../core/selection\";\nimport type { Cell } from \"../core/selection\";\nimport { TERMINAL_DEFAULTS, TERMINAL_FONT_FAMILY, pinchFontSize, stepFontSize, terminalTheme } from \"../core/theme\";\nimport { visibleHeightBelow } from \"../core/viewport\";\nimport { AccessoryBar } from \"./AccessoryBar\";\n\nexport interface TerminalSize {\n cols: number;\n rows: number;\n}\n\n/** What a host drives the terminal with. Stable for the terminal's life. */\nexport interface TerminalHandle {\n /** Write output; resolves once xterm has parsed it (use it to pace credit-based streams). */\n write(data: string | Uint8Array): Promise<void>;\n /** Clear screen, scrollback and modes — before writing a fresh screen snapshot. */\n reset(): void;\n /** Clear the scrollback, keep the prompt line. */\n clear(): void;\n focus(): void;\n blur(): void;\n /** Visible text of the whole buffer (scrollback included), lines joined with \\n. */\n getText(): string;\n readonly cols: number;\n readonly rows: number;\n /** The underlying xterm, for what this package does not wrap (read-mostly use). */\n readonly xterm: XTerm;\n}\n\nexport interface TerminalProps {\n /** Keystrokes and pastes, already modified by the accessory bar's Ctrl / Alt. */\n onData?: (data: string) => void;\n /** Grid size after every fit (and once at start). */\n onResize?: (size: TerminalSize) => void;\n /**\n * The person zoomed the text: a pinch on touch, ⌘+ / ⌘− / ⌘0 with a keyboard. Pass it (and feed\n * the value back as `fontSize`) to turn zoom on; the host decides where the size is remembered.\n */\n onFontSizeChange?: (fontSize: number) => void;\n onReady?: (handle: TerminalHandle) => void;\n /**\n * Hardware Ctrl-C (no Shift/Alt/Meta). Return true to consume it — e.g. send a SIGINT frame\n * because the page's own shortcuts eat the key. Default: xterm sends ETX (0x03) through onData.\n */\n onInterrupt?: () => boolean;\n /** \"auto\" follows the `dark` class on <html>. */\n theme?: \"auto\" | \"dark\" | \"light\";\n fontSize?: number;\n lineHeight?: number;\n scrollback?: number;\n /** Side padding, px. */\n padding?: number;\n /** Translate bare \\n to \\r\\n (for line-oriented output that is not a PTY). */\n convertEol?: boolean;\n cursorBlink?: boolean;\n disableStdin?: boolean;\n /** Clickable URLs. Default true. */\n links?: boolean;\n /** Phone touch gestures. \"auto\" = when the primary pointer is coarse. */\n touch?: \"auto\" | \"on\" | \"off\";\n /** The keyboard accessory bar. \"auto\" = when the primary pointer is coarse. */\n accessory?: \"auto\" | \"on\" | \"off\";\n /**\n * \"container\": fill the parent box (it must have a height). \"viewport\": grow from where the\n * terminal starts down to the bottom of the VISUAL viewport, so the last row and the accessory\n * bar sit right above the on-screen keyboard.\n */\n fit?: \"container\" | \"viewport\";\n autoFocus?: boolean;\n className?: string;\n style?: CSSProperties;\n \"aria-label\"?: string;\n /** Rendered over the terminal (e.g. a reconnecting veil). */\n children?: ReactNode;\n}\n\ninterface Latches {\n ctrl: ModifierLatch;\n alt: ModifierLatch;\n}\n\nfunction prefersDark(): boolean {\n return typeof document !== \"undefined\" && document.documentElement.classList.contains(\"dark\");\n}\n\nfunction coarsePointer(): boolean {\n return typeof window !== \"undefined\" && typeof window.matchMedia === \"function\" && window.matchMedia(\"(pointer: coarse)\").matches;\n}\n\nexport function Terminal(props: TerminalProps) {\n const {\n theme = \"auto\",\n fontSize = TERMINAL_DEFAULTS.fontSize,\n lineHeight = TERMINAL_DEFAULTS.lineHeight,\n scrollback = TERMINAL_DEFAULTS.scrollback,\n padding = TERMINAL_DEFAULTS.padding,\n convertEol = false,\n cursorBlink = true,\n disableStdin = false,\n links = true,\n touch = \"auto\",\n accessory = \"auto\",\n fit = \"container\",\n autoFocus = false,\n } = props;\n\n const rootRef = useRef<HTMLDivElement | null>(null);\n const hostRef = useRef<HTMLDivElement | null>(null);\n const termRef = useRef<XTerm | null>(null);\n const fitRef = useRef<FitAddon | null>(null);\n const handleRef = useRef<TerminalHandle | null>(null);\n const latchRef = useRef<Latches>({ ctrl: MODIFIER_OFF, alt: MODIFIER_OFF });\n const callbacksRef = useRef({\n onData: props.onData,\n onResize: props.onResize,\n onReady: props.onReady,\n onInterrupt: props.onInterrupt,\n onFontSizeChange: props.onFontSizeChange,\n });\n const fontSizeRef = useRef(fontSize);\n\n const [latches, setLatches] = useState<Latches>({ ctrl: MODIFIER_OFF, alt: MODIFIER_OFF });\n const [coarse, setCoarse] = useState(false);\n const [dark, setDark] = useState(theme === \"dark\");\n const [copyVisible, setCopyVisible] = useState(false);\n const [viewportHeight, setViewportHeight] = useState<number | null>(null);\n const [booted, setBooted] = useState(false);\n\n useEffect(() => {\n callbacksRef.current = {\n onData: props.onData,\n onResize: props.onResize,\n onReady: props.onReady,\n onInterrupt: props.onInterrupt,\n onFontSizeChange: props.onFontSizeChange,\n };\n fontSizeRef.current = fontSize;\n });\n\n // Pointer class and theme are browser facts: read after mount (SSR renders the neutral frame).\n useEffect(() => {\n setCoarse(coarsePointer());\n const mq = typeof window.matchMedia === \"function\" ? window.matchMedia(\"(pointer: coarse)\") : null;\n const onChange = () => setCoarse(coarsePointer());\n mq?.addEventListener(\"change\", onChange);\n return () => mq?.removeEventListener(\"change\", onChange);\n }, []);\n\n useEffect(() => {\n if (theme !== \"auto\") {\n setDark(theme === \"dark\");\n return undefined;\n }\n setDark(prefersDark());\n if (typeof MutationObserver === \"undefined\") return undefined;\n const observer = new MutationObserver(() => setDark(prefersDark()));\n observer.observe(document.documentElement, { attributes: true, attributeFilter: [\"class\"] });\n return () => observer.disconnect();\n }, [theme]);\n\n const touchOn = touch === \"on\" || (touch === \"auto\" && coarse);\n const barOn = accessory === \"on\" || (accessory === \"auto\" && coarse);\n\n function setLatchState(next: Latches): void {\n latchRef.current = next;\n setLatches(next);\n }\n\n /** Keyboard input → accessory modifiers → host. */\n function emit(data: string): void {\n const current = latchRef.current;\n const mods = { ctrl: isActive(current.ctrl), alt: isActive(current.alt) };\n const { data: out, consumed } = applyModifiers(data, mods);\n if (consumed) setLatchState({ ctrl: afterKey(current.ctrl), alt: afterKey(current.alt) });\n callbacksRef.current.onData?.(out);\n }\n\n // ── boot xterm once ───────────────────────────────────────────────────────\n useEffect(() => {\n let cancelled = false;\n let disposeAll: (() => void) | null = null;\n void (async () => {\n const [{ Terminal: XTermCtor }, { FitAddon: FitCtor }, linksModule] = await Promise.all([\n import(\"@xterm/xterm\"),\n import(\"@xterm/addon-fit\"),\n import(\"@xterm/addon-web-links\"),\n ]);\n const host = hostRef.current;\n if (cancelled || !host) return;\n const options: ITerminalOptions = {\n fontFamily: TERMINAL_FONT_FAMILY,\n fontSize,\n lineHeight,\n scrollback,\n convertEol,\n cursorBlink,\n cursorStyle: \"bar\",\n disableStdin,\n allowProposedApi: false,\n theme: terminalTheme(theme === \"auto\" ? prefersDark() : theme === \"dark\"),\n };\n const term = new XTermCtor(options);\n const fitAddon = new FitCtor();\n term.loadAddon(fitAddon);\n if (links) term.loadAddon(new linksModule.WebLinksAddon());\n term.open(host);\n const textarea = term.textarea;\n if (textarea) {\n // iOS: no autocorrect/capitalisation in a shell; 16px stops the focus zoom (styles.css).\n textarea.setAttribute(\"autocorrect\", \"off\");\n textarea.setAttribute(\"autocapitalize\", \"off\");\n textarea.setAttribute(\"autocomplete\", \"off\");\n textarea.setAttribute(\"spellcheck\", \"false\");\n textarea.setAttribute(\"aria-label\", props[\"aria-label\"] ?? \"Terminal input\");\n }\n termRef.current = term;\n fitRef.current = fitAddon;\n\n const dataSub = term.onData((data) => emit(data));\n const resizeSub = term.onResize(({ cols, rows }) => callbacksRef.current.onResize?.({ cols, rows }));\n term.attachCustomKeyEventHandler((event) => {\n // ⌘+ / ⌘− / ⌘0 zoom the text (only when the host takes the size: onFontSizeChange).\n const zoom = callbacksRef.current.onFontSizeChange;\n if (zoom && event.type === \"keydown\" && event.metaKey && !event.altKey && !event.ctrlKey) {\n const delta = event.key === \"=\" || event.key === \"+\" ? 1 : event.key === \"-\" ? -1 : event.key === \"0\" ? 0 : null;\n if (delta !== null) {\n event.preventDefault();\n zoom(delta === 0 ? TERMINAL_DEFAULTS.fontSize : stepFontSize(fontSizeRef.current, delta));\n return false;\n }\n }\n if (\n event.type === \"keydown\" &&\n event.ctrlKey &&\n !event.shiftKey &&\n !event.altKey &&\n !event.metaKey &&\n event.key.toLowerCase() === \"c\" &&\n !term.hasSelection()\n ) {\n const consumed = callbacksRef.current.onInterrupt?.() ?? false;\n if (consumed) return false;\n }\n return true;\n });\n const selectionSub = term.onSelectionChange(() => setCopyVisible(term.hasSelection()));\n\n const handle: TerminalHandle = {\n write: (data) => new Promise<void>((resolve) => term.write(data, resolve)),\n reset: () => term.reset(),\n clear: () => term.clear(),\n focus: () => term.focus(),\n blur: () => term.blur(),\n getText: () => {\n const buffer = term.buffer.active;\n const lines: string[] = [];\n for (let y = 0; y < buffer.length; y++) lines.push(buffer.getLine(y)?.translateToString(true) ?? \"\");\n while (lines.length > 0 && lines[lines.length - 1] === \"\") lines.pop();\n return lines.join(\"\\n\");\n },\n get cols() {\n return term.cols;\n },\n get rows() {\n return term.rows;\n },\n xterm: term,\n };\n handleRef.current = handle;\n try {\n fitAddon.fit();\n } catch {\n // The box may not be laid out yet; the resize observer fits it when it is.\n }\n setBooted(true);\n callbacksRef.current.onResize?.({ cols: term.cols, rows: term.rows });\n callbacksRef.current.onReady?.(handle);\n if (autoFocus) term.focus();\n\n disposeAll = () => {\n dataSub.dispose();\n resizeSub.dispose();\n selectionSub.dispose();\n term.dispose();\n };\n })();\n return () => {\n cancelled = true;\n disposeAll?.();\n termRef.current = null;\n fitRef.current = null;\n handleRef.current = null;\n };\n // Boot exactly once per mount; later option changes are applied by the effects below.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // ── live options ──────────────────────────────────────────────────────────\n useEffect(() => {\n const term = termRef.current;\n if (!term) return;\n term.options.theme = terminalTheme(dark);\n }, [dark, booted]);\n\n useEffect(() => {\n const term = termRef.current;\n if (!term) return;\n term.options.disableStdin = disableStdin;\n term.options.fontSize = fontSize;\n term.options.lineHeight = lineHeight;\n try {\n fitRef.current?.fit();\n } catch {\n // between frames\n }\n }, [disableStdin, fontSize, lineHeight, booted]);\n\n // ── fit to the box ────────────────────────────────────────────────────────\n useEffect(() => {\n const host = hostRef.current;\n if (!host) return undefined;\n const refit = () => {\n const term = termRef.current;\n if (!term || host.clientWidth <= 0 || host.clientHeight <= 0) return;\n try {\n fitRef.current?.fit();\n // A DOM renderer mounted while hidden measured zero-width glyphs; refresh re-measures.\n term.refresh(0, term.rows - 1);\n } catch {\n // xterm is mid-paint\n }\n };\n refit();\n if (typeof ResizeObserver === \"undefined\") return undefined; // non-browser hosts (jsdom)\n const ro = new ResizeObserver(refit);\n ro.observe(host);\n return () => ro.disconnect();\n }, [booted]);\n\n // ── fit to the visual viewport (phones: stop exactly at the keyboard) ─────\n useEffect(() => {\n if (fit !== \"viewport\") {\n setViewportHeight(null);\n return undefined;\n }\n const root = rootRef.current;\n if (!root) return undefined;\n const vv = window.visualViewport;\n const measure = () => {\n // The console owns the screen: a page scrolled by iOS to \"reveal\" the input only hides the top.\n if (window.scrollY !== 0) window.scrollTo(0, 0);\n const top = root.getBoundingClientRect().top + window.scrollY;\n setViewportHeight(visibleHeightBelow(top, vv ? { height: vv.height, offsetTop: vv.offsetTop } : null, window.innerHeight));\n };\n measure();\n vv?.addEventListener(\"resize\", measure);\n vv?.addEventListener(\"scroll\", measure);\n window.addEventListener(\"resize\", measure);\n window.addEventListener(\"orientationchange\", measure);\n return () => {\n vv?.removeEventListener(\"resize\", measure);\n vv?.removeEventListener(\"scroll\", measure);\n window.removeEventListener(\"resize\", measure);\n window.removeEventListener(\"orientationchange\", measure);\n };\n }, [fit]);\n\n // ── touch: tap focuses, drag scrolls with momentum, hold selects ──────────\n useEffect(() => {\n const host = hostRef.current;\n const term = termRef.current;\n if (!touchOn || !host || !term) return undefined;\n // Re-created at each touch so a zoom (pinch, ⌘±) is already in the row height it scrolls by.\n let recognizer = createGestureRecognizer({ lineHeight: fontSizeRef.current * lineHeight });\n let holdTimer: ReturnType<typeof setTimeout> | null = null;\n let flingFrame: number | null = null;\n let flingCarry = 0;\n let anchor: Cell | null = null;\n\n const screen = () => (term.element?.querySelector(\".xterm-screen\") as HTMLElement | null) ?? host;\n const cellFor = (x: number, y: number): Cell => {\n const r = screen().getBoundingClientRect();\n return cellAt({ x, y }, { left: r.left, top: r.top, width: r.width, height: r.height }, { cols: term.cols, rows: term.rows, viewportY: term.buffer.active.viewportY });\n };\n const scrollLines = (lines: number) => {\n if (lines === 0) return;\n if (term.buffer.active.type === \"alternate\") {\n // Full-screen programs (less, vim, htop) own their screen: a drag pages them with arrows.\n const key = lines > 0 ? \"down\" : \"up\";\n const seq = keySequence(key, { ctrl: false, alt: false }, { applicationCursor: term.modes.applicationCursorKeysMode });\n if (seq) callbacksRef.current.onData?.(seq.repeat(Math.min(Math.abs(lines), 50)));\n return;\n }\n term.scrollLines(lines);\n };\n const stopFling = () => {\n if (flingFrame !== null) cancelAnimationFrame(flingFrame);\n flingFrame = null;\n flingCarry = 0;\n };\n const startFling = (velocity: number) => {\n stopFling();\n let v = velocity;\n let last = performance.now();\n const step = (now: number) => {\n const res = flingStep(v, now - last);\n last = now;\n v = res.velocity;\n flingCarry += res.lines;\n const whole = flingCarry > 0 ? Math.floor(flingCarry) : Math.ceil(flingCarry);\n if (whole !== 0) {\n flingCarry -= whole;\n scrollLines(whole);\n }\n flingFrame = v === 0 ? null : requestAnimationFrame(step);\n };\n flingFrame = requestAnimationFrame(step);\n };\n const act = (actions: GestureAction[]) => {\n for (const a of actions) {\n switch (a.kind) {\n case \"tap\":\n term.clearSelection();\n term.focus();\n break;\n case \"scroll\":\n scrollLines(a.lines);\n break;\n case \"fling\":\n startFling(a.velocity);\n break;\n case \"select-start\": {\n const cell = cellFor(a.x, a.y);\n const line = term.buffer.active.getLine(cell.row)?.translateToString(false) ?? \"\";\n const word = wordBounds(line, cell.col);\n anchor = { col: word.start, row: cell.row };\n term.select(word.start, cell.row, Math.max(1, word.end - word.start));\n navigator.vibrate?.(10);\n break;\n }\n case \"select-extend\": {\n if (!anchor) break;\n const span = spanBetween(anchor, cellFor(a.x, a.y), term.cols);\n term.select(span.col, span.row, span.length);\n break;\n }\n case \"select-end\":\n anchor = null;\n setCopyVisible(term.hasSelection());\n break;\n }\n }\n };\n const clearHold = () => {\n if (holdTimer !== null) clearTimeout(holdTimer);\n holdTimer = null;\n };\n /** Two fingers: pinch-zoom the TEXT (when the host takes the size), never the page. */\n let pinch: { startDistance: number; startSize: number } | null = null;\n const fingerDistance = (e: TouchEvent) => {\n const a = e.touches[0]!;\n const b = e.touches[1]!;\n return Math.hypot(a.clientX - b.clientX, a.clientY - b.clientY);\n };\n const onStart = (e: TouchEvent) => {\n if (e.touches.length === 2 && callbacksRef.current.onFontSizeChange) {\n e.preventDefault();\n clearHold();\n stopFling();\n act(recognizer.cancel());\n pinch = { startDistance: fingerDistance(e), startSize: fontSizeRef.current };\n return;\n }\n if (e.touches.length !== 1) {\n clearHold();\n act(recognizer.cancel());\n return; // more fingers, or no zoom wanted: leave it to the browser\n }\n const t = e.touches[0]!;\n e.preventDefault();\n stopFling();\n recognizer = createGestureRecognizer({ lineHeight: fontSizeRef.current * lineHeight });\n act(recognizer.down({ x: t.clientX, y: t.clientY, t: e.timeStamp }));\n clearHold();\n holdTimer = setTimeout(() => act(recognizer.longPress()), LONG_PRESS_MS);\n };\n const onMove = (e: TouchEvent) => {\n if (pinch && e.touches.length === 2) {\n e.preventDefault();\n const size = pinchFontSize(pinch.startSize, pinch.startDistance, fingerDistance(e));\n if (size !== fontSizeRef.current) {\n fontSizeRef.current = size;\n callbacksRef.current.onFontSizeChange?.(size);\n }\n return;\n }\n if (e.touches.length !== 1 || recognizer.phase === \"idle\") return;\n const t = e.touches[0]!;\n e.preventDefault();\n act(recognizer.move({ x: t.clientX, y: t.clientY, t: e.timeStamp }));\n if (recognizer.phase !== \"pressed\") clearHold();\n };\n const onEnd = (e: TouchEvent) => {\n if (pinch) {\n if (e.touches.length < 2) pinch = null;\n e.preventDefault();\n return;\n }\n clearHold();\n if (recognizer.phase === \"idle\") return;\n const t = e.changedTouches[0];\n e.preventDefault();\n act(recognizer.up({ x: t?.clientX ?? 0, y: t?.clientY ?? 0, t: e.timeStamp }));\n };\n const onCancel = () => {\n clearHold();\n act(recognizer.cancel());\n };\n host.addEventListener(\"touchstart\", onStart, { passive: false });\n host.addEventListener(\"touchmove\", onMove, { passive: false });\n host.addEventListener(\"touchend\", onEnd, { passive: false });\n host.addEventListener(\"touchcancel\", onCancel);\n return () => {\n clearHold();\n stopFling();\n host.removeEventListener(\"touchstart\", onStart);\n host.removeEventListener(\"touchmove\", onMove);\n host.removeEventListener(\"touchend\", onEnd);\n host.removeEventListener(\"touchcancel\", onCancel);\n };\n }, [touchOn, booted, lineHeight]);\n\n // ── accessory bar ─────────────────────────────────────────────────────────\n function onAccessoryKey(id: AccessoryKeyId): void {\n const term = termRef.current;\n if (!term) return;\n const def = ACCESSORY_KEYS.find((k) => k.id === id);\n if (!def) return;\n if (def.kind === \"modifier\") {\n const now = performance.now();\n const current = latchRef.current;\n setLatchState(id === \"ctrl\" ? { ...current, ctrl: tapModifier(current.ctrl, now) } : { ...current, alt: tapModifier(current.alt, now) });\n return;\n }\n if (id === \"hide\") {\n term.blur();\n term.textarea?.blur();\n return;\n }\n if (id === \"paste\") {\n if (!navigator.clipboard?.readText) return;\n navigator.clipboard.readText().then(\n (text) => {\n if (text) term.paste(text);\n },\n () => undefined, // permission refused: the system paste menu still works on the input\n );\n return;\n }\n const current = latchRef.current;\n const mods = { ctrl: isActive(current.ctrl), alt: isActive(current.alt) };\n const seq = keySequence(id, mods, { applicationCursor: term.modes.applicationCursorKeysMode });\n if (seq === null) return;\n if (mods.ctrl || mods.alt) setLatchState({ ctrl: afterKey(current.ctrl), alt: afterKey(current.alt) });\n callbacksRef.current.onData?.(seq);\n }\n\n function copySelection(): void {\n const term = termRef.current;\n if (!term) return;\n const text = term.getSelection();\n if (text && navigator.clipboard?.writeText) void navigator.clipboard.writeText(text);\n term.clearSelection();\n setCopyVisible(false);\n }\n\n const rootStyle: CSSProperties = { ...props.style };\n if (viewportHeight !== null) rootStyle.height = viewportHeight;\n\n return (\n <div\n ref={rootRef}\n className={[\"mxt-root\", props.className].filter(Boolean).join(\" \")}\n style={rootStyle}\n data-touch={touchOn ? \"on\" : \"off\"}\n data-theme={dark ? \"dark\" : \"light\"}\n >\n <div className=\"mxt-frame\" style={{ background: terminalTheme(dark).background }}>\n <div ref={hostRef} className=\"mxt-host\" style={{ paddingLeft: padding, paddingRight: padding }} />\n {copyVisible ? (\n <button type=\"button\" className=\"mxt-copy\" onPointerDown={(e) => e.preventDefault()} onClick={copySelection}>\n Copy\n </button>\n ) : null}\n {props.children}\n </div>\n {barOn ? <AccessoryBar ctrl={latches.ctrl.state} alt={latches.alt.state} onKey={onAccessoryKey} /> : null}\n </div>\n );\n}\n","/**\n * The keyboard accessory bar's keys and the bytes each sends — the keys a phone keyboard lacks.\n * Pure: no DOM, no xterm. Sequences follow xterm's own encoding (CSI 1;<mod> for modified cursor\n * keys, SS3 in application cursor mode), so full-screen programs (vim, less, htop) read them\n * exactly as they read a desktop keyboard.\n */\n\nexport type AccessoryKeyId =\n | \"esc\"\n | \"tab\"\n | \"ctrl\"\n | \"alt\"\n | \"left\"\n | \"down\"\n | \"up\"\n | \"right\"\n | \"pipe\"\n | \"slash\"\n | \"tilde\"\n | \"dash\"\n | \"home\"\n | \"end\"\n | \"pgup\"\n | \"pgdn\"\n | \"paste\"\n | \"hide\";\n\nexport interface AccessoryKeyDef {\n id: AccessoryKeyId;\n /** What the key shows. */\n label: string;\n /** What a screen reader says. */\n aria: string;\n /** send = bytes to the PTY; modifier = Ctrl/Alt state; action = paste / hide keyboard. */\n kind: \"send\" | \"modifier\" | \"action\";\n /** Keys sharing a group sit together; a divider separates groups. */\n group: number;\n}\n\n/** Termius order: Esc Tab Ctrl Alt | ← ↓ ↑ → | | / ~ - | Home End PgUp PgDn | Paste, hide. */\nexport const ACCESSORY_KEYS: readonly AccessoryKeyDef[] = [\n { id: \"esc\", label: \"Esc\", aria: \"Escape\", kind: \"send\", group: 0 },\n { id: \"tab\", label: \"Tab\", aria: \"Tab\", kind: \"send\", group: 0 },\n { id: \"ctrl\", label: \"Ctrl\", aria: \"Control\", kind: \"modifier\", group: 0 },\n { id: \"alt\", label: \"Alt\", aria: \"Alt\", kind: \"modifier\", group: 0 },\n { id: \"left\", label: \"←\", aria: \"Left arrow\", kind: \"send\", group: 1 },\n { id: \"down\", label: \"↓\", aria: \"Down arrow\", kind: \"send\", group: 1 },\n { id: \"up\", label: \"↑\", aria: \"Up arrow\", kind: \"send\", group: 1 },\n { id: \"right\", label: \"→\", aria: \"Right arrow\", kind: \"send\", group: 1 },\n { id: \"pipe\", label: \"|\", aria: \"Pipe\", kind: \"send\", group: 2 },\n { id: \"slash\", label: \"/\", aria: \"Slash\", kind: \"send\", group: 2 },\n { id: \"tilde\", label: \"~\", aria: \"Tilde\", kind: \"send\", group: 2 },\n { id: \"dash\", label: \"-\", aria: \"Dash\", kind: \"send\", group: 2 },\n { id: \"home\", label: \"Home\", aria: \"Home\", kind: \"send\", group: 3 },\n { id: \"end\", label: \"End\", aria: \"End\", kind: \"send\", group: 3 },\n { id: \"pgup\", label: \"PgUp\", aria: \"Page up\", kind: \"send\", group: 3 },\n { id: \"pgdn\", label: \"PgDn\", aria: \"Page down\", kind: \"send\", group: 3 },\n { id: \"paste\", label: \"Paste\", aria: \"Paste\", kind: \"action\", group: 4 },\n { id: \"hide\", label: \"Hide\", aria: \"Hide keyboard\", kind: \"action\", group: 4 },\n];\n\nexport interface ActiveModifiers {\n ctrl: boolean;\n alt: boolean;\n}\n\nexport interface KeyModes {\n /** DECCKM — xterm's `modes.applicationCursorKeysMode`. */\n applicationCursor: boolean;\n}\n\nconst ESC = \"\\x1b\";\nconst CURSOR: Partial<Record<AccessoryKeyId, string>> = { up: \"A\", down: \"B\", right: \"C\", left: \"D\", home: \"H\", end: \"F\" };\nconst TILDE: Partial<Record<AccessoryKeyId, string>> = { pgup: \"5\", pgdn: \"6\" };\nconst LITERAL: Partial<Record<AccessoryKeyId, string>> = { pipe: \"|\", slash: \"/\", tilde: \"~\", dash: \"-\", tab: \"\\t\", esc: ESC };\n\n/** xterm's modifier parameter: 1 + shift(1) + alt(2) + ctrl(4). */\nfunction modParam(mods: ActiveModifiers): number {\n return 1 + (mods.alt ? 2 : 0) + (mods.ctrl ? 4 : 0);\n}\n\n/**\n * Bytes for a \"send\" key with the active modifiers applied, or null for a modifier/action key.\n * Modifiers on literal keys go through `applyModifiers` (Ctrl+/ → 0x1f, Alt+| → ESC |).\n */\nexport function keySequence(id: AccessoryKeyId, mods: ActiveModifiers, modes: KeyModes): string | null {\n const cursor = CURSOR[id];\n if (cursor !== undefined) {\n const m = modParam(mods);\n if (m > 1) return `${ESC}[1;${m}${cursor}`;\n return modes.applicationCursor ? `${ESC}O${cursor}` : `${ESC}[${cursor}`;\n }\n const tilde = TILDE[id];\n if (tilde !== undefined) {\n const m = modParam(mods);\n return m > 1 ? `${ESC}[${tilde};${m}~` : `${ESC}[${tilde}~`;\n }\n const literal = LITERAL[id];\n if (literal !== undefined) {\n if (id === \"tab\" && mods.ctrl === false && mods.alt === false) return literal;\n if (id === \"esc\") return mods.alt ? ESC + ESC : ESC;\n return applyModifiers(literal, mods).data;\n }\n return null;\n}\n\n/** Ctrl applied to one character, as a terminal keyboard encodes it; null when Ctrl has no code. */\nexport function controlCode(char: string): string | null {\n if (char.length !== 1) return null;\n const code = char.charCodeAt(0);\n if (code >= 0x61 && code <= 0x7a) return String.fromCharCode(code - 0x60); // a-z\n if (code >= 0x40 && code <= 0x5f) return String.fromCharCode(code - 0x40); // @ A-Z [ \\ ] ^ _\n switch (char) {\n case \" \":\n case \"2\":\n return \"\\x00\";\n case \"3\":\n return \"\\x1b\";\n case \"4\":\n return \"\\x1c\";\n case \"5\":\n return \"\\x1d\";\n case \"6\":\n return \"\\x1e\";\n case \"7\":\n case \"/\":\n case \"-\":\n return \"\\x1f\";\n case \"8\":\n case \"?\":\n return \"\\x7f\";\n default:\n return null;\n }\n}\n\n/**\n * Apply one-shot or locked modifiers to what the keyboard typed. Only a single key press is\n * modified — a paste or a multi-character IME commit passes through and does NOT consume the\n * modifier, so \"Ctrl, then paste\" never mangles the paste.\n */\nexport function applyModifiers(data: string, mods: ActiveModifiers): { data: string; consumed: boolean } {\n if (!mods.ctrl && !mods.alt) return { data, consumed: false };\n const chars = Array.from(data);\n if (chars.length !== 1) {\n // A cursor key typed on a hardware keyboard while Ctrl/Alt are latched: re-encode it.\n const m = /^\\x1b(?:\\[|O)([ABCDHF])$/.exec(data);\n if (m) return { data: `${ESC}[1;${modParam(mods)}${m[1]}`, consumed: true };\n return { data, consumed: false };\n }\n let out = data;\n if (mods.ctrl) {\n const ctl = controlCode(data);\n if (ctl !== null) out = ctl;\n }\n if (mods.alt) out = ESC + out;\n return { data: out, consumed: true };\n}\n","/**\n * Ctrl / Alt on the accessory bar: tap once = the next key only; tap twice quickly = locked until\n * tapped again. Pure state machine; the clock is passed in.\n */\n\nexport type ModifierState = \"off\" | \"once\" | \"locked\";\n\nexport interface ModifierLatch {\n state: ModifierState;\n /** When the latch was last tapped (ms), for double-tap detection. */\n tappedAt: number | null;\n}\n\n/** Two taps within this window lock the modifier (iOS's own double-tap timing for Shift lock). */\nexport const DOUBLE_TAP_MS = 350;\n\nexport const MODIFIER_OFF: ModifierLatch = { state: \"off\", tappedAt: null };\n\nexport function tapModifier(latch: ModifierLatch, now: number): ModifierLatch {\n switch (latch.state) {\n case \"off\":\n return { state: \"once\", tappedAt: now };\n case \"once\":\n return latch.tappedAt !== null && now - latch.tappedAt <= DOUBLE_TAP_MS\n ? { state: \"locked\", tappedAt: now }\n : { state: \"off\", tappedAt: now };\n case \"locked\":\n return { state: \"off\", tappedAt: now };\n }\n}\n\n/** After a key used the modifier: a one-shot latch releases, a locked one holds. */\nexport function afterKey(latch: ModifierLatch): ModifierLatch {\n return latch.state === \"once\" ? { state: \"off\", tappedAt: latch.tappedAt } : latch;\n}\n\nexport function isActive(latch: ModifierLatch): boolean {\n return latch.state !== \"off\";\n}\n","/**\n * One-finger gestures on a terminal, as iOS terminals (Termius, Blink) read them:\n *\n * tap → focus (opens the keyboard)\n * drag up / down → scroll the scrollback, by whole lines, with momentum on release\n * press and hold, no move → select the word under the finger; keep dragging to extend\n *\n * Pure: the host feeds pointer samples and the long-press timeout, and acts on what comes back.\n */\n\nexport interface GestureSample {\n x: number;\n y: number;\n /** ms */\n t: number;\n}\n\nexport type GestureAction =\n | { kind: \"tap\"; x: number; y: number }\n /** Positive = toward newer output (finger moved up). Whole lines only; the remainder is kept. */\n | { kind: \"scroll\"; lines: number }\n /** Finger lifted mid-scroll: continue with `flingStep` from this velocity (lines/ms, same sign as scroll). */\n | { kind: \"fling\"; velocity: number }\n | { kind: \"select-start\"; x: number; y: number }\n | { kind: \"select-extend\"; x: number; y: number }\n | { kind: \"select-end\" };\n\nexport interface GestureOptions {\n /** Row height in px (font size × line height). */\n lineHeight: number;\n /** Movement under this many px is still a tap / hold. */\n slopPx?: number;\n}\n\n/** Press-and-hold time before selection starts (iOS text selection is ~500 ms; terminals use less). */\nexport const LONG_PRESS_MS = 450;\n/** Momentum decay per 16 ms frame. */\nexport const FLING_FRICTION = 0.95;\n/** Below this (lines/ms) momentum stops. */\nexport const FLING_STOP = 0.002;\n/** Releases slower than this (lines/ms) do not fling. */\nconst FLING_MIN = 0.01;\n\ntype Phase = \"idle\" | \"pressed\" | \"scrolling\" | \"selecting\";\n\nexport interface GestureRecognizer {\n down(s: GestureSample): GestureAction[];\n move(s: GestureSample): GestureAction[];\n up(s: GestureSample): GestureAction[];\n cancel(): GestureAction[];\n /** The host's long-press timer fired (LONG_PRESS_MS after down). */\n longPress(): GestureAction[];\n readonly phase: Phase;\n}\n\nexport function createGestureRecognizer(options: GestureOptions): GestureRecognizer {\n const slop = options.slopPx ?? 8;\n const lineHeight = Math.max(1, options.lineHeight);\n let phase: Phase = \"idle\";\n let start: GestureSample = { x: 0, y: 0, t: 0 };\n let last: GestureSample = start;\n let carryPx = 0;\n /** Recent samples for release velocity. */\n let trail: GestureSample[] = [];\n\n function scrollBy(fromY: number, toY: number): GestureAction[] {\n carryPx += fromY - toY;\n const lines = carryPx > 0 ? Math.floor(carryPx / lineHeight) : Math.ceil(carryPx / lineHeight);\n if (lines === 0) return [];\n carryPx -= lines * lineHeight;\n return [{ kind: \"scroll\", lines }];\n }\n\n return {\n get phase() {\n return phase;\n },\n down(s) {\n phase = \"pressed\";\n start = s;\n last = s;\n carryPx = 0;\n trail = [s];\n return [];\n },\n move(s) {\n if (phase === \"idle\") return [];\n const out: GestureAction[] = [];\n if (phase === \"pressed\") {\n if (Math.hypot(s.x - start.x, s.y - start.y) <= slop) return [];\n phase = \"scrolling\";\n }\n if (phase === \"scrolling\") {\n out.push(...scrollBy(last.y, s.y));\n trail.push(s);\n while (trail.length > 2 && s.t - trail[0]!.t > 100) trail.shift();\n } else if (phase === \"selecting\") {\n out.push({ kind: \"select-extend\", x: s.x, y: s.y });\n }\n last = s;\n return out;\n },\n up(s) {\n const was = phase;\n phase = \"idle\";\n if (was === \"pressed\") return [{ kind: \"tap\", x: start.x, y: start.y }];\n if (was === \"selecting\") return [{ kind: \"select-end\" }];\n if (was === \"scrolling\") {\n const out = scrollBy(last.y, s.y);\n trail.push(s);\n const first = trail[0]!;\n const dt = s.t - first.t;\n const velocity = dt > 0 ? (first.y - s.y) / dt / lineHeight : 0;\n if (Math.abs(velocity) >= FLING_MIN) out.push({ kind: \"fling\", velocity });\n return out;\n }\n return [];\n },\n cancel() {\n const was = phase;\n phase = \"idle\";\n return was === \"selecting\" ? [{ kind: \"select-end\" }] : [];\n },\n longPress() {\n if (phase !== \"pressed\") return [];\n phase = \"selecting\";\n return [{ kind: \"select-start\", x: start.x, y: start.y }];\n },\n };\n}\n\n/**\n * One momentum frame: how far to move (lines, fractional) and the decayed velocity. The host\n * accumulates the fractional lines and scrolls whole ones until `velocity` is 0.\n */\nexport function flingStep(velocity: number, dtMs: number): { lines: number; velocity: number } {\n const lines = velocity * dtMs;\n const next = velocity * Math.pow(FLING_FRICTION, dtMs / 16);\n return { lines, velocity: Math.abs(next) < FLING_STOP ? 0 : next };\n}\n","/**\n * Long-press selection math in buffer cells. Pure; the React layer maps touch points to cells.\n */\n\nexport interface Cell {\n col: number;\n /** Absolute buffer row (scrollback included). */\n row: number;\n}\n\n/** Characters that belong to a \"word\" for a long press: paths, URLs, flags and hosts select whole. */\nconst WORD = /[A-Za-z0-9_\\-./~:@%+=,?&#]/;\n\n/** [start, end) of the word at `col` in `line`; a one-cell range on a separator. */\nexport function wordBounds(line: string, col: number): { start: number; end: number } {\n const chars = Array.from(line);\n if (col < 0 || col >= chars.length || !WORD.test(chars[col] ?? \" \")) return { start: col, end: col + 1 };\n let start = col;\n let end = col + 1;\n while (start > 0 && WORD.test(chars[start - 1]!)) start--;\n while (end < chars.length && WORD.test(chars[end]!)) end++;\n return { start, end };\n}\n\n/**\n * xterm's `select(column, row, length)` for the span between two cells (either order), where a\n * span wraps at `cols`. `anchor` is the first selected cell; `focus` is included too.\n */\nexport function spanBetween(anchor: Cell, focus: Cell, cols: number): { col: number; row: number; length: number } {\n const a = anchor.row * cols + anchor.col;\n const b = focus.row * cols + focus.col;\n const from = Math.min(a, b);\n const to = Math.max(a, b);\n return { col: from % cols, row: Math.floor(from / cols), length: to - from + 1 };\n}\n\n/** The cell under a point, given the screen element's box and the grid size; clamped to the grid. */\nexport function cellAt(\n point: { x: number; y: number },\n box: { left: number; top: number; width: number; height: number },\n grid: { cols: number; rows: number; viewportY: number },\n): Cell {\n const cw = box.width / Math.max(1, grid.cols);\n const ch = box.height / Math.max(1, grid.rows);\n const col = Math.min(grid.cols - 1, Math.max(0, Math.floor((point.x - box.left) / cw)));\n const screenRow = Math.min(grid.rows - 1, Math.max(0, Math.floor((point.y - box.top) / ch)));\n return { col, row: grid.viewportY + screenRow };\n}\n","/**\n * Terminal look: font, metrics and the two palettes. One place, so every terminal in every app\n * renders the same.\n */\nimport type { ITheme } from \"@xterm/xterm\";\n\n/** The system monospace first: SF Mono on Apple platforms, then the usual fallbacks. */\nexport const TERMINAL_FONT_FAMILY = 'ui-monospace, \"SF Mono\", SFMono-Regular, Menlo, Consolas, \"Liberation Mono\", monospace';\n\nexport const TERMINAL_DEFAULTS = {\n fontSize: 13,\n lineHeight: 1.2,\n scrollback: 5000,\n /** Side padding inside the terminal box, px. */\n padding: 8,\n} as const;\n\n/** The keyboard accessory bar's height, px (styles.css .mxt-bar: 44px keys + 4px above and below). */\nexport const ACCESSORY_BAR_HEIGHT = 52;\n\n/** The range a person can zoom the terminal text to (pinch, ⌘+ / ⌘−). */\nexport const FONT_SIZE_MIN = 9;\nexport const FONT_SIZE_MAX = 24;\n\n/** ⌘+ / ⌘− steps one point; the result stays in range. */\nexport function stepFontSize(current: number, delta: number): number {\n return Math.min(FONT_SIZE_MAX, Math.max(FONT_SIZE_MIN, Math.round(current) + delta));\n}\n\n/** A pinch scales the size it started from by the change in finger distance, to whole points. */\nexport function pinchFontSize(startSize: number, startDistance: number, distance: number): number {\n if (startDistance <= 0) return startSize;\n return Math.min(FONT_SIZE_MAX, Math.max(FONT_SIZE_MIN, Math.round((startSize * distance) / startDistance)));\n}\n\nexport function terminalTheme(dark: boolean): ITheme {\n return dark\n ? {\n background: \"#1e1e1e\",\n foreground: \"#e4e4e7\",\n cursor: \"#e4e4e7\",\n cursorAccent: \"#1e1e1e\",\n black: \"#1e1e1e\",\n red: \"#f87171\",\n green: \"#4ade80\",\n yellow: \"#facc15\",\n blue: \"#60a5fa\",\n magenta: \"#c084fc\",\n cyan: \"#22d3ee\",\n white: \"#e5e7eb\",\n brightBlack: \"#71717a\",\n brightRed: \"#fca5a5\",\n brightGreen: \"#86efac\",\n brightYellow: \"#fde047\",\n brightBlue: \"#93c5fd\",\n brightMagenta: \"#d8b4fe\",\n brightCyan: \"#67e8f9\",\n brightWhite: \"#f4f4f5\",\n selectionBackground: \"#3b82f680\",\n }\n : {\n background: \"#ffffff\",\n foreground: \"#18181b\",\n cursor: \"#18181b\",\n cursorAccent: \"#ffffff\",\n black: \"#18181b\",\n red: \"#b91c1c\",\n green: \"#15803d\",\n yellow: \"#b45309\",\n blue: \"#1d4ed8\",\n magenta: \"#7c3aed\",\n cyan: \"#0e7490\",\n white: \"#d4d4d8\",\n brightBlack: \"#71717a\",\n brightRed: \"#dc2626\",\n brightGreen: \"#16a34a\",\n brightYellow: \"#d97706\",\n brightBlue: \"#2563eb\",\n brightMagenta: \"#9333ea\",\n brightCyan: \"#0891b2\",\n brightWhite: \"#a1a1aa\",\n selectionBackground: \"#93c5fd99\",\n };\n}\n","/**\n * Visual-viewport arithmetic: where the on-screen keyboard is, and how tall a terminal anchored\n * at `top` may be so its last row and the accessory bar sit exactly above the keyboard. iOS\n * Safari shrinks only the VISUAL viewport when the keyboard opens; the layout viewport (and every\n * `100dvh`) stays full height, so a `bottom: 0` element ends up behind the keyboard.\n */\n\nexport interface ViewportBox {\n height: number;\n offsetTop: number;\n}\n\n/**\n * Below this the difference is browser chrome (Safari's collapsing toolbar), not a keyboard.\n * The smallest phone keyboard (iPhone SE landscape) is ~160px.\n */\nexport const KEYBOARD_MIN_PX = 120;\n\n/** Height the keyboard (or any bottom overlay) takes out of the layout viewport; 0 when closed. */\nexport function keyboardInset(layoutHeight: number, vv: ViewportBox | null): number {\n if (!vv) return 0;\n const inset = Math.round(layoutHeight - vv.height - vv.offsetTop);\n return inset >= KEYBOARD_MIN_PX ? inset : 0;\n}\n\n/** Height from `top` (layout px) down to the bottom of what is visible. Never negative. */\nexport function visibleHeightBelow(top: number, vv: ViewportBox | null, layoutHeight: number): number {\n const bottom = vv ? vv.offsetTop + vv.height : layoutHeight;\n return Math.max(0, Math.floor(bottom - top));\n}\n","\"use client\";\n\n/**\n * The keyboard accessory bar: one 44px row of the keys a phone keyboard lacks, scrolling\n * sideways. Every key keeps the terminal focused (pointerdown is cancelled), so the keyboard\n * stays up while you tap Esc, arrows or Ctrl. Ctrl / Alt: tap = next key only, double-tap = locked.\n */\nimport type { ReactNode } from \"react\";\n\nimport { ACCESSORY_KEYS } from \"../core/keys\";\nimport type { AccessoryKeyDef, AccessoryKeyId } from \"../core/keys\";\nimport type { ModifierState } from \"../core/modifiers\";\n\nfunction PasteIcon() {\n return (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <rect x=\"8\" y=\"2\" width=\"8\" height=\"4\" rx=\"1\" />\n <path d=\"M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2\" />\n </svg>\n );\n}\n\nfunction HideKeyboardIcon() {\n return (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <rect x=\"2\" y=\"3\" width=\"20\" height=\"12\" rx=\"2\" />\n <path d=\"M6 7h.01M10 7h.01M14 7h.01M18 7h.01M7 11h10\" />\n <path d=\"m8 19 4 3 4-3\" />\n </svg>\n );\n}\n\nconst ICONS: Partial<Record<AccessoryKeyId, () => ReactNode>> = { paste: PasteIcon, hide: HideKeyboardIcon };\n\nexport interface AccessoryBarProps {\n ctrl: ModifierState;\n alt: ModifierState;\n onKey: (id: AccessoryKeyId) => void;\n}\n\nexport function AccessoryBar({ ctrl, alt, onKey }: AccessoryBarProps) {\n const groups: AccessoryKeyDef[][] = [];\n for (const key of ACCESSORY_KEYS) (groups[key.group] ??= []).push(key);\n return (\n <div className=\"mxt-bar\" role=\"toolbar\" aria-label=\"Terminal keys\">\n {groups.map((group, gi) => (\n <div key={gi} className=\"mxt-bar-group\">\n {gi > 0 ? <span className=\"mxt-bar-divider\" aria-hidden=\"true\" /> : null}\n {group.map((key) => {\n const state = key.id === \"ctrl\" ? ctrl : key.id === \"alt\" ? alt : null;\n const Icon = ICONS[key.id];\n return (\n <button\n key={key.id}\n type=\"button\"\n className=\"mxt-key\"\n data-state={state ?? undefined}\n aria-label={key.aria}\n aria-pressed={state === null ? undefined : state !== \"off\"}\n // Keep focus (and the keyboard) on the terminal.\n onPointerDown={(e) => e.preventDefault()}\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => onKey(key.id)}\n >\n {Icon ? <Icon /> : key.label}\n </button>\n );\n })}\n </div>\n ))}\n </div>\n );\n}\n"],"mappings":"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","names":["jsx","jsxs","current"]}
1
+ {"version":3,"sources":["../src/react/Terminal.tsx","../src/core/keys.ts","../src/core/modifiers.ts","../src/core/gesture.ts","../src/core/selection.ts","../src/core/theme.ts","../src/core/viewport.ts","../src/react/AccessoryBar.tsx"],"sourcesContent":["\"use client\";\n\n/**\n * <Terminal> — xterm 6 (DOM renderer) with everything a host would otherwise rebuild: fit to its\n * box or to the visual viewport, theme that follows the app's `.dark` class, Ctrl-C hook, phone\n * touch (momentum scroll, long-press word select, copy), and the keyboard accessory bar with\n * one-shot / locked Ctrl and Alt. Transport-free: bytes in through the handle's `write`, keys\n * out through `onData`, size out through `onResize`. Any PTY (desktop relay, cloud sandbox,\n * local process) plugs in with three lines.\n */\n// The package ships its stylesheets; importing them here means a host never forgets them. Both\n// stay as imports in the built bundle (tsup externals) for the host's bundler to place.\nimport \"@xterm/xterm/css/xterm.css\";\nimport \"@ai-matrx/terminal/styles.css\";\nimport { useEffect, useRef, useState } from \"react\";\nimport { copyText, readText } from \"@ai-matrx/kit/clipboard\";\nimport type { CSSProperties, ReactNode } from \"react\";\nimport type { ITerminalOptions, Terminal as XTerm } from \"@xterm/xterm\";\nimport type { FitAddon } from \"@xterm/addon-fit\";\n\nimport { ACCESSORY_KEYS, applyModifiers, keySequence } from \"../core/keys\";\nimport type { AccessoryKeyId } from \"../core/keys\";\nimport { MODIFIER_OFF, afterKey, isActive, tapModifier } from \"../core/modifiers\";\nimport type { ModifierLatch } from \"../core/modifiers\";\nimport { LONG_PRESS_MS, createGestureRecognizer, flingStep } from \"../core/gesture\";\nimport type { GestureAction } from \"../core/gesture\";\nimport { cellAt, spanBetween, wordBounds } from \"../core/selection\";\nimport type { Cell } from \"../core/selection\";\nimport { TERMINAL_DEFAULTS, TERMINAL_FONT_FAMILY, pinchFontSize, stepFontSize, terminalTheme } from \"../core/theme\";\nimport { visibleHeightBelow } from \"../core/viewport\";\nimport { AccessoryBar } from \"./AccessoryBar\";\n\nexport interface TerminalSize {\n cols: number;\n rows: number;\n}\n\n/** What a host drives the terminal with. Stable for the terminal's life. */\nexport interface TerminalHandle {\n /** Write output; resolves once xterm has parsed it (use it to pace credit-based streams). */\n write(data: string | Uint8Array): Promise<void>;\n /** Clear screen, scrollback and modes — before writing a fresh screen snapshot. */\n reset(): void;\n /** Clear the scrollback, keep the prompt line. */\n clear(): void;\n focus(): void;\n blur(): void;\n /** Visible text of the whole buffer (scrollback included), lines joined with \\n. */\n getText(): string;\n readonly cols: number;\n readonly rows: number;\n /** The underlying xterm, for what this package does not wrap (read-mostly use). */\n readonly xterm: XTerm;\n}\n\nexport interface TerminalProps {\n /** Keystrokes and pastes, already modified by the accessory bar's Ctrl / Alt. */\n onData?: (data: string) => void;\n /** Grid size after every fit (and once at start). */\n onResize?: (size: TerminalSize) => void;\n /**\n * The person zoomed the text: a pinch on touch, ⌘+ / ⌘− / ⌘0 with a keyboard. Pass it (and feed\n * the value back as `fontSize`) to turn zoom on; the host decides where the size is remembered.\n */\n onFontSizeChange?: (fontSize: number) => void;\n onReady?: (handle: TerminalHandle) => void;\n /**\n * Hardware Ctrl-C (no Shift/Alt/Meta). Return true to consume it — e.g. send a SIGINT frame\n * because the page's own shortcuts eat the key. Default: xterm sends ETX (0x03) through onData.\n */\n onInterrupt?: () => boolean;\n /** \"auto\" follows the `dark` class on <html>. */\n theme?: \"auto\" | \"dark\" | \"light\";\n fontSize?: number;\n lineHeight?: number;\n scrollback?: number;\n /** Side padding, px. */\n padding?: number;\n /** Translate bare \\n to \\r\\n (for line-oriented output that is not a PTY). */\n convertEol?: boolean;\n cursorBlink?: boolean;\n disableStdin?: boolean;\n /** Clickable URLs. Default true. */\n links?: boolean;\n /** Phone touch gestures. \"auto\" = when the primary pointer is coarse. */\n touch?: \"auto\" | \"on\" | \"off\";\n /** The keyboard accessory bar. \"auto\" = when the primary pointer is coarse. */\n accessory?: \"auto\" | \"on\" | \"off\";\n /**\n * \"container\": fill the parent box (it must have a height). \"viewport\": grow from where the\n * terminal starts down to the bottom of the VISUAL viewport, so the last row and the accessory\n * bar sit right above the on-screen keyboard.\n */\n fit?: \"container\" | \"viewport\";\n autoFocus?: boolean;\n className?: string;\n style?: CSSProperties;\n \"aria-label\"?: string;\n /** Rendered over the terminal (e.g. a reconnecting veil). */\n children?: ReactNode;\n}\n\ninterface Latches {\n ctrl: ModifierLatch;\n alt: ModifierLatch;\n}\n\nfunction prefersDark(): boolean {\n return typeof document !== \"undefined\" && document.documentElement.classList.contains(\"dark\");\n}\n\nfunction coarsePointer(): boolean {\n return typeof window !== \"undefined\" && typeof window.matchMedia === \"function\" && window.matchMedia(\"(pointer: coarse)\").matches;\n}\n\nexport function Terminal(props: TerminalProps) {\n const {\n theme = \"auto\",\n fontSize = TERMINAL_DEFAULTS.fontSize,\n lineHeight = TERMINAL_DEFAULTS.lineHeight,\n scrollback = TERMINAL_DEFAULTS.scrollback,\n padding = TERMINAL_DEFAULTS.padding,\n convertEol = false,\n cursorBlink = true,\n disableStdin = false,\n links = true,\n touch = \"auto\",\n accessory = \"auto\",\n fit = \"container\",\n autoFocus = false,\n } = props;\n\n const rootRef = useRef<HTMLDivElement | null>(null);\n const hostRef = useRef<HTMLDivElement | null>(null);\n const termRef = useRef<XTerm | null>(null);\n const fitRef = useRef<FitAddon | null>(null);\n const handleRef = useRef<TerminalHandle | null>(null);\n const latchRef = useRef<Latches>({ ctrl: MODIFIER_OFF, alt: MODIFIER_OFF });\n const callbacksRef = useRef({\n onData: props.onData,\n onResize: props.onResize,\n onReady: props.onReady,\n onInterrupt: props.onInterrupt,\n onFontSizeChange: props.onFontSizeChange,\n });\n const fontSizeRef = useRef(fontSize);\n\n const [latches, setLatches] = useState<Latches>({ ctrl: MODIFIER_OFF, alt: MODIFIER_OFF });\n const [coarse, setCoarse] = useState(false);\n const [dark, setDark] = useState(theme === \"dark\");\n const [copyVisible, setCopyVisible] = useState(false);\n const [viewportHeight, setViewportHeight] = useState<number | null>(null);\n const [booted, setBooted] = useState(false);\n\n useEffect(() => {\n callbacksRef.current = {\n onData: props.onData,\n onResize: props.onResize,\n onReady: props.onReady,\n onInterrupt: props.onInterrupt,\n onFontSizeChange: props.onFontSizeChange,\n };\n fontSizeRef.current = fontSize;\n });\n\n // Pointer class and theme are browser facts: read after mount (SSR renders the neutral frame).\n useEffect(() => {\n setCoarse(coarsePointer());\n const mq = typeof window.matchMedia === \"function\" ? window.matchMedia(\"(pointer: coarse)\") : null;\n const onChange = () => setCoarse(coarsePointer());\n mq?.addEventListener(\"change\", onChange);\n return () => mq?.removeEventListener(\"change\", onChange);\n }, []);\n\n useEffect(() => {\n if (theme !== \"auto\") {\n setDark(theme === \"dark\");\n return undefined;\n }\n setDark(prefersDark());\n if (typeof MutationObserver === \"undefined\") return undefined;\n const observer = new MutationObserver(() => setDark(prefersDark()));\n observer.observe(document.documentElement, { attributes: true, attributeFilter: [\"class\"] });\n return () => observer.disconnect();\n }, [theme]);\n\n const touchOn = touch === \"on\" || (touch === \"auto\" && coarse);\n const barOn = accessory === \"on\" || (accessory === \"auto\" && coarse);\n\n function setLatchState(next: Latches): void {\n latchRef.current = next;\n setLatches(next);\n }\n\n /** Keyboard input → accessory modifiers → host. */\n function emit(data: string): void {\n const current = latchRef.current;\n const mods = { ctrl: isActive(current.ctrl), alt: isActive(current.alt) };\n const { data: out, consumed } = applyModifiers(data, mods);\n if (consumed) setLatchState({ ctrl: afterKey(current.ctrl), alt: afterKey(current.alt) });\n callbacksRef.current.onData?.(out);\n }\n\n // ── boot xterm once ───────────────────────────────────────────────────────\n useEffect(() => {\n let cancelled = false;\n let disposeAll: (() => void) | null = null;\n void (async () => {\n const [{ Terminal: XTermCtor }, { FitAddon: FitCtor }, linksModule] = await Promise.all([\n import(\"@xterm/xterm\"),\n import(\"@xterm/addon-fit\"),\n import(\"@xterm/addon-web-links\"),\n ]);\n const host = hostRef.current;\n if (cancelled || !host) return;\n const options: ITerminalOptions = {\n fontFamily: TERMINAL_FONT_FAMILY,\n fontSize,\n lineHeight,\n scrollback,\n convertEol,\n cursorBlink,\n cursorStyle: \"bar\",\n disableStdin,\n allowProposedApi: false,\n theme: terminalTheme(theme === \"auto\" ? prefersDark() : theme === \"dark\"),\n };\n const term = new XTermCtor(options);\n const fitAddon = new FitCtor();\n term.loadAddon(fitAddon);\n if (links) term.loadAddon(new linksModule.WebLinksAddon());\n term.open(host);\n const textarea = term.textarea;\n if (textarea) {\n // iOS: no autocorrect/capitalisation in a shell; 16px stops the focus zoom (styles.css).\n textarea.setAttribute(\"autocorrect\", \"off\");\n textarea.setAttribute(\"autocapitalize\", \"off\");\n textarea.setAttribute(\"autocomplete\", \"off\");\n textarea.setAttribute(\"spellcheck\", \"false\");\n textarea.setAttribute(\"aria-label\", props[\"aria-label\"] ?? \"Terminal input\");\n }\n termRef.current = term;\n fitRef.current = fitAddon;\n\n const dataSub = term.onData((data) => emit(data));\n const resizeSub = term.onResize(({ cols, rows }) => callbacksRef.current.onResize?.({ cols, rows }));\n term.attachCustomKeyEventHandler((event) => {\n // ⌘+ / ⌘− / ⌘0 zoom the text (only when the host takes the size: onFontSizeChange).\n const zoom = callbacksRef.current.onFontSizeChange;\n if (zoom && event.type === \"keydown\" && event.metaKey && !event.altKey && !event.ctrlKey) {\n const delta = event.key === \"=\" || event.key === \"+\" ? 1 : event.key === \"-\" ? -1 : event.key === \"0\" ? 0 : null;\n if (delta !== null) {\n event.preventDefault();\n zoom(delta === 0 ? TERMINAL_DEFAULTS.fontSize : stepFontSize(fontSizeRef.current, delta));\n return false;\n }\n }\n if (\n event.type === \"keydown\" &&\n event.ctrlKey &&\n !event.shiftKey &&\n !event.altKey &&\n !event.metaKey &&\n event.key.toLowerCase() === \"c\" &&\n !term.hasSelection()\n ) {\n const consumed = callbacksRef.current.onInterrupt?.() ?? false;\n if (consumed) return false;\n }\n return true;\n });\n const selectionSub = term.onSelectionChange(() => setCopyVisible(term.hasSelection()));\n\n const handle: TerminalHandle = {\n write: (data) => new Promise<void>((resolve) => term.write(data, resolve)),\n reset: () => term.reset(),\n clear: () => term.clear(),\n focus: () => term.focus(),\n blur: () => term.blur(),\n getText: () => {\n const buffer = term.buffer.active;\n const lines: string[] = [];\n for (let y = 0; y < buffer.length; y++) lines.push(buffer.getLine(y)?.translateToString(true) ?? \"\");\n while (lines.length > 0 && lines[lines.length - 1] === \"\") lines.pop();\n return lines.join(\"\\n\");\n },\n get cols() {\n return term.cols;\n },\n get rows() {\n return term.rows;\n },\n xterm: term,\n };\n handleRef.current = handle;\n try {\n fitAddon.fit();\n } catch {\n // The box may not be laid out yet; the resize observer fits it when it is.\n }\n setBooted(true);\n callbacksRef.current.onResize?.({ cols: term.cols, rows: term.rows });\n callbacksRef.current.onReady?.(handle);\n if (autoFocus) term.focus();\n\n disposeAll = () => {\n dataSub.dispose();\n resizeSub.dispose();\n selectionSub.dispose();\n term.dispose();\n };\n })();\n return () => {\n cancelled = true;\n disposeAll?.();\n termRef.current = null;\n fitRef.current = null;\n handleRef.current = null;\n };\n // Boot exactly once per mount; later option changes are applied by the effects below.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // ── live options ──────────────────────────────────────────────────────────\n useEffect(() => {\n const term = termRef.current;\n if (!term) return;\n term.options.theme = terminalTheme(dark);\n }, [dark, booted]);\n\n useEffect(() => {\n const term = termRef.current;\n if (!term) return;\n term.options.disableStdin = disableStdin;\n term.options.fontSize = fontSize;\n term.options.lineHeight = lineHeight;\n try {\n fitRef.current?.fit();\n } catch {\n // between frames\n }\n }, [disableStdin, fontSize, lineHeight, booted]);\n\n // ── fit to the box ────────────────────────────────────────────────────────\n useEffect(() => {\n const host = hostRef.current;\n if (!host) return undefined;\n const refit = () => {\n const term = termRef.current;\n if (!term || host.clientWidth <= 0 || host.clientHeight <= 0) return;\n try {\n fitRef.current?.fit();\n // A DOM renderer mounted while hidden measured zero-width glyphs; refresh re-measures.\n term.refresh(0, term.rows - 1);\n } catch {\n // xterm is mid-paint\n }\n };\n refit();\n if (typeof ResizeObserver === \"undefined\") return undefined; // non-browser hosts (jsdom)\n const ro = new ResizeObserver(refit);\n ro.observe(host);\n return () => ro.disconnect();\n }, [booted]);\n\n // ── fit to the visual viewport (phones: stop exactly at the keyboard) ─────\n useEffect(() => {\n if (fit !== \"viewport\") {\n setViewportHeight(null);\n return undefined;\n }\n const root = rootRef.current;\n if (!root) return undefined;\n const vv = window.visualViewport;\n const measure = () => {\n // The console owns the screen: a page scrolled by iOS to \"reveal\" the input only hides the top.\n if (window.scrollY !== 0) window.scrollTo(0, 0);\n const top = root.getBoundingClientRect().top + window.scrollY;\n setViewportHeight(visibleHeightBelow(top, vv ? { height: vv.height, offsetTop: vv.offsetTop } : null, window.innerHeight));\n };\n measure();\n vv?.addEventListener(\"resize\", measure);\n vv?.addEventListener(\"scroll\", measure);\n window.addEventListener(\"resize\", measure);\n window.addEventListener(\"orientationchange\", measure);\n return () => {\n vv?.removeEventListener(\"resize\", measure);\n vv?.removeEventListener(\"scroll\", measure);\n window.removeEventListener(\"resize\", measure);\n window.removeEventListener(\"orientationchange\", measure);\n };\n }, [fit]);\n\n // ── touch: tap focuses, drag scrolls with momentum, hold selects ──────────\n useEffect(() => {\n const host = hostRef.current;\n const term = termRef.current;\n if (!touchOn || !host || !term) return undefined;\n // Re-created at each touch so a zoom (pinch, ⌘±) is already in the row height it scrolls by.\n let recognizer = createGestureRecognizer({ lineHeight: fontSizeRef.current * lineHeight });\n let holdTimer: ReturnType<typeof setTimeout> | null = null;\n let flingFrame: number | null = null;\n let flingCarry = 0;\n let anchor: Cell | null = null;\n\n const screen = () => (term.element?.querySelector(\".xterm-screen\") as HTMLElement | null) ?? host;\n const cellFor = (x: number, y: number): Cell => {\n const r = screen().getBoundingClientRect();\n return cellAt({ x, y }, { left: r.left, top: r.top, width: r.width, height: r.height }, { cols: term.cols, rows: term.rows, viewportY: term.buffer.active.viewportY });\n };\n const scrollLines = (lines: number) => {\n if (lines === 0) return;\n if (term.buffer.active.type === \"alternate\") {\n // Full-screen programs (less, vim, htop) own their screen: a drag pages them with arrows.\n const key = lines > 0 ? \"down\" : \"up\";\n const seq = keySequence(key, { ctrl: false, alt: false }, { applicationCursor: term.modes.applicationCursorKeysMode });\n if (seq) callbacksRef.current.onData?.(seq.repeat(Math.min(Math.abs(lines), 50)));\n return;\n }\n term.scrollLines(lines);\n };\n const stopFling = () => {\n if (flingFrame !== null) cancelAnimationFrame(flingFrame);\n flingFrame = null;\n flingCarry = 0;\n };\n const startFling = (velocity: number) => {\n stopFling();\n let v = velocity;\n let last = performance.now();\n const step = (now: number) => {\n const res = flingStep(v, now - last);\n last = now;\n v = res.velocity;\n flingCarry += res.lines;\n const whole = flingCarry > 0 ? Math.floor(flingCarry) : Math.ceil(flingCarry);\n if (whole !== 0) {\n flingCarry -= whole;\n scrollLines(whole);\n }\n flingFrame = v === 0 ? null : requestAnimationFrame(step);\n };\n flingFrame = requestAnimationFrame(step);\n };\n const act = (actions: GestureAction[]) => {\n for (const a of actions) {\n switch (a.kind) {\n case \"tap\":\n term.clearSelection();\n term.focus();\n break;\n case \"scroll\":\n scrollLines(a.lines);\n break;\n case \"fling\":\n startFling(a.velocity);\n break;\n case \"select-start\": {\n const cell = cellFor(a.x, a.y);\n const line = term.buffer.active.getLine(cell.row)?.translateToString(false) ?? \"\";\n const word = wordBounds(line, cell.col);\n anchor = { col: word.start, row: cell.row };\n term.select(word.start, cell.row, Math.max(1, word.end - word.start));\n navigator.vibrate?.(10);\n break;\n }\n case \"select-extend\": {\n if (!anchor) break;\n const span = spanBetween(anchor, cellFor(a.x, a.y), term.cols);\n term.select(span.col, span.row, span.length);\n break;\n }\n case \"select-end\":\n anchor = null;\n setCopyVisible(term.hasSelection());\n break;\n }\n }\n };\n const clearHold = () => {\n if (holdTimer !== null) clearTimeout(holdTimer);\n holdTimer = null;\n };\n /** Two fingers: pinch-zoom the TEXT (when the host takes the size), never the page. */\n let pinch: { startDistance: number; startSize: number } | null = null;\n const fingerDistance = (e: TouchEvent) => {\n const a = e.touches[0]!;\n const b = e.touches[1]!;\n return Math.hypot(a.clientX - b.clientX, a.clientY - b.clientY);\n };\n const onStart = (e: TouchEvent) => {\n if (e.touches.length === 2 && callbacksRef.current.onFontSizeChange) {\n e.preventDefault();\n clearHold();\n stopFling();\n act(recognizer.cancel());\n pinch = { startDistance: fingerDistance(e), startSize: fontSizeRef.current };\n return;\n }\n if (e.touches.length !== 1) {\n clearHold();\n act(recognizer.cancel());\n return; // more fingers, or no zoom wanted: leave it to the browser\n }\n const t = e.touches[0]!;\n e.preventDefault();\n stopFling();\n recognizer = createGestureRecognizer({ lineHeight: fontSizeRef.current * lineHeight });\n act(recognizer.down({ x: t.clientX, y: t.clientY, t: e.timeStamp }));\n clearHold();\n holdTimer = setTimeout(() => act(recognizer.longPress()), LONG_PRESS_MS);\n };\n const onMove = (e: TouchEvent) => {\n if (pinch && e.touches.length === 2) {\n e.preventDefault();\n const size = pinchFontSize(pinch.startSize, pinch.startDistance, fingerDistance(e));\n if (size !== fontSizeRef.current) {\n fontSizeRef.current = size;\n callbacksRef.current.onFontSizeChange?.(size);\n }\n return;\n }\n if (e.touches.length !== 1 || recognizer.phase === \"idle\") return;\n const t = e.touches[0]!;\n e.preventDefault();\n act(recognizer.move({ x: t.clientX, y: t.clientY, t: e.timeStamp }));\n if (recognizer.phase !== \"pressed\") clearHold();\n };\n const onEnd = (e: TouchEvent) => {\n if (pinch) {\n if (e.touches.length < 2) pinch = null;\n e.preventDefault();\n return;\n }\n clearHold();\n if (recognizer.phase === \"idle\") return;\n const t = e.changedTouches[0];\n e.preventDefault();\n act(recognizer.up({ x: t?.clientX ?? 0, y: t?.clientY ?? 0, t: e.timeStamp }));\n };\n const onCancel = () => {\n clearHold();\n act(recognizer.cancel());\n };\n host.addEventListener(\"touchstart\", onStart, { passive: false });\n host.addEventListener(\"touchmove\", onMove, { passive: false });\n host.addEventListener(\"touchend\", onEnd, { passive: false });\n host.addEventListener(\"touchcancel\", onCancel);\n return () => {\n clearHold();\n stopFling();\n host.removeEventListener(\"touchstart\", onStart);\n host.removeEventListener(\"touchmove\", onMove);\n host.removeEventListener(\"touchend\", onEnd);\n host.removeEventListener(\"touchcancel\", onCancel);\n };\n }, [touchOn, booted, lineHeight]);\n\n // ── accessory bar ─────────────────────────────────────────────────────────\n function onAccessoryKey(id: AccessoryKeyId): void {\n const term = termRef.current;\n if (!term) return;\n const def = ACCESSORY_KEYS.find((k) => k.id === id);\n if (!def) return;\n if (def.kind === \"modifier\") {\n const now = performance.now();\n const current = latchRef.current;\n setLatchState(id === \"ctrl\" ? { ...current, ctrl: tapModifier(current.ctrl, now) } : { ...current, alt: tapModifier(current.alt, now) });\n return;\n }\n if (id === \"hide\") {\n term.blur();\n term.textarea?.blur();\n return;\n }\n if (id === \"paste\") {\n // null = permission refused / unsupported: the system paste menu still works on the input.\n void readText().then((text) => {\n if (text) term.paste(text);\n });\n return;\n }\n const current = latchRef.current;\n const mods = { ctrl: isActive(current.ctrl), alt: isActive(current.alt) };\n const seq = keySequence(id, mods, { applicationCursor: term.modes.applicationCursorKeysMode });\n if (seq === null) return;\n if (mods.ctrl || mods.alt) setLatchState({ ctrl: afterKey(current.ctrl), alt: afterKey(current.alt) });\n callbacksRef.current.onData?.(seq);\n }\n\n function copySelection(): void {\n const term = termRef.current;\n if (!term) return;\n const text = term.getSelection();\n if (text) void copyText(text);\n term.clearSelection();\n setCopyVisible(false);\n }\n\n const rootStyle: CSSProperties = { ...props.style };\n if (viewportHeight !== null) rootStyle.height = viewportHeight;\n\n return (\n <div\n ref={rootRef}\n className={[\"mxt-root\", props.className].filter(Boolean).join(\" \")}\n style={rootStyle}\n data-touch={touchOn ? \"on\" : \"off\"}\n data-theme={dark ? \"dark\" : \"light\"}\n >\n <div className=\"mxt-frame\" style={{ background: terminalTheme(dark).background }}>\n <div ref={hostRef} className=\"mxt-host\" style={{ paddingLeft: padding, paddingRight: padding }} />\n {copyVisible ? (\n <button type=\"button\" className=\"mxt-copy\" onPointerDown={(e) => e.preventDefault()} onClick={copySelection}>\n Copy\n </button>\n ) : null}\n {props.children}\n </div>\n {barOn ? <AccessoryBar ctrl={latches.ctrl.state} alt={latches.alt.state} onKey={onAccessoryKey} /> : null}\n </div>\n );\n}\n","/**\n * The keyboard accessory bar's keys and the bytes each sends — the keys a phone keyboard lacks.\n * Pure: no DOM, no xterm. Sequences follow xterm's own encoding (CSI 1;<mod> for modified cursor\n * keys, SS3 in application cursor mode), so full-screen programs (vim, less, htop) read them\n * exactly as they read a desktop keyboard.\n */\n\nexport type AccessoryKeyId =\n | \"esc\"\n | \"tab\"\n | \"ctrl\"\n | \"alt\"\n | \"left\"\n | \"down\"\n | \"up\"\n | \"right\"\n | \"pipe\"\n | \"slash\"\n | \"tilde\"\n | \"dash\"\n | \"home\"\n | \"end\"\n | \"pgup\"\n | \"pgdn\"\n | \"paste\"\n | \"hide\";\n\nexport interface AccessoryKeyDef {\n id: AccessoryKeyId;\n /** What the key shows. */\n label: string;\n /** What a screen reader says. */\n aria: string;\n /** send = bytes to the PTY; modifier = Ctrl/Alt state; action = paste / hide keyboard. */\n kind: \"send\" | \"modifier\" | \"action\";\n /** Keys sharing a group sit together; a divider separates groups. */\n group: number;\n}\n\n/** Termius order: Esc Tab Ctrl Alt | ← ↓ ↑ → | | / ~ - | Home End PgUp PgDn | Paste, hide. */\nexport const ACCESSORY_KEYS: readonly AccessoryKeyDef[] = [\n { id: \"esc\", label: \"Esc\", aria: \"Escape\", kind: \"send\", group: 0 },\n { id: \"tab\", label: \"Tab\", aria: \"Tab\", kind: \"send\", group: 0 },\n { id: \"ctrl\", label: \"Ctrl\", aria: \"Control\", kind: \"modifier\", group: 0 },\n { id: \"alt\", label: \"Alt\", aria: \"Alt\", kind: \"modifier\", group: 0 },\n { id: \"left\", label: \"←\", aria: \"Left arrow\", kind: \"send\", group: 1 },\n { id: \"down\", label: \"↓\", aria: \"Down arrow\", kind: \"send\", group: 1 },\n { id: \"up\", label: \"↑\", aria: \"Up arrow\", kind: \"send\", group: 1 },\n { id: \"right\", label: \"→\", aria: \"Right arrow\", kind: \"send\", group: 1 },\n { id: \"pipe\", label: \"|\", aria: \"Pipe\", kind: \"send\", group: 2 },\n { id: \"slash\", label: \"/\", aria: \"Slash\", kind: \"send\", group: 2 },\n { id: \"tilde\", label: \"~\", aria: \"Tilde\", kind: \"send\", group: 2 },\n { id: \"dash\", label: \"-\", aria: \"Dash\", kind: \"send\", group: 2 },\n { id: \"home\", label: \"Home\", aria: \"Home\", kind: \"send\", group: 3 },\n { id: \"end\", label: \"End\", aria: \"End\", kind: \"send\", group: 3 },\n { id: \"pgup\", label: \"PgUp\", aria: \"Page up\", kind: \"send\", group: 3 },\n { id: \"pgdn\", label: \"PgDn\", aria: \"Page down\", kind: \"send\", group: 3 },\n { id: \"paste\", label: \"Paste\", aria: \"Paste\", kind: \"action\", group: 4 },\n { id: \"hide\", label: \"Hide\", aria: \"Hide keyboard\", kind: \"action\", group: 4 },\n];\n\nexport interface ActiveModifiers {\n ctrl: boolean;\n alt: boolean;\n}\n\nexport interface KeyModes {\n /** DECCKM — xterm's `modes.applicationCursorKeysMode`. */\n applicationCursor: boolean;\n}\n\nconst ESC = \"\\x1b\";\nconst CURSOR: Partial<Record<AccessoryKeyId, string>> = { up: \"A\", down: \"B\", right: \"C\", left: \"D\", home: \"H\", end: \"F\" };\nconst TILDE: Partial<Record<AccessoryKeyId, string>> = { pgup: \"5\", pgdn: \"6\" };\nconst LITERAL: Partial<Record<AccessoryKeyId, string>> = { pipe: \"|\", slash: \"/\", tilde: \"~\", dash: \"-\", tab: \"\\t\", esc: ESC };\n\n/** xterm's modifier parameter: 1 + shift(1) + alt(2) + ctrl(4). */\nfunction modParam(mods: ActiveModifiers): number {\n return 1 + (mods.alt ? 2 : 0) + (mods.ctrl ? 4 : 0);\n}\n\n/**\n * Bytes for a \"send\" key with the active modifiers applied, or null for a modifier/action key.\n * Modifiers on literal keys go through `applyModifiers` (Ctrl+/ → 0x1f, Alt+| → ESC |).\n */\nexport function keySequence(id: AccessoryKeyId, mods: ActiveModifiers, modes: KeyModes): string | null {\n const cursor = CURSOR[id];\n if (cursor !== undefined) {\n const m = modParam(mods);\n if (m > 1) return `${ESC}[1;${m}${cursor}`;\n return modes.applicationCursor ? `${ESC}O${cursor}` : `${ESC}[${cursor}`;\n }\n const tilde = TILDE[id];\n if (tilde !== undefined) {\n const m = modParam(mods);\n return m > 1 ? `${ESC}[${tilde};${m}~` : `${ESC}[${tilde}~`;\n }\n const literal = LITERAL[id];\n if (literal !== undefined) {\n if (id === \"tab\" && mods.ctrl === false && mods.alt === false) return literal;\n if (id === \"esc\") return mods.alt ? ESC + ESC : ESC;\n return applyModifiers(literal, mods).data;\n }\n return null;\n}\n\n/** Ctrl applied to one character, as a terminal keyboard encodes it; null when Ctrl has no code. */\nexport function controlCode(char: string): string | null {\n if (char.length !== 1) return null;\n const code = char.charCodeAt(0);\n if (code >= 0x61 && code <= 0x7a) return String.fromCharCode(code - 0x60); // a-z\n if (code >= 0x40 && code <= 0x5f) return String.fromCharCode(code - 0x40); // @ A-Z [ \\ ] ^ _\n switch (char) {\n case \" \":\n case \"2\":\n return \"\\x00\";\n case \"3\":\n return \"\\x1b\";\n case \"4\":\n return \"\\x1c\";\n case \"5\":\n return \"\\x1d\";\n case \"6\":\n return \"\\x1e\";\n case \"7\":\n case \"/\":\n case \"-\":\n return \"\\x1f\";\n case \"8\":\n case \"?\":\n return \"\\x7f\";\n default:\n return null;\n }\n}\n\n/**\n * Apply one-shot or locked modifiers to what the keyboard typed. Only a single key press is\n * modified — a paste or a multi-character IME commit passes through and does NOT consume the\n * modifier, so \"Ctrl, then paste\" never mangles the paste.\n */\nexport function applyModifiers(data: string, mods: ActiveModifiers): { data: string; consumed: boolean } {\n if (!mods.ctrl && !mods.alt) return { data, consumed: false };\n const chars = Array.from(data);\n if (chars.length !== 1) {\n // A cursor key typed on a hardware keyboard while Ctrl/Alt are latched: re-encode it.\n const m = /^\\x1b(?:\\[|O)([ABCDHF])$/.exec(data);\n if (m) return { data: `${ESC}[1;${modParam(mods)}${m[1]}`, consumed: true };\n return { data, consumed: false };\n }\n let out = data;\n if (mods.ctrl) {\n const ctl = controlCode(data);\n if (ctl !== null) out = ctl;\n }\n if (mods.alt) out = ESC + out;\n return { data: out, consumed: true };\n}\n","/**\n * Ctrl / Alt on the accessory bar: tap once = the next key only; tap twice quickly = locked until\n * tapped again. Pure state machine; the clock is passed in.\n */\n\nexport type ModifierState = \"off\" | \"once\" | \"locked\";\n\nexport interface ModifierLatch {\n state: ModifierState;\n /** When the latch was last tapped (ms), for double-tap detection. */\n tappedAt: number | null;\n}\n\n/** Two taps within this window lock the modifier (iOS's own double-tap timing for Shift lock). */\nexport const DOUBLE_TAP_MS = 350;\n\nexport const MODIFIER_OFF: ModifierLatch = { state: \"off\", tappedAt: null };\n\nexport function tapModifier(latch: ModifierLatch, now: number): ModifierLatch {\n switch (latch.state) {\n case \"off\":\n return { state: \"once\", tappedAt: now };\n case \"once\":\n return latch.tappedAt !== null && now - latch.tappedAt <= DOUBLE_TAP_MS\n ? { state: \"locked\", tappedAt: now }\n : { state: \"off\", tappedAt: now };\n case \"locked\":\n return { state: \"off\", tappedAt: now };\n }\n}\n\n/** After a key used the modifier: a one-shot latch releases, a locked one holds. */\nexport function afterKey(latch: ModifierLatch): ModifierLatch {\n return latch.state === \"once\" ? { state: \"off\", tappedAt: latch.tappedAt } : latch;\n}\n\nexport function isActive(latch: ModifierLatch): boolean {\n return latch.state !== \"off\";\n}\n","/**\n * One-finger gestures on a terminal, as iOS terminals (Termius, Blink) read them:\n *\n * tap → focus (opens the keyboard)\n * drag up / down → scroll the scrollback, by whole lines, with momentum on release\n * press and hold, no move → select the word under the finger; keep dragging to extend\n *\n * Pure: the host feeds pointer samples and the long-press timeout, and acts on what comes back.\n */\n\nexport interface GestureSample {\n x: number;\n y: number;\n /** ms */\n t: number;\n}\n\nexport type GestureAction =\n | { kind: \"tap\"; x: number; y: number }\n /** Positive = toward newer output (finger moved up). Whole lines only; the remainder is kept. */\n | { kind: \"scroll\"; lines: number }\n /** Finger lifted mid-scroll: continue with `flingStep` from this velocity (lines/ms, same sign as scroll). */\n | { kind: \"fling\"; velocity: number }\n | { kind: \"select-start\"; x: number; y: number }\n | { kind: \"select-extend\"; x: number; y: number }\n | { kind: \"select-end\" };\n\nexport interface GestureOptions {\n /** Row height in px (font size × line height). */\n lineHeight: number;\n /** Movement under this many px is still a tap / hold. */\n slopPx?: number;\n}\n\n/** Press-and-hold time before selection starts (iOS text selection is ~500 ms; terminals use less). */\nexport const LONG_PRESS_MS = 450;\n/** Momentum decay per 16 ms frame. */\nexport const FLING_FRICTION = 0.95;\n/** Below this (lines/ms) momentum stops. */\nexport const FLING_STOP = 0.002;\n/** Releases slower than this (lines/ms) do not fling. */\nconst FLING_MIN = 0.01;\n\ntype Phase = \"idle\" | \"pressed\" | \"scrolling\" | \"selecting\";\n\nexport interface GestureRecognizer {\n down(s: GestureSample): GestureAction[];\n move(s: GestureSample): GestureAction[];\n up(s: GestureSample): GestureAction[];\n cancel(): GestureAction[];\n /** The host's long-press timer fired (LONG_PRESS_MS after down). */\n longPress(): GestureAction[];\n readonly phase: Phase;\n}\n\nexport function createGestureRecognizer(options: GestureOptions): GestureRecognizer {\n const slop = options.slopPx ?? 8;\n const lineHeight = Math.max(1, options.lineHeight);\n let phase: Phase = \"idle\";\n let start: GestureSample = { x: 0, y: 0, t: 0 };\n let last: GestureSample = start;\n let carryPx = 0;\n /** Recent samples for release velocity. */\n let trail: GestureSample[] = [];\n\n function scrollBy(fromY: number, toY: number): GestureAction[] {\n carryPx += fromY - toY;\n const lines = carryPx > 0 ? Math.floor(carryPx / lineHeight) : Math.ceil(carryPx / lineHeight);\n if (lines === 0) return [];\n carryPx -= lines * lineHeight;\n return [{ kind: \"scroll\", lines }];\n }\n\n return {\n get phase() {\n return phase;\n },\n down(s) {\n phase = \"pressed\";\n start = s;\n last = s;\n carryPx = 0;\n trail = [s];\n return [];\n },\n move(s) {\n if (phase === \"idle\") return [];\n const out: GestureAction[] = [];\n if (phase === \"pressed\") {\n if (Math.hypot(s.x - start.x, s.y - start.y) <= slop) return [];\n phase = \"scrolling\";\n }\n if (phase === \"scrolling\") {\n out.push(...scrollBy(last.y, s.y));\n trail.push(s);\n while (trail.length > 2 && s.t - trail[0]!.t > 100) trail.shift();\n } else if (phase === \"selecting\") {\n out.push({ kind: \"select-extend\", x: s.x, y: s.y });\n }\n last = s;\n return out;\n },\n up(s) {\n const was = phase;\n phase = \"idle\";\n if (was === \"pressed\") return [{ kind: \"tap\", x: start.x, y: start.y }];\n if (was === \"selecting\") return [{ kind: \"select-end\" }];\n if (was === \"scrolling\") {\n const out = scrollBy(last.y, s.y);\n trail.push(s);\n const first = trail[0]!;\n const dt = s.t - first.t;\n const velocity = dt > 0 ? (first.y - s.y) / dt / lineHeight : 0;\n if (Math.abs(velocity) >= FLING_MIN) out.push({ kind: \"fling\", velocity });\n return out;\n }\n return [];\n },\n cancel() {\n const was = phase;\n phase = \"idle\";\n return was === \"selecting\" ? [{ kind: \"select-end\" }] : [];\n },\n longPress() {\n if (phase !== \"pressed\") return [];\n phase = \"selecting\";\n return [{ kind: \"select-start\", x: start.x, y: start.y }];\n },\n };\n}\n\n/**\n * One momentum frame: how far to move (lines, fractional) and the decayed velocity. The host\n * accumulates the fractional lines and scrolls whole ones until `velocity` is 0.\n */\nexport function flingStep(velocity: number, dtMs: number): { lines: number; velocity: number } {\n const lines = velocity * dtMs;\n const next = velocity * Math.pow(FLING_FRICTION, dtMs / 16);\n return { lines, velocity: Math.abs(next) < FLING_STOP ? 0 : next };\n}\n","/**\n * Long-press selection math in buffer cells. Pure; the React layer maps touch points to cells.\n */\n\nexport interface Cell {\n col: number;\n /** Absolute buffer row (scrollback included). */\n row: number;\n}\n\n/** Characters that belong to a \"word\" for a long press: paths, URLs, flags and hosts select whole. */\nconst WORD = /[A-Za-z0-9_\\-./~:@%+=,?&#]/;\n\n/** [start, end) of the word at `col` in `line`; a one-cell range on a separator. */\nexport function wordBounds(line: string, col: number): { start: number; end: number } {\n const chars = Array.from(line);\n if (col < 0 || col >= chars.length || !WORD.test(chars[col] ?? \" \")) return { start: col, end: col + 1 };\n let start = col;\n let end = col + 1;\n while (start > 0 && WORD.test(chars[start - 1]!)) start--;\n while (end < chars.length && WORD.test(chars[end]!)) end++;\n return { start, end };\n}\n\n/**\n * xterm's `select(column, row, length)` for the span between two cells (either order), where a\n * span wraps at `cols`. `anchor` is the first selected cell; `focus` is included too.\n */\nexport function spanBetween(anchor: Cell, focus: Cell, cols: number): { col: number; row: number; length: number } {\n const a = anchor.row * cols + anchor.col;\n const b = focus.row * cols + focus.col;\n const from = Math.min(a, b);\n const to = Math.max(a, b);\n return { col: from % cols, row: Math.floor(from / cols), length: to - from + 1 };\n}\n\n/** The cell under a point, given the screen element's box and the grid size; clamped to the grid. */\nexport function cellAt(\n point: { x: number; y: number },\n box: { left: number; top: number; width: number; height: number },\n grid: { cols: number; rows: number; viewportY: number },\n): Cell {\n const cw = box.width / Math.max(1, grid.cols);\n const ch = box.height / Math.max(1, grid.rows);\n const col = Math.min(grid.cols - 1, Math.max(0, Math.floor((point.x - box.left) / cw)));\n const screenRow = Math.min(grid.rows - 1, Math.max(0, Math.floor((point.y - box.top) / ch)));\n return { col, row: grid.viewportY + screenRow };\n}\n","/**\n * Terminal look: font, metrics and the two palettes. One place, so every terminal in every app\n * renders the same.\n */\nimport type { ITheme } from \"@xterm/xterm\";\n\n/** The system monospace first: SF Mono on Apple platforms, then the usual fallbacks. */\nexport const TERMINAL_FONT_FAMILY = 'ui-monospace, \"SF Mono\", SFMono-Regular, Menlo, Consolas, \"Liberation Mono\", monospace';\n\nexport const TERMINAL_DEFAULTS = {\n fontSize: 13,\n lineHeight: 1.2,\n scrollback: 5000,\n /** Side padding inside the terminal box, px. */\n padding: 8,\n} as const;\n\n/** The keyboard accessory bar's height, px (styles.css .mxt-bar: 44px keys + 4px above and below). */\nexport const ACCESSORY_BAR_HEIGHT = 52;\n\n/** The range a person can zoom the terminal text to (pinch, ⌘+ / ⌘−). */\nexport const FONT_SIZE_MIN = 9;\nexport const FONT_SIZE_MAX = 24;\n\n/** ⌘+ / ⌘− steps one point; the result stays in range. */\nexport function stepFontSize(current: number, delta: number): number {\n return Math.min(FONT_SIZE_MAX, Math.max(FONT_SIZE_MIN, Math.round(current) + delta));\n}\n\n/** A pinch scales the size it started from by the change in finger distance, to whole points. */\nexport function pinchFontSize(startSize: number, startDistance: number, distance: number): number {\n if (startDistance <= 0) return startSize;\n return Math.min(FONT_SIZE_MAX, Math.max(FONT_SIZE_MIN, Math.round((startSize * distance) / startDistance)));\n}\n\nexport function terminalTheme(dark: boolean): ITheme {\n return dark\n ? {\n background: \"#1e1e1e\",\n foreground: \"#e4e4e7\",\n cursor: \"#e4e4e7\",\n cursorAccent: \"#1e1e1e\",\n black: \"#1e1e1e\",\n red: \"#f87171\",\n green: \"#4ade80\",\n yellow: \"#facc15\",\n blue: \"#60a5fa\",\n magenta: \"#c084fc\",\n cyan: \"#22d3ee\",\n white: \"#e5e7eb\",\n brightBlack: \"#71717a\",\n brightRed: \"#fca5a5\",\n brightGreen: \"#86efac\",\n brightYellow: \"#fde047\",\n brightBlue: \"#93c5fd\",\n brightMagenta: \"#d8b4fe\",\n brightCyan: \"#67e8f9\",\n brightWhite: \"#f4f4f5\",\n selectionBackground: \"#3b82f680\",\n }\n : {\n background: \"#ffffff\",\n foreground: \"#18181b\",\n cursor: \"#18181b\",\n cursorAccent: \"#ffffff\",\n black: \"#18181b\",\n red: \"#b91c1c\",\n green: \"#15803d\",\n yellow: \"#b45309\",\n blue: \"#1d4ed8\",\n magenta: \"#7c3aed\",\n cyan: \"#0e7490\",\n white: \"#d4d4d8\",\n brightBlack: \"#71717a\",\n brightRed: \"#dc2626\",\n brightGreen: \"#16a34a\",\n brightYellow: \"#d97706\",\n brightBlue: \"#2563eb\",\n brightMagenta: \"#9333ea\",\n brightCyan: \"#0891b2\",\n brightWhite: \"#a1a1aa\",\n selectionBackground: \"#93c5fd99\",\n };\n}\n","/**\n * Visual-viewport arithmetic: where the on-screen keyboard is, and how tall a terminal anchored\n * at `top` may be so its last row and the accessory bar sit exactly above the keyboard. iOS\n * Safari shrinks only the VISUAL viewport when the keyboard opens; the layout viewport (and every\n * `100dvh`) stays full height, so a `bottom: 0` element ends up behind the keyboard.\n */\n\nexport interface ViewportBox {\n height: number;\n offsetTop: number;\n}\n\n/**\n * Below this the difference is browser chrome (Safari's collapsing toolbar), not a keyboard.\n * The smallest phone keyboard (iPhone SE landscape) is ~160px.\n */\nexport const KEYBOARD_MIN_PX = 120;\n\n/** Height the keyboard (or any bottom overlay) takes out of the layout viewport; 0 when closed. */\nexport function keyboardInset(layoutHeight: number, vv: ViewportBox | null): number {\n if (!vv) return 0;\n const inset = Math.round(layoutHeight - vv.height - vv.offsetTop);\n return inset >= KEYBOARD_MIN_PX ? inset : 0;\n}\n\n/** Height from `top` (layout px) down to the bottom of what is visible. Never negative. */\nexport function visibleHeightBelow(top: number, vv: ViewportBox | null, layoutHeight: number): number {\n const bottom = vv ? vv.offsetTop + vv.height : layoutHeight;\n return Math.max(0, Math.floor(bottom - top));\n}\n","\"use client\";\n\n/**\n * The keyboard accessory bar: one 44px row of the keys a phone keyboard lacks, scrolling\n * sideways. Every key keeps the terminal focused (pointerdown is cancelled), so the keyboard\n * stays up while you tap Esc, arrows or Ctrl. Ctrl / Alt: tap = next key only, double-tap = locked.\n */\nimport type { ReactNode } from \"react\";\n\nimport { ACCESSORY_KEYS } from \"../core/keys\";\nimport type { AccessoryKeyDef, AccessoryKeyId } from \"../core/keys\";\nimport type { ModifierState } from \"../core/modifiers\";\n\nfunction PasteIcon() {\n return (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <rect x=\"8\" y=\"2\" width=\"8\" height=\"4\" rx=\"1\" />\n <path d=\"M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2\" />\n </svg>\n );\n}\n\nfunction HideKeyboardIcon() {\n return (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <rect x=\"2\" y=\"3\" width=\"20\" height=\"12\" rx=\"2\" />\n <path d=\"M6 7h.01M10 7h.01M14 7h.01M18 7h.01M7 11h10\" />\n <path d=\"m8 19 4 3 4-3\" />\n </svg>\n );\n}\n\nconst ICONS: Partial<Record<AccessoryKeyId, () => ReactNode>> = { paste: PasteIcon, hide: HideKeyboardIcon };\n\nexport interface AccessoryBarProps {\n ctrl: ModifierState;\n alt: ModifierState;\n onKey: (id: AccessoryKeyId) => void;\n}\n\nexport function AccessoryBar({ ctrl, alt, onKey }: AccessoryBarProps) {\n const groups: AccessoryKeyDef[][] = [];\n for (const key of ACCESSORY_KEYS) (groups[key.group] ??= []).push(key);\n return (\n <div className=\"mxt-bar\" role=\"toolbar\" aria-label=\"Terminal keys\">\n {groups.map((group, gi) => (\n <div key={gi} className=\"mxt-bar-group\">\n {gi > 0 ? <span className=\"mxt-bar-divider\" aria-hidden=\"true\" /> : null}\n {group.map((key) => {\n const state = key.id === \"ctrl\" ? ctrl : key.id === \"alt\" ? alt : null;\n const Icon = ICONS[key.id];\n return (\n <button\n key={key.id}\n type=\"button\"\n className=\"mxt-key\"\n data-state={state ?? undefined}\n aria-label={key.aria}\n aria-pressed={state === null ? undefined : state !== \"off\"}\n // Keep focus (and the keyboard) on the terminal.\n onPointerDown={(e) => e.preventDefault()}\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => onKey(key.id)}\n >\n {Icon ? <Icon /> : key.label}\n </button>\n );\n })}\n </div>\n ))}\n </div>\n );\n}\n"],"mappings":"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","names":["jsx","jsxs","current"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-matrx/terminal",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "The AI Matrx terminal: xterm 6 with fit (to its box or to the visual viewport above an on-screen keyboard), a theme that follows the app, a transport-free handle any PTY drives, phone-grade touch (momentum scroll, long-press word select, copy), a Termius-style keyboard accessory bar with one-shot and locked Ctrl/Alt, and a shell line editor (prompt, editing, history, Ctrl-C/L, multi-line paste, typeahead) for backends that run one command per call.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -59,7 +59,8 @@
59
59
  "dependencies": {
60
60
  "@xterm/addon-fit": "^0.11.0",
61
61
  "@xterm/addon-web-links": "^0.12.0",
62
- "@xterm/xterm": "^6.0.0"
62
+ "@xterm/xterm": "^6.0.0",
63
+ "@ai-matrx/kit": "latest"
63
64
  },
64
65
  "peerDependencies": {
65
66
  "react": ">=18.0.0",