Skip to content
Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/wicked-buttons-wink.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@primer/react': minor
---

Add support for `ref` types from React 19 by annotating `React.RefObject` types as `React.RefObject<T | null>`
201 changes: 201 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"lint:css:fix": "npm run lint:css -- --fix",
"lint:fix": "npm run lint -- --fix",
"lint:md": "markdownlint-cli2 \"**/*.{md,mdx}\" \"!.github\" \"!.changeset\" \"!**/node_modules/**\" \"!**/CHANGELOG.md\"",
"postinstall": "patch-package",
"test": "vitest",
"test:type-check": "tsc --noEmit",
"test:update": "npm run test -- -u",
Expand Down Expand Up @@ -81,6 +82,7 @@
"globals": "^16.2.0",
"markdownlint-cli2": "^0.17.2",
"markdownlint-cli2-formatter-pretty": "^0.0.8",
"patch-package": "^8.0.1",
"prettier": "3.4.2",
"rimraf": "5.0.5",
"size-limit": "11.2.0",
Expand Down
27 changes: 15 additions & 12 deletions packages/react/src/ActionBar/ActionBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -320,16 +320,19 @@ export const ActionBar: React.FC<React.PropsWithChildren<ActionBarProps>> = prop
const moreMenuBtnRef = useRef<HTMLButtonElement>(null)
const containerRef = React.useRef<HTMLUListElement>(null)

useResizeObserver((resizeObserverEntries: ResizeObserverEntry[]) => {
const navWidth = resizeObserverEntries[0].contentRect.width
const moreMenuWidth = moreMenuRef.current?.getBoundingClientRect().width ?? 0
const hasActiveMenu = menuItemIds.size > 0

if (navWidth > 0) {
const newMenuItemIds = getMenuItems(navWidth, moreMenuWidth, childRegistry, hasActiveMenu, computedGap)
if (newMenuItemIds) setMenuItemIds(newMenuItemIds)
}
}, navRef as RefObject<HTMLElement>)
useResizeObserver(
(resizeObserverEntries: ResizeObserverEntry[]) => {
const navWidth = resizeObserverEntries[0].contentRect.width
const moreMenuWidth = moreMenuRef.current?.getBoundingClientRect().width ?? 0
const hasActiveMenu = menuItemIds.size > 0

if (navWidth > 0) {
const newMenuItemIds = getMenuItems(navWidth, moreMenuWidth, childRegistry, hasActiveMenu, computedGap)
if (newMenuItemIds) setMenuItemIds(newMenuItemIds)
}
},
navRef as RefObject<HTMLElement | null>,
)

const isVisibleChild = useCallback(
(id: string) => {
Expand Down Expand Up @@ -554,7 +557,7 @@ const ActionBarGroupContext = React.createContext<{

export const ActionBarGroup = forwardRef(({children}: React.PropsWithChildren, forwardedRef) => {
const backupRef = useRef<HTMLDivElement>(null)
const ref = (forwardedRef ?? backupRef) as RefObject<HTMLDivElement>
const ref = (forwardedRef ?? backupRef) as RefObject<HTMLDivElement | null>
const id = useId()
const {registerChild, unregisterChild} = React.useContext(ActionBarContext)

Expand Down Expand Up @@ -586,7 +589,7 @@ export const ActionBarGroup = forwardRef(({children}: React.PropsWithChildren, f
export const ActionBarMenu = forwardRef(
({'aria-label': ariaLabel, icon, overflowIcon, items, ...props}: ActionBarMenuProps, forwardedRef) => {
const backupRef = useRef<HTMLButtonElement>(null)
const ref = (forwardedRef ?? backupRef) as RefObject<HTMLButtonElement>
const ref = (forwardedRef ?? backupRef) as RefObject<HTMLButtonElement | null>
const id = useId()
const {registerChild, unregisterChild, isVisibleChild} = React.useContext(ActionBarContext)

Expand Down
2 changes: 1 addition & 1 deletion packages/react/src/ActionList/List.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ const UnwrappedList = <As extends React.ElementType = 'ul'>(

const ariaLabelledBy = slots.heading ? (slots.heading.props.id ?? headingId) : listLabelledBy
const listRole = role || listRoleFromContainer
const listRef = useProvidedRefOrCreate(forwardedRef as React.RefObject<HTMLUListElement>)
const listRef = useProvidedRefOrCreate(forwardedRef as React.RefObject<HTMLUListElement | null>)

let enableFocusZone = false
if (enableFocusZoneFromContainer !== undefined) enableFocusZone = enableFocusZoneFromContainer
Expand Down
4 changes: 2 additions & 2 deletions packages/react/src/AnchoredOverlay/AnchoredOverlay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ interface AnchoredOverlayPropsWithAnchor {
/**
* An override to the internal ref that will be spread on to the renderAnchor
*/
anchorRef?: React.RefObject<HTMLElement>
anchorRef?: React.RefObject<HTMLElement | null>

/**
* An override to the internal id that will be spread on to the renderAnchor
Expand All @@ -46,7 +46,7 @@ interface AnchoredOverlayPropsWithoutAnchor {
* An override to the internal renderAnchor ref that will be used to position the overlay.
* When renderAnchor is null this can be used to make an anchor that is detached from ActionMenu.
*/
anchorRef: React.RefObject<HTMLElement>
anchorRef: React.RefObject<HTMLElement | null>
/**
* An override to the internal id that will be spread on to the renderAnchor
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,7 @@ export const CustomOverlayMenuAnchor = () => {
<FormControl.Label htmlFor="autocompleteInput" id="autocompleteLabel">
Default label
</FormControl.Label>
<div ref={menuAnchorRef as React.RefObject<HTMLDivElement>} className={classes.AnchorContainer}>
<div ref={menuAnchorRef as React.RefObject<HTMLDivElement | null>} className={classes.AnchorContainer}>
<Autocomplete>
<Autocomplete.Input
id="autocompleteInput"
Expand Down Expand Up @@ -522,7 +522,7 @@ export const InOverlayWithCustomScrollContainerRef = () => {
<div className={classes.OverlayInputBar}>
<Autocomplete.Input ref={inputRef} className={classes.OverlayInput} block aria-label="Search" />
</div>
<div ref={scrollContainerRef as RefObject<HTMLDivElement>} className={classes.OverlayScroll}>
<div ref={scrollContainerRef as RefObject<HTMLDivElement | null>} className={classes.OverlayScroll}>
<Autocomplete.Menu
items={items}
selectedItemIds={[]}
Expand Down
Loading
Loading