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
|
@@ -15,6 +15,7 @@ import type { Time, TimeFormat } from '../../core/types';
|
|
|
15
15
|
import type { PickerStrings } from '../theme/defaultStrings';
|
|
16
16
|
import type { PickerStyles } from '../theme/styleKeys';
|
|
17
17
|
import { MAX_FONT_SCALE } from '../theme/a11y';
|
|
18
|
+
import { useNumerals } from '../theme/numerals';
|
|
18
19
|
import type { ThemeTokens } from '../theme/tokens';
|
|
19
20
|
import { useReduceMotion } from '../hooks/useReduceMotion';
|
|
20
21
|
import { buildTimeStyles } from './timeStyles';
|
|
@@ -31,6 +32,21 @@ export interface WheelItem {
|
|
|
31
32
|
disabled: boolean;
|
|
32
33
|
}
|
|
33
34
|
|
|
35
|
+
/**
|
|
36
|
+
* The row showing `value`, or the nearest one when the value has no row (a
|
|
37
|
+
* minute off the step, e.g. 07 on a 5-minute wheel, shows at 05, not 00).
|
|
38
|
+
*/
|
|
39
|
+
export const indexOfValue = (items: WheelItem[], value: number): number => {
|
|
40
|
+
const exact = items.findIndex((i) => i.value === value);
|
|
41
|
+
if (exact > -1) return exact;
|
|
42
|
+
let best = 0;
|
|
43
|
+
items.forEach((item, i) => {
|
|
44
|
+
if (Math.abs(item.value - value) < Math.abs(items[best]!.value - value))
|
|
45
|
+
best = i;
|
|
46
|
+
});
|
|
47
|
+
return best;
|
|
48
|
+
};
|
|
49
|
+
|
|
34
50
|
/** The enabled row nearest to `index` (searching both ways), or `index` when none is. */
|
|
35
51
|
export const nearestEnabled = (items: WheelItem[], index: number): number => {
|
|
36
52
|
const start = Math.max(0, Math.min(items.length - 1, index));
|
|
@@ -83,13 +99,11 @@ const WheelColumnBase: React.FC<ColumnProps> = ({
|
|
|
83
99
|
styles,
|
|
84
100
|
testID,
|
|
85
101
|
}) => {
|
|
102
|
+
const digits = useNumerals();
|
|
86
103
|
const s = buildTimeStyles(tokens);
|
|
87
104
|
const ref = useRef<ScrollViewRef>(null);
|
|
88
105
|
const reduceMotion = useReduceMotion();
|
|
89
|
-
const selectedIndex =
|
|
90
|
-
0,
|
|
91
|
-
items.findIndex((i) => i.value === value)
|
|
92
|
-
);
|
|
106
|
+
const selectedIndex = indexOfValue(items, value);
|
|
93
107
|
const [centered, setCentered] = useState(selectedIndex);
|
|
94
108
|
const spinning = useRef(false);
|
|
95
109
|
const momentumTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
@@ -216,7 +230,7 @@ const WheelColumnBase: React.FC<ColumnProps> = ({
|
|
|
216
230
|
],
|
|
217
231
|
]}
|
|
218
232
|
>
|
|
219
|
-
{item.label}
|
|
233
|
+
{digits(item.label)}
|
|
220
234
|
</Text>
|
|
221
235
|
</View>
|
|
222
236
|
))}
|
|
@@ -23,13 +23,13 @@ const create = (t: ThemeTokens) =>
|
|
|
23
23
|
fontSize: t.fontSizeLarge,
|
|
24
24
|
color: t.heading,
|
|
25
25
|
},
|
|
26
|
-
// Times read hh:mm in every language, so the boxes don't mirror in RTL.
|
|
27
26
|
boxes: {
|
|
28
27
|
flexDirection: 'row',
|
|
29
28
|
alignItems: 'center',
|
|
30
29
|
gap: 22,
|
|
31
|
-
direction: 'ltr',
|
|
32
30
|
},
|
|
31
|
+
// The boxes follow the row's direction: right to left (the Hijri tab, or a
|
|
32
|
+
// right-to-left app), the hour sits on the right and AM / PM on the left.
|
|
33
33
|
clock: { flexDirection: 'row', alignItems: 'center' },
|
|
34
34
|
// Each box is 50 × 46 with a 1 pt border and radius 6.
|
|
35
35
|
boxWrap: { width: 50 },
|
|
@@ -104,7 +104,6 @@ const create = (t: ThemeTokens) =>
|
|
|
104
104
|
flexDirection: 'row',
|
|
105
105
|
alignItems: 'center',
|
|
106
106
|
alignSelf: 'center',
|
|
107
|
-
direction: 'ltr',
|
|
108
107
|
},
|
|
109
108
|
wheelColumn: { width: 64, height: 200, overflow: 'hidden' },
|
|
110
109
|
wheelHighlight: {
|
package/src/components/types.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type React from 'react';
|
|
2
2
|
import type { StyleProp, TextStyle } from 'react-native';
|
|
3
|
+
import type { CalendarSystem } from '../core/calendarSystem';
|
|
3
4
|
import type { Constraints, TimeBounds } from '../core/constraints';
|
|
5
|
+
import type { Numerals } from '../core/numerals';
|
|
4
6
|
import type {
|
|
5
7
|
CalendarDate,
|
|
6
8
|
PickerType,
|
|
@@ -35,7 +37,7 @@ export interface PickerState {
|
|
|
35
37
|
disabled: boolean;
|
|
36
38
|
readOnly: boolean;
|
|
37
39
|
isOpen: boolean;
|
|
38
|
-
/** The keyboard is up inside the picker
|
|
40
|
+
/** The keyboard is up inside the picker and `hideCalendarOnKeyboard` hid the calendar. */
|
|
39
41
|
folded: boolean;
|
|
40
42
|
/**
|
|
41
43
|
* Confirm can be pressed: the dates are complete and allowed. A time with a
|
|
@@ -102,6 +104,18 @@ export interface SheetOptions {
|
|
|
102
104
|
height?: SheetSize;
|
|
103
105
|
/** Default '90%'. Built-in sheet only. */
|
|
104
106
|
maxHeight?: SheetSize;
|
|
107
|
+
/**
|
|
108
|
+
* The most the sheet grows to while the keyboard is up; a percentage is of
|
|
109
|
+
* the room above the keyboard. Default: `maxHeight`. Built-in sheet only.
|
|
110
|
+
*/
|
|
111
|
+
keyboardMaxHeight?: SheetSize;
|
|
112
|
+
/**
|
|
113
|
+
* Space kept free below Confirm while the keyboard is down: the home
|
|
114
|
+
* indicator, or Android's navigation bar in an edge-to-edge app. Default:
|
|
115
|
+
* the bottom inset from react-native-safe-area-context's SafeAreaProvider
|
|
116
|
+
* when the app has one, else 0. Built-in sheet only.
|
|
117
|
+
*/
|
|
118
|
+
bottomInset?: number;
|
|
105
119
|
/** The header stays put while the body scrolls. false: it scrolls with the body. Default true. */
|
|
106
120
|
fixedHeader?: boolean;
|
|
107
121
|
/** The footer (Confirm) stays pinned below the body. false: it scrolls at the end of the body. Default true. */
|
|
@@ -118,6 +132,27 @@ export interface SheetOptions {
|
|
|
118
132
|
fieldIcon?: boolean;
|
|
119
133
|
}
|
|
120
134
|
|
|
135
|
+
/**
|
|
136
|
+
* The second argument of `onChange` when the picker can show a Hijri calendar:
|
|
137
|
+
* the calendar the date was picked in. The value itself is always Gregorian.
|
|
138
|
+
* The picker remembers it while mounted; to show a stored value back the same
|
|
139
|
+
* way later, store this too and pass it as `dualDefaultTab` (dual) or
|
|
140
|
+
* `calendarSystem`.
|
|
141
|
+
*/
|
|
142
|
+
export interface ChangeInfo {
|
|
143
|
+
calendarSystem: 'gregory' | 'hijri';
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/** What `renderCalendarSwitch` receives. */
|
|
147
|
+
export interface CalendarSwitchRenderProps {
|
|
148
|
+
/** The choices, in order. */
|
|
149
|
+
systems: CalendarSystem[];
|
|
150
|
+
selected: CalendarSystem;
|
|
151
|
+
onSelect: (system: CalendarSystem) => void;
|
|
152
|
+
tokens: ThemeTokens;
|
|
153
|
+
strings: PickerStrings;
|
|
154
|
+
}
|
|
155
|
+
|
|
121
156
|
/** What `renderLabel` receives. */
|
|
122
157
|
export interface LabelRenderProps {
|
|
123
158
|
label?: string;
|
|
@@ -167,8 +202,10 @@ export interface DateTimePickerProps {
|
|
|
167
202
|
/**
|
|
168
203
|
* A value was saved: on Confirm; as it's edited with commitMode 'instant';
|
|
169
204
|
* when typing in the on-screen field pauses; or '' on clear. Never on close.
|
|
205
|
+
* When the picker can show a Hijri calendar, `info` says which calendar the
|
|
206
|
+
* date was picked in.
|
|
170
207
|
*/
|
|
171
|
-
onChange: (value: PickerValue) => void;
|
|
208
|
+
onChange: (value: PickerValue, info?: ChangeInfo) => void;
|
|
172
209
|
/**
|
|
173
210
|
* Right after every onChange that saves a value (Confirm, an 'instant' edit,
|
|
174
211
|
* on-screen typing), like a form field losing focus. Not on clear.
|
|
@@ -213,6 +250,12 @@ export interface DateTimePickerProps {
|
|
|
213
250
|
readOnly?: boolean;
|
|
214
251
|
/** Type date and time as segments in the field inside the sheet. */
|
|
215
252
|
allowTyping?: boolean;
|
|
253
|
+
/**
|
|
254
|
+
* Hide the calendar while the keyboard is up (typing a date or a time), so
|
|
255
|
+
* the box being typed in and Confirm stay in view on small phones. Default
|
|
256
|
+
* true; `false` keeps the calendar in view.
|
|
257
|
+
*/
|
|
258
|
+
hideCalendarOnKeyboard?: boolean;
|
|
216
259
|
/**
|
|
217
260
|
* The on-screen field is typeable too. A complete, allowed value is saved
|
|
218
261
|
* once, when focus leaves the field or its last box fills. Default false.
|
|
@@ -277,10 +320,42 @@ export interface DateTimePickerProps {
|
|
|
277
320
|
initialVisibleDate?: CalendarDate;
|
|
278
321
|
enableMonthSwipe?: boolean;
|
|
279
322
|
showToday?: boolean;
|
|
280
|
-
/**
|
|
281
|
-
|
|
323
|
+
/**
|
|
324
|
+
* The calendar the grid uses: 'gregory', 'hijri' (Umm al-Qura), or 'dual':
|
|
325
|
+
* Gregorian and Hijri tabs, one calendar at a time. A day is shown selected
|
|
326
|
+
* only in the calendar it was picked in, and the field writes it in that
|
|
327
|
+
* calendar. With `calendarSwitch`, this is the one shown first. Default
|
|
328
|
+
* 'gregory'; anything Hijri falls back to 'gregory' when the platform has no
|
|
329
|
+
* Hijri calendar.
|
|
330
|
+
*/
|
|
331
|
+
calendarSystem?: CalendarSystem;
|
|
332
|
+
/**
|
|
333
|
+
* A Gregorian / Hijri / Dual switch above the calendar. true shows all three;
|
|
334
|
+
* a list shows those, in that order (e.g. ['hijri', 'gregory']). Not shown for
|
|
335
|
+
* month and year picks, or when the platform has no Hijri calendar. Default false.
|
|
336
|
+
*/
|
|
337
|
+
calendarSwitch?: boolean | CalendarSystem[];
|
|
338
|
+
/** The user picked another calendar in the switch. */
|
|
339
|
+
onCalendarSystemChange?: (system: CalendarSystem) => void;
|
|
340
|
+
/**
|
|
341
|
+
* The language a Hijri calendar is written in, whatever `locale` is: its
|
|
342
|
+
* month and weekday names, the Hijri date in the field, and what screen
|
|
343
|
+
* readers say. Default 'ar-SA' (Arabic).
|
|
344
|
+
*/
|
|
345
|
+
hijriLocale?: string;
|
|
346
|
+
/** The tab a dual calendar opens on, each time it opens. Default 'gregory'. */
|
|
347
|
+
dualDefaultTab?: 'gregory' | 'hijri';
|
|
348
|
+
/** Replaces the built-in calendar switch. */
|
|
349
|
+
renderCalendarSwitch?: (p: CalendarSwitchRenderProps) => React.ReactNode;
|
|
282
350
|
/** Any BCP-47 tag; decides names, the date order and the clock. Default: the device locale. */
|
|
283
351
|
locale?: string;
|
|
352
|
+
/**
|
|
353
|
+
* The digits every number is drawn in: 'latin' (0–9), 'arabic' (١٢٣ in any
|
|
354
|
+
* language) or 'locale' (the language's own: ١٢٣ for 'ar-SA', ۱۲۳ for
|
|
355
|
+
* 'fa-IR', 123 for 'en-US'). Values stay 0–9. Default: 'arabic' for a Hijri
|
|
356
|
+
* calendar and a date picked in it, 'latin' for a Gregorian one.
|
|
357
|
+
*/
|
|
358
|
+
numerals?: Numerals;
|
|
284
359
|
/** IANA zone for date-time values and "today". Default: the device zone. */
|
|
285
360
|
timeZone?: string;
|
|
286
361
|
/** The current time, for "today" and a new day's time. Default `() => new Date()`. */
|
|
@@ -316,6 +391,13 @@ export interface DateTimePickerProps {
|
|
|
316
391
|
theme?: Partial<ThemeTokens>;
|
|
317
392
|
styles?: PickerStyles;
|
|
318
393
|
strings?: Partial<PickerStrings>;
|
|
394
|
+
/**
|
|
395
|
+
* The texts while the Hijri tab shows (e.g. Arabic), for its calendar and
|
|
396
|
+
* time rows, the error messages inside the picker, and a date picked in it
|
|
397
|
+
* (the on-screen field's errors keep `strings`). A key left out (or `undefined`)
|
|
398
|
+
* keeps AM / PM in `hijriLocale` (ص / م), then `strings`.
|
|
399
|
+
*/
|
|
400
|
+
hijriStrings?: Partial<PickerStrings>;
|
|
319
401
|
testID?: string;
|
|
320
402
|
|
|
321
403
|
// events
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { addDays, addMonths, daysInMonth } from './calendarDate';
|
|
2
2
|
import type { CalendarDate, Weekday } from './types';
|
|
3
3
|
import { weekdayOf } from './calendarDate';
|
|
4
|
+
import { toLatinDigits } from './digits';
|
|
5
|
+
import { withCalendar } from './locale';
|
|
4
6
|
|
|
5
7
|
/**
|
|
6
|
-
* Calendar systems for the picker
|
|
7
|
-
*
|
|
8
|
+
* Calendar systems for the picker. Saved values are always Gregorian; a
|
|
9
|
+
* system only changes how months are laid out and labelled.
|
|
8
10
|
* - 'gregory': the normal grid;
|
|
9
|
-
* - '
|
|
10
|
-
* - '
|
|
11
|
+
* - 'hijri': a Hijri (Umm al-Qura) grid showing the Hijri day;
|
|
12
|
+
* - 'dual': both, as Gregorian and Hijri tabs showing one grid at a time.
|
|
11
13
|
*
|
|
12
14
|
* Hijri dates come from the platform's Intl ('islamic-umalqura'). When Intl
|
|
13
15
|
* can't do it (checked once; some JS engines ship without that calendar) the
|
|
@@ -57,16 +59,9 @@ const utcDate = (
|
|
|
57
59
|
return d;
|
|
58
60
|
};
|
|
59
61
|
|
|
60
|
-
/**
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
*/
|
|
64
|
-
const withHijriCalendar = (locale: string): string => {
|
|
65
|
-
const [base, ext] = locale.split(/-u-/i);
|
|
66
|
-
if (ext === undefined) return `${locale}-u-ca-islamic-umalqura`;
|
|
67
|
-
const rest = ext.replace(/(^|-)ca(-[a-z0-9]{3,8})+/i, '').replace(/^-/, '');
|
|
68
|
-
return `${base}-u-ca-islamic-umalqura${rest ? `-${rest}` : ''}`;
|
|
69
|
-
};
|
|
62
|
+
/** The locale with the Umm al-Qura calendar ('ar-SA-u-nu-arab' → 'ar-SA-u-ca-islamic-umalqura-nu-arab'). */
|
|
63
|
+
const withHijriCalendar = (locale: string): string =>
|
|
64
|
+
withCalendar(locale, 'islamic-umalqura');
|
|
70
65
|
|
|
71
66
|
const readParts = (
|
|
72
67
|
f: Intl.DateTimeFormat,
|
|
@@ -83,19 +78,45 @@ const readParts = (
|
|
|
83
78
|
: null;
|
|
84
79
|
};
|
|
85
80
|
|
|
81
|
+
/**
|
|
82
|
+
* Remembers results by key. Every tap redraws the grid and its labels, and
|
|
83
|
+
* Intl is slow on some engines (Hermes on Android), so Hijri conversions are
|
|
84
|
+
* worked out once. Cleared when full, to stay small.
|
|
85
|
+
*/
|
|
86
|
+
const memoize = <V>(limit = 4000) => {
|
|
87
|
+
const map = new Map<string, V>();
|
|
88
|
+
return {
|
|
89
|
+
get: (key: string, make: () => V): V => {
|
|
90
|
+
if (map.has(key)) return map.get(key)!;
|
|
91
|
+
const value = make();
|
|
92
|
+
if (map.size >= limit) map.clear();
|
|
93
|
+
map.set(key, value);
|
|
94
|
+
return value;
|
|
95
|
+
},
|
|
96
|
+
clear: () => map.clear(),
|
|
97
|
+
};
|
|
98
|
+
};
|
|
99
|
+
const hijriDays = memoize<CalendarDate | null>();
|
|
100
|
+
const hijriStarts = memoize<CalendarDate>(600);
|
|
101
|
+
const hijriTexts = memoize<string | null>();
|
|
102
|
+
|
|
86
103
|
/** Whether this device can show Hijri dates. */
|
|
87
104
|
export const isHijriSupported = (): boolean => getHijriFormat() !== null;
|
|
88
105
|
|
|
89
|
-
/** Test hook: forget the cached Intl check. */
|
|
106
|
+
/** Test hook: forget the cached Intl check and what was worked out with it. */
|
|
90
107
|
export const resetHijriSupportCache = (): void => {
|
|
91
108
|
hijriFormat = undefined;
|
|
109
|
+
hijriDays.clear();
|
|
110
|
+
hijriStarts.clear();
|
|
111
|
+
hijriTexts.clear();
|
|
92
112
|
};
|
|
93
113
|
|
|
94
114
|
/** Gregorian day → Hijri {year, month, day}, or null when unsupported. */
|
|
95
|
-
export const toHijri = (d: CalendarDate): CalendarDate | null =>
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
115
|
+
export const toHijri = (d: CalendarDate): CalendarDate | null =>
|
|
116
|
+
hijriDays.get(`${d.year}-${d.month}-${d.day}`, () => {
|
|
117
|
+
const f = getHijriFormat();
|
|
118
|
+
return f ? readParts(f, d) : null;
|
|
119
|
+
});
|
|
99
120
|
|
|
100
121
|
const HIJRI_EPOCH = { year: 622, month: 7, day: 19 };
|
|
101
122
|
const MEAN_YEAR = 354.367;
|
|
@@ -105,7 +126,10 @@ const cmp = (a: SystemMonth, b: SystemMonth) =>
|
|
|
105
126
|
a.year - b.year || a.month - b.month;
|
|
106
127
|
|
|
107
128
|
/** The Gregorian day on which a Hijri month starts. */
|
|
108
|
-
export const hijriMonthStart = (year: number, month: number): CalendarDate =>
|
|
129
|
+
export const hijriMonthStart = (year: number, month: number): CalendarDate =>
|
|
130
|
+
hijriStarts.get(`${year}-${month}`, () => findMonthStart(year, month));
|
|
131
|
+
|
|
132
|
+
const findMonthStart = (year: number, month: number): CalendarDate => {
|
|
109
133
|
const estimate = Math.round(
|
|
110
134
|
(year - 1) * MEAN_YEAR + (month - 1) * MEAN_MONTH
|
|
111
135
|
);
|
|
@@ -125,7 +149,11 @@ export const hijriMonthStart = (year: number, month: number): CalendarDate => {
|
|
|
125
149
|
|
|
126
150
|
export const addHijriMonths = (m: SystemMonth, n: number): SystemMonth => {
|
|
127
151
|
const index = m.year * 12 + (m.month - 1) + n;
|
|
128
|
-
|
|
152
|
+
// % keeps the sign in JS, so a year before 1 AH still gets months 1–12.
|
|
153
|
+
return {
|
|
154
|
+
year: Math.floor(index / 12),
|
|
155
|
+
month: (((index % 12) + 12) % 12) + 1,
|
|
156
|
+
};
|
|
129
157
|
};
|
|
130
158
|
|
|
131
159
|
export const hijriMonthLength = (year: number, month: number): number => {
|
|
@@ -154,13 +182,26 @@ export const HIJRI_MONTHS_EN = [
|
|
|
154
182
|
'Dhuʻl-Hijjah',
|
|
155
183
|
];
|
|
156
184
|
|
|
185
|
+
const monthNameCache = new Map<string, string[]>();
|
|
186
|
+
|
|
157
187
|
/** Hijri month names in the user's language (Intl), English otherwise. */
|
|
158
188
|
export const hijriMonthNames = (locale: string): string[] => {
|
|
189
|
+
const hit = monthNameCache.get(locale);
|
|
190
|
+
if (hit) return hit;
|
|
191
|
+
const names = readHijriMonthNames(locale);
|
|
192
|
+
monthNameCache.set(locale, names);
|
|
193
|
+
return names;
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
const readHijriMonthNames = (locale: string): string[] => {
|
|
159
197
|
try {
|
|
160
198
|
const f = new Intl.DateTimeFormat(withHijriCalendar(locale), {
|
|
161
199
|
timeZone: 'UTC',
|
|
162
200
|
month: 'long',
|
|
163
201
|
});
|
|
202
|
+
// A locale Intl doesn't know drops the calendar and would give Gregorian names.
|
|
203
|
+
if (f.resolvedOptions().calendar !== 'islamic-umalqura')
|
|
204
|
+
return HIJRI_MONTHS_EN;
|
|
164
205
|
return HIJRI_MONTHS_EN.map((fallback, i) => {
|
|
165
206
|
const start = hijriMonthStart(1448, i + 1);
|
|
166
207
|
const name = f.format(
|
|
@@ -173,6 +214,89 @@ export const hijriMonthNames = (locale: string): string[] => {
|
|
|
173
214
|
}
|
|
174
215
|
};
|
|
175
216
|
|
|
217
|
+
const dateTextFormats = new Map<string, Intl.DateTimeFormat | null>();
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* A Gregorian day written as a Hijri date in the user's language, in 0–9
|
|
221
|
+
* ('16 Jumada I 1448 AH', '16 جمادى الأولى 1448 هـ'), or null when unsupported.
|
|
222
|
+
*/
|
|
223
|
+
export const hijriDateText = (d: CalendarDate, locale: string): string | null =>
|
|
224
|
+
hijriTexts.get(`${locale}|${d.year}-${d.month}-${d.day}`, () =>
|
|
225
|
+
writeHijriDate(d, locale)
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
const writeHijriDate = (d: CalendarDate, locale: string): string | null => {
|
|
229
|
+
const h = toHijri(d);
|
|
230
|
+
if (!h) return null;
|
|
231
|
+
if (!dateTextFormats.has(locale)) {
|
|
232
|
+
let f: Intl.DateTimeFormat | null = null;
|
|
233
|
+
try {
|
|
234
|
+
f = new Intl.DateTimeFormat(withHijriCalendar(locale), {
|
|
235
|
+
timeZone: 'UTC',
|
|
236
|
+
day: 'numeric',
|
|
237
|
+
month: 'long',
|
|
238
|
+
year: 'numeric',
|
|
239
|
+
});
|
|
240
|
+
} catch {
|
|
241
|
+
f = null;
|
|
242
|
+
}
|
|
243
|
+
// A locale Intl doesn't know drops the calendar: build the text instead.
|
|
244
|
+
dateTextFormats.set(
|
|
245
|
+
locale,
|
|
246
|
+
f?.resolvedOptions().calendar === 'islamic-umalqura' ? f : null
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
const f = dateTextFormats.get(locale);
|
|
250
|
+
const text = f
|
|
251
|
+
? toLatinDigits(f.format(utcDate(d.year, d.month - 1, d.day, 12)))
|
|
252
|
+
: '';
|
|
253
|
+
// An engine that ignores the calendar writes the Gregorian year: build it instead.
|
|
254
|
+
if (text.includes(String(h.year))) return text;
|
|
255
|
+
return `${h.day} ${hijriMonthNames(locale)[h.month - 1]} ${h.year}`;
|
|
256
|
+
};
|
|
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
|
+
|
|
176
300
|
/**
|
|
177
301
|
* The system the picker uses: the requested one, Gregorian by default.
|
|
178
302
|
* Anything Hijri falls back to Gregorian when unsupported.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The zero of each decimal digit block a keyboard may type in: Arabic-Indic
|
|
3
|
+
* (٠–٩), Persian (۰–۹), N'Ko, the Indic scripts, Thai, Lao, Tibetan, Myanmar,
|
|
4
|
+
* Khmer, Mongolian and full-width. Each block runs zero to nine in order.
|
|
5
|
+
*/
|
|
6
|
+
const DIGIT_ZEROS = [
|
|
7
|
+
0x0660, 0x06f0, 0x07c0, 0x0966, 0x09e6, 0x0a66, 0x0ae6, 0x0b66, 0x0be6,
|
|
8
|
+
0x0c66, 0x0ce6, 0x0d66, 0x0e50, 0x0ed0, 0x0f20, 0x1040, 0x17e0, 0x1810,
|
|
9
|
+
0xff10,
|
|
10
|
+
];
|
|
11
|
+
|
|
12
|
+
/** Any decimal digits as 0–9 ('٢٥' → '25'); other characters are kept. */
|
|
13
|
+
export const toLatinDigits = (text: string): string => {
|
|
14
|
+
let out = '';
|
|
15
|
+
for (const ch of text) {
|
|
16
|
+
const code = ch.charCodeAt(0);
|
|
17
|
+
const zero = DIGIT_ZEROS.find((z) => code >= z && code <= z + 9);
|
|
18
|
+
out += zero === undefined ? ch : String(code - zero);
|
|
19
|
+
}
|
|
20
|
+
return out;
|
|
21
|
+
};
|
package/src/core/draft.ts
CHANGED
|
@@ -37,7 +37,15 @@ export interface DraftSlot {
|
|
|
37
37
|
export type Draft =
|
|
38
38
|
| { mode: 'single'; slot: DraftSlot }
|
|
39
39
|
| { mode: 'range'; from: DraftSlot; to: DraftSlot }
|
|
40
|
-
| {
|
|
40
|
+
| {
|
|
41
|
+
mode: 'multiple';
|
|
42
|
+
slots: DraftSlot[];
|
|
43
|
+
/**
|
|
44
|
+
* Shared time mode: the time every date gets. Null while the saved dates
|
|
45
|
+
* have different times, which each date then keeps until one is set.
|
|
46
|
+
*/
|
|
47
|
+
sharedTime: Time | null;
|
|
48
|
+
};
|
|
41
49
|
|
|
42
50
|
export interface DraftOptions {
|
|
43
51
|
type: PickerType;
|
|
@@ -119,13 +127,22 @@ export const createDraft = (
|
|
|
119
127
|
return { mode, from: slotFrom(from, opts), to: slotFrom(to, opts) };
|
|
120
128
|
}
|
|
121
129
|
if (mode === 'multiple') {
|
|
130
|
+
// One slot per day: a later value on a day already listed is dropped.
|
|
122
131
|
const slots = sortSlots(
|
|
123
132
|
splitMultiple(safe)
|
|
124
133
|
.map((w) => slotFrom(w, opts))
|
|
125
|
-
.filter(
|
|
134
|
+
.filter(
|
|
135
|
+
(s, i, all) =>
|
|
136
|
+
s.value &&
|
|
137
|
+
all.findIndex((o) => isSameDay(o.value?.date, s.value?.date)) === i
|
|
138
|
+
)
|
|
139
|
+
);
|
|
140
|
+
const times = slots.map((s) => s.value?.time ?? null);
|
|
141
|
+
const first = times[0] ?? null;
|
|
142
|
+
const sameTime = times.every(
|
|
143
|
+
(t) => t?.hour === first?.hour && t?.minute === first?.minute
|
|
126
144
|
);
|
|
127
|
-
const sharedTime =
|
|
128
|
-
opts.type === 'datetime' ? (slots[0]?.value?.time ?? null) : null;
|
|
145
|
+
const sharedTime = opts.type === 'datetime' && sameTime ? first : null;
|
|
129
146
|
return { mode, slots, sharedTime };
|
|
130
147
|
}
|
|
131
148
|
return {
|
|
@@ -158,6 +175,14 @@ const withDay = (
|
|
|
158
175
|
};
|
|
159
176
|
};
|
|
160
177
|
|
|
178
|
+
/**
|
|
179
|
+
* Whether a range may start and end on one day: date-time ranges and
|
|
180
|
+
* `allowSameDay` date ranges, as long as minDays allows a 1-day range.
|
|
181
|
+
*/
|
|
182
|
+
export const sameDayRangeOk = (opts: DraftOptions): boolean =>
|
|
183
|
+
(opts.type === 'datetime' || !!opts.range?.allowSameDay) &&
|
|
184
|
+
(opts.range?.minDays ?? 1) <= 1;
|
|
185
|
+
|
|
161
186
|
const pickRangeDay = (
|
|
162
187
|
draft: Extract<Draft, { mode: 'range' }>,
|
|
163
188
|
day: CalendarDate,
|
|
@@ -166,10 +191,6 @@ const pickRangeDay = (
|
|
|
166
191
|
): Draft => {
|
|
167
192
|
const from = draft.from.value?.date;
|
|
168
193
|
const to = draft.to.value?.date;
|
|
169
|
-
// A same-day range is 1 day long, so it's only an end when minDays allows it.
|
|
170
|
-
const allowSameDay =
|
|
171
|
-
(opts.type === 'datetime' || !!opts.range?.allowSameDay) &&
|
|
172
|
-
(opts.range?.minDays ?? 1) <= 1;
|
|
173
194
|
|
|
174
195
|
if (!from) return { ...draft, from: withDay(draft.from, day, opts, eq) };
|
|
175
196
|
|
|
@@ -177,7 +198,8 @@ const pickRangeDay = (
|
|
|
177
198
|
const order = compareCalendarDates(day, from);
|
|
178
199
|
if (order < 0)
|
|
179
200
|
return { ...draft, from: withDay(draft.from, day, opts, eq) };
|
|
180
|
-
|
|
201
|
+
// The start tapped again, where it can't also be the end: deselects it.
|
|
202
|
+
if (order === 0 && !sameDayRangeOk(opts))
|
|
181
203
|
return { ...draft, from: { ...draft.from, value: null } };
|
|
182
204
|
return { ...draft, to: withDay(draft.to, day, opts, eq) };
|
|
183
205
|
}
|
|
@@ -228,8 +250,10 @@ export const selectDay = (
|
|
|
228
250
|
...draft.slots,
|
|
229
251
|
{ value: { date: day, time }, initialWire: '' },
|
|
230
252
|
]),
|
|
253
|
+
// The first date's time becomes the shared one; dates with their own
|
|
254
|
+
// (different) times keep them.
|
|
231
255
|
sharedTime:
|
|
232
|
-
opts.type === 'datetime' && !perDate
|
|
256
|
+
opts.type === 'datetime' && !perDate && draft.slots.length === 0
|
|
233
257
|
? (draft.sharedTime ?? time)
|
|
234
258
|
: draft.sharedTime,
|
|
235
259
|
};
|
|
@@ -237,7 +261,9 @@ export const selectDay = (
|
|
|
237
261
|
|
|
238
262
|
/**
|
|
239
263
|
* From/To layout: a tap fills the end being edited. An end that would come
|
|
240
|
-
* before the start (or after the end) clears the other one.
|
|
264
|
+
* before the start (or after the end) clears the other one. The start tapped
|
|
265
|
+
* again as the end, where a range can't be one day, deselects the start, as
|
|
266
|
+
* in the single field.
|
|
241
267
|
*/
|
|
242
268
|
export const setRangeEnd = (
|
|
243
269
|
draft: Draft,
|
|
@@ -247,12 +273,14 @@ export const setRangeEnd = (
|
|
|
247
273
|
newDayTime?: Time | null
|
|
248
274
|
): Draft => {
|
|
249
275
|
if (draft.mode !== 'range') return draft;
|
|
250
|
-
const sameDayOk = opts
|
|
276
|
+
const sameDayOk = sameDayRangeOk(opts);
|
|
251
277
|
const fits = (from?: CalendarDate, to?: CalendarDate) => {
|
|
252
278
|
if (!from || !to) return true;
|
|
253
279
|
const order = compareCalendarDates(to, from);
|
|
254
280
|
return order > 0 || (order === 0 && sameDayOk);
|
|
255
281
|
};
|
|
282
|
+
if (end === 'to' && !sameDayOk && isSameDay(draft.from.value?.date, day))
|
|
283
|
+
return { ...draft, from: { ...draft.from, value: null } };
|
|
256
284
|
if (end === 'from') {
|
|
257
285
|
const from = withDay(draft.from, day, opts, newDayTime);
|
|
258
286
|
const keepTo = fits(day, draft.to.value?.date);
|
|
@@ -346,7 +374,7 @@ const effectiveValue = (
|
|
|
346
374
|
opts.type === 'datetime' &&
|
|
347
375
|
opts.multiple?.timeMode !== 'perDate'
|
|
348
376
|
) {
|
|
349
|
-
return { ...slot.value, time: draft.sharedTime };
|
|
377
|
+
return { ...slot.value, time: draft.sharedTime ?? slot.value.time };
|
|
350
378
|
}
|
|
351
379
|
return slot.value;
|
|
352
380
|
};
|
package/src/core/locale.ts
CHANGED
|
@@ -8,10 +8,24 @@ import type { TimeFormat, Weekday } from './types';
|
|
|
8
8
|
const FALLBACK_LOCALE = 'en-US';
|
|
9
9
|
const FALLBACK_DATE_FORMAT = 'yyyy-MM-dd';
|
|
10
10
|
const SEPARATORS = ['/', '-', '.'];
|
|
11
|
-
const DATE_TOKENS: Partial<Record<
|
|
11
|
+
const DATE_TOKENS: Partial<Record<string, string>> = {
|
|
12
12
|
day: 'dd',
|
|
13
13
|
month: 'MM',
|
|
14
14
|
year: 'yyyy',
|
|
15
|
+
// Hermes on Android labels the year of some locales (ar-SA) this way.
|
|
16
|
+
yearName: 'yyyy',
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The locale with a calendar, keeping any Unicode extension it already has
|
|
21
|
+
* ('ar-SA-u-nu-arab' → 'ar-SA-u-ca-gregory-nu-arab'). Some engines write a
|
|
22
|
+
* locale in its own calendar by default (iOS: Hijri for 'ar-SA').
|
|
23
|
+
*/
|
|
24
|
+
export const withCalendar = (locale: string, calendar: string): string => {
|
|
25
|
+
const [base, ext] = locale.split(/-u-/i);
|
|
26
|
+
if (ext === undefined) return `${locale}-u-ca-${calendar}`;
|
|
27
|
+
const rest = ext.replace(/(^|-)ca(-[a-z0-9]{3,8})+/i, '').replace(/^-/, '');
|
|
28
|
+
return `${base}-u-ca-${calendar}${rest ? `-${rest}` : ''}`;
|
|
15
29
|
};
|
|
16
30
|
|
|
17
31
|
/** The device locale (a BCP-47 tag), or 'en-US'. */
|
|
@@ -31,7 +45,7 @@ export const defaultLocale = (): string => {
|
|
|
31
45
|
*/
|
|
32
46
|
export const deriveDateFormat = (locale: string): string => {
|
|
33
47
|
try {
|
|
34
|
-
const parts = new Intl.DateTimeFormat(locale, {
|
|
48
|
+
const parts = new Intl.DateTimeFormat(withCalendar(locale, 'gregory'), {
|
|
35
49
|
year: 'numeric',
|
|
36
50
|
month: '2-digit',
|
|
37
51
|
day: '2-digit',
|
|
@@ -42,7 +56,10 @@ export const deriveDateFormat = (locale: string): string => {
|
|
|
42
56
|
!['dd', 'MM', 'yyyy'].every((t) => tokens.includes(t))
|
|
43
57
|
)
|
|
44
58
|
return FALLBACK_DATE_FORMAT;
|
|
45
|
-
|
|
59
|
+
// RTL locales mark the separator with a direction mark ('\u200F/').
|
|
60
|
+
const first = (
|
|
61
|
+
parts.find((p) => p.type === 'literal')?.value ?? ''
|
|
62
|
+
).replace(/[\u200E\u200F\u061C]/g, '');
|
|
46
63
|
const separator = SEPARATORS.includes(first) ? first : '/';
|
|
47
64
|
return tokens.join(separator);
|
|
48
65
|
} catch {
|