src/lib/descriptors/decorators/resource.js
import invariant from 'fbjs/lib/invariant';
import warning from 'fbjs/lib/warning';
import PropTypes from 'react/lib/ReactPropTypes';
import ResourceContainer from '../../Resources/ResourceContainer';
import THREEElementDescriptor from '../THREEElementDescriptor';
/**
* Resource decorator.
* Allows descriptors to be slotted into the <resources/> component.
*
* @param descriptor The descriptor to be patched
* @returns {ResourceDescriptor} the modified descriptor class
*/
function resource(descriptor) {
class ResourceDescriptor extends descriptor {
static displayName = `${descriptor.displayName || descriptor.name}`;
// used for docs
isResource = true;
constructor(react3RendererInstance) {
super(react3RendererInstance);
this.hasProp('resourceId', {
type: PropTypes.string,
updateInitial: true,
initialOnly: true,
update: (threeObject, resourceId, hasProp) => {
if (hasProp) {
threeObject.userData._resourceId = resourceId;
if (!threeObject.userData._hasReferences) {
threeObject.userData._hasReferences = true;
threeObject.userData._references = [];
}
}
},
default: '',
});
}
applyInitialProps(threeObject, props) {
super.applyInitialProps(threeObject, props);
}
setParent(threeObject, parentObject3D) {
if (parentObject3D instanceof ResourceContainer) {
if (process.env.NODE_ENV !== 'production') {
invariant(!!threeObject.userData._resourceId,
'All resources inside <resources> should have the "resourceId" property. ' +
`Current resource: <${threeObject.userData.react3internalComponent._elementType}>`);
} else {
invariant(!!threeObject.userData._resourceId);
}
// still let it be mounted to root
THREEElementDescriptor.prototype.setParent.call(this, threeObject, parentObject3D);
} else {
if (process.env.NODE_ENV !== 'production') {
warning(!threeObject.userData._resourceId,
`Found <${threeObject.userData.react3internalComponent._elementType}> `
+ 'with a resourceId property, ' +
'but it was not placed within a <resources/> element.');
}
super.setParent(threeObject, parentObject3D);
}
}
highlight(threeObject) {
let result;
if (threeObject.userData._resourceId) {
// it's a resource. Let's highlight all references.
threeObject.userData.events.emit('highlight', {
uuid: threeObject.uuid,
boundingBoxFunc: () => threeObject.userData._references
.reduce((boxes, objectWithReference) => {
const boxesForReference =
objectWithReference.userData._descriptor
.getBoundingBoxes(objectWithReference);
if (process.env.NODE_ENV !== 'production') {
invariant(boxesForReference.length > 0, 'No boxes found for resource.');
} else {
invariant(boxesForReference.length > 0);
}
return boxes.concat(boxesForReference);
}, []),
});
} else {
result = super.highlight(threeObject);
}
return result;
}
hideHighlight(threeObject) {
let result;
if (threeObject.userData._resourceId) {
threeObject.userData.events.emit('hideHighlight');
} else {
result = super.hideHighlight(threeObject);
}
return result;
}
}
return ResourceDescriptor;
}
module.exports = resource;