@sproutsocial/racine 11.9.0-typescript.0 → 12.0.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 (49) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/__flow__/Button/{index.tsx → index.js} +21 -20
  3. package/__flow__/Button/{styles.ts → styles.js} +1 -1
  4. package/__flow__/Checkbox/styles.js +75 -75
  5. package/__flow__/Collapsible/index.js +2 -3
  6. package/__flow__/Image/index.js +2 -10
  7. package/__flow__/Input/index.js +2 -2
  8. package/__flow__/SegmentedControl/index.js +2 -3
  9. package/__flow__/TableCell/index.js +2 -9
  10. package/__flow__/ToggleHint/index.js +2 -9
  11. package/__flow__/Token/styles.js +13 -12
  12. package/__flow__/index.js +1 -0
  13. package/__flow__/systemProps/color.js +2 -1
  14. package/__flow__/themes/dark/theme.js +0 -5
  15. package/__flow__/themes/extendedThemes/sproutTheme/dark/theme.js +9 -0
  16. package/__flow__/themes/extendedThemes/sproutTheme/light/theme.js +9 -0
  17. package/__flow__/themes/light/theme.js +0 -5
  18. package/__flow__/types/theme.flow.js +2 -2
  19. package/__flow__/utils/responsiveProps/index.test.js +2 -10
  20. package/__flow__/utils/useInteractiveColor.js +32 -0
  21. package/commonjs/Button/index.js +70 -0
  22. package/commonjs/Button/styles.js +66 -0
  23. package/commonjs/Input/index.js +3 -1
  24. package/commonjs/Token/styles.js +9 -7
  25. package/commonjs/index.js +6 -1
  26. package/commonjs/themes/dark/theme.js +0 -5
  27. package/commonjs/themes/extendedThemes/sproutTheme/dark/theme.js +11 -2
  28. package/commonjs/themes/extendedThemes/sproutTheme/light/theme.js +11 -2
  29. package/commonjs/themes/light/theme.js +0 -5
  30. package/commonjs/utils/useInteractiveColor.js +33 -0
  31. package/dist/themes/dark/theme.scss +0 -3
  32. package/dist/themes/extendedThemes/sproutTheme/dark/theme.scss +14 -3
  33. package/dist/themes/extendedThemes/sproutTheme/light/theme.scss +14 -3
  34. package/dist/themes/light/theme.scss +0 -3
  35. package/lib/Button/index.js +57 -0
  36. package/lib/Button/styles.js +48 -0
  37. package/lib/Input/index.js +2 -1
  38. package/lib/Token/styles.js +8 -7
  39. package/lib/index.js +1 -0
  40. package/lib/themes/dark/theme.js +0 -4
  41. package/lib/themes/extendedThemes/sproutTheme/dark/theme.js +9 -1
  42. package/lib/themes/extendedThemes/sproutTheme/light/theme.js +9 -1
  43. package/lib/themes/light/theme.js +0 -4
  44. package/lib/types/theme.flow.js +1 -1
  45. package/lib/utils/useInteractiveColor.js +27 -0
  46. package/package.json +1 -6
  47. package/__flow__/themes/utils/interact.js +0 -12
  48. package/commonjs/themes/utils/interact.js +0 -19
  49. package/lib/themes/utils/interact.js +0 -13
package/CHANGELOG.md CHANGED
@@ -1,5 +1,38 @@
1
1
  # Change Log
2
2
 
