@alchemy.run/sigil 0.0.0-alpha.8 → 0.1.0-alpha.1

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.
Files changed (40) hide show
  1. package/README.md +176 -0
  2. package/THIRD_PARTY_NOTICES.md +28 -0
  3. package/dist/ansi.d.ts +53 -53
  4. package/dist/capabilities.js +1 -1
  5. package/dist/{color-policy-DlrZXC0f.js → color-policy-BAC9-TZX.js} +15 -1
  6. package/dist/color.d.ts +8 -8
  7. package/dist/{devtools-DbthxoD1.js → devtools-B_2SDRaO.js} +3 -0
  8. package/dist/index.d.ts +209 -42
  9. package/dist/index.js +354 -171
  10. package/dist/jsx-dev-runtime.d.ts +3 -0
  11. package/dist/jsx-dev-runtime.js +7 -0
  12. package/dist/jsx-runtime-BS_OosoY.js +42 -0
  13. package/dist/jsx-runtime.d.ts +2 -0
  14. package/dist/jsx-runtime.js +8 -0
  15. package/dist/react-CeO3oT_g.js +394 -0
  16. package/dist/react.d.ts +2 -0
  17. package/dist/react.js +50 -0
  18. package/dist/rolldown-runtime-BPOCksWG.js +24 -0
  19. package/dist/router.d.ts +26 -26
  20. package/dist/router.js +45 -42
  21. package/dist/{session-Cg6STjFV.js → session-DDQ5V300.js} +34 -11
  22. package/dist/terminal.d.ts +9 -10
  23. package/dist/terminal.js +1 -1
  24. package/dist/use-focus-B1WVNBQm.js +8383 -0
  25. package/package.json +27 -15
  26. package/src/ansi/strip.ts +2 -2
  27. package/src/capabilities/query.ts +22 -0
  28. package/src/components/VirtualList.tsx +128 -0
  29. package/src/devtools.ts +5 -0
  30. package/src/hooks/use-virtual-scroll.ts +84 -0
  31. package/src/hooks/use-window-size.ts +10 -3
  32. package/src/index.ts +8 -0
  33. package/src/input-parser.ts +31 -11
  34. package/src/jsx-dev-runtime.ts +3 -0
  35. package/src/jsx-runtime.ts +6 -0
  36. package/src/react.ts +53 -0
  37. package/src/reconciler.ts +51 -0
  38. package/src/terminal/input.ts +11 -5
  39. package/src/virtual-scroll.ts +133 -0
  40. package/dist/use-focus-BNG0xsb7.js +0 -1337
package/dist/index.js CHANGED
@@ -1,14 +1,17 @@
1
+ import { n as __toESM } from "./rolldown-runtime-BPOCksWG.js";
2
+ import { t as require_react } from "./react-CeO3oT_g.js";
3
+ import { _ as squashTextNodes, a as reconciler, b as require_react_reconciler, c as kittyModifiers, d as FocusContext, f as Text, g as transformAnsiLine, h as emitLayoutListeners, i as useStdinContext, l as resolveFlags, m as createNode, n as useInput, o as detectKittySupport, p as addLayoutListener, r as useStdin, s as kittyFlags, t as useFocus, u as StdinContext, v as accessibilityContext, y as require_constants } from "./use-focus-B1WVNBQm.js";
1
4
  import { C as bsu, S as ansiEscapes, V as esu, W as link, _ as CSI } from "./sgr-BhwaWAJB.js";
2
5
  import { h as tokenizeAnsi, p as graphemes } from "./tokenize-AjqbvtiT.js";
3
6
  import { t as stringWidth } from "./string-width-CijQwpIk.js";
4
7
  import { n as sliceAnsi, r as wrapAnsi } from "./truncate-D31fhU6i.js";
5
- import { _ as squashTextNodes, a as reconciler, c as kittyModifiers, d as FocusContext, f as Text, g as transformAnsiLine, h as emitLayoutListeners, i as useStdinContext, l as resolveFlags, m as createNode, n as useInput, o as detectKittySupport, p as addLayoutListener, r as useStdin, s as kittyFlags, t as useFocus, u as StdinContext, v as accessibilityContext } from "./use-focus-BNG0xsb7.js";
6
8
  import { a as isTty, i as isSigilDev, o as isWindows, r as isScreenReader, t as isInCi } from "./env-YVw64yZS.js";
7
9
  import { a as detectTerminal, i as detectHyperlinkSupport, n as detectCapabilities, o as detectUnicodeSupport, r as detectColorLevel, s as signalExit, t as createSupportsColor } from "./detect-B3dL4Q11.js";
8
10
  import { u as cliCursor } from "./osc-BFKKSqpg.js";
9
- import { a as registerTerminalIntegration, c as ensureTerminalQuery, d as queryTerminal, f as refreshTerminalQuery, i as getCapabilities, l as getTerminalQuery, o as getRawModeStream, r as capabilities, s as applyTerminalQuery, u as getTerminalQueryPromise } from "./color-policy-DlrZXC0f.js";
10
- import { a as buildCursorSuffix, c as hideCursorEscape, i as buildCursorOnlySequence, o as buildReturnToBottomPrefix, s as cursorPositionChanged, t as TerminalSession } from "./session-Cg6STjFV.js";
11
+ import { a as registerTerminalIntegration, c as ensureTerminalQuery, f as queryTerminal, i as getCapabilities, l as getTerminalQuery, o as getRawModeStream, p as refreshTerminalQuery, r as capabilities, s as applyTerminalQuery, u as getTerminalQueryPromise } from "./color-policy-BAC9-TZX.js";
12
+ import { a as buildCursorSuffix, c as hideCursorEscape, i as buildCursorOnlySequence, o as buildReturnToBottomPrefix, s as cursorPositionChanged, t as TerminalSession } from "./session-DDQ5V300.js";
11
13
  import { t as Yoga } from "./yoga-5jKhYCJC.js";
14
+ import { t as require_jsx_runtime } from "./jsx-runtime-BS_OosoY.js";
12
15
  import { r as createCell, t as cellAttributes } from "./cell-_ZVhbfl0.js";
13
16
  import { i as semanticTextStyleToCellStyle, n as mergeSemanticTextStyles, t as emptySemanticTextStyle } from "./semantic-text-style-DIMzC7xt.js";
14
17
  import { a as samplePaint } from "./sample-Cqw1bjUL.js";
@@ -20,16 +23,14 @@ import "./color-CkbalRqK.js";
20
23
  import { PassThrough, Stream } from "node:stream";
21
24
  import { setImmediate as setImmediate$1 } from "node:timers/promises";
22
25
  import { isNativeError } from "node:util/types";
