easeljs-react
Version:
React - EaselJS bindings with React Reconciler
264 lines (263 loc) • 9.29 kB
JavaScript
;
function __export(m) {
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}
Object.defineProperty(exports, "__esModule", { value: true });
const createjs = require("@createjs/easeljs");
const easeljs_1 = require("@createjs/easeljs");
const React = require("react");
const ReactReconciler = require("react-reconciler");
const now_1 = require("./now");
const dom_tree_1 = require("./dom-tree");
const kPropsToSkip = { children: true, ref: true, key: true, style: true };
let warningShowed = false;
function storedEventHandlerKey(ev) {
return `__easeljs_react_wrapped_event_listener:${ev}`;
}
function applyNodeProps(instance, props, oldProps = {}) {
if (!warningShowed && 'id' in props) {
const message = `easeljs-react: You are using "id" attribute for a easeljs node. In some very rare cases it may produce bugs. Currently we recommend not to use it and use "name" attribute instead.
You are using id = "${props.id}"`;
console.warn(message);
warningShowed = true;
}
const updatedProps = {};
let hasUpdates = false;
for (const key in oldProps) {
if (kPropsToSkip[key]) {
continue;
}
// events
const isEvent = key.slice(0, 2) === 'on';
const propChanged = oldProps[key] !== props[key];
if (isEvent && propChanged) {
let eventName = key.substr(2).toLowerCase();
const func = instance[storedEventHandlerKey(key)];
if (func) {
instance.off(eventName, func);
}
}
const toRemove = !props.hasOwnProperty(key);
if (toRemove) {
updatedProps[key] = void 0;
}
}
for (const key in props) {
if (kPropsToSkip[key]) {
continue;
}
if (key === "bounds") {
const bounds = props[key] || { x: null };
instance.setBounds(bounds.x, bounds.y, bounds.width, bounds.height);
continue;
}
const isEvent = key.slice(0, 2) === 'on';
const toAdd = oldProps[key] !== props[key];
if (isEvent && toAdd) {
let eventName = key.substr(2).toLowerCase();
if (props[key]) {
const listener = instance.on(eventName, props[key]);
instance[storedEventHandlerKey(key)] = listener;
}
}
if (!isEvent &&
(props[key] !== oldProps[key] || props[key] !== instance[key])) {
hasUpdates = true;
updatedProps[key] = props[key];
}
}
if (hasUpdates) {
instance.set(updatedProps);
updatePicture(instance);
}
}
function updatePicture(node) {
//TODO: should update be done manually?
const { stage } = node;
if (stage) {
stage.update();
}
}
const UPDATE_SIGNAL = {};
const kEmptyObject = Object.freeze({});
class HostConfigImpl {
constructor() {
this.isPrimaryRenderer = false;
this.noTimeout = -1;
this.supportsHydration = false;
this.supportsMutation = true;
this.supportsPersistence = false;
}
appendInitialChild(parentInstance, child) {
if (typeof child === 'string') {
// Noop for string children of Text (eg <Text>{'foo'}{'bar'}</Text>)
throw new Error(`Don not use plain text as child of Konva.Node. You are using text: "${child}"`);
}
parentInstance.addChild(child);
updatePicture(parentInstance);
}
cancelDeferredCallback(callbackID) {
}
clearTimeout(handle) {
}
createInstance(type, props, rootContainerInstance, hostContext, internalInstanceHandle) {
const NodeClass = createjs[type];
if (!NodeClass) {
throw new Error(`createjs does not support the type "${type}"`);
}
const instance = new NodeClass();
instance._applyProps = applyNodeProps;
instance._applyProps(instance, props);
return instance;
}
createTextInstance(text, rootContainerInstance, hostContext, internalInstanceHandle) {
throw new Error('Text components are not supported for now in easeljs-react. Use "TextComponent" instead.');
}
finalizeInitialChildren(parentInstance, type, props, rootContainerInstance, hostContext) {
return false;
}
getChildHostContext(parentHostContext, type, rootContainerInstance) {
return kEmptyObject;
}
getPublicInstance(instance) {
return Object.assign(instance, {
getPublicInstance() {
return instance;
}
});
}
getRootHostContext(rootContainerInstance) {
return kEmptyObject;
}
prepareForCommit(containerInfo) {
// noop
}
prepareUpdate(instance, type, oldProps, newProps, rootContainerInstance, hostContext) {
return UPDATE_SIGNAL;
}
resetAfterCommit(containerInfo) {
}
scheduleDeferredCallback(callback, options) {
}
setTimeout(handler, timeout) {
return undefined;
}
shouldDeprioritizeSubtree(type, props) {
return false;
}
shouldSetTextContent(type, props) {
return false;
}
appendChild(parentInstance, child) {
if (child.parent === parentInstance) {
parentInstance.setChildIndex(child, parentInstance.numChildren - 1);
}
else {
parentInstance.addChild(child);
}
updatePicture(parentInstance);
}
appendChildToContainer(parentInstance, child) {
if (child.parent === parentInstance) {
parentInstance.setChildIndex(child, parentInstance.numChildren - 1);
}
else {
parentInstance.addChild(child);
}
updatePicture(parentInstance);
}
insertBefore(parentInstance, child, beforeChild) {
if (child === beforeChild) {
throw new Error('easeljs-react: Can not insert node before itself');
}
if (child.parent) {
child.parent.removeChild(child);
}
const idx = parentInstance.getChildIndex(beforeChild);
parentInstance.addChildAt(child, idx);
updatePicture(parentInstance);
}
insertInContainerBefore(parentInstance, child, beforeChild) {
if (child === beforeChild) {
throw new Error('easeljs-react: Can not insert node before itself');
}
if (child.parent) {
child.parent.removeChild(child);
}
const idx = parentInstance.getChildIndex(beforeChild);
parentInstance.addChildAt(child, idx);
updatePicture(parentInstance);
}
removeChild(parentInstance, child) {
child.removeAllEventListeners();
parentInstance.removeChild(child);
updatePicture(parentInstance);
}
removeChildFromContainer(parentInstance, child) {
child.removeAllEventListeners();
parentInstance.removeChild(child);
updatePicture(parentInstance);
}
commitTextUpdate(textInstance, oldText, newText) {
textInstance.text = newText;
updatePicture(textInstance.parent);
}
commitMount(instance, type, newProps) {
// Noop
}
commitUpdate(instance, updatePayload, type, oldProps, newProps, fiberInstance) {
instance._applyProps(instance, newProps, oldProps);
}
now() {
return now_1.now();
}
}
const hostConfig = new HostConfigImpl();
const Renderer = ReactReconciler(hostConfig);
const foundDevTools = Renderer.injectIntoDevTools({
findFiberByHostInstance: dom_tree_1.getClosestInstanceFromNode,
bundleType: process.env.NODE_ENV !== 'production' ? 1 : 0,
version: React.version,
rendererPackageName: 'easeljs-react',
getInspectorDataForViewTag: (...args) => {
console.log(args);
return { name: "noop" };
}
});
class StageComponentImpl extends React.Component {
constructor() {
super(...arguments);
this.setCanvasRef = n => this._canvas = n;
}
get stage() {
return this._stage;
}
componentDidMount() {
this._stage = new easeljs_1.Stage(this._canvas);
applyNodeProps(this._stage, this.props);
this._mountNode = Renderer.createContainer(this._stage, false, false);
Renderer.updateContainer(this.props.children, this._mountNode, this, () => {
if (this.props.onContainerMounted) {
this.props.onContainerMounted(this._stage);
}
});
}
componentDidUpdate(prevProps, prevState) {
applyNodeProps(this._stage, this.props, prevProps);
Renderer.updateContainer(this.props.children, this._mountNode, this, () => {
if (this.props.onContainerUpdated) {
this.props.onContainerUpdated(this._stage);
}
});
}
componentWillUnmount() {
Renderer.updateContainer(null, this._mountNode, this, null);
this._stage.clear();
}
render() {
const { width, height } = this.props;
return (React.createElement("canvas", { className: this.props.className, style: this.props.style, ref: this.setCanvasRef, width: ~~width, height: ~~height }));
}
}
exports.StageComponent = StageComponentImpl;
__export(require("./types"));