@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,1180 @@
1
+ @use "variables" as *;
2
+ @use "mixins" as *;
3
+
4
+ // ==========================================
5
+ // 1. KEYFRAMES
6
+ // ==========================================
7
+
8
+ // Keyframes are now in mixins.scss as shared animations
9
+
10
+ // ==========================================
11
+ // 2. COMMON UTILITIES & SHARED COMPONENTS
12
+ // ==========================================
13
+
14
+ .editor-icon-sm {
15
+ width: 15px; // 15px
16
+ height: 15px;
17
+ }
18
+
19
+ .editor-icon-xs {
20
+ width: 14px; // 14px
21
+ height: 14px;
22
+ }
23
+
24
+ .editor-loader {
25
+ width: 24px;
26
+ height: 24px;
27
+ animation: spin 1s linear infinite;
28
+ color: var(--muted-foreground);
29
+ }
30
+
31
+ .editor-checkbox {
32
+ height: 16px; // h-4
33
+ width: 16px; // w-4
34
+ @include rounded-sm;
35
+ border: 1px solid var(--input);
36
+ cursor: pointer;
37
+
38
+ &:checked {
39
+ background-color: var(--primary);
40
+ border-color: var(--primary);
41
+ }
42
+ }
43
+
44
+ .editor-label--normal {
45
+ font-weight: 400;
46
+ cursor: pointer;
47
+ }
48
+
49
+ .editor-shrink-0 {
50
+ flex-shrink: 0;
51
+ }
52
+
53
+ .editor-flex-grow {
54
+ flex-grow: 1;
55
+ }
56
+
57
+ .editor-flex-1 {
58
+ flex: 1 1 0%;
59
+ }
60
+
61
+ .editor-flex-end {
62
+ display: flex;
63
+ justify-content: flex-end;
64
+ align-items: center;
65
+ gap: 4px;
66
+ flex-wrap: nowrap;
67
+ flex-shrink: 0;
68
+ }
69
+
70
+ .editor-flex-row-center {
71
+ display: flex;
72
+ align-items: center;
73
+ gap: 8px; // gap-2
74
+
75
+ &--pointer {
76
+ cursor: pointer;
77
+ }
78
+ }
79
+
80
+ .editor-flex-center-justify-py-8 {
81
+ display: flex;
82
+ align-items: center;
83
+ justify-content: center;
84
+ padding-top: 32px;
85
+ padding-bottom: 32px;
86
+ }
87
+
88
+ .editor-flex-col-gap-2 {
89
+ display: flex;
90
+ flex-direction: column;
91
+ gap: 8px;
92
+ }
93
+
94
+ .editor-flex-col-gap-4 {
95
+ display: flex;
96
+ flex-direction: column;
97
+ gap: 16px;
98
+ }
99
+
100
+ .editor-absolute-full {
101
+ position: absolute;
102
+ top: 0;
103
+ right: 0;
104
+ bottom: 0;
105
+ left: 0;
106
+ }
107
+
108
+ .editor-truncate {
109
+ overflow: hidden;
110
+ text-overflow: ellipsis;
111
+ white-space: nowrap;
112
+ }
113
+
114
+ .editor-object-cover {
115
+ object-fit: cover;
116
+ }
117
+
118
+ .editor-transition-transform {
119
+ transition-property: transform;
120
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
121
+ transition-duration: 150ms;
122
+ }
123
+
124
+ .editor-rotate-90 {
125
+ transform: rotate(90deg);
126
+ }
127
+
128
+ .editor-rounded-sm {
129
+ border-radius: calc(var(--radius) - 2px);
130
+ }
131
+
132
+ .editor-font-mono {
133
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
134
+ }
135
+
136
+ .editor-mb-2 {
137
+ margin-bottom: 8px;
138
+ }
139
+
140
+ .editor-mb-3 {
141
+ margin-bottom: 12px;
142
+ }
143
+
144
+ .editor-mt-1 {
145
+ margin-top: 4px;
146
+ }
147
+
148
+ .editor-ml-auto {
149
+ margin-left: auto;
150
+ }
151
+
152
+ .editor-ml-4 {
153
+ margin-left: 16px;
154
+ }
155
+
156
+ .editor-w-14 {
157
+ width: 56px;
158
+ }
159
+
160
+ .editor-w-full {
161
+ width: 100%;
162
+ }
163
+
164
+ .editor-h-full {
165
+ height: 100%;
166
+ }
167
+
168
+ // ==========================================
169
+ // 3. TOOLBAR COMPONENTS
170
+ // ==========================================
171
+
172
+ .editor-toolbar {
173
+ position: sticky;
174
+ top: 0; // Will be overridden by inline style from ToolbarPlugin
175
+ z-index: 20;
176
+ display: flex;
177
+ flex-wrap: wrap;
178
+ align-items: center;
179
+ gap: 4px; // gap-1
180
+ border-bottom: 1px solid var(--border);
181
+ border-top-left-radius: var(--radius);
182
+ border-top-right-radius: var(--radius);
183
+ background-color: white; // Ensure solid background
184
+ padding: 4px; // p-1
185
+ @include shadow-sm;
186
+ width: 100%;
187
+ overflow-x: visible;
188
+ overflow-y: visible;
189
+ white-space: normal;
190
+
191
+ @supports (backdrop-filter: blur(4px)) {
192
+ background-color: rgba(255, 255, 255, 0.8);
193
+ backdrop-filter: blur(4px);
194
+ }
195
+ }
196
+
197
+ .editor-toolbar-group {
198
+ display: flex;
199
+ flex-wrap: wrap;
200
+ align-items: center;
201
+ gap: 4px; // gap-1
202
+ padding: 4px; // p-1
203
+ border-radius: var(--radius);
204
+ }
205
+
206
+ .editor-toolbar-item {
207
+ height: 36px; // h-9
208
+ width: 36px; // w-9
209
+ padding: 0;
210
+ border: 1px solid var(--border);
211
+ border-radius: var(--radius);
212
+ background-color: var(--background);
213
+ transition: all 0.2s;
214
+
215
+ @include editor-button-interactive;
216
+
217
+ &[data-state="on"] {
218
+ background-color: $editor-accent-color;
219
+ color: $editor-accent-foreground-color !important;
220
+ border-color: $editor-accent-color;
221
+ }
222
+
223
+ &--lg {
224
+ height: 40px !important; // h-10
225
+ width: 40px !important; // w-10
226
+ }
227
+
228
+ &--w-fit {
229
+ width: fit-content;
230
+ }
231
+
232
+ &--w-auto {
233
+ width: auto;
234
+ padding-left: 8px;
235
+ padding-right: 8px;
236
+ }
237
+
238
+ &--gap-sm {
239
+ gap: 4px;
240
+ }
241
+
242
+ &--bg-background {
243
+ background-color: var(--background);
244
+ }
245
+
246
+ &--text-center {
247
+ text-align: center;
248
+ }
249
+ }
250
+
251
+ .editor-toolbar-separator {
252
+ height: 24px !important; // h-6 (standard separator height)
253
+ margin-left: 4px;
254
+ margin-right: 4px;
255
+ }
256
+
257
+ .editor-toolbar-select-trigger {
258
+ height: 36px; // h-9
259
+ width: auto;
260
+ gap: 8px; // gap-2
261
+ padding-left: 8px; // px-2
262
+ padding-right: 8px;
263
+ font-size: 12px; // text-xs
264
+ font-weight: 500;
265
+ border: 1px solid var(--border);
266
+ border-radius: var(--radius);
267
+ transition: all 0.2s;
268
+
269
+ &:hover:not(:disabled) {
270
+ @include editor-hover-base;
271
+ }
272
+
273
+ &:active:not(:disabled) {
274
+ @include editor-active-base;
275
+ }
276
+
277
+ &:focus {
278
+ box-shadow: 0 0 0 2px var(--ring);
279
+ outline: none;
280
+ }
281
+
282
+ &--w-md {
283
+ width: 160px;
284
+ }
285
+ }
286
+
287
+ .editor-toolbar-select-icon {
288
+ height: 16px; // h-4
289
+ width: 16px; // w-4
290
+ display: flex;
291
+ align-items: center;
292
+ justify-content: center;
293
+ margin-right: 8px; // mr-2
294
+ }
295
+
296
+ .editor-format-select-trigger {
297
+ width: 72px !important;
298
+ min-width: 72px !important;
299
+ flex-shrink: 0;
300
+ }
301
+
302
+ // ==========================================
303
+ // 4. FLOATING TOOLBARS & OVERLAYS
304
+ // ==========================================
305
+
306
+ @keyframes editor-floating-zoom-in {
307
+ from {
308
+ opacity: 0;
309
+ transform: scale(0.95) translateY(4px);
310
+ }
311
+ to {
312
+ opacity: 1;
313
+ transform: scale(1) translateY(0);
314
+ }
315
+ }
316
+
317
+ .editor-floating-toolbar {
318
+ background-color: rgba(var(--background-rgb, 255, 255, 255), 0.85);
319
+ backdrop-filter: blur(8px);
320
+ position: absolute;
321
+ top: 0;
322
+ left: 0;
323
+ display: flex;
324
+ max-width: 560px;
325
+ flex-wrap: wrap;
326
+ align-items: center;
327
+ gap: 4px; // gap-1
328
+ @include rounded-md;
329
+ border: 1px solid var(--border);
330
+ padding: 4px; // p-1
331
+ opacity: 0;
332
+ @include shadow-lg;
333
+ transition: opacity 200ms ease, transform 200ms ease;
334
+ will-change: transform;
335
+ z-index: 50;
336
+
337
+ &--visible {
338
+ opacity: 1;
339
+ animation: editor-floating-zoom-in 0.2s cubic-bezier(0.16, 1, 0.3, 1);
340
+ }
341
+ }
342
+
343
+ .editor-floating-text-format {
344
+ background-color: var(--background);
345
+ position: absolute;
346
+ top: 0;
347
+ left: 0;
348
+ display: flex;
349
+ align-items: center;
350
+ gap: 4px; // gap-1
351
+ @include rounded-md;
352
+ border: 1px solid var(--border);
353
+ padding: 4px; // p-1
354
+ opacity: 0;
355
+ @include shadow-lg;
356
+ transition: opacity 200ms ease, transform 200ms ease;
357
+ will-change: transform;
358
+ z-index: 50;
359
+
360
+ // Backdrop blur if supported
361
+ @supports (backdrop-filter: blur(4px)) {
362
+ background-color: rgba(var(--background-rgb, 255, 255, 255), 0.8);
363
+ backdrop-filter: blur(8px);
364
+ }
365
+
366
+ // Dark mode adjustment
367
+ .dark & {
368
+ @supports (backdrop-filter: blur(4px)) {
369
+ background-color: rgba(var(--background-rgb, 15, 15, 15), 0.8);
370
+ }
371
+ }
372
+
373
+ // Hover effect for the whole bar
374
+ &:hover {
375
+ @include shadow-xl;
376
+ }
377
+
378
+ &--visible {
379
+ opacity: 1;
380
+ animation: editor-floating-zoom-in 0.2s cubic-bezier(0.16, 1, 0.3, 1);
381
+ }
382
+
383
+ // Divider between groups
384
+ .editor-separator--vertical {
385
+ height: 20px;
386
+ width: 1px;
387
+ margin: 0 4px;
388
+ background-color: var(--border);
389
+ }
390
+
391
+ // Custom styling for buttons in floating toolbar
392
+ .editor-toggle-group-item, .editor-btn, .editor-toolbar-item {
393
+ border: none;
394
+ border-radius: calc(var(--radius, 8px) - 4px);
395
+ height: 30px; // 30px
396
+ width: 30px;
397
+ padding: 0;
398
+ background-color: transparent;
399
+ transition: all 0.2s;
400
+ display: flex;
401
+ align-items: center;
402
+ justify-content: center;
403
+
404
+ &:hover {
405
+ background-color: $editor-accent-color;
406
+ color: $editor-accent-foreground-color;
407
+ }
408
+
409
+ &[data-state="on"] {
410
+ background-color: $editor-accent-color;
411
+ color: $editor-accent-foreground-color !important;
412
+ font-weight: bold;
413
+ }
414
+
415
+ &--active {
416
+ background-color: $editor-accent-color;
417
+ color: $editor-accent-foreground-color !important;
418
+ }
419
+ }
420
+
421
+ // Group of buttons with border as requested
422
+ .editor-floating-group, .editor-floating-group--lg {
423
+ display: flex;
424
+ align-items: center;
425
+ gap: 2px;
426
+ padding: 2px;
427
+ border-radius: calc(var(--radius, 8px) - 2px);
428
+ // Remove border from inner groups to make it cleaner
429
+ border: none;
430
+ background-color: transparent;
431
+ }
432
+ }
433
+
434
+ // ==========================================
435
+ // 5. PLUGIN SPECIFIC STYLES
436
+ // ==========================================
437
+
438
+ // --- List Color Plugin ---
439
+ .editor-list-color-dialog {
440
+ padding: 8px 0;
441
+ animation: editor-fade-in 0.3s ease-out;
442
+ }
443
+
444
+ .editor-list-color-trigger {
445
+ height: 44px;
446
+ width: 100%;
447
+ display: flex;
448
+ align-items: center;
449
+ justify-content: flex-start;
450
+ gap: 12px;
451
+ @include rounded-md;
452
+ border: 1px solid var(--input);
453
+ padding: 0 16px;
454
+ background-color: var(--background);
455
+ transition: all 0.2s;
456
+ @include shadow-sm;
457
+
458
+ @include editor-button-interactive;
459
+ }
460
+
461
+ // --- Color Picker ---
462
+ .editor-color-picker-content {
463
+ display: flex;
464
+ flex-direction: column;
465
+ gap: 16px; // gap-4
466
+ padding: 16px; // p-4
467
+ }
468
+
469
+ .editor-color-picker-area {
470
+ position: relative;
471
+ height: 160px; // h-40
472
+ width: 100%;
473
+ cursor: crosshair;
474
+ touch-action: none;
475
+ @include rounded-sm;
476
+ border: 1px solid var(--border);
477
+ overflow: hidden;
478
+
479
+ &[data-disabled="true"] {
480
+ pointer-events: none;
481
+ opacity: 0.5;
482
+ }
483
+ }
484
+
485
+ .editor-slider-root {
486
+ position: relative;
487
+ display: flex;
488
+ width: 100%;
489
+ touch-action: none;
490
+ align-items: center;
491
+ user-select: none;
492
+
493
+ &[data-disabled] {
494
+ opacity: 0.5;
495
+ pointer-events: none;
496
+ }
497
+ }
498
+
499
+ .editor-slider-track {
500
+ position: relative;
501
+ height: 12px; // h-3
502
+ width: 100%;
503
+ flex-grow: 1;
504
+ overflow: hidden;
505
+ border-radius: 9999px; // rounded-full
506
+ }
507
+
508
+ .editor-slider-thumb {
509
+ display: block;
510
+ height: 16px; // size-4
511
+ width: 16px;
512
+ border-radius: 9999px; // rounded-full
513
+ border: 1px solid var(--border); // border-primary/50
514
+ background-color: var(--background);
515
+ @include shadow-sm;
516
+ transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out;
517
+
518
+ &:focus-visible {
519
+ outline: none;
520
+ box-shadow: 0 0 0 2px var(--ring);
521
+ }
522
+ }
523
+
524
+ .editor-color-swatch {
525
+ box-sizing: border-box;
526
+ height: 32px; // size-8
527
+ width: 32px;
528
+ @include rounded-sm;
529
+ border: 1px solid var(--border);
530
+ @include shadow-sm;
531
+
532
+ &--disabled {
533
+ opacity: 0.5;
534
+ }
535
+ }
536
+
537
+ .editor-color-presets {
538
+ display: flex;
539
+ align-items: center;
540
+ gap: 8px; // gap-2
541
+ width: 100%;
542
+ }
543
+
544
+ .editor-color-preset-item {
545
+ height: 32px; // h-8
546
+ padding-left: 8px; // px-2
547
+ padding-right: 8px;
548
+ flex: 1;
549
+
550
+ &__preview {
551
+ height: 12px; // size-3
552
+ width: 12px;
553
+ border-radius: 9999px;
554
+ border: 1px solid var(--border);
555
+ }
556
+
557
+ &__label {
558
+ font-family: monospace;
559
+ font-size: 12px; // text-xs
560
+ }
561
+ }
562
+
563
+ .editor-color-value-text {
564
+ color: var(--muted-foreground);
565
+ font-family: monospace;
566
+ font-size: 12px;
567
+ font-variant-numeric: tabular-nums;
568
+ }
569
+
570
+ // --- Table Plugin ---
571
+ .editor-table-dialog {
572
+ display: grid;
573
+ gap: 20px;
574
+ padding: 8px 0;
575
+ animation: editor-fade-in 0.3s ease-out;
576
+
577
+ &__group {
578
+ @include flex-col;
579
+ gap: 8px;
580
+ }
581
+
582
+ &__checkbox-group {
583
+ display: flex;
584
+ align-items: center;
585
+ gap: 12px;
586
+ margin-top: 8px;
587
+ }
588
+ }
589
+
590
+ // --- Image Plugin & Dialog Forms ---
591
+ .editor-form-grid {
592
+ display: grid;
593
+ gap: 16px;
594
+ padding-top: 16px;
595
+ padding-bottom: 16px;
596
+ }
597
+
598
+ .editor-form-item {
599
+ display: grid;
600
+ gap: 8px;
601
+ }
602
+
603
+ .editor-image-grid {
604
+ display: grid;
605
+ grid-template-columns: repeat(4, 1fr);
606
+ gap: 8px;
607
+ margin-bottom: 12px;
608
+ }
609
+
610
+ .editor-image-btn {
611
+ position: relative;
612
+ aspect-ratio: 1 / 1;
613
+ @include rounded-sm;
614
+ overflow: hidden;
615
+ border: 2px solid transparent;
616
+ transition: all 0.2s;
617
+ cursor: pointer;
618
+ padding: 0;
619
+
620
+ &--selected {
621
+ border-color: var(--primary);
622
+ box-shadow: 0 0 0 2px var(--primary), 0 0 0 4px var(--background);
623
+ }
624
+
625
+ &:hover:not(&--selected) {
626
+ border-color: color-mix(in srgb, var(--primary), transparent 50%);
627
+ }
628
+ }
629
+
630
+ .editor-folder-tree-trigger {
631
+ display: flex;
632
+ align-items: center;
633
+ gap: 8px;
634
+ width: 100%;
635
+ padding: 6px 8px;
636
+ @include rounded-sm;
637
+ transition: background-color 0.2s;
638
+ text-align: left;
639
+ border: none;
640
+ background: transparent;
641
+
642
+ &:hover {
643
+ background-color: $editor-accent-color;
644
+ color: $editor-accent-foreground-color;
645
+ }
646
+ }
647
+
648
+ .editor-tree-content {
649
+ margin-left: 16px;
650
+ margin-top: 4px;
651
+ }
652
+
653
+ .editor-empty-state {
654
+ text-align: center;
655
+ padding-top: 32px;
656
+ padding-bottom: 32px;
657
+ }
658
+
659
+ .editor-scroll-area {
660
+ max-height: 350px;
661
+ overflow-y: auto;
662
+ padding: 8px;
663
+ border: 1px solid var(--border);
664
+ @include rounded-sm;
665
+ }
666
+
667
+ .editor-tabs-list {
668
+ width: 100%;
669
+ display: flex;
670
+ }
671
+
672
+ .editor-tabs-trigger {
673
+ flex: 1;
674
+ }
675
+
676
+ // --- Image Resizer ---
677
+ .editor-image-resizer {
678
+ &-wrapper {
679
+ // Wrapper for handles if needed, or just container logic
680
+ // Currently handles are absolute, relative to image container
681
+ }
682
+
683
+ &-handle {
684
+ position: absolute;
685
+ width: 10px; // Slightly larger for better grab area
686
+ height: 10px;
687
+ background-color: $editor-primary-color; // Using editor primary color
688
+ border: 1px solid $editor-bg-color; // White border for contrast
689
+ z-index: 50; // Ensure on top of image
690
+ transition: background-color 0.2s;
691
+
692
+ &:hover {
693
+ background-color: $editor-accent-color; // Highlight on hover
694
+ }
695
+
696
+ // Directions
697
+ &--n {
698
+ top: -5px;
699
+ left: 50%;
700
+ transform: translateX(-50%);
701
+ cursor: ns-resize;
702
+ }
703
+
704
+ &--ne {
705
+ top: -5px;
706
+ right: -5px;
707
+ cursor: nesw-resize;
708
+ }
709
+
710
+ &--e {
711
+ top: 50%;
712
+ right: -5px;
713
+ transform: translateY(-50%);
714
+ cursor: ew-resize;
715
+ }
716
+
717
+ &--se {
718
+ bottom: -5px;
719
+ right: -5px;
720
+ cursor: nwse-resize;
721
+ }
722
+
723
+ &--s {
724
+ bottom: -5px;
725
+ left: 50%;
726
+ transform: translateX(-50%);
727
+ cursor: ns-resize;
728
+ }
729
+
730
+ &--sw {
731
+ bottom: -5px;
732
+ left: -5px;
733
+ cursor: nesw-resize;
734
+ }
735
+
736
+ &--w {
737
+ top: 50%;
738
+ left: -5px;
739
+ transform: translateY(-50%);
740
+ cursor: ew-resize;
741
+ }
742
+
743
+ &--nw {
744
+ top: -5px;
745
+ left: -5px;
746
+ cursor: nwse-resize;
747
+ }
748
+ }
749
+ }
750
+
751
+ // --- Layout Plugin ---
752
+ .editor-layout-dialog-grid {
753
+ display: grid;
754
+ grid-template-columns: repeat(1, minmax(0, 1fr));
755
+ gap: 0.75rem; // gap-3
756
+
757
+ @media (min-width: 768px) {
758
+ grid-template-columns: repeat(3, minmax(0, 1fr));
759
+ }
760
+ }
761
+
762
+ .editor-layout-dialog-group {
763
+ display: flex;
764
+ flex-direction: column;
765
+ gap: 0.375rem; // Slightly increased
766
+ }
767
+
768
+ .editor-layout-color-trigger {
769
+ height: 2.75rem; // h-11
770
+ width: 100%;
771
+ justify-content: flex-start;
772
+ gap: 0.5rem; // gap-2
773
+ padding-left: 0.5rem; // px-2
774
+ padding-right: 0.5rem;
775
+ font-size: 0.75rem; // text-xs
776
+ transition: all 0.2s;
777
+
778
+ &:hover:not(:disabled) {
779
+ @include editor-button-interactive;
780
+ }
781
+ }
782
+
783
+ .editor-layout-color-preview {
784
+ width: 1rem; // size-4
785
+ height: 1rem;
786
+ flex-shrink: 0;
787
+ @include rounded-sm;
788
+ border: 1px solid var(--border);
789
+ }
790
+
791
+ // --- Mentions Plugin ---
792
+ .editor-mentions-popover {
793
+ position: fixed;
794
+ z-index: 10;
795
+ width: 200px;
796
+ @include rounded-md;
797
+ @include shadow-md;
798
+ }
799
+
800
+ .editor-mentions-item {
801
+ display: flex;
802
+ align-items: center;
803
+ gap: 0.5rem; // gap-2
804
+
805
+ @include editor-dropdown-item-interactive;
806
+
807
+ &[data-selected="true"] {
808
+ background-color: $editor-accent-color;
809
+ color: $editor-accent-foreground-color;
810
+ }
811
+
812
+ &--transparent {
813
+ background-color: transparent !important;
814
+ }
815
+ }
816
+
817
+ // --- Tree View Plugin ---
818
+ .editor-tree-view-scroll-area {
819
+ background-color: var(--foreground);
820
+ color: var(--background);
821
+ height: 24rem; // h-96
822
+ overflow: hidden;
823
+ border-radius: var(--radius); // rounded-lg
824
+ padding: 0.5rem; // p-2
825
+ }
826
+
827
+ // --- Draggable Block Plugin ---
828
+ .editor-draggable-line {
829
+ background-color: var(--secondary-foreground);
830
+ pointer-events: none;
831
+ position: absolute;
832
+ top: 0;
833
+ left: 0;
834
+ height: 0.25rem; // h-1 (actually 4px usually, but h-1 is 0.25rem)
835
+ opacity: 0;
836
+ will-change: transform;
837
+ }
838
+
839
+ .editor-draggable-menu {
840
+ position: absolute;
841
+ top: 0;
842
+ left: 0;
843
+ cursor: grab;
844
+ @include rounded-sm;
845
+ padding: 0.125rem 0.25rem; // px-[1px] py-0.5 approx
846
+ opacity: 0;
847
+ will-change: transform;
848
+
849
+ &:hover {
850
+ background-color: #f3f4f6; // hover:bg-gray-100
851
+ }
852
+
853
+ &:active {
854
+ cursor: grabbing;
855
+ }
856
+ }
857
+
858
+ // --- Auto Embed Plugin ---
859
+ .editor-auto-embed-menu {
860
+ width: 200px;
861
+ padding: 0;
862
+ }
863
+
864
+ .editor-auto-embed-wrapper {
865
+ transform: translateY(-100%);
866
+ }
867
+
868
+ // --- Floating Link Editor ---
869
+ .editor-floating-link-editor {
870
+ display: flex;
871
+ position: absolute;
872
+ top: 0;
873
+ left: 0;
874
+ z-index: 50;
875
+ max-width: 400px;
876
+ width: 100%;
877
+ opacity: 0;
878
+ background-color: var(--background);
879
+ @include rounded-md;
880
+ border: 1px solid var(--border);
881
+ @include shadow-lg;
882
+ transition: opacity 0.2s;
883
+ will-change: transform;
884
+
885
+ &__input-container {
886
+ display: flex;
887
+ align-items: center;
888
+ gap: 0.25rem;
889
+ padding: 0.25rem;
890
+ width: 100%;
891
+ }
892
+
893
+ &__view-container {
894
+ display: flex;
895
+ align-items: center;
896
+ justify-content: space-between;
897
+ gap: 0.5rem;
898
+ padding: 0.25rem 0.25rem 0.25rem 0.75rem;
899
+ width: 100%;
900
+ }
901
+
902
+ &__link {
903
+ display: block;
904
+ flex-grow: 1;
905
+ overflow: hidden;
906
+ text-overflow: ellipsis;
907
+ white-space: nowrap;
908
+ color: var(--primary);
909
+ font-size: 0.875rem;
910
+ text-decoration: none;
911
+
912
+ &:hover {
913
+ text-decoration: underline;
914
+ }
915
+ }
916
+ }
917
+
918
+ // ==========================================
919
+ // 6. MENUS & PICKERS
920
+ // ==========================================
921
+
922
+ .editor-component-picker-menu {
923
+ position: fixed;
924
+ z-index: 100;
925
+ width: 250px;
926
+ @include rounded-md;
927
+ border: 1px solid var(--border);
928
+ background-color: var(--popover);
929
+ color: var(--popover-foreground);
930
+ @include shadow-lg;
931
+ overflow: hidden;
932
+
933
+ // Base visibility
934
+ visibility: visible;
935
+ opacity: 1;
936
+ max-height: 300px;
937
+ }
938
+
939
+ .editor-command {
940
+ display: flex;
941
+ height: 100%;
942
+ width: 100%;
943
+ flex-direction: column;
944
+ overflow: hidden;
945
+ border-radius: inherit;
946
+ }
947
+
948
+ .editor-command-list {
949
+ max-height: 300px;
950
+ overflow-y: auto;
951
+ overflow-x: hidden;
952
+ padding: 0.25rem;
953
+ }
954
+
955
+ .editor-command-group {
956
+ overflow: hidden;
957
+ color: var(--foreground);
958
+
959
+ & > [cmdk-group-heading] {
960
+ padding: 0.5rem 0.5rem 0.2rem;
961
+ font-size: 0.75rem;
962
+ font-weight: 500;
963
+ color: var(--muted-foreground);
964
+ }
965
+ }
966
+
967
+ .editor-command-item {
968
+ position: relative;
969
+ display: flex;
970
+ cursor: pointer;
971
+ user-select: none;
972
+ align-items: center;
973
+ border-radius: 0.125rem; // rounded-sm
974
+ padding: 0.375rem 0.5rem; // py-1.5 px-2
975
+ border: 1px solid transparent; // Added for hover border
976
+ font-size: 0.875rem; // text-sm
977
+ outline: none;
978
+ gap: 0.5rem;
979
+
980
+ @include editor-dropdown-item-interactive;
981
+
982
+ &[data-disabled="true"] {
983
+ pointer-events: none;
984
+ opacity: 0.5;
985
+ }
986
+
987
+ svg {
988
+ width: 1rem;
989
+ height: 1rem;
990
+ flex-shrink: 0;
991
+ }
992
+ }
993
+
994
+ .editor-context-menu {
995
+ background-color: var(--popover);
996
+ color: var(--popover-foreground);
997
+ z-index: 50 !important;
998
+ overflow: hidden;
999
+ @include rounded-md;
1000
+ border: 1px solid var(--border);
1001
+ @include shadow-md;
1002
+ outline: none;
1003
+
1004
+ &:has(*) {
1005
+ z-index: 10 !important;
1006
+ }
1007
+ }
1008
+
1009
+ .editor-context-menu-item {
1010
+ position: relative;
1011
+ width: 100%;
1012
+ display: flex;
1013
+ cursor: default;
1014
+ align-items: center;
1015
+ gap: 0.5rem; // gap-2
1016
+ border-radius: calc(var(--radius) - 2px); // rounded-sm
1017
+ padding: 0.375rem 0.5rem; // py-1.5 px-2
1018
+ border: 1px solid transparent; // Added for hover border
1019
+ font-size: 0.875rem; // text-sm
1020
+ outline: none;
1021
+ user-select: none;
1022
+
1023
+ @include editor-dropdown-item-interactive;
1024
+
1025
+ &[data-disabled="true"] {
1026
+ pointer-events: none;
1027
+ opacity: 0.5;
1028
+ }
1029
+ }
1030
+
1031
+ .editor-context-menu-separator {
1032
+ background-color: var(--border);
1033
+ margin-left: -0.25rem; // -mx-1
1034
+ margin-right: -0.25rem;
1035
+ height: 1px;
1036
+ }
1037
+
1038
+ .editor-actions-bar {
1039
+ clear: both;
1040
+ display: flex;
1041
+ width: 100%;
1042
+ align-items: center;
1043
+ justify-content: space-between;
1044
+ gap: 0.75rem; // gap-3
1045
+ overflow-x: auto;
1046
+ flex-wrap: nowrap;
1047
+ border-top: 1px solid var(--border);
1048
+ padding: 0.375rem 0.75rem; // py-1.5 px-3
1049
+ background-color: color-mix(in srgb, var(--background), transparent 50%);
1050
+ backdrop-filter: blur(8px);
1051
+
1052
+ &::-webkit-scrollbar {
1053
+ display: none;
1054
+ }
1055
+ -ms-overflow-style: none;
1056
+ scrollbar-width: none;
1057
+
1058
+ // Ẩn nội dung tooltip mặc định trong actions bar nếu nó đang bị hiển thị sai
1059
+ .editor-tooltip-content {
1060
+ display: none !important;
1061
+ }
1062
+
1063
+ // Chỉ hiển thị tooltip khi hover vào trigger
1064
+ .editor-tooltip-group:hover .editor-tooltip-content {
1065
+ display: block !important;
1066
+ position: absolute;
1067
+ bottom: 100%;
1068
+ left: 50%;
1069
+ transform: translateX(-50%);
1070
+ margin-bottom: 0.5rem;
1071
+ background: var(--popover);
1072
+ color: var(--popover-foreground);
1073
+ padding: 0.25rem 0.5rem;
1074
+ border-radius: 0.25rem;
1075
+ font-size: 0.75rem;
1076
+ white-space: nowrap;
1077
+ border: 1px solid var(--border);
1078
+ box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1);
1079
+ z-index: 50;
1080
+ pointer-events: none;
1081
+ }
1082
+ }
1083
+
1084
+ // ==========================================
1085
+ // 7. INPUTS & BUTTON VARIANTS
1086
+ // ==========================================
1087
+
1088
+ .editor-input {
1089
+ &:hover:not(:disabled):not([readonly]) {
1090
+ @include editor-hover-base;
1091
+ background-color: color-mix(in srgb, var(--background), black 3%);
1092
+ }
1093
+
1094
+ &:focus {
1095
+ border-color: var(--primary);
1096
+ box-shadow: 0 0 0 2px var(--ring);
1097
+ outline: none;
1098
+ }
1099
+ }
1100
+
1101
+ .editor-input-lg {
1102
+ height: 2.75rem; // h-11
1103
+ width: 100%;
1104
+ }
1105
+
1106
+ .editor-input-wrapper {
1107
+ display: flex;
1108
+ align-items: center;
1109
+ }
1110
+
1111
+ .editor-input-group-item {
1112
+ height: 2rem; // h-8
1113
+
1114
+ // Reset number input arrows
1115
+ &::-webkit-inner-spin-button,
1116
+ &::-webkit-outer-spin-button {
1117
+ -webkit-appearance: none;
1118
+ margin: 0;
1119
+ }
1120
+ -moz-appearance: textfield;
1121
+
1122
+ &--first {
1123
+ border-top-right-radius: 0;
1124
+ border-bottom-right-radius: 0;
1125
+ }
1126
+ &--middle {
1127
+ border-radius: 0;
1128
+ border-left: 0;
1129
+ margin-inline-start: -1px;
1130
+ }
1131
+ &--last {
1132
+ border-top-left-radius: 0;
1133
+ border-bottom-left-radius: 0;
1134
+ border-left: 0;
1135
+ margin-inline-start: -1px;
1136
+ }
1137
+ }
1138
+
1139
+ // Hover styles for all button types
1140
+ .editor-btn {
1141
+ @include editor-button-interactive;
1142
+ }
1143
+
1144
+ .editor-btn--ghost,
1145
+ .editor-btn--outline {
1146
+ @include editor-button-interactive;
1147
+ }
1148
+
1149
+ .editor-btn-icon-lg {
1150
+ height: 2.5rem !important; // h-10
1151
+ min-height: 2.5rem !important;
1152
+ width: 2.5rem !important; // w-10
1153
+ }
1154
+
1155
+ .editor-btn-icon-md {
1156
+ height: 2.25rem; // h-9
1157
+ width: 2.25rem;
1158
+ }
1159
+
1160
+ // Toggle group items hover
1161
+ .editor-toggle-group-item {
1162
+ @include editor-button-interactive;
1163
+
1164
+ &[data-state="on"]:hover {
1165
+ @include editor-hover-base;
1166
+ background-color: color-mix(in srgb, $editor-accent-color, black 10%);
1167
+ border-color: $editor-accent-color;
1168
+ }
1169
+ }
1170
+
1171
+ // Toggle button hover
1172
+ .editor-toggle {
1173
+ @include editor-button-interactive;
1174
+
1175
+ &[data-state="on"]:hover {
1176
+ @include editor-hover-base;
1177
+ background-color: color-mix(in srgb, $editor-accent-color, black 10%);
1178
+ border-color: $editor-accent-color;
1179
+ }
1180
+ }