Comparing version 4.3.1 to 4.4.0
/// <reference types="node" resolution-mode="require"/> | ||
/// <reference types="node" resolution-mode="require"/> | ||
import { EventEmitter } from 'node:events'; | ||
import React, { PureComponent, type ReactNode } from 'react'; | ||
@@ -35,2 +37,3 @@ type Props = { | ||
rawModeEnabledCount: number; | ||
internal_eventEmitter: EventEmitter; | ||
isRawModeSupported(): boolean; | ||
@@ -42,2 +45,3 @@ render(): React.JSX.Element; | ||
handleSetRawMode: (isEnabled: boolean) => void; | ||
handleReadable: () => void; | ||
handleInput: (input: string) => void; | ||
@@ -44,0 +48,0 @@ handleExit: (error?: Error) => void; |
@@ -0,1 +1,2 @@ | ||
import { EventEmitter } from 'node:events'; | ||
import process from 'node:process'; | ||
@@ -38,2 +39,9 @@ import React, { PureComponent } from 'react'; | ||
}); | ||
// eslint-disable-next-line @typescript-eslint/naming-convention | ||
Object.defineProperty(this, "internal_eventEmitter", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: new EventEmitter() | ||
}); | ||
Object.defineProperty(this, "handleSetRawMode", { | ||
@@ -57,5 +65,4 @@ enumerable: true, | ||
if (this.rawModeEnabledCount === 0) { | ||
stdin.addListener('data', this.handleInput); | ||
stdin.resume(); | ||
stdin.setRawMode(true); | ||
stdin.addListener('readable', this.handleReadable); | ||
} | ||
@@ -68,7 +75,20 @@ this.rawModeEnabledCount++; | ||
stdin.setRawMode(false); | ||
stdin.removeListener('data', this.handleInput); | ||
stdin.pause(); | ||
stdin.removeListener('readable', this.handleReadable); | ||
stdin.unref(); | ||
} | ||
} | ||
}); | ||
Object.defineProperty(this, "handleReadable", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: () => { | ||
let chunk; | ||
// eslint-disable-next-line @typescript-eslint/ban-types | ||
while ((chunk = this.props.stdin.read()) !== null) { | ||
this.handleInput(chunk); | ||
this.internal_eventEmitter.emit('input', chunk); | ||
} | ||
} | ||
}); | ||
Object.defineProperty(this, "handleInput", { | ||
@@ -309,3 +329,5 @@ enumerable: true, | ||
// eslint-disable-next-line @typescript-eslint/naming-convention | ||
internal_exitOnCtrlC: this.props.exitOnCtrlC | ||
internal_exitOnCtrlC: this.props.exitOnCtrlC, | ||
// eslint-disable-next-line @typescript-eslint/naming-convention | ||
internal_eventEmitter: this.internal_eventEmitter | ||
} }, | ||
@@ -312,0 +334,0 @@ React.createElement(StdoutContext.Provider |
/// <reference types="node" resolution-mode="require"/> | ||
/// <reference types="node" resolution-mode="require"/> | ||
/// <reference types="react" /> | ||
import { EventEmitter } from 'node:events'; | ||
export type Props = { | ||
@@ -18,2 +20,3 @@ /** | ||
readonly internal_exitOnCtrlC: boolean; | ||
readonly internal_eventEmitter: EventEmitter; | ||
}; | ||
@@ -20,0 +23,0 @@ /** |
@@ -0,1 +1,2 @@ | ||
import { EventEmitter } from 'node:events'; | ||
import process from 'node:process'; | ||
@@ -9,2 +10,4 @@ import { createContext } from 'react'; | ||
stdin: process.stdin, | ||
// eslint-disable-next-line @typescript-eslint/naming-convention | ||
internal_eventEmitter: new EventEmitter(), | ||
setRawMode() { }, | ||
@@ -11,0 +14,0 @@ isRawModeSupported: false, |
@@ -6,3 +6,3 @@ import React, { type ReactNode } from 'react'; | ||
*/ | ||
readonly transform: (children: string) => string; | ||
readonly transform: (children: string, index: number) => string; | ||
readonly children?: ReactNode; | ||
@@ -9,0 +9,0 @@ }; |
@@ -32,3 +32,3 @@ import { useEffect } from 'react'; | ||
// eslint-disable-next-line @typescript-eslint/naming-convention | ||
const { stdin, setRawMode, internal_exitOnCtrlC } = useStdin(); | ||
const { stdin, setRawMode, internal_exitOnCtrlC, internal_eventEmitter } = useStdin(); | ||
useEffect(() => { | ||
@@ -91,5 +91,5 @@ if (options.isActive === false) { | ||
}; | ||
stdin?.on('data', handleData); | ||
internal_eventEmitter?.on('input', handleData); | ||
return () => { | ||
stdin?.off('data', handleData); | ||
internal_eventEmitter?.removeListener('input', handleData); | ||
}; | ||
@@ -96,0 +96,0 @@ }, [options.isActive, stdin, internal_exitOnCtrlC, inputHandler]); |
@@ -120,3 +120,3 @@ import sliceAnsi from 'slice-ansi'; | ||
let offsetY = 0; | ||
for (let line of lines) { | ||
for (let [index, line] of lines.entries()) { | ||
const currentLine = output[y + offsetY]; | ||
@@ -128,3 +128,3 @@ // Line can be missing if `text` is taller than height of pre-initialized `this.output` | ||
for (const transformer of transformers) { | ||
line = transformer(line); | ||
line = transformer(line, index); | ||
} | ||
@@ -131,0 +131,0 @@ const characters = styledCharsFromTokens(tokenize(line)); |
import { type DOMElement } from './dom.js'; | ||
import type Output from './output.js'; | ||
export type OutputTransformer = (s: string) => string; | ||
export type OutputTransformer = (s: string, index: number) => string; | ||
declare const renderNodeToOutput: (node: DOMElement, output: Output, options: { | ||
@@ -5,0 +5,0 @@ offsetX?: number; |
@@ -9,22 +9,24 @@ // Squashing text nodes allows to combine multiple text nodes into one and write | ||
let text = ''; | ||
if (node.childNodes.length > 0) { | ||
for (const childNode of node.childNodes) { | ||
let nodeText = ''; | ||
if (childNode.nodeName === '#text') { | ||
nodeText = childNode.nodeValue; | ||
for (let index = 0; index < node.childNodes.length; index++) { | ||
const childNode = node.childNodes[index]; | ||
if (childNode === undefined) { | ||
continue; | ||
} | ||
let nodeText = ''; | ||
if (childNode.nodeName === '#text') { | ||
nodeText = childNode.nodeValue; | ||
} | ||
else { | ||
if (childNode.nodeName === 'ink-text' || | ||
childNode.nodeName === 'ink-virtual-text') { | ||
nodeText = squashTextNodes(childNode); | ||
} | ||
else { | ||
if (childNode.nodeName === 'ink-text' || | ||
childNode.nodeName === 'ink-virtual-text') { | ||
nodeText = squashTextNodes(childNode); | ||
} | ||
// Since these text nodes are being concatenated, `Output` instance won't be able to | ||
// apply children transform, so we have to do it manually here for each text node | ||
if (nodeText.length > 0 && | ||
typeof childNode.internal_transform === 'function') { | ||
nodeText = childNode.internal_transform(nodeText); | ||
} | ||
// Since these text nodes are being concatenated, `Output` instance won't be able to | ||
// apply children transform, so we have to do it manually here for each text node | ||
if (nodeText.length > 0 && | ||
typeof childNode.internal_transform === 'function') { | ||
nodeText = childNode.internal_transform(nodeText, index); | ||
} | ||
text += nodeText; | ||
} | ||
text += nodeText; | ||
} | ||
@@ -31,0 +33,0 @@ return text; |
{ | ||
"name": "ink", | ||
"version": "4.3.1", | ||
"version": "4.4.0", | ||
"description": "React for CLI", | ||
@@ -5,0 +5,0 @@ "license": "MIT", |
@@ -1376,4 +1376,38 @@ [![](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/banner2-direct.svg)](https://github.com/vshymanskyy/StandWithUkraine/blob/main/docs/README.md) | ||
#### transform(children) | ||
When the output wraps to multiple lines, it can be helpful to know which line is being processed. | ||
For example, to implement a hanging indent component, you can indent all the lines except for the first. | ||
```jsx | ||
import {render, Transform} from 'ink'; | ||
const HangingIndent = ({content, indent = 4, children, ...props}) => ( | ||
<Transform | ||
transform={(line, index) => | ||
index === 0 ? line : ' '.repeat(indent) + line | ||
} | ||
{...props} | ||
> | ||
{children} | ||
</Transform> | ||
); | ||
const text = | ||
'WHEN I WROTE the following pages, or rather the bulk of them, ' + | ||
'I lived alone, in the woods, a mile from any neighbor, in a ' + | ||
'house which I had built myself, on the shore of Walden Pond, ' + | ||
'in Concord, Massachusetts, and earned my living by the labor ' + | ||
'of my hands only. I lived there two years and two months. At ' + | ||
'present I am a sojourner in civilized life again.'; | ||
// Other text properties are allowed as well | ||
render( | ||
<HangingIndent bold dimColor indent={4}> | ||
{text} | ||
</HangingIndent> | ||
); | ||
``` | ||
#### transform(outputLine, index) | ||
Type: `Function` | ||
@@ -1390,2 +1424,8 @@ | ||
##### index | ||
Type: `number` | ||
The zero-indexed line number of the line currently being transformed. | ||
## Hooks | ||
@@ -1392,0 +1432,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
266390
3649
2167