peachsim 0.1.666 → 0.1.667
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-lib/agent-daemon-client.cjs +1 -1
- package/dist-lib/agent-events.cjs +1 -1
- package/dist-lib/agent-identity.cjs +1 -1
- package/dist-lib/agent-sessions.cjs +1 -1
- package/dist-lib/attached-projects.cjs +1 -1
- package/dist-lib/auth/shared-session.cjs +1 -1
- package/dist-lib/backend-origin.cjs +1 -1
- package/dist-lib/beta.cjs +1 -1
- package/dist-lib/beta.mjs +1 -1
- package/dist-lib/bridge-constants.cjs +1 -1
- package/dist-lib/bridge-contract-input.cjs +1 -1
- package/dist-lib/bridge-contract-input.mjs +1 -1
- package/dist-lib/bridge-contract.cjs +1 -1
- package/dist-lib/bridge-contract.mjs +1 -1
- package/dist-lib/capture-contract.cjs +1 -1
- package/dist-lib/capture-contract.mjs +1 -1
- package/dist-lib/cli-constants.cjs +1 -1
- package/dist-lib/cloud-contract.cjs +1 -1
- package/dist-lib/cloud-contract.mjs +1 -1
- package/dist-lib/cloud-test-args.cjs +1 -1
- package/dist-lib/cloud-test-args.mjs +1 -1
- package/dist-lib/cloud.cjs +1 -1
- package/dist-lib/cloud.mjs +1 -1
- package/dist-lib/config.cjs +1 -1
- package/dist-lib/detox/index.cjs +1 -1
- package/dist-lib/dev-bundle-resolution.cjs +1 -1
- package/dist-lib/home-paths.cjs +1 -1
- package/dist-lib/host/bridge-host.cjs +1 -1
- package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
- package/dist-lib/host/replacement-module-handler.cjs +1 -1
- package/dist-lib/host/websocket-proxy.cjs +1 -1
- package/dist-lib/index.cjs +1 -1
- package/dist-lib/jump-to-source-babel.cjs +1 -1
- package/dist-lib/jump-to-source-native.cjs +1 -1
- package/dist-lib/kotlin-host.cjs +4 -1
- package/dist-lib/menu.cjs +1 -1
- package/dist-lib/menu.mjs +1 -1
- package/dist-lib/metro-fingerprint-registry.cjs +1 -1
- package/dist-lib/metro-fingerprint-registry.mjs +1 -1
- package/dist-lib/metro-production-bundle.cjs +1 -1
- package/dist-lib/metro-production-bundle.mjs +1 -1
- package/dist-lib/metro.cjs +1 -1
- package/dist-lib/native-app-identity.cjs +1 -1
- package/dist-lib/native-app-identity.mjs +1 -1
- package/dist-lib/plist.cjs +1 -1
- package/dist-lib/plist.mjs +1 -1
- package/dist-lib/profiles.cjs +1 -1
- package/dist-lib/public-brand.cjs +1 -1
- package/dist-lib/react-native-host-modules.cjs +1 -1
- package/dist-lib/react-native-host-modules.mjs +1 -1
- package/dist-lib/render-mode.cjs +1 -1
- package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
- package/dist-lib/sdk.cjs +1 -1
- package/dist-lib/sdk.mjs +1 -1
- package/dist-lib/skills.cjs +1 -1
- package/dist-lib/swift-compile.cjs +1 -1
- package/dist-lib/swift-compile.mjs +1 -1
- package/dist-lib/swift-package.cjs +1 -1
- package/dist-lib/swift-package.mjs +1 -1
- package/dist-lib/swift-submit.cjs +1 -1
- package/dist-lib/swift-submit.mjs +1 -1
- package/dist-lib/swift.cjs +1 -1
- package/dist-lib/vite-swift.cjs +1 -1
- package/dist-lib/vite.cjs +1 -1
- package/kotlin/AppSources/dev/peach/app/PeachApp.kt +15 -3
- package/kotlin/ComposeSources/PeachComposeHost.kt +200 -0
- package/kotlin/Sources/org/json/JSON.kt +13 -0
- package/kotlin/fixtures/kotlin-app-variants/Anim.kt +62 -0
- package/kotlin/fixtures/kotlin-app-variants/Form.kt +47 -0
- package/kotlin/fixtures/kotlin-app-variants/Ime.kt +51 -0
- package/kotlin/fixtures/kotlin-app-variants/Note.kt +40 -0
- package/package.json +1 -1
- package/src/kotlin-host.ts +3 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.667 | (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;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.667 | (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 __defProp = Object.defineProperty;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.667 | (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 __defProp = Object.defineProperty;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.667 | (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;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.667 | (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;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.667 | (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;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.667 | (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 __defProp = Object.defineProperty;
|
package/dist-lib/beta.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.667 | (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 __defProp = Object.defineProperty;
|
package/dist-lib/beta.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.667 | (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 __defProp = Object.defineProperty;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.667 | (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 __defProp = Object.defineProperty;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.667 | (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 __defProp = Object.defineProperty;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.667 | (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 __defProp = Object.defineProperty;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.667 | (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 __defProp = Object.defineProperty;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.667 | (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 __defProp = Object.defineProperty;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.667 | (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 __defProp = Object.defineProperty;
|
package/dist-lib/cloud.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.667 | (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 __defProp = Object.defineProperty;
|
package/dist-lib/cloud.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.667 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
2
|
var __defProp = Object.defineProperty;
|
|
3
3
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
4
4
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
package/dist-lib/config.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.667 | (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 __defProp = Object.defineProperty;
|
package/dist-lib/detox/index.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.667 | (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;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.667 | (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 __defProp = Object.defineProperty;
|
package/dist-lib/home-paths.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.667 | (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;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.667 | (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;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.667 | (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;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.667 | (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 __defProp = Object.defineProperty;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.667 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
2
|
|
|
3
3
|
// src/host/fetch-proxy-overrides.ts
|
|
4
4
|
var FETCH_PROXY_BROWSER_USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.667 | (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;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.667 | (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 __defProp = Object.defineProperty;
|
package/dist-lib/index.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.667 | (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;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.667 | (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 __defProp = Object.defineProperty;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.667 | (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;
|
package/dist-lib/kotlin-host.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.667 | (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;
|
|
@@ -420,6 +420,9 @@ async function kotlinAppArtifact(app, moduleRoot, origin) {
|
|
|
420
420
|
"",
|
|
421
421
|
"@JsExport",
|
|
422
422
|
"fun peachAppNight(night: Boolean) = dev.peach.app.peachAppNight(night)",
|
|
423
|
+
"",
|
|
424
|
+
"@JsExport",
|
|
425
|
+
"fun peachAppIme(bottom: Int) = dev.peach.app.peachAppIme(bottom)",
|
|
423
426
|
""
|
|
424
427
|
].join("\n");
|
|
425
428
|
const generated = {
|
package/dist-lib/menu.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.667 | (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 __defProp = Object.defineProperty;
|
package/dist-lib/menu.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.667 | (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 __defProp = Object.defineProperty;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.667 | (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 __defProp = Object.defineProperty;
|
package/dist-lib/metro.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.667 | (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;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.667 | (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 __defProp = Object.defineProperty;
|
package/dist-lib/plist.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.667 | (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;
|
package/dist-lib/plist.mjs
CHANGED
package/dist-lib/profiles.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.667 | (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;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.667 | (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 __defProp = Object.defineProperty;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.667 | (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 __defProp = Object.defineProperty;
|
package/dist-lib/render-mode.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.667 | (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 __defProp = Object.defineProperty;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.667 | (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;
|
package/dist-lib/sdk.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.667 | (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 __defProp = Object.defineProperty;
|
package/dist-lib/sdk.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.667 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
2
|
var __defProp = Object.defineProperty;
|
|
3
3
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
4
4
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
package/dist-lib/skills.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.667 | (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;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.667 | (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;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.667 | (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 __defProp = Object.defineProperty;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.667 | (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 __defProp = Object.defineProperty;
|
package/dist-lib/swift.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.667 | (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 __defProp = Object.defineProperty;
|
package/dist-lib/vite-swift.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.667 | (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;
|
package/dist-lib/vite.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.667 | (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;
|
|
@@ -68,8 +68,9 @@ internal fun peachApplication(): Application = runningApp().application
|
|
|
68
68
|
// them on an edge-to-edge window, none once the decor fits system windows.
|
|
69
69
|
// insets lists the status bars, navigation bars, display cutout, system
|
|
70
70
|
// gestures, mandatory system gestures and tappable element, each left, top,
|
|
71
|
-
// right and bottom.
|
|
72
|
-
|
|
71
|
+
// right and bottom. the IME's inset is the keyboard's height above the
|
|
72
|
+
// screen's bottom edge, which moves with the keyboard frame by frame.
|
|
73
|
+
private class DeviceInsets(private val window: Window, insets: String, imeBottom: () -> Int) : PlatformWindowInsets {
|
|
73
74
|
private val pixels = insets.split(',').map { it.toInt() }.also { require(it.size == 24) }
|
|
74
75
|
|
|
75
76
|
// read when compose lays out, so a later change to the window applies
|
|
@@ -84,6 +85,7 @@ private class DeviceInsets(private val window: Window, insets: String) : Platfor
|
|
|
84
85
|
override val systemGestures = type(3)
|
|
85
86
|
override val mandatorySystemGestures = type(4)
|
|
86
87
|
override val tappableElement = type(5)
|
|
88
|
+
override val ime = PlatformInsets({ 0 }, { 0 }, { 0 }, { if (window.fitsSystemWindows) 0 else imeBottom() })
|
|
87
89
|
override val systemBars = PlatformInsets(
|
|
88
90
|
{ maxOf(statusBars.left, navigationBars.left) },
|
|
89
91
|
{ maxOf(statusBars.top, navigationBars.top) },
|
|
@@ -127,6 +129,8 @@ private class AppProcess(
|
|
|
127
129
|
// the night mode last reported to the activity: ActivityRecord compares
|
|
128
130
|
// the configuration with it before a relaunch or onConfigurationChanged
|
|
129
131
|
var reportedNight = false
|
|
132
|
+
// the software keyboard's height above the screen's bottom edge, in pixels
|
|
133
|
+
var ime by mutableIntStateOf(0)
|
|
130
134
|
}
|
|
131
135
|
|
|
132
136
|
private var process: AppProcess? = null
|
|
@@ -228,7 +232,7 @@ private fun launchActivity(app: AppProcess, lastNonConfigurationInstance: Any?):
|
|
|
228
232
|
app.density, app.fontScale, app.locale, app.gpu, app.stencilBits, app.fonts, app.invalidate,
|
|
229
233
|
night = isNight(activity.resources.configuration),
|
|
230
234
|
owners = componentActivity?.let(::ActivityOwners),
|
|
231
|
-
insets = DeviceInsets(window, app.insets),
|
|
235
|
+
insets = DeviceInsets(window, app.insets) { app.ime },
|
|
232
236
|
clockRunning = { componentActivity == null || componentActivity.lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED) },
|
|
233
237
|
)
|
|
234
238
|
mount.setContent {
|
|
@@ -322,6 +326,14 @@ private fun reportConfiguration(app: AppProcess): Boolean {
|
|
|
322
326
|
private fun isNight(configuration: Configuration) =
|
|
323
327
|
configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES
|
|
324
328
|
|
|
329
|
+
// the software keyboard moved: its inset reaches the window's content
|
|
330
|
+
internal fun peachAppIme(bottom: Int) {
|
|
331
|
+
val app = runningApp()
|
|
332
|
+
if (app.ime == bottom) return
|
|
333
|
+
app.ime = bottom
|
|
334
|
+
app.invalidate(true)
|
|
335
|
+
}
|
|
336
|
+
|
|
325
337
|
// the device's night mode changed. the process's configuration changes in
|
|
326
338
|
// place and the Application hears it first; a visible activity then takes it.
|
|
327
339
|
// a stopped activity takes it once visible again, if it still differs.
|
|
@@ -9,9 +9,13 @@ import androidx.compose.runtime.setValue
|
|
|
9
9
|
import androidx.compose.runtime.snapshots.Snapshot
|
|
10
10
|
import androidx.compose.ui.LocalSystemTheme
|
|
11
11
|
import androidx.compose.ui.geometry.Offset
|
|
12
|
+
import androidx.compose.ui.geometry.Rect
|
|
12
13
|
import androidx.compose.ui.graphics.asComposeCanvas
|
|
13
14
|
import androidx.compose.ui.input.InputMode
|
|
14
15
|
import androidx.compose.ui.input.InputModeManager
|
|
16
|
+
import androidx.compose.ui.input.key.Key
|
|
17
|
+
import androidx.compose.ui.input.key.KeyEvent
|
|
18
|
+
import androidx.compose.ui.input.key.KeyEventType
|
|
15
19
|
import androidx.compose.ui.input.pointer.PointerEventType
|
|
16
20
|
import androidx.compose.ui.input.pointer.PointerType
|
|
17
21
|
import androidx.compose.ui.platform.FrameRecomposer
|
|
@@ -19,6 +23,7 @@ import androidx.compose.ui.platform.LocalFontFamilyResolver
|
|
|
19
23
|
import androidx.compose.ui.platform.PlatformArchitectureComponentsOwner
|
|
20
24
|
import androidx.compose.ui.platform.PlatformWindowInsets
|
|
21
25
|
import androidx.compose.ui.platform.PlatformContext
|
|
26
|
+
import androidx.compose.ui.platform.PlatformTextInputMethodRequest
|
|
22
27
|
import androidx.compose.ui.platform.WindowInfo
|
|
23
28
|
import androidx.compose.ui.platform.registerSkikoComposeImplementation
|
|
24
29
|
import androidx.compose.ui.scene.CanvasLayersComposeScene
|
|
@@ -34,6 +39,19 @@ import androidx.compose.ui.text.font.FontWeight
|
|
|
34
39
|
import androidx.compose.ui.text.font.PlatformTypefacesLoader
|
|
35
40
|
import androidx.compose.ui.text.font.createPlatformFontFamilyResolver
|
|
36
41
|
import androidx.compose.ui.text.font.platformTypefacesLoader
|
|
42
|
+
import androidx.compose.ui.text.input.BackspaceCommand
|
|
43
|
+
import androidx.compose.ui.text.input.CommitTextCommand
|
|
44
|
+
import androidx.compose.ui.text.input.EditCommand
|
|
45
|
+
import androidx.compose.ui.text.input.FinishComposingTextCommand
|
|
46
|
+
import androidx.compose.ui.text.input.ImeAction
|
|
47
|
+
import androidx.compose.ui.text.input.ImeOptions
|
|
48
|
+
import androidx.compose.ui.text.input.KeyboardCapitalization
|
|
49
|
+
import androidx.compose.ui.text.input.KeyboardType
|
|
50
|
+
import androidx.compose.ui.text.input.PlatformTextInputService
|
|
51
|
+
import androidx.compose.ui.text.input.SetComposingRegionCommand
|
|
52
|
+
import androidx.compose.ui.text.input.SetComposingTextCommand
|
|
53
|
+
import androidx.compose.ui.text.input.SetSelectionCommand
|
|
54
|
+
import androidx.compose.ui.text.input.TextFieldValue
|
|
37
55
|
import androidx.compose.ui.text.intl.LocaleList
|
|
38
56
|
import androidx.compose.ui.text.intl.setPlatformLocaleProvider
|
|
39
57
|
import androidx.compose.ui.text.platform.Font
|
|
@@ -45,6 +63,7 @@ import androidx.compose.ui.unit.LayoutDirection
|
|
|
45
63
|
import dev.onejs.one.OneNativeSourceViewDispatch
|
|
46
64
|
import kotlin.io.encoding.Base64
|
|
47
65
|
import kotlinx.coroutines.Dispatchers
|
|
66
|
+
import kotlinx.coroutines.awaitCancellation
|
|
48
67
|
import org.jetbrains.skiko.SystemTheme
|
|
49
68
|
import org.jetbrains.skia.BackendRenderTarget
|
|
50
69
|
import org.jetbrains.skia.Bitmap
|
|
@@ -94,6 +113,129 @@ internal class PeachComposePlatform(
|
|
|
94
113
|
override fun onSemanticsOwnerRemoved(semanticsOwner: SemanticsOwner) { owners.remove(semanticsOwner) }
|
|
95
114
|
override fun onSemanticsChange(semanticsOwner: SemanticsOwner) = Unit
|
|
96
115
|
override fun onLayoutChange(semanticsOwner: SemanticsOwner, semanticsNodeId: Int) = Unit
|
|
116
|
+
|
|
117
|
+
// the input method session the focused text field holds, android's
|
|
118
|
+
// InputConnection. each session gets a new token, so the host can tell a
|
|
119
|
+
// late close from the session that replaced it
|
|
120
|
+
var input: PeachInputSession? = null
|
|
121
|
+
private set
|
|
122
|
+
var onInputChange: () -> Unit = {}
|
|
123
|
+
private var nextInput = 1
|
|
124
|
+
|
|
125
|
+
override suspend fun startInputMethod(request: PlatformTextInputMethodRequest): Nothing {
|
|
126
|
+
val session = PeachInputSession(nextInput++, request)
|
|
127
|
+
input = session
|
|
128
|
+
onInputChange()
|
|
129
|
+
try { awaitCancellation() }
|
|
130
|
+
finally {
|
|
131
|
+
if (input === session) input = null
|
|
132
|
+
onInputChange()
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// compose's keyboard controller: show and hide move the keyboard and keep
|
|
137
|
+
// the session, as Done does on android. a session opens with the keyboard
|
|
138
|
+
// up, as android's legacy text input service shows it on startInput
|
|
139
|
+
@Suppress("DEPRECATION")
|
|
140
|
+
override val textInputService: PlatformTextInputService = object : PlatformTextInputService {
|
|
141
|
+
override fun startInput(value: TextFieldValue, imeOptions: ImeOptions,
|
|
142
|
+
onEditCommand: (List<EditCommand>) -> Unit, onImeActionPerformed: (ImeAction) -> Unit) = Unit
|
|
143
|
+
override fun stopInput() = Unit
|
|
144
|
+
override fun showSoftwareKeyboard() { input?.request(true); onInputChange() }
|
|
145
|
+
override fun hideSoftwareKeyboard() { input?.request(false); onInputChange() }
|
|
146
|
+
override fun updateState(oldValue: TextFieldValue?, newValue: TextFieldValue) = Unit
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
internal class PeachInputSession(val token: Int, val request: PlatformTextInputMethodRequest) {
|
|
151
|
+
var keyboard = true
|
|
152
|
+
private set
|
|
153
|
+
// each show or hide compose asks for, so a repeat still reaches the keyboard
|
|
154
|
+
private var keyboardRequest = 0
|
|
155
|
+
private val options get() = request.imeOptions
|
|
156
|
+
|
|
157
|
+
// EditorInfo.android.kt: a single line field's default action is Done; a
|
|
158
|
+
// multi line field's default has no enter action, so enter types a newline
|
|
159
|
+
private val action: ImeAction? get() = when (options.imeAction) {
|
|
160
|
+
ImeAction.Default -> if (options.singleLine) ImeAction.Done else null
|
|
161
|
+
ImeAction.None -> null
|
|
162
|
+
else -> options.imeAction
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
fun request(visible: Boolean) {
|
|
166
|
+
keyboard = visible
|
|
167
|
+
keyboardRequest++
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
private fun rect(rect: Rect?) = rect?.let { JSONArray().put(it.left).put(it.top).put(it.right).put(it.bottom) }
|
|
171
|
+
|
|
172
|
+
fun state(): JSONObject {
|
|
173
|
+
val value = request.value()
|
|
174
|
+
return JSONObject().put("token", token).put("keyboard", keyboard).put("keyboardRequest", keyboardRequest)
|
|
175
|
+
.put("value", value.text).put("selectionStart", value.selection.start).put("selectionEnd", value.selection.end)
|
|
176
|
+
.put("singleLine", options.singleLine).put("enterInsertsNewline", action == null && !options.singleLine)
|
|
177
|
+
.put("keyboardType", when (options.keyboardType) {
|
|
178
|
+
KeyboardType.Number -> "number"
|
|
179
|
+
KeyboardType.Phone -> "phone"
|
|
180
|
+
KeyboardType.Uri -> "uri"
|
|
181
|
+
KeyboardType.Email -> "email"
|
|
182
|
+
KeyboardType.Password -> "password"
|
|
183
|
+
KeyboardType.NumberPassword -> "number-password"
|
|
184
|
+
KeyboardType.Decimal -> "decimal"
|
|
185
|
+
KeyboardType.Ascii -> "ascii"
|
|
186
|
+
else -> "text"
|
|
187
|
+
})
|
|
188
|
+
.put("imeAction", when (action) {
|
|
189
|
+
ImeAction.Done -> "done"
|
|
190
|
+
ImeAction.Go -> "go"
|
|
191
|
+
ImeAction.Search -> "search"
|
|
192
|
+
ImeAction.Send -> "send"
|
|
193
|
+
ImeAction.Next -> "next"
|
|
194
|
+
ImeAction.Previous -> "previous"
|
|
195
|
+
else -> "default"
|
|
196
|
+
})
|
|
197
|
+
.put("capitalization", when (options.capitalization) {
|
|
198
|
+
KeyboardCapitalization.Characters -> "characters"
|
|
199
|
+
KeyboardCapitalization.Words -> "words"
|
|
200
|
+
KeyboardCapitalization.Sentences -> "sentences"
|
|
201
|
+
else -> "none"
|
|
202
|
+
})
|
|
203
|
+
.put("autoCorrect", options.autoCorrect)
|
|
204
|
+
.put("field", rect(request.textFieldRectInRoot()))
|
|
205
|
+
.put("caret", rect(request.focusedRectInRoot()))
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// one keyboard edit, applied as one batch the way RecordingInputConnection
|
|
209
|
+
// ends a batch edit. typed text commits as an IME's commitText does; a
|
|
210
|
+
// composition replaces its own region, else the edit's range
|
|
211
|
+
fun edit(command: JSONObject): Boolean {
|
|
212
|
+
val value = request.value()
|
|
213
|
+
val start = command.optInt("start")
|
|
214
|
+
val end = command.optInt("end")
|
|
215
|
+
val composing = value.composition?.let { it.start == start && it.end == end } == true
|
|
216
|
+
val commands: List<EditCommand> = when (command.getString("kind")) {
|
|
217
|
+
"text" -> listOf(CommitTextCommand(command.getString("text"), 1))
|
|
218
|
+
"backspace" -> listOf(BackspaceCommand())
|
|
219
|
+
"enter" -> {
|
|
220
|
+
val performed = action
|
|
221
|
+
if (performed != null) {
|
|
222
|
+
request.onImeAction?.invoke(performed)
|
|
223
|
+
return true
|
|
224
|
+
}
|
|
225
|
+
if (options.singleLine) return false
|
|
226
|
+
listOf(CommitTextCommand("\n", 1))
|
|
227
|
+
}
|
|
228
|
+
"compositionStart" -> if (start == end) return true else listOf(SetComposingRegionCommand(start, end))
|
|
229
|
+
"replace" -> {
|
|
230
|
+
val text = command.getString("text")
|
|
231
|
+
val place = if (composing) emptyList() else listOf(FinishComposingTextCommand(), SetSelectionCommand(start, end))
|
|
232
|
+
place + if (command.getString("composition") == "update") SetComposingTextCommand(text, 1) else CommitTextCommand(text, 1)
|
|
233
|
+
}
|
|
234
|
+
else -> error("unknown input edit ${command.getString("kind")}")
|
|
235
|
+
}
|
|
236
|
+
request.onEditCommand(commands)
|
|
237
|
+
return true
|
|
238
|
+
}
|
|
97
239
|
}
|
|
98
240
|
|
|
99
241
|
// android's default and sans-serif families use the same device font bytes as
|
|
@@ -150,12 +292,16 @@ internal class PeachComposeMount(
|
|
|
150
292
|
recomposer, platform.density, LayoutDirection.Ltr, null, platform,
|
|
151
293
|
invalidateLayout = { needsMeasure = true; invalidate(true) }, invalidateDraw = { invalidate(false) },
|
|
152
294
|
)
|
|
295
|
+
// the session's state as last reported; a change reports it again
|
|
296
|
+
private var reportedInput: String? = null
|
|
153
297
|
private var surface: Surface? = null
|
|
154
298
|
private var context: DirectContext? = null
|
|
155
299
|
private var target: BackendRenderTarget? = null
|
|
156
300
|
private var pixels: Bitmap? = null
|
|
157
301
|
private var size = IntSize.Zero
|
|
158
302
|
|
|
303
|
+
init { platform.onInputChange = { invalidate(false) } }
|
|
304
|
+
|
|
159
305
|
fun setContent(content: @Composable () -> Unit) {
|
|
160
306
|
try {
|
|
161
307
|
scene.setContent {
|
|
@@ -221,6 +367,11 @@ internal class PeachComposeMount(
|
|
|
221
367
|
for ((name, args) in frameState) events.add(JSONObject().put("name", name).put("args", args()))
|
|
222
368
|
frameState.clear()
|
|
223
369
|
reply.put("events", JSONArray(events))
|
|
370
|
+
val input = platform.input?.state()?.toString()
|
|
371
|
+
if (input != reportedInput) {
|
|
372
|
+
reportedInput = input
|
|
373
|
+
reply.put("input", input?.let { JSONObject(it) } ?: JSONObject.NULL)
|
|
374
|
+
}
|
|
224
375
|
events.clear()
|
|
225
376
|
if (gpu) checkNotNull(surface).flushAndSubmit()
|
|
226
377
|
else {
|
|
@@ -245,6 +396,37 @@ internal class PeachComposeMount(
|
|
|
245
396
|
invalidate(false)
|
|
246
397
|
}
|
|
247
398
|
|
|
399
|
+
private fun session(token: Int) = platform.input?.takeIf { it.token == token }
|
|
400
|
+
|
|
401
|
+
fun inputEdit(token: Int, command: String): Boolean {
|
|
402
|
+
val session = session(token) ?: return false
|
|
403
|
+
return session.edit(JSONObject(command)).also { invalidate(false) }
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// a hardware key, pressed and released, through compose's key input as an
|
|
407
|
+
// android view dispatches it; true when compose consumed the press
|
|
408
|
+
fun inputKey(token: Int, name: String, ctrl: Boolean, shift: Boolean, alt: Boolean): Boolean {
|
|
409
|
+
if (session(token) == null) return false
|
|
410
|
+
val key = hardwareKeys[name] ?: name.singleOrNull()?.lowercaseChar()?.let { letterKeys["$it"] } ?: return false
|
|
411
|
+
val codePoint = name.singleOrNull()?.code ?: 0
|
|
412
|
+
fun send(type: KeyEventType) = scene.sendKeyEvent(KeyEvent(key, type, codePoint,
|
|
413
|
+
isCtrlPressed = ctrl, isAltPressed = alt, isShiftPressed = shift))
|
|
414
|
+
val consumed = send(KeyEventType.KeyDown)
|
|
415
|
+
send(KeyEventType.KeyUp)
|
|
416
|
+
invalidate(false)
|
|
417
|
+
return consumed
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
fun inputState(token: Int): String = session(token)?.state()?.toString() ?: ""
|
|
421
|
+
|
|
422
|
+
// the host gave focus to another input: the view loses focus, as
|
|
423
|
+
// View.clearFocus does, and compose closes the session itself
|
|
424
|
+
fun inputBlur(token: Int) {
|
|
425
|
+
if (session(token) == null) return
|
|
426
|
+
scene.focusManager.releaseFocus()
|
|
427
|
+
invalidate(false)
|
|
428
|
+
}
|
|
429
|
+
|
|
248
430
|
fun semantics(): String {
|
|
249
431
|
val nodes = JSONArray()
|
|
250
432
|
fun collect(node: SemanticsNode) {
|
|
@@ -274,6 +456,19 @@ internal class PeachComposeMount(
|
|
|
274
456
|
}
|
|
275
457
|
}
|
|
276
458
|
|
|
459
|
+
// the keys a hardware keyboard sends, by their DOM names
|
|
460
|
+
private val hardwareKeys = mapOf(
|
|
461
|
+
"ArrowLeft" to Key.DirectionLeft, "ArrowRight" to Key.DirectionRight,
|
|
462
|
+
"ArrowUp" to Key.DirectionUp, "ArrowDown" to Key.DirectionDown,
|
|
463
|
+
"Home" to Key.MoveHome, "End" to Key.MoveEnd, "PageUp" to Key.PageUp, "PageDown" to Key.PageDown,
|
|
464
|
+
"Tab" to Key.Tab, "Delete" to Key.Delete, "Backspace" to Key.Backspace,
|
|
465
|
+
"Enter" to Key.Enter, "Escape" to Key.Escape,
|
|
466
|
+
)
|
|
467
|
+
private val letterKeys = listOf(
|
|
468
|
+
Key.A, Key.B, Key.C, Key.D, Key.E, Key.F, Key.G, Key.H, Key.I, Key.J, Key.K, Key.L, Key.M,
|
|
469
|
+
Key.N, Key.O, Key.P, Key.Q, Key.R, Key.S, Key.T, Key.U, Key.V, Key.W, Key.X, Key.Y, Key.Z,
|
|
470
|
+
).mapIndexed { index, key -> "${'a' + index}" to key }.toMap()
|
|
471
|
+
|
|
277
472
|
internal val mounts = mutableMapOf<Int, PeachComposeMount>()
|
|
278
473
|
private var nextMount = 1
|
|
279
474
|
private var deviceLocale: String? = null
|
|
@@ -330,6 +525,11 @@ fun peachViewMount(source: String, view: String, hash: String, props: String,
|
|
|
330
525
|
}
|
|
331
526
|
@JsExport fun peachViewFrame(id: Int, millis: Double): String = checkNotNull(mounts[id]).frame((millis * 1_000_000).toLong())
|
|
332
527
|
@JsExport fun peachViewPointer(id: Int, phase: String, x: Float, y: Float, millis: Double) = checkNotNull(mounts[id]).pointer(phase, x, y, millis.toLong())
|
|
528
|
+
@JsExport fun peachViewInputEdit(id: Int, token: Int, command: String): Boolean = checkNotNull(mounts[id]).inputEdit(token, command)
|
|
529
|
+
@JsExport fun peachViewInputKey(id: Int, token: Int, key: String, ctrl: Boolean, shift: Boolean, alt: Boolean): Boolean =
|
|
530
|
+
checkNotNull(mounts[id]).inputKey(token, key, ctrl, shift, alt)
|
|
531
|
+
@JsExport fun peachViewInputState(id: Int, token: Int): String = checkNotNull(mounts[id]).inputState(token)
|
|
532
|
+
@JsExport fun peachViewInputBlur(id: Int, token: Int) = checkNotNull(mounts[id]).inputBlur(token)
|
|
333
533
|
@JsExport fun peachViewSemantics(id: Int): String = checkNotNull(mounts[id]).semantics()
|
|
334
534
|
@JsExport fun peachViewDispose(id: Int) { mounts.remove(id)?.close() }
|
|
335
535
|
|
|
@@ -207,6 +207,19 @@ class JSONObject() {
|
|
|
207
207
|
return this
|
|
208
208
|
}
|
|
209
209
|
|
|
210
|
+
// android's coercions: any value reads as its string; a number or a
|
|
211
|
+
// numeric string reads as an int, anything else as the fallback
|
|
212
|
+
fun getString(name: String): String = when (val value = get(name)) {
|
|
213
|
+
is String -> value
|
|
214
|
+
else -> value.toString()
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
fun optInt(name: String, fallback: Int = 0): Int = when (val value = opt(name)) {
|
|
218
|
+
is Number -> value.toInt()
|
|
219
|
+
is String -> value.toDoubleOrNull()?.toInt() ?: fallback
|
|
220
|
+
else -> fallback
|
|
221
|
+
}
|
|
222
|
+
|
|
210
223
|
fun optBoolean(name: String): Boolean = when (val value = opt(name)) {
|
|
211
224
|
is Boolean -> value
|
|
212
225
|
is String -> value.equals("true", ignoreCase = true)
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
package dev.contrast.kotlinapp
|
|
2
|
+
|
|
3
|
+
import androidx.compose.animation.AnimatedVisibility
|
|
4
|
+
import androidx.compose.animation.animateColorAsState
|
|
5
|
+
import androidx.compose.animation.core.animateDpAsState
|
|
6
|
+
import androidx.compose.foundation.background
|
|
7
|
+
import androidx.compose.foundation.layout.Arrangement
|
|
8
|
+
import androidx.compose.foundation.layout.Box
|
|
9
|
+
import androidx.compose.foundation.layout.Column
|
|
10
|
+
import androidx.compose.foundation.layout.fillMaxSize
|
|
11
|
+
import androidx.compose.foundation.layout.fillMaxWidth
|
|
12
|
+
import androidx.compose.foundation.layout.height
|
|
13
|
+
import androidx.compose.foundation.layout.padding
|
|
14
|
+
import androidx.compose.foundation.layout.safeDrawingPadding
|
|
15
|
+
import androidx.compose.foundation.layout.width
|
|
16
|
+
import androidx.compose.material3.Button
|
|
17
|
+
import androidx.compose.material3.Text
|
|
18
|
+
import androidx.compose.runtime.Composable
|
|
19
|
+
import androidx.compose.runtime.LaunchedEffect
|
|
20
|
+
import androidx.compose.runtime.withFrameNanos
|
|
21
|
+
import androidx.compose.runtime.getValue
|
|
22
|
+
import androidx.compose.runtime.mutableStateOf
|
|
23
|
+
import androidx.compose.runtime.remember
|
|
24
|
+
import androidx.compose.runtime.setValue
|
|
25
|
+
import androidx.compose.ui.Modifier
|
|
26
|
+
import androidx.compose.ui.graphics.Color
|
|
27
|
+
import androidx.compose.ui.unit.dp
|
|
28
|
+
import kotlin.math.roundToInt
|
|
29
|
+
|
|
30
|
+
// a tap flips one state that AnimatedVisibility, animateDpAsState and
|
|
31
|
+
// animateColorAsState each animate on the frame clock; the label reads the
|
|
32
|
+
// animated width, so it settles only when the animation has finished. took
|
|
33
|
+
// is the frame clock time and frame count from the flip to the width's arrival
|
|
34
|
+
@Composable
|
|
35
|
+
fun Anim() {
|
|
36
|
+
var on by remember { mutableStateOf(false) }
|
|
37
|
+
var flips by remember { mutableStateOf(0) }
|
|
38
|
+
var took by remember { mutableStateOf("none") }
|
|
39
|
+
val target = if (on) 240.dp else 80.dp
|
|
40
|
+
val width by animateDpAsState(target, label = "width")
|
|
41
|
+
LaunchedEffect(flips) {
|
|
42
|
+
if (flips == 0) return@LaunchedEffect
|
|
43
|
+
val start = withFrameNanos { it }
|
|
44
|
+
var count = 0
|
|
45
|
+
var end = start
|
|
46
|
+
while (width != target) end = withFrameNanos { count += 1; it }
|
|
47
|
+
took = "${(end - start) / 1_000_000}ms $count frames"
|
|
48
|
+
}
|
|
49
|
+
val color by animateColorAsState(if (on) Color(0xFF3F51B5) else Color(0xFFE91E63), label = "color")
|
|
50
|
+
Column(
|
|
51
|
+
Modifier.fillMaxSize().background(Color(0xFFE8EEF8)).safeDrawingPadding().padding(16.dp),
|
|
52
|
+
verticalArrangement = Arrangement.spacedBy(12.dp),
|
|
53
|
+
) {
|
|
54
|
+
Text("Anim: $on width ${if (width == target) "${target.value.roundToInt()}" else "moving"}")
|
|
55
|
+
Button(onClick = { on = !on; flips += 1 }) { Text("Animate") }
|
|
56
|
+
Text("Took: $took")
|
|
57
|
+
Box(Modifier.width(width).height(48.dp).background(color))
|
|
58
|
+
AnimatedVisibility(on) {
|
|
59
|
+
Text("Panel", Modifier.fillMaxWidth().background(Color(0xFF009688)).padding(24.dp), color = Color.White)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
package dev.contrast.kotlinapp
|
|
2
|
+
|
|
3
|
+
import androidx.compose.foundation.background
|
|
4
|
+
import androidx.compose.foundation.layout.Arrangement
|
|
5
|
+
import androidx.compose.foundation.layout.Column
|
|
6
|
+
import androidx.compose.foundation.layout.fillMaxSize
|
|
7
|
+
import androidx.compose.foundation.layout.fillMaxWidth
|
|
8
|
+
import androidx.compose.foundation.layout.padding
|
|
9
|
+
import androidx.compose.foundation.layout.safeDrawingPadding
|
|
10
|
+
import androidx.compose.foundation.text.KeyboardActions
|
|
11
|
+
import androidx.compose.foundation.text.KeyboardOptions
|
|
12
|
+
import androidx.compose.material3.OutlinedTextField
|
|
13
|
+
import androidx.compose.material3.Text
|
|
14
|
+
import androidx.compose.runtime.Composable
|
|
15
|
+
import androidx.compose.runtime.getValue
|
|
16
|
+
import androidx.compose.runtime.mutableStateOf
|
|
17
|
+
import androidx.compose.runtime.remember
|
|
18
|
+
import androidx.compose.runtime.setValue
|
|
19
|
+
import androidx.compose.ui.Modifier
|
|
20
|
+
import androidx.compose.ui.focus.onFocusChanged
|
|
21
|
+
import androidx.compose.ui.graphics.Color
|
|
22
|
+
import androidx.compose.ui.text.input.ImeAction
|
|
23
|
+
import androidx.compose.ui.unit.dp
|
|
24
|
+
|
|
25
|
+
// a single line field a tap focuses, typing fills and Done finishes, keeping
|
|
26
|
+
// its focus as android does
|
|
27
|
+
@Composable
|
|
28
|
+
fun Form() {
|
|
29
|
+
var name by remember { mutableStateOf("") }
|
|
30
|
+
var focused by remember { mutableStateOf(false) }
|
|
31
|
+
var done by remember { mutableStateOf(0) }
|
|
32
|
+
Column(
|
|
33
|
+
Modifier.fillMaxSize().background(Color(0xFFE8EEF8)).safeDrawingPadding().padding(16.dp),
|
|
34
|
+
verticalArrangement = Arrangement.spacedBy(12.dp),
|
|
35
|
+
) {
|
|
36
|
+
Text("Name: ${name.ifEmpty { "empty" }} focus $focused done $done")
|
|
37
|
+
OutlinedTextField(
|
|
38
|
+
value = name,
|
|
39
|
+
onValueChange = { name = it },
|
|
40
|
+
label = { Text("Name") },
|
|
41
|
+
singleLine = true,
|
|
42
|
+
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
|
|
43
|
+
keyboardActions = KeyboardActions(onDone = { done += 1; defaultKeyboardAction(ImeAction.Done) }),
|
|
44
|
+
modifier = Modifier.fillMaxWidth().onFocusChanged { focused = it.isFocused },
|
|
45
|
+
)
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
package dev.contrast.kotlinapp
|
|
2
|
+
|
|
3
|
+
import androidx.compose.foundation.background
|
|
4
|
+
import androidx.compose.foundation.layout.Column
|
|
5
|
+
import androidx.compose.foundation.layout.Spacer
|
|
6
|
+
import androidx.compose.foundation.layout.WindowInsets
|
|
7
|
+
import androidx.compose.foundation.layout.fillMaxSize
|
|
8
|
+
import androidx.compose.foundation.layout.fillMaxWidth
|
|
9
|
+
import androidx.compose.foundation.layout.ime
|
|
10
|
+
import androidx.compose.foundation.layout.padding
|
|
11
|
+
import androidx.compose.foundation.layout.safeDrawingPadding
|
|
12
|
+
import androidx.compose.material3.OutlinedTextField
|
|
13
|
+
import androidx.compose.material3.Text
|
|
14
|
+
import androidx.compose.runtime.Composable
|
|
15
|
+
import androidx.compose.runtime.getValue
|
|
16
|
+
import androidx.compose.runtime.mutableStateOf
|
|
17
|
+
import androidx.compose.runtime.remember
|
|
18
|
+
import androidx.compose.runtime.setValue
|
|
19
|
+
import androidx.compose.ui.Modifier
|
|
20
|
+
import androidx.compose.ui.graphics.Color
|
|
21
|
+
import androidx.compose.ui.layout.onSizeChanged
|
|
22
|
+
import androidx.compose.ui.platform.LocalDensity
|
|
23
|
+
import androidx.compose.ui.unit.dp
|
|
24
|
+
|
|
25
|
+
// safe drawing padding holds a bottom bar above the keyboard, which the IME
|
|
26
|
+
// inset moves as the keyboard opens and closes. a window that fits system
|
|
27
|
+
// windows takes no IME inset, and lifted reports whether its content shrank
|
|
28
|
+
@Composable
|
|
29
|
+
fun Ime() {
|
|
30
|
+
var note by remember { mutableStateOf("") }
|
|
31
|
+
var height by remember { mutableStateOf(0) }
|
|
32
|
+
var tallest by remember { mutableStateOf(0) }
|
|
33
|
+
val shown = WindowInsets.ime.getBottom(LocalDensity.current) > 0
|
|
34
|
+
Column(
|
|
35
|
+
Modifier.fillMaxSize()
|
|
36
|
+
.onSizeChanged { height = it.height; tallest = maxOf(tallest, it.height) }
|
|
37
|
+
.background(Color(0xFFE8EEF8))
|
|
38
|
+
.safeDrawingPadding()
|
|
39
|
+
.padding(16.dp),
|
|
40
|
+
) {
|
|
41
|
+
Text("Ime: ${if (shown) "shown" else "hidden"} lifted ${height < tallest}")
|
|
42
|
+
OutlinedTextField(
|
|
43
|
+
value = note,
|
|
44
|
+
onValueChange = { note = it },
|
|
45
|
+
label = { Text("Note") },
|
|
46
|
+
modifier = Modifier.fillMaxWidth().padding(top = 12.dp),
|
|
47
|
+
)
|
|
48
|
+
Spacer(Modifier.weight(1f))
|
|
49
|
+
Text("Bottom bar", Modifier.fillMaxWidth().background(Color(0xFF3F51B5)).padding(16.dp), color = Color.White)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
package dev.contrast.kotlinapp
|
|
2
|
+
|
|
3
|
+
import androidx.compose.foundation.background
|
|
4
|
+
import androidx.compose.foundation.layout.Arrangement
|
|
5
|
+
import androidx.compose.foundation.layout.Column
|
|
6
|
+
import androidx.compose.foundation.layout.fillMaxSize
|
|
7
|
+
import androidx.compose.foundation.layout.fillMaxWidth
|
|
8
|
+
import androidx.compose.foundation.layout.padding
|
|
9
|
+
import androidx.compose.foundation.layout.safeDrawingPadding
|
|
10
|
+
import androidx.compose.material3.OutlinedTextField
|
|
11
|
+
import androidx.compose.material3.Text
|
|
12
|
+
import androidx.compose.runtime.Composable
|
|
13
|
+
import androidx.compose.runtime.getValue
|
|
14
|
+
import androidx.compose.runtime.mutableStateOf
|
|
15
|
+
import androidx.compose.runtime.remember
|
|
16
|
+
import androidx.compose.runtime.setValue
|
|
17
|
+
import androidx.compose.ui.Modifier
|
|
18
|
+
import androidx.compose.ui.focus.onFocusChanged
|
|
19
|
+
import androidx.compose.ui.graphics.Color
|
|
20
|
+
import androidx.compose.ui.unit.dp
|
|
21
|
+
|
|
22
|
+
// a multi line field with default keyboard options: enter inserts a newline
|
|
23
|
+
// and delete removes what it typed
|
|
24
|
+
@Composable
|
|
25
|
+
fun Note() {
|
|
26
|
+
var note by remember { mutableStateOf("") }
|
|
27
|
+
var focused by remember { mutableStateOf(false) }
|
|
28
|
+
Column(
|
|
29
|
+
Modifier.fillMaxSize().background(Color(0xFFE8EEF8)).safeDrawingPadding().padding(16.dp),
|
|
30
|
+
verticalArrangement = Arrangement.spacedBy(12.dp),
|
|
31
|
+
) {
|
|
32
|
+
Text("Note: ${note.ifEmpty { "empty" }.replace('\n', '|')} focus $focused")
|
|
33
|
+
OutlinedTextField(
|
|
34
|
+
value = note,
|
|
35
|
+
onValueChange = { note = it },
|
|
36
|
+
label = { Text("Note") },
|
|
37
|
+
modifier = Modifier.fillMaxWidth().onFocusChanged { focused = it.isFocused },
|
|
38
|
+
)
|
|
39
|
+
}
|
|
40
|
+
}
|
package/package.json
CHANGED
package/src/kotlin-host.ts
CHANGED
|
@@ -401,6 +401,9 @@ export async function kotlinAppArtifact(
|
|
|
401
401
|
'@JsExport',
|
|
402
402
|
'fun peachAppNight(night: Boolean) = dev.peach.app.peachAppNight(night)',
|
|
403
403
|
'',
|
|
404
|
+
'@JsExport',
|
|
405
|
+
'fun peachAppIme(bottom: Int) = dev.peach.app.peachAppIme(bottom)',
|
|
406
|
+
'',
|
|
404
407
|
].join('\n')
|
|
405
408
|
const generated: Record<string, string> = {
|
|
406
409
|
'PeachEntry.kt': entrySource([]),
|