craft-native 0.0.199 → 0.0.200

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/cli.js CHANGED
@@ -3424,7 +3424,7 @@ function pinCraftNativeDependency(packagePath, craftVersion) {
3424
3424
  `);
3425
3425
  }
3426
3426
  // package.json
3427
- var version = "0.0.199";
3427
+ var version = "0.0.200";
3428
3428
 
3429
3429
  // bin/cli.ts
3430
3430
  var spawnedFrom = process6.env[CRAFT_CLI_SPAWN_MARKER];
package/dist/index.cjs CHANGED
@@ -309,7 +309,7 @@ function craftBinaryNotFoundMessage(triedPath) {
309
309
  `);
310
310
  }
311
311
  // package.json
312
- var version = "0.0.199";
312
+ var version = "0.0.200";
313
313
 
314
314
  // src/sdk-version.ts
315
315
  var SDK_VERSION = version;
@@ -10403,11 +10403,17 @@ ${e.stdout ?? ""}`;
10403
10403
  };
10404
10404
  }
10405
10405
  async function verifyBundleTrust(appPath, policy = {}) {
10406
- const identity = await readBundleIdentity(appPath);
10407
- const requireNotarized = policy.requireNotarized ?? true;
10408
10406
  if (!import_fs3.existsSync(appPath)) {
10409
- return { ok: false, identity, gatekeeperSource: null, reason: "unreadable", detail: `No such bundle: ${appPath}` };
10407
+ return {
10408
+ ok: false,
10409
+ identity: { identifier: null, teamId: null, authority: null },
10410
+ gatekeeperSource: null,
10411
+ reason: "unreadable",
10412
+ detail: `No such bundle: ${appPath}`
10413
+ };
10410
10414
  }
10415
+ const identity = await readBundleIdentity(appPath);
10416
+ const requireNotarized = policy.requireNotarized ?? true;
10411
10417
  try {
10412
10418
  await execFileAsync("codesign", ["--verify", "--deep", "--strict", "--verbose=2", appPath]);
10413
10419
  } catch (error) {
package/dist/index.js CHANGED
@@ -57,7 +57,7 @@ function craftBinaryNotFoundMessage(triedPath) {
57
57
  `);
58
58
  }
59
59
  // package.json
60
- var version = "0.0.199";
60
+ var version = "0.0.200";
61
61
 
62
62
  // src/sdk-version.ts
63
63
  var SDK_VERSION = version;
