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

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 (135) hide show
  1. package/README.md +21 -1
  2. package/assets/fonts/dejavu/DejaVuSans-Bold.ttf +0 -0
  3. package/assets/fonts/dejavu/DejaVuSans-ExtraLight.ttf +0 -0
  4. package/assets/fonts/dejavu/DejaVuSans-Oblique.ttf +0 -0
  5. package/assets/fonts/dejavu/DejaVuSans.ttf +0 -0
  6. package/assets/fonts/dejavu/DejaVuSansMono-Bold.ttf +0 -0
  7. package/assets/fonts/dejavu/DejaVuSansMono.ttf +0 -0
  8. package/assets/fonts/dejavu/LICENSE +187 -0
  9. package/assets/fonts/dejavu/README.md +49 -0
  10. package/dist/cli.d.ts +2 -0
  11. package/dist/cli.js +74 -0
  12. package/dist/engine-index.js +2 -0
  13. package/dist/preview/build-program.d.ts +7 -1
  14. package/dist/preview/build-program.js +94 -15
  15. package/dist/preview/host-gfx.d.ts +3 -0
  16. package/dist/preview/host-gfx.js +30 -3
  17. package/dist/preview/host-ui-runtime.d.ts +115 -0
  18. package/dist/preview/host-ui-runtime.js +928 -46
  19. package/dist/ui-engine/block-layout.js +25 -11
  20. package/dist/ui-engine/color.d.ts +6 -0
  21. package/dist/ui-engine/color.js +80 -2
  22. package/dist/ui-engine/compat-report.d.ts +8 -0
  23. package/dist/ui-engine/compat-report.js +124 -0
  24. package/dist/ui-engine/css-imports.d.ts +4 -0
  25. package/dist/ui-engine/css-imports.js +70 -0
  26. package/dist/ui-engine/css-parser.js +58 -14
  27. package/dist/ui-engine/default-font.d.ts +25 -0
  28. package/dist/ui-engine/default-font.js +80 -0
  29. package/dist/ui-engine/font-assets.d.ts +2 -2
  30. package/dist/ui-engine/font-assets.js +22 -5
  31. package/dist/ui-engine/html-parser.d.ts +4 -0
  32. package/dist/ui-engine/html-parser.js +241 -26
  33. package/dist/ui-engine/image-assets.d.ts +8 -1
  34. package/dist/ui-engine/image-assets.js +35 -2
  35. package/dist/ui-engine/image-decode.d.ts +22 -0
  36. package/dist/ui-engine/image-decode.js +194 -0
  37. package/dist/ui-engine/inline-parser.js +1 -1
  38. package/dist/ui-engine/layout-engine.d.ts +19 -0
  39. package/dist/ui-engine/layout-engine.js +59 -3
  40. package/dist/ui-engine/model.d.ts +18 -0
  41. package/dist/ui-engine/model.js +76 -8
  42. package/dist/ui-engine/runtime-header/blend-bodies.js +29 -9
  43. package/dist/ui-engine/runtime-header/canvas-helpers.js +5 -2
  44. package/dist/ui-engine/runtime-header/canvas-scrollbar.js +115 -111
  45. package/dist/ui-engine/runtime-header/cuttlefish-gfx.js +21 -0
  46. package/dist/ui-engine/runtime-header/dirty-scroll-mutators.js +182 -179
  47. package/dist/ui-engine/runtime-header/forward-decls.js +215 -167
  48. package/dist/ui-engine/runtime-header/init-press-input.js +138 -135
  49. package/dist/ui-engine/runtime-header/keyboard.js +682 -380
  50. package/dist/ui-engine/runtime-header/node-draw-body.js +1656 -1377
  51. package/dist/ui-engine/runtime-header/paint-order-coords.js +259 -214
  52. package/dist/ui-engine/runtime-header/paint-rects-repair.js +736 -568
  53. package/dist/ui-engine/runtime-header/scroll-physics.js +25 -1
  54. package/dist/ui-engine/runtime-header/state-bindings-nav.js +9 -0
  55. package/dist/ui-engine/runtime-header/structs.js +228 -216
  56. package/dist/ui-engine/runtime-header/text-rendering.js +888 -770
  57. package/dist/ui-engine/runtime-header/tick/bindings-phase.js +118 -116
  58. package/dist/ui-engine/runtime-header/tick/dirty-draw-phase.js +897 -633
  59. package/dist/ui-engine/runtime-header/tick/scroll-canvas-phase.js +24 -25
  60. package/dist/ui-engine/runtime-header/touch-keyboard-fwd.js +79 -23
  61. package/dist/ui-engine/runtime-header/types-defines.js +110 -93
  62. package/dist/ui-engine/shadcn-kit.d.ts +1 -0
  63. package/dist/ui-engine/shadcn-kit.js +502 -0
  64. package/dist/ui-engine/style-resolver.d.ts +4 -0
  65. package/dist/ui-engine/style-resolver.js +58 -6
  66. package/dist/ui-engine/transpile-ui.js +12 -5
  67. package/dist/ui-engine/ua-stylesheet.d.ts +22 -1
  68. package/dist/ui-engine/ua-stylesheet.js +119 -32
  69. package/dist/ui-engine/ui-lowering.js +37 -3
  70. package/dist/ui-engine/ui-registry.js +32 -4
  71. package/dist/ui-engine/yoga-layout.js +57 -52
  72. package/dist/wizard/config-writer.d.ts +49 -0
  73. package/dist/wizard/config-writer.js +366 -0
  74. package/dist/wizard/display-catalog.d.ts +75 -0
  75. package/dist/wizard/display-catalog.js +207 -0
  76. package/dist/wizard/index.d.ts +7 -0
  77. package/dist/wizard/index.js +10 -0
  78. package/dist/wizard/integration-wizard.d.ts +15 -0
  79. package/dist/wizard/integration-wizard.js +486 -0
  80. package/dist/wizard/prompts.d.ts +32 -0
  81. package/dist/wizard/prompts.js +95 -0
  82. package/dist/wizard/starter-ui.d.ts +1 -0
  83. package/dist/wizard/starter-ui.js +56 -0
  84. package/package.json +18 -5
  85. package/src/cli.ts +87 -0
  86. package/src/engine-index.ts +53 -51
  87. package/src/preview/build-program.ts +810 -734
  88. package/src/preview/host-gfx.ts +30 -3
  89. package/src/preview/host-ui-runtime.ts +4133 -3289
  90. package/src/ui-engine/block-layout.ts +24 -11
  91. package/src/ui-engine/color.ts +77 -2
  92. package/src/ui-engine/compat-report.ts +139 -0
  93. package/src/ui-engine/css-imports.ts +69 -0
  94. package/src/ui-engine/css-parser.ts +64 -15
  95. package/src/ui-engine/default-font.ts +95 -0
  96. package/src/ui-engine/font-assets.ts +545 -525
  97. package/src/ui-engine/html-parser.ts +615 -397
  98. package/src/ui-engine/image-assets.ts +37 -2
  99. package/src/ui-engine/image-decode.ts +244 -0
  100. package/src/ui-engine/inline-parser.ts +1 -1
  101. package/src/ui-engine/layout-engine.ts +61 -3
  102. package/src/ui-engine/model.ts +1317 -1230
  103. package/src/ui-engine/runtime-header/blend-bodies.ts +29 -9
  104. package/src/ui-engine/runtime-header/canvas-helpers.ts +5 -2
  105. package/src/ui-engine/runtime-header/canvas-scrollbar.ts +121 -117
  106. package/src/ui-engine/runtime-header/cuttlefish-gfx.ts +21 -0
  107. package/src/ui-engine/runtime-header/dirty-scroll-mutators.ts +188 -185
  108. package/src/ui-engine/runtime-header/forward-decls.ts +227 -179
  109. package/src/ui-engine/runtime-header/init-press-input.ts +144 -141
  110. package/src/ui-engine/runtime-header/keyboard.ts +689 -386
  111. package/src/ui-engine/runtime-header/node-draw-body.ts +1681 -1402
  112. package/src/ui-engine/runtime-header/paint-order-coords.ts +265 -220
  113. package/src/ui-engine/runtime-header/paint-rects-repair.ts +742 -574
  114. package/src/ui-engine/runtime-header/scroll-physics.ts +25 -1
  115. package/src/ui-engine/runtime-header/state-bindings-nav.ts +9 -0
  116. package/src/ui-engine/runtime-header/structs.ts +234 -222
  117. package/src/ui-engine/runtime-header/text-rendering.ts +894 -776
  118. package/src/ui-engine/runtime-header/tick/bindings-phase.ts +124 -122
  119. package/src/ui-engine/runtime-header/tick/dirty-draw-phase.ts +902 -638
  120. package/src/ui-engine/runtime-header/tick/scroll-canvas-phase.ts +30 -31
  121. package/src/ui-engine/runtime-header/touch-keyboard-fwd.ts +79 -23
  122. package/src/ui-engine/runtime-header/types-defines.ts +116 -99
  123. package/src/ui-engine/shadcn-kit.ts +503 -0
  124. package/src/ui-engine/style-resolver.ts +471 -416
  125. package/src/ui-engine/transpile-ui.ts +12 -5
  126. package/src/ui-engine/ua-stylesheet.ts +137 -31
  127. package/src/ui-engine/ui-lowering.ts +486 -452
  128. package/src/ui-engine/ui-registry.ts +556 -524
  129. package/src/ui-engine/yoga-layout.ts +307 -309
  130. package/src/wizard/config-writer.ts +404 -0
  131. package/src/wizard/display-catalog.ts +273 -0
  132. package/src/wizard/index.ts +38 -0
  133. package/src/wizard/integration-wizard.ts +619 -0
  134. package/src/wizard/prompts.ts +145 -0
  135. package/src/wizard/starter-ui.ts +58 -0
