@shopify/cli-kit 3.93.2 → 3.94.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.
Files changed (84) hide show
  1. package/dist/private/node/analytics.d.ts +2 -0
  2. package/dist/private/node/analytics.js +10 -1
  3. package/dist/private/node/analytics.js.map +1 -1
  4. package/dist/private/node/api/urls.js +19 -5
  5. package/dist/private/node/api/urls.js.map +1 -1
  6. package/dist/private/node/content-tokens.js +6 -2
  7. package/dist/private/node/content-tokens.js.map +1 -1
  8. package/dist/private/node/session/exchange.js +11 -3
  9. package/dist/private/node/session/exchange.js.map +1 -1
  10. package/dist/private/node/session.d.ts +7 -7
  11. package/dist/private/node/session.js +11 -9
  12. package/dist/private/node/session.js.map +1 -1
  13. package/dist/private/node/temp-dir.d.ts +1 -0
  14. package/dist/private/node/temp-dir.js +8 -0
  15. package/dist/private/node/temp-dir.js.map +1 -0
  16. package/dist/private/node/testing/ui.js +4 -3
  17. package/dist/private/node/testing/ui.js.map +1 -1
  18. package/dist/private/node/ui/components/AutocompletePrompt.js +5 -4
  19. package/dist/private/node/ui/components/AutocompletePrompt.js.map +1 -1
  20. package/dist/private/node/ui/components/ConcurrentOutput.js +12 -10
  21. package/dist/private/node/ui/components/ConcurrentOutput.js.map +1 -1
  22. package/dist/private/node/ui/components/ConcurrentOutput.test.js +27 -4
  23. package/dist/private/node/ui/components/ConcurrentOutput.test.js.map +1 -1
  24. package/dist/private/node/ui/components/DangerousConfirmationPrompt.d.ts +2 -0
  25. package/dist/private/node/ui/components/DangerousConfirmationPrompt.js +12 -7
  26. package/dist/private/node/ui/components/DangerousConfirmationPrompt.js.map +1 -1
  27. package/dist/private/node/ui/components/LoadingBar.js +9 -2
  28. package/dist/private/node/ui/components/LoadingBar.js.map +1 -1
  29. package/dist/private/node/ui/components/LoadingBar.test.js +49 -88
  30. package/dist/private/node/ui/components/LoadingBar.test.js.map +1 -1
  31. package/dist/private/node/ui/components/SelectPrompt.js +4 -4
  32. package/dist/private/node/ui/components/SelectPrompt.js.map +1 -1
  33. package/dist/private/node/ui/components/SingleTask.js +12 -6
  34. package/dist/private/node/ui/components/SingleTask.js.map +1 -1
  35. package/dist/private/node/ui/components/TextPrompt.js +5 -5
  36. package/dist/private/node/ui/components/TextPrompt.js.map +1 -1
  37. package/dist/private/node/ui/hooks/use-abort-signal.js +10 -15
  38. package/dist/private/node/ui/hooks/use-abort-signal.js.map +1 -1
  39. package/dist/private/node/ui/hooks/use-async-and-unmount.js +11 -5
  40. package/dist/private/node/ui/hooks/use-async-and-unmount.js.map +1 -1
  41. package/dist/private/node/ui.d.ts +17 -1
  42. package/dist/private/node/ui.js +35 -4
  43. package/dist/private/node/ui.js.map +1 -1
  44. package/dist/public/common/version.d.ts +1 -1
  45. package/dist/public/common/version.js +1 -1
  46. package/dist/public/common/version.js.map +1 -1
  47. package/dist/public/node/context/local.js +1 -2
  48. package/dist/public/node/context/local.js.map +1 -1
  49. package/dist/public/node/error-handler.js +4 -0
  50. package/dist/public/node/error-handler.js.map +1 -1
  51. package/dist/public/node/error.js +2 -0
  52. package/dist/public/node/error.js.map +1 -1
  53. package/dist/public/node/fs.js +10 -4
  54. package/dist/public/node/fs.js.map +1 -1
  55. package/dist/public/node/hooks/postrun.js +9 -10
  56. package/dist/public/node/hooks/postrun.js.map +1 -1
  57. package/dist/public/node/metadata.d.ts +1 -1
  58. package/dist/public/node/metadata.js.map +1 -1
  59. package/dist/public/node/monorail.d.ts +10 -1
  60. package/dist/public/node/monorail.js +1 -1
  61. package/dist/public/node/monorail.js.map +1 -1
  62. package/dist/public/node/node-package-manager.d.ts +12 -0
  63. package/dist/public/node/node-package-manager.js +62 -30
  64. package/dist/public/node/node-package-manager.js.map +1 -1
  65. package/dist/public/node/path.d.ts +8 -0
  66. package/dist/public/node/path.js +17 -2
  67. package/dist/public/node/path.js.map +1 -1
  68. package/dist/public/node/system.d.ts +6 -0
  69. package/dist/public/node/system.js +9 -0
  70. package/dist/public/node/system.js.map +1 -1
  71. package/dist/public/node/tcp.js +32 -8
  72. package/dist/public/node/tcp.js.map +1 -1
  73. package/dist/public/node/ui.d.ts +1 -3
  74. package/dist/public/node/ui.js +16 -14
  75. package/dist/public/node/ui.js.map +1 -1
  76. package/dist/public/node/upgrade.d.ts +7 -2
  77. package/dist/public/node/upgrade.js +20 -7
  78. package/dist/public/node/upgrade.js.map +1 -1
  79. package/dist/public/node/vendor/dev_server/dev-server-2024.js +1 -1
  80. package/dist/public/node/vendor/dev_server/dev-server-2024.js.map +1 -1
  81. package/dist/public/node/vendor/otel-js/service/DefaultOtelService/DefaultMeterProvider.js +1 -2
  82. package/dist/public/node/vendor/otel-js/service/DefaultOtelService/DefaultMeterProvider.js.map +1 -1
  83. package/dist/tsconfig.tsbuildinfo +1 -1
  84. package/package.json +1 -8
