@typecad/ui 1.0.0-alpha.13 → 1.0.0-alpha.15

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 (60) hide show
  1. package/README.md +1457 -1469
  2. package/dist/cli.js +22 -19
  3. package/dist/preview/host-ui-runtime.js +0 -1
  4. package/dist/ui-engine/model.js +7 -1
  5. package/dist/ui-engine/runtime-header/canvas-scrollbar.js +115 -115
  6. package/dist/ui-engine/runtime-header/dirty-scroll-mutators.js +182 -182
  7. package/dist/ui-engine/runtime-header/forward-decls.js +227 -216
  8. package/dist/ui-engine/runtime-header/init-press-input.js +138 -138
  9. package/dist/ui-engine/runtime-header/keyboard.js +676 -676
  10. package/dist/ui-engine/runtime-header/node-draw-body.js +1658 -1656
  11. package/dist/ui-engine/runtime-header/paint-order-coords.js +259 -259
  12. package/dist/ui-engine/runtime-header/paint-rects-repair.js +736 -736
  13. package/dist/ui-engine/runtime-header/scroll-physics.js +4 -4
  14. package/dist/ui-engine/runtime-header/structs.js +228 -228
  15. package/dist/ui-engine/runtime-header/text-rendering.js +888 -888
  16. package/dist/ui-engine/runtime-header/tick/bindings-phase.js +118 -118
  17. package/dist/ui-engine/runtime-header/tick/dirty-draw-phase.js +896 -896
  18. package/dist/ui-engine/runtime-header/tick/scroll-canvas-phase.js +24 -24
  19. package/dist/ui-engine/runtime-header/touch-keyboard-fwd.js +11 -11
  20. package/dist/ui-engine/runtime-header/types-defines.js +110 -110
  21. package/dist/ui-engine/shadcn-kit.d.ts +1 -1
  22. package/dist/ui-engine/shadcn-kit.js +4 -0
  23. package/dist/ui-engine/ui-lowering.d.ts +1 -1
  24. package/dist/ui-engine/ui-lowering.js +14 -5
  25. package/dist/ui-engine/ui-registry.js +9 -1
  26. package/dist/wizard/display-catalog.d.ts +0 -3
  27. package/dist/wizard/display-catalog.js +3 -12
  28. package/dist/wizard/index.d.ts +2 -0
  29. package/dist/wizard/index.js +1 -0
  30. package/dist/wizard/integration-wizard.d.ts +3 -0
  31. package/dist/wizard/integration-wizard.js +69 -20
  32. package/dist/wizard/package-writer.d.ts +20 -0
  33. package/dist/wizard/package-writer.js +79 -0
  34. package/package.json +4 -4
  35. package/src/cli.ts +90 -87
  36. package/src/preview/host-ui-runtime.ts +0 -1
  37. package/src/ui-engine/model.ts +6 -1
  38. package/src/ui-engine/runtime-header/canvas-scrollbar.ts +121 -121
  39. package/src/ui-engine/runtime-header/dirty-scroll-mutators.ts +188 -188
  40. package/src/ui-engine/runtime-header/forward-decls.ts +238 -227
  41. package/src/ui-engine/runtime-header/init-press-input.ts +144 -144
  42. package/src/ui-engine/runtime-header/keyboard.ts +689 -689
  43. package/src/ui-engine/runtime-header/node-draw-body.ts +1683 -1681
  44. package/src/ui-engine/runtime-header/paint-order-coords.ts +265 -265
  45. package/src/ui-engine/runtime-header/paint-rects-repair.ts +742 -742
  46. package/src/ui-engine/runtime-header/scroll-physics.ts +4 -4
  47. package/src/ui-engine/runtime-header/structs.ts +234 -234
  48. package/src/ui-engine/runtime-header/text-rendering.ts +894 -894
  49. package/src/ui-engine/runtime-header/tick/bindings-phase.ts +124 -124
  50. package/src/ui-engine/runtime-header/tick/dirty-draw-phase.ts +902 -902
  51. package/src/ui-engine/runtime-header/tick/scroll-canvas-phase.ts +30 -30
  52. package/src/ui-engine/runtime-header/touch-keyboard-fwd.ts +11 -11
  53. package/src/ui-engine/runtime-header/types-defines.ts +116 -116
  54. package/src/ui-engine/shadcn-kit.ts +4 -0
  55. package/src/ui-engine/ui-lowering.ts +12 -4
  56. package/src/ui-engine/ui-registry.ts +9 -1
  57. package/src/wizard/display-catalog.ts +261 -273
  58. package/src/wizard/index.ts +46 -38
  59. package/src/wizard/integration-wizard.ts +679 -619
  60. package/src/wizard/package-writer.ts +98 -0
