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.cjs CHANGED
@@ -8902,8 +8902,12 @@ function buildComposeChunkedRowArguments(style2, modifier, columnGap, styleResol
8902
8902
  }
8903
8903
  return args.join(", ");
8904
8904
  }
8905
- function buildComposeChunkedTrackModifier(baseModifier, row) {
8905
+ function buildComposeChunkedTrackModifier(baseModifier, row, options = {}) {
8906
+ const fillWidth = options.fillWidth ?? true;
8906
8907
  let modifier = baseModifier;
8908
+ if (row.trackWeight !== void 0) {
8909
+ modifier = appendComposeModifierCall(modifier, `weight(${formatFloat(row.trackWeight)}f, fill = true)`);
8910
+ }
8907
8911
  if (row.height !== void 0) {
8908
8912
  modifier = appendComposeModifierCall(modifier, `height(${formatFloat(row.height)}.dp)`);
8909
8913
  } else if (row.minHeight !== void 0 || row.maxHeight !== void 0) {
@@ -8916,7 +8920,7 @@ function buildComposeChunkedTrackModifier(baseModifier, row) {
8916
8920
  }
8917
8921
  modifier = appendComposeModifierCall(modifier, `heightIn(${heightInArgs.join(", ")})`);
8918
8922
  }
8919
- return row.trackWeight !== void 0 ? appendComposeModifierCall(modifier, `weight(${formatFloat(row.trackWeight)}f, fill = true)`) : modifier;
8923
+ return fillWidth ? appendComposeModifierCall(modifier, "fillMaxWidth()") : modifier;
8920
8924
  }
8921
8925
  function buildComposeChunkedColumnArrangement(layout) {
8922
8926
  const contentAlignment = resolveEffectiveChunkedContentAlignment(layout);
@@ -10665,7 +10669,7 @@ function renderComposeChunkedLayout(node, layout, level, context, modifier, hint
10665
10669
  const usesSingleRowGridStackAlignment = layout.kind === "grid" && layout.rows.length === 1 && effectiveContentAlignment !== void 0 && effectiveContentAlignment !== "start";
10666
10670
  if (layout.kind === "grid" && layout.rows.length === 1 && !usesSingleRowGridStackAlignment) {
10667
10671
  const [row] = layout.rows;
10668
- const lines2 = [`${indent4(level)}Row(${buildComposeChunkedRowArguments(style2, buildComposeChunkedTrackModifier(modifier, row), layout.columnGap, context.styleResolveOptions)}) {`];
10672
+ const lines2 = [`${indent4(level)}Row(${buildComposeChunkedRowArguments(style2, buildComposeChunkedTrackModifier(modifier, row, { fillWidth: false }), layout.columnGap, context.styleResolveOptions)}) {`];
10669
10673
  const totalWeight = row.weights ? row.weights.reduce((sum, entry) => sum + (entry ?? 0), 0) : void 0;
10670
10674
  row.items.forEach((child, index) => {
10671
10675
  const weight = row.weights?.[index];
@@ -10697,7 +10701,7 @@ function renderComposeChunkedLayout(node, layout, level, context, modifier, hint
10697
10701
  const lines = [`${indent4(level)}Column(modifier = ${modifier}${outerGap ? `, verticalArrangement = ${outerGap}` : ""}) {`];
10698
10702
  for (const row of layout.rows) {
10699
10703
  const totalWeight = row.weights ? row.weights.reduce((sum, entry) => sum + (entry ?? 0), 0) : void 0;
10700
- lines.push(`${indent4(level + 1)}Row(${buildComposeChunkedRowArguments(style2, buildComposeChunkedTrackModifier("Modifier.fillMaxWidth()", row), layout.columnGap, context.styleResolveOptions)}) {`);
10704
+ lines.push(`${indent4(level + 1)}Row(${buildComposeChunkedRowArguments(style2, buildComposeChunkedTrackModifier("Modifier", row), layout.columnGap, context.styleResolveOptions)}) {`);
10701
10705
  row.items.forEach((child, index) => {
10702
10706
  const weight = row.weights?.[index];
10703
10707
  const columnSize = row.columnSizes?.[index];
@@ -11135,7 +11139,7 @@ function renderComposeContainerNode(node, level, context, hints, modifier, baseL
11135
11139
  }
11136
11140
  const lines = [
11137
11141
  ...baseLines,
11138
- `${indent7(level)}Box {`,
11142
+ `${indent7(level)}Box(modifier = Modifier.matchParentSize()) {`,
11139
11143
  ...renderComposeContainerBody(flowNode, level + 1, context, modifier, hints, renderComposeNode)
11140
11144
  ];
11141
11145
  absoluteChildren.forEach((child) => {
@@ -11152,6 +11156,18 @@ function renderComposeContainerNode(node, level, context, hints, modifier, baseL
11152
11156
  lines.push(`${indent7(level)}}`);
11153
11157
  return lines;
11154
11158
  }
11159
+ function renderComposeUnsupportedFallback(node, level, context, modifier, baseLines, label2) {
11160
+ context.helperFlags.add("unsupportedPlaceholder");
11161
+ const sourceTag = node.sourceTag ?? node.component.toLowerCase();
11162
+ const args = [`label = ${quoteKotlinString(label2)}`, `sourceTag = ${quoteKotlinString(sourceTag)}`];
11163
+ if (modifier !== "Modifier") {
11164
+ args.push(`modifier = ${modifier}`);
11165
+ }
11166
+ return [
11167
+ ...baseLines,
11168
+ `${indent7(level)}ElitUnsupported(${args.join(", ")})`
11169
+ ];
11170
+ }
11155
11171
  function renderComposeNode(node, level, context, hints = {}) {
11156
11172
  if (node.kind === "text") {
11157
11173
  return renderTextComposable(node, level, context);
@@ -11224,8 +11240,11 @@ function renderComposeNode(node, level, context, hints = {}) {
11224
11240
  ];
11225
11241
  }
11226
11242
  if (node.component === "WebView") {
11243
+ const source2 = resolveNativeSurfaceSource(node);
11244
+ if (!source2) {
11245
+ return renderComposeUnsupportedFallback(node, level, context, modifier, baseLines, "WebView");
11246
+ }
11227
11247
  context.helperFlags.add("webViewSurface");
11228
- const source2 = resolveNativeSurfaceSource(node) ?? "";
11229
11248
  const label3 = resolveNativeAccessibilityLabel(node) ?? "Web content";
11230
11249
  return [
11231
11250
  ...baseLines,
@@ -11233,8 +11252,11 @@ function renderComposeNode(node, level, context, hints = {}) {
11233
11252
  ];
11234
11253
  }
11235
11254
  if (node.component === "Media") {
11255
+ const source2 = resolveNativeSurfaceSource(node);
11256
+ if (!source2) {
11257
+ return renderComposeUnsupportedFallback(node, level, context, modifier, baseLines, "Media");
11258
+ }
11236
11259
  context.helperFlags.add("mediaSurface");
11237
- const source2 = resolveNativeSurfaceSource(node) ?? "";
11238
11260
  const label3 = resolveNativeMediaLabel(node);
11239
11261
  const style2 = getStyleObject(node, context.resolvedStyles, context.styleResolveOptions);
11240
11262
  const objectFit = resolveNativeObjectFitStyle(style2);
@@ -11251,19 +11273,44 @@ function renderComposeNode(node, level, context, hints = {}) {
11251
11273
  const poster = resolveNativeVideoPoster(node);
11252
11274
  const controls = shouldNativeShowVideoControls(node);
11253
11275
  const playsInline = shouldNativePlayInline(node);
11276
+ const videoArgs = [
11277
+ `source = ${quoteKotlinString(source2)}`,
11278
+ `label = ${quoteKotlinString(label3)}`,
11279
+ `autoPlay = ${autoPlay ? "true" : "false"}`,
11280
+ `loop = ${loop ? "true" : "false"}`,
11281
+ `muted = ${muted ? "true" : "false"}`,
11282
+ `controls = ${controls ? "true" : "false"}`,
11283
+ `poster = ${poster ? quoteKotlinString(poster) : "null"}`,
11284
+ `playsInline = ${playsInline ? "true" : "false"}`
11285
+ ];
11286
+ if (objectFit !== "cover") {
11287
+ videoArgs.push(`posterFit = ${quoteKotlinString(objectFit)}`);
11288
+ }
11289
+ if (objectPosition !== "center") {
11290
+ videoArgs.push(`posterPosition = ${quoteKotlinString(objectPosition)}`);
11291
+ }
11292
+ videoArgs.push(`modifier = ${modifier}`);
11254
11293
  return [
11255
11294
  ...baseLines,
11256
- `${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})`
11295
+ `${indent7(level)}ElitVideoSurface(${videoArgs.join(", ")})`
11257
11296
  ];
11258
11297
  }
11298
+ if (node.component === "Math") {
11299
+ return renderComposeUnsupportedFallback(node, level, context, modifier, baseLines, "Math");
11300
+ }
11259
11301
  if (node.component === "Cell") {
11260
11302
  const style2 = getStyleObject(node, context.resolvedStyles, context.styleResolveOptions);
11303
+ const hasExplicitWidth = hasExplicitNativeWidthStyle(style2);
11261
11304
  const cellHints = {
11262
11305
  ...hints,
11263
- ...!hasExplicitNativeWidthStyle(style2) ? { fillWidth: true } : {},
11306
+ ...!hasExplicitWidth ? { fillWidth: true } : {},
11264
11307
  ...!hasExplicitNativeHeightStyle(style2) && hints.fillHeight ? { fillHeight: true } : {}
11265
11308
  };
11266
- return renderComposeContainerNode(node, level, context, cellHints, modifier, baseLines);
11309
+ let cellModifier = modifier;
11310
+ if (hints.parentFlexLayout === "Row" && !hasExplicitWidth) {
11311
+ cellModifier = cellModifier === "Modifier" ? "Modifier.weight(1f, fill = true)" : cellModifier.replace(/^Modifier\./, "Modifier.weight(1f, fill = true).");
11312
+ }
11313
+ return renderComposeContainerNode(node, level, context, cellHints, cellModifier, baseLines);
11267
11314
  }
11268
11315
  if (node.children.length > 0 || node.component === "Screen") {
11269
11316
  return renderComposeContainerNode(node, level, context, hints, modifier, baseLines);
@@ -11280,11 +11327,13 @@ function buildAndroidComposeHelpers(context) {
11280
11327
  if (context.helperFlags.has("bridge")) {
11281
11328
  helpers.push("");
11282
11329
  helpers.push("private object ElitNativeBridge {");
11330
+ helpers.push(" var onAction: ((String, String?, String?) -> Unit)? = null");
11331
+ helpers.push(" var onNavigate: ((String) -> Unit)? = null");
11283
11332
  helpers.push(" fun dispatch(action: String? = null, route: String? = null, payloadJson: String? = null) {");
11284
11333
  helpers.push(' android.util.Log.d("ElitNativeBridge", listOfNotNull(action, route, payloadJson).joinToString(" | "))');
11285
11334
  helpers.push(" }");
11286
11335
  helpers.push("");
11287
- 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 {");
11336
+ 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 {");
11288
11337
  helpers.push(" val parts = mutableListOf<String>()");
11289
11338
  helpers.push(' parts += ""event":"$event""');
11290
11339
  helpers.push(' parts += ""sourceTag":"$sourceTag""');
@@ -11308,33 +11357,50 @@ function buildAndroidComposeHelpers(context) {
11308
11357
  helpers.push("}");
11309
11358
  }
11310
11359
  if (context.helperFlags.has("backgroundImage") || context.helperFlags.has("imagePlaceholder")) {
11360
+ helpers.push("");
11361
+ helpers.push("private fun elitLoadBackgroundBitmap(view: android.widget.ImageView, source: String, repeatMode: String, backgroundSize: String, backgroundPosition: String) {");
11362
+ helpers.push(" if (source.isBlank()) return");
11363
+ helpers.push(' val tileModeX = if (repeatMode == "repeat-y") android.graphics.Shader.TileMode.CLAMP else android.graphics.Shader.TileMode.REPEAT');
11364
+ helpers.push(' val tileModeY = if (repeatMode == "repeat-x") android.graphics.Shader.TileMode.CLAMP else android.graphics.Shader.TileMode.REPEAT');
11365
+ helpers.push(" view.scaleType = android.widget.ImageView.ScaleType.CENTER_CROP");
11366
+ helpers.push(' if (repeatMode == "no-repeat" || repeatMode == "round") {');
11367
+ helpers.push(" view.setImageURI(android.net.Uri.parse(source))");
11368
+ helpers.push(" } else {");
11369
+ helpers.push(" val bitmap = android.graphics.BitmapFactory.decodeStream(android.net.Uri.parse(source).let { runCatching { view.context.contentResolver.openInputStream(it) }.getOrNull() })");
11370
+ helpers.push(" if (bitmap != null) view.setImageDrawable(android.graphics.drawable.BitmapDrawable(view.resources, bitmap).apply { tileModeX = tileModeX; tileModeY = tileModeY })");
11371
+ helpers.push(" }");
11372
+ helpers.push("}");
11311
11373
  helpers.push("");
11312
11374
  helpers.push("@Composable");
11313
11375
  helpers.push('private fun ElitBackgroundImage(source: String, backgroundSize: String = "cover", backgroundPosition: String = "center", backgroundRepeat: String = "no-repeat", modifier: Modifier = Modifier) {');
11314
11376
  helpers.push(" androidx.compose.ui.viewinterop.AndroidView(");
11315
11377
  helpers.push(" factory = { context -> android.widget.ImageView(context).apply {");
11316
- helpers.push(" scaleType = android.widget.ImageView.ScaleType.CENTER_CROP");
11317
- helpers.push(" if (source.isNotBlank()) setImageURI(android.net.Uri.parse(source))");
11378
+ helpers.push(" elitLoadBackgroundBitmap(this, source, backgroundRepeat, backgroundSize, backgroundPosition)");
11318
11379
  helpers.push(" } },");
11319
11380
  helpers.push(" modifier = modifier,");
11320
11381
  helpers.push(" )");
11321
11382
  helpers.push("}");
11322
11383
  helpers.push("");
11323
11384
  helpers.push("@Composable");
11324
- helpers.push('private fun ElitImageSurface(source: String, label: String, alt: String? = null, modifier: Modifier = Modifier, objectFit: String = "cover", objectPosition: String = "center") {');
11385
+ helpers.push('private fun ElitImageSurface(source: String, label: String, contentDescription: String?, objectFit: String = "cover", objectPosition: String = "center", modifier: Modifier = Modifier) {');
11325
11386
  helpers.push(" if (source.isBlank()) {");
11326
11387
  helpers.push(" Box(modifier = modifier, contentAlignment = Alignment.Center) {");
11327
- helpers.push(" Text(text = alt ?: label)");
11388
+ helpers.push(" Text(text = contentDescription ?: label)");
11328
11389
  helpers.push(" }");
11329
11390
  helpers.push(" return");
11330
11391
  helpers.push(" }");
11331
- helpers.push(" ElitBackgroundImage(source = source, backgroundSize = objectFit, backgroundPosition = objectPosition, modifier = modifier)");
11392
+ helpers.push(" androidx.compose.ui.viewinterop.AndroidView(");
11393
+ helpers.push(" factory = { context -> android.widget.ImageView(context).apply {");
11394
+ helpers.push(' elitLoadBackgroundBitmap(this, source, "no-repeat", objectFit, objectPosition)');
11395
+ helpers.push(" } },");
11396
+ helpers.push(" modifier = modifier,");
11397
+ helpers.push(" )");
11332
11398
  helpers.push("}");
11333
11399
  }
11334
11400
  if (context.helperFlags.has("webViewSurface")) {
11335
11401
  helpers.push("");
11336
11402
  helpers.push("@Composable");
11337
- helpers.push("private fun ElitWebViewSurface(source: String, label: String, modifier: Modifier = Modifier) {");
11403
+ helpers.push("private fun ElitWebViewSurface(source: String, label: String?, modifier: Modifier = Modifier) {");
11338
11404
  helpers.push(" androidx.compose.ui.viewinterop.AndroidView(");
11339
11405
  helpers.push(" factory = { context -> android.webkit.WebView(context).apply {");
11340
11406
  helpers.push(" contentDescription = label");
@@ -11346,18 +11412,58 @@ function buildAndroidComposeHelpers(context) {
11346
11412
  helpers.push("}");
11347
11413
  }
11348
11414
  if (context.helperFlags.has("mediaSurface")) {
11415
+ helpers.push("");
11416
+ helpers.push("private fun elitVideoPosterScaleType(posterFit: String, posterPosition: String): android.widget.ImageView.ScaleType = when (posterFit.trim().lowercase()) {");
11417
+ helpers.push(' "contain", "scale-down" -> when (posterPosition.trim().lowercase()) {');
11418
+ helpers.push(' "top", "leading", "top-leading", "bottom-leading" -> android.widget.ImageView.ScaleType.FIT_START');
11419
+ helpers.push(' "bottom", "trailing", "bottom-trailing" -> android.widget.ImageView.ScaleType.FIT_END');
11420
+ helpers.push(" else -> android.widget.ImageView.ScaleType.FIT_CENTER");
11421
+ helpers.push(" }");
11422
+ helpers.push(" else -> android.widget.ImageView.ScaleType.CENTER_CROP");
11423
+ helpers.push("}");
11349
11424
  helpers.push("");
11350
11425
  helpers.push("@Composable");
11351
- 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) {');
11426
+ 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) {');
11427
+ helpers.push(" // Android VideoView already renders inline; playsInline is retained for parity with iOS generation.");
11352
11428
  helpers.push(" Box(modifier = modifier, contentAlignment = Alignment.Center) {");
11353
- helpers.push(' Text(text = if (autoPlay) "Playing $label" else label)');
11429
+ helpers.push(" androidx.compose.ui.viewinterop.AndroidView(");
11430
+ helpers.push(" factory = { context ->");
11431
+ helpers.push(" android.widget.ImageView(context).apply {");
11432
+ helpers.push(" val posterView = this");
11433
+ helpers.push(" posterView.contentDescription = label");
11434
+ helpers.push(" posterView.scaleType = elitVideoPosterScaleType(posterFit, posterPosition)");
11435
+ helpers.push(" if (poster != null) posterView.setImageURI(android.net.Uri.parse(poster))");
11436
+ helpers.push(" }");
11437
+ helpers.push(" },");
11438
+ helpers.push(" )");
11439
+ helpers.push(" if (controls) {");
11440
+ helpers.push(" // Hand off to platform chrome; ElitVideoSurface exposes controls for parity only.");
11441
+ helpers.push(" }");
11354
11442
  helpers.push(" }");
11355
11443
  helpers.push("}");
11356
11444
  helpers.push("");
11357
11445
  helpers.push("@Composable");
11358
11446
  helpers.push("private fun ElitAudioSurface(source: String, label: String, autoPlay: Boolean, loop: Boolean, muted: Boolean, modifier: Modifier = Modifier) {");
11359
- helpers.push(" Button(onClick = {}, modifier = modifier) {");
11360
- helpers.push(" Text(text = label)");
11447
+ helpers.push(" androidx.compose.ui.viewinterop.AndroidView(");
11448
+ helpers.push(" factory = { context ->");
11449
+ helpers.push(" android.media.MediaPlayer().apply {");
11450
+ helpers.push(" val mediaPlayer = this");
11451
+ helpers.push(" mediaPlayer.isLooping = loop");
11452
+ helpers.push(" mediaPlayer.setVolume(if (muted) 0f else 1f, if (muted) 0f else 1f)");
11453
+ helpers.push(" if (source.isNotBlank()) setDataSource(source)");
11454
+ helpers.push(" if (autoPlay) start()");
11455
+ helpers.push(" }");
11456
+ helpers.push(" },");
11457
+ helpers.push(" modifier = modifier,");
11458
+ helpers.push(" )");
11459
+ helpers.push("}");
11460
+ }
11461
+ if (context.helperFlags.has("unsupportedPlaceholder")) {
11462
+ helpers.push("");
11463
+ helpers.push("@Composable");
11464
+ helpers.push("private fun ElitUnsupported(label: String, sourceTag: String, modifier: Modifier = Modifier) {");
11465
+ helpers.push(" Box(modifier = modifier, contentAlignment = Alignment.Center) {");
11466
+ helpers.push(' Text(text = "$label ($sourceTag)")');
11361
11467
  helpers.push(" }");
11362
11468
  helpers.push("}");
11363
11469
  }
@@ -11388,11 +11494,27 @@ function renderAndroidCompose(input2, options = {}) {
11388
11494
  resolvedStyles: styleData.resolvedStyles,
11389
11495
  styleContexts: styleData.styleContexts
11390
11496
  };
11391
- const bodyLines = tree.roots.length === 1 ? renderComposeNode(tree.roots[0], 1, context, { availableWidth: styleResolveOptions.viewportWidth, availableHeight: styleResolveOptions.viewportHeight }) : [
11392
- " Column(modifier = Modifier.fillMaxSize()) {",
11393
- ...renderComposeChildren(tree.roots, 2, context, renderComposeNode, "Column", void 0, { availableWidth: styleResolveOptions.viewportWidth, availableHeight: styleResolveOptions.viewportHeight }),
11394
- " }"
11395
- ];
11497
+ const singleRoot = tree.roots.length === 1 ? tree.roots[0] : null;
11498
+ const isSingleScreenRoot = singleRoot !== null && singleRoot.kind === "element" && singleRoot.component === "Screen";
11499
+ if (isSingleScreenRoot) {
11500
+ context.helperFlags.add("screenRoot");
11501
+ }
11502
+ let bodyLines;
11503
+ if (isSingleScreenRoot) {
11504
+ bodyLines = [
11505
+ " Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState())) {",
11506
+ ...renderComposeNode(tree.roots[0], 2, context, { availableWidth: styleResolveOptions.viewportWidth, availableHeight: styleResolveOptions.viewportHeight }),
11507
+ " }"
11508
+ ];
11509
+ } else if (tree.roots.length === 1) {
11510
+ bodyLines = renderComposeNode(tree.roots[0], 1, context, { availableWidth: styleResolveOptions.viewportWidth, availableHeight: styleResolveOptions.viewportHeight });
11511
+ } else {
11512
+ bodyLines = [
11513
+ " Column(modifier = Modifier.fillMaxSize()) {",
11514
+ ...renderComposeChildren(tree.roots, 2, context, renderComposeNode, "Column", void 0, { availableWidth: styleResolveOptions.viewportWidth, availableHeight: styleResolveOptions.viewportHeight }),
11515
+ " }"
11516
+ ];
11517
+ }
11396
11518
  const lines = [];
11397
11519
  if (resolvedOptions.includePackage) {
11398
11520
  lines.push(`package ${resolvedOptions.packageName}`);
@@ -12292,6 +12414,18 @@ function renderSwiftUIContainerNode(node, level, context, hints, baseLines) {
12292
12414
  ];
12293
12415
  return [...baseLines, ...appendSwiftUIOverlays(contentLines, overlays, level)];
12294
12416
  }
12417
+ function renderSwiftUnsupportedFallback(node, level, context, baseLines, modifiers, label2) {
12418
+ context.helperFlags.add("unsupportedPlaceholder");
12419
+ const sourceTag = node.sourceTag ?? node.component.toLowerCase();
12420
+ return appendSwiftUIModifiers(
12421
+ [
12422
+ ...baseLines,
12423
+ `${indent11(level)}elitUnsupportedPlaceholder(label: ${quoteSwiftString(label2)}, sourceTag: ${quoteSwiftString(sourceTag)})`
12424
+ ],
12425
+ modifiers,
12426
+ level
12427
+ );
12428
+ }
12295
12429
  function renderSwiftUINode(node, level, context, hints = {}) {
12296
12430
  if (node.kind === "text") {
12297
12431
  return renderTextView(node, level, context);
@@ -12325,10 +12459,21 @@ function renderSwiftUINode(node, level, context, hints = {}) {
12325
12459
  const imageStyle = getStyleObject(node, context.resolvedStyles, context.styleResolveOptions);
12326
12460
  const objectFit = resolveNativeObjectFitStyle(imageStyle);
12327
12461
  const objectPosition = resolveNativeObjectPositionStyle(imageStyle);
12462
+ const imageArgs = [
12463
+ `source: ${quoteSwiftString(source2)}`,
12464
+ `label: ${quoteSwiftString(fallbackLabel)}`,
12465
+ `alt: ${alt ? quoteSwiftString(alt) : "nil"}`
12466
+ ];
12467
+ if (objectFit !== "cover") {
12468
+ imageArgs.push(`objectFit: ${quoteSwiftString(objectFit)}`);
12469
+ }
12470
+ if (objectPosition !== "center") {
12471
+ imageArgs.push(`objectPosition: ${quoteSwiftString(objectPosition)}`);
12472
+ }
12328
12473
  return appendSwiftUIModifiers(
12329
12474
  [
12330
12475
  ...baseLines,
12331
- `${indent11(level)}elitImageSurface(source: ${quoteSwiftString(source2)}, label: ${quoteSwiftString(fallbackLabel)}, alt: ${alt ? quoteSwiftString(alt) : "nil"}, objectFit: ${quoteSwiftString(objectFit)}, objectPosition: ${quoteSwiftString(objectPosition)})`
12476
+ `${indent11(level)}elitImageSurface(${imageArgs.join(", ")})`
12332
12477
  ],
12333
12478
  modifiers,
12334
12479
  level
@@ -12363,33 +12508,38 @@ function renderSwiftUINode(node, level, context, hints = {}) {
12363
12508
  return [...baseLines, ...appendSwiftUIModifiers(canvas2.lines, canvas2.modifiers, level)];
12364
12509
  }
12365
12510
  if (node.component === "WebView") {
12511
+ const source2 = resolveNativeSurfaceSource(node);
12512
+ if (!source2) {
12513
+ return renderSwiftUnsupportedFallback(node, level, context, baseLines, modifiers, "WebView");
12514
+ }
12366
12515
  context.helperFlags.add("webViewSurface");
12367
- const source2 = resolveNativeSurfaceSource(node) ?? "";
12368
12516
  const label3 = resolveNativeAccessibilityLabel(node) ?? "Web content";
12369
12517
  return appendSwiftUIModifiers(
12370
12518
  [
12371
12519
  ...baseLines,
12372
- `${indent11(level)}elitWebViewSurface(source: ${quoteSwiftString(source2)}, label: ${quoteSwiftString(label3)})`
12520
+ `${indent11(level)}ElitWebViewSurface(source: ${quoteSwiftString(source2)}, label: ${quoteSwiftString(label3)})`
12373
12521
  ],
12374
12522
  modifiers,
12375
12523
  level
12376
12524
  );
12377
12525
  }
12378
12526
  if (node.component === "Media") {
12527
+ const source2 = resolveNativeSurfaceSource(node);
12528
+ if (!source2) {
12529
+ return renderSwiftUnsupportedFallback(node, level, context, baseLines, modifiers, "Media");
12530
+ }
12379
12531
  context.helperFlags.add("mediaSurface");
12380
- const source2 = resolveNativeSurfaceSource(node) ?? "";
12381
12532
  const label3 = resolveNativeMediaLabel(node);
12382
12533
  const style2 = getStyleObject(node, context.resolvedStyles, context.styleResolveOptions);
12383
12534
  const objectFit = resolveNativeObjectFitStyle(style2);
12384
12535
  const objectPosition = resolveNativeObjectPositionStyle(style2);
12385
12536
  const autoPlay = toNativeBoolean(node.props.autoPlay ?? node.props.autoplay);
12386
- const loop = toNativeBoolean(node.props.loop);
12387
12537
  const muted = isNativeMuted(node);
12388
12538
  if (node.sourceTag === "audio") {
12389
12539
  return appendSwiftUIModifiers(
12390
12540
  [
12391
12541
  ...baseLines,
12392
- `${indent11(level)}ElitAudioSurface(source: ${quoteSwiftString(source2)}, label: ${quoteSwiftString(label3)}, autoPlay: ${autoPlay ? "true" : "false"}, loop: ${loop ? "true" : "false"}, muted: ${muted ? "true" : "false"})`
12542
+ `${indent11(level)}ElitAudioSurface(source: ${quoteSwiftString(source2)}, label: ${quoteSwiftString(label3)}, autoPlay: ${autoPlay ? "true" : "false"}, muted: ${muted ? "true" : "false"})`
12393
12543
  ],
12394
12544
  modifiers,
12395
12545
  level
@@ -12398,15 +12548,33 @@ function renderSwiftUINode(node, level, context, hints = {}) {
12398
12548
  const poster = resolveNativeVideoPoster(node);
12399
12549
  const controls = shouldNativeShowVideoControls(node);
12400
12550
  const playsInline = shouldNativePlayInline(node);
12551
+ const videoArgs = [
12552
+ `source: ${quoteSwiftString(source2)}`,
12553
+ `label: ${quoteSwiftString(label3)}`,
12554
+ `autoPlay: ${autoPlay ? "true" : "false"}`,
12555
+ `muted: ${muted ? "true" : "false"}`,
12556
+ `controls: ${controls ? "true" : "false"}`,
12557
+ `poster: ${poster ? quoteSwiftString(poster) : "nil"}`,
12558
+ `playsInline: ${playsInline ? "true" : "false"}`
12559
+ ];
12560
+ if (objectFit !== "cover") {
12561
+ videoArgs.push(`posterFit: ${quoteSwiftString(objectFit)}`);
12562
+ }
12563
+ if (objectPosition !== "center") {
12564
+ videoArgs.push(`posterPosition: ${quoteSwiftString(objectPosition)}`);
12565
+ }
12401
12566
  return appendSwiftUIModifiers(
12402
12567
  [
12403
12568
  ...baseLines,
12404
- `${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)})`
12569
+ `${indent11(level)}ElitVideoSurface(${videoArgs.join(", ")})`
12405
12570
  ],
12406
12571
  modifiers,
12407
12572
  level
12408
12573
  );
12409
12574
  }
12575
+ if (node.component === "Math") {
12576
+ return renderSwiftUnsupportedFallback(node, level, context, baseLines, modifiers, "Math");
12577
+ }
12410
12578
  if (node.component === "Cell") {
12411
12579
  const style2 = getStyleObject(node, context.resolvedStyles, context.styleResolveOptions);
12412
12580
  const cellHints = {
@@ -12432,6 +12600,8 @@ function buildSwiftUIHelpers(context) {
12432
12600
  if (context.helperFlags.has("bridge")) {
12433
12601
  helpers.push("");
12434
12602
  helpers.push("private enum ElitNativeBridge {");
12603
+ helpers.push(" static var onAction: ((String, String?, String?) -> Void)?");
12604
+ helpers.push(" static var onNavigate: ((String) -> Void)?");
12435
12605
  helpers.push(" static func dispatch(action: String? = nil, route: String? = nil, payloadJson: String? = nil) {");
12436
12606
  helpers.push(' print("ElitNativeBridge", action ?? "", route ?? "", payloadJson ?? "")');
12437
12607
  helpers.push(" }");
@@ -12456,6 +12626,13 @@ function buildSwiftUIHelpers(context) {
12456
12626
  helpers.push("}");
12457
12627
  }
12458
12628
  if (context.helperFlags.has("backgroundImage") || context.helperFlags.has("imagePlaceholder")) {
12629
+ helpers.push("");
12630
+ helpers.push("@ViewBuilder");
12631
+ helpers.push('private func elitBackgroundImage(_ image: Image, backgroundSize: String = "cover", backgroundPosition: String = "center", backgroundRepeat: String = "no-repeat") -> some View {');
12632
+ helpers.push(" image");
12633
+ helpers.push(" .resizable()");
12634
+ helpers.push(" .scaledToFill()");
12635
+ helpers.push("}");
12459
12636
  helpers.push("");
12460
12637
  helpers.push("@ViewBuilder");
12461
12638
  helpers.push('private func elitBackgroundImageSurface(source: String, objectFit: String = "cover", objectPosition: String = "center") -> some View {');
@@ -12463,9 +12640,7 @@ function buildSwiftUIHelpers(context) {
12463
12640
  helpers.push(" AsyncImage(url: url) { phase in");
12464
12641
  helpers.push(" switch phase {");
12465
12642
  helpers.push(" case .success(let image):");
12466
- helpers.push(" image");
12467
- helpers.push(" .resizable()");
12468
- helpers.push(" .scaledToFill()");
12643
+ helpers.push(' elitBackgroundImage(image, backgroundSize: objectFit, backgroundPosition: objectPosition, backgroundRepeat: "no-repeat")');
12469
12644
  helpers.push(" default:");
12470
12645
  helpers.push(" Color.clear");
12471
12646
  helpers.push(" }");
@@ -12476,7 +12651,7 @@ function buildSwiftUIHelpers(context) {
12476
12651
  helpers.push("}");
12477
12652
  helpers.push("");
12478
12653
  helpers.push("@ViewBuilder");
12479
- helpers.push('private func elitImageSurface(source: String, label: String, alt: String? = nil, objectFit: String = "cover", objectPosition: String = "center") -> some View {');
12654
+ helpers.push('private func elitImageSurface(source: String, label: String, alt: String?, objectFit: String = "cover", objectPosition: String = "center") -> some View {');
12480
12655
  helpers.push(" if source.isEmpty {");
12481
12656
  helpers.push(" Text(alt ?? label)");
12482
12657
  helpers.push(" .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center)");
@@ -12487,31 +12662,131 @@ function buildSwiftUIHelpers(context) {
12487
12662
  }
12488
12663
  if (context.helperFlags.has("webViewSurface")) {
12489
12664
  helpers.push("");
12490
- helpers.push("@ViewBuilder");
12491
- helpers.push("private func elitWebViewSurface(source: String, label: String) -> some View {");
12492
- helpers.push(" VStack(alignment: .leading, spacing: 8) {");
12493
- helpers.push(" Text(label)");
12494
- helpers.push(" Text(source)");
12495
- helpers.push(" .font(.caption)");
12496
- helpers.push(" .foregroundStyle(.secondary)");
12665
+ helpers.push("struct ElitWebViewSurface: UIViewRepresentable {");
12666
+ helpers.push(" let source: String");
12667
+ helpers.push(" let label: String?");
12668
+ helpers.push("");
12669
+ helpers.push(" func makeUIView(context: Context) -> WKWebView {");
12670
+ helpers.push(" let webView = WKWebView()");
12671
+ helpers.push(" webView.accessibilityLabel = label");
12672
+ helpers.push(" if let url = URL(string: source), !source.isEmpty { webView.load(URLRequest(url: url)) }");
12673
+ helpers.push(" return webView");
12497
12674
  helpers.push(" }");
12675
+ helpers.push("");
12676
+ helpers.push(" func updateUIView(_ uiView: WKWebView, context: Context) {}");
12498
12677
  helpers.push("}");
12499
12678
  }
12500
12679
  if (context.helperFlags.has("mediaSurface")) {
12680
+ helpers.push("");
12681
+ helpers.push("private func elitPosterAlignment(_ posterPosition: String) -> Alignment {");
12682
+ helpers.push(" switch posterPosition.lowercased() {");
12683
+ helpers.push(' case "top", "leading", "top-leading":');
12684
+ helpers.push(" return .topLeading");
12685
+ helpers.push(' case "bottom", "trailing", "bottom-trailing":');
12686
+ helpers.push(" return .bottomTrailing");
12687
+ helpers.push(' case "center":');
12688
+ helpers.push(" return .center");
12689
+ helpers.push(" default:");
12690
+ helpers.push(" return .center");
12691
+ helpers.push(" }");
12692
+ helpers.push("}");
12501
12693
  helpers.push("");
12502
12694
  helpers.push("@ViewBuilder");
12503
- 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 {');
12504
- helpers.push(" VStack(alignment: .leading, spacing: 8) {");
12505
- helpers.push(" if let poster, !poster.isEmpty {");
12506
- helpers.push(" elitBackgroundImageSurface(source: poster, objectFit: posterFit, objectPosition: posterPosition)");
12695
+ helpers.push("private func elitPosterImage(_ image: Image, posterFit: String, posterPosition: String) -> some View {");
12696
+ helpers.push(" let resizable = image.resizable()");
12697
+ helpers.push(" switch posterFit.lowercased() {");
12698
+ helpers.push(' case "contain":');
12699
+ helpers.push(" return AnyView(resizable.scaledToFit().frame(maxWidth: .infinity, maxHeight: .infinity, alignment: elitPosterAlignment(posterPosition)))");
12700
+ helpers.push(' case "fill", "cover":');
12701
+ helpers.push(" return AnyView(resizable.scaledToFill().frame(maxWidth: .infinity, maxHeight: .infinity, alignment: elitPosterAlignment(posterPosition)))");
12702
+ helpers.push(" default:");
12703
+ helpers.push(" return AnyView(resizable.scaledToFill())");
12704
+ helpers.push(" }");
12705
+ helpers.push("}");
12706
+ helpers.push("");
12707
+ helpers.push("struct ElitVideoPlayerController: UIViewControllerRepresentable {");
12708
+ helpers.push(" let source: String");
12709
+ helpers.push(" let autoPlay: Bool");
12710
+ helpers.push(" let muted: Bool");
12711
+ helpers.push(" let controls: Bool");
12712
+ helpers.push(" let playsInline: Bool");
12713
+ helpers.push("");
12714
+ helpers.push(" func makeUIViewController(context: Context) -> AVPlayerViewController {");
12715
+ helpers.push(" let controller = AVPlayerViewController()");
12716
+ helpers.push(" if let url = URL(string: source) {");
12717
+ helpers.push(" let player = AVPlayer(url: url)");
12718
+ helpers.push(" let resolvedPlayer = player");
12719
+ helpers.push(" resolvedPlayer.isMuted = muted");
12720
+ helpers.push(" controller.player = resolvedPlayer");
12721
+ helpers.push(" if autoPlay { resolvedPlayer.play() }");
12507
12722
  helpers.push(" }");
12508
- helpers.push(" Text(label)");
12723
+ helpers.push(" controller.showsPlaybackControls = controls");
12724
+ helpers.push(" controller.entersFullScreenWhenPlaybackBegins = !playsInline");
12725
+ helpers.push(" return controller");
12509
12726
  helpers.push(" }");
12727
+ helpers.push("");
12728
+ helpers.push(" func updateUIViewController(_ controller: AVPlayerViewController, context: Context) {}");
12510
12729
  helpers.push("}");
12730
+ helpers.push("");
12731
+ helpers.push("struct ElitVideoSurface: View {");
12732
+ helpers.push(" let source: String");
12733
+ helpers.push(" let label: String");
12734
+ helpers.push(" let autoPlay: Bool");
12735
+ helpers.push(" let muted: Bool");
12736
+ helpers.push(" let controls: Bool");
12737
+ helpers.push(" let poster: String?");
12738
+ helpers.push(" let playsInline: Bool");
12739
+ helpers.push(" let posterFit: String");
12740
+ helpers.push(" let posterPosition: String");
12741
+ helpers.push("");
12742
+ helpers.push(" var body: some View {");
12743
+ helpers.push(" ZStack {");
12744
+ helpers.push(" if let poster, !poster.isEmpty, let posterURL = URL(string: poster) {");
12745
+ helpers.push(" AsyncImage(url: posterURL) { phase in");
12746
+ helpers.push(" switch phase {");
12747
+ helpers.push(" case .success(let image):");
12748
+ helpers.push(" elitPosterImage(image, posterFit: posterFit, posterPosition: posterPosition)");
12749
+ helpers.push(" default:");
12750
+ helpers.push(" Color.clear");
12751
+ helpers.push(" }");
12752
+ helpers.push(" }");
12753
+ helpers.push(" }");
12754
+ helpers.push(" ElitVideoPlayerController(source: source, autoPlay: autoPlay, muted: muted, controls: controls, playsInline: playsInline)");
12755
+ helpers.push(" .accessibilityLabel(label)");
12756
+ helpers.push(" }");
12757
+ helpers.push(" }");
12758
+ helpers.push("}");
12759
+ helpers.push("");
12760
+ helpers.push("struct ElitAudioSurface: View {");
12761
+ helpers.push(" let source: String");
12762
+ helpers.push(" let label: String");
12763
+ helpers.push(" let autoPlay: Bool");
12764
+ helpers.push(" let muted: Bool");
12765
+ helpers.push("");
12766
+ helpers.push(" var body: some View {");
12767
+ helpers.push(" VStack {");
12768
+ helpers.push(" if let url = URL(string: source), !source.isEmpty {");
12769
+ helpers.push(" AVPlayer(url: url).let { resolvedPlayer in");
12770
+ helpers.push(" resolvedPlayer.isMuted = muted");
12771
+ helpers.push(" if autoPlay { resolvedPlayer.play() }");
12772
+ helpers.push(" }");
12773
+ helpers.push(" }");
12774
+ helpers.push(' Label(label, systemImage: "waveform")');
12775
+ helpers.push(" .accessibilityLabel(label)");
12776
+ helpers.push(" }");
12777
+ helpers.push(" }");
12778
+ helpers.push("}");
12779
+ }
12780
+ if (context.helperFlags.has("unsupportedPlaceholder")) {
12511
12781
  helpers.push("");
12512
12782
  helpers.push("@ViewBuilder");
12513
- helpers.push("private func ElitAudioSurface(source: String, label: String, autoPlay: Bool, loop: Bool, muted: Bool) -> some View {");
12514
- helpers.push(' Label(label, systemImage: "waveform")');
12783
+ helpers.push("private func elitUnsupportedPlaceholder(label: String, sourceTag: String) -> some View {");
12784
+ helpers.push(" VStack(spacing: 8) {");
12785
+ helpers.push(" Text(label)");
12786
+ helpers.push(" Text(sourceTag)");
12787
+ helpers.push(" .font(.caption)");
12788
+ helpers.push(" .foregroundStyle(.secondary)");
12789
+ helpers.push(" }");
12515
12790
  helpers.push("}");
12516
12791
  }
12517
12792
  return helpers;
@@ -12539,17 +12814,30 @@ function renderSwiftUI(input2, options = {}) {
12539
12814
  resolvedStyles: styleData.resolvedStyles,
12540
12815
  styleContexts: styleData.styleContexts
12541
12816
  };
12542
- const bodyLines = tree.roots.length === 1 ? renderSwiftUINode(tree.roots[0], 2, context, { availableWidth: styleResolveOptions.viewportWidth, availableHeight: styleResolveOptions.viewportHeight }) : [
12817
+ const singleRoot = tree.roots.length === 1 ? tree.roots[0] : null;
12818
+ const isSingleScreenRoot = singleRoot !== null && singleRoot.kind === "element" && singleRoot.component === "Screen";
12819
+ const innerLines = tree.roots.length === 1 ? renderSwiftUINode(tree.roots[0], 2, context, { availableWidth: styleResolveOptions.viewportWidth, availableHeight: styleResolveOptions.viewportHeight }) : [
12543
12820
  " VStack(alignment: .leading, spacing: 0) {",
12544
12821
  ...renderSwiftUIChildren(tree.roots, 3, context, renderSwiftUINode, "VStack", void 0, { availableWidth: styleResolveOptions.viewportWidth, availableHeight: styleResolveOptions.viewportHeight }),
12545
12822
  " }"
12546
12823
  ];
12824
+ const bodyLines = isSingleScreenRoot ? [
12825
+ " ScrollView {",
12826
+ ...innerLines.map((line) => " " + line),
12827
+ " }"
12828
+ ] : innerLines;
12547
12829
  const lines = [];
12548
12830
  if (resolvedOptions.includeImports) {
12549
12831
  lines.push("import SwiftUI");
12550
12832
  if (context.helperFlags.has("backgroundImage") || context.helperFlags.has("imagePlaceholder") || context.helperFlags.has("openUrlHandler")) {
12551
12833
  lines.push("import Foundation");
12552
12834
  }
12835
+ if (context.helperFlags.has("webViewSurface")) {
12836
+ lines.push("import WebKit");
12837
+ }
12838
+ if (context.helperFlags.has("mediaSurface")) {
12839
+ lines.push("import AVKit");
12840
+ }
12553
12841
  lines.push("");
12554
12842
  }
12555
12843
  lines.push(`struct ${resolvedOptions.structName}: View {`);