@webround/core 0.3.3 → 0.3.4
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/context/WrAppContext.js +2 -1
- package/dist/routing.d.ts +10 -0
- package/dist/routing.js +12 -0
- package/dist/scroll.d.ts +6 -0
- package/dist/scroll.js +31 -0
- package/dist/seo.d.ts +3 -0
- package/dist/seo.js +8 -2
- package/package.json +6 -1
|
@@ -2,6 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
// packages/core/src/context/WrAppContext.tsx
|
|
3
3
|
import { createContext, useContext, useState, useCallback, useEffect, useMemo, useSyncExternalStore, lazy, Suspense, } from 'react';
|
|
4
4
|
import { createBrowserRouter, RouterProvider, useLocation, useParams } from 'react-router-dom';
|
|
5
|
+
import { WrScroll } from '../scroll';
|
|
5
6
|
import { wrResolveRoutes, wrBuildRegistry, wrBuildLazyRegistry, wrBuildPageConfigMap, wrExpandRoutesForLangs, wrExtractLang, wrBuildLangPath, } from '../routing';
|
|
6
7
|
import { WrPageProvider } from './WrPageContext';
|
|
7
8
|
import { WrLayout } from './WrLayout';
|
|
@@ -47,7 +48,7 @@ function WrRouteElement({ route, pageConfigMap, lazyFallback: LazyFallback, Page
|
|
|
47
48
|
const Component = route.Component;
|
|
48
49
|
return _jsx(Component, {});
|
|
49
50
|
})();
|
|
50
|
-
return (
|
|
51
|
+
return (_jsxs(PageProvider, { config: config, pageName: pageName, children: [_jsx(WrScroll, {}), _jsxs(WrSharedContext.Provider, { value: shared, children: [_jsx(WrSeoHead, { site: seo, config: config, pathname: pathname, lang: lang, langs: langs }), _jsx(WrLayout, { Header: Header, Footer: Footer, showHeader: route.header, showFooter: route.footer, pageConfigMap: pageConfigMap, ScopeProvider: PageProvider, children: body })] })] }, pageName));
|
|
51
52
|
}
|
|
52
53
|
export function WrAppProvider({ routesFile, eagerModules, lazyModules, configModules, langs, initialLang = 'default', lazyFallback = WrDefaultPageFallback, onRouterReady, PageProvider = WrPageProvider, Header, Footer, seo, children, }) {
|
|
53
54
|
const router = useMemo(() => {
|
package/dist/routing.d.ts
CHANGED
|
@@ -115,6 +115,16 @@ export declare function wrExtractLang(pathname: string, langs: WrLangConfig): La
|
|
|
115
115
|
export declare function wrBuildLangPath(targetLang: LangCode, pathname: string, langs: WrLangConfig): string;
|
|
116
116
|
/** Where an address that leads to no page goes: the home page of the language it is in (`/en/nope` → `/en`, `/nope` → `/`). */
|
|
117
117
|
export declare function wrHomeOf(pathname: string, langs?: WrLangConfig): string;
|
|
118
|
+
export type WrScrollAction = 'anchor' | 'top' | 'none';
|
|
119
|
+
/**
|
|
120
|
+
* What the scroll does when the address changes (the one rule, used by `WrScroll`). A link to a place of a page (`#list`) goes to that place; a NEW page (another path) starts at the top;
|
|
121
|
+
* "back" and "forward" leave it to the browser, which puts the page where it was left; and the same page in another state (a change of the query: the filters or the page of a shop) keeps its place.
|
|
122
|
+
* `previous` is the path of the page before, `null` for the first one the visitor sees.
|
|
123
|
+
*/
|
|
124
|
+
export declare function wrScrollAction(previous: string | null, location: {
|
|
125
|
+
pathname: string;
|
|
126
|
+
hash: string;
|
|
127
|
+
}, navigationType: 'PUSH' | 'REPLACE' | 'POP'): WrScrollAction;
|
|
118
128
|
/** An address that leaves the site: it has a scheme (`https:`, `mailto:`, `tel:`) or starts with `//`. Anything else is the site's own and is a router `Link`, whatever `target` it was given. */
|
|
119
129
|
export declare const wrIsExternalHref: (href: string) => boolean;
|
|
120
130
|
export declare function wrLocalizeHref(href: string, lang: string): string;
|
package/dist/routing.js
CHANGED
|
@@ -178,6 +178,18 @@ export function wrBuildLangPath(targetLang, pathname, langs) {
|
|
|
178
178
|
export function wrHomeOf(pathname, langs) {
|
|
179
179
|
return langs ? wrBuildLangPath(wrExtractLang(pathname, langs), '/', langs) : '/';
|
|
180
180
|
}
|
|
181
|
+
/**
|
|
182
|
+
* What the scroll does when the address changes (the one rule, used by `WrScroll`). A link to a place of a page (`#list`) goes to that place; a NEW page (another path) starts at the top;
|
|
183
|
+
* "back" and "forward" leave it to the browser, which puts the page where it was left; and the same page in another state (a change of the query: the filters or the page of a shop) keeps its place.
|
|
184
|
+
* `previous` is the path of the page before, `null` for the first one the visitor sees.
|
|
185
|
+
*/
|
|
186
|
+
export function wrScrollAction(previous, location, navigationType) {
|
|
187
|
+
if (location.hash)
|
|
188
|
+
return 'anchor';
|
|
189
|
+
if (previous === null || previous === location.pathname)
|
|
190
|
+
return 'none';
|
|
191
|
+
return navigationType === 'POP' ? 'none' : 'top';
|
|
192
|
+
}
|
|
181
193
|
/** An address that leaves the site: it has a scheme (`https:`, `mailto:`, `tel:`) or starts with `//`. Anything else is the site's own and is a router `Link`, whatever `target` it was given. */
|
|
182
194
|
export const wrIsExternalHref = (href) => /^([a-z][a-z0-9+.-]*:|\/\/)/i.test(href);
|
|
183
195
|
export function wrLocalizeHref(href, lang) {
|
package/dist/scroll.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Puts the scroll where a visitor expects it when the address changes: at the top on a new page, at the place a link points to, and leaves it alone on the same page in another state
|
|
3
|
+
* (the rule is `wrScrollAction`). Renders nothing. One per page, inside the router; core and editor mount the same one.
|
|
4
|
+
*/
|
|
5
|
+
export declare function WrScroll(): null;
|
|
6
|
+
//# sourceMappingURL=scroll.d.ts.map
|
package/dist/scroll.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { useLayoutEffect } from 'react';
|
|
2
|
+
import { useLocation, useNavigationType } from 'react-router-dom';
|
|
3
|
+
import { wrScrollAction } from './routing';
|
|
4
|
+
// The path of the page before: kept here and not in the component, because the component is inside the page, which is made again for every page (its `key` is the page's name)
|
|
5
|
+
let previousPath = null;
|
|
6
|
+
/**
|
|
7
|
+
* Puts the scroll where a visitor expects it when the address changes: at the top on a new page, at the place a link points to, and leaves it alone on the same page in another state
|
|
8
|
+
* (the rule is `wrScrollAction`). Renders nothing. One per page, inside the router; core and editor mount the same one.
|
|
9
|
+
*/
|
|
10
|
+
export function WrScroll() {
|
|
11
|
+
const { pathname, hash } = useLocation();
|
|
12
|
+
const type = useNavigationType();
|
|
13
|
+
useLayoutEffect(() => {
|
|
14
|
+
const before = previousPath;
|
|
15
|
+
previousPath = pathname;
|
|
16
|
+
let action = wrScrollAction(before, { pathname, hash }, type);
|
|
17
|
+
if (action === 'anchor') {
|
|
18
|
+
const place = document.getElementById(decodeURIComponent(hash.slice(1)));
|
|
19
|
+
if (place) {
|
|
20
|
+
place.scrollIntoView();
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
// a place that is not there: the page is treated as if the link had no `#`
|
|
24
|
+
action = wrScrollAction(before, { pathname, hash: '' }, type);
|
|
25
|
+
}
|
|
26
|
+
if (action === 'top')
|
|
27
|
+
window.scrollTo(0, 0);
|
|
28
|
+
}, [pathname, hash, type]);
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=scroll.js.map
|
package/dist/seo.d.ts
CHANGED
|
@@ -74,6 +74,9 @@ export type WrSeoJsonLd = WrJsonLd[] | Record<string, WrJsonLd[]>;
|
|
|
74
74
|
export declare const WR_ROBOTS_FILE = "robots.txt";
|
|
75
75
|
export declare const WR_SITEMAP_INDEX_FILE = "sitemap-index.xml";
|
|
76
76
|
export declare const WR_SITEMAP_PAGES_FILE = "sitemap-pages.xml";
|
|
77
|
+
/** The sitemaps the shop's server writes every day (not the build): a site with the page of a product (or of a collection) always has its index point to the sitemap of them. */
|
|
78
|
+
export declare const WR_SITEMAP_PRODUCTS_FILE = "sitemap-products.xml";
|
|
79
|
+
export declare const WR_SITEMAP_COLLECTIONS_FILE = "sitemap-collections.xml";
|
|
77
80
|
/** A page's SEO data out of its JSON (an empty object when it says nothing). */
|
|
78
81
|
export declare function wrSeoPageOf(config: WrPageConfig | undefined): WrSeoPage;
|
|
79
82
|
/** The site's address without a trailing slash, or undefined when it is not an http(s) address. */
|
package/dist/seo.js
CHANGED
|
@@ -20,6 +20,10 @@ export function wrSearchConsoleCode(input) {
|
|
|
20
20
|
export const WR_ROBOTS_FILE = 'robots.txt';
|
|
21
21
|
export const WR_SITEMAP_INDEX_FILE = 'sitemap-index.xml';
|
|
22
22
|
export const WR_SITEMAP_PAGES_FILE = 'sitemap-pages.xml';
|
|
23
|
+
/** The sitemaps the shop's server writes every day (not the build): a site with the page of a product (or of a collection) always has its index point to the sitemap of them. */
|
|
24
|
+
export const WR_SITEMAP_PRODUCTS_FILE = 'sitemap-products.xml';
|
|
25
|
+
export const WR_SITEMAP_COLLECTIONS_FILE = 'sitemap-collections.xml';
|
|
26
|
+
const WR_SHOP_SITEMAPS = { 'product/[slug]': WR_SITEMAP_PRODUCTS_FILE, 'shop/[slug]': WR_SITEMAP_COLLECTIONS_FILE };
|
|
23
27
|
/** A page's SEO data out of its JSON (an empty object when it says nothing). */
|
|
24
28
|
export function wrSeoPageOf(config) {
|
|
25
29
|
const raw = config?.[WR_SEO_KEY];
|
|
@@ -211,10 +215,12 @@ export function wrSeoFiles(input) {
|
|
|
211
215
|
if (!siteUrl)
|
|
212
216
|
return null;
|
|
213
217
|
const entries = wrSeoEntries(input);
|
|
214
|
-
|
|
218
|
+
// The shop's sitemaps are cited whether the files exist yet or not: the server writes them daily and the index must already say where they are
|
|
219
|
+
const own = [WR_SITEMAP_PAGES_FILE, ...Object.entries(WR_SHOP_SITEMAPS).filter(([route]) => route in input.routes).map(([, file]) => file)];
|
|
220
|
+
const extra = (input.site?.extraSitemaps ?? []).filter(name => typeof name === 'string' && name.trim() && !own.includes(name));
|
|
215
221
|
return {
|
|
216
222
|
[WR_ROBOTS_FILE]: wrRobotsTxt(siteUrl),
|
|
217
|
-
[WR_SITEMAP_INDEX_FILE]: wrSitemapIndexXml(siteUrl, [
|
|
223
|
+
[WR_SITEMAP_INDEX_FILE]: wrSitemapIndexXml(siteUrl, [...own, ...extra]),
|
|
218
224
|
[WR_SITEMAP_PAGES_FILE]: wrSitemapPagesXml(entries, input.langs),
|
|
219
225
|
};
|
|
220
226
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webround/core",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -61,6 +61,11 @@
|
|
|
61
61
|
"types": "./dist/seo-react.d.ts",
|
|
62
62
|
"development": "./src/seo-react.tsx"
|
|
63
63
|
},
|
|
64
|
+
"./scroll": {
|
|
65
|
+
"import": "./dist/scroll.js",
|
|
66
|
+
"types": "./dist/scroll.d.ts",
|
|
67
|
+
"development": "./src/scroll.tsx"
|
|
68
|
+
},
|
|
64
69
|
"./not-found": {
|
|
65
70
|
"import": "./dist/not-found.js",
|
|
66
71
|
"types": "./dist/not-found.d.ts",
|