@eeacms/volto-eea-map 4.0.0 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/CHANGELOG.md +36 -1
  2. package/package.json +6 -3
  3. package/src/Arcgis/Editor/Editor.jsx +130 -0
  4. package/src/Arcgis/Editor/EditorContext.jsx +2 -0
  5. package/src/Arcgis/Editor/Fold/Fold.jsx +56 -0
  6. package/src/Arcgis/Editor/Panels/Panel.jsx +8 -0
  7. package/src/Arcgis/Editor/Panels/SettingsGeneralPanel.jsx +217 -0
  8. package/src/Arcgis/Editor/Panels/SettingsLayersPanel.jsx +216 -0
  9. package/src/Arcgis/Editor/Panels/StructureBaseLayerPanel.jsx +60 -0
  10. package/src/Arcgis/Editor/Panels/StructureLayersPanel.jsx +394 -0
  11. package/src/Arcgis/Editor/Panels/StructureWidgetsPanel.jsx +181 -0
  12. package/src/Arcgis/Editor/Panels/index.js +6 -0
  13. package/src/Arcgis/Editor/SidebarGroup.jsx +62 -0
  14. package/src/Arcgis/Layer/Layer.jsx +247 -0
  15. package/src/Arcgis/Map/Map.jsx +287 -0
  16. package/src/Arcgis/Map/MapBuilder.jsx +111 -0
  17. package/src/Arcgis/Map/MapContext.jsx +3 -0
  18. package/src/Arcgis/Widget/Widget.jsx +170 -0
  19. package/src/Arcgis/helpers.js +140 -0
  20. package/src/Blocks/EmbedEEAMap/Edit.jsx +40 -0
  21. package/src/Blocks/EmbedEEAMap/View.jsx +122 -0
  22. package/src/Blocks/EmbedEEAMap/helpers.js +12 -0
  23. package/src/Blocks/EmbedEEAMap/schema.js +126 -0
  24. package/src/{components → Toolbar}/Share.jsx +1 -1
  25. package/src/{components/ExtraViews.jsx → Toolbar/Toolbar.jsx} +14 -16
  26. package/src/{components/visualization → Views}/VisualizationView.jsx +8 -9
  27. package/src/Widgets/ArcgisColorPickerWidget.jsx +95 -0
  28. package/src/Widgets/ArcgisRendererWidget/ArcgisRendererWidget.jsx +106 -0
  29. package/src/Widgets/ArcgisRendererWidget/RendererEditor/ClassBreaks.jsx +8 -0
  30. package/src/Widgets/ArcgisRendererWidget/RendererEditor/Dictionary.jsx +8 -0
  31. package/src/Widgets/ArcgisRendererWidget/RendererEditor/DotDensity.jsx +8 -0
  32. package/src/Widgets/ArcgisRendererWidget/RendererEditor/Heatmap.jsx +8 -0
  33. package/src/Widgets/ArcgisRendererWidget/RendererEditor/PieChart.jsx +8 -0
  34. package/src/Widgets/ArcgisRendererWidget/RendererEditor/Simple.jsx +109 -0
  35. package/src/Widgets/ArcgisRendererWidget/RendererEditor/UniqueValue.jsx +8 -0
  36. package/src/Widgets/ArcgisRendererWidget/RendererEditor/_Editor.jsx +29 -0
  37. package/src/Widgets/ArcgisRendererWidget/RendererEditor/_EditorModal.jsx +88 -0
  38. package/src/Widgets/ArcgisRendererWidget/RendererEditor/_defaults.js +30 -0
  39. package/src/Widgets/ArcgisSliderWidget.jsx +79 -0
  40. package/src/Widgets/ArcgisViewpointWidget.jsx +112 -0
  41. package/src/{components/visualization → Widgets}/VisualizationViewWidget.jsx +9 -10
  42. package/src/Widgets/VisualizationWidget.jsx +200 -0
  43. package/src/arcgis.js +48 -0
  44. package/src/constants.js +225 -7
  45. package/src/hocs/withArcgis.jsx +27 -0
  46. package/src/hooks/useChangedProps.jsx +24 -0
  47. package/src/hooks/useClass.jsx +17 -0
  48. package/src/hooks/useCopyToClipboard.jsx +25 -0
  49. package/src/index.js +16 -16
  50. package/src/jsoneditor.js +72 -0
  51. package/src/styles/editor.less +446 -0
  52. package/src/styles/map.less +3 -0
  53. package/src/components/Blocks/EmbedEEAMap/Edit.jsx +0 -161
  54. package/src/components/Blocks/EmbedEEAMap/Schema.js +0 -161
  55. package/src/components/Blocks/EmbedEEAMap/View.jsx +0 -79
  56. package/src/components/Blocks/EmbedEEAMap/helpers.js +0 -45
  57. package/src/components/LegendView.jsx +0 -150
  58. package/src/components/Webmap.jsx +0 -365
  59. package/src/components/index.js +0 -6
  60. package/src/components/visualization/VisualizationEditorWidget.jsx +0 -122
  61. package/src/components/visualization/panelsSchema.js +0 -229
  62. package/src/components/widgets/DataQueryWidget.jsx +0 -51
  63. package/src/components/widgets/LayerSelectWidget.jsx +0 -456
  64. package/src/components/widgets/LayersPanelWidget.jsx +0 -59
  65. package/src/components/widgets/SimpleColorPickerWidget.jsx +0 -121
  66. package/src/hocs/index.js +0 -3
  67. package/src/hocs/withDeviceSize.jsx +0 -45
  68. package/src/less/global.less +0 -253
  69. package/src/less/variables.less +0 -5
  70. package/src/utils.js +0 -151
  71. /package/src/{components → Toolbar}/FigureNote.jsx +0 -0
  72. /package/src/{components → Toolbar}/MoreInfoLink.jsx +0 -0
  73. /package/src/{components → Toolbar}/Sources.jsx +0 -0
