├── src
└── gwt
│ └── react
│ ├── todo_mvc
│ ├── client
│ │ ├── utils.java
│ │ ├── Classnames.java
│ │ ├── App.java
│ │ ├── TodoModel.java
│ │ ├── Footer.java
│ │ ├── TodoItem.java
│ │ └── TodoList.java
│ └── todomvc.gwt.xml
│ ├── api_sanity_test
│ ├── client
│ │ ├── ComponentDidCatchBadComponent.java
│ │ ├── ComponentDidCatchExample.java
│ │ ├── ChildApiTests.java
│ │ ├── App.java
│ │ └── StatefulExample.java
│ └── apisanitytest.gwt.xml
│ ├── widget_interop
│ ├── client
│ │ ├── ReactPanel.java
│ │ ├── App.java
│ │ └── StatefulExample.java
│ └── widget_interop.gwt.xml
│ ├── js_react_component_interop
│ ├── jsReactComponentInterop.gwt.xml
│ └── client
│ │ ├── FineUploader.java
│ │ └── App.java
│ └── preact_sanity_test
│ ├── preactsanitytest.gwt.xml
│ └── client
│ ├── ChildApiTests.java
│ ├── App.java
│ ├── StatefulExample2.java
│ └── StatefulExample.java
├── web
├── WEB-INF
│ └── web.xml
├── widgetInterop.html
├── todomvc.html
├── apiSanityTest.html
├── jsReactComponentInteropTest.html
├── preactSanityTest.html
├── css
│ ├── base.css
│ ├── gwt.css
│ └── index.css
└── dist
│ ├── gwt-preact-bundle.min.js
│ └── gwt-preact-bundle.js
├── .gitignore
├── LICENSE
└── README.md
/src/gwt/react/todo_mvc/client/utils.java:
--------------------------------------------------------------------------------
1 | package gwt.react.todo_mvc.client;
2 |
3 | public class utils {
4 | static String pluralize(int count, String word) {
5 | return count == 1 ? word : word + 's';
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/web/WEB-INF/web.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
--------------------------------------------------------------------------------
/web/widgetInterop.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Widget Interop example
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/gwt/react/api_sanity_test/client/ComponentDidCatchBadComponent.java:
--------------------------------------------------------------------------------
1 | package gwt.react.api_sanity_test.client;
2 |
3 | import gwt.interop.utils.client.plainobjects.JsPlainObj;
4 | import gwt.react.client.components.Component;
5 | import gwt.react.client.elements.ReactElement;
6 | import gwt.react.client.proptypes.BaseProps;
7 | import jsinterop.annotations.JsType;
8 |
9 | @JsType
10 | public class ComponentDidCatchBadComponent extends Component {
11 |
12 | public ComponentDidCatchBadComponent(BaseProps props) {
13 | super(props);
14 | }
15 |
16 | @Override
17 | protected ReactElement render() {
18 |
19 | throw new NullPointerException();
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.class
2 | .DS_Store
3 |
4 | # Package Files #
5 | *.jar
6 | *.war
7 | war
8 |
9 | # Gradle stuff
10 | .gradle/
11 | build/
12 |
13 | # gwt caches and compiled units #
14 | war/gwt_bree/
15 | gwt-unitCache/
16 |
17 | # boilerplate generated classes #
18 | .apt_generated/
19 |
20 | # more caches and things from deploy #
21 | war/WEB-INF/deploy/
22 | war/WEB-INF/classes/
23 |
24 | #compilation logs
25 | .gwt/
26 |
27 | #caching for already compiled files
28 | gwt-unitCache/
29 |
30 | #gwt junit compilation files
31 | www-test/
32 |
33 | #old GWT (1.5) created this dir
34 | .gwt-tmp/
35 |
36 | # Eclipse specific files and directories
37 | bin/
38 | .settings/
39 | .classpath
40 | .project
41 |
--------------------------------------------------------------------------------
/web/todomvc.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | React • TodoMVC
6 |
7 |
8 |
9 |
10 |
11 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/web/apiSanityTest.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | React API Test
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/src/gwt/react/widget_interop/client/ReactPanel.java:
--------------------------------------------------------------------------------
1 | package gwt.react.widget_interop.client;
2 |
3 | import com.google.gwt.dom.client.DivElement;
4 | import com.google.gwt.dom.client.Document;
5 | import com.google.gwt.user.client.ui.Widget;
6 | import gwt.react.client.api.ReactDOM;
7 | import gwt.react.client.elements.ReactElement;
8 |
9 |
10 | public class ReactPanel extends Widget {
11 | DivElement container;
12 | ReactElement elementToRender;
13 |
14 | public ReactPanel(ReactElement elementToRender) {
15 | this.elementToRender = elementToRender;
16 | container = Document.get().createDivElement();
17 | setElement(container);
18 | }
19 |
20 | @Override
21 | public void onAttach() {
22 | super.onAttach();
23 | ReactDOM.render(elementToRender, container);
24 |
25 | }
26 |
27 | @Override
28 | public void onDetach() {
29 | ReactDOM.unmountComponentAtNode(container);
30 | super.onDetach();
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/web/jsReactComponentInteropTest.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | React API Test
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/web/preactSanityTest.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | React API Test
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/src/gwt/react/widget_interop/widget_interop.gwt.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/src/gwt/react/todo_mvc/todomvc.gwt.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | -->
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/src/gwt/react/js_react_component_interop/jsReactComponentInterop.gwt.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | -->
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/gwt/react/api_sanity_test/apisanitytest.gwt.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/gwt/react/preact_sanity_test/preactsanitytest.gwt.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 GWT React
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # gwt-react-examples
2 | Examples for the various GWT React projects
3 |
4 | ## Introduction
5 |
6 | gwt-react-examples provides examples of how to use the various GWTReact projects including:
7 |
8 | * [gwt-react](https://github.com/GWTReact/gwt-react) - example [todomvc](https://github.com/GWTReact/gwt-react)
9 | * [gwt-react-router](https://github.com/GWTReact/gwt-react-router) - example [todomvc](https://github.com/GWTReact/gwt-react)
10 | * GWT interop with existing Widgets.
11 | * Using Preact instead of React.
12 |
13 | If you click on the example links above, you can see the Javascript projects the examples where ported from.
14 |
15 | ## Getting Started
16 |
17 | 1. Download and install Gradle from [gradle.org](http://gradle.org/)
18 |
19 | 2. cd to the top level of gwt-react-examples
20 |
21 | 3. Type gradle jettyDraftWar
22 |
23 | 4. You can then go to the following url's for each sample
24 |
25 | * http://localhost:8080/gwt-react-examples/apiSanityTest.html
26 | * http://localhost:8080/gwt-react-examples/todomvc.html
27 | * http://localhost:8080/gwt-react-examples/widgetInterop.html
28 | * http://localhost:8080/gwt-react-examples/preactSanityTest.html
29 |
--------------------------------------------------------------------------------
/src/gwt/react/api_sanity_test/client/ComponentDidCatchExample.java:
--------------------------------------------------------------------------------
1 | package gwt.react.api_sanity_test.client;
2 |
3 | import gwt.interop.utils.client.plainobjects.JsPlainObj;
4 | import gwt.react.client.api.React;
5 | import gwt.react.client.components.Component;
6 | import gwt.react.client.components.lifecycle.ComponentDidCatch;
7 | import gwt.react.client.elements.ReactElement;
8 | import gwt.react.client.proptypes.BaseProps;
9 | import jsinterop.annotations.JsType;
10 |
11 | import static gwt.interop.utils.client.plainobjects.JsPlainObj.$jsPlainObj;
12 | import static gwt.react.client.api.React.DOM.div;
13 |
14 | @JsType
15 | public class ComponentDidCatchExample extends Component implements ComponentDidCatch {
16 |
17 | public ComponentDidCatchExample(BaseProps props) {
18 | super(props);
19 | state = $jsPlainObj("errorInfo", "");
20 | }
21 |
22 | @Override
23 | protected ReactElement render() {
24 |
25 | if (state.getStr("errorInfo").length() > 0)
26 | return div(null, "Caught error in sub component, component stack = " + state.getStr("errorInfo"));
27 | else {
28 | return React.createElement(ComponentDidCatchBadComponent.class, null);
29 | }
30 | }
31 |
32 | @Override
33 | public void componentDidCatch(Object error, ErrorInfo info) {
34 | setState($jsPlainObj("errorInfo", info.getComponentStack()));
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/gwt/react/todo_mvc/client/Classnames.java:
--------------------------------------------------------------------------------
1 | package gwt.react.todo_mvc.client;
2 |
3 | /**
4 | * A class for combining css classnames based on specific conditions
5 | */
6 | public class Classnames {
7 | public static String get(String className, boolean condition) {
8 |
9 | return condition ? className : "";
10 | }
11 |
12 | public static String get(String className1, boolean condition1,
13 | String className2, boolean condition2) {
14 | String cls = condition1 ? className1 : "";
15 |
16 | if (condition2) {
17 | if (!cls.isEmpty()) {
18 | cls += " ";
19 | }
20 | cls += className2;
21 | }
22 | return cls;
23 | }
24 |
25 | public static String get(String className1, boolean condition1,
26 | String className2, boolean condition2,
27 | String className3, boolean condition3) {
28 | String cls = condition1 ? className1 : "";
29 |
30 | if (condition2) {
31 | if (!cls.isEmpty()) {
32 | cls += " ";
33 | }
34 | cls += className2;
35 | }
36 |
37 | if (condition3) {
38 | if (!cls.isEmpty()) {
39 | cls += " ";
40 | }
41 | cls += className3;
42 | }
43 | return cls;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/gwt/react/js_react_component_interop/client/FineUploader.java:
--------------------------------------------------------------------------------
1 | package gwt.react.js_react_component_interop.client;
2 |
3 | import gwt.interop.utils.client.plainobjects.JsPlainObj;
4 | import gwt.react.client.api.React;
5 | import gwt.react.client.components.ComponentConstructorFn;
6 | import gwt.react.client.elements.ReactElement;
7 | import gwt.react.client.proptypes.BaseProps;
8 | import jsinterop.annotations.*;
9 |
10 | @JsType(isNative = true, namespace = JsPackage.GLOBAL)
11 | public class FineUploader {
12 |
13 | @JsProperty
14 | public static ComponentConstructorFn Gallery;
15 |
16 |
17 | @JsType(isNative = true, namespace = JsPackage.GLOBAL, name = "Object")
18 | static class GalleryProps extends BaseProps {
19 | public FineUploaderTraditional uploader;
20 |
21 | }
22 |
23 | @JsOverlay
24 | public static ReactElement Gallery(GalleryProps props) {
25 | return React.createElement(Gallery, props);
26 | }
27 |
28 | @JsType(isNative = true, namespace = "FineUploader", name = "FineUploaderTraditional")
29 | static class FineUploaderTraditional {
30 | public FineUploaderTraditional(JsPlainObj options) {}
31 |
32 | public native void on(String name, UploaderCallback callback);
33 | public native void off(String name, UploaderCallback callback);
34 |
35 | @JsFunction
36 | interface UploaderCallback {
37 | void onCall(Object id, String name, Object response);
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/gwt/react/widget_interop/client/App.java:
--------------------------------------------------------------------------------
1 | package gwt.react.widget_interop.client;
2 |
3 | import com.google.gwt.core.client.EntryPoint;
4 | import com.google.gwt.user.client.ui.Button;
5 | import com.google.gwt.user.client.ui.PopupPanel;
6 | import com.google.gwt.user.client.ui.RootPanel;
7 | import gwt.react.client.api.React;
8 |
9 |
10 | public class App implements EntryPoint {
11 | private PopupPanel dialog;
12 |
13 | @Override
14 | public void onModuleLoad() {
15 | final Button button = new Button("Show embedded React view");
16 |
17 | button.addClickHandler((event) -> {
18 | //Show a React component in a popup panel
19 | dialog = new PopupPanel(true);
20 |
21 | StatefulExample.Props statefulComp1Props = new StatefulExample.Props();
22 | statefulComp1Props.aProp = "Embedded React component 1";
23 |
24 | ReactPanel reactPanel = new ReactPanel(React.createElement(StatefulExample.class, statefulComp1Props));
25 | reactPanel.setWidth("700px");
26 | reactPanel.setHeight("700px");
27 |
28 | dialog.add(reactPanel);
29 | dialog.setGlassEnabled(true);
30 | dialog.center();
31 | });
32 |
33 | RootPanel.get("replaceme").add(button);
34 |
35 | //Add React component to Root Panel
36 | StatefulExample.Props statefulComp2Props = new StatefulExample.Props();
37 | statefulComp2Props.aProp = "Embedded React component 2";
38 |
39 | ReactPanel reactPanel = new ReactPanel(React.createElement(StatefulExample.class, statefulComp2Props));
40 | RootPanel.get("replaceme2").add(reactPanel);
41 | }
42 | }
--------------------------------------------------------------------------------
/src/gwt/react/preact_sanity_test/client/ChildApiTests.java:
--------------------------------------------------------------------------------
1 | package gwt.react.preact_sanity_test.client;
2 |
3 | import gwt.interop.utils.shared.collections.Array;
4 | import gwt.react.client.api.React;
5 | import gwt.react.client.elements.ReactElement;
6 | import gwt.react.client.proptypes.BaseProps;
7 | import gwt.react.client.proptypes.html.CssProps;
8 | import gwt.react.client.proptypes.html.HtmlProps;
9 |
10 | import static gwt.react.client.api.GwtReact.castAsReactElement;
11 | import static gwt.react.client.api.React.DOM.br;
12 | import static gwt.react.client.api.React.DOM.div;
13 |
14 | class ChildApiTests {
15 | static ReactElement countChildrenComponent(BaseProps props) {
16 | int countChildren = React.Children.count(props.children);
17 |
18 | return
19 | div(null,
20 | div(null, "There are " + countChildren + " child components"),
21 | castAsReactElement(props.children),
22 | br(null)
23 | );
24 | }
25 |
26 | static ReactElement updatePropsOfChildrenComponent(BaseProps props) {
27 |
28 | Array newChildren = React.Children.map(props.children, (child) -> {
29 | HtmlProps propsToMerge = new HtmlProps()
30 | .style(new CssProps()
31 | .color("red"));
32 |
33 | return React.cloneElement(child, propsToMerge);
34 | });
35 |
36 | return
37 | div(null,
38 | castAsReactElement(newChildren),
39 | br(null));
40 | }
41 |
42 | static ReactElement childArrayTestComponent(BaseProps props) {
43 | Array existingChildren = React.Children.toArray(props.children);
44 |
45 | return
46 | div(null,
47 | castAsReactElement(existingChildren),
48 | br(null));
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/gwt/react/preact_sanity_test/client/App.java:
--------------------------------------------------------------------------------
1 | package gwt.react.preact_sanity_test.client;
2 |
3 | import com.google.gwt.core.client.EntryPoint;
4 | import elemental2.dom.DomGlobal;
5 | import gwt.react.client.api.React;
6 | import gwt.react.client.api.ReactDOM;
7 | import gwt.react.client.api.ReactDOMServer;
8 | import gwt.react.client.elements.ReactElement;
9 |
10 | import static gwt.react.client.api.React.DOM.div;
11 |
12 | public class App implements EntryPoint {
13 |
14 | @Override
15 | public void onModuleLoad() {
16 |
17 | StatefulExample.Props statefulCompProps = new StatefulExample.Props();
18 | statefulCompProps.aProp = "aPropValue";
19 |
20 | ReactElement appComp =
21 | div(null,
22 | React.createElement(ChildApiTests::countChildrenComponent, null,
23 | div(null, "Child 1"),
24 | div(null, "Child 2")
25 | ),
26 | React.createElement(ChildApiTests::childArrayTestComponent, null,
27 | div(null, "Array Child 1"),
28 | div(null, "Array Child 2"),
29 | div(null, "Array Child 3 (should be the last child)")
30 | ),
31 | React.createElement(ChildApiTests::updatePropsOfChildrenComponent, null,
32 | div(null, "Child 1 should be red"),
33 | div(null, "Child 2 should be red (should be the last child)")
34 | ),
35 | React.createElement(StatefulExample.class, statefulCompProps),
36 | //The following creates an element using a class
37 | React.createElement(StatefulExample2.class, null)
38 | );
39 |
40 | ReactDOM.render(appComp, DomGlobal.document.getElementById("mainCont"), () -> DomGlobal.alert("Rendered"));
41 |
42 | DomGlobal.alert("renderToString returned: '" + ReactDOMServer.renderToString(div(null, "a div")) + "'");
43 | }
44 | }
--------------------------------------------------------------------------------
/src/gwt/react/api_sanity_test/client/ChildApiTests.java:
--------------------------------------------------------------------------------
1 | package gwt.react.api_sanity_test.client;
2 |
3 | import gwt.interop.utils.shared.collections.Array;
4 | import gwt.react.client.api.React;
5 | import gwt.react.client.components.StatelessComponent;
6 | import gwt.react.client.elements.ReactElement;
7 | import gwt.react.client.proptypes.BaseProps;
8 | import gwt.react.client.proptypes.html.CssProps;
9 | import gwt.react.client.proptypes.html.HtmlProps;
10 |
11 | import static gwt.react.client.api.GwtReact.castAsReactElement;
12 | import static gwt.react.client.api.React.DOM.br;
13 | import static gwt.react.client.api.React.DOM.div;
14 |
15 | class ChildApiTests {
16 | static StatelessComponent countChildrenComponent = (props) -> {
17 | int countChildren = React.Children.count(props.children);
18 |
19 | return
20 | div(null,
21 | div(null, "There are " + countChildren + " child components"),
22 | castAsReactElement(props.children),
23 | br(null)
24 | );
25 | };
26 |
27 | static StatelessComponent updatePropsOfChildrenComponent = (props) -> {
28 |
29 | Array newChildren = React.Children.map(props.children, (child) -> {
30 | HtmlProps propsToMerge = new HtmlProps()
31 | .style(new CssProps()
32 | .color("red"));
33 |
34 | return React.cloneElement(child, propsToMerge);
35 | });
36 |
37 | return
38 | div(null,
39 | castAsReactElement(newChildren),
40 | br(null));
41 | };
42 |
43 | static StatelessComponent childArrayTestComponent = (props) -> {
44 | Array existingChildren = React.Children.toArray(props.children);
45 |
46 | return
47 | div(null,
48 | castAsReactElement(existingChildren),
49 | br(null));
50 | };
51 | }
52 |
--------------------------------------------------------------------------------
/src/gwt/react/todo_mvc/client/App.java:
--------------------------------------------------------------------------------
1 | package gwt.react.todo_mvc.client;
2 |
3 | import com.google.gwt.core.client.EntryPoint;
4 | import elemental2.dom.DomGlobal;
5 | import gwt.interop.utils.client.collections.JsArray;
6 | import gwt.interop.utils.shared.collections.Array;
7 | import gwt.react.client.api.React;
8 | import gwt.react.client.api.ReactDOM;
9 | import gwt.react.client.components.ComponentUtils;
10 | import gwt.react.client.elements.ReactElement;
11 | import gwt.react_router.client.ReactRouter;
12 | import gwt.react_router.client.RouteProps;
13 | import gwt.react_router.client.RouterProps;
14 |
15 | import static gwt.react.client.api.GwtReact.castAsReactElement;
16 | import static gwt.react_router.client.ReactRouter.Route;
17 | import static gwt.react_router.client.ReactRouter.Router;
18 |
19 | public class App implements EntryPoint {
20 |
21 | static final int ESCAPE_KEY = 27;
22 | static final int ENTER_KEY = 13;
23 |
24 | static TodoModel model = new TodoModel();
25 | private static Array routes = JsArray.create();
26 |
27 | private void render() {
28 | ReactDOM.render(
29 | React.createElement(Router, new RouterProps().History(ReactRouter.hashHistory),
30 | castAsReactElement(routes)), DomGlobal.document.getElementById("todoapp"));
31 | }
32 |
33 | @Override
34 | public void onModuleLoad() {
35 | //React Router now requires that you only create the Routes once so define them statically
36 | routes.push(React.createElement(Route,
37 | new RouteProps()
38 | .path("/")
39 | .component(ComponentUtils.getCtorFn(TodoList.class))
40 | .key("1")));
41 |
42 | routes.push(React.createElement(Route,
43 | new RouteProps()
44 | .path("/:nowShowing")
45 | .component(ComponentUtils.getCtorFn(TodoList.class))
46 | .key("2")));
47 |
48 | model.subscribe(this::render);
49 | render();
50 | }
51 | }
--------------------------------------------------------------------------------
/src/gwt/react/js_react_component_interop/client/App.java:
--------------------------------------------------------------------------------
1 | package gwt.react.js_react_component_interop.client;
2 |
3 | import com.google.gwt.core.client.EntryPoint;
4 | import elemental2.dom.DomGlobal;
5 | import gwt.interop.utils.client.plainobjects.JsPlainObj;
6 | import gwt.react.client.api.ReactDOM;
7 | import gwt.react.js_react_component_interop.client.FineUploader.FineUploaderTraditional;
8 |
9 | import static gwt.interop.utils.client.plainobjects.JsPlainObj.$jsPlainObj;
10 |
11 | public class App implements EntryPoint {
12 |
13 | @Override
14 | public void onModuleLoad() {
15 |
16 | FineUploader.GalleryProps galProps = new FineUploader.GalleryProps();
17 |
18 | /*
19 | We want to pass an Object literal of the following form.
20 |
21 | {
22 | options: {
23 | chunking: {
24 | enabled: true
25 | },
26 | deleteFile: {
27 | enabled: true,
28 | endpoint: '/uploads'
29 | },
30 | request: {
31 | endpoint: '/uploads'
32 | },
33 | retry: {
34 | enableAuto: true
35 | }
36 | }
37 | }
38 |
39 | Without defining all the types we can use $jsPlainObj
40 | */
41 |
42 |
43 | JsPlainObj uploaderConfig =
44 |
45 | $jsPlainObj(
46 | "options",
47 | $jsPlainObj(
48 | "chunking",
49 | $jsPlainObj(
50 | "enabled", true
51 | ),
52 | "deleteFile",
53 | $jsPlainObj(
54 | "enabled", true,
55 | "endpoint", "/uploads"
56 | ),
57 | "request",
58 | $jsPlainObj(
59 | "endpoint", "/uploads"
60 | ),
61 | "retry",
62 | $jsPlainObj(
63 | "enableAuto", false
64 | )
65 | )
66 | );
67 |
68 | galProps.uploader = new FineUploaderTraditional(uploaderConfig);
69 |
70 | ReactDOM.render(FineUploader.Gallery(galProps), DomGlobal.document.getElementById("mainCont"));
71 | }
72 | }
73 |
74 |
75 |
--------------------------------------------------------------------------------
/src/gwt/react/widget_interop/client/StatefulExample.java:
--------------------------------------------------------------------------------
1 | package gwt.react.widget_interop.client;
2 |
3 | import elemental2.dom.HTMLInputElement;
4 | import gwt.interop.utils.client.plainobjects.JsPlainObj;
5 | import gwt.react.client.components.Component;
6 | import gwt.react.client.elements.ReactElement;
7 | import gwt.react.client.events.FormEvent;
8 | import gwt.react.client.proptypes.BaseProps;
9 | import gwt.react.client.proptypes.html.BtnProps;
10 | import gwt.react.client.proptypes.html.InputProps;
11 | import jsinterop.annotations.JsOverlay;
12 | import jsinterop.annotations.JsPackage;
13 | import jsinterop.annotations.JsType;
14 |
15 | import static gwt.react.client.api.React.DOM.*;
16 |
17 | @JsType
18 | class StatefulExample extends Component {
19 |
20 | @JsType(isNative = true, namespace = JsPackage.GLOBAL, name="Object")
21 | static class Props extends BaseProps {
22 | String aProp;
23 | }
24 |
25 | @JsType(isNative = true, namespace = JsPackage.GLOBAL, name="Object")
26 | static class State extends JsPlainObj {
27 | String aStateVar;
28 |
29 | @JsOverlay
30 | static State make(String aStateVar) {
31 | State o = new State();
32 | o.aStateVar = aStateVar;
33 | return o;
34 | }
35 | }
36 |
37 | public StatefulExample(StatefulExample.Props props) {
38 | super(props);
39 | state = State.make("Initial Value");
40 | }
41 |
42 | private void doChange(FormEvent event) {
43 | HTMLInputElement e = (HTMLInputElement)event.target;
44 | String val = e.value;
45 | setState(State.make(val));
46 | }
47 |
48 | public ReactElement render() {
49 | return
50 | div(null,
51 | button(new BtnProps()
52 | .title("Some title")
53 | .onClick((e) -> setState(State.make("Updated Value"))),
54 | getDescription()),
55 |
56 | input(new InputProps()
57 | .placeholder("What needs to be done?")
58 | .value(state.aStateVar)
59 | .onChange(this::doChange))
60 | );
61 | }
62 |
63 | private String getDescription() {
64 | return "Click Me (state=" + state.aStateVar + ", props=" + props.aProp + ")";
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/gwt/react/preact_sanity_test/client/StatefulExample2.java:
--------------------------------------------------------------------------------
1 | package gwt.react.preact_sanity_test.client;
2 |
3 |
4 | import gwt.interop.utils.client.collections.JsArray;
5 | import gwt.interop.utils.client.plainobjects.JsPlainObj;
6 | import gwt.interop.utils.shared.collections.Array;
7 | import gwt.react.client.components.Component;
8 | import gwt.react.client.elements.ReactElement;
9 | import gwt.react.client.events.MouseEvent;
10 | import gwt.react.client.proptypes.BaseProps;
11 | import gwt.react.client.proptypes.html.InputProps;
12 | import gwt.react.client.proptypes.html.LabelProps;
13 | import gwt.react.client.proptypes.html.attributeTypes.InputType;
14 | import jsinterop.annotations.JsPackage;
15 | import jsinterop.annotations.JsType;
16 |
17 | import static gwt.interop.utils.client.plainobjects.JsPlainObj.$;
18 | import static gwt.react.client.api.GwtReact.castAsReactElement;
19 | import static gwt.react.client.api.React.DOM.*;
20 |
21 | /**
22 | * This example shows a stateful component where we have renamed the JsType and added it to the global scope
23 | */
24 | @JsType(name = "RenamedStatefulExample2", namespace = JsPackage.GLOBAL)
25 | public class StatefulExample2 extends Component{
26 |
27 | @JsType(isNative = true, namespace = JsPackage.GLOBAL, name="Object")
28 | static class State extends JsPlainObj {
29 | public boolean checked;
30 | }
31 |
32 | public StatefulExample2(BaseProps props) {
33 | super(props);
34 | }
35 |
36 | void onClicked(MouseEvent e) {
37 | //React recommends using the setState function if you are setting the new state based on the old state.
38 | //possibly set state calls could be batched up and updated asynchronously
39 | setState((prevState, props) -> $(new State(), "checked", !prevState.checked));
40 | }
41 |
42 | @Override
43 | protected ReactElement render() {
44 | Array testLiItems = JsArray.create("Item1", "Item2", "Item3");
45 |
46 | return
47 | div(null,
48 | label(new LabelProps()
49 | .htmlFor("checkField"),
50 | "Click me "
51 | ),
52 | input(new InputProps()
53 | .id("checkField")
54 | .type(InputType.checkbox)
55 | .checked(state.checked)
56 | .onClick(this::onClicked)
57 | ),
58 | //The following doesn't work with Preact 7.2.0 without a patch (included in gwt-react), due to iFrame JS loading issues
59 | ul(null,
60 | castAsReactElement(testLiItems.map(i -> li(null, i)))
61 | )
62 | );
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/gwt/react/api_sanity_test/client/App.java:
--------------------------------------------------------------------------------
1 | package gwt.react.api_sanity_test.client;
2 |
3 | import static gwt.react.client.api.React.DOM.div;
4 | import static gwt.react.client.api.React.DOM.fragment;
5 | import static gwt.react.client.api.React.DOM.strictMode;
6 |
7 | import com.google.gwt.core.client.EntryPoint;
8 |
9 | import elemental2.dom.DomGlobal;
10 | import gwt.react.client.api.React;
11 | import gwt.react.client.api.ReactDOM;
12 | import gwt.react.client.api.ReactDOMServer;
13 | import gwt.react.client.elements.ReactElement;
14 | import gwt.react.client.proptypes.FragmentProps;
15 |
16 | public class App implements EntryPoint {
17 |
18 | @Override
19 | public void onModuleLoad() {
20 |
21 | StatefulExample.Props statefulCompProps = new StatefulExample.Props();
22 | statefulCompProps.aProp = "aPropValue";
23 |
24 | ReactElement appComp =
25 | strictMode(
26 | div(null,
27 | ReactDOM.createPortal(
28 | div(null, "This is in a portal!"), DomGlobal.document.getElementById("portalCont")
29 | ),
30 |
31 | React.createElement(ChildApiTests.countChildrenComponent, null,
32 | div(null, "Child 1"),
33 | div(null, "Child 2")
34 | ),
35 | React.createElement(ChildApiTests.childArrayTestComponent, null,
36 | div(null, "Array Child 1"),
37 | div(null, "Array Child 2"),
38 | div(null, "Array Child 3 (should be the last child)")
39 | ),
40 | React.createElement(ChildApiTests.updatePropsOfChildrenComponent, null,
41 | div(null, "Child 1 should be red"),
42 | div(null, "Child 2 should be red (should be the last child)")
43 | ),
44 | React.createElement(StatefulExample.class, statefulCompProps),
45 |
46 | React.createElement(ComponentDidCatchExample.class, statefulCompProps),
47 | fragment(
48 | div(null, "Child of fragment")
49 | ),
50 | fragment(new FragmentProps().key("1"),
51 | div(null, "Child of fragment with key")
52 | )
53 | )
54 | );
55 |
56 | ReactDOM.render(appComp, DomGlobal.document.getElementById("mainCont"), () -> DomGlobal.alert("Rendered"));
57 |
58 | DomGlobal.alert("renderToString returned: '" + ReactDOMServer.renderToString(div(null, "a div")) + "'");
59 | }
60 | }
--------------------------------------------------------------------------------
/src/gwt/react/todo_mvc/client/TodoModel.java:
--------------------------------------------------------------------------------
1 | package gwt.react.todo_mvc.client;
2 |
3 | import gwt.interop.utils.client.collections.JsArray;
4 | import gwt.interop.utils.shared.functional.JsRunnable;
5 | import gwt.interop.utils.shared.collections.Array;
6 |
7 | import java.util.Date;
8 |
9 | class TodoModel {
10 | // Generic "model" object. You can use whatever
11 | // framework you want. For this application it
12 | // may not even be worth separating this logic
13 | // out, but we do this to demonstrate one way to
14 | // separate out parts of your application.
15 | static class Todo {
16 | String id;
17 | String title;
18 | boolean completed;
19 |
20 | Todo(String id, String title, boolean completed) {
21 | this.id = id;
22 | this.title = title;
23 | this.completed = completed;
24 | }
25 | }
26 |
27 | Array todos = JsArray.create();
28 | private Array onChanges = JsArray.create();
29 |
30 | void subscribe(JsRunnable onChange) {
31 | onChanges.push(onChange);
32 | }
33 |
34 | private void inform() {
35 | //Utils.store(this.key, this.todos);
36 | onChanges.forEachElem((v, index, theArray) -> v.run());
37 | }
38 |
39 | void addTodo(String title) {
40 | todos = todos.concatValue(new Todo(Long.toString(new Date().getTime()), title, false));
41 |
42 | inform();
43 |
44 | }
45 |
46 | void toggleAll(boolean checked) {
47 | // Note: it's usually better to use immutable data structures since they're
48 | // easier to reason about and React works very well with them. That's why
49 | // we use map() and filter() everywhere instead of mutating the array or
50 | // todo items themselves.
51 |
52 | todos = todos.map((v, index, theArray) -> new Todo(v.id, v.title, checked));
53 |
54 | inform();
55 | }
56 |
57 | void toggle(Todo todoToToggle) {
58 | todos = todos.map((v, index, theArray) -> (v == todoToToggle) ? new Todo(v.id, v.title, !v.completed) : v);
59 |
60 | inform();
61 | }
62 |
63 | void destroy(Todo todo) {
64 | todos = todos.filter((v, index, theArray) -> (v != todo));
65 |
66 | inform();
67 | }
68 |
69 | void save(Todo todoToSave, String newTitle) {
70 | todos = todos.map((v, index, theArray) -> (v == todoToSave) ? new Todo(v.id, newTitle, v.completed) : v);
71 |
72 | inform();
73 | }
74 |
75 | void clearCompleted() {
76 | todos = todos.filter((v, index, theArray) -> !v.completed);
77 |
78 | inform();
79 | }
80 | }
--------------------------------------------------------------------------------
/src/gwt/react/todo_mvc/client/Footer.java:
--------------------------------------------------------------------------------
1 | package gwt.react.todo_mvc.client;
2 |
3 | import gwt.react.client.components.*;
4 | import gwt.react.client.elements.ReactElement;
5 | import gwt.react.client.events.MouseEventHandler;
6 | import gwt.react.client.proptypes.*;
7 | import gwt.react.client.proptypes.html.AnchorProps;
8 | import gwt.react.client.proptypes.html.BtnProps;
9 | import gwt.react.client.proptypes.html.HtmlProps;
10 | import jsinterop.annotations.JsPackage;
11 | import jsinterop.annotations.JsType;
12 | import static gwt.react.client.api.React.DOM.*;
13 |
14 | class Footer {
15 |
16 | @JsType(isNative = true, namespace = JsPackage.GLOBAL, name = "Object")
17 | static class FooterProps extends BaseProps {
18 | int count;
19 | int completedCount;
20 | String nowShowing;
21 | MouseEventHandler onClearCompleted;
22 | }
23 |
24 | public static StatelessComponent component = (props) -> {
25 |
26 | String activeTodoWord = utils.pluralize(props.count, "item");
27 | ReactElement clearButton = null;
28 |
29 | if (props.completedCount > 0) {
30 | clearButton = button(
31 | new BtnProps()
32 | .className("clear-completed")
33 | .onClick(props.onClearCompleted),
34 | "Clear Completed"
35 | );
36 | }
37 | String nowShowing = props.nowShowing;
38 |
39 | return
40 | footer(new HtmlProps().className("footer"),
41 | span(new HtmlProps().className("todo-count"),
42 | strong(null, Integer.toString(props.count)),
43 | activeTodoWord + " left"
44 | ),
45 | ul(new HtmlProps().className("filters"),
46 | li(null,
47 | a(new AnchorProps()
48 | .className(Classnames.get("selected", nowShowing == null))
49 | .href("#/"), "All")
50 | ),
51 | li(null,
52 | a(new AnchorProps()
53 | .className(Classnames.get("selected", TodoList.NOW_SHOWING_ACTIVE_TODOS.equals(nowShowing)))
54 | .href("#/active"), "Active")
55 | ),
56 | li(null,
57 | a(new AnchorProps()
58 | .className(Classnames.get("selected", TodoList.NOW_SHOWING_COMPLETED_TODOS.equals(nowShowing)))
59 | .href("#/completed"), "Completed")
60 | )
61 | ),
62 | clearButton
63 | );
64 | };
65 | }
--------------------------------------------------------------------------------
/web/css/base.css:
--------------------------------------------------------------------------------
1 | hr {
2 | margin: 20px 0;
3 | border: 0;
4 | border-top: 1px dashed #c5c5c5;
5 | border-bottom: 1px dashed #f7f7f7;
6 | }
7 |
8 | .learn a {
9 | font-weight: normal;
10 | text-decoration: none;
11 | color: #b83f45;
12 | }
13 |
14 | .learn a:hover {
15 | text-decoration: underline;
16 | color: #787e7e;
17 | }
18 |
19 | .learn h3,
20 | .learn h4,
21 | .learn h5 {
22 | margin: 10px 0;
23 | font-weight: 500;
24 | line-height: 1.2;
25 | color: #000;
26 | }
27 |
28 | .learn h3 {
29 | font-size: 24px;
30 | }
31 |
32 | .learn h4 {
33 | font-size: 18px;
34 | }
35 |
36 | .learn h5 {
37 | margin-bottom: 0;
38 | font-size: 14px;
39 | }
40 |
41 | .learn ul {
42 | padding: 0;
43 | margin: 0 0 30px 25px;
44 | }
45 |
46 | .learn li {
47 | line-height: 20px;
48 | }
49 |
50 | .learn p {
51 | font-size: 15px;
52 | font-weight: 300;
53 | line-height: 1.3;
54 | margin-top: 0;
55 | margin-bottom: 0;
56 | }
57 |
58 | #issue-count {
59 | display: none;
60 | }
61 |
62 | .quote {
63 | border: none;
64 | margin: 20px 0 60px 0;
65 | }
66 |
67 | .quote p {
68 | font-style: italic;
69 | }
70 |
71 | .quote p:before {
72 | content: '“';
73 | font-size: 50px;
74 | opacity: .15;
75 | position: absolute;
76 | top: -20px;
77 | left: 3px;
78 | }
79 |
80 | .quote p:after {
81 | content: '”';
82 | font-size: 50px;
83 | opacity: .15;
84 | position: absolute;
85 | bottom: -42px;
86 | right: 3px;
87 | }
88 |
89 | .quote footer {
90 | position: absolute;
91 | bottom: -40px;
92 | right: 0;
93 | }
94 |
95 | .quote footer img {
96 | border-radius: 3px;
97 | }
98 |
99 | .quote footer a {
100 | margin-left: 5px;
101 | vertical-align: middle;
102 | }
103 |
104 | .speech-bubble {
105 | position: relative;
106 | padding: 10px;
107 | background: rgba(0, 0, 0, .04);
108 | border-radius: 5px;
109 | }
110 |
111 | .speech-bubble:after {
112 | content: '';
113 | position: absolute;
114 | top: 100%;
115 | right: 30px;
116 | border: 13px solid transparent;
117 | border-top-color: rgba(0, 0, 0, .04);
118 | }
119 |
120 | .learn-bar > .learn {
121 | position: absolute;
122 | width: 272px;
123 | top: 8px;
124 | left: -300px;
125 | padding: 10px;
126 | border-radius: 5px;
127 | background-color: rgba(255, 255, 255, .6);
128 | transition-property: left;
129 | transition-duration: 500ms;
130 | }
131 |
132 | @media (min-width: 899px) {
133 | .learn-bar {
134 | width: auto;
135 | padding-left: 300px;
136 | }
137 |
138 | .learn-bar > .learn {
139 | left: 8px;
140 | }
141 | }
--------------------------------------------------------------------------------
/src/gwt/react/preact_sanity_test/client/StatefulExample.java:
--------------------------------------------------------------------------------
1 | package gwt.react.preact_sanity_test.client;
2 |
3 | import elemental2.dom.DomGlobal;
4 | import elemental2.dom.HTMLInputElement;
5 | import gwt.interop.utils.client.plainobjects.JsPlainObj;
6 | import gwt.react.client.components.PureComponent;
7 | import gwt.react.client.elements.ReactElement;
8 | import gwt.react.client.events.FormEvent;
9 | import gwt.react.client.proptypes.BaseProps;
10 | import gwt.react.client.proptypes.html.BtnProps;
11 | import gwt.react.client.proptypes.html.InputProps;
12 | import jsinterop.annotations.JsOverlay;
13 | import jsinterop.annotations.JsPackage;
14 | import jsinterop.annotations.JsType;
15 |
16 | import static gwt.react.client.api.React.DOM.*;
17 |
18 | @JsType
19 | class StatefulExample extends PureComponent {
20 |
21 | @JsType(isNative = true, namespace = JsPackage.GLOBAL, name="Object")
22 | static class Props extends BaseProps {
23 | String aProp;
24 | }
25 |
26 | @JsType(isNative = true, namespace = JsPackage.GLOBAL, name="Object")
27 | static class State extends JsPlainObj {
28 | String aStateVar;
29 |
30 | @JsOverlay
31 | static State make(String aStateVar) {
32 | State o = new State();
33 | o.aStateVar = aStateVar;
34 | return o;
35 | }
36 | }
37 |
38 | public StatefulExample(StatefulExample.Props props) {
39 | super(props);
40 | this.state = State.make("Initial Value");
41 | }
42 |
43 | private void doChange(FormEvent event) {
44 | HTMLInputElement e = (HTMLInputElement)event.target;
45 | String val = e.value;
46 | setState(State.make(val));
47 | }
48 |
49 | public ReactElement render() {
50 | return
51 | div(null,
52 | button(new BtnProps()
53 | .title("Some title")
54 | .onClick((e) -> setState(State.make("Updated Value"))),
55 | getDescription()),
56 |
57 | input(new InputProps()
58 | .placeholder("What needs to be done?")
59 | .value(state.aStateVar)
60 | .onChange(this::doChange))
61 | );
62 | }
63 |
64 | //Optional lifecycle methods
65 |
66 | public void componentWillMount() {
67 | DomGlobal.alert("componentWillMount called");
68 | }
69 |
70 | public void componentDidMount() {
71 | DomGlobal.alert("componentDidMount called");
72 | }
73 |
74 | public void componentWillReceiveProps(Props nextProps) {
75 | DomGlobal.alert("componentWillReceiveProps called (nextProps "+ nextProps.toJSONString() + ")");
76 | }
77 |
78 | public boolean shouldComponentUpdate(Props nextProps, State nextState) {
79 | DomGlobal.alert("shouldComponentUpdate called (nextProps "+ nextProps.toJSONString() + " nextState " + nextState.toJSONString() + ")");
80 | return true;
81 | }
82 |
83 | public void componentWillUpdate(Props nextProps, State nextState) {
84 | DomGlobal.alert("componentWillUpdate called (nextProps "+ nextProps.toJSONString() + " nextState " + nextState.toJSONString() + ")");
85 | }
86 |
87 | public void componentDidUpdate(Props prevProps, State prevState) {
88 | DomGlobal.alert("componentDidUpdate called (prevProps "+ prevProps.toJSONString() + " prevState " + prevState.toJSONString() + ")");
89 | }
90 |
91 | public void componentWillUnmount() {
92 | DomGlobal.alert("componentWillUnmount called");
93 | }
94 |
95 | private String getDescription() {
96 | return "Click Me (state=" + state.aStateVar + ", props=" + props.aProp + ")";
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/src/gwt/react/api_sanity_test/client/StatefulExample.java:
--------------------------------------------------------------------------------
1 | package gwt.react.api_sanity_test.client;
2 |
3 | import com.google.gwt.core.client.GWT;
4 | import elemental2.dom.DomGlobal;
5 | import elemental2.dom.HTMLButtonElement;
6 | import elemental2.dom.HTMLInputElement;
7 | import gwt.interop.utils.client.plainobjects.JsPlainObj;
8 | import gwt.react.client.api.React;
9 | import gwt.react.client.api.ReactRef;
10 | import gwt.react.client.components.Component;
11 | import gwt.react.client.components.lifecycle.*;
12 | import gwt.react.client.elements.ReactElement;
13 | import gwt.react.client.events.FormEvent;
14 | import gwt.react.client.proptypes.BaseProps;
15 | import gwt.react.client.proptypes.html.BtnProps;
16 | import gwt.react.client.proptypes.html.InputProps;
17 | import jsinterop.annotations.*;
18 |
19 | import static gwt.react.client.api.React.DOM.*;
20 |
21 | /**
22 | * This shows the optional use of lifecycle interfaces. They aren't strictly necessary, however,
23 | * they help with type checking
24 | */
25 | @JsType
26 | class StatefulExample extends Component implements
27 | ComponentWillMount,
28 | ComponentDidMount,
29 | ComponentWillReceiveProps,
30 | ShouldComponentUpdate,
31 | ComponentDidUpdate,
32 | ComponentWillUnmount,
33 | GetSnapshotBeforeUpdate{
34 |
35 |
36 | @JsType(isNative = true, namespace = JsPackage.GLOBAL, name="Object")
37 | static class Props extends BaseProps {
38 | String aProp;
39 | }
40 |
41 | @JsType(isNative = true, namespace = JsPackage.GLOBAL, name="Object")
42 | static class State extends JsPlainObj {
43 | String aStateVar;
44 |
45 | @JsOverlay
46 | static State make(String aStateVar) {
47 | State o = new State();
48 | o.aStateVar = aStateVar;
49 | return o;
50 | }
51 | }
52 |
53 | private ReactRef btnRef = React.createRef();
54 |
55 | public StatefulExample(StatefulExample.Props props) {
56 | super(props);
57 | this.state = State.make("Initial Value");
58 | }
59 |
60 | private void doChange(FormEvent event) {
61 | HTMLInputElement e = (HTMLInputElement) event.target;
62 | String val = e.value;
63 | setState(State.make(val));
64 | }
65 |
66 | public ReactElement render() {
67 | GWT.log("btnRef = " + btnRef.current);
68 |
69 | return
70 | div(null,
71 | button(new BtnProps()
72 | .ref(btnRef)
73 | .title("Some title")
74 | .onClick((e) -> setState(State.make("Updated Value"))),
75 | getDescription()),
76 |
77 | input(new InputProps()
78 | .placeholder("What needs to be done?")
79 | .value(state.aStateVar)
80 | .onChange(this::doChange))
81 | );
82 | }
83 |
84 | //Optional lifecycle methods
85 |
86 | public static State getDerivedStateFromProps(Props nextProps, State prevState) {
87 | DomGlobal.alert("getDerivedStateFromProps called (nextProps "+ nextProps.toJSONString() + " nextState " + prevState.toJSONString() + ")");
88 | return null; //Do nothing
89 | }
90 |
91 | public void componentWillMount() {
92 | DomGlobal.alert("componentWillMount called");
93 | }
94 |
95 | public void componentDidMount() {
96 | DomGlobal.alert("componentDidMount called");
97 | }
98 |
99 | public void componentWillReceiveProps(Props nextProps) {
100 | DomGlobal.alert("componentWillReceiveProps called (nextProps "+ nextProps.toJSONString() + ")");
101 | }
102 |
103 | public boolean shouldComponentUpdate(Props nextProps, State nextState) {
104 | DomGlobal.alert("shouldComponentUpdate called (nextProps "+ nextProps.toJSONString() + " nextState " + nextState.toJSONString() + ")");
105 | return true;
106 | }
107 |
108 | public void componentWillUpdate(Props nextProps, State nextState) {
109 | DomGlobal.alert("componentWillUpdate called (nextProps "+ nextProps.toJSONString() + " nextState " + nextState.toJSONString() + ")");
110 | }
111 |
112 | public void componentDidUpdate(Props prevProps, State prevState, Object snapshotValue) {
113 | DomGlobal.alert("componentDidUpdate called (prevProps "+ prevProps.toJSONString() + " prevState " + prevState.toJSONString() + "snapshot " + snapshotValue + ")");
114 | }
115 |
116 | public Object getSnapshotBeforeUpdate(Props prevProps, State prevState) {
117 | return "TestSnapshot";
118 | }
119 |
120 | public void componentWillUnmount() {
121 | DomGlobal.alert("componentWillUnmount called");
122 | }
123 |
124 | private String getDescription() {
125 | return "Click Me (state=" + state.aStateVar + ", props=" + props.aProp + ")";
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/src/gwt/react/todo_mvc/client/TodoItem.java:
--------------------------------------------------------------------------------
1 | package gwt.react.todo_mvc.client;
2 |
3 | import elemental2.dom.HTMLInputElement;
4 | import gwt.interop.utils.client.plainobjects.JsPlainObj;
5 | import gwt.interop.utils.shared.functional.JsBiConsumer;
6 | import gwt.react.client.components.Component;
7 | import gwt.react.client.elements.ReactElement;
8 | import gwt.react.client.events.FocusEvent;
9 | import gwt.react.client.events.FormEvent;
10 | import gwt.react.client.events.KeyboardEvent;
11 | import gwt.react.client.events.MouseEvent;
12 | import gwt.react.client.proptypes.BaseProps;
13 | import gwt.react.client.proptypes.html.BtnProps;
14 | import gwt.react.client.proptypes.html.HtmlProps;
15 | import gwt.react.client.proptypes.html.InputProps;
16 | import gwt.react.client.proptypes.html.LabelProps;
17 | import gwt.react.client.proptypes.html.attributeTypes.InputType;
18 | import jsinterop.annotations.JsPackage;
19 | import jsinterop.annotations.JsType;
20 |
21 | import static gwt.interop.utils.client.plainobjects.JsPlainObj.$;
22 | import static gwt.react.client.api.React.DOM.*;
23 |
24 | @JsType
25 | class TodoItem extends Component {
26 |
27 | @JsType(isNative = true, namespace = JsPackage.GLOBAL, name = "Object")
28 | static class TodoItemProps extends BaseProps {
29 | TodoModel.Todo todo;
30 | boolean isEditing;
31 | JsBiConsumer doSave;
32 | JsBiConsumer doAction;
33 | }
34 |
35 | @JsType(isNative = true, namespace = JsPackage.GLOBAL, name = "Object")
36 | static class TodoState extends JsPlainObj {
37 | String editText;
38 | }
39 |
40 | private TodoState newTodoItemState(String editText) {
41 | return $(new TodoState(), "editText", editText);
42 | }
43 |
44 | public TodoItem(TodoItem.TodoItemProps props) {
45 | super(props);
46 |
47 | state = newTodoItemState(props.todo.title);
48 | }
49 |
50 | private void submitTodo(FocusEvent event) {
51 | String val = state.editText;
52 | if (val != null && !val.isEmpty()) {
53 | props.doSave.accept(props.todo, val);
54 |
55 | setState(newTodoItemState(val));
56 | } else {
57 | props.doAction.accept(TodoList.Action.DESTROY, props.todo);
58 | }
59 | }
60 |
61 | private void handleEdit(MouseEvent event) {
62 | props.doAction.accept(TodoList.Action.EDIT, props.todo);
63 | setState(newTodoItemState(props.todo.title));
64 | }
65 |
66 | private void handleKeyDown(KeyboardEvent event) {
67 | if (event.which == App.ESCAPE_KEY) {
68 | setState(newTodoItemState(props.todo.title));
69 | props.doAction.accept(TodoList.Action.CANCEL, props.todo);
70 | } else if (event.which == App.ENTER_KEY) {
71 | submitTodo(null);
72 | }
73 | }
74 |
75 | private void handleChange(FormEvent event) {
76 | if (props.isEditing) {
77 | setState(newTodoItemState(((HTMLInputElement)event.target).value));
78 | }
79 | }
80 |
81 |
82 | /**
83 | * This is a completely optional performance enhancement that you can
84 | * implement on any React component. If you were to delete this method
85 | * the app would still work correctly (and still be very performant!), we
86 | * just use it as an example of how little code it takes to getCtorFn an order
87 | * of magnitude performance improvement.
88 | */
89 | public boolean shouldComponentUpdate(TodoItemProps nextProps, TodoState nextState) {
90 | return (nextProps.todo != props.todo ||
91 | nextProps.isEditing != props.isEditing ||
92 | !nextState.editText.equals(state.editText));
93 | }
94 |
95 | /**
96 | * Safely manipulate the DOM after updating the state when invoking
97 | * `props.onEdit()` in the `handleEdit` method above.
98 | * For more info refer to notes at https://facebook.github.io/react/docs/component-api.html#setstate
99 | * and https://facebook.github.io/react/docs/component-specs.html#updating-componentdidupdate
100 | */
101 | public void componentDidUpdate(TodoItemProps prevProps, TodoItemProps prevState) {
102 |
103 | if (!prevProps.isEditing && props.isEditing) {
104 | HTMLInputElement inputEl = (HTMLInputElement)this.refs.get("editField");
105 | inputEl.focus();
106 | inputEl.select();
107 | }
108 | }
109 |
110 | public ReactElement render() {
111 | return
112 | li(new HtmlProps()
113 | .className(Classnames.get("completed", props.todo.completed, "editing", props.isEditing)),
114 | div(new HtmlProps().className("view"),
115 | input(new InputProps()
116 | .className("toggle")
117 | .type(InputType.checkbox).checked(props.todo.completed)
118 | .onChange((event) -> props.doAction.accept(TodoList.Action.TOGGLE, props.todo))),
119 | label(new LabelProps()
120 | .onDoubleClick(this::handleEdit), props.todo.title),
121 | button(new BtnProps()
122 | .className("destroy")
123 | .onClick((event) -> props.doAction.accept(TodoList.Action.DESTROY, props.todo)))
124 | ),
125 | input(new InputProps()
126 | .ref("editField")
127 | .className("edit")
128 | .defaultValue(state.editText)
129 | .onBlur(this::submitTodo)
130 | .onChange(this::handleChange)
131 | .onKeyDown(this::handleKeyDown))
132 | );
133 | }
134 | }
135 |
--------------------------------------------------------------------------------
/web/css/gwt.css:
--------------------------------------------------------------------------------
1 | /**
2 | * The file contains styles for GWT widgets in the Clean theme.
3 | *
4 | * In order to maintain cross-browser compatibility, the following syntax is
5 | * used to create IE6 specific style rules:
6 | * .gwt-Widget {
7 | * property: rule applies to all browsers
8 | * -property: rule applies only to IE6 (overrides previous rule)
9 | * }
10 | * * html .gwt-Widget {
11 | * property: rule applies to all versions of IE
12 | * }
13 | */
14 |
15 | body, table td, select, button {
16 | font-family: Arial Unicode MS, Arial, sans-serif;
17 | font-size: small;
18 | }
19 | pre {
20 | font-family: "courier new", courier;
21 | font-size: small;
22 | }
23 | body {
24 | color: black;
25 | margin: 0px;
26 | border: 0px;
27 | padding: 0px;
28 | background: #fff;
29 | direction: ltr;
30 | }
31 | a, a:visited {
32 | color: #0066cc;
33 | text-decoration:none;
34 | }
35 |
36 | a:hover {
37 | cursor: hand;
38 | color: #0066cc;
39 | text-decoration:underline;
40 | }
41 |
42 | select {
43 | background: white;
44 | }
45 |
46 | /**
47 | * The reference theme can be used to determine when this style sheet has
48 | * loaded. Create a hidden div element with absolute position, assign the style
49 | * name below, and attach it to the DOM. Use a timer to detect when the
50 | * element's height and width are set to 5px.
51 | */
52 | .gwt-Reference-clean {
53 | height: 5px;
54 | width: 5px;
55 | zoom: 1;
56 | }
57 |
58 | .gwt-FileUpload {
59 | }
60 |
61 | .gwt-Frame {
62 | border-top: 2px solid #666;
63 | border-left: 2px solid #666;
64 | border-right: 2px solid #bbb;
65 | border-bottom: 2px solid #bbb;
66 | }
67 |
68 | .gwt-HTML {
69 | padding: 0 0px;
70 | }
71 |
72 | .gwt-Hyperlink {
73 | }
74 |
75 | .gwt-Image {
76 | }
77 |
78 | .gwt-Label {
79 | }
80 |
81 | .gwt-ListBox {
82 | }
83 |
84 | .gwt-PopupPanel {
85 | border: 3px solid #e7e7e7;
86 | padding: 3px;
87 | background: white;
88 | }
89 |
90 | .gwt-DecoratedPopupPanel .popupContent {
91 | }
92 | .gwt-DecoratedPopupPanel .popupMiddleCenter {
93 | padding: 3px;
94 | background: #f1f1f1;
95 | }
96 | .gwt-DecoratedPopupPanel .popupTopLeftInner {
97 | width: 6px;
98 | height: 5px;
99 | zoom: 1;
100 | }
101 | .gwt-DecoratedPopupPanel .popupTopRightInner {
102 | width: 6px;
103 | height: 5px;
104 | zoom: 1;
105 | }
106 | .gwt-DecoratedPopupPanel .popupBottomLeftInner {
107 | width: 6px;
108 | height: 6px;
109 | zoom: 1;
110 | }
111 | .gwt-DecoratedPopupPanel .popupBottomRightInner {
112 | width: 6px;
113 | height: 6px;
114 | zoom: 1;
115 | }
116 | * html .gwt-DecoratedPopupPanel .popupTopLeftInner {
117 | width: 6px;
118 | height: 5px;
119 | overflow: hidden;
120 | }
121 | * html .gwt-DecoratedPopupPanel .popupTopRightInner {
122 | width: 6px;
123 | height: 5px;
124 | overflow: hidden;
125 | }
126 | * html .gwt-DecoratedPopupPanel .popupBottomLeftInner {
127 | width: 6px;
128 | height: 6px;
129 | overflow: hidden;
130 | }
131 | * html .gwt-DecoratedPopupPanel .popupBottomRightInner {
132 | width: 6px;
133 | height: 6px;
134 | overflow: hidden;
135 | }
136 |
137 | .gwt-PopupPanelGlass {
138 | background-color: #000;
139 | opacity: 0.3;
140 | filter: alpha(opacity=30);
141 | }
142 |
143 | .gwt-RadioButton {
144 | }
145 | .gwt-RadioButton-disabled {
146 | color: #888;
147 | }
148 |
149 | .gwt-RichTextArea {
150 | }
151 |
152 | .gwt-TextArea {
153 | padding: 4px;
154 | border: 1px solid #ccc;
155 | border-top: 1px solid #666;
156 | font-size: 100%;
157 | font-family: Arial Unicode MS, Arial, sans-serif;
158 | }
159 | .gwt-TextArea-readonly {
160 | color: #888;
161 | }
162 |
163 | .gwt-TextBox {
164 | padding: 2px 1px;
165 | border: 1px solid #ccc;
166 | border-top: 1px solid #999;
167 | font-size: small;
168 | font-family: Arial Unicode MS, Arial, sans-serif;
169 | }
170 | .gwt-TextBox-readonly {
171 | color: #888;
172 | }
173 |
174 | .gwt-Tree .gwt-TreeItem {
175 | padding: 1px 0px;
176 | margin: 0px;
177 | white-space: nowrap;
178 | cursor: hand;
179 | cursor: pointer;
180 | }
181 | .gwt-Tree .gwt-TreeItem-selected {
182 | background: #ebeff9;
183 | }
184 | .gwt-TreeItem .gwt-RadioButton input,
185 | .gwt-TreeItem .gwt-CheckBox input {
186 | margin-left: 0px;
187 | }
188 | * html .gwt-TreeItem .gwt-RadioButton input,
189 | * html .gwt-TreeItem .gwt-CheckBox input {
190 | margin-left: -4px;
191 | }
192 |
193 | .gwt-DateBox {
194 | padding: 5px 4px;
195 | border: 1px solid #ccc;
196 | border-top: 1px solid #999;
197 | font-size: 100%;
198 | }
199 | .gwt-DateBox input {
200 | width: 8em;
201 | }
202 | .dateBoxFormatError {
203 | background: #ffcccc;
204 | }
205 | .dateBoxPopup {
206 | z-index: 1000000;
207 | }
208 |
209 | .gwt-DatePicker {
210 | border: 1px solid #ccc;
211 | border-top:1px solid #999;
212 | cursor: default;
213 | }
214 | .gwt-DatePicker td,
215 | .datePickerMonthSelector td:focus {
216 | outline: none;
217 | }
218 | .datePickerDays {
219 | width: 100%;
220 | background: white;
221 | }
222 | .datePickerDay,
223 | .datePickerWeekdayLabel,
224 | .datePickerWeekendLabel {
225 | font-size: 85%;
226 | text-align: center;
227 | padding: 4px;
228 | outline: none;
229 | font-weight:bold;
230 | color:#333;
231 | border-right: 1px solid #EDEDED;
232 | border-bottom: 1px solid #EDEDED;
233 | }
234 | .datePickerWeekdayLabel,
235 | .datePickerWeekendLabel {
236 | background: #fff;
237 | padding: 0px 4px 2px;
238 | cursor: default;
239 | color:#666;
240 | font-size:70%;
241 | font-weight:normal;
242 | }
243 | .datePickerDay {
244 | padding: 4px 7px;
245 | cursor: hand;
246 | cursor: pointer;
247 | }
248 | .datePickerDayIsWeekend {
249 | background: #f7f7f7;
250 | }
251 | .datePickerDayIsFiller {
252 | color: #999;
253 | font-weight:normal;
254 | }
255 | .datePickerDayIsValue {
256 | background: #d7dfe8;
257 | }
258 | .datePickerDayIsDisabled {
259 | color: #AAAAAA;
260 | font-style: italic;
261 | }
262 | .datePickerDayIsHighlighted {
263 | background: #F0E68C;
264 | }
265 | .datePickerDayIsValueAndHighlighted {
266 | background: #d7dfe8;
267 | }
268 | .datePickerDayIsToday {
269 | padding: 3px;
270 | color: #fff;
271 | }
272 |
273 | .datePickerMonthSelector {
274 | width: 100%;
275 | padding: 1px 0 5px 0;
276 | background: #fff;
277 | }
278 | td.datePickerMonth {
279 | text-align: center;
280 | vertical-align: middle;
281 | white-space: nowrap;
282 | font-size: 100%;
283 | font-weight: bold;
284 | color: #333;
285 | }
286 | .datePickerPreviousButton,
287 | .datePickerNextButton {
288 | font-size: 120%;
289 | line-height: 1em;
290 | color: #3a6aad;
291 | cursor: hand;
292 | cursor: pointer;
293 | font-weight: bold;
294 | padding: 0px 4px;
295 | outline: none;
296 | }
297 |
298 | /* Application styles */
299 |
--------------------------------------------------------------------------------
/src/gwt/react/todo_mvc/client/TodoList.java:
--------------------------------------------------------------------------------
1 | package gwt.react.todo_mvc.client;
2 |
3 | import elemental2.dom.HTMLInputElement;
4 | import gwt.interop.utils.client.plainobjects.JsPlainObj;
5 | import gwt.interop.utils.shared.collections.Array;
6 | import gwt.react.client.api.React;
7 | import gwt.react.client.components.Component;
8 | import gwt.react.client.elements.ReactElement;
9 | import gwt.react.client.events.FormEvent;
10 | import gwt.react.client.events.KeyboardEvent;
11 | import gwt.react.client.events.MouseEvent;
12 | import gwt.react.client.proptypes.BaseProps;
13 | import gwt.react.client.proptypes.html.HtmlProps;
14 | import gwt.react.client.proptypes.html.InputProps;
15 | import gwt.react.client.proptypes.html.attributeTypes.InputType;
16 | import gwt.react_router.client.HistoryLocation;
17 | import gwt.react_router.client.RouterEnhancedProps;
18 | import jsinterop.annotations.JsPackage;
19 | import jsinterop.annotations.JsProperty;
20 | import jsinterop.annotations.JsType;
21 |
22 | import java.util.Objects;
23 |
24 | import static gwt.interop.utils.client.plainobjects.JsPlainObj.$;
25 | import static gwt.react.client.api.GwtReact.castAsReactElement;
26 | import static gwt.react.client.api.React.DOM.*;
27 |
28 | @JsType
29 | class TodoList extends Component {
30 |
31 | final static String NOW_SHOWING_ACTIVE_TODOS = "active";
32 | final static String NOW_SHOWING_COMPLETED_TODOS = "completed";
33 |
34 | enum Action { EDIT, DESTROY, TOGGLE, CANCEL }
35 |
36 | @JsType(isNative = true, namespace = JsPackage.GLOBAL, name = "Object")
37 | static class TodoRouterParams {
38 | String nowShowing;
39 | }
40 |
41 | @JsType(isNative = true, namespace = JsPackage.GLOBAL, name = "Object")
42 | static class TodoListProps extends BaseProps implements RouterEnhancedProps{
43 |
44 | //Having to define the JsProperty annotations again when implementing an interface
45 | //has been logged as an issue that should be fixed in the future
46 | @JsProperty(name="location")
47 | public native HistoryLocation getRouterLocation();
48 |
49 | @JsProperty(name="params")
50 | public native TodoRouterParams getRouterParams();
51 | }
52 |
53 | @JsType(isNative = true, namespace = JsPackage.GLOBAL, name = "Object")
54 | static class TodoListState extends JsPlainObj {
55 | String editingId;
56 | String newTodo;
57 | }
58 |
59 | public TodoList(TodoList.TodoListProps props) {
60 | super(props);
61 | state = $(new TodoListState(), "editingId",null, "newTodo","");
62 | }
63 |
64 | private void handleDoAction(Action action, TodoModel.Todo todo) {
65 | switch(action) {
66 | case TOGGLE :
67 | App.model.toggle(todo);
68 | break;
69 | case CANCEL:
70 | setState($(new TodoListState(),"editingId", null));
71 | break;
72 | case DESTROY:
73 | App.model.destroy(todo);
74 | break;
75 | case EDIT:
76 | setState($(new TodoListState(),"editingId", todo.id));
77 | }
78 | }
79 |
80 | private void handleSave(TodoModel.Todo todoToSave, String text) {
81 | App.model.save(todoToSave, text);
82 | setState($(new TodoListState(),"editingId", null));
83 | }
84 |
85 | private void handleClearCompleted(MouseEvent event) {
86 | App.model.clearCompleted();
87 | }
88 |
89 | private void handleToggleAll(FormEvent event) {
90 | App.model.toggleAll(((HTMLInputElement)event.target).checked);
91 | }
92 |
93 | private void handleNewTodoKeyDown(KeyboardEvent event) {
94 | if (event.keyCode != App.ENTER_KEY) {
95 | return;
96 | }
97 |
98 | event.preventDefault();
99 |
100 | String val = state.newTodo.trim();
101 |
102 | if (val.length() > 0) {
103 | App.model.addTodo(val);
104 | setState($(new TodoListState(), "newTodo", ""));
105 | }
106 | }
107 |
108 | private void handleChange(FormEvent event) {
109 | setState($(new TodoListState(),"newTodo", (((HTMLInputElement)event.target).value)));
110 | }
111 |
112 | public ReactElement render() {
113 | ReactElement footer = null;
114 | ReactElement main = null;
115 | Array todos = App.model.todos;
116 | String nowShowing = props.getRouterParams().nowShowing;
117 |
118 | Array shownTodos = todos.filter((todo, index, theArray) -> {
119 | if (nowShowing == null) {
120 | return true;
121 | }else if (nowShowing.equals(NOW_SHOWING_ACTIVE_TODOS)){
122 | return !todo.completed;
123 | }else {
124 | return todo.completed;
125 | }
126 | });
127 |
128 | Array todoItems = shownTodos.map((todo, index, theArray) -> {
129 | TodoItem.TodoItemProps todoProps = new TodoItem.TodoItemProps();
130 |
131 | todoProps.key = todo.id;
132 | todoProps.todo = todo;
133 | todoProps.doAction = this::handleDoAction;
134 | todoProps.doSave = this::handleSave;
135 | todoProps.isEditing = Objects.equals(state.editingId, todo.id);
136 |
137 | return React.createElement(TodoItem.class, todoProps);
138 | });
139 |
140 | Integer activeTodoCount = todos.reduce((accum, currentValue, index, theArray) ->
141 | currentValue.completed ? accum : accum + 1, 0);
142 |
143 | int completedCount = todos.getLength() - activeTodoCount;
144 |
145 | if (activeTodoCount > 0 || completedCount > 0) {
146 | Footer.FooterProps footerProps = new Footer.FooterProps();
147 | footerProps.count = activeTodoCount;
148 | footerProps.completedCount = completedCount;
149 | footerProps.nowShowing = props.getRouterParams().nowShowing;
150 | footerProps.onClearCompleted = this::handleClearCompleted;
151 |
152 | footer = React.createElement(Footer.component, footerProps);
153 | }
154 |
155 | if (todos.getLength() > 0) {
156 | main = section(new HtmlProps()
157 | .className("header"),
158 | input(new InputProps()
159 | .className("toggle-all")
160 | .type(InputType.checkbox)
161 | .onChange(this::handleToggleAll)),
162 | ul(new HtmlProps()
163 | .className("todo-list"),
164 | castAsReactElement(todoItems)
165 | )
166 | );
167 | }
168 |
169 | return
170 | div(null,
171 | header(new HtmlProps()
172 | .className("header"),
173 | h1(null, "todos"),
174 | input(new InputProps()
175 | .className("new-todo")
176 | .placeholder("What needs to be done?")
177 | .value(state.newTodo)
178 | .onKeyDown(this::handleNewTodoKeyDown)
179 | .onChange(this::handleChange)
180 | .autoFocus(true))
181 | ),
182 | main,
183 | footer
184 | );
185 | }
186 | }
187 |
--------------------------------------------------------------------------------
/web/css/index.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | margin: 0;
4 | padding: 0;
5 | }
6 |
7 | button {
8 | margin: 0;
9 | padding: 0;
10 | border: 0;
11 | background: none;
12 | font-size: 100%;
13 | vertical-align: baseline;
14 | font-family: inherit;
15 | font-weight: inherit;
16 | color: inherit;
17 | -webkit-appearance: none;
18 | appearance: none;
19 | -webkit-font-smoothing: antialiased;
20 | -moz-font-smoothing: antialiased;
21 | font-smoothing: antialiased;
22 | }
23 |
24 | body {
25 | font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
26 | line-height: 1.4em;
27 | background: #f5f5f5;
28 | color: #4d4d4d;
29 | min-width: 230px;
30 | max-width: 550px;
31 | margin: 0 auto;
32 | -webkit-font-smoothing: antialiased;
33 | -moz-font-smoothing: antialiased;
34 | font-smoothing: antialiased;
35 | font-weight: 300;
36 | }
37 |
38 | button,
39 | input[type="checkbox"] {
40 | outline: none;
41 | }
42 |
43 | .hidden {
44 | display: none;
45 | }
46 |
47 | .todoapp {
48 | background: #fff;
49 | margin: 130px 0 40px 0;
50 | position: relative;
51 | box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2),
52 | 0 25px 50px 0 rgba(0, 0, 0, 0.1);
53 | }
54 |
55 | .todoapp input::-webkit-input-placeholder {
56 | font-style: italic;
57 | font-weight: 300;
58 | color: #e6e6e6;
59 | }
60 |
61 | .todoapp input::-moz-placeholder {
62 | font-style: italic;
63 | font-weight: 300;
64 | color: #e6e6e6;
65 | }
66 |
67 | .todoapp input::input-placeholder {
68 | font-style: italic;
69 | font-weight: 300;
70 | color: #e6e6e6;
71 | }
72 |
73 | .todoapp h1 {
74 | position: absolute;
75 | top: -155px;
76 | width: 100%;
77 | font-size: 100px;
78 | font-weight: 100;
79 | text-align: center;
80 | color: rgba(175, 47, 47, 0.15);
81 | -webkit-text-rendering: optimizeLegibility;
82 | -moz-text-rendering: optimizeLegibility;
83 | text-rendering: optimizeLegibility;
84 | }
85 |
86 | .new-todo,
87 | .edit {
88 | position: relative;
89 | margin: 0;
90 | width: 100%;
91 | font-size: 24px;
92 | font-family: inherit;
93 | font-weight: inherit;
94 | line-height: 1.4em;
95 | border: 0;
96 | outline: none;
97 | color: inherit;
98 | padding: 6px;
99 | border: 1px solid #999;
100 | box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
101 | box-sizing: border-box;
102 | -webkit-font-smoothing: antialiased;
103 | -moz-font-smoothing: antialiased;
104 | font-smoothing: antialiased;
105 | }
106 |
107 | .new-todo {
108 | padding: 16px 16px 16px 60px;
109 | border: none;
110 | background: rgba(0, 0, 0, 0.003);
111 | box-shadow: inset 0 -2px 1px rgba(0,0,0,0.03);
112 | }
113 |
114 | .main {
115 | position: relative;
116 | z-index: 2;
117 | border-top: 1px solid #e6e6e6;
118 | }
119 |
120 | label[for='toggle-all'] {
121 | display: none;
122 | }
123 |
124 | .toggle-all {
125 | position: absolute;
126 | top: -55px;
127 | left: -12px;
128 | width: 60px;
129 | height: 34px;
130 | text-align: center;
131 | border: none; /* Mobile Safari */
132 | }
133 |
134 | .toggle-all:before {
135 | content: '❯';
136 | font-size: 22px;
137 | color: #e6e6e6;
138 | padding: 10px 27px 10px 27px;
139 | }
140 |
141 | .toggle-all:checked:before {
142 | color: #737373;
143 | }
144 |
145 | .todo-list {
146 | margin: 0;
147 | padding: 0;
148 | list-style: none;
149 | }
150 |
151 | .todo-list li {
152 | position: relative;
153 | font-size: 24px;
154 | border-bottom: 1px solid #ededed;
155 | }
156 |
157 | .todo-list li:last-child {
158 | border-bottom: none;
159 | }
160 |
161 | .todo-list li.editing {
162 | border-bottom: none;
163 | padding: 0;
164 | }
165 |
166 | .todo-list li.editing .edit {
167 | display: block;
168 | width: 506px;
169 | padding: 13px 17px 12px 17px;
170 | margin: 0 0 0 43px;
171 | }
172 |
173 | .todo-list li.editing .view {
174 | display: none;
175 | }
176 |
177 | .todo-list li .toggle {
178 | text-align: center;
179 | width: 40px;
180 | /* auto, since non-WebKit browsers doesn't support input styling */
181 | height: auto;
182 | position: absolute;
183 | top: 0;
184 | bottom: 0;
185 | margin: auto 0;
186 | border: none; /* Mobile Safari */
187 | -webkit-appearance: none;
188 | appearance: none;
189 | }
190 |
191 | .todo-list li .toggle:after {
192 | content: url('data:image/svg+xml;utf8,');
193 | }
194 |
195 | .todo-list li .toggle:checked:after {
196 | content: url('data:image/svg+xml;utf8,');
197 | }
198 |
199 | .todo-list li label {
200 | white-space: pre-line;
201 | word-break: break-all;
202 | padding: 15px 60px 15px 15px;
203 | margin-left: 45px;
204 | display: block;
205 | line-height: 1.2;
206 | transition: color 0.4s;
207 | }
208 |
209 | .todo-list li.completed label {
210 | color: #d9d9d9;
211 | text-decoration: line-through;
212 | }
213 |
214 | .todo-list li .destroy {
215 | display: none;
216 | position: absolute;
217 | top: 0;
218 | right: 10px;
219 | bottom: 0;
220 | width: 40px;
221 | height: 40px;
222 | margin: auto 0;
223 | font-size: 30px;
224 | color: #cc9a9a;
225 | margin-bottom: 11px;
226 | transition: color 0.2s ease-out;
227 | }
228 |
229 | .todo-list li .destroy:hover {
230 | color: #af5b5e;
231 | }
232 |
233 | .todo-list li .destroy:after {
234 | content: '×';
235 | }
236 |
237 | .todo-list li:hover .destroy {
238 | display: block;
239 | }
240 |
241 | .todo-list li .edit {
242 | display: none;
243 | }
244 |
245 | .todo-list li.editing:last-child {
246 | margin-bottom: -1px;
247 | }
248 |
249 | .footer {
250 | color: #777;
251 | padding: 10px 15px;
252 | height: 20px;
253 | text-align: center;
254 | border-top: 1px solid #e6e6e6;
255 | }
256 |
257 | .footer:before {
258 | content: '';
259 | position: absolute;
260 | right: 0;
261 | bottom: 0;
262 | left: 0;
263 | height: 50px;
264 | overflow: hidden;
265 | box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2),
266 | 0 8px 0 -3px #f6f6f6,
267 | 0 9px 1px -3px rgba(0, 0, 0, 0.2),
268 | 0 16px 0 -6px #f6f6f6,
269 | 0 17px 2px -6px rgba(0, 0, 0, 0.2);
270 | }
271 |
272 | .todo-count {
273 | float: left;
274 | text-align: left;
275 | }
276 |
277 | .todo-count strong {
278 | font-weight: 300;
279 | }
280 |
281 | .filters {
282 | margin: 0;
283 | padding: 0;
284 | list-style: none;
285 | position: absolute;
286 | right: 0;
287 | left: 0;
288 | }
289 |
290 | .filters li {
291 | display: inline;
292 | }
293 |
294 | .filters li a {
295 | color: inherit;
296 | margin: 3px;
297 | padding: 3px 7px;
298 | text-decoration: none;
299 | border: 1px solid transparent;
300 | border-radius: 3px;
301 | }
302 |
303 | .filters li a.selected,
304 | .filters li a:hover {
305 | border-color: rgba(175, 47, 47, 0.1);
306 | }
307 |
308 | .filters li a.selected {
309 | border-color: rgba(175, 47, 47, 0.2);
310 | }
311 |
312 | .clear-completed,
313 | html .clear-completed:active {
314 | float: right;
315 | position: relative;
316 | line-height: 20px;
317 | text-decoration: none;
318 | cursor: pointer;
319 | position: relative;
320 | }
321 |
322 | .clear-completed:hover {
323 | text-decoration: underline;
324 | }
325 |
326 | .info {
327 | margin: 65px auto 0;
328 | color: #bfbfbf;
329 | font-size: 10px;
330 | text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
331 | text-align: center;
332 | }
333 |
334 | .info p {
335 | line-height: 1;
336 | }
337 |
338 | .info a {
339 | color: inherit;
340 | text-decoration: none;
341 | font-weight: 400;
342 | }
343 |
344 | .info a:hover {
345 | text-decoration: underline;
346 | }
347 |
348 | /*
349 | Hack to remove background from Mobile Safari.
350 | Can't use it globally since it destroys checkboxes in Firefox
351 | */
352 | @media screen and (-webkit-min-device-pixel-ratio:0) {
353 | .toggle-all,
354 | .todo-list li .toggle {
355 | background: none;
356 | }
357 |
358 | .todo-list li .toggle {
359 | height: 40px;
360 | }
361 |
362 | .toggle-all {
363 | -webkit-transform: rotate(90deg);
364 | transform: rotate(90deg);
365 | -webkit-appearance: none;
366 | appearance: none;
367 | }
368 | }
369 |
370 | @media (max-width: 430px) {
371 | .footer {
372 | height: 50px;
373 | }
374 |
375 | .filters {
376 | bottom: 10px;
377 | }
378 | }
--------------------------------------------------------------------------------
/web/dist/gwt-preact-bundle.min.js:
--------------------------------------------------------------------------------
1 | !function(e){function t(r){if(n[r])return n[r].exports;var o=n[r]={exports:{},id:r,loaded:!1};return e[r].call(o.exports,o,o.exports,t),o.loaded=!0,o.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}var o=n(1),i=r(o),a=n(1),u=r(a),l=n(4),c=r(l);window.React=i.default,window.ReactDOM=u.default,window.ReactDOMServer=c.default;var p={};p.cast=function(e){return e},window.GWTReact=p},function(e,t,n){(function(t){!function(t,r){e.exports=r(n(9),n(6))}(this,function(e,n){function r(){return null}function o(e){var t=e.nodeName,n=e.attributes;e.attributes={},t.defaultProps&&x(e.attributes,t.defaultProps),n&&x(e.attributes,n)}function i(e,t){var n,r,o;if(t){for(o in t)if(n=I.test(o))break;if(n){r=e.attributes={};for(o in t)t.hasOwnProperty(o)&&(r[I.test(o)?o.replace(/([A-Z0-9])/,"-$1").toLowerCase():o]=t[o])}}}function a(e,t,r){var o=t&&t._preactCompatRendered&&t._preactCompatRendered.base;o&&o.parentNode!==t&&(o=null),o||(o=t.children[0]);for(var i=t.childNodes.length;i--;)t.childNodes[i]!==o&&t.removeChild(t.childNodes[i]);var a=n.render(e,t,o);return t&&(t._preactCompatRendered=a&&(a._component||{base:a})),"function"==typeof r&&r(),a&&a._component||a}function u(e,t,r,o){var i=n.h(B,{context:e.context},t),u=a(i,r);return o&&o(u),u._component||u.base}function l(e){var t=e._preactCompatRendered&&e._preactCompatRendered.base;return!(!t||t.parentNode!==e)&&(n.render(n.h(r),e,t),!0)}function c(e){return h.bind(null,e)}function p(e,t){for(var n=t||0;n0;)r[o]=arguments[o+2];if(!_(e))return e;var i=e.attributes||e.props,a=n.h(e.nodeName||e.type,i,e.children||i&&i.children),u=[a,t];return r&&r.length?u.push(r):t&&t.children&&u.push(t.children),m(n.cloneElement.apply(void 0,u))}function _(e){return e&&(e instanceof F||e.$$typeof===V)}function y(e,t){return t._refProxies[e]||(t._refProxies[e]=function(n){t&&t.refs&&(t.refs[e]=n,null===n&&(delete t._refProxies[e],t=null))})}function b(e){var t=e.nodeName,n=e.attributes;if(n&&"string"==typeof t){var r={};for(var o in n)r[o.toLowerCase()]=o;if(r.ondoubleclick&&(n.ondblclick=n[r.ondoubleclick],delete n[r.ondoubleclick]),r.onchange&&("textarea"===t||"input"===t.toLowerCase()&&!/^fil|che|rad/i.test(n.type))){var i=r.oninput||"oninput";n[i]||(n[i]=R([n[i],n[r.onchange]]),delete n[r.onchange])}}}function g(e){var t=e.attributes;if(t){var n=t.className||t.class;n&&(t.className=n)}}function x(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n]);return e}function w(e,t){for(var n in e)if(!(n in t))return!0;for(var r in t)if(e[r]!==t[r])return!0;return!1}function C(e){return e&&e.base||e}function N(){}function k(e){function t(e,t){O(this),E.call(this,e,t,z),A.call(this,e,t)}return e=x({constructor:t},e),e.mixins&&P(e,T(e.mixins)),e.statics&&x(t,e.statics),e.propTypes&&(t.propTypes=e.propTypes),e.defaultProps&&(t.defaultProps=e.defaultProps),e.getDefaultProps&&(t.defaultProps=e.getDefaultProps()),N.prototype=E.prototype,t.prototype=x(new N,e),t.displayName=e.displayName||"Component",t}function T(e){for(var t={},n=0;n",g.indexOf(_)>-1&&(O=O.replace(/>$/," />")),S)C&&m(S)&&(S="\n"+N+h(S,N)),O+=S;else{for(var W=x&&x.length,j=[],D=~O.indexOf("\n"),V=0;V"}return(l.jsx||g.indexOf(_)===-1)&&(C&&~O.indexOf("\n")&&(O+="\n"),O+=""+_+">"),O}function i(e){var t=e.prototype;t&&t.constructor;return e.displayName||e.name||t&&(t.displayName||t.name)||a(e)}function a(e){var t=Function.prototype.toString.call(e),n=(t.match(/^\s*function\s+([^\( ]+)/)||b)[1];if(!n){for(var r=-1,o=y.length;o--;)if(y[o]===e){r=o;break}r<0&&(r=y.push(e)-1),n="UnnamedComponent"+r}return n}var u={boxFlex:1,boxFlexGroup:1,columnCount:1,fillOpacity:1,flex:1,flexGrow:1,flexPositive:1,flexShrink:1,flexNegative:1,fontWeight:1,lineClamp:1,lineHeight:1,opacity:1,order:1,orphans:1,strokeOpacity:1,widows:1,zIndex:1,zoom:1},l={"<":"<",">":">",'"':""","&":"&"},c=Object.keys||function(e){var t=[];for(var n in e)e.hasOwnProperty(n)&&t.push(n);return t},p=function(e){return String(e).replace(/[<>"&]/g,s)},s=function(e){return l[e]||e},f=function(e){return null==e||e===!1},d=function(e){var t=arguments.length<=1||void 0===arguments[1]?{}:arguments[1];return function(n){return t[n]||(t[n]=e(n))}},h=function(e,t){return String(e).replace(/(\n+)/g,"$1"+(t||"\t"))},m=function(e,t,n){return String(e).length>(t||40)||!n&&String(e).indexOf("\n")!==-1||String(e).indexOf("<")!==-1},v=d(function(e){return e.replace(/([A-Z])/g,"-$1").toLowerCase()}),_={shallow:!0},y=[],b={},g=["area","base","br","col","embed","hr","img","input","link","meta","param","source","track","wbr"];o.render=o;var x=function(e,t){return o(e,t,_)};return o.shallowRender=x,o})},function(e,t,n){!function(){"use strict";function t(){}function n(e,n){var r,o,i,a,u=M;for(a=arguments.length;a-- >2;)U.push(arguments[a]);for(n&&null!=n.children&&(U.length||U.push(n.children),delete n.children);U.length;)if((o=U.pop())&&void 0!==o.pop)for(a=o.length;a--;)U.push(o[a]);else o!==!0&&o!==!1||(o=null),(i="function"!=typeof e)&&(null==o?o="":"number"==typeof o?o=String(o):"string"!=typeof o&&(i=!1)),i&&r?u[u.length-1]+=o:u===M?u=[o]:u.push(o),r=i;var l=new t;return l.nodeName=e,l.children=u,l.attributes=null==n?void 0:n,l.key=null==n?void 0:n.key,void 0!==A.vnode&&A.vnode(l),l}function r(e,t){for(var n in t)e[n]=t[n];return e}function o(e,t){return n(e.nodeName,r(r({},e.attributes),t),arguments.length>2?[].slice.call(arguments,2):e.children)}function i(e){!e.__d&&(e.__d=!0)&&1==E.push(e)&&(A.debounceRendering||setTimeout)(a)}function a(){var e,t=E;for(E=[];e=t.pop();)e.__d&&T(e)}function u(e,t,n){return"string"==typeof t||"number"==typeof t?void 0!==e.splitText:"string"==typeof t.nodeName?!e._componentConstructor&&l(e,t.nodeName):n||e._componentConstructor===t.nodeName}function l(e,t){return e.__n===t||e.nodeName.toLowerCase()===t.toLowerCase()}function c(e){var t=r({},e.attributes);t.children=e.children;var n=e.nodeName.defaultProps;if(void 0!==n)for(var o in n)void 0===t[o]&&(t[o]=n[o]);return t}function p(e,t){var n=t?document.createElementNS("http://www.w3.org/2000/svg",e):document.createElement(e);return n.__n=e,n}function s(e){e.parentNode&&e.parentNode.removeChild(e)}function f(e,t,n,r,o){if("className"===t&&(t="class"),"key"===t);else if("ref"===t)n&&n(null),r&&r(e);else if("class"!==t||o)if("style"===t){if(r&&"string"!=typeof r&&"string"!=typeof n||(e.style.cssText=r||""),r&&"object"==typeof r){if("string"!=typeof n)for(var i in n)i in r||(e.style[i]="");for(var i in r)e.style[i]="number"==typeof r[i]&&L.test(i)===!1?r[i]+"px":r[i]}}else if("dangerouslySetInnerHTML"===t)r&&(e.innerHTML=r.__html||"");else if("o"==t[0]&&"n"==t[1]){var a=t!==(t=t.replace(/Capture$/,""));t=t.toLowerCase().substring(2),r?n||e.addEventListener(t,h,a):e.removeEventListener(t,h,a),(e.__l||(e.__l={}))[t]=r}else if("list"!==t&&"type"!==t&&!o&&t in e)d(e,t,null==r?"":r),null!=r&&r!==!1||e.removeAttribute(t);else{var u=o&&t!==(t=t.replace(/^xlink\:?/,""));null==r||r===!1?u?e.removeAttributeNS("http://www.w3.org/1999/xlink",t.toLowerCase()):e.removeAttribute(t):"function"!=typeof r&&(u?e.setAttributeNS("http://www.w3.org/1999/xlink",t.toLowerCase(),r):e.setAttribute(t,r))}else e.className=r||""}function d(e,t,n){try{e[t]=n}catch(e){}}function h(e){return this.__l[e.type](A.event&&A.event(e)||e)}function m(){for(var e;e=W.pop();)A.afterMount&&A.afterMount(e),e.componentDidMount&&e.componentDidMount()}function v(e,t,n,r,o,i){j++||(D=null!=o&&void 0!==o.ownerSVGElement,V=null!=e&&!("__preactattr_"in e));var a=_(e,t,n,r,i);return o&&a.parentNode!==o&&o.appendChild(a),--j||(V=!1,i||m()),a}function _(e,t,n,r,o){var i=e,a=D;if(null==t&&(t=""),"string"==typeof t)return e&&void 0!==e.splitText&&e.parentNode&&(!e._component||o)?e.nodeValue!=t&&(e.nodeValue=t):(i=document.createTextNode(t),e&&(e.parentNode&&e.parentNode.replaceChild(i,e),b(e,!0))),i.__preactattr_=!0,i;if("function"==typeof t.nodeName)return P(e,t,n,r);if(D="svg"===t.nodeName||"foreignObject"!==t.nodeName&&D,(!e||!l(e,String(t.nodeName)))&&(i=p(String(t.nodeName),D),e)){for(;e.firstChild;)i.appendChild(e.firstChild);e.parentNode&&e.parentNode.replaceChild(i,e),b(e,!0)}var u=i.firstChild,c=i.__preactattr_||(i.__preactattr_={}),s=t.children;return!V&&s&&1===s.length&&"string"==typeof s[0]&&null!=u&&void 0!==u.splitText&&null==u.nextSibling?u.nodeValue!=s[0]&&(u.nodeValue=s[0]):(s&&s.length||null!=u)&&y(i,s,n,r,V||null!=c.dangerouslySetInnerHTML),x(i,t.attributes,c),D=a,i}function y(e,t,n,r,o){var i,a,l,c,p=e.childNodes,f=[],d={},h=0,m=0,v=p.length,y=0,g=t?t.length:0;if(0!==v)for(var x=0;x=v?e.appendChild(c):c!==p[x]&&(c===p[x+1]?s(p[x]):e.insertBefore(c,p[x]||null)))}if(h)for(var x in d)void 0!==d[x]&&b(d[x],!1);for(;m<=y;)void 0!==(c=f[y--])&&b(c,!1)}function b(e,t){var n=e._component;n?O(n):(null!=e.__preactattr_&&e.__preactattr_.ref&&e.__preactattr_.ref(null),t!==!1&&null!=e.__preactattr_||s(e),g(e))}function g(e){for(e=e.lastChild;e;){var t=e.previousSibling;b(e,!0),e=t}}function x(e,t,n){var r;for(r in n)t&&null!=t[r]||null==n[r]||f(e,r,n[r],n[r]=void 0,D);for(r in t)"children"===r||"innerHTML"===r||r in n&&t[r]===("value"===r||"checked"===r?e[r]:n[r])||f(e,r,n[r],n[r]=t[r],D)}function w(e){var t=e.constructor.name;($[t]||($[t]=[])).push(e)}function C(e,t,n){var r,o=$[e.name];if(e.prototype&&e.prototype.render?(r=new e(t,n),S.call(r,t,n)):(r=new S(t,n),r.constructor=e,r.render=N),o)for(var i=o.length;i--;)if(o[i].constructor===e){r.__b=o[i].__b,o.splice(i,1);break}return r}function N(e,t,n){return this.constructor(e,n)}function k(e,t,n,r,o){e.__x||(e.__x=!0,(e.__r=t.ref)&&delete t.ref,(e.__k=t.key)&&delete t.key,!e.base||o?e.componentWillMount&&e.componentWillMount():e.componentWillReceiveProps&&e.componentWillReceiveProps(t,r),r&&r!==e.context&&(e.__c||(e.__c=e.context),e.context=r),e.__p||(e.__p=e.props),e.props=t,e.__x=!1,0!==n&&(1!==n&&A.syncComponentUpdates===!1&&e.base?i(e):T(e,1,o)),e.__r&&e.__r(e))}function T(e,t,n,o){if(!e.__x){var i,a,u,l=e.props,p=e.state,s=e.context,f=e.__p||l,d=e.__s||p,h=e.__c||s,_=e.base,y=e.__b,g=_||y,x=e._component,w=!1;if(_&&(e.props=f,e.state=d,e.context=h,2!==t&&e.shouldComponentUpdate&&e.shouldComponentUpdate(l,p,s)===!1?w=!0:e.componentWillUpdate&&e.componentWillUpdate(l,p,s),e.props=l,e.state=p,e.context=s),e.__p=e.__s=e.__c=e.__b=null,e.__d=!1,!w){i=e.render(l,p,s),e.getChildContext&&(s=r(r({},s),e.getChildContext()));var N,P,S=i&&i.nodeName;if("function"==typeof S){var R=c(i);a=x,a&&a.constructor===S&&R.key==a.__k?k(a,R,1,s,!1):(N=a,e._component=a=C(S,R,s),a.__b=a.__b||y,a.__u=e,k(a,R,0,s,!1),T(a,1,n,!0)),P=a.base}else u=g,N=x,N&&(u=e._component=null),(g||1===t)&&(u&&(u._component=null),P=v(u,i,s,n||!_,g&&g.parentNode,!0));if(g&&P!==g&&a!==x){var U=g.parentNode;U&&P!==U&&(U.replaceChild(P,g),N||(g._component=null,b(g,!1)))}if(N&&O(N),e.base=P,P&&!o){for(var M=e,L=e;L=L.__u;)(M=L).base=P;P._component=M,P._componentConstructor=M.constructor}}if(!_||n?W.unshift(e):w||(m(),e.componentDidUpdate&&e.componentDidUpdate(f,d,h),A.afterUpdate&&A.afterUpdate(e)),null!=e.__h)for(;e.__h.length;)e.__h.pop().call(e);j||o||m()}}function P(e,t,n,r){for(var o=e&&e._component,i=o,a=e,u=o&&e._componentConstructor===t.nodeName,l=u,p=c(t);o&&!l&&(o=o.__u);)l=o.constructor===t.nodeName;return o&&l&&(!r||o._component)?(k(o,p,3,n,r),e=o.base):(i&&!u&&(O(i),e=a=null),o=C(t.nodeName,p,n),e&&!o.__b&&(o.__b=e,a=null),k(o,p,1,n,r),e=o.base,a&&e!==a&&(a._component=null,b(a,!1))),e}function O(e){A.beforeUnmount&&A.beforeUnmount(e);var t=e.base;e.__x=!0,e.componentWillUnmount&&e.componentWillUnmount(),e.base=null;var n=e._component;n?O(n):t&&(t.__preactattr_&&t.__preactattr_.ref&&t.__preactattr_.ref(null),e.__b=t,s(t),w(e),g(t)),e.__r&&e.__r(null)}function S(e,t){this.__d=!0,this.context=t,this.props=e,this.state=this.state||{}}function R(e,t,n){return v(n,e,{},!1,t,!1)}var A={},U=[],M=[],L=/acit|ex(?:s|g|n|p|$)|rph|ows|mnc|ntw|ine[ch]|zoo|^ord/i,E=[],W=[],j=0,D=!1,V=!1,$={};r(S.prototype,{setState:function(e,t){var n=this.state;this.__s||(this.__s=r({},n)),r(n,"function"==typeof e?e(n,this.props):e),t&&(this.__h=this.__h||[]).push(t),i(this)},forceUpdate:function(e){e&&(this.__h=this.__h||[]).push(e),T(this,2)},render:function(){}});var H={h:n,createElement:n,cloneElement:o,Component:S,render:R,rerender:a,options:A};e.exports=H}()},function(e,t){function n(){throw new Error("setTimeout has not been defined")}function r(){throw new Error("clearTimeout has not been defined")}function o(e){if(p===setTimeout)return setTimeout(e,0);if((p===n||!p)&&setTimeout)return p=setTimeout,setTimeout(e,0);try{return p(e,0)}catch(t){try{return p.call(null,e,0)}catch(t){return p.call(this,e,0)}}}function i(e){if(s===clearTimeout)return clearTimeout(e);if((s===r||!s)&&clearTimeout)return s=clearTimeout,clearTimeout(e);try{return s(e)}catch(t){try{return s.call(null,e)}catch(t){return s.call(this,e)}}}function a(){m&&d&&(m=!1,d.length?h=d.concat(h):v=-1,h.length&&u())}function u(){if(!m){var e=o(a);m=!0;for(var t=h.length;t;){for(d=h,h=[];++v1)for(var n=1;n 0 ) children[ len ] = arguments[ len + 2 ];
400 |
401 | if (!isValidElement(element)) { return element; }
402 | var elementProps = element.attributes || element.props;
403 | var node = preact.h(
404 | element.nodeName || element.type,
405 | elementProps,
406 | element.children || elementProps && elementProps.children
407 | );
408 | // Only provide the 3rd argument if needed.
409 | // Arguments 3+ overwrite element.children in preactCloneElement
410 | var cloneArgs = [node, props];
411 | if (children && children.length) {
412 | cloneArgs.push(children);
413 | }
414 | else if (props && props.children) {
415 | cloneArgs.push(props.children);
416 | }
417 | return normalizeVNode(preact.cloneElement.apply(void 0, cloneArgs));
418 | }
419 |
420 |
421 | function isValidElement(element) {
422 | return element && ((element instanceof VNode) || element.$$typeof===REACT_ELEMENT_TYPE);
423 | }
424 |
425 |
426 | function createStringRefProxy(name, component) {
427 | return component._refProxies[name] || (component._refProxies[name] = function (resolved) {
428 | if (component && component.refs) {
429 | component.refs[name] = resolved;
430 | if (resolved===null) {
431 | delete component._refProxies[name];
432 | component = null;
433 | }
434 | }
435 | });
436 | }
437 |
438 |
439 | function applyEventNormalization(ref) {
440 | var nodeName = ref.nodeName;
441 | var attributes = ref.attributes;
442 |
443 | if (!attributes || typeof nodeName!=='string') { return; }
444 | var props = {};
445 | for (var i in attributes) {
446 | props[i.toLowerCase()] = i;
447 | }
448 | if (props.ondoubleclick) {
449 | attributes.ondblclick = attributes[props.ondoubleclick];
450 | delete attributes[props.ondoubleclick];
451 | }
452 | // for *textual inputs* (incl textarea), normalize `onChange` -> `onInput`:
453 | if (props.onchange && (nodeName==='textarea' || (nodeName.toLowerCase()==='input' && !/^fil|che|rad/i.test(attributes.type)))) {
454 | var normalized = props.oninput || 'oninput';
455 | if (!attributes[normalized]) {
456 | attributes[normalized] = multihook([attributes[normalized], attributes[props.onchange]]);
457 | delete attributes[props.onchange];
458 | }
459 | }
460 | }
461 |
462 |
463 | function applyClassName(ref) {
464 | var attributes = ref.attributes;
465 |
466 | if (!attributes) { return; }
467 | var cl = attributes.className || attributes.class;
468 | if (cl) { attributes.className = cl; }
469 | }
470 |
471 |
472 | function extend(base, props) {
473 | for (var key in props) {
474 | if (props.hasOwnProperty(key)) {
475 | base[key] = props[key];
476 | }
477 | }
478 | return base;
479 | }
480 |
481 |
482 | function shallowDiffers(a, b) {
483 | for (var i in a) { if (!(i in b)) { return true; } }
484 | for (var i$1 in b) { if (a[i$1]!==b[i$1]) { return true; } }
485 | return false;
486 | }
487 |
488 |
489 | function findDOMNode(component) {
490 | return component && component.base || component;
491 | }
492 |
493 |
494 | function F(){}
495 |
496 | function createClass(obj) {
497 | function cl(props, context) {
498 | bindAll(this);
499 | Component$1.call(this, props, context, BYPASS_HOOK);
500 | newComponentHook.call(this, props, context);
501 | }
502 |
503 | obj = extend({ constructor: cl }, obj);
504 |
505 | // We need to apply mixins here so that getDefaultProps is correctly mixed
506 | if (obj.mixins) {
507 | applyMixins(obj, collateMixins(obj.mixins));
508 | }
509 | if (obj.statics) {
510 | extend(cl, obj.statics);
511 | }
512 | if (obj.propTypes) {
513 | cl.propTypes = obj.propTypes;
514 | }
515 | if (obj.defaultProps) {
516 | cl.defaultProps = obj.defaultProps;
517 | }
518 | if (obj.getDefaultProps) {
519 | cl.defaultProps = obj.getDefaultProps();
520 | }
521 |
522 | F.prototype = Component$1.prototype;
523 | cl.prototype = extend(new F(), obj);
524 |
525 | cl.displayName = obj.displayName || 'Component';
526 |
527 | return cl;
528 | }
529 |
530 |
531 | // Flatten an Array of mixins to a map of method name to mixin implementations
532 | function collateMixins(mixins) {
533 | var keyed = {};
534 | for (var i=0; i 1) {
857 | for (var i = 1; i < arguments.length; i++) {
858 | args[i - 1] = arguments[i];
859 | }
860 | }
861 | queue.push(new Item(fun, args));
862 | if (queue.length === 1 && !draining) {
863 | runTimeout(drainQueue);
864 | }
865 | };
866 |
867 | // v8 likes predictible objects
868 | function Item(fun, array) {
869 | this.fun = fun;
870 | this.array = array;
871 | }
872 | Item.prototype.run = function () {
873 | this.fun.apply(null, this.array);
874 | };
875 | process.title = 'browser';
876 | process.browser = true;
877 | process.env = {};
878 | process.argv = [];
879 | process.version = ''; // empty string to avoid regexp issues
880 | process.versions = {};
881 |
882 | function noop() {}
883 |
884 | process.on = noop;
885 | process.addListener = noop;
886 | process.once = noop;
887 | process.off = noop;
888 | process.removeListener = noop;
889 | process.removeAllListeners = noop;
890 | process.emit = noop;
891 | process.prependListener = noop;
892 | process.prependOnceListener = noop;
893 |
894 | process.listeners = function (name) { return [] }
895 |
896 | process.binding = function (name) {
897 | throw new Error('process.binding is not supported');
898 | };
899 |
900 | process.cwd = function () { return '/' };
901 | process.chdir = function (dir) {
902 | throw new Error('process.chdir is not supported');
903 | };
904 | process.umask = function() { return 0; };
905 |
906 |
907 | /***/ }),
908 | /* 3 */
909 | /***/ (function(module, exports, __webpack_require__) {
910 |
911 | /* WEBPACK VAR INJECTION */(function(process) {/**
912 | * Copyright 2013-present, Facebook, Inc.
913 | * All rights reserved.
914 | *
915 | * This source code is licensed under the BSD-style license found in the
916 | * LICENSE file in the root directory of this source tree. An additional grant
917 | * of patent rights can be found in the PATENTS file in the same directory.
918 | */
919 |
920 | if (process.env.NODE_ENV !== 'production') {
921 | var REACT_ELEMENT_TYPE = (typeof Symbol === 'function' &&
922 | Symbol.for &&
923 | Symbol.for('react.element')) ||
924 | 0xeac7;
925 |
926 | var isValidElement = function(object) {
927 | return typeof object === 'object' &&
928 | object !== null &&
929 | object.$$typeof === REACT_ELEMENT_TYPE;
930 | };
931 |
932 | // By explicitly using `prop-types` you are opting into new development behavior.
933 | // http://fb.me/prop-types-in-prod
934 | var throwOnDirectAccess = true;
935 | module.exports = __webpack_require__(4)(isValidElement, throwOnDirectAccess);
936 | } else {
937 | // By explicitly using `prop-types` you are opting into new production behavior.
938 | // http://fb.me/prop-types-in-prod
939 | module.exports = __webpack_require__(10)();
940 | }
941 |
942 | /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(2)))
943 |
944 | /***/ }),
945 | /* 4 */
946 | /***/ (function(module, exports, __webpack_require__) {
947 |
948 | /* WEBPACK VAR INJECTION */(function(process) {/**
949 | * Copyright 2013-present, Facebook, Inc.
950 | * All rights reserved.
951 | *
952 | * This source code is licensed under the BSD-style license found in the
953 | * LICENSE file in the root directory of this source tree. An additional grant
954 | * of patent rights can be found in the PATENTS file in the same directory.
955 | */
956 |
957 | 'use strict';
958 |
959 | var emptyFunction = __webpack_require__(5);
960 | var invariant = __webpack_require__(6);
961 | var warning = __webpack_require__(7);
962 |
963 | var ReactPropTypesSecret = __webpack_require__(8);
964 | var checkPropTypes = __webpack_require__(9);
965 |
966 | module.exports = function(isValidElement, throwOnDirectAccess) {
967 | /* global Symbol */
968 | var ITERATOR_SYMBOL = typeof Symbol === 'function' && Symbol.iterator;
969 | var FAUX_ITERATOR_SYMBOL = '@@iterator'; // Before Symbol spec.
970 |
971 | /**
972 | * Returns the iterator method function contained on the iterable object.
973 | *
974 | * Be sure to invoke the function with the iterable as context:
975 | *
976 | * var iteratorFn = getIteratorFn(myIterable);
977 | * if (iteratorFn) {
978 | * var iterator = iteratorFn.call(myIterable);
979 | * ...
980 | * }
981 | *
982 | * @param {?object} maybeIterable
983 | * @return {?function}
984 | */
985 | function getIteratorFn(maybeIterable) {
986 | var iteratorFn = maybeIterable && (ITERATOR_SYMBOL && maybeIterable[ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL]);
987 | if (typeof iteratorFn === 'function') {
988 | return iteratorFn;
989 | }
990 | }
991 |
992 | /**
993 | * Collection of methods that allow declaration and validation of props that are
994 | * supplied to React components. Example usage:
995 | *
996 | * var Props = require('ReactPropTypes');
997 | * var MyArticle = React.createClass({
998 | * propTypes: {
999 | * // An optional string prop named "description".
1000 | * description: Props.string,
1001 | *
1002 | * // A required enum prop named "category".
1003 | * category: Props.oneOf(['News','Photos']).isRequired,
1004 | *
1005 | * // A prop named "dialog" that requires an instance of Dialog.
1006 | * dialog: Props.instanceOf(Dialog).isRequired
1007 | * },
1008 | * render: function() { ... }
1009 | * });
1010 | *
1011 | * A more formal specification of how these methods are used:
1012 | *
1013 | * type := array|bool|func|object|number|string|oneOf([...])|instanceOf(...)
1014 | * decl := ReactPropTypes.{type}(.isRequired)?
1015 | *
1016 | * Each and every declaration produces a function with the same signature. This
1017 | * allows the creation of custom validation functions. For example:
1018 | *
1019 | * var MyLink = React.createClass({
1020 | * propTypes: {
1021 | * // An optional string or URI prop named "href".
1022 | * href: function(props, propName, componentName) {
1023 | * var propValue = props[propName];
1024 | * if (propValue != null && typeof propValue !== 'string' &&
1025 | * !(propValue instanceof URI)) {
1026 | * return new Error(
1027 | * 'Expected a string or an URI for ' + propName + ' in ' +
1028 | * componentName
1029 | * );
1030 | * }
1031 | * }
1032 | * },
1033 | * render: function() {...}
1034 | * });
1035 | *
1036 | * @internal
1037 | */
1038 |
1039 | var ANONYMOUS = '<>';
1040 |
1041 | // Important!
1042 | // Keep this list in sync with production version in `./factoryWithThrowingShims.js`.
1043 | var ReactPropTypes = {
1044 | array: createPrimitiveTypeChecker('array'),
1045 | bool: createPrimitiveTypeChecker('boolean'),
1046 | func: createPrimitiveTypeChecker('function'),
1047 | number: createPrimitiveTypeChecker('number'),
1048 | object: createPrimitiveTypeChecker('object'),
1049 | string: createPrimitiveTypeChecker('string'),
1050 | symbol: createPrimitiveTypeChecker('symbol'),
1051 |
1052 | any: createAnyTypeChecker(),
1053 | arrayOf: createArrayOfTypeChecker,
1054 | element: createElementTypeChecker(),
1055 | instanceOf: createInstanceTypeChecker,
1056 | node: createNodeChecker(),
1057 | objectOf: createObjectOfTypeChecker,
1058 | oneOf: createEnumTypeChecker,
1059 | oneOfType: createUnionTypeChecker,
1060 | shape: createShapeTypeChecker
1061 | };
1062 |
1063 | /**
1064 | * inlined Object.is polyfill to avoid requiring consumers ship their own
1065 | * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
1066 | */
1067 | /*eslint-disable no-self-compare*/
1068 | function is(x, y) {
1069 | // SameValue algorithm
1070 | if (x === y) {
1071 | // Steps 1-5, 7-10
1072 | // Steps 6.b-6.e: +0 != -0
1073 | return x !== 0 || 1 / x === 1 / y;
1074 | } else {
1075 | // Step 6.a: NaN == NaN
1076 | return x !== x && y !== y;
1077 | }
1078 | }
1079 | /*eslint-enable no-self-compare*/
1080 |
1081 | /**
1082 | * We use an Error-like object for backward compatibility as people may call
1083 | * PropTypes directly and inspect their output. However, we don't use real
1084 | * Errors anymore. We don't inspect their stack anyway, and creating them
1085 | * is prohibitively expensive if they are created too often, such as what
1086 | * happens in oneOfType() for any type before the one that matched.
1087 | */
1088 | function PropTypeError(message) {
1089 | this.message = message;
1090 | this.stack = '';
1091 | }
1092 | // Make `instanceof Error` still work for returned errors.
1093 | PropTypeError.prototype = Error.prototype;
1094 |
1095 | function createChainableTypeChecker(validate) {
1096 | if (process.env.NODE_ENV !== 'production') {
1097 | var manualPropTypeCallCache = {};
1098 | var manualPropTypeWarningCount = 0;
1099 | }
1100 | function checkType(isRequired, props, propName, componentName, location, propFullName, secret) {
1101 | componentName = componentName || ANONYMOUS;
1102 | propFullName = propFullName || propName;
1103 |
1104 | if (secret !== ReactPropTypesSecret) {
1105 | if (throwOnDirectAccess) {
1106 | // New behavior only for users of `prop-types` package
1107 | invariant(
1108 | false,
1109 | 'Calling PropTypes validators directly is not supported by the `prop-types` package. ' +
1110 | 'Use `PropTypes.checkPropTypes()` to call them. ' +
1111 | 'Read more at http://fb.me/use-check-prop-types'
1112 | );
1113 | } else if (process.env.NODE_ENV !== 'production' && typeof console !== 'undefined') {
1114 | // Old behavior for people using React.PropTypes
1115 | var cacheKey = componentName + ':' + propName;
1116 | if (
1117 | !manualPropTypeCallCache[cacheKey] &&
1118 | // Avoid spamming the console because they are often not actionable except for lib authors
1119 | manualPropTypeWarningCount < 3
1120 | ) {
1121 | warning(
1122 | false,
1123 | 'You are manually calling a React.PropTypes validation ' +
1124 | 'function for the `%s` prop on `%s`. This is deprecated ' +
1125 | 'and will throw in the standalone `prop-types` package. ' +
1126 | 'You may be seeing this warning due to a third-party PropTypes ' +
1127 | 'library. See https://fb.me/react-warning-dont-call-proptypes ' + 'for details.',
1128 | propFullName,
1129 | componentName
1130 | );
1131 | manualPropTypeCallCache[cacheKey] = true;
1132 | manualPropTypeWarningCount++;
1133 | }
1134 | }
1135 | }
1136 | if (props[propName] == null) {
1137 | if (isRequired) {
1138 | if (props[propName] === null) {
1139 | return new PropTypeError('The ' + location + ' `' + propFullName + '` is marked as required ' + ('in `' + componentName + '`, but its value is `null`.'));
1140 | }
1141 | return new PropTypeError('The ' + location + ' `' + propFullName + '` is marked as required in ' + ('`' + componentName + '`, but its value is `undefined`.'));
1142 | }
1143 | return null;
1144 | } else {
1145 | return validate(props, propName, componentName, location, propFullName);
1146 | }
1147 | }
1148 |
1149 | var chainedCheckType = checkType.bind(null, false);
1150 | chainedCheckType.isRequired = checkType.bind(null, true);
1151 |
1152 | return chainedCheckType;
1153 | }
1154 |
1155 | function createPrimitiveTypeChecker(expectedType) {
1156 | function validate(props, propName, componentName, location, propFullName, secret) {
1157 | var propValue = props[propName];
1158 | var propType = getPropType(propValue);
1159 | if (propType !== expectedType) {
1160 | // `propValue` being instance of, say, date/regexp, pass the 'object'
1161 | // check, but we can offer a more precise error message here rather than
1162 | // 'of type `object`'.
1163 | var preciseType = getPreciseType(propValue);
1164 |
1165 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + preciseType + '` supplied to `' + componentName + '`, expected ') + ('`' + expectedType + '`.'));
1166 | }
1167 | return null;
1168 | }
1169 | return createChainableTypeChecker(validate);
1170 | }
1171 |
1172 | function createAnyTypeChecker() {
1173 | return createChainableTypeChecker(emptyFunction.thatReturnsNull);
1174 | }
1175 |
1176 | function createArrayOfTypeChecker(typeChecker) {
1177 | function validate(props, propName, componentName, location, propFullName) {
1178 | if (typeof typeChecker !== 'function') {
1179 | return new PropTypeError('Property `' + propFullName + '` of component `' + componentName + '` has invalid PropType notation inside arrayOf.');
1180 | }
1181 | var propValue = props[propName];
1182 | if (!Array.isArray(propValue)) {
1183 | var propType = getPropType(propValue);
1184 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected an array.'));
1185 | }
1186 | for (var i = 0; i < propValue.length; i++) {
1187 | var error = typeChecker(propValue, i, componentName, location, propFullName + '[' + i + ']', ReactPropTypesSecret);
1188 | if (error instanceof Error) {
1189 | return error;
1190 | }
1191 | }
1192 | return null;
1193 | }
1194 | return createChainableTypeChecker(validate);
1195 | }
1196 |
1197 | function createElementTypeChecker() {
1198 | function validate(props, propName, componentName, location, propFullName) {
1199 | var propValue = props[propName];
1200 | if (!isValidElement(propValue)) {
1201 | var propType = getPropType(propValue);
1202 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected a single ReactElement.'));
1203 | }
1204 | return null;
1205 | }
1206 | return createChainableTypeChecker(validate);
1207 | }
1208 |
1209 | function createInstanceTypeChecker(expectedClass) {
1210 | function validate(props, propName, componentName, location, propFullName) {
1211 | if (!(props[propName] instanceof expectedClass)) {
1212 | var expectedClassName = expectedClass.name || ANONYMOUS;
1213 | var actualClassName = getClassName(props[propName]);
1214 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + actualClassName + '` supplied to `' + componentName + '`, expected ') + ('instance of `' + expectedClassName + '`.'));
1215 | }
1216 | return null;
1217 | }
1218 | return createChainableTypeChecker(validate);
1219 | }
1220 |
1221 | function createEnumTypeChecker(expectedValues) {
1222 | if (!Array.isArray(expectedValues)) {
1223 | process.env.NODE_ENV !== 'production' ? warning(false, 'Invalid argument supplied to oneOf, expected an instance of array.') : void 0;
1224 | return emptyFunction.thatReturnsNull;
1225 | }
1226 |
1227 | function validate(props, propName, componentName, location, propFullName) {
1228 | var propValue = props[propName];
1229 | for (var i = 0; i < expectedValues.length; i++) {
1230 | if (is(propValue, expectedValues[i])) {
1231 | return null;
1232 | }
1233 | }
1234 |
1235 | var valuesString = JSON.stringify(expectedValues);
1236 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of value `' + propValue + '` ' + ('supplied to `' + componentName + '`, expected one of ' + valuesString + '.'));
1237 | }
1238 | return createChainableTypeChecker(validate);
1239 | }
1240 |
1241 | function createObjectOfTypeChecker(typeChecker) {
1242 | function validate(props, propName, componentName, location, propFullName) {
1243 | if (typeof typeChecker !== 'function') {
1244 | return new PropTypeError('Property `' + propFullName + '` of component `' + componentName + '` has invalid PropType notation inside objectOf.');
1245 | }
1246 | var propValue = props[propName];
1247 | var propType = getPropType(propValue);
1248 | if (propType !== 'object') {
1249 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected an object.'));
1250 | }
1251 | for (var key in propValue) {
1252 | if (propValue.hasOwnProperty(key)) {
1253 | var error = typeChecker(propValue, key, componentName, location, propFullName + '.' + key, ReactPropTypesSecret);
1254 | if (error instanceof Error) {
1255 | return error;
1256 | }
1257 | }
1258 | }
1259 | return null;
1260 | }
1261 | return createChainableTypeChecker(validate);
1262 | }
1263 |
1264 | function createUnionTypeChecker(arrayOfTypeCheckers) {
1265 | if (!Array.isArray(arrayOfTypeCheckers)) {
1266 | process.env.NODE_ENV !== 'production' ? warning(false, 'Invalid argument supplied to oneOfType, expected an instance of array.') : void 0;
1267 | return emptyFunction.thatReturnsNull;
1268 | }
1269 |
1270 | function validate(props, propName, componentName, location, propFullName) {
1271 | for (var i = 0; i < arrayOfTypeCheckers.length; i++) {
1272 | var checker = arrayOfTypeCheckers[i];
1273 | if (checker(props, propName, componentName, location, propFullName, ReactPropTypesSecret) == null) {
1274 | return null;
1275 | }
1276 | }
1277 |
1278 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` supplied to ' + ('`' + componentName + '`.'));
1279 | }
1280 | return createChainableTypeChecker(validate);
1281 | }
1282 |
1283 | function createNodeChecker() {
1284 | function validate(props, propName, componentName, location, propFullName) {
1285 | if (!isNode(props[propName])) {
1286 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` supplied to ' + ('`' + componentName + '`, expected a ReactNode.'));
1287 | }
1288 | return null;
1289 | }
1290 | return createChainableTypeChecker(validate);
1291 | }
1292 |
1293 | function createShapeTypeChecker(shapeTypes) {
1294 | function validate(props, propName, componentName, location, propFullName) {
1295 | var propValue = props[propName];
1296 | var propType = getPropType(propValue);
1297 | if (propType !== 'object') {
1298 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type `' + propType + '` ' + ('supplied to `' + componentName + '`, expected `object`.'));
1299 | }
1300 | for (var key in shapeTypes) {
1301 | var checker = shapeTypes[key];
1302 | if (!checker) {
1303 | continue;
1304 | }
1305 | var error = checker(propValue, key, componentName, location, propFullName + '.' + key, ReactPropTypesSecret);
1306 | if (error) {
1307 | return error;
1308 | }
1309 | }
1310 | return null;
1311 | }
1312 | return createChainableTypeChecker(validate);
1313 | }
1314 |
1315 | function isNode(propValue) {
1316 | switch (typeof propValue) {
1317 | case 'number':
1318 | case 'string':
1319 | case 'undefined':
1320 | return true;
1321 | case 'boolean':
1322 | return !propValue;
1323 | case 'object':
1324 | if (Array.isArray(propValue)) {
1325 | return propValue.every(isNode);
1326 | }
1327 | if (propValue === null || isValidElement(propValue)) {
1328 | return true;
1329 | }
1330 |
1331 | var iteratorFn = getIteratorFn(propValue);
1332 | if (iteratorFn) {
1333 | var iterator = iteratorFn.call(propValue);
1334 | var step;
1335 | if (iteratorFn !== propValue.entries) {
1336 | while (!(step = iterator.next()).done) {
1337 | if (!isNode(step.value)) {
1338 | return false;
1339 | }
1340 | }
1341 | } else {
1342 | // Iterator will provide entry [k,v] tuples rather than values.
1343 | while (!(step = iterator.next()).done) {
1344 | var entry = step.value;
1345 | if (entry) {
1346 | if (!isNode(entry[1])) {
1347 | return false;
1348 | }
1349 | }
1350 | }
1351 | }
1352 | } else {
1353 | return false;
1354 | }
1355 |
1356 | return true;
1357 | default:
1358 | return false;
1359 | }
1360 | }
1361 |
1362 | function isSymbol(propType, propValue) {
1363 | // Native Symbol.
1364 | if (propType === 'symbol') {
1365 | return true;
1366 | }
1367 |
1368 | // 19.4.3.5 Symbol.prototype[@@toStringTag] === 'Symbol'
1369 | if (propValue['@@toStringTag'] === 'Symbol') {
1370 | return true;
1371 | }
1372 |
1373 | // Fallback for non-spec compliant Symbols which are polyfilled.
1374 | if (typeof Symbol === 'function' && propValue instanceof Symbol) {
1375 | return true;
1376 | }
1377 |
1378 | return false;
1379 | }
1380 |
1381 | // Equivalent of `typeof` but with special handling for array and regexp.
1382 | function getPropType(propValue) {
1383 | var propType = typeof propValue;
1384 | if (Array.isArray(propValue)) {
1385 | return 'array';
1386 | }
1387 | if (propValue instanceof RegExp) {
1388 | // Old webkits (at least until Android 4.0) return 'function' rather than
1389 | // 'object' for typeof a RegExp. We'll normalize this here so that /bla/
1390 | // passes PropTypes.object.
1391 | return 'object';
1392 | }
1393 | if (isSymbol(propType, propValue)) {
1394 | return 'symbol';
1395 | }
1396 | return propType;
1397 | }
1398 |
1399 | // This handles more types than `getPropType`. Only used for error messages.
1400 | // See `createPrimitiveTypeChecker`.
1401 | function getPreciseType(propValue) {
1402 | var propType = getPropType(propValue);
1403 | if (propType === 'object') {
1404 | if (propValue instanceof Date) {
1405 | return 'date';
1406 | } else if (propValue instanceof RegExp) {
1407 | return 'regexp';
1408 | }
1409 | }
1410 | return propType;
1411 | }
1412 |
1413 | // Returns class name of the object, if any.
1414 | function getClassName(propValue) {
1415 | if (!propValue.constructor || !propValue.constructor.name) {
1416 | return ANONYMOUS;
1417 | }
1418 | return propValue.constructor.name;
1419 | }
1420 |
1421 | ReactPropTypes.checkPropTypes = checkPropTypes;
1422 | ReactPropTypes.PropTypes = ReactPropTypes;
1423 |
1424 | return ReactPropTypes;
1425 | };
1426 |
1427 | /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(2)))
1428 |
1429 | /***/ }),
1430 | /* 5 */
1431 | /***/ (function(module, exports) {
1432 |
1433 | "use strict";
1434 |
1435 | /**
1436 | * Copyright (c) 2013-present, Facebook, Inc.
1437 | * All rights reserved.
1438 | *
1439 | * This source code is licensed under the BSD-style license found in the
1440 | * LICENSE file in the root directory of this source tree. An additional grant
1441 | * of patent rights can be found in the PATENTS file in the same directory.
1442 | *
1443 | *
1444 | */
1445 |
1446 | function makeEmptyFunction(arg) {
1447 | return function () {
1448 | return arg;
1449 | };
1450 | }
1451 |
1452 | /**
1453 | * This function accepts and discards inputs; it has no side effects. This is
1454 | * primarily useful idiomatically for overridable function endpoints which
1455 | * always need to be callable, since JS lacks a null-call idiom ala Cocoa.
1456 | */
1457 | var emptyFunction = function emptyFunction() {};
1458 |
1459 | emptyFunction.thatReturns = makeEmptyFunction;
1460 | emptyFunction.thatReturnsFalse = makeEmptyFunction(false);
1461 | emptyFunction.thatReturnsTrue = makeEmptyFunction(true);
1462 | emptyFunction.thatReturnsNull = makeEmptyFunction(null);
1463 | emptyFunction.thatReturnsThis = function () {
1464 | return this;
1465 | };
1466 | emptyFunction.thatReturnsArgument = function (arg) {
1467 | return arg;
1468 | };
1469 |
1470 | module.exports = emptyFunction;
1471 |
1472 | /***/ }),
1473 | /* 6 */
1474 | /***/ (function(module, exports, __webpack_require__) {
1475 |
1476 | /* WEBPACK VAR INJECTION */(function(process) {/**
1477 | * Copyright (c) 2013-present, Facebook, Inc.
1478 | * All rights reserved.
1479 | *
1480 | * This source code is licensed under the BSD-style license found in the
1481 | * LICENSE file in the root directory of this source tree. An additional grant
1482 | * of patent rights can be found in the PATENTS file in the same directory.
1483 | *
1484 | */
1485 |
1486 | 'use strict';
1487 |
1488 | /**
1489 | * Use invariant() to assert state which your program assumes to be true.
1490 | *
1491 | * Provide sprintf-style format (only %s is supported) and arguments
1492 | * to provide information about what broke and what you were
1493 | * expecting.
1494 | *
1495 | * The invariant message will be stripped in production, but the invariant
1496 | * will remain to ensure logic does not differ in production.
1497 | */
1498 |
1499 | var validateFormat = function validateFormat(format) {};
1500 |
1501 | if (process.env.NODE_ENV !== 'production') {
1502 | validateFormat = function validateFormat(format) {
1503 | if (format === undefined) {
1504 | throw new Error('invariant requires an error message argument');
1505 | }
1506 | };
1507 | }
1508 |
1509 | function invariant(condition, format, a, b, c, d, e, f) {
1510 | validateFormat(format);
1511 |
1512 | if (!condition) {
1513 | var error;
1514 | if (format === undefined) {
1515 | error = new Error('Minified exception occurred; use the non-minified dev environment ' + 'for the full error message and additional helpful warnings.');
1516 | } else {
1517 | var args = [a, b, c, d, e, f];
1518 | var argIndex = 0;
1519 | error = new Error(format.replace(/%s/g, function () {
1520 | return args[argIndex++];
1521 | }));
1522 | error.name = 'Invariant Violation';
1523 | }
1524 |
1525 | error.framesToPop = 1; // we don't care about invariant's own frame
1526 | throw error;
1527 | }
1528 | }
1529 |
1530 | module.exports = invariant;
1531 | /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(2)))
1532 |
1533 | /***/ }),
1534 | /* 7 */
1535 | /***/ (function(module, exports, __webpack_require__) {
1536 |
1537 | /* WEBPACK VAR INJECTION */(function(process) {/**
1538 | * Copyright 2014-2015, Facebook, Inc.
1539 | * All rights reserved.
1540 | *
1541 | * This source code is licensed under the BSD-style license found in the
1542 | * LICENSE file in the root directory of this source tree. An additional grant
1543 | * of patent rights can be found in the PATENTS file in the same directory.
1544 | *
1545 | */
1546 |
1547 | 'use strict';
1548 |
1549 | var emptyFunction = __webpack_require__(5);
1550 |
1551 | /**
1552 | * Similar to invariant but only logs a warning if the condition is not met.
1553 | * This can be used to log issues in development environments in critical
1554 | * paths. Removing the logging code for production environments will keep the
1555 | * same logic and follow the same code paths.
1556 | */
1557 |
1558 | var warning = emptyFunction;
1559 |
1560 | if (process.env.NODE_ENV !== 'production') {
1561 | (function () {
1562 | var printWarning = function printWarning(format) {
1563 | for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
1564 | args[_key - 1] = arguments[_key];
1565 | }
1566 |
1567 | var argIndex = 0;
1568 | var message = 'Warning: ' + format.replace(/%s/g, function () {
1569 | return args[argIndex++];
1570 | });
1571 | if (typeof console !== 'undefined') {
1572 | console.error(message);
1573 | }
1574 | try {
1575 | // --- Welcome to debugging React ---
1576 | // This error was thrown as a convenience so that you can use this stack
1577 | // to find the callsite that caused this warning to fire.
1578 | throw new Error(message);
1579 | } catch (x) {}
1580 | };
1581 |
1582 | warning = function warning(condition, format) {
1583 | if (format === undefined) {
1584 | throw new Error('`warning(condition, format, ...args)` requires a warning ' + 'message argument');
1585 | }
1586 |
1587 | if (format.indexOf('Failed Composite propType: ') === 0) {
1588 | return; // Ignore CompositeComponent proptype check.
1589 | }
1590 |
1591 | if (!condition) {
1592 | for (var _len2 = arguments.length, args = Array(_len2 > 2 ? _len2 - 2 : 0), _key2 = 2; _key2 < _len2; _key2++) {
1593 | args[_key2 - 2] = arguments[_key2];
1594 | }
1595 |
1596 | printWarning.apply(undefined, [format].concat(args));
1597 | }
1598 | };
1599 | })();
1600 | }
1601 |
1602 | module.exports = warning;
1603 | /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(2)))
1604 |
1605 | /***/ }),
1606 | /* 8 */
1607 | /***/ (function(module, exports) {
1608 |
1609 | /**
1610 | * Copyright 2013-present, Facebook, Inc.
1611 | * All rights reserved.
1612 | *
1613 | * This source code is licensed under the BSD-style license found in the
1614 | * LICENSE file in the root directory of this source tree. An additional grant
1615 | * of patent rights can be found in the PATENTS file in the same directory.
1616 | */
1617 |
1618 | 'use strict';
1619 |
1620 | var ReactPropTypesSecret = 'SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED';
1621 |
1622 | module.exports = ReactPropTypesSecret;
1623 |
1624 |
1625 | /***/ }),
1626 | /* 9 */
1627 | /***/ (function(module, exports, __webpack_require__) {
1628 |
1629 | /* WEBPACK VAR INJECTION */(function(process) {/**
1630 | * Copyright 2013-present, Facebook, Inc.
1631 | * All rights reserved.
1632 | *
1633 | * This source code is licensed under the BSD-style license found in the
1634 | * LICENSE file in the root directory of this source tree. An additional grant
1635 | * of patent rights can be found in the PATENTS file in the same directory.
1636 | */
1637 |
1638 | 'use strict';
1639 |
1640 | if (process.env.NODE_ENV !== 'production') {
1641 | var invariant = __webpack_require__(6);
1642 | var warning = __webpack_require__(7);
1643 | var ReactPropTypesSecret = __webpack_require__(8);
1644 | var loggedTypeFailures = {};
1645 | }
1646 |
1647 | /**
1648 | * Assert that the values match with the type specs.
1649 | * Error messages are memorized and will only be shown once.
1650 | *
1651 | * @param {object} typeSpecs Map of name to a ReactPropType
1652 | * @param {object} values Runtime values that need to be type-checked
1653 | * @param {string} location e.g. "prop", "context", "child context"
1654 | * @param {string} componentName Name of the component for error messages.
1655 | * @param {?Function} getStack Returns the component stack.
1656 | * @private
1657 | */
1658 | function checkPropTypes(typeSpecs, values, location, componentName, getStack) {
1659 | if (process.env.NODE_ENV !== 'production') {
1660 | for (var typeSpecName in typeSpecs) {
1661 | if (typeSpecs.hasOwnProperty(typeSpecName)) {
1662 | var error;
1663 | // Prop type validation may throw. In case they do, we don't want to
1664 | // fail the render phase where it didn't fail before. So we log it.
1665 | // After these have been cleaned up, we'll let them throw.
1666 | try {
1667 | // This is intentionally an invariant that gets caught. It's the same
1668 | // behavior as without this statement except with a better message.
1669 | invariant(typeof typeSpecs[typeSpecName] === 'function', '%s: %s type `%s` is invalid; it must be a function, usually from ' + 'React.PropTypes.', componentName || 'React class', location, typeSpecName);
1670 | error = typeSpecs[typeSpecName](values, typeSpecName, componentName, location, null, ReactPropTypesSecret);
1671 | } catch (ex) {
1672 | error = ex;
1673 | }
1674 | warning(!error || error instanceof Error, '%s: type specification of %s `%s` is invalid; the type checker ' + 'function must return `null` or an `Error` but returned a %s. ' + 'You may have forgotten to pass an argument to the type checker ' + 'creator (arrayOf, instanceOf, objectOf, oneOf, oneOfType, and ' + 'shape all require an argument).', componentName || 'React class', location, typeSpecName, typeof error);
1675 | if (error instanceof Error && !(error.message in loggedTypeFailures)) {
1676 | // Only monitor this failure once because there tends to be a lot of the
1677 | // same error.
1678 | loggedTypeFailures[error.message] = true;
1679 |
1680 | var stack = getStack ? getStack() : '';
1681 |
1682 | warning(false, 'Failed %s type: %s%s', location, error.message, stack != null ? stack : '');
1683 | }
1684 | }
1685 | }
1686 | }
1687 | }
1688 |
1689 | module.exports = checkPropTypes;
1690 |
1691 | /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(2)))
1692 |
1693 | /***/ }),
1694 | /* 10 */
1695 | /***/ (function(module, exports, __webpack_require__) {
1696 |
1697 | /**
1698 | * Copyright 2013-present, Facebook, Inc.
1699 | * All rights reserved.
1700 | *
1701 | * This source code is licensed under the BSD-style license found in the
1702 | * LICENSE file in the root directory of this source tree. An additional grant
1703 | * of patent rights can be found in the PATENTS file in the same directory.
1704 | */
1705 |
1706 | 'use strict';
1707 |
1708 | var emptyFunction = __webpack_require__(5);
1709 | var invariant = __webpack_require__(6);
1710 |
1711 | module.exports = function() {
1712 | // Important!
1713 | // Keep this list in sync with production version in `./factoryWithTypeCheckers.js`.
1714 | function shim() {
1715 | invariant(
1716 | false,
1717 | 'Calling PropTypes validators directly is not supported by the `prop-types` package. ' +
1718 | 'Use PropTypes.checkPropTypes() to call them. ' +
1719 | 'Read more at http://fb.me/use-check-prop-types'
1720 | );
1721 | };
1722 | shim.isRequired = shim;
1723 | function getShim() {
1724 | return shim;
1725 | };
1726 | var ReactPropTypes = {
1727 | array: shim,
1728 | bool: shim,
1729 | func: shim,
1730 | number: shim,
1731 | object: shim,
1732 | string: shim,
1733 | symbol: shim,
1734 |
1735 | any: shim,
1736 | arrayOf: getShim,
1737 | element: shim,
1738 | instanceOf: getShim,
1739 | node: shim,
1740 | objectOf: getShim,
1741 | oneOf: getShim,
1742 | oneOfType: getShim,
1743 | shape: getShim
1744 | };
1745 |
1746 | ReactPropTypes.checkPropTypes = emptyFunction;
1747 | ReactPropTypes.PropTypes = ReactPropTypes;
1748 |
1749 | return ReactPropTypes;
1750 | };
1751 |
1752 |
1753 | /***/ }),
1754 | /* 11 */
1755 | /***/ (function(module, exports, __webpack_require__) {
1756 |
1757 | !function() {
1758 | 'use strict';
1759 | function VNode() {}
1760 | function h(nodeName, attributes) {
1761 | var lastSimple, child, simple, i, children = EMPTY_CHILDREN;
1762 | for (i = arguments.length; i-- > 2; ) stack.push(arguments[i]);
1763 | if (attributes && null != attributes.children) {
1764 | if (!stack.length) stack.push(attributes.children);
1765 | delete attributes.children;
1766 | }
1767 | while (stack.length) if ((child = stack.pop()) && void 0 !== child.pop) for (i = child.length; i--; ) stack.push(child[i]); else {
1768 | if (child === !0 || child === !1) child = null;
1769 | if (simple = 'function' != typeof nodeName) if (null == child) child = ''; else if ('number' == typeof child) child = String(child); else if ('string' != typeof child) simple = !1;
1770 | if (simple && lastSimple) children[children.length - 1] += child; else if (children === EMPTY_CHILDREN) children = [ child ]; else children.push(child);
1771 | lastSimple = simple;
1772 | }
1773 | var p = new VNode();
1774 | p.nodeName = nodeName;
1775 | p.children = children;
1776 | p.attributes = null == attributes ? void 0 : attributes;
1777 | p.key = null == attributes ? void 0 : attributes.key;
1778 | if (void 0 !== options.vnode) options.vnode(p);
1779 | return p;
1780 | }
1781 | function extend(obj, props) {
1782 | for (var i in props) obj[i] = props[i];
1783 | return obj;
1784 | }
1785 | function cloneElement(vnode, props) {
1786 | return h(vnode.nodeName, extend(extend({}, vnode.attributes), props), arguments.length > 2 ? [].slice.call(arguments, 2) : vnode.children);
1787 | }
1788 | function enqueueRender(component) {
1789 | if (!component.__d && (component.__d = !0) && 1 == items.push(component)) (options.debounceRendering || setTimeout)(rerender);
1790 | }
1791 | function rerender() {
1792 | var p, list = items;
1793 | items = [];
1794 | while (p = list.pop()) if (p.__d) renderComponent(p);
1795 | }
1796 | function isSameNodeType(node, vnode, hydrating) {
1797 | if ('string' == typeof vnode || 'number' == typeof vnode) return void 0 !== node.splitText;
1798 | if ('string' == typeof vnode.nodeName) return !node._componentConstructor && isNamedNode(node, vnode.nodeName); else return hydrating || node._componentConstructor === vnode.nodeName;
1799 | }
1800 | function isNamedNode(node, nodeName) {
1801 | return node.__n === nodeName || node.nodeName.toLowerCase() === nodeName.toLowerCase();
1802 | }
1803 | function getNodeProps(vnode) {
1804 | var props = extend({}, vnode.attributes);
1805 | props.children = vnode.children;
1806 | var defaultProps = vnode.nodeName.defaultProps;
1807 | if (void 0 !== defaultProps) for (var i in defaultProps) if (void 0 === props[i]) props[i] = defaultProps[i];
1808 | return props;
1809 | }
1810 | function createNode(nodeName, isSvg) {
1811 | var node = isSvg ? document.createElementNS('http://www.w3.org/2000/svg', nodeName) : document.createElement(nodeName);
1812 | node.__n = nodeName;
1813 | return node;
1814 | }
1815 | function removeNode(node) {
1816 | if (node.parentNode) node.parentNode.removeChild(node);
1817 | }
1818 | function setAccessor(node, name, old, value, isSvg) {
1819 | if ('className' === name) name = 'class';
1820 | if ('key' === name) ; else if ('ref' === name) {
1821 | if (old) old(null);
1822 | if (value) value(node);
1823 | } else if ('class' === name && !isSvg) node.className = value || ''; else if ('style' === name) {
1824 | if (!value || 'string' == typeof value || 'string' == typeof old) node.style.cssText = value || '';
1825 | if (value && 'object' == typeof value) {
1826 | if ('string' != typeof old) for (var i in old) if (!(i in value)) node.style[i] = '';
1827 | for (var i in value) node.style[i] = 'number' == typeof value[i] && IS_NON_DIMENSIONAL.test(i) === !1 ? value[i] + 'px' : value[i];
1828 | }
1829 | } else if ('dangerouslySetInnerHTML' === name) {
1830 | if (value) node.innerHTML = value.__html || '';
1831 | } else if ('o' == name[0] && 'n' == name[1]) {
1832 | var useCapture = name !== (name = name.replace(/Capture$/, ''));
1833 | name = name.toLowerCase().substring(2);
1834 | if (value) {
1835 | if (!old) node.addEventListener(name, eventProxy, useCapture);
1836 | } else node.removeEventListener(name, eventProxy, useCapture);
1837 | (node.__l || (node.__l = {}))[name] = value;
1838 | } else if ('list' !== name && 'type' !== name && !isSvg && name in node) {
1839 | setProperty(node, name, null == value ? '' : value);
1840 | if (null == value || value === !1) node.removeAttribute(name);
1841 | } else {
1842 | var ns = isSvg && name !== (name = name.replace(/^xlink\:?/, ''));
1843 | if (null == value || value === !1) if (ns) node.removeAttributeNS('http://www.w3.org/1999/xlink', name.toLowerCase()); else node.removeAttribute(name); else if ('function' != typeof value) if (ns) node.setAttributeNS('http://www.w3.org/1999/xlink', name.toLowerCase(), value); else node.setAttribute(name, value);
1844 | }
1845 | }
1846 | function setProperty(node, name, value) {
1847 | try {
1848 | node[name] = value;
1849 | } catch (e) {}
1850 | }
1851 | function eventProxy(e) {
1852 | return this.__l[e.type](options.event && options.event(e) || e);
1853 | }
1854 | function flushMounts() {
1855 | var c;
1856 | while (c = mounts.pop()) {
1857 | if (options.afterMount) options.afterMount(c);
1858 | if (c.componentDidMount) c.componentDidMount();
1859 | }
1860 | }
1861 | function diff(dom, vnode, context, mountAll, parent, componentRoot) {
1862 | if (!diffLevel++) {
1863 | isSvgMode = null != parent && void 0 !== parent.ownerSVGElement;
1864 | hydrating = null != dom && !('__preactattr_' in dom);
1865 | }
1866 | var ret = idiff(dom, vnode, context, mountAll, componentRoot);
1867 | if (parent && ret.parentNode !== parent) parent.appendChild(ret);
1868 | if (!--diffLevel) {
1869 | hydrating = !1;
1870 | if (!componentRoot) flushMounts();
1871 | }
1872 | return ret;
1873 | }
1874 | function idiff(dom, vnode, context, mountAll, componentRoot) {
1875 | var out = dom, prevSvgMode = isSvgMode;
1876 | if (null == vnode) vnode = '';
1877 | if ('string' == typeof vnode) {
1878 | if (dom && void 0 !== dom.splitText && dom.parentNode && (!dom._component || componentRoot)) {
1879 | if (dom.nodeValue != vnode) dom.nodeValue = vnode;
1880 | } else {
1881 | out = document.createTextNode(vnode);
1882 | if (dom) {
1883 | if (dom.parentNode) dom.parentNode.replaceChild(out, dom);
1884 | recollectNodeTree(dom, !0);
1885 | }
1886 | }
1887 | out.__preactattr_ = !0;
1888 | return out;
1889 | }
1890 | if ('function' == typeof vnode.nodeName) return buildComponentFromVNode(dom, vnode, context, mountAll);
1891 | isSvgMode = 'svg' === vnode.nodeName ? !0 : 'foreignObject' === vnode.nodeName ? !1 : isSvgMode;
1892 | if (!dom || !isNamedNode(dom, String(vnode.nodeName))) {
1893 | out = createNode(String(vnode.nodeName), isSvgMode);
1894 | if (dom) {
1895 | while (dom.firstChild) out.appendChild(dom.firstChild);
1896 | if (dom.parentNode) dom.parentNode.replaceChild(out, dom);
1897 | recollectNodeTree(dom, !0);
1898 | }
1899 | }
1900 | var fc = out.firstChild, props = out.__preactattr_ || (out.__preactattr_ = {}), vchildren = vnode.children;
1901 | if (!hydrating && vchildren && 1 === vchildren.length && 'string' == typeof vchildren[0] && null != fc && void 0 !== fc.splitText && null == fc.nextSibling) {
1902 | if (fc.nodeValue != vchildren[0]) fc.nodeValue = vchildren[0];
1903 | } else if (vchildren && vchildren.length || null != fc) innerDiffNode(out, vchildren, context, mountAll, hydrating || null != props.dangerouslySetInnerHTML);
1904 | diffAttributes(out, vnode.attributes, props);
1905 | isSvgMode = prevSvgMode;
1906 | return out;
1907 | }
1908 | function innerDiffNode(dom, vchildren, context, mountAll, isHydrating) {
1909 | var j, c, vchild, child, originalChildren = dom.childNodes, children = [], keyed = {}, keyedLen = 0, min = 0, len = originalChildren.length, childrenLen = 0, vlen = vchildren ? vchildren.length : 0;
1910 | if (0 !== len) for (var i = 0; i < len; i++) {
1911 | var _child = originalChildren[i], props = _child.__preactattr_, key = vlen && props ? _child._component ? _child._component.__k : props.key : null;
1912 | if (null != key) {
1913 | keyedLen++;
1914 | keyed[key] = _child;
1915 | } else if (props || (void 0 !== _child.splitText ? isHydrating ? _child.nodeValue.trim() : !0 : isHydrating)) children[childrenLen++] = _child;
1916 | }
1917 | if (0 !== vlen) for (var i = 0; i < vlen; i++) {
1918 | vchild = vchildren[i];
1919 | child = null;
1920 | var key = vchild.key;
1921 | if (null != key) {
1922 | if (keyedLen && void 0 !== keyed[key]) {
1923 | child = keyed[key];
1924 | keyed[key] = void 0;
1925 | keyedLen--;
1926 | }
1927 | } else if (!child && min < childrenLen) for (j = min; j < childrenLen; j++) if (void 0 !== children[j] && isSameNodeType(c = children[j], vchild, isHydrating)) {
1928 | child = c;
1929 | children[j] = void 0;
1930 | if (j === childrenLen - 1) childrenLen--;
1931 | if (j === min) min++;
1932 | break;
1933 | }
1934 | child = idiff(child, vchild, context, mountAll);
1935 | if (child && child !== dom) if (i >= len) dom.appendChild(child); else if (child !== originalChildren[i]) if (child === originalChildren[i + 1]) removeNode(originalChildren[i]); else dom.insertBefore(child, originalChildren[i] || null);
1936 | }
1937 | if (keyedLen) for (var i in keyed) if (void 0 !== keyed[i]) recollectNodeTree(keyed[i], !1);
1938 | while (min <= childrenLen) if (void 0 !== (child = children[childrenLen--])) recollectNodeTree(child, !1);
1939 | }
1940 | function recollectNodeTree(node, unmountOnly) {
1941 | var component = node._component;
1942 | if (component) unmountComponent(component); else {
1943 | if (null != node.__preactattr_ && node.__preactattr_.ref) node.__preactattr_.ref(null);
1944 | if (unmountOnly === !1 || null == node.__preactattr_) removeNode(node);
1945 | removeChildren(node);
1946 | }
1947 | }
1948 | function removeChildren(node) {
1949 | node = node.lastChild;
1950 | while (node) {
1951 | var next = node.previousSibling;
1952 | recollectNodeTree(node, !0);
1953 | node = next;
1954 | }
1955 | }
1956 | function diffAttributes(dom, attrs, old) {
1957 | var name;
1958 | for (name in old) if ((!attrs || null == attrs[name]) && null != old[name]) setAccessor(dom, name, old[name], old[name] = void 0, isSvgMode);
1959 | for (name in attrs) if (!('children' === name || 'innerHTML' === name || name in old && attrs[name] === ('value' === name || 'checked' === name ? dom[name] : old[name]))) setAccessor(dom, name, old[name], old[name] = attrs[name], isSvgMode);
1960 | }
1961 | function collectComponent(component) {
1962 | var name = component.constructor.name;
1963 | (components[name] || (components[name] = [])).push(component);
1964 | }
1965 | function createComponent(Ctor, props, context) {
1966 | var inst, list = components[Ctor.name];
1967 | if (Ctor.prototype && Ctor.prototype.render) {
1968 | inst = new Ctor(props, context);
1969 | Component.call(inst, props, context);
1970 | } else {
1971 | inst = new Component(props, context);
1972 | inst.constructor = Ctor;
1973 | inst.render = doRender;
1974 | }
1975 | if (list) for (var i = list.length; i--; ) if (list[i].constructor === Ctor) {
1976 | inst.__b = list[i].__b;
1977 | list.splice(i, 1);
1978 | break;
1979 | }
1980 | return inst;
1981 | }
1982 | function doRender(props, state, context) {
1983 | return this.constructor(props, context);
1984 | }
1985 | function setComponentProps(component, props, opts, context, mountAll) {
1986 | if (!component.__x) {
1987 | component.__x = !0;
1988 | if (component.__r = props.ref) delete props.ref;
1989 | if (component.__k = props.key) delete props.key;
1990 | if (!component.base || mountAll) {
1991 | if (component.componentWillMount) component.componentWillMount();
1992 | } else if (component.componentWillReceiveProps) component.componentWillReceiveProps(props, context);
1993 | if (context && context !== component.context) {
1994 | if (!component.__c) component.__c = component.context;
1995 | component.context = context;
1996 | }
1997 | if (!component.__p) component.__p = component.props;
1998 | component.props = props;
1999 | component.__x = !1;
2000 | if (0 !== opts) if (1 === opts || options.syncComponentUpdates !== !1 || !component.base) renderComponent(component, 1, mountAll); else enqueueRender(component);
2001 | if (component.__r) component.__r(component);
2002 | }
2003 | }
2004 | function renderComponent(component, opts, mountAll, isChild) {
2005 | if (!component.__x) {
2006 | var rendered, inst, cbase, props = component.props, state = component.state, context = component.context, previousProps = component.__p || props, previousState = component.__s || state, previousContext = component.__c || context, isUpdate = component.base, nextBase = component.__b, initialBase = isUpdate || nextBase, initialChildComponent = component._component, skip = !1;
2007 | if (isUpdate) {
2008 | component.props = previousProps;
2009 | component.state = previousState;
2010 | component.context = previousContext;
2011 | if (2 !== opts && component.shouldComponentUpdate && component.shouldComponentUpdate(props, state, context) === !1) skip = !0; else if (component.componentWillUpdate) component.componentWillUpdate(props, state, context);
2012 | component.props = props;
2013 | component.state = state;
2014 | component.context = context;
2015 | }
2016 | component.__p = component.__s = component.__c = component.__b = null;
2017 | component.__d = !1;
2018 | if (!skip) {
2019 | rendered = component.render(props, state, context);
2020 | if (component.getChildContext) context = extend(extend({}, context), component.getChildContext());
2021 | var toUnmount, base, childComponent = rendered && rendered.nodeName;
2022 | if ('function' == typeof childComponent) {
2023 | var childProps = getNodeProps(rendered);
2024 | inst = initialChildComponent;
2025 | if (inst && inst.constructor === childComponent && childProps.key == inst.__k) setComponentProps(inst, childProps, 1, context, !1); else {
2026 | toUnmount = inst;
2027 | component._component = inst = createComponent(childComponent, childProps, context);
2028 | inst.__b = inst.__b || nextBase;
2029 | inst.__u = component;
2030 | setComponentProps(inst, childProps, 0, context, !1);
2031 | renderComponent(inst, 1, mountAll, !0);
2032 | }
2033 | base = inst.base;
2034 | } else {
2035 | cbase = initialBase;
2036 | toUnmount = initialChildComponent;
2037 | if (toUnmount) cbase = component._component = null;
2038 | if (initialBase || 1 === opts) {
2039 | if (cbase) cbase._component = null;
2040 | base = diff(cbase, rendered, context, mountAll || !isUpdate, initialBase && initialBase.parentNode, !0);
2041 | }
2042 | }
2043 | if (initialBase && base !== initialBase && inst !== initialChildComponent) {
2044 | var baseParent = initialBase.parentNode;
2045 | if (baseParent && base !== baseParent) {
2046 | baseParent.replaceChild(base, initialBase);
2047 | if (!toUnmount) {
2048 | initialBase._component = null;
2049 | recollectNodeTree(initialBase, !1);
2050 | }
2051 | }
2052 | }
2053 | if (toUnmount) unmountComponent(toUnmount);
2054 | component.base = base;
2055 | if (base && !isChild) {
2056 | var componentRef = component, t = component;
2057 | while (t = t.__u) (componentRef = t).base = base;
2058 | base._component = componentRef;
2059 | base._componentConstructor = componentRef.constructor;
2060 | }
2061 | }
2062 | if (!isUpdate || mountAll) mounts.unshift(component); else if (!skip) {
2063 | flushMounts();
2064 | if (component.componentDidUpdate) component.componentDidUpdate(previousProps, previousState, previousContext);
2065 | if (options.afterUpdate) options.afterUpdate(component);
2066 | }
2067 | if (null != component.__h) while (component.__h.length) component.__h.pop().call(component);
2068 | if (!diffLevel && !isChild) flushMounts();
2069 | }
2070 | }
2071 | function buildComponentFromVNode(dom, vnode, context, mountAll) {
2072 | var c = dom && dom._component, originalComponent = c, oldDom = dom, isDirectOwner = c && dom._componentConstructor === vnode.nodeName, isOwner = isDirectOwner, props = getNodeProps(vnode);
2073 | while (c && !isOwner && (c = c.__u)) isOwner = c.constructor === vnode.nodeName;
2074 | if (c && isOwner && (!mountAll || c._component)) {
2075 | setComponentProps(c, props, 3, context, mountAll);
2076 | dom = c.base;
2077 | } else {
2078 | if (originalComponent && !isDirectOwner) {
2079 | unmountComponent(originalComponent);
2080 | dom = oldDom = null;
2081 | }
2082 | c = createComponent(vnode.nodeName, props, context);
2083 | if (dom && !c.__b) {
2084 | c.__b = dom;
2085 | oldDom = null;
2086 | }
2087 | setComponentProps(c, props, 1, context, mountAll);
2088 | dom = c.base;
2089 | if (oldDom && dom !== oldDom) {
2090 | oldDom._component = null;
2091 | recollectNodeTree(oldDom, !1);
2092 | }
2093 | }
2094 | return dom;
2095 | }
2096 | function unmountComponent(component) {
2097 | if (options.beforeUnmount) options.beforeUnmount(component);
2098 | var base = component.base;
2099 | component.__x = !0;
2100 | if (component.componentWillUnmount) component.componentWillUnmount();
2101 | component.base = null;
2102 | var inner = component._component;
2103 | if (inner) unmountComponent(inner); else if (base) {
2104 | if (base.__preactattr_ && base.__preactattr_.ref) base.__preactattr_.ref(null);
2105 | component.__b = base;
2106 | removeNode(base);
2107 | collectComponent(component);
2108 | removeChildren(base);
2109 | }
2110 | if (component.__r) component.__r(null);
2111 | }
2112 | function Component(props, context) {
2113 | this.__d = !0;
2114 | this.context = context;
2115 | this.props = props;
2116 | this.state = this.state || {};
2117 | }
2118 | function render(vnode, parent, merge) {
2119 | return diff(merge, vnode, {}, !1, parent, !1);
2120 | }
2121 | var options = {};
2122 | var stack = [];
2123 | var EMPTY_CHILDREN = [];
2124 | var IS_NON_DIMENSIONAL = /acit|ex(?:s|g|n|p|$)|rph|ows|mnc|ntw|ine[ch]|zoo|^ord/i;
2125 | var items = [];
2126 | var mounts = [];
2127 | var diffLevel = 0;
2128 | var isSvgMode = !1;
2129 | var hydrating = !1;
2130 | var components = {};
2131 | extend(Component.prototype, {
2132 | setState: function(state, callback) {
2133 | var s = this.state;
2134 | if (!this.__s) this.__s = extend({}, s);
2135 | extend(s, 'function' == typeof state ? state(s, this.props) : state);
2136 | if (callback) (this.__h = this.__h || []).push(callback);
2137 | enqueueRender(this);
2138 | },
2139 | forceUpdate: function(callback) {
2140 | if (callback) (this.__h = this.__h || []).push(callback);
2141 | renderComponent(this, 2);
2142 | },
2143 | render: function() {}
2144 | });
2145 | var preact = {
2146 | h: h,
2147 | createElement: h,
2148 | cloneElement: cloneElement,
2149 | Component: Component,
2150 | render: render,
2151 | rerender: rerender,
2152 | options: options
2153 | };
2154 | if (true) module.exports = preact; else self.preact = preact;
2155 | }();
2156 | //# sourceMappingURL=preact.js.map
2157 |
2158 | /***/ }),
2159 | /* 12 */
2160 | /***/ (function(module, exports, __webpack_require__) {
2161 |
2162 | /* eslint-disable */
2163 | var renderToString = dep(__webpack_require__(13));
2164 |
2165 | function dep(obj) { return obj['default'] || obj; }
2166 |
2167 | module.exports = {
2168 | renderToString: renderToString,
2169 | renderToStaticMarkup: renderToString
2170 | };
2171 |
2172 |
2173 | /***/ }),
2174 | /* 13 */
2175 | /***/ (function(module, exports, __webpack_require__) {
2176 |
2177 | (function (global, factory) {
2178 | true ? module.exports = factory() :
2179 | typeof define === 'function' && define.amd ? define(factory) :
2180 | (global.preactRenderToString = factory());
2181 | }(this, (function () {
2182 |
2183 | var NON_DIMENSION_PROPS = {
2184 | boxFlex: 1, boxFlexGroup: 1, columnCount: 1, fillOpacity: 1, flex: 1, flexGrow: 1,
2185 | flexPositive: 1, flexShrink: 1, flexNegative: 1, fontWeight: 1, lineClamp: 1, lineHeight: 1,
2186 | opacity: 1, order: 1, orphans: 1, strokeOpacity: 1, widows: 1, zIndex: 1, zoom: 1
2187 | };
2188 |
2189 | var ESC = {
2190 | '<': '<',
2191 | '>': '>',
2192 | '"': '"',
2193 | '&': '&'
2194 | };
2195 |
2196 | var objectKeys = Object.keys || function (obj) {
2197 | var keys = [];
2198 | for (var i in obj) {
2199 | if (obj.hasOwnProperty(i)) keys.push(i);
2200 | }return keys;
2201 | };
2202 |
2203 | var encodeEntities = function (s) {
2204 | return String(s).replace(/[<>"&]/g, escapeChar);
2205 | };
2206 |
2207 | var escapeChar = function (a) {
2208 | return ESC[a] || a;
2209 | };
2210 |
2211 | var falsey = function (v) {
2212 | return v == null || v === false;
2213 | };
2214 |
2215 | var memoize = function (fn) {
2216 | var mem = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
2217 | return function (v) {
2218 | return mem[v] || (mem[v] = fn(v));
2219 | };
2220 | };
2221 |
2222 | var indent = function (s, char) {
2223 | return String(s).replace(/(\n+)/g, '$1' + (char || '\t'));
2224 | };
2225 |
2226 | var isLargeString = function (s, length, ignoreLines) {
2227 | return String(s).length > (length || 40) || !ignoreLines && String(s).indexOf('\n') !== -1 || String(s).indexOf('<') !== -1;
2228 | };
2229 |
2230 | function styleObjToCss(s) {
2231 | var str = '';
2232 | for (var prop in s) {
2233 | var val = s[prop];
2234 | if (val != null) {
2235 | if (str) str += ' ';
2236 | str += jsToCss(prop);
2237 | str += ': ';
2238 | str += val;
2239 | if (typeof val === 'number' && !NON_DIMENSION_PROPS[prop]) {
2240 | str += 'px';
2241 | }
2242 | str += ';';
2243 | }
2244 | }
2245 | return str || undefined;
2246 | }
2247 |
2248 | function hashToClassName(c) {
2249 | var str = '';
2250 | for (var prop in c) {
2251 | if (c[prop]) {
2252 | if (str) str += ' ';
2253 | str += prop;
2254 | }
2255 | }
2256 | return str;
2257 | }
2258 |
2259 | var jsToCss = memoize(function (s) {
2260 | return s.replace(/([A-Z])/g, '-$1').toLowerCase();
2261 | });
2262 |
2263 | function assign(obj, props) {
2264 | for (var i in props) {
2265 | obj[i] = props[i];
2266 | }return obj;
2267 | }
2268 |
2269 | function getNodeProps(vnode) {
2270 | var defaultProps = vnode.nodeName.defaultProps,
2271 | props = assign({}, defaultProps || vnode.attributes);
2272 | if (defaultProps) assign(props, vnode.attributes);
2273 | if (vnode.children) props.children = vnode.children;
2274 | return props;
2275 | }
2276 |
2277 | var SHALLOW = { shallow: true };
2278 |
2279 | var UNNAMED = [];
2280 |
2281 | var EMPTY = {};
2282 |
2283 | var VOID_ELEMENTS = ['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', 'track', 'wbr'];
2284 |
2285 | renderToString.render = renderToString;
2286 |
2287 | var shallowRender = function (vnode, context) {
2288 | return renderToString(vnode, context, SHALLOW);
2289 | };
2290 |
2291 | function renderToString(vnode, context, opts, inner, isSvgMode) {
2292 | var _ref = vnode || EMPTY;
2293 |
2294 | var nodeName = _ref.nodeName;
2295 | var attributes = _ref.attributes;
2296 | var children = _ref.children;
2297 | var isComponent = false;
2298 | context = context || {};
2299 | opts = opts || {};
2300 |
2301 | var pretty = opts.pretty,
2302 | indentChar = typeof pretty === 'string' ? pretty : '\t';
2303 |
2304 | if (vnode == null || vnode === false) {
2305 | return '';
2306 | }
2307 |
2308 | if (!nodeName) {
2309 | return encodeEntities(vnode);
2310 | }
2311 |
2312 | if (typeof nodeName === 'function') {
2313 | isComponent = true;
2314 | if (opts.shallow && (inner || opts.renderRootComponent === false)) {
2315 | nodeName = getComponentName(nodeName);
2316 | } else {
2317 | var props = getNodeProps(vnode),
2318 | rendered = void 0;
2319 |
2320 | if (!nodeName.prototype || typeof nodeName.prototype.render !== 'function') {
2321 | rendered = nodeName(props, context);
2322 | } else {
2323 | var c = new nodeName(props, context);
2324 |
2325 | c._disable = c.__x = true;
2326 | c.props = props;
2327 | c.context = context;
2328 | if (c.componentWillMount) c.componentWillMount();
2329 | rendered = c.render(c.props, c.state, c.context);
2330 |
2331 | if (c.getChildContext) {
2332 | context = assign(assign({}, context), c.getChildContext());
2333 | }
2334 | }
2335 |
2336 | return renderToString(rendered, context, opts, opts.shallowHighOrder !== false);
2337 | }
2338 | }
2339 |
2340 | var s = '',
2341 | html = void 0;
2342 |
2343 | if (attributes) {
2344 | var attrs = objectKeys(attributes);
2345 |
2346 | if (opts && opts.sortAttributes === true) attrs.sort();
2347 |
2348 | for (var i = 0; i < attrs.length; i++) {
2349 | var name = attrs[i],
2350 | v = attributes[name];
2351 | if (name === 'children') continue;
2352 | if (!(opts && opts.allAttributes) && (name === 'key' || name === 'ref')) continue;
2353 |
2354 | if (name === 'className') {
2355 | if (attributes['class']) continue;
2356 | name = 'class';
2357 | } else if (isSvgMode && name.match(/^xlink\:?(.+)/)) {
2358 | name = name.toLowerCase().replace(/^xlink\:?(.+)/, 'xlink:$1');
2359 | }
2360 |
2361 | if (name === 'class' && v && typeof v === 'object') {
2362 | v = hashToClassName(v);
2363 | } else if (name === 'style' && v && typeof v === 'object') {
2364 | v = styleObjToCss(v);
2365 | }
2366 |
2367 | var hooked = opts.attributeHook && opts.attributeHook(name, v, context, opts, isComponent);
2368 | if (hooked || hooked === '') {
2369 | s += hooked;
2370 | continue;
2371 | }
2372 |
2373 | if (name === 'dangerouslySetInnerHTML') {
2374 | html = v && v.__html;
2375 | } else if ((v || v === 0 || v === '') && typeof v !== 'function') {
2376 | if (v === true || v === '') {
2377 | v = name;
2378 |
2379 | if (!opts || !opts.xml) {
2380 | s += ' ' + name;
2381 | continue;
2382 | }
2383 | }
2384 | s += ' ' + name + '="' + encodeEntities(v) + '"';
2385 | }
2386 | }
2387 | }
2388 |
2389 | var sub = s.replace(/^\n\s*/, ' ');
2390 | if (sub !== s && !~sub.indexOf('\n')) s = sub;else if (~s.indexOf('\n')) s += '\n';
2391 |
2392 | s = '<' + nodeName + s + '>';
2393 |
2394 | if (VOID_ELEMENTS.indexOf(nodeName) > -1) {
2395 | s = s.replace(/>$/, ' />');
2396 | }
2397 |
2398 | if (html) {
2399 | if (pretty && isLargeString(html)) {
2400 | html = '\n' + indentChar + indent(html, indentChar);
2401 | }
2402 | s += html;
2403 | } else {
2404 | var len = children && children.length,
2405 | pieces = [],
2406 | hasLarge = ~s.indexOf('\n');
2407 | for (var _i = 0; _i < len; _i++) {
2408 | var child = children[_i];
2409 | if (!falsey(child)) {
2410 | var childSvgMode = nodeName === 'svg' ? true : nodeName === 'foreignObject' ? false : isSvgMode,
2411 | ret = renderToString(child, context, opts, true, childSvgMode);
2412 | if (!hasLarge && pretty && isLargeString(ret)) hasLarge = true;
2413 | pieces.push(ret);
2414 | }
2415 | }
2416 | if (hasLarge) {
2417 | for (var _i2 = pieces.length; _i2--;) {
2418 | pieces[_i2] = '\n' + indentChar + indent(pieces[_i2], indentChar);
2419 | }
2420 | }
2421 | if (pieces.length) {
2422 | s += pieces.join('');
2423 | } else if (opts && opts.xml) {
2424 | return s.substring(0, s.length - 1) + ' />';
2425 | }
2426 | }
2427 |
2428 | if (opts.jsx || VOID_ELEMENTS.indexOf(nodeName) === -1) {
2429 | if (pretty && ~s.indexOf('\n')) s += '\n';
2430 | s += '' + nodeName + '>';
2431 | }
2432 |
2433 | return s;
2434 | }
2435 |
2436 | function getComponentName(component) {
2437 | var proto = component.prototype,
2438 | ctor = proto && proto.constructor;
2439 | return component.displayName || component.name || proto && (proto.displayName || proto.name) || getFallbackComponentName(component);
2440 | }
2441 |
2442 | function getFallbackComponentName(component) {
2443 | var str = Function.prototype.toString.call(component),
2444 | name = (str.match(/^\s*function\s+([^\( ]+)/) || EMPTY)[1];
2445 | if (!name) {
2446 | var index = -1;
2447 | for (var i = UNNAMED.length; i--;) {
2448 | if (UNNAMED[i] === component) {
2449 | index = i;
2450 | break;
2451 | }
2452 | }
2453 |
2454 | if (index < 0) {
2455 | index = UNNAMED.push(component) - 1;
2456 | }
2457 | name = 'UnnamedComponent' + index;
2458 | }
2459 | return name;
2460 | }
2461 | renderToString.shallowRender = shallowRender;
2462 |
2463 | return renderToString;
2464 |
2465 | })));
2466 | //# sourceMappingURL=index.js.map
2467 |
2468 |
2469 | /***/ })
2470 | /******/ ]);
--------------------------------------------------------------------------------