@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.
Files changed (186) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/LICENSE +21 -0
  3. package/README.md +54 -0
  4. package/dist/.tsbuildinfo +1 -0
  5. package/dist/bottom-sheet.d.ts +26 -0
  6. package/dist/bottom-sheet.d.ts.map +1 -0
  7. package/dist/bottom-sheet.js +87 -0
  8. package/dist/bottom-sheet.js.map +1 -0
  9. package/dist/button-group.d.ts +14 -0
  10. package/dist/button-group.d.ts.map +1 -0
  11. package/dist/button-group.js +3 -0
  12. package/dist/button-group.js.map +1 -0
  13. package/dist/color-palette.d.ts +34 -0
  14. package/dist/color-palette.d.ts.map +1 -0
  15. package/dist/color-palette.js +77 -0
  16. package/dist/color-palette.js.map +1 -0
  17. package/dist/color-swatch-picker.d.ts +29 -0
  18. package/dist/color-swatch-picker.d.ts.map +1 -0
  19. package/dist/color-swatch-picker.js +56 -0
  20. package/dist/color-swatch-picker.js.map +1 -0
  21. package/dist/command-palette.d.ts +13 -0
  22. package/dist/command-palette.d.ts.map +1 -0
  23. package/dist/command-palette.js +146 -0
  24. package/dist/command-palette.js.map +1 -0
  25. package/dist/comments-panel.d.ts +27 -0
  26. package/dist/comments-panel.d.ts.map +1 -0
  27. package/dist/comments-panel.js +139 -0
  28. package/dist/comments-panel.js.map +1 -0
  29. package/dist/constants.d.ts +112 -0
  30. package/dist/constants.d.ts.map +1 -0
  31. package/dist/constants.js +119 -0
  32. package/dist/constants.js.map +1 -0
  33. package/dist/context-menu-controller.d.ts +41 -0
  34. package/dist/context-menu-controller.d.ts.map +1 -0
  35. package/dist/context-menu-controller.js +26 -0
  36. package/dist/context-menu-controller.js.map +1 -0
  37. package/dist/context-menu.d.ts +53 -0
  38. package/dist/context-menu.d.ts.map +1 -0
  39. package/dist/context-menu.js +333 -0
  40. package/dist/context-menu.js.map +1 -0
  41. package/dist/context.d.ts +44 -0
  42. package/dist/context.d.ts.map +1 -0
  43. package/dist/context.js +95 -0
  44. package/dist/context.js.map +1 -0
  45. package/dist/diagram-bars.d.ts +21 -0
  46. package/dist/diagram-bars.d.ts.map +1 -0
  47. package/dist/diagram-bars.js +4 -0
  48. package/dist/diagram-bars.js.map +1 -0
  49. package/dist/diagram-canvas.d.ts +39 -0
  50. package/dist/diagram-canvas.d.ts.map +1 -0
  51. package/dist/diagram-canvas.js +9 -0
  52. package/dist/diagram-canvas.js.map +1 -0
  53. package/dist/diagram-root.d.ts +70 -0
  54. package/dist/diagram-root.d.ts.map +1 -0
  55. package/dist/diagram-root.js +180 -0
  56. package/dist/diagram-root.js.map +1 -0
  57. package/dist/diff-panel.d.ts +25 -0
  58. package/dist/diff-panel.d.ts.map +1 -0
  59. package/dist/diff-panel.js +77 -0
  60. package/dist/diff-panel.js.map +1 -0
  61. package/dist/edge-style-panel.d.ts +19 -0
  62. package/dist/edge-style-panel.d.ts.map +1 -0
  63. package/dist/edge-style-panel.js +120 -0
  64. package/dist/edge-style-panel.js.map +1 -0
  65. package/dist/frame-name-editor-overlay.d.ts +13 -0
  66. package/dist/frame-name-editor-overlay.d.ts.map +1 -0
  67. package/dist/frame-name-editor-overlay.js +84 -0
  68. package/dist/frame-name-editor-overlay.js.map +1 -0
  69. package/dist/frame-panel.d.ts +19 -0
  70. package/dist/frame-panel.d.ts.map +1 -0
  71. package/dist/frame-panel.js +66 -0
  72. package/dist/frame-panel.js.map +1 -0
  73. package/dist/help-button.d.ts +16 -0
  74. package/dist/help-button.d.ts.map +1 -0
  75. package/dist/help-button.js +14 -0
  76. package/dist/help-button.js.map +1 -0
  77. package/dist/help-dialog.d.ts +56 -0
  78. package/dist/help-dialog.d.ts.map +1 -0
  79. package/dist/help-dialog.js +142 -0
  80. package/dist/help-dialog.js.map +1 -0
  81. package/dist/hooks.d.ts +54 -0
  82. package/dist/hooks.d.ts.map +1 -0
  83. package/dist/hooks.js +85 -0
  84. package/dist/hooks.js.map +1 -0
  85. package/dist/icon-button.d.ts +28 -0
  86. package/dist/icon-button.d.ts.map +1 -0
  87. package/dist/icon-button.js +14 -0
  88. package/dist/icon-button.js.map +1 -0
  89. package/dist/index.d.ts +45 -0
  90. package/dist/index.d.ts.map +1 -0
  91. package/dist/index.js +46 -0
  92. package/dist/index.js.map +1 -0
  93. package/dist/layer-panel.d.ts +13 -0
  94. package/dist/layer-panel.d.ts.map +1 -0
  95. package/dist/layer-panel.js +109 -0
  96. package/dist/layer-panel.js.map +1 -0
  97. package/dist/library-panel.d.ts +33 -0
  98. package/dist/library-panel.d.ts.map +1 -0
  99. package/dist/library-panel.js +37 -0
  100. package/dist/library-panel.js.map +1 -0
  101. package/dist/link-caption-editor.d.ts +8 -0
  102. package/dist/link-caption-editor.d.ts.map +1 -0
  103. package/dist/link-caption-editor.js +65 -0
  104. package/dist/link-caption-editor.js.map +1 -0
  105. package/dist/link-drop-shape-menu.d.ts +12 -0
  106. package/dist/link-drop-shape-menu.d.ts.map +1 -0
  107. package/dist/link-drop-shape-menu.js +55 -0
  108. package/dist/link-drop-shape-menu.js.map +1 -0
  109. package/dist/link-hover-popup.d.ts +2 -0
  110. package/dist/link-hover-popup.d.ts.map +1 -0
  111. package/dist/link-hover-popup.js +96 -0
  112. package/dist/link-hover-popup.js.map +1 -0
  113. package/dist/main-menu.d.ts +67 -0
  114. package/dist/main-menu.d.ts.map +1 -0
  115. package/dist/main-menu.js +243 -0
  116. package/dist/main-menu.js.map +1 -0
  117. package/dist/markdown.d.ts +10 -0
  118. package/dist/markdown.d.ts.map +1 -0
  119. package/dist/markdown.js +131 -0
  120. package/dist/markdown.js.map +1 -0
  121. package/dist/merge-dialog.d.ts +22 -0
  122. package/dist/merge-dialog.d.ts.map +1 -0
  123. package/dist/merge-dialog.js +46 -0
  124. package/dist/merge-dialog.js.map +1 -0
  125. package/dist/modal.d.ts +19 -0
  126. package/dist/modal.d.ts.map +1 -0
  127. package/dist/modal.js +87 -0
  128. package/dist/modal.js.map +1 -0
  129. package/dist/palette.d.ts +73 -0
  130. package/dist/palette.d.ts.map +1 -0
  131. package/dist/palette.js +330 -0
  132. package/dist/palette.js.map +1 -0
  133. package/dist/popover.d.ts +33 -0
  134. package/dist/popover.d.ts.map +1 -0
  135. package/dist/popover.js +107 -0
  136. package/dist/popover.js.map +1 -0
  137. package/dist/property-panel.d.ts +32 -0
  138. package/dist/property-panel.d.ts.map +1 -0
  139. package/dist/property-panel.js +728 -0
  140. package/dist/property-panel.js.map +1 -0
  141. package/dist/reset-to-content-button.d.ts +10 -0
  142. package/dist/reset-to-content-button.d.ts.map +1 -0
  143. package/dist/reset-to-content-button.js +62 -0
  144. package/dist/reset-to-content-button.js.map +1 -0
  145. package/dist/segmented-control.d.ts +23 -0
  146. package/dist/segmented-control.d.ts.map +1 -0
  147. package/dist/segmented-control.js +5 -0
  148. package/dist/segmented-control.js.map +1 -0
  149. package/dist/selection-floating-panel.d.ts +56 -0
  150. package/dist/selection-floating-panel.d.ts.map +1 -0
  151. package/dist/selection-floating-panel.js +251 -0
  152. package/dist/selection-floating-panel.js.map +1 -0
  153. package/dist/sidebar.d.ts +31 -0
  154. package/dist/sidebar.d.ts.map +1 -0
  155. package/dist/sidebar.js +66 -0
  156. package/dist/sidebar.js.map +1 -0
  157. package/dist/slider.d.ts +20 -0
  158. package/dist/slider.d.ts.map +1 -0
  159. package/dist/slider.js +9 -0
  160. package/dist/slider.js.map +1 -0
  161. package/dist/text-editor-overlay.d.ts +16 -0
  162. package/dist/text-editor-overlay.d.ts.map +1 -0
  163. package/dist/text-editor-overlay.js +112 -0
  164. package/dist/text-editor-overlay.js.map +1 -0
  165. package/dist/toast.d.ts +34 -0
  166. package/dist/toast.d.ts.map +1 -0
  167. package/dist/toast.js +89 -0
  168. package/dist/toast.js.map +1 -0
  169. package/dist/toolbar.d.ts +149 -0
  170. package/dist/toolbar.d.ts.map +1 -0
  171. package/dist/toolbar.js +282 -0
  172. package/dist/toolbar.js.map +1 -0
  173. package/dist/tooltip.d.ts +21 -0
  174. package/dist/tooltip.d.ts.map +1 -0
  175. package/dist/tooltip.js +217 -0
  176. package/dist/tooltip.js.map +1 -0
  177. package/dist/ui-layer.d.ts +22 -0
  178. package/dist/ui-layer.d.ts.map +1 -0
  179. package/dist/ui-layer.js +3 -0
  180. package/dist/ui-layer.js.map +1 -0
  181. package/dist/versioning.d.ts +32 -0
  182. package/dist/versioning.d.ts.map +1 -0
  183. package/dist/versioning.js +206 -0
  184. package/dist/versioning.js.map +1 -0
  185. package/package.json +81 -0
  186. package/src/styles.css +1502 -0