@@ -0,0 +1,109 @@
1
+ import { toNumber } from 'lodash';
2
+
3
+ import { InlineForm } from '@plone/volto/components';
4
+
5
+ import { simpleSymbols as simpleSymbolsOptions } from '@eeacms/volto-eea-map/constants';
6
+
7
+ import { simpleSymbols } from '../RendererEditor/_defaults';
8
+
9
+ export default function Simple(props) {
10
+ const { $map, value, id, onChange } = props;
11
+
12
+ const symbol = value?.symbol || {};
13
+
14
+ return (
15
+ <InlineForm
16
+ schema={{
17
+ title: 'Symbol',
18
+ fieldsets: [
19
+ {
20
+ id: 'default',
21
+ title: 'Default',
22
+ fields: [],
23
+ },
24
+ {
25
+ id: 'symbol',
26
+ title: 'Symbol',
27
+ fields: [
28
+ 'type',
29
+ ...(['simple-fill', 'simple-marker', 'simple-line'].includes(
30
+ symbol.type,
31
+ )
32
+ ? ['color']
33
+ : []),
34
+ ...(['simple-fill', 'simple-marker'].includes(symbol.type)
35
+ ? ['outline_color', 'outline_width']
36
+ : []),
37
+ ...(symbol.type === 'simple-marker' ? ['size'] : []),
38
+ ...(symbol.type === 'simple-line' ? ['width'] : []),
39
+ ],
40
+ },
41
+ ],
42
+ properties: {
43
+ type: {
44
+ title: 'Type',
45
+ choices: simpleSymbolsOptions,
46
+ },
47
+ color: {
48
+ title: 'Color',
49
+ widget: 'arcgis_color_picker',
50
+ $map,
51
+ },
52
+ outline_color: {
53
+ title: 'Outline color',
54
+ widget: 'arcgis_color_picker',
55
+ $map,
56
+ },
57
+ outline_width: {
58
+ title: 'Outline width',
59
+ type: 'number',
60
+ minimum: 0,
61
+ step: 0.1,
62
+ },
63
+ size: {
64
+ title: 'Size',
65
+ type: 'number',
66
+ minimum: 0,
67
+ step: 0.1,
68
+ },
69
+ width: {
70
+ title: 'Width',
71
+ type: 'number',
72
+ minimum: 0,
73
+ step: 0.1,
74
+ },
75
+ },
76
+ required: [],
77
+ }}
78
+ formData={{
79
+ ...symbol,
80
+ outline_color: symbol.outline?.color,
81
+ outline_width: symbol.outline?.width,
82
+ }}
83
+ onChangeField={(symbolId, fieldValue) => {
84
+ let $fieldValue = fieldValue;
85
+
86
+ if (['outline_width', 'size', 'width'].includes(symbolId)) {
87
+ $fieldValue = Math.max(toNumber(fieldValue) || 0, 0);
88
+ }
89
+
90
+ onChange(id, {
91
+ ...(value || {}),
92
+ ...(symbolId === 'type' ? { autocast: true } : {}),
93
+ symbol: {
94
+ ...(symbolId !== 'type' ? symbol : {}),
95
+ ...(symbolId === 'type' ? simpleSymbols[fieldValue] || {} : {}),
96
+ ...(['outline_color', 'outline_width'].includes(symbolId)
97
+ ? {
98
+ outline: {
99
+ ...(symbol.outline || {}),
100
+ [symbolId.replace('outline_', '')]: $fieldValue,
101
+ },
102
+ }
103
+ : { [symbolId]: $fieldValue }),
104
+ },
105
+ });
106
+ }}
107
+ />
108
+ );
109
+ }
@@ -0,0 +1,8 @@
1
+ export default function UniqueValue() {
2
+ return (
3
+ <p>
4
+ Renderer visual editor under work. Please edit it through json editor by
5
+ pressing the "Renderer" button
6
+ </p>
7
+ );
8
+ }
@@ -0,0 +1,29 @@
1
+ import { useMemo } from 'react';
2
+
3
+ import Simple from './Simple';
4
+ import UniqueValue from './UniqueValue';
5
+ import Heatmap from './Heatmap';
6
+ import ClassBreaks from './ClassBreaks';
7
+ import Dictionary from './Dictionary';
8
+ import DotDensity from './DotDensity';
9
+ import PieChart from './PieChart';
10
+
11
+ const types = {
12
+ simle: Simple,
13
+ 'unique-value': UniqueValue,
14
+ heatmap: Heatmap,
15
+ 'class-breaks': ClassBreaks,
16
+ dictionary: Dictionary,
17
+ 'dot-density': DotDensity,
18
+ 'pie-chart': PieChart,
19
+ };
20
+
21
+ function getRendererByType(type) {
22
+ return types[type] || Simple;
23
+ }
24
+
25
+ export default function Editor(props) {
26
+ const Renderer = useMemo(() => getRendererByType(props.type), [props.type]);
27
+
28
+ return <Renderer {...props} />;
29
+ }
@@ -0,0 +1,88 @@
1
+ import { useEffect, useRef } from 'react';
2
+ import { Modal, Button } from 'semantic-ui-react';
3
+ import { toast } from 'react-toastify';
4
+ import { Toast } from '@plone/volto/components';
5
+ import {
6
+ initEditor,
7
+ destroyEditor,
8
+ validateEditor,
9
+ onPasteEditor,
10
+ } from '@eeacms/volto-eea-map/jsoneditor';
11
+
12
+ export default function EditorModal(props) {
13
+ const { value, onClose, onChange } = props;
14
+ const editor = useRef();
15
+ const initailValue = useRef(props.value);
16
+
17
+ async function getValue() {
18
+ const valid = await validateEditor(editor);
19
+ if (!valid) {
20
+ throw new Error('Invalid JSON');
21
+ }
22
+ try {
23
+ return editor.current.get();
24
+ } catch {
25
+ throw new Error('Invalid JSON');
26
+ }
27
+ }
28
+
29
+ useEffect(() => {
30
+ initEditor({
31
+ el: 'jsoneditor-plotlyjson',
32
+ editor,
33
+ options: {
34
+ schema: undefined,
35
+ },
36
+ dflt: initailValue.current,
37
+ });
38
+
39
+ const editorCurr = editor.current;
40
+
41
+ return () => {
42
+ destroyEditor(editorCurr);
43
+ };
44
+ }, []);
45
+
46
+ return (
47
+ <Modal size="fullscreen" open={true} className="plotly-json-modal">
48
+ <Modal.Content scrolling>
49
+ <div
50
+ id="jsoneditor-plotlyjson"
51
+ style={{ width: '100%', height: '100%' }}
52
+ onPaste={(e) => {
53
+ onPasteEditor(editor);
54
+ }}
55
+ />
56
+ </Modal.Content>
57
+ <Modal.Actions>
58
+ <Button
59
+ onClick={() => {
60
+ onChange(initailValue.current);
61
+ onClose();
62
+ }}
63
+ >
64
+ Close
65
+ </Button>
66
+ <Button
67
+ primary
68
+ onClick={async () => {
69
+ try {
70
+ const newValue = {
71
+ ...value,
72
+ ...(await getValue()),
73
+ };
74
+ onChange(newValue);
75
+ onClose();
76
+ } catch (error) {
77
+ toast.error(
78
+ <Toast error title={'JSON error'} content={error.message} />,
79
+ );
80
+ }
81
+ }}
82
+ >
83
+ Apply
84
+ </Button>
85
+ </Modal.Actions>
86
+ </Modal>
87
+ );
88
+ }
@@ -0,0 +1,30 @@
1
+ export const simpleFillSymbol = {
2
+ type: 'simple-fill',
3
+ color: [17, 157, 255, 0.5],
4
+ outline: {
5
+ color: [17, 157, 255, 0.6],
6
+ width: 0.5,
7
+ },
8
+ };
9
+
10
+ export const simpleMarkerSymbol = {
11
+ type: 'simple-marker',
12
+ size: 8,
13
+ color: [17, 157, 255, 0.2],
14
+ outline: {
15
+ color: [17, 157, 255, 0.8],
16
+ width: 0.5,
17
+ },
18
+ };
19
+
20
+ export const simpleLineSymbol = {
21
+ type: 'simple-line',
22
+ color: [17, 157, 255, 0.5],
23
+ width: 1,
24
+ };
25
+
26
+ export const simpleSymbols = {
27
+ 'simple-fill': simpleFillSymbol,
28
+ 'simple-line': simpleLineSymbol,
29
+ 'simple-marker': simpleMarkerSymbol,
30
+ };
@@ -0,0 +1,79 @@
1
+ /**
2
+ * ArcgisSliderWidget component.
3
+ * @module components/manage/Widgets/ArcgisSliderWidget
4
+ */
5
+
6
+ import React, { Component } from 'react';
7
+
8
+ import { FormFieldWrapper } from '@plone/volto/components';
9
+
10
+ /**
11
+ * The simple slider widget.
12
+ *
13
+ * It is the default fallback widget, so if no other widget is found based on
14
+ * passed field properties, it will be used.
15
+ */
16
+ class ArcgisSliderWidget extends Component {
17
+ /**
18
+ * Component did mount lifecycle method
19
+ * @method componentDidMount
20
+ * @returns {undefined}
21
+ */
22
+ componentDidMount() {
23
+ if (this.props.focus) {
24
+ this.node.focus();
25
+ }
26
+ }
27
+
28
+ /**
29
+ * Render method.
30
+ * @method render
31
+ * @returns {string} Markup for the component.
32
+ */
33
+ render() {
34
+ const { id, value, onChange, min = 0, max = 1, step = 0.1 } = this.props;
35
+
36
+ return (
37
+ <FormFieldWrapper {...this.props} className="text">
38
+ <div style={{ display: 'flex', flexFlow: 'column', marginTop: '1rem' }}>
39
+ <input
40
+ className="map-number-input"
41
+ type="number"
42
+ min={min}
43
+ max={max}
44
+ step={step}
45
+ value={value}
46
+ onChange={({ target }) => {
47
+ if (target.value < min) {
48
+ target.value = min;
49
+ }
50
+ if (target.value > max) {
51
+ target.value = max;
52
+ }
53
+ onChange(id, target.value === '' ? undefined : target.value);
54
+ }}
55
+ />
56
+ <input
57
+ className="map-range-input"
58
+ type="range"
59
+ min={min}
60
+ max={max}
61
+ step={step}
62
+ value={value}
63
+ onChange={({ target }) => {
64
+ if (target.value < min) {
65
+ target.value = min;
66
+ }
67
+ if (target.value > max) {
68
+ target.value = max;
69
+ }
70
+ onChange(id, target.value === '' ? undefined : target.value);
71
+ }}
72
+ />
73
+ </div>
74
+ </FormFieldWrapper>
75
+ );
76
+ }
77
+ }
78
+
79
+ export default ArcgisSliderWidget;
@@ -0,0 +1,112 @@
1
+ import { useEffect, useState } from 'react';
2
+ import { toNumber } from 'lodash';
3
+ import { FormFieldWrapper, InlineForm } from '@plone/volto/components';
4
+
5
+ export default function ArcgisViewpointWidget(props) {
6
+ const [watchViewpoint, setWatchViewpoint] = useState(false);
7
+ const { $map, id, value, onChange } = props;
8
+
9
+ useEffect(() => {
10
+ if (!$map.current?.isReady) return;
11
+ const homeWidget = $map.current.view.ui.find('Home');
12
+ if (!homeWidget) return;
13
+ homeWidget.viewpoint = new $map.current.modules.AgViewpoint({
14
+ center: [value.longitude, value.latitude],
15
+ zoom: value.zoom,
16
+ });
17
+ }, [$map, value]);
18
+
19
+ useEffect(() => {
20
+ if (watchViewpoint && $map.current?.isReady) {
21
+ const reactiveUtils = $map.current.modules.agReactiveUtils;
22
+
23
+ reactiveUtils.when(
24
+ () => $map.current.view.stationary,
25
+ (stationary) => {
26
+ if (stationary) {
27
+ const { longitude, latitude } = $map.current.view.center;
28
+ const zoom = $map.current.view.zoom;
29
+ onChange(id, {
30
+ ...value,
31
+ longitude,
32
+ latitude,
33
+ zoom,
34
+ });
35
+ }
36
+ setWatchViewpoint(false);
37
+ },
38
+ {
39
+ once: true,
40
+ },
41
+ );
42
+ }
43
+ }, [$map, watchViewpoint, id, value, onChange]);
44
+
45
+ return (
46
+ <>
47
+ <FormFieldWrapper {...props}>
48
+ <div style={{ display: 'flex', alignItems: 'center', width: '100%' }}>
49
+ <button
50
+ className="btn-primary"
51
+ style={{
52
+ fontSize: 'var(--font-size-small)',
53
+ width: '100%',
54
+ display: 'inline-block',
55
+ textAlign: 'center',
56
+ }}
57
+ onClick={() => {
58
+ setWatchViewpoint(true);
59
+ }}
60
+ >
61
+ {watchViewpoint ? 'Waiting...' : 'Drag on map'}
62
+ </button>
63
+ </div>
64
+ </FormFieldWrapper>
65
+ <div className="arcgis-viewpoint-editor">
66
+ <InlineForm
67
+ schema={{
68
+ title: 'Initial viewpoint',
69
+ fieldsets: [
70
+ {
71
+ id: 'default',
72
+ title: 'Default',
73
+ fields: ['longitude', 'latitude', 'zoom'],
74
+ },
75
+ ],
76
+ properties: {
77
+ longitude: {
78
+ title: 'Longitude',
79
+ type: 'number',
80
+ minimum: 0,
81
+ },
82
+ latitude: {
83
+ title: 'Latitude',
84
+ type: 'number',
85
+ minimum: 0,
86
+ },
87
+ zoom: {
88
+ title: 'Zoom',
89
+ type: 'number',
90
+ minimum: 0,
91
+ },
92
+ },
93
+ required: [],
94
+ }}
95
+ formData={value}
96
+ onChangeField={(fieldId, fieldValue) => {
97
+ let $fieldValue = fieldValue;
98
+
99
+ if (['longitude', 'latitude', 'zoom'].includes(fieldId)) {
100
+ $fieldValue = Math.max(toNumber($fieldValue) || 0, 0);
101
+ }
102
+
103
+ onChange(id, {
104
+ ...value,
105
+ [fieldId]: $fieldValue,
106
+ });
107
+ }}
108
+ />
109
+ </div>
110
+ </>
111
+ );
112
+ }
@@ -1,25 +1,24 @@
1
1
  import { connect } from 'react-redux';
