@primer/react 38.34.0-rc.f86dc8614 → 38.34.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/CHANGELOG.md +6 -0
- package/dist/ActionList/Group.js +1 -1
- package/dist/ActionList/List.js +20 -14
- package/dist/AnchoredOverlay/AnchoredOverlay.js +6 -3
- package/dist/Autocomplete/AutocompleteInput.js +10 -7
- package/dist/ButtonGroup/ButtonGroup.js +15 -8
- package/dist/Checkbox/Checkbox.js +16 -9
- package/dist/Dialog/Dialog.js +12 -5
- package/dist/FeatureFlags/DefaultFeatureFlags.js +2 -1
- package/dist/FilteredActionList/FilteredActionList.js +31 -20
- package/dist/FilteredActionList/FilteredActionListInput.d.ts +1 -1
- package/dist/Link/Link.js +33 -33
- package/dist/Overlay/Overlay.js +1 -1
- package/dist/PageHeader/PageHeader.js +30 -21
- package/dist/SegmentedControl/{SegmentedControl-a004561f.css → SegmentedControl-de65527b.css} +2 -2
- package/dist/SegmentedControl/{SegmentedControl-a004561f.css.map → SegmentedControl-de65527b.css.map} +1 -1
- package/dist/SegmentedControl/SegmentedControl.module.css.js +1 -1
- package/dist/SegmentedControl/SegmentedControlButton.js +1 -1
- package/dist/SegmentedControl/SegmentedControlIconButton.js +1 -1
- package/dist/SelectPanel/SelectPanel.js +1 -1
- package/dist/TextInput/TextInput.js +13 -6
- package/dist/TooltipV2/Tooltip.js +18 -11
- package/dist/experimental/Tabs/Tabs.js +3 -2
- package/dist/experimental/Tabs/types.d.ts +10 -3
- package/dist/experimental/Tabs/useTabList.js +18 -10
- package/dist/experimental/UnderlinePanels/UnderlinePanels.js +69 -42
- package/dist/experimental/index.js +5 -5
- package/dist/hooks/useMergedRefs.d.ts +4 -4
- package/dist/hooks/useMergedRefs.js +8 -5
- package/dist/hooks/useProvidedRefOrCreate.d.ts +7 -10
- package/dist/hooks/useProvidedRefOrCreate.js +7 -10
- package/package.json +1 -2
package/CHANGELOG.md
CHANGED
|
@@ -8,8 +8,14 @@
|
|
|
8
8
|
|
|
9
9
|
### Patch Changes
|
|
10
10
|
|
|
11
|
+
- [#8211](https://github.com/primer/react/pull/8211) [`a3e669f`](https://github.com/primer/react/commit/a3e669fa551a7d07841ce20224199d172905860f) Thanks [@francinelucca](https://github.com/francinelucca)! - Link: Remove unnecessary `data-hover-color` attribute from rendered DOM element
|
|
12
|
+
|
|
13
|
+
- [#8196](https://github.com/primer/react/pull/8196) [`e24effd`](https://github.com/primer/react/commit/e24effd440d69f0068a89aba26bae9e39fb3254e) Thanks [@liuliu-dev](https://github.com/liuliu-dev)! - Use `aria-pressed` instead of `aria-current` on `SegmentedControl.Button` and `SegmentedControl.IconButton` so JAWS announces the selected state when a segment is activated.
|
|
14
|
+
|
|
11
15
|
- [#8169](https://github.com/primer/react/pull/8169) [`1d6f559`](https://github.com/primer/react/commit/1d6f5593f5e482d1d03027522bc882560c7b1f06) Thanks [@liuliu-dev](https://github.com/liuliu-dev)! - Timeline: `Timeline.Actions` now wraps onto a new row below `Timeline.Body`, left-aligned with the body content, when `Timeline.Item` is narrower than 480px.
|
|
12
16
|
|
|
17
|
+
- [#8214](https://github.com/primer/react/pull/8214) [`41705f4`](https://github.com/primer/react/commit/41705f430ce0f64eb61c2665313f36a88cf6f16c) Thanks [@rickyzhangca](https://github.com/rickyzhangca)! - UnderlinePanels: The experimental `UnderlinePanels` component is now built on the experimental `Tabs` component instead of `@github/tab-container-element`. Its public API and behavior are unchanged.
|
|
18
|
+
|
|
13
19
|
## 38.33.0
|
|
14
20
|
|
|
15
21
|
### Minor Changes
|
package/dist/ActionList/Group.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { useId as useId$1 } from "../hooks/useId.js";
|
|
2
2
|
import { useSlots } from "../hooks/useSlots.js";
|
|
3
|
+
import { useFeatureFlag } from "../FeatureFlags/useFeatureFlag.js";
|
|
3
4
|
import { invariant } from "../utils/invariant.js";
|
|
4
5
|
import { ListContext } from "./shared.js";
|
|
5
6
|
import ActionList_module_css_default from "./ActionList.module.css.js";
|
|
6
|
-
import { useFeatureFlag } from "../FeatureFlags/useFeatureFlag.js";
|
|
7
7
|
import Group_module_css_default from "./Group.module.css.js";
|
|
8
8
|
import { GroupHeadingTrailingAction } from "./GroupHeadingTrailingAction.js";
|
|
9
9
|
import { GroupContext } from "./GroupContext.js";
|
package/dist/ActionList/List.js
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
|
+
import { useMergedRefs } from "../hooks/useMergedRefs.js";
|
|
1
2
|
import { useProvidedRefOrCreate } from "../hooks/useProvidedRefOrCreate.js";
|
|
2
3
|
import useIsomorphicLayoutEffect from "../utils/useIsomorphicLayoutEffect.js";
|
|
3
4
|
import { useId as useId$1 } from "../hooks/useId.js";
|
|
4
5
|
import { useSlots } from "../hooks/useSlots.js";
|
|
6
|
+
import { useFeatureFlag } from "../FeatureFlags/useFeatureFlag.js";
|
|
5
7
|
import { fixedForwardRef } from "../utils/modern-polymorphic.js";
|
|
6
8
|
import { FocusKeys, useFocusZone } from "../hooks/useFocusZone.js";
|
|
7
9
|
import { ActionListContainerContext } from "./ActionListContainerContext.js";
|
|
8
10
|
import { ListContext } from "./shared.js";
|
|
9
11
|
import { Heading } from "./Heading.js";
|
|
10
12
|
import ActionList_module_css_default from "./ActionList.module.css.js";
|
|
11
|
-
import { useFeatureFlag } from "../FeatureFlags/useFeatureFlag.js";
|
|
12
13
|
import { c } from "react-compiler-runtime";
|
|
13
14
|
import { clsx } from "clsx";
|
|
14
15
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
15
|
-
import React from "react";
|
|
16
|
+
import React, { useRef } from "react";
|
|
16
17
|
//#region src/ActionList/List.tsx
|
|
17
18
|
const UnwrappedList = (props, forwardedRef) => {
|
|
18
19
|
var _slots$heading$props$;
|
|
@@ -60,7 +61,12 @@ const UnwrappedList = (props, forwardedRef) => {
|
|
|
60
61
|
const { listRole: listRoleFromContainer, listLabelledBy, selectionVariant: containerSelectionVariant, enableFocusZone: enableFocusZoneFromContainer, container } = React.useContext(ActionListContainerContext);
|
|
61
62
|
const ariaLabelledBy = slots.heading ? (_slots$heading$props$ = slots.heading.props.id) !== null && _slots$heading$props$ !== void 0 ? _slots$heading$props$ : headingId : listLabelledBy;
|
|
62
63
|
const listRole = role || listRoleFromContainer;
|
|
63
|
-
const
|
|
64
|
+
const mergedRefEnabled = useFeatureFlag("primer_react_merged_forwarded_refs");
|
|
65
|
+
const listRef = useRef(null);
|
|
66
|
+
const mergedRef = useMergedRefs(listRef, forwardedRef);
|
|
67
|
+
const providedOrCreatedRef = useProvidedRefOrCreate(forwardedRef);
|
|
68
|
+
const readRef = mergedRefEnabled ? listRef : providedOrCreatedRef;
|
|
69
|
+
const appliedRef = mergedRefEnabled ? mergedRef : providedOrCreatedRef;
|
|
64
70
|
const itemGapEnabled = useFeatureFlag("primer_react_action_list_item_gap") && container === "NavList";
|
|
65
71
|
let enableFocusZone = false;
|
|
66
72
|
if (enableFocusZoneFromContainer !== void 0) enableFocusZone = enableFocusZoneFromContainer;
|
|
@@ -79,14 +85,14 @@ const UnwrappedList = (props, forwardedRef) => {
|
|
|
79
85
|
const t5 = !enableFocusZone;
|
|
80
86
|
const t6 = listRole === "menu" || container === "SelectPanel" || container === "FilteredActionList" ? "wrap" : void 0;
|
|
81
87
|
let t7;
|
|
82
|
-
if ($[11] !==
|
|
88
|
+
if ($[11] !== readRef || $[12] !== t5 || $[13] !== t6) {
|
|
83
89
|
t7 = {
|
|
84
90
|
disabled: t5,
|
|
85
|
-
containerRef:
|
|
91
|
+
containerRef: readRef,
|
|
86
92
|
bindKeys: FocusKeys.ArrowVertical | FocusKeys.HomeAndEnd | FocusKeys.PageUpDown,
|
|
87
93
|
focusOutBehavior: t6
|
|
88
94
|
};
|
|
89
|
-
$[11] =
|
|
95
|
+
$[11] = readRef;
|
|
90
96
|
$[12] = t5;
|
|
91
97
|
$[13] = t6;
|
|
92
98
|
$[14] = t7;
|
|
@@ -111,16 +117,16 @@ const UnwrappedList = (props, forwardedRef) => {
|
|
|
111
117
|
} else t9 = $[20];
|
|
112
118
|
const listContextValue = t9;
|
|
113
119
|
let t10;
|
|
114
|
-
if ($[21] !==
|
|
120
|
+
if ($[21] !== readRef.current) {
|
|
115
121
|
t10 = () => {
|
|
116
|
-
const list =
|
|
122
|
+
const list = readRef.current;
|
|
117
123
|
if (!list) return;
|
|
118
124
|
const hasMixed = list.querySelector("[data-has-description=\"true\"]") !== null && list.querySelector("[data-has-description=\"false\"]") !== null;
|
|
119
125
|
const current = list.getAttribute("data-mixed-descriptions");
|
|
120
126
|
if (hasMixed && current !== "true") list.setAttribute("data-mixed-descriptions", "true");
|
|
121
127
|
else if (!hasMixed && current !== null) list.removeAttribute("data-mixed-descriptions");
|
|
122
128
|
};
|
|
123
|
-
$[21] =
|
|
129
|
+
$[21] = readRef.current;
|
|
124
130
|
$[22] = t10;
|
|
125
131
|
} else t10 = $[22];
|
|
126
132
|
useIsomorphicLayoutEffect(t10);
|
|
@@ -133,12 +139,12 @@ const UnwrappedList = (props, forwardedRef) => {
|
|
|
133
139
|
} else t12 = $[24];
|
|
134
140
|
const t13 = itemGapEnabled ? "" : void 0;
|
|
135
141
|
let t14;
|
|
136
|
-
if ($[25] !== Component || $[26] !==
|
|
142
|
+
if ($[25] !== Component || $[26] !== appliedRef || $[27] !== ariaLabelledBy || $[28] !== childrenWithoutSlots || $[29] !== listRole || $[30] !== restProps || $[31] !== showDividers || $[32] !== t12 || $[33] !== t13 || $[34] !== variant) {
|
|
137
143
|
t14 = /*#__PURE__*/ jsx(Component, {
|
|
138
144
|
className: t12,
|
|
139
145
|
role: listRole,
|
|
140
146
|
"aria-labelledby": ariaLabelledBy,
|
|
141
|
-
ref:
|
|
147
|
+
ref: appliedRef,
|
|
142
148
|
"data-component": "ActionList",
|
|
143
149
|
"data-dividers": showDividers,
|
|
144
150
|
"data-variant": variant,
|
|
@@ -147,9 +153,9 @@ const UnwrappedList = (props, forwardedRef) => {
|
|
|
147
153
|
children: childrenWithoutSlots
|
|
148
154
|
});
|
|
149
155
|
$[25] = Component;
|
|
150
|
-
$[26] =
|
|
151
|
-
$[27] =
|
|
152
|
-
$[28] =
|
|
156
|
+
$[26] = appliedRef;
|
|
157
|
+
$[27] = ariaLabelledBy;
|
|
158
|
+
$[28] = childrenWithoutSlots;
|
|
153
159
|
$[29] = listRole;
|
|
154
160
|
$[30] = restProps;
|
|
155
161
|
$[31] = showDividers;
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { reactMajorVersion } from "../utils/environment.js";
|
|
2
|
+
import { useMergedRefs } from "../hooks/useMergedRefs.js";
|
|
2
3
|
import { useProvidedRefOrCreate } from "../hooks/useProvidedRefOrCreate.js";
|
|
3
4
|
import { useAnchoredPosition } from "../hooks/useAnchoredPosition.js";
|
|
4
5
|
import { useRenderForcingRef } from "../hooks/useRenderForcingRef.js";
|
|
5
6
|
import { useId as useId$1 } from "../hooks/useId.js";
|
|
7
|
+
import { useFeatureFlag } from "../FeatureFlags/useFeatureFlag.js";
|
|
6
8
|
import { IconButton } from "../Button/IconButton.js";
|
|
7
9
|
import { useFocusTrap } from "../hooks/useFocusTrap.js";
|
|
8
10
|
import { useFocusZone } from "../hooks/useFocusZone.js";
|
|
9
|
-
import { useFeatureFlag } from "../FeatureFlags/useFeatureFlag.js";
|
|
10
11
|
import Overlay from "../Overlay/Overlay.js";
|
|
11
12
|
import AnchoredOverlay_module_css_default from "./AnchoredOverlay.module.css.js";
|
|
12
13
|
import { widthMap } from "../Overlay/constants.js";
|
|
@@ -33,7 +34,9 @@ const AnchoredOverlay = ({ renderAnchor, anchorRef: externalAnchorRef, anchorId:
|
|
|
33
34
|
const [anchorElement, setAnchorElement] = useState(null);
|
|
34
35
|
if (anchorRef.current !== anchorElement) setAnchorElement(anchorRef.current);
|
|
35
36
|
const [overlayRef, updateOverlayRef] = useRenderForcingRef();
|
|
37
|
+
const mergedRefEnabled = useFeatureFlag("primer_react_merged_forwarded_refs");
|
|
36
38
|
const [overlayElement, setOverlayElement] = useState(null);
|
|
39
|
+
const mergedOverlayRef = useMergedRefs(updateOverlayRef, useMergedRefs(overlayProps === null || overlayProps === void 0 ? void 0 : overlayProps.ref, setOverlayElement));
|
|
37
40
|
const anchorId = useId$1(externalAnchorId);
|
|
38
41
|
const onClickOutside = useCallback(() => onClose === null || onClose === void 0 ? void 0 : onClose("click-outside"), [onClose]);
|
|
39
42
|
const onEscape = useCallback(() => onClose === null || onClose === void 0 ? void 0 : onClose("escape"), [onClose]);
|
|
@@ -190,10 +193,10 @@ const AnchoredOverlay = ({ renderAnchor, anchorRef: externalAnchorRef, anchorId:
|
|
|
190
193
|
...shouldRenderAsPopover ? { popover: "manual" } : {},
|
|
191
194
|
...restOverlayProps,
|
|
192
195
|
...shouldRenderAsPopover ? { id: popoverId } : {},
|
|
193
|
-
ref: (node) => {
|
|
196
|
+
ref: mergedRefEnabled ? mergedOverlayRef : (node) => {
|
|
197
|
+
setOverlayElement(node);
|
|
194
198
|
if (overlayProps !== null && overlayProps !== void 0 && overlayProps.ref) assignRef(overlayProps.ref, node);
|
|
195
199
|
updateOverlayRef(node);
|
|
196
|
-
setOverlayElement(node);
|
|
197
200
|
},
|
|
198
201
|
"data-anchor-position": cssAnchorPositioning,
|
|
199
202
|
"data-side": cssAnchorPositioning ? side : position === null || position === void 0 ? void 0 : position.anchorSide,
|
|
@@ -20,9 +20,11 @@ const AutocompleteInput = /*#__PURE__*/ React.forwardRef(({ as: Component = Text
|
|
|
20
20
|
if (openOnFocus) setShowMenu(true);
|
|
21
21
|
};
|
|
22
22
|
const handleInputBlur = useCallback((event) => {
|
|
23
|
-
onBlur
|
|
23
|
+
onBlur === null || onBlur === void 0 || onBlur(event);
|
|
24
24
|
safeSetTimeout(() => {
|
|
25
|
-
|
|
25
|
+
const nextFocusedElement = event.relatedTarget;
|
|
26
|
+
const menuElement = document.getElementById(`${id}-listbox`);
|
|
27
|
+
if (!nextFocusedElement || nextFocusedElement !== menuElement && !(menuElement !== null && menuElement !== void 0 && menuElement.contains(nextFocusedElement))) {
|
|
26
28
|
setShowMenu(false);
|
|
27
29
|
if (inputRef.current && autocompleteSuggestion && inputRef.current.value !== inputValue) inputRef.current.value = inputValue;
|
|
28
30
|
}
|
|
@@ -33,16 +35,17 @@ const AutocompleteInput = /*#__PURE__*/ React.forwardRef(({ as: Component = Text
|
|
|
33
35
|
inputRef,
|
|
34
36
|
safeSetTimeout,
|
|
35
37
|
autocompleteSuggestion,
|
|
36
|
-
inputValue
|
|
38
|
+
inputValue,
|
|
39
|
+
id
|
|
37
40
|
]);
|
|
38
41
|
const handleInputChange = (event) => {
|
|
39
|
-
onChange
|
|
42
|
+
onChange === null || onChange === void 0 || onChange(event);
|
|
40
43
|
setInputValue(event.currentTarget.value);
|
|
41
44
|
if (!showMenu) setShowMenu(true);
|
|
42
45
|
};
|
|
43
46
|
const handleInputKeyDown = useCallback((event) => {
|
|
44
47
|
var _inputRef$current;
|
|
45
|
-
onKeyDown
|
|
48
|
+
onKeyDown === null || onKeyDown === void 0 || onKeyDown(event);
|
|
46
49
|
if (event.key === "Backspace") setHighlightRemainingText(false);
|
|
47
50
|
if (event.key === "Escape" && (_inputRef$current = inputRef.current) !== null && _inputRef$current !== void 0 && _inputRef$current.value) {
|
|
48
51
|
setInputValue("");
|
|
@@ -58,11 +61,11 @@ const AutocompleteInput = /*#__PURE__*/ React.forwardRef(({ as: Component = Text
|
|
|
58
61
|
setShowMenu
|
|
59
62
|
]);
|
|
60
63
|
const handleInputKeyUp = useCallback((event) => {
|
|
61
|
-
onKeyUp
|
|
64
|
+
onKeyUp === null || onKeyUp === void 0 || onKeyUp(event);
|
|
62
65
|
if (event.key === "Backspace") setHighlightRemainingText(true);
|
|
63
66
|
}, [setHighlightRemainingText, onKeyUp]);
|
|
64
67
|
const onInputKeyPress = useCallback((event) => {
|
|
65
|
-
onKeyPress
|
|
68
|
+
onKeyPress === null || onKeyPress === void 0 || onKeyPress(event);
|
|
66
69
|
if (showMenu && event.key === "Enter" && activeDescendantRef.current) {
|
|
67
70
|
event.preventDefault();
|
|
68
71
|
event.nativeEvent.stopImmediatePropagation();
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
import { useMergedRefs } from "../hooks/useMergedRefs.js";
|
|
1
2
|
import { useProvidedRefOrCreate } from "../hooks/useProvidedRefOrCreate.js";
|
|
3
|
+
import { useFeatureFlag } from "../FeatureFlags/useFeatureFlag.js";
|
|
2
4
|
import { FocusKeys, useFocusZone } from "../hooks/useFocusZone.js";
|
|
3
5
|
import ButtonGroup_module_css_default from "./ButtonGroup.module.css.js";
|
|
4
6
|
import { c } from "react-compiler-runtime";
|
|
5
7
|
import { clsx } from "clsx";
|
|
6
8
|
import { jsx } from "react/jsx-runtime";
|
|
7
|
-
import React from "react";
|
|
9
|
+
import React, { useRef } from "react";
|
|
8
10
|
//#region src/ButtonGroup/ButtonGroup.tsx
|
|
9
11
|
const ButtonGroup = /*#__PURE__*/ React.forwardRef(function ButtonGroup(t0, forwardRef) {
|
|
10
12
|
const $ = c(20);
|
|
@@ -29,6 +31,12 @@ const ButtonGroup = /*#__PURE__*/ React.forwardRef(function ButtonGroup(t0, forw
|
|
|
29
31
|
t1 = $[5];
|
|
30
32
|
}
|
|
31
33
|
const BaseComponent = t1 === void 0 ? "div" : t1;
|
|
34
|
+
const mergedRefEnabled = useFeatureFlag("primer_react_merged_forwarded_refs");
|
|
35
|
+
const buttonRef = useRef(null);
|
|
36
|
+
const mergedRef = useMergedRefs(buttonRef, forwardRef);
|
|
37
|
+
const providedOrCreatedRef = useProvidedRefOrCreate(forwardRef);
|
|
38
|
+
const readRef = mergedRefEnabled ? buttonRef : providedOrCreatedRef;
|
|
39
|
+
const appliedRef = mergedRefEnabled ? mergedRef : providedOrCreatedRef;
|
|
32
40
|
let t2;
|
|
33
41
|
if ($[6] !== children) {
|
|
34
42
|
t2 = React.Children.map(children, _temp);
|
|
@@ -36,17 +44,16 @@ const ButtonGroup = /*#__PURE__*/ React.forwardRef(function ButtonGroup(t0, forw
|
|
|
36
44
|
$[7] = t2;
|
|
37
45
|
} else t2 = $[7];
|
|
38
46
|
const buttons = t2;
|
|
39
|
-
const buttonRef = useProvidedRefOrCreate(forwardRef);
|
|
40
47
|
const t3 = role !== "toolbar";
|
|
41
48
|
let t4;
|
|
42
|
-
if ($[8] !==
|
|
49
|
+
if ($[8] !== readRef || $[9] !== t3) {
|
|
43
50
|
t4 = {
|
|
44
|
-
containerRef:
|
|
51
|
+
containerRef: readRef,
|
|
45
52
|
disabled: t3,
|
|
46
53
|
bindKeys: FocusKeys.ArrowHorizontal,
|
|
47
54
|
focusOutBehavior: "wrap"
|
|
48
55
|
};
|
|
49
|
-
$[8] =
|
|
56
|
+
$[8] = readRef;
|
|
50
57
|
$[9] = t3;
|
|
51
58
|
$[10] = t4;
|
|
52
59
|
} else t4 = $[10];
|
|
@@ -58,9 +65,9 @@ const ButtonGroup = /*#__PURE__*/ React.forwardRef(function ButtonGroup(t0, forw
|
|
|
58
65
|
$[12] = t5;
|
|
59
66
|
} else t5 = $[12];
|
|
60
67
|
let t6;
|
|
61
|
-
if ($[13] !== BaseComponent || $[14] !==
|
|
68
|
+
if ($[13] !== BaseComponent || $[14] !== appliedRef || $[15] !== buttons || $[16] !== rest || $[17] !== role || $[18] !== t5) {
|
|
62
69
|
t6 = /*#__PURE__*/ jsx(BaseComponent, {
|
|
63
|
-
ref:
|
|
70
|
+
ref: appliedRef,
|
|
64
71
|
className: t5,
|
|
65
72
|
role,
|
|
66
73
|
...rest,
|
|
@@ -68,7 +75,7 @@ const ButtonGroup = /*#__PURE__*/ React.forwardRef(function ButtonGroup(t0, forw
|
|
|
68
75
|
children: buttons
|
|
69
76
|
});
|
|
70
77
|
$[13] = BaseComponent;
|
|
71
|
-
$[14] =
|
|
78
|
+
$[14] = appliedRef;
|
|
72
79
|
$[15] = buttons;
|
|
73
80
|
$[16] = rest;
|
|
74
81
|
$[17] = role;
|
|
@@ -1,30 +1,37 @@
|
|
|
1
|
+
import { useMergedRefs } from "../hooks/useMergedRefs.js";
|
|
1
2
|
import { useProvidedRefOrCreate } from "../hooks/useProvidedRefOrCreate.js";
|
|
2
3
|
import useIsomorphicLayoutEffect from "../utils/useIsomorphicLayoutEffect.js";
|
|
4
|
+
import { useFeatureFlag } from "../FeatureFlags/useFeatureFlag.js";
|
|
3
5
|
import shared_module_css_default from "./shared.module.css.js";
|
|
4
6
|
import { CheckboxGroupContext } from "../CheckboxGroup/CheckboxGroupContext.js";
|
|
5
7
|
import Checkbox_module_css_default from "./Checkbox.module.css.js";
|
|
6
8
|
import { clsx } from "clsx";
|
|
7
9
|
import { jsx } from "react/jsx-runtime";
|
|
8
|
-
import React, { useContext, useEffect } from "react";
|
|
10
|
+
import React, { useContext, useEffect, useRef } from "react";
|
|
9
11
|
//#region src/Checkbox/Checkbox.tsx
|
|
10
12
|
/**
|
|
11
13
|
* An accessible, native checkbox component
|
|
12
14
|
*/
|
|
13
15
|
const Checkbox = /*#__PURE__*/ React.forwardRef(({ checked, className, defaultChecked, indeterminate, disabled, onChange, required, validationStatus, value, ["data-component"]: dataComponent, ...rest }, ref) => {
|
|
14
|
-
const
|
|
16
|
+
const mergedRefEnabled = useFeatureFlag("primer_react_merged_forwarded_refs");
|
|
17
|
+
const checkboxRef = useRef(null);
|
|
18
|
+
const mergedRef = useMergedRefs(checkboxRef, ref);
|
|
19
|
+
const providedOrCreatedRef = useProvidedRefOrCreate(ref);
|
|
20
|
+
const readRef = mergedRefEnabled ? checkboxRef : providedOrCreatedRef;
|
|
21
|
+
const appliedRef = mergedRefEnabled ? mergedRef : providedOrCreatedRef;
|
|
15
22
|
const checkboxGroupContext = useContext(CheckboxGroupContext);
|
|
16
23
|
const handleOnChange = (e) => {
|
|
17
24
|
checkboxGroupContext.onChange && checkboxGroupContext.onChange(e);
|
|
18
25
|
onChange && onChange(e);
|
|
19
|
-
if (indeterminate &&
|
|
20
|
-
|
|
21
|
-
|
|
26
|
+
if (indeterminate && readRef.current) {
|
|
27
|
+
readRef.current.indeterminate = true;
|
|
28
|
+
readRef.current.setAttribute("aria-checked", "mixed");
|
|
22
29
|
}
|
|
23
30
|
};
|
|
24
31
|
const inputProps = {
|
|
25
32
|
type: "checkbox",
|
|
26
33
|
disabled,
|
|
27
|
-
ref:
|
|
34
|
+
ref: appliedRef,
|
|
28
35
|
checked: indeterminate ? false : checked,
|
|
29
36
|
defaultChecked,
|
|
30
37
|
required,
|
|
@@ -36,14 +43,14 @@ const Checkbox = /*#__PURE__*/ React.forwardRef(({ checked, className, defaultCh
|
|
|
36
43
|
...rest
|
|
37
44
|
};
|
|
38
45
|
useIsomorphicLayoutEffect(() => {
|
|
39
|
-
if (
|
|
46
|
+
if (readRef.current) readRef.current.indeterminate = indeterminate || false;
|
|
40
47
|
}, [
|
|
41
48
|
indeterminate,
|
|
42
49
|
checked,
|
|
43
|
-
|
|
50
|
+
readRef
|
|
44
51
|
]);
|
|
45
52
|
useEffect(() => {
|
|
46
|
-
const { current: checkbox } =
|
|
53
|
+
const { current: checkbox } = readRef;
|
|
47
54
|
if (!checkbox) return;
|
|
48
55
|
if (indeterminate) checkbox.setAttribute("aria-checked", "mixed");
|
|
49
56
|
else checkbox.setAttribute("aria-checked", checkbox.checked ? "true" : "false");
|
package/dist/Dialog/Dialog.js
CHANGED
|
@@ -4,6 +4,7 @@ import { useOnEscapePress } from "../hooks/useOnEscapePress.js";
|
|
|
4
4
|
import { useResizeObserver } from "../hooks/useResizeObserver.js";
|
|
5
5
|
import { useId as useId$1 } from "../hooks/useId.js";
|
|
6
6
|
import { useSlots } from "../hooks/useSlots.js";
|
|
7
|
+
import { useFeatureFlag } from "../FeatureFlags/useFeatureFlag.js";
|
|
7
8
|
import { IconButton } from "../Button/IconButton.js";
|
|
8
9
|
import { ButtonComponent } from "../Button/Button.js";
|
|
9
10
|
import { useFocusTrap } from "../hooks/useFocusTrap.js";
|
|
@@ -244,22 +245,28 @@ const Footer = /*#__PURE__*/ React.forwardRef(function Footer({ className, ...re
|
|
|
244
245
|
Footer.displayName = "Dialog.Footer";
|
|
245
246
|
const Buttons = ({ buttons }) => {
|
|
246
247
|
var _buttons$find;
|
|
247
|
-
const
|
|
248
|
+
const mergedRefEnabled = useFeatureFlag("primer_react_merged_forwarded_refs");
|
|
249
|
+
const providedButtonRef = (_buttons$find = buttons.find((button) => button.autoFocus)) === null || _buttons$find === void 0 ? void 0 : _buttons$find.ref;
|
|
250
|
+
const autoFocusRef = useRef(null);
|
|
251
|
+
const mergedRef = useMergedRefs(autoFocusRef, providedButtonRef);
|
|
252
|
+
const providedOrCreatedRef = useProvidedRefOrCreate(providedButtonRef);
|
|
253
|
+
const readRef = mergedRefEnabled ? autoFocusRef : providedOrCreatedRef;
|
|
254
|
+
const appliedRef = mergedRefEnabled ? mergedRef : providedOrCreatedRef;
|
|
248
255
|
let autoFocusCount = 0;
|
|
249
256
|
const [hasRendered, setHasRendered] = useState(0);
|
|
250
257
|
useEffect(() => {
|
|
251
258
|
if (hasRendered === 1) {
|
|
252
|
-
var
|
|
253
|
-
(
|
|
259
|
+
var _readRef$current;
|
|
260
|
+
(_readRef$current = readRef.current) === null || _readRef$current === void 0 || _readRef$current.focus();
|
|
254
261
|
} else setHasRendered(hasRendered + 1);
|
|
255
|
-
}, [
|
|
262
|
+
}, [readRef, hasRendered]);
|
|
256
263
|
return /*#__PURE__*/ jsx(Fragment, { children: buttons.map((dialogButtonProps, index) => {
|
|
257
264
|
const { content, buttonType = "default", autoFocus = false, ...buttonProps } = dialogButtonProps;
|
|
258
265
|
return /*#__PURE__*/ jsx(ButtonComponent, {
|
|
259
266
|
"data-component": "Dialog.FooterButton",
|
|
260
267
|
...buttonProps,
|
|
261
268
|
variant: buttonType === "normal" ? "default" : buttonType,
|
|
262
|
-
ref: autoFocus && autoFocusCount === 0 ? (autoFocusCount++,
|
|
269
|
+
ref: autoFocus && autoFocusCount === 0 ? (autoFocusCount++, appliedRef) : null,
|
|
263
270
|
children: content
|
|
264
271
|
}, index);
|
|
265
272
|
}) });
|
|
@@ -7,7 +7,8 @@ const DefaultFeatureFlags = FeatureFlagScope.create({
|
|
|
7
7
|
primer_react_styled_react_use_primer_theme_providers: false,
|
|
8
8
|
primer_react_action_list_group_heading_trailing_action: false,
|
|
9
9
|
primer_react_action_list_item_gap: false,
|
|
10
|
-
primer_react_timeline_list_semantics: false
|
|
10
|
+
primer_react_timeline_list_semantics: false,
|
|
11
|
+
primer_react_merged_forwarded_refs: false
|
|
11
12
|
});
|
|
12
13
|
//#endregion
|
|
13
14
|
export { DefaultFeatureFlags };
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import { useMergedRefs } from "../hooks/useMergedRefs.js";
|
|
1
2
|
import { VisuallyHidden } from "../VisuallyHidden/VisuallyHidden.js";
|
|
2
3
|
import { useProvidedRefOrCreate } from "../hooks/useProvidedRefOrCreate.js";
|
|
3
4
|
import { useProvidedStateOrCreate } from "../hooks/useProvidedStateOrCreate.js";
|
|
4
5
|
import { useId as useId$1 } from "../hooks/useId.js";
|
|
6
|
+
import { useFeatureFlag } from "../FeatureFlags/useFeatureFlag.js";
|
|
5
7
|
import { useFocusZone } from "../hooks/useFocusZone.js";
|
|
6
8
|
import { ActionListContainerContext } from "../ActionList/ActionListContainerContext.js";
|
|
7
9
|
import { ActionList } from "../ActionList/index.js";
|
|
@@ -34,8 +36,17 @@ function FilteredActionList({ loading = false, placeholderText, filterValue: ext
|
|
|
34
36
|
}, [onFilterChange, setInternalFilterValue]);
|
|
35
37
|
const inputAndListContainerRef = useRef(null);
|
|
36
38
|
const listRef = useRef(null);
|
|
37
|
-
const
|
|
38
|
-
const
|
|
39
|
+
const mergedRefEnabled = useFeatureFlag("primer_react_merged_forwarded_refs");
|
|
40
|
+
const scrollContainerRef = useRef(null);
|
|
41
|
+
const mergedScrollContainerRef = useMergedRefs(scrollContainerRef, providedScrollContainerRef);
|
|
42
|
+
const providedOrCreatedScrollContainerRef = useProvidedRefOrCreate(providedScrollContainerRef);
|
|
43
|
+
const readScrollContainerRef = mergedRefEnabled ? scrollContainerRef : providedOrCreatedScrollContainerRef;
|
|
44
|
+
const appliedScrollContainerRef = mergedRefEnabled ? mergedScrollContainerRef : providedOrCreatedScrollContainerRef;
|
|
45
|
+
const inputRef = useRef(null);
|
|
46
|
+
const mergedInputRef = useMergedRefs(inputRef, providedInputRef);
|
|
47
|
+
const providedOrCreatedInputRef = useProvidedRefOrCreate(providedInputRef);
|
|
48
|
+
const readInputRef = mergedRefEnabled ? inputRef : providedOrCreatedInputRef;
|
|
49
|
+
const appliedInputRef = mergedRefEnabled ? mergedInputRef : providedOrCreatedInputRef;
|
|
39
50
|
const usingRovingTabindex = _PrivateFocusManagement === "roving-tabindex";
|
|
40
51
|
const [listContainerElement, setListContainerElement] = useState(null);
|
|
41
52
|
const activeDescendantRef = useRef();
|
|
@@ -89,12 +100,12 @@ function FilteredActionList({ loading = false, placeholderText, filterValue: ext
|
|
|
89
100
|
onListContainerRefChanged === null || onListContainerRefChanged === void 0 || onListContainerRefChanged(node);
|
|
90
101
|
}, [onListContainerRefChanged]);
|
|
91
102
|
useEffect(() => {
|
|
92
|
-
onInputRefChanged === null || onInputRefChanged === void 0 || onInputRefChanged(
|
|
93
|
-
}, [
|
|
103
|
+
onInputRefChanged === null || onInputRefChanged === void 0 || onInputRefChanged(readInputRef);
|
|
104
|
+
}, [readInputRef, onInputRefChanged]);
|
|
94
105
|
const DEFAULT_VIRTUAL_ITEM_HEIGHT = 32;
|
|
95
106
|
const virtualizer = useVirtualizer({
|
|
96
107
|
count: items.length,
|
|
97
|
-
getScrollElement: () =>
|
|
108
|
+
getScrollElement: () => readScrollContainerRef.current,
|
|
98
109
|
estimateSize: () => DEFAULT_VIRTUAL_ITEM_HEIGHT,
|
|
99
110
|
overscan: 10,
|
|
100
111
|
enabled: isVirtualized,
|
|
@@ -128,7 +139,7 @@ function FilteredActionList({ loading = false, placeholderText, filterValue: ext
|
|
|
128
139
|
focusableElementFilter: (element) => {
|
|
129
140
|
return !(element instanceof HTMLInputElement);
|
|
130
141
|
},
|
|
131
|
-
activeDescendantFocus:
|
|
142
|
+
activeDescendantFocus: readInputRef,
|
|
132
143
|
onActiveDescendantChanged: (current, previous, directlyActivated) => {
|
|
133
144
|
activeDescendantRef.current = current;
|
|
134
145
|
if (isVirtualized && current) {
|
|
@@ -136,7 +147,7 @@ function FilteredActionList({ loading = false, placeholderText, filterValue: ext
|
|
|
136
147
|
const range = virtualizer.range;
|
|
137
148
|
if (index !== null && range && (Number(index) < range.startIndex || Number(index) >= range.endIndex)) virtualizer.scrollToIndex(Number(index), { align: "auto" });
|
|
138
149
|
}
|
|
139
|
-
if (current &&
|
|
150
|
+
if (current && readScrollContainerRef.current && (directlyActivated || focusPrependedElements)) scrollIntoView(current, readScrollContainerRef.current, {
|
|
140
151
|
...menuScrollMargins,
|
|
141
152
|
behavior: scrollBehavior
|
|
142
153
|
});
|
|
@@ -153,14 +164,14 @@ function FilteredActionList({ loading = false, placeholderText, filterValue: ext
|
|
|
153
164
|
isVirtualized
|
|
154
165
|
]);
|
|
155
166
|
useEffect(() => {
|
|
156
|
-
if (activeDescendantRef.current &&
|
|
167
|
+
if (activeDescendantRef.current && readScrollContainerRef.current) scrollIntoView(activeDescendantRef.current, readScrollContainerRef.current, {
|
|
157
168
|
...menuScrollMargins,
|
|
158
169
|
behavior: scrollBehavior
|
|
159
170
|
});
|
|
160
171
|
}, [
|
|
161
172
|
items,
|
|
162
|
-
|
|
163
|
-
|
|
173
|
+
readInputRef,
|
|
174
|
+
readScrollContainerRef,
|
|
164
175
|
scrollBehavior
|
|
165
176
|
]);
|
|
166
177
|
useEffect(() => {
|
|
@@ -170,7 +181,7 @@ function FilteredActionList({ loading = false, placeholderText, filterValue: ext
|
|
|
170
181
|
const list = listRef.current;
|
|
171
182
|
if (!list) return;
|
|
172
183
|
const handleFocusIn = (event) => {
|
|
173
|
-
if (event.target ===
|
|
184
|
+
if (event.target === readInputRef.current || list.contains(event.target)) setIsInputFocused(readInputRef.current && readInputRef.current === document.activeElement ? true : false);
|
|
174
185
|
};
|
|
175
186
|
inputAndListContainerElement.addEventListener("focusin", handleFocusIn);
|
|
176
187
|
return () => {
|
|
@@ -179,26 +190,26 @@ function FilteredActionList({ loading = false, placeholderText, filterValue: ext
|
|
|
179
190
|
}
|
|
180
191
|
}, [
|
|
181
192
|
items,
|
|
182
|
-
|
|
193
|
+
readInputRef,
|
|
183
194
|
listContainerElement,
|
|
184
195
|
usingRovingTabindex
|
|
185
196
|
]);
|
|
186
197
|
useEffect(() => {
|
|
187
|
-
if (usingRovingTabindex && !loading) setIsInputFocused(
|
|
198
|
+
if (usingRovingTabindex && !loading) setIsInputFocused(readInputRef.current && readInputRef.current === document.activeElement ? true : false);
|
|
188
199
|
}, [
|
|
189
200
|
loading,
|
|
190
|
-
|
|
201
|
+
readInputRef,
|
|
191
202
|
usingRovingTabindex
|
|
192
203
|
]);
|
|
193
|
-
useAnnouncements(items, usingRovingTabindex ? listRef : { current: listContainerElement },
|
|
194
|
-
useScrollFlash(
|
|
204
|
+
useAnnouncements(items, usingRovingTabindex ? listRef : { current: listContainerElement }, readInputRef, announcementsEnabled, loading, messageText, _PrivateFocusManagement);
|
|
205
|
+
useScrollFlash(readScrollContainerRef);
|
|
195
206
|
const handleSelectAllChange = useCallback((e) => {
|
|
196
207
|
if (onSelectAllChange) onSelectAllChange(e.target.checked);
|
|
197
208
|
}, [onSelectAllChange]);
|
|
198
209
|
function getBodyContent() {
|
|
199
|
-
if (loading &&
|
|
210
|
+
if (loading && readScrollContainerRef.current && loadingType.appearsInBody) return /*#__PURE__*/ jsx(FilteredActionListBodyLoader, {
|
|
200
211
|
loadingType,
|
|
201
|
-
height:
|
|
212
|
+
height: readScrollContainerRef.current.clientHeight
|
|
202
213
|
});
|
|
203
214
|
if (message) return message;
|
|
204
215
|
let firstGroupIndex = 0;
|
|
@@ -290,7 +301,7 @@ function FilteredActionList({ loading = false, placeholderText, filterValue: ext
|
|
|
290
301
|
"data-component": "FilteredActionList",
|
|
291
302
|
children: [
|
|
292
303
|
/*#__PURE__*/ jsx(FilteredActionListInput, {
|
|
293
|
-
inputRef,
|
|
304
|
+
inputRef: appliedInputRef,
|
|
294
305
|
value: filterValue,
|
|
295
306
|
onInputChange,
|
|
296
307
|
onInputKeyPress,
|
|
@@ -324,7 +335,7 @@ function FilteredActionList({ loading = false, placeholderText, filterValue: ext
|
|
|
324
335
|
})]
|
|
325
336
|
}),
|
|
326
337
|
/*#__PURE__*/ jsx("div", {
|
|
327
|
-
ref:
|
|
338
|
+
ref: appliedScrollContainerRef,
|
|
328
339
|
className: FilteredActionList_module_css_default.Container,
|
|
329
340
|
children: getBodyContent()
|
|
330
341
|
})
|
|
@@ -3,7 +3,7 @@ import React from "react";
|
|
|
3
3
|
|
|
4
4
|
//#region src/FilteredActionList/FilteredActionListInput.d.ts
|
|
5
5
|
interface FilteredActionListInputProps extends Partial<Omit<TextInputProps, 'onChange' | 'onKeyDown'>> {
|
|
6
|
-
inputRef: React.
|
|
6
|
+
inputRef: React.Ref<HTMLInputElement | null>;
|
|
7
7
|
onInputChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
|
8
8
|
onInputKeyPress?: React.KeyboardEventHandler<HTMLInputElement>;
|
|
9
9
|
onInputKeyDown?: React.KeyboardEventHandler<HTMLInputElement>;
|