@westpac/ui 0.49.0 → 0.50.3

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 (104) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/component-type.json +1 -1
  3. package/dist/components/accordion/components/accordion-item/accordion-item.component.js +44 -24
  4. package/dist/components/accordion/components/accordion-item/accordion-item.styles.d.ts +18 -6
  5. package/dist/components/accordion/components/accordion-item/accordion-item.styles.js +10 -6
  6. package/dist/components/autocomplete/autocomplete.component.d.ts +1 -1
  7. package/dist/components/autocomplete/autocomplete.component.js +3 -2
  8. package/dist/components/autocomplete/autocomplete.types.d.ts +6 -0
  9. package/dist/components/date-picker-beta/components/calendar/calendar.component.d.ts +5 -0
  10. package/dist/components/date-picker-beta/components/calendar/calendar.component.js +101 -0
  11. package/dist/components/date-picker-beta/components/calendar/calendar.types.d.ts +2 -0
  12. package/dist/components/date-picker-beta/components/calendar/calendar.types.js +1 -0
  13. package/dist/components/date-picker-beta/components/calendar/components/calendar-cell/calendar-cell.component.d.ts +5 -0
  14. package/dist/components/date-picker-beta/components/calendar/components/calendar-cell/calendar-cell.component.js +28 -0
  15. package/dist/components/date-picker-beta/components/calendar/components/calendar-cell/calendar-cell.styles.d.ts +103 -0
  16. package/dist/components/date-picker-beta/components/calendar/components/calendar-cell/calendar-cell.styles.js +39 -0
  17. package/dist/components/date-picker-beta/components/calendar/components/calendar-cell/calendar-cell.types.d.ts +5 -0
  18. package/dist/components/date-picker-beta/components/calendar/components/calendar-cell/calendar-cell.types.js +1 -0
  19. package/dist/components/date-picker-beta/components/calendar/components/calendar-grid/calendar-grid.component.d.ts +5 -0
  20. package/dist/components/date-picker-beta/components/calendar/components/calendar-grid/calendar-grid.component.js +26 -0
  21. package/dist/components/date-picker-beta/components/calendar/components/calendar-grid/calendar-grid.types.d.ts +5 -0
  22. package/dist/components/date-picker-beta/components/calendar/components/calendar-grid/calendar-grid.types.js +1 -0
  23. package/dist/components/date-picker-beta/components/calendar/components/select/select.component.d.ts +5 -0
  24. package/dist/components/date-picker-beta/components/calendar/components/select/select.component.js +23 -0
  25. package/dist/components/date-picker-beta/components/calendar/components/select/select.styles.d.ts +28 -0
  26. package/dist/components/date-picker-beta/components/calendar/components/select/select.styles.js +14 -0
  27. package/dist/components/date-picker-beta/components/calendar/components/select/select.types.d.ts +2 -0
  28. package/dist/components/date-picker-beta/components/calendar/components/select/select.types.js +1 -0
  29. package/dist/components/date-picker-beta/components/date-field/components/date-segment/date-segment.component.d.ts +5 -0
  30. package/dist/components/date-picker-beta/components/date-field/components/date-segment/date-segment.component.js +20 -0
  31. package/dist/components/date-picker-beta/components/date-field/components/date-segment/date-segment.styles.d.ts +44 -0
  32. package/dist/components/date-picker-beta/components/date-field/components/date-segment/date-segment.styles.js +26 -0
  33. package/dist/components/date-picker-beta/components/date-field/components/date-segment/date-segment.types.d.ts +7 -0
  34. package/dist/components/date-picker-beta/components/date-field/components/date-segment/date-segment.types.js +1 -0
  35. package/dist/components/date-picker-beta/components/date-field/date-field.component.d.ts +5 -0
  36. package/dist/components/date-picker-beta/components/date-field/date-field.component.js +25 -0
  37. package/dist/components/date-picker-beta/components/date-field/date-field.types.d.ts +4 -0
  38. package/dist/components/date-picker-beta/components/date-field/date-field.types.js +1 -0
  39. package/dist/components/date-picker-beta/components/dialog/dialog.component.d.ts +5 -0
  40. package/dist/components/date-picker-beta/components/dialog/dialog.component.js +16 -0
  41. package/dist/components/date-picker-beta/components/dialog/dialog.types.d.ts +3 -0
  42. package/dist/components/date-picker-beta/components/dialog/dialog.types.js +1 -0
  43. package/dist/components/date-picker-beta/components/popover/popover.component.d.ts +5 -0
  44. package/dist/components/date-picker-beta/components/popover/popover.component.js +38 -0
  45. package/dist/components/date-picker-beta/components/popover/popover.styles.d.ts +71 -0
  46. package/dist/components/date-picker-beta/components/popover/popover.styles.js +35 -0
  47. package/dist/components/date-picker-beta/components/popover/popover.types.d.ts +9 -0
  48. package/dist/components/date-picker-beta/components/popover/popover.types.js +1 -0
  49. package/dist/components/date-picker-beta/date-picker.component.d.ts +2 -0
  50. package/dist/components/date-picker-beta/date-picker.component.js +114 -0
  51. package/dist/components/date-picker-beta/date-picker.styles.d.ts +107 -0
  52. package/dist/components/date-picker-beta/date-picker.styles.js +47 -0
  53. package/dist/components/date-picker-beta/date-picker.types.d.ts +32 -0
  54. package/dist/components/date-picker-beta/date-picker.types.js +1 -0
  55. package/dist/components/date-picker-beta/index.d.ts +2 -0
  56. package/dist/components/date-picker-beta/index.js +1 -0
  57. package/dist/components/footer/footer.component.js +4 -11
  58. package/dist/components/footer/footer.styles.d.ts +3 -21
  59. package/dist/components/footer/footer.styles.js +3 -9
  60. package/dist/components/index.d.ts +1 -0
  61. package/dist/components/index.js +1 -0
  62. package/dist/css/westpac-ui.css +1025 -35
  63. package/dist/css/westpac-ui.min.css +1025 -35
  64. package/dist/hook/breakpoints.hook.js +59 -10
  65. package/dist/hook/index.d.ts +1 -0
  66. package/dist/hook/index.js +1 -0
  67. package/dist/tailwind/constants/colors.d.ts +25 -25
  68. package/dist/tailwind/tailwind-plugin.js +20 -0
  69. package/dist/tailwind/themes/index.d.ts +27 -27
  70. package/package.json +10 -5
  71. package/src/components/accordion/components/accordion-item/accordion-item.component.tsx +49 -32
  72. package/src/components/accordion/components/accordion-item/accordion-item.styles.ts +10 -6
  73. package/src/components/autocomplete/autocomplete.component.tsx +3 -1
  74. package/src/components/autocomplete/autocomplete.types.ts +6 -0
  75. package/src/components/date-picker-beta/components/calendar/calendar.component.tsx +106 -0
  76. package/src/components/date-picker-beta/components/calendar/calendar.types.ts +3 -0
  77. package/src/components/date-picker-beta/components/calendar/components/calendar-cell/calendar-cell.component.tsx +42 -0
  78. package/src/components/date-picker-beta/components/calendar/components/calendar-cell/calendar-cell.styles.ts +40 -0
  79. package/src/components/date-picker-beta/components/calendar/components/calendar-cell/calendar-cell.types.ts +8 -0
  80. package/src/components/date-picker-beta/components/calendar/components/calendar-grid/calendar-grid.component.tsx +36 -0
  81. package/src/components/date-picker-beta/components/calendar/components/calendar-grid/calendar-grid.types.ts +4 -0
  82. package/src/components/date-picker-beta/components/calendar/components/select/select.component.tsx +21 -0
  83. package/src/components/date-picker-beta/components/calendar/components/select/select.styles.ts +13 -0
  84. package/src/components/date-picker-beta/components/calendar/components/select/select.types.ts +3 -0
  85. package/src/components/date-picker-beta/components/date-field/components/date-segment/date-segment.component.tsx +26 -0
  86. package/src/components/date-picker-beta/components/date-field/components/date-segment/date-segment.styles.ts +22 -0
  87. package/src/components/date-picker-beta/components/date-field/components/date-segment/date-segment.types.ts +8 -0
  88. package/src/components/date-picker-beta/components/date-field/date-field.component.tsx +32 -0
  89. package/src/components/date-picker-beta/components/date-field/date-field.types.ts +3 -0
  90. package/src/components/date-picker-beta/components/dialog/dialog.component.tsx +23 -0
  91. package/src/components/date-picker-beta/components/dialog/dialog.types.ts +4 -0
  92. package/src/components/date-picker-beta/components/popover/popover.component.tsx +34 -0
  93. package/src/components/date-picker-beta/components/popover/popover.styles.ts +34 -0
  94. package/src/components/date-picker-beta/components/popover/popover.types.ts +10 -0
  95. package/src/components/date-picker-beta/date-picker.component.tsx +114 -0
  96. package/src/components/date-picker-beta/date-picker.styles.ts +44 -0
  97. package/src/components/date-picker-beta/date-picker.types.ts +40 -0
  98. package/src/components/date-picker-beta/index.ts +2 -0
  99. package/src/components/footer/footer.component.tsx +8 -12
  100. package/src/components/footer/footer.styles.ts +2 -6
  101. package/src/components/index.ts +1 -0
  102. package/src/hook/breakpoints.hook.ts +71 -11
  103. package/src/hook/index.ts +1 -0
  104. package/src/tailwind/tailwind-plugin.ts +20 -0
