@flyingrobots/bijou 0.9.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/test/assertions.d.ts +51 -0
- package/dist/adapters/test/assertions.d.ts.map +1 -0
- package/dist/adapters/test/assertions.js +67 -0
- package/dist/adapters/test/assertions.js.map +1 -0
- package/dist/adapters/test/audit-style.d.ts +28 -7
- package/dist/adapters/test/audit-style.d.ts.map +1 -1
- package/dist/adapters/test/audit-style.js +61 -4
- package/dist/adapters/test/audit-style.js.map +1 -1
- package/dist/adapters/test/index.d.ts +36 -1
- package/dist/adapters/test/index.d.ts.map +1 -1
- package/dist/adapters/test/index.js +12 -1
- package/dist/adapters/test/index.js.map +1 -1
- package/dist/adapters/test/io.d.ts +27 -0
- package/dist/adapters/test/io.d.ts.map +1 -1
- package/dist/adapters/test/io.js +56 -0
- package/dist/adapters/test/io.js.map +1 -1
- package/dist/adapters/test/runtime.d.ts +17 -0
- package/dist/adapters/test/runtime.d.ts.map +1 -1
- package/dist/adapters/test/runtime.js +14 -0
- package/dist/adapters/test/runtime.js.map +1 -1
- package/dist/adapters/test/style.d.ts +9 -0
- package/dist/adapters/test/style.d.ts.map +1 -1
- package/dist/adapters/test/style.js +54 -0
- package/dist/adapters/test/style.js.map +1 -1
- package/dist/context.d.ts +21 -0
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +21 -0
- package/dist/context.js.map +1 -1
- package/dist/core/bg-fill.d.ts +32 -0
- package/dist/core/bg-fill.d.ts.map +1 -0
- package/dist/core/bg-fill.js +42 -0
- package/dist/core/bg-fill.js.map +1 -0
- package/dist/core/components/accordion.d.ts +20 -0
- package/dist/core/components/accordion.d.ts.map +1 -1
- package/dist/core/components/accordion.js +13 -6
- package/dist/core/components/accordion.js.map +1 -1
- package/dist/core/components/alert.d.ts +16 -0
- package/dist/core/components/alert.d.ts.map +1 -1
- package/dist/core/components/alert.js +17 -6
- package/dist/core/components/alert.js.map +1 -1
- package/dist/core/components/badge.d.ts +18 -0
- package/dist/core/components/badge.d.ts.map +1 -1
- package/dist/core/components/badge.js +15 -11
- package/dist/core/components/badge.js.map +1 -1
- package/dist/core/components/box.d.ts +33 -0
- package/dist/core/components/box.d.ts.map +1 -1
- package/dist/core/components/box.js +72 -23
- package/dist/core/components/box.js.map +1 -1
- package/dist/core/components/breadcrumb.d.ts +15 -0
- package/dist/core/components/breadcrumb.d.ts.map +1 -1
- package/dist/core/components/breadcrumb.js +13 -6
- package/dist/core/components/breadcrumb.js.map +1 -1
- package/dist/core/components/dag-source.d.ts +52 -9
- package/dist/core/components/dag-source.d.ts.map +1 -1
- package/dist/core/components/dag-source.js +53 -9
- package/dist/core/components/dag-source.js.map +1 -1
- package/dist/core/components/dag-stats.d.ts +2 -0
- package/dist/core/components/dag-stats.d.ts.map +1 -1
- package/dist/core/components/dag-stats.js.map +1 -1
- package/dist/core/components/dag.d.ts +88 -1
- package/dist/core/components/dag.d.ts.map +1 -1
- package/dist/core/components/dag.js +127 -6
- package/dist/core/components/dag.js.map +1 -1
- package/dist/core/components/enumerated-list.d.ts +30 -0
- package/dist/core/components/enumerated-list.d.ts.map +1 -1
- package/dist/core/components/enumerated-list.js +50 -11
- package/dist/core/components/enumerated-list.js.map +1 -1
- package/dist/core/components/hyperlink.d.ts +16 -0
- package/dist/core/components/hyperlink.d.ts.map +1 -1
- package/dist/core/components/hyperlink.js +22 -11
- package/dist/core/components/hyperlink.js.map +1 -1
- package/dist/core/components/index.d.ts +7 -0
- package/dist/core/components/index.d.ts.map +1 -1
- package/dist/core/components/index.js +7 -0
- package/dist/core/components/index.js.map +1 -1
- package/dist/core/components/kbd.d.ts +14 -0
- package/dist/core/components/kbd.d.ts.map +1 -1
- package/dist/core/components/kbd.js +13 -6
- package/dist/core/components/kbd.js.map +1 -1
- package/dist/core/components/log.d.ts +20 -0
- package/dist/core/components/log.d.ts.map +1 -1
- package/dist/core/components/log.js +24 -11
- package/dist/core/components/log.js.map +1 -1
- package/dist/core/components/logo.d.ts +32 -0
- package/dist/core/components/logo.d.ts.map +1 -1
- package/dist/core/components/logo.js +38 -0
- package/dist/core/components/logo.js.map +1 -1
- package/dist/core/components/markdown.d.ts +7 -1
- package/dist/core/components/markdown.d.ts.map +1 -1
- package/dist/core/components/markdown.js +76 -0
- package/dist/core/components/markdown.js.map +1 -1
- package/dist/core/components/paginator.d.ts +16 -0
- package/dist/core/components/paginator.d.ts.map +1 -1
- package/dist/core/components/paginator.js +12 -6
- package/dist/core/components/paginator.js.map +1 -1
- package/dist/core/components/progress.d.ts +55 -0
- package/dist/core/components/progress.d.ts.map +1 -1
- package/dist/core/components/progress.js +37 -6
- package/dist/core/components/progress.js.map +1 -1
- package/dist/core/components/separator.d.ts +16 -0
- package/dist/core/components/separator.d.ts.map +1 -1
- package/dist/core/components/separator.js +12 -6
- package/dist/core/components/separator.js.map +1 -1
- package/dist/core/components/skeleton.d.ts +15 -0
- package/dist/core/components/skeleton.d.ts.map +1 -1
- package/dist/core/components/skeleton.js +12 -6
- package/dist/core/components/skeleton.js.map +1 -1
- package/dist/core/components/spinner.d.ts +37 -0
- package/dist/core/components/spinner.d.ts.map +1 -1
- package/dist/core/components/spinner.js +26 -6
- package/dist/core/components/spinner.js.map +1 -1
- package/dist/core/components/stepper.d.ts +20 -0
- package/dist/core/components/stepper.d.ts.map +1 -1
- package/dist/core/components/stepper.js +16 -6
- package/dist/core/components/stepper.js.map +1 -1
- package/dist/core/components/table.d.ts +20 -0
- package/dist/core/components/table.d.ts.map +1 -1
- package/dist/core/components/table.js +31 -6
- package/dist/core/components/table.js.map +1 -1
- package/dist/core/components/tabs.d.ts +19 -0
- package/dist/core/components/tabs.d.ts.map +1 -1
- package/dist/core/components/tabs.js +19 -6
- package/dist/core/components/tabs.js.map +1 -1
- package/dist/core/components/timeline.d.ts +19 -0
- package/dist/core/components/timeline.d.ts.map +1 -1
- package/dist/core/components/timeline.js +20 -6
- package/dist/core/components/timeline.js.map +1 -1
- package/dist/core/components/tree.d.ts +19 -0
- package/dist/core/components/tree.d.ts.map +1 -1
- package/dist/core/components/tree.js +49 -11
- package/dist/core/components/tree.js.map +1 -1
- package/dist/core/detect/index.d.ts +8 -2
- package/dist/core/detect/index.d.ts.map +1 -1
- package/dist/core/detect/index.js +7 -1
- package/dist/core/detect/index.js.map +1 -1
- package/dist/core/detect/tty.d.ts +36 -0
- package/dist/core/detect/tty.d.ts.map +1 -1
- package/dist/core/detect/tty.js +34 -0
- package/dist/core/detect/tty.js.map +1 -1
- package/dist/core/forms/confirm.d.ts +14 -0
- package/dist/core/forms/confirm.d.ts.map +1 -1
- package/dist/core/forms/confirm.js +15 -5
- package/dist/core/forms/confirm.js.map +1 -1
- package/dist/core/forms/filter.d.ts +30 -0
- package/dist/core/forms/filter.d.ts.map +1 -1
- package/dist/core/forms/filter.js +67 -49
- package/dist/core/forms/filter.js.map +1 -1
- package/dist/core/forms/form-utils.d.ts +103 -0
- package/dist/core/forms/form-utils.d.ts.map +1 -0
- package/dist/core/forms/form-utils.js +135 -0
- package/dist/core/forms/form-utils.js.map +1 -0
- package/dist/core/forms/group.d.ts +12 -0
- package/dist/core/forms/group.d.ts.map +1 -1
- package/dist/core/forms/group.js +7 -0
- package/dist/core/forms/group.js.map +1 -1
- package/dist/core/forms/index.d.ts +6 -0
- package/dist/core/forms/index.d.ts.map +1 -1
- package/dist/core/forms/index.js +6 -0
- package/dist/core/forms/index.js.map +1 -1
- package/dist/core/forms/input.d.ts +17 -0
- package/dist/core/forms/input.d.ts.map +1 -1
- package/dist/core/forms/input.js +27 -15
- package/dist/core/forms/input.js.map +1 -1
- package/dist/core/forms/multiselect.d.ts +16 -0
- package/dist/core/forms/multiselect.d.ts.map +1 -1
- package/dist/core/forms/multiselect.js +54 -38
- package/dist/core/forms/multiselect.js.map +1 -1
- package/dist/core/forms/select.d.ts +17 -0
- package/dist/core/forms/select.d.ts.map +1 -1
- package/dist/core/forms/select.js +51 -37
- package/dist/core/forms/select.js.map +1 -1
- package/dist/core/forms/textarea.d.ts +19 -0
- package/dist/core/forms/textarea.d.ts.map +1 -1
- package/dist/core/forms/textarea.js +51 -47
- package/dist/core/forms/textarea.js.map +1 -1
- package/dist/core/forms/types.d.ts +41 -2
- package/dist/core/forms/types.d.ts.map +1 -1
- package/dist/core/forms/wizard.d.ts +19 -0
- package/dist/core/forms/wizard.d.ts.map +1 -1
- package/dist/core/forms/wizard.js +4 -0
- package/dist/core/forms/wizard.js.map +1 -1
- package/dist/core/resolve-ctx.d.ts +30 -0
- package/dist/core/resolve-ctx.d.ts.map +1 -0
- package/dist/core/resolve-ctx.js +43 -0
- package/dist/core/resolve-ctx.js.map +1 -0
- package/dist/core/text/clip.d.ts +21 -0
- package/dist/core/text/clip.d.ts.map +1 -0
- package/dist/core/text/clip.js +75 -0
- package/dist/core/text/clip.js.map +1 -0
- package/dist/core/text/grapheme.d.ts +15 -3
- package/dist/core/text/grapheme.d.ts.map +1 -1
- package/dist/core/text/grapheme.js +21 -3
- package/dist/core/text/grapheme.js.map +1 -1
- package/dist/core/text/index.d.ts +8 -0
- package/dist/core/text/index.d.ts.map +1 -1
- package/dist/core/text/index.js +8 -0
- package/dist/core/text/index.js.map +1 -1
- package/dist/core/theme/color.d.ts +47 -8
- package/dist/core/theme/color.d.ts.map +1 -1
- package/dist/core/theme/color.js +77 -8
- package/dist/core/theme/color.js.map +1 -1
- package/dist/core/theme/downsample.d.ts +24 -6
- package/dist/core/theme/downsample.d.ts.map +1 -1
- package/dist/core/theme/downsample.js +41 -10
- package/dist/core/theme/downsample.js.map +1 -1
- package/dist/core/theme/dtcg.d.ts +28 -2
- package/dist/core/theme/dtcg.d.ts.map +1 -1
- package/dist/core/theme/dtcg.js +112 -9
- package/dist/core/theme/dtcg.js.map +1 -1
- package/dist/core/theme/extend.d.ts +14 -0
- package/dist/core/theme/extend.d.ts.map +1 -1
- package/dist/core/theme/extend.js +14 -0
- package/dist/core/theme/extend.js.map +1 -1
- package/dist/core/theme/gradient.d.ts +16 -0
- package/dist/core/theme/gradient.d.ts.map +1 -1
- package/dist/core/theme/gradient.js +13 -0
- package/dist/core/theme/gradient.js.map +1 -1
- package/dist/core/theme/index.d.ts +7 -0
- package/dist/core/theme/index.d.ts.map +1 -1
- package/dist/core/theme/index.js +7 -0
- package/dist/core/theme/index.js.map +1 -1
- package/dist/core/theme/presets.d.ts +6 -1
- package/dist/core/theme/presets.d.ts.map +1 -1
- package/dist/core/theme/presets.js +34 -1
- package/dist/core/theme/presets.js.map +1 -1
- package/dist/core/theme/resolve.d.ts +59 -13
- package/dist/core/theme/resolve.d.ts.map +1 -1
- package/dist/core/theme/resolve.js +36 -9
- package/dist/core/theme/resolve.js.map +1 -1
- package/dist/core/theme/styled.d.ts +12 -0
- package/dist/core/theme/styled.d.ts.map +1 -1
- package/dist/core/theme/styled.js +12 -0
- package/dist/core/theme/styled.js.map +1 -1
- package/dist/core/theme/tokens.d.ts +29 -0
- package/dist/core/theme/tokens.d.ts.map +1 -1
- package/dist/factory.d.ts +18 -0
- package/dist/factory.d.ts.map +1 -1
- package/dist/factory.js +11 -0
- package/dist/factory.js.map +1 -1
- package/dist/index.d.ts +11 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -2
- package/dist/index.js.map +1 -1
- package/dist/ports/context.d.ts +11 -0
- package/dist/ports/context.d.ts.map +1 -1
- package/dist/ports/index.d.ts +6 -1
- package/dist/ports/index.d.ts.map +1 -1
- package/dist/ports/index.js +5 -0
- package/dist/ports/index.js.map +1 -1
- package/dist/ports/io.d.ts +66 -2
- package/dist/ports/io.d.ts.map +1 -1
- package/dist/ports/runtime.d.ts +11 -0
- package/dist/ports/runtime.d.ts.map +1 -1
- package/dist/ports/style.d.ts +14 -0
- package/dist/ports/style.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/core/forms/input.js
CHANGED
|
@@ -1,32 +1,44 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { resolveCtx } from '../resolve-ctx.js';
|
|
2
|
+
import { formatFormTitle, writeValidationError } from './form-utils.js';
|
|
3
|
+
/**
|
|
4
|
+
* Prompt the user for a single-line text input.
|
|
5
|
+
*
|
|
6
|
+
* Display adapts to the current output mode (interactive, accessible, pipe).
|
|
7
|
+
* Runs validation and required-field checks after the user responds.
|
|
8
|
+
*
|
|
9
|
+
* @remarks Validation is non-blocking — errors are written to output but the
|
|
10
|
+
* entered value is always returned.
|
|
11
|
+
*
|
|
12
|
+
* @param options - Input field configuration.
|
|
13
|
+
* @returns The trimmed user input, or the default value if none was provided.
|
|
14
|
+
*/
|
|
2
15
|
export async function input(options) {
|
|
3
|
-
const ctx = options.ctx
|
|
16
|
+
const ctx = resolveCtx(options.ctx);
|
|
4
17
|
const mode = ctx.mode;
|
|
5
18
|
const noColor = ctx.theme.noColor;
|
|
6
19
|
const prompt = buildPrompt(options, mode, noColor, ctx);
|
|
7
20
|
const answer = await ctx.io.question(prompt);
|
|
8
21
|
const value = answer.trim() || options.defaultValue || '';
|
|
9
22
|
if (options.required && value === '') {
|
|
10
|
-
|
|
11
|
-
ctx.io.write('This field is required.\n');
|
|
12
|
-
}
|
|
13
|
-
else {
|
|
14
|
-
ctx.io.write(ctx.style.styled(ctx.theme.theme.semantic.error, 'This field is required.') + '\n');
|
|
15
|
-
}
|
|
23
|
+
writeValidationError('This field is required.', ctx);
|
|
16
24
|
}
|
|
17
25
|
if (options.validate) {
|
|
18
26
|
const result = options.validate(value);
|
|
19
27
|
if (!result.valid && result.message) {
|
|
20
|
-
|
|
21
|
-
ctx.io.write(result.message + '\n');
|
|
22
|
-
}
|
|
23
|
-
else {
|
|
24
|
-
ctx.io.write(ctx.style.styled(ctx.theme.theme.semantic.error, result.message) + '\n');
|
|
25
|
-
}
|
|
28
|
+
writeValidationError(result.message, ctx);
|
|
26
29
|
}
|
|
27
30
|
}
|
|
28
31
|
return value;
|
|
29
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* Build a mode-appropriate prompt string for the input field.
|
|
35
|
+
*
|
|
36
|
+
* @param options - Input field configuration.
|
|
37
|
+
* @param mode - Current output mode (interactive, accessible, pipe).
|
|
38
|
+
* @param noColor - Whether color output is disabled.
|
|
39
|
+
* @param ctx - Bijou context for styling.
|
|
40
|
+
* @returns Formatted prompt string.
|
|
41
|
+
*/
|
|
30
42
|
function buildPrompt(options, mode, noColor, ctx) {
|
|
31
43
|
const defaultHint = options.defaultValue ? ` (${options.defaultValue})` : '';
|
|
32
44
|
if (mode === 'accessible')
|
|
@@ -35,7 +47,7 @@ function buildPrompt(options, mode, noColor, ctx) {
|
|
|
35
47
|
return `${options.title}${defaultHint}: `;
|
|
36
48
|
if (noColor)
|
|
37
49
|
return `${options.title}${defaultHint}: `;
|
|
38
|
-
const label =
|
|
50
|
+
const label = formatFormTitle(options.title, ctx);
|
|
39
51
|
const hint = options.defaultValue ? ctx.style.styled(ctx.theme.theme.semantic.muted, ` (${options.defaultValue})`) : '';
|
|
40
52
|
return `${label}${hint} `;
|
|
41
53
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"input.js","sourceRoot":"","sources":["../../../src/core/forms/input.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"input.js","sourceRoot":"","sources":["../../../src/core/forms/input.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAYxE;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,KAAK,CAAC,OAAqB;IAC/C,MAAM,GAAG,GAAG,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACpC,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC;IACtB,MAAM,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC;IAElC,MAAM,MAAM,GAAG,WAAW,CAAC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC;IACxD,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC7C,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,EAAE,IAAI,OAAO,CAAC,YAAY,IAAI,EAAE,CAAC;IAE1D,IAAI,OAAO,CAAC,QAAQ,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;QACrC,oBAAoB,CAAC,yBAAyB,EAAE,GAAG,CAAC,CAAC;IACvD,CAAC;IAED,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;QACrB,MAAM,MAAM,GAAqB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QACzD,IAAI,CAAC,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YACpC,oBAAoB,CAAC,MAAM,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QAC5C,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,WAAW,CAAC,OAAqB,EAAE,IAAY,EAAE,OAAgB,EAAE,GAAiB;IAC3F,MAAM,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IAE7E,IAAI,IAAI,KAAK,YAAY;QAAE,OAAO,SAAS,OAAO,CAAC,KAAK,CAAC,WAAW,EAAE,GAAG,WAAW,IAAI,CAAC;IACzF,IAAI,IAAI,KAAK,MAAM;QAAE,OAAO,GAAG,OAAO,CAAC,KAAK,GAAG,WAAW,IAAI,CAAC;IAC/D,IAAI,OAAO;QAAE,OAAO,GAAG,OAAO,CAAC,KAAK,GAAG,WAAW,IAAI,CAAC;IAEvD,MAAM,KAAK,GAAG,eAAe,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAClD,MAAM,IAAI,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,OAAO,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACxH,OAAO,GAAG,KAAK,GAAG,IAAI,GAAG,CAAC;AAC5B,CAAC"}
|
|
@@ -1,7 +1,23 @@
|
|
|
1
1
|
import type { SelectFieldOptions } from './types.js';
|
|
2
2
|
import type { BijouContext } from '../../ports/context.js';
|
|
3
|
+
/**
|
|
4
|
+
* Options for the multi-select field.
|
|
5
|
+
*
|
|
6
|
+
* @typeParam T - Type of each option's value.
|
|
7
|
+
*/
|
|
3
8
|
export interface MultiselectOptions<T = string> extends SelectFieldOptions<T> {
|
|
9
|
+
/** Bijou context for IO, styling, and mode detection. */
|
|
4
10
|
ctx?: BijouContext;
|
|
5
11
|
}
|
|
12
|
+
/**
|
|
13
|
+
* Prompt the user to choose zero or more items from a list.
|
|
14
|
+
*
|
|
15
|
+
* Uses arrow-key navigation with space-to-toggle in interactive TTY mode,
|
|
16
|
+
* or a comma-separated numeric input fallback for pipe and accessible modes.
|
|
17
|
+
*
|
|
18
|
+
* @typeParam T - Type of each option's value.
|
|
19
|
+
* @param options - Multiselect field configuration.
|
|
20
|
+
* @returns Array of selected option values.
|
|
21
|
+
*/
|
|
6
22
|
export declare function multiselect<T = string>(options: MultiselectOptions<T>): Promise<T[]>;
|
|
7
23
|
//# sourceMappingURL=multiselect.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"multiselect.d.ts","sourceRoot":"","sources":["../../../src/core/forms/multiselect.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"multiselect.d.ts","sourceRoot":"","sources":["../../../src/core/forms/multiselect.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAI3D;;;;GAIG;AACH,MAAM,WAAW,kBAAkB,CAAC,CAAC,GAAG,MAAM,CAAE,SAAQ,kBAAkB,CAAC,CAAC,CAAC;IAC3E,yDAAyD;IACzD,GAAG,CAAC,EAAE,YAAY,CAAC;CACpB;AAED;;;;;;;;;GASG;AACH,wBAAsB,WAAW,CAAC,CAAC,GAAG,MAAM,EAAE,OAAO,EAAE,kBAAkB,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC,CAU1F"}
|
|
@@ -1,27 +1,34 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { resolveCtx } from '../resolve-ctx.js';
|
|
2
|
+
import { formatFormTitle, renderNumberedOptions, terminalRenderer, formDispatch, createStyledFn, createBoldFn } from './form-utils.js';
|
|
3
|
+
/**
|
|
4
|
+
* Prompt the user to choose zero or more items from a list.
|
|
5
|
+
*
|
|
6
|
+
* Uses arrow-key navigation with space-to-toggle in interactive TTY mode,
|
|
7
|
+
* or a comma-separated numeric input fallback for pipe and accessible modes.
|
|
8
|
+
*
|
|
9
|
+
* @typeParam T - Type of each option's value.
|
|
10
|
+
* @param options - Multiselect field configuration.
|
|
11
|
+
* @returns Array of selected option values.
|
|
12
|
+
*/
|
|
2
13
|
export async function multiselect(options) {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
}
|
|
8
|
-
return numberedMultiselect(options, mode, ctx);
|
|
14
|
+
if (options.options.length === 0)
|
|
15
|
+
return [];
|
|
16
|
+
const ctx = resolveCtx(options.ctx);
|
|
17
|
+
return formDispatch(ctx, (c) => interactiveMultiselect(options, c), (c) => numberedMultiselect(options, c));
|
|
9
18
|
}
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
24
|
-
const prompt = mode === 'accessible'
|
|
19
|
+
/**
|
|
20
|
+
* Display options as a numbered list and accept comma-separated numeric input.
|
|
21
|
+
*
|
|
22
|
+
* Used as the fallback for non-interactive or accessible modes.
|
|
23
|
+
*
|
|
24
|
+
* @param options - Multiselect field configuration.
|
|
25
|
+
* @param ctx - Bijou context.
|
|
26
|
+
* @returns Array of selected option values.
|
|
27
|
+
*/
|
|
28
|
+
async function numberedMultiselect(options, ctx) {
|
|
29
|
+
ctx.io.write(formatFormTitle(options.title, ctx) + '\n');
|
|
30
|
+
renderNumberedOptions(options.options, ctx);
|
|
31
|
+
const prompt = ctx.mode === 'accessible'
|
|
25
32
|
? 'Enter numbers separated by commas: '
|
|
26
33
|
: 'Enter numbers (comma-separated): ';
|
|
27
34
|
const answer = await ctx.io.question(prompt);
|
|
@@ -30,27 +37,40 @@ async function numberedMultiselect(options, mode, ctx) {
|
|
|
30
37
|
.filter((i) => i >= 0 && i < options.options.length);
|
|
31
38
|
return indices.map((i) => options.options[i].value);
|
|
32
39
|
}
|
|
40
|
+
/**
|
|
41
|
+
* Display a keyboard-navigable multi-select menu using raw terminal input.
|
|
42
|
+
*
|
|
43
|
+
* Supports arrow keys and j/k for navigation, Space to toggle selection,
|
|
44
|
+
* Enter to confirm, Ctrl+C or Escape to cancel (returns empty array).
|
|
45
|
+
*
|
|
46
|
+
* @param options - Multiselect field configuration.
|
|
47
|
+
* @param ctx - Bijou context.
|
|
48
|
+
* @returns Array of selected option values in index order.
|
|
49
|
+
*/
|
|
33
50
|
async function interactiveMultiselect(options, ctx) {
|
|
34
51
|
const noColor = ctx.theme.noColor;
|
|
35
52
|
const t = ctx.theme;
|
|
36
|
-
const styledFn = (
|
|
53
|
+
const styledFn = createStyledFn(ctx);
|
|
54
|
+
const boldFn = createBoldFn(ctx);
|
|
55
|
+
const term = terminalRenderer(ctx);
|
|
37
56
|
let cursor = 0;
|
|
38
57
|
const selected = new Set();
|
|
39
58
|
function render() {
|
|
40
|
-
const label =
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
ctx.io.write(`\r\x1b[K${label} ${styledFn(t.theme.semantic.muted, '(space to toggle, enter to confirm)')}\n`);
|
|
59
|
+
const label = formatFormTitle(options.title, ctx);
|
|
60
|
+
term.hideCursor();
|
|
61
|
+
const hint = styledFn(t.theme.semantic.muted, '(space to toggle, enter to confirm)');
|
|
62
|
+
term.writeLine(`${label} ${hint}`);
|
|
45
63
|
for (let i = 0; i < options.options.length; i++) {
|
|
46
64
|
const opt = options.options[i];
|
|
47
65
|
const isCurrent = i === cursor;
|
|
48
66
|
const isSelected = selected.has(i);
|
|
49
67
|
const prefix = isCurrent ? '\u276f' : ' ';
|
|
50
68
|
const check = isSelected ? '\u25c9' : '\u25cb';
|
|
51
|
-
const desc = opt.description
|
|
69
|
+
const desc = opt.description
|
|
70
|
+
? styledFn(t.theme.semantic.muted, ` \u2014 ${opt.description}`)
|
|
71
|
+
: '';
|
|
52
72
|
if (isCurrent && !noColor) {
|
|
53
|
-
ctx.io.write(`\x1b[K ${styledFn(t.theme.semantic.info, prefix)} ${styledFn(t.theme.semantic.info, check)} ${
|
|
73
|
+
ctx.io.write(`\x1b[K ${styledFn(t.theme.semantic.info, prefix)} ${styledFn(t.theme.semantic.info, check)} ${boldFn(opt.label)}${desc}\n`);
|
|
54
74
|
}
|
|
55
75
|
else if (isSelected && !noColor) {
|
|
56
76
|
ctx.io.write(`\x1b[K ${prefix} ${styledFn(t.theme.semantic.success, check)} ${opt.label}${desc}\n`);
|
|
@@ -62,20 +82,16 @@ async function interactiveMultiselect(options, ctx) {
|
|
|
62
82
|
}
|
|
63
83
|
function clearRender() {
|
|
64
84
|
const totalLines = options.options.length + 1;
|
|
65
|
-
|
|
85
|
+
term.moveUp(totalLines);
|
|
66
86
|
}
|
|
67
87
|
function cleanup() {
|
|
68
88
|
clearRender();
|
|
69
89
|
const totalLines = options.options.length + 1;
|
|
70
|
-
|
|
71
|
-
ctx.io.write(`\x1b[K\n`);
|
|
72
|
-
ctx.io.write(`\x1b[${totalLines}A`);
|
|
90
|
+
term.clearBlock(totalLines);
|
|
73
91
|
const selectedLabels = [...selected].sort().map((i) => options.options[i].label).join(', ');
|
|
74
|
-
const label =
|
|
75
|
-
? `? ${options.title} ${selectedLabels}`
|
|
76
|
-
: styledFn(t.theme.semantic.info, '? ') + ctx.style.bold(options.title) + ' ' + styledFn(t.theme.semantic.info, selectedLabels);
|
|
92
|
+
const label = formatFormTitle(options.title, ctx) + ' ' + styledFn(t.theme.semantic.info, selectedLabels);
|
|
77
93
|
ctx.io.write(`\x1b[K${label}\n`);
|
|
78
|
-
|
|
94
|
+
term.showCursor();
|
|
79
95
|
}
|
|
80
96
|
render();
|
|
81
97
|
return new Promise((resolve) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"multiselect.js","sourceRoot":"","sources":["../../../src/core/forms/multiselect.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"multiselect.js","sourceRoot":"","sources":["../../../src/core/forms/multiselect.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,24 @@
|
|
|
1
1
|
import type { SelectFieldOptions } from './types.js';
|
|
2
2
|
import type { BijouContext } from '../../ports/context.js';
|
|
3
|
+
/**
|
|
4
|
+
* Options for the single-select field.
|
|
5
|
+
*
|
|
6
|
+
* @typeParam T - Type of each option's value.
|
|
7
|
+
*/
|
|
3
8
|
export interface SelectOptions<T = string> extends SelectFieldOptions<T> {
|
|
9
|
+
/** Bijou context for IO, styling, and mode detection. */
|
|
4
10
|
ctx?: BijouContext;
|
|
5
11
|
}
|
|
12
|
+
/**
|
|
13
|
+
* Prompt the user to choose one item from a list.
|
|
14
|
+
*
|
|
15
|
+
* Uses arrow-key navigation in interactive TTY mode, or a numbered list
|
|
16
|
+
* fallback for pipe and accessible modes.
|
|
17
|
+
*
|
|
18
|
+
* @typeParam T - Type of each option's value.
|
|
19
|
+
* @param options - Select field configuration.
|
|
20
|
+
* @returns The value of the selected option.
|
|
21
|
+
* @throws {Error} If `options.options` is empty.
|
|
22
|
+
*/
|
|
6
23
|
export declare function select<T = string>(options: SelectOptions<T>): Promise<T>;
|
|
7
24
|
//# sourceMappingURL=select.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"select.d.ts","sourceRoot":"","sources":["../../../src/core/forms/select.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAgB,MAAM,YAAY,CAAC;AACnE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"select.d.ts","sourceRoot":"","sources":["../../../src/core/forms/select.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAgB,MAAM,YAAY,CAAC;AACnE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAI3D;;;;GAIG;AACH,MAAM,WAAW,aAAa,CAAC,CAAC,GAAG,MAAM,CAAE,SAAQ,kBAAkB,CAAC,CAAC,CAAC;IACtE,yDAAyD;IACzD,GAAG,CAAC,EAAE,YAAY,CAAC;CACpB;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,MAAM,CAAC,CAAC,GAAG,MAAM,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAY9E"}
|
|
@@ -1,28 +1,36 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { resolveCtx } from '../resolve-ctx.js';
|
|
2
|
+
import { formatFormTitle, renderNumberedOptions, terminalRenderer, formDispatch, createStyledFn, createBoldFn } from './form-utils.js';
|
|
3
|
+
/**
|
|
4
|
+
* Prompt the user to choose one item from a list.
|
|
5
|
+
*
|
|
6
|
+
* Uses arrow-key navigation in interactive TTY mode, or a numbered list
|
|
7
|
+
* fallback for pipe and accessible modes.
|
|
8
|
+
*
|
|
9
|
+
* @typeParam T - Type of each option's value.
|
|
10
|
+
* @param options - Select field configuration.
|
|
11
|
+
* @returns The value of the selected option.
|
|
12
|
+
* @throws {Error} If `options.options` is empty.
|
|
13
|
+
*/
|
|
2
14
|
export async function select(options) {
|
|
3
|
-
const ctx = options.ctx
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
return interactiveSelect(options, ctx);
|
|
15
|
+
const ctx = resolveCtx(options.ctx);
|
|
16
|
+
if (options.options.length === 0) {
|
|
17
|
+
throw new Error('select() requires at least one option');
|
|
7
18
|
}
|
|
8
|
-
return
|
|
19
|
+
return formDispatch(ctx, (c) => interactiveSelect(options, c), (c) => numberedSelect(options, c));
|
|
9
20
|
}
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
ctx.io.write(`${num} ${opt.label}${desc}\n`);
|
|
24
|
-
}
|
|
25
|
-
const prompt = mode === 'accessible' ? 'Enter number: ' : '> ';
|
|
21
|
+
/**
|
|
22
|
+
* Display options as a numbered list and accept numeric input.
|
|
23
|
+
*
|
|
24
|
+
* Used as the fallback for non-interactive or accessible modes.
|
|
25
|
+
*
|
|
26
|
+
* @param options - Select field configuration.
|
|
27
|
+
* @param ctx - Bijou context.
|
|
28
|
+
* @returns The value of the selected option.
|
|
29
|
+
*/
|
|
30
|
+
async function numberedSelect(options, ctx) {
|
|
31
|
+
ctx.io.write(formatFormTitle(options.title, ctx) + '\n');
|
|
32
|
+
renderNumberedOptions(options.options, ctx);
|
|
33
|
+
const prompt = ctx.mode === 'accessible' ? 'Enter number: ' : '> ';
|
|
26
34
|
const answer = await ctx.io.question(prompt);
|
|
27
35
|
const idx = parseInt(answer.trim(), 10) - 1;
|
|
28
36
|
if (idx >= 0 && idx < options.options.length) {
|
|
@@ -30,24 +38,34 @@ async function numberedSelect(options, mode, ctx) {
|
|
|
30
38
|
}
|
|
31
39
|
return options.defaultValue ?? options.options[0].value;
|
|
32
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* Display a keyboard-navigable select menu using raw terminal input.
|
|
43
|
+
*
|
|
44
|
+
* Supports arrow keys and j/k for navigation, Enter to confirm,
|
|
45
|
+
* Ctrl+C or Escape to cancel (returns default or first option).
|
|
46
|
+
*
|
|
47
|
+
* @param options - Select field configuration.
|
|
48
|
+
* @param ctx - Bijou context.
|
|
49
|
+
* @returns The value of the selected option.
|
|
50
|
+
*/
|
|
33
51
|
async function interactiveSelect(options, ctx) {
|
|
34
52
|
const noColor = ctx.theme.noColor;
|
|
35
53
|
const t = ctx.theme;
|
|
36
|
-
const styledFn = (
|
|
54
|
+
const styledFn = createStyledFn(ctx);
|
|
55
|
+
const boldFn = createBoldFn(ctx);
|
|
56
|
+
const term = terminalRenderer(ctx);
|
|
37
57
|
let cursor = 0;
|
|
38
58
|
function render() {
|
|
39
|
-
const label =
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
ctx.io.write(`\x1b[?25l`);
|
|
43
|
-
ctx.io.write(`\r\x1b[K${label}\n`);
|
|
59
|
+
const label = formatFormTitle(options.title, ctx);
|
|
60
|
+
term.hideCursor();
|
|
61
|
+
term.writeLine(label);
|
|
44
62
|
for (let i = 0; i < options.options.length; i++) {
|
|
45
63
|
const opt = options.options[i];
|
|
46
64
|
const isCurrent = i === cursor;
|
|
47
65
|
const prefix = isCurrent ? '\u276f' : ' ';
|
|
48
66
|
const desc = opt.description ? styledFn(t.theme.semantic.muted, ` \u2014 ${opt.description}`) : '';
|
|
49
67
|
if (isCurrent && !noColor) {
|
|
50
|
-
ctx.io.write(`\x1b[K ${styledFn(t.theme.semantic.info, prefix)} ${
|
|
68
|
+
ctx.io.write(`\x1b[K ${styledFn(t.theme.semantic.info, prefix)} ${boldFn(opt.label)}${desc}\n`);
|
|
51
69
|
}
|
|
52
70
|
else {
|
|
53
71
|
ctx.io.write(`\x1b[K ${prefix} ${opt.label}${desc}\n`);
|
|
@@ -56,20 +74,16 @@ async function interactiveSelect(options, ctx) {
|
|
|
56
74
|
}
|
|
57
75
|
function clearRender() {
|
|
58
76
|
const totalLines = options.options.length + 1;
|
|
59
|
-
|
|
77
|
+
term.moveUp(totalLines);
|
|
60
78
|
}
|
|
61
79
|
function cleanup() {
|
|
62
80
|
clearRender();
|
|
63
81
|
const totalLines = options.options.length + 1;
|
|
64
|
-
|
|
65
|
-
ctx.io.write(`\x1b[K\n`);
|
|
66
|
-
ctx.io.write(`\x1b[${totalLines}A`);
|
|
82
|
+
term.clearBlock(totalLines);
|
|
67
83
|
const selected = options.options[cursor];
|
|
68
|
-
const label =
|
|
69
|
-
? `? ${options.title} ${selected.label}`
|
|
70
|
-
: styledFn(t.theme.semantic.info, '? ') + ctx.style.bold(options.title) + ' ' + styledFn(t.theme.semantic.info, selected.label);
|
|
84
|
+
const label = formatFormTitle(options.title, ctx) + ' ' + styledFn(t.theme.semantic.info, selected.label);
|
|
71
85
|
ctx.io.write(`\x1b[K${label}\n`);
|
|
72
|
-
|
|
86
|
+
term.showCursor();
|
|
73
87
|
}
|
|
74
88
|
render();
|
|
75
89
|
return new Promise((resolve) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"select.js","sourceRoot":"","sources":["../../../src/core/forms/select.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"select.js","sourceRoot":"","sources":["../../../src/core/forms/select.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,12 +1,31 @@
|
|
|
1
1
|
import type { FieldOptions } from './types.js';
|
|
2
2
|
import type { BijouContext } from '../../ports/context.js';
|
|
3
|
+
/**
|
|
4
|
+
* Options for the multi-line textarea field.
|
|
5
|
+
*/
|
|
3
6
|
export interface TextareaOptions extends FieldOptions<string> {
|
|
7
|
+
/** Placeholder text shown when the textarea is empty. */
|
|
4
8
|
placeholder?: string;
|
|
9
|
+
/** Maximum character count (including newlines). */
|
|
5
10
|
maxLength?: number;
|
|
11
|
+
/** Display line numbers in the gutter. Default: false. */
|
|
6
12
|
showLineNumbers?: boolean;
|
|
13
|
+
/** Visible editor height in lines. Default: 6. */
|
|
7
14
|
height?: number;
|
|
15
|
+
/** Render width in columns. Default: 80. */
|
|
8
16
|
width?: number;
|
|
17
|
+
/** Bijou context for IO, styling, and mode detection. */
|
|
9
18
|
ctx?: BijouContext;
|
|
10
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* Prompt the user for multi-line text input.
|
|
22
|
+
*
|
|
23
|
+
* In interactive TTY mode, renders a scrollable editor with cursor
|
|
24
|
+
* navigation, optional line numbers, and a character count status bar.
|
|
25
|
+
* Falls back to a single-line question for pipe and accessible modes.
|
|
26
|
+
*
|
|
27
|
+
* @param options - Textarea field configuration.
|
|
28
|
+
* @returns The entered text (newline-joined), or the default/empty string on cancel.
|
|
29
|
+
*/
|
|
11
30
|
export declare function textarea(options: TextareaOptions): Promise<string>;
|
|
12
31
|
//# sourceMappingURL=textarea.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"textarea.d.ts","sourceRoot":"","sources":["../../../src/core/forms/textarea.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"textarea.d.ts","sourceRoot":"","sources":["../../../src/core/forms/textarea.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAI3D;;GAEG;AACH,MAAM,WAAW,eAAgB,SAAQ,YAAY,CAAC,MAAM,CAAC;IAC3D,yDAAyD;IACzD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oDAAoD;IACpD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0DAA0D;IAC1D,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,kDAAkD;IAClD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4CAA4C;IAC5C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yDAAyD;IACzD,GAAG,CAAC,EAAE,YAAY,CAAC;CACpB;AAED;;;;;;;;;GASG;AACH,wBAAsB,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CAQxE"}
|