notra-editor 0.3.0 → 0.4.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 (221) hide show
  1. package/README.md +4 -8
  2. package/dist/components/blockquote-button/blockquote-button.cjs +91 -0
  3. package/dist/components/blockquote-button/blockquote-button.cjs.map +1 -0
  4. package/dist/components/blockquote-button/blockquote-button.d.cts +9 -0
  5. package/dist/components/blockquote-button/blockquote-button.d.ts +9 -0
  6. package/dist/components/blockquote-button/blockquote-button.mjs +67 -0
  7. package/dist/components/blockquote-button/blockquote-button.mjs.map +1 -0
  8. package/dist/components/code-block-button/code-block-button.cjs +91 -0
  9. package/dist/components/code-block-button/code-block-button.cjs.map +1 -0
  10. package/dist/components/code-block-button/code-block-button.d.cts +9 -0
  11. package/dist/components/code-block-button/code-block-button.d.ts +9 -0
  12. package/dist/components/code-block-button/code-block-button.mjs +67 -0
  13. package/dist/components/code-block-button/code-block-button.mjs.map +1 -0
  14. package/dist/components/code-block-view.cjs +39 -0
  15. package/dist/components/code-block-view.cjs.map +1 -0
  16. package/dist/components/code-block-view.d.cts +12 -0
  17. package/dist/components/code-block-view.d.ts +12 -0
  18. package/dist/components/code-block-view.mjs +17 -0
  19. package/dist/components/code-block-view.mjs.map +1 -0
  20. package/dist/components/copy-button.cjs +49 -0
  21. package/dist/components/copy-button.cjs.map +1 -0
  22. package/dist/components/copy-button.d.cts +9 -0
  23. package/dist/components/copy-button.d.ts +9 -0
  24. package/dist/components/copy-button.mjs +25 -0
  25. package/dist/components/copy-button.mjs.map +1 -0
  26. package/dist/components/heading-dropdown-menu/heading-dropdown-menu.cjs +67 -0
  27. package/dist/components/heading-dropdown-menu/heading-dropdown-menu.cjs.map +1 -0
  28. package/dist/components/heading-dropdown-menu/heading-dropdown-menu.d.cts +17 -0
  29. package/dist/components/heading-dropdown-menu/heading-dropdown-menu.d.ts +17 -0
  30. package/dist/components/heading-dropdown-menu/heading-dropdown-menu.mjs +51 -0
  31. package/dist/components/heading-dropdown-menu/heading-dropdown-menu.mjs.map +1 -0
  32. package/dist/components/heading-dropdown-menu/heading-menu-item.cjs +56 -0
  33. package/dist/components/heading-dropdown-menu/heading-menu-item.cjs.map +1 -0
  34. package/dist/components/heading-dropdown-menu/heading-menu-item.d.cts +12 -0
  35. package/dist/components/heading-dropdown-menu/heading-menu-item.d.ts +12 -0
  36. package/dist/components/heading-dropdown-menu/heading-menu-item.mjs +32 -0
  37. package/dist/components/heading-dropdown-menu/heading-menu-item.mjs.map +1 -0
  38. package/dist/components/heading-dropdown-menu/use-heading.cjs +109 -0
  39. package/dist/components/heading-dropdown-menu/use-heading.cjs.map +1 -0
  40. package/dist/components/heading-dropdown-menu/use-heading.d.cts +19 -0
  41. package/dist/components/heading-dropdown-menu/use-heading.d.ts +19 -0
  42. package/dist/components/heading-dropdown-menu/use-heading.mjs +83 -0
  43. package/dist/components/heading-dropdown-menu/use-heading.mjs.map +1 -0
  44. package/dist/components/link-popover/link-popover.cjs +148 -0
  45. package/dist/components/link-popover/link-popover.cjs.map +1 -0
  46. package/dist/components/link-popover/link-popover.d.cts +9 -0
  47. package/dist/components/link-popover/link-popover.d.ts +9 -0
  48. package/dist/components/link-popover/link-popover.mjs +129 -0
  49. package/dist/components/link-popover/link-popover.mjs.map +1 -0
  50. package/dist/components/link-popover/use-link-popover.cjs +71 -0
  51. package/dist/components/link-popover/use-link-popover.cjs.map +1 -0
  52. package/dist/components/link-popover/use-link-popover.d.cts +17 -0
  53. package/dist/components/link-popover/use-link-popover.d.ts +17 -0
  54. package/dist/components/link-popover/use-link-popover.mjs +47 -0
  55. package/dist/components/link-popover/use-link-popover.mjs.map +1 -0
  56. package/dist/components/list-dropdown-menu/list-dropdown-menu.cjs +73 -0
  57. package/dist/components/list-dropdown-menu/list-dropdown-menu.cjs.map +1 -0
  58. package/dist/components/list-dropdown-menu/list-dropdown-menu.d.cts +17 -0
  59. package/dist/components/list-dropdown-menu/list-dropdown-menu.d.ts +17 -0
  60. package/dist/components/list-dropdown-menu/list-dropdown-menu.mjs +57 -0
  61. package/dist/components/list-dropdown-menu/list-dropdown-menu.mjs.map +1 -0
  62. package/dist/components/list-dropdown-menu/list-menu-item.cjs +56 -0
  63. package/dist/components/list-dropdown-menu/list-menu-item.cjs.map +1 -0
  64. package/dist/components/list-dropdown-menu/list-menu-item.d.cts +12 -0
  65. package/dist/components/list-dropdown-menu/list-menu-item.d.ts +12 -0
  66. package/dist/components/list-dropdown-menu/list-menu-item.mjs +32 -0
  67. package/dist/components/list-dropdown-menu/list-menu-item.mjs.map +1 -0
  68. package/dist/components/list-dropdown-menu/use-list.cjs +111 -0
  69. package/dist/components/list-dropdown-menu/use-list.cjs.map +1 -0
  70. package/dist/components/list-dropdown-menu/use-list.d.cts +19 -0
  71. package/dist/components/list-dropdown-menu/use-list.d.ts +19 -0
  72. package/dist/components/list-dropdown-menu/use-list.mjs +85 -0
  73. package/dist/components/list-dropdown-menu/use-list.mjs.map +1 -0
  74. package/dist/components/mark-button/mark-button.cjs +72 -0
  75. package/dist/components/mark-button/mark-button.cjs.map +1 -0
  76. package/dist/components/mark-button/mark-button.d.cts +12 -0
  77. package/dist/components/mark-button/mark-button.d.ts +12 -0
  78. package/dist/components/mark-button/mark-button.mjs +48 -0
  79. package/dist/components/mark-button/mark-button.mjs.map +1 -0
  80. package/dist/components/mark-button/use-mark.cjs +71 -0
  81. package/dist/components/mark-button/use-mark.cjs.map +1 -0
  82. package/dist/components/mark-button/use-mark.d.cts +17 -0
  83. package/dist/components/mark-button/use-mark.d.ts +17 -0
  84. package/dist/components/mark-button/use-mark.mjs +47 -0
  85. package/dist/components/mark-button/use-mark.mjs.map +1 -0
  86. package/dist/components/toolbar/toolbar.cjs +77 -0
  87. package/dist/components/toolbar/toolbar.cjs.map +1 -0
  88. package/dist/components/toolbar/toolbar.d.cts +14 -0
  89. package/dist/components/toolbar/toolbar.d.ts +14 -0
  90. package/dist/components/toolbar/toolbar.mjs +51 -0
  91. package/dist/components/toolbar/toolbar.mjs.map +1 -0
  92. package/dist/components/ui/button.cjs +82 -0
  93. package/dist/components/ui/button.cjs.map +1 -0
  94. package/dist/components/ui/button.d.cts +14 -0
  95. package/dist/components/ui/button.d.ts +14 -0
  96. package/dist/components/ui/button.mjs +57 -0
  97. package/dist/components/ui/button.mjs.map +1 -0
  98. package/dist/components/ui/dropdown-menu.cjs +290 -0
  99. package/dist/components/ui/dropdown-menu.cjs.map +1 -0
  100. package/dist/components/ui/dropdown-menu.d.cts +32 -0
  101. package/dist/components/ui/dropdown-menu.d.ts +32 -0
  102. package/dist/components/ui/dropdown-menu.mjs +252 -0
  103. package/dist/components/ui/dropdown-menu.mjs.map +1 -0
  104. package/dist/components/ui/input.cjs +44 -0
  105. package/dist/components/ui/input.cjs.map +1 -0
  106. package/dist/components/ui/input.d.cts +6 -0
  107. package/dist/components/ui/input.d.ts +6 -0
  108. package/dist/components/ui/input.mjs +20 -0
  109. package/dist/components/ui/input.mjs.map +1 -0
  110. package/dist/components/ui/popover.cjs +72 -0
  111. package/dist/components/ui/popover.cjs.map +1 -0
  112. package/dist/components/ui/popover.d.cts +10 -0
  113. package/dist/components/ui/popover.d.ts +10 -0
  114. package/dist/components/ui/popover.mjs +45 -0
  115. package/dist/components/ui/popover.mjs.map +1 -0
  116. package/dist/components/ui/separator.cjs +51 -0
  117. package/dist/components/ui/separator.cjs.map +1 -0
  118. package/dist/components/ui/separator.d.cts +7 -0
  119. package/dist/components/ui/separator.d.ts +7 -0
  120. package/dist/components/ui/separator.mjs +27 -0
  121. package/dist/components/ui/separator.mjs.map +1 -0
  122. package/dist/components/ui/spacer.cjs +32 -0
  123. package/dist/components/ui/spacer.cjs.map +1 -0
  124. package/dist/components/ui/spacer.d.cts +5 -0
  125. package/dist/components/ui/spacer.d.ts +5 -0
  126. package/dist/components/ui/spacer.mjs +8 -0
  127. package/dist/components/ui/spacer.mjs.map +1 -0
  128. package/dist/components/undo-redo-button/undo-redo-button.cjs +63 -0
  129. package/dist/components/undo-redo-button/undo-redo-button.cjs.map +1 -0
  130. package/dist/components/undo-redo-button/undo-redo-button.d.cts +12 -0
  131. package/dist/components/undo-redo-button/undo-redo-button.d.ts +12 -0
  132. package/dist/components/undo-redo-button/undo-redo-button.mjs +39 -0
  133. package/dist/components/undo-redo-button/undo-redo-button.mjs.map +1 -0
  134. package/dist/components/undo-redo-button/use-undo-redo.cjs +68 -0
  135. package/dist/components/undo-redo-button/use-undo-redo.cjs.map +1 -0
  136. package/dist/components/undo-redo-button/use-undo-redo.d.cts +17 -0
  137. package/dist/components/undo-redo-button/use-undo-redo.d.ts +17 -0
  138. package/dist/components/undo-redo-button/use-undo-redo.mjs +44 -0
  139. package/dist/components/undo-redo-button/use-undo-redo.mjs.map +1 -0
  140. package/dist/extensions/code-block.cjs +46 -0
  141. package/dist/extensions/code-block.cjs.map +1 -0
  142. package/dist/extensions/code-block.d.cts +6 -0
  143. package/dist/extensions/code-block.d.ts +6 -0
  144. package/dist/extensions/code-block.mjs +12 -0
  145. package/dist/extensions/code-block.mjs.map +1 -0
  146. package/dist/extensions/editor.cjs +53 -0
  147. package/dist/extensions/editor.cjs.map +1 -0
  148. package/dist/extensions/editor.d.cts +9 -0
  149. package/dist/extensions/editor.d.ts +9 -0
  150. package/dist/extensions/editor.mjs +19 -0
  151. package/dist/extensions/editor.mjs.map +1 -0
  152. package/dist/extensions/index.cjs +32 -0
  153. package/dist/extensions/index.cjs.map +1 -0
  154. package/dist/extensions/index.d.cts +7 -0
  155. package/dist/extensions/index.d.ts +7 -0
  156. package/dist/extensions/index.mjs +7 -0
  157. package/dist/extensions/index.mjs.map +1 -0
  158. package/dist/extensions/shared.cjs +64 -0
  159. package/dist/extensions/shared.cjs.map +1 -0
  160. package/dist/extensions/shared.d.cts +8 -0
  161. package/dist/extensions/shared.d.ts +8 -0
  162. package/dist/extensions/shared.mjs +29 -0
  163. package/dist/extensions/shared.mjs.map +1 -0
  164. package/dist/hooks/use-copy-to-clipboard.cjs +50 -0
  165. package/dist/hooks/use-copy-to-clipboard.cjs.map +1 -0
  166. package/dist/hooks/use-copy-to-clipboard.d.cts +10 -0
  167. package/dist/hooks/use-copy-to-clipboard.d.ts +10 -0
  168. package/dist/hooks/use-copy-to-clipboard.mjs +26 -0
  169. package/dist/hooks/use-copy-to-clipboard.mjs.map +1 -0
  170. package/dist/hooks/use-markdown-editor.cjs +80 -0
  171. package/dist/hooks/use-markdown-editor.cjs.map +1 -0
  172. package/dist/hooks/use-markdown-editor.d.cts +13 -0
  173. package/dist/hooks/use-markdown-editor.d.ts +13 -0
  174. package/dist/hooks/use-markdown-editor.mjs +56 -0
  175. package/dist/hooks/use-markdown-editor.mjs.map +1 -0
  176. package/dist/icons/redo-icon.cjs +54 -0
  177. package/dist/icons/redo-icon.cjs.map +1 -0
  178. package/dist/icons/redo-icon.d.cts +7 -0
  179. package/dist/icons/redo-icon.d.ts +7 -0
  180. package/dist/icons/redo-icon.mjs +30 -0
  181. package/dist/icons/redo-icon.mjs.map +1 -0
  182. package/dist/icons/undo-icon.cjs +54 -0
  183. package/dist/icons/undo-icon.cjs.map +1 -0
  184. package/dist/icons/undo-icon.d.cts +7 -0
  185. package/dist/icons/undo-icon.d.ts +7 -0
  186. package/dist/icons/undo-icon.mjs +30 -0
  187. package/dist/icons/undo-icon.mjs.map +1 -0
  188. package/dist/index.cjs +24 -1322
  189. package/dist/index.cjs.map +1 -1
  190. package/dist/index.d.cts +22 -105
  191. package/dist/index.d.ts +22 -105
  192. package/dist/index.mjs +14 -1301
  193. package/dist/index.mjs.map +1 -1
  194. package/dist/lib/utils.cjs +33 -0
  195. package/dist/lib/utils.cjs.map +1 -0
  196. package/dist/lib/utils.d.cts +5 -0
  197. package/dist/lib/utils.d.ts +5 -0
  198. package/dist/lib/utils.mjs +9 -0
  199. package/dist/lib/utils.mjs.map +1 -0
  200. package/dist/notra-editor.cjs +88 -0
  201. package/dist/notra-editor.cjs.map +1 -0
  202. package/dist/notra-editor.d.cts +17 -0
  203. package/dist/notra-editor.d.ts +17 -0
  204. package/dist/notra-editor.mjs +68 -0
  205. package/dist/notra-editor.mjs.map +1 -0
  206. package/dist/notra-reader.cjs +47 -0
  207. package/dist/notra-reader.cjs.map +1 -0
  208. package/dist/notra-reader.d.cts +11 -0
  209. package/dist/notra-reader.d.ts +11 -0
  210. package/dist/notra-reader.mjs +23 -0
  211. package/dist/notra-reader.mjs.map +1 -0
  212. package/dist/styles/globals.css +29 -0
  213. package/dist/themes/default/editor.css +2 -0
  214. package/dist/themes/default/reader.css +2 -0
  215. package/dist/utils/markdown-to-json.cjs +50 -0
  216. package/dist/utils/markdown-to-json.cjs.map +1 -0
  217. package/dist/utils/markdown-to-json.d.cts +7 -0
  218. package/dist/utils/markdown-to-json.d.ts +7 -0
  219. package/dist/utils/markdown-to-json.mjs +26 -0
  220. package/dist/utils/markdown-to-json.mjs.map +1 -0
  221. package/package.json +2 -1
