@hero-design/rn 8.94.0 → 8.96.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 (61) hide show
  1. package/.turbo/turbo-build.log +7 -2
  2. package/CHANGELOG.md +12 -0
  3. package/es/index.js +1319 -966
  4. package/lib/index.js +1319 -965
  5. package/locales/en_AU.js +10 -0
  6. package/locales/en_AU.mjs +8 -0
  7. package/locales/en_CA.js +10 -0
  8. package/locales/en_CA.mjs +8 -0
  9. package/locales/index.js +11 -0
  10. package/locales/index.mjs +9 -0
  11. package/locales/types.js +2 -0
  12. package/locales/types.mjs +1 -0
  13. package/package.json +4 -3
  14. package/rollup.config.mjs +97 -58
  15. package/src/components/DatePicker/DatePickerAndroid.tsx +27 -7
  16. package/src/components/DatePicker/DatePickerCalendar.tsx +23 -4
  17. package/src/components/DatePicker/DatePickerIOS.tsx +27 -8
  18. package/src/components/DatePicker/__tests__/DatePicker.spec.tsx +30 -1
  19. package/src/components/DatePicker/__tests__/DatePickerAndroid.spec.tsx +27 -0
  20. package/src/components/DatePicker/__tests__/DatePickerCalendar.spec.tsx +27 -0
  21. package/src/components/DatePicker/__tests__/DatePickerIOS.spec.tsx +28 -1
  22. package/src/components/DatePicker/__tests__/__snapshots__/DatePickerIOS.spec.tsx.snap +1 -0
  23. package/src/components/DatePicker/hooks/__tests__/useFormatDate.spec.ts +61 -0
  24. package/src/components/DatePicker/{useCalculateDate.tsx → hooks/useCalculateDate.tsx} +1 -1
  25. package/src/components/DatePicker/hooks/useFormatDate.ts +25 -0
  26. package/src/components/DatePicker/hooks/utils.ts +30 -0
  27. package/src/components/DatePicker/types.ts +15 -1
  28. package/src/components/HeroDesignProvider/index.tsx +19 -6
  29. package/src/components/LocaleProvider/__tests__/utils.specs.ts +12 -0
  30. package/src/components/LocaleProvider/context.ts +7 -0
  31. package/src/components/LocaleProvider/hooks.ts +19 -0
  32. package/src/components/LocaleProvider/index.tsx +27 -0
  33. package/src/components/LocaleProvider/utils.ts +14 -0
  34. package/src/index.ts +2 -0
  35. package/src/locales/en_AU.ts +10 -0
  36. package/src/locales/en_CA.ts +10 -0
  37. package/src/locales/index.ts +7 -0
  38. package/src/locales/types.ts +12 -0
  39. package/src/testHelpers/renderWithTheme.tsx +7 -1
  40. package/src/types.ts +4 -0
  41. package/stats/8.95.0/rn-stats.html +4842 -0
  42. package/stats/8.96.0/rn-stats.html +4842 -0
  43. package/types/components/DatePicker/DatePickerAndroid.d.ts +1 -1
  44. package/types/components/DatePicker/DatePickerCalendar.d.ts +1 -1
  45. package/types/components/DatePicker/DatePickerIOS.d.ts +1 -1
  46. package/types/components/DatePicker/{useCalculateDate.d.ts → hooks/useCalculateDate.d.ts} +1 -1
  47. package/types/components/DatePicker/hooks/useFormatDate.d.ts +10 -0
  48. package/types/components/DatePicker/hooks/utils.d.ts +6 -0
  49. package/types/components/DatePicker/types.d.ts +8 -1
  50. package/types/components/HeroDesignProvider/index.d.ts +5 -1
  51. package/types/components/LocaleProvider/__tests__/utils.specs.d.ts +1 -0
  52. package/types/components/LocaleProvider/context.d.ts +3 -0
  53. package/types/components/LocaleProvider/hooks.d.ts +5 -0
  54. package/types/components/LocaleProvider/index.d.ts +7 -0
  55. package/types/components/LocaleProvider/utils.d.ts +3 -0
  56. package/types/index.d.ts +2 -1
  57. package/types/locales/en_AU.d.ts +3 -0
  58. package/types/locales/en_CA.d.ts +3 -0
  59. package/types/locales/index.d.ts +5 -0
  60. package/types/locales/types.d.ts +10 -0
  61. package/types/types.d.ts +2 -1
