@levu/snap 0.1.1 → 0.2.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/CHANGELOG.md +41 -0
- package/README.md +26 -2
- package/dist/dx/terminal/index.d.ts +2 -1
- package/dist/dx/terminal/index.js +3 -1
- package/dist/dx/terminal/intro-outro.d.ts +4 -0
- package/dist/dx/terminal/intro-outro.js +44 -0
- package/dist/dx/terminal/output.d.ts +13 -1
- package/dist/dx/terminal/output.js +43 -2
- package/dist/dx/tui/index.d.ts +12 -0
- package/dist/dx/tui/index.js +12 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +2 -0
- package/dist/tui/component-adapters/autocomplete.d.ts +15 -0
- package/dist/tui/component-adapters/autocomplete.js +34 -0
- package/dist/tui/component-adapters/note.d.ts +7 -0
- package/dist/tui/component-adapters/note.js +23 -0
- package/dist/tui/component-adapters/password.d.ts +7 -0
- package/dist/tui/component-adapters/password.js +24 -0
- package/dist/tui/component-adapters/progress.d.ts +7 -0
- package/dist/tui/component-adapters/progress.js +44 -0
- package/dist/tui/component-adapters/spinner.d.ts +10 -0
- package/dist/tui/component-adapters/spinner.js +48 -0
- package/dist/tui/component-adapters/tasks.d.ts +9 -0
- package/dist/tui/component-adapters/tasks.js +31 -0
- package/docs/component-reference.md +474 -0
- package/docs/getting-started.md +242 -0
- package/docs/help-contract-spec.md +29 -0
- package/docs/integration-examples.md +677 -0
- package/docs/module-authoring-guide.md +156 -0
- package/docs/snap-args.md +323 -0
- package/docs/snap-help.md +372 -0
- package/docs/snap-runtime.md +394 -0
- package/docs/snap-terminal.md +410 -0
- package/docs/snap-tui.md +529 -0
- package/package.json +4 -2
package/docs/snap-tui.md
ADDED
|
@@ -0,0 +1,529 @@
|
|
|
1
|
+
# SnapTui - Typed TUI Flow Definitions
|
|
2
|
+
|
|
3
|
+
`SnapTui` provides type-safe helpers for defining structured TUI flows with validation and custom component support.
|
|
4
|
+
|
|
5
|
+
## Import
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
import * as SnapTui from 'snap-framework';
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Core Concepts
|
|
12
|
+
|
|
13
|
+
### Structured vs. Legacy Flows
|
|
14
|
+
|
|
15
|
+
Snap supports two TUI definition styles:
|
|
16
|
+
|
|
17
|
+
1. **Legacy**: Simple string array of step IDs
|
|
18
|
+
```typescript
|
|
19
|
+
tui: { steps: ['step1', 'step2'] }
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
2. **Structured**: Full component definitions with validation
|
|
23
|
+
```typescript
|
|
24
|
+
tui: {
|
|
25
|
+
flow: SnapTui.defineTuiFlow({
|
|
26
|
+
entryStepId: 'step1',
|
|
27
|
+
steps: [/* ... */]
|
|
28
|
+
})
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Component Types
|
|
33
|
+
|
|
34
|
+
SnapTui supports these component types:
|
|
35
|
+
|
|
36
|
+
- **text**: Single-line text input
|
|
37
|
+
- **select**: Single-choice selection
|
|
38
|
+
- **multiselect**: Multi-choice selection
|
|
39
|
+
- **confirm**: Boolean yes/no confirmation
|
|
40
|
+
- **custom**: Custom renderer (for advanced use cases)
|
|
41
|
+
|
|
42
|
+
## API Reference
|
|
43
|
+
|
|
44
|
+
### `defineTuiFlow(flow)`
|
|
45
|
+
|
|
46
|
+
Defines a validated TUI flow structure.
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
const flow = SnapTui.defineTuiFlow({
|
|
50
|
+
entryStepId: 'start',
|
|
51
|
+
steps: [
|
|
52
|
+
{
|
|
53
|
+
stepId: 'start',
|
|
54
|
+
title: 'Start Step',
|
|
55
|
+
components: [/* ... */]
|
|
56
|
+
}
|
|
57
|
+
]
|
|
58
|
+
});
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
**Validation:**
|
|
62
|
+
- At least one step required
|
|
63
|
+
- `entryStepId` must reference an existing step
|
|
64
|
+
- All components are validated
|
|
65
|
+
|
|
66
|
+
### `defineTuiStep(step)`
|
|
67
|
+
|
|
68
|
+
Defines a validated TUI step.
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
const step = SnapTui.defineTuiStep({
|
|
72
|
+
stepId: 'collect-name',
|
|
73
|
+
title: 'Enter your name',
|
|
74
|
+
components: [
|
|
75
|
+
{
|
|
76
|
+
componentId: 'name',
|
|
77
|
+
type: 'text',
|
|
78
|
+
label: 'Name',
|
|
79
|
+
arg: 'name',
|
|
80
|
+
required: true
|
|
81
|
+
}
|
|
82
|
+
]
|
|
83
|
+
});
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### `defineTuiComponent(component)`
|
|
87
|
+
|
|
88
|
+
Defines a validated TUI component.
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
const component = SnapTui.defineTuiComponent({
|
|
92
|
+
componentId: 'operation',
|
|
93
|
+
type: 'select',
|
|
94
|
+
label: 'Choose operation',
|
|
95
|
+
arg: 'op',
|
|
96
|
+
required: true,
|
|
97
|
+
options: [
|
|
98
|
+
{ value: 'create', label: 'Create new' },
|
|
99
|
+
{ value: 'update', label: 'Update existing' }
|
|
100
|
+
]
|
|
101
|
+
});
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
**Component Options:**
|
|
105
|
+
|
|
106
|
+
| Field | Type | Description |
|
|
107
|
+
|-------|------|-------------|
|
|
108
|
+
| `componentId` | `string` | Unique identifier for the component |
|
|
109
|
+
| `type` | `'text'\|'select'\|'multiselect'\|'confirm'\|'custom'` | Component type |
|
|
110
|
+
| `label` | `string` | Display label for the prompt |
|
|
111
|
+
| `arg` | `string` | Argument key to store value in |
|
|
112
|
+
| `required` | `boolean` | Whether input is required |
|
|
113
|
+
| `options` | `TuiOption[]` | Options for select/multiselect |
|
|
114
|
+
| `initialValue` | `string` | Default value for text input |
|
|
115
|
+
| `placeholder` | `string` | Placeholder text |
|
|
116
|
+
|
|
117
|
+
### `defineTuiOptions(options)`
|
|
118
|
+
|
|
119
|
+
Defines validated select/multiselect options.
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
const options = SnapTui.defineTuiOptions([
|
|
123
|
+
{ value: 'option1', label: 'Option 1' },
|
|
124
|
+
{ value: 'option2', label: 'Option 2' }
|
|
125
|
+
]);
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### `defineCustomTuiComponent(component)`
|
|
129
|
+
|
|
130
|
+
Defines a custom TUI component with a renderer.
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
const customComponent = SnapTui.defineCustomTuiComponent({
|
|
134
|
+
componentId: 'searchable-select',
|
|
135
|
+
label: 'Search and select',
|
|
136
|
+
arg: 'target',
|
|
137
|
+
renderer: 'searchable-select',
|
|
138
|
+
config: {
|
|
139
|
+
maxItems: 8,
|
|
140
|
+
allowCustomValue: true
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Complete Examples
|
|
146
|
+
|
|
147
|
+
### Basic Text Input
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
import type { ModuleContract } from 'snap-framework';
|
|
151
|
+
import { ExitCode } from 'snap-framework';
|
|
152
|
+
import * as SnapTui from 'snap-framework';
|
|
153
|
+
|
|
154
|
+
const greeterModule: ModuleContract = {
|
|
155
|
+
moduleId: 'greet',
|
|
156
|
+
description: 'Greeting module',
|
|
157
|
+
actions: [
|
|
158
|
+
{
|
|
159
|
+
actionId: 'hello',
|
|
160
|
+
description: 'Say hello',
|
|
161
|
+
tui: {
|
|
162
|
+
flow: SnapTui.defineTuiFlow({
|
|
163
|
+
entryStepId: 'collect-name',
|
|
164
|
+
steps: [
|
|
165
|
+
SnapTui.defineTuiStep({
|
|
166
|
+
stepId: 'collect-name',
|
|
167
|
+
title: 'Enter your name',
|
|
168
|
+
components: [
|
|
169
|
+
SnapTui.defineTuiComponent({
|
|
170
|
+
componentId: 'name',
|
|
171
|
+
type: 'text',
|
|
172
|
+
label: 'Your name',
|
|
173
|
+
arg: 'name',
|
|
174
|
+
required: true,
|
|
175
|
+
placeholder: 'Enter your name here...'
|
|
176
|
+
})
|
|
177
|
+
]
|
|
178
|
+
})
|
|
179
|
+
]
|
|
180
|
+
})
|
|
181
|
+
},
|
|
182
|
+
commandline: { requiredArgs: ['name'] },
|
|
183
|
+
help: {
|
|
184
|
+
summary: 'Say hello to someone.',
|
|
185
|
+
args: [{ name: 'name', required: true, description: 'Name to greet' }]
|
|
186
|
+
},
|
|
187
|
+
run: async (context) => {
|
|
188
|
+
const name = String(context.args.name ?? 'World');
|
|
189
|
+
return {
|
|
190
|
+
ok: true,
|
|
191
|
+
mode: context.mode,
|
|
192
|
+
exitCode: ExitCode.SUCCESS,
|
|
193
|
+
data: `Hello, ${name}!`
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
]
|
|
198
|
+
};
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Select Component
|
|
202
|
+
|
|
203
|
+
```typescript
|
|
204
|
+
const deployModule: ModuleContract = {
|
|
205
|
+
moduleId: 'deploy',
|
|
206
|
+
description: 'Deployment module',
|
|
207
|
+
actions: [
|
|
208
|
+
{
|
|
209
|
+
actionId: 'start',
|
|
210
|
+
description: 'Start deployment',
|
|
211
|
+
tui: {
|
|
212
|
+
flow: SnapTui.defineTuiFlow({
|
|
213
|
+
entryStepId: 'select-environment',
|
|
214
|
+
steps: [
|
|
215
|
+
SnapTui.defineTuiStep({
|
|
216
|
+
stepId: 'select-environment',
|
|
217
|
+
title: 'Select Environment',
|
|
218
|
+
components: [
|
|
219
|
+
SnapTui.defineTuiComponent({
|
|
220
|
+
componentId: 'env',
|
|
221
|
+
type: 'select',
|
|
222
|
+
label: 'Environment',
|
|
223
|
+
arg: 'environment',
|
|
224
|
+
required: true,
|
|
225
|
+
options: SnapTui.defineTuiOptions([
|
|
226
|
+
{ value: 'development', label: 'Development (Local)' },
|
|
227
|
+
{ value: 'staging', label: 'Staging (Pre-production)' },
|
|
228
|
+
{ value: 'production', label: 'Production (Live)' }
|
|
229
|
+
])
|
|
230
|
+
})
|
|
231
|
+
]
|
|
232
|
+
})
|
|
233
|
+
]
|
|
234
|
+
})
|
|
235
|
+
},
|
|
236
|
+
commandline: { requiredArgs: ['environment'] },
|
|
237
|
+
help: {
|
|
238
|
+
summary: 'Deploy to environment.',
|
|
239
|
+
args: [{ name: 'environment', required: true, description: 'Target env' }]
|
|
240
|
+
},
|
|
241
|
+
run: async (context) => {
|
|
242
|
+
const environment = String(context.args.environment ?? '');
|
|
243
|
+
return {
|
|
244
|
+
ok: true,
|
|
245
|
+
mode: context.mode,
|
|
246
|
+
exitCode: ExitCode.SUCCESS,
|
|
247
|
+
data: `Deployed to ${environment}`
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
]
|
|
252
|
+
};
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### Multi-Step Flow with Multiple Components
|
|
256
|
+
|
|
257
|
+
```typescript
|
|
258
|
+
const userModule: ModuleContract = {
|
|
259
|
+
moduleId: 'user',
|
|
260
|
+
description: 'User management',
|
|
261
|
+
actions: [
|
|
262
|
+
{
|
|
263
|
+
actionId: 'create',
|
|
264
|
+
description: 'Create a new user',
|
|
265
|
+
tui: {
|
|
266
|
+
flow: SnapTui.defineTuiFlow({
|
|
267
|
+
entryStepId: 'collect-basic',
|
|
268
|
+
steps: [
|
|
269
|
+
{
|
|
270
|
+
stepId: 'collect-basic',
|
|
271
|
+
title: 'Basic Information',
|
|
272
|
+
components: [
|
|
273
|
+
SnapTui.defineTuiComponent({
|
|
274
|
+
componentId: 'name',
|
|
275
|
+
type: 'text',
|
|
276
|
+
label: 'Full name',
|
|
277
|
+
arg: 'name',
|
|
278
|
+
required: true
|
|
279
|
+
}),
|
|
280
|
+
SnapTui.defineTuiComponent({
|
|
281
|
+
componentId: 'email',
|
|
282
|
+
type: 'text',
|
|
283
|
+
label: 'Email address',
|
|
284
|
+
arg: 'email',
|
|
285
|
+
required: true
|
|
286
|
+
})
|
|
287
|
+
]
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
stepId: 'collect-roles',
|
|
291
|
+
title: 'Assign Roles',
|
|
292
|
+
components: [
|
|
293
|
+
SnapTui.defineTuiComponent({
|
|
294
|
+
componentId: 'roles',
|
|
295
|
+
type: 'multiselect',
|
|
296
|
+
label: 'User roles',
|
|
297
|
+
arg: 'roles',
|
|
298
|
+
required: true,
|
|
299
|
+
options: SnapTui.defineTuiOptions([
|
|
300
|
+
{ value: 'admin', label: 'Administrator' },
|
|
301
|
+
{ value: 'editor', label: 'Editor' },
|
|
302
|
+
{ value: 'viewer', label: 'Viewer' }
|
|
303
|
+
])
|
|
304
|
+
})
|
|
305
|
+
]
|
|
306
|
+
},
|
|
307
|
+
{
|
|
308
|
+
stepId: 'confirm',
|
|
309
|
+
title: 'Confirm Creation',
|
|
310
|
+
components: [
|
|
311
|
+
SnapTui.defineTuiComponent({
|
|
312
|
+
componentId: 'confirmed',
|
|
313
|
+
type: 'confirm',
|
|
314
|
+
label: 'Create this user?',
|
|
315
|
+
arg: 'confirmed',
|
|
316
|
+
required: true
|
|
317
|
+
})
|
|
318
|
+
]
|
|
319
|
+
}
|
|
320
|
+
]
|
|
321
|
+
})
|
|
322
|
+
},
|
|
323
|
+
commandline: {
|
|
324
|
+
requiredArgs: ['name', 'email'],
|
|
325
|
+
optionalArgs: ['roles']
|
|
326
|
+
},
|
|
327
|
+
help: {
|
|
328
|
+
summary: 'Create a new user account.',
|
|
329
|
+
args: [
|
|
330
|
+
{ name: 'name', required: true, description: 'User full name' },
|
|
331
|
+
{ name: 'email', required: true, description: 'User email' },
|
|
332
|
+
{ name: 'roles', required: false, description: 'Comma-separated roles' }
|
|
333
|
+
]
|
|
334
|
+
},
|
|
335
|
+
run: async (context) => {
|
|
336
|
+
const name = String(context.args.name ?? '');
|
|
337
|
+
const email = String(context.args.email ?? '');
|
|
338
|
+
const rolesArg = context.args.roles;
|
|
339
|
+
|
|
340
|
+
let roles: string[] = ['viewer'];
|
|
341
|
+
if (Array.isArray(rolesArg)) {
|
|
342
|
+
roles = rolesArg as string[];
|
|
343
|
+
} else if (typeof rolesArg === 'string') {
|
|
344
|
+
roles = rolesArg.split(',');
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
return {
|
|
348
|
+
ok: true,
|
|
349
|
+
mode: context.mode,
|
|
350
|
+
exitCode: ExitCode.SUCCESS,
|
|
351
|
+
data: { name, email, roles }
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
]
|
|
356
|
+
};
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
### Custom Component
|
|
360
|
+
|
|
361
|
+
```typescript
|
|
362
|
+
const advancedModule: ModuleContract = {
|
|
363
|
+
moduleId: 'advanced',
|
|
364
|
+
description: 'Advanced operations',
|
|
365
|
+
actions: [
|
|
366
|
+
{
|
|
367
|
+
actionId: 'select-resource',
|
|
368
|
+
description: 'Select from resources',
|
|
369
|
+
tui: {
|
|
370
|
+
flow: SnapTui.defineTuiFlow({
|
|
371
|
+
entryStepId: 'search',
|
|
372
|
+
steps: [
|
|
373
|
+
{
|
|
374
|
+
stepId: 'search',
|
|
375
|
+
title: 'Select Resource',
|
|
376
|
+
components: [
|
|
377
|
+
SnapTui.defineCustomTuiComponent({
|
|
378
|
+
componentId: 'resource',
|
|
379
|
+
label: 'Search resources',
|
|
380
|
+
arg: 'resource',
|
|
381
|
+
renderer: 'searchable-select',
|
|
382
|
+
config: {
|
|
383
|
+
maxItems: 10,
|
|
384
|
+
allowCustomValue: false,
|
|
385
|
+
searchPlaceholder: 'Type to search...'
|
|
386
|
+
}
|
|
387
|
+
})
|
|
388
|
+
]
|
|
389
|
+
}
|
|
390
|
+
]
|
|
391
|
+
})
|
|
392
|
+
},
|
|
393
|
+
commandline: { requiredArgs: ['resource'] },
|
|
394
|
+
help: {
|
|
395
|
+
summary: 'Select a resource.',
|
|
396
|
+
args: [{ name: 'resource', required: true, description: 'Resource ID or name' }]
|
|
397
|
+
},
|
|
398
|
+
run: async (context) => {
|
|
399
|
+
const resource = String(context.args.resource ?? '');
|
|
400
|
+
return {
|
|
401
|
+
ok: true,
|
|
402
|
+
mode: context.mode,
|
|
403
|
+
exitCode: ExitCode.SUCCESS,
|
|
404
|
+
data: { resource }
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
]
|
|
409
|
+
};
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
## Advanced Patterns
|
|
413
|
+
|
|
414
|
+
### Conditional Step Display
|
|
415
|
+
|
|
416
|
+
Use flow control to skip steps:
|
|
417
|
+
|
|
418
|
+
```typescript
|
|
419
|
+
run: async (context) => {
|
|
420
|
+
const skipConfig = SnapArgs.readBooleanArg(context.args, 'skip-config');
|
|
421
|
+
|
|
422
|
+
if (skipConfig) {
|
|
423
|
+
context.flow.jump('confirm');
|
|
424
|
+
} else {
|
|
425
|
+
context.flow.next();
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// ... rest of logic
|
|
429
|
+
}
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
### Dynamic Options
|
|
433
|
+
|
|
434
|
+
Options can be computed at runtime:
|
|
435
|
+
|
|
436
|
+
```typescript
|
|
437
|
+
const getEnvironmentOptions = async (): Promise<TuiOptionContract[]> => {
|
|
438
|
+
const envs = await fetchEnvironments();
|
|
439
|
+
return envs.map(env => ({
|
|
440
|
+
value: env.name,
|
|
441
|
+
label: `${env.name} (${env.region})`
|
|
442
|
+
}));
|
|
443
|
+
};
|
|
444
|
+
|
|
445
|
+
// Use in flow
|
|
446
|
+
flow: SnapTui.defineTuiFlow({
|
|
447
|
+
entryStepId: 'select-env',
|
|
448
|
+
steps: [
|
|
449
|
+
{
|
|
450
|
+
stepId: 'select-env',
|
|
451
|
+
title: 'Select Environment',
|
|
452
|
+
components: [
|
|
453
|
+
{
|
|
454
|
+
componentId: 'env',
|
|
455
|
+
type: 'select',
|
|
456
|
+
label: 'Environment',
|
|
457
|
+
arg: 'environment',
|
|
458
|
+
required: true,
|
|
459
|
+
options: await getEnvironmentOptions()
|
|
460
|
+
}
|
|
461
|
+
]
|
|
462
|
+
}
|
|
463
|
+
]
|
|
464
|
+
})
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
### Type Safety
|
|
468
|
+
|
|
469
|
+
Define interfaces for your data:
|
|
470
|
+
|
|
471
|
+
```typescript
|
|
472
|
+
interface CreateUserInput {
|
|
473
|
+
name: string;
|
|
474
|
+
email: string;
|
|
475
|
+
roles: string[];
|
|
476
|
+
confirmed: boolean;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
run: async (context): Promise<ActionResultEnvelope<CreateUserInput>> => {
|
|
480
|
+
// TypeScript knows the shape
|
|
481
|
+
return {
|
|
482
|
+
ok: true,
|
|
483
|
+
mode: context.mode,
|
|
484
|
+
exitCode: ExitCode.SUCCESS,
|
|
485
|
+
data: {
|
|
486
|
+
name: String(context.args.name),
|
|
487
|
+
email: String(context.args.email),
|
|
488
|
+
roles: context.args.roles as string[],
|
|
489
|
+
confirmed: Boolean(context.args.confirmed)
|
|
490
|
+
}
|
|
491
|
+
};
|
|
492
|
+
}
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
## Best Practices
|
|
496
|
+
|
|
497
|
+
1. **Use structured flows** - Better validation and IDE support
|
|
498
|
+
2. **Group related inputs** - One step per logical grouping
|
|
499
|
+
3. **Provide clear labels** - Help users understand each field
|
|
500
|
+
4. **Use confirm for destructive actions** - Always confirm deletes, etc.
|
|
501
|
+
5. **Set reasonable defaults** - Reduce user typing with `initialValue`
|
|
502
|
+
6. **Validate arg names** - Match component `arg` to action's expected args
|
|
503
|
+
7. **Keep steps focused** - One logical operation per step
|
|
504
|
+
|
|
505
|
+
## Component Validation
|
|
506
|
+
|
|
507
|
+
SnapTui validates at definition time:
|
|
508
|
+
|
|
509
|
+
```typescript
|
|
510
|
+
// Throws: componentId cannot be empty
|
|
511
|
+
SnapTui.defineTuiComponent({
|
|
512
|
+
componentId: '',
|
|
513
|
+
type: 'text',
|
|
514
|
+
label: 'Label',
|
|
515
|
+
arg: 'x'
|
|
516
|
+
});
|
|
517
|
+
|
|
518
|
+
// Throws: options required for select
|
|
519
|
+
SnapTui.defineTuiComponent({
|
|
520
|
+
componentId: 'x',
|
|
521
|
+
type: 'select',
|
|
522
|
+
label: 'Label',
|
|
523
|
+
arg: 'x',
|
|
524
|
+
options: [] // Empty!
|
|
525
|
+
});
|
|
526
|
+
|
|
527
|
+
// Throws: empty options array
|
|
528
|
+
SnapTui.defineTuiOptions([]);
|
|
529
|
+
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@levu/snap",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"snap": "./dist/cli-entry.js"
|
|
@@ -25,7 +25,9 @@
|
|
|
25
25
|
},
|
|
26
26
|
"files": [
|
|
27
27
|
"dist",
|
|
28
|
+
"docs",
|
|
28
29
|
"README.md",
|
|
29
|
-
"LICENSE"
|
|
30
|
+
"LICENSE",
|
|
31
|
+
"CHANGELOG.md"
|
|
30
32
|
]
|
|
31
33
|
}
|