@shopify/cli-kit 3.35.0 → 3.36.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.
- package/dist/content-tokens.js +1 -1
- package/dist/content-tokens.js.map +1 -1
- package/dist/error.js +2 -2
- package/dist/error.js.map +1 -1
- package/dist/index.d.ts +0 -3
- package/dist/index.js +0 -3
- package/dist/index.js.map +1 -1
- package/dist/metadata.d.ts +1 -1
- package/dist/metadata.js.map +1 -1
- package/dist/monorail.d.ts +1 -1
- package/dist/monorail.js +1 -1
- package/dist/monorail.js.map +1 -1
- package/dist/output.js +0 -4
- package/dist/output.js.map +1 -1
- package/dist/plugins.d.ts +1 -1
- package/dist/plugins.js.map +1 -1
- package/dist/{typing → private/common/ts}/deep-required.d.ts +3 -3
- package/dist/{typing → private/common/ts}/deep-required.js +0 -0
- package/dist/private/common/ts/deep-required.js.map +1 -0
- package/dist/{typing → private/common/ts}/overloaded-parameters.d.ts +0 -0
- package/dist/{typing → private/common/ts}/overloaded-parameters.js +0 -0
- package/dist/private/common/ts/overloaded-parameters.js.map +1 -0
- package/dist/private/node/api/graphql.js +1 -2
- package/dist/private/node/api/graphql.js.map +1 -1
- package/dist/private/node/api/headers.d.ts +9 -0
- package/dist/private/node/api/headers.js +26 -0
- package/dist/private/node/api/headers.js.map +1 -1
- package/dist/private/node/constants.js +3 -3
- package/dist/private/node/constants.js.map +1 -1
- package/dist/private/node/session/device-authorization.js +1 -1
- package/dist/private/node/session/device-authorization.js.map +1 -1
- package/dist/private/node/session/exchange.js +1 -1
- package/dist/private/node/session/exchange.js.map +1 -1
- package/dist/private/node/session/identity-token-validation.js +1 -1
- package/dist/private/node/session/identity-token-validation.js.map +1 -1
- package/dist/private/node/session/post-auth.js +3 -3
- package/dist/private/node/session/post-auth.js.map +1 -1
- package/dist/{typing → private/node}/simple-definitions.d.ts +0 -0
- package/dist/{typing → private/node}/simple-definitions.js +0 -0
- package/dist/private/node/simple-definitions.js.map +1 -0
- package/dist/private/node/ui/alert.d.ts +1 -1
- package/dist/private/node/ui/alert.js +2 -2
- package/dist/private/node/ui/alert.js.map +1 -1
- package/dist/private/node/ui/components/Alert.d.ts +5 -0
- package/dist/private/node/ui/components/Alert.js +9 -6
- package/dist/private/node/ui/components/Alert.js.map +1 -1
- package/dist/private/node/ui/components/Alert.test.js +30 -4
- package/dist/private/node/ui/components/Alert.test.js.map +1 -1
- package/dist/private/node/ui/components/AutocompletePrompt.d.ts +12 -0
- package/dist/private/node/ui/components/AutocompletePrompt.js +111 -0
- package/dist/private/node/ui/components/AutocompletePrompt.js.map +1 -0
- package/dist/private/node/ui/components/AutocompletePrompt.test.d.ts +1 -0
- package/dist/private/node/ui/components/AutocompletePrompt.test.js +473 -0
- package/dist/private/node/ui/components/AutocompletePrompt.test.js.map +1 -0
- package/dist/private/node/ui/components/Banner.d.ts +0 -1
- package/dist/private/node/ui/components/Banner.js +4 -4
- package/dist/private/node/ui/components/Banner.js.map +1 -1
- package/dist/private/node/ui/components/Banner.test.js +10 -5
- package/dist/private/node/ui/components/Banner.test.js.map +1 -1
- package/dist/private/node/ui/components/FatalError.js +1 -1
- package/dist/private/node/ui/components/FatalError.js.map +1 -1
- package/dist/private/node/ui/components/FatalError.test.js +4 -8
- package/dist/private/node/ui/components/FatalError.test.js.map +1 -1
- package/dist/private/node/ui/components/{Table.d.ts → Prompts/InfoTable.d.ts} +2 -2
- package/dist/private/node/ui/components/{Table.js → Prompts/InfoTable.js} +6 -6
- package/dist/private/node/ui/components/Prompts/InfoTable.js.map +1 -0
- package/dist/private/node/ui/components/SelectInput.d.ts +9 -2
- package/dist/private/node/ui/components/SelectInput.js +96 -52
- package/dist/private/node/ui/components/SelectInput.js.map +1 -1
- package/dist/private/node/ui/components/SelectInput.test.js +140 -54
- package/dist/private/node/ui/components/SelectInput.test.js.map +1 -1
- package/dist/private/node/ui/components/SelectPrompt.d.ts +4 -3
- package/dist/private/node/ui/components/SelectPrompt.js +17 -11
- package/dist/private/node/ui/components/SelectPrompt.js.map +1 -1
- package/dist/private/node/ui/components/SelectPrompt.test.js +113 -23
- package/dist/private/node/ui/components/SelectPrompt.test.js.map +1 -1
- package/dist/private/node/ui/components/Tasks.d.ts +6 -5
- package/dist/private/node/ui/components/Tasks.js +32 -11
- package/dist/private/node/ui/components/Tasks.js.map +1 -1
- package/dist/private/node/ui/components/Tasks.test.js +55 -9
- package/dist/private/node/ui/components/Tasks.test.js.map +1 -1
- package/dist/private/node/ui/components/TextInput.d.ts +4 -1
- package/dist/private/node/ui/components/TextInput.js +22 -13
- package/dist/private/node/ui/components/TextInput.js.map +1 -1
- package/dist/private/node/ui/components/TextInput.test.js +47 -40
- package/dist/private/node/ui/components/TextInput.test.js.map +1 -1
- package/dist/private/node/ui/components/TextPrompt.d.ts +3 -1
- package/dist/private/node/ui/components/TextPrompt.js +28 -15
- package/dist/private/node/ui/components/TextPrompt.js.map +1 -1
- package/dist/private/node/ui/components/TextPrompt.test.js +71 -15
- package/dist/private/node/ui/components/TextPrompt.test.js.map +1 -1
- package/dist/private/node/ui/components/TokenizedText.d.ts +3 -0
- package/dist/private/node/ui/components/TokenizedText.js +33 -1
- package/dist/private/node/ui/components/TokenizedText.js.map +1 -1
- package/dist/private/node/ui/utilities.d.ts +2 -0
- package/dist/private/node/ui/utilities.js +6 -0
- package/dist/private/node/ui/utilities.js.map +1 -0
- package/dist/{typing → public/common/ts}/pick-by-prefix.d.ts +4 -3
- package/dist/{typing → public/common/ts}/pick-by-prefix.js +0 -0
- package/dist/public/common/ts/pick-by-prefix.js.map +1 -0
- package/dist/public/common/version.d.ts +1 -1
- package/dist/public/common/version.js +1 -1
- package/dist/public/common/version.js.map +1 -1
- package/dist/public/node/api/admin.js +1 -1
- package/dist/public/node/api/admin.js.map +1 -1
- package/dist/public/node/api/http.d.ts +0 -0
- package/dist/public/node/api/http.js +2 -0
- package/dist/public/node/api/http.js.map +1 -0
- package/dist/public/node/api/oxygen.js +1 -1
- package/dist/public/node/api/oxygen.js.map +1 -1
- package/dist/public/node/archiver.js +2 -1
- package/dist/public/node/archiver.js.map +1 -1
- package/dist/public/node/cli.js +2 -2
- package/dist/public/node/cli.js.map +1 -1
- package/dist/public/node/environment/spin.js +2 -2
- package/dist/public/node/environment/spin.js.map +1 -1
- package/dist/public/node/error-handler.js +7 -5
- package/dist/public/node/error-handler.js.map +1 -1
- package/dist/public/node/framework.js +2 -2
- package/dist/public/node/framework.js.map +1 -1
- package/dist/public/node/fs.d.ts +22 -4
- package/dist/public/node/fs.js +34 -6
- package/dist/public/node/fs.js.map +1 -1
- package/dist/public/node/github.js +1 -1
- package/dist/public/node/github.js.map +1 -1
- package/dist/{http/fetch.d.ts → public/node/http.d.ts} +18 -7
- package/dist/{http/fetch.js → public/node/http.js} +22 -8
- package/dist/public/node/http.js.map +1 -0
- package/dist/public/node/liquid.js +4 -4
- package/dist/public/node/liquid.js.map +1 -1
- package/dist/public/node/node-package-manager.d.ts +22 -1
- package/dist/public/node/node-package-manager.js +22 -11
- package/dist/public/node/node-package-manager.js.map +1 -1
- package/dist/public/node/path.d.ts +22 -0
- package/dist/{path.js → public/node/path.js} +8 -20
- package/dist/public/node/path.js.map +1 -0
- package/dist/public/node/presets.js +4 -4
- package/dist/public/node/presets.js.map +1 -1
- package/dist/public/node/ruby.js +23 -27
- package/dist/public/node/ruby.js.map +1 -1
- package/dist/public/node/ui.d.ts +50 -9
- package/dist/public/node/ui.js +69 -8
- package/dist/public/node/ui.js.map +1 -1
- package/dist/public/node/vscode.js +4 -4
- package/dist/public/node/vscode.js.map +1 -1
- package/dist/testing/ui.d.ts +4 -1
- package/dist/testing/ui.js +24 -1
- package/dist/testing/ui.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/ui/executor.d.ts +2 -14
- package/dist/ui/executor.js +38 -72
- package/dist/ui/executor.js.map +1 -1
- package/dist/ui.js +6 -23
- package/dist/ui.js.map +1 -1
- package/package.json +3 -5
- package/dist/http/fetch.js.map +0 -1
- package/dist/http/formdata.d.ts +0 -3
- package/dist/http/formdata.js +0 -6
- package/dist/http/formdata.js.map +0 -1
- package/dist/http.d.ts +0 -26
- package/dist/http.js +0 -31
- package/dist/http.js.map +0 -1
- package/dist/npm.d.ts +0 -27
- package/dist/npm.js +0 -20
- package/dist/npm.js.map +0 -1
- package/dist/path.d.ts +0 -25
- package/dist/path.js.map +0 -1
- package/dist/private/node/ui/components/Table.js.map +0 -1
- package/dist/typing/deep-required.js.map +0 -1
- package/dist/typing/overloaded-parameters.js.map +0 -1
- package/dist/typing/pick-by-prefix.js.map +0 -1
- package/dist/typing/simple-definitions.js.map +0 -1
- package/dist/ui/inquirer/autocomplete.d.ts +0 -11
- package/dist/ui/inquirer/autocomplete.js +0 -110
- package/dist/ui/inquirer/autocomplete.js.map +0 -1
- package/dist/ui/inquirer/input.d.ts +0 -16
- package/dist/ui/inquirer/input.js +0 -45
- package/dist/ui/inquirer/input.js.map +0 -1
- package/dist/ui/inquirer/password.d.ts +0 -7
- package/dist/ui/inquirer/password.js +0 -8
- package/dist/ui/inquirer/password.js.map +0 -1
- package/dist/ui/inquirer/select.d.ts +0 -14
- package/dist/ui/inquirer/select.js +0 -26
- package/dist/ui/inquirer/select.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SelectPrompt.test.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/SelectPrompt.test.tsx"],"names":[],"mappings":"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","sourcesContent":["import {SelectPrompt} from './SelectPrompt.js'\nimport {getLastFrameAfterUnmount, sendInput, waitForInputsToBeReady} from '../../../../testing/ui.js'\nimport {describe, expect, test, vi} from 'vitest'\nimport React from 'react'\nimport {render} from 'ink-testing-library'\n\nconst ARROW_DOWN = '\\u001B[B'\nconst ENTER = '\\r'\n\ndescribe('Prompt', async () => {\n test('choose an answer', async () => {\n const onEnter = vi.fn()\n\n const items = [\n {label: 'first', value: 'first'},\n {label: 'second', value: 'second'},\n {label: 'third', value: 'third'},\n ]\n\n const infoTable = {Add: ['new-ext'], Remove: ['integrated-demand-ext', 'order-discount']}\n\n const renderInstance = render(\n <SelectPrompt\n message=\"Associate your project with the org Castile Ventures?\"\n choices={items}\n infoTable={infoTable}\n onSubmit={onEnter}\n />,\n )\n\n await waitForInputsToBeReady()\n await sendInput(renderInstance, ARROW_DOWN)\n await sendInput(renderInstance, ENTER)\n\n expect(getLastFrameAfterUnmount(renderInstance)).toMatchInlineSnapshot(`\n \"? Associate your project with the org Castile Ventures?\n \u001b[36m✔\u001b[39m \u001b[36msecond\u001b[39m\n \"\n `)\n\n expect(onEnter).toHaveBeenCalledWith(items[1]!.value)\n })\n\n test('supports an info table', async () => {\n const items = [\n {label: 'first', value: 'first', key: 'f'},\n {label: 'second', value: 'second', key: 's'},\n {label: 'third', value: 'third'},\n {label: 'fourth', value: 'fourth'},\n {label: 'fifth', value: 'fifth', group: 'Automations'},\n {label: 'sixth', value: 'sixth', group: 'Automations'},\n {label: 'seventh', value: 'seventh'},\n {label: 'eighth', value: 'eighth', group: 'Merchant Admin'},\n {label: 'ninth', value: 'ninth', group: 'Merchant Admin'},\n {label: 'tenth', value: 'tenth'},\n ]\n\n const infoTable = {\n Add: ['new-ext'],\n Remove: ['integrated-demand-ext', 'order-discount'],\n }\n\n const renderInstance = render(\n <SelectPrompt\n message=\"Associate your project with the org Castile Ventures?\"\n choices={items}\n infoTable={infoTable}\n onSubmit={() => {}}\n />,\n )\n\n expect(renderInstance.lastFrame()).toMatchInlineSnapshot(`\n \"? Associate your project with the org Castile Ventures?\n\n Add: • new-ext\n\n Remove: • integrated-demand-ext\n • order-discount\n\n \u001b[36m>\u001b[39m \u001b[36m(f) first\u001b[39m\n (s) second\n (3) third\n (4) fourth\n (5) seventh\n (6) tenth\n\n \u001b[1mAutomations\u001b[22m\n (7) fifth\n (8) sixth\n\n \u001b[1mMerchant Admin\u001b[22m\n (9) eighth\n (10) ninth\n\n \u001b[2mnavigate with arrows, enter to select\u001b[22m\n \"\n `)\n })\n})\n"]}
|
|
1
|
+
{"version":3,"file":"SelectPrompt.test.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/SelectPrompt.test.tsx"],"names":[],"mappings":"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","sourcesContent":["import {SelectPrompt} from './SelectPrompt.js'\nimport {getLastFrameAfterUnmount, sendInputAndWaitForChange, waitForInputsToBeReady} from '../../../../testing/ui.js'\nimport {unstyled} from '../../../../output.js'\nimport {describe, expect, test, vi} from 'vitest'\nimport React from 'react'\nimport {render} from 'ink-testing-library'\n\nconst ARROW_DOWN = '\\u001B[B'\nconst ENTER = '\\r'\n\ndescribe('SelectPrompt', async () => {\n test('choose an answer', async () => {\n const onEnter = vi.fn()\n\n const items = [\n {label: 'first', value: 'first'},\n {label: 'second', value: 'second'},\n {label: 'third', value: 'third'},\n ]\n\n const infoTable = {Add: ['new-ext'], Remove: ['integrated-demand-ext', 'order-discount']}\n\n const renderInstance = render(\n <SelectPrompt\n message=\"Associate your project with the org Castile Ventures?\"\n choices={items}\n infoTable={infoTable}\n onSubmit={onEnter}\n />,\n )\n\n await waitForInputsToBeReady()\n await sendInputAndWaitForChange(renderInstance, ARROW_DOWN)\n await sendInputAndWaitForChange(renderInstance, ENTER)\n\n expect(getLastFrameAfterUnmount(renderInstance)).toMatchInlineSnapshot(`\n \"? Associate your project with the org Castile Ventures?\n \u001b[36m✔\u001b[39m \u001b[36msecond\u001b[39m\n \"\n `)\n\n expect(onEnter).toHaveBeenCalledWith(items[1]!.value)\n })\n\n test('renders groups', async () => {\n const items = [\n {label: 'first', value: 'first', group: 'Automations', key: 'f'},\n {label: 'second', value: 'second', group: 'Automations', key: 's'},\n {label: 'third', value: 'third', group: 'Merchant Admin'},\n {label: 'fourth', value: 'fourth', group: 'Merchant Admin'},\n {label: 'fifth', value: 'fifth', key: 'a'},\n {label: 'sixth', value: 'sixth'},\n {label: 'seventh', value: 'seventh'},\n {label: 'eighth', value: 'eighth'},\n {label: 'ninth', value: 'ninth'},\n {label: 'tenth', value: 'tenth'},\n ]\n\n const renderInstance = render(\n <SelectPrompt\n message=\"Associate your project with the org Castile Ventures?\"\n choices={items}\n onSubmit={() => {}}\n />,\n )\n\n expect(renderInstance.lastFrame()).toMatchInlineSnapshot(`\n \"? Associate your project with the org Castile Ventures?\n\n \u001b[1mAutomations\u001b[22m\n \u001b[36m>\u001b[39m \u001b[36m(f) first\u001b[39m\n (s) second\n\n \u001b[1mMerchant Admin\u001b[22m\n (3) third\n (4) fourth\n\n \u001b[1mOther\u001b[22m\n (a) fifth\n (6) sixth\n (7) seventh\n (8) eighth\n (9) ninth\n (10) tenth\n\n \u001b[2mPress ↑↓ arrows to select, enter to confirm\u001b[22m\n \"\n `)\n })\n\n test('supports an info table', async () => {\n const items = [\n {label: 'first', value: 'first'},\n {label: 'second', value: 'second'},\n {label: 'third', value: 'third'},\n {label: 'fourth', value: 'fourth'},\n ]\n\n const infoTable = {\n Add: ['new-ext'],\n Remove: ['integrated-demand-ext', 'order-discount'],\n }\n\n const renderInstance = render(\n <SelectPrompt\n message=\"Associate your project with the org Castile Ventures?\"\n choices={items}\n infoTable={infoTable}\n onSubmit={() => {}}\n />,\n )\n\n expect(renderInstance.lastFrame()).toMatchInlineSnapshot(`\n \"? Associate your project with the org Castile Ventures?\n\n Add: • new-ext\n\n Remove: • integrated-demand-ext\n • order-discount\n\n \u001b[36m>\u001b[39m \u001b[36m(1) first\u001b[39m\n (2) second\n (3) third\n (4) fourth\n\n \u001b[2mPress ↑↓ arrows to select, enter to confirm\u001b[22m\n \"\n `)\n })\n\n test(\"it doesn't submit if there are no choices\", async () => {\n const onEnter = vi.fn()\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const items: any[] = []\n\n const renderInstance = render(\n <SelectPrompt\n message=\"Associate your project with the org Castile Ventures?\"\n choices={items}\n onSubmit={onEnter}\n />,\n )\n\n expect(unstyled(getLastFrameAfterUnmount(renderInstance)!)).toContain(\n 'ERROR SelectPrompt requires at least one choice',\n )\n })\n\n test(\"doesn't append a colon to the message if it ends with a question mark\", async () => {\n const {lastFrame} = render(\n <SelectPrompt choices={[{label: 'a', value: 'a'}]} onSubmit={() => {}} message=\"Test question?\" />,\n )\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"? Test question?\n\n > (1) a\n\n Press ↑↓ arrows to select, enter to confirm\n \"\n `)\n })\n\n test('accepts a default value', async () => {\n const onEnter = vi.fn()\n const items = [\n {label: 'a', value: 'a'},\n {label: 'b', value: 'b'},\n ]\n\n const renderInstance = render(\n <SelectPrompt choices={items} onSubmit={onEnter} message=\"Test question?\" defaultValue=\"b\" />,\n )\n\n expect(unstyled(renderInstance.lastFrame()!)).toMatchInlineSnapshot(`\n \"? Test question?\n\n (1) a\n > (2) b\n\n Press ↑↓ arrows to select, enter to confirm\n \"\n `)\n\n await waitForInputsToBeReady()\n await sendInputAndWaitForChange(renderInstance, ENTER)\n\n expect(getLastFrameAfterUnmount(renderInstance)).toMatchInlineSnapshot(`\n \"? Test question?\n \u001b[36m✔\u001b[39m \u001b[36mb\u001b[39m\n \"\n `)\n expect(onEnter).toHaveBeenCalledWith(items[1]!.value)\n })\n\n test('can submit the initial value', async () => {\n const onEnter = vi.fn()\n const items = [\n {label: 'a', value: 'a'},\n {label: 'b', value: 'b'},\n ]\n\n const renderInstance = render(<SelectPrompt choices={items} onSubmit={onEnter} message=\"Test question?\" />)\n\n expect(unstyled(renderInstance.lastFrame()!)).toMatchInlineSnapshot(`\n \"? Test question?\n\n > (1) a\n (2) b\n\n Press ↑↓ arrows to select, enter to confirm\n \"\n `)\n\n await waitForInputsToBeReady()\n await sendInputAndWaitForChange(renderInstance, ENTER)\n\n expect(getLastFrameAfterUnmount(renderInstance)).toMatchInlineSnapshot(`\n \"? Test question?\n \u001b[36m✔\u001b[39m \u001b[36ma\u001b[39m\n \"\n `)\n expect(onEnter).toHaveBeenCalledWith(items[0]!.value)\n })\n})\n"]}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
export interface Task {
|
|
2
|
+
export interface Task<TContext = unknown> {
|
|
3
3
|
title: string;
|
|
4
|
-
task: () => Promise<void>;
|
|
4
|
+
task: (ctx: TContext) => Promise<void | Task<TContext>[]>;
|
|
5
5
|
}
|
|
6
|
-
export interface Props {
|
|
7
|
-
tasks: Task[];
|
|
6
|
+
export interface Props<TContext> {
|
|
7
|
+
tasks: Task<TContext>[];
|
|
8
|
+
silent?: boolean;
|
|
8
9
|
}
|
|
9
|
-
declare
|
|
10
|
+
declare function Tasks<TContext>({ tasks, silent }: React.PropsWithChildren<Props<TContext>>): JSX.Element | null;
|
|
10
11
|
export { Tasks };
|
|
@@ -1,27 +1,48 @@
|
|
|
1
1
|
import { TextAnimation } from './TextAnimation.js';
|
|
2
2
|
import useLayout from '../hooks/use-layout.js';
|
|
3
3
|
import useAsyncAndUnmount from '../hooks/use-async-and-unmount.js';
|
|
4
|
+
// import {environment} from '@shopify/cli-kit'
|
|
4
5
|
import { Box, Text } from 'ink';
|
|
5
|
-
import React, { useState } from 'react';
|
|
6
|
-
const loadingBarChar = '
|
|
7
|
-
|
|
6
|
+
import React, { useRef, useState } from 'react';
|
|
7
|
+
const loadingBarChar = '▀';
|
|
8
|
+
var TasksState;
|
|
9
|
+
(function (TasksState) {
|
|
10
|
+
TasksState["Loading"] = "loading";
|
|
11
|
+
TasksState["Success"] = "success";
|
|
12
|
+
TasksState["Failure"] = "failure";
|
|
13
|
+
})(TasksState || (TasksState = {}));
|
|
14
|
+
function Tasks({ tasks, silent = false }) {
|
|
8
15
|
const { twoThirds } = useLayout();
|
|
9
16
|
const loadingBar = new Array(twoThirds).fill(loadingBarChar).join('');
|
|
10
17
|
const [currentTask, setCurrentTask] = useState(tasks[0]);
|
|
11
|
-
const [state, setState] = useState(
|
|
18
|
+
const [state, setState] = useState(TasksState.Loading);
|
|
19
|
+
const ctx = useRef({});
|
|
12
20
|
const runTasks = async () => {
|
|
13
21
|
for (const task of tasks) {
|
|
14
22
|
setCurrentTask(task);
|
|
15
23
|
// eslint-disable-next-line no-await-in-loop
|
|
16
|
-
await task.task();
|
|
24
|
+
const result = await task.task(ctx.current);
|
|
25
|
+
if (Array.isArray(result) && result.length > 0 && result.every((el) => 'task' in el)) {
|
|
26
|
+
for (const subTask of result) {
|
|
27
|
+
setCurrentTask(subTask);
|
|
28
|
+
// eslint-disable-next-line no-await-in-loop
|
|
29
|
+
await subTask.task(ctx.current);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
17
32
|
}
|
|
18
33
|
};
|
|
19
|
-
useAsyncAndUnmount(runTasks, {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
34
|
+
useAsyncAndUnmount(runTasks, {
|
|
35
|
+
onFulfilled: () => setState(TasksState.Success),
|
|
36
|
+
onRejected: () => setState(TasksState.Failure),
|
|
37
|
+
});
|
|
38
|
+
if (silent) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
return state === TasksState.Loading ? (React.createElement(Box, { flexDirection: "column" },
|
|
42
|
+
React.createElement(TextAnimation, { text: loadingBar }),
|
|
43
|
+
React.createElement(Text, null,
|
|
23
44
|
currentTask.title,
|
|
24
|
-
|
|
25
|
-
}
|
|
45
|
+
" ..."))) : null;
|
|
46
|
+
}
|
|
26
47
|
export { Tasks };
|
|
27
48
|
//# sourceMappingURL=Tasks.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Tasks.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/Tasks.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,aAAa,EAAC,MAAM,oBAAoB,CAAA;AAChD,OAAO,SAAS,MAAM,wBAAwB,CAAA;AAC9C,OAAO,kBAAkB,MAAM,mCAAmC,CAAA;
|
|
1
|
+
{"version":3,"file":"Tasks.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/Tasks.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,aAAa,EAAC,MAAM,oBAAoB,CAAA;AAChD,OAAO,SAAS,MAAM,wBAAwB,CAAA;AAC9C,OAAO,kBAAkB,MAAM,mCAAmC,CAAA;AAElE,+CAA+C;AAC/C,OAAO,EAAC,GAAG,EAAE,IAAI,EAAC,MAAM,KAAK,CAAA;AAC7B,OAAO,KAAK,EAAE,EAAC,MAAM,EAAE,QAAQ,EAAC,MAAM,OAAO,CAAA;AAE7C,MAAM,cAAc,GAAG,GAAG,CAAA;AAY1B,IAAK,UAIJ;AAJD,WAAK,UAAU;IACb,iCAAmB,CAAA;IACnB,iCAAmB,CAAA;IACnB,iCAAmB,CAAA;AACrB,CAAC,EAJI,UAAU,KAAV,UAAU,QAId;AAED,SAAS,KAAK,CAAW,EAAC,KAAK,EAAE,MAAM,GAAG,KAAK,EAA2C;IACxF,MAAM,EAAC,SAAS,EAAC,GAAG,SAAS,EAAE,CAAA;IAC/B,MAAM,UAAU,GAAG,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IACrE,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAiB,KAAK,CAAC,CAAC,CAAE,CAAC,CAAA;IACzE,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAa,UAAU,CAAC,OAAO,CAAC,CAAA;IAClE,MAAM,GAAG,GAAG,MAAM,CAAW,EAAc,CAAC,CAAA;IAE5C,MAAM,QAAQ,GAAG,KAAK,IAAI,EAAE;QAC1B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE;YACxB,cAAc,CAAC,IAAI,CAAC,CAAA;YACpB,4CAA4C;YAC5C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;YAC3C,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,MAAM,IAAI,EAAE,CAAC,EAAE;gBACpF,KAAK,MAAM,OAAO,IAAI,MAAM,EAAE;oBAC5B,cAAc,CAAC,OAAO,CAAC,CAAA;oBACvB,4CAA4C;oBAC5C,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;iBAChC;aACF;SACF;IACH,CAAC,CAAA;IAED,kBAAkB,CAAC,QAAQ,EAAE;QAC3B,WAAW,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC;QAC/C,UAAU,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC;KAC/C,CAAC,CAAA;IAEF,IAAI,MAAM,EAAE;QACV,OAAO,IAAI,CAAA;KACZ;IAED,OAAO,KAAK,KAAK,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CACpC,oBAAC,GAAG,IAAC,aAAa,EAAC,QAAQ;QACzB,oBAAC,aAAa,IAAC,IAAI,EAAE,UAAU,GAAI;QACnC,oBAAC,IAAI;YAAE,WAAW,CAAC,KAAK;mBAAY,CAChC,CACP,CAAC,CAAC,CAAC,IAAI,CAAA;AACV,CAAC;AAED,OAAO,EAAC,KAAK,EAAC,CAAA","sourcesContent":["import {TextAnimation} from './TextAnimation.js'\nimport useLayout from '../hooks/use-layout.js'\nimport useAsyncAndUnmount from '../hooks/use-async-and-unmount.js'\n\n// import {environment} from '@shopify/cli-kit'\nimport {Box, Text} from 'ink'\nimport React, {useRef, useState} from 'react'\n\nconst loadingBarChar = '▀'\n\nexport interface Task<TContext = unknown> {\n title: string\n task: (ctx: TContext) => Promise<void | Task<TContext>[]>\n}\n\nexport interface Props<TContext> {\n tasks: Task<TContext>[]\n silent?: boolean\n}\n\nenum TasksState {\n Loading = 'loading',\n Success = 'success',\n Failure = 'failure',\n}\n\nfunction Tasks<TContext>({tasks, silent = false}: React.PropsWithChildren<Props<TContext>>) {\n const {twoThirds} = useLayout()\n const loadingBar = new Array(twoThirds).fill(loadingBarChar).join('')\n const [currentTask, setCurrentTask] = useState<Task<TContext>>(tasks[0]!)\n const [state, setState] = useState<TasksState>(TasksState.Loading)\n const ctx = useRef<TContext>({} as TContext)\n\n const runTasks = async () => {\n for (const task of tasks) {\n setCurrentTask(task)\n // eslint-disable-next-line no-await-in-loop\n const result = await task.task(ctx.current)\n if (Array.isArray(result) && result.length > 0 && result.every((el) => 'task' in el)) {\n for (const subTask of result) {\n setCurrentTask(subTask)\n // eslint-disable-next-line no-await-in-loop\n await subTask.task(ctx.current)\n }\n }\n }\n }\n\n useAsyncAndUnmount(runTasks, {\n onFulfilled: () => setState(TasksState.Success),\n onRejected: () => setState(TasksState.Failure),\n })\n\n if (silent) {\n return null\n }\n\n return state === TasksState.Loading ? (\n <Box flexDirection=\"column\">\n <TextAnimation text={loadingBar} />\n <Text>{currentTask.title} ...</Text>\n </Box>\n ) : null\n}\n\nexport {Tasks}\n"]}
|
|
@@ -1,10 +1,29 @@
|
|
|
1
1
|
import { Tasks } from './Tasks.js';
|
|
2
2
|
import { getLastFrameAfterUnmount } from '../../../../testing/ui.js';
|
|
3
|
+
import { unstyled } from '../../../../output.js';
|
|
3
4
|
import React from 'react';
|
|
4
5
|
import { describe, expect, test } from 'vitest';
|
|
5
6
|
import { render } from 'ink-testing-library';
|
|
6
7
|
describe('Tasks', () => {
|
|
7
|
-
test('shows a
|
|
8
|
+
test('shows a loading state at the start', async () => {
|
|
9
|
+
// Given
|
|
10
|
+
const firstTask = {
|
|
11
|
+
title: 'task 1',
|
|
12
|
+
task: async () => {
|
|
13
|
+
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
// When
|
|
17
|
+
const renderInstance = render(React.createElement(Tasks, { tasks: [firstTask] }));
|
|
18
|
+
// wait for next tick
|
|
19
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
20
|
+
// Then
|
|
21
|
+
expect(unstyled(getLastFrameAfterUnmount(renderInstance))).toMatchInlineSnapshot(`
|
|
22
|
+
"▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
|
|
23
|
+
task 1 ..."
|
|
24
|
+
`);
|
|
25
|
+
});
|
|
26
|
+
test('shows nothing at the end in case of success', async () => {
|
|
8
27
|
// Given
|
|
9
28
|
const firstTask = {
|
|
10
29
|
title: 'task 1',
|
|
@@ -19,12 +38,9 @@ describe('Tasks', () => {
|
|
|
19
38
|
// wait for next tick
|
|
20
39
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
21
40
|
// Then
|
|
22
|
-
expect(getLastFrameAfterUnmount(renderInstance)).toMatchInlineSnapshot(
|
|
23
|
-
"[32m████████████████████████████████████████████████████████████████████████████████[39m
|
|
24
|
-
Complete!"
|
|
25
|
-
`);
|
|
41
|
+
expect(getLastFrameAfterUnmount(renderInstance)).toMatchInlineSnapshot('""');
|
|
26
42
|
});
|
|
27
|
-
test('shows
|
|
43
|
+
test('shows nothing at the end in case of failure', async () => {
|
|
28
44
|
// Given
|
|
29
45
|
const firstTask = {
|
|
30
46
|
title: 'task 1',
|
|
@@ -41,9 +57,39 @@ describe('Tasks', () => {
|
|
|
41
57
|
// wait for next tick
|
|
42
58
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
43
59
|
// Then
|
|
44
|
-
expect(getLastFrameAfterUnmount(renderInstance)).toMatchInlineSnapshot(
|
|
45
|
-
|
|
46
|
-
|
|
60
|
+
expect(getLastFrameAfterUnmount(renderInstance)).toMatchInlineSnapshot('""');
|
|
61
|
+
});
|
|
62
|
+
test('it supports subtasks', async () => {
|
|
63
|
+
// Given
|
|
64
|
+
const firstTask = {
|
|
65
|
+
title: 'task 1',
|
|
66
|
+
task: async () => {
|
|
67
|
+
return [
|
|
68
|
+
{
|
|
69
|
+
title: 'subtask 1',
|
|
70
|
+
task: async () => {
|
|
71
|
+
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
title: 'subtask 2',
|
|
76
|
+
task: async () => { },
|
|
77
|
+
},
|
|
78
|
+
];
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
const secondTask = {
|
|
82
|
+
title: 'task 2',
|
|
83
|
+
task: async () => { },
|
|
84
|
+
};
|
|
85
|
+
// When
|
|
86
|
+
const renderInstance = render(React.createElement(Tasks, { tasks: [firstTask, secondTask] }));
|
|
87
|
+
// wait for next tick
|
|
88
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
89
|
+
// Then
|
|
90
|
+
expect(unstyled(getLastFrameAfterUnmount(renderInstance))).toMatchInlineSnapshot(`
|
|
91
|
+
"▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
|
|
92
|
+
subtask 1 ..."
|
|
47
93
|
`);
|
|
48
94
|
});
|
|
49
95
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Tasks.test.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/Tasks.test.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,KAAK,EAAC,MAAM,YAAY,CAAA;AAChC,OAAO,EAAC,wBAAwB,EAAC,MAAM,2BAA2B,CAAA;AAClE,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAC,MAAM,QAAQ,CAAA;AAC7C,OAAO,EAAC,MAAM,EAAC,MAAM,qBAAqB,CAAA;AAE1C,QAAQ,CAAC,OAAO,EAAE,GAAG,EAAE;IACrB,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"Tasks.test.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/Tasks.test.tsx"],"names":[],"mappings":"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","sourcesContent":["import {Tasks} from './Tasks.js'\nimport {getLastFrameAfterUnmount} from '../../../../testing/ui.js'\nimport {unstyled} from '../../../../output.js'\nimport React from 'react'\nimport {describe, expect, test} from 'vitest'\nimport {render} from 'ink-testing-library'\n\ndescribe('Tasks', () => {\n test('shows a loading state at the start', async () => {\n // Given\n const firstTask = {\n title: 'task 1',\n task: async () => {\n await new Promise((resolve) => setTimeout(resolve, 2000))\n },\n }\n\n // When\n const renderInstance = render(<Tasks tasks={[firstTask]} />)\n // wait for next tick\n await new Promise((resolve) => setTimeout(resolve, 0))\n\n // Then\n expect(unstyled(getLastFrameAfterUnmount(renderInstance)!)).toMatchInlineSnapshot(`\n \"▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀\n task 1 ...\"\n `)\n })\n\n test('shows nothing at the end in case of success', async () => {\n // Given\n const firstTask = {\n title: 'task 1',\n task: async () => {},\n }\n\n const secondTask = {\n title: 'task 2',\n task: async () => {},\n }\n // When\n\n const renderInstance = render(<Tasks tasks={[firstTask, secondTask]} />)\n\n // wait for next tick\n await new Promise((resolve) => setTimeout(resolve, 0))\n\n // Then\n expect(getLastFrameAfterUnmount(renderInstance)).toMatchInlineSnapshot('\"\"')\n })\n\n test('shows nothing at the end in case of failure', async () => {\n // Given\n const firstTask = {\n title: 'task 1',\n task: async () => {\n throw new Error('something went wrong')\n },\n }\n\n const secondTask = {\n title: 'task 2',\n task: async () => {},\n }\n\n // When\n const renderInstance = render(<Tasks tasks={[firstTask, secondTask]} />)\n\n // wait for next tick\n await new Promise((resolve) => setTimeout(resolve, 0))\n\n // Then\n expect(getLastFrameAfterUnmount(renderInstance)).toMatchInlineSnapshot('\"\"')\n })\n\n test('it supports subtasks', async () => {\n // Given\n const firstTask = {\n title: 'task 1',\n task: async () => {\n return [\n {\n title: 'subtask 1',\n task: async () => {\n await new Promise((resolve) => setTimeout(resolve, 2000))\n },\n },\n {\n title: 'subtask 2',\n task: async () => {},\n },\n ]\n },\n }\n\n const secondTask = {\n title: 'task 2',\n task: async () => {},\n }\n\n // When\n const renderInstance = render(<Tasks tasks={[firstTask, secondTask]} />)\n\n // wait for next tick\n await new Promise((resolve) => setTimeout(resolve, 100))\n\n // Then\n expect(unstyled(getLastFrameAfterUnmount(renderInstance)!)).toMatchInlineSnapshot(`\n \"▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀\n subtask 1 ...\"\n `)\n })\n})\n"]}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import type { FC } from 'react';
|
|
2
2
|
interface Props {
|
|
3
|
-
|
|
3
|
+
defaultValue?: string;
|
|
4
4
|
value: string;
|
|
5
5
|
onChange: (value: string) => void;
|
|
6
6
|
color?: string;
|
|
7
|
+
password?: boolean;
|
|
8
|
+
focus?: boolean;
|
|
9
|
+
placeholder?: string;
|
|
7
10
|
}
|
|
8
11
|
declare const TextInput: FC<Props>;
|
|
9
12
|
export { TextInput };
|
|
@@ -3,20 +3,28 @@ import * as React from 'react';
|
|
|
3
3
|
import { useEffect, useState } from 'react';
|
|
4
4
|
import { Text, useInput } from 'ink';
|
|
5
5
|
import chalk from 'chalk';
|
|
6
|
-
const TextInput = ({ value,
|
|
7
|
-
const [cursorOffset, setCursorOffset] = useState((
|
|
6
|
+
const TextInput = ({ value: originalValue, defaultValue = '', onChange, placeholder = '', color = 'cyan', password = false, focus = true, }) => {
|
|
7
|
+
const [cursorOffset, setCursorOffset] = useState((originalValue || '').length);
|
|
8
8
|
// if the updated value is shorter than the last one we need to reset the cursor
|
|
9
9
|
useEffect(() => {
|
|
10
10
|
setCursorOffset((previousOffset) => {
|
|
11
|
-
const newValue =
|
|
11
|
+
const newValue = originalValue || '';
|
|
12
12
|
if (previousOffset > newValue.length - 1) {
|
|
13
13
|
return newValue.length;
|
|
14
14
|
}
|
|
15
15
|
return previousOffset;
|
|
16
16
|
});
|
|
17
|
-
}, [
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
}, [originalValue]);
|
|
18
|
+
const value = password ? '*'.repeat(originalValue.length) : originalValue;
|
|
19
|
+
let renderedValue;
|
|
20
|
+
const renderPlaceholder = (value) => {
|
|
21
|
+
return chalk.inverse(value[0]) + chalk.dim(value.slice(1));
|
|
22
|
+
};
|
|
23
|
+
const renderedPlaceholder = defaultValue.length > 0
|
|
24
|
+
? renderPlaceholder(defaultValue)
|
|
25
|
+
: placeholder.length > 0
|
|
26
|
+
? renderPlaceholder(placeholder)
|
|
27
|
+
: chalk.inverse(' ');
|
|
20
28
|
// render cursor
|
|
21
29
|
renderedValue = value
|
|
22
30
|
.split('')
|
|
@@ -42,33 +50,34 @@ const TextInput = ({ value, placeholder = '', onChange, color = 'cyan' }) => {
|
|
|
42
50
|
return;
|
|
43
51
|
}
|
|
44
52
|
let nextCursorOffset = cursorOffset;
|
|
45
|
-
let nextValue =
|
|
53
|
+
let nextValue = originalValue;
|
|
46
54
|
if (key.leftArrow) {
|
|
47
55
|
if (cursorOffset > 0) {
|
|
48
56
|
nextCursorOffset--;
|
|
49
57
|
}
|
|
50
58
|
}
|
|
51
59
|
else if (key.rightArrow) {
|
|
52
|
-
if (cursorOffset <
|
|
60
|
+
if (cursorOffset < originalValue.length) {
|
|
53
61
|
nextCursorOffset++;
|
|
54
62
|
}
|
|
55
63
|
}
|
|
56
64
|
else if (key.backspace || key.delete) {
|
|
57
65
|
if (cursorOffset > 0) {
|
|
58
|
-
nextValue =
|
|
66
|
+
nextValue = originalValue.slice(0, cursorOffset - 1) + originalValue.slice(cursorOffset, originalValue.length);
|
|
59
67
|
nextCursorOffset--;
|
|
60
68
|
}
|
|
61
69
|
}
|
|
62
70
|
else {
|
|
63
|
-
nextValue =
|
|
71
|
+
nextValue =
|
|
72
|
+
originalValue.slice(0, cursorOffset) + input + originalValue.slice(cursorOffset, originalValue.length);
|
|
64
73
|
nextCursorOffset += input.length;
|
|
65
74
|
}
|
|
66
75
|
setCursorOffset(nextCursorOffset);
|
|
67
|
-
if (nextValue !==
|
|
76
|
+
if (nextValue !== originalValue) {
|
|
68
77
|
onChange(nextValue);
|
|
69
78
|
}
|
|
70
|
-
});
|
|
71
|
-
return
|
|
79
|
+
}, { isActive: focus });
|
|
80
|
+
return React.createElement(Text, { color: color }, value.length > 0 ? renderedValue : renderedPlaceholder);
|
|
72
81
|
};
|
|
73
82
|
export { TextInput };
|
|
74
83
|
//# sourceMappingURL=TextInput.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TextInput.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/TextInput.tsx"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAC,SAAS,EAAE,QAAQ,EAAC,MAAM,OAAO,CAAA;AACzC,OAAO,EAAC,IAAI,EAAE,QAAQ,EAAC,MAAM,KAAK,CAAA;AAClC,OAAO,KAAK,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"TextInput.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/TextInput.tsx"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable no-nested-ternary */\nimport * as React from 'react'\nimport {useEffect, useState} from 'react'\nimport {Text, useInput} from 'ink'\nimport chalk from 'chalk'\nimport type {FC} from 'react'\n\ninterface Props {\n defaultValue?: string\n value: string\n onChange: (value: string) => void\n color?: string\n password?: boolean\n focus?: boolean\n placeholder?: string\n}\n\nconst TextInput: FC<Props> = ({\n value: originalValue,\n defaultValue = '',\n onChange,\n placeholder = '',\n color = 'cyan',\n password = false,\n focus = true,\n}) => {\n const [cursorOffset, setCursorOffset] = useState((originalValue || '').length)\n\n // if the updated value is shorter than the last one we need to reset the cursor\n useEffect(() => {\n setCursorOffset((previousOffset) => {\n const newValue = originalValue || ''\n\n if (previousOffset > newValue.length - 1) {\n return newValue.length\n }\n\n return previousOffset\n })\n }, [originalValue])\n\n const value = password ? '*'.repeat(originalValue.length) : originalValue\n let renderedValue\n\n const renderPlaceholder = (value: string) => {\n return chalk.inverse(value[0]) + chalk.dim(value.slice(1))\n }\n\n const renderedPlaceholder =\n defaultValue.length > 0\n ? renderPlaceholder(defaultValue)\n : placeholder.length > 0\n ? renderPlaceholder(placeholder)\n : chalk.inverse(' ')\n\n // render cursor\n renderedValue = value\n .split('')\n .map((char, index) => {\n if (index === cursorOffset) {\n return chalk.inverse(char)\n } else {\n return char\n }\n })\n .join('')\n\n if (cursorOffset === value.length) {\n renderedValue += chalk.inverse(' ')\n }\n\n useInput(\n (input, key) => {\n if (\n key.upArrow ||\n key.downArrow ||\n (key.ctrl && input === 'c') ||\n key.tab ||\n (key.shift && key.tab) ||\n key.return\n ) {\n return\n }\n\n let nextCursorOffset = cursorOffset\n let nextValue = originalValue\n\n if (key.leftArrow) {\n if (cursorOffset > 0) {\n nextCursorOffset--\n }\n } else if (key.rightArrow) {\n if (cursorOffset < originalValue.length) {\n nextCursorOffset++\n }\n } else if (key.backspace || key.delete) {\n if (cursorOffset > 0) {\n nextValue = originalValue.slice(0, cursorOffset - 1) + originalValue.slice(cursorOffset, originalValue.length)\n nextCursorOffset--\n }\n } else {\n nextValue =\n originalValue.slice(0, cursorOffset) + input + originalValue.slice(cursorOffset, originalValue.length)\n nextCursorOffset += input.length\n }\n\n setCursorOffset(nextCursorOffset)\n\n if (nextValue !== originalValue) {\n onChange(nextValue)\n }\n },\n {isActive: focus},\n )\n\n return <Text color={color}>{value.length > 0 ? renderedValue : renderedPlaceholder}</Text>\n}\n\nexport {TextInput}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { TextInput } from './TextInput.js';
|
|
2
|
-
import {
|
|
2
|
+
import { sendInputAndWait, sendInputAndWaitForChange, waitForChange, waitForInputsToBeReady, } from '../../../../testing/ui.js';
|
|
3
3
|
import React, { useState } from 'react';
|
|
4
4
|
import { describe, test, expect, vi } from 'vitest';
|
|
5
5
|
import { render } from 'ink-testing-library';
|
|
@@ -26,33 +26,31 @@ describe('TextInput', () => {
|
|
|
26
26
|
const renderInstance = render(React.createElement(TextInput, { value: "Hello", onChange: () => { } }));
|
|
27
27
|
expect(renderInstance.lastFrame()).toMatchInlineSnapshot('"[36mHello[7m [27m[39m"');
|
|
28
28
|
await waitForInputsToBeReady();
|
|
29
|
-
await
|
|
29
|
+
await sendInputAndWaitForChange(renderInstance, ARROW_LEFT);
|
|
30
30
|
expect(renderInstance.lastFrame()).toMatchInlineSnapshot('"[36mHell[7mo[27m[39m"');
|
|
31
|
-
await
|
|
31
|
+
await sendInputAndWaitForChange(renderInstance, ARROW_LEFT);
|
|
32
32
|
expect(renderInstance.lastFrame()).toMatchInlineSnapshot('"[36mHel[7ml[27mo[39m"');
|
|
33
|
-
await
|
|
33
|
+
await sendInputAndWaitForChange(renderInstance, ARROW_LEFT);
|
|
34
34
|
expect(renderInstance.lastFrame()).toMatchInlineSnapshot('"[36mHe[7ml[27mlo[39m"');
|
|
35
|
-
await
|
|
35
|
+
await sendInputAndWaitForChange(renderInstance, ARROW_LEFT);
|
|
36
36
|
expect(renderInstance.lastFrame()).toMatchInlineSnapshot('"[36mH[7me[27mllo[39m"');
|
|
37
|
-
await
|
|
37
|
+
await sendInputAndWaitForChange(renderInstance, ARROW_LEFT);
|
|
38
38
|
expect(renderInstance.lastFrame()).toMatchInlineSnapshot('"[36m[7mH[27mello[39m"');
|
|
39
39
|
// cursor can't go before the first character
|
|
40
|
-
renderInstance
|
|
41
|
-
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
40
|
+
await sendInputAndWait(renderInstance, 100, ARROW_LEFT);
|
|
42
41
|
expect(renderInstance.lastFrame()).toMatchInlineSnapshot('"[36m[7mH[27mello[39m"');
|
|
43
|
-
await
|
|
42
|
+
await sendInputAndWaitForChange(renderInstance, ARROW_RIGHT);
|
|
44
43
|
expect(renderInstance.lastFrame()).toMatchInlineSnapshot('"[36mH[7me[27mllo[39m"');
|
|
45
|
-
await
|
|
44
|
+
await sendInputAndWaitForChange(renderInstance, ARROW_RIGHT);
|
|
46
45
|
expect(renderInstance.lastFrame()).toMatchInlineSnapshot('"[36mHe[7ml[27mlo[39m"');
|
|
47
|
-
await
|
|
46
|
+
await sendInputAndWaitForChange(renderInstance, ARROW_RIGHT);
|
|
48
47
|
expect(renderInstance.lastFrame()).toMatchInlineSnapshot('"[36mHel[7ml[27mo[39m"');
|
|
49
|
-
await
|
|
48
|
+
await sendInputAndWaitForChange(renderInstance, ARROW_RIGHT);
|
|
50
49
|
expect(renderInstance.lastFrame()).toMatchInlineSnapshot('"[36mHell[7mo[27m[39m"');
|
|
51
|
-
await
|
|
50
|
+
await sendInputAndWaitForChange(renderInstance, ARROW_RIGHT);
|
|
52
51
|
expect(renderInstance.lastFrame()).toMatchInlineSnapshot('"[36mHello[7m [27m[39m"');
|
|
53
52
|
// cursor can't go after the last character
|
|
54
|
-
renderInstance
|
|
55
|
-
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
53
|
+
await sendInputAndWait(renderInstance, 100, ARROW_RIGHT);
|
|
56
54
|
expect(renderInstance.lastFrame()).toMatchInlineSnapshot('"[36mHello[7m [27m[39m"');
|
|
57
55
|
});
|
|
58
56
|
test('moves the cursor when deleting', async () => {
|
|
@@ -63,19 +61,18 @@ describe('TextInput', () => {
|
|
|
63
61
|
const renderInstance = render(React.createElement(StatefulTextInput, null));
|
|
64
62
|
expect(renderInstance.lastFrame()).toMatchInlineSnapshot('"[36mHello[7m [27m[39m"');
|
|
65
63
|
await waitForInputsToBeReady();
|
|
66
|
-
await
|
|
64
|
+
await sendInputAndWaitForChange(renderInstance, DELETE);
|
|
67
65
|
expect(renderInstance.lastFrame()).toMatchInlineSnapshot('"[36mHell[7m [27m[39m"');
|
|
68
|
-
await
|
|
66
|
+
await sendInputAndWaitForChange(renderInstance, DELETE);
|
|
69
67
|
expect(renderInstance.lastFrame()).toMatchInlineSnapshot('"[36mHel[7m [27m[39m"');
|
|
70
|
-
await
|
|
68
|
+
await sendInputAndWaitForChange(renderInstance, DELETE);
|
|
71
69
|
expect(renderInstance.lastFrame()).toMatchInlineSnapshot('"[36mHe[7m [27m[39m"');
|
|
72
|
-
await
|
|
70
|
+
await sendInputAndWaitForChange(renderInstance, DELETE);
|
|
73
71
|
expect(renderInstance.lastFrame()).toMatchInlineSnapshot('"[36mH[7m [27m[39m"');
|
|
74
|
-
await
|
|
72
|
+
await sendInputAndWaitForChange(renderInstance, DELETE);
|
|
75
73
|
expect(renderInstance.lastFrame()).toMatchInlineSnapshot('"[36m[7m [27m[39m"');
|
|
76
74
|
// cannot delete after the value has been cleared
|
|
77
|
-
renderInstance
|
|
78
|
-
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
75
|
+
await sendInputAndWait(renderInstance, 100, DELETE);
|
|
79
76
|
expect(renderInstance.lastFrame()).toMatchInlineSnapshot('"[36m[7m [27m[39m"');
|
|
80
77
|
});
|
|
81
78
|
test('accepts input', async () => {
|
|
@@ -85,16 +82,23 @@ describe('TextInput', () => {
|
|
|
85
82
|
};
|
|
86
83
|
const renderInstance = render(React.createElement(StatefulTextInput, null));
|
|
87
84
|
await waitForInputsToBeReady();
|
|
88
|
-
await
|
|
85
|
+
await sendInputAndWaitForChange(renderInstance, 'H');
|
|
89
86
|
expect(renderInstance.lastFrame()).toMatchInlineSnapshot('"[36mH[7m [27m[39m"');
|
|
90
|
-
await
|
|
87
|
+
await sendInputAndWaitForChange(renderInstance, 'ello');
|
|
91
88
|
expect(renderInstance.lastFrame()).toMatchInlineSnapshot('"[36mHello[7m [27m[39m"');
|
|
92
89
|
});
|
|
93
90
|
test('onChange', async () => {
|
|
94
91
|
const onChange = vi.fn();
|
|
95
|
-
const
|
|
92
|
+
const StatefulTextInput = () => {
|
|
93
|
+
const [value, setValue] = useState('');
|
|
94
|
+
return (React.createElement(TextInput, { value: value, onChange: (value) => {
|
|
95
|
+
setValue(value);
|
|
96
|
+
onChange(value);
|
|
97
|
+
} }));
|
|
98
|
+
};
|
|
99
|
+
const renderInstance = render(React.createElement(StatefulTextInput, null));
|
|
96
100
|
await waitForInputsToBeReady();
|
|
97
|
-
await
|
|
101
|
+
await sendInputAndWaitForChange(renderInstance, 'X');
|
|
98
102
|
expect(onChange).toHaveBeenCalledWith('X');
|
|
99
103
|
});
|
|
100
104
|
test('deletes at the beginning and in the middle of text', async () => {
|
|
@@ -104,17 +108,16 @@ describe('TextInput', () => {
|
|
|
104
108
|
};
|
|
105
109
|
const renderInstance = render(React.createElement(StatefulTextInput, null));
|
|
106
110
|
await waitForInputsToBeReady();
|
|
107
|
-
await
|
|
108
|
-
await
|
|
109
|
-
await
|
|
110
|
-
await
|
|
111
|
-
await
|
|
112
|
-
await
|
|
111
|
+
await sendInputAndWaitForChange(renderInstance, 'T');
|
|
112
|
+
await sendInputAndWaitForChange(renderInstance, 'e');
|
|
113
|
+
await sendInputAndWaitForChange(renderInstance, 's');
|
|
114
|
+
await sendInputAndWaitForChange(renderInstance, 't');
|
|
115
|
+
await sendInputAndWaitForChange(renderInstance, ARROW_LEFT);
|
|
116
|
+
await sendInputAndWaitForChange(renderInstance, DELETE);
|
|
113
117
|
expect(renderInstance.lastFrame()).toMatchInlineSnapshot('"[36mTe[7mt[27m[39m"');
|
|
114
|
-
await
|
|
115
|
-
await
|
|
116
|
-
renderInstance
|
|
117
|
-
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
118
|
+
await sendInputAndWaitForChange(renderInstance, ARROW_LEFT);
|
|
119
|
+
await sendInputAndWaitForChange(renderInstance, ARROW_LEFT);
|
|
120
|
+
await sendInputAndWait(renderInstance, 100, DELETE);
|
|
118
121
|
expect(renderInstance.lastFrame()).toMatchInlineSnapshot('"[36m[7mT[27met[39m"');
|
|
119
122
|
});
|
|
120
123
|
test('adjusts cursor when text is shorter than last value', async () => {
|
|
@@ -126,14 +129,18 @@ describe('TextInput', () => {
|
|
|
126
129
|
};
|
|
127
130
|
const renderInstance = render(React.createElement(StatefulTextInput, null));
|
|
128
131
|
await waitForInputsToBeReady();
|
|
129
|
-
await
|
|
130
|
-
await
|
|
132
|
+
await sendInputAndWaitForChange(renderInstance, 'A');
|
|
133
|
+
await sendInputAndWaitForChange(renderInstance, 'B');
|
|
131
134
|
await waitForChange(resetValue, renderInstance.lastFrame);
|
|
132
135
|
expect(renderInstance.lastFrame()).toMatchInlineSnapshot('"[36m[7m [27m[39m"');
|
|
133
|
-
await
|
|
136
|
+
await sendInputAndWaitForChange(renderInstance, 'A');
|
|
134
137
|
expect(renderInstance.lastFrame()).toMatchInlineSnapshot('"[36mA[7m [27m[39m"');
|
|
135
|
-
await
|
|
138
|
+
await sendInputAndWaitForChange(renderInstance, 'B');
|
|
136
139
|
expect(renderInstance.lastFrame()).toMatchInlineSnapshot('"[36mAB[7m [27m[39m"');
|
|
137
140
|
});
|
|
141
|
+
test("masking the input if it's a password", async () => {
|
|
142
|
+
const renderInstance = render(React.createElement(TextInput, { onChange: () => { }, value: "ABC", password: true }));
|
|
143
|
+
expect(renderInstance.lastFrame()).toMatchInlineSnapshot('"[36m***[7m [27m[39m"');
|
|
144
|
+
});
|
|
138
145
|
});
|
|
139
146
|
//# sourceMappingURL=TextInput.test.js.map
|