paris 0.8.15 → 0.8.17
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/README.md +1 -1
- package/package.json +1 -1
- package/src/stories/button/Button.tsx +10 -0
- package/src/stories/icon/NotificationDot.tsx +8 -0
- package/src/stories/menu/Menu.module.scss +21 -0
- package/src/stories/menu/Menu.tsx +11 -6
- package/src/stories/tag/Tag.module.scss +4 -6
- package/src/stories/tag/Tag.tsx +4 -2
- package/src/stories/theme/tokens.ts +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# paris
|
|
2
2
|
|
|
3
|
+
## 0.8.17
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- c1fd99a: feat(Tag): Add new Tag styling
|
|
8
|
+
- c1fd99a: feat: Update menu component to support new feature styling
|
|
9
|
+
- c1fd99a: chore: Update README typo
|
|
10
|
+
- c1fd99a: feat(Button): Add notification dot support
|
|
11
|
+
|
|
12
|
+
## 0.8.16
|
|
13
|
+
|
|
14
|
+
### Patch Changes
|
|
15
|
+
|
|
16
|
+
- 616d1e6: fix: Remove New Tag styling and add teal700
|
|
17
|
+
|
|
3
18
|
## 0.8.15
|
|
4
19
|
|
|
5
20
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ Paris is Slingshot's React design system, meant to work universally across serve
|
|
|
4
4
|
|
|
5
5
|
Currently, Paris is provided as a set of *unbundled* `.tsx` components styled with SCSS modules. This means that you can import only the components you need, and you can use your own bundler to optimize your bundle size. As a result, Paris works best with frameworks like Next.js that have built-in support for TypeScript and SCSS modules.
|
|
6
6
|
|
|
7
|
-
Paris 1.x styling is heavily inspired by Uber's [Base Web](https://baseweb.design), which we previously used in our production apps. We built Paris
|
|
7
|
+
Paris 1.x styling is heavily inspired by Uber's [Base Web](https://baseweb.design), which we previously used in our production apps. We built Paris to move away from Styletron and CSS-in-JS, since we're now largely working with React 18, RSC, and the Next.js `app` directory.
|
|
8
8
|
|
|
9
9
|
<br />
|
|
10
10
|
|
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.8.
|
|
5
|
+
"version": "0.8.17",
|
|
6
6
|
"homepage": "https://paris.slingshot.fm",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"repository": {
|
|
@@ -13,6 +13,7 @@ import type { Enhancer } from '../../types/Enhancer';
|
|
|
13
13
|
import { MemoizedEnhancer } from '../../helpers/renderEnhancer';
|
|
14
14
|
import { pvar } from '../theme';
|
|
15
15
|
import { Spinner } from '../icon';
|
|
16
|
+
import { NotificationDot } from '../icon/NotificationDot';
|
|
16
17
|
|
|
17
18
|
const EnhancerSizes = {
|
|
18
19
|
large: 13,
|
|
@@ -104,6 +105,8 @@ export type ButtonProps = {
|
|
|
104
105
|
* This should be text. When Button shape is `circle` or `square`, the action description should still be passed here for screen readers.
|
|
105
106
|
*/
|
|
106
107
|
children?: ReactNode | ReactNode[];
|
|
108
|
+
|
|
109
|
+
displayNotificationDot?: boolean;
|
|
107
110
|
} & Omit<AriaButtonProps, 'children' | 'disabled' | 'onClick'>;
|
|
108
111
|
|
|
109
112
|
/**
|
|
@@ -133,6 +136,7 @@ export const Button: FC<ButtonProps> = ({
|
|
|
133
136
|
disabled,
|
|
134
137
|
loading,
|
|
135
138
|
href,
|
|
139
|
+
displayNotificationDot = false,
|
|
136
140
|
...props
|
|
137
141
|
}) => (
|
|
138
142
|
<AriaButton
|
|
@@ -145,6 +149,7 @@ export const Button: FC<ButtonProps> = ({
|
|
|
145
149
|
'--pte-colors-backgroundTertiary': theme ? ButtonThemes[theme].secondary : colors?.secondary,
|
|
146
150
|
} as CSSProperties : {}}
|
|
147
151
|
className={clsx(
|
|
152
|
+
'relative',
|
|
148
153
|
styles.button,
|
|
149
154
|
styles[kind],
|
|
150
155
|
styles[shape],
|
|
@@ -189,5 +194,10 @@ export const Button: FC<ButtonProps> = ({
|
|
|
189
194
|
size={EnhancerSizes[size]}
|
|
190
195
|
/>
|
|
191
196
|
)}
|
|
197
|
+
{!!displayNotificationDot && (
|
|
198
|
+
<div className="absolute top-0 right-0">
|
|
199
|
+
<NotificationDot size={8} />
|
|
200
|
+
</div>
|
|
201
|
+
)}
|
|
192
202
|
</AriaButton>
|
|
193
203
|
);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { memo } from 'react';
|
|
2
|
+
import type { IconDefinition } from './Icon';
|
|
3
|
+
|
|
4
|
+
export const NotificationDot: IconDefinition = memo(({ size }) => (
|
|
5
|
+
<svg xmlns="http://www.w3.org/2000/svg" width={size} height={size} viewBox="0 0 8 8" fill="none">
|
|
6
|
+
<circle cx="4" cy="4" r="3.5" fill="#1DEECD" stroke="#8EF7E6" />
|
|
7
|
+
</svg>
|
|
8
|
+
));
|
|
@@ -49,4 +49,25 @@
|
|
|
49
49
|
&:hover {
|
|
50
50
|
background-color: var(--pte-colors-backgroundSecondary);
|
|
51
51
|
}
|
|
52
|
+
|
|
53
|
+
@keyframes gradientFlow {
|
|
54
|
+
0% {
|
|
55
|
+
background-position: 0%;
|
|
56
|
+
}
|
|
57
|
+
100% {
|
|
58
|
+
background-position: 125%;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.newItem {
|
|
64
|
+
background: radial-gradient(circle, rgba(20,239,172,0.2) 0%, rgba(38,237,237,0.05) 75%);
|
|
65
|
+
background-size: 150% 100%;
|
|
66
|
+
animation: gradientFlow 2.5s ease-in-out infinite alternate;
|
|
67
|
+
background-position: 0%;
|
|
68
|
+
|
|
69
|
+
&:hover {
|
|
70
|
+
background-color: unset;
|
|
71
|
+
animation-play-state: paused;
|
|
72
|
+
}
|
|
52
73
|
}
|
|
@@ -31,9 +31,11 @@ export const Menu: FC<MenuProps<React.ElementType>> & {
|
|
|
31
31
|
Items: FC<MenuItemsProps<React.ElementType> & {
|
|
32
32
|
position?: 'left' | 'right';
|
|
33
33
|
}>;
|
|
34
|
-
Item: FC<MenuItemProps<React.ElementType
|
|
34
|
+
Item: FC<MenuItemProps<React.ElementType> & {
|
|
35
|
+
isNew?: boolean;
|
|
36
|
+
}>;
|
|
35
37
|
} = ({ className, children, ...props }) => (
|
|
36
|
-
<HeadlessMenu as="div" className={clsx(
|
|
38
|
+
<HeadlessMenu as="div" className={clsx(styles.menu, className)} {...props}>
|
|
37
39
|
{children}
|
|
38
40
|
</HeadlessMenu>
|
|
39
41
|
);
|
|
@@ -44,7 +46,7 @@ export const Menu: FC<MenuProps<React.ElementType>> & {
|
|
|
44
46
|
* Should be used inside a `Menu` component to serve as the toggle for `MenuItems`.
|
|
45
47
|
*/
|
|
46
48
|
Menu.Button = ({ className, children, ...props }) => (
|
|
47
|
-
<HeadlessMenu.Button className={clsx(
|
|
49
|
+
<HeadlessMenu.Button className={clsx(styles.menuButton, className)} {...props}>
|
|
48
50
|
{children}
|
|
49
51
|
</HeadlessMenu.Button>
|
|
50
52
|
);
|
|
@@ -59,7 +61,7 @@ Menu.Button = ({ className, children, ...props }) => (
|
|
|
59
61
|
Menu.Items = ({
|
|
60
62
|
className, children, position = 'left', ...props
|
|
61
63
|
}) => (
|
|
62
|
-
<HeadlessMenu.Items className={clsx(
|
|
64
|
+
<HeadlessMenu.Items className={clsx(styles.menuItems, position === 'left' && styles.leftPosition, position === 'right' && styles.rightPosition, className)} {...props}>
|
|
63
65
|
{children}
|
|
64
66
|
</HeadlessMenu.Items>
|
|
65
67
|
);
|
|
@@ -69,9 +71,12 @@ Menu.Items = ({
|
|
|
69
71
|
*
|
|
70
72
|
* Should be used inside `MenuItems` to represent selectable options in the menu.
|
|
71
73
|
*
|
|
74
|
+
* @param isNew - Whether the menu items should be styled as new items.
|
|
72
75
|
*/
|
|
73
|
-
Menu.Item = ({
|
|
74
|
-
|
|
76
|
+
Menu.Item = ({
|
|
77
|
+
className, children, isNew = false, ...props
|
|
78
|
+
}) => (
|
|
79
|
+
<HeadlessMenu.Item className={clsx(styles.menuItem, isNew && styles.newItem, className)} {...props}>
|
|
75
80
|
{children}
|
|
76
81
|
</HeadlessMenu.Item>
|
|
77
82
|
);
|
|
@@ -16,6 +16,10 @@
|
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
.new {
|
|
20
|
+
padding: 4px 10px;
|
|
21
|
+
}
|
|
22
|
+
|
|
19
23
|
.default {
|
|
20
24
|
background-color: var(--pte-colors-backgroundTertiary);
|
|
21
25
|
color: var(--pte-colors-contentTertiary);
|
|
@@ -43,10 +47,4 @@
|
|
|
43
47
|
background-color: var(--pte-colors-backgroundNegative);
|
|
44
48
|
color: var(--pte-colors-contentNegative);
|
|
45
49
|
border-color: var(--pte-colors-contentNegative);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
.new {
|
|
49
|
-
border: 1px solid var(--pte-colors-borderAccent);
|
|
50
|
-
background-color: var(--pte-tokens-colors-teal200);
|
|
51
|
-
box-shadow: 0px 0px 10px 0px color-mix(in srgb, var(--pte-colors-contentAccent) 30%, transparent);
|
|
52
50
|
}
|
package/src/stories/tag/Tag.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { FC, ReactNode } from 'react';
|
|
1
|
+
import type { ComponentPropsWithoutRef, FC, ReactNode } from 'react';
|
|
2
2
|
import clsx from 'clsx';
|
|
3
3
|
import styles from './Tag.module.scss';
|
|
4
4
|
import typography from '../text/Typography.module.css';
|
|
@@ -10,7 +10,7 @@ export type TagProps = {
|
|
|
10
10
|
kind?: 'default' | 'secondary' | 'positive' | 'warning' | 'negative' | 'new';
|
|
11
11
|
/** The contents of the Tag. */
|
|
12
12
|
children: ReactNode;
|
|
13
|
-
}
|
|
13
|
+
} & Omit<ComponentPropsWithoutRef<'div'>, 'children'>;
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* A Tag component.
|
|
@@ -28,6 +28,7 @@ export const Tag: FC<TagProps> = ({
|
|
|
28
28
|
size = 'normal',
|
|
29
29
|
kind = 'default',
|
|
30
30
|
children,
|
|
31
|
+
className,
|
|
31
32
|
}) => (
|
|
32
33
|
<div
|
|
33
34
|
className={clsx(
|
|
@@ -36,6 +37,7 @@ export const Tag: FC<TagProps> = ({
|
|
|
36
37
|
styles[kind],
|
|
37
38
|
size === 'normal' && typography.labelXSmall,
|
|
38
39
|
size === 'compact' && typography.labelXXSmall,
|
|
40
|
+
className,
|
|
39
41
|
)}
|
|
40
42
|
>
|
|
41
43
|
{children}
|