paris 0.9.2 → 0.10.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 +15 -0
- package/package.json +2 -1
- package/src/stories/accordion/Accordion.module.scss +2 -2
- package/src/stories/button/Button.stories.ts +7 -0
- package/src/stories/button/Button.tsx +3 -1
- package/src/stories/card/Card.module.scss +35 -7
- package/src/stories/card/Card.stories.ts +17 -6
- package/src/stories/card/Card.tsx +17 -11
- package/src/stories/cardbutton/CardButton.module.scss +43 -0
- package/src/stories/cardbutton/CardButton.stories.tsx +24 -0
- package/src/stories/cardbutton/CardButton.tsx +86 -0
- package/src/stories/cardbutton/index.ts +1 -0
- package/src/stories/checkbox/Checkbox.module.scss +70 -32
- package/src/stories/checkbox/Checkbox.stories.ts +16 -0
- package/src/stories/checkbox/Checkbox.tsx +31 -10
- package/src/stories/combobox/Combobox.tsx +8 -1
- package/src/stories/select/Select.module.scss +84 -0
- package/src/stories/select/Select.stories.ts +16 -0
- package/src/stories/select/Select.tsx +31 -3
- package/src/stories/theme/themes.ts +7 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# paris
|
|
2
2
|
|
|
3
|
+
## 0.10.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 41e4bb5: CardButton: new component, clickable card button
|
|
8
|
+
- 41e4bb5: Select: new `card` kind, and `hasOptionBorder` prop for listbox
|
|
9
|
+
- 41e4bb5: Card: removed `hover` kind, replaced with `raised` kind, new `surface` kind, updates to `flat` kind, new `status` prop with a `pending` state
|
|
10
|
+
- 41e4bb5: Checkbox: added `surface` kind
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- 41e4bb5: Accordion: updated border-bottom color
|
|
15
|
+
- 41e4bb5: Theme: added `roundedMedium` border radius, updated dark mode dropdown and overlayBlack variables
|
|
16
|
+
- 41e4bb5: Combobox: added `hasOptionBorder` prop to match Select listbox
|
|
17
|
+
|
|
3
18
|
## 0.9.2
|
|
4
19
|
|
|
5
20
|
### Patch 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.10.0",
|
|
6
6
|
"homepage": "https://paris.slingshot.fm",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"repository": {
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
"./button": "./src/stories/button/index.ts",
|
|
35
35
|
"./callout": "./src/stories/callout/index.ts",
|
|
36
36
|
"./card": "./src/stories/card/index.ts",
|
|
37
|
+
"./cardbutton": "./src/stories/cardbutton/index.ts",
|
|
37
38
|
"./checkbox": "./src/stories/checkbox/index.ts",
|
|
38
39
|
"./combobox": "./src/stories/combobox/index.ts",
|
|
39
40
|
"./dialog": "./src/stories/dialog/index.ts",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
.container {
|
|
2
2
|
color: var(--pte-new-colors-contentPrimary);
|
|
3
|
-
border-bottom: 1px solid var(--pte-new-colors-
|
|
3
|
+
border-bottom: 1px solid var(--pte-new-colors-borderMedium);
|
|
4
4
|
cursor: pointer;
|
|
5
5
|
transition: all var(--pte-animations-duration-relaxed) var(--pte-animations-timing-easeInOutExpo);
|
|
6
6
|
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
border-bottom: 1px solid transparent;
|
|
20
20
|
transition: border-bottom-color var(--pte-animations-duration-gradual) var(--pte-animations-timing-easeInOutExpo);
|
|
21
21
|
&.open {
|
|
22
|
-
border-bottom-color: var(--pte-new-colors-
|
|
22
|
+
border-bottom-color: var(--pte-new-colors-borderMedium);
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
25
|
|
|
@@ -123,7 +123,9 @@ export type ButtonProps = {
|
|
|
123
123
|
* This should be text. When Button shape is `circle` or `square`, the action description should still be passed here for screen readers.
|
|
124
124
|
*/
|
|
125
125
|
children?: ReactNode | ReactNode[];
|
|
126
|
-
|
|
126
|
+
/**
|
|
127
|
+
* Displays a notification dot.
|
|
128
|
+
*/
|
|
127
129
|
displayNotificationDot?: boolean;
|
|
128
130
|
} & Omit<AriaButtonProps, 'children' | 'disabled' | 'onClick'>;
|
|
129
131
|
|
|
@@ -1,14 +1,42 @@
|
|
|
1
1
|
.container {
|
|
2
|
-
|
|
2
|
+
user-select: var(--pte-utils-defaultUserSelect);
|
|
3
|
+
width: auto;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
.raised {
|
|
3
7
|
border-radius: var(--pte-borders-radius-rounded);
|
|
8
|
+
background-color: var(--pte-new-colors-surfacePrimary);
|
|
4
9
|
box-shadow: var(--pte-new-lighting-subtlePopup);
|
|
10
|
+
border: 1px solid var(--pte-new-colors-surfacePrimary);
|
|
5
11
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
12
|
+
&.pending {
|
|
13
|
+
border: 1px dashed var(--pte-new-colors-borderMedium);
|
|
14
|
+
background-color: var(--pte-new-colors-surfaceSecondary);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
9
17
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
18
|
+
.surface {
|
|
19
|
+
border-radius: var(--pte-new-borders-radius-roundedMedium);
|
|
20
|
+
border: 1px solid var(--pte-new-colors-borderMedium);
|
|
21
|
+
background-color: var(--pte-new-colors-overlaySubtle);
|
|
22
|
+
|
|
23
|
+
&.pending {
|
|
24
|
+
border: 1px dashed var(--pte-new-colors-borderMedium);
|
|
25
|
+
background-color: transparent;
|
|
13
26
|
}
|
|
14
27
|
}
|
|
28
|
+
|
|
29
|
+
.flat {
|
|
30
|
+
border-radius: var(--pte-new-borders-radius-roundedMedium);
|
|
31
|
+
border: 1px solid var(--pte-new-colors-borderStrong);
|
|
32
|
+
background: linear-gradient(0deg, var(--pte-new-colors-overlayWhiteSubtle) 0%, var(--pte-new-colors-overlayWhiteSubtle) 100%), var(--pte-new-colors-surfacePrimary);
|
|
33
|
+
|
|
34
|
+
&.pending {
|
|
35
|
+
border: 1px dashed var(--pte-new-colors-borderStrong);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.text {
|
|
40
|
+
padding: 10px 12px;
|
|
41
|
+
color: var(--pte-new-colors-contentPrimary);
|
|
42
|
+
}
|
|
@@ -10,18 +10,29 @@ const meta: Meta<typeof Card> = {
|
|
|
10
10
|
export default meta;
|
|
11
11
|
type Story = StoryObj<typeof Card>;
|
|
12
12
|
|
|
13
|
-
export const
|
|
13
|
+
export const Raised: Story = {
|
|
14
14
|
args: {
|
|
15
|
-
children: '
|
|
15
|
+
children: 'Hello world!',
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const Surface: Story = {
|
|
20
|
+
args: {
|
|
21
|
+
kind: 'surface',
|
|
22
|
+
children: 'Hello world!',
|
|
16
23
|
},
|
|
17
24
|
};
|
|
18
25
|
|
|
19
|
-
/**
|
|
20
|
-
* Setting the `kind` prop to `flat` will remove the shadow from the card.
|
|
21
|
-
*/
|
|
22
26
|
export const Flat: Story = {
|
|
23
27
|
args: {
|
|
24
28
|
kind: 'flat',
|
|
25
|
-
children: '
|
|
29
|
+
children: 'Hello world!',
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export const Pending: Story = {
|
|
34
|
+
args: {
|
|
35
|
+
children: 'Hello world!',
|
|
36
|
+
status: 'pending',
|
|
26
37
|
},
|
|
27
38
|
};
|
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
import type { FC, HTMLAttributes, ReactNode } from 'react';
|
|
2
2
|
import clsx from 'clsx';
|
|
3
3
|
import styles from './Card.module.scss';
|
|
4
|
+
import { TextWhenString } from '../utility';
|
|
4
5
|
|
|
5
6
|
export type CardProps = {
|
|
6
7
|
/**
|
|
7
|
-
* The visual variant of the Card.
|
|
8
|
+
* The visual variant of the Card. `raised` is the default variant with a drop shadow, `surface` is a variant with a border and overlay, `flat` is a variant with a border.
|
|
8
9
|
*
|
|
9
|
-
* @default "
|
|
10
|
+
* @default "raised"
|
|
10
11
|
*/
|
|
11
|
-
kind?: '
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
kind?: 'raised' | 'surface' | 'flat';
|
|
13
|
+
/**
|
|
14
|
+
* The status of the Card. `pending` adds a dashed border.
|
|
15
|
+
*
|
|
16
|
+
* @default "default"
|
|
17
|
+
*/
|
|
18
|
+
status?: 'default' | 'pending';
|
|
18
19
|
/** The contents of the Card. */
|
|
19
20
|
children?: ReactNode | ReactNode[];
|
|
20
21
|
// /**
|
|
@@ -38,7 +39,8 @@ export type CardProps = {
|
|
|
38
39
|
* @constructor
|
|
39
40
|
*/
|
|
40
41
|
export const Card: FC<CardProps> = ({
|
|
41
|
-
kind = '
|
|
42
|
+
kind = 'raised',
|
|
43
|
+
status = 'default',
|
|
42
44
|
children,
|
|
43
45
|
...props
|
|
44
46
|
}) => (
|
|
@@ -47,9 +49,13 @@ export const Card: FC<CardProps> = ({
|
|
|
47
49
|
className={clsx(
|
|
48
50
|
styles.container,
|
|
49
51
|
styles[kind],
|
|
52
|
+
styles[status],
|
|
53
|
+
typeof children === 'string' && styles.text,
|
|
50
54
|
props?.className,
|
|
51
55
|
)}
|
|
52
56
|
>
|
|
53
|
-
|
|
57
|
+
<TextWhenString kind="paragraphMedium">
|
|
58
|
+
{children}
|
|
59
|
+
</TextWhenString>
|
|
54
60
|
</div>
|
|
55
61
|
);
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
.container {
|
|
2
|
+
user-select: var(--pte-utils-defaultUserSelect);
|
|
3
|
+
width: auto;
|
|
4
|
+
background: var(--pte-new-colors-surfacePrimary);
|
|
5
|
+
border-radius: var(--pte-new-borders-radius-roundedMedium);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.card {
|
|
9
|
+
transition: var(--pte-animations-interaction);
|
|
10
|
+
width: 100%;
|
|
11
|
+
|
|
12
|
+
border: 1px solid var(--pte-new-colors-borderStrong);
|
|
13
|
+
background-color: var(--pte-new-colors-overlayWhiteSubtle);
|
|
14
|
+
border-radius: var(--pte-new-borders-radius-roundedMedium);
|
|
15
|
+
|
|
16
|
+
display: flex;
|
|
17
|
+
justify-content: flex-start;
|
|
18
|
+
align-items: center;
|
|
19
|
+
|
|
20
|
+
&:hover {
|
|
21
|
+
background-color: var(--pte-new-colors-overlayStrong);
|
|
22
|
+
cursor: default;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
&[aria-disabled=false]:active {
|
|
26
|
+
//border: 1px solid var(--pte-new-colors-borderUltrastrong);
|
|
27
|
+
background-color: var(--pte-new-colors-overlayMedium);
|
|
28
|
+
transform: scale(0.996);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
&[aria-disabled=true] {
|
|
32
|
+
pointer-events: none;
|
|
33
|
+
|
|
34
|
+
&.text {
|
|
35
|
+
color: var(--pte-new-colors-contentDisabled);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.text {
|
|
41
|
+
padding: 4px 10px;
|
|
42
|
+
color: var(--pte-new-colors-contentPrimary);
|
|
43
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { CardButton } from './CardButton';
|
|
3
|
+
|
|
4
|
+
const meta: Meta<typeof CardButton> = {
|
|
5
|
+
title: 'Inputs/CardButton',
|
|
6
|
+
component: CardButton,
|
|
7
|
+
tags: ['autodocs'],
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export default meta;
|
|
11
|
+
type Story = StoryObj<typeof CardButton>;
|
|
12
|
+
|
|
13
|
+
export const Default: Story = {
|
|
14
|
+
args: {
|
|
15
|
+
children: 'Hello world!',
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const Disabled: Story = {
|
|
20
|
+
args: {
|
|
21
|
+
children: 'Hello world!',
|
|
22
|
+
disabled: true,
|
|
23
|
+
},
|
|
24
|
+
};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import type {
|
|
4
|
+
FC, HTMLAttributeAnchorTarget, MouseEventHandler, ReactNode,
|
|
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';
|
|
9
|
+
import styles from './CardButton.module.scss';
|
|
10
|
+
import { TextWhenString } from '../utility';
|
|
11
|
+
|
|
12
|
+
export type CardButtonProps = {
|
|
13
|
+
/**
|
|
14
|
+
* Disables the Button, disallowing user interaction.
|
|
15
|
+
* @default false
|
|
16
|
+
*/
|
|
17
|
+
disabled?: boolean;
|
|
18
|
+
/**
|
|
19
|
+
* The interaction handler for the Button.
|
|
20
|
+
*/
|
|
21
|
+
onClick?: MouseEventHandler<HTMLButtonElement>;
|
|
22
|
+
/**
|
|
23
|
+
* 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.
|
|
24
|
+
*/
|
|
25
|
+
href?: string;
|
|
26
|
+
/**
|
|
27
|
+
* Optionally, the target of the anchor element can be specified (defaults to `_self`).
|
|
28
|
+
*/
|
|
29
|
+
hreftarget?: HTMLAttributeAnchorTarget;
|
|
30
|
+
/**
|
|
31
|
+
* The contents of the Button.
|
|
32
|
+
*/
|
|
33
|
+
children?: ReactNode | ReactNode[];
|
|
34
|
+
} & Omit<AriaButtonProps, 'children' | 'disabled' | 'onClick'>;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* A CardButton component.
|
|
38
|
+
*
|
|
39
|
+
* <hr />
|
|
40
|
+
*
|
|
41
|
+
* To use this component, import it as follows:
|
|
42
|
+
*
|
|
43
|
+
* ```js
|
|
44
|
+
* import { CardButton } from 'paris/cardbutton';
|
|
45
|
+
* ```
|
|
46
|
+
* @constructor
|
|
47
|
+
*/
|
|
48
|
+
export const CardButton: FC<CardButtonProps> = ({
|
|
49
|
+
type = 'button',
|
|
50
|
+
onClick,
|
|
51
|
+
children,
|
|
52
|
+
disabled,
|
|
53
|
+
href,
|
|
54
|
+
...props
|
|
55
|
+
}) => (
|
|
56
|
+
<div className={styles.container}>
|
|
57
|
+
<AriaButton
|
|
58
|
+
{...props}
|
|
59
|
+
className={clsx(
|
|
60
|
+
styles.card,
|
|
61
|
+
typeof children === 'string' && styles.text,
|
|
62
|
+
props?.className,
|
|
63
|
+
)}
|
|
64
|
+
aria-disabled={disabled ?? false}
|
|
65
|
+
type={type}
|
|
66
|
+
aria-details={typeof children === 'string' ? children : undefined}
|
|
67
|
+
onClick={!disabled && !href ? onClick : () => {}}
|
|
68
|
+
disabled={false}
|
|
69
|
+
{...href ? {
|
|
70
|
+
render: (properties) => (
|
|
71
|
+
// eslint-disable-next-line jsx-a11y/anchor-has-content
|
|
72
|
+
<a
|
|
73
|
+
{...properties}
|
|
74
|
+
href={href}
|
|
75
|
+
target={props.hreftarget ?? '_self'}
|
|
76
|
+
rel={props.hreftarget === '_self' ? undefined : 'noreferrer'}
|
|
77
|
+
/>
|
|
78
|
+
),
|
|
79
|
+
} : {}}
|
|
80
|
+
>
|
|
81
|
+
<TextWhenString kind="paragraphMedium">
|
|
82
|
+
{children}
|
|
83
|
+
</TextWhenString>
|
|
84
|
+
</AriaButton>
|
|
85
|
+
</div>
|
|
86
|
+
);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './CardButton';
|
|
@@ -20,48 +20,78 @@
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
.root {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
23
|
+
&.default {
|
|
24
|
+
background-color: transparent;
|
|
25
|
+
width: 14px;
|
|
26
|
+
height: 14px;
|
|
27
|
+
display: flex;
|
|
28
|
+
align-items: center;
|
|
29
|
+
justify-content: center;
|
|
30
|
+
flex-shrink: 0;
|
|
30
31
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
//box-shadow: var(--pte-new-lighting-shallowBelow);
|
|
32
|
+
border: 2px solid var(--pte-new-colors-contentTertiary);
|
|
33
|
+
border-radius: var(--pte-borders-radius-rectangle);
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
&:focus-visible {
|
|
39
|
-
outline: 1px solid var(--pte-new-colors-borderUltrastrong);
|
|
40
|
-
}
|
|
35
|
+
&:hover {
|
|
36
|
+
//background-color: ;
|
|
37
|
+
}
|
|
41
38
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
position: absolute;
|
|
48
|
-
background-color: transparent;
|
|
49
|
-
transition: var(--pte-animations-interaction);
|
|
50
|
-
transition-delay: 50ms;
|
|
51
|
-
}
|
|
39
|
+
&:focus-visible {
|
|
40
|
+
outline: 1px solid var(--pte-new-colors-borderUltrastrong);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
position: relative;
|
|
52
44
|
|
|
53
|
-
&[data-state="checked"], &[data-state="indeterminate"] {
|
|
54
45
|
&:after {
|
|
55
|
-
|
|
46
|
+
content: "";
|
|
47
|
+
width: 100%;
|
|
48
|
+
height: 100%;
|
|
49
|
+
position: absolute;
|
|
50
|
+
background-color: transparent;
|
|
51
|
+
transition: var(--pte-animations-interaction);
|
|
52
|
+
transition-delay: 50ms;
|
|
56
53
|
}
|
|
57
|
-
}
|
|
58
54
|
|
|
59
|
-
|
|
60
|
-
|
|
55
|
+
&[data-state="checked"], &[data-state="indeterminate"] {
|
|
56
|
+
&:after {
|
|
57
|
+
opacity: 0;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
&[data-disabled=true] {
|
|
62
|
+
border-color: var(--pte-new-colors-contentDisabled);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
& span {
|
|
66
|
+
transition: var(--pte-animations-interaction);
|
|
67
|
+
}
|
|
61
68
|
}
|
|
62
69
|
|
|
63
|
-
|
|
70
|
+
&.surface {
|
|
71
|
+
width: 100%;
|
|
72
|
+
padding: 6px 10px;
|
|
73
|
+
color: var(--pte-new-colors-contentSecondary);
|
|
74
|
+
display: flex;
|
|
75
|
+
align-items: center;
|
|
76
|
+
justify-content: space-between;
|
|
64
77
|
transition: var(--pte-animations-interaction);
|
|
78
|
+
|
|
79
|
+
&:focus-visible {
|
|
80
|
+
outline: 1px solid var(--pte-new-colors-borderUltrastrong);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
&[data-state="checked"], &[data-state="indeterminate"] {
|
|
84
|
+
background-color: var(--pte-new-colors-overlayMedium);
|
|
85
|
+
color: var(--pte-new-colors-contentPrimary);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
&[data-disabled=true] {
|
|
89
|
+
color: var(--pte-new-colors-contentDisabled);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
&:hover {
|
|
93
|
+
background-color: var(--pte-new-colors-overlayStrong);
|
|
94
|
+
}
|
|
65
95
|
}
|
|
66
96
|
}
|
|
67
97
|
|
|
@@ -76,3 +106,11 @@
|
|
|
76
106
|
fill: var(--pte-new-colors-contentDisabled);
|
|
77
107
|
}
|
|
78
108
|
}
|
|
109
|
+
|
|
110
|
+
.checkIcon {
|
|
111
|
+
color: var(--pte-new-colors-contentPrimary);
|
|
112
|
+
|
|
113
|
+
&[data-disabled=true] {
|
|
114
|
+
color: var(--pte-new-colors-contentDisabled);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -25,3 +25,19 @@ export const Default: Story = {
|
|
|
25
25
|
});
|
|
26
26
|
},
|
|
27
27
|
};
|
|
28
|
+
|
|
29
|
+
export const Surface: Story = {
|
|
30
|
+
args: {
|
|
31
|
+
children: 'ACH Bank Transfer',
|
|
32
|
+
kind: 'surface',
|
|
33
|
+
},
|
|
34
|
+
render: (args) => {
|
|
35
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
36
|
+
const [checked, setChecked] = useState(false);
|
|
37
|
+
return createElement(Checkbox, {
|
|
38
|
+
...args,
|
|
39
|
+
checked,
|
|
40
|
+
onChange: (e) => setChecked(!!e),
|
|
41
|
+
});
|
|
42
|
+
},
|
|
43
|
+
};
|
|
@@ -5,8 +5,11 @@ import clsx from 'clsx';
|
|
|
5
5
|
import styles from './Checkbox.module.scss';
|
|
6
6
|
import { pvar } from '../theme';
|
|
7
7
|
import { TextWhenString } from '../utility';
|
|
8
|
+
import { Check, Icon } from '../icon';
|
|
8
9
|
|
|
9
10
|
export type CheckboxProps = {
|
|
11
|
+
/** The visual style of the Checkbox. `default` is a standard checkbox with a label next to it, `surface` is a clickable card that displays a check when selected. */
|
|
12
|
+
kind?: 'default' | 'surface'
|
|
10
13
|
checked?: boolean;
|
|
11
14
|
onChange?: (checked: boolean | 'indeterminate') => void;
|
|
12
15
|
disabled?: boolean;
|
|
@@ -27,6 +30,7 @@ export type CheckboxProps = {
|
|
|
27
30
|
* @constructor
|
|
28
31
|
*/
|
|
29
32
|
export const Checkbox: FC<CheckboxProps> = ({
|
|
33
|
+
kind = 'default',
|
|
30
34
|
checked,
|
|
31
35
|
onChange,
|
|
32
36
|
disabled,
|
|
@@ -38,29 +42,46 @@ export const Checkbox: FC<CheckboxProps> = ({
|
|
|
38
42
|
return (
|
|
39
43
|
<label
|
|
40
44
|
htmlFor={inputID}
|
|
41
|
-
className={clsx(styles.container, disabled && styles.disabled, className)}
|
|
45
|
+
className={clsx(styles.container, disabled && styles.disabled, className, checked && styles.checked)}
|
|
42
46
|
{...props}
|
|
43
47
|
>
|
|
44
48
|
<RadixCheckbox.Root
|
|
45
49
|
id={inputID}
|
|
46
|
-
className={styles.root}
|
|
50
|
+
className={clsx(styles.root, styles[kind])}
|
|
47
51
|
checked={checked}
|
|
48
52
|
onCheckedChange={onChange}
|
|
49
53
|
data-disabled={disabled}
|
|
50
54
|
>
|
|
55
|
+
{kind === 'surface' && (
|
|
56
|
+
<TextWhenString kind="paragraphXSmall">
|
|
57
|
+
{children}
|
|
58
|
+
</TextWhenString>
|
|
59
|
+
)}
|
|
51
60
|
<RadixCheckbox.Indicator className={styles.indicator}>
|
|
52
|
-
|
|
53
|
-
<
|
|
54
|
-
|
|
61
|
+
{kind === 'default' && (
|
|
62
|
+
<svg width={14} height={14} viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
63
|
+
<path
|
|
64
|
+
className={styles.checkSvg}
|
|
65
|
+
data-disabled={disabled}
|
|
66
|
+
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"
|
|
67
|
+
/>
|
|
68
|
+
</svg>
|
|
69
|
+
)}
|
|
70
|
+
{kind === 'surface' && (
|
|
71
|
+
<Icon
|
|
72
|
+
icon={Check}
|
|
73
|
+
size={12.8}
|
|
55
74
|
data-disabled={disabled}
|
|
56
|
-
|
|
75
|
+
className={styles.checkIcon}
|
|
57
76
|
/>
|
|
58
|
-
|
|
77
|
+
)}
|
|
59
78
|
</RadixCheckbox.Indicator>
|
|
60
79
|
</RadixCheckbox.Root>
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
80
|
+
{kind === 'default' && (
|
|
81
|
+
<TextWhenString kind="paragraphXSmall">
|
|
82
|
+
{children}
|
|
83
|
+
</TextWhenString>
|
|
84
|
+
)}
|
|
64
85
|
</label>
|
|
65
86
|
);
|
|
66
87
|
};
|
|
@@ -68,9 +68,14 @@ export type ComboboxProps<T extends Record<string, any>> = {
|
|
|
68
68
|
*/
|
|
69
69
|
customValueString?: string;
|
|
70
70
|
/**
|
|
71
|
-
* The size of the options dropdown, in pixels.
|
|
71
|
+
* The size of the options dropdown, in pixels.
|
|
72
72
|
*/
|
|
73
73
|
maxHeight?: number;
|
|
74
|
+
/**
|
|
75
|
+
* Adds a bottom border to the dropdown options.
|
|
76
|
+
* @default false
|
|
77
|
+
*/
|
|
78
|
+
hasOptionBorder?: boolean;
|
|
74
79
|
/**
|
|
75
80
|
* Prop overrides for other rendered elements. Overrides for the input itself should be passed directly to the component.
|
|
76
81
|
*/
|
|
@@ -115,6 +120,7 @@ export function Combobox<T extends Record<string, any> = Record<string, any>>({
|
|
|
115
120
|
allowCustomValue,
|
|
116
121
|
customValueString = 'Create "%v"',
|
|
117
122
|
maxHeight = 320,
|
|
123
|
+
hasOptionBorder = false,
|
|
118
124
|
overrides,
|
|
119
125
|
}: ComboboxProps<T>) {
|
|
120
126
|
const inputID = useId();
|
|
@@ -262,6 +268,7 @@ export function Combobox<T extends Record<string, any> = Record<string, any>>({
|
|
|
262
268
|
className={clsx(
|
|
263
269
|
overrides?.option,
|
|
264
270
|
styles.option,
|
|
271
|
+
hasOptionBorder && styles.optionBorder,
|
|
265
272
|
)}
|
|
266
273
|
>
|
|
267
274
|
{typeof option.node === 'string' ? (
|
|
@@ -87,6 +87,13 @@
|
|
|
87
87
|
color: var(--pte-new-colors-contentDisabled);
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
|
+
|
|
91
|
+
&.optionBorder {
|
|
92
|
+
border-bottom: 0.5px solid var(--pte-new-colors-borderMedium);
|
|
93
|
+
}
|
|
94
|
+
&.optionBorder:last-child {
|
|
95
|
+
border-bottom: none;
|
|
96
|
+
}
|
|
90
97
|
}
|
|
91
98
|
|
|
92
99
|
.content {
|
|
@@ -155,3 +162,80 @@
|
|
|
155
162
|
border: 1.5px solid var(--pte-new-colors-contentTertiary);
|
|
156
163
|
transition: all var(--pte-animations-interaction);
|
|
157
164
|
}
|
|
165
|
+
|
|
166
|
+
.cardContainer {
|
|
167
|
+
display: flex;
|
|
168
|
+
flex-direction: column;
|
|
169
|
+
gap: 8px;
|
|
170
|
+
justify-content: flex-start;
|
|
171
|
+
align-items: flex-start;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.cardOption {
|
|
175
|
+
background-color: var(--pte-new-colors-surfacePrimary);
|
|
176
|
+
border-radius: 6px;
|
|
177
|
+
width: 100%;
|
|
178
|
+
|
|
179
|
+
&[data-headlessui-state~="active"] {
|
|
180
|
+
//.cardSurface {
|
|
181
|
+
// background-color: var(--pte-new-colors-overlayWhiteSubtle);
|
|
182
|
+
// border-color: var(--pte-new-colors-borderStrong);
|
|
183
|
+
//}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
&[data-headlessui-state~="checked"] {
|
|
187
|
+
.cardSurface {
|
|
188
|
+
background-color: var(--pte-new-colors-overlayMedium);
|
|
189
|
+
border-color: var(--pte-new-colors-borderUltrastrong);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
&[data-status="disabled"], &[data-headlessui-state~="disabled"] {
|
|
194
|
+
pointer-events: none;
|
|
195
|
+
cursor: default;
|
|
196
|
+
|
|
197
|
+
&, & * {
|
|
198
|
+
color: var(--pte-new-colors-contentDisabled);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
//.cardSurface {
|
|
202
|
+
// background-color: var(--pte-new-colors-overlayWhiteSubtle);
|
|
203
|
+
// border-color: var(--pte-new-colors-borderStrong);
|
|
204
|
+
//}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
&[data-status="error"] {
|
|
208
|
+
.cardSurface {
|
|
209
|
+
background-color: var(--pte-new-colors-backgroundNegative);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
&[data-status="success"] {
|
|
214
|
+
.cardSurface {
|
|
215
|
+
background-color: var(--pte-new-colors-backgroundPositive);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
&:hover {
|
|
220
|
+
.cardSurface {
|
|
221
|
+
background-color: var(--pte-new-colors-overlayStrong);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
.cardSurface {
|
|
227
|
+
width: 100%;
|
|
228
|
+
display: flex;
|
|
229
|
+
flex-direction: row;
|
|
230
|
+
justify-content: flex-start;
|
|
231
|
+
align-items: center;
|
|
232
|
+
transition: all var(--pte-animations-interaction);
|
|
233
|
+
|
|
234
|
+
border-radius: 6px;
|
|
235
|
+
background-color: var(--pte-new-colors-overlayWhiteSubtle);
|
|
236
|
+
border: 1px solid var(--pte-new-colors-borderStrong);
|
|
237
|
+
|
|
238
|
+
&.text {
|
|
239
|
+
padding: 4px 10px;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
@@ -48,6 +48,7 @@ export const Default: Story = {
|
|
|
48
48
|
|
|
49
49
|
export const WithCustomNodes: Story = {
|
|
50
50
|
args: {
|
|
51
|
+
hasOptionBorder: true,
|
|
51
52
|
options: [
|
|
52
53
|
{
|
|
53
54
|
id: '1',
|
|
@@ -95,3 +96,18 @@ export const Radio: Story = {
|
|
|
95
96
|
},
|
|
96
97
|
render,
|
|
97
98
|
};
|
|
99
|
+
|
|
100
|
+
export const Card: Story = {
|
|
101
|
+
args: {
|
|
102
|
+
label: 'Release type',
|
|
103
|
+
description: 'Select the type of release you want to create.',
|
|
104
|
+
kind: 'card',
|
|
105
|
+
options: [
|
|
106
|
+
{ id: '1', node: 'Single' },
|
|
107
|
+
{ id: '2', node: 'EP' },
|
|
108
|
+
{ id: '3', node: 'Album (LP)' },
|
|
109
|
+
{ id: '4', node: 'Compilation' },
|
|
110
|
+
],
|
|
111
|
+
},
|
|
112
|
+
render,
|
|
113
|
+
};
|
|
@@ -48,15 +48,19 @@ export type SelectProps<T = Record<string, any>> = {
|
|
|
48
48
|
*/
|
|
49
49
|
onChange?: (value: Option<T>['id'] | null) => void | Promise<void>;
|
|
50
50
|
/**
|
|
51
|
-
* The visual variant of the Select.
|
|
51
|
+
* The visual variant of the Select. `listbox` will render as a dropdown menu, `radio` will render as a radio group, and `card` will render as selectable cards.
|
|
52
52
|
* @default listbox
|
|
53
53
|
*/
|
|
54
|
-
kind?: 'listbox' | 'radio';
|
|
55
|
-
|
|
54
|
+
kind?: 'listbox' | 'radio' | 'card';
|
|
56
55
|
/**
|
|
57
56
|
* The size of the options dropdown, in pixels. Only applicable to kind="listbox".
|
|
58
57
|
*/
|
|
59
58
|
maxHeight?: number;
|
|
59
|
+
/**
|
|
60
|
+
* Adds a bottom border to the dropdown options. Only applicable to kind="listbox".
|
|
61
|
+
* @default false
|
|
62
|
+
*/
|
|
63
|
+
hasOptionBorder?: boolean;
|
|
60
64
|
|
|
61
65
|
/**
|
|
62
66
|
* Prop overrides for other rendered elements. Overrides for the input itself should be passed directly to the component.
|
|
@@ -100,6 +104,7 @@ export const Select = forwardRef(function <T = Record<string, any>>({
|
|
|
100
104
|
disabled,
|
|
101
105
|
kind = 'listbox',
|
|
102
106
|
maxHeight = 320,
|
|
107
|
+
hasOptionBorder = false,
|
|
103
108
|
overrides,
|
|
104
109
|
}: SelectProps<T>, ref: ForwardedRef<any>) {
|
|
105
110
|
const inputID = useId();
|
|
@@ -195,6 +200,7 @@ export const Select = forwardRef(function <T = Record<string, any>>({
|
|
|
195
200
|
className={clsx(
|
|
196
201
|
overrides?.option,
|
|
197
202
|
styles.option,
|
|
203
|
+
hasOptionBorder && styles.optionBorder,
|
|
198
204
|
)}
|
|
199
205
|
disabled={option.disabled || false}
|
|
200
206
|
>
|
|
@@ -233,6 +239,28 @@ export const Select = forwardRef(function <T = Record<string, any>>({
|
|
|
233
239
|
))}
|
|
234
240
|
</RadioGroup>
|
|
235
241
|
)}
|
|
242
|
+
{kind === 'card' && (
|
|
243
|
+
<RadioGroup ref={ref} as="div" className={styles.cardContainer} value={value} onChange={onChange}>
|
|
244
|
+
{options.map((option) => (
|
|
245
|
+
<RadioGroup.Option
|
|
246
|
+
as="div"
|
|
247
|
+
className={clsx(
|
|
248
|
+
styles.cardOption,
|
|
249
|
+
)}
|
|
250
|
+
key={option.id}
|
|
251
|
+
value={option.id}
|
|
252
|
+
disabled={option.disabled || false}
|
|
253
|
+
data-status={disabled ? 'disabled' : (status || 'default')}
|
|
254
|
+
>
|
|
255
|
+
<div className={clsx(styles.cardSurface, typeof option.node === 'string' && styles.text)}>
|
|
256
|
+
<TextWhenString kind="paragraphSmall">
|
|
257
|
+
{option.node}
|
|
258
|
+
</TextWhenString>
|
|
259
|
+
</div>
|
|
260
|
+
</RadioGroup.Option>
|
|
261
|
+
))}
|
|
262
|
+
</RadioGroup>
|
|
263
|
+
)}
|
|
236
264
|
</Field>
|
|
237
265
|
);
|
|
238
266
|
});
|
|
@@ -378,6 +378,7 @@ export type Theme = {
|
|
|
378
378
|
rectangle: CSSLength,
|
|
379
379
|
rounded: CSSLength,
|
|
380
380
|
roundedSmall: CSSLength,
|
|
381
|
+
roundedMedium: CSSLength,
|
|
381
382
|
roundedLarge: CSSLength,
|
|
382
383
|
roundedXL: CSSLength,
|
|
383
384
|
},
|
|
@@ -1005,6 +1006,7 @@ export const LightTheme: Theme = {
|
|
|
1005
1006
|
rectangle: '0px',
|
|
1006
1007
|
rounded: '8px',
|
|
1007
1008
|
roundedSmall: '4px',
|
|
1009
|
+
roundedMedium: '6px',
|
|
1008
1010
|
roundedLarge: '12px',
|
|
1009
1011
|
roundedXL: '16px',
|
|
1010
1012
|
},
|
|
@@ -1376,9 +1378,9 @@ export const DarkTheme: Theme = merge(LightTheme, {
|
|
|
1376
1378
|
overlayInverseSubtle: 'rgba(0, 0, 0, 0.02)',
|
|
1377
1379
|
overlayInverseMedium: 'rgba(0, 0, 0, 0.05)',
|
|
1378
1380
|
overlayWhiteUltrastrong: 'rgba(0, 0, 0, 0.18)',
|
|
1379
|
-
overlayBlackSubtle: 'rgba(
|
|
1380
|
-
overlayBlackMedium: 'rgba(
|
|
1381
|
-
overlayBlackStrong: 'rgba(
|
|
1381
|
+
overlayBlackSubtle: 'rgba(0, 0, 0, 0.2)',
|
|
1382
|
+
overlayBlackMedium: 'rgba(0, 0, 0, 0.3)',
|
|
1383
|
+
overlayBlackStrong: 'rgba(0, 0, 0, 0.4)',
|
|
1382
1384
|
overlayPageBackground: 'rgba(18, 18, 18, 0.75)',
|
|
1383
1385
|
},
|
|
1384
1386
|
lighting: {
|
|
@@ -1418,8 +1420,8 @@ export const DarkTheme: Theme = merge(LightTheme, {
|
|
|
1418
1420
|
},
|
|
1419
1421
|
borders: {
|
|
1420
1422
|
dropdown: {
|
|
1421
|
-
shadow:
|
|
1422
|
-
color: '
|
|
1423
|
+
shadow: ShadowsDark.deepBelow,
|
|
1424
|
+
color: 'transparent',
|
|
1423
1425
|
border: 'none',
|
|
1424
1426
|
},
|
|
1425
1427
|
},
|