@defra/interactive-map 0.0.41-alpha → 0.0.42-alpha

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 (65) hide show
  1. package/dist/css/index.css +1 -1
  2. package/dist/esm/im-core.js +1 -1
  3. package/dist/umd/im-core.js +1 -1
  4. package/dist/umd/index.js +1 -1
  5. package/docs/api/button-definition.md +7 -8
  6. package/docs/api/control-definition.md +8 -0
  7. package/docs/api/panel-definition.md +5 -0
  8. package/docs/api/slots.md +24 -1
  9. package/docs/examples/add-polygons.mdx +8 -2
  10. package/docs/examples/add-symbols.mdx +8 -2
  11. package/docs/plugins/datasets.md +23 -15
  12. package/docs/plugins/map-key.md +147 -0
  13. package/docs/plugins.md +5 -1
  14. package/package.json +1 -1
  15. package/plugins/beta/map-styles/dist/umd/im-map-styles-plugin.js +1 -1
  16. package/plugins/beta/map-styles/dist/umd/index.js +1 -1
  17. package/plugins/beta/use-location/dist/esm/im-use-location-plugin.js +1 -1
  18. package/plugins/beta/use-location/dist/umd/im-use-location-plugin.js +1 -1
  19. package/plugins/beta/use-location/src/manifest.js +1 -1
  20. package/plugins/draw/dist/esm/im-draw-plugin.js +1 -1
  21. package/plugins/draw/dist/umd/im-draw-plugin.js +1 -1
  22. package/plugins/draw/dist/umd/index.js +1 -1
  23. package/plugins/draw/src/api/createNewShape.js +41 -0
  24. package/plugins/draw/src/api/createNewShape.test.js +63 -0
  25. package/plugins/draw/src/api/newLine.js +2 -40
  26. package/plugins/draw/src/api/newPolygon.js +2 -40
  27. package/plugins/interact/dist/esm/im-interact-plugin.js +1 -1
  28. package/plugins/interact/dist/umd/im-interact-plugin.js +1 -1
  29. package/plugins/interact/dist/umd/index.js +1 -1
  30. package/plugins/interact/src/manifest.js +1 -1
  31. package/plugins/map-key/dist/css/index.css +6 -0
  32. package/plugins/map-key/dist/esm/im-map-key-plugin.js +1 -1
  33. package/plugins/map-key/dist/umd/im-map-key-plugin.js +1 -1
  34. package/plugins/map-key/src/components/Key/Key.jsx +5 -3
  35. package/plugins/map-key/src/components/Key/Key.module.scss +6 -0
  36. package/plugins/map-key/src/components/Key/KeyItem.jsx +5 -8
  37. package/plugins/map-key/src/components/Key/KeySvg.jsx +21 -22
  38. package/plugins/map-key/src/components/Key/KeySvgLine.jsx +3 -9
  39. package/plugins/map-key/src/components/Key/KeySvgPattern.jsx +2 -7
  40. package/plugins/map-key/src/components/Key/KeySvgPattern.test.jsx +6 -0
  41. package/plugins/map-key/src/components/Key/KeySvgRect.jsx +4 -11
  42. package/plugins/map-key/src/components/Key/KeySvgSymbol.jsx +5 -11
  43. package/plugins/map-key/src/components/Key/KeySvgSymbol.test.jsx +12 -0
  44. package/plugins/map-key/src/components/Key/MapKey.jsx +5 -2
  45. package/plugins/map-key/src/components/Key/MapKey.test.jsx +28 -11
  46. package/src/App/components/KeyboardHelp/KeyboardHelp.jsx +25 -23
  47. package/src/App/components/KeyboardHelp/KeyboardHelp.test.jsx +22 -5
  48. package/src/App/components/Panel/Panel.jsx +50 -8
  49. package/src/App/components/Panel/Panel.module.scss +31 -7
  50. package/src/App/components/Panel/Panel.test.jsx +81 -2
  51. package/src/App/components/Tabs/Tabs.jsx +43 -17
  52. package/src/App/components/Tabs/Tabs.module.scss +32 -5
  53. package/src/App/components/Tabs/Tabs.test.jsx +40 -10
  54. package/src/App/renderer/groupByKey.js +28 -0
  55. package/src/App/renderer/groupByKey.test.js +39 -0
  56. package/src/App/renderer/groupIntoTabs.js +42 -0
  57. package/src/App/renderer/groupIntoTabs.test.js +95 -0
  58. package/src/App/renderer/mapButtons.js +74 -122
  59. package/src/App/renderer/mapButtons.test.js +51 -80
  60. package/src/App/renderer/mapControls.js +1 -0
  61. package/src/App/renderer/mapControls.test.js +16 -0
  62. package/src/App/renderer/mapPanels.js +26 -19
  63. package/src/App/renderer/mapPanels.test.js +44 -0
  64. package/src/config/appConfig.js +2 -2
  65. package/src/types.js +20 -2
@@ -170,6 +170,50 @@ describe('mapPanels', () => {
170
170
  expect(logger.warn).toHaveBeenCalledWith(expect.stringContaining('p1'))
171
171
  })
172
172
 
