Skip to content

Commit bd06ddb

Browse files
authored
Use render prop in withModalHandlers for target (#748)
* Use render prop for target in withModalHandlers I'm working on code splitting things with suspense and things are breaking because of the findDOMNode calls in react-node-resolver Slightly related to this: @jossmac, i think you'll like this, reactjs/rfcs#97 * Update types * Fix linting error * Fix a thing * Fix thing
1 parent 370cdae commit bd06ddb

File tree

10 files changed

+61
-37
lines changed

10 files changed

+61
-37
lines changed

packages/admin-ui/client/components/ListTable.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,8 @@ class ListRow extends Component {
195195
render() {
196196
const { list, link, isSelected, item, itemErrors, fields } = this.props;
197197

198-
const row = (
199-
<TableRow>
198+
const row = props => (
199+
<TableRow {...props}>
200200
<BodyCell isSelected={isSelected} key="checkbox">
201201
<CheckboxPrimitive
202202
checked={isSelected}

packages/admin-ui/client/components/Popout.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,8 @@ export const Popout = ({
8989
target,
9090
...props
9191
}: Props) => {
92-
const defaultTarget = (
93-
<Button>
92+
const defaultTarget = props => (
93+
<Button {...props}>
9494
{buttonLabel}
9595
<DisclosureArrow />
9696
</Button>

packages/admin-ui/client/pages/List/Filters/ActiveFilters.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,16 @@ export default function ActiveFilters({ filterList, onClear, onRemove, onUpdate
3333
key={label}
3434
onChange={onUpdate}
3535
filter={filter}
36-
target={
37-
<Pill appearance="primary" onRemove={onRemove(filter)} style={pillStyle}>
36+
target={props => (
37+
<Pill
38+
{...props}
39+
appearance="primary"
40+
onRemove={onRemove(filter)}
41+
style={pillStyle}
42+
>
3843
{label}
3944
</Pill>
40-
}
45+
)}
4146
/>
4247
);
4348
})

packages/admin-ui/client/pages/List/ListDetails.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -310,11 +310,11 @@ class ListDetails extends Component<Props, State> {
310310
return (
311311
<Dropdown
312312
align="right"
313-
target={
314-
<IconButton variant="nuance" icon={KebabVerticalIcon} id="ks-list-dropdown">
313+
target={props => (
314+
<IconButton {...props} variant="nuance" icon={KebabVerticalIcon} id="ks-list-dropdown">
315315
<A11yText>Show more...</A11yText>
316316
</IconButton>
317-
}
317+
)}
318318
items={items}
319319
/>
320320
);
@@ -362,12 +362,12 @@ class ListDetails extends Component<Props, State> {
362362
Hold <Kbd>alt</Kbd> to toggle ascending/descending
363363
</Note>
364364
}
365-
target={
366-
<SortButton>
365+
target={props => (
366+
<SortButton {...props}>
367367
{sortBy.field.label.toLowerCase()}
368368
<DisclosureArrow size="0.2em" />
369369
</SortButton>
370-
}
370+
)}
371371
>
372372
<SortSelect
373373
popoutRef={this.sortPopoutRef}

packages/admin-ui/client/pages/List/MoreDropdown.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ import { IconButton } from '@arch-ui/button';
77
import Dropdown from '@arch-ui/dropdown';
88
import { useMeasure } from '@arch-ui/hooks';
99

10-
let dropdownTarget = (
11-
<IconButton variant="nuance" icon={KebabVerticalIcon} id="ks-list-dropdown">
10+
let dropdownTarget = props => (
11+
<IconButton {...props} variant="nuance" icon={KebabVerticalIcon} id="ks-list-dropdown">
1212
<A11yText>Show more...</A11yText>
1313
</IconButton>
1414
);

packages/admin-ui/client/pages/StyleGuide/Components/Modals.js

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,25 +47,30 @@ export default class ModalGuide extends Component {
4747
<h4>Dropdowns</h4>
4848
<FlexGroup justify="space-between">
4949
{['left', 'right'].map(a => (
50-
<Dropdown align={a} key={a} target={<Button>Align {a}</Button>} items={dropdownItems} />
50+
<Dropdown
51+
align={a}
52+
key={a}
53+
target={props => <Button {...props}>Align {a}</Button>}
54+
items={dropdownItems}
55+
/>
5156
))}
5257
</FlexGroup>
5358

5459
<h4>Popouts</h4>
5560
<FlexGroup justify="space-between">
56-
<Popout target={<Button>Left</Button>}>
61+
<Popout target={props => <Button {...props}>Left</Button>}>
5762
<PopoutContent>Left</PopoutContent>
5863
</Popout>
59-
<Popout target={<Button>Intermediate Left</Button>}>
64+
<Popout target={props => <Button {...props}>Intermediate Left</Button>}>
6065
<PopoutContent>Intermediate Left</PopoutContent>
6166
</Popout>
62-
<Popout target={<Button>Middle</Button>}>
67+
<Popout target={props => <Button {...props}>Middle</Button>}>
6368
<PopoutContent>Middle</PopoutContent>
6469
</Popout>
65-
<Popout target={<Button>Intermediate Right</Button>}>
70+
<Popout target={props => <Button {...props}>Intermediate Right</Button>}>
6671
<PopoutContent>Intermediate Right</PopoutContent>
6772
</Popout>
68-
<Popout target={<Button>Right</Button>}>
73+
<Popout target={props => <Button {...props}>Right</Button>}>
6974
<PopoutContent>Right</PopoutContent>
7075
</Popout>
7176
</FlexGroup>

packages/arch/packages/modal-utils/src/withModalHandlers.js

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,25 @@
11
// @flow
22

3-
import React, { cloneElement, Component, Fragment, type ComponentType, type Element } from 'react';
4-
import NodeResolver from 'react-node-resolver';
3+
import React, { Component, Fragment, type ComponentType, type Node, memo } from 'react';
54
import ScrollLock from 'react-scrolllock';
65
import { TransitionProvider } from './transitions';
76

87
type GenericFn = any => mixed;
98
export type CloseType = (event: Event) => void;
9+
type TargetArg = {
10+
isActive: boolean,
11+
onClick?: Function,
12+
onContextMenu?: Function,
13+
ref: Function,
14+
};
15+
1016
export type ModalHandlerProps = {
1117
close: CloseType,
1218
defaultIsOpen: boolean,
1319
mode: 'click' | 'contextmenu',
1420
onClose: GenericFn,
1521
onOpen: GenericFn,
16-
target: Element<*>,
22+
target: TargetArg => Node,
1723
};
1824
type State = { isOpen: boolean, clientX: number, clientY: number };
1925
type Config = { Transition: (*) => * };
@@ -23,6 +29,13 @@ function getDisplayName(C) {
2329
}
2430
const NOOP = () => {};
2531

32+
let Target = memo(function Target({ isOpen, mode, target, targetRef, open, toggle }) {
33+
const cloneProps: TargetArg = { isActive: isOpen, ref: targetRef };
34+
if (mode === 'click') cloneProps.onClick = toggle;
35+
if (mode === 'contextmenu') cloneProps.onContextMenu = open;
36+
return target(cloneProps);
37+
});
38+
2639
export default function withModalHandlers(
2740
WrappedComponent: ComponentType<*>,
2841
{ Transition }: Config
@@ -105,15 +118,16 @@ export default function withModalHandlers(
105118
const { mode, onClose, onOpen, target } = this.props;
106119
const { clientX, clientY, isOpen } = this.state;
107120

108-
const cloneProps = {};
109-
if (isOpen) cloneProps.isActive = true;
110-
if (mode === 'click') cloneProps.onClick = this.toggle;
111-
if (mode === 'contextmenu') cloneProps.onContextMenu = this.open;
112-
113-
// TODO: prefer functional children that pass refs + snapshot to the target node
114121
return (
115122
<Fragment>
116-
<NodeResolver innerRef={this.getTarget}>{cloneElement(target, cloneProps)}</NodeResolver>
123+
<Target
124+
targetRef={this.getTarget}
125+
target={target}
126+
mode={mode}
127+
isOpen={isOpen}
128+
toggle={this.toggle}
129+
open={this.open}
130+
/>
117131
{isOpen ? <ScrollLock /> : null}
118132
<TransitionProvider isOpen={isOpen} onEntered={onOpen} onExited={onClose}>
119133
{transitionState => (

packages/fields/types/CalendarDay/views/Field.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ export default class CalendarDayField extends Component {
2828
render() {
2929
const { autoFocus, field, value } = this.props;
3030
const htmlID = `ks-input-${field.path}`;
31-
const target = (
32-
<Button autoFocus={autoFocus} id={htmlID} variant="ghost">
31+
const target = props => (
32+
<Button {...props} autoFocus={autoFocus} id={htmlID} variant="ghost">
3333
{value ? format(value, this.props.field.config.format || 'Do MMM YYYY') : 'Set Date'}
3434
</Button>
3535
);

packages/fields/types/Color/views/Field.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ const ColorField = ({ field, value: serverValue, error, onChange }) => {
1414
const htmlID = `ks-input-${field.path}`;
1515
const canRead = !(error instanceof Error && error.name === 'AccessDeniedError');
1616

17-
const target = (
18-
<Button variant="ghost">
17+
const target = props => (
18+
<Button {...props} variant="ghost">
1919
{value ? (
2020
<React.Fragment>
2121
<div

packages/fields/types/DateTime/views/Field.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@ const CalendarDayField = ({ autoFocus, field, onChange, value }: Props) => {
4343
const { date, time, offset } = parsedDate;
4444

4545
const htmlID = `ks-input-${field.path}`;
46-
const target = (
47-
<Button autoFocus={autoFocus} id={htmlID} variant="ghost">
46+
const target = props => (
47+
<Button {...props} autoFocus={autoFocus} id={htmlID} variant="ghost">
4848
{value
4949
? format(date + ' ' + time + offset, field.config.format || 'Do MMM YYYY')
5050
: 'Set Date & Time'}

0 commit comments

Comments
 (0)