flet-box 0.0.0-stage → 1.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/LICENSE +21 -0
- package/README.md +190 -2
- package/bin/cli.js +394 -0
- package/bin/commands/buildAndroid.js +200 -0
- package/bin/commands/buildIOS.js +237 -0
- package/bin/commands/create.js +406 -0
- package/bin/commands/createBundle.js +375 -0
- package/bin/commands/createComponent.js +115 -0
- package/bin/commands/createScreen.js +161 -0
- package/bin/commands/killServer.js +107 -0
- package/bin/commands/package.js +131 -0
- package/bin/commands/release.js +189 -0
- package/bin/commands/runBundle.js +62 -0
- package/bin/commands/runCloudflare.js +89 -0
- package/bin/commands/runNative.js +109 -0
- package/bin/commands/runServer.js +390 -0
- package/bin/ota/loader.js +361 -0
- package/bin/utils/bundleConfig.js +178 -0
- package/bin/utils/capacitor.js +137 -0
- package/bin/utils/colors.js +215 -0
- package/bin/utils/helpers.js +80 -0
- package/bin/utils/spinner.js +96 -0
- package/bin/utils/templates.js +1824 -0
- package/bin/utils/version.js +108 -0
- package/package.json +58 -4
- package/src/animations/AnimatedBox.js +607 -0
- package/src/animations/AnimatedText.js +105 -0
- package/src/animations/MatrixRain.js +220 -0
- package/src/animations/ParallaxBox.js +369 -0
- package/src/animations/animate.js +332 -0
- package/src/animations/index.js +25 -0
- package/src/app.js +41 -0
- package/src/assets/icon-1024-maskable.png +0 -0
- package/src/assets/icon-192-maskable.png +0 -0
- package/src/assets/icon-192.png +0 -0
- package/src/assets/icon-512-maskable.png +0 -0
- package/src/assets/icon-512.png +0 -0
- package/src/assets/logo.png +0 -0
- package/src/core/App.js +44 -0
- package/src/core/hmr-client.js +142 -0
- package/src/core/index.js +34 -0
- package/src/core/pwa.js +100 -0
- package/src/core/runApp.js +430 -0
- package/src/create-index.sh +237 -0
- package/src/fonts/MaterialIcons-Regular.woff2 +0 -0
- package/src/fonts/icons.css +23 -0
- package/src/index.d.ts +1930 -0
- package/src/index.js +288 -0
- package/src/navigations/AdaptiveScaffold.js +149 -0
- package/src/navigations/AppBar.js +331 -0
- package/src/navigations/BottomNavigation.js +298 -0
- package/src/navigations/CollapsibleSideBar.js +139 -0
- package/src/navigations/Drawer.js +333 -0
- package/src/navigations/DrawerItem.js +260 -0
- package/src/navigations/Router.js +475 -0
- package/src/navigations/Scaffold.js +537 -0
- package/src/navigations/Tabs.js +384 -0
- package/src/navigations/index.js +57 -0
- package/src/services/RamStore.js +213 -0
- package/src/services/Session.js +310 -0
- package/src/services/Storage.js +309 -0
- package/src/services/http.js +350 -0
- package/src/services/index.js +57 -0
- package/src/tools/animation.js +42 -0
- package/src/tools/array.js +95 -0
- package/src/tools/border.js +28 -0
- package/src/tools/clipboard.js +104 -0
- package/src/tools/color.js +329 -0
- package/src/tools/createList.js +215 -0
- package/src/tools/delay.js +55 -0
- package/src/tools/device.js +138 -0
- package/src/tools/dict.js +297 -0
- package/src/tools/dimensions.js +118 -0
- package/src/tools/filter.js +41 -0
- package/src/tools/flex.js +26 -0
- package/src/tools/gradient.js +34 -0
- package/src/tools/grid.js +57 -0
- package/src/tools/index.js +38 -0
- package/src/tools/mapList.js +107 -0
- package/src/tools/margin.js +93 -0
- package/src/tools/memo.js +60 -0
- package/src/tools/os.js +104 -0
- package/src/tools/padding.js +93 -0
- package/src/tools/print.js +69 -0
- package/src/tools/random.js +299 -0
- package/src/tools/ref.js +70 -0
- package/src/tools/rgba.js +4 -0
- package/src/tools/shadow.js +23 -0
- package/src/tools/string.js +85 -0
- package/src/tools/time.js +674 -0
- package/src/tools/transform.js +68 -0
- package/src/tools/transition.js +48 -0
- package/src/tools/useState.js +268 -0
- package/src/tools/uuid.js +42 -0
- package/src/utils/TextInputValidator.js +256 -0
- package/src/utils/composeUpdate.js +65 -0
- package/src/utils/getWidgetProps.js +35 -0
- package/src/utils/index.js +76 -0
- package/src/utils/markdownParser.js +368 -0
- package/src/utils/mediaTime.js +79 -0
- package/src/utils/navigation.js +263 -0
- package/src/utils/scriptInjector.js +73 -0
- package/src/utils/stackPosition.js +31 -0
- package/src/utils/stopWebRefresh.js +77 -0
- package/src/utils/styleInjector.js +38 -0
- package/src/utils/syntaxHighlight.js +339 -0
- package/src/utils/themes.js +347 -0
- package/src/utils/units.js +87 -0
- package/src/utils/visualEffects.js +169 -0
- package/src/widget-factory/addChildren.js +114 -0
- package/src/widget-factory/assignProps.js +256 -0
- package/src/widget-factory/createWidget.js +28 -0
- package/src/widget-factory/effects.js +132 -0
- package/src/widget-factory/index.js +7 -0
- package/src/widget-factory/lifecycle.js +210 -0
- package/src/widget-factory/makeParentable.js +89 -0
- package/src/widget-factory/pixTool.js +40 -0
- package/src/widget-factory/processProps.js +122 -0
- package/src/widget-factory/reactivity.js +98 -0
- package/src/widget-factory/remTool.js +34 -0
- package/src/widget-factory/stackPosition.js +87 -0
- package/src/widget-factory/stringTool.js +26 -0
- package/src/widget-factory/tools.js +249 -0
- package/src/widget-factory/translateProps.js +1049 -0
- package/src/widget-factory/warnings.js +284 -0
- package/src/widget-factory/widgetFactory.js +200 -0
- package/src/widgets/Accordion.js +562 -0
- package/src/widgets/AdMob.js +315 -0
- package/src/widgets/AdSense.js +268 -0
- package/src/widgets/AlertDialog.js +162 -0
- package/src/widgets/Audio.js +311 -0
- package/src/widgets/Avatar.js +210 -0
- package/src/widgets/Badge.js +189 -0
- package/src/widgets/BottomSheet.js +287 -0
- package/src/widgets/Button.js +247 -0
- package/src/widgets/Card.js +33 -0
- package/src/widgets/Carousel.js +301 -0
- package/src/widgets/Chart.js +632 -0
- package/src/widgets/Checkbox.js +106 -0
- package/src/widgets/Chip.js +153 -0
- package/src/widgets/CircularBar.js +352 -0
- package/src/widgets/CircularChart.js +549 -0
- package/src/widgets/CodeViewer.js +236 -0
- package/src/widgets/Column.js +29 -0
- package/src/widgets/Container.js +31 -0
- package/src/widgets/DataTable.js +257 -0
- package/src/widgets/Divider.js +93 -0
- package/src/widgets/DraggBox.js +115 -0
- package/src/widgets/Dropdown.js +505 -0
- package/src/widgets/DroppBox.js +180 -0
- package/src/widgets/FloatingActionButton.js +91 -0
- package/src/widgets/GridView.js +20 -0
- package/src/widgets/Icon.js +33 -0
- package/src/widgets/Image.js +15 -0
- package/src/widgets/Input.js +565 -0
- package/src/widgets/Inspector.js +254 -0
- package/src/widgets/InstallButton.js +110 -0
- package/src/widgets/ListTile.js +224 -0
- package/src/widgets/ListView.js +503 -0
- package/src/widgets/Markdown.js +1236 -0
- package/src/widgets/Modal.js +496 -0
- package/src/widgets/Pagination.js +195 -0
- package/src/widgets/ProgressBar.js +178 -0
- package/src/widgets/QRCode.js +467 -0
- package/src/widgets/Radio.js +132 -0
- package/src/widgets/Rating.js +261 -0
- package/src/widgets/Row.js +29 -0
- package/src/widgets/Skeleton.js +243 -0
- package/src/widgets/Slider.js +527 -0
- package/src/widgets/SnackBar.js +227 -0
- package/src/widgets/Stack.js +29 -0
- package/src/widgets/Stepper.js +296 -0
- package/src/widgets/Switch.js +102 -0
- package/src/widgets/Text.js +98 -0
- package/src/widgets/Tooltip.js +267 -0
- package/src/widgets/TreeView.js +370 -0
- package/src/widgets/Video.js +92 -0
- package/src/widgets/index.js +52 -0
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
// bin/utils/colors.js
|
|
2
|
+
// Visual system of the CLI: ANSI + truecolor (gradients) with safe fallbacks.
|
|
3
|
+
|
|
4
|
+
const TRUE_COLOR = (() => {
|
|
5
|
+
if (process.env.COLORTERM === "truecolor") return true;
|
|
6
|
+
return /iTerm|vscode|kitty|ghostty|hyper|alacritty|wezterm|contour|tmux/i.test(
|
|
7
|
+
process.env.TERM_PROGRAM || "",
|
|
8
|
+
);
|
|
9
|
+
})();
|
|
10
|
+
|
|
11
|
+
// Colors only if there is a TTY and they weren't disabled (NO_COLOR, TERM=dumb)
|
|
12
|
+
const enabled = (() => {
|
|
13
|
+
if (process.env.NO_COLOR) return false;
|
|
14
|
+
if (process.env.TERM === "dumb") return false;
|
|
15
|
+
try {
|
|
16
|
+
return Boolean(process.stdout && process.stdout.isTTY);
|
|
17
|
+
} catch {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
})();
|
|
21
|
+
|
|
22
|
+
const code = (x) => (enabled ? x : "");
|
|
23
|
+
const reset = () => code("\x1b[0m");
|
|
24
|
+
|
|
25
|
+
export const colors = {
|
|
26
|
+
// Standard
|
|
27
|
+
black: code("\x1b[30m"),
|
|
28
|
+
red: code("\x1b[31m"),
|
|
29
|
+
green: code("\x1b[32m"),
|
|
30
|
+
yellow: code("\x1b[33m"),
|
|
31
|
+
blue: code("\x1b[34m"),
|
|
32
|
+
magenta: code("\x1b[35m"),
|
|
33
|
+
cyan: code("\x1b[36m"),
|
|
34
|
+
white: code("\x1b[37m"),
|
|
35
|
+
gray: code("\x1b[90m"),
|
|
36
|
+
// Bright
|
|
37
|
+
brightRed: code("\x1b[91m"),
|
|
38
|
+
brightGreen: code("\x1b[92m"),
|
|
39
|
+
brightYellow: code("\x1b[93m"),
|
|
40
|
+
brightBlue: code("\x1b[94m"),
|
|
41
|
+
brightMagenta: code("\x1b[95m"),
|
|
42
|
+
brightCyan: code("\x1b[96m"),
|
|
43
|
+
brightWhite: code("\x1b[97m"),
|
|
44
|
+
// Styles
|
|
45
|
+
bold: code("\x1b[1m"),
|
|
46
|
+
dim: code("\x1b[2m"),
|
|
47
|
+
italic: code("\x1b[3m"),
|
|
48
|
+
underline: code("\x1b[4m"),
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export const c = (color, text) => {
|
|
52
|
+
const colorCode = colors[color];
|
|
53
|
+
if (colorCode == null) return text;
|
|
54
|
+
return `${colorCode}${text}${reset()}`;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
// ---------- Truecolor ----------
|
|
58
|
+
|
|
59
|
+
const rgb = (r, g, b) => code(`\x1b[38;2;${r};${g};${b}m`);
|
|
60
|
+
const hex2rgb = (hex) => {
|
|
61
|
+
let h = (hex || "#6366f1").replace("#", "");
|
|
62
|
+
if (h.length === 3) h = h.split("").map((x) => x + x).join("");
|
|
63
|
+
return [
|
|
64
|
+
parseInt(h.slice(0, 2), 16) || 0,
|
|
65
|
+
parseInt(h.slice(2, 4), 16) || 0,
|
|
66
|
+
parseInt(h.slice(4, 6), 16) || 0,
|
|
67
|
+
];
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
// ANSI fallback for terminals without truecolor (e.g. Terminal.app)
|
|
71
|
+
const ANSI_FALLBACK = ["\x1b[36m", "\x1b[96m", "\x1b[35m", "\x1b[95m"];
|
|
72
|
+
const paintFallback = (text) => {
|
|
73
|
+
const chars = [...text];
|
|
74
|
+
let out = "";
|
|
75
|
+
for (let i = 0; i < chars.length; i++) {
|
|
76
|
+
out += ANSI_FALLBACK[i % ANSI_FALLBACK.length] + chars[i];
|
|
77
|
+
}
|
|
78
|
+
return out + reset();
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export const hex = (text, hexColor = "#6366f1") => {
|
|
82
|
+
if (!enabled || !TRUE_COLOR) return text;
|
|
83
|
+
const [r, g, b] = hex2rgb(hexColor);
|
|
84
|
+
return `${rgb(r, g, b)}${text}${reset()}`;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
export const gradient = (text, from = "#6366f1", to = "#d946ef") => {
|
|
88
|
+
if (!enabled || text.length === 0) return text;
|
|
89
|
+
if (!TRUE_COLOR) return paintFallback(text);
|
|
90
|
+
const [f1, f2, f3] = hex2rgb(from);
|
|
91
|
+
const [t1, t2, t3] = hex2rgb(to);
|
|
92
|
+
const chars = [...text];
|
|
93
|
+
const N = Math.max(chars.length - 1, 1);
|
|
94
|
+
let out = "";
|
|
95
|
+
for (let i = 0; i < chars.length; i++) {
|
|
96
|
+
out +=
|
|
97
|
+
rgb(
|
|
98
|
+
Math.round(f1 + ((t1 - f1) * i) / N),
|
|
99
|
+
Math.round(f2 + ((t2 - f2) * i) / N),
|
|
100
|
+
Math.round(f3 + ((t3 - f3) * i) / N),
|
|
101
|
+
) + chars[i];
|
|
102
|
+
}
|
|
103
|
+
return out + reset();
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
const PALETTE = [
|
|
107
|
+
"#6366f1",
|
|
108
|
+
"#8b5cf6",
|
|
109
|
+
"#d946ef",
|
|
110
|
+
"#ec4899",
|
|
111
|
+
"#f43f5e",
|
|
112
|
+
"#fb923c",
|
|
113
|
+
"#fbbf24",
|
|
114
|
+
"#34d399",
|
|
115
|
+
"#22d3ee",
|
|
116
|
+
"#6366f1",
|
|
117
|
+
];
|
|
118
|
+
|
|
119
|
+
export const rainbow = (text) => {
|
|
120
|
+
if (!enabled || text.length === 0) return text;
|
|
121
|
+
if (!TRUE_COLOR) return paintFallback(text);
|
|
122
|
+
const chars = [...text];
|
|
123
|
+
const N = chars.length;
|
|
124
|
+
let out = "";
|
|
125
|
+
for (let i = 0; i < N; i++) {
|
|
126
|
+
const [r, g, b] = hex2rgb(PALETTE[Math.floor((i / N) * (PALETTE.length - 1))]);
|
|
127
|
+
out += rgb(r, g, b) + chars[i];
|
|
128
|
+
}
|
|
129
|
+
return out + reset();
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
// ---------- Layout helpers ----------
|
|
133
|
+
|
|
134
|
+
const strip = (t) => t.replace(/\x1b\[[0-9;]*m/g, "");
|
|
135
|
+
export const width = (t) => [...strip(t)].length;
|
|
136
|
+
|
|
137
|
+
// Display length: emoji / wide glyphs count as 2 cells
|
|
138
|
+
const dispLen = (t) =>
|
|
139
|
+
[...strip(t)].reduce(
|
|
140
|
+
(n, ch) => n + (ch.codePointAt(0) >= 0x1100 ? 2 : 1),
|
|
141
|
+
0,
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
export const divider = (text = "", color = "#8b5cf6") => {
|
|
145
|
+
const line = "─".repeat(Math.max(2, 56 - width(text)));
|
|
146
|
+
if (!text) return hex(line, color);
|
|
147
|
+
return hex(line, color) + " " + text + " " + hex(line, color);
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
export const section = (icon, text, color = "#22d3ee") =>
|
|
151
|
+
`\n ${gradient(icon + " " + text, color, "#a855f7")} ${hex("─".repeat(Math.max(4, 46 - width(text))), "#4338ca")}`;
|
|
152
|
+
|
|
153
|
+
// Double-line panel with gradient border and centered title
|
|
154
|
+
export const panel = (title, subtitle = "", { minW = 62 } = {}) => {
|
|
155
|
+
const content = rainbow(title) + (subtitle ? c("gray", " " + subtitle) : "");
|
|
156
|
+
const cw = dispLen(content);
|
|
157
|
+
const W = Math.max(cw + 4, minW);
|
|
158
|
+
const total = W - cw;
|
|
159
|
+
const left = " ".repeat(Math.floor(total / 2));
|
|
160
|
+
const right = " ".repeat(Math.ceil(total / 2));
|
|
161
|
+
const border = TRUE_COLOR
|
|
162
|
+
? gradient("═".repeat(W), "#6366f1", "#a855f7")
|
|
163
|
+
: c("cyan", "═".repeat(W));
|
|
164
|
+
const corner = (ch) => hex(ch, "#818cf8");
|
|
165
|
+
return (
|
|
166
|
+
"\n" +
|
|
167
|
+
corner("╔") + border + corner("╗") + "\n" +
|
|
168
|
+
corner("║") + left + content + right + corner("║") + "\n" +
|
|
169
|
+
corner("╚") + border + corner("╝") + "\n"
|
|
170
|
+
);
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
export const banner = (title, subtitle = "", opts = {}) =>
|
|
174
|
+
panel(title, subtitle, opts);
|
|
175
|
+
|
|
176
|
+
export const badge = (icon, text, color = "brightCyan") =>
|
|
177
|
+
` ${c(color, icon + " " + text)}`;
|
|
178
|
+
|
|
179
|
+
// Status dot (green by default, red/amber for failures/warnings)
|
|
180
|
+
export const dot = (color = "#34d399") => hex("●", color);
|
|
181
|
+
|
|
182
|
+
// Typewriter effect: prints the text character by character (only on a TTY)
|
|
183
|
+
export const typewriter = async (
|
|
184
|
+
text,
|
|
185
|
+
{ ms = 12, color = "#34d399" } = {},
|
|
186
|
+
) => {
|
|
187
|
+
if (!enabled) {
|
|
188
|
+
console.log(text);
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
const paint = TRUE_COLOR
|
|
192
|
+
? (() => {
|
|
193
|
+
const [r, g, b] = hex2rgb(color);
|
|
194
|
+
return (ch) => `\x1b[38;2;${r};${g};${b}m${ch}`;
|
|
195
|
+
})()
|
|
196
|
+
: (ch) => `\x1b[96m${ch}`;
|
|
197
|
+
for (const ch of [...text]) {
|
|
198
|
+
process.stdout.write(paint(ch));
|
|
199
|
+
await new Promise((res) => setTimeout(res, ms));
|
|
200
|
+
}
|
|
201
|
+
process.stdout.write("\x1b[0m\n");
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
// Global Ctrl+C handler
|
|
205
|
+
export const setupCtrlC = () => {
|
|
206
|
+
process.on("SIGINT", () => {
|
|
207
|
+
console.log(`\n\n${rainbow("👋 Bye!")}\n`);
|
|
208
|
+
process.exit(0);
|
|
209
|
+
});
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
// Show help message for Ctrl+C
|
|
213
|
+
export const showExitHint = () => {
|
|
214
|
+
console.log(`${c("gray", "Press Ctrl+C to exit")}`);
|
|
215
|
+
};
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// bin/utils/helpers.js
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { execSync } from "child_process";
|
|
5
|
+
import { c } from "./colors.js";
|
|
6
|
+
|
|
7
|
+
export const createFile = (filePath, content) => {
|
|
8
|
+
try {
|
|
9
|
+
const dir = path.dirname(filePath);
|
|
10
|
+
if (!fs.existsSync(dir)) {
|
|
11
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
12
|
+
}
|
|
13
|
+
fs.writeFileSync(filePath, content, "utf8");
|
|
14
|
+
console.log(`${c("green", "✅")} Created: ${path.basename(filePath)}`);
|
|
15
|
+
} catch (error) {
|
|
16
|
+
console.error(
|
|
17
|
+
`${c("red", "❌")} Failed to create ${filePath}: ${error.message}`,
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const copyFile = (source, dest) => {
|
|
23
|
+
try {
|
|
24
|
+
if (fs.existsSync(source)) {
|
|
25
|
+
const destDir = path.dirname(dest);
|
|
26
|
+
if (!fs.existsSync(destDir)) {
|
|
27
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
28
|
+
}
|
|
29
|
+
fs.copyFileSync(source, dest);
|
|
30
|
+
console.log(`${c("green", "✅")} Copied: ${path.basename(source)}`);
|
|
31
|
+
return true;
|
|
32
|
+
} else {
|
|
33
|
+
console.log(
|
|
34
|
+
`${c("yellow", "⚠️")} Source not found: ${path.basename(source)}`,
|
|
35
|
+
);
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
} catch (error) {
|
|
39
|
+
console.error(
|
|
40
|
+
`${c("red", "❌")} Failed to copy ${path.basename(source)}: ${error.message}`,
|
|
41
|
+
);
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export const makeExecutable = (filePath) => {
|
|
47
|
+
try {
|
|
48
|
+
if (fs.existsSync(filePath)) {
|
|
49
|
+
fs.chmodSync(filePath, 0o755);
|
|
50
|
+
console.log(`${c("blue", "🔧")} Executable: ${path.basename(filePath)}`);
|
|
51
|
+
}
|
|
52
|
+
} catch (error) {
|
|
53
|
+
if (process.env.DEBUG) {
|
|
54
|
+
console.error(
|
|
55
|
+
`${c("red", "⚠️")} Could not make executable: ${path.basename(filePath)}`,
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export const execCmd = (cmd) => {
|
|
62
|
+
try {
|
|
63
|
+
execSync(cmd, {
|
|
64
|
+
stdio: "inherit",
|
|
65
|
+
shell: true,
|
|
66
|
+
});
|
|
67
|
+
return true;
|
|
68
|
+
} catch (error) {
|
|
69
|
+
console.error(`${c("red", "❌")} Command failed: ${cmd}`);
|
|
70
|
+
if (process.env.DEBUG) {
|
|
71
|
+
console.error(error.message);
|
|
72
|
+
}
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
// Fixed: Now returns actual package path
|
|
78
|
+
export const getPackagePath = () => {
|
|
79
|
+
return path.join(process.cwd(), "node_modules", "flet-box");
|
|
80
|
+
};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// bin/utils/spinner.js
|
|
2
|
+
// Dependency-free CLI spinner (keeps flet-box zero-deps, looks like ora).
|
|
3
|
+
|
|
4
|
+
import { execSync } from "child_process";
|
|
5
|
+
import { c } from "./colors.js";
|
|
6
|
+
|
|
7
|
+
const FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
8
|
+
const INTERVAL = 80;
|
|
9
|
+
const RESET = "\x1b[0m";
|
|
10
|
+
const CYAN = "\x1b[96m";
|
|
11
|
+
|
|
12
|
+
const isTTY = () => Boolean(process.stdout && process.stdout.isTTY);
|
|
13
|
+
|
|
14
|
+
class Spinner {
|
|
15
|
+
constructor(text = "") {
|
|
16
|
+
this.text = text;
|
|
17
|
+
this.frame = 0;
|
|
18
|
+
this.timer = null;
|
|
19
|
+
this.running = false;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
start() {
|
|
23
|
+
if (this.running) return this;
|
|
24
|
+
this.running = true;
|
|
25
|
+
process.stdout.write("\n");
|
|
26
|
+
this.timer = setInterval(() => this.render(), INTERVAL);
|
|
27
|
+
this.render();
|
|
28
|
+
return this;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
render() {
|
|
32
|
+
const f = FRAMES[this.frame % FRAMES.length];
|
|
33
|
+
process.stdout.write(`\x1b[1A\x1b[K${CYAN}${f}${RESET} ${this.text}\n`);
|
|
34
|
+
this.frame++;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
stop(msg) {
|
|
38
|
+
if (!this.running) return;
|
|
39
|
+
this.running = false;
|
|
40
|
+
clearInterval(this.timer);
|
|
41
|
+
process.stdout.write(`\x1b[1A\x1b[K${msg}\n`);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
succeed(text) {
|
|
45
|
+
this.stop(`${c("green", "✔")} ${text ?? this.text}`);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
fail(text) {
|
|
49
|
+
this.stop(`${c("red", "✖")} ${text ?? this.text}`);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
setText(text) {
|
|
53
|
+
this.text = text;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Return a no-op spinner when there is no TTY (instant clean output)
|
|
58
|
+
export const spinner = (text) => {
|
|
59
|
+
if (!isTTY()) {
|
|
60
|
+
console.log(c("gray", text));
|
|
61
|
+
return { succeed: () => {}, fail: () => {}, stop: () => {}, setText: () => {} };
|
|
62
|
+
}
|
|
63
|
+
return new Spinner(text).start();
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
// Run a shell command with a spinner. Silences stdout/stderr; on failure the
|
|
67
|
+
// last lines of stderr are shown.
|
|
68
|
+
export const execSpin = (text, cmd) => {
|
|
69
|
+
if (!isTTY()) {
|
|
70
|
+
try {
|
|
71
|
+
execSync(cmd, { stdio: "inherit", shell: true });
|
|
72
|
+
console.log(c("green", `✔ ${text}`));
|
|
73
|
+
return true;
|
|
74
|
+
} catch {
|
|
75
|
+
console.log(c("red", `✖ ${text}`));
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
const s = new Spinner(text).start();
|
|
80
|
+
try {
|
|
81
|
+
execSync(cmd, {
|
|
82
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
83
|
+
shell: true,
|
|
84
|
+
encoding: "utf8",
|
|
85
|
+
});
|
|
86
|
+
s.succeed(text);
|
|
87
|
+
return true;
|
|
88
|
+
} catch (e) {
|
|
89
|
+
s.fail(text);
|
|
90
|
+
const err = (e.stderr || "").toString().trim();
|
|
91
|
+
if (err) {
|
|
92
|
+
console.log(c("red", err.split("\n").slice(-4).join("\n")));
|
|
93
|
+
}
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
};
|