From 338ae6e8a146992b5cca5255ee66e3dd283b20d5 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Tue, 14 May 2024 15:00:10 +0700 Subject: [PATCH] Require Node.js 18 and support Ink 5 (#84) --- .github/workflows/test.yml | 6 ++--- .gitignore | 1 + package.json | 46 +++++++++++++++++++------------------- readme.md | 6 ++--- source/index.tsx | 28 +++++++++++------------ test/test.tsx | 15 +++++-------- tsconfig.json | 9 +++----- 7 files changed, 51 insertions(+), 60 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8c7ca93..fdce555 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -7,12 +7,12 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node_version: [14, 16, 18] + node_version: [18, 20] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Use Node.js ${{ matrix.node_version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node_version }} - run: npm install diff --git a/.gitignore b/.gitignore index dd87e2d..cc90d03 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules build +/.tsimp diff --git a/package.json b/package.json index 54fe144..1272270 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "default": "./build/index.js" }, "engines": { - "node": ">=14.16" + "node": ">=18" }, "scripts": { "test": "tsc --noEmit && xo && FORCE_COLOR=1 ava", @@ -39,31 +39,31 @@ "query" ], "dependencies": { - "chalk": "^5.2.0", - "type-fest": "^3.6.1" + "chalk": "^5.3.0", + "type-fest": "^4.18.2" }, "devDependencies": { - "@sindresorhus/tsconfig": "^3.0.1", - "@types/react": "^18.0.0", - "@types/sinon": "^10.0.13", - "@vdemedes/prettier-config": "^1.0.1", - "ava": "^5.1.1", - "delay": "^5.0.0", + "@sindresorhus/tsconfig": "^5.0.0", + "@types/react": "^18.3.2", + "@types/sinon": "^17.0.3", + "@vdemedes/prettier-config": "^2.0.1", + "ava": "^6.1.3", + "delay": "^6.0.0", "eslint-config-xo-react": "^0.27.0", - "eslint-plugin-react": "^7.32.2", - "eslint-plugin-react-hooks": "^4.6.0", - "ink": "^4.0.0", - "ink-testing-library": "^3.0.0", - "prettier": "^2.0.5", - "react": "^18.0.0", - "sinon": "^15.0.1", - "ts-node": "^10.9.1", - "typescript": "^4.9.5", - "xo": "^0.53.0" + "eslint-plugin-react": "^7.34.1", + "eslint-plugin-react-hooks": "^4.6.2", + "ink": "^5.0.0", + "ink-testing-library": "vadimdemedes/ink-testing-library#f44b077e9a05a1d615bab41c72906726d34ea085", + "prettier": "^3.2.5", + "react": "^18.3.1", + "sinon": "^17.0.1", + "tsimp": "^2.0.11", + "typescript": "^5.4.5", + "xo": "^0.58.0" }, "peerDependencies": { - "ink": "^4.0.0", - "react": "^18.0.0" + "ink": ">=5", + "react": ">=18" }, "ava": { "extensions": { @@ -71,7 +71,7 @@ "tsx": "module" }, "nodeArguments": [ - "--loader=ts-node/esm" + "--import=tsimp/import" ] }, "xo": { @@ -80,7 +80,7 @@ ], "prettier": true, "rules": { - "unicorn/no-hex-escape": 0 + "unicorn/prevent-abbreviations": "off" } }, "prettier": "@vdemedes/prettier-config" diff --git a/readme.md b/readme.md index eaa7ab4..1ba994e 100644 --- a/readme.md +++ b/readme.md @@ -2,12 +2,10 @@ > Text input component for [Ink](https://github.com/vadimdemedes/ink). -Looking for a version compatible with Ink 2.x? Check out [this release](https://github.com/vadimdemedes/ink-text-input/tree/v3.3.0). - ## Install -``` -$ npm install ink-text-input +```sh +npm install ink-text-input ``` ## Usage diff --git a/source/index.tsx b/source/index.tsx index 1f3bdfd..24e49ab 100644 --- a/source/index.tsx +++ b/source/index.tsx @@ -7,43 +7,43 @@ export type Props = { /** * Text to display when `value` is empty. */ - placeholder?: string; + readonly placeholder?: string; /** * Listen to user's input. Useful in case there are multiple input components * at the same time and input must be "routed" to a specific component. */ - focus?: boolean; // eslint-disable-line react/boolean-prop-naming + readonly focus?: boolean; // eslint-disable-line react/boolean-prop-naming /** * Replace all chars and mask the value. Useful for password inputs. */ - mask?: string; + readonly mask?: string; /** * Whether to show cursor and allow navigation inside text input with arrow keys. */ - showCursor?: boolean; // eslint-disable-line react/boolean-prop-naming + readonly showCursor?: boolean; // eslint-disable-line react/boolean-prop-naming /** * Highlight pasted text */ - highlightPastedText?: boolean; // eslint-disable-line react/boolean-prop-naming + readonly highlightPastedText?: boolean; // eslint-disable-line react/boolean-prop-naming /** * Value to display in a text input. */ - value: string; + readonly value: string; /** * Function to call when value updates. */ - onChange: (value: string) => void; + readonly onChange: (value: string) => void; /** * Function to call when `Enter` is pressed, where first argument is a value of the input. */ - onSubmit?: (value: string) => void; + readonly onSubmit?: (value: string) => void; }; function TextInput({ @@ -54,11 +54,11 @@ function TextInput({ highlightPastedText = false, showCursor = true, onChange, - onSubmit + onSubmit, }: Props) { const [state, setState] = useState({ cursorOffset: (originalValue || '').length, - cursorWidth: 0 + cursorWidth: 0, }); const {cursorOffset, cursorWidth} = state; @@ -74,7 +74,7 @@ function TextInput({ if (previousState.cursorOffset > newValue.length - 1) { return { cursorOffset: newValue.length, - cursorWidth: 0 + cursorWidth: 0, }; } @@ -176,14 +176,14 @@ function TextInput({ setState({ cursorOffset: nextCursorOffset, - cursorWidth: nextCursorWidth + cursorWidth: nextCursorWidth, }); if (nextValue !== originalValue) { onChange(nextValue); } }, - {isActive: focus} + {isActive: focus}, ); return ( @@ -203,7 +203,7 @@ type UncontrolledProps = { /** * Initial value. */ - initialValue?: string; + readonly initialValue?: string; } & Except; export function UncontrolledTextInput({ diff --git a/test/test.tsx b/test/test.tsx index 54b54c2..51913a1 100644 --- a/test/test.tsx +++ b/test/test.tsx @@ -24,7 +24,7 @@ test('default state', t => { test('display value', t => { const {lastFrame} = render( - + , ); t.is(lastFrame(), 'Hello'); @@ -38,7 +38,7 @@ test('display value with cursor', t => { test('display placeholder', t => { const {lastFrame} = render( - + , ); t.is(lastFrame(), chalk.inverse('P') + chalk.grey('laceholder')); @@ -51,7 +51,7 @@ test('display placeholder when cursor is hidden', t => { placeholder="Placeholder" showCursor={false} onChange={noop} - /> + />, ); t.is(lastFrame(), chalk.grey('Placeholder')); @@ -59,7 +59,7 @@ test('display placeholder when cursor is hidden', t => { test('display value with mask', t => { const {lastFrame} = render( - + , ); t.is(lastFrame(), `*****${chalk.inverse(' ')}`); @@ -168,11 +168,6 @@ test('paste and move cursor', async t => { const {stdin, lastFrame} = render(); - // Need this to invert each char separately - const inverse = (s: string) => { - return [...s].map(c => chalk.inverse(c)).join(''); - }; - await delay(100); stdin.write('A'); await delay(100); @@ -186,7 +181,7 @@ test('paste and move cursor', async t => { stdin.write('Hello World'); await delay(100); - t.is(lastFrame(), `A${inverse('Hello WorldB')}`); + t.is(lastFrame(), `A${chalk.inverse('Hello WorldB')}`); stdin.write(arrowRight); await delay(100); diff --git a/tsconfig.json b/tsconfig.json index 3098f03..ea66c1c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,11 +2,8 @@ "extends": "@sindresorhus/tsconfig", "compilerOptions": { "outDir": "build", - "sourceMap": true + "sourceMap": true, + "jsx": "react" }, - "include": ["source"], - "ts-node": { - "transpileOnly": true, - "files": true - } + "include": ["source"] }