@react-aria/datepicker 3.0.0-rc.1 → 3.0.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/dist/main.js CHANGED
@@ -4,6 +4,7 @@ var $IwcIq$react = require("react");
4
4
  var $IwcIq$reactarialabel = require("@react-aria/label");
5
5
  var $IwcIq$reactariai18n = require("@react-aria/i18n");
6
6
  var $IwcIq$reactariainteractions = require("@react-aria/interactions");
7
+ var $IwcIq$internationalizeddate = require("@internationalized/date");
7
8
  var $IwcIq$internationalizednumber = require("@internationalized/number");
8
9
  var $IwcIq$reactariaspinbutton = require("@react-aria/spinbutton");
9
10
  var $IwcIq$internationalizedmessage = require("@internationalized/message");
@@ -258,9 +259,9 @@ function $715562ad3b4cced4$export$4a931266a3838b86(state, ref1, disableArrowNavi
258
259
  }while (last)
259
260
  }
260
261
  // Now go backwards until we find an element that is not a placeholder.
261
- while(target === null || target === void 0 ? void 0 : target.getAttribute('aria-placeholder')){
262
+ while(target === null || target === void 0 ? void 0 : target.hasAttribute('data-placeholder')){
262
263
  let prev = walker.previousNode();
263
- if (prev && prev.getAttribute('aria-placeholder')) target = prev;
264
+ if (prev && prev.hasAttribute('data-placeholder')) target = prev;
264
265
  else break;
265
266
  }
266
267
  if (target) target.focus();
@@ -467,6 +468,7 @@ function $e90ae7c26a69c6b1$export$42df105a73306d51(props, state, ref) {
467
468
 
468
469
 
469
470
 
471
+
470
472
  function $934ac650a0aceb4b$export$d42c60378c8168f8() {
471
473
  let { locale: locale } = $IwcIq$reactariai18n.useLocale();
472
474
  return $IwcIq$react.useMemo(()=>{
@@ -501,7 +503,7 @@ function $5c015c6316d1904d$export$1315d136e6f7581(segment, state, ref) {
501
503
  let { locale: locale } = $IwcIq$reactariai18n.useLocale();
502
504
  let displayNames = $934ac650a0aceb4b$export$d42c60378c8168f8();
503
505
  let { ariaLabel: ariaLabel , ariaLabelledBy: ariaLabelledBy , ariaDescribedBy: ariaDescribedBy , focusManager: focusManager } = $4acc2f407c169e55$export$653eddfc964b0f8a.get(state);
504
- let textValue = segment.text;
506
+ let textValue = segment.isPlaceholder ? '' : segment.text;
505
507
  let options = $IwcIq$react.useMemo(()=>state.dateFormatter.resolvedOptions()
506
508
  , [
507
509
  state.dateFormatter
@@ -515,11 +517,14 @@ function $5c015c6316d1904d$export$1315d136e6f7581(segment, state, ref) {
515
517
  hour12: options.hour12,
516
518
  timeZone: options.timeZone
517
519
  });
518
- if (segment.type === 'month') {
520
+ if (segment.type === 'month' && !segment.isPlaceholder) {
519
521
  let monthTextValue = monthDateFormatter.format(state.dateValue);
520
522
  textValue = monthTextValue !== textValue ? `${textValue} – ${monthTextValue}` : monthTextValue;
521
- } else if (segment.type === 'hour') textValue = hourDateFormatter.format(state.dateValue);
523
+ } else if (segment.type === 'hour' && !segment.isPlaceholder) textValue = hourDateFormatter.format(state.dateValue);
522
524
  let { spinButtonProps: spinButtonProps } = $IwcIq$reactariaspinbutton.useSpinButton({
525
+ // The ARIA spec says aria-valuenow is optional if there's no value, but aXe seems to require it.
526
+ // This doesn't seem to have any negative effects with real AT since we also use aria-valuetext.
527
+ // https://github.com/dequelabs/axe-core/issues/3505
523
528
  value: segment.value,
524
529
  textValue: textValue,
525
530
  minValue: segment.minValue,
@@ -573,14 +578,6 @@ function $5c015c6316d1904d$export$1315d136e6f7581(segment, state, ref) {
573
578
  if (e.key === 'a' && ($IwcIq$reactariautils.isMac() ? e.metaKey : e.ctrlKey)) e.preventDefault();
574
579
  if (e.ctrlKey || e.metaKey || e.shiftKey || e.altKey) return;
575
580
  switch(e.key){
576
- case 'Enter':
577
- e.preventDefault();
578
- e.stopPropagation();
579
- if (segment.isPlaceholder && !state.isReadOnly) state.confirmPlaceholder(segment.type);
580
- focusManager.focusNext();
581
- break;
582
- case 'Tab':
583
- break;
584
581
  case 'Backspace':
585
582
  case 'Delete':
586
583
  // Safari on iOS does not fire beforeinput for the backspace key because the cursor is at the start.
@@ -614,6 +611,42 @@ function $5c015c6316d1904d$export$1315d136e6f7581(segment, state, ref) {
614
611
  }, [
615
612
  amPmFormatter
616
613
  ]);
614
+ // Get a list of formatted era names so users can type the first character to choose one.
615
+ let eraFormatter = $IwcIq$reactariai18n.useDateFormatter({
616
+ year: 'numeric',
617
+ era: 'narrow',
618
+ timeZone: 'UTC'
619
+ });
620
+ let eras1 = $IwcIq$react.useMemo(()=>{
621
+ if (segment.type !== 'era') return [];
622
+ let date = $IwcIq$internationalizeddate.toCalendar(new $IwcIq$internationalizeddate.CalendarDate(1, 1, 1), state.calendar);
623
+ let eras = state.calendar.getEras().map((era)=>{
624
+ let eraDate = date.set({
625
+ year: 1,
626
+ month: 1,
627
+ day: 1,
628
+ era: era
629
+ }).toDate('UTC');
630
+ let parts = eraFormatter.formatToParts(eraDate);
631
+ let formatted = parts.find((p)=>p.type === 'era'
632
+ ).value;
633
+ return {
634
+ era: era,
635
+ formatted: formatted
636
+ };
637
+ });
638
+ // Remove the common prefix from formatted values. This is so that in calendars with eras like
639
+ // ERA0 and ERA1 (e.g. Ethiopic), users can press "0" and "1" to select an era. In other cases,
640
+ // the first letter is used.
641
+ let prefixLength = $5c015c6316d1904d$var$commonPrefixLength(eras.map((era)=>era.formatted
642
+ ));
643
+ if (prefixLength) for (let era1 of eras)era1.formatted = era1.formatted.slice(prefixLength);
644
+ return eras;
645
+ }, [
646
+ eraFormatter,
647
+ state.calendar,
648
+ segment.type
649
+ ]);
617
650
  let onInput = (key)=>{
618
651
  if (state.isDisabled || state.isReadOnly) return;
619
652
  let newValue = enteredKeys.current + key;
@@ -624,6 +657,16 @@ function $5c015c6316d1904d$export$1315d136e6f7581(segment, state, ref) {
624
657
  else break;
625
658
  focusManager.focusNext();
626
659
  break;
660
+ case 'era':
661
+ {
662
+ let matched = eras1.find((e)=>startsWith(e.formatted, key)
663
+ );
664
+ if (matched) {
665
+ state.setSegment('era', matched.era);
666
+ focusManager.focusNext();
667
+ }
668
+ break;
669
+ }
627
670
  case 'day':
628
671
  case 'hour':
629
672
  case 'minute':
@@ -661,14 +704,9 @@ function $5c015c6316d1904d$export$1315d136e6f7581(segment, state, ref) {
661
704
  let onFocus = ()=>{
662
705
  enteredKeys.current = '';
663
706
  $IwcIq$reactariautils.scrollIntoView($IwcIq$reactariautils.getScrollParent(ref.current), ref.current);
664
- // Safari requires that a selection is set or it won't fire input events.
665
- // Since usePress disables text selection, this won't happen by default.
666
- ref.current.style.webkitUserSelect = 'text';
667
- ref.current.style.userSelect = 'text';
707
+ // Collapse selection to start or Chrome won't fire input events.
668
708
  let selection = window.getSelection();
669
709
  selection.collapse(ref.current);
670
- ref.current.style.webkitUserSelect = 'none';
671
- ref.current.style.userSelect = 'none';
672
710
  };
673
711
  let compositionRef = $IwcIq$react.useRef('');
674
712
  // @ts-ignore - TODO: possibly old TS version? doesn't fail in my editor...
@@ -704,10 +742,19 @@ function $5c015c6316d1904d$export$1315d136e6f7581(segment, state, ref) {
704
742
  break;
705
743
  }
706
744
  });
707
- // For Android: prevent selection on long press.
708
- $IwcIq$reactariautils.useEvent(ref, 'selectstart', (e)=>{
709
- e.preventDefault();
710
- });
745
+ $IwcIq$reactariautils.useLayoutEffect(()=>{
746
+ let element = ref.current;
747
+ return ()=>{
748
+ // If the focused segment is removed, focus the previous one, or the next one if there was no previous one.
749
+ if (document.activeElement === element) {
750
+ let prev = focusManager.focusPrevious();
751
+ if (!prev) focusManager.focusNext();
752
+ }
753
+ };
754
+ }, [
755
+ ref,
756
+ focusManager
757
+ ]);
711
758
  // spinbuttons cannot be focused with VoiceOver on iOS.
712
759
  let touchPropOverrides = $IwcIq$reactariautils.isIOS() || segment.type === 'timeZoneName' ? {
713
760
  role: 'textbox',
@@ -747,8 +794,8 @@ function $5c015c6316d1904d$export$1315d136e6f7581(segment, state, ref) {
747
794
  ...touchPropOverrides,
748
795
  'aria-invalid': state.validationState === 'invalid' ? 'true' : undefined,
749
796
  'aria-describedby': ariaDescribedBy,
750
- 'aria-placeholder': segment.isPlaceholder ? segment.text : undefined,
751
797
  'aria-readonly': state.isReadOnly || !segment.isEditable ? 'true' : undefined,
798
+ 'data-placeholder': segment.isPlaceholder || undefined,
752
799
  contentEditable: isEditable,
753
800
  suppressContentEditableWarning: isEditable,
754
801
  spellCheck: isEditable ? 'false' : undefined,
@@ -756,14 +803,12 @@ function $5c015c6316d1904d$export$1315d136e6f7581(segment, state, ref) {
756
803
  autoCorrect: isEditable ? 'off' : undefined,
757
804
  // Capitalization was changed in React 17...
758
805
  [parseInt(($parcel$interopDefault($IwcIq$react)).version, 10) >= 17 ? 'enterKeyHint' : 'enterkeyhint']: isEditable ? 'next' : undefined,
759
- inputMode: state.isDisabled || segment.type === 'dayPeriod' || !isEditable ? undefined : 'numeric',
806
+ inputMode: state.isDisabled || segment.type === 'dayPeriod' || segment.type === 'era' || !isEditable ? undefined : 'numeric',
760
807
  tabIndex: state.isDisabled ? undefined : 0,
761
808
  onKeyDown: onKeyDown,
762
809
  onFocus: onFocus,
763
810
  style: {
764
- caretColor: 'transparent',
765
- userSelect: 'none',
766
- WebkitUserSelect: 'none'
811
+ caretColor: 'transparent'
767
812
  },
768
813
  // Prevent pointer events from reaching useDatePickerGroup, and allow native browser behavior to focus the segment.
769
814
  onPointerDown (e) {
@@ -775,7 +820,16 @@ function $5c015c6316d1904d$export$1315d136e6f7581(segment, state, ref) {
775
820
  })
776
821
  };
777
822
  }
778
-
823
+ function $5c015c6316d1904d$var$commonPrefixLength(strings) {
824
+ // Sort the strings, and compare the characters in the first and last to find the common prefix.
825
+ strings.sort();
826
+ let first = strings[0];
827
+ let last = strings[strings.length - 1];
828
+ for(let i = 0; i < first.length; i++){
829
+ if (first[i] !== last[i]) return i;
830
+ }
831
+ return 0;
832
+ }
779
833
 
780
834
 
781
835
 
@@ -815,11 +869,6 @@ function $20f695b1b69e6b9e$export$12fd5f0e9f4bb192(props, state, ref) {
815
869
  let buttonId = $IwcIq$reactariautils.useId();
816
870
  let dialogId = $IwcIq$reactariautils.useId();
817
871
  let groupProps = $715562ad3b4cced4$export$4a931266a3838b86(state, ref);
818
- let { focusWithinProps: focusWithinProps } = $IwcIq$reactariainteractions.useFocusWithin({
819
- onBlurWithin () {
820
- state.confirmPlaceholder();
821
- }
822
- });
823
872
  let ariaDescribedBy = [
824
873
  descProps['aria-describedby'],
825
874
  fieldProps['aria-describedby']
@@ -849,7 +898,7 @@ function $20f695b1b69e6b9e$export$12fd5f0e9f4bb192(props, state, ref) {
849
898
  };
850
899
  let domProps = $IwcIq$reactariautils.filterDOMProps(props);
851
900
  return {
852
- groupProps: $IwcIq$reactariautils.mergeProps(domProps, groupProps, fieldProps, descProps, focusWithinProps, {
901
+ groupProps: $IwcIq$reactariautils.mergeProps(domProps, groupProps, fieldProps, descProps, {
853
902
  role: 'group',
854
903
  'aria-disabled': props.isDisabled || null,
855
904
  'aria-describedby': ariaDescribedBy