Skip to content

Commit

Permalink
Merge branch 'canary' into suspensey-dynamic
Browse files Browse the repository at this point in the history
  • Loading branch information
huozhi committed Dec 6, 2022
2 parents 5290c06 + 5cff316 commit 92cd7d2
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 44 deletions.
29 changes: 14 additions & 15 deletions .github/workflows/build_test_deploy.yml
Expand Up @@ -923,13 +923,6 @@ jobs:
node-version: 16
check-latest: true

- name: Install
uses: actions-rs/toolchain@v1
if: ${{ steps.docs-change.outputs.DOCS_CHANGE == 'nope' }}
with:
profile: minimal
toolchain: ${{ env.RUST_TOOLCHAIN }}

- name: Cache cargo registry
uses: actions/cache@v3
if: ${{ steps.docs-change.outputs.DOCS_CHANGE == 'nope' }}
Expand Down Expand Up @@ -976,14 +969,20 @@ jobs:
restore-keys: |
next-swc-cargo-cache-dev-ubuntu-latest
# since the repo's dependencies aren't installed we need
# to install napi globally
- run: npm i -g @napi-rs/cli@${{ env.NAPI_CLI_VERSION }} turbo@${{ env.TURBO_VERSION }} pnpm@${PNPM_VERSION}
- name: Build
if: ${{ steps.docs-change.outputs.DOCS_CHANGE == 'nope' }}
run: turbo run build-native --cache-dir=".turbo" -- --release
env:
MACOSX_DEPLOYMENT_TARGET: '10.13'
- name: Build in docker
uses: addnab/docker-run-action@v3
with:
image: ghcr.io/napi-rs/napi-rs/nodejs-rust:stable-2022-10-24-x64
options: -e RUST_TOOLCHAIN=${{ env.RUST_TOOLCHAIN }} -e NAPI_CLI_VERSION=${{ env.NAPI_CLI_VERSION }} -e TURBO_VERSION=${{ env.TURBO_VERSION }} -e TURBO_TEAM=vercel -e TURBO_TOKEN=${{ secrets.TURBO_TOKEN }} -e TURBO_REMOTE_ONLY=true -v ${{ env.HOME }}/.cargo/git:/root/.cargo/git -v ${{ env.HOME }}/.cargo/registry:/root/.cargo/registry -v ${{ github.workspace }}:/build -w /build
run: |
set -e &&
rustup toolchain install "${RUST_TOOLCHAIN}" &&
rustup default "${RUST_TOOLCHAIN}" &&
rustup target add x86_64-unknown-linux-gnu &&
npm i -g "@napi-rs/cli@${NAPI_CLI_VERSION}" "turbo@${TURBO_VERSION}" && if [ ! -f $(dirname $(which yarn))/pnpm ]; then ln -s $(which yarn) $(dirname $(which yarn))/pnpm;fi &&
unset CC_x86_64_unknown_linux_gnu && unset CC &&
turbo run build-native --cache-dir=".turbo" -- --release --target x86_64-unknown-linux-gnu &&
strip packages/next-swc/native/next-swc.*.node
- name: Upload artifact
uses: actions/upload-artifact@v3
Expand Down
91 changes: 62 additions & 29 deletions packages/next/client/components/layout-router.tsx
@@ -1,20 +1,18 @@
'use client'

import React, { useContext, useEffect, useRef, use } from 'react'
import type {
ChildProp,
//Segment
} from '../../server/app-render'
import type {
AppRouterInstance,
ChildSegmentMap,
} from '../../shared/lib/app-router-context'
import type {
FlightRouterState,
FlightSegmentPath,
// FlightDataPath,
} from '../../server/app-render'
import type { ErrorComponent } from './error-boundary'
import type { FocusAndScrollRef } from './reducer'

