• Stars
    star
    257
  • Rank 158,728 (Top 4 %)
  • Language
    JavaScript
  • License
    MIT License
  • Created almost 5 years ago
  • Updated over 3 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Add persistent and nested layouts to your Next.js projects in a declarative way

next-layout

NPM version Downloads Build Status Coverage Status Dependency status Dev Dependency status

Add persistent and nested layouts to your Next.js projects in a declarative way.

Installation

$ npm install @moxy/next-layout

This library is written in modern JavaScript and is published in both CommonJS and ES module transpiled variants. If you target older browsers please make sure to transpile accordingly.

Motivation

Next.js projects usually have the need to have one or more layouts. Layouts are the "shell" of your app and usually contain navigation elements, such as an header and a footer. In more complex projects, you might also need to have nested layouts which are often associated with nested routes.

In the ideal scenario, each page would be able to say which layout they want to use, including tweaking its properties dynamically, such as variant="light". However, we also want to keep the layout persistent in the React tree, to avoid having to remount it every time a user navigate between pages.

Historically, projects overlook the need of multiple layouts or the ability to change layout props between pages. They start off with a simple layout and only later they handle this need, often with poor and non-scalable solutions.

This library solves the need for multi-layouts and changing layout props dynamically in a consistent and reusable way.

Usage

Setup <LayoutTree> in your pages/_app.js component:

import React from 'react';
import { LayoutTree } from '@moxy/next-layout';

const App = ({ Component, pageProps }) => (
    <LayoutTree
        Component={ Component }
        pageProps={ pageProps } />
);

export default App;

...and then use withLayout in your page components, e.g.: in pages/about.js:

import React from 'react';
import { withLayout } from '@moxy/next-layout';
import { PrimaryLayout } from '../components';
import styles from './about.module.css';

const About = () => (
    <div className={ styles.about }>
        <h1>About</h1>
    </div>
);

export default withLayout(<PrimaryLayout variant="light" />)(About);

ℹī¸ The PrimaryLayout component will receive the page to be rendered as the children prop.

Nested layouts

Nested layouts are as easy as nesting them in the withLayout. Let's say that you have two account pages, pages/account/profile.js and pages/account/settings.js, and you want them to be wrapped by an AccountLayout. You would define the pages like so:

// pages/account/profile.js
import React from 'react';
import { withLayout } from '@moxy/next-layout';
import { PrimaryLayout, AccountLayout } from '../components';
import styles from './.account-profile.module.css';

const AccountProfile = () => (
    <div className={ styles.accountProfile }>
        <h1>Account Profile</h1>
    </div>
);

export default withLayout(
    <PrimaryLayout>
        <AccountLayout />
    <PrimaryLayout />
)(AccountProfile);
// pages/account/settings.js
import React from 'react';
import { withLayout } from '@moxy/next-layout';
import { PrimaryLayout, AccountLayout } from '../components';
import styles from './account-settings.module.css';

const AccountSettings = () => (
    <div className={ styles.accountSettings }>
        <h1>Account Settings</h1>
    </div>
);

export default withLayout(
    <PrimaryLayout>
        <AccountLayout />
    <PrimaryLayout />
)(AccountSettings);

ℹī¸ The PrimaryLayout component will receive AccountLayout as a children, which in turn will receive the page as children too.

ℹī¸ You could create a withAccountLayout HOC to avoid repeating the layout tree in every account page.

⚠ī¸ The layout tree specified in withLayout must be a unary tree, that is, a tree where nodes just have one child.

API

@moxy/next-layout exposes a <LayoutTree> component and a withLayout HOC to be used in pages.

<LayoutTree>

A component that infers the layout tree based on what the active page specifies. It keeps the layout persistent between page transitions whenever possible (e.g.: when the layout is the same).

Here's the list of props it supports:

Component

Type: ReactElementType

The page component, which maps to your App Component prop.

pageProps

Type: object

The page component props, which maps to your App pageProps prop.

pageKey?

Type: string

The page key used to uniquely identify this page. Useful for dynamic routes, where the Component is the same, but you still want the page to be re-mounted. For such cases, you may use router.asPath.replace(/\?.+/, '').

defaultLayout

Type: ReactElement

The default layout tree to be used when a child page doesn't explicitly sets one.

// pages/_app.js
import React from 'react';
import { LayoutTree } from '@moxy/next-layout';
import { PrimaryLayout } from '../components';

const App = ({ Component, pageProps }) => (
    <LayoutTree
        Component={ Component }
        pageProps={ pageProps }
        defaultLayout={ <PrimaryLayout /> } />
);

export default App;

children

Type: function

A render prop to override the default render behavior, which just regularly renders the tree.

Its signature is (tree) => <ReactElement>, where: tree is the React's tree composed by layout elements and a leaf page element.

This might be useful if you want to add animations between page transitions.

withLayout(mapLayoutStateToLayoutTree?, initialLayoutState?)(Page)

Sets up a Page component with the ability to specify which layout tree to use. Moreover, it injects a setLayoutState prop so that you may dynamically update the layout tree.

mapLayoutStateToLayoutTree