2
2
  import { pickMetadata } from '@eeacms/volto-embed/helpers';
3
- import Webmap from '../Webmap';
4
- import ExtraViews from '../ExtraViews';
3
+ import MapBuilder from '@eeacms/volto-eea-map/Arcgis/Map/MapBuilder';
4
+ import Toolbar from '../Toolbar/Toolbar';
5
5
 
6
6
  function VisualizationViewWidget(props) {
7
- const { value: map_visualization_data = {} } = props;
7
+ const { value: mapData = {}, content } = props;
8
8
 
9
9
  return (
10
10
  <>
11
- <Webmap data={map_visualization_data} />
12
- <ExtraViews
11
+ <MapBuilder data={mapData} />
12
+ <Toolbar
13
+ style={{ marginTop: '1rem' }}
13
14
  data={{
14
- show_viewer: true,
15
- show_legend: true,
16
15
  show_note: false,
17
16
  show_sources: false,
18
17
  show_more_info: false,
19
18
  show_share: true,
20
- map_visualization_data: {
21
- ...map_visualization_data,
22
- ...pickMetadata(props.content),
19
+ mapData: {
20
+ ...mapData,
21
+ ...pickMetadata(content),
23
22
  },
24
23
  }}
25
24
  />
@@ -0,0 +1,200 @@
1
+ import React, { useState, useRef, useEffect } from 'react';
2
+ import { Modal, Button, Grid } from 'semantic-ui-react';
3
+ import { toast } from 'react-toastify';
4
+
5
+ import { FormFieldWrapper, Icon, Toast } from '@plone/volto/components';
6
+
7
+ import MapBuilder from '@eeacms/volto-eea-map/Arcgis/Map/MapBuilder';
8
+ import {
9
+ initEditor,
10
+ destroyEditor,
11
+ validateEditor,
12
+ onPasteEditor,
13
+ } from '@eeacms/volto-eea-map/jsoneditor';
14
+
15
+ import editSVG from '@plone/volto/icons/editing.svg';
16
+
17
+ import '@eeacms/volto-eea-map/styles/editor.less';
18
+ import MapEditor from '../Arcgis/Editor/Editor';
19
+
20
+ function JsonEditorModal(props) {
21
+ const { value, onClose, onChange } = props;
22
+ const editor = useRef();
23
+ const initailValue = useRef(props.value);
24
+
25
+ async function getValue() {
26
+ const valid = await validateEditor(editor);
27
+ if (!valid) {
28
+ throw new Error('Invalid JSON');
29
+ }
30
+ try {
31
+ return editor.current.get();
32
+ } catch {
33
+ throw new Error('Invalid JSON');
34
+ }
35
+ }
36
+
37
+ useEffect(() => {
38
+ initEditor({
39
+ el: 'jsoneditor-plotlyjson',
40
+ editor,
41
+ options: {
42
+ schema: undefined,
43
+ },
44
+ dflt: initailValue.current,
45
+ });
46
+
47
+ const editorCurr = editor.current;
48
+
49
+ return () => {
50
+ destroyEditor(editorCurr);
51
+ };
52
+ }, []);
53
+
54
+ return (
55
+ <Modal size="fullscreen" open={true} className="plotly-json-modal">
56
+ <Modal.Content scrolling>
57
+ <div
58
+ id="jsoneditor-plotlyjson"
59
+ style={{ width: '100%', height: '100%' }}
60
+ onPaste={(e) => {
61
+ onPasteEditor(editor);
62
+ }}
63
+ />
64
+ </Modal.Content>
65
+ <Modal.Actions>
66
+ <Button
67
+ onClick={() => {
68
+ onChange(initailValue.current);
69
+ onClose();
70
+ }}
71
+ >
72
+ Close
73
+ </Button>
74
+ <Button
75
+ primary
76
+ onClick={async () => {
77
+ try {
78
+ const newValue = {
79
+ ...value,
80
+ ...(await getValue()),
81
+ };
82
+ onChange(newValue);
83
+ onClose();
84
+ } catch (error) {
85
+ toast.error(
86
+ <Toast error title={'JSON error'} content={error.message} />,
87
+ );
88
+ }
89
+ }}
90
+ >
91
+ Apply
92
+ </Button>
93
+ </Modal.Actions>
94
+ </Modal>
95
+ );
96
+ }
97
+
98
+ function MapEditorModal(props) {
99
+ const [value, setValue] = useState(props.value);
100
+ const [open, setOpen] = useState(false);
101
+
102
+ const properties = props.formData;
103
+
104
+ return (
105
+ <>
106
+ <Modal open={true} size="fullscreen" className="chart-editor-modal">
107
+ <Modal.Content scrolling>
108
+ <MapEditor
109
+ value={value}
110
+ properties={properties}
111
+ onChangeValue={(value) => {
112
+ setValue(value);
113
+ }}
114
+ />
115
+ </Modal.Content>
116
+ <Modal.Actions>
117
+ <Grid>
118
+ <Grid.Row>
119
+ <Grid.Column
120
+ verticalAlign="middle"
121
+ style={{
122
+ display: 'inline-flex',
123
+ flexFlow: 'row',
124
+ justifyContent: 'space-between',
125
+ }}
126
+ >
127
+ <Button
128
+ secondary
129
+ className="json-btn"
130
+ onClick={() => setOpen(true)}
131
+ >
132
+ <Icon name={editSVG} size="20px" />
133
+ JSON
134
+ </Button>
135
+ <div style={{ display: 'flex' }}>
136
+ <Button floated="right" onClick={props.onClose}>
137
+ Close
138
+ </Button>
139
+ <Button
140
+ primary
141
+ floated="right"
142
+ onClick={() => {
143
+ props.onChange(props.id, value);
144
+ props.onClose();
145
+ }}
146
+ >
147
+ Apply
148
+ </Button>
149
+ </div>
150
+ </Grid.Column>
151
+ </Grid.Row>
152
+ </Grid>
153
+ </Modal.Actions>
154
+ </Modal>
155
+ {open && (
156
+ <JsonEditorModal
157
+ value={value}
158
+ onChange={setValue}
159
+ onClose={() => setOpen(false)}
160
+ />
161
+ )}
162
+ </>
163
+ );
164
+ }
165
+
166
+ const VisualizationWidget = (props) => {
167
+ const { id, title, description, value } = props;
168
+ const [showMapEditor, setShowMapEditor] = useState(false);
169
+
170
+ if (__SERVER__) return '';
171
+
172
+ return (
173
+ <FormFieldWrapper {...props} columns={1}>
174
+ <div className="wrapper">
175
+ <label htmlFor={`field-${id}`}>{title}</label>
176
+ <Button
177
+ floated="right"
178
+ onClick={(e) => {
179
+ e.preventDefault();
180
+ e.stopPropagation();
181
+ setShowMapEditor(true);
182
+ }}
183
+ >
184
+ Open Map Editor
185
+ </Button>
186
+ </div>
187
+ {description && <p className="help">{description}</p>}
188
+ <MapBuilder data={value} />
189
+ {showMapEditor && (
190
+ <MapEditorModal
191
+ {...props}
192
+ value={value || {}}
193
+ onClose={() => setShowMapEditor(false)}
194
+ />
195
+ )}
196
+ </FormFieldWrapper>
197
+ );
198
+ };
199
+
200
+ export default VisualizationWidget;