Skip to content

Commit

Permalink
feat(refs): migrate more components to properly forward their refs
Browse files Browse the repository at this point in the history
Migrates Image and ProgressBar components to forward their refs
properly.

Relevant to #4194.
  • Loading branch information
bpas247 committed Aug 25, 2019
1 parent b7fa945 commit 7d5eef1
Show file tree
Hide file tree
Showing 2 changed files with 135 additions and 119 deletions.
102 changes: 53 additions & 49 deletions src/Image.js
@@ -1,68 +1,72 @@
import classNames from 'classnames';
import React from 'react';
import React, { useMemo } from 'react';
import PropTypes from 'prop-types';

import { createBootstrapComponent } from './ThemeProvider';
import { useBootstrapPrefix } from './ThemeProvider';

class Image extends React.Component {
static propTypes = {
/**
* @default 'img'
*/
bsPrefix: PropTypes.string,
/**
* Sets image as fluid image.
*/
fluid: PropTypes.bool,
const propTypes = {
/**
* @default 'img'
*/
bsPrefix: PropTypes.string,
/**
* Sets image as fluid image.
*/
fluid: PropTypes.bool,

/**
* Sets image shape as rounded.
*/
rounded: PropTypes.bool,
/**
* Sets image shape as rounded.
*/
rounded: PropTypes.bool,

/**
* Sets image shape as circle.
*/
roundedCircle: PropTypes.bool,
/**
* Sets image shape as circle.
*/
roundedCircle: PropTypes.bool,

/**
* Sets image shape as thumbnail.
*/
thumbnail: PropTypes.bool,
};
/**
* Sets image shape as thumbnail.
*/
thumbnail: PropTypes.bool,
};

static defaultProps = {
fluid: false,
rounded: false,
roundedCircle: false,
thumbnail: false,
};
const defaultProps = {
fluid: false,
rounded: false,
roundedCircle: false,
thumbnail: false,
};

render() {
const {
bsPrefix,
className,
fluid,
rounded,
roundedCircle,
thumbnail,
...props
} = this.props;
const Image = React.forwardRef(
(
{ bsPrefix, className, fluid, rounded, roundedCircle, thumbnail, ...props },
ref,
) => {
bsPrefix = useBootstrapPrefix(bsPrefix, 'img');

const classes = classNames(
fluid && `${bsPrefix}-fluid`,
rounded && `rounded`,
roundedCircle && `rounded-circle`,
thumbnail && `${bsPrefix}-thumbnail`,
const classes = useMemo(
() =>
classNames(
fluid && `${bsPrefix}-fluid`,
rounded && `rounded`,
roundedCircle && `rounded-circle`,
thumbnail && `${bsPrefix}-thumbnail`,
),
[fluid, rounded, roundedCircle, thumbnail, bsPrefix],
);

return (
<img // eslint-disable-line jsx-a11y/alt-text
ref={ref}
{...props}
className={classNames(className, classes)}
/>
);
}
}
},
);

export default createBootstrapComponent(Image, 'img');
Image.displayName = 'Image';
Image.propTypes = propTypes;
Image.defaultProps = defaultProps;

export default Image;
152 changes: 82 additions & 70 deletions src/ProgressBar.js
Expand Up @@ -2,7 +2,7 @@ import classNames from 'classnames';
import React, { cloneElement } from 'react';
import PropTypes from 'prop-types';

import { createBootstrapComponent } from './ThemeProvider';
import { useBootstrapPrefix } from './ThemeProvider';

import { map } from './utils/ElementChildren';

Expand Down Expand Up @@ -30,7 +30,7 @@ function onlyProgressBar(props, propName, componentName) {
*
* see https://github.com/gaearon/react-hot-loader#checking-element-types
*/
const element = <DecoratedProgressBar />;
const element = <ProgressBar />;
if (child.type === element.type) return;

const childIdentifier = React.isValidElement(child)
Expand Down Expand Up @@ -120,84 +120,96 @@ function getPercentage(now, min, max) {
return Math.round(percentage * ROUND_PRECISION) / ROUND_PRECISION;
}

class ProgressBar extends React.Component {
renderProgressBar({
min,
now,
max,
label,
srOnly,
striped,
animated,
className,
style,
variant,
bsPrefix,
...props
}) {
return (
<div
{...props}
role="progressbar"
className={classNames(className, `${bsPrefix}-bar`, {
[`bg-${variant}`]: variant,
[`${bsPrefix}-bar-animated`]: animated,
[`${bsPrefix}-bar-striped`]: animated || striped,
})}
style={{ width: `${getPercentage(now, min, max)}%`, ...style }}
aria-valuenow={now}
aria-valuemin={min}
aria-valuemax={max}
>
{srOnly ? <span className="sr-only">{label}</span> : label}
</div>
);
}

render() {
const { isChild, ...props } = this.props;

if (isChild) {
return this.renderProgressBar(props);
}

const {
const RenderProgressBar = React.forwardRef(
(
{
min,
now,
max,
label,
srOnly,
striped,
animated,
bsPrefix,
variant,
className,
children,
...wrapperProps
} = props;

return (
<div {...wrapperProps} className={classNames(className, bsPrefix)}>
{children
? map(children, child => cloneElement(child, { isChild: true }))
: this.renderProgressBar({
min,
now,
max,
label,
srOnly,
striped,
animated,
bsPrefix,
variant,
})}
</div>
);
style,
variant,
bsPrefix,
...props
},
ref,
) => (
<div
ref={ref}
{...props}
role="progressbar"
className={classNames(className, `${bsPrefix}-bar`, {
[`bg-${variant}`]: variant,
[`${bsPrefix}-bar-animated`]: animated,
[`${bsPrefix}-bar-striped`]: animated || striped,
})}
style={{ width: `${getPercentage(now, min, max)}%`, ...style }}
aria-valuenow={now}
aria-valuemin={min}
aria-valuemax={max}
>
{srOnly ? <span className="sr-only">{label}</span> : label}
</div>
),
);

RenderProgressBar.propTypes = propTypes;
RenderProgressBar.defaultProps = propTypes;

const ProgressBar = React.forwardRef(({ isChild, ...props }, ref) => {
props.bsPrefix = useBootstrapPrefix(props.bsPrefix, 'progress');

if (isChild) {
return <RenderProgressBar {...props} />;
}
}

const {
min,
now,
max,
label,
srOnly,
striped,
animated,
bsPrefix,
variant,
className,
children,
...wrapperProps
} = props;

return (
<div
ref={ref}
{...wrapperProps}
className={classNames(className, bsPrefix)}
>
{children ? (
map(children, child => cloneElement(child, { isChild: true }))
) : (
<RenderProgressBar
ref={ref}
min={min}
now={now}
max={max}
label={label}
srOnly={srOnly}
striped={striped}
animated={animated}
bsPrefix={bsPrefix}
variant={variant}
/>
)}
</div>
);
});

ProgressBar.displayName = 'ProgressBar';
ProgressBar.propTypes = propTypes;
ProgressBar.defaultProps = defaultProps;
const DecoratedProgressBar = createBootstrapComponent(ProgressBar, 'progress');

export default DecoratedProgressBar;
export default ProgressBar;

0 comments on commit 7d5eef1

Please sign in to comment.