@wasto/cms-components 1.5.10

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 (94) hide show
  1. package/README.md +47 -0
  2. package/dist/index.d.mts +465 -0
  3. package/dist/index.d.ts +465 -0
  4. package/dist/index.js +10445 -0
  5. package/dist/index.mjs +10553 -0
  6. package/package.json +90 -0
  7. package/src/components/announcement-modal/AnnouncementModal.tsx +183 -0
  8. package/src/components/article/Article.tsx +22 -0
  9. package/src/components/article/ArticleCard.tsx +81 -0
  10. package/src/components/article/ArticleExcerpts.tsx +80 -0
  11. package/src/components/article/ArticleList.tsx +114 -0
  12. package/src/components/article/ArticleMarkdown.tsx +170 -0
  13. package/src/components/article/ArticleReaderModal.tsx +93 -0
  14. package/src/components/article/ArticleSingle.tsx +57 -0
  15. package/src/components/bottom-tab/BottomTab.tsx +392 -0
  16. package/src/components/button/Button.tsx +154 -0
  17. package/src/components/challenge/Badges.tsx +84 -0
  18. package/src/components/challenge/BadgesModal.tsx +166 -0
  19. package/src/components/challenge/Challenge.tsx +380 -0
  20. package/src/components/challenge/ChallengeModal.tsx +231 -0
  21. package/src/components/challenge/ChallengeVignette.tsx +249 -0
  22. package/src/components/challenge/ChallengesModal.tsx +243 -0
  23. package/src/components/challenge/QuizModal.tsx +381 -0
  24. package/src/components/challenge/ResultModal.tsx +144 -0
  25. package/src/components/chat/Chat.tsx +928 -0
  26. package/src/components/collection-calendar/CollectionCalendar.tsx +274 -0
  27. package/src/components/columns/Columns.tsx +34 -0
  28. package/src/components/consignes-modal/ConsignesModal.tsx +267 -0
  29. package/src/components/content-inset/ContentInset.tsx +33 -0
  30. package/src/components/header/Header.tsx +391 -0
  31. package/src/components/image/Image.tsx +16 -0
  32. package/src/components/image/ImageFrame.tsx +102 -0
  33. package/src/components/image/ImageMedia.tsx +31 -0
  34. package/src/components/image/ImageUrl.tsx +30 -0
  35. package/src/components/locations-map/LocationSheet.tsx +417 -0
  36. package/src/components/locations-map/LocationsMap.native.tsx +260 -0
  37. package/src/components/locations-map/LocationsMap.tsx +13 -0
  38. package/src/components/locations-map/LocationsMap.web.tsx +10 -0
  39. package/src/components/locations-map/LocationsMapShell.tsx +527 -0
  40. package/src/components/locations-map/LocationsMapView.tsx +108 -0
  41. package/src/components/locations-map/LocationsMapView.web.tsx +331 -0
  42. package/src/components/nav-button/NavButton.tsx +59 -0
  43. package/src/components/next-collection/NextCollection.tsx +621 -0
  44. package/src/components/notifications/NotificationsScreen.tsx +247 -0
  45. package/src/components/page/Page.tsx +64 -0
  46. package/src/components/parapraph/Paragraph.tsx +67 -0
  47. package/src/components/profile/ProfileScreen.tsx +236 -0
  48. package/src/components/recycling-info/RecyclingInfo.tsx +189 -0
  49. package/src/components/safe-area/OptionalSafeAreaProvider.tsx +17 -0
  50. package/src/components/search/Search.tsx +320 -0
  51. package/src/components/select-street-modal/SelectStreetModal.tsx +475 -0
  52. package/src/components/title/Title.tsx +100 -0
  53. package/src/components/vision/Vision.tsx +447 -0
  54. package/src/components/vision/VisionActionCard.tsx +117 -0
  55. package/src/components/vision/VisionCapture.tsx +30 -0
  56. package/src/components/vision/VisionTapOverlay.tsx +122 -0
  57. package/src/contexts/AnnouncementsContext.tsx +171 -0
  58. package/src/contexts/ChallengesContext.tsx +182 -0
  59. package/src/contexts/LocalContext.tsx +227 -0
  60. package/src/contexts/ThemeContext.tsx +37 -0
  61. package/src/contexts/WastoContext.tsx +127 -0
  62. package/src/helpers/blogPost.ts +72 -0
  63. package/src/helpers/generateQuizQuestions.ts +247 -0
  64. package/src/helpers/getContrastColor.ts +19 -0
  65. package/src/helpers/haptics.ts +20 -0
  66. package/src/helpers/hoursSchedule.ts +230 -0
  67. package/src/helpers/htmlContentToMarkdown.ts +114 -0
  68. package/src/helpers/layout.ts +54 -0
  69. package/src/helpers/loadLinearGradient.ts +22 -0
  70. package/src/helpers/maquetteTheme.ts +76 -0
  71. package/src/helpers/markdownUnderlinePlugin.ts +32 -0
  72. package/src/helpers/normalizeWasteTypeRecyclingInfo.ts +80 -0
  73. package/src/helpers/publicMediaUrl.ts +8 -0
  74. package/src/helpers/resolveApiAssetUrl.ts +21 -0
  75. package/src/helpers/systemRoutes.ts +7 -0
  76. package/src/helpers/themeStyles.ts +114 -0
  77. package/src/helpers/useSafeAreaPadding.ts +14 -0
  78. package/src/hooks/useBadges.ts +100 -0
  79. package/src/hooks/useBlogPosts.ts +105 -0
  80. package/src/hooks/useChallenges.ts +110 -0
  81. package/src/hooks/useCities.ts +56 -0
  82. package/src/hooks/useCityAnnouncements.ts +118 -0
  83. package/src/hooks/useCollectionCalendar.ts +421 -0
  84. package/src/hooks/useColumns.ts +20 -0
  85. package/src/hooks/useConsignes.ts +62 -0
  86. package/src/hooks/useLocations.ts +248 -0
  87. package/src/hooks/useNextCollection.ts +238 -0
  88. package/src/hooks/useRecyclingInfo.ts +90 -0
  89. package/src/hooks/useWastoClient.ts +16 -0
  90. package/src/index.ts +142 -0
  91. package/src/navigation/NavigationContext.tsx +56 -0
  92. package/src/sentry/initSentry.ts +120 -0
  93. package/src/types/Theme.ts +72 -0
  94. package/src/types/css-modules.d.ts +1 -0
