react-spatial 2.0.0-beta.0 → 2.0.0-beta.2

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 (124) hide show
  1. package/README.md +5 -10
  2. package/components/BaseLayerSwitcher/BaseLayerSwitcher.js +188 -107
  3. package/components/BaseLayerSwitcher/BaseLayerSwitcher.js.map +2 -2
  4. package/components/BaseLayerSwitcher/BaseLayerSwitcher.scss +6 -5
  5. package/components/BaseLayerSwitcher/index.js.map +2 -2
  6. package/components/BasicMap/BasicMap.js +116 -98
  7. package/components/BasicMap/BasicMap.js.map +2 -2
  8. package/components/BasicMap/index.js.map +2 -2
  9. package/components/CanvasSaveButton/CanvasSaveButton.js +448 -316
  10. package/components/CanvasSaveButton/CanvasSaveButton.js.map +2 -2
  11. package/components/CanvasSaveButton/CanvasSaveButton.md.scss +1 -1
  12. package/components/CanvasSaveButton/index.js.map +2 -2
  13. package/components/Copyright/Copyright.js +43 -35
  14. package/components/Copyright/Copyright.js.map +2 -2
  15. package/components/Copyright/index.js.map +2 -2
  16. package/components/FeatureExportButton/FeatureExportButton.js +35 -17
  17. package/components/FeatureExportButton/FeatureExportButton.js.map +2 -2
  18. package/components/FeatureExportButton/index.js.map +2 -2
  19. package/components/FitExtent/FitExtent.js +36 -18
  20. package/components/FitExtent/FitExtent.js.map +2 -2
  21. package/components/FitExtent/index.js.map +2 -2
  22. package/components/Geolocation/Geolocation.js +131 -92
  23. package/components/Geolocation/Geolocation.js.map +2 -2
  24. package/components/Geolocation/Geolocation.scss +7 -5
  25. package/components/Geolocation/index.js.map +2 -2
  26. package/components/LayerTree/LayerTree.js +361 -169
  27. package/components/LayerTree/LayerTree.js.map +2 -2
  28. package/components/LayerTree/LayerTree.scss +4 -6
  29. package/components/LayerTree/index.js.map +2 -2
  30. package/components/MousePosition/MousePosition.js +64 -33
  31. package/components/MousePosition/MousePosition.js.map +2 -2
  32. package/components/MousePosition/index.js.map +2 -2
  33. package/components/NorthArrow/NorthArrow.js +35 -19
  34. package/components/NorthArrow/NorthArrow.js.map +2 -2
  35. package/components/NorthArrow/index.js.map +2 -2
  36. package/components/Overlay/Overlay.js +100 -83
  37. package/components/Overlay/Overlay.js.map +2 -2
  38. package/components/Overlay/index.js.map +2 -2
  39. package/components/Permalink/Permalink.js +135 -90
  40. package/components/Permalink/Permalink.js.map +2 -2
  41. package/components/Permalink/index.js.map +2 -2
  42. package/components/Popup/Popup.js +134 -83
  43. package/components/Popup/Popup.js.map +2 -2
  44. package/components/Popup/Popup.md.scss +1 -0
  45. package/components/Popup/Popup.scss +3 -1
  46. package/components/Popup/index.js.map +2 -2
  47. package/components/ResizeHandler/ResizeHandler.js +51 -45
  48. package/components/ResizeHandler/ResizeHandler.js.map +2 -2
  49. package/components/ResizeHandler/index.js.map +2 -2
  50. package/components/RouteSchedule/RouteSchedule.js +218 -136
  51. package/components/RouteSchedule/RouteSchedule.js.map +2 -2
  52. package/components/RouteSchedule/RouteSchedule.md.scss +4 -2
  53. package/components/RouteSchedule/RouteSchedule.scss +12 -23
  54. package/components/RouteSchedule/index.js.map +2 -2
  55. package/components/ScaleLine/ScaleLine.js +11 -9
  56. package/components/ScaleLine/ScaleLine.js.map +2 -2
  57. package/components/ScaleLine/ScaleLine.scss +6 -4
  58. package/components/ScaleLine/index.js.map +2 -2
  59. package/components/StopsFinder/StopsFinder.js +141 -118
  60. package/components/StopsFinder/StopsFinder.js.map +2 -2
  61. package/components/StopsFinder/StopsFinderOption.js +11 -24
  62. package/components/StopsFinder/StopsFinderOption.js.map +2 -2
  63. package/components/StopsFinder/index.js.map +2 -2
  64. package/components/Zoom/Zoom.js +101 -62
  65. package/components/Zoom/Zoom.js.map +2 -2
  66. package/components/Zoom/Zoom.md.scss +3 -1
  67. package/components/Zoom/Zoom.scss +7 -5
  68. package/components/Zoom/index.js.map +2 -2
  69. package/images/geops_qr.png +0 -0
  70. package/package.json +81 -177
  71. package/propTypes.js +67 -0
  72. package/propTypes.js.map +7 -0
  73. package/setupTests.js +22 -0
  74. package/setupTests.js.map +7 -0
  75. package/themes/README.md +26 -0
  76. package/themes/default/components.scss +9 -13
  77. package/themes/default/examples.scss +20 -19
  78. package/themes/default/index.scss +3 -3
  79. package/themes/default/mixins.scss +7 -5
  80. package/themes/default/variables.scss +27 -25
  81. package/utils/GlobalsForOle.js +57 -57
  82. package/utils/GlobalsForOle.js.map +2 -2
  83. package/utils/KML.js +174 -49
  84. package/utils/KML.js.map +2 -2
  85. package/utils/Styles.js +7 -7
  86. package/utils/Styles.js.map +2 -2
  87. package/utils/getLayersAsFlatArray.js +14 -0
  88. package/utils/getLayersAsFlatArray.js.map +7 -0
  89. package/utils/getPolygonPattern.js.map +2 -2
  90. package/utils/timeUtils.js +11 -7
  91. package/utils/timeUtils.js.map +2 -2
  92. package/components/FilterButton/FilterButton.js +0 -66
  93. package/components/FilterButton/FilterButton.js.map +0 -7
  94. package/components/FilterButton/FilterButton.scss +0 -36
  95. package/components/FilterButton/index.js +0 -1
  96. package/components/FilterButton/index.js.map +0 -7
  97. package/components/FollowButton/FollowButton.js +0 -73
  98. package/components/FollowButton/FollowButton.js.map +0 -7
  99. package/components/FollowButton/FollowButton.scss +0 -36
  100. package/components/FollowButton/index.js +0 -1
  101. package/components/FollowButton/index.js.map +0 -7
  102. package/components/Search/Search.js +0 -166
  103. package/components/Search/Search.js.map +0 -7
  104. package/components/Search/Search.md.scss +0 -4
  105. package/components/Search/Search.scss +0 -78
  106. package/components/Search/SearchService.js +0 -48
  107. package/components/Search/SearchService.js.map +0 -7
  108. package/components/Search/engines/Engine.js +0 -19
  109. package/components/Search/engines/Engine.js.map +0 -7
  110. package/components/Search/engines/StopFinder.js +0 -30
  111. package/components/Search/engines/StopFinder.js.map +0 -7
  112. package/components/Search/index.js +0 -3
  113. package/components/Search/index.js.map +0 -7
  114. package/components/TrackerControl/TrackerControl.js +0 -116
  115. package/components/TrackerControl/TrackerControl.js.map +0 -7
  116. package/components/TrackerControl/TrackerControl.scss +0 -30
  117. package/components/TrackerControl/index.js +0 -1
  118. package/components/TrackerControl/index.js.map +0 -7
  119. package/images/FilterButton/filter.svg +0 -1
  120. package/images/FollowButton/follow.svg +0 -1
  121. package/images/baselayer/osm.baselayer.hot.png +0 -0
  122. package/images/baselayer/osm.baselayer.png +0 -0
  123. package/utils/KMLFormat.js +0 -69
  124. package/utils/KMLFormat.js.map +0 -7
