cloudcommerce 2.8.7 → 2.8.8
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/CHANGELOG.md +9 -0
- package/ecomplus-stores/barradoce/functions/many/package.json +3 -3
- package/ecomplus-stores/barradoce/functions/ssr/package.json +6 -6
- package/ecomplus-stores/barradoce/functions/with-apps/package.json +3 -3
- package/ecomplus-stores/barradoce/package.json +2 -2
- package/package.json +2 -2
- package/packages/api/package.json +1 -1
- package/packages/apps/affiliate-program/package.json +1 -1
- package/packages/apps/correios/package.json +1 -1
- package/packages/apps/custom-payment/package.json +1 -1
- package/packages/apps/custom-shipping/package.json +1 -1
- package/packages/apps/datafrete/package.json +1 -1
- package/packages/apps/discounts/package.json +1 -1
- package/packages/apps/emails/package.json +1 -1
- package/packages/apps/fb-conversions/package.json +1 -1
- package/packages/apps/flash-courier/package.json +1 -1
- package/packages/apps/frenet/package.json +1 -1
- package/packages/apps/galaxpay/package.json +1 -1
- package/packages/apps/google-analytics/package.json +1 -1
- package/packages/apps/jadlog/package.json +1 -1
- package/packages/apps/loyalty-points/package.json +1 -1
- package/packages/apps/mandae/package.json +1 -1
- package/packages/apps/melhor-envio/package.json +1 -1
- package/packages/apps/mercadopago/package.json +1 -1
- package/packages/apps/pagarme/package.json +1 -1
- package/packages/apps/pagarme-v5/package.json +1 -1
- package/packages/apps/paghiper/package.json +1 -1
- package/packages/apps/pix/package.json +1 -1
- package/packages/apps/tiny-erp/package.json +1 -1
- package/packages/apps/webhooks/package.json +1 -1
- package/packages/cli/lib/cli.js +3 -3
- package/packages/cli/package.json +1 -1
- package/packages/cli/src/cli.ts +3 -3
- package/packages/config/package.json +1 -1
- package/packages/emails/package.json +1 -1
- package/packages/eslint/package.json +1 -1
- package/packages/events/package.json +1 -1
- package/packages/feeds/package.json +1 -1
- package/packages/firebase/package.json +1 -1
- package/packages/i18n/package.json +1 -1
- package/packages/modules/package.json +1 -1
- package/packages/passport/package.json +1 -1
- package/packages/ssr/package.json +1 -1
- package/packages/storefront/config/astro/client-sf-directive.mjs +0 -3
- package/packages/storefront/package.json +1 -1
- package/packages/storefront/src/lib/components/globals/ALink.vue +6 -6
- package/packages/storefront/src/lib/composables/use-sku-selector.ts +1 -1
- package/packages/storefront/src/lib/layouts/Base.astro +5 -0
- package/packages/storefront/src/lib/layouts/BaseHead.astro +1 -6
- package/packages/storefront/src/lib/state/use-analytics.ts +0 -1
- package/packages/test-base/package.json +1 -1
- package/packages/types/package.json +1 -1
- package/packages/storefront/src/lib/components/ViewTransitions.astro +0 -426
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
### [2.8.8](https://github.com/ecomplus/cloud-commerce/compare/v2.8.7...v2.8.8) (2024-03-13)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
* **cli:** Handle `start` (npm start) with ssr dev server ([0093426](https://github.com/ecomplus/cloud-commerce/commit/009342688ee2e753abd943c3fd07b161e08ccf3e))
|
|
11
|
+
* **storefront:** Move script importing `astro:prefetch` to body, within `base-body-scripts` slot ([141cca4](https://github.com/ecomplus/cloud-commerce/commit/141cca42733a7a9b13b83fb0556d39a1e953dd8d))
|
|
12
|
+
* **storefront:** Properly listen grids data load on SKU selector composable ([5c0ad4f](https://github.com/ecomplus/cloud-commerce/commit/5c0ad4f6ef1b60bb5bea0834a23c2f92dd66597c))
|
|
13
|
+
|
|
5
14
|
### [2.8.7](https://github.com/ecomplus/cloud-commerce/compare/v2.8.6...v2.8.7) (2024-03-12)
|
|
6
15
|
|
|
7
16
|
### [2.8.6](https://github.com/ecomplus/cloud-commerce/compare/v2.8.5...v2.8.6) (2024-03-12)
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
},
|
|
16
16
|
"main": "index.js",
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@cloudcommerce/feeds": "^2.7
|
|
19
|
-
"@cloudcommerce/firebase": "^2.7
|
|
20
|
-
"@cloudcommerce/passport": "^2.7
|
|
18
|
+
"@cloudcommerce/feeds": "^2.8.7",
|
|
19
|
+
"@cloudcommerce/firebase": "^2.8.7",
|
|
20
|
+
"@cloudcommerce/passport": "^2.8.7"
|
|
21
21
|
}
|
|
22
22
|
}
|
|
@@ -19,16 +19,16 @@
|
|
|
19
19
|
},
|
|
20
20
|
"main": "index.js",
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@cloudcommerce/api": "^2.7
|
|
23
|
-
"@cloudcommerce/firebase": "^2.7
|
|
24
|
-
"@cloudcommerce/ssr": "^2.7
|
|
22
|
+
"@cloudcommerce/api": "^2.8.7",
|
|
23
|
+
"@cloudcommerce/firebase": "^2.8.7",
|
|
24
|
+
"@cloudcommerce/ssr": "^2.8.7",
|
|
25
25
|
"@headlessui/vue": "^1.7.18",
|
|
26
26
|
"micromark": "^4.0.0"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
|
-
"@cloudcommerce/i18n": "^2.7
|
|
30
|
-
"@cloudcommerce/storefront": "^2.7
|
|
31
|
-
"@cloudcommerce/types": "^2.7
|
|
29
|
+
"@cloudcommerce/i18n": "^2.8.7",
|
|
30
|
+
"@cloudcommerce/storefront": "^2.8.7",
|
|
31
|
+
"@cloudcommerce/types": "^2.8.7",
|
|
32
32
|
"@iconify-json/mingcute": "^1.1.16",
|
|
33
33
|
"photoswipe": "^5.4.3"
|
|
34
34
|
}
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
},
|
|
16
16
|
"main": "index.js",
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@cloudcommerce/events": "^2.7
|
|
19
|
-
"@cloudcommerce/firebase": "^2.7
|
|
20
|
-
"@cloudcommerce/modules": "^2.7
|
|
18
|
+
"@cloudcommerce/events": "^2.8.7",
|
|
19
|
+
"@cloudcommerce/firebase": "^2.8.7",
|
|
20
|
+
"@cloudcommerce/modules": "^2.8.7"
|
|
21
21
|
}
|
|
22
22
|
}
|
|
@@ -26,10 +26,10 @@
|
|
|
26
26
|
"url": "https://github.com/ecomplus/cloud-commerce/issues"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@cloudcommerce/cli": "^2.7
|
|
29
|
+
"@cloudcommerce/cli": "^2.8.7"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
|
-
"@cloudcommerce/eslint": "^2.7
|
|
32
|
+
"@cloudcommerce/eslint": "^2.8.7",
|
|
33
33
|
"husky": "^9.0.10",
|
|
34
34
|
"lint-staged": "^15.2.2"
|
|
35
35
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cloudcommerce",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "2.8.
|
|
4
|
+
"version": "2.8.8",
|
|
5
5
|
"description": "Open fair-code headless commerce platform: API-first, microservices based, event driven and cloud native",
|
|
6
6
|
"main": "packages/api/lib/index.js",
|
|
7
7
|
"author": "E-Com Club Softwares para E-commerce <ti@e-com.club>",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"vite": "^5.1.5",
|
|
37
37
|
"vitest": "^1.3.1",
|
|
38
38
|
"zx": "^7.2.3",
|
|
39
|
-
"@cloudcommerce/eslint": "2.8.
|
|
39
|
+
"@cloudcommerce/eslint": "2.8.8"
|
|
40
40
|
},
|
|
41
41
|
"scripts": {
|
|
42
42
|
"fix-install": "bash scripts/pre-install.sh && pnpm i",
|
package/packages/cli/lib/cli.js
CHANGED
|
@@ -80,7 +80,7 @@ export default async () => {
|
|
|
80
80
|
}
|
|
81
81
|
return $`firebase --project=${projectId} ${cmd} ${options}`;
|
|
82
82
|
};
|
|
83
|
-
if (argv._.includes('serve')) {
|
|
83
|
+
if (argv._.includes('serve') || argv._.includes('preview')) {
|
|
84
84
|
if (argv.build !== false) {
|
|
85
85
|
await build(argv.codebase);
|
|
86
86
|
}
|
|
@@ -95,7 +95,7 @@ ${chalk.bold('npx kill-port 4000 9099 5001 8080 5000 8085 9199 4400 4500')}
|
|
|
95
95
|
throw err;
|
|
96
96
|
});
|
|
97
97
|
}
|
|
98
|
-
if (argv._.find((cmd) => /^(\w+:)?
|
|
98
|
+
if (argv._.find((cmd) => /^(\w+:)?shell$/.test(cmd))) {
|
|
99
99
|
return $firebase('functions:shell');
|
|
100
100
|
}
|
|
101
101
|
if (argv._.find((cmd) => /^(\w+:)?logs?$/.test(cmd))) {
|
|
@@ -175,7 +175,7 @@ Finish by saving the following secrets to your GitHub repository:
|
|
|
175
175
|
if (argv._.includes('prepare')) {
|
|
176
176
|
return prepareCodebases();
|
|
177
177
|
}
|
|
178
|
-
if (argv._.includes('dev') || !argv._.length) {
|
|
178
|
+
if (argv._.includes('dev') || argv._.includes('start') || !argv._.length) {
|
|
179
179
|
await prepareCodebases(true);
|
|
180
180
|
const prefix = joinPath(pwd, 'functions/ssr');
|
|
181
181
|
// https://docs.astro.build/en/reference/cli-reference/#astro-dev
|
package/packages/cli/src/cli.ts
CHANGED
|
@@ -103,7 +103,7 @@ export default async () => {
|
|
|
103
103
|
return $`firebase --project=${projectId} ${cmd} ${options}`;
|
|
104
104
|
};
|
|
105
105
|
|
|
106
|
-
if (argv._.includes('serve')) {
|
|
106
|
+
if (argv._.includes('serve') || argv._.includes('preview')) {
|
|
107
107
|
if (argv.build !== false) {
|
|
108
108
|
await build(argv.codebase);
|
|
109
109
|
}
|
|
@@ -119,7 +119,7 @@ ${chalk.bold('npx kill-port 4000 9099 5001 8080 5000 8085 9199 4400 4500')}
|
|
|
119
119
|
});
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
-
if (argv._.find((cmd) => /^(\w+:)?
|
|
122
|
+
if (argv._.find((cmd) => /^(\w+:)?shell$/.test(cmd))) {
|
|
123
123
|
return $firebase('functions:shell');
|
|
124
124
|
}
|
|
125
125
|
if (argv._.find((cmd) => /^(\w+:)?logs?$/.test(cmd))) {
|
|
@@ -216,7 +216,7 @@ Finish by saving the following secrets to your GitHub repository:
|
|
|
216
216
|
return prepareCodebases();
|
|
217
217
|
}
|
|
218
218
|
|
|
219
|
-
if (argv._.includes('dev') || !argv._.length) {
|
|
219
|
+
if (argv._.includes('dev') || argv._.includes('start') || !argv._.length) {
|
|
220
220
|
await prepareCodebases(true);
|
|
221
221
|
const prefix = joinPath(pwd, 'functions/ssr');
|
|
222
222
|
// https://docs.astro.build/en/reference/cli-reference/#astro-dev
|
|
@@ -88,9 +88,6 @@ export default (load, opts, el) => {
|
|
|
88
88
|
const id = window.$storefront?.apiContext?.doc._id || null;
|
|
89
89
|
if (window._firstLoadContextId === id && window._emitedContextId === id) {
|
|
90
90
|
next();
|
|
91
|
-
document.addEventListener('astro:beforeload', () => {
|
|
92
|
-
delete window._firstLoadContextId;
|
|
93
|
-
}, { once: true });
|
|
94
91
|
return;
|
|
95
92
|
}
|
|
96
93
|
window.addEventListener('storefront:apiContext', next, { once: true });
|
|
@@ -42,16 +42,16 @@ if (prefetchHref.value) {
|
|
|
42
42
|
const isOnHover = prefetch === 'hover';
|
|
43
43
|
if (isMobile && isOnHover) return;
|
|
44
44
|
const isOnVisible = prefetch === 'visible';
|
|
45
|
-
const
|
|
45
|
+
const useElementEv = isOnVisible
|
|
46
46
|
? useElementVisibility
|
|
47
47
|
: isOnHover && useElementHover;
|
|
48
|
-
if (!
|
|
49
|
-
const
|
|
50
|
-
const unwatch = watch(
|
|
51
|
-
if (!
|
|
48
|
+
if (!useElementEv) return;
|
|
49
|
+
const isActive = useElementEv(link.value);
|
|
50
|
+
const unwatch = watch(isActive, (_isActive) => {
|
|
51
|
+
if (!_isActive || !window.$prefetch) return;
|
|
52
52
|
unwatch();
|
|
53
53
|
setTimeout(() => {
|
|
54
|
-
if (isOnVisible && !
|
|
54
|
+
if (isOnVisible && !isActive.value) return;
|
|
55
55
|
requestIdleCallback(() => {
|
|
56
56
|
if (!prefetchHref.value) return;
|
|
57
57
|
window.$prefetch!(prefetchHref.value);
|
|
@@ -27,7 +27,7 @@ const useSkuSelector = (props: Props) => {
|
|
|
27
27
|
|| [],
|
|
28
28
|
);
|
|
29
29
|
if (!grids.length && !import.meta.env.SSR) {
|
|
30
|
-
window.addEventListener('storefront:data:
|
|
30
|
+
window.addEventListener('storefront:data:grids', () => {
|
|
31
31
|
globalThis.$storefront.data.grids?.forEach((grid) => grids.push(grid));
|
|
32
32
|
}, { once: true });
|
|
33
33
|
}
|
|
@@ -21,6 +21,11 @@ const { customCode } = await getContent('layout');
|
|
|
21
21
|
<slot name="base-body-scripts">
|
|
22
22
|
<script src="../scripts/session-utm"></script>
|
|
23
23
|
<script src="../scripts/push-analytics-events"></script>
|
|
24
|
+
<script>
|
|
25
|
+
/* eslint-disable */
|
|
26
|
+
import { prefetch } from 'astro:prefetch';
|
|
27
|
+
window.$prefetch = prefetch;
|
|
28
|
+
</script>
|
|
24
29
|
</slot>
|
|
25
30
|
<slot name="before-body-end" />
|
|
26
31
|
</BaseBody>
|
|
@@ -206,12 +206,7 @@ const generator = `e-com.plus @cloudcommerce/storefront, ${Astro.generator}`;
|
|
|
206
206
|
&& <link rel="manifest" href="/manifest.webmanifest" />}
|
|
207
207
|
</>}
|
|
208
208
|
|
|
209
|
-
<script is:inline set:html={inlineClientJS}
|
|
209
|
+
<script is:inline set:html={inlineClientJS} />
|
|
210
210
|
<script is:inline type="application/ld+json" set:html={inlineJSONLd} />
|
|
211
211
|
|
|
212
|
-
<script>
|
|
213
|
-
/* eslint-disable */
|
|
214
|
-
import { prefetch } from 'astro:prefetch';
|
|
215
|
-
window.$prefetch = prefetch;
|
|
216
|
-
</script>
|
|
217
212
|
{contextInlineClientJS && <script is:inline set:html={contextInlineClientJS} />}
|
|
@@ -1,426 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type Fallback = 'none' | 'animate' | 'swap';
|
|
3
|
-
|
|
4
|
-
export interface Props {
|
|
5
|
-
fallback?: Fallback;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
const { fallback = 'animate' } = Astro.props as Props;
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
<meta name="astro-view-transitions-enabled" content="true" />
|
|
12
|
-
<meta name="astro-view-transitions-fallback" content={fallback} />
|
|
13
|
-
<script>
|
|
14
|
-
/* eslint-disable */
|
|
15
|
-
type Fallback = 'none' | 'animate' | 'swap';
|
|
16
|
-
type Direction = 'forward' | 'back';
|
|
17
|
-
type State = {
|
|
18
|
-
index: number;
|
|
19
|
-
scrollY: number;
|
|
20
|
-
};
|
|
21
|
-
type Events = 'astro:load' | 'astro:beforeload';
|
|
22
|
-
|
|
23
|
-
const persistState = (state: State) => history.replaceState(state, '');
|
|
24
|
-
// @ts-ignore
|
|
25
|
-
const supportsViewTransitions = !!document.startViewTransition;
|
|
26
|
-
const transitionEnabledOnThisPage = () =>
|
|
27
|
-
!!document.querySelector('[name="astro-view-transitions-enabled"]');
|
|
28
|
-
const triggerEvent = (name: Events) => document.dispatchEvent(new Event(name));
|
|
29
|
-
const onload = () => triggerEvent('astro:load');
|
|
30
|
-
const PERSIST_ATTR = 'data-astro-transition-persist';
|
|
31
|
-
|
|
32
|
-
// The History API does not tell you if navigation is forward or back, so
|
|
33
|
-
// you can figure it using an index. On pushState the index is incremented so you
|
|
34
|
-
// can use that to determine popstate if going forward or back.
|
|
35
|
-
let currentHistoryIndex = history.state?.index || 0;
|
|
36
|
-
if (!history.state && transitionEnabledOnThisPage()) {
|
|
37
|
-
persistState({ index: currentHistoryIndex, scrollY: 0 });
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const throttle = (cb: (...args: any[]) => any, delay: number) => {
|
|
41
|
-
let wait = false;
|
|
42
|
-
// During the waiting time additional events are lost.
|
|
43
|
-
// So repeat the callback at the end if we have swallowed events.
|
|
44
|
-
let onceMore = false;
|
|
45
|
-
return (...args: any[]) => {
|
|
46
|
-
if (wait) {
|
|
47
|
-
onceMore = true;
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
cb(...args);
|
|
51
|
-
wait = true;
|
|
52
|
-
setTimeout(() => {
|
|
53
|
-
if (onceMore) {
|
|
54
|
-
onceMore = false;
|
|
55
|
-
cb(...args);
|
|
56
|
-
}
|
|
57
|
-
wait = false;
|
|
58
|
-
}, delay);
|
|
59
|
-
};
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
async function getHTML(href: string) {
|
|
63
|
-
const res = await fetch(href);
|
|
64
|
-
const html = await res.text();
|
|
65
|
-
return { ok: res.ok, html };
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
function getFallback(): Fallback {
|
|
69
|
-
const el = document.querySelector('[name="astro-view-transitions-fallback"]');
|
|
70
|
-
if (el) {
|
|
71
|
-
return el.getAttribute('content') as Fallback;
|
|
72
|
-
}
|
|
73
|
-
return 'animate';
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function markScriptsExec() {
|
|
77
|
-
for (const script of document.scripts) {
|
|
78
|
-
script.dataset.astroExec = '';
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
function runScripts() {
|
|
83
|
-
let wait = Promise.resolve();
|
|
84
|
-
for (const script of Array.from(document.scripts)) {
|
|
85
|
-
if (script.dataset.astroExec === '') continue;
|
|
86
|
-
const s = document.createElement('script');
|
|
87
|
-
s.innerHTML = script.innerHTML;
|
|
88
|
-
for (const attr of script.attributes) {
|
|
89
|
-
if (attr.name === 'src') {
|
|
90
|
-
const p = new Promise((r) => {
|
|
91
|
-
s.onload = r;
|
|
92
|
-
});
|
|
93
|
-
wait = wait.then(() => p as any);
|
|
94
|
-
}
|
|
95
|
-
s.setAttribute(attr.name, attr.value);
|
|
96
|
-
}
|
|
97
|
-
s.dataset.astroExec = '';
|
|
98
|
-
script.replaceWith(s);
|
|
99
|
-
}
|
|
100
|
-
return wait;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
const parser = new DOMParser();
|
|
104
|
-
|
|
105
|
-
async function updateDOM(html: string, state?: State, fallback?: Fallback) {
|
|
106
|
-
const doc = parser.parseFromString(html, 'text/html');
|
|
107
|
-
|
|
108
|
-
// Check for a head element that should persist, either because it has the data
|
|
109
|
-
// attribute or is a link el.
|
|
110
|
-
const persistedHeadElement = (el: Element): Element | null => {
|
|
111
|
-
const id = el.getAttribute(PERSIST_ATTR);
|
|
112
|
-
const newEl = id && doc.head.querySelector(`[${PERSIST_ATTR}="${id}"]`);
|
|
113
|
-
if (newEl) {
|
|
114
|
-
return newEl;
|
|
115
|
-
}
|
|
116
|
-
if (el.matches('link[rel=stylesheet]')) {
|
|
117
|
-
const href = el.getAttribute('href');
|
|
118
|
-
return doc.head.querySelector(`link[rel=stylesheet][href="${href}"]`);
|
|
119
|
-
}
|
|
120
|
-
if (el.tagName === 'SCRIPT') {
|
|
121
|
-
let s1 = el as HTMLScriptElement;
|
|
122
|
-
for (const s2 of doc.scripts) {
|
|
123
|
-
if (
|
|
124
|
-
// Inline
|
|
125
|
-
(s1.textContent && s1.textContent === s2.textContent) ||
|
|
126
|
-
// External
|
|
127
|
-
(s1.type === s2.type && s1.src && s1.src === s2.src)
|
|
128
|
-
) {
|
|
129
|
-
return s2;
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
return null;
|
|
134
|
-
};
|
|
135
|
-
|
|
136
|
-
const swap = () => {
|
|
137
|
-
// noscript tags inside head element are not honored on swap (#7969).
|
|
138
|
-
// Remove them before swapping.
|
|
139
|
-
doc.querySelectorAll('head noscript').forEach((el) => el.remove());
|
|
140
|
-
|
|
141
|
-
// swap attributes of the html element
|
|
142
|
-
// - delete all attributes from the current document
|
|
143
|
-
// - insert all attributes from doc
|
|
144
|
-
// - reinsert all original attributes that are named 'data-astro-*'
|
|
145
|
-
const html = document.documentElement;
|
|
146
|
-
const astro = [...html.attributes].filter(
|
|
147
|
-
({ name }) => (html.removeAttribute(name), name.startsWith('data-astro-'))
|
|
148
|
-
);
|
|
149
|
-
[...doc.documentElement.attributes, ...astro].forEach(({ name, value }) =>
|
|
150
|
-
html.setAttribute(name, value)
|
|
151
|
-
);
|
|
152
|
-
|
|
153
|
-
// Swap head
|
|
154
|
-
for (const el of Array.from(document.head.children)) {
|
|
155
|
-
const newEl = persistedHeadElement(el);
|
|
156
|
-
// If the element exists in the document already, remove it
|
|
157
|
-
// from the new document and leave the current node alone
|
|
158
|
-
if (newEl) {
|
|
159
|
-
newEl.remove();
|
|
160
|
-
} else {
|
|
161
|
-
// Otherwise remove the element in the head. It doesn't exist in the new page.
|
|
162
|
-
el.remove();
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
// Everything left in the new head is new, append it all.
|
|
166
|
-
document.head.append(...doc.head.children);
|
|
167
|
-
|
|
168
|
-
// Move over persist stuff in the body
|
|
169
|
-
const oldBody = document.body;
|
|
170
|
-
document.body.replaceWith(doc.body);
|
|
171
|
-
for (const el of oldBody.querySelectorAll(`[${PERSIST_ATTR}]`)) {
|
|
172
|
-
const id = el.getAttribute(PERSIST_ATTR);
|
|
173
|
-
const newEl = document.querySelector(`[${PERSIST_ATTR}="${id}"]`);
|
|
174
|
-
if (newEl) {
|
|
175
|
-
// The element exists in the new page, replace it with the element
|
|
176
|
-
// from the old page so that state is preserved.
|
|
177
|
-
newEl.replaceWith(el);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
// Simulate scroll behavior of Safari and
|
|
182
|
-
// Chromium based browsers (Chrome, Edge, Opera, ...)
|
|
183
|
-
// @ts-ignore
|
|
184
|
-
scrollTo({ left: 0, top: 0, behavior: 'instant' });
|
|
185
|
-
|
|
186
|
-
if (state?.scrollY === 0 && location.hash) {
|
|
187
|
-
const id = decodeURIComponent(location.hash.slice(1));
|
|
188
|
-
const elem = document.getElementById(id);
|
|
189
|
-
// prefer scrollIntoView() over scrollTo() because it takes scroll-padding into account
|
|
190
|
-
if (elem) {
|
|
191
|
-
state.scrollY = elem.offsetTop;
|
|
192
|
-
persistState(state); // first guess, later updated by scroll handler
|
|
193
|
-
elem.scrollIntoView(); // for Firefox, this should better be {behavior: 'instant'}
|
|
194
|
-
}
|
|
195
|
-
} else if (state && state.scrollY !== 0) {
|
|
196
|
-
scrollTo(0, state.scrollY); // usings default scrollBehavior
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
triggerEvent('astro:beforeload');
|
|
200
|
-
};
|
|
201
|
-
|
|
202
|
-
// Wait on links to finish, to prevent FOUC
|
|
203
|
-
const links: Promise<any>[] = [];
|
|
204
|
-
for (const el of doc.querySelectorAll('head link[rel=stylesheet]')) {
|
|
205
|
-
// Do not preload links that are already on the page.
|
|
206
|
-
if (
|
|
207
|
-
!document.querySelector(
|
|
208
|
-
`[${PERSIST_ATTR}="${el.getAttribute(PERSIST_ATTR)}"], link[rel=stylesheet]`
|
|
209
|
-
)
|
|
210
|
-
) {
|
|
211
|
-
const c = document.createElement('link');
|
|
212
|
-
c.setAttribute('rel', 'preload');
|
|
213
|
-
c.setAttribute('as', 'style');
|
|
214
|
-
c.setAttribute('href', el.getAttribute('href')!);
|
|
215
|
-
links.push(
|
|
216
|
-
new Promise<any>((resolve) => {
|
|
217
|
-
['load', 'error'].forEach((evName) => c.addEventListener(evName, resolve));
|
|
218
|
-
document.head.append(c);
|
|
219
|
-
})
|
|
220
|
-
);
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
links.length && (await Promise.all(links));
|
|
224
|
-
|
|
225
|
-
if (fallback === 'animate') {
|
|
226
|
-
let isAnimating = false;
|
|
227
|
-
addEventListener('animationstart', () => (isAnimating = true), { once: true });
|
|
228
|
-
|
|
229
|
-
// Trigger the animations
|
|
230
|
-
document.documentElement.dataset.astroTransitionFallback = 'old';
|
|
231
|
-
await new Promise((resolve) => {
|
|
232
|
-
const fallbackSwap = () => {
|
|
233
|
-
removeEventListener('animationend', fallbackSwap);
|
|
234
|
-
clearTimeout(timeout);
|
|
235
|
-
swap();
|
|
236
|
-
resolve(true);
|
|
237
|
-
document.documentElement.dataset.astroTransitionFallback = 'new';
|
|
238
|
-
};
|
|
239
|
-
// If there are any animations, want for the animationend event.
|
|
240
|
-
addEventListener('animationend', fallbackSwap, { once: true });
|
|
241
|
-
// If there are no animations, go ahead and swap on next tick
|
|
242
|
-
// This is necessary because we do not know if there are animations.
|
|
243
|
-
// The setTimeout is a fallback in case there are none.
|
|
244
|
-
let timeout = setTimeout(() => !isAnimating && fallbackSwap());
|
|
245
|
-
});
|
|
246
|
-
} else {
|
|
247
|
-
swap();
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
async function navigate(dir: Direction, href: string, state?: State) {
|
|
252
|
-
let finished: Promise<void>;
|
|
253
|
-
const { html, ok } = await getHTML(href);
|
|
254
|
-
// If there is a problem fetching the new page, just do an MPA navigation to it.
|
|
255
|
-
if (!ok) {
|
|
256
|
-
location.href = href;
|
|
257
|
-
return;
|
|
258
|
-
}
|
|
259
|
-
document.documentElement.dataset.astroTransition = dir;
|
|
260
|
-
if (supportsViewTransitions) {
|
|
261
|
-
// @ts-ignore
|
|
262
|
-
finished = document.startViewTransition(() => updateDOM(html, state)).finished;
|
|
263
|
-
} else {
|
|
264
|
-
finished = updateDOM(html, state, getFallback());
|
|
265
|
-
}
|
|
266
|
-
try {
|
|
267
|
-
await finished;
|
|
268
|
-
} finally {
|
|
269
|
-
// skip this for the moment as it tends to stop fallback animations
|
|
270
|
-
// document.documentElement.removeAttribute('data-astro-transition');
|
|
271
|
-
await runScripts();
|
|
272
|
-
markScriptsExec();
|
|
273
|
-
onload();
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
// Prefetching
|
|
278
|
-
function maybePrefetch(pathname: string) {
|
|
279
|
-
if (document.querySelector(`link[rel=prefetch][href="${pathname}"]`)) return;
|
|
280
|
-
// @ts-ignore
|
|
281
|
-
if (navigator.connection) {
|
|
282
|
-
// @ts-ignore
|
|
283
|
-
let conn = navigator.connection;
|
|
284
|
-
if (conn.saveData || /(2|3)g/.test(conn.effectiveType || '')) return;
|
|
285
|
-
}
|
|
286
|
-
let link = document.createElement('link');
|
|
287
|
-
link.setAttribute('rel', 'prefetch');
|
|
288
|
-
link.setAttribute('href', pathname);
|
|
289
|
-
document.head.append(link);
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
if (
|
|
293
|
-
(supportsViewTransitions || getFallback() !== 'none') &&
|
|
294
|
-
!location.pathname.startsWith('/app/') &&
|
|
295
|
-
!location.pathname.startsWith('/admin/')
|
|
296
|
-
) {
|
|
297
|
-
markScriptsExec();
|
|
298
|
-
|
|
299
|
-
document.addEventListener('click', (ev) => {
|
|
300
|
-
let link = ev.target;
|
|
301
|
-
if (link instanceof Element && link.tagName !== 'A') {
|
|
302
|
-
link = link.closest('a');
|
|
303
|
-
}
|
|
304
|
-
// This check verifies that the click is happening on an anchor
|
|
305
|
-
// that is going to another page within the same origin. Basically it determines
|
|
306
|
-
// same-origin navigation, but omits special key combos for new tabs, etc.
|
|
307
|
-
if (
|
|
308
|
-
!link ||
|
|
309
|
-
!(link instanceof HTMLAnchorElement) ||
|
|
310
|
-
link.dataset.astroReload !== undefined ||
|
|
311
|
-
link.hasAttribute('download') ||
|
|
312
|
-
!link.href ||
|
|
313
|
-
link.pathname.startsWith('/app/') || // "real" SPA routes
|
|
314
|
-
link.pathname.startsWith('/admin/') || // CMS route
|
|
315
|
-
(link.target && link.target !== '_self') ||
|
|
316
|
-
link.origin !== location.origin ||
|
|
317
|
-
ev.button !== 0 || // left clicks only
|
|
318
|
-
ev.metaKey || // new tab (mac)
|
|
319
|
-
ev.ctrlKey || // new tab (windows)
|
|
320
|
-
ev.altKey || // download
|
|
321
|
-
ev.shiftKey || // new window
|
|
322
|
-
ev.defaultPrevented ||
|
|
323
|
-
!transitionEnabledOnThisPage()
|
|
324
|
-
)
|
|
325
|
-
// No page transitions in these cases,
|
|
326
|
-
// Let the browser standard action handle this
|
|
327
|
-
return;
|
|
328
|
-
|
|
329
|
-
// We do not need to handle same page links because there are no page transitions
|
|
330
|
-
// Same page means same path and same query params (but different hash)
|
|
331
|
-
if (location.pathname === link.pathname && location.search === link.search) {
|
|
332
|
-
if (link.hash) {
|
|
333
|
-
// The browser default action will handle navigations with hash fragments
|
|
334
|
-
return;
|
|
335
|
-
} else {
|
|
336
|
-
// Special case: self link without hash
|
|
337
|
-
// If handed to the browser it will reload the page
|
|
338
|
-
// But we want to handle it like any other same page navigation
|
|
339
|
-
// So we scroll to the top of the page but do not start page transitions
|
|
340
|
-
ev.preventDefault();
|
|
341
|
-
persistState({ ...history.state, scrollY });
|
|
342
|
-
// @ts-ignore
|
|
343
|
-
scrollTo({ left: 0, top: 0, behavior: 'instant' });
|
|
344
|
-
if (location.hash) {
|
|
345
|
-
// last target was different
|
|
346
|
-
const newState: State = { index: ++currentHistoryIndex, scrollY: 0 };
|
|
347
|
-
history.pushState(newState, '', link.href);
|
|
348
|
-
}
|
|
349
|
-
return;
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
// these are the cases we will handle: same origin, different page
|
|
354
|
-
ev.preventDefault();
|
|
355
|
-
navigate('forward', link.href, { index: ++currentHistoryIndex, scrollY: 0 });
|
|
356
|
-
const newState: State = { index: currentHistoryIndex, scrollY };
|
|
357
|
-
persistState({ index: currentHistoryIndex - 1, scrollY });
|
|
358
|
-
history.pushState(newState, '', link.href);
|
|
359
|
-
});
|
|
360
|
-
|
|
361
|
-
addEventListener('popstate', (ev) => {
|
|
362
|
-
if (!transitionEnabledOnThisPage() && ev.state) {
|
|
363
|
-
// The current page doesn't haven't View Transitions,
|
|
364
|
-
// respect that with a full page reload
|
|
365
|
-
// -- but only for transition managed by us (ev.state is set)
|
|
366
|
-
location.reload();
|
|
367
|
-
return;
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
// History entries without state are created by the browser (e.g. for hash links)
|
|
371
|
-
// Our view transition entries always have state.
|
|
372
|
-
// Just ignore stateless entries.
|
|
373
|
-
// The browser will handle navigation fine without our help
|
|
374
|
-
if (ev.state === null) {
|
|
375
|
-
return;
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
const state: State | undefined = history.state;
|
|
379
|
-
const nextIndex = state?.index ?? currentHistoryIndex + 1;
|
|
380
|
-
const direction: Direction = nextIndex > currentHistoryIndex ? 'forward' : 'back';
|
|
381
|
-
navigate(direction, location.href, state);
|
|
382
|
-
currentHistoryIndex = nextIndex;
|
|
383
|
-
});
|
|
384
|
-
|
|
385
|
-
['mouseenter', 'touchstart', 'focus'].forEach((evName) => {
|
|
386
|
-
document.addEventListener(
|
|
387
|
-
evName,
|
|
388
|
-
(ev) => {
|
|
389
|
-
if (ev.target instanceof HTMLAnchorElement) {
|
|
390
|
-
let el = ev.target;
|
|
391
|
-
if (
|
|
392
|
-
el.origin === location.origin &&
|
|
393
|
-
el.pathname !== location.pathname &&
|
|
394
|
-
!el.pathname.startsWith('/app/') && // "real" SPA routes
|
|
395
|
-
!el.pathname.startsWith('/admin/') && // CMS route
|
|
396
|
-
el.dataset.astroReload === undefined &&
|
|
397
|
-
!el.hasAttribute('download') &&
|
|
398
|
-
/* <a role=button> commonly used as no-JS interaction fallback,
|
|
399
|
-
thus, on-click redirect may be prevented after component hydration.
|
|
400
|
-
Shouldn't prefetch. */
|
|
401
|
-
el.role !== 'button' &&
|
|
402
|
-
transitionEnabledOnThisPage()
|
|
403
|
-
) {
|
|
404
|
-
maybePrefetch(el.pathname);
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
},
|
|
408
|
-
{ passive: true, capture: true }
|
|
409
|
-
);
|
|
410
|
-
});
|
|
411
|
-
addEventListener('load', onload);
|
|
412
|
-
// There's not a good way to record scroll position before a back button.
|
|
413
|
-
// So the way we do it is by listening to scroll and just continuously recording it.
|
|
414
|
-
addEventListener(
|
|
415
|
-
'scroll',
|
|
416
|
-
throttle(() => {
|
|
417
|
-
// only updste history entries that are managed by us
|
|
418
|
-
// leave other entries alone and do not accidently add state.
|
|
419
|
-
if (history.state) {
|
|
420
|
-
persistState({ ...history.state, scrollY });
|
|
421
|
-
}
|
|
422
|
-
}, 300),
|
|
423
|
-
{ passive: true }
|
|
424
|
-
);
|
|
425
|
-
}
|
|
426
|
-
</script>
|