@@ -1 +1 @@
1
- {"version":3,"file":"DangerousConfirmationPrompt.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/DangerousConfirmationPrompt.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,EAAC,MAAM,gBAAgB,CAAA;AACxC,OAAO,EAAyB,aAAa,EAAC,MAAM,oBAAoB,CAAA;AACxE,OAAO,EAAC,SAAS,EAAiB,MAAM,wBAAwB,CAAA;AAChE,OAAO,EAAC,WAAW,EAAC,MAAM,aAAa,CAAA;AACvC,OAAO,SAAS,MAAM,wBAAwB,CAAA;AAC9C,OAAO,EAAC,sBAAsB,EAAC,MAAM,iBAAiB,CAAA;AAEtD,OAAO,cAAc,MAAM,8BAA8B,CAAA;AACzD,OAAO,SAAS,EAAE,EAAC,WAAW,EAAC,MAAM,wBAAwB,CAAA;AAE7D,OAAO,KAAK,EAAE,EAAoB,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAC,MAAM,OAAO,CAAA;AAChF,OAAO,EAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAC,MAAM,KAAK,CAAA;AAC/C,OAAO,OAAO,MAAM,SAAS,CAAA;AAU7B,MAAM,2BAA2B,GAAwD,CAAC,EACxF,OAAO,EACP,YAAY,EACZ,SAAS,EACT,QAAQ,EACR,WAAW,GACZ,EAAE,EAAE;IACH,MAAM,cAAc,GAAG,WAAW,CAChC,CAAC,KAAa,EAAsC,EAAE;QACpD,OAAO,KAAK,KAAK,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,uBAAuB,EAAE,EAAC,SAAS,EAAE,YAAY,EAAC,CAAC,CAAA;IAClG,CAAC,EACD,CAAC,YAAY,CAAC,CACf,CAAA;IAED,MAAM,EAAC,QAAQ,EAAE,SAAS,EAAC,GAAG,SAAS,EAAE,CAAA;IACzC,MAAM,EAAC,WAAW,EAAE,cAAc,EAAE,MAAM,EAAE,SAAS,EAAC,GAAG,SAAS,CAAS;QACzE,aAAa,EAAE,EAAE;KAClB,CAAC,CAAA;IACF,MAAM,EAAC,IAAI,EAAE,UAAU,EAAC,GAAG,MAAM,EAAE,CAAA;IACnC,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAqC,SAAS,CAAC,CAAA;IACjF,MAAM,KAAK,GAAG,WAAW,KAAK,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAA;IAChE,MAAM,SAAS,GAAG,IAAI,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IACnD,MAAM,EAAC,SAAS,EAAC,GAAG,cAAc,CAAC,WAAW,CAAC,CAAA;IAE/C,QAAQ,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QACtB,WAAW,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;QAEvB,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;YACf,cAAc,CAAC,WAAW,CAAC,SAAS,CAAC,CAAA;YACrC,QAAQ,CAAC,SAAS,CAAC,CAAA;QACrB,CAAC;QAED,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;YACf,MAAM,KAAK,GAAG,cAAc,CAAC,MAAM,CAAC,CAAA;YAEpC,IAAI,KAAK,EAAE,CAAC;gBACV,cAAc,CAAC,WAAW,CAAC,KAAK,CAAC,CAAA;gBACjC,QAAQ,CAAC,KAAK,CAAC,CAAA;YACjB,CAAC;iBAAM,CAAC;gBACN,cAAc,CAAC,WAAW,CAAC,SAAS,CAAC,CAAA;YACvC,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CAAA;IAEF,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,WAAW,KAAK,WAAW,CAAC,SAAS,EAAE,CAAC;YAC1C,QAAQ,CAAC,IAAI,CAAC,CAAA;YACd,UAAU,EAAE,CAAA;QACd,CAAC;aAAM,IAAI,WAAW,KAAK,WAAW,CAAC,SAAS,EAAE,CAAC;YACjD,QAAQ,CAAC,KAAK,CAAC,CAAA;YACf,UAAU,EAAE,CAAA;QACd,CAAC;IACH,CAAC,EAAE,CAAC,QAAQ,EAAE,WAAW,EAAE,UAAU,CAAC,CAAC,CAAA;IAEvC,MAAM,SAAS,GAAG,WAAW,KAAK,WAAW,CAAC,SAAS,IAAI,WAAW,KAAK,WAAW,CAAC,SAAS,CAAA;IAEhG,OAAO,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CACxB,oBAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,YAAY,EAAE,CAAC,EAAE,KAAK,EAAE,SAAS;QAC3D,oBAAC,GAAG;YACF,oBAAC,GAAG,IAAC,WAAW,EAAE,CAAC;gBACjB,oBAAC,IAAI,YAAS,CACV;YACN,oBAAC,aAAa,IAAC,IAAI,EAAE,sBAAsB,CAAC,OAAO,CAAC,GAAI,CACpD;QACL,SAAS,CAAC,CAAC,CAAC,CACX,oBAAC,eAAe,IAAM,SAAS,EAAE,WAAW,KAAK,WAAW,CAAC,SAAS,GAAK,CAC5E,CAAC,CAAC,CAAC,CACF;YACE,oBAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,GAAG,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC;gBAC5D,SAAS,CAAC,CAAC,CAAC,CACX,oBAAC,GAAG,IACF,WAAW,EAAE,CAAC,EACd,WAAW,EAAC,MAAM,EAClB,UAAU,QACV,WAAW,EAAE,KAAK,EAClB,SAAS,EAAE,KAAK,EAChB,YAAY,EAAE,KAAK,EACnB,aAAa,EAAC,QAAQ,EACtB,GAAG,EAAE,CAAC;oBAEN,oBAAC,SAAS,IAAC,KAAK,EAAE,SAAS,GAAI,CAC3B,CACP,CAAC,CAAC,CAAC,IAAI;gBACR,oBAAC,GAAG;oBACF,oBAAC,aAAa,IAAC,IAAI,EAAE,CAAC,MAAM,EAAE,EAAC,SAAS,EAAE,YAAY,EAAC,EAAE,wCAAwC,CAAC,GAAI,CAClG,CACF;YACN,oBAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,KAAK,EAAE,QAAQ;gBACzC,oBAAC,GAAG;oBACF,oBAAC,GAAG,IAAC,WAAW,EAAE,CAAC;wBACjB,oBAAC,IAAI,IAAC,KAAK,EAAE,KAAK,IAAG,GAAG,CAAQ,CAC5B;oBACN,oBAAC,GAAG,IAAC,QAAQ,EAAE,CAAC;wBACd,oBAAC,SAAS,IACR,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,CAAC,MAAM,EAAE,EAAE;gCACnB,SAAS,CAAC,MAAM,CAAC,CAAA;gCACjB,cAAc,CAAC,WAAW,CAAC,IAAI,CAAC,CAAA;4BAClC,CAAC,EACD,YAAY,EAAC,EAAE,EACf,KAAK,EAAE,KAAK,GACZ,CACE,CACF;gBACN,oBAAC,GAAG,IAAC,UAAU,EAAE,CAAC;oBAChB,oBAAC,IAAI,IAAC,KAAK,EAAE,KAAK,IAAG,SAAS,CAAQ,CAClC;gBACL,WAAW,KAAK,WAAW,CAAC,KAAK,IAAI,KAAK,CAAC,CAAC,CAAC,CAC5C,oBAAC,GAAG,IAAC,UAAU,EAAE,CAAC;oBAChB,oBAAC,IAAI,IAAC,KAAK,EAAE,KAAK;wBAChB,oBAAC,aAAa,IAAC,IAAI,EAAE,KAAK,GAAI,CACzB,CACH,CACP,CAAC,CAAC,CAAC,IAAI,CACJ,CACL,CACJ,CACG,CACP,CAAA;AACH,CAAC,CAAA;AAMD,MAAM,eAAe,GAA4C,CAAC,EAAC,SAAS,EAAC,EAAE,EAAE,CAAC,CAChF,oBAAC,GAAG;IACF,oBAAC,GAAG,IAAC,KAAK,EAAE,CAAC,IACV,SAAS,CAAC,CAAC,CAAC,oBAAC,IAAI,IAAC,KAAK,EAAC,KAAK,IAAE,OAAO,CAAC,KAAK,CAAQ,CAAC,CAAC,CAAC,oBAAC,IAAI,IAAC,KAAK,EAAC,MAAM,IAAE,OAAO,CAAC,IAAI,CAAQ,CAC5F;IAEN,oBAAC,GAAG,IAAC,QAAQ,EAAE,CAAC,IAAG,SAAS,CAAC,CAAC,CAAC,oBAAC,IAAI,IAAC,KAAK,EAAC,KAAK,gBAAiB,CAAC,CAAC,CAAC,oBAAC,IAAI,IAAC,KAAK,EAAC,MAAM,gBAAiB,CAAO,CAC1G,CACP,CAAA;AAED,OAAO,EAAC,2BAA2B,EAAC,CAAA","sourcesContent":["import {TextInput} from './TextInput.js'\nimport {InlineToken, TokenItem, TokenizedText} from './TokenizedText.js'\nimport {InfoTable, InfoTableProps} from './Prompts/InfoTable.js'\nimport {handleCtrlC} from '../../ui.js'\nimport useLayout from '../hooks/use-layout.js'\nimport {messageWithPunctuation} from '../utilities.js'\nimport {AbortSignal} from '../../../../public/node/abort.js'\nimport useAbortSignal from '../hooks/use-abort-signal.js'\nimport usePrompt, {PromptState} from '../hooks/use-prompt.js'\n\nimport React, {FunctionComponent, useCallback, useEffect, useState} from 'react'\nimport {Box, useApp, useInput, Text} from 'ink'\nimport figures from 'figures'\n\nexport interface DangerousConfirmationPromptProps {\n message: string\n confirmation: string\n infoTable?: InfoTableProps['table']\n onSubmit: (value: boolean) => void\n abortSignal?: AbortSignal\n}\n\nconst DangerousConfirmationPrompt: FunctionComponent<DangerousConfirmationPromptProps> = ({\n message,\n confirmation,\n infoTable,\n onSubmit,\n abortSignal,\n}) => {\n const validateAnswer = useCallback(\n (value: string): TokenItem<InlineToken> | undefined => {\n return value === confirmation ? undefined : ['Value must be exactly', {userInput: confirmation}]\n },\n [confirmation],\n )\n\n const {oneThird, twoThirds} = useLayout()\n const {promptState, setPromptState, answer, setAnswer} = usePrompt<string>({\n initialAnswer: '',\n })\n const {exit: unmountInk} = useApp()\n const [error, setError] = useState<TokenItem<InlineToken> | undefined>(undefined)\n const color = promptState === PromptState.Error ? 'red' : 'cyan'\n const underline = new Array(oneThird - 3).fill('▔')\n const {isAborted} = useAbortSignal(abortSignal)\n\n useInput((input, key) => {\n handleCtrlC(input, key)\n\n if (key.escape) {\n setPromptState(PromptState.Cancelled)\n setError(undefined)\n }\n\n if (key.return) {\n const error = validateAnswer(answer)\n\n if (error) {\n setPromptState(PromptState.Error)\n setError(error)\n } else {\n setPromptState(PromptState.Submitted)\n }\n }\n })\n\n useEffect(() => {\n if (promptState === PromptState.Submitted) {\n onSubmit(true)\n unmountInk()\n } else if (promptState === PromptState.Cancelled) {\n onSubmit(false)\n unmountInk()\n }\n }, [onSubmit, promptState, unmountInk])\n\n const completed = promptState === PromptState.Submitted || promptState === PromptState.Cancelled\n\n return isAborted ? null : (\n <Box flexDirection=\"column\" marginBottom={1} width={twoThirds}>\n <Box>\n <Box marginRight={2}>\n <Text>?</Text>\n </Box>\n <TokenizedText item={messageWithPunctuation(message)} />\n </Box>\n {completed ? (\n <CompletedPrompt {...{cancelled: promptState === PromptState.Cancelled}} />\n ) : (\n <>\n <Box flexDirection=\"column\" gap={1} marginTop={1} marginLeft={3}>\n {infoTable ? (\n <Box\n paddingLeft={2}\n borderStyle=\"bold\"\n borderLeft\n borderRight={false}\n borderTop={false}\n borderBottom={false}\n flexDirection=\"column\"\n gap={1}\n >\n <InfoTable table={infoTable} />\n </Box>\n ) : null}\n <Box>\n <TokenizedText item={['Type', {userInput: confirmation}, 'to confirm, or press Escape to cancel.']} />\n </Box>\n </Box>\n <Box flexDirection=\"column\" width={oneThird}>\n <Box>\n <Box marginRight={2}>\n <Text color={color}>{`>`}</Text>\n </Box>\n <Box flexGrow={1}>\n <TextInput\n value={answer}\n onChange={(answer) => {\n setAnswer(answer)\n setPromptState(PromptState.Idle)\n }}\n defaultValue=\"\"\n color={color}\n />\n </Box>\n </Box>\n <Box marginLeft={3}>\n <Text color={color}>{underline}</Text>\n </Box>\n {promptState === PromptState.Error && error ? (\n <Box marginLeft={3}>\n <Text color={color}>\n <TokenizedText item={error} />\n </Text>\n </Box>\n ) : null}\n </Box>\n </>\n )}\n </Box>\n )\n}\n\ninterface CompletedPromptProps {\n cancelled: boolean\n}\n\nconst CompletedPrompt: FunctionComponent<CompletedPromptProps> = ({cancelled}) => (\n <Box>\n <Box width={3}>\n {cancelled ? <Text color=\"red\">{figures.cross}</Text> : <Text color=\"cyan\">{figures.tick}</Text>}\n </Box>\n\n <Box flexGrow={1}>{cancelled ? <Text color=\"red\">Cancelled</Text> : <Text color=\"cyan\">Confirmed</Text>}</Box>\n </Box>\n)\n\nexport {DangerousConfirmationPrompt}\n"]}
1
+ {"version":3,"file":"DangerousConfirmationPrompt.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/DangerousConfirmationPrompt.tsx"],"names":[],"mappings":"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","sourcesContent":["import {TextInput} from './TextInput.js'\nimport {InlineToken, TokenItem, TokenizedText} from './TokenizedText.js'\nimport {InfoTable, InfoTableProps} from './Prompts/InfoTable.js'\nimport {handleCtrlC, useComplete} from '../../ui.js'\nimport useLayout from '../hooks/use-layout.js'\nimport {messageWithPunctuation} from '../utilities.js'\nimport {AbortSignal} from '../../../../public/node/abort.js'\nimport useAbortSignal from '../hooks/use-abort-signal.js'\nimport usePrompt, {PromptState} from '../hooks/use-prompt.js'\n\nimport React, {FunctionComponent, useCallback, useEffect, useState} from 'react'\nimport {Box, useInput, Text} from 'ink'\nimport figures from 'figures'\n\nexport interface DangerousConfirmationPromptProps {\n message: string\n confirmation: string\n infoTable?: InfoTableProps['table']\n warningItem?: TokenItem<InlineToken>\n onSubmit: (value: boolean) => void\n abortSignal?: AbortSignal\n}\n\nconst DangerousConfirmationPrompt: FunctionComponent<DangerousConfirmationPromptProps> = ({\n message,\n confirmation,\n infoTable,\n warningItem,\n onSubmit,\n abortSignal,\n}) => {\n const validateAnswer = useCallback(\n (value: string): TokenItem<InlineToken> | undefined => {\n return value === confirmation ? undefined : ['Value must be exactly', {userInput: confirmation}]\n },\n [confirmation],\n )\n\n const {oneThird, twoThirds} = useLayout()\n const {promptState, setPromptState, answer, setAnswer} = usePrompt<string>({\n initialAnswer: '',\n })\n const complete = useComplete()\n const [error, setError] = useState<TokenItem<InlineToken> | undefined>(undefined)\n const color = promptState === PromptState.Error ? 'red' : 'cyan'\n const underline = new Array(oneThird - 3).fill('▔')\n const {isAborted} = useAbortSignal(abortSignal)\n\n useInput((input, key) => {\n handleCtrlC(input, key)\n\n if (key.escape) {\n setPromptState(PromptState.Cancelled)\n setError(undefined)\n }\n\n if (key.return) {\n const error = validateAnswer(answer)\n\n if (error) {\n setPromptState(PromptState.Error)\n setError(error)\n } else {\n setPromptState(PromptState.Submitted)\n }\n }\n })\n\n useEffect(() => {\n if (promptState === PromptState.Submitted) {\n onSubmit(true)\n complete()\n } else if (promptState === PromptState.Cancelled) {\n onSubmit(false)\n complete()\n }\n }, [onSubmit, promptState, complete])\n\n const completed = promptState === PromptState.Submitted || promptState === PromptState.Cancelled\n\n return isAborted ? null : (\n <Box flexDirection=\"column\" marginBottom={1} width={twoThirds}>\n <Box>\n <Box marginRight={2}>\n <Text>?</Text>\n </Box>\n <TokenizedText item={messageWithPunctuation(message)} />\n </Box>\n {completed ? (\n <CompletedPrompt {...{cancelled: promptState === PromptState.Cancelled}} />\n ) : (\n <>\n <Box flexDirection=\"column\" gap={1} marginTop={1} marginLeft={3}>\n {infoTable ? (\n <Box\n paddingLeft={2}\n borderStyle=\"bold\"\n borderLeft\n borderRight={false}\n borderTop={false}\n borderBottom={false}\n flexDirection=\"column\"\n gap={1}\n >\n <InfoTable table={infoTable} />\n </Box>\n ) : null}\n {warningItem ? (\n <Box flexDirection=\"column\">\n <Text color=\"red\">{figures.warning} WARNING</Text>\n <TokenizedText item={warningItem} />\n </Box>\n ) : null}\n <Box>\n <TokenizedText item={['Type', {userInput: confirmation}, 'to confirm, or press Escape to cancel.']} />\n </Box>\n </Box>\n <Box flexDirection=\"column\" width={oneThird}>\n <Box>\n <Box marginRight={2}>\n <Text color={color}>{`>`}</Text>\n </Box>\n <Box flexGrow={1}>\n <TextInput\n value={answer}\n onChange={(answer) => {\n setAnswer(answer)\n setPromptState(PromptState.Idle)\n }}\n defaultValue=\"\"\n color={color}\n />\n </Box>\n </Box>\n <Box marginLeft={3}>\n <Text color={color}>{underline}</Text>\n </Box>\n {promptState === PromptState.Error && error ? (\n <Box marginLeft={3}>\n <Text color={color}>\n <TokenizedText item={error} />\n </Text>\n </Box>\n ) : null}\n </Box>\n </>\n )}\n </Box>\n )\n}\n\ninterface CompletedPromptProps {\n cancelled: boolean\n}\n\nconst CompletedPrompt: FunctionComponent<CompletedPromptProps> = ({cancelled}) => (\n <Box>\n <Box width={3}>\n {cancelled ? <Text color=\"red\">{figures.cross}</Text> : <Text color=\"cyan\">{figures.tick}</Text>}\n </Box>\n\n <Box flexGrow={1}>{cancelled ? <Text color=\"red\">Cancelled</Text> : <Text color=\"cyan\">Confirmed</Text>}</Box>\n </Box>\n)\n\nexport {DangerousConfirmationPrompt}\n"]}
@@ -2,17 +2,24 @@ import { TextAnimation } from './TextAnimation.js';
2
2
  import useLayout from '../hooks/use-layout.js';
