diff --git a/package.json b/package.json index 39eb5a8..fb04974 100644 --- a/package.json +++ b/package.json @@ -22,10 +22,13 @@ "url": "https://github.com/ProjectSeptemberInc/gl-react-core/issues" }, "homepage": "https://github.com/ProjectSeptemberInc/gl-react-core#readme", + "peerDependencies": { + }, "dependencies": { "babelify": "^6.3.0", "envify": "^3.4.0", - "invariant": "^2.1.0" + "invariant": "^2.2.0", + "events": "1.1.0" }, "devDependencies": { "eslint": "^1.6.0", diff --git a/react-native.js b/react-native.js new file mode 100644 index 0000000..db06996 --- /dev/null +++ b/react-native.js @@ -0,0 +1 @@ +require("./src/react-runtime-mutate").set(require("react-native")); diff --git a/react.js b/react.js new file mode 100644 index 0000000..e968ca2 --- /dev/null +++ b/react.js @@ -0,0 +1 @@ +require("./src/react-runtime-mutate").set(require("react")); diff --git a/src/Node.js b/src/Node.js new file mode 100644 index 0000000..190712f --- /dev/null +++ b/src/Node.js @@ -0,0 +1,27 @@ +const React = require("./react-runtime"); +const { Component, PropTypes } = React; +const invariant = require("invariant"); + +class Node extends Component { + render () { + invariant( + false, + "GL.Node elements can only be used as children of GL.Surface / GL.Node and should not be rendered" + ); + } +} + +Node.isGLNode = true; + +Node.displayName = "GL.Node"; + +Node.propTypes = { + shader: PropTypes.number.isRequired, + uniforms: PropTypes.object, + children: PropTypes.node, + width: PropTypes.number, + height: PropTypes.number, + preload: PropTypes.bool +}; + +module.exports = Node; diff --git a/src/Shaders.js b/src/Shaders.js new file mode 100644 index 0000000..2ca8814 --- /dev/null +++ b/src/Shaders.js @@ -0,0 +1,49 @@ +const {EventEmitter} = require("events"); +const invariant = require("invariant"); + +let _uid = 1; +const names = {}; +const shaders = {}; + +const Shaders = { + create (obj) { + invariant(typeof obj === "object", "config must be an object"); + const result = {}; + for (let key in obj) { + const shader = obj[key]; + invariant(typeof shader === "object" && typeof shader.frag === "string", + "invalid shader given to Shaders.create(). A valid shader is a { frag: String }"); + const id = _uid ++; + if (!shader.name) shader.name = key; + names[id] = shader.name; + shaders[id] = shader; + this.emit("add", id, shader); + result[key] = id; + } + return result; + }, + remove (id) { + invariant(id in shaders, "There is no such shader '%s'", id); + delete shaders[id]; + delete names[id]; + this.emit("remove", id); + }, + get (id) { + return shaders[id]; + }, + getName (id) { + return names[id]; + }, + list () { + return Object.keys(shaders); + }, + exists (id) { + return typeof id === "number" && id >= 1 && id < _uid; + }, + + ...EventEmitter.prototype +}; + +EventEmitter.call(Shaders); + +module.exports = Object.freeze(Shaders); diff --git a/src/Uniform.js b/src/Uniform.js new file mode 100644 index 0000000..beefb7d --- /dev/null +++ b/src/Uniform.js @@ -0,0 +1,23 @@ +const React = require("./react-runtime"); +const { Component, PropTypes } = React; +const invariant = require("invariant"); + +class Uniform extends Component { + render () { + invariant( + false, + "GL.Uniform elements are for GL.Node configuration only and should not be rendered" + ); + } +} + +Uniform.isGLUniform = true; + +Uniform.displayName = "GL.Uniform"; + +Uniform.propTypes = { + children: PropTypes.any.isRequired, + name: PropTypes.string.isRequired +}; + +module.exports = Uniform; diff --git a/src/createComponent.js b/src/createComponent.js index 3338630..e1fe63d 100644 --- a/src/createComponent.js +++ b/src/createComponent.js @@ -1,39 +1,36 @@ +const React = require("./react-runtime"); const invariant = require("invariant"); -const glViewMethods = require("./glViewMethods"); - -module.exports = function (React, View) { - function createComponent (renderGLView, staticFields) { - invariant(typeof renderGLView === "function", - "GL.createComponent(props => glview) must have a function in parameter"); - class GLComponent extends React.Component { - constructor (props, context) { - super(props, context); - glViewMethods.forEach(this._delegateMethod, this); - } - _delegateMethod (methodname) { - const self = this; - this[methodname] = function () { - const glViewRef = self.refs._; - invariant(glViewRef, "glView has been rendered"); - return glViewRef[methodname].apply(glViewRef, arguments); - }; - } - render () { - const glView = renderGLView(this.props); - invariant(glView && (glView.type === View || glView.type.isGLComponent), - "The GL.createComponent function parameter must return a GL.View or another GL Component"); - return React.cloneElement(glView, { ...glView.props, ref: "_" }); - } + +module.exports = function createComponent (renderGLNode, staticFields) { + + invariant(typeof renderGLNode === "function", + "GL.createComponent(props => glnode) must have a function in parameter"); + + class GLComponent extends React.Component { + render () { + const glNode = renderGLNode(this.props); + + invariant(glNode && glNode.type && (glNode.type.isGLNode || glNode.type.isGLComponent), + "%s: The GL.createComponent function parameter must return a GL.Node or "+ + "another GL Component", GLComponent.displayName); + + return glNode; } - GLComponent.isGLComponent = true; - GLComponent.displayName = renderGLView.name || ""; - if (staticFields) { - invariant(typeof staticFields === "object", "second parameter of createComponent must be an object of static fields to set in the React component. (example: propTypes, displayName)"); - for (let key in staticFields) { - GLComponent[key] = staticFields[key]; - } + } + + GLComponent.isGLComponent = true; + + GLComponent.displayName = renderGLNode.name || ""; + + if (staticFields) { + invariant(typeof staticFields === "object", + "second parameter of createComponent must be an object of static fields "+ + "to set in the React component. (example: propTypes, displayName)"); + + for (let key in staticFields) { + GLComponent[key] = staticFields[key]; } - return GLComponent; } - return createComponent; + + return GLComponent; }; diff --git a/src/createComponentDeprecated.js b/src/createComponentDeprecated.js deleted file mode 100644 index 7e495d6..0000000 --- a/src/createComponentDeprecated.js +++ /dev/null @@ -1,16 +0,0 @@ -const invariant = require("invariant"); -const glViewMethods = require("./glViewMethods"); -module.exports = function (React) { - class GLComponent extends React.Component { - constructor (props, context) { - super(props, context); - glViewMethods.forEach(methodname => { - if (!this[methodname]) this[methodname] = () => invariant(true, "'%s' method is not available in deprecated GL.Component. Use GL.createComponent(props => glView) instead"); - }); - if (process.env.NODE_ENV !== "production") - console.error("GL.Component class is deprecated. Use GL.createComponent(props => glView) function instead"); // eslint-disable-line no-console - } - } - GLComponent.isGLComponent = true; - return GLComponent; -}; diff --git a/src/createShaders.js b/src/createShaders.js deleted file mode 100644 index 676c3f4..0000000 --- a/src/createShaders.js +++ /dev/null @@ -1,36 +0,0 @@ -const invariant = require("invariant"); - -module.exports = function (recordShader) { - let _uid = 1; - - const names = {}; - - const Shaders = { - create: function (obj) { - invariant(typeof obj === "object", "config must be an object"); - const result = {}; - for (let key in obj) { - const shader = obj[key]; - invariant(typeof shader === "object" && typeof shader.frag === "string", - "invalid shader given to Shaders.create(). A valid shader is a { frag: String }"); - const id = _uid ++; - if (!shader.name) shader.name = key; - names[id] = shader.name; - recordShader(id, shader); - result[key] = id; - } - return result; - }, - getName: function (id) { - return names[id]; - }, - list: function () { - return Object.keys(names); - }, - exists: function (id) { - return typeof id === "number" && id >= 1 && id < _uid; - } - }; - - return Shaders; -}; diff --git a/src/createSurface.js b/src/createSurface.js new file mode 100644 index 0000000..4c8e2b9 --- /dev/null +++ b/src/createSurface.js @@ -0,0 +1,111 @@ +const React = require("./react-runtime"); +const { + Component, + PropTypes +} = React; +const invariant = require("invariant"); +const { fill, resolve, build } = require("./data"); +const findGLNodeInGLComponentChildren = require("./data/findGLNodeInGLComponentChildren"); + +function logResult (data, contentsVDOM) { + if (typeof console !== "undefined" && + console.debug // eslint-disable-line + ) { + console.debug("GL.Surface rendered with", data, contentsVDOM); // eslint-disable-line no-console + } +} + +module.exports = function (renderVcontainer, renderVcontent, renderVGL) { + + class GLSurface extends Component { + constructor (props, context) { + super(props, context); + this._renderId = 1; + } + getGLCanvas () { + return this.refs.canvas; + } + captureFrame (callback) { + const c = this.getGLCanvas(); + invariant(c && c.captureFrame, "captureFrame() should be implemented by GLCanvas"); + invariant(typeof callback === "function", "captureFrame(cb) should have a callback function in first parameter"); + return c.captureFrame.call(c, callback); + } + render() { + const renderId = this._renderId ++; + const props = this.props; + const { + style, + width, + height, + children, + debug, + preload, + opaque, + visibleContent, + eventsThrough, + ...restProps + } = props; + + const { via, childGLNode } = + findGLNodeInGLComponentChildren(children); + + invariant(childGLNode, "GL.Surface must have in children a GL.Node or a GL Component"); + + const { data, contentsVDOM, imagesToPreload } = + resolve( + fill( + build( + childGLNode, + width, + height, + preload, + via))); + + if (debug) logResult(data, contentsVDOM); + + return renderVcontainer( + { width, height, style, visibleContent, eventsThrough }, + contentsVDOM.map((vdom, i) => + renderVcontent(data.width, data.height, i, vdom, { visibleContent })), + renderVGL({ + ...restProps, // eslint-disable-line no-undef + width, + height, + data, + nbContentTextures: contentsVDOM.length, + imagesToPreload, + renderId, + opaque, + visibleContent, + eventsThrough + }) + ); + } + } + + GLSurface.displayName = "GL.Surface"; + + GLSurface.propTypes = { + width: PropTypes.number.isRequired, + height: PropTypes.number.isRequired, + children: PropTypes.element.isRequired, + opaque: PropTypes.bool, + preload: PropTypes.bool, + autoRedraw: PropTypes.bool, + eventsThrough: PropTypes.bool, + visibleContent: PropTypes.bool, + onLoad: PropTypes.func, + onProgress: PropTypes.func + }; + + GLSurface.defaultProps = { + opaque: true, + preload: false, + autoRedraw: false, + eventsThrough: false, + visibleContent: false + }; + + return GLSurface; +}; diff --git a/src/createUniform.js b/src/createUniform.js deleted file mode 100644 index c8e10dd..0000000 --- a/src/createUniform.js +++ /dev/null @@ -1,21 +0,0 @@ -const invariant = require("invariant"); - -module.exports = function (React) { - const { Component, PropTypes } = React; - - class Uniform extends Component { - render () { - invariant( - false, - "GL.Uniform elements are for GL.View configuration only and should not be rendered" - ); - } - } - Uniform.displayName = "GL.Uniform"; - Uniform.propTypes = { - children: PropTypes.any.isRequired, - name: PropTypes.string.isRequired - }; - - return Uniform; -}; diff --git a/src/createView.js b/src/createView.js deleted file mode 100644 index b1e4458..0000000 --- a/src/createView.js +++ /dev/null @@ -1,93 +0,0 @@ -const invariant = require("invariant"); -const { fill, resolve, createBuild } = require("./data"); - -function logResult (data, contentsVDOM) { - if (typeof console !== "undefined" && - console.debug // eslint-disable-line - ) { - console.debug("GL.View rendered with", data, contentsVDOM); // eslint-disable-line no-console - } -} - -module.exports = function (React, Shaders, Uniform, renderVcontainer, renderVcontent, renderVGL) { - const { - Component, - PropTypes - } = React; - - let build; // will be set after GLView class defined. - - class GLView extends Component { - constructor (props, context) { - super(props, context); - this._renderId = 1; - } - getGLCanvas () { - return this.refs.canvas; - } - captureFrame (callback) { - const c = this.getGLCanvas(); - invariant(c && c.captureFrame, "captureFrame() should be implemented by GLCanvas"); - invariant(typeof callback === "function", "captureFrame(cb) should have a callback function in first parameter"); - return c.captureFrame.call(c, callback); - } - render() { - const renderId = this._renderId ++; - const props = this.props; - const { style, width, height, children, shader, uniforms, debug, preload, opaque, visibleContent, eventsThrough, ...restProps } = props; - - invariant(width && height && width>0 && height>0, "width and height are required for the root GLView"); - - const {data, contentsVDOM, imagesToPreload} = - resolve( - fill( - build( - shader, - uniforms, - width, - height, - children, - preload||false, - []))); - - if (debug) logResult(data, contentsVDOM); - - return renderVcontainer( - { width, height, style, visibleContent, eventsThrough }, - contentsVDOM.map((vdom, i) => renderVcontent(data.width, data.height, i, vdom, { visibleContent })), - renderVGL({ - ...restProps, // eslint-disable-line no-undef - width, - height, - data, - nbContentTextures: contentsVDOM.length, - imagesToPreload, - renderId, - opaque, - visibleContent, - eventsThrough - }) - ); - } - } - - GLView.displayName = "GL.View"; - GLView.propTypes = { - shader: PropTypes.number.isRequired, - width: PropTypes.number, - height: PropTypes.number, - uniforms: PropTypes.object, - opaque: PropTypes.bool, - preload: PropTypes.bool, - autoRedraw: PropTypes.bool, - eventsThrough: PropTypes.bool, - visibleContent: PropTypes.bool - }; - GLView.defaultProps = { - opaque: true - }; - - build = createBuild(React, Shaders, Uniform, GLView); - - return GLView; -}; diff --git a/src/data/build.js b/src/data/build.js index 6f8353f..2e4b904 100644 --- a/src/data/build.js +++ b/src/data/build.js @@ -1,133 +1,108 @@ +const React = require("../react-runtime"); const invariant = require("invariant"); +const Uniform = require("../Uniform"); +const Shaders = require("../Shaders"); const TextureObjects = require("./TextureObjects"); const isNonSamplerUniformValue = require("./isNonSamplerUniformValue"); +const findGLNodeInGLComponentChildren = require("./findGLNodeInGLComponentChildren"); //// build: converts the VDOM gl-react DSL into an internal data tree. -module.exports = function (React, Shaders, Uniform, GLView) { - // FIXME: maybe with React 0.14, we will be able to make this library depending on React so we don't have to do this closure +module.exports = function build (GLNode, parentWidth, parentHeight, parentPreload, via) { + const props = GLNode.props; + const shader = props.shader; + const GLNodeUniforms = props.uniforms; + const width = props.width || parentWidth; + const height = props.height || parentHeight; + const GLNodeChildren = props.children; + const preload = "preload" in props ? props.preload : preload; - function pickReactFirstChild (children) { - return React.Children.count(children) === 1 ? - (children instanceof Array ? children[0] : children) : - null; - } + invariant(Shaders.exists(shader), "Shader #%s does not exists", shader); - function unfoldGLComponent (c, glComponentNameArray) { - const Class = c.type; - if (!(Class.isGLComponent)) return; - const instance = new Class(); // FIXME: React might eventually improve to ease the work done here. see https://github.com/facebook/react/issues/4697#issuecomment-134335822 - instance.props = c.props; - const child = pickReactFirstChild(instance.render()); - const glComponentName = Class.displayName || Class.name || ""; - glComponentNameArray.push(glComponentName); - return child; - } + const shaderName = Shaders.getName(shader); - function findGLViewInGLComponentChildren (children) { - // going down the VDOM tree, while we can unfold GLComponent - const via = []; - for (let c = children; c && typeof c.type === "function"; c = unfoldGLComponent(c, via)) { - if (c.type === GLView) - return { childGLView: c, via }; // found a GLView - } - } - - return function build (shader, glViewUniforms, width, height, glViewChildren, preload, via) { - invariant(Shaders.exists(shader), "Shader #%s does not exists", shader); - - const shaderName = Shaders.getName(shader); - - const uniforms = { ...glViewUniforms }; - const children = []; - const contents = []; + const uniforms = { ...GLNodeUniforms }; + const children = []; + const contents = []; - React.Children.forEach(glViewChildren, child => { - invariant(child.type === Uniform, "(Shader '%s') GL.View can only contains children of type GL.Uniform. Got '%s'", shaderName, child.type && child.type.displayName || child); - const { name, children, ...opts } = child.props; - invariant(typeof name === "string" && name, "(Shader '%s') GL.Uniform must define an name String", shaderName); - invariant(!glViewUniforms || !(name in glViewUniforms), "(Shader '%s') The uniform '%s' set by GL.Uniform must not be in {uniforms} props", shaderName); - invariant(!(name in uniforms), "(Shader '%s') The uniform '%s' set by GL.Uniform must not be defined in another GL.Uniform", shaderName); - uniforms[name] = !children || children.value ? children : { value: children, opts }; // eslint-disable-line no-undef - }); + React.Children.forEach(GLNodeChildren, child => { + invariant(child.type === Uniform, "(Shader '%s') GL.Node can only contains children of type GL.Uniform. Got '%s'", shaderName, child.type && child.type.displayName || child); + const { name, children, ...opts } = child.props; + invariant(typeof name === "string" && name, "(Shader '%s') GL.Uniform must define an name String", shaderName); + invariant(!GLNodeUniforms || !(name in GLNodeUniforms), "(Shader '%s') The uniform '%s' set by GL.Uniform must not be in {uniforms} props", shaderName); + invariant(!(name in uniforms), "(Shader '%s') The uniform '%s' set by GL.Uniform must not be defined in another GL.Uniform", shaderName); + uniforms[name] = !children || children.value ? children : { value: children, opts }; // eslint-disable-line no-undef + }); - Object.keys(uniforms).forEach(name => { - let value = uniforms[name]; - if (isNonSamplerUniformValue(value)) return; + Object.keys(uniforms).forEach(name => { + let value = uniforms[name]; + if (isNonSamplerUniformValue(value)) return; - let opts, typ = typeof value; + let opts, typ = typeof value; - if (value && typ === "object" && !value.prototype && "value" in value) { - // if value has a value field, we tread this field as the value, but keep opts in memory if provided - if (typeof value.opts === "object") { - opts = value.opts; - } - value = value.value; - typ = typeof value; + if (value && typ === "object" && !value.prototype && "value" in value) { + // if value has a value field, we tread this field as the value, but keep opts in memory if provided + if (typeof value.opts === "object") { + opts = value.opts; } + value = value.value; + typ = typeof value; + } - if (!value) { - // falsy value are accepted to indicate blank texture - uniforms[name] = value; - } - else if (typ === "string") { - // uri specified as a string - uniforms[name] = TextureObjects.withOpts(TextureObjects.URI({ uri: value }), opts); - } - else if (typ === "object" && typeof value.uri === "string") { - // uri specified in an object, we keep all other fields for RN "local" image use-case - uniforms[name] = TextureObjects.withOpts(TextureObjects.URI(value), opts); - } - else if (typ === "object" && value.data && value.shape && value.stride) { - // ndarray kind of texture - uniforms[name] = TextureObjects.withOpts(TextureObjects.NDArray(value), opts); - } - else if(typ === "object" && (value instanceof Array ? React.isValidElement(value[0]) : React.isValidElement(value))) { - // value is a VDOM or array of VDOM - const res = findGLViewInGLComponentChildren(value); - if (res) { - const { childGLView, via } = res; - // We have found a GL.View children, we integrate it in the tree and recursively do the same - const childProps = childGLView.props; - children.push({ - vdom: value, - uniform: name, - data: build( - childProps.shader, - childProps.uniforms, - childProps.width || width, - childProps.height || height, - childProps.children, - "preload" in childProps ? childProps.preload : preload, - via) - }); - } - else { - // in other cases VDOM, we will use child as a content - contents.push({ - vdom: value, - uniform: name, - opts - }); - } + if (!value) { + // falsy value are accepted to indicate blank texture + uniforms[name] = value; + } + else if (typ === "string") { + // uri specified as a string + uniforms[name] = TextureObjects.withOpts(TextureObjects.URI({ uri: value }), opts); + } + else if (typ === "object" && typeof value.uri === "string") { + // uri specified in an object, we keep all other fields for RN "local" image use-case + uniforms[name] = TextureObjects.withOpts(TextureObjects.URI(value), opts); + } + else if (typ === "object" && value.data && value.shape && value.stride) { + // ndarray kind of texture + uniforms[name] = TextureObjects.withOpts(TextureObjects.NDArray(value), opts); + } + else if(typ === "object" && (value instanceof Array ? React.isValidElement(value[0]) : React.isValidElement(value))) { + // value is a VDOM or array of VDOM + const res = findGLNodeInGLComponentChildren(value); + if (res) { + const { childGLNode, via } = res; + // We have found a GL.Node children, we integrate it in the tree and recursively do the same + + children.push({ + vdom: value, + uniform: name, + data: build(childGLNode, width, height, preload, via) + }); } else { - // in any other case, it is an unrecognized invalid format - delete uniforms[name]; - if (typeof console !== "undefined" && console.error) console.error("invalid uniform '"+name+"' value:", value); // eslint-disable-line no-console - invariant(false, "Shader #%s: Unrecognized format for uniform '%s'", shader, name); + // in other cases VDOM, we will use child as a content + contents.push({ + vdom: value, + uniform: name, + opts + }); } - }); + } + else { + // in any other case, it is an unrecognized invalid format + delete uniforms[name]; + if (typeof console !== "undefined" && console.error) console.error("invalid uniform '"+name+"' value:", value); // eslint-disable-line no-console + invariant(false, "Shader '%s': Unrecognized format for uniform '%s'", shaderName, name); + } + }); - return { - shader, - uniforms, - width, - height, - children, - contents, - preload, - via - }; + return { + shader, + uniforms, + width, + height, + children, + contents, + preload, + via }; }; diff --git a/src/data/fill.js b/src/data/fill.js index bbd24d9..c25116f 100644 --- a/src/data/fill.js +++ b/src/data/fill.js @@ -3,7 +3,7 @@ function fill (dataTree) { function fillRec (node) { // we compute all the descendants vdom under the current node - let descendantsVDOM = [], descendantsVDOMData = []; + let descendantsVDOM = [ node.vdom ], descendantsVDOMData = [ node.data ]; const newChildren = node.data.children.map(node => { const res = fillRec(node); if (descendantsVDOM.indexOf(res.vdom) === -1) { diff --git a/src/data/findGLNodeInGLComponentChildren.js b/src/data/findGLNodeInGLComponentChildren.js new file mode 100644 index 0000000..0f26a81 --- /dev/null +++ b/src/data/findGLNodeInGLComponentChildren.js @@ -0,0 +1,10 @@ +const unfoldGLComponent = require("./unfoldGLComponent"); + +module.exports = function findGLNodeInGLComponentChildren (children) { + // going down the VDOM tree, while we can unfold GLComponent + const via = []; + for (let c = children; c && typeof c.type === "function"; c = unfoldGLComponent(c, via)) { + if (c.type.isGLNode) + return { childGLNode: c, via }; // found a GLNode + } +}; diff --git a/src/data/index.js b/src/data/index.js index ce98c68..d14946e 100644 --- a/src/data/index.js +++ b/src/data/index.js @@ -1,6 +1,6 @@ module.exports = { - createBuild: require("./build"), + build: require("./build"), fill: require("./fill"), resolve: require("./resolve") }; diff --git a/src/data/pickReactFirstChild.js b/src/data/pickReactFirstChild.js new file mode 100644 index 0000000..ebe1dfc --- /dev/null +++ b/src/data/pickReactFirstChild.js @@ -0,0 +1,7 @@ +const React = require("../react-runtime"); + +module.exports = function pickReactFirstChild (children) { + return React.Children.count(children) === 1 ? + (children instanceof Array ? children[0] : children) : + null; +}; diff --git a/src/data/resolve.js b/src/data/resolve.js index 082c083..ddc6854 100644 --- a/src/data/resolve.js +++ b/src/data/resolve.js @@ -7,7 +7,7 @@ const extractImages = require("./extractImages"); const uniqImages = require("./uniqImages"); ///// resolve: takes the output of fill(build(*)) to generate the final data tree -// The algorithm simplifies the data tree to use shared framebuffers if some VDOM is duplicated in the tree (e.g: content / GL.View) +// The algorithm simplifies the data tree to use shared framebuffers if some VDOM is duplicated in the tree (e.g: content / GL.Node) function resolve (dataTree) { let imagesToPreload = []; diff --git a/src/data/unfoldGLComponent.js b/src/data/unfoldGLComponent.js new file mode 100644 index 0000000..af8f312 --- /dev/null +++ b/src/data/unfoldGLComponent.js @@ -0,0 +1,12 @@ +const pickReactFirstChild = require("./pickReactFirstChild"); + +module.exports = function unfoldGLComponent (c, glComponentNameArray) { + const Class = c.type; + if (!(Class.isGLComponent)) return; + const instance = new Class(); // FIXME: React might eventually improve to ease the work done here. see https://github.com/facebook/react/issues/4697#issuecomment-134335822 + instance.props = c.props; + const child = pickReactFirstChild(instance.render()); + const glComponentName = Class.displayName || Class.name || ""; + glComponentNameArray.push(glComponentName); + return child; +}; diff --git a/src/glViewMethods.json b/src/glViewMethods.json deleted file mode 100644 index 287a851..0000000 --- a/src/glViewMethods.json +++ /dev/null @@ -1,4 +0,0 @@ -[ - "getGLCanvas", - "captureFrame" -] diff --git a/src/index.js b/src/index.js index c54e17e..2f96af7 100644 --- a/src/index.js +++ b/src/index.js @@ -1,13 +1,13 @@ const createComponent = require("./createComponent"); -const createComponentDeprecated = require("./createComponentDeprecated"); -const createShaders = require("./createShaders"); -const createUniform = require("./createUniform"); -const createView = require("./createView"); +const createSurface = require("./createSurface"); +const Node = require("./Node"); +const Shaders = require("./Shaders"); +const Uniform = require("./Uniform"); module.exports = { createComponent, - createComponentDeprecated, - createShaders, - createUniform, - createView + createSurface, + Node, + Shaders, + Uniform }; diff --git a/src/react-runtime-mutate.js b/src/react-runtime-mutate.js new file mode 100644 index 0000000..695342f --- /dev/null +++ b/src/react-runtime-mutate.js @@ -0,0 +1,13 @@ +const invariant = require("invariant"); +let runtime; +function set (React) { + if (React.version) { // RN don't provide version... + const version = React.version.split("."); + invariant(version[0]==="0" && parseInt(version[1], 10) >= 14, "React version must be at least 0.14.x. got: %s", React.version); + } + runtime = React; +} +module.exports = { + set, + get: () => runtime +}; diff --git a/src/react-runtime.js b/src/react-runtime.js new file mode 100644 index 0000000..846b99e --- /dev/null +++ b/src/react-runtime.js @@ -0,0 +1,19 @@ +const runtime = require("./react-runtime-mutate").get(); +if (!runtime) { + console.warn( // eslint-disable-line no-console +`Please prepend in your JavaScript entry point one of following imports: + +${"require"}("gl-react/react") // for React + + OR + +${"require"}("gl-react/react-native") // for React Native + + +Make sure to do this BEFORE any other imports. (that are gl-react related) + +> Note: This mechanism will be removed once React Native depends on React`); + + throw new Error("gl-react: React instance not available at runtime. Please read instructions"); +} +module.exports = runtime;