diff --git a/apps/web/src/components/ui/report/plugins/metric-kit/metric-kit.tsx b/apps/web/src/components/ui/report/plugins/metric-kit/metric-kit.tsx index b621ee81a..fa9b69286 100644 --- a/apps/web/src/components/ui/report/plugins/metric-kit/metric-kit.tsx +++ b/apps/web/src/components/ui/report/plugins/metric-kit/metric-kit.tsx @@ -34,6 +34,54 @@ export const MetricPlugin = createPlatePlugin< isElement: true, isVoid: false, component: MetricElement + }, + handlers: { + onKeyDown: ({ editor, event }) => { + // Only handle single-caret (collapsed) cases + if (!editor.api.isCollapsed()) return true; + + const key = event.key; + if (key !== 'Backspace' && key !== 'Delete') return true; + + const block = editor.api.block(); + if (!block) return true; + + const [, path] = block; + + // Helper to get sibling at offset from current block index + const getSiblingEntry = (offset: number) => { + const index = path[path.length - 1] + offset; + if (index < 0) return undefined; + const siblingPath = [...path.slice(0, -1), index] as unknown as Path; + return editor.api.node(siblingPath); + }; + + // Backspace at start of block should remove previous metric node + if (key === 'Backspace' && editor.api.isAt({ start: true })) { + const prevEntry = getSiblingEntry(-1); + if (!prevEntry) return true; + const [prevNode, prevPath] = prevEntry; + if ((prevNode as TElement).type === CUSTOM_KEYS.metric) { + event.preventDefault(); + editor.tf.removeNodes({ at: prevPath }); + return false; + } + } + + // Delete at end of block should remove next metric node + if (key === 'Delete' && editor.api.isAt({ end: true })) { + const nextEntry = getSiblingEntry(1); + if (!nextEntry) return true; + const [nextNode, nextPath] = nextEntry; + if ((nextNode as TElement).type === CUSTOM_KEYS.metric) { + event.preventDefault(); + editor.tf.removeNodes({ at: nextPath }); + return false; + } + } + + return true; + } } }).extendApi(({ setOption, plugin, editor, tf, ...rest }) => { return {