瀏覽代碼

Add Next.js + MDX support

Implement Next.js MDX

Separate the docs from the code and tests.
tags/0.3.0
TheoryOfNekomata 4 年之前
父節點
當前提交
36954ed21c
共有 59 個檔案被更改,包括 7524 行新增265 行删除
  1. +2
    -2
      jest.config.js
  2. +0
    -25
      lib/components/Checkbox/Checkbox.mdx
  3. +0
    -20
      lib/components/Icon/Icon.mdx
  4. +0
    -32
      lib/components/RadioButton/RadioButton.mdx
  5. +0
    -45
      lib/components/Select/Select.mdx
  6. +0
    -71
      lib/components/TextInput/TextInput.mdx
  7. +0
    -42
      lib/services/isEmpty.test.ts
  8. +30
    -0
      packages/react-common-docs/README.md
  9. +9
    -0
      packages/react-common-docs/brand.tsx
  10. +2
    -0
      packages/react-common-docs/next-env.d.ts
  11. +6
    -0
      packages/react-common-docs/next.config.js
  12. +19
    -0
      packages/react-common-docs/package.json
  13. 二進制
      packages/react-common-docs/public/favicon.ico
  14. +52
    -0
      packages/react-common-docs/public/global.css
  15. +127
    -0
      packages/react-common-docs/public/theme/dark.css
  16. +138
    -0
      packages/react-common-docs/public/theme/light.css
  17. +4
    -0
      packages/react-common-docs/public/vercel.svg
  18. +91
    -0
      packages/react-common-docs/src/components/Nav.tsx
  19. +47
    -0
      packages/react-common-docs/src/components/Playground.tsx
  20. +96
    -0
      packages/react-common-docs/src/components/Sidebar.tsx
  21. +35
    -0
      packages/react-common-docs/src/pages/_app.tsx
  22. +45
    -0
      packages/react-common-docs/src/pages/_document.tsx
  23. +12
    -9
      packages/react-common-docs/src/pages/components/Button.mdx
  24. +26
    -0
      packages/react-common-docs/src/pages/components/Checkbox.mdx
  25. +21
    -0
      packages/react-common-docs/src/pages/components/Icon.mdx
  26. +33
    -0
      packages/react-common-docs/src/pages/components/RadioButton.mdx
  27. +46
    -0
      packages/react-common-docs/src/pages/components/Select.mdx
  28. +9
    -8
      packages/react-common-docs/src/pages/components/Slider.mdx
  29. +78
    -0
      packages/react-common-docs/src/pages/components/TextInput.mdx
  30. +1
    -0
      packages/react-common-docs/src/pages/index.md
  31. +0
    -0
      packages/react-common-docs/src/pages/theming.md
  32. +18
    -0
      packages/react-common-docs/src/sidebar.json
  33. +37
    -0
      packages/react-common-docs/tsconfig.json
  34. +6489
    -0
      packages/react-common-docs/yarn.lock
  35. +1
    -1
      packages/react-common/components/Button/Button.test.tsx
  36. +0
    -0
      packages/react-common/components/Button/Button.tsx
  37. +1
    -1
      packages/react-common/components/Checkbox/Checkbox.test.tsx
  38. +0
    -0
      packages/react-common/components/Checkbox/Checkbox.tsx
  39. +1
    -1
      packages/react-common/components/Icon/Icon.test.tsx
  40. +0
    -0
      packages/react-common/components/Icon/Icon.tsx
  41. +1
    -1
      packages/react-common/components/RadioButton/RadioButton.test.tsx
  42. +0
    -0
      packages/react-common/components/RadioButton/RadioButton.tsx
  43. +1
    -1
      packages/react-common/components/Select/Select.test.tsx
  44. +0
    -0
      packages/react-common/components/Select/Select.tsx
  45. +1
    -1
      packages/react-common/components/Slider/Slider.test.tsx
  46. +0
    -0
      packages/react-common/components/Slider/Slider.tsx
  47. +1
    -1
      packages/react-common/components/TextInput/TextInput.test.tsx
  48. +0
    -0
      packages/react-common/components/TextInput/TextInput.tsx
  49. +1
    -1
      packages/react-common/index.test.ts
  50. +0
    -0
      packages/react-common/index.ts
  51. +40
    -0
      packages/react-common/services/isEmpty.test.ts
  52. +0
    -0
      packages/react-common/services/isEmpty.ts
  53. +0
    -0
      packages/react-common/services/splitValueAndUnit.test.ts
  54. +0
    -0
      packages/react-common/services/splitValueAndUnit.ts
  55. +1
    -1
      packages/react-common/services/stringify.test.ts
  56. +0
    -0
      packages/react-common/services/stringify.ts
  57. +0
    -0
      packages/react-common/services/utilities.ts
  58. +1
    -1
      plopfile.js
  59. +1
    -1
      rollup.config.js

+ 2
- 2
jest.config.js 查看文件

@@ -5,8 +5,8 @@ module.exports = {
'./jest.setup.ts',
],
collectCoverageFrom: [
'./lib/**/*.{ts,tsx}',
'!./lib/**/*.stories.{ts,tsx}'
'./packages/**/*.{ts,tsx}',
'!./packages/**/*.stories.{ts,tsx}'
],
preset: 'ts-jest',
testTimeout: 30000,


+ 0
- 25
lib/components/Checkbox/Checkbox.mdx 查看文件

@@ -1,25 +0,0 @@
---
name: Checkbox
route: /components/checkbox
menu: Components
---

