[READ-ONLY] Mirror of https://github.com/bombshell-dev/clack. Effortlessly build beautiful command-line apps bomb.sh/docs/clack/basics/getting-started/
cli command-line command-line-app node prompt prompts
5

Configure Feed

Select the types of activity you want to include in your feed.

[ci] format

authored by

natemoo-re and committed by
github-actions[bot]
(Feb 25, 2023, 1:16 AM UTC) b623d6a5 4bfc89a2

+75 -45
+18 -16
examples/changesets/index.ts
··· 29 29 { value: '@scope/x' }, 30 30 { value: '@scope/y' }, 31 31 { value: '@scope/z' }, 32 - ] 33 - } 32 + ], 33 + }, 34 34 }), 35 35 major: ({ results }) => { 36 36 const packages = results.packages ?? []; 37 37 return p.multiselect({ 38 38 message: `Which packages should have a ${color.red('major')} bump?`, 39 - options: packages.map(value => ({ value })), 39 + options: packages.map((value) => ({ value })), 40 40 required: false, 41 - }) 41 + }); 42 42 }, 43 43 minor: ({ results }) => { 44 44 const packages = results.packages ?? []; 45 45 const major = Array.isArray(results.major) ? results.major : []; 46 - const possiblePackages = packages.filter(pkg => !major.includes(pkg)) 46 + const possiblePackages = packages.filter((pkg) => !major.includes(pkg)); 47 47 if (possiblePackages.length === 0) return; 48 48 return p.multiselect({ 49 49 message: `Which packages should have a ${color.yellow('minor')} bump?`, 50 - options: possiblePackages.map(value => ({ value })), 51 - required: false 52 - }) 50 + options: possiblePackages.map((value) => ({ value })), 51 + required: false, 52 + }); 53 53 }, 54 54 patch: async ({ results }) => { 55 55 const packages = results.packages ?? []; 56 56 const major = Array.isArray(results.major) ? results.major : []; 57 57 const minor = Array.isArray(results.minor) ? results.minor : []; 58 - const possiblePackages = packages.filter(pkg => !major.includes(pkg) && !minor.includes(pkg)); 58 + const possiblePackages = packages.filter( 59 + (pkg) => !major.includes(pkg) && !minor.includes(pkg) 60 + ); 59 61 if (possiblePackages.length === 0) return; 60 62 let note = possiblePackages.join('\n'); 61 - 63 + 62 64 p.log.step(`These packages will have a ${color.green('patch')} bump.\n${color.dim(note)}`); 63 - return possiblePackages 64 - } 65 + return possiblePackages; 66 + }, 65 67 }, 66 68 { 67 - onCancel 69 + onCancel, 68 70 } 69 71 ); 70 72 71 73 const message = await p.text({ 72 74 placeholder: 'Summary', 73 - message: 'Please enter a summary for this change' 74 - }) 75 + message: 'Please enter a summary for this change', 76 + }); 75 77 76 78 if (p.isCancel(message)) { 77 - return onCancel() 79 + return onCancel(); 78 80 } 79 81 80 82 p.outro(`Changeset added! ${color.underline(color.cyan('.changeset/orange-crabs-sing.md'))}`);
+1 -1
packages/core/src/index.ts
··· 1 1 export { default as ConfirmPrompt } from './prompts/confirm'; 2 - export { default as MultiSelectPrompt } from './prompts/multi-select'; 3 2 export { default as GroupMultiSelectPrompt } from './prompts/group-multiselect'; 3 + export { default as MultiSelectPrompt } from './prompts/multi-select'; 4 4 export { default as PasswordPrompt } from './prompts/password'; 5 5 export { default as Prompt, isCancel } from './prompts/prompt'; 6 6 export type { State } from './prompts/prompt';
+11 -8
packages/core/src/prompts/group-multiselect.ts
··· 1 1 import Prompt, { PromptOptions } from './prompt'; 2 2 3 - interface GroupMultiSelectOptions<T extends { value: any }> extends PromptOptions<GroupMultiSelectPrompt<T>> { 3 + interface GroupMultiSelectOptions<T extends { value: any }> 4 + extends PromptOptions<GroupMultiSelectPrompt<T>> { 4 5 options: Record<string, T[]>; 5 6 initialValues?: T['value'][]; 6 7 required?: boolean; ··· 11 12 cursor: number = 0; 12 13 13 14 getGroupItems(group: string): T[] { 14 - return this.options.filter(o => o.group === group); 15 + return this.options.filter((o) => o.group === group); 15 16 } 16 17 17 18 isGroupSelected(group: string) { 18 19 const items = this.getGroupItems(group); 19 - return items.every(i => this.value.includes(i.value)); 20 + return items.every((i) => this.value.includes(i.value)); 20 21 } 21 22 22 23 private toggleValue() { ··· 25 26 const group = item.value; 26 27 const groupedItems = this.getGroupItems(group); 27 28 if (this.isGroupSelected(group)) { 28 - this.value = this.value.filter((v: string) => groupedItems.findIndex(i => i.value === v) === -1); 29 + this.value = this.value.filter( 30 + (v: string) => groupedItems.findIndex((i) => i.value === v) === -1 31 + ); 29 32 } else { 30 - this.value = [...this.value, ...groupedItems.map(i => i.value)]; 33 + this.value = [...this.value, ...groupedItems.map((i) => i.value)]; 31 34 } 32 35 this.value = Array.from(new Set(this.value)); 33 36 } else { ··· 42 45 super(opts, false); 43 46 const { options } = opts; 44 47 this.options = Object.entries(options).flatMap(([key, option]) => [ 45 - { value: key, group: true, label: key }, 46 - ...option.map((opt) => ({ ...opt, group: key })), 47 - ]) 48 + { value: key, group: true, label: key }, 49 + ...option.map((opt) => ({ ...opt, group: key })), 50 + ]); 48 51 this.value = [...(opts.initialValues ?? [])]; 49 52 this.cursor = Math.max( 50 53 this.options.findIndex(({ value }) => value === opts.cursorAt),
+3 -3
packages/core/src/prompts/multi-select.ts
··· 16 16 17 17 private toggleAll() { 18 18 const allSelected = this.value.length === this.options.length; 19 - this.value = allSelected ? [] : this.options.map(v => v.value); 19 + this.value = allSelected ? [] : this.options.map((v) => v.value); 20 20 } 21 21 22 22 private toggleValue() { ··· 37 37 ); 38 38 this.on('key', (char) => { 39 39 if (char === 'a') { 40 - this.toggleAll() 40 + this.toggleAll(); 41 41 } 42 - }) 42 + }); 43 43 44 44 this.on('cursor', (key) => { 45 45 switch (key) {
+42 -17
packages/prompts/src/index.ts
··· 1 1 import { 2 2 block, 3 3 ConfirmPrompt, 4 + GroupMultiSelectPrompt, 4 5 isCancel, 5 6 MultiSelectPrompt, 6 - GroupMultiSelectPrompt, 7 7 PasswordPrompt, 8 8 SelectKeyPrompt, 9 9 SelectPrompt, ··· 325 325 326 326 switch (this.state) { 327 327 case 'submit': { 328 - return `${title}${color.gray(S_BAR)} ${this.options 329 - .filter(({ value }) => this.value.includes(value)) 330 - .map((option) => opt(option, 'submitted')) 331 - .join(color.dim(', ')) || color.dim('none')}`; 328 + return `${title}${color.gray(S_BAR)} ${ 329 + this.options 330 + .filter(({ value }) => this.value.includes(value)) 331 + .map((option) => opt(option, 'submitted')) 332 + .join(color.dim(', ')) || color.dim('none') 333 + }`; 332 334 } 333 335 case 'cancel': { 334 336 const label = this.options ··· 400 402 ) => { 401 403 const opt = ( 402 404 option: Options[number], 403 - state: 'inactive' | 'active' | 'selected' | 'active-selected' | 'group-active' | 'group-active-selected' | 'submitted' | 'cancelled', 404 - options: Options = [] as any, 405 + state: 406 + | 'inactive' 407 + | 'active' 408 + | 'selected' 409 + | 'active-selected' 410 + | 'group-active' 411 + | 'group-active-selected' 412 + | 'submitted' 413 + | 'cancelled', 414 + options: Options = [] as any 405 415 ) => { 406 416 const label = option.label ?? String(option.value); 407 417 const isItem = typeof option.group === 'string'; ··· 474 484 .join('\n'); 475 485 return `${title}${color.yellow(S_BAR)} ${this.options 476 486 .map((option, i, options) => { 477 - const selected = this.value.includes(option.value) || (option.group === true && this.isGroupSelected(option.value)); 487 + const selected = 488 + this.value.includes(option.value) || 489 + (option.group === true && this.isGroupSelected(option.value)); 478 490 const active = i === this.cursor; 479 - const groupActive = !active && typeof option.group === 'string' && this.options[this.cursor].value === option.group; 491 + const groupActive = 492 + !active && 493 + typeof option.group === 'string' && 494 + this.options[this.cursor].value === option.group; 480 495 if (groupActive) { 481 496 return opt(option, selected ? 'group-active-selected' : 'group-active', options); 482 497 } ··· 493 508 default: { 494 509 return `${title}${color.cyan(S_BAR)} ${this.options 495 510 .map((option, i, options) => { 496 - const selected = this.value.includes(option.value) || (option.group === true && this.isGroupSelected(option.value)); 511 + const selected = 512 + this.value.includes(option.value) || 513 + (option.group === true && this.isGroupSelected(option.value)); 497 514 const active = i === this.cursor; 498 - const groupActive = !active && typeof option.group === 'string' && this.options[this.cursor].value === option.group; 515 + const groupActive = 516 + !active && 517 + typeof option.group === 'string' && 518 + this.options[this.cursor].value === option.group; 499 519 if (groupActive) { 500 520 return opt(option, selected ? 'group-active-selected' : 'group-active', options); 501 521 } ··· 517 537 const strip = (str: string) => str.replace(ansiRegex(), ''); 518 538 export const note = (message = '', title = '') => { 519 539 const lines = `\n${message}\n`.split('\n'); 520 - const len = Math.max( 521 - lines.reduce((sum, ln) => { 522 - ln = strip(ln); 523 - return ln.length > sum ? ln.length : sum; 524 - }, 0), strip(title).length) + 2; 540 + const len = 541 + Math.max( 542 + lines.reduce((sum, ln) => { 543 + ln = strip(ln); 544 + return ln.length > sum ? ln.length : sum; 545 + }, 0), 546 + strip(title).length 547 + ) + 2; 525 548 const msg = lines 526 549 .map( 527 550 (ln) => ··· 641 664 } 642 665 643 666 export type PromptGroup<T> = { 644 - [P in keyof T]: (opts: { results: Partial<PromptGroupAwaitedReturn<T>> }) => void | Promise<T[P] | void>; 667 + [P in keyof T]: (opts: { 668 + results: Partial<PromptGroupAwaitedReturn<T>>; 669 + }) => void | Promise<T[P] | void>; 645 670 }; 646 671 647 672 /**