@alchemy.run/sigil 0.0.0-alpha.2 → 0.0.0-alpha.4

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 (107) hide show
  1. package/README.md +2 -4
  2. package/THIRD_PARTY_NOTICES.md +31 -22
  3. package/dist/ansi.d.ts +17 -14
  4. package/dist/ansi.js +7 -2
  5. package/dist/{devtools-BhYGjb7h.js → devtools-DbthxoD1.js} +22 -23
  6. package/dist/index.d.ts +125 -288
  7. package/dist/index.js +2460 -2864
  8. package/dist/{truncate-CBiyyZzw.js → truncate-Cr6xVFMa.js} +447 -273
  9. package/package.json +3 -9
  10. package/src/ansi/chalk.ts +8 -51
  11. package/src/ansi/cursor.ts +2 -4
  12. package/src/ansi/east-asian-width.ts +44 -0
  13. package/src/ansi/escapes.ts +4 -26
  14. package/src/ansi/index.ts +12 -14
  15. package/src/ansi/sgr.ts +2 -5
  16. package/src/ansi/slice.ts +1 -1
  17. package/src/ansi/string-width.ts +91 -206
  18. package/src/ansi/strip.ts +13 -33
  19. package/src/ansi/supports-color.ts +8 -14
  20. package/src/ansi/tokenize.ts +94 -166
  21. package/src/ansi/truncate.ts +5 -3
  22. package/src/ansi/wrap.ts +13 -14
  23. package/src/ansi-tokenizer.ts +1 -1
  24. package/src/colorize.ts +1 -1
  25. package/src/components/App.tsx +14 -14
  26. package/src/components/BackgroundContext.ts +2 -2
  27. package/src/components/Box.tsx +51 -59
  28. package/src/components/CursorContext.ts +1 -1
  29. package/src/components/ErrorBoundary.tsx +2 -1
  30. package/src/components/ErrorOverview.tsx +9 -7
  31. package/src/components/Newline.tsx +1 -0
  32. package/src/components/Spacer.tsx +2 -1
  33. package/src/components/Static.tsx +2 -1
  34. package/src/components/StderrContext.ts +0 -2
  35. package/src/components/StdinContext.ts +0 -1
  36. package/src/components/StdoutContext.ts +1 -3
  37. package/src/components/Text.tsx +7 -6
  38. package/src/components/Transform.tsx +2 -1
  39. package/src/cursor-position.ts +1 -1
  40. package/src/devtools.ts +84 -24
  41. package/src/dom.ts +7 -7
  42. package/src/env.ts +12 -0
  43. package/src/get-max-width.ts +1 -1
  44. package/src/global.d.ts +3 -4
  45. package/src/{boxes.ts → glyphs.ts} +17 -18
  46. package/src/hooks/use-animation.ts +1 -1
  47. package/src/hooks/use-app.ts +1 -1
  48. package/src/hooks/use-box-metrics.ts +1 -1
  49. package/src/hooks/use-cursor.ts +2 -2
  50. package/src/hooks/use-focus-manager.ts +1 -1
  51. package/src/hooks/use-focus.ts +5 -6
  52. package/src/hooks/use-input.ts +4 -4
  53. package/src/hooks/use-is-screen-reader-enabled.ts +1 -1
  54. package/src/hooks/use-paste.ts +2 -2
  55. package/src/hooks/use-stderr.ts +1 -1
  56. package/src/hooks/use-stdin.ts +1 -1
  57. package/src/hooks/use-stdout.ts +1 -1
  58. package/src/hooks/use-window-size.ts +2 -2
  59. package/src/index.ts +44 -44
  60. package/src/ink.tsx +536 -720
  61. package/src/input-parser.ts +1 -1
  62. package/src/instances.ts +1 -1
  63. package/src/kitty-keyboard.ts +128 -0
  64. package/src/log-update.ts +4 -4
  65. package/src/measure-element.ts +1 -1
  66. package/src/measure-text.ts +2 -2
  67. package/src/output.ts +4 -4
  68. package/src/parse-keypress.ts +4 -5
  69. package/src/parse-stack-line.ts +0 -1
  70. package/src/patch-console.ts +44 -0
  71. package/src/reconciler.ts +13 -60
  72. package/src/render-background.ts +3 -3
  73. package/src/render-border.ts +6 -6
  74. package/src/render-node-to-output.ts +13 -11
  75. package/src/render-to-string.ts +4 -4
  76. package/src/render.ts +9 -10
  77. package/src/renderer.ts +3 -3
  78. package/src/sanitize-ansi.ts +1 -1
  79. package/src/signal-exit.ts +4 -5
  80. package/src/squash-text-nodes.ts +2 -2
  81. package/src/stream.ts +2 -4
  82. package/src/styles.ts +6 -6
  83. package/src/terminal-size.ts +9 -8
  84. package/src/types.ts +1 -6
  85. package/src/utils.ts +2 -2
  86. package/src/wrap-text.ts +4 -4
  87. package/src/yoga/config.ts +2 -2
  88. package/src/yoga/core/absoluteLayout.ts +15 -15
  89. package/src/yoga/core/baseline.ts +3 -3
  90. package/src/yoga/core/cache.ts +4 -4
  91. package/src/yoga/core/calculateLayout.ts +33 -27
  92. package/src/yoga/core/config.ts +1 -1
  93. package/src/yoga/core/flexLine.ts +3 -3
  94. package/src/yoga/core/helpers.ts +3 -3
  95. package/src/yoga/core/layoutResults.ts +4 -4
  96. package/src/yoga/core/node.ts +16 -16
  97. package/src/yoga/core/pixelGrid.ts +4 -4
  98. package/src/yoga/core/style.ts +11 -11
  99. package/src/yoga/core/types.ts +2 -2
  100. package/src/yoga/index.ts +6 -6
  101. package/src/yoga/node.ts +8 -8
  102. package/src/ansi/widest-line.ts +0 -12
  103. package/src/auto-bind.ts +0 -41
  104. package/src/devtools-window-polyfill.ts +0 -73
  105. package/src/indent-string.ts +0 -16
  106. package/src/is-in-ci.ts +0 -7
  107. package/src/write-synchronized.ts +0 -9