3
3
  import { shouldDisplayColors } from '../../../../public/node/output.js';
4
4
  import React from 'react';
5
- import { Box, Text } from 'ink';
5
+ import { Box, Text, useStdout } from 'ink';
6
6
  const loadingBarChar = '▀';
7
7
  const hillString = '▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁';
8
8
  const LoadingBar = ({ title, noColor, noProgressBar }) => {
9
9
  const { twoThirds } = useLayout();
10
+ const { stdout } = useStdout();
11
+ // On real Node streams, isTTY is only present as an own property when the
12
+ // stream IS a TTY. When Ink's output stream is not a TTY (e.g. AI agents
13
+ // capturing stderr via 2>&1), the animated progress bar can't overwrite
14
+ // previous frames and would flood the output. Show only the static title
15
+ // in that case.
16
+ const isTTY = Boolean(stdout.isTTY);
10
17
  let loadingBar = new Array(twoThirds).fill(loadingBarChar).join('');
11
18
  if (noColor ?? !shouldDisplayColors()) {
12
19
  loadingBar = hillString.repeat(Math.ceil(twoThirds / hillString.length));
13
20
  }
14
21
  return (React.createElement(Box, { flexDirection: "column" },
15
- !noProgressBar && React.createElement(TextAnimation, { text: loadingBar, maxWidth: twoThirds }),
22
+ isTTY && !noProgressBar && React.createElement(TextAnimation, { text: loadingBar, maxWidth: twoThirds }),
16
23
  React.createElement(Text, null,
17
24
  title,
18
25
  " ...")));
@@ -1 +1 @@
1
- {"version":3,"file":"LoadingBar.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/LoadingBar.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,aAAa,EAAC,MAAM,oBAAoB,CAAA;AAChD,OAAO,SAAS,MAAM,wBAAwB,CAAA;AAC9C,OAAO,EAAC,mBAAmB,EAAC,MAAM,mCAAmC,CAAA;AACrE,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,EAAC,GAAG,EAAE,IAAI,EAAC,MAAM,KAAK,CAAA;AAE7B,MAAM,cAAc,GAAG,GAAG,CAAA;AAC1B,MAAM,UAAU,GAAG,gCAAgC,CAAA;AAQnD,MAAM,UAAU,GAAG,CAAC,EAAC,KAAK,EAAE,OAAO,EAAE,aAAa,EAA2C,EAAE,EAAE;IAC/F,MAAM,EAAC,SAAS,EAAC,GAAG,SAAS,EAAE,CAAA;IAC/B,IAAI,UAAU,GAAG,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IACnE,IAAI,OAAO,IAAI,CAAC,mBAAmB,EAAE,EAAE,CAAC;QACtC,UAAU,GAAG,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAA;IAC1E,CAAC;IAED,OAAO,CACL,oBAAC,GAAG,IAAC,aAAa,EAAC,QAAQ;QACxB,CAAC,aAAa,IAAI,oBAAC,aAAa,IAAC,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,GAAI;QAC3E,oBAAC,IAAI;YAAE,KAAK;mBAAY,CACpB,CACP,CAAA;AACH,CAAC,CAAA;AAED,OAAO,EAAC,UAAU,EAAC,CAAA","sourcesContent":["import {TextAnimation} from './TextAnimation.js'\nimport useLayout from '../hooks/use-layout.js'\nimport {shouldDisplayColors} from '../../../../public/node/output.js'\nimport React from 'react'\n\nimport {Box, Text} from 'ink'\n\nconst loadingBarChar = '▀'\nconst hillString = '▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁'\n\ninterface LoadingBarProps {\n title: string\n noColor?: boolean\n noProgressBar?: boolean\n}\n\nconst LoadingBar = ({title, noColor, noProgressBar}: React.PropsWithChildren<LoadingBarProps>) => {\n const {twoThirds} = useLayout()\n let loadingBar = new Array(twoThirds).fill(loadingBarChar).join('')\n if (noColor ?? !shouldDisplayColors()) {\n loadingBar = hillString.repeat(Math.ceil(twoThirds / hillString.length))\n }\n\n return (\n <Box flexDirection=\"column\">\n {!noProgressBar && <TextAnimation text={loadingBar} maxWidth={twoThirds} />}\n <Text>{title} ...</Text>\n </Box>\n )\n}\n\nexport {LoadingBar}\n"]}
1
+ {"version":3,"file":"LoadingBar.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/LoadingBar.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,aAAa,EAAC,MAAM,oBAAoB,CAAA;AAChD,OAAO,SAAS,MAAM,wBAAwB,CAAA;AAC9C,OAAO,EAAC,mBAAmB,EAAC,MAAM,mCAAmC,CAAA;AACrE,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,EAAC,GAAG,EAAE,IAAI,EAAE,SAAS,EAAC,MAAM,KAAK,CAAA;AAExC,MAAM,cAAc,GAAG,GAAG,CAAA;AAC1B,MAAM,UAAU,GAAG,gCAAgC,CAAA;AAQnD,MAAM,UAAU,GAAG,CAAC,EAAC,KAAK,EAAE,OAAO,EAAE,aAAa,EAA2C,EAAE,EAAE;IAC/F,MAAM,EAAC,SAAS,EAAC,GAAG,SAAS,EAAE,CAAA;IAC/B,MAAM,EAAC,MAAM,EAAC,GAAG,SAAS,EAAE,CAAA;IAE5B,0EAA0E;IAC1E,0EAA0E;IAC1E,wEAAwE;IACxE,0EAA0E;IAC1E,gBAAgB;IAChB,MAAM,KAAK,GAAG,OAAO,CAAE,MAA6C,CAAC,KAAK,CAAC,CAAA;IAE3E,IAAI,UAAU,GAAG,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IACnE,IAAI,OAAO,IAAI,CAAC,mBAAmB,EAAE,EAAE,CAAC;QACtC,UAAU,GAAG,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAA;IAC1E,CAAC;IAED,OAAO,CACL,oBAAC,GAAG,IAAC,aAAa,EAAC,QAAQ;QACxB,KAAK,IAAI,CAAC,aAAa,IAAI,oBAAC,aAAa,IAAC,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,GAAI;QACpF,oBAAC,IAAI;YAAE,KAAK;mBAAY,CACpB,CACP,CAAA;AACH,CAAC,CAAA;AAED,OAAO,EAAC,UAAU,EAAC,CAAA","sourcesContent":["import {TextAnimation} from './TextAnimation.js'\nimport useLayout from '../hooks/use-layout.js'\nimport {shouldDisplayColors} from '../../../../public/node/output.js'\nimport React from 'react'\n\nimport {Box, Text, useStdout} from 'ink'\n\nconst loadingBarChar = '▀'\nconst hillString = '▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁'\n\ninterface LoadingBarProps {\n title: string\n noColor?: boolean\n noProgressBar?: boolean\n}\n\nconst LoadingBar = ({title, noColor, noProgressBar}: React.PropsWithChildren<LoadingBarProps>) => {\n const {twoThirds} = useLayout()\n const {stdout} = useStdout()\n\n // On real Node streams, isTTY is only present as an own property when the\n // stream IS a TTY. When Ink's output stream is not a TTY (e.g. AI agents\n // capturing stderr via 2>&1), the animated progress bar can't overwrite\n // previous frames and would flood the output. Show only the static title\n // in that case.\n const isTTY = Boolean((stdout as unknown as Record<string, unknown>).isTTY)\n\n let loadingBar = new Array(twoThirds).fill(loadingBarChar).join('')\n if (noColor ?? !shouldDisplayColors()) {\n loadingBar = hillString.repeat(Math.ceil(twoThirds / hillString.length))\n }\n\n return (\n <Box flexDirection=\"column\">\n {isTTY && !noProgressBar && <TextAnimation text={loadingBar} maxWidth={twoThirds} />}\n <Text>{title} ...</Text>\n </Box>\n )\n}\n\nexport {LoadingBar}\n"]}
@@ -1,4 +1,5 @@
1
1
  import { LoadingBar } from './LoadingBar.js';
2
+ import { Stdout } from '../../ui.js';
2
3
  import { render } from '../../testing/ui.js';
3
4
  import { shouldDisplayColors, unstyled } from '../../../../public/node/output.js';
4
5
  import useLayout from '../hooks/use-layout.js';
@@ -13,7 +14,6 @@ vi.mock('../../../../public/node/output.js', async () => {
13
14
  };
14
15
  });
