paris 0.3.0 → 0.4.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 +20 -0
- package/package.json +14 -12
- package/src/pages/_app.tsx +1 -1
- package/src/pages/index.tsx +1 -1
- package/src/stories/Pagination.mdx +73 -0
- package/src/stories/button/Button.module.scss +11 -1
- package/src/stories/button/Button.tsx +40 -17
- package/src/stories/card/Card.module.scss +14 -0
- package/src/stories/card/Card.stories.ts +33 -0
- package/src/stories/card/Card.tsx +60 -0
- package/src/stories/card/index.ts +1 -0
- package/src/stories/checkbox/Checkbox.module.scss +57 -0
- package/src/stories/checkbox/Checkbox.stories.ts +27 -0
- package/src/stories/checkbox/Checkbox.tsx +58 -0
- package/src/stories/checkbox/index.ts +1 -0
- package/src/stories/combobox/Combobox.module.scss +5 -0
- package/src/stories/combobox/Combobox.stories.ts +84 -0
- package/src/stories/combobox/Combobox.tsx +264 -0
- package/src/stories/combobox/index.ts +1 -0
- package/src/stories/dialog/Dialog.module.scss +187 -0
- package/src/stories/dialog/Dialog.stories.tsx +70 -0
- package/src/stories/dialog/Dialog.tsx +279 -0
- package/src/stories/dialog/index.ts +1 -0
- package/src/stories/drawer/Drawer.module.scss +284 -0
- package/src/stories/drawer/Drawer.stories.tsx +94 -0
- package/src/stories/drawer/Drawer.tsx +339 -0
- package/src/stories/drawer/index.ts +1 -0
- package/src/stories/field/Field.module.scss +5 -0
- package/src/stories/field/Field.stories.ts +32 -0
- package/src/stories/field/Field.tsx +106 -0
- package/src/stories/field/index.ts +1 -0
- package/src/stories/icon/ChevronLeft.tsx +11 -0
- package/src/stories/icon/ChevronRight.tsx +11 -0
- package/src/stories/icon/Close.tsx +11 -0
- package/src/stories/icon/Icon.module.scss +5 -0
- package/src/stories/icon/Icon.stories.ts +28 -0
- package/src/stories/icon/Icon.tsx +46 -0
- package/src/stories/icon/index.ts +4 -0
- package/src/stories/input/Input.module.scss +3 -2
- package/src/stories/input/Input.stories.ts +2 -0
- package/src/stories/input/Input.tsx +38 -73
- package/src/stories/pagination/index.ts +1 -0
- package/src/stories/pagination/usePagination.ts +106 -0
- package/src/stories/select/Select.module.scss +8 -4
- package/src/stories/select/Select.stories.ts +5 -3
- package/src/stories/select/Select.tsx +80 -7
- package/src/stories/theme/themes.ts +75 -2
- package/src/stories/theme/tw-preflight.css +3 -1
- package/src/stories/tilt/Tilt.module.scss +1 -0
- package/src/stories/tilt/Tilt.stories.tsx +43 -0
- package/src/stories/tilt/Tilt.tsx +63 -0
- package/src/stories/tilt/index.ts +1 -0
- package/src/stories/utility/RemoveFromDOM.tsx +19 -0
- package/src/stories/utility/TextWhenString.tsx +28 -0
- package/src/stories/utility/VisuallyHidden.tsx +25 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# paris
|
|
2
2
|
|
|
3
|
+
## 0.4.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 0a23074: Allow rendering `Button`s as anchors by passing `href` prop
|
|
8
|
+
- 6e5ea2c: `Tilt` component
|
|
9
|
+
- 50ab5e3: `Icon` component for included icons
|
|
10
|
+
- 50ab5e3: `Drawer` component
|
|
11
|
+
- 6e5ea2c: `Card` component
|
|
12
|
+
- dcd9bb6: `Combobox` component
|
|
13
|
+
- 05903f0: `Checkbox` component
|
|
14
|
+
- b758949: `Dialog` component
|
|
15
|
+
|
|
16
|
+
### Patch Changes
|
|
17
|
+
|
|
18
|
+
- bbe60be: `Field` component for generic form fields with a label and description
|
|
19
|
+
- 50ab5e3: Drawer pagination
|
|
20
|
+
- bbe60be: Add label/description for Select
|
|
21
|
+
- 50ab5e3: Glassmorphic Dialog variant
|
|
22
|
+
|
|
3
23
|
## 0.3.0
|
|
4
24
|
|
|
5
25
|
### Minor Changes
|
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.4.0",
|
|
6
6
|
"homepage": "https://paris.slingshot.fm",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"repository": {
|
|
@@ -31,7 +31,20 @@
|
|
|
31
31
|
"exports": {
|
|
32
32
|
"./*": "./src/stories/*"
|
|
33
33
|
},
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"@ariakit/react": "^0.2.3",
|
|
36
|
+
"@headlessui/react": "^1.7.14",
|
|
37
|
+
"@radix-ui/react-checkbox": "^1.0.4",
|
|
38
|
+
"clsx": "^1.2.1",
|
|
39
|
+
"pte": "^0.4.9",
|
|
40
|
+
"react-parallax-tilt": "^1.7.144",
|
|
41
|
+
"ts-deepmerge": "^6.0.3"
|
|
42
|
+
},
|
|
34
43
|
"peerDependencies": {
|
|
44
|
+
"@fortawesome/fontawesome-svg-core": "^6.4.0",
|
|
45
|
+
"@fortawesome/free-regular-svg-icons": "^6.4.0",
|
|
46
|
+
"@fortawesome/free-solid-svg-icons": "^6.4.0",
|
|
47
|
+
"@fortawesome/react-fontawesome": "^0.2.0",
|
|
35
48
|
"react": "^18.x || ^17.x",
|
|
36
49
|
"react-dom": "^18.x || ^17.x",
|
|
37
50
|
"sass": "^1.x",
|
|
@@ -39,10 +52,6 @@
|
|
|
39
52
|
},
|
|
40
53
|
"devDependencies": {
|
|
41
54
|
"@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",
|
|
46
55
|
"@ssh/csstypes": "^1.1.0",
|
|
47
56
|
"@ssh/eslint-config": "^1.0.0",
|
|
48
57
|
"@storybook/addon-essentials": "^7.0.18",
|
|
@@ -84,13 +93,6 @@
|
|
|
84
93
|
"type-fest": "^3.10.0",
|
|
85
94
|
"typescript": "^5.0.2"
|
|
86
95
|
},
|
|
87
|
-
"dependencies": {
|
|
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"
|
|
93
|
-
},
|
|
94
96
|
"scripts": {
|
|
95
97
|
"dev": "next dev",
|
|
96
98
|
"build": "next build",
|
package/src/pages/_app.tsx
CHANGED
package/src/pages/index.tsx
CHANGED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { Meta } from '@storybook/blocks';
|
|
2
|
+
|
|
3
|
+
<Meta title="Surfaces/Pagination" />
|
|
4
|
+
|
|
5
|
+
# Paginating Drawers
|
|
6
|
+
|
|
7
|
+
Paris contains a mechanism for creating pagination within a single surface. This is useful for complex or multi-step processes that would otherwise require a lot of scrolling or complicate the UI.
|
|
8
|
+
|
|
9
|
+
> This API currently supports `Drawer`, and will soon be expanded to support pagination of any surface.
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
Paris provides a hook for pagination called `usePagination`. This hook functions as a router that allows you to control pagination state and navigate between pages.
|
|
14
|
+
|
|
15
|
+
To enable pagination:
|
|
16
|
+
|
|
17
|
+
1. Instantiate a pagination router using `usePagination`.
|
|
18
|
+
2. Pass the pagination object to the Drawer using the `pagination` prop.
|
|
19
|
+
3. Pass your pages as children to the Drawer. Each must have a key that is unique across all pages, which can then be passed to `pagination.open` to navigate to that page.
|
|
20
|
+
|
|
21
|
+
The pagination object returned by `usePagination` has the following properties:
|
|
22
|
+
|
|
23
|
+
- `open`: A function that takes a page key and navigates to that page.
|
|
24
|
+
- `currentPage`: The key of the current page.
|
|
25
|
+
- `history`: An array of page keys that are currently in the navigable history stack.
|
|
26
|
+
- `back`: A function that navigates to the previous page.
|
|
27
|
+
- `forward`: A function that navigates to the next page.
|
|
28
|
+
- `canGoBack`: A boolean indicating whether the user can go back.
|
|
29
|
+
- `canGoForward`: A boolean indicating whether the user can go forward.
|
|
30
|
+
|
|
31
|
+
The hook creates a shared state object between your parent component and the drawer. This means that you can use the `pagination` object's methods to control the drawer from your parent component, or from pages passed to the drawer.
|
|
32
|
+
|
|
33
|
+
## Example
|
|
34
|
+
|
|
35
|
+
```tsx
|
|
36
|
+
import { Drawer } from 'paris/drawer';
|
|
37
|
+
import { Button } from 'paris/button';
|
|
38
|
+
import { usePagination } from 'paris/pagination';
|
|
39
|
+
|
|
40
|
+
const MyComponent = () => {
|
|
41
|
+
const pages = ['page1', 'page2', 'page3'] as const;
|
|
42
|
+
|
|
43
|
+
const pagination = usePagination<typeof pages>('step1');
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<Drawer
|
|
47
|
+
title="User creation flow"
|
|
48
|
+
open={true}
|
|
49
|
+
onClose={() => {}}
|
|
50
|
+
// Pass the entire pagination object to the Drawer to enable pagination
|
|
51
|
+
pagination={pagination}
|
|
52
|
+
>
|
|
53
|
+
<div key={pages[0]}>
|
|
54
|
+
Page 1
|
|
55
|
+
<Button
|
|
56
|
+
onClick={() => {
|
|
57
|
+
// Navigate to the next page using `open`
|
|
58
|
+
pagination.open('page2');
|
|
59
|
+
}}
|
|
60
|
+
>
|
|
61
|
+
Next Page
|
|
62
|
+
</Button>
|
|
63
|
+
</div>
|
|
64
|
+
<div key={pages[1]}>
|
|
65
|
+
Page 2
|
|
66
|
+
</div>
|
|
67
|
+
<div key={pages[2]}>
|
|
68
|
+
Page 3
|
|
69
|
+
</div>
|
|
70
|
+
</Drawer>
|
|
71
|
+
);
|
|
72
|
+
};
|
|
73
|
+
```
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Main styles
|
|
3
3
|
*/
|
|
4
4
|
.button {
|
|
5
|
-
user-select:
|
|
5
|
+
user-select: var(--pte-utils-defaultUserSelect);
|
|
6
6
|
|
|
7
7
|
border: 1px solid;
|
|
8
8
|
|
|
@@ -96,6 +96,11 @@
|
|
|
96
96
|
padding: 4px 15px;
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
+
.xs {
|
|
100
|
+
height: 16px;
|
|
101
|
+
padding: 2px 8px;
|
|
102
|
+
}
|
|
103
|
+
|
|
99
104
|
|
|
100
105
|
/*
|
|
101
106
|
* SHAPE
|
|
@@ -131,4 +136,9 @@
|
|
|
131
136
|
width: 20px;
|
|
132
137
|
padding: 4px;
|
|
133
138
|
}
|
|
139
|
+
|
|
140
|
+
&.xs {
|
|
141
|
+
width: 16px;
|
|
142
|
+
padding: 2px;
|
|
143
|
+
}
|
|
134
144
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import type {
|
|
4
|
-
FC, MouseEventHandler, ReactNode,
|
|
4
|
+
FC, HTMLAttributeAnchorTarget, MouseEventHandler, ReactNode,
|
|
5
5
|
} from 'react';
|
|
6
6
|
import type { ButtonProps as AriaButtonProps } from '@ariakit/react';
|
|
7
7
|
import { Button as AriaButton } from '@ariakit/react';
|
|
@@ -13,7 +13,8 @@ import { MemoizedEnhancer, renderEnhancer } from '../../helpers/renderEnhancer';
|
|
|
13
13
|
|
|
14
14
|
const EnhancerSizes = {
|
|
15
15
|
large: 13,
|
|
16
|
-
small:
|
|
16
|
+
small: 11,
|
|
17
|
+
xs: 9,
|
|
17
18
|
};
|
|
18
19
|
|
|
19
20
|
export type ButtonProps = {
|
|
@@ -26,7 +27,7 @@ export type ButtonProps = {
|
|
|
26
27
|
* The size of the Button.
|
|
27
28
|
* @default large
|
|
28
29
|
*/
|
|
29
|
-
size?: 'large' | 'small';
|
|
30
|
+
size?: 'large' | 'small' | 'xs';
|
|
30
31
|
/**
|
|
31
32
|
* The shape of the Button.
|
|
32
33
|
* @default pill
|
|
@@ -51,6 +52,14 @@ export type ButtonProps = {
|
|
|
51
52
|
* The interaction handler for the Button.
|
|
52
53
|
*/
|
|
53
54
|
onClick?: MouseEventHandler<HTMLButtonElement>;
|
|
55
|
+
/**
|
|
56
|
+
* Optionally, the Button can be rendered as an anchor element by passing an `href` prop. To use a Next.js Link component, use the `render` prop directly.
|
|
57
|
+
*/
|
|
58
|
+
href?: string;
|
|
59
|
+
/**
|
|
60
|
+
* Optionally, the target of the anchor element can be specified (defaults to `_self`).
|
|
61
|
+
*/
|
|
62
|
+
hrefTarget?: HTMLAttributeAnchorTarget;
|
|
54
63
|
/**
|
|
55
64
|
* The contents of the Button.
|
|
56
65
|
*
|
|
@@ -73,45 +82,59 @@ export type ButtonProps = {
|
|
|
73
82
|
* @constructor
|
|
74
83
|
*/
|
|
75
84
|
export const Button: FC<ButtonProps> = ({
|
|
76
|
-
kind,
|
|
77
|
-
size,
|
|
78
|
-
shape,
|
|
79
|
-
type,
|
|
85
|
+
kind = 'primary',
|
|
86
|
+
size = 'large',
|
|
87
|
+
shape = 'pill',
|
|
88
|
+
type = 'button',
|
|
80
89
|
startEnhancer,
|
|
81
90
|
endEnhancer,
|
|
82
91
|
onClick,
|
|
83
92
|
children,
|
|
84
93
|
disabled,
|
|
94
|
+
href,
|
|
85
95
|
...props
|
|
86
96
|
}) => (
|
|
87
97
|
<AriaButton
|
|
88
98
|
{...props}
|
|
89
99
|
className={clsx(
|
|
90
100
|
styles.button,
|
|
91
|
-
styles[kind
|
|
92
|
-
styles[shape
|
|
93
|
-
styles[size
|
|
101
|
+
styles[kind],
|
|
102
|
+
styles[shape],
|
|
103
|
+
styles[size],
|
|
94
104
|
props?.className,
|
|
95
105
|
)}
|
|
96
106
|
aria-disabled={disabled ?? false}
|
|
97
|
-
type={type
|
|
107
|
+
type={type}
|
|
98
108
|
aria-details={children}
|
|
99
|
-
onClick={!disabled ? onClick : () => {}}
|
|
109
|
+
onClick={!disabled && !href ? onClick : () => {}}
|
|
100
110
|
disabled={false}
|
|
111
|
+
{...href ? {
|
|
112
|
+
render: (properties) => (
|
|
113
|
+
// eslint-disable-next-line jsx-a11y/anchor-has-content
|
|
114
|
+
<a
|
|
115
|
+
{...properties}
|
|
116
|
+
href={href}
|
|
117
|
+
target={props.hrefTarget ?? '_self'}
|
|
118
|
+
rel={props.hrefTarget === '_self' ? undefined : 'noreferrer'}
|
|
119
|
+
/>
|
|
120
|
+
),
|
|
121
|
+
} : {}}
|
|
101
122
|
>
|
|
102
123
|
{!!startEnhancer && (
|
|
103
124
|
<MemoizedEnhancer
|
|
104
125
|
enhancer={startEnhancer}
|
|
105
|
-
size={EnhancerSizes[size
|
|
126
|
+
size={EnhancerSizes[size]}
|
|
106
127
|
/>
|
|
107
128
|
)}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
129
|
+
{!['circle', 'square'].includes(shape) && (
|
|
130
|
+
<Text kind="labelXSmall">
|
|
131
|
+
{children || 'Button'}
|
|
132
|
+
</Text>
|
|
133
|
+
)}
|
|
111
134
|
{!!endEnhancer && (
|
|
112
135
|
<MemoizedEnhancer
|
|
113
136
|
enhancer={endEnhancer}
|
|
114
|
-
size={EnhancerSizes[size
|
|
137
|
+
size={EnhancerSizes[size]}
|
|
115
138
|
/>
|
|
116
139
|
)}
|
|
117
140
|
</AriaButton>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
.container {
|
|
2
|
+
border: 1px solid var(--pte-borders-dropdown-color);
|
|
3
|
+
border-radius: var(--pte-borders-radius-rounded);
|
|
4
|
+
box-shadow: var(--pte-lighting-subtlePopup);
|
|
5
|
+
|
|
6
|
+
user-select: var(--pte-utils-defaultUserSelect);
|
|
7
|
+
width: max-content;
|
|
8
|
+
padding: 16px;
|
|
9
|
+
|
|
10
|
+
&.flat {
|
|
11
|
+
box-shadow: none;
|
|
12
|
+
border-color: var(--pte-colors-borderOpaque);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { Card } from './Card';
|
|
3
|
+
|
|
4
|
+
const meta: Meta<typeof Card> = {
|
|
5
|
+
title: 'Surfaces/Card',
|
|
6
|
+
component: Card,
|
|
7
|
+
tags: ['autodocs'],
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export default meta;
|
|
11
|
+
type Story = StoryObj<typeof Card>;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* By default, the card has a shadow and parallax tilt effect. You may want to adjust the max tilt angles through the `overrides.tilt.tiltMaxAngle(X|Y)` props to provide a good experience depending on the size of the content. See the [Tilt component](/docs/surfaces-tilt--docs) for all available props.
|
|
15
|
+
*/
|
|
16
|
+
export const Default: Story = {
|
|
17
|
+
args: {
|
|
18
|
+
children: 'Revenue: $3000',
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Setting the `kind` prop to `flat` will remove the shadow from the card.
|
|
24
|
+
*
|
|
25
|
+
* This example also disables the `tilt` effect by setting the `tilt` prop to `false`, but by default the `tilt` prop will remain set to `true`.
|
|
26
|
+
*/
|
|
27
|
+
export const Flat: Story = {
|
|
28
|
+
args: {
|
|
29
|
+
kind: 'flat',
|
|
30
|
+
tilt: false,
|
|
31
|
+
children: 'Revenue: $3000',
|
|
32
|
+
},
|
|
33
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { FC, ReactNode } from 'react';
|
|
2
|
+
import clsx from 'clsx';
|
|
3
|
+
import { createElement, Fragment } from 'react';
|
|
4
|
+
import styles from './Card.module.scss';
|
|
5
|
+
import type { TiltProps } from '../tilt';
|
|
6
|
+
import { Tilt } from '../tilt';
|
|
7
|
+
|
|
8
|
+
export type CardProps = {
|
|
9
|
+
/**
|
|
10
|
+
* The visual variant of the Card.
|
|
11
|
+
*
|
|
12
|
+
* @default "hover"
|
|
13
|
+
*/
|
|
14
|
+
kind?: 'hover' | 'flat';
|
|
15
|
+
/**
|
|
16
|
+
* Whether the Card should tilt on hover.
|
|
17
|
+
*
|
|
18
|
+
* @default true
|
|
19
|
+
*/
|
|
20
|
+
tilt?: boolean;
|
|
21
|
+
/** The contents of the Card. */
|
|
22
|
+
children?: ReactNode | ReactNode[];
|
|
23
|
+
/**
|
|
24
|
+
* Overrides for nested components.
|
|
25
|
+
*/
|
|
26
|
+
overrides?: {
|
|
27
|
+
tilt?: TiltProps;
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* A Card component.
|
|
33
|
+
*
|
|
34
|
+
* <hr />
|
|
35
|
+
*
|
|
36
|
+
* To use this component, import it as follows:
|
|
37
|
+
*
|
|
38
|
+
* ```js
|
|
39
|
+
* import { Card } from 'paris/card';
|
|
40
|
+
* ```
|
|
41
|
+
* @constructor
|
|
42
|
+
*/
|
|
43
|
+
export const Card: FC<CardProps> = ({
|
|
44
|
+
kind = 'hover',
|
|
45
|
+
tilt = true,
|
|
46
|
+
children,
|
|
47
|
+
overrides,
|
|
48
|
+
}) => (
|
|
49
|
+
<Tilt
|
|
50
|
+
disableTilt={!tilt}
|
|
51
|
+
{...overrides?.tilt}
|
|
52
|
+
className={clsx(
|
|
53
|
+
styles.container,
|
|
54
|
+
styles[kind],
|
|
55
|
+
overrides?.tilt?.className,
|
|
56
|
+
)}
|
|
57
|
+
>
|
|
58
|
+
{children}
|
|
59
|
+
</Tilt>
|
|
60
|
+
);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Card';
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
.container {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-direction: row;
|
|
4
|
+
align-items: center;
|
|
5
|
+
justify-content: flex-start;
|
|
6
|
+
gap: 12px;
|
|
7
|
+
user-select: var(--pte-utils-defaultUserSelect);
|
|
8
|
+
cursor: default;
|
|
9
|
+
&button {
|
|
10
|
+
all: unset;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.root {
|
|
15
|
+
background-color: var(--pte-colors-backgroundPrimary);
|
|
16
|
+
width: 14px;
|
|
17
|
+
height: 14px;
|
|
18
|
+
display: flex;
|
|
19
|
+
align-items: center;
|
|
20
|
+
justify-content: center;
|
|
21
|
+
|
|
22
|
+
border: 2px solid var(--pte-colors-contentPrimary);
|
|
23
|
+
border-radius: var(--pte-borders-radius-rectangle);
|
|
24
|
+
box-shadow: var(--pte-lighting-shallowBelow);
|
|
25
|
+
|
|
26
|
+
&:hover {
|
|
27
|
+
//background-color: ;
|
|
28
|
+
}
|
|
29
|
+
&:focus-visible {
|
|
30
|
+
outline: 1px solid var(--pte-colors-contentTertiary);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
position: relative;
|
|
34
|
+
&:after {
|
|
35
|
+
content: "";
|
|
36
|
+
width: 100%;
|
|
37
|
+
height: 100%;
|
|
38
|
+
position: absolute;
|
|
39
|
+
background-color: var(--pte-colors-backgroundPrimary);
|
|
40
|
+
transition: var(--pte-animations-interaction);
|
|
41
|
+
transition-delay: 50ms;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
&[data-state="checked"], &[data-state="indeterminate"] {
|
|
45
|
+
&:after {
|
|
46
|
+
opacity: 0;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
& span {
|
|
51
|
+
transition: var(--pte-animations-interaction);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.indicator {
|
|
56
|
+
cursor: default;
|
|
57
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { createElement, useState } from 'react';
|
|
3
|
+
import { Checkbox } from './Checkbox';
|
|
4
|
+
|
|
5
|
+
const meta: Meta<typeof Checkbox> = {
|
|
6
|
+
title: 'Inputs/Checkbox',
|
|
7
|
+
component: Checkbox,
|
|
8
|
+
tags: ['autodocs'],
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export default meta;
|
|
12
|
+
type Story = StoryObj<typeof Checkbox>;
|
|
13
|
+
|
|
14
|
+
export const Default: Story = {
|
|
15
|
+
args: {
|
|
16
|
+
children: 'I agree to the terms of service',
|
|
17
|
+
},
|
|
18
|
+
render: (args) => {
|
|
19
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
20
|
+
const [checked, setChecked] = useState(false);
|
|
21
|
+
return createElement(Checkbox, {
|
|
22
|
+
...args,
|
|
23
|
+
checked,
|
|
24
|
+
onChange: (e) => setChecked(!!e),
|
|
25
|
+
});
|
|
26
|
+
},
|
|
27
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { FC } from 'react';
|
|
2
|
+
import { useId } from 'react';
|
|
3
|
+
import * as RadixCheckbox from '@radix-ui/react-checkbox';
|
|
4
|
+
import styles from './Checkbox.module.scss';
|
|
5
|
+
import { pvar } from '../theme';
|
|
6
|
+
|
|
7
|
+
export type CheckboxProps = {
|
|
8
|
+
checked?: boolean;
|
|
9
|
+
onChange?: (checked: boolean | 'indeterminate') => void;
|
|
10
|
+
disabled?: boolean;
|
|
11
|
+
/** The contents of the Checkbox. */
|
|
12
|
+
children?: string;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* A Checkbox component.
|
|
17
|
+
*
|
|
18
|
+
* <hr />
|
|
19
|
+
*
|
|
20
|
+
* To use this component, import it as follows:
|
|
21
|
+
*
|
|
22
|
+
* ```js
|
|
23
|
+
* import { Checkbox } from 'paris/checkbox';
|
|
24
|
+
* ```
|
|
25
|
+
* @constructor
|
|
26
|
+
*/
|
|
27
|
+
export const Checkbox: FC<CheckboxProps> = ({
|
|
28
|
+
checked,
|
|
29
|
+
onChange,
|
|
30
|
+
disabled,
|
|
31
|
+
children,
|
|
32
|
+
}) => {
|
|
33
|
+
const inputID = useId();
|
|
34
|
+
return (
|
|
35
|
+
<label
|
|
36
|
+
htmlFor={inputID}
|
|
37
|
+
className={styles.container}
|
|
38
|
+
>
|
|
39
|
+
<RadixCheckbox.Root
|
|
40
|
+
id={inputID}
|
|
41
|
+
className={styles.root}
|
|
42
|
+
checked={checked}
|
|
43
|
+
onCheckedChange={onChange}
|
|
44
|
+
data-disabled={disabled}
|
|
45
|
+
>
|
|
46
|
+
<RadixCheckbox.Indicator className={styles.indicator}>
|
|
47
|
+
<svg width={14} height={14} viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
48
|
+
<path
|
|
49
|
+
d="M0.333374 0.333252V13.6666H13.6667V0.333252H0.333374ZM6.00004 10.3999L2.26672 6.66658L3.66671 5.26658L5.93339 7.53325L10.2 3.26658L11.6001 4.66659L6.00004 10.3999Z"
|
|
50
|
+
fill={pvar('colors.contentPrimary')}
|
|
51
|
+
/>
|
|
52
|
+
</svg>
|
|
53
|
+
</RadixCheckbox.Indicator>
|
|
54
|
+
</RadixCheckbox.Root>
|
|
55
|
+
{children}
|
|
56
|
+
</label>
|
|
57
|
+
);
|
|
58
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Checkbox';
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/* eslint-disable react-hooks/rules-of-hooks,react/no-children-prop */
|
|
2
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
|
+
import { createElement, useState } from 'react';
|
|
4
|
+
import type { Option } from './Combobox';
|
|
5
|
+
import { Combobox } from './Combobox';
|
|
6
|
+
import { Text } from '../text';
|
|
7
|
+
|
|
8
|
+
const meta: Meta<typeof Combobox> = {
|
|
9
|
+
title: 'Inputs/Combobox',
|
|
10
|
+
component: Combobox,
|
|
11
|
+
tags: ['autodocs'],
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export default meta;
|
|
15
|
+
type Story = StoryObj<typeof Combobox>;
|
|
16
|
+
|
|
17
|
+
export const Default: Story = {
|
|
18
|
+
args: {
|
|
19
|
+
label: 'Share',
|
|
20
|
+
description: 'Search for a friend to share this document with.',
|
|
21
|
+
placeholder: 'Search...',
|
|
22
|
+
options: [
|
|
23
|
+
{
|
|
24
|
+
id: '1',
|
|
25
|
+
node: createElement(Text, {
|
|
26
|
+
kind: 'paragraphSmall',
|
|
27
|
+
children: "Billie O'Connell",
|
|
28
|
+
}),
|
|
29
|
+
metadata: {
|
|
30
|
+
name: "Billie O'Connell",
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
id: '2',
|
|
35
|
+
node: createElement(Text, {
|
|
36
|
+
kind: 'paragraphSmall',
|
|
37
|
+
children: "Finneas O'Connell",
|
|
38
|
+
}),
|
|
39
|
+
metadata: {
|
|
40
|
+
name: "Finneas O'Connell",
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
id: '3',
|
|
45
|
+
node: createElement(Text, {
|
|
46
|
+
kind: 'paragraphSmall',
|
|
47
|
+
children: 'Taylor Alison Swift',
|
|
48
|
+
}),
|
|
49
|
+
metadata: {
|
|
50
|
+
name: 'Taylor Alison Swift',
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
id: '4',
|
|
55
|
+
node: createElement(Text, {
|
|
56
|
+
kind: 'paragraphSmall',
|
|
57
|
+
children: 'Taylor Alison Swift',
|
|
58
|
+
}),
|
|
59
|
+
metadata: {
|
|
60
|
+
name: 'Taylor Alison Swift',
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
},
|
|
65
|
+
render: (args) => {
|
|
66
|
+
const [selected, setSelected] = useState<Option | null>(null);
|
|
67
|
+
const [inputValue, setInputValue] = useState<string>('');
|
|
68
|
+
return createElement('div', {
|
|
69
|
+
style: { minHeight: '200px' },
|
|
70
|
+
}, createElement(Combobox<{ name: string }>, {
|
|
71
|
+
...args,
|
|
72
|
+
value: (selected?.id === null) ? {
|
|
73
|
+
id: null,
|
|
74
|
+
node: inputValue,
|
|
75
|
+
metadata: {
|
|
76
|
+
name: inputValue,
|
|
77
|
+
},
|
|
78
|
+
} : selected as Option<{ name: string }> | null,
|
|
79
|
+
options: (args.options as Option<{ name: string }>[]).filter((o) => (o.metadata?.name as string || '').toLowerCase().includes(inputValue.toLowerCase())),
|
|
80
|
+
onChange: (e) => setSelected(e),
|
|
81
|
+
onInputChange: (e) => setInputValue(e),
|
|
82
|
+
}));
|
|
83
|
+
},
|
|
84
|
+
};
|