paris 0.2.2 → 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 +37 -0
- package/README.md +61 -5
- package/package.json +27 -15
- package/src/helpers/renderEnhancer.tsx +21 -0
- package/src/pages/_app.tsx +1 -1
- package/src/pages/index.tsx +1 -1
- package/src/stories/Pagination.mdx +73 -0
- package/src/stories/Tokens.mdx +0 -8
- package/src/stories/button/Button.module.scss +23 -7
- package/src/stories/button/Button.stories.ts +17 -0
- package/src/stories/button/Button.tsx +80 -20
- 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/dropdown/Dropdown.module.scss +23 -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 +135 -0
- package/src/stories/input/Input.stories.ts +89 -0
- package/src/stories/input/Input.tsx +137 -0
- package/src/stories/input/index.ts +1 -0
- package/src/stories/pagination/index.ts +1 -0
- package/src/stories/pagination/usePagination.ts +106 -0
- package/src/stories/select/Select.module.scss +74 -0
- package/src/stories/select/Select.stories.ts +73 -0
- package/src/stories/select/Select.tsx +176 -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 +126 -7
- package/src/{styles → stories/theme}/tw-preflight.css +3 -1
- package/src/stories/theme/util.scss +8 -0
- 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/src/types/Enhancer.ts +3 -0
- package/src/styles/util.scss +0 -4
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import type { ReactNode, ComponentPropsWithoutRef } from 'react';
|
|
4
|
+
import { Listbox, Transition } from '@headlessui/react';
|
|
5
|
+
import clsx from 'clsx';
|
|
6
|
+
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
7
|
+
import { faChevronDown } from '@fortawesome/free-solid-svg-icons';
|
|
8
|
+
import { useId } from 'react';
|
|
9
|
+
import inputStyles from '../input/Input.module.scss';
|
|
10
|
+
import dropdownStyles from '../dropdown/Dropdown.module.scss';
|
|
11
|
+
import styles from './Select.module.scss';
|
|
12
|
+
import type { TextProps } from '../text';
|
|
13
|
+
import { Text } from '../text';
|
|
14
|
+
import type { InputProps } from '../input';
|
|
15
|
+
import { MemoizedEnhancer } from '../../helpers/renderEnhancer';
|
|
16
|
+
import { pget, theme } from '../theme';
|
|
17
|
+
import { Field } from '../field';
|
|
18
|
+
|
|
19
|
+
export type Option<T = Record<string, any>> = {
|
|
20
|
+
id: string,
|
|
21
|
+
node: ReactNode,
|
|
22
|
+
metadata?: T,
|
|
23
|
+
};
|
|
24
|
+
export type SelectProps<T = Record<string, any>> = {
|
|
25
|
+
/**
|
|
26
|
+
* The {@link Option}s to render in the select box.
|
|
27
|
+
*
|
|
28
|
+
* Each option should have an id (`string`) and node ({@link ReactNode}) property at minimum. You can also pass in any other metadata through the `metadata` attribute.
|
|
29
|
+
*
|
|
30
|
+
* For type safety, you can pass in a type parameter to `SelectProps` component. This will be used as the type for the `metadata` property of each option.
|
|
31
|
+
*/
|
|
32
|
+
options: Option<T>[];
|
|
33
|
+
/**
|
|
34
|
+
* The option ID to render as selected in the select box.
|
|
35
|
+
*
|
|
36
|
+
* This should exactly match one of the option IDs passed in the `options` prop. If `null`, no option will be selected.
|
|
37
|
+
*/
|
|
38
|
+
value?: string | null;
|
|
39
|
+
/**
|
|
40
|
+
* The interaction handler for the Select.
|
|
41
|
+
*/
|
|
42
|
+
onChange?: (value: string | null) => void | Promise<void>;
|
|
43
|
+
/**
|
|
44
|
+
* Prop overrides for other rendered elements. Overrides for the input itself should be passed directly to the component.
|
|
45
|
+
*/
|
|
46
|
+
overrides?: {
|
|
47
|
+
container?: ComponentPropsWithoutRef<'div'>;
|
|
48
|
+
selectInput?: ComponentPropsWithoutRef<'button'>;
|
|
49
|
+
optionsContainer?: ComponentPropsWithoutRef<'div'>;
|
|
50
|
+
option?: ComponentPropsWithoutRef<'div'>;
|
|
51
|
+
label?: TextProps<'label'>;
|
|
52
|
+
description?: TextProps<'p'>;
|
|
53
|
+
startEnhancerContainer?: ComponentPropsWithoutRef<'div'>;
|
|
54
|
+
endEnhancerContainer?: ComponentPropsWithoutRef<'div'>;
|
|
55
|
+
}
|
|
56
|
+
} & Omit<InputProps, 'type' | 'overrides'>;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* A Select component is used to render a `select` box.
|
|
60
|
+
*
|
|
61
|
+
* <hr />
|
|
62
|
+
*
|
|
63
|
+
* To use this component, import it as follows:
|
|
64
|
+
*
|
|
65
|
+
* ```js
|
|
66
|
+
* import { Select } from 'paris/select';
|
|
67
|
+
* ```
|
|
68
|
+
* @constructor
|
|
69
|
+
*/
|
|
70
|
+
export function Select<T = Record<string, any>>({
|
|
71
|
+
options,
|
|
72
|
+
value,
|
|
73
|
+
onChange,
|
|
74
|
+
label,
|
|
75
|
+
status,
|
|
76
|
+
hideLabel,
|
|
77
|
+
description,
|
|
78
|
+
hideDescription,
|
|
79
|
+
placeholder,
|
|
80
|
+
startEnhancer,
|
|
81
|
+
endEnhancer,
|
|
82
|
+
disabled,
|
|
83
|
+
overrides,
|
|
84
|
+
}: SelectProps<T>) {
|
|
85
|
+
const inputID = useId();
|
|
86
|
+
return (
|
|
87
|
+
<Field
|
|
88
|
+
htmlFor={inputID}
|
|
89
|
+
label={label}
|
|
90
|
+
hideLabel={hideLabel}
|
|
91
|
+
description={description}
|
|
92
|
+
hideDescription={hideDescription}
|
|
93
|
+
disabled={disabled}
|
|
94
|
+
overrides={{
|
|
95
|
+
container: overrides?.container,
|
|
96
|
+
label: overrides?.label,
|
|
97
|
+
description: overrides?.description,
|
|
98
|
+
}}
|
|
99
|
+
>
|
|
100
|
+
<Listbox
|
|
101
|
+
as="div"
|
|
102
|
+
value={value}
|
|
103
|
+
onChange={onChange}
|
|
104
|
+
>
|
|
105
|
+
<Listbox.Button
|
|
106
|
+
id={inputID}
|
|
107
|
+
{...overrides?.selectInput}
|
|
108
|
+
aria-disabled={disabled}
|
|
109
|
+
data-status={disabled ? 'disabled' : (status || 'default')}
|
|
110
|
+
className={clsx(
|
|
111
|
+
overrides?.selectInput?.className,
|
|
112
|
+
inputStyles.inputContainer,
|
|
113
|
+
styles.field,
|
|
114
|
+
)}
|
|
115
|
+
>
|
|
116
|
+
{!!startEnhancer && (
|
|
117
|
+
<div {...overrides?.startEnhancerContainer} className={clsx(inputStyles.enhancer, overrides?.startEnhancerContainer?.className)}>
|
|
118
|
+
{!!startEnhancer && (
|
|
119
|
+
<MemoizedEnhancer
|
|
120
|
+
enhancer={startEnhancer}
|
|
121
|
+
size={parseInt(pget('typography.styles.paragraphSmall.fontSize') || theme.typography.styles.paragraphSmall.fontSize, 10)}
|
|
122
|
+
/>
|
|
123
|
+
)}
|
|
124
|
+
</div>
|
|
125
|
+
)}
|
|
126
|
+
{options?.find((o) => o.id === value)?.node || placeholder || 'Select an option'}
|
|
127
|
+
{endEnhancer ? (
|
|
128
|
+
<div {...overrides?.endEnhancerContainer} className={clsx(inputStyles.enhancer, overrides?.endEnhancerContainer?.className)}>
|
|
129
|
+
{!!endEnhancer && (
|
|
130
|
+
<MemoizedEnhancer
|
|
131
|
+
enhancer={endEnhancer}
|
|
132
|
+
size={parseInt(pget('typography.styles.paragraphSmall.fontSize') || theme.typography.styles.paragraphSmall.fontSize, 10)}
|
|
133
|
+
/>
|
|
134
|
+
)}
|
|
135
|
+
</div>
|
|
136
|
+
) : (
|
|
137
|
+
<FontAwesomeIcon className={inputStyles.enhancer} width="10px" icon={faChevronDown} />
|
|
138
|
+
)}
|
|
139
|
+
</Listbox.Button>
|
|
140
|
+
<Transition
|
|
141
|
+
enter={dropdownStyles.transition}
|
|
142
|
+
enterFrom={dropdownStyles.enterFrom}
|
|
143
|
+
enterTo={dropdownStyles.enterTo}
|
|
144
|
+
leave={dropdownStyles.transition}
|
|
145
|
+
leaveFrom={dropdownStyles.leaveFrom}
|
|
146
|
+
leaveTo={dropdownStyles.leaveTo}
|
|
147
|
+
>
|
|
148
|
+
<Listbox.Options
|
|
149
|
+
className={clsx(
|
|
150
|
+
overrides?.optionsContainer,
|
|
151
|
+
styles.options,
|
|
152
|
+
)}
|
|
153
|
+
>
|
|
154
|
+
{(options || []).map((option) => (
|
|
155
|
+
<Listbox.Option
|
|
156
|
+
key={option.id}
|
|
157
|
+
value={option.id}
|
|
158
|
+
data-selected={option.id === value}
|
|
159
|
+
className={clsx(
|
|
160
|
+
overrides?.option,
|
|
161
|
+
styles.option,
|
|
162
|
+
)}
|
|
163
|
+
>
|
|
164
|
+
{typeof option.node === 'string' ? (
|
|
165
|
+
<Text as="span" kind="paragraphSmall">
|
|
166
|
+
{option.node}
|
|
167
|
+
</Text>
|
|
168
|
+
) : option.node}
|
|
169
|
+
</Listbox.Option>
|
|
170
|
+
))}
|
|
171
|
+
</Listbox.Options>
|
|
172
|
+
</Transition>
|
|
173
|
+
</Listbox>
|
|
174
|
+
</Field>
|
|
175
|
+
);
|
|
176
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Select';
|
|
@@ -1,40 +1,62 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ComponentProps, FC, ReactNode } from 'react';
|
|
2
2
|
import { createElement } from 'react';
|
|
3
|
+
import clsx from 'clsx';
|
|
4
|
+
import styles from './Text.module.scss';
|
|
3
5
|
import typography from './Typography.module.css';
|
|
4
6
|
import type { LightTheme } from '../theme';
|
|
5
7
|
|
|
6
|
-
export type
|
|
8
|
+
export type TextElement = 'p' | 'span' | 'div' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'label' | 'legend' | 'caption' | 'small';
|
|
9
|
+
export type TextProps<T extends TextElement = 'span'> = {
|
|
7
10
|
/**
|
|
8
11
|
* The font class to use.
|
|
9
12
|
* @default paragraphMedium
|
|
10
13
|
*/
|
|
11
|
-
kind
|
|
14
|
+
kind?: keyof typeof LightTheme.typography.styles;
|
|
12
15
|
/**
|
|
13
16
|
* The HTML text tag to use.
|
|
14
17
|
* @default span
|
|
15
18
|
*/
|
|
16
|
-
as?:
|
|
19
|
+
as?: T;
|
|
17
20
|
/** The contents of the Text element. */
|
|
18
21
|
children: ReactNode;
|
|
19
|
-
}
|
|
22
|
+
} & ComponentProps<T>;
|
|
20
23
|
|
|
21
24
|
/**
|
|
22
25
|
* A `Text` component is used to render text with one of our theme formats.
|
|
26
|
+
*
|
|
27
|
+
* <hr />
|
|
28
|
+
*
|
|
29
|
+
* To use the `Text` component, import it as follows:
|
|
30
|
+
*
|
|
31
|
+
* ```tsx
|
|
32
|
+
* import { Text } from 'paris/text';
|
|
33
|
+
*
|
|
34
|
+
* export const ExampleHeading: FC = () => (
|
|
35
|
+
* <Text as="h1" format="headingLarge">Hello World!</Text>
|
|
36
|
+
* );
|
|
37
|
+
* ```
|
|
38
|
+
*
|
|
23
39
|
* @example ```tsx
|
|
24
40
|
* <Text as="h1" format="headingLarge">Hello World!</Text>
|
|
25
41
|
* ```
|
|
26
42
|
* @constructor
|
|
27
43
|
*/
|
|
28
|
-
export
|
|
44
|
+
export function Text<T extends TextElement>({
|
|
29
45
|
kind,
|
|
30
46
|
as,
|
|
31
47
|
children,
|
|
32
48
|
...props
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
49
|
+
}: TextProps<T>): JSX.Element {
|
|
50
|
+
return createElement(
|
|
51
|
+
as || 'span',
|
|
52
|
+
{
|
|
53
|
+
...props,
|
|
54
|
+
className: clsx(
|
|
55
|
+
styles.text,
|
|
56
|
+
typography[kind || 'paragraphMedium'],
|
|
57
|
+
props?.className,
|
|
58
|
+
),
|
|
59
|
+
},
|
|
60
|
+
children,
|
|
61
|
+
);
|
|
62
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { TextArea } from './TextArea';
|
|
3
|
+
|
|
4
|
+
const meta: Meta<typeof TextArea> = {
|
|
5
|
+
title: 'Inputs/TextArea',
|
|
6
|
+
component: TextArea,
|
|
7
|
+
tags: ['autodocs'],
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export default meta;
|
|
11
|
+
type Story = StoryObj<typeof TextArea>;
|
|
12
|
+
|
|
13
|
+
export const Default: Story = {
|
|
14
|
+
args: {
|
|
15
|
+
placeholder: 'Billie Eilish',
|
|
16
|
+
label: 'Name',
|
|
17
|
+
description: 'Type your full name here.',
|
|
18
|
+
},
|
|
19
|
+
};
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import type { ComponentPropsWithoutRef, FC } from 'react';
|
|
2
|
+
import { useId } from 'react';
|
|
3
|
+
import clsx from 'clsx';
|
|
4
|
+
import type { InputProps } from '../input';
|
|
5
|
+
import styles from '../input/Input.module.scss';
|
|
6
|
+
import { Text } from '../text';
|
|
7
|
+
import { MemoizedEnhancer } from '../../helpers/renderEnhancer';
|
|
8
|
+
import { pget, theme } from '../theme';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* A `textarea` input field.
|
|
12
|
+
*
|
|
13
|
+
* <hr />
|
|
14
|
+
*
|
|
15
|
+
* To use this component in your app, import it as follows:
|
|
16
|
+
*
|
|
17
|
+
* ```js
|
|
18
|
+
* import { TextArea } from 'paris/textarea';
|
|
19
|
+
* ```
|
|
20
|
+
* @constructor
|
|
21
|
+
*/
|
|
22
|
+
export const TextArea: FC<InputProps & ComponentPropsWithoutRef<'textarea'>> = ({ status, disabled, ...props }) => {
|
|
23
|
+
const inputID = useId();
|
|
24
|
+
return (
|
|
25
|
+
// Disable a11y rules because the container doesn't need to be focusable for screen readers; the input itself should receive focus instead.
|
|
26
|
+
// The container is only made clickable for usability purposes.
|
|
27
|
+
// eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions
|
|
28
|
+
<div
|
|
29
|
+
{...props.overrides?.container}
|
|
30
|
+
className={clsx(
|
|
31
|
+
props.overrides?.container?.className,
|
|
32
|
+
styles.container,
|
|
33
|
+
)}
|
|
34
|
+
onClick={(e) => {
|
|
35
|
+
if (disabled) e.preventDefault();
|
|
36
|
+
if (typeof window !== 'undefined') {
|
|
37
|
+
const input = document.getElementById(inputID);
|
|
38
|
+
if (input && !disabled) {
|
|
39
|
+
input.focus();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}}
|
|
43
|
+
>
|
|
44
|
+
<Text
|
|
45
|
+
{...props.overrides?.label}
|
|
46
|
+
as="label"
|
|
47
|
+
kind="paragraphSmall"
|
|
48
|
+
htmlFor={inputID}
|
|
49
|
+
className={clsx(
|
|
50
|
+
styles.label,
|
|
51
|
+
{ [styles.hidden]: props.hideLabel },
|
|
52
|
+
)}
|
|
53
|
+
>
|
|
54
|
+
{props.label}
|
|
55
|
+
</Text>
|
|
56
|
+
<div
|
|
57
|
+
className={styles.inputContainer}
|
|
58
|
+
data-status={status}
|
|
59
|
+
data-disabled={disabled}
|
|
60
|
+
>
|
|
61
|
+
{!!props.startEnhancer && (
|
|
62
|
+
<div {...props.overrides?.startEnhancerContainer} className={clsx(styles.enhancer, props.overrides?.startEnhancerContainer?.className)}>
|
|
63
|
+
{!!props.startEnhancer && (
|
|
64
|
+
<MemoizedEnhancer
|
|
65
|
+
enhancer={props.startEnhancer}
|
|
66
|
+
size={parseInt(pget('typography.styles.paragraphSmall.fontSize') || theme.typography.styles.paragraphSmall.fontSize, 10)}
|
|
67
|
+
/>
|
|
68
|
+
)}
|
|
69
|
+
</div>
|
|
70
|
+
)}
|
|
71
|
+
<textarea
|
|
72
|
+
{...props}
|
|
73
|
+
id={inputID}
|
|
74
|
+
aria-label={props.label}
|
|
75
|
+
aria-describedby={`${inputID}-description`}
|
|
76
|
+
aria-disabled={disabled}
|
|
77
|
+
readOnly={disabled}
|
|
78
|
+
className={clsx(
|
|
79
|
+
props.className,
|
|
80
|
+
styles.input,
|
|
81
|
+
)}
|
|
82
|
+
/>
|
|
83
|
+
{!!props.endEnhancer && (
|
|
84
|
+
<div {...props.overrides?.endEnhancerContainer} className={clsx(styles.enhancer, props.overrides?.endEnhancerContainer?.className)}>
|
|
85
|
+
{!!props.endEnhancer && (
|
|
86
|
+
<MemoizedEnhancer
|
|
87
|
+
enhancer={props.endEnhancer}
|
|
88
|
+
size={parseInt(pget('typography.styles.paragraphSmall.fontSize') || theme.typography.styles.paragraphSmall.fontSize, 10)}
|
|
89
|
+
/>
|
|
90
|
+
)}
|
|
91
|
+
</div>
|
|
92
|
+
)}
|
|
93
|
+
</div>
|
|
94
|
+
<Text
|
|
95
|
+
id={`${inputID}-description`}
|
|
96
|
+
{...props.overrides?.description}
|
|
97
|
+
as="p"
|
|
98
|
+
kind="paragraphXSmall"
|
|
99
|
+
className={clsx(
|
|
100
|
+
styles.description,
|
|
101
|
+
{ [styles.hidden]: !props.description || props.hideDescription },
|
|
102
|
+
props.overrides?.description?.className,
|
|
103
|
+
)}
|
|
104
|
+
>
|
|
105
|
+
{props.description}
|
|
106
|
+
</Text>
|
|
107
|
+
</div>
|
|
108
|
+
);
|
|
109
|
+
// return (
|
|
110
|
+
// <div
|
|
111
|
+
// className={clsx(
|
|
112
|
+
// styles.inputContainer,
|
|
113
|
+
// )}
|
|
114
|
+
// >
|
|
115
|
+
// <textarea
|
|
116
|
+
// {...props}
|
|
117
|
+
// />
|
|
118
|
+
// </div>
|
|
119
|
+
// );
|
|
120
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './TextArea';
|
|
@@ -2,6 +2,7 @@ import { createTheme } from 'pte';
|
|
|
2
2
|
import type { CSSColor, CSSLength } from '@ssh/csstypes';
|
|
3
3
|
import type { Property } from 'csstype';
|
|
4
4
|
import type { PartialDeep } from 'type-fest';
|
|
5
|
+
import merge from 'ts-deepmerge';
|
|
5
6
|
import { Tokens as T } from './tokens';
|
|
6
7
|
import type { TokensT } from './tokens';
|
|
7
8
|
|
|
@@ -16,8 +17,36 @@ export type FontDefinition = {
|
|
|
16
17
|
|
|
17
18
|
export type FontClassDefinition = Omit<FontDefinition, 'fontSize' | 'lineHeight'>;
|
|
18
19
|
|
|
20
|
+
export type ShadowDefinition = `${CSSLength} ${CSSLength} ${CSSLength} ${CSSColor}` | 'none';
|
|
21
|
+
|
|
22
|
+
const Shadows = {
|
|
23
|
+
shallowBelow: '0px 4px 20px rgba(0, 0, 0, 0.2)',
|
|
24
|
+
deepBelow: '0px 8px 20px rgba(0, 0, 0, 0.2)',
|
|
25
|
+
shallowAbove: '0px -4px 20px rgba(0, 0, 0, 0.2)',
|
|
26
|
+
deepAbove: '0px -8px 20px rgba(0, 0, 0, 0.2)',
|
|
27
|
+
shallowPopup: '0px 0px 30px rgba(0, 0, 0, 0.2)',
|
|
28
|
+
deepPopup: '0px 0px 40px rgba(0, 0, 0, 0.2)',
|
|
29
|
+
subtlePopup: '0px 0px 10px rgba(0, 0, 0, 0.1)',
|
|
30
|
+
shallowLeft: '-20px 0px 40px rgba(0, 0, 0, 0.1)',
|
|
31
|
+
shallowRight: '20px 0px 40px rgba(0, 0, 0, 0.1)',
|
|
32
|
+
} as const;
|
|
33
|
+
|
|
34
|
+
export type TimingFunction = `cubic-bezier(${number}, ${number}, ${number}, ${number})` | 'ease' | 'ease-in' | 'ease-out' | 'ease-in-out' | 'linear';
|
|
35
|
+
export type Duration = `${number}ms` | `${number}s`;
|
|
36
|
+
|
|
37
|
+
const TimingFunctions: Omit<Theme['animations']['timing'], 'default'> = {
|
|
38
|
+
easeInOut: 'cubic-bezier(0.42, 0.0, 0.58, 1.0)',
|
|
39
|
+
easeOut: 'cubic-bezier(0.0, 0.0, 0.58, 1.0)',
|
|
40
|
+
easeIn: 'cubic-bezier(0.42, 0.0, 1.0, 1.0)',
|
|
41
|
+
easeOutQuad: 'cubic-bezier(0.5, 1, 0.89, 1)',
|
|
42
|
+
easeInQuad: 'cubic-bezier(0.11, 0, 0.5, 0)',
|
|
43
|
+
};
|
|
44
|
+
|
|
19
45
|
export type Theme = {
|
|
20
46
|
tokens: TokensT,
|
|
47
|
+
utils: {
|
|
48
|
+
defaultUserSelect: Property.UserSelect,
|
|
49
|
+
}
|
|
21
50
|
colors: {
|
|
22
51
|
// Primary
|
|
23
52
|
|
|
@@ -71,6 +100,7 @@ export type Theme = {
|
|
|
71
100
|
backgroundOverlayLight: CSSColor,
|
|
72
101
|
backgroundOverlayXLight: CSSColor,
|
|
73
102
|
backgroundOverlayGrey: CSSColor,
|
|
103
|
+
backgroundOverlayDark: CSSColor,
|
|
74
104
|
backgroundOverlayTeal: CSSColor,
|
|
75
105
|
|
|
76
106
|
// Border
|
|
@@ -91,6 +121,7 @@ export type Theme = {
|
|
|
91
121
|
fontFamily: string,
|
|
92
122
|
boldFontWeight: number,
|
|
93
123
|
italicLetterSpacing: CSSLength,
|
|
124
|
+
verticalMetricsAdjust: CSSLength;
|
|
94
125
|
|
|
95
126
|
styles: {
|
|
96
127
|
// Display
|
|
@@ -124,6 +155,17 @@ export type Theme = {
|
|
|
124
155
|
paragraphXXSmall: FontDefinition,
|
|
125
156
|
}
|
|
126
157
|
},
|
|
158
|
+
lighting: {
|
|
159
|
+
shallowBelow: ShadowDefinition,
|
|
160
|
+
deepBelow: ShadowDefinition,
|
|
161
|
+
shallowAbove: ShadowDefinition,
|
|
162
|
+
deepAbove: ShadowDefinition,
|
|
163
|
+
shallowPopup: ShadowDefinition,
|
|
164
|
+
deepPopup: ShadowDefinition,
|
|
165
|
+
subtlePopup: ShadowDefinition,
|
|
166
|
+
shallowLeft: ShadowDefinition,
|
|
167
|
+
shallowRight: ShadowDefinition,
|
|
168
|
+
},
|
|
127
169
|
borders: {
|
|
128
170
|
// Border Radius
|
|
129
171
|
radius: {
|
|
@@ -133,10 +175,42 @@ export type Theme = {
|
|
|
133
175
|
rounded: CSSLength,
|
|
134
176
|
roundedSmall: CSSLength,
|
|
135
177
|
roundedLarge: CSSLength,
|
|
178
|
+
roundedXL: CSSLength,
|
|
179
|
+
},
|
|
180
|
+
|
|
181
|
+
// Dropdowns (Select, Menu, Popovers, etc.)
|
|
182
|
+
|
|
183
|
+
dropdown: {
|
|
184
|
+
color: CSSColor,
|
|
185
|
+
shadow: ShadowDefinition,
|
|
136
186
|
},
|
|
137
187
|
},
|
|
188
|
+
surfaces: {
|
|
189
|
+
dialog: {
|
|
190
|
+
border: `${number}px ${string} ${CSSColor}`,
|
|
191
|
+
outline: `${number}px ${string} ${CSSColor}`,
|
|
192
|
+
background: CSSColor,
|
|
193
|
+
backdropFilter: string,
|
|
194
|
+
},
|
|
195
|
+
}
|
|
138
196
|
animations: {
|
|
139
197
|
interaction: string,
|
|
198
|
+
timing: {
|
|
199
|
+
easeInOut: TimingFunction,
|
|
200
|
+
easeOut: TimingFunction,
|
|
201
|
+
easeIn: TimingFunction,
|
|
202
|
+
easeOutQuad: TimingFunction,
|
|
203
|
+
easeInQuad: TimingFunction,
|
|
204
|
+
default: TimingFunction,
|
|
205
|
+
},
|
|
206
|
+
duration: {
|
|
207
|
+
rapid: Duration,
|
|
208
|
+
fast: Duration,
|
|
209
|
+
normal: Duration,
|
|
210
|
+
relaxed: Duration,
|
|
211
|
+
slow: Duration,
|
|
212
|
+
gradual: Duration,
|
|
213
|
+
},
|
|
140
214
|
}
|
|
141
215
|
};
|
|
142
216
|
|
|
@@ -172,6 +246,9 @@ export const ParagraphFontClass: FontClassDefinition = {
|
|
|
172
246
|
|
|
173
247
|
export const LightTheme: Theme = {
|
|
174
248
|
tokens: T,
|
|
249
|
+
utils: {
|
|
250
|
+
defaultUserSelect: 'none',
|
|
251
|
+
},
|
|
175
252
|
colors: {
|
|
176
253
|
// Primary
|
|
177
254
|
|
|
@@ -225,6 +302,7 @@ export const LightTheme: Theme = {
|
|
|
225
302
|
backgroundOverlayLight: 'rgba(255, 255, 255, 0.07)',
|
|
226
303
|
backgroundOverlayXLight: 'rgba(255, 255, 255, 0.1)',
|
|
227
304
|
backgroundOverlayGrey: 'rgba(175, 175, 175, 0.8)',
|
|
305
|
+
backgroundOverlayDark: 'rgba(0, 0, 0, 0.1)',
|
|
228
306
|
backgroundOverlayTeal: 'rgba(29, 238, 205, 0.1)',
|
|
229
307
|
|
|
230
308
|
// Border
|
|
@@ -245,6 +323,7 @@ export const LightTheme: Theme = {
|
|
|
245
323
|
fontFamily: '"Graphik Web", -apple-system, BlinkMacSystemFont, Helvetica, Arial, sans-serif',
|
|
246
324
|
boldFontWeight: 500,
|
|
247
325
|
italicLetterSpacing: '-0.01em',
|
|
326
|
+
verticalMetricsAdjust: '1px',
|
|
248
327
|
|
|
249
328
|
styles: {
|
|
250
329
|
// Display
|
|
@@ -350,6 +429,9 @@ export const LightTheme: Theme = {
|
|
|
350
429
|
},
|
|
351
430
|
},
|
|
352
431
|
},
|
|
432
|
+
lighting: {
|
|
433
|
+
...Shadows,
|
|
434
|
+
},
|
|
353
435
|
borders: {
|
|
354
436
|
radius: {
|
|
355
437
|
pill: '1000px',
|
|
@@ -358,18 +440,41 @@ export const LightTheme: Theme = {
|
|
|
358
440
|
rounded: '8px',
|
|
359
441
|
roundedSmall: '4px',
|
|
360
442
|
roundedLarge: '12px',
|
|
443
|
+
roundedXL: '16px',
|
|
444
|
+
},
|
|
445
|
+
|
|
446
|
+
dropdown: {
|
|
447
|
+
shadow: Shadows.deepBelow,
|
|
448
|
+
color: 'transparent',
|
|
449
|
+
},
|
|
450
|
+
},
|
|
451
|
+
surfaces: {
|
|
452
|
+
dialog: {
|
|
453
|
+
border: '8px solid rgba(0, 0, 0, 0.2)',
|
|
454
|
+
outline: '1px solid rgba(0, 0, 0, 0.25)',
|
|
455
|
+
background: 'rgba(255, 255, 255, 0.9)',
|
|
456
|
+
backdropFilter: 'blur(6px)',
|
|
361
457
|
},
|
|
362
458
|
},
|
|
363
459
|
animations: {
|
|
364
|
-
interaction: '
|
|
460
|
+
interaction: '200ms cubic-bezier(0.5, 1, 0.89, 1)',
|
|
461
|
+
timing: {
|
|
462
|
+
...TimingFunctions,
|
|
463
|
+
default: TimingFunctions.easeOut,
|
|
464
|
+
},
|
|
465
|
+
duration: {
|
|
466
|
+
rapid: '50ms',
|
|
467
|
+
fast: '100ms',
|
|
468
|
+
normal: '200ms',
|
|
469
|
+
relaxed: '300ms',
|
|
470
|
+
slow: '400ms',
|
|
471
|
+
gradual: '600ms',
|
|
472
|
+
},
|
|
365
473
|
},
|
|
366
474
|
};
|
|
367
475
|
|
|
368
|
-
export const DarkTheme: Theme = {
|
|
369
|
-
...LightTheme,
|
|
476
|
+
export const DarkTheme: Theme = merge(LightTheme, {
|
|
370
477
|
colors: {
|
|
371
|
-
...LightTheme.colors,
|
|
372
|
-
|
|
373
478
|
// Reverse all inverse colors
|
|
374
479
|
|
|
375
480
|
contentPrimary: LightTheme.colors.contentInversePrimary,
|
|
@@ -397,7 +502,21 @@ export const DarkTheme: Theme = {
|
|
|
397
502
|
borderInverseOpaque: LightTheme.colors.borderOpaque,
|
|
398
503
|
borderInverseSelected: LightTheme.colors.borderSelected,
|
|
399
504
|
},
|
|
400
|
-
|
|
505
|
+
borders: {
|
|
506
|
+
dropdown: {
|
|
507
|
+
shadow: 'none',
|
|
508
|
+
color: T.colors.grey600,
|
|
509
|
+
},
|
|
510
|
+
},
|
|
511
|
+
surfaces: {
|
|
512
|
+
dialog: {
|
|
513
|
+
border: '8px solid rgba(255, 255, 255, 0.2)',
|
|
514
|
+
outline: '1px solid rgba(255, 255, 255, 0.25)',
|
|
515
|
+
background: 'rgba(0, 0, 0, 0.6)',
|
|
516
|
+
backdropFilter: 'blur(6px)',
|
|
517
|
+
},
|
|
518
|
+
},
|
|
519
|
+
} as PartialDeep<Theme>) as Theme;
|
|
401
520
|
|
|
402
521
|
export const {
|
|
403
522
|
theme,
|
|
@@ -406,4 +525,4 @@ export const {
|
|
|
406
525
|
updateTheme,
|
|
407
526
|
injectTheme,
|
|
408
527
|
generateThemeInjection,
|
|
409
|
-
} = createTheme(LightTheme);
|
|
528
|
+
} = createTheme<Theme>(LightTheme);
|
|
@@ -15,6 +15,8 @@
|
|
|
15
15
|
border-width: 0; /* 2 */
|
|
16
16
|
border-style: solid; /* 2 */
|
|
17
17
|
border-color: var(--pte-colors-borderSelected); /* 2 */
|
|
18
|
+
|
|
19
|
+
-webkit-tap-highlight-color: transparent;
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
/*
|
|
@@ -325,7 +327,7 @@ Set the default cursor for buttons.
|
|
|
325
327
|
|
|
326
328
|
button,
|
|
327
329
|
[role="button"] {
|
|
328
|
-
cursor:
|
|
330
|
+
cursor: default;
|
|
329
331
|
}
|
|
330
332
|
|
|
331
333
|
/*
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.container {}
|