@westpac/ui 0.48.0 → 0.50.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.
- package/CHANGELOG.md +21 -0
- package/dist/component-type.json +1 -1
- package/dist/components/accordion/components/accordion-item/accordion-item.component.js +3 -2
- package/dist/components/button-dropdown/button-dropdown.component.d.ts +1 -1
- package/dist/components/button-dropdown/button-dropdown.component.js +3 -2
- package/dist/components/button-dropdown/button-dropdown.types.d.ts +2 -1
- package/dist/components/button-dropdown/components/button-dropdown-panel/button-dropdown-panel.component.js +0 -1
- package/dist/components/button-dropdown/components/button-dropdown-panel/button-dropdown-panel.styles.js +1 -1
- package/dist/components/date-picker-beta/components/calendar/calendar.component.d.ts +5 -0
- package/dist/components/date-picker-beta/components/calendar/calendar.component.js +101 -0
- package/dist/components/date-picker-beta/components/calendar/calendar.types.d.ts +2 -0
- package/dist/components/date-picker-beta/components/calendar/calendar.types.js +1 -0
- package/dist/components/date-picker-beta/components/calendar/components/calendar-cell/calendar-cell.component.d.ts +5 -0
- package/dist/components/date-picker-beta/components/calendar/components/calendar-cell/calendar-cell.component.js +28 -0
- package/dist/components/date-picker-beta/components/calendar/components/calendar-cell/calendar-cell.styles.d.ts +103 -0
- package/dist/components/date-picker-beta/components/calendar/components/calendar-cell/calendar-cell.styles.js +39 -0
- package/dist/components/date-picker-beta/components/calendar/components/calendar-cell/calendar-cell.types.d.ts +5 -0
- package/dist/components/date-picker-beta/components/calendar/components/calendar-cell/calendar-cell.types.js +1 -0
- package/dist/components/date-picker-beta/components/calendar/components/calendar-grid/calendar-grid.component.d.ts +5 -0
- package/dist/components/date-picker-beta/components/calendar/components/calendar-grid/calendar-grid.component.js +26 -0
- package/dist/components/date-picker-beta/components/calendar/components/calendar-grid/calendar-grid.types.d.ts +5 -0
- package/dist/components/date-picker-beta/components/calendar/components/calendar-grid/calendar-grid.types.js +1 -0
- package/dist/components/date-picker-beta/components/calendar/components/select/select.component.d.ts +5 -0
- package/dist/components/date-picker-beta/components/calendar/components/select/select.component.js +23 -0
- package/dist/components/date-picker-beta/components/calendar/components/select/select.styles.d.ts +28 -0
- package/dist/components/date-picker-beta/components/calendar/components/select/select.styles.js +14 -0
- package/dist/components/date-picker-beta/components/calendar/components/select/select.types.d.ts +2 -0
- package/dist/components/date-picker-beta/components/calendar/components/select/select.types.js +1 -0
- package/dist/components/date-picker-beta/components/date-field/components/date-segment/date-segment.component.d.ts +5 -0
- package/dist/components/date-picker-beta/components/date-field/components/date-segment/date-segment.component.js +20 -0
- package/dist/components/date-picker-beta/components/date-field/components/date-segment/date-segment.styles.d.ts +44 -0
- package/dist/components/date-picker-beta/components/date-field/components/date-segment/date-segment.styles.js +26 -0
- package/dist/components/date-picker-beta/components/date-field/components/date-segment/date-segment.types.d.ts +7 -0
- package/dist/components/date-picker-beta/components/date-field/components/date-segment/date-segment.types.js +1 -0
- package/dist/components/date-picker-beta/components/date-field/date-field.component.d.ts +5 -0
- package/dist/components/date-picker-beta/components/date-field/date-field.component.js +25 -0
- package/dist/components/date-picker-beta/components/date-field/date-field.types.d.ts +4 -0
- package/dist/components/date-picker-beta/components/date-field/date-field.types.js +1 -0
- package/dist/components/date-picker-beta/components/dialog/dialog.component.d.ts +5 -0
- package/dist/components/date-picker-beta/components/dialog/dialog.component.js +16 -0
- package/dist/components/date-picker-beta/components/dialog/dialog.types.d.ts +3 -0
- package/dist/components/date-picker-beta/components/dialog/dialog.types.js +1 -0
- package/dist/components/date-picker-beta/components/popover/popover.component.d.ts +5 -0
- package/dist/components/date-picker-beta/components/popover/popover.component.js +38 -0
- package/dist/components/date-picker-beta/components/popover/popover.styles.d.ts +71 -0
- package/dist/components/date-picker-beta/components/popover/popover.styles.js +35 -0
- package/dist/components/date-picker-beta/components/popover/popover.types.d.ts +9 -0
- package/dist/components/date-picker-beta/components/popover/popover.types.js +1 -0
- package/dist/components/date-picker-beta/date-picker.component.d.ts +2 -0
- package/dist/components/date-picker-beta/date-picker.component.js +114 -0
- package/dist/components/date-picker-beta/date-picker.styles.d.ts +107 -0
- package/dist/components/date-picker-beta/date-picker.styles.js +47 -0
- package/dist/components/date-picker-beta/date-picker.types.d.ts +32 -0
- package/dist/components/date-picker-beta/date-picker.types.js +1 -0
- package/dist/components/date-picker-beta/index.d.ts +2 -0
- package/dist/components/date-picker-beta/index.js +1 -0
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.js +1 -0
- package/dist/components/input-group/input-group.component.d.ts +1 -1
- package/dist/components/input-group/input-group.component.js +9 -3
- package/dist/components/input-group/input-group.styles.js +1 -1
- package/dist/components/input-group/input-group.types.d.ts +16 -0
- package/dist/css/westpac-ui.css +1015 -3
- package/dist/css/westpac-ui.min.css +1015 -3
- package/dist/tailwind/constants/colors.d.ts +25 -25
- package/dist/tailwind/tailwind-plugin.js +20 -0
- package/dist/tailwind/themes/index.d.ts +27 -27
- package/package.json +7 -3
- package/src/components/accordion/components/accordion-item/accordion-item.component.tsx +23 -24
- package/src/components/button-dropdown/button-dropdown.component.tsx +2 -0
- package/src/components/button-dropdown/button-dropdown.types.ts +3 -1
- package/src/components/button-dropdown/components/button-dropdown-panel/button-dropdown-panel.component.tsx +1 -1
- package/src/components/button-dropdown/components/button-dropdown-panel/button-dropdown-panel.styles.ts +1 -1
- package/src/components/date-picker-beta/components/calendar/calendar.component.tsx +106 -0
- package/src/components/date-picker-beta/components/calendar/calendar.types.ts +3 -0
- package/src/components/date-picker-beta/components/calendar/components/calendar-cell/calendar-cell.component.tsx +42 -0
- package/src/components/date-picker-beta/components/calendar/components/calendar-cell/calendar-cell.styles.ts +40 -0
- package/src/components/date-picker-beta/components/calendar/components/calendar-cell/calendar-cell.types.ts +8 -0
- package/src/components/date-picker-beta/components/calendar/components/calendar-grid/calendar-grid.component.tsx +36 -0
- package/src/components/date-picker-beta/components/calendar/components/calendar-grid/calendar-grid.types.ts +4 -0
- package/src/components/date-picker-beta/components/calendar/components/select/select.component.tsx +21 -0
- package/src/components/date-picker-beta/components/calendar/components/select/select.styles.ts +13 -0
- package/src/components/date-picker-beta/components/calendar/components/select/select.types.ts +3 -0
- package/src/components/date-picker-beta/components/date-field/components/date-segment/date-segment.component.tsx +26 -0
- package/src/components/date-picker-beta/components/date-field/components/date-segment/date-segment.styles.ts +22 -0
- package/src/components/date-picker-beta/components/date-field/components/date-segment/date-segment.types.ts +8 -0
- package/src/components/date-picker-beta/components/date-field/date-field.component.tsx +32 -0
- package/src/components/date-picker-beta/components/date-field/date-field.types.ts +3 -0
- package/src/components/date-picker-beta/components/dialog/dialog.component.tsx +23 -0
- package/src/components/date-picker-beta/components/dialog/dialog.types.ts +4 -0
- package/src/components/date-picker-beta/components/popover/popover.component.tsx +34 -0
- package/src/components/date-picker-beta/components/popover/popover.styles.ts +34 -0
- package/src/components/date-picker-beta/components/popover/popover.types.ts +10 -0
- package/src/components/date-picker-beta/date-picker.component.tsx +114 -0
- package/src/components/date-picker-beta/date-picker.styles.ts +44 -0
- package/src/components/date-picker-beta/date-picker.types.ts +40 -0
- package/src/components/date-picker-beta/index.ts +2 -0
- package/src/components/index.ts +1 -0
- package/src/components/input-group/input-group.component.tsx +9 -3
- package/src/components/input-group/input-group.styles.ts +1 -1
- package/src/components/input-group/input-group.types.ts +16 -0
- package/src/tailwind/tailwind-plugin.ts +20 -0
|
@@ -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,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
|
+
}
|
package/src/components/date-picker-beta/components/calendar/components/select/select.component.tsx
ADDED
|
@@ -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
|
+
}
|
package/src/components/date-picker-beta/components/calendar/components/select/select.styles.ts
ADDED
|
@@ -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,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,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,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,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
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { tv } from 'tailwind-variants';
|
|
2
|
+
|
|
3
|
+
export const styles = tv(
|
|
4
|
+
{
|
|
5
|
+
slots: {
|
|
6
|
+
underlay: 'fixed inset-0',
|
|
7
|
+
popover: 'bg-white',
|
|
8
|
+
header: '',
|
|
9
|
+
headerLabel: '',
|
|
10
|
+
closeButton: 'flex items-center justify-center focus-outline',
|
|
11
|
+
},
|
|
12
|
+
variants: {
|
|
13
|
+
showAsBottomSheet: {
|
|
14
|
+
true: {
|
|
15
|
+
underlay: 'animate-fadeIn bg-black/20',
|
|
16
|
+
popover: '!fixed inset-x-0 !bottom-0 !left-0 !top-auto animate-slideUp overflow-auto rounded-t px-[8%] pb-3',
|
|
17
|
+
header: 'mx-[-8vw] flex items-center justify-between border-b border-b-border px-3.5 py-2',
|
|
18
|
+
headerLabel: 'typography-body-10 text-text',
|
|
19
|
+
closeButton:
|
|
20
|
+
'pointer-events-none touch-none rounded-full bg-white opacity-0 focus:pointer-events-auto focus:touch-auto focus:opacity-100',
|
|
21
|
+
},
|
|
22
|
+
false: {
|
|
23
|
+
underlay: '',
|
|
24
|
+
closeButton:
|
|
25
|
+
'border-border pointer-events-none absolute right-0 top-0 size-5 -translate-y-1/2 translate-x-1/2 touch-none rounded-full border bg-white opacity-0 focus:pointer-events-auto focus:touch-auto focus:opacity-100',
|
|
26
|
+
headerLabel: 'hidden',
|
|
27
|
+
popover:
|
|
28
|
+
'absolute mt-1 scale-100 animate-fadeIn rounded border border-border bg-white opacity-100 shadow-[0_5px_10px_rgba(0,0,0,0.2)]',
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
{ responsiveVariants: ['xsl', 'sm', 'md', 'lg', 'xl'] },
|
|
34
|
+
);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { AriaPopoverProps } from 'react-aria';
|
|
3
|
+
import { OverlayTriggerState } from 'react-stately';
|
|
4
|
+
|
|
5
|
+
export type PopoverProps = Omit<AriaPopoverProps, 'popoverRef'> & {
|
|
6
|
+
children: ReactNode;
|
|
7
|
+
showAsBottomSheet?: boolean;
|
|
8
|
+
state: OverlayTriggerState;
|
|
9
|
+
portalContainer?: Element;
|
|
10
|
+
};
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { DateValue, getDayOfWeek, isWeekend } from '@internationalized/date';
|
|
4
|
+
import React, { useMemo, useRef } from 'react';
|
|
5
|
+
import { useButton, useDatePicker, useLocale } from 'react-aria';
|
|
6
|
+
import { useDatePickerState } from 'react-stately';
|
|
7
|
+
|
|
8
|
+
import { useBreakpoint } from '../../hook/breakpoints.hook.js';
|
|
9
|
+
import { Breakpoint } from '../../tailwind/constants/index.js';
|
|
10
|
+
import { Button } from '../button/index.js';
|
|
11
|
+
import { CalendarIcon } from '../icon/index.js';
|
|
12
|
+
|
|
13
|
+
import { Calendar } from './components/calendar/calendar.component.js';
|
|
14
|
+
import { DateField } from './components/date-field/date-field.component.js';
|
|
15
|
+
import { Dialog } from './components/dialog/dialog.component.js';
|
|
16
|
+
import { Popover } from './components/popover/popover.component.js';
|
|
17
|
+
import { styles as datePickerStyles } from './date-picker.styles.js';
|
|
18
|
+
import { type DatePickerBetaProps } from './date-picker.types.js';
|
|
19
|
+
|
|
20
|
+
const BREAKPOINTS_DECRECENT = ['xl', 'lg', 'md', 'sm', 'xsl', 'initial'] as const;
|
|
21
|
+
export function DatePickerBeta({
|
|
22
|
+
size = 'medium',
|
|
23
|
+
className,
|
|
24
|
+
bottomSheetView = { initial: true, xsl: false },
|
|
25
|
+
isDateUnavailable,
|
|
26
|
+
disableDaysOfWeek,
|
|
27
|
+
disableWeekends,
|
|
28
|
+
separator,
|
|
29
|
+
portalContainer,
|
|
30
|
+
...props
|
|
31
|
+
}: DatePickerBetaProps) {
|
|
32
|
+
const { locale } = useLocale();
|
|
33
|
+
|
|
34
|
+
const enhancedIsDateUnavailable = useMemo(() => {
|
|
35
|
+
return disableDaysOfWeek || disableWeekends
|
|
36
|
+
? (date: DateValue) => {
|
|
37
|
+
let conditions = [isDateUnavailable?.(date) || false];
|
|
38
|
+
if (disableDaysOfWeek) {
|
|
39
|
+
conditions = [disableDaysOfWeek.indexOf(getDayOfWeek(date, locale)) !== -1, ...conditions];
|
|
40
|
+
}
|
|
41
|
+
if (disableWeekends) {
|
|
42
|
+
conditions = [isWeekend(date, locale), ...conditions];
|
|
43
|
+
}
|
|
44
|
+
return conditions.some(condition => condition);
|
|
45
|
+
}
|
|
46
|
+
: isDateUnavailable;
|
|
47
|
+
}, [disableDaysOfWeek, disableWeekends, isDateUnavailable, locale]);
|
|
48
|
+
|
|
49
|
+
const state = useDatePickerState({ isDateUnavailable: enhancedIsDateUnavailable, ...props });
|
|
50
|
+
const styles = datePickerStyles({ size, isInvalid: state.isInvalid, isDisabled: props.isDisabled });
|
|
51
|
+
const breakpoint = useBreakpoint();
|
|
52
|
+
const ref = useRef(null);
|
|
53
|
+
|
|
54
|
+
const { groupProps, labelProps, fieldProps, buttonProps, dialogProps, calendarProps } = useDatePicker(
|
|
55
|
+
{ isDateUnavailable: enhancedIsDateUnavailable, ...props },
|
|
56
|
+
state,
|
|
57
|
+
ref,
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
const showAsBottomSheet: boolean = useMemo(() => {
|
|
61
|
+
if (typeof bottomSheetView === 'boolean') {
|
|
62
|
+
return bottomSheetView;
|
|
63
|
+
}
|
|
64
|
+
const currentBreakpointIndex = BREAKPOINTS_DECRECENT.findIndex(bp => bp === breakpoint);
|
|
65
|
+
const finalBreakPoint = [breakpoint, ...BREAKPOINTS_DECRECENT.slice(currentBreakpointIndex)].find(
|
|
66
|
+
currentBreakpoint => bottomSheetView[currentBreakpoint] !== undefined,
|
|
67
|
+
) as Breakpoint | 'initial';
|
|
68
|
+
|
|
69
|
+
return bottomSheetView[finalBreakPoint] || false;
|
|
70
|
+
}, [bottomSheetView, breakpoint]);
|
|
71
|
+
|
|
72
|
+
const buttonRef = useRef(null);
|
|
73
|
+
|
|
74
|
+
const { buttonProps: newButtonProps } = useButton(buttonProps, buttonRef);
|
|
75
|
+
|
|
76
|
+
const brandContainer = useMemo(() => {
|
|
77
|
+
return (
|
|
78
|
+
document.querySelector('[data-theme]') ||
|
|
79
|
+
document.querySelector('[class^="theme-"], [class*=" theme-"]') ||
|
|
80
|
+
undefined
|
|
81
|
+
);
|
|
82
|
+
}, []);
|
|
83
|
+
|
|
84
|
+
return (
|
|
85
|
+
<>
|
|
86
|
+
<div {...labelProps}>{props.label}</div>
|
|
87
|
+
<div {...props} {...groupProps} ref={ref} className={styles.input({ className })}>
|
|
88
|
+
<DateField separator={separator} {...fieldProps} />
|
|
89
|
+
<Button
|
|
90
|
+
look="faint"
|
|
91
|
+
className={styles.button()}
|
|
92
|
+
iconColor="muted"
|
|
93
|
+
size={size}
|
|
94
|
+
iconAfter={CalendarIcon}
|
|
95
|
+
{...newButtonProps}
|
|
96
|
+
aria-labelledby={undefined}
|
|
97
|
+
/>
|
|
98
|
+
</div>
|
|
99
|
+
{state.isOpen && (
|
|
100
|
+
<Popover
|
|
101
|
+
portalContainer={portalContainer || brandContainer}
|
|
102
|
+
showAsBottomSheet={showAsBottomSheet}
|
|
103
|
+
state={state}
|
|
104
|
+
triggerRef={ref}
|
|
105
|
+
placement="bottom left"
|
|
106
|
+
>
|
|
107
|
+
<Dialog {...dialogProps}>
|
|
108
|
+
<Calendar {...calendarProps} firstDayOfWeek={props.firstDayOfWeek} />
|
|
109
|
+
</Dialog>
|
|
110
|
+
</Popover>
|
|
111
|
+
)}
|
|
112
|
+
</>
|
|
113
|
+
);
|
|
114
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { tv } from 'tailwind-variants';
|
|
2
|
+
|
|
3
|
+
export const styles = tv(
|
|
4
|
+
{
|
|
5
|
+
slots: {
|
|
6
|
+
input: 'form-control flex items-center border-borderDark disabled:form-control-disabled',
|
|
7
|
+
button:
|
|
8
|
+
'flex h-auto items-center justify-center rounded-l-none border-y-0 border-l border-r-0 border-l-borderDark bg-light',
|
|
9
|
+
},
|
|
10
|
+
variants: {
|
|
11
|
+
size: {
|
|
12
|
+
small: {
|
|
13
|
+
input: 'form-control-small gap-1.5',
|
|
14
|
+
button: '-my-0.5 -mr-1.5 mb-[-0.25rem] min-h-5 py-[0.25rem]',
|
|
15
|
+
},
|
|
16
|
+
medium: {
|
|
17
|
+
input: 'form-control-medium gap-2',
|
|
18
|
+
button: 'my-[-0.3125rem] -mr-2 min-h-6 py-[0.3125rem]',
|
|
19
|
+
},
|
|
20
|
+
large: {
|
|
21
|
+
input: 'form-control-large gap-2.5',
|
|
22
|
+
button: 'my-[-0.5rem] -mr-2.5 min-h-7 py-[0.5rem]',
|
|
23
|
+
},
|
|
24
|
+
xlarge: {
|
|
25
|
+
input: 'form-control-xlarge gap-3',
|
|
26
|
+
button: '-my-1.5 -mr-3 mb-[-0.625rem] min-h-8 py-1.5',
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
isInvalid: {
|
|
30
|
+
true: {
|
|
31
|
+
input: 'border-danger',
|
|
32
|
+
},
|
|
33
|
+
false: {},
|
|
34
|
+
},
|
|
35
|
+
isDisabled: {
|
|
36
|
+
true: {
|
|
37
|
+
input: 'form-control-disabled',
|
|
38
|
+
},
|
|
39
|
+
false: {},
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
{ responsiveVariants: ['xsl', 'sm', 'md', 'lg', 'xl'] },
|
|
44
|
+
);
|