@examplary/ui 1.19.0 → 1.21.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 (38) hide show
  1. package/dist/components/rich-text/index.d.ts +1 -0
  2. package/dist/components/rich-text/index.js +1 -0
  3. package/dist/components/rich-text/math-view.d.ts +3 -0
  4. package/dist/components/rich-text/math-view.js +25 -0
  5. package/dist/components/rich-text/minimal-rich-text-field.js +7 -6
  6. package/dist/components/rich-text/rich-text-display.js +1 -14
  7. package/dist/components/rich-text/rich-text-toolbar.js +2 -2
  8. package/dist/components/rich-text/tiptap/crop-page-clipping-modal.d.ts +6 -0
  9. package/dist/components/rich-text/tiptap/crop-page-clipping-modal.js +48 -0
  10. package/dist/components/rich-text/tiptap/mathematics-component.d.ts +14 -0
  11. package/dist/components/rich-text/tiptap/mathematics-component.js +59 -0
  12. package/dist/components/rich-text/tiptap/mathematics.d.ts +41 -0
  13. package/dist/components/rich-text/tiptap/mathematics.js +131 -0
  14. package/dist/components/rich-text/tiptap/rich-text-formatting-menu.d.ts +2 -1
  15. package/dist/components/rich-text/tiptap/rich-text-formatting-menu.js +34 -4
  16. package/dist/components/ui/checkbox.js +2 -2
  17. package/dist/components/ui/dialog.js +3 -3
  18. package/dist/components/ui/dropdown.d.ts +1 -0
  19. package/dist/components/ui/dropdown.js +13 -6
  20. package/dist/components/ui/help-icon.d.ts +9 -0
  21. package/dist/components/ui/help-icon.js +8 -0
  22. package/dist/components/ui/index.d.ts +1 -0
  23. package/dist/components/ui/index.js +1 -0
  24. package/dist/components/ui/input.js +1 -1
  25. package/dist/components/ui/label.d.ts +3 -1
  26. package/dist/components/ui/label.js +5 -4
  27. package/dist/components/ui/progress-bar.js +1 -1
  28. package/dist/components/ui/resizable.js +2 -2
  29. package/dist/components/ui/select.js +5 -5
  30. package/dist/components/ui/sheet.js +2 -2
  31. package/dist/components/ui/textarea.js +1 -1
  32. package/dist/components/web-components/index.d.ts +1 -0
  33. package/dist/components/web-components/index.js +5 -0
  34. package/dist/components/web-components/inline-math.d.ts +6 -0
  35. package/dist/components/web-components/inline-math.js +55 -0
  36. package/dist/src/global.css +1 -1
  37. package/package.json +18 -16
  38. package/src/global.css +5 -0
@@ -2,4 +2,5 @@ export { RichTextDisplay } from "./rich-text-display";
2
2
  export { RichTextField } from "./rich-text-field";
3
3
  export { RichTextToolbar } from "./rich-text-toolbar";
4
4
  export { MinimalRichTextField } from "./minimal-rich-text-field";
5
+ export { MathView } from "./math-view";
5
6
  export { processFilesAsString } from "./tiptap/file-handler";
@@ -2,4 +2,5 @@ export { RichTextDisplay } from "./rich-text-display";
2
2
  export { RichTextField } from "./rich-text-field";
3
3
  export { RichTextToolbar } from "./rich-text-toolbar";
4
4
  export { MinimalRichTextField } from "./minimal-rich-text-field";
5
+ export { MathView } from "./math-view";
5
6
  export { processFilesAsString } from "./tiptap/file-handler";
@@ -0,0 +1,3 @@
1
+ export declare const MathView: ({ children }: {
2
+ children?: string;
3
+ }) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,25 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useMemo } from "react";
3
+ import KaTeX from "katex";
4
+ export var MathView = function (_a) {
5
+ var children = _a.children;
6
+ var _b = useMemo(function () {
7
+ try {
8
+ var html_1 = KaTeX.renderToString(children !== null && children !== void 0 ? children : "", {
9
+ displayMode: false,
10
+ throwOnError: false,
11
+ });
12
+ return { html: html_1, error: undefined };
13
+ }
14
+ catch (error) {
15
+ if (error instanceof KaTeX.ParseError || error instanceof TypeError) {
16
+ return { error: error };
17
+ }
18
+ throw error;
19
+ }
20
+ }, [children]), html = _b.html, error = _b.error;
21
+ if (error) {
22
+ return _jsx("span", { children: error.message });
23
+ }
24
+ return _jsx("span", { dangerouslySetInnerHTML: { __html: html } });
25
+ };
@@ -34,8 +34,7 @@ import { useEffect, useMemo, useState } from "react";
34
34
  import Document from "@tiptap/extension-document";
35
35
  import Highlight from "@tiptap/extension-highlight";
36
36
  import Link from "@tiptap/extension-link";
37
- // TODO: fix maths integration
38
- // import Mathematics, { migrateMathStrings } from "@tiptap/extension-mathematics";
37
+ import { migrateMathStrings } from "@tiptap/extension-mathematics";
39
38
  import Placeholder from "@tiptap/extension-placeholder";
40
39
  import { TableKit } from "@tiptap/extension-table";
41
40
  import Typography from "@tiptap/extension-typography";
@@ -46,6 +45,7 @@ import { registerWebComponents } from "../web-components";
46
45
  import FileAttachment from "./tiptap/file-attachment";
47
46
  import { fileHandler } from "./tiptap/file-handler";
48
47
  import Image from "./tiptap/image";
48
+ import { Mathematics } from "./tiptap/mathematics";
49
49
  import PageClipping from "./tiptap/page-clipping";
50
50
  import { RichTextFormattingMenu } from "./tiptap/rich-text-formatting-menu";
51
51
  registerWebComponents();
