rn-grid-date-time-picker 1.3.0 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -0
- package/lib/commonjs/components/DateTimePicker.js +67 -115
- package/lib/commonjs/components/DateTimePicker.js.map +1 -1
- package/lib/commonjs/components/calendar/DayCell.js +17 -6
- package/lib/commonjs/components/calendar/DayCell.js.map +1 -1
- package/lib/commonjs/components/calendar/calendarStyles.js +11 -0
- package/lib/commonjs/components/calendar/calendarStyles.js.map +1 -1
- package/lib/commonjs/components/field/ValueField.js +19 -2
- package/lib/commonjs/components/field/ValueField.js.map +1 -1
- package/lib/commonjs/components/field/fieldText.js +44 -5
- package/lib/commonjs/components/field/fieldText.js.map +1 -1
- package/lib/commonjs/components/theme/styleKeys.js +3 -1
- package/lib/commonjs/components/theme/styleKeys.js.map +1 -1
- package/lib/commonjs/components/types.js +2 -1
- package/lib/commonjs/components/types.js.map +1 -1
- package/lib/module/components/DateTimePicker.js +68 -116
- package/lib/module/components/DateTimePicker.js.map +1 -1
- package/lib/module/components/calendar/DayCell.js +18 -7
- package/lib/module/components/calendar/DayCell.js.map +1 -1
- package/lib/module/components/calendar/calendarStyles.js +11 -0
- package/lib/module/components/calendar/calendarStyles.js.map +1 -1
- package/lib/module/components/field/ValueField.js +20 -3
- package/lib/module/components/field/ValueField.js.map +1 -1
- package/lib/module/components/field/fieldText.js +40 -4
- package/lib/module/components/field/fieldText.js.map +1 -1
- package/lib/module/components/theme/styleKeys.js +3 -1
- package/lib/module/components/theme/styleKeys.js.map +1 -1
- package/lib/module/components/types.js +2 -1
- package/lib/module/components/types.js.map +1 -1
- package/lib/typescript/commonjs/src/components/DateTimePicker.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/components/calendar/DayCell.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/components/calendar/calendarStyles.d.ts +9 -0
- package/lib/typescript/commonjs/src/components/calendar/calendarStyles.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/components/field/ValueField.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/components/field/fieldText.d.ts +19 -0
- package/lib/typescript/commonjs/src/components/field/fieldText.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/components/theme/styleKeys.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/components/types.d.ts +18 -5
- package/lib/typescript/commonjs/src/components/types.d.ts.map +1 -1
- package/lib/typescript/module/src/components/DateTimePicker.d.ts.map +1 -1
- package/lib/typescript/module/src/components/calendar/DayCell.d.ts.map +1 -1
- package/lib/typescript/module/src/components/calendar/calendarStyles.d.ts +9 -0
- package/lib/typescript/module/src/components/calendar/calendarStyles.d.ts.map +1 -1
- package/lib/typescript/module/src/components/field/ValueField.d.ts.map +1 -1
- package/lib/typescript/module/src/components/field/fieldText.d.ts +19 -0
- package/lib/typescript/module/src/components/field/fieldText.d.ts.map +1 -1
- package/lib/typescript/module/src/components/theme/styleKeys.d.ts.map +1 -1
- package/lib/typescript/module/src/components/types.d.ts +18 -5
- package/lib/typescript/module/src/components/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/DateTimePicker.tsx +79 -120
- package/src/components/calendar/DayCell.tsx +25 -6
- package/src/components/calendar/calendarStyles.ts +11 -0
- package/src/components/field/ValueField.tsx +30 -11
- package/src/components/field/fieldText.ts +48 -5
- package/src/components/theme/styleKeys.ts +3 -1
- package/src/components/types.ts +18 -5
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,22 @@ All notable changes to this project are documented here. The format follows [Kee
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [1.3.1] - 2026-11-13
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- `sheet.showNotAllowedError` (default `true`): `false` hides "This date isn't available" above the calendar when the picked date (or a range's end) is a disabled day, such as a saved value the rules no longer allow. Confirm stays off for that day either way.
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- A greyed (disabled) today no longer keeps the full accent ring. Its ring keeps the accent colour at 40% opacity, like the other greyed controls, and the day number stays as grey as the other greyed days. A custom `styles.today` (its border colour or width, for example) and the corner radius from `styles.day` still apply to that ring.
|
|
16
|
+
- With a `fieldDateText` style, the empty date-time field's placeholder now sets its date apart from its time, like the value does, so `{ minWidth: '50%' }` starts the placeholder's time at the middle of the field too. A `placeholder` passed in is cut at the first `strings.dateTimeSeparator` when what follows is a time (`'DD/MM/YYYY HH:MM'`); wording such as `'Pick a time'` stays whole.
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
|
|
20
|
+
- **A dual calendar's selection shows in both tabs.** A day picked on the Gregorian tab is highlighted on the Hijri tab too, and the other way round, and a tap on either tab edits the same selection instead of starting over, so a range can start on one tab and end on the other. The selection is saved with the tab on screen: Confirm on the Hijri tab saves a Gregorian pick as Hijri (`info.calendarSystem: 'hijri'`), and the field writes it that way. With `commitMode="instant"`, a tab (or a calendar in the switch) the user picks saves the selection again with that calendar; the tab the picker opens on doesn't. The field inside the sheet now follows the tab too. A new `calendarSystem` prop no longer clears a selection in progress. Values stay Gregorian.
|
|
21
|
+
- **A dual calendar reopens on the tab its value was saved with.** A date saved from the Hijri tab opens the picker on the Hijri tab next time, while the picker stays mounted. With no value it still opens on `dualDefaultTab`, and so does a value passed in from outside: to keep the tab after a remount, store `info.calendarSystem` and pass it as `dualDefaultTab`.
|
|
22
|
+
|
|
7
23
|
## [1.3.0] - 2026-11-12
|
|
8
24
|
|
|
9
25
|
### Added
|
|
@@ -160,6 +176,11 @@ Initial release.
|
|
|
160
176
|
- `dateFormat` in any case (`'dd/mm/yyyy'`). A format the picker can't use warns in development and falls back to the locale order.
|
|
161
177
|
- Accessibility labels and states, reduce-motion support, a font-scale cap and RTL mirroring. On iOS every typed box gets a Done button above the number pad, and errors are announced to VoiceOver.
|
|
162
178
|
|
|
179
|
+
[Unreleased]: https://github.com/Bhairavi-ancy/rn-grid-date-time-picker/compare/v1.3.1...HEAD
|
|
180
|
+
[1.3.1]: https://github.com/Bhairavi-ancy/rn-grid-date-time-picker/compare/v1.3.0...v1.3.1
|
|
181
|
+
[1.3.0]: https://github.com/Bhairavi-ancy/rn-grid-date-time-picker/compare/v1.2.2...v1.3.0
|
|
182
|
+
[1.2.2]: https://github.com/Bhairavi-ancy/rn-grid-date-time-picker/compare/v1.2.1...v1.2.2
|
|
183
|
+
[1.2.1]: https://github.com/Bhairavi-ancy/rn-grid-date-time-picker/compare/v1.2.0...v1.2.1
|
|
163
184
|
[1.2.0]: https://github.com/Bhairavi-ancy/rn-grid-date-time-picker/compare/v1.1.0...v1.2.0
|
|
164
185
|
[1.1.0]: https://github.com/Bhairavi-ancy/rn-grid-date-time-picker/compare/v1.0.0...v1.1.0
|
|
165
186
|
[1.0.0]: https://github.com/Bhairavi-ancy/rn-grid-date-time-picker/releases/tag/v1.0.0
|
|
@@ -21,7 +21,6 @@ var _CalendarSwitch = _interopRequireDefault(require("./calendar/CalendarSwitch.
|
|
|
21
21
|
var _localeNames = require("./calendar/localeNames.js");
|
|
22
22
|
var _direction = require("./theme/direction.js");
|
|
23
23
|
var _numerals2 = require("./theme/numerals.js");
|
|
24
|
-
var _selection = require("./calendar/selection.js");
|
|
25
24
|
var _PickerContainer = _interopRequireDefault(require("./container/PickerContainer.js"));
|
|
26
25
|
var _fieldText = require("./field/fieldText.js");
|
|
27
26
|
var _FieldMessages = _interopRequireDefault(require("./field/FieldMessages.js"));
|
|
@@ -46,19 +45,6 @@ const RTL = {
|
|
|
46
45
|
direction: 'rtl'
|
|
47
46
|
};
|
|
48
47
|
|
|
49
|
-
/** The same kind of selection with nothing in it. */
|
|
50
|
-
const emptySelection = sel => sel.kind === 'single' ? {
|
|
51
|
-
kind: 'single',
|
|
52
|
-
day: null
|
|
53
|
-
} : sel.kind === 'range' ? {
|
|
54
|
-
kind: 'range',
|
|
55
|
-
from: null,
|
|
56
|
-
to: null
|
|
57
|
-
} : {
|
|
58
|
-
...sel,
|
|
59
|
-
days: []
|
|
60
|
-
};
|
|
61
|
-
|
|
62
48
|
/** Minute steps that divide the hour. */
|
|
63
49
|
const MINUTE_STEPS = [1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30, 60];
|
|
64
50
|
|
|
@@ -575,10 +561,10 @@ const DateTimePicker = props => {
|
|
|
575
561
|
};
|
|
576
562
|
const valueKey = JSON.stringify(value ?? '');
|
|
577
563
|
|
|
578
|
-
// A selection
|
|
579
|
-
//
|
|
580
|
-
// value remembers its calendar; one from outside counts as picked in
|
|
581
|
-
// calendar the picker opens on.
|
|
564
|
+
// A selection shows in both tabs (Gregorian and Hijri). It is saved with the
|
|
565
|
+
// calendar on screen, and the on-screen field writes it in that calendar. A
|
|
566
|
+
// saved value remembers its calendar; one from outside counts as picked in
|
|
567
|
+
// the calendar the picker opens on.
|
|
582
568
|
// The saved value as a draft, for the on-screen field and for comparing
|
|
583
569
|
// values by what they hold.
|
|
584
570
|
const saved = (0, _react.useMemo)(() => (0, _draft.createDraft)(mode, value, draftOptions),
|
|
@@ -589,32 +575,12 @@ const DateTimePicker = props => {
|
|
|
589
575
|
const savedContent = contentOf(saved);
|
|
590
576
|
const savedSystemRef = (0, _react.useRef)(null);
|
|
591
577
|
const savedSystem = savedSystemRef.current?.content === savedContent ? savedSystemRef.current.system : outsideSystem;
|
|
592
|
-
const
|
|
593
|
-
//
|
|
594
|
-
//
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
valueKey,
|
|
599
|
-
savedSystem
|
|
600
|
-
});
|
|
601
|
-
(0, _react.useEffect)(() => {
|
|
602
|
-
const seen = systemSeen.current;
|
|
603
|
-
systemSeen.current = {
|
|
604
|
-
isOpen,
|
|
605
|
-
valueKey,
|
|
606
|
-
savedSystem
|
|
607
|
-
};
|
|
608
|
-
setDraftSystem(savedSystem);
|
|
609
|
-
const systemOnly = seen.isOpen === isOpen && seen.valueKey === valueKey && seen.savedSystem !== savedSystem;
|
|
610
|
-
if (systemOnly && isOpen && edited.current) {
|
|
611
|
-
draft.clear();
|
|
612
|
-
resetSelectionUi();
|
|
613
|
-
}
|
|
614
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps -- the draft's actions are stable
|
|
615
|
-
}, [isOpen, valueKey, savedSystem]);
|
|
616
|
-
(0, _react.useEffect)(() => setDualTab(dualDefaultTab), [isOpen, dualDefaultTab]);
|
|
617
|
-
const selectionShown = draftSystem === shownSystem;
|
|
578
|
+
const hasSaved = valuesOf(saved).some(v => v !== null);
|
|
579
|
+
// Each open starts on the tab the saved value was saved with; with no value,
|
|
580
|
+
// on dualDefaultTab.
|
|
581
|
+
(0, _react.useEffect)(() => setDualTab(hasSaved ? savedSystem : dualDefaultTab),
|
|
582
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps -- on open and on a new dualDefaultTab, not on every save
|
|
583
|
+
[isOpen, dualDefaultTab]);
|
|
618
584
|
/** Saves a value: with the calendar it was picked in, when one can be Hijri. */
|
|
619
585
|
const emitChange = (0, _react.useCallback)((wire, picked) => {
|
|
620
586
|
savedSystemRef.current = {
|
|
@@ -638,11 +604,12 @@ const DateTimePicker = props => {
|
|
|
638
604
|
bounds: constraints.timeBounds(v.date)
|
|
639
605
|
}) === null)) && !typingBlocked && !wheelSpinning && !confirmDisabled;
|
|
640
606
|
|
|
641
|
-
// Every save: Confirm, an 'instant' edit (onConfirm is added by `confirm`)
|
|
607
|
+
// Every save: Confirm, an 'instant' edit (onConfirm is added by `confirm`),
|
|
608
|
+
// with the calendar on screen.
|
|
642
609
|
const commit = (0, _react.useCallback)(wire => {
|
|
643
|
-
emitChange(wire,
|
|
610
|
+
emitChange(wire, shownSystem);
|
|
644
611
|
onBlur?.();
|
|
645
|
-
}, [emitChange,
|
|
612
|
+
}, [emitChange, shownSystem, onBlur]);
|
|
646
613
|
const confirm = (0, _react.useCallback)(() => {
|
|
647
614
|
if (!canConfirm) return;
|
|
648
615
|
const {
|
|
@@ -674,8 +641,8 @@ const DateTimePicker = props => {
|
|
|
674
641
|
draft.clear();
|
|
675
642
|
resetSelectionUi();
|
|
676
643
|
edited.current = false;
|
|
677
|
-
emitChange('',
|
|
678
|
-
}, [draft, emitChange,
|
|
644
|
+
emitChange('', shownSystem);
|
|
645
|
+
}, [draft, emitChange, shownSystem, resetSelectionUi]);
|
|
679
646
|
const clearDraft = (0, _react.useCallback)(() => {
|
|
680
647
|
edited.current = true;
|
|
681
648
|
draft.clear();
|
|
@@ -684,7 +651,6 @@ const DateTimePicker = props => {
|
|
|
684
651
|
|
|
685
652
|
// × in the field above the calendar. 'instant' saves every edit, so it
|
|
686
653
|
// clears the saved value too (once; an empty value isn't saved again).
|
|
687
|
-
const hasSaved = valuesOf(saved).some(v => v !== null);
|
|
688
654
|
const clearInSheet = (0, _react.useCallback)(() => {
|
|
689
655
|
if (commitMode === 'instant' && hasSaved) clearValue();else clearDraft();
|
|
690
656
|
}, [commitMode, hasSaved, clearValue, clearDraft]);
|
|
@@ -696,7 +662,8 @@ const DateTimePicker = props => {
|
|
|
696
662
|
// Confirm press, but only while open (closing discards, as with Confirm),
|
|
697
663
|
// and only what the draft holds: a time still being typed isn't saved yet.
|
|
698
664
|
// An edit equal to the saved value isn't saved again; one `validate`
|
|
699
|
-
// rejected waits until the selection or the saved value changes.
|
|
665
|
+
// rejected waits until the selection or the saved value changes. A tab
|
|
666
|
+
// change the user makes saves the selection again with the new calendar.
|
|
700
667
|
const lastRejected = (0, _react.useRef)(null);
|
|
701
668
|
// The last value saved: not saved again while the parent's `value` catches
|
|
702
669
|
// up (a slow store, a server round trip) or when it never does.
|
|
@@ -714,11 +681,12 @@ const DateTimePicker = props => {
|
|
|
714
681
|
if (!typingDone || timeIssue || !canSave(draft.draft)) return;
|
|
715
682
|
const wire = draft.toWire();
|
|
716
683
|
const key = JSON.stringify(wire);
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
// dates
|
|
684
|
+
const sent = `${shownSystem} ${key}`;
|
|
685
|
+
if (key === lastRejected.current || sent === lastEmitted.current) return;
|
|
686
|
+
// The same dates in the same calendar aren't saved again; the same dates
|
|
687
|
+
// with the other tab on screen are.
|
|
720
688
|
const unchanged = key === valueKey || contentOf(draft.draft) === savedContent;
|
|
721
|
-
if (unchanged &&
|
|
689
|
+
if (unchanged && shownSystem === savedSystem) return;
|
|
722
690
|
const message = latest.current.validate?.(wire);
|
|
723
691
|
if (message) {
|
|
724
692
|
lastRejected.current = key;
|
|
@@ -729,14 +697,14 @@ const DateTimePicker = props => {
|
|
|
729
697
|
latest.current.onError?.('VALIDATION', wire);
|
|
730
698
|
return;
|
|
731
699
|
}
|
|
732
|
-
lastEmitted.current =
|
|
700
|
+
lastEmitted.current = sent;
|
|
733
701
|
commit(wire);
|
|
734
702
|
};
|
|
735
703
|
// Only typing waits for the field to be left; a tap is a finished edit.
|
|
736
704
|
const typedLast = (0, _react.useRef)(false);
|
|
737
705
|
(0, _react.useEffect)(() => saveInstant(!sheetTyping || !typedLast.current),
|
|
738
706
|
// eslint-disable-next-line react-hooks/exhaustive-deps -- when the draft or what blocks it changes, not when callbacks are re-created
|
|
739
|
-
[commitMode, isOpen, sheetTyping, draft.draft,
|
|
707
|
+
[commitMode, isOpen, sheetTyping, draft.draft, shownSystem, timeIssue, typingBlocked, wheelSpinning, confirmDisabled, constraints]);
|
|
740
708
|
// Closing while the sheet's field still has focus ends the typing: an
|
|
741
709
|
// instant picker saves what was typed before it closes.
|
|
742
710
|
const saveInstantRef = (0, _react.useRef)(saveInstant);
|
|
@@ -752,16 +720,9 @@ const DateTimePicker = props => {
|
|
|
752
720
|
date: parsed.dateOnly,
|
|
753
721
|
time: fixedTime ?? pending[key] ?? newTime()
|
|
754
722
|
} : null);
|
|
755
|
-
|
|
756
|
-
// Typed segments are Gregorian, so typing keeps the calendar a selection was
|
|
757
|
-
// picked in; into an empty draft, it takes the calendar on screen.
|
|
758
|
-
const adoptShownIfEmpty = () => {
|
|
759
|
-
if (valuesOf(d).every(v => v === null)) setDraftSystem(shownSystem);
|
|
760
|
-
};
|
|
761
723
|
const onSheetTyped = parsed => {
|
|
762
724
|
edited.current = true;
|
|
763
725
|
typedLast.current = true;
|
|
764
|
-
adoptShownIfEmpty();
|
|
765
726
|
const typed = withFilledTime(parsed, 'single');
|
|
766
727
|
setTypingBlock('single', !parsed.isEmpty && !typed);
|
|
767
728
|
if (typed) draft.setValue(typed, 'single');else if (parsed.isEmpty) draft.clear();
|
|
@@ -769,7 +730,6 @@ const DateTimePicker = props => {
|
|
|
769
730
|
const onRangeTyped = (end, parsed) => {
|
|
770
731
|
edited.current = true;
|
|
771
732
|
typedLast.current = true;
|
|
772
|
-
adoptShownIfEmpty();
|
|
773
733
|
const typed = withFilledTime(parsed, end);
|
|
774
734
|
setTypingBlock(end, !parsed.isEmpty && !typed);
|
|
775
735
|
if (typed || parsed.isEmpty) draft.setValue(typed, end);
|
|
@@ -815,56 +775,45 @@ const DateTimePicker = props => {
|
|
|
815
775
|
const onSelectDay = (0, _react.useCallback)(day => {
|
|
816
776
|
edited.current = true;
|
|
817
777
|
typedLast.current = false;
|
|
818
|
-
// A pick in the other calendar starts over: the selection is one calendar's.
|
|
819
|
-
const fresh = draftSystem !== shownSystem && valuesOf(d).some(v => v !== null);
|
|
820
|
-
setDraftSystem(shownSystem);
|
|
821
|
-
const cur = fresh ? (0, _draft.clearDraft)(d) : d;
|
|
822
|
-
const end0 = fresh ? 'from' : activeEnd;
|
|
823
|
-
const dayInEdit = fresh ? null : activeDay;
|
|
824
|
-
const times = fresh ? {} : pending;
|
|
825
|
-
if (fresh) {
|
|
826
|
-
draft.clear();
|
|
827
|
-
resetSelectionUi();
|
|
828
|
-
}
|
|
829
778
|
// A multiple picker scrolls for its first date only, so more can be picked.
|
|
830
|
-
if (
|
|
831
|
-
if (
|
|
779
|
+
if (d.mode !== 'multiple' || d.slots.length === 0) revealTime();
|
|
780
|
+
if (d.mode === 'range') {
|
|
832
781
|
if (rangeLayout === 'fromTo') {
|
|
833
782
|
setEndPicked(false);
|
|
834
783
|
// A full range: the tap starts a new one (or moves the nearest end).
|
|
835
|
-
if (!endPicked &&
|
|
784
|
+
if (!endPicked && d.from.value && d.to.value) {
|
|
836
785
|
const moveNearest = range?.reselect === 'moveNearestEnd';
|
|
837
|
-
const nearest = Math.abs((0, _calendarDate.daysBetween)(
|
|
786
|
+
const nearest = Math.abs((0, _calendarDate.daysBetween)(d.from.value.date, day)) < Math.abs((0, _calendarDate.daysBetween)(d.to.value.date, day)) ? 'from' : 'to';
|
|
838
787
|
const end = moveNearest ? nearest : 'from';
|
|
839
788
|
setTypingBlock('from', false);
|
|
840
789
|
setTypingBlock('to', false);
|
|
841
|
-
draft.selectDay(day, fixedTime ??
|
|
790
|
+
draft.selectDay(day, fixedTime ?? pending[end] ?? newTime());
|
|
842
791
|
setActiveEnd(moveNearest ? nearest : 'to');
|
|
843
792
|
return;
|
|
844
793
|
}
|
|
845
794
|
// Choosing the end after a start tap: a day before the start moves the start.
|
|
846
|
-
const end1 =
|
|
795
|
+
const end1 = activeEnd === 'to' && !endPicked && d.from.value && (0, _calendarDate.compareCalendarDates)(day, d.from.value.date) < 0 ? 'from' : activeEnd;
|
|
847
796
|
// The tapped day replaces whatever was typed in this end only.
|
|
848
797
|
setTypingBlock(end1, false);
|
|
849
|
-
draft.setRangeEnd(day, end1, end1 === 'to' ? endTimeFor(
|
|
798
|
+
draft.setRangeEnd(day, end1, end1 === 'to' ? endTimeFor(d.from.value, day, pending.to) : fixedTime ?? pending.from ?? newTime());
|
|
850
799
|
// The start tapped again where a range can't be one day deselects
|
|
851
800
|
// it, so the next tap picks the start again.
|
|
852
|
-
const deselects = end1 === 'to' && !(0, _draft.sameDayRangeOk)(draftOptions) && (0, _calendarDate.isSameDay)(
|
|
853
|
-
if (
|
|
801
|
+
const deselects = end1 === 'to' && !(0, _draft.sameDayRangeOk)(draftOptions) && (0, _calendarDate.isSameDay)(d.from.value?.date, day);
|
|
802
|
+
if (activeEnd === 'from') setActiveEnd('to');else if (deselects) setActiveEnd('from');
|
|
854
803
|
return;
|
|
855
804
|
}
|
|
856
805
|
// The single field: the first tap is the start, the next one the end.
|
|
857
|
-
const startsOver = !
|
|
806
|
+
const startsOver = !d.from.value || !!d.to.value && range?.reselect !== 'moveNearestEnd';
|
|
858
807
|
const end = startsOver ? 'from' : 'to';
|
|
859
808
|
setTypingBlock('single', false);
|
|
860
|
-
draft.selectDay(day, end === 'to' && !
|
|
809
|
+
draft.selectDay(day, end === 'to' && !d.to.value ? endTimeFor(d.from.value, day, pending.to) : fixedTime ?? pending[end] ?? newTime());
|
|
861
810
|
return;
|
|
862
811
|
}
|
|
863
|
-
if (
|
|
812
|
+
if (d.mode === 'multiple') {
|
|
864
813
|
const perDate = type === 'datetime' && multipleTimeMode === 'perDate';
|
|
865
|
-
const picked =
|
|
814
|
+
const picked = d.slots.some(slot => (0, _calendarDate.isSameDay)(slot.value?.date, day));
|
|
866
815
|
// perDate: a tap on a picked day first makes it the one the time row edits.
|
|
867
|
-
if (perDate && picked && !(0, _calendarDate.isSameDay)(
|
|
816
|
+
if (perDate && picked && !(0, _calendarDate.isSameDay)(activeDay, day)) {
|
|
868
817
|
setActiveDay(day);
|
|
869
818
|
return;
|
|
870
819
|
}
|
|
@@ -873,10 +822,10 @@ const DateTimePicker = props => {
|
|
|
873
822
|
return;
|
|
874
823
|
}
|
|
875
824
|
setTypingBlock('single', false);
|
|
876
|
-
draft.selectDay(day, fixedTime ??
|
|
825
|
+
draft.selectDay(day, fixedTime ?? pending.single ?? newTime());
|
|
877
826
|
},
|
|
878
827
|
// eslint-disable-next-line react-hooks/exhaustive-deps -- valuesOf reads only `d` and props listed here
|
|
879
|
-
[d, draft, newTime, rangeLayout, activeEnd, activeDay, fixedTime, pending, range?.reselect, type, multipleTimeMode, setTypingBlock,
|
|
828
|
+
[d, draft, newTime, rangeLayout, activeEnd, activeDay, fixedTime, pending, range?.reselect, type, multipleTimeMode, setTypingBlock, endPicked, draftOptions, minuteStep, constraints, revealTime]);
|
|
880
829
|
|
|
881
830
|
// The calendar gets a tap handler that never changes, so its memoized day
|
|
882
831
|
// cells don't all redraw on every tap; it calls the current one.
|
|
@@ -999,11 +948,10 @@ const DateTimePicker = props => {
|
|
|
999
948
|
// The calendar the on-screen field writes the saved value in.
|
|
1000
949
|
const fieldSystem = fieldCalendar === 'gregory' ? 'gregory' : savedSystem;
|
|
1001
950
|
const savedDateText = dateTextFor(fieldSystem);
|
|
1002
|
-
const draftDateText = dateTextFor(
|
|
951
|
+
const draftDateText = dateTextFor(shownSystem);
|
|
1003
952
|
const savedStrings = stringsFor(fieldSystem);
|
|
1004
|
-
|
|
1005
|
-
//
|
|
1006
|
-
// field's keep `strings`.
|
|
953
|
+
// The texts inside the picker, its error messages too, follow the tab on
|
|
954
|
+
// screen; the on-screen field's keep `strings`.
|
|
1007
955
|
const shownStrings = stringsFor(shownSystem);
|
|
1008
956
|
|
|
1009
957
|
// What the on-screen field shows: the saved value, never the draft.
|
|
@@ -1055,11 +1003,12 @@ const DateTimePicker = props => {
|
|
|
1055
1003
|
};
|
|
1056
1004
|
const sheetValue = draft.draft.mode === 'single' ? draft.draft.slot.value : null;
|
|
1057
1005
|
// A time outside the limits is explained under the time row, not here.
|
|
1058
|
-
const
|
|
1006
|
+
const notAllowedError = sheetOptions?.showNotAllowedError === false ? '' : shownStrings.errorNotAllowed;
|
|
1007
|
+
const sheetValueError = sheetValue && dayOff(sheetValue.date) ? notAllowedError : '';
|
|
1059
1008
|
let rangeError = '';
|
|
1060
1009
|
if (d.mode === 'range' && d.from.value && d.to.value) {
|
|
1061
1010
|
const length = (0, _calendarDate.daysBetween)(d.from.value.date, d.to.value.date) + 1;
|
|
1062
|
-
if (constraints.dayStatus(d.from.value.date).disabled || constraints.dayStatus(d.to.value.date).disabled) rangeError =
|
|
1011
|
+
if (constraints.dayStatus(d.from.value.date).disabled || constraints.dayStatus(d.to.value.date).disabled) rangeError = notAllowedError;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);
|
|
1063
1012
|
}
|
|
1064
1013
|
const fieldCommon = {
|
|
1065
1014
|
type,
|
|
@@ -1109,7 +1058,7 @@ const DateTimePicker = props => {
|
|
|
1109
1058
|
testID: testID ? `${testID}-value` : undefined
|
|
1110
1059
|
}) : mode === 'single' ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_ValueField.default, {
|
|
1111
1060
|
...fieldCommon,
|
|
1112
|
-
strings:
|
|
1061
|
+
strings: shownStrings,
|
|
1113
1062
|
errorStrings: shownStrings,
|
|
1114
1063
|
value: sheetValue,
|
|
1115
1064
|
displayText: precision !== 'day' ? periodText(sheetValue) : undefined,
|
|
@@ -1126,7 +1075,7 @@ const DateTimePicker = props => {
|
|
|
1126
1075
|
testID: testID ? `${testID}-value` : undefined
|
|
1127
1076
|
}) : d.mode === 'range' ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_RangeFields.default, {
|
|
1128
1077
|
...fieldCommon,
|
|
1129
|
-
strings:
|
|
1078
|
+
strings: shownStrings,
|
|
1130
1079
|
errorStrings: shownStrings,
|
|
1131
1080
|
layout: rangeLayout,
|
|
1132
1081
|
dateText: draftDateText,
|
|
@@ -1146,9 +1095,9 @@ const DateTimePicker = props => {
|
|
|
1146
1095
|
testID: testID
|
|
1147
1096
|
}) : d.mode === 'multiple' ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_ValueField.default, {
|
|
1148
1097
|
...fieldCommon,
|
|
1149
|
-
strings:
|
|
1098
|
+
strings: shownStrings,
|
|
1150
1099
|
value: null,
|
|
1151
|
-
displayText: (0, _fieldText.formatMultipleText)(draftValues, type, dateFormat, timeFormat, draftDateText,
|
|
1100
|
+
displayText: (0, _fieldText.formatMultipleText)(draftValues, type, dateFormat, timeFormat, draftDateText, shownStrings),
|
|
1152
1101
|
placeholder: sheetOptions?.fieldPlaceholder,
|
|
1153
1102
|
allowClear: allowClear,
|
|
1154
1103
|
onClear: clearInSheet,
|
|
@@ -1163,13 +1112,20 @@ const DateTimePicker = props => {
|
|
|
1163
1112
|
dual: strings.calendarDual ?? _defaultStrings.DEFAULT_STRINGS.calendarDual
|
|
1164
1113
|
};
|
|
1165
1114
|
const systemA11yLabel = strings.a11yCalendarSystem ?? _defaultStrings.DEFAULT_STRINGS.a11yCalendarSystem;
|
|
1115
|
+
// A calendar or tab the user picks is an edit: 'instant' saves the selection
|
|
1116
|
+
// again with that calendar.
|
|
1166
1117
|
const chooseSystem = next => {
|
|
1167
1118
|
if (next === system) return;
|
|
1119
|
+
edited.current = true;
|
|
1168
1120
|
setChosenSystem(next);
|
|
1169
1121
|
if (next === 'dual') setDualTab(dualDefaultTab);
|
|
1170
1122
|
echo.current = next;
|
|
1171
1123
|
onCalendarSystemChange?.(next);
|
|
1172
1124
|
};
|
|
1125
|
+
const chooseTab = next => {
|
|
1126
|
+
edited.current = true;
|
|
1127
|
+
setDualTab(next);
|
|
1128
|
+
};
|
|
1173
1129
|
const calendarSwitchNode = !switchSystems ? null : renderCalendarSwitch ? renderCalendarSwitch({
|
|
1174
1130
|
systems: switchSystems,
|
|
1175
1131
|
selected: system,
|
|
@@ -1201,7 +1157,7 @@ const DateTimePicker = props => {
|
|
|
1201
1157
|
label: systemLabels.hijri
|
|
1202
1158
|
}],
|
|
1203
1159
|
selected: dualTab,
|
|
1204
|
-
onSelect:
|
|
1160
|
+
onSelect: chooseTab,
|
|
1205
1161
|
accessibilityLabel: systemA11yLabel,
|
|
1206
1162
|
tokens: tokens,
|
|
1207
1163
|
styles: styles,
|
|
@@ -1217,16 +1173,16 @@ const DateTimePicker = props => {
|
|
|
1217
1173
|
children: node
|
|
1218
1174
|
})
|
|
1219
1175
|
});
|
|
1220
|
-
// Another calendar opens on the days the last one showed, else
|
|
1221
|
-
//
|
|
1222
|
-
const calendarAnchor = shownAnchor.current ??
|
|
1176
|
+
// Another calendar opens on the days the last one showed, else where the
|
|
1177
|
+
// picker would open.
|
|
1178
|
+
const calendarAnchor = shownAnchor.current ?? initialVisibleDate;
|
|
1223
1179
|
const calendar = /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
1224
1180
|
style: folded ? FOLDED : undefined,
|
|
1225
1181
|
children: [calendarSwitchNode, dualTabs, mirrored(/*#__PURE__*/(0, _jsxRuntime.jsx)(_Calendar.default, {
|
|
1226
|
-
constraints:
|
|
1182
|
+
constraints: calendarConstraints,
|
|
1227
1183
|
today: today,
|
|
1228
1184
|
initialVisibleDate: calendarAnchor,
|
|
1229
|
-
selection:
|
|
1185
|
+
selection: selection,
|
|
1230
1186
|
onSelectDay: onSelectDayStable,
|
|
1231
1187
|
firstDayOfWeek: firstDayOfWeek,
|
|
1232
1188
|
showOutsideDays: showOutsideDays,
|
|
@@ -1289,15 +1245,11 @@ const DateTimePicker = props => {
|
|
|
1289
1245
|
// Shown while the selection is still the one it was given for.
|
|
1290
1246
|
const validationMessage = validation && (validation.key === JSON.stringify(draft.toWire()) || validation.key === JSON.stringify((0, _draft.draftToWire)(preview, draftOptions))) ? validation.message : null;
|
|
1291
1247
|
|
|
1292
|
-
// The field
|
|
1293
|
-
// the calendar and the time rows follow the tab that shows.
|
|
1248
|
+
// The field, the calendar and the time rows follow the tab that shows.
|
|
1294
1249
|
const sheetContent = /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
|
|
1295
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.
|
|
1296
|
-
value: digitsFor(draftSystem),
|
|
1297
|
-
children: sheetField
|
|
1298
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_numerals2.NumeralsContext.Provider, {
|
|
1250
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_numerals2.NumeralsContext.Provider, {
|
|
1299
1251
|
value: digitsFor(shownSystem),
|
|
1300
|
-
children: calendar
|
|
1252
|
+
children: [sheetField, calendar]
|
|
1301
1253
|
}), timeRow == null ? null :
|
|
1302
1254
|
/*#__PURE__*/
|
|
1303
1255
|
// Measured for the scroll to the time (sheet.scrollToTime).
|