rn-grid-date-time-picker 1.1.0 → 1.2.1
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 +44 -0
- package/lib/commonjs/components/DateTimePicker.js +55 -13
- package/lib/commonjs/components/DateTimePicker.js.map +1 -1
- package/lib/commonjs/components/calendar/CalendarHeader.js +3 -1
- package/lib/commonjs/components/calendar/CalendarHeader.js.map +1 -1
- package/lib/commonjs/components/calendar/DayGrid.js +4 -1
- package/lib/commonjs/components/calendar/DayGrid.js.map +1 -1
- package/lib/commonjs/components/calendar/calendarStyles.js +2 -1
- package/lib/commonjs/components/calendar/calendarStyles.js.map +1 -1
- package/lib/commonjs/components/field/RangeFields.js +2 -0
- package/lib/commonjs/components/field/RangeFields.js.map +1 -1
- package/lib/commonjs/components/field/SegmentedInput.js +1 -1
- package/lib/commonjs/components/field/SegmentedInput.js.map +1 -1
- package/lib/commonjs/components/field/ValueField.js +57 -5
- package/lib/commonjs/components/field/ValueField.js.map +1 -1
- package/lib/commonjs/components/field/fieldStyles.js +17 -0
- package/lib/commonjs/components/field/fieldStyles.js.map +1 -1
- package/lib/commonjs/components/field/fieldText.js +12 -3
- package/lib/commonjs/components/field/fieldText.js.map +1 -1
- package/lib/commonjs/components/theme/defaultStrings.js +6 -2
- package/lib/commonjs/components/theme/defaultStrings.js.map +1 -1
- package/lib/commonjs/components/theme/direction.js +17 -0
- package/lib/commonjs/components/theme/direction.js.map +1 -0
- package/lib/commonjs/components/theme/styleKeys.js +9 -2
- package/lib/commonjs/components/theme/styleKeys.js.map +1 -1
- package/lib/commonjs/components/time/TimeRow.js +42 -4
- package/lib/commonjs/components/time/TimeRow.js.map +1 -1
- package/lib/commonjs/components/time/TimeRows.js +27 -1
- package/lib/commonjs/components/time/TimeRows.js.map +1 -1
- package/lib/commonjs/components/time/timeStyles.js +19 -6
- package/lib/commonjs/components/time/timeStyles.js.map +1 -1
- package/lib/commonjs/components/types.js +2 -0
- package/lib/commonjs/components/types.js.map +1 -1
- package/lib/commonjs/core/calendarSystem.js +39 -1
- package/lib/commonjs/core/calendarSystem.js.map +1 -1
- package/lib/commonjs/core/zoned.js +18 -10
- package/lib/commonjs/core/zoned.js.map +1 -1
- package/lib/commonjs/index.js +6 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/components/DateTimePicker.js +57 -15
- package/lib/module/components/DateTimePicker.js.map +1 -1
- package/lib/module/components/calendar/CalendarHeader.js +4 -2
- package/lib/module/components/calendar/CalendarHeader.js.map +1 -1
- package/lib/module/components/calendar/DayGrid.js +5 -2
- package/lib/module/components/calendar/DayGrid.js.map +1 -1
- package/lib/module/components/calendar/calendarStyles.js +2 -1
- package/lib/module/components/calendar/calendarStyles.js.map +1 -1
- package/lib/module/components/field/RangeFields.js +2 -0
- package/lib/module/components/field/RangeFields.js.map +1 -1
- package/lib/module/components/field/SegmentedInput.js +1 -1
- package/lib/module/components/field/SegmentedInput.js.map +1 -1
- package/lib/module/components/field/ValueField.js +59 -7
- package/lib/module/components/field/ValueField.js.map +1 -1
- package/lib/module/components/field/fieldStyles.js +17 -0
- package/lib/module/components/field/fieldStyles.js.map +1 -1
- package/lib/module/components/field/fieldText.js +10 -2
- package/lib/module/components/field/fieldText.js.map +1 -1
- package/lib/module/components/theme/defaultStrings.js +4 -1
- package/lib/module/components/theme/defaultStrings.js.map +1 -1
- package/lib/module/components/theme/direction.js +13 -0
- package/lib/module/components/theme/direction.js.map +1 -0
- package/lib/module/components/theme/styleKeys.js +9 -2
- package/lib/module/components/theme/styleKeys.js.map +1 -1
- package/lib/module/components/time/TimeRow.js +43 -5
- package/lib/module/components/time/TimeRow.js.map +1 -1
- package/lib/module/components/time/TimeRows.js +27 -1
- package/lib/module/components/time/TimeRows.js.map +1 -1
- package/lib/module/components/time/timeStyles.js +19 -6
- package/lib/module/components/time/timeStyles.js.map +1 -1
- package/lib/module/components/types.js +2 -0
- package/lib/module/components/types.js.map +1 -1
- package/lib/module/core/calendarSystem.js +37 -0
- package/lib/module/core/calendarSystem.js.map +1 -1
- package/lib/module/core/zoned.js +18 -10
- package/lib/module/core/zoned.js.map +1 -1
- package/lib/module/index.js +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/commonjs/src/components/DateTimePicker.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/components/calendar/CalendarHeader.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/components/calendar/DayGrid.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/components/calendar/calendarStyles.d.ts +1 -1
- package/lib/typescript/commonjs/src/components/calendar/calendarStyles.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/components/field/RangeFields.d.ts +2 -0
- package/lib/typescript/commonjs/src/components/field/RangeFields.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/components/field/ValueField.d.ts +4 -0
- package/lib/typescript/commonjs/src/components/field/ValueField.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/components/field/fieldStyles.d.ts +15 -0
- package/lib/typescript/commonjs/src/components/field/fieldStyles.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/components/field/fieldText.d.ts +5 -0
- package/lib/typescript/commonjs/src/components/field/fieldText.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/components/theme/defaultStrings.d.ts +2 -0
- package/lib/typescript/commonjs/src/components/theme/defaultStrings.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/components/theme/direction.d.ts +8 -0
- package/lib/typescript/commonjs/src/components/theme/direction.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/components/theme/styleKeys.d.ts +1 -1
- package/lib/typescript/commonjs/src/components/theme/styleKeys.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/components/time/TimeRow.d.ts +4 -0
- package/lib/typescript/commonjs/src/components/time/TimeRow.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/components/time/TimeRows.d.ts +7 -0
- package/lib/typescript/commonjs/src/components/time/TimeRows.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/components/time/timeStyles.d.ts +24 -3
- package/lib/typescript/commonjs/src/components/time/timeStyles.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/components/types.d.ts +28 -0
- package/lib/typescript/commonjs/src/components/types.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/core/calendarSystem.d.ts +10 -0
- package/lib/typescript/commonjs/src/core/calendarSystem.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/core/zoned.d.ts +5 -1
- package/lib/typescript/commonjs/src/core/zoned.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/index.d.ts +3 -3
- package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
- package/lib/typescript/module/src/components/DateTimePicker.d.ts.map +1 -1
- package/lib/typescript/module/src/components/calendar/CalendarHeader.d.ts.map +1 -1
- package/lib/typescript/module/src/components/calendar/DayGrid.d.ts.map +1 -1
- package/lib/typescript/module/src/components/calendar/calendarStyles.d.ts +1 -1
- package/lib/typescript/module/src/components/calendar/calendarStyles.d.ts.map +1 -1
- package/lib/typescript/module/src/components/field/RangeFields.d.ts +2 -0
- package/lib/typescript/module/src/components/field/RangeFields.d.ts.map +1 -1
- package/lib/typescript/module/src/components/field/ValueField.d.ts +4 -0
- package/lib/typescript/module/src/components/field/ValueField.d.ts.map +1 -1
- package/lib/typescript/module/src/components/field/fieldStyles.d.ts +15 -0
- package/lib/typescript/module/src/components/field/fieldStyles.d.ts.map +1 -1
- package/lib/typescript/module/src/components/field/fieldText.d.ts +5 -0
- package/lib/typescript/module/src/components/field/fieldText.d.ts.map +1 -1
- package/lib/typescript/module/src/components/theme/defaultStrings.d.ts +2 -0
- package/lib/typescript/module/src/components/theme/defaultStrings.d.ts.map +1 -1
- package/lib/typescript/module/src/components/theme/direction.d.ts +8 -0
- package/lib/typescript/module/src/components/theme/direction.d.ts.map +1 -0
- package/lib/typescript/module/src/components/theme/styleKeys.d.ts +1 -1
- package/lib/typescript/module/src/components/theme/styleKeys.d.ts.map +1 -1
- package/lib/typescript/module/src/components/time/TimeRow.d.ts +4 -0
- package/lib/typescript/module/src/components/time/TimeRow.d.ts.map +1 -1
- package/lib/typescript/module/src/components/time/TimeRows.d.ts +7 -0
- package/lib/typescript/module/src/components/time/TimeRows.d.ts.map +1 -1
- package/lib/typescript/module/src/components/time/timeStyles.d.ts +24 -3
- package/lib/typescript/module/src/components/time/timeStyles.d.ts.map +1 -1
- package/lib/typescript/module/src/components/types.d.ts +28 -0
- package/lib/typescript/module/src/components/types.d.ts.map +1 -1
- package/lib/typescript/module/src/core/calendarSystem.d.ts +10 -0
- package/lib/typescript/module/src/core/calendarSystem.d.ts.map +1 -1
- package/lib/typescript/module/src/core/zoned.d.ts +5 -1
- package/lib/typescript/module/src/core/zoned.d.ts.map +1 -1
- package/lib/typescript/module/src/index.d.ts +3 -3
- package/lib/typescript/module/src/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/DateTimePicker.tsx +97 -47
- package/src/components/calendar/CalendarHeader.tsx +3 -2
- package/src/components/calendar/DayGrid.tsx +5 -2
- package/src/components/calendar/calendarStyles.ts +2 -1
- package/src/components/field/RangeFields.tsx +4 -0
- package/src/components/field/SegmentedInput.tsx +1 -1
- package/src/components/field/ValueField.tsx +83 -15
- package/src/components/field/fieldStyles.ts +6 -0
- package/src/components/field/fieldText.ts +25 -4
- package/src/components/theme/defaultStrings.ts +11 -1
- package/src/components/theme/direction.ts +12 -0
- package/src/components/theme/styleKeys.ts +9 -0
- package/src/components/time/TimeRow.tsx +49 -2
- package/src/components/time/TimeRows.tsx +38 -2
- package/src/components/time/timeStyles.ts +12 -4
- package/src/components/types.ts +29 -0
- package/src/core/calendarSystem.ts +42 -0
- package/src/core/zoned.ts +15 -3
- package/src/index.tsx +3 -2
|
@@ -25,6 +25,11 @@ export const STYLE_KEYS = [
|
|
|
25
25
|
'fieldText',
|
|
26
26
|
/** The value's text while the field is disabled (the placeholder keeps its own colour). */
|
|
27
27
|
'fieldTextDisabled',
|
|
28
|
+
/**
|
|
29
|
+
* Sets the date of a single date-time value apart from its time, e.g.
|
|
30
|
+
* `{ minWidth: '50%' }` starts the time at the middle of the field.
|
|
31
|
+
*/
|
|
32
|
+
'fieldDateText',
|
|
28
33
|
'fieldPlaceholder',
|
|
29
34
|
'fieldSegment',
|
|
30
35
|
'fieldSegmentFocused',
|
|
@@ -105,6 +110,10 @@ export const STYLE_KEYS = [
|
|
|
105
110
|
// time
|
|
106
111
|
'timeRow',
|
|
107
112
|
'timeLabel',
|
|
113
|
+
/** Holds the label and its date (`timeRowDate`) or a `renderTimeLabel` label. */
|
|
114
|
+
'timeLabelWrap',
|
|
115
|
+
/** The picked day under a time row's label (`timeRowDate`). */
|
|
116
|
+
'timeLabelDate',
|
|
108
117
|
'timeBox',
|
|
109
118
|
'timeBoxFocused',
|
|
110
119
|
'timeBoxError',
|
|
@@ -57,6 +57,10 @@ export interface TimeRowProps {
|
|
|
57
57
|
/** The day's limits (`Constraints.timeBounds`). */
|
|
58
58
|
bounds?: TimeBounds | null;
|
|
59
59
|
label: string;
|
|
60
|
+
/** The row's day, shown under the label (`timeRowDate`); null shows none. */
|
|
61
|
+
dateText?: string | null;
|
|
62
|
+
/** Replaces the label and its date (`renderTimeLabel`). */
|
|
63
|
+
renderLabel?: () => React.ReactNode;
|
|
60
64
|
disabled?: boolean;
|
|
61
65
|
tokens: ThemeTokens;
|
|
62
66
|
styles?: PickerStyles;
|
|
@@ -77,6 +81,37 @@ const issueText = (
|
|
|
77
81
|
return strings.errorTimeNotAllowed;
|
|
78
82
|
};
|
|
79
83
|
|
|
84
|
+
/** The row's label: plain, with the day under it, or the app's own. */
|
|
85
|
+
const TimeLabel: React.FC<
|
|
86
|
+
Pick<
|
|
87
|
+
TimeRowProps,
|
|
88
|
+
'label' | 'dateText' | 'renderLabel' | 'tokens' | 'styles' | 'testID'
|
|
89
|
+
>
|
|
90
|
+
> = ({ label, dateText, renderLabel, tokens, styles, testID }) => {
|
|
91
|
+
const s = buildTimeStyles(tokens);
|
|
92
|
+
if (!renderLabel && !dateText)
|
|
93
|
+
return <Text style={[s.label, styles?.timeLabel]}>{label}</Text>;
|
|
94
|
+
return (
|
|
95
|
+
<View style={[s.labelWrap, styles?.timeLabelWrap]}>
|
|
96
|
+
{renderLabel ? (
|
|
97
|
+
renderLabel()
|
|
98
|
+
) : (
|
|
99
|
+
<>
|
|
100
|
+
<Text style={[s.label, s.labelInWrap, styles?.timeLabel]}>
|
|
101
|
+
{label}
|
|
102
|
+
</Text>
|
|
103
|
+
<Text
|
|
104
|
+
style={[s.labelDate, styles?.timeLabelDate]}
|
|
105
|
+
testID={testID ? `${testID}-date` : undefined}
|
|
106
|
+
>
|
|
107
|
+
{dateText}
|
|
108
|
+
</Text>
|
|
109
|
+
</>
|
|
110
|
+
)}
|
|
111
|
+
</View>
|
|
112
|
+
);
|
|
113
|
+
};
|
|
114
|
+
|
|
80
115
|
/**
|
|
81
116
|
* Label, the time boxes and the error below them. The boxes are
|
|
82
117
|
* normal inputs (free cursor, digits only, two at most) with three helpers:
|
|
@@ -97,6 +132,8 @@ const TimeRow: React.FC<TimeRowProps> = ({
|
|
|
97
132
|
minuteStep = 1,
|
|
98
133
|
bounds,
|
|
99
134
|
label,
|
|
135
|
+
dateText,
|
|
136
|
+
renderLabel,
|
|
100
137
|
disabled,
|
|
101
138
|
tokens,
|
|
102
139
|
styles,
|
|
@@ -205,8 +242,11 @@ const TimeRow: React.FC<TimeRowProps> = ({
|
|
|
205
242
|
let issue: TimeEntryIssue | null = effective.issue;
|
|
206
243
|
if (effective.isEmpty) issue = time ? 'INCOMPLETE' : null;
|
|
207
244
|
if (effective.time) issue = checkTime(effective.time, { minuteStep, bounds });
|
|
245
|
+
// A time set elsewhere reaches the boxes one render later (the effect
|
|
246
|
+
// above); until then the boxes are stale, so check that time instead.
|
|
247
|
+
const boxesStale = !focused && timeKey(time) !== lastKey.current;
|
|
208
248
|
// The wheel always holds a complete time: only the limits and the step apply.
|
|
209
|
-
if (input === 'wheel')
|
|
249
|
+
if (input === 'wheel' || boxesStale)
|
|
210
250
|
issue = time ? checkTime(time, { minuteStep, bounds }) : null;
|
|
211
251
|
|
|
212
252
|
const pending =
|
|
@@ -268,7 +308,14 @@ const TimeRow: React.FC<TimeRowProps> = ({
|
|
|
268
308
|
return (
|
|
269
309
|
<View style={s.wrapper} testID={testID}>
|
|
270
310
|
<View style={[s.row, styles?.timeRow]}>
|
|
271
|
-
<
|
|
311
|
+
<TimeLabel
|
|
312
|
+
label={label}
|
|
313
|
+
dateText={dateText}
|
|
314
|
+
renderLabel={renderLabel}
|
|
315
|
+
tokens={tokens}
|
|
316
|
+
styles={styles}
|
|
317
|
+
testID={testID}
|
|
318
|
+
/>
|
|
272
319
|
{input === 'wheel' ? (
|
|
273
320
|
<TimeWheel
|
|
274
321
|
time={time}
|
|
@@ -5,10 +5,11 @@ import type { Draft, DraftTarget } from '../../core/draft';
|
|
|
5
5
|
import type { TimeEntryIssue } from '../../core/timeEntry';
|
|
6
6
|
import type { CalendarDate, Time, TimeFormat } from '../../core/types';
|
|
7
7
|
import type { RangeEnd } from '../field/RangeFields';
|
|
8
|
-
import { formatDateText } from '../field/fieldText';
|
|
8
|
+
import { formatDateText, type DateTextFormatter } from '../field/fieldText';
|
|
9
9
|
import type { PickerStrings } from '../theme/defaultStrings';
|
|
10
10
|
import type { PickerStyles } from '../theme/styleKeys';
|
|
11
11
|
import type { ThemeTokens } from '../theme/tokens';
|
|
12
|
+
import type { TimeLabelRenderProps } from '../types';
|
|
12
13
|
import TimeRow from './TimeRow';
|
|
13
14
|
|
|
14
15
|
/** Times typed before their day is picked, per end ('shared' lives in the draft). */
|
|
@@ -37,6 +38,11 @@ interface Props {
|
|
|
37
38
|
onSpinChange: (spinning: boolean) => void;
|
|
38
39
|
/** A row's box gained or lost focus. */
|
|
39
40
|
onFocusChange?: (rowKey: string, focused: boolean) => void;
|
|
41
|
+
/** Shows each row's day under its label. */
|
|
42
|
+
timeRowDate?: boolean;
|
|
43
|
+
renderTimeLabel?: (p: TimeLabelRenderProps) => React.ReactNode;
|
|
44
|
+
/** A day as the field writes it (the Hijri text for a Hijri pick); default `dateFormat`. */
|
|
45
|
+
dateText?: DateTextFormatter;
|
|
40
46
|
/** A row's time that is typed but not saved yet (null once saved or gone). */
|
|
41
47
|
onPendingChange?: (
|
|
42
48
|
rowKey: string,
|
|
@@ -51,6 +57,7 @@ interface Props {
|
|
|
51
57
|
|
|
52
58
|
interface RowSpec {
|
|
53
59
|
key: string;
|
|
60
|
+
kind: TimeLabelRenderProps['row'];
|
|
54
61
|
label: string;
|
|
55
62
|
time: Time | null;
|
|
56
63
|
day: CalendarDate | null;
|
|
@@ -85,6 +92,9 @@ const TimeRows: React.FC<Props> = (props) => {
|
|
|
85
92
|
onSpinChange,
|
|
86
93
|
onFocusChange,
|
|
87
94
|
onPendingChange,
|
|
95
|
+
timeRowDate = false,
|
|
96
|
+
renderTimeLabel,
|
|
97
|
+
dateText,
|
|
88
98
|
tokens,
|
|
89
99
|
styles,
|
|
90
100
|
strings,
|
|
@@ -98,6 +108,7 @@ const TimeRows: React.FC<Props> = (props) => {
|
|
|
98
108
|
): RowSpec => {
|
|
99
109
|
return {
|
|
100
110
|
key,
|
|
111
|
+
kind: key,
|
|
101
112
|
label,
|
|
102
113
|
time: value?.time ?? pending[key] ?? null,
|
|
103
114
|
day: value?.date ?? null,
|
|
@@ -123,6 +134,7 @@ const TimeRows: React.FC<Props> = (props) => {
|
|
|
123
134
|
rows = [
|
|
124
135
|
{
|
|
125
136
|
key: 'shared',
|
|
137
|
+
kind: 'shared',
|
|
126
138
|
label: strings.time,
|
|
127
139
|
time: draft.sharedTime,
|
|
128
140
|
day: null,
|
|
@@ -142,7 +154,11 @@ const TimeRows: React.FC<Props> = (props) => {
|
|
|
142
154
|
rows = [
|
|
143
155
|
{
|
|
144
156
|
key: `day-${slot.date.year}-${slot.date.month}-${slot.date.day}`,
|
|
145
|
-
|
|
157
|
+
kind: 'day',
|
|
158
|
+
// With timeRowDate the day goes under the label instead.
|
|
159
|
+
label: timeRowDate
|
|
160
|
+
? strings.time
|
|
161
|
+
: `${strings.time} · ${formatDateText(slot, dateFormat)}`,
|
|
146
162
|
time: slot.time,
|
|
147
163
|
day: slot.date,
|
|
148
164
|
target: { day: slot.date },
|
|
@@ -200,6 +216,24 @@ const TimeRows: React.FC<Props> = (props) => {
|
|
|
200
216
|
// eslint-disable-next-line react-hooks/exhaustive-deps -- reports changes only; the callback may be a new function on every render
|
|
201
217
|
useEffect(() => onSpinChange(anySpinning), [anySpinning]);
|
|
202
218
|
|
|
219
|
+
/** A row's day as the field writes it, or null before it is picked. */
|
|
220
|
+
const dayText = (row: RowSpec): string | null => {
|
|
221
|
+
if (!row.day) return null;
|
|
222
|
+
const value = { date: row.day, time: row.time };
|
|
223
|
+
return dateText ? dateText(value) : formatDateText(value, dateFormat);
|
|
224
|
+
};
|
|
225
|
+
const labelRenderer = (row: RowSpec) =>
|
|
226
|
+
renderTimeLabel
|
|
227
|
+
? () =>
|
|
228
|
+
renderTimeLabel({
|
|
229
|
+
label: row.label,
|
|
230
|
+
row: row.kind,
|
|
231
|
+
date: row.day,
|
|
232
|
+
dateText: dayText(row),
|
|
233
|
+
time: row.time,
|
|
234
|
+
})
|
|
235
|
+
: undefined;
|
|
236
|
+
|
|
203
237
|
const single = rows.length === 1;
|
|
204
238
|
return (
|
|
205
239
|
<>
|
|
@@ -218,6 +252,8 @@ const TimeRows: React.FC<Props> = (props) => {
|
|
|
218
252
|
minuteStep={minuteStep}
|
|
219
253
|
bounds={row.day ? constraints.timeBounds(row.day) : null}
|
|
220
254
|
label={row.label}
|
|
255
|
+
dateText={timeRowDate ? dayText(row) : null}
|
|
256
|
+
renderLabel={labelRenderer(row)}
|
|
221
257
|
disabled={disabled}
|
|
222
258
|
tokens={tokens}
|
|
223
259
|
styles={styles}
|
|
@@ -23,13 +23,22 @@ const create = (t: ThemeTokens) =>
|
|
|
23
23
|
fontSize: t.fontSizeLarge,
|
|
24
24
|
color: t.heading,
|
|
25
25
|
},
|
|
26
|
-
//
|
|
26
|
+
// The label with the day under it (timeRowDate), or a renderTimeLabel label.
|
|
27
|
+
labelWrap: { flexShrink: 1, marginEnd: 12 },
|
|
28
|
+
labelInWrap: { marginEnd: 0 },
|
|
29
|
+
labelDate: {
|
|
30
|
+
marginTop: 2,
|
|
31
|
+
...fontStyle(t, 'regular'),
|
|
32
|
+
fontSize: t.fontSizeSmall,
|
|
33
|
+
color: t.mutedText,
|
|
34
|
+
},
|
|
27
35
|
boxes: {
|
|
28
36
|
flexDirection: 'row',
|
|
29
37
|
alignItems: 'center',
|
|
30
38
|
gap: 22,
|
|
31
|
-
direction: 'ltr',
|
|
32
39
|
},
|
|
40
|
+
// The boxes follow the row's direction: right to left (the Hijri tab, or a
|
|
41
|
+
// right-to-left app), the hour sits on the right and AM / PM on the left.
|
|
33
42
|
clock: { flexDirection: 'row', alignItems: 'center' },
|
|
34
43
|
// Each box is 50 × 46 with a 1 pt border and radius 6.
|
|
35
44
|
boxWrap: { width: 50 },
|
|
@@ -62,9 +71,9 @@ const create = (t: ThemeTokens) =>
|
|
|
62
71
|
},
|
|
63
72
|
boxFocused: { borderColor: t.borderFocused },
|
|
64
73
|
boxError: { borderColor: t.error },
|
|
74
|
+
// No height of its own, so `timeBox` sets the row's height.
|
|
65
75
|
colonCell: {
|
|
66
76
|
width: 24,
|
|
67
|
-
height: 46,
|
|
68
77
|
alignItems: 'center',
|
|
69
78
|
justifyContent: 'center',
|
|
70
79
|
},
|
|
@@ -104,7 +113,6 @@ const create = (t: ThemeTokens) =>
|
|
|
104
113
|
flexDirection: 'row',
|
|
105
114
|
alignItems: 'center',
|
|
106
115
|
alignSelf: 'center',
|
|
107
|
-
direction: 'ltr',
|
|
108
116
|
},
|
|
109
117
|
wheelColumn: { width: 64, height: 200, overflow: 'hidden' },
|
|
110
118
|
wheelHighlight: {
|
package/src/components/types.ts
CHANGED
|
@@ -165,6 +165,20 @@ export interface LabelRenderProps {
|
|
|
165
165
|
fieldTestID?: string;
|
|
166
166
|
}
|
|
167
167
|
|
|
168
|
+
/** What `renderTimeLabel` receives, for one time row. */
|
|
169
|
+
export interface TimeLabelRenderProps {
|
|
170
|
+
/** The row's label from `strings`: 'Time', 'Start time' or 'End time'. */
|
|
171
|
+
label: string;
|
|
172
|
+
/** A single value's row, a range end, the multiple-mode shared row, or a day's own row (`timeMode: 'perDate'`). */
|
|
173
|
+
row: 'single' | 'from' | 'to' | 'shared' | 'day';
|
|
174
|
+
/** The row's picked day; null before it is picked, and for the shared row. */
|
|
175
|
+
date: CalendarDate | null;
|
|
176
|
+
/** That day as the field writes it; null when there is no day. Set whether or not `timeRowDate` is on. */
|
|
177
|
+
dateText: string | null;
|
|
178
|
+
/** The row's time, or null. */
|
|
179
|
+
time: Time | null;
|
|
180
|
+
}
|
|
181
|
+
|
|
168
182
|
/** What `renderInstruction` receives. */
|
|
169
183
|
export interface InstructionRenderProps {
|
|
170
184
|
instruction: string;
|
|
@@ -368,6 +382,14 @@ export interface DateTimePickerProps {
|
|
|
368
382
|
minuteStep?: number;
|
|
369
383
|
/** A newly picked day always gets this time (over a time typed first and over the current time). */
|
|
370
384
|
newDayTime?: Time;
|
|
385
|
+
/**
|
|
386
|
+
* Shows each time row's picked day under its label ('Start time',
|
|
387
|
+
* 10-03-2026), as the field writes it. Nothing shows until the day is
|
|
388
|
+
* picked. Style it with `timeLabelDate`. Default false.
|
|
389
|
+
*/
|
|
390
|
+
timeRowDate?: boolean;
|
|
391
|
+
/** Replaces a time row's label (and its date). The boxes and errors stay built in. */
|
|
392
|
+
renderTimeLabel?: (p: TimeLabelRenderProps) => React.ReactNode;
|
|
371
393
|
|
|
372
394
|
// limits → greyed days and errors
|
|
373
395
|
showHolidays?: boolean;
|
|
@@ -391,6 +413,13 @@ export interface DateTimePickerProps {
|
|
|
391
413
|
theme?: Partial<ThemeTokens>;
|
|
392
414
|
styles?: PickerStyles;
|
|
393
415
|
strings?: Partial<PickerStrings>;
|
|
416
|
+
/**
|
|
417
|
+
* The texts while the Hijri tab shows (e.g. Arabic), for its calendar and
|
|
418
|
+
* time rows, the error messages inside the picker, and a date picked in it
|
|
419
|
+
* (the on-screen field's errors keep `strings`). A key left out (or `undefined`)
|
|
420
|
+
* keeps AM / PM in `hijriLocale` (ص / م), then `strings`.
|
|
421
|
+
*/
|
|
422
|
+
hijriStrings?: Partial<PickerStrings>;
|
|
394
423
|
testID?: string;
|
|
395
424
|
|
|
396
425
|
// events
|
|
@@ -255,6 +255,48 @@ const writeHijriDate = (d: CalendarDate, locale: string): string | null => {
|
|
|
255
255
|
return `${h.day} ${hijriMonthNames(locale)[h.month - 1]} ${h.year}`;
|
|
256
256
|
};
|
|
257
257
|
|
|
258
|
+
export interface Periods {
|
|
259
|
+
am: string;
|
|
260
|
+
pm: string;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const ARABIC_PERIODS: Periods = { am: 'ص', pm: 'م' };
|
|
264
|
+
const periodCache = new Map<string, Periods | null>();
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* AM and PM in the Hijri locale's language, as Intl writes them ('ar-SA' →
|
|
268
|
+
* ص / م). An Arabic locale whose engine gives none, or Latin ones, gets ص / م;
|
|
269
|
+
* another locale gets null (the picker keeps strings.am / pm).
|
|
270
|
+
*/
|
|
271
|
+
export const hijriPeriods = (locale: string): Periods | null => {
|
|
272
|
+
if (!periodCache.has(locale)) periodCache.set(locale, readPeriods(locale));
|
|
273
|
+
return periodCache.get(locale)!;
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
const readPeriods = (locale: string): Periods | null => {
|
|
277
|
+
const arabic = /^ar\b/i.test(locale);
|
|
278
|
+
try {
|
|
279
|
+
const f = new Intl.DateTimeFormat(locale, {
|
|
280
|
+
timeZone: 'UTC',
|
|
281
|
+
hour: 'numeric',
|
|
282
|
+
hour12: true,
|
|
283
|
+
});
|
|
284
|
+
const period = (hour: number) =>
|
|
285
|
+
f
|
|
286
|
+
.formatToParts(utcDate(2026, 0, 1, hour))
|
|
287
|
+
// Some engines write the part type in lower case.
|
|
288
|
+
.find((p) => p.type.toLowerCase() === 'dayperiod')
|
|
289
|
+
?.value.trim();
|
|
290
|
+
const am = period(9);
|
|
291
|
+
const pm = period(21);
|
|
292
|
+
if (am && pm && am !== pm && !(arabic && /[A-Za-z]/.test(am + pm)))
|
|
293
|
+
return { am, pm };
|
|
294
|
+
} catch {
|
|
295
|
+
// An engine without this locale falls through.
|
|
296
|
+
}
|
|
297
|
+
return arabic ? ARABIC_PERIODS : null;
|
|
298
|
+
};
|
|
299
|
+
|
|
258
300
|
/**
|
|
259
301
|
* The system the picker uses: the requested one, Gregorian by default.
|
|
260
302
|
* Anything Hijri falls back to Gregorian when unsupported.
|
package/src/core/zoned.ts
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
import { DateTime } from 'luxon';
|
|
2
2
|
import type { DateTimeValue } from './types';
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
/**
|
|
5
|
+
* The Luxon DateTime for a date-time value in `zone` (seconds and ms zeroed).
|
|
6
|
+
* A time that happens twice resolves to its first occurrence: Luxon alone picks
|
|
7
|
+
* by the zone's offset today, so the result would change with the season.
|
|
8
|
+
*/
|
|
9
|
+
export const toZonedDateTime = (
|
|
10
|
+
value: DateTimeValue,
|
|
11
|
+
zone: string
|
|
12
|
+
): DateTime => {
|
|
13
|
+
const dt = DateTime.fromObject(
|
|
7
14
|
{
|
|
8
15
|
...value.date,
|
|
9
16
|
hour: value.time?.hour ?? 0,
|
|
@@ -13,6 +20,11 @@ export const toZonedDateTime = (value: DateTimeValue, zone: string): DateTime =>
|
|
|
13
20
|
},
|
|
14
21
|
{ zone }
|
|
15
22
|
);
|
|
23
|
+
if (!dt.isValid) return dt;
|
|
24
|
+
return dt
|
|
25
|
+
.getPossibleOffsets()
|
|
26
|
+
.reduce((first, d) => (d.toMillis() < first.toMillis() ? d : first), dt);
|
|
27
|
+
};
|
|
16
28
|
|
|
17
29
|
export type DstStatus = 'ok' | 'gap' | 'overlap';
|
|
18
30
|
|
package/src/index.tsx
CHANGED
|
@@ -31,7 +31,7 @@ export {
|
|
|
31
31
|
todayIn,
|
|
32
32
|
weekdayOf,
|
|
33
33
|
} from './core/calendarDate';
|
|
34
|
-
export { hijriDateText } from './core/calendarSystem';
|
|
34
|
+
export { hijriDateText, hijriPeriods } from './core/calendarSystem';
|
|
35
35
|
export { arabicDigits } from './core/numerals';
|
|
36
36
|
|
|
37
37
|
// Types
|
|
@@ -70,8 +70,9 @@ export type {
|
|
|
70
70
|
SheetRenderProps,
|
|
71
71
|
SheetSize,
|
|
72
72
|
Slot,
|
|
73
|
+
TimeLabelRenderProps,
|
|
73
74
|
} from './components/types';
|
|
74
|
-
export type { CalendarSystem } from './core/calendarSystem';
|
|
75
|
+
export type { CalendarSystem, Periods } from './core/calendarSystem';
|
|
75
76
|
export type { Numerals } from './core/numerals';
|
|
76
77
|
export type { PickerStrings } from './components/theme/defaultStrings';
|
|
77
78
|
export type {
|