Make docs use the latest (bleeding edge) of the components by importing them directly.tags/0.3.0
@@ -66,6 +66,4 @@ typings/ | |||||
.env | .env | ||||
.next | .next | ||||
dist/ | dist/ | ||||
.gitignore | |||||
.docz/ | |||||
/docz.config.js | |||||
.next/ |
@@ -1,91 +0,0 @@ | |||||
# Tesseract Web - React Common | |||||
Common front-end components for Web using the [Tesseract design system](https://make.modal.sh/tesseract/design), written for [React](https://reactjs.org). | |||||
Package: | |||||
[![@tesseract-design/react-common](https://code.modal.sh/badge?repo=tesseract-design/react-common&type=package&color=C78AB3&kind=name)](https://js.pack.modal.sh/-/web/detail/@tesseract-design/react-common) | |||||
[![@tesseract-design/react-common](https://code.modal.sh/badge?repo=tesseract-design/react-common&type=package&color=C78AB3&kind=version)](https://js.pack.modal.sh/-/web/detail/@tesseract-design/react-common#versions) | |||||
Dependencies: | |||||
[![React](https://code.modal.sh/badge?repo=tesseract-design/react-common&type=dependency&dependency=react&kind=peerDependencies)](https://github.com/facebook/react) | |||||
[![Styled Components](https://code.modal.sh/badge?repo=tesseract-design/react-common&type=dependency&dependency=styled-components&kind=peerDependencies)](https://github.com/styled-components/styled-components) | |||||
[![TypeScript](https://code.modal.sh/badge?repo=tesseract-design/react-common&type=dependency&dependency=typescript&kind=devDependencies)](https://github.com/microsoft/typescript) | |||||
[![Jest](https://code.modal.sh/badge?repo=tesseract-design/react-common&type=dependency&dependency=jest&kind=devDependencies)](https://github.com/facebook/jest) | |||||
[![Rollup](https://code.modal.sh/badge?repo=tesseract-design/react-common&type=dependency&dependency=rollup&kind=devDependencies)](https://github.com/rollup/rollup) | |||||
## Installation | |||||
Since this package resides in the [Modal.sh JavaScript Package Registry](https://js.pack.modal.sh/), you may need to | |||||
adjust configuration in your chosen package manager. | |||||
With [Yarn](https://yarnpkg.com), add this to your `.yarnrc` file: | |||||
``` | |||||
"@tesseract-design:registry" "https://js.pack.modal.sh/" | |||||
``` | |||||
Then, install the package by running the following command: | |||||
```shell script | |||||
yarn add @tesseract-design/react-common | |||||
``` | |||||
## Usage | |||||
The package includes components as named exports. Simply import the components you need individually or use a namespace | |||||
import, like so: | |||||
```jsx harmony | |||||
import * as React from 'react' | |||||
import ReactDOM from 'react-dom' | |||||
import * as T from '@tesseract-design/react-common' | |||||
const LoginForm = etcProps => ( | |||||
<form | |||||
{...etcProps} | |||||
> | |||||
<fieldset> | |||||
<legend> | |||||
Log In | |||||
</legend> | |||||
<div> | |||||
<T.TextInput | |||||
block | |||||
label="Username" | |||||
/> | |||||
</div> | |||||
<div> | |||||
<T.TextInput | |||||
block | |||||
type="password" | |||||
label="Password" | |||||
/> | |||||
</div> | |||||
<div> | |||||
<T.Button> | |||||
Log In | |||||
</T.Button> | |||||
</div> | |||||
</fieldset> | |||||
</form> | |||||
) | |||||
const mountNode = window.document.createElement('div') | |||||
ReactDOM.render( | |||||
<LoginForm />, | |||||
mountNode, | |||||
) | |||||
window.document.body.appendChild(mountNode) | |||||
``` | |||||
Detailed usage guides can be found in the [Tesseract Design - React Common documentation](https://make.modal.sh/tesseract/web/react/common). | |||||
## TypeScript | |||||
The package is written and tested using TypeScript. Thus, typings for consumption in TypeScript are bundled with the | |||||
compiled source. | |||||
@@ -0,0 +1 @@ | |||||
packages/react-common-docs/src/pages/index.md |
@@ -12,6 +12,8 @@ | |||||
"license": "MIT", | "license": "MIT", | ||||
"private": false, | "private": false, | ||||
"devDependencies": { | "devDependencies": { | ||||
"@babel/runtime": "^7.12.5", | |||||
"@reach/slider": "^0.10.5", | |||||
"@rollup/plugin-typescript": "^5.0.2", | "@rollup/plugin-typescript": "^5.0.2", | ||||
"@types/enzyme": "^3.10.5", | "@types/enzyme": "^3.10.5", | ||||
"@types/enzyme-adapter-react-16": "^1.0.6", | "@types/enzyme-adapter-react-16": "^1.0.6", | ||||
@@ -29,23 +31,20 @@ | |||||
"jest-axe": "3.4.0", | "jest-axe": "3.4.0", | ||||
"jest-enzyme": "7.1.2", | "jest-enzyme": "7.1.2", | ||||
"jest-extended": "0.11.5", | "jest-extended": "0.11.5", | ||||
"pascal-case": "3.1.1", | |||||
"plop": "2.6.0", | "plop": "2.6.0", | ||||
"prettier": "1.19.1", | "prettier": "1.19.1", | ||||
"react-is": "^16.13.1", | |||||
"prop-types": "15.7.2", | |||||
"react": "16.13.1", | |||||
"react-dom": "16.13.1", | |||||
"react-feather": "2.0.3", | |||||
"rollup": "^2.23.0", | "rollup": "^2.23.0", | ||||
"rollup-plugin-peer-deps-external": "2.2.2", | "rollup-plugin-peer-deps-external": "2.2.2", | ||||
"rollup-plugin-terser": "5.3.0", | "rollup-plugin-terser": "5.3.0", | ||||
"styled-components": "5.1.0", | |||||
"ts-jest": "^26.1.3", | "ts-jest": "^26.1.3", | ||||
"tslib": "^2.0.0", | "tslib": "^2.0.0", | ||||
"typescript": "^3.9.7", | |||||
"@reach/slider": "^0.10.5", | |||||
"docz": "^2.3.1", | |||||
"pascal-case": "3.1.1", | |||||
"prop-types": "15.7.2", | |||||
"react": "16.13.1", | |||||
"react-dom": "16.13.1", | |||||
"react-feather": "2.0.3", | |||||
"styled-components": "5.1.0" | |||||
"typescript": "^3.9.7" | |||||
}, | }, | ||||
"scripts": { | "scripts": { | ||||
"prepublishOnly": "NODE_ENV=production rm -rf dist/ && rollup -c", | "prepublishOnly": "NODE_ENV=production rm -rf dist/ && rollup -c", | ||||
@@ -64,5 +63,6 @@ | |||||
"react-feather": "2.0.3", | "react-feather": "2.0.3", | ||||
"styled-components": "5.1.0" | "styled-components": "5.1.0" | ||||
}, | }, | ||||
"homepage": "https://make.modal.sh/tesseract/web/react/common" | |||||
"homepage": "https://make.modal.sh/tesseract/web/react/common", | |||||
"dependencies": {} | |||||
} | } |
@@ -1,30 +0,0 @@ | |||||
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). | |||||
## Getting Started | |||||
First, run the development server: | |||||
```bash | |||||
npm run dev | |||||
# or | |||||
yarn dev | |||||
``` | |||||
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. | |||||
You can start editing the page by modifying `pages/index.js`. The page auto-updates as you edit the file. | |||||
## Learn More | |||||
To learn more about Next.js, take a look at the following resources: | |||||
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. | |||||
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. | |||||
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! | |||||
## Deploy on Vercel | |||||
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/import?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. | |||||
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. |
@@ -1,9 +1,40 @@ | |||||
const Brand = () => ( | |||||
<div> | |||||
<strong> | |||||
Tesseract | |||||
</strong> | |||||
</div> | |||||
) | |||||
import * as React from 'react' | |||||
import styled from 'styled-components' | |||||
import pkg from '../../package.json' | |||||
const Base = styled('div')({ | |||||
position: 'relative', | |||||
}) | |||||
const Title = styled('strong')({ | |||||
fontSize: '2rem', | |||||
fontFamily: 'var(--font-family-headings), sans-serif', | |||||
fontWeight: 'var(--font-weight-headings, 400)', | |||||
lineHeight: 'var(--line-height-headings, 1.5)', | |||||
fontStretch: 'var(--font-stretch-headings, normal)', | |||||
textTransform: 'lowercase', | |||||
whiteSpace: 'nowrap', | |||||
}) | |||||
const Subtitle = styled('small')({ | |||||
position: 'absolute', | |||||
bottom: '-1em', | |||||
right: 0, | |||||
fontWeight: 'bolder', | |||||
}) | |||||
const Brand = () => { | |||||
const name = pkg.name.includes('@') ? pkg.name.split('/')[1] : pkg.name | |||||
return ( | |||||
<Base> | |||||
<Title> | |||||
{name} | |||||
</Title> | |||||
<Subtitle> | |||||
v.{pkg.version} | |||||
</Subtitle> | |||||
</Base> | |||||
) | |||||
} | |||||
export default Brand | export default Brand |
@@ -1,6 +1,25 @@ | |||||
const path = require('path') | |||||
const withMDX = require('next-mdx-frontmatter')({ | const withMDX = require('next-mdx-frontmatter')({ | ||||
extension: /\.mdx?$/ | extension: /\.mdx?$/ | ||||
}) | }) | ||||
module.exports = withMDX({ | |||||
const e = withMDX({ | |||||
pageExtensions: ['js', 'jsx', 'ts', 'tsx', 'md', 'mdx'] | pageExtensions: ['js', 'jsx', 'ts', 'tsx', 'md', 'mdx'] | ||||
}) | }) | ||||
module.exports = { | |||||
...e, | |||||
webpack(...args) { | |||||
const oldWebpack = e.webpack(...args) | |||||
const [config, { defaultLoaders, }] = args | |||||
config.module.rules.push({ | |||||
test: /\.(ts|tsx)$/, | |||||
include: [path.resolve(__dirname, '../react-common/')], | |||||
use: [defaultLoaders.babel], | |||||
}) | |||||
return oldWebpack | |||||
} | |||||
} |
@@ -3,14 +3,16 @@ | |||||
"version": "0.1.0", | "version": "0.1.0", | ||||
"private": true, | "private": true, | ||||
"scripts": { | "scripts": { | ||||
"predev": "./scripts/docgen", | |||||
"dev": "next dev", | "dev": "next dev", | ||||
"prebuild": "./scripts/docgen", | |||||
"build": "next build", | "build": "next build", | ||||
"prestart": "./scripts/docgen", | |||||
"start": "next start", | "start": "next start", | ||||
"docgen": "node scripts/docgen.js" | |||||
"docgen": "./scripts/docgen" | |||||
}, | }, | ||||
"dependencies": { | "dependencies": { | ||||
"@mdx-js/loader": "^1.6.19", | "@mdx-js/loader": "^1.6.19", | ||||
"@tesseract-design/react-common": "^0.2.1", | |||||
"next": "10.0.1", | "next": "10.0.1", | ||||
"next-mdx-frontmatter": "^0.0.3", | "next-mdx-frontmatter": "^0.0.3", | ||||
"pascal-case": "^3.1.1", | "pascal-case": "^3.1.1", | ||||
@@ -78,6 +78,9 @@ | |||||
font-stretch: var(--font-stretch-base, normal); | font-stretch: var(--font-stretch-base, normal); | ||||
font-weight: var(--font-weight-base, 400); | font-weight: var(--font-weight-base, 400); | ||||
line-height: var(--line-height-base, 2); | line-height: var(--line-height-base, 2); | ||||
transition-property: color, background-color; | |||||
transition-timing-function: ease; | |||||
transition-duration: 350ms; | |||||
} | } | ||||
h1 { | h1 { | ||||
@@ -1,3 +1,5 @@ | |||||
#!/usr/bin/env node | |||||
const docgen = require('react-docgen-typescript') | const docgen = require('react-docgen-typescript') | ||||
const path = require('path') | const path = require('path') | ||||
const fs = require('fs') | const fs = require('fs') |
@@ -1,7 +1,7 @@ | |||||
import * as React from 'react' | import * as React from 'react' | ||||
import * as PropTypes from 'prop-types' | import * as PropTypes from 'prop-types' | ||||
import styled from 'styled-components' | import styled from 'styled-components' | ||||
import { Icon } from '@tesseract-design/react-common' | |||||
import { Icon } from '../../../../react-common/src' | |||||
const Image = styled('img')({ | const Image = styled('img')({ | ||||
display: 'block', | display: 'block', | ||||
@@ -16,7 +16,7 @@ const Container = styled('span')({ | |||||
margin: '0 0 0 auto', | margin: '0 0 0 auto', | ||||
boxSizing: 'border-box', | boxSizing: 'border-box', | ||||
'@media (min-width: 720px)': { | '@media (min-width: 720px)': { | ||||
maxWidth: 360, | |||||
maxWidth: 'var(--max-width)', | |||||
}, | }, | ||||
}) | }) | ||||
@@ -1,7 +1,7 @@ | |||||
import * as React from 'react' | import * as React from 'react' | ||||
import * as PropTypes from 'prop-types' | import * as PropTypes from 'prop-types' | ||||
import styled from 'styled-components' | import styled from 'styled-components' | ||||
import { Icon } from '@tesseract-design/react-common' | |||||
import { Icon } from '../../../../react-common/src' | |||||
import MenuGraphics, { propTypes as menuGraphicsPropTypes } from '../MenuGraphics/MenuGraphics' | import MenuGraphics, { propTypes as menuGraphicsPropTypes } from '../MenuGraphics/MenuGraphics' | ||||
const Link = styled('a')({ | const Link = styled('a')({ | ||||
@@ -1,12 +1,15 @@ | |||||
import { Icon } from '../../../../react-common/src' | |||||
import pkg from '../../../../../package.json' | |||||
import styled from 'styled-components' | import styled from 'styled-components' | ||||
import Nav from '../Nav/Nav' | |||||
import Link from 'next/link' | import Link from 'next/link' | ||||
import * as React from 'react' | import * as React from 'react' | ||||
import Nav from '../Nav/Nav' | |||||
const StyledLink = styled('a')({ | const StyledLink = styled('a')({ | ||||
display: 'block', | display: 'block', | ||||
textDecoration: 'none', | textDecoration: 'none', | ||||
marginBottom: '2rem', | |||||
marginTop: '3rem', | |||||
marginBottom: '3rem', | |||||
}) | }) | ||||
const Container = styled('span')({ | const Container = styled('span')({ | ||||
@@ -17,11 +20,12 @@ const Container = styled('span')({ | |||||
margin: '0 0 0 auto', | margin: '0 0 0 auto', | ||||
boxSizing: 'border-box', | boxSizing: 'border-box', | ||||
'@media (min-width: 720px)': { | '@media (min-width: 720px)': { | ||||
maxWidth: 360, | |||||
maxWidth: 'var(--max-width)', | |||||
}, | }, | ||||
}) | }) | ||||
const Base = styled('aside')({ | const Base = styled('aside')({ | ||||
'--max-width': 240, | |||||
position: 'fixed', | position: 'fixed', | ||||
top: 0, | top: 0, | ||||
left: '-100%', | left: '-100%', | ||||
@@ -29,55 +33,96 @@ const Base = styled('aside')({ | |||||
height: '100%', | height: '100%', | ||||
backgroundColor: 'var(--color-bg)', | backgroundColor: 'var(--color-bg)', | ||||
zIndex: 4, | zIndex: 4, | ||||
transitionProperty: 'color, background-color', | |||||
transitionTimingFunction: 'ease', | |||||
transitionDuration: '350ms', | |||||
'@media (min-width: 720px)': { | '@media (min-width: 720px)': { | ||||
left: 0, | left: 0, | ||||
width: `${100 / 3}%`, | |||||
width: `${100 / 4}%`, | |||||
maxWidth: 'none', | maxWidth: 'none', | ||||
height: '100%', | height: '100%', | ||||
'+ *': { | '+ *': { | ||||
paddingLeft: `${100 / 3}%`, | |||||
paddingLeft: `${100 / 4}%`, | |||||
boxSizing: 'border-box', | boxSizing: 'border-box', | ||||
}, | }, | ||||
}, | }, | ||||
}) | }) | ||||
const Actions = styled('div')({ | |||||
marginBottom: '4rem', | |||||
display: 'flex', | |||||
gap: '1rem', | |||||
alignItems: 'center', | |||||
}) | |||||
const ToggleWrapper = styled('label')({ | |||||
cursor: 'pointer', | |||||
color: 'var(--color-accent)', | |||||
display: 'inline-block', | |||||
}) | |||||
const ToggleIcon = styled('span')({ | |||||
}) | |||||
const ToggleInput = styled('input')({ | |||||
position: 'absolute', | |||||
left: -999999, | |||||
}) | |||||
const NavWrapper = styled('nav')({ | const NavWrapper = styled('nav')({ | ||||
'--size-link': '3rem', | '--size-link': '3rem', | ||||
}) | }) | ||||
const RepoLink = styled('a')({ | |||||
display: 'inline-grid', | |||||
width: '1.5rem', | |||||
height: '1.5rem', | |||||
placeContent: 'center', | |||||
}) | |||||
const Sidebar = ({ | const Sidebar = ({ | ||||
data, | data, | ||||
brand: Brand, | brand: Brand, | ||||
initialTheme = 'Dark', | |||||
}) => { | }) => { | ||||
const [dark, setDark] = React.useState(false) | |||||
const toggleDarkMode = (b: boolean) => () => { | |||||
setDark(b) | |||||
const [theme, setTheme] = React.useState(initialTheme) | |||||
const toggleDarkMode = (b: string) => () => { | |||||
setTheme(b) | |||||
} | } | ||||
React.useEffect(() => { | React.useEffect(() => { | ||||
const stylesheets = Array.from(window.document.querySelectorAll('link[title]')) | |||||
let storageTheme = window.localStorage.getItem('tesseract-theme') | |||||
|| ( | |||||
window.matchMedia('(prefers-color-scheme: dark)').matches | |||||
? 'Dark' | |||||
: 'Light' | |||||
) | |||||
window.localStorage.setItem('tesseract-theme', storageTheme) | |||||
setTimeout(() => { | |||||
setTheme(storageTheme) | |||||
}) | |||||
}, []) | |||||
React.useEffect(() => { | |||||
window.localStorage.setItem('tesseract-theme', theme) | |||||
}, [theme]) | |||||
React.useEffect(() => { | |||||
const stylesheets = Array.from(window.document.querySelectorAll('link[title]')) as HTMLLinkElement[] | |||||
stylesheets.forEach(s => { | stylesheets.forEach(s => { | ||||
if (s.getAttribute('rel').includes('alternate')) { | |||||
s.setAttribute('rel', 'stylesheet') | |||||
const enabled = s.title === theme | |||||
s.setAttribute('rel', enabled ? 'stylesheet' : 'alternate stylesheet') | |||||
if (enabled) { | |||||
s.removeAttribute('disabled') | s.removeAttribute('disabled') | ||||
} else { | } else { | ||||
s.setAttribute('rel', 'alternate stylesheet') | |||||
s.setAttribute('disabled', 'disabled') | s.setAttribute('disabled', 'disabled') | ||||
} | } | ||||
}) | }) | ||||
}, [dark]) | |||||
}, [theme]) | |||||
return ( | return ( | ||||
<Base> | <Base> | ||||
<Container> | |||||
<input | |||||
type="checkbox" | |||||
defaultChecked={dark} | |||||
onChange={toggleDarkMode(!dark)} | |||||
/> | |||||
</Container> | |||||
<NavWrapper> | <NavWrapper> | ||||
<Link | <Link | ||||
href="/" | href="/" | ||||
@@ -89,6 +134,47 @@ const Sidebar = ({ | |||||
</Container> | </Container> | ||||
</StyledLink> | </StyledLink> | ||||
</Link> | </Link> | ||||
<Container> | |||||
<Actions> | |||||
<ToggleWrapper> | |||||
<ToggleInput | |||||
type="checkbox" | |||||
defaultChecked={theme === 'Dark'} | |||||
onChange={toggleDarkMode(theme === 'Dark' ? 'Light' : 'Dark')} | |||||
/> | |||||
<ToggleIcon> | |||||
{ | |||||
theme === 'Dark' | |||||
&& ( | |||||
<Icon | |||||
label="Set Light Mode" | |||||
name="moon" | |||||
/> | |||||
) | |||||
} | |||||
{ | |||||
theme === 'Light' | |||||
&& ( | |||||
<Icon | |||||
label="Set Dark Mode" | |||||
name="sun" | |||||
/> | |||||
) | |||||
} | |||||
</ToggleIcon> | |||||
</ToggleWrapper> | |||||
<RepoLink | |||||
href={pkg.repository} | |||||
target="_blank" | |||||
rel="noopener noreferer" | |||||
> | |||||
<Icon | |||||
name="code" | |||||
label="Visit Repository" | |||||
/> | |||||
</RepoLink> | |||||
</Actions> | |||||
</Container> | |||||
<Nav | <Nav | ||||
data={data.nav} | data={data.nav} | ||||
/> | /> | ||||
@@ -677,6 +677,17 @@ | |||||
"type": { | "type": { | ||||
"name": "number" | "name": "number" | ||||
} | } | ||||
}, | |||||
"alternate": { | |||||
"defaultValue": { | |||||
"value": false | |||||
}, | |||||
"description": "Should the component be displayed with an alternate appearance?", | |||||
"name": "alternate", | |||||
"required": false, | |||||
"type": { | |||||
"name": "boolean" | |||||
} | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -1,3 +1,4 @@ | |||||
import * as React from 'react' | |||||
import styled from 'styled-components' | import styled from 'styled-components' | ||||
import sidebar from '../sidebar.json' | import sidebar from '../sidebar.json' | ||||
import brand from '../../brand' | import brand from '../../brand' | ||||
@@ -12,11 +13,16 @@ const Container = styled('div')({ | |||||
boxSizing: 'border-box', | boxSizing: 'border-box', | ||||
}) | }) | ||||
const App = ({ | |||||
type AppProps = { | |||||
Component: React.ElementType, | |||||
pageProps: Record<string, unknown>, | |||||
} | |||||
const App: React.FC<AppProps> = ({ | |||||
Component, | Component, | ||||
pageProps, | pageProps, | ||||
}) => ( | }) => ( | ||||
<div> | |||||
<React.Fragment> | |||||
<Sidebar | <Sidebar | ||||
brand={brand} | brand={brand} | ||||
data={sidebar} | data={sidebar} | ||||
@@ -28,7 +34,7 @@ const App = ({ | |||||
/> | /> | ||||
</Container> | </Container> | ||||
</main> | </main> | ||||
</div> | |||||
</React.Fragment> | |||||
) | ) | ||||
export default App | export default App |
@@ -2,7 +2,7 @@ | |||||
title: Button | title: Button | ||||
--- | --- | ||||
import { Button } from '@tesseract-design/react-common' | |||||
import { Button } from '../../../../react-common/src' | |||||
import Playground from '../../components/Playground/Playground' | import Playground from '../../components/Playground/Playground' | ||||
import Props from '../../components/Props/Props' | import Props from '../../components/Props/Props' | ||||
import Header from '../../components/Header/Header' | import Header from '../../components/Header/Header' | ||||
@@ -2,7 +2,7 @@ | |||||
name: Checkbox | name: Checkbox | ||||
--- | --- | ||||
import { Checkbox } from '@tesseract-design/react-common' | |||||
import { Checkbox } from '../../../../react-common/src' | |||||
import Playground from '../../components/Playground/Playground' | import Playground from '../../components/Playground/Playground' | ||||
import Props from '../../components/Props/Props' | import Props from '../../components/Props/Props' | ||||
import Header from '../../components/Header/Header' | import Header from '../../components/Header/Header' | ||||
@@ -2,7 +2,7 @@ | |||||
name: Icon | name: Icon | ||||
--- | --- | ||||
import { Icon } from '@tesseract-design/react-common' | |||||
import { Icon } from '../../../../react-common/src' | |||||
import Playground from '../../components/Playground/Playground' | import Playground from '../../components/Playground/Playground' | ||||
import Props from '../../components/Props/Props' | import Props from '../../components/Props/Props' | ||||
import Header from '../../components/Header/Header' | import Header from '../../components/Header/Header' | ||||
@@ -2,7 +2,7 @@ | |||||
name: RadioButton | name: RadioButton | ||||
--- | --- | ||||
import { RadioButton } from '@tesseract-design/react-common' | |||||
import { RadioButton } from '../../../../react-common/src' | |||||
import Playground from '../../components/Playground/Playground' | import Playground from '../../components/Playground/Playground' | ||||
import Props from '../../components/Props/Props' | import Props from '../../components/Props/Props' | ||||
import Header from '../../components/Header/Header' | import Header from '../../components/Header/Header' | ||||
@@ -2,7 +2,7 @@ | |||||
name: Select | name: Select | ||||
--- | --- | ||||
import { Select } from '@tesseract-design/react-common' | |||||
import { Select } from '../../../../react-common/src' | |||||
import Playground from '../../components/Playground/Playground' | import Playground from '../../components/Playground/Playground' | ||||
import Props from '../../components/Props/Props' | import Props from '../../components/Props/Props' | ||||
import Header from '../../components/Header/Header' | import Header from '../../components/Header/Header' | ||||
@@ -2,7 +2,7 @@ | |||||
name: Slider | name: Slider | ||||
--- | --- | ||||
import { Slider } from '@tesseract-design/react-common' | |||||
import { Slider } from '../../../../react-common/src' | |||||
import Playground from '../../components/Playground/Playground' | import Playground from '../../components/Playground/Playground' | ||||
import Props from '../../components/Props/Props' | import Props from '../../components/Props/Props' | ||||
import Header from '../../components/Header/Header' | import Header from '../../components/Header/Header' | ||||
@@ -2,7 +2,7 @@ | |||||
name: TextInput | name: TextInput | ||||
--- | --- | ||||
import { TextInput } from '@tesseract-design/react-common' | |||||
import { TextInput } from '../../../../react-common/src' | |||||
import Playground from '../../components/Playground/Playground' | import Playground from '../../components/Playground/Playground' | ||||
import Props from '../../components/Props/Props' | import Props from '../../components/Props/Props' | ||||
import Header from '../../components/Header/Header' | import Header from '../../components/Header/Header' | ||||
@@ -12,7 +12,11 @@ import Header from '../../components/Header/Header' | |||||
<Playground | <Playground | ||||
components={{ TextInput }} | components={{ TextInput }} | ||||
code={` | code={` | ||||
<TextInput label="Username" placeholder="johndoe" hint="the name you use to log in" /> | |||||
<TextInput | |||||
label="Username" | |||||
placeholder="johndoe" | |||||
hint="the name you use to log in" | |||||
/> | |||||
`} | `} | ||||
/> | /> | ||||
@@ -34,7 +38,7 @@ act as guide to the user on how long the expected input values are. | |||||
components={{ TextInput }} | components={{ TextInput }} | ||||
code={` | code={` | ||||
<form> | <form> | ||||
I am <span style={{ display: 'inline-block', width: '16rem', verticalAlign: 'middle', }}><TextInput label="Full name" border hint="given and family name" /></span> and I live in <span style={{ display: 'inline-block', width: '24rem', verticalAlign: 'middle', }}><TextInput border label="Address" hint="city, state and country" /></span>. | |||||
I am <span style={{ display: 'inline-block', width: '16rem', verticalAlign: 'bottom', }}><TextInput label="Full name" hint="given and family name" /></span> and I live in <span style={{ display: 'inline-block', width: '24rem', verticalAlign: 'bottom', }}><TextInput label="Address" hint="city, state and country" /></span>. | |||||
</form> | </form> | ||||
`} | `} | ||||
/> | /> | ||||
@@ -52,19 +56,19 @@ some content that is best displayed outside the component instead of putting in | |||||
style={{ display: 'grid', gridTemplateColumns: '4fr 4fr 5fr', gap: '1rem', }} | style={{ display: 'grid', gridTemplateColumns: '4fr 4fr 5fr', gap: '1rem', }} | ||||
> | > | ||||
<div style={{ gridColumnStart: 1, gridColumnEnd: 4, }}> | <div style={{ gridColumnStart: 1, gridColumnEnd: 4, }}> | ||||
<TextInput border label="Address line 1" hint="unit/house number, building" /> | |||||
<TextInput alternate border label="Address line 1" hint="unit/house number, building" /> | |||||
</div> | </div> | ||||
<div style={{ gridColumnStart: 1, gridColumnEnd: 4, }}> | <div style={{ gridColumnStart: 1, gridColumnEnd: 4, }}> | ||||
<TextInput border label="Address line 2" hint="street, area" /> | |||||
<TextInput alternate border label="Address line 2" hint="street, area" /> | |||||
</div> | </div> | ||||
<div> | <div> | ||||
<TextInput border size="large" label="City/Town" /> | |||||
<TextInput alternate border size="large" label="City/Town" /> | |||||
</div> | </div> | ||||
<div> | <div> | ||||
<TextInput border size="large" label="State/Province" /> | |||||
<TextInput alternate border size="large" label="State/Province" /> | |||||
</div> | </div> | ||||
<div> | <div> | ||||
<TextInput border size="large" label="Country" hint="abbreviations are accepted" /> | |||||
<TextInput alternate border size="large" label="Country" hint="abbreviations are accepted" /> | |||||
<small> | <small> | ||||
Consult the <a href="#">fees table</a> for shipping fee details. | Consult the <a href="#">fees table</a> for shipping fee details. | ||||
</small> | </small> | ||||
@@ -1 +0,0 @@ | |||||
../../../../README.md |
@@ -0,0 +1,91 @@ | |||||
# Tesseract Web - React Common | |||||
Common front-end components for Web using the [Tesseract design system](https://make.modal.sh/tesseract/design), written for [React](https://reactjs.org). | |||||
Package: | |||||
[![@tesseract-design/react-common](https://code.modal.sh/badge?repo=tesseract-design/react-common&type=package&color=C78AB3&kind=name)](https://js.pack.modal.sh/-/web/detail/@tesseract-design/react-common) | |||||
[![@tesseract-design/react-common](https://code.modal.sh/badge?repo=tesseract-design/react-common&type=package&color=C78AB3&kind=version)](https://js.pack.modal.sh/-/web/detail/@tesseract-design/react-common#versions) | |||||
Dependencies: | |||||
[![React](https://code.modal.sh/badge?repo=tesseract-design/react-common&type=dependency&dependency=react&kind=peerDependencies)](https://github.com/facebook/react) | |||||
[![Styled Components](https://code.modal.sh/badge?repo=tesseract-design/react-common&type=dependency&dependency=styled-components&kind=peerDependencies)](https://github.com/styled-components/styled-components) | |||||
[![TypeScript](https://code.modal.sh/badge?repo=tesseract-design/react-common&type=dependency&dependency=typescript&kind=devDependencies)](https://github.com/microsoft/typescript) | |||||
[![Jest](https://code.modal.sh/badge?repo=tesseract-design/react-common&type=dependency&dependency=jest&kind=devDependencies)](https://github.com/facebook/jest) | |||||
[![Rollup](https://code.modal.sh/badge?repo=tesseract-design/react-common&type=dependency&dependency=rollup&kind=devDependencies)](https://github.com/rollup/rollup) | |||||
## Installation | |||||
Since this package resides in the [Modal.sh JavaScript Package Registry](https://js.pack.modal.sh/), you may need to | |||||
adjust configuration in your chosen package manager. | |||||
With [Yarn](https://yarnpkg.com), add this to your `.yarnrc` file: | |||||
``` | |||||
"@tesseract-design:registry" "https://js.pack.modal.sh/" | |||||
``` | |||||
Then, install the package by running the following command: | |||||
```shell script | |||||
yarn add @tesseract-design/react-common | |||||
``` | |||||
## Usage | |||||
The package includes components as named exports. Simply import the components you need individually or use a namespace | |||||
import, like so: | |||||
```jsx harmony | |||||
import * as React from 'react' | |||||
import ReactDOM from 'react-dom' | |||||
import * as T from '@tesseract-design/react-common' | |||||
const LoginForm = etcProps => ( | |||||
<form | |||||
{...etcProps} | |||||
> | |||||
<fieldset> | |||||
<legend> | |||||
Log In | |||||
</legend> | |||||
<div> | |||||
<T.TextInput | |||||
block | |||||
label="Username" | |||||
/> | |||||
</div> | |||||
<div> | |||||
<T.TextInput | |||||
block | |||||
type="password" | |||||
label="Password" | |||||
/> | |||||
</div> | |||||
<div> | |||||
<T.Button> | |||||
Log In | |||||
</T.Button> | |||||
</div> | |||||
</fieldset> | |||||
</form> | |||||
) | |||||
const mountNode = window.document.createElement('div') | |||||
ReactDOM.render( | |||||
<LoginForm />, | |||||
mountNode, | |||||
) | |||||
window.document.body.appendChild(mountNode) | |||||
``` | |||||
Detailed usage guides can be found in the [Tesseract Design - React Common documentation](https://make.modal.sh/tesseract/web/react/common). | |||||
## TypeScript | |||||
The package is written and tested using TypeScript. Thus, typings for consumption in TypeScript are bundled with the | |||||
compiled source. | |||||
@@ -62,7 +62,6 @@ const LabelWrapper = styled('span')({ | |||||
position: 'absolute', | position: 'absolute', | ||||
top: 0, | top: 0, | ||||
left: 0, | left: 0, | ||||
paddingLeft: '0.5rem', | |||||
fontSize: '0.85em', | fontSize: '0.85em', | ||||
maxWidth: '100%', | maxWidth: '100%', | ||||
overflow: 'hidden', | overflow: 'hidden', | ||||
@@ -120,7 +119,6 @@ const Input = styled('input')({ | |||||
position: 'relative', | position: 'relative', | ||||
border: 0, | border: 0, | ||||
borderRadius: 'inherit', | borderRadius: 'inherit', | ||||
paddingLeft: '1rem', | |||||
margin: 0, | margin: 0, | ||||
font: 'inherit', | font: 'inherit', | ||||
minHeight: '4rem', | minHeight: '4rem', | ||||
@@ -150,7 +148,6 @@ const TextArea = styled('textarea')({ | |||||
position: 'relative', | position: 'relative', | ||||
border: 0, | border: 0, | ||||
borderRadius: 'inherit', | borderRadius: 'inherit', | ||||
paddingLeft: '1rem', | |||||
margin: 0, | margin: 0, | ||||
font: 'inherit', | font: 'inherit', | ||||
minHeight: '4rem', | minHeight: '4rem', | ||||
@@ -168,9 +165,7 @@ TextArea.displayName = 'textarea' | |||||
const HintWrapper = styled('span')({ | const HintWrapper = styled('span')({ | ||||
boxSizing: 'border-box', | boxSizing: 'border-box', | ||||
position: 'absolute', | position: 'absolute', | ||||
bottom: 0, | |||||
left: 0, | left: 0, | ||||
paddingLeft: '1rem', | |||||
fontSize: '0.85em', | fontSize: '0.85em', | ||||
opacity: 0.5, | opacity: 0.5, | ||||
maxWidth: '100%', | maxWidth: '100%', | ||||
@@ -252,6 +247,10 @@ const propTypes = { | |||||
* Event handler triggered when the component loses focus. | * Event handler triggered when the component loses focus. | ||||
*/ | */ | ||||
onBlur: PropTypes.func, | onBlur: PropTypes.func, | ||||
/** | |||||
* Should the component be displayed with an alternate appearance? | |||||
*/ | |||||
alternate: PropTypes.bool, | |||||
} | } | ||||
type Props = PropTypes.InferProps<typeof propTypes> | type Props = PropTypes.InferProps<typeof propTypes> | ||||
@@ -275,6 +274,7 @@ const TextInput = React.forwardRef<HTMLInputElement | HTMLTextAreaElement, Props | |||||
onChange, | onChange, | ||||
onFocus, | onFocus, | ||||
onBlur, | onBlur, | ||||
alternate = false, | |||||
...etcProps | ...etcProps | ||||
}, | }, | ||||
ref, | ref, | ||||
@@ -288,6 +288,7 @@ const TextInput = React.forwardRef<HTMLInputElement | HTMLTextAreaElement, Props | |||||
<CaptureArea> | <CaptureArea> | ||||
<LabelWrapper | <LabelWrapper | ||||
style={{ | style={{ | ||||
paddingLeft: alternate ? '0.5rem' : undefined, | |||||
paddingTop: LABEL_VERTICAL_PADDING_SIZES[size!], | paddingTop: LABEL_VERTICAL_PADDING_SIZES[size!], | ||||
paddingBottom: LABEL_VERTICAL_PADDING_SIZES[size!], | paddingBottom: LABEL_VERTICAL_PADDING_SIZES[size!], | ||||
paddingRight: indicator ? MIN_HEIGHTS[size!] : '0.5rem', | paddingRight: indicator ? MIN_HEIGHTS[size!] : '0.5rem', | ||||
@@ -311,9 +312,10 @@ const TextInput = React.forwardRef<HTMLInputElement | HTMLTextAreaElement, Props | |||||
height: `calc(${MIN_HEIGHTS[size!]} * ${rows})`, | height: `calc(${MIN_HEIGHTS[size!]} * ${rows})`, | ||||
fontSize: INPUT_FONT_SIZES[size!], | fontSize: INPUT_FONT_SIZES[size!], | ||||
minHeight: MIN_HEIGHTS[size!], | minHeight: MIN_HEIGHTS[size!], | ||||
paddingTop: VERTICAL_PADDING_SIZES[size!], | |||||
paddingTop: alternate ? VERTICAL_PADDING_SIZES[size!] : `calc(${SECONDARY_TEXT_SIZES[size!]} * 2)`, | |||||
paddingBottom: VERTICAL_PADDING_SIZES[size!], | paddingBottom: VERTICAL_PADDING_SIZES[size!], | ||||
paddingRight: indicator ? MIN_HEIGHTS[size!] : '1rem', | |||||
paddingRight: indicator ? MIN_HEIGHTS[size!] : (alternate ? '1rem' : undefined), | |||||
paddingLeft: alternate ? '1rem' : undefined, | |||||
}} | }} | ||||
/> | /> | ||||
)} | )} | ||||
@@ -327,9 +329,11 @@ const TextInput = React.forwardRef<HTMLInputElement | HTMLTextAreaElement, Props | |||||
ref={ref as React.Ref<HTMLInputElement>} | ref={ref as React.Ref<HTMLInputElement>} | ||||
disabled={disabled!} | disabled={disabled!} | ||||
style={{ | style={{ | ||||
paddingLeft: alternate ? '1rem' : undefined, | |||||
fontSize: INPUT_FONT_SIZES[size!], | fontSize: INPUT_FONT_SIZES[size!], | ||||
minHeight: MIN_HEIGHTS[size!], | minHeight: MIN_HEIGHTS[size!], | ||||
paddingRight: indicator ? MIN_HEIGHTS[size!] : '1rem', | |||||
paddingTop: alternate ? undefined : `calc(${SECONDARY_TEXT_SIZES[size!]} * 2)`, | |||||
paddingRight: indicator ? MIN_HEIGHTS[size!] : (alternate ? '1rem' : undefined), | |||||
}} | }} | ||||
/> | /> | ||||
)} | )} | ||||
@@ -338,6 +342,9 @@ const TextInput = React.forwardRef<HTMLInputElement | HTMLTextAreaElement, Props | |||||
{stringify(hint).length > 0 && ( | {stringify(hint).length > 0 && ( | ||||
<HintWrapper | <HintWrapper | ||||
style={{ | style={{ | ||||
top: alternate ? undefined : '0.75rem', | |||||
bottom: alternate ? 0 : undefined, | |||||
paddingLeft: alternate ? '1rem' : undefined, | |||||
paddingTop: LABEL_VERTICAL_PADDING_SIZES[size!], | paddingTop: LABEL_VERTICAL_PADDING_SIZES[size!], | ||||
paddingBottom: LABEL_VERTICAL_PADDING_SIZES[size!], | paddingBottom: LABEL_VERTICAL_PADDING_SIZES[size!], | ||||
paddingRight: indicator ? MIN_HEIGHTS[size!] : '1rem', | paddingRight: indicator ? MIN_HEIGHTS[size!] : '1rem', | ||||