bare-tui-form 0.0.0 → 0.0.2

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/theme.js ADDED
@@ -0,0 +1,86 @@
1
+ // theme — how a form's chrome is styled.
2
+ //
3
+ // A theme is a small bag of style functions (string → string) plus a couple of
4
+ // literal markers. Every field renders its label, description, error, and
5
+ // validating line through the theme, and the form renders its title and help
6
+ // footer through it. Pass a partial theme to form.create({ theme }) and it's
7
+ // merged over these defaults, so you override only what you care about:
8
+ //
9
+ // form.create({
10
+ // theme: {
11
+ // title: (s) => style().bold(true).foreground('magenta').render(s),
12
+ // error: (s) => style().foreground('yellow').render(s),
13
+ // spinner: { frames: 'line', fps: 12 }
14
+ // },
15
+ // fields: [...]
16
+ // })
17
+ //
18
+ // Field *controls* themselves (the textinput cursor, the select dropdown
19
+ // colours) are styled by bare-tui, not here — this theme covers the form chrome.
20
+ const { style } = require('bare-tui')
21
+
22
+ const defaultTheme = {
23
+ title: (s) => style().bold(true).render(s),
24
+ sectionTitle: (s) => style().bold(true).render(s), // a nested-object section heading
25
+ label: (s) => s,
26
+ labelFocused: (s) => style().bold(true).render(s),
27
+ description: (s) => style().faint(true).render(s),
28
+ error: (s) => style().foreground('red').render(s),
29
+ validating: (s) => style().foreground('cyan').render(s),
30
+ help: (s) => style().faint(true).render(s),
31
+
32
+ requiredMarker: ' *', // appended to a required field's label
33
+ errorPrefix: '✗ ', // prefixed to an error message
34
+ spinner: {}, // { frames, fps } for the validating spinner; see startSpinner
35
+
36
+ // Optional: wrap the whole rendered form in a border / background / padding.
37
+ // May be a function (content, { width, title }) => string for full control, or
38
+ // a plain descriptor object that merge() turns into one via frame() — e.g.
39
+ // frame: { border: 'rounded', color: '#a78bfa', padding: [1, 2], width: 56 }
40
+ // The form measures the rows it adds so scrolling still fits the terminal.
41
+ frame: null
42
+ }
43
+
44
+ // Build a frame function from a descriptor, so the common case is one line
45
+ // instead of a hand-written style() chain:
46
+ //
47
+ // form.frame({ border: 'rounded', color, background, padding, width, align })
48
+ //
49
+ // `border` is a name ('normal' | 'rounded' | 'thick' | 'double') or a bare-tui
50
+ // border char object; `color` paints the border line; `background` fills the box
51
+ // (content keeps its own colours); `padding` is a number or [v, h] / [t, r, b, l].
52
+ function frame(opts = {}) {
53
+ const border = typeof opts.border === 'string' ? style.borders[opts.border] : opts.border
54
+ return (content) => {
55
+ let s = style()
56
+ if (border) s = s.border(border)
57
+ if (opts.color) s = s.borderForeground(opts.color)
58
+ if (opts.background) s = s.background(opts.background)
59
+ if (opts.padding !== undefined && opts.padding !== null) {
60
+ s = s.padding(...[].concat(opts.padding))
61
+ }
62
+ if (opts.width) s = s.width(opts.width)
63
+ if (opts.align) s = s.align(opts.align)
64
+ return s.render(content)
65
+ }
66
+ }
67
+
68
+ // Ready-made, palette-neutral frame presets (drop straight into theme.frame):
69
+ // form.create({ theme: { frame: form.frames.rounded } })
70
+ const frames = {
71
+ normal: frame({ border: 'normal', padding: [0, 1] }),
72
+ rounded: frame({ border: 'rounded', padding: [0, 1] }),
73
+ thick: frame({ border: 'thick', padding: [0, 1] }),
74
+ double: frame({ border: 'double', padding: [0, 1] })
75
+ }
76
+
77
+ // Shallow-merge a user theme over the defaults. Functions and markers replace
78
+ // wholesale; `spinner` is replaced as a unit when provided. A `frame` given as a
79
+ // plain descriptor object is normalized to a frame function here.
80
+ function merge(user) {
81
+ const merged = { ...defaultTheme, ...(user || {}) }
82
+ if (merged.frame && typeof merged.frame === 'object') merged.frame = frame(merged.frame)
83
+ return merged
84
+ }
85
+
86
+ module.exports = { defaultTheme, merge, frame, frames }