import { Playground, Props, Link } from 'docz'
import Checkbox from './Checkbox'

# Checkbox

Component for values that have an on/off state.

<Playground>
<Checkbox label="Accept Terms" />
</Playground>

## Props

<Props of={Checkbox} />

## See Also

- <Link to="../select">Select</Link> for a similar component suitable for selecting more values.
- <Link to="../radiobutton">RadioButton</Link> for a similar component on selecting a single value among very few choices.

+ 0
- 20
lib/components/Icon/Icon.mdx 查看文件

@@ -1,20 +0,0 @@
---
name: Icon
route: /components/icon
menu: Components
---

import { Playground, Props } from 'docz'
import Icon from './Icon'

# Icon

Component for displaying graphics.

<Playground>
<Icon name="check" label="OK" size="1.5rem" weight={0.125} />
</Playground>

## Props

<Props of={Icon} />

+ 0
- 32
lib/components/RadioButton/RadioButton.mdx 查看文件

@@ -1,32 +0,0 @@
---
name: RadioButton
route: /components/radiobutton
menu: Components
---

import { Playground, Props, Link } from 'docz'
import RadioButton from './RadioButton'

# RadioButton

Component for values which are to be selected from a few list of options.

<Playground>
<div style={{ display: 'grid', gap: '1rem', }}>
<div>
<RadioButton name="flavor" label="Chocolate" />
</div>
<div>
<RadioButton name="flavor" label="Vanilla" />
</div>
</div>
</Playground>

## Props

<Props of={RadioButton} />

## See Also

- <Link to="../checkbox">Checkbox</Link> for a similar component on selecting values among very few choices.
- <Link to="../select">Select</Link> for a similar component suitable for selecting more values.

+ 0
- 45
lib/components/Select/Select.mdx 查看文件

@@ -1,45 +0,0 @@
---
name: Select
route: /components/select
menu: Components
---

import { Playground, Props, Link } from 'docz'
import Select from './Select'

# Select

Component for selecting values from a larger number of options.

<Playground>
<Select>
<optgroup
label="Fruits"
>
<option value="mango">Mango</option>
<option value="strawberry">Strawberry</option>
<option value="blueberry">Blueberry</option>
</optgroup>
<optgroup
label="Classic"
>
<option value="chocolate">Chocolate</option>
<option value="vanilla">Vanilla</option>
</optgroup>
</Select>
</Playground>

## Props

<Props of={Select} />

## Usage Notes

The component will behave as `block`, i.e. it takes the remaining of the horizontal space.
To use the component together with layouts, see [TextInput](./textinput) for examples. Both `Select` and
`TextInput` have similar strategies on usage with layouts.

## See Also

- <Link to="../checkbox">Checkbox</Link> for a similar component on selecting values among very few choices.
- <Link to="../radiobutton">RadioButton</Link> for a similar component on selecting a single value among very few choices.

+ 0
- 71
lib/components/TextInput/TextInput.mdx 查看文件

@@ -1,71 +0,0 @@
---
name: TextInput
route: /components/textinput
menu: Components
---

import { Playground, Props, Link } from 'docz'
import TextInput from './TextInput'

# TextInput

Component for inputting textual values.

<Playground>
<TextInput label="Username" placeholder="johndoe" hint="the name you use to log in" />
</Playground>

## Props

<Props of={TextInput} />

## Usage Notes

The component will behave as `block`, i.e. it takes the remaining of the horizontal space.
To use the component together with layouts, see the following examples.

### Inline

The components are surrounded by `inline-block` elements. These surrounding elements have specified widths, which could
act as guide to the user on how long the expected input values are.

<Playground>
<form>
I am <span style={{ display: 'inline-block', width: '16rem', }}><TextInput label="Full name" hint="given and family name" /></span> and I live in <span style={{ display: 'inline-block', width: '24rem', }}><TextInput label="Address" hint="city, state and country" /></span>.
</form>
</Playground>

### Grid

It is advisable to put surrounding elements instead of the `TextInput` components themselves as children of the
element specified as `grid`. This is to be able to add complementing content to the components, if for example there are
some content that is best displayed outside the component instead of putting in the `hint` prop.

<Playground>
<form
style={{ display: 'grid', gridTemplateColumns: '4fr 4fr 5fr', gap: '1rem', }}
>
<div style={{ gridColumnStart: 1, gridColumnEnd: 4, }}>
<TextInput label="Address line 1" hint="unit/house number, building" />
</div>
<div style={{ gridColumnStart: 1, gridColumnEnd: 4, }}>
<TextInput label="Address line 2" hint="street, area" />
</div>
<div>
<TextInput size="large" label="City/Town" />
</div>
<div>
<TextInput size="large" label="State/Province" />
</div>
<div>
<TextInput size="large" label="Country" hint="abbreviations are accepted" />
<small>
Consult the <a href="#">fees table</a> for shipping fee details.
</small>
</div>
</form>
</Playground>

## See Also

- <Link to="../select">Select</Link> for a graphically-similar component suitable for selecting more values.

+ 0
- 42
lib/services/isEmpty.test.ts 查看文件

@@ -1,42 +0,0 @@
import * as fc from 'fast-check'
import isEmpty from './isEmpty'

