craft-native 0.0.156 → 0.0.160

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.
@@ -1238,7 +1238,9 @@ export declare const pushNotifications: {
1238
1238
  */
1239
1239
  onReceive(callback: (data: Record<string, unknown>) => void): () => void;
1240
1240
  };
1241
- export type HealthDataType = 'steps' | 'heartRate' | 'activeEnergy' | 'distance' | 'workouts' | 'restingHeartRate' | 'heartRateVariability' | 'bodyMass' | 'sleep';
1241
+ export type HealthDataType = 'steps' | 'heartRate' | 'activeEnergy' | 'distance' | 'workouts' | 'restingHeartRate' | 'heartRateVariability' | 'bodyMass' | 'sleep'
1242
+ /** Food logged by any app, per day: kcal eaten, then grams of protein, carbohydrate and fat. Read only. */
1243
+ | 'dietaryEnergy' | 'dietaryProtein' | 'dietaryCarbohydrates' | 'dietaryFat';
1242
1244
  /** The types with one value per day. `sleep` is hours asleep, counted on the day you woke. */
1243
1245
  export type HealthDailyType = Exclude<HealthDataType, 'workouts'>;
1244
1246
  export interface HealthAuthorizationOptions {
package/dist/cli.js CHANGED
@@ -3303,7 +3303,7 @@ function pinCraftNativeDependency(packagePath, craftVersion) {
3303
3303
  `);
3304
3304
  }
3305
3305
  // package.json
3306
- var version = "0.0.156";
3306
+ var version = "0.0.160";
3307
3307
 
3308
3308
  // bin/cli.ts
3309
3309
  var spawnedFrom = process6.env[CRAFT_CLI_SPAWN_MARKER];
package/dist/index.cjs CHANGED
@@ -310,7 +310,7 @@ function craftBinaryNotFoundMessage(triedPath) {
310
310
  `);
311
311
  }
312
312
  // package.json
313
- var version = "0.0.156";
313
+ var version = "0.0.160";
314
314
 
315
315
  // src/sdk-version.ts
316
316
  var SDK_VERSION = version;
package/dist/index.js CHANGED
@@ -58,7 +58,7 @@ function craftBinaryNotFoundMessage(triedPath) {
58
58
  `);
59
59
  }
60
60
  // package.json
61
- var version = "0.0.156";
61
+ var version = "0.0.160";
62
62
 
63
63
  // src/sdk-version.ts
64
64
  var SDK_VERSION = version;
@@ -3,6 +3,8 @@
3
3
  *
4
4
  * Generates native iOS apps from web content using WKWebView.
5
5
  */
6
+ /** This package's version, which the app names in its user agent (`Craft/<version>`). */
7
+ export declare function resolveCraftVersion(startDir?: string): string;
6
8
  export type CraftAppearance = 'light' | 'dark' | 'system';
7
9
  export interface CraftConfig {
8
10
  appName: string;
@@ -66,9 +66,11 @@ function serializeSimulatorSteps(steps) {
66
66
  throw new Error("Simulator identifiers must be nonempty single tokens");
67
67
  return value;
68
68
  };
69
- return steps.map((step) => {
69
+ const line = (step) => {
70
70
  let arg = "";
71
- if ("seconds" in step && !("text" in step))
71
+ if ("step" in step)
72
+ arg = `${token(step.id)} ${line(step.step)}`;
73
+ else if ("seconds" in step && !("text" in step))
72
74
  arg = String(number(step.seconds));
73
75
  else if ("milliseconds" in step)
74
76
  arg = String(number(step.milliseconds));
@@ -100,8 +102,9 @@ function serializeSimulatorSteps(steps) {
100
102
  if (/[\r\n]/.test(arg))
101
103
  throw new Error("Simulator arguments cannot contain newlines");
102
104
  return `${step.command}${arg ? ` ${arg}` : ""}`;
103
- }).join(`
104
- `) + `
105
+ };
106
+ return `${steps.map(line).join(`
107
+ `)}
105
108
  `;
106
109
  }
