@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,936 @@
1
+ @use "variables" as *;
2
+ @use "mixins" as *;
3
+
4
+ /* --- TABS --- */
5
+ .editor-tabs-trigger {
6
+ display: inline-flex;
7
+ align-items: center;
8
+ justify-content: center;
9
+ white-space: nowrap;
10
+ border-radius: calc(var(--radius) - 2px);
11
+ padding: 0.375rem 0.75rem;
12
+ font-size: 0.875rem;
13
+ font-weight: 500;
14
+ transition: all 0.2s;
15
+ cursor: pointer;
16
+ border: none;
17
+ background: transparent;
18
+ color: var(--muted-foreground);
19
+
20
+ @include focus-ring;
21
+
22
+ &:disabled {
23
+ pointer-events: none;
24
+ opacity: 0.5;
25
+ }
26
+
27
+ &[data-state="active"] {
28
+ background-color: var(--background);
29
+ color: var(--foreground);
30
+ @include shadow-sm;
31
+ }
32
+ }
33
+
34
+ .editor-tabs-list {
35
+ display: inline-flex;
36
+ height: 2.5rem;
37
+ align-items: center;
38
+ justify-content: center;
39
+ border-radius: var(--radius);
40
+ background-color: var(--muted);
41
+ padding: 0.25rem;
42
+ color: var(--muted-foreground);
43
+ }
44
+
45
+ .editor-tabs-content {
46
+ margin-top: 0.5rem;
47
+ @include focus-ring;
48
+ }
49
+
50
+ /* --- FLEX Component Utilities --- */
51
+ .editor-flex {
52
+ display: flex;
53
+
54
+ // Align
55
+ &--items-start { align-items: flex-start; }
56
+ &--items-center { align-items: center; }
57
+ &--items-end { align-items: flex-end; }
58
+ &--items-baseline { align-items: baseline; }
59
+ &--items-stretch { align-items: stretch; }
60
+
61
+ // Justify
62
+ &--justify-start { justify-content: flex-start; }
63
+ &--justify-center { justify-content: center; }
64
+ &--justify-end { justify-content: flex-end; }
65
+ &--justify-between { justify-content: space-between; }
66
+ &--justify-around { justify-content: space-around; }
67
+ &--justify-evenly { justify-content: space-evenly; }
68
+
69
+ // Direction
70
+ &--flex-row { flex-direction: row; }
71
+ &--flex-col { flex-direction: column; }
72
+ &--flex-column { flex-direction: column; }
73
+ &--flex-row-reverse { flex-direction: row-reverse; }
74
+ &--flex-col-reverse { flex-direction: column-reverse; }
75
+ &--flex-column-reverse { flex-direction: column-reverse; }
76
+
77
+ // Wrap
78
+ &--flex-nowrap { flex-wrap: nowrap; }
79
+ &--flex-wrap { flex-wrap: wrap; }
80
+ &--flex-wrap-reverse { flex-wrap: wrap-reverse; }
81
+ }
82
+
83
+ .editor-flex-1 {
84
+ flex: 1 1 0%;
85
+ }
86
+
87
+ .editor-w-full {
88
+ width: 100%;
89
+ }
90
+
91
+ .editor-w-14 {
92
+ width: 3.5rem;
93
+ }
94
+
95
+ .editor-w-48 {
96
+ width: 12rem;
97
+ }
98
+
99
+ .editor-w-\[200px\] {
100
+ width: 200px;
101
+ }
102
+
103
+ .editor-h-full {
104
+ height: 100%;
105
+ }
106
+
107
+ .editor-h-4 {
108
+ height: 1rem;
109
+ }
110
+
111
+ .editor-overflow-hidden {
112
+ overflow: hidden;
113
+ }
114
+
115
+ .editor-fixed {
116
+ position: fixed;
117
+ }
118
+
119
+ .editor-absolute {
120
+ position: absolute;
121
+ }
122
+
123
+ .editor-absolute-full {
124
+ position: absolute;
125
+ inset: 0;
126
+ }
127
+
128
+ .editor-relative {
129
+ position: relative;
130
+ }
131
+
132
+ .editor-relative-full {
133
+ position: relative;
134
+ width: 100%;
135
+ height: 100%;
136
+ }
137
+
138
+ .editor-inline-block {
139
+ display: inline-block;
140
+ }
141
+
142
+ .editor-block {
143
+ display: block;
144
+ }
145
+
146
+ .editor-inset-0 {
147
+ inset: 0;
148
+ }
149
+
150
+ .editor-pointer-events-none {
151
+ pointer-events: none;
152
+ }
153
+
154
+ .editor-select-none {
155
+ user-select: none;
156
+ }
157
+
158
+ .editor-text-ellipsis {
159
+ text-overflow: ellipsis;
160
+ white-space: nowrap;
161
+ overflow: hidden;
162
+ }
163
+
164
+ .editor-z-10 {
165
+ z-index: 10;
166
+ }
167
+
168
+ /* --- ROUNDED --- */
169
+ .editor-rounded-sm { border-radius: calc(var(--radius) - 4px); }
170
+ .editor-rounded-md { border-radius: calc(var(--radius) - 2px); }
171
+ .editor-rounded-lg { border-radius: var(--radius); }
172
+ .editor-rounded-full { border-radius: 9999px; }
173
+
174
+ /* --- SHADOW --- */
175
+ .editor-shadow-sm { @include shadow-sm; }
176
+ .editor-shadow-md { @include shadow-md; }
177
+ .editor-shadow-lg { @include shadow-lg; }
178
+
179
+ /* --- BACKGROUNDS --- */
180
+ .editor-bg-background { background-color: var(--background); }
181
+ .editor-bg-primary { background-color: $editor-primary-color; }
182
+ .editor-bg-muted { background-color: var(--muted); }
183
+ .editor-bg-accent { background-color: $editor-accent-color; }
184
+ .editor-bg-transparent { background-color: transparent; }
185
+ .editor-bg-none { background: none; }
186
+
187
+ /* --- MARGINS --- */
188
+ .editor-mb-2 { margin-bottom: 0.5rem; }
189
+ .editor-mb-3 { margin-bottom: 0.75rem; }
190
+ .editor-mt-1 { margin-top: 0.25rem; }
191
+ .editor-ml-auto { margin-left: auto; }
192
+ .editor-ml-4 { margin-left: 1rem; }
193
+ .editor-px-1 { padding-left: 0.25rem; padding-right: 0.25rem; }
194
+ .editor-px-8 { padding-left: 2rem; padding-right: 2rem; }
195
+ .editor-py-18 { padding-top: 18px; padding-bottom: 18px; }
196
+
197
+ /* --- SIZES --- */
198
+ .editor-h-2 { height: 0.5rem; }
199
+ .editor-w-2 { width: 0.5rem; }
200
+
201
+ /* --- POSITIONING --- */
202
+ .editor--top-2-5 { top: -0.625rem; }
203
+ .editor--right-2-5 { right: -0.625rem; }
204
+ .editor--bottom-2-5 { bottom: -0.625rem; }
205
+ .editor--left-2-5 { left: -0.625rem; }
206
+ .editor-top-1-2 { top: 50%; }
207
+ .editor-left-1-2 { left: 50%; }
208
+ .editor-translate-x-1-2 { transform: translateX(-50%); }
209
+ .editor-translate-y-1-2 { transform: translateY(-50%); }
210
+
211
+ /* --- CURSORS --- */
212
+ .editor-cursor-ns-resize { cursor: ns-resize; }
213
+ .editor-cursor-ew-resize { cursor: ew-resize; }
214
+ .editor-cursor-nesw-resize { cursor: nesw-resize; }
215
+ .editor-cursor-nwse-resize { cursor: nwse-resize; }
216
+
217
+ /* --- TEXT UTILITIES --- */
218
+ .editor-text-muted-xs {
219
+ font-size: 0.75rem;
220
+ color: var(--muted-foreground);
221
+ }
222
+
223
+ .editor-text-sm {
224
+ font-size: 0.875rem;
225
+ }
226
+
227
+ .editor-font-medium {
228
+ font-weight: 500;
229
+ }
230
+
231
+ /* --- UTILITIES --- */
232
+ .editor-text-muted-foreground { color: var(--muted-foreground); }
233
+ .editor-block { display: block; }
234
+ .editor-inline { display: inline; }
235
+ .editor-inline-block { display: inline-block; }
236
+ .editor-min-h-5 { min-height: 1.25rem; }
237
+ .editor-resize-none { resize: none; }
238
+ .editor-border-0 { border-width: 0; }
239
+ .editor-bg-transparent { background-color: transparent; }
240
+ .editor-px-2\.5 { padding-left: 0.625rem; padding-right: 0.625rem; }
241
+ .editor-py-2 { padding-top: 0.5rem; padding-bottom: 0.5rem; }
242
+ .editor-whitespace-pre-wrap { white-space: pre-wrap; }
243
+ .editor-outline-none { outline: 2px solid transparent; outline-offset: 2px; }
244
+ .editor-word-break-break-word { word-break: break-word; }
245
+ .editor-box-border { box-sizing: border-box; }
246
+ .editor-cursor-text { cursor: text; }
247
+ .editor-caret-primary { caret-color: var(--primary); }
248
+ .editor-user-select-text { user-select: text; }
249
+ .editor-cursor-default { cursor: default; }
250
+ .editor-select-text { user-select: text; }
251
+ .editor-top-0 { top: 0; }
252
+ .editor-left-0 { left: 0; }
253
+ .editor-text-ellipsis { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
254
+ .editor-opacity-30 { opacity: 0.3; }
255
+ .editor-p-1 { padding: 0.25rem; }
256
+ .editor-p-2 { padding: 0.5rem; }
257
+ .editor-px-1 { padding-left: 0.25rem; padding-right: 0.25rem; }
258
+ .editor-px-0 { padding-left: 0; padding-right: 0; }
259
+ .editor-rotate-90 { transform: rotate(90deg); }
260
+ .editor-transition-transform { transition-property: transform; transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); transition-duration: 150ms; }
261
+ .editor-shrink-0 { flex-shrink: 0; }
262
+ .editor-flex-grow { flex-grow: 1; }
263
+ .editor-flex-end { display: flex; justify-content: flex-end; align-items: center; }
264
+ .editor-ml-auto { margin-left: auto; }
265
+ .editor-ml-4 { margin-left: 1rem; }
266
+ .editor-mr-1-5 { margin-right: 0.375rem; }
267
+ .editor-mt-1 { margin-top: 0.25rem; }
268
+ .editor-mt-2 { margin-top: 0.5rem; }
269
+ .editor-mb-2 { margin-bottom: 0.5rem; }
270
+ .editor-mb-3 { margin-bottom: 0.75rem; }
271
+ .editor-gap-1 { gap: 0.25rem; }
272
+ .editor-gap-2 { gap: 0.5rem; }
273
+ .editor-items-center { align-items: center; }
274
+ .editor-justify-center { justify-content: center; }
275
+ .editor-flex-col { flex-direction: column; }
276
+ .editor-flex-wrap { flex-wrap: wrap; }
277
+ .editor-cursor-pointer { cursor: pointer; }
278
+ .editor-border { border: 1px solid var(--border); }
279
+ .editor-border-transparent { border-color: transparent; }
280
+ .editor-uppercase { text-transform: uppercase; }
281
+ .editor-transition-colors { transition-property: color, background-color, border-color, text-decoration-color, fill, stroke; transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); transition-duration: 150ms; }
282
+ .editor-animate-pulse { animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; }
283
+ .editor-whitespace-nowrap { white-space: nowrap; }
284
+ .editor-text-foreground-50 { color: color-mix(in srgb, var(--foreground), transparent 50%); }
285
+
286
+ @keyframes pulse {
287
+ 0%, 100% { opacity: 1; }
288
+ 50% { opacity: .5; }
289
+ }
290
+
291
+ .editor-flex-center-justify-py-8 {
292
+ display: flex;
293
+ align-items: center;
294
+ justify-content: center;
295
+ padding-top: 2rem;
296
+ padding-bottom: 2rem;
297
+ }
298
+
299
+ .editor-object-cover { object-fit: cover; }
300
+
301
+ .editor-sr-only {
302
+ position: absolute;
303
+ width: 1px;
304
+ height: 1px;
305
+ padding: 0;
306
+ margin: -1px;
307
+ overflow: hidden;
308
+ clip: rect(0, 0, 0, 0);
309
+ white-space: nowrap;
310
+ border-width: 0;
311
+ }
312
+
313
+ /* --- ICONS --- */
314
+ .editor-icon-xs { width: 0.75rem; height: 0.75rem; } // 12px
315
+ .editor-icon-sm { width: 1rem; height: 1rem; } // 16px
316
+ .editor-icon-md { width: 1.25rem; height: 1.25rem; } // 20px
317
+ .editor-icon-lg { width: 1.5rem; height: 1.5rem; } // 24px
318
+ .editor-icon-xl { width: 2rem; height: 2rem; } // 32px
319
+
320
+ /* --- TYPOGRAPHY --- */
321
+ .editor-typography-p {
322
+ line-height: 1.75rem;
323
+ &:not(:first-child) { margin-top: 1.5rem; }
324
+ }
325
+
326
+ .editor-typography-p-small {
327
+ font-size: 0.875rem;
328
+ font-weight: 500;
329
+ line-height: 1;
330
+ }
331
+
332
+ .editor-typography-span-small-muted {
333
+ font-size: 0.875rem;
334
+ color: var(--muted-foreground);
335
+ }
336
+
337
+ /* --- TOGGLE GROUP --- */
338
+ .editor-toggle-group {
339
+ display: flex;
340
+ flex-wrap: wrap;
341
+ align-items: center;
342
+ justify-content: center;
343
+ gap: 0.25rem;
344
+ }
345
+
346
+ .editor-toggle-group-item {
347
+ display: inline-flex;
348
+ align-items: center;
349
+ justify-content: center;
350
+ border-radius: var(--radius);
351
+ font-size: 0.875rem;
352
+ font-weight: 500;
353
+ background-color: transparent;
354
+ color: var(--foreground);
355
+ transition: all 0.2s;
356
+ cursor: pointer;
357
+ border: 1px solid transparent;
358
+ padding: 0.5rem;
359
+ line-height: 1;
360
+
361
+ &:hover {
362
+ background-color: var(--muted);
363
+ color: var(--muted-foreground);
364
+ }
365
+
366
+ &[data-state="on"] {
367
+ background-color: $editor-accent-color;
368
+ color: $editor-accent-foreground-color !important;
369
+ }
370
+
371
+ &--size-sm {
372
+ padding: 0.25rem;
373
+ font-size: 0.75rem;
374
+ }
375
+
376
+ &--size-lg {
377
+ padding: 0.75rem;
378
+ font-size: 1rem;
379
+ }
380
+
381
+ &--outline {
382
+ border-color: var(--border);
383
+ &:hover {
384
+ background-color: $editor-accent-color;
385
+ border-color: $editor-accent-color;
386
+ }
387
+ }
388
+
389
+ &:disabled {
390
+ pointer-events: none;
391
+ opacity: 0.5;
392
+ }
393
+ }
394
+
395
+ /* --- BUTTON --- */
396
+ .editor-btn {
397
+ @include flex-center-justify;
398
+ white-space: nowrap;
399
+ border-radius: var(--radius);
400
+ font-weight: 500;
401
+ transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;
402
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
403
+ transition-duration: 150ms;
404
+ @include text-sm;
405
+ @include focus-ring;
406
+ border: 1px solid var(--input); // Default border
407
+ cursor: pointer;
408
+
409
+ &:disabled {
410
+ pointer-events: none;
411
+ opacity: 0.5;
412
+ }
413
+
414
+ &[data-state="on"] {
415
+ background-color: $editor-accent-color;
416
+ color: $editor-accent-foreground-color !important;
417
+ border-color: $editor-accent-color;
418
+ }
419
+
420
+ &--default {
421
+ background-color: var(--primary);
422
+ color: var(--primary-foreground);
423
+ border-color: var(--primary);
424
+ &:hover {
425
+ background-color: color-mix(in srgb, var(--primary), black 10%);
426
+ }
427
+ }
428
+
429
+ &--destructive {
430
+ background-color: var(--destructive);
431
+ color: var(--destructive-foreground);
432
+ border-color: var(--destructive);
433
+ &:hover {
434
+ background-color: color-mix(in srgb, var(--destructive), black 10%);
435
+ }
436
+ }
437
+
438
+ &--outline {
439
+ border-color: var(--input);
440
+ background-color: var(--background);
441
+ &:hover {
442
+ background-color: $editor-accent-color;
443
+ color: $editor-accent-foreground-color;
444
+ }
445
+ }
446
+
447
+ &--secondary {
448
+ background-color: var(--secondary);
449
+ color: var(--secondary-foreground);
450
+ border-color: transparent;
451
+ &:hover {
452
+ background-color: color-mix(in srgb, var(--secondary), black 10%);
453
+ }
454
+ }
455
+
456
+ &--ghost {
457
+ background-color: transparent;
458
+ border-color: transparent;
459
+ &:hover {
460
+ background-color: $editor-accent-color;
461
+ color: $editor-accent-foreground-color;
462
+ }
463
+ }
464
+
465
+ &--link {
466
+ color: var(--primary);
467
+ text-decoration-line: underline;
468
+ text-underline-offset: 4px;
469
+ background-color: transparent;
470
+ &:hover {
471
+ text-decoration-line: underline;
472
+ }
473
+ }
474
+
475
+ /* Sizes */
476
+ &--size-default {
477
+ height: 2.25rem; /* h-9 */
478
+ padding-left: 1rem;
479
+ padding-right: 1rem;
480
+ }
481
+ &--size-sm {
482
+ height: 2rem; /* h-8 */
483
+ border-radius: calc(var(--radius) - 2px);
484
+ padding-left: 0.75rem;
485
+ padding-right: 0.75rem;
486
+ font-size: 0.75rem; /* xs */
487
+ }
488
+ &--size-md {
489
+ height: 2.25rem; /* h-9 */
490
+ width: 2.25rem; /* w-9 */
491
+ padding: 0;
492
+ }
493
+ &--size-lg {
494
+ height: 2.5rem; /* h-10 */
495
+ border-radius: calc(var(--radius) + 2px);
496
+ padding-left: 2rem;
497
+ padding-right: 2rem;
498
+ }
499
+ &--size-icon {
500
+ height: 2.25rem; /* h-9 */
501
+ width: 2.25rem; /* w-9 */
502
+ padding: 0;
503
+ }
504
+ }
505
+
506
+ /* --- BUTTON GROUP --- */
507
+ .editor-button-group {
508
+ display: flex;
509
+ flex-wrap: wrap;
510
+ align-items: center;
511
+ gap: 0.25rem;
512
+ }
513
+
514
+ /* --- SEPARATOR --- */
515
+ .editor-separator {
516
+ background-color: var(--border);
517
+ flex-shrink: 0;
518
+
519
+ &--horizontal {
520
+ height: 1px;
521
+ width: 100%;
522
+ }
523
+
524
+ &--vertical {
525
+ width: 1px;
526
+ height: 100%;
527
+ min-height: 1.5rem;
528
+ }
529
+ }
530
+
531
+ /* --- INPUT --- */
532
+ .editor-input {
533
+ display: flex;
534
+ height: 2.25rem; /* h-9 */
535
+ width: 100%;
536
+ border-radius: var(--radius);
537
+ border: 1px solid var(--input);
538
+ background-color: var(--background);
539
+ padding-left: 0.75rem;
540
+ padding-right: 0.75rem;
541
+ padding-top: 0.5rem;
542
+ padding-bottom: 0.5rem;
543
+ @include text-sm;
544
+
545
+ &::file-selector-button {
546
+ border: 0;
547
+ background-color: transparent;
548
+ font-size: 0.875rem;
549
+ font-weight: 500;
550
+ }
551
+
552
+ &::placeholder {
553
+ color: var(--muted-foreground);
554
+ }
555
+
556
+ &:focus {
557
+ border-color: var(--primary);
558
+ box-shadow: 0 0 0 2px var(--ring);
559
+ outline: none;
560
+ }
561
+
562
+ &:focus-visible {
563
+ outline: none;
564
+ box-shadow: 0 0 0 2px var(--ring), 0 0 0 4px var(--background);
565
+ }
566
+
567
+ &:disabled {
568
+ cursor: not-allowed;
569
+ opacity: 0.5;
570
+ }
571
+
572
+ &:hover:not(:disabled):not([readonly]) {
573
+ background-color: color-mix(in srgb, var(--background), black 3%);
574
+ color: black !important;
575
+ border-color: $editor-accent-color;
576
+ transform: translateY(-1px);
577
+ box-shadow: 0 2px 4px -1px rgba(0, 0, 0, 0.1);
578
+ }
579
+
580
+ /* Hide spin buttons for input[type=number] */
581
+ &::-webkit-outer-spin-button,
582
+ &::-webkit-inner-spin-button {
583
+ -webkit-appearance: none;
584
+ margin: 0;
585
+ }
586
+
587
+ &[type=number] {
588
+ -moz-appearance: textfield;
589
+ }
590
+ }
591
+
592
+ /* --- INPUT GROUP ITEM --- */
593
+ .editor-input-group-item {
594
+ &--first {
595
+ border-top-right-radius: 0;
596
+ border-bottom-right-radius: 0;
597
+ }
598
+ &--middle {
599
+ border-radius: 0;
600
+ border-left-width: 0;
601
+ }
602
+ &--last {
603
+ border-top-left-radius: 0;
604
+ border-bottom-left-radius: 0;
605
+ border-left-width: 0;
606
+ }
607
+ }
608
+
609
+ /* --- LABEL --- */
610
+ .editor-label {
611
+ @include text-sm;
612
+ font-weight: 500;
613
+ line-height: 1;
614
+
615
+ &--disabled {
616
+ cursor: not-allowed;
617
+ opacity: 0.7;
618
+ }
619
+ }
620
+
621
+ /* --- DIALOG --- */
622
+ @keyframes editor-dialog-zoom-in {
623
+ from {
624
+ opacity: 0;
625
+ transform: translate(-50%, -48%) scale(0.95);
626
+ }
627
+ to {
628
+ opacity: 1;
629
+ transform: translate(-50%, -50%) scale(1);
630
+ }
631
+ }
632
+
633
+ @keyframes editor-fade-in {
634
+ from { opacity: 0; }
635
+ to { opacity: 1; }
636
+ }
637
+
638
+ @keyframes editor-popover-zoom-in {
639
+ from {
640
+ opacity: 0;
641
+ transform: scale(0.95);
642
+ }
643
+ to {
644
+ opacity: 1;
645
+ transform: scale(1);
646
+ }
647
+ }
648
+
649
+ .editor-dialog-overlay {
650
+ position: fixed;
651
+ inset: 0;
652
+ z-index: 50;
653
+ background-color: rgba(0, 0, 0, 0.4); /* Lighter backdrop for better feel */
654
+ backdrop-filter: blur(4px);
655
+ animation: editor-fade-in 0.2s ease-out;
656
+
657
+ &[data-state="open"] {
658
+ animation: editor-fade-in 0.2s ease-out;
659
+ }
660
+ }
661
+
662
+ .editor-dialog-content {
663
+ position: fixed;
664
+ left: 50%;
665
+ top: 50%;
666
+ z-index: 51;
667
+ display: grid;
668
+ width: 100%;
669
+ max-width: 32rem; /* max-w-lg */
670
+ transform: translate(-50%, -50%);
671
+ gap: 1.5rem;
672
+ border: 1px solid var(--border);
673
+ background-color: var(--background);
674
+ padding: 1.5rem;
675
+ @include shadow-lg;
676
+ border-radius: calc(var(--radius) + 4px); /* rounded-lg */
677
+ animation: editor-dialog-zoom-in 0.2s cubic-bezier(0.16, 1, 0.3, 1);
678
+
679
+ &--lg {
680
+ max-width: 50rem;
681
+ }
682
+
683
+ &__close {
684
+ position: absolute;
685
+ right: 1rem;
686
+ top: 1rem;
687
+ border-radius: var(--radius);
688
+ opacity: 0.7;
689
+ background: transparent;
690
+ border: none;
691
+ cursor: pointer;
692
+ transition: opacity 0.2s;
693
+
694
+ &:hover {
695
+ opacity: 1;
696
+ }
697
+
698
+ @include focus-ring;
699
+ }
700
+ }
701
+
702
+ .editor-dialog-header {
703
+ display: flex;
704
+ flex-direction: column;
705
+ gap: 0.375rem; /* space-y-1.5 */
706
+ text-align: center;
707
+
708
+ @media (min-width: 640px) {
709
+ text-align: left;
710
+ }
711
+
712
+ &__title {
713
+ font-size: 1.125rem; /* text-lg */
714
+ font-weight: 600;
715
+ line-height: 1;
716
+ margin: 0;
717
+ }
718
+
719
+ &__description {
720
+ @include text-sm;
721
+ color: var(--muted-foreground);
722
+ margin: 0;
723
+ }
724
+ }
725
+
726
+ .editor-dialog-footer {
727
+ display: flex;
728
+ flex-direction: column-reverse;
729
+ gap: 0.5rem; /* sm:space-x-2 */
730
+
731
+ @media (min-width: 640px) {
732
+ flex-direction: row;
733
+ justify-content: flex-end;
734
+ }
735
+ }
736
+
737
+ /* --- POPOVER --- */
738
+ .editor-popover-content {
739
+ z-index: 50;
740
+ width: 18rem; /* w-72 */
741
+ border-radius: var(--radius);
742
+ border: 1px solid var(--border);
743
+ background-color: var(--popover);
744
+ color: var(--popover-foreground);
745
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); /* shadow-md */
746
+ padding: 1rem;
747
+ outline: none;
748
+ animation: editor-popover-zoom-in 0.1s ease-out;
749
+ }
750
+
751
+ /* --- SELECT (Native styling wrapper) --- */
752
+ .editor-select {
753
+ display: flex;
754
+ height: 2.25rem; /* h-9 */
755
+ width: 100%;
756
+ align-items: center;
757
+ justify-content: space-between;
758
+ border-radius: var(--radius);
759
+ border: 1px solid var(--input);
760
+ background-color: var(--background);
761
+ padding-left: 0.75rem;
762
+ padding-right: 0.75rem;
763
+ @include text-sm;
764
+
765
+ &:focus {
766
+ outline: none;
767
+ box-shadow: 0 0 0 2px var(--ring), 0 0 0 4px var(--background);
768
+ }
769
+
770
+ &:disabled {
771
+ cursor: not-allowed;
772
+ opacity: 0.5;
773
+ }
774
+
775
+ /* Sizes */
776
+ &--size-default {
777
+ height: 2.25rem; /* h-9 */
778
+ padding-left: 0.75rem;
779
+ padding-right: 0.75rem;
780
+ }
781
+
782
+ &--size-sm {
783
+ height: 2rem; /* h-8 */
784
+ padding-left: 0.5rem;
785
+ padding-right: 0.5rem;
786
+ font-size: 0.75rem; /* xs */
787
+ }
788
+
789
+ &--size-lg {
790
+ height: 2.5rem; /* h-10 */
791
+ padding-left: 1rem;
792
+ padding-right: 1rem;
793
+ }
794
+
795
+ &--size-icon {
796
+ height: 2.25rem; /* h-9 */
797
+ width: 2.25rem; /* w-9 */
798
+ padding: 0;
799
+ justify-content: center;
800
+
801
+ // Hide chevron if it's an icon button, or make it small overlay?
802
+ // Usually icon select trigger implies the content IS the icon.
803
+ .editor-select-icon {
804
+ display: none;
805
+ }
806
+ }
807
+
808
+ &--w-auto {
809
+ width: auto;
810
+ padding-left: 0.75rem;
811
+ padding-right: 0.75rem;
812
+ min-width: 7rem; // 112px - Ensures button isn't too narrow
813
+ justify-content: space-between; // Ensure content is spaced if it's a select
814
+ }
815
+
816
+ &--gap-sm {
817
+ gap: 0.5rem;
818
+ }
819
+ }
820
+
821
+ .editor-select-item {
822
+ position: relative;
823
+ display: flex;
824
+ width: 100%;
825
+ cursor: pointer;
826
+ user-select: none;
827
+ align-items: center;
828
+ gap: 0.5rem;
829
+ border-radius: 0.125rem; /* rounded-sm */
830
+ padding: 0.375rem 0.5rem 0.375rem 2rem; /* py-1.5 pl-8 pr-2 */
831
+ font-size: 0.875rem; /* text-sm */
832
+ outline: none;
833
+
834
+ &:hover {
835
+ background-color: $editor-accent-color;
836
+ color: $editor-accent-foreground-color;
837
+ }
838
+
839
+ &[data-selected="true"] {
840
+ background-color: $editor-accent-color;
841
+ color: $editor-accent-foreground-color;
842
+ }
843
+
844
+ &__check {
845
+ position: absolute;
846
+ left: 0.5rem; /* left-2 */
847
+ display: flex;
848
+ height: 0.875rem; /* h-3.5 */
849
+ width: 0.875rem; /* w-3.5 */
850
+ align-items: center;
851
+ justify-content: center;
852
+ }
853
+ }
854
+
855
+ .editor-select-label {
856
+ padding: 0.375rem 0.5rem 0.375rem 2rem;
857
+ font-size: 0.875rem;
858
+ font-weight: 600;
859
+ }
860
+
861
+ .editor-block-format-label {
862
+ max-width: 80px;
863
+ overflow: hidden;
864
+ text-overflow: ellipsis;
865
+ white-space: nowrap;
866
+ }
867
+
868
+ /* --- TOGGLE --- */
869
+ .editor-toggle {
870
+ display: inline-flex;
871
+ align-items: center;
872
+ justify-content: center;
873
+ border-radius: calc(var(--radius) - 2px); // rounded-md
874
+ font-size: 0.875rem; // text-sm
875
+ font-weight: 500;
876
+ transition-property: color, background-color, border-color;
877
+ transition-duration: 150ms;
878
+ background-color: transparent;
879
+ border: 1px solid transparent;
880
+ cursor: pointer;
881
+
882
+ &:hover {
883
+ background-color: $editor-accent-color;
884
+ color: $editor-accent-foreground-color;
885
+ }
886
+
887
+ &:focus-visible {
888
+ outline: none;
889
+ box-shadow: 0 0 0 2px var(--ring), 0 0 0 4px var(--background);
890
+ }
891
+
892
+ &:disabled {
893
+ pointer-events: none;
894
+ opacity: 0.5;
895
+ }
896
+
897
+ &[data-state="on"] {
898
+ background-color: $editor-accent-color;
899
+ color: $editor-accent-foreground-color !important;
900
+ }
901
+
902
+ &--outline {
903
+ border-color: var(--input);
904
+ box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05); // shadow-sm
905
+ &:hover {
906
+ background-color: color-mix(in srgb, $editor-accent-color, black 50%);
907
+ color: $editor-accent-foreground-color;
908
+ }
909
+ }
910
+
911
+ &--ghost {
912
+ &:hover {
913
+ background-color: color-mix(in srgb, $editor-accent-color, black 50%);
914
+ color: $editor-accent-foreground-color;
915
+ }
916
+ }
917
+
918
+ &--size-default {
919
+ height: 2.25rem; // h-9
920
+ padding-left: 0.75rem; // px-3
921
+ padding-right: 0.75rem;
922
+ }
923
+
924
+ &--size-sm {
925
+ height: 2rem; // h-8
926
+ padding-left: 0.5rem; // px-2
927
+ padding-right: 0.5rem;
928
+ font-size: 0.75rem; // text-xs
929
+ }
930
+
931
+ &--size-lg {
932
+ height: 2.5rem; // h-10
933
+ padding-left: 0.75rem; // px-3
934
+ padding-right: 0.75rem;
935
+ }
936
+ }