@valyrianjs/terminal 0.2.1 → 0.2.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.
Files changed (80) hide show
  1. package/dist/ansi.d.ts.map +1 -1
  2. package/dist/ansi.js +12 -14
  3. package/dist/ansi.js.map +1 -1
  4. package/dist/events.d.ts.map +1 -1
  5. package/dist/events.js +4 -0
  6. package/dist/events.js.map +1 -1
  7. package/dist/frame-style.d.ts +7 -0
  8. package/dist/frame-style.d.ts.map +1 -0
  9. package/dist/frame-style.js +27 -0
  10. package/dist/frame-style.js.map +1 -0
  11. package/dist/layout.d.ts +5 -1
  12. package/dist/layout.d.ts.map +1 -1
  13. package/dist/layout.js +53 -23
  14. package/dist/layout.js.map +1 -1
  15. package/dist/mouse.d.ts.map +1 -1
  16. package/dist/mouse.js +8 -1
  17. package/dist/mouse.js.map +1 -1
  18. package/dist/render.d.ts.map +1 -1
  19. package/dist/render.js +87 -48
  20. package/dist/render.js.map +1 -1
  21. package/dist/session.d.ts.map +1 -1
  22. package/dist/session.js +2 -0
  23. package/dist/session.js.map +1 -1
  24. package/dist/text.d.ts +7 -0
  25. package/dist/text.d.ts.map +1 -1
  26. package/dist/text.js +114 -0
  27. package/dist/text.js.map +1 -1
  28. package/dist/types.d.ts +3 -0
  29. package/dist/types.d.ts.map +1 -1
  30. package/docs/api-reference.md +6 -3
  31. package/docs/cookbook.md +1 -1
  32. package/docs/interaction-model.md +5 -5
  33. package/docs/primitive-gallery.md +4 -4
  34. package/examples/basic.tsx +22 -0
  35. package/examples/cli.tsx +55 -0
  36. package/examples/demo.tsx +98 -0
  37. package/examples/docs/background-fill.tsx +107 -0
  38. package/examples/docs/component-composition.tsx +140 -0
  39. package/examples/docs/cursor.tsx +121 -0
  40. package/examples/docs/employees-list.tsx +138 -0
  41. package/examples/docs/hello.tsx +98 -0
  42. package/examples/docs/interactive-note.tsx +111 -0
  43. package/examples/docs/module-api-dashboard.tsx +307 -0
  44. package/examples/docs/module-flux-store.tsx +181 -0
  45. package/examples/docs/module-form-workflow.tsx +339 -0
  46. package/examples/docs/module-forms.tsx +218 -0
  47. package/examples/docs/module-money.tsx +175 -0
  48. package/examples/docs/module-native-store.tsx +188 -0
  49. package/examples/docs/module-pulses.tsx +142 -0
  50. package/examples/docs/module-query.tsx +209 -0
  51. package/examples/docs/module-request.tsx +194 -0
  52. package/examples/docs/module-state-workbench.tsx +283 -0
  53. package/examples/docs/module-tasks.tsx +223 -0
  54. package/examples/docs/module-translate.tsx +194 -0
  55. package/examples/docs/module-utils.tsx +168 -0
  56. package/examples/docs/module-valyrian-core.tsx +159 -0
  57. package/examples/docs/pizza-builder.tsx +463 -0
  58. package/examples/docs/primitive-activity-console.tsx +113 -0
  59. package/examples/docs/primitive-command-panel.tsx +186 -0
  60. package/examples/docs/primitive-data-explorer.tsx +155 -0
  61. package/examples/docs/primitive-input-workbench.tsx +128 -0
  62. package/examples/docs/primitive-layout-shell.tsx +115 -0
  63. package/examples/docs/responsive-split.tsx +186 -0
  64. package/examples/docs/style-system.tsx +209 -0
  65. package/examples/docs/theme-colors.tsx +225 -0
  66. package/examples/docs/virtualized-list-workbench.tsx +232 -0
  67. package/examples/opencode-dogfood-app.tsx +215 -0
  68. package/examples/opencode-dogfood-lifecycle.tsx +194 -0
  69. package/examples/opencode-dogfood.tsx +11 -0
  70. package/llms-full.txt +16 -13
  71. package/package.json +3 -2
  72. package/src/ansi.ts +12 -14
  73. package/src/events.ts +2 -0
  74. package/src/frame-style.ts +36 -0
  75. package/src/layout.ts +57 -24
  76. package/src/mouse.ts +10 -1
  77. package/src/render.ts +92 -48
  78. package/src/session.ts +2 -0
  79. package/src/text.ts +148 -0
  80. package/src/types.ts +3 -0