Type: ReactElement or function

In simple cases, you may define a "static" layout tree, like so:

export default withLayout(<PrimaryLayout variant="light" />)(Home);

However, you might have external props, component state or other mutations influencing the layout tree. In those cases, you may pass a function that maps layout state into a tree, with the following signature: (layoutState) => <ReactElement>. Here's an example:

const mapLayoutStateToLayoutTree = ({ variant }) => <PrimaryLayout variant={ variant } />;

export default withLayout(mapLayoutStateToLayoutTree, { variant: 'light' })(Home);

The function is run initially and every time the layout state changes.

initialLayoutState

Type: object or function

The initial layout state to be passed to mapLayoutStateToLayoutTree. If your initial layout state depends on the props you receive, you may pass a function with the following signature: (props) => <object>.

Page

Type: ReactElementType

The page component to wrap.

Injected setLayoutState

Type: function

Allows dynamic changes to the layout state. Has the following signature: (newState | updater?).

The behavior of setLayoutState is exactly the same as setState of class components: it merges properties and it supports both an object or an updater function.

// pages/about.js
import React, { useCallback } from 'react';
import { withLayout } from '@moxy/next-layout';
import { PrimaryLayout } from '../components';

import styles from './about.module.css';

const About = ({ setLayoutState }) => {
    const handleSetToDark = useCallback(() => {
        setLayoutState({ variant: 'dark' });
        // ..or setLayoutState((layoutState) => ({ variant: 'dark' }));
    }, [setLayoutState]);

    return (
        <div className={ styles.about }>
            <h1>About</h1>
            <button onClick={ handleSetToDark }>Enable dark mode</button>
        </div>
    );
};

const mapLayoutStateToLayoutTree = ({ variant }) => <PrimaryLayout variant={ variant } />;

export default withLayout(mapLayoutStateToLayoutTree, { variant: 'light' })(About);

Tests

$ npm test
$ npm test -- --watch # during development

License

Released under the MIT License.

More Repositories

1

node-cross-spawn

A cross platform solution to node's spawn and spawnSync
JavaScript
1,067
star
2

node-proper-lockfile

An inter-process and inter-machine lockfile utility that works on a local or network file system.
JavaScript
221
star
3

node-promptly

Simple command line prompting utility for nodejs
JavaScript
148
star
4

gatsby-plugin-ipfs

Adds support for deploying Gatsby to IPFS by ensuring that assets are relative
JavaScript
113
star
5

next-router-scroll

Take control of when scroll is updated and restored in your Next.js projects.
JavaScript
105
star
6

next-with-moxy

MOXY's boilerplate to accelerate the setup of new Next.js based web applications
JavaScript
101
star
7

js-proper-url-join

Like path.join but for a URL
JavaScript
40
star
8

next-intl

Library to integrate react-intl with Next.js.
JavaScript
40
star
9

webpack-isomorphic-dev-middleware

The webpack-dev-middleware, but for isomorphic applications
JavaScript
39
star
10

react-with-moxy

MOXY's boilerplate to create isomorphic react applications
JavaScript
36
star
11

js-deep-for-each

Recursively iterates over collections arrays and objects
JavaScript
35
star
12

node-token-dealer

Circumvent API rate limits by having several API tokens and let the dealer manage and give them to you
JavaScript
24
star
13

react-native-with-moxy

MOXY's boilerplate to accelerate the setup of new React Native mobile apps
JavaScript
22
star
14

js-class-is

Enhances a JavaScript class by adding an is<Class> property to compare types between realms.
JavaScript
17
star
15

webpack-isomorphic-compiler

A compiler that makes your life easier if you are building isomorphic webpack powered apps, that is, single page applications with server-side rendering
JavaScript
16
star
16

react-page-swapper

An orchestrator that eases out the implementation of page transitions
JavaScript
15
star
17

eslint-config

MOXY eslint configuration to be used across several JavaScript projects
JavaScript
14
star
18

react-carousel

A React carousel component that aims to be as flexible as possible
JavaScript
14
star
19

react-contentful-image

A react image renderer that uses the Contentful Images API.
JavaScript
12
star
20

ugo

An extensible and composable cli
12
star
21

next-sitemaps

An API handler and a plugin that enables your Next.js application to have working sitemaps
JavaScript
12
star
22

js-keyboard-only-outlines

Disable outlines caused by navigation methods other than keyboard
JavaScript
11
star
23

next-common-files

Next.js plugins that configure webpack with loaders for common files
JavaScript
9
star
24

react-promiseful

A React component and hook to render children conditionally based on a promise state
JavaScript
9
star
25

postcss-preset

PostCSS preset to be used at MOXY
JavaScript
8
star
26

next-env

Next.js plugin to pass environment variables to Next.js's configuration
JavaScript
8
star
27

webpack-sane-compiler

A webpack compiler wrapper that provides a nicer API
JavaScript
8
star
28

react-lib-template

This template aims to make the implementation of react component packages easier and more methodic.
JavaScript
8
star
29

stylelint-config

MOXY stylelint configuration to be used across several CSS projects
JavaScript
8
star
30

