flet-box 1.0.4 → 1.0.6

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 (147) hide show
  1. package/README.md +10 -0
  2. package/bin/cli.js +23 -7
  3. package/bin/commands/checkApi.js +761 -0
  4. package/bin/commands/create.js +77 -5
  5. package/bin/utils/dtsProps.js +191 -0
  6. package/bin/utils/moduleExports.js +165 -0
  7. package/bin/utils/neutralise.js +64 -0
  8. package/bin/utils/templates.js +366 -27
  9. package/docs/CONTRIBUTING.md +156 -0
  10. package/docs/README.md +68 -0
  11. package/docs/arquitectura.md +164 -0
  12. package/docs/cli/README.md +542 -0
  13. package/docs/guides/README.md +33 -0
  14. package/docs/guides/app-templates.md +197 -0
  15. package/docs/guides/compatibility.md +95 -0
  16. package/docs/guides/embedding.md +284 -0
  17. package/docs/guides/first-app.md +208 -0
  18. package/docs/guides/frontend-services.md +171 -0
  19. package/docs/guides/minification-and-protection.md +260 -0
  20. package/docs/guides/mobile-and-platforms.md +439 -0
  21. package/docs/guides/online-updates.md +196 -0
  22. package/docs/guides/router.md +282 -0
  23. package/docs/guides/state.md +283 -0
  24. package/docs/guides/syntax-philosophy.md +150 -0
  25. package/docs/guides/utilities.md +241 -0
  26. package/docs/guides/widget-structure.md +163 -0
  27. package/docs/server/README.md +68 -0
  28. package/docs/server/START_HERE.md +121 -0
  29. package/docs/server/api.md +225 -0
  30. package/docs/server/data-services.md +300 -0
  31. package/docs/server/deployment.md +113 -0
  32. package/docs/server/security.md +196 -0
  33. package/docs/services/README.md +79 -0
  34. package/docs/services/RamStore.md +84 -0
  35. package/docs/services/Session.md +84 -0
  36. package/docs/services/Storage.md +88 -0
  37. package/docs/services/http.md +86 -0
  38. package/docs/tools/README.md +138 -0
  39. package/docs/tools/animation.md +87 -0
  40. package/docs/tools/async-ids-log.md +80 -0
  41. package/docs/tools/device.md +132 -0
  42. package/docs/tools/introspection.md +67 -0
  43. package/docs/tools/lists.md +96 -0
  44. package/docs/tools/markdown.md +79 -0
  45. package/docs/tools/reactivity.md +288 -0
  46. package/docs/tools/state.md +103 -0
  47. package/docs/tools/styling.md +92 -0
  48. package/docs/tools/text-and-time.md +89 -0
  49. package/docs/tools/theme.md +102 -0
  50. package/docs/tools/validation.md +75 -0
  51. package/docs/tools/visual-effects.md +84 -0
  52. package/docs/widget/Accordion.md +144 -0
  53. package/docs/widget/AdMob.md +144 -0
  54. package/docs/widget/AdSense.md +133 -0
  55. package/docs/widget/AdaptiveScaffold.md +105 -0
  56. package/docs/widget/AlertDialog.md +103 -0
  57. package/docs/widget/AnimatedBox.md +130 -0
  58. package/docs/widget/AnimatedText.md +123 -0
  59. package/docs/widget/AppBar.md +118 -0
  60. package/docs/widget/Audio.md +135 -0
  61. package/docs/widget/Avatar.md +119 -0
  62. package/docs/widget/Badge.md +128 -0
  63. package/docs/widget/BottomNavigation.md +116 -0
  64. package/docs/widget/BottomSheet.md +125 -0
  65. package/docs/widget/Button.md +137 -0
  66. package/docs/widget/COMMON_PROPS.md +150 -0
  67. package/docs/widget/Card.md +125 -0
  68. package/docs/widget/Carousel.md +151 -0
  69. package/docs/widget/Chart.md +151 -0
  70. package/docs/widget/Checkbox.md +118 -0
  71. package/docs/widget/Chip.md +126 -0
  72. package/docs/widget/CircularBar.md +168 -0
  73. package/docs/widget/CircularChart.md +164 -0
  74. package/docs/widget/CodeViewer.md +130 -0
  75. package/docs/widget/CollapsibleSideBar.md +112 -0
  76. package/docs/widget/Column.md +129 -0
  77. package/docs/widget/Container.md +136 -0
  78. package/docs/widget/DataTable.md +150 -0
  79. package/docs/widget/Divider.md +109 -0
  80. package/docs/widget/DraggBox.md +129 -0
  81. package/docs/widget/Drawer.md +135 -0
  82. package/docs/widget/DrawerItem.md +98 -0
  83. package/docs/widget/Dropdown.md +139 -0
  84. package/docs/widget/DroppBox.md +152 -0
  85. package/docs/widget/FloatingActionButton.md +120 -0
  86. package/docs/widget/GridView.md +140 -0
  87. package/docs/widget/Icon.md +117 -0
  88. package/docs/widget/Image.md +125 -0
  89. package/docs/widget/Input.md +151 -0
  90. package/docs/widget/Inspector.md +92 -0
  91. package/docs/widget/InstallButton.md +128 -0
  92. package/docs/widget/ListTile.md +132 -0
  93. package/docs/widget/ListView.md +138 -0
  94. package/docs/widget/Markdown.md +175 -0
  95. package/docs/widget/MatrixRain.md +122 -0
  96. package/docs/widget/Modal.md +129 -0
  97. package/docs/widget/Pagination.md +135 -0
  98. package/docs/widget/ParallaxBox.md +128 -0
  99. package/docs/widget/ProgressBar.md +130 -0
  100. package/docs/widget/QRCode.md +117 -0
  101. package/docs/widget/README.md +188 -0
  102. package/docs/widget/Radio.md +123 -0
  103. package/docs/widget/Rating.md +131 -0
  104. package/docs/widget/Row.md +131 -0
  105. package/docs/widget/START_HERE.md +146 -0
  106. package/docs/widget/Scaffold.md +152 -0
  107. package/docs/widget/Skeleton.md +130 -0
  108. package/docs/widget/Slider.md +146 -0
  109. package/docs/widget/SnackBar.md +102 -0
  110. package/docs/widget/Stack.md +128 -0
  111. package/docs/widget/Stepper.md +145 -0
  112. package/docs/widget/Switch.md +118 -0
  113. package/docs/widget/Tabs.md +124 -0
  114. package/docs/widget/Text.md +133 -0
  115. package/docs/widget/Tooltip.md +145 -0
  116. package/docs/widget/TreeView.md +176 -0
  117. package/docs/widget/Video.md +127 -0
  118. package/docs/widget/_template.md +61 -0
  119. package/package.json +3 -2
  120. package/src/animations/animate.js +180 -70
  121. package/src/animations/index.js +1 -0
  122. package/src/create-index.sh +1 -1
  123. package/src/index.d.ts +45 -22
  124. package/src/index.js +1 -0
  125. package/src/navigations/AdaptiveScaffold.js +11 -2
  126. package/src/navigations/BottomNavigation.js +10 -3
  127. package/src/navigations/Tabs.js +6 -2
  128. package/src/tools/useState.js +54 -63
  129. package/src/widget-factory/assignProps.js +23 -1
  130. package/src/widget-factory/processProps.js +10 -3
  131. package/src/widget-factory/reactiveValue.js +43 -18
  132. package/src/widget-factory/translateProps.js +777 -901
  133. package/src/widgets/AlertDialog.js +7 -5
  134. package/src/widgets/Checkbox.js +9 -7
  135. package/src/widgets/CircularBar.js +12 -1
  136. package/src/widgets/FloatingActionButton.js +4 -7
  137. package/src/widgets/Image.js +5 -7
  138. package/src/widgets/Input.js +92 -0
  139. package/src/widgets/ListView.js +73 -29
  140. package/src/widgets/Pagination.js +6 -3
  141. package/src/widgets/ProgressBar.js +16 -13
  142. package/src/widgets/Radio.js +6 -7
  143. package/src/widgets/Slider.js +23 -4
  144. package/src/widgets/Stack.js +36 -3
  145. package/src/widgets/Stepper.js +4 -3
  146. package/src/widgets/Switch.js +3 -4
  147. package/src/widgets/TreeView.js +0 -1
@@ -1,775 +1,225 @@
1
1
  // core/translateProps.js
2
2
  import { warnUnknownProp, setPropNames } from "./warnings.js";
3
+
3
4
  /**
4
5
  * CENTRAL PROP DATABASE
5
6
  *
6
- * This file defines every prop that the system understands.
7
- * It is a pure data file – no processing logic here.
7
+ * Pure data — no processing logic here.
8
8
  *
9
9
  * Each entry:
10
10
  * prop : custom name used in widgets (e.g., 'w', 'p', 'onClick')
11
11
  * domProp : corresponding DOM property or CSS property
12
12
  * type : 'style' | 'attribute' | 'event' | 'text' | 'special'
13
- * unit : (optional) 'rem' | 'px' | 'none' – only for style props
14
- * reactive : (optional) true/false – whether the prop is reactive
13
+ * unit : (optional) 'rem' | 'px' | 'none' – style props only
14
+ * reactive : (optional) true – whether the prop is reactive
15
15
  * targets : (optional) list of CSS DOM props a shorthand expands to
16
- * (e.g. 'px' → paddingLeft + paddingRight). When absent the
17
- * prop writes to its single `domProp`.
16
+ * boolValues: (optional) { true, false } – CSS values a boolean prop maps to.
17
+ * Without it, `true`/`false` reach the stylesheet as `1`/`0`, which
18
+ * is right for `opacity` but invalid for keyword-valued props like
19
+ * `flex-wrap`.
20
+ *
21
+ * Props typed as `special` are consumed by widget implementations via
22
+ * `composeUpdate` / `_originalProps`. They are registered here so that:
23
+ * • `processProps` classifies them without warning
24
+ * • `assignProps` ignores them (no matching case in `applySpecial`)
25
+ * • the widget receives them intact for its own rendering logic
18
26
  */
19
27
 