describe('lib/services/isEmpty', () => {
it('should exist', () => {
expect(isEmpty).toBeDefined()
})

it('should be a function', () => {
expect(isEmpty).toBeFunction()
})

it('should accept 1 argument', () => {
expect(isEmpty).toHaveLength(1)
})

it('should return a boolean value', () => {
fc.assert(
fc.property(fc.anything(), (v) => {
expect(typeof isEmpty(v)).toBe('boolean')
}),
)
})

describe('on arguments', () => {
it('should return `true` on an argument with value of `undefined`', () => {
expect(isEmpty(undefined)).toBe(true)
})

it('should return `true` on an argument with value of `null`', () => {
expect(isEmpty(null)).toBe(true)
})

it('should return `false` on an argument with value that is neither `undefined` nor `null`', () => {
fc.assert(
fc.property(fc.anything().filter((v) => typeof v !== 'undefined' && v !== null), (v) => {
expect(isEmpty(v)).toBe(false)
}),
)
})
})
})

+ 30
- 0
packages/react-common-docs/README.md 查看文件

@@ -0,0 +1,30 @@
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.

+ 9
- 0
packages/react-common-docs/brand.tsx 查看文件

@@ -0,0 +1,9 @@
const Brand = () => (
<div>
<strong>
Tesseract
</strong>
</div>
)

export default Brand

+ 2
- 0
packages/react-common-docs/next-env.d.ts 查看文件

@@ -0,0 +1,2 @@
/// <reference types="next" />
/// <reference types="next/types/global" />

+ 6
- 0
packages/react-common-docs/next.config.js 查看文件

@@ -0,0 +1,6 @@
const withMDX = require('next-mdx-frontmatter')({
extension: /\.mdx?$/
})
module.exports = withMDX({
pageExtensions: ['js', 'jsx', 'ts', 'tsx', 'md', 'mdx']
})

+ 19
- 0
packages/react-common-docs/package.json 查看文件

@@ -0,0 +1,19 @@
{
"name": "react-common-docs",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
},
"dependencies": {
"@mdx-js/loader": "^1.6.19",
"@tesseract-design/react-common": "^0.2.1",
"next": "10.0.1",
"next-mdx-frontmatter": "^0.0.3",
"pascalcase": "^1.0.0",
"react-live": "^2.2.3",
"styled-components": "^5.2.1"
}
}

二進制
packages/react-common-docs/public/favicon.ico 查看文件

Before After

+ 52
- 0
packages/react-common-docs/public/global.css 查看文件

@@ -0,0 +1,52 @@
body {
margin: 0;
}

h1 {
font-size: 3em;
text-transform: lowercase;
}

h2 {
font-size: 2em;
text-transform: lowercase;
}

h3 {
font-size: 1.75em;
text-transform: lowercase;
}

h4 {
text-transform: lowercase;
}

h5 {
text-transform: lowercase;
}

h6 {
text-transform: lowercase;
}

p {
margin: 2em 0;
}

small {
font-size: 0.75em;
}

a:focus {
color: var(--color-active);
outline: 0;
}

::selection {
background-color: var(--color-active);
color: var(--color-fg);
}

:root {
caret-color: var(--color-active);
}

+ 127
- 0
packages/react-common-docs/public/theme/dark.css 查看文件

@@ -0,0 +1,127 @@
@font-face {
font-family: 'Encode Sans';
font-stretch: semi-expanded;
font-weight: 400;
src:
local('Encode Sans Semi Expanded'),
local('Encode Sans');
}

@font-face {
font-family: 'Encode Sans';
font-stretch: semi-expanded;
font-weight: 700;
src:
local('Encode Sans Semi Expanded Bold'),
local('Encode Sans Semi Expanded'),
local('Encode Sans');
}

@font-face {
font-family: 'Encode Sans';
font-stretch: condensed;
font-weight: 100;
src:
local('Encode Sans Condensed Thin'),
local('Encode Sans Condensed'),
local('Encode Sans');
}

@font-face {
font-family: 'Encode Sans';
font-stretch: condensed;
font-weight: 200;
src:
local('Encode Sans Condensed ExtraLight'),
local('Encode Sans Condensed Extra Light'),
local('Encode Sans Condensed'),
local('Encode Sans');
}

@font-face {
font-family: 'Encode Sans';
font-stretch: condensed;
font-weight: 300;
src:
local('Encode Sans Condensed Light'),
local('Encode Sans Condensed'),
local('Encode Sans');
}

:root {
--color-active: #f90;
--font-family-base: 'Encode Sans Semi Expanded', 'Encode Sans', system-ui;
--font-stretch-base: semi-expanded;
--font-weight-base: 400;
--line-height-base: 2;
--font-family-headings:'Encode Sans Condensed', 'Encode Sans', system-ui;
--font-stretch-headings: condensed;
--font-weight-headings: 100;
--line-height-headings: 1.5;
--font-family-monospace: 'mononoki';
--font-size-root: 16px;
--color-negative: #222;
--color-positive: #eee;
--color-accent: #C78AB3;
--opacity-light: 0.25;
--opacity-lighter: 0.5;
--opacity-lightest: 0.75;
}

:root {
--color-bg: var(--color-negative, white);
--color-fg: var(--color-positive, black);
background-color: var(--color-bg);
color: var(--color-fg);
font-size: var(--font-size-root);
font-family: var(--font-family-base), sans-serif;
font-stretch: var(--font-stretch-base, normal);
font-weight: var(--font-weight-base, 400);
line-height: var(--line-height-base, 2);
}

h1 {
font-family: var(--font-family-headings), sans-serif;
font-stretch: var(--font-stretch-headings, normal);
font-weight: var(--font-weight-headings, 400);
line-height: var(--line-height-headings, 1.5);
}