@@ -88,7 +88,7 @@ export var MinimalRichTextField = function (_a) {
88
88
  placeholder && Placeholder.configure({ placeholder: placeholder }),
89
89
  FileAttachment,
90
90
  PageClipping,
91
- // Mathematics,
91
+ Mathematics,
92
92
  Highlight,
93
93
  TableKit.configure({
94
94
  table: { resizable: true },
@@ -110,9 +110,10 @@ export var MinimalRichTextField = function (_a) {
110
110
  html = isEmpty(html) ? "" : html;
111
111
  onBlur === null || onBlur === void 0 ? void 0 : onBlur(html);
112
112
  },
113
- // onCreate: ({ editor: currentEditor }) => {
114
- // migrateMathStrings(currentEditor);
115
- // },
113
+ onCreate: function (_a) {
114
+ var currentEditor = _a.editor;
115
+ migrateMathStrings(currentEditor);
116
+ },
116
117
  autofocus: autoFocus,
117
118
  content: content,
118
119
  extensions: extensions,
@@ -20,24 +20,11 @@ var __rest = (this && this.__rest) || function (s, e) {
20
20
  }
21
21
  return t;
22
22
  };
23
- import { createElement, useEffect, useRef } from "react";
24
- import renderMathInElement from "katex/dist/contrib/auto-render.js";
23
+ import { createElement, useRef } from "react";
25
24
  import { cn } from "../../utils";
26
25
  export var RichTextDisplay = function (_a) {
27
26
  var _b = _a.as, as = _b === void 0 ? "div" : _b, children = _a.children, _c = _a.className, className = _c === void 0 ? "" : _c, props = __rest(_a, ["as", "children", "className"]);
28
27
  var ref = useRef(null);
29
- useEffect(function () {
30
- if (!ref.current)
31
- return;
32
- renderMathInElement(ref.current, {
33
- throwOnError: false,
34
- delimiters: [
35
- { left: "$$", right: "$$", display: true },
36
- { left: "@@", right: "@@", display: true },
37
- { left: "$", right: "$", display: false },
38
- ],
39
- });
40
- });
41
28
  // eslint-disable-next-line react-hooks/refs
42
29
  return createElement(as, __assign(__assign({}, props), { key: "rich-text-display", className: cn("tiptap", className), dangerouslySetInnerHTML: { __html: children }, ref: ref }));
43
30
  };
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useCallback } from "react";
3
- import { Bold, Italic, LinkIcon, List, TextQuote } from "lucide-react";
3
+ import { BoldIcon, ItalicIcon, LinkIcon, ListIcon, TextQuoteIcon, } from "lucide-react";
4
4
  import { cn } from "../../utils";
5
5
  export var RichTextToolbar = function (_a) {
6
6
  var editor = _a.editor;
@@ -29,5 +29,5 @@ export var RichTextToolbar = function (_a) {
29
29
  if (!editor) {
30
30
  return null;
31
31
  }
32
- return (_jsxs("div", { className: "border border-border border-b-0 rounded-t-base p-1 gap-1 flex items-center", children: [_jsx("span", { onClick: function () { return editor.chain().focus().toggleBold().run(); }, className: cn("p-2 cursor-pointer", editor.isActive("bold") ? "bg-bright rounded-base" : ""), children: _jsx(Bold, { size: 16 }) }), _jsx("span", { onClick: function () { return editor.chain().focus().toggleItalic().run(); }, className: cn("p-2 cursor-pointer", editor.isActive("italic") ? "bg-bright rounded-base" : ""), children: _jsx(Italic, { size: 16 }) }), _jsx("span", { onClick: setLink, className: cn("p-2 cursor-pointer", editor.isActive("link") ? "bg-bright rounded-base" : ""), children: _jsx(LinkIcon, { size: 16 }) }), _jsx("span", { onClick: function () { return editor.chain().focus().toggleBulletList().run(); }, className: cn("p-2 cursor-pointer", editor.isActive("bulletList") ? "bg-bright rounded-base" : ""), children: _jsx(List, { size: 16 }) }), _jsx("span", { onClick: function () { return editor.chain().focus().toggleOrderedList().run(); }, className: cn("p-2 cursor-pointer", editor.isActive("orderedList") ? "bg-bright rounded-base" : ""), children: _jsx(List, { size: 16 }) }), _jsx("span", { onClick: function () { return editor.chain().focus().toggleBlockquote().run(); }, className: cn("p-2 cursor-pointer", editor.isActive("blockquote") ? "bg-bright rounded-base" : ""), children: _jsx(TextQuote, { size: 16 }) })] }));
32
+ return (_jsxs("div", { className: "border border-border border-b-0 rounded-t-base p-1 gap-1 flex items-center", children: [_jsx("span", { onClick: function () { return editor.chain().focus().toggleBold().run(); }, className: cn("p-2 cursor-pointer", editor.isActive("bold") ? "bg-bright rounded-base" : ""), children: _jsx(BoldIcon, { size: 16 }) }), _jsx("span", { onClick: function () { return editor.chain().focus().toggleItalic().run(); }, className: cn("p-2 cursor-pointer", editor.isActive("italic") ? "bg-bright rounded-base" : ""), children: _jsx(ItalicIcon, { size: 16 }) }), _jsx("span", { onClick: setLink, className: cn("p-2 cursor-pointer", editor.isActive("link") ? "bg-bright rounded-base" : ""), children: _jsx(LinkIcon, { size: 16 }) }), _jsx("span", { onClick: function () { return editor.chain().focus().toggleBulletList().run(); }, className: cn("p-2 cursor-pointer", editor.isActive("bulletList") ? "bg-bright rounded-base" : ""), children: _jsx(ListIcon, { size: 16 }) }), _jsx("span", { onClick: function () { return editor.chain().focus().toggleOrderedList().run(); }, className: cn("p-2 cursor-pointer", editor.isActive("orderedList") ? "bg-bright rounded-base" : ""), children: _jsx(ListIcon, { size: 16 }) }), _jsx("span", { onClick: function () { return editor.chain().focus().toggleBlockquote().run(); }, className: cn("p-2 cursor-pointer", editor.isActive("blockquote") ? "bg-bright rounded-base" : ""), children: _jsx(TextQuoteIcon, { size: 16 }) })] }));
33
33
  };
@@ -0,0 +1,6 @@
1
+ import "react-image-crop/dist/ReactCrop.css";
2
+ export declare const CropPageClippingModal: ({ pageClipping, onClose, onUpdate }: {
3
+ pageClipping: any;
4
+ onClose: any;
5
+ onUpdate: any;
6
+ }) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,48 @@
1
+ var __assign = (this && this.__assign) || function () {
2
+ __assign = Object.assign || function(t) {
3
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
4
+ s = arguments[i];
5
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
6
+ t[p] = s[p];
7
+ }
8
+ return t;
9
+ };
10
+ return __assign.apply(this, arguments);
11
+ };
12
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
13
+ import { useEffect, useState } from "react";
14
+ import { Trans } from "react-i18next";
15
+ import ReactCrop from "react-image-crop";
16
+ import "react-image-crop/dist/ReactCrop.css";
17
+ import { Button } from "../../ui/button";
18
+ import { Dialog, DialogContent, DialogFooter, } from "../../ui/dialog";
19
+ export var CropPageClippingModal = function (_a) {
20
+ var pageClipping = _a.pageClipping, onClose = _a.onClose, onUpdate = _a.onUpdate;
21
+ var _b = useState(), crop = _b[0], setCrop = _b[1];
22
+ var url = "https://page-clippings.examplary.ai/?".concat(new URLSearchParams({
23
+ url: pageClipping === null || pageClipping === void 0 ? void 0 : pageClipping.url,
24
+ page: pageClipping === null || pageClipping === void 0 ? void 0 : pageClipping.page,
25
+ x: "0",
26
+ y: "0",
27
+ width: "1",
28
+ height: "1",
29
+ }).toString());
30
+ useEffect(function () {
31
+ if (!pageClipping)
32
+ return;
33
+ setCrop({
34
+ unit: "%",
35
+ x: pageClipping.x * 100 || 0,
36
+ y: pageClipping.y * 100 || 0,
37
+ width: pageClipping.width * 100 || 100,
38
+ height: pageClipping.height * 100 || 100,
39
+ });
40
+ }, [pageClipping]);
41
+ var save = function () {
42
+ onUpdate(__assign(__assign({}, pageClipping), { x: ((crop === null || crop === void 0 ? void 0 : crop.x) || 0) / 100, y: ((crop === null || crop === void 0 ? void 0 : crop.y) || 0) / 100, width: ((crop === null || crop === void 0 ? void 0 : crop.width) || 100) / 100, height: ((crop === null || crop === void 0 ? void 0 : crop.height) || 100) / 100 }));
43
+ };
44
+ return (_jsx(Dialog, { open: !!pageClipping, onOpenChange: function (open) {
45
+ if (!open)
46
+ onClose();
47
+ }, children: _jsxs(DialogContent, { className: "sm:max-w-[725px]", showClose: false, children: [_jsx("div", { className: "flex items-center justify-center overflow-hidden mb-4", children: pageClipping && (_jsx(ReactCrop, { className: "max-h-[70vh] max-w-full", crop: crop, onChange: function (_, c) { return setCrop(c); }, children: _jsx("img", { src: url }) })) }), _jsx(DialogFooter, { children: _jsx(Button, { variant: "primary", type: "submit", onClick: save, children: _jsx(Trans, { children: "formatting.crop.crop" }) }) })] }) }));
48
+ };
@@ -0,0 +1,14 @@
1
+ import React from "react";
2
+ import { Editor } from "@tiptap/core";
3
+ import type { Node as PMNode } from "@tiptap/pm/model";
4
+ import "mathlive";
5
+ export declare const MathematicsEditComponent: React.FC<{
6
+ node: PMNode;
7
+ editor: Editor;
8
+ }>;
9
+ interface InlineMathProps {
10
+ children?: string;
11
+ onEdit: (newLatex: string) => void;
12
+ }
13
+ export declare const InlineMathView: React.FC<InlineMathProps>;
14
+ export {};
@@ -0,0 +1,59 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState } from "react";
3
+ import { NodeViewWrapper } from "@tiptap/react";
4
+ import { EditIcon } from "lucide-react";
5
+ import { cn } from "../../../utils";
6
+ import { Popover, PopoverTrigger, PopoverContent } from "../../ui/popover";
7
+ import "mathlive";
8
+ export var MathematicsEditComponent = function (_a) {
9
+ var node = _a.node, editor = _a.editor;
10
+ return (_jsx(NodeViewWrapper, { as: "span", children: _jsx(InlineMathView, { children: node.attrs.latex, onEdit: function (newLatex) {
11
+ editor.commands.updateInlineMath({ latex: newLatex });
12
+ } }, node.attrs.latex) }));
13
+ };
14
+ export var InlineMathView = function (_a) {
15
+ var children = _a.children, onEdit = _a.onEdit;
16
+ var _b = useState(false), menuOpen = _b[0], setMenuOpen = _b[1];
17
+ var _c = useState(children || ""), value = _c[0], setValue = _c[1];
18
+ return (_jsxs(Popover, { open: menuOpen, onOpenChange: function (open) {
19
+ var _a;
20
+ setMenuOpen(open);
21
+ if (!open && value !== children) {
22
+ onEdit === null || onEdit === void 0 ? void 0 : onEdit(value);
23
+ var keyboard = document.querySelector(".ML__keyboard");
24
+ if (keyboard)
25
+ (_a = keyboard.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(keyboard);
26
+ }
27
+ }, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs("span", { className: cn("rounded-2xl bg-pink-50 min-h-6 px-1.5 py-0.25 inline-flex gap-2.5 items-center cursor-pointer hover:bg-pink-200 group transition-all", menuOpen && "bg-pink-200"), children: [_jsx("inline-math", { children: children }), _jsx(EditIcon, { className: cn("text-pink-500 size-3 hidden group-hover:block shrink-0", menuOpen && "block") })] }) }), _jsx(PopoverContent, { align: "center", side: "bottom", sideOffset: -30, collisionPadding: 12, className: "border border-black p-0 bg-white rounded-md shadow-md max-w-none", onPointerDownOutside: function (event) {
28
+ var mathKeyboard = document.querySelector(".ML__keyboard");
29
+ if (mathKeyboard === null || mathKeyboard === void 0 ? void 0 : mathKeyboard.contains(event.target)) {
30
+ // Prevent closing when clicking on the math keyboard
31
+ event.preventDefault();
32
+ }
33
+ var mathField = document.querySelector("math-field");
34
+ if (mathField === null || mathField === void 0 ? void 0 : mathField.contains(event.target)) {
35
+ // Prevent closing when clicking on the math field
36
+ event.preventDefault();
37
+ }
38
+ }, children: _jsx("math-field", { className: "min-w-64 max-w-128 p-2 rounded-lg outline-none border-0 focus:ring-0", onInput: function (event) {
39
+ setValue(event.target.value);
40
+ var inputType = event.nativeEvent.inputType;
41
+ if (inputType === "insertLineBreak") {
42
+ // Close popover on Enter
43
+ setMenuOpen(false);
44
+ if (value !== children) {
45
+ onEdit === null || onEdit === void 0 ? void 0 : onEdit(value);
46
+ }
47
+ }
48
+ }, ref: function (el) {
49
+ if (!el)
50
+ return;
51
+ el.menuItems = el.menuItems.filter(function (item) {
52
+ return !item.id ||
53
+ (item.id !== "insert-matrix" &&
54
+ item.id !== "mode" &&
55
+ item.id !== "color" &&
56
+ item.id !== "background-color");
57
+ });
58
+ }, children: value }) })] }));
59
+ };
@@ -0,0 +1,41 @@
1
+ import { Node } from "@tiptap/core";
2
+ /**
3
+ * InlineMath is a Tiptap extension for rendering inline mathematical expressions using KaTeX.
4
+ * It allows users to insert LaTeX formatted math expressions inline within text.
5
+ * It supports rendering, input rules for LaTeX syntax, and click handling for interaction.
6
+ *
7
+ * Original:
8
+ * https://github.com/ueberdosis/tiptap/blob/develop/packages/extension-mathematics/src/extensions/InlineMath.ts
9
+ */
10
+ export declare const Mathematics: Node<any, any>;
11
+ declare module "@tiptap/core" {
12
+ interface Commands<ReturnType> {
13
+ inlineMath: {
14
+ /**
15
+ * Insert a inline math node with LaTeX string.
16
+ * @param options - Options for inserting inline math.
17
+ * @returns ReturnType
18
+ */
19
+ insertInlineMath: (options: {
20
+ latex: string;
21
+ pos?: number;
22
+ }) => ReturnType;
23
+ /**
24
+ * Delete an inline math node.
25
+ * @returns ReturnType
26
+ */
27
+ deleteInlineMath: (options?: {
28
+ pos?: number;
29
+ }) => ReturnType;
30
+ /**
31
+ * Update inline math node with optional LaTeX string.
32
+ * @param options - Options for updating inline math.
33
+ * @returns ReturnType
34
+ */
35
+ updateInlineMath: (options?: {
36
+ latex?: string;
37
+ pos?: number;
38
+ }) => ReturnType;
39
+ };
40
+ }
41
+ }
@@ -0,0 +1,131 @@
1
+ var __assign = (this && this.__assign) || function () {
2
+ __assign = Object.assign || function(t) {
3
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
4
+ s = arguments[i];
5
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
6
+ t[p] = s[p];
7
+ }
8
+ return t;
9
+ };
10
+ return __assign.apply(this, arguments);
11
+ };
12
+ import { InputRule, Node } from "@tiptap/core";
13
+ import { ReactNodeViewRenderer } from "@tiptap/react";
14
+ import { MathematicsEditComponent } from "./mathematics-component";
15
+ /**
16
+ * InlineMath is a Tiptap extension for rendering inline mathematical expressions using KaTeX.
17
+ * It allows users to insert LaTeX formatted math expressions inline within text.
18
+ * It supports rendering, input rules for LaTeX syntax, and click handling for interaction.
19
+ *
20
+ * Original:
21
+ * https://github.com/ueberdosis/tiptap/blob/develop/packages/extension-mathematics/src/extensions/InlineMath.ts
22
+ */
23
+ export var Mathematics = Node.create({
24
+ name: "inlineMath",
25
+ group: "inline",
26
+ inline: true,
27
+ atom: true,
28
+ addAttributes: function () {
29
+ return {
30
+ latex: {
31
+ default: "",
32
+ parseHTML: function (element) { return element.textContent; },
33
+ renderHTML: function () {
34
+ return {};
35
+ },
36
+ },
37
+ };
38
+ },
39
+ addCommands: function () {
40
+ var _this = this;
41
+ return {
42
+ deleteInlineMath: function (options) {
43
+ return function (_a) {
44
+ var _b;
45
+ var editor = _a.editor, tr = _a.tr;
46
+ var pos = (_b = options === null || options === void 0 ? void 0 : options.pos) !== null && _b !== void 0 ? _b : editor.state.selection.$from.pos;
47
+ var node = editor.state.doc.nodeAt(pos);
48
+ if (!node || node.type.name !== _this.name) {
49
+ return false;
50
+ }
51
+ tr.delete(pos, pos + node.nodeSize);
52
+ return true;
53
+ };
54
+ },
55
+ insertInlineMath: function (options) {
56
+ return function (_a) {
57
+ var _b, _c, _d;
58
+ var editor = _a.editor, tr = _a.tr;
59
+ // Insert latex if specified
60
+ if (options === null || options === void 0 ? void 0 : options.latex) {
61
+ var from_1 = (_b = options === null || options === void 0 ? void 0 : options.pos) !== null && _b !== void 0 ? _b : editor.state.selection.from;
62
+ tr.replaceWith(from_1, from_1, _this.type.create({ latex: options.latex }));
63
+ return true;
64
+ }
65
+ // If there is a selection that isn't empty, replace it with the inline math
66
+ var _e = editor.state.selection, from = _e.from, to = _e.to;
67
+ if (from !== to) {
68
+ var selectedText = editor.state.doc.textBetween(from, to);
69
+ tr.replaceWith(from, to, _this.type.create({ latex: selectedText.trim() || "2x + 2" }));
70
+ return true;
71
+ }
72
+ // Otherwise, insert at the current position
73
+ var pos = (_c = options === null || options === void 0 ? void 0 : options.pos) !== null && _c !== void 0 ? _c : editor.state.selection.to;
74
+ tr.replaceWith(pos, pos, _this.type.create({ latex: ((_d = options.latex) === null || _d === void 0 ? void 0 : _d.trim()) || "2x + 2" }));
75
+ return true;
76
+ };
77
+ },
78
+ updateInlineMath: function (options) {
79
+ return function (_a) {
80
+ var editor = _a.editor, tr = _a.tr;
81
+ var latex = options === null || options === void 0 ? void 0 : options.latex;
82
+ var pos = options === null || options === void 0 ? void 0 : options.pos;
83
+ if (pos === undefined) {
84
+ pos = editor.state.selection.$from.pos;
85
+ }
86
+ var node = editor.state.doc.nodeAt(pos);
87
+ if (!node || node.type.name !== _this.name) {
88
+ return false;
89
+ }
90
+ if ((latex === null || latex === void 0 ? void 0 : latex.trim()) === "") {
91
+ // Delete node if new latex is empty
92
+ tr.delete(pos, pos + node.nodeSize);
93
+ return true;
94
+ }
95
+ tr.setNodeMarkup(pos, _this.type, __assign(__assign({}, node.attrs), { latex: latex }));
96
+ return true;
97
+ };
98
+ },
99
+ };
100
+ },
101
+ parseHTML: function () {
102
+ return [
103
+ {
104
+ tag: "inline-math",
105
+ },
106
+ ];
107
+ },
108
+ renderHTML: function (_a) {
109
+ var node = _a.node, HTMLAttributes = _a.HTMLAttributes;
110
+ return ["inline-math", HTMLAttributes, node.attrs.latex || ""];
111
+ },
112
+ addInputRules: function () {
113
+ var _this = this;
114
+ return [
115
+ new InputRule({
116
+ find: /(^|[^$])(\$\$([^$\n]+?)\$\$)(?!\$)/,
117
+ handler: function (_a) {
118
+ var state = _a.state, range = _a.range, match = _a.match;
119
+ var latex = match[3];
120
+ var tr = state.tr;
121
+ var start = range.from;
122
+ var end = range.to;
123
+ tr.replaceWith(start, end, _this.type.create({ latex: latex }));
124
+ },
125
+ }),
126
+ ];
127
+ },
128
+ addNodeView: function () {
129
+ return ReactNodeViewRenderer(MathematicsEditComponent);
130
+ },
131
+ });
@@ -1,3 +1,4 @@
1
+ import { Editor } from "@tiptap/core";
1
2
  export declare const RichTextFormattingMenu: ({ editor }: {
2
- editor: any;
3
+ editor: Editor;
3
4
  }) => import("react/jsx-runtime").JSX.Element;
