panelui-native 0.78.0 → 0.79.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 (60) hide show
  1. package/lib/module/components/map/index.js +63 -39
  2. package/lib/module/components/map/index.js.map +1 -1
  3. package/lib/module/components/map/map-children.js +54 -0
  4. package/lib/module/components/map/map-children.js.map +1 -0
  5. package/lib/module/components/map/maplibre.js +31 -3
  6. package/lib/module/components/map/maplibre.js.map +1 -1
  7. package/lib/module/components/markdown-editor/index.js +288 -34
  8. package/lib/module/components/markdown-editor/index.js.map +1 -1
  9. package/lib/module/components/markdown-editor/markdown-transforms.js +272 -9
  10. package/lib/module/components/markdown-editor/markdown-transforms.js.map +1 -1
  11. package/lib/module/components/marquee/index.js +119 -46
  12. package/lib/module/components/marquee/index.js.map +1 -1
  13. package/lib/module/components/panelside/index.js +162 -34
  14. package/lib/module/components/panelside/index.js.map +1 -1
  15. package/lib/module/components/progress-button/index.js +279 -52
  16. package/lib/module/components/progress-button/index.js.map +1 -1
  17. package/lib/module/components/progress-button/progress-button-hold.js +40 -6
  18. package/lib/module/components/progress-button/progress-button-hold.js.map +1 -1
  19. package/lib/module/components/theme-selector/index.js +239 -0
  20. package/lib/module/components/theme-selector/index.js.map +1 -0
  21. package/lib/module/components/theme-selector/theme-preview.js +320 -0
  22. package/lib/module/components/theme-selector/theme-preview.js.map +1 -0
  23. package/lib/module/index.js +1 -0
  24. package/lib/module/index.js.map +1 -1
  25. package/lib/typescript/src/components/map/index.d.ts +8 -4
  26. package/lib/typescript/src/components/map/index.d.ts.map +1 -1
  27. package/lib/typescript/src/components/map/map-children.d.ts +41 -0
  28. package/lib/typescript/src/components/map/map-children.d.ts.map +1 -0
  29. package/lib/typescript/src/components/map/maplibre.d.ts +8 -4
  30. package/lib/typescript/src/components/map/maplibre.d.ts.map +1 -1
  31. package/lib/typescript/src/components/markdown-editor/index.d.ts +64 -5
  32. package/lib/typescript/src/components/markdown-editor/index.d.ts.map +1 -1
  33. package/lib/typescript/src/components/markdown-editor/markdown-transforms.d.ts +33 -5
  34. package/lib/typescript/src/components/markdown-editor/markdown-transforms.d.ts.map +1 -1
  35. package/lib/typescript/src/components/marquee/index.d.ts.map +1 -1
  36. package/lib/typescript/src/components/panelside/index.d.ts +79 -4
  37. package/lib/typescript/src/components/panelside/index.d.ts.map +1 -1
  38. package/lib/typescript/src/components/progress-button/index.d.ts +29 -13
  39. package/lib/typescript/src/components/progress-button/index.d.ts.map +1 -1
  40. package/lib/typescript/src/components/progress-button/progress-button-hold.d.ts +26 -6
  41. package/lib/typescript/src/components/progress-button/progress-button-hold.d.ts.map +1 -1
  42. package/lib/typescript/src/components/theme-selector/index.d.ts +107 -0
  43. package/lib/typescript/src/components/theme-selector/index.d.ts.map +1 -0
  44. package/lib/typescript/src/components/theme-selector/theme-preview.d.ts +32 -0
  45. package/lib/typescript/src/components/theme-selector/theme-preview.d.ts.map +1 -0
  46. package/lib/typescript/src/index.d.ts +4 -3
  47. package/lib/typescript/src/index.d.ts.map +1 -1
  48. package/package.json +1 -1
  49. package/src/components/map/index.tsx +63 -36
  50. package/src/components/map/map-children.ts +66 -0
  51. package/src/components/map/maplibre.ts +32 -4
  52. package/src/components/markdown-editor/index.tsx +413 -35
  53. package/src/components/markdown-editor/markdown-transforms.ts +274 -10
  54. package/src/components/marquee/index.tsx +128 -55
  55. package/src/components/panelside/index.tsx +179 -40
  56. package/src/components/progress-button/index.tsx +264 -45
  57. package/src/components/progress-button/progress-button-hold.ts +37 -6
  58. package/src/components/theme-selector/index.tsx +281 -0
  59. package/src/components/theme-selector/theme-preview.tsx +205 -0
  60. package/src/index.ts +15 -0
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Which of a map's children belong to the renderer, and which belong to us.
3
+ *
4
+ * The native map view is not a React Native container. On Android it is a real
5
+ * `FrameLayout`, and it lays its children out itself — so an ordinary view
6
+ * handed to it loses the frame the layout engine computed, arrives stretched
7
+ * to the full size of the map, and covers the surface the map is drawn on. A
8
+ * control group written to sit in a corner ends up in the top-left, full
9
+ * bleed, with the map invisible behind it.
10
+ *
11
+ * So the children are split before they are mounted. Anything the renderer
12
+ * understands — a marker, a route, a layer — goes inside it. Everything else,
13
+ * including `Map.Controls` and any chrome written at the call site, is drawn
14
+ * as a sibling above the map, where the layout engine still owns it.
15
+ *
16
+ * Parts opt in by carrying `MAP_LAYER`, so the rule is a property of the part
17
+ * rather than a list kept somewhere else that a new part could be left out of.
18
+ */
19
+ import { Children, isValidElement, type ReactNode } from 'react';
20
+
21
+ /** Marks a component that has to be mounted inside the native map view. */
22
+ export const MAP_LAYER = Symbol.for('panelui.map.layer');
23
+
24
+ type Layer = { [MAP_LAYER]?: true };
25
+
26
+ /** Tags a part as belonging inside the renderer, and hands it back. */
27
+ export function asMapLayer<T>(part: T): T {
28
+ (part as T & Layer)[MAP_LAYER] = true;
29
+ return part;
30
+ }
31
+
32
+ /** Whether an element type has been tagged with {@link asMapLayer}. */
33
+ export function isMapLayer(type: unknown): boolean {
34
+ return (
35
+ (typeof type === 'function' || typeof type === 'object') &&
36
+ type !== null &&
37
+ (type as Layer)[MAP_LAYER] === true
38
+ );
39
+ }
40
+
41
+ export interface PartitionedMapChildren {
42
+ /** Mounted inside the native map view. */
43
+ layers: ReactNode[];
44
+ /** Drawn as a sibling above it, where React Native's layout still applies. */
45
+ overlay: ReactNode[];
46
+ }
47
+
48
+ /**
49
+ * Splits a map's children into the two halves above.
50
+ *
51
+ * A child that is not an element at all — a string, a number, a nullish branch
52
+ * — goes to the overlay. The renderer drops what it does not recognise, and
53
+ * drops it *silently*, which also puts its own child bookkeeping out of step
54
+ * with React's.
55
+ */
56
+ export function partitionMapChildren(children: ReactNode): PartitionedMapChildren {
57
+ const layers: ReactNode[] = [];
58
+ const overlay: ReactNode[] = [];
59
+
60
+ Children.forEach(children, (child) => {
61
+ if (isValidElement(child) && isMapLayer(child.type)) layers.push(child);
62
+ else if (child !== null && child !== undefined && child !== false) overlay.push(child);
63
+ });
64
+
65
+ return { layers, overlay };
66
+ }
@@ -27,6 +27,7 @@
27
27
  * below against the package rather than assuming they survived.