h2 {
font-family: var(--font-family-headings), sans-serif;
font-stretch: var(--font-stretch-headings, normal);
font-weight: var(--font-weight-headings, 400);
line-height: var(--line-height-headings, 1.5);
}

h3 {
font-family: var(--font-family-headings), sans-serif;
font-stretch: var(--font-stretch-headings, normal);
font-weight: var(--font-weight-headings, 400);
line-height: var(--line-height-headings, 1.5);
}

h4 {
font-family: var(--font-family-headings), sans-serif;
font-stretch: var(--font-stretch-headings, normal);
font-weight: var(--font-weight-headings, 400);
line-height: var(--line-height-headings, 1.5);
}

h5 {
font-family: var(--font-family-headings), sans-serif;
font-stretch: var(--font-stretch-headings, normal);
font-weight: var(--font-weight-headings, 400);
line-height: var(--line-height-headings, 1.5);
}

h6 {
font-family: var(--font-family-headings), sans-serif;
font-stretch: var(--font-stretch-headings, normal);
font-weight: var(--font-weight-headings, 400);
line-height: var(--line-height-headings, 1.5);
}

a {
color: var(--color-accent);
}

+ 138
- 0
packages/react-common-docs/public/theme/light.css 查看文件

@@ -0,0 +1,138 @@
@font-face {
font-family: 'Encode Sans';
font-stretch: semi-expanded;
font-weight: 400;
src:
local('Encode Sans Semi Expanded'),
local('Encode Sans');
}

@font-face {
font-family: 'Encode Sans';
font-stretch: semi-expanded;
font-weight: 700;
src:
local('Encode Sans Semi Expanded Bold'),
local('Encode Sans Semi Expanded'),
local('Encode Sans');
}

@font-face {
font-family: 'Encode Sans';
font-stretch: condensed;
font-weight: 100;
src:
local('Encode Sans Condensed Thin'),
local('Encode Sans Condensed'),
local('Encode Sans');
}

@font-face {
font-family: 'Encode Sans';
font-stretch: condensed;
font-weight: 200;
src:
local('Encode Sans Condensed ExtraLight'),
local('Encode Sans Condensed Extra Light'),
local('Encode Sans Condensed'),
local('Encode Sans');
}

@font-face {
font-family: 'Encode Sans';
font-stretch: condensed;
font-weight: 300;
src:
local('Encode Sans Condensed Light'),
local('Encode Sans Condensed'),
local('Encode Sans');
}

:root {
--color-negative: #eee;
--color-positive: #222;
--color-accent: #ba6a9c;
--color-active: #f90;
--font-family-base: 'Encode Sans Semi Expanded', 'Encode Sans', system-ui;
--font-stretch-base: semi-expanded;
--font-weight-base: 400;
--line-height-base: 2;
--font-family-headings:'Encode Sans Condensed', 'Encode Sans', system-ui;
--font-stretch-headings: condensed;
--font-weight-headings: 100;
--line-height-headings: 1.5;
--font-family-monospace: 'mononoki';
--font-size-root: 16px;
--opacity-light: 0.5;
--opacity-lighter: 0.75;
--opacity-lightest: 0.875;
}

/*@media (prefers-color-scheme: dark) {*/
/* :root {*/
/* --color-negative: #222;*/
/* --color-positive: #eee;*/
/* --color-accent: #C78AB3;*/
/* --opacity-light: 0.25;*/
/* --opacity-lighter: 0.5;*/
/* --opacity-lightest: 0.75;*/
/* }*/
/*}*/

:root {
--color-bg: var(--color-negative, white);
--color-fg: var(--color-positive, black);
background-color: var(--color-bg);
color: var(--color-fg);
font-size: var(--font-size-root);
font-family: var(--font-family-base), sans-serif;
font-stretch: var(--font-stretch-base, normal);
font-weight: var(--font-weight-base, 400);
line-height: var(--line-height-base, 2);
}

h1 {
font-family: var(--font-family-headings), sans-serif;
font-stretch: var(--font-stretch-headings, normal);
font-weight: var(--font-weight-headings, 400);
line-height: var(--line-height-headings, 1.5);
}

h2 {
font-family: var(--font-family-headings), sans-serif;
font-stretch: var(--font-stretch-headings, normal);
font-weight: var(--font-weight-headings, 400);
line-height: var(--line-height-headings, 1.5);
}

h3 {
font-family: var(--font-family-headings), sans-serif;
font-stretch: var(--font-stretch-headings, normal);
font-weight: var(--font-weight-headings, 400);
line-height: var(--line-height-headings, 1.5);
}

h4 {
font-family: var(--font-family-headings), sans-serif;
font-stretch: var(--font-stretch-headings, normal);
font-weight: var(--font-weight-headings, 400);
line-height: var(--line-height-headings, 1.5);
}

h5 {
font-family: var(--font-family-headings), sans-serif;
font-stretch: var(--font-stretch-headings, normal);
font-weight: var(--font-weight-headings, 400);
line-height: var(--line-height-headings, 1.5);
}

h6 {
font-family: var(--font-family-headings), sans-serif;
font-stretch: var(--font-stretch-headings, normal);
font-weight: var(--font-weight-headings, 400);
line-height: var(--line-height-headings, 1.5);
}

a {
color: var(--color-accent);
}

+ 4
- 0
packages/react-common-docs/public/vercel.svg 查看文件

