@box/blueprint-web 6.15.1 → 6.15.3

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.
@@ -100,14 +100,7 @@ const RootInner = ({
100
100
  }
101
101
  return getSelectedOptionValues(valueProp);
102
102
  }, [getSelectedOptionValues, valueProp]);
103
- const focusInput = useCallback(() => {
104
- inputRef.current?.focus();
105
- }, []);
106
103
  const setValue = newSelectedValue => {
107
- // Move focus back to input for single selects
108
- if (!Array.isArray(newSelectedValue)) {
109
- focusInput();
110
- }
111
104
  if (!onValueChange) {
112
105
  return;
113
106
  }
@@ -148,6 +141,9 @@ const RootInner = ({
148
141
  },
149
142
  // eslint-disable-next-line react-hooks/exhaustive-deps
150
143
  [displayAvatar]);
144
+ const focusInput = useCallback(() => {
145
+ inputRef.current?.focus();
146
+ }, []);
151
147
  const renderSelectItemOption = useCallback(option => {
152
148
  const value = getOptionValue(option);
153
149
  return jsxs(OptionWithIndicator, {
@@ -166,8 +162,10 @@ const RootInner = ({
166
162
  setInputValue('');
167
163
  } else if (selectedValueMemoized) {
168
164
  setInputValue(getDisplayValueFromOptionValue(selectedValueMemoized));
165
+ // Also focus input for single-select variant
166
+ focusInput();
169
167
  }
170
- }, [selectedValueMemoized, getDisplayValueFromOptionValue, setInputValue]);
168
+ }, [selectedValueMemoized, getDisplayValueFromOptionValue, setInputValue, focusInput]);
171
169
  const handleKeyDown = useCallback(event => {
172
170
  // Close menu
173
171
  if (event.key === 'Enter' || event.key === 'Tab') {
@@ -3,10 +3,56 @@ import { ChevronLeft, ChevronRight } from '@box/blueprint-web-assets/icons/Fill'
3
3
  import { Gray65 } from '@box/blueprint-web-assets/tokens/tokens';
4
4
  import { isSameDay, today, getLocalTimeZone } from '@internationalized/date';
5
5
  import { clsx } from 'clsx';
6
- import { forwardRef } from 'react';
6
+ import { forwardRef, useRef, useEffect } from 'react';
7
7
  import { Calendar as Calendar$1, Button, Heading, CalendarGrid, CalendarGridHeader, CalendarHeaderCell, CalendarGridBody, CalendarCell } from 'react-aria-components';
8
8
  import styles from './calendar.module.js';
9
9
 
10
+ // Dispatch duplicated event with bubbling enabled, so Radix popover knows that this click happened.
11
+ const handlePointerDownInCell = e => {
12
+ const newEvent = new PointerEvent('pointerdown', {
13
+ ...e,
14
+ bubbles: true
15
+ });
16
+ // Dispatch event on the parent to avoid infinite loop
17
+ e.currentTarget.parentElement?.dispatchEvent(newEvent);
18
+ };
19
+ /**
20
+ * Custom calendar cell that adds a pointerdown event listener to the CalendarCell.
21
+ * This fixes DSYS-872 issue, where it takes 2 clicks to close the popover.
22
+ */
23
+ const CustomCalendarCell = ({
24
+ date,
25
+ className
26
+ }) => {
27
+ const calendarCellRef = useRef(null);
28
+ useEffect(() => {
29
+ const calendarCell = calendarCellRef.current;
30
+ const shouldModifyEventListener = calendarCell && !calendarCell.ariaDisabled;
31
+ if (shouldModifyEventListener) {
32
+ // Attach the listener to the `div` with `role=button` instead of `td`, since we don't want the event to be triggered when clicking on td's padding.
33
+ calendarCell.firstElementChild?.addEventListener('pointerdown', handlePointerDownInCell);
34
+ }
35
+ return () => {
36
+ if (shouldModifyEventListener) {
37
+ calendarCell.firstElementChild?.removeEventListener('pointerdown', handlePointerDownInCell);
38
+ }
39
+ };
40
+ }, []);
41
+ return jsx(CalendarCell, {
42
+ ref: calendarCellRef,
43
+ className: className,
44
+ date: date,
45
+ children: ({
46
+ formattedDate
47
+ }) => jsx("span", {
48
+ children: formattedDate
49
+ })
50
+ });
51
+ };
52
+ // Ensure clicking on the header button triggers Radix onPointerDown event handler to close the popover with single click.
53
+ function continuePropagation(e) {
54
+ e.continuePropagation();
55
+ }
10
56
  const Calendar = /*#__PURE__*/forwardRef((props, forwardedRef) => {
11
57
  const {
12
58
  className,
@@ -25,6 +71,7 @@ const Calendar = /*#__PURE__*/forwardRef((props, forwardedRef) => {
25
71
  children: [jsx(Button, {
26
72
  "aria-label": previousMonthAriaLabel,
27
73
  className: styles.calendarHeaderButton,
74
+ onPressStart: continuePropagation,
28
75
  slot: "previous",
29
76
  children: jsx(ChevronLeft, {
30
77
  "aria-label": previousMonthAriaLabel,
@@ -35,6 +82,7 @@ const Calendar = /*#__PURE__*/forwardRef((props, forwardedRef) => {
35
82
  }), jsx(Button, {
36
83
  "aria-label": nextMonthAriaLabel,
37
84
  className: styles.calendarHeaderButton,
85
+ onPressStart: continuePropagation,
38
86
  slot: "next",
39
87
  children: jsx(ChevronRight, {
40
88
  "aria-label": nextMonthAriaLabel,
@@ -49,16 +97,11 @@ const Calendar = /*#__PURE__*/forwardRef((props, forwardedRef) => {
49
97
  children: day
50
98
  })
51
99
  }), jsx(CalendarGridBody, {
52
- children: date => jsx(CalendarCell, {
100
+ children: date => jsx(CustomCalendarCell, {
53
101
  className: clsx(styles.calendarCell, {
54
102
  [styles.today]: isSameDay(date, today(getLocalTimeZone()))
55
103
  }),
56
- date: date,
57
- children: ({
58
- formattedDate
59
- }) => jsx("span", {
60
- children: formattedDate
61
- })
104
+ date: date
62
105
  })
63
106
  })]
64
107
  })]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@box/blueprint-web",
3
- "version": "6.15.1",
3
+ "version": "6.15.3",
4
4
  "license": "SEE LICENSE IN LICENSE",
5
5
  "publishConfig": {
6
6
  "access": "public",
@@ -57,7 +57,7 @@
57
57
  "devDependencies": {
58
58
  "@box/storybook-utils": "^0.0.3"
59
59
  },
60
- "gitHead": "1f7ff1dd54e90dd51c1766a4c51ee7da2fd39552",
60
+ "gitHead": "dfb4022d75a7c0fc43d599749ce92d61aa576254",
61
61
  "module": "lib-esm/index.js",
62
62
  "main": "lib-esm/index.js",
63
63
  "exports": {