react-onsenui
Version:
Onsen UI - React Components for Hybrid Cordova/PhoneGap Apps with Material Design and iOS UI components
81 lines (67 loc) • 2.18 kB
JSX
import React, { useRef, useEffect } from 'react';
const kebabize = camelString =>
camelString.replace(/([a-zA-Z])([A-Z])/g, '$1-$2').toLowerCase();
const addDeprecated = (props, deprecated) => {
const propsCopy = { ...props };
const nameMap = {
className: 'class',
...deprecated
};
// eslint-disable-next-line no-unused-vars
for (const [oldName, newName] of Object.entries(nameMap)) {
if (propsCopy[newName] === undefined && propsCopy[oldName] !== undefined) {
propsCopy[newName] = propsCopy[oldName];
delete propsCopy[oldName];
}
}
return propsCopy;
};
function useCustomElementListener(ref, prop, handler) {
const event = prop.slice(2).toLowerCase();
useEffect(() => {
const current = ref.current;
current.addEventListener(event, handler);
return function cleanup() {
current.removeEventListener(event, handler);
};
}, [ref, handler]);
}
function useCustomElement(props, options = {}, ref) {
const notAttributes = options.notAttributes || [];
const deprecated = options.deprecated || {};
const properties = {};
// eslint-disable-next-line no-unused-vars
for (const [prop, value] of Object.entries(addDeprecated(props, deprecated))) {
const jsName = kebabize(prop);
if (notAttributes.includes(prop)) {
useEffect(() => {
ref.current[prop] = value;
});
} else if (/^on[A-Z]/.test(prop)) {
useCustomElementListener(ref, prop, value);
} else if (typeof value === 'boolean') {
properties[jsName] = value ? '' : null;
} else if (typeof value === 'object' && value !== null) {
properties[jsName] = JSON.stringify(value);
} else {
properties[jsName] = value;
}
}
return {properties};
}
export default function onsCustomElement(WrappedComponent, options) {
return React.forwardRef((props, _ref) => {
const ref = _ref || useRef();
const {style, children, ...rest} = props;
const {properties} = useCustomElement(rest, options, ref);
return (
<WrappedComponent
ref={ref}
style={style}
{...properties}
>
{children}
</WrappedComponent>
);
});
}