@ovotech/element-native 5.3.0 → 5.4.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 (85) hide show
  1. package/dist/d.d.ts +4 -0
  2. package/dist/esm/src/components/Button/Button.js +2 -1
  3. package/dist/esm/src/components/Button/Button.styles.js +4 -1
  4. package/dist/esm/src/components/CurrencyField/CurrencyField.js +2 -2
  5. package/dist/esm/src/components/EmailField/EmailField.js +2 -2
  6. package/dist/esm/src/components/Grid/Col.js +14 -12
  7. package/dist/esm/src/components/Grid/Row.js +6 -10
  8. package/dist/esm/src/components/Heading/Heading.js +1 -1
  9. package/dist/esm/src/components/NavHeader/NavHeader.js +126 -29
  10. package/dist/esm/src/components/NavHeader/NavHeader.styles.js +84 -54
  11. package/dist/esm/src/components/NavHeader/NavHeaderComponents/ActionButtons.js +12 -0
  12. package/dist/esm/src/components/NavHeader/NavHeaderComponents/NavButton.js +23 -0
  13. package/dist/esm/src/components/NavHeader/NavHeaderComponents/StepCounterBars.js +5 -0
  14. package/dist/esm/src/components/NavHeader/utils.js +23 -0
  15. package/dist/esm/src/components/PasswordField/PasswordField.js +2 -2
  16. package/dist/esm/src/components/PasswordInput/PasswordInput.js +1 -1
  17. package/dist/esm/src/components/PhoneField/PhoneField.js +2 -2
  18. package/dist/esm/src/components/ScreenView/ScreenView.js +33 -0
  19. package/dist/esm/src/components/ScreenView/index.js +1 -0
  20. package/dist/esm/src/components/SegmentedControls/components/SegmentButton.js +1 -1
  21. package/dist/esm/src/components/SelectField/Select.js +5 -4
  22. package/dist/esm/src/components/SelectField/SelectField.js +1 -1
  23. package/dist/esm/src/components/TextField/TextField.js +2 -2
  24. package/dist/esm/src/components/TextInput/TextInput.js +1 -1
  25. package/dist/esm/src/components/TextareaField/TextareaField.js +2 -2
  26. package/dist/esm/src/components/Toggle/styles.js +1 -1
  27. package/dist/esm/src/components/index.js +1 -0
  28. package/dist/esm/src/hooks/index.js +1 -1
  29. package/dist/esm/src/hooks/use-full-width.js +1 -1
  30. package/dist/src/components/Button/Button.d.ts +3 -2
  31. package/dist/src/components/Button/Button.js +2 -1
  32. package/dist/src/components/Button/Button.styles.d.ts +1 -1
  33. package/dist/src/components/Button/Button.styles.js +4 -1
  34. package/dist/src/components/Cards/IconDataCard/IconDataCard.styles.d.ts +2 -2
  35. package/dist/src/components/Cards/LinkTextCard/LinkTextCard.styles.d.ts +1 -1
  36. package/dist/src/components/CurrencyField/CurrencyField.d.ts +1 -1
  37. package/dist/src/components/CurrencyField/CurrencyField.js +2 -2
  38. package/dist/src/components/EmailField/EmailField.d.ts +1 -1
  39. package/dist/src/components/EmailField/EmailField.js +2 -2
  40. package/dist/src/components/Grid/Col.js +14 -12
  41. package/dist/src/components/Grid/Row.js +6 -10
  42. package/dist/src/components/Heading/Heading.d.ts +3 -1
  43. package/dist/src/components/Heading/Heading.js +1 -1
  44. package/dist/src/components/NavHeader/NavHeader.d.ts +24 -21
  45. package/dist/src/components/NavHeader/NavHeader.js +126 -29
  46. package/dist/src/components/NavHeader/NavHeader.styles.d.ts +2320 -20
  47. package/dist/src/components/NavHeader/NavHeader.styles.js +84 -54
  48. package/dist/src/components/NavHeader/NavHeaderComponents/ActionButtons.d.ts +3 -0
  49. package/dist/src/components/NavHeader/NavHeaderComponents/ActionButtons.js +12 -0
  50. package/dist/src/components/NavHeader/NavHeaderComponents/NavButton.d.ts +11 -0
  51. package/dist/src/components/NavHeader/NavHeaderComponents/NavButton.js +23 -0
  52. package/dist/src/components/NavHeader/NavHeaderComponents/StepCounterBars.d.ts +7 -0
  53. package/dist/src/components/NavHeader/NavHeaderComponents/StepCounterBars.js +5 -0
  54. package/dist/src/components/NavHeader/utils.d.ts +9 -0
  55. package/dist/src/components/NavHeader/utils.js +23 -0
  56. package/dist/src/components/PasswordField/PasswordField.d.ts +1 -1
  57. package/dist/src/components/PasswordField/PasswordField.js +2 -2
  58. package/dist/src/components/PasswordInput/PasswordInput.js +1 -1
  59. package/dist/src/components/PhoneField/PhoneField.d.ts +1 -1
  60. package/dist/src/components/PhoneField/PhoneField.js +2 -2
  61. package/dist/src/components/ScreenView/ScreenView.d.ts +5 -0
  62. package/dist/src/components/ScreenView/ScreenView.js +33 -0
  63. package/dist/src/components/ScreenView/index.d.ts +1 -0
  64. package/dist/src/components/ScreenView/index.js +1 -0
  65. package/dist/src/components/SegmentedControls/components/SegmentButton.js +1 -1
  66. package/dist/src/components/SelectField/Select.d.ts +3 -1
  67. package/dist/src/components/SelectField/Select.js +5 -4
  68. package/dist/src/components/SelectField/SelectField.d.ts +4 -1
  69. package/dist/src/components/SelectField/SelectField.js +1 -1
  70. package/dist/src/components/TextField/TextField.d.ts +1 -1
  71. package/dist/src/components/TextField/TextField.js +2 -2
  72. package/dist/src/components/TextInput/TextInput.d.ts +5 -3
  73. package/dist/src/components/TextInput/TextInput.js +1 -1
  74. package/dist/src/components/TextareaField/TextareaField.d.ts +1 -1
  75. package/dist/src/components/TextareaField/TextareaField.js +2 -2
  76. package/dist/src/components/Toggle/styles.js +1 -1
  77. package/dist/src/components/index.d.ts +1 -0
  78. package/dist/src/components/index.js +1 -0
  79. package/dist/src/hooks/index.d.ts +1 -1
  80. package/dist/src/hooks/index.js +1 -1
  81. package/dist/src/hooks/use-full-width.js +1 -1
  82. package/package.json +2 -1
  83. /package/dist/esm/src/hooks/{use-breakpoint.js → use-breakpoint.native.js} +0 -0
  84. /package/dist/src/hooks/{use-breakpoint.d.ts → use-breakpoint.native.d.ts} +0 -0
  85. /package/dist/src/hooks/{use-breakpoint.js → use-breakpoint.native.js} +0 -0