23
- import { PureComponent, createContext, useCallback, useContext, useEffect, useEffectEvent, useInsertionEffect, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
24
- import "react-reconciler";
25
- import { ConcurrentRoot, LegacyRoot } from "react-reconciler/constants.js";
26
26
  import { EventEmitter } from "node:events";
27
27
  import { existsSync, readFileSync } from "node:fs";
28
28
  import { cwd } from "node:process";
29
- import { jsx, jsxs } from "react/jsx-runtime";
30
29
  import { Console } from "node:console";
31
- //#region src/components/AnimationContext.ts
32
- const animationContext = createContext({
30
+ require_react_reconciler();
31
+ var import_constants = require_constants();
32
+ var import_react = /* @__PURE__ */ __toESM(require_react(), 1);
33
+ const animationContext = (0, import_react.createContext)({
33
34
  renderThrottleMs: 0,
34
35
  subscribe() {
35
36
  return {
@@ -48,7 +49,7 @@ const noopSuspension = {
48
49
  async resume() {},
49
50
  async [Symbol.asyncDispose]() {}
50
51
  };
51
- const AppContext = createContext({
52
+ const AppContext = (0, import_react.createContext)({
52
53
  exit(_errorOrResult) {},
53
54
  async waitUntilRenderFlush() {},
54
55
  suspendTerminal: (async (callback) => {
@@ -62,7 +63,7 @@ const AppContext = createContext({
62
63
  AppContext.displayName = "InternalAppContext";
63
64
  //#endregion
64
65
  //#region src/components/CursorContext.ts
65
- const CursorContext = createContext({ setCursorPosition() {} });
66
+ const CursorContext = (0, import_react.createContext)({ setCursorPosition() {} });
66
67
  CursorContext.displayName = "InternalCursorContext";
67
68
  //#endregion
68
69
  //#region src/code-excerpt.ts
@@ -168,14 +169,15 @@ const BOXES = {
168
169
  //#endregion
169
170
  //#region src/components/Box.tsx
170
171
  /** @jsxImportSource react */
172
+ var import_jsx_runtime = require_jsx_runtime();
171
173
  /**
172
174
  `<Box>` is an essential Ink component to build your layout. It's like `<div style="display: flex">` in the browser.
173
175
  */
174
176
  function Box({ children, ref, backgroundColor, "aria-label": ariaLabel, "aria-hidden": ariaHidden, "aria-role": role, "aria-state": ariaState, ...style }) {
175
- const { isScreenReaderEnabled } = useContext(accessibilityContext);
176
- const label = ariaLabel ? /* @__PURE__ */ jsx("ink-text", { children: ariaLabel }) : void 0;
177
+ const { isScreenReaderEnabled } = (0, import_react.useContext)(accessibilityContext);
178
+ const label = ariaLabel ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ink-text", { children: ariaLabel }) : void 0;
177
179
  if (isScreenReaderEnabled && ariaHidden) return null;
178
- return /* @__PURE__ */ jsx("ink-box", {
180
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ink-box", {
179
181
  ref,
180
182
  style: {
181
183
  flexWrap: "nowrap",
@@ -273,11 +275,11 @@ function ErrorOverview({ error }) {
273
275
  excerpt = codeExcerpt(sourceCode, origin.line);
274
276
  if (excerpt) for (const { line } of excerpt) lineWidth = Math.max(lineWidth, String(line).length);
275
277
  }
276
- return /* @__PURE__ */ jsxs(Box, {
278
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Box, {
277
279
  flexDirection: "column",
278
280
  padding: 1,
279
281
  children: [
280
- /* @__PURE__ */ jsxs(Box, { children: [/* @__PURE__ */ jsxs(Text, {
282
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Box, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Text, {
281
283
  backgroundColor: "red",
282
284
  color: "white",
283
285
  children: [
@@ -285,10 +287,10 @@ function ErrorOverview({ error }) {
285
287
  "ERROR",
286
288
  " "
287
289
  ]
288
- }), /* @__PURE__ */ jsxs(Text, { children: [" ", error.message] })] }),
289
- origin && filePath ? /* @__PURE__ */ jsx(Box, {
290
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Text, { children: [" ", error.message] })] }),
291
+ origin && filePath ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box, {
290
292
  marginTop: 1,
291
- children: /* @__PURE__ */ jsxs(Text, {
293
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Text, {
292
294
  dimColor: true,
293
295
  children: [
294
296
  filePath,
@@ -299,25 +301,25 @@ function ErrorOverview({ error }) {
299
301
  ]
300
302
  })
301
303
  }) : null,
302
- origin && excerpt ? /* @__PURE__ */ jsx(Box, {
304
+ origin && excerpt ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box, {
303
305
  marginTop: 1,
304
306
  flexDirection: "column",
305
- children: excerpt.map(({ line, value }) => /* @__PURE__ */ jsxs(Box, { children: [/* @__PURE__ */ jsx(Box, {
307
+ children: excerpt.map(({ line, value }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Box, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box, {
306
308
  width: lineWidth + 1,
307
- children: /* @__PURE__ */ jsxs(Text, {
309
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Text, {
308
310
  dimColor: line !== origin.line,
309
311
  backgroundColor: line === origin.line ? "red" : void 0,
310
312
  color: line === origin.line ? "white" : void 0,
311
313
  "aria-label": line === origin.line ? `Line ${line}, error` : `Line ${line}`,
312
314
  children: [String(line).padStart(lineWidth, " "), ":"]
313
315
  })
314
- }), /* @__PURE__ */ jsx(Text, {
316
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, {
315
317
  backgroundColor: line === origin.line ? "red" : void 0,
316
318
  color: line === origin.line ? "white" : void 0,
317
319
  children: " " + value
318
320
  }, line)] }, line))
319
321
  }) : null,
320
- error.stack ? /* @__PURE__ */ jsx(Box, {
322
+ error.stack ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box, {
321
323
  marginTop: 1,
322
324
  flexDirection: "column",
323
325
  children: error.stack.split("\n").slice(1).map((line) => {
@@ -325,10 +327,10 @@ function ErrorOverview({ error }) {
325
327
  const lineCount = stackLineCounts.get(line) ?? 0;
326
328
  stackLineCounts.set(line, lineCount + 1);
327
329
  const key = `${line}-${lineCount}`;
328
- if (!parsedLine?.file || !parsedLine.line || !parsedLine.column) return /* @__PURE__ */ jsxs(Box, { children: [/* @__PURE__ */ jsx(Text, {
330
+ if (!parsedLine?.file || !parsedLine.line || !parsedLine.column) return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Box, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, {
329
331
  dimColor: true,
330
332
  children: "- "
331
- }), /* @__PURE__ */ jsxs(Text, {
333
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Text, {
332
334
  dimColor: true,
333
335
  bold: true,
334
336
  children: [
@@ -337,17 +339,17 @@ function ErrorOverview({ error }) {
337
339
  " "
338
340
  ]
339
341
  })] }, key);
340
- return /* @__PURE__ */ jsxs(Box, { children: [
341
- /* @__PURE__ */ jsx(Text, {
342
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Box, { children: [
343
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, {
342
344
  dimColor: true,
343
345
  children: "- "
344
346
  }),
345
- /* @__PURE__ */ jsx(Text, {
347
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, {
346
348
  dimColor: true,
347
349
  bold: true,
348
350
  children: parsedLine.function
349
351
  }),
350
- /* @__PURE__ */ jsxs(Text, {
352
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Text, {
351
353
  dimColor: true,
352
354
  color: "gray",
353
355
  "aria-label": `at ${cleanupPath(parsedLine.file) ?? ""} line ${parsedLine.line} column ${parsedLine.column}`,
@@ -371,7 +373,7 @@ function ErrorOverview({ error }) {
371
373
  //#endregion
372
374
  //#region src/components/ErrorBoundary.tsx
373
375
  /** @jsxImportSource react */
374
- var ErrorBoundary = class extends PureComponent {
376
+ var ErrorBoundary = class extends import_react.PureComponent {
375
377
  static displayName = "InternalErrorBoundary";
376
378
  static getDerivedStateFromError(error) {
377
379
  return { error };
@@ -381,7 +383,7 @@ var ErrorBoundary = class extends PureComponent {
381
383
  this.props.onError(error);
382
384
  }
383
385
  render() {
384
- if (this.state.error) return /* @__PURE__ */ jsx(ErrorOverview, { error: this.state.error });
386
+ if (this.state.error) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ErrorOverview, { error: this.state.error });
385
387
  return this.props.children;
386
388
  }
387
389
  };
@@ -390,7 +392,7 @@ var ErrorBoundary = class extends PureComponent {
390
392
  /**
391
393
  `StderrContext` is a React context that exposes the stderr stream.
392
394
  */
393
- const StderrContext = createContext({
395
+ const StderrContext = (0, import_react.createContext)({
394
396
  stderr: process.stderr,
395
397
  write() {}
396
398
  });
@@ -400,7 +402,7 @@ StderrContext.displayName = "InternalStderrContext";
400
402
  /**
401
403
  `StdoutContext` is a React context that exposes the stdout stream where Ink renders your app.
402
404
  */
403
- const StdoutContext = createContext({
405
+ const StdoutContext = (0, import_react.createContext)({
404
406
  stdout: process.stdout,
405
407
  write() {}
406
408
  });
@@ -412,32 +414,32 @@ const tab = " ";
412
414
  const shiftTab = `${CSI}Z`;
413
415
  const escape = "\x1B";
414
416
  function App({ children, stdin, stdout, stderr, writeToStdout, writeToStderr, exitOnCtrlC, onExit, onWaitUntilRenderFlush, onSuspendTerminal, onRegisterInputControl, setCursorPosition, interactive, renderThrottleMs, terminalInput }) {
415
- const [isFocusEnabled, setIsFocusEnabled] = useState(true);
416
- const [activeFocusId, setActiveFocusId] = useState(void 0);
417
- const [, setFocusables] = useState([]);
418
- const focusablesCountRef = useRef(0);
419
- const animationSubscribersRef = useRef(/* @__PURE__ */ new Map());
420
- const animationTimerRef = useRef(void 0);
421
- const rawModeEnabledCount = useRef(0);
422
- const pendingDisableRawModeRef = useRef(false);
423
- const bracketedPasteModeEnabledCount = useRef(0);
424
- const internal_eventEmitter = useRef(new EventEmitter());
417
+ const [isFocusEnabled, setIsFocusEnabled] = (0, import_react.useState)(true);
418
+ const [activeFocusId, setActiveFocusId] = (0, import_react.useState)(void 0);
419
+ const [, setFocusables] = (0, import_react.useState)([]);
420
+ const focusablesCountRef = (0, import_react.useRef)(0);
421
+ const animationSubscribersRef = (0, import_react.useRef)(/* @__PURE__ */ new Map());
422
+ const animationTimerRef = (0, import_react.useRef)(void 0);
423
+ const rawModeEnabledCount = (0, import_react.useRef)(0);
424
+ const pendingDisableRawModeRef = (0, import_react.useRef)(false);
425
+ const bracketedPasteModeEnabledCount = (0, import_react.useRef)(0);
426
+ const internal_eventEmitter = (0, import_react.useRef)(new EventEmitter());
425
427
  internal_eventEmitter.current.setMaxListeners(Infinity);
426
- const readableListenerRef = useRef(void 0);
427
- const isMountedRef = useRef(true);
428
- const pendingInputFlushRef = useRef(void 0);
428
+ const readableListenerRef = (0, import_react.useRef)(void 0);
429
+ const isMountedRef = (0, import_react.useRef)(true);
430
+ const pendingInputFlushRef = (0, import_react.useRef)(void 0);
429
431
  const pendingInputFlushDelayMilliseconds = 20;
430
- const clearPendingInputFlush = useCallback(() => {
432
+ const clearPendingInputFlush = (0, import_react.useCallback)(() => {
431
433
  if (!pendingInputFlushRef.current) return;
432
434
  clearTimeout(pendingInputFlushRef.current);
433
435
  pendingInputFlushRef.current = void 0;
434
436
  }, []);
435
- const clearAnimationTimer = useCallback(() => {
437
+ const clearAnimationTimer = (0, import_react.useCallback)(() => {
436
438
  if (!animationTimerRef.current) return;
437
439
  clearTimeout(animationTimerRef.current);
438
440
  animationTimerRef.current = void 0;
439
441
  }, []);
440
- const scheduleAnimationTick = useCallback(() => {
442
+ const scheduleAnimationTick = (0, import_react.useCallback)(() => {
441
443
  clearAnimationTimer();
442
444
  if (animationSubscribersRef.current.size === 0) return;
443
445
  let nextDueTime = Number.POSITIVE_INFINITY;
@@ -456,7 +458,7 @@ function App({ children, stdin, stdout, stderr, writeToStdout, writeToStderr, ex
456
458
  scheduleAnimationTick();
457
459
  }, delay);
458
460
  }, [clearAnimationTimer]);
459
- const animationSubscribe = useCallback((callback, interval) => {
461
+ const animationSubscribe = (0, import_react.useCallback)((callback, interval) => {
460
462
  const startTime = performance.now();
461
463
  animationSubscribersRef.current.set(callback, {
462
464
  callback,
@@ -477,19 +479,19 @@ function App({ children, stdin, stdout, stderr, writeToStdout, writeToStderr, ex
477
479
  }
478
480
  };
479
481
  }, [clearAnimationTimer, scheduleAnimationTick]);
480
- useEffect(() => {
482
+ (0, import_react.useEffect)(() => {
481
483
  return () => {
482
484
  clearAnimationTimer();
483
485
  };
484
486
  }, [clearAnimationTimer]);
485
487
  const rawModeStdin = getRawModeStream(stdin);
486
488
  const isRawModeSupported = rawModeStdin !== void 0;
487
- const detachReadableListener = useCallback(() => {
489
+ const detachReadableListener = (0, import_react.useCallback)(() => {
488
490
  if (!readableListenerRef.current) return;
489
491
  stdin.removeListener("readable", readableListenerRef.current);
490
492
  readableListenerRef.current = void 0;
491
493
  }, [stdin]);
492
- const clearInputState = useCallback(() => {
494
+ const clearInputState = (0, import_react.useCallback)(() => {
493
495
  terminalInput.reset();
494
496
  clearPendingInputFlush();
495
497
  detachReadableListener();
@@ -498,7 +500,7 @@ function App({ children, stdin, stdout, stderr, writeToStdout, writeToStderr, ex
498
500
  detachReadableListener,
499
501
  terminalInput
500
502
  ]);
501
- const disableRawMode = useCallback(() => {
503
+ const disableRawMode = (0, import_react.useCallback)(() => {
502
504
  if (!rawModeStdin) return;
503
505
  pendingDisableRawModeRef.current = false;
504
506
  rawModeStdin.setRawMode(false);
@@ -506,7 +508,7 @@ function App({ children, stdin, stdout, stderr, writeToStdout, writeToStderr, ex
506
508
  rawModeEnabledCount.current = 0;
507
509
  clearInputState();
508
510
  }, [rawModeStdin, clearInputState]);
509
- const handleExit = useCallback((errorOrResult) => {
511
+ const handleExit = (0, import_react.useCallback)((errorOrResult) => {
510
512
  if (isRawModeSupported && (rawModeEnabledCount.current > 0 || pendingDisableRawModeRef.current)) disableRawMode();
511
513
  onExit(errorOrResult);
512
514
  }, [
@@ -514,7 +516,7 @@ function App({ children, stdin, stdout, stderr, writeToStdout, writeToStderr, ex
514
516
  disableRawMode,
515
517
  onExit
516
518
  ]);
517
- const handleInput = useCallback((input) => {
519
+ const handleInput = (0, import_react.useCallback)((input) => {
518
520
  if (input === "" && exitOnCtrlC) {
519
521
  handleExit();
520
522
  return;
@@ -525,11 +527,11 @@ function App({ children, stdin, stdout, stderr, writeToStdout, writeToStderr, ex
525
527
  handleExit,
526
528
  isFocusEnabled
527
529
  ]);
528
- const emitInput = useCallback((input) => {
530
+ const emitInput = (0, import_react.useCallback)((input) => {
529
531
  handleInput(input);
530
532
  internal_eventEmitter.current.emit("input", input);
531
533
  }, [handleInput]);
532
- const schedulePendingInputFlush = useCallback(() => {
534
+ const schedulePendingInputFlush = (0, import_react.useCallback)(() => {
533
535
  clearPendingInputFlush();
534
536
  pendingInputFlushRef.current = setTimeout(() => {
535
537
  pendingInputFlushRef.current = void 0;
@@ -542,7 +544,7 @@ function App({ children, stdin, stdout, stderr, writeToStdout, writeToStderr, ex
542
544
  emitInput,
543
545
  terminalInput
544
546
  ]);
545
- const handleReadable = useCallback(() => {
547
+ const handleReadable = (0, import_react.useCallback)(() => {
546
548
  clearPendingInputFlush();
547
549
  let chunk;
548
550
  while ((chunk = stdin.read()) !== null) {
@@ -564,12 +566,12 @@ function App({ children, stdin, stdout, stderr, writeToStdout, writeToStderr, ex
564
566
  schedulePendingInputFlush,
565
567
  terminalInput
566
568
  ]);
567
- const attachReadableListener = useCallback(() => {
569
+ const attachReadableListener = (0, import_react.useCallback)(() => {
568
570
  if (readableListenerRef.current) return;
569
571
  readableListenerRef.current = handleReadable;
570
572
  stdin.addListener("readable", handleReadable);
571
573
  }, [stdin, handleReadable]);
572
- const handleSetRawMode = useCallback((isEnabled) => {
574
+ const handleSetRawMode = (0, import_react.useCallback)((isEnabled) => {
573
575
  if (!rawModeStdin) {
574
576
  if (stdin === process.stdin) throw new Error("Raw mode is not supported on the current process.stdin, which Ink uses as input stream by default.\nRead about how to prevent this error on https://github.com/vadimdemedes/ink/#israwmodesupported");
575
577
  else throw new Error("Raw mode is not supported on the stdin provided to Ink.\nRead about how to prevent this error on https://github.com/vadimdemedes/ink/#israwmodesupported");
@@ -604,7 +606,7 @@ function App({ children, stdin, stdout, stderr, writeToStdout, writeToStderr, ex
604
606
  clearInputState,
605
607
  disableRawMode
606
608
  ]);
607
- const handleQueryTerminal = useCallback(async ({ refresh = false } = {}) => {
609
+ const handleQueryTerminal = (0, import_react.useCallback)(async ({ refresh = false } = {}) => {
608
610
  if (!interactive || !isRawModeSupported || !stdout.isTTY) return;
609
611
  if (!refresh) {
610
612
  const existing = getTerminalQueryPromise(stdout);
@@ -627,13 +629,13 @@ function App({ children, stdin, stdout, stderr, writeToStdout, writeToStderr, ex
627
629
  detachReadableListener,
628
630
  attachReadableListener
629
631
  ]);
630
- const reportFeedActiveRef = useRef(false);
631
- const handleSetReportFeed = useCallback((active) => {
632
+ const reportFeedActiveRef = (0, import_react.useRef)(false);
633
+ const handleSetReportFeed = (0, import_react.useCallback)((active) => {
632
634
  if (active === reportFeedActiveRef.current || !isRawModeSupported) return;
633
635
  reportFeedActiveRef.current = active;
634
636
  handleSetRawMode(active);
635
637
  }, [isRawModeSupported, handleSetRawMode]);
636
- useInsertionEffect(() => {
638
+ (0, import_react.useInsertionEffect)(() => {
637
639
  const unregister = registerTerminalIntegration(stdout, {
638
640
  runQuery: handleQueryTerminal,
639
641
  setReportFeed: handleSetReportFeed
@@ -647,7 +649,7 @@ function App({ children, stdin, stdout, stderr, writeToStdout, writeToStderr, ex
647
649
  handleQueryTerminal,
648
650
  handleSetReportFeed
649
651
  ]);
650
- const handleSetBracketedPasteMode = useCallback((isEnabled) => {
652
+ const handleSetBracketedPasteMode = (0, import_react.useCallback)((isEnabled) => {
651
653
  if (!stdout.isTTY) return;
652
654
  if (isEnabled) {
653
655
  if (bracketedPasteModeEnabledCount.current === 0) stdout.write(ansiEscapes.enableBracketedPaste);
@@ -657,11 +659,11 @@ function App({ children, stdin, stdout, stderr, writeToStdout, writeToStderr, ex
657
659
  if (bracketedPasteModeEnabledCount.current === 0) return;
658
660
  if (--bracketedPasteModeEnabledCount.current === 0) stdout.write(ansiEscapes.disableBracketedPaste);
659
661
  }, [stdout]);
660
- const suspendedInputStateRef = useRef({
662
+ const suspendedInputStateRef = (0, import_react.useRef)({
661
663
  rawMode: false,
662
664
  bracketedPaste: false
663
665
  });
664
- const pauseInput = useCallback(() => {
666
+ const pauseInput = (0, import_react.useCallback)(() => {
665
667
  const wasRawMode = isRawModeSupported && rawModeEnabledCount.current > 0;
666
668
  const wasBracketedPaste = bracketedPasteModeEnabledCount.current > 0;
667
669
  suspendedInputStateRef.current = {
@@ -682,7 +684,7 @@ function App({ children, stdin, stdout, stderr, writeToStdout, writeToStderr, ex
682
684
  stdout,
683
685
  clearInputState
684
686
  ]);
685
- const resumeInput = useCallback(() => {
687
+ const resumeInput = (0, import_react.useCallback)(() => {
686
688
  const { rawMode, bracketedPaste } = suspendedInputStateRef.current;
687
689
  if (rawMode) {
688
690
  rawModeStdin?.setEncoding("utf8");
@@ -698,14 +700,14 @@ function App({ children, stdin, stdout, stderr, writeToStdout, writeToStderr, ex
698
700
  stdout,
699
701
  attachReadableListener
700
702
  ]);
701
- useInsertionEffect(() => {
703
+ (0, import_react.useInsertionEffect)(() => {
702
704
  onRegisterInputControl(pauseInput, resumeInput);
703
705
  }, [
704
706
  onRegisterInputControl,
705
707
  pauseInput,
706
708
  resumeInput
707
709
  ]);
708
- const findNextFocusable = useCallback((currentFocusables, currentActiveFocusId) => {
710
+ const findNextFocusable = (0, import_react.useCallback)((currentFocusables, currentActiveFocusId) => {
709
711
  const activeIndex = currentFocusables.findIndex((focusable) => {
710
712
  return focusable.id === currentActiveFocusId;
711
713
  });
@@ -714,7 +716,7 @@ function App({ children, stdin, stdout, stderr, writeToStdout, writeToStderr, ex
714
716
  if (focusable?.isActive) return focusable.id;
715
717
  }
716
718
  }, []);
717
- const findPreviousFocusable = useCallback((currentFocusables, currentActiveFocusId) => {
719
+ const findPreviousFocusable = (0, import_react.useCallback)((currentFocusables, currentActiveFocusId) => {
718
720
  const activeIndex = currentFocusables.findIndex((focusable) => {
719
721
  return focusable.id === currentActiveFocusId;
720
722
  });
@@ -723,7 +725,7 @@ function App({ children, stdin, stdout, stderr, writeToStdout, writeToStderr, ex
723
725
  if (focusable?.isActive) return focusable.id;
724
726
  }
725
727
  }, []);
726
- const focusNext = useCallback(() => {
728
+ const focusNext = (0, import_react.useCallback)(() => {
727
729
  setFocusables((currentFocusables) => {
728
730
  setActiveFocusId((currentActiveFocusId) => {
729
731
  const firstFocusableId = currentFocusables.find((focusable) => focusable.isActive)?.id;
@@ -732,7 +734,7 @@ function App({ children, stdin, stdout, stderr, writeToStdout, writeToStderr, ex
732
734
  return currentFocusables;
733
735
  });
734
736
  }, [findNextFocusable]);
735
- const focusPrevious = useCallback(() => {
737
+ const focusPrevious = (0, import_react.useCallback)(() => {
736
738
  setFocusables((currentFocusables) => {
737
739
  setActiveFocusId((currentActiveFocusId) => {
738
740
  const lastFocusableId = currentFocusables.findLast((focusable) => focusable.isActive)?.id;
@@ -741,7 +743,7 @@ function App({ children, stdin, stdout, stderr, writeToStdout, writeToStderr, ex
741
743
  return currentFocusables;
742
744
  });
743
745
  }, [findPreviousFocusable]);
744
- useEffect(() => {
746
+ (0, import_react.useEffect)(() => {
745
747
  const handleTabNavigation = (input) => {
746
748
  if (!isFocusEnabled || focusablesCountRef.current === 0) return;
747
749
  if (input === tab) focusNext();
@@ -757,19 +759,19 @@ function App({ children, stdin, stdout, stderr, writeToStdout, writeToStderr, ex
757
759
  focusNext,
758
760
  focusPrevious
759
761
  ]);
760
- const enableFocus = useCallback(() => {
762
+ const enableFocus = (0, import_react.useCallback)(() => {
761
763
  setIsFocusEnabled(true);
762
764
  }, []);
763
- const disableFocus = useCallback(() => {
765
+ const disableFocus = (0, import_react.useCallback)(() => {
764
766
  setIsFocusEnabled(false);
765
767
  }, []);
766
- const focus = useCallback((id) => {
768
+ const focus = (0, import_react.useCallback)((id) => {
767
769
  setFocusables((currentFocusables) => {
768
770
  if (currentFocusables.some((focusable) => focusable?.id === id)) setActiveFocusId(id);
769
771
  return currentFocusables;
770
772
  });
771
773
  }, []);
772
- const addFocusable = useCallback((id, { autoFocus }) => {
774
+ const addFocusable = (0, import_react.useCallback)((id, { autoFocus }) => {
773
775
  setFocusables((currentFocusables) => {
774
776
  focusablesCountRef.current = currentFocusables.length + 1;
775
777
  return [...currentFocusables, {
@@ -782,7 +784,7 @@ function App({ children, stdin, stdout, stderr, writeToStdout, writeToStderr, ex
782
784
  return currentActiveFocusId;
783
785
  });
784
786
  }, []);
785
- const removeFocusable = useCallback((id) => {
787
+ const removeFocusable = (0, import_react.useCallback)((id) => {
786
788
  setActiveFocusId((currentActiveFocusId) => {
787
789
  if (currentActiveFocusId === id) return;
788
790
  return currentActiveFocusId;
@@ -795,7 +797,7 @@ function App({ children, stdin, stdout, stderr, writeToStdout, writeToStderr, ex
795
797
  return filtered;
796
798
  });
797
799
  }, []);
798
- const activateFocusable = useCallback((id) => {
800
+ const activateFocusable = (0, import_react.useCallback)((id) => {
799
801
  setFocusables((currentFocusables) => currentFocusables.map((focusable) => {
800
802
  if (focusable.id !== id) return focusable;
801
803
  return {
@@ -804,7 +806,7 @@ function App({ children, stdin, stdout, stderr, writeToStdout, writeToStderr, ex
804
806
  };
805
807
  }));
806
808
  }, []);
807
- const deactivateFocusable = useCallback((id) => {
809
+ const deactivateFocusable = (0, import_react.useCallback)((id) => {
808
810
  setActiveFocusId((currentActiveFocusId) => {
809
811
  if (currentActiveFocusId === id) return;
810
812
  return currentActiveFocusId;
@@ -817,7 +819,7 @@ function App({ children, stdin, stdout, stderr, writeToStdout, writeToStderr, ex
817
819
  };
818
820
  }));
819
821
  }, []);
820
- useEffect(() => {
822
+ (0, import_react.useEffect)(() => {
821
823
  isMountedRef.current = true;
822
824
  return () => {
823
825
  isMountedRef.current = false;
@@ -835,7 +837,7 @@ function App({ children, stdin, stdout, stderr, writeToStdout, writeToStderr, ex
835
837
  disableRawMode,
836
838
  interactive
837
839
  ]);
838
- const appContextValue = useMemo(() => ({
840
+ const appContextValue = (0, import_react.useMemo)(() => ({
839
841
  exit: handleExit,
840
842
  waitUntilRenderFlush: onWaitUntilRenderFlush,
841
843
  suspendTerminal: onSuspendTerminal
@@ -844,7 +846,7 @@ function App({ children, stdin, stdout, stderr, writeToStdout, writeToStderr, ex
844
846
  onWaitUntilRenderFlush,
845
847
  onSuspendTerminal
846
848
  ]);
847
- const stdinContextValue = useMemo(() => ({
849
+ const stdinContextValue = (0, import_react.useMemo)(() => ({
848
850
  stdin,
849
851
  setRawMode: handleSetRawMode,
850
852
  setBracketedPasteMode: handleSetBracketedPasteMode,
@@ -858,16 +860,16 @@ function App({ children, stdin, stdout, stderr, writeToStdout, writeToStderr, ex
858
860
  isRawModeSupported,
859
861
  exitOnCtrlC
860
862
  ]);
861
- const stdoutContextValue = useMemo(() => ({
863
+ const stdoutContextValue = (0, import_react.useMemo)(() => ({
862
864
  stdout,
863
865
  write: writeToStdout
864
866
  }), [stdout, writeToStdout]);
865
- const stderrContextValue = useMemo(() => ({
867
+ const stderrContextValue = (0, import_react.useMemo)(() => ({
866
868
  stderr,
867
869
  write: writeToStderr
868
870
  }), [stderr, writeToStderr]);
869
- const cursorContextValue = useMemo(() => ({ setCursorPosition }), [setCursorPosition]);
870
- const focusContextValue = useMemo(() => ({
871
+ const cursorContextValue = (0, import_react.useMemo)(() => ({ setCursorPosition }), [setCursorPosition]);
872
+ const focusContextValue = (0, import_react.useMemo)(() => ({
871
873
  activeId: activeFocusId,
872
874
  add: addFocusable,
873
875
  remove: removeFocusable,
@@ -890,25 +892,25 @@ function App({ children, stdin, stdout, stderr, writeToStdout, writeToStderr, ex
890
892
  focusPrevious,
891
893
  focus
892
894
  ]);
893
- const animationContextValue = useMemo(() => ({
895
+ const animationContextValue = (0, import_react.useMemo)(() => ({
894
896
  renderThrottleMs,
895
897
  subscribe: animationSubscribe
896
898
  }), [animationSubscribe, renderThrottleMs]);
897
- return /* @__PURE__ */ jsx(AppContext.Provider, {
899
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AppContext.Provider, {
898
900
  value: appContextValue,
899
- children: /* @__PURE__ */ jsx(StdinContext.Provider, {
901
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StdinContext.Provider, {
900
902
  value: stdinContextValue,
901
- children: /* @__PURE__ */ jsx(StdoutContext.Provider, {
903
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StdoutContext.Provider, {
902
904
  value: stdoutContextValue,
903
- children: /* @__PURE__ */ jsx(StderrContext.Provider, {
905
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StderrContext.Provider, {
904
906
  value: stderrContextValue,
905
- children: /* @__PURE__ */ jsx(FocusContext.Provider, {
907
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FocusContext.Provider, {
906
908
  value: focusContextValue,
907
- children: /* @__PURE__ */ jsx(animationContext.Provider, {
909
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(animationContext.Provider, {
908
910
  value: animationContextValue,
909
- children: /* @__PURE__ */ jsx(CursorContext.Provider, {
911
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CursorContext.Provider, {
910
912
  value: cursorContextValue,
911
- children: /* @__PURE__ */ jsx(ErrorBoundary, {
913
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ErrorBoundary, {
912
914
  onError: handleExit,
913
915
  children
914
916
  })
@@ -924,7 +926,7 @@ App.displayName = "InternalApp";
924
926
  //#endregion
925
927
  //#region src/components/TerminalOscContext.ts
926
928
  const noop$1 = () => {};
927
- const TerminalOscContext = createContext({
929
+ const TerminalOscContext = (0, import_react.createContext)({
928
930
  publishProgress: noop$1,
929
931
  copyToClipboard: noop$1,
930
932
  publishTitle: noop$1,
@@ -1799,7 +1801,7 @@ const createInk = (options) => {
1799
1801
  let nextRenderCommit;
1800
1802
  let pauseInput;
1801
1803
  let resumeInput;
1802
- const rootTag = isConcurrent ? ConcurrentRoot : LegacyRoot;
1804
+ const rootTag = isConcurrent ? import_constants.ConcurrentRoot : import_constants.LegacyRoot;
1803
1805
  const container = reconciler.createContainer(rootNode, rootTag, null, false, null, "id", () => {}, () => {}, () => {}, () => {});
1804
1806
  const unsubscribeExit = signalExit(unmount, { alwaysLast: false });
1805
1807
  setAlternateScreen(Boolean(options.alternateScreen));
@@ -1975,11 +1977,11 @@ const createInk = (options) => {
1975
1977
  renderInteractiveFrame(output, outputHeight, hasStaticOutput ? staticOutput : "", screen, false);
1976
1978
  }
1977
1979
  function render(node) {
1978
- const tree = /* @__PURE__ */ jsx(accessibilityContext.Provider, {
1980
+ const tree = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(accessibilityContext.Provider, {
1979
1981
  value: { isScreenReaderEnabled },
1980
- children: /* @__PURE__ */ jsx(TerminalOscContext.Provider, {
1982
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TerminalOscContext.Provider, {
1981
1983
  value: terminalOsc,
1982
- children: /* @__PURE__ */ jsx(App, {
1984
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(App, {
1983
1985
  stdin: options.stdin,
1984
1986
  stdout: options.stdout,
1985
1987
  stderr: options.stderr,
@@ -2451,7 +2453,7 @@ const renderToString = (node, options) => {
2451
2453
  if (staticOutput && staticOutput !== "\n") capturedStaticOutput += staticOutput;
2452
2454
  };
2453
2455
  let uncaughtError;
2454
- const container = reconciler.createContainer(rootNode, LegacyRoot, null, false, null, "render-to-string", (error) => {
2456
+ const container = reconciler.createContainer(rootNode, import_constants.LegacyRoot, null, false, null, "render-to-string", (error) => {
2455
2457
  uncaughtError ??= error;
2456
2458
  }, () => {}, () => {}, () => {});
2457
2459
  reconciler.updateContainerSync(node, container, null, () => {});
@@ -2476,12 +2478,12 @@ const renderToString = (node, options) => {
2476
2478
  * Ordinary `Text` continues to strip terminal control sequences.
2477
2479
  */
2478
2480
  function AnsiText({ children, wrap = "wrap", "aria-label": ariaLabel, "aria-hidden": ariaHidden = false }) {
2479
- const { isScreenReaderEnabled } = useContext(accessibilityContext);
2481
+ const { isScreenReaderEnabled } = (0, import_react.useContext)(accessibilityContext);
2480
2482
  if (isScreenReaderEnabled) {
2481
2483
  if (ariaHidden) return null;
2482
- return /* @__PURE__ */ jsx(Text, { children: ariaLabel ?? stripAnsi(children) });
2484
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { children: ariaLabel ?? stripAnsi(children) });
2483
2485
  }
2484
- return /* @__PURE__ */ jsx("ink-text", {
2486
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ink-text", {
2485
2487
  style: {
2486
2488
  flexGrow: 0,
2487
2489
  flexShrink: 1,
@@ -2504,22 +2506,22 @@ For example, [Tap](https://github.com/tapjs/node-tap) uses `<Static>` to display
2504
2506
  */
2505
2507
  function Static(props) {
2506
2508
  const { items, children: render, style: customStyle } = props;
2507
- const [index, setIndex] = useState(0);
2508
- const itemsToRender = useMemo(() => {
2509
+ const [index, setIndex] = (0, import_react.useState)(0);
2510
+ const itemsToRender = (0, import_react.useMemo)(() => {
2509
2511
  return items.slice(index);
2510
2512
  }, [items, index]);
2511
- useLayoutEffect(() => {
2513
+ (0, import_react.useLayoutEffect)(() => {
2512
2514
  setIndex(items.length);
2513
2515
  }, [items.length]);
2514
2516
  const children = itemsToRender.map((item, itemIndex) => {
2515
2517
  return render(item, index + itemIndex);
2516
2518
  });
2517
- const style = useMemo(() => ({
2519
+ const style = (0, import_react.useMemo)(() => ({
2518
2520
  position: "absolute",
2519
2521
  flexDirection: "column",
2520
2522
  ...customStyle
2521
2523
  }), [customStyle]);
2522
- return /* @__PURE__ */ jsx("ink-box", {
2524
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ink-box", {
2523
2525
  internal_static: true,
2524
2526
  style,
2525
2527
  children
@@ -2532,9 +2534,9 @@ function Static(props) {
2532
2534
  Transform a string representation of React components before they're written to output. For example, you might want to apply a gradient to text, add a clickable link, or create some text effects. These use cases can't accept React nodes as input; they expect a string. That's what the <Transform> component does: it gives you an output string of its child components and lets you transform it in any way.
2533
2535
  */
2534
2536
  function Transform({ children, transform, accessibilityLabel }) {
2535
- const { isScreenReaderEnabled } = useContext(accessibilityContext);
2537
+ const { isScreenReaderEnabled } = (0, import_react.useContext)(accessibilityContext);
2536
2538
  if (children === void 0 || children === null) return null;
2537
- return /* @__PURE__ */ jsx("ink-text", {
2539
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ink-text", {
2538
2540
  style: {
2539
2541
  flexGrow: 0,
2540
2542
  flexShrink: 1,
@@ -2549,9 +2551,10 @@ function Transform({ children, transform, accessibilityLabel }) {
2549
2551
  /**
2550
2552
  A React hook that returns the stdout stream where Ink renders your app.
2551
2553
  */
2552
- const useStdout = () => useContext(StdoutContext);
2554
+ const useStdout = () => (0, import_react.useContext)(StdoutContext);
2553
2555
  //#endregion
2554
2556
  //#region src/components/Hyperlink.tsx
2557
+ /** @jsxImportSource react */
2555
2558
  /**
2556
2559
  A clickable OSC 8 hyperlink — the counterpart to the router's `<Link>`, which
2557
2560
  navigates between screens. On terminals without hyperlink support it falls
@@ -2563,9 +2566,9 @@ back to `text (url)`.
2563
2566
  */
2564
2567
  function Hyperlink({ url, fallback = true, children, ...textProps }) {
2565
2568
  const { stdout } = useStdout();
2566
- if (!detectHyperlinkSupport(stdout)) return /* @__PURE__ */ jsxs(Text, {
2569
+ if (!detectHyperlinkSupport(stdout)) return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Text, {
2567
2570
  ...textProps,
2568
- children: [children, fallback ? /* @__PURE__ */ jsxs(Text, {
2571
+ children: [children, fallback ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Text, {
2569
2572
  dimColor: true,
2570
2573
  children: [
2571
2574
  " (",
@@ -2574,9 +2577,9 @@ function Hyperlink({ url, fallback = true, children, ...textProps }) {
2574
2577
  ]
2575
2578
  }) : null]
2576
2579
  });
2577
- return /* @__PURE__ */ jsx(Transform, {
2580
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Transform, {
2578
2581
  transform: (text) => link(text, url),
2579
- children: /* @__PURE__ */ jsx(Text, {
2582
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, {
2580
2583
  ...textProps,
2581
2584
  children
2582
2585
  })
@@ -2588,7 +2591,7 @@ function Hyperlink({ url, fallback = true, children, ...textProps }) {
2588
2591
  Adds one or more newline (`\n`) characters. Must be used within `<Text>` components.
2589
2592
  */
2590
2593
  function Newline({ count = 1 }) {
2591
- return /* @__PURE__ */ jsx("ink-text", { children: "\n".repeat(count) });
2594
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ink-text", { children: "\n".repeat(count) });
2592
2595
  }
2593
2596
  //#endregion
2594
2597
  //#region src/components/Spacer.tsx
@@ -2599,7 +2602,182 @@ A flexible space that expands along the major axis of its containing layout.
2599
2602
  It's useful as a shortcut for filling all the available space between elements.
2600
2603
  */
2601
2604
  function Spacer() {
2602
- return /* @__PURE__ */ jsx(Box, { flexGrow: 1 });
2605
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box, { flexGrow: 1 });
2606
+ }
2607
+ //#endregion
2608
+ //#region src/virtual-scroll.ts
2609
+ const clamp = (value, min, max) => Math.min(Math.max(value, min), max);
2610
+ const wholeRows = (value) => Math.max(0, Math.floor(value)) || 0;
2611
+ /**
2612
+ Compute which items intersect a viewport over a vertical stack of items.
2613
+ */
2614
+ const virtualScrollWindow = (options) => {
2615
+ const count = wholeRows(options.count);
2616
+ const viewportHeight = wholeRows(options.viewportHeight);
2617
+ const tops = [];
2618
+ let totalHeight = 0;
2619
+ for (let index = 0; index < count; index++) {
2620
+ tops.push(totalHeight);
2621
+ totalHeight += wholeRows(options.itemHeight(index));
2622
+ }
2623
+ const bottomOf = (index) => index + 1 < count ? tops[index + 1] : totalHeight;
2624
+ const maxScrollTop = Math.max(0, totalHeight - viewportHeight);
2625
+ let scrollTop = clamp(Math.floor(options.scrollTop) || 0, 0, maxScrollTop);
2626
+ const focused = options.focusedIndex;
2627
+ if (focused !== void 0 && Number.isInteger(focused) && focused >= 0 && focused < count) {
2628
+ const top = tops[focused];
2629
+ const bottom = bottomOf(focused);
2630
+ if (top < scrollTop) scrollTop = top;
2631
+ else if (bottom > scrollTop + viewportHeight) scrollTop = Math.min(top, bottom - viewportHeight);
2632
+ scrollTop = clamp(scrollTop, 0, maxScrollTop);
2633
+ }
2634
+ const viewportBottom = scrollTop + viewportHeight;
2635
+ let start = 0;
2636
+ while (start < count && bottomOf(start) <= scrollTop) start++;
2637
+ let end = start;
2638
+ while (end < count && tops[end] < viewportBottom) end++;
2639
+ return {
2640
+ start,
2641
+ end,
2642
+ scrollTop,
2643
+ maxScrollTop,
2644
+ totalHeight,
2645
+ offset: start < end ? tops[start] - scrollTop : 0,
2646
+ hiddenAbove: scrollTop,
2647
+ hiddenBelow: Math.max(0, totalHeight - viewportBottom)
2648
+ };
2649
+ };
2650
+ //#endregion
2651
+ //#region src/hooks/use-virtual-scroll.ts
2652
+ /**
2653
+ A React hook that owns the scroll position of a windowed list and returns which
2654
+ items to render for it. The position is clamped to the scrollable range and,
2655
+ while `focusedIndex` is set, moved as little as necessary to keep that item
2656
+ fully visible. Render the items in `[start, end)` inside an `overflowY="hidden"`
2657
+ box of `viewportHeight` rows, shifted up by `offset` rows.
2658
+
2659
+ `<VirtualList>` wraps this hook; use it directly to draw your own chrome such
2660
+ as overflow markers or a scrollbar around the window.
2661
+
2662
+ @example
2663
+ ```tsx
2664
+ import { Box, Text, useVirtualScroll } from "@alchemy.run/sigil";
2665
+
2666
+ const Example = ({ lines, cursor }: { lines: string[]; cursor: number }) => {
2667
+ const { start, end, offset, hiddenAbove, hiddenBelow } = useVirtualScroll({
2668
+ count: lines.length,
2669
+ itemHeight: () => 1,
2670
+ viewportHeight: 10,
2671
+ focusedIndex: cursor,
2672
+ });
2673
+
2674
+ return (
2675
+ <Box flexDirection="column">
2676
+ <Text dimColor>{hiddenAbove > 0 ? `↑ ${hiddenAbove} more` : ""}</Text>
2677
+ <Box flexDirection="column" height={10} overflowY="hidden">
2678
+ <Box flexDirection="column" flexShrink={0} marginTop={offset}>
2679
+ {lines.slice(start, end).map((line, index) => (
2680
+ <Text key={start + index} inverse={start + index === cursor}>
2681
+ {line}
2682
+ </Text>
2683
+ ))}
2684
+ </Box>
2685
+ </Box>
2686
+ <Text dimColor>{hiddenBelow > 0 ? `↓ ${hiddenBelow} more` : ""}</Text>
2687
+ </Box>
2688
+ );
2689
+ };
2690
+ ```
2691
+ */
2692
+ const useVirtualScroll = (options) => {
2693
+ const [position, setPosition] = (0, import_react.useState)(0);
2694
+ const window = virtualScrollWindow({
2695
+ ...options,
2696
+ scrollTop: position
2697
+ });
2698
+ (0, import_react.useEffect)(() => {
2699
+ if (window.scrollTop !== position) setPosition(window.scrollTop);
2700
+ }, [window.scrollTop, position]);
2701
+ const scrollTo = (0, import_react.useCallback)((top) => {
2702
+ setPosition(top);
2703
+ }, []);
2704
+ const scrollBy = (0, import_react.useCallback)((delta) => {
2705
+ setPosition((current) => current + delta);
2706
+ }, []);
2707
+ return {
2708
+ ...window,
2709
+ scrollTo,
2710
+ scrollBy
2711
+ };
2712
+ };
2713
+ //#endregion
2714
+ //#region src/components/VirtualList.tsx
2715
+ /** @jsxImportSource react */
2716
+ const rootOf = (node) => {
2717
+ let current = node;
2718
+ while (current?.parentNode) current = current.parentNode;
2719
+ return current?.nodeName === "ink-root" ? current : void 0;
2720
+ };
2721
+ /**
2722
+ A vertically windowed list: only the items intersecting the viewport are
2723
+ rendered, inside a clipped box that scrolls by whole rows. Items may have
2724
+ different heights, and the item at the top edge may be partially visible.
2725
+
2726
+ Until the first layout pass has measured the viewport, every item is rendered
2727
+ inside the clipped box so the first frame already looks right.
2728
+ */
2729
+ function VirtualList({ items, itemHeight, renderItem, getKey, focusedIndex, height }) {
2730
+ const ref = (0, import_react.useRef)(null);
2731
+ const [measured, setMeasured] = (0, import_react.useState)();
2732
+ const measure = () => {
2733
+ const next = ref.current?.yogaNode?.getComputedHeight();
2734
+ if (next !== void 0) setMeasured((previous) => previous === next ? previous : next);
2735
+ };
2736
+ (0, import_react.useLayoutEffect)(() => {
2737
+ if (height === void 0) measure();
2738
+ });
2739
+ (0, import_react.useEffect)(() => {
2740
+ if (height !== void 0) return;
2741
+ const root = rootOf(ref.current);
2742
+ return root ? addLayoutListener(root, measure) : void 0;
2743
+ });
2744
+ const viewportHeight = height ?? measured;
2745
+ const windowed = viewportHeight !== void 0;
2746
+ const window = useVirtualScroll({
2747
+ count: items.length,
2748
+ itemHeight: (index) => itemHeight(items[index], index),
2749
+ viewportHeight: viewportHeight ?? 0,
2750
+ focusedIndex: windowed ? focusedIndex : void 0
2751
+ });
2752
+ const start = windowed ? window.start : 0;
2753
+ const end = windowed ? window.end : items.length;
2754
+ const offset = windowed ? window.offset : 0;
2755
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box, {
2756
+ ref,
2757
+ flexDirection: "column",
2758
+ overflowY: "hidden",
2759
+ ...height === void 0 ? {
2760
+ height: window.totalHeight,
2761
+ minHeight: 0,
2762
+ flexShrink: 1
2763
+ } : {
2764
+ height,
2765
+ flexShrink: 0
2766
+ },
2767
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box, {
2768
+ flexDirection: "column",
2769
+ flexShrink: 0,
2770
+ marginTop: offset,
2771
+ children: items.slice(start, end).map((item, sliceIndex) => {
2772
+ const index = start + sliceIndex;
2773
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box, {
2774
+ flexDirection: "column",
2775
+ flexShrink: 0,
2776
+ children: renderItem(item, index)
2777
+ }, getKey ? getKey(item, index) : index);
2778
+ })
2779
+ })
2780
+ });
2603
2781
  }
2604
2782
  //#endregion
2605
2783
  //#region src/hooks/use-capabilities.ts
@@ -2617,8 +2795,8 @@ const useCapabilities = () => {
2617
2795
  const { stdout } = useStdout();
2618
2796
  const { stdin } = useStdinContext();
2619
2797
  const store = getCapabilities(stdin, stdout);
2620
- const capabilities = useSyncExternalStore(store.subscribe, () => store.current);
2621
- useEffect(() => {
2798
+ const capabilities = (0, import_react.useSyncExternalStore)(store.subscribe, () => store.current);
2799
+ (0, import_react.useEffect)(() => {
2622
2800
  store.query();
2623
2801
  }, [store]);
2624
2802
  return capabilities;
@@ -2645,8 +2823,8 @@ const useCapabilitiesChange = (onChange) => {
2645
2823
  const { stdout } = useStdout();
2646
2824
  const { stdin } = useStdinContext();
2647
2825
  const store = getCapabilities(stdin, stdout);
2648
- const handleChange = useEffectEvent(onChange);
2649
- useEffect(() => {
2826
+ const handleChange = (0, import_react.useEffectEvent)(onChange);
2827
+ (0, import_react.useEffect)(() => {
2650
2828
  let previous = store.current;
2651
2829
  const unsubscribe = store.subscribe((next) => {
2652
2830
  const before = previous;
@@ -2686,7 +2864,7 @@ return …
2686
2864
  */
2687
2865
  const usePaste = (handler, options = {}) => {
2688
2866
  const { setRawMode, setBracketedPasteMode, internal_eventEmitter } = useStdinContext();
2689
- useEffect(() => {
2867
+ (0, import_react.useEffect)(() => {
2690
2868
  if (options.isActive === false) return;
2691
2869
  setRawMode(true);
2692
2870
  setBracketedPasteMode(true);
@@ -2699,12 +2877,12 @@ const usePaste = (handler, options = {}) => {
2699
2877
  setRawMode,
2700
2878
  setBracketedPasteMode
2701
2879
  ]);
2702
- const handlePaste = useEffectEvent((text) => {
2880
+ const handlePaste = (0, import_react.useEffectEvent)((text) => {
2703
2881
  reconciler.discreteUpdates(() => {
2704
2882
  handler(text);
2705
2883
  });
2706
2884
  });
2707
- useEffect(() => {
2885
+ (0, import_react.useEffect)(() => {
2708
2886
  if (options.isActive === false) return;
2709
2887
  internal_eventEmitter.on("paste", handlePaste);
2710
2888
  return () => {
@@ -2717,20 +2895,20 @@ const usePaste = (handler, options = {}) => {
2717
2895
  /**
2718
2896
  A React hook that returns app lifecycle methods like `exit()` and `waitUntilRenderFlush()`.
2719
2897
  */
2720
- const useApp = () => useContext(AppContext);
2898
+ const useApp = () => (0, import_react.useContext)(AppContext);
2721
2899
  //#endregion
2722
2900
  //#region src/hooks/use-stderr.ts
2723
2901
  /**
2724
2902
  A React hook that returns the stderr stream.
2725
2903
  */
2726
- const useStderr = () => useContext(StderrContext);
2904
+ const useStderr = () => (0, import_react.useContext)(StderrContext);
2727
2905
  //#endregion
2728
2906
  //#region src/hooks/use-focus-manager.ts
2729
2907
  /**
2730
2908
  A React hook that returns methods to enable or disable focus management for all components or manually switch focus to the next or previous components.
2731
2909
  */
2732
2910
  const useFocusManager = () => {
2733
- const focusContext = useContext(FocusContext);
2911
+ const focusContext = (0, import_react.useContext)(FocusContext);
2734
2912
  return {
2735
2913
  enableFocus: focusContext.enableFocus,
2736
2914
  disableFocus: focusContext.disableFocus,
@@ -2747,7 +2925,7 @@ A React hook that returns whether a screen reader is enabled.
2747
2925
  This is useful when you want to render different output for screen readers.
2748
2926
  */
2749
2927
  const useIsScreenReaderEnabled = () => {
2750
- const { isScreenReaderEnabled } = useContext(accessibilityContext);
2928
+ const { isScreenReaderEnabled } = (0, import_react.useContext)(accessibilityContext);
2751
2929
  return isScreenReaderEnabled;
2752
2930
  };
2753
2931
  //#endregion
@@ -2760,12 +2938,12 @@ Setting a cursor position makes the cursor visible at the specified coordinates
2760
2938
  Pass `undefined` to hide the cursor.
2761
2939
  */
2762
2940
  const useCursor = () => {
2763
- const context = useContext(CursorContext);
2764
- const positionRef = useRef(void 0);
2765
- const setCursorPosition = useCallback((position) => {
2941
+ const context = (0, import_react.useContext)(CursorContext);
2942
+ const positionRef = (0, import_react.useRef)(void 0);
2943
+ const setCursorPosition = (0, import_react.useCallback)((position) => {
2766
2944
  positionRef.current = position;
2767
2945
  }, []);
2768
- useInsertionEffect(() => {
2946
+ (0, import_react.useInsertionEffect)(() => {
2769
2947
  context.setCursorPosition(positionRef.current);
2770
2948
  return () => {
2771
2949
  context.setCursorPosition(void 0);
@@ -2800,22 +2978,22 @@ return <Text>{characters[frame % characters.length]}</Text>;
2800
2978
  function useAnimation(options) {
2801
2979
  const { interval = defaultAnimationInterval, isActive = true } = options ?? {};
2802
2980
  const safeInterval = normalizeAnimationInterval(interval);
2803
- const { subscribe, renderThrottleMs } = useContext(animationContext);
2804
- const [resetKey, setResetKey] = useState(0);
2805
- const [animState, setAnimState] = useState(zeroAnimState);
2806
- const nextRenderTimeRef = useRef(0);
2807
- const lastRenderTimeRef = useRef(0);
2808
- const previousOptionsRef = useRef({
2981
+ const { subscribe, renderThrottleMs } = (0, import_react.useContext)(animationContext);
2982
+ const [resetKey, setResetKey] = (0, import_react.useState)(0);
2983
+ const [animState, setAnimState] = (0, import_react.useState)(zeroAnimState);
2984
+ const nextRenderTimeRef = (0, import_react.useRef)(0);
2985
+ const lastRenderTimeRef = (0, import_react.useRef)(0);
2986
+ const previousOptionsRef = (0, import_react.useRef)({
2809
2987
  isActive,
2810
2988
  safeInterval,
2811
2989
  resetKey
2812
2990
  });
2813
2991
  const previousOptions = previousOptionsRef.current;
2814
2992
  const shouldReset = isActive && (safeInterval !== previousOptions.safeInterval || !previousOptions.isActive || resetKey !== previousOptions.resetKey);
2815
- const reset = useCallback(() => {
2993
+ const reset = (0, import_react.useCallback)(() => {
2816
2994
  setResetKey((k) => k + 1);
2817
2995
  }, []);
2818
- useLayoutEffect(() => {
2996
+ (0, import_react.useLayoutEffect)(() => {
2819
2997
  if (!isActive) return;
2820
2998
  setAnimState(zeroAnimState);
2821
2999
  let startTime = 0;
@@ -2842,7 +3020,7 @@ function useAnimation(options) {
2842
3020
  renderThrottleMs,
2843
3021
  resetKey
2844
3022
  ]);
2845
- useLayoutEffect(() => {
3023
+ (0, import_react.useLayoutEffect)(() => {
2846
3024
  previousOptionsRef.current = {
2847
3025
  isActive,
2848
3026
  safeInterval,
@@ -2869,48 +3047,48 @@ function normalizeAnimationInterval(interval) {
2869
3047
  //#endregion
2870
3048
  //#region src/hooks/use-terminal-osc.ts
2871
3049
  const useProgress = ({ state, value }) => {
2872
- const terminal = useContext(TerminalOscContext);
2873
- const owner = useRef(void 0);
3050
+ const terminal = (0, import_react.useContext)(TerminalOscContext);
3051
+ const owner = (0, import_react.useRef)(void 0);
2874
3052
  owner.current ??= Symbol("terminal-progress");
2875
- useEffect(() => {
3053
+ (0, import_react.useEffect)(() => {
2876
3054
  terminal.publishProgress(owner.current, state, value);
2877
3055
  }, [
2878
3056
  state,
2879
3057
  terminal,
2880
3058
  value
2881
3059
  ]);
2882
- useEffect(() => {
3060
+ (0, import_react.useEffect)(() => {
2883
3061
  return () => {
2884
3062
  terminal.publishProgress(owner.current, "inactive");
2885
3063
  };
2886
3064
  }, [terminal]);
2887
3065
  };
2888
3066
  const useClipboard = () => {
2889
- const terminal = useContext(TerminalOscContext);
2890
- return useCallback((text, selection) => terminal.copyToClipboard(text, selection), [terminal]);
3067
+ const terminal = (0, import_react.useContext)(TerminalOscContext);
3068
+ return (0, import_react.useCallback)((text, selection) => terminal.copyToClipboard(text, selection), [terminal]);
2891
3069
  };
2892
3070
  const useTitle = (title) => {
2893
- const terminal = useContext(TerminalOscContext);
2894
- const owner = useRef(void 0);
3071
+ const terminal = (0, import_react.useContext)(TerminalOscContext);
3072
+ const owner = (0, import_react.useRef)(void 0);
2895
3073
  owner.current ??= Symbol("terminal-title");
2896
- useEffect(() => {
3074
+ (0, import_react.useEffect)(() => {
2897
3075
  terminal.publishTitle(owner.current, title);
2898
3076
  }, [terminal, title]);
2899
- useEffect(() => () => terminal.publishTitle(owner.current, void 0), [terminal]);
3077
+ (0, import_react.useEffect)(() => () => terminal.publishTitle(owner.current, void 0), [terminal]);
2900
3078
  };
2901
3079
  const useWorkingDirectory = (directory) => {
2902
- const terminal = useContext(TerminalOscContext);
2903
- useEffect(() => {
3080
+ const terminal = (0, import_react.useContext)(TerminalOscContext);
3081
+ (0, import_react.useEffect)(() => {
2904
3082
  terminal.setWorkingDirectory(directory);
2905
3083
  }, [directory, terminal]);
2906
3084
  };
2907
3085
  const useNotification = () => {
2908
- const terminal = useContext(TerminalOscContext);
2909
- return useCallback((title) => terminal.notify(title), [terminal]);
3086
+ const terminal = (0, import_react.useContext)(TerminalOscContext);
3087
+ return (0, import_react.useCallback)((title) => terminal.notify(title), [terminal]);
2910
3088
  };
2911
3089
  const usePointerShape = (shape) => {
2912
- const terminal = useContext(TerminalOscContext);
2913
- useEffect(() => {
3090
+ const terminal = (0, import_react.useContext)(TerminalOscContext);
3091
+ (0, import_react.useEffect)(() => {
2914
3092
  terminal.setPointerShape(shape);
2915
3093
  }, [shape, terminal]);
2916
3094
  };
@@ -2922,10 +3100,15 @@ A React hook that returns the current terminal window dimensions and re-renders
2922
3100
  Reads the capabilities store, so on terminals that send in-band size reports
2923
3101
  (mode 2048) the dimensions are the emulator's own, arriving after it has
2924
3102
  rewrapped its screen; elsewhere they are the stream's `columns`/`rows`.
3103
+ Subscribing to dimensions does not initiate capability queries. In-band reports
3104
+ are used when another consumer has explicitly enabled capability discovery.
2925
3105
  */
2926
3106
  const useWindowSize = () => {
2927
- const { size } = useCapabilities();
2928
- return useMemo(() => ({
3107
+ const { stdin } = useStdinContext();
3108
+ const { stdout } = useStdout();
3109
+ const store = getCapabilities(stdin, stdout);
3110
+ const { size } = (0, import_react.useSyncExternalStore)(store.subscribe, () => store.current);
3111
+ return (0, import_react.useMemo)(() => ({
2929
3112
  columns: size.columns,
2930
3113
  rows: size.rows
2931
3114
  }), [size.columns, size.rows]);
@@ -2970,22 +3153,22 @@ return (
2970
3153
  ```
2971
3154
  */
2972
3155
  const useBoxMetrics = (ref) => {
2973
- const [metrics, setMetrics] = useState(emptyMetrics);
2974
- const [hasMeasured, setHasMeasured] = useState(false);
2975
- const updateMetrics = useCallback(() => {
3156
+ const [metrics, setMetrics] = (0, import_react.useState)(emptyMetrics);
3157
+ const [hasMeasured, setHasMeasured] = (0, import_react.useState)(false);
3158
+ const updateMetrics = (0, import_react.useCallback)(() => {
2976
3159
  const layout = ref.current?.yogaNode?.getComputedLayout() ?? emptyMetrics;
2977
3160
  setMetrics((previousMetrics) => {
2978
3161
  return previousMetrics.width !== layout.width || previousMetrics.height !== layout.height || previousMetrics.left !== layout.left || previousMetrics.top !== layout.top ? layout : previousMetrics;
2979
3162
  });
2980
3163
  setHasMeasured(Boolean(ref.current));
2981
3164
  }, [ref]);
2982
- useEffect(updateMetrics);
2983
- useEffect(() => {
3165
+ (0, import_react.useEffect)(updateMetrics);
3166
+ (0, import_react.useEffect)(() => {
2984
3167
  const rootNode = findRootNode(ref.current);
2985
3168
  if (!rootNode) return;
2986
3169
  return addLayoutListener(rootNode, updateMetrics);
2987
3170
  });
2988
- return useMemo(() => ({
3171
+ return (0, import_react.useMemo)(() => ({
2989
3172
  ...metrics,
2990
3173
  hasMeasured
2991
3174
  }), [metrics, hasMeasured]);
@@ -3026,4 +3209,4 @@ const measureElement = (node) => {
3026
3209
  };
3027
3210
  };
3028
3211
  //#endregion
3029
- export { AnsiText, Box, Hyperlink, Newline, Spacer, Static, Text, Transform, applyTerminalQuery, capabilities, createSupportsColor, detectCapabilities, detectColorLevel, detectHyperlinkSupport, detectTerminal, detectUnicodeSupport, getCapabilities, getTerminalQuery, kittyFlags, kittyModifiers, measureElement, queryTerminal, refreshTerminalQuery, render, renderToString, useAnimation, useApp, useBoxMetrics, useCapabilities, useCapabilitiesChange, useClipboard, useCursor, useFocus, useFocusManager, useInput, useIsScreenReaderEnabled, useNotification, usePaste, usePointerShape, useProgress, useStderr, useStdin, useStdout, useTitle, useWindowSize, useWorkingDirectory };
3212
+ export { AnsiText, Box, Hyperlink, Newline, Spacer, Static, Text, Transform, VirtualList, applyTerminalQuery, capabilities, createSupportsColor, detectCapabilities, detectColorLevel, detectHyperlinkSupport, detectTerminal, detectUnicodeSupport, getCapabilities, getTerminalQuery, kittyFlags, kittyModifiers, measureElement, queryTerminal, refreshTerminalQuery, render, renderToString, useAnimation, useApp, useBoxMetrics, useCapabilities, useCapabilitiesChange, useClipboard, useCursor, useFocus, useFocusManager, useInput, useIsScreenReaderEnabled, useNotification, usePaste, usePointerShape, useProgress, useStderr, useStdin, useStdout, useTitle, useVirtualScroll, useWindowSize, useWorkingDirectory };