notra-editor 0.7.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "notra-editor",
3
3
  "type": "module",
4
- "version": "0.7.0",
4
+ "version": "0.8.0",
5
5
  "description": "A Markdown-first rich text editor for React",
6
6
  "license": "MIT",
7
7
  "keywords": [
@@ -23,7 +23,6 @@
23
23
  "default": "./dist/index.cjs"
24
24
  }
25
25
  },
26
- "./themes/default/shared.css": "./dist/themes/default/shared.css",
27
26
  "./themes/default/editor.css": "./dist/themes/default/editor.css",
28
27
  "./themes/default/reader.css": "./dist/themes/default/reader.css",
29
28
  "./styles/globals.css": "./dist/styles/globals.css"
@@ -71,6 +70,7 @@
71
70
  "postcss-cli": "^11.0.1",
72
71
  "react": "^19.2.0",
73
72
  "react-dom": "^19.2.0",
73
+ "sass": "^1.99.0",
74
74
  "shadcn": "^4.6.0",
75
75
  "tailwindcss": "^4.2.4",
76
76
  "tsup": "^8.4.0",
@@ -80,7 +80,7 @@
80
80
  },
81
81
  "scripts": {
82
82
  "build": "tsup && pnpm build:css",
83
- "build:css": "postcss src/styles/globals.css -o dist/styles/globals.css",
83
+ "build:css": "sass --no-source-map --style=expanded src/themes/default/editor.scss:dist/themes/default/editor.css src/themes/default/reader.scss:dist/themes/default/reader.css && postcss src/styles/globals.css -o dist/styles/globals.css",
84
84
  "dev": "tsup --watch",
85
85
  "test": "vitest run --passWithNoTests",
86
86
  "test:watch": "vitest",
@@ -1,609 +0,0 @@
1
- /* =====================
2
- CSS Custom Properties
3
- ===================== */
4
- .notra {
5
- --notra-font-body: 'DM Sans', system-ui, -apple-system, sans-serif;
6
- --notra-font-mono: 'JetBrains Mono NL', ui-monospace, 'SF Mono', monospace;
7
- --notra-font-size: 1rem;
8
- --notra-line-height: 1.6;
9
-
10
- /* Light mode colors */
11
- --notra-color-text: rgba(29, 30, 32, 0.98);
12
- --notra-color-bg: #ffffff;
13
- --notra-color-border: rgba(37, 39, 45, 0.1);
14
- --notra-color-link: rgba(98, 41, 255, 1);
15
-
16
- /* Code */
17
- --notra-code-bg: rgba(15, 22, 36, 0.05);
18
- --notra-code-text: rgba(35, 37, 42, 0.87);
19
- --notra-code-border: rgba(37, 39, 45, 0.1);
20
- --notra-codeblock-bg: rgba(56, 56, 56, 0.04);
21
- --notra-codeblock-text: rgba(30, 32, 36, 0.95);
22
- --notra-codeblock-border: rgba(37, 39, 45, 0.1);
23
-
24
- /* Blockquote */
25
- --notra-blockquote-bar: rgba(29, 30, 32, 0.98);
26
-
27
- /* Horizontal rule */
28
- --notra-hr-color: rgba(37, 39, 45, 0.1);
29
-
30
- /* Task list */
31
- --notra-checklist-bg: rgba(15, 22, 36, 0.05);
32
- --notra-checklist-bg-active: rgba(29, 30, 32, 0.98);
33
- --notra-checklist-border: rgba(37, 39, 45, 0.1);
34
- --notra-checklist-border-active: rgba(29, 30, 32, 0.98);
35
- --notra-checklist-check-color: #ffffff;
36
- --notra-checklist-text-active: rgba(52, 55, 60, 0.64);
37
-
38
- --notra-radius: 6px;
39
- }
40
-
41
- /* =====================
42
- Dark Mode Overrides
43
- ===================== */
44
- .dark .notra {
45
- /* Dark mode colors */
46
- --notra-color-text: rgba(255, 255, 255, 0.96);
47
- --notra-color-bg: rgba(14, 14, 17, 1);
48
- --notra-color-border: rgba(238, 238, 246, 0.11);
49
- --notra-color-link: rgba(122, 82, 255, 1);
50
-
51
- /* Code */
52
- --notra-code-bg: rgba(231, 231, 243, 0.07);
53
- --notra-code-text: rgba(251, 251, 254, 0.75);
54
- --notra-code-border: rgba(238, 238, 246, 0.11);
55
- --notra-codeblock-bg: rgba(232, 232, 253, 0.05);
56
- --notra-codeblock-text: rgba(253, 253, 253, 0.88);
57
- --notra-codeblock-border: rgba(238, 238, 246, 0.11);
58
-
59
- /* Blockquote */
60
- --notra-blockquote-bar: rgba(245, 245, 245, 1);
61
-
62
- /* Horizontal rule */
63
- --notra-hr-color: rgba(238, 238, 246, 0.11);
64
-
65
- /* Task list */
66
- --notra-checklist-bg: rgba(231, 231, 243, 0.07);
67
- --notra-checklist-bg-active: rgba(255, 255, 255, 0.96);
68
- --notra-checklist-border: rgba(238, 238, 246, 0.11);
69
- --notra-checklist-border-active: rgba(255, 255, 255, 0.96);
70
- --notra-checklist-check-color: rgba(14, 14, 17, 1);
71
- --notra-checklist-text-active: rgba(236, 238, 253, 0.5);
72
- }
73
-
74
- /* =====================
75
- Base Typography
76
- ===================== */
77
- .notra .tiptap,
78
- .notra-reader {
79
- font-family: var(--notra-font-body);
80
- font-size: var(--notra-font-size);
81
- line-height: var(--notra-line-height);
82
- color: var(--notra-color-text);
83
- }
84
-
85
- /* =====================
86
- Paragraphs
87
- ===================== */
88
- .notra .tiptap p:not(:first-child):not(td p):not(th p),
89
- .notra-reader p:not(:first-child) {
90
- font-size: 1rem;
91
- line-height: 1.6;
92
- font-weight: normal;
93
- margin-top: 20px;
94
- }
95
-
96
- /* =====================
97
- Headings
98
- ===================== */
99
- .notra .tiptap h1,
100
- .notra .tiptap h2,
101
- .notra .tiptap h3,
102
- .notra .tiptap h4,
103
- .notra .tiptap h5,
104
- .notra .tiptap h6,
105
- .notra-reader h1,
106
- .notra-reader h2,
107
- .notra-reader h3,
108
- .notra-reader h4,
109
- .notra-reader h5,
110
- .notra-reader h6 {
111
- position: relative;
112
- color: inherit;
113
- font-style: inherit;
114
- }
115
-
116
- .notra .tiptap > h1:first-child,
117
- .notra .tiptap > h2:first-child,
118
- .notra .tiptap > h3:first-child,
119
- .notra .tiptap > h4:first-child,
120
- .notra-reader > h1:first-child,
121
- .notra-reader > h2:first-child,
122
- .notra-reader > h3:first-child,
123
- .notra-reader > h4:first-child {
124
- margin-top: 0;
125
- }
126
-
127
- .notra .tiptap h1,
128
- .notra-reader h1 {
129
- font-size: 1.5em;
130
- font-weight: 700;
131
- margin-top: 3em;
132
- }
133
-
134
- .notra .tiptap h2,
135
- .notra-reader h2 {
136
- font-size: 1.25em;
137
- font-weight: 700;
138
- margin-top: 2.5em;
139
- }
140
-
141
- .notra .tiptap h3,
142
- .notra-reader h3 {
143
- font-size: 1.125em;
144
- font-weight: 600;
145
- margin-top: 2em;
146
- }
147
-
148
- .notra .tiptap h4,
149
- .notra-reader h4 {
150
- font-size: 1em;
151
- font-weight: 600;
152
- margin-top: 2em;
153
- }
154
-
155
- .notra .tiptap h5,
156
- .notra-reader h5 {
157
- font-size: 0.875em;
158
- font-weight: 600;
159
- margin-top: 1.5em;
160
- }
161
-
162
- .notra .tiptap h6,
163
- .notra-reader h6 {
164
- font-size: 0.75em;
165
- font-weight: 600;
166
- margin-top: 1.5em;
167
- }
168
-
169
- /* =====================
170
- Lists — Common
171
- ===================== */
172
- .notra .tiptap ol,
173
- .notra .tiptap ul,
174
- .notra-reader ol,
175
- .notra-reader ul {
176
- margin-top: 1.5em;
177
- margin-bottom: 1.5em;
178
- padding-left: 1.5em;
179
- }
180
-
181
- .notra .tiptap ol:first-child,
182
- .notra .tiptap ul:first-child,
183
- .notra-reader ol:first-child,
184
- .notra-reader ul:first-child {
185
- margin-top: 0;
186
- }
187
-
188
- .notra .tiptap ol:last-child,
189
- .notra .tiptap ul:last-child,
190
- .notra-reader ol:last-child,
191
- .notra-reader ul:last-child {
192
- margin-bottom: 0;
193
- }
194
-
195
- .notra .tiptap ol ol,
196
- .notra .tiptap ol ul,
197
- .notra .tiptap ul ol,
198
- .notra .tiptap ul ul,
199
- .notra-reader ol ol,
200
- .notra-reader ol ul,
201
- .notra-reader ul ol,
202
- .notra-reader ul ul {
203
- margin-top: 0;
204
- margin-bottom: 0;
205
- }
206
-
207
- .notra .tiptap li p,
208
- .notra-reader li p {
209
- margin-top: 0;
210
- line-height: 1.6;
211
- }
212
-
213
- /* =====================
214
- Ordered Lists — Nested styles
215
- ===================== */
216
- .notra .tiptap ol,
217
- .notra-reader ol {
218
- list-style: decimal;
219
- }
220
-
221
- .notra .tiptap ol ol,
222
- .notra-reader ol ol {
223
- list-style: lower-alpha;
224
- }
225
-
226
- .notra .tiptap ol ol ol,
227
- .notra-reader ol ol ol {
228
- list-style: lower-roman;
229
- }
230
-
231
- /* =====================
232
- Unordered Lists — Nested styles
233
- ===================== */
234
- .notra .tiptap ul:not([data-type='taskList']),
235
- .notra-reader ul:not([data-type='taskList']) {
236
- list-style: disc;
237
- }
238
-
239
- .notra .tiptap ul:not([data-type='taskList']) ul,
240
- .notra-reader ul:not([data-type='taskList']) ul {
241
- list-style: circle;
242
- }
243
-
244
- .notra .tiptap ul:not([data-type='taskList']) ul ul,
245
- .notra-reader ul:not([data-type='taskList']) ul ul {
246
- list-style: square;
247
- }
248
-
249
- /* =====================
250
- Task Lists
251
- ===================== */
252
- .notra .tiptap ul[data-type='taskList'],
253
- .notra-reader ul[data-type='taskList'] {
254
- padding-left: 0.25em;
255
- list-style: none;
256
- }
257
-
258
- .notra .tiptap ul[data-type='taskList'] li,
259
- .notra-reader ul[data-type='taskList'] li {
260
- display: flex;
261
- flex-direction: row;
262
- align-items: flex-start;
263
- }
264
-
265
- .notra .tiptap ul[data-type='taskList'] li[data-checked='true'] > div > p,
266
- .notra-reader ul[data-type='taskList'] li[data-checked='true'] > div > p {
267
- opacity: 0.5;
268
- text-decoration: line-through;
269
- }
270
-
271
- .notra .tiptap ul[data-type='taskList'] li label,
272
- .notra-reader ul[data-type='taskList'] li label {
273
- position: relative;
274
- padding-top: 0.375rem;
275
- padding-right: 0.5rem;
276
- }
277
-
278
- .notra .tiptap ul[data-type='taskList'] li label input[type='checkbox'],
279
- .notra-reader ul[data-type='taskList'] li label input[type='checkbox'] {
280
- position: absolute;
281
- opacity: 0;
282
- width: 0;
283
- height: 0;
284
- }
285
-
286
- .notra .tiptap ul[data-type='taskList'] li label span,
287
- .notra-reader ul[data-type='taskList'] li label span {
288
- display: block;
289
- width: 1em;
290
- height: 1em;
291
- border: 1px solid var(--notra-checklist-border);
292
- border-radius: 0.25rem;
293
- position: relative;
294
- cursor: pointer;
295
- background-color: var(--notra-checklist-bg);
296
- transition:
297
- background-color 80ms ease-out,
298
- border-color 80ms ease-out;
299
- }
300
-
301
- .notra .tiptap ul[data-type='taskList'] li label span::before,
302
- .notra-reader ul[data-type='taskList'] li label span::before {
303
- content: '';
304
- position: absolute;
305
- left: 50%;
306
- top: 50%;
307
- transform: translate(-50%, -50%);
308
- width: 0.75em;
309
- height: 0.75em;
310
- background-color: var(--notra-checklist-check-color);
311
- opacity: 0;
312
- -webkit-mask: url("data:image/svg+xml,%3Csvg width='24' height='24' viewBox='0 0 24 24' fill='currentColor' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M21.4142 4.58579C22.1953 5.36683 22.1953 6.63317 21.4142 7.41421L10.4142 18.4142C9.63317 19.1953 8.36684 19.1953 7.58579 18.4142L2.58579 13.4142C1.80474 12.6332 1.80474 11.3668 2.58579 10.5858C3.36683 9.80474 4.63317 9.80474 5.41421 10.5858L9 14.1716L18.5858 4.58579C19.3668 3.80474 20.6332 3.80474 21.4142 4.58579Z' fill='currentColor'/%3E%3C/svg%3E")
313
- center / contain no-repeat;
314
- mask: url("data:image/svg+xml,%3Csvg width='24' height='24' viewBox='0 0 24 24' fill='currentColor' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M21.4142 4.58579C22.1953 5.36683 22.1953 6.63317 21.4142 7.41421L10.4142 18.4142C9.63317 19.1953 8.36684 19.1953 7.58579 18.4142L2.58579 13.4142C1.80474 12.6332 1.80474 11.3668 2.58579 10.5858C3.36683 9.80474 4.63317 9.80474 5.41421 10.5858L9 14.1716L18.5858 4.58579C19.3668 3.80474 20.6332 3.80474 21.4142 4.58579Z' fill='currentColor'/%3E%3C/svg%3E")
315
- center / contain no-repeat;
316
- }
317
-
318
- .notra
319
- .tiptap
320
- ul[data-type='taskList']
321
- li
322
- label
323
- input[type='checkbox']:checked
324
- + span,
325
- .notra-reader
326
- ul[data-type='taskList']
327
- li
328
- label
329
- input[type='checkbox']:checked
330
- + span {
331
- background: var(--notra-checklist-bg-active);
332
- border-color: var(--notra-checklist-border-active);
333
- }
334
-
335
- .notra
336
- .tiptap
337
- ul[data-type='taskList']
338
- li
339
- label
340
- input[type='checkbox']:checked
341
- + span::before,
342
- .notra-reader
343
- ul[data-type='taskList']
344
- li
345
- label
346
- input[type='checkbox']:checked
347
- + span::before {
348
- opacity: 1;
349
- }
350
-
351
- .notra .tiptap ul[data-type='taskList'] li div,
352
- .notra-reader ul[data-type='taskList'] li div {
353
- flex: 1 1 0%;
354
- min-width: 0;
355
- }
356
-
357
- /* =====================
358
- Code — Inline
359
- ===================== */
360
- .notra .tiptap code,
361
- .notra-reader code {
362
- background-color: var(--notra-code-bg);
363
- color: var(--notra-code-text);
364
- border: 1px solid var(--notra-code-border);
365
- font-family: var(--notra-font-mono);
366
- font-size: 0.875em;
367
- line-height: 1.4;
368
- border-radius: var(--notra-radius);
369
- padding: 0.1em 0.2em;
370
- }
371
-
372
- /* =====================
373
- Code — Block
374
- ===================== */
375
- .notra .tiptap pre,
376
- .notra-reader pre {
377
- border: 1px solid var(--notra-codeblock-border);
378
- margin-top: 1.5em;
379
- margin-bottom: 1.5em;
380
- font-size: 1rem;
381
- border-radius: var(--notra-radius);
382
- overflow: hidden;
383
- font-family: var(--notra-font-mono);
384
- }
385
-
386
- .notra .tiptap pre code,
387
- .notra-reader pre code {
388
- background-color: transparent;
389
- border: none;
390
- border-radius: 0;
391
- padding: 1em;
392
- display: block;
393
- overflow-x: auto;
394
- font-size: 0.875em;
395
- line-height: 1.5;
396
- }
397
-
398
- /* =====================
399
- Code — Highlight (Atom One Light, default)
400
- ===================== */
401
- .notra .hljs {
402
- color: #383a42;
403
- background: #fafafa;
404
- }
405
- .notra .hljs-comment,
406
- .notra .hljs-quote {
407
- color: #a0a1a7;
408
- font-style: italic;
409
- }
410
- .notra .hljs-doctag,
411
- .notra .hljs-formula,
412
- .notra .hljs-keyword {
413
- color: #a626a4;
414
- }
415
- .notra .hljs-deletion,
416
- .notra .hljs-name,
417
- .notra .hljs-section,
418
- .notra .hljs-selector-tag,
419
- .notra .hljs-subst {
420
- color: #e45649;
421
- }
422
- .notra .hljs-literal {
423
- color: #0184bb;
424
- }
425
- .notra .hljs-addition,
426
- .notra .hljs-attribute,
427
- .notra .hljs-meta .hljs-string,
428
- .notra .hljs-regexp,
429
- .notra .hljs-string {
430
- color: #50a14f;
431
- }
432
- .notra .hljs-built_in,
433
- .notra .hljs-class .hljs-title,
434
- .notra .hljs-title.class_ {
435
- color: #c18401;
436
- }
437
- .notra .hljs-attr,
438
- .notra .hljs-number,
439
- .notra .hljs-selector-attr,
440
- .notra .hljs-selector-class,
441
- .notra .hljs-selector-pseudo,
442
- .notra .hljs-template-variable,
443
- .notra .hljs-type,
444
- .notra .hljs-variable {
445
- color: #986801;
446
- }
447
- .notra .hljs-bullet,
448
- .notra .hljs-link,
449
- .notra .hljs-meta,
450
- .notra .hljs-selector-id,
451
- .notra .hljs-symbol,
452
- .notra .hljs-title {
453
- color: #4078f2;
454
- }
455
- .notra .hljs-emphasis {
456
- font-style: italic;
457
- }
458
- .notra .hljs-strong {
459
- font-weight: bold;
460
- }
461
- .notra .hljs-link {
462
- text-decoration: underline;
463
- }
464
-
465
- /* =====================
466
- Code — Highlight (Atom One Dark, .dark override)
467
- ===================== */
468
- .dark .notra .hljs {
469
- color: #abb2bf;
470
- background: #282c34;
471
- }
472
- .dark .notra .hljs-comment,
473
- .dark .notra .hljs-quote {
474
- color: #5c6370;
475
- font-style: italic;
476
- }
477
- .dark .notra .hljs-doctag,
478
- .dark .notra .hljs-formula,
479
- .dark .notra .hljs-keyword {
480
- color: #c678dd;
481
- }
482
- .dark .notra .hljs-deletion,
483
- .dark .notra .hljs-name,
484
- .dark .notra .hljs-section,
485
- .dark .notra .hljs-selector-tag,
486
- .dark .notra .hljs-subst {
487
- color: #e06c75;
488
- }
489
- .dark .notra .hljs-literal {
490
- color: #56b6c2;
491
- }
492
- .dark .notra .hljs-addition,
493
- .dark .notra .hljs-attribute,
494
- .dark .notra .hljs-meta .hljs-string,
495
- .dark .notra .hljs-regexp,
496
- .dark .notra .hljs-string {
497
- color: #98c379;
498
- }
499
- .dark .notra .hljs-built_in,
500
- .dark .notra .hljs-class .hljs-title,
501
- .dark .notra .hljs-title.class_ {
502
- color: #e6c07b;
503
- }
504
- .dark .notra .hljs-attr,
505
- .dark .notra .hljs-number,
506
- .dark .notra .hljs-selector-attr,
507
- .dark .notra .hljs-selector-class,
508
- .dark .notra .hljs-selector-pseudo,
509
- .dark .notra .hljs-template-variable,
510
- .dark .notra .hljs-type,
511
- .dark .notra .hljs-variable {
512
- color: #d19a66;
513
- }
514
- .dark .notra .hljs-bullet,
515
- .dark .notra .hljs-link,
516
- .dark .notra .hljs-meta,
517
- .dark .notra .hljs-selector-id,
518
- .dark .notra .hljs-symbol,
519
- .dark .notra .hljs-title {
520
- color: #61aeee;
521
- }
522
-
523
- /* =====================
524
- Blockquote
525
- ===================== */
526
- .notra .tiptap blockquote,
527
- .notra-reader blockquote {
528
- position: relative;
529
- padding-left: 1em;
530
- padding-top: 0.375em;
531
- padding-bottom: 0.375em;
532
- margin: 1.5rem 0;
533
- }
534
-
535
- .notra .tiptap blockquote p,
536
- .notra-reader blockquote p {
537
- margin-top: 0;
538
- }
539
-
540
- .notra .tiptap blockquote::before,
541
- .notra-reader blockquote::before {
542
- position: absolute;
543
- bottom: 0;
544
- left: 0;
545
- top: 0;
546
- height: 100%;
547
- width: 0.25em;
548
- background-color: var(--notra-blockquote-bar);
549
- content: '';
550
- border-radius: 0;
551
- }
552
-
553
- /* =====================
554
- Horizontal Rule
555
- ===================== */
556
- .notra .tiptap hr,
557
- .notra-reader hr {
558
- border: none;
559
- height: 1px;
560
- background-color: var(--notra-hr-color);
561
- }
562
-
563
- .notra .tiptap [data-type='horizontalRule'],
564
- .notra-reader [data-type='horizontalRule'] {
565
- margin-top: 2.25em;
566
- margin-bottom: 2.25em;
567
- padding-top: 0.75rem;
568
- padding-bottom: 0.75rem;
569
- }
570
-
571
- /* =====================
572
- Links
573
- ===================== */
574
- .notra .tiptap a,
575
- .notra-reader a {
576
- color: var(--notra-color-link);
577
- text-decoration: underline;
578
- }
579
-
580
- /* =====================
581
- Images
582
- ===================== */
583
- .notra .tiptap img,
584
- .notra-reader img {
585
- max-width: 100%;
586
- height: auto;
587
- display: block;
588
- margin: 1.5em 0;
589
- border-radius: var(--notra-radius);
590
- }
591
-
592
- /* Selected image (NodeSelection) — only relevant in the editor */
593
- .notra .tiptap img.ProseMirror-selectednode {
594
- outline: 2px solid var(--tt-brand-color-500);
595
- outline-offset: 2px;
596
- }
597
-
598
- /* =====================
599
- Inline Text Decoration
600
- ===================== */
601
- .notra .tiptap a span,
602
- .notra-reader a span {
603
- text-decoration: underline;
604
- }
605
-
606
- .notra .tiptap s span,
607
- .notra-reader s span {
608
- text-decoration: line-through;
609
- }