elit 3.6.9 → 3.7.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.
Files changed (50) hide show
  1. package/Cargo.lock +380 -449
  2. package/Cargo.toml +3 -3
  3. package/dist/build.cjs +1 -1
  4. package/dist/build.d.ts +1 -1
  5. package/dist/build.js +14 -10
  6. package/dist/build.mjs +1 -1
  7. package/dist/cli.cjs +1607 -6431
  8. package/dist/cli.d.ts +10 -3
  9. package/dist/cli.mjs +1611 -6435
  10. package/dist/config.cjs +7 -2
  11. package/dist/config.d.ts +4 -4
  12. package/dist/config.js +20 -11
  13. package/dist/config.mjs +7 -2
  14. package/dist/{contracts-D7KIS-TK.d.ts → contracts-Av9yuqDM.d.ts} +11 -4
  15. package/dist/dev-build.d.ts +2 -1
  16. package/dist/dev-build.js +13 -9
  17. package/dist/https.cjs +7 -2
  18. package/dist/https.js +7 -2
  19. package/dist/https.mjs +7 -2
  20. package/dist/index.cjs +340 -52
  21. package/dist/index.d.ts +1 -1
  22. package/dist/index.js +340 -52
  23. package/dist/index.mjs +340 -52
  24. package/dist/native.cjs +340 -52
  25. package/dist/native.js +340 -52
  26. package/dist/native.mjs +340 -52
  27. package/dist/pm.cjs +7 -2
  28. package/dist/pm.d.ts +3 -3
  29. package/dist/pm.js +20 -11
  30. package/dist/pm.mjs +7 -2
  31. package/dist/preview-build.d.ts +2 -2
  32. package/dist/preview-build.js +13 -9
  33. package/dist/server.cjs +861 -5998
  34. package/dist/server.d.ts +3 -2
  35. package/dist/server.js +12178 -4468
  36. package/dist/server.mjs +861 -5998
  37. package/dist/smtp-server.js +514 -44
  38. package/dist/test-runtime.cjs +20 -0
  39. package/dist/test-runtime.js +33 -9
  40. package/dist/test-runtime.mjs +20 -0
  41. package/dist/test.cjs +27 -2
  42. package/dist/test.js +40 -11
  43. package/dist/test.mjs +27 -2
  44. package/dist/{types-BayMVo_k.d.ts → types-CLGrLRTl.d.ts} +8 -2
  45. package/dist/{types-fiLday0L.d.ts → types-CYEpzeEi.d.ts} +10 -0
  46. package/dist/types.d.ts +52 -36
  47. package/dist/wss.cjs +7 -2
  48. package/dist/wss.js +7 -2
  49. package/dist/wss.mjs +7 -2
  50. package/package.json +7 -2
package/dist/index.mjs CHANGED
@@ -8608,8 +8608,12 @@ function buildComposeChunkedRowArguments(style2, modifier, columnGap, styleResol
8608
8608
  }
8609
8609
  return args.join(", ");
8610
8610
  }