@@ -0,0 +1,4 @@
<svg width="283" height="64" viewBox="0 0 283 64" fill="none"
xmlns="http://www.w3.org/2000/svg">
<path d="M141.04 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.46 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM248.72 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.45 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM200.24 34c0 6 3.92 10 10 10 4.12 0 7.21-1.87 8.8-4.92l7.68 4.43c-3.18 5.3-9.14 8.49-16.48 8.49-11.05 0-19-7.2-19-18s7.96-18 19-18c7.34 0 13.29 3.19 16.48 8.49l-7.68 4.43c-1.59-3.05-4.68-4.92-8.8-4.92-6.07 0-10 4-10 10zm82.48-29v46h-9V5h9zM36.95 0L73.9 64H0L36.95 0zm92.38 5l-27.71 48L73.91 5H84.3l17.32 30 17.32-30h10.39zm58.91 12v9.69c-1-.29-2.06-.49-3.2-.49-5.81 0-10 4-10 10V51h-9V17h9v9.2c0-5.08 5.91-9.2 13.2-9.2z" fill="#000"/>
</svg>

+ 91
- 0
packages/react-common-docs/src/components/Nav.tsx 查看文件

@@ -0,0 +1,91 @@
import * as React from 'react'
import Link from 'next/link'
import styled from 'styled-components'

const StyledLink = styled('a')({
display: 'block',
textDecoration: 'none',
})

const Container = styled('span')({
display: 'flex',
alignItems: 'center',
padding: '0 1rem',
height: '2rem',
margin: '0 0 0 auto',
'@media (min-width: 720px)': {
maxWidth: 360,
},
})

const HeaderContainer = styled(Container)({
marginTop: '2rem',
})

const NavContainer = styled('div')({

})

const Nav = ({
data,
}) => {
if (Array.isArray(data)) {
return (
<NavContainer>
{
data.map(d => (
<Nav
data={d}
/>
))
}
</NavContainer>
)
}
if (typeof data === 'object') {
const [entry] = Object.entries(data)
const [key, value] = entry
if (Array.isArray(value)) {
return (
<NavContainer>
<HeaderContainer>
{key}
</HeaderContainer>
{
value.map(v => (
<Nav
data={v}
/>
))
}
</NavContainer>
)
}
return (
<Link
href={value}
passHref
>
<StyledLink>
<Container>
{key}
</Container>
</StyledLink>
</Link>
)
}
return (
<Link
href={data}
passHref
>
<StyledLink>
<Container>
{data}
</Container>
</StyledLink>
</Link>
)
}

export default Nav

+ 47
- 0
packages/react-common-docs/src/components/Playground.tsx 查看文件

@@ -0,0 +1,47 @@
import * as React from 'react'
import {
LiveProvider,
LiveEditor,
LivePreview
} from 'react-live'
import styled from 'styled-components'

const Figure = styled('figure')({
margin: 0,
})

const Playground = ({
components,
code,
label,
}) => {
const indentLevel = code.indexOf('<') - 1
const normalizedCode = code
.split('\n')
.map((s: string) => s.slice(indentLevel))
.filter((s: string) => s.trim().length > 0)
.join('\n')

return (
<div>
<Figure>
{
label
&& (
<figcaption>
{label}
</figcaption>
)
}
<div>
<LiveProvider code={normalizedCode} scope={components}>
<LivePreview />
<LiveEditor />
</LiveProvider>
</div>
</Figure>
</div>
)
}

export default Playground

+ 96
- 0
packages/react-common-docs/src/components/Sidebar.tsx 查看文件

@@ -0,0 +1,96 @@
import styled from 'styled-components'
import Nav from './Nav'
import Link from 'next/link'
import * as React from 'react'
import { Checkbox } from '@tesseract-design/react-common'

const StyledLink = styled('a')({
display: 'block',
textDecoration: 'none',
marginBottom: '2rem',
})

const Container = styled('span')({
display: 'flex',
alignItems: 'center',
padding: '0 1rem',
height: '2rem',
margin: '0 0 0 auto',
'@media (min-width: 720px)': {
maxWidth: 360,
},
})

const Base = styled('aside')({
position: 'fixed',
top: 0,
left: '-100%',
width: '100%',
height: '100%',
backgroundColor: 'var(--color-bg)',
zIndex: 4,
'@media (min-width: 720px)': {
left: 0,
width: `${100 / 3}%`,
maxWidth: 'none',
height: '100%',
'+ *': {
paddingLeft: `${100 / 3}%`,
boxSizing: 'border-box',
},
},
})

const Sidebar = ({
data,
brand: Brand,
}) => {
const [dark, setDark] = React.useState(false)

const toggleDarkMode = b => () => {
setDark(b)
}

React.useEffect(() => {
const stylesheets = Array.from(window.document.querySelectorAll('link[title]'))

stylesheets.forEach(s => {
if (s.getAttribute('rel').includes('alternate')) {
s.setAttribute('rel', 'stylesheet')
s.removeAttribute('disabled')
} else {
s.setAttribute('rel', 'alternate stylesheet')
s.setAttribute('disabled', 'disabled')
}
})
}, [dark])

return (
<Base>
<Container>
<input
type="checkbox"
defaultChecked={dark}
onChange={toggleDarkMode(!dark)}
/>
</Container>
<nav>
<Link
href="/"
passHref
>
<StyledLink>
<Container>
<Brand />
</Container>
</StyledLink>
</Link>
<Nav
data={data.nav}
/>
</nav>
</Base>
)
}

export default Sidebar

+ 35
- 0
packages/react-common-docs/src/pages/_app.tsx 查看文件