15
16
  beforeEach(() => {
16
- // Default terminal width
17
17
  vi.mocked(useLayout).mockReturnValue({
18
18
  twoThirds: 53,
19
19
  oneThird: 27,
@@ -21,162 +21,123 @@ beforeEach(() => {
21
21
  });
22
22
  vi.mocked(shouldDisplayColors).mockReturnValue(true);
23
23
  });
24
+ /**
25
+ * Creates a Stdout test double simulating a TTY stream.
26
+ * On real Node streams, isTTY is only present as an own property when the
27
+ * stream IS a TTY.
28
+ */
29
+ function createTTYStdout(columns = 100) {
30
+ const stdout = new Stdout({ columns });
31
+ stdout.isTTY = true;
32
+ return stdout;
33
+ }
34
+ /**
35
+ * Renders LoadingBar with a TTY stdout so the animated progress bar renders.
36
+ */
37
+ function renderWithTTY(element) {
38
+ const stdout = createTTYStdout();
39
+ const instance = render(element, { stdout });
40
+ return { lastFrame: stdout.lastFrame, unmount: instance.unmount };
41
+ }
24
42
  describe('LoadingBar', () => {
25
43
  test('renders loading bar with default colored characters', async () => {
26
- // Given
27
- const title = 'Loading content';
28
- // When
29
- const { lastFrame } = render(React.createElement(LoadingBar, { title: title }));
30
- // Then
44
+ const { lastFrame } = renderWithTTY(React.createElement(LoadingBar, { title: "Loading content" }));
31
45
  expect(unstyled(lastFrame())).toMatchInlineSnapshot(`
32
46
  "▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
33
47
  Loading content ..."
34
48
  `);
35
49
  });
36
50
  test('renders loading bar with hill pattern when noColor prop is true', async () => {
37
- // Given
38
- const title = 'Processing files';
39
- // When
40
- const { lastFrame } = render(React.createElement(LoadingBar, { title: title, noColor: true }));
41
- // Then
51
+ const { lastFrame } = renderWithTTY(React.createElement(LoadingBar, { title: "Processing files", noColor: true }));
42
52
  expect(unstyled(lastFrame())).toMatchInlineSnapshot(`
43
53
  "▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅
44
54
  Processing files ..."
45
55
  `);
46
56
  });
47
57
  test('renders loading bar with hill pattern when shouldDisplayColors returns false', async () => {
48
- // Given
49
58
  vi.mocked(shouldDisplayColors).mockReturnValue(false);
50
- const title = 'Downloading packages';
51
- // When
52
- const { lastFrame } = render(React.createElement(LoadingBar, { title: title }));
53
- // Then
59
+ const { lastFrame } = renderWithTTY(React.createElement(LoadingBar, { title: "Downloading packages" }));
54
60
  expect(unstyled(lastFrame())).toMatchInlineSnapshot(`
55
61
  "▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅
56
62
  Downloading packages ..."
57
63
  `);
58
64
  });
59
65
  test('handles narrow terminal width correctly', async () => {
60
- // Given
61
- vi.mocked(useLayout).mockReturnValue({
62
- twoThirds: 20,
63
- oneThird: 10,
64
- fullWidth: 30,
65
- });
66
- const title = 'Building app';
67
- // When
68
- const { lastFrame } = render(React.createElement(LoadingBar, { title: title }));
69
- // Then
66
+ vi.mocked(useLayout).mockReturnValue({ twoThirds: 20, oneThird: 10, fullWidth: 30 });
67
+ const { lastFrame } = renderWithTTY(React.createElement(LoadingBar, { title: "Building app" }));
70
68
  expect(unstyled(lastFrame())).toMatchInlineSnapshot(`
71
69
  "▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
72
70
  Building app ..."
73
71
  `);
74
72
  });
75
73
  test('handles narrow terminal width correctly in no-color mode', async () => {
76
- // Given
77
- vi.mocked(useLayout).mockReturnValue({
78
- twoThirds: 15,
79
- oneThird: 8,
80
- fullWidth: 23,
81
- });
82
- const title = 'Installing';
83
- // When
84
- const { lastFrame } = render(React.createElement(LoadingBar, { title: title, noColor: true }));
85
- // Then
74
+ vi.mocked(useLayout).mockReturnValue({ twoThirds: 15, oneThird: 8, fullWidth: 23 });
75
+ const { lastFrame } = renderWithTTY(React.createElement(LoadingBar, { title: "Installing", noColor: true }));
86
76
  expect(unstyled(lastFrame())).toMatchInlineSnapshot(`
87
77
  "▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇
88
78
  Installing ..."
89
79
  `);
90
80
  });
91
81
  test('handles very narrow terminal width in no-color mode', async () => {
92
- // Given
93
- vi.mocked(useLayout).mockReturnValue({
94
- twoThirds: 5,
95
- oneThird: 3,
96
- fullWidth: 8,
97
- });
98
- const title = 'Wait';
99
- // When
100
- const { lastFrame } = render(React.createElement(LoadingBar, { title: title, noColor: true }));
101
- // Then
82
+ vi.mocked(useLayout).mockReturnValue({ twoThirds: 5, oneThird: 3, fullWidth: 8 });
83
+ const { lastFrame } = renderWithTTY(React.createElement(LoadingBar, { title: "Wait", noColor: true }));
102
84
  expect(unstyled(lastFrame())).toMatchInlineSnapshot(`
103
85
  "▁▁▁▂▂
104
86
  Wait ..."
105
87
  `);
106
88
  });
107
89
  test('handles wide terminal width correctly', async () => {
108
- // Given
109
- vi.mocked(useLayout).mockReturnValue({
110
- twoThirds: 100,
111
- oneThird: 50,
112
- fullWidth: 150,
113
- });
114
- const title = 'Synchronizing data';
115
- // When
116
- const { lastFrame } = render(React.createElement(LoadingBar, { title: title }));
117
- // Then
90
+ vi.mocked(useLayout).mockReturnValue({ twoThirds: 100, oneThird: 50, fullWidth: 150 });
91
+ const { lastFrame } = renderWithTTY(React.createElement(LoadingBar, { title: "Synchronizing data" }));
118
92
  expect(unstyled(lastFrame())).toMatchInlineSnapshot(`
119
93
  "▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
120
94
  Synchronizing data ..."
121
95
  `);
122
96
  });
123
97
  test('handles wide terminal width correctly in no-color mode with pattern repetition', async () => {
124
- // Given
125
- vi.mocked(useLayout).mockReturnValue({
126
- twoThirds: 90,
127
- oneThird: 45,
128
- fullWidth: 135,
129
- });
130
- const title = 'Analyzing dependencies';
131
- // When
132
- const { lastFrame } = render(React.createElement(LoadingBar, { title: title, noColor: true }));
133
- // Then
98
+ vi.mocked(useLayout).mockReturnValue({ twoThirds: 90, oneThird: 45, fullWidth: 135 });
99
+ const { lastFrame } = renderWithTTY(React.createElement(LoadingBar, { title: "Analyzing dependencies", noColor: true }));
134
100
  expect(unstyled(lastFrame())).toMatchInlineSnapshot(`
135
101
  "▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁
136
102
  Analyzing dependencies ..."
137
103
  `);
138
104
  });
139
105
  test('renders correctly with empty title', async () => {
140
- // Given
141
- const title = '';
142
- // When
143
- const { lastFrame } = render(React.createElement(LoadingBar, { title: title }));
144
- // Then
106
+ const { lastFrame } = renderWithTTY(React.createElement(LoadingBar, { title: "" }));
145
107
  expect(unstyled(lastFrame())).toMatchInlineSnapshot(`
146
108
  "▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
147
109
  ..."
148
110
  `);
149
111
  });
150
112
  test('noColor prop overrides shouldDisplayColors when both would show colors', async () => {
151
- // Given
152
113
  vi.mocked(shouldDisplayColors).mockReturnValue(true);
153
- const title = 'Testing override';
154
- // When
155
- const { lastFrame } = render(React.createElement(LoadingBar, { title: title, noColor: true }));
156
- // Then
114
+ const { lastFrame } = renderWithTTY(React.createElement(LoadingBar, { title: "Testing override", noColor: true }));
157
115
  expect(unstyled(lastFrame())).toMatchInlineSnapshot(`
158
116
  "▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅
159
117
  Testing override ..."
160
118
  `);
161
119
  });
162
120
  test('renders consistently with same props', async () => {
163
- // Given
164
- const title = 'Consistent test';
165
- const props = { title, noColor: false };
166
- // When
167
- const { lastFrame: frame1 } = render(React.createElement(LoadingBar, { ...props }));
168
- const { lastFrame: frame2 } = render(React.createElement(LoadingBar, { ...props }));
169
- // Then
121
+ const props = { title: 'Consistent test', noColor: false };
122
+ const { lastFrame: frame1 } = renderWithTTY(React.createElement(LoadingBar, { ...props }));
123
+ const { lastFrame: frame2 } = renderWithTTY(React.createElement(LoadingBar, { ...props }));
170
124
  expect(frame1()).toBe(frame2());
171
125
  });
172
126
  test('hides progress bar when noProgressBar is true', async () => {
173
- // Given
174
127
  vi.mocked(shouldDisplayColors).mockReturnValue(true);
175
- const title = 'task 1';
176
- // When
177
- const { lastFrame } = render(React.createElement(LoadingBar, { title: title, noProgressBar: true }));
178
- // Then
128
+ const { lastFrame } = renderWithTTY(React.createElement(LoadingBar, { title: "task 1", noProgressBar: true }));
179
129
  expect(unstyled(lastFrame())).toMatchInlineSnapshot(`"task 1 ..."`);
180
130
  });
131
+ test('shows only static title text when output stream is not a TTY', async () => {
132
+ // Default test Stdout has no isTTY property, simulating a non-TTY stream
133
+ const { lastFrame } = render(React.createElement(LoadingBar, { title: "Installing dependencies" }));
134
+ expect(unstyled(lastFrame())).toMatchInlineSnapshot(`"Installing dependencies ..."`);
135
+ });
136
+ test('shows animated progress bar when output stream is a TTY', async () => {
137
+ const { lastFrame } = renderWithTTY(React.createElement(LoadingBar, { title: "Uploading theme" }));
138
+ const frame = unstyled(lastFrame());
139
+ expect(frame).toContain('▀');
140
+ expect(frame).toContain('Uploading theme ...');
141
+ });
181
142
  });
182
143
  //# sourceMappingURL=LoadingBar.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"LoadingBar.test.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/LoadingBar.test.tsx"],"names":[],"mappings":"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","sourcesContent":["import {LoadingBar} from './LoadingBar.js'\nimport {render} from '../../testing/ui.js'\nimport {shouldDisplayColors, unstyled} from '../../../../public/node/output.js'\nimport useLayout from '../hooks/use-layout.js'\nimport React from 'react'\n\nimport {beforeEach, describe, expect, test, vi} from 'vitest'\n\nvi.mock('../hooks/use-layout.js')\nvi.mock('../../../../public/node/output.js', async () => {\n const original: any = await vi.importActual('../../../../public/node/output.js')\n return {\n ...original,\n shouldDisplayColors: vi.fn(),\n }\n})\n\nbeforeEach(() => {\n // Default terminal width\n vi.mocked(useLayout).mockReturnValue({\n twoThirds: 53,\n oneThird: 27,\n fullWidth: 80,\n })\n vi.mocked(shouldDisplayColors).mockReturnValue(true)\n})\n\ndescribe('LoadingBar', () => {\n test('renders loading bar with default colored characters', async () => {\n // Given\n const title = 'Loading content'\n\n // When\n const {lastFrame} = render(<LoadingBar title={title} />)\n\n // Then\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀\n Loading content ...\"\n `)\n })\n\n test('renders loading bar with hill pattern when noColor prop is true', async () => {\n // Given\n const title = 'Processing files'\n\n // When\n const {lastFrame} = render(<LoadingBar title={title} noColor />)\n\n // Then\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅\n Processing files ...\"\n `)\n })\n\n test('renders loading bar with hill pattern when shouldDisplayColors returns false', async () => {\n // Given\n vi.mocked(shouldDisplayColors).mockReturnValue(false)\n const title = 'Downloading packages'\n\n // When\n const {lastFrame} = render(<LoadingBar title={title} />)\n\n // Then\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅\n Downloading packages ...\"\n `)\n })\n\n test('handles narrow terminal width correctly', async () => {\n // Given\n vi.mocked(useLayout).mockReturnValue({\n twoThirds: 20,\n oneThird: 10,\n fullWidth: 30,\n })\n const title = 'Building app'\n\n // When\n const {lastFrame} = render(<LoadingBar title={title} />)\n\n // Then\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀\n Building app ...\"\n `)\n })\n\n test('handles narrow terminal width correctly in no-color mode', async () => {\n // Given\n vi.mocked(useLayout).mockReturnValue({\n twoThirds: 15,\n oneThird: 8,\n fullWidth: 23,\n })\n const title = 'Installing'\n\n // When\n const {lastFrame} = render(<LoadingBar title={title} noColor />)\n\n // Then\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇\n Installing ...\"\n `)\n })\n\n test('handles very narrow terminal width in no-color mode', async () => {\n // Given\n vi.mocked(useLayout).mockReturnValue({\n twoThirds: 5,\n oneThird: 3,\n fullWidth: 8,\n })\n const title = 'Wait'\n\n // When\n const {lastFrame} = render(<LoadingBar title={title} noColor />)\n\n // Then\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"▁▁▁▂▂\n Wait ...\"\n `)\n })\n\n test('handles wide terminal width correctly', async () => {\n // Given\n vi.mocked(useLayout).mockReturnValue({\n twoThirds: 100,\n oneThird: 50,\n fullWidth: 150,\n })\n const title = 'Synchronizing data'\n\n // When\n const {lastFrame} = render(<LoadingBar title={title} />)\n\n // Then\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀\n Synchronizing data ...\"\n `)\n })\n\n test('handles wide terminal width correctly in no-color mode with pattern repetition', async () => {\n // Given\n vi.mocked(useLayout).mockReturnValue({\n twoThirds: 90,\n oneThird: 45,\n fullWidth: 135,\n })\n const title = 'Analyzing dependencies'\n\n // When\n const {lastFrame} = render(<LoadingBar title={title} noColor />)\n\n // Then\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁\n Analyzing dependencies ...\"\n `)\n })\n\n test('renders correctly with empty title', async () => {\n // Given\n const title = ''\n\n // When\n const {lastFrame} = render(<LoadingBar title={title} />)\n\n // Then\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀\n ...\"\n `)\n })\n\n test('noColor prop overrides shouldDisplayColors when both would show colors', async () => {\n // Given\n vi.mocked(shouldDisplayColors).mockReturnValue(true)\n const title = 'Testing override'\n\n // When\n const {lastFrame} = render(<LoadingBar title={title} noColor />)\n\n // Then\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅\n Testing override ...\"\n `)\n })\n\n test('renders consistently with same props', async () => {\n // Given\n const title = 'Consistent test'\n const props = {title, noColor: false}\n\n // When\n const {lastFrame: frame1} = render(<LoadingBar {...props} />)\n const {lastFrame: frame2} = render(<LoadingBar {...props} />)\n\n // Then\n expect(frame1()).toBe(frame2())\n })\n\n test('hides progress bar when noProgressBar is true', async () => {\n // Given\n vi.mocked(shouldDisplayColors).mockReturnValue(true)\n const title = 'task 1'\n\n // When\n const {lastFrame} = render(<LoadingBar title={title} noProgressBar />)\n\n // Then\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\"task 1 ...\"`)\n })\n})\n"]}
1
+ {"version":3,"file":"LoadingBar.test.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/LoadingBar.test.tsx"],"names":[],"mappings":"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","sourcesContent":["import {LoadingBar} from './LoadingBar.js'\nimport {Stdout} from '../../ui.js'\nimport {render} from '../../testing/ui.js'\nimport {shouldDisplayColors, unstyled} from '../../../../public/node/output.js'\nimport useLayout from '../hooks/use-layout.js'\nimport React from 'react'\n\nimport {beforeEach, describe, expect, test, vi} from 'vitest'\n\nvi.mock('../hooks/use-layout.js')\nvi.mock('../../../../public/node/output.js', async () => {\n const original: any = await vi.importActual('../../../../public/node/output.js')\n return {\n ...original,\n shouldDisplayColors: vi.fn(),\n }\n})\n\nbeforeEach(() => {\n vi.mocked(useLayout).mockReturnValue({\n twoThirds: 53,\n oneThird: 27,\n fullWidth: 80,\n })\n vi.mocked(shouldDisplayColors).mockReturnValue(true)\n})\n\n/**\n * Creates a Stdout test double simulating a TTY stream.\n * On real Node streams, isTTY is only present as an own property when the\n * stream IS a TTY.\n */\nfunction createTTYStdout(columns = 100) {\n const stdout = new Stdout({columns}) as Stdout & {isTTY: boolean}\n stdout.isTTY = true\n return stdout\n}\n\n/**\n * Renders LoadingBar with a TTY stdout so the animated progress bar renders.\n */\nfunction renderWithTTY(element: React.ReactElement) {\n const stdout = createTTYStdout()\n const instance = render(element, {stdout})\n return {lastFrame: stdout.lastFrame, unmount: instance.unmount}\n}\n\ndescribe('LoadingBar', () => {\n test('renders loading bar with default colored characters', async () => {\n const {lastFrame} = renderWithTTY(<LoadingBar title=\"Loading content\" />)\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀\n Loading content ...\"\n `)\n })\n\n test('renders loading bar with hill pattern when noColor prop is true', async () => {\n const {lastFrame} = renderWithTTY(<LoadingBar title=\"Processing files\" noColor />)\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅\n Processing files ...\"\n `)\n })\n\n test('renders loading bar with hill pattern when shouldDisplayColors returns false', async () => {\n vi.mocked(shouldDisplayColors).mockReturnValue(false)\n const {lastFrame} = renderWithTTY(<LoadingBar title=\"Downloading packages\" />)\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅\n Downloading packages ...\"\n `)\n })\n\n test('handles narrow terminal width correctly', async () => {\n vi.mocked(useLayout).mockReturnValue({twoThirds: 20, oneThird: 10, fullWidth: 30})\n const {lastFrame} = renderWithTTY(<LoadingBar title=\"Building app\" />)\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀\n Building app ...\"\n `)\n })\n\n test('handles narrow terminal width correctly in no-color mode', async () => {\n vi.mocked(useLayout).mockReturnValue({twoThirds: 15, oneThird: 8, fullWidth: 23})\n const {lastFrame} = renderWithTTY(<LoadingBar title=\"Installing\" noColor />)\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇\n Installing ...\"\n `)\n })\n\n test('handles very narrow terminal width in no-color mode', async () => {\n vi.mocked(useLayout).mockReturnValue({twoThirds: 5, oneThird: 3, fullWidth: 8})\n const {lastFrame} = renderWithTTY(<LoadingBar title=\"Wait\" noColor />)\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"▁▁▁▂▂\n Wait ...\"\n `)\n })\n\n test('handles wide terminal width correctly', async () => {\n vi.mocked(useLayout).mockReturnValue({twoThirds: 100, oneThird: 50, fullWidth: 150})\n const {lastFrame} = renderWithTTY(<LoadingBar title=\"Synchronizing data\" />)\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀\n Synchronizing data ...\"\n `)\n })\n\n test('handles wide terminal width correctly in no-color mode with pattern repetition', async () => {\n vi.mocked(useLayout).mockReturnValue({twoThirds: 90, oneThird: 45, fullWidth: 135})\n const {lastFrame} = renderWithTTY(<LoadingBar title=\"Analyzing dependencies\" noColor />)\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁\n Analyzing dependencies ...\"\n `)\n })\n\n test('renders correctly with empty title', async () => {\n const {lastFrame} = renderWithTTY(<LoadingBar title=\"\" />)\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀\n ...\"\n `)\n })\n\n test('noColor prop overrides shouldDisplayColors when both would show colors', async () => {\n vi.mocked(shouldDisplayColors).mockReturnValue(true)\n const {lastFrame} = renderWithTTY(<LoadingBar title=\"Testing override\" noColor />)\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅\n Testing override ...\"\n `)\n })\n\n test('renders consistently with same props', async () => {\n const props = {title: 'Consistent test', noColor: false}\n const {lastFrame: frame1} = renderWithTTY(<LoadingBar {...props} />)\n const {lastFrame: frame2} = renderWithTTY(<LoadingBar {...props} />)\n\n expect(frame1()).toBe(frame2())\n })\n\n test('hides progress bar when noProgressBar is true', async () => {\n vi.mocked(shouldDisplayColors).mockReturnValue(true)\n const {lastFrame} = renderWithTTY(<LoadingBar title=\"task 1\" noProgressBar />)\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\"task 1 ...\"`)\n })\n\n test('shows only static title text when output stream is not a TTY', async () => {\n // Default test Stdout has no isTTY property, simulating a non-TTY stream\n const {lastFrame} = render(<LoadingBar title=\"Installing dependencies\" />)\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\"Installing dependencies ...\"`)\n })\n\n test('shows animated progress bar when output stream is a TTY', async () => {\n const {lastFrame} = renderWithTTY(<LoadingBar title=\"Uploading theme\" />)\n\n const frame = unstyled(lastFrame()!)\n expect(frame).toContain('▀')\n expect(frame).toContain('Uploading theme ...')\n })\n})\n"]}
@@ -1,13 +1,13 @@
1
1
  import { SelectInput } from './SelectInput.js';
2
2
  import { PromptLayout } from './Prompts/PromptLayout.js';
3
+ import { useComplete } from '../../ui.js';
3
4
  import usePrompt, { PromptState } from '../hooks/use-prompt.js';
4
5
  import React, { useCallback, useEffect } from 'react';
5
- import { useApp } from 'ink';
6
6
  function SelectPrompt({ message, choices, infoTable, infoMessage, onSubmit, defaultValue, abortSignal, groupOrder, }) {
7
7
  if (choices.length === 0) {
8
8
  throw new Error('SelectPrompt requires at least one choice');
9
9
  }
10
- const { exit: unmountInk } = useApp();
10
+ const complete = useComplete();
11
11
  const { promptState, setPromptState, answer, setAnswer } = usePrompt({
12
12
  initialAnswer: undefined,
13
13
  });
@@ -17,10 +17,10 @@ function SelectPrompt({ message, choices, infoTable, infoMessage, onSubmit, defa
17
17
  }, [setAnswer, setPromptState]);
18
18
  useEffect(() => {
19
19
  if (promptState === PromptState.Submitted && answer) {
20
- unmountInk();
21
20
  onSubmit(answer.value);
21
+ complete();
22
22
  }
23
- }, [answer, onSubmit, promptState, unmountInk]);
23
+ }, [answer, onSubmit, promptState, complete]);
24
24
  return (React.createElement(PromptLayout, { message: message, state: promptState, submittedAnswerLabel: answer?.label, infoTable: infoTable, infoMessage: infoMessage, abortSignal: abortSignal, input: React.createElement(SelectInput, { defaultValue: defaultValue, items: choices, onSubmit: submitAnswer, groupOrder: groupOrder }) }));
