@thangph2146/lexical-editor 0.0.1

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 (183) hide show
  1. package/dist/editor-x/editor.cjs +33121 -0
  2. package/dist/editor-x/editor.cjs.map +1 -0
  3. package/dist/editor-x/editor.css +2854 -0
  4. package/dist/editor-x/editor.css.map +1 -0
  5. package/dist/editor-x/editor.d.cts +12 -0
  6. package/dist/editor-x/editor.d.ts +12 -0
  7. package/dist/editor-x/editor.js +33095 -0
  8. package/dist/editor-x/editor.js.map +1 -0
  9. package/dist/index.cjs +33210 -0
  10. package/dist/index.cjs.map +1 -0
  11. package/dist/index.css +2854 -0
  12. package/dist/index.css.map +1 -0
  13. package/dist/index.d.cts +15 -0
  14. package/dist/index.d.ts +15 -0
  15. package/dist/index.js +33183 -0
  16. package/dist/index.js.map +1 -0
  17. package/package.json +84 -0
  18. package/src/components/lexical-editor.tsx +123 -0
  19. package/src/context/editor-container-context.tsx +29 -0
  20. package/src/context/priority-image-context.tsx +7 -0
  21. package/src/context/toolbar-context.tsx +60 -0
  22. package/src/context/uploads-context.tsx +53 -0
  23. package/src/editor-hooks/use-debounce.ts +80 -0
  24. package/src/editor-hooks/use-modal.tsx +64 -0
  25. package/src/editor-hooks/use-report.ts +57 -0
  26. package/src/editor-hooks/use-update-toolbar.ts +41 -0
  27. package/src/editor-ui/broken-image.tsx +18 -0
  28. package/src/editor-ui/caption-composer.tsx +45 -0
  29. package/src/editor-ui/code-button.tsx +75 -0
  30. package/src/editor-ui/color-picker.tsx +2010 -0
  31. package/src/editor-ui/content-editable.tsx +37 -0
  32. package/src/editor-ui/hooks/use-image-caption-controls.ts +118 -0
  33. package/src/editor-ui/hooks/use-image-node-interactions.ts +245 -0
  34. package/src/editor-ui/hooks/use-responsive-image-dimensions.ts +202 -0
  35. package/src/editor-ui/image-component.tsx +321 -0
  36. package/src/editor-ui/image-placeholder.tsx +57 -0
  37. package/src/editor-ui/image-resizer.tsx +499 -0
  38. package/src/editor-ui/image-sizing.ts +120 -0
  39. package/src/editor-ui/lazy-image.tsx +136 -0
  40. package/src/editor-x/editor.tsx +117 -0
  41. package/src/editor-x/nodes.ts +79 -0
  42. package/src/editor-x/plugins.tsx +380 -0
  43. package/src/hooks/use-click-outside.ts +27 -0
  44. package/src/hooks/use-element-size.ts +54 -0
  45. package/src/hooks/use-header-height.ts +95 -0
  46. package/src/hooks/use-isomorphic-layout-effect.ts +4 -0
  47. package/src/index.ts +4 -0
  48. package/src/lib/logger.ts +6 -0
  49. package/src/lib/utils.ts +19 -0
  50. package/src/nodes/autocomplete-node.tsx +94 -0
  51. package/src/nodes/embeds/tweet-node.tsx +224 -0
  52. package/src/nodes/embeds/youtube-node.tsx +519 -0
  53. package/src/nodes/emoji-node.tsx +83 -0
  54. package/src/nodes/image-node.tsx +328 -0
  55. package/src/nodes/keyword-node.tsx +58 -0
  56. package/src/nodes/layout-container-node.tsx +128 -0
  57. package/src/nodes/layout-item-node.tsx +118 -0
  58. package/src/nodes/list-with-color-node.tsx +160 -0
  59. package/src/nodes/mention-node.ts +122 -0
  60. package/src/plugins/actions/actions-plugin.tsx +3 -0
  61. package/src/plugins/actions/character-limit-plugin.tsx +27 -0
  62. package/src/plugins/actions/clear-editor-plugin.tsx +70 -0
  63. package/src/plugins/actions/counter-character-plugin.tsx +80 -0
  64. package/src/plugins/actions/edit-mode-toggle-plugin.tsx +49 -0
  65. package/src/plugins/actions/import-export-plugin.tsx +61 -0
  66. package/src/plugins/actions/markdown-toggle-plugin.tsx +78 -0
  67. package/src/plugins/actions/max-length-plugin.tsx +59 -0
  68. package/src/plugins/actions/share-content-plugin.tsx +72 -0
  69. package/src/plugins/actions/speech-to-text-plugin.tsx +159 -0
  70. package/src/plugins/actions/tree-view-plugin.tsx +63 -0
  71. package/src/plugins/align-plugin.tsx +86 -0
  72. package/src/plugins/auto-link-plugin.tsx +34 -0
  73. package/src/plugins/autocomplete-plugin.tsx +2574 -0
  74. package/src/plugins/code-action-menu-plugin.tsx +240 -0
  75. package/src/plugins/code-highlight-plugin.tsx +22 -0
  76. package/src/plugins/component-picker-menu-plugin.tsx +427 -0
  77. package/src/plugins/context-menu-plugin.tsx +311 -0
  78. package/src/plugins/drag-drop-paste-plugin.tsx +52 -0
  79. package/src/plugins/draggable-block-plugin.tsx +50 -0
  80. package/src/plugins/embeds/auto-embed-plugin.tsx +324 -0
  81. package/src/plugins/embeds/twitter-plugin.tsx +45 -0
  82. package/src/plugins/embeds/youtube-plugin.tsx +84 -0
  83. package/src/plugins/emoji-picker-plugin.tsx +206 -0
  84. package/src/plugins/emojis-plugin.tsx +84 -0
  85. package/src/plugins/floating-link-editor-plugin.tsx +791 -0
  86. package/src/plugins/floating-text-format-plugin.tsx +710 -0
  87. package/src/plugins/images-plugin.tsx +671 -0
  88. package/src/plugins/keywords-plugin.tsx +59 -0
  89. package/src/plugins/layout-plugin.tsx +658 -0
  90. package/src/plugins/link-plugin.tsx +18 -0
  91. package/src/plugins/list-color-plugin.tsx +178 -0
  92. package/src/plugins/list-max-indent-level-plugin.tsx +85 -0
  93. package/src/plugins/mentions-plugin.tsx +714 -0
  94. package/src/plugins/picker/alignment-picker-plugin.tsx +40 -0
  95. package/src/plugins/picker/bulleted-list-picker-plugin.tsx +14 -0
  96. package/src/plugins/picker/check-list-picker-plugin.tsx +14 -0
  97. package/src/plugins/picker/code-picker-plugin.tsx +30 -0
  98. package/src/plugins/picker/columns-layout-picker-plugin.tsx +16 -0
  99. package/src/plugins/picker/component-picker-option.tsx +47 -0
  100. package/src/plugins/picker/divider-picker-plugin.tsx +14 -0
  101. package/src/plugins/picker/embeds-picker-plugin.tsx +24 -0
  102. package/src/plugins/picker/heading-picker-plugin.tsx +32 -0
  103. package/src/plugins/picker/image-picker-plugin.tsx +16 -0
  104. package/src/plugins/picker/numbered-list-picker-plugin.tsx +14 -0
  105. package/src/plugins/picker/paragraph-picker-plugin.tsx +20 -0
  106. package/src/plugins/picker/quote-picker-plugin.tsx +21 -0
  107. package/src/plugins/picker/table-picker-plugin.tsx +56 -0
  108. package/src/plugins/tab-focus-plugin.tsx +66 -0
  109. package/src/plugins/table-column-resizer-plugin.tsx +309 -0
  110. package/src/plugins/table-plugin.tsx +299 -0
  111. package/src/plugins/toolbar/block-format/block-format-data.tsx +69 -0
  112. package/src/plugins/toolbar/block-format/format-bulleted-list.tsx +40 -0
  113. package/src/plugins/toolbar/block-format/format-check-list.tsx +40 -0
  114. package/src/plugins/toolbar/block-format/format-code-block.tsx +45 -0
  115. package/src/plugins/toolbar/block-format/format-heading.tsx +34 -0
  116. package/src/plugins/toolbar/block-format/format-list-with-marker.tsx +74 -0
  117. package/src/plugins/toolbar/block-format/format-numbered-list.tsx +40 -0
  118. package/src/plugins/toolbar/block-format/format-paragraph.tsx +31 -0
  119. package/src/plugins/toolbar/block-format/format-quote.tsx +32 -0
  120. package/src/plugins/toolbar/block-format-toolbar-plugin.tsx +117 -0
  121. package/src/plugins/toolbar/block-insert/insert-columns-layout.tsx +32 -0
  122. package/src/plugins/toolbar/block-insert/insert-embeds.tsx +31 -0
  123. package/src/plugins/toolbar/block-insert/insert-horizontal-rule.tsx +30 -0
  124. package/src/plugins/toolbar/block-insert/insert-image.tsx +32 -0
  125. package/src/plugins/toolbar/block-insert/insert-table.tsx +32 -0
  126. package/src/plugins/toolbar/block-insert-plugin.tsx +30 -0
  127. package/src/plugins/toolbar/clear-formatting-toolbar-plugin.tsx +92 -0
  128. package/src/plugins/toolbar/code-language-toolbar-plugin.tsx +121 -0
  129. package/src/plugins/toolbar/element-format-toolbar-plugin.tsx +251 -0
  130. package/src/plugins/toolbar/font-background-toolbar-plugin.tsx +179 -0
  131. package/src/plugins/toolbar/font-color-toolbar-plugin.tsx +101 -0
  132. package/src/plugins/toolbar/font-family-toolbar-plugin.tsx +91 -0
  133. package/src/plugins/toolbar/font-format-toolbar-plugin.tsx +85 -0
  134. package/src/plugins/toolbar/font-size-toolbar-plugin.tsx +177 -0
  135. package/src/plugins/toolbar/history-toolbar-plugin.tsx +87 -0
  136. package/src/plugins/toolbar/link-toolbar-plugin.tsx +90 -0
  137. package/src/plugins/toolbar/subsuper-toolbar-plugin.tsx +69 -0
  138. package/src/plugins/toolbar/toolbar-plugin.tsx +66 -0
  139. package/src/plugins/typing-pref-plugin.tsx +118 -0
  140. package/src/shared/can-use-dom.ts +4 -0
  141. package/src/shared/environment.ts +47 -0
  142. package/src/shared/invariant.ts +16 -0
  143. package/src/shared/use-layout-effect.ts +12 -0
  144. package/src/themes/_mixins.scss +107 -0
  145. package/src/themes/_variables.scss +33 -0
  146. package/src/themes/editor-theme.scss +622 -0
  147. package/src/themes/editor-theme.ts +118 -0
  148. package/src/themes/plugins.scss +1180 -0
  149. package/src/themes/ui-components.scss +936 -0
  150. package/src/transformers/markdown-emoji-transformer.ts +20 -0
  151. package/src/transformers/markdown-hr-transformer.ts +28 -0
  152. package/src/transformers/markdown-image-transformer.ts +31 -0
  153. package/src/transformers/markdown-list-transformer.ts +51 -0
  154. package/src/transformers/markdown-table-transformer.ts +200 -0
  155. package/src/transformers/markdown-tweet-transformer.ts +26 -0
  156. package/src/ui/button-group.tsx +10 -0
  157. package/src/ui/button.tsx +29 -0
  158. package/src/ui/collapsible.tsx +67 -0
  159. package/src/ui/command.tsx +48 -0
  160. package/src/ui/dialog.tsx +146 -0
  161. package/src/ui/flex.tsx +38 -0
  162. package/src/ui/input.tsx +20 -0
  163. package/src/ui/label.tsx +20 -0
  164. package/src/ui/popover.tsx +128 -0
  165. package/src/ui/scroll-area.tsx +17 -0
  166. package/src/ui/select.tsx +171 -0
  167. package/src/ui/separator.tsx +20 -0
  168. package/src/ui/slider.tsx +14 -0
  169. package/src/ui/slot.tsx +3 -0
  170. package/src/ui/tabs.tsx +87 -0
  171. package/src/ui/toggle-group.tsx +109 -0
  172. package/src/ui/toggle.tsx +28 -0
  173. package/src/ui/tooltip.tsx +28 -0
  174. package/src/ui/typography.tsx +44 -0
  175. package/src/utils/doc-serialization.ts +68 -0
  176. package/src/utils/emoji-list.ts +16604 -0
  177. package/src/utils/get-dom-range-rect.ts +20 -0
  178. package/src/utils/get-selected-node.ts +20 -0
  179. package/src/utils/is-mobile-width.ts +0 -0
  180. package/src/utils/set-floating-elem-position-for-link-editor.ts +39 -0
  181. package/src/utils/set-floating-elem-position.ts +44 -0
  182. package/src/utils/swipe.ts +119 -0
  183. package/src/utils/url.ts +32 -0
