diff --git a/dataweaver/apps/web/src/components/primitives/icons/redo.tsx b/dataweaver/apps/web/src/components/primitives/icons/redo.tsx
new file mode 100644
index 00000000..29242b5e
--- /dev/null
+++ b/dataweaver/apps/web/src/components/primitives/icons/redo.tsx
@@ -0,0 +1,18 @@
+import type { ComponentPropsWithRef } from 'react';
+
+export const IconRedo = (props: ComponentPropsWithRef<'svg'>) => {
+ return (
+
+ );
+};
diff --git a/dataweaver/apps/web/src/components/primitives/icons/undo.tsx b/dataweaver/apps/web/src/components/primitives/icons/undo.tsx
new file mode 100644
index 00000000..54ddbf96
--- /dev/null
+++ b/dataweaver/apps/web/src/components/primitives/icons/undo.tsx
@@ -0,0 +1,18 @@
+import type { ComponentPropsWithRef } from 'react';
+
+export const IconUndo = (props: ComponentPropsWithRef<'svg'>) => {
+ return (
+
+ );
+};
diff --git a/dataweaver/apps/web/src/components/scopes/atlas/components/in_front_of_canvas/controls.tsx b/dataweaver/apps/web/src/components/scopes/atlas/components/in_front_of_canvas/controls.tsx
index 3ecb8617..8ef07239 100644
--- a/dataweaver/apps/web/src/components/scopes/atlas/components/in_front_of_canvas/controls.tsx
+++ b/dataweaver/apps/web/src/components/scopes/atlas/components/in_front_of_canvas/controls.tsx
@@ -1,14 +1,16 @@
import s from './controls.module.scss';
import { Export } from './export/export';
+import { History } from './history';
import { Zoom } from './zoom/zoom';
/**
* Editor-bound controls rendered through tldraw's `InFrontOfTheCanvas` slot:
- * the zoom menu and the export menu, each owning its own trigger + popover.
+ * the undo / redo history control, the zoom menu and the export menu.
*/
export const Controls = () => {
return (
+
diff --git a/dataweaver/apps/web/src/components/scopes/atlas/components/in_front_of_canvas/history.module.scss b/dataweaver/apps/web/src/components/scopes/atlas/components/in_front_of_canvas/history.module.scss
new file mode 100644
index 00000000..8c14ae83
--- /dev/null
+++ b/dataweaver/apps/web/src/components/scopes/atlas/components/in_front_of_canvas/history.module.scss
@@ -0,0 +1,19 @@
+.container {
+ display: flex;
+ column-gap: 10px;
+ align-items: center;
+ justify-content: space-between;
+ height: var(--controls-height);
+ padding: 0
+ calc((var(--controls-height) - var(--button-circle-size-medium)) / 2);
+ color: rgb(var(--color-control-accent));
+ background: rgb(var(--color-control-surface));
+ border-radius: calc(var(--controls-height) / 2);
+ box-shadow: var(--shadow-elevated);
+
+ .divider {
+ width: 1px;
+ height: 30px;
+ background: rgb(var(--color-control-divider));
+ }
+}
diff --git a/dataweaver/apps/web/src/components/scopes/atlas/components/in_front_of_canvas/history.tsx b/dataweaver/apps/web/src/components/scopes/atlas/components/in_front_of_canvas/history.tsx
new file mode 100644
index 00000000..a3f32b95
--- /dev/null
+++ b/dataweaver/apps/web/src/components/scopes/atlas/components/in_front_of_canvas/history.tsx
@@ -0,0 +1,39 @@
+import { useEditor, useValue } from 'tldraw';
+import { Button } from '~/components/elements/button';
+import { IconRedo } from '~/components/primitives/icons/redo';
+import { IconUndo } from '~/components/primitives/icons/undo';
+import s from './history.module.scss';
+
+/** Editor-bound undo / redo control. */
+export const History = () => {
+ const editor = useEditor();
+
+ const canUndo = useValue('canUndo', () => editor.getCanUndo(), [editor]);
+ const canRedo = useValue('canRedo', () => editor.getCanRedo(), [editor]);
+
+ return (
+
+
+ );
+};
diff --git a/dataweaver/packages/tokens/src/colors.json b/dataweaver/packages/tokens/src/colors.json
index ef459ce5..ffe26c86 100644
--- a/dataweaver/packages/tokens/src/colors.json
+++ b/dataweaver/packages/tokens/src/colors.json
@@ -71,6 +71,7 @@
"control-accent-subtle": "$accent-subtle",
"control-content": "$content",
"control-content-muted": "$content-muted",
+ "control-divider": [22, 23, 24, 0.15],
"card-surface": "$surface-raised",
"card-surface-selected": "$accent",