@@ -0,0 +1,186 @@
1
+ import {
2
+ Fixed,
3
+ Pane,
4
+ Screen,
5
+ Split,
6
+ Text,
7
+ mountTerminal
8
+ } from "@valyrianjs/terminal";
9
+ import type {
10
+ TerminalMountOptions,
11
+ TerminalSession
12
+ } from "@valyrianjs/terminal";
13
+
14
+ interface ResponsiveSplitState {
15
+ running: boolean;
16
+ }
17
+
18
+ export interface ResponsiveSplitDemo {
19
+ session: TerminalSession;
20
+ dispatchKey(key: string): string;
21
+ output(): string;
22
+ ansiOutput(): string;
23
+ isRunning(): boolean;
24
+ destroy(): void;
25
+ }
26
+
27
+ function shouldRunSnapshot() {
28
+ return (
29
+ process.argv.includes("--snapshot") ||
30
+ process.env.VALYRIAN_TERMINAL_EXAMPLE_SNAPSHOT === "1" ||
31
+ !process.stdin.isTTY
32
+ );
33
+ }
34
+
35
+ export function App({
36
+ getSize
37
+ }: {
38
+ getSize?: () => { cols: number; rows: number } | undefined;
39
+ }) {
40
+ const terminalWidth = getSize?.()?.cols;
41
+ const layout = "3 columns";
42
+ const sizes = "25% / 1fr / 2fr";
43
+ const widthLabel = terminalWidth ? String(terminalWidth) : "auto";
44
+
45
+ return (
46
+ <Screen title="Workspace">
47
+ <Fixed position="top" size={3}>
48
+ <Text>{`Terminal width: ${widthLabel}`}</Text>
49
+ <Text>{`Layout: ${layout}`}</Text>
50
+ <Text>{`sizes: ${sizes}`}</Text>
51
+ </Fixed>
52
+ <Split
53
+ gap={1}
54
+ sizes={["25%", "1fr", "2fr"]}
55
+ breakpoints={[
56
+ {
57
+ maxCols: 72,
58
+ direction: "column",
59
+ sizes: ["1fr", "1fr", "1fr"],
60
+ gap: 0
61
+ }
62
+ ]}
63
+ >
64
+ <Pane
65
+ style={{
66
+ background: "#111827",
67
+ border: {
68
+ top: true,
69
+ right: true,
70
+ bottom: true,
71
+ left: true,
72
+ style: "solid",
73
+ color: "#2563eb"
74
+ }
75
+ }}
76
+ >
77
+ <Text>Inbox</Text>
78
+ <Text>3 unread</Text>
79
+ </Pane>
80
+ <Pane
81
+ style={{
82
+ background: "#172554",
83
+ border: {
84
+ top: true,
85
+ right: true,
86
+ bottom: true,
87
+ left: true,
88
+ style: "solid",
89
+ color: "#60a5fa"
90
+ }
91
+ }}
92
+ >
93
+ <Text>Preview</Text>
94
+ <Text>Welcome thread</Text>
95
+ </Pane>
96
+ <Pane
97
+ style={{
98
+ background: "#1f2937",
99
+ border: {
100
+ top: true,
101
+ right: true,
102
+ bottom: true,
103
+ left: true,
104
+ style: "solid",
105
+ color: "#a78bfa"
106
+ }
107
+ }}
108
+ >
109
+ <Text>Details</Text>
110
+ <Text>Owner: team</Text>
111
+ </Pane>
112
+ </Split>
113
+ <Fixed position="bottom" size={1}>
114
+ <Text>Resize the terminal to change layout | Ctrl+C: quit</Text>
115
+ </Fixed>
116
+ </Screen>
117
+ );
118
+ }
119
+
120
+ export function createResponsiveSplitDemo(
121
+ options: TerminalMountOptions = {}
122
+ ): ResponsiveSplitDemo {
123
+ let session: TerminalSession;
124
+ const state = {
125
+ running: true
126
+ };
127
+
128
+ function quit() {
129
+ state.running = false;
130
+ session.destroy();
131
+ }
132
+
133
+ session = mountTerminal(<App getSize={() => session?.size()} />, {
134
+ ...options,
135
+ keymap: {
136
+ ...options.keymap,
137
+ bindings: [
138
+ ...(options.keymap?.bindings || []),
139
+ { key: "CTRL_C", command: { id: "quit" }, scope: "global" }
140
+ ],
141
+ onCommand(command, context) {
142
+ if (command.id === "quit") {
143
+ quit();
144
+ return true;
145
+ }
146
+ return options.keymap?.onCommand?.(command, context);
147
+ }
148
+ }
149
+ });
150
+ session.update();
151
+
152
+ return {
153
+ session,
154
+ dispatchKey(key: string) {
155
+ return session.dispatchKey(key);
156
+ },
157
+ output() {
158
+ return session.output();
159
+ },
160
+ ansiOutput() {
161
+ return session.ansiOutput();
162
+ },
163
+ isRunning() {
164
+ return state.running;
165
+ },
166
+ destroy() {
167
+ state.running = false;
168
+ session.destroy();
169
+ }
170
+ };
171
+ }
172
+
173
+ if (import.meta.main) {
174
+ if (shouldRunSnapshot()) {
175
+ const demo = createResponsiveSplitDemo({
176
+ runtime: "headless",
177
+ cols: 40,
178
+ rows: 16
179
+ });
180
+ process.stdout.write(demo.output());
181
+ process.stdout.write("\n");
182
+ demo.destroy();
183
+ } else {
184
+ createResponsiveSplitDemo();
185
+ }
186
+ }
@@ -0,0 +1,209 @@
1
+ import { Button, Input, Pane, Screen, Text, mountTerminal } from "@valyrianjs/terminal";
2
+ import type { TerminalMountOptions, TerminalSession, TerminalVisualState } from "@valyrianjs/terminal";
3
+
4
+ type BuildStatus = "Ready" | "Building" | "Built";
5
+
6
+ interface StyleSystemDemoState {
7
+ status: BuildStatus;
8
+ warnings: boolean;
9
+ note: string;
10
+ running: boolean;
11
+ }
12
+
13
+ export interface StyleSystemDemo {
14
+ session: TerminalSession;
15
+ dispatchKey(key: string): string;
16
+ output(): string;
17
+ ansiOutput(): string;
18
+ isRunning(): boolean;
19
+ destroy(): void;
20
+ }
21
+
22
+ const theme = {
23
+ styles: {
24
+ title: {
25
+ app: { color: "#88c0d0" }
26
+ },
27
+ button: {
28
+ primary: {
29
+ color: "#ffffff",
30
+ background: "#5e81ac",
31
+ padding: { left: 1, right: 1 },
32
+ focus: { color: "#eceff4", background: "#81a1c1" }
33
+ },
34
+ loading: { color: "#88c0d0" },
35
+ success: { color: "#a3be8c" }
36
+ },
37
+ panel: {
38
+ queue: {
39
+ border: { top: true, right: true, bottom: true, left: true, style: "solid", color: "#4b5563" },
40
+ padding: { left: 1, right: 1 },
41
+ dropTarget: { border: { top: true, right: true, bottom: true, left: true, style: "solid", color: "#8fbcbb" } }
42
+ },
43
+ cta: {
44
+ color: "#eceff4",
45
+ background: "#1f2328",
46
+ padding: { left: 2, right: 2 }
47
+ }
48
+ },
49
+ input: {
50
+ readonly: { color: "#777777" },
51
+ placeholder: { color: "#777777" }
52
+ },
53
+ state: {
54
+ success: { color: "#a3be8c" },
55
+ warning: { color: "#ebcb8b" },
56
+ loading: { color: "#88c0d0" },
57
+ readonly: { color: "#777777" },
58
+ expanded: { color: "#b48ead" },
59
+ dropTarget: { color: "#8fbcbb" },
60
+ muted: { color: "#6b7280" }
61
+ }
62
+ }
63
+ };
64
+
65
+ function createInitialState(): StyleSystemDemoState {
66
+ return {
67
+ status: "Ready",
68
+ warnings: true,
69
+ note: "local-preview-2026-05-29",
70
+ running: true
71
+ };
72
+ }
73
+
74
+ function nextBuildStatus(status: BuildStatus): BuildStatus {
75
+ if (status === "Ready") {
76
+ return "Building";
77
+ }
78
+ if (status === "Building") {
79
+ return "Built";
80
+ }
81
+ return "Building";
82
+ }
83
+
84
+ export function App({ state }: { state: StyleSystemDemoState }) {
85
+ const warningText = state.warnings ? "2 warnings" : "No warnings";
86
+ const statusState: TerminalVisualState = state.status === "Built"
87
+ ? "success"
88
+ : state.status === "Building"
89
+ ? "loading"
90
+ : state.warnings
91
+ ? "warning"
92
+ : "success";
93
+ const buildButtonState: TerminalVisualState | undefined = state.status === "Built" ? "success" : state.status === "Building" ? "loading" : undefined;
94
+
95
+ return (
96
+ <Screen title="Valyrian Preview Console">
97
+ <Text style="title.app">Valyrian Preview Console</Text>
98
+ <Text>Project valyrianjs-terminal</Text>
99
+ <Text>Target local preview</Text>
100
+ <Text state={statusState} styles={{ warning: "state.warning", success: "state.success", loading: "state.loading" }}>
101
+ {`Status ${state.status} · ${warningText}`}
102
+ </Text>
103
+
104
+ <Pane style="panel.queue" state="dropTarget" styles={{ dropTarget: "panel.queue.dropTarget" }}>
105
+ <Text>Build queue</Text>
106
+ <Text state="loading" styles={{ loading: "state.loading" }}>&gt; bundle-assets loading</Text>
107
+ <Text state="readonly" styles={{ readonly: "state.readonly" }}> config-check readonly</Text>
108
+ <Text state="expanded" styles={{ expanded: "state.expanded" }}> preview-server expanded</Text>
109
+ <Text state="dropTarget" styles={{ dropTarget: "state.dropTarget" }}> cache-warmup drop target</Text>
110
+ </Pane>
111
+
112
+ <Text>Preview note</Text>
113
+ <Input
114
+ id="note"
115
+ value={state.note}
116
+ state="readonly"
117
+ styles={{ readonly: "input.readonly", placeholder: "input.placeholder" }}
118
+ />
119
+
120
+ <Pane width={24} style="panel.cta">
121
+ <Button
122
+ id="build"
123
+ style="button.primary"
124
+ state={buildButtonState}
125
+ styles={{ focus: "button.primary.focus", loading: "button.loading", success: "button.success" }}
126
+ onpress={() => {
127
+ state.status = nextBuildStatus(state.status);
128
+ }}
129
+ >
130
+ BUILD PREVIEW
131
+ </Button>
132
+ </Pane>
133
+
134
+ <Text state="muted" styles={{ muted: "state.muted" }}>Tab: focus Enter: build W: warnings Ctrl+C: quit</Text>
135
+ </Screen>
136
+ );
137
+ }
138
+
139
+ export function createStyleSystemDemo(options: TerminalMountOptions = {}): StyleSystemDemo {
140
+ const state = createInitialState();
141
+ let session: TerminalSession;
142
+
143
+ function quit() {
144
+ state.running = false;
145
+ session.destroy();
146
+ }
147
+
148
+ session = mountTerminal(<App state={state} />, {
149
+ theme,
150
+ ...options,
151
+ keymap: {
152
+ ...options.keymap,
153
+ bindings: [
154
+ ...(options.keymap?.bindings || []),
155
+ { key: "w", command: { id: "warnings.toggle" }, scope: "global" },
156
+ { key: "W", command: { id: "warnings.toggle" }, scope: "global" },
157
+ { key: "CTRL_C", command: { id: "quit" }, scope: "global" }
158
+ ],
159
+ onCommand(command, context) {
160
+ if (command.id === "warnings.toggle") {
161
+ state.warnings = !state.warnings;
162
+ return true;
163
+ }
164
+ if (command.id === "quit") {
165
+ quit();
166
+ return true;
167
+ }
168
+ return options.keymap?.onCommand?.(command, context);
169
+ }
170
+ }
171
+ });
172
+
173
+ session.focus("build");
174
+
175
+ return {
176
+ session,
177
+ dispatchKey(key: string) {
178
+ return session.dispatchKey(key);
179
+ },
180
+ output() {
181
+ return session.output();
182
+ },
183
+ ansiOutput() {
184
+ return session.ansiOutput();
185
+ },
186
+ isRunning() {
187
+ return state.running;
188
+ },
189
+ destroy() {
190
+ state.running = false;
191
+ session.destroy();
192
+ }
193
+ };
194
+ }
195
+
196
+ function shouldRunSnapshot() {
197
+ return process.argv.includes("--snapshot") || process.env.VALYRIAN_TERMINAL_EXAMPLE_SNAPSHOT === "1" || !process.stdin.isTTY;
198
+ }
199
+
200
+ if (import.meta.main) {
201
+ if (shouldRunSnapshot()) {
202
+ const demo = createStyleSystemDemo({ runtime: "headless", cols: 56, rows: 18 });
203
+ process.stdout.write(demo.output());
204
+ process.stdout.write("\n");
205
+ demo.destroy();
206
+ } else {
207
+ createStyleSystemDemo();
208
+ }
209
+ }
@@ -0,0 +1,225 @@
1
+ import { Screen, Text, mountTerminal } from "@valyrianjs/terminal";
2
+ import type {
3
+ TerminalMountOptions,
4
+ TerminalSession
5
+ } from "@valyrianjs/terminal";
6
+
7
+ interface ThemeColorsState {
8
+ palette: "day" | "night";
9
+ changedTo: "day" | "night" | "";
10
+ running: boolean;
11
+ }
12
+
13
+ export interface ThemeColorsDemo {
14
+ session: TerminalSession;
15
+ dispatchKey(key: string): string;
16
+ output(): string;
17
+ ansiOutput(): string;
18
+ isRunning(): boolean;
19
+ destroy(): void;
20
+ }
21
+
22
+ const paletteNames = {
23
+ day: "Day",
24
+ night: "Night"
25
+ } as const;
26
+
27
+ const swatchStyles = {
28
+ day: {
29
+ primary: "swatch.day.primary",
30
+ success: "swatch.day.success",
31
+ warning: "swatch.day.warning",
32
+ danger: "swatch.day.danger",
33
+ muted: "swatch.day.muted"
34
+ },
35
+ night: {
36
+ primary: "swatch.night.primary",
37
+ success: "swatch.night.success",
38
+ warning: "swatch.night.warning",
39
+ danger: "swatch.night.danger",
40
+ muted: "swatch.night.muted"
41
+ }
42
+ } as const;
43
+
44
+ const theme = {
45
+ styles: {
46
+ swatch: {
47
+ day: {
48
+ primary: {
49
+ color: "#ffffff",
50
+ background: "#2563eb",
51
+ padding: { left: 1, right: 1 }
52
+ },
53
+ success: {
54
+ color: "#052e16",
55
+ background: "#86efac",
56
+ padding: { left: 1, right: 1 }
57
+ },
58
+ warning: {
59
+ color: "#451a03",
60
+ background: "#fbbf24",
61
+ padding: { left: 1, right: 1 }
62
+ },
63
+ danger: {
64
+ color: "#ffffff",
65
+ background: "#dc2626",
66
+ padding: { left: 1, right: 1 }
67
+ },
68
+ muted: {
69
+ color: "#111827",
70
+ background: "#d1d5db",
71
+ padding: { left: 1, right: 1 }
72
+ }
73
+ },
74
+ night: {
75
+ primary: {
76
+ color: "#dbeafe",
77
+ background: "#1d4ed8",
78
+ padding: { left: 1, right: 1 }
79
+ },
80
+ success: {
81
+ color: "#dcfce7",
82
+ background: "#15803d",
83
+ padding: { left: 1, right: 1 }
84
+ },
85
+ warning: {
86
+ color: "#fef3c7",
87
+ background: "#b45309",
88
+ padding: { left: 1, right: 1 }
89
+ },
90
+ danger: {
91
+ color: "#fee2e2",
92
+ background: "#b91c1c",
93
+ padding: { left: 1, right: 1 }
94
+ },
95
+ muted: {
96
+ color: "#e5e7eb",
97
+ background: "#374151",
98
+ padding: { left: 1, right: 1 }
99
+ }
100
+ }
101
+ }
102
+ }
103
+ };
104
+
105
+ function createInitialState(): ThemeColorsState {
106
+ return { palette: "day", changedTo: "", running: true };
107
+ }
108
+
109
+ function shouldRunSnapshot() {
110
+ return (
111
+ process.argv.includes("--snapshot") ||
112
+ process.env.VALYRIAN_TERMINAL_EXAMPLE_SNAPSHOT === "1" ||
113
+ !process.stdin.isTTY
114
+ );
115
+ }
116
+
117
+ export function App({ state }: { state: ThemeColorsState }) {
118
+ const paletteLabel = paletteNames[state.palette];
119
+ const swatches = swatchStyles[state.palette];
120
+ const feedback = state.changedTo
121
+ ? `Changed to ${paletteNames[state.changedTo]} palette`
122
+ : "Tab/1/2 changes the palette";
123
+
124
+ return (
125
+ <Screen title="Theme tokens">
126
+ <Text>{`Palette: ${paletteLabel}`}</Text>
127
+ <Text>{feedback}</Text>
128
+ <Text style={swatches.primary}>Primary App action</Text>
129
+ <Text style={swatches.success}>Success Completed</Text>
130
+ <Text style={swatches.warning}>Warning Needs review</Text>
131
+ <Text style={swatches.danger}>Danger Destructive</Text>
132
+ <Text style={swatches.muted}>Muted Secondary text</Text>
133
+ <Text styles={{ muted: swatches.muted }} state="muted">
134
+ Tab/1/2 palette | Ctrl+C: quit
135
+ </Text>
136
+ </Screen>
137
+ );
138
+ }
139
+
140
+ export function createThemeColorsDemo(
141
+ options: TerminalMountOptions = {}
142
+ ): ThemeColorsDemo {
143
+ const state = createInitialState();
144
+ let session: TerminalSession;
145
+
146
+ function quit() {
147
+ state.running = false;
148
+ session.destroy();
149
+ }
150
+
151
+ function setPalette(palette: ThemeColorsState["palette"]) {
152
+ state.palette = palette;
153
+ state.changedTo = palette;
154
+ }
155
+
156
+ function switchPalette() {
157
+ setPalette(state.palette === "day" ? "night" : "day");
158
+ }
159
+
160
+ session = mountTerminal(<App state={state} />, {
161
+ theme,
162
+ ...options,
163
+ keymap: {
164
+ ...options.keymap,
165
+ bindings: [
166
+ ...(options.keymap?.bindings || []),
167
+ { key: "Tab", command: { id: "palette.switch" }, scope: "global" },
168
+ { key: "TAB", command: { id: "palette.switch" }, scope: "global" },
169
+ { key: "1", command: { id: "palette.day" }, scope: "global" },
170
+ { key: "2", command: { id: "palette.night" }, scope: "global" },
171
+ { key: "CTRL_C", command: { id: "quit" }, scope: "global" }
172
+ ],
173
+ onCommand(command, context) {
174
+ if (command.id === "palette.switch") {
175
+ switchPalette();
176
+ return true;
177
+ }
178
+ if (command.id === "palette.day") {
179
+ setPalette("day");
180
+ return true;
181
+ }
182
+ if (command.id === "palette.night") {
183
+ setPalette("night");
184
+ return true;
185
+ }
186
+ if (command.id === "quit") {
187
+ quit();
188
+ return true;
189
+ }
190
+ return options.keymap?.onCommand?.(command, context);
191
+ }
192
+ }
193
+ });
194
+
195
+ return {
196
+ session,
197
+ dispatchKey(key: string) {
198
+ return session.dispatchKey(key);
199
+ },
200
+ output() {
201
+ return session.output();
202
+ },
203
+ ansiOutput() {
204
+ return session.ansiOutput();
205
+ },
206
+ isRunning() {
207
+ return state.running;
208
+ },
209
+ destroy() {
210
+ state.running = false;
211
+ session.destroy();
212
+ }
213
+ };
214
+ }
215
+
216
+ if (import.meta.main) {
217
+ if (shouldRunSnapshot()) {
218
+ const demo = createThemeColorsDemo({ runtime: "headless", cols: 64, rows: 10 });
219
+ process.stdout.write(demo.output());
220
+ process.stdout.write("\n");
221
+ demo.destroy();
222
+ } else {
223
+ createThemeColorsDemo();
224
+ }
225
+ }