diff --git a/src/components/fields/_labelFromFieldName.js b/src/components/_labelFromFieldName.js
similarity index 100%
rename from src/components/fields/_labelFromFieldName.js
rename to src/components/_labelFromFieldName.js
diff --git a/src/components/icons/LayerIcon.jsx b/src/components/icons/LayerIcon.jsx
deleted file mode 100644
index fb5d327..0000000
--- a/src/components/icons/LayerIcon.jsx
+++ /dev/null
@@ -1,34 +0,0 @@
-import React from 'react'
-import PropTypes from 'prop-types'
-
-import LineIcon from './LineIcon.jsx'
-import FillIcon from './FillIcon.jsx'
-import SymbolIcon from './SymbolIcon.jsx'
-import BackgroundIcon from './BackgroundIcon.jsx'
-import CircleIcon from './CircleIcon.jsx'
-import MissingIcon from './MissingIcon.jsx'
-
-class LayerIcon extends React.Component {
- static propTypes = {
- type: PropTypes.string.isRequired,
- style: PropTypes.object,
- }
-
- render() {
- const iconProps = { style: this.props.style }
- switch(this.props.type) {
- case 'fill-extrusion': return
- case 'raster': return
- case 'hillshade': return
- case 'heatmap': return
- case 'fill': return
- case 'background': return
- case 'line': return
- case 'symbol': return
- case 'circle': return
- default: return
- }
- }
-}
-
-export default LayerIcon
diff --git a/src/components/util/codemirror-mgl.js b/src/util/codemirror-mgl.js
similarity index 100%
rename from src/components/util/codemirror-mgl.js
rename to src/util/codemirror-mgl.js
diff --git a/src/components/util/format.js b/src/util/format.js
similarity index 100%
rename from src/components/util/format.js
rename to src/util/format.js
diff --git a/src/components/util/spec-helper.js b/src/util/spec-helper.js
similarity index 100%
rename from src/components/util/spec-helper.js
rename to src/util/spec-helper.js
diff --git a/stories/0-Welcome.stories.js b/stories/0-Welcome.stories.js
new file mode 100644
index 0000000..98868a7
--- /dev/null
+++ b/stories/0-Welcome.stories.js
@@ -0,0 +1,26 @@
+import '../src/styles/index.scss';
+import React from 'react';
+import {Describe} from './ui';
+
+
+export default {
+ title: 'Welcome',
+};
+
+export const ToStorybook = () => {
+ return (
+
+ Maputnik component library
+
+ This is the Maputnik component library, which shows the uses of some commonly used components from the Maputnik editor. This is a stand alone place where we can better refine them and improve their API separate from their use inside the editor.
+
+
+ This should also help us better refine our CSS and make it more modular as currently we rely on the cascade quite a bit in a number of places.
+
+
+ );
+}
+
+ToStorybook.story = {
+ name: 'Intro',
+};
diff --git a/stories/Button.stories.js b/stories/Button.stories.js
new file mode 100644
index 0000000..c158d7c
--- /dev/null
+++ b/stories/Button.stories.js
@@ -0,0 +1,21 @@
+import React from 'react';
+import Button from '../src/components/Button';
+import {action} from '@storybook/addon-actions';
+import {Wrapper} from './ui';
+import {withA11y} from '@storybook/addon-a11y';
+
+
+export default {
+ title: 'Button',
+ component: Button,
+ decorators: [withA11y],
+};
+
+export const Basic = () => (
+
+
+
+);
+
diff --git a/stories/FieldArray.stories.js b/stories/FieldArray.stories.js
new file mode 100644
index 0000000..0ee6aab
--- /dev/null
+++ b/stories/FieldArray.stories.js
@@ -0,0 +1,44 @@
+import React from 'react';
+import {useActionState} from './helper';
+import FieldArray from '../src/components/FieldArray';
+import {Wrapper} from './ui';
+import {withA11y} from '@storybook/addon-a11y';
+
+export default {
+ title: 'FieldArray',
+ component: FieldArray,
+ decorators: [withA11y],
+};
+
+
+export const NumberType = () => {
+ const [value, setValue] = useActionState("onChange", [1,2,3]);
+
+ return (
+
+
+
+ );
+};
+
+export const StringType = () => {
+ const [value, setValue] = useActionState("onChange", ["a", "b", "c"]);
+
+ return (
+
+
+
+ );
+};
+
+
diff --git a/stories/FieldAutocomplete.stories.js b/stories/FieldAutocomplete.stories.js
new file mode 100644
index 0000000..b39eace
--- /dev/null
+++ b/stories/FieldAutocomplete.stories.js
@@ -0,0 +1,28 @@
+import React from 'react';
+import {useActionState} from './helper';
+import FieldAutocomplete from '../src/components/FieldAutocomplete';
+import {Wrapper} from './ui';
+import {withA11y} from '@storybook/addon-a11y';
+
+export default {
+ title: 'FieldAutocomplete',
+ component: FieldAutocomplete,
+ decorators: [withA11y],
+};
+
+
+export const Basic = () => {
+ const options = [["FOO", "foo"], ["BAR", "bar"], ["BAZ", "baz"]];
+ const [value, setValue] = useActionState("onChange", "bar");
+
+ return (
+
+
+
+ );
+};
+
diff --git a/stories/FieldCheckbox.stories.js b/stories/FieldCheckbox.stories.js
new file mode 100644
index 0000000..5e7b6f0
--- /dev/null
+++ b/stories/FieldCheckbox.stories.js
@@ -0,0 +1,39 @@
+import React from 'react';
+import {useActionState} from './helper';
+import FieldCheckbox from '../src/components/FieldCheckbox';
+import {Wrapper} from './ui';
+import {withA11y} from '@storybook/addon-a11y';
+
+export default {
+ title: 'FieldCheckbox',
+ component: FieldCheckbox,
+ decorators: [withA11y],
+};
+
+
+export const BasicUnchecked = () => {
+ const [value, setValue] = useActionState("onChange", false);
+
+ return (
+
+
+
+ );
+};
+
+export const BasicChecked = () => {
+ const [value, setValue] = useActionState("onChange", true);
+
+ return (
+
+
+
+ );
+};
+
diff --git a/stories/FieldColor.stories.js b/stories/FieldColor.stories.js
new file mode 100644
index 0000000..31a35ac
--- /dev/null
+++ b/stories/FieldColor.stories.js
@@ -0,0 +1,27 @@
+import React from 'react';
+import {useActionState} from './helper';
+import FieldColor from '../src/components/FieldColor';
+import {Wrapper} from './ui';
+import {withA11y} from '@storybook/addon-a11y';
+
+export default {
+ title: 'FieldColor',
+ component: FieldColor,
+ decorators: [withA11y],
+};
+
+
+export const Basic = () => {
+ const [color, setColor] = useActionState("onChange", "#ff0000");
+
+ return (
+
+
+
+ );
+};
+
diff --git a/stories/FieldDynamicArray.stories.js b/stories/FieldDynamicArray.stories.js
new file mode 100644
index 0000000..85555fd
--- /dev/null
+++ b/stories/FieldDynamicArray.stories.js
@@ -0,0 +1,55 @@
+import React from 'react';
+import {useActionState} from './helper';
+import FieldDynamicArray from '../src/components/FieldDynamicArray';
+import {Wrapper} from './ui';
+import {withA11y} from '@storybook/addon-a11y';
+
+export default {
+ title: 'FieldDynamicArray',
+ component: FieldDynamicArray,
+ decorators: [withA11y],
+};
+
+
+export const NumberType = () => {
+ const [value, setValue] = useActionState("onChange", [1,2,3]);
+
+ return (
+
+
+
+ );
+};
+
+export const UrlType = () => {
+ const [value, setValue] = useActionState("onChange", ["http://example.com"]);
+
+ return (
+
+
+
+ );
+};
+
+export const EnumType = () => {
+ const [value, setValue] = useActionState("onChange", ["foo"]);
+
+ return (
+
+
+
+ );
+};
diff --git a/stories/FieldEnum.stories.js b/stories/FieldEnum.stories.js
new file mode 100644
index 0000000..3d1cd91
--- /dev/null
+++ b/stories/FieldEnum.stories.js
@@ -0,0 +1,76 @@
+import React from 'react';
+import {useActionState} from './helper';
+import FieldEnum from '../src/components/FieldEnum';
+import {Wrapper} from './ui';
+import {withA11y} from '@storybook/addon-a11y';
+
+export default {
+ title: 'FieldEnum',
+ component: FieldEnum,
+ decorators: [withA11y],
+};
+
+
+export const BasicFew = () => {
+ const options = ["Foo", "Bar", "Baz"];
+ const [value, setValue] = useActionState("onChange", "Foo");
+
+ return (
+
+
+
+ );
+};
+
+export const BasicFewWithDefault = () => {
+ const options = ["Foo", "Bar", "Baz"];
+ const [value, setValue] = useActionState("onChange", null);
+
+ return (
+
+
+
+ );
+};
+
+export const BasicMany = () => {
+ const options = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"];
+ const [value, setValue] = useActionState("onChange", "a");
+
+ return (
+
+
+
+ );
+};
+
+export const BasicManyWithDefault = () => {
+ const options = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"];
+ const [value, setValue] = useActionState("onChange", "a");
+
+ return (
+
+
+
+ );
+};
+
+
diff --git a/stories/FieldFont.stories.js b/stories/FieldFont.stories.js
new file mode 100644
index 0000000..be1bdad
--- /dev/null
+++ b/stories/FieldFont.stories.js
@@ -0,0 +1,28 @@
+import React from 'react';
+import {useActionState} from './helper';
+import FieldFont from '../src/components/FieldFont';
+import {Wrapper} from './ui';
+import {withA11y} from '@storybook/addon-a11y';
+
+export default {
+ title: 'FieldFont',
+ component: FieldFont,
+ decorators: [withA11y],
+};
+
+
+export const Basic = () => {
+ const fonts = ["Comic Sans", "Helvectica", "Gotham"];
+ const [value, setValue] = useActionState("onChange", ["Comic Sans"]);
+
+ return (
+
+
+
+ );
+};
+
diff --git a/stories/FieldMultiInput.stories.js b/stories/FieldMultiInput.stories.js
new file mode 100644
index 0000000..443bb14
--- /dev/null
+++ b/stories/FieldMultiInput.stories.js
@@ -0,0 +1,28 @@
+import React from 'react';
+import {useActionState} from './helper';
+import FieldMultiInput from '../src/components/FieldMultiInput';
+import {Wrapper} from './ui';
+import {withA11y} from '@storybook/addon-a11y';
+
+export default {
+ title: 'FieldMultiInput',
+ component: FieldMultiInput,
+ decorators: [withA11y],
+};
+
+
+export const Basic = () => {
+ const options = [["FOO", "foo"], ["BAR", "bar"], ["BAZ", "baz"]];
+ const [value, setValue] = useActionState("onChange", "FOO");
+
+ return (
+
+
+
+ );
+};
+
diff --git a/stories/FieldNumber.stories.js b/stories/FieldNumber.stories.js
new file mode 100644
index 0000000..ec6f721
--- /dev/null
+++ b/stories/FieldNumber.stories.js
@@ -0,0 +1,43 @@
+import React from 'react';
+import {useActionState} from './helper';
+import FieldNumber from '../src/components/FieldNumber';
+import {Wrapper} from './ui';
+import {withA11y} from '@storybook/addon-a11y';
+
+export default {
+ title: 'FieldNumber',
+ component: FieldNumber,
+ decorators: [withA11y],
+};
+
+export const Basic = () => {
+ const [value, setValue] = useActionState("onChange", 1);
+
+ return (
+
+
+
+ );
+};
+
+export const Range = () => {
+ const [value, setValue] = useActionState("onChange", 1);
+
+ return (
+
+
+
+ );
+};
diff --git a/stories/FieldSelect.stories.js b/stories/FieldSelect.stories.js
new file mode 100644
index 0000000..0b78158
--- /dev/null
+++ b/stories/FieldSelect.stories.js
@@ -0,0 +1,29 @@
+import React from 'react';
+import {useActionState} from './helper';
+import FieldSelect from '../src/components/FieldSelect';
+import {Wrapper} from './ui';
+import {withA11y} from '@storybook/addon-a11y';
+
+export default {
+ title: 'FieldSelect',
+ component: FieldSelect,
+ decorators: [withA11y],
+};
+
+
+export const Basic = () => {
+ const options = [["FOO", "Foo"], ["BAR", "Bar"], ["BAZ", "Baz"]];
+ const [value, setValue] = useActionState("onChange", "FOO");
+
+ return (
+
+
+
+ );
+};
+
+
diff --git a/stories/FieldString.stories.js b/stories/FieldString.stories.js
new file mode 100644
index 0000000..2889b45
--- /dev/null
+++ b/stories/FieldString.stories.js
@@ -0,0 +1,69 @@
+import React from 'react';
+import {useActionState} from './helper';
+import FieldString from '../src/components/FieldString';
+import {Wrapper} from './ui';
+import {withA11y} from '@storybook/addon-a11y';
+
+export default {
+ title: 'FieldString',
+ component: FieldString,
+ decorators: [withA11y],
+};
+
+
+export const Basic = () => {
+ const [value, setValue] = useActionState("onChange", "Hello world");
+
+ return (
+
+
+
+ );
+};
+
+export const WithDefault = () => {
+ const [value, setValue] = useActionState("onChange", null);
+
+ return (
+
+
+
+ );
+};
+
+export const Multiline = () => {
+ const [value, setValue] = useActionState("onChange", "Hello\nworld");
+
+ return (
+
+
+
+ );
+};
+
+export const MultilineWithDefault = () => {
+ const [value, setValue] = useActionState("onChange", null);
+
+ return (
+
+
+
+ );
+};
+
diff --git a/stories/FieldSymbol.stories.js b/stories/FieldSymbol.stories.js
new file mode 100644
index 0000000..300eabf
--- /dev/null
+++ b/stories/FieldSymbol.stories.js
@@ -0,0 +1,29 @@
+import React from 'react';
+import {useActionState} from './helper';
+import FieldSymbol from '../src/components/FieldSymbol';
+import {Wrapper} from './ui';
+import {withA11y} from '@storybook/addon-a11y';
+
+export default {
+ title: 'FieldSymbol',
+ component: FieldSymbol,
+ decorators: [withA11y],
+};
+
+
+export const Basic = () => {
+ const icons = ["Bicycle", "Ski", "Ramp"];
+ const [value, setValue] = useActionState("onChange", "Ski");
+
+ return (
+
+
+
+ );
+};
+
+
diff --git a/stories/FieldUrl.stories.js b/stories/FieldUrl.stories.js
new file mode 100644
index 0000000..b30d7bc
--- /dev/null
+++ b/stories/FieldUrl.stories.js
@@ -0,0 +1,42 @@
+import React from 'react';
+import {useActionState} from './helper';
+import FieldUrl from '../src/components/FieldUrl';
+import {Wrapper} from './ui';
+import {withA11y} from '@storybook/addon-a11y';
+
+export default {
+ title: 'FieldUrl',
+ component: FieldUrl,
+ decorators: [withA11y],
+};
+
+
+export const Valid = () => {
+ const [value, setValue] = useActionState("onChange", "http://example.com");
+
+ return (
+
+
+
+ );
+};
+
+export const Invalid = () => {
+ const [value, setValue] = useActionState("onChange", "foo");
+
+ return (
+
+
+
+ );
+};
+
+
diff --git a/stories/helper.js b/stories/helper.js
new file mode 100644
index 0000000..728b931
--- /dev/null
+++ b/stories/helper.js
@@ -0,0 +1,12 @@
+import React, {useState} from 'react';
+import {action} from '@storybook/addon-actions';
+
+export function useActionState (name, initialVal) {
+ const [val, fn] = useState(initialVal);
+ const actionFn = action(name);
+ function retFn(val) {
+ actionFn(val);
+ return fn(val);
+ }
+ return [val, retFn];
+}
diff --git a/stories/ui.js b/stories/ui.js
new file mode 100644
index 0000000..41cfb7f
--- /dev/null
+++ b/stories/ui.js
@@ -0,0 +1,19 @@
+import React from 'react';
+
+
+export function Describe ({children}) {
+ return (
+
+ {children}
+
+ )
+}
+
+export function Wrapper ({children}) {
+ return (
+
+ {children}
+
+ );
+};
+