`.
6 |
7 | Uses [Tailwind CSS font size](https://tailwindcss.com/docs/font-size) scaling.
8 |
9 | ```js
10 | import { Text } from 'minerva-ui';
11 | ```
12 |
13 | ```jsx live
14 |
Text
15 | ```
16 |
17 | ## Text Font Sizes
18 |
19 | ```jsx live
20 |
21 | Extra Small Text
22 | Small Text
23 | Medium Text
24 | Large Text
25 | Extra Large Text
26 | 2x Large Text
27 |
28 | ```
29 |
30 | ## Props
31 |
32 | These are props related to the Text component.
33 |
34 | | Name | Type | Is Required | Default | Description |
35 | | ------------ | ------ | ----------- | ------- | ------------------------ |
36 | | `lineHeight` | string | optional | normal | Sets line height of font |
37 |
--------------------------------------------------------------------------------
/docs/pages/components/Tooltip.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: 'Tooltip'
3 | ---
4 |
5 | The `
` component displays a small pop-up that display additional information when hovered or focused.
6 |
7 | ```js
8 | import { Tooltip } from 'minerva-ui';
9 | ```
10 |
11 | ```jsx live
12 |
13 |
14 |
15 | ```
16 |
17 | # Tooltip with Custom Position
18 |
19 | ```jsx live
20 |
21 |
22 |
23 | ```
24 |
25 | # Tooltip with Custom Styles
26 |
27 | ```js
28 | import { Tooltip } from 'minerva-ui';
29 | ```
30 |
31 | ```jsx live
32 |
33 |
34 |
35 | ```
36 |
37 | ## Props
38 |
39 | | Name | Type | Is Required | Default | Description |
40 | | ---------- | -------------------------------- | ----------- | -------- | -------------------------- |
41 | | `label` | `string` | optional | `null` | Text to display in tooltip |
42 | | `position` | `top`, `right`, `bottom`, `left` | optional | `bottom` | Text to display in tooltip |
43 |
--------------------------------------------------------------------------------
/docs/pages/homepage.tsx:
--------------------------------------------------------------------------------
1 | import Layout from '../components/homepage-components/Layout';
2 | import HomeBody from '../components/homepage-components/HomeBody';
3 |
4 | export default function HomePage() {
5 | return (
6 |
7 |
8 |
9 | );
10 | }
11 |
--------------------------------------------------------------------------------
/docs/pages/meta.json:
--------------------------------------------------------------------------------
1 | {
2 | "index": "Getting Started",
3 | "overview": "Overview",
4 | "concepts": "Concepts",
5 | "theming": "Theming",
6 | "utility-props": "Utility Props",
7 | "responsive-styling": "Responsive Styling",
8 | "components": "Components",
9 | "utilities": "Utilities",
10 | "examples": "Examples",
11 | "change-log": "Change Log"
12 | }
--------------------------------------------------------------------------------
/docs/pages/overview/meta.json:
--------------------------------------------------------------------------------
1 | {
2 | "responsive-styling": "Responsive Styling",
3 | "utility-props": "Utility Props"
4 | }
--------------------------------------------------------------------------------
/docs/pages/theme-builder.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { defaultIcons, defaultTheme, ThemeProvider } from 'minerva-ui';
3 | import { createGlobalStyle } from 'styled-components';
4 | import { AppProvider } from '../components/theme-builder/AppContext';
5 | import ThemeBuilder from '../components/theme-builder/ThemeBuilder';
6 |
7 | const ThemeBuilderStyles = createGlobalStyle`
8 | html, body {
9 | background-color: #fff;
10 | color: #333;
11 | }
12 | `;
13 |
14 | function ThemeBuilderPage() {
15 | return (
16 |
17 |
18 |
19 |
20 |
21 |
22 | );
23 | }
24 |
25 | export default ThemeBuilderPage;
26 |
--------------------------------------------------------------------------------
/docs/pages/utilities/FontSizes.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Font Sizes
3 | ---
4 |
5 | import { Text, defaultTheme } from 'minerva-ui';
6 | import UtilityTable from '../../components/UtilityTable';
7 |
(
10 | Text font size sample
11 | )}
12 | />;
13 |
--------------------------------------------------------------------------------
/docs/pages/utilities/Layout.mdx:
--------------------------------------------------------------------------------
1 | Layout components help replace common patterns when building a UI.
2 |
3 | For example, `` saves you the time of having to write `` or ``.
4 |
5 | ## Box
6 |
7 | Basic `div` element with no defaults
8 |
9 | ```jsx live
10 | () => (
11 |
16 |
17 |
18 |
19 | );
20 | ```
21 |
22 | ## Flex
23 |
24 | Renders a `div` with `display: flex` set by default.
25 |
26 | ```jsx live
27 | () => (
28 |
33 |
34 |
35 |
36 | );
37 | ```
38 |
39 | ## Block
40 |
41 | Renders a `div` with `display: block` set by default.
42 |
43 | ```jsx live
44 | () => (
45 | <>
46 |
47 | First Block
48 |
49 |
50 | Second Block
51 |
52 | >
53 | );
54 | ```
55 |
--------------------------------------------------------------------------------
/docs/pages/utilities/Shadows.mdx:
--------------------------------------------------------------------------------
1 | import { defaultTheme } from 'minerva-ui';
2 | import UtilityTable from '../../components/UtilityTable';
3 |
4 | ```jsx noInline
5 | const Card = props => (
6 |
14 | );
15 |
16 | render(
17 |
18 | base
19 | md
20 | lg
21 | xl
22 | 2xl
23 | inner
24 | outline
25 | none
26 |
27 | );
28 | ```
29 |
30 | ## Shorthand Props
31 |
32 | ```jsx noInline
33 | const Card = props => (
34 |
42 | );
43 |
44 | render(
45 |
46 | base
47 |
48 | );
49 | ```
50 |
51 |
52 |
--------------------------------------------------------------------------------
/docs/pages/utilities/useClipboard.mdx:
--------------------------------------------------------------------------------
1 | import { useClipboard } from 'minerva-ui';
2 |
3 | `useClipboard` is a custom hook to handle copying content to clipboard.
4 |
5 | The useClipboard hook returns an object with the following fields:
6 |
7 | | Name | Type | Default | Description |
8 | | ----------- | -------- | ------- | ------------------------------------------------- |
9 | | `value` | string | | The copied value |
10 | | `onCopy` | function | | Action to copy content |
11 | | `hasCopied` | boolean | false | True if the content has been copied to clipboard. |
12 |
13 | ```js
14 | import { useClipboard } from 'minerva-ui';
15 | ```
16 |
17 | ## Usage
18 |
19 | ```jsx live
20 | function Example() {
21 | const [value, setValue] = useState('Hello World');
22 | const { onCopy, hasCopied } = useClipboard(value);
23 |
24 | return (
25 | <>
26 |
27 | setValue(e.target.value)} />
28 |
31 |
32 |
33 | >
34 | );
35 | }
36 | ```
37 |
--------------------------------------------------------------------------------
/docs/pages/utilities/useDisclosure.mdx:
--------------------------------------------------------------------------------
1 | import { useDisclosure } from 'minerva-ui';
2 |
3 | `useDisclosure` is a custom hook to help handle common open, close, or toggle scenarios. It can be used to control feedback component such as Modal, AlertDialog, Drawer, etc.
4 |
5 | ```js
6 | import { useDisclosure } from 'minerva-ui';
7 | ```
8 |
9 | The `useDisclosure` hook returns an object with the following fields:
10 |
11 | | Name | Type | Default | Description |
12 | | ---------- | -------- | ------- | ------------------------------------------------------ |
13 | | `isOpen` | boolean | false | If true, it sets the component to it's visible state. |
14 | | `onClose` | function | | Function that sets `isOpen` to false. |
15 | | `onOpen` | function | | Function that sets `isOpen` to true. |
16 | | `onToggle` | function | | Function that toggles `isOpen` between true and false. |
17 |
18 | ## Usage
19 |
20 | ```jsx live
21 | function Example() {
22 | const { isOpen, onOpen, onClose } = useDisclosure();
23 |
24 | return (
25 | <>
26 |
27 |
28 | Hello World!
29 |
30 | Sit nulla est ex deserunt exercitation anim occaecat. Nostrud ullamco
31 | deserunt aute id consequat veniam incididunt duis in sint irure nisi.
32 |
33 |
34 | >
35 | );
36 | }
37 | ```
38 |
--------------------------------------------------------------------------------
/docs/pages/utilities/useLocalStorage.mdx:
--------------------------------------------------------------------------------
1 | import { useLocalStorage } from 'minerva-ui';
2 |
3 | `useLocalStorage` is a custom hook to help handle storing data in Local Storage.
4 |
5 | ```js
6 | import { useLocalStorage } from 'minerva-ui';
7 | ```
8 |
9 | The `useLocalStorage` hook returns an object with the following fields:
10 |
11 | | Name | Type | Default | Description |
12 | | ---------- | -------- | ------- | ------------------------------------------------------ |
13 | | `isOpen` | boolean | false | If true, it sets the component to it's visible state. |
14 | | `onClose` | function | | Function that sets `isOpen` to false. |
15 | | `onOpen` | function | | Function that sets `isOpen` to true. |
16 | | `onToggle` | function | | Function that toggles `isOpen` between true and false. |
17 |
18 | ## Usage
19 |
20 | ```jsx live
21 | function Example() {
22 | const [count, setCount] = useLocalStorage('click-count', 0);
23 |
24 | return (
25 | <>
26 |
27 |
28 | You've clicked the button {count} times.
29 |
30 | >
31 | );
32 | }
33 | ```
34 |
--------------------------------------------------------------------------------
/docs/pages/utilities/useMedia.mdx:
--------------------------------------------------------------------------------
1 | import { useMedia } from 'minerva-ui';
2 |
3 | `useMedia` is a custom hook to handle media queries. It utilizes [json2mq](https://github.com/akiran/json2mq) to parse a string or object into json.
4 |
5 | The useMedia hook returns an object with the following fields:
6 |
7 | | Name | Type | Default | Description |
8 | | ------- | ------- | ------- | ------------------------------------------------- |
9 | | `match` | boolean | | True if the media query matches, false otherwise. |
10 |
11 | ```js
12 | import { useMedia } from 'minerva-ui';
13 | ```
14 |
15 | ## Usage
16 |
17 | ```jsx live
18 | function Example() {
19 | const small = useMedia('(max-width: 640px)');
20 | const medium = useMedia({ maxWidth: 768 });
21 |
22 | return (
23 | <>
24 |
25 |
26 | >
27 | );
28 | }
29 | ```
30 |
--------------------------------------------------------------------------------
/docs/pages/utilities/useNetwork.mdx:
--------------------------------------------------------------------------------
1 | import { useNetwork } from 'minerva-ui';
2 |
3 | `useNetwork` is a custom hook to check the network status to determine if the user is connected to the internet or not.
4 |
5 | The useNetwork hook returns an object with the following fields:
6 |
7 | | Name | Type | Default | Description |
8 | | -------------- | ------- | ------- | --------------------------------------------------------------- |
9 | | `onlineStatus` | boolean | | True if the user is connected to the internet, false otherwise. |
10 |
11 | ```js
12 | import { useNetwork } from 'minerva-ui';
13 | ```
14 |
15 | ## Usage
16 |
17 | ```jsx live
18 | function Example() {
19 | const online = useNetwork();
20 | // Disable network to view change
21 |
22 | return (
23 |
24 | Network {online ? 'Online' : 'Offline'}
25 |
26 | );
27 | }
28 | ```
29 |
--------------------------------------------------------------------------------
/docs/public/about_minerva_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cratebind/minerva-ui/c7826bb8255834a5312f2695686d2c0eb6885cca/docs/public/about_minerva_logo.png
--------------------------------------------------------------------------------
/docs/public/aboutpage_example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cratebind/minerva-ui/c7826bb8255834a5312f2695686d2c0eb6885cca/docs/public/aboutpage_example.png
--------------------------------------------------------------------------------
/docs/public/coffee.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cratebind/minerva-ui/c7826bb8255834a5312f2695686d2c0eb6885cca/docs/public/coffee.png
--------------------------------------------------------------------------------
/docs/public/demo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cratebind/minerva-ui/c7826bb8255834a5312f2695686d2c0eb6885cca/docs/public/demo.png
--------------------------------------------------------------------------------
/docs/public/ellipsis.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cratebind/minerva-ui/c7826bb8255834a5312f2695686d2c0eb6885cca/docs/public/ellipsis.png
--------------------------------------------------------------------------------
/docs/public/explore_icon.svg:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/docs/public/fonts/TiemposHeadline-Black.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cratebind/minerva-ui/c7826bb8255834a5312f2695686d2c0eb6885cca/docs/public/fonts/TiemposHeadline-Black.otf
--------------------------------------------------------------------------------
/docs/public/fonts/TiemposHeadline-BlackItalic.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cratebind/minerva-ui/c7826bb8255834a5312f2695686d2c0eb6885cca/docs/public/fonts/TiemposHeadline-BlackItalic.otf
--------------------------------------------------------------------------------
/docs/public/fonts/TiemposHeadline-Bold.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cratebind/minerva-ui/c7826bb8255834a5312f2695686d2c0eb6885cca/docs/public/fonts/TiemposHeadline-Bold.otf
--------------------------------------------------------------------------------
/docs/public/fonts/TiemposHeadline-BoldItalic.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cratebind/minerva-ui/c7826bb8255834a5312f2695686d2c0eb6885cca/docs/public/fonts/TiemposHeadline-BoldItalic.otf
--------------------------------------------------------------------------------
/docs/public/fonts/TiemposHeadline-Light.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cratebind/minerva-ui/c7826bb8255834a5312f2695686d2c0eb6885cca/docs/public/fonts/TiemposHeadline-Light.otf
--------------------------------------------------------------------------------
/docs/public/fonts/TiemposHeadline-LightItalic.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cratebind/minerva-ui/c7826bb8255834a5312f2695686d2c0eb6885cca/docs/public/fonts/TiemposHeadline-LightItalic.otf
--------------------------------------------------------------------------------
/docs/public/fonts/TiemposHeadline-Medium.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cratebind/minerva-ui/c7826bb8255834a5312f2695686d2c0eb6885cca/docs/public/fonts/TiemposHeadline-Medium.otf
--------------------------------------------------------------------------------
/docs/public/fonts/TiemposHeadline-MediumItalic.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cratebind/minerva-ui/c7826bb8255834a5312f2695686d2c0eb6885cca/docs/public/fonts/TiemposHeadline-MediumItalic.otf
--------------------------------------------------------------------------------
/docs/public/fonts/TiemposHeadline-Regular.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cratebind/minerva-ui/c7826bb8255834a5312f2695686d2c0eb6885cca/docs/public/fonts/TiemposHeadline-Regular.otf
--------------------------------------------------------------------------------
/docs/public/fonts/TiemposHeadline-RegularItalic.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cratebind/minerva-ui/c7826bb8255834a5312f2695686d2c0eb6885cca/docs/public/fonts/TiemposHeadline-RegularItalic.otf
--------------------------------------------------------------------------------
/docs/public/fonts/TiemposHeadline-Semibold.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cratebind/minerva-ui/c7826bb8255834a5312f2695686d2c0eb6885cca/docs/public/fonts/TiemposHeadline-Semibold.otf
--------------------------------------------------------------------------------
/docs/public/fonts/TiemposHeadline-SemiboldItalic.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cratebind/minerva-ui/c7826bb8255834a5312f2695686d2c0eb6885cca/docs/public/fonts/TiemposHeadline-SemiboldItalic.otf
--------------------------------------------------------------------------------
/docs/public/github_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cratebind/minerva-ui/c7826bb8255834a5312f2695686d2c0eb6885cca/docs/public/github_logo.png
--------------------------------------------------------------------------------
/docs/public/homepage_example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cratebind/minerva-ui/c7826bb8255834a5312f2695686d2c0eb6885cca/docs/public/homepage_example.png
--------------------------------------------------------------------------------
/docs/public/install_icon.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/docs/public/jonathan_profile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cratebind/minerva-ui/c7826bb8255834a5312f2695686d2c0eb6885cca/docs/public/jonathan_profile.png
--------------------------------------------------------------------------------
/docs/public/minerva_logo_purple.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cratebind/minerva-ui/c7826bb8255834a5312f2695686d2c0eb6885cca/docs/public/minerva_logo_purple.png
--------------------------------------------------------------------------------
/docs/public/minerva_logo_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cratebind/minerva-ui/c7826bb8255834a5312f2695686d2c0eb6885cca/docs/public/minerva_logo_white.png
--------------------------------------------------------------------------------
/docs/public/mountain_sky.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cratebind/minerva-ui/c7826bb8255834a5312f2695686d2c0eb6885cca/docs/public/mountain_sky.png
--------------------------------------------------------------------------------
/docs/public/owl.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cratebind/minerva-ui/c7826bb8255834a5312f2695686d2c0eb6885cca/docs/public/owl.png
--------------------------------------------------------------------------------
/docs/public/starry_sky.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cratebind/minerva-ui/c7826bb8255834a5312f2695686d2c0eb6885cca/docs/public/starry_sky.jpeg
--------------------------------------------------------------------------------
/docs/public/tim_profile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cratebind/minerva-ui/c7826bb8255834a5312f2695686d2c0eb6885cca/docs/public/tim_profile.png
--------------------------------------------------------------------------------
/docs/public/trust_icon.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/docs/public/unsplash.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cratebind/minerva-ui/c7826bb8255834a5312f2695686d2c0eb6885cca/docs/public/unsplash.jpeg
--------------------------------------------------------------------------------
/docs/public/wood_sky.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cratebind/minerva-ui/c7826bb8255834a5312f2695686d2c0eb6885cca/docs/public/wood_sky.jpeg
--------------------------------------------------------------------------------
/docs/theme.config.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export default {
4 | github: 'https://github.com/cratebind/minerva-ui',
5 | titleSuffix: ' – Minerva UI',
6 | logo: (
7 | <>
8 | Minerva UI
9 |
10 | Composable React Components
11 |
12 | >
13 | ),
14 | head: (
15 | <>
16 |
17 |
18 |
19 |
20 |
24 |
28 | {/* */}
29 | {/* */}
30 |
34 |
35 | >
36 | ),
37 | search: true,
38 | prevLinks: true,
39 | nextLinks: true,
40 | footer: true,
41 | footerEditOnGitHubLink: true,
42 | footerText: <>MIT {new Date().getFullYear()} © Cratebind.>,
43 | };
44 |
--------------------------------------------------------------------------------
/docs/theme/arrow-right.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const ArrowRight = ({ height = 24, ...props }) => {
4 | return (
5 |
14 | );
15 | };
16 |
17 | export default ArrowRight;
18 |
--------------------------------------------------------------------------------
/docs/theme/callout.tsx:
--------------------------------------------------------------------------------
1 | // import React from 'react';
2 |
3 | const Callout = ({ children, background = 'bg-orange-100', emoji = '💡' }) => {
4 | return (
5 |
6 | {emoji}
7 | {children}
8 | {/* */}
13 |
14 | );
15 | };
16 |
17 | // https://www.notion.so/Callout-blocks-5b2638247b54447eb2e21145f97194b0
18 | export default Callout;
19 |
--------------------------------------------------------------------------------
/docs/theme/github-icon.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const GithubIcon = ({ height = 40 }) => {
4 | return (
5 |
13 | );
14 | };
15 |
16 | export default GithubIcon;
17 |
--------------------------------------------------------------------------------
/docs/theme/misc/default.config.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export default {
4 | github: 'https://github.com/shuding/nextra',
5 | titleSuffix: ' – Nextra',
6 | nextLinks: true,
7 | prevLinks: true,
8 | search: true,
9 | footer: true,
10 | footerText: 'MIT 2020 © Shu Ding.',
11 | footerEditOnGitHubLink: true,
12 | logo: (
13 |
14 | Nextra
15 |
16 | The Next Docs Builder
17 |
18 |
19 | ),
20 | head: (
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | ),
34 | };
35 |
--------------------------------------------------------------------------------
/docs/theme/utils/flatten.ts:
--------------------------------------------------------------------------------
1 | export default function flatten(list) {
2 | return list.reduce((flat, toFlatten) => {
3 | return flat.concat(
4 | toFlatten.children ? flatten(toFlatten.children) : toFlatten
5 | );
6 | }, []);
7 | }
8 |
--------------------------------------------------------------------------------
/docs/theme/utils/reorder.ts:
--------------------------------------------------------------------------------
1 | import getTitle from 'title';
2 |
3 | export default function reorderBasedOnMeta(list) {
4 | let meta = list.find(item => item.name === 'meta.json');
5 | if (!meta) {
6 | meta = {};
7 | } else {
8 | meta = meta.meta;
9 | }
10 |
11 | const metaKeys = Object.keys(meta);
12 |
13 | return list
14 | .filter(a => {
15 | return a.name !== 'meta.json' && a.name !== '_app';
16 | })
17 | .sort((a, b) => {
18 | return metaKeys.indexOf(a.name) - metaKeys.indexOf(b.name);
19 | })
20 | .map(a => {
21 | return {
22 | ...a,
23 | children: a.children ? reorderBasedOnMeta(a.children) : undefined,
24 | title: meta[a.name] || getTitle(a.name),
25 | };
26 | });
27 | }
28 |
--------------------------------------------------------------------------------
/docs/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": [
5 | "dom",
6 | "dom.iterable",
7 | "esnext"
8 | ],
9 | "allowJs": true,
10 | "skipLibCheck": true,
11 | "strict": false,
12 | "forceConsistentCasingInFileNames": true,
13 | "noEmit": true,
14 | "esModuleInterop": true,
15 | "module": "esnext",
16 | "moduleResolution": "node",
17 | "resolveJsonModule": true,
18 | "isolatedModules": true,
19 | "jsx": "preserve"
20 | },
21 | "include": [
22 | "next-env.d.ts",
23 | "**/*.ts",
24 | "**/*.tsx",
25 | "theme/index.js",
26 | "types.d.ts"
27 | ],
28 | "exclude": [
29 | "node_modules"
30 | ]
31 | }
--------------------------------------------------------------------------------
/docs/types.d.ts:
--------------------------------------------------------------------------------
1 | export * from 'react';
2 |
3 | declare module 'react' {
4 | interface DOMAttributes {
5 | css?: InterpolationWithTheme;
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/example/.npmignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .cache
3 | dist
--------------------------------------------------------------------------------
/example/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Playground
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/example/index.tsx:
--------------------------------------------------------------------------------
1 | import 'react-app-polyfill/ie11';
2 | import * as React from 'react';
3 | import * as ReactDOM from 'react-dom';
4 | import { Button, Box } from '..';
5 | // import { Button, Box } from 'minerva-ui';
6 |
7 | const App = () => {
8 | return (
9 |
10 |
11 | This is a box
12 |
13 | );
14 | };
15 |
16 | ReactDOM.render(, document.querySelector('#root'));
17 |
--------------------------------------------------------------------------------
/example/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "example",
3 | "version": "1.0.0",
4 | "main": "index.js",
5 | "license": "MIT",
6 | "scripts": {
7 | "start": "parcel index.html",
8 | "build": "parcel build index.html"
9 | },
10 | "dependencies": {
11 | "minerva-ui": "7.0.0",
12 | "react-app-polyfill": "^1.0.0"
13 | },
14 | "alias": {
15 | "react": "../node_modules/react",
16 | "react-dom": "../node_modules/react-dom/profiling",
17 | "scheduler/tracing": "../node_modules/scheduler/tracing-profiling"
18 | },
19 | "devDependencies": {
20 | "@babel/core": "^7.12.10",
21 | "@types/react": "^16.9.11",
22 | "@types/react-dom": "^16.8.4",
23 | "parcel": "^1.12.3",
24 | "typescript": "^3.4.5"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/example/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "allowSyntheticDefaultImports": false,
4 | "target": "es5",
5 | "module": "commonjs",
6 | "jsx": "react",
7 | "moduleResolution": "node",
8 | "noImplicitAny": false,
9 | "noUnusedLocals": false,
10 | "noUnusedParameters": false,
11 | "removeComments": true,
12 | "strictNullChecks": true,
13 | "preserveConstEnums": true,
14 | "sourceMap": true,
15 | "lib": ["es2015", "es2016", "dom"],
16 | "types": ["node"]
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/lerna.json:
--------------------------------------------------------------------------------
1 | {
2 | "packages": [
3 | ".",
4 | "docs"
5 | ],
6 | "version": "independent",
7 | "npmClient": "yarn"
8 | }
--------------------------------------------------------------------------------
/register.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { addons, types } from '@storybook/addons';
3 | import { useParameter } from '@storybook/api';
4 | import { AddonPanel } from '@storybook/components';
5 |
6 | const ADDON_ID = 'myaddon';
7 | const PARAM_KEY = 'myAddon';
8 | const PANEL_ID = `${ADDON_ID}/panel`;
9 |
10 | const MyPanel = () => {
11 | const value = useParameter(PARAM_KEY, null);
12 |
13 | return {value}
;
14 | };
15 |
16 | addons.register(ADDON_ID, api => {
17 | const render = ({ active, key }) => (
18 |
19 |
20 |
21 | );
22 | const title = 'My Addon';
23 |
24 | addons.add(PANEL_ID, {
25 | type: types.PANEL,
26 | title,
27 | render,
28 | paramKey: PARAM_KEY,
29 | });
30 | });
31 |
--------------------------------------------------------------------------------
/src/Alert/Alert.stories.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Alert } from '../Alert';
3 | import Button from '../Button';
4 | import { Close } from '../Icon/baseIcons';
5 |
6 | import { defaultIcons, defaultTheme, ThemeProvider } from '..';
7 | import { filteredArgs } from '../utils';
8 |
9 | export default {
10 | title: 'Alert',
11 | component: Alert,
12 | argTypes: {
13 | ...filteredArgs,
14 | },
15 | };
16 |
17 | const Provider = props => (
18 |
19 | );
20 |
21 | export const Statuses = () => {
22 | return (
23 |
24 |
25 | Something not great is happening.
26 |
27 |
28 |
29 | Something great is happening!
30 |
31 |
32 |
33 | Something is happening that isn't bad yet, but might be soon.
34 |
35 |
36 |
37 | Something is happening and you should know about it.
38 |
39 |
40 | );
41 | };
42 |
43 | export const Hidden = () => {
44 | const [open, setOpen] = React.useState(false);
45 |
46 | return (
47 |
48 |
49 | {open && (
50 |
51 | Something not great is happening!
52 |
62 |
63 | )}
64 |
65 | );
66 | };
67 |
68 | export const Custom = () => (
69 |
70 |
71 |
72 | Here is some information.
73 |
74 | );
75 |
--------------------------------------------------------------------------------
/src/Box.stories.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Meta, Story } from '@storybook/react';
3 | import { Box, BoxProps, Stack } from '.';
4 |
5 | const meta: Meta = {
6 | title: 'Box',
7 | component: Box,
8 | argTypes: {
9 | children: {
10 | control: {
11 | type: 'text',
12 | },
13 | },
14 | },
15 | parameters: {
16 | controls: { expanded: true },
17 | },
18 | };
19 |
20 | export default meta;
21 |
22 | const Template: Story = (args: Omit) => (
23 |
24 | );
25 |
26 | export const Default = Template.bind({});
27 | Default.args = {
28 | children: 'Basic Box',
29 | };
30 |
31 | export const PseudoProps = () => (
32 |
33 | Hover Box
34 |
35 | Focus Button
36 |
37 |
38 | );
39 |
40 | // export const Variants = () => (
41 | //
42 | //
43 | //
44 | //
45 | //
46 | // );
47 |
48 | // export const LoadingButton = Template.bind({});
49 | // LoadingButton.args = {
50 | // children: 'Basic Button',
51 | // isLoading: true,
52 | // };
53 |
54 | // export const DisabledButton = Template.bind({});
55 | // DisabledButton.args = {
56 | // children: 'Basic Button',
57 | // disabled: true,
58 | // };
59 |
--------------------------------------------------------------------------------
/src/Button/Button.stories.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Meta, Story } from '@storybook/react';
3 | import { Button, ButtonProps } from '.';
4 | import { Stack } from '..';
5 |
6 | const meta: Meta = {
7 | title: 'Button',
8 | component: Button,
9 | argTypes: {
10 | children: {
11 | control: {
12 | type: 'text',
13 | },
14 | },
15 | },
16 | parameters: {
17 | controls: { expanded: true },
18 | },
19 | };
20 |
21 | export default meta;
22 |
23 | const Template: Story = (args: Omit) => (
24 |
25 | );
26 |
27 | export const Default = Template.bind({});
28 | Default.args = {
29 | children: 'Basic Button',
30 | };
31 |
32 | export const Variants = () => (
33 |
34 |
35 |
36 |
37 |
38 | );
39 |
40 | export const LoadingButton = Template.bind({});
41 | LoadingButton.args = {
42 | children: 'Basic Button',
43 | isLoading: true,
44 | };
45 |
46 | export const DisabledButton = Template.bind({});
47 | DisabledButton.args = {
48 | children: 'Basic Button',
49 | disabled: true,
50 | };
51 |
--------------------------------------------------------------------------------
/src/Checkbox/Checkbox.stories.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Meta, Story } from '@storybook/react';
3 | import { Checkbox, CheckboxProps } from '.';
4 |
5 | const meta: Meta = {
6 | title: 'Checkbox',
7 | component: Checkbox,
8 | argTypes: {
9 | children: {
10 | control: {
11 | type: 'text',
12 | },
13 | },
14 | },
15 | parameters: {
16 | controls: { expanded: true },
17 | },
18 | };
19 |
20 | export default meta;
21 |
22 | const Template: Story = args => {
23 | const [checked, setChecked] = React.useState(true);
24 | return (
25 | setChecked(!checked)}
28 | {...args}
29 | />
30 | );
31 | };
32 |
33 | export const Basic = Template.bind({});
34 | Basic.args = {
35 | children: 'Stay Logged In',
36 | };
37 |
--------------------------------------------------------------------------------
/src/Combobox/Combobox.stories.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Meta, Story } from '@storybook/react';
3 | import {
4 | Combobox,
5 | ComboboxInput,
6 | ComboboxPopover,
7 | ComboboxList,
8 | ComboboxOption,
9 | ComboboxOptionText,
10 | } from '.';
11 | import { filteredArgs } from '../utils';
12 |
13 | const meta: Meta = {
14 | title: 'Combobox',
15 | component: Combobox,
16 | subcomponents: {
17 | ComboboxInput,
18 | ComboboxPopover,
19 | ComboboxList,
20 | ComboboxOption,
21 | ComboboxOptionText,
22 | },
23 | argTypes: {
24 | ...filteredArgs,
25 | },
26 | parameters: {
27 | controls: { expanded: true },
28 | },
29 | };
30 |
31 | export default meta;
32 |
33 | const Template: Story = () => {
34 | return (
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 | );
45 | };
46 |
47 | export const Basic = Template.bind({});
48 | Basic.args = {};
49 |
50 | export const NoPortal = () => {
51 | return (
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 | );
62 | };
63 |
--------------------------------------------------------------------------------
/src/Combobox/index.tsx:
--------------------------------------------------------------------------------
1 | import React, { InputHTMLAttributes, ReactNode } from 'react';
2 | import {
3 | Combobox as ReachCombobox,
4 | ComboboxInput as ReachComboboxInput,
5 | ComboboxPopover as ReachComboboxPopover,
6 | ComboboxList as ReachComboboxList,
7 | ComboboxOption as ReachComboboxOption,
8 | ComboboxOptionText as ReachComboboxOptionText,
9 | ComboboxProps,
10 | ComboboxInputProps,
11 | ComboboxPopoverProps,
12 | ComboboxListProps,
13 | ComboboxOptionProps,
14 | } from '@reach/combobox';
15 | // import css from '@styled-system/css';
16 |
17 | import Input from '../Input';
18 | import { OverlayBox } from '../Menu';
19 | import { Box, MinervaProps } from '../layout';
20 |
21 | export const Combobox = (props: ComboboxProps) => ;
22 |
23 | export const ComboboxInput = (
24 | props: ComboboxInputProps & InputHTMLAttributes
25 | ) => ;
26 |
27 | export const ComboboxPopover = ({
28 | portal = true,
29 | ...props
30 | }: ComboboxPopoverProps & MinervaProps) => {
31 | const Popover = props => ;
32 | return (
33 |
43 | );
44 | };
45 |
46 | export const ComboboxList = (
47 | props: ComboboxListProps & { children?: ReactNode }
48 | ) => ;
49 |
50 | export const ComboboxOption = (props: ComboboxOptionProps & MinervaProps) => (
51 |
63 | );
64 |
65 | export const ComboboxOptionText = (props: MinervaProps) => (
66 |
67 | );
68 |
--------------------------------------------------------------------------------
/src/Drawer/Drawer.stories.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Meta, Story } from '@storybook/react';
3 | import Drawer, {
4 | DrawerBody,
5 | DrawerHeader,
6 | DrawerFooter,
7 | DrawerProps,
8 | } from '../Drawer';
9 | import Button from '../Button';
10 | import { Flex } from '..';
11 | import { filteredArgs } from '../utils';
12 |
13 | const meta: Meta = {
14 | title: 'Drawer',
15 | component: Drawer,
16 | subcomponents: {
17 | DrawerBody,
18 | DrawerHeader,
19 | DrawerFooter,
20 | },
21 | argTypes: {
22 | ...filteredArgs,
23 | placement: {},
24 | },
25 | parameters: {
26 | controls: { expanded: true },
27 | },
28 | };
29 |
30 | export default meta;
31 |
32 | const Template: Story = ({
33 | placement = 'right',
34 | isOpen = false,
35 | }) => {
36 | const [open, setOpen] = React.useState(isOpen);
37 |
38 | return (
39 | <>
40 |
41 | setOpen(false)}
45 | overflow="hidden"
46 | >
47 | setOpen(false)}>Hello World!
48 |
49 | Sit nulla est ex deserunt exercitation anim occaecat. Nostrud ullamco
50 | deserunt aute id consequat veniam incididunt duis in sint irure nisi.
51 |
52 |
53 |
60 |
67 |
68 |
69 |
70 | >
71 | );
72 | };
73 |
74 | export const Basic = Template.bind({});
75 | Basic.args = {};
76 |
--------------------------------------------------------------------------------
/src/Heading/Heading.stories.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Meta, Story } from '@storybook/react';
3 | import { Heading, HeadingProps } from '.';
4 | import { filteredArgs } from '../utils';
5 |
6 | const meta: Meta = {
7 | title: 'Heading',
8 | component: Heading,
9 | argTypes: {
10 | children: {
11 | control: {
12 | type: 'text',
13 | },
14 | },
15 | ...filteredArgs,
16 | },
17 | parameters: {
18 | controls: { expanded: true },
19 | },
20 | };
21 |
22 | export default meta;
23 |
24 | const Template: Story = args => ;
25 |
26 | export const Default = Template.bind({});
27 | Default.args = {
28 | children: 'Basic Heading',
29 | };
30 |
31 | export const Heading2 = Template.bind({});
32 | Heading2.args = {
33 | children: 'H2 Heading',
34 | as: 'h2',
35 | };
36 |
--------------------------------------------------------------------------------
/src/Heading/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { MinervaProps, Box } from '../layout';
3 | import { useComponentStyles } from '../theme';
4 |
5 | export interface HeadingProps extends MinervaProps {
6 | children?: React.ReactNode;
7 | }
8 |
9 | export const Heading = React.forwardRef(function Heading(
10 | { children, fontSize = '2xl', ...props }: HeadingProps,
11 | ref
12 | ) {
13 | const componentStyles = useComponentStyles('Heading');
14 |
15 | return (
16 |
26 | {children}
27 |
28 | );
29 | });
30 |
31 | export default Heading;
32 |
33 | // if (__DEV__) {
34 | // Heading.propTypes = {
35 | // children: PropTypes.node,
36 | // };
37 | // }
38 |
--------------------------------------------------------------------------------
/src/Icon/Icon.stories.mdx:
--------------------------------------------------------------------------------
1 | import { Meta, Story, Preview, Props } from '@storybook/addon-docs/blocks';
2 | import Icon from '../Icon';
3 |
4 |
5 |
6 | # Icon
7 |
8 | Basic icon component. SVGs can be added to the `icons` prop in your theme.
9 |
10 | The default theme includes [Feather Icons](https://feathericons.com/).
11 |
12 | ```js
13 | import { Icon } from 'minerva-ui'
14 | ```
15 |
16 | ```jsx
17 |
18 | ```
19 |
20 | ## Color
21 | ```jsx
22 | <>
23 |
24 |
25 | >
26 | ```
27 |
28 | ## Size
29 | ```jsx
30 | <>
31 |
32 |
33 | >
34 | ```
35 |
36 |
--------------------------------------------------------------------------------
/src/Icon/baseIcons.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | // import { Box } from '../layout';
3 |
4 | type BaseIconProps = {
5 | color?: string;
6 | size?: number | string;
7 | };
8 |
9 | export const Close = ({
10 | color = 'currentColor',
11 | size = 24,
12 | ...props
13 | }: BaseIconProps) => (
14 |
45 | );
46 |
47 | export const ChevronDown = ({
48 | color = 'currentColor',
49 | size = 24,
50 | ...props
51 | }: BaseIconProps) => (
52 |
69 | );
70 |
71 | // basic UI icons used throughout the component library
72 | const baseIcons = {
73 | Close,
74 | ChevronDown,
75 | };
76 |
77 | export default baseIcons;
78 |
--------------------------------------------------------------------------------
/src/Icon/index.tsx:
--------------------------------------------------------------------------------
1 | import React, { forwardRef } from 'react';
2 | // import PropTypes from 'prop-types';
3 | import { MinervaProps, Box } from '../layout';
4 | import { useTheme } from '../theme';
5 | import { ResponsiveValue } from 'styled-system';
6 |
7 | export interface IconProps {
8 | /**
9 | * Name of icon
10 | */
11 | name: string;
12 | /**
13 | * Height and width of icon (in pixels)
14 | */
15 | // size?: number | string;
16 | size?: ResponsiveValue;
17 | /**
18 | * Icon color
19 | */
20 | color?: string;
21 | }
22 |
23 | export const Icon = forwardRef(function Icon(
24 | { size = '32px', name, color = '#000', ...props }: MinervaProps & IconProps,
25 | ref
26 | ) {
27 | const theme = useTheme();
28 |
29 | if (!theme || !theme.icons || !theme.icons[name]) {
30 | if (process.env.NODE_ENV === 'development') {
31 | // in dev, give a more descriptive error to help debugging
32 | console.error(`Could not find icon in theme with name of ${name}`);
33 | console.error(`Icons in theme: ${Object.keys(theme.icons).join('\n')}`);
34 | } else {
35 | console.warn(`Could not find icon in theme with name of ${name}`);
36 | return null;
37 | }
38 | }
39 |
40 | const IconComponent = theme.icons[name] || null;
41 |
42 | return (
43 |
54 | );
55 | });
56 |
57 | export default Icon;
58 |
59 | // if (__DEV__) {
60 | // Icon.propTypes = {
61 | // name: PropTypes.string.isRequired,
62 | // color: PropTypes.string,
63 | // };
64 | // }
65 |
--------------------------------------------------------------------------------
/src/Image/Image.stories.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Meta, Story } from '@storybook/react';
3 | import { filteredArgs } from '../utils';
4 | import { Image, ImageProps } from '.';
5 |
6 | const meta: Meta = {
7 | title: 'Image',
8 | component: Image,
9 | argTypes: {
10 | ...filteredArgs,
11 | },
12 | parameters: {
13 | controls: { expanded: true },
14 | },
15 | };
16 |
17 | export default meta;
18 |
19 | const Template: Story = args => {
20 | return ;
21 | };
22 |
23 | export const Basic = Template.bind({});
24 | Basic.args = {
25 | src: 'https://source.unsplash.com/random',
26 | maxWidth: '20rem',
27 | alt: 'Random image from unsplash',
28 | };
29 |
--------------------------------------------------------------------------------
/src/Image/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import warning from 'tiny-warning';
3 | // import PropTypes from 'prop-types';
4 | import { MinervaProps, Box } from '../layout';
5 | import { useComponentStyles } from '../theme';
6 | // import PseudoBox, { PseudoBoxProps } from '../PseudoBox';
7 |
8 | // type BaseProps = MinervaProps &
9 | // React.ImgHTMLAttributes ;
10 |
11 | export interface ImageProps extends MinervaProps {
12 | /**
13 | * Path or URL to image source
14 | */
15 | src?: string;
16 | /**
17 | * Alternate text that describes image for screen reader users
18 | */
19 | alt?: string;
20 | }
21 |
22 | export const Image = React.forwardRef(function Image(
23 | { src, alt, ...props }: ImageProps,
24 | ref
25 | ) {
26 | const componentStyles = useComponentStyles('Image');
27 |
28 | warning(Boolean(alt), 'Images require an `alt` attribute to be accessible.');
29 |
30 | return (
31 |
39 | );
40 | });
41 |
42 | export default Image;
43 |
44 | // if (__DEV__) {
45 | // Image.propTypes = {
46 | // src: PropTypes.string,
47 | // alt: PropTypes.string,
48 | // };
49 | // }
50 |
--------------------------------------------------------------------------------
/src/Input/Input.stories.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Meta, Story } from '@storybook/react';
3 | import { filteredArgs } from '../utils';
4 | import { Input, InputProps } from '.';
5 |
6 | const meta: Meta = {
7 | title: 'Input',
8 | component: Input,
9 | argTypes: {
10 | disabled: {
11 | control: 'boolean',
12 | },
13 | ...filteredArgs,
14 | },
15 | parameters: {
16 | controls: { expanded: true },
17 | },
18 | };
19 |
20 | export default meta;
21 |
22 | const Template: Story = args => {
23 | const [name, setName] = React.useState('');
24 |
25 | return (
26 | setName(e.target.value)}
29 | placeholder="Basic Input"
30 | {...args}
31 | />
32 | );
33 | };
34 |
35 | export const Basic = Template.bind({});
36 | Basic.args = {};
37 |
38 | export const Disabled = Template.bind({});
39 | Disabled.args = {
40 | disabled: true,
41 | };
42 |
43 | export const Textarea = Template.bind({});
44 | Textarea.args = {
45 | as: 'textarea',
46 | };
47 |
--------------------------------------------------------------------------------
/src/Input/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import warning from 'tiny-warning';
3 | import { Box, MinervaProps } from '../layout';
4 | import { useComponentStyles } from '../theme';
5 |
6 | type BaseProps = React.InputHTMLAttributes & MinervaProps;
7 |
8 | export interface InputProps extends BaseProps {
9 | /** Toggles disabled pseudo class */
10 | disabled?: boolean;
11 | /** allows input to be labeled for accessibility */
12 | hiddenLabel?: string;
13 | }
14 |
15 | export const Input = React.forwardRef(function Input(
16 | { hiddenLabel, ...props }: InputProps,
17 | ref
18 | ) {
19 | // return ;
20 | const componentStyles = useComponentStyles('Input');
21 |
22 | warning(
23 | !hiddenLabel,
24 | 'Inputs without associated labels require a `hiddenLabel` attribute to be accessible.'
25 | );
26 |
27 | return (
28 |
35 | );
36 | });
37 |
38 | export default Input;
39 |
--------------------------------------------------------------------------------
/src/InputField/InputField.stories.mdx:
--------------------------------------------------------------------------------
1 | import { useState } from 'react';
2 | import { Meta, Story, Preview, Props } from '@storybook/addon-docs/blocks';
3 | import InputField from '../InputField';
4 | import Input from '../Input';
5 |
6 |
7 |
8 | # Input Field
9 |
10 | ### Basic Input Field component
11 |
12 | ```js
13 | import { InputField, Input } from 'minerva-ui';
14 | ```
15 |
16 | ```jsx
17 | () => {
18 | const [name, setName] = React.useState('');
19 | const [error, setError] = React.useState('');
20 |
21 | return (
22 |
23 | setError('This field cannot be empty') : null}
27 | onChange={e => {
28 | setError('');
29 | setName(e.target.value);
30 | }}
31 | >
32 |
33 | );
34 | };
35 | ```
36 |
37 | # Variants
38 |
39 | ### Input Field with custom error message styles
40 |
41 | ```jsx
42 | () => {
43 | const [name, setName] = React.useState('');
44 | const [error, setError] = React.useState('');
45 |
46 | return (
47 |
51 | setError('This field cannot be empty') : null}
55 | onChange={e => {
56 | setError('');
57 | setName(e.target.value);
58 | }}
59 | >
60 |
61 | );
62 | };
63 | ```
64 |
65 | ### Required Input Field
66 |
67 | ```jsx
68 | () => {
69 | const [name, setName] = React.useState('');
70 | const [error, setError] = React.useState('');
71 |
72 | return (
73 |
78 | setError('This field cannot be empty') : null}
82 | onChange={e => {
83 | setError('');
84 | setName(e.target.value);
85 | }}
86 | >
87 |
88 | );
89 | };
90 | ```
91 |
92 |
93 |
--------------------------------------------------------------------------------
/src/InputField/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styled from 'styled-components';
3 | // import PropTypes from 'prop-types';
4 | import { Text } from '../Text';
5 | import { systemProps, Box } from '../layout';
6 |
7 | export const InputFieldGroup = styled('div')(
8 | props => ({
9 | ...props.theme.InputField,
10 | }),
11 | systemProps
12 | );
13 |
14 | export interface InputFieldProps {
15 | children?: React.ReactNode;
16 | label?: string;
17 | errorText?: string;
18 | isRequired?: boolean;
19 | // requiredMarkerColor?: string;
20 | }
21 |
22 | // export const StyledRequiredMarker = styled(Text)(() => {
23 | // return {
24 | // display: 'inline-block',
25 | // marginLeft: '3px',
26 | // };
27 | // });
28 |
29 | // export const RequiredMarker = ({ color }) => {
30 | // return (
31 | //
32 | // *
33 | //
34 | // );
35 | // };
36 |
37 | export const RequiredMarker = props => (
38 |
45 | *
46 |
47 | );
48 |
49 | export const FieldErrorMessage = styled(Box)`
50 | font-size: 12px;
51 | font-weight: 400;
52 | color: #ff0000;
53 | `;
54 |
55 | export const FieldLabel = styled.label`
56 | display: block;
57 | position: relative;
58 | margin-bottom: 8px;
59 | line-height: 1.5;
60 | `;
61 |
62 | const InputField = ({
63 | children,
64 | label,
65 | errorText,
66 | isRequired,
67 | ...props
68 | }: InputFieldProps) => {
69 | return (
70 |
71 |
72 |
73 | {label}{' '}
74 | {isRequired && }
75 |
76 | {children}
77 |
78 |
79 | {errorText && (
80 | {errorText}
81 | )}
82 |
83 | );
84 | };
85 |
86 | export default InputField;
87 |
88 | // if (__DEV__) {
89 | // InputField.propTypes = {
90 | // children: PropTypes.node,
91 | // label: PropTypes.string,
92 | // errorText: PropTypes.string,
93 | // isRequired: PropTypes.bool,
94 | // };
95 | // }
96 |
--------------------------------------------------------------------------------
/src/Link/Link.stories.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Meta, Story } from '@storybook/react';
3 | import { filteredArgs } from '../utils';
4 | import { Link, LinkProps } from '.';
5 |
6 | const meta: Meta = {
7 | title: 'Link',
8 | component: Link,
9 | argTypes: {
10 | ...filteredArgs,
11 | },
12 | parameters: {
13 | controls: { expanded: true },
14 | },
15 | };
16 |
17 | export default meta;
18 |
19 | const Template: Story = args => {
20 | return ;
21 | };
22 |
23 | export const Basic = Template.bind({});
24 | Basic.args = {
25 | children: 'Basic Link',
26 | href: 'https://github.com',
27 | };
28 |
29 | export const External = Template.bind({});
30 | External.args = {
31 | children: 'External Link',
32 | href: 'https://github.com',
33 | isExternal: true,
34 | };
35 |
--------------------------------------------------------------------------------
/src/Link/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | // import styled from 'styled-components';
3 | // import PropTypes from 'prop-types';
4 | // import { systemProps } from '../layout';
5 | // import PseudoBox from '../PseudoBox';
6 | import { useComponentStyles } from '../theme';
7 | import { Box, MinervaProps } from '../layout';
8 |
9 | type BaseProps = MinervaProps & React.LinkHTMLAttributes;
10 |
11 | export interface LinkProps extends BaseProps {
12 | children?: React.ReactNode;
13 | href?: string;
14 | /** If `true`, the link will open in new tab */
15 | isExternal?: boolean;
16 | }
17 |
18 | /**
19 | * Links are tags used for navigation.
20 | *
21 | * @see Docs @TODO
22 | */
23 | export const Link = React.forwardRef(function Link(
24 | { children, href, isExternal, ...props }: LinkProps,
25 | ref
26 | ) {
27 | const componentStyles = useComponentStyles('Link');
28 | const externalProps = isExternal
29 | ? { target: '_blank', rel: 'noopener noreferrer' }
30 | : null;
31 |
32 | return (
33 |
42 | {children}
43 |
44 | );
45 | });
46 |
47 | export default Link;
48 |
49 | // if (__DEV__) {
50 | // Link.propTypes = {
51 | // children: PropTypes.node,
52 | // href: PropTypes.string,
53 | // isExternal: PropTypes.bool,
54 | // };
55 | // }
56 |
--------------------------------------------------------------------------------
/src/Menu/Menu.stories.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Meta, Story } from '@storybook/react';
3 | import {
4 | MenuContainer,
5 | MenuContainerProps,
6 | MenuButton,
7 | MenuList,
8 | MenuItem,
9 | MenuLink,
10 | MenuDivider,
11 | } from '.';
12 | import { Icon } from '..';
13 | import { filteredArgs } from '../utils';
14 | import { Flex } from '../layout';
15 |
16 | const meta: Meta = {
17 | title: 'Menu',
18 | component: MenuContainer,
19 | subcomponents: {
20 | MenuButton,
21 | MenuList,
22 | MenuItem,
23 | MenuLink,
24 | },
25 | argTypes: {
26 | ...filteredArgs,
27 | placement: {},
28 | },
29 | parameters: {
30 | controls: { expanded: true },
31 | },
32 | };
33 |
34 | export default meta;
35 |
36 | const Template: Story = ({}) => {
37 | return (
38 | <>
39 |
40 |
41 | Actions
42 |
43 |
44 |
45 |
46 |
49 |
50 |
51 | Open Documentation
52 |
53 |
54 |
55 | >
56 | );
57 | };
58 |
59 | export const Basic = Template.bind({});
60 | Basic.args = {};
61 |
62 | export const PositionedRight = () => (
63 |
64 |
65 |
66 | Actions
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | );
75 |
76 | export const DisabledItems = () => (
77 |
78 |
79 | Actions
80 |
81 |
82 |
83 |
86 |
87 | Sign Out
88 |
89 |
90 | );
91 |
--------------------------------------------------------------------------------
/src/Modal/Modal.stories.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Meta, Story } from '@storybook/react';
3 | import Modal, {
4 | ModalBody,
5 | ModalHeader,
6 | ModalFooter,
7 | ModalProps,
8 | } from '../Modal';
9 | import Button from '../Button';
10 | import { Flex } from '..';
11 | import { filteredArgs } from '../utils';
12 |
13 | const meta: Meta = {
14 | title: 'Modal',
15 | component: Modal,
16 | subcomponents: {
17 | ModalBody,
18 | ModalHeader,
19 | ModalFooter,
20 | },
21 | argTypes: {
22 | ...filteredArgs,
23 | placement: {},
24 | },
25 | parameters: {
26 | controls: { expanded: true },
27 | },
28 | };
29 |
30 | export default meta;
31 |
32 | const Template: Story = ({ isOpen = false }) => {
33 | const [open, setOpen] = React.useState(isOpen);
34 |
35 | return (
36 | <>
37 |
38 | setOpen(false)} overflow="hidden">
39 | setOpen(false)}>Hello World!
40 |
41 | Sit nulla est ex deserunt exercitation anim occaecat. Nostrud ullamco
42 | deserunt aute id consequat veniam incididunt duis in sint irure nisi.
43 | Mollit officia cillum Lorem ullamco minim nostrud elit officia tempor
44 | esse quis. Sunt ad dolore quis aute consequat.
45 |
46 |
47 |
54 |
61 |
62 |
63 |
64 | >
65 | );
66 | };
67 |
68 | export const Basic = Template.bind({});
69 | Basic.args = {};
70 |
--------------------------------------------------------------------------------
/src/PseudoBox/PseudoBox.stories.mdx:
--------------------------------------------------------------------------------
1 | import { Meta, Story, Preview, Props } from '@storybook/addon-docs/blocks';
2 | import PseudoBox from '../PseudoBox';
3 |
4 |
5 |
6 | # PseudoBox
7 |
8 | Basic `div` component with additional props for CSS pseudo selectors.
9 |
10 | ```jsx
11 |
24 | ```
25 |
26 |
--------------------------------------------------------------------------------
/src/Radio/Radio.stories.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Meta, Story } from '@storybook/react';
3 | import { filteredArgs } from '../utils';
4 | import { Radio, RadioGroup, RadioProps } from '.';
5 |
6 | const meta: Meta = {
7 | title: 'Radio',
8 | component: RadioGroup,
9 | argTypes: {
10 | disabled: {
11 | control: 'boolean',
12 | },
13 | ...filteredArgs,
14 | },
15 | subcomponents: {
16 | Radio,
17 | },
18 | parameters: {
19 | controls: { expanded: true },
20 | },
21 | };
22 |
23 | export default meta;
24 |
25 | const Template: Story = args => {
26 | const [value, setValue] = React.useState('test');
27 | return (
28 | setValue(e.target.value)} value={value}>
29 |
30 | Meat
31 |
32 | Vegetarian
33 | Supreme
34 |
35 | );
36 | };
37 |
38 | export const Basic = Template.bind({});
39 | Basic.args = {};
40 |
41 | export const Disabled = Template.bind({});
42 | Disabled.args = {
43 | disabled: true,
44 | };
45 |
--------------------------------------------------------------------------------
/src/Select/Select.stories.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Meta, Story } from '@storybook/react';
3 | import { filteredArgs } from '../utils';
4 | import { Select, SelectProps } from '.';
5 |
6 | const meta: Meta = {
7 | title: 'Select',
8 | component: Select,
9 | argTypes: {
10 | disabled: {
11 | control: 'boolean',
12 | },
13 | ...filteredArgs,
14 | },
15 | parameters: {
16 | controls: { expanded: true },
17 | },
18 | };
19 |
20 | export default meta;
21 |
22 | const Template: Story = args => {
23 | return (
24 |
29 | );
30 | };
31 |
32 | export const Basic = Template.bind({});
33 | Basic.args = {};
34 |
35 | export const Disabled = Template.bind({});
36 | Disabled.args = {
37 | disabled: true,
38 | };
39 |
--------------------------------------------------------------------------------
/src/Skeleton/Skeleton.stories.mdx:
--------------------------------------------------------------------------------
1 | import { Meta, Story, Preview, Props } from '@storybook/addon-docs/blocks';
2 | import { Skeleton } from '../Skeleton';
3 | import Text from '../Text';
4 | import Icon from '../Icon';
5 | import Image from '../Image';
6 | import Box from '../layout';
7 | import Button from '../Button';
8 |
9 |
10 |
11 | # Skeleton
12 |
13 | Animated loading skeleton that automatically adapts to your app.
14 |
15 | ```js
16 | import { Text } from 'minerva-ui';
17 | ```
18 |
19 | ```jsx
20 | () => {
21 | const [data, setData] = React.useState('');
22 | return {data ? test : }
;
23 | };
24 | ```
25 |
26 | ### Circular loading skeleton
27 |
28 | ```jsx
29 | () => ;
30 | ```
31 |
32 | ### Three-line loading skeleton with custom gap and width. Gap defaults to 10px
33 |
34 | ```jsx
35 | () => {
36 | const [data, setData] = React.useState('');
37 | return (
38 |
39 | {data ? (
40 | test
41 | ) : (
42 |
43 | )}
44 |
45 | );
46 | };
47 | ```
48 |
49 | ### Use the button to toggle between the 'loaded' and 'loading' states of the image
50 |
51 | ```jsx
52 | () => {
53 | const [loading, setLoading] = React.useState(false);
54 | return (
55 | <>
56 |
59 |
60 | {!loading ? (
61 |
67 | ) : (
68 |
69 | )}
70 |
71 | >
72 | );
73 | };
74 | ```
75 |
--------------------------------------------------------------------------------
/src/Skeleton/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | // import PropTypes from 'prop-types';
3 | import styled, { keyframes } from 'styled-components';
4 | import { MinervaProps, Box } from '../layout';
5 | import { useTheme } from '../theme';
6 | import Stack from '../Stack';
7 |
8 | export interface SkeletonProps extends MinervaProps {
9 | count?: number;
10 | gap?: string;
11 | }
12 |
13 | const pulseKeyframes = keyframes`
14 | from {
15 | background-position: 0% 0%;
16 | }
17 |
18 | to {
19 | background-position: -135% 0%;
20 | }
21 | `;
22 |
23 | export const SkeletonItem = styled(Box)`
24 | display: inline-block;
25 | background: linear-gradient(-90deg, #f0f0f0 0%, #f8f8f8 50%, #f0f0f0 100%);
26 | background-size: 400% 400%;
27 | animation: 1.2s ease-in-out infinite alternate ${pulseKeyframes};
28 |
29 | &::before {
30 | content: '\00a0';
31 | }
32 | `;
33 |
34 | export const Skeleton = ({
35 | count = 1,
36 | width = '100%',
37 | height = '2rem',
38 | borderRadius = '5px',
39 | gap = '10px',
40 | ...props
41 | }: SkeletonProps) => {
42 | const theme = useTheme();
43 | const elements: JSX.Element[] = [];
44 | for (let i = 0; i < count; i++) {
45 | elements.push(
46 |
56 | );
57 | }
58 | return (
59 |
60 | {elements}
61 |
62 | );
63 | };
64 |
65 | export default Skeleton;
66 |
67 | // if (__DEV__) {
68 | // Skeleton.propTypes = {
69 | // count: PropTypes.number,
70 | // gap: PropTypes.string,
71 | // };
72 | // }
73 |
--------------------------------------------------------------------------------
/src/Spinner/Spinner.stories.mdx:
--------------------------------------------------------------------------------
1 | import { Meta, Story, Preview, Props } from '@storybook/addon-docs/blocks';
2 | import Spinner from '../Spinner';
3 |
4 |
5 |
6 | # Spinner
7 |
8 | Basic button component
9 |
10 | ```js
11 | import { Spinner } from 'minerva-ui'
12 | ```
13 |
14 | ```jsx
15 |
16 | ```
17 |
18 |
--------------------------------------------------------------------------------
/src/Spinner/index.tsx:
--------------------------------------------------------------------------------
1 | import React, { forwardRef } from 'react';
2 | // import PropTypes from 'prop-types';
3 | import styled, { css, keyframes } from 'styled-components';
4 | import { Block } from '../layout';
5 |
6 | const spin = keyframes`
7 | 0% {
8 | transform: rotate(0deg);
9 | }
10 | 100% {
11 | transform: rotate(360deg);
12 | }
13 | `;
14 |
15 | export interface SpinnerProps {
16 | /**
17 | * size of spinner
18 | */
19 | size?: string;
20 | /**
21 | * The color of the empty area in the spinner
22 | */
23 | emptyColor?: string;
24 | /**
25 | * The color of the spinner
26 | */
27 | color?: string;
28 | /**
29 | * The thickness of the spinner
30 | * @example
31 | * ```jsx
32 | *
33 | * ```
34 | */
35 | thickness?: string;
36 | /**
37 | * For accessibility, it's important to add a fallback loading text.
38 | * This text will be visible to screen readers.
39 | */
40 | label?: string;
41 | }
42 |
43 | const StyledSpinner = styled(Block)(
44 | {
45 | display: 'inline-block',
46 | borderBottomColor: 'transparent',
47 | borderLeftColor: 'transparent',
48 | borderRightColor: 'currentColor',
49 | borderTopColor: 'currentColor',
50 | borderRadius: '9999px',
51 | color: 'currentColor',
52 | borderStyle: 'solid',
53 | height: '20px',
54 | width: '20px',
55 | borderWidth: '2px',
56 | margin: '2px',
57 | },
58 | css`
59 | animation: ${spin} 0.45s linear infinite;
60 | `
61 | );
62 |
63 | /* const animation = css`
64 | ${spin} 0.45s linear infinite
65 | `; */
66 |
67 | export type SpinnerRef = HTMLDivElement;
68 |
69 | export const Spinner = forwardRef(
70 | ({ color = '#777', size = '20px', thickness = '2px', ...rest }, ref) => {
71 | return (
72 |
80 | );
81 | }
82 | );
83 |
84 | Spinner.displayName = 'Spinner';
85 |
86 | export default Spinner;
87 |
88 | // if (__DEV__) {
89 | // Spinner.propTypes = {
90 | // size: PropTypes.string,
91 | // emptyColor: PropTypes.string,
92 | // color: PropTypes.string,
93 | // thickness: PropTypes.string,
94 | // label: PropTypes.string,
95 | // };
96 | // }
97 |
--------------------------------------------------------------------------------
/src/Stack/Stack.stories.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Stack, Flex, Image, Text } from '..';
3 |
4 | export default {
5 | title: 'Stack',
6 | component: Stack,
7 | };
8 |
9 | const Card = ({
10 | children,
11 | direction = 'row',
12 | }: {
13 | children: React.ReactNode;
14 | direction?: 'row' | 'column';
15 | }) => (
16 |
23 |
28 |
29 |
30 | {children}
31 |
32 |
33 | Lorem ipsum dolor sit amet, consectetur adipisicing elit
34 |
35 |
36 |
37 | );
38 |
39 | export const Basic = () => {
40 | return (
41 |
42 | Item 1
43 | Item 2
44 | Item 3
45 |
46 | );
47 | };
48 |
49 | export const Horizontal = () => {
50 | return (
51 |
52 | Item 1
53 | Item 2
54 | Item 3
55 |
56 | );
57 | };
58 |
59 | export const CustomGap = () => {
60 | return (
61 |
62 | Item 1
63 | Item 2
64 | Item 3
65 |
66 | );
67 | };
68 |
--------------------------------------------------------------------------------
/src/Stack/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | // import PropTypes from 'prop-types';
3 | import styled from 'styled-components';
4 | import { systemProps, Flex, MinervaProps } from '../layout';
5 | import { ForwardRefComponent } from '../utilities/polymorphic';
6 |
7 | export interface StackProps extends MinervaProps {
8 | children?: React.ReactNode;
9 | /**
10 | * Space between items in stack
11 | * @default 10px
12 | */
13 | gap?: string;
14 | /**
15 | * change stack direction to horizontal
16 | * @default false
17 | */
18 | horizontal?: boolean;
19 | }
20 | const StyledStack = styled(Flex)`
21 | flex-direction: ${(p: any) => (p.horizontal ? 'row' : 'column')};
22 |
23 | > * + * {
24 | ${(p: any) =>
25 | p.horizontal ? `margin-left: ${p.gap}` : `margin-top: ${p.gap}`};
26 | }
27 |
28 | ${systemProps}
29 | `;
30 |
31 | export const Stack = React.forwardRef(function Stack(
32 | { children, gap = '10px', horizontal = false, ...props }: StackProps,
33 | ref
34 | ) {
35 | return (
36 |
37 | {children}
38 |
39 | );
40 | }) as ForwardRefComponent<'div', StackProps>;
41 |
42 | export default Stack;
43 |
44 | // if (__DEV__) {
45 | // Stack.propTypes = {
46 | // children: PropTypes.node,
47 | // gap: PropTypes.string,
48 | // horizontal: PropTypes.bool,
49 | // };
50 | // }
51 |
--------------------------------------------------------------------------------
/src/Switch/Switch.stories.mdx:
--------------------------------------------------------------------------------
1 | import { Meta, Story, Preview, Props } from '@storybook/addon-docs/blocks';
2 | import Switch from '../Switch';
3 |
4 |
5 |
6 | # Switch
7 |
8 | ```js
9 | import { Switch } from 'minerva-ui';
10 | ```
11 |
12 | ```jsx
13 | () => {
14 | const [checked, setChecked] = React.useState(false);
15 | return (
16 | setChecked(!checked)}
20 | >
21 | );
22 | };
23 | ```
24 |
25 |
26 |
27 | # Variants
28 |
29 | ### Switch with size variant
30 |
31 | ```jsx
32 | () => {
33 | const [checked, setChecked] = React.useState(false);
34 | return (
35 | <>
36 | setChecked(!checked)}
41 | >
42 | >
43 | );
44 | };
45 | ```
46 |
47 | ### Switch with size and color variant
48 |
49 | ```jsx
50 | () => {
51 | const [checked, setChecked] = React.useState(false);
52 | return (
53 | <>
54 | setChecked(!checked)}
60 | >
61 | >
62 | );
63 | };
64 | ```
65 |
--------------------------------------------------------------------------------
/src/Table/Table.stories.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Meta, Story } from '@storybook/react';
3 | import Table, {
4 | TableHeader,
5 | TableRow,
6 | TableHeaderCell,
7 | TableBody,
8 | TableCell,
9 | CustomTableProps,
10 | } from '.';
11 | import { Link } from '..';
12 | import { filteredArgs } from '../utils';
13 |
14 | const meta: Meta = {
15 | title: 'Table',
16 | component: Table,
17 | subcomponents: {
18 | TableHeader,
19 | TableRow,
20 | TableHeaderCell,
21 | TableBody,
22 | TableCell,
23 | },
24 | argTypes: {
25 | ...filteredArgs,
26 | placement: {},
27 | },
28 | parameters: {
29 | controls: { expanded: true },
30 | },
31 | };
32 |
33 | export default meta;
34 |
35 | const Template: Story = ({}) => {
36 | return (
37 | <>
38 |
39 |
40 |
41 | Name
42 | Job
43 | Status
44 | Role
45 |
46 |
47 |
48 |
49 |
50 | Test
51 | Tester
52 | Testing
53 | Test Master
54 |
55 | Edit
56 |
57 |
58 |
59 | Test
60 | Tester
61 | Testing
62 | Test Master
63 |
64 | Edit
65 |
66 |
67 |
68 |
69 | >
70 | );
71 | };
72 |
73 | export const Basic = Template.bind({});
74 | Basic.args = {};
75 |
--------------------------------------------------------------------------------
/src/Tabs/Tabs.stories.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Meta, Story } from '@storybook/react';
3 | import { Tabs, TabList, Tab, TabPanels, TabPanel, TabsProps } from '../Tabs';
4 | import { filteredArgs } from '../utils';
5 |
6 | const meta: Meta = {
7 | title: 'Tabs',
8 | component: Tabs,
9 | subcomponents: {
10 | TabList,
11 | Tab,
12 | TabPanels,
13 | TabPanel,
14 | },
15 | argTypes: {
16 | ...filteredArgs,
17 | },
18 | parameters: {
19 | controls: { expanded: true },
20 | },
21 | };
22 |
23 | export default meta;
24 |
25 | const Template: Story = ({}) => {
26 | return (
27 | <>
28 |
29 |
30 | My Account
31 | Favorites
32 | Orders
33 | Billing
34 |
35 |
36 |
37 | My Account!
38 |
39 |
40 | Favorites!
41 |
42 |
43 | Orders!
44 |
45 |
46 | Billing!
47 |
48 |
49 |
50 | >
51 | );
52 | };
53 |
54 | export const Basic = Template.bind({});
55 | Basic.args = {};
56 |
--------------------------------------------------------------------------------
/src/Tag/Tag.stories.mdx:
--------------------------------------------------------------------------------
1 | import { Meta, Story, Preview, Props } from '@storybook/addon-docs/blocks';
2 | import Tag, { TagButton } from '../Tag';
3 |
4 |
5 |
6 | # Tag
7 |
8 | Basic Tag component
9 |
10 | ```js
11 | import { Tag } from 'minerva-ui';
12 | ```
13 |
14 | ```jsx
15 |
16 | #photography
17 | #nature
18 | #travel
19 |
20 | ```
21 |
22 |
23 |
24 |
25 | ## Closeable Tag
26 | ```jsx
27 |
28 | #photography
29 | #nature
30 | #travel
31 |
32 | ```
--------------------------------------------------------------------------------
/src/Tag/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | // import PropTypes from 'prop-types';
3 | import styled from 'styled-components';
4 | // import { Close } from '../Icon/baseIcons';
5 |
6 | import { MinervaProps, Box } from '../layout';
7 | // import { Icon } from '../Icon';
8 | import { useComponentStyles } from '../theme';
9 | import Button from '../Button';
10 | import { PseudoBoxProps } from '..';
11 | import { ForwardRefComponent } from '../utilities/polymorphic';
12 | // import { ForwardRefComponent } from '../utilities/polymorphic';
13 |
14 | export const TagIcon = styled(Button)`
15 | margin-left: 5px;
16 | margin-top: 1px;
17 | &:hover {
18 | cursor: pointer;
19 | }
20 | `;
21 |
22 | // const StyledTag = styled(Box)(
23 | // props => ({
24 | // display: 'inline-flex',
25 | // alignItems: 'center',
26 | // backgroundColor: '#EDF2F7',
27 | // borderRadius: '5px',
28 | // padding: '8px 10px',
29 | // fontSize: '16px',
30 | // ...props.theme.Tag,
31 | // }),
32 | // systemProps
33 | // );
34 |
35 | export interface TagProps extends MinervaProps, PseudoBoxProps {
36 | children?: React.ReactNode;
37 | }
38 |
39 | // export interface TagButtonProps extends MinervaProps, PseudoBoxProps {
40 | // iconName?: string;
41 | // }
42 |
43 | // export const TagButton = React.forwardRef(function TagButton(
44 | // { iconName, ...props }: TagButtonProps,
45 | // ref
46 | // ) {
47 | // return (
48 | //
62 | // );
63 | // });
64 |
65 | export const Tag = React.forwardRef(function Tag({ children, ...props }, ref) {
66 | const componentStyles = useComponentStyles('Tag');
67 | return (
68 |
69 | {children}
70 |
71 | );
72 | }) as ForwardRefComponent<'div', TagProps>;
73 |
74 | export default Tag;
75 |
76 | // if (__DEV__) {
77 | // Tag.propTypes = {
78 | // children: PropTypes.node,
79 | // };
80 |
81 | // TagButton.propTypes = {
82 | // iconName: PropTypes.string,
83 | // };
84 | // }
85 |
--------------------------------------------------------------------------------
/src/Text/Text.stories.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Meta, Story } from '@storybook/react';
3 | import { Text, TextProps } from '.';
4 | import { filteredArgs } from '../utils';
5 |
6 | const meta: Meta = {
7 | title: 'Text',
8 | component: Text,
9 | argTypes: {
10 | children: {
11 | control: {
12 | type: 'text',
13 | },
14 | },
15 | ...filteredArgs,
16 | },
17 | parameters: {
18 | controls: { expanded: true },
19 | },
20 | };
21 |
22 | export default meta;
23 |
24 | const Template: Story = (args: TextProps) => ;
25 |
26 | export const Default = Template.bind({});
27 | Default.args = {
28 | children: 'Basic Text',
29 | };
30 |
31 | export const Heading1 = () => (
32 |
33 | Heading 1
34 |
35 | );
36 |
37 | export const Heading2 = Template.bind({});
38 | Heading2.args = {
39 | children: 'H2 Text',
40 | as: 'h2',
41 | };
42 |
--------------------------------------------------------------------------------
/src/Text/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { PseudoBoxProps } from '..';
3 | // import PropTypes from 'prop-types';
4 | import { MinervaProps, Box } from '../layout';
5 | import { useComponentStyles } from '../theme';
6 | // import { ForwardRefComponent } from '../utilities/polymorphic';
7 |
8 | export interface TextProps extends MinervaProps, PseudoBoxProps {
9 | children?: React.ReactNode;
10 | }
11 |
12 | export const Text = React.forwardRef(function Text(
13 | { children, as = 'p', ...props }: TextProps,
14 | ref
15 | ) {
16 | const componentStyles = useComponentStyles('Text');
17 |
18 | return (
19 |
28 | {children}
29 |
30 | );
31 | });
32 |
33 | Text.displayName = 'Text';
34 |
35 | // export default Text;
36 |
37 | // if (__DEV__) {
38 | // Text.propTypes = {
39 | // children: PropTypes.node,
40 | // };
41 | // }
42 |
--------------------------------------------------------------------------------
/src/ThemeProvider.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { ThemeProvider as StyledThemeProvider } from 'styled-components';
3 | import defaultTheme from './theme';
4 |
5 | // const defaultTheme = {};
6 |
7 | export interface ProviderProps {
8 | /** theme config object to style components */
9 | theme?: object;
10 | /** array of a type! */
11 | children?: React.ReactNode;
12 | }
13 |
14 | function ThemeProvider({ theme = defaultTheme, children }: ProviderProps) {
15 | return {children};
16 | }
17 |
18 | // const useTheme = () => {
19 | // const theme = useContext(ThemeContext);
20 | // if (theme === undefined) {
21 | // throw new Error('useTheme must be used within a ThemeProvider');
22 | // }
23 | // return theme;
24 | // };
25 |
26 | export default ThemeProvider;
27 | // export { useTheme };
28 |
--------------------------------------------------------------------------------
/src/Tooltip/Tooltip.stories.mdx:
--------------------------------------------------------------------------------
1 | import { Meta, Story, Preview, Props } from '@storybook/addon-docs/blocks';
2 | import Tooltip from '../Tooltip';
3 | import { Box } from '../layout';
4 | import { Button } from '../Button';
5 |
6 |
7 |
8 | # Tooltip
9 |
10 | Basic tooltip that pops up when hovering its child component
11 |
12 | ```js
13 | import { Tooltip } from 'minerva-ui'
14 | ```
15 |
16 | ```jsx
17 |
20 |
21 |
22 | ```
23 |
24 | # Tooltip with Custom Position
25 |
26 | ```js
27 | import { Tooltip } from 'minerva-ui'
28 | ```
29 |
30 | ```jsx
31 |
35 |
36 |
37 | ```
38 |
39 | # Tooltip with Custom Styles
40 |
41 | ```js
42 | import { Tooltip } from 'minerva-ui'
43 | ```
44 |
45 | ```jsx
46 |
51 |
52 |
53 | ```
54 |
55 |
--------------------------------------------------------------------------------
/src/VisuallyHidden/index.tsx:
--------------------------------------------------------------------------------
1 | import styled from 'styled-components';
2 | import PseudoBox from '../PseudoBox';
3 |
4 | const VisuallyHidden = styled(PseudoBox as any)`
5 | border: 0px;
6 | clip: rect(0px, 0px, 0px, 0px);
7 | height: 1px;
8 | width: 1px;
9 | margin: -1px;
10 | padding: 0px;
11 | overflow: hidden;
12 | white-space: nowrap;
13 | position: absolute;
14 | `;
15 |
16 | export default VisuallyHidden;
17 |
--------------------------------------------------------------------------------
/src/hooks/useClipboard.ts:
--------------------------------------------------------------------------------
1 | import { useState, useEffect, useCallback } from 'react';
2 | import copy from 'copy-to-clipboard';
3 |
4 | // Heavily influenced by Chakra UI hook:
5 | // https://github.com/chakra-ui/chakra-ui/blob/master/packages/chakra-ui/src/useClipboard/index.js
6 | function useClipboard(value) {
7 | const [hasCopied, setHasCopied] = useState(false);
8 |
9 | const onCopy = useCallback(() => {
10 | const didCopy = copy(value);
11 | setHasCopied(didCopy);
12 | }, [value]);
13 |
14 | useEffect(() => {
15 | if (hasCopied) {
16 | const id = setTimeout(() => {
17 | setHasCopied(false);
18 | }, 1500);
19 |
20 | return () => clearTimeout(id);
21 | }
22 |
23 | return;
24 | }, [hasCopied]);
25 |
26 | return { value, onCopy, hasCopied };
27 | }
28 |
29 | export default useClipboard;
30 |
--------------------------------------------------------------------------------
/src/index.d.ts:
--------------------------------------------------------------------------------
1 | export { Checkbox as default } from './Checkbox';
2 |
3 | declare module '@mdx-js/react';
4 |
--------------------------------------------------------------------------------
/src/useClipboard/index.tsx:
--------------------------------------------------------------------------------
1 | import { useState, useCallback } from 'react';
2 | import copy from 'copy-to-clipboard';
3 |
4 | export function useClipboard(value) {
5 | const [hasCopied, setHasCopied] = useState(false);
6 |
7 | const onCopy = useCallback(() => {
8 | const didCopy = copy(value);
9 | setHasCopied(didCopy);
10 | }, [value]);
11 |
12 | return { value, onCopy, hasCopied };
13 | }
14 |
15 | export default useClipboard;
16 |
--------------------------------------------------------------------------------
/src/useDisclosure/index.tsx:
--------------------------------------------------------------------------------
1 | import { useState, useCallback } from 'react';
2 |
3 | const useDisclosure = (initialState = false) => {
4 | const [isOpen, setIsOpen] = useState(Boolean(initialState));
5 | const onClose = useCallback(() => setIsOpen(false), []);
6 | const onOpen = useCallback(() => setIsOpen(true), []);
7 | const onToggle = useCallback(() => setIsOpen(prevIsOpen => !prevIsOpen), []);
8 | return { isOpen, onOpen, onClose, onToggle };
9 | };
10 |
11 | export default useDisclosure;
12 |
--------------------------------------------------------------------------------
/src/useLocalStorage/index.tsx:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from 'react';
2 |
3 | export function useLocalStorage(key: string, defaultValue: string | number) {
4 | const [state, setState] = useState(() => {
5 | let value;
6 | try {
7 | value = JSON.parse(
8 | window.localStorage.getItem(key) || String(defaultValue)
9 | );
10 | } catch (e) {
11 | value = defaultValue;
12 | }
13 | return value;
14 | });
15 |
16 | useEffect(() => {
17 | window.localStorage.setItem(key, state);
18 | }, [state]);
19 |
20 | return [state, setState];
21 | }
22 |
23 | export default useLocalStorage;
24 |
--------------------------------------------------------------------------------
/src/useMedia/index.tsx:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from 'react';
2 | import json2mq from 'json2mq';
3 |
4 | export function useMedia(
5 | query: string | { [key: string]: any },
6 | defaultMatches = true
7 | ) {
8 | const [matches, setMatches] = useState(defaultMatches);
9 |
10 | /* istanbul ignore next */
11 | useEffect(() => {
12 | const mediaQueryList = window.matchMedia(
13 | typeof query === 'string' ? query : json2mq(query)
14 | );
15 | let active = true;
16 |
17 | const listener = () => {
18 | if (!active) {
19 | return;
20 | }
21 |
22 | if (mediaQueryList.matches) {
23 | setMatches(true);
24 | } else {
25 | setMatches(false);
26 | }
27 | };
28 |
29 | mediaQueryList.addListener(listener);
30 | setMatches(mediaQueryList.matches);
31 |
32 | return () => {
33 | active = false;
34 | mediaQueryList.removeListener(listener);
35 | };
36 | }, [query]);
37 |
38 | return matches;
39 | }
40 |
41 | export default useMedia;
42 |
--------------------------------------------------------------------------------
/src/useNetwork/index.tsx:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from 'react';
2 |
3 | export function getOnlineStatus() {
4 | return typeof navigator !== 'undefined' &&
5 | typeof navigator.onLine === 'boolean'
6 | ? navigator.onLine
7 | : true;
8 | }
9 |
10 | function useOnlineStatus() {
11 | const [onlineStatus, setOnlineStatus] = useState(getOnlineStatus());
12 |
13 | const goOnline = () => setOnlineStatus(true);
14 |
15 | const goOffline = () => setOnlineStatus(false);
16 |
17 | useEffect(() => {
18 | window.addEventListener('online', goOnline);
19 | window.addEventListener('offline', goOffline);
20 |
21 | return () => {
22 | window.removeEventListener('online', goOnline);
23 | window.removeEventListener('offline', goOffline);
24 | };
25 | }, []);
26 |
27 | return onlineStatus;
28 | }
29 |
30 | export default useOnlineStatus;
31 |
--------------------------------------------------------------------------------
/src/utilities/BorderRadius.stories.mdx:
--------------------------------------------------------------------------------
1 | import { Meta, Story, Preview, Props } from '@storybook/addon-docs/blocks';
2 | import baseTheme from '../theme';
3 |
4 |
5 |
6 | # Border Radius
7 |
8 | ## Aliases
9 |
10 | ```jsx
11 | () => (
12 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | )
25 | ```
26 |
27 |
28 |
29 |
30 | Key |
31 | Value |
32 |
33 |
34 |
35 | {Object.entries(baseTheme.radii).map(([name, value]) => (
36 |
37 | {name} |
38 |
39 | {value}
40 | |
41 |
42 | ))}
43 |
44 |
45 |
46 | ## Custom Props
47 | ```jsx isManual=true
48 | const Card = (props) =>
49 |
50 | render(
51 |
56 | Radius Left: 4px
57 | Radius Right: 'md'
58 | Radius Top: 'md'
59 | Radius Bottom: 'md'
60 |
61 | )
62 | ```
--------------------------------------------------------------------------------
/src/utilities/FontSizes.stories.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Text, Block } from '..';
3 | import defaultTheme from '../theme';
4 |
5 | const { fontSizes }: any = defaultTheme;
6 |
7 | export default {
8 | title: 'FontSizes',
9 | };
10 |
11 | export const FontSizes = () => {
12 | return Object.keys(fontSizes).map(key => (
13 |
14 | Heading ({key})
15 |
16 | ));
17 | };
18 |
--------------------------------------------------------------------------------
/src/utilities/Layout.stories.mdx:
--------------------------------------------------------------------------------
1 | import { Meta, Story, Preview, Props } from '@storybook/addon-docs/blocks';
2 | import PseudoBox from '../PseudoBox';
3 |
4 |
5 |
6 | # Layout
7 |
8 | Layout components help replace common patterns when building a UI.
9 |
10 | For example, `` saves you the time of having to write `` or ``.
11 |
12 | ## Box
13 |
14 | Basic `div` element with no defaults
15 |
16 | ```jsx
17 | () => (
18 |
23 |
24 |
25 |
26 | )
27 | ```
28 |
29 | ## Flex
30 |
31 | Renders a `div` with `display: flex` set by default.
32 |
33 | ```jsx
34 | () => (
35 |
40 |
41 |
42 |
43 | )
44 | ```
45 |
46 | ## Block
47 |
48 | Renders a `div` with `display: block` set by default.
49 |
50 | ```jsx
51 | () => (
52 |
56 |
57 |
58 |
59 | )
60 | ```
--------------------------------------------------------------------------------
/src/utilities/Shadows.stories.mdx:
--------------------------------------------------------------------------------
1 | import { Meta, Story, Preview, Props } from '@storybook/addon-docs/blocks';
2 | import defaultTheme from '../theme'
3 | import UtilityTable from '../../utils/UtilityTable';
4 |
5 |
6 |
7 | # Shadows
8 |
9 | ```jsx isManual=true
10 | const Card = (props) =>
11 |
12 | render(
13 |
18 | base
19 | md
20 | lg
21 | xl
22 | 2xl
23 | inner
24 | outline
25 | none
26 |
27 | )
28 | ```
29 |
30 | ## Shorthand Props
31 | ```jsx isManual=true
32 | const Card = (props) =>
33 |
34 | render(
35 |
40 | base
41 |
42 | )
43 | ```
44 |
45 |
--------------------------------------------------------------------------------
/stories/1-Theming.stories.mdx:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Theming
4 |
5 | The Minerva theme object follows the [Styled System spec](https://system-ui.com/theme/), with some more specific styles added to create styles for specific components.
6 |
7 | These specific styles allow you to control different components and their different states. In the future we plan to connect this config with tools like Figma to easily generate themes from design systems.
8 |
9 | ## Default Theme
10 |
11 | Minerva comes with a [default theme](https://github.com/cratebind/minerva-ui/blob/master/src/theme.ts) that you can use to show the styles from Storybook by default.
12 |
13 | You can also extend these styles to customize them or provide your own style object:
14 |
15 | ```jsx live=false
16 | import { ThemeProvider, defaultTheme } from 'minerva-ui';
17 |
18 | const customTheme = {
19 | // spread the default theme if you want to extend them
20 | ...defaultTheme
21 | colors: {
22 | // make sure to spread nested objects like this
23 | // unless you are trying to override the entire object
24 | ...defaultTheme.colors,
25 | primary: '#551A8B'
26 | }
27 | }
28 |
29 | const App = () => {
30 | return (
31 |
32 | {/* ...rest of your app */}
33 |
34 | )
35 | }
36 | ```
37 |
38 | ## Component Theming
39 |
40 | Theme styles for specific components can be provided in your `theme` object:
41 |
42 | ```jsx
43 | () => {
44 | const theme = {
45 | Button: {
46 | backgroundColor: 'midnightblue',
47 | color: '#fff'
48 | }
49 | }
50 |
51 | return (
52 |
53 |
54 |
55 | )
56 | }
57 | ```
58 |
59 | ## Default Theme
60 |
61 | ```jsx
62 | () => {
63 | return (
64 |
65 | {JSON.stringify(defaultTheme, null, 2)}
66 |
67 | )
68 | }
69 | ```
--------------------------------------------------------------------------------
/test/GlobalStyles.test.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render } from '@testing-library/react';
3 | import styled from 'styled-components';
4 | import 'jest-styled-components';
5 | import { ThemeProvider, GlobalStyles } from '../src';
6 |
7 | const PlainButton = styled.button``;
8 |
9 | describe('', () => {
10 | it('should render', () => {
11 | const { container } = render(
12 |
13 |
14 | Test
15 |
16 | );
17 | expect(container).toMatchSnapshot();
18 | });
19 | });
20 |
--------------------------------------------------------------------------------
/test/__mocks__/styleMock.js:
--------------------------------------------------------------------------------
1 | module.exports = {};
2 |
--------------------------------------------------------------------------------
/test/__snapshots__/GlobalStyles.test.tsx.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[` should render 1`] = `
4 |
5 |
10 |
11 | `;
12 |
--------------------------------------------------------------------------------
/test/__snapshots__/alert.test.tsx.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[` should render 1`] = `
4 | .c0 {
5 | box-sizing: border-box;
6 | min-width: 0;
7 | background-color: #e5e7eb;
8 | line-height: 1;
9 | font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";
10 | }
11 |
12 | .c3 {
13 | box-sizing: border-box;
14 | min-width: 0;
15 | margin: 0;
16 | font-size: 16px;
17 | font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";
18 | }
19 |
20 | .c1 {
21 | display: -webkit-box;
22 | display: -webkit-flex;
23 | display: -ms-flexbox;
24 | display: flex;
25 | background-color: #e5e7eb;
26 | line-height: 1;
27 | font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";
28 | }
29 |
30 | .c2 {
31 | padding: 16px;
32 | border-radius: 5px;
33 | -webkit-align-items: center;
34 | -webkit-box-align: center;
35 | -ms-flex-align: center;
36 | align-items: center;
37 | background-color: #e5e7eb;
38 | line-height: 1;
39 | font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";
40 | }
41 |
42 | .c4 {
43 | font-weight: bold;
44 | margin-right: 5px;
45 | }
46 |
47 |
61 | `;
62 |
--------------------------------------------------------------------------------
/test/__snapshots__/combobox.test.tsx.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[` should render 1`] = `
4 | .c0 {
5 | box-sizing: border-box;
6 | min-width: 0;
7 | -webkit-appearance: none;
8 | -moz-appearance: none;
9 | appearance: none;
10 | font-size: 16px;
11 | border-style: solid;
12 | border-color: #d2d6dc;
13 | padding-top: 8px;
14 | padding-bottom: 8px;
15 | padding-left: 12px;
16 | padding-right: 32px;
17 | border-width: 1px;
18 | border-radius: 4px;
19 | -webkit-transition: all 250ms ease 0s;
20 | transition: all 250ms ease 0s;
21 | outline: none;
22 | width: 100%;
23 | }
24 |
25 | .c1:focus {
26 | border-color: #a4cafe;
27 | box-shadow: 0 0 0 3px rgba(164,202,254,.45);
28 | }
29 |
30 | .c1:disabled,
31 | .c1:disabled:focus,
32 | .c1:disabled:hover,
33 | .c1[aria-disabled=true],
34 | .c1[aria-disabled=true]:focus,
35 | .c1[aria-disabled=true]:hover {
36 | background-color: #EAEAEA;
37 | color: #8F8F8F;
38 | cursor: not-allowed;
39 | }
40 |
41 |
42 |
62 |
63 | `;
64 |
--------------------------------------------------------------------------------
/test/__snapshots__/heading.test.tsx.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[` should render 1`] = `
4 | .c0 {
5 | box-sizing: border-box;
6 | min-width: 0;
7 | margin: 0;
8 | font-weight: bold;
9 | font-family: inherit;
10 | font-size: 1.5rem;
11 | }
12 |
13 |
14 |
17 | Test
18 |
19 |
20 | `;
21 |
--------------------------------------------------------------------------------
/test/__snapshots__/icon.test.tsx.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Default Icons should render 1`] = `
4 |
5 |
39 |
59 |
60 | `;
61 |
--------------------------------------------------------------------------------
/test/__snapshots__/input.test.tsx.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[` should render 1`] = `
4 | .c0 {
5 | box-sizing: border-box;
6 | min-width: 0;
7 | -webkit-appearance: none;
8 | -moz-appearance: none;
9 | appearance: none;
10 | font-size: 16px;
11 | border-style: solid;
12 | border-color: #d2d6dc;
13 | padding-top: 8px;
14 | padding-bottom: 8px;
15 | padding-left: 12px;
16 | padding-right: 32px;
17 | border-width: 1px;
18 | border-radius: 4px;
19 | -webkit-transition: all 250ms ease 0s;
20 | transition: all 250ms ease 0s;
21 | outline: none;
22 | width: 100%;
23 | }
24 |
25 | .c1:focus {
26 | border-color: #a4cafe;
27 | box-shadow: 0 0 0 3px rgba(164,202,254,.45);
28 | }
29 |
30 | .c1:disabled,
31 | .c1:disabled:focus,
32 | .c1:disabled:hover,
33 | .c1[aria-disabled=true],
34 | .c1[aria-disabled=true]:focus,
35 | .c1[aria-disabled=true]:hover {
36 | background-color: #EAEAEA;
37 | color: #8F8F8F;
38 | cursor: not-allowed;
39 | }
40 |
41 |
42 |
52 |
53 | `;
54 |
--------------------------------------------------------------------------------
/test/__snapshots__/inputField.test.tsx.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[` should render 1`] = `
4 | .c1 {
5 | box-sizing: border-box;
6 | min-width: 0;
7 | padding-bottom: 0.5rem;
8 | }
9 |
10 | .c2 {
11 | box-sizing: border-box;
12 | min-width: 0;
13 | -webkit-appearance: none;
14 | -moz-appearance: none;
15 | appearance: none;
16 | font-size: 16px;
17 | border-style: solid;
18 | border-color: #d2d6dc;
19 | padding-top: 8px;
20 | padding-bottom: 8px;
21 | padding-left: 12px;
22 | padding-right: 32px;
23 | border-width: 1px;
24 | border-radius: 4px;
25 | -webkit-transition: all 250ms ease 0s;
26 | transition: all 250ms ease 0s;
27 | outline: none;
28 | width: 100%;
29 | }
30 |
31 | .c3:focus {
32 | border-color: #a4cafe;
33 | box-shadow: 0 0 0 3px rgba(164,202,254,.45);
34 | }
35 |
36 | .c3:disabled,
37 | .c3:disabled:focus,
38 | .c3:disabled:hover,
39 | .c3[aria-disabled=true],
40 | .c3[aria-disabled=true]:focus,
41 | .c3[aria-disabled=true]:hover {
42 | background-color: #EAEAEA;
43 | color: #8F8F8F;
44 | cursor: not-allowed;
45 | }
46 |
47 | .c0 {
48 | display: block;
49 | position: relative;
50 | margin-bottom: 8px;
51 | line-height: 1.5;
52 | }
53 |
54 |
55 |
59 |
76 |
77 |
78 | `;
79 |
--------------------------------------------------------------------------------
/test/__snapshots__/link.test.tsx.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[` should render 1`] = `
4 | .c0 {
5 | box-sizing: border-box;
6 | min-width: 0;
7 | font-size: 16px;
8 | }
9 |
10 |
17 | `;
18 |
--------------------------------------------------------------------------------
/test/__snapshots__/skeleton.test.tsx.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[` should render 1`] = `
4 | .c0 {
5 | box-sizing: border-box;
6 | min-width: 0;
7 | width: 100%;
8 | height: 100%;
9 | }
10 |
11 | .c3 {
12 | box-sizing: border-box;
13 | min-width: 0;
14 | height: 2rem;
15 | width: 100%;
16 | border-radius: 5px;
17 | }
18 |
19 | .c1 {
20 | display: -webkit-box;
21 | display: -webkit-flex;
22 | display: -ms-flexbox;
23 | display: flex;
24 | width: 100%;
25 | height: 100%;
26 | }
27 |
28 | .c2 {
29 | -webkit-flex-direction: column;
30 | -ms-flex-direction: column;
31 | flex-direction: column;
32 | width: 100%;
33 | height: 100%;
34 | }
35 |
36 | .c2 > * + * {
37 | margin-top: 10px;
38 | }
39 |
40 | .c4 {
41 | display: inline-block;
42 | background: linear-gradient(-90deg,#f0f0f0 0%,#f8f8f8 50%,#f0f0f0 100%);
43 | background-size: 400% 400%;
44 | -webkit-animation: 1.2s ease-in-out infinite alternate kYdCAA;
45 | animation: 1.2s ease-in-out infinite alternate kYdCAA;
46 | }
47 |
48 |
58 | `;
59 |
--------------------------------------------------------------------------------
/test/__snapshots__/stack.test.tsx.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[` should change margin with gap prop 1`] = `
4 | .c0 {
5 | box-sizing: border-box;
6 | min-width: 0;
7 | }
8 |
9 | .c1 {
10 | display: -webkit-box;
11 | display: -webkit-flex;
12 | display: -ms-flexbox;
13 | display: flex;
14 | }
15 |
16 | .c2 {
17 | -webkit-flex-direction: column;
18 | -ms-flex-direction: column;
19 | flex-direction: column;
20 | }
21 |
22 | .c2 > * + * {
23 | margin-top: 30px;
24 | }
25 |
26 |
27 |
30 |
33 | Item 1
34 |
35 |
39 | Item 2
40 |
41 |
42 |
43 | `;
44 |
45 | exports[` should render 1`] = `
46 | .c0 {
47 | box-sizing: border-box;
48 | min-width: 0;
49 | }
50 |
51 | .c1 {
52 | display: -webkit-box;
53 | display: -webkit-flex;
54 | display: -ms-flexbox;
55 | display: flex;
56 | }
57 |
58 | .c2 {
59 | -webkit-flex-direction: column;
60 | -ms-flex-direction: column;
61 | flex-direction: column;
62 | }
63 |
64 | .c2 > * + * {
65 | margin-top: 10px;
66 | }
67 |
68 |
69 |
72 |
75 | Item 1
76 |
77 |
80 | Item 2
81 |
82 |
83 |
84 | `;
85 |
--------------------------------------------------------------------------------
/test/__snapshots__/tag.test.tsx.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[` should render 1`] = `
4 | .c0 {
5 | box-sizing: border-box;
6 | min-width: 0;
7 | background-color: #EDF2F7;
8 | }
9 |
10 |
17 | `;
18 |
--------------------------------------------------------------------------------
/test/__snapshots__/tagsInput.test.tsx.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[` should render 1`] = `
4 | .c1 {
5 | box-sizing: border-box;
6 | min-width: 0;
7 | }
8 |
9 | .c3 {
10 | box-sizing: border-box;
11 | min-width: 0;
12 | -webkit-appearance: none;
13 | -moz-appearance: none;
14 | appearance: none;
15 | font-size: 16px;
16 | border-style: solid;
17 | border-color: #d2d6dc;
18 | padding-top: 8px;
19 | padding-bottom: 8px;
20 | padding-left: 12px;
21 | padding-right: 32px;
22 | border-width: 1px;
23 | border-radius: 4px;
24 | -webkit-transition: all 250ms ease 0s;
25 | transition: all 250ms ease 0s;
26 | outline: none;
27 | width: 100%;
28 | }
29 |
30 | .c4:focus {
31 | border-color: #a4cafe;
32 | box-shadow: 0 0 0 3px rgba(164,202,254,.45);
33 | }
34 |
35 | .c4:disabled,
36 | .c4:disabled:focus,
37 | .c4:disabled:hover,
38 | .c4[aria-disabled=true],
39 | .c4[aria-disabled=true]:focus,
40 | .c4[aria-disabled=true]:hover {
41 | background-color: #EAEAEA;
42 | color: #8F8F8F;
43 | cursor: not-allowed;
44 | }
45 |
46 | .c0 {
47 | background: white;
48 | box-sizing: border-box;
49 | border: 1px solid #d2d6dc;
50 | padding: 3px 12px 3px 12px;
51 | border-width: 1px;
52 | border-radius: 4px;
53 | -webkit-transition: all 250ms ease 0s;
54 | transition: all 250ms ease 0s;
55 | outline: none;
56 | width: 100%;
57 | display: -webkit-inline-box;
58 | display: -webkit-inline-flex;
59 | display: -ms-inline-flexbox;
60 | display: inline-flex;
61 | -webkit-flex-wrap: wrap;
62 | -ms-flex-wrap: wrap;
63 | flex-wrap: wrap;
64 | -webkit-flex: 1 1 0%;
65 | -ms-flex: 1 1 0%;
66 | flex: 1 1 0%;
67 | }
68 |
69 | .c0 li {
70 | margin: 0 2px;
71 | }
72 |
73 | .c5 {
74 | display: inline-block;
75 | width: 100%;
76 | border: none;
77 | padding: 0;
78 | padding-left: 10px;
79 | line-height: 44px;
80 | height: 100%;
81 | min-height: 44px;
82 | }
83 |
84 | .c5:focus {
85 | box-shadow: none;
86 | }
87 |
88 | .c2 {
89 | list-style-type: none;
90 | margin-right: 5px;
91 | }
92 |
93 |
108 | `;
109 |
--------------------------------------------------------------------------------
/test/__snapshots__/text.test.tsx.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[` should render 1`] = `
4 | .c0 {
5 | box-sizing: border-box;
6 | min-width: 0;
7 | margin: 0;
8 | font-size: 16px;
9 | font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";
10 | }
11 |
12 |
19 | `;
20 |
--------------------------------------------------------------------------------
/test/__snapshots__/utilities.test.tsx.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Border Radius should render 1`] = `
4 | .c0 {
5 | box-sizing: border-box;
6 | min-width: 0;
7 | border-radius: 0.125rem;
8 | }
9 |
10 | .c1 {
11 | display: block;
12 | border-radius: 0.125rem;
13 | }
14 |
15 |
16 |
20 | Default Text
21 |
22 |
23 | `;
24 |
25 | exports[`Colors should render 1`] = `
26 | .c0 {
27 | box-sizing: border-box;
28 | min-width: 0;
29 | background-color: #0694a2;
30 | }
31 |
32 | .c1 {
33 | display: block;
34 | background-color: #0694a2;
35 | }
36 |
37 |
38 |
42 | Default Text
43 |
44 |
45 | `;
46 |
--------------------------------------------------------------------------------
/test/accordion.test.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render } from '@testing-library/react';
3 | import 'jest-styled-components';
4 | import {
5 | Accordion,
6 | AccordionButton,
7 | AccordionItem,
8 | AccordionPanel,
9 | ThemeProvider,
10 | } from '../src';
11 |
12 | const ExampleAccordion = () => {
13 | return (
14 |
15 |
16 | Section 1 title
17 |
18 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
19 | eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad
20 | minim veniam, quis nostrud exercitation ullamco laboris nisi ut
21 | aliquip ex ea commodo consequat.
22 |
23 |
24 |
25 | Section 2 title
26 |
27 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
28 | eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad
29 | minim veniam, quis nostrud exercitation ullamco laboris nisi ut
30 | aliquip ex ea commodo consequat.
31 |
32 |
33 |
34 | );
35 | };
36 |
37 | describe('', () => {
38 | it('should render', () => {
39 | const { container } = render(
40 |
41 |
42 |
43 | );
44 | expect(container).toMatchSnapshot();
45 | });
46 |
47 | it('should display content', () => {
48 | const title = 'Section 1 title';
49 | const { container } = render(
50 |
51 |
52 |
53 | );
54 |
55 | expect(container).toHaveTextContent(title);
56 | });
57 | });
58 |
--------------------------------------------------------------------------------
/test/heading.test.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render } from '@testing-library/react';
3 | import 'jest-styled-components';
4 | import { Heading } from '../src';
5 | import { ThemeProvider } from '../src';
6 |
7 | describe('', () => {
8 | it('should render', () => {
9 | const { container } = render(
10 |
11 | Test
12 |
13 | );
14 | expect(container).toMatchSnapshot();
15 | });
16 |
17 | it('should display text at default size', () => {
18 | const content = 'Heading';
19 | const { container } = render(
20 |
21 | {content}
22 |
23 | );
24 |
25 | expect(container).toHaveTextContent(content);
26 | });
27 |
28 | it('should display text with style prop preset', () => {
29 | const content = 'Heading';
30 | const { container } = render(
31 |
32 | {content}
33 |
34 | );
35 |
36 | expect(container).toHaveTextContent(content);
37 | expect(container.firstChild).toHaveStyleRule('font-size', '1.125rem');
38 | });
39 |
40 | it('should display text with style prop custom value', () => {
41 | const content = 'Heading';
42 | const { container } = render(
43 |
44 | {content}
45 |
46 | );
47 |
48 | expect(container).toHaveTextContent(content);
49 | expect(container.firstChild).toHaveStyleRule('font-size', '16px');
50 | });
51 | });
52 |
--------------------------------------------------------------------------------
/test/icon.test.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render } from '@testing-library/react';
3 | import 'jest-styled-components';
4 | import { defaultIcons, ThemeProvider } from '../src';
5 |
6 | const Close = defaultIcons['close'];
7 | const ChevronDown = defaultIcons['chevron-down'];
8 |
9 | describe('Default Icons', () => {
10 | it('should render', () => {
11 | const { container } = render(
12 |
13 |
14 |
15 |
16 | );
17 | expect(container).toMatchSnapshot();
18 | });
19 | });
20 |
--------------------------------------------------------------------------------
/test/input.test.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import { render, fireEvent } from '@testing-library/react';
3 | import 'jest-styled-components';
4 | import { Input } from '../src';
5 | import { ThemeProvider } from '../src';
6 |
7 | const inputLabel = 'Name';
8 |
9 | const ExampleInput = props => {
10 | const [state, setState] = useState('');
11 | return (
12 |
13 |
22 |
23 | );
24 | };
25 |
26 | describe('', () => {
27 | it('should render', () => {
28 | const { container } = render();
29 | expect(container).toMatchSnapshot();
30 | });
31 |
32 | it('should show value', () => {
33 | const content = 'Hello';
34 | const { getByLabelText } = render();
35 |
36 | const input = getByLabelText(inputLabel);
37 |
38 | expect(input).toHaveValue(content);
39 | });
40 |
41 | it('should show updated value', () => {
42 | const { getByLabelText } = render();
43 |
44 | const input = getByLabelText(inputLabel);
45 |
46 | expect(input).toHaveValue('');
47 |
48 | const updatedValue = 'Input updated!';
49 | fireEvent.change(input, {
50 | target: {
51 | value: updatedValue,
52 | },
53 | });
54 |
55 | expect(input).toHaveValue(updatedValue);
56 | });
57 |
58 | // it('should show new background color if provided in theme', () => {
59 | // const newColor = 'green';
60 | // const theme = {
61 | // Input: {
62 | // container: {
63 | // backgroundColor: newColor,
64 | // },
65 | // },
66 | // };
67 |
68 | // const { getByRole } = render(
69 | //
70 | //
71 | //
72 | // );
73 |
74 | // const input = getByRole('input');
75 |
76 | // expect(input).toHaveStyleRule('background-color', newColor);
77 | // });
78 | });
79 |
--------------------------------------------------------------------------------
/test/inputField.test.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import { render } from '@testing-library/react';
3 | import { ThemeProvider, InputField, Input } from '../src';
4 | import 'jest-styled-components';
5 |
6 | const ExampleInputField = ({ errorText, ...props }: any) => {
7 | const [state, setState] = useState('');
8 | const [error, setError] = useState('');
9 | return (
10 |
11 |
12 | setError('This field cannot be empty') : () => {}
18 | }
19 | onChange={e => {
20 | setError('');
21 | setState(e.target.value);
22 | }}
23 | />
24 |
25 |
26 | );
27 | };
28 |
29 | describe('', () => {
30 | it('should render', () => {
31 | const { container } = render();
32 | expect(container).toMatchSnapshot();
33 | });
34 |
35 | it('should show error message if error exists', () => {
36 | const { container } = render(
37 |
38 | );
39 |
40 | expect(container.lastChild).toHaveTextContent('This field cannot be empty');
41 | });
42 |
43 | it('should show label', () => {
44 | const { container } = render();
45 | const elem = container.firstChild;
46 | expect(elem).toHaveTextContent('Placeholder');
47 | });
48 |
49 | it('should show required marker', () => {
50 | const { getByTestId } = render();
51 | expect(getByTestId('required-marker')).toBeInTheDocument();
52 | });
53 | });
54 |
--------------------------------------------------------------------------------
/test/layout.test.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styled from 'styled-components';
3 | import { render } from '@testing-library/react';
4 | import 'jest-styled-components';
5 | import { Box, PseudoBox } from '../src';
6 | import { ThemeProvider } from '../src';
7 |
8 | describe('', () => {
9 | it('should render', () => {
10 | const testId = `box`;
11 | const { getByTestId } = render(
12 |
13 |
14 |
15 | );
16 | expect(getByTestId(testId)).toBeInTheDocument();
17 | });
18 |
19 | it('should not forward style props', () => {
20 | const testId = `box`;
21 | const { getByTestId } = render(
22 |
23 |
24 |
25 | );
26 |
27 | const element = getByTestId(testId);
28 | expect(element.getAttribute('width')).toBeNull();
29 | });
30 |
31 | it('should allow wrapped components to pass styles', () => {
32 | const testId = `box`;
33 | const WrappedComponent = styled(Box)`
34 | width: 50px;
35 | `;
36 |
37 | const { getByTestId } = render(
38 |
39 |
40 |
41 | );
42 |
43 | const element = getByTestId(testId);
44 |
45 | expect(element).toHaveStyleRule('width', '50px');
46 | expect(element.getAttribute('width')).toBeNull();
47 | });
48 |
49 | it('should allow pseudobox to pass styles', () => {
50 | const testId = `box`;
51 |
52 | const { getByTestId } = render(
53 |
54 |
55 |
56 | );
57 |
58 | const element = getByTestId(testId);
59 |
60 | expect(element).toHaveStyleRule('width', '50px');
61 | expect(element.getAttribute('width')).toBeNull();
62 | expect(element).toMatchInlineSnapshot(`
63 | .c0 {
64 | box-sizing: border-box;
65 | min-width: 0;
66 | width: 50px;
67 | }
68 |
69 |
73 | `);
74 | });
75 | });
76 |
--------------------------------------------------------------------------------
/test/link.test.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render } from '@testing-library/react';
3 | import 'jest-styled-components';
4 | import { Link } from '../src';
5 | import { ThemeProvider } from '../src';
6 |
7 | describe('', () => {
8 | it('should render', () => {
9 | const { container } = render(
10 |
11 | Test
12 |
13 | );
14 | expect(container).toMatchSnapshot();
15 | });
16 |
17 | it('should display text', () => {
18 | const content = 'Hello';
19 | const { container } = render(
20 |
21 | {content}
22 |
23 | );
24 |
25 | expect(container).toHaveTextContent(content);
26 | });
27 |
28 | it('should add attributes when `isExternal` prop is passed', () => {
29 | const content = 'Hello';
30 | const { getByText } = render(
31 |
32 | {content}
33 |
34 | );
35 |
36 | const element = getByText(content);
37 |
38 | expect(element.getAttribute('rel')).toEqual('noopener noreferrer');
39 | expect(element.getAttribute('target')).toEqual('_blank');
40 | });
41 | });
42 |
--------------------------------------------------------------------------------
/test/select.test.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import { render, fireEvent } from '@testing-library/react';
3 | import 'jest-styled-components';
4 | import { Select } from '../src';
5 | import { ThemeProvider } from '../src';
6 |
7 | const inputLabel = 'Name';
8 |
9 | const ExampleSelect = props => {
10 | const [state, setState] = useState('');
11 | return (
12 |
13 |
14 |
26 |
27 | );
28 | };
29 |
30 | describe('', () => {
31 | it('should render', () => {
32 | const { container } = render();
33 | expect(container).toMatchSnapshot();
34 | });
35 |
36 | it('should change style if disabled', () => {
37 | const { container, getByDisplayValue } = render(
38 |
39 |
40 |
41 | );
42 |
43 | expect(container).toMatchSnapshot();
44 | expect(getByDisplayValue('Default')).toHaveStyleRule(
45 | 'background-color',
46 | '#EAEAEA',
47 | {
48 | modifier: ':disabled',
49 | }
50 | );
51 | });
52 |
53 | it('should show value', () => {
54 | const { getByDisplayValue } = render();
55 |
56 | const select = getByDisplayValue('Default');
57 |
58 | expect(select).toBeInTheDocument();
59 | });
60 |
61 | it('should show updated value', () => {
62 | const { getByLabelText } = render();
63 |
64 | const input = getByLabelText(inputLabel);
65 |
66 | expect(input).toHaveValue('');
67 |
68 | const updatedValue = 'second';
69 |
70 | fireEvent.change(input, {
71 | target: {
72 | value: updatedValue,
73 | },
74 | });
75 |
76 | expect(input).toHaveValue(updatedValue);
77 | });
78 | });
79 |
--------------------------------------------------------------------------------
/test/setup.ts:
--------------------------------------------------------------------------------
1 | import '@testing-library/jest-dom/extend-expect';
2 | import 'jest-styled-components';
3 | // import { matchers } from 'jest-styled-components';
4 | // expect.extend(matchers);
5 |
6 | // ignore check styles function since we're inlining them
7 | jest.mock('@reach/utils', () => ({
8 | ...jest.requireActual('@reach/utils'),
9 | checkStyles: jest.fn(),
10 | }));
11 |
12 | jest.mock('copy-to-clipboard', () => {
13 | return jest.fn();
14 | });
15 |
16 | jest.mock('json2mq', () => {
17 | return jest.fn();
18 | });
19 |
--------------------------------------------------------------------------------
/test/stack.test.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render } from '@testing-library/react';
3 | import 'jest-styled-components';
4 | import { Stack, Box, ThemeProvider } from '../src';
5 |
6 | describe('', () => {
7 | it('should render', () => {
8 | const { container } = render(
9 |
10 |
11 | Item 1
12 | Item 2
13 |
14 |
15 | );
16 | expect(container).toMatchSnapshot();
17 | });
18 |
19 | it('should change flex-direction with horizontal prop', () => {
20 | const { container } = render(
21 |
22 |
23 | Item 1
24 | Item 2
25 |
26 |
27 | );
28 |
29 | expect(container.firstChild).toHaveStyleRule('flex-direction', 'row');
30 | });
31 |
32 | // @TODO: Figure out a better way to test this since nested selectors can't be tested with jest-styled-components
33 | it('should change margin with gap prop', () => {
34 | const { container } = render(
35 |
36 |
37 | Item 1
38 | Item 2
39 |
40 |
41 | );
42 |
43 | expect(container).toMatchSnapshot();
44 | });
45 | });
46 |
--------------------------------------------------------------------------------
/test/switch.test.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render } from '@testing-library/react';
3 | import 'jest-styled-components';
4 | import * as ReactDOM from 'react-dom';
5 | import { Switch, ThemeProvider } from '../src';
6 |
7 | describe('Switch', () => {
8 | it('renders without crashing', () => {
9 | const div = document.createElement('div');
10 | ReactDOM.render(, div);
11 | ReactDOM.unmountComponentAtNode(div);
12 | });
13 |
14 | it('shows gray background when unchecked', () => {
15 | const { getByTestId } = render(
16 |
17 |
18 |
19 | );
20 | const switchInner = getByTestId('switch-inner');
21 |
22 | expect(switchInner).toHaveStyleRule('background-color', '#ccc');
23 | });
24 |
25 | it('shows purple background when checked', () => {
26 | const { getByTestId } = render(
27 |
28 |
29 |
30 | );
31 | const switchInner = getByTestId('switch-inner');
32 |
33 | expect(switchInner).toHaveStyleRule('background-color', '#5850ec');
34 | });
35 |
36 | it('shows custom background color when switchColor prop exists and when checked', () => {
37 | const { getByTestId } = render(
38 |
39 |
40 |
41 | );
42 | const switchInner = getByTestId('switch-inner');
43 |
44 | expect(switchInner).toHaveStyleRule('background-color', '#FF00FF');
45 | });
46 |
47 | it('shows switch on the right when checked', () => {
48 | const { getByTestId } = render(
49 |
50 |
51 |
52 | );
53 | const switchBtn = getByTestId('switch');
54 |
55 | expect(switchBtn).toHaveStyleRule('transform', 'translateX(14px)');
56 | });
57 | });
58 |
--------------------------------------------------------------------------------
/test/table.test.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render } from '@testing-library/react';
3 | import 'jest-styled-components';
4 | import {
5 | Table,
6 | TableHeader,
7 | TableRow,
8 | TableCell,
9 | TableBody,
10 | TableHeaderCell,
11 | } from '../src';
12 | import { ThemeProvider } from '../src';
13 |
14 | const BasicTable = () => {
15 | const ref = React.useRef(null);
16 |
17 | return (
18 |
19 |
20 |
21 |
22 | Name
23 | Job
24 | Status
25 | Role
26 |
27 |
28 |
29 |
30 | Test
31 | Tester
32 | Testing
33 | Test Master
34 |
35 |
36 |
37 |
38 | );
39 | };
40 |
41 | describe('', () => {
42 | it('should render', () => {
43 | const { container } = render();
44 | expect(container).toMatchSnapshot();
45 | });
46 |
47 | it('should render', () => {
48 | const { container } = render();
49 |
50 | expect(container).toMatchSnapshot();
51 | });
52 |
53 | // it('should change style if disabled', () => {
54 | // const { container, getByRole } = render(
55 | //
56 | //
57 | //
58 | // );
59 |
60 | // expect(container).toMatchSnapshot();
61 | // expect(getByRole('button')).toHaveStyleRule('opacity', '0.4', {
62 | // modifier: ':disabled',
63 | // });
64 | // });
65 | });
66 |
--------------------------------------------------------------------------------
/test/tag.test.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render } from '@testing-library/react';
3 | import 'jest-styled-components';
4 | import { Tag } from '../src';
5 | import { ThemeProvider } from '../src';
6 |
7 | describe('', () => {
8 | it('should render', () => {
9 | const { container } = render(
10 |
11 | Test
12 |
13 | );
14 | expect(container).toMatchSnapshot();
15 | });
16 |
17 | it('should pass basic style props ', () => {
18 | const color = '#8B008B';
19 | const { getByTestId } = render(
20 |
21 |
22 | Magenta
23 |
24 |
25 | );
26 | const tag = getByTestId('tag');
27 | expect(tag).toHaveStyleRule('color', color);
28 | });
29 |
30 | it('should pass shorthand props', () => {
31 | const backgroundColor = '#008080';
32 | const { getByTestId } = render(
33 |
34 |
35 | Teal Tag
36 |
37 |
38 | );
39 | const tag = getByTestId('tag');
40 | expect(tag).toHaveStyleRule('background-color', backgroundColor);
41 | });
42 |
43 | it('should display text', () => {
44 | const content = 'I AM A TAG';
45 | const { getByTestId } = render(
46 |
47 | {content}
48 |
49 | );
50 | const tag = getByTestId('tag');
51 | expect(tag).toHaveTextContent(content);
52 | });
53 |
54 | it('should show default background color', () => {
55 | const { getByTestId } = render(
56 |
57 | Test
58 |
59 | );
60 | const tag = getByTestId('tag');
61 | expect(tag).toHaveStyle('background-color: #EDF2F7');
62 | });
63 |
64 | it('should show new background color if provided in theme', () => {
65 | const newColor = 'green';
66 | const theme = {
67 | Tag: {
68 | backgroundColor: newColor,
69 | },
70 | };
71 |
72 | const { getByTestId } = render(
73 |
74 | Test
75 |
76 | );
77 | const tag = getByTestId('tag');
78 | expect(tag).toHaveStyle(`background-color: ${newColor}`);
79 | });
80 | });
81 |
--------------------------------------------------------------------------------
/test/text.test.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render } from '@testing-library/react';
3 | import 'jest-styled-components';
4 | import { Text } from '../src';
5 | import { ThemeProvider } from '../src';
6 |
7 | describe('', () => {
8 | it('should render', () => {
9 | const { container } = render(
10 |
11 | Test
12 |
13 | );
14 | expect(container).toMatchSnapshot();
15 | });
16 |
17 | it('should display text', () => {
18 | const content = 'Hello';
19 | const { container } = render(
20 |
21 | {content}
22 |
23 | );
24 |
25 | expect(container).toHaveTextContent(content);
26 | });
27 | });
28 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "include": [
3 | "src",
4 | "types",
5 | "stories",
6 | "cypress",
7 | "cypress-real-events",
8 | "dist"
9 | ],
10 | "exclude": [
11 | "node_modules",
12 | "theme-builder",
13 | "docs",
14 | "cypress"
15 | ],
16 | "compilerOptions": {
17 | "target": "es5",
18 | "module": "esnext",
19 | "lib": [
20 | "dom",
21 | "esnext"
22 | ],
23 | "importHelpers": true,
24 | "declaration": true,
25 | "sourceMap": true,
26 | "rootDir": "./src",
27 | "strict": true,
28 | "noImplicitAny": false,
29 | "strictNullChecks": true,
30 | "strictFunctionTypes": true,
31 | "strictPropertyInitialization": true,
32 | "noImplicitThis": true,
33 | "alwaysStrict": true,
34 | "allowSyntheticDefaultImports": true,
35 | "noUnusedLocals": true,
36 | "skipLibCheck": true,
37 | "noUnusedParameters": true,
38 | "noImplicitReturns": true,
39 | "noFallthroughCasesInSwitch": true,
40 | "moduleResolution": "node",
41 | "jsx": "react",
42 | "esModuleInterop": true,
43 | "incremental": true
44 | }
45 | }
--------------------------------------------------------------------------------
/types/index.d.ts:
--------------------------------------------------------------------------------
1 | declare var __DEV__: boolean;
2 |
3 | declare global {
4 | namespace Cypress {
5 | interface Chainable {
6 | toMatchImageSnapshot: any;
7 | realHover(): Chainable;
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/types/jest-styled-components.d.ts:
--------------------------------------------------------------------------------
1 | declare namespace jest {
2 | interface AsymmetricMatcher {
3 | $$typeof: Symbol;
4 | sample?: string | RegExp | object | Array | Function;
5 | }
6 |
7 | type Value = string | number | RegExp | AsymmetricMatcher | undefined;
8 |
9 | interface Options {
10 | media?: string;
11 | modifier?: string;
12 | supports?: string;
13 | }
14 |
15 | interface Matchers {
16 | toHaveStyleRule(property: string, value?: Value, options?: Options): R;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/utils/ColorTag.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Block } from '../src';
3 |
4 | const ColorTag = ({ number, code, ...props }) => (
5 | 500 ? '#fff' : '#000'}
9 | margin="4px"
10 | backgroundColor={code}
11 | {...props}
12 | />
13 | );
14 |
15 | export default ColorTag;
16 |
--------------------------------------------------------------------------------
/utils/UtilityTable.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {
3 | Table,
4 | TableHeader,
5 | TableRow,
6 | TableHeaderCell,
7 | TableBody,
8 | TableCell,
9 | } from '../src';
10 |
11 | const UtilityTable = ({ themeProperty }) => {
12 | return (
13 |
14 |
15 |
16 | Key
17 | Value
18 |
19 |
20 |
21 | {Object.entries(themeProperty).map(([property, value]) => (
22 |
23 |
24 | {property}
25 |
26 |
27 | {value}
28 | {/* {typeof value === 'string' ? (
29 |
35 | {value}
36 |
37 | ) : (
38 | Object.entries(value).map(([number, code]) => (
39 |
40 | {number}: {code}
41 |
42 | ))
43 | )} */}
44 |
45 |
46 | ))}
47 |
48 |
49 | );
50 | };
51 |
52 | export default UtilityTable;
53 |
--------------------------------------------------------------------------------
/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite';
2 | import reactRefresh from '@vitejs/plugin-react-refresh';
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [reactRefresh()],
7 | });
8 |
--------------------------------------------------------------------------------