package/dist/index.cjs CHANGED
@@ -1,9 +1,7 @@
1
1
  "use strict";
2
- var __create = Object.create;
3
2
  var __defProp = Object.defineProperty;
4
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
6
  var __export = (target, all) => {
9
7
  for (var name in all)
@@ -17,1336 +15,40 @@ var __copyProps = (to, from, except, desc) => {
17
15
  }
18
16
  return to;
19
17
  };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
-
30
- // src/index.ts
31
19
  var index_exports = {};
32
20
  __export(index_exports, {
33
- BlockquoteButton: () => BlockquoteButton,
34
- CodeBlockButton: () => CodeBlockButton,
35
- DropdownMenu: () => DropdownMenu2,
36
- HeadingDropdownMenu: () => HeadingDropdownMenu,
37
- LinkPopover: () => LinkPopover,
38
- ListDropdownMenu: () => ListDropdownMenu,
39
- MarkButton: () => MarkButton,
40
- NotraEditor: () => NotraEditor,
41
- NotraReader: () => NotraReader,
42
- Spacer: () => Spacer,
43
- Toolbar: () => Toolbar,
44
- ToolbarGroup: () => ToolbarGroup,
45
- ToolbarSeparator: () => ToolbarSeparator,
46
- UndoRedoButton: () => UndoRedoButton
21
+ BlockquoteButton: () => import_blockquote_button.BlockquoteButton,
22
+ CodeBlockButton: () => import_code_block_button.CodeBlockButton,
23
+ HeadingDropdownMenu: () => import_heading_dropdown_menu.HeadingDropdownMenu,
24
+ LinkPopover: () => import_link_popover.LinkPopover,
25
+ ListDropdownMenu: () => import_list_dropdown_menu.ListDropdownMenu,
26
+ MarkButton: () => import_mark_button.MarkButton,
27
+ NotraEditor: () => import_notra_editor.NotraEditor,
28
+ NotraReader: () => import_notra_reader.NotraReader,
29
+ Spacer: () => import_spacer.Spacer,
30
+ Toolbar: () => import_toolbar.Toolbar,
31
+ ToolbarGroup: () => import_toolbar.ToolbarGroup,
32
+ ToolbarSeparator: () => import_toolbar.ToolbarSeparator,
33
+ UndoRedoButton: () => import_undo_redo_button.UndoRedoButton
47
34
  });