@@ -10162,11 +10162,17 @@ ${e.stdout ?? ""}`;
10162
10162
  };
10163
10163
  }
10164
10164
  async function verifyBundleTrust(appPath, policy = {}) {
10165
- const identity = await readBundleIdentity(appPath);
10166
- const requireNotarized = policy.requireNotarized ?? true;
10167
10165
  if (!existsSync4(appPath)) {
10168
- return { ok: false, identity, gatekeeperSource: null, reason: "unreadable", detail: `No such bundle: ${appPath}` };
10166
+ return {
10167
+ ok: false,
10168
+ identity: { identifier: null, teamId: null, authority: null },
10169
+ gatekeeperSource: null,
10170
+ reason: "unreadable",
10171
+ detail: `No such bundle: ${appPath}`
10172
+ };
10169
10173
  }
10174
+ const identity = await readBundleIdentity(appPath);
10175
+ const requireNotarized = policy.requireNotarized ?? true;
10170
10176
  try {
10171
10177
  await execFileAsync("codesign", ["--verify", "--deep", "--strict", "--verbose=2", appPath]);
10172
10178
  } catch (error) {
@@ -1022,6 +1022,7 @@ final class CraftHybridController: UIViewController, UINavigationControllerDeleg
1022
1022
  private var tabBarHeight: CGFloat = 0
1023
1023
  private var tabSwipeRecognizers: [UIGestureRecognizer] = []
1024
1024
  private var activeTabSwipeTarget: String?
1025
+ private var tabSwipeSettling = false
1025
1026
  /// The edge the incoming tab started from for the current gesture. Keep
1026
1027
  /// this separate from the live frame: deriving it after the drag begins
1027
1028
  /// makes the target jump when the translation crosses the midpoint.
@@ -1077,6 +1078,7 @@ final class CraftHybridController: UIViewController, UINavigationControllerDeleg
1077
1078
  }
1078
1079
 
1079
1080
  @objc private func tabSwipeRecognized(_ recognizer: UIPanGestureRecognizer) {
1081
+ guard !tabSwipeSettling else { return }
1080
1082
  let tabs = hybrid.tabIds
1081
1083
  guard let index = tabs.firstIndex(of: currentTab), tabs.count > 1 else { return }
1082
1084
  let translation = recognizer.translation(in: view).x
@@ -1101,9 +1103,19 @@ final class CraftHybridController: UIViewController, UINavigationControllerDeleg
1101
1103
  CraftChrome.shared.swipe(to: tabs[next])
1102
1104
  return
1103
1105
  }
1104
- activeTabSwipeTarget = nil
1105
- let complete = recognizer.state == .ended && (abs(translation) >= max(32, view.bounds.width * 0.28) || abs(velocity) > 700)
1106
+ // Keep the target until the settling animation has read it and
1107
+ // finished. Clearing it here made finishInteractiveTabSwipe return
1108
+ // early, leaving cancelled screens offset and completed swipes
1109
+ // jumping straight to their destination.
1110
+ tabSwipeSettling = true
1111
+ let direction: CGFloat = tabSwipeFrom > 0 ? -1 : 1
1112
+ let progress = translation * direction
1113
+ let speed = velocity * direction
1114
+ let complete = recognizer.state == .ended && speed > -700
1115
+ && (progress >= max(32, view.bounds.width * 0.28) || speed > 700)
1106
1116
  finishInteractiveTabSwipe(completed: complete) { [weak self] in
1117
+ self?.activeTabSwipeTarget = nil
1118
+ self?.tabSwipeSettling = false
1107
1119
  guard complete else {
1108
1120
  CraftChrome.shared.cancelTabSwipe()
1109
1121
  return
@@ -1121,8 +1133,19 @@ final class CraftHybridController: UIViewController, UINavigationControllerDeleg
1121
1133
  /// transparent until its page route catches up. Two web roots still use
1122
1134
  /// the route-aware fallback because one WebView cannot render both pages.
1123
1135
  private func beginInteractiveTabSwipe(to id: String, direction: CGFloat) -> Bool {
1124
- guard let current = visibleStack, let target = stacks[id],
1125
- current.view !== target.view,
1136
+ guard let current = visibleStack, view.bounds.width > 0 else { return false }
1137
+ let target: UINavigationController
1138
+ if let mounted = stacks[id] {
1139
+ target = mounted
1140
+ } else {
1141
+ // A native tab must also follow the first swipe to it. Do not
1142
+ // create a second web root here: the shared WebView cannot draw
1143
+ // both pages during the same gesture.
1144
+ guard hybrid.routes.match(id) != nil else { return false }
1145
+ target = makeStack(tab: id, rootPath: id)
1146
+ (target.topViewController as? CraftNativeScreenController)?.screenVisibilityChanged(false)
1147
+ }
1148
+ guard current.view !== target.view,
1126
1149
  !(current.topViewController is CraftHybridWebSlot && target.topViewController is CraftHybridWebSlot),
1127
1150
  view.bounds.width > 0 else { return false }
1128
1151
  if let slot = target.topViewController as? CraftHybridWebSlot {
@@ -1155,7 +1178,11 @@ final class CraftHybridController: UIViewController, UINavigationControllerDeleg
1155
1178
  guard let targetId = activeTabSwipeTarget, let current = visibleStack,
1156
1179
  let target = stacks[targetId] else { return }
1157
1180
  let width = max(1, view.bounds.width)
1158
- let offset = min(width, max(-width, translation))
1181
+ // Reversing past the start stays at zero progress, rather than
1182
+ // pulling both screens away and exposing the background.
1183
+ let offset = tabSwipeFrom > 0
1184
+ ? min(0, max(-width, translation))
1185
+ : max(0, min(width, translation))
1159
1186
  target.view.frame.origin.x = tabSwipeFrom + offset
1160
1187
  current.view.frame.origin.x = offset
1161
1188
  }
@@ -1164,14 +1191,19 @@ final class CraftHybridController: UIViewController, UINavigationControllerDeleg
1164
1191
  guard let targetId = activeTabSwipeTarget, let current = visibleStack,
1165
1192
  let target = stacks[targetId] else { completion(); return }
1166
1193
  let width = view.bounds.width
1167
- let direction: CGFloat = target.view.frame.minX >= 0 ? 1 : -1
1194
+ let direction: CGFloat = tabSwipeFrom > 0 ? 1 : -1
1168
1195
  let end = completed ? 0 : direction * width
1169
- let duration = CraftChrome.motion(.easeOut(duration: completed ? 0.22 : 0.18)) == nil ? 0 : 0.22
1170
- UIView.animate(withDuration: duration, animations: {
1196
+ let settlingDuration = completed ? 0.22 : 0.18
1197
+ let duration = CraftChrome.motion(.easeOut(duration: settlingDuration)) == nil ? 0 : settlingDuration
1198
+ UIView.animate(withDuration: duration, delay: 0, options: [.curveEaseOut, .beginFromCurrentState], animations: {
1171
1199
  target.view.frame.origin.x = end
1172
1200
  current.view.frame.origin.x = completed ? -direction * width : 0
1173
1201
  }, completion: { _ in
1174
- if !completed {
1202
+ if completed {
1203
+ current.view.isHidden = true
1204
+ current.view.frame = self.view.bounds
1205
+ target.view.frame = self.view.bounds
1206
+ } else {
1175
1207
  target.view.isHidden = true
1176
1208
  target.view.frame = self.view.bounds
1177
1209
  current.view.frame = self.view.bounds
@@ -1690,7 +1722,8 @@ final class CraftHybridController: UIViewController, UINavigationControllerDeleg
1690
1722
 
1691
1723
  func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
1692
1724
  if tabSwipeRecognizers.contains(where: { $0 === gestureRecognizer }) {
1693
- guard hybrid.tabIds.count > 1, let nav = visibleStack, let top = nav.topViewController else { return false }
1725
+ guard activeTabSwipeTarget == nil, !tabSwipeSettling,
1726
+ hybrid.tabIds.count > 1, let nav = visibleStack, let top = nav.topViewController else { return false }
1694
1727
  guard CraftChrome.shared.tabSwipeEnabled else { return false }
1695
1728
  // Only between the tabs' own first screens, as the bar shows them:
1696
1729
  // deeper in a tab a swipe to the right is Back, and a screen that
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "craft-native",
3
- "version": "0.0.199",
3
+ "version": "0.0.200",
4
4
  "type": "module",
5
5
  "description": "Build desktop apps with web languages - TypeScript SDK for Craft",
6
6
  "author": "Chris Breuer <chris@stacksjs.org>",