@iternio/react-native-auto-play 0.5.14-beta.1 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/README.md +214 -29
  2. package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/AndroidAutoSession.kt +5 -0
  3. package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridMapTemplate.kt +9 -2
  4. package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/NativeBackdrop.kt +40 -0
  5. package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/VirtualRenderer.kt +52 -0
  6. package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/template/GridTemplate.kt +47 -13
  7. package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/template/Parser.kt +21 -2
  8. package/ios/Types.swift +3 -0
  9. package/ios/extensions/UIImage+Toggle.swift +5 -2
  10. package/ios/hybrid/HybridAutoPlay.swift +28 -16
  11. package/ios/hybrid/HybridMapTemplate.swift +22 -5
  12. package/ios/scenes/AutoPlayInterfaceController.swift +261 -72
  13. package/ios/templates/AutoPlayMapPanelDelegate.swift +190 -0
  14. package/ios/templates/AutoPlayTemplate.swift +24 -2
  15. package/ios/templates/GridTemplate.swift +57 -57
  16. package/ios/templates/InformationTemplate.swift +84 -9
  17. package/ios/templates/ListTemplate.swift +66 -11
  18. package/ios/templates/MapTemplate.swift +83 -68
  19. package/ios/templates/MessageTemplate.swift +72 -6
  20. package/ios/templates/Parser.swift +564 -69
  21. package/ios/templates/SearchTemplate.swift +1 -1
  22. package/ios/templates/TemplateStore.swift +5 -15
  23. package/ios/utils/SymbolFont.swift +13 -28
  24. package/lib/Constants.d.ts +4 -0
  25. package/lib/Constants.js +6 -0
  26. package/lib/index.d.ts +1 -0
  27. package/lib/index.js +1 -0
  28. package/lib/specs/MapTemplate.nitro.d.ts +3 -1
  29. package/lib/templates/GridTemplate.d.ts +23 -3
  30. package/lib/templates/GridTemplate.js +8 -0
  31. package/lib/templates/InformationTemplate.d.ts +38 -12
  32. package/lib/templates/ListTemplate.d.ts +16 -47
  33. package/lib/templates/MapTemplate.d.ts +26 -2
  34. package/lib/templates/MapTemplate.js +16 -2
  35. package/lib/templates/MessageTemplate.d.ts +52 -11
  36. package/lib/templates/MessageTemplate.js +1 -1
  37. package/lib/utils/NitroOptionsPanel.d.ts +103 -0
  38. package/lib/utils/NitroOptionsPanel.js +63 -0
  39. package/lib/utils/NitroSection.d.ts +89 -2
  40. package/lib/utils/NitroSection.js +49 -2
  41. package/nitrogen/generated/android/ReactNativeAutoPlay+autolinking.cmake +1 -0
  42. package/nitrogen/generated/android/c++/JChargingConnector.hpp +79 -0
  43. package/nitrogen/generated/android/c++/JGridImageSize.hpp +64 -0
  44. package/nitrogen/generated/android/c++/JGridTemplateConfig.hpp +7 -1
  45. package/nitrogen/generated/android/c++/JHybridGridTemplateSpec.cpp +4 -0
  46. package/nitrogen/generated/android/c++/JHybridInformationTemplateSpec.cpp +12 -0
  47. package/nitrogen/generated/android/c++/JHybridListTemplateSpec.cpp +12 -0
  48. package/nitrogen/generated/android/c++/JHybridMapTemplateSpec.cpp +78 -3
  49. package/nitrogen/generated/android/c++/JHybridMapTemplateSpec.hpp +2 -1
  50. package/nitrogen/generated/android/c++/JHybridSearchTemplateSpec.cpp +12 -0
  51. package/nitrogen/generated/android/c++/JInformationTemplateConfig.hpp +6 -0
  52. package/nitrogen/generated/android/c++/JListImageType.hpp +67 -0
  53. package/nitrogen/generated/android/c++/JListTemplateConfig.hpp +6 -0
  54. package/nitrogen/generated/android/c++/JNitroChargerLocation.hpp +115 -0
  55. package/nitrogen/generated/android/c++/JNitroChargerOutlet.hpp +82 -0
  56. package/nitrogen/generated/android/c++/JNitroOptionsPanelChargerSection.hpp +112 -0
  57. package/nitrogen/generated/android/c++/JNitroOptionsPanelConfig.hpp +157 -0
  58. package/nitrogen/generated/android/c++/JNitroOptionsPanelGridSection.hpp +102 -0
  59. package/nitrogen/generated/android/c++/JNitroOptionsPanelSection.cpp +30 -0
  60. package/nitrogen/generated/android/c++/JNitroOptionsPanelSection.hpp +129 -0
  61. package/nitrogen/generated/android/c++/JNitroRow.hpp +33 -3
  62. package/nitrogen/generated/android/c++/JNitroSection.hpp +6 -0
  63. package/nitrogen/generated/android/c++/JSearchTemplateConfig.hpp +6 -0
  64. package/nitrogen/generated/android/c++/JWaypointCoordinate.hpp +65 -0
  65. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/ChargingConnector.kt +30 -0
  66. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/GridImageSize.kt +25 -0
  67. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/GridTemplateConfig.kt +9 -4
  68. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridMapTemplateSpec.kt +5 -1
  69. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/ListImageType.kt +26 -0
  70. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/NitroChargerLocation.kt +90 -0
  71. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/NitroChargerOutlet.kt +70 -0
  72. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/NitroOptionsPanelChargerSection.kt +61 -0
  73. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/NitroOptionsPanelConfig.kt +61 -0
  74. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/NitroOptionsPanelGridSection.kt +56 -0
  75. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/NitroOptionsPanelSection.kt +75 -0
  76. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/NitroRow.kt +36 -6
  77. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/WaypointCoordinate.kt +61 -0
  78. package/nitrogen/generated/ios/ReactNativeAutoPlay-Swift-Cxx-Bridge.hpp +174 -0
  79. package/nitrogen/generated/ios/ReactNativeAutoPlay-Swift-Cxx-Umbrella.hpp +27 -0
  80. package/nitrogen/generated/ios/c++/HybridGridTemplateSpecSwift.hpp +3 -0
  81. package/nitrogen/generated/ios/c++/HybridInformationTemplateSpecSwift.hpp +9 -0
  82. package/nitrogen/generated/ios/c++/HybridListTemplateSpecSwift.hpp +9 -0
  83. package/nitrogen/generated/ios/c++/HybridMapTemplateSpecSwift.hpp +47 -1
  84. package/nitrogen/generated/ios/c++/HybridSearchTemplateSpecSwift.hpp +9 -0
  85. package/nitrogen/generated/ios/swift/ChargingConnector.swift +68 -0
  86. package/nitrogen/generated/ios/swift/GridImageSize.swift +48 -0
  87. package/nitrogen/generated/ios/swift/GridTemplateConfig.swift +12 -1
  88. package/nitrogen/generated/ios/swift/HybridMapTemplateSpec.swift +2 -1
  89. package/nitrogen/generated/ios/swift/HybridMapTemplateSpec_cxx.swift +31 -4
  90. package/nitrogen/generated/ios/swift/ListImageType.swift +52 -0
  91. package/nitrogen/generated/ios/swift/NitroChargerLocation.swift +161 -0
  92. package/nitrogen/generated/ios/swift/NitroChargerOutlet.swift +65 -0
  93. package/nitrogen/generated/ios/swift/NitroOptionsPanelChargerSection.swift +64 -0
  94. package/nitrogen/generated/ios/swift/NitroOptionsPanelConfig.swift +94 -0
  95. package/nitrogen/generated/ios/swift/NitroOptionsPanelGridSection.swift +53 -0
  96. package/nitrogen/generated/ios/swift/NitroOptionsPanelSection.swift +32 -0
  97. package/nitrogen/generated/ios/swift/NitroRow.swift +81 -1
  98. package/nitrogen/generated/ios/swift/WaypointCoordinate.swift +52 -0
  99. package/nitrogen/generated/shared/c++/ChargingConnector.hpp +104 -0
  100. package/nitrogen/generated/shared/c++/GridImageSize.hpp +84 -0
  101. package/nitrogen/generated/shared/c++/GridTemplateConfig.hpp +8 -1
  102. package/nitrogen/generated/shared/c++/HybridMapTemplateSpec.cpp +1 -0
  103. package/nitrogen/generated/shared/c++/HybridMapTemplateSpec.hpp +5 -1
  104. package/nitrogen/generated/shared/c++/ListImageType.hpp +88 -0
  105. package/nitrogen/generated/shared/c++/NitroChargerLocation.hpp +131 -0
  106. package/nitrogen/generated/shared/c++/NitroChargerOutlet.hpp +98 -0
  107. package/nitrogen/generated/shared/c++/NitroOptionsPanelChargerSection.hpp +98 -0
  108. package/nitrogen/generated/shared/c++/NitroOptionsPanelConfig.hpp +107 -0
  109. package/nitrogen/generated/shared/c++/NitroOptionsPanelGridSection.hpp +91 -0
  110. package/nitrogen/generated/shared/c++/NitroRow.hpp +39 -2
  111. package/nitrogen/generated/shared/c++/WaypointCoordinate.hpp +91 -0
  112. package/package.json +1 -1
  113. package/src/Constants.ts +9 -0
  114. package/src/index.ts +1 -0
  115. package/src/specs/MapTemplate.nitro.ts +3 -1
  116. package/src/templates/GridTemplate.ts +38 -3
  117. package/src/templates/InformationTemplate.ts +60 -29
  118. package/src/templates/ListTemplate.ts +27 -55
  119. package/src/templates/MapTemplate.ts +60 -2
  120. package/src/templates/MessageTemplate.ts +71 -24
  121. package/src/utils/NitroOptionsPanel.ts +218 -0
  122. package/src/utils/NitroSection.ts +160 -5