48
35
  module.exports = __toCommonJS(index_exports);
49
36
  var import_globals = require("./styles/globals.css");
50
-
51
- // src/notra-editor.tsx
52
- var import_react18 = require("@tiptap/react");
53
-
54
- // src/components/blockquote-button/blockquote-button.tsx
55
- var import_lucide_react = require("lucide-react");
56
- var import_react = require("react");
57
-
58
- // src/components/ui/button.tsx
59
- var import_class_variance_authority = require("class-variance-authority");
60
- var import_radix_ui = require("radix-ui");
61
-
62
- // src/lib/utils.ts
63
- var import_clsx = require("clsx");
64
- var import_tailwind_merge = require("tailwind-merge");
65
- function cn(...inputs) {
66
- return (0, import_tailwind_merge.twMerge)((0, import_clsx.clsx)(inputs));
67
- }
68
-
69
- // src/components/ui/button.tsx
70
- var import_jsx_runtime = require("react/jsx-runtime");
71
- var buttonVariants = (0, import_class_variance_authority.cva)(
72
- "nt:group/button nt:inline-flex nt:shrink-0 nt:items-center nt:justify-center nt:rounded-lg nt:border nt:border-transparent nt:bg-clip-padding nt:text-sm nt:font-medium nt:whitespace-nowrap nt:transition-all nt:outline-none nt:select-none nt:focus-visible:border-ring nt:focus-visible:ring-3 nt:focus-visible:ring-ring/50 nt:active:not-aria-[haspopup]:translate-y-px nt:disabled:pointer-events-none nt:disabled:opacity-50 nt:aria-invalid:border-destructive nt:aria-invalid:ring-3 nt:aria-invalid:ring-destructive/20 nt:dark:aria-invalid:border-destructive/50 nt:dark:aria-invalid:ring-destructive/40 nt:[&_svg]:pointer-events-none nt:[&_svg]:shrink-0 nt:[&_svg:not([class*=size-])]:size-4",
73
- {
74
- variants: {
75
- variant: {
76
- default: "nt:bg-primary nt:text-primary-foreground nt:[a]:hover:bg-primary/80",
77
- outline: "nt:border-border nt:bg-background nt:hover:bg-muted nt:hover:text-foreground nt:aria-expanded:bg-muted nt:aria-expanded:text-foreground nt:dark:border-input nt:dark:bg-input/30 nt:dark:hover:bg-input/50",
78
- secondary: "nt:bg-secondary nt:text-secondary-foreground nt:hover:bg-secondary/80 nt:aria-expanded:bg-secondary nt:aria-expanded:text-secondary-foreground",
79
- ghost: "nt:hover:bg-muted nt:hover:text-foreground nt:aria-expanded:bg-muted nt:aria-expanded:text-foreground nt:dark:hover:bg-muted/50",
80
- destructive: "nt:bg-destructive/10 nt:text-destructive nt:hover:bg-destructive/20 nt:focus-visible:border-destructive/40 nt:focus-visible:ring-destructive/20 nt:dark:bg-destructive/20 nt:dark:hover:bg-destructive/30 nt:dark:focus-visible:ring-destructive/40",
81
- link: "nt:text-primary nt:underline-offset-4 nt:hover:underline"
82
- },
83
- size: {
84
- default: "nt:h-8 nt:gap-1.5 nt:px-2.5 nt:has-data-[icon=inline-end]:pr-2 nt:has-data-[icon=inline-start]:pl-2",
85
- xs: "nt:h-6 nt:gap-1 nt:rounded-[min(var(--radius-md),10px)] nt:px-2 nt:text-xs nt:in-data-[slot=button-group]:rounded-lg nt:has-data-[icon=inline-end]:pr-1.5 nt:has-data-[icon=inline-start]:pl-1.5 nt:[&_svg:not([class*=size-])]:size-3",
86
- sm: "nt:h-7 nt:gap-1 nt:rounded-[min(var(--radius-md),12px)] nt:px-2.5 nt:text-[0.8rem] nt:in-data-[slot=button-group]:rounded-lg nt:has-data-[icon=inline-end]:pr-1.5 nt:has-data-[icon=inline-start]:pl-1.5 nt:[&_svg:not([class*=size-])]:size-3.5",
87
- lg: "nt:h-9 nt:gap-1.5 nt:px-2.5 nt:has-data-[icon=inline-end]:pr-2 nt:has-data-[icon=inline-start]:pl-2",
88
- icon: "nt:size-8",
89
- "icon-xs": "nt:size-6 nt:rounded-[min(var(--radius-md),10px)] nt:in-data-[slot=button-group]:rounded-lg nt:[&_svg:not([class*=size-])]:size-3",
90
- "icon-sm": "nt:size-7 nt:rounded-[min(var(--radius-md),12px)] nt:in-data-[slot=button-group]:rounded-lg",
91
- "icon-lg": "nt:size-9"
92
- }
93
- },
94
- defaultVariants: {
95
- variant: "default",
96
- size: "default"
97
- }
98
- }
99
- );
100
- function Button({
101
- className,
102
- variant = "default",
103
- size = "default",
104
- asChild = false,
105
- ...props
106
- }) {
107
- const Comp = asChild ? import_radix_ui.Slot.Root : "button";
108
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
109
- Comp,
110
- {
111
- className: cn(buttonVariants({ variant, size, className })),
112
- "data-size": size,
113
- "data-slot": "button",
114
- "data-variant": variant,
115
- ...props
116
- }
117
- );
118
- }
119
-
120
- // src/components/blockquote-button/blockquote-button.tsx
121
- var import_jsx_runtime2 = require("react/jsx-runtime");
122
- function canToggleBlockquote(editor) {
123
- if (!editor || !editor.isEditable) return false;
124
- return editor.can().toggleWrap("blockquote") || editor.can().clearNodes();
125
- }
126
- var BlockquoteButton = (0, import_react.forwardRef)(({ editor, onClick, ...buttonProps }, ref) => {
127
- const [isActive, setIsActive] = (0, import_react.useState)(false);
128
- const [canToggle, setCanToggle] = (0, import_react.useState)(false);
129
- (0, import_react.useEffect)(() => {
130
- if (!editor) return;
131
- const update = () => {
132
- setIsActive(editor.isActive("blockquote"));
133
- setCanToggle(canToggleBlockquote(editor));
134
- };
135
- update();
136
- editor.on("selectionUpdate", update);
137
- editor.on("transaction", update);
138
- return () => {
139
- editor.off("selectionUpdate", update);
140
- editor.off("transaction", update);
141
- };
142
- }, [editor]);
143
- const handleClick = (0, import_react.useCallback)(
144
- (event) => {
145
- onClick?.(event);
146
- if (event.defaultPrevented) return;
147
- if (!editor) return;
148
- if (editor.isActive("blockquote")) {
149
- editor.chain().focus().lift("blockquote").run();
150
- } else {
151
- editor.chain().focus().clearNodes().wrapIn("blockquote").run();
152
- }
153
- },
154
- [editor, onClick]
155
- );
156
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
157
- Button,
158
- {
159
- ref,
160
- "aria-label": "Blockquote",
161
- "aria-pressed": isActive,
162
- "data-active-state": isActive ? "on" : "off",
163
- disabled: !canToggle,
164
- size: "icon",
165
- tabIndex: -1,
166
- type: "button",
167
- variant: "ghost",
168
- onClick: handleClick,
169
- ...buttonProps,
170
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
171
- import_lucide_react.TextQuote,
172
- {
173
- className: isActive ? "nt:text-[var(--tt-brand-color-500)]" : void 0
174
- }
175
- )
176
- }
177
- );
178
- });
179
- BlockquoteButton.displayName = "BlockquoteButton";
180
-
181
- // src/components/code-block-button/code-block-button.tsx
182
- var import_lucide_react2 = require("lucide-react");
183
- var import_react2 = require("react");
184
- var import_jsx_runtime3 = require("react/jsx-runtime");
185
- function canToggleCodeBlock(editor) {
186
- if (!editor || !editor.isEditable) return false;
187
- return editor.can().toggleNode("codeBlock", "paragraph") || editor.can().clearNodes();
188
- }
189
- var CodeBlockButton = (0, import_react2.forwardRef)(({ editor, onClick, ...buttonProps }, ref) => {
190
- const [isActive, setIsActive] = (0, import_react2.useState)(false);
191
- const [canToggle, setCanToggle] = (0, import_react2.useState)(false);
192
- (0, import_react2.useEffect)(() => {
193
- if (!editor) return;
194
- const update = () => {
195
- setIsActive(editor.isActive("codeBlock"));
196
- setCanToggle(canToggleCodeBlock(editor));
197
- };
198
- update();
199
- editor.on("selectionUpdate", update);
200
- editor.on("transaction", update);
201
- return () => {
202
- editor.off("selectionUpdate", update);
203
- editor.off("transaction", update);
204
- };
205
- }, [editor]);
206
- const handleClick = (0, import_react2.useCallback)(
207
- (event) => {
208
- onClick?.(event);
209
- if (event.defaultPrevented) return;
210
- if (!editor) return;
211
- if (editor.isActive("codeBlock")) {
212
- editor.chain().focus().setNode("paragraph").run();
213
- } else {
214
- editor.chain().focus().clearNodes().toggleNode("codeBlock", "paragraph").run();
215
- }
216
- },
217
- [editor, onClick]
218
- );
219
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
220
- Button,
221
- {
222
- ref,
223
- "aria-label": "Code Block",
224
- "aria-pressed": isActive,
225
- "data-active-state": isActive ? "on" : "off",
226
- disabled: !canToggle,
227
- size: "icon",
228
- tabIndex: -1,
229
- type: "button",
230
- variant: "ghost",
231
- onClick: handleClick,
232
- ...buttonProps,
233
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
234
- import_lucide_react2.SquareCode,
235
- {
236
- className: isActive ? "nt:text-[var(--tt-brand-color-500)]" : void 0
237
- }
238
- )
239
- }
240
- );
241
- });
242
- CodeBlockButton.displayName = "CodeBlockButton";
243
-
244
- // src/components/heading-dropdown-menu/heading-dropdown-menu.tsx
245
- var import_lucide_react5 = require("lucide-react");
246
- var import_react5 = require("react");
247
-
248
- // src/components/heading-dropdown-menu/heading-menu-item.tsx
249
- var import_react4 = require("react");
250
-
251
- // src/components/heading-dropdown-menu/use-heading.ts
252
- var import_lucide_react3 = require("lucide-react");
253
- var import_react3 = require("react");
254
- var headingIcons = {
255
- 1: import_lucide_react3.Heading1,
256
- 2: import_lucide_react3.Heading2,
257
- 3: import_lucide_react3.Heading3,
258
- 4: import_lucide_react3.Heading4
259
- };
260
- var headingLabels = {
261
- 1: "Heading 1",
262
- 2: "Heading 2",
263
- 3: "Heading 3",
264
- 4: "Heading 4"
265
- };
266
- function canToggleHeading(editor, level) {
267
- if (!editor || !editor.isEditable) return false;
268
- return editor.can().setNode("heading", { level }) || editor.can().clearNodes();
269
- }
270
- function useHeading({
271
- editor,
272
- level
273
- }) {
274
- const [isActive, setIsActive] = (0, import_react3.useState)(false);
275
- const [canToggle, setCanToggle] = (0, import_react3.useState)(false);
276
- (0, import_react3.useEffect)(() => {
277
- if (!editor) return;
278
- const handleUpdate = () => {
279
- setIsActive(editor.isActive("heading", { level }));
280
- setCanToggle(canToggleHeading(editor, level));
281
- };
282
- handleUpdate();
283
- editor.on("selectionUpdate", handleUpdate);
284
- editor.on("transaction", handleUpdate);
285
- return () => {
286
- editor.off("selectionUpdate", handleUpdate);
287
- editor.off("transaction", handleUpdate);
288
- };
289
- }, [editor, level]);
290
- const handleToggle = (0, import_react3.useCallback)(() => {
291
- if (!editor || !editor.isEditable) return false;
292
- if (editor.isActive("heading", { level })) {
293
- return editor.chain().focus().setNode("paragraph").run();
294
- }
295
- return editor.chain().focus().clearNodes().setNode("heading", { level }).run();
296
- }, [editor, level]);
297
- return {
298
- isActive,
299
- canToggle,
300
- handleToggle,
301
- label: headingLabels[level],
302
- Icon: headingIcons[level]
303
- };
304
- }
305
- function useActiveHeadingLevel(editor, levels) {
306
- const [activeLevel, setActiveLevel] = (0, import_react3.useState)(null);
307
- (0, import_react3.useEffect)(() => {
308
- if (!editor) return;
309
- const handleUpdate = () => {
310
- const found = levels.find(
311
- (level) => editor.isActive("heading", { level })
312
- );
313
- setActiveLevel(found ?? null);
314
- };
315
- handleUpdate();
316
- editor.on("selectionUpdate", handleUpdate);
317
- editor.on("transaction", handleUpdate);
318
- return () => {
319
- editor.off("selectionUpdate", handleUpdate);
320
- editor.off("transaction", handleUpdate);
321
- };
322
- }, [editor, levels]);
323
- return activeLevel;
324
- }
325
- function getHeadingTriggerIcon(activeLevel) {
326
- if (activeLevel === null) return import_lucide_react3.Heading;
327
- return headingIcons[activeLevel];
328
- }
329
-
330
- // src/components/ui/dropdown-menu.tsx
331
- var import_lucide_react4 = require("lucide-react");
332
- var import_radix_ui2 = require("radix-ui");
333
- var import_jsx_runtime4 = require("react/jsx-runtime");
334
- function DropdownMenu({
335
- ...props
336
- }) {
337
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_radix_ui2.DropdownMenu.Root, { "data-slot": "dropdown-menu", ...props });
338
- }
339
- function DropdownMenuTrigger({
340
- ...props
341
- }) {
342
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
343
- import_radix_ui2.DropdownMenu.Trigger,
344
- {
345
- "data-slot": "dropdown-menu-trigger",
346
- ...props
347
- }
348
- );
349
- }
350
- function DropdownMenuContent({
351
- className,
352
- align = "start",
353
- sideOffset = 4,
354
- ...props
355
- }) {
356
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_radix_ui2.DropdownMenu.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
357
- import_radix_ui2.DropdownMenu.Content,
358
- {
359
- align,
360
- className: cn(
361
- "nt:z-50 nt:max-h-(--radix-dropdown-menu-content-available-height) nt:w-(--radix-dropdown-menu-trigger-width) nt:min-w-32 nt:origin-(--radix-dropdown-menu-content-transform-origin) nt:overflow-x-hidden nt:overflow-y-auto nt:rounded-lg nt:bg-popover nt:p-1 nt:text-popover-foreground nt:shadow-md nt:ring-1 nt:ring-foreground/10 nt:duration-100 nt:data-[side=bottom]:slide-in-from-top-2 nt:data-[side=left]:slide-in-from-right-2 nt:data-[side=right]:slide-in-from-left-2 nt:data-[side=top]:slide-in-from-bottom-2 nt:data-[state=closed]:overflow-hidden nt:data-open:animate-in nt:data-open:fade-in-0 nt:data-open:zoom-in-95 nt:data-closed:animate-out nt:data-closed:fade-out-0 nt:data-closed:zoom-out-95",
362
- className
363
- ),
364
- "data-slot": "dropdown-menu-content",
365
- sideOffset,
366
- ...props
367
- }
368
- ) });
369
- }
370
- function DropdownMenuGroup({
371
- ...props
372
- }) {
373
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_radix_ui2.DropdownMenu.Group, { "data-slot": "dropdown-menu-group", ...props });
374
- }
375
- function DropdownMenuItem({
376
- className,
377
- inset,
378
- variant = "default",
379
- ...props
380
- }) {
381
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
382
- import_radix_ui2.DropdownMenu.Item,
383
- {
384
- className: cn(
385
- "nt:group/dropdown-menu-item nt:relative nt:flex nt:cursor-default nt:items-center nt:gap-1.5 nt:rounded-md nt:px-1.5 nt:py-1 nt:text-sm nt:outline-hidden nt:select-none nt:focus:bg-accent nt:focus:text-accent-foreground nt:not-data-[variant=destructive]:focus:**:text-accent-foreground nt:data-inset:pl-7 nt:data-[variant=destructive]:text-destructive nt:data-[variant=destructive]:focus:bg-destructive/10 nt:data-[variant=destructive]:focus:text-destructive nt:dark:data-[variant=destructive]:focus:bg-destructive/20 nt:data-disabled:pointer-events-none nt:data-disabled:opacity-50 nt:[&_svg]:pointer-events-none nt:[&_svg]:shrink-0 nt:[&_svg:not([class*=size-])]:size-4 nt:data-[variant=destructive]:*:[svg]:text-destructive",
386
- className
387
- ),
388
- "data-inset": inset,
389
- "data-slot": "dropdown-menu-item",
390
- "data-variant": variant,
391
- ...props
392
- }
393
- );
394
- }
395
-
396
- // src/components/heading-dropdown-menu/heading-menu-item.tsx
397
- var import_jsx_runtime5 = require("react/jsx-runtime");
398
- var HeadingMenuItem = (0, import_react4.forwardRef)(
399
- ({ editor, level }, ref) => {
400
- const { isActive, canToggle, handleToggle, label, Icon } = useHeading({
401
- editor,
402
- level
403
- });
404
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
405
- DropdownMenuItem,
406
- {
407
- ref,
408
- "aria-label": label,
409
- className: "nt:data-[active-state=on]:bg-accent nt:data-[active-state=on]:text-[var(--tt-brand-color-500)]",
410
- "data-active-state": isActive ? "on" : "off",
411
- disabled: !canToggle,
412
- onSelect: handleToggle,
413
- children: [
414
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Icon, {}),
415
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: label })
416
- ]
417
- }
418
- );
419
- }
420
- );
421
- HeadingMenuItem.displayName = "HeadingMenuItem";
422
-
423
- // src/components/heading-dropdown-menu/heading-dropdown-menu.tsx
424
- var import_jsx_runtime6 = require("react/jsx-runtime");
425
- var HeadingDropdownMenu = (0, import_react5.forwardRef)(({ editor, levels = [1, 2, 3, 4], ...buttonProps }, ref) => {
426
- const activeLevel = useActiveHeadingLevel(editor, levels);
427
- const TriggerIcon = getHeadingTriggerIcon(activeLevel);
428
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(DropdownMenu, { children: [
429
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
430
- Button,
431
- {
432
- ref,
433
- "aria-label": "Heading",
434
- className: "nt:gap-1 nt:px-2",
435
- "data-active-state": activeLevel !== null ? "on" : "off",
436
- size: "default",
437
- tabIndex: -1,
438
- type: "button",
439
- variant: "ghost",
440
- ...buttonProps,
441
- children: [
442
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
443
- TriggerIcon,
444
- {
445
- className: activeLevel !== null ? "nt:text-[var(--tt-brand-color-500)]" : void 0
446
- }
447
- ),
448
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react5.ChevronDown, { className: "nt:size-3" })
449
- ]
450
- }
451
- ) }),
452
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DropdownMenuContent, { align: "start", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DropdownMenuGroup, { children: levels.map((level) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(HeadingMenuItem, { editor, level }, level)) }) })
453
- ] });
454
- });
455
- HeadingDropdownMenu.displayName = "HeadingDropdownMenu";
456
-
457
- // src/components/link-popover/link-popover.tsx
458
- var import_lucide_react6 = require("lucide-react");
459
- var import_react7 = require("react");
460
-
461
- // src/components/link-popover/use-link-popover.ts
462
- var import_react6 = require("react");
463
- function useLinkPopover({ editor }) {
464
- const [url, setUrl] = (0, import_react6.useState)("");
465
- const [isActive, setIsActive] = (0, import_react6.useState)(false);
466
- const [canSet, setCanSet] = (0, import_react6.useState)(false);
467
- (0, import_react6.useEffect)(() => {
468
- if (!editor) return;
469
- const handleUpdate = () => {
470
- const active = editor.isActive("link");
471
- setIsActive(active);
472
- setCanSet(editor.isEditable);
473
- if (active) {
474
- setUrl(editor.getAttributes("link").href ?? "");
475
- }
476
- };
477
- handleUpdate();
478
- editor.on("selectionUpdate", handleUpdate);
479
- editor.on("transaction", handleUpdate);
480
- return () => {
481
- editor.off("selectionUpdate", handleUpdate);
482
- editor.off("transaction", handleUpdate);
483
- };
484
- }, [editor]);
485
- const setLink = (0, import_react6.useCallback)(() => {
486
- if (!editor) return;
487
- if (!url) {
488
- editor.chain().focus().extendMarkRange("link").unsetLink().run();
489
- return;
490
- }
491
- editor.chain().focus().extendMarkRange("link").setLink({ href: url }).run();
492
- }, [editor, url]);
493
- const removeLink = (0, import_react6.useCallback)(() => {
494
- if (!editor) return;
495
- editor.chain().focus().extendMarkRange("link").unsetLink().run();
496
- setUrl("");
497
- }, [editor]);
498
- const openLink = (0, import_react6.useCallback)(() => {
499
- if (!url) return;
500
- const sanitized = /^https?:\/\//i.test(url) ? url : `https://${url}`;
501
- window.open(sanitized, "_blank", "noopener,noreferrer");
502
- }, [url]);
503
- return { url, setUrl, isActive, canSet, setLink, removeLink, openLink };
504
- }
505
-
506
- // src/components/ui/input.tsx
507
- var import_jsx_runtime7 = require("react/jsx-runtime");
508
- function Input({ className, type, ...props }) {
509
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
510
- "input",
511
- {
512
- className: cn(
513
- "nt:flex nt:h-9 nt:w-full nt:min-w-0 nt:rounded-md nt:border nt:border-input nt:bg-transparent nt:px-3 nt:py-1 nt:text-base nt:shadow-xs nt:transition-[color,box-shadow] nt:outline-none nt:file:inline-flex nt:file:h-7 nt:file:border-0 nt:file:bg-transparent nt:file:text-sm nt:file:font-medium nt:file:text-foreground nt:placeholder:text-muted-foreground nt:selection:bg-primary nt:selection:text-primary-foreground nt:dark:bg-input/30 nt:md:text-sm nt:focus-visible:border-ring nt:focus-visible:ring-3 nt:focus-visible:ring-ring/50 nt:aria-invalid:border-destructive nt:aria-invalid:ring-3 nt:aria-invalid:ring-destructive/20 nt:dark:aria-invalid:ring-destructive/40 nt:disabled:cursor-not-allowed nt:disabled:opacity-50",
514
- className
515
- ),
516
- "data-slot": "input",
517
- type,
518
- ...props
519
- }
520
- );
521
- }
522
-
523
- // src/components/ui/popover.tsx
524
- var import_radix_ui3 = require("radix-ui");
525
- var import_jsx_runtime8 = require("react/jsx-runtime");
526
- function Popover({
527
- ...props
528
- }) {
529
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_radix_ui3.Popover.Root, { "data-slot": "popover", ...props });
530
- }
531
- function PopoverTrigger({
532
- ...props
533
- }) {
534
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_radix_ui3.Popover.Trigger, { "data-slot": "popover-trigger", ...props });
535
- }
536
- function PopoverContent({
537
- className,
538
- align = "center",
539
- sideOffset = 4,
540
- ...props
541
- }) {
542
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_radix_ui3.Popover.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
543
- import_radix_ui3.Popover.Content,
544
- {
545
- align,
546
- className: cn(
547
- "nt:z-50 nt:w-72 nt:origin-(--radix-popover-content-transform-origin) nt:rounded-lg nt:bg-popover nt:p-4 nt:text-popover-foreground nt:shadow-md nt:ring-1 nt:ring-foreground/10 nt:outline-none nt:data-[side=bottom]:slide-in-from-top-2 nt:data-[side=left]:slide-in-from-right-2 nt:data-[side=right]:slide-in-from-left-2 nt:data-[side=top]:slide-in-from-bottom-2 nt:data-open:animate-in nt:data-open:fade-in-0 nt:data-open:zoom-in-95 nt:data-closed:animate-out nt:data-closed:fade-out-0 nt:data-closed:zoom-out-95",
548
- className
549
- ),
550
- "data-slot": "popover-content",
551
- sideOffset,
552
- ...props
553
- }
554
- ) });
555
- }
556
-
557
- // src/components/ui/separator.tsx
558
- var import_radix_ui4 = require("radix-ui");
559
- var import_jsx_runtime9 = require("react/jsx-runtime");
560
- function Separator({
561
- className,
562
- orientation = "horizontal",
563
- decorative = true,
564
- ...props
565
- }) {
566
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
567
- import_radix_ui4.Separator.Root,
568
- {
569
- className: cn(
570
- "nt:shrink-0 nt:bg-border nt:data-[orientation=horizontal]:h-px nt:data-[orientation=horizontal]:w-full nt:data-[orientation=vertical]:h-full nt:data-[orientation=vertical]:w-px",
571
- className
572
- ),
573
- "data-slot": "separator",
574
- decorative,
575
- orientation,
576
- ...props
577
- }
578
- );
579
- }
580
-
581
- // src/components/link-popover/link-popover.tsx
582
- var import_jsx_runtime10 = require("react/jsx-runtime");
583
- var LinkPopover = (0, import_react7.forwardRef)(
584
- ({ editor, ...buttonProps }, ref) => {
585
- const [isOpen, setIsOpen] = (0, import_react7.useState)(false);
586
- const { url, setUrl, isActive, canSet, setLink, removeLink, openLink } = useLinkPopover({ editor });
587
- (0, import_react7.useEffect)(() => {
588
- if (isActive) {
589
- setIsOpen(true);
590
- }
591
- }, [isActive]);
592
- const handleSetLink = (0, import_react7.useCallback)(() => {
593
- setLink();
594
- setIsOpen(false);
595
- }, [setLink]);
596
- const handleRemoveLink = (0, import_react7.useCallback)(() => {
597
- removeLink();
598
- setIsOpen(false);
599
- }, [removeLink]);
600
- const handleKeyDown = (0, import_react7.useCallback)(
601
- (event) => {
602
- if (event.key === "Enter") {
603
- event.preventDefault();
604
- handleSetLink();
605
- }
606
- },
607
- [handleSetLink]
608
- );
609
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Popover, { open: isOpen, onOpenChange: setIsOpen, children: [
610
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
611
- Button,
612
- {
613
- ref,
614
- "aria-label": "Link",
615
- "aria-pressed": isActive,
616
- "data-active-state": isActive ? "on" : "off",
617
- disabled: !canSet,
618
- size: "icon",
619
- tabIndex: -1,
620
- type: "button",
621
- variant: "ghost",
622
- ...buttonProps,
623
- children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
624
- import_lucide_react6.Link,
625
- {
626
- className: isActive ? "nt:text-[var(--tt-brand-color-500)]" : void 0
627
- }
628
- )
629
- }
630
- ) }),
631
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
632
- PopoverContent,
633
- {
634
- align: "start",
635
- className: "nt:flex nt:w-auto nt:items-center nt:gap-1 nt:p-1",
636
- children: [
637
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
638
- Input,
639
- {
640
- autoFocus: true,
641
- className: "nt:h-7 nt:min-w-48 nt:border-none nt:shadow-none nt:focus-visible:ring-0",
642
- placeholder: "Paste a link...",
643
- type: "url",
644
- value: url,
645
- onChange: (e) => setUrl(e.target.value),
646
- onKeyDown: handleKeyDown
647
- }
648
- ),
649
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
650
- Button,
651
- {
652
- "aria-label": "Apply link",
653
- disabled: !url && !isActive,
654
- size: "icon-sm",
655
- tabIndex: -1,
656
- type: "button",
657
- variant: "ghost",
658
- onClick: handleSetLink,
659
- children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react6.CornerDownLeft, {})
660
- }
661
- ),
662
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Separator, { className: "nt:h-5", orientation: "vertical" }),
663
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
664
- Button,
665
- {
666
- "aria-label": "Open link in new window",
667
- size: "icon-sm",
668
- tabIndex: -1,
669
- type: "button",
670
- variant: "ghost",
671
- onClick: openLink,
672
- children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react6.ExternalLink, {})
673
- }
674
- ),
675
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
676
- Button,
677
- {
678
- "aria-label": "Remove link",
679
- size: "icon-sm",
680
- tabIndex: -1,
681
- type: "button",
682
- variant: "ghost",
683
- onClick: handleRemoveLink,
684
- children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react6.Trash2, {})
685
- }
686
- )
687
- ]
688
- }
689
- )
690
- ] });
691
- }
692
- );
693
- LinkPopover.displayName = "LinkPopover";
694
-
695
- // src/components/list-dropdown-menu/list-dropdown-menu.tsx
696
- var import_lucide_react8 = require("lucide-react");
697
- var import_react10 = require("react");
698
-
699
- // src/components/list-dropdown-menu/list-menu-item.tsx
700
- var import_react9 = require("react");
701
-
702
- // src/components/list-dropdown-menu/use-list.ts
703
- var import_lucide_react7 = require("lucide-react");
704
- var import_react8 = require("react");
705
- var listIcons = {
706
- bulletList: import_lucide_react7.List,
707
- orderedList: import_lucide_react7.ListOrdered,
708
- taskList: import_lucide_react7.ListTodo
709
- };
710
- var listLabels = {
711
- bulletList: "Bullet List",
712
- orderedList: "Ordered List",
713
- taskList: "Task List"
714
- };
715
- var listItemTypes = {
716
- bulletList: "listItem",
717
- orderedList: "listItem",
718
- taskList: "taskItem"
719
- };
720
- function canToggleList(editor) {
721
- if (!editor || !editor.isEditable) return false;
722
- return editor.can().toggleList("bulletList", "listItem") || editor.can().clearNodes();
723
- }
724
- function useList({
725
- editor,
726
- type
727
- }) {
728
- const [isActive, setIsActive] = (0, import_react8.useState)(false);
729
- const [canToggle, setCanToggle] = (0, import_react8.useState)(false);
730
- (0, import_react8.useEffect)(() => {
731
- if (!editor) return;
732
- const handleUpdate = () => {
733
- setIsActive(editor.isActive(type));
734
- setCanToggle(canToggleList(editor));
735
- };
736
- handleUpdate();
737
- editor.on("selectionUpdate", handleUpdate);
738
- editor.on("transaction", handleUpdate);
739
- return () => {
740
- editor.off("selectionUpdate", handleUpdate);
741
- editor.off("transaction", handleUpdate);
742
- };
743
- }, [editor, type]);
744
- const handleToggle = (0, import_react8.useCallback)(() => {
745
- if (!editor || !editor.isEditable) return false;
746
- const itemType = listItemTypes[type];
747
- if (editor.isActive(type)) {
748
- return editor.chain().focus().clearNodes().run();
749
- }
750
- return editor.chain().focus().clearNodes().toggleList(type, itemType).run();
751
- }, [editor, type]);
752
- return {
753
- isActive,
754
- canToggle,
755
- handleToggle,
756
- label: listLabels[type],
757
- Icon: listIcons[type]
758
- };
759
- }
760
- function useActiveListType(editor, types) {
761
- const [activeType, setActiveType] = (0, import_react8.useState)(null);
762
- (0, import_react8.useEffect)(() => {
763
- if (!editor) return;
764
- const handleUpdate = () => {
765
- const found = types.find((type) => editor.isActive(type));
766
- setActiveType(found ?? null);
767
- };
768
- handleUpdate();
769
- editor.on("selectionUpdate", handleUpdate);
770
- editor.on("transaction", handleUpdate);
771
- return () => {
772
- editor.off("selectionUpdate", handleUpdate);
773
- editor.off("transaction", handleUpdate);
774
- };
775
- }, [editor, types]);
776
- return activeType;
777
- }
778
- function getListTriggerIcon(activeType) {
779
- if (activeType === null) return import_lucide_react7.List;
780
- return listIcons[activeType];
781
- }
782
-
783
- // src/components/list-dropdown-menu/list-menu-item.tsx
784
- var import_jsx_runtime11 = require("react/jsx-runtime");
785
- var ListMenuItem = (0, import_react9.forwardRef)(
786
- ({ editor, listType }, ref) => {
787
- const { isActive, canToggle, handleToggle, label, Icon } = useList({
788
- editor,
789
- type: listType
790
- });
791
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
792
- DropdownMenuItem,
793
- {
794
- ref,
795
- "aria-label": label,
796
- className: "nt:data-[active-state=on]:bg-accent nt:data-[active-state=on]:text-[var(--tt-brand-color-500)]",
797
- "data-active-state": isActive ? "on" : "off",
798
- disabled: !canToggle,
799
- onSelect: handleToggle,
800
- children: [
801
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Icon, {}),
802
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: label })
803
- ]
804
- }
805
- );
806
- }
807
- );
808
- ListMenuItem.displayName = "ListMenuItem";
809
-
810
- // src/components/list-dropdown-menu/list-dropdown-menu.tsx
811
- var import_jsx_runtime12 = require("react/jsx-runtime");
812
- var ListDropdownMenu = (0, import_react10.forwardRef)(
813
- ({
814
- editor,
815
- types = ["bulletList", "orderedList", "taskList"],
816
- ...buttonProps
817
- }, ref) => {
818
- const activeType = useActiveListType(editor, types);
819
- const TriggerIcon = getListTriggerIcon(activeType);
820
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(DropdownMenu, { children: [
821
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
822
- Button,
823
- {
824
- ref,
825
- "aria-label": "List",
826
- className: "nt:gap-1 nt:px-2",
827
- "data-active-state": activeType !== null ? "on" : "off",
828
- size: "default",
829
- tabIndex: -1,
830
- type: "button",
831
- variant: "ghost",
832
- ...buttonProps,
833
- children: [
834
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
835
- TriggerIcon,
836
- {
837
- className: activeType !== null ? "nt:text-[var(--tt-brand-color-500)]" : void 0
838
- }
839
- ),
840
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react8.ChevronDown, { className: "nt:size-3" })
841
- ]
842
- }
843
- ) }),
844
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(DropdownMenuContent, { align: "start", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(DropdownMenuGroup, { children: types.map((type) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ListMenuItem, { editor, listType: type }, type)) }) })
845
- ] });
846
- }
847
- );
848
- ListDropdownMenu.displayName = "ListDropdownMenu";
849
-
850
- // src/components/mark-button/mark-button.tsx
851
- var import_react12 = require("react");
852
-
853
- // src/components/mark-button/use-mark.ts
854
- var import_lucide_react9 = require("lucide-react");
855
- var import_react11 = require("react");
856
- var markLabels = {
857
- bold: "Bold",
858
- italic: "Italic",
859
- strike: "Strikethrough",
860
- code: "Code"
861
- };
862
- var markIcons = {
863
- bold: import_lucide_react9.Bold,
864
- italic: import_lucide_react9.Italic,
865
- strike: import_lucide_react9.Strikethrough,
866
- code: import_lucide_react9.Code
867
- };
868
- function useMark({ editor, type }) {
869
- const [isActive, setIsActive] = (0, import_react11.useState)(false);
870
- const [canToggle, setCanToggle] = (0, import_react11.useState)(false);
871
- (0, import_react11.useEffect)(() => {
872
- if (!editor) return;
873
- const handleUpdate = () => {
874
- setIsActive(editor.isActive(type));
875
- setCanToggle(editor.isEditable && editor.can().toggleMark(type));
876
- };
877
- handleUpdate();
878
- editor.on("selectionUpdate", handleUpdate);
879
- editor.on("transaction", handleUpdate);
880
- return () => {
881
- editor.off("selectionUpdate", handleUpdate);
882
- editor.off("transaction", handleUpdate);
883
- };
884
- }, [editor, type]);
885
- const handleToggle = (0, import_react11.useCallback)(() => {
886
- if (!editor || !editor.isEditable) return false;
887
- return editor.chain().focus().toggleMark(type).run();
888
- }, [editor, type]);
889
- return {
890
- isActive,
891
- canToggle,
892
- handleToggle,
893
- label: markLabels[type],
894
- Icon: markIcons[type]
895
- };
896
- }
897
-
898
- // src/components/mark-button/mark-button.tsx
899
- var import_jsx_runtime13 = require("react/jsx-runtime");
900
- var MarkButton = (0, import_react12.forwardRef)(
901
- ({ editor, type, onClick, ...buttonProps }, ref) => {
902
- const { isActive, canToggle, handleToggle, label, Icon } = useMark({
903
- editor,
904
- type
905
- });
906
- const handleClick = (0, import_react12.useCallback)(
907
- (event) => {
908
- onClick?.(event);
909
- if (event.defaultPrevented) return;
910
- handleToggle();
911
- },
912
- [handleToggle, onClick]
913
- );
914
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
915
- Button,
916
- {
917
- ref,
918
- "aria-label": label,
919
- "aria-pressed": isActive,
920
- "data-active-state": isActive ? "on" : "off",
921
- disabled: !canToggle,
922
- size: "icon",
923
- tabIndex: -1,
924
- type: "button",
925
- variant: "ghost",
926
- onClick: handleClick,
927
- ...buttonProps,
928
- children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
929
- Icon,
930
- {
931
- className: isActive ? "nt:text-[var(--tt-brand-color-500)]" : void 0
932
- }
933
- )
934
- }
935
- );
936
- }
937
- );
938
- MarkButton.displayName = "MarkButton";
939
-
940
- // src/components/toolbar/toolbar.tsx
941
- var import_react13 = require("react");
942
- var import_jsx_runtime14 = require("react/jsx-runtime");
943
- var Toolbar = (0, import_react13.forwardRef)(
944
- ({ children, className, variant = "fixed", ...props }, ref) => {
945
- const classNames = ["tiptap-toolbar", className].filter(Boolean).join(" ");
946
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
947
- "div",
948
- {
949
- ref,
950
- "aria-label": "toolbar",
951
- className: classNames,
952
- "data-variant": variant,
953
- role: "toolbar",
954
- ...props,
955
- children
956
- }
957
- );
958
- }
959
- );
960
- Toolbar.displayName = "Toolbar";
961
- function ToolbarGroup({
962
- children,
963
- className,
964
- ...props
965
- }) {
966
- const classNames = ["tiptap-toolbar-group", className].filter(Boolean).join(" ");
967
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: classNames, role: "group", ...props, children });
968
- }
969
- function ToolbarSeparator({
970
- orientation = "vertical",
971
- className,
972
- ...props
973
- }) {
974
- const classNames = ["tiptap-separator", className].filter(Boolean).join(" ");
975
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
976
- "div",
977
- {
978
- "aria-orientation": orientation === "vertical" ? orientation : void 0,
979
- className: classNames,
980
- "data-orientation": orientation,
981
- role: "separator",
982
- ...props
983
- }
984
- );
985
- }
986
-
987
- // src/components/ui-primitive/spacer.tsx
988
- var import_jsx_runtime15 = require("react/jsx-runtime");
989
- function Spacer() {
990
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: { flex: 1 } });
991
- }
992
-
993
- // src/components/undo-redo-button/undo-redo-button.tsx
994
- var import_react15 = require("react");
995
-
996
- // src/components/undo-redo-button/use-undo-redo.ts
997
- var import_lucide_react10 = require("lucide-react");
998
- var import_react14 = require("react");
999
- var actionLabels = {
1000
- undo: "Undo",
1001
- redo: "Redo"
1002
- };
1003
- var actionIcons = {
1004
- undo: import_lucide_react10.Undo2,
1005
- redo: import_lucide_react10.Redo2
1006
- };
1007
- function canExecuteAction(editor, action) {
1008
- if (!editor || !editor.isEditable) return false;
1009
- return action === "undo" ? editor.can().undo() : editor.can().redo();
1010
- }
1011
- function useUndoRedo({ editor, action }) {
1012
- const [canExecute, setCanExecute] = (0, import_react14.useState)(false);
1013
- (0, import_react14.useEffect)(() => {
1014
- if (!editor) return;
1015
- const handleUpdate = () => {
1016
- setCanExecute(canExecuteAction(editor, action));
1017
- };
1018
- handleUpdate();
1019
- editor.on("transaction", handleUpdate);
1020
- return () => {
1021
- editor.off("transaction", handleUpdate);
1022
- };
1023
- }, [editor, action]);
1024
- const handleAction = (0, import_react14.useCallback)(() => {
1025
- if (!editor || !editor.isEditable) return false;
1026
- if (!canExecuteAction(editor, action)) return false;
1027
- const chain = editor.chain().focus();
1028
- return action === "undo" ? chain.undo().run() : chain.redo().run();
1029
- }, [editor, action]);
1030
- return {
1031
- canExecute,
1032
- handleAction,
1033
- label: actionLabels[action],
1034
- Icon: actionIcons[action]
1035
- };
1036
- }
1037
-
1038
- // src/components/undo-redo-button/undo-redo-button.tsx
1039
- var import_jsx_runtime16 = require("react/jsx-runtime");
1040
- var UndoRedoButton = (0, import_react15.forwardRef)(({ editor, action, onClick, ...buttonProps }, ref) => {
1041
- const { canExecute, handleAction, label, Icon } = useUndoRedo({
1042
- editor,
1043
- action
1044
- });
1045
- const handleClick = (0, import_react15.useCallback)(
1046
- (event) => {
1047
- onClick?.(event);
1048
- if (event.defaultPrevented) return;
1049
- handleAction();
1050
- },
1051
- [handleAction, onClick]
1052
- );
1053
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1054
- Button,
1055
- {
1056
- ref,
1057
- "aria-label": label,
1058
- disabled: !canExecute,
1059
- size: "icon",
1060
- tabIndex: -1,
1061
- type: "button",
1062
- variant: "ghost",
1063
- onClick: handleClick,
1064
- ...buttonProps,
1065
- children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Icon, {})
1066
- }
1067
- );
1068
- });
1069
- UndoRedoButton.displayName = "UndoRedoButton";
1070
-
1071
- // src/hooks/use-markdown-editor.ts
1072
- var import_state = require("@tiptap/pm/state");
1073
- var import_react16 = require("@tiptap/react");
1074
- var import_react17 = require("react");
1075
-
1076
- // src/extensions/shared.ts
1077
- var import_extension_list = require("@tiptap/extension-list");
1078
- var import_starter_kit = __toESM(require("@tiptap/starter-kit"), 1);
1079
- var starterKitBaseConfig = {
1080
- heading: { levels: [1, 2, 3, 4, 5, 6] },
1081
- link: {
1082
- openOnClick: false,
1083
- autolink: true
1084
- },
1085
- // Disable StarterKit's built-in list handling; use @tiptap/extension-list instead
1086
- bulletList: false,
1087
- orderedList: false,
1088
- listItem: false,
1089
- listKeymap: false
1090
- };
1091
- var sharedExtensions = [
1092
- import_starter_kit.default.configure({
1093
- ...starterKitBaseConfig,
1094
- dropcursor: false,
1095
- gapcursor: false,
1096
- undoRedo: false,
1097
- trailingNode: false
1098
- }),
1099
- import_extension_list.ListKit
1100
- ];
1101
-
1102
- // src/extensions/editor.ts
1103
- var import_extension_list2 = require("@tiptap/extension-list");
1104
- var import_starter_kit2 = __toESM(require("@tiptap/starter-kit"), 1);
1105
- var import_tiptap_markdown = require("tiptap-markdown");
1106
- var editorExtensions = [
1107
- import_starter_kit2.default.configure(starterKitBaseConfig),
1108
- import_extension_list2.ListKit,
1109
- import_tiptap_markdown.Markdown.configure({
1110
- html: false,
1111
- transformPastedText: true,
1112
- transformCopiedText: true
1113
- })
1114
- ];
1115
-
1116
- // src/hooks/use-markdown-editor.ts
1117
- function getMarkdown(storage) {
1118
- return storage.markdown.getMarkdown();
1119
- }
1120
- function useMarkdownEditor({
1121
- value,
1122
- onChange,
1123
- editable = true
1124
- }) {
1125
- const externalValue = (0, import_react17.useRef)(value);
1126
- const onChangeRef = (0, import_react17.useRef)(onChange);
1127
- onChangeRef.current = onChange;
1128
- const editor = (0, import_react16.useEditor)({
1129
- extensions: editorExtensions,
1130
- editable,
1131
- content: value,
1132
- onUpdate({ editor: editor2 }) {
1133
- const md = getMarkdown(
1134
- editor2.storage
1135
- );
1136
- externalValue.current = md;
1137
- onChangeRef.current(md);
1138
- },
1139
- onCreate({ editor: editor2 }) {
1140
- setTimeout(() => {
1141
- if (editor2.isDestroyed) return;
1142
- const { state } = editor2;
1143
- const freshState = import_state.EditorState.create({
1144
- doc: state.doc,
1145
- selection: state.selection,
1146
- plugins: state.plugins
1147
- });
1148
- editor2.view.updateState(freshState);
1149
- editor2.view.dispatch(editor2.view.state.tr);
1150
- }, 0);
1151
- }
1152
- });
1153
- (0, import_react17.useEffect)(() => {
1154
- if (!editor) return;
1155
- if (value === externalValue.current) return;
1156
- externalValue.current = value;
1157
- editor.commands.setContent(value);
1158
- }, [value, editor]);
1159
- (0, import_react17.useEffect)(() => {
1160
- if (!editor) return;
1161
- editor.setEditable(editable);
1162
- }, [editable, editor]);
1163
- return { editor };
1164
- }
1165
-
1166
- // src/notra-editor.tsx
1167
- var import_jsx_runtime17 = require("react/jsx-runtime");
1168
- function NotraEditor({
1169
- value,
1170
- onChange,
1171
- placeholder,
1172
- readOnly = false,
1173
- className
1174
- }) {
1175
- const { editor } = useMarkdownEditor({
1176
- value,
1177
- onChange,
1178
- placeholder,
1179
- editable: !readOnly
1180
- });
1181
- const classNames = ["notra", "notra-editor", className].filter(Boolean).join(" ");
1182
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: classNames, children: [
1183
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(Toolbar, { variant: "fixed", children: [
1184
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Spacer, {}),
1185
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(ToolbarGroup, { children: [
1186
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(UndoRedoButton, { action: "undo", editor }),
1187
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(UndoRedoButton, { action: "redo", editor })
1188
- ] }),
1189
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ToolbarSeparator, {}),
1190
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(ToolbarGroup, { children: [
1191
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(HeadingDropdownMenu, { editor, levels: [1, 2, 3, 4] }),
1192
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1193
- ListDropdownMenu,
1194
- {
1195
- editor,
1196
- types: ["bulletList", "orderedList", "taskList"]
1197
- }
1198
- ),
1199
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(BlockquoteButton, { editor }),
1200
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(CodeBlockButton, { editor })
1201
- ] }),
1202
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ToolbarSeparator, {}),
1203
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(ToolbarGroup, { children: [
1204
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(MarkButton, { editor, type: "bold" }),
1205
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(MarkButton, { editor, type: "italic" }),
1206
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(MarkButton, { editor, type: "strike" }),
1207
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(MarkButton, { editor, type: "code" }),
1208
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(LinkPopover, { editor })
1209
- ] }),
1210
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Spacer, {})
1211
- ] }),
1212
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_react18.EditorContent, { className: "notra-editor-content", editor })
1213
- ] });
1214
- }
1215
-
1216
- // src/notra-reader.tsx
1217
- var import_react19 = require("@tiptap/static-renderer/pm/react");
1218
-
1219
- // src/utils/markdown-to-json.ts
1220
- var import_core = require("@tiptap/core");
1221
- var import_tiptap_markdown2 = require("tiptap-markdown");
1222
- var parserExtensions = [
1223
- ...sharedExtensions,
1224
- import_tiptap_markdown2.Markdown.configure({ html: false })
1225
- ];
1226
- var parserEditor = null;
1227
- function getParserEditor() {
1228
- if (!parserEditor) {
1229
- parserEditor = new import_core.Editor({
1230
- extensions: parserExtensions,
1231
- content: ""
1232
- });
1233
- }
1234
- return parserEditor;
1235
- }
1236
- function markdownToJSON(markdown) {
1237
- const editor = getParserEditor();
1238
- editor.commands.setContent(markdown);
1239
- return editor.getJSON();
1240
- }
1241
-
1242
- // src/notra-reader.tsx
1243
- var import_jsx_runtime18 = require("react/jsx-runtime");
1244
- function NotraReader({ content, className }) {
1245
- const json = markdownToJSON(content);
1246
- const rendered = (0, import_react19.renderToReactElement)({
1247
- extensions: sharedExtensions,
1248
- content: json
1249
- });
1250
- const classNames = ["notra", "notra-reader", className].filter(Boolean).join(" ");
1251
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: classNames, children: rendered });
1252
- }
1253
-
1254
- // src/components/ui-primitive/dropdown-menu.tsx
1255
- var import_react20 = require("react");
1256
- var import_react_dom = require("react-dom");
1257
- var import_jsx_runtime19 = require("react/jsx-runtime");
1258
- function DropdownMenu2({
1259
- trigger,
1260
- children,
1261
- open: controlledOpen,
1262
- onOpenChange
1263
- }) {
1264
- const isControlled = controlledOpen !== void 0;
1265
- const [uncontrolledOpen, setUncontrolledOpen] = (0, import_react20.useState)(false);
1266
- const open = isControlled ? controlledOpen : uncontrolledOpen;
1267
- const triggerRef = (0, import_react20.useRef)(null);
1268
- const contentRef = (0, import_react20.useRef)(null);
1269
- const [position, setPosition] = (0, import_react20.useState)({ top: 0, left: 0 });
1270
- const setOpen = (value) => {
1271
- if (!isControlled) {
1272
- setUncontrolledOpen(value);
1273
- }
1274
- onOpenChange?.(value);
1275
- };
1276
- (0, import_react20.useEffect)(() => {
1277
- if (!open || !triggerRef.current) return;
1278
- const updatePosition = () => {
1279
- if (!triggerRef.current) return;
1280
- const rect = triggerRef.current.getBoundingClientRect();
1281
- setPosition({
1282
- top: rect.bottom + 4,
1283
- left: rect.left + rect.width / 2
1284
- });
1285
- };
1286
- updatePosition();
1287
- window.addEventListener("scroll", updatePosition, true);
1288
- window.addEventListener("resize", updatePosition);
1289
- return () => {
1290
- window.removeEventListener("scroll", updatePosition, true);
1291
- window.removeEventListener("resize", updatePosition);
1292
- };
1293
- }, [open]);
1294
- (0, import_react20.useEffect)(() => {
1295
- if (!open) return;
1296
- const handleMouseDown = (event) => {
1297
- const target = event.target;
1298
- if (triggerRef.current?.contains(target) || contentRef.current?.contains(target)) {
1299
- return;
1300
- }
1301
- setOpen(false);
1302
- };
1303
- document.addEventListener("mousedown", handleMouseDown);
1304
- return () => document.removeEventListener("mousedown", handleMouseDown);
1305
- }, [open]);
1306
- (0, import_react20.useEffect)(() => {
1307
- if (!open) return;
1308
- const handleKeyDown = (event) => {
1309
- if (event.key === "Escape") {
1310
- setOpen(false);
1311
- }
1312
- };
1313
- document.addEventListener("keydown", handleKeyDown);
1314
- return () => document.removeEventListener("keydown", handleKeyDown);
1315
- }, [open]);
1316
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
1317
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { ref: triggerRef, onClick: () => setOpen(!open), children: trigger }),
1318
- open && (0, import_react_dom.createPortal)(
1319
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "notra-editor", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1320
- "div",
1321
- {
1322
- ref: contentRef,
1323
- className: "tiptap-dropdown-menu-content",
1324
- "data-state": "open",
1325
- role: "menu",
1326
- style: {
1327
- position: "fixed",
1328
- top: position.top,
1329
- left: position.left
1330
- },
1331
- children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1332
- "div",
1333
- {
1334
- className: "tiptap-dropdown-menu-group",
1335
- onClick: () => setOpen(false),
1336
- children
1337
- }
1338
- )
1339
- }
1340
- ) }),
1341
- document.body
1342
- )
1343
- ] });
1344
- }
37
+ var import_notra_editor = require("./notra-editor");
38
+ var import_notra_reader = require("./notra-reader");
39
+ var import_toolbar = require("./components/toolbar/toolbar");
40
+ var import_undo_redo_button = require("./components/undo-redo-button/undo-redo-button");
41
+ var import_spacer = require("./components/ui/spacer");
42
+ var import_mark_button = require("./components/mark-button/mark-button");
43
+ var import_heading_dropdown_menu = require("./components/heading-dropdown-menu/heading-dropdown-menu");
44
+ var import_list_dropdown_menu = require("./components/list-dropdown-menu/list-dropdown-menu");
45
+ var import_blockquote_button = require("./components/blockquote-button/blockquote-button");
46
+ var import_code_block_button = require("./components/code-block-button/code-block-button");
47
+ var import_link_popover = require("./components/link-popover/link-popover");
1345
48
  // Annotate the CommonJS export names for ESM import in node:
1346
49
  0 && (module.exports = {
1347
50
  BlockquoteButton,
1348
51
  CodeBlockButton,
1349
- DropdownMenu,
1350
52
  HeadingDropdownMenu,
1351
53
  LinkPopover,
1352
54
  ListDropdownMenu,