Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade EUI and use EuiProvider #50

Merged
merged 4 commits into from
Jan 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 2 additions & 24 deletions next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const iniparser = require('iniparser');

const withBundleAnalyzer = require('@next/bundle-analyzer');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const { IgnorePlugin, NormalModuleReplacementPlugin } = require('webpack');
const { IgnorePlugin } = require('webpack');

/**
* If you are deploying your site under a directory other than `/` e.g.
Expand Down Expand Up @@ -66,24 +66,14 @@ const nextConfig = {
}

return (context, callback) => {
if (
context.request.indexOf('@elastic/eui') > -1 ||
context.request.indexOf('react-ace') > -1
) {
if (context.request.indexOf('@elastic/eui') > -1) {
thompsongl marked this conversation as resolved.
Show resolved Hide resolved
return callback();
}

return eachExternal(context, callback);
};
});

// Replace `react-ace` with an empty module on the server.
// https://webpack.js.org/loaders/null-loader/
config.module.rules.push({
test: /react-ace/,
use: 'null-loader',
});

// Mock HTMLElement on the server-side
const definePluginId = config.plugins.findIndex(
p => p.constructor.name === 'DefinePlugin'
Expand All @@ -99,18 +89,6 @@ const nextConfig = {
config.plugins.push(
new CopyWebpackPlugin({ patterns: themeConfig.copyConfig }),

// We don't want to load all highlight.js language - provide a mechanism to register just some.
// If you need to highlight more than just JSON, edit the file below.
new NormalModuleReplacementPlugin(
/^highlight\.js$/,
path.join(__dirname, `src/lib/highlight.ts`)
),

new NormalModuleReplacementPlugin(
/^lowlight$/,
path.join(__dirname, `src/lib/lowlight.ts`)
),

// Moment ships with a large number of locales. Exclude them, leaving
// just the default English locale. If you need other locales, see:
// https://create-react-app.dev/docs/troubleshooting/#momentjs-locales-are-missing
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@
"dependencies": {},
"devDependencies": {
"@elastic/datemath": "^5.0.3",
"@elastic/eui": "^41.3.0",
"@elastic/eui": "^43.1.1",
"@emotion/cache": "^11.7.1",
"@emotion/react": "^11.7.1",
"@next/bundle-analyzer": "^12.0.4",
"@types/node": "^16.11.10",
"@typescript-eslint/eslint-plugin": "^5.5.0",
Expand Down
64 changes: 43 additions & 21 deletions src/components/chrome/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { FunctionComponent, useState } from 'react';
import { useRouter } from 'next/router';
import createCache from '@emotion/cache';

import {
EuiSideNav,
Expand All @@ -10,8 +11,11 @@ import {
EuiErrorBoundary,
EuiFlexGroup,
EuiFlexItem,
EuiProvider,
} from '@elastic/eui';

import { useProvider } from '../provider';

import { buildTopLinks } from '../navigation_links/top_links';
import { buildSolutionLinks } from '../navigation_links/solution_links';
import { buildExploreLinks } from '../navigation_links/explore_links';
Expand Down Expand Up @@ -60,6 +64,22 @@ const AppLogo: FunctionComponent<{ onClick: () => void }> = ({ onClick }) => (
*/
const Chrome: FunctionComponent = ({ children }) => {
const router = useRouter();
const { colorMode } = useProvider();

/**
* This `@emotion/cache` instance is used to insert the global styles
* into the correct location in `<head>`. Otherwise they would be
* inserted after the static CSS files, resulting in style clashes.
* Only necessary until EUI has converted all components to CSS-in-JS:
* https://github.com/elastic/eui/issues/3912
*/
const emotionCache = createCache({
thompsongl marked this conversation as resolved.
Show resolved Hide resolved
key: 'eui-styles',
container:
typeof document !== 'undefined'
? document.querySelector('meta[name="eui-styles-global"]')
: null,
});

const [isSideNavOpenOnMobile, setIsSideNavOpenOnMobile] = useState(false);

Expand All @@ -84,29 +104,31 @@ const Chrome: FunctionComponent = ({ children }) => {
];

return (
<EuiPage restrictWidth={1240} className={styles.guidePage}>
<EuiPageBody>
<EuiPageSideBar className={styles.guideSideNav}>
<AppLogo
onClick={() => {
setIsSideNavOpenOnMobile(false);
router.push('/');
}}
/>
<EuiErrorBoundary>
<EuiSideNav
className={styles.guideSideNav__content}
mobileTitle="Navigate"
toggleOpenOnMobile={toggleOpenOnMobile}
isOpenOnMobile={isSideNavOpenOnMobile}
items={sideNav}
<EuiProvider colorMode={colorMode} cache={emotionCache}>
<EuiPage restrictWidth={1240} className={styles.guidePage}>
<EuiPageBody>
<EuiPageSideBar className={styles.guideSideNav}>
<AppLogo
onClick={() => {
setIsSideNavOpenOnMobile(false);
router.push('/');
}}
/>
</EuiErrorBoundary>
</EuiPageSideBar>
<EuiErrorBoundary>
<EuiSideNav
className={styles.guideSideNav__content}
mobileTitle="Navigate"
toggleOpenOnMobile={toggleOpenOnMobile}
isOpenOnMobile={isSideNavOpenOnMobile}
items={sideNav}
/>
</EuiErrorBoundary>
</EuiPageSideBar>

<div className={styles.guidePageContent}>{children}</div>
</EuiPageBody>
</EuiPage>
<div className={styles.guidePageContent}>{children}</div>
</EuiPageBody>
</EuiPage>
</EuiProvider>
);
};

