tinky 0.1.0 → 1.0.0
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/README.ja-JP.md +2 -0
- package/README.md +2 -0
- package/README.zh-CN.md +2 -0
- package/lib/components/AccessibilityContext.d.ts +25 -4
- package/lib/components/AccessibilityContext.js +16 -1
- package/lib/components/BackgroundContext.d.ts +15 -0
- package/lib/components/BackgroundContext.js +4 -0
- package/lib/components/FocusContext.d.ts +13 -2
- package/lib/dimension.d.ts +9 -0
- package/lib/dimension.js +1 -0
- package/lib/dom.d.ts +28 -2
- package/lib/hooks/use-app.d.ts +1 -1
- package/lib/hooks/use-app.js +1 -1
- package/lib/hooks/use-focus-manager.d.ts +3 -4
- package/lib/hooks/use-focus.d.ts +4 -5
- package/lib/hooks/use-input.d.ts +3 -4
- package/lib/hooks/use-stdout.d.ts +17 -1
- package/lib/hooks/use-stdout.js +5 -0
- package/lib/index.d.ts +10 -6
- package/lib/index.js +3 -3
- package/lib/measure-element.d.ts +2 -12
- package/lib/measure-text.d.ts +2 -6
- package/lib/output.d.ts +7 -15
- package/lib/output.js +3 -3
- package/lib/parse-keypress.d.ts +11 -0
- package/lib/reconciler.js +12 -3
- package/lib/render.d.ts +4 -2
- package/lib/styles.d.ts +1 -1
- package/lib/styles.js +1 -1
- package/lib/taffy-node.d.ts +5 -0
- package/lib/taffy-node.js +5 -0
- package/lib/tinky.d.ts +18 -0
- package/lib/tinky.js +18 -6
- package/package.json +25 -8
package/README.ja-JP.md
CHANGED
package/README.md
CHANGED
package/README.zh-CN.md
CHANGED
|
@@ -1,9 +1,30 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Value type for the AccessibilityContext.
|
|
3
3
|
*/
|
|
4
|
-
export
|
|
4
|
+
export interface AccessibilityContextValue {
|
|
5
5
|
/**
|
|
6
6
|
* Whether the screen reader is enabled.
|
|
7
|
+
*
|
|
8
|
+
* @defaultValue false
|
|
7
9
|
*/
|
|
8
|
-
isScreenReaderEnabled: boolean;
|
|
9
|
-
}
|
|
10
|
+
readonly isScreenReaderEnabled: boolean;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Context to manage accessibility settings, specifically screen reader.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```tsx
|
|
17
|
+
* import { useIsScreenReaderEnabled } from 'tinky';
|
|
18
|
+
*
|
|
19
|
+
* const Component = () => {
|
|
20
|
+
* const isScreenReaderEnabled = useIsScreenReaderEnabled();
|
|
21
|
+
*
|
|
22
|
+
* if (isScreenReaderEnabled) {
|
|
23
|
+
* return <Text>Screen reader friendly output</Text>;
|
|
24
|
+
* }
|
|
25
|
+
*
|
|
26
|
+
* return <Text>Regular output</Text>;
|
|
27
|
+
* };
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export declare const AccessibilityContext: import("react").Context<AccessibilityContextValue>;
|
|
@@ -1,6 +1,21 @@
|
|
|
1
1
|
import { createContext } from "react";
|
|
2
2
|
/**
|
|
3
|
-
* Context to manage accessibility settings, specifically screen reader
|
|
3
|
+
* Context to manage accessibility settings, specifically screen reader.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```tsx
|
|
7
|
+
* import { useIsScreenReaderEnabled } from 'tinky';
|
|
8
|
+
*
|
|
9
|
+
* const Component = () => {
|
|
10
|
+
* const isScreenReaderEnabled = useIsScreenReaderEnabled();
|
|
11
|
+
*
|
|
12
|
+
* if (isScreenReaderEnabled) {
|
|
13
|
+
* return <Text>Screen reader friendly output</Text>;
|
|
14
|
+
* }
|
|
15
|
+
*
|
|
16
|
+
* return <Text>Regular output</Text>;
|
|
17
|
+
* };
|
|
18
|
+
* ```
|
|
4
19
|
*/
|
|
5
20
|
export const AccessibilityContext = createContext({
|
|
6
21
|
/**
|
|
@@ -2,9 +2,24 @@ import { type LiteralUnion } from "type-fest";
|
|
|
2
2
|
import { type ForegroundColorName } from "ansi-styles";
|
|
3
3
|
/**
|
|
4
4
|
* Union type for background colors.
|
|
5
|
+
*
|
|
6
|
+
* Accepts any named color from `ansi-styles`, hex colors, RGB colors,
|
|
7
|
+
* or ANSI 256 color codes.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```tsx
|
|
11
|
+
* backgroundColor="red" // Named color
|
|
12
|
+
* backgroundColor="#ff6600" // Hex color
|
|
13
|
+
* backgroundColor="rgb(255, 102, 0)" // RGB color
|
|
14
|
+
* backgroundColor="ansi256:208" // ANSI 256 color
|
|
15
|
+
* ```
|
|
5
16
|
*/
|
|
6
17
|
export type BackgroundColor = LiteralUnion<ForegroundColorName, string>;
|
|
7
18
|
/**
|
|
8
19
|
* Context to pass the background color down the component tree.
|
|
20
|
+
*
|
|
21
|
+
* Allows nested components to inherit the background color from parents.
|
|
22
|
+
*
|
|
23
|
+
* @defaultValue undefined
|
|
9
24
|
*/
|
|
10
25
|
export declare const backgroundContext: import("react").Context<BackgroundColor | undefined>;
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { createContext } from "react";
|
|
2
2
|
/**
|
|
3
3
|
* Context to pass the background color down the component tree.
|
|
4
|
+
*
|
|
5
|
+
* Allows nested components to inherit the background color from parents.
|
|
6
|
+
*
|
|
7
|
+
* @defaultValue undefined
|
|
4
8
|
*/
|
|
5
9
|
export const backgroundContext = createContext(undefined);
|
|
@@ -8,20 +8,29 @@ export interface FocusProps {
|
|
|
8
8
|
readonly activeId?: string;
|
|
9
9
|
/**
|
|
10
10
|
* Register a new focusable component.
|
|
11
|
+
*
|
|
12
|
+
* @param id - Unique identifier for the focusable component.
|
|
13
|
+
* @param options.autoFocus - Auto-focus the component when registered.
|
|
11
14
|
*/
|
|
12
15
|
readonly add: (id: string, options: {
|
|
13
16
|
autoFocus: boolean;
|
|
14
17
|
}) => void;
|
|
15
18
|
/**
|
|
16
19
|
* Unregister a focusable component.
|
|
20
|
+
*
|
|
21
|
+
* @param id - Unique identifier of the component to unregister.
|
|
17
22
|
*/
|
|
18
23
|
readonly remove: (id: string) => void;
|
|
19
24
|
/**
|
|
20
|
-
* Mark a component as active.
|
|
25
|
+
* Mark a component as active (focused).
|
|
26
|
+
*
|
|
27
|
+
* @param id - Unique identifier of the component to activate.
|
|
21
28
|
*/
|
|
22
29
|
readonly activate: (id: string) => void;
|
|
23
30
|
/**
|
|
24
|
-
* Mark a component as inactive.
|
|
31
|
+
* Mark a component as inactive (unfocused).
|
|
32
|
+
*
|
|
33
|
+
* @param id - Unique identifier of the component to deactivate.
|
|
25
34
|
*/
|
|
26
35
|
readonly deactivate: (id: string) => void;
|
|
27
36
|
/**
|
|
@@ -42,6 +51,8 @@ export interface FocusProps {
|
|
|
42
51
|
readonly focusPrevious: () => void;
|
|
43
52
|
/**
|
|
44
53
|
* Focus a specific component by ID.
|
|
54
|
+
*
|
|
55
|
+
* @param id - Unique identifier of the component to focus.
|
|
45
56
|
*/
|
|
46
57
|
readonly focus: (id: string) => void;
|
|
47
58
|
}
|
package/lib/dimension.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/lib/dom.d.ts
CHANGED
|
@@ -4,10 +4,14 @@ import { TaffyNode } from "./taffy-node.js";
|
|
|
4
4
|
/**
|
|
5
5
|
* Interface representing a node in the Tinky tree.
|
|
6
6
|
*/
|
|
7
|
-
interface TinkyNode {
|
|
7
|
+
export interface TinkyNode {
|
|
8
|
+
/** Parent DOM element in the tree. */
|
|
8
9
|
parentNode: DOMElement | undefined;
|
|
10
|
+
/** Taffy layout node for computing dimensions. */
|
|
9
11
|
taffyNode?: TaffyNode;
|
|
12
|
+
/** Whether this node is inside a Static component. */
|
|
10
13
|
internal_static?: boolean;
|
|
14
|
+
/** Styles applied to this node. */
|
|
11
15
|
style: Styles;
|
|
12
16
|
}
|
|
13
17
|
/**
|
|
@@ -26,35 +30,58 @@ export type NodeNames = ElementNames | TextName;
|
|
|
26
30
|
* Interface representing a DOM element in Tinky.
|
|
27
31
|
*/
|
|
28
32
|
export type DOMElement = {
|
|
33
|
+
/** Name of the element type. */
|
|
29
34
|
nodeName: ElementNames;
|
|
35
|
+
/** Key-value pairs of element attributes. */
|
|
30
36
|
attributes: Record<string, DOMNodeAttribute>;
|
|
37
|
+
/** Array of child nodes. */
|
|
31
38
|
childNodes: DOMNode[];
|
|
39
|
+
/** Function to transform the output of this element. */
|
|
32
40
|
internal_transform?: OutputTransformer;
|
|
41
|
+
/** Accessibility attributes for screen readers. */
|
|
33
42
|
internal_accessibility?: {
|
|
43
|
+
/** ARIA role for the element. */
|
|
34
44
|
role?: "button" | "checkbox" | "combobox" | "list" | "listbox" | "listitem" | "menu" | "menuitem" | "option" | "progressbar" | "radio" | "radiogroup" | "tab" | "tablist" | "table" | "textbox" | "timer" | "toolbar";
|
|
45
|
+
/** ARIA state values for the element. */
|
|
35
46
|
state?: {
|
|
47
|
+
/** Whether the element is busy. */
|
|
36
48
|
busy?: boolean;
|
|
49
|
+
/** Whether the element is checked. */
|
|
37
50
|
checked?: boolean;
|
|
51
|
+
/** Whether the element is disabled. */
|
|
38
52
|
disabled?: boolean;
|
|
53
|
+
/** Whether the element is expanded. */
|
|
39
54
|
expanded?: boolean;
|
|
55
|
+
/** Whether the element accepts multiline input. */
|
|
40
56
|
multiline?: boolean;
|
|
57
|
+
/** Whether multiple items can be selected. */
|
|
41
58
|
multiselectable?: boolean;
|
|
59
|
+
/** Whether the element is read-only. */
|
|
42
60
|
readonly?: boolean;
|
|
61
|
+
/** Whether the element is required. */
|
|
43
62
|
required?: boolean;
|
|
63
|
+
/** Whether the element is selected. */
|
|
44
64
|
selected?: boolean;
|
|
45
65
|
};
|
|
46
66
|
};
|
|
67
|
+
/** Whether static nodes need to be re-rendered. */
|
|
47
68
|
isStaticDirty?: boolean;
|
|
69
|
+
/** Reference to the Static component node. */
|
|
48
70
|
staticNode?: DOMElement;
|
|
71
|
+
/** Callback to compute layout before rendering. */
|
|
49
72
|
onComputeLayout?: () => void;
|
|
73
|
+
/** Callback to trigger a render. */
|
|
50
74
|
onRender?: () => void;
|
|
75
|
+
/** Callback to trigger an immediate render. */
|
|
51
76
|
onImmediateRender?: () => void;
|
|
52
77
|
} & TinkyNode;
|
|
53
78
|
/**
|
|
54
79
|
* Interface representing a text node in Tinky.
|
|
55
80
|
*/
|
|
56
81
|
export type TextNode = {
|
|
82
|
+
/** Text node identifier. */
|
|
57
83
|
nodeName: TextName;
|
|
84
|
+
/** Text content of the node. */
|
|
58
85
|
nodeValue: string;
|
|
59
86
|
} & TinkyNode;
|
|
60
87
|
/**
|
|
@@ -127,4 +154,3 @@ export declare const createTextNode: (text: string) => TextNode;
|
|
|
127
154
|
* @param text - The new text value.
|
|
128
155
|
*/
|
|
129
156
|
export declare const setTextNodeValue: (node: TextNode, text: string) => void;
|
|
130
|
-
export {};
|
package/lib/hooks/use-app.d.ts
CHANGED
package/lib/hooks/use-app.js
CHANGED
|
@@ -23,6 +23,6 @@ import { AppContext } from "../components/AppContext.js";
|
|
|
23
23
|
* render(<Component />);
|
|
24
24
|
* ```
|
|
25
25
|
*
|
|
26
|
-
* @returns The app context containing the exit function.
|
|
26
|
+
* @returns The app context containing the `exit` function.
|
|
27
27
|
*/
|
|
28
28
|
export const useApp = () => useContext(AppContext);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { type FocusProps } from "../components/FocusContext.js";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Focus management control methods.
|
|
4
4
|
*/
|
|
5
|
-
interface
|
|
5
|
+
export interface FocusManager {
|
|
6
6
|
/**
|
|
7
7
|
* Enable focus management for all components.
|
|
8
8
|
*/
|
|
@@ -36,5 +36,4 @@ interface Output {
|
|
|
36
36
|
*
|
|
37
37
|
* @returns Object containing focus management functions.
|
|
38
38
|
*/
|
|
39
|
-
export declare const useFocusManager: () =>
|
|
40
|
-
export {};
|
|
39
|
+
export declare const useFocusManager: () => FocusManager;
|
package/lib/hooks/use-focus.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Options for the useFocus hook.
|
|
3
3
|
*/
|
|
4
|
-
interface
|
|
4
|
+
export interface FocusOptions {
|
|
5
5
|
/**
|
|
6
6
|
* Enable or disable this component's focus, while still maintaining its
|
|
7
7
|
* position in the list of focusable components.
|
|
@@ -23,9 +23,9 @@ interface Input {
|
|
|
23
23
|
id?: string;
|
|
24
24
|
}
|
|
25
25
|
/**
|
|
26
|
-
*
|
|
26
|
+
* Focus state and control methods.
|
|
27
27
|
*/
|
|
28
|
-
interface
|
|
28
|
+
export interface FocusState {
|
|
29
29
|
/**
|
|
30
30
|
* Determines whether this component is focused.
|
|
31
31
|
*/
|
|
@@ -63,5 +63,4 @@ interface Output {
|
|
|
63
63
|
* @param options - Configuration options.
|
|
64
64
|
* @returns Focus state and control methods.
|
|
65
65
|
*/
|
|
66
|
-
export declare const useFocus: ({ isActive, autoFocus, id: customId, }?:
|
|
67
|
-
export {};
|
|
66
|
+
export declare const useFocus: ({ isActive, autoFocus, id: customId, }?: FocusOptions) => FocusState;
|
package/lib/hooks/use-input.d.ts
CHANGED
|
@@ -70,11 +70,11 @@ export interface Key {
|
|
|
70
70
|
/**
|
|
71
71
|
* Handler function for input events.
|
|
72
72
|
*/
|
|
73
|
-
type
|
|
73
|
+
export type InputHandler = (input: string, key: Key) => void;
|
|
74
74
|
/**
|
|
75
75
|
* Options for useInput hook.
|
|
76
76
|
*/
|
|
77
|
-
interface
|
|
77
|
+
export interface InputOptions {
|
|
78
78
|
/**
|
|
79
79
|
* Enable or disable capturing of user input. Useful when there are
|
|
80
80
|
* multiple `useInput` hooks used at once to avoid handling same input.
|
|
@@ -114,5 +114,4 @@ interface Options {
|
|
|
114
114
|
* @param inputHandler - The function to call when input is received.
|
|
115
115
|
* @param options - Configuration options.
|
|
116
116
|
*/
|
|
117
|
-
export declare const useInput: (inputHandler:
|
|
118
|
-
export {};
|
|
117
|
+
export declare const useInput: (inputHandler: InputHandler, options?: InputOptions) => void;
|
|
@@ -3,5 +3,21 @@
|
|
|
3
3
|
* renders your app.
|
|
4
4
|
*
|
|
5
5
|
* @returns The stdout context.
|
|
6
|
+
* @returns {NodeJS.WriteStream} stdout.stdout - Stdout stream passed to
|
|
7
|
+
* `render()` in `options.stdout` or `process.stdout` by default.
|
|
8
|
+
* @returns {function(data: string): void} stdout.write - Write any string to
|
|
9
|
+
* stdout while preserving Tinky's output. Similar to `<Static>`, but only
|
|
10
|
+
* works with strings.
|
|
6
11
|
*/
|
|
7
|
-
export declare const useStdout: () =>
|
|
12
|
+
export declare const useStdout: () => {
|
|
13
|
+
/**
|
|
14
|
+
* Stdout stream passed to `render()` in `options.stdout` or `process.stdout`
|
|
15
|
+
* by default.
|
|
16
|
+
*/
|
|
17
|
+
readonly stdout: NodeJS.WriteStream;
|
|
18
|
+
/**
|
|
19
|
+
* Write any string to stdout while preserving Tinky's output. Similar to
|
|
20
|
+
* `<Static>`, but only works with strings.
|
|
21
|
+
*/
|
|
22
|
+
readonly write: (data: string) => void;
|
|
23
|
+
};
|
package/lib/hooks/use-stdout.js
CHANGED
|
@@ -5,5 +5,10 @@ import { StdoutContext } from "../components/StdoutContext.js";
|
|
|
5
5
|
* renders your app.
|
|
6
6
|
*
|
|
7
7
|
* @returns The stdout context.
|
|
8
|
+
* @returns {NodeJS.WriteStream} stdout.stdout - Stdout stream passed to
|
|
9
|
+
* `render()` in `options.stdout` or `process.stdout` by default.
|
|
10
|
+
* @returns {function(data: string): void} stdout.write - Write any string to
|
|
11
|
+
* stdout while preserving Tinky's output. Similar to `<Static>`, but only
|
|
12
|
+
* works with strings.
|
|
8
13
|
*/
|
|
9
14
|
export const useStdout = () => useContext(StdoutContext);
|
package/lib/index.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
export { type RenderOptions, type Instance } from "./render.js";
|
|
2
|
-
export { render } from "./render.js";
|
|
1
|
+
export { render, type RenderOptions, type Instance } from "./render.js";
|
|
3
2
|
export { Box, type BoxProps } from "./components/Box.js";
|
|
4
3
|
export { Text, type TextProps } from "./components/Text.js";
|
|
5
4
|
export { AppContext, type AppProps } from "./components/AppContext.js";
|
|
@@ -10,13 +9,18 @@ export { Static, type StaticProps } from "./components/Static.js";
|
|
|
10
9
|
export { Transform, type TransformProps } from "./components/Transform.js";
|
|
11
10
|
export { Newline, type NewlineProps } from "./components/Newline.js";
|
|
12
11
|
export { Spacer } from "./components/Spacer.js";
|
|
13
|
-
export { useInput, type Key } from "./hooks/use-input.js";
|
|
12
|
+
export { useInput, type InputHandler, type InputOptions, type Key, } from "./hooks/use-input.js";
|
|
14
13
|
export { useApp } from "./hooks/use-app.js";
|
|
15
14
|
export { useStdin } from "./hooks/use-stdin.js";
|
|
16
15
|
export { useStdout } from "./hooks/use-stdout.js";
|
|
17
16
|
export { useStderr } from "./hooks/use-stderr.js";
|
|
18
|
-
export { useFocus } from "./hooks/use-focus.js";
|
|
19
|
-
export { useFocusManager } from "./hooks/use-focus-manager.js";
|
|
17
|
+
export { useFocus, type FocusOptions, type FocusState, } from "./hooks/use-focus.js";
|
|
18
|
+
export { useFocusManager, type FocusManager, } from "./hooks/use-focus-manager.js";
|
|
20
19
|
export { useIsScreenReaderEnabled } from "./hooks/use-is-screen-reader-enabled.js";
|
|
21
20
|
export { measureElement } from "./measure-element.js";
|
|
22
|
-
export { type
|
|
21
|
+
export { type Dimension } from "./dimension.js";
|
|
22
|
+
export { type DOMElement, type DOMNode, type DOMNodeAttribute, type ElementNames, type NodeNames, type TextName, type TextNode, type TinkyNode, } from "./dom.js";
|
|
23
|
+
export { type Styles } from "./styles.js";
|
|
24
|
+
export { type OutputTransformer } from "./render-node-to-output.js";
|
|
25
|
+
export { type RenderMetrics } from "./tinky.js";
|
|
26
|
+
export { type TaffyNode } from "./taffy-node.js";
|
package/lib/index.js
CHANGED
|
@@ -9,12 +9,12 @@ export { Static } from "./components/Static.js";
|
|
|
9
9
|
export { Transform } from "./components/Transform.js";
|
|
10
10
|
export { Newline } from "./components/Newline.js";
|
|
11
11
|
export { Spacer } from "./components/Spacer.js";
|
|
12
|
-
export { useInput } from "./hooks/use-input.js";
|
|
12
|
+
export { useInput, } from "./hooks/use-input.js";
|
|
13
13
|
export { useApp } from "./hooks/use-app.js";
|
|
14
14
|
export { useStdin } from "./hooks/use-stdin.js";
|
|
15
15
|
export { useStdout } from "./hooks/use-stdout.js";
|
|
16
16
|
export { useStderr } from "./hooks/use-stderr.js";
|
|
17
|
-
export { useFocus } from "./hooks/use-focus.js";
|
|
18
|
-
export { useFocusManager } from "./hooks/use-focus-manager.js";
|
|
17
|
+
export { useFocus, } from "./hooks/use-focus.js";
|
|
18
|
+
export { useFocusManager, } from "./hooks/use-focus-manager.js";
|
|
19
19
|
export { useIsScreenReaderEnabled } from "./hooks/use-is-screen-reader-enabled.js";
|
|
20
20
|
export { measureElement } from "./measure-element.js";
|
package/lib/measure-element.d.ts
CHANGED
|
@@ -1,19 +1,9 @@
|
|
|
1
1
|
import { type DOMElement } from "./dom.js";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Element width.
|
|
5
|
-
*/
|
|
6
|
-
width: number;
|
|
7
|
-
/**
|
|
8
|
-
* Element height.
|
|
9
|
-
*/
|
|
10
|
-
height: number;
|
|
11
|
-
}
|
|
2
|
+
import { type Dimension } from "./dimension.js";
|
|
12
3
|
/**
|
|
13
4
|
* Measure the dimensions of a particular `<Box>` element.
|
|
14
5
|
*
|
|
15
6
|
* @param node - The DOM element to measure.
|
|
16
7
|
* @returns The measured dimensions.
|
|
17
8
|
*/
|
|
18
|
-
export declare const measureElement: (node: DOMElement) =>
|
|
19
|
-
export {};
|
|
9
|
+
export declare const measureElement: (node: DOMElement) => Dimension;
|
package/lib/measure-text.d.ts
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
width: number;
|
|
3
|
-
height: number;
|
|
4
|
-
}
|
|
1
|
+
import { type Dimension } from "./dimension.js";
|
|
5
2
|
/**
|
|
6
3
|
* Measures the width and height of a text string.
|
|
7
4
|
* Results are cached to improve performance.
|
|
@@ -9,5 +6,4 @@ interface Output {
|
|
|
9
6
|
* @param text - The text string to measure.
|
|
10
7
|
* @returns The width and height of the text.
|
|
11
8
|
*/
|
|
12
|
-
export declare const measureText: (text: string) =>
|
|
13
|
-
export {};
|
|
9
|
+
export declare const measureText: (text: string) => Dimension;
|
package/lib/output.d.ts
CHANGED
|
@@ -1,24 +1,16 @@
|
|
|
1
1
|
import { type OutputTransformer } from "./render-node-to-output.js";
|
|
2
|
-
|
|
3
|
-
* Options for creating an Output instance.
|
|
4
|
-
*/
|
|
5
|
-
interface Options {
|
|
6
|
-
/**
|
|
7
|
-
* Width of the output area.
|
|
8
|
-
*/
|
|
9
|
-
width: number;
|
|
10
|
-
/**
|
|
11
|
-
* Height of the output area.
|
|
12
|
-
*/
|
|
13
|
-
height: number;
|
|
14
|
-
}
|
|
2
|
+
import { type Dimension } from "./dimension.js";
|
|
15
3
|
/**
|
|
16
4
|
* Represents a clipping rectangle.
|
|
17
5
|
*/
|
|
18
6
|
interface Clip {
|
|
7
|
+
/** Left boundary (undefined for no limit). */
|
|
19
8
|
x1: number | undefined;
|
|
9
|
+
/** Right boundary (undefined for no limit). */
|
|
20
10
|
x2: number | undefined;
|
|
11
|
+
/** Top boundary (undefined for no limit). */
|
|
21
12
|
y1: number | undefined;
|
|
13
|
+
/** Bottom boundary (undefined for no limit). */
|
|
22
14
|
y2: number | undefined;
|
|
23
15
|
}
|
|
24
16
|
/**
|
|
@@ -36,9 +28,9 @@ export declare class Output {
|
|
|
36
28
|
/**
|
|
37
29
|
* Creates a new Output instance.
|
|
38
30
|
*
|
|
39
|
-
* @param
|
|
31
|
+
* @param dimension - Dimensions containing width and height.
|
|
40
32
|
*/
|
|
41
|
-
constructor(
|
|
33
|
+
constructor(dimension: Dimension);
|
|
42
34
|
/**
|
|
43
35
|
* Writes text to the output at a specified position.
|
|
44
36
|
*
|
package/lib/output.js
CHANGED
|
@@ -17,10 +17,10 @@ export class Output {
|
|
|
17
17
|
/**
|
|
18
18
|
* Creates a new Output instance.
|
|
19
19
|
*
|
|
20
|
-
* @param
|
|
20
|
+
* @param dimension - Dimensions containing width and height.
|
|
21
21
|
*/
|
|
22
|
-
constructor(
|
|
23
|
-
const { width, height } =
|
|
22
|
+
constructor(dimension) {
|
|
23
|
+
const { width, height } = dimension;
|
|
24
24
|
this.width = width;
|
|
25
25
|
this.height = height;
|
|
26
26
|
}
|
package/lib/parse-keypress.d.ts
CHANGED
|
@@ -1,13 +1,24 @@
|
|
|
1
1
|
import { Buffer } from "node:buffer";
|
|
2
2
|
export declare const nonAlphanumericKeys: string[];
|
|
3
|
+
/**
|
|
4
|
+
* Represents a parsed key press with modifier states.
|
|
5
|
+
*/
|
|
3
6
|
interface ParsedKey {
|
|
7
|
+
/** Name of the key (e.g., "enter", "escape", "a"). */
|
|
4
8
|
name: string;
|
|
9
|
+
/** Whether the Ctrl modifier key was pressed. */
|
|
5
10
|
ctrl: boolean;
|
|
11
|
+
/** Whether the Meta (Option/Command) modifier key was pressed. */
|
|
6
12
|
meta: boolean;
|
|
13
|
+
/** Whether the Shift modifier key was pressed. */
|
|
7
14
|
shift: boolean;
|
|
15
|
+
/** Whether the Option modifier key was pressed. */
|
|
8
16
|
option: boolean;
|
|
17
|
+
/** Full key sequence including escape codes. */
|
|
9
18
|
sequence: string;
|
|
19
|
+
/** Raw input string before parsing. */
|
|
10
20
|
raw: string | undefined;
|
|
21
|
+
/** Internal key code for special keys. */
|
|
11
22
|
code?: string;
|
|
12
23
|
}
|
|
13
24
|
/**
|
package/lib/reconciler.js
CHANGED
|
@@ -4,7 +4,7 @@ import { DefaultEventPriority, NoEventPriority, } from "react-reconciler/constan
|
|
|
4
4
|
import { Display } from "taffy-layout";
|
|
5
5
|
import { createContext } from "react";
|
|
6
6
|
import { createTextNode, appendChildNode, insertBeforeNode, removeChildNode, setStyle, setTextNodeValue, createNode, setAttribute, } from "./dom.js";
|
|
7
|
-
import {
|
|
7
|
+
import { applyStyles } from "./styles.js";
|
|
8
8
|
// We need to conditionally perform devtools connection to avoid
|
|
9
9
|
// accidentally breaking other third-party code.
|
|
10
10
|
if (process.env["DEV"] === "true") {
|
|
@@ -54,10 +54,19 @@ const diff = (before, after) => {
|
|
|
54
54
|
}
|
|
55
55
|
return isChanged ? changed : undefined;
|
|
56
56
|
};
|
|
57
|
+
/**
|
|
58
|
+
* Cleans up a Taffy node by freeing its resources.
|
|
59
|
+
*
|
|
60
|
+
* @param node - The Taffy node to cleanup.
|
|
61
|
+
*/
|
|
57
62
|
const cleanupTaffyNode = (node) => {
|
|
58
63
|
node?.free();
|
|
59
64
|
};
|
|
60
65
|
let currentUpdatePriority = NoEventPriority;
|
|
66
|
+
/**
|
|
67
|
+
* Reference to the current root DOM element during rendering.
|
|
68
|
+
* Used to track static node state across renders.
|
|
69
|
+
*/
|
|
61
70
|
let currentRootNode;
|
|
62
71
|
/**
|
|
63
72
|
* React reconciler implementation for Tinky.
|
|
@@ -113,7 +122,7 @@ export const reconciler = createReconciler({
|
|
|
113
122
|
if (key === "style") {
|
|
114
123
|
setStyle(node, value);
|
|
115
124
|
if (node.taffyNode) {
|
|
116
|
-
|
|
125
|
+
applyStyles(node.taffyNode, value);
|
|
117
126
|
}
|
|
118
127
|
continue;
|
|
119
128
|
}
|
|
@@ -224,7 +233,7 @@ export const reconciler = createReconciler({
|
|
|
224
233
|
}
|
|
225
234
|
}
|
|
226
235
|
if (style && node.taffyNode) {
|
|
227
|
-
|
|
236
|
+
applyStyles(node.taffyNode, style);
|
|
228
237
|
}
|
|
229
238
|
},
|
|
230
239
|
commitTextUpdate(node, _oldText, newText) {
|
package/lib/render.d.ts
CHANGED
|
@@ -23,7 +23,8 @@ export interface RenderOptions {
|
|
|
23
23
|
*/
|
|
24
24
|
stderr?: NodeJS.WriteStream;
|
|
25
25
|
/**
|
|
26
|
-
* If true, each update will be rendered as separate output, without
|
|
26
|
+
* If true, each update will be rendered as separate output, without
|
|
27
|
+
* replacing.
|
|
27
28
|
*
|
|
28
29
|
* @defaultValue false
|
|
29
30
|
*/
|
|
@@ -63,7 +64,8 @@ export interface RenderOptions {
|
|
|
63
64
|
maxFps?: number;
|
|
64
65
|
/**
|
|
65
66
|
* Enable incremental rendering mode which only updates changed lines instead
|
|
66
|
-
* of redrawing the entire output. Reduces flickering and improves
|
|
67
|
+
* of redrawing the entire output. Reduces flickering and improves
|
|
68
|
+
* performance.
|
|
67
69
|
*
|
|
68
70
|
* @defaultValue false
|
|
69
71
|
*/
|
package/lib/styles.d.ts
CHANGED
package/lib/styles.js
CHANGED
|
@@ -617,7 +617,7 @@ const applyGridStyles = (taffyStyle, style) => {
|
|
|
617
617
|
}
|
|
618
618
|
}
|
|
619
619
|
};
|
|
620
|
-
export const
|
|
620
|
+
export const applyStyles = (node, style = {}) => {
|
|
621
621
|
const taffyStyle = node.tree.getStyle(node.id);
|
|
622
622
|
applyPositionStyles(taffyStyle, style);
|
|
623
623
|
applyMarginStyles(taffyStyle, style);
|
package/lib/taffy-node.d.ts
CHANGED
|
@@ -35,5 +35,10 @@ export declare class TaffyNode {
|
|
|
35
35
|
* Necessary to prevent memory leaks as Taffy nodes aren't GC'd automatically.
|
|
36
36
|
*/
|
|
37
37
|
free(): void;
|
|
38
|
+
/**
|
|
39
|
+
* Recursively removes a node and all its descendants from the Taffy tree.
|
|
40
|
+
*
|
|
41
|
+
* @param id - The ID of the node to remove.
|
|
42
|
+
*/
|
|
38
43
|
private freeRecursive;
|
|
39
44
|
}
|
package/lib/taffy-node.js
CHANGED
|
@@ -51,6 +51,11 @@ export class TaffyNode {
|
|
|
51
51
|
}
|
|
52
52
|
this.tree.remove(this.id);
|
|
53
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* Recursively removes a node and all its descendants from the Taffy tree.
|
|
56
|
+
*
|
|
57
|
+
* @param id - The ID of the node to remove.
|
|
58
|
+
*/
|
|
54
59
|
freeRecursive(id) {
|
|
55
60
|
for (const childId of this.tree.children(id)) {
|
|
56
61
|
this.freeRecursive(childId);
|
package/lib/tinky.d.ts
CHANGED
|
@@ -68,19 +68,33 @@ export interface Options {
|
|
|
68
68
|
* lifecycle, and terminal output.
|
|
69
69
|
*/
|
|
70
70
|
export declare class Tinky {
|
|
71
|
+
/** Configuration options for this instance. */
|
|
71
72
|
private readonly options;
|
|
73
|
+
/** Log update instance for output. */
|
|
72
74
|
private readonly log;
|
|
75
|
+
/** Throttled log update instance for output. */
|
|
73
76
|
private readonly throttledLog;
|
|
77
|
+
/** Whether screen reader support is enabled. */
|
|
74
78
|
private readonly isScreenReaderEnabled;
|
|
79
|
+
/** Whether the app has been unmounted. */
|
|
75
80
|
private isUnmounted;
|
|
81
|
+
/** Last output string that was rendered. */
|
|
76
82
|
private lastOutput;
|
|
83
|
+
/** Height of the last output in lines. */
|
|
77
84
|
private lastOutputHeight;
|
|
85
|
+
/** Width of the terminal at last render. */
|
|
78
86
|
private lastTerminalWidth;
|
|
87
|
+
/** React reconciler container. */
|
|
79
88
|
private readonly container;
|
|
89
|
+
/** Root DOM element for the React tree. */
|
|
80
90
|
private readonly rootNode;
|
|
91
|
+
/** Full static output for debug mode. */
|
|
81
92
|
private fullStaticOutput;
|
|
93
|
+
/** Promise that resolves when the app exits. */
|
|
82
94
|
private exitPromise?;
|
|
95
|
+
/** Function to restore console after patching. */
|
|
83
96
|
private restoreConsole?;
|
|
97
|
+
/** Function to unsubscribe from resize events. */
|
|
84
98
|
private readonly unsubscribeResize?;
|
|
85
99
|
/**
|
|
86
100
|
* Creates an instance of Tinky.
|
|
@@ -99,9 +113,13 @@ export declare class Tinky {
|
|
|
99
113
|
* Clears the screen when width decreases to prevent overlapping re-renders.
|
|
100
114
|
*/
|
|
101
115
|
resized: () => void;
|
|
116
|
+
/** Resolves the exit promise when the app unmounts. */
|
|
102
117
|
resolveExitPromise: () => void;
|
|
118
|
+
/** Rejects the exit promise with an error. */
|
|
103
119
|
rejectExitPromise: (reason?: Error) => void;
|
|
120
|
+
/** Unsubscribes from the exit event. */
|
|
104
121
|
unsubscribeExit: () => void;
|
|
122
|
+
/** Error that occurred during rendering, if any. */
|
|
105
123
|
renderError: Error | null;
|
|
106
124
|
/**
|
|
107
125
|
* Calculates the layout of the UI (TaffyLayout).
|
package/lib/tinky.js
CHANGED
|
@@ -23,24 +23,33 @@ const noop = () => {
|
|
|
23
23
|
* lifecycle, and terminal output.
|
|
24
24
|
*/
|
|
25
25
|
export class Tinky {
|
|
26
|
+
/** Configuration options for this instance. */
|
|
26
27
|
options;
|
|
28
|
+
/** Log update instance for output. */
|
|
27
29
|
log;
|
|
30
|
+
/** Throttled log update instance for output. */
|
|
28
31
|
throttledLog;
|
|
32
|
+
/** Whether screen reader support is enabled. */
|
|
29
33
|
isScreenReaderEnabled;
|
|
30
|
-
|
|
31
|
-
// exit
|
|
34
|
+
/** Whether the app has been unmounted. */
|
|
32
35
|
isUnmounted;
|
|
36
|
+
/** Last output string that was rendered. */
|
|
33
37
|
lastOutput;
|
|
38
|
+
/** Height of the last output in lines. */
|
|
34
39
|
lastOutputHeight;
|
|
40
|
+
/** Width of the terminal at last render. */
|
|
35
41
|
lastTerminalWidth;
|
|
42
|
+
/** React reconciler container. */
|
|
36
43
|
container;
|
|
44
|
+
/** Root DOM element for the React tree. */
|
|
37
45
|
rootNode;
|
|
38
|
-
|
|
39
|
-
// that it's rerendered every time, not just new static parts, like in
|
|
40
|
-
// non-debug mode
|
|
46
|
+
/** Full static output for debug mode. */
|
|
41
47
|
fullStaticOutput;
|
|
48
|
+
/** Promise that resolves when the app exits. */
|
|
42
49
|
exitPromise;
|
|
50
|
+
/** Function to restore console after patching. */
|
|
43
51
|
restoreConsole;
|
|
52
|
+
/** Function to unsubscribe from resize events. */
|
|
44
53
|
unsubscribeResize;
|
|
45
54
|
/**
|
|
46
55
|
* Creates an instance of Tinky.
|
|
@@ -134,10 +143,13 @@ export class Tinky {
|
|
|
134
143
|
this.onRender();
|
|
135
144
|
this.lastTerminalWidth = currentWidth;
|
|
136
145
|
};
|
|
146
|
+
/** Resolves the exit promise when the app unmounts. */
|
|
137
147
|
resolveExitPromise = noop;
|
|
148
|
+
/** Rejects the exit promise with an error. */
|
|
138
149
|
rejectExitPromise = noop;
|
|
150
|
+
/** Unsubscribes from the exit event. */
|
|
139
151
|
unsubscribeExit = noop;
|
|
140
|
-
|
|
152
|
+
/** Error that occurred during rendering, if any. */
|
|
141
153
|
renderError = null;
|
|
142
154
|
/**
|
|
143
155
|
* Calculates the layout of the UI (TaffyLayout).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tinky",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "React for CLIs, re-imagined with the Taffy engine",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -26,39 +26,53 @@
|
|
|
26
26
|
},
|
|
27
27
|
"type": "module",
|
|
28
28
|
"main": "./lib/index.js",
|
|
29
|
+
"files": [
|
|
30
|
+
"./bin/*",
|
|
31
|
+
"./lib/*"
|
|
32
|
+
],
|
|
29
33
|
"scripts": {
|
|
30
34
|
"test": "bun test",
|
|
31
|
-
"build": "tsc",
|
|
35
|
+
"build": "tsc && npm run docs",
|
|
32
36
|
"lint": "tslint -c tslint.json src/**/*.ts",
|
|
33
37
|
"prepublish": "npm run build",
|
|
34
|
-
"prepare": "husky"
|
|
38
|
+
"prepare": "husky",
|
|
39
|
+
"docs": "typedoc --plugin typedoc-plugin-markdown --disableSources --out docs/api && prettier --write docs/api"
|
|
35
40
|
},
|
|
36
41
|
"dependencies": {
|
|
37
42
|
"@alcalzone/ansi-tokenize": "^0.2.3",
|
|
43
|
+
"ansi-escapes": "^7.2.0",
|
|
38
44
|
"ansi-styles": "^6.2.3",
|
|
39
45
|
"auto-bind": "^5.0.1",
|
|
40
46
|
"chalk": "^5.6.2",
|
|
41
47
|
"cli-boxes": "^4.0.1",
|
|
48
|
+
"cli-cursor": "^5.0.0",
|
|
49
|
+
"cli-truncate": "^5.1.1",
|
|
42
50
|
"code-excerpt": "^4.0.0",
|
|
43
51
|
"es-toolkit": "^1.43.0",
|
|
44
52
|
"indent-string": "^5.0.0",
|
|
45
53
|
"is-in-ci": "^2.0.0",
|
|
46
54
|
"patch-console": "^2.0.0",
|
|
47
55
|
"react-reconciler": "^0.33.0",
|
|
56
|
+
"signal-exit": "^4.1.0",
|
|
48
57
|
"stack-utils": "^2.0.6",
|
|
49
58
|
"taffy-layout": "^0.1.0",
|
|
50
59
|
"tslint": "^5.20.1",
|
|
51
60
|
"type-fest": "^5.4.1",
|
|
52
|
-
"widest-line": "^5.0.0"
|
|
61
|
+
"widest-line": "^5.0.0",
|
|
62
|
+
"wrap-ansi": "^9.0.2"
|
|
63
|
+
},
|
|
64
|
+
"peerDependencies": {
|
|
65
|
+
"@types/react": ">=19.0.0",
|
|
66
|
+
"react": ">=19.0.0",
|
|
67
|
+
"react-devtools-core": ">=7.0.0"
|
|
53
68
|
},
|
|
54
|
-
"files": [
|
|
55
|
-
"./bin/*",
|
|
56
|
-
"./lib/*"
|
|
57
|
-
],
|
|
58
69
|
"typings": "./lib/index.d.ts",
|
|
59
70
|
"devDependencies": {
|
|
60
71
|
"@commitlint/cli": "^20.3.0",
|
|
61
72
|
"@commitlint/config-conventional": "^20.3.0",
|
|
73
|
+
"@semantic-release/changelog": "^6.0.3",
|
|
74
|
+
"@semantic-release/git": "^10.0.1",
|
|
75
|
+
"@semantic-release/npm": "^13.1.3",
|
|
62
76
|
"@sinonjs/fake-timers": "^15.1.0",
|
|
63
77
|
"@types/bun": "^1.3.6",
|
|
64
78
|
"@types/react-reconciler": "^0.32.3",
|
|
@@ -73,7 +87,10 @@
|
|
|
73
87
|
"jiti": "^2.6.1",
|
|
74
88
|
"lint-staged": "^16.2.7",
|
|
75
89
|
"prettier": "^3.7.4",
|
|
90
|
+
"semantic-release": "^25.0.2",
|
|
76
91
|
"sinon": "^21.0.1",
|
|
92
|
+
"typedoc": "^0.28.16",
|
|
93
|
+
"typedoc-plugin-markdown": "^4.9.0",
|
|
77
94
|
"typescript-eslint": "^8.53.0"
|
|
78
95
|
},
|
|
79
96
|
"commitlint": {
|