Skip to content

Commit

Permalink
Replace ThemeProvider with BasisProvider
Browse files Browse the repository at this point in the history
  • Loading branch information
moroshko committed Jan 17, 2020
1 parent 695f61f commit 8c31fc2
Show file tree
Hide file tree
Showing 15 changed files with 160 additions and 45 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@ npm install --save typeface-{montserrat,roboto}

```jsx
import React from "react";
import { ThemeProvider, defaultTheme, Text } from "basis";
import { BasisProvider, defaultTheme, Text } from "basis";
import "typeface-montserrat";
import "typeface-roboto";

function App() {
return (
<ThemeProvider theme={defaultTheme}>
<BasisProvider theme={defaultTheme}>
<Text>Hello World</Text>
</ThemeProvider>
</BasisProvider>
);
}

Expand Down
32 changes: 28 additions & 4 deletions src/components/Link.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import React from "react";
import React, { useContext } from "react";
import PropTypes from "prop-types";
import { LinkContext } from "../providers/LinkProvider";
import useTheme from "../hooks/useTheme";
import useContainer from "../hooks/useContainer";
import { responsiveMarginType } from "../hooks/useResponsiveProp";
import {
responsiveMarginType,
responsivePaddingType
} from "../hooks/useResponsiveProp";
import useResponsivePropsCSS from "../hooks/useResponsivePropsCSS";
import { responsiveMargin } from "../utils/css";
import { responsiveMargin, responsivePadding } from "../utils/css";

export const COLORS = [
"primary.blue.t100",
Expand All @@ -19,10 +23,12 @@ export const DEFAULT_PROPS = {
function Link(_props) {
const props = { ...DEFAULT_PROPS, ..._props };
const { href, newTab, children } = props;
const { InternalLink, isLinkInternal } = useContext(LinkContext);
const theme = useTheme();
const { linkColor } = useContainer();
const responsivePropsCSS = useResponsivePropsCSS(props, {
margin: responsiveMargin
margin: responsiveMargin,
padding: responsivePadding
});
const color =
!COLORS.includes(_props.color) && linkColor ? linkColor : props.color;
Expand All @@ -43,6 +49,23 @@ function Link(_props) {
}
: {};

if (!newTab && InternalLink && isLinkInternal(href)) {
/*
Note: We assume here that InternalLink respects the following contract:
- It gets a `className` prop, which gets applies to the rendered <a>.
- It gets a `to` prop, which gets mapped to <a>'s `href` prop.
- It gets a `children` prop, which gets rendered as <a>'s `children`.
Example: Gatsby `Link` component.
*/
return (
<InternalLink css={css} to={href}>
{children}
</InternalLink>
);
}

return (
<a css={css} href={href} {...newTabProps}>
{children}
Expand All @@ -52,6 +75,7 @@ function Link(_props) {

Link.propTypes = {
...responsiveMarginType,
...responsivePaddingType,
color: PropTypes.oneOf(COLORS),
href: PropTypes.string.isRequired,
newTab: PropTypes.bool.isRequired,
Expand Down
13 changes: 13 additions & 0 deletions src/components/Link.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,4 +95,17 @@ describe("Link", () => {
margin: 4px 8px 12px;
`);
});

it("with padding", () => {
const { getByText } = render(
<Link href="/terms" newTab={false} padding="3 6">
Terms and Conditions
</Link>
);
const link = getByText("Terms and Conditions");

expect(link).toHaveStyle(`
padding: 12px 24px;
`);
});
});
2 changes: 1 addition & 1 deletion src/hooks/useTheme.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useContext } from "react";
import { ThemeContext } from "../providers/ThemeProvider";
import { ThemeContext } from "../providers/BasisProvider";

