svelte-cross-frameworks
Version:
Wrapper for Svelte cross-frameworks
126 lines (118 loc) • 3.65 kB
JavaScript
;
const React = require('react');
const Vue = require('vue');
function _interopNamespaceCompat(e) {
if (e && typeof e === 'object' && 'default' in e) return e;
const n = Object.create(null);
if (e) {
for (const k in e) {
n[k] = e[k];
}
}
n.default = e;
return n;
}
const React__namespace = /*#__PURE__*/_interopNamespaceCompat(React);
const Vue__namespace = /*#__PURE__*/_interopNamespaceCompat(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__namespace.memo(React__namespace.forwardRef(function ReactComponent2(props, ref) {
const targetRef = React__namespace.useRef();
const componentRef = React__namespace.useRef();
React__namespace.useImperativeHandle(ref, () => componentRef.current);
const eventEntries = React__namespace.useMemo(() => Array.from(extractEventMapFromProps(props)), [props]);
React__namespace.useEffect(() => {
if (componentRef.current || !targetRef.current) {
return;
}
componentRef.current = new svelteComponent({ target: targetRef.current, props });
return () => {
componentRef.current?.$destroy?.();
componentRef.current = void 0;
};
}, []);
React__namespace.useEffect(
() => {
if (!componentRef.current)
return;
const offs = eventEntries.map(([eventName, handler]) => componentRef.current?.$on?.(eventName, handler));
return () => offs.forEach((off) => off?.());
},
[]
);
React__namespace.useEffect(() => {
componentRef.current?.$set?.(props);
}, [props]);
return React__namespace.createElement("div", { ref: targetRef });
}));
ReactComponent.displayName = svelteComponent.name;
return ReactComponent;
}
function createVueComponent(svelteComponent) {
return Vue__namespace.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__namespace.h("div", { ref: "targetRef" });
}
});
}
exports.createReactComponent = createReactComponent;
exports.createVueComponent = createVueComponent;