25
25
  }
26
26
  export { SelectPrompt };
@@ -1 +1 @@
1
- {"version":3,"file":"SelectPrompt.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/SelectPrompt.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,WAAW,EAAuC,MAAM,kBAAkB,CAAA;AAGlF,OAAO,EAAU,YAAY,EAAC,MAAM,2BAA2B,CAAA;AAE/D,OAAO,SAAS,EAAE,EAAC,WAAW,EAAC,MAAM,wBAAwB,CAAA;AAE7D,OAAO,KAAK,EAAE,EAAe,WAAW,EAAE,SAAS,EAAC,MAAM,OAAO,CAAA;AACjE,OAAO,EAAC,MAAM,EAAC,MAAM,KAAK,CAAA;AAa1B,SAAS,YAAY,CAAI,EACvB,OAAO,EACP,OAAO,EACP,SAAS,EACT,WAAW,EACX,QAAQ,EACR,YAAY,EACZ,WAAW,EACX,UAAU,GACoC;IAC9C,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAA;IAC9D,CAAC;IACD,MAAM,EAAC,IAAI,EAAE,UAAU,EAAC,GAAG,MAAM,EAAE,CAAA;IACnC,MAAM,EAAC,WAAW,EAAE,cAAc,EAAE,MAAM,EAAE,SAAS,EAAC,GAAG,SAAS,CAA4B;QAC5F,aAAa,EAAE,SAAS;KACzB,CAAC,CAAA;IAEF,MAAM,YAAY,GAAG,WAAW,CAC9B,CAAC,MAAqB,EAAE,EAAE;QACxB,SAAS,CAAC,MAAM,CAAC,CAAA;QACjB,cAAc,CAAC,WAAW,CAAC,SAAS,CAAC,CAAA;IACvC,CAAC,EACD,CAAC,SAAS,EAAE,cAAc,CAAC,CAC5B,CAAA;IAED,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,WAAW,KAAK,WAAW,CAAC,SAAS,IAAI,MAAM,EAAE,CAAC;YACpD,UAAU,EAAE,CAAA;YACZ,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QACxB,CAAC;IACH,CAAC,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,UAAU,CAAC,CAAC,CAAA;IAE/C,OAAO,CACL,oBAAC,YAAY,IACX,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,WAAW,EAClB,oBAAoB,EAAE,MAAM,EAAE,KAAK,EACnC,SAAS,EAAE,SAAS,EACpB,WAAW,EAAE,WAAW,EACxB,WAAW,EAAE,WAAW,EACxB,KAAK,EACH,oBAAC,WAAW,IAAC,YAAY,EAAE,YAAY,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,UAAU,EAAE,UAAU,GAAI,GAE7G,CACH,CAAA;AACH,CAAC;AAED,OAAO,EAAC,YAAY,EAAC,CAAA","sourcesContent":["import {SelectInput, SelectInputProps, Item as SelectItem} from './SelectInput.js'\nimport {InfoTableProps} from './Prompts/InfoTable.js'\nimport {InfoMessageProps} from './Prompts/InfoMessage.js'\nimport {Message, PromptLayout} from './Prompts/PromptLayout.js'\nimport {AbortSignal} from '../../../../public/node/abort.js'\nimport usePrompt, {PromptState} from '../hooks/use-prompt.js'\n\nimport React, {ReactElement, useCallback, useEffect} from 'react'\nimport {useApp} from 'ink'\n\nexport interface SelectPromptProps<T> {\n message: Message\n choices: SelectInputProps<T>['items']\n onSubmit: (value: T) => void\n infoTable?: InfoTableProps['table']\n defaultValue?: T\n abortSignal?: AbortSignal\n infoMessage?: InfoMessageProps['message']\n groupOrder?: string[]\n}\n\nfunction SelectPrompt<T>({\n message,\n choices,\n infoTable,\n infoMessage,\n onSubmit,\n defaultValue,\n abortSignal,\n groupOrder,\n}: React.PropsWithChildren<SelectPromptProps<T>>): ReactElement | null {\n if (choices.length === 0) {\n throw new Error('SelectPrompt requires at least one choice')\n }\n const {exit: unmountInk} = useApp()\n const {promptState, setPromptState, answer, setAnswer} = usePrompt<SelectItem<T> | undefined>({\n initialAnswer: undefined,\n })\n\n const submitAnswer = useCallback(\n (answer: SelectItem<T>) => {\n setAnswer(answer)\n setPromptState(PromptState.Submitted)\n },\n [setAnswer, setPromptState],\n )\n\n useEffect(() => {\n if (promptState === PromptState.Submitted && answer) {\n unmountInk()\n onSubmit(answer.value)\n }\n }, [answer, onSubmit, promptState, unmountInk])\n\n return (\n <PromptLayout\n message={message}\n state={promptState}\n submittedAnswerLabel={answer?.label}\n infoTable={infoTable}\n infoMessage={infoMessage}\n abortSignal={abortSignal}\n input={\n <SelectInput defaultValue={defaultValue} items={choices} onSubmit={submitAnswer} groupOrder={groupOrder} />\n }\n />\n )\n}\n\nexport {SelectPrompt}\n"]}
1
+ {"version":3,"file":"SelectPrompt.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/SelectPrompt.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,WAAW,EAAuC,MAAM,kBAAkB,CAAA;AAGlF,OAAO,EAAU,YAAY,EAAC,MAAM,2BAA2B,CAAA;AAE/D,OAAO,EAAC,WAAW,EAAC,MAAM,aAAa,CAAA;AACvC,OAAO,SAAS,EAAE,EAAC,WAAW,EAAC,MAAM,wBAAwB,CAAA;AAE7D,OAAO,KAAK,EAAE,EAAe,WAAW,EAAE,SAAS,EAAC,MAAM,OAAO,CAAA;AAajE,SAAS,YAAY,CAAI,EACvB,OAAO,EACP,OAAO,EACP,SAAS,EACT,WAAW,EACX,QAAQ,EACR,YAAY,EACZ,WAAW,EACX,UAAU,GACoC;IAC9C,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAA;IAC9D,CAAC;IACD,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAA;IAC9B,MAAM,EAAC,WAAW,EAAE,cAAc,EAAE,MAAM,EAAE,SAAS,EAAC,GAAG,SAAS,CAA4B;QAC5F,aAAa,EAAE,SAAS;KACzB,CAAC,CAAA;IAEF,MAAM,YAAY,GAAG,WAAW,CAC9B,CAAC,MAAqB,EAAE,EAAE;QACxB,SAAS,CAAC,MAAM,CAAC,CAAA;QACjB,cAAc,CAAC,WAAW,CAAC,SAAS,CAAC,CAAA;IACvC,CAAC,EACD,CAAC,SAAS,EAAE,cAAc,CAAC,CAC5B,CAAA;IAED,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,WAAW,KAAK,WAAW,CAAC,SAAS,IAAI,MAAM,EAAE,CAAC;YACpD,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;YACtB,QAAQ,EAAE,CAAA;QACZ,CAAC;IACH,CAAC,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC,CAAA;IAE7C,OAAO,CACL,oBAAC,YAAY,IACX,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,WAAW,EAClB,oBAAoB,EAAE,MAAM,EAAE,KAAK,EACnC,SAAS,EAAE,SAAS,EACpB,WAAW,EAAE,WAAW,EACxB,WAAW,EAAE,WAAW,EACxB,KAAK,EACH,oBAAC,WAAW,IAAC,YAAY,EAAE,YAAY,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,UAAU,EAAE,UAAU,GAAI,GAE7G,CACH,CAAA;AACH,CAAC;AAED,OAAO,EAAC,YAAY,EAAC,CAAA","sourcesContent":["import {SelectInput, SelectInputProps, Item as SelectItem} from './SelectInput.js'\nimport {InfoTableProps} from './Prompts/InfoTable.js'\nimport {InfoMessageProps} from './Prompts/InfoMessage.js'\nimport {Message, PromptLayout} from './Prompts/PromptLayout.js'\nimport {AbortSignal} from '../../../../public/node/abort.js'\nimport {useComplete} from '../../ui.js'\nimport usePrompt, {PromptState} from '../hooks/use-prompt.js'\n\nimport React, {ReactElement, useCallback, useEffect} from 'react'\n\nexport interface SelectPromptProps<T> {\n message: Message\n choices: SelectInputProps<T>['items']\n onSubmit: (value: T) => void\n infoTable?: InfoTableProps['table']\n defaultValue?: T\n abortSignal?: AbortSignal\n infoMessage?: InfoMessageProps['message']\n groupOrder?: string[]\n}\n\nfunction SelectPrompt<T>({\n message,\n choices,\n infoTable,\n infoMessage,\n onSubmit,\n defaultValue,\n abortSignal,\n groupOrder,\n}: React.PropsWithChildren<SelectPromptProps<T>>): ReactElement | null {\n if (choices.length === 0) {\n throw new Error('SelectPrompt requires at least one choice')\n }\n const complete = useComplete()\n const {promptState, setPromptState, answer, setAnswer} = usePrompt<SelectItem<T> | undefined>({\n initialAnswer: undefined,\n })\n\n const submitAnswer = useCallback(\n (answer: SelectItem<T>) => {\n setAnswer(answer)\n setPromptState(PromptState.Submitted)\n },\n [setAnswer, setPromptState],\n )\n\n useEffect(() => {\n if (promptState === PromptState.Submitted && answer) {\n onSubmit(answer.value)\n complete()\n }\n }, [answer, onSubmit, promptState, complete])\n\n return (\n <PromptLayout\n message={message}\n state={promptState}\n submittedAnswerLabel={answer?.label}\n infoTable={infoTable}\n infoMessage={infoMessage}\n abortSignal={abortSignal}\n input={\n <SelectInput defaultValue={defaultValue} items={choices} onSubmit={submitAnswer} groupOrder={groupOrder} />\n }\n />\n )\n}\n\nexport {SelectPrompt}\n"]}
@@ -1,11 +1,12 @@
1
1
  import { LoadingBar } from './LoadingBar.js';
