@brillout/docpress 0.10.1 → 0.10.3
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/Layout.tsx +1 -1
- package/MenuModal/NavigationWithColumnLayout.css +0 -1
- package/MenuModal/NavigationWithColumnLayout.tsx +38 -12
- package/MenuModal/toggleMenuModal.ts +37 -16
- package/MenuModal.tsx +53 -41
- package/NavItemComponent.css +1 -1
- package/package.json +2 -10
- package/renderer/getHydrationPromise.ts +31 -0
- package/renderer/onRenderClient.tsx +11 -14
- package/utils/css.ts +1 -1
- package/utils/genPromise.ts +5 -0
package/Layout.tsx
CHANGED
|
@@ -26,9 +26,14 @@ function NavigationWithColumnLayout(props: { navItems: NavItem[] }) {
|
|
|
26
26
|
return (
|
|
27
27
|
<>
|
|
28
28
|
<Style>{getStyle()}</Style>
|
|
29
|
-
<div className="navigation-content"
|
|
29
|
+
<div id="menu-navigation-container" className="navigation-content">
|
|
30
30
|
{navItemsByColumnLayouts.map((columnLayout, i) => (
|
|
31
|
-
<div
|
|
31
|
+
<div
|
|
32
|
+
id={`menu-navigation-${i}`}
|
|
33
|
+
className="menu-navigation-content"
|
|
34
|
+
style={{ paddingTop: 10, transition: 'none 0.2s ease-in-out', transitionProperty: 'opacity, transform' }}
|
|
35
|
+
key={i}
|
|
36
|
+
>
|
|
32
37
|
{columnLayout.isFullWidthCategory ? (
|
|
33
38
|
<div style={{ marginTop: 0 }}>
|
|
34
39
|
<ColumnsWrapper numberOfColumns={columnLayout.columns.length}>
|
|
@@ -85,17 +90,35 @@ function NavigationWithColumnLayout(props: { navItems: NavItem[] }) {
|
|
|
85
90
|
function getStyle() {
|
|
86
91
|
const style = css`
|
|
87
92
|
@media(min-width: ${containerQueryMobileMenu + 1}px) {
|
|
93
|
+
.menu-navigation-content {
|
|
94
|
+
position: absolute;
|
|
95
|
+
width: 100%;
|
|
96
|
+
}
|
|
88
97
|
${navItemsByColumnLayouts
|
|
89
|
-
.map(
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
98
|
+
.map((_, i) => {
|
|
99
|
+
const isFirst = i === 0
|
|
100
|
+
const isLast = i === navItemsByColumnLayouts.length - 1
|
|
101
|
+
return css`
|
|
102
|
+
#menu-navigation-${i} {
|
|
103
|
+
${/* Fading animation */ ''}
|
|
104
|
+
html:not(.menu-modal-show-${i}) & {
|
|
105
|
+
opacity: 0;
|
|
106
|
+
pointer-events: none;
|
|
107
|
+
}
|
|
108
|
+
${/* Sliding animation */ ''}
|
|
109
|
+
html:not(.menu-modal-show-${i}).menu-modal-show & {
|
|
110
|
+
${!isFirst && !isLast ? '' : `transform: translate(${isFirst ? '-' : ''}50px, 0);`}
|
|
111
|
+
}
|
|
112
|
+
${/* Performance optimization. */ ''}
|
|
113
|
+
${/* - Using clip-path transition instead of height transition doesn't make a difference: https://github.com/brillout/docpress/commit/005cba0b4cba9c1b526e8e26901ee04129d79715 */ ''}
|
|
114
|
+
${/* - Suprisingly, this is a performance regression when transitioning from one menu to another (the menu is kept open). Thus we apply this only when the menu is being closed/opened. */ ''}
|
|
115
|
+
html:not(.menu-modal-show-${i}).menu-modal-opening-or-closing & {
|
|
116
|
+
display: none;
|
|
117
|
+
}
|
|
94
118
|
}
|
|
95
|
-
|
|
96
|
-
.menu-
|
|
119
|
+
.menu-toggle-${i} {
|
|
120
|
+
html.menu-modal-show.menu-modal-show-${i} & {
|
|
97
121
|
color: black !important;
|
|
98
|
-
cursor: default !important;
|
|
99
122
|
[class^='decolorize-'],
|
|
100
123
|
[class*=' decolorize-'] {
|
|
101
124
|
filter: grayscale(0) opacity(1) !important;
|
|
@@ -104,9 +127,12 @@ html.menu-modal-show.menu-modal-show-${i} {
|
|
|
104
127
|
top: 0;
|
|
105
128
|
}
|
|
106
129
|
}
|
|
130
|
+
html.menu-modal-show & {
|
|
131
|
+
cursor: default !important;
|
|
132
|
+
}
|
|
107
133
|
}
|
|
108
|
-
|
|
109
|
-
)
|
|
134
|
+
`
|
|
135
|
+
})
|
|
110
136
|
.join('')}
|
|
111
137
|
}
|
|
112
138
|
`
|
|
@@ -6,19 +6,19 @@ export { closeMenuOnMouseLeave }
|
|
|
6
6
|
export { addListenerOpenMenuModal }
|
|
7
7
|
|
|
8
8
|
import { containerQueryMobileLayout } from '../Layout'
|
|
9
|
+
import { getHydrationPromise } from '../renderer/getHydrationPromise'
|
|
9
10
|
import { getViewportWidth } from '../utils/getViewportWidth'
|
|
10
11
|
import { isBrowser } from '../utils/isBrowser'
|
|
11
12
|
|
|
12
13
|
initScrollListener()
|
|
13
14
|
|
|
14
15
|
function keepMenuModalOpen() {
|
|
15
|
-
if (keepOpenIsDisabled) return
|
|
16
16
|
open()
|
|
17
17
|
}
|
|
18
18
|
function openMenuModal(menuNavigationId: number) {
|
|
19
19
|
open(menuNavigationId)
|
|
20
20
|
}
|
|
21
|
-
function open(menuNavigationId?: number) {
|
|
21
|
+
async function open(menuNavigationId?: number) {
|
|
22
22
|
if (menuModalLock) {
|
|
23
23
|
if (menuNavigationId === undefined) {
|
|
24
24
|
clearTimeout(menuModalLock?.timeout)
|
|
@@ -29,7 +29,10 @@ function open(menuNavigationId?: number) {
|
|
|
29
29
|
return
|
|
30
30
|
}
|
|
31
31
|
const { classList } = document.documentElement
|
|
32
|
-
classList.
|
|
32
|
+
if (!classList.contains('menu-modal-show')) {
|
|
33
|
+
onBeforeOpeningOrClosing()
|
|
34
|
+
classList.add('menu-modal-show')
|
|
35
|
+
}
|
|
33
36
|
if (menuNavigationId !== undefined) {
|
|
34
37
|
const currentModalId = getCurrentMenuId()
|
|
35
38
|
if (currentModalId === menuNavigationId) return
|
|
@@ -37,6 +40,10 @@ function open(menuNavigationId?: number) {
|
|
|
37
40
|
classList.remove(`menu-modal-show-${currentModalId}`)
|
|
38
41
|
}
|
|
39
42
|
classList.add(`menu-modal-show-${menuNavigationId}`)
|
|
43
|
+
await getHydrationPromise()
|
|
44
|
+
// Because all `.menu-navigation-content` are `position: absolute` we have to propagate the content height ourselves.
|
|
45
|
+
const height = window.getComputedStyle(document.getElementById(`menu-navigation-${menuNavigationId}`)!).height
|
|
46
|
+
document.getElementById('menu-navigation-container')!.style.height = height
|
|
40
47
|
}
|
|
41
48
|
listener?.()
|
|
42
49
|
}
|
|
@@ -45,16 +52,31 @@ function addListenerOpenMenuModal(cb: () => void) {
|
|
|
45
52
|
listener = cb
|
|
46
53
|
}
|
|
47
54
|
function closeMenuModal() {
|
|
48
|
-
document.documentElement
|
|
55
|
+
const { classList } = document.documentElement
|
|
56
|
+
if (classList.contains('menu-modal-show')) {
|
|
57
|
+
onBeforeOpeningOrClosing(() => {
|
|
58
|
+
// Remove:
|
|
59
|
+
// menu-modal-show-0
|
|
60
|
+
// menu-modal-show-1
|
|
61
|
+
// ...
|
|
62
|
+
classList.forEach((className) => {
|
|
63
|
+
if (className.startsWith('menu-modal-show-')) {
|
|
64
|
+
classList.remove(className)
|
|
65
|
+
}
|
|
66
|
+
})
|
|
67
|
+
})
|
|
68
|
+
classList.remove('menu-modal-show')
|
|
69
|
+
}
|
|
49
70
|
}
|
|
50
|
-
let
|
|
51
|
-
function
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
setTimeout(() => {
|
|
56
|
-
|
|
57
|
-
|
|
71
|
+
let timeoutModalAnimation: NodeJS.Timeout | undefined
|
|
72
|
+
function onBeforeOpeningOrClosing(cb?: () => void) {
|
|
73
|
+
const { classList } = document.documentElement
|
|
74
|
+
classList.add('menu-modal-opening-or-closing')
|
|
75
|
+
clearTimeout(timeoutModalAnimation)
|
|
76
|
+
timeoutModalAnimation = setTimeout(() => {
|
|
77
|
+
classList.remove('menu-modal-opening-or-closing')
|
|
78
|
+
cb?.()
|
|
79
|
+
}, 450)
|
|
58
80
|
}
|
|
59
81
|
|
|
60
82
|
let menuModalLock:
|
|
@@ -72,7 +94,7 @@ function closeMenuOnMouseLeave() {
|
|
|
72
94
|
menuModalLock = undefined
|
|
73
95
|
if (idNext === idCurrent) return
|
|
74
96
|
if (idNext === undefined) {
|
|
75
|
-
|
|
97
|
+
closeMenuModal()
|
|
76
98
|
} else {
|
|
77
99
|
openMenuModal(idNext)
|
|
78
100
|
}
|
|
@@ -94,11 +116,10 @@ function getCurrentMenuId(): null | number {
|
|
|
94
116
|
|
|
95
117
|
function initScrollListener() {
|
|
96
118
|
if (!isBrowser()) return
|
|
97
|
-
window.addEventListener('scroll',
|
|
119
|
+
window.addEventListener('scroll', closeMenuModal, { passive: true })
|
|
98
120
|
}
|
|
99
121
|
|
|
100
122
|
function toggleMenuModal(menuId: number) {
|
|
101
|
-
keepOpenIsDisabled = undefined
|
|
102
123
|
const { classList } = document.documentElement
|
|
103
124
|
if (classList.contains('menu-modal-show') && classList.contains(`menu-modal-show-${menuId}`)) {
|
|
104
125
|
closeMenuModal()
|
|
@@ -109,7 +130,7 @@ function toggleMenuModal(menuId: number) {
|
|
|
109
130
|
}
|
|
110
131
|
|
|
111
132
|
function autoScroll() {
|
|
112
|
-
const nav = document.querySelector('#menu-modal .navigation-content')!
|
|
133
|
+
const nav = document.querySelector('#menu-modal-wrapper .navigation-content')!
|
|
113
134
|
const href = window.location.pathname
|
|
114
135
|
const navLinks = Array.from(nav.querySelectorAll(`a[href="${href}"]`))
|
|
115
136
|
const navLink = navLinks[0] as HTMLElement | undefined
|
package/MenuModal.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { MenuModal }
|
|
2
2
|
|
|
3
|
-
import React, { useEffect,
|
|
3
|
+
import React, { useEffect, useState } from 'react'
|
|
4
4
|
import { usePageContext } from './renderer/usePageContext'
|
|
5
5
|
import { css } from './utils/css'
|
|
6
6
|
import { blockMargin, containerQueryMobileLayout, containerQueryMobileMenu } from './Layout'
|
|
@@ -10,58 +10,48 @@ import { NavigationWithColumnLayout } from './MenuModal/NavigationWithColumnLayo
|
|
|
10
10
|
import { addListenerOpenMenuModal, closeMenuModal, keepMenuModalOpen } from './MenuModal/toggleMenuModal'
|
|
11
11
|
|
|
12
12
|
function MenuModal({ isTopNav }: { isTopNav: boolean }) {
|
|
13
|
-
|
|
14
|
-
const [height, setHeight] = useState
|
|
13
|
+
// `transition: height` doesn't work on `height: auto` => we have to manually set and change `height` to a fixed size.
|
|
14
|
+
const [height, setHeight] = useState(0)
|
|
15
15
|
useEffect(() => {
|
|
16
|
-
|
|
17
|
-
const { scrollHeight } =
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
updateHeight()
|
|
16
|
+
addListenerOpenMenuModal(() => {
|
|
17
|
+
const { scrollHeight } = document.getElementById('menu-modal-scroll-container')!
|
|
18
|
+
const heightNew = scrollHeight + blockMargin
|
|
19
|
+
if (height !== heightNew) setHeight(heightNew)
|
|
20
|
+
})
|
|
22
21
|
})
|
|
23
22
|
return (
|
|
24
23
|
<>
|
|
25
24
|
<Style>{getStyle()}</Style>
|
|
26
25
|
<div
|
|
27
|
-
id="menu-modal"
|
|
28
|
-
className="link-hover-animation add-transition"
|
|
26
|
+
id="menu-modal-wrapper"
|
|
27
|
+
className="link-hover-animation add-transition show-on-nav-hover"
|
|
29
28
|
style={{
|
|
30
29
|
position: isTopNav ? 'absolute' : 'fixed',
|
|
31
30
|
width: '100%',
|
|
32
31
|
top: 'var(--nav-head-height)',
|
|
33
32
|
left: 0,
|
|
34
|
-
zIndex:
|
|
35
|
-
overflowY: 'scroll',
|
|
33
|
+
zIndex: 199, // maximum value, because docsearch's modal has `z-index: 200`
|
|
36
34
|
background: '#ededef',
|
|
37
|
-
transitionProperty: 'height',
|
|
35
|
+
transitionProperty: 'height, opacity',
|
|
38
36
|
transitionTimingFunction: 'ease',
|
|
39
|
-
// https://github.com/brillout/docpress/issues/23
|
|
40
|
-
// https://stackoverflow.com/questions/64514118/css-overscroll-behavior-contain-when-target-element-doesnt-overflow
|
|
41
|
-
// https://stackoverflow.com/questions/9538868/prevent-body-from-scrolling-when-a-modal-is-opened
|
|
42
|
-
overscrollBehavior: 'none',
|
|
43
37
|
height,
|
|
38
|
+
overflow: 'hidden',
|
|
44
39
|
}}
|
|
45
|
-
ref={ref}
|
|
46
40
|
onMouseOver={() => keepMenuModalOpen()}
|
|
47
41
|
onMouseLeave={closeMenuModal}
|
|
48
42
|
>
|
|
49
43
|
<div
|
|
44
|
+
id="menu-modal-scroll-container"
|
|
50
45
|
style={{
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
flexDirection: 'column',
|
|
54
|
-
justifyContent: 'space-between',
|
|
55
|
-
minHeight: '100%',
|
|
56
|
-
position: 'relative',
|
|
57
|
-
// We don't set `container` to the parent #menu-modal beacuse of a Chrome bug (showing a blank <MenuModal>)
|
|
46
|
+
overflowY: 'scroll',
|
|
47
|
+
// We don't set `container` to the parent #menu-modal-wrapper beacuse of a Chrome bug (showing a blank <MenuModal>). Edit: IIRC because #menu-modal-wrapper has `position: fixed`.
|
|
58
48
|
container: 'container-viewport / inline-size',
|
|
59
49
|
}}
|
|
60
50
|
>
|
|
61
51
|
<Nav />
|
|
62
52
|
<NavSecondary className="show-only-for-mobile" />
|
|
63
|
-
<BorderBottom />
|
|
64
53
|
</div>
|
|
54
|
+
<BorderBottom />
|
|
65
55
|
<CloseButton className="show-only-for-mobile" />
|
|
66
56
|
</div>
|
|
67
57
|
</>
|
|
@@ -71,7 +61,13 @@ function BorderBottom() {
|
|
|
71
61
|
return (
|
|
72
62
|
<div
|
|
73
63
|
id="border-bottom"
|
|
74
|
-
style={{
|
|
64
|
+
style={{
|
|
65
|
+
position: 'absolute',
|
|
66
|
+
background: '#fff',
|
|
67
|
+
height: 'var(--block-margin)',
|
|
68
|
+
width: '100%',
|
|
69
|
+
bottom: 0,
|
|
70
|
+
}}
|
|
75
71
|
/>
|
|
76
72
|
)
|
|
77
73
|
}
|
|
@@ -98,30 +94,42 @@ function NavSecondary({ className }: { className: string }) {
|
|
|
98
94
|
function getStyle() {
|
|
99
95
|
return css`
|
|
100
96
|
@media(min-width: ${containerQueryMobileMenu + 1}px) {
|
|
101
|
-
#menu-modal
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
max-height: calc(100vh - var(--nav-head-height));
|
|
105
|
-
${/* We use dvh because of mobile */ ''}
|
|
106
|
-
${/* https://stackoverflow.com/questions/37112218/css3-100vh-not-constant-in-mobile-browser/72245072#72245072 */ ''}
|
|
107
|
-
max-height: calc(100dvh - var(--nav-head-height));
|
|
97
|
+
#menu-modal-scroll-container,
|
|
98
|
+
#menu-modal-wrapper {
|
|
99
|
+
max-height: calc(100vh - var(--nav-head-height));
|
|
108
100
|
}
|
|
109
|
-
|
|
110
|
-
|
|
101
|
+
#menu-modal-scroll-container {
|
|
102
|
+
${/* https://github.com/brillout/docpress/issues/23 */ ''}
|
|
103
|
+
${/* https://stackoverflow.com/questions/64514118/css-overscroll-behavior-contain-when-target-element-doesnt-overflow */ ''}
|
|
104
|
+
${/* https://stackoverflow.com/questions/9538868/prevent-body-from-scrolling-when-a-modal-is-opened */ ''}
|
|
105
|
+
overscroll-behavior: none;
|
|
106
|
+
}
|
|
107
|
+
html:not(.menu-modal-show) #menu-modal-wrapper {
|
|
108
|
+
${/* 3px */ ''}
|
|
109
|
+
height: var(--block-margin) !important;
|
|
110
|
+
pointer-events: none;
|
|
111
111
|
}
|
|
112
112
|
.show-only-for-mobile {
|
|
113
113
|
display: none !important;
|
|
114
114
|
}
|
|
115
115
|
}
|
|
116
116
|
@media(max-width: ${containerQueryMobileMenu}px) {
|
|
117
|
-
#menu-modal {
|
|
117
|
+
#menu-modal-scroll-container {
|
|
118
|
+
${/* Fallback for Firefox: it doesn't support `dvh` yet: https://caniuse.com/?search=dvh */ ''}
|
|
119
|
+
${/* Let's always and systematically use `dvh` instead of `vh` once Firefox supports it */ ''}
|
|
118
120
|
height: calc(100vh) !important;
|
|
121
|
+
${/* We use dvh because of mobile */ ''}
|
|
122
|
+
${/* https://stackoverflow.com/questions/37112218/css3-100vh-not-constant-in-mobile-browser/72245072#72245072 */ ''}
|
|
119
123
|
height: calc(100dvh) !important;
|
|
124
|
+
${/* Place <NavSecondary /> to the bottom */ ''}
|
|
125
|
+
display: flex;
|
|
126
|
+
flex-direction: column;
|
|
127
|
+
justify-content: space-between;
|
|
120
128
|
}
|
|
121
129
|
#border-bottom {
|
|
122
130
|
display: none;
|
|
123
131
|
}
|
|
124
|
-
html:not(.menu-modal-show) #menu-modal {
|
|
132
|
+
html:not(.menu-modal-show) #menu-modal-wrapper {
|
|
125
133
|
opacity: 0;
|
|
126
134
|
pointer-events: none;
|
|
127
135
|
}
|
|
@@ -129,12 +137,16 @@ function getStyle() {
|
|
|
129
137
|
html.menu-modal-show {
|
|
130
138
|
overflow: hidden !important;
|
|
131
139
|
}
|
|
132
|
-
#menu-modal {
|
|
140
|
+
#menu-modal-wrapper {
|
|
133
141
|
--nav-head-height: 0px !important;
|
|
134
142
|
}
|
|
143
|
+
#menu-modal-wrapper,
|
|
144
|
+
#menu-navigation-container {
|
|
145
|
+
height: auto!important;
|
|
146
|
+
}
|
|
135
147
|
}
|
|
136
148
|
@container container-viewport (min-width: ${containerQueryMobileLayout}px) {
|
|
137
|
-
#menu-modal .nav-item-level-3 {
|
|
149
|
+
#menu-modal-wrapper .nav-item-level-3 {
|
|
138
150
|
display: none;
|
|
139
151
|
}
|
|
140
152
|
}
|
package/NavItemComponent.css
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@brillout/docpress",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@brillout/picocolors": "^1.0.10",
|
|
@@ -55,15 +55,7 @@
|
|
|
55
55
|
}
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
|
-
"@brillout/release-me": "^0.4.2"
|
|
59
|
-
"@types/node": "link:../demo/node_modules/@types/node/",
|
|
60
|
-
"@types/react": "link:../demo/node_modules/@types/react/",
|
|
61
|
-
"@types/react-dom": "link:../demo/node_modules/@types/react-dom/",
|
|
62
|
-
"react": "link:../demo/node_modules/react/",
|
|
63
|
-
"react-dom": "link:../demo/node_modules/react-dom/",
|
|
64
|
-
"typescript": "link:../demo/node_modules/typescript/",
|
|
65
|
-
"vike": "link:../demo/node_modules/vike/",
|
|
66
|
-
"vite": "link:../demo/node_modules/vite/"
|
|
58
|
+
"@brillout/release-me": "^0.4.2"
|
|
67
59
|
},
|
|
68
60
|
"repository": "https://github.com/brillout/docpress",
|
|
69
61
|
"license": "MIT",
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export { getHydrationPromise }
|
|
2
|
+
export { setHydrationIsFinished }
|
|
3
|
+
|
|
4
|
+
import { getGlobalObject } from '../utils/client'
|
|
5
|
+
import { genPromise } from '../utils/genPromise'
|
|
6
|
+
|
|
7
|
+
const globalObject = getGlobalObject<{
|
|
8
|
+
hydrationPromise: Promise<void>
|
|
9
|
+
hydrationPromiseResolve: () => void
|
|
10
|
+
}>(
|
|
11
|
+
'onRenderClient.ts',
|
|
12
|
+
(() => {
|
|
13
|
+
const { promise: hydrationPromise, resolve: hydrationPromiseResolve } = genPromise()
|
|
14
|
+
return {
|
|
15
|
+
hydrationPromise,
|
|
16
|
+
hydrationPromiseResolve,
|
|
17
|
+
}
|
|
18
|
+
})(),
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
function getHydrationPromise() {
|
|
22
|
+
return globalObject.hydrationPromise
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function setHydrationIsFinished() {
|
|
26
|
+
globalObject.hydrationPromiseResolve()
|
|
27
|
+
// Used by:
|
|
28
|
+
// - https://github.com/vikejs/vike/blob/9d67f3dd4bdfb38c835186b8147251e0e3b06657/docs/.testRun.ts#L22
|
|
29
|
+
// - https://github.com/brillout/telefunc/blob/57c942c15b7795cfda96b5106acc9e098aa509aa/docs/.testRun.ts#L26
|
|
30
|
+
;(window as any).__docpress_hydrationFinished = true
|
|
31
|
+
}
|
|
@@ -12,10 +12,10 @@ import { installSectionUrlHashs } from '../installSectionUrlHashs'
|
|
|
12
12
|
import { getGlobalObject } from '../utils/client'
|
|
13
13
|
import { initKeyBindings } from '../initKeyBindings'
|
|
14
14
|
import { initOnNavigation } from './initOnNavigation'
|
|
15
|
+
import { setHydrationIsFinished } from './getHydrationPromise'
|
|
15
16
|
|
|
16
17
|
const globalObject = getGlobalObject<{
|
|
17
18
|
root?: ReactDOM.Root
|
|
18
|
-
renderPromiseResolve?: () => void
|
|
19
19
|
}>('onRenderClient.ts', {})
|
|
20
20
|
|
|
21
21
|
addEcosystemStamp()
|
|
@@ -27,11 +27,12 @@ async function onRenderClient(pageContext: PageContextClient) {
|
|
|
27
27
|
|
|
28
28
|
// TODO: stop using any
|
|
29
29
|
const pageContextResolved: PageContextResolved = (pageContext as any).pageContextResolved
|
|
30
|
+
let renderPromiseResolve!: () => void
|
|
30
31
|
const renderPromise = new Promise<void>((r) => {
|
|
31
|
-
|
|
32
|
+
renderPromiseResolve = r
|
|
32
33
|
})
|
|
33
34
|
let page = getPageElement(pageContext, pageContextResolved)
|
|
34
|
-
page = <OnRenderDoneHook>{page}</OnRenderDoneHook>
|
|
35
|
+
page = <OnRenderDoneHook renderPromiseResolve={renderPromiseResolve}>{page}</OnRenderDoneHook>
|
|
35
36
|
const container = document.getElementById('page-view')!
|
|
36
37
|
if (pageContext.isHydration) {
|
|
37
38
|
globalObject.root = ReactDOM.hydrateRoot(container, page)
|
|
@@ -58,26 +59,22 @@ function onRenderStart() {
|
|
|
58
59
|
closeMenuModal()
|
|
59
60
|
}
|
|
60
61
|
|
|
61
|
-
function onRenderDone() {
|
|
62
|
+
function onRenderDone(renderPromiseResolve: () => void) {
|
|
62
63
|
autoScrollNav()
|
|
63
64
|
// TODO/refactor: use React?
|
|
64
65
|
installSectionUrlHashs()
|
|
65
66
|
setHydrationIsFinished()
|
|
66
|
-
|
|
67
|
+
renderPromiseResolve()
|
|
67
68
|
}
|
|
68
69
|
|
|
69
|
-
function OnRenderDoneHook({
|
|
70
|
-
|
|
70
|
+
function OnRenderDoneHook({
|
|
71
|
+
renderPromiseResolve,
|
|
72
|
+
children,
|
|
73
|
+
}: { renderPromiseResolve: () => void; children: React.ReactNode }) {
|
|
74
|
+
useEffect(() => onRenderDone(renderPromiseResolve))
|
|
71
75
|
return children
|
|
72
76
|
}
|
|
73
77
|
|
|
74
|
-
function setHydrationIsFinished() {
|
|
75
|
-
// Used by:
|
|
76
|
-
// - https://github.com/vikejs/vike/blob/9d67f3dd4bdfb38c835186b8147251e0e3b06657/docs/.testRun.ts#L22
|
|
77
|
-
// - https://github.com/brillout/telefunc/blob/57c942c15b7795cfda96b5106acc9e098aa509aa/docs/.testRun.ts#L26
|
|
78
|
-
;(window as any).__docpress_hydrationFinished = true
|
|
79
|
-
}
|
|
80
|
-
|
|
81
78
|
// Used by:
|
|
82
79
|
// - https://github.com/vikejs/vike/blob/87cca54f30b3c7e71867763d5723493d7eef37ab/vike/client/client-routing-runtime/prefetch.ts#L309-L312
|
|
83
80
|
function addEcosystemStamp() {
|
package/utils/css.ts
CHANGED