@oh-just-another/react-ui 0.57.0
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/CHANGELOG.md +22 -0
- package/LICENSE +21 -0
- package/README.md +54 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/bottom-sheet.d.ts +26 -0
- package/dist/bottom-sheet.d.ts.map +1 -0
- package/dist/bottom-sheet.js +87 -0
- package/dist/bottom-sheet.js.map +1 -0
- package/dist/button-group.d.ts +14 -0
- package/dist/button-group.d.ts.map +1 -0
- package/dist/button-group.js +3 -0
- package/dist/button-group.js.map +1 -0
- package/dist/color-palette.d.ts +34 -0
- package/dist/color-palette.d.ts.map +1 -0
- package/dist/color-palette.js +77 -0
- package/dist/color-palette.js.map +1 -0
- package/dist/color-swatch-picker.d.ts +29 -0
- package/dist/color-swatch-picker.d.ts.map +1 -0
- package/dist/color-swatch-picker.js +56 -0
- package/dist/color-swatch-picker.js.map +1 -0
- package/dist/command-palette.d.ts +13 -0
- package/dist/command-palette.d.ts.map +1 -0
- package/dist/command-palette.js +146 -0
- package/dist/command-palette.js.map +1 -0
- package/dist/comments-panel.d.ts +27 -0
- package/dist/comments-panel.d.ts.map +1 -0
- package/dist/comments-panel.js +139 -0
- package/dist/comments-panel.js.map +1 -0
- package/dist/constants.d.ts +112 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +119 -0
- package/dist/constants.js.map +1 -0
- package/dist/context-menu-controller.d.ts +41 -0
- package/dist/context-menu-controller.d.ts.map +1 -0
- package/dist/context-menu-controller.js +26 -0
- package/dist/context-menu-controller.js.map +1 -0
- package/dist/context-menu.d.ts +53 -0
- package/dist/context-menu.d.ts.map +1 -0
- package/dist/context-menu.js +333 -0
- package/dist/context-menu.js.map +1 -0
- package/dist/context.d.ts +44 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +95 -0
- package/dist/context.js.map +1 -0
- package/dist/diagram-bars.d.ts +21 -0
- package/dist/diagram-bars.d.ts.map +1 -0
- package/dist/diagram-bars.js +4 -0
- package/dist/diagram-bars.js.map +1 -0
- package/dist/diagram-canvas.d.ts +39 -0
- package/dist/diagram-canvas.d.ts.map +1 -0
- package/dist/diagram-canvas.js +9 -0
- package/dist/diagram-canvas.js.map +1 -0
- package/dist/diagram-root.d.ts +70 -0
- package/dist/diagram-root.d.ts.map +1 -0
- package/dist/diagram-root.js +180 -0
- package/dist/diagram-root.js.map +1 -0
- package/dist/diff-panel.d.ts +25 -0
- package/dist/diff-panel.d.ts.map +1 -0
- package/dist/diff-panel.js +77 -0
- package/dist/diff-panel.js.map +1 -0
- package/dist/edge-style-panel.d.ts +19 -0
- package/dist/edge-style-panel.d.ts.map +1 -0
- package/dist/edge-style-panel.js +120 -0
- package/dist/edge-style-panel.js.map +1 -0
- package/dist/frame-name-editor-overlay.d.ts +13 -0
- package/dist/frame-name-editor-overlay.d.ts.map +1 -0
- package/dist/frame-name-editor-overlay.js +84 -0
- package/dist/frame-name-editor-overlay.js.map +1 -0
- package/dist/frame-panel.d.ts +19 -0
- package/dist/frame-panel.d.ts.map +1 -0
- package/dist/frame-panel.js +66 -0
- package/dist/frame-panel.js.map +1 -0
- package/dist/help-button.d.ts +16 -0
- package/dist/help-button.d.ts.map +1 -0
- package/dist/help-button.js +14 -0
- package/dist/help-button.js.map +1 -0
- package/dist/help-dialog.d.ts +56 -0
- package/dist/help-dialog.d.ts.map +1 -0
- package/dist/help-dialog.js +142 -0
- package/dist/help-dialog.js.map +1 -0
- package/dist/hooks.d.ts +54 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/hooks.js +85 -0
- package/dist/hooks.js.map +1 -0
- package/dist/icon-button.d.ts +28 -0
- package/dist/icon-button.d.ts.map +1 -0
- package/dist/icon-button.js +14 -0
- package/dist/icon-button.js.map +1 -0
- package/dist/index.d.ts +45 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +46 -0
- package/dist/index.js.map +1 -0
- package/dist/layer-panel.d.ts +13 -0
- package/dist/layer-panel.d.ts.map +1 -0
- package/dist/layer-panel.js +109 -0
- package/dist/layer-panel.js.map +1 -0
- package/dist/library-panel.d.ts +33 -0
- package/dist/library-panel.d.ts.map +1 -0
- package/dist/library-panel.js +37 -0
- package/dist/library-panel.js.map +1 -0
- package/dist/link-caption-editor.d.ts +8 -0
- package/dist/link-caption-editor.d.ts.map +1 -0
- package/dist/link-caption-editor.js +65 -0
- package/dist/link-caption-editor.js.map +1 -0
- package/dist/link-drop-shape-menu.d.ts +12 -0
- package/dist/link-drop-shape-menu.d.ts.map +1 -0
- package/dist/link-drop-shape-menu.js +55 -0
- package/dist/link-drop-shape-menu.js.map +1 -0
- package/dist/link-hover-popup.d.ts +2 -0
- package/dist/link-hover-popup.d.ts.map +1 -0
- package/dist/link-hover-popup.js +96 -0
- package/dist/link-hover-popup.js.map +1 -0
- package/dist/main-menu.d.ts +67 -0
- package/dist/main-menu.d.ts.map +1 -0
- package/dist/main-menu.js +243 -0
- package/dist/main-menu.js.map +1 -0
- package/dist/markdown.d.ts +10 -0
- package/dist/markdown.d.ts.map +1 -0
- package/dist/markdown.js +131 -0
- package/dist/markdown.js.map +1 -0
- package/dist/merge-dialog.d.ts +22 -0
- package/dist/merge-dialog.d.ts.map +1 -0
- package/dist/merge-dialog.js +46 -0
- package/dist/merge-dialog.js.map +1 -0
- package/dist/modal.d.ts +19 -0
- package/dist/modal.d.ts.map +1 -0
- package/dist/modal.js +87 -0
- package/dist/modal.js.map +1 -0
- package/dist/palette.d.ts +73 -0
- package/dist/palette.d.ts.map +1 -0
- package/dist/palette.js +330 -0
- package/dist/palette.js.map +1 -0
- package/dist/popover.d.ts +33 -0
- package/dist/popover.d.ts.map +1 -0
- package/dist/popover.js +107 -0
- package/dist/popover.js.map +1 -0
- package/dist/property-panel.d.ts +32 -0
- package/dist/property-panel.d.ts.map +1 -0
- package/dist/property-panel.js +728 -0
- package/dist/property-panel.js.map +1 -0
- package/dist/reset-to-content-button.d.ts +10 -0
- package/dist/reset-to-content-button.d.ts.map +1 -0
- package/dist/reset-to-content-button.js +62 -0
- package/dist/reset-to-content-button.js.map +1 -0
- package/dist/segmented-control.d.ts +23 -0
- package/dist/segmented-control.d.ts.map +1 -0
- package/dist/segmented-control.js +5 -0
- package/dist/segmented-control.js.map +1 -0
- package/dist/selection-floating-panel.d.ts +56 -0
- package/dist/selection-floating-panel.d.ts.map +1 -0
- package/dist/selection-floating-panel.js +251 -0
- package/dist/selection-floating-panel.js.map +1 -0
- package/dist/sidebar.d.ts +31 -0
- package/dist/sidebar.d.ts.map +1 -0
- package/dist/sidebar.js +66 -0
- package/dist/sidebar.js.map +1 -0
- package/dist/slider.d.ts +20 -0
- package/dist/slider.d.ts.map +1 -0
- package/dist/slider.js +9 -0
- package/dist/slider.js.map +1 -0
- package/dist/text-editor-overlay.d.ts +16 -0
- package/dist/text-editor-overlay.d.ts.map +1 -0
- package/dist/text-editor-overlay.js +112 -0
- package/dist/text-editor-overlay.js.map +1 -0
- package/dist/toast.d.ts +34 -0
- package/dist/toast.d.ts.map +1 -0
- package/dist/toast.js +89 -0
- package/dist/toast.js.map +1 -0
- package/dist/toolbar.d.ts +149 -0
- package/dist/toolbar.d.ts.map +1 -0
- package/dist/toolbar.js +282 -0
- package/dist/toolbar.js.map +1 -0
- package/dist/tooltip.d.ts +21 -0
- package/dist/tooltip.d.ts.map +1 -0
- package/dist/tooltip.js +217 -0
- package/dist/tooltip.js.map +1 -0
- package/dist/ui-layer.d.ts +22 -0
- package/dist/ui-layer.d.ts.map +1 -0
- package/dist/ui-layer.js +3 -0
- package/dist/ui-layer.js.map +1 -0
- package/dist/versioning.d.ts +32 -0
- package/dist/versioning.d.ts.map +1 -0
- package/dist/versioning.js +206 -0
- package/dist/versioning.js.map +1 -0
- package/package.json +81 -0
- package/src/styles.css +1502 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useReducer, useRef, useState } from "react";
|
|
3
|
+
import { createPortal } from "react-dom";
|
|
4
|
+
import { ExternalLink } from "lucide-react";
|
|
5
|
+
import { useDiagramOptional } from "./hooks.js";
|
|
6
|
+
/**
|
|
7
|
+
* Hover link popup. When the pointer is over an element that carries a
|
|
8
|
+
* (safe) `href`, a small chip appears above it showing the URL and an
|
|
9
|
+
* open button. The pointer can move onto the chip to click it; it closes
|
|
10
|
+
* after a short grace once the pointer leaves both the element and the
|
|
11
|
+
* chip. Hidden while editing text.
|
|
12
|
+
*
|
|
13
|
+
* Reads the hovered link via `editor.linkAt(worldPoint)` on host
|
|
14
|
+
* `pointermove`; positions itself in screen space from the element's
|
|
15
|
+
* world bounds and viewport. Portaled to `document.body`.
|
|
16
|
+
*
|
|
17
|
+
* Opening also works via Cmd/Ctrl-click on the element (state layer).
|
|
18
|
+
*/
|
|
19
|
+
const CLOSE_GRACE_MS = 220;
|
|
20
|
+
export const LinkHoverPopup = () => {
|
|
21
|
+
const editor = useDiagramOptional();
|
|
22
|
+
const [hover, setHover] = useState(null);
|
|
23
|
+
const [, bump] = useReducer((x) => x + 1, 0);
|
|
24
|
+
const overPopup = useRef(false);
|
|
25
|
+
const closeTimer = useRef(null);
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
if (!editor)
|
|
28
|
+
return undefined;
|
|
29
|
+
const host = editor.hostElement;
|
|
30
|
+
if (!host)
|
|
31
|
+
return undefined;
|
|
32
|
+
const clearClose = () => {
|
|
33
|
+
if (closeTimer.current !== null) {
|
|
34
|
+
clearTimeout(closeTimer.current);
|
|
35
|
+
closeTimer.current = null;
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
const scheduleClose = () => {
|
|
39
|
+
clearClose();
|
|
40
|
+
closeTimer.current = setTimeout(() => {
|
|
41
|
+
if (!overPopup.current)
|
|
42
|
+
setHover(null);
|
|
43
|
+
}, CLOSE_GRACE_MS);
|
|
44
|
+
};
|
|
45
|
+
const onMove = (ev) => {
|
|
46
|
+
if (editor.editingTextElement !== null) {
|
|
47
|
+
setHover(null);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const rect = host.getBoundingClientRect();
|
|
51
|
+
const world = editor.screenToWorld({ x: ev.clientX - rect.left, y: ev.clientY - rect.top });
|
|
52
|
+
const link = editor.linkAt(world);
|
|
53
|
+
if (link) {
|
|
54
|
+
clearClose();
|
|
55
|
+
setHover({ href: link.href, bounds: link.bounds });
|
|
56
|
+
}
|
|
57
|
+
else if (!overPopup.current) {
|
|
58
|
+
scheduleClose();
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
const onLeave = () => { scheduleClose(); };
|
|
62
|
+
host.addEventListener("pointermove", onMove);
|
|
63
|
+
host.addEventListener("pointerleave", onLeave);
|
|
64
|
+
// Follow pan / zoom while the popup is open.
|
|
65
|
+
const off = editor.on("change", () => { bump(); });
|
|
66
|
+
return () => {
|
|
67
|
+
host.removeEventListener("pointermove", onMove);
|
|
68
|
+
host.removeEventListener("pointerleave", onLeave);
|
|
69
|
+
off();
|
|
70
|
+
clearClose();
|
|
71
|
+
};
|
|
72
|
+
}, [editor]);
|
|
73
|
+
if (!editor || !hover)
|
|
74
|
+
return null;
|
|
75
|
+
const host = editor.hostElement;
|
|
76
|
+
if (!host)
|
|
77
|
+
return null;
|
|
78
|
+
// World bounds → screen (top-centre of the element), then offset by the
|
|
79
|
+
// host's client rect so the body-portaled chip lands in the right place.
|
|
80
|
+
const v = editor.scene.viewport;
|
|
81
|
+
const hostRect = host.getBoundingClientRect();
|
|
82
|
+
const sx = (hover.bounds.x - v.pan.x) * v.zoom + hostRect.left;
|
|
83
|
+
const sy = (hover.bounds.y - v.pan.y) * v.zoom + hostRect.top;
|
|
84
|
+
const sw = hover.bounds.width * v.zoom;
|
|
85
|
+
const display = hover.href.replace(/^mailto:/, "").replace(/^https?:\/\//, "");
|
|
86
|
+
return createPortal(_jsx("div", { className: "du-link-popup", style: { position: "fixed", left: sx + sw / 2, top: sy, transform: "translate(-50%, -100%)" }, onPointerEnter: () => {
|
|
87
|
+
overPopup.current = true;
|
|
88
|
+
}, onPointerLeave: () => {
|
|
89
|
+
overPopup.current = false;
|
|
90
|
+
setHover(null);
|
|
91
|
+
}, children: _jsxs("a", { className: "du-link-popup-url", href: hover.href, title: hover.href, onClick: (ev) => {
|
|
92
|
+
ev.preventDefault();
|
|
93
|
+
editor.openLink(hover.href);
|
|
94
|
+
}, children: [_jsx("span", { className: "du-link-popup-text", children: display }), _jsx(ExternalLink, { size: 13, strokeWidth: 1.75, "aria-hidden": true })] }) }), document.body);
|
|
95
|
+
};
|
|
96
|
+
//# sourceMappingURL=link-hover-popup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"link-hover-popup.js","sourceRoot":"","sources":["../src/link-hover-popup.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { type CSSProperties, type ReactNode } from "react";
|
|
2
|
+
export interface MainMenuProps {
|
|
3
|
+
readonly children: ReactNode;
|
|
4
|
+
/** Label / icon for the trigger button. Default "≡". */
|
|
5
|
+
readonly trigger?: ReactNode;
|
|
6
|
+
readonly className?: string;
|
|
7
|
+
readonly style?: CSSProperties;
|
|
8
|
+
}
|
|
9
|
+
export declare const MainMenu: {
|
|
10
|
+
({ children, trigger, className, style, }: MainMenuProps): import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
Item: ({ children, onClick, shortcut, disabled, active, icon }: MainMenuItemProps) => import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
ItemLink: ({ children, href, external }: MainMenuItemLinkProps) => import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
Separator: () => import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
Group: ({ title, children }: {
|
|
15
|
+
title: string;
|
|
16
|
+
children: ReactNode;
|
|
17
|
+
}) => import("react/jsx-runtime").JSX.Element;
|
|
18
|
+
Toggle: <T extends string>({ value, onChange, options, }: MainMenuToggleProps<T>) => import("react/jsx-runtime").JSX.Element;
|
|
19
|
+
Submenu: ({ children, label, icon, disabled }: MainMenuSubmenuProps) => import("react/jsx-runtime").JSX.Element;
|
|
20
|
+
};
|
|
21
|
+
export interface MainMenuItemProps {
|
|
22
|
+
readonly children: ReactNode;
|
|
23
|
+
readonly onClick?: () => void;
|
|
24
|
+
readonly shortcut?: string;
|
|
25
|
+
readonly disabled?: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Shows a leading checkmark — used by submenu items that act as a
|
|
28
|
+
* radio group (theme switcher, language switcher, etc.) to signal
|
|
29
|
+
* which option is currently active.
|
|
30
|
+
*/
|
|
31
|
+
readonly active?: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Optional leading icon rendered before the label. Sized to the same
|
|
34
|
+
* 14×14 footprint as the active-check column so the columns stay
|
|
35
|
+
* aligned across mixed icon / no-icon items.
|
|
36
|
+
*/
|
|
37
|
+
readonly icon?: ReactNode;
|
|
38
|
+
}
|
|
39
|
+
export interface MainMenuItemLinkProps {
|
|
40
|
+
readonly children: ReactNode;
|
|
41
|
+
readonly href: string;
|
|
42
|
+
readonly external?: boolean;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Horizontal segmented control inside a menu — a theme / language
|
|
46
|
+
* toggle. Renders `options` as a pill, highlighting the active one with
|
|
47
|
+
* the accent colour. The menu stays open after a click so the user can
|
|
48
|
+
* try several values without re-opening the dropdown.
|
|
49
|
+
*/
|
|
50
|
+
export interface MainMenuToggleProps<T extends string> {
|
|
51
|
+
readonly value: T;
|
|
52
|
+
readonly onChange: (next: T) => void;
|
|
53
|
+
readonly options: readonly {
|
|
54
|
+
value: T;
|
|
55
|
+
label: string;
|
|
56
|
+
icon?: ReactNode;
|
|
57
|
+
}[];
|
|
58
|
+
}
|
|
59
|
+
export interface MainMenuSubmenuProps {
|
|
60
|
+
readonly children: ReactNode;
|
|
61
|
+
/** Trigger row label. Same render style as `MainMenu.Item`. */
|
|
62
|
+
readonly label: ReactNode;
|
|
63
|
+
/** Optional leading icon — same sizing rules as `MainMenu.Item`. */
|
|
64
|
+
readonly icon?: ReactNode;
|
|
65
|
+
readonly disabled?: boolean;
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=main-menu.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main-menu.d.ts","sourceRoot":"","sources":["../src/main-menu.tsx"],"names":[],"mappings":"AAAA,OAAO,EAQL,KAAK,aAAa,EAClB,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AA0Cf,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC;IAC7B,wDAAwD;IACxD,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC;IAC7B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,CAAC,EAAE,aAAa,CAAC;CAChC;AAED,eAAO,MAAM,QAAQ;+CAKlB,aAAa;oEAgHuD,iBAAiB;6CAmDxC,qBAAqB;;iCA6BjC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,SAAS,CAAA;KAAE;aA6B1D,CAAC,SAAS,MAAM,iCAI7B,mBAAmB,CAAC,CAAC,CAAC;mDAgF6B,oBAAoB;CAzOzE,CAAC;AAqBF,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC;IAC7B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IAC9B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B;;;;OAIG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B;;;;OAIG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC;CAC3B;AA+CD,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CAC7B;AAgDD;;;;;GAKG;AACH,MAAM,WAAW,mBAAmB,CAAC,CAAC,SAAS,MAAM;IACnD,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;IAClB,QAAQ,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC;IACrC,QAAQ,CAAC,OAAO,EAAE,SAAS;QAAE,KAAK,EAAE,CAAC,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,SAAS,CAAA;KAAE,EAAE,CAAC;CAC5E;AA6ED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC;IAC7B,+DAA+D;IAC/D,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAC1B,oEAAoE;IACpE,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC;IAC1B,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CAC7B"}
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { createContext, useCallback, useContext, useEffect, useId, useRef, useState, } from "react";
|
|
3
|
+
import { Check, ChevronRight, Menu as MenuIcon } from "lucide-react";
|
|
4
|
+
/** Pixel size for the trigger icon — matches the toolbar tool buttons. */
|
|
5
|
+
const TRIGGER_ICON_SIZE = 16;
|
|
6
|
+
const TRIGGER_ICON_STROKE = 1.75;
|
|
7
|
+
const Ctx = createContext(null);
|
|
8
|
+
const useMenuCtx = () => {
|
|
9
|
+
const ctx = useContext(Ctx);
|
|
10
|
+
return (ctx ?? {
|
|
11
|
+
close: () => {
|
|
12
|
+
/* no-op: fallback when used outside a MainMenu provider */
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
};
|
|
16
|
+
export const MainMenu = ({ children, trigger = _jsx(MenuIcon, { size: TRIGGER_ICON_SIZE, strokeWidth: TRIGGER_ICON_STROKE }), className, style, }) => {
|
|
17
|
+
const [open, setOpen] = useState(false);
|
|
18
|
+
const ref = useRef(null);
|
|
19
|
+
const menuId = useId();
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
if (!open)
|
|
22
|
+
return undefined;
|
|
23
|
+
const onDown = (ev) => {
|
|
24
|
+
if (!ref.current)
|
|
25
|
+
return;
|
|
26
|
+
if (ref.current.contains(ev.target))
|
|
27
|
+
return;
|
|
28
|
+
setOpen(false);
|
|
29
|
+
};
|
|
30
|
+
const onKey = (ev) => {
|
|
31
|
+
if (ev.key === "Escape")
|
|
32
|
+
setOpen(false);
|
|
33
|
+
};
|
|
34
|
+
// Listen on both `mousedown` and `pointerdown`. The canvas surface
|
|
35
|
+
// captures pointer events; `mousedown` still fires on the document,
|
|
36
|
+
// but for some touch / pen interactions only `pointerdown` does.
|
|
37
|
+
// Subscribing to both closes the menu reliably for every input type.
|
|
38
|
+
window.addEventListener("mousedown", onDown);
|
|
39
|
+
window.addEventListener("pointerdown", onDown);
|
|
40
|
+
window.addEventListener("keydown", onKey);
|
|
41
|
+
return () => {
|
|
42
|
+
window.removeEventListener("mousedown", onDown);
|
|
43
|
+
window.removeEventListener("pointerdown", onDown);
|
|
44
|
+
window.removeEventListener("keydown", onKey);
|
|
45
|
+
};
|
|
46
|
+
}, [open]);
|
|
47
|
+
const close = useCallback(() => { setOpen(false); }, []);
|
|
48
|
+
const containerStyle = {
|
|
49
|
+
position: "relative",
|
|
50
|
+
display: "inline-flex",
|
|
51
|
+
...style,
|
|
52
|
+
};
|
|
53
|
+
const panelStyle = {
|
|
54
|
+
position: "absolute",
|
|
55
|
+
top: "calc(100% + 6px)",
|
|
56
|
+
left: 0,
|
|
57
|
+
minWidth: 200,
|
|
58
|
+
background: "var(--menu-bg)",
|
|
59
|
+
color: "var(--menu-text)",
|
|
60
|
+
border: "1px solid var(--menu-border)",
|
|
61
|
+
borderRadius: 6,
|
|
62
|
+
boxShadow: "var(--du-ui-shadow)",
|
|
63
|
+
padding: 4,
|
|
64
|
+
zIndex: 900,
|
|
65
|
+
};
|
|
66
|
+
return (_jsxs("div", { ref: ref, className: className, style: containerStyle, children: [_jsx("button", { type: "button", className: `du-icon-button du-icon-button-flat${open ? " is-active" : ""}`, "aria-haspopup": "menu", "aria-expanded": open, "aria-controls": menuId, "aria-label": "Main menu", title: "Main menu", onClick: () => { setOpen((p) => !p); }, children: trigger }), open ? (_jsx("div", { id: menuId, role: "menu", style: panelStyle, children: _jsx(Ctx.Provider, { value: { close }, children: children }) })) : null] }));
|
|
67
|
+
};
|
|
68
|
+
const itemBase = {
|
|
69
|
+
display: "block",
|
|
70
|
+
width: "100%",
|
|
71
|
+
textAlign: "left",
|
|
72
|
+
background: "transparent",
|
|
73
|
+
color: "inherit",
|
|
74
|
+
border: "none",
|
|
75
|
+
borderRadius: 4,
|
|
76
|
+
padding: "6px 10px",
|
|
77
|
+
font: "inherit",
|
|
78
|
+
fontSize: 13,
|
|
79
|
+
cursor: "pointer",
|
|
80
|
+
};
|
|
81
|
+
const itemHoverable = (extra) => ({
|
|
82
|
+
...itemBase,
|
|
83
|
+
...extra,
|
|
84
|
+
});
|
|
85
|
+
const Item = ({ children, onClick, shortcut, disabled, active, icon }) => {
|
|
86
|
+
const { close } = useMenuCtx();
|
|
87
|
+
return (_jsxs("button", { type: "button", role: "menuitem", disabled: disabled, onClick: () => {
|
|
88
|
+
if (disabled)
|
|
89
|
+
return;
|
|
90
|
+
onClick?.();
|
|
91
|
+
close();
|
|
92
|
+
}, style: {
|
|
93
|
+
...itemHoverable(),
|
|
94
|
+
cursor: disabled ? "not-allowed" : "pointer",
|
|
95
|
+
opacity: disabled ? 0.4 : 1,
|
|
96
|
+
display: "flex",
|
|
97
|
+
alignItems: "center",
|
|
98
|
+
justifyContent: "space-between",
|
|
99
|
+
gap: 12,
|
|
100
|
+
}, children: [_jsxs("span", { style: { display: "inline-flex", alignItems: "center", gap: 8 }, children: [_jsx("span", { "aria-hidden": true, style: {
|
|
101
|
+
width: 14,
|
|
102
|
+
height: 14,
|
|
103
|
+
display: "inline-flex",
|
|
104
|
+
alignItems: "center",
|
|
105
|
+
justifyContent: "center",
|
|
106
|
+
color: active ? "var(--du-accent, #1a73e8)" : "var(--du-text-muted, #888)",
|
|
107
|
+
}, children: active ? _jsx(Check, { size: 12, strokeWidth: 2.25 }) : icon ?? "" }), children] }), shortcut ? (_jsx("span", { style: { color: "var(--muted, #888)", fontSize: 11 }, children: shortcut })) : null] }));
|
|
108
|
+
};
|
|
109
|
+
const ItemLink = ({ children, href, external }) => {
|
|
110
|
+
const { close } = useMenuCtx();
|
|
111
|
+
return (_jsx("a", { role: "menuitem", href: href, target: external ? "_blank" : undefined, rel: external ? "noreferrer noopener" : undefined, onClick: close, style: {
|
|
112
|
+
...itemHoverable({ textDecoration: "none" }),
|
|
113
|
+
color: "var(--text, #ddd)",
|
|
114
|
+
}, children: children }));
|
|
115
|
+
};
|
|
116
|
+
const Separator = () => (_jsx("hr", { style: {
|
|
117
|
+
margin: "4px 6px",
|
|
118
|
+
border: "none",
|
|
119
|
+
borderTop: "1px solid var(--border, #2a2a2a)",
|
|
120
|
+
} }));
|
|
121
|
+
const Group = ({ title, children }) => (_jsxs("div", { children: [_jsx("div", { style: {
|
|
122
|
+
padding: "6px 10px 2px",
|
|
123
|
+
fontSize: 11,
|
|
124
|
+
textTransform: "uppercase",
|
|
125
|
+
letterSpacing: 0.5,
|
|
126
|
+
color: "var(--muted, #888)",
|
|
127
|
+
}, children: title }), children] }));
|
|
128
|
+
const Toggle = ({ value, onChange, options, }) => {
|
|
129
|
+
return (_jsx("div", { role: "radiogroup", style: {
|
|
130
|
+
display: "flex",
|
|
131
|
+
margin: "4px 8px 6px",
|
|
132
|
+
background: "var(--menu-divider, #2a2a2a)",
|
|
133
|
+
borderRadius: 6,
|
|
134
|
+
padding: 2,
|
|
135
|
+
gap: 2,
|
|
136
|
+
}, children: options.map((opt) => {
|
|
137
|
+
const active = opt.value === value;
|
|
138
|
+
return (_jsx("button", { type: "button", role: "radio", "aria-checked": active, title: opt.label, "aria-label": opt.label, onClick: () => { onChange(opt.value); }, style: {
|
|
139
|
+
flex: 1,
|
|
140
|
+
display: "inline-flex",
|
|
141
|
+
alignItems: "center",
|
|
142
|
+
justifyContent: "center",
|
|
143
|
+
gap: 4,
|
|
144
|
+
minHeight: 26,
|
|
145
|
+
padding: "0 8px",
|
|
146
|
+
background: active ? "var(--menu-bg, #1a1a1a)" : "transparent",
|
|
147
|
+
color: active ? "var(--text, #ddd)" : "var(--muted, #888)",
|
|
148
|
+
border: "none",
|
|
149
|
+
borderRadius: 4,
|
|
150
|
+
cursor: "pointer",
|
|
151
|
+
fontSize: 12,
|
|
152
|
+
fontWeight: active ? 600 : 400,
|
|
153
|
+
boxShadow: active ? "0 1px 2px rgba(0, 0, 0, 0.15)" : "none",
|
|
154
|
+
transition: "background 0.12s ease, color 0.12s ease",
|
|
155
|
+
}, children: opt.icon ?? opt.label }, opt.value));
|
|
156
|
+
}) }));
|
|
157
|
+
};
|
|
158
|
+
/**
|
|
159
|
+
* Nested submenu — opens a child panel to the right of the parent item
|
|
160
|
+
* on hover (with a small close-delay so a mouse moving diagonally toward
|
|
161
|
+
* the child doesn't accidentally collapse the panel). Also opens on
|
|
162
|
+
* click for touch / keyboard activation.
|
|
163
|
+
*
|
|
164
|
+
* Children are typically `MainMenu.Item`s. The submenu inherits the
|
|
165
|
+
* parent menu's `close()` context, so child item clicks collapse the
|
|
166
|
+
* whole menu chain.
|
|
167
|
+
*
|
|
168
|
+
* <MainMenu.Submenu icon={<Download/>} label="Export…">
|
|
169
|
+
* <MainMenu.Item onClick={exportPng}>PNG</MainMenu.Item>
|
|
170
|
+
* <MainMenu.Item onClick={exportSvg}>SVG</MainMenu.Item>
|
|
171
|
+
* </MainMenu.Submenu>
|
|
172
|
+
*
|
|
173
|
+
* Positioning is fixed to "right of trigger, top-aligned with the
|
|
174
|
+
* trigger row".
|
|
175
|
+
*/
|
|
176
|
+
const SUBMENU_CLOSE_DELAY_MS = 120;
|
|
177
|
+
const Submenu = ({ children, label, icon, disabled }) => {
|
|
178
|
+
const [open, setOpen] = useState(false);
|
|
179
|
+
const closeTimerRef = useRef(null);
|
|
180
|
+
const cancelClose = useCallback(() => {
|
|
181
|
+
if (closeTimerRef.current !== null) {
|
|
182
|
+
window.clearTimeout(closeTimerRef.current);
|
|
183
|
+
closeTimerRef.current = null;
|
|
184
|
+
}
|
|
185
|
+
}, []);
|
|
186
|
+
const scheduleClose = useCallback(() => {
|
|
187
|
+
cancelClose();
|
|
188
|
+
closeTimerRef.current = window.setTimeout(() => {
|
|
189
|
+
setOpen(false);
|
|
190
|
+
closeTimerRef.current = null;
|
|
191
|
+
}, SUBMENU_CLOSE_DELAY_MS);
|
|
192
|
+
}, [cancelClose]);
|
|
193
|
+
// Clear a pending close-timer on unmount so it doesn't fire on a
|
|
194
|
+
// detached component.
|
|
195
|
+
useEffect(() => cancelClose, [cancelClose]);
|
|
196
|
+
const panelStyle = {
|
|
197
|
+
position: "absolute",
|
|
198
|
+
top: -4,
|
|
199
|
+
left: "100%",
|
|
200
|
+
marginLeft: 4,
|
|
201
|
+
minWidth: 220,
|
|
202
|
+
background: "var(--menu-bg)",
|
|
203
|
+
color: "var(--menu-text)",
|
|
204
|
+
border: "1px solid var(--menu-border)",
|
|
205
|
+
borderRadius: 6,
|
|
206
|
+
boxShadow: "var(--du-ui-shadow)",
|
|
207
|
+
padding: 4,
|
|
208
|
+
zIndex: 1000,
|
|
209
|
+
};
|
|
210
|
+
return (_jsxs("div", { style: { position: "relative" }, onMouseEnter: () => {
|
|
211
|
+
if (disabled)
|
|
212
|
+
return;
|
|
213
|
+
cancelClose();
|
|
214
|
+
setOpen(true);
|
|
215
|
+
}, onMouseLeave: scheduleClose, children: [_jsxs("button", { type: "button", role: "menuitem", disabled: disabled, "aria-haspopup": "menu", "aria-expanded": open, onClick: () => {
|
|
216
|
+
if (disabled)
|
|
217
|
+
return;
|
|
218
|
+
cancelClose();
|
|
219
|
+
setOpen((p) => !p);
|
|
220
|
+
}, style: {
|
|
221
|
+
...itemHoverable(),
|
|
222
|
+
cursor: disabled ? "not-allowed" : "pointer",
|
|
223
|
+
opacity: disabled ? 0.4 : 1,
|
|
224
|
+
display: "flex",
|
|
225
|
+
alignItems: "center",
|
|
226
|
+
justifyContent: "space-between",
|
|
227
|
+
gap: 12,
|
|
228
|
+
}, children: [_jsxs("span", { style: { display: "inline-flex", alignItems: "center", gap: 8 }, children: [_jsx("span", { "aria-hidden": true, style: {
|
|
229
|
+
width: 14,
|
|
230
|
+
height: 14,
|
|
231
|
+
display: "inline-flex",
|
|
232
|
+
alignItems: "center",
|
|
233
|
+
justifyContent: "center",
|
|
234
|
+
color: "var(--du-text-muted, #888)",
|
|
235
|
+
}, children: icon ?? "" }), label] }), _jsx(ChevronRight, { size: 12, strokeWidth: 2.25, "aria-hidden": true })] }), open ? (_jsx("div", { role: "menu", style: panelStyle, children: children })) : null] }));
|
|
236
|
+
};
|
|
237
|
+
MainMenu.Item = Item;
|
|
238
|
+
MainMenu.ItemLink = ItemLink;
|
|
239
|
+
MainMenu.Separator = Separator;
|
|
240
|
+
MainMenu.Group = Group;
|
|
241
|
+
MainMenu.Toggle = Toggle;
|
|
242
|
+
MainMenu.Submenu = Submenu;
|
|
243
|
+
//# sourceMappingURL=main-menu.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main-menu.js","sourceRoot":"","sources":["../src/main-menu.tsx"],"names":[],"mappings":";AAAA,OAAO,EACL,aAAa,EACb,WAAW,EACX,UAAU,EACV,SAAS,EACT,KAAK,EACL,MAAM,EACN,QAAQ,GAGT,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,IAAI,QAAQ,EAAE,MAAM,cAAc,CAAC;AAErE,0EAA0E;AAC1E,MAAM,iBAAiB,GAAG,EAAE,CAAC;AAC7B,MAAM,mBAAmB,GAAG,IAAI,CAAC;AAwBjC,MAAM,GAAG,GAAG,aAAa,CAAqB,IAAI,CAAC,CAAC;AAEpD,MAAM,UAAU,GAAG,GAAgB,EAAE;IACnC,MAAM,GAAG,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;IAC5B,OAAO,CACL,GAAG,IAAI;QACL,KAAK,EAAE,GAAG,EAAE;YACV,2DAA2D;QAC7D,CAAC;KACF,CACF,CAAC;AACJ,CAAC,CAAC;AAUF,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,EACvB,QAAQ,EACR,OAAO,GAAG,KAAC,QAAQ,IAAC,IAAI,EAAE,iBAAiB,EAAE,WAAW,EAAE,mBAAmB,GAAI,EACjF,SAAS,EACT,KAAK,GACS,EAAE,EAAE;IAClB,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IACxC,MAAM,GAAG,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAC;IACzC,MAAM,MAAM,GAAG,KAAK,EAAE,CAAC;IAEvB,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,IAAI;YAAE,OAAO,SAAS,CAAC;QAC5B,MAAM,MAAM,GAAG,CAAC,EAA6B,EAAQ,EAAE;YACrD,IAAI,CAAC,GAAG,CAAC,OAAO;gBAAE,OAAO;YACzB,IAAI,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAc,CAAC;gBAAE,OAAO;YACpD,OAAO,CAAC,KAAK,CAAC,CAAC;QACjB,CAAC,CAAC;QACF,MAAM,KAAK,GAAG,CAAC,EAAiB,EAAQ,EAAE;YACxC,IAAI,EAAE,CAAC,GAAG,KAAK,QAAQ;gBAAE,OAAO,CAAC,KAAK,CAAC,CAAC;QAC1C,CAAC,CAAC;QACF,mEAAmE;QACnE,oEAAoE;QACpE,iEAAiE;QACjE,qEAAqE;QACrE,MAAM,CAAC,gBAAgB,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;QAC7C,MAAM,CAAC,gBAAgB,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;QAC/C,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QAC1C,OAAO,GAAG,EAAE;YACV,MAAM,CAAC,mBAAmB,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;YAChD,MAAM,CAAC,mBAAmB,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;YAClD,MAAM,CAAC,mBAAmB,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QAC/C,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;IAEX,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAEzD,MAAM,cAAc,GAAkB;QACpC,QAAQ,EAAE,UAAU;QACpB,OAAO,EAAE,aAAa;QACtB,GAAG,KAAK;KACT,CAAC;IAEF,MAAM,UAAU,GAAkB;QAChC,QAAQ,EAAE,UAAU;QACpB,GAAG,EAAE,kBAAkB;QACvB,IAAI,EAAE,CAAC;QACP,QAAQ,EAAE,GAAG;QACb,UAAU,EAAE,gBAAgB;QAC5B,KAAK,EAAE,kBAAkB;QACzB,MAAM,EAAE,8BAA8B;QACtC,YAAY,EAAE,CAAC;QACf,SAAS,EAAE,qBAAqB;QAChC,OAAO,EAAE,CAAC;QACV,MAAM,EAAE,GAAG;KACZ,CAAC;IAEF,OAAO,CACL,eAAK,GAAG,EAAE,GAAG,EAAE,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,cAAc,aACxD,iBACE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAE,qCAAqC,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,EAAE,mBAC5D,MAAM,mBACL,IAAI,mBACJ,MAAM,gBACV,WAAW,EACtB,KAAK,EAAC,WAAW,EACjB,OAAO,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,YAErC,OAAO,GACD,EACR,IAAI,CAAC,CAAC,CAAC,CACN,cAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAC,MAAM,EAAC,KAAK,EAAE,UAAU,YAC5C,KAAC,GAAG,CAAC,QAAQ,IAAC,KAAK,EAAE,EAAE,KAAK,EAAE,YAAG,QAAQ,GAAgB,GACrD,CACP,CAAC,CAAC,CAAC,IAAI,IACJ,CACP,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,QAAQ,GAAkB;IAC9B,OAAO,EAAE,OAAO;IAChB,KAAK,EAAE,MAAM;IACb,SAAS,EAAE,MAAM;IACjB,UAAU,EAAE,aAAa;IACzB,KAAK,EAAE,SAAS;IAChB,MAAM,EAAE,MAAM;IACd,YAAY,EAAE,CAAC;IACf,OAAO,EAAE,UAAU;IACnB,IAAI,EAAE,SAAS;IACf,QAAQ,EAAE,EAAE;IACZ,MAAM,EAAE,SAAS;CAClB,CAAC;AAEF,MAAM,aAAa,GAAG,CAAC,KAAqB,EAAiB,EAAE,CAAC,CAAC;IAC/D,GAAG,QAAQ;IACX,GAAG,KAAK;CACT,CAAC,CAAC;AAqBH,MAAM,IAAI,GAAG,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAqB,EAAE,EAAE;IAC1F,MAAM,EAAE,KAAK,EAAE,GAAG,UAAU,EAAE,CAAC;IAC/B,OAAO,CACL,kBACE,IAAI,EAAC,QAAQ,EACb,IAAI,EAAC,UAAU,EACf,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,GAAG,EAAE;YACZ,IAAI,QAAQ;gBAAE,OAAO;YACrB,OAAO,EAAE,EAAE,CAAC;YACZ,KAAK,EAAE,CAAC;QACV,CAAC,EACD,KAAK,EAAE;YACL,GAAG,aAAa,EAAE;YAClB,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS;YAC5C,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAC3B,OAAO,EAAE,MAAM;YACf,UAAU,EAAE,QAAQ;YACpB,cAAc,EAAE,eAAe;YAC/B,GAAG,EAAE,EAAE;SACR,aAED,gBAAM,KAAK,EAAE,EAAE,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,EAAE,aACnE,oCAEE,KAAK,EAAE;4BACL,KAAK,EAAE,EAAE;4BACT,MAAM,EAAE,EAAE;4BACV,OAAO,EAAE,aAAa;4BACtB,UAAU,EAAE,QAAQ;4BACpB,cAAc,EAAE,QAAQ;4BACxB,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,2BAA2B,CAAC,CAAC,CAAC,4BAA4B;yBAC3E,YAEA,MAAM,CAAC,CAAC,CAAC,KAAC,KAAK,IAAC,IAAI,EAAE,EAAE,EAAE,WAAW,EAAE,IAAI,GAAI,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,GACxD,EACN,QAAQ,IACJ,EACN,QAAQ,CAAC,CAAC,CAAC,CACV,eAAM,KAAK,EAAE,EAAE,KAAK,EAAE,oBAAoB,EAAE,QAAQ,EAAE,EAAE,EAAE,YAAG,QAAQ,GAAQ,CAC9E,CAAC,CAAC,CAAC,IAAI,IACD,CACV,CAAC;AACJ,CAAC,CAAC;AAQF,MAAM,QAAQ,GAAG,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAyB,EAAE,EAAE;IACvE,MAAM,EAAE,KAAK,EAAE,GAAG,UAAU,EAAE,CAAC;IAC/B,OAAO,CACL,YACE,IAAI,EAAC,UAAU,EACf,IAAI,EAAE,IAAI,EACV,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,EACvC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,SAAS,EACjD,OAAO,EAAE,KAAK,EACd,KAAK,EAAE;YACL,GAAG,aAAa,CAAC,EAAE,cAAc,EAAE,MAAM,EAAE,CAAC;YAC5C,KAAK,EAAE,mBAAmB;SAC3B,YAEA,QAAQ,GACP,CACL,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,SAAS,GAAG,GAAG,EAAE,CAAC,CACtB,aACE,KAAK,EAAE;QACL,MAAM,EAAE,SAAS;QACjB,MAAM,EAAE,MAAM;QACd,SAAS,EAAE,kCAAkC;KAC9C,GACD,CACH,CAAC;AAEF,MAAM,KAAK,GAAG,CAAC,EAAE,KAAK,EAAE,QAAQ,EAA0C,EAAE,EAAE,CAAC,CAC7E,0BACE,cACE,KAAK,EAAE;gBACL,OAAO,EAAE,cAAc;gBACvB,QAAQ,EAAE,EAAE;gBACZ,aAAa,EAAE,WAAW;gBAC1B,aAAa,EAAE,GAAG;gBAClB,KAAK,EAAE,oBAAoB;aAC5B,YAEA,KAAK,GACF,EACL,QAAQ,IACL,CACP,CAAC;AAcF,MAAM,MAAM,GAAG,CAAmB,EAChC,KAAK,EACL,QAAQ,EACR,OAAO,GACgB,EAAE,EAAE;IAC3B,OAAO,CACL,cACE,IAAI,EAAC,YAAY,EACjB,KAAK,EAAE;YACL,OAAO,EAAE,MAAM;YACf,MAAM,EAAE,aAAa;YACrB,UAAU,EAAE,8BAA8B;YAC1C,YAAY,EAAE,CAAC;YACf,OAAO,EAAE,CAAC;YACV,GAAG,EAAE,CAAC;SACP,YAEA,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;YACnB,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,KAAK,KAAK,CAAC;YACnC,OAAO,CACL,iBAEE,IAAI,EAAC,QAAQ,EACb,IAAI,EAAC,OAAO,kBACE,MAAM,EACpB,KAAK,EAAE,GAAG,CAAC,KAAK,gBACJ,GAAG,CAAC,KAAK,EACrB,OAAO,EAAE,GAAG,EAAE,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EACvC,KAAK,EAAE;oBACL,IAAI,EAAE,CAAC;oBACP,OAAO,EAAE,aAAa;oBACtB,UAAU,EAAE,QAAQ;oBACpB,cAAc,EAAE,QAAQ;oBACxB,GAAG,EAAE,CAAC;oBACN,SAAS,EAAE,EAAE;oBACb,OAAO,EAAE,OAAO;oBAChB,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC,CAAC,aAAa;oBAC9D,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,oBAAoB;oBAC1D,MAAM,EAAE,MAAM;oBACd,YAAY,EAAE,CAAC;oBACf,MAAM,EAAE,SAAS;oBACjB,QAAQ,EAAE,EAAE;oBACZ,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG;oBAC9B,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,+BAA+B,CAAC,CAAC,CAAC,MAAM;oBAC5D,UAAU,EAAE,yCAAyC;iBACtD,YAEA,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,KAAK,IA1BjB,GAAG,CAAC,KAAK,CA2BP,CACV,CAAC;QACJ,CAAC,CAAC,GACE,CACP,CAAC;AACJ,CAAC,CAAC;AAEF;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,sBAAsB,GAAG,GAAG,CAAC;AAWnC,MAAM,OAAO,GAAG,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAwB,EAAE,EAAE;IAC5E,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IACxC,MAAM,aAAa,GAAG,MAAM,CAAgB,IAAI,CAAC,CAAC;IAElD,MAAM,WAAW,GAAG,WAAW,CAAC,GAAS,EAAE;QACzC,IAAI,aAAa,CAAC,OAAO,KAAK,IAAI,EAAE,CAAC;YACnC,MAAM,CAAC,YAAY,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;YAC3C,aAAa,CAAC,OAAO,GAAG,IAAI,CAAC;QAC/B,CAAC;IACH,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,aAAa,GAAG,WAAW,CAAC,GAAS,EAAE;QAC3C,WAAW,EAAE,CAAC;QACd,aAAa,CAAC,OAAO,GAAG,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE;YAC7C,OAAO,CAAC,KAAK,CAAC,CAAC;YACf,aAAa,CAAC,OAAO,GAAG,IAAI,CAAC;QAC/B,CAAC,EAAE,sBAAsB,CAAC,CAAC;IAC7B,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC;IAElB,iEAAiE;IACjE,sBAAsB;IACtB,SAAS,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC;IAE5C,MAAM,UAAU,GAAkB;QAChC,QAAQ,EAAE,UAAU;QACpB,GAAG,EAAE,CAAC,CAAC;QACP,IAAI,EAAE,MAAM;QACZ,UAAU,EAAE,CAAC;QACb,QAAQ,EAAE,GAAG;QACb,UAAU,EAAE,gBAAgB;QAC5B,KAAK,EAAE,kBAAkB;QACzB,MAAM,EAAE,8BAA8B;QACtC,YAAY,EAAE,CAAC;QACf,SAAS,EAAE,qBAAqB;QAChC,OAAO,EAAE,CAAC;QACV,MAAM,EAAE,IAAI;KACb,CAAC;IAEF,OAAO,CACL,eACE,KAAK,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,EAC/B,YAAY,EAAE,GAAG,EAAE;YACjB,IAAI,QAAQ;gBAAE,OAAO;YACrB,WAAW,EAAE,CAAC;YACd,OAAO,CAAC,IAAI,CAAC,CAAC;QAChB,CAAC,EACD,YAAY,EAAE,aAAa,aAE3B,kBACE,IAAI,EAAC,QAAQ,EACb,IAAI,EAAC,UAAU,EACf,QAAQ,EAAE,QAAQ,mBACJ,MAAM,mBACL,IAAI,EACnB,OAAO,EAAE,GAAG,EAAE;oBACZ,IAAI,QAAQ;wBAAE,OAAO;oBACrB,WAAW,EAAE,CAAC;oBACd,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;gBACrB,CAAC,EACD,KAAK,EAAE;oBACL,GAAG,aAAa,EAAE;oBAClB,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS;oBAC5C,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;oBAC3B,OAAO,EAAE,MAAM;oBACf,UAAU,EAAE,QAAQ;oBACpB,cAAc,EAAE,eAAe;oBAC/B,GAAG,EAAE,EAAE;iBACR,aAED,gBAAM,KAAK,EAAE,EAAE,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,EAAE,aACnE,oCAEE,KAAK,EAAE;oCACL,KAAK,EAAE,EAAE;oCACT,MAAM,EAAE,EAAE;oCACV,OAAO,EAAE,aAAa;oCACtB,UAAU,EAAE,QAAQ;oCACpB,cAAc,EAAE,QAAQ;oCACxB,KAAK,EAAE,4BAA4B;iCACpC,YAEA,IAAI,IAAI,EAAE,GACN,EACN,KAAK,IACD,EACP,KAAC,YAAY,IAAC,IAAI,EAAE,EAAE,EAAE,WAAW,EAAE,IAAI,wBAAgB,IAClD,EACR,IAAI,CAAC,CAAC,CAAC,CACN,cAAK,IAAI,EAAC,MAAM,EAAC,KAAK,EAAE,UAAU,YAC/B,QAAQ,GACL,CACP,CAAC,CAAC,CAAC,IAAI,IACJ,CACP,CAAC;AACJ,CAAC,CAAC;AAEF,QAAQ,CAAC,IAAI,GAAG,IAAI,CAAC;AACrB,QAAQ,CAAC,QAAQ,GAAG,QAAQ,CAAC;AAC7B,QAAQ,CAAC,SAAS,GAAG,SAAS,CAAC;AAC/B,QAAQ,CAAC,KAAK,GAAG,KAAK,CAAC;AACvB,QAAQ,CAAC,MAAM,GAAG,MAAM,CAAC;AACzB,QAAQ,CAAC,OAAO,GAAG,OAAO,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
export interface MarkdownProps {
|
|
3
|
+
readonly text: string;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Render plain text as React nodes with inline markdown. Each line is
|
|
7
|
+
* tokenised separately; lines are joined with `<br />`.
|
|
8
|
+
*/
|
|
9
|
+
export declare const Markdown: ({ text }: MarkdownProps) => ReactNode;
|
|
10
|
+
//# sourceMappingURL=markdown.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../src/markdown.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAuIvC,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED;;;GAGG;AACH,eAAO,MAAM,QAAQ,GAAI,UAAU,aAAa,KAAG,SAWlD,CAAC"}
|
package/dist/markdown.js
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Lightweight regex-only markdown renderer for comment bodies.
|
|
4
|
+
* Supported subset:
|
|
5
|
+
*
|
|
6
|
+
* • `**bold**` → `<strong>`
|
|
7
|
+
* • `*italic*` → `<em>`
|
|
8
|
+
* • `_italic_` → `<em>`
|
|
9
|
+
* • `` `code` `` → `<code>` (inline only)
|
|
10
|
+
* • `[label](url)` → `<a href="...">` (http/https/mailto only)
|
|
11
|
+
*
|
|
12
|
+
* Line breaks become `<br />`; whitespace is otherwise preserved.
|
|
13
|
+
*
|
|
14
|
+
* Every URL goes through `safeUrl()`; everything else is plain text
|
|
15
|
+
* put inside React children, so React escapes it. No
|
|
16
|
+
* `dangerouslySetInnerHTML`.
|
|
17
|
+
*/
|
|
18
|
+
const URL_RE = /^(https?:|mailto:)/i;
|
|
19
|
+
const safeUrl = (raw) => (URL_RE.test(raw) ? raw : null);
|
|
20
|
+
/**
|
|
21
|
+
* Tokenise a single line of comment text. Greedy left-to-right scan;
|
|
22
|
+
* on no match emit the next char as a text token and advance.
|
|
23
|
+
*/
|
|
24
|
+
const tokenise = (line) => {
|
|
25
|
+
const tokens = [];
|
|
26
|
+
let i = 0;
|
|
27
|
+
let textBuf = "";
|
|
28
|
+
const flushText = () => {
|
|
29
|
+
if (textBuf.length > 0) {
|
|
30
|
+
tokens.push({ kind: "text", value: textBuf });
|
|
31
|
+
textBuf = "";
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
while (i < line.length) {
|
|
35
|
+
// **bold**
|
|
36
|
+
if (line[i] === "*" && line[i + 1] === "*") {
|
|
37
|
+
const close = line.indexOf("**", i + 2);
|
|
38
|
+
if (close !== -1) {
|
|
39
|
+
flushText();
|
|
40
|
+
tokens.push({ kind: "bold", value: line.slice(i + 2, close) });
|
|
41
|
+
i = close + 2;
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// *italic* or _italic_
|
|
46
|
+
if (line[i] === "*" || line[i] === "_") {
|
|
47
|
+
const close = line.indexOf(line.charAt(i), i + 1);
|
|
48
|
+
if (close !== -1 && close > i + 1) {
|
|
49
|
+
flushText();
|
|
50
|
+
tokens.push({ kind: "italic", value: line.slice(i + 1, close) });
|
|
51
|
+
i = close + 1;
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
// `code`
|
|
56
|
+
if (line[i] === "`") {
|
|
57
|
+
const close = line.indexOf("`", i + 1);
|
|
58
|
+
if (close !== -1) {
|
|
59
|
+
flushText();
|
|
60
|
+
tokens.push({ kind: "code", value: line.slice(i + 1, close) });
|
|
61
|
+
i = close + 1;
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// [label](url)
|
|
66
|
+
if (line[i] === "[") {
|
|
67
|
+
const labelClose = line.indexOf("](", i + 1);
|
|
68
|
+
if (labelClose !== -1) {
|
|
69
|
+
const urlClose = line.indexOf(")", labelClose + 2);
|
|
70
|
+
if (urlClose !== -1) {
|
|
71
|
+
const label = line.slice(i + 1, labelClose);
|
|
72
|
+
const url = line.slice(labelClose + 2, urlClose);
|
|
73
|
+
const safe = safeUrl(url);
|
|
74
|
+
if (safe) {
|
|
75
|
+
flushText();
|
|
76
|
+
tokens.push({ kind: "link", value: label, href: safe });
|
|
77
|
+
i = urlClose + 1;
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
textBuf += line.charAt(i);
|
|
84
|
+
i++;
|
|
85
|
+
}
|
|
86
|
+
flushText();
|
|
87
|
+
return tokens;
|
|
88
|
+
};
|
|
89
|
+
/**
|
|
90
|
+
* Convert a tokenised line into React children. Text tokens are
|
|
91
|
+
* emitted as plain children so React handles escaping.
|
|
92
|
+
*/
|
|
93
|
+
const tokensToNodes = (tokens, baseKey) => tokens.map((t, i) => {
|
|
94
|
+
const key = `${baseKey}-${i}`;
|
|
95
|
+
if (t.kind === "bold")
|
|
96
|
+
return _jsx("strong", { children: t.value }, key);
|
|
97
|
+
if (t.kind === "italic")
|
|
98
|
+
return _jsx("em", { children: t.value }, key);
|
|
99
|
+
if (t.kind === "code") {
|
|
100
|
+
return (_jsx("code", { style: {
|
|
101
|
+
background: "var(--code-bg, rgba(255,255,255,0.08))",
|
|
102
|
+
padding: "0 4px",
|
|
103
|
+
borderRadius: 2,
|
|
104
|
+
fontFamily: "var(--font-mono, monospace)",
|
|
105
|
+
fontSize: "0.92em",
|
|
106
|
+
}, children: t.value }, key));
|
|
107
|
+
}
|
|
108
|
+
if (t.kind === "link") {
|
|
109
|
+
return (_jsx("a", { href: t.href, target: "_blank", rel: "noopener noreferrer", children: t.value }, key));
|
|
110
|
+
}
|
|
111
|
+
return _jsx("span", { children: t.value }, key);
|
|
112
|
+
});
|
|
113
|
+
/**
|
|
114
|
+
* Render plain text as React nodes with inline markdown. Each line is
|
|
115
|
+
* tokenised separately; lines are joined with `<br />`.
|
|
116
|
+
*/
|
|
117
|
+
export const Markdown = ({ text }) => {
|
|
118
|
+
if (!text)
|
|
119
|
+
return null;
|
|
120
|
+
const lines = text.split("\n");
|
|
121
|
+
const out = [];
|
|
122
|
+
for (let i = 0; i < lines.length; i++) {
|
|
123
|
+
if (i > 0)
|
|
124
|
+
out.push(_jsx("br", {}, `br-${i}`));
|
|
125
|
+
const line = lines[i] ?? "";
|
|
126
|
+
const tokens = tokenise(line);
|
|
127
|
+
out.push(...tokensToNodes(tokens, `l${i}`));
|
|
128
|
+
}
|
|
129
|
+
return out;
|
|
130
|
+
};
|
|
131
|
+
//# sourceMappingURL=markdown.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown.js","sourceRoot":"","sources":["../src/markdown.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type CSSProperties } from "react";
|
|
2
|
+
import { type MergeReport, type SnapshotStore, type VersionId } from "@oh-just-another/versioning";
|
|
3
|
+
/**
|
|
4
|
+
* Modal that drives a three-way branch merge. The host supplies the
|
|
5
|
+
* `SnapshotStore`, source / target branch heads, and an `onApply`
|
|
6
|
+
* callback that takes the merged scene (typically calling
|
|
7
|
+
* `editor.loadScene` and then `store.capture` to record the result).
|
|
8
|
+
*
|
|
9
|
+
* Conflicts are listed per-item; the user picks `source` / `target` /
|
|
10
|
+
* `both` before clicking Apply. Auto-mergeable changes ride along in
|
|
11
|
+
* the merged scene without UI noise.
|
|
12
|
+
*/
|
|
13
|
+
export interface MergeDialogProps {
|
|
14
|
+
readonly store: SnapshotStore;
|
|
15
|
+
readonly sourceVersionId: VersionId;
|
|
16
|
+
readonly targetVersionId: VersionId;
|
|
17
|
+
readonly onApply: (mergedScene: MergeReport["mergedScene"]) => void;
|
|
18
|
+
readonly onCancel: () => void;
|
|
19
|
+
readonly style?: CSSProperties;
|
|
20
|
+
}
|
|
21
|
+
export declare const MergeDialog: ({ store, sourceVersionId, targetVersionId, onApply, onCancel, style, }: MergeDialogProps) => import("react/jsx-runtime").JSX.Element;
|
|
22
|
+
//# sourceMappingURL=merge-dialog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merge-dialog.d.ts","sourceRoot":"","sources":["../src/merge-dialog.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,aAAa,EAAE,MAAM,OAAO,CAAC;AAC9D,OAAO,EAIL,KAAK,WAAW,EAEhB,KAAK,aAAa,EAClB,KAAK,SAAS,EACf,MAAM,6BAA6B,CAAC;AAGrC;;;;;;;;;GASG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAC9B,QAAQ,CAAC,eAAe,EAAE,SAAS,CAAC;IACpC,QAAQ,CAAC,eAAe,EAAE,SAAS,CAAC;IACpC,QAAQ,CAAC,OAAO,EAAE,CAAC,WAAW,EAAE,WAAW,CAAC,aAAa,CAAC,KAAK,IAAI,CAAC;IACpE,QAAQ,CAAC,QAAQ,EAAE,MAAM,IAAI,CAAC;IAC9B,QAAQ,CAAC,KAAK,CAAC,EAAE,aAAa,CAAC;CAChC;AAED,eAAO,MAAM,WAAW,GAAI,wEAOzB,gBAAgB,4CA+ElB,CAAC"}
|