@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,622 @@
1
+ /**
2
+ * Editor Theme - Independent SCSS Structure
3
+ * Built for Lexical + Next.js Monorepo
4
+ */
5
+
6
+ @use "variables" as *;
7
+ @use "mixins" as *;
8
+ @use "ui-components";
9
+ @use "plugins";
10
+
11
+ // 2. Scoped Editor Styles
12
+ .editor-root-container {
13
+ // Editor Container Border (matches input style)
14
+ // border: 1px solid transparent; // Removed default border to avoid layout issues
15
+ border-radius: $editor-border-radius;
16
+ transition: all 0.2s ease-in-out;
17
+
18
+ &.editor-root-container--shadow:focus-within {
19
+ // Use box-shadow to simulate border and ring without layout shift
20
+ // 1px border simulation + 2px ring
21
+ box-shadow: 0 0 0 1px $editor-border-color, 0 0 0 3px var(--ring, rgba(59, 130, 246, 0.5));
22
+ }
23
+ }
24
+
25
+ .lexical-editor-root {
26
+ font-family: $editor-font-family !important;
27
+ font-size: $editor-font-size-base; // Set base font size for consistency
28
+ color: $editor-text-color !important;
29
+ background-color: $editor-bg-color !important;
30
+ position: relative !important;
31
+ width: 100% !important;
32
+ margin: 0 !important;
33
+ padding: 0 !important;
34
+ text-align: left !important; // Ensure consistent text alignment
35
+ box-sizing: border-box !important;
36
+
37
+ // Editor Container Border (matches input style)
38
+ // border: 1px solid transparent;
39
+ // border-radius: $editor-border-radius;
40
+ // transition: all 0.2s ease-in-out;
41
+
42
+ // &:focus-within {
43
+ // border-color: $editor-border-color !important;
44
+ // box-shadow: 0 0 0 2px var(--ring, rgba(59, 130, 246, 0.5));
45
+ // }
46
+
47
+ // 2.1 CSS Reset & Style Isolation
48
+ // Reset common elements to prevent host app styles from leaking in.
49
+ // Using specific selectors to maintain performance while ensuring isolation.
50
+ *, *::before, *::after {
51
+ box-sizing: border-box;
52
+ }
53
+
54
+ // Reset base typography and layout tags
55
+ p, ul, ol, li, span, strong, em, b, i, blockquote, h1, h2, h3, h4, h5, h6 {
56
+ margin: 0 !important;
57
+ padding: 0 !important;
58
+ border: 0 !important;
59
+ font-size: 100%; // Removed !important to allow overrides
60
+ // font: inherit !important; // Removed aggressive font reset to allow inline styles
61
+ vertical-align: baseline !important;
62
+ -webkit-font-smoothing: antialiased !important;
63
+ -moz-osx-font-smoothing: grayscale !important;
64
+ letter-spacing: normal !important; // Reset letter spacing
65
+ word-spacing: normal !important; // Reset word spacing
66
+ text-indent: 0 !important; // Reset text indentation
67
+ text-transform: none !important; // Reset text transformation
68
+ text-decoration: none !important; // Reset text decoration
69
+ line-height: inherit; // Removed !important to allow overrides
70
+ text-align: inherit; // Removed !important to allow overrides
71
+ white-space: inherit !important;
72
+ word-break: normal !important;
73
+ word-wrap: normal !important;
74
+ overflow-wrap: normal !important;
75
+ margin-inline-start: 0 !important;
76
+ margin-inline-end: 0 !important;
77
+ padding-inline-start: 0 !important;
78
+ padding-inline-end: 0 !important;
79
+ margin-block-start: 0 !important;
80
+ margin-block-end: 0 !important;
81
+ -webkit-tap-highlight-color: transparent !important;
82
+ }
83
+
84
+ // Ensure consistent list behavior
85
+ ul, ol {
86
+ list-style-position: outside !important;
87
+ list-style-type: none !important; // Default to none, will be overridden by .editor-ul/ol
88
+ }
89
+
90
+ li {
91
+ margin: 0;
92
+ padding: 0;
93
+ }
94
+
95
+ // Ensure span (Lexical text nodes) don't inherit unexpected layout properties
96
+ span[data-lexical-text="true"] {
97
+ display: inline !important;
98
+ white-space: pre-wrap !important;
99
+ word-break: break-word !important;
100
+ margin: 0 !important;
101
+ padding: 0 !important;
102
+ }
103
+
104
+ // Core Typography
105
+ .editor-paragraph {
106
+ font-size: $editor-font-size-base !important;
107
+ line-height: $editor-line-height-base !important;
108
+ margin-top: 12px !important; // Increased spacing
109
+ margin-bottom: 12px !important;
110
+
111
+ &:first-child { margin-top: 0 !important; }
112
+ }
113
+
114
+ // Headings - Improved sizes and spacing
115
+ .editor-h1 { font-size: 36px; line-height: 40px !important; font-weight: 700 !important; letter-spacing: -0.025em; margin-top: 32px !important; margin-bottom: 16px !important; }
116
+ .editor-h2 { font-size: 30px; line-height: 36px !important; font-weight: 600 !important; letter-spacing: -0.025em; margin-top: 24px !important; margin-bottom: 12px !important; border-bottom: 1px solid $editor-border-color; padding-bottom: 5px; }
117
+ .editor-h3 { font-size: 24px; line-height: 32px !important; font-weight: 600 !important; letter-spacing: -0.025em; margin-top: 24px !important; margin-bottom: 12px !important; }
118
+ .editor-h4 { font-size: 20px; line-height: 28px !important; font-weight: 600 !important; margin-top: 20px !important; margin-bottom: 8px !important; }
119
+ .editor-h5 { font-size: 18px; line-height: 28px !important; font-weight: 600 !important; margin-top: 20px !important; margin-bottom: 8px !important; }
120
+ .editor-h6 { font-size: 16px; line-height: 24px !important; font-weight: 600 !important; margin-top: 20px !important; margin-bottom: 8px !important; }
121
+
122
+ // Quote
123
+ .editor-quote {
124
+ margin: 24px 0 !important;
125
+ padding-left: 16px !important;
126
+ border-left: 4px solid $editor-quote-border-color !important;
127
+ font-style: italic !important;
128
+ color: #64748b !important; // slate-500
129
+ }
130
+
131
+ // Lists
132
+ .editor-ol {
133
+ list-style-type: decimal !important;
134
+ padding-left: 24px !important;
135
+ margin-top: 8px !important;
136
+ margin-bottom: 8px !important;
137
+
138
+ &[data-list-marker="alpha"] {
139
+ list-style-type: lower-alpha !important;
140
+ }
141
+
142
+ &[data-list-color] {
143
+ li::marker { color: var(--list-marker-color, currentColor) !important; }
144
+ }
145
+ }
146
+
147
+ .editor-ul:not(.editor-checklist) {
148
+ padding-left: 24px !important;
149
+ margin-top: 8px !important;
150
+ margin-bottom: 8px !important;
151
+
152
+ &:not([data-list-marker]) {
153
+ list-style-type: disc !important;
154
+ }
155
+
156
+ &[data-list-marker="-"] {
157
+ list-style-type: none !important;
158
+ > li::marker { content: "- " !important; }
159
+ }
160
+ &[data-list-marker="+"] {
161
+ list-style-type: none !important;
162
+ > li::marker { content: "+ " !important; }
163
+ }
164
+
165
+ &[data-list-color] {
166
+ li::marker { color: var(--list-marker-color, currentColor) !important; }
167
+ }
168
+ }
169
+
170
+ .editor-listitem {
171
+ margin-bottom: 4px !important;
172
+ line-height: 1.6 !important;
173
+ }
174
+
175
+ .editor-checklist {
176
+ list-style: none !important;
177
+ padding: 0 !important;
178
+ margin-top: 8px !important;
179
+ margin-bottom: 8px !important;
180
+ margin-left: 0 !important;
181
+ margin-right: 0 !important;
182
+ outline: none !important; // Prevent focus outline
183
+ box-shadow: none !important; // Prevent focus ring
184
+
185
+ .editor-listitem-checked,
186
+ .editor-listitem-unchecked {
187
+ display: flex; // Use Flexbox for natural alignment
188
+ align-items: flex-start; // Align icon with the first line of text
189
+ margin-left: 0;
190
+ padding: 4px 0; // Vertical padding only
191
+ list-style: none;
192
+ outline: none;
193
+ gap: 12px; // Space between icon and text
194
+
195
+ // Checkbox Icon (using ::before as the visual container)
196
+ &::before {
197
+ content: "";
198
+ width: 18px;
199
+ height: 18px;
200
+ flex-shrink: 0; // Prevent icon from shrinking
201
+ margin-top: 3px; // Optical alignment with text cap-height (approx)
202
+ cursor: pointer;
203
+ display: block;
204
+ border: 2px solid var(--list-marker-color, #{$editor-link-color}) !important;
205
+ border-radius: 4px;
206
+ box-sizing: border-box;
207
+ transition: all 0.1s ease-in-out;
208
+ background-position: center;
209
+ background-repeat: no-repeat;
210
+ background-size: 12px; // Size of the checkmark
211
+ }
212
+ }
213
+
214
+ .editor-listitem-checked {
215
+ text-decoration: line-through;
216
+ color: #64748b;
217
+
218
+ &::before {
219
+ background-color: var(--list-marker-color, #{$editor-link-color}) !important;
220
+ border-color: var(--list-marker-color, #{$editor-link-color}) !important;
221
+ // SVG Checkmark
222
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14'%3E%3Cpath fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' d='M3 7.5L5.5 10L11 4.5'/%3E%3C/svg%3E");
223
+ }
224
+
225
+ // Remove old ::after tick mark
226
+ &::after {
227
+ display: none;
228
+ }
229
+ }
230
+ }
231
+
232
+ // Remove the standalone .editor-listitem-checked/unchecked blocks if they exist elsewhere
233
+ // But wait, are they used outside .editor-checklist?
234
+ // Checklist items are only in checklists.
235
+
236
+
237
+ .editor-nested-listitem {
238
+ list-style: none;
239
+
240
+ &::before, &::after { display: none; }
241
+ }
242
+
243
+ // List Depths
244
+ $list-styles: (
245
+ 1: decimal,
246
+ 2: upper-roman,
247
+ 3: lower-roman,
248
+ 4: upper-alpha,
249
+ 5: lower-alpha
250
+ );
251
+
252
+ @each $depth, $style in $list-styles {
253
+ .editor-ol-depth-#{$depth} {
254
+ list-style-type: $style !important;
255
+ }
256
+ .editor-ul-depth-#{$depth}:not(.editor-checklist) {
257
+ &[data-list-marker="-"] {
258
+ list-style-type: none !important;
259
+ li::marker { content: "- " !important; }
260
+ }
261
+ &[data-list-marker="+"] {
262
+ list-style-type: none !important;
263
+ li::marker { content: "+ " !important; }
264
+ }
265
+ &:not([data-list-marker]) {
266
+ list-style-type: disc !important;
267
+ }
268
+ }
269
+ }
270
+
271
+ // Code Block
272
+ .editor-code {
273
+ background-color: #fcfcfc;
274
+ color: #1a1a1a;
275
+ font-family: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
276
+ display: block;
277
+ padding: 16px 16px 16px 64px;
278
+ line-height: 1.6;
279
+ font-size: 14px;
280
+ margin: 24px 0 !important;
281
+ overflow-x: auto;
282
+ border: 1px solid #e2e8f0;
283
+ position: relative;
284
+ border-radius: 8px;
285
+ tab-size: 2;
286
+ box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.05);
287
+
288
+ &:before {
289
+ content: attr(data-gutter);
290
+ position: absolute;
291
+ background-color: #f8fafc;
292
+ border-right: 1px solid #e2e8f0;
293
+ left: 0;
294
+ top: 0;
295
+ bottom: 0;
296
+ padding: 16px 12px;
297
+ color: #94a3b8;
298
+ white-space: pre-wrap;
299
+ text-align: right;
300
+ min-width: 56px;
301
+ font-variant-numeric: tabular-nums;
302
+ user-select: none;
303
+ font-size: 12px;
304
+ }
305
+ }
306
+
307
+ // Hashtag
308
+ .editor-hashtag {
309
+ background-color: rgba($editor-primary-color, 0.1);
310
+ color: $editor-primary-color;
311
+ border-bottom: 1px solid $editor-primary-color;
312
+ padding: 0 2px;
313
+ }
314
+
315
+ // Table Styles - Clean borders
316
+ .editor-table {
317
+ border-collapse: collapse;
318
+ border-spacing: 0;
319
+ width: 100%; // Fit to parent container
320
+ // min-width: 100%; // Ensure it fills at least the container (redundant with width: 100%)
321
+ table-layout: fixed; // Ensure accurate column resizing
322
+ margin: 16px 0;
323
+ // overflow-x: auto; // Removed: overflow should be handled by the container
324
+ border-radius: $editor-border-radius;
325
+ border: 1px solid $editor-border-color;
326
+
327
+ .editor-table-cell,
328
+ .editor-table-cell-header {
329
+ min-width: 0 !important;
330
+ border: 1px solid $editor-table-border-color;
331
+ padding: 8px 6px; // Further reduced padding for better data density
332
+ position: relative;
333
+ text-align: left;
334
+ vertical-align: top;
335
+ }
336
+
337
+ .editor-table-cell-header {
338
+ background-color: $editor-table-header-bg;
339
+ font-weight: 600;
340
+ color: $editor-text-color;
341
+ }
342
+
343
+ .editor-table-cell-selected {
344
+ background-color: rgba($editor-primary-color, 0.05);
345
+ }
346
+
347
+ .editor-table-cell-resizer {
348
+ position: absolute;
349
+ right: -4px;
350
+ height: 100%;
351
+ width: 8px;
352
+ cursor: ew-resize;
353
+ z-index: 10;
354
+ top: 0;
355
+ }
356
+
357
+ .editor-table-cell-resize-ruler {
358
+ display: block;
359
+ position: absolute;
360
+ width: 1px;
361
+ height: 100%;
362
+ background-color: $editor-primary-color;
363
+ top: 0;
364
+ }
365
+
366
+ .editor-table-cell-action-button-container {
367
+ display: block;
368
+ right: 4px;
369
+ top: 6px;
370
+ position: absolute;
371
+ z-index: 10;
372
+ width: 20px;
373
+ height: 20px;
374
+ }
375
+
376
+ .editor-table-cell-action-button {
377
+ background-color: #eee;
378
+ display: block;
379
+ border: 0;
380
+ border-radius: 20px;
381
+ width: 20px;
382
+ height: 20px;
383
+ color: #222;
384
+ cursor: pointer;
385
+
386
+ &:hover {
387
+ background-color: #ddd;
388
+ }
389
+ }
390
+
391
+ .editor-table-cell-editing {
392
+ box-shadow: 0 0 5px rgba(0,0,0,0.1);
393
+ border-radius: 2px;
394
+ }
395
+
396
+ .editor-table-cell-primary-selected {
397
+ border: 2px solid $editor-primary-color;
398
+ display: block;
399
+ height: calc(100% - 2px);
400
+ width: calc(100% - 2px);
401
+ position: absolute;
402
+ left: -1px;
403
+ top: -1px;
404
+ z-index: 10;
405
+ }
406
+
407
+ .editor-table-cell-sorted-indicator {
408
+ display: block;
409
+ opacity: 0.5;
410
+ position: absolute;
411
+ bottom: 0;
412
+ left: 0;
413
+ width: 100%;
414
+ height: 4px;
415
+ background-color: $editor-muted-color;
416
+ }
417
+
418
+ .editor-table-row-striping {
419
+ margin: 0;
420
+ border-top: 1px solid $editor-border-color;
421
+ padding: 0;
422
+
423
+ &:nth-child(even) {
424
+ background-color: $editor-muted-color;
425
+ }
426
+ }
427
+
428
+ .editor-table-selected {
429
+ outline: 2px solid $editor-primary-color;
430
+ }
431
+
432
+ .editor-table-selection {
433
+ background-color: transparent;
434
+ }
435
+ }
436
+
437
+ // Text Formatting
438
+ .editor-link { color: $editor-link-color; text-decoration: none; &:hover { text-decoration: underline; cursor: pointer; } }
439
+ .editor-text-bold { font-weight: 700 !important; }
440
+ .editor-text-italic { font-style: italic !important; }
441
+ .editor-text-underline { text-decoration: underline !important; }
442
+ .editor-text-strikethrough { text-decoration: line-through !important; }
443
+ .editor-text-underline-strikethrough { text-decoration: underline line-through !important; }
444
+ .editor-text-subscript { vertical-align: sub !important; font-size: 0.8em !important; }
445
+ .editor-text-superscript { vertical-align: super !important; font-size: 0.8em !important; }
446
+ .editor-text-code {
447
+ background-color: #f1f5f9;
448
+ color: #0f172a;
449
+ padding: 2px 6px;
450
+ font-family: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
451
+ font-size: 14px;
452
+ border-radius: 6px;
453
+ border: 1px solid #e2e8f0;
454
+ font-weight: 500;
455
+ }
456
+
457
+ // Text Alignment
458
+ .editor-text-align-left {
459
+ text-align: left !important;
460
+ }
461
+
462
+ .editor-text-align-center {
463
+ text-align: center !important;
464
+ }
465
+
466
+ .editor-text-align-right {
467
+ text-align: right !important;
468
+ }
469
+
470
+ .editor-text-align-justify {
471
+ text-align: justify !important;
472
+ }
473
+
474
+ // Images
475
+ .editor-image {
476
+ display: inline-block;
477
+ position: relative;
478
+ cursor: default;
479
+ user-select: none;
480
+
481
+ img {
482
+ max-width: 100%;
483
+ height: auto;
484
+ }
485
+ }
486
+
487
+ .editor-inline-image {
488
+ display: inline-block;
489
+ position: relative;
490
+ z-index: 1;
491
+
492
+ img {
493
+ max-width: 100%;
494
+ height: auto;
495
+ }
496
+ }
497
+
498
+ .editor-image-focused {
499
+ outline: 2px solid $editor-primary-color;
500
+ outline-offset: 2px;
501
+ }
502
+
503
+ .editor-image-draggable {
504
+ cursor: grab;
505
+
506
+ &:active {
507
+ cursor: grabbing;
508
+ }
509
+ }
510
+
511
+ .editor-image-caption {
512
+ display: block;
513
+ min-width: 100px;
514
+ overflow: hidden;
515
+ padding: 0;
516
+ margin-top: 8px;
517
+
518
+ &.editable {
519
+ border: 1px solid $editor-border-color;
520
+ border-radius: $editor-border-radius;
521
+ background-color: rgba(255, 255, 255, 0.9);
522
+ }
523
+
524
+ &.readonly {
525
+ border: 0;
526
+ background-color: transparent;
527
+ }
528
+ }
529
+
530
+ .editor-lazy-image-wrapper {
531
+ display: inline-block;
532
+
533
+ &.full-width {
534
+ width: 100%;
535
+ }
536
+ }
537
+
538
+ // Broken Image
539
+ .editor-broken-image-container {
540
+ display: inline-block;
541
+ width: 200px;
542
+ height: 200px;
543
+
544
+ img {
545
+ opacity: 0.2;
546
+ object-fit: contain;
547
+ }
548
+ }
549
+
550
+ // Tweet
551
+ .editor-tweet-container {
552
+ display: block;
553
+ width: 100%;
554
+ max-width: 550px;
555
+ }
556
+
557
+ // Horizontal Rule
558
+ .editor-hr {
559
+ padding: 2px;
560
+ border: none;
561
+ margin: 1em 0;
562
+ cursor: pointer;
563
+
564
+ &:after {
565
+ content: "";
566
+ display: block;
567
+ height: 2px;
568
+ background-color: $editor-border-color;
569
+ line-height: 2px;
570
+ }
571
+
572
+ &.selected {
573
+ outline: 2px solid $editor-primary-color;
574
+ user-select: none;
575
+ }
576
+ }
577
+
578
+ // Embed Block
579
+ .editor-embed-block {
580
+ user-select: none;
581
+ }
582
+
583
+ .editor-embed-block-focused {
584
+ outline: 2px solid $editor-primary-color;
585
+ }
586
+
587
+ // Autocomplete
588
+ .editor-autocomplete {
589
+ color: #9ca3af; // text-muted-foreground
590
+ }
591
+
592
+
593
+ }
594
+
595
+ .editor-content-editable {
596
+ position: relative !important;
597
+ display: block !important;
598
+ min-height: 288px !important; // min-h-72
599
+ padding: 16px 32px !important; // py-4 px-8
600
+ outline: none !important;
601
+
602
+ &:focus {
603
+ outline: none !important;
604
+ }
605
+
606
+ &--readonly {
607
+ cursor: default !important;
608
+ user-select: text !important;
609
+ }
610
+ }
611
+
612
+ .editor-placeholder {
613
+ color: var(--muted-foreground) !important;
614
+ pointer-events: none !important;
615
+ position: absolute !important;
616
+ top: 0 !important;
617
+ left: 0 !important;
618
+ overflow: hidden !important;
619
+ padding: 18px 32px !important; // py-[18px] px-8
620
+ text-overflow: ellipsis !important;
621
+ user-select: none !important;
622
+ }