UNPKG

svelte-cross-frameworks

Version:
108 lines (103 loc) 3.08 kB
import * as React from 'react'; import * as Vue from 'vue'; const conventionalEventHandlerPredicate = (maybeEventName) => { const match = maybeEventName.match(/^on([A-Z])(.*)/); if (match) { const [_, cap, ...resetEventName] = match; return cap.toLowerCase() + resetEventName.join(""); } return false; }; function extractEventMapFromProps(props, eventPredicate = conventionalEventHandlerPredicate) { return Object.keys(props).reduce( (registration, eventName) => { const predicated = eventPredicate(eventName); if (predicated && typeof predicated === "string") { registration.set(predicated, props[eventName]); } return registration; }, /* @__PURE__ */ new Map() ); } function createReactComponent(svelteComponent) { const ReactComponent = React.memo(React.forwardRef(function ReactComponent2(props, ref) { const targetRef = React.useRef(); const componentRef = React.useRef(); React.useImperativeHandle(ref, () => componentRef.current); const eventEntries = React.useMemo(() => Array.from(extractEventMapFromProps(props)), [props]); React.useEffect(() => { if (componentRef.current || !targetRef.current) { return; } componentRef.current = new svelteComponent({ target: targetRef.current, props }); return () => { componentRef.current?.$destroy?.(); componentRef.current = void 0; }; }, []); React.useEffect( () => { if (!componentRef.current) return; const offs = eventEntries.map(([eventName, handler]) => componentRef.current?.$on?.(eventName, handler)); return () => offs.forEach((off) => off?.()); }, [] ); React.useEffect(() => { componentRef.current?.$set?.(props); }, [props]); return React.createElement("div", { ref: targetRef }); })); ReactComponent.displayName = svelteComponent.name; return ReactComponent; } function createVueComponent(svelteComponent) { return Vue.defineComponent({ name: svelteComponent.name, data() { return { component: null, offs: [] }; }, computed: { eventEntries() { return Array.from(extractEventMapFromProps(this.$attrs)); } }, methods: { boundEvents() { this.offs = this.eventEntries.map(([eventName, handler]) => this.component?.$on?.(eventName, handler)); }, unboundEvents() { this.offs.forEach((off) => off?.()); } }, mounted() { if (!this.$refs.targetRef) { return; } this.component = new svelteComponent({ target: this.$refs.targetRef, props: this.$attrs }); }, unmounted() { this.unboundEvents(); this.component?.$destroy?.(); }, beforeUpdate() { this.unboundEvents(); }, updated() { this.component?.$set?.(this.$attrs); this.boundEvents(); }, render() { return Vue.h("div", { ref: "targetRef" }); } }); } export { createReactComponent, createVueComponent };