notra-editor 0.4.0 → 0.5.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 (49) hide show
  1. package/dist/components/image-popover/image-popover.cjs +161 -0
  2. package/dist/components/image-popover/image-popover.cjs.map +1 -0
  3. package/dist/components/image-popover/image-popover.d.cts +9 -0
  4. package/dist/components/image-popover/image-popover.d.ts +9 -0
  5. package/dist/components/image-popover/image-popover.mjs +137 -0
  6. package/dist/components/image-popover/image-popover.mjs.map +1 -0
  7. package/dist/components/image-popover/use-image-popover.cjs +88 -0
  8. package/dist/components/image-popover/use-image-popover.cjs.map +1 -0
  9. package/dist/components/image-popover/use-image-popover.d.cts +19 -0
  10. package/dist/components/image-popover/use-image-popover.d.ts +19 -0
  11. package/dist/components/image-popover/use-image-popover.mjs +64 -0
  12. package/dist/components/image-popover/use-image-popover.mjs.map +1 -0
  13. package/dist/components/link-popover/link-popover.cjs +12 -3
  14. package/dist/components/link-popover/link-popover.cjs.map +1 -1
  15. package/dist/components/link-popover/link-popover.mjs +12 -3
  16. package/dist/components/link-popover/link-popover.mjs.map +1 -1
  17. package/dist/components/link-popover/use-link-popover.cjs +17 -2
  18. package/dist/components/link-popover/use-link-popover.cjs.map +1 -1
  19. package/dist/components/link-popover/use-link-popover.d.cts +1 -0
  20. package/dist/components/link-popover/use-link-popover.d.ts +1 -0
  21. package/dist/components/link-popover/use-link-popover.mjs +17 -2
  22. package/dist/components/link-popover/use-link-popover.mjs.map +1 -1
  23. package/dist/extensions/editor.cjs +2 -0
  24. package/dist/extensions/editor.cjs.map +1 -1
  25. package/dist/extensions/editor.d.cts +2 -1
  26. package/dist/extensions/editor.d.ts +2 -1
  27. package/dist/extensions/editor.mjs +2 -0
  28. package/dist/extensions/editor.mjs.map +1 -1
  29. package/dist/extensions/index.d.cts +1 -0
  30. package/dist/extensions/index.d.ts +1 -0
  31. package/dist/extensions/shared.cjs +3 -1
  32. package/dist/extensions/shared.cjs.map +1 -1
  33. package/dist/extensions/shared.d.cts +2 -1
  34. package/dist/extensions/shared.d.ts +2 -1
  35. package/dist/extensions/shared.mjs +3 -1
  36. package/dist/extensions/shared.mjs.map +1 -1
  37. package/dist/index.cjs +3 -0
  38. package/dist/index.cjs.map +1 -1
  39. package/dist/index.d.cts +1 -0
  40. package/dist/index.d.ts +1 -0
  41. package/dist/index.mjs +2 -0
  42. package/dist/index.mjs.map +1 -1
  43. package/dist/notra-editor.cjs +3 -1
  44. package/dist/notra-editor.cjs.map +1 -1
  45. package/dist/notra-editor.mjs +3 -1
  46. package/dist/notra-editor.mjs.map +1 -1
  47. package/dist/styles/globals.css +3 -0
  48. package/dist/themes/default/shared.css +18 -0
  49. package/package.json +2 -1
