rn-grid-date-time-picker 1.0.0 → 1.2.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 +86 -0
- package/README.md +100 -638
- package/lib/commonjs/adapters/utcMidnight.js +15 -6
- package/lib/commonjs/adapters/utcMidnight.js.map +1 -1
- package/lib/commonjs/components/DateTimePicker.js +484 -85
- package/lib/commonjs/components/DateTimePicker.js.map +1 -1
- package/lib/commonjs/components/calendar/Calendar.js +21 -7
- package/lib/commonjs/components/calendar/Calendar.js.map +1 -1
- package/lib/commonjs/components/calendar/CalendarHeader.js +46 -6
- package/lib/commonjs/components/calendar/CalendarHeader.js.map +1 -1
- package/lib/commonjs/components/calendar/CalendarSwitch.js +150 -0
- package/lib/commonjs/components/calendar/CalendarSwitch.js.map +1 -0
- package/lib/commonjs/components/calendar/DayCell.js +8 -3
- package/lib/commonjs/components/calendar/DayCell.js.map +1 -1
- package/lib/commonjs/components/calendar/DayGrid.js +13 -2
- package/lib/commonjs/components/calendar/DayGrid.js.map +1 -1
- package/lib/commonjs/components/calendar/PeriodGrid.js +3 -1
- package/lib/commonjs/components/calendar/PeriodGrid.js.map +1 -1
- package/lib/commonjs/components/calendar/calendarStyles.js +3 -2
- package/lib/commonjs/components/calendar/calendarStyles.js.map +1 -1
- package/lib/commonjs/components/calendar/localeNames.js +46 -24
- package/lib/commonjs/components/calendar/localeNames.js.map +1 -1
- package/lib/commonjs/components/calendar/selection.js +9 -1
- package/lib/commonjs/components/calendar/selection.js.map +1 -1
- package/lib/commonjs/components/container/DefaultSheet.js +42 -11
- package/lib/commonjs/components/container/DefaultSheet.js.map +1 -1
- package/lib/commonjs/components/container/PickerContainer.js +4 -0
- package/lib/commonjs/components/container/PickerContainer.js.map +1 -1
- package/lib/commonjs/components/container/PickerLayout.js +1 -1
- package/lib/commonjs/components/container/PickerLayout.js.map +1 -1
- package/lib/commonjs/components/container/containerStyles.js +12 -4
- package/lib/commonjs/components/container/containerStyles.js.map +1 -1
- package/lib/commonjs/components/field/RangeFields.js +5 -1
- package/lib/commonjs/components/field/RangeFields.js.map +1 -1
- package/lib/commonjs/components/field/SegmentedInput.js +8 -3
- package/lib/commonjs/components/field/SegmentedInput.js.map +1 -1
- package/lib/commonjs/components/field/ValueField.js +64 -8
- 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 +29 -13
- package/lib/commonjs/components/field/fieldText.js.map +1 -1
- package/lib/commonjs/components/hooks/useBottomInset.js +32 -0
- package/lib/commonjs/components/hooks/useBottomInset.js.map +1 -0
- package/lib/commonjs/components/hooks/useKeyboardFold.js +36 -13
- package/lib/commonjs/components/hooks/useKeyboardFold.js.map +1 -1
- package/lib/commonjs/components/hooks/useOpenPicker.js +39 -17
- package/lib/commonjs/components/hooks/useOpenPicker.js.map +1 -1
- package/lib/commonjs/components/hooks/useTypedSegments.js +6 -2
- package/lib/commonjs/components/hooks/useTypedSegments.js.map +1 -1
- package/lib/commonjs/components/theme/defaultStrings.js +13 -3
- 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/numerals.js +16 -0
- package/lib/commonjs/components/theme/numerals.js.map +1 -0
- package/lib/commonjs/components/theme/styleKeys.js +10 -2
- package/lib/commonjs/components/theme/styleKeys.js.map +1 -1
- package/lib/commonjs/components/theme/tokens.js +4 -0
- package/lib/commonjs/components/theme/tokens.js.map +1 -1
- package/lib/commonjs/components/time/TimeRow.js +10 -2
- package/lib/commonjs/components/time/TimeRow.js.map +1 -1
- package/lib/commonjs/components/time/TypedTime.js +3 -1
- package/lib/commonjs/components/time/TypedTime.js.map +1 -1
- package/lib/commonjs/components/time/Wheel.js +20 -3
- package/lib/commonjs/components/time/Wheel.js.map +1 -1
- package/lib/commonjs/components/time/timeStyles.js +4 -5
- package/lib/commonjs/components/time/timeStyles.js.map +1 -1
- package/lib/commonjs/components/types.js +10 -0
- package/lib/commonjs/components/types.js.map +1 -1
- package/lib/commonjs/core/calendarSystem.js +123 -22
- package/lib/commonjs/core/calendarSystem.js.map +1 -1
- package/lib/commonjs/core/digits.js +25 -0
- package/lib/commonjs/core/digits.js.map +1 -0
- package/lib/commonjs/core/draft.js +31 -10
- package/lib/commonjs/core/draft.js.map +1 -1
- package/lib/commonjs/core/locale.js +20 -4
- package/lib/commonjs/core/locale.js.map +1 -1
- package/lib/commonjs/core/numerals.js +46 -0
- package/lib/commonjs/core/numerals.js.map +1 -0
- package/lib/commonjs/core/segmentEditor.js +9 -0
- package/lib/commonjs/core/segmentEditor.js.map +1 -1
- package/lib/commonjs/core/segments.js +2 -11
- package/lib/commonjs/core/segments.js.map +1 -1
- package/lib/commonjs/core/selectionRules.js +2 -1
- package/lib/commonjs/core/selectionRules.js.map +1 -1
- package/lib/commonjs/core/timeEntry.js +7 -91
- package/lib/commonjs/core/timeEntry.js.map +1 -1
- package/lib/commonjs/icons/index.js +5 -1
- package/lib/commonjs/icons/index.js.map +1 -1
- package/lib/commonjs/index.js +20 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/adapters/utcMidnight.js +14 -5
- package/lib/module/adapters/utcMidnight.js.map +1 -1
- package/lib/module/components/DateTimePicker.js +490 -91
- package/lib/module/components/DateTimePicker.js.map +1 -1
- package/lib/module/components/calendar/Calendar.js +25 -11
- package/lib/module/components/calendar/Calendar.js.map +1 -1
- package/lib/module/components/calendar/CalendarHeader.js +47 -7
- package/lib/module/components/calendar/CalendarHeader.js.map +1 -1
- package/lib/module/components/calendar/CalendarSwitch.js +145 -0
- package/lib/module/components/calendar/CalendarSwitch.js.map +1 -0
- package/lib/module/components/calendar/DayCell.js +8 -3
- package/lib/module/components/calendar/DayCell.js.map +1 -1
- package/lib/module/components/calendar/DayGrid.js +14 -3
- package/lib/module/components/calendar/DayGrid.js.map +1 -1
- package/lib/module/components/calendar/PeriodGrid.js +3 -1
- package/lib/module/components/calendar/PeriodGrid.js.map +1 -1
- package/lib/module/components/calendar/calendarStyles.js +3 -2
- package/lib/module/components/calendar/calendarStyles.js.map +1 -1
- package/lib/module/components/calendar/localeNames.js +46 -24
- package/lib/module/components/calendar/localeNames.js.map +1 -1
- package/lib/module/components/calendar/selection.js +7 -0
- package/lib/module/components/calendar/selection.js.map +1 -1
- package/lib/module/components/container/DefaultSheet.js +42 -12
- package/lib/module/components/container/DefaultSheet.js.map +1 -1
- package/lib/module/components/container/PickerContainer.js +4 -0
- package/lib/module/components/container/PickerContainer.js.map +1 -1
- package/lib/module/components/container/PickerLayout.js +1 -1
- package/lib/module/components/container/PickerLayout.js.map +1 -1
- package/lib/module/components/container/containerStyles.js +11 -3
- package/lib/module/components/container/containerStyles.js.map +1 -1
- package/lib/module/components/field/RangeFields.js +5 -1
- package/lib/module/components/field/RangeFields.js.map +1 -1
- package/lib/module/components/field/SegmentedInput.js +8 -3
- package/lib/module/components/field/SegmentedInput.js.map +1 -1
- package/lib/module/components/field/ValueField.js +66 -10
- 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 +28 -11
- package/lib/module/components/field/fieldText.js.map +1 -1
- package/lib/module/components/hooks/useBottomInset.js +27 -0
- package/lib/module/components/hooks/useBottomInset.js.map +1 -0
- package/lib/module/components/hooks/useKeyboardFold.js +33 -12
- package/lib/module/components/hooks/useKeyboardFold.js.map +1 -1
- package/lib/module/components/hooks/useOpenPicker.js +39 -17
- package/lib/module/components/hooks/useOpenPicker.js.map +1 -1
- package/lib/module/components/hooks/useTypedSegments.js +6 -2
- package/lib/module/components/hooks/useTypedSegments.js.map +1 -1
- package/lib/module/components/theme/defaultStrings.js +11 -2
- 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/numerals.js +12 -0
- package/lib/module/components/theme/numerals.js.map +1 -0
- package/lib/module/components/theme/styleKeys.js +10 -2
- package/lib/module/components/theme/styleKeys.js.map +1 -1
- package/lib/module/components/theme/tokens.js +4 -0
- package/lib/module/components/theme/tokens.js.map +1 -1
- package/lib/module/components/time/TimeRow.js +11 -3
- package/lib/module/components/time/TimeRow.js.map +1 -1
- package/lib/module/components/time/TypedTime.js +3 -1
- package/lib/module/components/time/TypedTime.js.map +1 -1
- package/lib/module/components/time/Wheel.js +18 -2
- package/lib/module/components/time/Wheel.js.map +1 -1
- package/lib/module/components/time/timeStyles.js +4 -5
- package/lib/module/components/time/timeStyles.js.map +1 -1
- package/lib/module/components/types.js +10 -0
- package/lib/module/components/types.js.map +1 -1
- package/lib/module/core/calendarSystem.js +118 -19
- package/lib/module/core/calendarSystem.js.map +1 -1
- package/lib/module/core/digits.js +20 -0
- package/lib/module/core/digits.js.map +1 -0
- package/lib/module/core/draft.js +29 -9
- package/lib/module/core/draft.js.map +1 -1
- package/lib/module/core/locale.js +18 -3
- package/lib/module/core/locale.js.map +1 -1
- package/lib/module/core/numerals.js +39 -0
- package/lib/module/core/numerals.js.map +1 -0
- package/lib/module/core/segmentEditor.js +9 -0
- package/lib/module/core/segmentEditor.js.map +1 -1
- package/lib/module/core/segments.js +0 -8
- package/lib/module/core/segments.js.map +1 -1
- package/lib/module/core/selectionRules.js +2 -1
- package/lib/module/core/selectionRules.js.map +1 -1
- package/lib/module/core/timeEntry.js +7 -89
- package/lib/module/core/timeEntry.js.map +1 -1
- package/lib/module/icons/index.js +5 -1
- package/lib/module/icons/index.js.map +1 -1
- package/lib/module/index.js +2 -0
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/commonjs/src/adapters/utcMidnight.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/components/DateTimePicker.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/components/calendar/Calendar.d.ts +8 -4
- package/lib/typescript/commonjs/src/components/calendar/Calendar.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/CalendarSwitch.d.ts +26 -0
- package/lib/typescript/commonjs/src/components/calendar/CalendarSwitch.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/components/calendar/DayCell.d.ts +1 -1
- package/lib/typescript/commonjs/src/components/calendar/DayCell.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/components/calendar/DayGrid.d.ts +2 -0
- package/lib/typescript/commonjs/src/components/calendar/DayGrid.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/components/calendar/PeriodGrid.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/calendar/localeNames.d.ts +8 -3
- package/lib/typescript/commonjs/src/components/calendar/localeNames.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/components/calendar/selection.d.ts +2 -0
- package/lib/typescript/commonjs/src/components/calendar/selection.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/components/container/DefaultSheet.d.ts +10 -2
- package/lib/typescript/commonjs/src/components/container/DefaultSheet.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/components/container/PickerContainer.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/components/container/containerStyles.d.ts +6 -0
- package/lib/typescript/commonjs/src/components/container/containerStyles.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/components/field/RangeFields.d.ts +5 -0
- package/lib/typescript/commonjs/src/components/field/RangeFields.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/components/field/SegmentedInput.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/components/field/ValueField.d.ts +7 -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 +14 -5
- package/lib/typescript/commonjs/src/components/field/fieldText.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/components/hooks/useBottomInset.d.ts +8 -0
- package/lib/typescript/commonjs/src/components/hooks/useBottomInset.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/components/hooks/useKeyboardFold.d.ts +10 -2
- package/lib/typescript/commonjs/src/components/hooks/useKeyboardFold.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/components/hooks/useOpenPicker.d.ts +2 -1
- package/lib/typescript/commonjs/src/components/hooks/useOpenPicker.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/components/hooks/useTypedSegments.d.ts +3 -2
- package/lib/typescript/commonjs/src/components/hooks/useTypedSegments.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/components/theme/defaultStrings.d.ts +13 -2
- 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/numerals.d.ts +7 -0
- package/lib/typescript/commonjs/src/components/theme/numerals.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/theme/tokens.d.ts +3 -1
- package/lib/typescript/commonjs/src/components/theme/tokens.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/components/time/TimeRow.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/components/time/TypedTime.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/components/time/Wheel.d.ts +5 -0
- package/lib/typescript/commonjs/src/components/time/Wheel.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/components/time/timeStyles.d.ts +0 -2
- package/lib/typescript/commonjs/src/components/time/timeStyles.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/components/types.d.ts +84 -4
- package/lib/typescript/commonjs/src/components/types.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/core/calendarSystem.d.ts +20 -5
- package/lib/typescript/commonjs/src/core/calendarSystem.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/core/digits.d.ts +3 -0
- package/lib/typescript/commonjs/src/core/digits.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/core/draft.d.ts +12 -1
- package/lib/typescript/commonjs/src/core/draft.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/core/locale.d.ts +6 -0
- package/lib/typescript/commonjs/src/core/locale.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/core/numerals.d.ts +15 -0
- package/lib/typescript/commonjs/src/core/numerals.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/core/segmentEditor.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/core/segments.d.ts +0 -2
- package/lib/typescript/commonjs/src/core/segments.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/core/selectionRules.d.ts +3 -2
- package/lib/typescript/commonjs/src/core/selectionRules.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/core/timeEntry.d.ts +4 -24
- package/lib/typescript/commonjs/src/core/timeEntry.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/icons/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/index.d.ts +7 -3
- package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
- package/lib/typescript/module/src/adapters/utcMidnight.d.ts.map +1 -1
- package/lib/typescript/module/src/components/DateTimePicker.d.ts.map +1 -1
- package/lib/typescript/module/src/components/calendar/Calendar.d.ts +8 -4
- package/lib/typescript/module/src/components/calendar/Calendar.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/CalendarSwitch.d.ts +26 -0
- package/lib/typescript/module/src/components/calendar/CalendarSwitch.d.ts.map +1 -0
- package/lib/typescript/module/src/components/calendar/DayCell.d.ts +1 -1
- package/lib/typescript/module/src/components/calendar/DayCell.d.ts.map +1 -1
- package/lib/typescript/module/src/components/calendar/DayGrid.d.ts +2 -0
- package/lib/typescript/module/src/components/calendar/DayGrid.d.ts.map +1 -1
- package/lib/typescript/module/src/components/calendar/PeriodGrid.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/calendar/localeNames.d.ts +8 -3
- package/lib/typescript/module/src/components/calendar/localeNames.d.ts.map +1 -1
- package/lib/typescript/module/src/components/calendar/selection.d.ts +2 -0
- package/lib/typescript/module/src/components/calendar/selection.d.ts.map +1 -1
- package/lib/typescript/module/src/components/container/DefaultSheet.d.ts +10 -2
- package/lib/typescript/module/src/components/container/DefaultSheet.d.ts.map +1 -1
- package/lib/typescript/module/src/components/container/PickerContainer.d.ts.map +1 -1
- package/lib/typescript/module/src/components/container/containerStyles.d.ts +6 -0
- package/lib/typescript/module/src/components/container/containerStyles.d.ts.map +1 -1
- package/lib/typescript/module/src/components/field/RangeFields.d.ts +5 -0
- package/lib/typescript/module/src/components/field/RangeFields.d.ts.map +1 -1
- package/lib/typescript/module/src/components/field/SegmentedInput.d.ts.map +1 -1
- package/lib/typescript/module/src/components/field/ValueField.d.ts +7 -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 +14 -5
- package/lib/typescript/module/src/components/field/fieldText.d.ts.map +1 -1
- package/lib/typescript/module/src/components/hooks/useBottomInset.d.ts +8 -0
- package/lib/typescript/module/src/components/hooks/useBottomInset.d.ts.map +1 -0
- package/lib/typescript/module/src/components/hooks/useKeyboardFold.d.ts +10 -2
- package/lib/typescript/module/src/components/hooks/useKeyboardFold.d.ts.map +1 -1
- package/lib/typescript/module/src/components/hooks/useOpenPicker.d.ts +2 -1
- package/lib/typescript/module/src/components/hooks/useOpenPicker.d.ts.map +1 -1
- package/lib/typescript/module/src/components/hooks/useTypedSegments.d.ts +3 -2
- package/lib/typescript/module/src/components/hooks/useTypedSegments.d.ts.map +1 -1
- package/lib/typescript/module/src/components/theme/defaultStrings.d.ts +13 -2
- 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/numerals.d.ts +7 -0
- package/lib/typescript/module/src/components/theme/numerals.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/theme/tokens.d.ts +3 -1
- package/lib/typescript/module/src/components/theme/tokens.d.ts.map +1 -1
- package/lib/typescript/module/src/components/time/TimeRow.d.ts.map +1 -1
- package/lib/typescript/module/src/components/time/TypedTime.d.ts.map +1 -1
- package/lib/typescript/module/src/components/time/Wheel.d.ts +5 -0
- package/lib/typescript/module/src/components/time/Wheel.d.ts.map +1 -1
- package/lib/typescript/module/src/components/time/timeStyles.d.ts +0 -2
- package/lib/typescript/module/src/components/time/timeStyles.d.ts.map +1 -1
- package/lib/typescript/module/src/components/types.d.ts +84 -4
- package/lib/typescript/module/src/components/types.d.ts.map +1 -1
- package/lib/typescript/module/src/core/calendarSystem.d.ts +20 -5
- package/lib/typescript/module/src/core/calendarSystem.d.ts.map +1 -1
- package/lib/typescript/module/src/core/digits.d.ts +3 -0
- package/lib/typescript/module/src/core/digits.d.ts.map +1 -0
- package/lib/typescript/module/src/core/draft.d.ts +12 -1
- package/lib/typescript/module/src/core/draft.d.ts.map +1 -1
- package/lib/typescript/module/src/core/locale.d.ts +6 -0
- package/lib/typescript/module/src/core/locale.d.ts.map +1 -1
- package/lib/typescript/module/src/core/numerals.d.ts +15 -0
- package/lib/typescript/module/src/core/numerals.d.ts.map +1 -0
- package/lib/typescript/module/src/core/segmentEditor.d.ts.map +1 -1
- package/lib/typescript/module/src/core/segments.d.ts +0 -2
- package/lib/typescript/module/src/core/segments.d.ts.map +1 -1
- package/lib/typescript/module/src/core/selectionRules.d.ts +3 -2
- package/lib/typescript/module/src/core/selectionRules.d.ts.map +1 -1
- package/lib/typescript/module/src/core/timeEntry.d.ts +4 -24
- package/lib/typescript/module/src/core/timeEntry.d.ts.map +1 -1
- package/lib/typescript/module/src/icons/index.d.ts.map +1 -1
- package/lib/typescript/module/src/index.d.ts +7 -3
- package/lib/typescript/module/src/index.d.ts.map +1 -1
- package/package.json +22 -7
- package/src/adapters/utcMidnight.ts +14 -5
- package/src/components/DateTimePicker.tsx +607 -108
- package/src/components/calendar/Calendar.tsx +54 -16
- package/src/components/calendar/CalendarHeader.tsx +41 -9
- package/src/components/calendar/CalendarSwitch.tsx +170 -0
- package/src/components/calendar/DayCell.tsx +16 -4
- package/src/components/calendar/DayGrid.tsx +18 -3
- package/src/components/calendar/PeriodGrid.tsx +3 -1
- package/src/components/calendar/calendarStyles.ts +3 -2
- package/src/components/calendar/localeNames.ts +52 -22
- package/src/components/calendar/selection.ts +8 -0
- package/src/components/container/DefaultSheet.tsx +60 -14
- package/src/components/container/PickerContainer.tsx +4 -0
- package/src/components/container/PickerLayout.tsx +1 -1
- package/src/components/container/containerStyles.ts +12 -3
- package/src/components/field/RangeFields.tsx +12 -2
- package/src/components/field/SegmentedInput.tsx +8 -3
- package/src/components/field/ValueField.tsx +94 -18
- package/src/components/field/fieldStyles.ts +6 -0
- package/src/components/field/fieldText.ts +68 -15
- package/src/components/hooks/useBottomInset.ts +33 -0
- package/src/components/hooks/useKeyboardFold.ts +41 -13
- package/src/components/hooks/useOpenPicker.ts +41 -18
- package/src/components/hooks/useTypedSegments.ts +7 -3
- package/src/components/theme/defaultStrings.ts +29 -4
- package/src/components/theme/direction.ts +12 -0
- package/src/components/theme/numerals.ts +11 -0
- package/src/components/theme/styleKeys.ts +18 -1
- package/src/components/theme/tokens.ts +5 -1
- package/src/components/time/TimeRow.tsx +23 -3
- package/src/components/time/TypedTime.tsx +3 -1
- package/src/components/time/Wheel.tsx +19 -5
- package/src/components/time/timeStyles.ts +2 -3
- package/src/components/types.ts +86 -4
- package/src/core/calendarSystem.ts +145 -21
- package/src/core/digits.ts +21 -0
- package/src/core/draft.ts +41 -13
- package/src/core/locale.ts +20 -3
- package/src/core/numerals.ts +35 -0
- package/src/core/segmentEditor.ts +13 -0
- package/src/core/segments.ts +0 -8
- package/src/core/selectionRules.ts +3 -2
- package/src/core/timeEntry.ts +6 -96
- package/src/icons/index.tsx +3 -1
- package/src/index.tsx +12 -2
|
@@ -2,18 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
4
4
|
import { DateTime } from 'luxon';
|
|
5
|
+
import { View } from 'react-native';
|
|
5
6
|
import { resolveAdapter } from "../adapters/index.js";
|
|
6
|
-
import { daysBetween, isSameDay } from "../core/calendarDate.js";
|
|
7
|
+
import { compareCalendarDates, daysBetween, isSameDay } from "../core/calendarDate.js";
|
|
7
8
|
import { createConstraints } from "../core/constraints.js";
|
|
8
|
-
import { createDraft, DEFAULT_TIME, draftToWire, setTime as applyTime, validateDraft } from "../core/draft.js";
|
|
9
|
-
import { resolveCalendarSystem } from "../core/calendarSystem.js";
|
|
9
|
+
import { clearDraft as emptied, createDraft, DEFAULT_TIME, draftToWire, sameDayRangeOk, setTime as applyTime, validateDraft } from "../core/draft.js";
|
|
10
|
+
import { hijriDateText, hijriPeriods, isHijriSupported, resolveCalendarSystem } from "../core/calendarSystem.js";
|
|
10
11
|
import { defaultLocale, deriveDateFormat, deriveFirstDayOfWeek, deriveTimeFormat, normalizeDateFormat } from "../core/locale.js";
|
|
12
|
+
import { arabicDigits, latinDigits, localeDigits } from "../core/numerals.js";
|
|
11
13
|
import { withSelectionRules } from "../core/selectionRules.js";
|
|
12
14
|
import { checkTime } from "../core/timeEntry.js";
|
|
13
15
|
import Calendar from "./calendar/Calendar.js";
|
|
16
|
+
import CalendarSwitch from "./calendar/CalendarSwitch.js";
|
|
14
17
|
import { localeNames } from "./calendar/localeNames.js";
|
|
18
|
+
import { RtlContext } from "./theme/direction.js";
|
|
19
|
+
import { NumeralsContext } from "./theme/numerals.js";
|
|
20
|
+
import { firstSelectedDay } from "./calendar/selection.js";
|
|
15
21
|
import PickerContainer from "./container/PickerContainer.js";
|
|
16
|
-
import { formatMultipleText, formatRangeText, formatValueText } from "./field/fieldText.js";
|
|
22
|
+
import { formatDateText, formatMultipleText, formatRangeText, formatValueText } from "./field/fieldText.js";
|
|
17
23
|
import FieldMessages from "./field/FieldMessages.js";
|
|
18
24
|
import RangeFields from "./field/RangeFields.js";
|
|
19
25
|
import ValueField from "./field/ValueField.js";
|
|
@@ -22,17 +28,43 @@ import { useOpenPicker } from "./hooks/useOpenPicker.js";
|
|
|
22
28
|
import { usePickerDraft } from "./hooks/usePickerDraft.js";
|
|
23
29
|
import { useTodayTick } from "./hooks/useTodayTick.js";
|
|
24
30
|
import TimeRows from "./time/TimeRows.js";
|
|
25
|
-
import { resolveStrings } from "./theme/defaultStrings.js";
|
|
31
|
+
import { DEFAULT_STRINGS, compactStrings, resolveStrings } from "./theme/defaultStrings.js";
|
|
26
32
|
import { buildTokens } from "./theme/tokens.js";
|
|
27
33
|
import { DEFAULT_YEAR_RANGE } from "./types.js";
|
|
28
34
|
|
|
29
35
|
/** Same day and time (or both without a time). */
|
|
30
|
-
import { jsx as _jsx,
|
|
36
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
31
37
|
const sameValue = (a, b) => isSameDay(a.date, b.date) && (a.time?.hour ?? -1) === (b.time?.hour ?? -1) && (a.time?.minute ?? -1) === (b.time?.minute ?? -1);
|
|
38
|
+
const ALL_SYSTEMS = ['gregory', 'hijri', 'dual'];
|
|
39
|
+
const RTL = {
|
|
40
|
+
direction: 'rtl'
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/** The same kind of selection with nothing in it. */
|
|
44
|
+
const emptySelection = sel => sel.kind === 'single' ? {
|
|
45
|
+
kind: 'single',
|
|
46
|
+
day: null
|
|
47
|
+
} : sel.kind === 'range' ? {
|
|
48
|
+
kind: 'range',
|
|
49
|
+
from: null,
|
|
50
|
+
to: null
|
|
51
|
+
} : {
|
|
52
|
+
...sel,
|
|
53
|
+
days: []
|
|
54
|
+
};
|
|
32
55
|
|
|
33
56
|
/** Minute steps that divide the hour. */
|
|
34
57
|
const MINUTE_STEPS = [1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30, 60];
|
|
35
58
|
|
|
59
|
+
/** A folded calendar stays mounted, so it comes back on the month and view it showed. */
|
|
60
|
+
const FOLDED = {
|
|
61
|
+
display: 'none'
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
/** The later / earlier of a limit and a bound; the bound when there's no limit. */
|
|
65
|
+
const later = (a, b) => a && compareCalendarDates(a, b) > 0 ? a : b;
|
|
66
|
+
const earlier = (a, b) => a && compareCalendarDates(a, b) < 0 ? a : b;
|
|
67
|
+
|
|
36
68
|
/**
|
|
37
69
|
* A date & time picker: a value field that opens a sheet (or an inline panel)
|
|
38
70
|
* with a calendar and, for date-time values, a time row. Single, range and
|
|
@@ -72,6 +104,7 @@ const DateTimePicker = props => {
|
|
|
72
104
|
disabled = false,
|
|
73
105
|
readOnly = false,
|
|
74
106
|
allowTyping,
|
|
107
|
+
hideCalendarOnKeyboard = true,
|
|
75
108
|
allowFieldTyping,
|
|
76
109
|
allowClear,
|
|
77
110
|
errorMessage,
|
|
@@ -103,6 +136,11 @@ const DateTimePicker = props => {
|
|
|
103
136
|
initialVisibleDate,
|
|
104
137
|
enableMonthSwipe = true,
|
|
105
138
|
calendarSystem,
|
|
139
|
+
calendarSwitch,
|
|
140
|
+
onCalendarSystemChange,
|
|
141
|
+
dualDefaultTab = 'gregory',
|
|
142
|
+
hijriLocale = 'ar-SA',
|
|
143
|
+
renderCalendarSwitch,
|
|
106
144
|
showToday = false,
|
|
107
145
|
showHolidays = true,
|
|
108
146
|
onVisibleMonthChange,
|
|
@@ -110,6 +148,7 @@ const DateTimePicker = props => {
|
|
|
110
148
|
validate,
|
|
111
149
|
yearRange: yearRangeProp = DEFAULT_YEAR_RANGE,
|
|
112
150
|
locale,
|
|
151
|
+
numerals: numeralsProp,
|
|
113
152
|
timeZone,
|
|
114
153
|
now,
|
|
115
154
|
timeFormat: timeFormatProp,
|
|
@@ -129,6 +168,7 @@ const DateTimePicker = props => {
|
|
|
129
168
|
theme,
|
|
130
169
|
styles,
|
|
131
170
|
strings: stringOverrides,
|
|
171
|
+
hijriStrings: hijriOverrides,
|
|
132
172
|
testID
|
|
133
173
|
} = props;
|
|
134
174
|
const tokens = useMemo(() => buildTokens(theme),
|
|
@@ -139,6 +179,69 @@ const DateTimePicker = props => {
|
|
|
139
179
|
const firstDayOfWeek = firstDayProp ?? deriveFirstDayOfWeek(loc);
|
|
140
180
|
// Month and year picks are for single dates only.
|
|
141
181
|
const precision = type === 'date' && mode === 'single' ? precisionProp : 'day';
|
|
182
|
+
// The calendars the switch offers: none for month and year picks (always
|
|
183
|
+
// Gregorian), or when the platform has no Hijri calendar.
|
|
184
|
+
const switchKey = Array.isArray(calendarSwitch) ? calendarSwitch.join(',') : String(!!calendarSwitch);
|
|
185
|
+
const switchSystems = useMemo(() => {
|
|
186
|
+
if (!calendarSwitch || precision !== 'day' || !isHijriSupported()) return null;
|
|
187
|
+
const list = calendarSwitch === true ? ALL_SYSTEMS : ALL_SYSTEMS.filter(x => calendarSwitch.includes(x)).sort((a, b) => calendarSwitch.indexOf(a) - calendarSwitch.indexOf(b));
|
|
188
|
+
return list.length > 1 ? list : null;
|
|
189
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps -- the list is compared by content
|
|
190
|
+
}, [switchKey, precision]);
|
|
191
|
+
const startSystem = () => {
|
|
192
|
+
const wanted = calendarSystem ?? 'gregory';
|
|
193
|
+
return switchSystems && !switchSystems.includes(wanted) ? switchSystems[0] ?? wanted : wanted;
|
|
194
|
+
};
|
|
195
|
+
// The switch changes this; a new calendarSystem prop starts over from it.
|
|
196
|
+
const [chosenSystem, setChosenSystem] = useState(startSystem);
|
|
197
|
+
// The calendar the props open on, which a value from outside counts as
|
|
198
|
+
// picked in. The switch's own choice coming back as the calendarSystem prop
|
|
199
|
+
// (onCalendarSystemChange={setSystem}) isn't a new one.
|
|
200
|
+
const [openedOn, setOpenedOn] = useState(startSystem);
|
|
201
|
+
const echo = useRef(null);
|
|
202
|
+
useEffect(() => {
|
|
203
|
+
const next = startSystem();
|
|
204
|
+
const own = echo.current === next;
|
|
205
|
+
echo.current = null;
|
|
206
|
+
if (own) return;
|
|
207
|
+
setChosenSystem(next);
|
|
208
|
+
setOpenedOn(next);
|
|
209
|
+
},
|
|
210
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps -- only when the props change
|
|
211
|
+
[calendarSystem, switchKey]);
|
|
212
|
+
// Month and year picks are Gregorian whatever the calendar system.
|
|
213
|
+
const system = precision === 'day' ? resolveCalendarSystem(chosenSystem) : 'gregory';
|
|
214
|
+
// A dual calendar shows one of its two tabs; each open starts on dualDefaultTab.
|
|
215
|
+
const [dualTab, setDualTab] = useState(dualDefaultTab);
|
|
216
|
+
/** The calendar on screen. */
|
|
217
|
+
const shownSystem = system === 'dual' ? dualTab : system;
|
|
218
|
+
// A value from outside counts as picked in the calendar the props open on,
|
|
219
|
+
// not the one the user has since chosen in the switch.
|
|
220
|
+
const propSystem = precision === 'day' ? resolveCalendarSystem(openedOn) : 'gregory';
|
|
221
|
+
const outsideSystem = propSystem === 'dual' ? dualDefaultTab : propSystem;
|
|
222
|
+
// Picks say which calendar they were made in only when one can be Hijri.
|
|
223
|
+
const hijriInPlay = switchSystems !== null || system !== 'gregory';
|
|
224
|
+
/**
|
|
225
|
+
* The digits for one calendar: a Hijri calendar (and a date picked in it)
|
|
226
|
+
* shows Arabic digits (١٢٣) in any language; a Gregorian one shows 0–9.
|
|
227
|
+
* `numerals` sets both.
|
|
228
|
+
*/
|
|
229
|
+
const digitsFor = sys => {
|
|
230
|
+
const kind = numeralsProp ?? (sys === 'hijri' ? 'arabic' : 'latin');
|
|
231
|
+
if (kind === 'arabic') return arabicDigits;
|
|
232
|
+
if (kind === 'latin') return latinDigits;
|
|
233
|
+
return localeDigits(sys === 'hijri' ? hijriLocale : loc);
|
|
234
|
+
};
|
|
235
|
+
/**
|
|
236
|
+
* The strings for one calendar. A Hijri one takes `hijriStrings` first, then
|
|
237
|
+
* AM / PM in `hijriLocale` (ص / م), then `strings`.
|
|
238
|
+
*/
|
|
239
|
+
const hijriStrings = useMemo(() => ({
|
|
240
|
+
...strings,
|
|
241
|
+
...hijriPeriods(hijriLocale),
|
|
242
|
+
...compactStrings(hijriOverrides)
|
|
243
|
+
}), [strings, hijriLocale, hijriOverrides]);
|
|
244
|
+
const stringsFor = sys => sys === 'hijri' ? hijriStrings : strings;
|
|
142
245
|
const monthNames = useMemo(() => localeNames(loc).monthsLong, [loc]);
|
|
143
246
|
/** A month or year pick shown as text: "March 2026" or "2026". */
|
|
144
247
|
const periodText = v => {
|
|
@@ -202,7 +305,7 @@ const DateTimePicker = props => {
|
|
|
202
305
|
const {
|
|
203
306
|
isOpen: sheetOpen,
|
|
204
307
|
open,
|
|
205
|
-
close
|
|
308
|
+
close: closePicker
|
|
206
309
|
} = useOpenPicker({
|
|
207
310
|
disabled,
|
|
208
311
|
readOnly,
|
|
@@ -212,7 +315,7 @@ const DateTimePicker = props => {
|
|
|
212
315
|
onClose
|
|
213
316
|
});
|
|
214
317
|
const isOpen = isInline || sheetOpen;
|
|
215
|
-
const keyboardUp = useKeyboardFold(isOpen);
|
|
318
|
+
const keyboardUp = useKeyboardFold(isOpen && hideCalendarOnKeyboard);
|
|
216
319
|
// The picker's own boxes that have focus. Inline, another field on the
|
|
217
320
|
// screen can raise the keyboard, so the calendar folds only for these.
|
|
218
321
|
const [focusedParts, setFocusedParts] = useState({});
|
|
@@ -259,16 +362,36 @@ const DateTimePicker = props => {
|
|
|
259
362
|
};
|
|
260
363
|
})).catch(() => requestedYears.current.delete(year));
|
|
261
364
|
}, [loadHolidays]);
|
|
365
|
+
// A month's grid also shows days of the months either side, and a Hijri
|
|
366
|
+
// month can run from December into January, so a month at either end of a
|
|
367
|
+
// year loads the year next to it too.
|
|
368
|
+
const loadHolidaysAround = useCallback((year, month) => {
|
|
369
|
+
loadHolidaysFor(year);
|
|
370
|
+
if (month >= 11 && year < yearRange.last) loadHolidaysFor(year + 1);
|
|
371
|
+
if (month === 1 && year > yearRange.first) loadHolidaysFor(year - 1);
|
|
372
|
+
}, [loadHolidaysFor, yearRange.first, yearRange.last]);
|
|
262
373
|
const holidays = useMemo(() => [...(holidaysProp ?? []), ...Object.values(loadedHolidays).flat()], [holidaysProp, loadedHolidays]);
|
|
263
374
|
|
|
264
375
|
// Limits are worked out when the picker opens (the screen's own validation
|
|
265
376
|
// after Confirm stays the final check).
|
|
266
377
|
const weekdaysKey = disabledWeekdays?.join(',');
|
|
378
|
+
// Limits built with `dependsOnNow` ("from now on") are rebuilt every minute
|
|
379
|
+
// while the picker is open.
|
|
380
|
+
const [minuteTick, setMinuteTick] = useState(0);
|
|
267
381
|
const constraints = useMemo(() => {
|
|
268
382
|
const nowDate = now?.() ?? new Date();
|
|
383
|
+
// yearRange bounds the limits too, so days outside it are greyed.
|
|
269
384
|
const limits = {
|
|
270
|
-
minDate,
|
|
271
|
-
|
|
385
|
+
minDate: later(minDate, {
|
|
386
|
+
year: yearRange.first,
|
|
387
|
+
month: 1,
|
|
388
|
+
day: 1
|
|
389
|
+
}),
|
|
390
|
+
maxDate: earlier(maxDate, {
|
|
391
|
+
year: yearRange.last,
|
|
392
|
+
month: 12,
|
|
393
|
+
day: 31
|
|
394
|
+
}),
|
|
272
395
|
disabledDates,
|
|
273
396
|
enabledDates,
|
|
274
397
|
timeBounds,
|
|
@@ -291,8 +414,8 @@ const DateTimePicker = props => {
|
|
|
291
414
|
type,
|
|
292
415
|
timeZone: zone,
|
|
293
416
|
now: nowDate,
|
|
294
|
-
minDate,
|
|
295
|
-
maxDate,
|
|
417
|
+
minDate: limits.minDate,
|
|
418
|
+
maxDate: limits.maxDate,
|
|
296
419
|
isDisabled: disabledDates,
|
|
297
420
|
isEnabled: enabledDates,
|
|
298
421
|
timeBounds,
|
|
@@ -300,8 +423,25 @@ const DateTimePicker = props => {
|
|
|
300
423
|
holidays,
|
|
301
424
|
disableHolidays
|
|
302
425
|
});
|
|
303
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps -- `isOpen` and `
|
|
304
|
-
}, [isOpen, today, type, zone, now, holidays, minDate, maxDate, disabledDates, enabledDates, timeBounds, weekdaysKey, disableHolidays, getConstraints]);
|
|
426
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps -- `isOpen`, `today` and `minuteTick` refresh the limits on open, at midnight and each minute; weekdays are compared by content
|
|
427
|
+
}, [isOpen, today, minuteTick, type, zone, now, holidays, minDate, maxDate, disabledDates, enabledDates, timeBounds, weekdaysKey, disableHolidays, getConstraints, yearRange]);
|
|
428
|
+
const followsClock = isOpen && constraints.dependsOnNow;
|
|
429
|
+
useEffect(() => {
|
|
430
|
+
if (!followsClock) return;
|
|
431
|
+
let timer;
|
|
432
|
+
const arm = () => {
|
|
433
|
+
const ms = 60_000 - (now?.() ?? new Date()).getTime() % 60_000;
|
|
434
|
+
timer = setTimeout(() => {
|
|
435
|
+
setMinuteTick(n => n + 1);
|
|
436
|
+
arm();
|
|
437
|
+
}, ms);
|
|
438
|
+
// Under Node (e.g. Jest) the timer must not keep the process alive.
|
|
439
|
+
timer.unref?.();
|
|
440
|
+
};
|
|
441
|
+
arm();
|
|
442
|
+
return () => clearTimeout(timer);
|
|
443
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps -- armed while open with a clock-bound limit
|
|
444
|
+
}, [followsClock]);
|
|
305
445
|
|
|
306
446
|
// A typed field that doesn't parse blocks Confirm, per field: one end of a
|
|
307
447
|
// range can't hide the other end's problem.
|
|
@@ -328,14 +468,30 @@ const DateTimePicker = props => {
|
|
|
328
468
|
const [wheelSpinning, setWheelSpinning] = useState(false);
|
|
329
469
|
// From/To layout: the end that calendar taps fill. perDate: the day the time row edits.
|
|
330
470
|
const [activeEnd, setActiveEnd] = useState('from');
|
|
471
|
+
// From/To layout: a From or To field was tapped, so the next day tap edits that end only.
|
|
472
|
+
const [endPicked, setEndPicked] = useState(false);
|
|
473
|
+
const activateEnd = useCallback(end => {
|
|
474
|
+
setActiveEnd(end);
|
|
475
|
+
setEndPicked(true);
|
|
476
|
+
}, []);
|
|
331
477
|
const [activeDay, setActiveDay] = useState(null);
|
|
332
478
|
const resetSelectionUi = useCallback(() => {
|
|
479
|
+
// What was typed is gone with the selection, so nothing blocks Confirm.
|
|
480
|
+
setTypingBlocks({});
|
|
333
481
|
setPendingTimes({});
|
|
334
482
|
setActiveEnd('from');
|
|
483
|
+
setEndPicked(false);
|
|
335
484
|
setActiveDay(null);
|
|
336
485
|
}, []);
|
|
486
|
+
// A day in the month the calendar last showed, so a switch to the other
|
|
487
|
+
// calendar opens on the same days. Each open starts from the value again.
|
|
488
|
+
const shownAnchor = useRef(null);
|
|
489
|
+
const rememberAnchor = useCallback(day => {
|
|
490
|
+
shownAnchor.current = day;
|
|
491
|
+
}, []);
|
|
337
492
|
// Opening or closing starts fresh: nothing edited, nothing blocked.
|
|
338
493
|
useEffect(() => {
|
|
494
|
+
shownAnchor.current = null;
|
|
339
495
|
edited.current = false;
|
|
340
496
|
setTypingBlocks({});
|
|
341
497
|
setTimeCheck(0);
|
|
@@ -399,6 +555,59 @@ const DateTimePicker = props => {
|
|
|
399
555
|
};
|
|
400
556
|
const valueKey = JSON.stringify(value ?? '');
|
|
401
557
|
|
|
558
|
+
// A selection belongs to the calendar it was picked in (Gregorian or Hijri):
|
|
559
|
+
// it shows only there, and the field writes it in that calendar. A saved
|
|
560
|
+
// value remembers its calendar; one from outside counts as picked in the
|
|
561
|
+
// calendar the picker opens on.
|
|
562
|
+
// The saved value as a draft, for the on-screen field and for comparing
|
|
563
|
+
// values by what they hold.
|
|
564
|
+
const saved = useMemo(() => createDraft(mode, value, draftOptions),
|
|
565
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps -- the value is compared by content (`valueKey`)
|
|
566
|
+
[valueKey, mode, draftOptions]);
|
|
567
|
+
/** A draft's days and times, so a value written another way ({to, from}) still matches. */
|
|
568
|
+
const contentOf = dr => JSON.stringify(valuesOf(dr));
|
|
569
|
+
const savedContent = contentOf(saved);
|
|
570
|
+
const savedSystemRef = useRef(null);
|
|
571
|
+
const savedSystem = savedSystemRef.current?.content === savedContent ? savedSystemRef.current.system : outsideSystem;
|
|
572
|
+
const [draftSystem, setDraftSystem] = useState(savedSystem);
|
|
573
|
+
// The draft is rebuilt on open and on a new value; so is its calendar. A new
|
|
574
|
+
// calendarSystem prop while the user is picking starts the selection over,
|
|
575
|
+
// since a selection is one calendar's.
|
|
576
|
+
const systemSeen = useRef({
|
|
577
|
+
isOpen,
|
|
578
|
+
valueKey,
|
|
579
|
+
savedSystem
|
|
580
|
+
});
|
|
581
|
+
useEffect(() => {
|
|
582
|
+
const seen = systemSeen.current;
|
|
583
|
+
systemSeen.current = {
|
|
584
|
+
isOpen,
|
|
585
|
+
valueKey,
|
|
586
|
+
savedSystem
|
|
587
|
+
};
|
|
588
|
+
setDraftSystem(savedSystem);
|
|
589
|
+
const systemOnly = seen.isOpen === isOpen && seen.valueKey === valueKey && seen.savedSystem !== savedSystem;
|
|
590
|
+
if (systemOnly && isOpen && edited.current) {
|
|
591
|
+
draft.clear();
|
|
592
|
+
resetSelectionUi();
|
|
593
|
+
}
|
|
594
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps -- the draft's actions are stable
|
|
595
|
+
}, [isOpen, valueKey, savedSystem]);
|
|
596
|
+
useEffect(() => setDualTab(dualDefaultTab), [isOpen, dualDefaultTab]);
|
|
597
|
+
const selectionShown = draftSystem === shownSystem;
|
|
598
|
+
/** Saves a value: with the calendar it was picked in, when one can be Hijri. */
|
|
599
|
+
const emitChange = useCallback((wire, picked) => {
|
|
600
|
+
savedSystemRef.current = {
|
|
601
|
+
content: contentOf(createDraft(mode, wire, draftOptions)),
|
|
602
|
+
system: picked
|
|
603
|
+
};
|
|
604
|
+
if (hijriInPlay) onChange(wire, {
|
|
605
|
+
calendarSystem: picked
|
|
606
|
+
});else onChange(wire);
|
|
607
|
+
},
|
|
608
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps -- contentOf reads only `type` and the options listed
|
|
609
|
+
[hijriInPlay, onChange, mode, draftOptions]);
|
|
610
|
+
|
|
402
611
|
/**
|
|
403
612
|
* Whether a draft can be saved as it stands: complete, every day allowed,
|
|
404
613
|
* every time allowed and on the minute step, and nothing being typed or
|
|
@@ -411,19 +620,19 @@ const DateTimePicker = props => {
|
|
|
411
620
|
|
|
412
621
|
// Every save: Confirm, an 'instant' edit (onConfirm is added by `confirm`).
|
|
413
622
|
const commit = useCallback(wire => {
|
|
414
|
-
|
|
623
|
+
emitChange(wire, draftSystem);
|
|
415
624
|
onBlur?.();
|
|
416
|
-
}, [
|
|
625
|
+
}, [emitChange, draftSystem, onBlur]);
|
|
417
626
|
const confirm = useCallback(() => {
|
|
418
627
|
if (!canConfirm) return;
|
|
419
628
|
const {
|
|
420
629
|
validate: check,
|
|
421
630
|
onError: report,
|
|
422
|
-
value:
|
|
631
|
+
value: current
|
|
423
632
|
} = latest.current;
|
|
424
633
|
if (timeBlocked) {
|
|
425
634
|
setTimeCheck(n => n + 1);
|
|
426
|
-
report?.(timeIssue ?? 'TIME_NOT_ALLOWED',
|
|
635
|
+
report?.(timeIssue ?? 'TIME_NOT_ALLOWED', current);
|
|
427
636
|
return;
|
|
428
637
|
}
|
|
429
638
|
const wire = draftToWire(preview, draftOptions);
|
|
@@ -439,14 +648,14 @@ const DateTimePicker = props => {
|
|
|
439
648
|
commit(wire);
|
|
440
649
|
onConfirm?.(wire);
|
|
441
650
|
edited.current = false;
|
|
442
|
-
if (!isInline)
|
|
443
|
-
}, [canConfirm, timeBlocked, timeIssue, commit, onConfirm, preview, draftOptions, isInline,
|
|
651
|
+
if (!isInline) closePicker();
|
|
652
|
+
}, [canConfirm, timeBlocked, timeIssue, commit, onConfirm, preview, draftOptions, isInline, closePicker]);
|
|
444
653
|
const clearValue = useCallback(() => {
|
|
445
654
|
draft.clear();
|
|
446
655
|
resetSelectionUi();
|
|
447
656
|
edited.current = false;
|
|
448
|
-
|
|
449
|
-
}, [draft,
|
|
657
|
+
emitChange('', draftSystem);
|
|
658
|
+
}, [draft, emitChange, draftSystem, resetSelectionUi]);
|
|
450
659
|
const clearDraft = useCallback(() => {
|
|
451
660
|
edited.current = true;
|
|
452
661
|
draft.clear();
|
|
@@ -455,9 +664,10 @@ const DateTimePicker = props => {
|
|
|
455
664
|
|
|
456
665
|
// × in the field above the calendar. 'instant' saves every edit, so it
|
|
457
666
|
// clears the saved value too (once; an empty value isn't saved again).
|
|
667
|
+
const hasSaved = valuesOf(saved).some(v => v !== null);
|
|
458
668
|
const clearInSheet = useCallback(() => {
|
|
459
|
-
if (commitMode === 'instant' &&
|
|
460
|
-
}, [commitMode,
|
|
669
|
+
if (commitMode === 'instant' && hasSaved) clearValue();else clearDraft();
|
|
670
|
+
}, [commitMode, hasSaved, clearValue, clearDraft]);
|
|
461
671
|
|
|
462
672
|
// Opening or closing starts without the last `validate` message.
|
|
463
673
|
useEffect(() => setValidation(null), [isOpen]);
|
|
@@ -468,15 +678,27 @@ const DateTimePicker = props => {
|
|
|
468
678
|
// An edit equal to the saved value isn't saved again; one `validate`
|
|
469
679
|
// rejected waits until the selection or the saved value changes.
|
|
470
680
|
const lastRejected = useRef(null);
|
|
681
|
+
// The last value saved: not saved again while the parent's `value` catches
|
|
682
|
+
// up (a slow store, a server round trip) or when it never does.
|
|
683
|
+
const lastEmitted = useRef(null);
|
|
471
684
|
useEffect(() => {
|
|
472
685
|
lastRejected.current = null;
|
|
473
|
-
|
|
474
|
-
|
|
686
|
+
lastEmitted.current = null;
|
|
687
|
+
}, [valueKey, isOpen]);
|
|
688
|
+
// The field in the sheet saves once typing there is done (focus leaves it),
|
|
689
|
+
// so 09:30 isn't saved as 09:00 and 09:03 on the way.
|
|
690
|
+
const sheetTyping = !!(focusedParts.value || focusedParts['value-from'] || focusedParts['value-to']);
|
|
691
|
+
/** Saves the draft in instant mode; `typingDone` once the sheet's field is left. */
|
|
692
|
+
const saveInstant = typingDone => {
|
|
475
693
|
if (commitMode !== 'instant' || !isOpen || !edited.current) return;
|
|
476
|
-
if (timeIssue || !canSave(draft.draft)) return;
|
|
694
|
+
if (!typingDone || timeIssue || !canSave(draft.draft)) return;
|
|
477
695
|
const wire = draft.toWire();
|
|
478
696
|
const key = JSON.stringify(wire);
|
|
479
|
-
if (key ===
|
|
697
|
+
if (key === lastRejected.current || key === lastEmitted.current) return;
|
|
698
|
+
// The same dates picked in the same calendar aren't saved again; the same
|
|
699
|
+
// dates picked in the other calendar are.
|
|
700
|
+
const unchanged = key === valueKey || contentOf(draft.draft) === savedContent;
|
|
701
|
+
if (unchanged && draftSystem === savedSystem) return;
|
|
480
702
|
const message = latest.current.validate?.(wire);
|
|
481
703
|
if (message) {
|
|
482
704
|
lastRejected.current = key;
|
|
@@ -487,9 +709,22 @@ const DateTimePicker = props => {
|
|
|
487
709
|
latest.current.onError?.('VALIDATION', wire);
|
|
488
710
|
return;
|
|
489
711
|
}
|
|
712
|
+
lastEmitted.current = key;
|
|
490
713
|
commit(wire);
|
|
491
|
-
|
|
492
|
-
|
|
714
|
+
};
|
|
715
|
+
// Only typing waits for the field to be left; a tap is a finished edit.
|
|
716
|
+
const typedLast = useRef(false);
|
|
717
|
+
useEffect(() => saveInstant(!sheetTyping || !typedLast.current),
|
|
718
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps -- when the draft or what blocks it changes, not when callbacks are re-created
|
|
719
|
+
[commitMode, isOpen, sheetTyping, draft.draft, draftSystem, timeIssue, typingBlocked, wheelSpinning, confirmDisabled, constraints]);
|
|
720
|
+
// Closing while the sheet's field still has focus ends the typing: an
|
|
721
|
+
// instant picker saves what was typed before it closes.
|
|
722
|
+
const saveInstantRef = useRef(saveInstant);
|
|
723
|
+
saveInstantRef.current = saveInstant;
|
|
724
|
+
const close = useCallback(() => {
|
|
725
|
+
saveInstantRef.current(true);
|
|
726
|
+
closePicker();
|
|
727
|
+
}, [closePicker]);
|
|
493
728
|
|
|
494
729
|
// A typed date with no time yet gets one the way a tapped day does: the fixed
|
|
495
730
|
// newDayTime, else a time already typed in the time row, else now.
|
|
@@ -497,14 +732,24 @@ const DateTimePicker = props => {
|
|
|
497
732
|
date: parsed.dateOnly,
|
|
498
733
|
time: fixedTime ?? pending[key] ?? nowTime()
|
|
499
734
|
} : null);
|
|
735
|
+
|
|
736
|
+
// Typed segments are Gregorian, so typing keeps the calendar a selection was
|
|
737
|
+
// picked in; into an empty draft, it takes the calendar on screen.
|
|
738
|
+
const adoptShownIfEmpty = () => {
|
|
739
|
+
if (valuesOf(d).every(v => v === null)) setDraftSystem(shownSystem);
|
|
740
|
+
};
|
|
500
741
|
const onSheetTyped = parsed => {
|
|
501
742
|
edited.current = true;
|
|
743
|
+
typedLast.current = true;
|
|
744
|
+
adoptShownIfEmpty();
|
|
502
745
|
const typed = withFilledTime(parsed, 'single');
|
|
503
746
|
setTypingBlock('single', !parsed.isEmpty && !typed);
|
|
504
747
|
if (typed) draft.setValue(typed, 'single');else if (parsed.isEmpty) draft.clear();
|
|
505
748
|
};
|
|
506
749
|
const onRangeTyped = (end, parsed) => {
|
|
507
750
|
edited.current = true;
|
|
751
|
+
typedLast.current = true;
|
|
752
|
+
adoptShownIfEmpty();
|
|
508
753
|
const typed = withFilledTime(parsed, end);
|
|
509
754
|
setTypingBlock(end, !parsed.isEmpty && !typed);
|
|
510
755
|
if (typed || parsed.isEmpty) draft.setValue(typed, end);
|
|
@@ -525,28 +770,77 @@ const DateTimePicker = props => {
|
|
|
525
770
|
minute: capped % 60
|
|
526
771
|
};
|
|
527
772
|
}, [now, zone, minuteStep]);
|
|
773
|
+
|
|
774
|
+
// A range end picked on the start's day starts an hour after the start (at
|
|
775
|
+
// most the day's latest allowed time, or its last step), so the range isn't
|
|
776
|
+
// out of order before the user has touched the time.
|
|
777
|
+
// A time typed for the end before its day is kept as typed.
|
|
778
|
+
const endTimeFor = (from, day, typed) => {
|
|
779
|
+
if (!fixedTime && typed) return typed;
|
|
780
|
+
const time = fixedTime ?? nowTime();
|
|
781
|
+
if (!from?.time || !isSameDay(from.date, day)) return time;
|
|
782
|
+
const start = from.time.hour * 60 + from.time.minute;
|
|
783
|
+
if (time.hour * 60 + time.minute > start) return time;
|
|
784
|
+
// Within the day's allowed hours when it has them.
|
|
785
|
+
const max = constraints.timeBounds(day)?.max;
|
|
786
|
+
const last = max ? max.hour * 60 + max.minute : 24 * 60 - Math.max(1, minuteStep);
|
|
787
|
+
const end = Math.min(start + 60, last);
|
|
788
|
+
return {
|
|
789
|
+
hour: Math.floor(end / 60),
|
|
790
|
+
minute: end % 60
|
|
791
|
+
};
|
|
792
|
+
};
|
|
528
793
|
const onSelectDay = useCallback(day => {
|
|
529
794
|
edited.current = true;
|
|
530
|
-
|
|
795
|
+
typedLast.current = false;
|
|
796
|
+
// A pick in the other calendar starts over: the selection is one calendar's.
|
|
797
|
+
const fresh = draftSystem !== shownSystem && valuesOf(d).some(v => v !== null);
|
|
798
|
+
setDraftSystem(shownSystem);
|
|
799
|
+
const cur = fresh ? emptied(d) : d;
|
|
800
|
+
const end0 = fresh ? 'from' : activeEnd;
|
|
801
|
+
const dayInEdit = fresh ? null : activeDay;
|
|
802
|
+
const times = fresh ? {} : pending;
|
|
803
|
+
if (fresh) {
|
|
804
|
+
draft.clear();
|
|
805
|
+
resetSelectionUi();
|
|
806
|
+
}
|
|
807
|
+
if (cur.mode === 'range') {
|
|
531
808
|
if (rangeLayout === 'fromTo') {
|
|
809
|
+
setEndPicked(false);
|
|
810
|
+
// A full range: the tap starts a new one (or moves the nearest end).
|
|
811
|
+
if (!endPicked && cur.from.value && cur.to.value) {
|
|
812
|
+
const moveNearest = range?.reselect === 'moveNearestEnd';
|
|
813
|
+
const nearest = Math.abs(daysBetween(cur.from.value.date, day)) < Math.abs(daysBetween(cur.to.value.date, day)) ? 'from' : 'to';
|
|
814
|
+
const end = moveNearest ? nearest : 'from';
|
|
815
|
+
setTypingBlock('from', false);
|
|
816
|
+
setTypingBlock('to', false);
|
|
817
|
+
draft.selectDay(day, fixedTime ?? times[end] ?? nowTime());
|
|
818
|
+
setActiveEnd(moveNearest ? nearest : 'to');
|
|
819
|
+
return;
|
|
820
|
+
}
|
|
821
|
+
// Choosing the end after a start tap: a day before the start moves the start.
|
|
822
|
+
const end1 = end0 === 'to' && !endPicked && cur.from.value && compareCalendarDates(day, cur.from.value.date) < 0 ? 'from' : end0;
|
|
532
823
|
// The tapped day replaces whatever was typed in this end only.
|
|
533
|
-
setTypingBlock(
|
|
534
|
-
draft.setRangeEnd(day,
|
|
535
|
-
|
|
824
|
+
setTypingBlock(end1, false);
|
|
825
|
+
draft.setRangeEnd(day, end1, end1 === 'to' ? endTimeFor(cur.from.value, day, times.to) : fixedTime ?? times.from ?? nowTime());
|
|
826
|
+
// The start tapped again where a range can't be one day deselects
|
|
827
|
+
// it, so the next tap picks the start again.
|
|
828
|
+
const deselects = end1 === 'to' && !sameDayRangeOk(draftOptions) && isSameDay(cur.from.value?.date, day);
|
|
829
|
+
if (end0 === 'from') setActiveEnd('to');else if (deselects) setActiveEnd('from');
|
|
536
830
|
return;
|
|
537
831
|
}
|
|
538
832
|
// The single field: the first tap is the start, the next one the end.
|
|
539
|
-
const startsOver = !
|
|
833
|
+
const startsOver = !cur.from.value || !!cur.to.value && range?.reselect !== 'moveNearestEnd';
|
|
540
834
|
const end = startsOver ? 'from' : 'to';
|
|
541
835
|
setTypingBlock('single', false);
|
|
542
|
-
draft.selectDay(day, fixedTime ??
|
|
836
|
+
draft.selectDay(day, end === 'to' && !cur.to.value ? endTimeFor(cur.from.value, day, times.to) : fixedTime ?? times[end] ?? nowTime());
|
|
543
837
|
return;
|
|
544
838
|
}
|
|
545
|
-
if (
|
|
839
|
+
if (cur.mode === 'multiple') {
|
|
546
840
|
const perDate = type === 'datetime' && multipleTimeMode === 'perDate';
|
|
547
|
-
const picked =
|
|
841
|
+
const picked = cur.slots.some(slot => isSameDay(slot.value?.date, day));
|
|
548
842
|
// perDate: a tap on a picked day first makes it the one the time row edits.
|
|
549
|
-
if (perDate && picked && !isSameDay(
|
|
843
|
+
if (perDate && picked && !isSameDay(dayInEdit, day)) {
|
|
550
844
|
setActiveDay(day);
|
|
551
845
|
return;
|
|
552
846
|
}
|
|
@@ -555,18 +849,28 @@ const DateTimePicker = props => {
|
|
|
555
849
|
return;
|
|
556
850
|
}
|
|
557
851
|
setTypingBlock('single', false);
|
|
558
|
-
draft.selectDay(day, fixedTime ??
|
|
559
|
-
},
|
|
852
|
+
draft.selectDay(day, fixedTime ?? times.single ?? nowTime());
|
|
853
|
+
},
|
|
854
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps -- valuesOf reads only `d` and props listed here
|
|
855
|
+
[d, draft, nowTime, rangeLayout, activeEnd, activeDay, fixedTime, pending, range?.reselect, type, multipleTimeMode, setTypingBlock, draftSystem, shownSystem, resetSelectionUi, endPicked, draftOptions, minuteStep, constraints]);
|
|
856
|
+
|
|
857
|
+
// The calendar gets a tap handler that never changes, so its memoized day
|
|
858
|
+
// cells don't all redraw on every tap; it calls the current one.
|
|
859
|
+
const selectDayRef = useRef(onSelectDay);
|
|
860
|
+
selectDayRef.current = onSelectDay;
|
|
861
|
+
const onSelectDayStable = useCallback(day => selectDayRef.current(day), []);
|
|
560
862
|
|
|
561
863
|
// Greying that depends on what's picked: range length, From/To order, the multiple cap.
|
|
562
864
|
const calendarConstraints = useMemo(() => {
|
|
563
865
|
if (d.mode === 'range') {
|
|
564
|
-
|
|
866
|
+
// A full From/To range greys nothing: the next tap starts a new one.
|
|
867
|
+
const choosingEnd = rangeLayout === 'fromTo' ? activeEnd === 'to' && (endPicked || !d.to.value) : !!d.from.value && !d.to.value;
|
|
565
868
|
return withSelectionRules(constraints, {
|
|
566
869
|
rangeStart: choosingEnd ? d.from.value?.date : null,
|
|
567
870
|
minDays: range?.minDays,
|
|
568
871
|
maxDays: range?.maxDays,
|
|
569
|
-
|
|
872
|
+
// Only an end chosen from the To field can't go before the start.
|
|
873
|
+
blockBeforeStart: rangeLayout === 'fromTo' && endPicked
|
|
570
874
|
});
|
|
571
875
|
}
|
|
572
876
|
if (d.mode === 'multiple') {
|
|
@@ -577,7 +881,7 @@ const DateTimePicker = props => {
|
|
|
577
881
|
});
|
|
578
882
|
}
|
|
579
883
|
return constraints;
|
|
580
|
-
}, [constraints, d, rangeLayout, activeEnd, range?.minDays, range?.maxDays, multiple?.maxSelections]);
|
|
884
|
+
}, [constraints, d, rangeLayout, activeEnd, endPicked, range?.minDays, range?.maxDays, multiple?.maxSelections]);
|
|
581
885
|
const selection = draft.draft.mode === 'single' ? {
|
|
582
886
|
kind: 'single',
|
|
583
887
|
day: draft.draft.slot.value?.date ?? null
|
|
@@ -604,13 +908,13 @@ const DateTimePicker = props => {
|
|
|
604
908
|
}
|
|
605
909
|
}, [isOpen, constraints, today]);
|
|
606
910
|
const handleVisibleMonth = useCallback((year, month) => {
|
|
607
|
-
|
|
911
|
+
loadHolidaysAround(year, month);
|
|
608
912
|
onVisibleMonthChange?.(year, month);
|
|
609
|
-
}, [
|
|
913
|
+
}, [loadHolidaysAround, onVisibleMonthChange]);
|
|
610
914
|
useEffect(() => {
|
|
611
915
|
if (!isOpen) return;
|
|
612
|
-
const anchor = selection.kind === 'single' ? selection.day : null;
|
|
613
|
-
|
|
916
|
+
const anchor = (selection.kind === 'single' ? selection.day : null) ?? today;
|
|
917
|
+
loadHolidaysAround(anchor.year, anchor.month);
|
|
614
918
|
// eslint-disable-next-line react-hooks/exhaustive-deps -- once per open
|
|
615
919
|
}, [isOpen]);
|
|
616
920
|
|
|
@@ -661,17 +965,24 @@ const DateTimePicker = props => {
|
|
|
661
965
|
return;
|
|
662
966
|
}
|
|
663
967
|
setTriggerError('');
|
|
664
|
-
|
|
968
|
+
// Typing keeps the calendar the saved value was picked in.
|
|
969
|
+
emitChange(wire, savedSystem);
|
|
665
970
|
onBlur?.();
|
|
666
971
|
};
|
|
667
972
|
|
|
973
|
+
/** A value's date in the calendar it was picked in: Hijri text, or none for the dateFormat. */
|
|
974
|
+
const dateTextFor = picked => picked === 'hijri' ? v => hijriDateText(v.date, hijriLocale) ?? formatDateText(v, dateFormat) : undefined;
|
|
975
|
+
const savedDateText = dateTextFor(savedSystem);
|
|
976
|
+
const draftDateText = dateTextFor(draftSystem);
|
|
977
|
+
const savedStrings = stringsFor(savedSystem);
|
|
978
|
+
const draftStrings = stringsFor(draftSystem);
|
|
979
|
+
// Error messages inside the picker follow the tab on screen; the on-screen
|
|
980
|
+
// field's keep `strings`.
|
|
981
|
+
const shownStrings = stringsFor(shownSystem);
|
|
982
|
+
|
|
668
983
|
// What the on-screen field shows: the saved value, never the draft.
|
|
669
|
-
const savedKey = valueKey;
|
|
670
|
-
const saved = useMemo(() => createDraft(mode, value, draftOptions),
|
|
671
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps -- the value is compared by content (`savedKey`)
|
|
672
|
-
[savedKey, mode, draftOptions]);
|
|
673
984
|
const savedSingle = saved.mode === 'single' ? saved.slot.value : null;
|
|
674
|
-
const savedText = saved.mode === 'range' ? formatRangeText(saved.from.value, saved.to.value, type, dateFormat, timeFormat, strings.rangeSeparator) : saved.mode === 'multiple' ? formatMultipleText(saved.slots.map(slot => slot.value), type, dateFormat, timeFormat) : precision !== 'day' ? periodText(savedSingle) : undefined;
|
|
985
|
+
const savedText = saved.mode === 'range' ? formatRangeText(saved.from.value, saved.to.value, type, dateFormat, timeFormat, strings.rangeSeparator, savedDateText, savedStrings) : saved.mode === 'multiple' ? formatMultipleText(saved.slots.map(slot => slot.value), type, dateFormat, timeFormat, savedDateText, savedStrings) : precision !== 'day' ? periodText(savedSingle) : undefined;
|
|
675
986
|
const periodPlaceholder = precision === 'year' ? strings.placeholderYear : precision === 'month' ? `${strings.placeholderMonth} ${strings.placeholderYear}` : undefined;
|
|
676
987
|
|
|
677
988
|
// The time a custom renderTimeRow edits, and how it sets it (the same
|
|
@@ -697,7 +1008,7 @@ const DateTimePicker = props => {
|
|
|
697
1008
|
type,
|
|
698
1009
|
mode,
|
|
699
1010
|
value,
|
|
700
|
-
displayText: savedText ?? formatValueText(savedSingle, type, dateFormat, timeFormat),
|
|
1011
|
+
displayText: digitsFor(savedSystem)(savedText ?? formatValueText(savedSingle, type, dateFormat, timeFormat, savedDateText, savedStrings)),
|
|
701
1012
|
disabled,
|
|
702
1013
|
readOnly,
|
|
703
1014
|
isOpen,
|
|
@@ -718,11 +1029,11 @@ const DateTimePicker = props => {
|
|
|
718
1029
|
};
|
|
719
1030
|
const sheetValue = draft.draft.mode === 'single' ? draft.draft.slot.value : null;
|
|
720
1031
|
// A time outside the limits is explained under the time row, not here.
|
|
721
|
-
const sheetValueError = sheetValue && dayOff(sheetValue.date) ?
|
|
1032
|
+
const sheetValueError = sheetValue && dayOff(sheetValue.date) ? shownStrings.errorNotAllowed : '';
|
|
722
1033
|
let rangeError = '';
|
|
723
1034
|
if (d.mode === 'range' && d.from.value && d.to.value) {
|
|
724
1035
|
const length = daysBetween(d.from.value.date, d.to.value.date) + 1;
|
|
725
|
-
if (constraints.dayStatus(d.from.value.date).disabled || constraints.dayStatus(d.to.value.date).disabled) rangeError =
|
|
1036
|
+
if (constraints.dayStatus(d.from.value.date).disabled || constraints.dayStatus(d.to.value.date).disabled) rangeError = shownStrings.errorNotAllowed;else if (previewIssue === 'RANGE_ORDER') rangeError = shownStrings.errorRangeOrder;else if (previewIssue === 'RANGE_LENGTH') rangeError = range?.minDays !== undefined && length < range.minDays ? shownStrings.errorRangeTooShort(range.minDays) : shownStrings.errorRangeTooLong(range?.maxDays ?? length);
|
|
726
1037
|
}
|
|
727
1038
|
const fieldCommon = {
|
|
728
1039
|
type,
|
|
@@ -738,8 +1049,11 @@ const DateTimePicker = props => {
|
|
|
738
1049
|
};
|
|
739
1050
|
const trigger = !showField || isInline ? null : renderField ? renderField(state) : /*#__PURE__*/_jsx(ValueField, {
|
|
740
1051
|
...fieldCommon,
|
|
1052
|
+
strings: savedStrings,
|
|
1053
|
+
errorStrings: strings,
|
|
741
1054
|
value: savedSingle,
|
|
742
1055
|
displayText: savedText,
|
|
1056
|
+
dateText: savedDateText,
|
|
743
1057
|
allowTyping: mode === 'single' && precision === 'day' && allowFieldTyping,
|
|
744
1058
|
onTypingDone: onTriggerTyped,
|
|
745
1059
|
onTyped: () => setTriggerError(''),
|
|
@@ -769,8 +1083,11 @@ const DateTimePicker = props => {
|
|
|
769
1083
|
testID: testID ? `${testID}-value` : undefined
|
|
770
1084
|
}) : mode === 'single' ? /*#__PURE__*/_jsx(ValueField, {
|
|
771
1085
|
...fieldCommon,
|
|
1086
|
+
strings: draftStrings,
|
|
1087
|
+
errorStrings: shownStrings,
|
|
772
1088
|
value: sheetValue,
|
|
773
1089
|
displayText: precision !== 'day' ? periodText(sheetValue) : undefined,
|
|
1090
|
+
dateText: draftDateText,
|
|
774
1091
|
placeholder: sheetOptions?.fieldPlaceholder ?? periodPlaceholder,
|
|
775
1092
|
allowTyping: allowTyping && precision === 'day',
|
|
776
1093
|
onTyped: onSheetTyped,
|
|
@@ -783,13 +1100,16 @@ const DateTimePicker = props => {
|
|
|
783
1100
|
testID: testID ? `${testID}-value` : undefined
|
|
784
1101
|
}) : d.mode === 'range' ? /*#__PURE__*/_jsx(RangeFields, {
|
|
785
1102
|
...fieldCommon,
|
|
1103
|
+
strings: draftStrings,
|
|
1104
|
+
errorStrings: shownStrings,
|
|
786
1105
|
layout: rangeLayout,
|
|
1106
|
+
dateText: draftDateText,
|
|
787
1107
|
showIcon: sheetOptions?.fieldIcon,
|
|
788
1108
|
from: d.from.value,
|
|
789
1109
|
to: d.to.value,
|
|
790
1110
|
placeholder: sheetOptions?.fieldPlaceholder,
|
|
791
1111
|
activeEnd: activeEnd,
|
|
792
|
-
onActivate:
|
|
1112
|
+
onActivate: activateEnd,
|
|
793
1113
|
allowTyping: allowTyping,
|
|
794
1114
|
onTyped: onRangeTyped,
|
|
795
1115
|
onFocusChange: (end, f) => reportFocus(`value-${end}`, f),
|
|
@@ -800,8 +1120,9 @@ const DateTimePicker = props => {
|
|
|
800
1120
|
testID: testID
|
|
801
1121
|
}) : d.mode === 'multiple' ? /*#__PURE__*/_jsx(ValueField, {
|
|
802
1122
|
...fieldCommon,
|
|
1123
|
+
strings: draftStrings,
|
|
803
1124
|
value: null,
|
|
804
|
-
displayText: formatMultipleText(draftValues, type, dateFormat, timeFormat),
|
|
1125
|
+
displayText: formatMultipleText(draftValues, type, dateFormat, timeFormat, draftDateText, draftStrings),
|
|
805
1126
|
placeholder: sheetOptions?.fieldPlaceholder,
|
|
806
1127
|
allowClear: allowClear,
|
|
807
1128
|
onClear: clearInSheet,
|
|
@@ -810,37 +1131,102 @@ const DateTimePicker = props => {
|
|
|
810
1131
|
active: true,
|
|
811
1132
|
testID: testID ? `${testID}-value` : undefined
|
|
812
1133
|
}) : null;
|
|
813
|
-
const
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
1134
|
+
const systemLabels = {
|
|
1135
|
+
gregory: strings.calendarGregorian ?? DEFAULT_STRINGS.calendarGregorian,
|
|
1136
|
+
hijri: strings.calendarHijri ?? DEFAULT_STRINGS.calendarHijri,
|
|
1137
|
+
dual: strings.calendarDual ?? DEFAULT_STRINGS.calendarDual
|
|
1138
|
+
};
|
|
1139
|
+
const systemA11yLabel = strings.a11yCalendarSystem ?? DEFAULT_STRINGS.a11yCalendarSystem;
|
|
1140
|
+
const chooseSystem = next => {
|
|
1141
|
+
if (next === system) return;
|
|
1142
|
+
setChosenSystem(next);
|
|
1143
|
+
if (next === 'dual') setDualTab(dualDefaultTab);
|
|
1144
|
+
echo.current = next;
|
|
1145
|
+
onCalendarSystemChange?.(next);
|
|
1146
|
+
};
|
|
1147
|
+
const calendarSwitchNode = !switchSystems ? null : renderCalendarSwitch ? renderCalendarSwitch({
|
|
1148
|
+
systems: switchSystems,
|
|
1149
|
+
selected: system,
|
|
1150
|
+
onSelect: chooseSystem,
|
|
1151
|
+
tokens,
|
|
1152
|
+
strings
|
|
1153
|
+
}) : /*#__PURE__*/_jsx(CalendarSwitch, {
|
|
1154
|
+
variant: "switch",
|
|
1155
|
+
options: switchSystems.map(v => {
|
|
1156
|
+
return {
|
|
1157
|
+
value: v,
|
|
1158
|
+
label: systemLabels[v]
|
|
1159
|
+
};
|
|
1160
|
+
}),
|
|
1161
|
+
selected: system,
|
|
1162
|
+
onSelect: chooseSystem,
|
|
1163
|
+
accessibilityLabel: systemA11yLabel,
|
|
840
1164
|
tokens: tokens,
|
|
841
1165
|
styles: styles,
|
|
842
|
-
|
|
843
|
-
|
|
1166
|
+
testID: testID ? `${testID}-calendar-switch` : undefined
|
|
1167
|
+
});
|
|
1168
|
+
const dualTabs = system !== 'dual' ? null : /*#__PURE__*/_jsx(CalendarSwitch, {
|
|
1169
|
+
variant: "tabs",
|
|
1170
|
+
options: [{
|
|
1171
|
+
value: 'gregory',
|
|
1172
|
+
label: systemLabels.gregory
|
|
1173
|
+
}, {
|
|
1174
|
+
value: 'hijri',
|
|
1175
|
+
label: systemLabels.hijri
|
|
1176
|
+
}],
|
|
1177
|
+
selected: dualTab,
|
|
1178
|
+
onSelect: setDualTab,
|
|
1179
|
+
accessibilityLabel: systemA11yLabel,
|
|
1180
|
+
tokens: tokens,
|
|
1181
|
+
styles: styles,
|
|
1182
|
+
testID: testID ? `${testID}-dual-tabs` : undefined
|
|
1183
|
+
});
|
|
1184
|
+
// The Hijri tab lays out its calendar and time rows right to left; the
|
|
1185
|
+
// wrapper always renders, so a tab change doesn't remount the time boxes.
|
|
1186
|
+
const hijriShown = shownSystem === 'hijri';
|
|
1187
|
+
const mirrored = node => node == null ? null : /*#__PURE__*/_jsx(RtlContext.Provider, {
|
|
1188
|
+
value: hijriShown || null,
|
|
1189
|
+
children: /*#__PURE__*/_jsx(View, {
|
|
1190
|
+
style: hijriShown ? RTL : undefined,
|
|
1191
|
+
children: node
|
|
1192
|
+
})
|
|
1193
|
+
});
|
|
1194
|
+
// Another calendar opens on the days the last one showed, else on the
|
|
1195
|
+
// selection (shown or not), else where the picker would open.
|
|
1196
|
+
const calendarAnchor = shownAnchor.current ?? (selectionShown ? null : firstSelectedDay(selection)) ?? initialVisibleDate;
|
|
1197
|
+
const calendar = /*#__PURE__*/_jsxs(View, {
|
|
1198
|
+
style: folded ? FOLDED : undefined,
|
|
1199
|
+
children: [calendarSwitchNode, dualTabs, mirrored(/*#__PURE__*/_jsx(Calendar, {
|
|
1200
|
+
constraints: selectionShown ? calendarConstraints : constraints,
|
|
1201
|
+
today: today,
|
|
1202
|
+
initialVisibleDate: calendarAnchor,
|
|
1203
|
+
selection: selectionShown ? selection : emptySelection(selection),
|
|
1204
|
+
onSelectDay: onSelectDayStable,
|
|
1205
|
+
firstDayOfWeek: firstDayOfWeek,
|
|
1206
|
+
showOutsideDays: showOutsideDays,
|
|
1207
|
+
showHolidays: showHolidays,
|
|
1208
|
+
yearRange: yearRange,
|
|
1209
|
+
locale: shownSystem === 'hijri' ? hijriLocale : loc,
|
|
1210
|
+
calendarSystem: shownSystem,
|
|
1211
|
+
initialView: initialView,
|
|
1212
|
+
precision: precision,
|
|
1213
|
+
enableMonthSwipe: enableMonthSwipe,
|
|
1214
|
+
showToday: showToday,
|
|
1215
|
+
onVisibleMonthChange: handleVisibleMonth,
|
|
1216
|
+
onAnchorChange: rememberAnchor,
|
|
1217
|
+
renderDay: renderDay,
|
|
1218
|
+
renderWeekday: renderWeekday,
|
|
1219
|
+
renderMonthChip: renderMonthChip,
|
|
1220
|
+
renderYearCell: renderYearCell,
|
|
1221
|
+
renderMonthCell: renderMonthCell,
|
|
1222
|
+
renderEmptyState: renderEmptyState,
|
|
1223
|
+
icons: icons,
|
|
1224
|
+
iconProps: iconProps,
|
|
1225
|
+
tokens: tokens,
|
|
1226
|
+
styles: styles,
|
|
1227
|
+
strings: stringsFor(shownSystem),
|
|
1228
|
+
testID: testID
|
|
1229
|
+
}, shownSystem))]
|
|
844
1230
|
});
|
|
845
1231
|
const timeRow = type !== 'datetime' ? null : renderTimeRow ? renderTimeRow(state) : /*#__PURE__*/_jsx(TimeRows, {
|
|
846
1232
|
draft: d,
|
|
@@ -867,14 +1253,26 @@ const DateTimePicker = props => {
|
|
|
867
1253
|
onPendingChange: onRowPending,
|
|
868
1254
|
tokens: tokens,
|
|
869
1255
|
styles: styles,
|
|
870
|
-
strings:
|
|
1256
|
+
strings: stringsFor(shownSystem),
|
|
871
1257
|
testID: testID
|
|
872
1258
|
});
|
|
873
1259
|
|
|
874
1260
|
// Shown while the selection is still the one it was given for.
|
|
875
1261
|
const validationMessage = validation && (validation.key === JSON.stringify(draft.toWire()) || validation.key === JSON.stringify(draftToWire(preview, draftOptions))) ? validation.message : null;
|
|
1262
|
+
|
|
1263
|
+
// The field writes the date in the digits of the calendar it was picked in;
|
|
1264
|
+
// the calendar and the time rows follow the tab that shows.
|
|
876
1265
|
const sheetContent = /*#__PURE__*/_jsxs(_Fragment, {
|
|
877
|
-
children: [
|
|
1266
|
+
children: [/*#__PURE__*/_jsx(NumeralsContext.Provider, {
|
|
1267
|
+
value: digitsFor(draftSystem),
|
|
1268
|
+
children: sheetField
|
|
1269
|
+
}), /*#__PURE__*/_jsx(NumeralsContext.Provider, {
|
|
1270
|
+
value: digitsFor(shownSystem),
|
|
1271
|
+
children: calendar
|
|
1272
|
+
}), /*#__PURE__*/_jsx(NumeralsContext.Provider, {
|
|
1273
|
+
value: digitsFor(shownSystem),
|
|
1274
|
+
children: mirrored(timeRow)
|
|
1275
|
+
}), validationMessage ? /*#__PURE__*/_jsx(FieldMessages, {
|
|
878
1276
|
error: validationMessage,
|
|
879
1277
|
tokens: tokens,
|
|
880
1278
|
styles: {
|
|
@@ -884,7 +1282,8 @@ const DateTimePicker = props => {
|
|
|
884
1282
|
testID: testID ? `${testID}-validation` : undefined
|
|
885
1283
|
}) : null]
|
|
886
1284
|
});
|
|
887
|
-
return /*#__PURE__*/_jsxs(
|
|
1285
|
+
return /*#__PURE__*/_jsxs(NumeralsContext.Provider, {
|
|
1286
|
+
value: digitsFor(savedSystem),
|
|
888
1287
|
children: [trigger, /*#__PURE__*/_jsx(PickerContainer, {
|
|
889
1288
|
presentation: presentation,
|
|
890
1289
|
isOpen: isOpen,
|