@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/module.js CHANGED
@@ -1,9 +1,10 @@
1
1
  import {createFocusManager as $cIPI0$createFocusManager, getFocusableTreeWalker as $cIPI0$getFocusableTreeWalker} from "@react-aria/focus";
2
- import {useId as $cIPI0$useId, useDescription as $cIPI0$useDescription, filterDOMProps as $cIPI0$filterDOMProps, mergeProps as $cIPI0$mergeProps, isMac as $cIPI0$isMac, scrollIntoView as $cIPI0$scrollIntoView, getScrollParent as $cIPI0$getScrollParent, useEvent as $cIPI0$useEvent, isIOS as $cIPI0$isIOS, useLabels as $cIPI0$useLabels} from "@react-aria/utils";
2
+ import {useId as $cIPI0$useId, useDescription as $cIPI0$useDescription, filterDOMProps as $cIPI0$filterDOMProps, mergeProps as $cIPI0$mergeProps, isMac as $cIPI0$isMac, scrollIntoView as $cIPI0$scrollIntoView, getScrollParent as $cIPI0$getScrollParent, useEvent as $cIPI0$useEvent, useLayoutEffect as $cIPI0$useLayoutEffect, isIOS as $cIPI0$isIOS, useLabels as $cIPI0$useLabels} from "@react-aria/utils";
3
3
  import $cIPI0$react, {useMemo as $cIPI0$useMemo, useRef as $cIPI0$useRef, useEffect as $cIPI0$useEffect} from "react";
4
4
  import {useField as $cIPI0$useField} from "@react-aria/label";
5
5
  import {useMessageFormatter as $cIPI0$useMessageFormatter, useLocale as $cIPI0$useLocale, useDateFormatter as $cIPI0$useDateFormatter, useFilter as $cIPI0$useFilter} from "@react-aria/i18n";
6
6
  import {useFocusWithin as $cIPI0$useFocusWithin, usePress as $cIPI0$usePress} from "@react-aria/interactions";
7
+ import {toCalendar as $cIPI0$toCalendar, CalendarDate as $cIPI0$CalendarDate} from "@internationalized/date";
7
8
  import {NumberParser as $cIPI0$NumberParser} from "@internationalized/number";
8
9
  import {useSpinButton as $cIPI0$useSpinButton} from "@react-aria/spinbutton";
9
10
  import {MessageDictionary as $cIPI0$MessageDictionary} from "@internationalized/message";
@@ -248,9 +249,9 @@ function $3dfb0f96be0d6a08$export$4a931266a3838b86(state, ref1, disableArrowNavi
248
249
  }while (last)
249
250
  }
250
251
  // Now go backwards until we find an element that is not a placeholder.
