@typecad/ui 1.0.0-alpha.12 → 1.0.0-alpha.14
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/assets/fonts/dejavu/DejaVuSans-Bold.ttf +0 -0
- package/assets/fonts/dejavu/DejaVuSans-ExtraLight.ttf +0 -0
- package/assets/fonts/dejavu/DejaVuSans-Oblique.ttf +0 -0
- package/assets/fonts/dejavu/DejaVuSans.ttf +0 -0
- package/assets/fonts/dejavu/DejaVuSansMono-Bold.ttf +0 -0
- package/assets/fonts/dejavu/DejaVuSansMono.ttf +0 -0
- package/assets/fonts/dejavu/LICENSE +187 -0
- package/assets/fonts/dejavu/README.md +49 -0
- package/dist/cli.js +22 -19
- package/dist/engine-index.js +2 -0
- package/dist/preview/build-program.d.ts +7 -1
- package/dist/preview/build-program.js +94 -15
- package/dist/preview/host-gfx.d.ts +3 -0
- package/dist/preview/host-gfx.js +30 -3
- package/dist/preview/host-ui-runtime.d.ts +115 -0
- package/dist/preview/host-ui-runtime.js +927 -46
- package/dist/ui-engine/block-layout.js +25 -11
- package/dist/ui-engine/color.d.ts +6 -0
- package/dist/ui-engine/color.js +80 -2
- package/dist/ui-engine/compat-report.d.ts +8 -0
- package/dist/ui-engine/compat-report.js +124 -0
- package/dist/ui-engine/css-imports.d.ts +4 -0
- package/dist/ui-engine/css-imports.js +70 -0
- package/dist/ui-engine/css-parser.js +58 -14
- package/dist/ui-engine/default-font.d.ts +25 -0
- package/dist/ui-engine/default-font.js +80 -0
- package/dist/ui-engine/font-assets.d.ts +2 -2
- package/dist/ui-engine/font-assets.js +22 -5
- package/dist/ui-engine/html-parser.d.ts +4 -0
- package/dist/ui-engine/html-parser.js +241 -26
- package/dist/ui-engine/image-assets.d.ts +8 -1
- package/dist/ui-engine/image-assets.js +35 -2
- package/dist/ui-engine/image-decode.d.ts +22 -0
- package/dist/ui-engine/image-decode.js +194 -0
- package/dist/ui-engine/inline-parser.js +1 -1
- package/dist/ui-engine/layout-engine.d.ts +19 -0
- package/dist/ui-engine/layout-engine.js +59 -3
- package/dist/ui-engine/model.d.ts +18 -0
- package/dist/ui-engine/model.js +82 -8
- package/dist/ui-engine/runtime-header/blend-bodies.js +29 -9
- package/dist/ui-engine/runtime-header/canvas-helpers.js +3 -0
- package/dist/ui-engine/runtime-header/canvas-scrollbar.js +115 -111
- package/dist/ui-engine/runtime-header/cuttlefish-gfx.js +21 -0
- package/dist/ui-engine/runtime-header/dirty-scroll-mutators.js +182 -179
- package/dist/ui-engine/runtime-header/forward-decls.js +215 -167
- package/dist/ui-engine/runtime-header/init-press-input.js +138 -135
- package/dist/ui-engine/runtime-header/keyboard.js +682 -380
- package/dist/ui-engine/runtime-header/node-draw-body.js +1658 -1386
- package/dist/ui-engine/runtime-header/paint-order-coords.js +259 -214
- package/dist/ui-engine/runtime-header/paint-rects-repair.js +736 -568
- package/dist/ui-engine/runtime-header/scroll-physics.js +25 -1
- package/dist/ui-engine/runtime-header/state-bindings-nav.js +9 -0
- package/dist/ui-engine/runtime-header/structs.js +228 -216
- package/dist/ui-engine/runtime-header/text-rendering.js +888 -770
- package/dist/ui-engine/runtime-header/tick/bindings-phase.js +118 -116
- package/dist/ui-engine/runtime-header/tick/dirty-draw-phase.js +897 -633
- package/dist/ui-engine/runtime-header/tick/scroll-canvas-phase.js +24 -25
- package/dist/ui-engine/runtime-header/touch-keyboard-fwd.js +78 -23
- package/dist/ui-engine/runtime-header/types-defines.js +110 -93
- package/dist/ui-engine/shadcn-kit.d.ts +1 -0
- package/dist/ui-engine/shadcn-kit.js +506 -0
- package/dist/ui-engine/style-resolver.d.ts +4 -0
- package/dist/ui-engine/style-resolver.js +58 -6
- package/dist/ui-engine/transpile-ui.js +12 -5
- package/dist/ui-engine/ua-stylesheet.d.ts +22 -1
- package/dist/ui-engine/ua-stylesheet.js +119 -32
- package/dist/ui-engine/ui-lowering.js +37 -3
- package/dist/ui-engine/ui-registry.js +32 -4
- package/dist/ui-engine/yoga-layout.js +57 -52
- package/dist/wizard/index.d.ts +2 -0
- package/dist/wizard/index.js +1 -0
- package/dist/wizard/integration-wizard.d.ts +3 -0
- package/dist/wizard/integration-wizard.js +67 -7
- package/dist/wizard/package-writer.d.ts +20 -0
- package/dist/wizard/package-writer.js +79 -0
- package/package.json +11 -5
- package/src/cli.ts +90 -87
- package/src/engine-index.ts +53 -51
- package/src/preview/build-program.ts +810 -734
- package/src/preview/host-gfx.ts +30 -3
- package/src/preview/host-ui-runtime.ts +4132 -3289
- package/src/ui-engine/block-layout.ts +24 -11
- package/src/ui-engine/color.ts +77 -2
- package/src/ui-engine/compat-report.ts +139 -0
- package/src/ui-engine/css-imports.ts +69 -0
- package/src/ui-engine/css-parser.ts +64 -15
- package/src/ui-engine/default-font.ts +95 -0
- package/src/ui-engine/font-assets.ts +545 -525
- package/src/ui-engine/html-parser.ts +615 -397
- package/src/ui-engine/image-assets.ts +37 -2
- package/src/ui-engine/image-decode.ts +244 -0
- package/src/ui-engine/inline-parser.ts +1 -1
- package/src/ui-engine/layout-engine.ts +61 -3
- package/src/ui-engine/model.ts +1322 -1230
- package/src/ui-engine/runtime-header/blend-bodies.ts +29 -9
- package/src/ui-engine/runtime-header/canvas-helpers.ts +3 -0
- package/src/ui-engine/runtime-header/canvas-scrollbar.ts +121 -117
- package/src/ui-engine/runtime-header/cuttlefish-gfx.ts +21 -0
- package/src/ui-engine/runtime-header/dirty-scroll-mutators.ts +188 -185
- package/src/ui-engine/runtime-header/forward-decls.ts +227 -179
- package/src/ui-engine/runtime-header/init-press-input.ts +144 -141
- package/src/ui-engine/runtime-header/keyboard.ts +689 -386
- package/src/ui-engine/runtime-header/node-draw-body.ts +1683 -1411
- package/src/ui-engine/runtime-header/paint-order-coords.ts +265 -220
- package/src/ui-engine/runtime-header/paint-rects-repair.ts +742 -574
- package/src/ui-engine/runtime-header/scroll-physics.ts +25 -1
- package/src/ui-engine/runtime-header/state-bindings-nav.ts +9 -0
- package/src/ui-engine/runtime-header/structs.ts +234 -222
- package/src/ui-engine/runtime-header/text-rendering.ts +894 -776
- package/src/ui-engine/runtime-header/tick/bindings-phase.ts +124 -122
- package/src/ui-engine/runtime-header/tick/dirty-draw-phase.ts +902 -638
- package/src/ui-engine/runtime-header/tick/scroll-canvas-phase.ts +30 -31
- package/src/ui-engine/runtime-header/touch-keyboard-fwd.ts +78 -23
- package/src/ui-engine/runtime-header/types-defines.ts +116 -99
- package/src/ui-engine/shadcn-kit.ts +507 -0
- package/src/ui-engine/style-resolver.ts +471 -416
- package/src/ui-engine/transpile-ui.ts +12 -5
- package/src/ui-engine/ua-stylesheet.ts +137 -31
- package/src/ui-engine/ui-lowering.ts +486 -452
- package/src/ui-engine/ui-registry.ts +556 -524
- package/src/ui-engine/yoga-layout.ts +307 -309
- package/src/wizard/index.ts +46 -38
- package/src/wizard/integration-wizard.ts +689 -619
- package/src/wizard/package-writer.ts +98 -0
|
@@ -5,8 +5,10 @@
|
|
|
5
5
|
// into their project's cuttlefish.config.ts: pick a display, answer bus/pin/
|
|
6
6
|
// speed questions with hardware-aware defaults, then splice the resulting
|
|
7
7
|
// `display` section into the config without touching any other section.
|
|
8
|
-
//
|
|
9
|
-
//
|
|
8
|
+
// Also adds a `preview` npm script to package.json so the desktop preview
|
|
9
|
+
// renderer starts via `npm run preview`. Offers to create a starter .ui entry
|
|
10
|
+
// file when none exists and prints the next build/flash/library steps at the
|
|
11
|
+
// end.
|
|
10
12
|
// ---------------------------------------------------------------------------
|
|
11
13
|
import fs from "node:fs";
|
|
12
14
|
import path from "node:path";
|
|
@@ -14,6 +16,7 @@ import chalk from "chalk";
|
|
|
14
16
|
import { createPromptInterface, promptConfirm, promptInt, promptSelect, promptText, } from "./prompts.js";
|
|
15
17
|
import { DISPLAY_CATALOG, TOUCH_CATALOG, findPinConflicts, } from "./display-catalog.js";
|
|
16
18
|
import { findCuttlefishConfig, findSyntaxError, readConfigSection, readEntryPath, renderDisplayProperty, upsertDisplaySection, } from "./config-writer.js";
|
|
19
|
+
import { findPackageJson, previewScriptCommand, readPackageScript, upsertPackageScript, } from "./package-writer.js";
|
|
17
20
|
import { renderStarterUi } from "./starter-ui.js";
|
|
18
21
|
/** Keys the wizard manages — anything else found in an existing display
|
|
19
22
|
* section is carried over untouched instead of being silently dropped. */
|
|
@@ -405,7 +408,35 @@ export async function runIntegrationWizard(cwd = process.cwd(), streams = {}) {
|
|
|
405
408
|
return { exitCode: 1 };
|
|
406
409
|
}
|
|
407
410
|
}
|
|
408
|
-
// --- 8.
|
|
411
|
+
// --- 8. package.json preview script ------------------------------------------
|
|
412
|
+
// `npm run preview` should start the desktop preview renderer, pointing at
|
|
413
|
+
// the config the wizard just verified. An existing identical script is
|
|
414
|
+
// left untouched; a differing one is only replaced with consent.
|
|
415
|
+
let packageJsonPath;
|
|
416
|
+
let packageJsonText;
|
|
417
|
+
let previewCommand;
|
|
418
|
+
let existingPreview;
|
|
419
|
+
let replacePreview = false;
|
|
420
|
+
const foundPackageJson = findPackageJson(path.dirname(configPath));
|
|
421
|
+
if (foundPackageJson) {
|
|
422
|
+
try {
|
|
423
|
+
packageJsonText = fs.readFileSync(foundPackageJson, "utf-8");
|
|
424
|
+
existingPreview = readPackageScript(packageJsonText, "preview");
|
|
425
|
+
packageJsonPath = foundPackageJson;
|
|
426
|
+
previewCommand = previewScriptCommand(foundPackageJson, configPath);
|
|
427
|
+
}
|
|
428
|
+
catch (err) {
|
|
429
|
+
console.log(` ${chalk.yellow("!")} ${err instanceof Error ? err.message : String(err)} — skipping the npm preview script.`);
|
|
430
|
+
}
|
|
431
|
+
if (previewCommand && existingPreview !== undefined && existingPreview !== previewCommand) {
|
|
432
|
+
console.log(` ${chalk.yellow("!")} package.json already has a preview script: ${chalk.white(existingPreview)}`);
|
|
433
|
+
replacePreview = await promptConfirm(rl, "Replace it with the wizard's preview command?", true);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
else {
|
|
437
|
+
console.log(`${chalk.yellow("!")} No package.json found next to ${path.relative(cwd, configPath)} — skipping the npm preview script.`);
|
|
438
|
+
}
|
|
439
|
+
// --- 9. Summary + write -------------------------------------------------------
|
|
409
440
|
console.log();
|
|
410
441
|
console.log(chalk.dim(" The following display section will be written to"));
|
|
411
442
|
console.log(chalk.dim(` ${path.relative(cwd, configPath)}:`));
|
|
@@ -421,6 +452,17 @@ export async function runIntegrationWizard(cwd = process.cwd(), streams = {}) {
|
|
|
421
452
|
if (carried.length > 0) {
|
|
422
453
|
console.log(` ${chalk.dim(`Kept existing display settings the wizard does not manage: ${carried.join(", ")}`)}`);
|
|
423
454
|
}
|
|
455
|
+
if (previewCommand && packageJsonPath) {
|
|
456
|
+
if (existingPreview === previewCommand) {
|
|
457
|
+
console.log(` ${chalk.dim(`npm script already configured: preview — "${previewCommand}"`)}`);
|
|
458
|
+
}
|
|
459
|
+
else if (existingPreview === undefined || replacePreview) {
|
|
460
|
+
console.log(` ${chalk.dim("Also writes npm script:")} ${chalk.white("preview")}${chalk.dim(` — "${previewCommand}"`)}`);
|
|
461
|
+
}
|
|
462
|
+
else {
|
|
463
|
+
console.log(` ${chalk.dim(`Kept existing preview script: "${existingPreview}"`)}`);
|
|
464
|
+
}
|
|
465
|
+
}
|
|
424
466
|
console.log();
|
|
425
467
|
if (!(await promptConfirm(rl, "Write this configuration?", true))) {
|
|
426
468
|
console.log(chalk.dim(" Aborted — nothing was written."));
|
|
@@ -434,7 +476,21 @@ export async function runIntegrationWizard(cwd = process.cwd(), streams = {}) {
|
|
|
434
476
|
}
|
|
435
477
|
fs.writeFileSync(configPath, updated.text, "utf-8");
|
|
436
478
|
console.log(`${chalk.green("✓")} ${updated.mode === "replaced" ? "Updated" : "Added"} the display section in ${chalk.white(path.relative(cwd, configPath))}`);
|
|
437
|
-
//
|
|
479
|
+
// The preview script rides along with the confirmed write: added when
|
|
480
|
+
// missing, confirmed verbatim when already the wizard's command, and only
|
|
481
|
+
// replaced when the user consented above.
|
|
482
|
+
if (packageJsonPath && packageJsonText !== undefined && previewCommand
|
|
483
|
+
&& (existingPreview === undefined || existingPreview === previewCommand || replacePreview)) {
|
|
484
|
+
const scriptUpsert = upsertPackageScript(packageJsonText, "preview", previewCommand);
|
|
485
|
+
if (scriptUpsert.changed) {
|
|
486
|
+
fs.writeFileSync(packageJsonPath, scriptUpsert.text, "utf-8");
|
|
487
|
+
console.log(`${chalk.green("✓")} ${scriptUpsert.previous !== undefined ? "Updated" : "Added"} npm script ${chalk.white("preview")} in ${chalk.white(path.relative(cwd, packageJsonPath))}`);
|
|
488
|
+
}
|
|
489
|
+
else {
|
|
490
|
+
console.log(`${chalk.green("✓")} npm script ${chalk.white("preview")} already configured in ${chalk.white(path.relative(cwd, packageJsonPath))}`);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
// --- 10. Starter entry file ------------------------------------------------------
|
|
438
494
|
if (entryPath) {
|
|
439
495
|
const entryAbs = path.resolve(path.dirname(configPath), entryPath);
|
|
440
496
|
if (!fs.existsSync(entryAbs) && entryAbs.endsWith(".ui")) {
|
|
@@ -445,7 +501,7 @@ export async function runIntegrationWizard(cwd = process.cwd(), streams = {}) {
|
|
|
445
501
|
}
|
|
446
502
|
}
|
|
447
503
|
}
|
|
448
|
-
// ---
|
|
504
|
+
// --- 11. Next steps ---------------------------------------------------------------
|
|
449
505
|
console.log();
|
|
450
506
|
console.log(chalk.cyan("Next steps"));
|
|
451
507
|
console.log();
|
|
@@ -463,7 +519,7 @@ export async function runIntegrationWizard(cwd = process.cwd(), streams = {}) {
|
|
|
463
519
|
const firstStep = libraries.length > 0 ? 2 : 1;
|
|
464
520
|
console.log(` ${firstStep}. Preview your UI on the desktop:`);
|
|
465
521
|
console.log();
|
|
466
|
-
console.log(` ${chalk.cyan("npx @typecad/cuttlefish preview")}`);
|
|
522
|
+
console.log(` ${chalk.cyan(previewCommand ? "npm run preview" : "npx @typecad/cuttlefish preview")}`);
|
|
467
523
|
console.log();
|
|
468
524
|
console.log(` ${firstStep + 1}. Compile for your board:`);
|
|
469
525
|
console.log();
|
|
@@ -478,7 +534,11 @@ export async function runIntegrationWizard(cwd = process.cwd(), streams = {}) {
|
|
|
478
534
|
console.log(chalk.dim(" off-target, calibrate your panel and update display.touch.calibration."));
|
|
479
535
|
console.log();
|
|
480
536
|
}
|
|
481
|
-
return {
|
|
537
|
+
return {
|
|
538
|
+
exitCode: 0,
|
|
539
|
+
configPath,
|
|
540
|
+
...(packageJsonPath && previewCommand ? { packageJsonPath } : {}),
|
|
541
|
+
};
|
|
482
542
|
}
|
|
483
543
|
finally {
|
|
484
544
|
rl.close();
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** Walk up from `startDir` looking for package.json. */
|
|
2
|
+
export declare function findPackageJson(startDir: string): string | undefined;
|
|
3
|
+
/** Read a single npm script; undefined when missing. Throws on invalid JSON. */
|
|
4
|
+
export declare function readPackageScript(sourceText: string, name: string): string | undefined;
|
|
5
|
+
export interface UpsertScriptResult {
|
|
6
|
+
text: string;
|
|
7
|
+
/** false — the script already had this exact command; text is unchanged. */
|
|
8
|
+
changed: boolean;
|
|
9
|
+
/** The command that was replaced, when a different script existed. */
|
|
10
|
+
previous?: string;
|
|
11
|
+
}
|
|
12
|
+
/** Insert or update one npm script, preserving every other key and their order. */
|
|
13
|
+
export declare function upsertPackageScript(sourceText: string, name: string, command: string): UpsertScriptResult;
|
|
14
|
+
/**
|
|
15
|
+
* The `cuttlefish preview` command the wizard writes as the `preview` npm
|
|
16
|
+
* script. The --config path is made relative to the package.json directory
|
|
17
|
+
* (npm scripts run there), posix-separated, and explicitly ./-prefixed so
|
|
18
|
+
* sibling configs render as `./cuttlefish.config.ts`.
|
|
19
|
+
*/
|
|
20
|
+
export declare function previewScriptCommand(packageJsonPath: string, configPath: string): string;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// package.json script writer for the @typecad/ui integration wizard.
|
|
3
|
+
//
|
|
4
|
+
// package.json is plain JSON (no comments, no expressions), so unlike
|
|
5
|
+
// cuttlefish.config.ts (see config-writer.ts) this needs no AST surgery —
|
|
6
|
+
// parse, compare, set, and re-serialize with the 2-space formatting npm and
|
|
7
|
+
// `cuttlefish create` both write. An unchanged script is a no-op: the
|
|
8
|
+
// original text is returned verbatim so a re-run never reformats the file.
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
import fs from "node:fs";
|
|
11
|
+
import path from "node:path";
|
|
12
|
+
const PACKAGE_FILENAME = "package.json";
|
|
13
|
+
/** Walk up from `startDir` looking for package.json. */
|
|
14
|
+
export function findPackageJson(startDir) {
|
|
15
|
+
let dir = path.resolve(startDir);
|
|
16
|
+
for (;;) {
|
|
17
|
+
const candidate = path.join(dir, PACKAGE_FILENAME);
|
|
18
|
+
if (fs.existsSync(candidate) && fs.statSync(candidate).isFile()) {
|
|
19
|
+
return candidate;
|
|
20
|
+
}
|
|
21
|
+
const parent = path.dirname(dir);
|
|
22
|
+
if (parent === dir)
|
|
23
|
+
return undefined;
|
|
24
|
+
dir = parent;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function parsePackageJson(sourceText) {
|
|
28
|
+
try {
|
|
29
|
+
return JSON.parse(sourceText);
|
|
30
|
+
}
|
|
31
|
+
catch (err) {
|
|
32
|
+
throw new Error(`package.json is not valid JSON: ${err instanceof Error ? err.message : String(err)}`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function scriptsOf(pkg) {
|
|
36
|
+
const scripts = pkg.scripts;
|
|
37
|
+
return typeof scripts === "object" && scripts !== null && !Array.isArray(scripts)
|
|
38
|
+
? scripts
|
|
39
|
+
: undefined;
|
|
40
|
+
}
|
|
41
|
+
/** Read a single npm script; undefined when missing. Throws on invalid JSON. */
|
|
42
|
+
export function readPackageScript(sourceText, name) {
|
|
43
|
+
const scripts = scriptsOf(parsePackageJson(sourceText));
|
|
44
|
+
const value = scripts?.[name];
|
|
45
|
+
return typeof value === "string" ? value : undefined;
|
|
46
|
+
}
|
|
47
|
+
/** Insert or update one npm script, preserving every other key and their order. */
|
|
48
|
+
export function upsertPackageScript(sourceText, name, command) {
|
|
49
|
+
const pkg = parsePackageJson(sourceText);
|
|
50
|
+
const scripts = scriptsOf(pkg);
|
|
51
|
+
const previous = scripts?.[name];
|
|
52
|
+
if (previous === command) {
|
|
53
|
+
return { text: sourceText, changed: false };
|
|
54
|
+
}
|
|
55
|
+
if (!scripts) {
|
|
56
|
+
pkg.scripts = {};
|
|
57
|
+
}
|
|
58
|
+
pkg.scripts[name] = command;
|
|
59
|
+
// Keep the file's trailing-newline convention (npm writes LF; a missing
|
|
60
|
+
// final newline stays missing so the diff is one line, not two).
|
|
61
|
+
const eol = sourceText.endsWith("\r\n") ? "\r\n" : sourceText.endsWith("\n") ? "\n" : "";
|
|
62
|
+
return {
|
|
63
|
+
text: `${JSON.stringify(pkg, null, 2)}${eol}`,
|
|
64
|
+
changed: true,
|
|
65
|
+
...(previous !== undefined ? { previous } : {}),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* The `cuttlefish preview` command the wizard writes as the `preview` npm
|
|
70
|
+
* script. The --config path is made relative to the package.json directory
|
|
71
|
+
* (npm scripts run there), posix-separated, and explicitly ./-prefixed so
|
|
72
|
+
* sibling configs render as `./cuttlefish.config.ts`.
|
|
73
|
+
*/
|
|
74
|
+
export function previewScriptCommand(packageJsonPath, configPath) {
|
|
75
|
+
let rel = path.relative(path.dirname(packageJsonPath), configPath).split(path.sep).join("/");
|
|
76
|
+
if (!rel.startsWith("."))
|
|
77
|
+
rel = `./${rel}`;
|
|
78
|
+
return `cuttlefish preview --config ${rel}`;
|
|
79
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@typecad/ui",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.14",
|
|
4
4
|
"description": "TypeCAD UI authoring library — HTML/CSS-driven graphics for microcontrollers",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -25,6 +25,9 @@
|
|
|
25
25
|
"types": "./dist/ui-engine/*.d.ts",
|
|
26
26
|
"default": "./dist/ui-engine/*.js"
|
|
27
27
|
},
|
|
28
|
+
"./themes/*": {
|
|
29
|
+
"default": "./themes/*"
|
|
30
|
+
},
|
|
28
31
|
"./preview/*": {
|
|
29
32
|
"types": "./dist/preview/*.d.ts",
|
|
30
33
|
"default": "./dist/preview/*.js"
|
|
@@ -37,14 +40,17 @@
|
|
|
37
40
|
"sideEffects": false,
|
|
38
41
|
"files": [
|
|
39
42
|
"dist",
|
|
40
|
-
"src"
|
|
43
|
+
"src",
|
|
44
|
+
"assets"
|
|
41
45
|
],
|
|
42
46
|
"dependencies": {
|
|
43
|
-
"@typecad/cuttlefish": "1.0.0-alpha.
|
|
44
|
-
"chalk": "^
|
|
47
|
+
"@typecad/cuttlefish": "1.0.0-alpha.14",
|
|
48
|
+
"chalk": "^6.0.0",
|
|
45
49
|
"css-tree": "^3.2.1",
|
|
50
|
+
"decode-ico": "^0.4.1",
|
|
46
51
|
"linkedom": "^0.18.12",
|
|
47
52
|
"opentype.js": "^2.0.0",
|
|
53
|
+
"sharp": "^0.35.3",
|
|
48
54
|
"typescript": "^5.7.3",
|
|
49
55
|
"yoga-layout": "^3.2.1"
|
|
50
56
|
},
|
|
@@ -80,7 +86,7 @@
|
|
|
80
86
|
"firmware"
|
|
81
87
|
],
|
|
82
88
|
"engines": {
|
|
83
|
-
"node": ">=
|
|
89
|
+
"node": ">=22.11.0"
|
|
84
90
|
},
|
|
85
91
|
"devDependencies": {
|
|
86
92
|
"@types/node": "^22.10.7",
|
package/src/cli.ts
CHANGED
|
@@ -1,87 +1,90 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// ---------------------------------------------------------------------------
|
|
3
|
-
// @typecad/ui CLI — display integration wizard.
|
|
4
|
-
//
|
|
5
|
-
// npx @typecad/ui --config Run the interactive integration wizard
|
|
6
|
-
// npx @typecad/ui --help Show usage
|
|
7
|
-
// npx @typecad/ui --version Show the installed version
|
|
8
|
-
// ---------------------------------------------------------------------------
|
|
9
|
-
|
|
10
|
-
import { runIntegrationWizard } from "./wizard/integration-wizard.js";
|
|
11
|
-
|
|
12
|
-
const USAGE = `
|
|
13
|
-
@typecad/ui — HTML/CSS-driven graphics for microcontrollers
|
|
14
|
-
|
|
15
|
-
Usage:
|
|
16
|
-
npx @typecad/ui --config Configure a display (+ touch) for your
|
|
17
|
-
cuttlefish project interactively. Writes the
|
|
18
|
-
\`display\` section of cuttlefish.config.ts
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
--
|
|
23
|
-
--
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
console.log("unknown");
|
|
58
|
-
return 0;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
console.error("
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
(
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
);
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// ---------------------------------------------------------------------------
|
|
3
|
+
// @typecad/ui CLI — display integration wizard.
|
|
4
|
+
//
|
|
5
|
+
// npx @typecad/ui --config Run the interactive integration wizard
|
|
6
|
+
// npx @typecad/ui --help Show usage
|
|
7
|
+
// npx @typecad/ui --version Show the installed version
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
|
|
10
|
+
import { runIntegrationWizard } from "./wizard/integration-wizard.js";
|
|
11
|
+
|
|
12
|
+
const USAGE = `
|
|
13
|
+
@typecad/ui — HTML/CSS-driven graphics for microcontrollers
|
|
14
|
+
|
|
15
|
+
Usage:
|
|
16
|
+
npx @typecad/ui --config Configure a display (+ touch) for your
|
|
17
|
+
cuttlefish project interactively. Writes the
|
|
18
|
+
\`display\` section of cuttlefish.config.ts
|
|
19
|
+
and a \`preview\` npm script.
|
|
20
|
+
|
|
21
|
+
Options:
|
|
22
|
+
--config Run the integration wizard
|
|
23
|
+
--help, -h Show this help
|
|
24
|
+
--version, -v Print the installed @typecad/ui version
|
|
25
|
+
|
|
26
|
+
The wizard asks which display module you are using (ILI9341 / ST7796S SPI TFT,
|
|
27
|
+
SSD1309 I2C OLED, desktop simulator, or custom), then walks through bus pins,
|
|
28
|
+
SPI/I2C speed, rotation, and touch controller wiring with hardware-aware
|
|
29
|
+
defaults. It never touches the rest of your cuttlefish.config.ts, and adds a
|
|
30
|
+
\`preview\` script to package.json so the desktop preview renderer starts with
|
|
31
|
+
\`npm run preview\`.
|
|
32
|
+
|
|
33
|
+
Docs: https://github.com/justind000/typecode/tree/main/packages/ui
|
|
34
|
+
`.trim();
|
|
35
|
+
|
|
36
|
+
function printUsage(): void {
|
|
37
|
+
console.log(USAGE);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function main(argv: string[]): Promise<number> {
|
|
41
|
+
const args = argv.slice(2);
|
|
42
|
+
|
|
43
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
44
|
+
printUsage();
|
|
45
|
+
return 0;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (args.includes("--version") || args.includes("-v")) {
|
|
49
|
+
// Lazily read the version so importing this module stays side-effect free.
|
|
50
|
+
const { readFile } = await import("node:fs/promises");
|
|
51
|
+
const { fileURLToPath } = await import("node:url");
|
|
52
|
+
const { dirname, join } = await import("node:path");
|
|
53
|
+
try {
|
|
54
|
+
const packageJson = JSON.parse(
|
|
55
|
+
await readFile(join(dirname(dirname(fileURLToPath(import.meta.url))), "package.json"), "utf-8"),
|
|
56
|
+
) as { version?: string };
|
|
57
|
+
console.log(packageJson.version ?? "unknown");
|
|
58
|
+
return 0;
|
|
59
|
+
} catch {
|
|
60
|
+
console.log("unknown");
|
|
61
|
+
return 0;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (args.length === 0 || (args.length === 1 && (args[0] === "--config" || args[0] === "config"))) {
|
|
66
|
+
if (!process.stdin.isTTY) {
|
|
67
|
+
console.error("The integration wizard is interactive and needs a terminal.");
|
|
68
|
+
console.error("Run `npx @typecad/ui --config` from your project directory, or configure");
|
|
69
|
+
console.error("the `display` section of cuttlefish.config.ts manually:");
|
|
70
|
+
console.error("https://github.com/justind000/typecode/tree/main/packages/ui#display-configuration");
|
|
71
|
+
return 1;
|
|
72
|
+
}
|
|
73
|
+
const result = await runIntegrationWizard(process.cwd());
|
|
74
|
+
return result.exitCode;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
console.error(`Unknown option${args.length > 1 ? "s" : ""}: ${args.join(" ")}\n`);
|
|
78
|
+
printUsage();
|
|
79
|
+
return 2;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
main(process.argv).then(
|
|
83
|
+
(code) => {
|
|
84
|
+
process.exitCode = code;
|
|
85
|
+
},
|
|
86
|
+
(error) => {
|
|
87
|
+
console.error(error instanceof Error ? error.message : error);
|
|
88
|
+
process.exitCode = 1;
|
|
89
|
+
},
|
|
90
|
+
);
|
package/src/engine-index.ts
CHANGED
|
@@ -1,51 +1,53 @@
|
|
|
1
|
-
// ---------------------------------------------------------------------------
|
|
2
|
-
// Engine entry point for @typecad/ui.
|
|
3
|
-
//
|
|
4
|
-
// Cuttlefish dynamically imports this module when UI usage is detected:
|
|
5
|
-
// const engine = await import("@typecad/ui/engine");
|
|
6
|
-
// const hook = await engine.registerTranspilerUI();
|
|
7
|
-
//
|
|
8
|
-
// registerTranspilerUI() returns an object implementing the TranspilerUIHook
|
|
9
|
-
// interface defined in @typecad/cuttlefish. This is the single runtime
|
|
10
|
-
// contract between the two packages.
|
|
11
|
-
// ---------------------------------------------------------------------------
|
|
12
|
-
|
|
13
|
-
import type { TranspilerUIHook } from "@typecad/cuttlefish/ui-hook";
|
|
14
|
-
import {
|
|
15
|
-
resetUIRegistry, loadUIModule, loadUIModuleFromText, getUIModule,
|
|
16
|
-
hasUIModule, allUIModules, allLoweredUIModules,
|
|
17
|
-
markEntryHasUI, entryHasUI, clearEntryHasUI, lowerOnMount,
|
|
18
|
-
generateProjectUITypeDeclarations,
|
|
19
|
-
} from "./ui-engine/ui-registry.js";
|
|
20
|
-
import { resolveColor, resolveColorInternal } from "./ui-engine/color.js";
|
|
21
|
-
import { emitRuntimeHeader } from "./ui-engine/runtime-header.js";
|
|
22
|
-
import { emitCuttlefishGfx } from "./ui-engine/runtime-header/cuttlefish-gfx.js";
|
|
23
|
-
import { splitUiFile } from "./ui-engine/ui-file-splitter.js";
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
*
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Engine entry point for @typecad/ui.
|
|
3
|
+
//
|
|
4
|
+
// Cuttlefish dynamically imports this module when UI usage is detected:
|
|
5
|
+
// const engine = await import("@typecad/ui/engine");
|
|
6
|
+
// const hook = await engine.registerTranspilerUI();
|
|
7
|
+
//
|
|
8
|
+
// registerTranspilerUI() returns an object implementing the TranspilerUIHook
|
|
9
|
+
// interface defined in @typecad/cuttlefish. This is the single runtime
|
|
10
|
+
// contract between the two packages.
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
|
|
13
|
+
import type { TranspilerUIHook } from "@typecad/cuttlefish/ui-hook";
|
|
14
|
+
import {
|
|
15
|
+
resetUIRegistry, loadUIModule, loadUIModuleFromText, getUIModule,
|
|
16
|
+
hasUIModule, allUIModules, allLoweredUIModules,
|
|
17
|
+
markEntryHasUI, entryHasUI, clearEntryHasUI, lowerOnMount,
|
|
18
|
+
generateProjectUITypeDeclarations,
|
|
19
|
+
} from "./ui-engine/ui-registry.js";
|
|
20
|
+
import { resolveColor, resolveColorInternal } from "./ui-engine/color.js";
|
|
21
|
+
import { emitRuntimeHeader } from "./ui-engine/runtime-header.js";
|
|
22
|
+
import { emitCuttlefishGfx } from "./ui-engine/runtime-header/cuttlefish-gfx.js";
|
|
23
|
+
import { splitUiFile } from "./ui-engine/ui-file-splitter.js";
|
|
24
|
+
import { warmUpImageDecoding } from "./ui-engine/image-decode.js";
|
|
25
|
+
|
|
26
|
+
export type { TranspilerUIHook };
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Build and return the TranspilerUIHook — the object cuttlefish core uses
|
|
30
|
+
* to access all UI capabilities (parsing, layout, lowering, emission).
|
|
31
|
+
*/
|
|
32
|
+
export function registerTranspilerUI(): TranspilerUIHook {
|
|
33
|
+
return {
|
|
34
|
+
resetUIRegistry,
|
|
35
|
+
loadUIModule,
|
|
36
|
+
loadUIModuleFromText,
|
|
37
|
+
getUIModule,
|
|
38
|
+
hasUIModule,
|
|
39
|
+
allUIModules,
|
|
40
|
+
allLoweredUIModules,
|
|
41
|
+
markEntryHasUI,
|
|
42
|
+
entryHasUI,
|
|
43
|
+
clearEntryHasUI,
|
|
44
|
+
lowerOnMount,
|
|
45
|
+
resolveColor,
|
|
46
|
+
resolveColorInternal,
|
|
47
|
+
emitRuntimeHeader,
|
|
48
|
+
emitCuttlefishGfx,
|
|
49
|
+
splitUiFile,
|
|
50
|
+
warmUpImageDecoding,
|
|
51
|
+
generateProjectUITypeDeclarations,
|
|
52
|
+
};
|
|
53
|
+
}
|