@@ -1,144 +1,144 @@
1
- // Slice of the C++ runtime header (original source lines 2442-2561).
2
- // ui_init, press/release entry points, pin-watch polling.
3
- // See docs/superpowers/specs/2026-07-12-split-runtime-header-design.md.
4
- export function emitInitPressInput(): string {
5
- return `
6
- // Initial draw: mark all nodes dirty so the first ui_tick renders everything.
7
- // Called once in setup() before the loop begins.
8
- // Also seed each text-bound node's buffer from its flash literal so the first
9
- // strcmp in ui_tick has a valid baseline (no spurious redraw on frame 1).
10
- static inline void ui_init(void) {
11
- // Discover <drawer> panels and seed them closed (full-travel offsets, so a
12
- // closed drawer never paints at its rest position).
13
- ui_drawer_discover();
14
- // Allocate the per-node scroll-canvas-OK flag array (once; __ui_node_count
15
- // is a compile-time constant known by this point). calloc zeroes it — all
16
- // containers start locked until the scroll-container loop proves their
17
- // canvas fits.
18
- if (!__ui_scroll_canvas_ok && __ui_node_count > 0) {
19
- __ui_scroll_canvas_ok = new (std::nothrow) uint8_t[__ui_node_count]();
20
- }
21
- if (!__ui_scroll_render_locked && __ui_node_count > 0) {
22
- __ui_scroll_render_locked = new (std::nothrow) uint8_t[__ui_node_count]();
23
- }
24
- for (uint16_t i = 0; i < __ui_node_count; i++) {
25
- __ui_nodes[i].dirty = 1;
26
- __ui_nodes[i].lastTextHeight = 0;
27
- __ui_nodes[i].layoutCacheKey = 0;
28
- if (__ui_nodes[i].scrollable) {
29
- // Force the first scroll-canvas composition to seed every pixel. After
30
- // that, a dirty child can be repaired in place without repainting the
31
- // entire viewport.
32
- __ui_nodes[i].lastPaintedScrollY = static_cast<int16_t>(
33
- __ui_nodes[i].scrollY - (__ui_nodes[i].box.h > 0 ? __ui_nodes[i].box.h : 1));
34
- }
35
- if (__ui_nodes[i].kind == NODE_PROGRESS || __ui_nodes[i].kind == NODE_RANGE) {
36
- __ui_nodes[i].lastTextWidth = -1;
37
- }
38
- }
39
- for (uint16_t i = 0; i < __ui_binding_count; i++) {
40
- if (__ui_bindings[i].prop == PROP_TEXT && __ui_bindings[i].textFn) {
41
- uint16_t n = __ui_bindings[i].node;
42
- __ui_nodes[n].hasTextBinding = 1;
43
- strncpy(__ui_nodes[n].textBuffer, __ui_nodes[n].text ? __ui_nodes[n].text : "", UI_TEXT_BUF);
44
- __ui_nodes[n].textBuffer[UI_TEXT_BUF] = '\\0';
45
- } else if (__ui_bindings[i].fn) {
46
- // Prime numeric binding caches once at setup; the first tick can then skip
47
- // redundant assignments and dirty propagation when values are unchanged.
48
- __ui_bindings[i].lastValue = __ui_bindings[i].fn();
49
- __ui_bindings[i].initialized = 1;
50
- }
51
- }
52
- // Seed virtualized-list runtime state. The fn pointers can't be baked into
53
- // the static node initializer: ui.bindList is resolved AFTER ui.mount lowers
54
- // the HTML, so the lowering can't see the binding yet. Instead the lowering
55
- // emits the UIListBinding table (the binding's fn bodies) and ui_init copies
56
- // the pointers onto each <list> node here, then computes the initial count
57
- // and contentHeight so the first paint and the scroll clamp bound are correct.
58
- for (uint16_t b = 0; b < __ui_list_binding_count; b++) {
59
- uint16_t n = __ui_list_bindings[b].node;
60
- if (n >= __ui_node_count || !__ui_nodes[n].virtualized) continue;
61
- __ui_nodes[n].listCountFn = __ui_list_bindings[b].countFn;
62
- __ui_nodes[n].listItemFn = __ui_list_bindings[b].itemFn;
63
- __ui_nodes[n].listTapFn = __ui_list_bindings[b].tapFn;
64
- }
65
- for (uint16_t i = 0; i < __ui_node_count; i++) {
66
- if (!__ui_nodes[i].virtualized || !__ui_nodes[i].listCountFn) continue;
67
- uint16_t ih = __ui_nodes[i].listItemHeight > 0 ? __ui_nodes[i].listItemHeight : 24;
68
- uint16_t cnt = __ui_nodes[i].listCountFn();
69
- __ui_nodes[i].listCount = cnt;
70
- __ui_nodes[i].contentHeight = static_cast<int16_t>(static_cast<uint32_t>(cnt) * ih);
71
- __ui_nodes[i].scrollY = 0;
72
- __ui_nodes[i].overscrollPx = 0;
73
- __ui_nodes[i].settling = 0;
74
- __ui_nodes[i].lastPaintedScrollY = -(__ui_nodes[i].box.h > 0 ? __ui_nodes[i].box.h : 1);
75
- }
76
- ui_build_draw_order();
77
- ui_build_scroll_owner_table();
78
- ui_refresh_active_screen_bg_node();
79
- if (!__ui_scroll_candidates && __ui_node_count > 0) {
80
- __ui_scroll_candidates = new (std::nothrow) UIScrollPaintCandidate[__ui_node_count];
81
- }
82
- }
83
-
84
- // Debounce: ignore press/release events within 50ms of the last edge.
85
- // Mechanical switches bounce (multiple edges in ~5-20ms); without this, the
86
- // transition gets armed/interrupted dozens of times per physical press.
87
- static volatile uint32_t __ui_last_edge_time = 0;
88
- #define UI_DEBOUNCE_MS 50
89
-
90
- static inline void ui_set_pressed(uint16_t nodeIdx, uint8_t pressed) {
91
- __ui_nodes[nodeIdx].value = pressed ? 1 : 0;
92
- ui_mark_dirty(nodeIdx);
93
- for (uint16_t i = 0; i < __ui_trans_count; i++) {
94
- if (__ui_trans[i].node == nodeIdx) {
95
- __ui_trans[i].prevValue = __ui_trans[i].prop == PROP_FG ? __ui_nodes[nodeIdx].fg : __ui_nodes[nodeIdx].bg;
96
- __ui_trans[i].targetValue = pressed ? __ui_trans[i].pressedTarget : __ui_trans[i].baseTarget;
97
- __ui_trans[i].elapsed = 0;
98
- __ui_trans[i].active = 1;
99
- }
100
- }
101
- }
102
-
103
- // Press / release entry points that node.onPress(pin) lowers to.
104
- // On press, arm transitions toward the :pressed target color; on release,
105
- // arm them back toward the base color (interrupt-and-re-lerp from current).
106
- static inline void ui_on_press(uint16_t nodeIdx) {
107
- uint32_t now = millis();
108
- if (now - __ui_last_edge_time < UI_DEBOUNCE_MS) return;
109
- __ui_last_edge_time = now;
110
- ui_set_pressed(nodeIdx, 1);
111
- }
112
- static inline void ui_on_release(uint16_t nodeIdx) {
113
- uint32_t now = millis();
114
- if (now - __ui_last_edge_time < UI_DEBOUNCE_MS) return;
115
- __ui_last_edge_time = now;
116
- ui_set_pressed(nodeIdx, 0);
117
- }
118
-
119
- // Pin-watch callback type: void fn(void)
120
- using PinWatchCallback = void (*)(void);
121
-
122
- struct UIPinWatch {
123
- uint8_t pin;
124
- uint8_t lastState; // for edge detection
125
- PinWatchCallback cb; // fires on falling edge
126
- };
127
-
128
- // Populated by the emit layer from ui.watchPin() calls.
129
- extern UIPinWatch __ui_pin_watches[];
130
- extern const uint16_t __ui_pin_watch_count;
131
-
132
- // Poll all configured pin-watchers. Called at the start of ui_tick each frame.
133
- // Detects falling edges with natural debounce from the ~16ms frame rate.
134
- static inline void ui_poll_inputs() {
135
- for (uint16_t i = 0; i < __ui_pin_watch_count; i++) {
136
- uint8_t val = digitalRead(__ui_pin_watches[i].pin);
137
- if (val == LOW && __ui_pin_watches[i].lastState == HIGH) {
138
- if (__ui_pin_watches[i].cb) __ui_pin_watches[i].cb();
139
- }
140
- __ui_pin_watches[i].lastState = val;
141
- }
142
- }
143
- `;
144
- }
1
+ // Slice of the C++ runtime header (original source lines 2442-2561).
2
+ // ui_init, press/release entry points, pin-watch polling.
3
+ // See docs/superpowers/specs/2026-07-12-split-runtime-header-design.md.
4
+ export function emitInitPressInput(): string {
5
+ return `
6
+ // Initial draw: mark all nodes dirty so the first ui_tick renders everything.
7
+ // Called once in setup() before the loop begins.
8
+ // Also seed each text-bound node's buffer from its flash literal so the first
9
+ // strcmp in ui_tick has a valid baseline (no spurious redraw on frame 1).
10
+ static inline void ui_init(void) {
11
+ // Discover <drawer> panels and seed them closed (full-travel offsets, so a
12
+ // closed drawer never paints at its rest position).
13
+ ui_drawer_discover();
14
+ // Allocate the per-node scroll-canvas-OK flag array (once; __ui_node_count
15
+ // is a compile-time constant known by this point). calloc zeroes it — all
16
+ // containers start locked until the scroll-container loop proves their
17
+ // canvas fits.
18
+ if (!__ui_scroll_canvas_ok && __ui_node_count > 0) {
19
+ __ui_scroll_canvas_ok = new (std::nothrow) uint8_t[__ui_node_count]();
20
+ }
21
+ if (!__ui_scroll_render_locked && __ui_node_count > 0) {
22
+ __ui_scroll_render_locked = new (std::nothrow) uint8_t[__ui_node_count]();
23
+ }
24
+ for (uint16_t i = 0; i < __ui_node_count; i++) {
25
+ __ui_nodes[i].dirty = 1;
26
+ __ui_nodes[i].lastTextHeight = 0;
27
+ __ui_nodes[i].layoutCacheKey = 0;
28
+ if (__ui_nodes[i].scrollable) {
29
+ // Force the first scroll-canvas composition to seed every pixel. After
30
+ // that, a dirty child can be repaired in place without repainting the
31
+ // entire viewport.
32
+ __ui_nodes[i].lastPaintedScrollY = static_cast<int16_t>(
33
+ __ui_nodes[i].scrollY - (__ui_nodes[i].box.h > 0 ? __ui_nodes[i].box.h : 1));
34
+ }
35
+ if (__ui_nodes[i].kind == NODE_PROGRESS || __ui_nodes[i].kind == NODE_RANGE) {
36
+ __ui_nodes[i].lastTextWidth = -1;
37
+ }
38
+ }
39
+ for (uint16_t i = 0; i < __ui_binding_count; i++) {
40
+ if (__ui_bindings[i].prop == PROP_TEXT && __ui_bindings[i].textFn) {
41
+ uint16_t n = __ui_bindings[i].node;
42
+ __ui_nodes[n].hasTextBinding = 1;
43
+ strncpy(__ui_nodes[n].textBuffer, __ui_nodes[n].text ? __ui_nodes[n].text : "", UI_TEXT_BUF);
44
+ __ui_nodes[n].textBuffer[UI_TEXT_BUF] = '\\0';
45
+ } else if (__ui_bindings[i].fn) {
46
+ // Prime numeric binding caches once at setup; the first tick can then skip
47
+ // redundant assignments and dirty propagation when values are unchanged.
48
+ __ui_bindings[i].lastValue = __ui_bindings[i].fn();
49
+ __ui_bindings[i].initialized = 1;
50
+ }
51
+ }
52
+ // Seed virtualized-list runtime state. The fn pointers can't be baked into
53
+ // the static node initializer: ui.bindList is resolved AFTER ui.mount lowers
54
+ // the HTML, so the lowering can't see the binding yet. Instead the lowering
55
+ // emits the UIListBinding table (the binding's fn bodies) and ui_init copies
56
+ // the pointers onto each <list> node here, then computes the initial count
57
+ // and contentHeight so the first paint and the scroll clamp bound are correct.
58
+ for (uint16_t b = 0; b < __ui_list_binding_count; b++) {
59
+ uint16_t n = __ui_list_bindings[b].node;
60
+ if (n >= __ui_node_count || !__ui_nodes[n].virtualized) continue;
61
+ __ui_nodes[n].listCountFn = __ui_list_bindings[b].countFn;
62
+ __ui_nodes[n].listItemFn = __ui_list_bindings[b].itemFn;
63
+ __ui_nodes[n].listTapFn = __ui_list_bindings[b].tapFn;
64
+ }
65
+ for (uint16_t i = 0; i < __ui_node_count; i++) {
66
+ if (!__ui_nodes[i].virtualized || !__ui_nodes[i].listCountFn) continue;
67
+ uint16_t ih = __ui_nodes[i].listItemHeight > 0 ? __ui_nodes[i].listItemHeight : 24;
68
+ uint16_t cnt = __ui_nodes[i].listCountFn();
69
+ __ui_nodes[i].listCount = cnt;
70
+ __ui_nodes[i].contentHeight = static_cast<int16_t>(static_cast<uint32_t>(cnt) * ih);
71
+ __ui_nodes[i].scrollY = 0;
72
+ __ui_nodes[i].overscrollPx = 0;
73
+ __ui_nodes[i].settling = 0;
74
+ __ui_nodes[i].lastPaintedScrollY = -(__ui_nodes[i].box.h > 0 ? __ui_nodes[i].box.h : 1);
75
+ }
76
+ ui_build_draw_order();
77
+ ui_build_scroll_owner_table();
78
+ ui_refresh_active_screen_bg_node();
79
+ if (!__ui_scroll_candidates && __ui_node_count > 0) {
80
+ __ui_scroll_candidates = new (std::nothrow) UIScrollPaintCandidate[__ui_node_count];
81
+ }
82
+ }
83
+
84
+ // Debounce: ignore press/release events within 50ms of the last edge.
85
+ // Mechanical switches bounce (multiple edges in ~5-20ms); without this, the
86
+ // transition gets armed/interrupted dozens of times per physical press.
87
+ static volatile uint32_t __ui_last_edge_time = 0;
88
+ #define UI_DEBOUNCE_MS 50
89
+
90
+ static inline void ui_set_pressed(uint16_t nodeIdx, uint8_t pressed) {
91
+ __ui_nodes[nodeIdx].value = pressed ? 1 : 0;
92
+ ui_mark_dirty(nodeIdx);
93
+ for (uint16_t i = 0; i < __ui_trans_count; i++) {
94
+ if (__ui_trans[i].node == nodeIdx) {
95
+ __ui_trans[i].prevValue = __ui_trans[i].prop == PROP_FG ? __ui_nodes[nodeIdx].fg : __ui_nodes[nodeIdx].bg;
96
+ __ui_trans[i].targetValue = pressed ? __ui_trans[i].pressedTarget : __ui_trans[i].baseTarget;
97
+ __ui_trans[i].elapsed = 0;
98
+ __ui_trans[i].active = 1;
99
+ }
100
+ }
101
+ }
102
+
103
+ // Press / release entry points that node.onPress(pin) lowers to.
104
+ // On press, arm transitions toward the :pressed target color; on release,
105
+ // arm them back toward the base color (interrupt-and-re-lerp from current).
106
+ static inline void ui_on_press(uint16_t nodeIdx) {
107
+ uint32_t now = __tc_now_ms();
108
+ if (now - __ui_last_edge_time < UI_DEBOUNCE_MS) return;
109
+ __ui_last_edge_time = now;
110
+ ui_set_pressed(nodeIdx, 1);
111
+ }
112
+ static inline void ui_on_release(uint16_t nodeIdx) {
113
+ uint32_t now = __tc_now_ms();
114
+ if (now - __ui_last_edge_time < UI_DEBOUNCE_MS) return;
115
+ __ui_last_edge_time = now;
116
+ ui_set_pressed(nodeIdx, 0);
117
+ }
118
+
119
+ // Pin-watch callback type: void fn(void)
120
+ using PinWatchCallback = void (*)(void);
121
+
122
+ struct UIPinWatch {
123
+ uint8_t pin;
124
+ uint8_t lastState; // for edge detection
125
+ PinWatchCallback cb; // fires on falling edge
126
+ };
127
+
128
+ // Populated by the emit layer from ui.watchPin() calls.
129
+ extern UIPinWatch __ui_pin_watches[];
130
+ extern const uint16_t __ui_pin_watch_count;
131
+
132
+ // Poll all configured pin-watchers. Called at the start of ui_tick each frame.
133
+ // Detects falling edges with natural debounce from the ~16ms frame rate.
134
+ static inline void ui_poll_inputs() {
135
+ for (uint16_t i = 0; i < __ui_pin_watch_count; i++) {
136
+ uint8_t val = digitalRead(__ui_pin_watches[i].pin);
137
+ if (val == LOW && __ui_pin_watches[i].lastState == HIGH) {
138
+ if (__ui_pin_watches[i].cb) __ui_pin_watches[i].cb();
139
+ }
140
+ __ui_pin_watches[i].lastState = val;
141
+ }
142
+ }
143
+ `;
144
+ }