@@ -1,122 +1,124 @@
1
- // Slice of the C++ runtime header (original source lines 3930-4026).
2
- // ui_tick signature + opening, caret blink re-mark, bindings/list-bindings/input-bindings. Contains ui_tick opening.
3
- // See docs/superpowers/specs/2026-07-12-split-runtime-header-design.md.
4
- export function emitTickBindingsPhase(): string {
5
- return `
6
- static inline void ui_tick(uint16_t deltaMs) {
7
- // Touch poll — runs if touch is configured (defined by the emit layer)
8
- ui_poll_touch();
9
- // Allocate the retained framebuffer before transitions run. Geometry repair
10
- // must clear old animation footprints into RAM, not directly onto the panel.
11
- (void)ui_get_framebuffer();
12
- // ⓪' Poll GPIO inputs
13
- ui_poll_inputs();
14
- #if defined(UI_HIDE_OSK)
15
- // Advance the caret blink phase for the active input (desktop target).
16
- __ui_kb_blink++;
17
- // Re-mark the edited input dirty every ~16 ticks so the blink repainting
18
- // keeps cycling even when no other state changes (otherwise the caret
19
- // freezes once the typed-text dirty clears).
20
- if (__ui_kb_visible && __ui_kb_target >= 0 && (__ui_kb_blink & 0x10)) {
21
- ui_mark_dirty(static_cast<uint16_t>(__ui_kb_target));
22
- }
23
- #endif
24
- // ⓪ Evaluate bindings: call each binding's fn, compare to the node's
25
- // current property value, mark dirty if changed.
26
- for (uint16_t i = 0; i < __ui_binding_count; i++) {
27
- if (__ui_bindings[i].prop == PROP_TEXT && __ui_bindings[i].textFn) {
28
- // Text callbacks are necessarily evaluated to detect changes (the callback
29
- // may format a signal or read external state), but avoid a stack-sized old
30
- // copy: compare the generated value against the node buffer after writing.
31
- // The callback contract is fill-style and must be deterministic for the same
32
- // inputs; the temporary buffer keeps a change from destroying the old text.
33
- uint16_t n = __ui_bindings[i].node;
34
- if (n >= __ui_node_count) continue;
35
- char nextBuf[UI_TEXT_BUF + 1];
36
- nextBuf[0] = '\\0';
37
- __ui_bindings[i].textFn(nextBuf, UI_TEXT_BUF + 1);
38
- nextBuf[UI_TEXT_BUF] = '\\0';
39
- if (strcmp(nextBuf, __ui_nodes[n].textBuffer) != 0) {
40
- strncpy(__ui_nodes[n].textBuffer, nextBuf, UI_TEXT_BUF);
41
- __ui_nodes[n].textBuffer[UI_TEXT_BUF] = '\\0';
42
- ui_invalidate_text_layout_cache(n);
43
- ui_mark_dirty(n);
44
- }
45
- } else if (__ui_bindings[i].fn) {
46
- // Color/numeric binding
47
- uint32_t newVal = __ui_bindings[i].fn();
48
- if (__ui_bindings[i].prop == PROP_VISIBLE) {
49
- uint8_t nextVisible = newVal ? 1 : 0;
50
- if (nextVisible != __ui_nodes[__ui_bindings[i].node].visible) {
51
- ui_set_visible(__ui_bindings[i].node, nextVisible);
52
- }
53
- continue;
54
- }
55
- if (__ui_bindings[i].prop == PROP_VALUE) {
56
- // Numeric value binding: drive a progress/range node's value live.
57
- uint16_t n = __ui_bindings[i].node;
58
- int16_t v = static_cast<int16_t>(__ui_bindings[i].fn());
59
- if (v != __ui_nodes[n].value) {
60
- __ui_nodes[n].value = v;
61
- ui_mark_dirty(n);
62
- }
63
- continue;
64
- }
65
- // Cache numeric binding results. The first sample establishes the baseline;
66
- // subsequent identical values return immediately without touching node state.
67
- if (__ui_bindings[i].initialized && newVal == __ui_bindings[i].lastValue) continue;
68
- __ui_bindings[i].lastValue = newVal;
69
- __ui_bindings[i].initialized = 1;
70
- uint32_t* target = (__ui_bindings[i].prop == PROP_BG) ? &__ui_nodes[__ui_bindings[i].node].bg
71
- : (__ui_bindings[i].prop == PROP_FG) ? &__ui_nodes[__ui_bindings[i].node].fg
72
- : (__ui_bindings[i].prop == PROP_BORDER_COLOR) ? &__ui_nodes[__ui_bindings[i].node].borderColor
73
- : &__ui_nodes[__ui_bindings[i].node].bg;
74
- if (newVal != *target) {
75
- *target = newVal;
76
- // When a background binding writes a new color, ensure hasBg is set
77
- // so the draw dispatch actually fills (the node may have started
78
- // transparent but now has a runtime-assigned background).
79
- if (__ui_bindings[i].prop == PROP_BG) __ui_nodes[__ui_bindings[i].node].hasBg = 1;
80
- ui_mark_dirty(__ui_bindings[i].node);
81
- }
82
- }
83
- }
84
- // ⓪b Evaluate list bindings (on-node): refresh item count, recompute content
85
- // height, and advance any in-flight settle animation (bounce-back / edge-snap).
86
- // Also note whether any active-screen node is settling (feeds scroll-motion
87
- // gating below without a second full-node scan).
88
- uint8_t settlingOnActiveScreen = 0;
89
- for (uint16_t i = 0; i < __ui_node_count; i++) {
90
- if (__ui_nodes[i].virtualized && __ui_nodes[i].listCountFn) {
91
- uint16_t ih = __ui_nodes[i].listItemHeight > 0 ? __ui_nodes[i].listItemHeight : 24;
92
- // Keep the callback result as the list's invalidation token. The callback
93
- // is still evaluated because it is the public list-count source, but an
94
- // unchanged token avoids layout/dirty work and preserves the retained
95
- // viewport canvas.
96
- uint16_t newCount = __ui_nodes[i].listCountFn();
97
- if (newCount != __ui_nodes[i].listCount) {
98
- __ui_nodes[i].listCount = newCount;
99
- __ui_nodes[i].contentHeight = static_cast<int16_t>(static_cast<uint32_t>(newCount) * ih);
100
- __ui_nodes[i].lastPaintedScrollY = __ui_nodes[i].scrollY - (__ui_nodes[i].box.h > 0 ? __ui_nodes[i].box.h : 1);
101
- ui_mark_dirty(i);
102
- }
103
- }
104
- if (__ui_nodes[i].settling) {
105
- if (__ui_nodes[i].screenId == __ui_active_screen) settlingOnActiveScreen = 1;
106
- ui_scroll_advance_settle(i, deltaMs);
107
- }
108
- }
109
- // ⓪c Evaluate input bindings (two-way): if a bound <input>'s textBuffer
110
- // changed since last tick (e.g. the user typed via the on-screen keyboard),
111
- // fire the author's callback with the new text.
112
- for (uint16_t i = 0; i < __ui_input_binding_count; i++) {
113
- if (!__ui_input_bindings[i].cb) continue;
114
- uint16_t n = __ui_input_bindings[i].node;
115
- if (n >= __ui_node_count) continue;
116
- const char* cur = __ui_nodes[n].textBuffer;
117
- if (strcmp(cur, __ui_input_bindings[i].lastSeen) != 0) {
118
- strncpy(__ui_input_bindings[i].lastSeen, cur, UI_TEXT_BUF);
119
- __ui_input_bindings[i].lastSeen[UI_TEXT_BUF] = '\\0';
120
- __ui_input_bindings[i].cb(cur);
121
- }`;
122
- }
1
+ // Slice of the C++ runtime header (original source lines 3930-4026).
2
+ // ui_tick signature + opening, caret blink re-mark, bindings/list-bindings/input-bindings. Contains ui_tick opening.
3
+ // See docs/superpowers/specs/2026-07-12-split-runtime-header-design.md.
4
+ export function emitTickBindingsPhase(): string {
5
+ return `
6
+ static inline void ui_tick(uint16_t deltaMs) {
7
+ // Touch poll — runs if touch is configured (defined by the emit layer)
8
+ ui_poll_touch();
9
+ // <drawer> slide animation (device parity with the preview's applyDrawers).
10
+ ui_drawer_tick(deltaMs);
11
+ // Allocate the retained framebuffer before transitions run. Geometry repair
12
+ // must clear old animation footprints into RAM, not directly onto the panel.
13
+ (void)ui_get_framebuffer();
14
+ // ⓪' Poll GPIO inputs
15
+ ui_poll_inputs();
16
+ #if defined(UI_HIDE_OSK)
17
+ // Advance the caret blink phase for the active input (desktop target).
18
+ __ui_kb_blink++;
19
+ // Re-mark the edited input dirty every ~16 ticks so the blink repainting
20
+ // keeps cycling even when no other state changes (otherwise the caret
21
+ // freezes once the typed-text dirty clears).
22
+ if (__ui_kb_visible && __ui_kb_target >= 0 && (__ui_kb_blink & 0x10)) {
23
+ ui_mark_dirty(static_cast<uint16_t>(__ui_kb_target));
24
+ }
25
+ #endif
26
+ // Evaluate bindings: call each binding's fn, compare to the node's
27
+ // current property value, mark dirty if changed.
28
+ for (uint16_t i = 0; i < __ui_binding_count; i++) {
29
+ if (__ui_bindings[i].prop == PROP_TEXT && __ui_bindings[i].textFn) {
30
+ // Text callbacks are necessarily evaluated to detect changes (the callback
31
+ // may format a signal or read external state), but avoid a stack-sized old
32
+ // copy: compare the generated value against the node buffer after writing.
33
+ // The callback contract is fill-style and must be deterministic for the same
34
+ // inputs; the temporary buffer keeps a change from destroying the old text.
35
+ uint16_t n = __ui_bindings[i].node;
36
+ if (n >= __ui_node_count) continue;
37
+ char nextBuf[UI_TEXT_BUF + 1];
38
+ nextBuf[0] = '\\0';
39
+ __ui_bindings[i].textFn(nextBuf, UI_TEXT_BUF + 1);
40
+ nextBuf[UI_TEXT_BUF] = '\\0';
41
+ if (strcmp(nextBuf, __ui_nodes[n].textBuffer) != 0) {
42
+ strncpy(__ui_nodes[n].textBuffer, nextBuf, UI_TEXT_BUF);
43
+ __ui_nodes[n].textBuffer[UI_TEXT_BUF] = '\\0';
44
+ ui_invalidate_text_layout_cache(n);
45
+ ui_mark_dirty(n);
46
+ }
47
+ } else if (__ui_bindings[i].fn) {
48
+ // Color/numeric binding
49
+ uint32_t newVal = __ui_bindings[i].fn();
50
+ if (__ui_bindings[i].prop == PROP_VISIBLE) {
51
+ uint8_t nextVisible = newVal ? 1 : 0;
52
+ if (nextVisible != __ui_nodes[__ui_bindings[i].node].visible) {
53
+ ui_set_visible(__ui_bindings[i].node, nextVisible);
54
+ }
55
+ continue;
56
+ }
57
+ if (__ui_bindings[i].prop == PROP_VALUE) {
58
+ // Numeric value binding: drive a progress/range node's value live.
59
+ uint16_t n = __ui_bindings[i].node;
60
+ int16_t v = static_cast<int16_t>(__ui_bindings[i].fn());
61
+ if (v != __ui_nodes[n].value) {
62
+ __ui_nodes[n].value = v;
63
+ ui_mark_dirty(n);
64
+ }
65
+ continue;
66
+ }
67
+ // Cache numeric binding results. The first sample establishes the baseline;
68
+ // subsequent identical values return immediately without touching node state.
69
+ if (__ui_bindings[i].initialized && newVal == __ui_bindings[i].lastValue) continue;
70
+ __ui_bindings[i].lastValue = newVal;
71
+ __ui_bindings[i].initialized = 1;
72
+ uint32_t* target = (__ui_bindings[i].prop == PROP_BG) ? &__ui_nodes[__ui_bindings[i].node].bg
73
+ : (__ui_bindings[i].prop == PROP_FG) ? &__ui_nodes[__ui_bindings[i].node].fg
74
+ : (__ui_bindings[i].prop == PROP_BORDER_COLOR) ? &__ui_nodes[__ui_bindings[i].node].borderColor
75
+ : &__ui_nodes[__ui_bindings[i].node].bg;
76
+ if (newVal != *target) {
77
+ *target = newVal;
78
+ // When a background binding writes a new color, ensure hasBg is set
79
+ // so the draw dispatch actually fills (the node may have started
80
+ // transparent but now has a runtime-assigned background).
81
+ if (__ui_bindings[i].prop == PROP_BG) __ui_nodes[__ui_bindings[i].node].hasBg = 1;
82
+ ui_mark_dirty(__ui_bindings[i].node);
83
+ }
84
+ }
85
+ }
86
+ // ⓪b Evaluate list bindings (on-node): refresh item count, recompute content
87
+ // height, and advance any in-flight settle animation (bounce-back / edge-snap).
88
+ // Also note whether any active-screen node is settling (feeds scroll-motion
89
+ // gating below without a second full-node scan).
90
+ uint8_t settlingOnActiveScreen = 0;
91
+ for (uint16_t i = 0; i < __ui_node_count; i++) {
92
+ if (__ui_nodes[i].virtualized && __ui_nodes[i].listCountFn) {
93
+ uint16_t ih = __ui_nodes[i].listItemHeight > 0 ? __ui_nodes[i].listItemHeight : 24;
94
+ // Keep the callback result as the list's invalidation token. The callback
95
+ // is still evaluated because it is the public list-count source, but an
96
+ // unchanged token avoids layout/dirty work and preserves the retained
97
+ // viewport canvas.
98
+ uint16_t newCount = __ui_nodes[i].listCountFn();
99
+ if (newCount != __ui_nodes[i].listCount) {
100
+ __ui_nodes[i].listCount = newCount;
101
+ __ui_nodes[i].contentHeight = static_cast<int16_t>(static_cast<uint32_t>(newCount) * ih);
102
+ __ui_nodes[i].lastPaintedScrollY = __ui_nodes[i].scrollY - (__ui_nodes[i].box.h > 0 ? __ui_nodes[i].box.h : 1);
103
+ ui_mark_dirty(i);
104
+ }
105
+ }
106
+ if (__ui_nodes[i].settling) {
107
+ if (__ui_nodes[i].screenId == __ui_active_screen) settlingOnActiveScreen = 1;
108
+ ui_scroll_advance_settle(i, deltaMs);
109
+ }
110
+ }
111
+ // ⓪c Evaluate input bindings (two-way): if a bound <input>'s textBuffer
112
+ // changed since last tick (e.g. the user typed via the on-screen keyboard),
113
+ // fire the author's callback with the new text.
114
+ for (uint16_t i = 0; i < __ui_input_binding_count; i++) {
115
+ if (!__ui_input_bindings[i].cb) continue;
116
+ uint16_t n = __ui_input_bindings[i].node;
117
+ if (n >= __ui_node_count) continue;
118
+ const char* cur = __ui_nodes[n].textBuffer;
119
+ if (strcmp(cur, __ui_input_bindings[i].lastSeen) != 0) {
120
+ strncpy(__ui_input_bindings[i].lastSeen, cur, UI_TEXT_BUF);
121
+ __ui_input_bindings[i].lastSeen[UI_TEXT_BUF] = '\\0';
122
+ __ui_input_bindings[i].cb(cur);
123
+ }`;
124
+ }