@indico-data/design-system 1.0.53 → 1.0.54

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@indico-data/design-system",
3
- "version": "1.0.53",
3
+ "version": "1.0.54",
4
4
  "description": "",
5
5
  "author": "",
6
6
  "main": "lib/index.js",
@@ -20,6 +20,7 @@ type Props = PermafrostComponent & {
20
20
  size?: [string | number] | [string | number, string | number];
21
21
  style?: any;
22
22
  onClick?(): void;
23
+ ref?: React.Ref<SVGSVGElement>;
23
24
  };
24
25
 
25
26
  type IconComponentProps = {
@@ -53,6 +54,7 @@ export function Icon({ style = {}, ...props }: Props): React.ReactElement | null
53
54
  {...iconComponentProps}
54
55
  {...ariaLabel}
55
56
  {...dimensions}
57
+ ref={props.ref}
56
58
  role="img"
57
59
  className={props.className}
58
60
  data-cy={props['data-cy']}
@@ -29,6 +29,7 @@ export const Single: Story = {
29
29
  value: today,
30
30
  triggerIcon: 'calendar',
31
31
  triggerIconSize: [20],
32
+ clearOnClose: true,
32
33
  onChange: (date: Date | DateRange | undefined) => {
33
34
  // eslint-disable-next-line no-console
34
35
  console.log(date);
@@ -1,5 +1,5 @@
1
1
  // TODO: This component's migration was fast-tracked for Insights. Assess for potential refactor and documentation.
2
- import React, { useEffect, useRef, useState } from 'react';
2
+ import React, { useEffect, useLayoutEffect, useRef, useState } from 'react';
3
3
  import { format } from 'date-fns';
4
4
  import FocusTrap from 'focus-trap-react';
5
5
  import {
@@ -25,21 +25,29 @@ type Props = PermafrostComponent & {
25
25
  label?: string;
26
26
  onChange: (value: Date | DateRange | undefined) => void;
27
27
  selected?: Date | undefined;
28
+ selectedRange?: DateRange | undefined;
28
29
  value: Date | undefined;
29
30
  triggerIcon: IconName;
30
31
  triggerIconSize: [string | number];
31
32
  isRangePicker?: boolean;
32
33
  isOpen?: boolean;
34
+ clearOnClose?: boolean;
33
35
  };
34
36
 
35
37
  function CustomCaption(props: CaptionProps) {
36
38
  const { goToMonth, nextMonth, previousMonth } = useNavigation();
39
+
37
40
  return (
38
41
  <div className="custom__caption">
39
42
  <button
40
43
  className="custom__caption__action__button"
41
44
  disabled={!previousMonth}
42
- onClick={() => previousMonth && goToMonth(previousMonth)}
45
+ onClick={(event) => {
46
+ event.preventDefault();
47
+ if (previousMonth) {
48
+ goToMonth(previousMonth);
49
+ }
50
+ }}
43
51
  >
44
52
  <Icon size={[10]} ariaLabel="Previous Month" name="chevron-left" />
45
53
  </button>
@@ -47,7 +55,12 @@ function CustomCaption(props: CaptionProps) {
47
55
  <button
48
56
  className="custom__caption__action__button"
49
57
  disabled={!nextMonth}
50
- onClick={() => nextMonth && goToMonth(nextMonth)}
58
+ onClick={(event) => {
59
+ event.preventDefault();
60
+ if (nextMonth) {
61
+ goToMonth(nextMonth);
62
+ }
63
+ }}
51
64
  >
52
65
  <Icon size={[10]} ariaLabel="Next Month" name="chevron-right" />
53
66
  </button>
@@ -68,11 +81,15 @@ export const NoInputDatePicker = (props: Props) => {
68
81
  triggerIcon,
69
82
  triggerIconSize,
70
83
  isRangePicker,
84
+ selectedRange,
71
85
  isOpen,
86
+ clearOnClose,
72
87
  } = props;
73
88
 
74
89
  const [localSelected, setLocalSelected] = useState<Date | undefined>(selected || undefined);
75
- const [range, setRange] = useState<DateRange | undefined>(undefined);
90
+ const [localSelectedRange, setLocalSelectedRange] = useState<DateRange | undefined>(
91
+ selectedRange || undefined,
92
+ );
76
93
  const [isPopperOpen, setIsPopperOpen] = useState(isOpen || false);
77
94
  const [popperElement, setPopperElement] = useState<HTMLDivElement | null>(null);
78
95
  const popperRef = useRef<HTMLDivElement>(null);
@@ -90,17 +107,40 @@ export const NoInputDatePicker = (props: Props) => {
90
107
 
91
108
  const [isTrapActive, setIsTrapActive] = useState(false);
92
109
 
110
+ const datePickerRef = useRef<HTMLDivElement | null>(null);
111
+
112
+ // Addresses clickout side bug when implementing in an application
93
113
  useEffect(() => {
114
+ const handleClickOutside = (event: MouseEvent) => {
115
+ // Close the date picker only when clicked outside
116
+ if (
117
+ datePickerRef.current &&
118
+ event.target instanceof Node &&
119
+ !datePickerRef.current.contains(event.target)
120
+ ) {
121
+ closePopper();
122
+ }
123
+ };
124
+
125
+ document.addEventListener('mousedown', handleClickOutside);
126
+ return () => {
127
+ document.removeEventListener('mousedown', handleClickOutside);
128
+ };
129
+ }, []);
130
+
131
+ // Allow datepicker to load before setting active trap
132
+ useLayoutEffect(() => {
94
133
  if (isOpen) {
95
- // Delay the activation of the FocusTrap to allow the DayPicker to render
96
- const timeoutId = setTimeout(() => setIsTrapActive(true), 0);
97
- return () => clearTimeout(timeoutId);
134
+ setIsTrapActive(true);
98
135
  } else {
99
136
  setIsTrapActive(false);
100
137
  }
101
138
  }, [isOpen]);
102
139
 
103
140
  const closePopper = () => {
141
+ clearOnClose && setLocalSelected(undefined);
142
+ clearOnClose && setLocalSelectedRange(undefined);
143
+
104
144
  setIsPopperOpen(false);
105
145
  };
106
146
 
@@ -115,7 +155,7 @@ export const NoInputDatePicker = (props: Props) => {
115
155
  };
116
156
 
117
157
  const handleRangeSelect: SelectRangeEventHandler = (range: DateRange | undefined) => {
118
- setRange(range);
158
+ setLocalSelectedRange(range);
119
159
  if (range?.from && range?.to) {
120
160
  onChange(range);
121
161
  closePopper();
@@ -131,6 +171,7 @@ export const NoInputDatePicker = (props: Props) => {
131
171
  data-cy={props['data-cy']}
132
172
  data-testid={props['data-testid']}
133
173
  id={id}
174
+ ref={datePickerRef}
134
175
  >
135
176
  {label ? (
136
177
  <div id={`picker-label--${id}`} className="visually-hidden">
@@ -155,6 +196,7 @@ export const NoInputDatePicker = (props: Props) => {
155
196
  allowOutsideClick: true,
156
197
  clickOutsideDeactivates: true,
157
198
  onDeactivate: closePopper,
199
+ fallbackFocus: popperRef.current || undefined,
158
200
  }}
159
201
  >
160
202
  <div
@@ -175,7 +217,7 @@ export const NoInputDatePicker = (props: Props) => {
175
217
  disabled={disabled}
176
218
  mode={'range'}
177
219
  defaultMonth={localSelected}
178
- selected={range}
220
+ selected={localSelectedRange}
179
221
  onSelect={handleRangeSelect}
180
222
  fromDate={disableBeforeDate}
181
223
  toDate={disableAfterDate}