107
110
  function createNativeMutationValidator() {
@@ -141,13 +144,22 @@ function createNativeMutationValidator() {
141
144
 
142
145
  // ../ios/src/index.ts
143
146
  var TEMPLATES_DIR = join2(dirname2(import.meta.dir), "templates");
144
- var CRAFT_VERSION = (() => {
145
- try {
146
- return JSON.parse(readFileSync2(join2(dirname2(import.meta.dir), "package.json"), "utf8")).version ?? "0.0.0";
147
- } catch {
148
- return "0.0.0";
147
+ function resolveCraftVersion(startDir = import.meta.dir) {
148
+ let directory = resolve(startDir);
149
+ while (true) {
150
+ try {
151
+ const packageJSON = JSON.parse(readFileSync2(join2(directory, "package.json"), "utf8"));
152
+ if (packageJSON.name === "@craft-native/ios" && typeof packageJSON.version === "string" && packageJSON.version.length > 0)
153
+ return packageJSON.version;
154
+ } catch {}
155
+ const parent = dirname2(directory);
156
+ if (parent === directory)
157
+ break;
158
+ directory = parent;
149
159
  }
150
- })();
160
+ return "0.0.0";
161
+ }
162
+ var CRAFT_VERSION = resolveCraftVersion();
151
163
  function normalizeNativePath(raw) {
152
164
  if (typeof raw !== "string")
153
165
  return null;
@@ -1274,6 +1286,7 @@ export {
1274
1286
  run,
1275
1287
  restoreShell,
1276
1288
  resolveRuntimeDir,
1289
+ resolveCraftVersion,
1277
1290
  resolveAppearance,
1278
1291
  renderWatchEntitlements,
1279
1292
  renderUsageDescriptions,
@@ -36,7 +36,7 @@ export type SimulatorStep = {
36
36
  index: number;
37
37
  text: string;
38
38
  } | {
39
- command: 'typeid';
39
+ command: 'typeid' | 'labelid';
40
40
  id: string;
41
41
  text: string;
42
42
  } | {
@@ -52,6 +52,12 @@ export type SimulatorStep = {
52
52
  } | {
53
53
  command: 'openurl';
54
54
  url: string;
55
+ }
56
+ /** Runs `step` only when the element with this identifier is there (a screen shown the first time). */
57
+ | {
58
+ command: 'ifid';
59
+ id: string;
60
+ step: SimulatorStep;
55
61
  };
56
62
  /** Typed journeys use the same wire protocol as existing line-based scripts. */
57
63
  export declare function serializeSimulatorSteps(steps: readonly SimulatorStep[]): string;
@@ -106,6 +106,12 @@ final class CraftHealth {
106
106
  if let sleepType = HKObjectType.categoryType(forIdentifier: .sleepAnalysis) {
107
107
  readTypes.insert(sleepType)
108
108
  }
109
+ case "dietaryEnergy", "dietaryProtein", "dietaryCarbohydrates", "dietaryFat":
110
+ // What a food log (MyFitnessPal, Lose It!, Cronometer...)
111
+ // writes to Apple Health: read only, never written back.
112
+ if let dietaryType = Self.healthQuantity(type)?.type {
113
+ readTypes.insert(dietaryType)
114
+ }
109
115
  default:
110
116
  break
111
117
  }
@@ -261,6 +267,11 @@ final class CraftHealth {
261
267
  case "restingHeartRate": return (HKQuantityType.quantityType(forIdentifier: .restingHeartRate), bpm, .discreteAverage)
262
268
  case "heartRateVariability": return (HKQuantityType.quantityType(forIdentifier: .heartRateVariabilitySDNN), .secondUnit(with: .milli), .discreteAverage)
263
269
  case "bodyMass": return (HKQuantityType.quantityType(forIdentifier: .bodyMass), .gramUnit(with: .kilo), .mostRecent)
270
+ // A day's food, summed over every meal any app logged: kcal and grams.
271
+ case "dietaryEnergy": return (HKQuantityType.quantityType(forIdentifier: .dietaryEnergyConsumed), .kilocalorie(), .cumulativeSum)
272
+ case "dietaryProtein": return (HKQuantityType.quantityType(forIdentifier: .dietaryProtein), .gram(), .cumulativeSum)
273
+ case "dietaryCarbohydrates": return (HKQuantityType.quantityType(forIdentifier: .dietaryCarbohydrates), .gram(), .cumulativeSum)
274
+ case "dietaryFat": return (HKQuantityType.quantityType(forIdentifier: .dietaryFatTotal), .gram(), .cumulativeSum)
264
275
  default: return nil
265
276
  }
266
277
  }
@@ -1457,6 +1457,19 @@ final class CraftHybridController: UIViewController, UINavigationControllerDeleg
1457
1457
  return popRecognizers(of: nav).contains { $0 === recognizer }
1458
1458
  }
1459
1459
 
1460
+ private func nativeScreenContainsHorizontalScroll(_ screen: CraftNativeScreenController) -> Bool {
1461
+ guard let root = screen.viewIfLoaded else { return false }
1462
+ func visit(_ view: UIView) -> Bool {
1463
+ if let scroll = view as? UIScrollView,
1464
+ scroll.isScrollEnabled,
1465
+ scroll.alwaysBounceHorizontal || scroll.contentSize.width > scroll.bounds.width + 1 {
1466
+ return true
1467
+ }
1468
+ return view.subviews.contains(where: visit)
1469
+ }
1470
+ return visit(root)
1471
+ }
1472
+
1460
1473
  /// The edge swipe goes ahead of the web view's own gestures, which
1461
1474
  /// otherwise hold every touch over the page until the page has answered it.
1462
1475
  func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
@@ -1470,6 +1483,12 @@ final class CraftHybridController: UIViewController, UINavigationControllerDeleg
1470
1483
  func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
1471
1484
  guard let nav = visibleStack, isPopRecognizer(gestureRecognizer),
1472
1485
  nav.viewControllers.count > 1, nav.transitionCoordinator == nil else { return false }
1486
+ if let native = nav.topViewController as? CraftNativeScreenController,
1487
+ gestureRecognizer !== nav.interactivePopGestureRecognizer,
1488
+ nativeScreenContainsHorizontalScroll(native) {
1489
+ let moved = (gestureRecognizer as? UIPanGestureRecognizer)?.translation(in: nav.view).x ?? 0
1490
+ if gestureRecognizer.location(in: nav.view).x - moved > 32 { return false }
1491
+ }
1473
1492
  guard let slot = nav.topViewController as? CraftHybridWebSlot else { return true }
1474
1493
  // Over the page, only from its left edge: a swipe across the page is
1475
1494
  // the page's (a carousel, a slider).