@@ -0,0 +1,465 @@
1
+ import * as react from 'react';
2
+ import react__default, { ReactNode, PropsWithChildren, ComponentType } from 'react';
3
+ import { StyleProp, ViewStyle, TextStyle } from 'react-native';
4
+ import { BottomTabBarProps } from '@react-navigation/bottom-tabs';
5
+ import { WastoRequestErrorContext, WastoClient } from '@wasto/sdk';
6
+
7
+ type ArticlePropsExcerpts = {
8
+ displayMode: "excerpts";
9
+ excerptLength: number;
10
+ };
11
+
12
+ type ArticlePropsList = {
13
+ displayMode: "list";
14
+ itemsPerPage?: number;
15
+ showPagination?: boolean;
16
+ };
17
+
18
+ type ArticlePropsSingle = {
19
+ displayMode: "single";
20
+ articleId: string;
21
+ };
22
+
23
+ type ArticleDisplayMode = "single" | "list" | "excerpts";
24
+ type ArticleProps = ArticlePropsSingle | ArticlePropsList | ArticlePropsExcerpts;
25
+ declare function Article(props: ArticleProps): ReactNode;
26
+
27
+ type ChallengeProps = {};
28
+ declare function Challenge({}: ChallengeProps): ReactNode;
29
+
30
+ type ChallengeVignetteProps = {};
31
+ declare function ChallengeVignette({}: ChallengeVignetteProps): ReactNode;
32
+
33
+ type ChatProps = {
34
+ title?: string;
35
+ cityId?: string;
36
+ cityGroupId?: string;
37
+ };
38
+ declare function Chat({ title, cityId, cityGroupId: cityGroupIdProp }: ChatProps): react__default.JSX.Element | null;
39
+
40
+ type CollectionCalendarProps = {};
41
+ declare function CollectionCalendar({}: CollectionCalendarProps): ReactNode;
42
+
43
+ type ColumnsColumnCount = 2 | 3;
44
+ type ColumnsProps = PropsWithChildren & {
45
+ columnCount: ColumnsColumnCount;
46
+ };
47
+ declare function Columns({ columnCount, children }: ColumnsProps): ReactNode;
48
+
49
+ type ImageMediaProps = {
50
+ sourceType: "media";
51
+ mediaId: string;
52
+ alt?: string;
53
+ transparentBackground?: boolean;
54
+ showBorder?: boolean;
55
+ };
56
+
57
+ type ImageUrlProps = {
58
+ sourceType: "url";
59
+ url: string;
60
+ alt?: string;
61
+ transparentBackground?: boolean;
62
+ showBorder?: boolean;
63
+ };
64
+
65
+ type ImageProps = ImageUrlProps | ImageMediaProps;
66
+ declare function Image(props: ImageProps): ReactNode;
67
+
68
+ type LocationsMapProps = {
69
+ fullScreen?: boolean;
70
+ showFilters?: boolean;
71
+ /** Header flottant au-dessus de la carte (titre + cloche + profil). */
72
+ overlayHeader?: boolean;
73
+ overlayTitle?: string;
74
+ };
75
+
76
+ /**
77
+ * Web MapLibre canvas. Native uses `LocationsMap.native.tsx` instead of this file.
78
+ */
79
+ declare function LocationsMap(props: LocationsMapProps): ReactNode;
80
+
81
+ type NextCollectionProps = {
82
+ /** Route / screen name for the calendar CTA. Defaults to trying common tab paths. */
83
+ calendarHref?: string;
84
+ /** Show calendar CTA under the slider (home mockup). Default true. */
85
+ showCalendarCta?: boolean;
86
+ /**
87
+ * Initial day offset relative to today (0 = today, 1 = tomorrow, -1 = yesterday).
88
+ * User can still navigate with prev/next.
89
+ */
90
+ dayOffset?: number;
91
+ };
92
+ declare function NextCollection({ calendarHref, showCalendarCta, dayOffset, }: NextCollectionProps): ReactNode;
93
+
94
+ type PageProps = PropsWithChildren & {
95
+ /** When false, content fills the screen without scrolling (e.g. fullScreen map). Default true. */
96
+ scroll?: boolean;
97
+ };
98
+ /**
99
+ * Page shell: top safe area + optional vertical scroll.
100
+ * No global horizontal padding — each block uses ContentInset or is full-bleed
101
+ * (map, calendar grid). Bottom inset is handled by BottomTab when using tabs.
102
+ */
103
+ declare function Page({ children, scroll }: PageProps): ReactNode;
104
+
105
+ type ContentInsetProps = PropsWithChildren & {
106
+ /** Use 12px horizontal instead of 16px */
107
+ tight?: boolean;
108
+ style?: StyleProp<ViewStyle>;
109
+ };
110
+ /**
111
+ * Horizontal page inset applied per block (not on Page).
112
+ * Full-bleed components (map canvas, calendar grid) skip this wrapper.
113
+ */
114
+ declare function ContentInset({ children, tight, style }: ContentInsetProps): ReactNode;
115
+
116
+ type TitleLevel = "1" | "2" | "3";
117
+ type TextAlignHorizontal = "left" | "center" | "right";
118
+ type TextAlignVertical = "top" | "middle" | "bottom";
119
+ type TitleProps = {
120
+ text: string;
121
+ level: TitleLevel;
122
+ style?: StyleProp<TextStyle>;
123
+ numberOfLines?: number;
124
+ alignHorizontal?: TextAlignHorizontal;
125
+ alignVertical?: TextAlignVertical;
126
+ };
127
+ declare function Title({ text, level, style, numberOfLines, alignHorizontal, alignVertical, }: TitleProps): ReactNode;
128
+
129
+ type PararaphProps = {
130
+ text: string;
131
+ style?: StyleProp<TextStyle>;
132
+ alignHorizontal?: TextAlignHorizontal;
133
+ alignVertical?: TextAlignVertical;
134
+ };
135
+ declare function Paragraph({ text, style, alignHorizontal, alignVertical, }: PararaphProps): ReactNode;
136
+
137
+ type RecyclingInfoProps = {};
138
+ declare function RecyclingInfo({}: RecyclingInfoProps): ReactNode;
139
+
140
+ type SearchType = "all" | "waste-type" | "collection-points" | "articles";
141
+ type SearchProps = {
142
+ searchType: SearchType;
143
+ placeholder?: string;
144
+ };
145
+ declare function Search({ searchType, placeholder, }: SearchProps): ReactNode;
146
+
147
+ type AppHeaderSlot = "left" | "center" | "right";
148
+ type AppHeaderLogoElement = {
149
+ id: string;
150
+ type: "logo";
151
+ slot: AppHeaderSlot;
152
+ sourceType: "url" | "media";
153
+ url?: string;
154
+ mediaId?: string;
155
+ };
156
+ type AppHeaderTitleElement = {
157
+ id: string;
158
+ type: "title";
159
+ slot: AppHeaderSlot;
160
+ useScreenTitle?: boolean;
161
+ text?: string;
162
+ };
163
+ type AppHeaderActionElement = {
164
+ id: string;
165
+ type: "action";
166
+ slot: AppHeaderSlot;
167
+ icon: string;
168
+ label?: string;
169
+ action: "navigate" | "back";
170
+ href?: string;
171
+ };
172
+ type AppHeaderElement = AppHeaderLogoElement | AppHeaderTitleElement | AppHeaderActionElement;
173
+ type AppHeaderConfig = {
174
+ elements: AppHeaderElement[];
175
+ };
176
+ type HeaderProps = {
177
+ readonly options: {
178
+ title?: string;
179
+ headerBackVisible?: boolean;
180
+ };
181
+ readonly route: {
182
+ name: string;
183
+ };
184
+ readonly navigation: {
185
+ canGoBack: () => boolean;
186
+ goBack: () => void;
187
+ };
188
+ /** Flotte au-dessus du contenu (ex. carte) : fond transparent. */
189
+ readonly overlay?: boolean;
190
+ /** Config layout (`header.elements`) — logo / titre / actions. */
191
+ readonly headerConfig?: AppHeaderConfig | null;
192
+ };
193
+ declare function Header({ options, route, navigation, overlay, headerConfig, }: HeaderProps): ReactNode;
194
+
195
+ type BottomTabProps = BottomTabBarProps;
196
+ declare function BottomTab({ state, descriptors, navigation, }: BottomTabProps): ReactNode;
197
+
198
+ /** Inbox list — detail uses the shared AnnouncementModal (WastoProvider). */
199
+ declare function NotificationsScreen(): ReactNode;
200
+
201
+ /** Profil local : récap secteur + actions changer / supprimer. */
202
+ declare function ProfileScreen(): ReactNode;
203
+
204
+ type VisionCaptureResult = {
205
+ uri: string;
206
+ };
207
+ type VisionProps = {
208
+ /** URL POST /detect (sinon fournie par startSession). */
209
+ detectUrl?: string;
210
+ /** @deprecated conservé pour compat CMS ; non utilisé en parcours Lens. */
211
+ offerUrl?: string;
212
+ title?: string;
213
+ description?: string;
214
+ height?: number;
215
+ /** Override ville ; sinon LocalContext.selectedCityId. */
216
+ cityId?: string;
217
+ /**
218
+ * Capture custom (sinon expo-image-picker si installé dans l’app hôte).
219
+ */
220
+ onRequestCapture?: () => Promise<VisionCaptureResult | null>;
221
+ };
222
+ declare function Vision({ detectUrl: detectUrlProp, title, description, height: heightProp, cityId: cityIdProp, onRequestCapture, }: VisionProps): react.JSX.Element;
223
+
224
+ type VisionSuggestion = {
225
+ kind: string;
226
+ rank: number;
227
+ title: string;
228
+ body: string;
229
+ payload?: Record<string, unknown>;
230
+ };
231
+ type VisionActionCardProps = {
232
+ suggestions: VisionSuggestion[];
233
+ primaryLabel: string | null;
234
+ confidence: number | null;
235
+ requireConfirm: boolean;
236
+ onConfirm: () => void;
237
+ onRetake: () => void;
238
+ onWrong: () => void;
239
+ busy?: boolean;
240
+ };
241
+
242
+ type ThemeShadowStyle = {
243
+ shadowColor: string;
244
+ shadowOffset: {
245
+ width: number;
246
+ height: number;
247
+ };
248
+ shadowOpacity: number;
249
+ shadowRadius: number;
250
+ elevation: number;
251
+ };
252
+ /**
253
+ * CMS app theme — edited in console (`config.theme`), injected via WastoProvider.
254
+ * Maquette defaults live in `createMaquetteTheme` / `MAQUETTE_*`; components must
255
+ * read colors/radii from here (no hardcoded brand hex / borderRadius).
256
+ */
257
+ type Theme = {
258
+ colors: {
259
+ primary: string;
260
+ onPrimary: string;
261
+ surface: string;
262
+ onSurface: string;
263
+ background: string;
264
+ onBackground: string;
265
+ /** Also used for completed challenges (maquette yellow when customized). */
266
+ success: string;
267
+ onSuccess: string;
268
+ error: string;
269
+ onError: string;
270
+ border: string;
271
+ /** Soft tint of primary (~15–20% alpha). Optional — resolved at runtime if omitted. */
272
+ primarySoft?: string;
273
+ /** Slightly elevated surface (cards on cards). Optional. */
274
+ surfaceElevated?: string;
275
+ /** Secondary / muted text color. Optional — derived from onSurface if omitted. */
276
+ muted?: string;
277
+ gradient: {
278
+ from: string;
279
+ to: string;
280
+ };
281
+ };
282
+ /** Primary corner radius (cards, inputs). */
283
+ radius: number;
284
+ /** Named radii. Optional — derived from `radius` if omitted. */
285
+ radii?: {
286
+ sm: number;
287
+ md: number;
288
+ lg: number;
289
+ pill: number;
290
+ };
291
+ /** Elevation shadows. Optional — sensible defaults if omitted. */
292
+ shadow?: {
293
+ card: ThemeShadowStyle;
294
+ soft: ThemeShadowStyle;
295
+ };
296
+ };
297
+ /** Fully resolved theme (all optional fields filled). */
298
+ type ResolvedTheme = Theme & {
299
+ colors: Theme["colors"] & {
300
+ primarySoft: string;
301
+ surfaceElevated: string;
302
+ muted: string;
303
+ };
304
+ radii: {
305
+ sm: number;
306
+ md: number;
307
+ lg: number;
308
+ pill: number;
309
+ };
310
+ shadow: {
311
+ card: ThemeShadowStyle;
312
+ soft: ThemeShadowStyle;
313
+ };
314
+ };
315
+
316
+ type WastoSentryConfig = {
317
+ dsn?: string;
318
+ enabled?: boolean | string;
319
+ environment?: string;
320
+ debug?: boolean | string;
321
+ release?: string;
322
+ appId?: string;
323
+ };
324
+ type WastoErrorContext = Record<string, unknown> & {
325
+ source?: string;
326
+ };
327
+ /**
328
+ * Initialize Sentry for GitLab Error Tracking (DSN from env).
329
+ * No-op when DSN is empty, disabled, or `@sentry/react-native` is missing.
330
+ */
331
+ declare function initWastoSentry(config?: WastoSentryConfig): boolean;
332
+ declare function isWastoSentryActive(): boolean;
333
+ declare function reportError(error: unknown, context?: WastoErrorContext): void;
334
+ declare function wrapWithSentry<P extends Record<string, unknown>>(Component: ComponentType<P>): ComponentType<P>;
335
+
336
+ type WastoContextType = {
337
+ apiUrl: string;
338
+ appId: string;
339
+ cityGroupId: string | null;
340
+ /**
341
+ * Studio / iframe preview — no anonymous device registration or challenge writes.
342
+ */
343
+ previewMode: boolean;
344
+ reportError: (error: unknown, context?: WastoErrorContext) => void;
345
+ onRequestError?: (error: Error, context: WastoRequestErrorContext) => void;
346
+ };
347
+ type WastoProviderProps = PropsWithChildren & {
348
+ apiUrl: string;
349
+ appId: string;
350
+ theme: Theme;
351
+ /** City group scoping street search / multi-city apps. */
352
+ cityGroupId?: string | null;
353
+ /** GitLab Error Tracking / Sentry config (DSN from env). */
354
+ sentry?: WastoSentryConfig;
355
+ /**
356
+ * When true (Studio preview): LocalContext skips analytics.track / device id.
357
+ */
358
+ previewMode?: boolean;
359
+ };
360
+ declare function WastoProvider(props: WastoProviderProps): ReactNode;
361
+ declare function useWasto(): WastoContextType;
362
+
363
+ /** Shared Wasto HTTP client wired with optional API error reporting. */
364
+ declare function useWastoClient(): WastoClient;
365
+
366
+ /** Fill optional theme fields with sensible defaults (retrocompat / maquette-like). */
367
+ declare function resolveTheme(theme: Theme): ResolvedTheme;
368
+ /**
369
+ * Soft elevation tinted with a brand / category color.
370
+ * Prefer border + category fill for cards; use sparingly (e.g. active chips).
371
+ */
372
+ declare function coloredShadow(hex: string, opacity?: number): ThemeShadowStyle;
373
+ /** Shared card: surface + border + light shadow (console / shadcn). */
374
+ declare function cardStyle(theme: Theme, opts?: {
375
+ elevated?: boolean;
376
+ }): ViewStyle;
377
+ declare function softCardStyle(theme: Theme): ViewStyle;
378
+ /** Inset grouped list section: one surface, rows separated by internal hairlines. */
379
+ declare function groupedSectionStyle(theme: Theme): ViewStyle;
380
+
381
+ /**
382
+ * Layout tokens from `.idea/maquette/00-tokens-et-style.md`.
383
+ * Structural spacing only — colors/radii come from Theme (CMS custom).
384
+ */
385
+ declare const SPACE: {
386
+ /** Horizontal padding for text / section content */
387
+ readonly pageX: 16;
388
+ /** Tighter horizontal (search, chips, CTA bottom) */
389
+ readonly pageXTight: 12;
390
+ /** Vertical gap between section header and content */
391
+ readonly sectionY: 24;
392
+ /** Internal card / challenge row padding */
393
+ readonly cardPad: 20;
394
+ /** Stack gap between list rows */
395
+ readonly stack: 12;
396
+ /** Primary button height */
397
+ readonly buttonH: 42;
398
+ /** Round icon hit target */
399
+ readonly iconHit: 34;
400
+ /** Glyph inside icon hit */
401
+ readonly iconGlyph: 18;
402
+ /** Approx. tab bar content height (excl. safe area) */
403
+ readonly tabBarH: 86;
404
+ /** Next-collection card height (maquette ~196) */
405
+ readonly collectionCardH: 196;
406
+ /** Next-collection card width target */
407
+ readonly collectionCardW: 286;
408
+ };
409
+ /** Suggested radii when building a maquette-aligned Theme (defaults, not hardcoded in UI). */
410
+ declare const MAQUETTE_RADII: {
411
+ readonly sm: 12;
412
+ readonly md: 16;
413
+ readonly lg: 24;
414
+ readonly pill: 999;
415
+ readonly radius: 20;
416
+ };
417
+ declare const MAQUETTE_COLORS: {
418
+ readonly background: "#F5F5F5";
419
+ readonly surface: "#FFFFFF";
420
+ readonly onSurface: "#090909";
421
+ readonly onBackground: "#090909";
422
+ readonly primary: "#00D100";
423
+ readonly onPrimary: "#FFFFFF";
424
+ readonly primarySoft: "#A6ECA6";
425
+ readonly muted: "#9A9A9A";
426
+ readonly border: "#E5E5E5";
427
+ readonly success: "#FEEA16";
428
+ readonly onSuccess: "#090909";
429
+ readonly error: "#D16602";
430
+ readonly onError: "#FFFFFF";
431
+ readonly surfaceElevated: "#FFFFFF";
432
+ };
433
+
434
+ /** Fixed Expo Router paths for shell screens (apps générées + playground). */
435
+ declare const SYSTEM_ROUTES: {
436
+ readonly notifications: "/(system)/notifications";
437
+ readonly profile: "/(system)/profile";
438
+ };
439
+ type SystemRouteKey = keyof typeof SYSTEM_ROUTES;
440
+
441
+ /**
442
+ * Default theme aligned with `.idea/maquette` tokens.
443
+ * Runtime apps override via CMS `config.theme` (console).
444
+ */
445
+ declare function createMaquetteTheme(overrides?: Partial<Theme>): Theme;
446
+
447
+ /**
448
+ * Host-agnostic navigation API.
449
+ * Expo Router apps pass `router.push` / `router.back`;
450
+ * React Navigation apps pass `navigation.navigate` / `goBack`.
451
+ */
452
+ type NavigationApi = {
453
+ push: (href: string) => void;
454
+ canGoBack?: () => boolean;
455
+ goBack?: () => void;
456
+ };
457
+ type NavigationProviderProps = PropsWithChildren & {
458
+ value: NavigationApi;
459
+ };
460
+ declare function NavigationProvider({ value, children }: NavigationProviderProps): ReactNode;
461
+ declare function useAppNavigation(): NavigationApi;
462
+ /** Soft read — returns null when no provider (e.g. isolated component tests). */
463
+ declare function useOptionalAppNavigation(): NavigationApi | null;
464
+
465
+ export { type AppHeaderActionElement, type AppHeaderConfig, type AppHeaderElement, type AppHeaderLogoElement, type AppHeaderSlot, type AppHeaderTitleElement, Article, type ArticleDisplayMode, type ArticleProps, BottomTab, type BottomTabProps, Challenge, type ChallengeProps, ChallengeVignette, type ChallengeVignetteProps, Chat, type ChatProps, CollectionCalendar, type CollectionCalendarProps, Columns, type ColumnsColumnCount, type ColumnsProps, ContentInset, type ContentInsetProps, Header, type HeaderProps, Image, type ImageProps, LocationsMap, type LocationsMapProps, MAQUETTE_COLORS, MAQUETTE_RADII, type NavigationApi, NavigationProvider, type NavigationProviderProps, NextCollection, type NextCollectionProps, NotificationsScreen, Page, type PageProps, Paragraph, type PararaphProps, ProfileScreen, RecyclingInfo, type RecyclingInfoProps, type ResolvedTheme, SPACE, SYSTEM_ROUTES, Search, type SearchProps, type SystemRouteKey, type Theme, type ThemeShadowStyle, Title, type TitleLevel, type TitleProps, Vision, type VisionActionCardProps, type VisionCaptureResult, type VisionProps, type VisionSuggestion, type WastoContextType, type WastoErrorContext, WastoProvider, type WastoProviderProps, type WastoSentryConfig, cardStyle, coloredShadow, createMaquetteTheme, groupedSectionStyle, initWastoSentry, isWastoSentryActive, reportError, resolveTheme, softCardStyle, useAppNavigation, useOptionalAppNavigation, useWasto, useWastoClient, wrapWithSentry };