peachsim 0.1.628 → 0.1.630

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 (111) hide show
  1. package/README.md +8 -4
  2. package/cli/bridge-flow-runner.ts +10 -3
  3. package/cli/cli-update.ts +2 -7
  4. package/cli/cloud-test-tunnel.ts +16 -3
  5. package/cli/commands/config.ts +1 -1
  6. package/cli/commands/control.ts +28 -3
  7. package/cli/commands/daemon-mac-app.ts +4 -2
  8. package/cli/commands/daemon.ts +4 -4
  9. package/cli/commands/device.ts +2 -3
  10. package/cli/commands/inspect/actions.ts +125 -90
  11. package/cli/commands/inspect/core.ts +5 -0
  12. package/cli/commands/inspect.ts +27 -13
  13. package/cli/commands/platform.ts +1 -1
  14. package/cli/commands/screenshot-layers.ts +1 -1
  15. package/cli/commands/screenshot.ts +1 -1
  16. package/cli/commands/skills.ts +0 -31
  17. package/cli/drivers/playwright-provisioning.ts +3 -2
  18. package/cli/drivers/playwright-sim-host.ts +25 -9
  19. package/cli/main.ts +8 -2
  20. package/cli/outbound-endpoints.ts +0 -4
  21. package/detox/index.ts +74 -43
  22. package/dist-lib/agent-daemon-client.cjs +1 -1
  23. package/dist-lib/agent-events.cjs +1 -1
  24. package/dist-lib/agent-identity.cjs +1 -1
  25. package/dist-lib/agent-sessions.cjs +1 -1
  26. package/dist-lib/attached-projects.cjs +1 -1
  27. package/dist-lib/auth/shared-session.cjs +1 -1
  28. package/dist-lib/backend-origin.cjs +1 -1
  29. package/dist-lib/beta.cjs +1 -1
  30. package/dist-lib/beta.mjs +1 -1
  31. package/dist-lib/bridge-constants.cjs +1 -1
  32. package/dist-lib/bridge-contract-input.cjs +1 -1
  33. package/dist-lib/bridge-contract-input.mjs +1 -1
  34. package/dist-lib/bridge-contract.cjs +1 -1
  35. package/dist-lib/bridge-contract.mjs +1 -1
  36. package/dist-lib/capture-contract.cjs +1 -1
  37. package/dist-lib/capture-contract.mjs +1 -1
  38. package/dist-lib/cli-constants.cjs +1 -1
  39. package/dist-lib/cloud-contract.cjs +1 -1
  40. package/dist-lib/cloud-contract.mjs +1 -1
  41. package/dist-lib/cloud-test-args.cjs +1 -1
  42. package/dist-lib/cloud-test-args.mjs +1 -1
  43. package/dist-lib/cloud.cjs +1 -1
  44. package/dist-lib/cloud.mjs +1 -1
  45. package/dist-lib/config.cjs +1 -1
  46. package/dist-lib/detox/index.cjs +129 -27
  47. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  48. package/dist-lib/home-paths.cjs +1 -1
  49. package/dist-lib/host/bridge-host.cjs +290 -315
  50. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  51. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  52. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  53. package/dist-lib/host/replacement-module-handler.cjs +1 -1
  54. package/dist-lib/host/websocket-proxy.cjs +1 -1
  55. package/dist-lib/index.cjs +253 -121
  56. package/dist-lib/jump-to-source-babel.cjs +1 -1
  57. package/dist-lib/jump-to-source-native.cjs +1 -1
  58. package/dist-lib/{vite-kotlin.cjs → kotlin-host.cjs} +130 -19
  59. package/dist-lib/menu.cjs +1 -1
  60. package/dist-lib/menu.mjs +1 -1
  61. package/dist-lib/metro-fingerprint-registry.cjs +1 -1
  62. package/dist-lib/metro-fingerprint-registry.mjs +1 -1
  63. package/dist-lib/metro-production-bundle.cjs +1 -1
  64. package/dist-lib/metro-production-bundle.mjs +1 -1
  65. package/dist-lib/metro.cjs +132 -9
  66. package/dist-lib/native-app-identity.cjs +278 -0
  67. package/dist-lib/native-app-identity.mjs +245 -0
  68. package/dist-lib/profiles.cjs +1 -1
  69. package/dist-lib/public-brand.cjs +1 -1
  70. package/dist-lib/react-native-host-modules.cjs +1 -1
  71. package/dist-lib/react-native-host-modules.mjs +1 -1
  72. package/dist-lib/render-mode.cjs +1 -1
  73. package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
  74. package/dist-lib/sdk.cjs +110 -87
  75. package/dist-lib/sdk.mjs +110 -87
  76. package/dist-lib/skills.cjs +841 -643
  77. package/dist-lib/swift-compile.cjs +1 -1
  78. package/dist-lib/swift-compile.mjs +1 -1
  79. package/dist-lib/swift-package.cjs +1 -1
  80. package/dist-lib/swift-package.mjs +1 -1
  81. package/dist-lib/swift-submit.cjs +1 -1
  82. package/dist-lib/swift-submit.mjs +1 -1
  83. package/dist-lib/swift.cjs +282 -177
  84. package/dist-lib/vite-swift.cjs +1 -1
  85. package/dist-lib/vite.cjs +11 -28
  86. package/kotlin/README.md +32 -4
  87. package/kotlin/fixtures/counter/Counter.kt +26 -0
  88. package/kotlin/fixtures/counter/CounterScreen.kt +40 -0
  89. package/kotlin/fixtures/headless-counter/Headless.kt +228 -0
  90. package/kotlin/fixtures/runtime-state/RuntimeState.kt +200 -0
  91. package/kotlin/fork/LICENSE +178 -0
  92. package/kotlin/fork/NOTICE +25 -0
  93. package/kotlin/fork/README.md +59 -0
  94. package/kotlin/fork/build.sh +128 -0
  95. package/kotlin/fork/compose-worker-globals.patch +96 -0
  96. package/kotlin/fork/fork.json +33 -0
  97. package/kotlin/fork/publish.ts +77 -0
  98. package/kotlin/fork/skiko-worker-clock.patch +33 -0
  99. package/kotlin/toolchain.json +288 -0
  100. package/package.json +12 -5
  101. package/src/automatic-update-policy.ts +17 -0
  102. package/src/host/bridge-host.ts +3 -1
  103. package/src/{vite-plugin-kotlin.ts → kotlin-host.ts} +155 -12
  104. package/src/metro-plugin.ts +18 -0
  105. package/src/native-app-identity.ts +376 -0
  106. package/src/native-firebase-config.ts +90 -0
  107. package/src/screenshots/frame-compose.ts +5 -2
  108. package/src/screenshots/registry.ts +1 -1
  109. package/src/screenshots/schema.ts +2 -2
  110. package/src/vite-plugin-one.ts +11 -28
  111. package/src/vite-plugin.ts +6 -1
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.628 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.630 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
3
  "use strict";
4
4
  var __create = Object.create;
@@ -1880,10 +1880,12 @@ var devices = {
1880
1880
  posture: "closed",
1881
1881
  supportedPostures: ["closed", "open"]
1882
1882
  }),
