@cdx-ui/components 0.0.1-beta.140 → 0.0.1-beta.141
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/lib/commonjs/components/BottomSheet/index.js +8 -2
- package/lib/commonjs/components/BottomSheet/index.js.map +1 -1
- package/lib/commonjs/components/Calendar/CalendarMonthHeader.js +96 -0
- package/lib/commonjs/components/Calendar/CalendarMonthHeader.js.map +1 -0
- package/lib/commonjs/components/Calendar/CalendarYearPickerGrid.js +74 -0
- package/lib/commonjs/components/Calendar/CalendarYearPickerGrid.js.map +1 -0
- package/lib/commonjs/components/Calendar/flashCalendarAdapter.js +298 -0
- package/lib/commonjs/components/Calendar/flashCalendarAdapter.js.map +1 -0
- package/lib/commonjs/components/Calendar/index.js +149 -0
- package/lib/commonjs/components/Calendar/index.js.map +1 -0
- package/lib/commonjs/components/Calendar/styles.js +70 -0
- package/lib/commonjs/components/Calendar/styles.js.map +1 -0
- package/lib/commonjs/components/DateField/index.js +147 -0
- package/lib/commonjs/components/DateField/index.js.map +1 -0
- package/lib/commonjs/components/DateField/styles.js +34 -0
- package/lib/commonjs/components/DateField/styles.js.map +1 -0
- package/lib/commonjs/components/DatePicker/index.js +163 -0
- package/lib/commonjs/components/DatePicker/index.js.map +1 -0
- package/lib/commonjs/components/DateRangePicker/index.js +177 -0
- package/lib/commonjs/components/DateRangePicker/index.js.map +1 -0
- package/lib/commonjs/components/DateTimeField/index.js +96 -0
- package/lib/commonjs/components/DateTimeField/index.js.map +1 -0
- package/lib/commonjs/components/DateTimeList/index.js +180 -0
- package/lib/commonjs/components/DateTimeList/index.js.map +1 -0
- package/lib/commonjs/components/DateTimeList/styles.js +55 -0
- package/lib/commonjs/components/DateTimeList/styles.js.map +1 -0
- package/lib/commonjs/components/DateTimePicker/index.js +187 -0
- package/lib/commonjs/components/DateTimePicker/index.js.map +1 -0
- package/lib/commonjs/components/MonthCalendar/index.js +229 -0
- package/lib/commonjs/components/MonthCalendar/index.js.map +1 -0
- package/lib/commonjs/components/MonthPicker/index.js +163 -0
- package/lib/commonjs/components/MonthPicker/index.js.map +1 -0
- package/lib/commonjs/components/RangeCalendar/index.js +165 -0
- package/lib/commonjs/components/RangeCalendar/index.js.map +1 -0
- package/lib/commonjs/components/index.js +120 -0
- package/lib/commonjs/components/index.js.map +1 -1
- package/lib/commonjs/components/picker/PickerTrigger.js +49 -0
- package/lib/commonjs/components/picker/PickerTrigger.js.map +1 -0
- package/lib/commonjs/components/picker/styles.js +15 -0
- package/lib/commonjs/components/picker/styles.js.map +1 -0
- package/lib/commonjs/components/picker/surfaces.js +141 -0
- package/lib/commonjs/components/picker/surfaces.js.map +1 -0
- package/lib/module/components/BottomSheet/index.js +8 -2
- package/lib/module/components/BottomSheet/index.js.map +1 -1
- package/lib/module/components/Calendar/CalendarMonthHeader.js +92 -0
- package/lib/module/components/Calendar/CalendarMonthHeader.js.map +1 -0
- package/lib/module/components/Calendar/CalendarYearPickerGrid.js +70 -0
- package/lib/module/components/Calendar/CalendarYearPickerGrid.js.map +1 -0
- package/lib/module/components/Calendar/flashCalendarAdapter.js +290 -0
- package/lib/module/components/Calendar/flashCalendarAdapter.js.map +1 -0
- package/lib/module/components/Calendar/index.js +145 -0
- package/lib/module/components/Calendar/index.js.map +1 -0
- package/lib/module/components/Calendar/styles.js +66 -0
- package/lib/module/components/Calendar/styles.js.map +1 -0
- package/lib/module/components/DateField/index.js +143 -0
- package/lib/module/components/DateField/index.js.map +1 -0
- package/lib/module/components/DateField/styles.js +30 -0
- package/lib/module/components/DateField/styles.js.map +1 -0
- package/lib/module/components/DatePicker/index.js +159 -0
- package/lib/module/components/DatePicker/index.js.map +1 -0
- package/lib/module/components/DateRangePicker/index.js +173 -0
- package/lib/module/components/DateRangePicker/index.js.map +1 -0
- package/lib/module/components/DateTimeField/index.js +92 -0
- package/lib/module/components/DateTimeField/index.js.map +1 -0
- package/lib/module/components/DateTimeList/index.js +176 -0
- package/lib/module/components/DateTimeList/index.js.map +1 -0
- package/lib/module/components/DateTimeList/styles.js +52 -0
- package/lib/module/components/DateTimeList/styles.js.map +1 -0
- package/lib/module/components/DateTimePicker/index.js +183 -0
- package/lib/module/components/DateTimePicker/index.js.map +1 -0
- package/lib/module/components/MonthCalendar/index.js +225 -0
- package/lib/module/components/MonthCalendar/index.js.map +1 -0
- package/lib/module/components/MonthPicker/index.js +159 -0
- package/lib/module/components/MonthPicker/index.js.map +1 -0
- package/lib/module/components/RangeCalendar/index.js +161 -0
- package/lib/module/components/RangeCalendar/index.js.map +1 -0
- package/lib/module/components/index.js +10 -0
- package/lib/module/components/index.js.map +1 -1
- package/lib/module/components/picker/PickerTrigger.js +45 -0
- package/lib/module/components/picker/PickerTrigger.js.map +1 -0
- package/lib/module/components/picker/styles.js +12 -0
- package/lib/module/components/picker/styles.js.map +1 -0
- package/lib/module/components/picker/surfaces.js +135 -0
- package/lib/module/components/picker/surfaces.js.map +1 -0
- package/lib/typescript/components/BottomSheet/index.d.ts +2 -2
- package/lib/typescript/components/BottomSheet/index.d.ts.map +1 -1
- package/lib/typescript/components/Calendar/CalendarMonthHeader.d.ts +14 -0
- package/lib/typescript/components/Calendar/CalendarMonthHeader.d.ts.map +1 -0
- package/lib/typescript/components/Calendar/CalendarYearPickerGrid.d.ts +12 -0
- package/lib/typescript/components/Calendar/CalendarYearPickerGrid.d.ts.map +1 -0
- package/lib/typescript/components/Calendar/flashCalendarAdapter.d.ts +18 -0
- package/lib/typescript/components/Calendar/flashCalendarAdapter.d.ts.map +1 -0
- package/lib/typescript/components/Calendar/index.d.ts +19 -0
- package/lib/typescript/components/Calendar/index.d.ts.map +1 -0
- package/lib/typescript/components/Calendar/styles.d.ts +23 -0
- package/lib/typescript/components/Calendar/styles.d.ts.map +1 -0
- package/lib/typescript/components/DateField/index.d.ts +43 -0
- package/lib/typescript/components/DateField/index.d.ts.map +1 -0
- package/lib/typescript/components/DateField/styles.d.ts +15 -0
- package/lib/typescript/components/DateField/styles.d.ts.map +1 -0
- package/lib/typescript/components/DatePicker/index.d.ts +40 -0
- package/lib/typescript/components/DatePicker/index.d.ts.map +1 -0
- package/lib/typescript/components/DateRangePicker/index.d.ts +45 -0
- package/lib/typescript/components/DateRangePicker/index.d.ts.map +1 -0
- package/lib/typescript/components/DateTimeField/index.d.ts +29 -0
- package/lib/typescript/components/DateTimeField/index.d.ts.map +1 -0
- package/lib/typescript/components/DateTimeList/index.d.ts +19 -0
- package/lib/typescript/components/DateTimeList/index.d.ts.map +1 -0
- package/lib/typescript/components/DateTimeList/styles.d.ts +17 -0
- package/lib/typescript/components/DateTimeList/styles.d.ts.map +1 -0
- package/lib/typescript/components/DateTimePicker/index.d.ts +40 -0
- package/lib/typescript/components/DateTimePicker/index.d.ts.map +1 -0
- package/lib/typescript/components/MonthCalendar/index.d.ts +29 -0
- package/lib/typescript/components/MonthCalendar/index.d.ts.map +1 -0
- package/lib/typescript/components/MonthPicker/index.d.ts +40 -0
- package/lib/typescript/components/MonthPicker/index.d.ts.map +1 -0
- package/lib/typescript/components/RangeCalendar/index.d.ts +19 -0
- package/lib/typescript/components/RangeCalendar/index.d.ts.map +1 -0
- package/lib/typescript/components/index.d.ts +10 -0
- package/lib/typescript/components/index.d.ts.map +1 -1
- package/lib/typescript/components/picker/PickerTrigger.d.ts +25 -0
- package/lib/typescript/components/picker/PickerTrigger.d.ts.map +1 -0
- package/lib/typescript/components/picker/styles.d.ts +4 -0
- package/lib/typescript/components/picker/styles.d.ts.map +1 -0
- package/lib/typescript/components/picker/surfaces.d.ts +28 -0
- package/lib/typescript/components/picker/surfaces.d.ts.map +1 -0
- package/package.json +6 -4
- package/src/components/BottomSheet/index.tsx +7 -1
- package/src/components/Calendar/CalendarMonthHeader.tsx +124 -0
- package/src/components/Calendar/CalendarYearPickerGrid.tsx +101 -0
- package/src/components/Calendar/flashCalendarAdapter.ts +362 -0
- package/src/components/Calendar/index.tsx +151 -0
- package/src/components/Calendar/styles.ts +80 -0
- package/src/components/DateField/index.tsx +196 -0
- package/src/components/DateField/styles.ts +51 -0
- package/src/components/DatePicker/index.tsx +187 -0
- package/src/components/DateRangePicker/index.tsx +202 -0
- package/src/components/DateTimeField/index.tsx +128 -0
- package/src/components/DateTimeList/index.tsx +187 -0
- package/src/components/DateTimeList/styles.ts +59 -0
- package/src/components/DateTimePicker/index.tsx +233 -0
- package/src/components/MonthCalendar/index.tsx +252 -0
- package/src/components/MonthPicker/index.tsx +188 -0
- package/src/components/RangeCalendar/index.tsx +162 -0
- package/src/components/index.ts +10 -0
- package/src/components/picker/PickerTrigger.tsx +65 -0
- package/src/components/picker/styles.ts +17 -0
- package/src/components/picker/surfaces.tsx +174 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { forwardRef, useMemo, type ReactNode } from 'react';
|
|
2
|
+
import { View, type ViewProps } from 'react-native';
|
|
3
|
+
import {
|
|
4
|
+
DateTimeFieldInput as DateTimeFieldInputPrimitive,
|
|
5
|
+
DateTimeFieldRoot as DateTimeFieldRootPrimitive,
|
|
6
|
+
DateTimeFieldSegment as DateTimeFieldSegmentPrimitive,
|
|
7
|
+
dataAttributes,
|
|
8
|
+
mergeDataAttributes,
|
|
9
|
+
type DateTimeFieldRootProps as DateTimeFieldRootPrimitiveProps,
|
|
10
|
+
} from '@cdx-ui/primitives';
|
|
11
|
+
import { cn, ParentContext, useParentContext } from '@cdx-ui/utils';
|
|
12
|
+
import { DateField } from '../DateField';
|
|
13
|
+
import {
|
|
14
|
+
dateFieldInputVariants,
|
|
15
|
+
dateFieldRootVariants,
|
|
16
|
+
dateFieldSegmentVariants,
|
|
17
|
+
type DateFieldGroupVariantProps,
|
|
18
|
+
} from '../DateField/styles';
|
|
19
|
+
|
|
20
|
+
const SCOPE = 'DATE_FIELD';
|
|
21
|
+
|
|
22
|
+
type DateFieldStyleContext = DateFieldGroupVariantProps & {
|
|
23
|
+
fullWidth?: boolean;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const useDateFieldStyleContext = (): DateFieldStyleContext =>
|
|
27
|
+
(useParentContext()[SCOPE] as DateFieldStyleContext | undefined) ?? {};
|
|
28
|
+
|
|
29
|
+
export interface DateTimeFieldProps
|
|
30
|
+
extends DateTimeFieldRootPrimitiveProps, DateFieldGroupVariantProps, Omit<ViewProps, 'children'> {
|
|
31
|
+
className?: string;
|
|
32
|
+
children?: ReactNode;
|
|
33
|
+
/** When true (the default), the group stretches to fill its container; when false, it hugs the segments. */
|
|
34
|
+
fullWidth?: boolean;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const DateTimeFieldRoot = forwardRef<View, DateTimeFieldProps>(
|
|
38
|
+
(
|
|
39
|
+
{ className, children, style, variant = 'outline', size = 'default', fullWidth, ...props },
|
|
40
|
+
ref,
|
|
41
|
+
) => {
|
|
42
|
+
const parent = useParentContext();
|
|
43
|
+
const ctx = useMemo(
|
|
44
|
+
() => ({ ...parent, [SCOPE]: { variant, size, fullWidth } }),
|
|
45
|
+
[parent, variant, size, fullWidth],
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<ParentContext.Provider value={ctx}>
|
|
50
|
+
<DateTimeFieldRootPrimitive
|
|
51
|
+
ref={ref}
|
|
52
|
+
className={cn(dateFieldRootVariants(), className)}
|
|
53
|
+
style={style}
|
|
54
|
+
{...props}
|
|
55
|
+
{...mergeDataAttributes(props, dataAttributes({ slot: 'date-time-field' }))}
|
|
56
|
+
>
|
|
57
|
+
{children ?? (
|
|
58
|
+
<DateField.Group>
|
|
59
|
+
<DateTimeField.Input>
|
|
60
|
+
{(segment) => <DateTimeField.Segment segment={segment} />}
|
|
61
|
+
</DateTimeField.Input>
|
|
62
|
+
</DateField.Group>
|
|
63
|
+
)}
|
|
64
|
+
</DateTimeFieldRootPrimitive>
|
|
65
|
+
</ParentContext.Provider>
|
|
66
|
+
);
|
|
67
|
+
},
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
DateTimeFieldRoot.displayName = 'DateTimeField';
|
|
71
|
+
|
|
72
|
+
const DateTimeFieldInput = forwardRef<
|
|
73
|
+
View,
|
|
74
|
+
{
|
|
75
|
+
children: (segment: import('@cdx-ui/formatters').DateSegment) => ReactNode;
|
|
76
|
+
className?: string;
|
|
77
|
+
} & Omit<ViewProps, 'children'>
|
|
78
|
+
>(({ className, style, ...props }, ref) => {
|
|
79
|
+
const { size } = useDateFieldStyleContext();
|
|
80
|
+
return (
|
|
81
|
+
<DateTimeFieldInputPrimitive
|
|
82
|
+
ref={ref}
|
|
83
|
+
className={cn(dateFieldInputVariants({ size: size ?? 'default' }), className)}
|
|
84
|
+
style={style}
|
|
85
|
+
{...props}
|
|
86
|
+
/>
|
|
87
|
+
);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
DateTimeFieldInput.displayName = 'DateTimeField.Input';
|
|
91
|
+
|
|
92
|
+
const DateTimeFieldSegment = forwardRef<
|
|
93
|
+
View,
|
|
94
|
+
{
|
|
95
|
+
segment: import('@cdx-ui/formatters').DateSegment;
|
|
96
|
+
className?: string;
|
|
97
|
+
} & Omit<ViewProps, 'children'>
|
|
98
|
+
>(({ segment, className, style, ...props }, ref) => (
|
|
99
|
+
<DateTimeFieldSegmentPrimitive
|
|
100
|
+
ref={ref}
|
|
101
|
+
segment={segment}
|
|
102
|
+
className={cn(dateFieldSegmentVariants({ literal: !segment.isEditable }), className)}
|
|
103
|
+
style={style}
|
|
104
|
+
{...props}
|
|
105
|
+
{...mergeDataAttributes(
|
|
106
|
+
props,
|
|
107
|
+
dataAttributes({
|
|
108
|
+
placeholder: segment.isEditable && segment.value == null,
|
|
109
|
+
}),
|
|
110
|
+
)}
|
|
111
|
+
/>
|
|
112
|
+
));
|
|
113
|
+
|
|
114
|
+
DateTimeFieldSegment.displayName = 'DateTimeField.Segment';
|
|
115
|
+
|
|
116
|
+
type DateTimeFieldCompound = typeof DateTimeFieldRoot & {
|
|
117
|
+
Group: typeof DateField.Group;
|
|
118
|
+
Input: typeof DateTimeFieldInput;
|
|
119
|
+
Segment: typeof DateTimeFieldSegment;
|
|
120
|
+
Suffix: typeof DateField.Suffix;
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
export const DateTimeField = Object.assign(DateTimeFieldRoot, {
|
|
124
|
+
Group: DateField.Group,
|
|
125
|
+
Input: DateTimeFieldInput,
|
|
126
|
+
Segment: DateTimeFieldSegment,
|
|
127
|
+
Suffix: DateField.Suffix,
|
|
128
|
+
}) as DateTimeFieldCompound;
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { forwardRef, type ReactNode } from 'react';
|
|
2
|
+
import { Pressable, Text, View, type ViewProps } from 'react-native';
|
|
3
|
+
import { useCSSVariable } from 'uniwind';
|
|
4
|
+
import {
|
|
5
|
+
dataAttributes,
|
|
6
|
+
DATE_TIME_LIST_HEIGHT,
|
|
7
|
+
DATE_TIME_LIST_ITEM_HEIGHT,
|
|
8
|
+
DateTimeListColumn as DateTimeListColumnPrimitive,
|
|
9
|
+
DateTimeListRoot as DateTimeListRootPrimitive,
|
|
10
|
+
mergeDataAttributes,
|
|
11
|
+
useDateTimeListColumnContext,
|
|
12
|
+
useDateTimeListContext,
|
|
13
|
+
type DateTimeListColumnType,
|
|
14
|
+
type DateTimeListRootProps as DateTimeListRootPrimitiveProps,
|
|
15
|
+
} from '@cdx-ui/primitives';
|
|
16
|
+
import { getDateTimeSegmentVisibility } from '@cdx-ui/formatters';
|
|
17
|
+
import { cn } from '@cdx-ui/utils';
|
|
18
|
+
import {
|
|
19
|
+
dateTimeListColumnsVariants,
|
|
20
|
+
dateTimeListColumnVariants,
|
|
21
|
+
dateTimeListEdgeFadeVariants,
|
|
22
|
+
dateTimeListHighlightVariants,
|
|
23
|
+
dateTimeListOptionTextVariants,
|
|
24
|
+
dateTimeListOptionVariants,
|
|
25
|
+
dateTimeListRootVariants,
|
|
26
|
+
} from './styles';
|
|
27
|
+
|
|
28
|
+
export interface DateTimeListProps
|
|
29
|
+
extends DateTimeListRootPrimitiveProps, Omit<ViewProps, 'children'> {
|
|
30
|
+
className?: string;
|
|
31
|
+
children?: ReactNode;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function DateTimeListDefaultBody() {
|
|
35
|
+
const { granularity, hour12 } = useDateTimeListContext();
|
|
36
|
+
const { showTime, showMinute, showSecond } = getDateTimeSegmentVisibility(granularity);
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<>
|
|
40
|
+
<DateTimeListDateColumn />
|
|
41
|
+
{showTime ? (
|
|
42
|
+
<>
|
|
43
|
+
<DateTimeListHourColumn />
|
|
44
|
+
{showMinute ? <DateTimeListMinuteColumn /> : null}
|
|
45
|
+
{showSecond ? <DateTimeListSecondColumn /> : null}
|
|
46
|
+
{hour12 ? <DateTimeListPeriodColumn /> : null}
|
|
47
|
+
</>
|
|
48
|
+
) : null}
|
|
49
|
+
</>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Cross-platform edge fade (Uniwind gradients are unreliable on native). */
|
|
54
|
+
function EdgeFade({ edge }: { edge: 'top' | 'bottom' }) {
|
|
55
|
+
const surface = useCSSVariable('--color-surface-primary') || 'transparent';
|
|
56
|
+
const isTop = edge === 'top';
|
|
57
|
+
return (
|
|
58
|
+
<View
|
|
59
|
+
pointerEvents="none"
|
|
60
|
+
className={dateTimeListEdgeFadeVariants({ edge })}
|
|
61
|
+
style={{
|
|
62
|
+
height: DATE_TIME_LIST_ITEM_HEIGHT * 1.75,
|
|
63
|
+
experimental_backgroundImage: isTop
|
|
64
|
+
? `linear-gradient(to bottom, ${surface as string}, transparent)`
|
|
65
|
+
: `linear-gradient(to top, ${surface as string}, transparent)`,
|
|
66
|
+
}}
|
|
67
|
+
/>
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const DateTimeListRoot = forwardRef<View, DateTimeListProps>(
|
|
72
|
+
({ className, children, style, ...props }, ref) => (
|
|
73
|
+
<DateTimeListRootPrimitive
|
|
74
|
+
ref={ref}
|
|
75
|
+
className={cn(dateTimeListRootVariants(), className)}
|
|
76
|
+
style={[{ height: DATE_TIME_LIST_HEIGHT }, style]}
|
|
77
|
+
{...props}
|
|
78
|
+
{...mergeDataAttributes(props, dataAttributes({ slot: 'date-time-list' }))}
|
|
79
|
+
>
|
|
80
|
+
<View
|
|
81
|
+
pointerEvents="none"
|
|
82
|
+
className={dateTimeListHighlightVariants()}
|
|
83
|
+
style={{
|
|
84
|
+
top: (DATE_TIME_LIST_HEIGHT - DATE_TIME_LIST_ITEM_HEIGHT) / 2,
|
|
85
|
+
height: DATE_TIME_LIST_ITEM_HEIGHT,
|
|
86
|
+
}}
|
|
87
|
+
/>
|
|
88
|
+
|
|
89
|
+
<View className={dateTimeListColumnsVariants()}>
|
|
90
|
+
{children ?? <DateTimeListDefaultBody />}
|
|
91
|
+
</View>
|
|
92
|
+
|
|
93
|
+
<EdgeFade edge="top" />
|
|
94
|
+
<EdgeFade edge="bottom" />
|
|
95
|
+
</DateTimeListRootPrimitive>
|
|
96
|
+
),
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
DateTimeListRoot.displayName = 'DateTimeList';
|
|
100
|
+
|
|
101
|
+
function ColumnOption({
|
|
102
|
+
option,
|
|
103
|
+
}: {
|
|
104
|
+
option: { value: string | number; label: string; selected: boolean };
|
|
105
|
+
}) {
|
|
106
|
+
const { onSelect, column } = useDateTimeListColumnContext();
|
|
107
|
+
|
|
108
|
+
return (
|
|
109
|
+
<Pressable
|
|
110
|
+
accessibilityRole="button"
|
|
111
|
+
accessibilityLabel={option.label}
|
|
112
|
+
accessibilityState={{ selected: option.selected }}
|
|
113
|
+
onPress={() => onSelect(option.value)}
|
|
114
|
+
className={dateTimeListOptionVariants()}
|
|
115
|
+
{...{ 'data-column': column, 'data-selected': option.selected }}
|
|
116
|
+
>
|
|
117
|
+
<Text
|
|
118
|
+
className={dateTimeListOptionTextVariants({ selected: option.selected })}
|
|
119
|
+
numberOfLines={1}
|
|
120
|
+
>
|
|
121
|
+
{option.label}
|
|
122
|
+
</Text>
|
|
123
|
+
</Pressable>
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function ColumnShell({
|
|
128
|
+
className,
|
|
129
|
+
style,
|
|
130
|
+
column,
|
|
131
|
+
...props
|
|
132
|
+
}: ViewProps & { column: DateTimeListColumnType }) {
|
|
133
|
+
return (
|
|
134
|
+
<DateTimeListColumnPrimitive
|
|
135
|
+
column={column}
|
|
136
|
+
className={cn(dateTimeListColumnVariants({ column }), className)}
|
|
137
|
+
style={[{ height: DATE_TIME_LIST_HEIGHT }, style]}
|
|
138
|
+
{...props}
|
|
139
|
+
>
|
|
140
|
+
{(option) => <ColumnOption option={option} />}
|
|
141
|
+
</DateTimeListColumnPrimitive>
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function DateTimeListDateColumn(props: ViewProps) {
|
|
146
|
+
return <ColumnShell column="date" {...props} />;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function DateTimeListHourColumn(props: ViewProps) {
|
|
150
|
+
return <ColumnShell column="hour" {...props} />;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function DateTimeListMinuteColumn(props: ViewProps) {
|
|
154
|
+
return <ColumnShell column="minute" {...props} />;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function DateTimeListSecondColumn(props: ViewProps) {
|
|
158
|
+
return <ColumnShell column="second" {...props} />;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function DateTimeListTimeColumn(props: ViewProps) {
|
|
162
|
+
const { granularity } = useDateTimeListContext();
|
|
163
|
+
const { showMinute, showSecond } = getDateTimeSegmentVisibility(granularity);
|
|
164
|
+
return (
|
|
165
|
+
<>
|
|
166
|
+
<DateTimeListHourColumn {...props} />
|
|
167
|
+
{showMinute ? <DateTimeListMinuteColumn {...props} /> : null}
|
|
168
|
+
{showSecond ? <DateTimeListSecondColumn {...props} /> : null}
|
|
169
|
+
</>
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function DateTimeListPeriodColumn(props: ViewProps) {
|
|
174
|
+
return <ColumnShell column="period" {...props} />;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
type DateTimeListCompound = typeof DateTimeListRoot & {
|
|
178
|
+
DateColumn: typeof DateTimeListDateColumn;
|
|
179
|
+
TimeColumn: typeof DateTimeListTimeColumn;
|
|
180
|
+
PeriodColumn: typeof DateTimeListPeriodColumn;
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
export const DateTimeList = Object.assign(DateTimeListRoot, {
|
|
184
|
+
DateColumn: DateTimeListDateColumn,
|
|
185
|
+
TimeColumn: DateTimeListTimeColumn,
|
|
186
|
+
PeriodColumn: DateTimeListPeriodColumn,
|
|
187
|
+
}) as DateTimeListCompound;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { cva, type VariantProps } from '@cdx-ui/utils';
|
|
2
|
+
|
|
3
|
+
// Stacking order inside the DateTimeList root: the highlight band sits behind
|
|
4
|
+
// the option columns, and the edge fades sit above both. Uniwind requires
|
|
5
|
+
// statically detectable class names, so each layer is a named literal rather
|
|
6
|
+
// than a computed `z-[...]` string.
|
|
7
|
+
const LAYER_HIGHLIGHT = 'z-[1]';
|
|
8
|
+
const LAYER_COLUMNS = 'z-[2]';
|
|
9
|
+
const LAYER_EDGE_FADE = 'z-[3]';
|
|
10
|
+
|
|
11
|
+
export const dateTimeListRootVariants = cva(
|
|
12
|
+
'relative overflow-hidden rounded-[var(--border-radius-default)] bg-surface-primary px-2',
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
export const dateTimeListHighlightVariants = cva([
|
|
16
|
+
'absolute left-2 right-2',
|
|
17
|
+
LAYER_HIGHLIGHT,
|
|
18
|
+
'rounded-[var(--border-radius-default)] bg-surface-secondary',
|
|
19
|
+
]);
|
|
20
|
+
|
|
21
|
+
export const dateTimeListColumnsVariants = cva([LAYER_COLUMNS, 'h-full flex-row']);
|
|
22
|
+
|
|
23
|
+
export const dateTimeListColumnVariants = cva('min-w-0', {
|
|
24
|
+
variants: {
|
|
25
|
+
column: {
|
|
26
|
+
date: 'flex-[1.8]',
|
|
27
|
+
hour: 'flex-1',
|
|
28
|
+
minute: 'flex-1',
|
|
29
|
+
second: 'flex-1',
|
|
30
|
+
period: 'flex-[0.8]',
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
defaultVariants: { column: 'hour' },
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
export const dateTimeListOptionVariants = cva('h-full items-center justify-center px-1');
|
|
37
|
+
|
|
38
|
+
export const dateTimeListOptionTextVariants = cva('body-md tabular-nums', {
|
|
39
|
+
variants: {
|
|
40
|
+
selected: {
|
|
41
|
+
true: 'font-semibold text-content-primary',
|
|
42
|
+
false: 'text-content-tertiary',
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
defaultVariants: { selected: false },
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
export const dateTimeListEdgeFadeVariants = cva(['absolute left-0 right-0', LAYER_EDGE_FADE], {
|
|
49
|
+
variants: {
|
|
50
|
+
edge: {
|
|
51
|
+
top: 'top-0',
|
|
52
|
+
bottom: 'bottom-0',
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
defaultVariants: { edge: 'top' },
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
export type DateTimeListColumnVariantProps = VariantProps<typeof dateTimeListColumnVariants>;
|
|
59
|
+
export type DateTimeListEdgeFadeVariantProps = VariantProps<typeof dateTimeListEdgeFadeVariants>;
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import { forwardRef, useCallback, useEffect, useMemo, useRef, type ReactNode } from 'react';
|
|
2
|
+
import { View, type ViewProps } from 'react-native';
|
|
3
|
+
import { Schedule } from '@cdx-ui/icons';
|
|
4
|
+
import {
|
|
5
|
+
dataAttributes,
|
|
6
|
+
DateTimePickerContext,
|
|
7
|
+
DateTimePickerRoot as DateTimePickerRootPrimitive,
|
|
8
|
+
mergeDataAttributes,
|
|
9
|
+
useDateTimePickerContext,
|
|
10
|
+
type DateTimePickerRootProps as DateTimePickerRootPrimitiveProps,
|
|
11
|
+
} from '@cdx-ui/primitives';
|
|
12
|
+
import { clampDateTimeId, nowDateTimeId, type DateTimeId } from '@cdx-ui/formatters';
|
|
13
|
+
import { cn, ParentContext, useParentContext } from '@cdx-ui/utils';
|
|
14
|
+
import { Dialog } from '../Dialog';
|
|
15
|
+
import { Icon } from '../Icon';
|
|
16
|
+
import { DateTimeList, type DateTimeListProps } from '../DateTimeList';
|
|
17
|
+
import { PickerTrigger, type PickerTriggerProps } from '../picker/PickerTrigger';
|
|
18
|
+
import {
|
|
19
|
+
PickerBottomSheetSurface,
|
|
20
|
+
PickerDialogSurface,
|
|
21
|
+
PickerPopoverSurface,
|
|
22
|
+
} from '../picker/surfaces';
|
|
23
|
+
|
|
24
|
+
export interface DateTimePickerProps
|
|
25
|
+
extends DateTimePickerRootPrimitiveProps, Omit<ViewProps, 'children'> {
|
|
26
|
+
className?: string;
|
|
27
|
+
children?: ReactNode;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const DATE_FIELD_SCOPE = 'DATE_FIELD';
|
|
31
|
+
|
|
32
|
+
const DateTimePickerRoot = forwardRef<View, DateTimePickerProps>(
|
|
33
|
+
({ className, children, style, ...props }, ref) => {
|
|
34
|
+
const parent = useParentContext();
|
|
35
|
+
const ctx = useMemo(
|
|
36
|
+
() => ({
|
|
37
|
+
...parent,
|
|
38
|
+
[DATE_FIELD_SCOPE]: { variant: 'outline', size: 'default', fullWidth: true },
|
|
39
|
+
}),
|
|
40
|
+
[parent],
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<ParentContext.Provider value={ctx}>
|
|
45
|
+
<DateTimePickerRootPrimitive
|
|
46
|
+
ref={ref}
|
|
47
|
+
className={cn('gap-2', className)}
|
|
48
|
+
style={style}
|
|
49
|
+
{...props}
|
|
50
|
+
{...mergeDataAttributes(props, dataAttributes({ slot: 'date-time-picker' }))}
|
|
51
|
+
>
|
|
52
|
+
{children}
|
|
53
|
+
</DateTimePickerRootPrimitive>
|
|
54
|
+
</ParentContext.Provider>
|
|
55
|
+
);
|
|
56
|
+
},
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
DateTimePickerRoot.displayName = 'DateTimePicker';
|
|
60
|
+
|
|
61
|
+
type DateTimePickerTriggerProps = Omit<
|
|
62
|
+
PickerTriggerProps,
|
|
63
|
+
'open' | 'setOpen' | 'disabled' | 'triggerRef' | 'accessibilityLabel'
|
|
64
|
+
> & {
|
|
65
|
+
accessibilityLabel?: string;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const DateTimePickerTrigger = forwardRef<View, DateTimePickerTriggerProps>(
|
|
69
|
+
({ accessibilityLabel, ...props }, ref) => {
|
|
70
|
+
const { open, setOpen, disabled, triggerRef, labels } = useDateTimePickerContext();
|
|
71
|
+
return (
|
|
72
|
+
<PickerTrigger
|
|
73
|
+
ref={ref}
|
|
74
|
+
open={open}
|
|
75
|
+
setOpen={setOpen}
|
|
76
|
+
disabled={disabled}
|
|
77
|
+
triggerRef={triggerRef}
|
|
78
|
+
accessibilityLabel={accessibilityLabel ?? labels.openDateTimePicker}
|
|
79
|
+
{...props}
|
|
80
|
+
/>
|
|
81
|
+
);
|
|
82
|
+
},
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
DateTimePickerTrigger.displayName = 'DateTimePicker.Trigger';
|
|
86
|
+
|
|
87
|
+
const DateTimePickerTriggerIndicator = () => (
|
|
88
|
+
<Icon as={Schedule} className="text-content-secondary" />
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
DateTimePickerTriggerIndicator.displayName = 'DateTimePicker.TriggerIndicator';
|
|
92
|
+
|
|
93
|
+
type DateTimePickerListProps = Omit<
|
|
94
|
+
DateTimeListProps,
|
|
95
|
+
| 'value'
|
|
96
|
+
| 'onValueChange'
|
|
97
|
+
| 'onUserInteract'
|
|
98
|
+
| 'granularity'
|
|
99
|
+
| 'hour12'
|
|
100
|
+
| 'locale'
|
|
101
|
+
| 'minValue'
|
|
102
|
+
| 'maxValue'
|
|
103
|
+
>;
|
|
104
|
+
|
|
105
|
+
const DateTimePickerList = forwardRef<View, DateTimePickerListProps>(({ ...props }, ref) => {
|
|
106
|
+
const {
|
|
107
|
+
value,
|
|
108
|
+
onValueChange,
|
|
109
|
+
draftValue,
|
|
110
|
+
setDraftValue,
|
|
111
|
+
open,
|
|
112
|
+
granularity,
|
|
113
|
+
locale,
|
|
114
|
+
hour12,
|
|
115
|
+
minValue,
|
|
116
|
+
maxValue,
|
|
117
|
+
} = useDateTimePickerContext();
|
|
118
|
+
const userInteractedRef = useRef(false);
|
|
119
|
+
|
|
120
|
+
useEffect(() => {
|
|
121
|
+
if (open) {
|
|
122
|
+
userInteractedRef.current = false;
|
|
123
|
+
}
|
|
124
|
+
}, [open]);
|
|
125
|
+
|
|
126
|
+
const handleUserInteract = useCallback(() => {
|
|
127
|
+
userInteractedRef.current = true;
|
|
128
|
+
}, []);
|
|
129
|
+
|
|
130
|
+
const handleValueChange = useCallback(
|
|
131
|
+
(next: DateTimeId) => {
|
|
132
|
+
setDraftValue(next);
|
|
133
|
+
if (!open) {
|
|
134
|
+
onValueChange?.(next);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
if (value !== undefined || userInteractedRef.current) {
|
|
138
|
+
onValueChange?.(next);
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
[onValueChange, open, setDraftValue, value],
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
const listValue = open
|
|
145
|
+
? (draftValue ??
|
|
146
|
+
clampDateTimeId(value ?? nowDateTimeId({ granularity }), { min: minValue, max: maxValue }))
|
|
147
|
+
: value;
|
|
148
|
+
|
|
149
|
+
return (
|
|
150
|
+
<DateTimeList
|
|
151
|
+
ref={ref}
|
|
152
|
+
value={listValue}
|
|
153
|
+
onValueChange={handleValueChange}
|
|
154
|
+
onUserInteract={handleUserInteract}
|
|
155
|
+
granularity={granularity}
|
|
156
|
+
locale={locale}
|
|
157
|
+
hour12={hour12}
|
|
158
|
+
minValue={minValue}
|
|
159
|
+
maxValue={maxValue}
|
|
160
|
+
{...props}
|
|
161
|
+
/>
|
|
162
|
+
);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
DateTimePickerList.displayName = 'DateTimePicker.List';
|
|
166
|
+
|
|
167
|
+
function DateTimePickerDialog({ children }: { children: ReactNode }) {
|
|
168
|
+
const ctx = useDateTimePickerContext();
|
|
169
|
+
return (
|
|
170
|
+
<PickerDialogSurface
|
|
171
|
+
open={ctx.open}
|
|
172
|
+
setOpen={ctx.setOpen}
|
|
173
|
+
registerSurface={ctx.registerSurface}
|
|
174
|
+
>
|
|
175
|
+
<Dialog.Popup className="p-4">
|
|
176
|
+
<DateTimePickerContext.Provider value={ctx}>{children}</DateTimePickerContext.Provider>
|
|
177
|
+
</Dialog.Popup>
|
|
178
|
+
</PickerDialogSurface>
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function DateTimePickerBottomSheet({ children }: { children: ReactNode }) {
|
|
183
|
+
const ctx = useDateTimePickerContext();
|
|
184
|
+
return (
|
|
185
|
+
<PickerBottomSheetSurface
|
|
186
|
+
open={ctx.open}
|
|
187
|
+
setOpen={ctx.setOpen}
|
|
188
|
+
registerSurface={ctx.registerSurface}
|
|
189
|
+
>
|
|
190
|
+
<DateTimePickerContext.Provider value={ctx}>{children}</DateTimePickerContext.Provider>
|
|
191
|
+
</PickerBottomSheetSurface>
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function DateTimePickerPopover({
|
|
196
|
+
children,
|
|
197
|
+
className,
|
|
198
|
+
}: {
|
|
199
|
+
children: ReactNode;
|
|
200
|
+
className?: string;
|
|
201
|
+
}) {
|
|
202
|
+
const ctx = useDateTimePickerContext();
|
|
203
|
+
return (
|
|
204
|
+
<PickerPopoverSurface
|
|
205
|
+
open={ctx.open}
|
|
206
|
+
setOpen={ctx.setOpen}
|
|
207
|
+
registerSurface={ctx.registerSurface}
|
|
208
|
+
anchorRef={ctx.anchorRef}
|
|
209
|
+
triggerRef={ctx.triggerRef}
|
|
210
|
+
className={className}
|
|
211
|
+
>
|
|
212
|
+
<DateTimePickerContext.Provider value={ctx}>{children}</DateTimePickerContext.Provider>
|
|
213
|
+
</PickerPopoverSurface>
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
type DateTimePickerCompound = typeof DateTimePickerRoot & {
|
|
218
|
+
Trigger: typeof DateTimePickerTrigger;
|
|
219
|
+
TriggerIndicator: typeof DateTimePickerTriggerIndicator;
|
|
220
|
+
List: typeof DateTimePickerList;
|
|
221
|
+
Popover: typeof DateTimePickerPopover;
|
|
222
|
+
Dialog: typeof DateTimePickerDialog;
|
|
223
|
+
BottomSheet: typeof DateTimePickerBottomSheet;
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
export const DateTimePicker = Object.assign(DateTimePickerRoot, {
|
|
227
|
+
Trigger: DateTimePickerTrigger,
|
|
228
|
+
TriggerIndicator: DateTimePickerTriggerIndicator,
|
|
229
|
+
List: DateTimePickerList,
|
|
230
|
+
Popover: DateTimePickerPopover,
|
|
231
|
+
Dialog: DateTimePickerDialog,
|
|
232
|
+
BottomSheet: DateTimePickerBottomSheet,
|
|
233
|
+
}) as DateTimePickerCompound;
|