@@ -1,10 +1,14 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useCallback } from "react";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useCallback, useState } from "react";
3
+ import { Trans } from "react-i18next";
4
+ import { useEditorState } from "@tiptap/react";
3
5
  import { BubbleMenu } from "@tiptap/react/menus";
4
- import { Bold, Highlighter, Italic, LinkIcon, List, TextQuote, } from "lucide-react";
6
+ import { BoldIcon, CropIcon, HighlighterIcon, ItalicIcon, LinkIcon, ListIcon, SquareFunctionIcon, TextQuoteIcon, } from "lucide-react";
7
+ import { CropPageClippingModal } from "./crop-page-clipping-modal";
5
8
  import { cn } from "../../../utils";
6
9
  export var RichTextFormattingMenu = function (_a) {
7
10
  var editor = _a.editor;
11
+ var _b = useState(null), pageClipping = _b[0], setPageClipping = _b[1];
8
12
  var setLink = useCallback(function () {
9
13
  if (editor.isActive("link")) {
10
14
  editor.chain().focus().extendMarkRange("link").unsetLink().run();
@@ -27,8 +31,34 @@ export var RichTextFormattingMenu = function (_a) {
27
31
  // update link
28
32
  editor.chain().focus().extendMarkRange("link").setLink({ href: url }).run();
29
33
  }, [editor]);
34
+ var state = useEditorState({
35
+ editor: editor,
36
+ selector: function (ctx) { return ({
37
+ isBold: ctx.editor.isActive("bold"),
38
+ isItalic: ctx.editor.isActive("italic"),
39
+ isStrikethrough: ctx.editor.isActive("strike"),
40
+ isHighlight: ctx.editor.isActive("highlight"),
41
+ isLink: ctx.editor.isActive("link"),
42
+ isBulletList: ctx.editor.isActive("bulletList"),
43
+ isOrderedList: ctx.editor.isActive("orderedList"),
44
+ isBlockquote: ctx.editor.isActive("blockquote"),
45
+ isInlineMath: ctx.editor.isActive("inlineMath"),
46
+ isPageClipping: ctx.editor.isActive("page-clipping"),
47
+ }); },
48
+ });
30
49
  if (!editor) {
31
50
  return null;
32
51
  }
33
- return (_jsx(BubbleMenu, { editor: editor, children: _jsxs("div", { className: "border-2 p-0.5 gap-0.5 bg-white rounded-md flex items-center shadow-md", children: [_jsx("span", { onClick: function () { return editor.chain().focus().toggleBold().run(); }, className: cn("p-1 cursor-pointer", editor.isActive("bold") ? "bg-zinc-200 rounded-base" : ""), children: _jsx(Bold, { size: 16, strokeWidth: editor.isActive("bold") ? 2.75 : 2 }) }), _jsx("span", { onClick: function () { return editor.chain().focus().toggleItalic().run(); }, className: cn("p-1 cursor-pointer", editor.isActive("italic") ? "bg-zinc-200 rounded-base" : ""), children: _jsx(Italic, { size: 16, strokeWidth: editor.isActive("italic") ? 2.75 : 2 }) }), _jsx("span", { onClick: function () { return editor.chain().focus().toggleHighlight().run(); }, className: cn("p-1 cursor-pointer", editor.isActive("highlight") ? "bg-zinc-200 rounded-base" : ""), children: _jsx(Highlighter, { size: 16, strokeWidth: editor.isActive("highlight") ? 2.75 : 2 }) }), _jsx("span", { onClick: setLink, className: cn("p-1 cursor-pointer", editor.isActive("link") ? "bg-zinc-200 rounded-base" : ""), children: _jsx(LinkIcon, { size: 16, strokeWidth: editor.isActive("link") ? 2.75 : 2 }) }), _jsx("span", { onClick: function () { return editor.chain().focus().toggleBulletList().run(); }, className: cn("p-1 cursor-pointer", editor.isActive("bulletList") ? "bg-zinc-200 rounded-base" : ""), children: _jsx(List, { size: 16, strokeWidth: editor.isActive("bulletList") ? 2.75 : 2 }) }), _jsx("span", { onClick: function () { return editor.chain().focus().toggleOrderedList().run(); }, className: cn("p-1 cursor-pointer", editor.isActive("orderedList") ? "bg-zinc-200 rounded-base" : ""), children: _jsx(List, { size: 16, strokeWidth: editor.isActive("orderedList") ? 2.75 : 2 }) }), _jsx("span", { onClick: function () { return editor.chain().focus().toggleBlockquote().run(); }, className: cn("p-1 cursor-pointer", editor.isActive("blockquote") ? "bg-zinc-200 rounded-base" : ""), children: _jsx(TextQuote, { size: 16, strokeWidth: editor.isActive("blockquote") ? 2.75 : 2 }) })] }) }));
52
+ return (_jsxs(_Fragment, { children: [_jsx(CropPageClippingModal, { pageClipping: pageClipping, onClose: function () { return setPageClipping(null); }, onUpdate: function (newParameters) {
53
+ setPageClipping(null);
54
+ editor
55
+ .chain()
56
+ .focus()
57
+ .updateAttributes("page-clipping", newParameters)
58
+ .run();
59
+ } }), _jsx(BubbleMenu, { editor: editor, children: _jsx("div", { className: "border p-0.5 gap-0.5 bg-white rounded-md flex items-center shadow-md text-xs font-medium select-none", children: state.isPageClipping ? (_jsxs("span", { onClick: function () {
60
+ return setPageClipping(editor.getAttributes("page-clipping"));
61
+ }, className: "p-1 cursor-pointer flex items-center gap-1 pr-2 hover:bg-zinc-100 rounded-base", children: [_jsx(CropIcon, { className: "size-3.5 m-0.5" }), _jsx(Trans, { children: "formatting.crop.crop" })] })) : (_jsxs(_Fragment, { children: [_jsx("span", { onClick: function () { return editor.chain().focus().toggleBold().run(); }, className: cn("p-1 cursor-pointer", state.isBold ? "bg-zinc-200 rounded-base" : ""), children: _jsx(BoldIcon, { className: "size-3.5 m-0.5", strokeWidth: state.isBold ? 2.75 : 2 }) }), _jsx("span", { onClick: function () { return editor.chain().focus().toggleItalic().run(); }, className: cn("p-1 cursor-pointer", state.isItalic ? "bg-zinc-200 rounded-base" : ""), children: _jsx(ItalicIcon, { className: "size-3.5 m-0.5", strokeWidth: state.isItalic ? 2.75 : 2 }) }), _jsx("span", { onClick: function () { return editor.chain().focus().toggleHighlight().run(); }, className: cn("p-1 cursor-pointer", state.isHighlight ? "bg-zinc-200 rounded-base" : ""), children: _jsx(HighlighterIcon, { className: "size-3.5 m-0.5", strokeWidth: state.isHighlight ? 2.75 : 2 }) }), _jsx("span", { onClick: setLink, className: cn("p-1 cursor-pointer", state.isLink ? "bg-zinc-200 rounded-base" : ""), children: _jsx(LinkIcon, { className: "size-3.5 m-0.5", strokeWidth: state.isLink ? 2.75 : 2 }) }), _jsx("span", { onClick: function () { return editor.chain().focus().toggleBulletList().run(); }, className: cn("p-1 cursor-pointer", state.isBulletList ? "bg-zinc-200 rounded-base" : ""), children: _jsx(ListIcon, { className: "size-3.5 m-0.5", strokeWidth: state.isBulletList ? 2.75 : 2 }) }), _jsx("span", { onClick: function () { return editor.chain().focus().toggleOrderedList().run(); }, className: cn("p-1 cursor-pointer", state.isOrderedList ? "bg-zinc-200 rounded-base" : ""), children: _jsx(ListIcon, { className: "size-3.5 m-0.5", strokeWidth: state.isOrderedList ? 2.75 : 2 }) }), _jsx("span", { onClick: function () { return editor.chain().focus().toggleBlockquote().run(); }, className: cn("p-1 cursor-pointer", state.isBlockquote ? "bg-zinc-200 rounded-base" : ""), children: _jsx(TextQuoteIcon, { className: "size-3.5 m-0.5", strokeWidth: state.isBlockquote ? 2.75 : 2 }) }), _jsx("span", { onClick: function () {
62
+ return editor.chain().focus().insertInlineMath({ latex: "" }).run();
63
+ }, className: cn("p-1 cursor-pointer", state.isInlineMath ? "bg-zinc-200 rounded-base" : ""), children: _jsx(SquareFunctionIcon, { className: "size-3.5 m-0.5", strokeWidth: state.isInlineMath ? 2.75 : 2 }) })] })) }) })] }));
34
64
  };
@@ -23,11 +23,11 @@ var __rest = (this && this.__rest) || function (s, e) {
23
23
  import { jsx as _jsx } from "react/jsx-runtime";
24
24
  import * as React from "react";
25
25
  import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
26
- import { Check } from "lucide-react";
26
+ import { CheckIcon } from "lucide-react";
27
27
  import { cn } from "../../utils";
28
28
  var Checkbox = React.forwardRef(function (_a, ref) {
29
29
  var className = _a.className, props = __rest(_a, ["className"]);
30
- return (_jsx(CheckboxPrimitive.Root, __assign({ ref: ref, className: cn("peer size-4.5 shrink-0 outline-none rounded-xs border-2 border-border-accent ring-offset-white focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-black/10 disabled:cursor-not-allowed disabled:text-zinc-400 data-[state=checked]:bg-current data-[state=checked]:border-current", className, "outline") }, props, { children: _jsx(CheckboxPrimitive.Indicator, { className: cn("flex items-center justify-center text-current"), children: _jsx(Check, { className: "w-full h-full text-white", strokeWidth: 2.6 }) }) })));
30
+ return (_jsx(CheckboxPrimitive.Root, __assign({ ref: ref, className: cn("peer size-4.5 shrink-0 outline-none rounded-xs border-2 border-border-accent ring-offset-white focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-black/10 disabled:cursor-not-allowed disabled:text-zinc-400 data-[state=checked]:bg-current data-[state=checked]:border-current", className, "outline") }, props, { children: _jsx(CheckboxPrimitive.Indicator, { className: cn("flex items-center justify-center text-current"), children: _jsx(CheckIcon, { className: "w-full h-full text-white", strokeWidth: 2.6 }) }) })));
31
31
  });
32
32
  Checkbox.displayName = CheckboxPrimitive.Root.displayName;
33
33
  export { Checkbox };
@@ -23,7 +23,7 @@ var __rest = (this && this.__rest) || function (s, e) {
23
23
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
24
24
  import * as React from "react";
25
25
  import * as DialogPrimitive from "@radix-ui/react-dialog";
26
- import { X } from "lucide-react";
26
+ import { XIcon } from "lucide-react";
27
27
  import { Button } from "./button";
28
28
  import { cn } from "../../utils";
29
29
  var Dialog = DialogPrimitive.Root;
@@ -32,7 +32,7 @@ var DialogPortal = DialogPrimitive.Portal;
32
32
  var DialogClose = DialogPrimitive.Close;
33
33
  var DialogCloseIcon = React.forwardRef(function (_a, ref) {
34
34
  var className = _a.className, props = __rest(_a, ["className"]);
35
- return (_jsx(DialogPrimitive.Close, { asChild: true, children: _jsxs(Button, __assign({ variant: "roundedSecondary", size: "icon-sm", className: cn("absolute right-4 lg:right-7 top-4 lg:top-7 bg-white", className), ref: ref }, props, { children: [_jsx(X, { strokeWidth: 2.5 }), _jsx("span", { className: "sr-only", children: "Close" })] })) }));
35
+ return (_jsx(DialogPrimitive.Close, { asChild: true, children: _jsxs(Button, __assign({ variant: "roundedSecondary", size: "icon-sm", className: cn("absolute right-4 lg:right-7 top-4 lg:top-7 bg-white", className), ref: ref }, props, { children: [_jsx(XIcon, { strokeWidth: 2.5 }), _jsx("span", { className: "sr-only", children: "Close" })] })) }));
36
36
  });
37
37
  DialogCloseIcon.displayName = "DialogCloseIcon";
38
38
  var DialogOverlay = React.forwardRef(function (_a, ref) {
@@ -42,7 +42,7 @@ var DialogOverlay = React.forwardRef(function (_a, ref) {
42
42
  DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
43
43
  var DialogContent = React.forwardRef(function (_a, ref) {
44
44
  var className = _a.className, children = _a.children, _b = _a.showClose, showClose = _b === void 0 ? true : _b, props = __rest(_a, ["className", "children", "showClose"]);
45
- return (_jsxs(DialogPortal, { children: [_jsx(DialogOverlay, {}), _jsxs(DialogPrimitive.Content, __assign({ ref: ref, className: cn("group/dialog fixed left-[50%] top-[50%] z-50 w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-top-[48%]", "border border-border-accent bg-bg rounded-xl p-6 lg:p-8", "has-[.dialog-section]:bg-transparent has-[.dialog-section]:border-0 has-[.dialog-section]:px-1 has-[.dialog-section]:py-10 has-[.dialog-section]:rounded-none has-[.dialog-section]:overflow-auto has-[.dialog-section]:max-h-none has-[.dialog-section]:h-screen has-[.dialog-section]:justify-center", className), onCloseAutoFocus: function (event) {
45
+ return (_jsxs(DialogPortal, { children: [_jsx(DialogOverlay, {}), _jsxs(DialogPrimitive.Content, __assign({ ref: ref, className: cn("group/dialog fixed left-[50%] top-[50%] z-50 w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-top-[48%]", "border border-border-accent bg-bg rounded-xl p-6 lg:p-8", "has-[.dialog-section]:bg-transparent has-[.dialog-section]:border-0 has-[.dialog-section]:px-1 has-[.dialog-section]:py-10 has-[.dialog-section]:outline-none has-[.dialog-section]:rounded-none has-[.dialog-section]:overflow-auto has-[.dialog-section]:max-h-none has-[.dialog-section]:h-screen has-[.dialog-section]:justify-center", className), onCloseAutoFocus: function (event) {
46
46
  event.preventDefault();
47
47
  document.body.style.pointerEvents = "";
48
48
  } }, props, { children: [children, showClose && _jsx(DialogCloseIcon, {})] }))] }));
@@ -20,6 +20,7 @@ declare const DropdownMenuLabel: React.ForwardRefExoticComponent<Omit<DropdownMe
20
20
  inset?: boolean;
21
21
  } & React.RefAttributes<HTMLDivElement>>;
22
22
  declare const DropdownMenuSeparator: React.ForwardRefExoticComponent<Omit<DropdownMenuPrimitive.DropdownMenuSeparatorProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
23
+ export declare const replaceShortCut: (text: any) => any;
23
24
  declare const DropdownMenuShortcut: {
24
25
  ({ className, ...props }: React.HTMLAttributes<HTMLSpanElement>): import("react/jsx-runtime").JSX.Element;
25
26
  displayName: string;
@@ -23,7 +23,7 @@ var __rest = (this && this.__rest) || function (s, e) {
23
23
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
24
24
  import * as React from "react";
25
25
  import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
26
- import { Check, ChevronRight, Circle } from "lucide-react";
26
+ import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react";
27
27
  import { cn } from "../../utils";
28
28
  var DropdownMenu = DropdownMenuPrimitive.Root;
29
29
  var DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
@@ -33,7 +33,7 @@ var DropdownMenuSub = DropdownMenuPrimitive.Sub;
33
33
  var DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
34
34
  var DropdownMenuSubTrigger = React.forwardRef(function (_a, ref) {
35
35
  var className = _a.className, inset = _a.inset, children = _a.children, props = __rest(_a, ["className", "inset", "children"]);
36
- return (_jsxs(DropdownMenuPrimitive.SubTrigger, __assign({ ref: ref, className: cn("flex cursor-default select-none items-center rounded-base bg-white px-2 py-1.5 text-sm font-base outline-none gap-2 [&_svg]:pointer-events-none [&_svg]:w-4 [&_svg]:h-4 [&_svg]:shrink-0", inset && "pl-8", className) }, props, { children: [children, _jsx(ChevronRight, { className: "ml-auto" })] })));
36
+ return (_jsxs(DropdownMenuPrimitive.SubTrigger, __assign({ ref: ref, className: cn("flex cursor-default select-none items-center rounded-base bg-white px-2 py-1.5 text-sm font-base outline-none gap-2 [&_svg]:pointer-events-none [&_svg]:w-4 [&_svg]:h-4 [&_svg]:shrink-0", inset && "pl-8", className) }, props, { children: [children, _jsx(ChevronRightIcon, { className: "ml-auto" })] })));
37
37
  });
38
38
  DropdownMenuSubTrigger.displayName =
39
39
  DropdownMenuPrimitive.SubTrigger.displayName;
@@ -55,13 +55,13 @@ var DropdownMenuItem = React.forwardRef(function (_a, ref) {
55
55
  DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
56
56
  var DropdownMenuCheckboxItem = React.forwardRef(function (_a, ref) {
57
57
  var className = _a.className, children = _a.children, checked = _a.checked, props = __rest(_a, ["className", "children", "checked"]);
58
- return (_jsxs(DropdownMenuPrimitive.CheckboxItem, __assign({ ref: ref, className: cn("relative flex cursor-pointer select-none items-center rounded-base py-1.5 pl-8 pr-2 text-sm font-base text-text outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50", className), checked: checked }, props, { children: [_jsx("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: _jsx(DropdownMenuPrimitive.ItemIndicator, { children: _jsx(Check, { className: "h-4 w-4" }) }) }), children] })));
58
+ return (_jsxs(DropdownMenuPrimitive.CheckboxItem, __assign({ ref: ref, className: cn("relative flex cursor-pointer select-none items-center rounded-base py-1.5 pl-8 pr-2 text-sm font-base text-text outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50", className), checked: checked }, props, { children: [_jsx("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: _jsx(DropdownMenuPrimitive.ItemIndicator, { children: _jsx(CheckIcon, { className: "h-4 w-4" }) }) }), children] })));
59
59
  });
60
60
  DropdownMenuCheckboxItem.displayName =
61
61
  DropdownMenuPrimitive.CheckboxItem.displayName;
62
62
  var DropdownMenuRadioItem = React.forwardRef(function (_a, ref) {
63
63
  var className = _a.className, children = _a.children, props = __rest(_a, ["className", "children"]);
64
- return (_jsxs(DropdownMenuPrimitive.RadioItem, __assign({ ref: ref, className: cn("relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm font-base outline-none transition-colors focus:bg-white focus:text-text data-[disabled]:pointer-events-none data-[disabled]:opacity-50", className) }, props, { children: [_jsx("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: _jsx(DropdownMenuPrimitive.ItemIndicator, { children: _jsx(Circle, { className: "h-2 w-2 fill-current" }) }) }), children] })));
64
+ return (_jsxs(DropdownMenuPrimitive.RadioItem, __assign({ ref: ref, className: cn("relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm font-base outline-none transition-colors focus:bg-white focus:text-text data-[disabled]:pointer-events-none data-[disabled]:opacity-50", className) }, props, { children: [_jsx("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: _jsx(DropdownMenuPrimitive.ItemIndicator, { children: _jsx(CircleIcon, { className: "h-2 w-2 fill-current" }) }) }), children] })));
65
65
  });
66
66
  DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
67
67
  var DropdownMenuLabel = React.forwardRef(function (_a, ref) {
@@ -74,10 +74,17 @@ var DropdownMenuSeparator = React.forwardRef(function (_a, ref) {
74
74
  return (_jsx(DropdownMenuPrimitive.Separator, __assign({ ref: ref, className: cn("-mx-1 my-1 h-[1px] bg-border-accent", className) }, props)));
75
75
  });
76
76
  DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
77
+ export var replaceShortCut = function (text) {
78
+ if (!text || typeof text !== "string")
79
+ return text;
80
+ if (navigator.userAgent.includes("Windows")) {
81
+ return text.replace("⌘", "Ctrl-");
82
+ }
83
+ return text;
84
+ };
77
85
  var DropdownMenuShortcut = function (_a) {
78
86
  var className = _a.className, props = __rest(_a, ["className"]);
79
- // TODO: replace with Ctrl on Windows
80
- return (_jsx("span", __assign({ className: cn("ml-auto pl-1 text-xs font-medium text-zinc-400 tracking-widest opacity-100", className) }, props)));
87
+ return (_jsx("span", __assign({ className: cn("ml-auto pl-1 text-xs font-medium text-zinc-400 tracking-widest opacity-100", className) }, props, { children: replaceShortCut(props.children) })));
81
88
  };
82
89
  DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
83
90
  export { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, DropdownMenuCheckboxItem, DropdownMenuRadioItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuGroup, DropdownMenuPortal, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuRadioGroup, };