251
- while(target === null || target === void 0 ? void 0 : target.getAttribute('aria-placeholder')){
252
+ while(target === null || target === void 0 ? void 0 : target.hasAttribute('data-placeholder')){
252
253
  let prev = walker.previousNode();
253
- if (prev && prev.getAttribute('aria-placeholder')) target = prev;
254
+ if (prev && prev.hasAttribute('data-placeholder')) target = prev;
254
255
  else break;
255
256
  }
256
257
  if (target) target.focus();
@@ -457,6 +458,7 @@ function $6057a3d2a53a12fd$export$42df105a73306d51(props, state, ref) {
457
458
 
458
459
 
459
460
 
461
+
460
462
  function $3aeceb3a64eb8358$export$d42c60378c8168f8() {
461
463
  let { locale: locale } = $cIPI0$useLocale();
462
464
  return $cIPI0$useMemo(()=>{
@@ -491,7 +493,7 @@ function $32489daedd52963e$export$1315d136e6f7581(segment, state, ref) {
491
493
  let { locale: locale } = $cIPI0$useLocale();
492
494
  let displayNames = $3aeceb3a64eb8358$export$d42c60378c8168f8();
493
495
  let { ariaLabel: ariaLabel , ariaLabelledBy: ariaLabelledBy , ariaDescribedBy: ariaDescribedBy , focusManager: focusManager } = $16f0b7bb276bc17e$export$653eddfc964b0f8a.get(state);
494
- let textValue = segment.text;
496
+ let textValue = segment.isPlaceholder ? '' : segment.text;
495
497
  let options = $cIPI0$useMemo(()=>state.dateFormatter.resolvedOptions()
496
498
  , [
497
499
  state.dateFormatter
@@ -505,11 +507,14 @@ function $32489daedd52963e$export$1315d136e6f7581(segment, state, ref) {
505
507
  hour12: options.hour12,
506
508
  timeZone: options.timeZone
507
509
  });
508
- if (segment.type === 'month') {
510
+ if (segment.type === 'month' && !segment.isPlaceholder) {
509
511
  let monthTextValue = monthDateFormatter.format(state.dateValue);
510
512
  textValue = monthTextValue !== textValue ? `${textValue} – ${monthTextValue}` : monthTextValue;
511
- } else if (segment.type === 'hour') textValue = hourDateFormatter.format(state.dateValue);
513
+ } else if (segment.type === 'hour' && !segment.isPlaceholder) textValue = hourDateFormatter.format(state.dateValue);
512
514
  let { spinButtonProps: spinButtonProps } = $cIPI0$useSpinButton({
515
+ // The ARIA spec says aria-valuenow is optional if there's no value, but aXe seems to require it.
516
+ // This doesn't seem to have any negative effects with real AT since we also use aria-valuetext.
517
+ // https://github.com/dequelabs/axe-core/issues/3505
513
518
  value: segment.value,
514
519
  textValue: textValue,
515
520
  minValue: segment.minValue,
@@ -563,14 +568,6 @@ function $32489daedd52963e$export$1315d136e6f7581(segment, state, ref) {
563
568
  if (e.key === 'a' && ($cIPI0$isMac() ? e.metaKey : e.ctrlKey)) e.preventDefault();
564
569
  if (e.ctrlKey || e.metaKey || e.shiftKey || e.altKey) return;
565
570
  switch(e.key){
566
- case 'Enter':
567
- e.preventDefault();
568
- e.stopPropagation();
569
- if (segment.isPlaceholder && !state.isReadOnly) state.confirmPlaceholder(segment.type);
570
- focusManager.focusNext();
571
- break;
572
- case 'Tab':
573
- break;
574
571
  case 'Backspace':
575
572
  case 'Delete':
576
573
  // Safari on iOS does not fire beforeinput for the backspace key because the cursor is at the start.
@@ -604,6 +601,42 @@ function $32489daedd52963e$export$1315d136e6f7581(segment, state, ref) {
604
601
  }, [
605
602
  amPmFormatter
606
603
  ]);
604
+ // Get a list of formatted era names so users can type the first character to choose one.
605
+ let eraFormatter = $cIPI0$useDateFormatter({
606
+ year: 'numeric',
607
+ era: 'narrow',
608
+ timeZone: 'UTC'
609
+ });
610
+ let eras1 = $cIPI0$useMemo(()=>{
611
+ if (segment.type !== 'era') return [];
612
+ let date = $cIPI0$toCalendar(new $cIPI0$CalendarDate(1, 1, 1), state.calendar);
613
+ let eras = state.calendar.getEras().map((era)=>{
614
+ let eraDate = date.set({
615
+ year: 1,
616
+ month: 1,
617
+ day: 1,
618
+ era: era
619
+ }).toDate('UTC');
620
+ let parts = eraFormatter.formatToParts(eraDate);
621
+ let formatted = parts.find((p)=>p.type === 'era'
622
+ ).value;
623
+ return {
624
+ era: era,
625
+ formatted: formatted
626
+ };
627
+ });
628
+ // Remove the common prefix from formatted values. This is so that in calendars with eras like
629
+ // ERA0 and ERA1 (e.g. Ethiopic), users can press "0" and "1" to select an era. In other cases,
630
+ // the first letter is used.
631
+ let prefixLength = $32489daedd52963e$var$commonPrefixLength(eras.map((era)=>era.formatted
632
+ ));
633
+ if (prefixLength) for (let era1 of eras)era1.formatted = era1.formatted.slice(prefixLength);
634
+ return eras;
635
+ }, [
636
+ eraFormatter,
637
+ state.calendar,
638
+ segment.type
639
+ ]);
607
640
  let onInput = (key)=>{
608
641
  if (state.isDisabled || state.isReadOnly) return;
609
642
  let newValue = enteredKeys.current + key;
@@ -614,6 +647,16 @@ function $32489daedd52963e$export$1315d136e6f7581(segment, state, ref) {
614
647
  else break;
615
648
  focusManager.focusNext();
616
649
  break;
650
+ case 'era':
651
+ {
652
+ let matched = eras1.find((e)=>startsWith(e.formatted, key)
653
+ );
654
+ if (matched) {
655
+ state.setSegment('era', matched.era);
656
+ focusManager.focusNext();
657
+ }
658
+ break;
659
+ }
617
660
  case 'day':
618
661
  case 'hour':
619
662
  case 'minute':
@@ -651,14 +694,9 @@ function $32489daedd52963e$export$1315d136e6f7581(segment, state, ref) {
651
694
  let onFocus = ()=>{
652
695
  enteredKeys.current = '';
653
696
  $cIPI0$scrollIntoView($cIPI0$getScrollParent(ref.current), ref.current);
654
- // Safari requires that a selection is set or it won't fire input events.
655
- // Since usePress disables text selection, this won't happen by default.
656
- ref.current.style.webkitUserSelect = 'text';
657
- ref.current.style.userSelect = 'text';
697
+ // Collapse selection to start or Chrome won't fire input events.
658
698
  let selection = window.getSelection();
659
699
  selection.collapse(ref.current);
660
- ref.current.style.webkitUserSelect = 'none';
661
- ref.current.style.userSelect = 'none';
662
700
  };
663
701
  let compositionRef = $cIPI0$useRef('');
664
702
  // @ts-ignore - TODO: possibly old TS version? doesn't fail in my editor...
@@ -694,10 +732,19 @@ function $32489daedd52963e$export$1315d136e6f7581(segment, state, ref) {
694
732
  break;
695
733
  }
696
734
  });
697
- // For Android: prevent selection on long press.
698
- $cIPI0$useEvent(ref, 'selectstart', (e)=>{
699
- e.preventDefault();
700
- });
735
+ $cIPI0$useLayoutEffect(()=>{
736
+ let element = ref.current;
737
+ return ()=>{
738
+ // If the focused segment is removed, focus the previous one, or the next one if there was no previous one.
739
+ if (document.activeElement === element) {
740
+ let prev = focusManager.focusPrevious();
741
+ if (!prev) focusManager.focusNext();
742
+ }
743
+ };
744
+ }, [
745
+ ref,
746
+ focusManager
747
+ ]);
701
748
  // spinbuttons cannot be focused with VoiceOver on iOS.
702
749
  let touchPropOverrides = $cIPI0$isIOS() || segment.type === 'timeZoneName' ? {
703
750
  role: 'textbox',
@@ -737,8 +784,8 @@ function $32489daedd52963e$export$1315d136e6f7581(segment, state, ref) {
737
784
  ...touchPropOverrides,
738
785
  'aria-invalid': state.validationState === 'invalid' ? 'true' : undefined,
739
786
  'aria-describedby': ariaDescribedBy,
740
- 'aria-placeholder': segment.isPlaceholder ? segment.text : undefined,
741
787
  'aria-readonly': state.isReadOnly || !segment.isEditable ? 'true' : undefined,
788
+ 'data-placeholder': segment.isPlaceholder || undefined,
742
789
  contentEditable: isEditable,
743
790
  suppressContentEditableWarning: isEditable,
744
791
  spellCheck: isEditable ? 'false' : undefined,
@@ -746,14 +793,12 @@ function $32489daedd52963e$export$1315d136e6f7581(segment, state, ref) {
746
793
  autoCorrect: isEditable ? 'off' : undefined,
747
794
  // Capitalization was changed in React 17...
748
795
  [parseInt($cIPI0$react.version, 10) >= 17 ? 'enterKeyHint' : 'enterkeyhint']: isEditable ? 'next' : undefined,
749
- inputMode: state.isDisabled || segment.type === 'dayPeriod' || !isEditable ? undefined : 'numeric',
796
+ inputMode: state.isDisabled || segment.type === 'dayPeriod' || segment.type === 'era' || !isEditable ? undefined : 'numeric',
750
797
  tabIndex: state.isDisabled ? undefined : 0,
751
798
  onKeyDown: onKeyDown,
752
799
  onFocus: onFocus,
753
800
  style: {
754
- caretColor: 'transparent',
755
- userSelect: 'none',
756
- WebkitUserSelect: 'none'
801
+ caretColor: 'transparent'
757
802
  },
758
803
  // Prevent pointer events from reaching useDatePickerGroup, and allow native browser behavior to focus the segment.
759
804
  onPointerDown (e) {
@@ -765,7 +810,16 @@ function $32489daedd52963e$export$1315d136e6f7581(segment, state, ref) {
765
810
  })
766
811
  };
767
812
  }
768
-
813
+ function $32489daedd52963e$var$commonPrefixLength(strings) {
814
+ // Sort the strings, and compare the characters in the first and last to find the common prefix.
815
+ strings.sort();
816
+ let first = strings[0];
817
+ let last = strings[strings.length - 1];
818
+ for(let i = 0; i < first.length; i++){
819
+ if (first[i] !== last[i]) return i;
820
+ }
821
+ return 0;
822
+ }
769
823
 
770
824
 
771
825
 
@@ -805,11 +859,6 @@ function $887cac91b7cc8801$export$12fd5f0e9f4bb192(props, state, ref) {
805
859
  let buttonId = $cIPI0$useId();
806
860
  let dialogId = $cIPI0$useId();
807
861
  let groupProps = $3dfb0f96be0d6a08$export$4a931266a3838b86(state, ref);
808
- let { focusWithinProps: focusWithinProps } = $cIPI0$useFocusWithin({
809
- onBlurWithin () {
810
- state.confirmPlaceholder();
811
- }
812
- });
813
862
  let ariaDescribedBy = [
814
863
  descProps['aria-describedby'],
815
864
  fieldProps['aria-describedby']
@@ -839,7 +888,7 @@ function $887cac91b7cc8801$export$12fd5f0e9f4bb192(props, state, ref) {
839
888
  };
840
889
  let domProps = $cIPI0$filterDOMProps(props);
841
890
  return {
842
- groupProps: $cIPI0$mergeProps(domProps, groupProps, fieldProps, descProps, focusWithinProps, {
891
+ groupProps: $cIPI0$mergeProps(domProps, groupProps, fieldProps, descProps, {
843
892
  role: 'group',
844
893
  'aria-disabled': props.isDisabled || null,
845
894
  'aria-describedby': ariaDescribedBy