@@ -548,6 +548,7 @@ exports[`DatePickerIOS renders correctly 1`] = `
548
548
  >
549
549
  <Picker
550
550
  display="spinner"
551
+ locale="en-AU"
551
552
  mode="date"
552
553
  onChange={[Function]}
553
554
  style={
@@ -0,0 +1,61 @@
1
+ import { renderHook } from '@testing-library/react-hooks';
2
+ import formatDate from 'date-fns/fp/format';
3
+ import useFormatDate from '../useFormatDate';
4
+ import { useDateTimeFormat } from '../../../LocaleProvider/hooks';
5
+
6
+ // Mock dependencies
7
+ jest.mock('../../../LocaleProvider/hooks', () => ({
8
+ useDateTimeFormat: jest.fn(),
9
+ }));
10
+
11
+ jest.mock('date-fns/fp/format', () => {
12
+ return jest.fn((format, date) => {
13
+ return `Formatted: ${format}, Date: ${date.toISOString()}`;
14
+ });
15
+ });
16
+
17
+ describe('useFormatDate', () => {
18
+ const testDate = new Date('2023-04-15');
19
+
20
+ beforeEach(() => {
21
+ jest.clearAllMocks();
22
+ (useDateTimeFormat as jest.Mock).mockReturnValue({
23
+ localizeDateTime: () => 'MM/dd/yyyy',
24
+ });
25
+ });
26
+
27
+ it('should return empty string when no date is provided', () => {
28
+ const { result } = renderHook(() => useFormatDate({}));
29
+ expect(result.current.displayValue).toBe('');
30
+ });
31
+
32
+ it('should format date with provided format', () => {
33
+ const { result } = renderHook(() =>
34
+ useFormatDate({
35
+ value: testDate,
36
+ displayFormat: 'yyyy-MM-dd',
37
+ })
38
+ );
39
+
40
+ expect(formatDate).toHaveBeenCalledWith('yyyy-MM-dd', testDate);
41
+ expect(result.current.format).toBe('yyyy-MM-dd');
42
+ });
43
+
44
+ it('should use locale format when no displayFormat provided', () => {
45
+ const { result } = renderHook(() =>
46
+ useFormatDate({
47
+ value: testDate,
48
+ locale: 'en-US',
49
+ })
50
+ );
51
+
52
+ expect(formatDate).toHaveBeenCalledWith('MM/dd/yyyy', testDate);
53
+ expect(result.current.format).toBe('MM/dd/yyyy');
54
+ });
55
+
56
+ it('should use default format when no displayFormat or locale provided', () => {
57
+ const { result } = renderHook(() => useFormatDate({ value: testDate }));
58
+ expect(formatDate).toHaveBeenCalledWith('MM/dd/yyyy', testDate);
59
+ expect(result.current.format).toBe('MM/dd/yyyy');
60
+ });
61
+ });
@@ -1,5 +1,5 @@
1
1
  import { useEffect } from 'react';
2
- import { DatePickerProps } from './types';
2
+ import { DatePickerProps } from '../types';
3
3
 
4
4
  export const getDateValue = (
5
5
  value: Date,
@@ -0,0 +1,25 @@
1
+ import formatDate from 'date-fns/fp/format';
2
+ import { useDateTimeFormat } from '../../LocaleProvider/hooks';
3
+ import { getDateFormat } from './utils';
4
+
5
+ type UseFormatDateProps = {
6
+ displayFormat?: string;
7
+ locale?: string;
8
+ value?: Date;
9
+ };
10
+
11
+ const useFormatDate = ({
12
+ displayFormat,
13
+ locale,
14
+ value,
15
+ }: UseFormatDateProps) => {
16
+ const { localizeDateTime } = useDateTimeFormat();
17
+
18
+ const format = getDateFormat({ displayFormat, locale, localizeDateTime });
19
+
20
+ const displayValue = value ? formatDate(format, value) : '';
21
+
22
+ return { displayValue, format };
23
+ };
24
+
25
+ export default useFormatDate;
@@ -0,0 +1,30 @@
1
+ import { DateTimeFormats, LocaleCode } from '../../../types';
2
+ import locales from '../../../locales';
3
+
4
+ // Function to get the date format based on the displayFormat and locale,
5
+ // if no displayFormat or locale is provided, use the default fullDate format
6
+ export const getDateFormat = ({
7
+ displayFormat,
8
+ locale,
9
+ localizeDateTime,
10
+ }: {
11
+ displayFormat?: string;
12
+ locale?: string;
13
+ localizeDateTime: (key: keyof DateTimeFormats) => string;
14
+ }) => {
15
+ // Prioritise displayFormat
16
+ if (displayFormat) {
17
+ return displayFormat;
18
+ }
19
+
20
+ // If locale is provided, find the corresponding locale in the locales object
21
+ if (locale && locales[locale as LocaleCode]) {
22
+ const localeObject = locales[locale as LocaleCode];
23
+ if (localeObject) {
24
+ return localeObject.dateTimeFormats.fullDate;
25
+ }
26
+ }
27
+
28
+ // If no displayFormat or locale is provided, use the default fullDate format
29
+ return localizeDateTime('fullDate');
30
+ };
@@ -1,4 +1,8 @@
1
- import type { StyleProp, ViewStyle } from 'react-native';
1
+ import type {
2
+ TextInputProps as NativeTextInputProps,
3
+ StyleProp,
4
+ ViewStyle,
5
+ } from 'react-native';
2
6
 
3
7
  export interface DatePickerProps {
4
8
  /**
@@ -85,4 +89,14 @@ export interface DatePickerProps {
85
89
  * [Android only] autoTheme will automatically set the theme based on the device's light mode or dark mode.
86
90
  * */
87
91
  autoTheme?: boolean;
92
+ /**
93
+ * Custom renderer for the selected value. The function provides the current date object and the formatted date string for the current display format.
94
+ */
95
+ renderSelectedValue?: (
96
+ value: {
97
+ date: Date;
98
+ formattedDateString: string;
99
+ },
100
+ props?: NativeTextInputProps
101
+ ) => React.ReactNode;
88
102
  }
@@ -2,13 +2,26 @@ import React from 'react';
2
2
  import ThemeProvider, { ThemeProviderProps } from '../../theme/ThemeProvider';
3
3
  import Toast from '../Toast';
4
4
  import Portal from '../Portal';
5
+ import LocaleProvider from '../LocaleProvider';
6
+ import { LocaleValues } from '../../locales/types';
7
+ import enAULocale from '../../locales/en_AU';
5
8
 
6
- const HeroDesignProvider = ({ theme, children }: ThemeProviderProps) => (
7
- <ThemeProvider theme={theme}>
8
- <Toast.Provider>
9
- <Portal.Provider>{children}</Portal.Provider>
10
- </Toast.Provider>
11
- </ThemeProvider>
9
+ interface HeroDesignProviderProps extends ThemeProviderProps {
10
+ locale?: LocaleValues;
11
+ }
12
+
13
+ const HeroDesignProvider = ({
14
+ theme,
15
+ locale = enAULocale,
16
+ children,
17
+ }: HeroDesignProviderProps) => (
18
+ <LocaleProvider locale={locale}>
19
+ <ThemeProvider theme={theme}>
20
+ <Toast.Provider>
21
+ <Portal.Provider>{children}</Portal.Provider>
22
+ </Toast.Provider>
23
+ </ThemeProvider>
24
+ </LocaleProvider>
12
25
  );
13
26
 
14
27
  export default HeroDesignProvider;
@@ -0,0 +1,12 @@
1
+ import enAU from 'date-fns/locale/en-AU';
2
+ import enCA from 'date-fns/locale/en-CA';
3
+ import { getDateFnsLocale } from '../utils';
4
+
5
+ describe('getDateFnsLocale', () => {
6
+ it('should find en-AU', () => {
7
+ expect(getDateFnsLocale('en-AU')).toBe(enAU);
8
+ });
9
+ it('should find en-CA', () => {
10
+ expect(getDateFnsLocale('en-CA')).toBe(enCA);
11
+ });
12
+ });
@@ -0,0 +1,7 @@
1
+ import { createContext } from 'react';
2
+ import enAULocale from '../../locales/en_AU';
3
+ import { LocaleValues } from '../../locales/types';
4
+
5
+ const LocaleContext = createContext<LocaleValues>(enAULocale);
6
+
7
+ export { LocaleContext };
@@ -0,0 +1,19 @@
1
+ import { useCallback, useContext } from 'react';
2
+ import { LocaleContext } from './context';
3
+ import enAUTranslations from '../../locales/en_AU';
4
+ import type { DateTimeFormats } from '../../locales/types';
5
+
6
+ export const useLocale = () => {
7
+ const context = useContext(LocaleContext);
8
+ if (!context) return enAUTranslations;
9
+ return context;
10
+ };
11
+
12
+ export const useDateTimeFormat = () => {
13
+ const { dateTimeFormats } = useLocale();
14
+ const localizeDateTime = useCallback(
15
+ (key: keyof DateTimeFormats) => dateTimeFormats?.[key],
16
+ [dateTimeFormats]
17
+ );
18
+ return { localizeDateTime };
19
+ };
@@ -0,0 +1,27 @@
1
+ import React, { useEffect } from 'react';
2
+ import setDefaultOptions from 'date-fns/setDefaultOptions';
3
+ import { LocaleContext } from './context';
4
+ import { getDateFnsLocale } from './utils';
5
+ import { LocaleValues } from '../../locales/types';
6
+
7
+ interface LocaleProviderProps {
8
+ locale: LocaleValues;
9
+ }
10
+
11
+ const LocaleProvider = (
12
+ props: React.PropsWithChildren<LocaleProviderProps>
13
+ ) => {
14
+ const { locale, children } = props;
15
+ const code = locale?.['lang'] || 'en-AU';
16
+ // setDefaultOptions here instead of inside useEffect for first rendering
17
+ setDefaultOptions({ locale: getDateFnsLocale(code) });
18
+ useEffect(() => {
19
+ return () => setDefaultOptions({ locale: getDateFnsLocale('en-AU') });
20
+ }, []);
21
+
22
+ return (
23
+ <LocaleContext.Provider value={locale}>{children}</LocaleContext.Provider>
24
+ );
25
+ };
26
+
27
+ export default LocaleProvider;
@@ -0,0 +1,14 @@
1
+ import enAU from 'date-fns/locale/en-AU';
2
+ import enCA from 'date-fns/locale/en-CA';
3
+ import type { Locale } from 'date-fns';
4
+ import { LocaleCode } from '../../locales/types';
5
+
6
+ const Locales = {
7
+ 'en-AU': enAU,
8
+ 'en-CA': enCA,
9
+ } as const;
10
+
11
+ export function getDateFnsLocale(locale: LocaleCode): Locale {
12
+ const fallbackLocale = Locales['en-AU'];
13
+ return Locales[locale] || fallbackLocale;
14
+ }
package/src/index.ts CHANGED
@@ -76,6 +76,7 @@ import {
76
76
  } from './components/AnimatedScroller';
77
77
  import Search from './components/Search';
78
78
  import FloatingIsland from './components/FloatingIsland';
79
+ import LocaleProvider from './components/LocaleProvider';
79
80
 
80
81
  export {
81
82
  theme,
@@ -153,6 +154,7 @@ export {
153
154
  RefreshControl,
154
155
  RichTextEditor,
155
156
  FloatingIsland,
157
+ LocaleProvider,
156
158
  };
157
159
 
158
160
  export * from './types';
@@ -0,0 +1,10 @@
1
+ import { LocaleValues } from './types';
2
+
3
+ const locale: LocaleValues = {
4
+ lang: 'en-AU',
5
+ dateTimeFormats: {
6
+ fullDate: 'dd/MM/yyyy',
7
+ },
8
+ };
9
+
10
+ export default locale;
@@ -0,0 +1,10 @@
1
+ import { LocaleValues } from './types';
2
+
3
+ const locale: LocaleValues = {
4
+ lang: 'en-CA',
5
+ dateTimeFormats: {
6
+ fullDate: 'MMM dd, yyyy',
7
+ },
8
+ };
9
+
10
+ export default locale;
@@ -0,0 +1,7 @@
1
+ import enAU from './en_AU';
2
+ import enCA from './en_CA';
3
+
4
+ export default {
5
+ 'en-AU': enAU,
6
+ 'en-CA': enCA,
7
+ };
@@ -0,0 +1,12 @@
1
+ const LOCALES = ['en-AU', 'en-CA'] as const;
2
+
3
+ export type LocaleCode = typeof LOCALES[number];
4
+
5
+ export type DateTimeFormats = {
6
+ fullDate: string;
7
+ };
8
+
9
+ export type LocaleValues = {
10
+ lang: LocaleCode;
11
+ dateTimeFormats: DateTimeFormats;
12
+ };
@@ -3,8 +3,14 @@ import { render } from '@testing-library/react-native'; // eslint-disable-line i
3
3
  import type { RenderOptions } from '@testing-library/react-native';
4
4
  import { theme } from '../index';
5
5
  import HeroDesignProvider from '../components/HeroDesignProvider';
6
+ import enAU from '../locales/en_AU';
6
7
 
7
8
  const renderWithTheme = (ui: JSX.Element, options?: RenderOptions) =>
8
- render(<HeroDesignProvider theme={theme}>{ui}</HeroDesignProvider>, options);
9
+ render(
10
+ <HeroDesignProvider theme={theme} locale={enAU}>
11
+ {ui}
12
+ </HeroDesignProvider>,
13
+ options
14
+ );
9
15
 
10
16
  export default renderWithTheme;
package/src/types.ts CHANGED
@@ -19,6 +19,7 @@ import { FABHandles } from './components/FAB/FAB';
19
19
  import { ActionGroupHandles } from './components/FAB/ActionGroup';
20
20
  import type { SliderRangeValue } from './components/Slider/RangeSlider';
21
21
  import type { CalendarDateRange } from './components/Calendar/CalendarRange';
22
+ import { LocaleCode, LocaleValues, DateTimeFormats } from './locales/types';
22
23
 
23
24
  export type {
24
25
  BottomNavigationTabType,
@@ -40,4 +41,7 @@ export type {
40
41
  ActionGroupHandles,
41
42
  SliderRangeValue,
42
43
  CalendarDateRange,
44
+ LocaleCode,
45
+ LocaleValues,
46
+ DateTimeFormats,
43
47
  };