paris 0.8.21 → 0.9.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.
Files changed (58) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/package.json +2 -2
  3. package/src/helpers/useIsMounted.ts +17 -0
  4. package/src/helpers/useResizeObserver.ts +97 -0
  5. package/src/stories/accordion/Accordion.module.scss +4 -4
  6. package/src/stories/avatar/Avatar.module.scss +1 -1
  7. package/src/stories/avatar/Avatar.tsx +1 -1
  8. package/src/stories/button/Button.module.scss +46 -24
  9. package/src/stories/button/Button.stories.ts +24 -0
  10. package/src/stories/button/Button.tsx +95 -70
  11. package/src/stories/callout/Callout.module.scss +7 -7
  12. package/src/stories/callout/Callout.stories.ts +8 -0
  13. package/src/stories/callout/Callout.tsx +4 -3
  14. package/src/stories/card/Card.module.scss +3 -3
  15. package/src/stories/card/Card.stories.ts +0 -5
  16. package/src/stories/checkbox/Checkbox.module.scss +19 -6
  17. package/src/stories/checkbox/Checkbox.tsx +2 -1
  18. package/src/stories/combobox/Combobox.stories.ts +8 -8
  19. package/src/stories/combobox/Combobox.tsx +11 -4
  20. package/src/stories/dialog/Dialog.module.scss +43 -19
  21. package/src/stories/dialog/Dialog.stories.tsx +40 -0
  22. package/src/stories/dialog/Dialog.tsx +28 -17
  23. package/src/stories/drawer/Drawer.module.scss +141 -46
  24. package/src/stories/drawer/Drawer.stories.tsx +151 -0
  25. package/src/stories/drawer/Drawer.tsx +100 -103
  26. package/src/stories/field/Field.stories.ts +1 -1
  27. package/src/stories/field/Field.tsx +0 -1
  28. package/src/stories/icon/ArrowRight.tsx +11 -0
  29. package/src/stories/icon/Check.tsx +11 -0
  30. package/src/stories/icon/Icon.stories.ts +5 -1
  31. package/src/stories/icon/index.ts +3 -0
  32. package/src/stories/input/Input.module.scss +43 -31
  33. package/src/stories/input/Input.stories.ts +7 -7
  34. package/src/stories/input/Input.tsx +14 -5
  35. package/src/stories/menu/Menu.module.scss +6 -6
  36. package/src/stories/menu/Menu.stories.tsx +24 -28
  37. package/src/stories/popover/Popover.module.scss +3 -3
  38. package/src/stories/select/Select.module.scss +38 -16
  39. package/src/stories/select/Select.stories.ts +24 -12
  40. package/src/stories/select/Select.tsx +17 -3
  41. package/src/stories/styledlink/StyledLink.module.scss +2 -2
  42. package/src/stories/table/Table.module.scss +6 -5
  43. package/src/stories/table/Table.stories.ts +9 -9
  44. package/src/stories/table/Table.tsx +7 -1
  45. package/src/stories/tabs/Tabs.module.scss +168 -27
  46. package/src/stories/tabs/Tabs.stories.tsx +125 -0
  47. package/src/stories/tabs/Tabs.tsx +69 -37
  48. package/src/stories/tag/Tag.module.scss +160 -21
  49. package/src/stories/tag/Tag.stories.ts +22 -1
  50. package/src/stories/tag/Tag.tsx +63 -16
  51. package/src/stories/textarea/TextArea.stories.ts +2 -2
  52. package/src/stories/textarea/TextArea.tsx +12 -5
  53. package/src/stories/theme/themes.ts +907 -13
  54. package/src/stories/theme/tokens.ts +77 -0
  55. package/src/stories/theme/tw-preflight.css +3 -3
  56. package/src/stories/tilt/Tilt.stories.tsx +4 -4
  57. package/src/stories/toast/Toast.module.scss +4 -4
  58. package/src/stories/tabs/Tabs.stories.ts +0 -39
