diff --git a/packages/cookbook-rn-shared/src/About.js b/packages/cookbook-rn-shared/src/About.js index 0e238ad..f3515e8 100644 --- a/packages/cookbook-rn-shared/src/About.js +++ b/packages/cookbook-rn-shared/src/About.js @@ -1,4 +1,3 @@ - import React, { Component } from "react"; import { StyleSheet, @@ -6,63 +5,63 @@ import { ScrollView, View, Platform, - Linking, + Linking } from "react-native"; import getGLReactImplementation from "./gl-react-implementation"; const { Surface, name } = getGLReactImplementation(); -import {Node, Shaders, GLSL, Backbuffer, LinearCopy} from "gl-react"; +import { Node, Shaders, GLSL, Uniform, LinearCopy } from "gl-react"; import timeLoop from "./HOC/timeLoop"; const styles = StyleSheet.create({ root: { flex: 1, - backgroundColor: "#fff", + backgroundColor: "#fff" }, container: { paddingVertical: 20, - flexDirection: "column", + flexDirection: "column" }, list: { - flex: 1, + flex: 1 }, subHeader: { padding: 10, - backgroundColor: "#f9f9f9", + backgroundColor: "#f9f9f9" }, subHeaderText: { color: "#333", fontSize: 12, - fontStyle: "italic", + fontStyle: "italic" }, title: { flex: 1, flexDirection: "row", alignItems: "center", - justifyContent: "center", + justifyContent: "center" }, titleText: { fontWeight: "bold", color: "#fff", - fontSize: 18, + fontSize: 18 }, ex1: { - flexDirection: "column", + flexDirection: "column" }, code: { backgroundColor: "transparent", color: "#282c34", fontFamily: Platform.select({ android: "monospace", - ios: "Courier New", + ios: "Courier New" }), fontSize: 9, padding: 8, - width: 250, + width: 250 }, link: { fontSize: 14, - textDecorationLine: "underline", - }, + textDecorationLine: "underline" + } }); const shaders = Shaders.create({ @@ -81,14 +80,15 @@ void main () { }` }, HelloGL: { - // uniforms are variables from JS. We pipe blue uniform into blue output color + // uniforms are variables from JS. We pipe blue uniform into blue output color frag: GLSL` precision highp float; varying vec2 uv; uniform float red; void main() { gl_FragColor = vec4(red, uv.x, uv.y, 1.0); -}` }, +}` + }, Rotate: { frag: GLSL` precision highp float; @@ -102,20 +102,22 @@ void main() { p.x < 0.0 || p.x > 1.0 || p.y < 0.0 || p.y > 1.0 ? vec4(0.0) : texture2D(children, p); -}` } +}` + } }); -const MotionBlur = ({ children, persistence }: *) => +const MotionBlur = ({ children, persistence }: *) => ( ; + uniforms={{ children, backbuffer: Uniform.Backbuffer, persistence }} + /> +); // We can make a that will render the concrete class HelloGL extends Component { props: { - red: number, + red: number }; render() { const { red } = this.props; @@ -127,11 +129,13 @@ class Rotate extends Component { props: { scale: number, angle: number, - children: any, + children: any }; render() { const { angle, scale, children } = this.props; - return ; + return ( + + ); } } @@ -154,8 +158,7 @@ class Ex1 extends Component { - { -` + {` @@ -163,8 +166,7 @@ class Ex1 extends Component { -` - } +`} ); } @@ -174,24 +176,27 @@ const Ex1Loop = timeLoop(Ex1); class Link extends React.Component { render() { - const {url} = this.props; - return Linking.openURL(url)}> - {url} - ; + const { url } = this.props; + return ( + Linking.openURL(url)}> + {url} + + ); } } export default class Home extends React.Component { static route = { navigationBar: { - renderTitle: () => + renderTitle: () => ( {name} - }, + ) + } }; props: { - navigator: *, + navigator: * }; render() { return ( diff --git a/packages/cookbook-rn-shared/src/examples/gol/index.js b/packages/cookbook-rn-shared/src/examples/gol/index.js index 0bc73f7..a99c5ab 100644 --- a/packages/cookbook-rn-shared/src/examples/gol/index.js +++ b/packages/cookbook-rn-shared/src/examples/gol/index.js @@ -1,12 +1,13 @@ //@flow import React from "react"; -import {Backbuffer,Shaders,Node,GLSL,NearestCopy} from "gl-react"; -import getGLReactImplementation from "../../gl-react-implementation"; const { Surface } = getGLReactImplementation(); +import { Uniform, Shaders, Node, GLSL, NearestCopy } from "gl-react"; +import getGLReactImplementation from "../../gl-react-implementation"; +const { Surface } = getGLReactImplementation(); import timeLoop from "../../HOC/timeLoop"; export const shaders = Shaders.create({ InitGameOfLife: { -// returns white or black randomly + // returns white or black randomly frag: GLSL` precision highp float; // i @@ -20,7 +21,7 @@ void main() { }` }, GameOfLife: { -// implement Game Of Life. + // implement Game Of Life. frag: GLSL` precision highp float; varying vec2 uv; @@ -48,36 +49,37 @@ const refreshEveryTicks = 20; export const GameOfLife = ({ tick }) => { // Changing size is "destructive" and will reset the Game of Life state - const size = 16 * (1+Math.floor(tick/refreshEveryTicks)); + const size = 16 * (1 + Math.floor(tick / refreshEveryTicks)); // However, we can conditionally change shader/uniforms, // React reconciliation will preserve the same instance, // and our Game of Life state will get preserved! - return tick%refreshEveryTicks===0 - ? to draw in sync each componentDidUpdate time - /> - : ; + return tick % refreshEveryTicks === 0 + ? to draw in sync each componentDidUpdate time + /> + : ; }; const GameOfLifeLoop = timeLoop(GameOfLife, { refreshRate: 20 }); -export default ({ width }) => +export default ({ width }) => ( +); diff --git a/packages/cookbook-rn-shared/src/examples/golglider/index.js b/packages/cookbook-rn-shared/src/examples/golglider/index.js index 6bf5561..0d7a0b5 100644 --- a/packages/cookbook-rn-shared/src/examples/golglider/index.js +++ b/packages/cookbook-rn-shared/src/examples/golglider/index.js @@ -1,6 +1,6 @@ //@flow import React, { Component } from "react"; -import { Backbuffer, Node, NearestCopy } from "gl-react"; +import { Uniform, Node, NearestCopy } from "gl-react"; import getGLReactImplementation from "../../gl-react-implementation"; const { Surface } = getGLReactImplementation(); import { shaders } from "../gol"; @@ -16,8 +16,8 @@ const GameOfLifeLoop = timeLoop( backbuffering sync uniforms={{ - t: tick === 0 ? gliderGunImage : Backbuffer, - size, + t: tick === 0 ? gliderGunImage : Uniform.Backbuffer, + size }} /> ), @@ -32,7 +32,7 @@ export default class Example extends Component { style={{ width, height: width }} preload={[ // preload textures before starting rendering - gliderGunImage, + gliderGunImage ]} > diff --git a/packages/cookbook-rn-shared/src/examples/ibex/index.js b/packages/cookbook-rn-shared/src/examples/ibex/index.js index 8845b91..051ac3e 100644 --- a/packages/cookbook-rn-shared/src/examples/ibex/index.js +++ b/packages/cookbook-rn-shared/src/examples/ibex/index.js @@ -7,8 +7,9 @@ //@flow import React, { Component } from "react"; -import { Shaders, Node, GLSL, Backbuffer } from "gl-react"; -import getGLReactImplementation from "../../gl-react-implementation"; const { Surface } = getGLReactImplementation(); +import { Shaders, Node, GLSL, Uniform } from "gl-react"; +import getGLReactImplementation from "../../gl-react-implementation"; +const { Surface } = getGLReactImplementation(); import ndarray from "ndarray"; import timeLoop from "../../HOC/timeLoop"; @@ -339,7 +340,7 @@ void main () { class IBEXLogic extends Component { state = { - seed: Math.random(), + seed: Math.random() }; shouldComponentUpdate({ tick }) { return tick !== this.props.tick; @@ -351,61 +352,58 @@ class IBEXLogic extends Component { initialState, forestGrowFactor, waterFactor, - fireFactor, + fireFactor } = this.props; const { seed } = this.state; - let draw=false, drawPosition=[0,0], drawRadius=0, drawElement=0; + let draw = false, drawPosition = [0, 0], drawRadius = 0, drawElement = 0; let w = Math.random() < waterFactor, f = Math.random() < fireFactor; if (w && f) { if (Math.random() * waterFactor - Math.random() * fireFactor > 0) { f = false; - } - else { + } else { w = false; } } if (w) { draw = true; - drawPosition=[ - size[0]*Math.random(), - size[1]*(0.8 + 0.2 * Math.random()), + drawPosition = [ + size[0] * Math.random(), + size[1] * (0.8 + 0.2 * Math.random()) ]; drawRadius = 4; drawElement = 3; console.log(drawElement, drawPosition, drawPosition); - } - else if (f) { + } else if (f) { draw = true; - drawPosition=[ - size[0]*Math.random(), - 0, - ]; + drawPosition = [size[0] * Math.random(), 0]; drawRadius = 4; drawElement = 2; console.log(drawElement, drawPosition, drawPosition); } - return ; + return ( + + ); } } @@ -416,86 +414,89 @@ var colors = [ [0.40, 0.75, 0.90], // 3: water [0.60, 0.00, 0.00], // 4: volcano (fire spawner) [0.30, 0.60, 0.70], // 5: source (water spawner) - [0.15, 0.20, 0.27], // 6: wind left - [0.07, 0.12, 0.19], // 7: wind right - [0.20, 0.60, 0.20] // 8: grass (forest) + [0.15, 0.20, 0.27], // 6: wind left + [0.07, 0.12, 0.19], // 7: wind right + [0.20, 0.60, 0.20] // 8: grass (forest) ]; -const IBEXRender = ({ size, children: state }) => +const IBEXRender = ({ size, children: state }) => ( ; + /> +); -const Game = timeLoop(class extends Component { - state = { - tick: 0, - lastTickTime: this.props.time, - }; +const Game = timeLoop( + class extends Component { + state = { + tick: 0, + lastTickTime: this.props.time + }; - componentWillReceiveProps({ time, speed }) { - this.setState(({ tick, lastTickTime }) => { - const delta = 1000/speed; - if (time-lastTickTime > delta) { - return { - tick: tick + 1, - lastTickTime: lastTickTime + delta, - }; - } - }); + componentWillReceiveProps({ time, speed }) { + this.setState(({ tick, lastTickTime }) => { + const delta = 1000 / speed; + if (time - lastTickTime > delta) { + return { + tick: tick + 1, + lastTickTime: lastTickTime + delta + }; + } + }); + } + + render() { + const { + size, + initialState, + forestGrowFactor, + waterFactor, + fireFactor + } = this.props; + const { tick } = this.state; + return ( + + + + ); + } } - - render() { - const { - size, - initialState, - forestGrowFactor, - waterFactor, - fireFactor - } = this.props; - const { - tick, - } = this.state; - return - - ; - } -}); +); // This should be implemented in a shader (it's a cellular automaton too) // but it's how it was done in the game -function generate (startX: number, worldSize: [number,number]) { +function generate(startX: number, worldSize: [number, number]) { var worldPixelRawBuf = new Uint8Array(worldSize[0] * worldSize[1] * 4); var worldPixelBuf = new Uint8Array(worldSize[0] * worldSize[1]); var waterInGeneration = 0; var volcanoInGeneration = 0; var w = worldSize[0], h = worldSize[1]; - function step (a, b, x) { - return Math.max(0, Math.min((x-a) / (b-a), 1)); + function step(a, b, x) { + return Math.max(0, Math.min((x - a) / (b - a), 1)); } - function affectColor (buf, i, c) { + function affectColor(buf, i, c) { buf[i] = ~~(256 * c / 9); - buf[i+3] = 1; + buf[i + 3] = 1; } - function get (b, x, y) { + function get(b, x, y) { if (x >= 0 && x < w && y >= 0 && y < h) { return b[x + y * w]; } return y > 50 ? 1 : 0; } - function set (b, x, y, e) { + function set(b, x, y, e) { if (x >= 0 && x < w && y >= 0 && y < h) { b[x + y * w] = e; } @@ -505,9 +506,9 @@ function generate (startX: number, worldSize: [number,number]) { for (x = startX; x < worldSize[0]; ++x) { for (y = 0; y < worldSize[1]; ++y) { e = +(Math.random() > - 0.22 - + 0.3 * (step(0, 20, y) - + step(worldSize[1]-20, worldSize[1] - 2, y))); + 0.22 + + 0.3 * + (step(0, 20, y) + step(worldSize[1] - 20, worldSize[1] - 2, y))); set(worldPixelBuf, x, y, e); } } @@ -519,17 +520,25 @@ function generate (startX: number, worldSize: [number,number]) { var me = get(cur, x, y); var sum = 0.1 * me + - (0.9 + 0.1 * Math.random()) * (get(cur, x-1, y-1)?1:0) + - (0.9 + 0.1 * Math.random()) * (get(cur, x, y-1)?1:0) + - (0.9 + 0.1 * Math.random()) * (get(cur, x+1, y-1)?1:0) + - (1.4 + 0.2 * Math.random()) * (get(cur, x-1, y)?1:0) + - (1.1 + 0.2 * Math.random()) * (get(cur, x+1, y)?1:0) + - (1.6 - 0.1 * Math.random()) * (get(cur, x-1, y+1)?1:0) + - (1.2 - 0.2 * Math.random()) * (get(cur, x, y+1)?1:0) + - (1.0 - 0.1 * Math.random()) * (get(cur, x+1, y+1?1:0)); - let e = +(sum <= 6 + (Math.random()-0.5) * (1-k/K)); - if (e && sum >= 6 - Math.random() * waterInGeneration + 4 * step(110, 0, y)) e = 5; - if (e && sum >= 6 - Math.random() * volcanoInGeneration + 6 * step(20, 60, y)) e = 4; + (0.9 + 0.1 * Math.random()) * (get(cur, x - 1, y - 1) ? 1 : 0) + + (0.9 + 0.1 * Math.random()) * (get(cur, x, y - 1) ? 1 : 0) + + (0.9 + 0.1 * Math.random()) * (get(cur, x + 1, y - 1) ? 1 : 0) + + (1.4 + 0.2 * Math.random()) * (get(cur, x - 1, y) ? 1 : 0) + + (1.1 + 0.2 * Math.random()) * (get(cur, x + 1, y) ? 1 : 0) + + (1.6 - 0.1 * Math.random()) * (get(cur, x - 1, y + 1) ? 1 : 0) + + (1.2 - 0.2 * Math.random()) * (get(cur, x, y + 1) ? 1 : 0) + + (1.0 - 0.1 * Math.random()) * get(cur, x + 1, y + 1 ? 1 : 0); + let e = +(sum <= 6 + (Math.random() - 0.5) * (1 - k / K)); + if ( + e && + sum >= 6 - Math.random() * waterInGeneration + 4 * step(110, 0, y) + ) + e = 5; + if ( + e && + sum >= 6 - Math.random() * volcanoInGeneration + 6 * step(20, 60, y) + ) + e = 4; set(swp, x, y, e); } } @@ -541,17 +550,25 @@ function generate (startX: number, worldSize: [number,number]) { for (i = 0; i < worldPixelBuf.length; ++i) { affectColor(worldPixelRawBuf, 4 * i, worldPixelBuf[i]); } - return ndarray(worldPixelRawBuf, [ worldSize[0], worldSize[1], 4]).transpose(1, 0, 2).step(1, -1, 1); + return ndarray(worldPixelRawBuf, [worldSize[0], worldSize[1], 4]) + .transpose(1, 0, 2) + .step(1, -1, 1); } -const size = [200,200]; +const size = [200, 200]; export default class Example extends Component { state = { - initialState: generate(0, size), + initialState: generate(0, size) }; render() { - const { forestGrowFactor, fireFactor, waterFactor, speed, width } = this.props; + const { + forestGrowFactor, + fireFactor, + waterFactor, + speed, + width + } = this.props; const { initialState } = this.state; return ( @@ -571,11 +588,10 @@ export default class Example extends Component { speed: 60, forestGrowFactor: 1, fireFactor: 0, - waterFactor: 0, + waterFactor: 0 }; } - /** * Game Rule Interactions. * diff --git a/packages/cookbook/src/Dashboard.js b/packages/cookbook/src/Dashboard.js index e643964..023123b 100755 --- a/packages/cookbook/src/Dashboard.js +++ b/packages/cookbook/src/Dashboard.js @@ -1,8 +1,8 @@ -import React, {Component} from "react"; -import {Link} from "react-router"; +import React, { Component } from "react"; +import { Link } from "react-router"; import Code from "./Code"; -import {Surface} from "gl-react-dom"; -import {Node, Shaders, GLSL, Backbuffer, LinearCopy} from "gl-react"; +import { Surface } from "gl-react-dom"; +import { Node, Shaders, GLSL, Uniform, LinearCopy } from "gl-react"; import timeLoop from "./HOC/timeLoop"; import "./Dashboard.css"; import Inspector from "./Inspector"; @@ -23,14 +23,15 @@ void main () { }` }, HelloGL: { - // uniforms are variables from JS. We pipe blue uniform into blue output color + // uniforms are variables from JS. We pipe blue uniform into blue output color frag: GLSL` precision highp float; varying vec2 uv; uniform float red; void main() { gl_FragColor = vec4(red, uv.x, uv.y, 1.0); -}` }, +}` + }, Rotate: { frag: GLSL` precision highp float; @@ -44,20 +45,22 @@ void main() { p.x < 0.0 || p.x > 1.0 || p.y < 0.0 || p.y > 1.0 ? vec4(0.0) : texture2D(children, p); -}` } +}` + } }); -const MotionBlur = ({ children, persistence }) => +const MotionBlur = ({ children, persistence }) => ( ; + uniforms={{ children, backbuffer: Uniform.Backbuffer, persistence }} + /> +); // We can make a that will render the concrete class HelloGL extends Component { props: { - red: number, + red: number }; render() { const { red } = this.props; @@ -69,11 +72,13 @@ class Rotate extends Component { props: { scale: number, angle: number, - children: any, + children: any }; render() { const { angle, scale, children } = this.props; - return ; + return ( + + ); } } @@ -81,7 +86,7 @@ class Ex1 extends Component { props: { time: number }; state = { showCode: false, - showInspector: false, + showInspector: false }; onShowCode = () => { this.setState({ showCode: true }); @@ -97,37 +102,40 @@ class Ex1 extends Component { const scale = 0.70 + 0.40 * Math.cos(0.001 * time); const angle = 2 * Math.PI * (0.5 + 0.5 * Math.cos(0.001 * time)); return ( -
-
- - - - - - - - - - { !showCode - ?
SHOW ME THE CODE!
- : - { - ` +
+
+ + + + + + + + + + {!showCode + ?
+ SHOW ME THE CODE! +
+ : {` - ` - } } -
- { showCode - ? - !showInspector - ?
SHOW ME UNDER THE HOOD!
- : - : null } -
+
`}
} +
+ {showCode + ? !showInspector + ?
+ SHOW ME UNDER THE HOOD! +
+ : + : null} +
); } } @@ -136,25 +144,31 @@ const Ex1Loop = timeLoop(Ex1); export default class Dashboard extends Component { render() { - return
-

- gl-react is a React library to write and compose WebGL shaders. -

- - -
; + return ( +
+

+ gl-react is a + {" "} + React + {" "} + library to write and compose WebGL shaders. +

+ + +
+ ); } } diff --git a/packages/cookbook/src/ExamplePage.js b/packages/cookbook/src/ExamplePage.js index 21c71ab..dfa98fd 100755 --- a/packages/cookbook/src/ExamplePage.js +++ b/packages/cookbook/src/ExamplePage.js @@ -1,4 +1,4 @@ -import React, {Component} from "react"; +import React, { Component } from "react"; import PropTypes from "prop-types"; const encodeQueryValue = value => JSON.stringify(value); @@ -18,8 +18,7 @@ const decodeQuery = query => { if (query.hasOwnProperty(k)) { try { query[k] = decodeQueryValue(query[k]); - } - catch (e) { + } catch (e) { console.warn(e); delete query[k]; } @@ -30,7 +29,7 @@ const decodeQuery = query => { export default class ExamplePage extends Component { static contextTypes = { - router: PropTypes.object.isRequired, + router: PropTypes.object.isRequired }; setToolState = (obj: any) => { @@ -51,38 +50,43 @@ export default class ExamplePage extends Component { const props = { setToolState: this.setToolState, ...Example.defaultProps, - ...decodeQuery(query), + ...decodeQuery(query) }; - return
-
{desc}
-
- + return ( +
+
+ {desc} +
+
+ +
+ {toolbox + ?
+ {toolbox.map((field, i) => +
+ {field.title + ?

+ {typeof field.title === "function" + ? field.title(props[field.prop]) + : field.title} +

+ : null} + {field.Editor + ? + : null} +
+ )} + {ToolboxFooter ? : null} +
+ : null} +
+ {descAfter} +
- { toolbox - ?
- {toolbox.map((field, i) => -
- { field.title - ?

{ - typeof field.title==="function" - ? field.title(props[field.prop]) - : field.title - }

- : null } - { field.Editor - ? - : null } -
)} - { ToolboxFooter - ? - : null} -
- : null } -
{descAfter}
-
; + ); } } diff --git a/packages/cookbook/src/Inspector/index.js b/packages/cookbook/src/Inspector/index.js index 468de31..dae41b5 100755 --- a/packages/cookbook/src/Inspector/index.js +++ b/packages/cookbook/src/Inspector/index.js @@ -6,7 +6,7 @@ import { VisitorLogger, Node, Bus, - Backbuffer, + Uniform, listSurfaces } from "gl-react"; import raf from "raf"; @@ -175,7 +175,7 @@ class UniformValue extends Component { } return Array.isArray(type) ? - {type.map((type, i) => ( + {type.map((type, i) => - ))} + )} : @@ -334,17 +334,21 @@ class MetaInfo extends Component { nodeId={node.id} anchorId={dependency.id} /> - : obj === Backbuffer - ? - : null} + : obj === Uniform.Backbuffer + ? + : null} {dependency ? dependency.getGLShortName() - : typeof obj === "string" - ? {obj} + : obj === Uniform.Backbuffer + ? "Backbuffer" + : typeof obj === "string" + ? + {obj} + : formatObject(obj)} ); @@ -529,10 +533,10 @@ class InspectorBox extends Component { style={{ left: pos[0], top: pos[1] }} className={ "box" + - (cls ? " " + cls : "") + - (recentDraw ? " recent-draw" : "") + - (grabbed ? " grabbed" : "") + - (minimized ? " minimized" : "") + (cls ? " " + cls : "") + + (recentDraw ? " recent-draw" : "") + + (grabbed ? " grabbed" : "") + + (minimized ? " minimized" : "") } >
@@ -547,8 +551,12 @@ class InspectorBox extends Component { {children}
- {width}⨉{height} - {mode} + + {width}⨉{height} + + + {mode} +
); @@ -570,7 +578,7 @@ class Uniforms extends PureComponent { return (
{preparedUniforms && - preparedUniforms.map(u => ( + preparedUniforms.map(u =>
- ))} + )}
); } @@ -628,17 +636,17 @@ class SVGConnectionLine extends PureComponent { className="connection-line" d={ `M${anchorX},${anchorY} ` + - `L${anchorX + s},${anchorY} ` + - `C${anchorX + t},${anchorY} ` + - (recursive - ? `${anchorX + t},${anchorY - anchorYOff} ` + - `${anchorX + s},${anchorY - anchorYOff} ` + - `L${hookX - s},${anchorY - anchorYOff} ` + - `C${hookX - t},${anchorY - anchorYOff} ` - : "") + - `${hookX - t * (reversedHook ? -1 : 1)},${hookY} ` + - `${hookX - s * (reversedHook ? -1 : 1)},${hookY} ` + - `L${hookX},${hookY}` + `L${anchorX + s},${anchorY} ` + + `C${anchorX + t},${anchorY} ` + + (recursive + ? `${anchorX + t},${anchorY - anchorYOff} ` + + `${anchorX + s},${anchorY - anchorYOff} ` + + `L${hookX - s},${anchorY - anchorYOff} ` + + `C${hookX - t},${anchorY - anchorYOff} ` + : "") + + `${hookX - t * (reversedHook ? -1 : 1)},${hookY} ` + + `${hookX - s * (reversedHook ? -1 : 1)},${hookY} ` + + `L${hookX},${hookY}` } /> ); @@ -1433,13 +1441,13 @@ export default class Inspector extends Component {

No Surface is currently inspected. Select one of these:

    - {listSurfaces().map(surface => ( + {listSurfaces().map(surface =>
  • this.setSurface(surface)}> {surface.getGLName()}
  • - ))} + )}
@@ -1462,11 +1470,11 @@ export default class Inspector extends Component { onChange={this.onSelectChange} > - {listSurfaces().map(surface => ( + {listSurfaces().map(surface => - ))} + )}