@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,66 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { createContext, useContext, useMemo, useState, } from "react";
3
+ const Ctx = createContext(null);
4
+ const useSidebar = () => {
5
+ const ctx = useContext(Ctx);
6
+ if (!ctx)
7
+ throw new Error("Sidebar sub-component must be inside <Sidebar>");
8
+ return ctx;
9
+ };
10
+ export const Sidebar = ({ children, defaultTab = "", docked = "right", width = 280, className, style, }) => {
11
+ const [active, setActive] = useState(defaultTab);
12
+ const ctx = useMemo(() => ({ active, setActive }), [active]);
13
+ const wrapper = {
14
+ width,
15
+ background: "var(--panel, #161616)",
16
+ color: "var(--text, #ddd)",
17
+ display: "flex",
18
+ flexDirection: "column",
19
+ minHeight: 0,
20
+ borderLeft: docked === "right" ? "1px solid var(--border, #2a2a2a)" : "none",
21
+ borderRight: docked === "left" ? "1px solid var(--border, #2a2a2a)" : "none",
22
+ ...style,
23
+ };
24
+ return (_jsx(Ctx.Provider, { value: ctx, children: _jsx("aside", { className: className, style: wrapper, children: children }) }));
25
+ };
26
+ const Header = ({ children }) => (_jsx("header", { style: {
27
+ padding: "12px 14px",
28
+ fontSize: 13,
29
+ fontWeight: 600,
30
+ color: "var(--text-strong, #fff)",
31
+ borderBottom: "1px solid var(--border, #2a2a2a)",
32
+ }, children: children }));
33
+ const TabTriggers = ({ children }) => (_jsx("div", { style: {
34
+ display: "flex",
35
+ gap: 4,
36
+ padding: "8px 10px",
37
+ borderBottom: "1px solid var(--border, #2a2a2a)",
38
+ }, children: children }));
39
+ const Trigger = ({ tab, children }) => {
40
+ const { active, setActive } = useSidebar();
41
+ const isActive = active === tab;
42
+ return (_jsx("button", { type: "button", "aria-pressed": isActive, onClick: () => { setActive(tab); }, style: {
43
+ background: isActive ? "var(--accent, #1a73e8)" : "transparent",
44
+ color: isActive ? "var(--surface, #fff)" : "var(--text, #ddd)",
45
+ border: `1px solid ${isActive ? "var(--accent, #1a73e8)" : "var(--border, #2a2a2a)"}`,
46
+ borderRadius: 4,
47
+ padding: "4px 10px",
48
+ fontSize: 12,
49
+ cursor: "pointer",
50
+ font: "inherit",
51
+ }, children: children }));
52
+ };
53
+ const Tab = ({ tab, children }) => {
54
+ const { active } = useSidebar();
55
+ if (active !== tab)
56
+ return null;
57
+ return (_jsx("div", { style: { flex: "1 1 auto", overflowY: "auto", padding: "10px 12px" }, children: children }));
58
+ };
59
+ /** Plain section (no tab gating) — for content that's always visible. */
60
+ const Section = ({ children }) => (_jsx("div", { style: { padding: "10px 12px", borderBottom: "1px solid var(--border, #2a2a2a)" }, children: children }));
61
+ Sidebar.Header = Header;
62
+ Sidebar.TabTriggers = TabTriggers;
63
+ Sidebar.Trigger = Trigger;
64
+ Sidebar.Tab = Tab;
65
+ Sidebar.Section = Section;
66
+ //# sourceMappingURL=sidebar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sidebar.js","sourceRoot":"","sources":["../src/sidebar.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Native `<input type=range>` wrapped in a styled track. Drives
3
+ * continuous numeric properties (opacity, blur, …). Optional
4
+ * `valueLabel` shows the formatted current value alongside the track —
5
+ * the host owns the formatter (e.g. `${Math.round(v * 100)}%`).
6
+ *
7
+ * `value === null` (mixed multi-selection) leaves the thumb at the
8
+ * midpoint of the range and renders a "—" label until the user moves it.
9
+ */
10
+ export interface SliderProps {
11
+ readonly value: number | null;
12
+ readonly min: number;
13
+ readonly max: number;
14
+ readonly step?: number;
15
+ readonly onChange: (value: number) => void;
16
+ readonly ariaLabel?: string;
17
+ readonly valueLabel?: string;
18
+ }
19
+ export declare const Slider: ({ value, min, max, step, onChange, ariaLabel, valueLabel, }: SliderProps) => import("react/jsx-runtime").JSX.Element;
20
+ //# sourceMappingURL=slider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slider.d.ts","sourceRoot":"","sources":["../src/slider.tsx"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,eAAO,MAAM,MAAM,GAAI,6DAQpB,WAAW,4CAoBb,CAAC"}
package/dist/slider.js ADDED
@@ -0,0 +1,9 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ export const Slider = ({ value, min, max, step = 1, onChange, ariaLabel, valueLabel, }) => {
3
+ const handle = (ev) => {
4
+ onChange(Number(ev.target.value));
5
+ };
6
+ const thumbValue = value ?? (min + max) / 2;
7
+ return (_jsxs("div", { className: "du-slider", children: [_jsx("input", { type: "range", min: min, max: max, step: step, value: thumbValue, onChange: handle, "aria-label": ariaLabel, className: "du-slider-track" }), _jsx("span", { className: "du-slider-value", children: value === null ? "—" : valueLabel ?? value })] }));
8
+ };
9
+ //# sourceMappingURL=slider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slider.js","sourceRoot":"","sources":["../src/slider.tsx"],"names":[],"mappings":";AAqBA,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,EACrB,KAAK,EACL,GAAG,EACH,GAAG,EACH,IAAI,GAAG,CAAC,EACR,QAAQ,EACR,SAAS,EACT,UAAU,GACE,EAAE,EAAE;IAChB,MAAM,MAAM,GAAG,CAAC,EAAiC,EAAQ,EAAE;QACzD,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IACpC,CAAC,CAAC;IACF,MAAM,UAAU,GAAG,KAAK,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;IAC5C,OAAO,CACL,eAAK,SAAS,EAAC,WAAW,aACxB,gBACE,IAAI,EAAC,OAAO,EACZ,GAAG,EAAE,GAAG,EACR,GAAG,EAAE,GAAG,EACR,IAAI,EAAE,IAAI,EACV,KAAK,EAAE,UAAU,EACjB,QAAQ,EAAE,MAAM,gBACJ,SAAS,EACrB,SAAS,EAAC,iBAAiB,GAC3B,EACF,eAAM,SAAS,EAAC,iBAAiB,YAAE,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,IAAI,KAAK,GAAQ,IACjF,CACP,CAAC;AACJ,CAAC,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Invisible keystroke/IME sink for in-canvas text editing. The caret and
3
+ * selection are drawn on the canvas by the renderer (the editor's
4
+ * overlay pass); this component is not a visible editor — it is a 1×1,
5
+ * fully-transparent `<textarea>` that holds keyboard focus so the
6
+ * browser delivers typing, IME composition, clipboard and native
7
+ * caret/selection navigation. Each change is mirrored into the editor
8
+ * (`setEditingText` / `setEditingSelection`), which mutates the shape's
9
+ * text live and owns the on-canvas caret.
10
+ *
11
+ * Wiring: drop as a sibling of `<DiagramSurface>` inside `<DiagramRoot>`.
12
+ * Editing opens via `editor.beginTextEdit(id)` / the text tool; it
13
+ * commits on Escape, on a click outside the shape, or on a tool change.
14
+ */
15
+ export declare const TextEditorOverlay: () => import("react/jsx-runtime").JSX.Element | null;
16
+ //# sourceMappingURL=text-editor-overlay.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text-editor-overlay.d.ts","sourceRoot":"","sources":["../src/text-editor-overlay.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,iBAAiB,sDA4G7B,CAAC"}
@@ -0,0 +1,112 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useEffect, useLayoutEffect, useReducer, useRef } from "react";
3
+ import { getElement } from "@oh-just-another/scene";
4
+ import { useDiagramOptional } from "./hooks.js";
5
+ /**
6
+ * Invisible keystroke/IME sink for in-canvas text editing. The caret and
7
+ * selection are drawn on the canvas by the renderer (the editor's
8
+ * overlay pass); this component is not a visible editor — it is a 1×1,
9
+ * fully-transparent `<textarea>` that holds keyboard focus so the
10
+ * browser delivers typing, IME composition, clipboard and native
11
+ * caret/selection navigation. Each change is mirrored into the editor
12
+ * (`setEditingText` / `setEditingSelection`), which mutates the shape's
13
+ * text live and owns the on-canvas caret.
14
+ *
15
+ * Wiring: drop as a sibling of `<DiagramSurface>` inside `<DiagramRoot>`.
16
+ * Editing opens via `editor.beginTextEdit(id)` / the text tool; it
17
+ * commits on Escape, on a click outside the shape, or on a tool change.
18
+ */
19
+ export const TextEditorOverlay = () => {
20
+ const editor = useDiagramOptional();
21
+ const ref = useRef(null);
22
+ const [, force] = useReducer((x) => x + 1, 0);
23
+ // Re-render on any editor change so value/selection stay mirrored.
24
+ useEffect(() => {
25
+ if (!editor)
26
+ return undefined;
27
+ return editor.on("change", force);
28
+ }, [editor]);
29
+ const editingId = editor?.editingTextElement ?? null;
30
+ // Focus the sink whenever an edit starts.
31
+ useEffect(() => {
32
+ if (!editingId)
33
+ return;
34
+ ref.current?.focus();
35
+ }, [editingId]);
36
+ // Mirror the editor's text + selection INTO the textarea so native
37
+ // navigation, IME and typing all operate on the live content. Guarded
38
+ // so it never fights the user's own caret.
39
+ useLayoutEffect(() => {
40
+ const ta = ref.current;
41
+ if (!editor || !editingId || !ta)
42
+ return;
43
+ const shape = getElement(editor.scene, editingId);
44
+ const text = shape?.type === "text" ? shape.text : "";
45
+ if (ta.value !== text)
46
+ ta.value = text;
47
+ const sel = editor.editingTextSelection;
48
+ if (sel && (ta.selectionStart !== sel.start || ta.selectionEnd !== sel.end)) {
49
+ ta.setSelectionRange(sel.start, sel.end, sel.dir);
50
+ }
51
+ });
52
+ if (!editor || !editingId)
53
+ return null;
54
+ const shape = getElement(editor.scene, editingId);
55
+ if (shape?.type !== "text")
56
+ return null;
57
+ // Park the sink at the text's screen position so the IME candidate
58
+ // window appears near the caret. It's invisible and click-through.
59
+ const vp = editor.scene.viewport;
60
+ const left = (shape.position.x - vp.pan.x) * vp.zoom;
61
+ const top = (shape.position.y - vp.pan.y) * vp.zoom;
62
+ const dirOf = (ta) => ta.selectionDirection === "backward" ? "backward" : "forward";
63
+ return (_jsx("textarea", { ref: ref, defaultValue: shape.text,
64
+ // `onInput` covers typing, paste, cut, delete and IME end — read
65
+ // the textarea's authoritative value + caret and push them live.
66
+ onInput: (ev) => {
67
+ const t = ev.currentTarget;
68
+ editor.setEditingText(t.value, t.selectionStart, t.selectionEnd, dirOf(t));
69
+ }, onSelect: (ev) => {
70
+ const t = ev.currentTarget;
71
+ editor.setEditingSelection(t.selectionStart, t.selectionEnd, dirOf(t));
72
+ }, onKeyDown: (ev) => {
73
+ // Escape (and Cmd/Ctrl+Enter) commit and exit; plain Enter is a
74
+ // newline (native textarea behaviour, mirrored via onInput).
75
+ if (ev.key === "Escape" || (ev.key === "Enter" && (ev.metaKey || ev.ctrlKey))) {
76
+ ev.preventDefault();
77
+ ev.stopPropagation();
78
+ editor.commitTextEdit();
79
+ }
80
+ }, onBlur: () => {
81
+ // A click inside the text repositions the caret (canvas handles
82
+ // it) and must NOT end editing — keep focus if still in an edit
83
+ // after the click resolves. A real exit (commit) clears
84
+ // `editingTextElement`, so it won't refocus then.
85
+ const id = editingId;
86
+ setTimeout(() => {
87
+ const ta = ref.current;
88
+ if (ta && editor.editingTextElement === id && document.activeElement !== ta) {
89
+ ta.focus();
90
+ }
91
+ }, 0);
92
+ }, spellCheck: false, autoCapitalize: "off", autoCorrect: "off", "aria-label": "Text editor", style: {
93
+ position: "absolute",
94
+ top,
95
+ left,
96
+ width: 1,
97
+ height: 1,
98
+ padding: 0,
99
+ margin: 0,
100
+ border: 0,
101
+ outline: "none",
102
+ opacity: 0,
103
+ resize: "none",
104
+ overflow: "hidden",
105
+ whiteSpace: "pre",
106
+ // Click-through so canvas pointer handling (caret placement /
107
+ // drag-select / commit-outside) receives the events.
108
+ pointerEvents: "none",
109
+ zIndex: 100,
110
+ } }));
111
+ };
112
+ //# sourceMappingURL=text-editor-overlay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text-editor-overlay.js","sourceRoot":"","sources":["../src/text-editor-overlay.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ import { type CSSProperties, type ReactNode } from "react";
2
+ /**
3
+ * In-process toast bus. Hosts mount `<ToastHost>` once at the root;
4
+ * descendants call `useToast()` to push messages. Each toast dismisses
5
+ * itself after `duration` ms; the × button closes it manually.
6
+ */
7
+ export type ToastKind = "info" | "success" | "warn" | "error";
8
+ export interface Toast {
9
+ readonly id: string;
10
+ readonly kind: ToastKind;
11
+ readonly message: string;
12
+ /** ms before auto-dismiss; 0 / Infinity keeps it open. */
13
+ readonly duration?: number;
14
+ }
15
+ export interface ToastApi {
16
+ push(message: string, kind?: ToastKind, duration?: number): string;
17
+ dismiss(id: string): void;
18
+ }
19
+ export declare const useToast: () => ToastApi;
20
+ /** Like `useToast` but returns null instead of throwing. */
21
+ export declare const useToastOptional: () => ToastApi | null;
22
+ export interface ToastHostProps {
23
+ readonly children?: ReactNode;
24
+ /** Default duration for `push` calls that omit the argument. */
25
+ readonly defaultDuration?: number;
26
+ readonly style?: CSSProperties;
27
+ }
28
+ export declare const ToastHost: ({ children, defaultDuration, style, }: ToastHostProps) => import("react/jsx-runtime").JSX.Element;
29
+ /**
30
+ * Auto-mount helper for hosts that want a single ToastHost at the top
31
+ * of their component tree without writing the JSX themselves.
32
+ */
33
+ export declare const useEphemeralToast: (message: string, kind?: ToastKind) => void;
34
+ //# sourceMappingURL=toast.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toast.d.ts","sourceRoot":"","sources":["../src/toast.tsx"],"names":[],"mappings":"AAAA,OAAO,EAQL,KAAK,aAAa,EAClB,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAGf;;;;GAIG;AAEH,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC;AAE9D,MAAM,WAAW,KAAK;IACpB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,0DAA0D;IAC1D,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACnE,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAID,eAAO,MAAM,QAAQ,QAAO,QAI3B,CAAC;AAEF,4DAA4D;AAC5D,eAAO,MAAM,gBAAgB,QAAO,QAAQ,GAAG,IAAgC,CAAC;AAEhF,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAC;IAC9B,gEAAgE;IAChE,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,KAAK,CAAC,EAAE,aAAa,CAAC;CAChC;AAED,eAAO,MAAM,SAAS,GAAI,uCAIvB,cAAc,4CA6BhB,CAAC;AAoFF;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAAI,SAAS,MAAM,EAAE,OAAM,SAAkB,KAAG,IAK7E,CAAC"}
package/dist/toast.js ADDED
@@ -0,0 +1,89 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState, } from "react";
3
+ import { TOAST_DEFAULT_DURATION_MS } from "./constants.js";
4
+ const ToastContext = createContext(null);
5
+ export const useToast = () => {
6
+ const ctx = useContext(ToastContext);
7
+ if (!ctx)
8
+ throw new Error("useToast: must be wrapped in <ToastHost>");
9
+ return ctx;
10
+ };
11
+ /** Like `useToast` but returns null instead of throwing. */
12
+ export const useToastOptional = () => useContext(ToastContext);
13
+ export const ToastHost = ({ children, defaultDuration = TOAST_DEFAULT_DURATION_MS, style, }) => {
14
+ const [items, setItems] = useState([]);
15
+ const counter = useRef(0);
16
+ const dismiss = useCallback((id) => {
17
+ setItems((prev) => prev.filter((t) => t.id !== id));
18
+ }, []);
19
+ const push = useCallback((message, kind = "info", duration) => {
20
+ const id = `toast-${++counter.current}`;
21
+ const ttl = duration ?? defaultDuration;
22
+ setItems((prev) => [...prev, { id, kind, message, duration: ttl }]);
23
+ if (ttl > 0 && Number.isFinite(ttl)) {
24
+ window.setTimeout(() => { dismiss(id); }, ttl);
25
+ }
26
+ return id;
27
+ }, [defaultDuration, dismiss]);
28
+ const api = useMemo(() => ({ push, dismiss }), [push, dismiss]);
29
+ return (_jsxs(ToastContext.Provider, { value: api, children: [children, _jsx(ToastStack, { toasts: items, onDismiss: dismiss, ...(style ? { style } : {}) })] }));
30
+ };
31
+ const ToastStack = ({ toasts, onDismiss, style, }) => {
32
+ const stackStyle = {
33
+ position: "fixed",
34
+ top: 16,
35
+ right: 16,
36
+ zIndex: 1100,
37
+ display: "flex",
38
+ flexDirection: "column",
39
+ gap: 8,
40
+ pointerEvents: "none",
41
+ ...style,
42
+ };
43
+ return (_jsx("div", { style: stackStyle, "aria-live": "polite", "aria-atomic": "false", children: toasts.map((t) => (_jsx(ToastItem, { toast: t, onDismiss: onDismiss }, t.id))) }));
44
+ };
45
+ const KIND_ACCENT = {
46
+ info: "var(--accent, #1a73e8)",
47
+ success: "#2e8b57",
48
+ warn: "#c79100",
49
+ error: "#c83232",
50
+ };
51
+ const ToastItem = ({ toast, onDismiss, }) => {
52
+ const itemStyle = {
53
+ pointerEvents: "auto",
54
+ minWidth: 240,
55
+ maxWidth: 360,
56
+ padding: "10px 12px",
57
+ background: "var(--panel, #1a1a1a)",
58
+ color: "var(--text, #ddd)",
59
+ border: "1px solid var(--border, #2a2a2a)",
60
+ borderLeft: `4px solid ${KIND_ACCENT[toast.kind]}`,
61
+ borderRadius: 4,
62
+ boxShadow: "0 4px 14px rgba(0, 0, 0, 0.3)",
63
+ fontSize: 13,
64
+ display: "flex",
65
+ alignItems: "flex-start",
66
+ gap: 12,
67
+ };
68
+ return (_jsxs("div", { role: "status", style: itemStyle, children: [_jsx("span", { style: { flex: 1, lineHeight: 1.35 }, children: toast.message }), _jsx("button", { type: "button", "aria-label": "Dismiss", onClick: () => { onDismiss(toast.id); }, style: {
69
+ background: "transparent",
70
+ border: "none",
71
+ color: "var(--muted, #888)",
72
+ cursor: "pointer",
73
+ fontSize: 16,
74
+ lineHeight: 1,
75
+ padding: 0,
76
+ }, children: "\u00D7" })] }));
77
+ };
78
+ /**
79
+ * Auto-mount helper for hosts that want a single ToastHost at the top
80
+ * of their component tree without writing the JSX themselves.
81
+ */
82
+ export const useEphemeralToast = (message, kind = "info") => {
83
+ const toast = useToastOptional();
84
+ useEffect(() => {
85
+ if (toast && message)
86
+ toast.push(message, kind);
87
+ }, [toast, message, kind]);
88
+ };
89
+ //# sourceMappingURL=toast.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toast.js","sourceRoot":"","sources":["../src/toast.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,149 @@
1
+ import { type CSSProperties, type ReactNode } from "react";
2
+ import type { Editor, Mode } from "@oh-just-another/state";
3
+ /**
4
+ * Single toolbar item. Builtin `mode` items wire to `editor.setMode`;
5
+ * `action` items receive the live editor and decide what to do; `divider`
6
+ * draws a thin vertical separator. The `zoom-*` kinds let hosts place
7
+ * individual zoom controls anywhere in the toolbar; `zoom` packs all
8
+ * four into a single compact widget (− / % / + / Fit).
9
+ */
10
+ export type ToolbarItem = {
11
+ readonly kind: "mode";
12
+ readonly mode: Mode;
13
+ readonly label: ReactNode;
14
+ readonly title?: string;
15
+ } | {
16
+ readonly kind: "action";
17
+ readonly id: string;
18
+ readonly label: ReactNode;
19
+ readonly title?: string;
20
+ readonly disabled?: boolean;
21
+ /** Render the button in its pressed/active state (e.g. a toggle). */
22
+ readonly active?: boolean;
23
+ readonly onClick: (editor: Editor) => void;
24
+ } | {
25
+ /**
26
+ * Button sourced from a registered action by id — label / icon /
27
+ * hotkey / pressed (`checked`) / disabled (`predicate`) all come from
28
+ * `defaultActionRegistry`. The registry-driven way to place a built-in
29
+ * (mode-*, undo, redo, tool-lock, …) on the toolbar.
30
+ */
31
+ readonly kind: "action-ref";
32
+ readonly id: string;
33
+ } | {
34
+ readonly kind: "divider";
35
+ } | {
36
+ readonly kind: "undo";
37
+ readonly label?: ReactNode;
38
+ } | {
39
+ readonly kind: "redo";
40
+ readonly label?: ReactNode;
41
+ } | {
42
+ readonly kind: "zoom";
43
+ } | {
44
+ readonly kind: "zoom-in";
45
+ readonly label?: ReactNode;
46
+ } | {
47
+ readonly kind: "zoom-out";
48
+ readonly label?: ReactNode;
49
+ } | {
50
+ readonly kind: "zoom-reset";
51
+ readonly label?: ReactNode;
52
+ } | {
53
+ readonly kind: "zoom-fit";
54
+ readonly label?: ReactNode;
55
+ } | {
56
+ readonly kind: "zoom-display";
57
+ } | {
58
+ /**
59
+ * Tool-lock toggle. Renders a pressed-when-locked button; click flips
60
+ * `editor.toolLocked`. When locked, draw modes (rectangle / ellipse /
61
+ * edge / brush) persist after each create instead of reverting to
62
+ * select.
63
+ */
64
+ readonly kind: "tool-lock";
65
+ readonly label?: ReactNode;
66
+ readonly title?: string;
67
+ };
68
+ /**
69
+ * Open an OS file picker for image(s) and insert them at the viewport
70
+ * centre via the editor's file-drop pipeline (same path as drag-and-drop,
71
+ * so sizing / GIF animation / Scene.files registration all apply).
72
+ * Multi-select supported — each file dispatched independently.
73
+ *
74
+ * Lives in the UI layer rather than the L2 `state` package because it
75
+ * touches the DOM (`<input type=file>`). Exported so hosts can wire it to
76
+ * a hotkey or a custom button.
77
+ */
78
+ export declare const openImageFilePicker: (editor: Editor) => void;
79
+ /** Convenience default — modes + tool-lock + undo/redo + zoom widget. */
80
+ export declare const DEFAULT_TOOLBAR: readonly ToolbarItem[];
81
+ /**
82
+ * Creation-tool set for the vertical left dock. Just the creation tools +
83
+ * the tool-lock toggle — no undo/redo/zoom (those live in the menu /
84
+ * bottom-left). Hosts prepend their own leading items (e.g. a
85
+ * templates-library toggle) and render with
86
+ * `<Toolbar orientation="vertical" />`.
87
+ */
88
+ export declare const DEFAULT_VERTICAL_TOOLBAR: readonly ToolbarItem[];
89
+ export interface ToolbarProps {
90
+ readonly items?: readonly ToolbarItem[];
91
+ readonly style?: CSSProperties;
92
+ readonly className?: string;
93
+ /**
94
+ * Lay the toolbar out as a horizontal row (default) or a vertical
95
+ * column (the left creation dock). Vertical flips the button-group
96
+ * flex direction and draws horizontal dividers.
97
+ */
98
+ readonly orientation?: "horizontal" | "vertical";
99
+ }
100
+ export declare const Toolbar: ({ items, style, className, orientation, }: ToolbarProps) => import("react/jsx-runtime").JSX.Element;
101
+ /**
102
+ * Pressable tool-lock affordance. Reads `editor.toolLocked` reactively so
103
+ * the active state stays in sync when the user toggles via hotkey or
104
+ * context menu.
105
+ */
106
+ export declare const ToolLockButton: ({ label, title, }: {
107
+ readonly label?: ReactNode;
108
+ readonly title?: string;
109
+ }) => import("react/jsx-runtime").JSX.Element;
110
+ export interface ZoomButtonProps {
111
+ readonly label?: ReactNode;
112
+ readonly title?: string;
113
+ readonly className?: string;
114
+ readonly style?: CSSProperties;
115
+ }
116
+ /** "−" — calls `editor.zoomOut()`. */
117
+ export declare const ZoomOutButton: ({ label, title, className, style, }: ZoomButtonProps) => import("react/jsx-runtime").JSX.Element;
118
+ /** "+" — calls `editor.zoomIn()`. */
119
+ export declare const ZoomInButton: ({ label, title, className, style, }: ZoomButtonProps) => import("react/jsx-runtime").JSX.Element;
120
+ /** "100%" / "Reset" — calls `editor.resetZoom()`. */
121
+ export declare const ResetZoomButton: ({ label, title, className, style, }: ZoomButtonProps) => import("react/jsx-runtime").JSX.Element;
122
+ /** "Fit" — calls `editor.zoomToFit()`. */
123
+ export declare const ZoomToFitButton: ({ label, title, className, style, }: ZoomButtonProps) => import("react/jsx-runtime").JSX.Element;
124
+ /**
125
+ * Live zoom percent. Clicks reset zoom to 100% — same UX as the percent
126
+ * button in `ZoomWidget`.
127
+ */
128
+ export declare const ZoomDisplay: ({ className, style }: {
129
+ readonly className?: string;
130
+ readonly style?: CSSProperties;
131
+ }) => import("react/jsx-runtime").JSX.Element;
132
+ /**
133
+ * Pre-composed inline zoom widget: − / current % / + / Fit. Equivalent
134
+ * to laying the four standalone buttons + display in a row.
135
+ */
136
+ export declare const ZoomWidget: ({ className, style }: {
137
+ readonly className?: string;
138
+ readonly style?: CSSProperties;
139
+ }) => import("react/jsx-runtime").JSX.Element;
140
+ /**
141
+ * Floating zoom controls — bottom-right cluster with rounded shadow
142
+ * chrome. Drops the widget into a corner so the toolbar stays free for
143
+ * tools. Hosts that need a different position pass `style`.
144
+ */
145
+ export declare const FloatingZoomControls: ({ className, style, }: {
146
+ readonly className?: string;
147
+ readonly style?: CSSProperties;
148
+ }) => import("react/jsx-runtime").JSX.Element;
149
+ //# sourceMappingURL=toolbar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toolbar.d.ts","sourceRoot":"","sources":["../src/toolbar.tsx"],"names":[],"mappings":"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"}