paris 0.2.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/README.md +61 -5
- package/package.json +23 -13
- package/src/helpers/renderEnhancer.tsx +21 -0
- package/src/stories/Tokens.mdx +0 -8
- package/src/stories/button/Button.module.scss +12 -6
- package/src/stories/button/Button.stories.ts +17 -0
- package/src/stories/button/Button.tsx +48 -11
- package/src/stories/dropdown/Dropdown.module.scss +23 -0
- package/src/stories/input/Input.module.scss +134 -0
- package/src/stories/input/Input.stories.ts +87 -0
- package/src/stories/input/Input.tsx +172 -0
- package/src/stories/input/index.ts +1 -0
- package/src/stories/select/Select.module.scss +70 -0
- package/src/stories/select/Select.stories.ts +71 -0
- package/src/stories/select/Select.tsx +103 -0
- package/src/stories/select/index.ts +1 -0
- package/src/stories/text/Text.module.scss +1 -1
- package/src/stories/text/Text.tsx +36 -14
- package/src/stories/textarea/TextArea.stories.ts +19 -0
- package/src/stories/textarea/TextArea.tsx +120 -0
- package/src/stories/textarea/index.ts +1 -0
- package/src/stories/theme/global.scss +2 -0
- package/src/stories/theme/index.ts +1 -0
- package/src/stories/theme/themes.ts +52 -6
- package/src/stories/theme/util.scss +8 -0
- package/src/types/Enhancer.ts +3 -0
- package/src/styles/util.scss +0 -4
- /package/src/{styles → stories/theme}/tw-preflight.css +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# paris
|
|
2
2
|
|
|
3
|
+
## 0.3.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- eef2375: `TextArea` component
|
|
8
|
+
- 2f6cd01: `Input` component
|
|
9
|
+
- eef2375: `Select` component
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- b61e950: Use `clsx` for cleaner class names
|
|
14
|
+
- b61e950: Add `global.scss` file and update docs to reflect global styles import
|
|
15
|
+
- 16c9c3e: Update docs to specify transpile requirement
|
|
16
|
+
- 2f6cd01: Memoized enhancers
|
|
17
|
+
- 646fccf: Add `status` for `Input` for success/error styling
|
|
18
|
+
- b61e950: Have `Text` use the theme fontFamily instead of inheriting
|
|
19
|
+
|
|
3
20
|
## 0.2.2
|
|
4
21
|
|
|
5
22
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -10,17 +10,73 @@ Paris 1.x styling is heavily inspired by Uber's [Base Web](https://baseweb.desig
|
|
|
10
10
|
|
|
11
11
|
## Getting started
|
|
12
12
|
|
|
13
|
-
First, install Paris
|
|
13
|
+
First, install Paris in your project:
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
|
-
pnpm i paris
|
|
16
|
+
pnpm i paris
|
|
17
17
|
# or
|
|
18
|
-
yarn add paris
|
|
18
|
+
yarn add paris
|
|
19
19
|
# or
|
|
20
|
-
npm i paris
|
|
20
|
+
npm i paris
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
You'll need to tell your bundler to transpile files from Paris. This is easy in Next.js 13.1+ with the `transpilePackages` option in `next.config.js`:
|
|
24
|
+
|
|
25
|
+
```js
|
|
26
|
+
// next.config.js
|
|
27
|
+
module.exports = {
|
|
28
|
+
// ...
|
|
29
|
+
transpilePackages: ['paris'],
|
|
30
|
+
};
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
For older versions of Next.js, you can use a plugin like [next-transpile-modules](https://www.npmjs.com/package/next-transpile-modules). Instructions for other bundlers are coming soon.
|
|
34
|
+
|
|
35
|
+
You'll need to configure your bundler to support Sass/SCSS and SCSS modules. In Next.js, support for SCSS modules is built-in and can be enabled by simply installing `sass` as a dependency.
|
|
36
|
+
|
|
37
|
+
Paris uses `pte` (our theming engine) for powering theming and initial styles through CSS variables. You can use `generateCSS` or `generateThemeInjection` from `paris/theme` to generate the CSS variables and inject them into your app through either a `style` or `script` tag in your document head respectively. Either method supports SSR and server components, since the initial theme is static.
|
|
38
|
+
|
|
39
|
+
Additionally, you need to import the static global styles from `paris/theme/global.scss`.
|
|
40
|
+
|
|
41
|
+
For example, with the Next.js 13 app directory, you can do all of this in your root `layout.tsx` file:
|
|
42
|
+
|
|
43
|
+
```tsx
|
|
44
|
+
// app/layout.tsx
|
|
45
|
+
import { generateCSS, generateThemeInjection, theme } from 'paris/theme';
|
|
46
|
+
|
|
47
|
+
// Import Paris's static global styling
|
|
48
|
+
import 'paris/theme/global.scss';
|
|
49
|
+
|
|
50
|
+
export default function RootLayout({
|
|
51
|
+
children,
|
|
52
|
+
}: {
|
|
53
|
+
children: React.ReactNode
|
|
54
|
+
}) {
|
|
55
|
+
return (
|
|
56
|
+
<html lang="en">
|
|
57
|
+
<head>
|
|
58
|
+
{/* Using a `style` tag (MUST have the id `pte-vars` and be in the document head) */}
|
|
59
|
+
<style
|
|
60
|
+
id="pte-vars"
|
|
61
|
+
dangerouslySetInnerHTML={{
|
|
62
|
+
__html: generateCSS(theme),
|
|
63
|
+
}}
|
|
64
|
+
/>
|
|
65
|
+
|
|
66
|
+
{/* Or, use a `script` tag (can be located anywhere, should be loaded as early as possible to avoid an unstyled flash) */}
|
|
67
|
+
<script
|
|
68
|
+
dangerouslySetInnerHTML={{
|
|
69
|
+
__html: generateThemeInjection(theme),
|
|
70
|
+
}}
|
|
71
|
+
/>
|
|
72
|
+
</head>
|
|
73
|
+
<body className={inter.className}>{children}</body>
|
|
74
|
+
</html>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Finally, map our types in your `.tsconfig.json` file (this is a temporary workaround that we'll fix soon):
|
|
24
80
|
|
|
25
81
|
```json
|
|
26
82
|
{
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "paris",
|
|
3
3
|
"author": "Sanil Chawla <sanil@slingshot.fm> (https://sanil.co)",
|
|
4
4
|
"description": "Paris is Slingshot's React design system. It's a collection of reusable components, design tokens, and guidelines that help us build consistent, accessible, and performant user interfaces.",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.3.0",
|
|
6
6
|
"homepage": "https://paris.slingshot.fm",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"repository": {
|
|
@@ -39,25 +39,31 @@
|
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"@changesets/cli": "^2.26.1",
|
|
42
|
+
"@fortawesome/fontawesome-svg-core": "^6.4.0",
|
|
43
|
+
"@fortawesome/free-regular-svg-icons": "^6.4.0",
|
|
44
|
+
"@fortawesome/free-solid-svg-icons": "^6.4.0",
|
|
45
|
+
"@fortawesome/react-fontawesome": "^0.2.0",
|
|
42
46
|
"@ssh/csstypes": "^1.1.0",
|
|
43
47
|
"@ssh/eslint-config": "^1.0.0",
|
|
44
|
-
"@storybook/addon-essentials": "^7.0.
|
|
45
|
-
"@storybook/addon-interactions": "^7.0.
|
|
46
|
-
"@storybook/addon-links": "^7.0.
|
|
47
|
-
"@storybook/
|
|
48
|
-
"@storybook/
|
|
49
|
-
"@storybook/
|
|
50
|
-
"@storybook/
|
|
48
|
+
"@storybook/addon-essentials": "^7.0.18",
|
|
49
|
+
"@storybook/addon-interactions": "^7.0.18",
|
|
50
|
+
"@storybook/addon-links": "^7.0.18",
|
|
51
|
+
"@storybook/addon-mdx-gfm": "^7.0.18",
|
|
52
|
+
"@storybook/addon-styling": "^1.0.8",
|
|
53
|
+
"@storybook/blocks": "^7.0.18",
|
|
54
|
+
"@storybook/manager-api": "^7.0.18",
|
|
55
|
+
"@storybook/nextjs": "^7.0.18",
|
|
56
|
+
"@storybook/react": "^7.0.18",
|
|
51
57
|
"@storybook/testing-library": "^0.1.0",
|
|
52
|
-
"@storybook/theming": "^7.0.
|
|
58
|
+
"@storybook/theming": "^7.0.18",
|
|
53
59
|
"@types/node": "18.15.11",
|
|
54
60
|
"@types/react": "18.0.31",
|
|
55
61
|
"@types/react-dom": "18.0.11",
|
|
56
62
|
"@typescript-eslint/eslint-plugin": "^5.13.0",
|
|
57
63
|
"@typescript-eslint/parser": "^5.0.0",
|
|
64
|
+
"autoprefixer": "^10.4.14",
|
|
58
65
|
"change-case": "^4.1.2",
|
|
59
66
|
"csstype": "^3.1.2",
|
|
60
|
-
"esbuild-scss-modules-plugin": "^1.1.1",
|
|
61
67
|
"eslint": "^8.2.0",
|
|
62
68
|
"eslint-config-next": "13.4.2",
|
|
63
69
|
"eslint-plugin-css": "^0.8.0",
|
|
@@ -66,20 +72,24 @@
|
|
|
66
72
|
"jss": "^10.10.0",
|
|
67
73
|
"jss-preset-default": "^10.10.0",
|
|
68
74
|
"next": "^13.4.2",
|
|
75
|
+
"postcss": "^8.4.23",
|
|
69
76
|
"react": "^18.2.0",
|
|
70
77
|
"react-dom": "^18.2.0",
|
|
71
78
|
"sass": "^1.62.1",
|
|
72
|
-
"storybook": "^7.0.
|
|
79
|
+
"storybook": "^7.0.18",
|
|
73
80
|
"storybook-dark-mode": "^3.0.0",
|
|
74
81
|
"title-case": "^3.0.3",
|
|
75
82
|
"ts-node": "^10.9.1",
|
|
76
83
|
"tsconfig-paths-webpack-plugin": "^4.0.1",
|
|
77
|
-
"tsup": "^6.7.0",
|
|
78
84
|
"type-fest": "^3.10.0",
|
|
79
85
|
"typescript": "^5.0.2"
|
|
80
86
|
},
|
|
81
87
|
"dependencies": {
|
|
82
|
-
"
|
|
88
|
+
"@ariakit/react": "^0.2.3",
|
|
89
|
+
"@headlessui/react": "^1.7.14",
|
|
90
|
+
"clsx": "^1.2.1",
|
|
91
|
+
"pte": "^0.4.7",
|
|
92
|
+
"ts-deepmerge": "^6.0.3"
|
|
83
93
|
},
|
|
84
94
|
"scripts": {
|
|
85
95
|
"dev": "next dev",
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import { isValidElement, memo } from 'react';
|
|
3
|
+
import type { Enhancer } from '../types/Enhancer';
|
|
4
|
+
|
|
5
|
+
export const renderEnhancer = (enhancer: Enhancer, size: number): ReactNode => {
|
|
6
|
+
if (isValidElement(enhancer)) {
|
|
7
|
+
return enhancer;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
if (typeof enhancer === 'function') {
|
|
11
|
+
return enhancer({ size });
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return enhancer;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const MemoizedEnhancer = memo<{ enhancer: Enhancer, size: number }>(({ enhancer, size }) => (
|
|
18
|
+
<>
|
|
19
|
+
{ renderEnhancer(enhancer, size)}
|
|
20
|
+
</>
|
|
21
|
+
), (prev, next) => prev.enhancer === next.enhancer && prev.size === next.size);
|
package/src/stories/Tokens.mdx
CHANGED
|
@@ -44,11 +44,3 @@ Tokens are the smallest pieces of design language that can be used to build comp
|
|
|
44
44
|
))}
|
|
45
45
|
</div>
|
|
46
46
|
|
|
47
|
-
<br />
|
|
48
|
-
|
|
49
|
-
## Typography
|
|
50
|
-
|
|
51
|
-
<div>
|
|
52
|
-
<pre style={{ color: pvar('colors.contentPrimary') }}>{JSON.stringify(LightTheme.typography, null, 4).replaceAll('"', '').replaceAll(',', '\n').replaceAll('{', '\n').replaceAll('}', '\n').replaceAll('\\', '')}</pre>
|
|
53
|
-
</div>
|
|
54
|
-
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
/*
|
|
2
|
+
* Main styles
|
|
3
|
+
*/
|
|
2
4
|
.button {
|
|
3
5
|
user-select: none;
|
|
4
6
|
|
|
@@ -12,17 +14,21 @@
|
|
|
12
14
|
|
|
13
15
|
transition: var(--pte-animations-interaction);
|
|
14
16
|
|
|
17
|
+
& > span {
|
|
18
|
+
margin-block-end: var(--pte-typography-verticalMetricsAdjust);
|
|
19
|
+
}
|
|
20
|
+
|
|
15
21
|
&:hover {
|
|
16
22
|
cursor: default;
|
|
17
23
|
background-color: var(--pte-colors-backgroundInverseTertiary);
|
|
18
24
|
}
|
|
19
25
|
|
|
20
|
-
|
|
26
|
+
&[aria-disabled=false]:active {
|
|
21
27
|
opacity: 0.9;
|
|
22
28
|
transform: scale(0.98);
|
|
23
29
|
}
|
|
24
30
|
|
|
25
|
-
&[disabled] {
|
|
31
|
+
&[aria-disabled=true] {
|
|
26
32
|
pointer-events: none;
|
|
27
33
|
}
|
|
28
34
|
}
|
|
@@ -41,7 +47,7 @@
|
|
|
41
47
|
border-color: var(--pte-colors-backgroundInverseTertiary);
|
|
42
48
|
}
|
|
43
49
|
|
|
44
|
-
&[disabled] {
|
|
50
|
+
&[aria-disabled=true] {
|
|
45
51
|
color: var(--pte-colors-contentDisabled);
|
|
46
52
|
background-color: var(--pte-colors-backgroundTertiary);
|
|
47
53
|
border-color: var(--pte-colors-backgroundTertiary);
|
|
@@ -53,7 +59,7 @@
|
|
|
53
59
|
background-color: transparent;
|
|
54
60
|
border-color: var(--pte-colors-contentPrimary);
|
|
55
61
|
|
|
56
|
-
&[disabled] {
|
|
62
|
+
&[aria-disabled=true] {
|
|
57
63
|
color: var(--pte-colors-contentDisabled);
|
|
58
64
|
border-color: var(--pte-colors-contentDisabled);
|
|
59
65
|
}
|
|
@@ -70,7 +76,7 @@
|
|
|
70
76
|
background-color: var(--pte-colors-backgroundTertiary);
|
|
71
77
|
}
|
|
72
78
|
|
|
73
|
-
&[disabled] {
|
|
79
|
+
&[aria-disabled=true] {
|
|
74
80
|
color: var(--pte-colors-contentDisabled);
|
|
75
81
|
}
|
|
76
82
|
}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { createElement } from 'react';
|
|
3
|
+
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
4
|
+
import { faPlus } from '@fortawesome/free-solid-svg-icons';
|
|
2
5
|
import { Button } from './Button';
|
|
3
6
|
|
|
4
7
|
const meta: Meta<typeof Button> = {
|
|
@@ -40,3 +43,17 @@ export const Tertiary: Story = {
|
|
|
40
43
|
kind: 'tertiary',
|
|
41
44
|
},
|
|
42
45
|
};
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Enhancers can be used to add icons at the start (left) or end (right) of a button.
|
|
49
|
+
*/
|
|
50
|
+
export const WithEnhancer: Story = {
|
|
51
|
+
args: {
|
|
52
|
+
children: 'Button',
|
|
53
|
+
kind: 'primary',
|
|
54
|
+
startEnhancer: ({ size }) => createElement(FontAwesomeIcon, {
|
|
55
|
+
icon: faPlus,
|
|
56
|
+
width: `${size}px`,
|
|
57
|
+
}),
|
|
58
|
+
},
|
|
59
|
+
};
|
|
@@ -1,10 +1,20 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import type {
|
|
4
|
-
|
|
4
|
+
FC, MouseEventHandler, ReactNode,
|
|
5
5
|
} from 'react';
|
|
6
|
+
import type { ButtonProps as AriaButtonProps } from '@ariakit/react';
|
|
7
|
+
import { Button as AriaButton } from '@ariakit/react';
|
|
8
|
+
import clsx from 'clsx';
|
|
6
9
|
import styles from './Button.module.scss';
|
|
7
10
|
import { Text } from '../text';
|
|
11
|
+
import type { Enhancer } from '../../types/Enhancer';
|
|
12
|
+
import { MemoizedEnhancer, renderEnhancer } from '../../helpers/renderEnhancer';
|
|
13
|
+
|
|
14
|
+
const EnhancerSizes = {
|
|
15
|
+
large: 13,
|
|
16
|
+
small: 9,
|
|
17
|
+
};
|
|
8
18
|
|
|
9
19
|
export type ButtonProps = {
|
|
10
20
|
/**
|
|
@@ -27,11 +37,11 @@ export type ButtonProps = {
|
|
|
27
37
|
*
|
|
28
38
|
* When Button shape is `circle` or `square`, this element will be the only visible content.
|
|
29
39
|
*/
|
|
30
|
-
startEnhancer?:
|
|
40
|
+
startEnhancer?: Enhancer;
|
|
31
41
|
/**
|
|
32
42
|
* An icon or other element to render after the Button's text. A `size` argument is passed that should be used to determine the width & height of the content displayed.
|
|
33
43
|
*/
|
|
34
|
-
endEnhancer?:
|
|
44
|
+
endEnhancer?: Enhancer;
|
|
35
45
|
/**
|
|
36
46
|
* Disables the Button, disallowing user interaction.
|
|
37
47
|
* @default false
|
|
@@ -47,11 +57,19 @@ export type ButtonProps = {
|
|
|
47
57
|
* This should be text. When Button shape is `circle` or `square`, the action description should still be passed here for screen readers.
|
|
48
58
|
*/
|
|
49
59
|
children: string;
|
|
50
|
-
} & Omit<
|
|
60
|
+
} & Omit<AriaButtonProps, 'children' | 'disabled' | 'onClick'>;
|
|
51
61
|
|
|
52
62
|
/**
|
|
53
63
|
* A `Button` is used to trigger an action or event, such as submitting a form, opening a dialog, canceling an action, or performing a delete operation.
|
|
54
64
|
*
|
|
65
|
+
* <hr />
|
|
66
|
+
*
|
|
67
|
+
* To use the `Button` component, import it as follows:
|
|
68
|
+
*
|
|
69
|
+
* ```js
|
|
70
|
+
* import { Button } from 'paris/button';
|
|
71
|
+
* ```
|
|
72
|
+
*
|
|
55
73
|
* @constructor
|
|
56
74
|
*/
|
|
57
75
|
export const Button: FC<ButtonProps> = ({
|
|
@@ -63,19 +81,38 @@ export const Button: FC<ButtonProps> = ({
|
|
|
63
81
|
endEnhancer,
|
|
64
82
|
onClick,
|
|
65
83
|
children,
|
|
84
|
+
disabled,
|
|
66
85
|
...props
|
|
67
86
|
}) => (
|
|
68
|
-
<
|
|
69
|
-
|
|
87
|
+
<AriaButton
|
|
88
|
+
{...props}
|
|
89
|
+
className={clsx(
|
|
90
|
+
styles.button,
|
|
91
|
+
styles[kind || 'primary'],
|
|
92
|
+
styles[shape || 'pill'],
|
|
93
|
+
styles[size || 'large'],
|
|
94
|
+
props?.className,
|
|
95
|
+
)}
|
|
96
|
+
aria-disabled={disabled ?? false}
|
|
70
97
|
type={type || 'button'}
|
|
71
98
|
aria-details={children}
|
|
72
|
-
onClick={onClick}
|
|
73
|
-
{
|
|
99
|
+
onClick={!disabled ? onClick : () => {}}
|
|
100
|
+
disabled={false}
|
|
74
101
|
>
|
|
75
|
-
{!!startEnhancer &&
|
|
102
|
+
{!!startEnhancer && (
|
|
103
|
+
<MemoizedEnhancer
|
|
104
|
+
enhancer={startEnhancer}
|
|
105
|
+
size={EnhancerSizes[size || 'large']}
|
|
106
|
+
/>
|
|
107
|
+
)}
|
|
76
108
|
<Text kind="labelXSmall">
|
|
77
109
|
{children || 'Button'}
|
|
78
110
|
</Text>
|
|
79
|
-
{!!endEnhancer &&
|
|
80
|
-
|
|
111
|
+
{!!endEnhancer && (
|
|
112
|
+
<MemoizedEnhancer
|
|
113
|
+
enhancer={endEnhancer}
|
|
114
|
+
size={EnhancerSizes[size || 'large']}
|
|
115
|
+
/>
|
|
116
|
+
)}
|
|
117
|
+
</AriaButton>
|
|
81
118
|
);
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
.transition {
|
|
2
|
+
transition: var(--pte-animations-interaction);
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
.enterFrom {
|
|
6
|
+
opacity: 0;
|
|
7
|
+
transform: translateY(-8px);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.enterTo {
|
|
11
|
+
opacity: 1;
|
|
12
|
+
transform: translateY(0);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.leaveFrom {
|
|
16
|
+
opacity: 1;
|
|
17
|
+
transform: translateY(0);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.leaveTo {
|
|
21
|
+
opacity: 0;
|
|
22
|
+
transform: translateY(-8px);
|
|
23
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
.inputContainer {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-direction: row;
|
|
4
|
+
gap: 12px;
|
|
5
|
+
min-height: 36px;
|
|
6
|
+
|
|
7
|
+
background-color: var(--pte-colors-backgroundSecondary);
|
|
8
|
+
|
|
9
|
+
//height: 36px;
|
|
10
|
+
width: 100%;
|
|
11
|
+
padding: calc(7.5px - var(--pte-typography-verticalMetricsAdjust)) 15px 7.5px;
|
|
12
|
+
|
|
13
|
+
font-size: var(--pte-typography-styles-paragraphSmall-fontSize);
|
|
14
|
+
font-style: var(--pte-typography-styles-paragraphSmall-fontStyle);
|
|
15
|
+
font-weight: var(--pte-typography-styles-paragraphSmall-fontWeight);
|
|
16
|
+
letter-spacing: var(--pte-typography-styles-paragraphSmall-letterSpacing);
|
|
17
|
+
line-height: var(--pte-typography-styles-paragraphSmall-lineHeight);
|
|
18
|
+
text-transform: var(--pte-typography-styles-paragraphSmall-textTransform);
|
|
19
|
+
|
|
20
|
+
border-width: 1px;
|
|
21
|
+
border-style: solid;
|
|
22
|
+
border-color: var(--pte-colors-backgroundSecondary);
|
|
23
|
+
border-radius: var(--pte-borders-radius-rectangle);
|
|
24
|
+
|
|
25
|
+
transition: var(--pte-animations-interaction);
|
|
26
|
+
|
|
27
|
+
&:focus-within {
|
|
28
|
+
outline: none;
|
|
29
|
+
border-color: var(--pte-colors-borderSelected);
|
|
30
|
+
background-color: var(--pte-colors-backgroundTertiary);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
&[data-status="disabled"] {
|
|
34
|
+
border-color: var(--pte-colors-backgroundTertiary);
|
|
35
|
+
background-color: var(--pte-colors-backgroundTertiary);
|
|
36
|
+
color: var(--pte-colors-contentDisabled);
|
|
37
|
+
pointer-events: none;
|
|
38
|
+
cursor: default;
|
|
39
|
+
|
|
40
|
+
&:focus-within {
|
|
41
|
+
border-color: var(--pte-colors-backgroundTertiary) !important;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
&[data-status="error"] {
|
|
46
|
+
border-color: var(--pte-colors-borderNegative);
|
|
47
|
+
background-color: var(--pte-colors-backgroundNegative);
|
|
48
|
+
color: var(--pte-colors-contentNegative);
|
|
49
|
+
|
|
50
|
+
&:focus-within {
|
|
51
|
+
color: var(--pte-colors-contentPrimary);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
&[data-status="success"] {
|
|
56
|
+
border-color: var(--pte-colors-borderPositive);
|
|
57
|
+
background-color: var(--pte-colors-backgroundPositive);
|
|
58
|
+
color: var(--pte-colors-contentPositive);
|
|
59
|
+
|
|
60
|
+
&:focus-within {
|
|
61
|
+
color: var(--pte-colors-contentPrimary);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
& > input, & > textarea {
|
|
66
|
+
width: 100%;
|
|
67
|
+
background-color: transparent;
|
|
68
|
+
padding: 0;
|
|
69
|
+
margin: 0;
|
|
70
|
+
border: none;
|
|
71
|
+
outline: none;
|
|
72
|
+
|
|
73
|
+
&::placeholder {
|
|
74
|
+
color: var(--pte-colors-contentTertiary);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
&[aria-disabled=true] {
|
|
78
|
+
color: var(--pte-colors-contentDisabled);
|
|
79
|
+
cursor: default;
|
|
80
|
+
|
|
81
|
+
&::placeholder {
|
|
82
|
+
color: var(--pte-colors-contentDisabled);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
&[type="color"]::-webkit-color-swatch {
|
|
87
|
+
border: 1px solid var(--pte-colors-borderSelected);
|
|
88
|
+
border-radius: var(--pte-borders-radius-circle);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
&[type="color"]::-webkit-color-swatch-wrapper {
|
|
92
|
+
width: 16px;
|
|
93
|
+
height: 100%;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
&[type="file"]::-webkit-file-upload-button {
|
|
97
|
+
display: none;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.enhancer {
|
|
103
|
+
color: var(--pte-colors-contentSecondary);
|
|
104
|
+
margin-block-start: -0.5px;
|
|
105
|
+
font-size: var(--pte-typography-styles-paragraphSmall-fontSize);
|
|
106
|
+
font-style: var(--pte-typography-styles-paragraphSmall-fontStyle);
|
|
107
|
+
font-weight: var(--pte-typography-styles-paragraphSmall-fontWeight);
|
|
108
|
+
letter-spacing: var(--pte-typography-styles-paragraphSmall-letterSpacing);
|
|
109
|
+
line-height: var(--pte-typography-styles-paragraphSmall-lineHeight);
|
|
110
|
+
text-transform: var(--pte-typography-styles-paragraphSmall-textTransform);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.container {
|
|
114
|
+
user-select: none;
|
|
115
|
+
cursor: default;
|
|
116
|
+
display: flex;
|
|
117
|
+
flex-direction: column;
|
|
118
|
+
gap: 8px;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Use double selector to ensure specificity is higher than the default styles
|
|
122
|
+
.label.label {
|
|
123
|
+
color: var(--pte-colors-contentPrimary);
|
|
124
|
+
font-weight: var(--pte-typography-boldFontWeight);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Use double selector to ensure specificity is higher than the default styles
|
|
128
|
+
.description.description {
|
|
129
|
+
color: var(--pte-colors-contentTertiary);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.hidden {
|
|
133
|
+
display: none;
|
|
134
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { createElement } from 'react';
|
|
3
|
+
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
4
|
+
import { faSearch } from '@fortawesome/free-solid-svg-icons';
|
|
5
|
+
import { Input } from './Input';
|
|
6
|
+
|
|
7
|
+
const meta: Meta<typeof Input> = {
|
|
8
|
+
title: 'Inputs/Input',
|
|
9
|
+
component: Input,
|
|
10
|
+
tags: ['autodocs'],
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export default meta;
|
|
14
|
+
type Story = StoryObj<typeof Input>;
|
|
15
|
+
|
|
16
|
+
export const Default: Story = {
|
|
17
|
+
args: {
|
|
18
|
+
placeholder: 'Billie Eilish',
|
|
19
|
+
label: 'Name',
|
|
20
|
+
description: 'Type your full name here.',
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export const Password: Story = {
|
|
25
|
+
args: {
|
|
26
|
+
type: 'password',
|
|
27
|
+
placeholder: 'Password',
|
|
28
|
+
label: 'Password',
|
|
29
|
+
hideLabel: true,
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export const Success: Story = {
|
|
34
|
+
args: {
|
|
35
|
+
placeholder: 'billie@eilish.com',
|
|
36
|
+
value: 'valid@email.com',
|
|
37
|
+
type: 'email',
|
|
38
|
+
label: 'Email',
|
|
39
|
+
description: 'Enter your email address.',
|
|
40
|
+
status: 'success',
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export const Error: Story = {
|
|
45
|
+
args: {
|
|
46
|
+
placeholder: 'billie@eilish.com',
|
|
47
|
+
value: 'notavalid@email',
|
|
48
|
+
type: 'email',
|
|
49
|
+
label: 'Email',
|
|
50
|
+
description: 'Enter your email address.',
|
|
51
|
+
status: 'error',
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export const Disabled: Story = {
|
|
56
|
+
args: {
|
|
57
|
+
placeholder: 'billie@eilish.com',
|
|
58
|
+
type: 'email',
|
|
59
|
+
label: 'Email',
|
|
60
|
+
description: 'Enter your email address.',
|
|
61
|
+
disabled: true,
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export const WithEnhancer: Story = {
|
|
66
|
+
args: {
|
|
67
|
+
placeholder: 'Billie Eilish',
|
|
68
|
+
label: 'Name',
|
|
69
|
+
description: 'Type your full name here.',
|
|
70
|
+
startEnhancer: ({ size }) => createElement(FontAwesomeIcon, {
|
|
71
|
+
icon: faSearch,
|
|
72
|
+
width: `${size}px`,
|
|
73
|
+
}),
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
export const WithEndEnhancer: Story = {
|
|
78
|
+
args: {
|
|
79
|
+
placeholder: 'Billie Eilish',
|
|
80
|
+
label: 'Name',
|
|
81
|
+
description: 'Type your full name here.',
|
|
82
|
+
endEnhancer: ({ size }) => createElement(FontAwesomeIcon, {
|
|
83
|
+
icon: faSearch,
|
|
84
|
+
width: `${size}px`,
|
|
85
|
+
}),
|
|
86
|
+
},
|
|
87
|
+
};
|