28
28
  */
29
29
  import type { ComponentType, ReactElement, ReactNode, Ref } from 'react';
30
+ import { TurboModuleRegistry } from 'react-native';
30
31
 
31
32
  /** `[longitude, latitude]` — the order the style spec uses, not the spoken one. */
32
33
  export type LngLat = [number, number];
@@ -34,6 +35,9 @@ export type LngLat = [number, number];
34
35
  /** `[west, south, east, north]`. */
35
36
  export type LngLatBounds = [number, number, number, number];
36
37
 
38
+ /** `[x, y]` in points, measured from the map's own top-left corner. */
39
+ export type PixelPoint = [number, number];
40
+
37
41
  /**
38
42
  * A MapLibre style document. Left loose on purpose: the spec is large, it is
39
43
  * versioned separately from this library, and the parts of it callers pass
@@ -121,7 +125,7 @@ interface MapLibreModule {
121
125
  touchPitch?: boolean;
122
126
  accessible?: boolean;
123
127
  importantForAccessibility?: 'auto' | 'yes' | 'no' | 'no-hide-descendants';
124
- onPress?: (event: NativeEvent<{ coordinates: LngLat }>) => void;
128
+ onPress?: (event: NativeEvent<{ lngLat: LngLat; point: PixelPoint }>) => void;
125
129
  onDidFinishLoadingMap?: () => void;
126
130
  onRegionDidChange?: (event: NativeEvent<ViewState>) => void;
127
131
  children?: ReactNode;
@@ -172,12 +176,35 @@ interface MapLibreModule {
172
176
  }>;
173
177
  }
174
178
 
179
+ /**
180
+ * Whether the renderer's native half is actually in this binary.
181
+ *
182
+ * The JavaScript resolving is not the question. A project that installed the
183
+ * package and then ran in a client built without it — Expo Go being the one
184
+ * everybody meets — has the JavaScript and none of the native views, and a
185
+ * `require` that succeeds there is a `require` that lies. The component would
186
+ * then try to mount a view nothing has registered, which is a crash in native
187
+ * code where a `try` in JavaScript has nothing to catch.
188
+ *
189
+ * `TurboModuleRegistry.get` answers the real question and returns null instead
190
+ * of throwing, so the graceful fallback the component already draws is reached
191
+ * rather than skipped.
192
+ */
193
+ function nativeRendererPresent(): boolean {
194
+ try {
195
+ return TurboModuleRegistry.get('MLRNMapViewModule') !== null;
196
+ } catch {
197
+ return false;
198
+ }
199
+ }
200
+
175
201
  /**
176
202
  * The renderer, or null when it is not installed. Resolved once at module
177
203
  * load — the require is cheap, and caching it keeps a try/catch out of render.
178
204
  */
179
205
  const maplibre: MapLibreModule | null = (() => {
180
206
  try {
207
+ if (!nativeRendererPresent()) return null;
181
208
  // eslint-disable-next-line @typescript-eslint/no-require-imports
182
209
  return require('@maplibre/maplibre-react-native') as MapLibreModule;
183
210
  } catch {
@@ -188,9 +215,10 @@ const maplibre: MapLibreModule | null = (() => {
188
215
  /**
189
216
  * True when a map can actually be drawn.
190
217
  *
191
- * False in any client that cannot load native modules, and in any project that
192
- * has not installed the renderer. Worth checking before routing somewhere whose
193
- * whole content is a map.
218
+ * False in any client that cannot load native modules — Expo Go included, even
219
+ * with the package installed — and in any project that has not installed the
220
+ * renderer. Worth checking before routing somewhere whose whole content is a
221
+ * map.
194
222
  */
195
223
  export const hasMapLibre = maplibre !== null;
196
224