@voithos-labs/aragonite 0.10.2 → 0.10.3
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 +18 -0
- package/dist/a11y-strings.js +18 -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 +35 -24
- package/dist/components/BlockHost.svelte +16 -9
- package/dist/components/Editor.svelte +381 -198
- package/dist/components/Editor.svelte.d.ts +1 -1
- package/dist/components/SelectionOverlay.svelte +17 -3
- 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 +686 -0
- package/dist/components/blocks/code/CodeBlockRail.svelte.d.ts +26 -0
- package/dist/components/blocks/code/code-bootstrap.js +4 -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 +11 -0
- 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 +243 -29
- package/dist/components/blocks/editable-surface.d.ts +9 -0
- package/dist/components/blocks/editable-surface.js +22 -3
- package/dist/components/blocks/list/ListItemBlock.svelte +3 -3
- 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/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 +56 -2
- package/dist/components/blocks/text/live-selection-edit.js +27 -0
- 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 +144 -22
- package/dist/components/drag-handle.d.ts +35 -0
- package/dist/components/drag-handle.js +126 -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 +10 -6
- package/dist/components/editor-root-listeners.js +23 -22
- 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 +59 -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/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 +11 -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-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/overlay-remeasure.js +8 -0
- package/dist/cursor/reveal-source.js +7 -2
- package/dist/cursor/widget-offset.d.ts +6 -0
- package/dist/cursor/widget-offset.js +61 -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/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/inline-range-commit.js +1 -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 +21 -12
- package/dist/index.d.ts +1 -1
- package/dist/plugin.d.ts +6 -0
- package/dist/plugin.js +11 -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 +36 -3
- 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 +97 -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/reactivity/list-windowing.svelte.d.ts +8 -8
- package/dist/reactivity/list-windowing.svelte.js +49 -24
- package/dist/schema/block-completions.d.ts +8 -0
- package/dist/schema/block-completions.js +11 -0
- 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 +25 -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 +1 -1
- package/dist/selection/cross-block/ops.js +1 -1
- package/dist/selection/cross-block/paste.js +32 -30
- package/dist/selection/cross-block/type-replace.d.ts +3 -2
- package/dist/selection/cross-block/type-replace.js +62 -13
- package/dist/selection/dead-space-caret.d.ts +10 -0
- package/dist/selection/dead-space-caret.js +47 -1
- package/dist/selection/double-click-trim.d.ts +17 -0
- package/dist/selection/double-click-trim.js +57 -0
- package/dist/selection/drag-pointer.d.ts +7 -2
- package/dist/selection/drag-pointer.js +61 -2
- package/dist/selection/gap-caret.js +1 -1
- package/dist/selection/keyboard-extend.js +1 -1
- package/dist/selection/path-lookup.js +1 -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.js +30 -2
- 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 +57 -28
- package/dist/styles/editor.css +217 -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.js +1 -1
- 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 +126 -96
- package/docs/guide/plugin-api.md +31 -3
- package/docs/guide/plugin-guide.md +26 -3
- package/package.json +4 -2
- 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
|
@@ -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;
|