@@ -162,7 +162,7 @@ class SearchTemplate: AutoPlayTemplate, CPSearchTemplateDelegate {
162
162
  listTemplate.invalidate()
163
163
 
164
164
  let _ = try await interfaceController.pushTemplate(
165
- listTemplate.template,
165
+ try listTemplate.getTemplate(),
166
166
  animated: true
167
167
  )
168
168
  }
@@ -9,8 +9,7 @@ import CarPlay
9
9
  class TemplateStore {
10
10
  /// Guards `store`. Templates are added from the JS thread (the
11
11
  /// `createXTemplate` hybrid methods are synchronous and never hop actors)
12
- /// while the CarPlay delegate callbacks remove/purge them on the main
13
- /// thread, and Swift dictionaries are not thread-safe.
12
+ /// while the CarPlay delegate callbacks remove/purge them on the main thread
14
13
  private let lock = NSLock()
15
14
  private var store: [String: AutoPlayTemplate] = [:]
16
15
 
@@ -21,7 +20,7 @@ class TemplateStore {
21
20
  }
22
21
 
23
22
  func getCPTemplate(templateId key: String) -> CPTemplate? {
24
- return withLock { store[key] }?.getTemplate()
23
+ return try? withLock { store[key] }?.getTemplate()
25
24
  }
26
25
 
27
26
  func getTemplate(templateId: String) throws -> AutoPlayTemplate {
@@ -36,9 +35,6 @@ class TemplateStore {
36
35
  }
37
36
 
38
37
  func removeTemplate(templateId: String) {
39
- // Remove first, then notify outside the lock: `onPopped` runs a JS
40
- // callback which can re-enter the store (see
41
- // VoiceInputTemplate.onDidDisappear).
42
38
  let removed = withLock { store.removeValue(forKey: templateId) }
43
39
 
44
40
  removed?.onPopped()
@@ -53,11 +49,10 @@ class TemplateStore {
53
49
  }
54
50
 
55
51
  func purge() {
56
- // These templates were popped by a native CarPlay button we cannot
57
- // intercept, so they need an `onPopped()` just like an explicit pop.
52
+ /// These templates were popped by a native CarPlay button we cannot intercept, so they need an `onPopped()`
58
53
  let removed = withLock {
59
54
  let searchTemplates = store.filter {
60
- $0.value.getTemplate() is CPSearchTemplate
55
+ (try? $0.value.getTemplate() is CPSearchTemplate) ?? false
61
56
  }
62
57
  searchTemplates.keys.forEach { store.removeValue(forKey: $0) }
63
58
 
@@ -75,12 +70,7 @@ class TemplateStore {
75
70
  }
76
71
 
77
72
  func disconnect() {
78
- // The session is gone, so these templates will never be popped
79
- // individually. Without an `onPopped()` here anything the app tied to a
80
- // template's lifetime (event listeners, timers, cached render state)
81
- // leaks for the rest of the app lifetime, and the host app keeps
82
- // running after a disconnect. Android does the same on
83
- // `Lifecycle.Event.ON_DESTROY` (AndroidAutoScreen.kt).
73
+ /// notify every visible template about it being gone
84
74
  let removed = withLock {
85
75
  let templates = Array(store.values)
86
76
  store = [:]
@@ -65,7 +65,8 @@ class SymbolFont {
65
65
  foregroundColor: UIColor,
66
66
  backgroundColor: UIColor,
67
67
  size: CGFloat,
68
- fontScale: CGFloat
68
+ fontScale: CGFloat,
69
+ displayScale: CGFloat
69
70
  ) -> UIImage? {
70
71
  guard let font = uiFont(for: glyphImage, size: size, fontScale: fontScale) else {
71
72
  return nil
@@ -89,7 +90,7 @@ class SymbolFont {
89
90
  )
90
91
 
91
92
  // Start drawing
92
- UIGraphicsBeginImageContextWithOptions(canvasSize, false, 0)
93
+ UIGraphicsBeginImageContextWithOptions(canvasSize, false, displayScale)
93
94
  guard let context = UIGraphicsGetCurrentContext() else {
94
95
  return nil
95
96
  }
@@ -128,7 +129,8 @@ class SymbolFont {
128
129
  value: backgroundColor.lightColor
129
130
  ),
130
131
  size: size,
131
- fontScale: fontScale
132
+ fontScale: fontScale,
133
+ displayScale: traitCollection.displayScale
132
134
  ),
133
135
  let darkImage = imageFromGlyph(
134
136
  glyphImage: glyphImage,
@@ -139,7 +141,8 @@ class SymbolFont {
139
141
  value: backgroundColor.darkColor
140
142
  ),
141
143
  size: size,
142
- fontScale: fontScale
144
+ fontScale: fontScale,
145
+ displayScale: traitCollection.displayScale
143
146
  )
144
147
  else {
145
148
  return nil
@@ -148,15 +151,19 @@ class SymbolFont {
148
151
  // Create a UIImageAsset that contains both light and dark variants
149
152
  let imageAsset = UIImageAsset()
150
153
 
154
+ let displayScaleTrait = UITraitCollection(displayScale: traitCollection.displayScale)
155
+
151
156
  // Register the light image for light trait collection
152
157
  let lightTraits = UITraitCollection(traitsFrom: [
153
- UITraitCollection(userInterfaceStyle: .light)
158
+ UITraitCollection(userInterfaceStyle: .light),
159
+ displayScaleTrait,
154
160
  ])
155
161
  imageAsset.register(lightImage, with: lightTraits)
156
162
 
157
163
  // Register the dark image for dark trait collection
158
164
  let darkTraits = UITraitCollection(traitsFrom: [
159
- UITraitCollection(userInterfaceStyle: .dark)
165
+ UITraitCollection(userInterfaceStyle: .dark),
166
+ displayScaleTrait,
160
167
  ])
161
168
  imageAsset.register(darkImage, with: darkTraits)
162
169
 
@@ -167,34 +174,12 @@ class SymbolFont {
167
174
  static func imageFromNitroImage(
168
175
  image: GlyphImage?,
169
176
  size: CGFloat = 32,
170
- noImageAsset: Bool = false,
171
177
  traitCollection: UITraitCollection
172
178
  ) -> UIImage? {
173
179
  guard let image else { return nil }
174
180
 
175
181
  let fontScale = image.fontScale ?? 1.0
176
182
 
177
- if noImageAsset {
178
- let foregroundColor = Parser.doubleToColor(
179
- value: traitCollection.userInterfaceStyle == .light
180
- ? image.color.lightColor : image.color.darkColor
181
- )
182
-
183
- let backgroundColor = Parser.doubleToColor(
184
- value: traitCollection.userInterfaceStyle == .light
185
- ? image.backgroundColor.lightColor
186
- : image.backgroundColor.darkColor
187
- )
188
-
189
- return SymbolFont.imageFromGlyph(
190
- glyphImage: image,
191
- foregroundColor: foregroundColor,
192
- backgroundColor: backgroundColor,
193
- size: size,
194
- fontScale: fontScale
195
- )
196
- }
197
-
198
183
  return SymbolFont.imageFromGlyph(
199
184
  glyphImage: image,
200
185
  size: size,
@@ -0,0 +1,4 @@
1
+ declare const Constants: Readonly<{
2
+ isIos27OrGreater: boolean;
3
+ }>;
4
+ export { Constants };
@@ -0,0 +1,6 @@
1
+ import { Platform } from 'react-native';
2
+ const isIos27OrGreater = Platform.OS === 'ios' && Math.floor(Number(Platform.Version)) >= 27;
3
+ const Constants = {
4
+ isIos27OrGreater,
5
+ };
6
+ export { Constants };
package/lib/index.d.ts CHANGED
@@ -14,6 +14,7 @@ export declare enum AutoPlayModules {
14
14
  AutoPlayRoot = "AutoPlayRoot",
15
15
  CarPlayDashboard = "CarPlayDashboard"
16
16
  }
17
+ export * from './Constants';
17
18
  export * from './components/SafeAreaView';
18
19
  export * from './hooks/useAndroidAutoTelemetry';
19
20
  export * from './hooks/useFocusedEffect';
package/lib/index.js CHANGED
@@ -20,6 +20,7 @@ export var AutoPlayModules;
20
20
  AutoPlayModules["AutoPlayRoot"] = "AutoPlayRoot";
21
21
  AutoPlayModules["CarPlayDashboard"] = "CarPlayDashboard";
22
22
  })(AutoPlayModules || (AutoPlayModules = {}));
23
+ export * from './Constants';
23
24
  export * from './components/SafeAreaView';
24
25
  export * from './hooks/useAndroidAutoTelemetry';
25
26
  export * from './hooks/useFocusedEffect';
@@ -6,6 +6,7 @@ import type { TripConfig, TripPoint, TripPreviewTextConfiguration, TripsConfig }
6
6
  import type { NitroNavigationAlert } from '../utils/NitroAlert';
7
7
  import type { NitroManeuver } from '../utils/NitroManeuver';
8
8
  import type { NitroMapButton } from '../utils/NitroMapButton';
9
+ import type { NitroOptionsPanelConfig } from '../utils/NitroOptionsPanel';
9
10
  import type { NitroTemplateConfig } from './AutoPlay.nitro';
10
11
  interface MapTemplateConfig extends NitroTemplateConfig, NitroMapTemplateConfig {
11
12
  }
@@ -23,8 +24,9 @@ export interface MapTemplate extends HybridObject<{
23
24
  updateVisibleTravelEstimate(templateId: string, visibleTravelEstimate: VisibleTravelEstimate): void;
24
25
  updateTravelEstimates(templateId: string, steps: Array<TripPoint>): void;
25
26
  updateManeuvers(templateId: string, maneuvers: NitroManeuver): void;
26
- startNavigation(templateId: string, trip: TripConfig): void;
27
+ startNavigation(templateId: string, trip: TripConfig): Promise<void>;
27
28
  stopNavigation(templateId: string): void;
28
29
  setManeuverState(templateId: string, state: ManeuverState): void;
30
+ updateOptionsPanel(templateId: string, config?: NitroOptionsPanelConfig): Promise<void>;
29
31
  }
30
32
  export {};
@@ -1,12 +1,18 @@
1
1
  import type { AutoText } from '../types/Text';
2
2
  import { type NitroAction } from '../utils/NitroAction';
3
3
  import { type GridButton, type NitroGridButton } from '../utils/NitroGrid';
4
- import type { BaseMapTemplateConfig } from './MapTemplate';
4
+ import type { BaseMapTemplateConfig, PanelHeaderActions } from './MapTemplate';
5
5
  import { type HeaderActions, type NitroBaseMapTemplateConfig, Template, type TemplateConfig } from './Template';
6
+ /**
7
+ * Controls the size of Android grid items. A selected size requires Android Car API 8.
8
+ * @namespace Android
9
+ */
10
+ export type GridImageSize = 'unset' | 'large' | 'medium' | 'small';
6
11
  export interface NitroGridTemplateConfig extends TemplateConfig {
7
12
  headerActions?: Array<NitroAction>;
8
13
  title: AutoText;
9
14
  buttons: Array<NitroGridButton>;
15
+ imageSize?: GridImageSize;
10
16
  mapConfig?: NitroBaseMapTemplateConfig;
11
17
  }
12
18
  export type GridTemplateConfig = Omit<NitroGridTemplateConfig, 'headerActions' | 'buttons' | 'mapConfig'> & {
@@ -16,10 +22,24 @@ export type GridTemplateConfig = Omit<NitroGridTemplateConfig, 'headerActions' |
16
22
  headerActions?: HeaderActions<GridTemplate>;
17
23
  buttons: Array<GridButton<GridTemplate>>;
18
24
  /**
19
- * If mapConfig is defined, it will use a MapWithContentTemplate with the current template. This results in a GridTemplate with a map in background. No actions need to be specified, can be empty object.
25
+ * Controls the size of all images in the Android grid. Defaults to `unset`, which preserves
26
+ * the platform's standard grid layout. `large`, `medium`, and `small` require Android Car API
27
+ * 8. Ignored (with a `__DEV__` warning) when `mapConfig` is also set — `MapWithContentTemplate`
28
+ * does not support the sized grid content type.
20
29
  * @namespace Android
21
30
  */
22
- mapConfig?: BaseMapTemplateConfig<GridTemplate>;
31
+ imageSize?: GridImageSize;
32
+ /**
33
+ * If mapConfig is defined, it will use a MapWithContentTemplate with the current template. This results in a GridTemplate with a map in background. No actions need to be specified, can be empty object.
34
+ * @namespace Android - uses MapWithContentTemplate
35
+ * @namespace iOS - renders as a CPMapPanel on the current root map template (iOS 27+);
36
+ * `headerActions` here is Android-only — on iOS this template's own `headerActions` are
37
+ * applied to the root map template's nav bar instead, since CarPlay has no separate header
38
+ * for the map behind a panel.
39
+ */
40
+ mapConfig?: Omit<BaseMapTemplateConfig<GridTemplate>, 'headerActions'> & {
41
+ headerActions?: PanelHeaderActions<GridTemplate>;
42
+ };
23
43
  };
24
44
  export declare class GridTemplate extends Template<GridTemplateConfig, HeaderActions<GridTemplate>> {
25
45
  private template;
@@ -1,3 +1,4 @@
1
+ import { Platform } from 'react-native';
1
2
  import { NitroModules } from 'react-native-nitro-modules';
2
3
  import { NitroActionUtil } from '../utils/NitroAction';
3
4
  import { NitroGridUtil } from '../utils/NitroGrid';
@@ -9,6 +10,13 @@ export class GridTemplate extends Template {
9
10
  constructor(config) {
10
11
  super(config);
11
12
  const { headerActions, buttons, mapConfig, ...rest } = config;
13
+ if (__DEV__ &&
14
+ Platform.OS === 'android' &&
15
+ mapConfig != null &&
16
+ rest.imageSize != null &&
17
+ rest.imageSize !== 'unset') {
18
+ console.warn('GridTemplate: imageSize is ignored on Android when mapConfig is set — MapWithContentTemplate does not support the sized grid content type');
19
+ }
12
20
  const nitroConfig = {
13
21
  ...rest,
14
22
  id: this.id,
@@ -3,8 +3,9 @@ import type { AutoText } from '../types/Text';
3
3
  import { type NitroAction } from '../utils/NitroAction';
4
4
  import { type NitroSection } from '../utils/NitroSection';
5
5
  import type { TextRow } from './ListTemplate';
6
- import type { BaseMapTemplateConfig } from './MapTemplate';
6
+ import type { BaseMapTemplateConfig, PanelActionsIos, PanelHeaderActions } from './MapTemplate';
7
7
  import { type HeaderActions, type NitroBaseMapTemplateConfig, Template, type TemplateConfig } from './Template';
8
+ type InformationActionsAndroid<T> = [CustomActionButtonAndroid<T>] | [CustomActionButtonAndroid<T>, CustomActionButtonAndroid<T>];
8
9
  export interface NitroInformationTemplateConfig extends TemplateConfig {
9
10
  headerActions?: Array<NitroAction>;
10
11
  title: AutoText;
@@ -13,7 +14,7 @@ export interface NitroInformationTemplateConfig extends TemplateConfig {
13
14
  mapConfig?: NitroBaseMapTemplateConfig;
14
15
  }
15
16
  export type InformationItems = [TextRow] | [TextRow, TextRow] | [TextRow, TextRow, TextRow] | [TextRow, TextRow, TextRow, TextRow];
16
- export type InformationTemplateConfig = Omit<NitroInformationTemplateConfig, 'headerActions' | 'section' | 'mapConfig' | 'actions'> & {
17
+ type InformationTemplateBaseConfig = Omit<NitroInformationTemplateConfig, 'headerActions' | 'section' | 'mapConfig' | 'actions'> & {
17
18
  /**
18
19
  * action buttons, usually at the the top right on Android and a top bar on iOS
19
20
  */
@@ -23,30 +24,55 @@ export type InformationTemplateConfig = Omit<NitroInformationTemplateConfig, 'he
23
24
  * @namespace iOS this is an InformationTemplate, ⚠️ the row image is NOT supported
24
25
  */
25
26
  items?: InformationItems;
26
- /**
27
- * If mapConfig is defined, it will use a MapWithContentTemplate with the current template. This results in a PaneTemplate with a map in background. No actions need to be specified, can be empty object.
28
- * @namespace Android
29
- */
30
- mapConfig?: BaseMapTemplateConfig<InformationTemplate>;
27
+ };
28
+ /**
29
+ * `actions`/`mapConfig` are a discriminated union — `mapConfig` restricts `actions.ios` to at
30
+ * most one `TextButton` plus one icon-only `ImageButton` (a `CPMapPanel` can't show more), vs. up
31
+ * to three `TextButton`s otherwise. If your `mapConfig` value comes from a variable/prop rather
32
+ * than an inline literal, TS can't narrow which branch applies — assign it to a local `const` and
33
+ * branch with `if (mapConfig) { ... } else { ... }` into two separate constructor calls instead
34
+ * of passing it straight through to one.
35
+ */
36
+ export type InformationTemplateConfig = InformationTemplateBaseConfig & ({
37
+ mapConfig?: undefined;
31
38
  /**
32
39
  * @namespace Android up to 2 buttons of type TextButton, TextAndImageButton or ImageButton
33
40
  * @namespace iOS - up to 3 buttons of type TextButton
34
41
  */
35
42
  actions?: {
36
- android?: [CustomActionButtonAndroid<InformationTemplate>] | [
37
- CustomActionButtonAndroid<InformationTemplate>,
38
- CustomActionButtonAndroid<InformationTemplate>
39
- ];
43
+ android?: InformationActionsAndroid<InformationTemplate>;
40
44
  ios?: [
41
45
  TextButton<InformationTemplate>,
42
46
  TextButton<InformationTemplate>,
43
47
  TextButton<InformationTemplate>
44
48
  ] | [TextButton<InformationTemplate>, TextButton<InformationTemplate>] | [TextButton<InformationTemplate>];
45
49
  };
46
- };
50
+ } | {
51
+ /**
52
+ * If mapConfig is defined, it will use a MapWithContentTemplate with the current template. This results in a PaneTemplate with a map in background. No actions need to be specified, can be empty object.
53
+ * @namespace Android - uses MapWithContentTemplate
54
+ * @namespace iOS - renders as a CPMapPanel on the current root map template (iOS 27+);
55
+ * `headerActions` here is Android-only — on iOS this template's own `headerActions` are
56
+ * applied to the root map template's nav bar instead, since CarPlay has no separate
57
+ * header for the map behind a panel.
58
+ */
59
+ mapConfig: Omit<BaseMapTemplateConfig<InformationTemplate>, 'headerActions'> & {
60
+ headerActions?: PanelHeaderActions<InformationTemplate>;
61
+ };
62
+ /**
63
+ * @namespace Android up to 2 buttons of type TextButton, TextAndImageButton or ImageButton
64
+ * @namespace iOS - the panel can only show one TextButton plus one optional icon-only
65
+ * ImageButton, see PanelActionsIos
66
+ */
67
+ actions?: {
68
+ android?: InformationActionsAndroid<InformationTemplate>;
69
+ ios?: PanelActionsIos<InformationTemplate>;
70
+ };
71
+ });
47
72
  export declare class InformationTemplate extends Template<InformationTemplateConfig, HeaderActions<InformationTemplate>> {
48
73
  private template;
49
74
  constructor(config: InformationTemplateConfig);
50
75
  updateItems(items?: InformationItems): Promise<void>;
51
76
  private getSection;
52
77
  }
78
+ export {};
@@ -1,50 +1,14 @@
1
- import type { AutoImage } from '../types/Image';
2
1
  import type { AutoText } from '../types/Text';
3
2
  import { type NitroAction } from '../utils/NitroAction';
4
- import { type NitroSection } from '../utils/NitroSection';
5
- import type { BaseMapTemplateConfig } from './MapTemplate';
3
+ import { type NitroSection, type Section } from '../utils/NitroSection';
4
+ import type { BaseMapTemplateConfig, PanelHeaderActions } from './MapTemplate';
6
5
  import { type HeaderActions, type NitroBaseMapTemplateConfig, Template, type TemplateConfig } from './Template';
7
- type BaseRow = {
8
- title: AutoText;
9
- enabled?: boolean;
10
- image?: AutoImage;
11
- };
12
- export type DefaultRow<T> = BaseRow & {
13
- type: 'default';
14
- /**
15
- * adds a chevron at the end of the row
16
- */
17
- browsable?: boolean;
18
- onPress: (template: T) => void;
19
- detailedText?: AutoText;
20
- };
21
- export type ToggleRow<T> = BaseRow & {
22
- type: 'toggle';
23
- checked: boolean;
24
- onPress: (template: T, checked: boolean) => void;
25
- };
26
- export type RadioRow<T> = BaseRow & {
27
- type: 'radio';
28
- onPress: (template: T) => void;
29
- selected?: boolean;
30
- };
31
- export type TextRow = BaseRow & {
32
- type: 'text';
33
- detailedText?: AutoText;
34
- };
35
- export type MultiSection<T> = {
36
- type: 'default';
37
- title: string;
38
- items: Array<DefaultRow<T> | ToggleRow<T> | TextRow>;
39
- } | {
40
- type: 'radio';
41
- title: string;
42
- items: Array<RadioRow<T>>;
43
- };
44
- export type SingleSection<T> = {
45
- [K in MultiSection<T> as K['type']]: Omit<K, 'title' | 'detailedText'>;
46
- }[MultiSection<T>['type']];
47
- export type Section<T> = Array<MultiSection<T>> | SingleSection<T>;
6
+ /**
7
+ * Controls the Android image size for a list item.
8
+ * @namespace Android
9
+ */
10
+ export type ListImageType = 'large' | 'medium' | 'small' | 'extra_small' | 'icon';
11
+ export type { DefaultRow, MultiSection, RadioRow, Section, SingleSection, TextRow, ToggleRow, WaypointCoordinate, WaypointRow, } from '../utils/NitroSection';
48
12
  export interface NitroListTemplateConfig extends TemplateConfig {
49
13
  headerActions?: Array<NitroAction>;
50
14
  title: AutoText;
@@ -65,13 +29,18 @@ export type ListTemplateConfig = Omit<NitroListTemplateConfig, 'headerActions' |
65
29
  sections?: Section<ListTemplate>;
66
30
  /**
67
31
  * If mapConfig is defined, it will use a MapWithContentTemplate with the current template. This results in a ListTemplate with a map in background. No actions need to be specified, can be empty object.
68
- * @namespace Android
32
+ * @namespace Android - uses MapWithContentTemplate
33
+ * @namespace iOS - renders as a CPMapPanel on the current root map template (iOS 27+);
34
+ * `headerActions` here is Android-only — on iOS this template's own `headerActions` are
35
+ * applied to the root map template's nav bar instead, since CarPlay has no separate header
36
+ * for the map behind a panel.
69
37
  */
70
- mapConfig?: BaseMapTemplateConfig<ListTemplate>;
38
+ mapConfig?: Omit<BaseMapTemplateConfig<ListTemplate>, 'headerActions'> & {
39
+ headerActions?: PanelHeaderActions<ListTemplate>;
40
+ };
71
41
  };
72
42
  export declare class ListTemplate extends Template<ListTemplateConfig, HeaderActions<ListTemplate>> {
73
43
  private template;
74
44
  constructor(config: ListTemplateConfig);
75
45
  updateSections(sections?: Section<ListTemplate>): Promise<void>;
76
46
  }
77
- export {};
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import type { AutoText } from '..';
3
- import type { ActionButtonAndroid, MapButton, MapPanButton } from '../types/Button';
3
+ import type { ActionButtonAndroid, ImageButton, MapButton, MapPanButton, TextButton } from '../types/Button';
4
4
  import type { AutoManeuver, ManeuverState } from '../types/Maneuver';
5
5
  import type { ColorScheme, RootComponentInitialProps } from '../types/RootComponent';
6
6
  import type { TripConfig, TripPoint, TripPreviewTextConfiguration, TripsConfig } from '../types/Trip';
@@ -8,7 +8,9 @@ import { type NitroAction } from '../utils/NitroAction';
8
8
  import { type NavigationAlert } from '../utils/NitroAlert';
9
9
  import { type NitroColor, type ThemedColor } from '../utils/NitroColor';
10
10
  import { NitroMapButton } from '../utils/NitroMapButton';
11
+ import { type OptionsPanelConfig } from '../utils/NitroOptionsPanel';
11
12
  import { type HeaderActionsIos, type NitroBaseMapTemplateConfig, Template, type TemplateConfig } from './Template';
13
+ export type { ChargerLocation, ChargerOutlet, ChargingConnector, OptionsPanelChargerSection, OptionsPanelConfig, OptionsPanelGridSection, OptionsPanelListSection, OptionsPanelSection, } from '../utils/NitroOptionsPanel';
12
14
  export type Point = {
13
15
  x: number;
14
16
  y: number;
@@ -68,6 +70,17 @@ export type MapHeaderActions<T> = {
68
70
  android?: HeaderActionsAndroidMap<T>;
69
71
  ios?: HeaderActionsIos<T>;
70
72
  };
73
+ /**
74
+ * @namespace iOS - not supported; CarPlay has no separate header for the map behind a panel, so
75
+ * the panel template's own `headerActions` are applied to the root map template's nav bar instead.
76
+ */
77
+ export type PanelHeaderActions<T> = Omit<MapHeaderActions<T>, 'ios'>;
78
+ /**
79
+ * @namespace iOS - a CPMapPanel can only show one CPTextButton (with a title) and one
80
+ * optional icon-only button (any title is dropped natively), so a second action must be an
81
+ * ImageButton rather than a TextButton, and a third action isn't supported at all.
82
+ */
83
+ export type PanelActionsIos<T> = [TextButton<T>] | [TextButton<T>, ImageButton<T>];
71
84
  export type BaseMapTemplateConfig<T> = {
72
85
  /**
73
86
  * buttons that represent actions on the map template, usually on the bottom right corner
@@ -85,6 +98,12 @@ export type MapTemplateConfig = Omit<NitroMapTemplateConfig, 'mapButtons' | 'hea
85
98
  * react component that is rendered
86
99
  */
87
100
  component: React.ComponentType<RootComponentInitialProps>;
101
+ /**
102
+ * the panel shown when tapping the ellipsis button next to the travel estimates during active navigation (iOS 27+).
103
+ * No-op on Android
104
+ * @namespace iOS
105
+ */
106
+ optionsPanel?: OptionsPanelConfig<MapTemplate>;
88
107
  /**
89
108
  * Notification that navigation was stopped. May occur when another source such as the car head unit starts navigating.
90
109
  * The navigation session on Android Auto/CarPlay is stopped already when this callback is triggered, make sure to stop other things like TTS too.
@@ -110,6 +129,11 @@ export declare class MapTemplate extends Template<MapTemplateConfig, MapTemplate
110
129
  id: string;
111
130
  private template;
112
131
  constructor(config: MapTemplateConfig);
132
+ /**
133
+ * @namespace iOS updates the panel shown when tapping the ellipsis button
134
+ * next to the travel estimates during navigation (iOS 27+).
135
+ */
136
+ updateOptionsPanel(optionsPanel?: OptionsPanelConfig<MapTemplate>): Promise<void> | undefined;
113
137
  setMapButtons(mapButtons: MapTemplateConfig['mapButtons']): Promise<void>;
114
138
  setHeaderActions(headerActions: MapTemplateConfig['headerActions']): Promise<void>;
115
139
  /**
@@ -155,7 +179,7 @@ export declare class MapTemplate extends Template<MapTemplateConfig, MapTemplate
155
179
  * either use showTripSelector to show a set of trips and let the user start the navigation session
156
180
  * or use this to start a navigation session without asking the user
157
181
  */
158
- startNavigation(trip: TripConfig): void;
182
+ startNavigation(trip: TripConfig): Promise<void>;
159
183
  stopNavigation(): void;
160
184
  /**
161
185
  * Sets the current maneuver state indicating progress within a maneuver.
@@ -10,6 +10,7 @@ import { NitroAlertUtil } from '../utils/NitroAlert';
10
10
  import { NitroColorUtil } from '../utils/NitroColor';
11
11
  import { NitroManeuverUtil } from '../utils/NitroManeuver';
12
12
  import { NitroMapButton } from '../utils/NitroMapButton';
13
+ import { NitroOptionsPanelUtil } from '../utils/NitroOptionsPanel';
13
14
  import { Template, } from './Template';
14
15
  const HybridMapTemplate = NitroModules.createHybridObject('MapTemplate');
15
16
  export class MapTemplate extends Template {
@@ -17,7 +18,7 @@ export class MapTemplate extends Template {
17
18
  template = this;
18
19
  constructor(config) {
19
20
  super(config);
20
- const { component, mapButtons, headerActions, onStopNavigation, onAutoDriveEnabled, defaultGuidanceBackgroundColor, ...baseConfig } = config;
21
+ const { component, mapButtons, headerActions, onStopNavigation, onAutoDriveEnabled, defaultGuidanceBackgroundColor, optionsPanel, ...baseConfig } = config;
21
22
  AppRegistry.registerComponent(this.id, () => (props) => React.createElement(MapTemplateProvider, {
22
23
  mapTemplate: this.template,
23
24
  // biome-ignore lint/correctness/noChildrenProp: there is no other way in a ts file
@@ -43,6 +44,19 @@ export class MapTemplate extends Template {
43
44
  : undefined,
44
45
  };
45
46
  HybridMapTemplate.createMapTemplate(nitroConfig);
47
+ // routed through updateOptionsPanel, not embedded in nitroConfig above — nitrogen can't generate
48
+ // a spec for a variant type nested that deep inside NitroMapTemplateConfig.
49
+ this.updateOptionsPanel(optionsPanel);
50
+ }
51
+ /**
52
+ * @namespace iOS updates the panel shown when tapping the ellipsis button
53
+ * next to the travel estimates during navigation (iOS 27+).
54
+ */
55
+ updateOptionsPanel(optionsPanel) {
56
+ if (Platform.OS !== 'ios') {
57
+ return;
58
+ }
59
+ return HybridMapTemplate.updateOptionsPanel(this.id, NitroOptionsPanelUtil.convert(this.template, optionsPanel));
46
60
  }
47
61
  setMapButtons(mapButtons) {
48
62
  const buttons = NitroMapButton.convert(this.template, mapButtons);
@@ -130,7 +144,7 @@ export class MapTemplate extends Template {
130
144
  * or use this to start a navigation session without asking the user
131
145
  */
132
146
  startNavigation(trip) {
133
- HybridMapTemplate.startNavigation(this.id, trip);
147
+ return HybridMapTemplate.startNavigation(this.id, trip);
134
148
  }
135
149
  stopNavigation() {
136
150
  HybridMapTemplate.stopNavigation(this.id);