diff --git a/.changeset/empty-years-type.md b/.changeset/empty-years-type.md new file mode 100644 index 000000000..84356426a --- /dev/null +++ b/.changeset/empty-years-type.md @@ -0,0 +1,5 @@ +--- +"@workleap/orbiter-ui": patch +--- + +Replace element.ref with element.props.ref for React 19 compatibility diff --git a/packages/components/src/accordion/src/useAccordionItems.ts b/packages/components/src/accordion/src/useAccordionItems.ts index bbcbc1997..36ded84eb 100644 --- a/packages/components/src/accordion/src/useAccordionItems.ts +++ b/packages/components/src/accordion/src/useAccordionItems.ts @@ -1,6 +1,7 @@ -import { Children, ReactElement, ReactNode, Ref, RefAttributes, useMemo } from "react"; +import { Children, ReactElement, ReactNode, Ref, useMemo } from "react"; import { Content, Header } from "../../placeholders/index.ts"; import { isNil, mergeProps } from "../../shared/index.ts"; +import { getElementRef } from "../../shared/src/getElementRef.tsx"; export interface AccordionBuilderItem { header: AccordionBuilderHeader; @@ -47,14 +48,14 @@ export class AccordionBuilder { // elementType: isHeading(header.type) ? undefined : header.type, elementType: header.type, props: mergeProps(header.props, element.props), - ref: (header as RefAttributes).ref as Ref + ref: getElementRef(header) }; const panelProps: AccordionBuilderItem["header"] = { // Use a custom type if available otherwise let the AccordionPanel component choose his default type. elementType: content.type !== Content ? content.type : undefined, props: content.props, - ref: (content as RefAttributes).ref as Ref + ref: getElementRef(content) }; return { diff --git a/packages/components/src/collection/src/useCollection.ts b/packages/components/src/collection/src/useCollection.ts index 1eec9e832..8bbda3934 100644 --- a/packages/components/src/collection/src/useCollection.ts +++ b/packages/components/src/collection/src/useCollection.ts @@ -1,6 +1,7 @@ -import { Children, ElementType, ReactElement, ReactNode, Ref, RefAttributes, useMemo } from "react"; +import { Children, ElementType, ReactElement, ReactNode, Ref, useMemo } from "react"; import { Divider } from "../../divider/index.ts"; import { Item, Section } from "../../collection/index.ts"; +import { getElementRef } from "../../shared/src/getElementRef.tsx"; import { TooltipTrigger, parseTooltipTrigger } from "../../tooltip/index.ts"; import { isNil, resolveChildren } from "../../shared/index.ts"; @@ -75,7 +76,7 @@ export class CollectionBuilder { index, key: !isNil(element.key) ? element.key.toString().replace(".", "").replace("$", "") : index.toString(), props, - ref: (element as RefAttributes).ref as Ref, + ref: getElementRef(element), type: NodeType.item }; } @@ -97,7 +98,7 @@ export class CollectionBuilder { items, key: index.toString(), props, - ref: (element as RefAttributes).ref as Ref, + ref: getElementRef(element), type: NodeType.section }; } @@ -113,7 +114,7 @@ export class CollectionBuilder { index, key: index.toString(), props, - ref: (element as RefAttributes).ref as Ref, + ref: getElementRef(element), type: NodeType.divider }; } diff --git a/packages/components/src/shared/src/augmentElement.tsx b/packages/components/src/shared/src/augmentElement.tsx index 0c8bf7725..6389635cf 100644 --- a/packages/components/src/shared/src/augmentElement.tsx +++ b/packages/components/src/shared/src/augmentElement.tsx @@ -1,9 +1,10 @@ import { ReactElement, RefAttributes, cloneElement } from "react"; import { Size, SizeAdapter, normalizeSize } from "./size.ts"; import { mergeProps } from "./mergeProps.ts"; +import { getElementRef } from "./getElementRef.tsx"; export function augmentElement(element: ReactElement & RefAttributes, newProps: Record) { - const augmentedProps = mergeProps({ ...element.props, ref: element.ref }, newProps); + const augmentedProps = mergeProps({ ...element.props, ref: getElementRef(element) }, newProps); return cloneElement(element, augmentedProps); } diff --git a/packages/components/src/shared/src/getElementRef.tsx b/packages/components/src/shared/src/getElementRef.tsx new file mode 100644 index 000000000..7f80435b8 --- /dev/null +++ b/packages/components/src/shared/src/getElementRef.tsx @@ -0,0 +1,10 @@ +import { ReactElement, Ref } from "react"; + +/** + * `ref` is passed as prop in React 19, whereas `ref` is directly attached to + * children in React 18 below check is to ensure `ref` is accessible in both + * cases + */ +export function getElementRef(element: ReactElement): Ref { + return element.props.propertyIsEnumerable("ref") ? element.props.ref : (element as any).ref; +} \ No newline at end of file diff --git a/packages/components/src/tabs/src/useTabsItems.ts b/packages/components/src/tabs/src/useTabsItems.ts index f391009ac..5e0d7d201 100644 --- a/packages/components/src/tabs/src/useTabsItems.ts +++ b/packages/components/src/tabs/src/useTabsItems.ts @@ -1,6 +1,7 @@ import { Children, ReactElement, ReactNode, Ref, RefAttributes, useMemo } from "react"; import { Content, Header } from "../../placeholders/index.ts"; import { isNil, mergeProps, resolveChildren } from "../../shared/index.ts"; +import { getElementRef } from "../../shared/src/getElementRef.tsx"; export interface PanelType { disabled?: boolean; @@ -56,7 +57,7 @@ export class TabsBuilder { key, panelId, props: mergeProps(header.props, element.props), - ref: header.ref as Ref, + ref: getElementRef(header), tabId }); @@ -69,7 +70,7 @@ export class TabsBuilder { key, panelId, props: content.props, - ref: content.ref as Ref, + ref: getElementRef(content), tabId }); });