@primer/react 38.40.0-rc.629dc4f91 → 38.40.0-rc.960078edf

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 CHANGED
@@ -10,6 +10,10 @@
10
10
 
11
11
  - [#8408](https://github.com/primer/react/pull/8408) [`c880319`](https://github.com/primer/react/commit/c8803199ddb0e669596f6e2370fd4117a055cfc3) Thanks [@janmaarten-a11y](https://github.com/janmaarten-a11y)! - Button and LinkButton: Limit link variant underlines to the text label when visuals are present
12
12
 
13
+ - [#8411](https://github.com/primer/react/pull/8411) [`8c52029`](https://github.com/primer/react/commit/8c520293151054fd39e5094f4740e97e89ce18d8) Thanks [@mattcosta7](https://github.com/mattcosta7)! - Tooltip: Prevent React Fragment triggers from crashing and provide a clear development warning
14
+
15
+ - [#8409](https://github.com/primer/react/pull/8409) [`9d0632c`](https://github.com/primer/react/commit/9d0632ccc6c23e92cbbe786ce922795c92931b04) Thanks [@iansan5653](https://github.com/iansan5653)! - Fix Tooltip ref handling to preserve child element ref
16
+
13
17
  ## 38.39.0
14
18
 
15
19
  ### Minor Changes
@@ -1,3 +1,4 @@
1
+ import { reactMajorVersion } from "../utils/environment.js";
1
2
  import { useMergedRefs } from "../hooks/useMergedRefs.js";
2
3
  import { useProvidedRefOrCreate } from "../hooks/useProvidedRefOrCreate.js";
3
4
  import { useOnEscapePress } from "../hooks/useOnEscapePress.js";
@@ -82,10 +83,14 @@ const emptyKeybindingHints = [];
82
83
  const Tooltip = /*#__PURE__*/ React.forwardRef(({ direction = "s", text, type = "description", children, id, className, keybindingHint = emptyKeybindingHints, delay = "short", _privateDisableTooltip = false, ...rest }, forwardedRef) => {
83
84
  const tooltipId = useId$1(id);
84
85
  const child = Children.only(children);
86
+ const isFragmentTrigger = /*#__PURE__*/ React.isValidElement(child) && child.type === React.Fragment;
87
+ warning(isFragmentTrigger, "The `Tooltip` component does not support a React Fragment as its trigger. Pass a single interactive element instead.");
88
+ const elementChild = /*#__PURE__*/ React.isValidElement(child) ? child : void 0;
89
+ const childRef = reactMajorVersion > 18 ? elementChild === null || elementChild === void 0 ? void 0 : elementChild.props.ref : elementChild === null || elementChild === void 0 ? void 0 : elementChild.ref;
85
90
  const mergedRefEnabled = useFeatureFlag("primer_react_merged_forwarded_refs");
86
91
  const triggerRef = useRef(null);
87
- const mergedTriggerRef = useMergedRefs(triggerRef, forwardedRef);
88
- const providedOrCreatedRef = useProvidedRefOrCreate(forwardedRef);
92
+ const mergedTriggerRef = useMergedRefs(triggerRef, useMergedRefs(forwardedRef, childRef));
93
+ const providedOrCreatedRef = useProvidedRefOrCreate(forwardedRef !== null && forwardedRef !== void 0 ? forwardedRef : childRef);
89
94
  const readTriggerRef = mergedRefEnabled ? triggerRef : providedOrCreatedRef;
90
95
  const appliedTriggerRef = mergedRefEnabled ? mergedTriggerRef : providedOrCreatedRef;
91
96
  const tooltipElRef = useRef(null);
@@ -95,7 +100,7 @@ const Tooltip = /*#__PURE__*/ React.forwardRef(({ direction = "s", text, type =
95
100
  const { safeSetTimeout, safeClearTimeout } = useSafeTimeout();
96
101
  const openTooltip = () => {
97
102
  try {
98
- if (tooltipElRef.current && readTriggerRef.current && tooltipElRef.current.hasAttribute("popover") && !tooltipElRef.current.matches(":popover-open") && !_privateDisableTooltip) {
103
+ if (tooltipElRef.current && readTriggerRef.current instanceof HTMLElement && tooltipElRef.current.hasAttribute("popover") && !tooltipElRef.current.matches(":popover-open") && !_privateDisableTooltip) {
99
104
  const tooltip = tooltipElRef.current;
100
105
  const trigger = readTriggerRef.current;
101
106
  tooltip.showPopover();
@@ -131,15 +136,19 @@ const Tooltip = /*#__PURE__*/ React.forwardRef(({ direction = "s", text, type =
131
136
  const value = useMemo(() => ({ tooltipId }), [tooltipId]);
132
137
  useEffect(() => {
133
138
  if (!tooltipElRef.current || !readTriggerRef.current) return;
134
- const isTriggerInteractive = isInteractive(readTriggerRef.current);
135
- const triggerChildren = readTriggerRef.current.childNodes;
139
+ const trigger = readTriggerRef.current;
140
+ const isInvalidTrigger = !(trigger instanceof HTMLElement);
141
+ warning(isInvalidTrigger, "The `Tooltip` component expects its trigger ref to resolve to an HTML element. Ensure the trigger forwards its ref to a single interactive element instead of a React Fragment.");
142
+ if (isInvalidTrigger) return;
143
+ const isTriggerInteractive = isInteractive(trigger);
144
+ const triggerChildren = trigger.childNodes;
136
145
  const hasInteractiveDescendant = Array.from(triggerChildren).some((child) => {
137
146
  return child instanceof HTMLElement && isInteractive(child) || Array.from(child.childNodes).some((grandChild) => grandChild instanceof HTMLElement && isInteractive(grandChild));
138
147
  });
139
148
  !(isTriggerInteractive || hasInteractiveDescendant) && invariant(false, "The `Tooltip` component expects a single React element that contains interactive content. Consider using a `<button>` or equivalent interactive element instead.");
140
149
  if (type === "label") {
141
- const hasAriaLabel = readTriggerRef.current.hasAttribute("aria-label");
142
- const hasAriaLabelInChildren = Array.from(readTriggerRef.current.childNodes).some((child) => child instanceof HTMLElement && child.hasAttribute("aria-label"));
150
+ const hasAriaLabel = trigger.hasAttribute("aria-label");
151
+ const hasAriaLabelInChildren = Array.from(trigger.childNodes).some((child) => child instanceof HTMLElement && child.hasAttribute("aria-label"));
143
152
  warning(hasAriaLabel || hasAriaLabelInChildren, "The label type `Tooltip` is going to be used here to label the trigger element. Please remove the aria-label from the trigger element.");
144
153
  }
145
154
  if (typeof window !== "undefined") {
@@ -162,6 +171,7 @@ const Tooltip = /*#__PURE__*/ React.forwardRef(({ direction = "s", text, type =
162
171
  const platform = usePlatform();
163
172
  const hasAriaLabel = "aria-label" in rest;
164
173
  const keybindingHints = Array.isArray(keybindingHint) ? keybindingHint : [keybindingHint];
174
+ if (isFragmentTrigger) return child;
165
175
  return /*#__PURE__*/ jsx(TooltipContext.Provider, {
166
176
  value,
167
177
  children: /*#__PURE__*/ jsxs(Fragment$1, { children: [/*#__PURE__*/ React.isValidElement(child) && /*#__PURE__*/ React.cloneElement(child, {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@primer/react",
3
3
  "type": "module",
4
- "version": "38.40.0-rc.629dc4f91",
4
+ "version": "38.40.0-rc.960078edf",
5
5
  "description": "An implementation of GitHub's Primer Design System using React",
6
6
  "main": "./dist/index.js",
7
7
  "module": "./dist/index.js",