@@ -1,76 +1,190 @@
1
- import React, { Component } from "react";
2
- import PropTypes from "prop-types";
3
- import { Layer, getLayersAsFlatArray } from "mobility-toolbox-js/ol";
1
+ import Layer from "ol/layer/Layer";
4
2
  import { unByKey } from "ol/Observable";
3
+ import { getUid } from "ol/util";
4
+ import PropTypes from "prop-types";
5
+ import React, { Component } from "react";
6
+ import getLayersAsFlatArray from "../../utils/getLayersAsFlatArray";
5
7
  const propTypes = {
6
- layers: PropTypes.arrayOf(Layer),
8
+ /**
9
+ * CSS class to apply on the container.
10
+ */
7
11
  className: PropTypes.string,
8
- padding: PropTypes.number,
9
- isItemHidden: PropTypes.func,
12
+ /**
13
+ * Boolean determining whether children collapse/expand when their parent is toggled
14
+ * @param {...(boolean|function)} expandChildren Boolean or function returning a boolean.
15
+ * @return {boolean} True or false
16
+ */
17
+ expandChildren: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
18
+ /**
19
+ * Determine the className used by the div containing the parent and its children.
20
+ */
10
21
  getParentClassName: PropTypes.func,
22
+ /**
23
+ * Determine if the item is hidden in the tree or not.
24
+ *
25
+ * @param {object} item The item to hide or not.
26
+ *
27
+ * @return {bool} true if the item is not displayed in the tree
28
+ */
29
+ isItemHidden: PropTypes.func,
30
+ /**
31
+ * Layers provider.
32
+ */
33
+ layers: PropTypes.arrayOf(PropTypes.instanceOf(Layer)),
34
+ /**
35
+ * Padding left to apply on each level.
36
+ */
37
+ padding: PropTypes.number,
38
+ /**
39
+ * Custom function to render custom content after the list of children of an item.
40
+ *
41
+ * @param {object} item The item to render.
42
+ *
43
+ * @return {node} A jsx node.
44
+ */
45
+ renderAfterItem: PropTypes.func,
46
+ /**
47
+ * Custom function to render custom content before the list of children of an item.
48
+ *
49
+ * @param {object} item The item to render.
50
+ *
51
+ * @return {node} A jsx node.
52
+ */
53
+ renderBeforeItem: PropTypes.func,
54
+ /**
55
+ * Custom function to render the checkbox.
56
+ */
57
+ renderCheckbox: PropTypes.func,
58
+ /**
59
+ * Custom function to render an item in the tree.
60
+ *
61
+ * @param {object} item The item to render.
62
+ *
63
+ * @return {node} A jsx node.
64
+ */
11
65
  renderItem: PropTypes.func,
66
+ /**
67
+ * Custom function to render only the content of an item in the tree.
68
+ * inputProps und toggleProps can be used when calling the default renderItemContent function
69
+ * (comp.renderItemContent(layer, inputProps, toggleProps)) to overwrite the default input and label props
70
+ *
71
+ * @param {Layer} layer The layer the item content is created for
72
+ * @param {LayerTree} comp The LayerTree component.
73
+ *
74
+ * @return {node} A jsx node.
75
+ */
12
76
  renderItemContent: PropTypes.func,
13
- renderBeforeItem: PropTypes.func,
14
- renderAfterItem: PropTypes.func,
77
+ /**
78
+ * Custom function to render the label.
79
+ *
80
+ * @param {string} item The label to render.
81
+ * @param {LayerTree} comp The LayerTree component.
82
+ *
83
+ * @return {node} A jsx node.
84
+ */
15
85
  renderLabel: PropTypes.func,
86
+ /**
87
+ * Translation function.
88
+ * @param {function} Translation function returning the translated string.
89
+ */
90
+ t: PropTypes.func,
91
+ /**
92
+ * Object holding title for the layer tree's buttons.
93
+ */
16
94
  titles: PropTypes.shape({
17
- layerShow: PropTypes.string,
95
+ /**
96
+ * aria-label on checkbox to hide layer.
97
+ */
18
98
  layerHide: PropTypes.string,
19
- subLayerShow: PropTypes.string,
20
- subLayerHide: PropTypes.string
21
- }),
22
- expandChildren: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
23
- t: PropTypes.func
99
+ /**
100
+ * aria-label on checkbox to show layer.
101
+ */
102
+ layerShow: PropTypes.string,
103
+ /**
104
+ * title on button to show sublayers.
105
+ */
106
+ subLayerHide: PropTypes.string,
107
+ /**
108
+ * title on button to show sublayers.
109
+ */
110
+ subLayerShow: PropTypes.string
111
+ })
24
112
  };