next-pre-compression

Next.js plugin to compress static assets at build time and serve them instead of having to compress on-the-fly
JavaScript
8
star
31

node-gh-issues-stats

Collect statistical information about issues of a GitHub repository
JavaScript
8
star
32

next-link

A component that enables client-side transitions between routes as well as external URLs.
JavaScript
7
star
33

redux-mock-store-await-actions

Waits for specific actions to be dispatched or a timeout expires
JavaScript
7
star
34

webpack-isomorphic-compiler-reporter

Beautiful reporting for webpack-isomorphic-compiler compilation events
JavaScript
7
star
35

react-split-text

A react component that wraps each word of a sentence into a <span> element.
JavaScript
6
star
36

yargs-get-help

Get the help output from a yargs instance
JavaScript
6
star
37

js-chained-config

Use a chaining API to generate and simplify the modification of configs
JavaScript
5
star
38

babel-preset

Babel preset to be used at MOXY
JavaScript
5
star
39

yargs-unparser

Converts back a yargs argv object to its original array form
5
star
40

workshop-react

A workshop to introduce developers to React, presented in the Aveiro University
JavaScript
5
star
41

next-compile-node-modules

Next.js plugin to compile all node_modules using Babel
JavaScript
5
star
42

yargs-promise-handler

Adds support for promises to yargs handlers and allows them to be composable
JavaScript
5
star
43

react-wait-for-react

Easily render a splash screen and loader while your React app is not yet interactive, optionally waiting for a promise as well
JavaScript
5
star
44

react-app-rewire-css-modules-extensionless

Enables CSS modules without any special extension for CRA apps using react-app-rewired
JavaScript
5
star
45

react-keyboard-only-outlines

Disable outlines caused by navigation methods other than keyboard
JavaScript
4
star
46

webpack-sane-compiler-notifier

Notify webpack compilation status to your operating system when using webpack-sane-compiler
JavaScript
4
star
47

react-icon

A component to render svg icons.
JavaScript
4
star
48

next-rest-api

Aims to ease the development of REST APIs in Next.js
JavaScript
4
star
49

next-seo

Manage document head SEO metadata in your Next.js projects with a simple data structure.
JavaScript
4
star
50

node-fetch-coverage

Fetch the code coverage from an open-source GIT repository, using a variety of well-known coverage services
JavaScript
4
star
51

webpack-sane-compiler-reporter

Beautiful reporting for webpack-sane-compiler compilation events
JavaScript
4
star
52

react-modal

A modal, built on top of react-modal, that also fixes the scrollable body in iOS
JavaScript
3
star
53

node-is-regular-file

Checks if a path is a regular file
JavaScript
3
star
54

react-navigation

Set of react components, hooks and providers to easily kickoff a navigation environment in web projects.
JavaScript
3
star
55

webpack-isomorphic-compiler-notifier

Notify webpack compilation status to your operating system when using webpack-isomorphic-compiler
JavaScript
3
star
56

js-pico-signals

A very simple signal library inspired by the 'signals' package
JavaScript
3
star
57

react-svg

MOXY'S base SVG component.
JavaScript
3
star
58

next-button

A react button that doubles down as a link.
JavaScript
3
star
59

jest-config

MOXY's Jest configuration to be used across several JavaScript projects
JavaScript
3
star
60

react-contentful-rich-text

A react component that transforms a contentful rich text structure to html.
JavaScript
3
star
61

react-animate-text

A react component that animates text per word and/or per line.
JavaScript
2
star
62

react-with-moxy-scripts

This package includes scripts and configuration used by react-with-moxy
2
star
63

create-next-routes

A CLI to manage Next.js routes
JavaScript
2
star
64

react-redata

React data container for isomorphic applications, providing a unified and performant load & reload pattern
JavaScript
2
star
65

react-circle

MOXY's circle animation component
JavaScript
2
star
66

next-webpack-oneof

Wraps all webpack loader rules into a single oneOf rule
JavaScript
2
star
67

rfcs-oss

RFCs for additions or changes to MOXY open-source projects
2
star
68

workshop-leveling-up-with-redux

Redux workshop composed by an introductory section, followed by some advanced aspects.
JavaScript
2
star
69

react-ellipsis

Moxy's base Ellipsis component.
JavaScript
1
star
70

react-app-rewire-external-svg-loader

Enables external-svg-loader for CRA apps using react-app-rewired
JavaScript
1
star
71

react-accordion

MOXY's base Accordion component.
JavaScript
1
star
72

next-with-router-ref

An alternative to Next.js withRouter HOC that supports refs by forwarding them
JavaScript
1
star
73

react-dropdown

A Dropdown component for React, based on react-select.
JavaScript
1
star
74

express-ensure-content-type

Express middleware that ensures requests match the specified content-type.
JavaScript
1
star
75

workshop-the-hitchhikers-guide-to-react

React workshop composed by an introductory section, followed by some advanced aspects.
JavaScript
1
star
76

redux-await-actions

Waits for specific actions to be dispatched or a timeout expires.
JavaScript
1
star