@hero-design/rn 8.120.2 → 8.121.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 (45) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/es/index.js +281 -32
  3. package/jest.config.js +1 -1
  4. package/lib/index.js +280 -30
  5. package/package.json +5 -1
  6. package/rollup.config.mjs +2 -0
  7. package/src/components/Icon/AnimatedIcon.tsx +7 -40
  8. package/src/components/Icon/GradientIcon/index.tsx +71 -0
  9. package/src/components/Icon/SpinWrapper.tsx +39 -0
  10. package/src/components/Icon/index.tsx +22 -1
  11. package/src/components/Toolbar/StyledToolbar.tsx +2 -2
  12. package/src/components/Typography/Body/StyledBody.tsx +2 -2
  13. package/src/components/Typography/Body/index.tsx +20 -2
  14. package/src/components/Typography/Caption/StyledCaption.tsx +2 -2
  15. package/src/components/Typography/Caption/index.tsx +20 -2
  16. package/src/components/Typography/GradientText/index.tsx +85 -0
  17. package/src/components/Typography/Label/StyledLabel.tsx +2 -2
  18. package/src/components/Typography/Label/index.tsx +20 -2
  19. package/src/components/Typography/Title/StyledTitle.tsx +2 -2
  20. package/src/components/Typography/Title/index.tsx +32 -13
  21. package/src/components/Typography/types.ts +3 -1
  22. package/src/components/Typography/utils.ts +31 -0
  23. package/src/theme/global/colors/gradients.ts +78 -0
  24. package/src/theme/global/colors/types.ts +22 -0
  25. package/src/theme/global/index.ts +5 -2
  26. package/testUtils/setup.tsx +34 -0
  27. package/types/components/Icon/GradientIcon/index.d.ts +12 -0
  28. package/types/components/Icon/SpinWrapper.d.ts +9 -0
  29. package/types/components/Icon/index.d.ts +1 -1
  30. package/types/components/TextInput/StyledTextInput.d.ts +1 -1
  31. package/types/components/Toolbar/StyledToolbar.d.ts +4 -4
  32. package/types/components/Typography/Body/StyledBody.d.ts +2 -2
  33. package/types/components/Typography/Body/index.d.ts +1 -1
  34. package/types/components/Typography/Caption/StyledCaption.d.ts +2 -2
  35. package/types/components/Typography/Caption/index.d.ts +1 -1
  36. package/types/components/Typography/GradientText/index.d.ts +7 -0
  37. package/types/components/Typography/Label/StyledLabel.d.ts +2 -2
  38. package/types/components/Typography/Label/index.d.ts +1 -1
  39. package/types/components/Typography/Title/StyledTitle.d.ts +2 -2
  40. package/types/components/Typography/Title/index.d.ts +1 -1
  41. package/types/components/Typography/types.d.ts +2 -1
  42. package/types/components/Typography/utils.d.ts +2 -0
  43. package/types/theme/global/colors/gradients.d.ts +3 -0
  44. package/types/theme/global/colors/types.d.ts +21 -0
  45. package/types/theme/global/index.d.ts +3 -2
@@ -3,6 +3,8 @@ import type { AccessibilityProps, StyleProp, TextStyle } from 'react-native';
3
3
  import IconList from './IconList';
4
4
  import HeroIcon from './HeroIcon';
5
5
  import AnimatedIcon from './AnimatedIcon';
6
+ import GradientIcon from './GradientIcon';
7
+ import SpinWrapper from './SpinWrapper';
6
8
  import { useDeprecation } from '../../utils/hooks';
7
9
 
8
10
  export type IconName = typeof IconList[number];
