From 2a9b3a45622d1071a345c5ed2cd30a570d9e5657 Mon Sep 17 00:00:00 2001 From: Ariel Caplan Date: Mon, 7 Sep 2026 19:06:09 +0300 Subject: [PATCH 1/2] Fix text prompt underlines in Windows consoles Assisted-By: devx/d54f9bfe-5e29-4147-aea5-071dbb6add71 --- .changeset/windows-prompt-underline.md | 5 +++++ .../DangerousConfirmationPrompt.test.tsx | 10 +++++----- .../components/DangerousConfirmationPrompt.tsx | 12 ++++++++---- .../node/ui/components/TextPrompt.test.tsx | 18 +++++++++--------- .../private/node/ui/components/TextPrompt.tsx | 12 ++++++++---- 5 files changed, 35 insertions(+), 22 deletions(-) create mode 100644 .changeset/windows-prompt-underline.md diff --git a/.changeset/windows-prompt-underline.md b/.changeset/windows-prompt-underline.md new file mode 100644 index 00000000000..daa7b2a0f74 --- /dev/null +++ b/.changeset/windows-prompt-underline.md @@ -0,0 +1,5 @@ +--- +'@shopify/cli-kit': patch +--- + +Fix text prompt underlines rendering as unsupported characters in Windows consoles. diff --git a/packages/cli-kit/src/private/node/ui/components/DangerousConfirmationPrompt.test.tsx b/packages/cli-kit/src/private/node/ui/components/DangerousConfirmationPrompt.test.tsx index b5eb3fc0d7e..af4ad4d6190 100644 --- a/packages/cli-kit/src/private/node/ui/components/DangerousConfirmationPrompt.test.tsx +++ b/packages/cli-kit/src/private/node/ui/components/DangerousConfirmationPrompt.test.tsx @@ -19,7 +19,7 @@ describe('DangerousConfirmationPrompt', () => { Type yes to confirm, or press Escape to cancel. > █ - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ───────────────────────────────────────────────────────────────────────────── " `) }) @@ -37,7 +37,7 @@ describe('DangerousConfirmationPrompt', () => { Type yes to confirm, or press Escape to cancel. > █ - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ───────────────────────────────────────────────────────────────────────────── Value must be exactly yes " `) @@ -48,7 +48,7 @@ describe('DangerousConfirmationPrompt', () => { Type yes to confirm, or press Escape to cancel. > A█ - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ───────────────────────────────────────────────────────────────────────────── " `) }) @@ -86,7 +86,7 @@ describe('DangerousConfirmationPrompt', () => { Type yes to confirm, or press Escape to cancel. > AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA BBBBBB█ - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ───────────────────────────────────────────────────────────────────────────── " `) }) @@ -101,7 +101,7 @@ describe('DangerousConfirmationPrompt', () => { Type yes to confirm, or press Escape to cancel. > █ - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ───────────────────────────────────────────────────────────────────────────── " `) }) diff --git a/packages/cli-kit/src/private/node/ui/components/DangerousConfirmationPrompt.tsx b/packages/cli-kit/src/private/node/ui/components/DangerousConfirmationPrompt.tsx index dfeda4abbe5..8aac30cc3de 100644 --- a/packages/cli-kit/src/private/node/ui/components/DangerousConfirmationPrompt.tsx +++ b/packages/cli-kit/src/private/node/ui/components/DangerousConfirmationPrompt.tsx @@ -44,7 +44,6 @@ const DangerousConfirmationPrompt: FunctionComponent | undefined>(undefined) const color = promptState === PromptState.Error ? 'red' : 'cyan' - const underline = new Array(oneThird - 3).fill('▔') const {isAborted} = useAbortSignal(abortSignal) useInput((input, key) => { @@ -133,9 +132,14 @@ const DangerousConfirmationPrompt: FunctionComponent - - {underline} - + {promptState === PromptState.Error && error ? ( diff --git a/packages/cli-kit/src/private/node/ui/components/TextPrompt.test.tsx b/packages/cli-kit/src/private/node/ui/components/TextPrompt.test.tsx index 939cec7006e..1bbf75cf1c5 100644 --- a/packages/cli-kit/src/private/node/ui/components/TextPrompt.test.tsx +++ b/packages/cli-kit/src/private/node/ui/components/TextPrompt.test.tsx @@ -16,7 +16,7 @@ describe('TextPrompt', () => { expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(` "? Test question: > Placeholder - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ───────────────────────────────────────────────────────────────────────────── " `) }) @@ -30,7 +30,7 @@ describe('TextPrompt', () => { expect(renderInstance.lastFrame()).toMatchInlineSnapshot(` "? Test question: > █ - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ───────────────────────────────────────────────────────────────────────────── Type an answer to the prompt. " `) @@ -39,7 +39,7 @@ describe('TextPrompt', () => { expect(renderInstance.lastFrame()).toMatchInlineSnapshot(` "? Test question: > A█ - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ───────────────────────────────────────────────────────────────────────────── " `) }) @@ -60,7 +60,7 @@ describe('TextPrompt', () => { expect(renderInstance.lastFrame()).toMatchInlineSnapshot(` "? Test question: > this-test-includes-shopify█ - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ───────────────────────────────────────────────────────────────────────────── App name can't include the word shopify " `) @@ -145,7 +145,7 @@ describe('TextPrompt', () => { "? Test question: > AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA BBBBBB█ - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ───────────────────────────────────────────────────────────────────────────── " `) }) @@ -158,7 +158,7 @@ describe('TextPrompt', () => { expect(renderInstance.lastFrame()).toMatchInlineSnapshot(` "? Test question: > ***█ - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ───────────────────────────────────────────────────────────────────────────── " `) @@ -176,7 +176,7 @@ describe('TextPrompt', () => { expect(lastFrame()!).toMatchInlineSnapshot(` "? Test question? > █ - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ───────────────────────────────────────────────────────────────────────────── " `) }) @@ -223,7 +223,7 @@ describe('TextPrompt', () => { expect(renderInstance.lastFrame()).toMatchInlineSnapshot(` "? How tall are you in cm? > 180█ - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ───────────────────────────────────────────────────────────────────────────── You are 1.8m tall. " `) @@ -248,7 +248,7 @@ describe('TextPrompt', () => { expect(renderInstance.lastFrame()!).toMatchInlineSnapshot(` "? How tall are you? > uber█ - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ───────────────────────────────────────────────────────────────────────────── You are incredibly humongously savagely unnaturally monstrously pathetically  arrogantly uber tall. " diff --git a/packages/cli-kit/src/private/node/ui/components/TextPrompt.tsx b/packages/cli-kit/src/private/node/ui/components/TextPrompt.tsx index 37e24221c94..cec4f5d2ea5 100644 --- a/packages/cli-kit/src/private/node/ui/components/TextPrompt.tsx +++ b/packages/cli-kit/src/private/node/ui/components/TextPrompt.tsx @@ -64,7 +64,6 @@ const TextPrompt: FunctionComponent = ({ const complete = useComplete() const [error, setError] = useState(undefined) const color = promptState === PromptState.Error ? 'red' : 'cyan' - const underline = new Array(oneThird - 3).fill('▔') const {isAborted} = useAbortSignal(abortSignal) useInput((input, key) => { @@ -128,9 +127,14 @@ const TextPrompt: FunctionComponent = ({ /> - - {underline} - + {promptState === PromptState.Error ? ( {error} From 0746103631c30052d5dc324942aa13e55d992c36 Mon Sep 17 00:00:00 2001 From: Ariel Caplan Date: Mon, 7 Sep 2026 19:21:12 +0300 Subject: [PATCH 2/2] Preserve text prompt underlines on macOS and Linux Assisted-By: devx/d54f9bfe-5e29-4147-aea5-071dbb6add71 --- .../DangerousConfirmationPrompt.test.tsx | 35 +++++++++++++--- .../DangerousConfirmationPrompt.tsx | 23 +++++++---- .../node/ui/components/TextPrompt.test.tsx | 40 ++++++++++++++----- .../private/node/ui/components/TextPrompt.tsx | 23 +++++++---- 4 files changed, 89 insertions(+), 32 deletions(-) diff --git a/packages/cli-kit/src/private/node/ui/components/DangerousConfirmationPrompt.test.tsx b/packages/cli-kit/src/private/node/ui/components/DangerousConfirmationPrompt.test.tsx index af4ad4d6190..69ac5628d5b 100644 --- a/packages/cli-kit/src/private/node/ui/components/DangerousConfirmationPrompt.test.tsx +++ b/packages/cli-kit/src/private/node/ui/components/DangerousConfirmationPrompt.test.tsx @@ -1,14 +1,37 @@ import {DangerousConfirmationPrompt} from './DangerousConfirmationPrompt.js' import {getLastFrameAfterUnmount, sendInputAndWaitForChange, waitForInputsToBeReady, render} from '../../testing/ui.js' import {unstyled} from '../../../../public/node/output.js' +import colors from '../../../../public/node/colors.js' +import {platformAndArch} from '../../../../public/node/os.js' import React from 'react' -import {describe, expect, test, vi} from 'vitest' +import {beforeEach, describe, expect, test, vi} from 'vitest' + +vi.mock('../../../../public/node/os.js') + +beforeEach(() => { + vi.mocked(platformAndArch).mockReturnValue({platform: 'darwin', arch: 'arm64'}) +}) const ENTER = '\r' const ESC = '\x1b' describe('DangerousConfirmationPrompt', () => { + test.each(['windows', 'darwin', 'linux'] as const)('renders the underline on %s', async (platform) => { + vi.mocked(platformAndArch).mockReturnValue({platform, arch: 'amd64'}) + const renderInstance = render( + {}} message="Test question" confirmation="yes" />, + ) + const underline = (platform === 'windows' ? '─' : '▔').repeat(77) + + expect(renderInstance.lastFrame()).toContain(colors.cyan(underline)) + + await waitForInputsToBeReady() + await sendInputAndWaitForChange(renderInstance, ENTER) + + expect(renderInstance.lastFrame()).toContain(colors.red(underline)) + }) + test('default state', () => { const {lastFrame} = render( {}} message="Test question" confirmation="yes" />, @@ -19,7 +42,7 @@ describe('DangerousConfirmationPrompt', () => { Type yes to confirm, or press Escape to cancel. > █ - ───────────────────────────────────────────────────────────────────────────── + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ " `) }) @@ -37,7 +60,7 @@ describe('DangerousConfirmationPrompt', () => { Type yes to confirm, or press Escape to cancel. > █ - ───────────────────────────────────────────────────────────────────────────── + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ Value must be exactly yes " `) @@ -48,7 +71,7 @@ describe('DangerousConfirmationPrompt', () => { Type yes to confirm, or press Escape to cancel. > A█ - ───────────────────────────────────────────────────────────────────────────── + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ " `) }) @@ -86,7 +109,7 @@ describe('DangerousConfirmationPrompt', () => { Type yes to confirm, or press Escape to cancel. > AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA BBBBBB█ - ───────────────────────────────────────────────────────────────────────────── + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ " `) }) @@ -101,7 +124,7 @@ describe('DangerousConfirmationPrompt', () => { Type yes to confirm, or press Escape to cancel. > █ - ───────────────────────────────────────────────────────────────────────────── + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ " `) }) diff --git a/packages/cli-kit/src/private/node/ui/components/DangerousConfirmationPrompt.tsx b/packages/cli-kit/src/private/node/ui/components/DangerousConfirmationPrompt.tsx index 8aac30cc3de..73abcf5fe25 100644 --- a/packages/cli-kit/src/private/node/ui/components/DangerousConfirmationPrompt.tsx +++ b/packages/cli-kit/src/private/node/ui/components/DangerousConfirmationPrompt.tsx @@ -5,6 +5,7 @@ import {handleCtrlC, useComplete} from '../../ui.js' import useLayout from '../hooks/use-layout.js' import {messageWithPunctuation} from '../utilities.js' import {AbortSignal} from '../../../../public/node/abort.js' +import {platformAndArch} from '../../../../public/node/os.js' import useAbortSignal from '../hooks/use-abort-signal.js' import usePrompt, {PromptState} from '../hooks/use-prompt.js' @@ -132,14 +133,20 @@ const DangerousConfirmationPrompt: FunctionComponent - + {platformAndArch().platform === 'windows' ? ( + + ) : ( + + {'▔'.repeat(oneThird - 3)} + + )} {promptState === PromptState.Error && error ? ( diff --git a/packages/cli-kit/src/private/node/ui/components/TextPrompt.test.tsx b/packages/cli-kit/src/private/node/ui/components/TextPrompt.test.tsx index 1bbf75cf1c5..b41b31b0842 100644 --- a/packages/cli-kit/src/private/node/ui/components/TextPrompt.test.tsx +++ b/packages/cli-kit/src/private/node/ui/components/TextPrompt.test.tsx @@ -3,20 +3,40 @@ import {getLastFrameAfterUnmount, sendInputAndWaitForChange, waitForInputsToBeRe import {unstyled} from '../../../../public/node/output.js' import {AbortController} from '../../../../public/node/abort.js' import colors from '../../../../public/node/colors.js' +import {platformAndArch} from '../../../../public/node/os.js' import React from 'react' -import {describe, expect, test, vi} from 'vitest' +import {beforeEach, describe, expect, test, vi} from 'vitest' + +vi.mock('../../../../public/node/os.js') + +beforeEach(() => { + vi.mocked(platformAndArch).mockReturnValue({platform: 'darwin', arch: 'arm64'}) +}) const ENTER = '\r' describe('TextPrompt', () => { + test.each(['windows', 'darwin', 'linux'] as const)('renders the underline on %s', async (platform) => { + vi.mocked(platformAndArch).mockReturnValue({platform, arch: 'amd64'}) + const renderInstance = render( {}} message="Test question" />) + const underline = (platform === 'windows' ? '─' : '▔').repeat(77) + + expect(renderInstance.lastFrame()).toContain(colors.cyan(underline)) + + await waitForInputsToBeReady() + await sendInputAndWaitForChange(renderInstance, ENTER) + + expect(renderInstance.lastFrame()).toContain(colors.red(underline)) + }) + test('default state', () => { const {lastFrame} = render( {}} message="Test question" defaultValue="Placeholder" />) expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(` "? Test question: > Placeholder - ───────────────────────────────────────────────────────────────────────────── + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ " `) }) @@ -30,7 +50,7 @@ describe('TextPrompt', () => { expect(renderInstance.lastFrame()).toMatchInlineSnapshot(` "? Test question: > █ - ───────────────────────────────────────────────────────────────────────────── + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ Type an answer to the prompt. " `) @@ -39,7 +59,7 @@ describe('TextPrompt', () => { expect(renderInstance.lastFrame()).toMatchInlineSnapshot(` "? Test question: > A█ - ───────────────────────────────────────────────────────────────────────────── + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ " `) }) @@ -60,7 +80,7 @@ describe('TextPrompt', () => { expect(renderInstance.lastFrame()).toMatchInlineSnapshot(` "? Test question: > this-test-includes-shopify█ - ───────────────────────────────────────────────────────────────────────────── + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ App name can't include the word shopify " `) @@ -145,7 +165,7 @@ describe('TextPrompt', () => { "? Test question: > AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA BBBBBB█ - ───────────────────────────────────────────────────────────────────────────── + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ " `) }) @@ -158,7 +178,7 @@ describe('TextPrompt', () => { expect(renderInstance.lastFrame()).toMatchInlineSnapshot(` "? Test question: > ***█ - ───────────────────────────────────────────────────────────────────────────── + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ " `) @@ -176,7 +196,7 @@ describe('TextPrompt', () => { expect(lastFrame()!).toMatchInlineSnapshot(` "? Test question? > █ - ───────────────────────────────────────────────────────────────────────────── + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ " `) }) @@ -223,7 +243,7 @@ describe('TextPrompt', () => { expect(renderInstance.lastFrame()).toMatchInlineSnapshot(` "? How tall are you in cm? > 180█ - ───────────────────────────────────────────────────────────────────────────── + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ You are 1.8m tall. " `) @@ -248,7 +268,7 @@ describe('TextPrompt', () => { expect(renderInstance.lastFrame()!).toMatchInlineSnapshot(` "? How tall are you? > uber█ - ───────────────────────────────────────────────────────────────────────────── + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ You are incredibly humongously savagely unnaturally monstrously pathetically  arrogantly uber tall. " diff --git a/packages/cli-kit/src/private/node/ui/components/TextPrompt.tsx b/packages/cli-kit/src/private/node/ui/components/TextPrompt.tsx index cec4f5d2ea5..1ca5f5a4749 100644 --- a/packages/cli-kit/src/private/node/ui/components/TextPrompt.tsx +++ b/packages/cli-kit/src/private/node/ui/components/TextPrompt.tsx @@ -4,6 +4,7 @@ import {handleCtrlC, useComplete} from '../../ui.js' import useLayout from '../hooks/use-layout.js' import {messageWithPunctuation} from '../utilities.js' import {AbortSignal} from '../../../../public/node/abort.js' +import {platformAndArch} from '../../../../public/node/os.js' import useAbortSignal from '../hooks/use-abort-signal.js' import usePrompt, {PromptState} from '../hooks/use-prompt.js' import React, {FunctionComponent, useCallback, useEffect, useState} from 'react' @@ -127,14 +128,20 @@ const TextPrompt: FunctionComponent = ({ /> - + {platformAndArch().platform === 'windows' ? ( + + ) : ( + + {'▔'.repeat(oneThird - 3)} + + )} {promptState === PromptState.Error ? ( {error}