@voithos-labs/aragonite 0.10.2 → 0.10.4
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/README.md +6 -21
- package/THIRD-PARTY-NOTICES.md +25 -0
- package/dist/a11y-strings.d.ts +19 -0
- package/dist/a11y-strings.js +19 -0
- package/dist/action-contracts.d.ts +7 -1
- package/dist/ambient/ambient-dom.js +5 -1
- package/dist/block-component.d.ts +14 -0
- package/dist/components/BlockDragHandle.svelte +37 -24
- package/dist/components/BlockHost.svelte +18 -11
- package/dist/components/Editor.svelte +434 -198
- package/dist/components/Editor.svelte.d.ts +1 -1
- package/dist/components/SelectionOverlay.svelte +25 -17
- package/dist/components/SelectionOverlay.svelte.d.ts +1 -1
- package/dist/components/TailInsert.svelte +107 -0
- package/dist/components/TailInsert.svelte.d.ts +17 -0
- package/dist/components/block-content-selector.d.ts +6 -2
- package/dist/components/block-content-selector.js +6 -2
- package/dist/components/blocks/ThematicBreakBlock.svelte +19 -6
- package/dist/components/blocks/ThematicBreakBlock.svelte.d.ts +1 -0
- package/dist/components/blocks/code/CodeBlock.svelte +211 -30
- package/dist/components/blocks/code/CodeBlockRail.svelte +704 -0
- package/dist/components/blocks/code/CodeBlockRail.svelte.d.ts +26 -0
- package/dist/components/blocks/code/code-bootstrap.js +16 -0
- package/dist/components/blocks/code/code-context-actions.d.ts +1 -0
- package/dist/components/blocks/code/code-context-actions.js +24 -0
- package/dist/components/blocks/code/code-fence-exit.d.ts +15 -0
- package/dist/components/blocks/code/code-fence-exit.js +26 -0
- package/dist/components/blocks/code/code-languages.d.ts +6 -0
- package/dist/components/blocks/code/code-languages.js +22 -3
- package/dist/components/blocks/code/code-renderer.js +11 -0
- package/dist/components/blocks/directive/DirectiveContainerBlock.svelte +1 -1
- package/dist/components/blocks/editable-leaf.d.ts +37 -6
- package/dist/components/blocks/editable-leaf.js +248 -30
- package/dist/components/blocks/editable-surface.d.ts +9 -0
- package/dist/components/blocks/editable-surface.js +22 -3
- package/dist/components/blocks/list/ListBlock.svelte +1 -0
- package/dist/components/blocks/list/ListItemBlock.svelte +14 -5
- package/dist/components/blocks/list/ListItemBlock.svelte.d.ts +2 -0
- package/dist/components/blocks/list/task-checkbox.d.ts +2 -0
- package/dist/components/blocks/list/task-checkbox.js +11 -2
- package/dist/components/blocks/surface-wiring.svelte.d.ts +4 -0
- package/dist/components/blocks/surface-wiring.svelte.js +8 -1
- package/dist/components/blocks/table/TableActionMenu.svelte +210 -86
- package/dist/components/blocks/table/TableActionMenu.svelte.d.ts +5 -0
- package/dist/components/blocks/table/TableBlock.svelte +205 -186
- package/dist/components/blocks/table/TableBlock.svelte.d.ts +1 -0
- package/dist/components/blocks/table/TableCellBlock.svelte +87 -22
- package/dist/components/blocks/table/TableRowBlock.svelte +4 -18
- package/dist/components/blocks/table/TableRowBlock.svelte.d.ts +0 -5
- package/dist/components/blocks/table/cell-clipboard.d.ts +10 -0
- package/dist/components/blocks/table/cell-clipboard.js +34 -1
- package/dist/components/blocks/table/cell-keydown-plan.d.ts +1 -1
- package/dist/components/blocks/table/cell-keydown-plan.js +3 -1
- package/dist/components/blocks/table/table-cell-paste.js +2 -1
- package/dist/components/blocks/table/table-menu-model.d.ts +35 -8
- package/dist/components/blocks/table/table-menu-model.js +36 -17
- package/dist/components/blocks/text/TextEditableBlock.svelte +58 -11
- package/dist/components/blocks/text/click-snap-guard.d.ts +3 -0
- package/dist/components/blocks/text/click-snap-guard.js +8 -0
- package/dist/components/blocks/text/delimiter-autopair.d.ts +71 -0
- package/dist/components/blocks/text/delimiter-autopair.js +216 -0
- package/dist/components/blocks/text/edge-policy-dispatch.d.ts +4 -0
- package/dist/components/blocks/text/edge-policy-dispatch.js +89 -20
- package/dist/components/blocks/text/live-selection-edit.d.ts +5 -5
- package/dist/components/blocks/text/live-selection-edit.js +37 -7
- package/dist/components/blocks/text/text-clipboard.js +2 -2
- package/dist/components/blocks/text/text-keydown.d.ts +7 -1
- package/dist/components/blocks/text/text-keydown.js +11 -1
- package/dist/components/blocks/text/text-render.d.ts +1 -1
- package/dist/components/blocks/text/text-render.js +3 -1
- package/dist/components/blocks/text/widget-interaction.d.ts +3 -0
- package/dist/components/blocks/text/widget-interaction.js +181 -37
- package/dist/components/drag-handle.d.ts +41 -0
- package/dist/components/drag-handle.js +134 -0
- package/dist/components/editor-root-focus.d.ts +19 -0
- package/dist/components/editor-root-focus.js +67 -0
- package/dist/components/editor-root-geometry.d.ts +39 -0
- package/dist/components/editor-root-geometry.js +91 -0
- package/dist/components/editor-root-keydown.d.ts +1 -1
- package/dist/components/editor-root-keydown.js +12 -3
- package/dist/components/editor-root-listeners.d.ts +3 -6
- package/dist/components/editor-root-listeners.js +3 -24
- package/dist/components/editor-root-mode-flip.d.ts +36 -0
- package/dist/components/editor-root-mode-flip.js +92 -0
- package/dist/components/image/ImageOverlayHost.svelte +14 -6
- package/dist/components/image/ImageProperties.svelte +512 -70
- package/dist/components/image/ImageProperties.svelte.d.ts +6 -1
- package/dist/components/image/ImageResizeHandles.svelte +67 -34
- package/dist/components/image/image-crop.d.ts +39 -0
- package/dist/components/image/image-crop.js +74 -0
- package/dist/components/image/image-edit-commit.d.ts +1 -0
- package/dist/components/image/image-edit-commit.js +21 -5
- package/dist/components/image/image-source-bytes.js +10 -3
- package/dist/components/image/image-widget-editing.js +1 -0
- package/dist/components/image/widget-dom.js +5 -1
- package/dist/components/link-card/link-card-commit.js +1 -1
- package/dist/components/lrd-map-gate.js +1 -1
- package/dist/components/menu/BlockMenu.svelte +315 -0
- package/dist/components/menu/BlockMenu.svelte.d.ts +34 -0
- package/dist/components/menu/MenuIcon.svelte +153 -0
- package/dist/components/menu/MenuIcon.svelte.d.ts +51 -0
- package/dist/components/menu/SelectionToolbar.svelte +385 -0
- package/dist/components/menu/SelectionToolbar.svelte.d.ts +16 -0
- package/dist/components/menu/clipboard-actions.d.ts +12 -0
- package/dist/components/menu/clipboard-actions.js +42 -0
- package/dist/components/menu/default-context-actions.d.ts +15 -0
- package/dist/components/menu/default-context-actions.js +76 -0
- package/dist/components/menu/flyout-placement.d.ts +6 -0
- package/dist/components/menu/flyout-placement.js +25 -0
- package/dist/core/inline/format-toggle.d.ts +12 -4
- package/dist/core/inline/format-toggle.js +94 -40
- package/dist/core/inline/image-dimensions.d.ts +3 -0
- package/dist/core/inline/image-dimensions.js +46 -10
- package/dist/core/inline/inline-widgets.d.ts +19 -0
- package/dist/core/inline/inline-widgets.js +5 -0
- package/dist/core/inline/scan/brackets.js +1 -0
- package/dist/core/inline/scan/plugin-syntax.d.ts +8 -0
- package/dist/core/inline/scan/plugin-syntax.js +15 -1
- package/dist/core/inline/transparency.js +3 -3
- package/dist/core/inline-render.d.ts +6 -0
- package/dist/core/inline-render.js +32 -0
- package/dist/core/nodes.d.ts +14 -0
- package/dist/cursor/edge-affinity.js +2 -1
- package/dist/cursor/height-oracle.d.ts +2 -3
- package/dist/cursor/height-oracle.js +0 -1
- package/dist/cursor/overlay-remeasure.js +8 -0
- package/dist/cursor/reveal-source.js +7 -2
- package/dist/cursor/scroll-hold.d.ts +10 -0
- package/dist/cursor/scroll-hold.js +22 -0
- package/dist/cursor/scrollport.d.ts +9 -0
- package/dist/cursor/scrollport.js +30 -1
- package/dist/cursor/visual-lines.d.ts +5 -4
- package/dist/cursor/visual-lines.js +56 -11
- package/dist/cursor/widget-edge-snap.d.ts +28 -0
- package/dist/cursor/widget-edge-snap.js +38 -0
- package/dist/cursor/widget-offset.d.ts +9 -0
- package/dist/cursor/widget-offset.js +71 -4
- package/dist/debug/interaction-trace.d.ts +4 -0
- package/dist/debug/interaction-trace.js +15 -0
- package/dist/decorations/decoration-state.svelte.js +1 -1
- package/dist/decorations/reserved-attrs.js +1 -0
- package/dist/editor-actions/ancestry-folds.d.ts +2 -2
- package/dist/editor-actions/ancestry-folds.js +1 -1
- package/dist/editor-actions/block-edit-scope.js +1 -1
- package/dist/editor-actions/commit/text-batch.d.ts +3 -2
- package/dist/editor-actions/commit/text-batch.js +1 -1
- package/dist/editor-actions/commit/undo-controller.js +4 -2
- package/dist/editor-actions/container-edit.js +2 -1
- package/dist/editor-actions/enter-completion.d.ts +2 -0
- package/dist/editor-actions/enter-completion.js +23 -2
- package/dist/editor-actions/focus/focus-dispatch.js +7 -4
- package/dist/editor-actions/focus/focus-landing.d.ts +10 -1
- package/dist/editor-actions/focus/focus-landing.js +20 -6
- package/dist/editor-actions/inline-range-commit.js +1 -1
- package/dist/editor-actions/plugin/container.d.ts +7 -0
- package/dist/editor-actions/plugin/container.js +3 -1
- package/dist/editor-actions/reorder-action.js +19 -10
- package/dist/editor-actions/reorder-drag.js +29 -1
- package/dist/editor-actions/replacement-focus.d.ts +1 -1
- package/dist/editor-actions/replacement-focus.js +1 -1
- package/dist/editor-actions/search-replace.js +1 -1
- package/dist/editor-actions/table-context.d.ts +4 -1
- package/dist/editor-actions/table-context.js +57 -1
- package/dist/editor-events.d.ts +3 -0
- package/dist/editor-keys.d.ts +33 -0
- package/dist/editor-props.d.ts +24 -12
- package/dist/index.d.ts +1 -1
- package/dist/plugin.d.ts +7 -0
- package/dist/plugin.js +16 -0
- package/dist/plugins/latex/BlockMath.svelte +264 -29
- package/dist/plugins/latex/BlockMath.svelte.d.ts +2 -0
- package/dist/plugins/latex/index.d.ts +2 -1
- package/dist/plugins/latex/latex-kind.js +60 -10
- package/dist/plugins/latex/math-completion.js +4 -1
- package/dist/plugins/latex/math-layout.d.ts +15 -0
- package/dist/plugins/latex/math-layout.js +13 -0
- package/dist/plugins/latex/math-source.d.ts +19 -0
- package/dist/plugins/latex/math-source.js +103 -0
- package/dist/plugins/latex/register.d.ts +11 -2
- package/dist/plugins/latex/register.js +3 -1
- package/dist/plugins/latex/renderer.d.ts +3 -3
- package/dist/plugins/latex/renderer.js +13 -6
- package/dist/plugins/mermaid/MermaidBlock.svelte +19 -9
- package/dist/plugins/parrot/ParrotBlock.svelte +3 -1
- package/dist/reactivity/list-windowing.svelte.d.ts +8 -8
- package/dist/reactivity/list-windowing.svelte.js +75 -30
- package/dist/schema/block-completions.d.ts +8 -0
- package/dist/schema/block-completions.js +11 -0
- package/dist/schema/commands.d.ts +9 -5
- package/dist/schema/commands.js +12 -7
- package/dist/schema/context-actions.d.ts +31 -0
- package/dist/schema/context-actions.js +23 -0
- package/dist/schema/fenced-code-raw.js +31 -1
- package/dist/schema/operations.d.ts +8 -1
- package/dist/schema/reserved-chords.js +37 -4
- package/dist/schema/table-cell-raw.d.ts +1 -1
- package/dist/schema/table-cell-raw.js +1 -1
- package/dist/selection/block-hit-test.js +3 -2
- package/dist/selection/char-endpoint-snap.js +1 -1
- package/dist/selection/clipboard-text.js +6 -1
- package/dist/selection/covered-block.d.ts +10 -0
- package/dist/selection/covered-block.js +24 -0
- package/dist/selection/cross-block/dispatch.d.ts +3 -0
- package/dist/selection/cross-block/dispatch.js +13 -1
- package/dist/selection/cross-block/format-range.d.ts +1 -1
- package/dist/selection/cross-block/format-range.js +4 -15
- package/dist/selection/cross-block/format-toggle.js +1 -1
- package/dist/selection/cross-block/keydown.js +3 -29
- package/dist/selection/cross-block/ops.js +1 -1
- package/dist/selection/cross-block/paste.js +31 -35
- package/dist/selection/cross-block/type-replace.d.ts +3 -2
- package/dist/selection/cross-block/type-replace.js +52 -13
- package/dist/selection/dead-space-caret.d.ts +13 -0
- package/dist/selection/dead-space-caret.js +57 -1
- package/dist/selection/drag-pointer.d.ts +26 -2
- package/dist/selection/drag-pointer.js +103 -2
- package/dist/selection/gap-caret.js +1 -1
- package/dist/selection/keyboard-extend.d.ts +3 -2
- package/dist/selection/keyboard-extend.js +4 -3
- package/dist/selection/multi-click.d.ts +42 -0
- package/dist/selection/multi-click.js +203 -0
- package/dist/selection/native-bridge.d.ts +3 -0
- package/dist/selection/native-bridge.js +31 -2
- package/dist/selection/path-lookup.d.ts +10 -2
- package/dist/selection/path-lookup.js +11 -4
- package/dist/selection/pointer-gesture.d.ts +9 -0
- package/dist/selection/pointer-gesture.js +11 -0
- package/dist/selection/primitives.d.ts +7 -0
- package/dist/selection/primitives.js +19 -1
- package/dist/selection/range-delete-ceremony.js +4 -2
- package/dist/selection/range-delete-chrome.js +2 -1
- package/dist/selection/range-delete-table-coverage.js +2 -1
- package/dist/selection/range-delete-table.js +3 -2
- package/dist/selection/range-delete.d.ts +4 -0
- package/dist/selection/range-delete.js +31 -3
- package/dist/selection/selection-drop.d.ts +34 -0
- package/dist/selection/selection-drop.js +253 -0
- package/dist/selection/selection-restore.js +1 -1
- package/dist/selection/selection-state.svelte.d.ts +6 -0
- package/dist/selection/selection-state.svelte.js +36 -1
- package/dist/selection/table-endpoint-snap.js +1 -1
- package/dist/selection/table-rect-extend.js +1 -1
- package/dist/styles/editor-theme.css +75 -31
- package/dist/styles/editor.css +268 -18
- package/dist/testing/container-conformance.js +2 -2
- package/dist/testing/inline-conformance.js +2 -1
- package/dist/tree-operations/blockquote.js +1 -1
- package/dist/tree-operations/chain-rebuild.d.ts +63 -0
- package/dist/tree-operations/chain-rebuild.js +142 -0
- package/dist/tree-operations/children.d.ts +1 -1
- package/dist/tree-operations/children.js +1 -1
- package/dist/tree-operations/cleanup.js +1 -1
- package/dist/tree-operations/content-write.d.ts +50 -0
- package/dist/tree-operations/content-write.js +263 -0
- package/dist/tree-operations/index.d.ts +8 -3
- package/dist/tree-operations/index.js +6 -2
- package/dist/tree-operations/list/exit-replacement.js +1 -1
- package/dist/tree-operations/list/unwrap-merge.js +3 -3
- package/dist/tree-operations/node-ops.d.ts +17 -234
- package/dist/tree-operations/node-ops.js +47 -1113
- package/dist/tree-operations/node-primitives.d.ts +75 -0
- package/dist/tree-operations/node-primitives.js +117 -0
- package/dist/tree-operations/paste/apply.js +1 -1
- package/dist/tree-operations/paste/body-write.d.ts +1 -1
- package/dist/tree-operations/paste/body-write.js +2 -2
- package/dist/tree-operations/paste/container-match.js +4 -2
- package/dist/tree-operations/paste/dispatch.js +2 -1
- package/dist/tree-operations/paste/find-enclosing-list.js +1 -1
- package/dist/tree-operations/paste/focus-target.d.ts +1 -1
- package/dist/tree-operations/paste/list-absorb.js +1 -1
- package/dist/tree-operations/paste/list-break-out.js +1 -1
- package/dist/tree-operations/paste/parent-scope.js +1 -1
- package/dist/tree-operations/paste/paste-replacement.js +1 -1
- package/dist/tree-operations/paste/replace-block-at-parent.d.ts +3 -1
- package/dist/tree-operations/paste/replace-block-at-parent.js +5 -2
- package/dist/tree-operations/paste/replacement-parse.d.ts +17 -0
- package/dist/tree-operations/paste/replacement-parse.js +22 -0
- package/dist/tree-operations/path-mutate.d.ts +1 -1
- package/dist/tree-operations/path-mutate.js +2 -1
- package/dist/tree-operations/reorder-unit.js +1 -1
- package/dist/tree-operations/reorder.d.ts +5 -2
- package/dist/tree-operations/reorder.js +55 -2
- package/dist/tree-operations/settle.d.ts +105 -0
- package/dist/tree-operations/settle.js +660 -0
- package/dist/tree-operations/table-grid-clipboard.d.ts +21 -0
- package/dist/tree-operations/table-grid-clipboard.js +90 -0
- package/dist/tree-operations/unshare.d.ts +15 -77
- package/dist/tree-operations/unshare.js +15 -166
- package/docs/guide/consumer-guide.md +136 -104
- package/docs/guide/plugin-api.md +73 -29
- package/docs/guide/plugin-guide.md +55 -23
- package/package.json +9 -7
- package/dist/components/blocks/code/CodeLanguageChip.svelte +0 -127
- package/dist/components/blocks/code/CodeLanguageChip.svelte.d.ts +0 -14
- package/dist/components/blocks/table/TableGrip.svelte +0 -91
- package/dist/components/blocks/table/TableGrip.svelte.d.ts +0 -8
- package/dist/components/blocks/table/table-drop-target.d.ts +0 -1
- package/dist/components/blocks/table/table-drop-target.js +0 -16
- package/dist/components/blocks/table/table-reorder-drag.d.ts +0 -78
- package/dist/components/blocks/table/table-reorder-drag.js +0 -97
|
@@ -9,6 +9,7 @@ import { BLOCK_EDIT_KEY, EDITOR_DOC_KEY, EDITOR_POLICIES_KEY, EDITOR_SERVICES_KE
|
|
|
9
9
|
import { emitCommandError } from '../../editor-events';
|
|
10
10
|
import { eventToChord } from '../../schema/keybindings';
|
|
11
11
|
import { dispatchKeyCommand } from '../../schema/block-commands';
|
|
12
|
+
import { resolveBinding } from '../../schema/commands';
|
|
12
13
|
import { parkFocusOnEditorRoot } from '../../selection/native-bridge';
|
|
13
14
|
export function wireSurfaceContexts() {
|
|
14
15
|
const blockEdit = getContext(BLOCK_EDIT_KEY);
|
|
@@ -56,7 +57,13 @@ export function wireSurfaceContexts() {
|
|
|
56
57
|
e.preventDefault();
|
|
57
58
|
return true;
|
|
58
59
|
};
|
|
59
|
-
|
|
60
|
+
const resolveChord = (e, kind) => {
|
|
61
|
+
const chord = eventToChord(e);
|
|
62
|
+
if (!chord)
|
|
63
|
+
return null;
|
|
64
|
+
return resolveBinding(chord, kind, keybindingOverrides(), activePlugins)?.command ?? null;
|
|
65
|
+
};
|
|
66
|
+
return { deps, dispatchChord, resolveChord };
|
|
60
67
|
}
|
|
61
68
|
// Windowed out while focused: hand focus to the editor root so the next keystroke
|
|
62
69
|
// routes through its document-level listener instead of falling to `<body>`.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { keepFlyoutOnScreen } from '../../menu/flyout-placement';
|
|
2
3
|
import {
|
|
3
4
|
clampMenuToViewport,
|
|
4
5
|
type TableMenuItem,
|
|
@@ -12,6 +13,27 @@
|
|
|
12
13
|
COLUMN_ALIGNMENT,
|
|
13
14
|
TABLE_ACTIONS
|
|
14
15
|
} from '../../../a11y-strings';
|
|
16
|
+
import MenuIcon, { type MenuIconName } from '../../menu/MenuIcon.svelte';
|
|
17
|
+
import { tick, untrack } from 'svelte';
|
|
18
|
+
|
|
19
|
+
// The glyph each entry carries, limestone's context-menu convention: an icon slot per row,
|
|
20
|
+
// the destructive rows in the accent.
|
|
21
|
+
const ICONS: Record<TableAxisAction | ClipboardAction, MenuIconName> = {
|
|
22
|
+
insertRowAbove: 'plus',
|
|
23
|
+
insertRowBelow: 'plus',
|
|
24
|
+
insertColumnLeft: 'plus',
|
|
25
|
+
insertColumnRight: 'plus',
|
|
26
|
+
moveRowUp: 'arrow-up',
|
|
27
|
+
moveRowDown: 'arrow-down',
|
|
28
|
+
moveColumnLeft: 'arrow-left',
|
|
29
|
+
moveColumnRight: 'arrow-right',
|
|
30
|
+
deleteRow: 'trash',
|
|
31
|
+
deleteColumn: 'trash',
|
|
32
|
+
cycleAlignment: 'align-left',
|
|
33
|
+
cut: 'scissors',
|
|
34
|
+
copy: 'copy',
|
|
35
|
+
paste: 'clipboard'
|
|
36
|
+
};
|
|
15
37
|
|
|
16
38
|
let {
|
|
17
39
|
items,
|
|
@@ -21,11 +43,14 @@
|
|
|
21
43
|
onclipboard,
|
|
22
44
|
onalign,
|
|
23
45
|
onclose,
|
|
24
|
-
onescape
|
|
46
|
+
onescape,
|
|
47
|
+
anchor
|
|
25
48
|
}: {
|
|
26
49
|
items: TableMenuItem[];
|
|
27
50
|
x: number;
|
|
28
51
|
y: number;
|
|
52
|
+
/** Where the open point is NOW, re-read on scroll and resize so the menu stays on it. */
|
|
53
|
+
anchor?: () => { x: number; y: number } | null;
|
|
29
54
|
onaction: (action: TableAxisAction, index: number) => void;
|
|
30
55
|
onclipboard: (action: ClipboardAction) => void;
|
|
31
56
|
onalign: (alignment: 'left' | 'center' | 'right') => void;
|
|
@@ -34,23 +59,46 @@
|
|
|
34
59
|
} = $props();
|
|
35
60
|
|
|
36
61
|
let menuEl: HTMLDivElement | undefined = $state();
|
|
62
|
+
/** The open flyout, if any: hover or ArrowRight on its row opens it, ArrowLeft closes it. */
|
|
63
|
+
let openGroup = $state<'row' | 'column' | null>(null);
|
|
37
64
|
|
|
38
|
-
//
|
|
39
|
-
//
|
|
40
|
-
|
|
65
|
+
// The open point, viewport coordinates, re-read on scroll and resize so the menu stays on
|
|
66
|
+
// what it opened on and leaves the viewport with it — never re-clamped into view, which
|
|
67
|
+
// would float it over unrelated content. The clamp runs once, when the size is first known,
|
|
68
|
+
// and its shift rides along as a constant offset.
|
|
69
|
+
// svelte-ignore state_referenced_locally
|
|
70
|
+
let at = $state({ x, y });
|
|
71
|
+
let shift = $state<{ x: number; y: number } | null>(null);
|
|
41
72
|
$effect(() => {
|
|
42
|
-
|
|
73
|
+
const follow = () => {
|
|
74
|
+
const next = anchor?.();
|
|
75
|
+
if (next) at = next;
|
|
76
|
+
};
|
|
77
|
+
window.addEventListener('scroll', follow, { capture: true, passive: true });
|
|
78
|
+
window.addEventListener('resize', follow, { passive: true });
|
|
79
|
+
return () => {
|
|
80
|
+
window.removeEventListener('scroll', follow, { capture: true });
|
|
81
|
+
window.removeEventListener('resize', follow);
|
|
82
|
+
};
|
|
83
|
+
});
|
|
84
|
+
$effect(() => {
|
|
85
|
+
if (!menuEl || shift) return;
|
|
43
86
|
const rect = menuEl.getBoundingClientRect();
|
|
44
|
-
clamped = clampMenuToViewport(
|
|
87
|
+
const clamped = clampMenuToViewport(
|
|
45
88
|
{ x, y },
|
|
46
89
|
{ width: rect.width, height: rect.height },
|
|
47
90
|
{ width: window.innerWidth, height: window.innerHeight }
|
|
48
91
|
);
|
|
92
|
+
shift = { x: clamped.x - x, y: clamped.y - y };
|
|
49
93
|
});
|
|
94
|
+
const left = $derived(at.x + (shift?.x ?? 0));
|
|
95
|
+
const top = $derived(at.y + (shift?.y ?? 0));
|
|
50
96
|
|
|
51
97
|
// The first enabled item is the keyboard entry point; disabled items are never stops.
|
|
98
|
+
// Untracked: `focusStop` reads the open flyout, and a tracked read here would re-run this
|
|
99
|
+
// mount-time landing every time a flyout opened, pulling focus straight back out of it.
|
|
52
100
|
$effect(() => {
|
|
53
|
-
if (menuEl) focusStop(0);
|
|
101
|
+
if (menuEl) untrack(() => focusStop(0));
|
|
54
102
|
});
|
|
55
103
|
|
|
56
104
|
$effect(() => {
|
|
@@ -90,7 +138,27 @@
|
|
|
90
138
|
const stops = focusableStops();
|
|
91
139
|
if (stops.length === 0) return;
|
|
92
140
|
const n = stops.length;
|
|
93
|
-
stops[((index % n) + n) % n]
|
|
141
|
+
const stop = stops[((index % n) + n) % n];
|
|
142
|
+
stop.focus();
|
|
143
|
+
// Focus that leaves an open flyout (and its own row) closes it, so the list reads as one.
|
|
144
|
+
if (
|
|
145
|
+
openGroup &&
|
|
146
|
+
!stop.closest('.table-action-menu-flyout') &&
|
|
147
|
+
stop.dataset.group !== openGroup
|
|
148
|
+
) {
|
|
149
|
+
openGroup = null;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/** Open a group's flyout and land on its first enabled item. */
|
|
154
|
+
function openFlyout(id: 'row' | 'column'): void {
|
|
155
|
+
openGroup = id;
|
|
156
|
+
void tick().then(() => {
|
|
157
|
+
const first = menuEl?.querySelector<HTMLElement>(
|
|
158
|
+
'.table-action-menu-flyout [role="menuitem"]:not([disabled])'
|
|
159
|
+
);
|
|
160
|
+
first?.focus();
|
|
161
|
+
});
|
|
94
162
|
}
|
|
95
163
|
|
|
96
164
|
function activeStopIndex(stops: HTMLElement[]): number {
|
|
@@ -121,10 +189,30 @@
|
|
|
121
189
|
e.preventDefault();
|
|
122
190
|
focusStop(last);
|
|
123
191
|
return;
|
|
124
|
-
case 'ArrowRight':
|
|
125
|
-
|
|
192
|
+
case 'ArrowRight': {
|
|
193
|
+
const group = (document.activeElement as HTMLElement | null)?.dataset.group;
|
|
194
|
+
if (group === 'row' || group === 'column') {
|
|
195
|
+
e.preventDefault();
|
|
196
|
+
openFlyout(group);
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
moveWithinAlignment(e);
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
case 'ArrowLeft': {
|
|
203
|
+
const inFlyout = (document.activeElement as HTMLElement | null)?.closest(
|
|
204
|
+
'.table-action-menu-flyout'
|
|
205
|
+
);
|
|
206
|
+
if (inFlyout && openGroup) {
|
|
207
|
+
e.preventDefault();
|
|
208
|
+
const row = menuEl?.querySelector<HTMLElement>(`[data-group="${openGroup}"]`);
|
|
209
|
+
openGroup = null;
|
|
210
|
+
row?.focus();
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
126
213
|
moveWithinAlignment(e);
|
|
127
214
|
return;
|
|
215
|
+
}
|
|
128
216
|
}
|
|
129
217
|
}
|
|
130
218
|
|
|
@@ -140,44 +228,78 @@
|
|
|
140
228
|
segments[(((i + delta) % n) + n) % n].focus();
|
|
141
229
|
}
|
|
142
230
|
|
|
231
|
+
// The actions that live inside a flyout: hovering one keeps its flyout open; hovering a
|
|
232
|
+
// top-level row closes whichever flyout is open.
|
|
233
|
+
const GROUPED = new Set<TableAxisAction>([
|
|
234
|
+
'insertRowAbove',
|
|
235
|
+
'insertRowBelow',
|
|
236
|
+
'moveRowUp',
|
|
237
|
+
'moveRowDown',
|
|
238
|
+
'insertColumnLeft',
|
|
239
|
+
'insertColumnRight',
|
|
240
|
+
'moveColumnLeft',
|
|
241
|
+
'moveColumnRight'
|
|
242
|
+
]);
|
|
243
|
+
const isGrouped = (action: TableAxisAction): boolean => GROUPED.has(action);
|
|
244
|
+
|
|
143
245
|
// 'none' renders identically to 'left', so the left segment reads active for both.
|
|
144
|
-
//
|
|
246
|
+
// The glyph is the visible label; the accessible name carries the full word.
|
|
145
247
|
const alignmentSegments = [
|
|
146
|
-
{ value: 'left',
|
|
147
|
-
{ value: 'center',
|
|
148
|
-
{ value: 'right',
|
|
248
|
+
{ value: 'left', icon: 'align-left', name: ALIGN_LEFT },
|
|
249
|
+
{ value: 'center', icon: 'align-center', name: ALIGN_CENTER },
|
|
250
|
+
{ value: 'right', icon: 'align-right', name: ALIGN_RIGHT }
|
|
149
251
|
] as const;
|
|
150
252
|
</script>
|
|
151
253
|
|
|
152
254
|
<div
|
|
153
255
|
bind:this={menuEl}
|
|
154
|
-
class="table-action-menu"
|
|
256
|
+
class="md-menu table-action-menu"
|
|
155
257
|
role="menu"
|
|
156
258
|
aria-label={TABLE_ACTIONS}
|
|
157
259
|
tabindex="-1"
|
|
158
|
-
style:left="{
|
|
159
|
-
style:top="{
|
|
260
|
+
style:left="{left}px"
|
|
261
|
+
style:top="{top}px"
|
|
160
262
|
onkeydown={onMenuKeyDown}
|
|
161
263
|
>
|
|
162
264
|
{#each items as item, i (i)}
|
|
163
265
|
{#if item.kind === 'action' || item.kind === 'clipboard'}
|
|
164
|
-
{@
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
266
|
+
{@render actionRow(item)}
|
|
267
|
+
{:else if item.kind === 'group'}
|
|
268
|
+
<div class="table-action-menu-group" role="presentation">
|
|
269
|
+
<button
|
|
270
|
+
type="button"
|
|
271
|
+
role="menuitem"
|
|
272
|
+
tabindex="-1"
|
|
273
|
+
class="md-menu-item table-action-menu-item"
|
|
274
|
+
data-group={item.id}
|
|
275
|
+
aria-haspopup="menu"
|
|
276
|
+
aria-expanded={openGroup === item.id}
|
|
277
|
+
onpointerenter={() => (openGroup = item.id)}
|
|
278
|
+
onclick={() => openFlyout(item.id)}
|
|
279
|
+
>
|
|
280
|
+
<span class="md-menu-icon"
|
|
281
|
+
><MenuIcon name={item.id === 'row' ? 'rows-2' : 'columns-2'} /></span
|
|
282
|
+
>
|
|
283
|
+
<span class="table-action-menu-label">{item.label}</span>
|
|
284
|
+
<span class="md-menu-icon"><MenuIcon name="chevron-right" size={13} /></span>
|
|
285
|
+
</button>
|
|
286
|
+
{#if openGroup === item.id}
|
|
287
|
+
<div
|
|
288
|
+
class="md-menu table-action-menu-flyout"
|
|
289
|
+
role="menu"
|
|
290
|
+
aria-label={item.label}
|
|
291
|
+
{@attach keepFlyoutOnScreen}
|
|
292
|
+
>
|
|
293
|
+
{#each item.items as sub, j (j)}
|
|
294
|
+
{#if sub.kind === 'action' || sub.kind === 'clipboard'}
|
|
295
|
+
{@render actionRow(sub)}
|
|
296
|
+
{/if}
|
|
297
|
+
{/each}
|
|
298
|
+
</div>
|
|
299
|
+
{/if}
|
|
300
|
+
</div>
|
|
179
301
|
{:else if item.kind === 'separator'}
|
|
180
|
-
<div class="table-action-menu-separator" role="separator"></div>
|
|
302
|
+
<div class="md-menu-divider table-action-menu-separator" role="separator"></div>
|
|
181
303
|
{:else}
|
|
182
304
|
<div class="table-action-menu-alignment" role="group" aria-label={COLUMN_ALIGNMENT}>
|
|
183
305
|
{#each alignmentSegments as seg (seg.value)}
|
|
@@ -190,7 +312,8 @@
|
|
|
190
312
|
tabindex="-1"
|
|
191
313
|
aria-label={seg.name}
|
|
192
314
|
aria-pressed={active}
|
|
193
|
-
|
|
315
|
+
title={seg.name}
|
|
316
|
+
onclick={() => onalign(seg.value)}><MenuIcon name={seg.icon} /></button
|
|
194
317
|
>
|
|
195
318
|
{/each}
|
|
196
319
|
</div>
|
|
@@ -198,70 +321,71 @@
|
|
|
198
321
|
{/each}
|
|
199
322
|
</div>
|
|
200
323
|
|
|
324
|
+
{#snippet actionRow(item: Extract<TableMenuItem, { kind: 'action' | 'clipboard' }>)}
|
|
325
|
+
{@const activate =
|
|
326
|
+
item.kind === 'action'
|
|
327
|
+
? () => onaction(item.action, item.index)
|
|
328
|
+
: () => onclipboard(item.action)}
|
|
329
|
+
<button
|
|
330
|
+
type="button"
|
|
331
|
+
role="menuitem"
|
|
332
|
+
tabindex="-1"
|
|
333
|
+
class="md-menu-item table-action-menu-item"
|
|
334
|
+
disabled={!item.enabled}
|
|
335
|
+
aria-disabled={!item.enabled}
|
|
336
|
+
onpointerenter={() => {
|
|
337
|
+
if (!(item.kind === 'action' && isGrouped(item.action))) openGroup = null;
|
|
338
|
+
}}
|
|
339
|
+
onclick={activate}
|
|
340
|
+
>
|
|
341
|
+
<span class="md-menu-icon"><MenuIcon name={ICONS[item.action]} /></span>
|
|
342
|
+
<span class="table-action-menu-label">{item.label}</span>
|
|
343
|
+
</button>
|
|
344
|
+
{/snippet}
|
|
345
|
+
|
|
201
346
|
<style>
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
padding: 0.25rem;
|
|
347
|
+
/* The surface, rows, icons and dividers are the shared `.md-menu` family (editor.css); only
|
|
348
|
+
the alignment trio is this menu's own — three glyph buttons on one row, the active one
|
|
349
|
+
lifted like a hover. */
|
|
350
|
+
.table-action-menu-alignment {
|
|
207
351
|
display: flex;
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
border: 1px solid var(--color-ui-muted, #a4a4a4);
|
|
211
|
-
border-radius: 6px;
|
|
212
|
-
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.14);
|
|
213
|
-
font-size: 0.9em;
|
|
214
|
-
user-select: none;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
.table-action-menu-item {
|
|
218
|
-
display: block;
|
|
219
|
-
width: 100%;
|
|
220
|
-
padding: 0.3rem 0.55rem;
|
|
221
|
-
border: 0;
|
|
222
|
-
border-radius: 4px;
|
|
223
|
-
background: transparent;
|
|
224
|
-
text-align: left;
|
|
225
|
-
font: inherit;
|
|
226
|
-
color: inherit;
|
|
227
|
-
cursor: pointer;
|
|
352
|
+
gap: 2px;
|
|
353
|
+
padding: 4px 6px;
|
|
228
354
|
}
|
|
229
|
-
.table-action-menu-
|
|
230
|
-
|
|
231
|
-
}
|
|
232
|
-
.table-action-menu-item:disabled {
|
|
233
|
-
opacity: 0.4;
|
|
234
|
-
cursor: default;
|
|
355
|
+
.table-action-menu-label {
|
|
356
|
+
flex: 1;
|
|
235
357
|
}
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
height: 1px;
|
|
239
|
-
margin: 0.25rem 0.3rem;
|
|
240
|
-
background: var(--color-ui-muted, #a4a4a4);
|
|
241
|
-
opacity: 0.5;
|
|
358
|
+
.table-action-menu-group {
|
|
359
|
+
position: relative;
|
|
242
360
|
}
|
|
243
|
-
|
|
244
|
-
.table-action-menu-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
361
|
+
/* limestone's submenu: a second surface hung off the row's right edge. */
|
|
362
|
+
.table-action-menu-flyout {
|
|
363
|
+
position: absolute;
|
|
364
|
+
left: 100%;
|
|
365
|
+
top: -4px;
|
|
366
|
+
margin-left: 4px;
|
|
367
|
+
white-space: nowrap;
|
|
248
368
|
}
|
|
249
369
|
.alignment-segment {
|
|
250
370
|
flex: 1;
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
371
|
+
display: inline-flex;
|
|
372
|
+
align-items: center;
|
|
373
|
+
justify-content: center;
|
|
374
|
+
height: 26px;
|
|
375
|
+
padding: 0;
|
|
376
|
+
border: 0;
|
|
377
|
+
border-radius: 5px;
|
|
255
378
|
background: transparent;
|
|
256
|
-
|
|
257
|
-
color: var(--color-ui-muted, #a4a4a4);
|
|
379
|
+
color: var(--color-ui-muted, #8f8f89);
|
|
258
380
|
cursor: pointer;
|
|
259
381
|
}
|
|
260
|
-
.alignment-segment:hover
|
|
261
|
-
|
|
382
|
+
.alignment-segment:hover,
|
|
383
|
+
.alignment-segment:focus-visible,
|
|
384
|
+
.alignment-segment.active {
|
|
385
|
+
background: var(--menu-item-hover, rgba(255, 255, 255, 0.07));
|
|
386
|
+
outline: none;
|
|
262
387
|
}
|
|
263
388
|
.alignment-segment.active {
|
|
264
|
-
color: var(--color-
|
|
265
|
-
border-color: var(--color-accent, #567b67);
|
|
389
|
+
color: var(--color-text-primary, #e8e8e5);
|
|
266
390
|
}
|
|
267
391
|
</style>
|
|
@@ -4,6 +4,11 @@ type $$ComponentProps = {
|
|
|
4
4
|
items: TableMenuItem[];
|
|
5
5
|
x: number;
|
|
6
6
|
y: number;
|
|
7
|
+
/** Where the open point is NOW, re-read on scroll and resize so the menu stays on it. */
|
|
8
|
+
anchor?: () => {
|
|
9
|
+
x: number;
|
|
10
|
+
y: number;
|
|
11
|
+
} | null;
|
|
7
12
|
onaction: (action: TableAxisAction, index: number) => void;
|
|
8
13
|
onclipboard: (action: ClipboardAction) => void;
|
|
9
14
|
onalign: (alignment: 'left' | 'center' | 'right') => void;
|