elit 3.6.9 → 3.7.1

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