import React, { useContext, useEffect, use } from 'react'
import { findDOMNode as ReactDOMfindDOMNode } from 'react-dom'
import type { ChildProp } from '../../server/app-render'
import {
CacheStates,
LayoutRouterContext,
Expand Down Expand Up @@ -77,6 +75,31 @@ function walkAddRefetch(
return treeToRecreate
}

// TODO-APP: Replace with new React API for finding dom nodes without a `ref` when available
/**
* Wraps ReactDOM.findDOMNode with additional logic to hide React Strict Mode warning
*/
function findDOMNode(
instance: Parameters<typeof ReactDOMfindDOMNode>[0]
): ReturnType<typeof ReactDOMfindDOMNode> {
// Only apply strict mode warning when not in production
if (process.env.NODE_ENV !== 'production') {
const originalConsoleError = console.error
try {
console.error = (...messages) => {
// Ignore strict mode warning for the findDomNode call below
if (!messages[0].includes('Warning: %s is deprecated in StrictMode.')) {
originalConsoleError(...messages)
}
}
return ReactDOMfindDOMNode(instance)
} finally {
console.error = originalConsoleError!
}
}
return ReactDOMfindDOMNode(instance)
}

/**
* Check if the top of the HTMLElement is in the viewport.
*/
Expand All @@ -85,6 +108,36 @@ function topOfElementInViewport(element: HTMLElement) {
return rect.top >= 0
}

class ScrollAndFocusHandler extends React.Component<{
focusAndScrollRef: FocusAndScrollRef
children: React.ReactNode
}> {
componentDidMount() {
// Handle scroll and focus, it's only applied once in the first useEffect that triggers that changed.
const { focusAndScrollRef } = this.props
const domNode = findDOMNode(this)

if (focusAndScrollRef.apply && domNode instanceof HTMLElement) {
// State is mutated to ensure that the focus and scroll is applied only once.
focusAndScrollRef.apply = false
// Set focus on the element
domNode.focus()
// Only scroll into viewport when the layout is not visible currently.
if (!topOfElementInViewport(domNode)) {
const htmlElement = document.documentElement
const existing = htmlElement.style.scrollBehavior
htmlElement.style.scrollBehavior = 'auto'
domNode.scrollIntoView()
htmlElement.style.scrollBehavior = existing
}
}
}

render() {
return this.props.children
}
}

/**
* InnerLayoutRouter handles rendering the provided segment based on the cache.
*/
Expand Down Expand Up @@ -117,26 +170,6 @@ export function InnerLayoutRouter({

const { changeByServerResponse, tree: fullTree, focusAndScrollRef } = context

const focusAndScrollElementRef = useRef<HTMLDivElement>(null)

useEffect(() => {
// Handle scroll and focus, it's only applied once in the first useEffect that triggers that changed.
if (focusAndScrollRef.apply && focusAndScrollElementRef.current) {
// State is mutated to ensure that the focus and scroll is applied only once.
focusAndScrollRef.apply = false
// Set focus on the element
focusAndScrollElementRef.current.focus()
// Only scroll into viewport when the layout is not visible currently.
if (!topOfElementInViewport(focusAndScrollElementRef.current)) {
const htmlElement = document.documentElement
const existing = htmlElement.style.scrollBehavior
htmlElement.style.scrollBehavior = 'auto'
focusAndScrollElementRef.current.scrollIntoView()
htmlElement.style.scrollBehavior = existing
}
}
}, [focusAndScrollRef])

// Read segment path from the parallel router cache node.
let childNode = childNodes.get(path)

Expand Down Expand Up @@ -257,9 +290,9 @@ export function InnerLayoutRouter({

// Ensure root layout is not wrapped in a div as the root layout renders `<html>`
return rootLayoutIncluded ? (
<div ref={focusAndScrollElementRef} data-nextjs-scroll-focus-boundary={''}>
<ScrollAndFocusHandler focusAndScrollRef={focusAndScrollRef}>
{subtree}
</div>
</ScrollAndFocusHandler>
) : (
subtree
)
Expand Down

0 comments on commit 92cd7d2

Please sign in to comment.