@@ -28,7 +30,8 @@ export interface IconProps extends AccessibilityProps {
28
30
  | 'disabled-text'
29
31
  | 'text-inverted'
30
32
  | 'muted'
31
- | 'inactive';
33
+ | 'inactive'
34
+ | 'ai';
32
35
  /**
33
36
  * Size of the Icon.
34
37
  */
@@ -87,6 +90,24 @@ const Icon = ({
87
90
  accessibilityActions,
88
91
  };
89
92
 
93
+ if (intent === 'ai') {
94
+ const gradientIcon = (
95
+ <GradientIcon
96
+ name={icon}
97
+ themeSize={size}
98
+ testID={testID}
99
+ style={spin ? undefined : style}
100
+ {...accessibilityProps}
101
+ />
102
+ );
103
+
104
+ if (spin) {
105
+ return <SpinWrapper style={style}>{gradientIcon}</SpinWrapper>;
106
+ }
107
+
108
+ return gradientIcon;
109
+ }
110
+
90
111
  return spin ? (
91
112
  <AnimatedIcon
92
113
  name={icon}
@@ -2,7 +2,7 @@ import styled from '@emotion/native';
2
2
  import { TextInput, TouchableOpacity, View } from 'react-native';
3
3
  import type { ViewProps } from 'react-native';
4
4
  import Typography from '../Typography';
5
- import type { BodyProps } from '../Typography/Body';
5
+ import type { TypographyColorIntent } from '../Typography/types';
6
6
 
7
7
  export type ToolbarMessageState =
8
8
  | 'default'
@@ -63,7 +63,7 @@ const IconButtonLabel = styled(Typography.Body)(({ theme }) => ({
63
63
  }));
64
64
 
65
65
  const StyledLabel = styled(Typography.Body)<{
66
- intent: Exclude<BodyProps['intent'], undefined>;
66
+ intent: TypographyColorIntent;
67
67
  }>(({ theme, intent }) => ({
68
68
  color:
69
69
  intent === 'secondary'
@@ -1,6 +1,6 @@
1
1
  import styled from '@emotion/native';
2
2
  import { Text } from 'react-native';
3
- import type { TypographyIntent } from '../types';
3
+ import type { TypographyColorIntent } from '../types';
4
4
 
5
5
  type ThemeVariant = 'small' | 'small-bold' | 'regular' | 'regular-bold';
6
6
  type FontWeights = 'regular' | 'semiBold';
@@ -20,7 +20,7 @@ const FONTSIZE_MAP: Record<ThemeVariant, FontSizes> = {
20
20
  'small-bold': 'small',
21
21
  } as const;
22
22
  const StyledBody = styled(Text)<{
23
- themeIntent: TypographyIntent;
23
+ themeIntent: TypographyColorIntent;
24
24
  themeTypeface: 'neutral' | 'playful';
25
25
  themeVariant: ThemeVariant;
26
26
  themeIsItalic?: boolean;
@@ -6,7 +6,9 @@ import type {
6
6
  TextStyle,
7
7
  } from 'react-native';
8
8
  import type { TypographyIntent } from '../types';
9
+ import { pickAccessibilityProps } from '../utils';
9
10
  import { StyledBody } from './StyledBody';
11
+ import GradientText from '../GradientText';
10
12
 
11
13
  export interface BodyProps extends NativeTextProps {
12
14
  /**
@@ -48,20 +50,36 @@ const Body = ({
48
50
  typeface = 'neutral',
49
51
  variant = 'regular',
50
52
  fontStyle = 'normal',
53
+ style,
54
+ testID,
51
55
  ...nativeProps
52
56
  }: BodyProps) => {
53
- return (
57
+ const isAi = intent === 'ai';
58
+
59
+ const styledText = (
54
60
  <StyledBody
55
61
  {...nativeProps}
56
62
  themeTypeface={typeface}
57
- themeIntent={intent}
63
+ themeIntent={isAi ? 'body' : intent}
58
64
  themeVariant={variant}
59
65
  themeIsItalic={fontStyle === 'italic'}
60
66
  allowFontScaling={allowFontScaling}
67
+ style={style}
68
+ testID={testID}
61
69
  >
62
70
  {children}
63
71
  </StyledBody>
64
72
  );
73
+
74
+ if (isAi) {
75
+ return (
76
+ <GradientText {...pickAccessibilityProps(nativeProps)}>
77
+ {styledText}
78
+ </GradientText>
79
+ );
80
+ }
81
+
82
+ return styledText;
65
83
  };
66
84
 
67
85
  export default Body;
@@ -1,11 +1,11 @@
1
1
  import { Text } from 'react-native';
2
2
  import styled from '@emotion/native';
3
- import type { TypographyIntent } from '../types';
3
+ import type { TypographyColorIntent } from '../types';
4
4
  import { FONTWEIGHT_MAP } from '../types';
5
5
 
6
6
  const StyledCaption = styled(Text)<{
7
7
  themeFontWeight: 'regular' | 'semi-bold';
8
- themeIntent: TypographyIntent;
8
+ themeIntent: TypographyColorIntent;
9
9
  themeIsItalic?: boolean;
10
10
  }>(({ themeFontWeight, themeIntent, theme, themeIsItalic }) => {
11
11
  const baseFontWeight = FONTWEIGHT_MAP[themeFontWeight];
@@ -7,6 +7,8 @@ import type {
7
7
  } from 'react-native';
8
8
  import { StyledCaption } from './StyledCaption';
9
9
  import type { TypographyIntent } from '../types';
10
+ import { pickAccessibilityProps } from '../utils';
11
+ import GradientText from '../GradientText';
10
12
 
11
13
  export interface CaptionProps extends NativeTextProps {
12
14
  /**
@@ -41,19 +43,35 @@ const Caption = ({
41
43
  intent = 'body',
42
44
  allowFontScaling = false,
43
45
  fontStyle = 'normal',
46
+ style,
47
+ testID,
44
48
  ...nativeProps
45
49
  }: CaptionProps) => {
46
- return (
50
+ const isAi = intent === 'ai';
51
+
52
+ const styledText = (
47
53
  <StyledCaption
48
54
  {...nativeProps}
49
55
  themeFontWeight={fontWeight}
50
- themeIntent={intent}
56
+ themeIntent={isAi ? 'body' : intent}
51
57
  themeIsItalic={fontStyle === 'italic'}
52
58
  allowFontScaling={allowFontScaling}
59
+ style={style}
60
+ testID={testID}
53
61
  >
54
62
  {children}
55
63
  </StyledCaption>
56
64
  );
65
+
66
+ if (isAi) {
67
+ return (
68
+ <GradientText {...pickAccessibilityProps(nativeProps)}>
69
+ {styledText}
70
+ </GradientText>
71
+ );
72
+ }
73
+
74
+ return styledText;
57
75
  };
58
76
 
59
77
  export default Caption;
@@ -0,0 +1,85 @@
1
+ import MaskedView from '@react-native-masked-view/masked-view';
2
+ import { LinearGradient } from 'expo-linear-gradient';
3
+ import React, { useCallback, useState } from 'react';
4
+ import type { AccessibilityProps, LayoutChangeEvent } from 'react-native';
5
+ import { View } from 'react-native';
6
+
7
+ import { useTheme } from '../../../theme';
8
+
9
+ interface GradientTextProps extends AccessibilityProps {
10
+ children: React.ReactNode;
11
+ }
12
+
13
+ const GradientText = ({
14
+ children,
15
+ ...accessibilityProps
16
+ }: GradientTextProps) => {
17
+ const theme = useTheme();
18
+ const gradient = theme.colors.gradients.aiDiagonal;
19
+ const [size, setSize] = useState<{ width: number; height: number } | null>(
20
+ null
21
+ );
22
+
23
+ const onLayout = useCallback((event: LayoutChangeEvent) => {
24
+ const { width, height } = event.nativeEvent.layout;
25
+ setSize((prevSize) => {
26
+ if (prevSize && prevSize.width === width && prevSize.height === height) {
27
+ return prevSize;
28
+ }
29
+ return { width, height };
30
+ });
31
+ }, []);
32
+
33
+ return (
34
+ <View {...accessibilityProps}>
35
+ {/*
36
+ * MaskedView is entirely hidden from the accessibility tree.
37
+ * It is purely visual: the mask defines the text clip shape and
38
+ * the content shows either a gradient or a visible fallback.
39
+ * Screen readers must not traverse into either branch here.
40
+ */}
41
+ <MaskedView
42
+ style={{ alignSelf: 'stretch' }}
43
+ accessibilityElementsHidden
44
+ importantForAccessibility="no-hide-descendants"
45
+ maskElement={
46
+ <View
47
+ onLayout={onLayout}
48
+ style={{ backgroundColor: 'transparent' }}
49
+ testID="gradient-text-mask"
50
+ >
51
+ {children}
52
+ </View>
53
+ }
54
+ >
55
+ {size ? (
56
+ <LinearGradient
57
+ start={gradient.start}
58
+ end={gradient.end}
59
+ colors={gradient.colors}
60
+ locations={gradient.locations}
61
+ style={{ width: size.width, height: size.height }}
62
+ />
63
+ ) : (
64
+ // Render children as fallback until layout is measured, so text
65
+ // is visible immediately rather than blank on the first frame.
66
+ children
67
+ )}
68
+ </MaskedView>
69
+ {/*
70
+ * Visually hidden but accessible: the single Text node that
71
+ * screen readers announce. Kept outside MaskedView so it is
72
+ * always present and never duplicated.
73
+ */}
74
+ <View
75
+ style={{ position: 'absolute', opacity: 0 }}
76
+ importantForAccessibility="yes"
77
+ accessibilityElementsHidden={false}
78
+ >
79
+ {children}
80
+ </View>
81
+ </View>
82
+ );
83
+ };
84
+
85
+ export default GradientText;
@@ -1,9 +1,9 @@
1
1
  import styled from '@emotion/native';
2
2
  import { Text } from 'react-native';
3
- import type { TypographyIntent } from '../types';
3
+ import type { TypographyColorIntent } from '../types';
4
4
 
5
5
  const StyledLabel = styled(Text)<{
6
- themeIntent: TypographyIntent;
6
+ themeIntent: TypographyColorIntent;
7
7
  themeIsItalic?: boolean;
8
8
  }>(({ themeIntent, theme, themeIsItalic }) => {
9
9
  // For Label, we assume 'regular' weight for base font family
@@ -7,6 +7,8 @@ import type {
7
7
  } from 'react-native';
8
8
  import { StyledLabel } from './StyledLabel';
9
9
  import type { TypographyIntent } from '../types';
10
+ import { pickAccessibilityProps } from '../utils';
11
+ import GradientText from '../GradientText';
10
12
 
11
13
  export interface LabelProps extends NativeTextProps {
12
14
  /**
@@ -36,18 +38,34 @@ const Label = ({
36
38
  intent = 'body',
37
39
  allowFontScaling = false,
38
40
  fontStyle = 'normal',
41
+ style,
42
+ testID,
39
43
  ...nativeProps
40
44
  }: LabelProps) => {
41
- return (
45
+ const isAi = intent === 'ai';
46
+
47
+ const styledText = (
42
48
  <StyledLabel
43
49
  {...nativeProps}
44
- themeIntent={intent}
50
+ themeIntent={isAi ? 'body' : intent}
45
51
  themeIsItalic={fontStyle === 'italic'}
46
52
  allowFontScaling={allowFontScaling}
53
+ style={style}
54
+ testID={testID}
47
55
  >
48
56
  {children}
49
57
  </StyledLabel>
50
58
  );
59
+
60
+ if (isAi) {
61
+ return (
62
+ <GradientText {...pickAccessibilityProps(nativeProps)}>
63
+ {styledText}
64
+ </GradientText>
65
+ );
66
+ }
67
+
68
+ return styledText;
51
69
  };
52
70
 
53
71
  export default Label;
@@ -1,11 +1,11 @@
1
1
  import styled from '@emotion/native';
2
2
  import { Text } from 'react-native';
3
- import type { TypographyIntent } from '../types';
3
+ import type { TypographyColorIntent } from '../types';
4
4
 
5
5
  type ThemeLevel = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
6
6
 
7
7
  const StyledTitle = styled(Text)<{
8
- themeIntent: TypographyIntent;
8
+ themeIntent: TypographyColorIntent;
9
9
  themeLevel: ThemeLevel;
10
10
  themeTypeface: 'neutral' | 'playful';
11
11
  themeIsItalic?: boolean;
@@ -6,7 +6,9 @@ import type {
6
6
  TextStyle,
7
7
  } from 'react-native';
8
8
  import type { TypographyIntent } from '../types';
9
+ import { pickAccessibilityProps } from '../utils';
9
10
  import { StyledTitle } from './StyledTitle';
11
+ import GradientText from '../GradientText';
10
12
 
11
13
  export interface TitleProps extends NativeTextProps {
12
14
  /**
@@ -31,7 +33,6 @@ export interface TitleProps extends NativeTextProps {
31
33
  * - `playful`: To visualise a playful content.
32
34
  */
33
35
  typeface?: 'neutral' | 'playful';
34
-
35
36
  /**
36
37
  * The level of Title including h1, h2, h3, h4, h5 and h6.
37
38
  */
@@ -49,18 +50,36 @@ const Title = ({
49
50
  level = 'h1',
50
51
  typeface = 'neutral',
51
52
  fontStyle = 'normal',
53
+ style,
54
+ testID,
52
55
  ...nativeProps
53
- }: TitleProps) => (
54
- <StyledTitle
55
- {...nativeProps}
56
- themeLevel={level}
57
- themeTypeface={typeface}
58
- themeIntent={intent}
59
- themeIsItalic={fontStyle === 'italic'}
60
- allowFontScaling={allowFontScaling}
61
- >
62
- {children}
63
- </StyledTitle>
64
- );
56
+ }: TitleProps) => {
57
+ const isAi = intent === 'ai';
58
+
59
+ const styledText = (
60
+ <StyledTitle
61
+ {...nativeProps}
62
+ themeLevel={level}
63
+ themeTypeface={typeface}
64
+ themeIntent={isAi ? 'body' : intent}
65
+ themeIsItalic={fontStyle === 'italic'}
66
+ allowFontScaling={allowFontScaling}
67
+ style={style}
68
+ testID={testID}
69
+ >
70
+ {children}
71
+ </StyledTitle>
72
+ );
73
+
74
+ if (isAi) {
75
+ return (
76
+ <GradientText {...pickAccessibilityProps(nativeProps)}>
77
+ {styledText}
78
+ </GradientText>
79
+ );
80
+ }
81
+
82
+ return styledText;
83
+ };
65
84
 
66
85
  export default Title;
@@ -4,7 +4,7 @@ export const FONTWEIGHT_MAP = {
4
4
  'semi-bold': 'semiBold',
5
5
  } as const;
6
6
 
7
- export type TypographyIntent =
7
+ export type TypographyColorIntent =
8
8
  | 'body'
9
9
  | 'subdued'
10
10
  | 'primary'
@@ -18,3 +18,5 @@ export type TypographyIntent =
18
18
  | 'disabled'
19
19
  | 'muted'
20
20
  | 'inactive';
21
+
22
+ export type TypographyIntent = TypographyColorIntent | 'ai';
@@ -0,0 +1,31 @@
1
+ import type { AccessibilityProps, TextProps } from 'react-native';
2
+
3
+ const ACCESSIBILITY_KEYS: ReadonlyArray<keyof AccessibilityProps> = [
4
+ 'accessible',
5
+ 'accessibilityActions',
6
+ 'accessibilityLabel',
7
+ 'accessibilityRole',
8
+ 'accessibilityState',
9
+ 'accessibilityHint',
10
+ 'accessibilityValue',
11
+ 'onAccessibilityAction',
12
+ // Android
13
+ 'accessibilityLabelledBy',
14
+ 'accessibilityLiveRegion',
15
+ 'importantForAccessibility',
16
+ // iOS
17
+ 'accessibilityElementsHidden',
18
+ 'accessibilityLanguage',
19
+ 'accessibilityIgnoresInvertColors',
20
+ 'accessibilityViewIsModal',
21
+ 'onAccessibilityEscape',
22
+ 'onAccessibilityTap',
23
+ 'onMagicTap',
24
+ 'accessibilityIgnoresInvertColors',
25
+ ];
26
+
27
+ export const pickAccessibilityProps = (props: TextProps): AccessibilityProps =>
28
+ ACCESSIBILITY_KEYS.filter((key) => key in props).reduce<AccessibilityProps>(
29
+ (acc, key) => Object.assign(acc, { [key]: props[key] }),
30
+ {}
31
+ );
@@ -0,0 +1,78 @@
1
+ import { mobileVisualisationPalette } from '@hero-design/colors';
2
+
3
+ import type { GradientPoint, Gradients, SystemPalette } from './types';
4
+
5
+ const DIAGONAL_ANGLE = 282;
6
+ const HORIZONTAL_ANGLE = 90;
7
+
8
+ const DIAGONAL_LOCATIONS = [0, 0.2931, 0.993] as const;
9
+ const HORIZONTAL_LOCATIONS = [0, 0.25, 0.75] as const;
10
+
11
+ // Convert CSS gradient angle (degrees) to expo-linear-gradient start/end points.
12
+ // Follows CSS convention: 0° = bottom→top, 90° = left→right,
13
+ // 180° = top→bottom, 270° = right→left.
14
+ const angleToPoints = (
15
+ angleDeg: number
16
+ ): { start: GradientPoint; end: GradientPoint } => {
17
+ const rad = ((angleDeg - 90) * Math.PI) / 180;
18
+ const x = Math.cos(rad);
19
+ const y = Math.sin(rad);
20
+ // Normalize so both components are in [0, 1]
21
+ const start = {
22
+ x: Math.round(((1 - x) / 2) * 100) / 100,
23
+ y: Math.round(((1 - y) / 2) * 100) / 100,
24
+ };
25
+ const end = {
26
+ x: Math.round(((1 + x) / 2) * 100) / 100,
27
+ y: Math.round(((1 + y) / 2) * 100) / 100,
28
+ };
29
+ return { start, end };
30
+ };
31
+
32
+ const getGradients = (systemPalette: SystemPalette): Gradients => {
33
+ const { blueMedium } = mobileVisualisationPalette;
34
+ const { pinkMedium } = mobileVisualisationPalette;
35
+ const brandPrimary = systemPalette.primary;
36
+ const backgroundFallback = systemPalette.defaultGlobalSurface;
37
+
38
+ return {
39
+ aiDiagonal: {
40
+ angle: DIAGONAL_ANGLE,
41
+ ...angleToPoints(DIAGONAL_ANGLE),
42
+ colors: [blueMedium, brandPrimary, pinkMedium],
43
+ locations: DIAGONAL_LOCATIONS,
44
+ },
45
+ aiDiagonal8: {
46
+ angle: DIAGONAL_ANGLE,
47
+ ...angleToPoints(DIAGONAL_ANGLE),
48
+ colors: [blueMedium, brandPrimary, pinkMedium],
49
+ locations: DIAGONAL_LOCATIONS,
50
+ opacity: 0.08,
51
+ backgroundFallback,
52
+ },
53
+ aiDiagonal16: {
54
+ angle: DIAGONAL_ANGLE,
55
+ ...angleToPoints(DIAGONAL_ANGLE),
56
+ colors: [blueMedium, brandPrimary, pinkMedium],
57
+ locations: DIAGONAL_LOCATIONS,
58
+ opacity: 0.16,
59
+ backgroundFallback,
60
+ },
61
+ aiDiagonal24: {
62
+ angle: DIAGONAL_ANGLE,
63
+ ...angleToPoints(DIAGONAL_ANGLE),
64
+ colors: [blueMedium, brandPrimary, pinkMedium],
65
+ locations: DIAGONAL_LOCATIONS,
66
+ opacity: 0.24,
67
+ backgroundFallback,
68
+ },
69
+ aiHorizontal: {
70
+ angle: HORIZONTAL_ANGLE,
71
+ ...angleToPoints(HORIZONTAL_ANGLE),
72
+ colors: [brandPrimary, pinkMedium, brandPrimary],
73
+ locations: HORIZONTAL_LOCATIONS,
74
+ },
75
+ };
76
+ };
77
+
78
+ export default getGradients;
@@ -1,3 +1,5 @@
1
+ import type { ColorValue } from 'react-native';
2
+
1
3
  export type GlobalSystemPalette = {
2
4
  // Updated 14 / Nov / 22
3
5
  // Surfaces
@@ -64,6 +66,26 @@ export type BrandSystemPalette = {
64
66
  decorativeSecondarySurface?: string;
65
67
  };
66
68
 
69
+ export type GradientPoint = { x: number; y: number };
70
+
71
+ export type GradientToken = {
72
+ angle: number;
73
+ start: GradientPoint;
74
+ end: GradientPoint;
75
+ colors: readonly [ColorValue, ColorValue, ...ColorValue[]];
76
+ locations: readonly [number, number, ...number[]];
77
+ opacity?: number;
78
+ backgroundFallback?: string;
79
+ };
80
+
81
+ export type Gradients = {
82
+ aiDiagonal: GradientToken;
83
+ aiDiagonal8: GradientToken;
84
+ aiDiagonal16: GradientToken;
85
+ aiDiagonal24: GradientToken;
86
+ aiHorizontal: GradientToken;
87
+ };
88
+
67
89
  export type ThemeMode = 'light' | 'dark';
68
90
  type ThemeName =
69
91
  | 'swagLight'
@@ -16,8 +16,9 @@ import { getSpace } from './space';
16
16
  import { getSizes } from './sizes';
17
17
  import { getBorderWidths, getRadii } from './borders';
18
18
  import type { Scale } from './scale';
19
- import type { SystemPalette } from './colors/types';
19
+ import type { GradientToken, Gradients, SystemPalette } from './colors/types';
20
20
  import { getShadows } from './shadows';
21
+ import getGradients from './colors/gradients';
21
22
 
22
23
  const getGlobalTheme = (scale: Scale, systemPalette: SystemPalette) => {
23
24
  const fonts = getFonts(scale.font);
@@ -28,10 +29,12 @@ const getGlobalTheme = (scale: Scale, systemPalette: SystemPalette) => {
28
29
  const sizes = getSizes(scale.size);
29
30
  const radii = getRadii(scale.radius);
30
31
  const shadows = getShadows(systemPalette);
32
+ const gradients = getGradients(systemPalette);
31
33
 
32
34
  return {
33
35
  colors: {
34
36
  ...systemPalette,
37
+ gradients,
35
38
  },
36
39
  fonts,
37
40
  fontSizes,
@@ -46,7 +49,7 @@ const getGlobalTheme = (scale: Scale, systemPalette: SystemPalette) => {
46
49
 
47
50
  type GlobalTheme = ReturnType<typeof getGlobalTheme>;
48
51
 
49
- export type { GlobalTheme, Scale, SystemPalette };
52
+ export type { GlobalTheme, GradientToken, Gradients, Scale, SystemPalette };
50
53
 
51
54
  export {
52
55
  getGlobalTheme,
@@ -110,6 +110,40 @@ jest.mock('react-native-webview', () => {
110
110
  };
111
111
  });
112
112
 
113
+ jest.mock('@react-native-masked-view/masked-view', () => {
114
+ const React = jest.requireActual('react');
115
+ const { View } = jest.requireActual('react-native');
116
+
117
+ const MaskedView = ({
118
+ maskElement,
119
+ children,
120
+ style,
121
+ testID,
122
+ }: {
123
+ maskElement: React.ReactNode;
124
+ children: React.ReactNode;
125
+ style?: object;
126
+ testID?: string;
127
+ }) => React.createElement(View, { style, testID }, maskElement, children);
128
+
129
+ return { __esModule: true, default: MaskedView };
130
+ });
131
+
132
+ jest.mock('expo-linear-gradient', () => {
133
+ const React = jest.requireActual('react');
134
+ const { View } = jest.requireActual('react-native');
135
+
136
+ return {
137
+ LinearGradient: ({
138
+ children,
139
+ style,
140
+ }: {
141
+ children?: React.ReactNode;
142
+ style?: object;
143
+ }) => React.createElement(View, { style }, children),
144
+ };
145
+ });
146
+
113
147
  jest.mock('hero-editor/dist/app.js', () => ({ default: '' }));
114
148
 
115
149
  jest.mock('react-native-gesture-handler', () => {
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ import type { AccessibilityProps, StyleProp, ViewStyle } from 'react-native';
3
+ import type { IconName } from '..';
4
+ type GradientIconSize = 'xxxsmall' | 'xsmall' | 'small' | 'medium' | 'large' | 'xlarge';
5
+ interface GradientIconProps extends AccessibilityProps {
6
+ name: IconName;
7
+ themeSize: GradientIconSize;
8
+ testID?: string;
9
+ style?: StyleProp<ViewStyle>;
10
+ }
11
+ declare const GradientIcon: ({ name, themeSize, testID, style, ...accessibilityProps }: GradientIconProps) => React.JSX.Element;
12
+ export default GradientIcon;
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ import type { StyleProp, ViewStyle } from 'react-native';
3
+ export interface SpinWrapperProps {
4
+ children: React.ReactNode;
5
+ style?: StyleProp<ViewStyle>;
6
+ testID?: string;
7
+ }
8
+ declare const SpinWrapper: ({ children, style, testID }: SpinWrapperProps) => React.JSX.Element;
9
+ export default SpinWrapper;
@@ -12,7 +12,7 @@ export interface IconProps extends AccessibilityProps {
12
12
  /**
13
13
  * Intent of the Icon.
14
14
  */
15
- intent?: 'text' | 'primary' | 'secondary' | 'info' | 'danger' | 'success' | 'warning' | 'disabled-text' | 'text-inverted' | 'muted' | 'inactive';
15
+ intent?: 'text' | 'primary' | 'secondary' | 'info' | 'danger' | 'success' | 'warning' | 'disabled-text' | 'text-inverted' | 'muted' | 'inactive' | 'ai';
16
16
  /**
17
17
  * Size of the Icon.
18
18
  */