@nan0web/ui 1.12.3 → 3.1.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.
- package/package.json +29 -20
- package/src/Component/index.js +1 -5
- package/src/Model/Element.js +183 -0
- package/src/Theme/AppTheme.js +19 -0
- package/src/Theme/CustomTheme.js +32 -0
- package/src/Theme/DarkLightTheme.js +34 -0
- package/src/Theme/Theme.js +25 -0
- package/src/Theme/atoms/Avatar.js +20 -0
- package/src/Theme/atoms/Badge.js +28 -0
- package/src/Theme/atoms/Button.js +88 -0
- package/src/Theme/atoms/Checkbox.js +26 -0
- package/src/Theme/atoms/Input.js +28 -0
- package/src/Theme/atoms/Radio.js +26 -0
- package/src/Theme/atoms/Select.js +16 -0
- package/src/Theme/atoms/TextArea.js +17 -0
- package/src/Theme/atoms/Typography.js +26 -0
- package/src/Theme/atoms/index.js +11 -0
- package/src/Theme/createTheme.js +22 -0
- package/src/Theme/index.js +20 -0
- package/src/Theme/molecules/Card.js +24 -0
- package/src/Theme/molecules/index.js +3 -0
- package/src/Theme/organisms/Modal.js +24 -0
- package/src/Theme/organisms/index.js +3 -0
- package/src/Theme/presets/HighContrastTheme.js +65 -0
- package/src/Theme/presets/NightTheme.js +66 -0
- package/src/Theme/presets/index.js +4 -0
- package/src/Theme/tokens.js +115 -0
- package/src/core/InputAdapter.js +1 -2
- package/src/core/Intent.js +22 -8
- package/src/core/Message/Message.js +3 -0
- package/src/core/OutputAdapter.js +9 -13
- package/src/core/index.js +7 -4
- package/src/domain/ModelAsApp.js +1 -1
- package/src/domain/app/IntentAuditor.js +53 -0
- package/src/domain/app/JsIntentAuditor.js +145 -0
- package/src/domain/app/PyIntentAuditor.js +144 -0
- package/src/domain/app/SnapshotAuditor.js +8 -8
- package/src/domain/components/ShellModel.js +2 -2
- package/src/index.js +35 -9
- package/src/inspect.js +3 -0
- package/src/utils/format.js +21 -0
- package/src/utils/processI18n.js +27 -0
- package/src/utils/resolveContext.js +79 -0
- package/types/Component/index.d.ts +1 -5
- package/types/Model/Element.d.ts +87 -0
- package/types/Theme/AppTheme.d.ts +14 -0
- package/types/Theme/CustomTheme.d.ts +21 -0
- package/types/Theme/DarkLightTheme.d.ts +16 -0
- package/types/Theme/Theme.d.ts +18 -0
- package/types/Theme/atoms/Avatar.d.ts +14 -0
- package/types/Theme/atoms/Badge.d.ts +22 -0
- package/types/Theme/atoms/Button.d.ts +144 -0
- package/types/Theme/atoms/Checkbox.d.ts +20 -0
- package/types/Theme/atoms/Input.d.ts +22 -0
- package/types/Theme/atoms/Radio.d.ts +20 -0
- package/types/Theme/atoms/Select.d.ts +15 -0
- package/types/Theme/atoms/TextArea.d.ts +17 -0
- package/types/Theme/atoms/Typography.d.ts +47 -0
- package/types/Theme/atoms/index.d.ts +10 -0
- package/types/Theme/createTheme.d.ts +7 -0
- package/types/Theme/index.d.ts +10 -0
- package/types/Theme/molecules/Card.d.ts +18 -0
- package/types/Theme/molecules/index.d.ts +2 -0
- package/types/Theme/organisms/Modal.d.ts +18 -0
- package/types/Theme/organisms/index.d.ts +2 -0
- package/types/Theme/presets/HighContrastTheme.d.ts +2 -0
- package/types/Theme/presets/NightTheme.d.ts +2 -0
- package/types/Theme/presets/index.d.ts +3 -0
- package/types/Theme/tokens.d.ts +119 -0
- package/types/core/Intent.d.ts +10 -7
- package/types/core/Message/Message.d.ts +3 -0
- package/types/core/OutputAdapter.d.ts +2 -4
- package/types/core/index.d.ts +5 -2
- package/types/domain/Document.d.ts +2 -1
- package/types/domain/FooterModel.d.ts +2 -1
- package/types/domain/ModelAsApp.d.ts +48 -48
- package/types/domain/app/IntentAuditor.d.ts +23 -0
- package/types/domain/app/JsIntentAuditor.d.ts +22 -0
- package/types/domain/app/PyIntentAuditor.d.ts +22 -0
- package/types/domain/app/SnapshotAuditor.d.ts +5 -6
- package/types/domain/components/ShellModel.d.ts +1 -5
- package/types/index.d.ts +7 -9
- package/types/inspect.d.ts +3 -0
- package/types/utils/format.d.ts +5 -0
- package/types/utils/processI18n.d.ts +8 -0
- package/types/utils/resolveContext.d.ts +21 -0
- package/src/App/Command/DepsCommand.js +0 -24
- package/src/App/Core/CoreApp.js +0 -125
- package/src/App/Core/UI.js +0 -63
- package/src/App/Core/Widget.js +0 -61
- package/src/App/Core/index.js +0 -11
- package/src/App/Scenario.js +0 -45
- package/src/App/User/Command/Message.js +0 -3
- package/src/App/User/Command/index.js +0 -5
- package/src/App/User/UserApp.js +0 -85
- package/src/App/User/UserUI.js +0 -20
- package/src/App/User/index.js +0 -9
- package/src/App/index.js +0 -14
- package/src/Component/Process/Input.js +0 -63
- package/src/Component/Process/Process.js +0 -24
- package/src/Component/Process/index.js +0 -5
- package/src/Component/Welcome/Input.js +0 -48
- package/src/Component/Welcome/Welcome.js +0 -22
- package/src/Component/Welcome/index.js +0 -5
- package/src/Frame/Frame.js +0 -608
- package/src/Frame/Props.js +0 -96
- package/src/StdIn.js +0 -100
- package/src/StdOut.js +0 -95
- package/src/View/RenderOptions.js +0 -48
- package/src/View/View.js +0 -306
- package/src/core/Message/index.js +0 -6
- package/types/App/Command/DepsCommand.d.ts +0 -14
- package/types/App/Core/CoreApp.d.ts +0 -70
- package/types/App/Core/UI.d.ts +0 -38
- package/types/App/Core/Widget.d.ts +0 -39
- package/types/App/Core/index.d.ts +0 -10
- package/types/App/Scenario.d.ts +0 -26
- package/types/App/User/Command/Message.d.ts +0 -2
- package/types/App/User/Command/index.d.ts +0 -3
- package/types/App/User/UserApp.d.ts +0 -41
- package/types/App/User/UserUI.d.ts +0 -9
- package/types/App/User/index.d.ts +0 -8
- package/types/App/index.d.ts +0 -12
- package/types/Component/Process/Input.d.ts +0 -48
- package/types/Component/Process/Process.d.ts +0 -13
- package/types/Component/Process/index.d.ts +0 -4
- package/types/Component/Welcome/Input.d.ts +0 -34
- package/types/Component/Welcome/Welcome.d.ts +0 -13
- package/types/Component/Welcome/index.d.ts +0 -4
- package/types/Frame/Frame.d.ts +0 -186
- package/types/Frame/Props.d.ts +0 -77
- package/types/StdIn.d.ts +0 -62
- package/types/StdOut.d.ts +0 -52
- package/types/View/RenderOptions.d.ts +0 -29
- package/types/View/View.d.ts +0 -124
- package/types/core/Message/index.d.ts +0 -4
package/src/Frame/Frame.js
DELETED
|
@@ -1,608 +0,0 @@
|
|
|
1
|
-
import stringWidth from 'string-width'
|
|
2
|
-
import { to, typeOf, empty } from '@nan0web/types'
|
|
3
|
-
import FrameProps from './Props.js'
|
|
4
|
-
|
|
5
|
-
export class FrameRenderMethod {
|
|
6
|
-
static APPEND = 'append'
|
|
7
|
-
static REPLACE = 'replace'
|
|
8
|
-
static VISIBLE = 'visible'
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* @link https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797 - ANSI escape codes
|
|
13
|
-
*/
|
|
14
|
-
export default class Frame {
|
|
15
|
-
/** @type {typeof FrameRenderMethod} */
|
|
16
|
-
static RenderMethod = FrameRenderMethod
|
|
17
|
-
static Props = FrameProps
|
|
18
|
-
/** @type {string} End of line */
|
|
19
|
-
static EOL = '\n'
|
|
20
|
-
/** @type {string} Beginning of line */
|
|
21
|
-
static BOL = '\r'
|
|
22
|
-
/** @type {string} Beginning of frame */
|
|
23
|
-
static BOF = '\x1b[0;0H'
|
|
24
|
-
/** @type {string} Hide cursor */
|
|
25
|
-
static HIDE_CURSOR = '\x1b[?25l'
|
|
26
|
-
/** @type {string} Show cursor */
|
|
27
|
-
static SHOW_CURSOR = '\x1b[?25h'
|
|
28
|
-
/** @type {string} Tab */
|
|
29
|
-
static TAB = '\t'
|
|
30
|
-
/** @type {string} Bold */
|
|
31
|
-
static BOLD = '\x1b[1m'
|
|
32
|
-
/** @type {string} Italic */
|
|
33
|
-
static ITALIC = '\x1b[3m'
|
|
34
|
-
/** @type {string} Underline */
|
|
35
|
-
static UNDERLINE = '\x1b[4m'
|
|
36
|
-
/** @type {string} Strikethrough */
|
|
37
|
-
static STRIKETHROUGH = '\x1b[9m'
|
|
38
|
-
/** @type {string} Reset */
|
|
39
|
-
static RESET = '\x1b[0m'
|
|
40
|
-
/** @type {string} Clear line */
|
|
41
|
-
static CLEAR_LINE = '\x1b[2K'
|
|
42
|
-
/**
|
|
43
|
-
* @example
|
|
44
|
-
* ```js
|
|
45
|
-
* new Frame([
|
|
46
|
-
* ["Hello", "World"],
|
|
47
|
-
* [["Hello", { color: "red", bgColor: "#009" }], "World"],
|
|
48
|
-
* ["<b i fg=#900>Hello</b>", "<i>World</i>"],
|
|
49
|
-
* ])
|
|
50
|
-
* ```
|
|
51
|
-
* @type {string[][]|any[][]}
|
|
52
|
-
*/
|
|
53
|
-
value
|
|
54
|
-
/** @type {FrameProps} */
|
|
55
|
-
defaultProps
|
|
56
|
-
/** @type {string} */
|
|
57
|
-
imprint
|
|
58
|
-
/** @type {number} */
|
|
59
|
-
width
|
|
60
|
-
/** @type {number} */
|
|
61
|
-
height
|
|
62
|
-
/** @type {string} */
|
|
63
|
-
renderMethod
|
|
64
|
-
/**
|
|
65
|
-
* @param {object} [input]
|
|
66
|
-
* @param {string[]|string[][]} [input.value]
|
|
67
|
-
* @param {number} [input.width]
|
|
68
|
-
* @param {number} [input.height]
|
|
69
|
-
* @param {string} [input.imprint]
|
|
70
|
-
* @param {string} [input.renderMethod]
|
|
71
|
-
* @param {FrameProps} [input.defaultProps]
|
|
72
|
-
*/
|
|
73
|
-
constructor(input = {}) {
|
|
74
|
-
// if (typeOf(Array)(input)) {
|
|
75
|
-
// input = { value: input }
|
|
76
|
-
// }
|
|
77
|
-
if (input instanceof Frame) {
|
|
78
|
-
input = { ...input }
|
|
79
|
-
}
|
|
80
|
-
let {
|
|
81
|
-
value = [],
|
|
82
|
-
width = -1,
|
|
83
|
-
height = -1,
|
|
84
|
-
imprint = '',
|
|
85
|
-
renderMethod = 'append',
|
|
86
|
-
defaultProps = new FrameProps(),
|
|
87
|
-
} = input
|
|
88
|
-
if (value instanceof Frame) {
|
|
89
|
-
value = value.value
|
|
90
|
-
}
|
|
91
|
-
if (!typeOf(Array)(value)) {
|
|
92
|
-
throw new TypeError(
|
|
93
|
-
[
|
|
94
|
-
'Frame constructor allows only string[] for rows or string[][] for rows with columns',
|
|
95
|
-
'Provided value:',
|
|
96
|
-
JSON.stringify(value, null, 2),
|
|
97
|
-
].join('\n'),
|
|
98
|
-
)
|
|
99
|
-
}
|
|
100
|
-
value = value.map((row) => {
|
|
101
|
-
if (typeOf(Array)(row)) {
|
|
102
|
-
return row.map(String)
|
|
103
|
-
}
|
|
104
|
-
return [row]
|
|
105
|
-
})
|
|
106
|
-
this.value = value.map((v) => (Array.isArray(v) ? v : [v]))
|
|
107
|
-
this.imprint = String(imprint)
|
|
108
|
-
this.width = width
|
|
109
|
-
this.height = height
|
|
110
|
-
this.renderMethod = renderMethod
|
|
111
|
-
this.defaultProps = defaultProps
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* Get whether the frame is empty.
|
|
115
|
-
* @returns {boolean} True if the frame has no content.
|
|
116
|
-
*/
|
|
117
|
-
get empty() {
|
|
118
|
-
return empty(this.value)
|
|
119
|
-
}
|
|
120
|
-
/**
|
|
121
|
-
* Calculate the visual width of a string.
|
|
122
|
-
* @param {string} str
|
|
123
|
-
* @returns {number} The visual width of the string.
|
|
124
|
-
*/
|
|
125
|
-
lengthOf(str) {
|
|
126
|
-
return stringWidth(str)
|
|
127
|
-
}
|
|
128
|
-
/**
|
|
129
|
-
* Render the frame into a string representation.
|
|
130
|
-
* @param {object} [options]
|
|
131
|
-
* @param {string} [options.method] - Render method to use.
|
|
132
|
-
* @param {FrameProps} [options.props] - Properties to apply during rendering.
|
|
133
|
-
* @returns {string} The rendered frame as a string.
|
|
134
|
-
*/
|
|
135
|
-
render(options = {}) {
|
|
136
|
-
const { method = this.renderMethod, props = this.defaultProps } = options
|
|
137
|
-
let rows = this.value.map((row) => {
|
|
138
|
-
if (typeOf(Array)(row)) {
|
|
139
|
-
row = row.join('')
|
|
140
|
-
}
|
|
141
|
-
return row
|
|
142
|
-
})
|
|
143
|
-
let spacesOn = ''
|
|
144
|
-
if (Frame.BOF === rows[0]) {
|
|
145
|
-
rows = rows.slice(1)
|
|
146
|
-
spacesOn = 'top'
|
|
147
|
-
} else if (Frame.BOF === rows[rows.length - 1]) {
|
|
148
|
-
rows = rows.slice(0, -1)
|
|
149
|
-
spacesOn = 'bottom'
|
|
150
|
-
}
|
|
151
|
-
if (this.height >= 0 && rows.length > this.height) {
|
|
152
|
-
rows = rows.slice(0, this.height)
|
|
153
|
-
}
|
|
154
|
-
if (this.width >= 0 && rows.length > 0) {
|
|
155
|
-
rows = rows.map((row) => {
|
|
156
|
-
if (row.length > this.width) {
|
|
157
|
-
row = row.slice(0, this.width)
|
|
158
|
-
}
|
|
159
|
-
return row
|
|
160
|
-
})
|
|
161
|
-
}
|
|
162
|
-
let carret = ''
|
|
163
|
-
if (method === Frame.RenderMethod.REPLACE) {
|
|
164
|
-
const printedRows = rows.map(
|
|
165
|
-
(row) => row + ' '.repeat(Math.max(0, this.width - this.lengthOf(row))),
|
|
166
|
-
)
|
|
167
|
-
const left = this.height >= 0 ? this.height - rows.length : 0
|
|
168
|
-
const eraser = []
|
|
169
|
-
for (let i = 0; i < left; i++) eraser.push(' '.repeat(this.width))
|
|
170
|
-
carret = Frame.BOF
|
|
171
|
-
if ('bottom' === spacesOn) {
|
|
172
|
-
rows = left > 0 ? [...printedRows, ...eraser] : []
|
|
173
|
-
} else {
|
|
174
|
-
rows = left > 0 ? [...eraser, ...printedRows] : []
|
|
175
|
-
}
|
|
176
|
-
} else if (method === Frame.RenderMethod.APPEND) {
|
|
177
|
-
rows = rows.map((row) => {
|
|
178
|
-
const used = this.lengthOf(row)
|
|
179
|
-
const left = Math.max(0, this.width - used)
|
|
180
|
-
row = row + ' '.repeat(left)
|
|
181
|
-
if (row.length > this.width) row = row.slice(0, this.width)
|
|
182
|
-
return row
|
|
183
|
-
})
|
|
184
|
-
if (this.height >= 0 && rows.length > this.height) {
|
|
185
|
-
rows = rows.slice(0, this.height)
|
|
186
|
-
}
|
|
187
|
-
if (spacesOn) {
|
|
188
|
-
carret = Frame.BOF
|
|
189
|
-
const left = this.height >= 0 ? this.height - rows.length : 0
|
|
190
|
-
const eraser = []
|
|
191
|
-
for (let i = 0; i < left; i++) eraser.push('')
|
|
192
|
-
if (spacesOn === 'top') {
|
|
193
|
-
rows = left > 0 ? [...eraser, ...rows] : []
|
|
194
|
-
} else if (spacesOn === 'bottom') {
|
|
195
|
-
rows = left > 0 ? [...rows, ...eraser] : []
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
} else if (method === Frame.RenderMethod.VISIBLE) {
|
|
199
|
-
// Move cursor up # lines (Math.max(0, Math.min(rows.length, height))) before rendering
|
|
200
|
-
if (spacesOn) {
|
|
201
|
-
let moveUpLines = Math.max(
|
|
202
|
-
0,
|
|
203
|
-
Math.min(rows.length, this.height >= 0 ? this.height : rows.length),
|
|
204
|
-
)
|
|
205
|
-
if (moveUpLines > 0) {
|
|
206
|
-
--moveUpLines
|
|
207
|
-
}
|
|
208
|
-
carret = Frame.cursorUp(moveUpLines)
|
|
209
|
-
}
|
|
210
|
-
rows = rows.map((row) => Frame.clearLine('\r') + row)
|
|
211
|
-
} else {
|
|
212
|
-
if (spacesOn) {
|
|
213
|
-
carret = Frame.BOF
|
|
214
|
-
const left = this.height >= 0 ? this.height - rows.length : 0
|
|
215
|
-
const eraser = []
|
|
216
|
-
for (let i = 0; i < left; i++) eraser.push('')
|
|
217
|
-
if (spacesOn === 'top') {
|
|
218
|
-
rows = left > 0 ? [...eraser, ...rows] : []
|
|
219
|
-
} else if (spacesOn === 'bottom') {
|
|
220
|
-
rows = left > 0 ? [...rows, ...eraser] : []
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
if ('bottom' === spacesOn) {
|
|
225
|
-
this.imprint = rows.join('\n') + carret
|
|
226
|
-
} else {
|
|
227
|
-
this.imprint = carret + rows.join('\n')
|
|
228
|
-
}
|
|
229
|
-
return this.imprint
|
|
230
|
-
}
|
|
231
|
-
#render1(options = {}) {
|
|
232
|
-
const { method = this.renderMethod, props = this.defaultProps } = options
|
|
233
|
-
|
|
234
|
-
/**
|
|
235
|
-
* Helper to apply CLI style codes.
|
|
236
|
-
* @param {string} str
|
|
237
|
-
* @param {object} style
|
|
238
|
-
* @returns {string}
|
|
239
|
-
*/
|
|
240
|
-
function applyStyle(str, style = {}) {
|
|
241
|
-
let out = str
|
|
242
|
-
let prefix = ''
|
|
243
|
-
let suffix = Frame.RESET
|
|
244
|
-
|
|
245
|
-
if (style.bold) prefix += Frame.BOLD
|
|
246
|
-
if (style.italic) prefix += Frame.ITALIC
|
|
247
|
-
if (style.underline) prefix += Frame.UNDERLINE
|
|
248
|
-
if (style.strikethrough) prefix += Frame.STRIKETHROUGH
|
|
249
|
-
|
|
250
|
-
// Color
|
|
251
|
-
if (style.color) {
|
|
252
|
-
const color = style.color
|
|
253
|
-
if (/^#[0-9a-f]{3,6}$/i.test(color)) {
|
|
254
|
-
// 24-bit color
|
|
255
|
-
const hex = color.replace('#', '')
|
|
256
|
-
const rgb =
|
|
257
|
-
hex.length === 3
|
|
258
|
-
? [0, 1, 2].map((i) => parseInt(hex[i] + hex[i], 16))
|
|
259
|
-
: [0, 2, 4].map((i) => parseInt(hex.slice(i, i + 2), 16))
|
|
260
|
-
prefix += `\x1b[38;2;${rgb[0]};${rgb[1]};${rgb[2]}m`
|
|
261
|
-
} else if (/^\d+$/.test(color)) {
|
|
262
|
-
prefix += `\x1b[38;5;${color}m`
|
|
263
|
-
} else {
|
|
264
|
-
// Named color, map to 8-bit
|
|
265
|
-
const map = {
|
|
266
|
-
black: 30,
|
|
267
|
-
red: 31,
|
|
268
|
-
green: 32,
|
|
269
|
-
yellow: 33,
|
|
270
|
-
blue: 34,
|
|
271
|
-
magenta: 35,
|
|
272
|
-
cyan: 36,
|
|
273
|
-
white: 37,
|
|
274
|
-
gray: 90,
|
|
275
|
-
grey: 90,
|
|
276
|
-
brightRed: 91,
|
|
277
|
-
brightGreen: 92,
|
|
278
|
-
brightYellow: 93,
|
|
279
|
-
brightBlue: 94,
|
|
280
|
-
brightMagenta: 95,
|
|
281
|
-
brightCyan: 96,
|
|
282
|
-
brightWhite: 97,
|
|
283
|
-
}
|
|
284
|
-
if (map[color]) prefix += `\x1b[${map[color]}m`
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
// BgColor
|
|
288
|
-
if (style.bgColor) {
|
|
289
|
-
const color = style.bgColor
|
|
290
|
-
if (/^#[0-9a-f]{3,6}$/i.test(color)) {
|
|
291
|
-
const hex = color.replace('#', '')
|
|
292
|
-
const rgb =
|
|
293
|
-
hex.length === 3
|
|
294
|
-
? [0, 1, 2].map((i) => parseInt(hex[i] + hex[i], 16))
|
|
295
|
-
: [0, 2, 4].map((i) => parseInt(hex.slice(i, i + 2), 16))
|
|
296
|
-
prefix += `\x1b[48;2;${rgb[0]};${rgb[1]};${rgb[2]}m`
|
|
297
|
-
} else if (/^\d+$/.test(color)) {
|
|
298
|
-
prefix += `\x1b[48;5;${color}m`
|
|
299
|
-
} else {
|
|
300
|
-
const map = {
|
|
301
|
-
black: 40,
|
|
302
|
-
red: 41,
|
|
303
|
-
green: 42,
|
|
304
|
-
yellow: 43,
|
|
305
|
-
blue: 44,
|
|
306
|
-
magenta: 45,
|
|
307
|
-
cyan: 46,
|
|
308
|
-
white: 47,
|
|
309
|
-
gray: 100,
|
|
310
|
-
grey: 100,
|
|
311
|
-
brightRed: 101,
|
|
312
|
-
brightGreen: 102,
|
|
313
|
-
brightYellow: 103,
|
|
314
|
-
brightBlue: 104,
|
|
315
|
-
brightMagenta: 105,
|
|
316
|
-
brightCyan: 106,
|
|
317
|
-
brightWhite: 107,
|
|
318
|
-
}
|
|
319
|
-
if (map[color]) prefix += `\x1b[${map[color]}m`
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
return prefix ? prefix + out + suffix : out
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
/**
|
|
326
|
-
* Merge style objects, rightmost has priority.
|
|
327
|
-
* @param {...object} styles
|
|
328
|
-
* @returns {object}
|
|
329
|
-
*/
|
|
330
|
-
function mergeStyles(...styles) {
|
|
331
|
-
return Object.assign({}, ...styles)
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
/**
|
|
335
|
-
* Parse cell for value and style.
|
|
336
|
-
* @param {any} cell
|
|
337
|
-
* @param {object} inherited
|
|
338
|
-
* @returns {{text: string, style: object}}
|
|
339
|
-
*/
|
|
340
|
-
function parseCell(cell, inherited = {}) {
|
|
341
|
-
if (typeOf(Array)(cell)) {
|
|
342
|
-
if (cell.length === 2 && typeOf(Object)(cell[1])) {
|
|
343
|
-
return { text: String(cell[0]), style: mergeStyles(inherited, cell[1]) }
|
|
344
|
-
}
|
|
345
|
-
return { text: cell.map((c) => parseCell(c, inherited).text).join(''), style: inherited }
|
|
346
|
-
}
|
|
347
|
-
if (typeOf(Object)(cell)) {
|
|
348
|
-
return { text: '', style: mergeStyles(inherited, cell) }
|
|
349
|
-
}
|
|
350
|
-
if (typeof cell === 'string' && cell.startsWith('<') && cell.endsWith('>')) {
|
|
351
|
-
// Simple XML-like tag parser for <b>, <i>, <u>, <s>, <fg=...>, <bg=...>
|
|
352
|
-
let text = cell
|
|
353
|
-
let style = { ...inherited }
|
|
354
|
-
const tagPattern = /<([bius]|fg|bg)(?:=([#\w\d]+))?>|<\/([bius]|fg|bg)>/gi
|
|
355
|
-
let stack = []
|
|
356
|
-
let result = ''
|
|
357
|
-
let lastIndex = 0
|
|
358
|
-
let m
|
|
359
|
-
while ((m = tagPattern.exec(cell))) {
|
|
360
|
-
result += cell.slice(lastIndex, m.index)
|
|
361
|
-
lastIndex = tagPattern.lastIndex
|
|
362
|
-
if (m[1]) {
|
|
363
|
-
// Opening tag
|
|
364
|
-
let tag = m[1]
|
|
365
|
-
let val = m[2]
|
|
366
|
-
let newStyle = { ...(stack.length ? stack[stack.length - 1] : style) }
|
|
367
|
-
switch (tag) {
|
|
368
|
-
case 'b':
|
|
369
|
-
newStyle.bold = true
|
|
370
|
-
break
|
|
371
|
-
case 'i':
|
|
372
|
-
newStyle.italic = true
|
|
373
|
-
break
|
|
374
|
-
case 'u':
|
|
375
|
-
newStyle.underline = true
|
|
376
|
-
break
|
|
377
|
-
case 's':
|
|
378
|
-
newStyle.strikethrough = true
|
|
379
|
-
break
|
|
380
|
-
case 'fg':
|
|
381
|
-
newStyle.color = val
|
|
382
|
-
break
|
|
383
|
-
case 'bg':
|
|
384
|
-
newStyle.bgColor = val
|
|
385
|
-
break
|
|
386
|
-
}
|
|
387
|
-
stack.push(newStyle)
|
|
388
|
-
} else if (m[3]) {
|
|
389
|
-
// Closing tag
|
|
390
|
-
stack.pop()
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
result += cell.slice(lastIndex)
|
|
394
|
-
let finalStyle = stack.length ? stack[stack.length - 1] : style
|
|
395
|
-
return { text: result, style: finalStyle }
|
|
396
|
-
}
|
|
397
|
-
return { text: String(cell), style: inherited }
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
// Determine frame-level style
|
|
401
|
-
let frameStyle = {}
|
|
402
|
-
if (
|
|
403
|
-
typeOf(Array)(this.value) &&
|
|
404
|
-
this.value.length &&
|
|
405
|
-
typeOf(Object)(this.value[this.value.length - 1])
|
|
406
|
-
) {
|
|
407
|
-
frameStyle = this.value[this.value.length - 1]
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
let rows = this.value
|
|
411
|
-
.filter((row) => !(typeOf(Object)(row) && !typeOf(Array)(row)))
|
|
412
|
-
.map((row) => {
|
|
413
|
-
let rowStyle = frameStyle
|
|
414
|
-
let cells = row
|
|
415
|
-
if (typeOf(Array)(row) && row.length && typeOf(Object)(row[row.length - 1])) {
|
|
416
|
-
rowStyle = mergeStyles(frameStyle, row[row.length - 1])
|
|
417
|
-
cells = row.slice(0, -1)
|
|
418
|
-
}
|
|
419
|
-
if (!typeOf(Array)(cells)) cells = [cells]
|
|
420
|
-
let styled = cells.map((cell) => {
|
|
421
|
-
const { text, style } = parseCell(cell, mergeStyles(props, rowStyle))
|
|
422
|
-
return applyStyle(text, style)
|
|
423
|
-
})
|
|
424
|
-
return styled.join('')
|
|
425
|
-
})
|
|
426
|
-
|
|
427
|
-
if (method === FrameRenderMethod.REPLACE) {
|
|
428
|
-
let emptyRows = rows.map((row) => ' '.repeat(this.lengthOf(row)))
|
|
429
|
-
if (rows.length > this.height) {
|
|
430
|
-
emptyRows = emptyRows.slice(0, this.height)
|
|
431
|
-
rows = rows.slice(0, this.height)
|
|
432
|
-
}
|
|
433
|
-
rows = [...emptyRows, Frame.BOF, ...rows]
|
|
434
|
-
} else if (method === FrameRenderMethod.APPEND) {
|
|
435
|
-
rows = rows.map((row) => {
|
|
436
|
-
const used = this.lengthOf(row)
|
|
437
|
-
const left = this.width - used
|
|
438
|
-
row = row + ' '.repeat(Math.max(0, left))
|
|
439
|
-
if (stringWidth(row) > this.width) {
|
|
440
|
-
let acc = ''
|
|
441
|
-
let w = 0
|
|
442
|
-
for (let ch of row) {
|
|
443
|
-
let chW = stringWidth(ch)
|
|
444
|
-
if (w + chW > this.width) break
|
|
445
|
-
acc += ch
|
|
446
|
-
w += chW
|
|
447
|
-
}
|
|
448
|
-
row = acc
|
|
449
|
-
}
|
|
450
|
-
return row
|
|
451
|
-
})
|
|
452
|
-
if (rows.length > this.height) {
|
|
453
|
-
rows = rows.slice(0, this.height)
|
|
454
|
-
}
|
|
455
|
-
} else if (method === FrameRenderMethod.VISIBLE) {
|
|
456
|
-
const moveUpLines = Math.max(
|
|
457
|
-
0,
|
|
458
|
-
Math.min(rows.length, this.height >= 0 ? this.height : rows.length),
|
|
459
|
-
)
|
|
460
|
-
rows = [`\x1b[${moveUpLines}A${Frame.BOF}`, ...rows]
|
|
461
|
-
if (rows.length > this.height && this.height >= 0) {
|
|
462
|
-
rows = rows.slice(0, this.height + 1) // +1 for the cursor move line
|
|
463
|
-
}
|
|
464
|
-
} else {
|
|
465
|
-
if (rows.length > this.height) {
|
|
466
|
-
rows = rows.slice(0, this.height)
|
|
467
|
-
}
|
|
468
|
-
rows = [Frame.BOF, ...rows]
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
this.imprint = rows.join('\n')
|
|
472
|
-
return this.imprint
|
|
473
|
-
}
|
|
474
|
-
/**
|
|
475
|
-
* Convert the frame to its string representation.
|
|
476
|
-
* @returns {string} The frame's imprint.
|
|
477
|
-
*/
|
|
478
|
-
toString() {
|
|
479
|
-
return this.imprint
|
|
480
|
-
}
|
|
481
|
-
/**
|
|
482
|
-
* Transform each cell in the frame using a function.
|
|
483
|
-
* @param {Function} fn - Function to apply to each cell.
|
|
484
|
-
* @returns {Frame} A new Frame with transformed values.
|
|
485
|
-
*/
|
|
486
|
-
transform(fn) {
|
|
487
|
-
const value = this.value.map((row) => row.map(fn))
|
|
488
|
-
return new Frame({ ...this, value })
|
|
489
|
-
}
|
|
490
|
-
/**
|
|
491
|
-
* Set the window size for the frame.
|
|
492
|
-
* @param {number} width - The width of the window.
|
|
493
|
-
* @param {number} height - The height of the window.
|
|
494
|
-
*/
|
|
495
|
-
setWindowSize(width, height) {
|
|
496
|
-
this.width = Math.max(0, Number(width))
|
|
497
|
-
this.height = Math.max(0, Number(height))
|
|
498
|
-
this.render()
|
|
499
|
-
}
|
|
500
|
-
/**
|
|
501
|
-
* Check if a value can be used to create a Frame instance.
|
|
502
|
-
* @param {*} value - Value to check.
|
|
503
|
-
* @returns {boolean} True if the value is valid for Frame creation.
|
|
504
|
-
*/
|
|
505
|
-
static is(value) {
|
|
506
|
-
try {
|
|
507
|
-
new Frame(value)
|
|
508
|
-
return true
|
|
509
|
-
} catch {
|
|
510
|
-
return false
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
/**
|
|
514
|
-
* Create a Frame instance from input.
|
|
515
|
-
* @param {*} input - Input value to convert.
|
|
516
|
-
* @returns {Frame} A new Frame instance.
|
|
517
|
-
*/
|
|
518
|
-
static from(input) {
|
|
519
|
-
if (input instanceof Frame) return input
|
|
520
|
-
if (input?.value instanceof Frame) return new Frame(to(Object)(input.value))
|
|
521
|
-
if ('string' === typeof input) input = [input]
|
|
522
|
-
if (Array.isArray(input)) return new Frame({ value: input })
|
|
523
|
-
return new Frame(input)
|
|
524
|
-
}
|
|
525
|
-
/**
|
|
526
|
-
* Create a function to space columns based on options.
|
|
527
|
-
* @param {object} options - Spacing options.
|
|
528
|
-
* @param {number[]} [options.cols=[]] - Widths of the columns.
|
|
529
|
-
* @param {number} [options.padding=1] - Padding between columns.
|
|
530
|
-
* @param {string[]} [options.aligns=[]] - Alignment for each column ('l' or 'r').
|
|
531
|
-
* @returns {Function} Function that spaces a row.
|
|
532
|
-
*/
|
|
533
|
-
static spaces(options = {}) {
|
|
534
|
-
const { cols = [], padding = 1, aligns = [] } = options
|
|
535
|
-
return (row) =>
|
|
536
|
-
row.map((str, i) => {
|
|
537
|
-
const pad = ' '.repeat(cols[i] - str.length + padding)
|
|
538
|
-
return aligns[i] === 'r' ? pad + str : str + pad
|
|
539
|
-
})
|
|
540
|
-
}
|
|
541
|
-
/**
|
|
542
|
-
*
|
|
543
|
-
* @param {Array} arr
|
|
544
|
-
* @returns {(v) => number[]}
|
|
545
|
-
*/
|
|
546
|
-
static weight(arr) {
|
|
547
|
-
return (Fn = (v) => v) => {
|
|
548
|
-
const cols = []
|
|
549
|
-
arr.forEach((m) => {
|
|
550
|
-
Fn(m).forEach((str, i) => {
|
|
551
|
-
if (undefined === cols[i]) cols[i] = 0
|
|
552
|
-
cols[i] = Math.max(String(str).length, cols[i])
|
|
553
|
-
})
|
|
554
|
-
})
|
|
555
|
-
return cols
|
|
556
|
-
}
|
|
557
|
-
}
|
|
558
|
-
/**
|
|
559
|
-
*
|
|
560
|
-
* @param {object} options
|
|
561
|
-
* @param {Function} [options.fn=(fn = v => v)] - Function to calculate weight.
|
|
562
|
-
* @param {number[]} [options.cols=[]] - Widths of the columns.
|
|
563
|
-
* @param {number} [options.padding=1] - The padding between columns.
|
|
564
|
-
* @param {string[]} [options.aligns=[]] - The column aligns: l, r
|
|
565
|
-
* @returns {(arr: []) => string[][]}
|
|
566
|
-
*/
|
|
567
|
-
static table(options = {}) {
|
|
568
|
-
const { fn = (v) => v, cols: initialCols = [], padding = 1, aligns = [] } = options
|
|
569
|
-
return (arr) => {
|
|
570
|
-
let cols = initialCols
|
|
571
|
-
if (empty(cols)) {
|
|
572
|
-
cols = Frame.weight(arr)(fn)
|
|
573
|
-
}
|
|
574
|
-
return arr.map((row) => Frame.spaces({ cols, padding, aligns })(row))
|
|
575
|
-
}
|
|
576
|
-
}
|
|
577
|
-
/**
|
|
578
|
-
* Move cursor up by specified lines.
|
|
579
|
-
* @param {number} [lines=1] - Number of lines to move up.
|
|
580
|
-
* @returns {string} ANSI escape code for cursor movement.
|
|
581
|
-
*/
|
|
582
|
-
static cursorUp(lines = 1) {
|
|
583
|
-
return `\x1b[${lines}A`
|
|
584
|
-
}
|
|
585
|
-
/**
|
|
586
|
-
* Move cursor down by specified lines.
|
|
587
|
-
* @param {number} [lines=1] - Number of lines to move down.
|
|
588
|
-
* @returns {string} ANSI escape code for cursor movement.
|
|
589
|
-
*/
|
|
590
|
-
static cursorDown(lines = 1) {
|
|
591
|
-
return `\x1b[${lines}B`
|
|
592
|
-
}
|
|
593
|
-
/**
|
|
594
|
-
* Clear the current line.
|
|
595
|
-
* @param {string} [str="\r"] - String to append after clearing.
|
|
596
|
-
* @returns {string} ANSI escape code for line clearing followed by the string.
|
|
597
|
-
*/
|
|
598
|
-
static clearLine(str = '\r') {
|
|
599
|
-
return Frame.CLEAR_LINE + str
|
|
600
|
-
}
|
|
601
|
-
/**
|
|
602
|
-
* Clear the entire screen.
|
|
603
|
-
* @returns {string} ANSI escape codes for screen clearing.
|
|
604
|
-
*/
|
|
605
|
-
static clearScreen() {
|
|
606
|
-
return '\x1b[2J\x1b[0;0H'
|
|
607
|
-
}
|
|
608
|
-
}
|
package/src/Frame/Props.js
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
import { typeOf, ObjectWithAlias } from '@nan0web/types'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Represents default styling properties for Frame rendering.
|
|
5
|
-
* Every tag must be a separate value in the array of rows/columns.
|
|
6
|
-
* If you want to apply the same props to multiple values, you can use an array of values.
|
|
7
|
-
* If you want to apply different props to multiple values, you can use an object with the props.
|
|
8
|
-
* If you want to apply props to a single value, you can use a string with the props in XML format.
|
|
9
|
-
* Parser checks every atom for its beginning and end and if it's a tag, it applies the props to the value.
|
|
10
|
-
*
|
|
11
|
-
* @example
|
|
12
|
-
* const defaultProps = new FrameProps({
|
|
13
|
-
* color: "red",
|
|
14
|
-
* bgColor: "blue",
|
|
15
|
-
* bold: true,
|
|
16
|
-
* italic: true,
|
|
17
|
-
* underline: true,
|
|
18
|
-
* strikethrough: true,
|
|
19
|
-
* })
|
|
20
|
-
* or by aliases:
|
|
21
|
-
* const defaultProps = new FrameProps({
|
|
22
|
-
* fg: "red",
|
|
23
|
-
* bg: "blue",
|
|
24
|
-
* b: true,
|
|
25
|
-
* i: true,
|
|
26
|
-
* u: true,
|
|
27
|
-
* s: true,
|
|
28
|
-
* })
|
|
29
|
-
* from an array of strings:
|
|
30
|
-
* const rows = [
|
|
31
|
-
* ["Hello", "World"],
|
|
32
|
-
* ["<fg=red>Hello</>", "<bg=blue>World</>"],
|
|
33
|
-
* ["<b>Hello</b>", "<i>World</i>"],
|
|
34
|
-
* ["<u>Hello</u>", "<s>World</s>"],
|
|
35
|
-
* ["<b fg=red>Hello</b>", "<i bg=blue>World</i>"],
|
|
36
|
-
* ["<b i>Hello</b>", "<i b>World</i>"],
|
|
37
|
-
* ["<b i s>Some</b>", ["thing", {b: true, i: true, s: true}]],
|
|
38
|
-
* [["Hello", "World", {b: true}]],
|
|
39
|
-
* ]
|
|
40
|
-
* const defaultProps = new FrameProps(rows)
|
|
41
|
-
*/
|
|
42
|
-
class FrameProps extends ObjectWithAlias {
|
|
43
|
-
/**
|
|
44
|
-
* Property aliases for shorthand notation.
|
|
45
|
-
* @type {Record<string, string>}
|
|
46
|
-
*/
|
|
47
|
-
static ALIAS = {
|
|
48
|
-
fg: 'color',
|
|
49
|
-
bg: 'bgColor',
|
|
50
|
-
b: 'bold',
|
|
51
|
-
i: 'italic',
|
|
52
|
-
u: 'underline',
|
|
53
|
-
s: 'strikethrough',
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* @param {object} props - Frame properties
|
|
58
|
-
* @param {string} [props.color=""] - Text color
|
|
59
|
-
* @param {string} [props.bgColor=""] - Background color
|
|
60
|
-
* @param {boolean} [props.bold=false] - Bold text flag
|
|
61
|
-
* @param {boolean} [props.italic=false] - Italic text flag
|
|
62
|
-
* @param {boolean} [props.underline=false] - Underline text flag
|
|
63
|
-
* @param {boolean} [props.strikethrough=false] - Strikethrough text flag
|
|
64
|
-
*/
|
|
65
|
-
constructor(props = {}) {
|
|
66
|
-
super()
|
|
67
|
-
const {
|
|
68
|
-
color = '',
|
|
69
|
-
bgColor = '',
|
|
70
|
-
bold = false,
|
|
71
|
-
italic = false,
|
|
72
|
-
underline = false,
|
|
73
|
-
strikethrough = false,
|
|
74
|
-
} = props
|
|
75
|
-
|
|
76
|
-
/** @type {string} Text color */
|
|
77
|
-
this.color = color
|
|
78
|
-
|
|
79
|
-
/** @type {string} Background color */
|
|
80
|
-
this.bgColor = bgColor
|
|
81
|
-
|
|
82
|
-
/** @type {boolean} Bold text flag */
|
|
83
|
-
this.bold = bold
|
|
84
|
-
|
|
85
|
-
/** @type {boolean} Italic text flag */
|
|
86
|
-
this.italic = italic
|
|
87
|
-
|
|
88
|
-
/** @type {boolean} Underline text flag */
|
|
89
|
-
this.underline = underline
|
|
90
|
-
|
|
91
|
-
/** @type {boolean} Strikethrough text flag */
|
|
92
|
-
this.strikethrough = strikethrough
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
export default FrameProps
|