89 lines
3.5 KiB
JavaScript
89 lines
3.5 KiB
JavaScript
/**
|
|
* @license
|
|
* Copyright 2018 Google LLC
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
const reservedReactProperties = new Set([
|
|
'children',
|
|
'localName',
|
|
'ref',
|
|
'style',
|
|
'className',
|
|
]);
|
|
/**
|
|
* Creates a React component for a custom element. Properties are distinguished
|
|
* from attributes automatically, and events can be configured so they are added
|
|
* to the custom element as event listeners.
|
|
*
|
|
* @param options An options bag containing the parameters needed to generate a
|
|
* wrapped web component.
|
|
*
|
|
* @param options.react The React module, typically imported from the `react`
|
|
* npm package.
|
|
* @param options.tagName The custom element tag name registered via
|
|
* `customElements.define`.
|
|
* @param options.elementClass The custom element class registered via
|
|
* `customElements.define`.
|
|
* @param options.events An object listing events to which the component can
|
|
* listen. The object keys are the event property names passed in via React
|
|
* props and the object values are the names of the corresponding events
|
|
* generated by the custom element. For example, given `{onactivate:
|
|
* 'activate'}` an event function may be passed via the component's `onactivate`
|
|
* prop and will be called when the custom element fires its `activate` event.
|
|
* @param options.displayName A React component display name, used in debugging
|
|
* messages. Default value is inferred from the name of custom element class
|
|
* registered via `customElements.define`.
|
|
*/
|
|
const createComponent = ({ react: React, tagName, elementClass, events, displayName, }) => {
|
|
const eventProps = new Set(Object.keys(events ?? {}));
|
|
const ReactComponent = React.forwardRef((props, ref) => {
|
|
React.useRef(new Map());
|
|
const elementRef = React.useRef(null);
|
|
// Props to be passed to React.createElement
|
|
const reactProps = {};
|
|
// Props to be set on element with setProperty
|
|
const elementProps = {};
|
|
for (const [k, v] of Object.entries(props)) {
|
|
if (reservedReactProperties.has(k)) {
|
|
// React does *not* handle `className` for custom elements so
|
|
// coerce it to `class` so it's handled correctly.
|
|
reactProps[k === 'className' ? 'class' : k] = v;
|
|
continue;
|
|
}
|
|
if (eventProps.has(k) || k in elementClass.prototype) {
|
|
elementProps[k] = v;
|
|
continue;
|
|
}
|
|
reactProps[k] = v;
|
|
}
|
|
{
|
|
// If component is to be server rendered with `@lit/ssr-react`, pass
|
|
// element properties in a special bag to be set by the server-side
|
|
// element renderer.
|
|
if ((React.createElement.name === 'litPatchedCreateElement' ||
|
|
globalThis.litSsrReactEnabled) &&
|
|
Object.keys(elementProps).length) {
|
|
// This property needs to remain unminified.
|
|
reactProps['_$litProps$'] = elementProps;
|
|
}
|
|
}
|
|
return React.createElement(tagName, {
|
|
...reactProps,
|
|
ref: React.useCallback((node) => {
|
|
elementRef.current = node;
|
|
if (typeof ref === 'function') {
|
|
ref(node);
|
|
}
|
|
else if (ref !== null) {
|
|
ref.current = node;
|
|
}
|
|
}, [ref]),
|
|
});
|
|
});
|
|
ReactComponent.displayName = displayName ?? elementClass.name;
|
|
return ReactComponent;
|
|
};
|
|
|
|
export { createComponent };
|
|
//# sourceMappingURL=create-component.js.map
|