function useTheme() {
const theme = useContext(ThemeContext);
Expand Down
2 changes: 1 addition & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export { default as designTokens } from "./themes/tokens";
export { default as defaultTheme } from "./themes/default";

// Providers
export { default as ThemeProvider } from "./providers/ThemeProvider";
export { default as BasisProvider } from "./providers/BasisProvider";

// Hooks
export { default as useTheme } from "./hooks/useTheme";
24 changes: 20 additions & 4 deletions src/providers/ThemeProvider.js → src/providers/BasisProvider.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,40 @@
import React, { useMemo } from "react";
import PropTypes from "prop-types";
import BreakpointProvider from "./BreakpointProvider";
import LinkProvider from "./LinkProvider";
import { enhanceTheme } from "../utils/theme";

export const ThemeContext = React.createContext();

function ThemeProvider({ theme, window, children }) {
function BasisProvider({
theme,
window,
InternalLink,
isLinkInternal,
children
}) {
const enhancedTheme = useMemo(() => enhanceTheme(theme), [theme]);

return (
<ThemeContext.Provider value={enhancedTheme}>
<BreakpointProvider window={window}>{children}</BreakpointProvider>
<BreakpointProvider window={window}>
<LinkProvider
InternalLink={InternalLink}
isLinkInternal={isLinkInternal}
>
{children}
</LinkProvider>
</BreakpointProvider>
</ThemeContext.Provider>
);
}

ThemeProvider.propTypes = {
BasisProvider.propTypes = {
theme: PropTypes.object.isRequired,
window: PropTypes.object,
InternalLink: PropTypes.elementType,
isLinkInternal: PropTypes.func,
children: PropTypes.node.isRequired
};

export default ThemeProvider;
export default BasisProvider;
29 changes: 29 additions & 0 deletions src/providers/LinkProvider.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from "react";
import PropTypes from "prop-types";

export const LinkContext = React.createContext();

// See: https://www.gatsbyjs.org/docs/gatsby-link/#reminder-use-link-only-for-internal-links
function defaultIsLinkInternal(href) {
return /^\/(?!\/)/.test(href);
}

function LinkProvider({
InternalLink,
isLinkInternal = defaultIsLinkInternal,
children
}) {
return (
<LinkContext.Provider value={{ InternalLink, isLinkInternal }}>
{children}
</LinkContext.Provider>
);
}

LinkProvider.propTypes = {
InternalLink: PropTypes.elementType,
isLinkInternal: PropTypes.func,
children: PropTypes.node.isRequired
};

export default LinkProvider;
4 changes: 2 additions & 2 deletions src/utils/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import React from "react";
import PropTypes from "prop-types";
import { render } from "@testing-library/react";
import matchMediaPolyfill from "mq-polyfill";
import { ThemeProvider, defaultTheme } from "..";
import { BasisProvider, defaultTheme } from "..";

matchMediaPolyfill(global);

export function TestWrapper({ children }) {
return <ThemeProvider theme={defaultTheme}>{children}</ThemeProvider>;
return <BasisProvider theme={defaultTheme}>{children}</BasisProvider>;
}

TestWrapper.propTypes = {
Expand Down
6 changes: 3 additions & 3 deletions website/src/components/ComponentPreview.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import Frame, { FrameContextConsumer } from "react-frame-component";
import weakMemoize from "@emotion/weak-memoize";
import createCache from "@emotion/cache";
import { CacheProvider, Global } from "@emotion/core";
import { ThemeProvider, defaultTheme } from "basis";
import { BasisProvider, defaultTheme } from "basis";
import CacheProviderWithContainer from "./CacheProviderWithContainer";
import "typeface-montserrat";
import "typeface-roboto";
Expand Down Expand Up @@ -57,7 +57,7 @@ function ComponentPreview({ iframeTitle = "Preview", hasBodyMargin = true }) {
return (
<CacheProvider value={cache}>
<CacheProviderWithContainer container={document.head}>
<ThemeProvider theme={defaultTheme} window={window}>
<BasisProvider theme={defaultTheme} window={window}>
{!hasBodyMargin && (
<Global
styles={{
Expand All @@ -68,7 +68,7 @@ function ComponentPreview({ iframeTitle = "Preview", hasBodyMargin = true }) {
/>
)}
<LivePreview />
</ThemeProvider>
</BasisProvider>
</CacheProviderWithContainer>
</CacheProvider>
);
Expand Down
40 changes: 20 additions & 20 deletions website/src/layouts/Page.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import React from "react";
import PropTypes from "prop-types";
import { Link } from "gatsby";
import { Location } from "@reach/router";
import { Global } from "@emotion/core";
import { Link as GatsbyLink } from "gatsby";
import { COMPONENT_STATUS } from "../utils/constants";
import SEO from "../components/SEO";
import Sidebar from "../components/Sidebar";
import ComponentStatusIndicator from "../components/ComponentStatusIndicator";
import { Text, Container, designTokens, ThemeProvider } from "basis";
import { BasisProvider, designTokens, Container, Text, Link } from "basis";
import { getTabsUrls } from "../utils/url";
import websiteTheme from "../themes/website";
import "typeface-montserrat";
Expand All @@ -18,14 +18,14 @@ function Page({ pageContext, children }) {
const title = header ? `${header} | Basis` : "Basis";

return (
<ThemeProvider theme={websiteTheme}>
<BasisProvider theme={websiteTheme} InternalLink={GatsbyLink}>
<Global
styles={{
body: {
margin: 0,
fontFamily: designTokens.fonts.body,
fontSize: designTokens.fontSizes[1],
lineHeight: designTokens.lineHeights[0],
lineHeight: designTokens.lineHeights[2],
color: designTokens.colors.black
},
a: {
Expand Down Expand Up @@ -57,14 +57,13 @@ function Page({ pageContext, children }) {
{header && (
<div
css={{
padding: `${designTokens.space[5]} ${designTokens.space[6]} 0`,
borderBottom: `1px solid ${designTokens.colors.grey.t16}`
}}
>
<div
css={{
display: "flex",
height: designTokens.space[5]
padding: `${designTokens.space[5]} ${designTokens.space[6]} 0`
}}
>
<Text intent="h1" size="4">
Expand All @@ -84,31 +83,32 @@ function Page({ pageContext, children }) {
<ul
css={{
display: "flex",
margin: `${designTokens.space[10]} 0 0`,
margin: `${designTokens.space[6]} 0 0`,
padding: 0
}}
>
{urls.map(({ name, to, isCurrent }, index) => (
{urls.map(({ name, href, isCurrent }) => (
<li
css={{
listStyleType: "none",
marginLeft:
index === 0 ? 0 : designTokens.space[8],
paddingBottom: designTokens.space[2],
color: isCurrent
? designTokens.colors.black
: designTokens.colors.grey.t65,
borderBottom: isCurrent
? `${designTokens.borderWidths[1]} solid ${designTokens.colors.black}`
: 0
...(isCurrent && {
"::after": {
content: "''",
display: "block",
height: designTokens.borderWidths[1],
margin: `0 ${designTokens.space[6]}`,
backgroundColor: designTokens.colors.black
}
})
}}
key={name}
>
{to ? (
<Link to={to}>{name}</Link>
) : (
<a title="Coming soon">{name}</a>
)}
<Link href={href} newTab={false} padding="2 6">
{name}
</Link>
</li>
))}
</ul>
Expand All @@ -131,7 +131,7 @@ function Page({ pageContext, children }) {
</main>
</div>
)}
</ThemeProvider>
</BasisProvider>
);
}

Expand Down
7 changes: 4 additions & 3 deletions website/src/layouts/Resources.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import React from "react";
import PropTypes from "prop-types";
import { MDXProvider } from "@mdx-js/react";
import { Link as GatsbyLink } from "gatsby";
import * as allDesignSystem from "basis";

const { ThemeProvider, defaultTheme, Container } = allDesignSystem;
const { BasisProvider, defaultTheme, Container } = allDesignSystem;

function Resources({ children }) {
return (
<ThemeProvider theme={defaultTheme}>
<BasisProvider theme={defaultTheme} InternalLink={GatsbyLink}>
<MDXProvider components={allDesignSystem}>
<Container padding="3 6">{children}</Container>
</MDXProvider>
</ThemeProvider>
</BasisProvider>
);
}

Expand Down
7 changes: 4 additions & 3 deletions website/src/layouts/Usage.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import React from "react";
import PropTypes from "prop-types";
import { MDXProvider } from "@mdx-js/react";
import { Link as GatsbyLink } from "gatsby";
import * as allDesignSystem from "basis";

const { ThemeProvider, defaultTheme, Container } = allDesignSystem;
const { BasisProvider, defaultTheme, Container } = allDesignSystem;

function Usage({ children }) {
return (
<ThemeProvider theme={defaultTheme}>
<BasisProvider theme={defaultTheme} InternalLink={GatsbyLink}>
<MDXProvider components={allDesignSystem}>
<Container padding="3 6">{children}</Container>
</MDXProvider>
</ThemeProvider>
</BasisProvider>
);
}

Expand Down
2 changes: 2 additions & 0 deletions website/src/themes/website/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ import { defaultTheme } from "basis";
import button from "./button";
import field from "./field";
import input from "./input";
import link from "./link";
import select from "./select";

const websiteTheme = {
...defaultTheme,
...button,
...field,
...input,
...link,
...select
};

Expand Down
Loading

0 comments on commit 8c31fc2

Please sign in to comment.