@@ -0,0 +1,66 @@
1
+ "use client"
2
+
3
+ import { type CSSProperties, type ReactNode, useEffect, useState } from "react"
4
+ import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext"
5
+ import { COMMAND_PRIORITY_CRITICAL, SELECTION_CHANGE_COMMAND } from "lexical"
6
+
7
+ import { ToolbarContext } from "../../context/toolbar-context"
8
+ import { useEditorModal } from "../../editor-hooks/use-modal"
9
+ import { useHeaderHeight } from "../../hooks/use-header-height"
10
+ import { cn } from "../../lib/utils"
11
+
12
+ export function ToolbarPlugin({
13
+ children,
14
+ className,
15
+ style,
16
+ }: {
17
+ children: (props: { blockType: string }) => ReactNode
18
+ className?: string
19
+ style?: CSSProperties
20
+ }) {
21
+ const [editor] = useLexicalComposerContext()
22
+ const { headerHeight } = useHeaderHeight()
23
+
24
+ const [activeEditor, setActiveEditor] = useState(editor)
25
+ const [blockType, setBlockType] = useState<string>("paragraph")
26
+
27
+ const [modal, showModal] = useEditorModal()
28
+
29
+ const $updateToolbar = () => {}
30
+
31
+ useEffect(() => {
32
+ return activeEditor.registerCommand(
33
+ SELECTION_CHANGE_COMMAND,
34
+ (_payload, newEditor) => {
35
+ setActiveEditor(newEditor)
36
+ return false
37
+ },
38
+ COMMAND_PRIORITY_CRITICAL
39
+ )
40
+ }, [activeEditor, editor])
41
+
42
+ return (
43
+ <ToolbarContext
44
+ activeEditor={activeEditor}
45
+ $updateToolbar={$updateToolbar}
46
+ blockType={blockType}
47
+ setBlockType={setBlockType}
48
+ showModal={showModal}
49
+ >
50
+ {modal}
51
+
52
+ <div
53
+ className={cn(
54
+ "editor-toolbar",
55
+ className
56
+ )}
57
+ style={{
58
+ ...style,
59
+ top: Math.round(headerHeight),
60
+ }}
61
+ >
62
+ {children({ blockType })}
63
+ </div>
64
+ </ToolbarContext>
65
+ )
66
+ }
@@ -0,0 +1,118 @@
1
+ "use client"
2
+
3
+ /**
4
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
5
+ *
6
+ * This source code is licensed under the MIT license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ *
9
+ */
10
+ import { JSX, useEffect } from "react"
11
+
12
+ import { useReport } from "../editor-hooks/use-report"
13
+
14
+ const validInputTypes = new Set([
15
+ "insertText",
16
+ "insertCompositionText",
17
+ "insertFromComposition",
18
+ "insertLineBreak",
19
+ "insertParagraph",
20
+ "deleteCompositionText",
21
+ "deleteContentBackward",
22
+ "deleteByComposition",
23
+ "deleteContent",
24
+ "deleteContentForward",
25
+ "deleteWordBackward",
26
+ "deleteWordForward",
27
+ "deleteHardLineBackward",
28
+ "deleteSoftLineBackward",
29
+ "deleteHardLineForward",
30
+ "deleteSoftLineForward",
31
+ ])
32
+
33
+ export function TypingPerfPlugin(): JSX.Element | null {
34
+ const report = useReport()
35
+ useEffect(() => {
36
+ let start = 0
37
+ let timerId: ReturnType<typeof setTimeout> | null
38
+ let keyPressTimerId: ReturnType<typeof setTimeout> | null
39
+ let log: Array<DOMHighResTimeStamp> = []
40
+ let invalidatingEvent = false
41
+
42
+ const measureEventEnd = function logKeyPress() {
43
+ if (keyPressTimerId != null) {
44
+ if (invalidatingEvent) {
45
+ invalidatingEvent = false
46
+ } else {
47
+ log.push(performance.now() - start)
48
+ }
49
+
50
+ clearTimeout(keyPressTimerId)
51
+ keyPressTimerId = null
52
+ }
53
+ }
54
+
55
+ const measureEventStart = function measureEvent() {
56
+ if (timerId != null) {
57
+ clearTimeout(timerId)
58
+ timerId = null
59
+ }
60
+
61
+ // We use a setTimeout(0) instead of requestAnimationFrame, due to
62
+ // inconsistencies between the sequencing of rAF in different browsers.
63
+ keyPressTimerId = setTimeout(measureEventEnd, 0)
64
+ // Schedule a timer to report the results.
65
+ timerId = setTimeout(() => {
66
+ const total = log.reduce((a, b) => a + b, 0)
67
+ const reportedText =
68
+ "Typing Perf: " + Math.round((total / log.length) * 100) / 100 + "ms"
69
+ report(reportedText)
70
+ log = []
71
+ }, 2000)
72
+ // Make the time after we do the previous logic, so we don't measure the overhead
73
+ // for it all.
74
+ start = performance.now()
75
+ }
76
+
77
+ const beforeInputHandler = function beforeInputHandler(event: InputEvent) {
78
+ if (!validInputTypes.has(event.inputType) || invalidatingEvent) {
79
+ invalidatingEvent = false
80
+ return
81
+ }
82
+
83
+ measureEventStart()
84
+ }
85
+
86
+ const keyDownHandler = function keyDownHandler(event: KeyboardEvent) {
87
+ const key = event.key
88
+
89
+ if (key === "Backspace" || key === "Enter") {
90
+ measureEventStart()
91
+ }
92
+ }
93
+
94
+ const pasteHandler = function pasteHandler() {
95
+ invalidatingEvent = true
96
+ }
97
+
98
+ const cutHandler = function cutHandler() {
99
+ invalidatingEvent = true
100
+ }
101
+
102
+ window.addEventListener("keydown", keyDownHandler, true)
103
+ window.addEventListener("selectionchange", measureEventEnd, true)
104
+ window.addEventListener("beforeinput", beforeInputHandler, true)
105
+ window.addEventListener("paste", pasteHandler, true)
106
+ window.addEventListener("cut", cutHandler, true)
107
+
108
+ return () => {
109
+ window.removeEventListener("keydown", keyDownHandler, true)
110
+ window.removeEventListener("selectionchange", measureEventEnd, true)
111
+ window.removeEventListener("beforeinput", beforeInputHandler, true)
112
+ window.removeEventListener("paste", pasteHandler, true)
113
+ window.removeEventListener("cut", cutHandler, true)
114
+ }
115
+ }, [report])
116
+
117
+ return null
118
+ }
@@ -0,0 +1,4 @@
1
+ export const CAN_USE_DOM: boolean =
2
+ typeof window !== "undefined" &&
3
+ typeof window.document !== "undefined" &&
4
+ typeof window.document.createElement !== "undefined"
@@ -0,0 +1,47 @@
1
+ import { CAN_USE_DOM } from "../shared/can-use-dom"
2
+
3
+ declare global {
4
+ interface Document {
5
+ documentMode?: unknown
6
+ }
7
+
8
+ interface Window {
9
+ MSStream?: unknown
10
+ }
11
+ }
12
+
13
+ const documentMode =
14
+ CAN_USE_DOM && "documentMode" in document ? document.documentMode : null
15
+
16
+ export const IS_APPLE: boolean =
17
+ CAN_USE_DOM && /Mac|iPod|iPhone|iPad/.test(navigator.platform)
18
+
19
+ export const IS_FIREFOX: boolean =
20
+ CAN_USE_DOM && /^(?!.*Seamonkey)(?=.*Firefox).*/i.test(navigator.userAgent)
21
+
22
+ export const CAN_USE_BEFORE_INPUT: boolean =
23
+ CAN_USE_DOM && "InputEvent" in window && !documentMode
24
+ ? "getTargetRanges" in new window.InputEvent("input")
25
+ : false
26
+
27
+ export const IS_SAFARI: boolean =
28
+ CAN_USE_DOM && /Version\/[\d.]+.*Safari/.test(navigator.userAgent)
29
+
30
+ export const IS_IOS: boolean =
31
+ CAN_USE_DOM &&
32
+ /iPad|iPhone|iPod/.test(navigator.userAgent) &&
33
+ !window.MSStream
34
+
35
+ export const IS_ANDROID: boolean =
36
+ CAN_USE_DOM && /Android/.test(navigator.userAgent)
37
+
38
+ // Keep these in case we need to use them in the future.
39
+ // export const IS_WINDOWS: boolean = CAN_USE_DOM && /Win/.test(navigator.platform);
40
+ export const IS_CHROME: boolean =
41
+ CAN_USE_DOM && /^(?=.*Chrome).*/i.test(navigator.userAgent)
42
+ // export const canUseTextInputEvent: boolean = CAN_USE_DOM && 'TextEvent' in window && !documentMode;
43
+
44
+ export const IS_ANDROID_CHROME: boolean = CAN_USE_DOM && IS_ANDROID && IS_CHROME
45
+
46
+ export const IS_APPLE_WEBKIT =
47
+ CAN_USE_DOM && /AppleWebKit\/[\d.]+/.test(navigator.userAgent) && !IS_CHROME
@@ -0,0 +1,16 @@
1
+ export function invariant(
2
+ cond?: boolean,
3
+ message?: string,
4
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars -- rest args for compile-time replacement
5
+ ..._args: string[]
6
+ ): asserts cond {
7
+ if (cond) {
8
+ return
9
+ }
10
+
11
+ throw new Error(
12
+ "Internal Lexical error: invariant() is meant to be replaced at compile " +
13
+ "time. There is no runtime version. Error: " +
14
+ message
15
+ )
16
+ }
@@ -0,0 +1,12 @@
1
+ import { useEffect, useLayoutEffect } from "react"
2
+
3
+ import { CAN_USE_DOM } from "../shared/can-use-dom"
4
+
5
+ // This workaround is no longer necessary in React 19,
6
+ // but we currently support React >=17.x
7
+ // https://github.com/facebook/react/pull/26395
8
+ const useLayoutEffectImpl: typeof useLayoutEffect = CAN_USE_DOM
9
+ ? useLayoutEffect
10
+ : useEffect
11
+
12
+ export default useLayoutEffectImpl
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Editor Theme Mixins
3
+ */
4
+
5
+ @use "variables" as *;
6
+
7
+ @mixin focus-ring {
8
+ &:focus-visible {
9
+ outline: none;
10
+ box-shadow: 0 0 0 2px var(--ring), 0 0 0 4px $editor-bg-color;
11
+ }
12
+ }
13
+
14
+ @mixin text-sm {
15
+ font-size: 14px;
16
+ line-height: 20px;
17
+ }
18
+
19
+ @mixin flex-center {
20
+ display: flex;
21
+ align-items: center;
22
+ }
23
+
24
+ @mixin flex-col {
25
+ display: flex;
26
+ flex-direction: column;
27
+ }
28
+
29
+ @mixin flex-center-justify {
30
+ @include flex-center;
31
+ justify-content: center;
32
+ }
33
+
34
+ @mixin shadow-sm {
35
+ box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
36
+ }
37
+
38
+ @mixin shadow-md {
39
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
40
+ }
41
+
42
+ @mixin shadow-lg {
43
+ box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
44
+ }
45
+
46
+ @mixin shadow-xl {
47
+ box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
48
+ }
49
+
50
+ @mixin rounded-sm {
51
+ border-radius: calc($editor-border-radius - 2px);
52
+ }
53
+
54
+ @mixin rounded-md {
55
+ border-radius: $editor-border-radius;
56
+ }
57
+
58
+ @mixin rounded-lg {
59
+ border-radius: calc($editor-border-radius + 4px);
60
+ }
61
+
62
+ // --- Unified Hover Styles ---
63
+ @mixin editor-hover-base {
64
+ background-color: $editor-accent-color;
65
+ color: $editor-accent-foreground-color;
66
+ border-color: $editor-accent-color;
67
+ transform: translateY(-1px);
68
+ box-shadow: 0 2px 4px -1px rgba(0, 0, 0, 0.1);
69
+ }
70
+
71
+ @mixin editor-active-base {
72
+ transform: translateY(0);
73
+ box-shadow: none;
74
+ }
75
+
76
+ @mixin editor-button-interactive {
77
+ &:hover:not(:disabled):not([data-state="on"]) {
78
+ @include editor-hover-base;
79
+ }
80
+
81
+ &:active:not(:disabled) {
82
+ @include editor-active-base;
83
+ }
84
+ }
85
+
86
+ // Interactive mixin for dropdown/menu items
87
+ @mixin editor-dropdown-item-interactive {
88
+ &:hover, &:focus, &--selected, &[aria-selected="true"], &[data-selected="true"] {
89
+ background-color: $editor-accent-color;
90
+ color: $editor-accent-foreground-color;
91
+ border-color: $editor-border-color; // Use border color for visibility
92
+ }
93
+
94
+ &:active {
95
+ @include editor-active-base;
96
+ }
97
+ }
98
+
99
+ @keyframes spin {
100
+ from { transform: rotate(0deg); }
101
+ to { transform: rotate(360deg); }
102
+ }
103
+
104
+ @keyframes editor-fade-in {
105
+ from { opacity: 0; transform: translateY(-10px); }
106
+ to { opacity: 1; transform: translateY(0); }
107
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Editor Theme Variables
3
+ * Use these variables to customize the editor's appearance.
4
+ * All variables use !default so they can be overridden by the consumer.
5
+ */
6
+
7
+ // Typography
8
+ $editor-font-family: var(--font-inter), "Inter", ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif !default;
9
+ $editor-font-size-base: 16px !default;
10
+ $editor-line-height-base: 1.75 !default;
11
+
12
+ // Colors - Compatible with Shadcn CSS Variables
13
+ $editor-primary-color: var(--primary, #3b82f6) !default; // blue-500 fallback
14
+ $editor-link-color: #3b82f6 !default; // Fixed link color (Blue 500) to ensure consistency across apps
15
+ $editor-text-color: var(--foreground, #1f2937) !default; // gray-800 fallback
16
+ $editor-bg-color: var(--background, transparent) !default;
17
+ $editor-muted-color: var(--muted, #f3f4f6) !default; // gray-100 fallback
18
+ $editor-border-color: var(--border, #d1d5db) !default; // gray-300 fallback
19
+ $editor-quote-border-color: var(--input, #e5e7eb) !default; // gray-200 fallback
20
+ $editor-accent-color: var(--accent, #f1f5f9) !default; // slate-100 fallback
21
+ $editor-accent-foreground-color: var(--accent-foreground, #0f172a) !default; // slate-900 fallback
22
+
23
+ // Layout
24
+ $editor-border-radius: var(--radius, 8px) !default;
25
+ $editor-spacing-unit: 8px !default;
26
+
27
+ // Code
28
+ $editor-code-bg: var(--muted, #f3f4f6) !default;
29
+ $editor-code-color: var(--muted-foreground, #1f2937) !default;
30
+
31
+ // Table
32
+ $editor-table-border-color: var(--border, #d1d5db) !default;
33
+ $editor-table-header-bg: var(--muted, #f9fafb) !default; // gray-50 fallback