Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion demo/draw-ol.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Draw tools demo (OpenLayers)</title>
<link href="/assets/govuk-frontend.min.css" rel="stylesheet" media="all">
<link href="./index.css" rel="stylesheet" media="all">
<link href="./draw-ol.css" rel="stylesheet" media="all">
</head>
<body style="padding: 20px">
<script>document.body.classList.add('im-is-loading')</script>
Expand Down
8 changes: 7 additions & 1 deletion demo/draw.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>React TypeScript Webpack App</title>
<link href="/assets/govuk-frontend.min.css" rel="stylesheet" media="all">
<link href="./index.css" rel="stylesheet" media="all">
<link href="./draw.css" rel="stylesheet" media="all">
<style>
:root {
--button-border-radius: 4px;
--panel-border-radius: 6px;
}
</style>
</head>
<body style="padding: 20px">
<script>document.body.classList.add('im-is-loading')</script>
Expand Down
6 changes: 6 additions & 0 deletions demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@
<title>React TypeScript Webpack App</title>
<link href="/assets/govuk-frontend.min.css" rel="stylesheet" media="all">
<link href="./index.css" rel="stylesheet" media="all">
<style>
:root {
--button-border-radius: 4px;
--panel-border-radius: 6px;
}
</style>
</head>
<body style="padding: 20px">
<script>document.body.classList.add('im-is-loading')</script>
Expand Down
5 changes: 1 addition & 4 deletions demo/js/draw.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,7 @@ const drawPlugin = createDrawPlugin({
onGeometryChange: (event) => ({
valid: isEastOfWalesBorder(event.feature.geometry),
reason: 'Points must be placed east of the England/Wales border'
}),
manifest: {
buttons: [{ id: 'drawMenu', mobile: { slot: 'bottom-right' }}]
}
})
})

