@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.
Files changed (148) hide show
  1. package/lib/commonjs/components/BottomSheet/index.js +8 -2
  2. package/lib/commonjs/components/BottomSheet/index.js.map +1 -1
  3. package/lib/commonjs/components/Calendar/CalendarMonthHeader.js +96 -0
  4. package/lib/commonjs/components/Calendar/CalendarMonthHeader.js.map +1 -0
  5. package/lib/commonjs/components/Calendar/CalendarYearPickerGrid.js +74 -0
  6. package/lib/commonjs/components/Calendar/CalendarYearPickerGrid.js.map +1 -0
  7. package/lib/commonjs/components/Calendar/flashCalendarAdapter.js +298 -0
  8. package/lib/commonjs/components/Calendar/flashCalendarAdapter.js.map +1 -0
  9. package/lib/commonjs/components/Calendar/index.js +149 -0
  10. package/lib/commonjs/components/Calendar/index.js.map +1 -0
  11. package/lib/commonjs/components/Calendar/styles.js +70 -0
  12. package/lib/commonjs/components/Calendar/styles.js.map +1 -0
  13. package/lib/commonjs/components/DateField/index.js +147 -0
  14. package/lib/commonjs/components/DateField/index.js.map +1 -0
  15. package/lib/commonjs/components/DateField/styles.js +34 -0
  16. package/lib/commonjs/components/DateField/styles.js.map +1 -0
  17. package/lib/commonjs/components/DatePicker/index.js +163 -0
  18. package/lib/commonjs/components/DatePicker/index.js.map +1 -0
  19. package/lib/commonjs/components/DateRangePicker/index.js +177 -0
  20. package/lib/commonjs/components/DateRangePicker/index.js.map +1 -0
  21. package/lib/commonjs/components/DateTimeField/index.js +96 -0
  22. package/lib/commonjs/components/DateTimeField/index.js.map +1 -0
  23. package/lib/commonjs/components/DateTimeList/index.js +180 -0
  24. package/lib/commonjs/components/DateTimeList/index.js.map +1 -0
  25. package/lib/commonjs/components/DateTimeList/styles.js +55 -0
  26. package/lib/commonjs/components/DateTimeList/styles.js.map +1 -0
  27. package/lib/commonjs/components/DateTimePicker/index.js +187 -0
  28. package/lib/commonjs/components/DateTimePicker/index.js.map +1 -0
  29. package/lib/commonjs/components/MonthCalendar/index.js +229 -0
  30. package/lib/commonjs/components/MonthCalendar/index.js.map +1 -0
  31. package/lib/commonjs/components/MonthPicker/index.js +163 -0
  32. package/lib/commonjs/components/MonthPicker/index.js.map +1 -0
  33. package/lib/commonjs/components/RangeCalendar/index.js +165 -0
  34. package/lib/commonjs/components/RangeCalendar/index.js.map +1 -0
  35. package/lib/commonjs/components/index.js +120 -0
  36. package/lib/commonjs/components/index.js.map +1 -1
  37. package/lib/commonjs/components/picker/PickerTrigger.js +49 -0
  38. package/lib/commonjs/components/picker/PickerTrigger.js.map +1 -0
  39. package/lib/commonjs/components/picker/styles.js +15 -0
  40. package/lib/commonjs/components/picker/styles.js.map +1 -0
  41. package/lib/commonjs/components/picker/surfaces.js +141 -0
  42. package/lib/commonjs/components/picker/surfaces.js.map +1 -0
  43. package/lib/module/components/BottomSheet/index.js +8 -2
  44. package/lib/module/components/BottomSheet/index.js.map +1 -1
  45. package/lib/module/components/Calendar/CalendarMonthHeader.js +92 -0
  46. package/lib/module/components/Calendar/CalendarMonthHeader.js.map +1 -0
  47. package/lib/module/components/Calendar/CalendarYearPickerGrid.js +70 -0
  48. package/lib/module/components/Calendar/CalendarYearPickerGrid.js.map +1 -0
  49. package/lib/module/components/Calendar/flashCalendarAdapter.js +290 -0
  50. package/lib/module/components/Calendar/flashCalendarAdapter.js.map +1 -0
  51. package/lib/module/components/Calendar/index.js +145 -0
  52. package/lib/module/components/Calendar/index.js.map +1 -0
  53. package/lib/module/components/Calendar/styles.js +66 -0
  54. package/lib/module/components/Calendar/styles.js.map +1 -0
  55. package/lib/module/components/DateField/index.js +143 -0
  56. package/lib/module/components/DateField/index.js.map +1 -0
  57. package/lib/module/components/DateField/styles.js +30 -0
  58. package/lib/module/components/DateField/styles.js.map +1 -0
  59. package/lib/module/components/DatePicker/index.js +159 -0
  60. package/lib/module/components/DatePicker/index.js.map +1 -0
  61. package/lib/module/components/DateRangePicker/index.js +173 -0
  62. package/lib/module/components/DateRangePicker/index.js.map +1 -0
  63. package/lib/module/components/DateTimeField/index.js +92 -0
  64. package/lib/module/components/DateTimeField/index.js.map +1 -0
  65. package/lib/module/components/DateTimeList/index.js +176 -0
  66. package/lib/module/components/DateTimeList/index.js.map +1 -0
  67. package/lib/module/components/DateTimeList/styles.js +52 -0
  68. package/lib/module/components/DateTimeList/styles.js.map +1 -0
  69. package/lib/module/components/DateTimePicker/index.js +183 -0
  70. package/lib/module/components/DateTimePicker/index.js.map +1 -0
  71. package/lib/module/components/MonthCalendar/index.js +225 -0
  72. package/lib/module/components/MonthCalendar/index.js.map +1 -0
  73. package/lib/module/components/MonthPicker/index.js +159 -0
  74. package/lib/module/components/MonthPicker/index.js.map +1 -0
  75. package/lib/module/components/RangeCalendar/index.js +161 -0
  76. package/lib/module/components/RangeCalendar/index.js.map +1 -0
  77. package/lib/module/components/index.js +10 -0
  78. package/lib/module/components/index.js.map +1 -1
  79. package/lib/module/components/picker/PickerTrigger.js +45 -0
  80. package/lib/module/components/picker/PickerTrigger.js.map +1 -0
  81. package/lib/module/components/picker/styles.js +12 -0
  82. package/lib/module/components/picker/styles.js.map +1 -0
  83. package/lib/module/components/picker/surfaces.js +135 -0
  84. package/lib/module/components/picker/surfaces.js.map +1 -0
  85. package/lib/typescript/components/BottomSheet/index.d.ts +2 -2
  86. package/lib/typescript/components/BottomSheet/index.d.ts.map +1 -1
  87. package/lib/typescript/components/Calendar/CalendarMonthHeader.d.ts +14 -0
  88. package/lib/typescript/components/Calendar/CalendarMonthHeader.d.ts.map +1 -0
  89. package/lib/typescript/components/Calendar/CalendarYearPickerGrid.d.ts +12 -0
  90. package/lib/typescript/components/Calendar/CalendarYearPickerGrid.d.ts.map +1 -0
  91. package/lib/typescript/components/Calendar/flashCalendarAdapter.d.ts +18 -0
  92. package/lib/typescript/components/Calendar/flashCalendarAdapter.d.ts.map +1 -0
  93. package/lib/typescript/components/Calendar/index.d.ts +19 -0
  94. package/lib/typescript/components/Calendar/index.d.ts.map +1 -0
  95. package/lib/typescript/components/Calendar/styles.d.ts +23 -0
  96. package/lib/typescript/components/Calendar/styles.d.ts.map +1 -0
  97. package/lib/typescript/components/DateField/index.d.ts +43 -0
  98. package/lib/typescript/components/DateField/index.d.ts.map +1 -0
  99. package/lib/typescript/components/DateField/styles.d.ts +15 -0
  100. package/lib/typescript/components/DateField/styles.d.ts.map +1 -0
  101. package/lib/typescript/components/DatePicker/index.d.ts +40 -0
  102. package/lib/typescript/components/DatePicker/index.d.ts.map +1 -0
  103. package/lib/typescript/components/DateRangePicker/index.d.ts +45 -0
  104. package/lib/typescript/components/DateRangePicker/index.d.ts.map +1 -0
  105. package/lib/typescript/components/DateTimeField/index.d.ts +29 -0
  106. package/lib/typescript/components/DateTimeField/index.d.ts.map +1 -0
  107. package/lib/typescript/components/DateTimeList/index.d.ts +19 -0
  108. package/lib/typescript/components/DateTimeList/index.d.ts.map +1 -0
  109. package/lib/typescript/components/DateTimeList/styles.d.ts +17 -0
  110. package/lib/typescript/components/DateTimeList/styles.d.ts.map +1 -0
  111. package/lib/typescript/components/DateTimePicker/index.d.ts +40 -0
  112. package/lib/typescript/components/DateTimePicker/index.d.ts.map +1 -0
  113. package/lib/typescript/components/MonthCalendar/index.d.ts +29 -0
  114. package/lib/typescript/components/MonthCalendar/index.d.ts.map +1 -0
  115. package/lib/typescript/components/MonthPicker/index.d.ts +40 -0
  116. package/lib/typescript/components/MonthPicker/index.d.ts.map +1 -0
  117. package/lib/typescript/components/RangeCalendar/index.d.ts +19 -0
  118. package/lib/typescript/components/RangeCalendar/index.d.ts.map +1 -0
  119. package/lib/typescript/components/index.d.ts +10 -0
  120. package/lib/typescript/components/index.d.ts.map +1 -1
  121. package/lib/typescript/components/picker/PickerTrigger.d.ts +25 -0
  122. package/lib/typescript/components/picker/PickerTrigger.d.ts.map +1 -0
  123. package/lib/typescript/components/picker/styles.d.ts +4 -0
  124. package/lib/typescript/components/picker/styles.d.ts.map +1 -0
  125. package/lib/typescript/components/picker/surfaces.d.ts +28 -0
  126. package/lib/typescript/components/picker/surfaces.d.ts.map +1 -0
  127. package/package.json +6 -4
  128. package/src/components/BottomSheet/index.tsx +7 -1
  129. package/src/components/Calendar/CalendarMonthHeader.tsx +124 -0
  130. package/src/components/Calendar/CalendarYearPickerGrid.tsx +101 -0
  131. package/src/components/Calendar/flashCalendarAdapter.ts +362 -0
  132. package/src/components/Calendar/index.tsx +151 -0
  133. package/src/components/Calendar/styles.ts +80 -0
  134. package/src/components/DateField/index.tsx +196 -0
  135. package/src/components/DateField/styles.ts +51 -0
  136. package/src/components/DatePicker/index.tsx +187 -0
  137. package/src/components/DateRangePicker/index.tsx +202 -0
  138. package/src/components/DateTimeField/index.tsx +128 -0
  139. package/src/components/DateTimeList/index.tsx +187 -0
  140. package/src/components/DateTimeList/styles.ts +59 -0
  141. package/src/components/DateTimePicker/index.tsx +233 -0
  142. package/src/components/MonthCalendar/index.tsx +252 -0
  143. package/src/components/MonthPicker/index.tsx +188 -0
  144. package/src/components/RangeCalendar/index.tsx +162 -0
  145. package/src/components/index.ts +10 -0
  146. package/src/components/picker/PickerTrigger.tsx +65 -0
  147. package/src/components/picker/styles.ts +17 -0
  148. 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;