@vime/react
Version:
React bindings for the Vime media player.
77 lines (76 loc) • 3.45 kB
JSX
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
/* eslint-disable react/prop-types */
import composeRefs from '@seznam/compose-react-refs';
import { createElement, forwardRef, useCallback, useEffect, useMemo, useRef, useState, } from 'react';
export const define = (tagName, clazz) => {
const isClient = typeof window !== 'undefined';
if (isClient && !customElements.get(tagName))
customElements.define(tagName, clazz);
};
const dashToPascalCase = (str) => str
.toLowerCase()
.split('-')
.map(segment => segment.charAt(0).toUpperCase() + segment.slice(1))
.join('');
const isEvent = (prop) => { var _a; return prop.indexOf('on') === 0 && prop[2] === ((_a = prop[2]) === null || _a === void 0 ? void 0 : _a.toUpperCase()); };
const toDomEventName = (prop) => prop.charAt(2).toLowerCase() + prop.substring(3);
export function createComponent(tagName, componentProps) {
const Component = forwardRef((_a, forwardedRef) => {
var { children } = _a, props = __rest(_a, ["children"]);
const [ref, setRef] = useState(null);
const setRefCb = useCallback((node) => {
setRef(node);
}, []);
const eventHandlers = useRef(new Map());
const domProps = useMemo(() => Object.keys(props)
.filter(prop => !componentProps.has(prop) && !isEvent(prop))
.reduce((p, c) => (Object.assign(Object.assign({}, p), { [c]: props[c] })), {}), [props]);
const wcProps = useMemo(() => Object.keys(props)
.filter(prop => componentProps.has(prop) || isEvent(prop))
.reduce((p, c) => (Object.assign(Object.assign({}, p), { [c]: props[c] })), {}), [props]);
const listen = useCallback((prop, handler) => {
var _a;
const domEvent = toDomEventName(prop);
(_a = eventHandlers.current.get(domEvent)) === null || _a === void 0 ? void 0 : _a();
if (!ref || !handler)
return;
ref.addEventListener(domEvent, handler);
eventHandlers.current.set(domEvent, () => {
ref.removeEventListener(domEvent, handler);
});
}, [ref]);
const cleanup = useCallback(() => {
eventHandlers.current.forEach(fn => fn());
eventHandlers.current.clear();
}, []);
useEffect(() => () => {
cleanup();
}, []);
useEffect(() => {
if (!ref)
return;
Object.keys(wcProps).forEach(prop => {
if (isEvent(prop)) {
listen(prop, wcProps[prop]);
return;
}
if (ref[prop] !== wcProps[prop]) {
ref[prop] = wcProps[prop];
}
});
}, [ref, wcProps]);
return createElement(tagName, Object.assign({ ref: composeRefs(setRefCb, forwardedRef) }, domProps), children);
});
Component.displayName = dashToPascalCase(tagName);
return Component;
}