paris 0.8.16 → 0.8.18

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 CHANGED
@@ -1,5 +1,23 @@
1
1
  # paris
2
2
 
3
+ ## 0.8.18
4
+
5
+ ### Patch Changes
6
+
7
+ - 3a29baf: Menu: update category
8
+ - e9d24cf: Icon: fix typings for `as` prop
9
+ - e9d24cf: StyledLink: fix typings for `as` prop
10
+ - 9b29f1d: Table: update docs to mention `cells` instead of `nodes` for `rowRenderFn`
11
+
12
+ ## 0.8.17
13
+
14
+ ### Patch Changes
15
+
16
+ - c1fd99a: feat(Tag): Add new Tag styling
17
+ - c1fd99a: feat: Update menu component to support new feature styling
18
+ - c1fd99a: chore: Update README typo
19
+ - c1fd99a: feat(Button): Add notification dot support
20
+
3
21
  ## 0.8.16
4
22
 
5
23
  ### 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 because 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.
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.16",
5
+ "version": "0.8.18",
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
  );
@@ -1,4 +1,4 @@
1
- import type { ComponentPropsWithoutRef, NamedExoticComponent } from 'react';
1
+ import type { ComponentPropsWithoutRef, ElementType, NamedExoticComponent } from 'react';
2
2
  import { createElement, memo } from 'react';
3
3
 
4
4
  export type IconDefinitionProps = {
@@ -9,7 +9,7 @@ export type IconDefinitionProps = {
9
9
  };
10
10
  export type IconDefinition = NamedExoticComponent<IconDefinitionProps>;
11
11
 
12
- export type IconProps<T extends keyof JSX.IntrinsicElements = 'span'> = IconDefinitionProps & {
12
+ export type IconProps<T extends ElementType = 'span'> = IconDefinitionProps & {
13
13
  icon: IconDefinition;
14
14
  as?: T;
15
15
  overrides?: {
@@ -31,7 +31,7 @@ export type IconProps<T extends keyof JSX.IntrinsicElements = 'span'> = IconDefi
31
31
  * ```
32
32
  * @constructor
33
33
  */
34
- export const Icon = memo<IconProps>(({
34
+ export const Icon = memo<IconProps<ElementType>>(({
35
35
  as = 'span',
36
36
  icon,
37
37
  size,
@@ -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
  }
@@ -6,7 +6,7 @@ import { Button } from '../button';
6
6
  import { ChevronRight, Ellipsis } from '../icon';
7
7
 
8
8
  const meta: Meta<typeof Menu> = {
9
- title: 'Uncategorized/Menu',
9
+ title: 'Surfaces/Menu',
10
10
  component: Menu,
11
11
  tags: ['autodocs'],
12
12
  };
@@ -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(className, styles.menu)} {...props}>
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(className, styles.menuButton)} {...props}>
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(className, styles.menuItems, position === 'left' && styles.leftPosition, position === 'right' && styles.rightPosition)} {...props}>
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 = ({ className, children, ...props }) => (
74
- <HeadlessMenu.Item className={clsx(className, styles.menuItem)} {...props}>
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
  );
@@ -12,12 +12,17 @@ type Story = StoryObj<typeof StyledLink>;
12
12
 
13
13
  export const Default: Story = {
14
14
  args: {
15
- children: 'Hello world! This is a new StyledLink component.',
15
+ href: 'https://slingshot.fm',
16
+ target: '_blank',
17
+ children: 'Hello world! This is a styled link.',
16
18
  },
17
19
  };
18
20
 
19
- export const Secondary: Story = {
21
+ export const AsButton: Story = {
20
22
  args: {
21
- children: 'Hello world! This is a secondary component.',
23
+ as: 'button',
24
+ // eslint-disable-next-line no-alert
25
+ onClick: () => alert('Hello world!'),
26
+ children: 'Hello world! This is a StyledLink rendered as a button.',
22
27
  },
23
28
  };
@@ -24,7 +24,7 @@ export type StyledLinkProps<T extends ElementType = 'a'> = {
24
24
  * ```
25
25
  * @constructor
26
26
  */
27
- export const StyledLink: FC<StyledLinkProps> = ({
27
+ export const StyledLink: FC<StyledLinkProps<ElementType>> = ({
28
28
  as = 'a',
29
29
  children,
30
30
  className,
@@ -42,7 +42,7 @@ export type TableProps<
42
42
  *
43
43
  * The function should return an object containing a property named `key` for the row's React key (should be a unique id), and a property named `nodes` containing an array of React nodes to be rendered as cells in the row.
44
44
  * @param row - The data for the row being rendered.
45
- * @returns An object containing a property named `key` for the row's React key (should be a unique id), and a property named `nodes` containing an array of React nodes to be rendered as cells in the row.
45
+ * @returns An object containing a property named `key` for the row's React key (should be a unique id), and a property named `cells` containing an array of React nodes to be rendered as cells in the row.
46
46
  * @see RowRenderData
47
47
  */
48
48
  rowRenderFn?: (row: RowData[number]) => RowRenderData;
@@ -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);