Make docs use the latest (bleeding edge) of the components by importing them directly.tags/0.3.0
@@ -66,6 +66,4 @@ typings/ | |||
.env | |||
.next | |||
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", | |||
"private": false, | |||
"devDependencies": { | |||
"@babel/runtime": "^7.12.5", | |||
"@reach/slider": "^0.10.5", | |||
"@rollup/plugin-typescript": "^5.0.2", | |||
"@types/enzyme": "^3.10.5", | |||
"@types/enzyme-adapter-react-16": "^1.0.6", | |||
@@ -29,23 +31,20 @@ | |||
"jest-axe": "3.4.0", | |||
"jest-enzyme": "7.1.2", | |||
"jest-extended": "0.11.5", | |||
"pascal-case": "3.1.1", | |||
"plop": "2.6.0", | |||
"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-plugin-peer-deps-external": "2.2.2", | |||
"rollup-plugin-terser": "5.3.0", | |||
"styled-components": "5.1.0", | |||
"ts-jest": "^26.1.3", | |||
"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": { | |||
"prepublishOnly": "NODE_ENV=production rm -rf dist/ && rollup -c", | |||
@@ -64,5 +63,6 @@ | |||
"react-feather": "2.0.3", | |||
"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 |
@@ -1,6 +1,25 @@ | |||
const path = require('path') | |||
const withMDX = require('next-mdx-frontmatter')({ | |||
extension: /\.mdx?$/ | |||
}) | |||
module.exports = withMDX({ | |||
const e = withMDX({ | |||
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", | |||
"private": true, | |||
"scripts": { | |||
"predev": "./scripts/docgen", | |||
"dev": "next dev", | |||
"prebuild": "./scripts/docgen", | |||
"build": "next build", | |||
"prestart": "./scripts/docgen", | |||
"start": "next start", | |||
"docgen": "node scripts/docgen.js" | |||
"docgen": "./scripts/docgen" | |||
}, | |||
"dependencies": { | |||
"@mdx-js/loader": "^1.6.19", | |||
"@tesseract-design/react-common": "^0.2.1", | |||
"next": "10.0.1", | |||
"next-mdx-frontmatter": "^0.0.3", | |||
"pascal-case": "^3.1.1", | |||
@@ -78,6 +78,9 @@ | |||
font-stretch: var(--font-stretch-base, normal); | |||
font-weight: var(--font-weight-base, 400); | |||
line-height: var(--line-height-base, 2); | |||
transition-property: color, background-color; | |||
transition-timing-function: ease; | |||
transition-duration: 350ms; | |||
} | |||
h1 { | |||
@@ -1,3 +1,5 @@ | |||
#!/usr/bin/env node | |||
const docgen = require('react-docgen-typescript') | |||
const path = require('path') | |||
const fs = require('fs') |
@@ -1,7 +1,7 @@ | |||
import * as React from 'react' | |||
import * as PropTypes from 'prop-types' | |||
import styled from 'styled-components' | |||
import { Icon } from '@tesseract-design/react-common' | |||
import { Icon } from '../../../../react-common/src' | |||
const Image = styled('img')({ | |||
display: 'block', | |||
@@ -16,7 +16,7 @@ const Container = styled('span')({ | |||
margin: '0 0 0 auto', | |||
boxSizing: 'border-box', | |||
'@media (min-width: 720px)': { | |||
maxWidth: 360, | |||
maxWidth: 'var(--max-width)', | |||
}, | |||
}) | |||
@@ -1,7 +1,7 @@ | |||
import * as React from 'react' | |||
import * as PropTypes from 'prop-types' | |||
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' | |||
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 Nav from '../Nav/Nav' | |||
import Link from 'next/link' | |||
import * as React from 'react' | |||
import Nav from '../Nav/Nav' | |||
const StyledLink = styled('a')({ | |||
display: 'block', | |||
textDecoration: 'none', | |||
marginBottom: '2rem', | |||
marginTop: '3rem', | |||
marginBottom: '3rem', | |||
}) | |||
const Container = styled('span')({ | |||
@@ -17,11 +20,12 @@ const Container = styled('span')({ | |||
margin: '0 0 0 auto', | |||
boxSizing: 'border-box', | |||
'@media (min-width: 720px)': { | |||
maxWidth: 360, | |||
maxWidth: 'var(--max-width)', | |||
}, | |||
}) | |||
const Base = styled('aside')({ | |||
'--max-width': 240, | |||
position: 'fixed', | |||
top: 0, | |||
left: '-100%', | |||
@@ -29,55 +33,96 @@ const Base = styled('aside')({ | |||
height: '100%', | |||
backgroundColor: 'var(--color-bg)', | |||
zIndex: 4, | |||
transitionProperty: 'color, background-color', | |||
transitionTimingFunction: 'ease', | |||
transitionDuration: '350ms', | |||
'@media (min-width: 720px)': { | |||
left: 0, | |||
width: `${100 / 3}%`, | |||
width: `${100 / 4}%`, | |||
maxWidth: 'none', | |||
height: '100%', | |||
'+ *': { | |||
paddingLeft: `${100 / 3}%`, | |||
paddingLeft: `${100 / 4}%`, | |||
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')({ | |||
'--size-link': '3rem', | |||
}) | |||
const RepoLink = styled('a')({ | |||
display: 'inline-grid', | |||
width: '1.5rem', | |||
height: '1.5rem', | |||
placeContent: 'center', | |||
}) | |||
const Sidebar = ({ | |||
data, | |||
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(() => { | |||
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 => { | |||
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') | |||
} else { | |||
s.setAttribute('rel', 'alternate stylesheet') | |||
s.setAttribute('disabled', 'disabled') | |||
} | |||
}) | |||
}, [dark]) | |||
}, [theme]) | |||
return ( | |||
<Base> | |||
<Container> | |||
<input | |||
type="checkbox" | |||
defaultChecked={dark} | |||
onChange={toggleDarkMode(!dark)} | |||
/> | |||
</Container> | |||
<NavWrapper> | |||
<Link | |||
href="/" | |||
@@ -89,6 +134,47 @@ const Sidebar = ({ | |||
</Container> | |||
</StyledLink> | |||
</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 | |||
data={data.nav} | |||
/> | |||
@@ -677,6 +677,17 @@ | |||
"type": { | |||
"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 sidebar from '../sidebar.json' | |||
import brand from '../../brand' | |||
@@ -12,11 +13,16 @@ const Container = styled('div')({ | |||
boxSizing: 'border-box', | |||
}) | |||
const App = ({ | |||
type AppProps = { | |||
Component: React.ElementType, | |||
pageProps: Record<string, unknown>, | |||
} | |||
const App: React.FC<AppProps> = ({ | |||
Component, | |||
pageProps, | |||
}) => ( | |||
<div> | |||
<React.Fragment> | |||
<Sidebar | |||
brand={brand} | |||
data={sidebar} | |||
@@ -28,7 +34,7 @@ const App = ({ | |||
/> | |||
</Container> | |||
</main> | |||
</div> | |||
</React.Fragment> | |||
) | |||
export default App |
@@ -2,7 +2,7 @@ | |||
title: Button | |||
--- | |||
import { Button } from '@tesseract-design/react-common' | |||
import { Button } from '../../../../react-common/src' | |||
import Playground from '../../components/Playground/Playground' | |||
import Props from '../../components/Props/Props' | |||
import Header from '../../components/Header/Header' | |||
@@ -2,7 +2,7 @@ | |||
name: Checkbox | |||
--- | |||
import { Checkbox } from '@tesseract-design/react-common' | |||
import { Checkbox } from '../../../../react-common/src' | |||
import Playground from '../../components/Playground/Playground' | |||
import Props from '../../components/Props/Props' | |||
import Header from '../../components/Header/Header' | |||
@@ -2,7 +2,7 @@ | |||
name: Icon | |||
--- | |||
import { Icon } from '@tesseract-design/react-common' | |||
import { Icon } from '../../../../react-common/src' | |||
import Playground from '../../components/Playground/Playground' | |||
import Props from '../../components/Props/Props' | |||
import Header from '../../components/Header/Header' | |||
@@ -2,7 +2,7 @@ | |||
name: RadioButton | |||
--- | |||
import { RadioButton } from '@tesseract-design/react-common' | |||
import { RadioButton } from '../../../../react-common/src' | |||
import Playground from '../../components/Playground/Playground' | |||
import Props from '../../components/Props/Props' | |||
import Header from '../../components/Header/Header' | |||
@@ -2,7 +2,7 @@ | |||
name: Select | |||
--- | |||
import { Select } from '@tesseract-design/react-common' | |||
import { Select } from '../../../../react-common/src' | |||
import Playground from '../../components/Playground/Playground' | |||
import Props from '../../components/Props/Props' | |||
import Header from '../../components/Header/Header' | |||
@@ -2,7 +2,7 @@ | |||
name: Slider | |||
--- | |||
import { Slider } from '@tesseract-design/react-common' | |||
import { Slider } from '../../../../react-common/src' | |||
import Playground from '../../components/Playground/Playground' | |||
import Props from '../../components/Props/Props' | |||
import Header from '../../components/Header/Header' | |||
@@ -2,7 +2,7 @@ | |||
name: TextInput | |||
--- | |||
import { TextInput } from '@tesseract-design/react-common' | |||
import { TextInput } from '../../../../react-common/src' | |||
import Playground from '../../components/Playground/Playground' | |||
import Props from '../../components/Props/Props' | |||
import Header from '../../components/Header/Header' | |||
@@ -12,7 +12,11 @@ import Header from '../../components/Header/Header' | |||
<Playground | |||
components={{ TextInput }} | |||
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 }} | |||
code={` | |||
<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> | |||
`} | |||
/> | |||
@@ -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', }} | |||
> | |||
<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 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> | |||
<TextInput border size="large" label="City/Town" /> | |||
<TextInput alternate border size="large" label="City/Town" /> | |||
</div> | |||
<div> | |||
<TextInput border size="large" label="State/Province" /> | |||
<TextInput alternate border size="large" label="State/Province" /> | |||
</div> | |||
<div> | |||
<TextInput border size="large" label="Country" hint="abbreviations are accepted" /> | |||
<TextInput alternate border size="large" label="Country" hint="abbreviations are accepted" /> | |||
<small> | |||
Consult the <a href="#">fees table</a> for shipping fee details. | |||
</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', | |||
top: 0, | |||
left: 0, | |||
paddingLeft: '0.5rem', | |||
fontSize: '0.85em', | |||
maxWidth: '100%', | |||
overflow: 'hidden', | |||
@@ -120,7 +119,6 @@ const Input = styled('input')({ | |||
position: 'relative', | |||
border: 0, | |||
borderRadius: 'inherit', | |||
paddingLeft: '1rem', | |||
margin: 0, | |||
font: 'inherit', | |||
minHeight: '4rem', | |||
@@ -150,7 +148,6 @@ const TextArea = styled('textarea')({ | |||
position: 'relative', | |||
border: 0, | |||
borderRadius: 'inherit', | |||
paddingLeft: '1rem', | |||
margin: 0, | |||
font: 'inherit', | |||
minHeight: '4rem', | |||
@@ -168,9 +165,7 @@ TextArea.displayName = 'textarea' | |||
const HintWrapper = styled('span')({ | |||
boxSizing: 'border-box', | |||
position: 'absolute', | |||
bottom: 0, | |||
left: 0, | |||
paddingLeft: '1rem', | |||
fontSize: '0.85em', | |||
opacity: 0.5, | |||
maxWidth: '100%', | |||
@@ -252,6 +247,10 @@ const propTypes = { | |||
* Event handler triggered when the component loses focus. | |||
*/ | |||
onBlur: PropTypes.func, | |||
/** | |||
* Should the component be displayed with an alternate appearance? | |||
*/ | |||
alternate: PropTypes.bool, | |||
} | |||
type Props = PropTypes.InferProps<typeof propTypes> | |||
@@ -275,6 +274,7 @@ const TextInput = React.forwardRef<HTMLInputElement | HTMLTextAreaElement, Props | |||
onChange, | |||
onFocus, | |||
onBlur, | |||
alternate = false, | |||
...etcProps | |||
}, | |||
ref, | |||
@@ -288,6 +288,7 @@ const TextInput = React.forwardRef<HTMLInputElement | HTMLTextAreaElement, Props | |||
<CaptureArea> | |||
<LabelWrapper | |||
style={{ | |||
paddingLeft: alternate ? '0.5rem' : undefined, | |||
paddingTop: LABEL_VERTICAL_PADDING_SIZES[size!], | |||
paddingBottom: LABEL_VERTICAL_PADDING_SIZES[size!], | |||
paddingRight: indicator ? MIN_HEIGHTS[size!] : '0.5rem', | |||
@@ -311,9 +312,10 @@ const TextInput = React.forwardRef<HTMLInputElement | HTMLTextAreaElement, Props | |||
height: `calc(${MIN_HEIGHTS[size!]} * ${rows})`, | |||
fontSize: INPUT_FONT_SIZES[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!], | |||
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>} | |||
disabled={disabled!} | |||
style={{ | |||
paddingLeft: alternate ? '1rem' : undefined, | |||
fontSize: INPUT_FONT_SIZES[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 && ( | |||
<HintWrapper | |||
style={{ | |||
top: alternate ? undefined : '0.75rem', | |||
bottom: alternate ? 0 : undefined, | |||
paddingLeft: alternate ? '1rem' : undefined, | |||
paddingTop: LABEL_VERTICAL_PADDING_SIZES[size!], | |||
paddingBottom: LABEL_VERTICAL_PADDING_SIZES[size!], | |||
paddingRight: indicator ? MIN_HEIGHTS[size!] : '1rem', | |||