20
28
  export const ALL_PROPS = [
21
- // ==================== DIMENSIONS ====================
29
+ // ============================================================
30
+ // DIMENSIONS
31
+ // ============================================================
22
32
  { prop: "w", domProp: "width", type: "style", unit: "rem", reactive: true },
23
- {
24
- prop: "width",
25
- domProp: "width",
26
- type: "style",
27
- unit: "rem",
28
- reactive: true,
29
- },
33
+ { prop: "width", domProp: "width", type: "style", unit: "rem", reactive: true },
30
34
  { prop: "h", domProp: "height", type: "style", unit: "rem", reactive: true },
31
- {
32
- prop: "height",
33
- domProp: "height",
34
- type: "style",
35
- unit: "rem",
36
- reactive: true,
37
- },
38
- {
39
- prop: "minW",
40
- domProp: "minWidth",
41
- type: "style",
42
- unit: "rem",
43
- reactive: true,
44
- },
45
- {
46
- prop: "minWidth",
47
- domProp: "minWidth",
48
- type: "style",
49
- unit: "rem",
50
- reactive: true,
51
- },
52
- {
53
- prop: "maxW",
54
- domProp: "maxWidth",
55
- type: "style",
56
- unit: "rem",
57
- reactive: true,
58
- },
59
- {
60
- prop: "maxWidth",
61
- domProp: "maxWidth",
62
- type: "style",
63
- unit: "rem",
64
- reactive: true,
65
- },
66
- {
67
- prop: "minH",
68
- domProp: "minHeight",
69
- type: "style",
70
- unit: "rem",
71
- reactive: true,
72
- },
73
- {
74
- prop: "minHeight",
75
- domProp: "minHeight",
76
- type: "style",
77
- unit: "rem",
78
- reactive: true,
79
- },
80
- {
81
- prop: "maxH",
82
- domProp: "maxHeight",
83
- type: "style",
84
- unit: "rem",
85
- reactive: true,
86
- },
87
- {
88
- prop: "maxHeight",
89
- domProp: "maxHeight",
90
- type: "style",
91
- unit: "rem",
92
- reactive: true,
93
- },
94
-
95
- // ==================== SPACING ====================
35
+ { prop: "height", domProp: "height", type: "style", unit: "rem", reactive: true },
36
+ { prop: "minW", domProp: "minWidth", type: "style", unit: "rem", reactive: true },
37
+ { prop: "minWidth", domProp: "minWidth", type: "style", unit: "rem", reactive: true },
38
+ { prop: "maxW", domProp: "maxWidth", type: "style", unit: "rem", reactive: true },
39
+ { prop: "maxWidth", domProp: "maxWidth", type: "style", unit: "rem", reactive: true },
40
+ { prop: "minH", domProp: "minHeight", type: "style", unit: "rem", reactive: true },
41
+ { prop: "minHeight", domProp: "minHeight", type: "style", unit: "rem", reactive: true },
42
+ { prop: "maxH", domProp: "maxHeight", type: "style", unit: "rem", reactive: true },
43
+ { prop: "maxHeight", domProp: "maxHeight", type: "style", unit: "rem", reactive: true },
44
+
45
+ // ============================================================
46
+ // SPACING
47
+ // ============================================================
96
48
  { prop: "p", domProp: "padding", type: "style", unit: "rem", reactive: true },
97
- {
98
- prop: "padding",
99
- domProp: "padding",
100
- type: "style",
101
- unit: "rem",
102
- reactive: true,
103
- },
49
+ { prop: "padding", domProp: "padding", type: "style", unit: "rem", reactive: true },
104
50
  { prop: "m", domProp: "margin", type: "style", unit: "rem", reactive: true },
105
- {
106
- prop: "margin",
107
- domProp: "margin",
108
- type: "style",
109
- unit: "rem",
110
- reactive: true,
111
- },
112
- {
113
- prop: "pt",
114
- domProp: "paddingTop",
115
- type: "style",
116
- unit: "rem",
117
- reactive: true,
118
- },
119
- {
120
- prop: "paddingTop",
121
- domProp: "paddingTop",
122
- type: "style",
123
- unit: "rem",
124
- reactive: true,
125
- },
126
- {
127
- prop: "pr",
128
- domProp: "paddingRight",
129
- type: "style",
130
- unit: "rem",
131
- reactive: true,
132
- },
133
- {
134
- prop: "paddingRight",
135
- domProp: "paddingRight",
136
- type: "style",
137
- unit: "rem",
138
- reactive: true,
139
- },
140
- {
141
- prop: "pb",
142
- domProp: "paddingBottom",
143
- type: "style",
144
- unit: "rem",
145
- reactive: true,
146
- },
147
- {
148
- prop: "paddingBottom",
149
- domProp: "paddingBottom",
150
- type: "style",
151
- unit: "rem",
152
- reactive: true,
153
- },
154
- {
155
- prop: "pl",
156
- domProp: "paddingLeft",
157
- type: "style",
158
- unit: "rem",
159
- reactive: true,
160
- },
161
- {
162
- prop: "paddingLeft",
163
- domProp: "paddingLeft",
164
- type: "style",
165
- unit: "rem",
166
- reactive: true,
167
- },
168
- {
169
- prop: "mt",
170
- domProp: "marginTop",
171
- type: "style",
172
- unit: "rem",
173
- reactive: true,
174
- },
175
- {
176
- prop: "marginTop",
177
- domProp: "marginTop",
178
- type: "style",
179
- unit: "rem",
180
- reactive: true,
181
- },
182
- {
183
- prop: "mr",
184
- domProp: "marginRight",
185
- type: "style",
186
- unit: "rem",
187
- reactive: true,
188
- },
189
- {
190
- prop: "marginRight",
191
- domProp: "marginRight",
192
- type: "style",
193
- unit: "rem",
194
- reactive: true,
195
- },
196
- {
197
- prop: "mb",
198
- domProp: "marginBottom",
199
- type: "style",
200
- unit: "rem",
201
- reactive: true,
202
- },
203
- {
204
- prop: "marginBottom",
205
- domProp: "marginBottom",
206
- type: "style",
207
- unit: "rem",
208
- reactive: true,
209
- },
210
- {
211
- prop: "ml",
212
- domProp: "marginLeft",
213
- type: "style",
214
- unit: "rem",
215
- reactive: true,
216
- },
217
- {
218
- prop: "marginLeft",
219
- domProp: "marginLeft",
220
- type: "style",
221
- unit: "rem",
222
- reactive: true,
223
- },
224
-
225
- // Shorthands (expand to both sides of an axis)
226
- {
227
- prop: "px",
228
- domProp: "paddingLeft",
229
- type: "style",
230
- unit: "rem",
231
- reactive: true,
232
- targets: ["paddingLeft", "paddingRight"],
233
- },
234
- {
235
- prop: "py",
236
- domProp: "paddingTop",
237
- type: "style",
238
- unit: "rem",
239
- reactive: true,
240
- targets: ["paddingTop", "paddingBottom"],
241
- },
242
- {
243
- prop: "mx",
244
- domProp: "marginLeft",
245
- type: "style",
246
- unit: "rem",
247
- reactive: true,
248
- targets: ["marginLeft", "marginRight"],
249
- },
250
- {
251
- prop: "my",
252
- domProp: "marginTop",
253
- type: "style",
254
- unit: "rem",
255
- reactive: true,
256
- targets: ["marginTop", "marginBottom"],
257
- },
51
+ { prop: "margin", domProp: "margin", type: "style", unit: "rem", reactive: true },
52
+ { prop: "pt", domProp: "paddingTop", type: "style", unit: "rem", reactive: true },
53
+ { prop: "paddingTop", domProp: "paddingTop", type: "style", unit: "rem", reactive: true },
54
+ { prop: "pr", domProp: "paddingRight", type: "style", unit: "rem", reactive: true },
55
+ { prop: "paddingRight", domProp: "paddingRight", type: "style", unit: "rem", reactive: true },
56
+ { prop: "pb", domProp: "paddingBottom", type: "style", unit: "rem", reactive: true },
57
+ { prop: "paddingBottom", domProp: "paddingBottom", type: "style", unit: "rem", reactive: true },
58
+ { prop: "pl", domProp: "paddingLeft", type: "style", unit: "rem", reactive: true },
59
+ { prop: "paddingLeft", domProp: "paddingLeft", type: "style", unit: "rem", reactive: true },
60
+ { prop: "mt", domProp: "marginTop", type: "style", unit: "rem", reactive: true },
61
+ { prop: "marginTop", domProp: "marginTop", type: "style", unit: "rem", reactive: true },
62
+ { prop: "mr", domProp: "marginRight", type: "style", unit: "rem", reactive: true },
63
+ { prop: "marginRight", domProp: "marginRight", type: "style", unit: "rem", reactive: true },
64
+ { prop: "mb", domProp: "marginBottom", type: "style", unit: "rem", reactive: true },
65
+ { prop: "marginBottom", domProp: "marginBottom", type: "style", unit: "rem", reactive: true },
66
+ { prop: "ml", domProp: "marginLeft", type: "style", unit: "rem", reactive: true },
67
+ { prop: "marginLeft", domProp: "marginLeft", type: "style", unit: "rem", reactive: true },
68
+ { prop: "px", domProp: "paddingLeft", type: "style", unit: "rem", reactive: true, targets: ["paddingLeft", "paddingRight"] },
69
+ { prop: "py", domProp: "paddingTop", type: "style", unit: "rem", reactive: true, targets: ["paddingTop", "paddingBottom"] },
70
+ { prop: "mx", domProp: "marginLeft", type: "style", unit: "rem", reactive: true, targets: ["marginLeft", "marginRight"] },
71
+ { prop: "my", domProp: "marginTop", type: "style", unit: "rem", reactive: true, targets: ["marginTop", "marginBottom"] },
258
72
  { prop: "gap", domProp: "gap", type: "style", unit: "rem", reactive: true },
259
-
260
- // ==================== POSITION ====================
261
- {
262
- prop: "pos",
263
- domProp: "position",
264
- type: "style",
265
- unit: "none",
266
- reactive: true,
267
- },
268
- {
269
- prop: "position",
270
- domProp: "position",
271
- type: "style",
272
- unit: "none",
273
- reactive: true,
274
- },
73
+ { prop: "marginVertical", domProp: "marginTop", type: "style", unit: "rem", reactive: true, targets: ["marginTop", "marginBottom"] },
74
+ { prop: "marginHorizontal", domProp: "marginLeft", type: "style", unit: "rem", reactive: true, targets: ["marginLeft", "marginRight"] },
75
+ { prop: "paddingVertical", domProp: "paddingTop", type: "style", unit: "rem", reactive: true, targets: ["paddingTop", "paddingBottom"] },
76
+ { prop: "paddingHorizontal", domProp: "paddingLeft", type: "style", unit: "rem", reactive: true, targets: ["paddingLeft", "paddingRight"] },
77
+
78
+ // ============================================================
79
+ // POSITION
80
+ // ============================================================
81
+ { prop: "pos", domProp: "position", type: "style", unit: "none", reactive: true },
82
+ { prop: "position", domProp: "position", type: "style", unit: "none", reactive: true },
275
83
  { prop: "z", domProp: "zIndex", type: "style", unit: "none", reactive: true },
276
- {
277
- prop: "zIndex",
278
- domProp: "zIndex",
279
- type: "style",
280
- unit: "none",
281
- reactive: true,
282
- },
84
+ { prop: "zIndex", domProp: "zIndex", type: "style", unit: "none", reactive: true },
283
85
  { prop: "top", domProp: "top", type: "style", unit: "rem", reactive: true },
284
- {
285
- prop: "right",
286
- domProp: "right",
287
- type: "style",
288
- unit: "rem",
289
- reactive: true,
290
- },
291
- {
292
- prop: "bottom",
293
- domProp: "bottom",
294
- type: "style",
295
- unit: "rem",
296
- reactive: true,
297
- },
86
+ { prop: "right", domProp: "right", type: "style", unit: "rem", reactive: true },
87
+ { prop: "bottom", domProp: "bottom", type: "style", unit: "rem", reactive: true },
298
88
  { prop: "left", domProp: "left", type: "style", unit: "rem", reactive: true },
299
- {
300
- prop: "inset",
301
- domProp: "inset",
302
- type: "style",
303
- unit: "rem",
304
- reactive: true,
305
- },
306
-
307
- // ==================== COLORS ====================
308
- {
309
- prop: "bg",
310
- domProp: "backgroundColor",
311
- type: "style",
312
- unit: "none",
313
- reactive: true,
314
- },
315
- {
316
- prop: "bgColor",
317
- domProp: "backgroundColor",
318
- type: "style",
319
- unit: "none",
320
- reactive: true,
321
- },
322
- {
323
- prop: "backgroundColor",
324
- domProp: "backgroundColor",
325
- type: "style",
326
- unit: "none",
327
- reactive: true,
328
- },
329
- {
330
- prop: "textColor",
331
- domProp: "color",
332
- type: "style",
333
- unit: "none",
334
- reactive: true,
335
- },
336
- {
337
- prop: "color",
338
- domProp: "color",
339
- type: "style",
340
- unit: "none",
341
- reactive: true,
342
- },
343
- {
344
- prop: "opacity",
345
- domProp: "opacity",
346
- type: "style",
347
- unit: "none",
348
- reactive: true,
349
- },
350
-
351
- // ==================== TEXT & TYPOGRAPHY ====================
89
+ { prop: "inset", domProp: "inset", type: "style", unit: "rem", reactive: true },
90
+
91
+ // ============================================================
92
+ // COLORS
93
+ // ============================================================
94
+ { prop: "bg", domProp: "backgroundColor", type: "style", unit: "none", reactive: true },
95
+ { prop: "bgColor", domProp: "backgroundColor", type: "style", unit: "none", reactive: true },
96
+ { prop: "backgroundColor", domProp: "backgroundColor", type: "style", unit: "none", reactive: true },
97
+ { prop: "textColor", domProp: "color", type: "style", unit: "none", reactive: true },
98
+ { prop: "color", domProp: "color", type: "style", unit: "none", reactive: true },
99
+ { prop: "opacity", domProp: "opacity", type: "style", unit: "none", reactive: true },
100
+
101
+ // ============================================================
102
+ // TEXT & TYPOGRAPHY
103
+ // ============================================================
352
104
  { prop: "text", domProp: "textContent", type: "text", reactive: true },
353
105
  { prop: "label", domProp: "textContent", type: "text", reactive: true },
354
106
  { prop: "title", domProp: "textContent", type: "text", reactive: true },
355
107
  { prop: "caption", domProp: "textContent", type: "text", reactive: true },
356
108
  { prop: "description", domProp: "textContent", type: "text", reactive: true },
357
- {
358
- prop: "textContent",
359
- domProp: "textContent",
360
- type: "text",
361
- // Not reactive on purpose: a reactive accessor would shadow the native
362
- // DOM .textContent property (see reactivity.js NEVER_SHADOW).
363
- reactive: false,
364
- },
365
109
  { prop: "message", domProp: "textContent", type: "text", reactive: true },
366
110
  { prop: "buttonText", domProp: "textContent", type: "text", reactive: true },
367
-
368
- {
369
- prop: "size",
370
- domProp: "fontSize",
371
- type: "style",
372
- unit: "rem",
373
- reactive: true,
374
- },
375
- {
376
- prop: "fontSize",
377
- domProp: "fontSize",
378
- type: "style",
379
- unit: "rem",
380
- reactive: true,
381
- },
382
- {
383
- prop: "weight",
384
- domProp: "fontWeight",
385
- type: "style",
386
- unit: "none",
387
- reactive: true,
388
- },
389
- {
390
- prop: "fontWeight",
391
- domProp: "fontWeight",
392
- type: "style",
393
- unit: "none",
394
- reactive: true,
395
- },
396
- {
397
- prop: "textAlign",
398
- domProp: "textAlign",
399
- type: "style",
400
- unit: "none",
401
- reactive: true,
402
- },
403
- {
404
- prop: "lineH",
405
- domProp: "lineHeight",
406
- type: "style",
407
- unit: "none",
408
- reactive: true,
409
- },
410
- {
411
- prop: "lineHeight",
412
- domProp: "lineHeight",
413
- type: "style",
414
- unit: "none",
415
- reactive: true,
416
- },
417
- {
418
- prop: "letterSpace",
419
- domProp: "letterSpacing",
420
- type: "style",
421
- unit: "rem",
422
- reactive: true,
423
- },
424
- {
425
- prop: "letterSpacing",
426
- domProp: "letterSpacing",
427
- type: "style",
428
- unit: "rem",
429
- reactive: true,
430
- },
431
- {
432
- prop: "textDecoration",
433
- domProp: "textDecoration",
434
- type: "style",
435
- unit: "none",
436
- reactive: true,
437
- },
438
- {
439
- prop: "textTransform",
440
- domProp: "textTransform",
441
- type: "style",
442
- unit: "none",
443
- reactive: true,
444
- },
445
- {
446
- prop: "whiteSpace",
447
- domProp: "whiteSpace",
448
- type: "style",
449
- unit: "none",
450
- reactive: true,
451
- },
452
- {
453
- prop: "wordBreak",
454
- domProp: "wordBreak",
455
- type: "style",
456
- unit: "none",
457
- reactive: true,
458
- },
459
-
460
- // ==================== FLEXBOX ====================
461
- {
462
- prop: "direction",
463
- domProp: "flexDirection",
464
- type: "style",
465
- unit: "none",
466
- reactive: true,
467
- },
468
- {
469
- prop: "flexDirection",
470
- domProp: "flexDirection",
471
- type: "style",
472
- unit: "none",
473
- reactive: true,
474
- },
475
- {
476
- prop: "justify",
477
- domProp: "justifyContent",
478
- type: "style",
479
- unit: "none",
480
- reactive: true,
481
- },
482
- {
483
- prop: "justifyContent",
484
- domProp: "justifyContent",
485
- type: "style",
486
- unit: "none",
487
- reactive: true,
488
- },
489
- {
490
- prop: "align",
491
- domProp: "alignItems",
492
- type: "style",
493
- unit: "none",
494
- reactive: true,
495
- },
496
- {
497
- prop: "alignItems",
498
- domProp: "alignItems",
499
- type: "style",
500
- unit: "none",
501
- reactive: true,
502
- },
503
- {
504
- prop: "wrap",
505
- domProp: "flexWrap",
506
- type: "style",
507
- unit: "none",
508
- reactive: true,
509
- },
510
- {
511
- prop: "flexWrap",
512
- domProp: "flexWrap",
513
- type: "style",
514
- unit: "none",
515
- reactive: true,
516
- },
517
- {
518
- prop: "flex",
519
- domProp: "flex",
520
- type: "style",
521
- unit: "none",
522
- reactive: true,
523
- },
524
- {
525
- prop: "flexGrow",
526
- domProp: "flexGrow",
527
- type: "style",
528
- unit: "none",
529
- reactive: true,
530
- },
531
- {
532
- prop: "flexShrink",
533
- domProp: "flexShrink",
534
- type: "style",
535
- unit: "none",
536
- reactive: true,
537
- },
538
- {
539
- prop: "flexBasis",
540
- domProp: "flexBasis",
541
- type: "style",
542
- unit: "rem",
543
- reactive: true,
544
- },
545
-
546
- // ==================== BORDERS & RADIUS ====================
547
- {
548
- prop: "rounded",
549
- domProp: "borderRadius",
550
- type: "style",
551
- unit: "rem",
552
- reactive: true,
553
- },
554
- {
555
- prop: "borderRadius",
556
- domProp: "borderRadius",
557
- type: "style",
558
- unit: "rem",
559
- reactive: true,
560
- },
561
- {
562
- prop: "border",
563
- domProp: "border",
564
- type: "style",
565
- unit: "none",
566
- reactive: true,
567
- },
568
- {
569
- prop: "borderColor",
570
- domProp: "borderColor",
571
- type: "style",
572
- unit: "none",
573
- reactive: true,
574
- },
575
- {
576
- prop: "borderWidth",
577
- domProp: "borderWidth",
578
- type: "style",
579
- unit: "px",
580
- reactive: true,
581
- },
582
- {
583
- prop: "borderStyle",
584
- domProp: "borderStyle",
585
- type: "style",
586
- unit: "none",
587
- reactive: true,
588
- },
589
-
590
- // Corner shorthands (expand to both corners of a side)
591
- {
592
- prop: "roundedTop",
593
- domProp: "borderTopLeftRadius",
594
- type: "style",
595
- unit: "rem",
596
- reactive: true,
597
- targets: ["borderTopLeftRadius", "borderTopRightRadius"],
598
- },
599
- {
600
- prop: "roundedBottom",
601
- domProp: "borderBottomLeftRadius",
602
- type: "style",
603
- unit: "rem",
604
- reactive: true,
605
- targets: ["borderBottomLeftRadius", "borderBottomRightRadius"],
606
- },
607
- {
608
- prop: "roundedLeft",
609
- domProp: "borderTopLeftRadius",
610
- type: "style",
611
- unit: "rem",
612
- reactive: true,
613
- targets: ["borderTopLeftRadius", "borderBottomLeftRadius"],
614
- },
615
- {
616
- prop: "roundedRight",
617
- domProp: "borderTopRightRadius",
618
- type: "style",
619
- unit: "rem",
620
- reactive: true,
621
- targets: ["borderTopRightRadius", "borderBottomRightRadius"],
622
- },
623
-
624
- // ==================== SHADOWS ====================
625
- {
626
- prop: "shadow",
627
- domProp: "boxShadow",
628
- type: "style",
629
- unit: "none",
630
- reactive: true,
631
- },
632
- {
633
- prop: "boxShadow",
634
- domProp: "boxShadow",
635
- type: "style",
636
- unit: "none",
637
- reactive: true,
638
- },
639
- {
640
- prop: "elevation",
641
- domProp: "boxShadow",
642
- type: "style",
643
- unit: "none",
644
- reactive: true,
645
- }, // handled separately
646
-
647
- // ==================== DISPLAY & LAYOUT ====================
648
- {
649
- prop: "display",
650
- domProp: "display",
651
- type: "style",
652
- unit: "none",
653
- reactive: true,
654
- },
655
- {
656
- prop: "overflow",
657
- domProp: "overflow",
658
- type: "style",
659
- unit: "none",
660
- reactive: true,
661
- },
662
- {
663
- prop: "overflowX",
664
- domProp: "overflowX",
665
- type: "style",
666
- unit: "none",
667
- reactive: true,
668
- },
669
- {
670
- prop: "overflowY",
671
- domProp: "overflowY",
672
- type: "style",
673
- unit: "none",
674
- reactive: true,
675
- },
676
- {
677
- prop: "boxSizing",
678
- domProp: "boxSizing",
679
- type: "style",
680
- unit: "none",
681
- reactive: true,
682
- },
683
- {
684
- prop: "cursor",
685
- domProp: "cursor",
686
- type: "style",
687
- unit: "none",
688
- reactive: true,
689
- },
690
- {
691
- prop: "visibility",
692
- domProp: "visibility",
693
- type: "style",
694
- unit: "none",
695
- reactive: true,
696
- },
697
- {
698
- prop: "pointerEvents",
699
- domProp: "pointerEvents",
700
- type: "style",
701
- unit: "none",
702
- reactive: true,
703
- },
704
- {
705
- prop: "userSelect",
706
- domProp: "userSelect",
707
- type: "style",
708
- unit: "none",
709
- reactive: true,
710
- },
711
-
712
- // ==================== BACKGROUND ====================
713
- {
714
- prop: "gradient",
715
- domProp: "background",
716
- type: "style",
717
- unit: "none",
718
- reactive: true,
719
- },
720
- {
721
- prop: "bgImage",
722
- domProp: "backgroundImage",
723
- type: "style",
724
- unit: "none",
725
- reactive: true,
726
- },
727
- {
728
- prop: "bgSize",
729
- domProp: "backgroundSize",
730
- type: "style",
731
- unit: "none",
732
- reactive: true,
733
- },
734
- {
735
- prop: "bgPosition",
736
- domProp: "backgroundPosition",
737
- type: "style",
738
- unit: "none",
739
- reactive: true,
740
- },
741
- {
742
- prop: "bgRepeat",
743
- domProp: "backgroundRepeat",
744
- type: "style",
745
- unit: "none",
746
- reactive: true,
747
- },
748
-
749
- // ==================== ANIMATIONS & TRANSITIONS ====================
750
- {
751
- prop: "transition",
752
- domProp: "transition",
753
- type: "style",
754
- unit: "none",
755
- reactive: true,
756
- },
757
- {
758
- prop: "animation",
759
- domProp: "animation",
760
- type: "style",
761
- unit: "none",
762
- reactive: true,
763
- },
764
- {
765
- prop: "transform",
766
- domProp: "transform",
767
- type: "style",
768
- unit: "none",
769
- reactive: true,
770
- },
771
-
772
- // ==================== HTML ATTRIBUTES ====================
111
+ { prop: "subtitle", domProp: "textContent", type: "text", reactive: true },
112
+ { prop: "textContent", domProp: "textContent", type: "text", reactive: false },
113
+
114
+ { prop: "size", domProp: "fontSize", type: "style", unit: "rem", reactive: true },
115
+ { prop: "fontSize", domProp: "fontSize", type: "style", unit: "rem", reactive: true },
116
+ { prop: "weight", domProp: "fontWeight", type: "style", unit: "none", reactive: true },
117
+ { prop: "fontWeight", domProp: "fontWeight", type: "style", unit: "none", reactive: true },
118
+ { prop: "align", domProp: "textAlign", type: "style", unit: "none", reactive: true },
119
+ { prop: "textAlign", domProp: "textAlign", type: "style", unit: "none", reactive: true },
120
+ { prop: "lineH", domProp: "lineHeight", type: "style", unit: "none", reactive: true },
121
+ { prop: "lineHeight", domProp: "lineHeight", type: "style", unit: "none", reactive: true },
122
+ { prop: "letterSpace", domProp: "letterSpacing", type: "style", unit: "rem", reactive: true },
123
+ { prop: "letterSpacing", domProp: "letterSpacing", type: "style", unit: "rem", reactive: true },
124
+ { prop: "decoration", domProp: "textDecoration", type: "style", unit: "none", reactive: true },
125
+ { prop: "textDecoration", domProp: "textDecoration", type: "style", unit: "none", reactive: true },
126
+ { prop: "textTransform", domProp: "textTransform", type: "style", unit: "none", reactive: true },
127
+ { prop: "whiteSpace", domProp: "whiteSpace", type: "style", unit: "none", reactive: true },
128
+ { prop: "wordBreak", domProp: "wordBreak", type: "style", unit: "none", reactive: true },
129
+ { prop: "fontFamily", domProp: "fontFamily", type: "style", unit: "none", reactive: true },
130
+ { prop: "textOverflow", domProp: "textOverflow", type: "style", unit: "none", reactive: true },
131
+
132
+ // ============================================================
133
+ // FLEXBOX
134
+ // ============================================================
135
+ { prop: "direction", domProp: "flexDirection", type: "style", unit: "none", reactive: true },
136
+ { prop: "flexDirection", domProp: "flexDirection", type: "style", unit: "none", reactive: true },
137
+ { prop: "justify", domProp: "justifyContent", type: "style", unit: "none", reactive: true },
138
+ { prop: "justifyContent", domProp: "justifyContent", type: "style", unit: "none", reactive: true },
139
+ { prop: "alignItems", domProp: "alignItems", type: "style", unit: "none", reactive: true },
140
+ { prop: "wrap", domProp: "flexWrap", type: "style", unit: "none", reactive: true, boolValues: { true: "wrap", false: "nowrap" } },
141
+ { prop: "flexWrap", domProp: "flexWrap", type: "style", unit: "none", reactive: true, boolValues: { true: "wrap", false: "nowrap" } },
142
+ { prop: "flex", domProp: "flex", type: "style", unit: "none", reactive: true },
143
+ { prop: "flexGrow", domProp: "flexGrow", type: "style", unit: "none", reactive: true },
144
+ { prop: "flexShrink", domProp: "flexShrink", type: "style", unit: "none", reactive: true },
145
+ { prop: "flexBasis", domProp: "flexBasis", type: "style", unit: "rem", reactive: true },
146
+
147
+ // ============================================================
148
+ // BORDERS & RADIUS
149
+ // ============================================================
150
+ { prop: "rounded", domProp: "borderRadius", type: "style", unit: "rem", reactive: true },
151
+ { prop: "borderRadius", domProp: "borderRadius", type: "style", unit: "rem", reactive: true },
152
+ { prop: "border", domProp: "border", type: "style", unit: "none", reactive: true },
153
+ { prop: "borderColor", domProp: "borderColor", type: "style", unit: "none", reactive: true },
154
+ { prop: "borderWidth", domProp: "borderWidth", type: "style", unit: "px", reactive: true },
155
+ { prop: "borderStyle", domProp: "borderStyle", type: "style", unit: "none", reactive: true },
156
+ { prop: "borderTop", domProp: "borderTop", type: "style", unit: "none", reactive: true },
157
+ { prop: "borderBottom", domProp: "borderBottom", type: "style", unit: "none", reactive: true },
158
+ { prop: "borderLeft", domProp: "borderLeft", type: "style", unit: "none", reactive: true },
159
+ { prop: "borderRight", domProp: "borderRight", type: "style", unit: "none", reactive: true },
160
+ { prop: "roundedTop", domProp: "borderTopLeftRadius", type: "style", unit: "rem", reactive: true, targets: ["borderTopLeftRadius", "borderTopRightRadius"] },
161
+ { prop: "roundedBottom", domProp: "borderBottomLeftRadius", type: "style", unit: "rem", reactive: true, targets: ["borderBottomLeftRadius", "borderBottomRightRadius"] },
162
+ { prop: "roundedLeft", domProp: "borderTopLeftRadius", type: "style", unit: "rem", reactive: true, targets: ["borderTopLeftRadius", "borderBottomLeftRadius"] },
163
+ { prop: "roundedRight", domProp: "borderTopRightRadius", type: "style", unit: "rem", reactive: true, targets: ["borderTopRightRadius", "borderBottomRightRadius"] },
164
+
165
+ // Aliases simétricos (usados en only_controls: Image({ borderRadiusTop: 20 }))
166
+ { prop: "borderRadiusTop", domProp: "borderTopLeftRadius", type: "style", unit: "rem", reactive: true, targets: ["borderTopLeftRadius", "borderTopRightRadius"] },
167
+ { prop: "borderRadiusBottom", domProp: "borderBottomLeftRadius", type: "style", unit: "rem", reactive: true, targets: ["borderBottomLeftRadius", "borderBottomRightRadius"] },
168
+ { prop: "borderRadiusLeft", domProp: "borderTopLeftRadius", type: "style", unit: "rem", reactive: true, targets: ["borderTopLeftRadius", "borderBottomLeftRadius"] },
169
+ { prop: "borderRadiusRight", domProp: "borderTopRightRadius", type: "style", unit: "rem", reactive: true, targets: ["borderTopRightRadius", "borderBottomRightRadius"] },
170
+
171
+ // Single-corner radii. The shorthands above fan out over two corners, so a
172
+ // widget that needs one corner only (Drawer rounds the side facing the body)
173
+ // writes the CSS corner names directly.
174
+ { prop: "borderTopLeftRadius", domProp: "borderTopLeftRadius", type: "style", unit: "rem", reactive: true },
175
+ { prop: "borderTopRightRadius", domProp: "borderTopRightRadius", type: "style", unit: "rem", reactive: true },
176
+ { prop: "borderBottomLeftRadius", domProp: "borderBottomLeftRadius", type: "style", unit: "rem", reactive: true },
177
+ { prop: "borderBottomRightRadius", domProp: "borderBottomRightRadius", type: "style", unit: "rem", reactive: true },
178
+
179
+ // ============================================================
180
+ // SHADOWS
181
+ // ============================================================
182
+ { prop: "shadow", domProp: "boxShadow", type: "style", unit: "none", reactive: true },
183
+ { prop: "boxShadow", domProp: "boxShadow", type: "style", unit: "none", reactive: true },
184
+ { prop: "elevation", domProp: "boxShadow", type: "style", unit: "none", reactive: true },
185
+
186
+ // ============================================================
187
+ // DISPLAY & LAYOUT
188
+ // ============================================================
189
+ { prop: "display", domProp: "display", type: "style", unit: "none", reactive: true },
190
+ { prop: "overflow", domProp: "overflow", type: "style", unit: "none", reactive: true },
191
+ { prop: "overflowX", domProp: "overflowX", type: "style", unit: "none", reactive: true },
192
+ { prop: "overflowY", domProp: "overflowY", type: "style", unit: "none", reactive: true },
193
+ { prop: "boxSizing", domProp: "boxSizing", type: "style", unit: "none", reactive: true },
194
+ { prop: "cursor", domProp: "cursor", type: "style", unit: "none", reactive: true },
195
+ { prop: "visibility", domProp: "visibility", type: "style", unit: "none", reactive: true },
196
+ { prop: "pointerEvents", domProp: "pointerEvents", type: "style", unit: "none", reactive: true },
197
+ { prop: "userSelect", domProp: "userSelect", type: "style", unit: "none", reactive: true },
198
+ { prop: "touchAction", domProp: "touchAction", type: "style", unit: "none", reactive: true },
199
+ // Hints the compositor about the property an animation will change. It is a
200
+ // render optimisation, never assigned by hand after mount, so it is not
201
+ // reactive and costs no accessor on every widget.
202
+ { prop: "willChange", domProp: "willChange", type: "style", unit: "none", reactive: false },
203
+
204
+ // ============================================================
205
+ // BACKGROUND
206
+ // ============================================================
207
+ { prop: "gradient", domProp: "background", type: "style", unit: "none", reactive: true },
208
+ { prop: "bgImage", domProp: "backgroundImage", type: "style", unit: "none", reactive: true },
209
+ { prop: "bgSize", domProp: "backgroundSize", type: "style", unit: "none", reactive: true },
210
+ { prop: "bgPosition", domProp: "backgroundPosition", type: "style", unit: "none", reactive: true },
211
+ { prop: "bgRepeat", domProp: "backgroundRepeat", type: "style", unit: "none", reactive: true },
212
+
213
+ // ============================================================
214
+ // ANIMATIONS & TRANSITIONS
215
+ // ============================================================
216
+ { prop: "transition", domProp: "transition", type: "style", unit: "none", reactive: true },
217
+ { prop: "animation", domProp: "animation", type: "style", unit: "none", reactive: true },
218
+ { prop: "transform", domProp: "transform", type: "style", unit: "none", reactive: true },
219
+
220
+ // ============================================================
221
+ // HTML ATTRIBUTES
222
+ // ============================================================
773
223
  { prop: "id", domProp: "id", type: "attribute" },
774
224
  { prop: "className", domProp: "className", type: "attribute" },
775
225
  { prop: "class", domProp: "className", type: "attribute" },
@@ -780,6 +230,7 @@ export const ALL_PROPS = [
780
230
  { prop: "alt", domProp: "alt", type: "attribute" },
781
231
  { prop: "disabled", domProp: "disabled", type: "attribute" },
782
232
  { prop: "readOnly", domProp: "readOnly", type: "attribute" },
233
+ { prop: "readonly", domProp: "readOnly", type: "attribute" },
783
234
  { prop: "required", domProp: "required", type: "attribute" },
784
235
  { prop: "checked", domProp: "checked", type: "attribute" },
785
236
  { prop: "selected", domProp: "selected", type: "attribute" },
@@ -794,16 +245,26 @@ export const ALL_PROPS = [
794
245
  { prop: "tabIndex", domProp: "tabIndex", type: "attribute" },
795
246
  { prop: "draggable", domProp: "draggable", type: "attribute" },
796
247
  { prop: "hidden", domProp: "hidden", type: "attribute" },
797
- { prop: "for", domProp: "htmlFor", type: "attribute" },
798
- { prop: "htmlFor", domProp: "htmlFor", type: "attribute" },
248
+ // Handled by `applySpecial`, not by CSS: `visible: false` has to hide the
249
+ // widget without overwriting the `display` its own styles set, and `visible:
250
+ // true` must give that value back. `hidden` stays the plain HTML form.
251
+ { prop: "visible", domProp: "visible", type: "special", reactive: true },
252
+ // The DOM attribute is `for`; `htmlFor` is its React-style alias. Writing
253
+ // `setAttribute("htmlFor")` would create a junk attribute and leave the label
254
+ // unassociated, so both names target the real one.
255
+ { prop: "for", domProp: "for", type: "attribute" },
256
+ { prop: "htmlFor", domProp: "for", type: "attribute" },
799
257
  { prop: "autofocus", domProp: "autofocus", type: "attribute" },
800
258
  { prop: "autocomplete", domProp: "autocomplete", type: "attribute" },
801
259
  { prop: "spellcheck", domProp: "spellcheck", type: "attribute" },
260
+ { prop: "inputmode", domProp: "inputMode", type: "attribute" },
802
261
 
803
- // ==================== EVENTS ====================
262
+ // ============================================================
263
+ // EVENTS (standard DOM events)
264
+ // ============================================================
804
265
  { prop: "onPress", domProp: "click", type: "event" },
805
266
  { prop: "onClick", domProp: "click", type: "event" },
806
- { prop: "onclick", domProp: "click", type: "event" }, // Lowercase alias
267
+ { prop: "onclick", domProp: "click", type: "event" },
807
268
  { prop: "onDoublePress", domProp: "dblclick", type: "event" },
808
269
  { prop: "onRightClick", domProp: "contextmenu", type: "event" },
809
270
  { prop: "onHover", domProp: "mouseenter", type: "event" },
@@ -823,121 +284,18 @@ export const ALL_PROPS = [
823
284
  { prop: "onTouchMove", domProp: "touchmove", type: "event" },
824
285
  { prop: "onTouchEnd", domProp: "touchend", type: "event" },
825
286
 
826
- // ==================== SPECIAL (handled elsewhere) ====================
287
+ // ============================================================
288
+ // CORE SPECIALS
289
+ // ============================================================
290
+ { prop: "value", domProp: "value", type: "special", reactive: true },
291
+ { prop: "variant", domProp: "variant", type: "special", reactive: true },
827
292
  { prop: "ref", domProp: "ref", type: "special" },
828
293
  { prop: "child", domProp: "child", type: "special" },
829
294
  { prop: "children", domProp: "children", type: "special" },
830
- // NOTE: there is intentionally no `style` prop. FletBox uses flat, aliased
831
- // CSS props (backgroundColor, padding, flexDirection, ...). Passing
832
- // `style: {...}` is rejected with a warning by processProps.
833
-
834
- // ==================== ADDITIONAL SPECIALS (handled elsewhere) ====================
835
- {
836
- prop: "value",
837
- domProp: "value",
838
- type: "special",
839
- reactive: true,
840
- },
841
- {
842
- prop: "variant",
843
- domProp: "variant",
844
- type: "special",
845
- reactive: true,
846
- },
847
-
848
- // ==================== AXIS SHORTHANDS (≡ px/py/mx/my) ====================
849
- {
850
- prop: "marginVertical",
851
- domProp: "marginTop",
852
- type: "style",
853
- unit: "rem",
854
- reactive: true,
855
- targets: ["marginTop", "marginBottom"],
856
- },
857
- {
858
- prop: "marginHorizontal",
859
- domProp: "marginLeft",
860
- type: "style",
861
- unit: "rem",
862
- reactive: true,
863
- targets: ["marginLeft", "marginRight"],
864
- },
865
- {
866
- prop: "paddingVertical",
867
- domProp: "paddingTop",
868
- type: "style",
869
- unit: "rem",
870
- reactive: true,
871
- targets: ["paddingTop", "paddingBottom"],
872
- },
873
- {
874
- prop: "paddingHorizontal",
875
- domProp: "paddingLeft",
876
- type: "style",
877
- unit: "rem",
878
- reactive: true,
879
- targets: ["paddingLeft", "paddingRight"],
880
- },
881
-
882
- // ==================== EXTRA CSS (used by built-in widgets) ====================
883
- {
884
- prop: "fontFamily",
885
- domProp: "fontFamily",
886
- type: "style",
887
- unit: "none",
888
- reactive: true,
889
- },
890
- {
891
- prop: "touchAction",
892
- domProp: "touchAction",
893
- type: "style",
894
- unit: "none",
895
- reactive: true,
896
- },
897
- {
898
- prop: "textOverflow",
899
- domProp: "textOverflow",
900
- type: "style",
901
- unit: "none",
902
- reactive: true,
903
- },
904
- {
905
- prop: "borderTop",
906
- domProp: "borderTop",
907
- type: "style",
908
- unit: "none",
909
- reactive: true,
910
- },
911
- {
912
- prop: "borderBottom",
913
- domProp: "borderBottom",
914
- type: "style",
915
- unit: "none",
916
- reactive: true,
917
- },
918
- {
919
- prop: "borderLeft",
920
- domProp: "borderLeft",
921
- type: "style",
922
- unit: "none",
923
- reactive: true,
924
- },
925
- {
926
- prop: "borderRight",
927
- domProp: "borderRight",
928
- type: "style",
929
- unit: "none",
930
- reactive: true,
931
- },
932
-
933
- // ==================== INTERNAL CONTROL FLAGS (no DOM output) ====================
934
- // Consumed by effects.js / widgets via _originalProps; never written to the DOM.
935
295
  { prop: "disableTransform", domProp: "disableTransform", type: "special" },
936
296
  { prop: "data", domProp: "data", type: "special" },
937
297
 
938
- // Stack positioning shorthands, consumed by stackPosition.js from the widget's
939
- // original props when `position: "stack"`. Registered here so they are not
940
- // reported as unknown props; they write nothing to the DOM themselves.
298
+ // Stack positioning helpers (consumed by stackPosition.js)
941
299
  { prop: "start", domProp: "start", type: "special" },
942
300
  { prop: "end", domProp: "end", type: "special" },
943
301
  { prop: "centerX", domProp: "centerX", type: "special" },
@@ -946,63 +304,575 @@ export const ALL_PROPS = [
946
304
  { prop: "fullWidth", domProp: "fullWidth", type: "special" },
947
305
  { prop: "fullHeight", domProp: "fullHeight", type: "special" },
948
306
  { prop: "full", domProp: "full", type: "special" },
307
+
308
+ // ============================================================
309
+ // WIDGET-CONSUMED SPECIALS
310
+ // ============================================================
311
+ // Props read by widgets from `_originalProps` and applied through their own
312
+ // `applyWidgetProps` (via `composeUpdate`). They never touch the DOM
313
+ // directly and never emit "unknown prop" warnings.
314
+
315
+ // ---- Text ----
316
+ { prop: "italic", domProp: "italic", type: "special" },
317
+ { prop: "styles", domProp: "styles", type: "special" },
318
+
319
+ // ---- AppBar / Accordion ----
320
+ { prop: "titleColor", domProp: "titleColor", type: "special" },
321
+ { prop: "titleSize", domProp: "titleSize", type: "special" },
322
+ { prop: "titleWeight", domProp: "titleWeight", type: "special" },
323
+ { prop: "expandedColor", domProp: "expandedColor", type: "special" },
324
+ { prop: "iconCollapsed", domProp: "iconCollapsed", type: "special" },
325
+ { prop: "iconExpanded", domProp: "iconExpanded", type: "special" },
326
+ { prop: "titlePadding", domProp: "titlePadding", type: "special" },
327
+ { prop: "contentPadding", domProp: "contentPadding", type: "special" },
328
+ { prop: "headerBgColor", domProp: "headerBgColor", type: "special" },
329
+ { prop: "headerTextColor", domProp: "headerTextColor", type: "special" },
330
+ { prop: "contentElevation", domProp: "contentElevation", type: "special" },
331
+ { prop: "headerBorder", domProp: "headerBorder", type: "special" },
332
+ { prop: "headerPadding", domProp: "headerPadding", type: "special" },
333
+ { prop: "footerBgColor", domProp: "footerBgColor", type: "special" },
334
+ { prop: "footerBorder", domProp: "footerBorder", type: "special" },
335
+ { prop: "footerPadding", domProp: "footerPadding", type: "special" },
336
+ { prop: "headerElevation", domProp: "headerElevation", type: "special" },
337
+ { prop: "footerElevation", domProp: "footerElevation", type: "special" },
338
+
339
+ // ---- AppBar structure ----
340
+ { prop: "leading", domProp: "leading", type: "special" },
341
+ { prop: "actions", domProp: "actions", type: "special" },
342
+ { prop: "showBackButton", domProp: "showBackButton", type: "special" },
343
+ { prop: "backButtonRoute", domProp: "backButtonRoute", type: "special" },
344
+ { prop: "onBackPress", domProp: "onBackPress", type: "special" },
345
+ { prop: "centerTitle", domProp: "centerTitle", type: "special" },
346
+ { prop: "sticky", domProp: "sticky", type: "special" },
347
+ { prop: "hideOnScroll", domProp: "hideOnScroll", type: "special" },
348
+ { prop: "scrollThreshold", domProp: "scrollThreshold", type: "special" },
349
+
350
+ // ---- Tabs ----
351
+ { prop: "tabs", domProp: "tabs", type: "special" },
352
+ { prop: "activeIndex", domProp: "activeIndex", type: "special" },
353
+ { prop: "showDivider", domProp: "showDivider", type: "special" },
354
+ { prop: "dividerColor", domProp: "dividerColor", type: "special" },
355
+ { prop: "showIcon", domProp: "showIcon", type: "special" },
356
+ { prop: "iconPosition", domProp: "iconPosition", type: "special" },
357
+ { prop: "iconSize", domProp: "iconSize", type: "special" },
358
+ { prop: "badges", domProp: "badges", type: "special" },
359
+ { prop: "alignment", domProp: "alignment", type: "special" },
360
+ { prop: "activeTextColor", domProp: "activeTextColor", type: "special" },
361
+ { prop: "buttonColor", domProp: "buttonColor", type: "special" },
362
+
363
+ // ---- Tooltip ----
364
+ { prop: "showArrow", domProp: "showArrow", type: "special" },
365
+ { prop: "arrowSize", domProp: "arrowSize", type: "special" },
366
+ { prop: "delay", domProp: "delay", type: "special" },
367
+ { prop: "animationDuration", domProp: "animationDuration", type: "special" },
368
+ { prop: "offset", domProp: "offset", type: "special" },
369
+
370
+ // ---- Input / Dropdown ----
371
+ { prop: "error", domProp: "error", type: "special" },
372
+ { prop: "validation", domProp: "validation", type: "special" },
373
+ { prop: "customPattern", domProp: "customPattern", type: "special" },
374
+ { prop: "maxLength", domProp: "maxLength", type: "special" },
375
+ { prop: "passwordToggle", domProp: "passwordToggle", type: "special" },
376
+ { prop: "showValidationMessage", domProp: "showValidationMessage", type: "special" },
377
+ { prop: "showValidationIcon", domProp: "showValidationIcon", type: "special" },
378
+ { prop: "iconLeft", domProp: "iconLeft", type: "special" },
379
+ { prop: "iconRight", domProp: "iconRight", type: "special" },
380
+ { prop: "iconTop", domProp: "iconTop", type: "special" },
381
+ { prop: "iconBottom", domProp: "iconBottom", type: "special" },
382
+ { prop: "options", domProp: "options", type: "special" },
383
+ { prop: "optionHoverColor", domProp: "optionHoverColor", type: "special" },
384
+ { prop: "portal", domProp: "portal", type: "special" },
385
+ { prop: "clearable", domProp: "clearable", type: "special" },
386
+ { prop: "onValidated", domProp: "onValidated", type: "special" },
387
+ { prop: "onEnter", domProp: "onEnter", type: "special" },
388
+
389
+ // ---- Slider / Rating ----
390
+ { prop: "thumbSize", domProp: "thumbSize", type: "special" },
391
+ { prop: "thumbColor", domProp: "thumbColor", type: "special" },
392
+ { prop: "trackColor", domProp: "trackColor", type: "special" },
393
+ { prop: "marks", domProp: "marks", type: "special" },
394
+ { prop: "showMarks", domProp: "showMarks", type: "special" },
395
+ { prop: "inverted", domProp: "inverted", type: "special" },
396
+ { prop: "valuePrefix", domProp: "valuePrefix", type: "special" },
397
+ { prop: "valueSuffix", domProp: "valueSuffix", type: "special" },
398
+ { prop: "allowHalf", domProp: "allowHalf", type: "special" },
399
+ { prop: "iconActive", domProp: "iconActive", type: "special" },
400
+ { prop: "iconInactive", domProp: "iconInactive", type: "special" },
401
+ { prop: "iconHalf", domProp: "iconHalf", type: "special" },
402
+ { prop: "activeColor", domProp: "activeColor", type: "special" },
403
+ { prop: "inactiveColor", domProp: "inactiveColor", type: "special" },
404
+ { prop: "onChangeEnd", domProp: "onChangeEnd", type: "special" },
405
+
406
+ // ---- Shared callbacks ----
407
+ { prop: "onCheck", domProp: "onCheck", type: "special" },
408
+ { prop: "onToggle", domProp: "onToggle", type: "special" },
409
+ { prop: "onSelect", domProp: "onSelect", type: "special" },
410
+ { prop: "onDelete", domProp: "onDelete", type: "special" },
411
+ { prop: "onLongPress", domProp: "onLongPress", type: "special" },
412
+
413
+ // ---- Modal / BottomSheet / AlertDialog / SnackBar ----
414
+ { prop: "content", domProp: "content", type: "special" },
415
+ { prop: "confirmText", domProp: "confirmText", type: "special" },
416
+ { prop: "cancelText", domProp: "cancelText", type: "special" },
417
+ { prop: "showCancel", domProp: "showCancel", type: "special" },
418
+ { prop: "closeOnOverlayClick", domProp: "closeOnOverlayClick", type: "special" },
419
+ { prop: "closeOnEsc", domProp: "closeOnEsc", type: "special" },
420
+ { prop: "showCloseButton", domProp: "showCloseButton", type: "special" },
421
+ { prop: "overlayColor", domProp: "overlayColor", type: "special" },
422
+ { prop: "contentBgColor", domProp: "contentBgColor", type: "special" },
423
+ { prop: "onOpen", domProp: "onOpen", type: "special" },
424
+ { prop: "onClose", domProp: "onClose", type: "special" },
425
+ { prop: "onConfirm", domProp: "onConfirm", type: "special" },
426
+ { prop: "onCancel", domProp: "onCancel", type: "special" },
427
+ { prop: "showDragHandle", domProp: "showDragHandle", type: "special" },
428
+ { prop: "closeOnDragDown", domProp: "closeOnDragDown", type: "special" },
429
+ { prop: "dragHandleColor", domProp: "dragHandleColor", type: "special" },
430
+ { prop: "actionPadding", domProp: "actionPadding", type: "special" },
431
+ { prop: "headerBorderColor", domProp: "headerBorderColor", type: "special" },
432
+ { prop: "actionBorderColor", domProp: "actionBorderColor", type: "special" },
433
+ { prop: "dragHandlePadding", domProp: "dragHandlePadding", type: "special" },
434
+ { prop: "dragHandleWidth", domProp: "dragHandleWidth", type: "special" },
435
+ { prop: "dragHandleHeight", domProp: "dragHandleHeight", type: "special" },
436
+ { prop: "overlayZIndex", domProp: "overlayZIndex", type: "special" },
437
+ { prop: "action", domProp: "action", type: "special" },
438
+ { prop: "actionColor", domProp: "actionColor", type: "special" },
439
+ { prop: "onAction", domProp: "onAction", type: "special" },
440
+ { prop: "dismissible", domProp: "dismissible", type: "special" },
441
+ { prop: "onShow", domProp: "onShow", type: "special" },
442
+
443
+ // ---- Scaffold / AdaptiveScaffold / Drawer ----
444
+ { prop: "appBar", domProp: "appBar", type: "special" },
445
+ { prop: "body", domProp: "body", type: "special" },
446
+ { prop: "footer", domProp: "footer", type: "special" },
447
+ { prop: "header", domProp: "header", type: "special" },
448
+ { prop: "bottomBar", domProp: "bottomBar", type: "special" },
449
+ { prop: "drawer", domProp: "drawer", type: "special" },
450
+ { prop: "fab", domProp: "fab", type: "special" },
451
+ { prop: "leftNavBar", domProp: "leftNavBar", type: "special" },
452
+ { prop: "rightNavBar", domProp: "rightNavBar", type: "special" },
453
+ { prop: "leftNavBarWidth", domProp: "leftNavBarWidth", type: "special" },
454
+ { prop: "rightNavBarWidth", domProp: "rightNavBarWidth", type: "special" },
455
+ { prop: "navSideBar", domProp: "navSideBar", type: "special" },
456
+ { prop: "navSideBarWidth", domProp: "navSideBarWidth", type: "special" },
457
+ { prop: "navSideBarPosition", domProp: "navSideBarPosition", type: "special" },
458
+ { prop: "routes", domProp: "routes", type: "special" },
459
+ { prop: "closeDrawerOnNavigate", domProp: "closeDrawerOnNavigate", type: "special" },
460
+ { prop: "forceMobile", domProp: "forceMobile", type: "special" },
461
+ { prop: "forceDesktop", domProp: "forceDesktop", type: "special" },
462
+ { prop: "blur", domProp: "blur", type: "special" },
463
+ { prop: "blurIntensity", domProp: "blurIntensity", type: "special" },
464
+ { prop: "useRouter", domProp: "useRouter", type: "special" },
465
+ { prop: "items", domProp: "items", type: "special" },
466
+ { prop: "currentIndex", domProp: "currentIndex", type: "special" },
467
+ { prop: "onTabChange", domProp: "onTabChange", type: "special" },
468
+ { prop: "selectedColor", domProp: "selectedColor", type: "special" },
469
+ { prop: "unselectedColor", domProp: "unselectedColor", type: "special" },
470
+ { prop: "showLabels", domProp: "showLabels", type: "special" },
471
+
472
+ // ---- DrawerItem / CollapsibleSideBar ----
473
+ { prop: "route", domProp: "route", type: "special" },
474
+ { prop: "trailingIcon", domProp: "trailingIcon", type: "special" },
475
+ { prop: "hintColor", domProp: "hintColor", type: "special" },
476
+ { prop: "trailingIconColor", domProp: "trailingIconColor", type: "special" },
477
+ { prop: "iconColor", domProp: "iconColor", type: "special" },
478
+ { prop: "closeOnPress", domProp: "closeOnPress", type: "special" },
479
+ { prop: "expanded", domProp: "expanded", type: "special" },
480
+ { prop: "widthExpanded", domProp: "widthExpanded", type: "special" },
481
+ { prop: "widthCollapsed", domProp: "widthCollapsed", type: "special" },
482
+ { prop: "showTooltip", domProp: "showTooltip", type: "special" },
483
+ { prop: "tooltipDelay", domProp: "tooltipDelay", type: "special" },
484
+
485
+ // ---- ListView / GridView ----
486
+ { prop: "renderItem", domProp: "renderItem", type: "special" },
487
+ { prop: "itemSize", domProp: "itemSize", type: "special" },
488
+ { prop: "itemHeight", domProp: "itemHeight", type: "special" },
489
+ { prop: "orientation", domProp: "orientation", type: "special" },
490
+ { prop: "onEndReached", domProp: "onEndReached", type: "special" },
491
+ { prop: "onEndReachedThreshold", domProp: "onEndReachedThreshold", type: "special" },
492
+ { prop: "onRefresh", domProp: "onRefresh", type: "special" },
493
+ { prop: "refreshing", domProp: "refreshing", type: "special" },
494
+ { prop: "ListHeaderComponent", domProp: "ListHeaderComponent", type: "special" },
495
+ { prop: "ListFooterComponent", domProp: "ListFooterComponent", type: "special" },
496
+ { prop: "ListEmptyComponent", domProp: "ListEmptyComponent", type: "special" },
497
+ { prop: "showsScrollIndicator", domProp: "showsScrollIndicator", type: "special" },
498
+ { prop: "bufferSize", domProp: "bufferSize", type: "special" },
499
+ // Same rule ListView applies internally: a flex child that grows to fill the
500
+ // free space. `false` restores the CSS default instead of leaving a stale
501
+ // `flex: 1` behind after an update.
502
+ { prop: "expand", domProp: "flex", type: "style", unit: "none", reactive: true, boolValues: { true: 1, false: "0 1 auto" } },
503
+ { prop: "spacing", domProp: "spacing", type: "special" },
504
+ { prop: "columns", domProp: "columns", type: "special" },
505
+ { prop: "wrapItems", domProp: "wrapItems", type: "special" },
506
+ { prop: "crossAxisCount", domProp: "crossAxisCount", type: "special" },
507
+
508
+ // ---- DataTable ----
509
+ { prop: "rows", domProp: "rows", type: "special" },
510
+ { prop: "striped", domProp: "striped", type: "special" },
511
+ { prop: "hoverable", domProp: "hoverable", type: "special" },
512
+ { prop: "bordered", domProp: "bordered", type: "special" },
513
+ { prop: "onRowClick", domProp: "onRowClick", type: "special" },
514
+ { prop: "headerFontWeight", domProp: "headerFontWeight", type: "special" },
515
+ { prop: "headerFontSize", domProp: "headerFontSize", type: "special" },
516
+ { prop: "rowBgColor", domProp: "rowBgColor", type: "special" },
517
+ { prop: "rowTextColor", domProp: "rowTextColor", type: "special" },
518
+ { prop: "rowFontSize", domProp: "rowFontSize", type: "special" },
519
+ { prop: "stripedRowBgColor", domProp: "stripedRowBgColor", type: "special" },
520
+ { prop: "hoverRowBgColor", domProp: "hoverRowBgColor", type: "special" },
521
+ { prop: "cellPadding", domProp: "cellPadding", type: "special" },
522
+ { prop: "headerCellPadding", domProp: "headerCellPadding", type: "special" },
523
+
524
+ // ---- Chart ----
525
+ { prop: "labels", domProp: "labels", type: "special" },
526
+ { prop: "barColor", domProp: "barColor", type: "special" },
527
+ { prop: "lineColor", domProp: "lineColor", type: "special" },
528
+ { prop: "areaColor", domProp: "areaColor", type: "special" },
529
+ { prop: "smooth", domProp: "smooth", type: "special" },
530
+ { prop: "areaGradient", domProp: "areaGradient", type: "special" },
531
+ { prop: "areaGradientColors", domProp: "areaGradientColors", type: "special" },
532
+ { prop: "axisColor", domProp: "axisColor", type: "special" },
533
+ { prop: "yAxisColor", domProp: "yAxisColor", type: "special" },
534
+ { prop: "showGrid", domProp: "showGrid", type: "special" },
535
+ { prop: "showLabels", domProp: "showLabels", type: "special" },
536
+ { prop: "showValues", domProp: "showValues", type: "special" },
537
+ { prop: "candleWidth", domProp: "candleWidth", type: "special" },
538
+ { prop: "candleSpacing", domProp: "candleSpacing", type: "special" },
539
+ { prop: "candleUpColor", domProp: "candleUpColor", type: "special" },
540
+ { prop: "candleDownColor", domProp: "candleDownColor", type: "special" },
541
+
542
+ // ---- Stepper ----
543
+ { prop: "steps", domProp: "steps", type: "special" },
544
+ { prop: "activeStep", domProp: "activeStep", type: "special" },
545
+ { prop: "onStepChange", domProp: "onStepChange", type: "special" },
546
+ { prop: "showNavigation", domProp: "showNavigation", type: "special" },
547
+ { prop: "nextLabel", domProp: "nextLabel", type: "special" },
548
+ { prop: "backLabel", domProp: "backLabel", type: "special" },
549
+ { prop: "finishLabel", domProp: "finishLabel", type: "special" },
550
+ { prop: "onFinish", domProp: "onFinish", type: "special" },
551
+
552
+ // ---- Pagination ----
553
+ { prop: "totalItems", domProp: "totalItems", type: "special" },
554
+ { prop: "pageSize", domProp: "pageSize", type: "special" },
555
+ { prop: "currentPage", domProp: "currentPage", type: "special" },
556
+ { prop: "onPageChange", domProp: "onPageChange", type: "special" },
557
+ { prop: "showFirstLast", domProp: "showFirstLast", type: "special" },
558
+ { prop: "showPrevNext", domProp: "showPrevNext", type: "special" },
559
+ { prop: "maxButtons", domProp: "maxButtons", type: "special" },
560
+ { prop: "showTotal", domProp: "showTotal", type: "special" },
561
+
562
+ // ---- TreeView ----
563
+ { prop: "nodes", domProp: "nodes", type: "special" },
564
+ { prop: "expandedNodes", domProp: "expandedNodes", type: "special" },
565
+ { prop: "indent", domProp: "indent", type: "special" },
566
+ { prop: "showIcons", domProp: "showIcons", type: "special" },
567
+ { prop: "folderIcon", domProp: "folderIcon", type: "special" },
568
+ { prop: "folderOpenIcon", domProp: "folderOpenIcon", type: "special" },
569
+ { prop: "fileIcon", domProp: "fileIcon", type: "special" },
570
+ { prop: "expandIcon", domProp: "expandIcon", type: "special" },
571
+ { prop: "collapseIcon", domProp: "collapseIcon", type: "special" },
572
+ { prop: "defaultExpanded", domProp: "defaultExpanded", type: "special" },
573
+ { prop: "selectable", domProp: "selectable", type: "special" },
574
+ { prop: "selectedNodeId", domProp: "selectedNodeId", type: "special" },
575
+ { prop: "hoverBgColor", domProp: "hoverBgColor", type: "special" },
576
+ { prop: "selectedBgColor", domProp: "selectedBgColor", type: "special" },
577
+ { prop: "selectedTextColor", domProp: "selectedTextColor", type: "special" },
578
+ { prop: "folderIconColor", domProp: "folderIconColor", type: "special" },
579
+ { prop: "nodePadding", domProp: "nodePadding", type: "special" },
580
+ { prop: "nodeGap", domProp: "nodeGap", type: "special" },
581
+ { prop: "childrenGap", domProp: "childrenGap", type: "special" },
582
+
583
+ // ---- AnimatedBox / AnimatedText / Parallax ----
584
+ { prop: "animations", domProp: "animations", type: "special" },
585
+ { prop: "timing", domProp: "timing", type: "special" },
586
+ { prop: "fillMode", domProp: "fillMode", type: "special" },
587
+ { prop: "sameTime", domProp: "sameTime", type: "special" },
588
+ { prop: "delayBetween", domProp: "delayBetween", type: "special" },
589
+ { prop: "effect", domProp: "effect", type: "special" },
590
+ { prop: "from", domProp: "from", type: "special" },
591
+ { prop: "to", domProp: "to", type: "special" },
592
+ { prop: "duration", domProp: "duration", type: "special" },
593
+ { prop: "reverse", domProp: "reverse", type: "special" },
594
+ { prop: "loop", domProp: "loop", type: "special" },
595
+ { prop: "maxOffset", domProp: "maxOffset", type: "special" },
596
+ { prop: "onParallaxMove", domProp: "onParallaxMove", type: "special" },
597
+ { prop: "easing", domProp: "easing", type: "special" },
598
+
599
+ // ---- CodeViewer ----
600
+ { prop: "code", domProp: "code", type: "special" },
601
+ { prop: "showHeader", domProp: "showHeader", type: "special" },
602
+ { prop: "showLineNumbers", domProp: "showLineNumbers", type: "special" },
603
+ { prop: "startingLineNumber", domProp: "startingLineNumber", type: "special" },
604
+ { prop: "lineNumberWidth", domProp: "lineNumberWidth", type: "special" },
605
+ { prop: "lineNumberColor", domProp: "lineNumberColor", type: "special" },
606
+ { prop: "language", domProp: "language", type: "special" },
607
+
608
+ // ---- Carousel ----
609
+ { prop: "autoPlay", domProp: "autoPlay", type: "special" },
610
+ { prop: "interval", domProp: "interval", type: "special" },
611
+ { prop: "showArrows", domProp: "showArrows", type: "special" },
612
+ { prop: "showDots", domProp: "showDots", type: "special" },
613
+ { prop: "infinite", domProp: "infinite", type: "special" },
614
+ { prop: "dotColor", domProp: "dotColor", type: "special" },
615
+ { prop: "dotActiveColor", domProp: "dotActiveColor", type: "special" },
616
+ { prop: "dotSize", domProp: "dotSize", type: "special" },
617
+ { prop: "dotActiveSize", domProp: "dotActiveSize", type: "special" },
618
+ { prop: "buttonBgColor", domProp: "buttonBgColor", type: "special" },
619
+ { prop: "buttonIconColor", domProp: "buttonIconColor", type: "special" },
620
+ { prop: "buttonSize", domProp: "buttonSize", type: "special" },
621
+ { prop: "buttonIconSize", domProp: "buttonIconSize", type: "special" },
622
+ { prop: "onIndexChange", domProp: "onIndexChange", type: "special" },
623
+
624
+ // ---- Video / Audio ----
625
+ { prop: "autoplay", domProp: "autoplay", type: "special" },
626
+ { prop: "controls", domProp: "controls", type: "special" },
627
+ { prop: "muted", domProp: "muted", type: "special" },
628
+ { prop: "poster", domProp: "poster", type: "special" },
629
+ { prop: "volume", domProp: "volume", type: "special" },
630
+ // Real DOM events, so every element that fires them gets them for free
631
+ // (`img`, `video`, `audio`, `iframe`). Audio/AdSense destructure their own
632
+ // `onLoad`/`onError` before the factory sees them, so they never double-bind.
633
+ { prop: "onLoad", domProp: "load", type: "event" },
634
+ { prop: "onError", domProp: "error", type: "event" },
635
+ { prop: "onPlay", domProp: "onPlay", type: "special" },
636
+ { prop: "onPause", domProp: "onPause", type: "special" },
637
+ { prop: "onEnd", domProp: "onEnd", type: "special" },
638
+ { prop: "onTimeUpdate", domProp: "onTimeUpdate", type: "special" },
639
+ { prop: "onProgress", domProp: "onProgress", type: "special" },
640
+
641
+ // ---- DraggBox / DroppBox ----
642
+ { prop: "acceptGroups", domProp: "acceptGroups", type: "special" },
643
+ { prop: "onDrop", domProp: "onDrop", type: "special" },
644
+ { prop: "onDragStart", domProp: "onDragStart", type: "special" },
645
+ { prop: "onDragEnd", domProp: "onDragEnd", type: "special" },
646
+ { prop: "onDragEnter", domProp: "onDragEnter", type: "special" },
647
+ { prop: "onDragLeave", domProp: "onDragLeave", type: "special" },
648
+ { prop: "onDragOver", domProp: "onDragOver", type: "special" },
649
+ { prop: "group", domProp: "group", type: "special" },
650
+ { prop: "cloneOnDrag", domProp: "cloneOnDrag", type: "special" },
651
+ { prop: "dragImage", domProp: "dragImage", type: "special" },
652
+ { prop: "dragOverlayColor", domProp: "dragOverlayColor", type: "special" },
653
+ { prop: "dragBorderColor", domProp: "dragBorderColor", type: "special" },
654
+ { prop: "activeBgColor", domProp: "activeBgColor", type: "special" },
655
+ { prop: "activeBorderColor", domProp: "activeBorderColor", type: "special" },
656
+ { prop: "activeBorderWidth", domProp: "activeBorderWidth", type: "special" },
657
+ { prop: "activeBorderStyle", domProp: "activeBorderStyle", type: "special" },
658
+ { prop: "activeShadow", domProp: "activeShadow", type: "special" },
659
+ { prop: "validBgColor", domProp: "validBgColor", type: "special" },
660
+ { prop: "validBorderColor", domProp: "validBorderColor", type: "special" },
661
+ { prop: "invalidBgColor", domProp: "invalidBgColor", type: "special" },
662
+ { prop: "invalidBorderColor", domProp: "invalidBorderColor", type: "special" },
663
+ { prop: "showFeedback", domProp: "showFeedback", type: "special" },
664
+ { prop: "transitionDuration", domProp: "transitionDuration", type: "special" },
665
+ { prop: "transitionTiming", domProp: "transitionTiming", type: "special" },
666
+
667
+ // ---- Progress / Circular / Skeleton ----
668
+ { prop: "strokeWidth", domProp: "strokeWidth", type: "special" },
669
+ { prop: "progress", domProp: "progress", type: "special" },
670
+ { prop: "showValue", domProp: "showValue", type: "special" },
671
+ { prop: "valueColor", domProp: "valueColor", type: "special" },
672
+ { prop: "valueSize", domProp: "valueSize", type: "special" },
673
+ { prop: "valuePosition", domProp: "valuePosition", type: "special" },
674
+ { prop: "valueFormat", domProp: "valueFormat", type: "special" },
675
+ { prop: "valueDecimals", domProp: "valueDecimals", type: "special" },
676
+ { prop: "labelColor", domProp: "labelColor", type: "special" },
677
+ { prop: "labelSize", domProp: "labelSize", type: "special" },
678
+ { prop: "lineCap", domProp: "lineCap", type: "special" },
679
+ { prop: "animate", domProp: "animate", type: "special" },
680
+ { prop: "indeterminate", domProp: "indeterminate", type: "special" },
681
+ { prop: "animatedStripes", domProp: "animatedStripes", type: "special" },
682
+ { prop: "stripeColor", domProp: "stripeColor", type: "special" },
683
+ { prop: "shadowBlur", domProp: "shadowBlur", type: "special" },
684
+ { prop: "shadowColor", domProp: "shadowColor", type: "special" },
685
+ { prop: "glow", domProp: "glow", type: "special" },
686
+ { prop: "glowColor", domProp: "glowColor", type: "special" },
687
+ { prop: "innerStrokeWidth", domProp: "innerStrokeWidth", type: "special" },
688
+ { prop: "innerColor", domProp: "innerColor", type: "special" },
689
+ { prop: "centerContent", domProp: "centerContent", type: "special" },
690
+ { prop: "cornerRadius", domProp: "cornerRadius", type: "special" },
691
+ { prop: "tooltip", domProp: "tooltip", type: "special" },
692
+ { prop: "subtitleColor", domProp: "subtitleColor", type: "special" },
693
+ { prop: "subtitleSize", domProp: "subtitleSize", type: "special" },
694
+ { prop: "markers", domProp: "markers", type: "special" },
695
+ { prop: "onComplete", domProp: "onComplete", type: "special" },
696
+ { prop: "count", domProp: "count", type: "special" },
697
+ { prop: "highlightColor", domProp: "highlightColor", type: "special" },
698
+ { prop: "shimmerColor", domProp: "shimmerColor", type: "special" },
699
+ { prop: "pulseDuration", domProp: "pulseDuration", type: "special" },
700
+ { prop: "waveDuration", domProp: "waveDuration", type: "special" },
701
+
702
+ // ---- Avatar / Badge / Icon / Chip ----
703
+ { prop: "icon", domProp: "icon", type: "special" },
704
+ { prop: "shape", domProp: "shape", type: "special" },
705
+ { prop: "online", domProp: "online", type: "special" },
706
+ { prop: "badge", domProp: "badge", type: "special" },
707
+ { prop: "badgeColor", domProp: "badgeColor", type: "special" },
708
+ { prop: "showZero", domProp: "showZero", type: "special" },
709
+
710
+ // ---- ListTile / FAB ----
711
+ { prop: "leftItem", domProp: "leftItem", type: "special" },
712
+ { prop: "rightItem", domProp: "rightItem", type: "special" },
713
+ { prop: "divider", domProp: "divider", type: "special" },
714
+ { prop: "hoverColor", domProp: "hoverColor", type: "special" },
715
+ { prop: "mini", domProp: "mini", type: "special" },
716
+ { prop: "extended", domProp: "extended", type: "special" },
717
+ { prop: "foregroundColor", domProp: "foregroundColor", type: "special" },
718
+
719
+ // ---- Divider ----
720
+ { prop: "thickness", domProp: "thickness", type: "special" },
721
+
722
+ // ---- Markdown ----
723
+ { prop: "linkColor", domProp: "linkColor", type: "special" },
724
+ { prop: "linkHoverColor", domProp: "linkHoverColor", type: "special" },
725
+ { prop: "linkUnderline", domProp: "linkUnderline", type: "special" },
726
+ { prop: "codeBgColor", domProp: "codeBgColor", type: "special" },
727
+ { prop: "codeColor", domProp: "codeColor", type: "special" },
728
+ { prop: "codeFontSize", domProp: "codeFontSize", type: "special" },
729
+ { prop: "preBgColor", domProp: "preBgColor", type: "special" },
730
+ { prop: "preBorderRadius", domProp: "preBorderRadius", type: "special" },
731
+ { prop: "blockquoteBorderColor", domProp: "blockquoteBorderColor", type: "special" },
732
+ { prop: "headingColor", domProp: "headingColor", type: "special" },
733
+ { prop: "allowDangerousHtml", domProp: "allowDangerousHtml", type: "special" },
734
+
735
+ // ---- InstallButton ----
736
+ { prop: "downloadable", domProp: "downloadable", type: "special" },
737
+ { prop: "downloadFileName", domProp: "downloadFileName", type: "special" },
738
+ { prop: "onInstalled", domProp: "onInstalled", type: "special" },
739
+
740
+ // ---- MatrixRain ----
741
+ { prop: "chars", domProp: "chars", type: "special" },
742
+ { prop: "speed", domProp: "speed", type: "special" },
743
+ { prop: "fadeAmount", domProp: "fadeAmount", type: "special" },
744
+ { prop: "resetProbability", domProp: "resetProbability", type: "special" },
745
+ { prop: "useDynamicColor", domProp: "useDynamicColor", type: "special" },
746
+
747
+ // ---- QRCode ----
748
+ { prop: "fgColor", domProp: "fgColor", type: "special" },
749
+ { prop: "errorCorrection", domProp: "errorCorrection", type: "special" },
750
+
751
+ // ---- Image fit ----
752
+ { prop: "fit", domProp: "objectFit", type: "style", unit: "none", reactive: true },
753
+ { prop: "objectFit", domProp: "objectFit", type: "style", unit: "none", reactive: true },
754
+ // ---- Search ----
755
+ { prop: "searchable", domProp: "searchable", type: "special" },
756
+ { prop: "searchPlaceholder", domProp: "searchPlaceholder", type: "special" },
757
+
758
+ // ============================================================
759
+ // WIDGET-OWNED PROPS (audit pass)
760
+ // ============================================================
761
+ // Every prop below is read by the named widget's own code. They were missing
762
+ // from the database, so any wrapper that forwards them through `...rest`
763
+ // produced an "unknown prop" warning and an invalid inline style.
764
+
765
+ // ---- AppBar ----
766
+ { prop: "actionsGap", domProp: "actionsGap", type: "special" },
767
+
768
+ // ---- Card ----
769
+ { prop: "showBorder", domProp: "showBorder", type: "special" },
770
+
771
+ // ---- Carousel ----
772
+ { prop: "buttonTop", domProp: "buttonTop", type: "special" },
773
+
774
+ // ---- CircularBar ----
775
+ { prop: "customValueFormatter", domProp: "customValueFormatter", type: "special" },
776
+ { prop: "gradientAngle", domProp: "gradientAngle", type: "special" },
777
+
778
+ // ---- CircularChart ----
779
+ { prop: "startAngle", domProp: "startAngle", type: "special" },
780
+ { prop: "endAngle", domProp: "endAngle", type: "special" },
781
+ { prop: "innerRadius", domProp: "innerRadius", type: "special" },
782
+ { prop: "semiCircle", domProp: "semiCircle", type: "special" },
783
+ { prop: "defaultColors", domProp: "defaultColors", type: "special" },
784
+ { prop: "sliceBorderColor", domProp: "sliceBorderColor", type: "special" },
785
+ { prop: "sliceBorderWidth", domProp: "sliceBorderWidth", type: "special" },
786
+
787
+ // ---- Image ----
788
+ // Rounds the element into a circle; it is not `borderRadius` because the
789
+ // widget must keep any explicit radius the caller also passed.
790
+ { prop: "circular", domProp: "circular", type: "special" },
791
+
792
+ // ---- Input ----
793
+ { prop: "onIconPress", domProp: "onIconPress", type: "special" },
794
+
795
+ // ---- ListTile ----
796
+ // Extra props forwarded to the `Text` widgets of each row slot.
797
+ { prop: "titleProps", domProp: "titleProps", type: "special" },
798
+ { prop: "subtitleProps", domProp: "subtitleProps", type: "special" },
799
+ { prop: "descriptionProps", domProp: "descriptionProps", type: "special" },
800
+
801
+ // ---- Scaffold / routing ----
802
+ { prop: "basePath", domProp: "basePath", type: "special" },
803
+
804
+ // ---- Slider ----
805
+ // Legacy alias of `onPress`, still honoured by the widget.
806
+ { prop: "onChanged", domProp: "onChanged", type: "special" },
807
+
808
+ // ---- Markdown ----
809
+ { prop: "source", domProp: "source", type: "special" },
810
+ { prop: "headingMargin", domProp: "headingMargin", type: "special" },
811
+ { prop: "codeFontFamily", domProp: "codeFontFamily", type: "special" },
812
+ { prop: "codeBorderRadius", domProp: "codeBorderRadius", type: "special" },
813
+ { prop: "codePadding", domProp: "codePadding", type: "special" },
814
+ { prop: "prePadding", domProp: "prePadding", type: "special" },
815
+ { prop: "preMargin", domProp: "preMargin", type: "special" },
816
+ { prop: "blockquoteColor", domProp: "blockquoteColor", type: "special" },
817
+ { prop: "blockquoteBorderWidth", domProp: "blockquoteBorderWidth", type: "special" },
818
+ { prop: "blockquotePadding", domProp: "blockquotePadding", type: "special" },
819
+ { prop: "blockquoteMargin", domProp: "blockquoteMargin", type: "special" },
820
+ { prop: "tableBorderColor", domProp: "tableBorderColor", type: "special" },
821
+ { prop: "tableCellPadding", domProp: "tableCellPadding", type: "special" },
822
+ { prop: "tableHeaderBgColor", domProp: "tableHeaderBgColor", type: "special" },
823
+ { prop: "listMargin", domProp: "listMargin", type: "special" },
824
+ { prop: "listPadding", domProp: "listPadding", type: "special" },
825
+ { prop: "listItemMargin", domProp: "listItemMargin", type: "special" },
826
+ { prop: "imageMaxWidth", domProp: "imageMaxWidth", type: "special" },
827
+ { prop: "imageBorderRadius", domProp: "imageBorderRadius", type: "special" },
828
+
829
+ // ---- AdMob ----
830
+ { prop: "adId", domProp: "adId", type: "special" },
831
+ { prop: "interstitialId", domProp: "interstitialId", type: "special" },
832
+ { prop: "rewardedId", domProp: "rewardedId", type: "special" },
833
+ { prop: "isTesting", domProp: "isTesting", type: "special" },
834
+ { prop: "autoShow", domProp: "autoShow", type: "special" },
835
+ { prop: "autoInitialize", domProp: "autoInitialize", type: "special" },
836
+ { prop: "plugin", domProp: "plugin", type: "special" },
837
+ { prop: "onLoaded", domProp: "onLoaded", type: "special" },
838
+ { prop: "onFailed", domProp: "onFailed", type: "special" },
839
+ { prop: "onDismissed", domProp: "onDismissed", type: "special" },
840
+
841
+ // ---- AdSense ----
842
+ { prop: "client", domProp: "client", type: "special" },
843
+ { prop: "slot", domProp: "slot", type: "special" },
844
+ { prop: "format", domProp: "format", type: "special" },
845
+ { prop: "responsive", domProp: "responsive", type: "special" },
846
+ { prop: "test", domProp: "test", type: "special" },
949
847
  ];
950
848
 
951
849
  // ============================================================
952
850
  // DERIVED MAPS
953
851
  // ============================================================
954
- /** Map: custom prop name → definition */
955
852
  export const PROP_MAP = Object.fromEntries(ALL_PROPS.map((p) => [p.prop, p]));
956
853
 
957
- /** Map: DOM property name → definition (useful for reverse lookups) */
958
854
  export const DOM_PROP_MAP = Object.fromEntries(
959
855
  ALL_PROPS.map((p) => [p.domProp, p]),
960
856
  );
961
857
 
962
- /** List of all style props (custom names) */
963
- export const STYLE_PROPS = ALL_PROPS.filter((p) => p.type === "style").map(
964
- (p) => p.prop,
965
- );
966
-
967
- /** List of all attribute props (custom names) */
968
- export const ATTRIBUTE_PROPS = ALL_PROPS.filter(
969
- (p) => p.type === "attribute",
970
- ).map((p) => p.prop);
971
-
972
- /** List of all event props (custom names) */
973
- export const EVENT_PROPS = ALL_PROPS.filter((p) => p.type === "event").map(
974
- (p) => p.prop,
975
- );
976
-
977
- /** List of all text props (custom names) */
978
- export const TEXT_PROPS = ALL_PROPS.filter((p) => p.type === "text").map(
979
- (p) => p.prop,
980
- );
858
+ export const STYLE_PROPS = ALL_PROPS.filter((p) => p.type === "style").map((p) => p.prop);
859
+ export const ATTRIBUTE_PROPS = ALL_PROPS.filter((p) => p.type === "attribute").map((p) => p.prop);
860
+ export const EVENT_PROPS = ALL_PROPS.filter((p) => p.type === "event").map((p) => p.prop);
861
+ export const TEXT_PROPS = ALL_PROPS.filter((p) => p.type === "text").map((p) => p.prop);
862
+ export const REACTIVE_PROPS = ALL_PROPS.filter((p) => p.reactive).map((p) => p.prop);
981
863
 
982
- /** List of all reactive props (custom names) */
983
- export const REACTIVE_PROPS = ALL_PROPS.filter((p) => p.reactive).map(
984
- (p) => p.prop,
985
- );
986
-
987
- /** Map: DOM prop → unit for style props */
988
864
  export const UNIT_MAP = Object.fromEntries(
989
- ALL_PROPS.filter((p) => p.type === "style" && p.unit).map((p) => [
990
- p.domProp,
991
- p.unit,
992
- ]),
865
+ ALL_PROPS.filter((p) => p.type === "style" && p.unit).map((p) => [p.domProp, p.unit]),
993
866
  );
994
867
 
995
- /** Set of attribute DOM names (for quick membership checks) */
996
868
  export const ATTRIBUTE_DOM_SET = new Set(
997
869
  ALL_PROPS.filter((p) => p.type === "attribute").map((p) => p.domProp),
998
870
  );
999
871
 
1000
- /** Set of event DOM names */
1001
872
  export const EVENT_DOM_SET = new Set(
1002
873
  ALL_PROPS.filter((p) => p.type === "event").map((p) => p.domProp),
1003
874
  );
1004
875
 
1005
- /** Set of text custom names */
1006
876
  export const TEXT_PROP_SET = new Set(TEXT_PROPS);
1007
877
 
1008
878
  // ============================================================
@@ -1011,22 +881,28 @@ export const TEXT_PROP_SET = new Set(TEXT_PROPS);
1011
881
  setPropNames(Object.keys(PROP_MAP));
1012
882
 
1013
883
  /**
1014
- * Looks up a prop definition by its custom name.
884
+ * Prop-name prefixes the engine applies as HTML attributes without a database
885
+ * entry, because the set of valid names is defined by HTML, not by FletBox.
1015
886
  *
1016
- * Returns `null` and emits a warning (via `warnUnknownProp`) when the prop is
1017
- * not registered. The `context` object is forwarded to the warning function to
1018
- * allow widget-name–aware messages.
887
+ * @type {string[]}
888
+ */
889
+ export const PASSTHROUGH_PREFIXES = ["data-", "aria-"];
890
+
891
+ /**
892
+ * Looks up a prop definition by its custom name.
893
+ * Returns `null` and emits `warnUnknownProp` when unregistered.
1019
894
  *
1020
- * @param {string} propName - The custom prop name to look up (e.g. `'w'`, `'onClick'`).
1021
- * @param {Object} [context={}] - Optional context for warning messages
1022
- * (e.g. `{ widgetName: 'Button' }`).
1023
- * @returns {Object|null} The prop definition object from `ALL_PROPS`, or `null`
1024
- * when the prop is unknown.
895
+ * `data-*` and `aria-*` are a documented passthrough convention, not database
896
+ * entries: `processProps()` routes them straight onto HTML attributes because
897
+ * their names are open-ended and cannot be enumerated. Asking for a warning
898
+ * here would flag correct code, so these names resolve to `null` silently.
1025
899
  */
1026
900
  export function getPropDefinition(propName, context = {}) {
1027
901
  const def = PROP_MAP[propName];
1028
902
  if (!def) {
1029
- warnUnknownProp(propName, context);
903
+ if (!PASSTHROUGH_PREFIXES.some((prefix) => propName.startsWith(prefix))) {
904
+ warnUnknownProp(propName, context);
905
+ }
1030
906
  return null;
1031
907
  }
1032
908
  return def;
@@ -1046,4 +922,4 @@ export default {
1046
922
  EVENT_DOM_SET,
1047
923
  TEXT_PROP_SET,
1048
924
  getPropDefinition,
1049
- };
925
+ };