@wasto/cms-components 1.5.16 → 1.5.18

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/index.d.mts CHANGED
@@ -95,9 +95,11 @@ type AppHeaderLogoElement = {
95
95
  id: string;
96
96
  type: "logo";
97
97
  slot: AppHeaderSlot;
98
- sourceType: "url" | "media";
98
+ sourceType: "url" | "media" | "bundled";
99
99
  url?: string;
100
100
  mediaId?: string;
101
+ /** `require(...)` d’un asset embarqué à l’export (ImageSource). */
102
+ module?: number;
101
103
  };
102
104
  type AppHeaderTitleElement = {
103
105
  id: string;
@@ -141,8 +143,8 @@ type HeaderProps = {
141
143
  */
142
144
  readonly headerConfig?: AppHeaderConfig | null;
143
145
  /**
144
- * Force le padding safe-area top. Par défaut : uniquement en `overlay`
145
- * (le header React Navigation est déjà placé sous la status bar).
146
+ * Padding safe-area top. Défaut `true` (header custom RN = edge-to-edge,
147
+ * il faut l’inset). Passer `false` seulement si le parent inset déjà.
146
148
  */
147
149
  readonly safeTop?: boolean;
148
150
  };
package/dist/index.d.ts CHANGED
@@ -95,9 +95,11 @@ type AppHeaderLogoElement = {
95
95
  id: string;
96
96
  type: "logo";
97
97
  slot: AppHeaderSlot;
98
- sourceType: "url" | "media";
98
+ sourceType: "url" | "media" | "bundled";
99
99
  url?: string;
100
100
  mediaId?: string;
101
+ /** `require(...)` d’un asset embarqué à l’export (ImageSource). */
102
+ module?: number;
101
103
  };
102
104
  type AppHeaderTitleElement = {
103
105
  id: string;
@@ -141,8 +143,8 @@ type HeaderProps = {
141
143
  */
142
144
  readonly headerConfig?: AppHeaderConfig | null;
143
145
  /**
144
- * Force le padding safe-area top. Par défaut : uniquement en `overlay`
145
- * (le header React Navigation est déjà placé sous la status bar).
146
+ * Padding safe-area top. Défaut `true` (header custom RN = edge-to-edge,
147
+ * il faut l’inset). Passer `false` seulement si le parent inset déjà.
146
148
  */
147
149
  readonly safeTop?: boolean;
148
150
  };
package/dist/index.js CHANGED
@@ -8264,6 +8264,7 @@ var DEFAULT_HEADER_ACTIONS = [
8264
8264
  }
8265
8265
  ];
8266
8266
  function resolveLogoUri(apiUrl, el) {
8267
+ if (el.sourceType === "bundled") return null;
8267
8268
  const url = (el.url || "").trim();
8268
8269
  if (url) return url;
8269
8270
  if (el.sourceType === "media" || el.mediaId) {
@@ -8286,6 +8287,17 @@ function HeaderLogo({
8286
8287
  element
8287
8288
  }) {
8288
8289
  const { apiUrl } = useWasto();
8290
+ if (element.sourceType === "bundled" && element.module != null) {
8291
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8292
+ import_react_native34.Image,
8293
+ {
8294
+ source: element.module,
8295
+ style: styles29.logo,
8296
+ resizeMode: "contain",
8297
+ accessibilityLabel: "Logo"
8298
+ }
8299
+ );
8300
+ }
8289
8301
  const uri = resolveLogoUri(apiUrl, element);
8290
8302
  if (!uri) return null;
8291
8303
  return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(HeaderLogoImage, { uri });
@@ -8295,8 +8307,10 @@ function CityLogoFallback() {
8295
8307
  const appData = useOptionalAppData();
8296
8308
  const logoMediaId = typeof appData?.city?.logoMediaId === "string" ? appData.city.logoMediaId : null;
8297
8309
  const uri = publicMediaUrl(apiUrl, logoMediaId);
8298
- if (!uri) return null;
8299
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(HeaderLogoImage, { uri });
8310
+ if (uri) return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(HeaderLogoImage, { uri });
8311
+ const cityName = typeof appData?.city?.name === "string" ? appData.city.name.trim() : "";
8312
+ if (cityName) return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(Title, { text: cityName, level: "1" });
8313
+ return null;
8300
8314
  }
8301
8315
  function HeaderActionButton({
8302
8316
  onPress,
@@ -8326,10 +8340,11 @@ function Header({
8326
8340
  const { theme } = useTheme();
8327
8341
  const t = resolveTheme(theme);
8328
8342
  const themedStyles = createThemedStyles14(theme);
8329
- const applyTopInset = safeTop ?? overlay;
8343
+ const applyTopInset = safeTop ?? true;
8330
8344
  const topInset = useSafeAreaPadding(applyTopInset ? ["top"] : []);
8331
8345
  const { hasUnread } = useAnnouncements();
8332
8346
  const { push } = useAppNavigation();
8347
+ const { apiUrl } = useWasto();
8333
8348
  const screenTitle = (0, import_react35.useMemo)(
8334
8349
  () => options.title ?? route.name,
8335
8350
  [options.title, route.name]
@@ -8340,7 +8355,11 @@ function Header({
8340
8355
  return raw.filter((el) => el.type !== "title");
8341
8356
  }, [headerConfig]);
8342
8357
  const hasCustomActions = elements.some((el) => el.type === "action");
8343
- const hasLogo = elements.some((el) => el.type === "logo");
8358
+ const hasResolvableLogo = elements.some((el) => {
8359
+ if (el.type !== "logo") return false;
8360
+ if (el.sourceType === "bundled" && el.module != null) return true;
8361
+ return resolveLogoUri(apiUrl, el) != null;
8362
+ });
8344
8363
  const bySlot = (0, import_react35.useMemo)(() => {
8345
8364
  const left = [];
8346
8365
  const center = [];
@@ -8463,7 +8482,7 @@ function Header({
8463
8482
  }
8464
8483
  ) : null,
8465
8484
  bySlot.left.map(renderElement),
8466
- !hasLogo ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(CityLogoFallback, {}) : null
8485
+ !hasResolvableLogo ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(CityLogoFallback, {}) : null
8467
8486
  ] }),
8468
8487
  /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8469
8488
  import_react_native34.View,
package/dist/index.mjs CHANGED
@@ -8342,6 +8342,7 @@ var DEFAULT_HEADER_ACTIONS = [
8342
8342
  }
8343
8343
  ];
8344
8344
  function resolveLogoUri(apiUrl, el) {
8345
+ if (el.sourceType === "bundled") return null;
8345
8346
  const url = (el.url || "").trim();
8346
8347
  if (url) return url;
8347
8348
  if (el.sourceType === "media" || el.mediaId) {
@@ -8364,6 +8365,17 @@ function HeaderLogo({
8364
8365
  element
8365
8366
  }) {
8366
8367
  const { apiUrl } = useWasto();
8368
+ if (element.sourceType === "bundled" && element.module != null) {
8369
+ return /* @__PURE__ */ jsx41(
8370
+ Image11,
8371
+ {
8372
+ source: element.module,
8373
+ style: styles29.logo,
8374
+ resizeMode: "contain",
8375
+ accessibilityLabel: "Logo"
8376
+ }
8377
+ );
8378
+ }
8367
8379
  const uri = resolveLogoUri(apiUrl, element);
8368
8380
  if (!uri) return null;
8369
8381
  return /* @__PURE__ */ jsx41(HeaderLogoImage, { uri });
@@ -8373,8 +8385,10 @@ function CityLogoFallback() {
8373
8385
  const appData = useOptionalAppData();
8374
8386
  const logoMediaId = typeof appData?.city?.logoMediaId === "string" ? appData.city.logoMediaId : null;
8375
8387
  const uri = publicMediaUrl(apiUrl, logoMediaId);
8376
- if (!uri) return null;
8377
- return /* @__PURE__ */ jsx41(HeaderLogoImage, { uri });
8388
+ if (uri) return /* @__PURE__ */ jsx41(HeaderLogoImage, { uri });
8389
+ const cityName = typeof appData?.city?.name === "string" ? appData.city.name.trim() : "";
8390
+ if (cityName) return /* @__PURE__ */ jsx41(Title, { text: cityName, level: "1" });
8391
+ return null;
8378
8392
  }
8379
8393
  function HeaderActionButton({
8380
8394
  onPress,
@@ -8404,10 +8418,11 @@ function Header({
8404
8418
  const { theme } = useTheme();
8405
8419
  const t = resolveTheme(theme);
8406
8420
  const themedStyles = createThemedStyles14(theme);
8407
- const applyTopInset = safeTop ?? overlay;
8421
+ const applyTopInset = safeTop ?? true;
8408
8422
  const topInset = useSafeAreaPadding(applyTopInset ? ["top"] : []);
8409
8423
  const { hasUnread } = useAnnouncements();
8410
8424
  const { push } = useAppNavigation();
8425
+ const { apiUrl } = useWasto();
8411
8426
  const screenTitle = useMemo20(
8412
8427
  () => options.title ?? route.name,
8413
8428
  [options.title, route.name]
@@ -8418,7 +8433,11 @@ function Header({
8418
8433
  return raw.filter((el) => el.type !== "title");
8419
8434
  }, [headerConfig]);
8420
8435
  const hasCustomActions = elements.some((el) => el.type === "action");
8421
- const hasLogo = elements.some((el) => el.type === "logo");
8436
+ const hasResolvableLogo = elements.some((el) => {
8437
+ if (el.type !== "logo") return false;
8438
+ if (el.sourceType === "bundled" && el.module != null) return true;
8439
+ return resolveLogoUri(apiUrl, el) != null;
8440
+ });
8422
8441
  const bySlot = useMemo20(() => {
8423
8442
  const left = [];
8424
8443
  const center = [];
@@ -8541,7 +8560,7 @@ function Header({
8541
8560
  }
8542
8561
  ) : null,
8543
8562
  bySlot.left.map(renderElement),
8544
- !hasLogo ? /* @__PURE__ */ jsx41(CityLogoFallback, {}) : null
8563
+ !hasResolvableLogo ? /* @__PURE__ */ jsx41(CityLogoFallback, {}) : null
8545
8564
  ] }),
8546
8565
  /* @__PURE__ */ jsx41(
8547
8566
  View29,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wasto/cms-components",
3
- "version": "1.5.16",
3
+ "version": "1.5.18",
4
4
  "description": "Wast'O CMS React Native components",
5
5
  "main": "./src/index.ts",
6
6
  "module": "./src/index.ts",
@@ -27,9 +27,11 @@ export type AppHeaderLogoElement = {
27
27
  id: string;
28
28
  type: "logo";
29
29
  slot: AppHeaderSlot;
30
- sourceType: "url" | "media";
30
+ sourceType: "url" | "media" | "bundled";
31
31
  url?: string;
32
32
  mediaId?: string;
33
+ /** `require(...)` d’un asset embarqué à l’export (ImageSource). */
34
+ module?: number;
33
35
  };
34
36
 
35
37
  export type AppHeaderTitleElement = {
@@ -94,8 +96,8 @@ export type HeaderProps = {
94
96
  */
95
97
  readonly headerConfig?: AppHeaderConfig | null;
96
98
  /**
97
- * Force le padding safe-area top. Par défaut : uniquement en `overlay`
98
- * (le header React Navigation est déjà placé sous la status bar).
99
+ * Padding safe-area top. Défaut `true` (header custom RN = edge-to-edge,
100
+ * il faut l’inset). Passer `false` seulement si le parent inset déjà.
99
101
  */
100
102
  readonly safeTop?: boolean;
101
103
  };
@@ -104,6 +106,7 @@ function resolveLogoUri(
104
106
  apiUrl: string,
105
107
  el: AppHeaderLogoElement,
106
108
  ): string | null {
109
+ if (el.sourceType === "bundled") return null;
107
110
  const url = (el.url || "").trim();
108
111
  if (url) return url;
109
112
  // Fallback média (export parfois laisse mediaId si rewrite manqué)
@@ -130,6 +133,16 @@ function HeaderLogo({
130
133
  readonly element: AppHeaderLogoElement;
131
134
  }): ReactNode {
132
135
  const { apiUrl } = useWasto();
136
+ if (element.sourceType === "bundled" && element.module != null) {
137
+ return (
138
+ <Image
139
+ source={element.module}
140
+ style={styles.logo as ImageStyle}
141
+ resizeMode="contain"
142
+ accessibilityLabel="Logo"
143
+ />
144
+ );
145
+ }
133
146
  const uri = resolveLogoUri(apiUrl, element);
134
147
  if (!uri) return null;
135
148
  return <HeaderLogoImage uri={uri} />;
@@ -143,8 +156,11 @@ function CityLogoFallback(): ReactNode {
143
156
  ? appData.city.logoMediaId
144
157
  : null;
145
158
  const uri = publicMediaUrl(apiUrl, logoMediaId);
146
- if (!uri) return null;
147
- return <HeaderLogoImage uri={uri} />;
159
+ if (uri) return <HeaderLogoImage uri={uri} />;
160
+ const cityName =
161
+ typeof appData?.city?.name === "string" ? appData.city.name.trim() : "";
162
+ if (cityName) return <Title text={cityName} level="1" />;
163
+ return null;
148
164
  }
149
165
 
150
166
  function HeaderActionButton({
@@ -182,12 +198,12 @@ export function Header({
182
198
  const { theme } = useTheme();
183
199
  const t = resolveTheme(theme);
184
200
  const themedStyles = createThemedStyles(theme);
185
- // Nav header : RN place déjà sous la status bar → pas de double inset.
186
- // Overlay (carte) : on flotte sous le notch → inset requis.
187
- const applyTopInset = safeTop ?? overlay;
201
+ // Header custom = plein écran sous le notch → inset requis (Page ne le re-ajoute plus).
202
+ const applyTopInset = safeTop ?? true;
188
203
  const topInset = useSafeAreaPadding(applyTopInset ? ["top"] : []);
189
204
  const { hasUnread } = useAnnouncements();
190
205
  const { push } = useAppNavigation();
206
+ const { apiUrl } = useWasto();
191
207
 
192
208
  const screenTitle = useMemo(
193
209
  () => options.title ?? route.name,
@@ -202,7 +218,12 @@ export function Header({
202
218
  return raw.filter((el) => el.type !== "title");
203
219
  }, [headerConfig]);
204
220
  const hasCustomActions = elements.some((el) => el.type === "action");
205
- const hasLogo = elements.some((el) => el.type === "logo");
221
+ // Logo CMS sans URI / sans module bundlé → fallback ville.
222
+ const hasResolvableLogo = elements.some((el) => {
223
+ if (el.type !== "logo") return false;
224
+ if (el.sourceType === "bundled" && el.module != null) return true;
225
+ return resolveLogoUri(apiUrl, el) != null;
226
+ });
206
227
 
207
228
  const bySlot = useMemo(() => {
208
229
  const left: AppHeaderElement[] = [];
@@ -329,7 +350,7 @@ export function Header({
329
350
  </HeaderActionButton>
330
351
  ) : null}
331
352
  {bySlot.left.map(renderElement)}
332
- {!hasLogo ? <CityLogoFallback /> : null}
353
+ {!hasResolvableLogo ? <CityLogoFallback /> : null}
333
354
  </View>
334
355
  <View
335
356
  style={styles.slotCenter}