package/CHANGELOG.md CHANGED
@@ -1,5 +1,41 @@
1
1
  # paris
2
2
 
3
+ ## 0.9.0
4
+
5
+ ### Minor Changes
6
+
7
+ - a8941e5: Tabs: color and styling updates, kind `full`, `barStyle` thick or thin, `backgroundStyle` with glass option
8
+ - ecd7deb: Theme: Revamped tokens and variables with updated structures, plus new materials and blurs
9
+ - a8941e5: Theme: updated “materials” variables, added accent glows to “lighting”
10
+ - a8941e5: Drawer: color and styling updates, new sizes `fullWithMargin` and `fullOnMobile` with tweaked `full` behavior, `bottomPanel` with glass material and removed padding, `additionalActions` available on paginated drawers, `overlayStyle` "greyed" renamed to "grey"
11
+ - a8941e5: Dialog: color and styling updates, `overlayStyle` with default `blur` and option `grey`
12
+ - a8941e5: Callout: color updates, default ArrowRight icon
13
+ - a8941e5: Tag: color and styling updates, `shape` prop for `square` variant with `icon`, `corners` prop for border and radius, planned`and`void`kinds,`colorLevel` to adjust color background
14
+ - a8941e5: Button: color updates, added `medium` size, `corners` prop for border-radius, removed `rounded` shape
15
+
16
+ ### Patch Changes
17
+
18
+ - a8941e5: Accordion: color updates
19
+ - a8941e5: Styled Link: color updates
20
+ - a8941e5: Table: color and styling updates
21
+ - a8941e5: Toast: color updates
22
+ - a8941e5: Popover: color updates
23
+ - a8941e5: Checkbox: color updates
24
+ - a8941e5: Select: color and styling updates, fixed disabled states
25
+ - a8941e5: Menu: color updates
26
+ - a8941e5: TextArea: color updates, enhancer updates to match Input
27
+ - a8941e5: Card: color updates
28
+ - a8941e5: Avatar: color updates
29
+ - a8941e5: Combobox: color and styling updates
30
+ - a8941e5: Icon: `Check` and `ArrowRight`
31
+ - a8941e5: Input: color and styling updates, enhancer color states
32
+
33
+ ## 0.8.22
34
+
35
+ ### Patch Changes
36
+
37
+ - 0243ccb: fix(Field): Remove stopPropagation on Field component
38
+
3
39
  ## 0.8.21
4
40
 
5
41
  ### 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.8.21",
5
+ "version": "0.9.0",
6
6
  "homepage": "https://paris.slingshot.fm",
7
7
  "license": "MIT",
8
8
  "repository": {
@@ -67,7 +67,7 @@
67
67
  "clsx": "^1.2.1",
68
68
  "font-color-contrast": "^11.1.0",
69
69
  "framer-motion": "^10.16.4",
70
- "pte": "^0.4.9",
70
+ "pte": "^0.5.0",
71
71
  "react-hot-toast": "^2.4.1",
72
72
  "react-parallax-tilt": "^1.7.144",
73
73
  "react-tiny-popover": "^8.0.4",
@@ -0,0 +1,17 @@
1
+ // Copied from https://usehooks-ts.com/react-hook/use-is-mounted
2
+
3
+ import { useCallback, useEffect, useRef } from 'react';
4
+
5
+ export function useIsMounted(): () => boolean {
6
+ const isMounted = useRef(false);
7
+
8
+ useEffect(() => {
9
+ isMounted.current = true;
10
+
11
+ return () => {
12
+ isMounted.current = false;
13
+ };
14
+ }, []);
15
+
16
+ return useCallback(() => isMounted.current, []);
17
+ }
@@ -0,0 +1,97 @@
1
+ // Copied from https://usehooks-ts.com/react-hook/use-resize-observer
2
+
3
+ import { useEffect, useRef, useState } from 'react';
4
+
5
+ import type { RefObject } from 'react';
6
+
7
+ import { useIsMounted } from './useIsMounted';
8
+
9
+ type Size = {
10
+ width: number | undefined
11
+ height: number | undefined
12
+ };
13
+
14
+ type UseResizeObserverOptions<T extends HTMLElement = HTMLElement> = {
15
+ ref: RefObject<T>
16
+ onResize?: (size: Size) => void
17
+ box?: 'border-box' | 'content-box' | 'device-pixel-content-box'
18
+ };
19
+
20
+ const initialSize: Size = {
21
+ width: undefined,
22
+ height: undefined,
23
+ };
24
+
25
+ export function useResizeObserver<T extends HTMLElement = HTMLElement>(
26
+ options: UseResizeObserverOptions<T>,
27
+ ): Size {
28
+ const { ref, box = 'content-box' } = options;
29
+ const [{ width, height }, setSize] = useState<Size>(initialSize);
30
+ const isMounted = useIsMounted();
31
+ const previousSize = useRef<Size>({ ...initialSize });
32
+ const onResize = useRef<((size: Size) => void) | undefined>(undefined);
33
+ onResize.current = options.onResize;
34
+
35
+ useEffect(() => {
36
+ if (!ref.current) return;
37
+
38
+ if (typeof window === 'undefined' || !('ResizeObserver' in window)) return;
39
+
40
+ const observer = new ResizeObserver(([entry]) => {
41
+ const boxProp = box === 'border-box'
42
+ ? 'borderBoxSize'
43
+ : box === 'device-pixel-content-box'
44
+ ? 'devicePixelContentBoxSize'
45
+ : 'contentBoxSize';
46
+
47
+ const newWidth = extractSize(entry, boxProp, 'inlineSize');
48
+ const newHeight = extractSize(entry, boxProp, 'blockSize');
49
+
50
+ const hasChanged = previousSize.current.width !== newWidth
51
+ || previousSize.current.height !== newHeight;
52
+
53
+ if (hasChanged) {
54
+ const newSize: Size = { width: newWidth, height: newHeight };
55
+ previousSize.current.width = newWidth;
56
+ previousSize.current.height = newHeight;
57
+
58
+ if (onResize.current) {
59
+ onResize.current(newSize);
60
+ } else if (isMounted()) {
61
+ setSize(newSize);
62
+ }
63
+ }
64
+ });
65
+
66
+ observer.observe(ref.current, { box });
67
+
68
+ return () => {
69
+ observer.disconnect();
70
+ };
71
+ }, [box, ref, isMounted]);
72
+
73
+ return { width, height };
74
+ }
75
+
76
+ type BoxSizesKey = keyof Pick<
77
+ ResizeObserverEntry,
78
+ 'borderBoxSize' | 'contentBoxSize' | 'devicePixelContentBoxSize'
79
+ >;
80
+
81
+ function extractSize(
82
+ entry: ResizeObserverEntry,
83
+ box: BoxSizesKey,
84
+ sizeType: keyof ResizeObserverSize,
85
+ ): number | undefined {
86
+ if (!entry[box]) {
87
+ if (box === 'contentBoxSize') {
88
+ return entry.contentRect[sizeType === 'inlineSize' ? 'width' : 'height'];
89
+ }
90
+ return undefined;
91
+ }
92
+
93
+ return Array.isArray(entry[box])
94
+ ? entry[box][0][sizeType]
95
+ : // @ts-ignore Support Firefox's non-standard behavior
96
+ (entry[box][sizeType] as number);
97
+ }
@@ -1,6 +1,6 @@
1
1
  .container {
2
- color: var(--pte-colors-contentPrimary);
3
- border-bottom: 1px solid var(--pte-colors-borderOpaque);
2
+ color: var(--pte-new-colors-contentPrimary);
3
+ border-bottom: 1px solid var(--pte-new-colors-borderSubtle);
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-colors-borderOpaque);
22
+ border-bottom-color: var(--pte-new-colors-borderSubtle);
23
23
  }
24
24
  }
25
25
 
@@ -48,6 +48,6 @@
48
48
  display: flex;
49
49
  flex-direction: column;
50
50
  gap: 12px;
51
- background-color: var(--pte-colors-backgroundSecondary);
51
+ background-color: var(--pte-new-colors-overlaySubtle);
52
52
  }
53
53
  }
@@ -3,5 +3,5 @@
3
3
  aspect-ratio: 1;
4
4
  border: 1px solid var(--frame-color);
5
5
  overflow: clip;
6
- box-shadow: var(--pte-lighting-subtlePopup);
6
+ box-shadow: var(--pte-new-lighting-subtlePopup);
7
7
  }
@@ -28,7 +28,7 @@ export type AvatarProps = {
28
28
  * @constructor
29
29
  */
30
30
  export const Avatar: FC<AvatarProps> = ({
31
- frameColor = pvar('colors.borderOpaque'),
31
+ frameColor = pvar('new.colors.borderMedium'),
32
32
  width = 'fit-content',
33
33
  children,
34
34
  className,
@@ -21,7 +21,7 @@
21
21
 
22
22
  &:hover {
23
23
  cursor: default;
24
- background-color: var(--pte-colors-backgroundInverseTertiary);
24
+ background-color: var(--pte-new-colors-buttonFillHover);
25
25
  }
26
26
 
27
27
  &[aria-disabled=false]:active {
@@ -40,45 +40,47 @@
40
40
  */
41
41
 
42
42
  .primary {
43
- color: var(--pte-colors-contentInversePrimary);
44
- background-color: var(--pte-colors-backgroundInversePrimary);
45
- border-color: var(--pte-colors-backgroundInversePrimary);
43
+ color: var(--pte-new-colors-contentInversePrimary);
44
+ background-color: var(--pte-new-colors-buttonFill);
45
+ border-color: var(--pte-new-colors-buttonFill);
46
46
 
47
47
  &:hover {
48
- border-color: var(--pte-colors-backgroundInverseTertiary);
48
+ border-color: var(-pte-new-colors-buttonFillHover);
49
49
  }
50
50
 
51
51
  &[aria-disabled=true] {
52
- color: var(--pte-colors-contentDisabled);
53
- background-color: var(--pte-colors-backgroundTertiary);
54
- border-color: var(--pte-colors-backgroundTertiary);
52
+ color: var(--pte-new-colors-contentDisabled);
53
+ background-color: var(--pte-new-colors-buttonFillDisabled);
54
+ border-color: var(--pte-new-colors-buttonFillDisabled);
55
55
  }
56
56
  }
57
57
 
58
58
  .secondary {
59
- color: var(--pte-colors-contentPrimary);
59
+ color: var(--pte-new-colors-contentPrimary);
60
60
  background-color: transparent;
61
- border-color: var(--pte-colors-contentPrimary);
61
+ border-color: var(--pte-new-colors-buttonBorder);
62
+
63
+ &:hover {
64
+ background-color: var(--pte-new-colors-overlayMedium);
65
+ }
62
66
 
63
67
  &[aria-disabled=true] {
64
- color: var(--pte-colors-contentDisabled);
65
- border-color: var(--pte-colors-contentDisabled);
68
+ color: var(--pte-new-colors-contentDisabled);
69
+ border-color: var(--pte-new-colors-buttonBorderDisabled);
66
70
  }
67
71
  }
68
72
 
69
73
  .tertiary {
70
- color: var(--pte-colors-contentPrimary);
74
+ color: var(--pte-new-colors-contentPrimary);
71
75
  background-color: transparent;
72
76
  border-color: transparent;
73
- }
74
77
 
75
- .secondary, .tertiary {
76
78
  &:hover {
77
- background-color: var(--pte-colors-backgroundTertiary);
79
+ background-color: var(--pte-new-colors-overlayMedium);
78
80
  }
79
81
 
80
82
  &[aria-disabled=true] {
81
- color: var(--pte-colors-contentDisabled);
83
+ color: var(--pte-new-colors-contentDisabled);
82
84
  }
83
85
  }
84
86
 
@@ -92,6 +94,11 @@
92
94
  padding: 8px 15px;
93
95
  }
94
96
 
97
+ .medium {
98
+ height: 28px;
99
+ padding: 6px 14px;
100
+ }
101
+
95
102
  .small {
96
103
  height: 20px;
97
104
  padding: 4px 15px;
@@ -115,16 +122,26 @@
115
122
  border-radius: var(--pte-borders-radius-circle);
116
123
  }
117
124
 
118
- .rounded {
119
- border-radius: var(--pte-borders-radius-rounded);
125
+ .square, .rectangle {
126
+ &.sharp {
127
+ border-radius: var(--pte-borders-radius-rectangle);
128
+ }
120
129
 
121
- &.small {
122
- border-radius: var(--pte-borders-radius-roundedSmall);
130
+ &.rounded {
131
+ border-radius: var(--pte-borders-radius-rounded);
132
+
133
+ &.small {
134
+ border-radius: var(--pte-borders-radius-roundedSmall);
135
+ }
123
136
  }
124
- }
125
137
 
126
- .square, .rectangle {
127
- border-radius: var(--pte-borders-radius-rectangle);
138
+ &.roundedXL {
139
+ border-radius: var(--pte-borders-radius-roundedLarge);
140
+
141
+ &.small {
142
+ border-radius: var(--pte-borders-radius-rounded);
143
+ }
144
+ }
128
145
  }
129
146
 
130
147
  .circle, .square {
@@ -133,6 +150,11 @@
133
150
  padding: 8px;
134
151
  }
135
152
 
153
+ &.medium {
154
+ width: 28px;
155
+ padding: 4px;
156
+ }
157
+
136
158
  &.small {
137
159
  width: 20px;
138
160
  padding: 4px;
@@ -57,3 +57,27 @@ export const WithEnhancer: Story = {
57
57
  }),
58
58
  },
59
59
  };
60
+
61
+ export const Circle: Story = {
62
+ args: {
63
+ children: 'Button',
64
+ shape: 'circle',
65
+ kind: 'tertiary',
66
+ startEnhancer: ({ size }) => createElement(FontAwesomeIcon, {
67
+ icon: faPlus,
68
+ width: `${size}px`,
69
+ }),
70
+ },
71
+ };
72
+
73
+ export const Rounded: Story = {
74
+ args: {
75
+ children: 'Button',
76
+ shape: 'rectangle',
77
+ corners: 'rounded',
78
+ startEnhancer: ({ size }) => createElement(FontAwesomeIcon, {
79
+ icon: faPlus,
80
+ width: `${size}px`,
81
+ }),
82
+ },
83
+ };
@@ -3,10 +3,12 @@
3
3
  import type {
4
4
  CSSProperties, FC, HTMLAttributeAnchorTarget, MouseEventHandler, ReactNode,
5
5
  } from 'react';
6
+ import { useMemo } from 'react';
6
7
  import type { ButtonProps as AriaButtonProps } from '@ariakit/react';
7
8
  import { Button as AriaButton } from '@ariakit/react';
8
9
  import clsx from 'clsx';
9
10
  import fontColorContrast from 'font-color-contrast';
11
+ import type { CSSLength } from '@ssh/csstypes';
10
12
  import styles from './Button.module.scss';
11
13
  import { Text } from '../text';
12
14
  import type { Enhancer } from '../../types/Enhancer';
@@ -17,22 +19,31 @@ import { NotificationDot } from '../icon/NotificationDot';
17
19
 
18
20
  const EnhancerSizes = {
19
21
  large: 13,
22
+ medium: 12,
20
23
  small: 11,
21
24
  xs: 9,
22
25
  };
23
26
 
27
+ export const CornerPresets = ['sharp', 'rounded', 'roundedXL'] as const;
28
+
24
29
  export const ButtonThemes = {
25
30
  negative: {
26
- primary: pvar('colors.contentNegative'),
27
- secondary: pvar('colors.backgroundNegative'),
31
+ primary: pvar('new.colors.buttonBorderNegative'),
32
+ secondary: pvar('new.colors.buttonFillHoverNegative'),
33
+ primaryAlt: pvar('new.colors.contentNegative'),
34
+ secondaryAlt: pvar('new.colors.backgroundNegativeStrong'),
28
35
  },
29
36
  positive: {
30
- primary: pvar('colors.contentPositive'),
31
- secondary: pvar('colors.backgroundPositive'),
37
+ primary: pvar('new.colors.contentPositive'),
38
+ secondary: pvar('new.colors.backgroundPositive'),
39
+ primaryAlt: pvar('new.colors.contentPositive'),
40
+ secondaryAlt: pvar('new.colors.backgroundPositiveStrong'),
32
41
  },
33
42
  warning: {
34
- primary: pvar('colors.contentWarning'),
35
- secondary: pvar('colors.backgroundWarning'),
43
+ primary: pvar('new.colors.contentWarning'),
44
+ secondary: pvar('new.colors.backgroundWarning'),
45
+ primaryAlt: pvar('new.colors.contentWarning'),
46
+ secondaryAlt: pvar('new.colors.backgroundWarningStrong'),
36
47
  },
37
48
  } as const;
38
49
 
@@ -46,12 +57,19 @@ export type ButtonProps = {
46
57
  * The size of the Button.
47
58
  * @default large
48
59
  */
49
- size?: 'large' | 'small' | 'xs';
60
+ size?: 'large' | 'medium' | 'small' | 'xs';
50
61
  /**
51
62
  * The shape of the Button.
52
63
  * @default pill
53
64
  */
54
- shape?: 'pill' | 'circle' | 'rectangle' | 'square' | 'rounded';
65
+ shape?: 'pill' | 'circle' | 'rectangle' | 'square';
66
+ /**
67
+ * The radius of the corners for the `rectangle` and `square` Button shapes. Either a preset or a valid {@link CSSLength} string.
68
+ * `sharp` will have no rounding, `rounded` will have a slight rounding, and `roundedXL` will have a large rounding.
69
+ * @see CornerPresets
70
+ * @default rounded
71
+ */
72
+ corners?: typeof CornerPresets[number] | CSSLength;
55
73
  /**
56
74
  * A color to apply for the Button. Provide an object with `primary` and `secondary` properties to set the primary and hover colors.
57
75
  */
@@ -126,6 +144,7 @@ export const Button: FC<ButtonProps> = ({
126
144
  kind = 'primary',
127
145
  size = 'large',
128
146
  shape = 'pill',
147
+ corners = 'rounded',
129
148
  colors,
130
149
  theme,
131
150
  type = 'button',
@@ -139,66 +158,72 @@ export const Button: FC<ButtonProps> = ({
139
158
  displayNotificationDot = false,
140
159
  style,
141
160
  ...props
142
- }) => (
143
- <AriaButton
144
- {...props}
145
- style={(theme || colors) ? {
146
- '--pte-colors-contentInversePrimary': fontColorContrast(theme ? ButtonThemes[theme].primary : colors?.primary || pvar('colors.contentPrimary')),
147
- '--pte-colors-backgroundInversePrimary': theme ? ButtonThemes[theme].primary : colors?.primary,
148
- '--pte-colors-backgroundInverseTertiary': theme ? ButtonThemes[theme].secondary : colors?.secondary,
149
- '--pte-colors-contentPrimary': theme ? ButtonThemes[theme].primary : colors?.primary,
150
- '--pte-colors-backgroundTertiary': theme ? ButtonThemes[theme].secondary : colors?.secondary,
151
- ...style,
152
- } as CSSProperties : style}
153
- className={clsx(
154
- styles.button,
155
- styles[kind],
156
- styles[shape],
157
- styles[size],
158
- props?.className,
159
- )}
160
- aria-disabled={disabled ?? false}
161
- type={type}
162
- aria-details={typeof children === 'string' ? children : undefined}
163
- onClick={!disabled && !href && !loading ? onClick : () => {}}
164
- disabled={false}
165
- {...href ? {
166
- render: (properties) => (
167
- // eslint-disable-next-line jsx-a11y/anchor-has-content
168
- <a
169
- {...properties}
170
- href={href}
171
- target={props.hreftarget ?? '_self'}
172
- rel={props.hreftarget === '_self' ? undefined : 'noreferrer'}
161
+ }) => {
162
+ const cornersIsPreset = useMemo(() => (CornerPresets as readonly string[]).includes(corners), [corners]);
163
+ return (
164
+ <AriaButton
165
+ {...props}
166
+ style={(theme || colors) ? {
167
+ '--pte-new-colors-contentInversePrimary': fontColorContrast(theme ? ButtonThemes[theme].primary : colors?.primary || pvar('new.colors.contentPrimary')), // text for primary
168
+ '--pte-new-colors-buttonFill': theme ? ButtonThemes[theme].primaryAlt : colors?.primary, // background for primary
169
+ '--pte-new-colors-buttonFillHover': theme ? ButtonThemes[theme].secondaryAlt : colors?.secondary, // hover background for primary
170
+ '--pte-new-colors-contentPrimary': theme ? ButtonThemes[theme].primary : colors?.primary, // text for secondary/tertiary
171
+ '--pte-new-colors-buttonBorder': theme ? ButtonThemes[theme].primary : colors?.primary, // border for secondary/tertiary
172
+ '--pte-new-colors-overlayMedium': theme ? ButtonThemes[theme].secondary : colors?.secondary, // hover background for secondary/tertiary
173
+ borderRadius: !cornersIsPreset ? corners : '',
174
+ ...style,
175
+ } as CSSProperties : ({ borderRadius: !cornersIsPreset ? corners : '', ...style })}
176
+ className={clsx(
177
+ styles.button,
178
+ styles[kind],
179
+ styles[shape],
180
+ styles[size],
181
+ cornersIsPreset && styles[corners],
182
+ props?.className,
183
+ )}
184
+ aria-disabled={disabled ?? false}
185
+ type={type}
186
+ aria-details={typeof children === 'string' ? children : undefined}
187
+ onClick={!disabled && !href && !loading ? onClick : () => {}}
188
+ disabled={false}
189
+ {...href ? {
190
+ render: (properties) => (
191
+ // eslint-disable-next-line jsx-a11y/anchor-has-content
192
+ <a
193
+ {...properties}
194
+ href={href}
195
+ target={props.hreftarget ?? '_self'}
196
+ rel={props.hreftarget === '_self' ? undefined : 'noreferrer'}
197
+ />
198
+ ),
199
+ } : {}}
200
+ >
201
+ {!!startEnhancer && (
202
+ <MemoizedEnhancer
203
+ enhancer={startEnhancer}
204
+ size={EnhancerSizes[size]}
173
205
  />
174
- ),
175
- } : {}}
176
- >
177
- {!!startEnhancer && (
178
- <MemoizedEnhancer
179
- enhancer={startEnhancer}
180
- size={EnhancerSizes[size]}
181
- />
182
- )}
183
- {!['circle', 'square'].includes(shape) && (
184
- <Text kind="labelXSmall">
185
- {!loading ? (
186
- children || 'Button'
187
- ) : (
188
- <Spinner size={EnhancerSizes[size]} />
189
- )}
190
- </Text>
191
- )}
192
- {!!endEnhancer && (
193
- <MemoizedEnhancer
194
- enhancer={endEnhancer}
195
- size={EnhancerSizes[size]}
196
- />
197
- )}
198
- {!!displayNotificationDot && (
199
- <div className="absolute top-0 right-0">
200
- <NotificationDot size={8} />
201
- </div>
202
- )}
203
- </AriaButton>
204
- );
206
+ )}
207
+ {!['circle', 'square'].includes(shape) && (
208
+ <Text kind="labelXSmall">
209
+ {!loading ? (
210
+ children || 'Button'
211
+ ) : (
212
+ <Spinner size={EnhancerSizes[size]} />
213
+ )}
214
+ </Text>
215
+ )}
216
+ {!!endEnhancer && (
217
+ <MemoizedEnhancer
218
+ enhancer={endEnhancer}
219
+ size={EnhancerSizes[size]}
220
+ />
221
+ )}
222
+ {!!displayNotificationDot && (
223
+ <div className="absolute top-0 right-0">
224
+ <NotificationDot size={8} />
225
+ </div>
226
+ )}
227
+ </AriaButton>
228
+ );
229
+ };
@@ -1,9 +1,9 @@
1
1
  .content {
2
- background-color: var(--pte-colors-backgroundSecondary);
2
+ background-color: var(--pte-new-colors-overlayMedium);
3
3
  border-radius: 6px;
4
4
  width: 100%;
5
5
  padding: 8px 10px;
6
- color: var(--pte-colors-contentTertiary);
6
+ color: var(--pte-new-colors-contentSecondary);
7
7
 
8
8
  display: flex;
9
9
  flex-direction: row;
@@ -26,18 +26,18 @@
26
26
  }
27
27
 
28
28
  &.warning {
29
- background-color: var(--pte-colors-backgroundWarning);
30
- color: var(--pte-colors-contentWarning);
29
+ background-color: var(--pte-new-colors-backgroundWarning);
30
+ color: var(--pte-new-colors-contentWarning);
31
31
  }
32
32
 
33
33
  &.negative {
34
- background-color: var(--pte-colors-backgroundNegative);
35
- color: var(--pte-colors-contentNegative);
34
+ background-color: var(--pte-new-colors-overlayRed);
35
+ color: var(--pte-new-colors-contentNegative);
36
36
  }
37
37
 
38
38
  &.positive {
39
39
  .icon {
40
- color: var(--pte-colors-contentPositive);
40
+ color: var(--pte-new-colors-contentPositive);
41
41
  }
42
42
  }
43
43
  }
@@ -51,3 +51,11 @@ export const Positive: Story = {
51
51
  ),
52
52
  },
53
53
  };
54
+
55
+ export const IconHidden: Story = {
56
+ args: {
57
+ variant: 'default',
58
+ children: 'Please upload a receipt',
59
+ icon: null,
60
+ },
61
+ };
@@ -4,12 +4,13 @@ import type {
4
4
  import clsx from 'clsx';
5
5
  import styles from './Callout.module.scss';
6
6
  import { RemoveFromDOM, TextWhenString } from '../utility';
7
+ import { Icon, ArrowRight } from '../icon';
7
8
 
8
9
  export type CalloutProps = {
9
10
  /** The variant of the Callout. */
10
11
  variant?: 'default' | 'warning' | 'positive' | 'negative';
11
- /** An icon to display in the Callout. For best results, use an SVG icon with fill set to `currentColor`. */
12
- icon?: ReactElement;
12
+ /** An icon to display in the Callout. To hide icon, set `icon={null}`. For best results, use an SVG icon with fill set to `currentColor`. */
13
+ icon?: ReactElement | null;
13
14
  /** The contents of the Callout. */
14
15
  children?: ReactNode;
15
16
  } & Omit<ComponentPropsWithoutRef<'div'>, 'children'>;
@@ -28,7 +29,7 @@ export type CalloutProps = {
28
29
  */
29
30
  export const Callout: FC<CalloutProps> = ({
30
31
  variant = 'default',
31
- icon,
32
+ icon = <Icon icon={ArrowRight} size={16} className={styles.icon} />,
32
33
  children,
33
34
  className,
34
35
  ...props