diff --git a/x-pack/legacy/plugins/canvas/common/lib/constants.ts b/x-pack/legacy/plugins/canvas/common/lib/constants.ts
index 3f5efd70bd4d6..83d53123ddde5 100644
--- a/x-pack/legacy/plugins/canvas/common/lib/constants.ts
+++ b/x-pack/legacy/plugins/canvas/common/lib/constants.ts
@@ -25,3 +25,5 @@ export const DEFAULT_WORKPAD_CSS = '.canvasPage {\n\n}';
export const DEFAULT_ELEMENT_CSS = '.canvasRenderEl{\n\n}';
export const VALID_IMAGE_TYPES = ['gif', 'jpeg', 'png', 'svg+xml'];
export const ASSET_MAX_SIZE = 25000;
+export const ELEMENT_SHIFT_OFFSET = 10;
+export const ELEMENT_NUDGE_OFFSET = 1;
diff --git a/x-pack/legacy/plugins/canvas/public/components/keyboard_shortcuts_doc/__examples__/__snapshots__/keyboard_shortcuts_doc.examples.storyshot b/x-pack/legacy/plugins/canvas/public/components/keyboard_shortcuts_doc/__examples__/__snapshots__/keyboard_shortcuts_doc.examples.storyshot
index 939f3fd777533..d41370f7f3558 100644
--- a/x-pack/legacy/plugins/canvas/public/components/keyboard_shortcuts_doc/__examples__/__snapshots__/keyboard_shortcuts_doc.examples.storyshot
+++ b/x-pack/legacy/plugins/canvas/public/components/keyboard_shortcuts_doc/__examples__/__snapshots__/keyboard_shortcuts_doc.examples.storyshot
@@ -451,6 +451,218 @@ exports[`Storyshots components/KeyboardShortcutsDoc default 1`] = `
+
({
removeNodes: (nodeIds, pageId) => dispatch(removeElements(nodeIds, pageId)),
selectToplevelNodes: nodes =>
dispatch(selectToplevelNodes(nodes.filter(e => !e.position.parent).map(e => e.id))),
- // TODO: Abstract this out, this is similar to layering code in sidebar/index.js:
- elementLayer: (pageId, elementId, movement) => {
- dispatch(elementLayer({ pageId, elementId, movement }));
- },
+ elementLayer: (pageId, elementId, movement) =>
+ dispatch(elementLayer({ pageId, elementId, movement })),
+ setMultiplePositions: pageId => repositionedNodes =>
+ dispatch(
+ setMultiplePositions(repositionedNodes.map(node => ({ ...node, pageId, elementId: node.id })))
+ ),
});
const mergeProps = (
@@ -132,6 +139,7 @@ const mergeProps = (
...restDispatchProps,
...restStateProps,
updateGlobalState: globalStateUpdater(dispatch, state),
+ setMultiplePositions: restDispatchProps.setMultiplePositions(ownProps.pageId),
});
export const InteractivePage = compose(
diff --git a/x-pack/legacy/plugins/canvas/public/components/workpad_page/workpad_interactive_page/interactive_workpad_page.js b/x-pack/legacy/plugins/canvas/public/components/workpad_page/workpad_interactive_page/interactive_workpad_page.js
index 881503132d233..8d32d47b4d3f7 100644
--- a/x-pack/legacy/plugins/canvas/public/components/workpad_page/workpad_interactive_page/interactive_workpad_page.js
+++ b/x-pack/legacy/plugins/canvas/public/components/workpad_page/workpad_interactive_page/interactive_workpad_page.js
@@ -47,6 +47,7 @@ export class InteractiveWorkpadPage extends PureComponent {
canvasOrigin,
saveCanvasOrigin,
commit,
+ setMultiplePositions,
} = this.props;
let shortcuts = null;
@@ -59,6 +60,7 @@ export class InteractiveWorkpadPage extends PureComponent {
selectedNodes,
selectToplevelNodes,
commit,
+ setMultiplePositions,
};
shortcuts =
;
diff --git a/x-pack/legacy/plugins/canvas/public/components/workpad_shortcuts/index.tsx b/x-pack/legacy/plugins/canvas/public/components/workpad_shortcuts/index.tsx
index e9e947ae5fd5e..dc6a90ae298ce 100644
--- a/x-pack/legacy/plugins/canvas/public/components/workpad_shortcuts/index.tsx
+++ b/x-pack/legacy/plugins/canvas/public/components/workpad_shortcuts/index.tsx
@@ -13,13 +13,15 @@ import {
basicHandlerCreators,
clipboardHandlerCreators,
Props as HandlerCreatorProps,
+ positionHandlerCreators,
} from '../../lib/element_handler_creators';
export const WorkpadShortcuts = compose
(
withHandlers(groupHandlerCreators),
withHandlers(layerHandlerCreators),
withHandlers(basicHandlerCreators),
- withHandlers(clipboardHandlerCreators)
+ withHandlers(clipboardHandlerCreators),
+ withHandlers(positionHandlerCreators)
)(Component);
WorkpadShortcuts.propTypes = {
diff --git a/x-pack/legacy/plugins/canvas/public/components/workpad_shortcuts/workpad_shortcuts.tsx b/x-pack/legacy/plugins/canvas/public/components/workpad_shortcuts/workpad_shortcuts.tsx
index 545042eba31a8..57d637502c9a3 100644
--- a/x-pack/legacy/plugins/canvas/public/components/workpad_shortcuts/workpad_shortcuts.tsx
+++ b/x-pack/legacy/plugins/canvas/public/components/workpad_shortcuts/workpad_shortcuts.tsx
@@ -56,6 +56,38 @@ export interface Props {
* ungroups selected group
*/
ungroupNodes: () => void;
+ /**
+ * shifts selected elements 10px up
+ */
+ shiftUp: () => void;
+ /**
+ * shifts selected elements 10px down
+ */
+ shiftDown: () => void;
+ /**
+ * shifts selected elements 10px left
+ */
+ shiftLeft: () => void;
+ /**
+ * shifts selected elements 10px right
+ */
+ shiftRight: () => void;
+ /**
+ * nudges selected elements 1px up
+ */
+ nudgeUp: () => void;
+ /**
+ * nudges selected elements 1px down
+ */
+ nudgeDown: () => void;
+ /**
+ * nudges selected elements 1px left
+ */
+ nudgeLeft: () => void;
+ /**
+ * nudges selected elements 1px right
+ */
+ nudgeRight: () => void;
}
export class WorkpadShortcuts extends Component {
@@ -71,6 +103,14 @@ export class WorkpadShortcuts extends Component {
SEND_TO_BACK: this.props.sendToBack,
GROUP: this.props.groupNodes,
UNGROUP: this.props.ungroupNodes,
+ SHIFT_UP: this.props.shiftUp,
+ SHIFT_DOWN: this.props.shiftDown,
+ SHIFT_LEFT: this.props.shiftLeft,
+ SHIFT_RIGHT: this.props.shiftRight,
+ NUDGE_UP: this.props.nudgeUp,
+ NUDGE_DOWN: this.props.nudgeDown,
+ NUDGE_LEFT: this.props.nudgeLeft,
+ NUDGE_RIGHT: this.props.nudgeRight,
};
public render() {
diff --git a/x-pack/legacy/plugins/canvas/public/lib/element_handler_creators.ts b/x-pack/legacy/plugins/canvas/public/lib/element_handler_creators.ts
index ee402a07497f5..c698001e75fc0 100644
--- a/x-pack/legacy/plugins/canvas/public/lib/element_handler_creators.ts
+++ b/x-pack/legacy/plugins/canvas/public/lib/element_handler_creators.ts
@@ -15,6 +15,7 @@ import { notify } from './notify';
import * as customElementService from './custom_element_service';
import { getId } from './get_id';
import { PositionedElement } from './positioned_element';
+import { ELEMENT_NUDGE_OFFSET, ELEMENT_SHIFT_OFFSET } from '../../common/lib/constants';
const extractId = (node: { id: string }): string => node.id;
@@ -47,9 +48,13 @@ export interface Props {
* commits events to layout engine
*/
commit: (eventType: string, config: { event: string }) => void;
+ /**
+ * sets new position for multiple elements
+ */
+ setMultiplePositions: (elements: PositionedElement[]) => void;
}
-// handlers for clone and delete
+// handlers for clone, delete, and saving custom elements
export const basicHandlerCreators = {
cloneNodes: ({ insertNodes, pageId, selectToplevelNodes, selectedNodes }: Props) => (): void => {
const clonedNodes = selectedNodes && cloneSubgraphs(selectedNodes);
@@ -154,3 +159,71 @@ export const layerHandlerCreators = {
}
},
};
+
+// handlers for shifting elements up, down, left, and right
+export const positionHandlerCreators = {
+ shiftUp: ({ selectedNodes, setMultiplePositions }: Props) => (): void => {
+ setMultiplePositions(
+ selectedNodes.map(element => {
+ element.position.top -= ELEMENT_SHIFT_OFFSET;
+ return element;
+ })
+ );
+ },
+ shiftDown: ({ selectedNodes, setMultiplePositions }: Props) => (): void => {
+ setMultiplePositions(
+ selectedNodes.map(element => {
+ element.position.top += ELEMENT_SHIFT_OFFSET;
+ return element;
+ })
+ );
+ },
+ shiftLeft: ({ selectedNodes, setMultiplePositions }: Props) => (): void => {
+ setMultiplePositions(
+ selectedNodes.map(element => {
+ element.position.left -= ELEMENT_SHIFT_OFFSET;
+ return element;
+ })
+ );
+ },
+ shiftRight: ({ selectedNodes, setMultiplePositions }: Props) => (): void => {
+ setMultiplePositions(
+ selectedNodes.map(element => {
+ element.position.left += ELEMENT_SHIFT_OFFSET;
+ return element;
+ })
+ );
+ },
+ nudgeUp: ({ selectedNodes, setMultiplePositions }: Props) => (): void => {
+ setMultiplePositions(
+ selectedNodes.map(element => {
+ element.position.top -= ELEMENT_NUDGE_OFFSET;
+ return element;
+ })
+ );
+ },
+ nudgeDown: ({ selectedNodes, setMultiplePositions }: Props) => (): void => {
+ setMultiplePositions(
+ selectedNodes.map(element => {
+ element.position.top += ELEMENT_NUDGE_OFFSET;
+ return element;
+ })
+ );
+ },
+ nudgeLeft: ({ selectedNodes, setMultiplePositions }: Props) => (): void => {
+ setMultiplePositions(
+ selectedNodes.map(element => {
+ element.position.left -= ELEMENT_NUDGE_OFFSET;
+ return element;
+ })
+ );
+ },
+ nudgeRight: ({ selectedNodes, setMultiplePositions }: Props) => (): void => {
+ setMultiplePositions(
+ selectedNodes.map(element => {
+ element.position.left += ELEMENT_NUDGE_OFFSET;
+ return element;
+ })
+ );
+ },
+};
diff --git a/x-pack/legacy/plugins/canvas/public/lib/keymap.ts b/x-pack/legacy/plugins/canvas/public/lib/keymap.ts
index 8d1127e9e9e58..d0ee49de37f5e 100644
--- a/x-pack/legacy/plugins/canvas/public/lib/keymap.ts
+++ b/x-pack/legacy/plugins/canvas/public/lib/keymap.ts
@@ -5,6 +5,7 @@
*/
import { mapValues } from 'lodash';
+import { ELEMENT_NUDGE_OFFSET, ELEMENT_SHIFT_OFFSET } from '../../common/lib/constants';
export interface ShortcutMap {
osx: string[];
@@ -86,6 +87,26 @@ export const keymap: KeyMap = {
SEND_TO_BACK: getShortcuts('down', { modifiers: ['ctrl', 'shift'], help: 'Send to back' }),
GROUP: getShortcuts('g', { help: 'Group' }),
UNGROUP: getShortcuts('u', { help: 'Ungroup' }),
+ SHIFT_UP: getShortcuts('up', { help: `Shift up by ${ELEMENT_SHIFT_OFFSET}px` }),
+ SHIFT_DOWN: getShortcuts('down', { help: `Shift down by ${ELEMENT_SHIFT_OFFSET}px` }),
+ SHIFT_LEFT: getShortcuts('left', { help: `Shift left by ${ELEMENT_SHIFT_OFFSET}px` }),
+ SHIFT_RIGHT: getShortcuts('right', { help: `Shift right by ${ELEMENT_SHIFT_OFFSET}px` }),
+ NUDGE_UP: getShortcuts('up', {
+ modifiers: ['shift'],
+ help: `Shift up by ${ELEMENT_NUDGE_OFFSET}px`,
+ }),
+ NUDGE_DOWN: getShortcuts('down', {
+ modifiers: ['shift'],
+ help: `Shift down by ${ELEMENT_NUDGE_OFFSET}px`,
+ }),
+ NUDGE_LEFT: getShortcuts('left', {
+ modifiers: ['shift'],
+ help: `Shift left by ${ELEMENT_NUDGE_OFFSET}px`,
+ }),
+ NUDGE_RIGHT: getShortcuts('right', {
+ modifiers: ['shift'],
+ help: `Shift right by ${ELEMENT_NUDGE_OFFSET}px`,
+ }),
},
EXPRESSION: {
displayName: 'Expression controls',