@@ -0,0 +1,161 @@
1
+ "use strict";
2
+ "use client";
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+ var image_popover_exports = {};
21
+ __export(image_popover_exports, {
22
+ ImagePopover: () => ImagePopover
23
+ });
24
+ module.exports = __toCommonJS(image_popover_exports);
25
+ var import_jsx_runtime = require("react/jsx-runtime");
26
+ var import_lucide_react = require("lucide-react");
27
+ var import_react = require("react");
28
+ var import_use_image_popover = require("./use-image-popover");
29
+ var import_button = require("../ui/button");
30
+ var import_input = require("../ui/input");
31
+ var import_popover = require("../ui/popover");
32
+ var import_separator = require("../ui/separator");
33
+ const ImagePopover = (0, import_react.forwardRef)(
34
+ ({ editor, ...buttonProps }, ref) => {
35
+ const [isOpen, setIsOpen] = (0, import_react.useState)(false);
36
+ const {
37
+ url,
38
+ setUrl,
39
+ alt,
40
+ setAlt,
41
+ isActive,
42
+ canSet,
43
+ setImage,
44
+ removeImage,
45
+ wasSelectionMove
46
+ } = (0, import_use_image_popover.useImagePopover)({ editor });
47
+ (0, import_react.useEffect)(() => {
48
+ if (isActive && wasSelectionMove) {
49
+ setIsOpen(true);
50
+ }
51
+ }, [isActive, wasSelectionMove]);
52
+ const handleSetImage = (0, import_react.useCallback)(() => {
53
+ setImage();
54
+ setIsOpen(false);
55
+ }, [setImage]);
56
+ const handleRemoveImage = (0, import_react.useCallback)(() => {
57
+ removeImage();
58
+ setIsOpen(false);
59
+ }, [removeImage]);
60
+ const handleKeyDown = (0, import_react.useCallback)(
61
+ (event) => {
62
+ if (event.key === "Enter") {
63
+ event.preventDefault();
64
+ handleSetImage();
65
+ }
66
+ },
67
+ [handleSetImage]
68
+ );
69
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_popover.Popover, { open: isOpen, onOpenChange: setIsOpen, children: [
70
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_popover.PopoverTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
71
+ import_button.Button,
72
+ {
73
+ ref,
74
+ "aria-label": "Image",
75
+ "aria-pressed": isActive,
76
+ "data-active-state": isActive ? "on" : "off",
77
+ disabled: !canSet,
78
+ size: "icon",
79
+ tabIndex: -1,
80
+ type: "button",
81
+ variant: "ghost",
82
+ ...buttonProps,
83
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
84
+ import_lucide_react.ImageIcon,
85
+ {
86
+ className: isActive ? "nt:text-[var(--tt-brand-color-500)]" : void 0
87
+ }
88
+ )
89
+ }
90
+ ) }),
91
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
92
+ import_popover.PopoverContent,
93
+ {
94
+ align: "start",
95
+ className: "nt:flex nt:w-72 nt:flex-col nt:gap-1 nt:p-1",
96
+ children: [
97
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
98
+ import_input.Input,
99
+ {
100
+ autoFocus: true,
101
+ className: "nt:h-7 nt:border-none nt:shadow-none nt:focus-visible:ring-0",
102
+ placeholder: "Paste image URL...",
103
+ type: "url",
104
+ value: url,
105
+ onChange: (e) => setUrl(e.target.value),
106
+ onKeyDown: handleKeyDown
107
+ }
108
+ ),
109
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
110
+ import_input.Input,
111
+ {
112
+ className: "nt:h-7 nt:border-none nt:shadow-none nt:focus-visible:ring-0",
113
+ placeholder: "Alt text (optional)",
114
+ type: "text",
115
+ value: alt,
116
+ onChange: (e) => setAlt(e.target.value),
117
+ onKeyDown: handleKeyDown
118
+ }
119
+ ),
120
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "nt:flex nt:items-center nt:justify-end nt:gap-1", children: [
121
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
122
+ import_button.Button,
123
+ {
124
+ "aria-label": "Apply image",
125
+ disabled: !url && !isActive,
126
+ size: "icon-sm",
127
+ tabIndex: -1,
128
+ type: "button",
129
+ variant: "ghost",
130
+ onClick: handleSetImage,
131
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.CornerDownLeft, {})
132
+ }
133
+ ),
134
+ isActive && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
135
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_separator.Separator, { className: "nt:h-5", orientation: "vertical" }),
136
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
137
+ import_button.Button,
138
+ {
139
+ "aria-label": "Remove image",
140
+ size: "icon-sm",
141
+ tabIndex: -1,
142
+ type: "button",
143
+ variant: "ghost",
144
+ onClick: handleRemoveImage,
145
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Trash2, {})
146
+ }
147
+ )
148
+ ] })
149
+ ] })
150
+ ]
151
+ }
152
+ )
153
+ ] });
154
+ }
155
+ );
156
+ ImagePopover.displayName = "ImagePopover";
157
+ // Annotate the CommonJS export names for ESM import in node:
158
+ 0 && (module.exports = {
159
+ ImagePopover
160
+ });
161
+ //# sourceMappingURL=image-popover.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/image-popover/image-popover.tsx"],"sourcesContent":["'use client';\n\nimport { CornerDownLeft, ImageIcon, Trash2 } from 'lucide-react';\nimport { forwardRef, useCallback, useEffect, useState } from 'react';\n\nimport { useImagePopover } from './use-image-popover';\nimport { Button } from '../ui/button';\nimport { Input } from '../ui/input';\nimport { Popover, PopoverContent, PopoverTrigger } from '../ui/popover';\nimport { Separator } from '../ui/separator';\n\nimport type { Editor } from '@tiptap/core';\n\nexport interface ImagePopoverProps extends Omit<\n\tReact.ButtonHTMLAttributes<HTMLButtonElement>,\n\t'type'\n> {\n\teditor: Editor | null;\n}\n\nexport const ImagePopover = forwardRef<HTMLButtonElement, ImagePopoverProps>(\n\t({ editor, ...buttonProps }, ref) => {\n\t\tconst [isOpen, setIsOpen] = useState(false);\n\n\t\tconst {\n\t\t\turl,\n\t\t\tsetUrl,\n\t\t\talt,\n\t\t\tsetAlt,\n\t\t\tisActive,\n\t\t\tcanSet,\n\t\t\tsetImage,\n\t\t\tremoveImage,\n\t\t\twasSelectionMove\n\t\t} = useImagePopover({ editor });\n\n\t\t// Auto-open popover when cursor moves onto an existing image (selection-only transaction)\n\t\tuseEffect(() => {\n\t\t\tif (isActive && wasSelectionMove) {\n\t\t\t\tsetIsOpen(true);\n\t\t\t}\n\t\t}, [isActive, wasSelectionMove]);\n\n\t\tconst handleSetImage = useCallback(() => {\n\t\t\tsetImage();\n\t\t\tsetIsOpen(false);\n\t\t}, [setImage]);\n\n\t\tconst handleRemoveImage = useCallback(() => {\n\t\t\tremoveImage();\n\t\t\tsetIsOpen(false);\n\t\t}, [removeImage]);\n\n\t\tconst handleKeyDown = useCallback(\n\t\t\t(event: React.KeyboardEvent<HTMLInputElement>) => {\n\t\t\t\tif (event.key === 'Enter') {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\thandleSetImage();\n\t\t\t\t}\n\t\t\t},\n\t\t\t[handleSetImage]\n\t\t);\n\n\t\treturn (\n\t\t\t<Popover open={isOpen} onOpenChange={setIsOpen}>\n\t\t\t\t<PopoverTrigger asChild>\n\t\t\t\t\t<Button\n\t\t\t\t\t\tref={ref}\n\t\t\t\t\t\taria-label=\"Image\"\n\t\t\t\t\t\taria-pressed={isActive}\n\t\t\t\t\t\tdata-active-state={isActive ? 'on' : 'off'}\n\t\t\t\t\t\tdisabled={!canSet}\n\t\t\t\t\t\tsize=\"icon\"\n\t\t\t\t\t\ttabIndex={-1}\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\t{...buttonProps}\n\t\t\t\t\t>\n\t\t\t\t\t\t<ImageIcon\n\t\t\t\t\t\t\tclassName={\n\t\t\t\t\t\t\t\tisActive ? 'nt:text-[var(--tt-brand-color-500)]' : undefined\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</Button>\n\t\t\t\t</PopoverTrigger>\n\t\t\t\t<PopoverContent\n\t\t\t\t\talign=\"start\"\n\t\t\t\t\tclassName=\"nt:flex nt:w-72 nt:flex-col nt:gap-1 nt:p-1\"\n\t\t\t\t>\n\t\t\t\t\t<Input\n\t\t\t\t\t\tautoFocus\n\t\t\t\t\t\tclassName=\"nt:h-7 nt:border-none nt:shadow-none nt:focus-visible:ring-0\"\n\t\t\t\t\t\tplaceholder=\"Paste image URL...\"\n\t\t\t\t\t\ttype=\"url\"\n\t\t\t\t\t\tvalue={url}\n\t\t\t\t\t\tonChange={(e) => setUrl(e.target.value)}\n\t\t\t\t\t\tonKeyDown={handleKeyDown}\n\t\t\t\t\t/>\n\t\t\t\t\t<Input\n\t\t\t\t\t\tclassName=\"nt:h-7 nt:border-none nt:shadow-none nt:focus-visible:ring-0\"\n\t\t\t\t\t\tplaceholder=\"Alt text (optional)\"\n\t\t\t\t\t\ttype=\"text\"\n\t\t\t\t\t\tvalue={alt}\n\t\t\t\t\t\tonChange={(e) => setAlt(e.target.value)}\n\t\t\t\t\t\tonKeyDown={handleKeyDown}\n\t\t\t\t\t/>\n\t\t\t\t\t<div className=\"nt:flex nt:items-center nt:justify-end nt:gap-1\">\n\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\taria-label=\"Apply image\"\n\t\t\t\t\t\t\tdisabled={!url && !isActive}\n\t\t\t\t\t\t\tsize=\"icon-sm\"\n\t\t\t\t\t\t\ttabIndex={-1}\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\t\tonClick={handleSetImage}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<CornerDownLeft />\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t{isActive && (\n\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t<Separator className=\"nt:h-5\" orientation=\"vertical\" />\n\t\t\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\t\t\taria-label=\"Remove image\"\n\t\t\t\t\t\t\t\t\tsize=\"icon-sm\"\n\t\t\t\t\t\t\t\t\ttabIndex={-1}\n\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\t\t\t\tonClick={handleRemoveImage}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<Trash2 />\n\t\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</div>\n\t\t\t\t</PopoverContent>\n\t\t\t</Popover>\n\t\t);\n\t}\n);\n\nImagePopover.displayName = 'ImagePopover';\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA8EM;AA5EN,0BAAkD;AAClD,mBAA6D;AAE7D,+BAAgC;AAChC,oBAAuB;AACvB,mBAAsB;AACtB,qBAAwD;AACxD,uBAA0B;AAWnB,MAAM,mBAAe;AAAA,EAC3B,CAAC,EAAE,QAAQ,GAAG,YAAY,GAAG,QAAQ;AACpC,UAAM,CAAC,QAAQ,SAAS,QAAI,uBAAS,KAAK;AAE1C,UAAM;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACD,QAAI,0CAAgB,EAAE,OAAO,CAAC;AAG9B,gCAAU,MAAM;AACf,UAAI,YAAY,kBAAkB;AACjC,kBAAU,IAAI;AAAA,MACf;AAAA,IACD,GAAG,CAAC,UAAU,gBAAgB,CAAC;AAE/B,UAAM,qBAAiB,0BAAY,MAAM;AACxC,eAAS;AACT,gBAAU,KAAK;AAAA,IAChB,GAAG,CAAC,QAAQ,CAAC;AAEb,UAAM,wBAAoB,0BAAY,MAAM;AAC3C,kBAAY;AACZ,gBAAU,KAAK;AAAA,IAChB,GAAG,CAAC,WAAW,CAAC;AAEhB,UAAM,oBAAgB;AAAA,MACrB,CAAC,UAAiD;AACjD,YAAI,MAAM,QAAQ,SAAS;AAC1B,gBAAM,eAAe;AACrB,yBAAe;AAAA,QAChB;AAAA,MACD;AAAA,MACA,CAAC,cAAc;AAAA,IAChB;AAEA,WACC,6CAAC,0BAAQ,MAAM,QAAQ,cAAc,WACpC;AAAA,kDAAC,iCAAe,SAAO,MACtB;AAAA,QAAC;AAAA;AAAA,UACA;AAAA,UACA,cAAW;AAAA,UACX,gBAAc;AAAA,UACd,qBAAmB,WAAW,OAAO;AAAA,UACrC,UAAU,CAAC;AAAA,UACX,MAAK;AAAA,UACL,UAAU;AAAA,UACV,MAAK;AAAA,UACL,SAAQ;AAAA,UACP,GAAG;AAAA,UAEJ;AAAA,YAAC;AAAA;AAAA,cACA,WACC,WAAW,wCAAwC;AAAA;AAAA,UAErD;AAAA;AAAA,MACD,GACD;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACA,OAAM;AAAA,UACN,WAAU;AAAA,UAEV;AAAA;AAAA,cAAC;AAAA;AAAA,gBACA,WAAS;AAAA,gBACT,WAAU;AAAA,gBACV,aAAY;AAAA,gBACZ,MAAK;AAAA,gBACL,OAAO;AAAA,gBACP,UAAU,CAAC,MAAM,OAAO,EAAE,OAAO,KAAK;AAAA,gBACtC,WAAW;AAAA;AAAA,YACZ;AAAA,YACA;AAAA,cAAC;AAAA;AAAA,gBACA,WAAU;AAAA,gBACV,aAAY;AAAA,gBACZ,MAAK;AAAA,gBACL,OAAO;AAAA,gBACP,UAAU,CAAC,MAAM,OAAO,EAAE,OAAO,KAAK;AAAA,gBACtC,WAAW;AAAA;AAAA,YACZ;AAAA,YACA,6CAAC,SAAI,WAAU,mDACd;AAAA;AAAA,gBAAC;AAAA;AAAA,kBACA,cAAW;AAAA,kBACX,UAAU,CAAC,OAAO,CAAC;AAAA,kBACnB,MAAK;AAAA,kBACL,UAAU;AAAA,kBACV,MAAK;AAAA,kBACL,SAAQ;AAAA,kBACR,SAAS;AAAA,kBAET,sDAAC,sCAAe;AAAA;AAAA,cACjB;AAAA,cACC,YACA,4EACC;AAAA,4DAAC,8BAAU,WAAU,UAAS,aAAY,YAAW;AAAA,gBACrD;AAAA,kBAAC;AAAA;AAAA,oBACA,cAAW;AAAA,oBACX,MAAK;AAAA,oBACL,UAAU;AAAA,oBACV,MAAK;AAAA,oBACL,SAAQ;AAAA,oBACR,SAAS;AAAA,oBAET,sDAAC,8BAAO;AAAA;AAAA,gBACT;AAAA,iBACD;AAAA,eAEF;AAAA;AAAA;AAAA,MACD;AAAA,OACD;AAAA,EAEF;AACD;AAEA,aAAa,cAAc;","names":[]}
@@ -0,0 +1,9 @@
1
+ import * as react from 'react';
2
+ import { Editor } from '@tiptap/core';
3
+
4
+ interface ImagePopoverProps extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'type'> {
5
+ editor: Editor | null;
6
+ }
7
+ declare const ImagePopover: react.ForwardRefExoticComponent<ImagePopoverProps & react.RefAttributes<HTMLButtonElement>>;
8
+
9
+ export { ImagePopover, type ImagePopoverProps };
@@ -0,0 +1,9 @@
1
+ import * as react from 'react';
2
+ import { Editor } from '@tiptap/core';
3
+
4
+ interface ImagePopoverProps extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'type'> {
5
+ editor: Editor | null;
6
+ }
7
+ declare const ImagePopover: react.ForwardRefExoticComponent<ImagePopoverProps & react.RefAttributes<HTMLButtonElement>>;
8
+
9
+ export { ImagePopover, type ImagePopoverProps };
@@ -0,0 +1,137 @@
1
+ "use client";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import { CornerDownLeft, ImageIcon, Trash2 } from "lucide-react";
4
+ import { forwardRef, useCallback, useEffect, useState } from "react";
5
+ import { useImagePopover } from "./use-image-popover";
6
+ import { Button } from "../ui/button";
7
+ import { Input } from "../ui/input";
8
+ import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover";
9
+ import { Separator } from "../ui/separator";
10
+ const ImagePopover = forwardRef(
11
+ ({ editor, ...buttonProps }, ref) => {
12
+ const [isOpen, setIsOpen] = useState(false);
13
+ const {
14
+ url,
15
+ setUrl,
16
+ alt,
17
+ setAlt,
18
+ isActive,
19
+ canSet,
20
+ setImage,
21
+ removeImage,
22
+ wasSelectionMove
23
+ } = useImagePopover({ editor });
24
+ useEffect(() => {
25
+ if (isActive && wasSelectionMove) {
26
+ setIsOpen(true);
27
+ }
28
+ }, [isActive, wasSelectionMove]);
29
+ const handleSetImage = useCallback(() => {
30
+ setImage();
31
+ setIsOpen(false);
32
+ }, [setImage]);
33
+ const handleRemoveImage = useCallback(() => {
34
+ removeImage();
35
+ setIsOpen(false);
36
+ }, [removeImage]);
37
+ const handleKeyDown = useCallback(
38
+ (event) => {
39
+ if (event.key === "Enter") {
40
+ event.preventDefault();
41
+ handleSetImage();
42
+ }
43
+ },
44
+ [handleSetImage]
45
+ );
46
+ return /* @__PURE__ */ jsxs(Popover, { open: isOpen, onOpenChange: setIsOpen, children: [
47
+ /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
48
+ Button,
49
+ {
50
+ ref,
51
+ "aria-label": "Image",
52
+ "aria-pressed": isActive,
53
+ "data-active-state": isActive ? "on" : "off",
54
+ disabled: !canSet,
55
+ size: "icon",
56
+ tabIndex: -1,
57
+ type: "button",
58
+ variant: "ghost",
59
+ ...buttonProps,
60
+ children: /* @__PURE__ */ jsx(
61
+ ImageIcon,
62
+ {
63
+ className: isActive ? "nt:text-[var(--tt-brand-color-500)]" : void 0
64
+ }
65
+ )
66
+ }
67
+ ) }),
68
+ /* @__PURE__ */ jsxs(
69
+ PopoverContent,
70
+ {
71
+ align: "start",
72
+ className: "nt:flex nt:w-72 nt:flex-col nt:gap-1 nt:p-1",
73
+ children: [
74
+ /* @__PURE__ */ jsx(
75
+ Input,
76
+ {
77
+ autoFocus: true,
78
+ className: "nt:h-7 nt:border-none nt:shadow-none nt:focus-visible:ring-0",
79
+ placeholder: "Paste image URL...",
80
+ type: "url",
81
+ value: url,
82
+ onChange: (e) => setUrl(e.target.value),
83
+ onKeyDown: handleKeyDown
84
+ }
85
+ ),
86
+ /* @__PURE__ */ jsx(
87
+ Input,
88
+ {
89
+ className: "nt:h-7 nt:border-none nt:shadow-none nt:focus-visible:ring-0",
90
+ placeholder: "Alt text (optional)",
91
+ type: "text",
92
+ value: alt,
93
+ onChange: (e) => setAlt(e.target.value),
94
+ onKeyDown: handleKeyDown
95
+ }
96
+ ),
97
+ /* @__PURE__ */ jsxs("div", { className: "nt:flex nt:items-center nt:justify-end nt:gap-1", children: [
98
+ /* @__PURE__ */ jsx(
99
+ Button,
100
+ {
101
+ "aria-label": "Apply image",
102
+ disabled: !url && !isActive,
103
+ size: "icon-sm",
104
+ tabIndex: -1,
105
+ type: "button",
106
+ variant: "ghost",
107
+ onClick: handleSetImage,
108
+ children: /* @__PURE__ */ jsx(CornerDownLeft, {})
109
+ }
110
+ ),
111
+ isActive && /* @__PURE__ */ jsxs(Fragment, { children: [
112
+ /* @__PURE__ */ jsx(Separator, { className: "nt:h-5", orientation: "vertical" }),
113
+ /* @__PURE__ */ jsx(
114
+ Button,
115
+ {
116
+ "aria-label": "Remove image",
117
+ size: "icon-sm",
118
+ tabIndex: -1,
119
+ type: "button",
120
+ variant: "ghost",
121
+ onClick: handleRemoveImage,
122
+ children: /* @__PURE__ */ jsx(Trash2, {})
123
+ }
124
+ )
125
+ ] })
126
+ ] })
127
+ ]
128
+ }
129
+ )
130
+ ] });
131
+ }
132
+ );
133
+ ImagePopover.displayName = "ImagePopover";
134
+ export {
135
+ ImagePopover
136
+ };
137
+ //# sourceMappingURL=image-popover.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/image-popover/image-popover.tsx"],"sourcesContent":["'use client';\n\nimport { CornerDownLeft, ImageIcon, Trash2 } from 'lucide-react';\nimport { forwardRef, useCallback, useEffect, useState } from 'react';\n\nimport { useImagePopover } from './use-image-popover';\nimport { Button } from '../ui/button';\nimport { Input } from '../ui/input';\nimport { Popover, PopoverContent, PopoverTrigger } from '../ui/popover';\nimport { Separator } from '../ui/separator';\n\nimport type { Editor } from '@tiptap/core';\n\nexport interface ImagePopoverProps extends Omit<\n\tReact.ButtonHTMLAttributes<HTMLButtonElement>,\n\t'type'\n> {\n\teditor: Editor | null;\n}\n\nexport const ImagePopover = forwardRef<HTMLButtonElement, ImagePopoverProps>(\n\t({ editor, ...buttonProps }, ref) => {\n\t\tconst [isOpen, setIsOpen] = useState(false);\n\n\t\tconst {\n\t\t\turl,\n\t\t\tsetUrl,\n\t\t\talt,\n\t\t\tsetAlt,\n\t\t\tisActive,\n\t\t\tcanSet,\n\t\t\tsetImage,\n\t\t\tremoveImage,\n\t\t\twasSelectionMove\n\t\t} = useImagePopover({ editor });\n\n\t\t// Auto-open popover when cursor moves onto an existing image (selection-only transaction)\n\t\tuseEffect(() => {\n\t\t\tif (isActive && wasSelectionMove) {\n\t\t\t\tsetIsOpen(true);\n\t\t\t}\n\t\t}, [isActive, wasSelectionMove]);\n\n\t\tconst handleSetImage = useCallback(() => {\n\t\t\tsetImage();\n\t\t\tsetIsOpen(false);\n\t\t}, [setImage]);\n\n\t\tconst handleRemoveImage = useCallback(() => {\n\t\t\tremoveImage();\n\t\t\tsetIsOpen(false);\n\t\t}, [removeImage]);\n\n\t\tconst handleKeyDown = useCallback(\n\t\t\t(event: React.KeyboardEvent<HTMLInputElement>) => {\n\t\t\t\tif (event.key === 'Enter') {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\thandleSetImage();\n\t\t\t\t}\n\t\t\t},\n\t\t\t[handleSetImage]\n\t\t);\n\n\t\treturn (\n\t\t\t<Popover open={isOpen} onOpenChange={setIsOpen}>\n\t\t\t\t<PopoverTrigger asChild>\n\t\t\t\t\t<Button\n\t\t\t\t\t\tref={ref}\n\t\t\t\t\t\taria-label=\"Image\"\n\t\t\t\t\t\taria-pressed={isActive}\n\t\t\t\t\t\tdata-active-state={isActive ? 'on' : 'off'}\n\t\t\t\t\t\tdisabled={!canSet}\n\t\t\t\t\t\tsize=\"icon\"\n\t\t\t\t\t\ttabIndex={-1}\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\t{...buttonProps}\n\t\t\t\t\t>\n\t\t\t\t\t\t<ImageIcon\n\t\t\t\t\t\t\tclassName={\n\t\t\t\t\t\t\t\tisActive ? 'nt:text-[var(--tt-brand-color-500)]' : undefined\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</Button>\n\t\t\t\t</PopoverTrigger>\n\t\t\t\t<PopoverContent\n\t\t\t\t\talign=\"start\"\n\t\t\t\t\tclassName=\"nt:flex nt:w-72 nt:flex-col nt:gap-1 nt:p-1\"\n\t\t\t\t>\n\t\t\t\t\t<Input\n\t\t\t\t\t\tautoFocus\n\t\t\t\t\t\tclassName=\"nt:h-7 nt:border-none nt:shadow-none nt:focus-visible:ring-0\"\n\t\t\t\t\t\tplaceholder=\"Paste image URL...\"\n\t\t\t\t\t\ttype=\"url\"\n\t\t\t\t\t\tvalue={url}\n\t\t\t\t\t\tonChange={(e) => setUrl(e.target.value)}\n\t\t\t\t\t\tonKeyDown={handleKeyDown}\n\t\t\t\t\t/>\n\t\t\t\t\t<Input\n\t\t\t\t\t\tclassName=\"nt:h-7 nt:border-none nt:shadow-none nt:focus-visible:ring-0\"\n\t\t\t\t\t\tplaceholder=\"Alt text (optional)\"\n\t\t\t\t\t\ttype=\"text\"\n\t\t\t\t\t\tvalue={alt}\n\t\t\t\t\t\tonChange={(e) => setAlt(e.target.value)}\n\t\t\t\t\t\tonKeyDown={handleKeyDown}\n\t\t\t\t\t/>\n\t\t\t\t\t<div className=\"nt:flex nt:items-center nt:justify-end nt:gap-1\">\n\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\taria-label=\"Apply image\"\n\t\t\t\t\t\t\tdisabled={!url && !isActive}\n\t\t\t\t\t\t\tsize=\"icon-sm\"\n\t\t\t\t\t\t\ttabIndex={-1}\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\t\tonClick={handleSetImage}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<CornerDownLeft />\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t{isActive && (\n\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t<Separator className=\"nt:h-5\" orientation=\"vertical\" />\n\t\t\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\t\t\taria-label=\"Remove image\"\n\t\t\t\t\t\t\t\t\tsize=\"icon-sm\"\n\t\t\t\t\t\t\t\t\ttabIndex={-1}\n\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\t\t\t\tonClick={handleRemoveImage}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<Trash2 />\n\t\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</div>\n\t\t\t\t</PopoverContent>\n\t\t\t</Popover>\n\t\t);\n\t}\n);\n\nImagePopover.displayName = 'ImagePopover';\n"],"mappings":"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","names":[]}
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var use_image_popover_exports = {};
20
+ __export(use_image_popover_exports, {
21
+ useImagePopover: () => useImagePopover
22
+ });
23
+ module.exports = __toCommonJS(use_image_popover_exports);
24
+ var import_react = require("react");
25
+ function useImagePopover({ editor }) {
26
+ const [url, setUrl] = (0, import_react.useState)("");
27
+ const [alt, setAlt] = (0, import_react.useState)("");
28
+ const [isActive, setIsActive] = (0, import_react.useState)(false);
29
+ const [canSet, setCanSet] = (0, import_react.useState)(false);
30
+ const [wasSelectionMove, setWasSelectionMove] = (0, import_react.useState)(false);
31
+ (0, import_react.useEffect)(() => {
32
+ if (!editor) return;
33
+ const handleUpdate = ({
34
+ transaction
35
+ } = {}) => {
36
+ const active = editor.isActive("image");
37
+ setIsActive(active);
38
+ setCanSet(editor.isEditable);
39
+ if (transaction) {
40
+ setWasSelectionMove(!transaction.docChanged);
41
+ }
42
+ if (active) {
43
+ const attrs = editor.getAttributes("image");
44
+ setUrl(attrs.src ?? "");
45
+ setAlt(attrs.alt ?? "");
46
+ }
47
+ };
48
+ handleUpdate();
49
+ editor.on("selectionUpdate", handleUpdate);
50
+ editor.on("transaction", handleUpdate);
51
+ return () => {
52
+ editor.off("selectionUpdate", handleUpdate);
53
+ editor.off("transaction", handleUpdate);
54
+ };
55
+ }, [editor]);
56
+ const removeImage = (0, import_react.useCallback)(() => {
57
+ if (!editor) return;
58
+ editor.chain().focus().deleteSelection().run();
59
+ setUrl("");
60
+ setAlt("");
61
+ }, [editor]);
62
+ const setImage = (0, import_react.useCallback)(() => {
63
+ if (!editor) return;
64
+ if (!url) {
65
+ if (isActive) {
66
+ removeImage();
67
+ }
68
+ return;
69
+ }
70
+ editor.chain().focus().setImage({ src: url, alt: alt || void 0 }).run();
71
+ }, [editor, url, alt, isActive, removeImage]);
72
+ return {
73
+ url,
74
+ setUrl,
75
+ alt,
76
+ setAlt,
77
+ isActive,
78
+ canSet,
79
+ setImage,
80
+ removeImage,
81
+ wasSelectionMove
82
+ };
83
+ }
84
+ // Annotate the CommonJS export names for ESM import in node:
85
+ 0 && (module.exports = {
86
+ useImagePopover
87
+ });
88
+ //# sourceMappingURL=use-image-popover.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/image-popover/use-image-popover.ts"],"sourcesContent":["import { useCallback, useEffect, useState } from 'react';\n\nimport type { Editor } from '@tiptap/core';\nimport type {} from '@tiptap/extension-image';\nimport type { Transaction } from '@tiptap/pm/state';\n\nexport interface UseImagePopoverConfig {\n\teditor: Editor | null;\n}\n\nexport function useImagePopover({ editor }: UseImagePopoverConfig) {\n\tconst [url, setUrl] = useState('');\n\tconst [alt, setAlt] = useState('');\n\tconst [isActive, setIsActive] = useState(false);\n\tconst [canSet, setCanSet] = useState(false);\n\tconst [wasSelectionMove, setWasSelectionMove] = useState(false);\n\n\tuseEffect(() => {\n\t\tif (!editor) return;\n\n\t\tconst handleUpdate = ({\n\t\t\ttransaction\n\t\t}: { transaction?: Transaction } = {}) => {\n\t\t\tconst active = editor.isActive('image');\n\n\t\t\tsetIsActive(active);\n\t\t\tsetCanSet(editor.isEditable);\n\n\t\t\tif (transaction) {\n\t\t\t\tsetWasSelectionMove(!transaction.docChanged);\n\t\t\t}\n\n\t\t\tif (active) {\n\t\t\t\tconst attrs = editor.getAttributes('image');\n\n\t\t\t\tsetUrl(attrs.src ?? '');\n\t\t\t\tsetAlt(attrs.alt ?? '');\n\t\t\t}\n\t\t};\n\n\t\thandleUpdate();\n\n\t\teditor.on('selectionUpdate', handleUpdate);\n\t\teditor.on('transaction', handleUpdate);\n\n\t\treturn () => {\n\t\t\teditor.off('selectionUpdate', handleUpdate);\n\t\t\teditor.off('transaction', handleUpdate);\n\t\t};\n\t}, [editor]);\n\n\tconst removeImage = useCallback(() => {\n\t\tif (!editor) return;\n\n\t\teditor.chain().focus().deleteSelection().run();\n\t\tsetUrl('');\n\t\tsetAlt('');\n\t}, [editor]);\n\n\tconst setImage = useCallback(() => {\n\t\tif (!editor) return;\n\n\t\tif (!url) {\n\t\t\tif (isActive) {\n\t\t\t\tremoveImage();\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\teditor\n\t\t\t.chain()\n\t\t\t.focus()\n\t\t\t.setImage({ src: url, alt: alt || undefined })\n\t\t\t.run();\n\t}, [editor, url, alt, isActive, removeImage]);\n\n\treturn {\n\t\turl,\n\t\tsetUrl,\n\t\talt,\n\t\tsetAlt,\n\t\tisActive,\n\t\tcanSet,\n\t\tsetImage,\n\t\tremoveImage,\n\t\twasSelectionMove\n\t};\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAiD;AAU1C,SAAS,gBAAgB,EAAE,OAAO,GAA0B;AAClE,QAAM,CAAC,KAAK,MAAM,QAAI,uBAAS,EAAE;AACjC,QAAM,CAAC,KAAK,MAAM,QAAI,uBAAS,EAAE;AACjC,QAAM,CAAC,UAAU,WAAW,QAAI,uBAAS,KAAK;AAC9C,QAAM,CAAC,QAAQ,SAAS,QAAI,uBAAS,KAAK;AAC1C,QAAM,CAAC,kBAAkB,mBAAmB,QAAI,uBAAS,KAAK;AAE9D,8BAAU,MAAM;AACf,QAAI,CAAC,OAAQ;AAEb,UAAM,eAAe,CAAC;AAAA,MACrB;AAAA,IACD,IAAmC,CAAC,MAAM;AACzC,YAAM,SAAS,OAAO,SAAS,OAAO;AAEtC,kBAAY,MAAM;AAClB,gBAAU,OAAO,UAAU;AAE3B,UAAI,aAAa;AAChB,4BAAoB,CAAC,YAAY,UAAU;AAAA,MAC5C;AAEA,UAAI,QAAQ;AACX,cAAM,QAAQ,OAAO,cAAc,OAAO;AAE1C,eAAO,MAAM,OAAO,EAAE;AACtB,eAAO,MAAM,OAAO,EAAE;AAAA,MACvB;AAAA,IACD;AAEA,iBAAa;AAEb,WAAO,GAAG,mBAAmB,YAAY;AACzC,WAAO,GAAG,eAAe,YAAY;AAErC,WAAO,MAAM;AACZ,aAAO,IAAI,mBAAmB,YAAY;AAC1C,aAAO,IAAI,eAAe,YAAY;AAAA,IACvC;AAAA,EACD,GAAG,CAAC,MAAM,CAAC;AAEX,QAAM,kBAAc,0BAAY,MAAM;AACrC,QAAI,CAAC,OAAQ;AAEb,WAAO,MAAM,EAAE,MAAM,EAAE,gBAAgB,EAAE,IAAI;AAC7C,WAAO,EAAE;AACT,WAAO,EAAE;AAAA,EACV,GAAG,CAAC,MAAM,CAAC;AAEX,QAAM,eAAW,0BAAY,MAAM;AAClC,QAAI,CAAC,OAAQ;AAEb,QAAI,CAAC,KAAK;AACT,UAAI,UAAU;AACb,oBAAY;AAAA,MACb;AAEA;AAAA,IACD;AAEA,WACE,MAAM,EACN,MAAM,EACN,SAAS,EAAE,KAAK,KAAK,KAAK,OAAO,OAAU,CAAC,EAC5C,IAAI;AAAA,EACP,GAAG,CAAC,QAAQ,KAAK,KAAK,UAAU,WAAW,CAAC;AAE5C,SAAO;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD;AACD;","names":[]}
@@ -0,0 +1,19 @@
1
+ import * as react from 'react';
2
+ import { Editor } from '@tiptap/core';
3
+
4
+ interface UseImagePopoverConfig {
5
+ editor: Editor | null;
6
+ }
7
+ declare function useImagePopover({ editor }: UseImagePopoverConfig): {
8
+ url: string;
9
+ setUrl: react.Dispatch<react.SetStateAction<string>>;
10
+ alt: string;
11
+ setAlt: react.Dispatch<react.SetStateAction<string>>;
12
+ isActive: boolean;
13
+ canSet: boolean;
14
+ setImage: () => void;
15
+ removeImage: () => void;
16
+ wasSelectionMove: boolean;
17
+ };
18
+
19
+ export { type UseImagePopoverConfig, useImagePopover };
@@ -0,0 +1,19 @@
1
+ import * as react from 'react';
2
+ import { Editor } from '@tiptap/core';
3
+
4
+ interface UseImagePopoverConfig {
5
+ editor: Editor | null;
6
+ }
7
+ declare function useImagePopover({ editor }: UseImagePopoverConfig): {
8
+ url: string;
9
+ setUrl: react.Dispatch<react.SetStateAction<string>>;
10
+ alt: string;
11
+ setAlt: react.Dispatch<react.SetStateAction<string>>;
12
+ isActive: boolean;
13
+ canSet: boolean;
14
+ setImage: () => void;
15
+ removeImage: () => void;
16
+ wasSelectionMove: boolean;
17
+ };
18
+
19
+ export { type UseImagePopoverConfig, useImagePopover };
@@ -0,0 +1,64 @@
1
+ import { useCallback, useEffect, useState } from "react";
2
+ function useImagePopover({ editor }) {
3
+ const [url, setUrl] = useState("");
4
+ const [alt, setAlt] = useState("");
5
+ const [isActive, setIsActive] = useState(false);
6
+ const [canSet, setCanSet] = useState(false);
7
+ const [wasSelectionMove, setWasSelectionMove] = useState(false);
8
+ useEffect(() => {
9
+ if (!editor) return;
10
+ const handleUpdate = ({
11
+ transaction
12
+ } = {}) => {
13
+ const active = editor.isActive("image");
14
+ setIsActive(active);
15
+ setCanSet(editor.isEditable);
16
+ if (transaction) {
17
+ setWasSelectionMove(!transaction.docChanged);
18
+ }
19
+ if (active) {
20
+ const attrs = editor.getAttributes("image");
21
+ setUrl(attrs.src ?? "");
22
+ setAlt(attrs.alt ?? "");
23
+ }
24
+ };
25
+ handleUpdate();
26
+ editor.on("selectionUpdate", handleUpdate);
27
+ editor.on("transaction", handleUpdate);
28
+ return () => {
29
+ editor.off("selectionUpdate", handleUpdate);
30
+ editor.off("transaction", handleUpdate);
31
+ };
32
+ }, [editor]);
33
+ const removeImage = useCallback(() => {
34
+ if (!editor) return;
35
+ editor.chain().focus().deleteSelection().run();
36
+ setUrl("");
37
+ setAlt("");
38
+ }, [editor]);
39
+ const setImage = useCallback(() => {
40
+ if (!editor) return;
41
+ if (!url) {
42
+ if (isActive) {
43
+ removeImage();
44
+ }
45
+ return;
46
+ }
47
+ editor.chain().focus().setImage({ src: url, alt: alt || void 0 }).run();
48
+ }, [editor, url, alt, isActive, removeImage]);
49
+ return {
50
+ url,
51
+ setUrl,
52
+ alt,
53
+ setAlt,
54
+ isActive,
55
+ canSet,
56
+ setImage,
57
+ removeImage,
58
+ wasSelectionMove
59
+ };
60
+ }
61
+ export {
62
+ useImagePopover
63
+ };
64
+ //# sourceMappingURL=use-image-popover.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/image-popover/use-image-popover.ts"],"sourcesContent":["import { useCallback, useEffect, useState } from 'react';\n\nimport type { Editor } from '@tiptap/core';\nimport type {} from '@tiptap/extension-image';\nimport type { Transaction } from '@tiptap/pm/state';\n\nexport interface UseImagePopoverConfig {\n\teditor: Editor | null;\n}\n\nexport function useImagePopover({ editor }: UseImagePopoverConfig) {\n\tconst [url, setUrl] = useState('');\n\tconst [alt, setAlt] = useState('');\n\tconst [isActive, setIsActive] = useState(false);\n\tconst [canSet, setCanSet] = useState(false);\n\tconst [wasSelectionMove, setWasSelectionMove] = useState(false);\n\n\tuseEffect(() => {\n\t\tif (!editor) return;\n\n\t\tconst handleUpdate = ({\n\t\t\ttransaction\n\t\t}: { transaction?: Transaction } = {}) => {\n\t\t\tconst active = editor.isActive('image');\n\n\t\t\tsetIsActive(active);\n\t\t\tsetCanSet(editor.isEditable);\n\n\t\t\tif (transaction) {\n\t\t\t\tsetWasSelectionMove(!transaction.docChanged);\n\t\t\t}\n\n\t\t\tif (active) {\n\t\t\t\tconst attrs = editor.getAttributes('image');\n\n\t\t\t\tsetUrl(attrs.src ?? '');\n\t\t\t\tsetAlt(attrs.alt ?? '');\n\t\t\t}\n\t\t};\n\n\t\thandleUpdate();\n\n\t\teditor.on('selectionUpdate', handleUpdate);\n\t\teditor.on('transaction', handleUpdate);\n\n\t\treturn () => {\n\t\t\teditor.off('selectionUpdate', handleUpdate);\n\t\t\teditor.off('transaction', handleUpdate);\n\t\t};\n\t}, [editor]);\n\n\tconst removeImage = useCallback(() => {\n\t\tif (!editor) return;\n\n\t\teditor.chain().focus().deleteSelection().run();\n\t\tsetUrl('');\n\t\tsetAlt('');\n\t}, [editor]);\n\n\tconst setImage = useCallback(() => {\n\t\tif (!editor) return;\n\n\t\tif (!url) {\n\t\t\tif (isActive) {\n\t\t\t\tremoveImage();\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\teditor\n\t\t\t.chain()\n\t\t\t.focus()\n\t\t\t.setImage({ src: url, alt: alt || undefined })\n\t\t\t.run();\n\t}, [editor, url, alt, isActive, removeImage]);\n\n\treturn {\n\t\turl,\n\t\tsetUrl,\n\t\talt,\n\t\tsetAlt,\n\t\tisActive,\n\t\tcanSet,\n\t\tsetImage,\n\t\tremoveImage,\n\t\twasSelectionMove\n\t};\n}\n"],"mappings":"AAAA,SAAS,aAAa,WAAW,gBAAgB;AAU1C,SAAS,gBAAgB,EAAE,OAAO,GAA0B;AAClE,QAAM,CAAC,KAAK,MAAM,IAAI,SAAS,EAAE;AACjC,QAAM,CAAC,KAAK,MAAM,IAAI,SAAS,EAAE;AACjC,QAAM,CAAC,UAAU,WAAW,IAAI,SAAS,KAAK;AAC9C,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAS,KAAK;AAC1C,QAAM,CAAC,kBAAkB,mBAAmB,IAAI,SAAS,KAAK;AAE9D,YAAU,MAAM;AACf,QAAI,CAAC,OAAQ;AAEb,UAAM,eAAe,CAAC;AAAA,MACrB;AAAA,IACD,IAAmC,CAAC,MAAM;AACzC,YAAM,SAAS,OAAO,SAAS,OAAO;AAEtC,kBAAY,MAAM;AAClB,gBAAU,OAAO,UAAU;AAE3B,UAAI,aAAa;AAChB,4BAAoB,CAAC,YAAY,UAAU;AAAA,MAC5C;AAEA,UAAI,QAAQ;AACX,cAAM,QAAQ,OAAO,cAAc,OAAO;AAE1C,eAAO,MAAM,OAAO,EAAE;AACtB,eAAO,MAAM,OAAO,EAAE;AAAA,MACvB;AAAA,IACD;AAEA,iBAAa;AAEb,WAAO,GAAG,mBAAmB,YAAY;AACzC,WAAO,GAAG,eAAe,YAAY;AAErC,WAAO,MAAM;AACZ,aAAO,IAAI,mBAAmB,YAAY;AAC1C,aAAO,IAAI,eAAe,YAAY;AAAA,IACvC;AAAA,EACD,GAAG,CAAC,MAAM,CAAC;AAEX,QAAM,cAAc,YAAY,MAAM;AACrC,QAAI,CAAC,OAAQ;AAEb,WAAO,MAAM,EAAE,MAAM,EAAE,gBAAgB,EAAE,IAAI;AAC7C,WAAO,EAAE;AACT,WAAO,EAAE;AAAA,EACV,GAAG,CAAC,MAAM,CAAC;AAEX,QAAM,WAAW,YAAY,MAAM;AAClC,QAAI,CAAC,OAAQ;AAEb,QAAI,CAAC,KAAK;AACT,UAAI,UAAU;AACb,oBAAY;AAAA,MACb;AAEA;AAAA,IACD;AAEA,WACE,MAAM,EACN,MAAM,EACN,SAAS,EAAE,KAAK,KAAK,KAAK,OAAO,OAAU,CAAC,EAC5C,IAAI;AAAA,EACP,GAAG,CAAC,QAAQ,KAAK,KAAK,UAAU,WAAW,CAAC;AAE5C,SAAO;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD;AACD;","names":[]}
@@ -33,12 +33,21 @@ var import_separator = require("../ui/separator");
33
33
  const LinkPopover = (0, import_react.forwardRef)(
34
34
  ({ editor, ...buttonProps }, ref) => {
35
35
  const [isOpen, setIsOpen] = (0, import_react.useState)(false);
36
- const { url, setUrl, isActive, canSet, setLink, removeLink, openLink } = (0, import_use_link_popover.useLinkPopover)({ editor });
36
+ const {
37
+ url,
38
+ setUrl,
39
+ isActive,
40
+ canSet,
41
+ setLink,
42
+ removeLink,
43
+ openLink,
44
+ wasSelectionMove
45
+ } = (0, import_use_link_popover.useLinkPopover)({ editor });
37
46
  (0, import_react.useEffect)(() => {
38
- if (isActive) {
47
+ if (isActive && wasSelectionMove) {
39
48
  setIsOpen(true);
40
49
  }
41
- }, [isActive]);
50
+ }, [isActive, wasSelectionMove]);
42
51
  const handleSetLink = (0, import_react.useCallback)(() => {
43
52
  setLink();
44
53
  setIsOpen(false);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/link-popover/link-popover.tsx"],"sourcesContent":["'use client';\n\nimport {\n\tCornerDownLeft,\n\tExternalLink,\n\tLink as LinkIcon,\n\tTrash2\n} from 'lucide-react';\nimport { forwardRef, useCallback, useEffect, useState } from 'react';\n\nimport { useLinkPopover } from './use-link-popover';\nimport { Button } from '../ui/button';\nimport { Input } from '../ui/input';\nimport { Popover, PopoverContent, PopoverTrigger } from '../ui/popover';\nimport { Separator } from '../ui/separator';\n\nimport type { Editor } from '@tiptap/core';\n\nexport interface LinkPopoverProps extends Omit<\n\tReact.ButtonHTMLAttributes<HTMLButtonElement>,\n\t'type'\n> {\n\teditor: Editor | null;\n}\n\nexport const LinkPopover = forwardRef<HTMLButtonElement, LinkPopoverProps>(\n\t({ editor, ...buttonProps }, ref) => {\n\t\tconst [isOpen, setIsOpen] = useState(false);\n\n\t\tconst { url, setUrl, isActive, canSet, setLink, removeLink, openLink } =\n\t\t\tuseLinkPopover({ editor });\n\n\t\t// Auto-open popover when a link becomes active\n\t\tuseEffect(() => {\n\t\t\tif (isActive) {\n\t\t\t\tsetIsOpen(true);\n\t\t\t}\n\t\t}, [isActive]);\n\n\t\tconst handleSetLink = useCallback(() => {\n\t\t\tsetLink();\n\t\t\tsetIsOpen(false);\n\t\t}, [setLink]);\n\n\t\tconst handleRemoveLink = useCallback(() => {\n\t\t\tremoveLink();\n\t\t\tsetIsOpen(false);\n\t\t}, [removeLink]);\n\n\t\tconst handleKeyDown = useCallback(\n\t\t\t(event: React.KeyboardEvent<HTMLInputElement>) => {\n\t\t\t\tif (event.key === 'Enter') {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\thandleSetLink();\n\t\t\t\t}\n\t\t\t},\n\t\t\t[handleSetLink]\n\t\t);\n\n\t\treturn (\n\t\t\t<Popover open={isOpen} onOpenChange={setIsOpen}>\n\t\t\t\t<PopoverTrigger asChild>\n\t\t\t\t\t<Button\n\t\t\t\t\t\tref={ref}\n\t\t\t\t\t\taria-label=\"Link\"\n\t\t\t\t\t\taria-pressed={isActive}\n\t\t\t\t\t\tdata-active-state={isActive ? 'on' : 'off'}\n\t\t\t\t\t\tdisabled={!canSet}\n\t\t\t\t\t\tsize=\"icon\"\n\t\t\t\t\t\ttabIndex={-1}\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\t{...buttonProps}\n\t\t\t\t\t>\n\t\t\t\t\t\t<LinkIcon\n\t\t\t\t\t\t\tclassName={\n\t\t\t\t\t\t\t\tisActive ? 'nt:text-[var(--tt-brand-color-500)]' : undefined\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</Button>\n\t\t\t\t</PopoverTrigger>\n\t\t\t\t<PopoverContent\n\t\t\t\t\talign=\"start\"\n\t\t\t\t\tclassName=\"nt:flex nt:w-auto nt:items-center nt:gap-1 nt:p-1\"\n\t\t\t\t>\n\t\t\t\t\t<Input\n\t\t\t\t\t\tautoFocus\n\t\t\t\t\t\tclassName=\"nt:h-7 nt:min-w-48 nt:border-none nt:shadow-none nt:focus-visible:ring-0\"\n\t\t\t\t\t\tplaceholder=\"Paste a link...\"\n\t\t\t\t\t\ttype=\"url\"\n\t\t\t\t\t\tvalue={url}\n\t\t\t\t\t\tonChange={(e) => setUrl(e.target.value)}\n\t\t\t\t\t\tonKeyDown={handleKeyDown}\n\t\t\t\t\t/>\n\t\t\t\t\t<Button\n\t\t\t\t\t\taria-label=\"Apply link\"\n\t\t\t\t\t\tdisabled={!url && !isActive}\n\t\t\t\t\t\tsize=\"icon-sm\"\n\t\t\t\t\t\ttabIndex={-1}\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\tonClick={handleSetLink}\n\t\t\t\t\t>\n\t\t\t\t\t\t<CornerDownLeft />\n\t\t\t\t\t</Button>\n\t\t\t\t\t<Separator className=\"nt:h-5\" orientation=\"vertical\" />\n\t\t\t\t\t<Button\n\t\t\t\t\t\taria-label=\"Open link in new window\"\n\t\t\t\t\t\tsize=\"icon-sm\"\n\t\t\t\t\t\ttabIndex={-1}\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\tonClick={openLink}\n\t\t\t\t\t>\n\t\t\t\t\t\t<ExternalLink />\n\t\t\t\t\t</Button>\n\t\t\t\t\t<Button\n\t\t\t\t\t\taria-label=\"Remove link\"\n\t\t\t\t\t\tsize=\"icon-sm\"\n\t\t\t\t\t\ttabIndex={-1}\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\tonClick={handleRemoveLink}\n\t\t\t\t\t>\n\t\t\t\t\t\t<Trash2 />\n\t\t\t\t\t</Button>\n\t\t\t\t</PopoverContent>\n\t\t\t</Popover>\n\t\t);\n\t}\n);\n\nLinkPopover.displayName = 'LinkPopover';\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA0EM;AAxEN,0BAKO;AACP,mBAA6D;AAE7D,8BAA+B;AAC/B,oBAAuB;AACvB,mBAAsB;AACtB,qBAAwD;AACxD,uBAA0B;AAWnB,MAAM,kBAAc;AAAA,EAC1B,CAAC,EAAE,QAAQ,GAAG,YAAY,GAAG,QAAQ;AACpC,UAAM,CAAC,QAAQ,SAAS,QAAI,uBAAS,KAAK;AAE1C,UAAM,EAAE,KAAK,QAAQ,UAAU,QAAQ,SAAS,YAAY,SAAS,QACpE,wCAAe,EAAE,OAAO,CAAC;AAG1B,gCAAU,MAAM;AACf,UAAI,UAAU;AACb,kBAAU,IAAI;AAAA,MACf;AAAA,IACD,GAAG,CAAC,QAAQ,CAAC;AAEb,UAAM,oBAAgB,0BAAY,MAAM;AACvC,cAAQ;AACR,gBAAU,KAAK;AAAA,IAChB,GAAG,CAAC,OAAO,CAAC;AAEZ,UAAM,uBAAmB,0BAAY,MAAM;AAC1C,iBAAW;AACX,gBAAU,KAAK;AAAA,IAChB,GAAG,CAAC,UAAU,CAAC;AAEf,UAAM,oBAAgB;AAAA,MACrB,CAAC,UAAiD;AACjD,YAAI,MAAM,QAAQ,SAAS;AAC1B,gBAAM,eAAe;AACrB,wBAAc;AAAA,QACf;AAAA,MACD;AAAA,MACA,CAAC,aAAa;AAAA,IACf;AAEA,WACC,6CAAC,0BAAQ,MAAM,QAAQ,cAAc,WACpC;AAAA,kDAAC,iCAAe,SAAO,MACtB;AAAA,QAAC;AAAA;AAAA,UACA;AAAA,UACA,cAAW;AAAA,UACX,gBAAc;AAAA,UACd,qBAAmB,WAAW,OAAO;AAAA,UACrC,UAAU,CAAC;AAAA,UACX,MAAK;AAAA,UACL,UAAU;AAAA,UACV,MAAK;AAAA,UACL,SAAQ;AAAA,UACP,GAAG;AAAA,UAEJ;AAAA,YAAC,oBAAAA;AAAA,YAAA;AAAA,cACA,WACC,WAAW,wCAAwC;AAAA;AAAA,UAErD;AAAA;AAAA,MACD,GACD;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACA,OAAM;AAAA,UACN,WAAU;AAAA,UAEV;AAAA;AAAA,cAAC;AAAA;AAAA,gBACA,WAAS;AAAA,gBACT,WAAU;AAAA,gBACV,aAAY;AAAA,gBACZ,MAAK;AAAA,gBACL,OAAO;AAAA,gBACP,UAAU,CAAC,MAAM,OAAO,EAAE,OAAO,KAAK;AAAA,gBACtC,WAAW;AAAA;AAAA,YACZ;AAAA,YACA;AAAA,cAAC;AAAA;AAAA,gBACA,cAAW;AAAA,gBACX,UAAU,CAAC,OAAO,CAAC;AAAA,gBACnB,MAAK;AAAA,gBACL,UAAU;AAAA,gBACV,MAAK;AAAA,gBACL,SAAQ;AAAA,gBACR,SAAS;AAAA,gBAET,sDAAC,sCAAe;AAAA;AAAA,YACjB;AAAA,YACA,4CAAC,8BAAU,WAAU,UAAS,aAAY,YAAW;AAAA,YACrD;AAAA,cAAC;AAAA;AAAA,gBACA,cAAW;AAAA,gBACX,MAAK;AAAA,gBACL,UAAU;AAAA,gBACV,MAAK;AAAA,gBACL,SAAQ;AAAA,gBACR,SAAS;AAAA,gBAET,sDAAC,oCAAa;AAAA;AAAA,YACf;AAAA,YACA;AAAA,cAAC;AAAA;AAAA,gBACA,cAAW;AAAA,gBACX,MAAK;AAAA,gBACL,UAAU;AAAA,gBACV,MAAK;AAAA,gBACL,SAAQ;AAAA,gBACR,SAAS;AAAA,gBAET,sDAAC,8BAAO;AAAA;AAAA,YACT;AAAA;AAAA;AAAA,MACD;AAAA,OACD;AAAA,EAEF;AACD;AAEA,YAAY,cAAc;","names":["LinkIcon"]}
1
+ {"version":3,"sources":["../../../src/components/link-popover/link-popover.tsx"],"sourcesContent":["'use client';\n\nimport {\n\tCornerDownLeft,\n\tExternalLink,\n\tLink as LinkIcon,\n\tTrash2\n} from 'lucide-react';\nimport { forwardRef, useCallback, useEffect, useState } from 'react';\n\nimport { useLinkPopover } from './use-link-popover';\nimport { Button } from '../ui/button';\nimport { Input } from '../ui/input';\nimport { Popover, PopoverContent, PopoverTrigger } from '../ui/popover';\nimport { Separator } from '../ui/separator';\n\nimport type { Editor } from '@tiptap/core';\n\nexport interface LinkPopoverProps extends Omit<\n\tReact.ButtonHTMLAttributes<HTMLButtonElement>,\n\t'type'\n> {\n\teditor: Editor | null;\n}\n\nexport const LinkPopover = forwardRef<HTMLButtonElement, LinkPopoverProps>(\n\t({ editor, ...buttonProps }, ref) => {\n\t\tconst [isOpen, setIsOpen] = useState(false);\n\n\t\tconst {\n\t\t\turl,\n\t\t\tsetUrl,\n\t\t\tisActive,\n\t\t\tcanSet,\n\t\t\tsetLink,\n\t\t\tremoveLink,\n\t\t\topenLink,\n\t\t\twasSelectionMove\n\t\t} = useLinkPopover({ editor });\n\n\t\t// Auto-open popover when cursor moves onto an existing link (selection-only transaction)\n\t\tuseEffect(() => {\n\t\t\tif (isActive && wasSelectionMove) {\n\t\t\t\tsetIsOpen(true);\n\t\t\t}\n\t\t}, [isActive, wasSelectionMove]);\n\n\t\tconst handleSetLink = useCallback(() => {\n\t\t\tsetLink();\n\t\t\tsetIsOpen(false);\n\t\t}, [setLink]);\n\n\t\tconst handleRemoveLink = useCallback(() => {\n\t\t\tremoveLink();\n\t\t\tsetIsOpen(false);\n\t\t}, [removeLink]);\n\n\t\tconst handleKeyDown = useCallback(\n\t\t\t(event: React.KeyboardEvent<HTMLInputElement>) => {\n\t\t\t\tif (event.key === 'Enter') {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\thandleSetLink();\n\t\t\t\t}\n\t\t\t},\n\t\t\t[handleSetLink]\n\t\t);\n\n\t\treturn (\n\t\t\t<Popover open={isOpen} onOpenChange={setIsOpen}>\n\t\t\t\t<PopoverTrigger asChild>\n\t\t\t\t\t<Button\n\t\t\t\t\t\tref={ref}\n\t\t\t\t\t\taria-label=\"Link\"\n\t\t\t\t\t\taria-pressed={isActive}\n\t\t\t\t\t\tdata-active-state={isActive ? 'on' : 'off'}\n\t\t\t\t\t\tdisabled={!canSet}\n\t\t\t\t\t\tsize=\"icon\"\n\t\t\t\t\t\ttabIndex={-1}\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\t{...buttonProps}\n\t\t\t\t\t>\n\t\t\t\t\t\t<LinkIcon\n\t\t\t\t\t\t\tclassName={\n\t\t\t\t\t\t\t\tisActive ? 'nt:text-[var(--tt-brand-color-500)]' : undefined\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</Button>\n\t\t\t\t</PopoverTrigger>\n\t\t\t\t<PopoverContent\n\t\t\t\t\talign=\"start\"\n\t\t\t\t\tclassName=\"nt:flex nt:w-auto nt:items-center nt:gap-1 nt:p-1\"\n\t\t\t\t>\n\t\t\t\t\t<Input\n\t\t\t\t\t\tautoFocus\n\t\t\t\t\t\tclassName=\"nt:h-7 nt:min-w-48 nt:border-none nt:shadow-none nt:focus-visible:ring-0\"\n\t\t\t\t\t\tplaceholder=\"Paste a link...\"\n\t\t\t\t\t\ttype=\"url\"\n\t\t\t\t\t\tvalue={url}\n\t\t\t\t\t\tonChange={(e) => setUrl(e.target.value)}\n\t\t\t\t\t\tonKeyDown={handleKeyDown}\n\t\t\t\t\t/>\n\t\t\t\t\t<Button\n\t\t\t\t\t\taria-label=\"Apply link\"\n\t\t\t\t\t\tdisabled={!url && !isActive}\n\t\t\t\t\t\tsize=\"icon-sm\"\n\t\t\t\t\t\ttabIndex={-1}\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\tonClick={handleSetLink}\n\t\t\t\t\t>\n\t\t\t\t\t\t<CornerDownLeft />\n\t\t\t\t\t</Button>\n\t\t\t\t\t<Separator className=\"nt:h-5\" orientation=\"vertical\" />\n\t\t\t\t\t<Button\n\t\t\t\t\t\taria-label=\"Open link in new window\"\n\t\t\t\t\t\tsize=\"icon-sm\"\n\t\t\t\t\t\ttabIndex={-1}\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\tonClick={openLink}\n\t\t\t\t\t>\n\t\t\t\t\t\t<ExternalLink />\n\t\t\t\t\t</Button>\n\t\t\t\t\t<Button\n\t\t\t\t\t\taria-label=\"Remove link\"\n\t\t\t\t\t\tsize=\"icon-sm\"\n\t\t\t\t\t\ttabIndex={-1}\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\tonClick={handleRemoveLink}\n\t\t\t\t\t>\n\t\t\t\t\t\t<Trash2 />\n\t\t\t\t\t</Button>\n\t\t\t\t</PopoverContent>\n\t\t\t</Popover>\n\t\t);\n\t}\n);\n\nLinkPopover.displayName = 'LinkPopover';\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAkFM;AAhFN,0BAKO;AACP,mBAA6D;AAE7D,8BAA+B;AAC/B,oBAAuB;AACvB,mBAAsB;AACtB,qBAAwD;AACxD,uBAA0B;AAWnB,MAAM,kBAAc;AAAA,EAC1B,CAAC,EAAE,QAAQ,GAAG,YAAY,GAAG,QAAQ;AACpC,UAAM,CAAC,QAAQ,SAAS,QAAI,uBAAS,KAAK;AAE1C,UAAM;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACD,QAAI,wCAAe,EAAE,OAAO,CAAC;AAG7B,gCAAU,MAAM;AACf,UAAI,YAAY,kBAAkB;AACjC,kBAAU,IAAI;AAAA,MACf;AAAA,IACD,GAAG,CAAC,UAAU,gBAAgB,CAAC;AAE/B,UAAM,oBAAgB,0BAAY,MAAM;AACvC,cAAQ;AACR,gBAAU,KAAK;AAAA,IAChB,GAAG,CAAC,OAAO,CAAC;AAEZ,UAAM,uBAAmB,0BAAY,MAAM;AAC1C,iBAAW;AACX,gBAAU,KAAK;AAAA,IAChB,GAAG,CAAC,UAAU,CAAC;AAEf,UAAM,oBAAgB;AAAA,MACrB,CAAC,UAAiD;AACjD,YAAI,MAAM,QAAQ,SAAS;AAC1B,gBAAM,eAAe;AACrB,wBAAc;AAAA,QACf;AAAA,MACD;AAAA,MACA,CAAC,aAAa;AAAA,IACf;AAEA,WACC,6CAAC,0BAAQ,MAAM,QAAQ,cAAc,WACpC;AAAA,kDAAC,iCAAe,SAAO,MACtB;AAAA,QAAC;AAAA;AAAA,UACA;AAAA,UACA,cAAW;AAAA,UACX,gBAAc;AAAA,UACd,qBAAmB,WAAW,OAAO;AAAA,UACrC,UAAU,CAAC;AAAA,UACX,MAAK;AAAA,UACL,UAAU;AAAA,UACV,MAAK;AAAA,UACL,SAAQ;AAAA,UACP,GAAG;AAAA,UAEJ;AAAA,YAAC,oBAAAA;AAAA,YAAA;AAAA,cACA,WACC,WAAW,wCAAwC;AAAA;AAAA,UAErD;AAAA;AAAA,MACD,GACD;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACA,OAAM;AAAA,UACN,WAAU;AAAA,UAEV;AAAA;AAAA,cAAC;AAAA;AAAA,gBACA,WAAS;AAAA,gBACT,WAAU;AAAA,gBACV,aAAY;AAAA,gBACZ,MAAK;AAAA,gBACL,OAAO;AAAA,gBACP,UAAU,CAAC,MAAM,OAAO,EAAE,OAAO,KAAK;AAAA,gBACtC,WAAW;AAAA;AAAA,YACZ;AAAA,YACA;AAAA,cAAC;AAAA;AAAA,gBACA,cAAW;AAAA,gBACX,UAAU,CAAC,OAAO,CAAC;AAAA,gBACnB,MAAK;AAAA,gBACL,UAAU;AAAA,gBACV,MAAK;AAAA,gBACL,SAAQ;AAAA,gBACR,SAAS;AAAA,gBAET,sDAAC,sCAAe;AAAA;AAAA,YACjB;AAAA,YACA,4CAAC,8BAAU,WAAU,UAAS,aAAY,YAAW;AAAA,YACrD;AAAA,cAAC;AAAA;AAAA,gBACA,cAAW;AAAA,gBACX,MAAK;AAAA,gBACL,UAAU;AAAA,gBACV,MAAK;AAAA,gBACL,SAAQ;AAAA,gBACR,SAAS;AAAA,gBAET,sDAAC,oCAAa;AAAA;AAAA,YACf;AAAA,YACA;AAAA,cAAC;AAAA;AAAA,gBACA,cAAW;AAAA,gBACX,MAAK;AAAA,gBACL,UAAU;AAAA,gBACV,MAAK;AAAA,gBACL,SAAQ;AAAA,gBACR,SAAS;AAAA,gBAET,sDAAC,8BAAO;AAAA;AAAA,YACT;AAAA;AAAA;AAAA,MACD;AAAA,OACD;AAAA,EAEF;AACD;AAEA,YAAY,cAAc;","names":["LinkIcon"]}
@@ -15,12 +15,21 @@ import { Separator } from "../ui/separator";
15
15
  const LinkPopover = forwardRef(
16
16
  ({ editor, ...buttonProps }, ref) => {
17
17
  const [isOpen, setIsOpen] = useState(false);
18
- const { url, setUrl, isActive, canSet, setLink, removeLink, openLink } = useLinkPopover({ editor });
18
+ const {
19
+ url,
20
+ setUrl,
21
+ isActive,
22
+ canSet,
23
+ setLink,
24
+ removeLink,
25
+ openLink,
26
+ wasSelectionMove
27
+ } = useLinkPopover({ editor });
19
28
  useEffect(() => {
20
- if (isActive) {
29
+ if (isActive && wasSelectionMove) {
21
30
  setIsOpen(true);
22
31
  }
23
- }, [isActive]);
32
+ }, [isActive, wasSelectionMove]);
24
33
  const handleSetLink = useCallback(() => {
25
34
  setLink();
26
35
  setIsOpen(false);