@defra/interactive-map 0.0.14-alpha → 0.0.16-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.
- package/assets/css/docusaurus.css +104 -0
- package/assets/images/favicon.svg +1 -0
- package/assets/images/hero.png +0 -0
- package/dist/css/index.css +1 -1
- package/dist/esm/im-core.js +1 -1
- package/dist/umd/im-core.js +1 -1
- package/dist/umd/index.js +1 -1
- package/docs/api/slot-map.svg +1 -0
- package/docs/api/slots.md +89 -6
- package/docs/api.md +1 -1
- package/docs/architecture.md +3 -1
- package/docs/{demo.mdx → examples.mdx} +1 -1
- package/docs/getting-started.md +1 -3
- package/docs/index.mdx +42 -0
- package/docs/plugins/interact.md +176 -55
- package/docs/plugins/map-styles.md +64 -7
- package/docs/plugins/search.md +207 -63
- package/docs/plugins.md +7 -15
- package/docusaurus.config.cjs +34 -34
- package/jest.setup.js +1 -1
- package/package.json +5 -4
- package/plugins/beta/datasets/dist/esm/im-datasets-plugin.js +1 -1
- package/plugins/beta/datasets/dist/umd/im-datasets-plugin.js +1 -1
- package/plugins/beta/datasets/src/DatasetsInit.jsx +1 -1
- package/plugins/beta/datasets/src/api/addDataset.js +1 -1
- package/plugins/beta/datasets/src/api/hideDataset.js +1 -1
- package/plugins/beta/datasets/src/api/hideFeatures.js +1 -1
- package/plugins/beta/datasets/src/api/removeDataset.js +1 -1
- package/plugins/beta/datasets/src/api/showDataset.js +1 -1
- package/plugins/beta/datasets/src/api/showFeatures.js +1 -1
- package/plugins/beta/datasets/src/datasets.js +4 -4
- package/plugins/beta/datasets/src/defaults.js +1 -1
- package/plugins/beta/datasets/src/fetch/createDynamicSource.js +5 -5
- package/plugins/beta/datasets/src/handleSetMapStyle.js +1 -1
- package/plugins/beta/datasets/src/manifest.js +7 -7
- package/plugins/beta/datasets/src/mapLayers.js +2 -3
- package/plugins/beta/datasets/src/panels/Key.jsx +31 -29
- package/plugins/beta/datasets/src/panels/Layers.jsx +8 -9
- package/plugins/beta/datasets/src/utils/bbox.js +4 -4
- package/plugins/beta/draw-es/dist/esm/im-draw-es-plugin.js +1 -1
- package/plugins/beta/draw-es/src/DrawInit.jsx +16 -16
- package/plugins/beta/draw-es/src/api/addFeature.js +3 -3
- package/plugins/beta/draw-es/src/api/deleteFeature.js +3 -3
- package/plugins/beta/draw-es/src/api/editFeature.js +3 -3
- package/plugins/beta/draw-es/src/api/newPolygon.js +3 -3
- package/plugins/beta/draw-es/src/events.js +52 -20
- package/plugins/beta/draw-es/src/events.test.js +301 -0
- package/plugins/beta/draw-es/src/graphic.js +1 -1
- package/plugins/beta/draw-es/src/manifest.js +4 -4
- package/plugins/beta/draw-es/src/reducer.js +1 -1
- package/plugins/beta/draw-es/src/sketchViewModel.js +1 -1
- package/plugins/beta/draw-ml/dist/esm/im-draw-ml-plugin.js +1 -1
- package/plugins/beta/draw-ml/dist/umd/im-draw-ml-plugin.js +1 -1
- package/plugins/beta/draw-ml/src/DrawInit.jsx +49 -52
- package/plugins/beta/draw-ml/src/api/deleteFeature.js +1 -1
- package/plugins/beta/draw-ml/src/api/editFeature.js +8 -5
- package/plugins/beta/draw-ml/src/api/newLine.js +0 -1
- package/plugins/beta/draw-ml/src/api/newPolygon.js +0 -1
- package/plugins/beta/draw-ml/src/api/split.js +4 -4
- package/plugins/beta/draw-ml/src/defaults.js +1 -1
- package/plugins/beta/draw-ml/src/events.js +8 -6
- package/plugins/beta/draw-ml/src/manifest.js +15 -15
- package/plugins/beta/draw-ml/src/mapboxDraw.js +1 -1
- package/plugins/beta/draw-ml/src/mapboxSnap.js +17 -18
- package/plugins/beta/draw-ml/src/modes/createDrawMode.js +31 -31
- package/plugins/beta/draw-ml/src/modes/disabledMode.js +1 -1
- package/plugins/beta/draw-ml/src/modes/editVertex/touchHandlers.js +11 -11
- package/plugins/beta/draw-ml/src/modes/editVertex/undoHandlers.js +7 -7
- package/plugins/beta/draw-ml/src/modes/editVertex/vertexOperations.js +8 -8
- package/plugins/beta/draw-ml/src/modes/editVertex/vertexQueries.js +7 -7
- package/plugins/beta/draw-ml/src/modes/editVertexMode.js +32 -24
- package/plugins/beta/draw-ml/src/reducer.js +1 -1
- package/plugins/beta/draw-ml/src/undoStack.js +4 -4
- package/plugins/beta/draw-ml/src/utils/snapHelpers.js +12 -12
- package/plugins/beta/draw-ml/src/utils/spatial.js +11 -11
- package/plugins/beta/frame/src/Frame.jsx +4 -4
- package/plugins/beta/frame/src/FrameInit.jsx +4 -4
- package/plugins/beta/frame/src/api/addFrame.js +1 -1
- package/plugins/beta/frame/src/api/editFeature.js +1 -1
- package/plugins/beta/frame/src/config.js +1 -1
- package/plugins/beta/frame/src/manifest.js +3 -3
- package/plugins/beta/frame/src/reducer.js +1 -1
- package/plugins/beta/frame/src/utils.js +1 -1
- package/plugins/beta/map-styles/dist/esm/im-map-styles-plugin.js +1 -1
- package/plugins/beta/map-styles/dist/umd/im-map-styles-plugin.js +1 -1
- package/plugins/beta/map-styles/src/MapStyles.jsx +18 -18
- package/plugins/beta/map-styles/src/manifest.js +2 -2
- package/plugins/beta/scale-bar/src/ScaleBar.jsx +5 -5
- package/plugins/beta/use-location/src/UseLocation.jsx +1 -1
- package/plugins/beta/use-location/src/defaults.js +1 -1
- package/plugins/beta/use-location/src/events.js +3 -3
- package/plugins/interact/src/InteractInit.jsx +1 -2
- package/plugins/interact/src/api/enable.js +8 -5
- package/plugins/interact/src/api/enable.test.js +2 -2
- package/plugins/interact/src/api/selectFeature.js +4 -4
- package/plugins/interact/src/api/unselectFeature.js +5 -5
- package/plugins/interact/src/defaults.js +0 -1
- package/plugins/interact/src/events.test.js +15 -15
- package/plugins/interact/src/hooks/useHighlightSync.js +1 -1
- package/plugins/interact/src/hooks/useInteractionHandlers.js +2 -2
- package/plugins/interact/src/hooks/useInteractionHandlers.test.js +5 -5
- package/plugins/interact/src/manifest.js +2 -2
- package/plugins/interact/src/manifest.test.js +3 -4
- package/plugins/interact/src/reducer.js +3 -3
- package/plugins/interact/src/reducer.test.js +0 -1
- package/plugins/interact/src/utils/spatial.js +10 -10
- package/plugins/interact/src/utils/spatial.test.js +14 -14
- package/plugins/search/dist/css/index.css +1 -1
- package/plugins/search/dist/esm/im-search-plugin.js +1 -1
- package/plugins/search/dist/esm/index.js +1 -1
- package/plugins/search/dist/umd/im-search-plugin.js +1 -1
- package/plugins/search/dist/umd/index.js +1 -1
- package/plugins/search/src/Search.jsx +7 -6
- package/plugins/search/src/Search.test.jsx +23 -23
- package/plugins/search/src/components/CloseButton/CloseButton.jsx +15 -15
- package/plugins/search/src/components/CloseButton/CloseButton.test.jsx +2 -2
- package/plugins/search/src/components/Form/Form.jsx +14 -14
- package/plugins/search/src/components/Form/Form.test.jsx +11 -11
- package/plugins/search/src/components/OpenButton/OpenButton.jsx +16 -15
- package/plugins/search/src/components/OpenButton/OpenButton.test.jsx +6 -2
- package/plugins/search/src/components/SubmitButton/SubmitButton.jsx +15 -15
- package/plugins/search/src/components/Suggestions/Suggestions.jsx +6 -6
- package/plugins/search/src/components/Suggestions/Suggestions.test.jsx +4 -4
- package/plugins/search/src/datasets.js +12 -13
- package/plugins/search/src/datasets.test.js +1 -1
- package/plugins/search/src/defaults.js +1 -1
- package/plugins/search/src/events/fetchSuggestions.js +4 -4
- package/plugins/search/src/events/fetchSuggestions.test.js +5 -5
- package/plugins/search/src/events/formHandlers.js +3 -3
- package/plugins/search/src/events/formHandlers.test.js +1 -1
- package/plugins/search/src/events/index.js +2 -2
- package/plugins/search/src/events/index.test.js +2 -2
- package/plugins/search/src/events/inputHandlers.js +4 -4
- package/plugins/search/src/events/inputHandlers.test.js +1 -1
- package/plugins/search/src/events/suggestionHandlers.js +2 -2
- package/plugins/search/src/events/suggestionHandlers.test.js +1 -1
- package/plugins/search/src/index.js +2 -1
- package/plugins/search/src/index.test.js +3 -3
- package/plugins/search/src/manifest.js +6 -4
- package/plugins/search/src/reducer.js +1 -2
- package/plugins/search/src/reducer.test.js +2 -2
- package/plugins/search/src/search.scss +18 -6
- package/plugins/search/src/utils/parseOsNamesResults.js +1 -2
- package/plugins/search/src/utils/parseOsNamesResults.test.js +2 -2
- package/plugins/search/src/utils/updateMap.js +1 -1
- package/plugins/search/src/utils/updateMap.test.js +5 -5
- package/providers/beta/esri/dist/esm/im-esri-provider.js +1 -1
- package/providers/beta/esri/src/esriProvider.js +5 -5
- package/providers/beta/esri/src/utils/coords.js +1 -1
- package/providers/beta/esri/src/utils/esriFixes.js +1 -1
- package/providers/beta/esri/src/utils/query.js +4 -4
- package/providers/beta/esri/src/utils/spatial.js +1 -2
- package/providers/beta/esri/src/utils/spatial.test.js +4 -1
- package/providers/beta/open-names/src/utils/mapToLocationModel.test.js +1 -1
- package/providers/maplibre/src/appEvents.test.js +1 -1
- package/providers/maplibre/src/index.js +1 -1
- package/providers/maplibre/src/index.test.js +3 -5
- package/providers/maplibre/src/mapEvents.test.js +15 -5
- package/providers/maplibre/src/maplibreProvider.test.js +6 -2
- package/providers/maplibre/src/utils/calculateLinearTextSize.js +4 -4
- package/providers/maplibre/src/utils/calculateLinearTextSize.test.js +3 -3
- package/providers/maplibre/src/utils/detectWebgl.test.js +1 -1
- package/providers/maplibre/src/utils/highlightFeatures.js +2 -2
- package/providers/maplibre/src/utils/highlightFeatures.test.js +12 -6
- package/providers/maplibre/src/utils/labels.js +19 -20
- package/providers/maplibre/src/utils/labels.test.js +15 -13
- package/providers/maplibre/src/utils/maplibreFixes.test.js +1 -1
- package/providers/maplibre/src/utils/queryFeatures.js +6 -6
- package/providers/maplibre/src/utils/queryFeatures.test.js +13 -13
- package/providers/maplibre/src/utils/spatial.js +0 -1
- package/providers/maplibre/src/utils/spatial.test.js +26 -27
- package/src/App/components/Panel/Panel.module.scss +1 -0
- package/src/App/hooks/useLayoutMeasurements.js +1 -10
- package/src/App/hooks/useLayoutMeasurements.test.js +2 -5
- package/src/App/hooks/useVisibleGeometry.js +7 -13
- package/src/App/hooks/useVisibleGeometry.test.js +72 -47
- package/src/App/layout/Layout.jsx +0 -3
- package/src/App/layout/Layout.test.jsx +0 -1
- package/src/App/layout/layout.module.scss +11 -77
- package/src/App/registry/pluginRegistry.js +17 -0
- package/src/App/registry/pluginRegistry.test.js +33 -0
- package/src/App/renderer/HtmlElementHost.jsx +0 -1
- package/src/App/renderer/HtmlElementHost.test.jsx +20 -11
- package/src/App/renderer/mapButtons.js +3 -2
- package/src/App/renderer/mapPanels.test.js +3 -3
- package/src/App/renderer/slotHelpers.js +2 -2
- package/src/App/renderer/slotHelpers.test.js +3 -3
- package/src/App/renderer/slots.js +0 -3
- package/src/App/store/AppProvider.jsx +0 -1
- package/src/App/store/appDispatchMiddleware.js +33 -1
- package/src/App/store/appDispatchMiddleware.test.js +250 -222
- package/src/config/appConfig.js +4 -4
- package/src/utils/getSafeZoneInset.js +139 -42
- package/src/utils/getSafeZoneInset.test.js +298 -122
- package/src/utils/logger.js +6 -0
- package/src/utils/logger.test.js +32 -0
- package/webpack.dev.mjs +22 -18
- package/docs/govuk-prototype.md +0 -23
- package/docs/index.md +0 -19
|
@@ -7,13 +7,13 @@ import { Form } from './Form'
|
|
|
7
7
|
jest.mock('../Suggestions/Suggestions', () => ({
|
|
8
8
|
Suggestions: ({ handleSuggestionClick, id }) => (
|
|
9
9
|
<button
|
|
10
|
-
data-testid=
|
|
10
|
+
data-testid='suggestion'
|
|
11
11
|
onClick={() => handleSuggestionClick('clicked-suggestion')}
|
|
12
12
|
id={`${id}-search-suggestions`}
|
|
13
13
|
>
|
|
14
14
|
Suggestion
|
|
15
15
|
</button>
|
|
16
|
-
)
|
|
16
|
+
)
|
|
17
17
|
}))
|
|
18
18
|
|
|
19
19
|
describe('Form', () => {
|
|
@@ -28,15 +28,15 @@ describe('Form', () => {
|
|
|
28
28
|
hasFetchedSuggestions: false,
|
|
29
29
|
suggestions: [],
|
|
30
30
|
selectedIndex: -1,
|
|
31
|
-
hasKeyboardFocusWithin: false
|
|
31
|
+
hasKeyboardFocusWithin: false
|
|
32
32
|
},
|
|
33
33
|
pluginConfig: {
|
|
34
34
|
expanded: false,
|
|
35
|
-
width: '400px'
|
|
35
|
+
width: '400px'
|
|
36
36
|
},
|
|
37
37
|
appState: {
|
|
38
38
|
breakpoint: 'desktop',
|
|
39
|
-
interfaceType: 'keyboard'
|
|
39
|
+
interfaceType: 'keyboard'
|
|
40
40
|
},
|
|
41
41
|
events: {
|
|
42
42
|
handleSubmit: jest.fn(),
|
|
@@ -45,11 +45,11 @@ describe('Form', () => {
|
|
|
45
45
|
handleInputFocus: jest.fn(),
|
|
46
46
|
handleInputBlur: jest.fn(),
|
|
47
47
|
handleInputKeyDown: jest.fn(),
|
|
48
|
-
handleSuggestionClick: jest.fn()
|
|
48
|
+
handleSuggestionClick: jest.fn()
|
|
49
49
|
},
|
|
50
50
|
services: {
|
|
51
|
-
announce: jest.fn()
|
|
52
|
-
}
|
|
51
|
+
announce: jest.fn()
|
|
52
|
+
}
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
beforeEach(() => {
|
|
@@ -98,7 +98,7 @@ describe('Form', () => {
|
|
|
98
98
|
pluginState={{
|
|
99
99
|
...baseProps.pluginState,
|
|
100
100
|
suggestionsVisible: true,
|
|
101
|
-
selectedIndex: 2
|
|
101
|
+
selectedIndex: 2
|
|
102
102
|
}}
|
|
103
103
|
/>
|
|
104
104
|
)
|
|
@@ -148,7 +148,7 @@ describe('Form', () => {
|
|
|
148
148
|
it('renders children passed into the input container (e.g., CloseButton)', () => {
|
|
149
149
|
render(
|
|
150
150
|
<Form {...baseProps}>
|
|
151
|
-
<div data-testid=
|
|
151
|
+
<div data-testid='close-button' />
|
|
152
152
|
</Form>
|
|
153
153
|
)
|
|
154
154
|
expect(screen.getByTestId('close-button')).toBeInTheDocument()
|
|
@@ -252,4 +252,4 @@ describe('Form', () => {
|
|
|
252
252
|
expect(baseProps.services.announce).not.toHaveBeenCalled()
|
|
253
253
|
})
|
|
254
254
|
})
|
|
255
|
-
})
|
|
255
|
+
})
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// src/plugins/search/OpenButton.jsx
|
|
2
|
-
export const OpenButton = ({ id, isExpanded, onClick, buttonRef, searchIcon }) => {
|
|
2
|
+
export const OpenButton = ({ id, isExpanded, onClick, buttonRef, searchIcon, showLabel }) => {
|
|
3
3
|
return (
|
|
4
4
|
<button
|
|
5
|
-
aria-label=
|
|
6
|
-
className=
|
|
5
|
+
aria-label='Open search'
|
|
6
|
+
className='im-c-map-button'
|
|
7
7
|
onClick={onClick}
|
|
8
8
|
aria-controls={`${id}-search-form`}
|
|
9
9
|
ref={buttonRef}
|
|
@@ -11,20 +11,21 @@ export const OpenButton = ({ id, isExpanded, onClick, buttonRef, searchIcon }) =
|
|
|
11
11
|
>
|
|
12
12
|
{searchIcon && (
|
|
13
13
|
<svg
|
|
14
|
-
xmlns=
|
|
15
|
-
width=
|
|
16
|
-
height=
|
|
17
|
-
viewBox=
|
|
18
|
-
fill=
|
|
19
|
-
stroke=
|
|
20
|
-
strokeWidth=
|
|
21
|
-
strokeLinecap=
|
|
22
|
-
strokeLinejoin=
|
|
23
|
-
aria-hidden=
|
|
24
|
-
focusable=
|
|
14
|
+
xmlns='http://www.w3.org/2000/svg'
|
|
15
|
+
width='24'
|
|
16
|
+
height='24'
|
|
17
|
+
viewBox='0 0 24 24'
|
|
18
|
+
fill='none'
|
|
19
|
+
stroke='currentColor'
|
|
20
|
+
strokeWidth='2'
|
|
21
|
+
strokeLinecap='round'
|
|
22
|
+
strokeLinejoin='round'
|
|
23
|
+
aria-hidden='true'
|
|
24
|
+
focusable='false'
|
|
25
25
|
dangerouslySetInnerHTML={{ __html: searchIcon }}
|
|
26
|
-
|
|
26
|
+
/>
|
|
27
27
|
)}
|
|
28
|
+
{showLabel && <span>Search</span>}
|
|
28
29
|
</button>
|
|
29
30
|
)
|
|
30
31
|
}
|
|
@@ -9,7 +9,7 @@ describe('OpenButton', () => {
|
|
|
9
9
|
isExpanded: false,
|
|
10
10
|
onClick: jest.fn(),
|
|
11
11
|
buttonRef: { current: null },
|
|
12
|
-
searchIcon: null
|
|
12
|
+
searchIcon: null
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
beforeEach(() => {
|
|
@@ -44,4 +44,8 @@ describe('OpenButton', () => {
|
|
|
44
44
|
const { container } = render(<OpenButton {...baseProps} />)
|
|
45
45
|
expect(container.querySelector('svg')).toBeNull()
|
|
46
46
|
})
|
|
47
|
-
|
|
47
|
+
it('should show a label if showLabel is true', () => {
|
|
48
|
+
const { container } = render(<OpenButton {...baseProps} showLabel />)
|
|
49
|
+
expect(container.querySelector('span').innerHTML).toContain('Search')
|
|
50
|
+
})
|
|
51
|
+
})
|
|
@@ -2,26 +2,26 @@
|
|
|
2
2
|
export const SubmitButton = ({ defaultExpanded, submitIcon }) => {
|
|
3
3
|
return (
|
|
4
4
|
<button
|
|
5
|
-
aria-label=
|
|
6
|
-
className=
|
|
7
|
-
type=
|
|
5
|
+
aria-label='Search'
|
|
6
|
+
className='im-c-map-button im-c-search-submit-button'
|
|
7
|
+
type='submit'
|
|
8
8
|
style={defaultExpanded ? undefined : { display: 'none' }}
|
|
9
9
|
>
|
|
10
10
|
{submitIcon && (
|
|
11
11
|
<svg
|
|
12
|
-
xmlns=
|
|
13
|
-
width=
|
|
14
|
-
height=
|
|
15
|
-
viewBox=
|
|
16
|
-
fill=
|
|
17
|
-
stroke=
|
|
18
|
-
strokeWidth=
|
|
19
|
-
strokeLinecap=
|
|
20
|
-
strokeLinejoin=
|
|
21
|
-
aria-hidden=
|
|
22
|
-
focusable=
|
|
12
|
+
xmlns='http://www.w3.org/2000/svg'
|
|
13
|
+
width='24'
|
|
14
|
+
height='24'
|
|
15
|
+
viewBox='0 0 24 24'
|
|
16
|
+
fill='none'
|
|
17
|
+
stroke='currentColor'
|
|
18
|
+
strokeWidth='2'
|
|
19
|
+
strokeLinecap='round'
|
|
20
|
+
strokeLinejoin='round'
|
|
21
|
+
aria-hidden='true'
|
|
22
|
+
focusable='false'
|
|
23
23
|
dangerouslySetInnerHTML={{ __html: submitIcon }}
|
|
24
|
-
|
|
24
|
+
/>
|
|
25
25
|
)}
|
|
26
26
|
</button>
|
|
27
27
|
)
|
|
@@ -3,23 +3,23 @@ export const Suggestions = ({ id, pluginState, handleSuggestionClick }) => {
|
|
|
3
3
|
return (
|
|
4
4
|
<ul // NOSONAR
|
|
5
5
|
id={`${id}-search-suggestions`}
|
|
6
|
-
role=
|
|
6
|
+
role='listbox' // NOSONAR
|
|
7
7
|
aria-labelledby={`${id}-search`} // Option A: label from input
|
|
8
|
-
className=
|
|
9
|
-
style={!pluginState.areSuggestionsVisible || !pluginState.suggestions.length ? { display: 'none' } : undefined
|
|
8
|
+
className='im-c-search-suggestions'
|
|
9
|
+
style={!pluginState.areSuggestionsVisible || !pluginState.suggestions.length ? { display: 'none' } : undefined}
|
|
10
10
|
>
|
|
11
11
|
{pluginState.suggestions.map((suggestion, i) => (
|
|
12
12
|
<li // NOSONAR
|
|
13
13
|
key={suggestion.id}
|
|
14
14
|
id={`${id}-search-suggestion-${i}`}
|
|
15
|
-
className=
|
|
16
|
-
role=
|
|
15
|
+
className='im-c-search-suggestions__item'
|
|
16
|
+
role='option' // NOSONAR
|
|
17
17
|
aria-selected={pluginState.selectedIndex === i}
|
|
18
18
|
aria-setsize={pluginState.suggestions.length}
|
|
19
19
|
aria-posinset={i + 1}
|
|
20
20
|
onClick={() => handleSuggestionClick(suggestion)} // NOSONAR
|
|
21
21
|
>
|
|
22
|
-
<span className=
|
|
22
|
+
<span className='im-c-search-suggestions__label' dangerouslySetInnerHTML={{ __html: suggestion.marked }} />
|
|
23
23
|
</li>
|
|
24
24
|
))}
|
|
25
25
|
</ul>
|
|
@@ -10,11 +10,11 @@ describe('Suggestions', () => {
|
|
|
10
10
|
areSuggestionsVisible: true,
|
|
11
11
|
suggestions: [
|
|
12
12
|
{ id: '1', marked: 'First' },
|
|
13
|
-
{ id: '2', marked: 'Second' }
|
|
13
|
+
{ id: '2', marked: 'Second' }
|
|
14
14
|
],
|
|
15
|
-
selectedIndex: 0
|
|
15
|
+
selectedIndex: 0
|
|
16
16
|
},
|
|
17
|
-
handleSuggestionClick: jest.fn()
|
|
17
|
+
handleSuggestionClick: jest.fn()
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
beforeEach(() => {
|
|
@@ -76,4 +76,4 @@ describe('Suggestions', () => {
|
|
|
76
76
|
baseProps.pluginState.suggestions[1]
|
|
77
77
|
)
|
|
78
78
|
})
|
|
79
|
-
})
|
|
79
|
+
})
|
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
// src/plugins/search/datasets.js
|
|
2
2
|
import { parseOsNamesResults } from './utils/parseOsNamesResults.js'
|
|
3
3
|
|
|
4
|
-
export function createDatasets({ customDatasets = [], osNamesURL, crs, regions = ['england', 'scotland', 'wales'] }) {
|
|
4
|
+
export function createDatasets ({ customDatasets = [], osNamesURL, crs, regions = ['england', 'scotland', 'wales'] }) {
|
|
5
|
+
if (!osNamesURL) {
|
|
6
|
+
return customDatasets
|
|
7
|
+
}
|
|
5
8
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
+
const defaultDatasets = [{
|
|
10
|
+
name: 'osNames',
|
|
11
|
+
urlTemplate: osNamesURL,
|
|
12
|
+
parseResults: (json, query) => parseOsNamesResults(json, query, regions, crs),
|
|
13
|
+
includeRegex: /[a-zA-Z0-9]/,
|
|
14
|
+
excludeRegex: /^(?:[a-z]{2}\s*(?:\d{3}\s*\d{3}|\d{4}\s*\d{4}|\d{5}\s*\d{5})|\d+\s*,?\s*\d+)$/i // NOSONAR - complexity unavoidable for gridref/coordinate matching
|
|
15
|
+
}]
|
|
9
16
|
|
|
10
|
-
|
|
11
|
-
name: 'osNames',
|
|
12
|
-
urlTemplate: osNamesURL,
|
|
13
|
-
parseResults: (json, query) => parseOsNamesResults(json, query, regions, crs),
|
|
14
|
-
includeRegex: /[a-zA-Z0-9]/,
|
|
15
|
-
excludeRegex: /^(?:[a-z]{2}\s*(?:\d{3}\s*\d{3}|\d{4}\s*\d{4}|\d{5}\s*\d{5})|\d+\s*,?\s*\d+)$/i // NOSONAR - complexity unavoidable for gridref/coordinate matching
|
|
16
|
-
}]
|
|
17
|
-
|
|
18
|
-
return [...defaultDatasets, ...customDatasets]
|
|
17
|
+
return [...defaultDatasets, ...customDatasets]
|
|
19
18
|
}
|
|
@@ -26,8 +26,8 @@ const getRequestConfig = async (ds, query, transformRequest) => {
|
|
|
26
26
|
*/
|
|
27
27
|
const fetchDatasetResults = async (ds, request, query) => {
|
|
28
28
|
try {
|
|
29
|
-
const response = await fetch(request
|
|
30
|
-
|
|
29
|
+
const response = await fetch(request)
|
|
30
|
+
|
|
31
31
|
if (!response.ok) {
|
|
32
32
|
console.error(`Fetch error for ${ds.label || 'dataset'}: ${response.status}`)
|
|
33
33
|
return null
|
|
@@ -68,9 +68,9 @@ export const fetchSuggestions = async (value, datasets, dispatch, transformReque
|
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
dispatch({ type: 'UPDATE_SUGGESTIONS', payload: finalResults })
|
|
71
|
-
|
|
71
|
+
|
|
72
72
|
return {
|
|
73
73
|
results: finalResults,
|
|
74
74
|
sanitisedValue
|
|
75
75
|
}
|
|
76
|
-
}
|
|
76
|
+
}
|
|
@@ -35,7 +35,7 @@ describe('fetchSuggestions', () => {
|
|
|
35
35
|
|
|
36
36
|
const result = await fetchSuggestions('test', datasets, dispatch)
|
|
37
37
|
|
|
38
|
-
expect(fetch).toHaveBeenCalledWith('/api?q=test', { method: 'GET' })
|
|
38
|
+
expect(fetch).toHaveBeenCalledWith({ url: '/api?q=test', options: { method: 'GET' } })
|
|
39
39
|
expect(result.results).toEqual(['a', 'b'])
|
|
40
40
|
expect(dispatch).toHaveBeenCalledWith({
|
|
41
41
|
type: 'UPDATE_SUGGESTIONS',
|
|
@@ -77,7 +77,7 @@ describe('fetchSuggestions', () => {
|
|
|
77
77
|
|
|
78
78
|
const result = await fetchSuggestions('abc', datasets, dispatch)
|
|
79
79
|
|
|
80
|
-
expect(fetch).toHaveBeenCalledWith('/custom/abc', { method: 'POST' })
|
|
80
|
+
expect(fetch).toHaveBeenCalledWith({ url: '/custom/abc', options: { method: 'POST' } })
|
|
81
81
|
expect(result.results).toEqual(['y'])
|
|
82
82
|
})
|
|
83
83
|
|
|
@@ -101,7 +101,7 @@ describe('fetchSuggestions', () => {
|
|
|
101
101
|
|
|
102
102
|
await fetchSuggestions('x', datasets, dispatch, transformRequest)
|
|
103
103
|
|
|
104
|
-
expect(fetch).toHaveBeenCalledWith('/t?q=x', { method: 'PUT' })
|
|
104
|
+
expect(fetch).toHaveBeenCalledWith({ url: '/t?q=x', options: { method: 'PUT' } })
|
|
105
105
|
})
|
|
106
106
|
|
|
107
107
|
test('handles fetch HTTP error', async () => {
|
|
@@ -206,7 +206,7 @@ describe('fetchSuggestions', () => {
|
|
|
206
206
|
|
|
207
207
|
const result = await fetchSuggestions('hi', datasets, dispatch)
|
|
208
208
|
|
|
209
|
-
expect(fetch).toHaveBeenCalledWith('/default?q=hi', { method: 'GET' })
|
|
209
|
+
expect(fetch).toHaveBeenCalledWith({ url: '/default?q=hi', options: { method: 'GET' } })
|
|
210
210
|
expect(result.results).toEqual(['ok'])
|
|
211
211
|
})
|
|
212
|
-
})
|
|
212
|
+
})
|
|
@@ -16,12 +16,12 @@ export const createFormHandlers = ({
|
|
|
16
16
|
let lastFetchedValue = ''
|
|
17
17
|
|
|
18
18
|
return {
|
|
19
|
-
handleOpenClick() {
|
|
19
|
+
handleOpenClick () {
|
|
20
20
|
dispatch({ type: 'TOGGLE_EXPANDED', payload: true })
|
|
21
21
|
services.eventBus.emit('search:open')
|
|
22
22
|
},
|
|
23
23
|
|
|
24
|
-
handleCloseClick(_e, buttonRef) {
|
|
24
|
+
handleCloseClick (_e, buttonRef) {
|
|
25
25
|
dispatch({ type: 'TOGGLE_EXPANDED', payload: false })
|
|
26
26
|
dispatch({ type: 'UPDATE_SUGGESTIONS', payload: [] })
|
|
27
27
|
dispatch({ type: 'SET_VALUE', payload: '' })
|
|
@@ -31,7 +31,7 @@ export const createFormHandlers = ({
|
|
|
31
31
|
services.eventBus.emit('search:close')
|
|
32
32
|
},
|
|
33
33
|
|
|
34
|
-
async handleSubmit(e, appState, pluginState) {
|
|
34
|
+
async handleSubmit (e, appState, pluginState) {
|
|
35
35
|
e.preventDefault()
|
|
36
36
|
const { suggestions, selectedIndex, value } = pluginState
|
|
37
37
|
const trimmedValue = value?.trim()
|
|
@@ -6,7 +6,7 @@ import { createSuggestionHandlers } from './suggestionHandlers.js'
|
|
|
6
6
|
|
|
7
7
|
const DEBOUNCE_FETCH_TIME = 350
|
|
8
8
|
|
|
9
|
-
export function attachEvents(args) {
|
|
9
|
+
export function attachEvents (args) {
|
|
10
10
|
const { dispatch, searchContainerRef } = args
|
|
11
11
|
|
|
12
12
|
// Debounce data fetching
|
|
@@ -26,7 +26,7 @@ export function attachEvents(args) {
|
|
|
26
26
|
...inputHandlers,
|
|
27
27
|
...suggestionHandlers,
|
|
28
28
|
|
|
29
|
-
handleOutside(e) {
|
|
29
|
+
handleOutside (e) {
|
|
30
30
|
if (searchContainerRef.current.contains(e.target)) {
|
|
31
31
|
return
|
|
32
32
|
}
|
|
@@ -69,7 +69,7 @@ describe('attachEvents', () => {
|
|
|
69
69
|
})
|
|
70
70
|
|
|
71
71
|
test('debouncedFetchSuggestions calls fetchSuggestions with correct args', () => {
|
|
72
|
-
|
|
72
|
+
attachEvents(args)
|
|
73
73
|
|
|
74
74
|
// grab the debounced function passed to input handlers
|
|
75
75
|
const { debouncedFetchSuggestions } =
|
|
@@ -115,4 +115,4 @@ describe('attachEvents', () => {
|
|
|
115
115
|
|
|
116
116
|
expect(services.eventBus.emit).toHaveBeenCalledWith('search:close')
|
|
117
117
|
})
|
|
118
|
-
})
|
|
118
|
+
})
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import { DEFAULTS } from '../defaults.js'
|
|
2
2
|
|
|
3
3
|
export const createInputHandlers = ({ dispatch, debouncedFetchSuggestions }) => ({
|
|
4
|
-
handleInputClick() {
|
|
4
|
+
handleInputClick () {
|
|
5
5
|
dispatch({ type: 'SHOW_SUGGESTIONS' })
|
|
6
6
|
},
|
|
7
7
|
|
|
8
|
-
handleInputFocus(interfaceType) {
|
|
8
|
+
handleInputFocus (interfaceType) {
|
|
9
9
|
dispatch({ type: 'SET_KEYBOARD_FOCUS_WITHIN', payload: interfaceType === 'keyboard' })
|
|
10
10
|
},
|
|
11
11
|
|
|
12
|
-
handleInputBlur(interfaceType) {
|
|
12
|
+
handleInputBlur (interfaceType) {
|
|
13
13
|
dispatch({ type: 'INPUT_BLUR', payload: interfaceType })
|
|
14
14
|
},
|
|
15
15
|
|
|
16
|
-
handleInputChange(e) {
|
|
16
|
+
handleInputChange (e) {
|
|
17
17
|
const value = e.target.value
|
|
18
18
|
dispatch({ type: 'SET_VALUE', payload: value })
|
|
19
19
|
|
|
@@ -7,7 +7,7 @@ export const createSuggestionHandlers = ({ dispatch, services, mapProvider, mark
|
|
|
7
7
|
: `${suggestions.length} suggestions available`
|
|
8
8
|
|
|
9
9
|
return {
|
|
10
|
-
handleSuggestionClick(suggestion, appState) {
|
|
10
|
+
handleSuggestionClick (suggestion, appState) {
|
|
11
11
|
dispatch({ type: 'SET_VALUE', payload: suggestion.text })
|
|
12
12
|
dispatch({ type: 'HIDE_SUGGESTIONS' })
|
|
13
13
|
dispatch({ type: 'SET_SELECTED', payload: -1 })
|
|
@@ -21,7 +21,7 @@ export const createSuggestionHandlers = ({ dispatch, services, mapProvider, mark
|
|
|
21
21
|
services.eventBus.emit('search:match', { query: suggestion.text, ...suggestion })
|
|
22
22
|
},
|
|
23
23
|
|
|
24
|
-
handleInputKeyDown(e, pluginState) {
|
|
24
|
+
handleInputKeyDown (e, pluginState) {
|
|
25
25
|
const { suggestions, selectedIndex } = pluginState
|
|
26
26
|
|
|
27
27
|
switch (e.key) {
|
|
@@ -4,11 +4,12 @@ import './search.scss'
|
|
|
4
4
|
export default function createPlugin (options = {}) {
|
|
5
5
|
// If search is open then we need to overirde the mobile slot
|
|
6
6
|
if (options.expanded) {
|
|
7
|
-
options.manifest = {controls: [{ id: 'search', mobile: { slot: 'banner' }}]}
|
|
7
|
+
options.manifest = { controls: [{ id: 'search', mobile: { slot: 'banner' } }] }
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
return {
|
|
11
11
|
showMarker: true,
|
|
12
|
+
placeholder: 'Search',
|
|
12
13
|
...options,
|
|
13
14
|
id: 'search',
|
|
14
15
|
load: async () => {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// /plugins/search/index.test.js
|
|
2
2
|
|
|
3
3
|
// Mock SCSS import so Jest can run without parsing errors
|
|
4
|
-
jest.mock('./search.scss', () => {})
|
|
5
|
-
|
|
6
4
|
import createPlugin from './index'
|
|
7
5
|
|
|
6
|
+
jest.mock('./search.scss', () => {})
|
|
7
|
+
|
|
8
8
|
describe('createPlugin', () => {
|
|
9
9
|
beforeEach(() => {
|
|
10
10
|
jest.resetModules()
|
|
@@ -44,4 +44,4 @@ describe('createPlugin', () => {
|
|
|
44
44
|
const result = await plugin.load()
|
|
45
45
|
expect(result).toEqual(manifestMock)
|
|
46
46
|
})
|
|
47
|
-
})
|
|
47
|
+
})
|
|
@@ -10,15 +10,17 @@ export const manifest = {
|
|
|
10
10
|
|
|
11
11
|
controls: [{
|
|
12
12
|
id: 'search',
|
|
13
|
-
label: 'Search',
|
|
14
13
|
mobile: {
|
|
15
|
-
slot: 'top-right'
|
|
14
|
+
slot: 'top-right',
|
|
15
|
+
showLabel: false
|
|
16
16
|
},
|
|
17
17
|
tablet: {
|
|
18
|
-
slot: 'top-left'
|
|
18
|
+
slot: 'top-left',
|
|
19
|
+
showLabel: false
|
|
19
20
|
},
|
|
20
21
|
desktop: {
|
|
21
|
-
slot: 'top-left'
|
|
22
|
+
slot: 'top-left',
|
|
23
|
+
showLabel: false
|
|
22
24
|
},
|
|
23
25
|
render: Search
|
|
24
26
|
}],
|
|
@@ -8,7 +8,6 @@ const initialState = {
|
|
|
8
8
|
selectedIndex: -1
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
|
|
12
11
|
const toggleExpanded = (state, payload) => {
|
|
13
12
|
return {
|
|
14
13
|
...state,
|
|
@@ -31,7 +30,7 @@ const inputBlur = (state, payload) => {
|
|
|
31
30
|
...state,
|
|
32
31
|
hasKeyboardFocusWithin: false,
|
|
33
32
|
areSuggestionsVisible: state.areSuggestionsVisible && payload !== 'keyboard',
|
|
34
|
-
selectedIndex: -1
|
|
33
|
+
selectedIndex: -1
|
|
35
34
|
}
|
|
36
35
|
}
|
|
37
36
|
|
|
@@ -73,7 +73,7 @@ describe('search state actions', () => {
|
|
|
73
73
|
|
|
74
74
|
it('SET_SELECTED updates selectedIndex and visibility', () => {
|
|
75
75
|
const state = { ...initialState, areSuggestionsVisible: false }
|
|
76
|
-
|
|
76
|
+
|
|
77
77
|
const selected = actions.SET_SELECTED(state, 1)
|
|
78
78
|
expect(selected.selectedIndex).toBe(1)
|
|
79
79
|
expect(selected.areSuggestionsVisible).toBe(true)
|
|
@@ -82,4 +82,4 @@ describe('search state actions', () => {
|
|
|
82
82
|
expect(deselected.selectedIndex).toBe(-1)
|
|
83
83
|
expect(deselected.areSuggestionsVisible).toBe(false)
|
|
84
84
|
})
|
|
85
|
-
})
|
|
85
|
+
})
|
|
@@ -50,14 +50,21 @@
|
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
// Input reset (extra specificity to reset govuk)
|
|
54
|
+
.im-o-app .im-c-search__input {
|
|
54
55
|
width: 100%;
|
|
55
|
-
border: 0;
|
|
56
|
-
padding: var(--divider-gap) calc(var(--divider-gap) + 2px);
|
|
57
56
|
color: var(--foreground-color);
|
|
58
57
|
background-color: transparent;
|
|
58
|
+
font-size: 1rem;
|
|
59
|
+
border: 0;
|
|
60
|
+
padding: var(--divider-gap) calc(var(--divider-gap) + 2px);
|
|
59
61
|
outline: 0;
|
|
60
62
|
|
|
63
|
+
&:focus {
|
|
64
|
+
outline: 3px solid transparent;
|
|
65
|
+
box-shadow: none;
|
|
66
|
+
}
|
|
67
|
+
|
|
61
68
|
&::placeholder {
|
|
62
69
|
color: var(--foreground-color);
|
|
63
70
|
}
|
|
@@ -84,9 +91,14 @@
|
|
|
84
91
|
opacity: 0;
|
|
85
92
|
z-index: -1;
|
|
86
93
|
}
|
|
87
|
-
.im-o-
|
|
88
|
-
|
|
89
|
-
|
|
94
|
+
.im-o-app__left-top,
|
|
95
|
+
.im-o-app__left-bottom,
|
|
96
|
+
.im-o-app__right-top,
|
|
97
|
+
.im-o-app__right-bottom {
|
|
98
|
+
.im-c-panel {
|
|
99
|
+
opacity: 0;
|
|
100
|
+
z-index: -1;
|
|
101
|
+
}
|
|
90
102
|
}
|
|
91
103
|
}
|
|
92
104
|
|
|
@@ -6,7 +6,7 @@ const MAX_RESULTS = 8
|
|
|
6
6
|
|
|
7
7
|
const isPostcode = (value) => {
|
|
8
8
|
value = value.replace(/\s/g, '')
|
|
9
|
-
const regex = /^(([A-Z]{1,2}\d[A-Z\d]?|ASCN|STHL|TDCU|BBND|[BFS]IQQ|PCRN|TKCA) ?\d[A-Z]{2}|BFPO ?\d{1,4}|(KY\d|MSR|VG|AI)[ -]?\d{4}|[A-Z]{2} ?\d{2}|GE ?CX|GIR ?0A{2}|SAN ?TA1)$/i //NOSONAR
|
|
9
|
+
const regex = /^(([A-Z]{1,2}\d[A-Z\d]?|ASCN|STHL|TDCU|BBND|[BFS]IQQ|PCRN|TKCA) ?\d[A-Z]{2}|BFPO ?\d{1,4}|(KY\d|MSR|VG|AI)[ -]?\d{4}|[A-Z]{2} ?\d{2}|GE ?CX|GIR ?0A{2}|SAN ?TA1)$/i // NOSONAR
|
|
10
10
|
return regex.test(value)
|
|
11
11
|
}
|
|
12
12
|
|
|
@@ -77,7 +77,6 @@ const bounds = (crs, { MBR_XMIN, MBR_YMIN, MBR_XMAX, MBR_YMAX, GEOMETRY_X, GEOME
|
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
const point = (crs, { GEOMETRY_X, GEOMETRY_Y }) => {
|
|
80
|
-
|
|
81
80
|
// EPSG:27700 → return raw OSGB grid coordinates (meters)
|
|
82
81
|
if (crs === 'EPSG:27700') {
|
|
83
82
|
return [GEOMETRY_X, GEOMETRY_Y]
|
|
@@ -134,13 +134,13 @@ describe('osNamesUtils', () => {
|
|
|
134
134
|
*/
|
|
135
135
|
|
|
136
136
|
test('uses NAME2 when NAME2_LANG is eng', () => {
|
|
137
|
-
const entry = { GAZETTEER_ENTRY: { ...sampleEntry.GAZETTEER_ENTRY, NAME1: 'Caerdydd', NAME2: 'Cardiff', NAME2_LANG: 'eng' }}
|
|
137
|
+
const entry = { GAZETTEER_ENTRY: { ...sampleEntry.GAZETTEER_ENTRY, NAME1: 'Caerdydd', NAME2: 'Cardiff', NAME2_LANG: 'eng' } }
|
|
138
138
|
const output = parseOsNamesResults({ results: [entry] }, 'Cardiff', regions, 'EPSG:27700')
|
|
139
139
|
expect(output[0].text).toContain('Cardiff')
|
|
140
140
|
})
|
|
141
141
|
|
|
142
142
|
test('falls back to NAME1 when NAME2_LANG is not eng', () => {
|
|
143
|
-
const entry = { GAZETTEER_ENTRY: { ...sampleEntry.GAZETTEER_ENTRY, NAME1: 'London', NAME2: 'Londres', NAME2_LANG: 'fra' }}
|
|
143
|
+
const entry = { GAZETTEER_ENTRY: { ...sampleEntry.GAZETTEER_ENTRY, NAME1: 'London', NAME2: 'Londres', NAME2_LANG: 'fra' } }
|
|
144
144
|
const output = parseOsNamesResults({ results: [entry] }, 'London', regions, 'EPSG:27700')
|
|
145
145
|
expect(output[0].text).toContain('London')
|
|
146
146
|
})
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* @param {boolean} showMarker - Whether to display a marker
|
|
11
11
|
* @param {boolean} showMarker - Marker colour
|
|
12
12
|
*/
|
|
13
|
-
export function updateMap({ mapProvider, bounds, point, markers, showMarker, markerColor }) {
|
|
13
|
+
export function updateMap ({ mapProvider, bounds, point, markers, showMarker, markerColor }) {
|
|
14
14
|
mapProvider.fitToBounds(bounds)
|
|
15
15
|
if (showMarker) {
|
|
16
16
|
markers.add('search', point, { color: markerColor })
|