@primer/react 38.36.0-rc.7156e7efc → 38.36.0-rc.a1228eda5
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/ActionBar/ActionBar.js +10 -8
- package/dist/ActionList/Heading.js +2 -1
- package/dist/CounterLabel/CounterLabel.js +5 -2
- package/dist/Details/Details.js +2 -1
- package/dist/Dialog/Dialog.js +3 -2
- package/dist/PageHeader/PageHeader.js +2 -1
- package/dist/Portal/Portal.js +91 -29
- package/dist/SelectPanel/SelectPanel.js +26 -25
- package/dist/TooltipV2/Tooltip.js +3 -2
- package/dist/TreeView/TreeView.js +0 -1
- package/dist/UnderlineNav/UnderlineNav.d.ts +3 -2
- package/dist/UnderlineNav/UnderlineNav.js +1 -1
- package/dist/deprecated/ActionList/List.js +2 -1
- package/dist/experimental/SelectPanel2/SelectPanel.js +7 -4
- package/dist/hooks/useFocusZone.js +2 -1
- package/dist/hooks/useMenuInitialFocus.js +72 -57
- package/generated/components.json +7 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,12 @@
|
|
|
7
7
|
- [#8212](https://github.com/primer/react/pull/8212) [`9ac9343`](https://github.com/primer/react/commit/9ac9343a70fd0f70413a42cd27baf562a74dd4fc) Thanks [@mattcosta7](https://github.com/mattcosta7)! - ThemeProvider: Add a CSS-variable-based implementation to `@primer/react/next`
|
|
8
8
|
and deprecate the legacy JavaScript theme implementation.
|
|
9
9
|
|
|
10
|
+
### Patch Changes
|
|
11
|
+
|
|
12
|
+
- [#8276](https://github.com/primer/react/pull/8276) [`5069f8a`](https://github.com/primer/react/commit/5069f8a7cb95544ce14122e97d67c8a1279f8a08) Thanks [@copilot-swe-agent](https://github.com/apps/copilot-swe-agent)! - Portal: Render nothing while server rendering and during hydration instead of accessing the DOM during render, fixing server rendering support. Client-only renders are unchanged and still mount portaled content in the same commit.
|
|
13
|
+
|
|
14
|
+
- [#8260](https://github.com/primer/react/pull/8260) [`24d0831`](https://github.com/primer/react/commit/24d0831d34b13e3b4bac8afcfa2ccd5795cd9a9d) Thanks [@liuliu-dev](https://github.com/liuliu-dev)! - UnderlineNav: Keep item icons visible by default at the medium breakpoint and above
|
|
15
|
+
|
|
10
16
|
## 38.35.1
|
|
11
17
|
|
|
12
18
|
### Patch Changes
|
|
@@ -133,14 +133,15 @@ const ActionBarIconButton = /*#__PURE__*/ forwardRef(({ disabled, onClick, ...pr
|
|
|
133
133
|
disabled,
|
|
134
134
|
onClick
|
|
135
135
|
]));
|
|
136
|
+
const clickHandler = useCallback((event) => {
|
|
137
|
+
if (disabled) return;
|
|
138
|
+
onClick === null || onClick === void 0 || onClick(event);
|
|
139
|
+
}, [disabled, onClick]);
|
|
136
140
|
return /*#__PURE__*/ jsx(IconButton, {
|
|
137
141
|
"aria-disabled": disabled,
|
|
138
142
|
ref: mergedRef,
|
|
139
143
|
size,
|
|
140
|
-
onClick:
|
|
141
|
-
if (disabled) return;
|
|
142
|
-
onClick === null || onClick === void 0 || onClick(event);
|
|
143
|
-
}, [disabled, onClick]),
|
|
144
|
+
onClick: clickHandler,
|
|
144
145
|
...props,
|
|
145
146
|
variant: "invisible",
|
|
146
147
|
"data-overflowing": dataOverflowingAttr
|
|
@@ -163,14 +164,15 @@ const ActionBarButton = /*#__PURE__*/ forwardRef(({ disabled, onClick, ...props
|
|
|
163
164
|
disabled,
|
|
164
165
|
onClick
|
|
165
166
|
]));
|
|
167
|
+
const clickHandler = useCallback((event) => {
|
|
168
|
+
if (disabled) return;
|
|
169
|
+
onClick === null || onClick === void 0 || onClick(event);
|
|
170
|
+
}, [disabled, onClick]);
|
|
166
171
|
return /*#__PURE__*/ jsx(ButtonComponent, {
|
|
167
172
|
"aria-disabled": disabled,
|
|
168
173
|
ref: mergedRef,
|
|
169
174
|
size,
|
|
170
|
-
onClick:
|
|
171
|
-
if (disabled) return;
|
|
172
|
-
onClick === null || onClick === void 0 || onClick(event);
|
|
173
|
-
}, [disabled, onClick]),
|
|
175
|
+
onClick: clickHandler,
|
|
174
176
|
...props,
|
|
175
177
|
variant: "invisible",
|
|
176
178
|
"data-overflowing": dataOverflowingAttr
|
|
@@ -37,7 +37,8 @@ const Heading = /*#__PURE__*/ forwardRef((t0, forwardedRef) => {
|
|
|
37
37
|
t1 = $[6];
|
|
38
38
|
}
|
|
39
39
|
const visuallyHidden = t1 === void 0 ? false : t1;
|
|
40
|
-
const
|
|
40
|
+
const innerRef = React.useRef(null);
|
|
41
|
+
const mergedRef = useMergedRefs(forwardedRef, innerRef);
|
|
41
42
|
const { headingId, variant: listVariant } = React.useContext(ListContext);
|
|
42
43
|
const { container } = React.useContext(ActionListContainerContext);
|
|
43
44
|
!(container !== "ActionMenu") && invariant(false, "ActionList.Heading shouldn't be used within an ActionMenu container. Menus are labelled by the menu button's name.");
|
|
@@ -11,11 +11,14 @@ const CounterLabel = /*#__PURE__*/ forwardRef(({ variant, scheme, className, chi
|
|
|
11
11
|
")"
|
|
12
12
|
] });
|
|
13
13
|
const inferredVariant = variant || scheme || "secondary";
|
|
14
|
-
|
|
14
|
+
const counterProps = {
|
|
15
15
|
ref: forwardedRef,
|
|
16
16
|
["aria-hidden"]: "true",
|
|
17
17
|
["data-variant"]: inferredVariant,
|
|
18
|
-
...rest
|
|
18
|
+
...rest
|
|
19
|
+
};
|
|
20
|
+
return /*#__PURE__*/ jsxs(Fragment, { children: [/*#__PURE__*/ jsx("span", {
|
|
21
|
+
...counterProps,
|
|
19
22
|
"data-component": dataComponent !== null && dataComponent !== void 0 ? dataComponent : "CounterLabel",
|
|
20
23
|
className: clsx(className, CounterLabel_module_css_default.CounterLabel),
|
|
21
24
|
children
|
package/dist/Details/Details.js
CHANGED
|
@@ -34,7 +34,8 @@ const Root = /*#__PURE__*/ React.forwardRef((t0, forwardRef) => {
|
|
|
34
34
|
t1 = () => {
|
|
35
35
|
const { current: details } = detailsRef;
|
|
36
36
|
if (!details) return;
|
|
37
|
-
|
|
37
|
+
const summary = details.querySelector("summary:not([data-default-summary])");
|
|
38
|
+
warning(summary === null, "The <Details> component must have a <summary> child component. You can either use <Details.Summary> or a native <summary> element.");
|
|
38
39
|
};
|
|
39
40
|
t2 = [];
|
|
40
41
|
$[5] = t1;
|
package/dist/Dialog/Dialog.js
CHANGED
|
@@ -140,7 +140,7 @@ const _Dialog = /*#__PURE__*/ React.forwardRef((props, forwardedRef) => {
|
|
|
140
140
|
});
|
|
141
141
|
const footer = (_slots$footer = slots.footer) !== null && _slots$footer !== void 0 ? _slots$footer : (renderFooter !== null && renderFooter !== void 0 ? renderFooter : DefaultFooter)(defaultedProps);
|
|
142
142
|
const hasFooter = footer != null;
|
|
143
|
-
|
|
143
|
+
const updateFooterButtonLayout = useCallback(() => {
|
|
144
144
|
if (!hasFooter) return;
|
|
145
145
|
const dialogElement = dialogRef.current;
|
|
146
146
|
if (!(dialogElement instanceof HTMLElement)) return;
|
|
@@ -150,7 +150,8 @@ const _Dialog = /*#__PURE__*/ React.forwardRef((props, forwardedRef) => {
|
|
|
150
150
|
const newLayout = bodyWrapper.clientHeight >= MIN_BODY_HEIGHT ? "wrap" : "scroll";
|
|
151
151
|
dialogElement.setAttribute("data-footer-button-layout", newLayout);
|
|
152
152
|
setFooterButtonLayout(newLayout);
|
|
153
|
-
}, [hasFooter])
|
|
153
|
+
}, [hasFooter]);
|
|
154
|
+
useResizeObserver(updateFooterButtonLayout, backdropRef);
|
|
154
155
|
const positionDataAttributes = typeof position === "string" ? { "data-position-regular": position } : Object.fromEntries(Object.entries(position).map(([key, value]) => {
|
|
155
156
|
return [`data-position-${key}`, value];
|
|
156
157
|
}));
|
|
@@ -72,7 +72,8 @@ const Root = /*#__PURE__*/ React.forwardRef((t0, forwardedRef) => {
|
|
|
72
72
|
if (/*#__PURE__*/ React.isValidElement(child_1) && (child_1.type === ContextArea || isSlot(child_1, ContextArea))) hasContextArea = true;
|
|
73
73
|
if (/*#__PURE__*/ React.isValidElement(child_1) && (child_1.type === LeadingAction || isSlot(child_1, LeadingAction))) hasLeadingAction = true;
|
|
74
74
|
}
|
|
75
|
-
|
|
75
|
+
const hasInteractiveContent = Array.from(titleArea.childNodes).some((child_2) => child_2 instanceof HTMLElement && isInteractive(child_2) || Array.from(child_2.childNodes).some((child_3) => child_3 instanceof HTMLElement && isInteractive(child_3)));
|
|
76
|
+
warning(hasInteractiveContent && (hasContextArea || hasLeadingAction), "When PageHeader.ContextArea or PageHeader.LeadingAction is present, we recommended not to include any interactive items in the PageHeader.TitleArea to make sure the focus order is logical.");
|
|
76
77
|
};
|
|
77
78
|
t3 = [children, readRef];
|
|
78
79
|
$[0] = children;
|
package/dist/Portal/Portal.js
CHANGED
|
@@ -1,43 +1,105 @@
|
|
|
1
1
|
import useIsomorphicLayoutEffect from "../utils/useIsomorphicLayoutEffect.js";
|
|
2
2
|
import { PortalContext } from "./PortalContext.js";
|
|
3
3
|
import { DEFAULT_PORTAL_CONTAINER_NAME, ensureDefaultPortal, getPortalRoot } from "./portalRoot.js";
|
|
4
|
-
import
|
|
4
|
+
import { c } from "react-compiler-runtime";
|
|
5
|
+
import React, { useContext, useSyncExternalStore } from "react";
|
|
5
6
|
import { createPortal } from "react-dom";
|
|
6
7
|
//#region src/Portal/Portal.tsx
|
|
8
|
+
const subscribe = () => () => {};
|
|
9
|
+
const getSnapshot = () => true;
|
|
10
|
+
const getServerSnapshot = () => false;
|
|
11
|
+
/**
|
|
12
|
+
* Returns `true` only when React is rendering on the client, and not as part of
|
|
13
|
+
* hydrating server-rendered markup.
|
|
14
|
+
*
|
|
15
|
+
* `Portal` needs this because React's server renderer throws when it encounters a
|
|
16
|
+
* portal, and portaled content is never part of the server-rendered markup.
|
|
17
|
+
*
|
|
18
|
+
* `useSyncExternalStore` is used rather than a `useEffect`/`useState` "is mounted"
|
|
19
|
+
* flag because it only defers the portal for the renders that need it: it returns
|
|
20
|
+
* `false` while server rendering and for the hydration pass (keeping hydration
|
|
21
|
+
* consistent with the server markup), but `true` from the very first render of a
|
|
22
|
+
* client-only render. That way client-rendered portals — the overwhelmingly common
|
|
23
|
+
* case for overlays, dialogs and menus — still mount their children in the same
|
|
24
|
+
* commit as the `Portal` itself, so refs into portaled content are populated by the
|
|
25
|
+
* time the parent's layout effects run.
|
|
26
|
+
*/
|
|
27
|
+
function useIsClientRender() {
|
|
28
|
+
return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
|
|
29
|
+
}
|
|
7
30
|
/**
|
|
8
31
|
* Creates a React Portal, placing all children in a separate physical DOM root node.
|
|
9
32
|
* @see https://reactjs.org/docs/portals.html
|
|
10
33
|
*/
|
|
11
|
-
const Portal = (
|
|
34
|
+
const Portal = (t0) => {
|
|
35
|
+
const $ = c(12);
|
|
36
|
+
const { children, onMount, containerName: _containerName } = t0;
|
|
12
37
|
const { portalContainerName } = useContext(PortalContext);
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
elementRef.current = div;
|
|
20
|
-
}
|
|
21
|
-
const element = elementRef.current;
|
|
22
|
-
useIsomorphicLayoutEffect(() => {
|
|
23
|
-
let containerName = _containerName !== null && _containerName !== void 0 ? _containerName : portalContainerName;
|
|
24
|
-
if (containerName === void 0) {
|
|
25
|
-
containerName = DEFAULT_PORTAL_CONTAINER_NAME;
|
|
26
|
-
ensureDefaultPortal();
|
|
27
|
-
}
|
|
28
|
-
const parentElement = getPortalRoot(containerName);
|
|
29
|
-
if (!parentElement) throw new Error(`Portal container '${containerName}' is not yet registered. Container must be registered with registerPortalRoot before use.`);
|
|
30
|
-
parentElement.appendChild(element);
|
|
31
|
-
onMount === null || onMount === void 0 || onMount();
|
|
32
|
-
return () => {
|
|
33
|
-
parentElement.removeChild(element);
|
|
38
|
+
const isClientRender = useIsClientRender();
|
|
39
|
+
const onMountRef = React.useRef(onMount);
|
|
40
|
+
let t1;
|
|
41
|
+
if ($[0] !== onMount) {
|
|
42
|
+
t1 = () => {
|
|
43
|
+
onMountRef.current = onMount;
|
|
34
44
|
};
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
]);
|
|
40
|
-
|
|
45
|
+
$[0] = onMount;
|
|
46
|
+
$[1] = t1;
|
|
47
|
+
} else t1 = $[1];
|
|
48
|
+
useIsomorphicLayoutEffect(t1);
|
|
49
|
+
const [element] = React.useState(_temp);
|
|
50
|
+
let t2;
|
|
51
|
+
let t3;
|
|
52
|
+
if ($[2] !== _containerName || $[3] !== element || $[4] !== isClientRender || $[5] !== portalContainerName) {
|
|
53
|
+
t2 = () => {
|
|
54
|
+
var _onMountRef$current;
|
|
55
|
+
if (!element || !isClientRender) return;
|
|
56
|
+
let containerName = _containerName !== null && _containerName !== void 0 ? _containerName : portalContainerName;
|
|
57
|
+
if (containerName === void 0) {
|
|
58
|
+
containerName = DEFAULT_PORTAL_CONTAINER_NAME;
|
|
59
|
+
ensureDefaultPortal();
|
|
60
|
+
}
|
|
61
|
+
const parentElement = getPortalRoot(containerName);
|
|
62
|
+
if (!parentElement) throw new Error(`Portal container '${containerName}' is not yet registered. Container must be registered with registerPortalRoot before use.`);
|
|
63
|
+
parentElement.appendChild(element);
|
|
64
|
+
(_onMountRef$current = onMountRef.current) === null || _onMountRef$current === void 0 || _onMountRef$current.call(onMountRef);
|
|
65
|
+
return () => {
|
|
66
|
+
parentElement.removeChild(element);
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
t3 = [
|
|
70
|
+
element,
|
|
71
|
+
isClientRender,
|
|
72
|
+
_containerName,
|
|
73
|
+
portalContainerName
|
|
74
|
+
];
|
|
75
|
+
$[2] = _containerName;
|
|
76
|
+
$[3] = element;
|
|
77
|
+
$[4] = isClientRender;
|
|
78
|
+
$[5] = portalContainerName;
|
|
79
|
+
$[6] = t2;
|
|
80
|
+
$[7] = t3;
|
|
81
|
+
} else {
|
|
82
|
+
t2 = $[6];
|
|
83
|
+
t3 = $[7];
|
|
84
|
+
}
|
|
85
|
+
useIsomorphicLayoutEffect(t2, t3);
|
|
86
|
+
let t4;
|
|
87
|
+
if ($[8] !== children || $[9] !== element || $[10] !== isClientRender) {
|
|
88
|
+
t4 = element && isClientRender ? /*#__PURE__*/ createPortal(children, element) : null;
|
|
89
|
+
$[8] = children;
|
|
90
|
+
$[9] = element;
|
|
91
|
+
$[10] = isClientRender;
|
|
92
|
+
$[11] = t4;
|
|
93
|
+
} else t4 = $[11];
|
|
94
|
+
return t4;
|
|
41
95
|
};
|
|
96
|
+
function _temp() {
|
|
97
|
+
if (typeof document === "undefined") return null;
|
|
98
|
+
const div = document.createElement("div");
|
|
99
|
+
div.setAttribute("data-component", "Portal");
|
|
100
|
+
div.style.position = "relative";
|
|
101
|
+
div.style.zIndex = "1";
|
|
102
|
+
return div;
|
|
103
|
+
}
|
|
42
104
|
//#endregion
|
|
43
105
|
export { Portal };
|
|
@@ -435,6 +435,31 @@ function Panel({ open, onOpenChange, renderAnchor = defaultRenderAnchor, anchorR
|
|
|
435
435
|
if (event.key !== "/" && !isAlphabetKey(event.nativeEvent)) return;
|
|
436
436
|
event.stopPropagation();
|
|
437
437
|
}, [overlayProps]);
|
|
438
|
+
const mergedOverlayProps = useMemo(() => ({
|
|
439
|
+
role: "dialog",
|
|
440
|
+
"aria-labelledby": titleId,
|
|
441
|
+
"aria-describedby": subtitle ? subtitleId : void 0,
|
|
442
|
+
...overlayProps,
|
|
443
|
+
...variant === "modal" ? {
|
|
444
|
+
top: "50vh",
|
|
445
|
+
left: "50vw",
|
|
446
|
+
anchorSide: void 0
|
|
447
|
+
} : {},
|
|
448
|
+
style: {
|
|
449
|
+
transform: variant === "modal" ? "translate(-50%, -50%)" : void 0,
|
|
450
|
+
...isKeyboardVisible ? { maxHeight: availablePanelHeight !== void 0 ? `${availablePanelHeight}px` : "auto" } : {}
|
|
451
|
+
},
|
|
452
|
+
onKeyDown: preventBubbling
|
|
453
|
+
}), [
|
|
454
|
+
titleId,
|
|
455
|
+
subtitle,
|
|
456
|
+
subtitleId,
|
|
457
|
+
overlayProps,
|
|
458
|
+
variant,
|
|
459
|
+
isKeyboardVisible,
|
|
460
|
+
availablePanelHeight,
|
|
461
|
+
preventBubbling
|
|
462
|
+
]);
|
|
438
463
|
return /*#__PURE__*/ jsxs(Fragment, { children: [/*#__PURE__*/ jsx(AnchoredOverlay, {
|
|
439
464
|
renderAnchor: renderMenuAnchor,
|
|
440
465
|
anchorRef,
|
|
@@ -442,31 +467,7 @@ function Panel({ open, onOpenChange, renderAnchor = defaultRenderAnchor, anchorR
|
|
|
442
467
|
open,
|
|
443
468
|
onOpen,
|
|
444
469
|
onClose,
|
|
445
|
-
overlayProps:
|
|
446
|
-
role: "dialog",
|
|
447
|
-
"aria-labelledby": titleId,
|
|
448
|
-
"aria-describedby": subtitle ? subtitleId : void 0,
|
|
449
|
-
...overlayProps,
|
|
450
|
-
...variant === "modal" ? {
|
|
451
|
-
top: "50vh",
|
|
452
|
-
left: "50vw",
|
|
453
|
-
anchorSide: void 0
|
|
454
|
-
} : {},
|
|
455
|
-
style: {
|
|
456
|
-
transform: variant === "modal" ? "translate(-50%, -50%)" : void 0,
|
|
457
|
-
...isKeyboardVisible ? { maxHeight: availablePanelHeight !== void 0 ? `${availablePanelHeight}px` : "auto" } : {}
|
|
458
|
-
},
|
|
459
|
-
onKeyDown: preventBubbling
|
|
460
|
-
}), [
|
|
461
|
-
titleId,
|
|
462
|
-
subtitle,
|
|
463
|
-
subtitleId,
|
|
464
|
-
overlayProps,
|
|
465
|
-
variant,
|
|
466
|
-
isKeyboardVisible,
|
|
467
|
-
availablePanelHeight,
|
|
468
|
-
preventBubbling
|
|
469
|
-
]),
|
|
470
|
+
overlayProps: mergedOverlayProps,
|
|
470
471
|
focusTrapSettings,
|
|
471
472
|
focusZoneSettings,
|
|
472
473
|
height,
|
|
@@ -100,10 +100,11 @@ const Tooltip = /*#__PURE__*/ React.forwardRef(({ direction = "s", text, type =
|
|
|
100
100
|
const trigger = readTriggerRef.current;
|
|
101
101
|
tooltip.showPopover();
|
|
102
102
|
setIsPopoverOpen(true);
|
|
103
|
-
const
|
|
103
|
+
const settings = {
|
|
104
104
|
side: directionToPosition[direction].side,
|
|
105
105
|
align: directionToPosition[direction].align
|
|
106
|
-
}
|
|
106
|
+
};
|
|
107
|
+
const { top, left, anchorAlign, anchorSide } = getAnchoredPosition(tooltip, trigger, settings);
|
|
107
108
|
const calculatedDirection = positionToDirection[`${anchorSide}-${anchorAlign}`];
|
|
108
109
|
setCalculatedDirection(calculatedDirection);
|
|
109
110
|
tooltip.style.top = `${top}px`;
|
|
@@ -17,8 +17,9 @@ type UnderlineNavProps = {
|
|
|
17
17
|
*/
|
|
18
18
|
variant?: 'inset' | 'flush';
|
|
19
19
|
/**
|
|
20
|
-
*
|
|
21
|
-
*
|
|
20
|
+
* Controls the container width below which icons are hidden to save space. Defaults to `medium`.
|
|
21
|
+
* To keep icons visible in a narrow container, use a smaller breakpoint such as `xsmall`, or set to `null` to
|
|
22
|
+
* always show icons.
|
|
22
23
|
*/
|
|
23
24
|
hideIconsBreakpoint?: 'xsmall' | 'small' | 'medium' | 'large' | 'xlarge' | 'xxlarge' | null;
|
|
24
25
|
};
|
|
@@ -22,7 +22,7 @@ const UnderlineNav = /*#__PURE__*/ forwardRef((t0, forwardedRef) => {
|
|
|
22
22
|
const as = t1 === void 0 ? "nav" : t1;
|
|
23
23
|
const loadingCounters = t2 === void 0 ? false : t2;
|
|
24
24
|
const variant = t3 === void 0 ? "inset" : t3;
|
|
25
|
-
const hideIconsBreakpoint = t4 === void 0 ? "
|
|
25
|
+
const hideIconsBreakpoint = t4 === void 0 ? "medium" : t4;
|
|
26
26
|
const backupRef = useRef(null);
|
|
27
27
|
const navRef = forwardedRef !== null && forwardedRef !== void 0 ? forwardedRef : backupRef;
|
|
28
28
|
const listRef = useRef(null);
|
|
@@ -59,7 +59,8 @@ const List = /*#__PURE__*/ React.forwardRef((props, forwardedRef) => {
|
|
|
59
59
|
const { firstGroupStyle, lastGroupStyle, headerStyle, itemStyle } = useListVariant(restProps.variant);
|
|
60
60
|
const renderGroup = (groupProps) => {
|
|
61
61
|
var _ref;
|
|
62
|
-
|
|
62
|
+
const GroupComponent = ((_ref = "renderGroup" in groupProps && groupProps.renderGroup) !== null && _ref !== void 0 ? _ref : restProps.renderGroup) || Group;
|
|
63
|
+
return /*#__PURE__*/ createElement(GroupComponent, {
|
|
63
64
|
...groupProps,
|
|
64
65
|
key: groupProps.groupId
|
|
65
66
|
});
|
|
@@ -43,10 +43,11 @@ const responsiveButtonSizes = {
|
|
|
43
43
|
const Panel = ({ title, description, variant: propsVariant, selectionVariant = "multiple", id, defaultOpen = false, open: propsOpen, anchorRef: providedAnchorRef, anchoredPositionSettings, onCancel: propsOnCancel, onClearSelection: propsOnClearSelection, onSubmit: propsOnSubmit, width = "medium", maxHeight = "large", className, ...props }) => {
|
|
44
44
|
var _position$top, _position$left, _slots$header;
|
|
45
45
|
const [internalOpen, setInternalOpen] = React.useState(defaultOpen);
|
|
46
|
-
const
|
|
46
|
+
const responsiveVariants = Object.assign({
|
|
47
47
|
regular: "anchored",
|
|
48
48
|
narrow: "full-screen"
|
|
49
|
-
}, typeof propsVariant === "string" ? { regular: propsVariant } : propsVariant)
|
|
49
|
+
}, typeof propsVariant === "string" ? { regular: propsVariant } : propsVariant);
|
|
50
|
+
const currentVariant = useResponsiveValue(responsiveVariants, "anchored");
|
|
50
51
|
if (propsOpen !== void 0 && internalOpen !== propsOpen) setInternalOpen(propsOpen);
|
|
51
52
|
let Anchor;
|
|
52
53
|
const anchorRef = useProvidedRefOrCreate(providedAnchorRef);
|
|
@@ -348,18 +349,20 @@ const SelectPanelFooter = ({ ...props }) => {
|
|
|
348
349
|
SelectPanelFooter.displayName = "SelectPanelFooter";
|
|
349
350
|
SelectPanelFooter.__SLOT__ = Symbol("SelectPanel.Footer");
|
|
350
351
|
const SecondaryButton = (props) => {
|
|
352
|
+
const size = useResponsiveValue(responsiveButtonSizes, "small");
|
|
351
353
|
return /*#__PURE__*/ jsx(ButtonComponent, {
|
|
352
354
|
type: "button",
|
|
353
|
-
size
|
|
355
|
+
size,
|
|
354
356
|
block: true,
|
|
355
357
|
...props
|
|
356
358
|
});
|
|
357
359
|
};
|
|
358
360
|
SecondaryButton.displayName = "SecondaryButton";
|
|
359
361
|
const SecondaryLink = ({ className, ...props }) => {
|
|
362
|
+
const size = useResponsiveValue(responsiveButtonSizes, "small");
|
|
360
363
|
return /*#__PURE__*/ jsx(ButtonComponent, {
|
|
361
364
|
as: Link,
|
|
362
|
-
size
|
|
365
|
+
size,
|
|
363
366
|
variant: "invisible",
|
|
364
367
|
block: true,
|
|
365
368
|
...props,
|
|
@@ -5,7 +5,8 @@ import { FocusKeys as FocusKeys$1, focusZone } from "@primer/behaviors";
|
|
|
5
5
|
function useFocusZone(settings = {}, dependencies = []) {
|
|
6
6
|
const containerRef = useProvidedRefOrCreate(settings.containerRef);
|
|
7
7
|
const useActiveDescendant = !!settings.activeDescendantFocus;
|
|
8
|
-
const
|
|
8
|
+
const passedActiveDescendantRef = typeof settings.activeDescendantFocus === "boolean" || !settings.activeDescendantFocus ? void 0 : settings.activeDescendantFocus;
|
|
9
|
+
const activeDescendantControlRef = useProvidedRefOrCreate(passedActiveDescendantRef);
|
|
9
10
|
const disabled = settings.disabled;
|
|
10
11
|
const abortController = React.useRef();
|
|
11
12
|
useEffect(() => {
|
|
@@ -1,68 +1,83 @@
|
|
|
1
|
+
import { c } from "react-compiler-runtime";
|
|
1
2
|
import React from "react";
|
|
2
3
|
import { iterateFocusableElements } from "@primer/behaviors/utils";
|
|
3
4
|
//#region src/hooks/useMenuInitialFocus.ts
|
|
4
5
|
const useMenuInitialFocus = (open, containerRef, anchorRef) => {
|
|
5
|
-
|
|
6
|
-
* We need to pick the first element to focus based on how the menu was opened,
|
|
7
|
-
* however, we need to wait for the menu to be open to set focus.
|
|
8
|
-
* This is why we use set openingKey in state and have 2 effects
|
|
9
|
-
*/
|
|
6
|
+
const $ = c(9);
|
|
10
7
|
const [openingGesture, setOpeningGesture] = React.useState(void 0);
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
8
|
+
let t0;
|
|
9
|
+
let t1;
|
|
10
|
+
if ($[0] !== anchorRef) {
|
|
11
|
+
t0 = function inferOpeningKey() {
|
|
12
|
+
const anchorElement = anchorRef === null || anchorRef === void 0 ? void 0 : anchorRef.current;
|
|
13
|
+
const clickHandler = (event) => {
|
|
14
|
+
if (event.detail !== 0) setOpeningGesture("mouse-click");
|
|
15
|
+
};
|
|
16
|
+
const keydownHandler = (event_0) => {
|
|
17
|
+
if ([
|
|
18
|
+
"Space",
|
|
19
|
+
"Enter",
|
|
20
|
+
"ArrowDown",
|
|
21
|
+
"ArrowUp"
|
|
22
|
+
].includes(event_0.code)) setOpeningGesture(event_0.code);
|
|
23
|
+
};
|
|
24
|
+
anchorElement === null || anchorElement === void 0 || anchorElement.addEventListener("click", clickHandler);
|
|
25
|
+
anchorElement === null || anchorElement === void 0 || anchorElement.addEventListener("keydown", keydownHandler);
|
|
26
|
+
return () => {
|
|
27
|
+
anchorElement === null || anchorElement === void 0 || anchorElement.removeEventListener("click", clickHandler);
|
|
28
|
+
anchorElement === null || anchorElement === void 0 || anchorElement.removeEventListener("keydown", keydownHandler);
|
|
29
|
+
};
|
|
15
30
|
};
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
31
|
+
t1 = [anchorRef];
|
|
32
|
+
$[0] = anchorRef;
|
|
33
|
+
$[1] = t0;
|
|
34
|
+
$[2] = t1;
|
|
35
|
+
} else {
|
|
36
|
+
t0 = $[1];
|
|
37
|
+
t1 = $[2];
|
|
38
|
+
}
|
|
39
|
+
React.useEffect(t0, t1);
|
|
40
|
+
let t2;
|
|
41
|
+
let t3;
|
|
42
|
+
if ($[3] !== anchorRef || $[4] !== containerRef || $[5] !== open || $[6] !== openingGesture) {
|
|
43
|
+
t2 = function moveFocusOnOpen() {
|
|
44
|
+
if (!open || !(containerRef !== null && containerRef !== void 0 && containerRef.current)) return;
|
|
45
|
+
const iterable = iterateFocusableElements(containerRef.current);
|
|
46
|
+
if (openingGesture === "mouse-click") if (anchorRef !== null && anchorRef !== void 0 && anchorRef.current) anchorRef.current.focus();
|
|
47
|
+
else throw new Error("For focus management, please attach anchorRef");
|
|
48
|
+
else if (openingGesture && [
|
|
20
49
|
"ArrowDown",
|
|
21
|
-
"
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
50
|
+
"Space",
|
|
51
|
+
"Enter"
|
|
52
|
+
].includes(openingGesture)) {
|
|
53
|
+
const firstElement = iterable.next().value;
|
|
54
|
+
setTimeout(() => firstElement === null || firstElement === void 0 ? void 0 : firstElement.focus());
|
|
55
|
+
} else if ("ArrowUp" === openingGesture) {
|
|
56
|
+
const elements = [...iterable];
|
|
57
|
+
const lastElement = elements[elements.length - 1];
|
|
58
|
+
setTimeout(() => lastElement.focus());
|
|
59
|
+
} else {
|
|
60
|
+
const firstElement_0 = iterable.next().value;
|
|
61
|
+
setTimeout(() => firstElement_0 === null || firstElement_0 === void 0 ? void 0 : firstElement_0.focus());
|
|
62
|
+
}
|
|
29
63
|
};
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const firstElement = iterable.next().value;
|
|
48
|
-
/** We push imperative focus to the next tick to prevent React's batching */
|
|
49
|
-
setTimeout(() => firstElement === null || firstElement === void 0 ? void 0 : firstElement.focus());
|
|
50
|
-
} else if ("ArrowUp" === openingGesture) {
|
|
51
|
-
const elements = [...iterable];
|
|
52
|
-
const lastElement = elements[elements.length - 1];
|
|
53
|
-
setTimeout(() => lastElement.focus());
|
|
54
|
-
} else {
|
|
55
|
-
/** if the menu was not opened with the anchor, we default to the first element
|
|
56
|
-
* for example: with keyboard shortcut (see stories/fixtures)
|
|
57
|
-
*/
|
|
58
|
-
const firstElement = iterable.next().value;
|
|
59
|
-
setTimeout(() => firstElement === null || firstElement === void 0 ? void 0 : firstElement.focus());
|
|
60
|
-
}
|
|
61
|
-
}, [
|
|
62
|
-
open,
|
|
63
|
-
openingGesture,
|
|
64
|
-
anchorRef
|
|
65
|
-
]);
|
|
64
|
+
t3 = [
|
|
65
|
+
open,
|
|
66
|
+
openingGesture,
|
|
67
|
+
anchorRef,
|
|
68
|
+
containerRef
|
|
69
|
+
];
|
|
70
|
+
$[3] = anchorRef;
|
|
71
|
+
$[4] = containerRef;
|
|
72
|
+
$[5] = open;
|
|
73
|
+
$[6] = openingGesture;
|
|
74
|
+
$[7] = t2;
|
|
75
|
+
$[8] = t3;
|
|
76
|
+
} else {
|
|
77
|
+
t2 = $[7];
|
|
78
|
+
t3 = $[8];
|
|
79
|
+
}
|
|
80
|
+
React.useEffect(t2, t3);
|
|
66
81
|
};
|
|
67
82
|
//#endregion
|
|
68
83
|
export { useMenuInitialFocus };
|
|
@@ -9042,7 +9042,7 @@
|
|
|
9042
9042
|
},
|
|
9043
9043
|
{
|
|
9044
9044
|
"id": "components-underlinenav-features--overflow-template",
|
|
9045
|
-
"code": "({ initialSelectedIndex = 1 }: { initialSelectedIndex?: number }) => {\n const [selectedIndex, setSelectedIndex] = React.useState<number | null>(\n initialSelectedIndex,\n )\n return (\n <UnderlineNav aria-label=\"Repository\">\n {items.map((item, index) => (\n <UnderlineNav.Item\n key={item.navigation}\n leadingVisual={item.icon}\n aria-current={index === selectedIndex ? 'page' : undefined}\n // Set so that navigation in interaction tests does not cause the\n // page to load the storybook iframe URL and instead keeps the test in\n // the local preview\n target=\"_self\"\n onSelect={(event) => {\n event.preventDefault()\n setSelectedIndex(index)\n }}\n counter={item.counter}\n href={item.href}\n >\n {item.navigation}\n </UnderlineNav.Item>\n ))}\n </UnderlineNav>\n )\n}"
|
|
9045
|
+
"code": "({ initialSelectedIndex = 1 }: { initialSelectedIndex?: number }) => {\n const [selectedIndex, setSelectedIndex] = React.useState<number | null>(\n initialSelectedIndex,\n )\n return (\n <UnderlineNav aria-label=\"Repository\" hideIconsBreakpoint=\"medium\">\n {items.map((item, index) => (\n <UnderlineNav.Item\n key={item.navigation}\n leadingVisual={item.icon}\n aria-current={index === selectedIndex ? 'page' : undefined}\n // Set so that navigation in interaction tests does not cause the\n // page to load the storybook iframe URL and instead keeps the test in\n // the local preview\n target=\"_self\"\n onSelect={(event) => {\n event.preventDefault()\n setSelectedIndex(index)\n }}\n counter={item.counter}\n href={item.href}\n >\n {item.navigation}\n </UnderlineNav.Item>\n ))}\n </UnderlineNav>\n )\n}"
|
|
9046
9046
|
},
|
|
9047
9047
|
{
|
|
9048
9048
|
"id": "components-underlinenav-features--overflow-on-narrow-screen",
|
|
@@ -9078,6 +9078,12 @@
|
|
|
9078
9078
|
"defaultValue": "false",
|
|
9079
9079
|
"description": "Whether the navigation items are in loading state. Component waits for all the counters to finish loading to prevent multiple layout shifts."
|
|
9080
9080
|
},
|
|
9081
|
+
{
|
|
9082
|
+
"name": "hideIconsBreakpoint",
|
|
9083
|
+
"type": "'xsmall' | 'small' | 'medium' | 'large' | 'xlarge' | 'xxlarge' | null",
|
|
9084
|
+
"defaultValue": "'medium'",
|
|
9085
|
+
"description": "Controls the container width below which icons are hidden to save space. To keep icons visible in a narrow container, use a smaller breakpoint such as `xsmall`, or set to `null` to always show icons."
|
|
9086
|
+
},
|
|
9081
9087
|
{
|
|
9082
9088
|
"name": "variant",
|
|
9083
9089
|
"type": "'inset' | 'flush'",
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@primer/react",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "38.36.0-rc.
|
|
4
|
+
"version": "38.36.0-rc.a1228eda5",
|
|
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",
|
|
@@ -166,7 +166,7 @@
|
|
|
166
166
|
"react-is": "18.3.1",
|
|
167
167
|
"recast": "0.23.7",
|
|
168
168
|
"rimraf": "5.0.5",
|
|
169
|
-
"rolldown": "^1.2.
|
|
169
|
+
"rolldown": "^1.2.2",
|
|
170
170
|
"rolldown-plugin-dts": "^0.26.0",
|
|
171
171
|
"rolldown-plugin-import-css": "^0.0.0",
|
|
172
172
|
"rolldown-plugin-preserve-directives": "^0.0.0",
|