Skip to content

Commit 5b1655a

Browse files
committed
fix(ui-modal): fix Modal.body throwing error when 'as' is set to a React component
The new code now digs recursively in the 'ref' prop until it finds the actual DOM element and returns that one to test: 1. Create a Modal.Body component with a custom 'as' prop set to a React component e.g. Flex 2. Create a Modal.Body component with a custom 'as' prop set to a native element, e.g. section INSTUI-4671
1 parent c563623 commit 5b1655a

File tree

2 files changed

+25
-5
lines changed

2 files changed

+25
-5
lines changed

packages/ui-modal/src/Modal/ModalBody/index.tsx

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import generateComponentTheme from './theme'
3535

3636
import { propTypes, allowedProps } from './props'
3737
import type { ModalBodyProps } from './props'
38+
import { UIElement } from '@instructure/shared-types'
3839

3940
/**
4041
---
@@ -55,9 +56,9 @@ class ModalBody extends Component<ModalBodyProps> {
5556
variant: 'default'
5657
}
5758

58-
ref: Element | null = null
59+
ref: UIElement | null = null
5960

60-
handleRef = (el: Element | null) => {
61+
handleRef = (el: UIElement | null) => {
6162
const { elementRef } = this.props
6263

6364
this.ref = el
@@ -93,6 +94,19 @@ class ModalBody extends Component<ModalBodyProps> {
9394
this.props.makeStyles?.()
9495
}
9596

97+
getFinalRef(el: UIElement): Element | undefined {
98+
if (!el) {
99+
return undefined
100+
}
101+
if (el instanceof Element) {
102+
return el
103+
}
104+
if ((el as unknown as { ref: UIElement }).ref) {
105+
return this.getFinalRef((el as unknown as { ref: UIElement }).ref)
106+
}
107+
return undefined
108+
}
109+
96110
render() {
97111
const { as, elementRef, overflow, variant, padding, children, ...rest } =
98112
this.props
@@ -102,6 +116,10 @@ class ModalBody extends Component<ModalBodyProps> {
102116
ModalBody
103117
)
104118
const isFit = overflow === 'fit'
119+
// this recursive function is needed because `ref` can be a React component.
120+
// TODO rethink, the 'as' prop, likely its not a good idea to allow React
121+
// components. See INSTUI-4674
122+
const finalRef = this.getFinalRef(this.ref)
105123

106124
return (
107125
<View
@@ -114,7 +132,8 @@ class ModalBody extends Component<ModalBodyProps> {
114132
css={this.props.styles?.modalBody}
115133
padding={padding}
116134
//check if there is a scrollbar, if so, the element has to be tabbable to be able to scroll with keyboard only
117-
{...(this.ref?.scrollHeight !== this.ref?.getBoundingClientRect().height
135+
{...(finalRef?.scrollHeight !==
136+
finalRef?.getBoundingClientRect()?.height
118137
? { tabIndex: 0 }
119138
: {})}
120139
>

packages/ui-modal/src/Modal/ModalBody/props.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,14 @@ import type {
3434
AsElementType,
3535
PropValidators,
3636
ModalBodyTheme,
37-
OtherHTMLAttributes
37+
OtherHTMLAttributes,
38+
UIElement
3839
} from '@instructure/shared-types'
3940

4041
type ModalBodyOwnProps = {
4142
children?: React.ReactNode
4243
padding?: Spacing
43-
elementRef?: (element: Element | null) => void
44+
elementRef?: (element: UIElement | null) => void
4445
as?: AsElementType
4546
variant?: 'default' | 'inverse'
4647
overflow?: 'scroll' | 'fit'

0 commit comments

Comments
 (0)