@wasto/cms-components 1.5.15 → 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 +10 -3
- package/dist/index.d.ts +10 -3
- package/dist/index.js +27 -6
- package/dist/index.mjs +27 -6
- package/package.json +1 -1
- package/src/components/header/Header.tsx +37 -7
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;
|
|
@@ -133,15 +135,20 @@ type HeaderProps = {
|
|
|
133
135
|
canGoBack: () => boolean;
|
|
134
136
|
goBack: () => void;
|
|
135
137
|
};
|
|
136
|
-
/** Flotte au-dessus du contenu (ex. carte) : fond transparent. */
|
|
138
|
+
/** Flotte au-dessus du contenu (ex. carte) : fond transparent + safe-area top. */
|
|
137
139
|
readonly overlay?: boolean;
|
|
138
140
|
/**
|
|
139
141
|
* Config layout (`header.elements`) — logo / actions.
|
|
140
142
|
* Si fournie (même vide), le fallback titre d’écran ne s’applique pas.
|
|
141
143
|
*/
|
|
142
144
|
readonly headerConfig?: AppHeaderConfig | null;
|
|
145
|
+
/**
|
|
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à.
|
|
148
|
+
*/
|
|
149
|
+
readonly safeTop?: boolean;
|
|
143
150
|
};
|
|
144
|
-
declare function Header({ options, route, navigation, overlay, headerConfig, }: HeaderProps): ReactNode;
|
|
151
|
+
declare function Header({ options, route, navigation, overlay, headerConfig, safeTop, }: HeaderProps): ReactNode;
|
|
145
152
|
|
|
146
153
|
type LocationsMapProps = {
|
|
147
154
|
fullScreen?: boolean;
|
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;
|
|
@@ -133,15 +135,20 @@ type HeaderProps = {
|
|
|
133
135
|
canGoBack: () => boolean;
|
|
134
136
|
goBack: () => void;
|
|
135
137
|
};
|
|
136
|
-
/** Flotte au-dessus du contenu (ex. carte) : fond transparent. */
|
|
138
|
+
/** Flotte au-dessus du contenu (ex. carte) : fond transparent + safe-area top. */
|
|
137
139
|
readonly overlay?: boolean;
|
|
138
140
|
/**
|
|
139
141
|
* Config layout (`header.elements`) — logo / actions.
|
|
140
142
|
* Si fournie (même vide), le fallback titre d’écran ne s’applique pas.
|
|
141
143
|
*/
|
|
142
144
|
readonly headerConfig?: AppHeaderConfig | null;
|
|
145
|
+
/**
|
|
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à.
|
|
148
|
+
*/
|
|
149
|
+
readonly safeTop?: boolean;
|
|
143
150
|
};
|
|
144
|
-
declare function Header({ options, route, navigation, overlay, headerConfig, }: HeaderProps): ReactNode;
|
|
151
|
+
declare function Header({ options, route, navigation, overlay, headerConfig, safeTop, }: HeaderProps): ReactNode;
|
|
145
152
|
|
|
146
153
|
type LocationsMapProps = {
|
|
147
154
|
fullScreen?: boolean;
|
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 (
|
|
8299
|
-
|
|
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,
|
|
@@ -8320,14 +8334,17 @@ function Header({
|
|
|
8320
8334
|
route,
|
|
8321
8335
|
navigation,
|
|
8322
8336
|
overlay = false,
|
|
8323
|
-
headerConfig
|
|
8337
|
+
headerConfig,
|
|
8338
|
+
safeTop
|
|
8324
8339
|
}) {
|
|
8325
8340
|
const { theme } = useTheme();
|
|
8326
8341
|
const t = resolveTheme(theme);
|
|
8327
8342
|
const themedStyles = createThemedStyles14(theme);
|
|
8328
|
-
const
|
|
8343
|
+
const applyTopInset = safeTop ?? true;
|
|
8344
|
+
const topInset = useSafeAreaPadding(applyTopInset ? ["top"] : []);
|
|
8329
8345
|
const { hasUnread } = useAnnouncements();
|
|
8330
8346
|
const { push } = useAppNavigation();
|
|
8347
|
+
const { apiUrl } = useWasto();
|
|
8331
8348
|
const screenTitle = (0, import_react35.useMemo)(
|
|
8332
8349
|
() => options.title ?? route.name,
|
|
8333
8350
|
[options.title, route.name]
|
|
@@ -8338,7 +8355,11 @@ function Header({
|
|
|
8338
8355
|
return raw.filter((el) => el.type !== "title");
|
|
8339
8356
|
}, [headerConfig]);
|
|
8340
8357
|
const hasCustomActions = elements.some((el) => el.type === "action");
|
|
8341
|
-
const
|
|
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
|
+
});
|
|
8342
8363
|
const bySlot = (0, import_react35.useMemo)(() => {
|
|
8343
8364
|
const left = [];
|
|
8344
8365
|
const center = [];
|
|
@@ -8461,7 +8482,7 @@ function Header({
|
|
|
8461
8482
|
}
|
|
8462
8483
|
) : null,
|
|
8463
8484
|
bySlot.left.map(renderElement),
|
|
8464
|
-
!
|
|
8485
|
+
!hasResolvableLogo ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(CityLogoFallback, {}) : null
|
|
8465
8486
|
] }),
|
|
8466
8487
|
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
|
|
8467
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 (
|
|
8377
|
-
|
|
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,
|
|
@@ -8398,14 +8412,17 @@ function Header({
|
|
|
8398
8412
|
route,
|
|
8399
8413
|
navigation,
|
|
8400
8414
|
overlay = false,
|
|
8401
|
-
headerConfig
|
|
8415
|
+
headerConfig,
|
|
8416
|
+
safeTop
|
|
8402
8417
|
}) {
|
|
8403
8418
|
const { theme } = useTheme();
|
|
8404
8419
|
const t = resolveTheme(theme);
|
|
8405
8420
|
const themedStyles = createThemedStyles14(theme);
|
|
8406
|
-
const
|
|
8421
|
+
const applyTopInset = safeTop ?? true;
|
|
8422
|
+
const topInset = useSafeAreaPadding(applyTopInset ? ["top"] : []);
|
|
8407
8423
|
const { hasUnread } = useAnnouncements();
|
|
8408
8424
|
const { push } = useAppNavigation();
|
|
8425
|
+
const { apiUrl } = useWasto();
|
|
8409
8426
|
const screenTitle = useMemo20(
|
|
8410
8427
|
() => options.title ?? route.name,
|
|
8411
8428
|
[options.title, route.name]
|
|
@@ -8416,7 +8433,11 @@ function Header({
|
|
|
8416
8433
|
return raw.filter((el) => el.type !== "title");
|
|
8417
8434
|
}, [headerConfig]);
|
|
8418
8435
|
const hasCustomActions = elements.some((el) => el.type === "action");
|
|
8419
|
-
const
|
|
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
|
+
});
|
|
8420
8441
|
const bySlot = useMemo20(() => {
|
|
8421
8442
|
const left = [];
|
|
8422
8443
|
const center = [];
|
|
@@ -8539,7 +8560,7 @@ function Header({
|
|
|
8539
8560
|
}
|
|
8540
8561
|
) : null,
|
|
8541
8562
|
bySlot.left.map(renderElement),
|
|
8542
|
-
!
|
|
8563
|
+
!hasResolvableLogo ? /* @__PURE__ */ jsx41(CityLogoFallback, {}) : null
|
|
8543
8564
|
] }),
|
|
8544
8565
|
/* @__PURE__ */ jsx41(
|
|
8545
8566
|
View29,
|
package/package.json
CHANGED
|
@@ -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 = {
|
|
@@ -86,19 +88,25 @@ export type HeaderProps = {
|
|
|
86
88
|
canGoBack: () => boolean;
|
|
87
89
|
goBack: () => void;
|
|
88
90
|
};
|
|
89
|
-
/** Flotte au-dessus du contenu (ex. carte) : fond transparent. */
|
|
91
|
+
/** Flotte au-dessus du contenu (ex. carte) : fond transparent + safe-area top. */
|
|
90
92
|
readonly overlay?: boolean;
|
|
91
93
|
/**
|
|
92
94
|
* Config layout (`header.elements`) — logo / actions.
|
|
93
95
|
* Si fournie (même vide), le fallback titre d’écran ne s’applique pas.
|
|
94
96
|
*/
|
|
95
97
|
readonly headerConfig?: AppHeaderConfig | null;
|
|
98
|
+
/**
|
|
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à.
|
|
101
|
+
*/
|
|
102
|
+
readonly safeTop?: boolean;
|
|
96
103
|
};
|
|
97
104
|
|
|
98
105
|
function resolveLogoUri(
|
|
99
106
|
apiUrl: string,
|
|
100
107
|
el: AppHeaderLogoElement,
|
|
101
108
|
): string | null {
|
|
109
|
+
if (el.sourceType === "bundled") return null;
|
|
102
110
|
const url = (el.url || "").trim();
|
|
103
111
|
if (url) return url;
|
|
104
112
|
// Fallback média (export parfois laisse mediaId si rewrite manqué)
|
|
@@ -125,6 +133,16 @@ function HeaderLogo({
|
|
|
125
133
|
readonly element: AppHeaderLogoElement;
|
|
126
134
|
}): ReactNode {
|
|
127
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
|
+
}
|
|
128
146
|
const uri = resolveLogoUri(apiUrl, element);
|
|
129
147
|
if (!uri) return null;
|
|
130
148
|
return <HeaderLogoImage uri={uri} />;
|
|
@@ -138,8 +156,11 @@ function CityLogoFallback(): ReactNode {
|
|
|
138
156
|
? appData.city.logoMediaId
|
|
139
157
|
: null;
|
|
140
158
|
const uri = publicMediaUrl(apiUrl, logoMediaId);
|
|
141
|
-
if (
|
|
142
|
-
|
|
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;
|
|
143
164
|
}
|
|
144
165
|
|
|
145
166
|
function HeaderActionButton({
|
|
@@ -172,13 +193,17 @@ export function Header({
|
|
|
172
193
|
navigation,
|
|
173
194
|
overlay = false,
|
|
174
195
|
headerConfig,
|
|
196
|
+
safeTop,
|
|
175
197
|
}: HeaderProps): ReactNode {
|
|
176
198
|
const { theme } = useTheme();
|
|
177
199
|
const t = resolveTheme(theme);
|
|
178
200
|
const themedStyles = createThemedStyles(theme);
|
|
179
|
-
|
|
201
|
+
// Header custom = plein écran sous le notch → inset requis (Page ne le re-ajoute plus).
|
|
202
|
+
const applyTopInset = safeTop ?? true;
|
|
203
|
+
const topInset = useSafeAreaPadding(applyTopInset ? ["top"] : []);
|
|
180
204
|
const { hasUnread } = useAnnouncements();
|
|
181
205
|
const { push } = useAppNavigation();
|
|
206
|
+
const { apiUrl } = useWasto();
|
|
182
207
|
|
|
183
208
|
const screenTitle = useMemo(
|
|
184
209
|
() => options.title ?? route.name,
|
|
@@ -193,7 +218,12 @@ export function Header({
|
|
|
193
218
|
return raw.filter((el) => el.type !== "title");
|
|
194
219
|
}, [headerConfig]);
|
|
195
220
|
const hasCustomActions = elements.some((el) => el.type === "action");
|
|
196
|
-
|
|
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
|
+
});
|
|
197
227
|
|
|
198
228
|
const bySlot = useMemo(() => {
|
|
199
229
|
const left: AppHeaderElement[] = [];
|
|
@@ -320,7 +350,7 @@ export function Header({
|
|
|
320
350
|
</HeaderActionButton>
|
|
321
351
|
) : null}
|
|
322
352
|
{bySlot.left.map(renderElement)}
|
|
323
|
-
{!
|
|
353
|
+
{!hasResolvableLogo ? <CityLogoFallback /> : null}
|
|
324
354
|
</View>
|
|
325
355
|
<View
|
|
326
356
|
style={styles.slotCenter}
|