25
113
  const defaultProps = {
26
- layers: [],
27
114
  className: "rs-layer-tree",
28
- padding: 30,
29
- isItemHidden: () => {
30
- return false;
31
- },
115
+ expandChildren: false,
32
116
  getParentClassName: () => {
33
117
  return void 0;
34
118
  },
119
+ isItemHidden: () => {
120
+ return false;
121
+ },
122
+ layers: [],
123
+ padding: 30,
124
+ renderAfterItem: null,
125
+ renderBeforeItem: null,
126
+ renderCheckbox: null,
35
127
  renderItem: null,
36
128
  renderItemContent: null,
37
- renderBeforeItem: null,
38
- renderAfterItem: null,
39
- renderLabel: (layer, layerComp) => {
40
- const { t } = layerComp.props;
41
- return t(layer.name);
42
- },
43
- titles: {
44
- layerShow: "Show layer",
45
- layerHide: "Hide layer",
46
- subLayerShow: "Show sublayer",
47
- subLayerHide: "Hide sublayer"
129
+ renderLabel: (layer) => {
130
+ return layer?.get("name") || "";
48
131
  },
49
132
  t: (s) => {
50
133
  return s;
51
134
  },
52
- expandChildren: false
135
+ titles: {
136
+ layerHide: "Hide layer",
137
+ layerShow: "Show layer",
138
+ subLayerHide: "Hide sublayer",
139
+ subLayerShow: "Show sublayer"
140
+ }
53
141
  };
54
142
  class LayerTree extends Component {
55
143
  constructor(props) {
56
144
  super(props);
57
- const { layers, isItemHidden } = this.props;
145
+ const { isItemHidden, layers } = this.props;
58
146
  const initialExpandedLayers = layers ? this.getExpandedLayers(
59
147
  layers.filter((l) => {
60
- return !isItemHidden(l) && (l.children || []).filter((child) => {
61
- return child.visible;
148
+ return !isItemHidden(l) && LayerTree.getChildren(l).filter((child) => {
149
+ return LayerTree.getVisible(child);
62
150
  }).filter((c) => {
63
151
  return !isItemHidden(c);
64
152
  }).length;
65
153
  })
66
154
  ) : [];
67
155
  this.state = {
68
- rootLayer: new Layer(),
69
156
  expandedLayers: initialExpandedLayers,
70
- revision: 0
157
+ revision: 0,
158
+ rootLayer: new Layer({})
71
159
  };
72
160
  this.olKeys = [];
73
161
  }
162
+ static getChildren = (layer) => layer?.get("children") || layer?.children || // ol.layer.group
163
+ layer?.getLayers?.().getArray() || [];
164
+ static getVisible = (layer) => layer.getVisible ? layer.getVisible() : layer.visible;
165
+ static listenGroups = (layers) => {
166
+ const flat = getLayersAsFlatArray(layers);
167
+ const keys = flat.map((layer) => {
168
+ return layer.on("change:visible", (e) => {
169
+ const { target } = e;
170
+ if (target.getVisible() && target.get("group")) {
171
+ flat.forEach((l) => {
172
+ if (l.get("group") === target.get("group") && l !== target) {
173
+ l.setVisible(false);
174
+ }
175
+ });
176
+ }
177
+ });
178
+ });
179
+ return keys;
180
+ };
181
+ static setVisible = (layer, visible) => {
182
+ if (layer.setVisible) {
183
+ layer.setVisible(visible);
184
+ return;
185
+ }
186
+ layer.visible = visible;
187
+ };
74
188
  componentDidMount() {
75
189
  this.updateLayers();
76
190
  }
@@ -84,29 +198,29 @@ class LayerTree extends Component {
84
198
  unByKey(this.olKeys);
85
199
  this.olKeys = [];
86
200
  }
87
- onInputClick(layer, toggle = false) {
88
- if (toggle) {
89
- this.onToggle(layer);
90
- } else if (layer.setVisible) {
91
- layer.setVisible(!layer.visible);
92
- } else {
93
- layer.visible = !layer.visible;
94
- }
95
- }
96
- onToggle(layer) {
97
- const { expandedLayers } = this.state;
98
- const pos = expandedLayers.indexOf(layer);
99
- if (pos > -1) {
100
- expandedLayers.splice(pos, 1);
101
- } else {
102
- expandedLayers.push(...this.getExpandedLayers([layer]));
201
+ expandLayer(layer, expLayers = []) {
202
+ const { isItemHidden } = this.props;
203
+ if (LayerTree.getVisible(layer) && !isItemHidden(layer)) {
204
+ const children = LayerTree.getChildren(layer).filter((c) => {
205
+ return !isItemHidden(c) && !c.get("isAlwaysExpanded");
206
+ }).flatMap((c) => {
207
+ return this.expandLayer(c, expLayers);
208
+ });
209
+ return [...expLayers, ...children, layer];
103
210
  }
104
- this.setState({ expandedLayers });
211
+ return expLayers;
105
212
  }
213
+ /**
214
+ * Get the always expanded ancestors (isAlwaysExpanded=true) of the given layers
215
+ * together with the (given) initially expanded layers
216
+ *
217
+ * @param {Layer} layers Initially expanded layers
218
+ * @return {Array.<Layer>} Initially expanded layers and all its always expanded ancestors
219
+ */
106
220
  getExpandedLayers(layers) {
107
221
  const { isItemHidden } = this.props;
108
222
  const children = layers.flatMap((l) => {
109
- return l.children.filter((c) => {
223
+ return LayerTree.getChildren(l).filter((c) => {
110
224
  return !isItemHidden(c) && c.get("isAlwaysExpanded");
111
225
  });
112
226
  });
@@ -115,160 +229,238 @@ class LayerTree extends Component {
115
229
  }
116
230
  return [...layers, this.getExpandedLayers(children)].flat();
117
231
  }
118
- updateLayers() {
119
- const { layers, expandChildren } = this.props;
120
- let rootLayer = new Layer();
121
- if (Array.isArray(layers)) {
122
- if (layers.length === 1) {
123
- [rootLayer] = layers;
124
- }
125
- rootLayer = new Layer({ children: layers });
232
+ onInputClick(layer, toggle = false) {
233
+ if (toggle) {
234
+ this.onToggle(layer);
126
235
  } else {
127
- rootLayer = layers;
236
+ LayerTree.setVisible(layer, !LayerTree.getVisible(layer));
128
237
  }
129
- getLayersAsFlatArray(rootLayer).forEach((layer) => {
130
- this.olKeys.push(
131
- layer.on("propertychange", (evt) => {
132
- const { revision } = this.state;
133
- this.setState({ revision: revision + 1 });
134
- })
135
- );
136
- });
137
- const state = { rootLayer };
138
- if (typeof expandChildren === "function" ? expandChildren(layers) : expandChildren) {
139
- state.expandedLayers = rootLayer.children.flatMap((l) => {
140
- return this.expandLayer(l);
141
- });
142
- }
143
- this.setState(state);
144
238
  }
145
- expandLayer(layer, expLayers = []) {
146
- const { isItemHidden } = this.props;
147
- if (layer.visible && !isItemHidden(layer)) {
148
- const children = layer.children.filter((c) => {
149
- return !isItemHidden(c) && !c.get("isAlwaysExpanded");
150
- }).flatMap((c) => {
151
- return this.expandLayer(c, expLayers);
152
- });
153
- return [...expLayers, ...children, layer];
239
+ onToggle(layer) {
240
+ const { expandedLayers } = this.state;
241
+ const pos = expandedLayers.indexOf(layer);
242
+ if (pos > -1) {
243
+ expandedLayers.splice(pos, 1);
244
+ } else {
245
+ expandedLayers.push(...this.getExpandedLayers([layer]));
154
246
  }
155
- return expLayers;
247
+ this.setState({ expandedLayers });
156
248
  }
157
- renderInput(layer) {
158
- const { titles, isItemHidden } = this.props;
159
- let tabIndex = 0;
160
- if (!(layer.children || []).filter((c) => {
161
- return !isItemHidden(c);
162
- }).length) {
163
- tabIndex = -1;
164
- }
165
- const inputType = layer.get("group") ? "radio" : "checkbox";
166
- return /* @__PURE__ */ React.createElement("label", {
167
- className: `rs-layer-tree-input rs-layer-tree-input-${inputType} rs-${inputType}`,
168
- tabIndex,
169
- title: layer.visible ? titles.layerHide : titles.layerShow,
170
- "aria-label": layer.visible ? titles.layerHide : titles.layerShow,
171
- onKeyPress: (e) => {
172
- if (e.which === 13) {
173
- this.onInputClick(layer);
174
- }
175
- }
176
- }, /* @__PURE__ */ React.createElement("input", {
177
- type: inputType,
178
- tabIndex: -1,
179
- checked: layer.visible,
180
- readOnly: true,
181
- onClick: () => {
182
- return this.onInputClick(layer);
183
- }
184
- }), /* @__PURE__ */ React.createElement("span", null));
249
+ render() {
250
+ const { className } = this.props;
251
+ return /* @__PURE__ */ React.createElement("div", { className }, this.renderTree());
185
252
  }
186
253
  renderArrow(layer) {
187
254
  const { isItemHidden } = this.props;
188
255
  const { expandedLayers } = this.state;
189
- if (!(layer.children || []).filter((c) => {
256
+ if (!LayerTree.getChildren(layer).filter((c) => {
190
257
  return !isItemHidden(c);
191
258
  }).length || layer.get("isAlwaysExpanded")) {
192
259
  return null;
193
260
  }
194
- return /* @__PURE__ */ React.createElement("div", {
195
- className: `rs-layer-tree-arrow rs-layer-tree-arrow-${!expandedLayers.includes(layer) ? "collapsed" : "expanded"}`
196
- });
197
- }
198
- renderToggleButton(layer) {
199
- const { t, titles, isItemHidden, renderLabel } = this.props;
200
- const { expandedLayers } = this.state;
201
- const onInputClick = () => {
202
- this.onInputClick(
203
- layer,
204
- (layer.children || []).filter((c) => {
205
- return !isItemHidden(c);
206
- }).length && !layer.get("isAlwaysExpanded")
207
- );
208
- };
209
- const title = `${t(layer.name)} ${expandedLayers.includes(layer) ? titles.subLayerHide : titles.subLayerShow}`;
210
- return /* @__PURE__ */ React.createElement("div", {
211
- role: "button",
212
- tabIndex: 0,
213
- className: "rs-layer-tree-toggle",
214
- title,
215
- "aria-expanded": expandedLayers.includes(layer),
216
- "aria-label": title,
217
- onClick: onInputClick,
218
- onKeyPress: onInputClick
219
- }, /* @__PURE__ */ React.createElement("div", null, renderLabel(layer, this)), this.renderArrow(layer));
261
+ return /* @__PURE__ */ React.createElement(
262
+ "div",
263
+ {
264
+ className: `rs-layer-tree-arrow rs-layer-tree-arrow-${!expandedLayers.includes(layer) ? "collapsed" : "expanded"}`
265
+ }
266
+ );
220
267
  }
221
- renderItemContent(layer) {
222
- return /* @__PURE__ */ React.createElement(React.Fragment, null, this.renderInput(layer), this.renderToggleButton(layer));
268
+ renderInput(layer, inputProps) {
269
+ const { isItemHidden, renderCheckbox, titles } = this.props;
270
+ let tabIndex = 0;
271
+ if (!LayerTree.getChildren(layer).filter((c) => {
272
+ return !isItemHidden(c);
273
+ }).length) {
274
+ tabIndex = -1;
275
+ }
276
+ const inputType = layer.get("group") ? "radio" : "checkbox";
277
+ return renderCheckbox ? renderCheckbox(layer, this, inputProps) : (
278
+ // eslint-disable-next-line jsx-a11y/label-has-associated-control,jsx-a11y/no-noninteractive-element-interactions
279
+ /* @__PURE__ */ React.createElement(
280
+ "label",
281
+ {
282
+ className: `rs-layer-tree-input rs-layer-tree-input-${inputType} rs-${inputType}`,
283
+ onKeyPress: (e) => {
284
+ if (e.which === 13) {
285
+ this.onInputClick(layer);
286
+ }
287
+ },
288
+ tabIndex,
289
+ title: LayerTree.getVisible(layer) ? titles.layerHide : titles.layerShow
290
+ },
291
+ /* @__PURE__ */ React.createElement(
292
+ "input",
293
+ {
294
+ checked: LayerTree.getVisible(layer),
295
+ onClick: () => {
296
+ return this.onInputClick(layer);
297
+ },
298
+ readOnly: true,
299
+ tabIndex: -1,
300
+ type: inputType,
301
+ ...inputProps
302
+ }
303
+ ),
304
+ /* @__PURE__ */ React.createElement("span", null)
305
+ )
306
+ );
223
307
  }
224
308
  renderItem(layer, level) {
225
309
  const { isItemHidden } = this.props;
226
310
  const { expandedLayers } = this.state;
227
311
  const {
228
- renderItem,
229
- renderItemContent,
230
- renderBeforeItem,
231
- renderAfterItem,
312
+ getParentClassName,
232
313
  padding,
233
- getParentClassName
314
+ renderAfterItem,
315
+ renderBeforeItem,
316
+ renderItem,
317
+ renderItemContent
234
318
  } = this.props;
235
319
  const children = expandedLayers.includes(layer) ? [
236
- ...(layer.children || []).filter((c) => {
320
+ ...LayerTree.getChildren(layer).filter((c) => {
237
321
  return !isItemHidden(c);
238
322
  })
239
323
  ] : [];
240
324
  if (renderItem) {
241
325
  return renderItem(layer, this.onInputClick, this.onToggle);
242
326
  }
243
- return /* @__PURE__ */ React.createElement("div", {
244
- className: getParentClassName(),
245
- key: layer.key
246
- }, /* @__PURE__ */ React.createElement("div", {
247
- className: `rs-layer-tree-item ${layer.visible ? "rs-visible" : ""}`,
248
- style: {
249
- paddingLeft: `${padding * level}px`
250
- }
251
- }, renderItemContent ? renderItemContent(layer, this) : this.renderItemContent(layer)), renderBeforeItem && renderBeforeItem(layer, level, this), [...children].reverse().map((child) => {
252
- return this.renderItem(child, level + 1);
253
- }), renderAfterItem && renderAfterItem(layer, level, this));
327
+ return /* @__PURE__ */ React.createElement(
328
+ "div",
329
+ {
330
+ className: getParentClassName(),
331
+ key: layer.key || layer.get("key") || layer.get("name") || getUid(layer)
332
+ },
333
+ /* @__PURE__ */ React.createElement(
334
+ "div",
335
+ {
336
+ className: `rs-layer-tree-item ${LayerTree.getVisible(layer) ? "rs-visible" : ""}`,
337
+ style: {
338
+ paddingLeft: `${padding * level}px`
339
+ }
340
+ },
341
+ renderItemContent ? renderItemContent(layer, this) : this.renderItemContent(layer)
342
+ ),
343
+ renderBeforeItem && renderBeforeItem(layer, level, this),
344
+ [...children].reverse().map((child) => {
345
+ return this.renderItem(child, level + 1);
346
+ }),
347
+ renderAfterItem && renderAfterItem(layer, level, this)
348
+ );
349
+ }
350
+ renderItemContent(layer, inputProps = {}, toggleProps = {}) {
351
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, this.renderInput(layer, inputProps), this.renderToggleButton(layer, toggleProps));
352
+ }
353
+ // Render a button which expands/collapse the layer if there is children
354
+ // or simulate a click on the input otherwise.
355
+ renderToggleButton(layer, toggleProps) {
356
+ const { isItemHidden, renderLabel, titles } = this.props;
357
+ const { expandedLayers } = this.state;
358
+ const onInputClick = () => {
359
+ this.onInputClick(
360
+ layer,
361
+ LayerTree.getChildren(layer).filter((c) => {
362
+ return !isItemHidden(c);
363
+ }).length && !layer.get("isAlwaysExpanded")
364
+ );
365
+ };
366
+ const title = `${renderLabel(layer, this)} ${expandedLayers.includes(layer) ? titles.subLayerHide : titles.subLayerShow}`;
367
+ return /* @__PURE__ */ React.createElement(
368
+ "div",
369
+ {
370
+ "aria-expanded": expandedLayers.includes(layer),
371
+ "aria-label": title,
372
+ className: "rs-layer-tree-toggle",
373
+ onClick: onInputClick,
374
+ onKeyPress: onInputClick,
375
+ role: "button",
376
+ tabIndex: 0,
377
+ title,
378
+ ...toggleProps
379
+ },
380
+ /* @__PURE__ */ React.createElement("div", null, renderLabel(layer, this)),
381
+ this.renderArrow(layer)
382
+ );
254
383
  }
255
384
  renderTree() {
256
385
  const { isItemHidden } = this.props;
257
386
  const { rootLayer } = this.state;
258
- if (!rootLayer?.children?.length) {
387
+ if (!LayerTree.getChildren(rootLayer).length) {
259
388
  return null;
260
389
  }
261
- return /* @__PURE__ */ React.createElement(React.Fragment, null, rootLayer.children.filter((l) => {
390
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, LayerTree.getChildren(rootLayer).filter((l) => {
262
391
  return !isItemHidden(l);
263
392
  }).reverse().map((l) => {
264
393
  return this.renderItem(l, 0);
265
394
  }));
266
395
  }
267
- render() {
268
- const { className } = this.props;
269
- return /* @__PURE__ */ React.createElement("div", {
270
- className
271
- }, this.renderTree());
396
+ updateLayers() {
397
+ const { expandChildren, layers } = this.props;
398
+ let rootLayer = new Layer({});
399
+ if (Array.isArray(layers)) {
400
+ if (layers.length === 1) {
401
+ [rootLayer] = layers;
402
+ }
403
+ rootLayer = new Layer({ children: layers });
404
+ } else {
405
+ rootLayer = layers;
406
+ }
407
+ const flat = getLayersAsFlatArray(rootLayer);
408
+ flat.forEach((layer) => {
409
+ this.olKeys.push(
410
+ layer.on("propertychange", () => {
411
+ const { revision } = this.state;
412
+ this.setState({ revision: revision + 1 });
413
+ }),
414
+ // Manage group visibility
415
+ layer.on("change:visible", (evt) => {
416
+ const { target } = evt;
417
+ if (target.getVisible() && target.get("group")) {
418
+ flat.forEach((l) => {
419
+ if (l.get("group") === target.get("group") && l !== target) {
420
+ l.setVisible(false);
421
+ }
422
+ });
423
+ }
424
+ }),
425
+ // Manage parent/children visibility
426
+ layer.on("change:visible", (evt) => {
427
+ const { target } = evt;
428
+ const parent = target.get("parent");
429
+ const children = LayerTree.getChildren(target);
430
+ if (target.getVisible()) {
431
+ if (parent) {
432
+ parent.setVisible(true);
433
+ }
434
+ if (children && !children.some((child) => child.getVisible())) {
435
+ children.forEach((child) => {
436
+ child.setVisible(true);
437
+ });
438
+ }
439
+ } else {
440
+ children.forEach((child) => {
441
+ child.setVisible(false);
442
+ });
443
+ if (parent?.getVisible() && !parent?.get("children").find((child) => child.getVisible())) {
444
+ parent.setVisible(false);
445
+ }
446
+ }
447
+ })
448
+ );
449
+ });
450
+ flat.forEach((layer) => {
451
+ const children = LayerTree.getChildren(layer);
452
+ children.forEach((child) => {
453
+ child.set("parent", layer);
454
+ });
455
+ });
456
+ const state = { rootLayer };
457
+ if (typeof expandChildren === "function" ? expandChildren(layers) : expandChildren) {
458
+ const children = LayerTree.getChildren(rootLayer);
459
+ state.expandedLayers = children.flatMap((l) => {
460
+ return this.expandLayer(l);
461
+ });
462
+ }
463
+ this.setState(state);
272
464
  }
273
465
  }
274
466
  LayerTree.propTypes = propTypes;