3
+ ## 12.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - 54639f5: Moved `theme.util.interact()` to a hook called `useInteractiveColor()`
8
+
9
+ - `theme.util.interact()` will no longer be available on the theme object and is moved to a hook called `useInteractiveColor()`
10
+ - To import the hook, use `import { useInteractiveColor } from '@sproutsocial/racine'`
11
+ - `useInteractiveColor()` accepts a theme color option and returns a lighten or darken version of that color depending on the theme mode currently in use('light' or 'dark')
12
+ - `useInteractiveColor()` can only be utilized within a theme context.
13
+
14
+ example:
15
+
16
+ ```jsx
17
+ import { useInteractiveColor } from '@sproutsocial/racine'
18
+
19
+ ....
20
+ &:hover,
21
+ &:active {
22
+ color: ${({theme}) => useInteract(theme.colors.icon.base)};
23
+ }
24
+ ```
25
+
26
+ ## 11.9.0
27
+
28
+ ### Minor Changes
29
+
30
+ - 6c3e703: Extend the sprout theme to add colors for trend arrows
31
+
32
+ ### Patch Changes
33
+
34
+ - 1c10a77: Fix args
35
+
3
36
  ## 11.8.0
4
37
 
5
38
  ### Minor Changes
@@ -1,36 +1,37 @@
1
- import React from "react";
1
+ // @flow
2
+ import * as React from "react";
2
3
  import Container from "./styles";
3
4
 
4
- export interface ButtonType {
5
+ export type TypeProps = {
5
6
  /** If the button is being used as an anchor, this prop will cause the link to open in a new tab. */
6
- external?: boolean;
7
- size?: "large" | "default";
7
+ external?: boolean,
8
+ size?: "large" | "default",
8
9
  /** What the button looks like. "default" is deprecated in favor of "unstyled" */
9
- appearance:
10
+ appearance?:
10
11
  | "primary"
11
12
  | "secondary"
12
13
  | "pill"
13
14
  | "destructive"
14
15
  | "default"
15
16
  | "unstyled"
16
- | "placeholder";
17
+ | "placeholder",
17
18
  /** Set the button to display in its active state */
18
- active?: boolean;
19
+ active?: boolean,
19
20
  /** Disables user action and applies a disabled style on the button */
20
- disabled?: boolean;
21
- children: React.ReactNode;
21
+ disabled?: boolean,
22
+ children: React.Node,
22
23
  /** Setting this prop will cause the component to be rendered as an anchor element instead of a button element */
23
- href?: string;
24
+ href?: string,
24
25
  /** Used to get a reference to the underlying button */
25
- innerRef?: React.Ref<"button">;
26
+ innerRef?: React.Ref<"button">,
26
27
  /** Action to perform when the button is clicked */
27
- onClick?: () => void;
28
- title?: string;
29
- qa?: Object;
30
- as?: any;
28
+ onClick?: (e: SyntheticEvent<HTMLButtonElement>) => any,
29
+ title?: string,
30
+ qa?: Object,
31
+ as?: any,
31
32
  /** Label used to describe the button if the button does not have text within it */
32
- ariaLabel?: string;
33
- }
33
+ ariaLabel?: string,
34
+ };
34
35
 