Expand Down
10 changes: 5 additions & 5 deletions src/components/chrome/theme_switcher.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,28 +7,28 @@ import {
EuiPopoverTitle,
} from '@elastic/eui';

import { setInitialTheme, setTheme, themeConfig } from '../../lib/theme';
import { useProvider } from '../provider';

const initialTheme = setInitialTheme();
import { setTheme, themeConfig } from '../../lib/theme';

/**
* Renders a dropdown menu for selecting the current theme. The selection
* is set in localStorage, so that it persists between visits.
*/
const ThemeSwitcher: FunctionComponent = () => {
const { colorMode, setColorMode } = useProvider();
const [isPopoverOpen, setPopoverOpen] = useState(false);
const [theme, setThemeInState] = useState(initialTheme);

const handleChangeTheme = (newTheme: string) => {
setPopoverOpen(false);
setColorMode(newTheme);
setTheme(newTheme);
setThemeInState(newTheme);
};

const items = themeConfig.availableThemes.map(each => (
<EuiContextMenuItem
key={each.id}
icon={each.id === theme ? 'check' : 'empty'}
icon={each.id === colorMode ? 'check' : 'empty'}
onClick={() => handleChangeTheme(each.id)}>
{each.name}
</EuiContextMenuItem>
Expand Down
32 changes: 32 additions & 0 deletions src/components/provider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React, {
FunctionComponent,
createContext,
useContext,
useState,
} from 'react';

import { setInitialTheme } from '../lib/theme';

/**
* React context for storing theme-related data and callbacks.
* `colorMode` is `light` or `dark` and will be consumed by
* various downstream components, including `EuiProvider`.
*/
export const GlobalProvider = createContext<{
thompsongl marked this conversation as resolved.
Show resolved Hide resolved
colorMode?: string;
setColorMode?: (colorMode: string) => void;
}>({});

export const Provider: FunctionComponent = ({ children }) => {
const initialTheme = setInitialTheme();
const [colorMode, setColorMode] = useState(initialTheme);
return (
<GlobalProvider.Provider value={{ colorMode, setColorMode }}>
{children}
</GlobalProvider.Provider>
);
};

export const useProvider = () => {
return useContext(GlobalProvider);
};
15 changes: 0 additions & 15 deletions src/lib/highlight.ts

This file was deleted.

15 changes: 0 additions & 15 deletions src/lib/lowlight.ts

This file was deleted.

1 change: 1 addition & 0 deletions src/lib/theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export function setTheme(newThemeName: string): void {
for (const themeLink of getAllThemes()) {
// Disable all theme links, except for the desired theme, which we enable
themeLink.disabled = themeLink.dataset.theme !== newThemeName;
themeLink['aria-disabled'] = themeLink.dataset.theme !== newThemeName;
}

// Add a class to the `body` element that indicates which theme we're using.
Expand Down
13 changes: 8 additions & 5 deletions src/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { EuiErrorBoundary } from '@elastic/eui';
import './app.scss';

import Chrome from '../components/chrome';
import { Provider } from '../components/provider';

/**
* Next.js uses the App component to initialize pages. You can override it
Expand All @@ -20,11 +21,13 @@ const EuiApp: FunctionComponent<AppProps> = ({ Component, pageProps }) => (
{/* You can override this in other pages - see page-2.tsx for an example */}
<title>Next.js EUI Starter</title>
</Head>
<Chrome>
<EuiErrorBoundary>
<Component {...pageProps} />
</EuiErrorBoundary>
</Chrome>
<Provider>
<Chrome>
<EuiErrorBoundary>
<Component {...pageProps} />
</EuiErrorBoundary>
</Chrome>
</Provider>
</>
);

Expand Down
5 changes: 4 additions & 1 deletion src/pages/_document.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,10 @@ export default class MyDocument extends Document {
render(): ReactElement {
return (
<Html lang="en">
<Head>{themeConfig.availableThemes.map(each => themeLink(each))}</Head>
<Head>
<meta name="eui-styles-global" />
{themeConfig.availableThemes.map(each => themeLink(each))}
</Head>
<body className="guideBody">
<Main />
<NextScript />
Expand Down
Loading