@@ -0,0 +1,35 @@
import '../../public/global.css'
import '../../public/theme/dark.css'
import sidebar from '../sidebar.json'
import brand from '../../brand'
import Sidebar from '../components/Sidebar'
import styled from 'styled-components'

const Container = styled('div')({
maxWidth: 720,
margin: '0 auto',
padding: '0 1rem',
boxSizing: 'border-box',
})

const App = ({
Component,
pageProps,
...etc
}) => (
<div>
<Sidebar
brand={brand}
data={sidebar}
/>
<main>
<Container>
<Component
{...pageProps}
/>
</Container>
</main>
</div>
)

export default App

+ 45
- 0
packages/react-common-docs/src/pages/_document.tsx 查看文件

@@ -0,0 +1,45 @@
import Document, { Html, Head, Main, NextScript, DocumentContext } from 'next/document'
import { ServerStyleSheet } from 'styled-components'

export default class MyDocument extends Document {
static async getInitialProps(ctx: DocumentContext) {
const sheet = new ServerStyleSheet()
const originalRenderPage = ctx.renderPage

try {
ctx.renderPage = () =>
originalRenderPage({
enhanceApp: (App) => (props) =>
sheet.collectStyles(<App {...props} />),
})

const initialProps = await Document.getInitialProps(ctx)
return {
...initialProps,
styles: (
<>
{initialProps.styles}
<link rel="stylesheet" href="/global.css" />
<link rel="stylesheet" title="Dark" href="/theme/dark.css" />
<link rel="alternate stylesheet" title="Light" href="/theme/light.css" />
{sheet.getStyleElement()}
</>
),
}
} finally {
sheet.seal()
}
}

render() {
return (
<Html lang="en-PH">
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
}

lib/components/Button/Button.mdx → packages/react-common-docs/src/pages/components/Button.mdx 查看文件

@@ -1,23 +1,26 @@
---
name: Button
route: /components/button
menu: Components
title: Button
---

import { Playground, Props } from 'docz'
import Button from './Button'
import { Button } from '@tesseract-design/react-common'
import Playground from '../../components/Playground'

# Button

Component for performing an action upon activation (e.g. when clicked).

<Playground>
<Button>Perform Action</Button>
</Playground>
<Playground
code={`
<Button>
Perform Action
</Button>
`}
components={{ Button }}
/>

## Props

<Props of={Button} />
Props

## Usage Notes


+ 26
- 0
packages/react-common-docs/src/pages/components/Checkbox.mdx 查看文件

@@ -0,0 +1,26 @@
---
name: Checkbox
---

import { Checkbox } from '@tesseract-design/react-common'
import Playground from '../../components/Playground'

# Checkbox

Component for values that have an on/off state.

<Playground
components={{ Checkbox }}
code={`
<Checkbox label="Accept Terms" />
`}
/>

## Props

Props

## See Also

- [Select](./Select) for a similar component suitable for selecting more values.
- [RadioButton](./RadioButton) for a similar component on selecting a single value among very few choices.

+ 21
- 0
packages/react-common-docs/src/pages/components/Icon.mdx 查看文件

@@ -0,0 +1,21 @@
---
name: Icon
---

import { Icon } from '@tesseract-design/react-common'
import Playground from '../../components/Playground'

# Icon

Component for displaying graphics.

<Playground
components={{ Icon }}
code={`
<Icon name="check" label="OK" size="1.5rem" weight={0.125} />
`}
/>

## Props

Props

+ 33
- 0
packages/react-common-docs/src/pages/components/RadioButton.mdx 查看文件

@@ -0,0 +1,33 @@
---
name: RadioButton
---

import { RadioButton } from '@tesseract-design/react-common'
import Playground from '../../components/Playground'

# RadioButton

Component for values which are to be selected from a few list of options.

<Playground
components={{ RadioButton }}
code={`
<div style={{ display: 'grid', gap: '1rem', }}>
<div>
<RadioButton name="flavor" label="Chocolate" />
</div>
<div>
<RadioButton name="flavor" label="Vanilla" />
</div>
</div>
`}
/>

## Props

Props

## See Also

- [Checkbox](./Checkbox) for a similar component on selecting values among very few choices.
- [Select](./Select) for a similar component suitable for selecting more values.

+ 46
- 0
packages/react-common-docs/src/pages/components/Select.mdx 查看文件

@@ -0,0 +1,46 @@
---
name: Select
---

import { Select } from '@tesseract-design/react-common'
import Playground from '../../components/Playground'

# Select

Component for selecting values from a larger number of options.

<Playground
components={{ Select }}
code={`
<Select>
<optgroup
label="Fruits"
>
<option value="mango">Mango</option>
<option value="strawberry">Strawberry</option>
<option value="blueberry">Blueberry</option>
</optgroup>
<optgroup
label="Classic"
>
<option value="chocolate">Chocolate</option>
<option value="vanilla">Vanilla</option>
</optgroup>
</Select>
`}
/>

## Props

Props

## Usage Notes

The component will behave as `block`, i.e. it takes the remaining of the horizontal space.
To use the component together with layouts, see [TextInput](./TextInput) for examples. Both `Select` and
`TextInput` have similar strategies on usage with layouts.

## See Also

- [Checkbox](./Checkbox) for a similar component on selecting values among very few choices.
- [RadioButton](./RadioButton) for a similar component on selecting a single value among very few choices.

lib/components/Slider/Slider.mdx → packages/react-common-docs/src/pages/components/Slider.mdx 查看文件

@@ -1,11 +1,9 @@
---
name: Slider
route: /components/slider
menu: Components
---

import { Playground, Props } from 'docz'
import Slider from './Slider'
import { Slider } from '@tesseract-design/react-common'
import Playground from '../../components/Playground'

# Slider

@@ -14,13 +12,16 @@ Component for inputting numeric values in a graphical manner.
The component is styled using client-side scripts. When the component is rendered server-side,
the component falls back into the original `<input type="range">` element.

<Playground>
<Slider />
</Playground>
<Playground
components={{ Slider }}
code={`
<Slider />
`}
/>

## Props

<Props of={Slider} />
Props

## See Also


+ 78
- 0
packages/react-common-docs/src/pages/components/TextInput.mdx 查看文件

@@ -0,0 +1,78 @@
---
name: TextInput
---

import { TextInput } from '@tesseract-design/react-common'
import Playground from '../../components/Playground'

# TextInput

Component for inputting textual values.

<Playground
components={{ TextInput }}
code={`
<TextInput label="Username" placeholder="johndoe" hint="the name you use to log in" />
`}
/>

## Props

Props

## Usage Notes

The component will behave as `block`, i.e. it takes the remaining of the horizontal space.
To use the component together with layouts, see the following examples.

### Inline

The components are surrounded by `inline-block` elements. These surrounding elements have specified widths, which could
act as guide to the user on how long the expected input values are.

<Playground
components={{ TextInput }}
code={`
<form>
I am <span style={{ display: 'inline-block', width: '16rem', }}><TextInput label="Full name" hint="given and family name" /></span> and I live in <span style={{ display: 'inline-block', width: '24rem', }}><TextInput label="Address" hint="city, state and country" /></span>.
</form>
`}
/>

### Grid

It is advisable to put surrounding elements instead of the `TextInput` components themselves as children of the
element specified as `grid`. This is to be able to add complementing content to the components, if for example there are
some content that is best displayed outside the component instead of putting in the `hint` prop.

<Playground
components={{ TextInput }}
code={`
<form
style={{ display: 'grid', gridTemplateColumns: '4fr 4fr 5fr', gap: '1rem', }}
>
<div style={{ gridColumnStart: 1, gridColumnEnd: 4, }}>
<TextInput label="Address line 1" hint="unit/house number, building" />
</div>
<div style={{ gridColumnStart: 1, gridColumnEnd: 4, }}>
<TextInput label="Address line 2" hint="street, area" />
</div>
<div>
<TextInput size="large" label="City/Town" />
</div>
<div>
<TextInput size="large" label="State/Province" />
</div>
<div>
<TextInput size="large" label="Country" hint="abbreviations are accepted" />
<small>
Consult the <a href="#">fees table</a> for shipping fee details.
</small>
</div>
</form>
`}
/>

## See Also

- [Select](./Select) for a graphically-similar component suitable for selecting more values.

+ 1
- 0
packages/react-common-docs/src/pages/index.md 查看文件

@@ -0,0 +1 @@
../../../../README.md

docs/theming.md → packages/react-common-docs/src/pages/theming.md 查看文件


+ 18
- 0
packages/react-common-docs/src/sidebar.json 查看文件

@@ -0,0 +1,18 @@
{
"nav": [
{
"Theming": "/theming"
},
{
"Components": [
{ "Button": "/components/Button" },
{ "Checkbox": "/components/Checkbox" },
{ "Icon": "/components/Icon" },
{ "RadioButton": "/components/RadioButton" },
{ "Select": "/components/Select" },
{ "Slider": "/components/Slider" },
{ "TextInput": "/components/TextInput" }
]
}
]
}

+ 37
- 0
packages/react-common-docs/tsconfig.json 查看文件

@@ -0,0 +1,37 @@
{
"compilerOptions": {
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "preserve",
"declaration": true,
"declarationDir": "./dist",
"sourceMap": true
},
"exclude": [
"node_modules",
"**/*.test.ts",
"**/*.test.tsx",
"utilities/**/*",
"jest.setup.ts"
],
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx"
]
}

+ 6489
- 0
packages/react-common-docs/yarn.lock
文件差異過大導致無法顯示
查看文件


lib/components/Button/Button.test.tsx → packages/react-common/components/Button/Button.test.tsx 查看文件

@@ -1,5 +1,5 @@
/// <reference types="jest-enzyme" />
/// <reference path="../../../utilities/jest/extensions.ts" />
/// <reference path="../../../../utilities/jest/extensions.ts" />

import * as fc from 'fast-check'
import * as Enzyme from 'enzyme'

lib/components/Button/Button.tsx → packages/react-common/components/Button/Button.tsx 查看文件


lib/components/Checkbox/Checkbox.test.tsx → packages/react-common/components/Checkbox/Checkbox.test.tsx 查看文件

@@ -1,5 +1,5 @@
/// <reference types="jest-enzyme" />
/// <reference path="../../../utilities/jest/extensions.ts" />
/// <reference path="../../../../utilities/jest/extensions.ts" />

import * as fc from 'fast-check'
import * as Enzyme from 'enzyme'

lib/components/Checkbox/Checkbox.tsx → packages/react-common/components/Checkbox/Checkbox.tsx 查看文件


lib/components/Icon/Icon.test.tsx → packages/react-common/components/Icon/Icon.test.tsx 查看文件

@@ -1,5 +1,5 @@
/// <reference types="jest-enzyme" />
/// <reference path="../../../utilities/jest/extensions.ts" />
/// <reference path="../../../../utilities/jest/extensions.ts" />

import * as fc from 'fast-check'
import * as Enzyme from 'enzyme'

lib/components/Icon/Icon.tsx → packages/react-common/components/Icon/Icon.tsx 查看文件


lib/components/RadioButton/RadioButton.test.tsx → packages/react-common/components/RadioButton/RadioButton.test.tsx 查看文件

@@ -1,5 +1,5 @@
/// <reference types="jest-enzyme" />
/// <reference path="../../../utilities/jest/extensions.ts" />
/// <reference path="../../../../utilities/jest/extensions.ts" />

import * as fc from 'fast-check'
import * as Enzyme from 'enzyme'

lib/components/RadioButton/RadioButton.tsx → packages/react-common/components/RadioButton/RadioButton.tsx 查看文件


lib/components/Select/Select.test.tsx → packages/react-common/components/Select/Select.test.tsx 查看文件

@@ -1,5 +1,5 @@
/// <reference types="jest-enzyme" />
/// <reference path="../../../utilities/jest/extensions.ts" />
/// <reference path="../../../../utilities/jest/extensions.ts" />

import * as fc from 'fast-check'
import * as Enzyme from 'enzyme'

lib/components/Select/Select.tsx → packages/react-common/components/Select/Select.tsx 查看文件


lib/components/Slider/Slider.test.tsx → packages/react-common/components/Slider/Slider.test.tsx 查看文件

@@ -1,5 +1,5 @@
/// <reference types="jest-enzyme" />
/// <reference path="../../../utilities/jest/extensions.ts" />
/// <reference path="../../../../utilities/jest/extensions.ts" />

import * as fc from 'fast-check'
import * as Enzyme from 'enzyme'

lib/components/Slider/Slider.tsx → packages/react-common/components/Slider/Slider.tsx 查看文件


lib/components/TextInput/TextInput.test.tsx → packages/react-common/components/TextInput/TextInput.test.tsx 查看文件

@@ -1,5 +1,5 @@
/// <reference types="jest-enzyme" />
/// <reference path="../../../utilities/jest/extensions.ts" />
/// <reference path="../../../../utilities/jest/extensions.ts" />

import * as fc from 'fast-check'
import * as Enzyme from 'enzyme'

lib/components/TextInput/TextInput.tsx → packages/react-common/components/TextInput/TextInput.tsx 查看文件


lib/index.test.ts → packages/react-common/index.test.ts 查看文件

@@ -1,5 +1,5 @@
/// <reference types="jest-enzyme" />
/// <reference path="../utilities/jest/extensions.ts" />
/// <reference path="../../utilities/jest/extensions.ts" />

import * as T from './index'


lib/index.ts → packages/react-common/index.ts 查看文件


+ 40
- 0
packages/react-common/services/isEmpty.test.ts 查看文件

@@ -0,0 +1,40 @@
import * as fc from 'fast-check'
import isEmpty from './isEmpty'

it('should exist', () => {
expect(isEmpty).toBeDefined()
})

it('should be a function', () => {
expect(typeof isEmpty).toBe('function')
})

it('should accept 1 argument', () => {
expect(isEmpty).toHaveLength(1)
})

it('should return a boolean value', () => {
fc.assert(
fc.property(fc.anything(), (v) => {
expect(typeof isEmpty(v)).toBe('boolean')
}),
)
})

describe('on arguments', () => {
it('should return `true` on an argument with value of `undefined`', () => {
expect(isEmpty(undefined)).toBe(true)
})

it('should return `true` on an argument with value of `null`', () => {
expect(isEmpty(null)).toBe(true)
})

it('should return `false` on an argument with value that is neither `undefined` nor `null`', () => {
fc.assert(
fc.property(fc.anything().filter((v) => typeof v !== 'undefined' && v !== null), (v) => {
expect(isEmpty(v)).toBe(false)
}),
)
})
})

lib/services/isEmpty.ts → packages/react-common/services/isEmpty.ts 查看文件


lib/services/splitValueAndUnit.test.ts → packages/react-common/services/splitValueAndUnit.test.ts 查看文件


lib/services/splitValueAndUnit.ts → packages/react-common/services/splitValueAndUnit.ts 查看文件


lib/services/stringify.test.ts → packages/react-common/services/stringify.test.ts 查看文件

@@ -1,5 +1,5 @@
import * as fc from 'fast-check'
import * as fcArb from '../../utilities/fast-check/arbitraries'
import * as fcArb from '../../../utilities/fast-check/arbitraries'
import stringify from './stringify'

it('should exist', () => {

lib/services/stringify.ts → packages/react-common/services/stringify.ts 查看文件


lib/services/utilities.ts → packages/react-common/services/utilities.ts 查看文件


+ 1
- 1
plopfile.js 查看文件

@@ -23,7 +23,7 @@ module.exports = plop => {
type: 'addMany',
templateFiles: 'plop/templates/component/*',
base: 'plop/templates/component',
destination: 'lib/components/{{pascalCase name}}',
destination: 'packages/react-common/components/{{pascalCase name}}',
},
],
})


+ 1
- 1
rollup.config.js 查看文件

@@ -4,7 +4,7 @@ import typescript from '@rollup/plugin-typescript'

import pkg from './package.json'

const ENTRY_POINT = './lib/index.ts'
const ENTRY_POINT = './packages/react-common/index.ts'

export default {
input: ENTRY_POINT,


Loading…
取消
儲存