const datasetsPlugin = createDatasetsPlugin({
Expand Down
6 changes: 1 addition & 5 deletions demo/js/esm.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,7 @@ const interactPlugin = createInteractPlugin({

const framePlugin = createFramePlugin({ aspectRatio: 1.5 })

const drawPlugin = createDrawPlugin({
manifest: {
buttons: [{ id: 'drawMenu', mobile: { slot: 'bottom-right' } }]
}
})
const drawPlugin = createDrawPlugin()

const landCoversDataset = {
id: 'land-covers',
Expand Down
4 changes: 1 addition & 3 deletions demo/js/farming.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@ var interactPlugin = createInteractPlugin({
// idProperty: 'gid'
}],
interactionModes: ['selectMarker', 'selectFeature', 'placeMarker'], // e.g. ['selectMarker'], ['selectFeature'], ['placeMarker'], or combinations
multiSelect: true,
// excludeModes: ['draw']
multiSelect: true
})

var datasetsPlugin = createDatasetsPlugin({
Expand Down Expand Up @@ -131,7 +130,6 @@ var interactiveMap = new InteractiveMap('map', {
})

interactiveMap.on('map:ready', function (e) {
// interactiveMap.setMode('draw')
// framePlugin.addFrame('test', {
// aspectRatio: 1
// })
Expand Down
97 changes: 72 additions & 25 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,40 @@ Uses a dark colour scheme. |

---

### `applicationModes`
**Type:** `Object<string, { include?: string[], exclude?: string[] } | false>`

Adjusts plugins' [application modes](#setapplicationmodeid-options), or defines your own, keyed by mode id. Plugins document the modes they set — for example the [draw plugin](./plugins/draw.md#application-mode) sets `'draw'` while drawing or editing. Your settings apply whenever that mode is current, whoever sets it.

Each mode's value is either:

- **an object**, with either or both of:
- `include` — for a plugin's mode, adds items to what it shows (including any a plugin excluded). For your own mode, makes it take over the interface: only these items stay visible.
- `exclude` — hides items.
- **`false`** — turns the mode off entirely, so it adds no class and hides nothing.

Ids name buttons, panels and controls, and don't need to exist yet — an item you add later with [`addControl`](#addcontrolid-config) or similar is picked up when it appears.

```js
new InteractiveMap('map', {
applicationModes: {
draw: { include: ['search', 'shapeDimensions'], exclude: ['scaleBar'] }
}
})
```

Or, when every item on your map is deliberate (e.g. a single-task map that goes straight into editing a shape), turn a mode off so it hides nothing and adds no class:

```js
new InteractiveMap('map', {
applicationModes: {
draw: false
}
})
```

---

### `autoColorScheme`
**Type:** `boolean`
**Default:** `false`
Expand Down Expand Up @@ -430,16 +464,6 @@ Passed directly to the underlying map engine.

---

### `mode`
**Type:** `string | null`
**Default:** `null`

Initial application mode. Modes facilitate attaching behaviour to certain states, enabling short user journey steps within the map interface. Plugins can be configured to respect modes, only rendering content when the app is in a specific mode.

See also: [`setMode()`](#setmodemode) method.

---

### `nudgePanDelta`
**Type:** `number`
**Default:** `5`
Expand Down Expand Up @@ -779,13 +803,50 @@ interactiveMap.hidePanel('info-panel')

---

### `setApplicationMode(id, options?)`

Enters an application mode — for example for a step in a journey that needs a pared-down interface. Modes form a stack: the new mode goes on top, and setting a mode that's already on the stack replaces its lists and moves it to the top. Only the current mode, the top of the stack, applies: the app root gets the class `im-o-app--mode-{id}`, and modes underneath wait until they're current again. Hidden items stay mounted, so their state is preserved, and modal panels are never hidden.

Plugins set modes too (e.g. the [draw plugin](./plugins/draw.md#application-mode) sets `'draw'`). Define your own mode's lists in the [`applicationModes`](#applicationmodes) option and call `setApplicationMode(id)`, or pass them here. Options passed here are applied last, after the plugins' manifests and your `applicationModes` option.

| Parameter | Type | Description |
|-----------|------|-------------|
| `id` | `string` | Mode id, used as-is in the class, so keep it class-safe |
| `options.include` | `string[]` | Buttons, panels and controls to keep visible. If nothing else defines the mode, only these stay visible |
| `options.exclude` | `string[]` | Buttons, panels and controls to hide |

Without any lists, nothing is hidden and only the class is added.

```js
// Only the map styles button and panel, and your own button, stay visible
interactiveMap.setApplicationMode('review', { include: ['mapStyles', 'myButton'] })

// Later, bring everything back
interactiveMap.clearApplicationMode('review')
```

> [!NOTE]
> Don't set or clear a plugin's mode id yourself (e.g. `'draw'`): it only changes the interface, so clearing it mid-draw would show everything again while drawing carries on. To adjust or disable a plugin's mode, use [`applicationModes`](#applicationmodes) instead.

---

### `clearApplicationMode(id)`

Leaves an application mode, removing it from the stack so the mode underneath (if any) takes over.

| Parameter | Type | Description |
|-----------|------|-------------|
| `id` | `string` | Mode id |

---

### `addControl(id, config)`

Add a custom control to the UI at runtime.

| Parameter | Type | Description |
|-----------|------|-------------|
| `id` | `string` | Unique control identifier |
| `id` | `string` | Unique control identifier. Also the id to list in an application mode's `include`/`exclude`, e.g. in [`applicationModes`](#applicationmodes) |
| `config` | `ControlDefinition` | Control configuration |

See [ControlDefinition](./api/control-definition.md) for configuration options.
Expand Down Expand Up @@ -849,20 +910,6 @@ interactiveMap.on('draw:unmerged', () => {

---

### `setMode(mode)`

Programmatically set the application mode. See the [`mode`](#mode) option for more detail.

| Parameter | Type | Description |
|-----------|------|-------------|
| `mode` | `string` | Mode identifier |

```js
interactiveMap.setMode('fullscreen')
```

---

### `toggleButtonState(id, prop, value)`

Set or toggle a button state. Where applicable the corresponding ARIA attribute is updated — `aria-pressed`, `aria-disabled`, or `aria-expanded`.
Expand Down
2 changes: 1 addition & 1 deletion docs/api/button-definition.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Defines a button that can be rendered in the UI at various breakpoints.
**Type:** `string`
**Required**

Unique button identifier.
Unique button identifier. It's also the id to list in an application mode's `include` or `exclude`, e.g. in the [`applicationModes`](../api.md#applicationmodes) option.

---

Expand Down
2 changes: 2 additions & 0 deletions docs/api/control-definition.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ const MyControl = ({ context }) => {
}
```

Core renders the component inside a wrapper element, `<div class="im-c-control-wrapper im-c-control-wrapper--{id}">` (the id kebab-cased), as it does for buttons (`im-c-button-wrapper--{id}`). The wrapper is `display: contents`, so it doesn't affect layout, but your control isn't a direct child of its slot, so write CSS selectors with that in mind.

---

### `mobile`
Expand Down
16 changes: 0 additions & 16 deletions docs/plugins/datasets.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,22 +92,6 @@ Array of dataset configurations to render on the map. See [Dataset configuration

---

### `includeModes`

**Type:** `string[]`

When set, the plugin only initialises when the app is in one of the specified modes.

---

### `excludeModes`

**Type:** `string[]`

When set, the plugin does not initialise when the app is in one of the specified modes.

---

## Dataset configuration

Each entry in the `datasets` array describes one data source and how it should be rendered.
Expand Down
45 changes: 27 additions & 18 deletions docs/plugins/draw.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ Vector tile source-layer names to snap new and edited vertices against. Can be o

The layer names available depend entirely on your basemap style — there's no universal default, so check your style's vector tile source(s) for the source-layer names to use. The example below (`'OS/TopographicArea_1/Agricultural Land'`) is specific to an Ordnance Survey basemap style.

When set (globally or per call), a "Snap to feature" toggle appears in the draw menu, letting the user turn snapping on and off during a session.
When set (globally or per call), a "Snap" toggle button appears in the top row, letting the user turn snapping on and off during a session.

```js
createDrawPlugin({
Expand All @@ -79,22 +79,6 @@ Plugin-level validation callback, called throughout the draw/edit lifecycle so y

---

### `includeModes`

**Type:** `string[]`

When set, the plugin only initialises when the app is in one of the specified modes.

---

### `excludeModes`

**Type:** `string[]`

When set, the plugin does not initialise when the app is in one of the specified modes.

---

### Colour and size overrides

> [!NOTE]
Expand Down Expand Up @@ -397,9 +381,34 @@ interactiveMap.on('draw:merge', (e) => {
})
```

## Application mode

While drawing or editing, the plugin sets the `'draw'` [application mode](../api.md#setapplicationmodeid-options), which gives the interface over to drawing: every button, panel and control, in every slot, is hidden except draw's own and these defaults:

```js
['mapStyles', 'mapControls', 'scaleBar']
```

Everything reappears as it was when the draw or edit mode ends. Hidden items stay mounted, so open panels keep their state and scroll position, and modal panels are never hidden. The app root also gets the class `im-o-app--mode-draw`.

Adjust it with the [`applicationModes`](../api.md#applicationmodes) option, keyed by the mode id. For example, to also keep search and a control of your own, and hide the scale bar:

```js
new InteractiveMap('map', {
applicationModes: {
draw: { include: ['search', 'myControl'], exclude: ['scaleBar'] }
}
})
```

Or set `draw: false` when every button on the map is deliberate — for example a single-task map that goes straight into editing a shape — so nothing is hidden.

> [!NOTE]
> The mode only changes the interface. Other plugins' own behaviour keeps running while their buttons are hidden, so disable any that shouldn't respond while drawing — for example, call `interactPlugin.disable()` on [`draw:started`](#drawstarted) and [`draw:editstart`](#draweditstart), and `interactPlugin.enable()` on [`draw:created`](#drawcreated), [`draw:edited`](#drawedited) and [`draw:cancelled`](#drawcancelled).

## Buttons and keyboard shortcuts

The plugin registers its own toolbar buttons automatically — Cancel, Add point (touch only), Done, and a Draw actions menu (Undo, Snap to feature, Delete point) — which show and enable themselves based on the current draw/edit state. You don't need to render these yourself; augment them with your own trigger buttons (e.g. "Draw polygon", "Draw line") the way the [Draw tools example](../examples/draw-tools.mdx) does.
The plugin registers its own toolbar buttons automatically — Cancel, Add point (touch only) and Done in the actions bar, plus Undo, Snap and Delete point in the middle of the top row — which show and enable themselves based on the current draw/edit state. You don't need to render these yourself; augment them with your own trigger buttons (e.g. "Draw polygon", "Draw line") the way the [Draw tools example](../examples/draw-tools.mdx) does.

| Shortcut | Action |
|----------|--------|
Expand Down
14 changes: 0 additions & 14 deletions docs/plugins/interact.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,6 @@ Options are passed to the factory function when creating the plugin.

---

### `includeModes`
**Type:** `string[]`

Array of mode identifiers. When set, the plugin only renders when the app is in one of these modes.

---

### `excludeModes`
**Type:** `string[]`

Array of mode identifiers. When set, the plugin does not render when the app is in one of these modes.

---

### `interactionModes`
**Type:** `Array<'selectMarker' | 'selectFeature' | 'placeMarker'>`
**Default:** `['selectMarker']`
Expand Down
16 changes: 0 additions & 16 deletions docs/plugins/map-key.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,22 +99,6 @@ createMapKeyPlugin({ noKeyItemText: 'No layers to show' })

---

### `includeModes`

**Type:** `string[]`

When set, the plugin only initialises when the app is in one of the specified modes.

---

### `excludeModes`

**Type:** `string[]`

When set, the plugin does not initialise when the app is in one of the specified modes.

---

## Key display properties

These properties control how an entry looks in the key panel — they have no effect on how a feature renders on the map itself. Today the only way to set them is via a dataset's [`style`](./datasets.md#style) object, since Datasets is the only plugin feeding this key panel.
Expand Down
14 changes: 0 additions & 14 deletions docs/plugins/map-styles.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,20 +70,6 @@ createMapStylesPlugin({

---

### `includeModes`
**Type:** `string[]`

Array of mode identifiers. When set, the plugin only renders when the app is in one of these modes.

---

### `excludeModes`
**Type:** `string[]`

Array of mode identifiers. When set, the plugin does not render when the app is in one of these modes.

---

## Map size

When the active map provider supports map sizes (i.e. `mapProvider.capabilities.supportsMapSizes` is `true`), the panel also shows a map size control. This lets users choose between three size levels:
Expand Down
Loading
Loading