flet-box 1.1.2 → 1.1.3
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/AGENTS_FOR_CODE_GEN.md +284 -0
- package/CONTRIBUTING.md +238 -0
- package/README.md +2 -2
- package/bin/cli.js +88 -1
- package/bin/commands/auditFix.js +181 -27
- package/bin/commands/checkApi.js +14 -3
- package/bin/commands/checkStructure.js +368 -0
- package/bin/commands/checkSyntax.js +293 -0
- package/bin/commands/checkUi.js +666 -14
- package/bin/commands/create.js +14 -0
- package/bin/commands/createBundle.js +2 -2
- package/bin/commands/metrics.js +448 -0
- package/bin/commands/release.js +18 -0
- package/bin/commands/report.js +849 -0
- package/bin/commands/tools.js +76 -0
- package/bin/commands/unpack.js +39 -11
- package/bin/commands/verify.js +879 -0
- package/bin/mcp.js +280 -0
- package/bin/utils/contract.js +27 -0
- package/bin/utils/dtsProps.js +5 -1
- package/bin/utils/migrationGuide.js +146 -0
- package/bin/utils/moduleExports.js +9 -5
- package/bin/utils/templates.js +225 -18
- package/bin/utils/toolkit.js +191 -0
- package/docs/README.md +5 -1
- package/docs/arquitectura.md +1 -1
- package/docs/cli/README.md +168 -2
- package/docs/guides/README.md +6 -0
- package/docs/guides/accessibility.md +2 -1
- package/docs/guides/ai-toolkit.md +166 -0
- package/docs/guides/compatibility.md +1 -1
- package/docs/guides/migration.md +92 -0
- package/docs/guides/minification-and-protection.md +2 -1
- package/docs/guides/mobile-and-platforms.md +1 -1
- package/docs/guides/online-updates.md +2 -0
- package/docs/server/deployment.md +1 -1
- package/docs/tools/styling.md +2 -2
- package/docs/tools/theme.md +139 -4
- package/docs/widget/Accordion.md +74 -8
- package/docs/widget/AdMob.md +68 -3
- package/docs/widget/AdSense.md +67 -2
- package/docs/widget/AlertDialog.md +1 -1
- package/docs/widget/AnimatedBox.md +80 -39
- package/docs/widget/AnimatedText.md +74 -18
- package/docs/widget/Audio.md +73 -14
- package/docs/widget/Avatar.md +69 -4
- package/docs/widget/Badge.md +68 -3
- package/docs/widget/BottomSheet.md +2 -2
- package/docs/widget/Button.md +69 -3
- package/docs/widget/Card.md +69 -4
- package/docs/widget/Carousel.md +67 -2
- package/docs/widget/Chart.md +67 -2
- package/docs/widget/Checkbox.md +74 -8
- package/docs/widget/Chip.md +68 -3
- package/docs/widget/CircularBar.md +74 -15
- package/docs/widget/CircularChart.md +71 -10
- package/docs/widget/CodeViewer.md +67 -2
- package/docs/widget/Column.md +68 -3
- package/docs/widget/Container.md +68 -3
- package/docs/widget/DataTable.md +67 -2
- package/docs/widget/Divider.md +67 -2
- package/docs/widget/DraggBox.md +67 -2
- package/docs/widget/Dropdown.md +76 -10
- package/docs/widget/DroppBox.md +67 -2
- package/docs/widget/FloatingActionButton.md +68 -3
- package/docs/widget/GridView.md +67 -2
- package/docs/widget/Icon.md +71 -5
- package/docs/widget/Image.md +68 -3
- package/docs/widget/Input.md +68 -3
- package/docs/widget/Inspector.md +2 -2
- package/docs/widget/InstallButton.md +73 -13
- package/docs/widget/ListTile.md +69 -3
- package/docs/widget/ListView.md +67 -2
- package/docs/widget/Maps.md +68 -3
- package/docs/widget/Markdown.md +74 -15
- package/docs/widget/MatrixRain.md +72 -11
- package/docs/widget/Menu.md +209 -0
- package/docs/widget/Modal.md +3 -3
- package/docs/widget/Pagination.md +68 -3
- package/docs/widget/ParallaxBox.md +72 -12
- package/docs/widget/ProgressBar.md +69 -4
- package/docs/widget/QRCode.md +67 -2
- package/docs/widget/README.md +54 -50
- package/docs/widget/Radio.md +76 -10
- package/docs/widget/Rating.md +70 -6
- package/docs/widget/Row.md +68 -3
- package/docs/widget/Skeleton.md +68 -3
- package/docs/widget/Slider.md +75 -9
- package/docs/widget/SnackBar.md +2 -2
- package/docs/widget/Stack.md +68 -3
- package/docs/widget/Stepper.md +68 -3
- package/docs/widget/Switch.md +74 -8
- package/docs/widget/Text.md +71 -4
- package/docs/widget/ThemePicker.md +197 -0
- package/docs/widget/Tooltip.md +72 -7
- package/docs/widget/TreeView.md +70 -10
- package/docs/widget/Video.md +71 -10
- package/package.json +10 -3
- package/skills/fletbox-design/SKILL.md +89 -5
- package/skills/fletbox-motion/SKILL.md +1 -1
- package/skills/fletbox-rules/SKILL.md +56 -4
- package/src/core/runApp.js +12 -0
- package/src/index.d.ts +374 -101
- package/src/index.js +9 -0
- package/src/navigations/AdaptiveScaffold.js +2 -2
- package/src/navigations/BottomNavigation.js +1 -1
- package/src/navigations/Scaffold.js +18 -6
- package/src/tools/useState.js +11 -4
- package/src/utils/colors.js +275 -0
- package/src/utils/errorBoundary.js +288 -0
- package/src/utils/index.js +10 -2
- package/src/utils/stackPosition.js +39 -24
- package/src/utils/syntaxHighlight.js +4 -1
- package/src/utils/themes.js +279 -3
- package/src/widget-factory/addChildren.js +17 -10
- package/src/widget-factory/assignProps.js +18 -6
- package/src/widget-factory/createWidget.js +7 -0
- package/src/widget-factory/deprecations.js +77 -0
- package/src/widget-factory/translateProps.js +11 -1
- package/src/widget-factory/warnings.js +1 -27
- package/src/widget-factory/widgetFactory.js +59 -17
- package/src/widgets/Accordion.js +21 -7
- package/src/widgets/Badge.js +11 -2
- package/src/widgets/Button.js +15 -3
- package/src/widgets/Carousel.js +12 -4
- package/src/widgets/Chart.js +7 -2
- package/src/widgets/Checkbox.js +1 -2
- package/src/widgets/Chip.js +24 -10
- package/src/widgets/CircularBar.js +9 -3
- package/src/widgets/CircularChart.js +5 -3
- package/src/widgets/Container.js +6 -0
- package/src/widgets/Divider.js +3 -1
- package/src/widgets/DraggBox.js +9 -0
- package/src/widgets/Dropdown.js +3 -3
- package/src/widgets/DroppBox.js +5 -0
- package/src/widgets/FloatingActionButton.js +1 -1
- package/src/widgets/Icon.js +5 -1
- package/src/widgets/InstallButton.js +4 -2
- package/src/widgets/Markdown.js +171 -103
- package/src/widgets/Menu.js +340 -0
- package/src/widgets/Modal.js +7 -1
- package/src/widgets/Pagination.js +10 -5
- package/src/widgets/ProgressBar.js +5 -4
- package/src/widgets/QRCode.js +4 -0
- package/src/widgets/Radio.js +1 -2
- package/src/widgets/Rating.js +9 -0
- package/src/widgets/Slider.js +4 -1
- package/src/widgets/SnackBar.js +2 -2
- package/src/widgets/Switch.js +1 -2
- package/src/widgets/Text.js +9 -5
- package/src/widgets/ThemePicker.js +234 -0
- package/src/widgets/TreeView.js +2 -1
- package/src/widgets/index.js +2 -0
- package/docs/CONTRIBUTING.md +0 -156
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file bin/commands/tools.js
|
|
3
|
+
* @description `flet-box tools` — the diagnosis toolkit, printed as a map.
|
|
4
|
+
*
|
|
5
|
+
* The catalogue lives in `bin/utils/toolkit.js` and is pure data. This file is
|
|
6
|
+
* its human mouth: the question each tool answers, the exact command, and what
|
|
7
|
+
* it reads or writes. `--emit` writes the same list to `.fletbox/api/tools.json`
|
|
8
|
+
* so an assistant that cannot run a shell can still discover it, and `--json`
|
|
9
|
+
* prints it for a script.
|
|
10
|
+
*
|
|
11
|
+
* Node core only: this file ships inside every app `flet-box create` builds.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import fs from "node:fs";
|
|
15
|
+
import path from "node:path";
|
|
16
|
+
import { TOOLS, catalogJson, CATALOG_VERSION } from "../utils/toolkit.js";
|
|
17
|
+
import { c, banner, section } from "../utils/colors.js";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The `flet-box tools` command.
|
|
21
|
+
*
|
|
22
|
+
* @param {string[]} argv Flags after the command name.
|
|
23
|
+
* @param {{print?: (line: string) => void, root?: string}} [io]
|
|
24
|
+
* @returns {Promise<{exitCode: number}>}
|
|
25
|
+
*/
|
|
26
|
+
export const tools = async (argv = [], io = {}) => {
|
|
27
|
+
const print = io.print ?? ((line) => console.log(line));
|
|
28
|
+
const rootIndex = argv.indexOf("--root");
|
|
29
|
+
const root = path.resolve(
|
|
30
|
+
rootIndex >= 0 && argv[rootIndex + 1] ? argv[rootIndex + 1] : io.root || process.cwd(),
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
if (argv.includes("--emit")) {
|
|
34
|
+
const dir = path.join(root, ".fletbox", "api");
|
|
35
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
36
|
+
const target = path.join(dir, "tools.json");
|
|
37
|
+
fs.writeFileSync(target, `${JSON.stringify(catalogJson(), null, 2)}\n`, "utf8");
|
|
38
|
+
print(`${c("green", "✅")} Wrote ${path.relative(root, target)} — ${TOOLS.length} read-only tool(s)`);
|
|
39
|
+
return { exitCode: 0 };
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (argv.includes("--json")) {
|
|
43
|
+
print(JSON.stringify(catalogJson(), null, 2));
|
|
44
|
+
return { exitCode: 0 };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
print(banner("🧰 FletBox toolkit", `${TOOLS.length} read-only tool(s) · catalogue v${CATALOG_VERSION}`));
|
|
48
|
+
print(
|
|
49
|
+
c(
|
|
50
|
+
"gray",
|
|
51
|
+
" Pick the question you have; the command under it is the answer. Nothing here edits, deletes or publishes.",
|
|
52
|
+
),
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
for (const tool of TOOLS) {
|
|
56
|
+
print("");
|
|
57
|
+
print(` ${c("brightCyan", tool.id.padEnd(16))} ${c("bold", tool.question)}`);
|
|
58
|
+
print(` ${c("gray", " ".repeat(16))} ${c("brightWhite", tool.usage)}`);
|
|
59
|
+
print(
|
|
60
|
+
` ${c("gray", " ".repeat(16))} output: ${tool.output.join(", ")}` +
|
|
61
|
+
(tool.writes.length ? ` · writes: ${tool.writes.join("; ")}` : ` · ${c("green", "writes nothing")}`),
|
|
62
|
+
);
|
|
63
|
+
for (const when of tool.when) print(` ${c("gray", " ".repeat(16))} · ${c("gray", when)}`);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
print("");
|
|
67
|
+
print(section("•", "as data", "#67e8f9"));
|
|
68
|
+
print(` ${c("gray", "flet-box tools --emit →")} .fletbox/api/tools.json`);
|
|
69
|
+
print(` ${c("gray", "flet-box tools --json →")} the same catalogue on stdout`);
|
|
70
|
+
print(
|
|
71
|
+
` ${c("gray", "flet-box mcp →")} the same tools over MCP stdio, for an assistant without a shell`,
|
|
72
|
+
);
|
|
73
|
+
return { exitCode: 0 };
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
export default tools;
|
package/bin/commands/unpack.js
CHANGED
|
@@ -28,6 +28,7 @@ import { c, banner, section } from "../utils/colors.js";
|
|
|
28
28
|
import { neutralise } from "../utils/neutralise.js";
|
|
29
29
|
import { membersOf, propsInterfaceFor, resolveInterfaceProps } from "../utils/dtsProps.js";
|
|
30
30
|
import { STRUCTURAL_PROPS, loadApi, nearest } from "./checkApi.js";
|
|
31
|
+
import { deprecationFor } from "../../src/widget-factory/deprecations.js";
|
|
31
32
|
|
|
32
33
|
/**
|
|
33
34
|
* Index of the character closing the bracket opened at `open`, or -1.
|
|
@@ -59,7 +60,7 @@ const matchPair = (text, open) => {
|
|
|
59
60
|
* @param {string} packageDir Installed package root.
|
|
60
61
|
* @returns {Map<string, string>} name → absolute file
|
|
61
62
|
*/
|
|
62
|
-
const definitionIndex = (packageDir) => {
|
|
63
|
+
export const definitionIndex = (packageDir) => {
|
|
63
64
|
const index = new Map();
|
|
64
65
|
const reexports = [];
|
|
65
66
|
const src = path.join(packageDir, "src");
|
|
@@ -213,6 +214,11 @@ const readProps = (file) => {
|
|
|
213
214
|
spread,
|
|
214
215
|
child: /\bchild\b/.test(code),
|
|
215
216
|
children: /\bchildren\b/.test(code),
|
|
217
|
+
// Every identifier the file mentions. A prop can be read somewhere other
|
|
218
|
+
// than the destructuring — `ThemeProvider` takes `theme` as a direct
|
|
219
|
+
// parameter, `Inspector` reads `widget` inside the view it delegates to —
|
|
220
|
+
// and a prop the file never mentions at all is the only honest "dead".
|
|
221
|
+
identifiers: new Set(code.match(/\b[A-Za-z_$][\w$]*\b/g) || []),
|
|
216
222
|
};
|
|
217
223
|
};
|
|
218
224
|
|
|
@@ -318,7 +324,7 @@ const INLINE = "(inline)";
|
|
|
318
324
|
* @param {string} name
|
|
319
325
|
* @returns {string|null} interface name, `INLINE`, or null
|
|
320
326
|
*/
|
|
321
|
-
const propsSource = (api, name) => {
|
|
327
|
+
export const propsSource = (api, name) => {
|
|
322
328
|
const iface = propsInterfaceFor(api.interfaces, name);
|
|
323
329
|
if (iface) return iface;
|
|
324
330
|
const first = api.signatures?.get(name)?.params?.[0];
|
|
@@ -333,7 +339,7 @@ const propsSource = (api, name) => {
|
|
|
333
339
|
* @param {Map<string, string>} definitions
|
|
334
340
|
* @returns {object|null} null when the package has no such export
|
|
335
341
|
*/
|
|
336
|
-
const unpackWidget = (api, name, definitions) => {
|
|
342
|
+
export const unpackWidget = (api, name, definitions) => {
|
|
337
343
|
const typedBy = propsSource(api, name);
|
|
338
344
|
const ifaceName = typedBy && typedBy !== INLINE ? typedBy : `${name}Props`;
|
|
339
345
|
const file = definitions.get(name);
|
|
@@ -353,7 +359,9 @@ const unpackWidget = (api, name, definitions) => {
|
|
|
353
359
|
? api.interfaces.get(ifaceName).props
|
|
354
360
|
: new Map();
|
|
355
361
|
const aliases = aliasGroups(api);
|
|
356
|
-
const source = file
|
|
362
|
+
const source = file
|
|
363
|
+
? readProps(file)
|
|
364
|
+
: { read: new Map(), spread: false, child: false, children: false, identifiers: new Set() };
|
|
357
365
|
|
|
358
366
|
const props = [];
|
|
359
367
|
const names = new Set([...declared.keys(), ...source.read.keys()]);
|
|
@@ -380,8 +388,16 @@ const unpackWidget = (api, name, definitions) => {
|
|
|
380
388
|
props.push(entry);
|
|
381
389
|
}
|
|
382
390
|
|
|
391
|
+
// Dead means nobody mentions it: a prop can be read outside the
|
|
392
|
+
// destructuring — as a direct parameter, or inside a view the widget
|
|
393
|
+
// delegates to — and a name the file never mentions is the honest case.
|
|
383
394
|
const dead = props.filter(
|
|
384
|
-
(c_) =>
|
|
395
|
+
(c_) =>
|
|
396
|
+
c_.declared &&
|
|
397
|
+
!c_.engine &&
|
|
398
|
+
!c_.read &&
|
|
399
|
+
!c_.structural &&
|
|
400
|
+
!source.identifiers.has(c_.prop),
|
|
385
401
|
);
|
|
386
402
|
const invented = props.filter(
|
|
387
403
|
(c_) => !c_.declared && !c_.engine && c_.read && !c_.structural,
|
|
@@ -567,8 +583,8 @@ const renderWidget = (data, api) => {
|
|
|
567
583
|
const renderDiff = (data) => {
|
|
568
584
|
const { dead, invented, hidden, docOnly, codeOnly } = data.gaps;
|
|
569
585
|
const rows = [
|
|
570
|
-
["DEAD", dead.map((p) => p.prop), "in index.d.ts, handled by nothing"],
|
|
571
|
-
["INVENTED", invented.map((p) => p.prop),
|
|
586
|
+
["DEAD", dead.map((p) => p.prop), "in index.d.ts, handled by nothing — wire it in the widget or drop it from the declaration"],
|
|
587
|
+
["INVENTED", invented.map((p) => p.prop), `read by the widget, absent from every type — declare it in ${data.interface || `${data.name}Props`}`],
|
|
572
588
|
["UNDOCUMENTED", hidden.map((p) => p.prop), "the engine routes it, the interface hides it"],
|
|
573
589
|
["DOC-ONLY", docOnly, "the doc page promises it, the code has never heard of it"],
|
|
574
590
|
["CODE-ONLY", codeOnly, "the code accepts it, the doc page omits it"],
|
|
@@ -838,14 +854,19 @@ const exampleValue = (p, api) => {
|
|
|
838
854
|
};
|
|
839
855
|
|
|
840
856
|
const RANK = ["text", "label", "title", "placeholder", "value", "data", "items", "options", "rows", "src", "name"];
|
|
841
|
-
/**
|
|
842
|
-
|
|
857
|
+
/**
|
|
858
|
+
* Props a pasted example never needs to demonstrate: identity and style plumbing,
|
|
859
|
+
* and the two sizes. A number sampled blind collapses the widget it is pasted
|
|
860
|
+
* into — `Switch({ width: 16 })` is 16 units wide over a 24-unit knob — so the
|
|
861
|
+
* canonical call lets each widget's own default size it.
|
|
862
|
+
*/
|
|
863
|
+
const SKIP = new Set(["ref", "key", "id", "className", "style", "width", "height"]);
|
|
843
864
|
|
|
844
865
|
/**
|
|
845
866
|
* The order an example should demonstrate props in: what it says, what it does,
|
|
846
867
|
* how it looks. Props outside these groups come last.
|
|
847
868
|
*/
|
|
848
|
-
const GROUPS = [RANK, ["
|
|
869
|
+
const GROUPS = [RANK, ["padding", "margin", "gap", "bgColor", "color", "borderRadius"]];
|
|
849
870
|
|
|
850
871
|
/** Within the callback group a renderer says more than a hook, a hook more than an option. */
|
|
851
872
|
const callbackRank = (name) => (name.startsWith("render") ? 0 : name.startsWith("on") ? 1 : 2);
|
|
@@ -868,6 +889,9 @@ const buildExample = (data, api) => {
|
|
|
868
889
|
(p) =>
|
|
869
890
|
!p.structural &&
|
|
870
891
|
(required(p) || ((p.read || p.engine) && !dead.has(p.prop))) &&
|
|
892
|
+
// The example is the call an app pastes, so it carries the current spelling
|
|
893
|
+
// only: `{ onPress, onToggle }` in one call teaches the retired name.
|
|
894
|
+
!deprecationFor(data.name, p.prop) &&
|
|
871
895
|
!SKIP.has(p.prop),
|
|
872
896
|
);
|
|
873
897
|
const groupOf = (p) => {
|
|
@@ -891,7 +915,11 @@ const buildExample = (data, api) => {
|
|
|
891
915
|
(p.optional === false ? -100000 : 0) +
|
|
892
916
|
groupOf(p) * 1000 +
|
|
893
917
|
within(p) * 10 +
|
|
894
|
-
(p.own ? 0 : 5)
|
|
918
|
+
(p.own ? 0 : 5) +
|
|
919
|
+
// When two declared names reach one target the camelCase one wins: `onclick`
|
|
920
|
+
// is a deliberate alias, but the example is what gets pasted, and the name
|
|
921
|
+
// every page of the docs uses is `onClick`.
|
|
922
|
+
(p.prop === p.prop.toLowerCase() ? 1 : 0);
|
|
895
923
|
// One prop per engine target: `text`, `label`, `title` and `caption` all write
|
|
896
924
|
// textContent, so an example carrying two of them is noise, not a demo.
|
|
897
925
|
const seen = new Set();
|