@@ -1,8 +1,8 @@
1
1
  /* eslint-disable sonarjs/deprecation */
2
2
  /* eslint-disable @typescript-eslint/no-unsafe-member-access */
3
3
  import { useAccordionItem } from '@react-aria/accordion';
4
- import { AnimatePresence, LazyMotion, m } from 'motion/react';
5
- import React, { useRef } from 'react';
4
+ import { LazyMotion, m, useAnimate } from 'motion/react';
5
+ import React, { useEffect, useRef, useState } from 'react';
6
6
  import { mergeProps, useFocusRing, useHover, useLocale } from 'react-aria';
7
7
 
8
8
  import { ArrowLeftIcon, ArrowRightIcon } from '../../../icon/index.js';
@@ -23,11 +23,44 @@ export function AccordionItem<T = HTMLElement>({
23
23
  const { state, item } = props;
24
24
  const { buttonProps, regionProps } = useAccordionItem<T>(props, state, ref);
25
25
  const { isFocusVisible, focusProps } = useFocusRing();
26
- const isOpen = state.expandedKeys.has(item.key);
26
+ const isOpenState = state.expandedKeys.has(item.key);
27
27
  const isDisabled = state.disabledKeys.has(item.key);
28
28
  const { hoverProps } = useHover({ isDisabled });
29
29
  const { direction } = useLocale();
30
- const styles = accordionItemStyles({ isOpen, isDisabled, look, isFocusVisible, rounded });
30
+ // Open/close animation needs to be done with useAnimate as AnimatePresence will unmount component
31
+ const [scope, animate] = useAnimate();
32
+ const [enableOpenStyle, setEnableOpenStyle] = useState(false);
33
+
34
+ const styles = accordionItemStyles({
35
+ isOpen: enableOpenStyle,
36
+ isOpenState,
37
+ isDisabled,
38
+ look,
39
+ isFocusVisible,
40
+ rounded,
41
+ });
42
+
43
+ useEffect(() => {
44
+ // setEnableStyle here as opening animation isn't working correctly if done below
45
+ if (isOpenState) setEnableOpenStyle(true);
46
+
47
+ if (enableOpenStyle) {
48
+ animate(scope.current, { height: 'auto' }, { duration: 0.3, ease: [0.25, 0.1, 0.25, 1.0] });
49
+ }
50
+ if (!isOpenState) {
51
+ animate(
52
+ scope.current,
53
+ { height: '0px' },
54
+ {
55
+ duration: 0.3,
56
+ ease: [0.25, 0.1, 0.25, 1.0],
57
+ // set some styles after animation completes so content doesn't disappear on close
58
+ onComplete: () => setEnableOpenStyle(false),
59
+ },
60
+ );
61
+ }
62
+ // eslint-disable-next-line react-hooks/exhaustive-deps
63
+ }, [isOpenState, enableOpenStyle]);
31
64
 
32
65
  return (
33
66
  <Tag className={styles.base({ className })}>
@@ -47,34 +80,18 @@ export function AccordionItem<T = HTMLElement>({
47
80
  </h3>
48
81
  <div {...regionProps}>
49
82
  <LazyMotion features={loadAnimations}>
50
- <AnimatePresence initial={false}>
51
- {isOpen && (
52
- <m.div
53
- className="overflow-hidden"
54
- initial={{
55
- height: 0,
56
- }}
57
- animate={{
58
- height: 'auto',
59
- }}
60
- exit={{
61
- height: 0,
62
- }}
63
- transition={{ duration: 0.3, ease: [0.25, 0.1, 0.25, 1.0] }}
64
- >
65
- <div
66
- className={styles.content()}
67
- // TODO: Remove below with updated accordion that uses disclosure as the issue doesn't happen with that version
68
- // Need to call stopPropagation here as some events from children are bubbling up and focusing the accordion i.e. inputs
69
- onBlur={e => {
70
- e.stopPropagation();
71
- }}
72
- >
73
- {item.props.children}
74
- </div>
75
- </m.div>
76
- )}
77
- </AnimatePresence>
83
+ <m.div className="overflow-hidden" initial={{ height: isOpenState ? 'auto' : 0 }} ref={scope}>
84
+ <div
85
+ className={styles.content()}
86
+ // TODO: Remove below with updated accordion that uses disclosure as the issue doesn't happen with that version
87
+ // Need to call stopPropagation here as some events from children are bubbling up and focusing the accordion i.e. inputs
88
+ onBlur={e => {
89
+ e.stopPropagation();
90
+ }}
91
+ >
92
+ {item.props.children}
93
+ </div>
94
+ </m.div>
78
95
  </LazyMotion>
79
96
  </div>
80
97
  </Tag>
@@ -7,7 +7,7 @@ export const styles = tv(
7
7
  itemHeader: 'typography-body-9 flex w-full flex-1 items-center justify-between px-3 py-2 group-first:border-t-0',
8
8
  headerTitleWrapper: 'flex-1 pr-2 text-left',
9
9
  indicator: 'size-3 rotate-90',
10
- content: 'hidden',
10
+ content: '',
11
11
  },
12
12
  variants: {
13
13
  look: {
@@ -19,13 +19,17 @@ export const styles = tv(
19
19
  'mb-[-1px] border-l-[0.375rem] border-r border-border bg-light shadow-[inset_0px_1px_0_0_var(--tw-shadow-color),inset_0_-1px_0_0_var(--tw-shadow-color)] !shadow-border transition-colors',
20
20
  },
21
21
  },
22
+ isOpenState: {
23
+ false: {
24
+ itemHeader: 'background-transition hover:bg-background',
25
+ },
26
+ },
22
27
  isOpen: {
23
28
  true: {
24
- content: 'block border-border p-3',
29
+ content: 'visible block border-border p-3',
25
30
  },
26
31
  false: {
27
- base: '',
28
- itemHeader: 'background-transition hover:bg-background',
32
+ content: 'hidden',
29
33
  },
30
34
  },
31
35
  isDisabled: {
@@ -45,13 +49,13 @@ export const styles = tv(
45
49
  compoundSlots: [
46
50
  {
47
51
  slots: ['indicator'],
48
- isOpen: true,
52
+ isOpenState: true,
49
53
  className: '-rotate-90',
50
54
  },
51
55
  {
52
56
  slots: ['itemHeader'],
53
57
  look: 'lego',
54
- isOpen: true,
58
+ isOpenState: true,
55
59
  className: 'border-l-hero',
56
60
  },
57
61
  {
@@ -41,13 +41,15 @@ function Autocomplete<T extends object>(
41
41
  className,
42
42
  width = 'full',
43
43
  loadingState,
44
+ comboBoxState,
44
45
  ...props
45
46
  }: AutocompleteProps<T>,
46
47
  ref: ForwardedRef<HTMLInputElement>,
47
48
  ) {
48
49
  // eslint-disable-next-line @typescript-eslint/unbound-method
49
50
  const { contains } = useFilter({ sensitivity: 'base' });
50
- const state = useComboBoxState({ isDisabled, ...props, defaultFilter: contains });
51
+ const internalState = useComboBoxState({ isDisabled, ...props, defaultFilter: contains });
52
+ const state = comboBoxState ?? internalState;
51
53
  const { isFocusVisible, focusProps } = useFocusRing();
52
54
  const { isFocusVisible: isInputFocusVisible, focusProps: inputFocusProps } = useFocusRing();
53
55
  const inputRef = React.useRef<HTMLInputElement>(null);
@@ -1,6 +1,7 @@
1
1
  import { type ComboBoxProps } from '@react-types/combobox';
2
2
  import { type AriaLabelingProps } from '@react-types/shared';
3
3
  import { type ReactNode } from 'react';
4
+ import { ComboBoxState } from 'react-stately';
4
5
  import { type VariantProps } from 'tailwind-variants';
5
6
 
6
7
  import { HintProps, InputProps } from '../index.js';
@@ -63,5 +64,10 @@ export type AutocompleteProps<T extends object> = {
63
64
  * Width of autocomplete
64
65
  */
65
66
  width?: InputProps['width'];
67
+ /**
68
+ * Pass through comboBox state from consuming component. If not specified,
69
+ * will be handled internally.
70
+ */
71
+ comboBoxState?: ComboBoxState<T>;
66
72
  } & ComboBoxProps<T> &
67
73
  AriaLabelingProps;
@@ -0,0 +1,106 @@
1
+ 'use client';
2
+
3
+ import { CalendarDate, createCalendar } from '@internationalized/date';
4
+ import React, { ChangeEvent, useCallback, useMemo, useRef } from 'react';
5
+ import { useButton, useCalendar, useLocale } from 'react-aria';
6
+ import { useCalendarState } from 'react-stately';
7
+
8
+ import { Button } from '../../../button/index.js';
9
+ import { Circle } from '../../../circle/circle.component.js';
10
+ import { ArrowLeftIcon, ArrowRightIcon } from '../../../icon/index.js';
11
+
12
+ import { type CalendarProps } from './calendar.types.js';
13
+ import { CalendarGrid } from './components/calendar-grid/calendar-grid.component.js';
14
+ import { Select } from './components/select/select.component.js';
15
+
16
+ const MONTHS = Array.from({ length: 12 }, (_, i) => {
17
+ const date = new Date(2020, i, 1); // Year doesn't matter, use 2020 as a common year
18
+ const monthName = new Intl.DateTimeFormat('en', { month: 'short' }).format(date);
19
+
20
+ return {
21
+ value: i + 1,
22
+ label: monthName,
23
+ };
24
+ });
25
+
26
+ const YEAR_OFFSET = 10;
27
+
28
+ /**
29
+ * @private
30
+ */
31
+ export function Calendar({ value, ...props }: CalendarProps) {
32
+ const { locale } = useLocale();
33
+ const refPrevButton = useRef(null);
34
+ const refNextButton = useRef(null);
35
+ const state = useCalendarState({
36
+ createCalendar,
37
+ ...props,
38
+ value,
39
+ locale,
40
+ });
41
+
42
+ const { calendarProps, prevButtonProps, nextButtonProps } = useCalendar({ value, ...props }, state);
43
+ const { buttonProps: newPrevButtonProps } = useButton(prevButtonProps, refPrevButton);
44
+ const { buttonProps: newNextButtonProps } = useButton(nextButtonProps, refNextButton);
45
+
46
+ const years = useMemo(() => {
47
+ const beginning = state.focusedDate.year - YEAR_OFFSET;
48
+ return Array.from({ length: 20 }, (_, i) => {
49
+ return {
50
+ value: beginning + i,
51
+ label: beginning + i,
52
+ };
53
+ });
54
+ }, [state.focusedDate.year]);
55
+
56
+ const handleMonthChange = useCallback(
57
+ (ev: ChangeEvent<HTMLSelectElement>) => {
58
+ state.setFocusedDate(new CalendarDate(state.focusedDate.year, +ev.target.value, state.focusedDate.day));
59
+ },
60
+ [state],
61
+ );
62
+
63
+ const handleYearChange = useCallback(
64
+ (ev: ChangeEvent<HTMLSelectElement>) => {
65
+ state.setFocusedDate(new CalendarDate(+ev.target.value, state.focusedDate.month, state.focusedDate.day));
66
+ },
67
+ [state],
68
+ );
69
+
70
+ return (
71
+ <div {...calendarProps}>
72
+ <div className="flex items-center justify-between">
73
+ <div className="flex gap-3">
74
+ <Select onChange={handleMonthChange} value={state.visibleRange.start.month}>
75
+ {MONTHS.map(month => (
76
+ <option key={month.value} value={month.value}>
77
+ {month.label}
78
+ </option>
79
+ ))}
80
+ </Select>
81
+
82
+ <Select onChange={handleYearChange} value={state.visibleRange.start.year}>
83
+ {years.map(year => (
84
+ <option key={year.value} value={year.value}>
85
+ {year.label}
86
+ </option>
87
+ ))}
88
+ </Select>
89
+ </div>
90
+ <div className="flex gap-2">
91
+ <Button look="unstyled" {...newPrevButtonProps}>
92
+ <Circle className="bg-light">
93
+ <ArrowLeftIcon size="small" color="primary" />
94
+ </Circle>
95
+ </Button>
96
+ <Button look="unstyled" {...newNextButtonProps}>
97
+ <Circle className="bg-light">
98
+ <ArrowRightIcon size="small" color="primary" />
99
+ </Circle>
100
+ </Button>
101
+ </div>
102
+ </div>
103
+ <CalendarGrid state={state} firstDayOfWeek={props.firstDayOfWeek} />
104
+ </div>
105
+ );
106
+ }
@@ -0,0 +1,3 @@
1
+ import { AriaCalendarProps, DateValue } from 'react-aria';
2
+
3
+ export type CalendarProps<T extends DateValue = DateValue> = AriaCalendarProps<T>;
@@ -0,0 +1,42 @@
1
+ 'use client';
2
+ import React, { useRef } from 'react';
3
+ import { useCalendarCell, useFocusVisible } from 'react-aria';
4
+
5
+ import { styles as calendarCellStyles } from './calendar-cell.styles.js';
6
+ import { CalendarCellProps } from './calendar-cell.types.js';
7
+
8
+ /**
9
+ * @private
10
+ */
11
+ export function CalendarCell({ state, date }: CalendarCellProps) {
12
+ const ref = useRef(null);
13
+ const { isFocusVisible } = useFocusVisible();
14
+ const {
15
+ cellProps,
16
+ buttonProps,
17
+ isSelected,
18
+ isOutsideVisibleRange,
19
+ isDisabled,
20
+ isUnavailable,
21
+ formattedDate,
22
+ isFocused,
23
+ } = useCalendarCell({ date }, state, ref);
24
+ const isToday = buttonProps['aria-label']?.indexOf('Today') !== -1;
25
+ const styles = calendarCellStyles({
26
+ isSelected,
27
+ isFocused: isFocused && isFocusVisible,
28
+ isToday,
29
+ isDisabled,
30
+ isUnavailable,
31
+ });
32
+
33
+ return (
34
+ <td {...cellProps}>
35
+ <div className={styles.base()}>
36
+ <div {...buttonProps} ref={ref} hidden={isOutsideVisibleRange} className={styles.text()}>
37
+ {formattedDate}
38
+ </div>
39
+ </div>
40
+ </td>
41
+ );
42
+ }
@@ -0,0 +1,40 @@
1
+ import { tv } from 'tailwind-variants';
2
+
3
+ export const styles = tv({
4
+ slots: {
5
+ base: 'flex items-center justify-center',
6
+ text: 'size-6 rounded-full border border-white text-center leading-[2.125rem]',
7
+ },
8
+ variants: {
9
+ isDisabled: {
10
+ true: {
11
+ text: 'cursor-default line-through opacity-50',
12
+ },
13
+ false: {
14
+ text: 'hover:bg-primary/5',
15
+ },
16
+ },
17
+ isUnavailable: {
18
+ true: {
19
+ text: 'cursor-default line-through opacity-50',
20
+ },
21
+ false: {},
22
+ },
23
+ isFocused: {
24
+ true: {
25
+ text: '!outline-offset-0 focus-outline',
26
+ },
27
+ },
28
+ isToday: {
29
+ true: {
30
+ text: 'border-primary bg-primary/5',
31
+ },
32
+ },
33
+ isSelected: {
34
+ true: {
35
+ text: 'bg-primary text-white hover:bg-primary',
36
+ },
37
+ false: 'bg-white',
38
+ },
39
+ },
40
+ });
@@ -0,0 +1,8 @@
1
+ import { AriaCalendarCellProps } from 'react-aria';
2
+ import { CalendarState, RangeCalendarState } from 'react-stately';
3
+
4
+ // import { styles } from './calendar-Cell.styles.js';
5
+
6
+ // type Variants = VariantProps<typeof styles>;
7
+
8
+ export type CalendarCellProps = AriaCalendarCellProps & { state: CalendarState | RangeCalendarState };
@@ -0,0 +1,36 @@
1
+ import React from 'react';
2
+ import { useCalendarGrid } from 'react-aria';
3
+
4
+ import { CalendarCell } from '../calendar-cell/calendar-cell.component.js';
5
+
6
+ import { CalendarGridProps } from './calendar-grid.types.js';
7
+
8
+ /**
9
+ * @private
10
+ */
11
+ export function CalendarGrid({ state, weekdayStyle = 'short', ...props }: CalendarGridProps) {
12
+ const { gridProps, headerProps, weekDays, weeksInMonth } = useCalendarGrid({ weekdayStyle, ...props }, state);
13
+
14
+ return (
15
+ <table className="w-full" {...gridProps}>
16
+ <thead {...headerProps}>
17
+ <tr>
18
+ {weekDays.map((day, index) => (
19
+ <th key={index} className="text-text size-6 text-center text-[0.75rem] font-semibold leading-9">
20
+ {day.toUpperCase().slice(0, 2)}
21
+ </th>
22
+ ))}
23
+ </tr>
24
+ </thead>
25
+ <tbody>
26
+ {[...new Array(weeksInMonth).keys()].map(weekIndex => (
27
+ <tr key={weekIndex}>
28
+ {state
29
+ .getDatesInWeek(weekIndex)
30
+ .map((date, i) => (date ? <CalendarCell key={i} state={state} date={date} /> : <td key={i} />))}
31
+ </tr>
32
+ ))}
33
+ </tbody>
34
+ </table>
35
+ );
36
+ }
@@ -0,0 +1,4 @@
1
+ import { AriaCalendarGridProps } from 'react-aria';
2
+ import { CalendarState, RangeCalendarState } from 'react-stately';
3
+
4
+ export type CalendarGridProps = AriaCalendarGridProps & { state: CalendarState | RangeCalendarState };
@@ -0,0 +1,21 @@
1
+ import React from 'react';
2
+ import { useFocusRing } from 'react-aria';
3
+
4
+ import { ExpandMoreIcon } from '../../../../../icon/index.js';
5
+
6
+ import { styles as selectStyles } from './select.styles.js';
7
+ import { SelectProps } from './select.types.js';
8
+
9
+ /**
10
+ * @private
11
+ */
12
+ export function Select({ ...props }: SelectProps) {
13
+ const { isFocusVisible, focusProps } = useFocusRing();
14
+ const styles = selectStyles({ isFocusVisible });
15
+ return (
16
+ <div className="relative">
17
+ <select {...focusProps} className={styles.base({ className: props.className })} {...props} />
18
+ <ExpandMoreIcon color="primary" size="small" className={styles.caret()} />
19
+ </div>
20
+ );
21
+ }
@@ -0,0 +1,13 @@
1
+ import { tv } from 'tailwind-variants';
2
+
3
+ export const styles = tv({
4
+ slots: {
5
+ base: '!typography-body-8 appearance-none border-none !bg-none pl-0 pr-4 font-semibold',
6
+ caret: 'pointer-events-none absolute right-0 top-1/2 -translate-y-1/2 touch-none',
7
+ },
8
+ variants: {
9
+ isFocusVisible: {
10
+ true: { base: 'focus-outline' },
11
+ },
12
+ },
13
+ });
@@ -0,0 +1,3 @@
1
+ import { SelectHTMLAttributes } from 'react';
2
+
3
+ export type SelectProps = SelectHTMLAttributes<HTMLSelectElement>;
@@ -0,0 +1,26 @@
1
+ 'use client';
2
+
3
+ import React, { useRef } from 'react';
4
+ import { mergeProps, useDateSegment, useFocusRing } from 'react-aria';
5
+
6
+ import { styles as dateSegmentStyles } from './date-segment.styles.js';
7
+ import { DateSegmentProps } from './date-segment.types.js';
8
+
9
+ /**
10
+ * @private
11
+ */
12
+ export function DateSegment({ segment, state, separator, ...props }: DateSegmentProps) {
13
+ const ref = useRef(null);
14
+ const { focusProps, isFocusVisible } = useFocusRing();
15
+ const { segmentProps } = useDateSegment(segment, state, ref);
16
+ const styles = dateSegmentStyles({
17
+ isFocusVisible,
18
+ isPlaceholder: segment.isPlaceholder,
19
+ isSeparator: segmentProps.role !== 'spinbutton',
20
+ });
21
+ return (
22
+ <span {...props} {...mergeProps(focusProps, segmentProps)} ref={ref} className={styles}>
23
+ {segment.type === 'literal' ? separator || segment.text : segment.text}
24
+ </span>
25
+ );
26
+ }
@@ -0,0 +1,22 @@
1
+ import { tv } from 'tailwind-variants';
2
+
3
+ export const styles = tv(
4
+ {
5
+ base: 'font-light disabled:form-control-disabled',
6
+ variants: {
7
+ isPlaceholder: {
8
+ true: 'text-text-50 opacity-100',
9
+ false: '',
10
+ },
11
+ isFocusVisible: {
12
+ true: 'focus-outline',
13
+ false: '',
14
+ },
15
+ isSeparator: {
16
+ true: 'px-0.5 text-text-50',
17
+ false: '',
18
+ },
19
+ },
20
+ },
21
+ { responsiveVariants: ['xsl', 'sm', 'md', 'lg', 'xl'] },
22
+ );
@@ -0,0 +1,8 @@
1
+ import { HTMLAttributes } from 'react';
2
+ import { DateFieldState, DateSegment } from 'react-stately';
3
+
4
+ export type DateSegmentProps = {
5
+ segment: DateSegment;
6
+ separator?: string;
7
+ state: DateFieldState;
8
+ } & HTMLAttributes<Element>;
@@ -0,0 +1,32 @@
1
+ 'use client';
2
+
3
+ import { createCalendar } from '@internationalized/date';
4
+ import React, { useRef } from 'react';
5
+ import { useDateField, useLocale } from 'react-aria';
6
+ import { useDateFieldState } from 'react-stately';
7
+
8
+ import { DateSegment } from './components/date-segment/date-segment.component.js';
9
+ import { type DateFieldProps } from './date-field.types.js';
10
+
11
+ /**
12
+ * @private
13
+ */
14
+ export function DateField({ separator, ...props }: DateFieldProps) {
15
+ const { locale } = useLocale();
16
+ const state = useDateFieldState({
17
+ ...props,
18
+ locale,
19
+ createCalendar,
20
+ });
21
+
22
+ const ref = useRef(null);
23
+ const { fieldProps } = useDateField(props, state, ref);
24
+
25
+ return (
26
+ <div {...fieldProps} ref={ref}>
27
+ {state.segments.map((segment, i) => (
28
+ <DateSegment separator={separator} key={i} segment={segment} state={state} />
29
+ ))}
30
+ </div>
31
+ );
32
+ }
@@ -0,0 +1,3 @@
1
+ import { AriaDateFieldProps, DateValue } from 'react-aria';
2
+
3
+ export type DateFieldProps<T extends DateValue = DateValue> = AriaDateFieldProps<T> & { separator?: string };
@@ -0,0 +1,23 @@
1
+ import React, { useRef } from 'react';
2
+ import { useDialog } from 'react-aria';
3
+
4
+ import { DialogProps } from './dialog.types.js';
5
+
6
+ /**
7
+ * @private
8
+ */
9
+ export function Dialog({ title, children, ...props }: DialogProps) {
10
+ const ref = useRef(null);
11
+ const { dialogProps, titleProps } = useDialog(props, ref);
12
+
13
+ return (
14
+ <div {...dialogProps} ref={ref} className="p-3">
15
+ {title && (
16
+ <h3 {...titleProps} style={{ marginTop: 0 }}>
17
+ {title}
18
+ </h3>
19
+ )}
20
+ {children}
21
+ </div>
22
+ );
23
+ }
@@ -0,0 +1,4 @@
1
+ import { HTMLAttributes } from 'react';
2
+ import { AriaDialogProps } from 'react-aria';
3
+
4
+ export type DialogProps = AriaDialogProps & HTMLAttributes<Element>;
@@ -0,0 +1,34 @@
1
+ import React, { useRef } from 'react';
2
+ import { Overlay, usePopover } from 'react-aria';
3
+
4
+ import { CloseIcon } from '../../../icon/index.js';
5
+
6
+ import { styles as popoverStyles } from './popover.styles.js';
7
+ import { PopoverProps } from './popover.types.js';
8
+
9
+ /**
10
+ * @private
11
+ */
12
+ export function Popover({ state, portalContainer, children, showAsBottomSheet, ...props }: PopoverProps) {
13
+ const ref = useRef(null);
14
+ const { popoverProps, underlayProps } = usePopover(
15
+ { ...props, popoverRef: ref, containerPadding: 0, offset: 0 },
16
+ state,
17
+ );
18
+ const styles = popoverStyles({ showAsBottomSheet });
19
+
20
+ return (
21
+ <Overlay portalContainer={portalContainer}>
22
+ <div {...underlayProps} className={styles.underlay()} />
23
+ <div {...popoverProps} ref={ref} className={styles.popover()}>
24
+ <div className={styles.header()}>
25
+ <p className={styles.headerLabel()}>Choose a date</p>
26
+ <button className={styles.closeButton()} onClick={() => state.close()} aria-label="Close window">
27
+ <CloseIcon color="primary" className="block" size="small" />
28
+ </button>
29
+ </div>
30
+ {children}
31
+ </div>
32
+ </Overlay>
33
+ );
34
+ }