173
+ it('orders multiple injected controls even when the panel has no render (regression: previously returned mapControls output unordered)', () => {
174
+ mapControls.mockReturnValue([
175
+ { id: 'first', order: 2, element: <span>first</span> },
176
+ { id: 'second', order: 1, element: <span>second</span> }
177
+ ])
178
+ defaultAppState.panelConfig = ({ p1: { desktop: { slot: 'header' }, includeModes: ['view'] } })
179
+ const result = map()
180
+ expect(result[0].element.props.items.map(i => i.id)).toEqual(['second', 'first'])
181
+ })
182
+
183
+ describe('tabs', () => {
184
+ it('does not build a tabs list when everything shares one (or no) tab', () => {
185
+ const renderFn = () => <div>child</div>
186
+ mapControls.mockReturnValue([{ id: 'injected1', order: 0, element: <span>injected</span> }])
187
+ defaultAppState.panelConfig = ({ p1: { ...baseConfig, render: renderFn } })
188
+ const result = map()
189
+ expect(result[0].element.props.tabs).toBeUndefined()
190
+ expect(result[0].element.props.items).toBeDefined()
191
+ })
192
+
193
+ it('groups the panel\'s own content and an injected control into separate tabs', () => {
194
+ const renderFn = () => <div>child</div>
195
+ mapControls.mockReturnValue([{ id: 'injected1', order: 0, tab: 'Injected', element: <span>injected</span> }])
196
+ defaultAppState.panelConfig = ({
197
+ p1: { ...baseConfig, render: renderFn, desktop: { slot: 'header', order: 1, tab: 'Own' } }
198
+ })
199
+ const result = map()
200
+ expect(result[0].element.props.items).toBeUndefined()
201
+ const tabNames = result[0].element.props.tabs.map(t => t.name)
202
+ expect(tabNames.sort()).toEqual(['Injected', 'Own'])
203
+ })
204
+
205
+ it('falls back to the panel\'s own label for its content\'s implicit tab', () => {
206
+ const renderFn = () => <div>child</div>
207
+ mapControls.mockReturnValue([{ id: 'injected1', order: 0, tab: 'Injected', element: <span>injected</span> }])
208
+ defaultAppState.panelConfig = ({
209
+ p1: { ...baseConfig, render: renderFn, label: 'Map styles' }
210
+ })
211
+ const result = map()
212
+ const tabNames = result[0].element.props.tabs.map(t => t.name)
213
+ expect(tabNames).toContain('Map styles')
214
+ })
215
+ })
216
+
173
217
  it('returns correct structure and defaults', () => {
174
218
  defaultAppState.panelConfig = ({ p1: { desktop: { slot: 'header' }, includeModes: ['view'] } })
175
219
  const result = map()
@@ -74,7 +74,7 @@ export const defaultAppConfig = {
74
74
  desktop: buttonSlots
75
75
  }, {
76
76
  id: 'zoomIn',
77
- group: { name: 'zoom', label: 'Zoom controls', order: 0 },
77
+ group: { label: 'Zoom controls', slotOrder: 0 },
78
78
  label: 'Zoom in',
79
79
  iconId: 'plus',
80
80
  keepFocus: true,
@@ -86,7 +86,7 @@ export const defaultAppConfig = {
86
86
  desktop: buttonSlots
87
87
  }, {
88
88
  id: 'zoomOut',
89
- group: { name: 'zoom', label: 'Zoom controls', order: 0 },
89
+ group: { label: 'Zoom controls', slotOrder: 0 },
90
90
  label: 'Zoom out',
91
91
  iconId: 'minus',
92
92
  keepFocus: true,
package/src/types.js CHANGED
@@ -40,6 +40,15 @@
40
40
  * different plugin. The panel's own content and every control targeting it are ordered together
41
41
  * via `order`. Only supported by panels with a `render` component — a panel using static `html`
42
42
  * can't host injected controls, since `dangerouslySetInnerHTML` owns its body's children.
43
+ *
44
+ * @property {string} [tab]
45
+ * Groups this item into a tab within its target panel. Two items share a tab by giving it the
46
+ * same `tab` string (case/whitespace-insensitive — compared kebab-cased); items with no `tab`
47
+ * share one implicit tab, labelled with the panel's own `label`. Tabs only render once this
48
+ * produces more than one distinct group — a panel with zero or one tab renders flat, with no
49
+ * tab UI at all. A tab's position and displayed label both come from whichever member ends up
50
+ * first once its own members are ordered by `order`, so there's no separate tab-order property
51
+ * to set. Like `order`, only respected for controls with a `render` component.
43
52
  */
44
53
 
45
54
  /**
@@ -67,6 +76,11 @@
67
76
  * @property {string} slot
68
77
  * Slot identifier.
69
78
  *
79
+ * @property {string} [tab]
80
+ * Groups the panel's own content into a tab alongside any controls injected into it — see
81
+ * `ControlBreakpointConfig.tab`. Optional even once tabs are active: the panel's own content
82
+ * falls back to an implicit tab labelled with the panel's `label` when omitted.
83
+ *
70
84
  * @property {string} [width]
71
85
  * Panel width.
72
86
  */
@@ -156,8 +170,12 @@
156
170
  * @property {(context: PluginContext) => boolean} [excludeWhen]
157
171
  * Callback to determine if the button should be excluded from rendering.
158
172
  *
159
- * @property {string} [group]
160
- * Button group label for grouping related buttons.
173
+ * @property {{ label: string, slotOrder?: number }} [group]
174
+ * Groups this button with any other button sharing the same `label` (kebab-cased) into one
175
+ * `role="group"` container, rendered as a single item in the slot. `label` is also the
176
+ * group's accessible name (aria-label) — buttons whose labels differ only by case/whitespace
177
+ * still merge into one group. `slotOrder` positions the group itself within the slot (defaults
178
+ * to 0); each button's own breakpoint `order` controls its position *within* the group.
161
179
  *
162
180
  * @property {(context: PluginContext) => boolean} [hiddenWhen]
163
181
  * Callback to determine if the button should be hidden. Sets display: none if true.