@@ -0,0 +1,84 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useEffect, useReducer, useRef } from "react";
3
+ import { getElement, isFrame, FRAME_HEADER_HEIGHT, FRAME_HEADER_PADDING_X, FRAME_HEADER_FONT_SIZE, } from "@oh-just-another/scene";
4
+ import { useDiagramOptional } from "./hooks.js";
5
+ /**
6
+ * Inline editor for a frame's header name. Unlike the in-canvas text
7
+ * editor (invisible sink + canvas-drawn caret), the frame label has no
8
+ * canvas caret, so this is a VISIBLE `<input>` positioned over the header
9
+ * strip and styled to match it (dark bar, light text). Opens via
10
+ * `editor.beginFrameNameEdit(id)` (double-click the header / frame body);
11
+ * commits on Enter or blur, cancels on Escape.
12
+ *
13
+ * Wiring: drop as a sibling of `<DiagramSurface>` inside `<DiagramRoot>`,
14
+ * next to `<TextEditorOverlay>`.
15
+ */
16
+ export const FrameNameEditorOverlay = () => {
17
+ const editor = useDiagramOptional();
18
+ const ref = useRef(null);
19
+ const [, force] = useReducer((x) => x + 1, 0);
20
+ // Follow scene / viewport changes (pan / zoom) while editing.
21
+ useEffect(() => {
22
+ if (!editor)
23
+ return undefined;
24
+ return editor.on("change", force);
25
+ }, [editor]);
26
+ const editingId = editor?.editingFrameName ?? null;
27
+ // Focus + select-all when an edit starts.
28
+ useEffect(() => {
29
+ if (!editingId)
30
+ return;
31
+ const el = ref.current;
32
+ if (el) {
33
+ el.focus();
34
+ el.select();
35
+ }
36
+ }, [editingId]);
37
+ if (!editor || !editingId)
38
+ return null;
39
+ const frame = getElement(editor.scene, editingId);
40
+ if (!frame || !isFrame(frame))
41
+ return null;
42
+ const vp = editor.scene.viewport;
43
+ const z = vp.zoom;
44
+ const left = (frame.position.x - vp.pan.x) * z;
45
+ const top = (frame.position.y - FRAME_HEADER_HEIGHT * frame.scale.y - vp.pan.y) * z;
46
+ // Editor input spans the frame's full width so a long name stays visible
47
+ // while typing (the rendered label hugs/ellipsises, but editing wants room).
48
+ const width = frame.width * frame.scale.x * z;
49
+ const height = FRAME_HEADER_HEIGHT * frame.scale.y * z;
50
+ return (_jsx("input", { ref: ref, type: "text", defaultValue: frame.name ?? "", placeholder: "Frame", "aria-label": "Frame name", spellCheck: false, autoCapitalize: "off", autoCorrect: "off", onKeyDown: (ev) => {
51
+ if (ev.key === "Enter") {
52
+ ev.preventDefault();
53
+ ev.stopPropagation();
54
+ editor.commitFrameNameEdit(ev.currentTarget.value);
55
+ }
56
+ else if (ev.key === "Escape") {
57
+ ev.preventDefault();
58
+ ev.stopPropagation();
59
+ editor.cancelFrameNameEdit();
60
+ }
61
+ else {
62
+ // Keep typing keys from reaching canvas hotkeys.
63
+ ev.stopPropagation();
64
+ }
65
+ }, onBlur: (ev) => { editor.commitFrameNameEdit(ev.currentTarget.value); }, style: {
66
+ position: "absolute",
67
+ left,
68
+ top,
69
+ width,
70
+ height,
71
+ boxSizing: "border-box",
72
+ padding: `0 ${FRAME_HEADER_PADDING_X * z}px`,
73
+ margin: 0,
74
+ border: 0,
75
+ outline: "none",
76
+ background: "#222",
77
+ color: "#ddd",
78
+ font: `${FRAME_HEADER_FONT_SIZE * z}px system-ui, sans-serif`,
79
+ lineHeight: `${height}px`,
80
+ pointerEvents: "auto",
81
+ zIndex: 100,
82
+ } }, editingId));
83
+ };
84
+ //# sourceMappingURL=frame-name-editor-overlay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frame-name-editor-overlay.js","sourceRoot":"","sources":["../src/frame-name-editor-overlay.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import { type CSSProperties } from "react";
2
+ import type { ElementId } from "@oh-just-another/types";
3
+ import { type FrameElement } from "@oh-just-another/scene";
4
+ /**
5
+ * Sidebar panel listing every `FrameElement` in the scene. Each row
6
+ * shows the frame's name and size and exposes two actions:
7
+ *
8
+ * • Select — sets the editor's selection to the frame.
9
+ * • Export — fires `onExport(frameId)`; the host decides what to do.
10
+ *
11
+ * Renders nothing when there are no frames.
12
+ */
13
+ export interface FramePanelProps {
14
+ /** Host-side export callback. Invoked per-frame on the action click. */
15
+ readonly onExport?: (frameId: ElementId, frame: FrameElement) => void;
16
+ readonly style?: CSSProperties;
17
+ }
18
+ export declare const FramePanel: ({ onExport, style }: FramePanelProps) => import("react/jsx-runtime").JSX.Element | null;
19
+ //# sourceMappingURL=frame-panel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frame-panel.d.ts","sourceRoot":"","sources":["../src/frame-panel.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAW,KAAK,aAAa,EAAE,MAAM,OAAO,CAAC;AACpD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAG3D;;;;;;;;GAQG;AACH,MAAM,WAAW,eAAe;IAC9B,wEAAwE;IACxE,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;IACtE,QAAQ,CAAC,KAAK,CAAC,EAAE,aAAa,CAAC;CAChC;AAED,eAAO,MAAM,UAAU,GAAI,qBAAqB,eAAe,mDA0G9D,CAAC"}
@@ -0,0 +1,66 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useMemo } from "react";
3
+ import {} from "@oh-just-another/scene";
4
+ import { useDiagramOptional, useScene } from "./hooks.js";
5
+ export const FramePanel = ({ onExport, style }) => {
6
+ const editor = useDiagramOptional();
7
+ const scene = useScene();
8
+ const frames = useMemo(() => {
9
+ const out = [];
10
+ for (const s of scene.elements.values()) {
11
+ if (s.type === "frame")
12
+ out.push(s);
13
+ }
14
+ out.sort((a, b) => (a.order < b.order ? -1 : a.order > b.order ? 1 : 0));
15
+ return out;
16
+ }, [scene]);
17
+ if (frames.length === 0)
18
+ return null;
19
+ return (_jsxs("aside", { "data-panel": "frames", style: {
20
+ display: "flex",
21
+ flexDirection: "column",
22
+ minHeight: 0,
23
+ fontSize: 12,
24
+ ...style,
25
+ }, children: [_jsxs("h2", { style: {
26
+ margin: 0,
27
+ padding: "10px 12px",
28
+ fontSize: 11,
29
+ textTransform: "uppercase",
30
+ letterSpacing: 0.5,
31
+ color: "var(--muted)",
32
+ borderBottom: "1px solid var(--border)",
33
+ display: "flex",
34
+ justifyContent: "space-between",
35
+ }, children: ["Frames", _jsx("span", { style: { textTransform: "none", color: "var(--faint)" }, children: frames.length })] }), _jsx("ul", { style: {
36
+ listStyle: "none",
37
+ margin: 0,
38
+ padding: 0,
39
+ flex: "1 1 auto",
40
+ overflowY: "auto",
41
+ }, children: frames.map((frame) => (_jsx("li", { children: _jsxs("div", { style: {
42
+ display: "flex",
43
+ alignItems: "center",
44
+ gap: 8,
45
+ padding: "6px 12px",
46
+ borderBottom: "1px solid var(--divider, transparent)",
47
+ }, children: [_jsxs("button", { type: "button", onClick: () => editor?.setSelection([frame.id]), style: {
48
+ flex: "1 1 auto",
49
+ textAlign: "left",
50
+ background: "transparent",
51
+ color: "var(--text)",
52
+ border: 0,
53
+ padding: 0,
54
+ cursor: "pointer",
55
+ font: "inherit",
56
+ }, title: "Select this frame on canvas", children: [_jsx("div", { style: { fontWeight: 500 }, children: frame.name ?? "Untitled frame" }), _jsxs("div", { style: { color: "var(--faint)", fontSize: 10 }, children: [Math.round(frame.width), " \u00D7 ", Math.round(frame.height)] })] }), onExport ? (_jsx("button", { type: "button", onClick: () => { onExport(frame.id, frame); }, style: {
57
+ fontSize: 10,
58
+ padding: "2px 8px",
59
+ border: "1px solid var(--border, #2a2a2a)",
60
+ borderRadius: 3,
61
+ background: "var(--button-bg, #2a2a2a)",
62
+ color: "var(--text, #ddd)",
63
+ cursor: "pointer",
64
+ }, title: "Export only this frame's content", children: "Export" })) : null] }) }, frame.id))) })] }));
65
+ };
66
+ //# sourceMappingURL=frame-panel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frame-panel.js","sourceRoot":"","sources":["../src/frame-panel.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Help icon button. Opens the bundled `<HelpDialog>` modal and manages
3
+ * its open state internally.
4
+ *
5
+ * Hosts that want a custom modal pass `renderDialog` — it receives
6
+ * `{open, onClose}` and renders whatever they like instead of the
7
+ * bundled `HelpDialog`.
8
+ */
9
+ export interface HelpButtonProps {
10
+ readonly renderDialog?: (api: {
11
+ open: boolean;
12
+ onClose: () => void;
13
+ }) => React.ReactNode;
14
+ }
15
+ export declare const HelpButton: ({ renderDialog }: HelpButtonProps) => import("react/jsx-runtime").JSX.Element;
16
+ //# sourceMappingURL=help-button.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"help-button.d.ts","sourceRoot":"","sources":["../src/help-button.tsx"],"names":[],"mappings":"AAQA;;;;;;;GAOG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE;QAAE,IAAI,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,MAAM,IAAI,CAAA;KAAE,KAAK,KAAK,CAAC,SAAS,CAAC;CAC1F;AAED,eAAO,MAAM,UAAU,GAAI,kBAAkB,eAAe,4CAY3D,CAAC"}
@@ -0,0 +1,14 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState } from "react";
3
+ import { HelpCircle } from "lucide-react";
4
+ import { HelpDialog } from "./help-dialog.js";
5
+ import { IconButton } from "./icon-button.js";
6
+ const HELP_ICON_SIZE = 16;
7
+ const HELP_ICON_STROKE = 1.75;
8
+ export const HelpButton = ({ renderDialog }) => {
9
+ const [open, setOpen] = useState(false);
10
+ return (_jsxs(_Fragment, { children: [_jsx(IconButton, { label: "Help", onClick: () => { setOpen(true); }, children: _jsx(HelpCircle, { size: HELP_ICON_SIZE, strokeWidth: HELP_ICON_STROKE }) }), renderDialog
11
+ ? renderDialog({ open, onClose: () => { setOpen(false); } })
12
+ : _jsx(HelpDialog, { open: open, onClose: () => { setOpen(false); } })] }));
13
+ };
14
+ //# sourceMappingURL=help-button.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"help-button.js","sourceRoot":"","sources":["../src/help-button.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,MAAM,cAAc,GAAG,EAAE,CAAC;AAC1B,MAAM,gBAAgB,GAAG,IAAI,CAAC;AAc9B,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,EAAE,YAAY,EAAmB,EAAE,EAAE;IAC9D,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IACxC,OAAO,CACL,8BACE,KAAC,UAAU,IAAC,KAAK,EAAC,MAAM,EAAC,OAAO,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,YACxD,KAAC,UAAU,IAAC,IAAI,EAAE,cAAc,EAAE,WAAW,EAAE,gBAAgB,GAAI,GACxD,EACZ,YAAY;gBACX,CAAC,CAAC,YAAY,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC5D,CAAC,CAAC,KAAC,UAAU,IAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAI,IACjE,CACJ,CAAC;AACJ,CAAC,CAAC"}
@@ -0,0 +1,56 @@
1
+ import { type ReactElement } from "react";
2
+ import { type ActionRegistry } from "@oh-just-another/state";
3
+ /**
4
+ * Help dialog — a cheatsheet of every Action's hotkey. Opens on "?" by
5
+ * default; hosts can also drive `open` via state.
6
+ *
7
+ * Shortcuts are grouped into bordered "islands"; every key is rendered
8
+ * as its own pill `<kbd>` chip. Multiple alternative shortcuts on one
9
+ * row are joined with "or".
10
+ *
11
+ * Platform-aware key labels come from `formatHotkeyParts`: macOS gets
12
+ * glyphs (⌘ ⌥ ⇧ ⌃ ⏎ ⌫), other platforms get spelled-out names (Ctrl,
13
+ * Alt, Shift, Enter, Delete). The platform badge in the header shows
14
+ * which set is in use.
15
+ */
16
+ export interface HelpDialogProps {
17
+ /** Override the registry — defaults to the package's shared default. */
18
+ readonly registry?: ActionRegistry;
19
+ /**
20
+ * Open / close control. Hosts that wire their own bindings pass these;
21
+ * the bundled `?` listener flips them via `useHelpDialogHotkey`.
22
+ */
23
+ readonly open: boolean;
24
+ readonly onClose: () => void;
25
+ readonly title?: string;
26
+ readonly extraSections?: readonly HelpSection[];
27
+ }
28
+ export interface HelpSection {
29
+ readonly title: string;
30
+ readonly rows: readonly HelpRow[];
31
+ }
32
+ /**
33
+ * Row payload. `keys` is an array of alternative shortcut combinations;
34
+ * each combination is a list of platform-formatted key labels (e.g.
35
+ * `[["⌘", "Z"], ["⌃", "Z"]]`). Empty `keys` renders an "—" placeholder.
36
+ */
37
+ export interface HelpRow {
38
+ readonly label: string;
39
+ readonly keys: readonly (readonly string[])[];
40
+ }
41
+ /**
42
+ * Hook that flips `open` when the user presses `?`. Wire in app shell:
43
+ *
44
+ * ```tsx
45
+ * const [help, setHelp] = useState(false);
46
+ * useHelpDialogHotkey(() => setHelp(true));
47
+ * <HelpDialog open={help} onClose={() => setHelp(false)} />
48
+ * ```
49
+ *
50
+ * "?" is Shift+/ on the typical keyboard — the listener checks for both
51
+ * `event.key === "?"` and `Shift + /`. Inputs and textareas are exempt
52
+ * so the user can still type a literal "?" into a text field.
53
+ */
54
+ export declare const useHelpDialogHotkey: (open: () => void) => void;
55
+ export declare const HelpDialog: ({ registry, open, onClose, title, extraSections, }: HelpDialogProps) => ReactElement | null;
56
+ //# sourceMappingURL=help-dialog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"help-dialog.d.ts","sourceRoot":"","sources":["../src/help-dialog.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAoD,KAAK,YAAY,EAAE,MAAM,OAAO,CAAC;AAE5F,OAAO,EAML,KAAK,cAAc,EAEpB,MAAM,wBAAwB,CAAC;AAIhC;;;;;;;;;;;;GAYG;AAEH,MAAM,WAAW,eAAe;IAC9B,wEAAwE;IACxE,QAAQ,CAAC,QAAQ,CAAC,EAAE,cAAc,CAAC;IACnC;;;OAGG;IACH,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,IAAI,CAAC;IAC7B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,WAAW,EAAE,CAAC;CACjD;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,SAAS,OAAO,EAAE,CAAC;CACnC;AAED;;;;GAIG;AACH,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,CAAC;CAC/C;AA4BD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,mBAAmB,GAAI,MAAM,MAAM,IAAI,KAAG,IAatD,CAAC;AAuBF,eAAO,MAAM,UAAU,GAAI,oDAMxB,eAAe,KAAG,YAAY,GAAG,IAuFnC,CAAC"}
@@ -0,0 +1,142 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Fragment, useEffect, useMemo } from "react";
3
+ import { X } from "lucide-react";
4
+ import { defaultActionRegistry, formatHotkeyParts, isMac, } from "@oh-just-another/state";
5
+ import { HELP_DIALOG_MAX_WIDTH_PX } from "./constants.js";
6
+ import { Modal } from "./modal.js";
7
+ const CATEGORY_TITLES = {
8
+ history: "History",
9
+ selection: "Selection",
10
+ clipboard: "Clipboard",
11
+ "z-order": "Z-order",
12
+ grouping: "Grouping",
13
+ zoom: "Zoom",
14
+ mode: "Tools",
15
+ layout: "Layout",
16
+ edit: "Editing",
17
+ other: "Other",
18
+ };
19
+ const CATEGORY_ORDER = [
20
+ "mode",
21
+ "edit",
22
+ "selection",
23
+ "clipboard",
24
+ "history",
25
+ "z-order",
26
+ "grouping",
27
+ "layout",
28
+ "zoom",
29
+ "other",
30
+ ];
31
+ /**
32
+ * Hook that flips `open` when the user presses `?`. Wire in app shell:
33
+ *
34
+ * ```tsx
35
+ * const [help, setHelp] = useState(false);
36
+ * useHelpDialogHotkey(() => setHelp(true));
37
+ * <HelpDialog open={help} onClose={() => setHelp(false)} />
38
+ * ```
39
+ *
40
+ * "?" is Shift+/ on the typical keyboard — the listener checks for both
41
+ * `event.key === "?"` and `Shift + /`. Inputs and textareas are exempt
42
+ * so the user can still type a literal "?" into a text field.
43
+ */
44
+ export const useHelpDialogHotkey = (open) => {
45
+ useEffect(() => {
46
+ const onKey = (ev) => {
47
+ const t = ev.target;
48
+ if (t instanceof HTMLInputElement || t instanceof HTMLTextAreaElement)
49
+ return;
50
+ const isQuestion = ev.key === "?" || (ev.shiftKey && ev.key === "/");
51
+ if (!isQuestion)
52
+ return;
53
+ ev.preventDefault();
54
+ open();
55
+ };
56
+ window.addEventListener("keydown", onKey);
57
+ return () => { window.removeEventListener("keydown", onKey); };
58
+ }, [open]);
59
+ };
60
+ /**
61
+ * Resolve the action's hotkey(s) into the per-chip parts the dialog
62
+ * renders. Single-hotkey actions return one combination; actions with
63
+ * an array hotkey return one combination per entry. Toolbar-only
64
+ * actions (no hotkey) return an empty array.
65
+ */
66
+ const actionKeys = (action) => {
67
+ const combos = [];
68
+ if (action.hotkey) {
69
+ const raw = Array.isArray(action.hotkey) ? action.hotkey : [action.hotkey];
70
+ for (const h of raw)
71
+ combos.push(formatHotkeyParts(h));
72
+ }
73
+ // Multi-key sequences (e.g. `d d`) render as a single chip with the keys
74
+ // space-separated, distinct from a `+` chord.
75
+ if (action.sequence && action.sequence.length > 0) {
76
+ const seq = action.sequence.map((k) => (k.length === 1 ? k.toUpperCase() : k)).join(" ");
77
+ combos.push([seq]);
78
+ }
79
+ return combos;
80
+ };
81
+ export const HelpDialog = ({ registry = defaultActionRegistry, open, onClose, title = "Keyboard shortcuts", extraSections, }) => {
82
+ // Esc / focus-trap / backdrop dismiss live on the base Modal.
83
+ const sections = useMemo(() => {
84
+ const byCategory = new Map();
85
+ for (const action of registry.getAll()) {
86
+ if (!action.label)
87
+ continue;
88
+ const cat = action.category ?? "other";
89
+ const list = byCategory.get(cat) ?? [];
90
+ list.push({ label: action.label, keys: actionKeys(action) });
91
+ byCategory.set(cat, list);
92
+ }
93
+ const out = [];
94
+ for (const cat of CATEGORY_ORDER) {
95
+ const rows = byCategory.get(cat);
96
+ if (!rows || rows.length === 0)
97
+ continue;
98
+ out.push({ title: CATEGORY_TITLES[cat], rows });
99
+ }
100
+ if (extraSections)
101
+ out.push(...extraSections);
102
+ return out;
103
+ }, [registry, extraSections]);
104
+ const modalStyle = {
105
+ maxWidth: HELP_DIALOG_MAX_WIDTH_PX,
106
+ width: "calc(100vw - 64px)",
107
+ display: "flex",
108
+ flexDirection: "column",
109
+ };
110
+ const headerStyle = {
111
+ padding: "16px 20px",
112
+ borderBottom: "1px solid var(--du-ui-border)",
113
+ display: "flex",
114
+ alignItems: "center",
115
+ justifyContent: "space-between",
116
+ };
117
+ const bodyStyle = {
118
+ padding: "16px 20px 20px",
119
+ overflowY: "auto",
120
+ };
121
+ return (_jsx(Modal, { open: open, onClose: onClose, title: title, style: modalStyle, children: _jsxs("div", { children: [_jsxs("div", { style: headerStyle, children: [_jsx("h2", { style: { margin: 0, fontSize: 16, fontWeight: 600 }, children: title }), _jsxs("div", { style: { display: "flex", alignItems: "center", gap: 12 }, children: [_jsx("span", { className: "du-help-platform-badge", children: isMac ? "macOS" : "Win / Linux" }), _jsx("button", { type: "button", "aria-label": "Close help", onClick: onClose, style: {
122
+ background: "transparent",
123
+ border: "none",
124
+ color: "var(--du-text)",
125
+ cursor: "pointer",
126
+ display: "inline-flex",
127
+ alignItems: "center",
128
+ justifyContent: "center",
129
+ padding: 4,
130
+ }, children: _jsx(X, { size: 18, strokeWidth: 1.75 }) })] })] }), _jsx("div", { style: bodyStyle, children: _jsx("div", { className: "du-help-islands", children: sections.map((section) => (_jsxs("section", { className: "du-help-island", children: [_jsx("h3", { className: "du-help-island-title", children: section.title }), _jsx("div", { className: "du-help-island-rows", children: section.rows.map((row) => (_jsxs("div", { className: "du-help-row", children: [_jsx("span", { className: "du-help-row-label", children: row.label }), _jsx(ShortcutKeys, { combos: row.keys })] }, row.label))) })] }, section.title))) }) })] }) }));
131
+ };
132
+ /**
133
+ * Render N alternative key combinations joined with "or". Each key
134
+ * renders as its own pill `<kbd>` chip.
135
+ */
136
+ const ShortcutKeys = ({ combos }) => {
137
+ if (combos.length === 0) {
138
+ return _jsx("span", { className: "du-help-keys-separator", children: "\u2014" });
139
+ }
140
+ return (_jsx("span", { className: "du-help-keys", children: combos.map((combo, i) => (_jsxs(Fragment, { children: [i > 0 ? _jsx("span", { className: "du-help-keys-separator", children: "or" }) : null, combo.map((part, j) => (_jsx("kbd", { className: "du-help-key", children: part }, j)))] }, i))) }));
141
+ };
142
+ //# sourceMappingURL=help-dialog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"help-dialog.js","sourceRoot":"","sources":["../src/help-dialog.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ import { type Annotation, type Layer, type Scene } from "@oh-just-another/scene";
2
+ import { type AnnotationId, type LinkId, type LayerId } from "@oh-just-another/types";
3
+ import { type Editor, type Mode, type Selection } from "@oh-just-another/state";
4
+ /**
5
+ * Live `Editor` instance. Use for imperative actions (`addElement`,
6
+ * `loadScene`, `screenToWorld`). Throws if not inside a provider.
7
+ *
8
+ * The reactive hooks below (`useScene`, etc.) accept the brief pre-mount
9
+ * window and return default values; this one assumes the caller already
10
+ * waited until the editor is ready.
11
+ */
12
+ export declare const useDiagram: () => Editor;
13
+ export declare const useMobileLayout: () => boolean;
14
+ /**
15
+ * Same as `useDiagram` but returns `null` while the editor is being
16
+ * created. Useful in components that render before `<DiagramSurface>`
17
+ * mounts and want to fire callbacks lazily.
18
+ */
19
+ export declare const useDiagramOptional: () => Editor | null;
20
+ /** Current `Scene`. Returns `emptyScene()` while the editor is being created. */
21
+ export declare const useScene: () => Scene;
22
+ /** Selected shape ids. Returns the canonical `EMPTY` set pre-mount. */
23
+ export declare const useSelection: () => Selection;
24
+ /** Current interaction mode. Defaults to `"select"` pre-mount. */
25
+ export declare const useMode: () => Mode;
26
+ /**
27
+ * History introspection and actions. Returns no-op callbacks (and `false`
28
+ * flags) while the editor is being created so toolbar buttons can render
29
+ * disabled without bespoke null-checking.
30
+ *
31
+ * Subscribes to the typed `history` event so undo/redo button updates
32
+ * skip pan / zoom / selection notifies entirely.
33
+ */
34
+ export declare const useHistory: () => {
35
+ readonly canUndo: boolean;
36
+ readonly canRedo: boolean;
37
+ readonly undo: () => void;
38
+ readonly redo: () => void;
39
+ };
40
+ /** All layers in z-order (back → front). Returns an empty array pre-mount. */
41
+ export declare const useLayers: () => readonly Layer[];
42
+ /** Currently active layer id (new shapes go here). */
43
+ export declare const useActiveLayerId: () => LayerId;
44
+ /**
45
+ * All annotations in scene order (insertion). Returns empty pre-mount.
46
+ * Newest annotations come last; hosts can sort by `createdAt` for
47
+ * chronological order.
48
+ */
49
+ export declare const useAnnotations: () => readonly Annotation[];
50
+ /** Currently focused annotation id (or null when nothing is open). */
51
+ export declare const useSelectedAnnotation: () => AnnotationId | null;
52
+ /** Currently selected edge id, or null when no edge is selected. */
53
+ export declare const useSelectedLink: () => LinkId | null;
54
+ //# sourceMappingURL=hooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AACA,OAAO,EAIL,KAAK,UAAU,EACf,KAAK,KAAK,EACV,KAAK,KAAK,EACX,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,MAAM,EAEX,KAAK,OAAO,EACb,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAa,KAAK,MAAM,EAAE,KAAK,IAAI,EAAE,KAAK,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAG3F;;;;;;;GAOG;AACH,eAAO,MAAM,UAAU,QAAO,MAA6B,CAAC;AAc5D,eAAO,MAAM,eAAe,QAAO,OAahC,CAAC;AAEJ;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,QAAO,MAAM,GAAG,IAAmC,CAAC;AAInF,iFAAiF;AACjF,eAAO,MAAM,QAAQ,QAAO,KAAgE,CAAC;AAE7F,uEAAuE;AACvE,eAAO,MAAM,YAAY,QAAO,SACqC,CAAC;AAEtE,kEAAkE;AAClE,eAAO,MAAM,OAAO,QAAO,IAAgE,CAAC;AAE5F;;;;;;;GAOG;AACH,eAAO,MAAM,UAAU,QAAO;IAC5B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,IAAI,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,IAAI,CAAC;CAc3B,CAAC;AAIF,8EAA8E;AAC9E,eAAO,MAAM,SAAS,QAAO,SAAS,KAAK,EACwB,CAAC;AAIpE,sDAAsD;AACtD,eAAO,MAAM,gBAAgB,QAAO,OAC6B,CAAC;AAIlE;;;;GAIG;AACH,eAAO,MAAM,cAAc,QAAO,SAAS,UAAU,EAC2B,CAAC;AAEjF,sEAAsE;AACtE,eAAO,MAAM,qBAAqB,QAAO,YAAY,GAAG,IACmB,CAAC;AAE5E,oEAAoE;AACpE,eAAO,MAAM,eAAe,QAAO,MAAM,GAAG,IACmB,CAAC"}
package/dist/hooks.js ADDED
@@ -0,0 +1,85 @@
1
+ import { useCallback, useSyncExternalStore } from "react";
2
+ import { DEFAULT_LAYER_ID, emptyScene, getLayersInOrder, } from "@oh-just-another/scene";
3
+ import { MOBILE_MAX_WIDTH_PX } from "./constants.js";
4
+ import { layerId as castLayerId, } from "@oh-just-another/types";
5
+ import { selection } from "@oh-just-another/state";
6
+ import { useDiagramContext, useDiagramContextOptional, useEditorSelector } from "./context.js";
7
+ /**
8
+ * Live `Editor` instance. Use for imperative actions (`addElement`,
9
+ * `loadScene`, `screenToWorld`). Throws if not inside a provider.
10
+ *
11
+ * The reactive hooks below (`useScene`, etc.) accept the brief pre-mount
12
+ * window and return default values; this one assumes the caller already
13
+ * waited until the editor is ready.
14
+ */
15
+ export const useDiagram = () => useDiagramContext();
16
+ /**
17
+ * `true` when the chrome should use its mobile layout — a coarse pointer
18
+ * (touch) OR a narrow viewport (≤ {@link MOBILE_MAX_WIDTH_PX}). Reactive:
19
+ * re-renders on orientation / resize / input-mode change. SSR-safe (returns
20
+ * `false` until mounted). Single source of truth for mobile adaptations.
21
+ */
22
+ const MOBILE_MEDIA = `(pointer: coarse), (max-width: ${MOBILE_MAX_WIDTH_PX}px)`;
23
+ const matchMobile = () => typeof window !== "undefined" && typeof window.matchMedia === "function"
24
+ ? window.matchMedia(MOBILE_MEDIA).matches
25
+ : false;
26
+ export const useMobileLayout = () => useSyncExternalStore((onChange) => {
27
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function")
28
+ return () => {
29
+ /* no-op: SSR / no-matchMedia env has no subscription to tear down */
30
+ };
31
+ const mq = window.matchMedia(MOBILE_MEDIA);
32
+ mq.addEventListener("change", onChange);
33
+ return () => { mq.removeEventListener("change", onChange); };
34
+ }, matchMobile, () => false);
35
+ /**
36
+ * Same as `useDiagram` but returns `null` while the editor is being
37
+ * created. Useful in components that render before `<DiagramSurface>`
38
+ * mounts and want to fire callbacks lazily.
39
+ */
40
+ export const useDiagramOptional = () => useDiagramContextOptional();
41
+ const EMPTY_SCENE = emptyScene();
42
+ /** Current `Scene`. Returns `emptyScene()` while the editor is being created. */
43
+ export const useScene = () => useEditorSelector((e) => e.scene, EMPTY_SCENE, "scene");
44
+ /** Selected shape ids. Returns the canonical `EMPTY` set pre-mount. */
45
+ export const useSelection = () => useEditorSelector((e) => e.selection, selection.EMPTY, "selection");
46
+ /** Current interaction mode. Defaults to `"select"` pre-mount. */
47
+ export const useMode = () => useEditorSelector((e) => e.mode, "select", "mode");
48
+ /**
49
+ * History introspection and actions. Returns no-op callbacks (and `false`
50
+ * flags) while the editor is being created so toolbar buttons can render
51
+ * disabled without bespoke null-checking.
52
+ *
53
+ * Subscribes to the typed `history` event so undo/redo button updates
54
+ * skip pan / zoom / selection notifies entirely.
55
+ */
56
+ export const useHistory = () => {
57
+ const editor = useDiagramOptional();
58
+ const canUndo = useEditorSelector((e) => e.canUndo, false, "history");
59
+ const canRedo = useEditorSelector((e) => e.canRedo, false, "history");
60
+ const undo = useCallback(() => {
61
+ editor?.undo();
62
+ }, [editor]);
63
+ const redo = useCallback(() => {
64
+ editor?.redo();
65
+ }, [editor]);
66
+ return { canUndo, canRedo, undo, redo };
67
+ };
68
+ const EMPTY_LAYERS = [];
69
+ /** All layers in z-order (back → front). Returns an empty array pre-mount. */
70
+ export const useLayers = () => useEditorSelector((e) => getLayersInOrder(e.scene), EMPTY_LAYERS);
71
+ const DEFAULT_ACTIVE_LAYER = castLayerId(DEFAULT_LAYER_ID);
72
+ /** Currently active layer id (new shapes go here). */
73
+ export const useActiveLayerId = () => useEditorSelector((e) => e.activeLayerId, DEFAULT_ACTIVE_LAYER);
74
+ const EMPTY_ANNOTATIONS = [];
75
+ /**
76
+ * All annotations in scene order (insertion). Returns empty pre-mount.
77
+ * Newest annotations come last; hosts can sort by `createdAt` for
78
+ * chronological order.
79
+ */
80
+ export const useAnnotations = () => useEditorSelector((e) => [...e.scene.annotations.values()], EMPTY_ANNOTATIONS);
81
+ /** Currently focused annotation id (or null when nothing is open). */
82
+ export const useSelectedAnnotation = () => useEditorSelector((e) => e.selectedAnnotation, null);
83
+ /** Currently selected edge id, or null when no edge is selected. */
84
+ export const useSelectedLink = () => useEditorSelector((e) => e.selectedLink, null);
85
+ //# sourceMappingURL=hooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks.js","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import type { ButtonHTMLAttributes, ReactNode } from "react";
2
+ /**
3
+ * Square clickable button — the base primitive for the top / bottom
4
+ * bars and panel headers. Style comes entirely from `du-icon-button` in
5
+ * `diagram-ui.css`; hosts override via CSS variables, not inline `style`.
6
+ *
7
+ * Active state is signalled through `aria-pressed` (the CSS hooks onto
8
+ * `[aria-pressed="true"]`). For tools that toggle on/off pass
9
+ * `active={true}`; for momentary actions omit it.
10
+ *
11
+ * The tooltip uses the shared `<TooltipProvider>` singleton so a second
12
+ * hover within the open-delay window skips the delay.
13
+ */
14
+ export interface IconButtonProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, "title"> {
15
+ /**
16
+ * Accessible name and tooltip text. Required. Renders through
17
+ * `<Tooltip>` (singleton) when a `<TooltipProvider>` is mounted; falls
18
+ * back to native `title=` otherwise.
19
+ */
20
+ readonly label: string;
21
+ /** Toggle state: maps to `aria-pressed` and a CSS `is-active` class. */
22
+ readonly active?: boolean;
23
+ /** Compact 28-px variant for dense panels (e.g. side-panel headers). */
24
+ readonly size?: "default" | "sm";
25
+ readonly children: ReactNode;
26
+ }
27
+ export declare const IconButton: ({ label, active, size, className, children, ...rest }: IconButtonProps) => import("react/jsx-runtime").JSX.Element;
28
+ //# sourceMappingURL=icon-button.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"icon-button.d.ts","sourceRoot":"","sources":["../src/icon-button.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAG7D;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,eACf,SAAQ,IAAI,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC9D;;;;OAIG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,wEAAwE;IACxE,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B,wEAAwE;IACxE,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC;CAC9B;AAED,eAAO,MAAM,UAAU,GAAI,uDAOxB,eAAe,4CAsBjB,CAAC"}