35
36
  const Button = ({
36
37
  href,
@@ -46,9 +47,8 @@ const Button = ({
46
47
  qa = {},
47
48
  as,
48
49
  ariaLabel,
49
-
50
50
  ...rest
51
- }: ButtonType) => {
51
+ }: TypeProps) => {
52
52
  if (!href && external) {
53
53
  console.warn(
54
54
  "Warning: external prop cannot be set without a href declaration"
@@ -60,7 +60,6 @@ const Button = ({
60
60
 
61
61
  return (
62
62
  <Container
63
- className="container"
64
63
  title={title}
65
64
  active={active}
66
65
  href={href}
@@ -85,4 +84,6 @@ const Button = ({
85
84
  );
86
85
  };
87
86
 
87
+ Button.displayName = "Button";
88
+
88
89
  export default Button;
@@ -6,7 +6,7 @@ import Icon from "../Icon/styles";
6
6
 
7
7
  import type { TypeTheme } from "../types/theme.flow";
8
8
 
9
- const Container = styled.button`
9
+ const Container: StyledComponent<any, TypeTheme, *> = styled.button`
10
10
  display: inline-block;
11
11
  box-sizing: border-box;
12
12
  text-align: center;
@@ -182,90 +182,90 @@ const getIcon = (type, color) => {
182
182
 
183
183
  // eslint-disable-next-line prettier/prettier
184
184
  export const CheckboxContainer: StyledComponent<any, TypeTheme, *> = styled.span(
185
- (props) => css`
186
- display: inline-flex;
187
- align-items: center;
188
- box-sizing: border-box;
189
- position: relative;
190
- transition: all ${props.theme.duration.fast} ${props.theme.easing.ease_in};
191
-
192
- @supports (-webkit-appearance: none) {
193
- &:before {
194
- /* stylelint-disable */
195
- content: url("data:image/svg+xml;utf8,${getIcon(
196
- props.indeterminate ? "indeterminate" : "check",
197
-
198
- props.checked
199
- ? props.theme.colors.form.background.base
200
- : props.theme.colors.form.border.base
201
- )}");
202
- opacity: ${props.checked ? 1 : 0};
203
- position: absolute;
204
- width: ${props.theme.space[400]};
205
- height: ${props.theme.space[400]};
206
- text-align: center;
207
- transform: translateY(1px);
208
- line-height: 1;
209
- margin: auto;
210
- pointer-events: none;
211
- transition: ${props.theme.duration.fast}
212
- ${props.theme.easing.ease_inout};
213
- }
214
-
215
- &:hover:before {
216
- opacity: ${props.disabled && !props.checked ? 0 : 1};
217
- }
218
-
219
- ${props.disabled &&
220
- css`
221
- opacity: 0.4;
222
- `}
223
-
224
- input[type='checkbox'] {
225
- box-sizing: border-box;
226
- appearance: none;
227
- margin: 0;
228
- padding: 0;
229
- width: ${props.theme.space[400]};
230
- height: ${props.theme.space[400]};
231
- border: 1px solid ${props.theme.colors.form.border.base};
232
- border-radius: 4px;
233
- background-color: ${props.theme.colors.form.background.base};
234
- transition: all ${props.theme.duration.fast}
235
- ${props.theme.easing.ease_in};
236
- cursor: ${props.disabled ? "not-allowed" : "pointer"};
237
- flex-shrink: 0;
238
-
239
- &:not(:checked) {
240
- ${!props.indeterminate &&
241
- css`
242
- border-color: ${props.theme.colors
243
- .neutral[300]} !important; /* We don't want the focus ring to remove the border */
244
- background-color: ${props.theme.colors.form.background.base};
245
- `}
185
+ (props) => css`
186
+ display: inline-flex;
187
+ align-items: center;
188
+ box-sizing: border-box;
189
+ position: relative;
190
+ transition: all ${props.theme.duration.fast} ${props.theme.easing.ease_in};
191
+
192
+ @supports (-webkit-appearance: none) {
193
+ &:before {
194
+ /* stylelint-disable */
195
+ content: url("data:image/svg+xml;utf8,${getIcon(
196
+ props.indeterminate ? "indeterminate" : "check",
197
+
198
+ props.checked
199
+ ? props.theme.colors.form.background.base
200
+ : props.theme.colors.form.border.base
201
+ )}");
202
+ opacity: ${props.checked ? 1 : 0};
203
+ position: absolute;
204
+ width: ${props.theme.space[400]};
205
+ height: ${props.theme.space[400]};
206
+ text-align: center;
207
+ transform: translateY(1px);
208
+ line-height: 1;
209
+ margin: auto;
210
+ pointer-events: none;
211
+ transition: ${props.theme.duration.fast}
212
+ ${props.theme.easing.ease_inout};
246
213
  }
247
214
 
248
- &:checked {
249
- border-color: ${props.theme.colors.form.border.selected};
250
- background-color: ${props.theme.colors.form.background.selected};
215
+ &:hover:before {
216
+ opacity: ${props.disabled && !props.checked ? 0 : 1};
251
217
  }
252
218
 
253
- ${props.indeterminate &&
254
- props.checked &&
219
+ ${props.disabled &&
255
220
  css`
256
- border-color: ${props.theme.colors.form.border.selected} !important;
257
- background-color: ${props.theme.colors.form.background
258
- .selected} !important;
221
+ opacity: 0.4;
259
222
  `}
260
223
 
261
- &:focus {
262
- ${focusRing}
224
+ input[type='checkbox'] {
225
+ box-sizing: border-box;
226
+ appearance: none;
227
+ margin: 0;
228
+ padding: 0;
229
+ width: ${props.theme.space[400]};
230
+ height: ${props.theme.space[400]};
231
+ border: 1px solid ${props.theme.colors.form.border.base};
232
+ border-radius: 4px;
233
+ background-color: ${props.theme.colors.form.background.base};
234
+ transition: all ${props.theme.duration.fast}
235
+ ${props.theme.easing.ease_in};
236
+ cursor: ${props.disabled ? "not-allowed" : "pointer"};
237
+ flex-shrink: 0;
238
+
239
+ &:not(:checked) {
240
+ ${!props.indeterminate &&
241
+ css`
242
+ border-color: ${props.theme.colors
243
+ .neutral[300]} !important; /* We don't want the focus ring to remove the border */
244
+ background-color: ${props.theme.colors.form.background.base};
245
+ `}
246
+ }
247
+
248
+ &:checked {
249
+ border-color: ${props.theme.colors.form.border.selected};
250
+ background-color: ${props.theme.colors.form.background.selected};
251
+ }
252
+
253
+ ${props.indeterminate &&
254
+ props.checked &&
255
+ css`
256
+ border-color: ${props.theme.colors.form.border.selected} !important;
257
+ background-color: ${props.theme.colors.form.background
258
+ .selected} !important;
259
+ `}
260
+
261
+ &:focus {
262
+ ${focusRing}
263
+ }
263
264
  }
264
265
  }
265
- }
266
266
 
267
- ${COMMON}
268
- `
269
- );
267
+ ${COMMON}
268
+ `
269
+ );
270
270
 
271
271
  export default Container;
@@ -73,9 +73,8 @@ const Trigger = ({ children, ...rest }) => {
73
73
  };
74
74
 
75
75
  const Panel = ({ children, ...rest }) => {
76
- const { isOpen, id, offset, collapsedHeight, openHeight } = useContext(
77
- CollapsibleContext
78
- );
76
+ const { isOpen, id, offset, collapsedHeight, openHeight } =
77
+ useContext(CollapsibleContext);
79
78
  const ref = useRef();
80
79
  const measurement = useMeasure(ref);
81
80
  const [isHidden, setIsHidden] = useState(undefined);
@@ -80,16 +80,8 @@ export default class Image extends React.Component<TypeProps, TypeState> {
80
80
  };
81
81
 
82
82
  render() {
83
- const {
84
- alt,
85
- title,
86
- onClick,
87
- onError,
88
- onLoad,
89
- src,
90
- qa,
91
- ...rest
92
- } = this.props;
83
+ const { alt, title, onClick, onError, onLoad, src, qa, ...rest } =
84
+ this.props;
93
85
 
94
86
  return (
95
87
  <ImageContainer
@@ -7,6 +7,7 @@ import styled from "styled-components";
7
7
  import type { StyledComponent } from "styled-components";
8
8
  import type { TypeTheme } from "../types/theme.flow";
9
9
  import { mergeRefs } from "../utils";
10
+ import { useInteractiveColor } from "../utils/useInteractiveColor";
10
11
 
11
12
  type TypeProps = {
12
13
  /** ID of the form element, should match the "for" value of the associated label */
@@ -90,8 +91,7 @@ const InputContext = React.createContext<TypeInputContext>({});
90
91
  const StyledButton: StyledComponent<any, TypeTheme, *> = styled(Button)`
91
92
  &:hover,
92
93
  &:active {
93
- color: ${(props) =>
94
- props.theme.utils.interact(props.theme.colors.icon.base)};
94
+ color: ${(props) => useInteractiveColor(props.theme.colors.icon.base)};
95
95
  }
96
96
  `;
97
97
 
@@ -17,9 +17,8 @@ type TypeSegmentedControlContext = {
17
17
  onChange: (e: SyntheticInputEvent<HTMLInputElement>) => void,
18
18
  };
19
19
 
20
- const SegmentedControlContext = React.createContext<?TypeSegmentedControlContext>(
21
- null
22
- );
20
+ const SegmentedControlContext =
21
+ React.createContext<?TypeSegmentedControlContext>(null);
23
22
 
24
23
  type TypeSegmentedControlItemProps = {
25
24
  /** The value of this item. Should be unique among sibling items. */
@@ -22,15 +22,8 @@ export type TypeTableCell = {
22
22
  */
23
23
  export default class TableCell extends React.Component<TypeTableCell> {
24
24
  render() {
25
- const {
26
- id,
27
- content,
28
- colSpan,
29
- width,
30
- align,
31
- children,
32
- ...rest
33
- } = this.props;
25
+ const { id, content, colSpan, width, align, children, ...rest } =
26
+ this.props;
34
27
 
35
28
  return (
36
29
  <Container
@@ -32,15 +32,8 @@ export default class ToggleHint extends React.Component<TypeProps> {
32
32
  };
33
33
 
34
34
  render() {
35
- const {
36
- icon,
37
- isOpen,
38
- openString,
39
- closeString,
40
- qa,
41
- className,
42
- ...rest
43
- } = this.props;
35
+ const { icon, isOpen, openString, closeString, qa, className, ...rest } =
36
+ this.props;
44
37
 
45
38
  return (
46
39
  <Container
@@ -2,6 +2,7 @@
2
2
  import styled, { css, type StyledComponent } from "styled-components";
3
3
  import { COMMON } from "../utils/system-props";
4
4
  import { focusRing } from "../utils/mixins";
5
+ import { useInteractiveColor } from "../utils/useInteractiveColor";
5
6
 
6
7
  import type { TypeTheme } from "../types/theme.flow";
7
8
 
@@ -29,30 +30,30 @@ const Container: StyledComponent<any, TypeTheme, *> = styled.button`
29
30
  ${focusRing}
30
31
  }
31
32
 
32
- ${({ theme, palette }) =>
33
- palette === "blue" &&
33
+ ${({ closeable, theme }) =>
34
+ closeable &&
34
35
  css`
35
- color: ${theme.colors.text.body};
36
- background: ${theme.colors.container.background.decorative.blue};
37
- border: 1px solid ${theme.colors.container.border.decorative.blue};
36
+ cursor: pointer;
38
37
  &:hover,
39
38
  &:active {
40
- cursor: pointer;
41
39
  box-shadow: ${theme.shadows.low};
42
40
  border: 1px solid
43
- ${theme.utils.interact(theme.colors.container.border.decorative.blue)};
41
+ ${useInteractiveColor(theme.colors.container.border.base)};
44
42
  }
45
43
  `}
46
44
 
47
- ${({ closeable, theme }) =>
48
- closeable &&
45
+ ${({ theme, palette }) =>
46
+ palette === "blue" &&
49
47
  css`
50
- cursor: pointer;
48
+ color: ${theme.colors.text.body};
49
+ background: ${theme.colors.container.background.decorative.blue};
50
+ border: 1px solid ${theme.colors.container.border.decorative.blue};
51
51
  &:hover,
52
52
  &:active {
53
+ cursor: pointer;
53
54
  box-shadow: ${theme.shadows.low};
54
55
  border: 1px solid
55
- ${theme.utils.interact(theme.colors.container.border.base)};
56
+ ${useInteractiveColor(theme.colors.container.border.decorative.blue)};
56
57
  }
57
58
  `}
58
59
 
@@ -77,7 +78,7 @@ const Container: StyledComponent<any, TypeTheme, *> = styled.button`
77
78
  &:hover {
78
79
  box-shadow: ${theme.shadows.low};
79
80
  border: 1px solid
80
- ${theme.utils.interact(theme.colors.container.border.error)};
81
+ ${useInteractiveColor(theme.colors.container.border.error)};
81
82
  }
82
83
  `}
83
84
 
package/__flow__/index.js CHANGED
@@ -4,6 +4,7 @@ export type { TypeTheme, TypeSproutTheme } from "./types/theme.flow";
4
4
  export * from "./systemProps";
5
5
  export { visuallyHidden, focusRing, disabled } from "./utils/mixins";
6
6
  export { useSelect, useMultiselect, useTextContent } from "./utils/hooks";
7
+ export { useInteractiveColor } from "./utils/useInteractiveColor";
7
8
  export { default as theme } from "./themes/light/theme";
8
9
  export { default as darkTheme } from "./themes/dark/theme";
9
10
  export {
@@ -14,7 +14,8 @@ import type {
14
14
 
15
15
  // https://styled-system.com/table#color
16
16
 
17
- type TypeBackgroundColorSystemProp = TypeResponsiveBaseSystemProp<BackgroundColorProperty>;
17
+ type TypeBackgroundColorSystemProp =
18
+ TypeResponsiveBaseSystemProp<BackgroundColorProperty>;
18
19
  export type TypeColorSystemProps = $ReadOnly<{|
19
20
  backgroundColor?: TypeBackgroundColorSystemProp,
20
21
  bg?: TypeBackgroundColorSystemProp,
@@ -15,8 +15,6 @@ import {
15
15
  } from "./decorative-palettes";
16
16
  import { transparentize } from "polished";
17
17
 
18
- import interact from "../utils/interact";
19
-
20
18
  const MODE = "dark";
21
19
 
22
20
  export const shadows = {
@@ -235,9 +233,6 @@ const colors = {
235
233
 
236
234
  const darkTheme = {
237
235
  ...lightTheme,
238
- utils: {
239
- interact: interact(MODE),
240
- },
241
236
  colors,
242
237
  shadows,
243
238
  mode: MODE,
@@ -42,12 +42,21 @@ export const datePicker = {
42
42
  },
43
43
  };
44
44
 
45
+ export const analytics = {
46
+ trend: {
47
+ positive: baseDarkTheme.colors.teal[500],
48
+ neutral: baseDarkTheme.colors.neutral[100],
49
+ negative: baseDarkTheme.colors.neutral[100],
50
+ },
51
+ };
52
+
45
53
  const darkTheme: TypeSproutTheme = {
46
54
  ...baseDarkTheme,
47
55
  colors: {
48
56
  ...baseDarkTheme.colors,
49
57
  navigation,
50
58
  datePicker,
59
+ analytics,
51
60
  },
52
61
  };
53
62
 
@@ -42,12 +42,21 @@ export const datePicker = {
42
42
  },
43
43
  };
44
44
 
45
+ export const analytics = {
46
+ trend: {
47
+ positive: baseLightTheme.colors.teal[800],
48
+ neutral: baseLightTheme.colors.neutral[800],
49
+ negative: baseLightTheme.colors.neutral[800],
50
+ },
51
+ };
52
+
45
53
  const lightTheme: TypeSproutTheme = {
46
54
  ...baseLightTheme,
47
55
  colors: {
48
56
  ...baseLightTheme.colors,
49
57
  navigation,
50
58
  datePicker,
59
+ analytics,
51
60
  },
52
61
  };
53
62
 
@@ -20,8 +20,6 @@ import MOTION from "@sproutsocial/seeds-motion";
20
20
  import BORDER from "@sproutsocial/seeds-border";
21
21
  import { transparentize } from "polished";
22
22
 
23
- import interact from "../utils/interact";
24
-
25
23
  export const breakpoints = ["900px", "1200px", "1500px", "1800px"];
26
24
 
27
25
  const MODE = "light";
@@ -350,9 +348,6 @@ export const duration = {
350
348
  };
351
349
 
352
350
  const theme = {
353
- utils: {
354
- interact: interact(MODE),
355
- },
356
351
  breakpoints,
357
352
  colors,
358
353
  typography: {
@@ -16,9 +16,9 @@ import type { TypeFontFamilyString } from "../themes/light/theme";
16
16
  import {
17
17
  datePicker,
18
18
  navigation,
19
+ analytics,
19
20
  } from "../themes/extendedThemes/sproutTheme/light/theme";
20
21
 
21
- export type TypeThemeUtils = {| interact: (color: string) => string |};
22
22
  export type TypeThemeMode = "light" | "dark";
23
23
  export type TypeBreakpoint = typeof breakpoints;
24
24
  export type TypeTypography = typeof typography;
@@ -35,7 +35,6 @@ export type TypeDuration = typeof duration;
35
35
 
36
36
  export type TypeTheme = {
37
37
  mode: TypeThemeMode,
38
- utils: TypeThemeUtils,
39
38
  breakpoints: TypeBreakpoint,
40
39
  colors: TypeColor,
41
40
  typography: TypeTypography,
@@ -57,5 +56,6 @@ export type TypeSproutTheme = {
57
56
  ...$Exact<TypeColor>,
58
57
  navigation: typeof navigation,
59
58
  datePicker: typeof datePicker,
59
+ analytics: typeof analytics,
60
60
  |},
61
61
  };
@@ -19,21 +19,13 @@ describe("normalizeResponsiveProp", () => {
19
19
 
20
20
  it("should handle arrays with 4 values", () => {
21
21
  expect(normalizeResponsiveProp([0, 1, 2, 3])).toMatchObject([
22
- 0,
23
- 1,
24
- 2,
25
- 3,
26
- 3,
22
+ 0, 1, 2, 3, 3,
27
23
  ]);
28
24
  });
29
25
 
30
26
  it("should handle arrays with 5 values", () => {
31
27
  expect(normalizeResponsiveProp([0, 1, 2, 3, 4])).toMatchObject([
32
- 0,
33
- 1,
34
- 2,
35
- 3,
36
- 4,
28
+ 0, 1, 2, 3, 4,
37
29
  ]);
38
30
  });
39
31
  });
@@ -0,0 +1,32 @@
1
+ //@flow strict-local
2
+ import { darken, lighten } from "polished";
3
+ import { useTheme } from "styled-components";
4
+ import type { TypeColors } from "../types/theme.colors.flow.js";
5
+
6
+ /**
7
+ * The useInteractiveColor hook has context of theme mode (light or dark)
8
+ * and can be used to lighten or darken a color dynamically
9
+ *
10
+ * note: colors are limited to our theme colors
11
+ */
12
+ const useInteractiveColor = (themeColor: TypeColors): string => {
13
+ // Throw error if used outside of a ThemeProvider (styled-components)
14
+ if (!useTheme()) {
15
+ throw new Error(
16
+ "useInteractiveColor() must be used within a Styled Components ThemeProvider"
17
+ );
18
+ }
19
+
20
+ // Get the current theme mode ie. 'light' or 'dark'
21
+ const themeMode = useTheme().mode;
22
+
23
+ // If the theme mode is dark, return a lightened version of the themeValue
24
+ if (themeMode === "dark") {
25
+ return lighten(0.2, themeColor);
26
+ } else {
27
+ // If the theme mode is light, return a darkened version of the themeValue
28
+ return darken(0.2, themeColor);
29
+ }
30
+ };
31
+
32
+ export { useInteractiveColor };