2
- import { handleCtrlC } from '../../ui.js';
2
+ import { handleCtrlC, useComplete } from '../../ui.js';
3
3
  import React, { useEffect, useState } from 'react';
4
- import { useApp, useInput, useStdin } from 'ink';
4
+ import { useInput, useStdin } from 'ink';
5
5
  const SingleTask = ({ task, title, onComplete, onAbort, noColor }) => {
6
6
  const [status, setStatus] = useState(title);
7
7
  const [isDone, setIsDone] = useState(false);
8
- const { exit: unmountInk } = useApp();
8
+ const [taskResult, setTaskResult] = useState(null);
9
+ const complete = useComplete();
9
10
  const { isRawModeSupported } = useStdin();
10
11
  useInput((input, key) => {
11
12
  if (onAbort) {
@@ -20,13 +21,18 @@ const SingleTask = ({ task, title, onComplete, onAbort, noColor }) => {
20
21
  .then((result) => {
21
22
  setIsDone(true);
22
23
  onComplete?.(result);
23
- unmountInk();
24
+ setTaskResult({});
24
25
  })
25
26
  .catch((error) => {
26
27
  setIsDone(true);
27
- unmountInk(error);
28
+ setTaskResult({ error });
28
29
  });
29
- }, [task, unmountInk, onComplete]);
30
+ }, [task, onComplete]);
31
+ useEffect(() => {
32
+ if (taskResult !== null) {
33
+ complete(taskResult.error);
34
+ }
35
+ }, [taskResult, complete]);
30
36
  if (isDone) {
31
37
  // clear things once done
32
38
  return null;
@@ -1 +1 @@
1
- {"version":3,"file":"SingleTask.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/SingleTask.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAAC,MAAM,iBAAiB,CAAA;AAC1C,OAAO,EAAC,WAAW,EAAC,MAAM,aAAa,CAAA;AAEvC,OAAO,KAAK,EAAE,EAAC,SAAS,EAAE,QAAQ,EAAC,MAAM,OAAO,CAAA;AAEhD,OAAO,EAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAC,MAAM,KAAK,CAAA;AAU9C,MAAM,UAAU,GAAG,CAAK,EAAC,IAAI,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAAqB,EAAE,EAAE;IACzF,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAC3C,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAC3C,MAAM,EAAC,IAAI,EAAE,UAAU,EAAC,GAAG,MAAM,EAAE,CAAA;IACnC,MAAM,EAAC,kBAAkB,EAAC,GAAG,QAAQ,EAAE,CAAA;IAEvC,QAAQ,CACN,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QACb,IAAI,OAAO,EAAE,CAAC;YACZ,WAAW,CAAC,KAAK,EAAE,GAAG,EAAE,OAAO,CAAC,CAAA;QAClC,CAAC;aAAM,CAAC;YACN,WAAW,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;QACzB,CAAC;IACH,CAAC,EACD,EAAC,QAAQ,EAAE,OAAO,CAAC,kBAAkB,CAAC,EAAC,CACxC,CAAA;IAED,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,SAAS,CAAC;aACZ,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;YACf,SAAS,CAAC,IAAI,CAAC,CAAA;YACf,UAAU,EAAE,CAAC,MAAM,CAAC,CAAA;YACpB,UAAU,EAAE,CAAA;QACd,CAAC,CAAC;aACD,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;YACf,SAAS,CAAC,IAAI,CAAC,CAAA;YACf,UAAU,CAAC,KAAK,CAAC,CAAA;QACnB,CAAC,CAAC,CAAA;IACN,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC,CAAA;IAElC,IAAI,MAAM,EAAE,CAAC;QACX,yBAAyB;QACzB,OAAO,IAAI,CAAA;IACb,CAAC;IAED,OAAO,oBAAC,UAAU,IAAC,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,GAAI,CAAA;AAC9D,CAAC,CAAA;AAED,OAAO,EAAC,UAAU,EAAC,CAAA","sourcesContent":["import {LoadingBar} from './LoadingBar.js'\nimport {handleCtrlC} from '../../ui.js'\nimport {TokenizedString} from '../../../../public/node/output.js'\nimport React, {useEffect, useState} from 'react'\n\nimport {useApp, useInput, useStdin} from 'ink'\n\ninterface SingleTaskProps<T> {\n title: TokenizedString\n task: (updateStatus: (status: TokenizedString) => void) => Promise<T>\n onComplete?: (result: T) => void\n onAbort?: () => void\n noColor?: boolean\n}\n\nconst SingleTask = <T,>({task, title, onComplete, onAbort, noColor}: SingleTaskProps<T>) => {\n const [status, setStatus] = useState(title)\n const [isDone, setIsDone] = useState(false)\n const {exit: unmountInk} = useApp()\n const {isRawModeSupported} = useStdin()\n\n useInput(\n (input, key) => {\n if (onAbort) {\n handleCtrlC(input, key, onAbort)\n } else {\n handleCtrlC(input, key)\n }\n },\n {isActive: Boolean(isRawModeSupported)},\n )\n\n useEffect(() => {\n task(setStatus)\n .then((result) => {\n setIsDone(true)\n onComplete?.(result)\n unmountInk()\n })\n .catch((error) => {\n setIsDone(true)\n unmountInk(error)\n })\n }, [task, unmountInk, onComplete])\n\n if (isDone) {\n // clear things once done\n return null\n }\n\n return <LoadingBar title={status.value} noColor={noColor} />\n}\n\nexport {SingleTask}\n"]}
1
+ {"version":3,"file":"SingleTask.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/SingleTask.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAAC,MAAM,iBAAiB,CAAA;AAC1C,OAAO,EAAC,WAAW,EAAE,WAAW,EAAC,MAAM,aAAa,CAAA;AAEpD,OAAO,KAAK,EAAE,EAAC,SAAS,EAAE,QAAQ,EAAC,MAAM,OAAO,CAAA;AAEhD,OAAO,EAAC,QAAQ,EAAE,QAAQ,EAAC,MAAM,KAAK,CAAA;AAUtC,MAAM,UAAU,GAAG,CAAK,EAAC,IAAI,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAAqB,EAAE,EAAE;IACzF,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAC3C,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAC3C,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAyB,IAAI,CAAC,CAAA;IAC1E,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAA;IAC9B,MAAM,EAAC,kBAAkB,EAAC,GAAG,QAAQ,EAAE,CAAA;IAEvC,QAAQ,CACN,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QACb,IAAI,OAAO,EAAE,CAAC;YACZ,WAAW,CAAC,KAAK,EAAE,GAAG,EAAE,OAAO,CAAC,CAAA;QAClC,CAAC;aAAM,CAAC;YACN,WAAW,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;QACzB,CAAC;IACH,CAAC,EACD,EAAC,QAAQ,EAAE,OAAO,CAAC,kBAAkB,CAAC,EAAC,CACxC,CAAA;IAED,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,SAAS,CAAC;aACZ,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;YACf,SAAS,CAAC,IAAI,CAAC,CAAA;YACf,UAAU,EAAE,CAAC,MAAM,CAAC,CAAA;YACpB,aAAa,CAAC,EAAE,CAAC,CAAA;QACnB,CAAC,CAAC;aACD,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;YACf,SAAS,CAAC,IAAI,CAAC,CAAA;YACf,aAAa,CAAC,EAAC,KAAK,EAAC,CAAC,CAAA;QACxB,CAAC,CAAC,CAAA;IACN,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC,CAAA;IAEtB,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;YACxB,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC,CAAA;QAC5B,CAAC;IACH,CAAC,EAAE,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC,CAAA;IAE1B,IAAI,MAAM,EAAE,CAAC;QACX,yBAAyB;QACzB,OAAO,IAAI,CAAA;IACb,CAAC;IAED,OAAO,oBAAC,UAAU,IAAC,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,GAAI,CAAA;AAC9D,CAAC,CAAA;AAED,OAAO,EAAC,UAAU,EAAC,CAAA","sourcesContent":["import {LoadingBar} from './LoadingBar.js'\nimport {handleCtrlC, useComplete} from '../../ui.js'\nimport {TokenizedString} from '../../../../public/node/output.js'\nimport React, {useEffect, useState} from 'react'\n\nimport {useInput, useStdin} from 'ink'\n\ninterface SingleTaskProps<T> {\n title: TokenizedString\n task: (updateStatus: (status: TokenizedString) => void) => Promise<T>\n onComplete?: (result: T) => void\n onAbort?: () => void\n noColor?: boolean\n}\n\nconst SingleTask = <T,>({task, title, onComplete, onAbort, noColor}: SingleTaskProps<T>) => {\n const [status, setStatus] = useState(title)\n const [isDone, setIsDone] = useState(false)\n const [taskResult, setTaskResult] = useState<{error?: Error} | null>(null)\n const complete = useComplete()\n const {isRawModeSupported} = useStdin()\n\n useInput(\n (input, key) => {\n if (onAbort) {\n handleCtrlC(input, key, onAbort)\n } else {\n handleCtrlC(input, key)\n }\n },\n {isActive: Boolean(isRawModeSupported)},\n )\n\n useEffect(() => {\n task(setStatus)\n .then((result) => {\n setIsDone(true)\n onComplete?.(result)\n setTaskResult({})\n })\n .catch((error) => {\n setIsDone(true)\n setTaskResult({error})\n })\n }, [task, onComplete])\n\n useEffect(() => {\n if (taskResult !== null) {\n complete(taskResult.error)\n }\n }, [taskResult, complete])\n\n if (isDone) {\n // clear things once done\n return null\n }\n\n return <LoadingBar title={status.value} noColor={noColor} />\n}\n\nexport {SingleTask}\n"]}
@@ -1,12 +1,12 @@
1
1
  import { TokenizedText } from './TokenizedText.js';
2
2
  import { TextInput } from './TextInput.js';
3
- import { handleCtrlC } from '../../ui.js';
3
+ import { handleCtrlC, useComplete } from '../../ui.js';
4
4
  import useLayout from '../hooks/use-layout.js';
5
5
  import { messageWithPunctuation } from '../utilities.js';
6
6
  import useAbortSignal from '../hooks/use-abort-signal.js';
7
7
  import usePrompt, { PromptState } from '../hooks/use-prompt.js';
8
8
  import React, { useCallback, useEffect, useState } from 'react';
9
- import { Box, useApp, useInput, Text } from 'ink';
9
+ import { Box, useInput, Text } from 'ink';
10
10
  import figures from 'figures';
11
11
  const TextPrompt = ({ message, onSubmit, validate, defaultValue = '', password = false, allowEmpty = false, emptyDisplayedValue = '(empty)', abortSignal, preview, initialAnswer = '', }) => {
12
12
  if (password && defaultValue) {
@@ -27,7 +27,7 @@ const TextPrompt = ({ message, onSubmit, validate, defaultValue = '', password =
27
27
  const answerOrDefault = answer.length > 0 ? answer : defaultValue;
28
28
  const displayEmptyValue = answerOrDefault === '';
29
29
  const displayedAnswer = displayEmptyValue ? emptyDisplayedValue : answerOrDefault;
30
- const { exit: unmountInk } = useApp();
30
+ const complete = useComplete();
31
31
  const [error, setError] = useState(undefined);
32
32
  const color = promptState === PromptState.Error ? 'red' : 'cyan';
33
33
  const underline = new Array(oneThird - 3).fill('▔');
@@ -48,9 +48,9 @@ const TextPrompt = ({ message, onSubmit, validate, defaultValue = '', password =
48
48
  useEffect(() => {
49
49
  if (promptState === PromptState.Submitted) {
50
50
  onSubmit(answerOrDefault);
51
- unmountInk();
51
+ complete();
52
52
  }
53
- }, [answerOrDefault, onSubmit, promptState, unmountInk]);
53
+ }, [answerOrDefault, onSubmit, promptState, complete]);
54
54
  return isAborted ? null : (React.createElement(Box, { flexDirection: "column", marginBottom: 1, width: oneThird },
55
55
  React.createElement(Box, null,
56
56
  React.createElement(Box, { marginRight: 2 },
@@ -1 +1 @@
1
- {"version":3,"file":"TextPrompt.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/TextPrompt.tsx"],"names":[],"mappings":"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","sourcesContent":["import {InlineToken, TokenItem, TokenizedText} from './TokenizedText.js'\nimport {TextInput} from './TextInput.js'\nimport {handleCtrlC} from '../../ui.js'\nimport useLayout from '../hooks/use-layout.js'\nimport {messageWithPunctuation} from '../utilities.js'\nimport {AbortSignal} from '../../../../public/node/abort.js'\nimport useAbortSignal from '../hooks/use-abort-signal.js'\nimport usePrompt, {PromptState} from '../hooks/use-prompt.js'\nimport React, {FunctionComponent, useCallback, useEffect, useState} from 'react'\n\nimport {Box, useApp, useInput, Text} from 'ink'\nimport figures from 'figures'\n\nexport interface TextPromptProps {\n message: TokenItem\n onSubmit: (value: string) => void\n defaultValue?: string\n password?: boolean\n validate?: (value: string) => string | undefined\n allowEmpty?: boolean\n emptyDisplayedValue?: string\n abortSignal?: AbortSignal\n preview?: (value: string) => TokenItem<InlineToken>\n initialAnswer?: string\n}\n\nconst TextPrompt: FunctionComponent<TextPromptProps> = ({\n message,\n onSubmit,\n validate,\n defaultValue = '',\n password = false,\n allowEmpty = false,\n emptyDisplayedValue = '(empty)',\n abortSignal,\n preview,\n initialAnswer = '',\n}) => {\n if (password && defaultValue) {\n throw new Error(\"Can't use defaultValue with password\")\n }\n\n const validateAnswer = useCallback(\n (value: string): string | undefined => {\n if (validate) {\n return validate(value)\n }\n\n if (value.length === 0 && !allowEmpty) return 'Type an answer to the prompt.'\n\n return undefined\n },\n [allowEmpty, validate],\n )\n\n const {oneThird} = useLayout()\n const {promptState, setPromptState, answer, setAnswer} = usePrompt<string>({\n initialAnswer,\n })\n const answerOrDefault = answer.length > 0 ? answer : defaultValue\n const displayEmptyValue = answerOrDefault === ''\n const displayedAnswer = displayEmptyValue ? emptyDisplayedValue : answerOrDefault\n const {exit: unmountInk} = useApp()\n const [error, setError] = useState<string | undefined>(undefined)\n const color = promptState === PromptState.Error ? 'red' : 'cyan'\n const underline = new Array(oneThird - 3).fill('▔')\n const {isAborted} = useAbortSignal(abortSignal)\n\n useInput((input, key) => {\n handleCtrlC(input, key)\n\n if (key.return) {\n const error = validateAnswer(answerOrDefault)\n\n if (error) {\n setPromptState(PromptState.Error)\n setError(error)\n } else {\n setPromptState(PromptState.Submitted)\n }\n }\n })\n\n useEffect(() => {\n if (promptState === PromptState.Submitted) {\n onSubmit(answerOrDefault)\n unmountInk()\n }\n }, [answerOrDefault, onSubmit, promptState, unmountInk])\n\n return isAborted ? null : (\n <Box flexDirection=\"column\" marginBottom={1} width={oneThird}>\n <Box>\n <Box marginRight={2}>\n <Text>?</Text>\n </Box>\n <TokenizedText item={messageWithPunctuation(message)} />\n </Box>\n {promptState === PromptState.Submitted ? (\n <Box>\n <Box width={3}>\n <Text color=\"cyan\">{figures.tick}</Text>\n </Box>\n\n <Box flexGrow={1}>\n <Text color=\"cyan\" dimColor={displayEmptyValue}>\n {password ? '*'.repeat(answer.length) : displayedAnswer}\n </Text>\n </Box>\n </Box>\n ) : (\n <Box flexDirection=\"column\">\n <Box>\n <Box marginRight={2}>\n <Text color={color}>{`>`}</Text>\n </Box>\n <Box flexGrow={1}>\n <TextInput\n value={answer}\n onChange={(answer) => {\n setAnswer(answer)\n setPromptState(PromptState.Idle)\n }}\n defaultValue={defaultValue}\n color={color}\n password={password}\n />\n </Box>\n </Box>\n <Box marginLeft={3}>\n <Text color={color}>{underline}</Text>\n </Box>\n {promptState === PromptState.Error ? (\n <Box marginLeft={3}>\n <Text color={color}>{error}</Text>\n </Box>\n ) : null}\n {promptState !== PromptState.Error && preview ? (\n <Box marginLeft={3}>\n <TokenizedText item={preview(answerOrDefault)} />\n </Box>\n ) : null}\n </Box>\n )}\n </Box>\n )\n}\n\nexport {TextPrompt}\n"]}
1
+ {"version":3,"file":"TextPrompt.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/TextPrompt.tsx"],"names":[],"mappings":"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","sourcesContent":["import {InlineToken, TokenItem, TokenizedText} from './TokenizedText.js'\nimport {TextInput} from './TextInput.js'\nimport {handleCtrlC, useComplete} from '../../ui.js'\nimport useLayout from '../hooks/use-layout.js'\nimport {messageWithPunctuation} from '../utilities.js'\nimport {AbortSignal} from '../../../../public/node/abort.js'\nimport useAbortSignal from '../hooks/use-abort-signal.js'\nimport usePrompt, {PromptState} from '../hooks/use-prompt.js'\nimport React, {FunctionComponent, useCallback, useEffect, useState} from 'react'\n\nimport {Box, useInput, Text} from 'ink'\nimport figures from 'figures'\n\nexport interface TextPromptProps {\n message: TokenItem\n onSubmit: (value: string) => void\n defaultValue?: string\n password?: boolean\n validate?: (value: string) => string | undefined\n allowEmpty?: boolean\n emptyDisplayedValue?: string\n abortSignal?: AbortSignal\n preview?: (value: string) => TokenItem<InlineToken>\n initialAnswer?: string\n}\n\nconst TextPrompt: FunctionComponent<TextPromptProps> = ({\n message,\n onSubmit,\n validate,\n defaultValue = '',\n password = false,\n allowEmpty = false,\n emptyDisplayedValue = '(empty)',\n abortSignal,\n preview,\n initialAnswer = '',\n}) => {\n if (password && defaultValue) {\n throw new Error(\"Can't use defaultValue with password\")\n }\n\n const validateAnswer = useCallback(\n (value: string): string | undefined => {\n if (validate) {\n return validate(value)\n }\n\n if (value.length === 0 && !allowEmpty) return 'Type an answer to the prompt.'\n\n return undefined\n },\n [allowEmpty, validate],\n )\n\n const {oneThird} = useLayout()\n const {promptState, setPromptState, answer, setAnswer} = usePrompt<string>({\n initialAnswer,\n })\n const answerOrDefault = answer.length > 0 ? answer : defaultValue\n const displayEmptyValue = answerOrDefault === ''\n const displayedAnswer = displayEmptyValue ? emptyDisplayedValue : answerOrDefault\n const complete = useComplete()\n const [error, setError] = useState<string | undefined>(undefined)\n const color = promptState === PromptState.Error ? 'red' : 'cyan'\n const underline = new Array(oneThird - 3).fill('▔')\n const {isAborted} = useAbortSignal(abortSignal)\n\n useInput((input, key) => {\n handleCtrlC(input, key)\n\n if (key.return) {\n const error = validateAnswer(answerOrDefault)\n\n if (error) {\n setPromptState(PromptState.Error)\n setError(error)\n } else {\n setPromptState(PromptState.Submitted)\n }\n }\n })\n\n useEffect(() => {\n if (promptState === PromptState.Submitted) {\n onSubmit(answerOrDefault)\n complete()\n }\n }, [answerOrDefault, onSubmit, promptState, complete])\n\n return isAborted ? null : (\n <Box flexDirection=\"column\" marginBottom={1} width={oneThird}>\n <Box>\n <Box marginRight={2}>\n <Text>?</Text>\n </Box>\n <TokenizedText item={messageWithPunctuation(message)} />\n </Box>\n {promptState === PromptState.Submitted ? (\n <Box>\n <Box width={3}>\n <Text color=\"cyan\">{figures.tick}</Text>\n </Box>\n\n <Box flexGrow={1}>\n <Text color=\"cyan\" dimColor={displayEmptyValue}>\n {password ? '*'.repeat(answer.length) : displayedAnswer}\n </Text>\n </Box>\n </Box>\n ) : (\n <Box flexDirection=\"column\">\n <Box>\n <Box marginRight={2}>\n <Text color={color}>{`>`}</Text>\n </Box>\n <Box flexGrow={1}>\n <TextInput\n value={answer}\n onChange={(answer) => {\n setAnswer(answer)\n setPromptState(PromptState.Idle)\n }}\n defaultValue={defaultValue}\n color={color}\n password={password}\n />\n </Box>\n </Box>\n <Box marginLeft={3}>\n <Text color={color}>{underline}</Text>\n </Box>\n {promptState === PromptState.Error ? (\n <Box marginLeft={3}>\n <Text color={color}>{error}</Text>\n </Box>\n ) : null}\n {promptState !== PromptState.Error && preview ? (\n <Box marginLeft={3}>\n <TokenizedText item={preview(answerOrDefault)} />\n </Box>\n ) : null}\n </Box>\n )}\n </Box>\n )\n}\n\nexport {TextPrompt}\n"]}
@@ -1,28 +1,23 @@
1
- import { useApp } from 'ink';
2
- import { useLayoutEffect, useState } from 'react';
1
+ import { useComplete } from '../../ui.js';
2
+ import { useEffect, useLayoutEffect, useState } from 'react';
3
3
  const noop = () => Promise.resolve();
4
4
  export default function useAbortSignal(abortSignal, onAbort = noop) {
5
- const { exit: unmountInk } = useApp();
5
+ const complete = useComplete();
6
6
  const [isAborted, setIsAborted] = useState(false);
7
7
  useLayoutEffect(() => {
8
8
  abortSignal?.addEventListener('abort', () => {
9
9
  const abortWithError = abortSignal.reason.message === 'AbortError' ? undefined : abortSignal.reason;
10
10
  onAbort(abortWithError)
11
- .then(() => {
12
- setIsAborted(true);
13
- // Defer unmounting to the next setImmediate so React 19 can flush
14
- // batched state updates before the tree is torn down. React 19's
15
- // scheduler also uses setImmediate in Node.js (check phase), and
16
- // since it was queued first (by setIsAborted above), it renders
17
- // before this callback fires (FIFO within the check phase).
18
- // NOTE: setTimeout(fn, 0) is NOT safe here because its timers-phase
19
- // fires BEFORE the check phase on slow CI machines where >1 ms has
20
- // elapsed, causing unmount to race ahead of the render.
21
- setImmediate(() => unmountInk(abortWithError));
22
- })
11
+ .then(() => setIsAborted(true))
23
12
  .catch(() => { });
24
13
  });
25
14
  }, []);
15
+ useEffect(() => {
16
+ if (isAborted) {
17
+ const abortWithError = abortSignal?.reason?.message === 'AbortError' ? undefined : abortSignal?.reason;
18
+ complete(abortWithError);
19
+ }
20
+ }, [isAborted]);
26
21
  return { isAborted };
27
22
  }
28
23
  //# sourceMappingURL=use-abort-signal.js.map