@@ -2,7 +2,8 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { numToPx } from '@ovotech/element-core';
3
3
  import groupBy from 'lodash.groupby';
4
4
  import { Fragment, useState } from 'react';
5
- import { Dimensions, Modal, ScrollView, View } from 'react-native';
5
+ import { Dimensions, Modal, ScrollView, View, } from 'react-native';
6
+ import { SafeAreaView } from 'react-native-safe-area-context';
6
7
  import styled, { css } from '../../styled.native';
7
8
  import { Icon } from '../Icon';
8
9
  import { P } from '../P';
@@ -30,7 +31,7 @@ const DropdownWrapper = styled.TouchableOpacity(({ theme }) => css `
30
31
  /* 80 is an opacity for hex https://gist.github.com/lopspower/03fb1cc0ac9f32ef38f4 */
31
32
  background-color: ${theme.color.brand.dark}80;
32
33
  `);
33
- const DropdownContainer = styled.SafeAreaView(({ theme }) => css `
34
+ const DropdownContainer = styled(SafeAreaView)(({ theme }) => css `
34
35
  width: 95%;
35
36
  max-height: 70%;
36
37
  border-radius: ${numToPx(theme.border.radius.sm)};
@@ -74,7 +75,7 @@ const StyledCategory = styled(P)(({ theme }) => css `
74
75
  background-color: ${theme.color.surface.surface};
75
76
  padding: ${numToPx(theme.space[100])} ${numToPx(theme.space[400])};
76
77
  `);
77
- export const Select = ({ options = [], defaultSelected = { label: '', value: 'default' }, noOptionMessage = 'No option selected', onSelected = () => null, hasError = false, testID = 'select', }) => {
78
+ export const Select = ({ options = [], defaultSelected = { label: '', value: 'default' }, noOptionMessage = 'No option selected', onSelected = () => null, hasError = false, testID = 'select', ref, }) => {
78
79
  const [isOpen, setOpen] = useState(false);
79
80
  const [selected, setSelected] = useState(defaultSelected);
80
81
  const height = Dimensions.get('window').height;
@@ -89,5 +90,5 @@ export const Select = ({ options = [], defaultSelected = { label: '', value: 'de
89
90
  label: `-- ${noOptionMessage} --`,
90
91
  value: 'default',
91
92
  };
92
- return (_jsxs(View, { children: [_jsxs(SelectInput, { testID: testID, hasError: hasError, onPress: () => setOpen(!isOpen), children: [_jsx(P, { style: { marginTop: 0, marginBottom: 0 }, children: selected.value === 'default' ? '' : selected.label }), _jsx(Icon, { name: "chevron-down", size: 16, style: { marginLeft: 'auto' } })] }), _jsx(Modal, { transparent: true, visible: isOpen, animationType: "fade", onRequestClose: () => setOpen(false), children: _jsx(DropdownWrapper, { onPress: () => setOpen(false), children: _jsx(DropdownContainer, { style: { maxHeight: dropdownContainerMaxHeight }, children: _jsxs(ScrollView, { nestedScrollEnabled: true, testID: `${testID}-OptionsScrollView`, children: [_jsxs(SelectOption, { accessible: true, accessibilityRole: "radio", onPress: () => handleOptionPress(requiredOption), children: [_jsx(StyledP, { children: _jsx(Strong, { children: requiredOption.label }) }), _jsx(Radio, { isChecked: selected.value === requiredOption.value, children: _jsx(RadioDot, { isChecked: selected.value === requiredOption.value }) })] }), Object.keys(optionsByCategories).map(category => (_jsxs(Fragment, { children: [category !== 'undefined' ? (_jsx(StyledCategory, { children: category })) : null, optionsByCategories[category].map((option, i) => (_jsxs(SelectOption, { accessible: true, accessibilityRole: "radio", isLastOption: i === optionsByCategories[category].length - 1, onPress: () => handleOptionPress(option), children: [_jsx(StyledP, { children: _jsx(Strong, { children: option.label }) }), _jsx(Radio, { isChecked: selected.value === option.value, children: _jsx(RadioDot, { isChecked: selected.value === option.value }) })] }, option.label)))] }, category)))] }) }) }) })] }));
93
+ return (_jsxs(View, { children: [_jsxs(SelectInput, { testID: testID, hasError: hasError, onPress: () => setOpen(!isOpen), ref: ref, children: [_jsx(P, { style: { marginTop: 0, marginBottom: 0 }, children: selected.value === 'default' ? '' : selected.label }), _jsx(Icon, { name: "chevron-down", size: 16, style: { marginLeft: 'auto' } })] }), _jsx(Modal, { transparent: true, visible: isOpen, animationType: "fade", onRequestClose: () => setOpen(false), children: _jsx(DropdownWrapper, { onPress: () => setOpen(false), children: _jsx(DropdownContainer, { style: { maxHeight: dropdownContainerMaxHeight }, children: _jsxs(ScrollView, { nestedScrollEnabled: true, testID: `${testID}-OptionsScrollView`, children: [_jsxs(SelectOption, { accessible: true, accessibilityRole: "radio", onPress: () => handleOptionPress(requiredOption), children: [_jsx(StyledP, { children: _jsx(Strong, { children: requiredOption.label }) }), _jsx(Radio, { isChecked: selected.value === requiredOption.value, children: _jsx(RadioDot, { isChecked: selected.value === requiredOption.value }) })] }), Object.keys(optionsByCategories).map(category => (_jsxs(Fragment, { children: [category !== 'undefined' ? (_jsx(StyledCategory, { children: category })) : null, optionsByCategories[category].map((option, i) => (_jsxs(SelectOption, { accessible: true, accessibilityRole: "radio", isLastOption: i === optionsByCategories[category].length - 1, onPress: () => handleOptionPress(option), children: [_jsx(StyledP, { children: _jsx(Strong, { children: option.label }) }), _jsx(Radio, { isChecked: selected.value === option.value, children: _jsx(RadioDot, { isChecked: selected.value === option.value }) })] }, option.label)))] }, category)))] }) }) }) })] }));
93
94
  };
@@ -1,4 +1,4 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { Field } from '../Field';
3
3
  import { Select } from './Select';
4
- export const SelectField = ({ error, options, onSelected, noOptionMessage, defaultSelected, testID, ...rest }) => (_jsx(Field, { affixWidth: 20, error: error, ...rest, children: _jsx(_Fragment, { children: _jsx(Select, { onSelected: onSelected, options: options, noOptionMessage: noOptionMessage, defaultSelected: defaultSelected, hasError: Boolean(error), testID: testID }) }) }));
4
+ export const SelectField = ({ error, options, onSelected, noOptionMessage, defaultSelected, testID, ref, ...rest }) => (_jsx(Field, { affixWidth: 20, error: error, ...rest, children: _jsx(_Fragment, { children: _jsx(Select, { onSelected: onSelected, options: options, noOptionMessage: noOptionMessage, defaultSelected: defaultSelected, hasError: Boolean(error), testID: testID, ref: ref }) }) }));
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { Field } from '../Field';
3
3
  import { TextInput } from '../TextInput';
4
- export const TextField = (props) => {
5
- return (_jsx(Field, { ...props, children: _jsx(TextInput, {}) }));
4
+ export const TextField = ({ ref, ...props }) => {
5
+ return (_jsx(Field, { ...props, children: _jsx(TextInput, { ref: ref }) }));
6
6
  };
@@ -1,4 +1,4 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { Input } from '../Input/Input';
3
- const TextInput = (props) => _jsx(Input, { ...props, keyboardType: "default", ref: props.ref });
3
+ const TextInput = ({ ref, ...props }) => (_jsx(Input, { ...props, keyboardType: "default", ref: ref }));
4
4
  export { TextInput };
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { Field } from '../Field';
3
3
  import { TextareaInput } from '../TextareaInput';
4
- export const TextareaField = ({ ...props }) => {
5
- return (_jsx(Field, { ...props, children: _jsx(TextareaInput, {}) }));
4
+ export const TextareaField = ({ ref, ...props }) => {
5
+ return (_jsx(Field, { ...props, children: _jsx(TextareaInput, { ref: ref }) }));
6
6
  };
@@ -16,7 +16,7 @@ export const StyledToggleInputWrapper = styled.View(({ theme, labelPosition }) =
16
16
  ? labelPosition === 'left'
17
17
  ? 'margin-left: 10px;'
18
18
  : 'margin-right: 10px;'
19
- : null}
19
+ : ''}
20
20
  `;
21
21
  });
22
22
  export const StyledToggleInput = styled.View(({ theme, checked }) => {
@@ -36,6 +36,7 @@ export * from './PhoneInput';
36
36
  export * from './Pictogram';
37
37
  export * from './Radio';
38
38
  export * from './RadioCard';
39
+ export * from './ScreenView';
39
40
  export * from './RemoteImage';
40
41
  export * from './SegmentedControls';
41
42
  export * from './SelectField';
@@ -1,2 +1,2 @@
1
- export * from './use-breakpoint';
1
+ export * from './use-breakpoint.native';
2
2
  export * from './use-full-width';
@@ -1,5 +1,5 @@
1
1
  import { useEffect, useState } from 'react';
2
- import { useBreakpoint } from './use-breakpoint';
2
+ import { useBreakpoint } from './use-breakpoint.native';
3
3
  export const useFullWidth = (fullWidth = 'small') => {
4
4
  const [isFullWidth, setIsfullWidth] = useState(true);
5
5
  const { smallAndUp } = useBreakpoint();
@@ -3,7 +3,7 @@ import { TouchableOpacityProps } from 'react-native';
3
3
  import { IconName } from '../../providers/icons-types';
4
4
  import { SizeSettings, StyledButtonWrapper } from './Button.styles';
5
5
  export type ButtonVariantName = 'surface' | 'destructive' | 'outline' | 'outline-variant';
6
- type ButtonBase = PropsWithChildren<TouchableOpacityProps & {
6
+ export type ButtonBase = PropsWithChildren<TouchableOpacityProps & {
7
7
  variant?: ButtonVariantName;
8
8
  inverted?: boolean;
9
9
  size?: SizeSettings;
@@ -15,11 +15,12 @@ type ButtonWithText = ButtonBase & {
15
15
  iconLeft?: IconName;
16
16
  iconRight?: IconName;
17
17
  };
18
- type ButtonIconOnly = ButtonBase & {
18
+ export type ButtonIconOnly = ButtonBase & {
19
19
  children?: never;
20
20
  iconLeft?: IconName;
21
21
  iconRight?: IconName;
22
22
  };
23
+ export declare const DEFAULT_BUTTON_VARIANT = "surface";
23
24
  export type ButtonProps = ButtonWithText | ButtonIconOnly;
24
25
  declare const Button: ({ iconLeft, iconRight, children, fullWidth, variant, inverted, size, accessibilityRole, activeOpacity, ref, ...rest }: ButtonProps) => import("react/jsx-runtime").JSX.Element;
25
26
  type OmittedButtonProps = Omit<ComponentProps<typeof Button>, 'variant' | 'children'>;
@@ -1,7 +1,8 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useBreakpoint } from '../../hooks';
3
3
  import { StyledButtonIcon, StyledButtonText, StyledButtonWrapper, StyledInner, } from './Button.styles';
4
- const Button = ({ iconLeft, iconRight, children, fullWidth = false, variant = 'surface', inverted = false, size = 'default', accessibilityRole = 'button', activeOpacity = 0.8, ref, ...rest }) => {
4
+ export const DEFAULT_BUTTON_VARIANT = 'surface';
5
+ const Button = ({ iconLeft, iconRight, children, fullWidth = false, variant = DEFAULT_BUTTON_VARIANT, inverted = false, size = 'default', accessibilityRole = 'button', activeOpacity = 0.8, ref, ...rest }) => {
5
6
  const { smallAndUp } = useBreakpoint();
6
7
  const isIconOnly = !children;
7
8
  const iconSizes = {
@@ -2309,6 +2309,6 @@ export declare const StyledButtonText: import("styled-components").StyledCompone
2309
2309
  }, {
2310
2310
  smallAndUp: boolean;
2311
2311
  inverted: boolean;
2312
- variant: ButtonVariantName;
2313
2312
  size: SizeSettings;
2313
+ variant: ButtonVariantName;
2314
2314
  }, never>;
@@ -94,7 +94,10 @@ const getBorderColor = (theme, variant, inverted) => {
94
94
  if (variant === 'outline-variant') {
95
95
  return button.surface.color.bgVariant;
96
96
  }
97
- return inverted ? button.surface.color.bgInverted : button[variant].color.bg;
97
+ if (inverted) {
98
+ return button.surface.color.bgInverted;
99
+ }
100
+ return button[variant].color.bg;
98
101
  };
99
102
  const getIconColor = (theme, inverted, variant) => {
100
103
  const button = theme.button;
@@ -3443,7 +3443,7 @@ export declare const IconContainer: import("styled-components").StyledComponent<
3443
3443
  }, {}, never>;
3444
3444
  export declare const Metric: import("styled-components").StyledComponent<(props: import("react").PropsWithChildren<import("react-native").TextProps & Omit<{
3445
3445
  inverted?: boolean;
3446
- level: "xl" | "2xl" | "3xl" | "4xl";
3446
+ level: import("../../Heading/Heading").HeadingLevel;
3447
3447
  variant?: "brand" | "surface";
3448
3448
  }, "level">>) => import("react/jsx-runtime").JSX.Element, {
3449
3449
  color: {
@@ -4020,7 +4020,7 @@ export declare const Metric: import("styled-components").StyledComponent<(props:
4020
4020
  }, {}, never>;
4021
4021
  export declare const SubMetric: import("styled-components").StyledComponent<(props: import("react").PropsWithChildren<import("react-native").TextProps & Omit<{
4022
4022
  inverted?: boolean;
4023
- level: "xl" | "2xl" | "3xl" | "4xl";
4023
+ level: import("../../Heading/Heading").HeadingLevel;
4024
4024
  variant?: "brand" | "surface";
4025
4025
  }, "level">>) => import("react/jsx-runtime").JSX.Element, {
4026
4026
  color: {
@@ -2879,7 +2879,7 @@ export declare const ImageContent: import("styled-components").StyledComponent<t
2879
2879
  }, {}, never>;
2880
2880
  export declare const Title: import("styled-components").StyledComponent<(props: import("react").PropsWithChildren<import("react-native").TextProps & Omit<{
2881
2881
  inverted?: boolean;
2882
- level: "xl" | "2xl" | "3xl" | "4xl";
2882
+ level: import("../../Heading/Heading").HeadingLevel;
2883
2883
  variant?: "brand" | "surface";
2884
2884
  }, "level">>) => import("react/jsx-runtime").JSX.Element, {
2885
2885
  color: {
@@ -1,5 +1,5 @@
1
1
  import { CurrencyInputProps } from '../CurrencyInput';
2
2
  import { FieldProps } from '../Field';
3
3
  type Props = Omit<FieldProps, 'children'> & CurrencyInputProps;
4
- export declare const CurrencyField: ({ ...props }: Props) => import("react/jsx-runtime").JSX.Element;
4
+ export declare const CurrencyField: ({ ref, ...props }: Props) => import("react/jsx-runtime").JSX.Element;
5
5
  export {};
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { CurrencyInput } from '../CurrencyInput';
3
3
  import { Field } from '../Field';
4
- export const CurrencyField = ({ ...props }) => {
5
- return (_jsx(Field, { affixWidth: 40, ...props, children: _jsx(CurrencyInput, { ref: props.ref }) }));
4
+ export const CurrencyField = ({ ref, ...props }) => {
5
+ return (_jsx(Field, { affixWidth: 40, ...props, children: _jsx(CurrencyInput, { ref: ref }) }));
6
6
  };
@@ -1,5 +1,5 @@
1
1
  import { FieldProps } from '../Field';
2
2
  import { InputProps } from '../Input/Input';
3
3
  type Props = Omit<FieldProps, 'children'> & InputProps;
4
- export declare const EmailField: ({ ...rest }: Props) => import("react/jsx-runtime").JSX.Element;
4
+ export declare const EmailField: ({ ref, ...rest }: Props) => import("react/jsx-runtime").JSX.Element;
5
5
  export {};
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { EmailInput } from '../EmailInput';
3
3
  import { Field } from '../Field';
4
- export const EmailField = ({ ...rest }) => {
5
- return (_jsx(Field, { ...rest, children: _jsx(EmailInput, {}) }));
4
+ export const EmailField = ({ ref, ...rest }) => {
5
+ return (_jsx(Field, { ...rest, children: _jsx(EmailInput, { ref: ref }) }));
6
6
  };
@@ -1,25 +1,27 @@
1
1
  import { numToPx } from '@ovotech/element-core';
2
2
  import styled, { css } from '../../styled.native';
3
3
  import { styledComponentWithBreakpoints } from '../../utils';
4
- const StyledCol = styled.View(({ theme, span = 12, small, medium, large, smallAndUp, mediumAndUp, largeAndUp, }) => {
4
+ const StyledCol = styled.View(({ theme, span, xsmallAndUp, small, smallAndUp, medium, mediumAndUp }) => {
5
5
  const COLS = 12;
6
- const gutter = mediumAndUp ? theme.space[800] : theme.space[400];
7
- const percentage = (span / COLS) * 100;
6
+ const gutter = mediumAndUp ? theme.space[600] : theme.space[400];
7
+ const percentage = span ? (span / COLS) * 100 : 100;
8
8
  const smallPercentage = small ? (small / COLS) * 100 : percentage;
9
9
  const mediumPercentage = medium ? (medium / COLS) * 100 : smallPercentage;
10
- const largePercentage = large ? (large / COLS) * 100 : mediumPercentage;
11
- const maxWidth = largeAndUp
12
- ? largePercentage
13
- : mediumAndUp
14
- ? mediumPercentage
15
- : smallAndUp
16
- ? smallPercentage
17
- : percentage;
10
+ let maxWidth;
11
+ if (mediumAndUp) {
12
+ maxWidth = mediumPercentage;
13
+ }
14
+ else if (smallAndUp || xsmallAndUp) {
15
+ maxWidth = span ? 50 : 100;
16
+ }
17
+ else {
18
+ maxWidth = 100;
19
+ }
18
20
  return css `
19
21
  flex: 0 0 auto;
20
22
  padding-left: ${numToPx(gutter / 2)};
21
23
  padding-right: ${numToPx(gutter / 2)};
22
- margin-bottom: ${numToPx(gutter)};
24
+ margin-bottom: ${numToPx(theme.space[smallAndUp ? 800 : 600])};
23
25
  max-width: ${maxWidth}%;
24
26
  width: 100%;
25
27
  `;
@@ -1,23 +1,19 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { numToPx } from '@ovotech/element-core';
2
+ import { numToPx } from '../..';
3
3
  import styled, { css } from '../../styled.native';
4
4
  import { styledComponentWithBreakpoints } from '../../utils';
5
5
  const StyledRow = styled.View(({ theme, isNested, smallAndUp, mediumAndUp }) => {
6
- const gutter = mediumAndUp ? theme.space[800] : theme.space[400];
7
- const margin = smallAndUp ? theme.space[800] : theme.space[400];
8
- /* We need to make up for the half gutter that is added to the left and right of a column, between the small and medium breakpoints */
9
- const additionalMargin = smallAndUp ? (margin - gutter) / 2 : 0;
6
+ const rowGap = mediumAndUp || smallAndUp ? theme.space[800] : theme.space[600];
7
+ const colGap = mediumAndUp ? theme.space[600] : theme.space[400];
10
8
  return css `
11
- padding-left: ${numToPx(margin / 2 + additionalMargin)};
12
- padding-right: ${numToPx(margin / 2 + additionalMargin)};
13
9
  margin: 0 auto;
14
- max-width: ${theme.breakpoint.large + margin}px;
10
+ max-width: ${theme.breakpoint.large + rowGap}px;
15
11
  width: 100%;
16
12
 
17
13
  ${isNested
18
14
  ? `
19
- margin-left: -${numToPx(margin / 2)};
20
- margin-right: -${numToPx(margin / 2)};
15
+ margin-left: -${numToPx(colGap / 2)};
16
+ margin-right: -${numToPx(colGap / 2)};
21
17
  width: auto;
22
18
  max-width: 200%; /* max width none not supported in RN */
23
19
  `
@@ -1,10 +1,12 @@
1
1
  import { PropsWithChildren } from 'react';
2
2
  import { TextProps } from 'react-native';
3
+ export type HeadingLevel = 'xl' | '2xl' | '3xl' | '4xl';
3
4
  type HeadingProps = {
4
5
  inverted?: boolean;
5
- level: 'xl' | '2xl' | '3xl' | '4xl';
6
+ level: HeadingLevel;
6
7
  variant?: 'brand' | 'surface';
7
8
  };
9
+ export declare const Heading: ({ accessibilityRole, ...rest }: PropsWithChildren<TextProps & HeadingProps>) => import("react/jsx-runtime").JSX.Element;
8
10
  export declare const Heading1: (props: PropsWithChildren<TextProps & Omit<HeadingProps, "level">>) => import("react/jsx-runtime").JSX.Element;
9
11
  export declare const Heading2: (props: PropsWithChildren<TextProps & Omit<HeadingProps, "level">>) => import("react/jsx-runtime").JSX.Element;
10
12
  export declare const Heading3: (props: PropsWithChildren<TextProps & Omit<HeadingProps, "level">>) => import("react/jsx-runtime").JSX.Element;
@@ -21,7 +21,7 @@ const StyledHeading = styled.Text(({ theme, smallAndUp, inverted, level, variant
21
21
  color: ${color};
22
22
  `;
23
23
  });
24
- const Heading = ({ accessibilityRole = 'header', ...rest }) => {
24
+ export const Heading = ({ accessibilityRole = 'header', ...rest }) => {
25
25
  const breakpoints = useBreakpoint();
26
26
  return (_jsx(StyledHeading, { accessible: true, accessibilityRole: accessibilityRole, ...breakpoints, ...rest }));
27
27
  };
@@ -1,24 +1,27 @@
1
- import { IconNameExtended } from '../../providers';
2
- export type RightActionConfig = {
3
- iconName?: IconNameExtended;
4
- onActionPress?: () => void;
5
- accessibilityLabel?: string;
6
- accessibilityHint?: string;
1
+ import { IconName } from '../../providers';
2
+ export type Layer = 0 | 1 | 2 | 3 | 4;
3
+ type ActionButton = {
4
+ icon?: IconName;
5
+ onPress: () => void;
7
6
  };
8
- export type NavHeaderProps = {
7
+ type StepCounterProps = {
8
+ totalSteps: number;
9
+ currentStep: number;
10
+ };
11
+ export type ScrollState = 'initial' | 'scrollStart' | 'scrolling' | 'scrollBack';
12
+ export type NavHeaderProps<L extends Layer> = {
13
+ layer: L;
9
14
  title?: string;
10
- scrolled: boolean;
11
- canGoBack?: boolean;
12
- backButtonText?: string;
13
- topOffset?: number;
14
- rightActionConfig?: RightActionConfig;
15
- onBackButtonPress?: () => void;
16
- /**
17
- * This callback is used to send the height of the NavContainer
18
- * to the app side. It will be used to set content offset
19
- * because NavHeader is absolutely positioned.
20
- * @param height - height of the expanded NavHeader
21
- */
22
- onHeaderHeightChange?: (height: number) => void;
15
+ actionButtons?: L extends 0 | 1 ? {
16
+ account?: ActionButton;
17
+ help?: ActionButton;
18
+ } : {
19
+ help?: ActionButton;
20
+ };
21
+ onBackPress?: () => void;
22
+ stepCounter?: StepCounterProps;
23
+ scrollState: ScrollState;
24
+ loading?: boolean;
23
25
  };
24
- export declare const NavHeader: ({ title, scrolled, canGoBack, rightActionConfig, topOffset, backButtonText, onHeaderHeightChange, onBackButtonPress, }: NavHeaderProps) => import("react/jsx-runtime").JSX.Element;
26
+ export declare const NavHeader: <L extends Layer>({ layer, onBackPress, actionButtons, title, stepCounter, scrollState, loading, }: NavHeaderProps<L>) => import("react/jsx-runtime").JSX.Element;
27
+ export {};
@@ -1,33 +1,130 @@
1
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
- import Animated, { Easing, FadeInDown, FadeInUp, FadeOutDown, FadeOutUp, useAnimatedStyle, useSharedValue, withTiming, } from 'react-native-reanimated';
3
- import { Action } from '../ActionList';
4
- import { Button } from '../Button';
5
- import { BackActionWrapper, CollapsedTitle, CollapsedTitleWrapper, ExpandedTitle, HeaderGap, NavContainer, NavWrapper, } from './NavHeader.styles';
6
- const FADE_ANIMATION_DURATION = 200;
7
- export const NavHeader = ({ title, scrolled, canGoBack, rightActionConfig, topOffset = 0, backButtonText = 'Back', onHeaderHeightChange, onBackButtonPress, }) => {
8
- const hasRightAction = !!rightActionConfig;
9
- const hasTitle = title !== undefined && title?.length > 0;
10
- const layoutHeight = useSharedValue(0);
11
- const animatedHeightStyle = useAnimatedStyle(() => {
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useEffect, useMemo } from 'react';
3
+ import { Platform } from 'react-native';
4
+ import { ComplexAnimationBuilder, Easing, FadeInUp, LinearTransition, useAnimatedStyle, useSharedValue, withTiming, } from 'react-native-reanimated';
5
+ import { useBreakpoint } from '../../hooks';
6
+ import { Heading, Heading2, Heading3, Heading4, } from '../Heading/Heading';
7
+ import { P } from '../P';
8
+ import { Strong } from '../Strong';
9
+ import { HeaderContainer, NavBackButton, NavContainer, ShadowContainer, SideContainer, SkeletonNavHeading, TitleContainer, } from './NavHeader.styles';
10
+ import { ActionButtons } from './NavHeaderComponents/ActionButtons';
11
+ import { StepCounterBars } from './NavHeaderComponents/StepCounterBars';
12
+ import { getTitleLength } from './utils';
13
+ const baseStyle = {
14
+ hasDropShadow: false,
15
+ isCollapsed: false,
16
+ };
17
+ const hasDropShadowOnly = {
18
+ hasDropShadow: true,
19
+ isCollapsed: false,
20
+ };
21
+ const isCollapsedAndDropShadow = {
22
+ hasDropShadow: true,
23
+ isCollapsed: true,
24
+ };
25
+ const scrollStyleMap = {
26
+ 0: {
27
+ initial: baseStyle,
28
+ scrollStart: baseStyle,
29
+ scrolling: isCollapsedAndDropShadow,
30
+ scrollBack: hasDropShadowOnly,
31
+ },
32
+ 1: {
33
+ initial: baseStyle,
34
+ scrollStart: hasDropShadowOnly,
35
+ scrolling: isCollapsedAndDropShadow,
36
+ scrollBack: hasDropShadowOnly,
37
+ },
38
+ 2: {
39
+ initial: hasDropShadowOnly,
40
+ scrollStart: hasDropShadowOnly,
41
+ scrolling: hasDropShadowOnly,
42
+ scrollBack: hasDropShadowOnly,
43
+ },
44
+ };
45
+ const LayerHeadingMap = {
46
+ 0: '3xl',
47
+ 1: '2xl',
48
+ 2: 'xl',
49
+ 3: 'xl',
50
+ 4: 'xl',
51
+ };
52
+ const ANIMATION_DURATION = 300;
53
+ export const NavHeader = ({ layer, onBackPress, actionButtons, title, stepCounter, scrollState, loading = false, }) => {
54
+ const displayTitle = getTitleLength({ layer, title });
55
+ const platform = Platform.OS;
56
+ const titleIsCentreAligned = layer > 1 && platform === 'ios';
57
+ const { isCollapsed, hasDropShadow } = scrollStyleMap[Math.min(layer, 2)][scrollState];
58
+ const shadowOpacity = useSharedValue(0.5);
59
+ const elevation = useSharedValue(9);
60
+ const LT = LinearTransition.duration(ANIMATION_DURATION);
61
+ const FADE_IN_DISTANCE = layer === 0 ? -68 : -50;
62
+ const FADE_OUT_DISTANCE = layer === 0 ? -72 : -52;
63
+ const ExitAnimation = useMemo(() => {
64
+ var _a;
65
+ return _a = class FadeOutUp extends ComplexAnimationBuilder {
66
+ constructor() {
67
+ super(...arguments);
68
+ this.build = () => {
69
+ const delayFunction = this.getDelayFunction();
70
+ const [animation, config] = this.getAnimationAndConfig();
71
+ const callback = this.callbackV;
72
+ const initialValues = this.initialValues;
73
+ const delay = this.getDelay();
74
+ return () => {
75
+ 'worklet';
76
+ return {
77
+ animations: {
78
+ opacity: delayFunction(delay, animation(0, config)),
79
+ transform: [
80
+ {
81
+ translateY: delayFunction(delay, animation(FADE_OUT_DISTANCE, config)),
82
+ },
83
+ ],
84
+ },
85
+ initialValues: {
86
+ opacity: 1,
87
+ transform: [{ translateY: 0 }],
88
+ ...initialValues,
89
+ },
90
+ callback,
91
+ };
92
+ };
93
+ };
94
+ }
95
+ static createInstance() {
96
+ return new _a();
97
+ }
98
+ },
99
+ _a.presetName = 'FadeOutUp',
100
+ _a;
101
+ }, [layer]);
102
+ const FadingAnimation = {
103
+ Enter: FadeInUp.duration(ANIMATION_DURATION)
104
+ .easing(Easing.ease)
105
+ .withInitialValues({ transform: [{ translateY: FADE_IN_DISTANCE }] }),
106
+ Exit: ExitAnimation.duration(ANIMATION_DURATION).easing(Easing.linear),
107
+ };
108
+ useEffect(() => {
109
+ shadowOpacity.value = withTiming(hasDropShadow ? 0.5 : 0, {
110
+ duration: ANIMATION_DURATION,
111
+ easing: Easing.ease,
112
+ });
113
+ elevation.value = withTiming(hasDropShadow ? 9 : 0, {
114
+ duration: ANIMATION_DURATION,
115
+ easing: Easing.ease,
116
+ });
117
+ }, [scrollState, shadowOpacity, hasDropShadow, elevation, isCollapsed]);
118
+ const animatedShadowStyle = useAnimatedStyle(() => {
12
119
  return {
13
- height: layoutHeight.value,
120
+ shadowOpacity: shadowOpacity.value,
121
+ elevation: elevation.value,
14
122
  };
15
123
  });
16
- const onLayout = (e) => {
17
- const { height } = e.nativeEvent.layout;
18
- if (height === layoutHeight.value) {
19
- return;
20
- }
21
- // we want to only update height of the expanded header to set content offset on the client side
22
- if (!scrolled) {
23
- onHeaderHeightChange?.(height);
24
- }
25
- layoutHeight.value = withTiming(height, {
26
- duration: FADE_ANIMATION_DURATION,
27
- easing: Easing.linear,
28
- });
29
- };
30
- // NavWrapper will recieve height of the NavContainer and animate it
31
- // content inside NavContainer is the only dynamic part of NavHeader
32
- return (_jsx(NavWrapper, { collapsed: scrolled, style: animatedHeightStyle, children: _jsxs(NavContainer, { topOffset: topOffset, hasTitle: hasTitle, onLayout: onLayout, children: [_jsx(BackActionWrapper, { collapsed: scrolled, hasBackButton: canGoBack, children: canGoBack && (_jsx(Action, { standalone: true, iconLeft: "chevron-left-small", onPress: onBackButtonPress, children: backButtonText })) }), scrolled ? (_jsxs(_Fragment, { children: [_jsx(CollapsedTitleWrapper, { entering: FadeInDown.delay(FADE_ANIMATION_DURATION), exiting: FadeOutDown.duration(FADE_ANIMATION_DURATION), children: _jsx(CollapsedTitle, { numberOfLines: 1, ellipsizeMode: "tail", children: title }) }), _jsx(HeaderGap, { hasRightAction: hasRightAction }), hasRightAction && (_jsx(_Fragment, { children: _jsx(Animated.View, { entering: FadeInDown.delay(FADE_ANIMATION_DURATION), exiting: FadeOutDown.duration(FADE_ANIMATION_DURATION), accessibilityRole: "button", accessibilityLabel: rightActionConfig?.accessibilityLabel, accessibilityHint: rightActionConfig?.accessibilityHint, children: _jsx(Button, { iconRight: rightActionConfig.iconName, onPress: rightActionConfig.onActionPress }) }) }))] })) : (_jsxs(_Fragment, { children: [_jsx(ExpandedTitle, { hasRightAction: !hasRightAction, hasTitle: hasTitle, numberOfLines: 2, ellipsizeMode: "tail", hasBackButton: canGoBack, entering: FadeInUp.delay(FADE_ANIMATION_DURATION), exiting: FadeOutUp.duration(FADE_ANIMATION_DURATION), children: title }), hasRightAction && (_jsx(Animated.View, { entering: FadeInUp.delay(FADE_ANIMATION_DURATION), exiting: FadeOutUp.duration(FADE_ANIMATION_DURATION), accessibilityRole: "button", accessibilityLabel: rightActionConfig?.accessibilityLabel, accessibilityHint: rightActionConfig?.accessibilityHint, children: _jsx(Button, { iconRight: rightActionConfig.iconName, onPress: rightActionConfig.onActionPress }) }))] }))] }) }));
124
+ const breakpoints = useBreakpoint();
125
+ return (_jsx(ShadowContainer, { style: [animatedShadowStyle], children: _jsx(NavContainer, { breakpoints: breakpoints, layer: layer, layout: LT, isCollapsed: isCollapsed, children: !isCollapsed && (_jsxs(_Fragment, { children: [_jsxs(HeaderContainer, { layout: LT, entering: FadingAnimation.Enter, exiting: FadingAnimation.Exit, children: [_jsx(SideContainer, { flex: titleIsCentreAligned ? 1 : 0, side: "start", children: layer > 1 && (_jsx(NavBackButton, { onPress: () => {
126
+ onBackPress && onBackPress();
127
+ }, variant: "bright", iconLeft: platform === 'ios' ? 'chevron-left' : 'arrow-left' })) }), _jsxs(TitleContainer, { layer: layer, isIOS: platform === 'ios', children: [loading ? (_jsx(SkeletonNavHeading, { size: "100%", headingComponent: layer === 0 ? Heading2 : layer === 1 ? Heading3 : Heading4 })) : layer < 2 ? (_jsx(Heading, { inverted: layer < 2, level: LayerHeadingMap[layer], children: displayTitle })) : (_jsx(P, { size: "md", children: _jsx(Strong, { maxLength: 23, children: displayTitle }) })), stepCounter && !loading && (_jsx(P, { size: "sm", children: `Step ${stepCounter.currentStep <= stepCounter.totalSteps
128
+ ? stepCounter.currentStep
129
+ : stepCounter.totalSteps} of ${stepCounter.totalSteps}` }))] }), _jsx(SideContainer, { side: "end", children: actionButtons && (_jsx(ActionButtons, { loading: loading, layer: layer, actionButtons: actionButtons })) })] }), stepCounter && (_jsx(StepCounterBars, { loading: loading, totalSteps: stepCounter.totalSteps, currentStep: stepCounter.currentStep }))] })) }) }));
33
130
  };