jui-tools-mcp-server 2.5.0 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/data/attribute_definitions.json +646 -203
- package/data/attribute_semantics.json +274 -20
- package/data/component_metadata.json +11 -2
- package/data/coverage.json +33 -61
- package/package.json +1 -1
- package/scripts/fetch-definitions.js +1 -1
|
@@ -101,8 +101,7 @@
|
|
|
101
101
|
"binding"
|
|
102
102
|
],
|
|
103
103
|
"description": "Width weight for flexible layouts (binding supported)",
|
|
104
|
-
"platform": "swift"
|
|
105
|
-
"mode": "uikit"
|
|
104
|
+
"platform": "swift"
|
|
106
105
|
},
|
|
107
106
|
"heightWeight": {
|
|
108
107
|
"type": [
|
|
@@ -110,8 +109,10 @@
|
|
|
110
109
|
"binding"
|
|
111
110
|
],
|
|
112
111
|
"description": "Height weight for flexible layouts (binding supported)",
|
|
113
|
-
"platform":
|
|
114
|
-
|
|
112
|
+
"platform": [
|
|
113
|
+
"swift",
|
|
114
|
+
"kotlin"
|
|
115
|
+
]
|
|
115
116
|
},
|
|
116
117
|
"maxWidthWeight": {
|
|
117
118
|
"type": [
|
|
@@ -180,7 +181,7 @@
|
|
|
180
181
|
"string",
|
|
181
182
|
"binding"
|
|
182
183
|
],
|
|
183
|
-
"description": "Background color - hex string (#RRGGBB or #RRGGBBAA) or color name from colors.json (can be data binding)"
|
|
184
|
+
"description": "Background color - hex string (#RRGGBB or #RRGGBBAA) or color name from colors.json (can be data binding). `backgroundColor` folds here: the genuine layout reads of that spelling all chain with `background` (kjui blurview_component.rb:42 `background || backgroundColor`, kjui segment_component.rb:55 `backgroundColor || background`, rjui blur_converter.rb:58 and circle_view_converter.rb:55). Note the two kjui sites read the pair in OPPOSITE order, so a layout setting both drew two different colours until the normalizer began folding them — the same defect shape as CheckBox's accent chain (plan 51-E). When a `gradient` is also declared on the same view, the GRADIENT wins and this is the fallback fill — not a layer underneath it. Full ruling in attribute_semantics.json -> backgroundFill; do not restate it in toolchain comments."
|
|
184
185
|
},
|
|
185
186
|
"tapBackground": {
|
|
186
187
|
"type": [
|
|
@@ -231,7 +232,7 @@
|
|
|
231
232
|
"string",
|
|
232
233
|
"binding"
|
|
233
234
|
],
|
|
234
|
-
"description": "Border color - hex string or color name from colors.json (binding supported)"
|
|
235
|
+
"description": "Border color - hex string or color name from colors.json (binding supported). There is deliberately NO default: a border is drawn only when borderWidth AND borderColor are both declared, and neither half summons one on its own (2026-08-03 user ruling, recorded in attribute_semantics.json#semantics.border and gated by `jui conformance gate --cross-effect` against the five `observable` entries there). Declaring a default here would make borderWidth alone draw, which is the direction d2c8628 took once and the ruling superseded."
|
|
235
236
|
},
|
|
236
237
|
"borderStyle": {
|
|
237
238
|
"type": "string",
|
|
@@ -243,15 +244,6 @@
|
|
|
243
244
|
"default": "solid",
|
|
244
245
|
"description": "Border line style - solid (default), dashed, or dotted"
|
|
245
246
|
},
|
|
246
|
-
"alpha": {
|
|
247
|
-
"type": [
|
|
248
|
-
"number",
|
|
249
|
-
"binding"
|
|
250
|
-
],
|
|
251
|
-
"min": 0,
|
|
252
|
-
"max": 1,
|
|
253
|
-
"description": "Opacity (0-1) - can be data binding"
|
|
254
|
-
},
|
|
255
247
|
"opacity": {
|
|
256
248
|
"type": [
|
|
257
249
|
"number",
|
|
@@ -259,7 +251,7 @@
|
|
|
259
251
|
],
|
|
260
252
|
"min": 0,
|
|
261
253
|
"max": 1,
|
|
262
|
-
"description": "Opacity (0-1)
|
|
254
|
+
"description": "Opacity (0-1) - can be data binding. `alpha` is an accepted alias spelling.",
|
|
263
255
|
"aliases": [
|
|
264
256
|
"alpha"
|
|
265
257
|
]
|
|
@@ -671,7 +663,8 @@
|
|
|
671
663
|
"boolean",
|
|
672
664
|
"binding"
|
|
673
665
|
],
|
|
674
|
-
"description": "Whether to clip content to bounds (binding supported)"
|
|
666
|
+
"description": "Whether to clip content to bounds (binding supported). Defaults to FALSE: content is not clipped unless the layout asks. A clipping default would silently destroy a child's `shadow` and would make `clipToBounds: true` inert on the platform that already clips. Full ruling in attribute_semantics.json -> clipToBounds; do not restate it in toolchain comments.",
|
|
667
|
+
"default": false
|
|
675
668
|
},
|
|
676
669
|
"onclick": {
|
|
677
670
|
"type": [
|
|
@@ -734,7 +727,7 @@
|
|
|
734
727
|
},
|
|
735
728
|
"variables": {
|
|
736
729
|
"type": "object",
|
|
737
|
-
"description": "Variables for include",
|
|
730
|
+
"description": "Variables for include The SwiftUI codegen DOES read this (base_view_converter.rb), but only to echo it back as a `// variables: ...` comment — nothing reaches the rendered view, so `mode: uikit` stands. Recorded because the 2026-08-05 mode audit flags the read and the next auditor would otherwise re-derive it: the read is real, the effect is not.",
|
|
738
731
|
"platform": "swift",
|
|
739
732
|
"mode": "uikit"
|
|
740
733
|
},
|
|
@@ -778,7 +771,7 @@
|
|
|
778
771
|
},
|
|
779
772
|
"binding_id": {
|
|
780
773
|
"type": "string",
|
|
781
|
-
"description": "Binding ID",
|
|
774
|
+
"description": "Binding ID The SwiftUI codegen DOES read this (base_view_converter.rb), but only to echo it back as a `// binding_id: ...` comment — nothing reaches the rendered view, so `mode: uikit` stands. Recorded because the 2026-08-05 mode audit flags the read and the next auditor would otherwise re-derive it: the read is real, the effect is not.",
|
|
782
775
|
"platform": "swift",
|
|
783
776
|
"mode": "uikit"
|
|
784
777
|
},
|
|
@@ -836,24 +829,46 @@
|
|
|
836
829
|
},
|
|
837
830
|
"events": {
|
|
838
831
|
"type": "object",
|
|
839
|
-
"description": "Complex event handlers"
|
|
840
|
-
"platform": "swift",
|
|
841
|
-
"mode": "uikit"
|
|
832
|
+
"description": "Complex event handlers"
|
|
842
833
|
},
|
|
843
834
|
"effectStyle": {
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
835
|
+
"type": "string",
|
|
836
|
+
"enum": [
|
|
837
|
+
"Light",
|
|
838
|
+
"Dark",
|
|
839
|
+
"ExtraLight",
|
|
840
|
+
"Regular",
|
|
841
|
+
"Prominent",
|
|
842
|
+
"UltraThin",
|
|
843
|
+
"Thin",
|
|
844
|
+
"Thick",
|
|
845
|
+
"Chrome",
|
|
846
|
+
"systemMaterial",
|
|
847
|
+
"systemUltraThinMaterial",
|
|
848
|
+
"systemThinMaterial",
|
|
849
|
+
"systemThickMaterial",
|
|
850
|
+
"systemChromeMaterial"
|
|
851
|
+
],
|
|
852
|
+
"valueAliases": {
|
|
853
|
+
"systemMaterial": "Regular",
|
|
854
|
+
"systemUltraThinMaterial": "UltraThin",
|
|
855
|
+
"systemThinMaterial": "Thin",
|
|
856
|
+
"systemThickMaterial": "Thick",
|
|
857
|
+
"systemChromeMaterial": "Chrome"
|
|
858
|
+
},
|
|
859
|
+
"default": "Regular",
|
|
860
|
+
"description": "Visual effect (blur) style. Measured across the three converters 2026-08-05: the UIKit trio Light/Dark/ExtraLight is what all three map (sjui blur_converter.rb:71, kjui blurview_component.rb:38, rjui blur_converter.rb:98), and web additionally maps the SwiftUI material names. Every converter downcases before matching, so the casing here is presentational. `Regular` is the fallback all three already use for an unrecognised or absent value, hence the declared default. Enumerated because it was declared as a bare string while Blur.effectStyle — the same concept on the component that owns it — carried the enum: the split let the common spelling reach the render stage unvalidated, which is what the codegen-effect gate reported once the mode audit put these fixtures back in scope. Declared on `common`, so it applies on all three platforms and not only on Blur; the ios material/tint table is pinned in attribute_semantics.json -> effectStyle, which is also where the system* valueAliases and the tint layer order are ruled."
|
|
861
|
+
},
|
|
849
862
|
"tag": {
|
|
850
863
|
"type": [
|
|
851
864
|
"number",
|
|
852
865
|
"binding"
|
|
853
866
|
],
|
|
854
867
|
"description": "View tag for identification (binding supported)",
|
|
855
|
-
"platform":
|
|
856
|
-
|
|
868
|
+
"platform": [
|
|
869
|
+
"swift",
|
|
870
|
+
"react"
|
|
871
|
+
]
|
|
857
872
|
},
|
|
858
873
|
"userInteractionEnabled": {
|
|
859
874
|
"type": [
|
|
@@ -904,8 +919,7 @@
|
|
|
904
919
|
"touchDisabledState": {
|
|
905
920
|
"type": "string",
|
|
906
921
|
"description": "Touch disable mode",
|
|
907
|
-
"platform": "swift"
|
|
908
|
-
"mode": "uikit"
|
|
922
|
+
"platform": "swift"
|
|
909
923
|
},
|
|
910
924
|
"touchEnabledViewIds": {
|
|
911
925
|
"type": "array",
|
|
@@ -919,7 +933,7 @@
|
|
|
919
933
|
},
|
|
920
934
|
"bindingScript": {
|
|
921
935
|
"type": "string",
|
|
922
|
-
"description": "Custom Swift binding code",
|
|
936
|
+
"description": "Custom Swift binding code The SwiftUI codegen DOES read this (base_view_converter.rb), but only to echo it back as a `// bindingScript: ...` comment — nothing reaches the rendered view, so `mode: uikit` stands. Recorded because the 2026-08-05 mode audit flags the read and the next auditor would otherwise re-derive it: the read is real, the effect is not.",
|
|
923
937
|
"platform": "swift",
|
|
924
938
|
"mode": "uikit"
|
|
925
939
|
},
|
|
@@ -937,7 +951,7 @@
|
|
|
937
951
|
"centerHorizontal",
|
|
938
952
|
"center"
|
|
939
953
|
],
|
|
940
|
-
"description": "Content gravity/alignment"
|
|
954
|
+
"description": "Content gravity/alignment. A single value names ONE axis; the axis it does not name falls to the container default (top vertically, start horizontally), so in LTR `left` and `top` both resolve to (start, top) and render identically. Use the array form to name both axes. Full ruling in attribute_semantics.json -> gravityDefaults; do not restate it in toolchain comments."
|
|
941
955
|
},
|
|
942
956
|
"onAppear": {
|
|
943
957
|
"type": "string",
|
|
@@ -1097,6 +1111,20 @@
|
|
|
1097
1111
|
"description": "Debug: original height string before parsing. Dynamic-only; not emitted to static code.",
|
|
1098
1112
|
"platform": "swift",
|
|
1099
1113
|
"mode": "dynamic-only"
|
|
1114
|
+
},
|
|
1115
|
+
"offsetX": {
|
|
1116
|
+
"type": [
|
|
1117
|
+
"number",
|
|
1118
|
+
"binding"
|
|
1119
|
+
],
|
|
1120
|
+
"description": "Horizontal offset applied after layout, in pt / dp / px. Measurement and sibling placement are unchanged — the layout is computed first and the offset moves only this view. Its INTERACTIVE region moves with it: an offset control is tappable where it is drawn, which is what rules out a draw-only translation. Absolute, not RTL-mirroring, like leftMargin/rightMargin rather than startMargin/endMargin. Pairs with offsetY; either one alone implies 0 for the other. Full ruling (including the android primitive) in attribute_semantics.json -> offset."
|
|
1121
|
+
},
|
|
1122
|
+
"offsetY": {
|
|
1123
|
+
"type": [
|
|
1124
|
+
"number",
|
|
1125
|
+
"binding"
|
|
1126
|
+
],
|
|
1127
|
+
"description": "Vertical offset applied after layout, in pt / dp / px. Measurement and sibling placement are unchanged — the layout is computed first and the offset moves only this view. Its INTERACTIVE region moves with it: an offset control is tappable where it is drawn, which is what rules out a draw-only translation. Absolute, not RTL-mirroring, like leftMargin/rightMargin rather than startMargin/endMargin. Pairs with offsetX; either one alone implies 0 for the other. Full ruling (including the android primitive) in attribute_semantics.json -> offset."
|
|
1100
1128
|
}
|
|
1101
1129
|
},
|
|
1102
1130
|
"Label": {
|
|
@@ -1221,9 +1249,7 @@
|
|
|
1221
1249
|
"array",
|
|
1222
1250
|
"string"
|
|
1223
1251
|
],
|
|
1224
|
-
"description": "Edge insets as array or pipe-separated string"
|
|
1225
|
-
"deprecated": "kotlin",
|
|
1226
|
-
"deprecation_note": "Compose Text has no edgeInset; use padding* instead."
|
|
1252
|
+
"description": "Edge insets as array or pipe-separated string. Applied on every platform including Compose, where it maps to .padding() (kjui text_component.rb / DynamicTextComponent.kt) - the former \"Compose Text has no edgeInset\" deprecation was contradicted by that implementation and was retracted 2026-08-05."
|
|
1227
1253
|
},
|
|
1228
1254
|
"underline": {
|
|
1229
1255
|
"type": [
|
|
@@ -1231,7 +1257,7 @@
|
|
|
1231
1257
|
"object",
|
|
1232
1258
|
"array"
|
|
1233
1259
|
],
|
|
1234
|
-
"description": "Underline styling
|
|
1260
|
+
"description": "Underline styling: boolean for a plain line, object to style it. The object face must never draw LESS than `true` does — a platform that cannot honour lineStyle or color still draws the plain Single line in the text colour. `lineStyle: \"None\"` is the one object value that draws nothing, exactly like `false`. Full ruling in attribute_semantics.json -> textDecoration; do not restate it in toolchain comments.",
|
|
1235
1261
|
"properties": {
|
|
1236
1262
|
"lineStyle": {
|
|
1237
1263
|
"type": "string",
|
|
@@ -1258,7 +1284,7 @@
|
|
|
1258
1284
|
"boolean",
|
|
1259
1285
|
"object"
|
|
1260
1286
|
],
|
|
1261
|
-
"description": "Strikethrough styling
|
|
1287
|
+
"description": "Strikethrough styling: boolean for a plain line, object to style it. Same contract as Label.underline, minus lineOffset, which strikethrough does not declare and must not invent. `lineStyle: \"None\"` draws nothing, exactly like `false`. Full ruling in attribute_semantics.json -> textDecoration; do not restate it in toolchain comments.",
|
|
1262
1288
|
"properties": {
|
|
1263
1289
|
"lineStyle": {
|
|
1264
1290
|
"type": "string",
|
|
@@ -1278,7 +1304,7 @@
|
|
|
1278
1304
|
},
|
|
1279
1305
|
"autoShrink": {
|
|
1280
1306
|
"type": "boolean",
|
|
1281
|
-
"description": "Enable auto-shrink"
|
|
1307
|
+
"description": "Enable auto-shrink. Active only on a bounded axis (explicit size, matchParent, or a max bound) — a no-op under wrapContent, which grows to the content and leaves nothing to shrink into. Full ruling in attribute_semantics.json -> autoShrink."
|
|
1282
1308
|
},
|
|
1283
1309
|
"minimumScaleFactor": {
|
|
1284
1310
|
"type": [
|
|
@@ -1442,7 +1468,7 @@
|
|
|
1442
1468
|
},
|
|
1443
1469
|
"hintAttributes": {
|
|
1444
1470
|
"type": "object",
|
|
1445
|
-
"description": "Hint text styling attributes",
|
|
1471
|
+
"description": "Hint text styling attributes. The nested keys win over the flat spellings (hintColor / hintFont / hintFontSize): a bag scoped to the hint is the more specific statement. That is the ordinary cascade rule and what all four readers do (rjui label_converter, kjui text_component, sjui Label and SelectBox) - it was unwritten until 2026-08-05, when the one converter that had it backwards was found by contradicting its own comment.",
|
|
1446
1472
|
"properties": {
|
|
1447
1473
|
"font": {
|
|
1448
1474
|
"type": "string",
|
|
@@ -1468,6 +1494,13 @@
|
|
|
1468
1494
|
"number"
|
|
1469
1495
|
],
|
|
1470
1496
|
"description": "Font weight (e.g., 'bold', 'semibold', '500', 600)"
|
|
1497
|
+
},
|
|
1498
|
+
"disabledFontColor": {
|
|
1499
|
+
"type": [
|
|
1500
|
+
"string",
|
|
1501
|
+
"binding"
|
|
1502
|
+
],
|
|
1503
|
+
"description": "Font color when disabled - hex string or color name from colors.json (binding supported). Declared from the implementation, which already read it: sjui label_converter.rb:179-180 (plan 51-E)."
|
|
1471
1504
|
}
|
|
1472
1505
|
},
|
|
1473
1506
|
"TextField": {
|
|
@@ -1476,8 +1509,11 @@
|
|
|
1476
1509
|
"string",
|
|
1477
1510
|
"binding"
|
|
1478
1511
|
],
|
|
1479
|
-
"description": "Text content (binding for two-way)",
|
|
1480
|
-
"binding_direction": "two-way"
|
|
1512
|
+
"description": "Text content (binding for two-way). `value` folds here (sjui textfield_converter.rb:527 reads `text || value || bind`).",
|
|
1513
|
+
"binding_direction": "two-way",
|
|
1514
|
+
"aliases": [
|
|
1515
|
+
"value"
|
|
1516
|
+
]
|
|
1481
1517
|
},
|
|
1482
1518
|
"hint": {
|
|
1483
1519
|
"type": "string",
|
|
@@ -1492,27 +1528,23 @@
|
|
|
1492
1528
|
"string",
|
|
1493
1529
|
"binding"
|
|
1494
1530
|
],
|
|
1495
|
-
"description": "Placeholder color - hex string or color name from colors.json (binding supported)",
|
|
1496
|
-
"
|
|
1497
|
-
|
|
1531
|
+
"description": "Placeholder color - hex string or color name from colors.json (binding supported). `placeholderColor` is an accepted alias spelling.",
|
|
1532
|
+
"aliases": [
|
|
1533
|
+
"placeholderColor"
|
|
1534
|
+
]
|
|
1498
1535
|
},
|
|
1499
1536
|
"hintFont": {
|
|
1500
1537
|
"type": "string",
|
|
1501
|
-
"description": "Placeholder font"
|
|
1502
|
-
"deprecated": "swiftui",
|
|
1503
|
-
"deprecation_note": "SwiftUI TextField placeholder cannot be custom-font-styled."
|
|
1538
|
+
"description": "Placeholder font"
|
|
1504
1539
|
},
|
|
1505
1540
|
"hintFontSize": {
|
|
1506
1541
|
"type": "number",
|
|
1507
|
-
"description": "Placeholder font size"
|
|
1508
|
-
"deprecated": "swiftui",
|
|
1509
|
-
"deprecation_note": "SwiftUI TextField placeholder cannot be custom-size-styled."
|
|
1542
|
+
"description": "Placeholder font size"
|
|
1510
1543
|
},
|
|
1511
1544
|
"hintAttributes": {
|
|
1512
1545
|
"type": "object",
|
|
1513
|
-
"description": "Hint text attributes (font,
|
|
1514
|
-
"platform": "swift"
|
|
1515
|
-
"mode": "uikit"
|
|
1546
|
+
"description": "Hint text attributes (font, fontSize, fontColor). The nested keys win over the flat spellings (hintColor / hintFont / hintFontSize): a bag scoped to the hint is the more specific statement. That is the ordinary cascade rule and what all four readers do (rjui label_converter, kjui text_component, sjui Label and SelectBox) - it was unwritten until 2026-08-05, when the one converter that had it backwards was found by contradicting its own comment.",
|
|
1547
|
+
"platform": "swift"
|
|
1516
1548
|
},
|
|
1517
1549
|
"font": {
|
|
1518
1550
|
"type": [
|
|
@@ -1577,7 +1609,22 @@
|
|
|
1577
1609
|
},
|
|
1578
1610
|
"inputType": {
|
|
1579
1611
|
"type": "string",
|
|
1580
|
-
"
|
|
1612
|
+
"enum": [
|
|
1613
|
+
"text",
|
|
1614
|
+
"number",
|
|
1615
|
+
"numberDecimal",
|
|
1616
|
+
"phone",
|
|
1617
|
+
"email",
|
|
1618
|
+
"password",
|
|
1619
|
+
"multiline",
|
|
1620
|
+
"textEmailAddress",
|
|
1621
|
+
"textPassword"
|
|
1622
|
+
],
|
|
1623
|
+
"valueAliases": {
|
|
1624
|
+
"textEmailAddress": "email",
|
|
1625
|
+
"textPassword": "password"
|
|
1626
|
+
},
|
|
1627
|
+
"description": "Input type for Android (Android-only; `input` is the cross-platform attribute). Both the JsonUI spellings and the raw android:inputType names the frozen XML mapper passed through are accepted; the latter normalize to the former.",
|
|
1581
1628
|
"platform": "kotlin"
|
|
1582
1629
|
},
|
|
1583
1630
|
"returnKeyType": {
|
|
@@ -1602,7 +1649,31 @@
|
|
|
1602
1649
|
"string",
|
|
1603
1650
|
"binding"
|
|
1604
1651
|
],
|
|
1605
|
-
"
|
|
1652
|
+
"enum": [
|
|
1653
|
+
"username",
|
|
1654
|
+
"password",
|
|
1655
|
+
"newPassword",
|
|
1656
|
+
"oneTimeCode",
|
|
1657
|
+
"email",
|
|
1658
|
+
"emailAddress",
|
|
1659
|
+
"name",
|
|
1660
|
+
"givenName",
|
|
1661
|
+
"familyName",
|
|
1662
|
+
"telephoneNumber",
|
|
1663
|
+
"tel",
|
|
1664
|
+
"phone",
|
|
1665
|
+
"streetAddress",
|
|
1666
|
+
"postalCode",
|
|
1667
|
+
"country",
|
|
1668
|
+
"creditCardNumber",
|
|
1669
|
+
"URL"
|
|
1670
|
+
],
|
|
1671
|
+
"valueAliases": {
|
|
1672
|
+
"emailAddress": "email",
|
|
1673
|
+
"tel": "telephoneNumber",
|
|
1674
|
+
"phone": "telephoneNumber"
|
|
1675
|
+
},
|
|
1676
|
+
"description": "Content type for autofill (binding supported). The enum is the set of tokens at least one platform actually maps: iOS to .textContentType, web to the autoComplete attribute, Android to the keyboard type. `email` (not emailAddress) and `telephoneNumber` (not tel) are the canonical spellings — the web converter only matches those two, so the alternates are normalized before conversion. Tokens no platform maps are deliberately absent: declaring UIKit's full UITextContentType list would enumerate values that cannot reach any output."
|
|
1606
1677
|
},
|
|
1607
1678
|
"secure": {
|
|
1608
1679
|
"type": [
|
|
@@ -1663,21 +1734,21 @@
|
|
|
1663
1734
|
},
|
|
1664
1735
|
"accessoryBackground": {
|
|
1665
1736
|
"type": "string",
|
|
1666
|
-
"description": "Input accessory background - hex string or color name from colors.json",
|
|
1737
|
+
"description": "Input accessory toolbar background - hex string or color name from colors.json. UIKit only: read by SJUITextField's accessory toolbar; SwiftUI has no input-accessory surface.",
|
|
1667
1738
|
"platform": "swift",
|
|
1668
|
-
"mode": "
|
|
1739
|
+
"mode": "uikit"
|
|
1669
1740
|
},
|
|
1670
1741
|
"accessoryTextColor": {
|
|
1671
1742
|
"type": "string",
|
|
1672
|
-
"description": "Input accessory text color - hex string or color name from colors.json",
|
|
1743
|
+
"description": "Input accessory toolbar text color - hex string or color name from colors.json. UIKit only (see accessoryBackground).",
|
|
1673
1744
|
"platform": "swift",
|
|
1674
|
-
"mode": "
|
|
1745
|
+
"mode": "uikit"
|
|
1675
1746
|
},
|
|
1676
1747
|
"doneText": {
|
|
1677
1748
|
"type": "string",
|
|
1678
|
-
"description": "Done button
|
|
1749
|
+
"description": "Text of the input accessory toolbar's Done button. UIKit only (see accessoryBackground).",
|
|
1679
1750
|
"platform": "swift",
|
|
1680
|
-
"mode": "
|
|
1751
|
+
"mode": "uikit"
|
|
1681
1752
|
},
|
|
1682
1753
|
"tintColor": {
|
|
1683
1754
|
"type": "string",
|
|
@@ -1691,9 +1762,7 @@
|
|
|
1691
1762
|
"type": "string",
|
|
1692
1763
|
"description": "Caret color - hex string or color name from colors.json"
|
|
1693
1764
|
}
|
|
1694
|
-
}
|
|
1695
|
-
"deprecated": "swiftui",
|
|
1696
|
-
"deprecation_note": "SwiftUI cannot style the caret (iOS 17 has partial .tint API)."
|
|
1765
|
+
}
|
|
1697
1766
|
},
|
|
1698
1767
|
"onTextChange": {
|
|
1699
1768
|
"type": "string",
|
|
@@ -1701,24 +1770,36 @@
|
|
|
1701
1770
|
},
|
|
1702
1771
|
"autocapitalizationType": {
|
|
1703
1772
|
"type": "string",
|
|
1704
|
-
"
|
|
1773
|
+
"enum": [
|
|
1774
|
+
"none",
|
|
1775
|
+
"words",
|
|
1776
|
+
"sentences",
|
|
1777
|
+
"allCharacters",
|
|
1778
|
+
"characters"
|
|
1779
|
+
],
|
|
1780
|
+
"valueAliases": {
|
|
1781
|
+
"characters": "allCharacters"
|
|
1782
|
+
},
|
|
1783
|
+
"description": "Auto-capitalization type. UIKit's vocabulary, honoured on every platform (.textInputAutocapitalization / KeyboardCapitalization / the HTML autocapitalize attribute). `characters` is an accepted alias spelling of allCharacters."
|
|
1705
1784
|
},
|
|
1706
1785
|
"autocorrectionType": {
|
|
1707
1786
|
"type": "string",
|
|
1708
|
-
"
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1787
|
+
"enum": [
|
|
1788
|
+
"default",
|
|
1789
|
+
"yes",
|
|
1790
|
+
"no",
|
|
1791
|
+
"on",
|
|
1792
|
+
"off",
|
|
1793
|
+
"true",
|
|
1794
|
+
"false"
|
|
1795
|
+
],
|
|
1796
|
+
"valueAliases": {
|
|
1797
|
+
"on": "yes",
|
|
1798
|
+
"true": "yes",
|
|
1799
|
+
"off": "no",
|
|
1800
|
+
"false": "no"
|
|
1801
|
+
},
|
|
1802
|
+
"description": "Auto-correction type. UIKit's vocabulary; `on`/`true` and `off`/`false` are accepted alias spellings of yes/no. `default` means \"leave it to the platform\" — web deliberately emits nothing for it."
|
|
1722
1803
|
},
|
|
1723
1804
|
"clearButtonMode": {
|
|
1724
1805
|
"type": "string",
|
|
@@ -1847,11 +1928,9 @@
|
|
|
1847
1928
|
"platform": "swift",
|
|
1848
1929
|
"mode": "swiftui"
|
|
1849
1930
|
},
|
|
1850
|
-
"
|
|
1851
|
-
"type": "
|
|
1852
|
-
"description": "
|
|
1853
|
-
"deprecated": "swift",
|
|
1854
|
-
"deprecation_note": "SwiftUI TextField placeholder cannot be color-styled."
|
|
1931
|
+
"hintLineHeightMultiple": {
|
|
1932
|
+
"type": "number",
|
|
1933
|
+
"description": "Placeholder line height multiplier. Declared from the implementation, which already read it: sjui textfield_converter.rb:153 and textview_converter.rb:93,117 (EditText/Input follow via _alias_of) (plan 51-E)."
|
|
1855
1934
|
}
|
|
1856
1935
|
},
|
|
1857
1936
|
"TextView": {
|
|
@@ -1892,7 +1971,7 @@
|
|
|
1892
1971
|
},
|
|
1893
1972
|
"hintAttributes": {
|
|
1894
1973
|
"type": "object",
|
|
1895
|
-
"description": "Hint styling attributes"
|
|
1974
|
+
"description": "Hint styling attributes. The nested keys win over the flat spellings (hintColor / hintFont / hintFontSize): a bag scoped to the hint is the more specific statement. That is the ordinary cascade rule and what all four readers do (rjui label_converter, kjui text_component, sjui Label and SelectBox) - it was unwritten until 2026-08-05, when the one converter that had it backwards was found by contradicting its own comment."
|
|
1896
1975
|
},
|
|
1897
1976
|
"hideOnFocused": {
|
|
1898
1977
|
"type": "boolean",
|
|
@@ -1985,7 +2064,15 @@
|
|
|
1985
2064
|
},
|
|
1986
2065
|
"lineBreakMode": {
|
|
1987
2066
|
"type": "string",
|
|
1988
|
-
"
|
|
2067
|
+
"enum": [
|
|
2068
|
+
"Char",
|
|
2069
|
+
"Clip",
|
|
2070
|
+
"Word",
|
|
2071
|
+
"Head",
|
|
2072
|
+
"Middle",
|
|
2073
|
+
"Tail"
|
|
2074
|
+
],
|
|
2075
|
+
"description": "Truncation mode. Same vocabulary as Label.lineBreakMode — the two were the same concept declared twice, once enumerated and once as a bare string."
|
|
1989
2076
|
},
|
|
1990
2077
|
"dataDetectorTypes": {
|
|
1991
2078
|
"type": "string",
|
|
@@ -2001,7 +2088,41 @@
|
|
|
2001
2088
|
},
|
|
2002
2089
|
"keyboardType": {
|
|
2003
2090
|
"type": "string",
|
|
2004
|
-
"
|
|
2091
|
+
"enum": [
|
|
2092
|
+
"default",
|
|
2093
|
+
"asciiCapable",
|
|
2094
|
+
"alphabet",
|
|
2095
|
+
"number",
|
|
2096
|
+
"numberPad",
|
|
2097
|
+
"decimal",
|
|
2098
|
+
"decimalPad",
|
|
2099
|
+
"phone",
|
|
2100
|
+
"phonePad",
|
|
2101
|
+
"email",
|
|
2102
|
+
"emailAddress",
|
|
2103
|
+
"URL",
|
|
2104
|
+
"webURL",
|
|
2105
|
+
"webSearch",
|
|
2106
|
+
"search",
|
|
2107
|
+
"namePhonePad",
|
|
2108
|
+
"twitter",
|
|
2109
|
+
"text",
|
|
2110
|
+
"numeric",
|
|
2111
|
+
"numbersAndPunctuation"
|
|
2112
|
+
],
|
|
2113
|
+
"valueAliases": {
|
|
2114
|
+
"alphabet": "asciiCapable",
|
|
2115
|
+
"numberPad": "number",
|
|
2116
|
+
"decimalPad": "decimal",
|
|
2117
|
+
"phonePad": "phone",
|
|
2118
|
+
"numeric": "phone",
|
|
2119
|
+
"numbersAndPunctuation": "number",
|
|
2120
|
+
"emailAddress": "email",
|
|
2121
|
+
"webURL": "URL",
|
|
2122
|
+
"search": "webSearch",
|
|
2123
|
+
"text": "default"
|
|
2124
|
+
},
|
|
2125
|
+
"description": "Soft-keyboard type. The canonical token of each pair is the one all three converters accept: `number` rather than UIKit's numberPad (Compose only matches `number` and would fall back to a plain text keyboard), likewise decimal/phone/email. `namePhonePad` and `twitter` reach iOS only; the other platforms fall back to their default keyboard."
|
|
2005
2126
|
},
|
|
2006
2127
|
"onTextChange": {
|
|
2007
2128
|
"type": "string",
|
|
@@ -2097,10 +2218,11 @@
|
|
|
2097
2218
|
"platform": "react"
|
|
2098
2219
|
},
|
|
2099
2220
|
"edgeInset": {
|
|
2100
|
-
"type":
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2221
|
+
"type": [
|
|
2222
|
+
"number",
|
|
2223
|
+
"array"
|
|
2224
|
+
],
|
|
2225
|
+
"description": "The UIKit spelling of containerInset (content inset). Same accepted shapes: a single number, or an array of 1/2/4 numbers. Was declared deprecated on kotlin (\"Compose Text has no edgeInset\"); retracted 2026-08-05 because Label.edgeInset maps to .padding() on Compose in both the codegen and the dynamic renderer. Unimplemented on the Compose TextView path, not impossible."
|
|
2104
2226
|
}
|
|
2105
2227
|
},
|
|
2106
2228
|
"EditText": {
|
|
@@ -2151,10 +2273,6 @@
|
|
|
2151
2273
|
"hilightColor"
|
|
2152
2274
|
]
|
|
2153
2275
|
},
|
|
2154
|
-
"hilightColor": {
|
|
2155
|
-
"type": "string",
|
|
2156
|
-
"description": "Highlight color - hex string or color name from colors.json (typo alias)"
|
|
2157
|
-
},
|
|
2158
2276
|
"tapBackground": {
|
|
2159
2277
|
"type": "string",
|
|
2160
2278
|
"description": "Background when tapped - hex string or color name from colors.json"
|
|
@@ -2202,6 +2320,105 @@
|
|
|
2202
2320
|
"binding"
|
|
2203
2321
|
],
|
|
2204
2322
|
"description": "Font weight (e.g., 'bold', 'semibold', '500', 600, or binding)"
|
|
2323
|
+
},
|
|
2324
|
+
"fontFamily": {
|
|
2325
|
+
"type": [
|
|
2326
|
+
"string",
|
|
2327
|
+
"binding"
|
|
2328
|
+
],
|
|
2329
|
+
"description": "Font family name (e.g., 'Noto Sans JP'). Passed as the `family` field of `FontSpec` to `Configuration.Font.fontProvider`. Coexists with `font` (weight) and `fontSize` which are passed in the same FontSpec. Declared from the implementation, which already read it: sjui button_converter.rb:173-178 (plan 51-E)."
|
|
2330
|
+
},
|
|
2331
|
+
"partialAttributes": {
|
|
2332
|
+
"type": "array",
|
|
2333
|
+
"description": "Partial text styling: apply font/size/color/underline/shadow to a substring selected by 'range' (a [start, end] pair, a text pattern, or a binding), and optionally make it tappable with 'onclick'. This is the supported way to get emphasis or a link inside a Label, since 'text' is plain text and markdown is not interpreted, and it is the portable way to express a cross-reference: the handler navigates (and scrolls to the target) in host code, so the same layout works everywhere, where a URL-based link would only work on web. All three platforms resolve partials at RUNTIME against the resolved string, so a pattern range and a localized or bound 'text' both work. Semantics, identical across platforms and verified against each runtime: an array range is [start, end) with the end exclusive; a string range is the FIRST occurrence and the partial is skipped (not an error) when the pattern is absent; a range that is out of bounds or inverted is skipped; partials apply in declaration order and MERGE where they overlap, later declarations winning per property. Declared from the implementation, which already read it: sjui button_converter.rb:68-129 (plan 51-E).",
|
|
2334
|
+
"items": {
|
|
2335
|
+
"type": "object",
|
|
2336
|
+
"properties": {
|
|
2337
|
+
"font": {
|
|
2338
|
+
"type": "string",
|
|
2339
|
+
"description": "Font name"
|
|
2340
|
+
},
|
|
2341
|
+
"fontSize": {
|
|
2342
|
+
"type": "number",
|
|
2343
|
+
"description": "Font size"
|
|
2344
|
+
},
|
|
2345
|
+
"fontColor": {
|
|
2346
|
+
"type": "string",
|
|
2347
|
+
"description": "Font color - hex string or color name from colors.json"
|
|
2348
|
+
},
|
|
2349
|
+
"lineSpacing": {
|
|
2350
|
+
"type": "number",
|
|
2351
|
+
"description": "Line spacing"
|
|
2352
|
+
},
|
|
2353
|
+
"lineHeightMultiple": {
|
|
2354
|
+
"type": "number",
|
|
2355
|
+
"description": "Line height multiplier"
|
|
2356
|
+
},
|
|
2357
|
+
"lineBreakMode": {
|
|
2358
|
+
"type": "string",
|
|
2359
|
+
"enum": [
|
|
2360
|
+
"Char",
|
|
2361
|
+
"Clip",
|
|
2362
|
+
"Word",
|
|
2363
|
+
"Head",
|
|
2364
|
+
"Middle",
|
|
2365
|
+
"Tail"
|
|
2366
|
+
],
|
|
2367
|
+
"description": "Line break mode"
|
|
2368
|
+
},
|
|
2369
|
+
"textAlign": {
|
|
2370
|
+
"type": "string",
|
|
2371
|
+
"enum": [
|
|
2372
|
+
"Left",
|
|
2373
|
+
"Right",
|
|
2374
|
+
"Center"
|
|
2375
|
+
],
|
|
2376
|
+
"description": "Text alignment"
|
|
2377
|
+
},
|
|
2378
|
+
"underline": {
|
|
2379
|
+
"type": "object",
|
|
2380
|
+
"properties": {
|
|
2381
|
+
"lineStyle": {
|
|
2382
|
+
"type": "string",
|
|
2383
|
+
"enum": [
|
|
2384
|
+
"Single",
|
|
2385
|
+
"Double",
|
|
2386
|
+
"Thick",
|
|
2387
|
+
"None"
|
|
2388
|
+
],
|
|
2389
|
+
"description": "Underline style"
|
|
2390
|
+
},
|
|
2391
|
+
"color": {
|
|
2392
|
+
"type": "string",
|
|
2393
|
+
"description": "Underline color - hex string or color name from colors.json"
|
|
2394
|
+
},
|
|
2395
|
+
"lineOffset": {
|
|
2396
|
+
"type": "number",
|
|
2397
|
+
"description": "Baseline offset"
|
|
2398
|
+
}
|
|
2399
|
+
}
|
|
2400
|
+
},
|
|
2401
|
+
"textShadow": {
|
|
2402
|
+
"type": "string",
|
|
2403
|
+
"description": "Text shadow"
|
|
2404
|
+
},
|
|
2405
|
+
"range": {
|
|
2406
|
+
"type": [
|
|
2407
|
+
"array",
|
|
2408
|
+
"string"
|
|
2409
|
+
],
|
|
2410
|
+
"description": "Range [start, end], text pattern string, or binding expression"
|
|
2411
|
+
},
|
|
2412
|
+
"onclick": {
|
|
2413
|
+
"type": "string",
|
|
2414
|
+
"description": "Click handler for this range (selector-based, lowercase)"
|
|
2415
|
+
},
|
|
2416
|
+
"onClick": {
|
|
2417
|
+
"type": "binding",
|
|
2418
|
+
"description": "Click handler for this range (camelCase) - binding only (@{functionName})"
|
|
2419
|
+
}
|
|
2420
|
+
}
|
|
2421
|
+
}
|
|
2205
2422
|
}
|
|
2206
2423
|
},
|
|
2207
2424
|
"Image": {
|
|
@@ -2259,7 +2476,10 @@
|
|
|
2259
2476
|
"Left",
|
|
2260
2477
|
"Right"
|
|
2261
2478
|
],
|
|
2262
|
-
"
|
|
2479
|
+
"valueAliases": {
|
|
2480
|
+
"ScaleToFill": "fill"
|
|
2481
|
+
},
|
|
2482
|
+
"description": "Content mode (binding supported). ScaleToFill is a declared synonym of fill (the stretch — see attribute_semantics.json#semantics.image); the normalizer folds it, fixtures are generated for the canonical spelling only."
|
|
2263
2483
|
},
|
|
2264
2484
|
"renderingMode": {
|
|
2265
2485
|
"type": "string",
|
|
@@ -2326,6 +2546,10 @@
|
|
|
2326
2546
|
"description": "Pinch-zoom lower bound.",
|
|
2327
2547
|
"platform": "swift",
|
|
2328
2548
|
"mode": "swiftui"
|
|
2549
|
+
},
|
|
2550
|
+
"defaultImage": {
|
|
2551
|
+
"type": "string",
|
|
2552
|
+
"description": "Default image name. Declared from the implementation, which already read it: sjui image_converter.rb:36,42 (defaultImage || errorImage || loadingImage) (plan 51-E)."
|
|
2329
2553
|
}
|
|
2330
2554
|
},
|
|
2331
2555
|
"NetworkImage": {
|
|
@@ -2341,7 +2565,10 @@
|
|
|
2341
2565
|
"string",
|
|
2342
2566
|
"binding"
|
|
2343
2567
|
],
|
|
2344
|
-
"description": "Image URL (alias, can be data binding)"
|
|
2568
|
+
"description": "Image URL (alias, can be data binding). `source` folds here (sjui network_image_converter.rb:14 reads `url || source || src`).",
|
|
2569
|
+
"aliases": [
|
|
2570
|
+
"source"
|
|
2571
|
+
]
|
|
2345
2572
|
},
|
|
2346
2573
|
"hint": {
|
|
2347
2574
|
"type": "string",
|
|
@@ -2421,6 +2648,18 @@
|
|
|
2421
2648
|
"description": "HTTP headers for the image request (Coil 3: httpHeaders(NetworkHeaders) on ImageRequest.Builder).",
|
|
2422
2649
|
"platform": "kotlin",
|
|
2423
2650
|
"mode": "compose"
|
|
2651
|
+
},
|
|
2652
|
+
"renderingMode": {
|
|
2653
|
+
"type": "string",
|
|
2654
|
+
"enum": [
|
|
2655
|
+
"original",
|
|
2656
|
+
"template"
|
|
2657
|
+
],
|
|
2658
|
+
"description": "Rendering mode. Declared from the implementation, which already read it: sjui network_image_converter.rb:67-68 (plan 51-E).",
|
|
2659
|
+
"platform": [
|
|
2660
|
+
"swift",
|
|
2661
|
+
"kotlin"
|
|
2662
|
+
]
|
|
2424
2663
|
}
|
|
2425
2664
|
},
|
|
2426
2665
|
"SelectBox": {
|
|
@@ -2443,14 +2682,6 @@
|
|
|
2443
2682
|
],
|
|
2444
2683
|
"description": "Hint text color - hex string or color name from colors.json (binding supported)"
|
|
2445
2684
|
},
|
|
2446
|
-
"text": {
|
|
2447
|
-
"type": [
|
|
2448
|
-
"string",
|
|
2449
|
-
"binding"
|
|
2450
|
-
],
|
|
2451
|
-
"description": "Display text (binding supported)",
|
|
2452
|
-
"platform": "swift"
|
|
2453
|
-
},
|
|
2454
2685
|
"items": {
|
|
2455
2686
|
"type": [
|
|
2456
2687
|
"array",
|
|
@@ -2481,15 +2712,17 @@
|
|
|
2481
2712
|
"binding"
|
|
2482
2713
|
],
|
|
2483
2714
|
"description": "Selected item value (two-way binding)",
|
|
2484
|
-
"platform":
|
|
2485
|
-
|
|
2715
|
+
"platform": [
|
|
2716
|
+
"swift",
|
|
2717
|
+
"kotlin"
|
|
2718
|
+
]
|
|
2486
2719
|
},
|
|
2487
2720
|
"selectedDate": {
|
|
2488
2721
|
"type": [
|
|
2489
2722
|
"string",
|
|
2490
2723
|
"binding"
|
|
2491
2724
|
],
|
|
2492
|
-
"description": "Initial selected date (yyyy-MM-dd format, two-way binding)"
|
|
2725
|
+
"description": "Initial selected date (yyyy-MM-dd format, two-way binding). No `default`: when it is absent no initial selection has been stated, and the closed face shows the prompt / hint / placeholder rather than today's date. Full ruling in attribute_semantics.json -> selectBoxDate."
|
|
2493
2726
|
},
|
|
2494
2727
|
"datePickerMode": {
|
|
2495
2728
|
"type": "string",
|
|
@@ -2500,7 +2733,10 @@
|
|
|
2500
2733
|
"dateAndTime",
|
|
2501
2734
|
"countDown"
|
|
2502
2735
|
],
|
|
2503
|
-
"
|
|
2736
|
+
"valueAliases": {
|
|
2737
|
+
"datetime": "dateAndTime"
|
|
2738
|
+
},
|
|
2739
|
+
"description": "Date picker mode. datetime is a declared synonym of dateAndTime and the normalizer folds it: sjui and rjui accept both spellings (selectbox_converter.rb case arms; rjui downcases), but KotlinJsonUI's DateSelectBox matches \"dateAndTime\" literally and datetime would silently fall to the date-only branch — so the UIKit spelling is canonical, same reasoning as gradientDirection's capitalised canon."
|
|
2504
2740
|
},
|
|
2505
2741
|
"datePickerStyle": {
|
|
2506
2742
|
"type": "string",
|
|
@@ -2516,7 +2752,10 @@
|
|
|
2516
2752
|
},
|
|
2517
2753
|
"dateStringFormat": {
|
|
2518
2754
|
"type": "string",
|
|
2519
|
-
"description": "Date string format"
|
|
2755
|
+
"description": "Date string format. `dateFormat` folds here (sjui selectbox_converter.rb:132 reads `dateFormat || dateStringFormat`).",
|
|
2756
|
+
"aliases": [
|
|
2757
|
+
"dateFormat"
|
|
2758
|
+
]
|
|
2520
2759
|
},
|
|
2521
2760
|
"minimumDate": {
|
|
2522
2761
|
"type": [
|
|
@@ -2807,10 +3046,6 @@
|
|
|
2807
3046
|
"platform": "swift",
|
|
2808
3047
|
"mode": "uikit"
|
|
2809
3048
|
},
|
|
2810
|
-
"onToggle": {
|
|
2811
|
-
"type": "binding",
|
|
2812
|
-
"description": "Toggle handler function - binding only (@{functionName}). Alias of onValueChange."
|
|
2813
|
-
},
|
|
2814
3049
|
"onValueChange": {
|
|
2815
3050
|
"type": "binding",
|
|
2816
3051
|
"description": "Value change handler - binding only (@{functionName})",
|
|
@@ -2854,9 +3089,43 @@
|
|
|
2854
3089
|
},
|
|
2855
3090
|
"trackTintColor": {
|
|
2856
3091
|
"type": "string",
|
|
2857
|
-
"description": "
|
|
2858
|
-
|
|
2859
|
-
|
|
3092
|
+
"description": "Colour of the switch track - hex string or color name from colors.json. Deprecation retracted with the Slider pair; a SwiftUI Toggle is not limited to a unified tint any more than Progress is."
|
|
3093
|
+
},
|
|
3094
|
+
"fontColor": {
|
|
3095
|
+
"type": [
|
|
3096
|
+
"string",
|
|
3097
|
+
"binding"
|
|
3098
|
+
],
|
|
3099
|
+
"description": "Text color - hex string or color name from colors.json (binding supported). Declared from the implementation, which already read it: sjui toggle_converter.rb:62-63,71-72 (plan 51-E)."
|
|
3100
|
+
},
|
|
3101
|
+
"toggleStyle": {
|
|
3102
|
+
"type": "string",
|
|
3103
|
+
"enum": [
|
|
3104
|
+
"switch",
|
|
3105
|
+
"button",
|
|
3106
|
+
"checkbox",
|
|
3107
|
+
"default"
|
|
3108
|
+
],
|
|
3109
|
+
"description": "Which control shape the Switch is drawn as. A SwiftUI-only concept (the ToggleStyle protocol); an unrecognised value falls back to the platform default rather than erroring. Declared from the implementation, which already read it: sjui toggle_converter.rb:92-104 (plan 51-E).",
|
|
3110
|
+
"platform": "swift",
|
|
3111
|
+
"mode": "swiftui"
|
|
3112
|
+
},
|
|
3113
|
+
"label": {
|
|
3114
|
+
"type": [
|
|
3115
|
+
"string",
|
|
3116
|
+
"binding"
|
|
3117
|
+
],
|
|
3118
|
+
"description": "Switch label (can be data binding). Same shape CheckBox and Radio already declare: `label` is the canonical row and `text` folds into it. Declared from the implementation, which already read it: sjui toggle_converter.rb:21 (text || label) (plan 51-E).",
|
|
3119
|
+
"aliases": [
|
|
3120
|
+
"text"
|
|
3121
|
+
]
|
|
3122
|
+
},
|
|
3123
|
+
"fontSize": {
|
|
3124
|
+
"type": [
|
|
3125
|
+
"number",
|
|
3126
|
+
"binding"
|
|
3127
|
+
],
|
|
3128
|
+
"description": "Font size (binding supported). Declared from the implementation, which already read it: sjui toggle_converter.rb hands the whole component to the shared apply_font_modifiers helper, so the size was honoured with no declaration behind it (plan 51-E)."
|
|
2860
3129
|
}
|
|
2861
3130
|
},
|
|
2862
3131
|
"Toggle": {
|
|
@@ -2874,30 +3143,32 @@
|
|
|
2874
3143
|
"number",
|
|
2875
3144
|
"binding"
|
|
2876
3145
|
],
|
|
2877
|
-
"description": "Initially selected index (binding for two-way)",
|
|
2878
|
-
"binding_direction": "two-way"
|
|
3146
|
+
"description": "Initially selected index (binding for two-way). `selectedTabIndex` folds here (sjui segment_converter.rb:16), matching the alias TabView already declares.",
|
|
3147
|
+
"binding_direction": "two-way",
|
|
3148
|
+
"aliases": [
|
|
3149
|
+
"selectedTabIndex"
|
|
3150
|
+
]
|
|
2879
3151
|
},
|
|
2880
3152
|
"tintColor": {
|
|
2881
3153
|
"type": "string",
|
|
2882
|
-
"description": "
|
|
3154
|
+
"description": "Accent color of the SELECTED segment - a background fill on ios/web, the indicator on Compose. Hex string or color name from colors.json. `selectedSegmentTintColor` folds here (sjui segment_converter.rb:128 reads `selectedSegmentTintColor || tintColor`).",
|
|
3155
|
+
"aliases": [
|
|
3156
|
+
"selectedSegmentTintColor"
|
|
3157
|
+
]
|
|
2883
3158
|
},
|
|
2884
|
-
"
|
|
2885
|
-
"type":
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
"platform": "swift",
|
|
2891
|
-
"mode": "swiftui"
|
|
3159
|
+
"fontColor": {
|
|
3160
|
+
"type": "string",
|
|
3161
|
+
"description": "Label color of the UNSELECTED segments - hex string or color name from colors.json",
|
|
3162
|
+
"aliases": [
|
|
3163
|
+
"normalColor"
|
|
3164
|
+
]
|
|
2892
3165
|
},
|
|
2893
|
-
"
|
|
2894
|
-
"type":
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
"platform": "swift",
|
|
2900
|
-
"mode": "swiftui"
|
|
3166
|
+
"selectedFontColor": {
|
|
3167
|
+
"type": "string",
|
|
3168
|
+
"description": "Label color of the selected segment, falling back to fontColor - hex string or color name from colors.json",
|
|
3169
|
+
"aliases": [
|
|
3170
|
+
"selectedColor"
|
|
3171
|
+
]
|
|
2901
3172
|
},
|
|
2902
3173
|
"valueChange": {
|
|
2903
3174
|
"type": "string",
|
|
@@ -2929,41 +3200,29 @@
|
|
|
2929
3200
|
"description": "Current value (binding for two-way)",
|
|
2930
3201
|
"binding_direction": "two-way"
|
|
2931
3202
|
},
|
|
2932
|
-
"minValue": {
|
|
2933
|
-
"type": [
|
|
2934
|
-
"number",
|
|
2935
|
-
"binding"
|
|
2936
|
-
],
|
|
2937
|
-
"description": "Minimum value (binding supported)"
|
|
2938
|
-
},
|
|
2939
3203
|
"minimum": {
|
|
2940
3204
|
"type": [
|
|
2941
3205
|
"number",
|
|
2942
3206
|
"binding"
|
|
2943
3207
|
],
|
|
2944
|
-
"description": "Minimum value (alias for
|
|
3208
|
+
"description": "Minimum value (binding supported). `minValue` / `minimumValue` are accepted alias spellings. Defaults to 0: with no bounds declared the range is 0 .. 1, this SSoT's convention for a unitless value on a track (compare Progress.progress and opacity, both declared min 0 / max 1). Full ruling in attribute_semantics.json -> sliderRange.",
|
|
2945
3209
|
"aliases": [
|
|
2946
3210
|
"minimumValue",
|
|
2947
3211
|
"minValue"
|
|
2948
|
-
]
|
|
2949
|
-
},
|
|
2950
|
-
"maxValue": {
|
|
2951
|
-
"type": [
|
|
2952
|
-
"number",
|
|
2953
|
-
"binding"
|
|
2954
3212
|
],
|
|
2955
|
-
"
|
|
3213
|
+
"default": 0
|
|
2956
3214
|
},
|
|
2957
3215
|
"maximum": {
|
|
2958
3216
|
"type": [
|
|
2959
3217
|
"number",
|
|
2960
3218
|
"binding"
|
|
2961
3219
|
],
|
|
2962
|
-
"description": "Maximum value (alias for
|
|
3220
|
+
"description": "Maximum value (binding supported). `maxValue` / `maximumValue` are accepted alias spellings. Defaults to 1: with no bounds declared the range is 0 .. 1, this SSoT's convention for a unitless value on a track (compare Progress.progress and opacity, both declared min 0 / max 1). Full ruling in attribute_semantics.json -> sliderRange.",
|
|
2963
3221
|
"aliases": [
|
|
2964
3222
|
"maximumValue",
|
|
2965
3223
|
"maxValue"
|
|
2966
|
-
]
|
|
3224
|
+
],
|
|
3225
|
+
"default": 1
|
|
2967
3226
|
},
|
|
2968
3227
|
"tintColor": {
|
|
2969
3228
|
"type": "string",
|
|
@@ -2995,15 +3254,15 @@
|
|
|
2995
3254
|
},
|
|
2996
3255
|
"progressTintColor": {
|
|
2997
3256
|
"type": "string",
|
|
2998
|
-
"description": "
|
|
2999
|
-
"deprecated": "swift",
|
|
3000
|
-
"deprecation_note": "SwiftUI Slider uses unified tint only."
|
|
3257
|
+
"description": "Colour of the filled portion of the track - hex string or color name from colors.json. Was declared deprecated on swift (\"SwiftUI Slider uses unified tint only\"); retracted 2026-08-05 because Progress, also SwiftUI, maps the same attribute to .tint(). Unimplemented on the Slider path, not impossible."
|
|
3001
3258
|
},
|
|
3002
3259
|
"trackTintColor": {
|
|
3003
3260
|
"type": "string",
|
|
3004
|
-
"description": "
|
|
3005
|
-
|
|
3006
|
-
|
|
3261
|
+
"description": "Colour of the unfilled track - hex string or color name from colors.json. Deprecation retracted with progressTintColor: SwiftUI Progress reaches the same result through .background()."
|
|
3262
|
+
},
|
|
3263
|
+
"range": {
|
|
3264
|
+
"type": "array",
|
|
3265
|
+
"description": "Both bounds at once, as [minimum, maximum] — a shorthand for declaring `minimum` and `maximum` separately. It is NOT an alias: one spelling carries two values, so the normalizer cannot fold it. Read only when it is a two-element array; anything else leaves `minimum` / `maximum` to speak for themselves. Declared from the implementation, which already read it: sjui slider_converter.rb:16-19 (plan 51-E)."
|
|
3007
3266
|
}
|
|
3008
3267
|
},
|
|
3009
3268
|
"Progress": {
|
|
@@ -3136,16 +3395,30 @@
|
|
|
3136
3395
|
},
|
|
3137
3396
|
"gradient": {
|
|
3138
3397
|
"type": "array",
|
|
3139
|
-
"description": "Gradient colors",
|
|
3140
|
-
"platform": "swift"
|
|
3141
|
-
"mode": "uikit"
|
|
3398
|
+
"description": "Gradient colors Wins over `background` when both are declared on the same view; see attribute_semantics.json -> backgroundFill.",
|
|
3399
|
+
"platform": "swift"
|
|
3142
3400
|
},
|
|
3143
3401
|
"gradientDirection": {
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
|
|
3402
|
+
"type": "string",
|
|
3403
|
+
"enum": [
|
|
3404
|
+
"Vertical",
|
|
3405
|
+
"Horizontal",
|
|
3406
|
+
"Oblique",
|
|
3407
|
+
"LeftToRight",
|
|
3408
|
+
"TopToBottom",
|
|
3409
|
+
"Diagonal",
|
|
3410
|
+
"RightToLeft",
|
|
3411
|
+
"BottomToTop"
|
|
3412
|
+
],
|
|
3413
|
+
"valueAliases": {
|
|
3414
|
+
"LeftToRight": "Horizontal",
|
|
3415
|
+
"TopToBottom": "Vertical",
|
|
3416
|
+
"Diagonal": "Oblique"
|
|
3417
|
+
},
|
|
3418
|
+
"default": "Vertical",
|
|
3419
|
+
"description": "Gradient direction. Canon copied from GradientView.gradientDirection, which declared the enum for the same concept while this spelling stayed a bare string. Vertical is the fallback on all three. CASE MATTERS on ios: sjui matches 'Horizontal'/'Oblique' literally (modifier_helper.rb:16) without downcasing, while Compose and web downcase — so the capitalised spellings are canonical and the aliases normalise to them before any converter sees the value. RightToLeft and BottomToTop are declared without an alias on purpose: they are reversed directions web implements (gradient_view_converter.rb:88,90) and the other two have no equivalent, so folding them into Horizontal/Vertical would silently reverse the gradient rather than preserve it.",
|
|
3420
|
+
"platform": "swift"
|
|
3421
|
+
},
|
|
3149
3422
|
"locations": {
|
|
3150
3423
|
"type": "array",
|
|
3151
3424
|
"description": "Gradient color stop locations",
|
|
@@ -3154,7 +3427,7 @@
|
|
|
3154
3427
|
},
|
|
3155
3428
|
"safeAreaInsetPositions": {
|
|
3156
3429
|
"type": "array",
|
|
3157
|
-
"description": "
|
|
3430
|
+
"description": "Which edges reserve the safe area. Declared here as well as on SafeAreaView on purpose: SafeAreaView is its own definition section and does not inherit View's, and every platform honours the attribute on a PLAIN view too (sjui base_view_converter.rb#apply_safe_area_insets_to_bag runs for every component; rjui view_converter.rb#safe_area_edges emits env(safe-area-inset-*) padding). The two declarations are the same concept reaching two routing paths, not a duplicate.",
|
|
3158
3431
|
"items": {
|
|
3159
3432
|
"type": "string",
|
|
3160
3433
|
"enum": [
|
|
@@ -3216,15 +3489,11 @@
|
|
|
3216
3489
|
"_comment": "Sparse by design, not an alias: only the Kotlin dynamic runtime dispatches CircleView (DynamicCircleViewComponent, CircleShape clip) - P18 audit 2026-08-01. Everything it renders beyond child/children comes from common. component_metadata.json carries the per-platform truth.",
|
|
3217
3490
|
"child": {
|
|
3218
3491
|
"type": "array",
|
|
3219
|
-
"description": "Child component(s)"
|
|
3220
|
-
"platform": "swift",
|
|
3221
|
-
"mode": "uikit"
|
|
3492
|
+
"description": "Child component(s)"
|
|
3222
3493
|
},
|
|
3223
3494
|
"children": {
|
|
3224
3495
|
"type": "array",
|
|
3225
|
-
"description": "Child components (alias for child)"
|
|
3226
|
-
"platform": "swift",
|
|
3227
|
-
"mode": "uikit"
|
|
3496
|
+
"description": "Child components (alias for child)"
|
|
3228
3497
|
}
|
|
3229
3498
|
},
|
|
3230
3499
|
"ScrollView": {
|
|
@@ -3388,6 +3657,19 @@
|
|
|
3388
3657
|
],
|
|
3389
3658
|
"description": "Scroll behavior animation",
|
|
3390
3659
|
"platform": "react"
|
|
3660
|
+
},
|
|
3661
|
+
"horizontalScroll": {
|
|
3662
|
+
"type": "boolean",
|
|
3663
|
+
"description": "Enable horizontal scroll. Declared from the implementation, which already read it: sjui scrollview_converter.rb:39 (plan 51-E)."
|
|
3664
|
+
},
|
|
3665
|
+
"defaultScrollAnchor": {
|
|
3666
|
+
"type": "string",
|
|
3667
|
+
"enum": [
|
|
3668
|
+
"top",
|
|
3669
|
+
"center",
|
|
3670
|
+
"bottom"
|
|
3671
|
+
],
|
|
3672
|
+
"description": "Initial scroll position anchor. Sets where the scroll view starts. Declared from the implementation, which already read it: sjui scrollview_converter.rb:207-215. Scope is deliberately all three platforms: the anchor is a portable concept and the declaration says an attribute EXISTS, not which face has caught up — the coverage ledger carries the android and web gaps. The \"(iOS 17+)\" note this description was copied with belonged to Collection's ios implementation, not to the contract, and has been dropped here (plan 51-E, raised by C)."
|
|
3391
3673
|
}
|
|
3392
3674
|
},
|
|
3393
3675
|
"Collection": {
|
|
@@ -3434,7 +3716,10 @@
|
|
|
3434
3716
|
},
|
|
3435
3717
|
"lineSpacing": {
|
|
3436
3718
|
"type": "number",
|
|
3437
|
-
"description": "Spacing between rows"
|
|
3719
|
+
"description": "Spacing between rows. `sectionSpacing` folds here (sjui collection_converter.rb:799,960 read `sectionSpacing || lineSpacing || 8`).",
|
|
3720
|
+
"aliases": [
|
|
3721
|
+
"sectionSpacing"
|
|
3722
|
+
]
|
|
3438
3723
|
},
|
|
3439
3724
|
"horizontalScroll": {
|
|
3440
3725
|
"type": "boolean",
|
|
@@ -3579,7 +3864,7 @@
|
|
|
3579
3864
|
},
|
|
3580
3865
|
"scrollTo": {
|
|
3581
3866
|
"type": "binding",
|
|
3582
|
-
"description": "PassthroughSubject<Int, Never> for
|
|
3867
|
+
"description": "Binding that requests a programmatic scroll. The declared DATA CLASS is a plain value — `String` when cellIdProperty is set (scroll to that cell id), `Int` otherwise (scroll to that index). It is deliberately NOT `PassthroughSubject<Int, Never>`, which this description used to prescribe: PassthroughSubject is a Combine type, and naming a Swift transport in the cross-platform SSoT is what made consumers write it into their data section, where kjui's map_to_kotlin_type passes unknown classes through verbatim and the Kotlin build dies on it. How the request is delivered is each platform's own business — iOS wraps the value in a publisher so a repeated send re-scrolls, Compose reads the String directly, web keys a useEffect on it. STATUS 2026-08-05, after B landed the derivation (jsonui-cli 8c41e3e): the CODEGEN side of all three platforms now takes the plain value — sjui emits `.onChange(of: data.<prop>)` with no publisher and no throttle, Compose keys a LaunchedEffect on it, web a useEffect. The remaining gap is the SwiftUI DYNAMIC renderer: CollectionConverter.swift:127 still resolves the binding as `data[propName] as? PassthroughSubject<Int, Never>` and gets nil for a plain value, so the scroll silently never fires there (it does not crash, it does nothing). Consequence for fixtures: a Collection.scrollTo fixture is now declarable and no longer kills the Kotlin build, and Collection.scrollAnchor is measurable on the codegen path — but ios codegen and ios dynamic will disagree until the dynamic resolver accepts the value, so expect a parity finding there rather than a render failure. Owner of the remainder: the SwiftJsonUI dynamic lane. Note also that the vendored CollectionAttributes.swift still carries the old publisher wording in its doc comment; it is generated from this description and will pick the correction up at the next re-vendor."
|
|
3583
3868
|
},
|
|
3584
3869
|
"scrollAnchor": {
|
|
3585
3870
|
"type": "string",
|
|
@@ -3588,7 +3873,8 @@
|
|
|
3588
3873
|
"center",
|
|
3589
3874
|
"bottom"
|
|
3590
3875
|
],
|
|
3591
|
-
"
|
|
3876
|
+
"default": "bottom",
|
|
3877
|
+
"description": "Anchor point for the scrollTo target. Measured 2026-08-05: ios (sjui collection_converter.rb:1138), web (rjui build_command.rb:768) and the Compose GRID path (kjui collection_component.rb:313) all fall back to bottom, so bottom is the declared default. The Compose LIST path emits no anchor offset unless the attribute is explicitly declared, which lands the target at top - that is a divergence in that one path, not a second default."
|
|
3592
3878
|
},
|
|
3593
3879
|
"defaultScrollAnchor": {
|
|
3594
3880
|
"type": "string",
|
|
@@ -3624,17 +3910,16 @@
|
|
|
3624
3910
|
"description": "Enable/disable scrolling (binding supported)"
|
|
3625
3911
|
},
|
|
3626
3912
|
"onItemAppear": {
|
|
3627
|
-
"type":
|
|
3628
|
-
|
|
3913
|
+
"type": [
|
|
3914
|
+
"string",
|
|
3915
|
+
"binding"
|
|
3916
|
+
],
|
|
3917
|
+
"description": "Called with the cell index (Int) when a cell appears on screen. Use for pagination by checking index against total count in ViewModel. Declared `binding` because that is what a layout actually carries: the author writes `@{handlerName}`, a STRING, and every reader matches it as one (kjui collection_component.rb:364 `json_data['onItemAppear'].match(/@\\{([^}]+)\\}/)`, and the binding validators infer `((Int) -> Unit)?` from that spelling). It was `type: \"callback\"` — the only callback-typed attribute in the whole SSoT — and attr-codegen skips that type as \"function-valued, not extractable from JSON\". True of a function; not true of the `@{...}` string a JSON layout can hold, so the attribute had no row in any generated table and no platform could read it typed (2026-08-05, plan 49-E, raised by A)."
|
|
3629
3918
|
},
|
|
3630
3919
|
"currentPage": {
|
|
3631
3920
|
"type": "binding",
|
|
3632
3921
|
"description": "Current page index for paging collections (binding supported)"
|
|
3633
3922
|
},
|
|
3634
|
-
"onPageChanged": {
|
|
3635
|
-
"type": "callback",
|
|
3636
|
-
"description": "Called with the new page index (Int) when the user swipes to a different page"
|
|
3637
|
-
},
|
|
3638
3923
|
"containerInset": {
|
|
3639
3924
|
"type": "array",
|
|
3640
3925
|
"description": "Container-level insets applied outside of individual cells.",
|
|
@@ -3657,6 +3942,29 @@
|
|
|
3657
3942
|
"onValueChanged",
|
|
3658
3943
|
"onPageChanged"
|
|
3659
3944
|
]
|
|
3945
|
+
},
|
|
3946
|
+
"cellWidth": {
|
|
3947
|
+
"type": "number",
|
|
3948
|
+
"description": "Fixed width for every cell, in pt / dp / px. Applied to the cell view AFTER it is built, so it overrides whatever width the cell layout asked for; leave it out to let each cell size itself. Declared from the implementation, which already read it: sjui collection_converter.rb:256,282,315,650 (plan 51-E)."
|
|
3949
|
+
},
|
|
3950
|
+
"cellHeight": {
|
|
3951
|
+
"type": "number",
|
|
3952
|
+
"description": "Fixed height for every cell, in pt / dp / px. Applied to the cell view AFTER it is built, so it overrides whatever height the cell layout asked for; leave it out to let each cell size itself. Declared from the implementation, which already read it: sjui collection_converter.rb:260,286,318,402 (plan 51-E)."
|
|
3953
|
+
},
|
|
3954
|
+
"hideSeparator": {
|
|
3955
|
+
"type": "boolean",
|
|
3956
|
+
"description": "Hide the row separators a list draws between cells. A NO-OP where the container draws no separators (a grid-shaped Collection has none) — that is the contract, not an unimplemented gap, and it does not license switching the container to a List. No CODEGEN face reads it, so the coverage row is runtime-only. Full ruling in attribute_semantics.json -> collectionSeparators."
|
|
3957
|
+
},
|
|
3958
|
+
"listStyle": {
|
|
3959
|
+
"type": "string",
|
|
3960
|
+
"enum": [
|
|
3961
|
+
"plain",
|
|
3962
|
+
"grouped",
|
|
3963
|
+
"insetGrouped",
|
|
3964
|
+
"sidebar"
|
|
3965
|
+
],
|
|
3966
|
+
"default": "plain",
|
|
3967
|
+
"description": "Which list chrome the collection is drawn with. Enumerated from the only implementation that reads it (SwiftJsonUI TableConverter.applyListStyle); an unrecognised value falls back to plain. ORTHOGONAL to hideSeparator — that one hides the separators, this one picks the chrome, and neither overrides the other. No CODEGEN face reads it, so the coverage row is runtime-only: sjui collection_converter.rb:213 hardcodes PlainListStyle instead. Full ruling in attribute_semantics.json -> collectionSeparators."
|
|
3660
3968
|
}
|
|
3661
3969
|
},
|
|
3662
3970
|
"Radio": {
|
|
@@ -3698,16 +4006,15 @@
|
|
|
3698
4006
|
"selected_icon"
|
|
3699
4007
|
]
|
|
3700
4008
|
},
|
|
3701
|
-
"selected_icon": {
|
|
3702
|
-
"type": "string",
|
|
3703
|
-
"description": "Selected icon name (underscore alias)"
|
|
3704
|
-
},
|
|
3705
4009
|
"checked": {
|
|
3706
4010
|
"type": [
|
|
3707
4011
|
"boolean",
|
|
3708
4012
|
"binding"
|
|
3709
4013
|
],
|
|
3710
|
-
"description": "
|
|
4014
|
+
"description": "Seeds the group's INITIAL selection — it is not the live state, and it is not two-way. The state a radio group carries is `selectedValue`; `checked` only says which option starts selected when nothing else has said. Precedence, and all three platforms implement it in this order: a BOUND `selectedValue` wins outright (the group's own two-way state), then a LITERAL `selectedValue` (a group-level statement naming the starting option), then this option's `checked`. So a radio group that binds selectedValue ignores `checked` entirely, which is what stops a seed from freezing a group that the user can no longer change. The bound form of `checked` seeds the glyph rather than the state, since a property initialiser cannot read the data map: it selects only while the group has made no choice yet (sjui radio_converter.rb:88-103, and the same rule in RadioConverter.swift). CONTRAST with CheckBox.checked and Switch.checked, which look identical and are not: those ARE the control's state and carry binding_direction two-way. A radio has no state of its own — the group does. Declared 2026-08-05 (plan 49-E) from the implementations; the previous description said only \"Initial checked state\", which was true and told nobody what happens when both are declared. `isOn` folds here (sjui radio_converter.rb:88,102 read both the literal and the bound form as `checked || isOn`).",
|
|
4015
|
+
"aliases": [
|
|
4016
|
+
"isOn"
|
|
4017
|
+
]
|
|
3711
4018
|
},
|
|
3712
4019
|
"value": {
|
|
3713
4020
|
"type": "any",
|
|
@@ -3783,6 +4090,13 @@
|
|
|
3783
4090
|
"onValueChange": {
|
|
3784
4091
|
"type": "binding",
|
|
3785
4092
|
"description": "Value change handler - binding only (@{functionName})"
|
|
4093
|
+
},
|
|
4094
|
+
"items": {
|
|
4095
|
+
"type": [
|
|
4096
|
+
"array",
|
|
4097
|
+
"binding"
|
|
4098
|
+
],
|
|
4099
|
+
"description": "List of items for normal picker (can be template variable). Declared from the implementation, which already read it: sjui radio_converter.rb:13 — the option list a radio GROUP renders; with it the converter emits a group, without it a single radio (plan 51-E)."
|
|
3786
4100
|
}
|
|
3787
4101
|
},
|
|
3788
4102
|
"CheckBox": {
|
|
@@ -3882,14 +4196,22 @@
|
|
|
3882
4196
|
},
|
|
3883
4197
|
"onValueChange": {
|
|
3884
4198
|
"type": "binding",
|
|
3885
|
-
"description": "Value change handler - binding only (@{functionName})"
|
|
4199
|
+
"description": "Value change handler - binding only (@{functionName}). Legacy handler spellings fold here (sjui checkbox_converter.rb:122 reads `onValueChange || onClick || action || onValueChanged`; `onClick` stays common).",
|
|
4200
|
+
"aliases": [
|
|
4201
|
+
"action",
|
|
4202
|
+
"onValueChanged"
|
|
4203
|
+
]
|
|
3886
4204
|
},
|
|
3887
4205
|
"checkedColor": {
|
|
3888
4206
|
"type": "color",
|
|
3889
|
-
"description": "Color when checked.",
|
|
4207
|
+
"description": "Color when checked. Legacy accent spellings fold here (sjui checkbox_converter.rb:98 and kjui checkbox_component.rb:211 both read the same four spellings for this one colour). `tintColor` is deliberately NOT in the alias list: it is already declared on `common`, and an alias that is also a declared row is a silent no-op (test_no_alias_is_cancelled_by_a_declaration_of_its_own_name). On a CheckBox the common tint IS the checked colour - that is what both converters implement - so it needs no alias row. Declaring the other two also settles a live divergence: ios reads `checkedColor` first, android reads `checkColor` first, so a layout setting both drew two different colours until the normalizer began folding them (plan 51-E).",
|
|
3890
4208
|
"platform": [
|
|
3891
4209
|
"swift",
|
|
3892
4210
|
"kotlin"
|
|
4211
|
+
],
|
|
4212
|
+
"aliases": [
|
|
4213
|
+
"checkColor",
|
|
4214
|
+
"onTintColor"
|
|
3893
4215
|
]
|
|
3894
4216
|
},
|
|
3895
4217
|
"uncheckedColor": {
|
|
@@ -3915,6 +4237,16 @@
|
|
|
3915
4237
|
"swift",
|
|
3916
4238
|
"kotlin"
|
|
3917
4239
|
]
|
|
4240
|
+
},
|
|
4241
|
+
"fontWeight": {
|
|
4242
|
+
"type": [
|
|
4243
|
+
"string",
|
|
4244
|
+
"number"
|
|
4245
|
+
],
|
|
4246
|
+
"description": "Font weight (e.g., 'bold', 'semibold', '500', 600). Canonical name matches Label and Button; the legacy `fontStyle` spelling folds here. Declared from the implementation, which already read it: sjui checkbox_converter.rb:74-76, which reads `fontStyle` and emits `fontWeight:` (plan 51-E).",
|
|
4247
|
+
"aliases": [
|
|
4248
|
+
"fontStyle"
|
|
4249
|
+
]
|
|
3918
4250
|
}
|
|
3919
4251
|
},
|
|
3920
4252
|
"Check": {
|
|
@@ -3922,6 +4254,18 @@
|
|
|
3922
4254
|
"_comment": "Component alias of CheckBox. Resolved by the L1 normalizer type rewrite and by every validator/codegen consumer - do not add attribute copies here."
|
|
3923
4255
|
},
|
|
3924
4256
|
"Indicator": {
|
|
4257
|
+
"animating": {
|
|
4258
|
+
"type": [
|
|
4259
|
+
"boolean",
|
|
4260
|
+
"binding"
|
|
4261
|
+
],
|
|
4262
|
+
"default": true,
|
|
4263
|
+
"description": "Whether the indicator is spinning. Defaults to true: an Indicator with nothing declared animates. `false` stops it, and hidesWhenStopped then decides whether the stopped indicator keeps its space or collapses out of the layout \u2014 which is why hidesWhenStopped is only ever read on this branch (sjui indicator_converter.rb:23, kjui indicator_component.rb:13).",
|
|
4264
|
+
"platform": [
|
|
4265
|
+
"swift",
|
|
4266
|
+
"kotlin"
|
|
4267
|
+
]
|
|
4268
|
+
},
|
|
3925
4269
|
"indicatorStyle": {
|
|
3926
4270
|
"type": "string",
|
|
3927
4271
|
"enum": [
|
|
@@ -3937,13 +4281,16 @@
|
|
|
3937
4281
|
"string",
|
|
3938
4282
|
"binding"
|
|
3939
4283
|
],
|
|
3940
|
-
"description": "Indicator color - hex string or color name from colors.json (binding supported)",
|
|
4284
|
+
"description": "Indicator color - hex string or color name from colors.json (binding supported). `tint` folds here (sjui indicator_converter.rb:77 reads `color || tintColor || tint`).",
|
|
3941
4285
|
"platform": "swift",
|
|
3942
|
-
"mode": "swiftui"
|
|
4286
|
+
"mode": "swiftui",
|
|
4287
|
+
"aliases": [
|
|
4288
|
+
"tint"
|
|
4289
|
+
]
|
|
3943
4290
|
},
|
|
3944
4291
|
"hidesWhenStopped": {
|
|
3945
4292
|
"type": "boolean",
|
|
3946
|
-
"description": "Hide when stopped",
|
|
4293
|
+
"description": "Hide when stopped. Decides SPACE: `true` collapses the stopped indicator out of the layout, `false` keeps it drawn AND laid out. Full ruling in attribute_semantics.json -> indicatorStopped.",
|
|
3947
4294
|
"platform": "swift",
|
|
3948
4295
|
"mode": "swiftui"
|
|
3949
4296
|
}
|
|
@@ -3951,7 +4298,10 @@
|
|
|
3951
4298
|
"GradientView": {
|
|
3952
4299
|
"gradient": {
|
|
3953
4300
|
"type": "array",
|
|
3954
|
-
"description": "Gradient colors"
|
|
4301
|
+
"description": "Gradient colors. `colors` folds here (sjui gradient_view_converter.rb:52,66 read `colors || gradient`). On GradientView the gradient is the component's own fill, so the backgroundFill precedence question does not arise.",
|
|
4302
|
+
"aliases": [
|
|
4303
|
+
"colors"
|
|
4304
|
+
]
|
|
3955
4305
|
},
|
|
3956
4306
|
"gradientDirection": {
|
|
3957
4307
|
"type": "string",
|
|
@@ -3965,6 +4315,54 @@
|
|
|
3965
4315
|
"locations": {
|
|
3966
4316
|
"type": "array",
|
|
3967
4317
|
"description": "Color stop locations (0.0-1.0)"
|
|
4318
|
+
},
|
|
4319
|
+
"child": {
|
|
4320
|
+
"type": "array",
|
|
4321
|
+
"description": "Child component(s). Declared from the implementation, which already read it: sjui gradient_view_converter.rb:16 (plan 51-E)."
|
|
4322
|
+
},
|
|
4323
|
+
"children": {
|
|
4324
|
+
"type": "array",
|
|
4325
|
+
"description": "Child components (alias for child). Declared from the implementation, which already read it: sjui gradient_view_converter.rb:16 (child || children) (plan 51-E)."
|
|
4326
|
+
},
|
|
4327
|
+
"startPoint": {
|
|
4328
|
+
"type": [
|
|
4329
|
+
"array",
|
|
4330
|
+
"object"
|
|
4331
|
+
],
|
|
4332
|
+
"description": "Unit coordinates in the view's own box for where the gradient starts: [x, y] or {\"x\": x, \"y\": y}, with 0 = leading/top, 0.5 = centre/middle, 1 = trailing/bottom. THREE faces read this key three incompatible ways today: sjui gradient_view_converter.rb:107-109 wants an OBJECT ({x, y}), rjui gradient_view_converter.rb:72-73 destructures an ARRAY ([x, y]), and kjui gradientview_component.rb:58-59 expects a STRING edge name ('top'). The two coordinate forms are declared because both are real coordinate spellings of the same thing; the android string form is NOT declared - it is `gradientDirection` semantics written under the wrong key, and is filed as a defect rather than blessed here. Declaring BOTH startPoint and endPoint replaces gradientDirection entirely; declaring only one is ignored and gradientDirection still decides (plan 51-E).",
|
|
4333
|
+
"items": {
|
|
4334
|
+
"type": "number"
|
|
4335
|
+
},
|
|
4336
|
+
"properties": {
|
|
4337
|
+
"x": {
|
|
4338
|
+
"type": "number",
|
|
4339
|
+
"description": "0 = leading, 0.5 = centre, 1 = trailing"
|
|
4340
|
+
},
|
|
4341
|
+
"y": {
|
|
4342
|
+
"type": "number",
|
|
4343
|
+
"description": "0 = top, 0.5 = middle, 1 = bottom"
|
|
4344
|
+
}
|
|
4345
|
+
}
|
|
4346
|
+
},
|
|
4347
|
+
"endPoint": {
|
|
4348
|
+
"type": [
|
|
4349
|
+
"array",
|
|
4350
|
+
"object"
|
|
4351
|
+
],
|
|
4352
|
+
"description": "Unit coordinates in the view's own box for where the gradient ends: [x, y] or {\"x\": x, \"y\": y}, with 0 = leading/top, 0.5 = centre/middle, 1 = trailing/bottom. THREE faces read this key three incompatible ways today: sjui gradient_view_converter.rb:107-109 wants an OBJECT ({x, y}), rjui gradient_view_converter.rb:72-73 destructures an ARRAY ([x, y]), and kjui gradientview_component.rb:58-59 expects a STRING edge name ('top'). The two coordinate forms are declared because both are real coordinate spellings of the same thing; the android string form is NOT declared - it is `gradientDirection` semantics written under the wrong key, and is filed as a defect rather than blessed here. Declaring BOTH startPoint and endPoint replaces gradientDirection entirely; declaring only one is ignored and gradientDirection still decides (plan 51-E).",
|
|
4353
|
+
"items": {
|
|
4354
|
+
"type": "number"
|
|
4355
|
+
},
|
|
4356
|
+
"properties": {
|
|
4357
|
+
"x": {
|
|
4358
|
+
"type": "number",
|
|
4359
|
+
"description": "0 = leading, 0.5 = centre, 1 = trailing"
|
|
4360
|
+
},
|
|
4361
|
+
"y": {
|
|
4362
|
+
"type": "number",
|
|
4363
|
+
"description": "0 = top, 0.5 = middle, 1 = bottom"
|
|
4364
|
+
}
|
|
4365
|
+
}
|
|
3968
4366
|
}
|
|
3969
4367
|
},
|
|
3970
4368
|
"Blur": {
|
|
@@ -3984,6 +4382,14 @@
|
|
|
3984
4382
|
"kotlin",
|
|
3985
4383
|
"react"
|
|
3986
4384
|
]
|
|
4385
|
+
},
|
|
4386
|
+
"child": {
|
|
4387
|
+
"type": "array",
|
|
4388
|
+
"description": "Child component(s). Declared from the implementation, which already read it: sjui blur_converter.rb:16 (plan 51-E)."
|
|
4389
|
+
},
|
|
4390
|
+
"children": {
|
|
4391
|
+
"type": "array",
|
|
4392
|
+
"description": "Child components (alias for child). Declared from the implementation, which already read it: sjui blur_converter.rb:16 (child || children) (plan 51-E)."
|
|
3987
4393
|
}
|
|
3988
4394
|
},
|
|
3989
4395
|
"IconLabel": {
|
|
@@ -3999,7 +4405,10 @@
|
|
|
3999
4405
|
"boolean",
|
|
4000
4406
|
"binding"
|
|
4001
4407
|
],
|
|
4002
|
-
"description": "Selected state (binding supported). Chooses icon_on over icon_off and selectedFontColor over fontColor, so every platform declaring those needs this too."
|
|
4408
|
+
"description": "Selected state (binding supported). Chooses icon_on over icon_off and selectedFontColor over fontColor, so every platform declaring those needs this too. `isOn` folds here — the legacy spelling for the same state. IconLabelConverter.swift:145-151 says so in as many words (\"Pre-SSoT layouts that spelled it `isOn` keep working\") and reads it out of rawData because no typed slot existed; sjui icon_label_converter.rb:130 reads the canonical `selected` (plan 51-E).",
|
|
4409
|
+
"aliases": [
|
|
4410
|
+
"isOn"
|
|
4411
|
+
]
|
|
4003
4412
|
},
|
|
4004
4413
|
"font": {
|
|
4005
4414
|
"type": "string",
|
|
@@ -4045,6 +4454,13 @@
|
|
|
4045
4454
|
"iconMargin": {
|
|
4046
4455
|
"type": "number",
|
|
4047
4456
|
"description": "Icon-text spacing"
|
|
4457
|
+
},
|
|
4458
|
+
"iconSize": {
|
|
4459
|
+
"type": [
|
|
4460
|
+
"number",
|
|
4461
|
+
"array"
|
|
4462
|
+
],
|
|
4463
|
+
"description": "Icon size. A number sizes both edges; a two-element [width, height] sizes them separately (rjui icon_label_converter.rb:130-138 reads both, and its spec covers both). NOT the same shape as CheckBox.iconSize, which is a square glyph and takes a number only. sjui icon_label_converter.rb:50-51 interpolates the value straight into `iconSize:`, so the array form is web-only today — declared here because the attribute's value space is a property of the attribute, not of whichever face lags (plan 51-E)."
|
|
4048
4464
|
}
|
|
4049
4465
|
},
|
|
4050
4466
|
"Web": {
|
|
@@ -4070,8 +4486,8 @@
|
|
|
4070
4486
|
"platform": "swift"
|
|
4071
4487
|
},
|
|
4072
4488
|
"sandbox": {
|
|
4073
|
-
"type": "
|
|
4074
|
-
"description": "Iframe sandbox attribute",
|
|
4489
|
+
"type": "boolean",
|
|
4490
|
+
"description": "Iframe sandboxing kill-switch. `false` emits no sandbox attribute at all; otherwise the permission list is built from the other Web attributes (javaScriptEnabled, javaScriptCanOpenWindowsAutomatically, allowPopupsToEscapeSandbox, allowModals, ...) rather than from a value written here.",
|
|
4075
4491
|
"platform": "react"
|
|
4076
4492
|
},
|
|
4077
4493
|
"allow": {
|
|
@@ -4091,7 +4507,10 @@
|
|
|
4091
4507
|
},
|
|
4092
4508
|
"safeAreaInsetPositions": {
|
|
4093
4509
|
"type": "array",
|
|
4094
|
-
"description": "Safe area edges",
|
|
4510
|
+
"description": "Safe area edges. `edges` is an accepted alias spelling: the Compose SafeAreaView builder reads it (kjui compose_builder.rb:722 `json_data['edges'] || json_data['safeAreaInsetPositions']`) while no declaration named it, so iOS and web silently ignored a layout that used it. Declaring the alias normalizes it to the canonical spelling and makes it reach all three platforms.",
|
|
4511
|
+
"aliases": [
|
|
4512
|
+
"edges"
|
|
4513
|
+
],
|
|
4095
4514
|
"items": {
|
|
4096
4515
|
"type": "string",
|
|
4097
4516
|
"enum": [
|
|
@@ -4111,6 +4530,34 @@
|
|
|
4111
4530
|
"children": {
|
|
4112
4531
|
"type": "array",
|
|
4113
4532
|
"description": "Child components (alias for child)"
|
|
4533
|
+
},
|
|
4534
|
+
"direction": {
|
|
4535
|
+
"type": "string",
|
|
4536
|
+
"enum": [
|
|
4537
|
+
"topToBottom",
|
|
4538
|
+
"bottomToTop",
|
|
4539
|
+
"leftToRight",
|
|
4540
|
+
"rightToLeft",
|
|
4541
|
+
"none"
|
|
4542
|
+
],
|
|
4543
|
+
"description": "Layout direction. Declared from the implementation, which already read it: sjui view_converter.rb:140 (SafeAreaView routes through the View converter) (plan 51-E)."
|
|
4544
|
+
},
|
|
4545
|
+
"gradient": {
|
|
4546
|
+
"type": "array",
|
|
4547
|
+
"description": "Gradient colors. Declared from the implementation, which already read it: sjui view_converter.rb:456 (plan 51-E).",
|
|
4548
|
+
"platform": "swift"
|
|
4549
|
+
},
|
|
4550
|
+
"spacing": {
|
|
4551
|
+
"type": [
|
|
4552
|
+
"number",
|
|
4553
|
+
"binding"
|
|
4554
|
+
],
|
|
4555
|
+
"description": "Space between children (binding supported). Declared from the implementation, which already read it: sjui view_converter.rb:181 (plan 51-E).",
|
|
4556
|
+
"mode": [
|
|
4557
|
+
"swiftui",
|
|
4558
|
+
"compose",
|
|
4559
|
+
"react"
|
|
4560
|
+
]
|
|
4114
4561
|
}
|
|
4115
4562
|
},
|
|
4116
4563
|
"TabView": {
|
|
@@ -4195,10 +4642,6 @@
|
|
|
4195
4642
|
"default": true,
|
|
4196
4643
|
"description": "Whether to show tab labels (default: true)"
|
|
4197
4644
|
},
|
|
4198
|
-
"onTabChange": {
|
|
4199
|
-
"type": "binding",
|
|
4200
|
-
"description": "Tab change handler - binding only (@{functionName})"
|
|
4201
|
-
},
|
|
4202
4645
|
"onValueChange": {
|
|
4203
4646
|
"type": [
|
|
4204
4647
|
"string",
|