1883
+ // the ios 27.1 simulator's camera occlusion region: 37pt, 29 1/3 in from
1884
+ // the top and trailing edges
1883
1885
  cameraCutout: {
1884
1886
  diameter: 37,
1885
- top: 29,
1886
- trailing: 29
1887
+ top: 88 / 3,
1888
+ trailing: 88 / 3
1887
1889
  }
1888
1890
  },
1889
1891
  "ipad-pro-11": {
@@ -2232,7 +2234,7 @@ function rotateDevice(device, side) {
2232
2234
  const barrelProtrusion = device.housing?.hingeBarrel?.protrusion ?? 0;
2233
2235
  if (side === "left") insets.top += barrelProtrusion;
2234
2236
  else insets.bottom += barrelProtrusion;
2235
- const safeArea = device.model === "ipad-pro-11" ? { top: 10, bottom: 20, left: 0, right: 0 } : device.model === "iphone-duo" ? { top: 0, bottom: 20, left: 0, right: 84 } : device.platform === "ios" && device.homeIndicatorHeight > 0 ? {
2237
+ const safeArea = device.model === "ipad-pro-11" ? { top: 10, bottom: 20, left: 0, right: 0 } : device.model === "iphone-duo" ? { top: 0, bottom: 34, left: 0, right: 84 } : device.platform === "ios" && device.homeIndicatorHeight > 0 ? {
2236
2238
  top: 0,
2237
2239
  bottom: 20,
2238
2240
  left: device.safeAreaInsets.top,
@@ -2267,10 +2269,14 @@ function rotateDevice(device, side) {
2267
2269
  // the bars stay on the interface's top and bottom; a cutout's inset moves
2268
2270
  // to whichever side the cutout turned to.
2269
2271
  safeAreaInsets: side === "left" ? safeArea : { ...safeArea, left: safeArea.right, right: safeArea.left },
2270
- statusBarHeight: device.platform === "ios" && device.model !== "ipad-pro-11" && device.model !== "iphone-duo" ? 0 : device.statusBarHeight,
2271
- homeIndicatorHeight: device.platform === "ios" && device.homeIndicatorHeight > 0 ? 20 : device.homeIndicatorHeight
2272
+ statusBarHeight: device.platform === "ios" && device.model !== "ipad-pro-11" ? 0 : device.statusBarHeight,
2273
+ // the indicator's band is the landscape bottom inset
2274
+ homeIndicatorHeight: device.platform === "ios" && device.homeIndicatorHeight > 0 ? safeArea.bottom : device.homeIndicatorHeight
2272
2275
  };
2273
2276
  }
2277
+ function defaultLandscapeSide(model, posture) {
2278
+ return model === "iphone-duo" && resolveDevicePosture(model, posture) === "closed" ? "right" : "left";
2279
+ }
2274
2280
  function isPadIdiom(spec) {
2275
2281
  return spec.model === "ipad-pro-11";
2276
2282
  }
@@ -2304,67 +2310,16 @@ function deviceSizeClasses(model, orientation, posture) {
2304
2310
  function withOsVersionOverride(spec, osVersion) {
2305
2311
  return osVersion && spec.platform === "ios" ? { ...spec, osVersion, iosVersion: osVersion } : spec;
2306
2312
  }
2307
- function getDevice(model, posture, orientation, landscapeSide = "left") {
2313
+ function getDevice(model, posture, orientation, landscapeSide) {
2308
2314
  const device = devices[model];
2315
+ const side = landscapeSide ?? defaultLandscapeSide(model, posture);
2309
2316
  if (!device.supportedPostures) {
2310
- return orientation === "landscape" && model !== "canvas-workspace" ? rotateDevice(device, landscapeSide) : device;
2317
+ return orientation === "landscape" && model !== "canvas-workspace" ? rotateDevice(device, side) : device;
2311
2318
  }
2312
2319
  const resolvedPosture = resolveDevicePosture(model, posture);
2313
2320
  const resolvedOrientation = orientation ?? deviceDefaultOrientation(model, resolvedPosture);
2314
2321
  if (resolvedPosture === "closed") {
2315
- if (resolvedOrientation === "portrait") return device;
2316
- const insets = device.frameInsets;
2317
- const radii = device.cornerRadius;
2318
- const body = device.frameCornerRadius ?? resolveDeviceFrameCorners(device).frameRadius;
2319
- const housing = device.housing;
2320
- const protrusion = housing?.hingeBarrel?.protrusion ?? 0;
2321
- return {
2322
- ...device,
2323
- width: device.height,
2324
- height: device.width,
2325
- orientation: "landscape",
2326
- cornerRadius: {
2327
- topLeft: radii.topRight,
2328
- topRight: radii.bottomRight,
2329
- bottomRight: radii.bottomLeft,
2330
- bottomLeft: radii.topLeft
2331
- },
2332
- continuousCornerRadius: {
2333
- topLeft: device.continuousCornerRadius.topRight,
2334
- topRight: device.continuousCornerRadius.bottomRight,
2335
- bottomRight: device.continuousCornerRadius.bottomLeft,
2336
- bottomLeft: device.continuousCornerRadius.topLeft
2337
- },
2338
- frameInsets: {
2339
- top: insets.right,
2340
- right: insets.bottom,
2341
- bottom: insets.left + protrusion,
2342
- left: insets.top
2343
- },
2344
- frameCornerRadius: {
2345
- topLeft: body.topRight,
2346
- topRight: body.bottomRight,
2347
- bottomRight: body.bottomLeft,
2348
- bottomLeft: body.topLeft
2349
- },
2350
- housing: housing ? {
2351
- rail: {
2352
- top: housing.rail.right,
2353
- right: housing.rail.bottom,
2354
- bottom: housing.rail.left,
2355
- left: housing.rail.top
2356
- },
2357
- hingeBarrel: null
2358
- } : void 0,
2359
- cameraCutout: device.cameraCutout ? {
2360
- diameter: device.cameraCutout.diameter,
2361
- top: device.cameraCutout.top,
2362
- leading: device.cameraCutout.trailing
2363
- } : null,
2364
- safeAreaInsets: { top: 0, bottom: 34, left: 84, right: 0 },
2365
- // vertically compact, so the status bar is hidden.
2366
- statusBarHeight: 0
2367
- };
2322
+ return resolvedOrientation === "portrait" ? device : rotateDevice(device, side);
2368
2323
  }
2369
2324
  const isRotatedPortrait = resolvedOrientation === "portrait";
2370
2325
  return {
@@ -3189,6 +3144,10 @@ function getDefaults() {
3189
3144
  overrides.deviceModel ?? DEFAULT_DEVICE,
3190
3145
  defaults2.posture
3191
3146
  );
3147
+ defaults2.landscapeSide = overrides.landscapeSide ?? defaultLandscapeSide(
3148
+ overrides.deviceModel ?? DEFAULT_DEVICE,
3149
+ defaults2.posture
3150
+ );
3192
3151
  return defaults2;
3193
3152
  }
3194
3153
 
@@ -3407,6 +3366,10 @@ for (const key of PERSISTED_KEYS) {
3407
3366
  var _state = { ...defaults, ..._persisted };
3408
3367
  var _listeners = [];
3409
3368
  var _deviceCache = null;
3369
+ function arrivingLandscapeSide(prev, next) {
3370
+ const enters = next.orientation === "landscape" && (prev.orientation !== "landscape" || prev.posture !== next.posture || prev.deviceModel !== next.deviceModel);
3371
+ return enters ? defaultLandscapeSide(next.deviceModel, next.posture) : next.landscapeSide;
3372
+ }
3410
3373
  function notifyListeners() {
3411
3374
  for (const fn of _listeners) fn();
3412
3375
  }
@@ -3422,7 +3385,7 @@ function updateSetting(key, value) {
3422
3385
  if (typeof value !== "string" || !isDevicePosture(value)) return false;
3423
3386
  const nextPosture = resolveDevicePosture(_state.deviceModel, value);
3424
3387
  if (_state.posture === nextPosture) return false;
3425
- _state = {
3388
+ const next = {
3426
3389
  ..._state,
3427
3390
  posture: nextPosture,
3428
3391
  orientation: orientationAfterPostureChange(
@@ -3431,11 +3394,13 @@ function updateSetting(key, value) {
3431
3394
  nextPosture
3432
3395
  )
3433
3396
  };
3397
+ _state = { ...next, landscapeSide: arrivingLandscapeSide(_state, next) };
3434
3398
  _deviceCache = null;
3435
3399
  return true;
3436
3400
  }
3437
3401
  if (key === "deviceModel" && _state.deviceModel === value) return false;
3438
3402
  if (_state[key] === value) return false;
3403
+ const prev = _state;
3439
3404
  _state = { ..._state, [key]: value };
3440
3405
  if (key === "deviceModel") {
3441
3406
  const nextPosture = resolveDevicePosture(_state.deviceModel);
@@ -3445,6 +3410,8 @@ function updateSetting(key, value) {
3445
3410
  orientation: deviceDefaultOrientation(_state.deviceModel, nextPosture)
3446
3411
  };
3447
3412
  }
3413
+ if (key !== "landscapeSide")
3414
+ _state = { ..._state, landscapeSide: arrivingLandscapeSide(prev, _state) };
3448
3415
  if (key === "deviceModel" || key === "orientation" || key === "landscapeSide" || key === "osVersionOverride")
3449
3416
  _deviceCache = null;
3450
3417
  return true;
@@ -3524,6 +3491,11 @@ var settingsStore = {
3524
3491
  next.orientation = nextOrientation;
3525
3492
  changed = true;
3526
3493
  }
3494
+ const nextSide = overrides.landscapeSide ?? arrivingLandscapeSide(_state, next);
3495
+ if (next.landscapeSide !== nextSide) {
3496
+ next.landscapeSide = nextSide;
3497
+ changed = true;
3498
+ }
3527
3499
  if (changed) {
3528
3500
  _state = next;
3529
3501
  _deviceCache = null;
@@ -6739,6 +6711,10 @@ var COLOR_STYLE_PROPS = /* @__PURE__ */ new Set([
6739
6711
  "borderRightColor",
6740
6712
  "borderStartColor",
6741
6713
  "borderEndColor",
6714
+ "borderBlockColor",
6715
+ "borderBlockStartColor",
6716
+ "borderBlockEndColor",
6717
+ "overlayColor",
6742
6718
  "textDecorationColor",
6743
6719
  "textShadowColor",
6744
6720
  "tintColor",
@@ -7481,12 +7457,14 @@ function isMetroAssetRegistryModulePath(modulePath) {
7481
7457
  return modulePath.includes("polyfill:assets-registry") || modulePath.includes("@react-native/assets-registry/registry") || modulePath.includes("assets-registry/registry") || modulePath.includes("react-native/asset-registry") || modulePath.includes("react-native/src/asset-registry");
7482
7458
  }
7483
7459
 
7460
+ // ../peach-compat/src/stubs/browser-object-url.ts
7461
+ var BrowserURL = globalThis.URL;
7462
+ var createBrowserObjectURL = BrowserURL.createObjectURL.bind(BrowserURL);
7463
+ var revokeBrowserObjectURL = BrowserURL.revokeObjectURL.bind(BrowserURL);
7464
+
7484
7465
  // ../peach-engine/src/native-globals.ts
7485
7466
  var nativeGlobals = globalThis;
7486
7467
  var NativeBlob = nativeGlobals.Blob;
7487
- var NativeURL = nativeGlobals.URL;
7488
- var nativeCreateObjectURL = URL.createObjectURL.bind(URL);
7489
- var nativeRevokeObjectURL = URL.revokeObjectURL.bind(URL);
7490
7468
  var NativeTextDecoder = nativeGlobals.TextDecoder;
7491
7469
  var NativeTextEncoder = nativeGlobals.TextEncoder;
7492
7470
  var NativeXMLHttpRequest = nativeGlobals.XMLHttpRequest;
@@ -7508,36 +7486,6 @@ var nativeMatchMedia = typeof window !== "undefined" && typeof window.matchMedia
7508
7486
  return false;
7509
7487
  }
7510
7488
  }));
7511
- function installBlobLock() {
7512
- const desc = Object.getOwnPropertyDescriptor(URL, "createObjectURL");
7513
- if (desc && desc.configurable === false && desc.get) {
7514
- return;
7515
- }
7516
- try {
7517
- Object.defineProperty(URL, "createObjectURL", {
7518
- configurable: false,
7519
- enumerable: false,
7520
- get() {
7521
- return nativeCreateObjectURL;
7522
- },
7523
- set(_) {
7524
- }
7525
- });
7526
- } catch {
7527
- }
7528
- try {
7529
- Object.defineProperty(URL, "revokeObjectURL", {
7530
- configurable: false,
7531
- enumerable: false,
7532
- get() {
7533
- return nativeRevokeObjectURL;
7534
- },
7535
- set(_) {
7536
- }
7537
- });
7538
- } catch {
7539
- }
7540
- }
7541
7489
  function installMatchMediaLock() {
7542
7490
  const g = globalThis;
7543
7491
  const desc = Object.getOwnPropertyDescriptor(g, "matchMedia");
@@ -7582,9 +7530,6 @@ function installNetworkingLock() {
7582
7530
  installCodecOrNetGlobalLock("XMLHttpRequest", NativeXMLHttpRequest);
7583
7531
  installCodecOrNetGlobalLock("FormData", NativeFormData);
7584
7532
  }
7585
- function installURLLock() {
7586
- installCodecOrNetGlobalLock("URL", NativeURL);
7587
- }
7588
7533
  function restoreNativeBlobHelpers() {
7589
7534
  const g = globalThis;
7590
7535
  if (g.Blob !== NativeBlob) {
@@ -7593,11 +7538,9 @@ function restoreNativeBlobHelpers() {
7593
7538
  } catch {
7594
7539
  }
7595
7540
  }
7596
- installBlobLock();
7597
7541
  installTextCodecLock();
7598
7542
  installMatchMediaLock();
7599
7543
  installNetworkingLock();
7600
- installURLLock();
7601
7544
  }
7602
7545
  restoreNativeBlobHelpers();
7603
7546
  var LOCKED_GLOBALS = /* @__PURE__ */ new Set([
@@ -7605,8 +7548,7 @@ var LOCKED_GLOBALS = /* @__PURE__ */ new Set([
7605
7548
  "TextEncoder",
7606
7549
  "Blob",
7607
7550
  "XMLHttpRequest",
7608
- "FormData",
7609
- "URL"
7551
+ "FormData"
7610
7552
  ]);
7611
7553
  function patchedDefineProperty(target, key, descriptor) {
7612
7554
  const onGlobal = target === globalThis;
@@ -10080,6 +10022,57 @@ var INLINE_STYLE_PROP_KEYS = [
10080
10022
  "transform"
10081
10023
  ];
10082
10024
  var INLINE_STYLE_PROP_SET = new Set(INLINE_STYLE_PROP_KEYS);
10025
+ var FABRIC_STYLE_PROP_SET = /* @__PURE__ */ new Set([
10026
+ ...INLINE_STYLE_PROP_SET,
10027
+ "insetBlock",
10028
+ "insetBlockEnd",
10029
+ "insetBlockStart",
10030
+ "insetInline",
10031
+ "insetInlineEnd",
10032
+ "insetInlineStart",
10033
+ "marginBlock",
10034
+ "marginBlockEnd",
10035
+ "marginBlockStart",
10036
+ "marginInline",
10037
+ "marginInlineEnd",
10038
+ "marginInlineStart",
10039
+ "paddingBlock",
10040
+ "paddingBlockEnd",
10041
+ "paddingBlockStart",
10042
+ "paddingInline",
10043
+ "paddingInlineEnd",
10044
+ "paddingInlineStart",
10045
+ "experimental_backgroundSize",
10046
+ "experimental_backgroundPosition",
10047
+ "experimental_backgroundRepeat",
10048
+ "backfaceVisibility",
10049
+ "borderBlockColor",
10050
+ "borderBlockEndColor",
10051
+ "borderBlockStartColor",
10052
+ "borderCurve",
10053
+ "borderEndEndRadius",
10054
+ "borderEndStartRadius",
10055
+ "borderStartEndRadius",
10056
+ "borderStartStartRadius",
10057
+ "borderTopEndRadius",
10058
+ "borderTopStartRadius",
10059
+ "cursor",
10060
+ "userSelect",
10061
+ "verticalAlign",
10062
+ "overlayColor",
10063
+ "resizeMode",
10064
+ "objectFit"
10065
+ ]);
10066
+ function mergeFabricRawProps(hostProps, rawProps) {
10067
+ const props = { ...hostProps };
10068
+ const style = {};
10069
+ for (const [key, value] of Object.entries(rawProps)) {
10070
+ if (FABRIC_STYLE_PROP_SET.has(key)) style[key] = value;
10071
+ else props[key] = value;
10072
+ }
10073
+ props.style = [hostProps.style, style];
10074
+ return props;
10075
+ }
10083
10076
  function extractOrderedStyleInput(type, props) {
10084
10077
  let out = null;
10085
10078
  let pending = null;
@@ -10395,6 +10388,9 @@ function resolveStyleValue(value, key) {
10395
10388
  if (typeof value === "boolean") return value;
10396
10389
  if (typeof value !== "object") return value;
10397
10390
  if (key && COLOR_STYLE_PROPS.has(key)) {
10391
+ if (value.space === "srgb") {
10392
+ return `rgba(${value.r * 255},${value.g * 255},${value.b * 255},${value.a})`;
10393
+ }
10398
10394
  const platformColor = resolveAndroidPlatformColor(value);
10399
10395
  if (platformColor) return normalizeColorStyleValue(key, platformColor);
10400
10396
  }
@@ -11624,7 +11620,8 @@ function attachNativeHostInstanceFields(node) {
11624
11620
  ["_nativeTag", node.id],
11625
11621
  ["__viewTag", node.id],
11626
11622
  ["__internalInstanceHandle", { stateNode: { node } }],
11627
- ["_viewConfig", viewConfig]
11623
+ ["_viewConfig", viewConfig],
11624
+ ["__viewConfig", viewConfig]
11628
11625
  ]) {
11629
11626
  Object.defineProperty(node, key, {
11630
11627
  value,
@@ -11779,6 +11776,8 @@ var SootSimNode = class _SootSimNode {
11779
11776
  id;
11780
11777
  type;
11781
11778
  props;
11779
+ lastReactProps;
11780
+ fabricNativeProps = null;
11782
11781
  // exact Tamagui token provenance for this node's resolved style, read from
11783
11782
  // the host style layers on ingestion (before flatten/resolve). empty for
11784
11783
  // ordinary React Native nodes; frozen into
@@ -11836,8 +11835,6 @@ var SootSimNode = class _SootSimNode {
11836
11835
  _scrollOffsetX = 0;
11837
11836
  _scrollOffsetY = 0;
11838
11837
  _scrollOffsetListeners = null;
11839
- _scrollFollowContentEndX = false;
11840
- _scrollFollowContentEndY = false;
11841
11838
  _maintainVisibleContentPositionAnchor = null;
11842
11839
  _maintainVisibleContentPositionAnchorFromMutation = false;
11843
11840
  // a scroll content container's children extent (engine/scroll.ts), valid
@@ -12075,6 +12072,19 @@ var SootSimNode = class _SootSimNode {
12075
12072
  return this.unstable_getBoundingClientRect();
12076
12073
  }
12077
12074
  // RN ref compatibility
12075
+ commitFabricRawProps(props) {
12076
+ let root = this;
12077
+ while (root.parent) root = root.parent;
12078
+ if (root === this || root.type !== "root") return null;
12079
+ this.updateProps(
12080
+ mergeFabricRawProps(
12081
+ { ...this.props, style: flattenStyle2(this.props.style) },
12082
+ props
12083
+ ),
12084
+ "native"
12085
+ );
12086
+ return root;
12087
+ }
12078
12088
  __setNativePropsImpl;
12079
12089
  __dispatchCommandImpl;
12080
12090
  markAnimatedNativePropKeys(props) {
@@ -12321,7 +12331,6 @@ var SootSimNode = class _SootSimNode {
12321
12331
  return;
12322
12332
  }
12323
12333
  if (this.scrollOffsetX === next) return;
12324
- this._scrollFollowContentEndX = false;
12325
12334
  this.scrollOffsetX = next;
12326
12335
  this.__scroll?.syncExternalOffset?.();
12327
12336
  this.markImperativeScrollDirty();
@@ -12342,7 +12351,6 @@ var SootSimNode = class _SootSimNode {
12342
12351
  return;
12343
12352
  }
12344
12353
  if (this.scrollOffsetY === next) return;
12345
- this._scrollFollowContentEndY = false;
12346
12354
  this.scrollOffsetY = next;
12347
12355
  this.__scroll?.syncExternalOffset?.();
12348
12356
  this.markImperativeScrollDirty();
@@ -12381,6 +12389,7 @@ var SootSimNode = class _SootSimNode {
12381
12389
  }
12382
12390
  }
12383
12391
  if (this.__scroll?.scrollToOffset) {
12392
+ this._flushPendingLayout();
12384
12393
  this.__scroll.scrollToOffset({
12385
12394
  ...hasX ? { x: nextLeft } : {},
12386
12395
  ...hasY ? { y: nextTop } : {},
@@ -12396,8 +12405,6 @@ var SootSimNode = class _SootSimNode {
12396
12405
  if (this.scrollOffsetX === nextLeft && this.scrollOffsetY === nextTop) {
12397
12406
  return;
12398
12407
  }
12399
- const requestedLeft = nextLeft;
12400
- const requestedTop = nextTop;
12401
12408
  const contentBounds = getScrollContentBounds(this);
12402
12409
  const maxScroll = getScrollContentEndOffset(this, this.props);
12403
12410
  const maxScrollX = maxScroll.x;
@@ -12416,12 +12423,6 @@ var SootSimNode = class _SootSimNode {
12416
12423
  ),
12417
12424
  Math.min(maxScrollY, nextTop)
12418
12425
  );
12419
- if (hasX) {
12420
- this._scrollFollowContentEndX = maxScrollX > 0 && requestedLeft >= maxScrollX - 0.5;
12421
- }
12422
- if (hasY) {
12423
- this._scrollFollowContentEndY = maxScrollY > 0 && requestedTop >= maxScrollY - 0.5;
12424
- }
12425
12426
  this.scrollOffsetX = nextLeft;
12426
12427
  this.scrollOffsetY = nextTop;
12427
12428
  this.__scroll?.syncExternalOffset?.();
@@ -12469,8 +12470,12 @@ var SootSimNode = class _SootSimNode {
12469
12470
  animated: arg1?.animated !== false
12470
12471
  });
12471
12472
  }
12473
+ // a command runs against the committed tree: fabric mounts a commit before
12474
+ // the ui thread runs a command issued after it (both queue on the main
12475
+ // queue), so a scrollToEnd from an effect sees the rows that commit added
12472
12476
  scrollToEnd(options) {
12473
12477
  if (this.__scroll?.scrollToOffset) {
12478
+ this._flushPendingLayout();
12474
12479
  const target = Number.MAX_SAFE_INTEGER;
12475
12480
  const opts = this.props?.horizontal === true ? { x: target, y: 0, animated: options?.animated !== false } : { x: 0, y: target, animated: options?.animated !== false };
12476
12481
  this.__scroll.scrollToOffset({
@@ -12705,6 +12710,7 @@ var SootSimNode = class _SootSimNode {
12705
12710
  );
12706
12711
  this.type = type;
12707
12712
  this.props = props;
12713
+ this.lastReactProps = props;
12708
12714
  if (type === "image") queueImageLoad(this);
12709
12715
  this._wireRevision = nextWireRevision();
12710
12716
  this._wireSubtreeRevision = this._wireRevision;
@@ -12780,7 +12786,26 @@ var SootSimNode = class _SootSimNode {
12780
12786
  }
12781
12787
  updateProps(newProps, source = "react") {
12782
12788
  if (source === "react") {
12789
+ if (this.fabricNativeProps) {
12790
+ const previous = {
12791
+ ...this.lastReactProps,
12792
+ ...flattenStyle2(getNodeStyleInput(this.type, this.lastReactProps))
12793
+ };
12794
+ const next = {
12795
+ ...newProps,
12796
+ ...flattenStyle2(getNodeStyleInput(this.type, newProps))
12797
+ };
12798
+ for (const key of Object.keys(this.fabricNativeProps)) {
12799
+ if (!styleValuesEqual(previous[key], next[key])) {
12800
+ this.fabricNativeProps[key] = next[key] ?? null;
12801
+ }
12802
+ }
12803
+ }
12804
+ this.lastReactProps = newProps;
12783
12805
  newProps = this.mergeAnimatedNativePropsForReact(newProps);
12806
+ if (this.fabricNativeProps) {
12807
+ newProps = mergeFabricRawProps(newProps, this.fabricNativeProps);
12808
+ }
12784
12809
  }
12785
12810
  const oldProps = this.props;
12786
12811
  const oldStyleInput = oldProps.style;
@@ -12860,7 +12885,7 @@ var SootSimNode = class _SootSimNode {
12860
12885
  if (scrollContentOffsetChanged) {
12861
12886
  const nextOffset = readContentOffsetProp(newProps.contentOffset);
12862
12887
  if (nextOffset) {
12863
- moved = this.__scroll?.scrollToOffset?.({
12888
+ moved = this.__scroll?.shiftScrollTo?.(nextOffset) === true || this.__scroll?.scrollToOffset?.({
12864
12889
  ...nextOffset,
12865
12890
  animated: false,
12866
12891
  fireScroll: true,
@@ -15319,6 +15344,7 @@ onDeviceSpecChange(_updateExports);
15319
15344
  var DEFAULT_AUX_SHELL_SCENE = {
15320
15345
  state: "home",
15321
15346
  activeAppId: null,
15347
+ systemAlertAppId: null,
15322
15348
  prewarmAppId: null,
15323
15349
  showSwitcher: false,
15324
15350
  isLocked: false,
@@ -15355,6 +15381,7 @@ var DEFAULT_AUX_SHELL_SCENE = {
15355
15381
  recentApps: []
15356
15382
  };
15357
15383
  var currentScene = DEFAULT_AUX_SHELL_SCENE;
15384
+ var systemAlertAppId = createSignal(null);
15358
15385
  function readAuxShellScene() {
15359
15386
  return currentScene;
15360
15387
  }
@@ -15468,7 +15495,7 @@ var pendingActionSheets = /* @__PURE__ */ new Map();
15468
15495
  var pendingAndroidPermissions = /* @__PURE__ */ new Map();
15469
15496
  var pendingShareSheets = /* @__PURE__ */ new Map();
15470
15497
  var nextRequestId = 1;
15471
- function showAlert(title, message, buttons, onDismiss, options, prompt, traitScheme) {
15498
+ function showAlert(title, message, buttons, onDismiss, options, prompt, traitScheme, systemPresentation) {
15472
15499
  const config = {
15473
15500
  title,
15474
15501
  message,
@@ -15490,7 +15517,8 @@ function showAlert(title, message, buttons, onDismiss, options, prompt, traitSch
15490
15517
  })),
15491
15518
  prompt
15492
15519
  };
15493
- if (!postTenantNativeUIRequest({ kind: "alert.show", requestId, spec, traitScheme })) {
15520
+ const request = systemPresentation ? { kind: "systemAlert.show", requestId, spec, ...systemPresentation } : { kind: "alert.show", requestId, spec, traitScheme };
15521
+ if (!postTenantNativeUIRequest(request)) {
15494
15522
  handleAlertResult(requestId, null);
15495
15523
  }
15496
15524
  return requestId;
@@ -15752,15 +15780,6 @@ function createToastAndroidNativeModule(toastAndroid) {
15752
15780
  };
15753
15781
  }
15754
15782
 
15755
- // ../peach-engine/src/react-native/source-code-native-module.ts
15756
- var SourceCodeNativeModule = {
15757
- getConstants: () => {
15758
- const g = globalThis;
15759
- const scriptURL = g.__sootsim_bundle_url || (g.__sootsim_bundle_origin ? `${g.__sootsim_bundle_origin}/index.bundle` : "http://localhost:8081/index.bundle");
15760
- return { scriptURL };
15761
- }
15762
- };
15763
-
15764
15783
  // ../peach-engine/src/react-native/AppState.ts
15765
15784
  var currentState = "active";
15766
15785
  var AppStateNativeModule = {
@@ -16082,6 +16101,15 @@ var Settings = {
16082
16101
  }
16083
16102
  };
16084
16103
 
16104
+ // ../peach-engine/src/react-native/source-code-native-module.ts
16105
+ var SourceCodeNativeModule = {
16106
+ getConstants: () => {
16107
+ const g = globalThis;
16108
+ const scriptURL = g.__sootsim_bundle_url || (g.__sootsim_bundle_origin ? `${g.__sootsim_bundle_origin}/index.bundle` : "http://localhost:8081/index.bundle");
16109
+ return { scriptURL };
16110
+ }
16111
+ };
16112
+
16085
16113
  // ../peach-engine/src/components/Text.tsx
16086
16114
  var import_react8 = require("react");
16087
16115
  function Text(props) {
@@ -16344,7 +16372,6 @@ function ScrollViewInner(props, ref) {
16344
16372
  const headerRef = headerScroll?.headerRef;
16345
16373
  const containerView = hostingSafeArea?.view;
16346
16374
  const containerHeight = hostingSafeArea?.height;
16347
- const laidOutRef = (0, import_react10.useRef)(false);
16348
16375
  const measureOverlap = (0, import_react10.useCallback)(() => {
16349
16376
  const host = hostRef.current;
16350
16377
  if (!host) return;
@@ -16372,14 +16399,13 @@ function ScrollViewInner(props, ref) {
16372
16399
  const handleLayout = (0, import_react10.useCallback)(
16373
16400
  (event) => {
16374
16401
  onLayout?.(event);
16375
- laidOutRef.current = true;
16376
16402
  measureOverlap();
16377
16403
  },
16378
16404
  [onLayout, measureOverlap]
16379
16405
  );
16380
16406
  (0, import_react10.useEffect)(() => {
16381
- if (laidOutRef.current) measureOverlap();
16382
- }, [measureOverlap]);
16407
+ if (measuresSafeArea && hostRef.current) measureOverlap();
16408
+ }, [measuresSafeArea, measureOverlap]);
16383
16409
  const bouncesVertically = props.alwaysBounceVertical ?? !horizontal;
16384
16410
  const tracksContentHeight = measuresSafeArea && !bouncesVertically && behavior !== "always";
16385
16411
  const [contentHeight, setContentHeight] = (0, import_react10.useState)();
@@ -17365,10 +17391,7 @@ function PressableInner(props, ref) {
17365
17391
  onLongPress,
17366
17392
  onInteractionFinished,
17367
17393
  minPressDuration,
17368
- onPress: props.testID === "signInButton" ? ((e) => {
17369
- console.log("[probe-press] signInButton onPress fired");
17370
- onPress?.(e);
17371
- }) : onPress,
17394
+ onPress,
17372
17395
  onPressIn(event) {
17373
17396
  if (shouldUpdatePressed) {
17374
17397
  setPressed(true);
@@ -17407,7 +17430,6 @@ function PressableInner(props, ref) {
17407
17430
  onPressMove,
17408
17431
  onPressOut,
17409
17432
  pressRetentionOffset,
17410
- props.testID,
17411
17433
  releaseRipple,
17412
17434
  shouldUpdatePressed,
17413
17435
  startRipple,
@@ -17462,23 +17484,37 @@ Pressable.displayName = "Pressable";
17462
17484
  var import_react17 = require("react");
17463
17485
 
17464
17486
  // ../peach-engine/src/components/touchable-core.ts
17465
- function buildTouchableViewProps(props, ref, wrapped) {
17487
+ function useTouchablePressability(props, wrapped) {
17488
+ return usePressability_default({
17489
+ cancelable: !props.rejectResponderTermination,
17490
+ disabled: props.disabled,
17491
+ hitSlop: props.hitSlop,
17492
+ delayLongPress: props.delayLongPress,
17493
+ delayPressIn: props.delayPressIn,
17494
+ delayPressOut: props.delayPressOut,
17495
+ minPressDuration: 0,
17496
+ pressRectOffset: props.pressRetentionOffset,
17497
+ onLongPress: props.onLongPress,
17498
+ onPress: wrapped.onPress ?? props.onPress,
17499
+ onPressIn: wrapped.onPressIn,
17500
+ onPressOut: wrapped.onPressOut
17501
+ });
17502
+ }
17503
+ function buildTouchableViewProps(props, ref) {
17466
17504
  const {
17467
17505
  // destructured only to transform or drop them; `rest` carries everything
17468
- // else (delays, hitSlop, onLayout, focusable, TV focus props, a11y props,
17469
- // etc.) straight through to the underlying view.
17506
+ // else (hitSlop, onLayout, focusable, TV focus props, a11y props, etc.)
17507
+ // straight through to the underlying view.
17470
17508
  children: _children,
17471
17509
  disabled = false,
17472
- onPress,
17473
- onPressIn: _userPressIn,
17474
- onPressOut: _userPressOut,
17475
- onLongPress,
17510
+ onPress: _onPress,
17511
+ onPressIn: _onPressIn,
17512
+ onPressOut: _onPressOut,
17513
+ onLongPress: _onLongPress,
17476
17514
  accessibilityRole,
17477
17515
  accessibilityState,
17478
17516
  id,
17479
17517
  nativeID,
17480
- // RN-specific knobs that sootsim doesn't wire — keep the names so
17481
- // component authors don't see a typed regression, but don't forward.
17482
17518
  rejectResponderTermination: _rejectResponderTermination,
17483
17519
  touchSoundDisabled: _touchSoundDisabled,
17484
17520
  ...rest
@@ -17486,10 +17522,6 @@ function buildTouchableViewProps(props, ref, wrapped) {
17486
17522
  return {
17487
17523
  ...rest,
17488
17524
  ref,
17489
- onPress: disabled ? void 0 : onPress,
17490
- onPressIn: disabled ? void 0 : wrapped.onPressIn,
17491
- onPressOut: disabled ? void 0 : wrapped.onPressOut,
17492
- onLongPress: disabled ? void 0 : onLongPress,
17493
17525
  id,
17494
17526
  nativeID: nativeID ?? id,
17495
17527
  accessibilityRole: accessibilityRole ?? "button",
@@ -17570,11 +17602,16 @@ function TouchableOpacityInner(props, ref) {
17570
17602
  animationRef.current?.stop();
17571
17603
  };
17572
17604
  }, []);
17573
- const viewProps = buildTouchableViewProps(props, ref, {
17605
+ const viewProps = buildTouchableViewProps(props, ref);
17606
+ const eventHandlers = useTouchablePressability(props, {
17574
17607
  onPressIn: handlePressIn,
17575
17608
  onPressOut: handlePressOut
17576
17609
  });
17577
- return (0, import_react17.createElement)("sootsim-view", { ...viewProps, style: animatedStyle }, children);
17610
+ return (0, import_react17.createElement)(
17611
+ "sootsim-view",
17612
+ { ...viewProps, ...eventHandlers, style: animatedStyle },
17613
+ children
17614
+ );
17578
17615
  }
17579
17616
  var TouchableOpacity = (0, import_react17.forwardRef)(TouchableOpacityInner);
17580
17617
  TouchableOpacity.displayName = "TouchableOpacity";
@@ -20952,8 +20989,24 @@ var TextInput = (0, import_react21.forwardRef)(function TextInput2(props, ref) {
20952
20989
  placeholderTextColor = DEFAULT_TEXT_INPUT_PLACEHOLDER_COLOR,
20953
20990
  onContentSizeChange,
20954
20991
  clearButtonMode = "never",
20992
+ onPress,
20993
+ onPressIn,
20994
+ onPressOut,
20995
+ rejectResponderTermination = true,
20955
20996
  ...rest
20956
20997
  } = props;
20998
+ const isAndroid = getRuntimePlatformAdapter(currentRuntimePlatform()).isAndroid;
20999
+ const pressabilityConfig = (0, import_react21.useMemo)(
21000
+ () => ({
21001
+ cancelable: isAndroid ? null : !rejectResponderTermination,
21002
+ hitSlop: rest.hitSlop,
21003
+ onPress,
21004
+ onPressIn,
21005
+ onPressOut
21006
+ }),
21007
+ [isAndroid, onPress, onPressIn, onPressOut, rejectResponderTermination, rest.hitSlop]
21008
+ );
21009
+ const pressHandlers = usePressability_default(pressabilityConfig) ?? {};
20957
21010
  const nativeText = typeof text === "string" ? text : void 0;
20958
21011
  const controlledValue = value;
20959
21012
  const hostRef = (0, import_react21.useRef)(null);
@@ -20970,10 +21023,10 @@ var TextInput = (0, import_react21.forwardRef)(function TextInput2(props, ref) {
20970
21023
  const showPlaceholder = !rawDisplayText && placeholder;
20971
21024
  const isMultiline = rest.multiline === true;
20972
21025
  const [editing, setEditing] = (0, import_react21.useState)(false);
20973
- const showClearButton = !isMultiline && rawDisplayText.length > 0 && !getRuntimePlatformAdapter(currentRuntimePlatform()).isAndroid && (clearButtonMode === "always" || clearButtonMode === "while-editing" && editing || clearButtonMode === "unless-editing" && !editing);
21026
+ const showClearButton = !isMultiline && rawDisplayText.length > 0 && !isAndroid && (clearButtonMode === "always" || clearButtonMode === "while-editing" && editing || clearButtonMode === "unless-editing" && !editing);
20974
21027
  const justifyContent = isMultiline ? "flex-start" : "center";
20975
21028
  const scrollEnabledProp = rest.scrollEnabled;
20976
- const scrollsInternally = isMultiline ? scrollEnabledProp !== false : true;
21029
+ const clipsToBounds = !isMultiline || scrollEnabledProp !== false || !isAndroid;
20977
21030
  (0, import_react21.useEffect)(() => {
20978
21031
  if (isControlled) {
20979
21032
  lastControlledValueRef.current = controlledValue;
@@ -21320,14 +21373,13 @@ var TextInput = (0, import_react21.forwardRef)(function TextInput2(props, ref) {
21320
21373
  // `flexDirection: 'row'` (e.g. Mattermost's FloatingTextInput).
21321
21374
  flexDirection: "column",
21322
21375
  justifyContent,
21323
- // UITextField/UITextView always clip to their frame natively. without
21324
- // this, a long single-line value or a tall multiline value paints
21325
- // outside the input border and the caret floats in no-mans-land.
21326
- // scrollEnabled=false multiline grows to fit content (no overflow),
21327
- // so the clip becomes a no-op rather than a behavior change.
21328
- ...scrollsInternally ? { overflow: "hidden" } : null
21376
+ // without this, a long single-line value or a tall multiline value
21377
+ // paints outside the input border and the caret floats in
21378
+ // no-mans-land.
21379
+ ...clipsToBounds ? { overflow: "hidden" } : null
21329
21380
  },
21330
21381
  ...rest,
21382
+ ...pressHandlers,
21331
21383
  ...onContentSizeChange ? { onLayout: handleHostLayout } : null,
21332
21384
  onFocus: handleFocus,
21333
21385
  onBlur: handleBlur,
@@ -23130,7 +23182,6 @@ var {
23130
23182
  thumbMargin: THUMB_MARGIN
23131
23183
  } = IOS_SWITCH_METRICS;
23132
23184
  var ON_POS = TRACK_WIDTH - IOS_THUMB_WIDTH - THUMB_MARGIN;
23133
- var LIFT_MIN_MS = 14 * 1e3 / 60;
23134
23185
  var THUMB_LAYER = {
23135
23186
  position: "absolute",
23136
23187
  left: 0,
@@ -23591,6 +23642,7 @@ function TouchableHighlightInner(props, ref) {
23591
23642
  onHideUnderlay,
23592
23643
  onPressIn,
23593
23644
  onPressOut,
23645
+ onPress,
23594
23646
  delayPressOut,
23595
23647
  style,
23596
23648
  children
@@ -23649,31 +23701,40 @@ function TouchableHighlightInner(props, ref) {
23649
23701
  );
23650
23702
  const handlePressOut = (0, import_react36.useCallback)(
23651
23703
  (e) => {
23652
- const delay = typeof delayPressOut === "number" ? delayPressOut : 0;
23704
+ if (hideTimerRef.current === null) hide();
23705
+ onPressOut?.(e);
23706
+ },
23707
+ [hide, onPressOut]
23708
+ );
23709
+ const handlePress = (0, import_react36.useCallback)(
23710
+ (e) => {
23653
23711
  clearHideTimer();
23654
- if (delay > 0) {
23655
- hideTimerRef.current = setTimeout(() => {
23656
- hideTimerRef.current = null;
23657
- hide();
23658
- }, delay);
23659
- } else {
23712
+ show();
23713
+ hideTimerRef.current = setTimeout(() => {
23714
+ hideTimerRef.current = null;
23660
23715
  hide();
23661
- }
23662
- onPressOut?.(e);
23716
+ }, delayPressOut ?? 0);
23717
+ onPress?.(e);
23663
23718
  },
23664
- [clearHideTimer, delayPressOut, hide, onPressOut]
23719
+ [clearHideTimer, delayPressOut, hide, onPress, show]
23665
23720
  );
23666
23721
  (0, import_react36.useEffect)(() => {
23667
23722
  return () => clearHideTimer();
23668
23723
  }, [clearHideTimer]);
23669
- const viewProps = buildTouchableViewProps(props, ref, {
23724
+ const viewProps = buildTouchableViewProps(props, ref);
23725
+ const eventHandlers = useTouchablePressability(props, {
23726
+ onPress: handlePress,
23670
23727
  onPressIn: handlePressIn,
23671
23728
  onPressOut: handlePressOut
23672
23729
  });
23673
23730
  const renderedChild = (0, import_react36.isValidElement)(child) ? (0, import_react36.cloneElement)(child, {
23674
23731
  style: [child.props?.style, childOpacityOverlay]
23675
23732
  }) : child;
23676
- return (0, import_react36.createElement)("sootsim-view", { ...viewProps, style: outerStyle }, renderedChild);
23733
+ return (0, import_react36.createElement)(
23734
+ "sootsim-view",
23735
+ { ...viewProps, ...eventHandlers, style: outerStyle },
23736
+ renderedChild
23737
+ );
23677
23738
  }
23678
23739
  var TouchableHighlight = (0, import_react36.forwardRef)(TouchableHighlightInner);
23679
23740
  TouchableHighlight.displayName = "TouchableHighlight";
@@ -25590,7 +25651,7 @@ function canOpenTenantUrl(url) {
25590
25651
  }
25591
25652
  function openSettings() {
25592
25653
  const open = (0, engine_config_exports.getOptionalEngineConfig)()?.nativePermissions?.openSettings;
25593
- return open ? open() : Promise.reject(
25654
+ return open ? open({ kind: "app" }) : Promise.reject(
25594
25655
  new Error(
25595
25656
  "[sootsim] app settings are unavailable before the native bridge installs"
25596
25657
  )
@@ -27205,7 +27266,8 @@ var VerticalBarColumnRegistryContext = (0, import_react44.createContext)(
27205
27266
  var VerticalBarSceneFocusContext = (0, import_react44.createContext)(true);
27206
27267
  var VerticalBarColumnMetricsContext = (0, import_react44.createContext)({
27207
27268
  availableHeaderHeight: null,
27208
- availableToolbarHeight: null
27269
+ availableToolbarHeight: null,
27270
+ availableTopToolbarHeight: null
27209
27271
  });
27210
27272
  var SPLIT_COLUMN_CHROME_KEY = "__peachSplitColumnChromeContext";
27211
27273
  var splitColumnChromeGlobals = globalThis;
@@ -27228,6 +27290,7 @@ var import_react46 = require("react");
27228
27290
  // ../peach-engine/src/components/SegmentedControl.tsx
27229
27291
  var import_react47 = require("react");
27230
27292
  var SYSTEM_TEXT = dynamicColor("#000000", "#ffffff");
27293
+ var STRETCH_GAIN = 1.87 / 60;
27231
27294
 
27232
27295
  // ../peach-compat/src/stubs/blur-utils.ts
27233
27296
  var import_react48 = require("react");
@@ -28047,7 +28110,7 @@ var import_sf_symbol_catalog4 = require("peach-engine/ios/sf-symbol-catalog");
28047
28110
  var import_SplitView2 = require("peach-engine/ios/SplitView");
28048
28111
  var import_platform_colors4 = require("peach-engine/react-native/platform-colors");
28049
28112
  var import_device_spec_bus26 = require("peach-engine/settings/device-spec-bus");
28050
- var import_devices6 = require("peach-engine/settings/devices");
28113
+ var import_devices7 = require("peach-engine/settings/devices");
28051
28114
  var import_store15 = require("peach-engine/settings/store");
28052
28115
  var import_use_device9 = require("peach-engine/settings/use-device");
28053
28116
  var import_react53 = require("react");
@@ -28555,7 +28618,7 @@ function deviceWindowSizeClasses() {
28555
28618
  throw new Error(
28556
28619
  `swift environment has no size classes on ${spec?.platform ?? "no device"}`
28557
28620
  );
28558
- return (0, import_devices6.deviceSizeClasses)(
28621
+ return (0, import_devices7.deviceSizeClasses)(
28559
28622
  spec.model,
28560
28623
  spec.width > spec.height ? "landscape" : "portrait",
28561
28624
  spec.posture
@@ -29617,6 +29680,7 @@ var NODE_COMPONENTS = {
29617
29680
  ContextMenu: import_ui.ContextMenu,
29618
29681
  ControlGroup: import_ui.ControlGroup,
29619
29682
  DatePicker: import_ui.DatePicker,
29683
+ DisclosureGroup: import_ui.DisclosureGroup,
29620
29684
  Divider: import_ui.Divider,
29621
29685
  EditButton: import_ui.Button,
29622
29686
  Ellipse: import_ui.Ellipse,
@@ -29654,6 +29718,7 @@ var NODE_COMPONENTS = {
29654
29718
  StyledToggle: import_ui.ZStack,
29655
29719
  SwipeActions: import_ui.SwipeActions,
29656
29720
  Text: import_ui.Text,
29721
+ TextEditor: import_ui.TextField,
29657
29722
  TextField: import_ui.TextField,
29658
29723
  Toggle: import_ui.Toggle,
29659
29724
  Tab: SwiftTabScene,
@@ -30216,6 +30281,9 @@ function nodeProps(node, deliver) {
30216
30281
  );
30217
30282
  return {
30218
30283
  ...align === void 0 ? {} : { style: align },
30284
+ // a vertical field grows with its lines and wraps a long one instead
30285
+ // of scrolling a single line (textfieldaxis, ios 27)
30286
+ ...props.axis === "vertical" ? { axis: "vertical" } : {},
30219
30287
  // a prompt is what the empty field shows, in the title's place; the
30220
30288
  // title still names the field (ios 27 controls oracle: SecureField
30221
30289
  // "Code" with prompt "6 digits" reads 6 digits)
@@ -30236,6 +30304,34 @@ function nodeProps(node, deliver) {
30236
30304
  ...focusProps(node, deliver)
30237
30305
  };
30238
30306
  }
30307
+ case "TextEditor": {
30308
+ const onChangeText = handlerId(node, "onChangeText");
30309
+ return {
30310
+ axis: "vertical",
30311
+ scrollEnabled: props.scrollEnabled !== false,
30312
+ // the tree's text-field control: describe collapses the engine input
30313
+ // host, so the role rides on the node describe keeps, as a
30314
+ // TextField's does
30315
+ accessibilityRole: "text-field",
30316
+ // a UITextView fills its offer on both axes and insets its text 8pt
30317
+ // from the top and bottom and 5pt from the sides, and its lines are
30318
+ // body lines (texteditor, ios 27: an empty editor in a padded stack
30319
+ // spans 370 and the rest of the height; text ink starts 5.33pt in and
30320
+ // 11.67pt down, and lines are 22pt apart)
30321
+ style: {
30322
+ lineHeight: textStyleAt("large", "body").lineHeight,
30323
+ flex: 1,
30324
+ alignSelf: "stretch",
30325
+ paddingTop: 8,
30326
+ paddingBottom: 8,
30327
+ paddingHorizontal: 5,
30328
+ textAlignVertical: "top"
30329
+ },
30330
+ ...typeof props.value === "string" ? { value: props.value } : {},
30331
+ ...onChangeText === void 0 ? {} : { onChangeText: (value) => deliver(onChangeText, value) },
30332
+ ...focusProps(node, deliver)
30333
+ };
30334
+ }
30239
30335
  case "Slider": {
30240
30336
  const onValueChange = handlerId(node, "onValueChange");
30241
30337
  return {
@@ -30446,6 +30542,15 @@ function nodeProps(node, deliver) {
30446
30542
  }
30447
30543
  case "GlassEffectContainer":
30448
30544
  return typeof props.spacing === "number" ? { spacing: props.spacing } : {};
30545
+ case "DisclosureGroup": {
30546
+ const onIsExpandedChange = handlerId(node, "onIsExpandedChange");
30547
+ return {
30548
+ ...typeof props.isExpanded === "boolean" ? { isExpanded: props.isExpanded } : {},
30549
+ ...onIsExpandedChange === void 0 ? {} : {
30550
+ onIsExpandedChange: (value) => deliver(onIsExpandedChange, value)
30551
+ }
30552
+ };
30553
+ }
30449
30554
  case "GroupBox":
30450
30555
  return pressProps(node, deliver);
30451
30556
  case "LabeledContent":
@@ -32180,7 +32285,7 @@ function buildNode(swiftNode, deliver, cache2, inToolbar = false, inList = false
32180
32285
  if (inToolbar) node = toolbarIconOnlyLabel(node);
32181
32286
  const modifiers = nodeModifiers(node);
32182
32287
  const childInList = node.t === "List" || node.t === "Form" || (node.t === "Section" || node.t === "Group") && inList;
32183
- if (node.t === "LabeledContent" || node.t === "GroupBox") {
32288
+ if (node.t === "LabeledContent" || node.t === "GroupBox" || node.t === "DisclosureGroup") {
32184
32289
  const { label, content } = labeledContentSlots(node);
32185
32290
  return withEnvironmentFont(
32186
32291
  node,