8611
- function buildComposeChunkedTrackModifier(baseModifier, row) {
8611
+ function buildComposeChunkedTrackModifier(baseModifier, row, options = {}) {
8612
+ const fillWidth = options.fillWidth ?? true;
8612
8613
  let modifier = baseModifier;
8614
+ if (row.trackWeight !== void 0) {
8615
+ modifier = appendComposeModifierCall(modifier, `weight(${formatFloat(row.trackWeight)}f, fill = true)`);
8616
+ }
8613
8617
  if (row.height !== void 0) {
8614
8618
  modifier = appendComposeModifierCall(modifier, `height(${formatFloat(row.height)}.dp)`);
8615
8619
  } else if (row.minHeight !== void 0 || row.maxHeight !== void 0) {
@@ -8622,7 +8626,7 @@ function buildComposeChunkedTrackModifier(baseModifier, row) {
8622
8626
  }
8623
8627
  modifier = appendComposeModifierCall(modifier, `heightIn(${heightInArgs.join(", ")})`);
8624
8628
  }
8625
- return row.trackWeight !== void 0 ? appendComposeModifierCall(modifier, `weight(${formatFloat(row.trackWeight)}f, fill = true)`) : modifier;
8629
+ return fillWidth ? appendComposeModifierCall(modifier, "fillMaxWidth()") : modifier;
8626
8630
  }
8627
8631
  function buildComposeChunkedColumnArrangement(layout) {
8628
8632
  const contentAlignment = resolveEffectiveChunkedContentAlignment(layout);
@@ -10371,7 +10375,7 @@ function renderComposeChunkedLayout(node, layout, level, context, modifier, hint
10371
10375
  const usesSingleRowGridStackAlignment = layout.kind === "grid" && layout.rows.length === 1 && effectiveContentAlignment !== void 0 && effectiveContentAlignment !== "start";
10372
10376
  if (layout.kind === "grid" && layout.rows.length === 1 && !usesSingleRowGridStackAlignment) {
10373
10377
  const [row] = layout.rows;
10374
- const lines2 = [`${indent4(level)}Row(${buildComposeChunkedRowArguments(style2, buildComposeChunkedTrackModifier(modifier, row), layout.columnGap, context.styleResolveOptions)}) {`];
10378
+ const lines2 = [`${indent4(level)}Row(${buildComposeChunkedRowArguments(style2, buildComposeChunkedTrackModifier(modifier, row, { fillWidth: false }), layout.columnGap, context.styleResolveOptions)}) {`];
10375
10379
  const totalWeight = row.weights ? row.weights.reduce((sum, entry) => sum + (entry ?? 0), 0) : void 0;
10376
10380
  row.items.forEach((child, index) => {
10377
10381
  const weight = row.weights?.[index];
@@ -10403,7 +10407,7 @@ function renderComposeChunkedLayout(node, layout, level, context, modifier, hint
10403
10407
  const lines = [`${indent4(level)}Column(modifier = ${modifier}${outerGap ? `, verticalArrangement = ${outerGap}` : ""}) {`];
10404
10408
  for (const row of layout.rows) {
10405
10409
  const totalWeight = row.weights ? row.weights.reduce((sum, entry) => sum + (entry ?? 0), 0) : void 0;
10406
- lines.push(`${indent4(level + 1)}Row(${buildComposeChunkedRowArguments(style2, buildComposeChunkedTrackModifier("Modifier.fillMaxWidth()", row), layout.columnGap, context.styleResolveOptions)}) {`);
10410
+ lines.push(`${indent4(level + 1)}Row(${buildComposeChunkedRowArguments(style2, buildComposeChunkedTrackModifier("Modifier", row), layout.columnGap, context.styleResolveOptions)}) {`);
10407
10411
  row.items.forEach((child, index) => {
10408
10412
  const weight = row.weights?.[index];
10409
10413
  const columnSize = row.columnSizes?.[index];
@@ -10841,7 +10845,7 @@ function renderComposeContainerNode(node, level, context, hints, modifier, baseL
10841
10845
  }
10842
10846
  const lines = [
10843
10847
  ...baseLines,
10844
- `${indent7(level)}Box {`,
10848
+ `${indent7(level)}Box(modifier = Modifier.matchParentSize()) {`,
10845
10849
  ...renderComposeContainerBody(flowNode, level + 1, context, modifier, hints, renderComposeNode)
10846
10850
  ];
10847
10851
  absoluteChildren.forEach((child) => {
@@ -10858,6 +10862,18 @@ function renderComposeContainerNode(node, level, context, hints, modifier, baseL
10858
10862
  lines.push(`${indent7(level)}}`);
10859
10863
  return lines;
10860
10864
  }
10865
+ function renderComposeUnsupportedFallback(node, level, context, modifier, baseLines, label2) {
10866
+ context.helperFlags.add("unsupportedPlaceholder");
10867
+ const sourceTag = node.sourceTag ?? node.component.toLowerCase();
10868
+ const args = [`label = ${quoteKotlinString(label2)}`, `sourceTag = ${quoteKotlinString(sourceTag)}`];
10869
+ if (modifier !== "Modifier") {
10870
+ args.push(`modifier = ${modifier}`);
10871
+ }
10872
+ return [
10873
+ ...baseLines,
10874
+ `${indent7(level)}ElitUnsupported(${args.join(", ")})`
10875
+ ];
10876
+ }
10861
10877
  function renderComposeNode(node, level, context, hints = {}) {
10862
10878
  if (node.kind === "text") {
10863
10879
  return renderTextComposable(node, level, context);
@@ -10930,8 +10946,11 @@ function renderComposeNode(node, level, context, hints = {}) {
10930
10946
  ];
10931
10947
  }
10932
10948
  if (node.component === "WebView") {
10949
+ const source2 = resolveNativeSurfaceSource(node);
10950
+ if (!source2) {
10951
+ return renderComposeUnsupportedFallback(node, level, context, modifier, baseLines, "WebView");
10952
+ }
10933
10953
  context.helperFlags.add("webViewSurface");
10934
- const source2 = resolveNativeSurfaceSource(node) ?? "";
10935
10954
  const label3 = resolveNativeAccessibilityLabel(node) ?? "Web content";
10936
10955
  return [
10937
10956
  ...baseLines,
@@ -10939,8 +10958,11 @@ function renderComposeNode(node, level, context, hints = {}) {
10939
10958
  ];
10940
10959
  }
10941
10960
  if (node.component === "Media") {
10961
+ const source2 = resolveNativeSurfaceSource(node);
10962
+ if (!source2) {
10963
+ return renderComposeUnsupportedFallback(node, level, context, modifier, baseLines, "Media");
10964
+ }
10942
10965
  context.helperFlags.add("mediaSurface");
10943
- const source2 = resolveNativeSurfaceSource(node) ?? "";
10944
10966
  const label3 = resolveNativeMediaLabel(node);
10945
10967
  const style2 = getStyleObject(node, context.resolvedStyles, context.styleResolveOptions);
10946
10968
  const objectFit = resolveNativeObjectFitStyle(style2);
@@ -10957,19 +10979,44 @@ function renderComposeNode(node, level, context, hints = {}) {
10957
10979
  const poster = resolveNativeVideoPoster(node);
10958
10980
  const controls = shouldNativeShowVideoControls(node);
10959
10981
  const playsInline = shouldNativePlayInline(node);
10982
+ const videoArgs = [
10983
+ `source = ${quoteKotlinString(source2)}`,
10984
+ `label = ${quoteKotlinString(label3)}`,
10985
+ `autoPlay = ${autoPlay ? "true" : "false"}`,
10986
+ `loop = ${loop ? "true" : "false"}`,
10987
+ `muted = ${muted ? "true" : "false"}`,
10988
+ `controls = ${controls ? "true" : "false"}`,
10989
+ `poster = ${poster ? quoteKotlinString(poster) : "null"}`,
10990
+ `playsInline = ${playsInline ? "true" : "false"}`
10991
+ ];
10992
+ if (objectFit !== "cover") {
10993
+ videoArgs.push(`posterFit = ${quoteKotlinString(objectFit)}`);
10994
+ }
10995
+ if (objectPosition !== "center") {
10996
+ videoArgs.push(`posterPosition = ${quoteKotlinString(objectPosition)}`);
10997
+ }
10998
+ videoArgs.push(`modifier = ${modifier}`);
10960
10999
  return [
10961
11000
  ...baseLines,
10962
- `${indent7(level)}ElitVideoSurface(source = ${quoteKotlinString(source2)}, label = ${quoteKotlinString(label3)}, autoPlay = ${autoPlay ? "true" : "false"}, loop = ${loop ? "true" : "false"}, muted = ${muted ? "true" : "false"}, controls = ${controls ? "true" : "false"}, playsInline = ${playsInline ? "true" : "false"}${poster ? `, poster = ${quoteKotlinString(poster)}` : ""}${objectFit !== "cover" ? `, posterFit = ${quoteKotlinString(objectFit)}` : ""}${objectPosition !== "center" ? `, posterPosition = ${quoteKotlinString(objectPosition)}` : ""}, modifier = ${modifier})`
11001
+ `${indent7(level)}ElitVideoSurface(${videoArgs.join(", ")})`
10963
11002
  ];
10964
11003
  }
11004
+ if (node.component === "Math") {
11005
+ return renderComposeUnsupportedFallback(node, level, context, modifier, baseLines, "Math");
11006
+ }
10965
11007
  if (node.component === "Cell") {
10966
11008
  const style2 = getStyleObject(node, context.resolvedStyles, context.styleResolveOptions);
11009
+ const hasExplicitWidth = hasExplicitNativeWidthStyle(style2);
10967
11010
  const cellHints = {
10968
11011
  ...hints,
10969
- ...!hasExplicitNativeWidthStyle(style2) ? { fillWidth: true } : {},
11012
+ ...!hasExplicitWidth ? { fillWidth: true } : {},
10970
11013
  ...!hasExplicitNativeHeightStyle(style2) && hints.fillHeight ? { fillHeight: true } : {}
10971
11014
  };
10972
- return renderComposeContainerNode(node, level, context, cellHints, modifier, baseLines);
11015
+ let cellModifier = modifier;
11016
+ if (hints.parentFlexLayout === "Row" && !hasExplicitWidth) {
11017
+ cellModifier = cellModifier === "Modifier" ? "Modifier.weight(1f, fill = true)" : cellModifier.replace(/^Modifier\./, "Modifier.weight(1f, fill = true).");
11018
+ }
11019
+ return renderComposeContainerNode(node, level, context, cellHints, cellModifier, baseLines);
10973
11020
  }
10974
11021
  if (node.children.length > 0 || node.component === "Screen") {
10975
11022
  return renderComposeContainerNode(node, level, context, hints, modifier, baseLines);
@@ -10986,11 +11033,13 @@ function buildAndroidComposeHelpers(context) {
10986
11033
  if (context.helperFlags.has("bridge")) {
10987
11034
  helpers.push("");
10988
11035
  helpers.push("private object ElitNativeBridge {");
11036
+ helpers.push(" var onAction: ((String, String?, String?) -> Unit)? = null");
11037
+ helpers.push(" var onNavigate: ((String) -> Unit)? = null");
10989
11038
  helpers.push(" fun dispatch(action: String? = null, route: String? = null, payloadJson: String? = null) {");
10990
11039
  helpers.push(' android.util.Log.d("ElitNativeBridge", listOfNotNull(action, route, payloadJson).joinToString(" | "))');
10991
11040
  helpers.push(" }");
10992
11041
  helpers.push("");
10993
- helpers.push(" fun controlEventPayload(event: String, sourceTag: String, inputType: String? = null, value: String? = null, values: List<String>? = null, checked: Boolean? = null, detailJson: String? = null): String {");
11042
+ helpers.push(" fun controlEventPayload(event: String, sourceTag: String, inputType: String? = null, value: String? = null, values: Iterable<String>? = null, checked: Boolean? = null, detailJson: String? = null): String {");
10994
11043
  helpers.push(" val parts = mutableListOf<String>()");
10995
11044
  helpers.push(' parts += ""event":"$event""');
10996
11045
  helpers.push(' parts += ""sourceTag":"$sourceTag""');
@@ -11014,33 +11063,50 @@ function buildAndroidComposeHelpers(context) {
11014
11063
  helpers.push("}");
11015
11064
  }
11016
11065
  if (context.helperFlags.has("backgroundImage") || context.helperFlags.has("imagePlaceholder")) {
11066
+ helpers.push("");
11067
+ helpers.push("private fun elitLoadBackgroundBitmap(view: android.widget.ImageView, source: String, repeatMode: String, backgroundSize: String, backgroundPosition: String) {");
11068
+ helpers.push(" if (source.isBlank()) return");
11069
+ helpers.push(' val tileModeX = if (repeatMode == "repeat-y") android.graphics.Shader.TileMode.CLAMP else android.graphics.Shader.TileMode.REPEAT');
11070
+ helpers.push(' val tileModeY = if (repeatMode == "repeat-x") android.graphics.Shader.TileMode.CLAMP else android.graphics.Shader.TileMode.REPEAT');
11071
+ helpers.push(" view.scaleType = android.widget.ImageView.ScaleType.CENTER_CROP");
11072
+ helpers.push(' if (repeatMode == "no-repeat" || repeatMode == "round") {');
11073
+ helpers.push(" view.setImageURI(android.net.Uri.parse(source))");
11074
+ helpers.push(" } else {");
11075
+ helpers.push(" val bitmap = android.graphics.BitmapFactory.decodeStream(android.net.Uri.parse(source).let { runCatching { view.context.contentResolver.openInputStream(it) }.getOrNull() })");
11076
+ helpers.push(" if (bitmap != null) view.setImageDrawable(android.graphics.drawable.BitmapDrawable(view.resources, bitmap).apply { tileModeX = tileModeX; tileModeY = tileModeY })");
11077
+ helpers.push(" }");
11078
+ helpers.push("}");
11017
11079
  helpers.push("");
11018
11080
  helpers.push("@Composable");
11019
11081
  helpers.push('private fun ElitBackgroundImage(source: String, backgroundSize: String = "cover", backgroundPosition: String = "center", backgroundRepeat: String = "no-repeat", modifier: Modifier = Modifier) {');
11020
11082
  helpers.push(" androidx.compose.ui.viewinterop.AndroidView(");
11021
11083
  helpers.push(" factory = { context -> android.widget.ImageView(context).apply {");
11022
- helpers.push(" scaleType = android.widget.ImageView.ScaleType.CENTER_CROP");
11023
- helpers.push(" if (source.isNotBlank()) setImageURI(android.net.Uri.parse(source))");
11084
+ helpers.push(" elitLoadBackgroundBitmap(this, source, backgroundRepeat, backgroundSize, backgroundPosition)");
11024
11085
  helpers.push(" } },");
11025
11086
  helpers.push(" modifier = modifier,");
11026
11087
  helpers.push(" )");
11027
11088
  helpers.push("}");
11028
11089
  helpers.push("");
11029
11090
  helpers.push("@Composable");
11030
- helpers.push('private fun ElitImageSurface(source: String, label: String, alt: String? = null, modifier: Modifier = Modifier, objectFit: String = "cover", objectPosition: String = "center") {');
11091
+ helpers.push('private fun ElitImageSurface(source: String, label: String, contentDescription: String?, objectFit: String = "cover", objectPosition: String = "center", modifier: Modifier = Modifier) {');
11031
11092
  helpers.push(" if (source.isBlank()) {");
11032
11093
  helpers.push(" Box(modifier = modifier, contentAlignment = Alignment.Center) {");
11033
- helpers.push(" Text(text = alt ?: label)");
11094
+ helpers.push(" Text(text = contentDescription ?: label)");
11034
11095
  helpers.push(" }");
11035
11096
  helpers.push(" return");
11036
11097
  helpers.push(" }");
11037
- helpers.push(" ElitBackgroundImage(source = source, backgroundSize = objectFit, backgroundPosition = objectPosition, modifier = modifier)");
11098
+ helpers.push(" androidx.compose.ui.viewinterop.AndroidView(");
11099
+ helpers.push(" factory = { context -> android.widget.ImageView(context).apply {");
11100
+ helpers.push(' elitLoadBackgroundBitmap(this, source, "no-repeat", objectFit, objectPosition)');
11101
+ helpers.push(" } },");
11102
+ helpers.push(" modifier = modifier,");
11103
+ helpers.push(" )");
11038
11104
  helpers.push("}");
11039
11105
  }
11040
11106
  if (context.helperFlags.has("webViewSurface")) {
11041
11107
  helpers.push("");
11042
11108
  helpers.push("@Composable");
11043
- helpers.push("private fun ElitWebViewSurface(source: String, label: String, modifier: Modifier = Modifier) {");
11109
+ helpers.push("private fun ElitWebViewSurface(source: String, label: String?, modifier: Modifier = Modifier) {");
11044
11110
  helpers.push(" androidx.compose.ui.viewinterop.AndroidView(");
11045
11111
  helpers.push(" factory = { context -> android.webkit.WebView(context).apply {");
11046
11112
  helpers.push(" contentDescription = label");
@@ -11052,18 +11118,58 @@ function buildAndroidComposeHelpers(context) {
11052
11118
  helpers.push("}");
11053
11119
  }
11054
11120
  if (context.helperFlags.has("mediaSurface")) {
11121
+ helpers.push("");
11122
+ helpers.push("private fun elitVideoPosterScaleType(posterFit: String, posterPosition: String): android.widget.ImageView.ScaleType = when (posterFit.trim().lowercase()) {");
11123
+ helpers.push(' "contain", "scale-down" -> when (posterPosition.trim().lowercase()) {');
11124
+ helpers.push(' "top", "leading", "top-leading", "bottom-leading" -> android.widget.ImageView.ScaleType.FIT_START');
11125
+ helpers.push(' "bottom", "trailing", "bottom-trailing" -> android.widget.ImageView.ScaleType.FIT_END');
11126
+ helpers.push(" else -> android.widget.ImageView.ScaleType.FIT_CENTER");
11127
+ helpers.push(" }");
11128
+ helpers.push(" else -> android.widget.ImageView.ScaleType.CENTER_CROP");
11129
+ helpers.push("}");
11055
11130
  helpers.push("");
11056
11131
  helpers.push("@Composable");
11057
- helpers.push('private fun ElitVideoSurface(source: String, label: String, autoPlay: Boolean, loop: Boolean, muted: Boolean, controls: Boolean, playsInline: Boolean, poster: String? = null, posterFit: String = "cover", posterPosition: String = "center", modifier: Modifier = Modifier) {');
11132
+ helpers.push('private fun ElitVideoSurface(source: String, label: String, autoPlay: Boolean, loop: Boolean, muted: Boolean, controls: Boolean, poster: String?, playsInline: Boolean, posterFit: String = "cover", posterPosition: String = "center", modifier: Modifier = Modifier) {');
11133
+ helpers.push(" // Android VideoView already renders inline; playsInline is retained for parity with iOS generation.");
11058
11134
  helpers.push(" Box(modifier = modifier, contentAlignment = Alignment.Center) {");
11059
- helpers.push(' Text(text = if (autoPlay) "Playing $label" else label)');
11135
+ helpers.push(" androidx.compose.ui.viewinterop.AndroidView(");
11136
+ helpers.push(" factory = { context ->");
11137
+ helpers.push(" android.widget.ImageView(context).apply {");
11138
+ helpers.push(" val posterView = this");
11139
+ helpers.push(" posterView.contentDescription = label");
11140
+ helpers.push(" posterView.scaleType = elitVideoPosterScaleType(posterFit, posterPosition)");
11141
+ helpers.push(" if (poster != null) posterView.setImageURI(android.net.Uri.parse(poster))");
11142
+ helpers.push(" }");
11143
+ helpers.push(" },");
11144
+ helpers.push(" )");
11145
+ helpers.push(" if (controls) {");
11146
+ helpers.push(" // Hand off to platform chrome; ElitVideoSurface exposes controls for parity only.");
11147
+ helpers.push(" }");
11060
11148
  helpers.push(" }");
11061
11149
  helpers.push("}");
11062
11150
  helpers.push("");
11063
11151
  helpers.push("@Composable");
11064
11152
  helpers.push("private fun ElitAudioSurface(source: String, label: String, autoPlay: Boolean, loop: Boolean, muted: Boolean, modifier: Modifier = Modifier) {");
11065
- helpers.push(" Button(onClick = {}, modifier = modifier) {");
11066
- helpers.push(" Text(text = label)");
11153
+ helpers.push(" androidx.compose.ui.viewinterop.AndroidView(");
11154
+ helpers.push(" factory = { context ->");
11155
+ helpers.push(" android.media.MediaPlayer().apply {");
11156
+ helpers.push(" val mediaPlayer = this");
11157
+ helpers.push(" mediaPlayer.isLooping = loop");
11158
+ helpers.push(" mediaPlayer.setVolume(if (muted) 0f else 1f, if (muted) 0f else 1f)");
11159
+ helpers.push(" if (source.isNotBlank()) setDataSource(source)");
11160
+ helpers.push(" if (autoPlay) start()");
11161
+ helpers.push(" }");
11162
+ helpers.push(" },");
11163
+ helpers.push(" modifier = modifier,");
11164
+ helpers.push(" )");
11165
+ helpers.push("}");
11166
+ }
11167
+ if (context.helperFlags.has("unsupportedPlaceholder")) {
11168
+ helpers.push("");
11169
+ helpers.push("@Composable");
11170
+ helpers.push("private fun ElitUnsupported(label: String, sourceTag: String, modifier: Modifier = Modifier) {");
11171
+ helpers.push(" Box(modifier = modifier, contentAlignment = Alignment.Center) {");
11172
+ helpers.push(' Text(text = "$label ($sourceTag)")');
11067
11173
  helpers.push(" }");
11068
11174
  helpers.push("}");
11069
11175
  }
@@ -11094,11 +11200,27 @@ function renderAndroidCompose(input2, options = {}) {
11094
11200
  resolvedStyles: styleData.resolvedStyles,
11095
11201
  styleContexts: styleData.styleContexts
11096
11202
  };
11097
- const bodyLines = tree.roots.length === 1 ? renderComposeNode(tree.roots[0], 1, context, { availableWidth: styleResolveOptions.viewportWidth, availableHeight: styleResolveOptions.viewportHeight }) : [
11098
- " Column(modifier = Modifier.fillMaxSize()) {",
11099
- ...renderComposeChildren(tree.roots, 2, context, renderComposeNode, "Column", void 0, { availableWidth: styleResolveOptions.viewportWidth, availableHeight: styleResolveOptions.viewportHeight }),
11100
- " }"
11101
- ];
11203
+ const singleRoot = tree.roots.length === 1 ? tree.roots[0] : null;
11204
+ const isSingleScreenRoot = singleRoot !== null && singleRoot.kind === "element" && singleRoot.component === "Screen";
11205
+ if (isSingleScreenRoot) {
11206
+ context.helperFlags.add("screenRoot");
11207
+ }
11208
+ let bodyLines;
11209
+ if (isSingleScreenRoot) {
11210
+ bodyLines = [
11211
+ " Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState())) {",
11212
+ ...renderComposeNode(tree.roots[0], 2, context, { availableWidth: styleResolveOptions.viewportWidth, availableHeight: styleResolveOptions.viewportHeight }),
11213
+ " }"
11214
+ ];
11215
+ } else if (tree.roots.length === 1) {
11216
+ bodyLines = renderComposeNode(tree.roots[0], 1, context, { availableWidth: styleResolveOptions.viewportWidth, availableHeight: styleResolveOptions.viewportHeight });
11217
+ } else {
11218
+ bodyLines = [
11219
+ " Column(modifier = Modifier.fillMaxSize()) {",
11220
+ ...renderComposeChildren(tree.roots, 2, context, renderComposeNode, "Column", void 0, { availableWidth: styleResolveOptions.viewportWidth, availableHeight: styleResolveOptions.viewportHeight }),
11221
+ " }"
11222
+ ];
11223
+ }
11102
11224
  const lines = [];
11103
11225
  if (resolvedOptions.includePackage) {
11104
11226
  lines.push(`package ${resolvedOptions.packageName}`);
@@ -11998,6 +12120,18 @@ function renderSwiftUIContainerNode(node, level, context, hints, baseLines) {
11998
12120
  ];
11999
12121
  return [...baseLines, ...appendSwiftUIOverlays(contentLines, overlays, level)];
12000
12122
  }
12123
+ function renderSwiftUnsupportedFallback(node, level, context, baseLines, modifiers, label2) {
12124
+ context.helperFlags.add("unsupportedPlaceholder");
12125
+ const sourceTag = node.sourceTag ?? node.component.toLowerCase();
12126
+ return appendSwiftUIModifiers(
12127
+ [
12128
+ ...baseLines,
12129
+ `${indent11(level)}elitUnsupportedPlaceholder(label: ${quoteSwiftString(label2)}, sourceTag: ${quoteSwiftString(sourceTag)})`
12130
+ ],
12131
+ modifiers,
12132
+ level
12133
+ );
12134
+ }
12001
12135
  function renderSwiftUINode(node, level, context, hints = {}) {
12002
12136
  if (node.kind === "text") {
12003
12137
  return renderTextView(node, level, context);
@@ -12031,10 +12165,21 @@ function renderSwiftUINode(node, level, context, hints = {}) {
12031
12165
  const imageStyle = getStyleObject(node, context.resolvedStyles, context.styleResolveOptions);
12032
12166
  const objectFit = resolveNativeObjectFitStyle(imageStyle);
12033
12167
  const objectPosition = resolveNativeObjectPositionStyle(imageStyle);
12168
+ const imageArgs = [
12169
+ `source: ${quoteSwiftString(source2)}`,
12170
+ `label: ${quoteSwiftString(fallbackLabel)}`,
12171
+ `alt: ${alt ? quoteSwiftString(alt) : "nil"}`
12172
+ ];
12173
+ if (objectFit !== "cover") {
12174
+ imageArgs.push(`objectFit: ${quoteSwiftString(objectFit)}`);
12175
+ }
12176
+ if (objectPosition !== "center") {
12177
+ imageArgs.push(`objectPosition: ${quoteSwiftString(objectPosition)}`);
12178
+ }
12034
12179
  return appendSwiftUIModifiers(
12035
12180
  [
12036
12181
  ...baseLines,
12037
- `${indent11(level)}elitImageSurface(source: ${quoteSwiftString(source2)}, label: ${quoteSwiftString(fallbackLabel)}, alt: ${alt ? quoteSwiftString(alt) : "nil"}, objectFit: ${quoteSwiftString(objectFit)}, objectPosition: ${quoteSwiftString(objectPosition)})`
12182
+ `${indent11(level)}elitImageSurface(${imageArgs.join(", ")})`
12038
12183
  ],
12039
12184
  modifiers,
12040
12185
  level
@@ -12069,33 +12214,38 @@ function renderSwiftUINode(node, level, context, hints = {}) {
12069
12214
  return [...baseLines, ...appendSwiftUIModifiers(canvas2.lines, canvas2.modifiers, level)];
12070
12215
  }
12071
12216
  if (node.component === "WebView") {
12217
+ const source2 = resolveNativeSurfaceSource(node);
12218
+ if (!source2) {
12219
+ return renderSwiftUnsupportedFallback(node, level, context, baseLines, modifiers, "WebView");
12220
+ }
12072
12221
  context.helperFlags.add("webViewSurface");
12073
- const source2 = resolveNativeSurfaceSource(node) ?? "";
12074
12222
  const label3 = resolveNativeAccessibilityLabel(node) ?? "Web content";
12075
12223
  return appendSwiftUIModifiers(
12076
12224
  [
12077
12225
  ...baseLines,
12078
- `${indent11(level)}elitWebViewSurface(source: ${quoteSwiftString(source2)}, label: ${quoteSwiftString(label3)})`
12226
+ `${indent11(level)}ElitWebViewSurface(source: ${quoteSwiftString(source2)}, label: ${quoteSwiftString(label3)})`
12079
12227
  ],
12080
12228
  modifiers,
12081
12229
  level
12082
12230
  );
12083
12231
  }
12084
12232
  if (node.component === "Media") {
12233
+ const source2 = resolveNativeSurfaceSource(node);
12234
+ if (!source2) {
12235
+ return renderSwiftUnsupportedFallback(node, level, context, baseLines, modifiers, "Media");
12236
+ }
12085
12237
  context.helperFlags.add("mediaSurface");
12086
- const source2 = resolveNativeSurfaceSource(node) ?? "";
12087
12238
  const label3 = resolveNativeMediaLabel(node);
12088
12239
  const style2 = getStyleObject(node, context.resolvedStyles, context.styleResolveOptions);
12089
12240
  const objectFit = resolveNativeObjectFitStyle(style2);
12090
12241
  const objectPosition = resolveNativeObjectPositionStyle(style2);
12091
12242
  const autoPlay = toNativeBoolean(node.props.autoPlay ?? node.props.autoplay);
12092
- const loop = toNativeBoolean(node.props.loop);
12093
12243
  const muted = isNativeMuted(node);
12094
12244
  if (node.sourceTag === "audio") {
12095
12245
  return appendSwiftUIModifiers(
12096
12246
  [
12097
12247
  ...baseLines,
12098
- `${indent11(level)}ElitAudioSurface(source: ${quoteSwiftString(source2)}, label: ${quoteSwiftString(label3)}, autoPlay: ${autoPlay ? "true" : "false"}, loop: ${loop ? "true" : "false"}, muted: ${muted ? "true" : "false"})`
12248
+ `${indent11(level)}ElitAudioSurface(source: ${quoteSwiftString(source2)}, label: ${quoteSwiftString(label3)}, autoPlay: ${autoPlay ? "true" : "false"}, muted: ${muted ? "true" : "false"})`
12099
12249
  ],
12100
12250
  modifiers,
12101
12251
  level
@@ -12104,15 +12254,33 @@ function renderSwiftUINode(node, level, context, hints = {}) {
12104
12254
  const poster = resolveNativeVideoPoster(node);
12105
12255
  const controls = shouldNativeShowVideoControls(node);
12106
12256
  const playsInline = shouldNativePlayInline(node);
12257
+ const videoArgs = [
12258
+ `source: ${quoteSwiftString(source2)}`,
12259
+ `label: ${quoteSwiftString(label3)}`,
12260
+ `autoPlay: ${autoPlay ? "true" : "false"}`,
12261
+ `muted: ${muted ? "true" : "false"}`,
12262
+ `controls: ${controls ? "true" : "false"}`,
12263
+ `poster: ${poster ? quoteSwiftString(poster) : "nil"}`,
12264
+ `playsInline: ${playsInline ? "true" : "false"}`
12265
+ ];
12266
+ if (objectFit !== "cover") {
12267
+ videoArgs.push(`posterFit: ${quoteSwiftString(objectFit)}`);
12268
+ }
12269
+ if (objectPosition !== "center") {
12270
+ videoArgs.push(`posterPosition: ${quoteSwiftString(objectPosition)}`);
12271
+ }
12107
12272
  return appendSwiftUIModifiers(
12108
12273
  [
12109
12274
  ...baseLines,
12110
- `${indent11(level)}ElitVideoSurface(source: ${quoteSwiftString(source2)}, label: ${quoteSwiftString(label3)}, autoPlay: ${autoPlay ? "true" : "false"}, loop: ${loop ? "true" : "false"}, muted: ${muted ? "true" : "false"}, controls: ${controls ? "true" : "false"}, playsInline: ${playsInline ? "true" : "false"}${poster ? `, poster: ${quoteSwiftString(poster)}` : ""}, posterFit: ${quoteSwiftString(objectFit)}, posterPosition: ${quoteSwiftString(objectPosition)})`
12275
+ `${indent11(level)}ElitVideoSurface(${videoArgs.join(", ")})`
12111
12276
  ],
12112
12277
  modifiers,
12113
12278
  level
12114
12279
  );
12115
12280
  }
12281
+ if (node.component === "Math") {
12282
+ return renderSwiftUnsupportedFallback(node, level, context, baseLines, modifiers, "Math");
12283
+ }
12116
12284
  if (node.component === "Cell") {
12117
12285
  const style2 = getStyleObject(node, context.resolvedStyles, context.styleResolveOptions);
12118
12286
  const cellHints = {
@@ -12138,6 +12306,8 @@ function buildSwiftUIHelpers(context) {
12138
12306
  if (context.helperFlags.has("bridge")) {
12139
12307
  helpers.push("");
12140
12308
  helpers.push("private enum ElitNativeBridge {");
12309
+ helpers.push(" static var onAction: ((String, String?, String?) -> Void)?");
12310
+ helpers.push(" static var onNavigate: ((String) -> Void)?");
12141
12311
  helpers.push(" static func dispatch(action: String? = nil, route: String? = nil, payloadJson: String? = nil) {");
12142
12312
  helpers.push(' print("ElitNativeBridge", action ?? "", route ?? "", payloadJson ?? "")');
12143
12313
  helpers.push(" }");
@@ -12162,6 +12332,13 @@ function buildSwiftUIHelpers(context) {
12162
12332
  helpers.push("}");
12163
12333
  }
12164
12334
  if (context.helperFlags.has("backgroundImage") || context.helperFlags.has("imagePlaceholder")) {
12335
+ helpers.push("");
12336
+ helpers.push("@ViewBuilder");
12337
+ helpers.push('private func elitBackgroundImage(_ image: Image, backgroundSize: String = "cover", backgroundPosition: String = "center", backgroundRepeat: String = "no-repeat") -> some View {');
12338
+ helpers.push(" image");
12339
+ helpers.push(" .resizable()");
12340
+ helpers.push(" .scaledToFill()");
12341
+ helpers.push("}");
12165
12342
  helpers.push("");
12166
12343
  helpers.push("@ViewBuilder");
12167
12344
  helpers.push('private func elitBackgroundImageSurface(source: String, objectFit: String = "cover", objectPosition: String = "center") -> some View {');
@@ -12169,9 +12346,7 @@ function buildSwiftUIHelpers(context) {
12169
12346
  helpers.push(" AsyncImage(url: url) { phase in");
12170
12347
  helpers.push(" switch phase {");
12171
12348
  helpers.push(" case .success(let image):");
12172
- helpers.push(" image");
12173
- helpers.push(" .resizable()");
12174
- helpers.push(" .scaledToFill()");
12349
+ helpers.push(' elitBackgroundImage(image, backgroundSize: objectFit, backgroundPosition: objectPosition, backgroundRepeat: "no-repeat")');
12175
12350
  helpers.push(" default:");
12176
12351
  helpers.push(" Color.clear");
12177
12352
  helpers.push(" }");
@@ -12182,7 +12357,7 @@ function buildSwiftUIHelpers(context) {
12182
12357
  helpers.push("}");
12183
12358
  helpers.push("");
12184
12359
  helpers.push("@ViewBuilder");
12185
- helpers.push('private func elitImageSurface(source: String, label: String, alt: String? = nil, objectFit: String = "cover", objectPosition: String = "center") -> some View {');
12360
+ helpers.push('private func elitImageSurface(source: String, label: String, alt: String?, objectFit: String = "cover", objectPosition: String = "center") -> some View {');
12186
12361
  helpers.push(" if source.isEmpty {");
12187
12362
  helpers.push(" Text(alt ?? label)");
12188
12363
  helpers.push(" .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center)");
@@ -12193,31 +12368,131 @@ function buildSwiftUIHelpers(context) {
12193
12368
  }
12194
12369
  if (context.helperFlags.has("webViewSurface")) {
12195
12370
  helpers.push("");
12196
- helpers.push("@ViewBuilder");
12197
- helpers.push("private func elitWebViewSurface(source: String, label: String) -> some View {");
12198
- helpers.push(" VStack(alignment: .leading, spacing: 8) {");
12199
- helpers.push(" Text(label)");
12200
- helpers.push(" Text(source)");
12201
- helpers.push(" .font(.caption)");
12202
- helpers.push(" .foregroundStyle(.secondary)");
12371
+ helpers.push("struct ElitWebViewSurface: UIViewRepresentable {");
12372
+ helpers.push(" let source: String");
12373
+ helpers.push(" let label: String?");
12374
+ helpers.push("");
12375
+ helpers.push(" func makeUIView(context: Context) -> WKWebView {");
12376
+ helpers.push(" let webView = WKWebView()");
12377
+ helpers.push(" webView.accessibilityLabel = label");
12378
+ helpers.push(" if let url = URL(string: source), !source.isEmpty { webView.load(URLRequest(url: url)) }");
12379
+ helpers.push(" return webView");
12203
12380
  helpers.push(" }");
12381
+ helpers.push("");
12382
+ helpers.push(" func updateUIView(_ uiView: WKWebView, context: Context) {}");
12204
12383
  helpers.push("}");
12205
12384
  }
12206
12385
  if (context.helperFlags.has("mediaSurface")) {
12386
+ helpers.push("");
12387
+ helpers.push("private func elitPosterAlignment(_ posterPosition: String) -> Alignment {");
12388
+ helpers.push(" switch posterPosition.lowercased() {");
12389
+ helpers.push(' case "top", "leading", "top-leading":');
12390
+ helpers.push(" return .topLeading");
12391
+ helpers.push(' case "bottom", "trailing", "bottom-trailing":');
12392
+ helpers.push(" return .bottomTrailing");
12393
+ helpers.push(' case "center":');
12394
+ helpers.push(" return .center");
12395
+ helpers.push(" default:");
12396
+ helpers.push(" return .center");
12397
+ helpers.push(" }");
12398
+ helpers.push("}");
12207
12399
  helpers.push("");
12208
12400
  helpers.push("@ViewBuilder");
12209
- helpers.push('private func ElitVideoSurface(source: String, label: String, autoPlay: Bool, loop: Bool, muted: Bool, controls: Bool, playsInline: Bool, poster: String? = nil, posterFit: String = "cover", posterPosition: String = "center") -> some View {');
12210
- helpers.push(" VStack(alignment: .leading, spacing: 8) {");
12211
- helpers.push(" if let poster, !poster.isEmpty {");
12212
- helpers.push(" elitBackgroundImageSurface(source: poster, objectFit: posterFit, objectPosition: posterPosition)");
12401
+ helpers.push("private func elitPosterImage(_ image: Image, posterFit: String, posterPosition: String) -> some View {");
12402
+ helpers.push(" let resizable = image.resizable()");
12403
+ helpers.push(" switch posterFit.lowercased() {");
12404
+ helpers.push(' case "contain":');
12405
+ helpers.push(" return AnyView(resizable.scaledToFit().frame(maxWidth: .infinity, maxHeight: .infinity, alignment: elitPosterAlignment(posterPosition)))");
12406
+ helpers.push(' case "fill", "cover":');
12407
+ helpers.push(" return AnyView(resizable.scaledToFill().frame(maxWidth: .infinity, maxHeight: .infinity, alignment: elitPosterAlignment(posterPosition)))");
12408
+ helpers.push(" default:");
12409
+ helpers.push(" return AnyView(resizable.scaledToFill())");
12410
+ helpers.push(" }");
12411
+ helpers.push("}");
12412
+ helpers.push("");
12413
+ helpers.push("struct ElitVideoPlayerController: UIViewControllerRepresentable {");
12414
+ helpers.push(" let source: String");
12415
+ helpers.push(" let autoPlay: Bool");
12416
+ helpers.push(" let muted: Bool");
12417
+ helpers.push(" let controls: Bool");
12418
+ helpers.push(" let playsInline: Bool");
12419
+ helpers.push("");
12420
+ helpers.push(" func makeUIViewController(context: Context) -> AVPlayerViewController {");
12421
+ helpers.push(" let controller = AVPlayerViewController()");
12422
+ helpers.push(" if let url = URL(string: source) {");
12423
+ helpers.push(" let player = AVPlayer(url: url)");
12424
+ helpers.push(" let resolvedPlayer = player");
12425
+ helpers.push(" resolvedPlayer.isMuted = muted");
12426
+ helpers.push(" controller.player = resolvedPlayer");
12427
+ helpers.push(" if autoPlay { resolvedPlayer.play() }");
12213
12428
  helpers.push(" }");
12214
- helpers.push(" Text(label)");
12429
+ helpers.push(" controller.showsPlaybackControls = controls");
12430
+ helpers.push(" controller.entersFullScreenWhenPlaybackBegins = !playsInline");
12431
+ helpers.push(" return controller");
12215
12432
  helpers.push(" }");
12433
+ helpers.push("");
12434
+ helpers.push(" func updateUIViewController(_ controller: AVPlayerViewController, context: Context) {}");
12216
12435
  helpers.push("}");
12436
+ helpers.push("");
12437
+ helpers.push("struct ElitVideoSurface: View {");
12438
+ helpers.push(" let source: String");
12439
+ helpers.push(" let label: String");
12440
+ helpers.push(" let autoPlay: Bool");
12441
+ helpers.push(" let muted: Bool");
12442
+ helpers.push(" let controls: Bool");
12443
+ helpers.push(" let poster: String?");
12444
+ helpers.push(" let playsInline: Bool");
12445
+ helpers.push(" let posterFit: String");
12446
+ helpers.push(" let posterPosition: String");
12447
+ helpers.push("");
12448
+ helpers.push(" var body: some View {");
12449
+ helpers.push(" ZStack {");
12450
+ helpers.push(" if let poster, !poster.isEmpty, let posterURL = URL(string: poster) {");
12451
+ helpers.push(" AsyncImage(url: posterURL) { phase in");
12452
+ helpers.push(" switch phase {");
12453
+ helpers.push(" case .success(let image):");
12454
+ helpers.push(" elitPosterImage(image, posterFit: posterFit, posterPosition: posterPosition)");
12455
+ helpers.push(" default:");
12456
+ helpers.push(" Color.clear");
12457
+ helpers.push(" }");
12458
+ helpers.push(" }");
12459
+ helpers.push(" }");
12460
+ helpers.push(" ElitVideoPlayerController(source: source, autoPlay: autoPlay, muted: muted, controls: controls, playsInline: playsInline)");
12461
+ helpers.push(" .accessibilityLabel(label)");
12462
+ helpers.push(" }");
12463
+ helpers.push(" }");
12464
+ helpers.push("}");
12465
+ helpers.push("");
12466
+ helpers.push("struct ElitAudioSurface: View {");
12467
+ helpers.push(" let source: String");
12468
+ helpers.push(" let label: String");
12469
+ helpers.push(" let autoPlay: Bool");
12470
+ helpers.push(" let muted: Bool");
12471
+ helpers.push("");
12472
+ helpers.push(" var body: some View {");
12473
+ helpers.push(" VStack {");
12474
+ helpers.push(" if let url = URL(string: source), !source.isEmpty {");
12475
+ helpers.push(" AVPlayer(url: url).let { resolvedPlayer in");
12476
+ helpers.push(" resolvedPlayer.isMuted = muted");
12477
+ helpers.push(" if autoPlay { resolvedPlayer.play() }");
12478
+ helpers.push(" }");
12479
+ helpers.push(" }");
12480
+ helpers.push(' Label(label, systemImage: "waveform")');
12481
+ helpers.push(" .accessibilityLabel(label)");
12482
+ helpers.push(" }");
12483
+ helpers.push(" }");
12484
+ helpers.push("}");
12485
+ }
12486
+ if (context.helperFlags.has("unsupportedPlaceholder")) {
12217
12487
  helpers.push("");
12218
12488
  helpers.push("@ViewBuilder");
12219
- helpers.push("private func ElitAudioSurface(source: String, label: String, autoPlay: Bool, loop: Bool, muted: Bool) -> some View {");
12220
- helpers.push(' Label(label, systemImage: "waveform")');
12489
+ helpers.push("private func elitUnsupportedPlaceholder(label: String, sourceTag: String) -> some View {");
12490
+ helpers.push(" VStack(spacing: 8) {");
12491
+ helpers.push(" Text(label)");
12492
+ helpers.push(" Text(sourceTag)");
12493
+ helpers.push(" .font(.caption)");
12494
+ helpers.push(" .foregroundStyle(.secondary)");
12495
+ helpers.push(" }");
12221
12496
  helpers.push("}");
12222
12497
  }
12223
12498
  return helpers;
@@ -12245,17 +12520,30 @@ function renderSwiftUI(input2, options = {}) {
12245
12520
  resolvedStyles: styleData.resolvedStyles,
12246
12521
  styleContexts: styleData.styleContexts
12247
12522
  };
12248
- const bodyLines = tree.roots.length === 1 ? renderSwiftUINode(tree.roots[0], 2, context, { availableWidth: styleResolveOptions.viewportWidth, availableHeight: styleResolveOptions.viewportHeight }) : [
12523
+ const singleRoot = tree.roots.length === 1 ? tree.roots[0] : null;
12524
+ const isSingleScreenRoot = singleRoot !== null && singleRoot.kind === "element" && singleRoot.component === "Screen";
12525
+ const innerLines = tree.roots.length === 1 ? renderSwiftUINode(tree.roots[0], 2, context, { availableWidth: styleResolveOptions.viewportWidth, availableHeight: styleResolveOptions.viewportHeight }) : [
12249
12526
  " VStack(alignment: .leading, spacing: 0) {",
12250
12527
  ...renderSwiftUIChildren(tree.roots, 3, context, renderSwiftUINode, "VStack", void 0, { availableWidth: styleResolveOptions.viewportWidth, availableHeight: styleResolveOptions.viewportHeight }),
12251
12528
  " }"
12252
12529
  ];
12530
+ const bodyLines = isSingleScreenRoot ? [
12531
+ " ScrollView {",
12532
+ ...innerLines.map((line) => " " + line),
12533
+ " }"
12534
+ ] : innerLines;
12253
12535
  const lines = [];
12254
12536
  if (resolvedOptions.includeImports) {
12255
12537
  lines.push("import SwiftUI");
12256
12538
  if (context.helperFlags.has("backgroundImage") || context.helperFlags.has("imagePlaceholder") || context.helperFlags.has("openUrlHandler")) {
12257
12539
  lines.push("import Foundation");
12258
12540
  }
12541
+ if (context.helperFlags.has("webViewSurface")) {
12542
+ lines.push("import WebKit");
12543
+ }
12544
+ if (context.helperFlags.has("mediaSurface")) {
12545
+ lines.push("import AVKit");
12546
+ }
12259
12547
  lines.push("");
12260
12548
  }
12261
12549
  lines.push(`struct ${resolvedOptions.structName}: View {`);