@@ -1,12 +1,12 @@
1
- import { forwardRef, useContext, type PropsWithChildren } from "react";
1
+ /** @jsxImportSource react */
2
+ import { useContext, type PropsWithChildren, type Ref } from "react";
2
3
 
3
- import { type DOMElement } from "../dom.ts";
4
- import { type Styles } from "../styles.ts";
5
- import { type Except } from "../types.ts";
6
- import { accessibilityContext } from "./AccessibilityContext.ts";
7
- import { backgroundContext } from "./BackgroundContext.ts";
4
+ import { accessibilityContext } from "#/components/AccessibilityContext.ts";
5
+ import { backgroundContext } from "#/components/BackgroundContext.ts";
6
+ import { type DOMElement } from "#/dom.ts";
7
+ import { type Styles } from "#/styles.ts";
8
8
 
9
- export type Props = Except<Styles, "textWrap"> & {
9
+ export type Props = Omit<Styles, "textWrap"> & {
10
10
  /**
11
11
  A label for the element for screen readers.
12
12
  */
@@ -59,58 +59,50 @@ export type Props = Except<Styles, "textWrap"> & {
59
59
  /**
60
60
  `<Box>` is an essential Ink component to build your layout. It's like `<div style="display: flex">` in the browser.
61
61
  */
62
- export const Box = forwardRef<DOMElement, PropsWithChildren<Props>>(
63
- (
64
- {
65
- children,
66
- backgroundColor,
67
- "aria-label": ariaLabel,
68
- "aria-hidden": ariaHidden,
69
- "aria-role": role,
70
- "aria-state": ariaState,
71
- ...style
72
- },
73
- ref,
74
- ) => {
75
- const { isScreenReaderEnabled } = useContext(accessibilityContext);
76
- const label = ariaLabel ? <ink-text>{ariaLabel}</ink-text> : undefined;
77
- if (isScreenReaderEnabled && ariaHidden) {
78
- return null;
79
- }
62
+ export function Box({
63
+ children,
64
+ ref,
65
+ backgroundColor,
66
+ "aria-label": ariaLabel,
67
+ "aria-hidden": ariaHidden,
68
+ "aria-role": role,
69
+ "aria-state": ariaState,
70
+ ...style
71
+ }: PropsWithChildren<Props> & { readonly ref?: Ref<DOMElement> }) {
72
+ const { isScreenReaderEnabled } = useContext(accessibilityContext);
73
+ const label = ariaLabel ? <ink-text>{ariaLabel}</ink-text> : undefined;
74
+ if (isScreenReaderEnabled && ariaHidden) {
75
+ return null;
76
+ }
80
77
 
81
- const boxElement = (
82
- <ink-box
83
- ref={ref}
84
- style={{
85
- flexWrap: "nowrap",
86
- flexDirection: "row",
87
- flexGrow: 0,
88
- flexShrink: 1,
89
- ...style,
90
- backgroundColor,
91
- overflowX: style.overflowX ?? style.overflow ?? "visible",
92
- overflowY: style.overflowY ?? style.overflow ?? "visible",
93
- }}
94
- internal_accessibility={{
95
- role,
96
- state: ariaState,
97
- }}
98
- >
99
- {isScreenReaderEnabled && label ? label : children}
100
- </ink-box>
101
- );
102
-
103
- // If this Box has a background color, provide it to children via context
104
- if (backgroundColor) {
105
- return (
106
- <backgroundContext.Provider value={backgroundColor}>
107
- {boxElement}
108
- </backgroundContext.Provider>
109
- );
110
- }
78
+ const boxElement = (
79
+ <ink-box
80
+ ref={ref}
81
+ style={{
82
+ flexWrap: "nowrap",
83
+ flexDirection: "row",
84
+ flexGrow: 0,
85
+ flexShrink: 1,
86
+ ...style,
87
+ backgroundColor,
88
+ overflowX: style.overflowX ?? style.overflow ?? "visible",
89
+ overflowY: style.overflowY ?? style.overflow ?? "visible",
90
+ }}
91
+ internal_accessibility={{
92
+ role,
93
+ state: ariaState,
94
+ }}
95
+ >
96
+ {isScreenReaderEnabled && label ? label : children}
97
+ </ink-box>
98
+ );
111
99
 
112
- return boxElement;
113
- },
114
- );
100
+ // If this Box has a background color, provide it to children via context
101
+ if (backgroundColor) {
102
+ return (
103
+ <backgroundContext.Provider value={backgroundColor}>{boxElement}</backgroundContext.Provider>
104
+ );
105
+ }
115
106
 
116
- Box.displayName = "Box";
107
+ return boxElement;
108
+ }
@@ -1,6 +1,6 @@
1
1
  import { createContext } from "react";
2
2
 
3
- import { type CursorPosition } from "../log-update.ts";
3
+ import { type CursorPosition } from "#/log-update.ts";
4
4
 
5
5
  export type Props = {
6
6
  /**
@@ -1,6 +1,7 @@
1
+ /** @jsxImportSource react */
1
2
  import { PureComponent, type ReactNode } from "react";
2
3
 
3
- import { ErrorOverview } from "./ErrorOverview.tsx";
4
+ import { ErrorOverview } from "#/components/ErrorOverview.tsx";
4
5
 
5
6
  type Props = {
6
7
  readonly children: ReactNode;
@@ -1,10 +1,12 @@
1
- import * as fs from "node:fs";
1
+ /** @jsxImportSource react */
2
+
3
+ import { existsSync, readFileSync } from "node:fs";
2
4
  import { cwd } from "node:process";
3
5
 
4
- import { codeExcerpt, type CodeExcerpt } from "../code-excerpt.ts";
5
- import { parseStackLine } from "../parse-stack-line.ts";
6
- import { Box } from "./Box.tsx";
7
- import { Text } from "./Text.tsx";
6
+ import { codeExcerpt, type CodeExcerpt } from "#/code-excerpt.ts";
7
+ import { Box } from "#/components/Box.tsx";
8
+ import { Text } from "#/components/Text.tsx";
9
+ import { parseStackLine } from "#/parse-stack-line.ts";
8
10
 
9
11
  // Error's source file is reported as file:///home/user/file.js
10
12
  // This function removes the file://[cwd] part
@@ -24,8 +26,8 @@ export function ErrorOverview({ error }: Props) {
24
26
  let lineWidth = 0;
25
27
  const stackLineCounts = new Map<string, number>();
26
28
 
27
- if (filePath && origin?.line && fs.existsSync(filePath)) {
28
- const sourceCode = fs.readFileSync(filePath, "utf8");
29
+ if (filePath && origin?.line && existsSync(filePath)) {
30
+ const sourceCode = readFileSync(filePath, "utf8");
29
31
  excerpt = codeExcerpt(sourceCode, origin.line);
30
32
 
31
33
  if (excerpt) {
@@ -1,3 +1,4 @@
1
+ /** @jsxImportSource react */
1
2
  export type Props = {
2
3
  /**
3
4
  Number of newlines to insert.
@@ -1,4 +1,5 @@
1
- import { Box } from "./Box.tsx";
1
+ /** @jsxImportSource react */
2
+ import { Box } from "#/components/Box.tsx";
2
3
 
3
4
  /**
4
5
  A flexible space that expands along the major axis of its containing layout.
@@ -1,6 +1,7 @@
1
+ /** @jsxImportSource react */
1
2
  import { useMemo, useState, useLayoutEffect, type ReactNode } from "react";
2
3
 
3
- import { type Styles } from "../styles.ts";
4
+ import { type Styles } from "#/styles.ts";
4
5
 
5
6
  export type Props<T> = {
6
7
  /**
@@ -1,5 +1,3 @@
1
- import process from "node:process";
2
-
3
1
  import { createContext } from "react";
4
2
 
5
3
  export type Props = {
@@ -1,5 +1,4 @@
1
1
  import { EventEmitter } from "node:events";
2
- import process from "node:process";
3
2
 
4
3
  import { createContext } from "react";
5
4
 
@@ -1,8 +1,6 @@
1
- import process from "node:process";
2
-
3
1
  import { createContext } from "react";
4
2
 
5
- import type { OutputStream } from "../stream.ts";
3
+ import type { OutputStream } from "#/stream.ts";
6
4
 
7
5
  export type Props = {
8
6
  /**
@@ -1,11 +1,12 @@
1
+ /** @jsxImportSource react */
1
2
  import { useContext, type ReactNode } from "react";
2
3
 
3
- import { chalk, type ForegroundColorName } from "../ansi/chalk.ts";
4
- import { colorize } from "../colorize.ts";
5
- import { type Styles } from "../styles.ts";
6
- import { type LiteralUnion } from "../types.ts";
7
- import { accessibilityContext } from "./AccessibilityContext.ts";
8
- import { backgroundContext } from "./BackgroundContext.ts";
4
+ import { chalk, type ForegroundColorName } from "#/ansi/chalk.ts";
5
+ import { colorize } from "#/colorize.ts";
6
+ import { accessibilityContext } from "#/components/AccessibilityContext.ts";
7
+ import { backgroundContext } from "#/components/BackgroundContext.ts";
8
+ import { type Styles } from "#/styles.ts";
9
+ import { type LiteralUnion } from "#/types.ts";
9
10
 
10
11
  export type Props = {
11
12
  /**
@@ -1,6 +1,7 @@
1
+ /** @jsxImportSource react */
1
2
  import { useContext, type ReactNode } from "react";
2
3
 
3
- import { accessibilityContext } from "./AccessibilityContext.ts";
4
+ import { accessibilityContext } from "#/components/AccessibilityContext.ts";
4
5
 
5
6
  export type Props = {
6
7
  /**
@@ -1,4 +1,4 @@
1
- import { ansiEscapes } from "./ansi/escapes.ts";
1
+ import { ansiEscapes } from "#/ansi/escapes.ts";
2
2
 
3
3
  export type CursorPosition = {
4
4
  x: number;
package/src/devtools.ts CHANGED
@@ -1,41 +1,101 @@
1
- /* eslint-disable import-x/order */
1
+ import { setTimeout } from "node:timers";
2
2
 
3
- // eslint-disable-next-line import-x/no-unassigned-import
4
- import "./devtools-window-polyfill.ts";
5
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
6
- // @ts-expect-error
7
- import devtools from "react-devtools-core";
8
- import WebSocket from "ws";
3
+ // Node 22.4+ ships a stable browser-compatible WebSocket client, so no `ws`
4
+ // dependency is needed. react-devtools-core resolves the constructor via the
5
+ // `window`/`ws` globals defined here.
6
+ Object.defineProperties(globalThis, {
7
+ ws: { value: WebSocket },
8
+ window: { value: globalThis },
9
+ self: { value: globalThis },
10
+ });
9
11
 
10
- const isDevToolsReachable = async (): Promise<boolean> =>
11
- new Promise((resolve) => {
12
+ // Filter out Ink's internal components from devtools for a cleaner view.
13
+ // Also, since `react-devtools-shared` package isn't published on npm, we can't
14
+ // use its types, that's why there are hard-coded values in `type` fields below.
15
+ // See https://github.com/facebook/react/blob/edf6eac8a181860fd8a2d076a43806f1237495a1/packages/react-devtools-shared/src/types.js#L24
16
+ Object.defineProperty(globalThis, "__REACT_DEVTOOLS_COMPONENT_FILTERS__", {
17
+ value: [
18
+ {
19
+ // ComponentFilterElementType
20
+ type: 1,
21
+ // ElementTypeHostComponent
22
+ value: 7,
23
+ isEnabled: true,
24
+ },
25
+ {
26
+ // ComponentFilterDisplayName
27
+ type: 2,
28
+ value: "InternalApp",
29
+ isEnabled: true,
30
+ isValid: true,
31
+ },
32
+ {
33
+ // ComponentFilterDisplayName
34
+ type: 2,
35
+ value: "InternalAppContext",
36
+ isEnabled: true,
37
+ isValid: true,
38
+ },
39
+ {
40
+ // ComponentFilterDisplayName
41
+ type: 2,
42
+ value: "InternalStdoutContext",
43
+ isEnabled: true,
44
+ isValid: true,
45
+ },
46
+ {
47
+ // ComponentFilterDisplayName
48
+ type: 2,
49
+ value: "InternalStderrContext",
50
+ isEnabled: true,
51
+ isValid: true,
52
+ },
53
+ {
54
+ // ComponentFilterDisplayName
55
+ type: 2,
56
+ value: "InternalStdinContext",
57
+ isEnabled: true,
58
+ isValid: true,
59
+ },
60
+ {
61
+ // ComponentFilterDisplayName
62
+ type: 2,
63
+ value: "InternalFocusContext",
64
+ isEnabled: true,
65
+ isValid: true,
66
+ },
67
+ ],
68
+ });
69
+
70
+ const isDevToolsReachable = () =>
71
+ new Promise<boolean>((resolve) => {
12
72
  const socket = new WebSocket("ws://localhost:8097");
13
73
 
74
+ const settle = (reachable: boolean) => {
75
+ clearTimeout(timeout);
76
+ socket.close();
77
+ resolve(reachable);
78
+ };
79
+
14
80
  const timeout = setTimeout(() => {
15
- socket.terminate();
16
- resolve(false);
81
+ settle(false);
17
82
  }, 2000);
18
83
  // Don't let the timeout keep the process alive on its own
19
84
  timeout.unref();
20
85
 
21
- socket.on("open", () => {
22
- clearTimeout(timeout);
23
- socket.terminate();
24
- resolve(true);
86
+ socket.addEventListener("open", () => {
87
+ settle(true);
25
88
  });
26
-
27
- socket.on("error", () => {
28
- clearTimeout(timeout);
29
- socket.terminate();
30
- resolve(false);
89
+ socket.addEventListener("error", () => {
90
+ settle(false);
31
91
  });
32
92
  });
33
93
 
34
94
  if (await isDevToolsReachable()) {
35
- // eslint-disable-next-line @typescript-eslint/no-unsafe-call
36
- (devtools as any).initialize();
37
- // eslint-disable-next-line @typescript-eslint/no-unsafe-call
38
- (devtools as any).connectToDevTools();
95
+ // @ts-expect-error: react-devtools-core is not typed
96
+ const devtools = await import("react-devtools-core");
97
+ devtools.initialize();
98
+ devtools.connectToDevTools();
39
99
  } else {
40
100
  console.warn(
41
101
  "SIGIL_DEV is set to true, but the React DevTools server is not running. Start it with:\n\n$ npx react-devtools\n",
package/src/dom.ts CHANGED
@@ -1,9 +1,9 @@
1
- import { measureText } from "./measure-text.ts";
2
- import { type OutputTransformer } from "./render-node-to-output.ts";
3
- import { squashTextNodes } from "./squash-text-nodes.ts";
4
- import { type Styles } from "./styles.ts";
5
- import { wrapText } from "./wrap-text.ts";
6
- import { Yoga, type Node as YogaNode } from "./yoga/index.ts";
1
+ import { measureText } from "#/measure-text.ts";
2
+ import { type OutputTransformer } from "#/render-node-to-output.ts";
3
+ import { squashTextNodes } from "#/squash-text-nodes.ts";
4
+ import { type Styles } from "#/styles.ts";
5
+ import { wrapText } from "#/wrap-text.ts";
6
+ import { Yoga, type Node as YogaNode } from "#/yoga/index.ts";
7
7
 
8
8
  type InkNode = {
9
9
  parentNode: DOMElement | undefined;
@@ -101,7 +101,7 @@ export const createNode = (nodeName: ElementNames): DOMElement => {
101
101
  };
102
102
 
103
103
  if (nodeName === "ink-text") {
104
- node.yogaNode?.setMeasureFunc(measureTextNode.bind(null, node));
104
+ node.yogaNode?.setMeasureFunc((width) => measureTextNode(node, width));
105
105
  }
106
106
 
107
107
  return node;
package/src/env.ts ADDED
@@ -0,0 +1,12 @@
1
+ // Every modern CI provider sets CI=1 (or CI=true), so any non-empty value
2
+ export const isInCi = Boolean(process.env.CI);
3
+
4
+ export const isSigilDev = process.env.SIGIL_DEV === "true";
5
+
6
+ export const isScreenReader = process.env.SIGIL_SCREEN_READER === "true";
7
+
8
+ export const isWindows = process.platform === "win32";
9
+
10
+ export const isMacos = process.platform === "darwin";
11
+
12
+ export const isTty = (stream: NodeJS.ReadableStream) => "isTTY" in stream && stream.isTTY === true;
@@ -1,4 +1,4 @@
1
- import { Yoga, type Node as YogaNode } from "./yoga/index.ts";
1
+ import { Yoga, type Node as YogaNode } from "#/yoga/index.ts";
2
2
 
3
3
  export const getMaxWidth = (yogaNode: YogaNode) => {
4
4
  return (
package/src/global.d.ts CHANGED
@@ -1,8 +1,7 @@
1
1
  import { type ReactNode, type Key, type Ref } from "react";
2
2
 
3
- import { type DOMElement } from "./dom.ts";
4
- import { type Styles } from "./styles.ts";
5
- import { type Except } from "./types.ts";
3
+ import { type DOMElement } from "#/dom.ts";
4
+ import { type Styles } from "#/styles.ts";
6
5
 
7
6
  declare module "react" {
8
7
  namespace JSX {
@@ -20,7 +19,7 @@ declare namespace Ink {
20
19
  children?: ReactNode;
21
20
  key?: Key;
22
21
  ref?: Ref<DOMElement>;
23
- style?: Except<Styles, "textWrap">;
22
+ style?: Omit<Styles, "textWrap">;
24
23
  internal_accessibility?: DOMElement["internal_accessibility"];
25
24
  };
26
25
 
@@ -1,20 +1,5 @@
1
1
  // Derived from `cli-boxes` (MIT, Sindre Sorhus).
2
-
3
- /**
4
- Style of the box border.
5
- */
6
- export type BoxStyle = {
7
- readonly topLeft: string;
8
- readonly top: string;
9
- readonly topRight: string;
10
- readonly right: string;
11
- readonly bottomRight: string;
12
- readonly bottom: string;
13
- readonly bottomLeft: string;
14
- readonly left: string;
15
- };
16
-
17
- export const boxes = {
2
+ export const BOXES = {
18
3
  single: {
19
4
  topLeft: "┌",
20
5
  top: "─",
@@ -95,6 +80,20 @@ export const boxes = {
95
80
  bottomLeft: "↗",
96
81
  left: "→",
97
82
  },
98
- } as const satisfies Record<string, BoxStyle>;
83
+ } as const;
99
84
 
100
- export type Boxes = typeof boxes;
85
+ export type BoxStyle = keyof typeof BOXES;
86
+
87
+ /**
88
+ The set of glyphs making up a box border, for custom `borderStyle` objects.
89
+ */
90
+ export type BoxGlyphs = {
91
+ readonly topLeft: string;
92
+ readonly top: string;
93
+ readonly topRight: string;
94
+ readonly right: string;
95
+ readonly bottomRight: string;
96
+ readonly bottom: string;
97
+ readonly bottomLeft: string;
98
+ readonly left: string;
99
+ };
@@ -1,6 +1,6 @@
1
1
  import { useState, useLayoutEffect, useRef, useCallback, useContext } from "react";
2
2
 
3
- import { animationContext as AnimationContext } from "../components/AnimationContext.ts";
3
+ import { animationContext as AnimationContext } from "#/components/AnimationContext.ts";
4
4
 
5
5
  const defaultAnimationInterval = 100;
6
6
  const maximumTimerInterval = 2_147_483_647;
@@ -1,6 +1,6 @@
1
1
  import { useContext } from "react";
2
2
 
3
- import { AppContext } from "../components/AppContext.ts";
3
+ import { AppContext } from "#/components/AppContext.ts";
4
4
 
5
5
  /**
6
6
  A React hook that returns app lifecycle methods like `exit()` and `waitUntilRenderFlush()`.
@@ -1,6 +1,6 @@
1
1
  import { type RefObject, useState, useEffect, useCallback, useMemo } from "react";
2
2
 
3
- import { type DOMElement, addLayoutListener } from "../dom.ts";
3
+ import { type DOMElement, addLayoutListener } from "#/dom.ts";
4
4
 
5
5
  // Yoga's `right`/`bottom` are omitted: always `0` for flow layout and unintuitive for absolute positioning.
6
6
  /**
@@ -1,7 +1,7 @@
1
1
  import { useContext, useRef, useCallback, useInsertionEffect } from "react";
2
2
 
3
- import { CursorContext } from "../components/CursorContext.ts";
4
- import { type CursorPosition } from "../log-update.ts";
3
+ import { CursorContext } from "#/components/CursorContext.ts";
4
+ import { type CursorPosition } from "#/log-update.ts";
5
5
 
6
6
  /**
7
7
  A React hook that returns methods to control the terminal cursor position.
@@ -1,6 +1,6 @@
1
1
  import { useContext } from "react";
2
2
 
3
- import { FocusContext, type Props } from "../components/FocusContext.ts";
3
+ import { FocusContext, type Props } from "#/components/FocusContext.ts";
4
4
 
5
5
  type Output = {
6
6
  /**
@@ -1,7 +1,7 @@
1
- import { useEffect, useContext, useMemo } from "react";
1
+ import { useEffect, useContext, useId } from "react";
2
2
 
3
- import { FocusContext } from "../components/FocusContext.ts";
4
- import { useStdin } from "./use-stdin.ts";
3
+ import { FocusContext } from "#/components/FocusContext.ts";
4
+ import { useStdin } from "#/hooks/use-stdin.ts";
5
5
 
6
6
  type Input = {
7
7
  /**
@@ -44,9 +44,8 @@ export const useFocus = ({
44
44
  const { isRawModeSupported, setRawMode } = useStdin();
45
45
  const { activeId, add, remove, activate, deactivate, focus } = useContext(FocusContext);
46
46
 
47
- const id = useMemo(() => {
48
- return customId ?? Math.random().toString().slice(2, 7);
49
- }, [customId]);
47
+ const autoId = useId();
48
+ const id = customId ?? autoId;
50
49
 
51
50
  useEffect(() => {
52
51
  add(id, { autoFocus });
@@ -1,9 +1,9 @@
1
1
  import { useEffect, useEffectEvent } from "react";
2
2
 
3
- import { ESC } from "../ansi/escapes.ts";
4
- import { parseKeypress, nonAlphanumericKeys } from "../parse-keypress.ts";
5
- import { reconciler } from "../reconciler.ts";
6
- import { useStdinContext } from "./use-stdin.ts";
3
+ import { ESC } from "#/ansi/escapes.ts";
4
+ import { useStdinContext } from "#/hooks/use-stdin.ts";
5
+ import { parseKeypress, nonAlphanumericKeys } from "#/parse-keypress.ts";
6
+ import { reconciler } from "#/reconciler.ts";
7
7
 
8
8
  /**
9
9
  Handy information about a key that was pressed.
@@ -1,6 +1,6 @@
1
1
  import { useContext } from "react";
2
2
 
3
- import { accessibilityContext } from "../components/AccessibilityContext.ts";
3
+ import { accessibilityContext } from "#/components/AccessibilityContext.ts";
4
4
 
5
5
  /**
6
6
  A React hook that returns whether a screen reader is enabled.
@@ -1,7 +1,7 @@
1
1
  import { useEffect, useEffectEvent } from "react";
2
2
 
3
- import { reconciler } from "../reconciler.ts";
4
- import { useStdinContext } from "./use-stdin.ts";
3
+ import { useStdinContext } from "#/hooks/use-stdin.ts";
4
+ import { reconciler } from "#/reconciler.ts";
5
5
 
6
6
  type Options = {
7
7
  /**
@@ -1,6 +1,6 @@
1
1
  import { useContext } from "react";
2
2
 
3
- import { StderrContext } from "../components/StderrContext.ts";
3
+ import { StderrContext } from "#/components/StderrContext.ts";
4
4
 
5
5
  /**
6
6
  A React hook that returns the stderr stream.
@@ -1,6 +1,6 @@
1
1
  import { useContext } from "react";
2
2
 
3
- import { StdinContext, type PublicProps, type Props } from "../components/StdinContext.ts";
3
+ import { StdinContext, type PublicProps, type Props } from "#/components/StdinContext.ts";
4
4
 
5
5
  /**
6
6
  A React hook that returns the stdin stream and stdin-related utilities.
@@ -1,6 +1,6 @@
1
1
  import { useContext } from "react";
2
2
 
3
- import { StdoutContext } from "../components/StdoutContext.ts";
3
+ import { StdoutContext } from "#/components/StdoutContext.ts";
4
4
 
5
5
  /**
6
6
  A React hook that returns the stdout stream where Ink renders your app.
@@ -1,7 +1,7 @@
1
1
  import { useState, useEffect } from "react";
2
2
 
3
- import { getWindowSize } from "../utils.ts";
4
- import { useStdout } from "./use-stdout.ts";
3
+ import { useStdout } from "#/hooks/use-stdout.ts";
4
+ import { getWindowSize } from "#/utils.ts";
5
5
 
6
6
  /**
7
7
  Dimensions of the terminal window.