@llui/markdown-editor 0.1.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.
Files changed (104) hide show
  1. package/LICENSE +21 -0
  2. package/dist/__llui_deps.json +252 -0
  3. package/dist/editor.d.ts +42 -0
  4. package/dist/editor.d.ts.map +1 -0
  5. package/dist/editor.js +157 -0
  6. package/dist/editor.js.map +1 -0
  7. package/dist/effects.d.ts +17 -0
  8. package/dist/effects.d.ts.map +1 -0
  9. package/dist/effects.js +33 -0
  10. package/dist/effects.js.map +1 -0
  11. package/dist/format.d.ts +6 -0
  12. package/dist/format.d.ts.map +1 -0
  13. package/dist/format.js +51 -0
  14. package/dist/format.js.map +1 -0
  15. package/dist/index.d.ts +23 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +24 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/plugins/callout.d.ts +15 -0
  20. package/dist/plugins/callout.d.ts.map +1 -0
  21. package/dist/plugins/callout.js +151 -0
  22. package/dist/plugins/callout.js.map +1 -0
  23. package/dist/plugins/context-menu.d.ts +3 -0
  24. package/dist/plugins/context-menu.d.ts.map +1 -0
  25. package/dist/plugins/context-menu.js +93 -0
  26. package/dist/plugins/context-menu.js.map +1 -0
  27. package/dist/plugins/core.d.ts +7 -0
  28. package/dist/plugins/core.d.ts.map +1 -0
  29. package/dist/plugins/core.js +189 -0
  30. package/dist/plugins/core.js.map +1 -0
  31. package/dist/plugins/emoji.d.ts +9 -0
  32. package/dist/plugins/emoji.d.ts.map +1 -0
  33. package/dist/plugins/emoji.js +50 -0
  34. package/dist/plugins/emoji.js.map +1 -0
  35. package/dist/plugins/floating-toolbar.d.ts +3 -0
  36. package/dist/plugins/floating-toolbar.d.ts.map +1 -0
  37. package/dist/plugins/floating-toolbar.js +137 -0
  38. package/dist/plugins/floating-toolbar.js.map +1 -0
  39. package/dist/plugins/hr.d.ts +5 -0
  40. package/dist/plugins/hr.d.ts.map +1 -0
  41. package/dist/plugins/hr.js +46 -0
  42. package/dist/plugins/hr.js.map +1 -0
  43. package/dist/plugins/image.d.ts +8 -0
  44. package/dist/plugins/image.d.ts.map +1 -0
  45. package/dist/plugins/image.js +173 -0
  46. package/dist/plugins/image.js.map +1 -0
  47. package/dist/plugins/link.d.ts +7 -0
  48. package/dist/plugins/link.d.ts.map +1 -0
  49. package/dist/plugins/link.js +100 -0
  50. package/dist/plugins/link.js.map +1 -0
  51. package/dist/plugins/math.d.ts +8 -0
  52. package/dist/plugins/math.d.ts.map +1 -0
  53. package/dist/plugins/math.js +81 -0
  54. package/dist/plugins/math.js.map +1 -0
  55. package/dist/plugins/mention.d.ts +11 -0
  56. package/dist/plugins/mention.d.ts.map +1 -0
  57. package/dist/plugins/mention.js +163 -0
  58. package/dist/plugins/mention.js.map +1 -0
  59. package/dist/plugins/mermaid.d.ts +8 -0
  60. package/dist/plugins/mermaid.d.ts.map +1 -0
  61. package/dist/plugins/mermaid.js +92 -0
  62. package/dist/plugins/mermaid.js.map +1 -0
  63. package/dist/plugins/overlay.d.ts +46 -0
  64. package/dist/plugins/overlay.d.ts.map +1 -0
  65. package/dist/plugins/overlay.js +83 -0
  66. package/dist/plugins/overlay.js.map +1 -0
  67. package/dist/plugins/slash.d.ts +3 -0
  68. package/dist/plugins/slash.d.ts.map +1 -0
  69. package/dist/plugins/slash.js +167 -0
  70. package/dist/plugins/slash.js.map +1 -0
  71. package/dist/plugins/table.d.ts +3 -0
  72. package/dist/plugins/table.d.ts.map +1 -0
  73. package/dist/plugins/table.js +227 -0
  74. package/dist/plugins/table.js.map +1 -0
  75. package/dist/plugins/types.d.ts +44 -0
  76. package/dist/plugins/types.d.ts.map +1 -0
  77. package/dist/plugins/types.js +4 -0
  78. package/dist/plugins/types.js.map +1 -0
  79. package/dist/plugins/ui.d.ts +44 -0
  80. package/dist/plugins/ui.d.ts.map +1 -0
  81. package/dist/plugins/ui.js +34 -0
  82. package/dist/plugins/ui.js.map +1 -0
  83. package/dist/state.d.ts +105 -0
  84. package/dist/state.d.ts.map +1 -0
  85. package/dist/state.js +100 -0
  86. package/dist/state.js.map +1 -0
  87. package/dist/styles/editor.css +517 -0
  88. package/dist/surfaces/link-dialog.d.ts +19 -0
  89. package/dist/surfaces/link-dialog.d.ts.map +1 -0
  90. package/dist/surfaces/link-dialog.js +45 -0
  91. package/dist/surfaces/link-dialog.js.map +1 -0
  92. package/dist/surfaces/toolbar.d.ts +48 -0
  93. package/dist/surfaces/toolbar.d.ts.map +1 -0
  94. package/dist/surfaces/toolbar.js +134 -0
  95. package/dist/surfaces/toolbar.js.map +1 -0
  96. package/dist/transformers/gfm.d.ts +7 -0
  97. package/dist/transformers/gfm.d.ts.map +1 -0
  98. package/dist/transformers/gfm.js +41 -0
  99. package/dist/transformers/gfm.js.map +1 -0
  100. package/dist/transformers/registry.d.ts +9 -0
  101. package/dist/transformers/registry.d.ts.map +1 -0
  102. package/dist/transformers/registry.js +43 -0
  103. package/dist/transformers/registry.js.map +1 -0
  104. package/package.json +89 -0
@@ -0,0 +1,517 @@
1
+ /**
2
+ * Default theme for @llui/markdown-editor. Headless components target
3
+ * data-scope / data-part attributes; this stylesheet gives a polished default.
4
+ * Override the `--md-*` custom properties to retheme (e.g. for light mode).
5
+ *
6
+ * import '@llui/markdown-editor/styles/editor.css'
7
+ */
8
+ :root {
9
+ --md-bg: #0f1117;
10
+ --md-surface: #181b24;
11
+ --md-surface-2: #1f2330;
12
+ --md-border: #2b3040;
13
+ --md-text: #e6e8ee;
14
+ --md-muted: #9aa3b2;
15
+ --md-primary: #5b8cff;
16
+ --md-primary-soft: #2a3656;
17
+ --md-radius: 8px;
18
+ --md-mono: ui-monospace, 'SF Mono', 'JetBrains Mono', Menlo, Consolas, monospace;
19
+ }
20
+
21
+ /* ── Editor surface (Lexical's contentEditable host) ──────────────────── */
22
+ [data-lexical-editor] {
23
+ position: relative;
24
+ outline: none;
25
+ padding: 1.1rem 1.25rem;
26
+ min-height: 8rem;
27
+ color: var(--md-text);
28
+ }
29
+ [data-lexical-editor] > * {
30
+ margin: 0 0 0.7rem;
31
+ }
32
+ [data-lexical-editor][data-empty='true']::before {
33
+ content: attr(data-placeholder);
34
+ position: absolute;
35
+ top: 1.1rem;
36
+ left: 1.25rem;
37
+ color: var(--md-muted);
38
+ pointer-events: none;
39
+ }
40
+ [data-lexical-editor] h1 {
41
+ font-size: 1.6rem;
42
+ letter-spacing: -0.02em;
43
+ }
44
+ [data-lexical-editor] h2 {
45
+ font-size: 1.3rem;
46
+ }
47
+ [data-lexical-editor] h3 {
48
+ font-size: 1.1rem;
49
+ }
50
+ [data-lexical-editor] blockquote {
51
+ border-left: 3px solid var(--md-primary);
52
+ margin-inline: 0;
53
+ padding-left: 0.9rem;
54
+ color: var(--md-muted);
55
+ }
56
+ [data-lexical-editor] ul,
57
+ [data-lexical-editor] ol {
58
+ padding-left: 1.4rem;
59
+ }
60
+ [data-lexical-editor] a {
61
+ color: var(--md-primary);
62
+ }
63
+ [data-lexical-editor] code[data-lexical-text='true'] {
64
+ background: var(--md-surface-2);
65
+ padding: 0.1em 0.35em;
66
+ border-radius: 5px;
67
+ font-family: var(--md-mono);
68
+ }
69
+ [data-lexical-editor] code:not([data-lexical-text='true']) {
70
+ display: block;
71
+ white-space: pre;
72
+ background: var(--md-bg);
73
+ border: 1px solid var(--md-border);
74
+ border-radius: 6px;
75
+ padding: 0.7rem 0.9rem;
76
+ font-size: 0.85rem;
77
+ font-family: var(--md-mono);
78
+ overflow: auto;
79
+ }
80
+
81
+ /* Task-list items (li[role="checkbox"]) with a clickable checkbox. */
82
+ [data-lexical-editor] li[role='checkbox'] {
83
+ position: relative;
84
+ list-style: none;
85
+ margin-left: -0.4rem;
86
+ padding-left: 1.5rem;
87
+ outline: none;
88
+ }
89
+ [data-lexical-editor] li[role='checkbox']::before {
90
+ content: '';
91
+ position: absolute;
92
+ left: 0;
93
+ top: 0.25em;
94
+ width: 1rem;
95
+ height: 1rem;
96
+ border: 1px solid var(--md-muted);
97
+ border-radius: 3px;
98
+ cursor: pointer;
99
+ }
100
+ [data-lexical-editor] li[role='checkbox'][aria-checked='true'] {
101
+ color: var(--md-muted);
102
+ text-decoration: line-through;
103
+ }
104
+ [data-lexical-editor] li[role='checkbox'][aria-checked='true']::before {
105
+ background: var(--md-primary);
106
+ border-color: var(--md-primary);
107
+ }
108
+ [data-lexical-editor] li[role='checkbox'][aria-checked='true']::after {
109
+ content: '';
110
+ position: absolute;
111
+ left: 0.34rem;
112
+ top: 0.3em;
113
+ width: 0.28rem;
114
+ height: 0.55rem;
115
+ border: solid #fff;
116
+ border-width: 0 2px 2px 0;
117
+ transform: rotate(45deg);
118
+ cursor: pointer;
119
+ }
120
+
121
+ /* ── Editor shell + toolbar ───────────────────────────────────────────── */
122
+ [data-scope='md-editor'][data-part='root'] {
123
+ display: flex;
124
+ flex-direction: column;
125
+ background: var(--md-surface);
126
+ }
127
+ [data-scope='md-toolbar'][data-part='root'] {
128
+ display: flex;
129
+ flex-wrap: wrap;
130
+ gap: 0.5rem;
131
+ padding: 0.5rem 0.6rem;
132
+ border-bottom: 1px solid var(--md-border);
133
+ background: var(--md-surface-2);
134
+ position: sticky;
135
+ top: 0;
136
+ z-index: 1;
137
+ }
138
+ [data-scope='md-toolbar'][data-part='group'] {
139
+ display: flex;
140
+ align-items: center;
141
+ gap: 0.15rem;
142
+ padding-right: 0.5rem;
143
+ border-right: 1px solid var(--md-border);
144
+ }
145
+ [data-scope='md-toolbar'][data-part='group']:last-child {
146
+ border-right: none;
147
+ padding-right: 0;
148
+ }
149
+ [data-scope='md-toolbar'] [data-part='item'] {
150
+ font: inherit;
151
+ font-size: 0.85rem;
152
+ min-width: 2rem;
153
+ height: 2rem;
154
+ padding: 0 0.4rem;
155
+ color: var(--md-text);
156
+ background: transparent;
157
+ border: 1px solid transparent;
158
+ border-radius: 6px;
159
+ cursor: pointer;
160
+ }
161
+ [data-scope='md-toolbar'] [data-part='item']:hover {
162
+ background: var(--md-surface);
163
+ }
164
+ [data-scope='md-toolbar'] [data-part='item'][data-active] {
165
+ background: var(--md-primary-soft);
166
+ color: #fff;
167
+ border-color: var(--md-primary);
168
+ }
169
+ [data-scope='md-toolbar'] [data-part='item']:disabled {
170
+ opacity: 0.4;
171
+ cursor: default;
172
+ }
173
+ [data-scope='md-toolbar'] [data-part='block-select'] {
174
+ font: inherit;
175
+ font-size: 0.85rem;
176
+ height: 2rem;
177
+ padding: 0 0.4rem;
178
+ color: var(--md-text);
179
+ background: var(--md-surface);
180
+ border: 1px solid var(--md-border);
181
+ border-radius: 6px;
182
+ cursor: pointer;
183
+ }
184
+ [data-part='glyph'] {
185
+ display: inline-flex;
186
+ align-items: center;
187
+ font-weight: 600;
188
+ }
189
+ [data-part='glyph'] svg {
190
+ display: block;
191
+ }
192
+
193
+ /* ── Callout decorator ────────────────────────────────────────────────── */
194
+ [data-scope='md-callout'][data-part='root'] {
195
+ display: flex;
196
+ align-items: flex-start;
197
+ gap: 0.7rem;
198
+ padding: 0.7rem 0.9rem;
199
+ border-radius: 8px;
200
+ border: 1px solid var(--md-border);
201
+ border-left-width: 4px;
202
+ background: var(--md-surface-2);
203
+ margin: 0.6rem 0;
204
+ }
205
+ [data-scope='md-callout'] [data-part='badge'] {
206
+ font: inherit;
207
+ font-size: 0.72rem;
208
+ font-weight: 700;
209
+ letter-spacing: 0.04em;
210
+ text-transform: uppercase;
211
+ color: #fff;
212
+ border: none;
213
+ border-radius: 5px;
214
+ padding: 0.2rem 0.5rem;
215
+ cursor: pointer;
216
+ flex: none;
217
+ }
218
+ [data-scope='md-callout'] [data-part='text'] {
219
+ flex: 1;
220
+ padding-top: 0.1rem;
221
+ outline: none;
222
+ border-radius: 4px;
223
+ }
224
+ [data-scope='md-callout'] [data-part='text']:focus {
225
+ box-shadow: 0 0 0 2px var(--md-primary-soft);
226
+ }
227
+ [data-scope='md-callout'] [data-part='text']:empty::before {
228
+ content: 'Callout text…';
229
+ color: var(--md-muted);
230
+ }
231
+ [data-scope='md-callout'][data-kind='note'] {
232
+ border-left-color: #5b8cff;
233
+ }
234
+ [data-scope='md-callout'][data-kind='note'] [data-part='badge'] {
235
+ background: #5b8cff;
236
+ }
237
+ [data-scope='md-callout'][data-kind='tip'] {
238
+ border-left-color: #34d399;
239
+ }
240
+ [data-scope='md-callout'][data-kind='tip'] [data-part='badge'] {
241
+ background: #34d399;
242
+ }
243
+ [data-scope='md-callout'][data-kind='warning'] {
244
+ border-left-color: #fbbf24;
245
+ }
246
+ [data-scope='md-callout'][data-kind='warning'] [data-part='badge'] {
247
+ background: #b8860b;
248
+ }
249
+ [data-scope='md-callout'][data-kind='danger'] {
250
+ border-left-color: #f87171;
251
+ }
252
+ [data-scope='md-callout'][data-kind='danger'] [data-part='badge'] {
253
+ background: #ef4444;
254
+ }
255
+
256
+ /* ── Image + horizontal-rule decorators ───────────────────────────────── */
257
+ [data-scope='md-image'][data-part='root'] {
258
+ margin: 0.6rem 0;
259
+ }
260
+ [data-scope='md-image'] img {
261
+ max-width: 100%;
262
+ height: auto;
263
+ border-radius: 6px;
264
+ border: 1px solid var(--md-border);
265
+ display: block;
266
+ }
267
+ [data-md-hr] {
268
+ border: none;
269
+ border-top: 1px solid var(--md-border);
270
+ margin: 1.2rem 0;
271
+ }
272
+
273
+ /* ── Tables ───────────────────────────────────────────────────────────── */
274
+ [data-lexical-editor] table {
275
+ border-collapse: collapse;
276
+ margin: 0.6rem 0;
277
+ width: 100%;
278
+ font-size: 0.9rem;
279
+ }
280
+ [data-lexical-editor] th,
281
+ [data-lexical-editor] td {
282
+ border: 1px solid var(--md-border);
283
+ padding: 0.4rem 0.6rem;
284
+ text-align: left;
285
+ vertical-align: top;
286
+ min-width: 4rem;
287
+ }
288
+ [data-lexical-editor] th {
289
+ background: var(--md-surface-2);
290
+ font-weight: 600;
291
+ }
292
+ [data-scope='md-table-tools'][data-part='bar'] {
293
+ display: flex;
294
+ gap: 0.1rem;
295
+ padding: 0.2rem;
296
+ background: var(--md-surface);
297
+ border: 1px solid var(--md-border);
298
+ border-radius: 7px;
299
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5);
300
+ }
301
+ [data-scope='md-table-tools'][data-part='tool'] {
302
+ font: inherit;
303
+ font-size: 0.78rem;
304
+ min-width: 1.9rem;
305
+ height: 1.8rem;
306
+ padding: 0 0.3rem;
307
+ color: var(--md-text);
308
+ background: transparent;
309
+ border: 1px solid transparent;
310
+ border-radius: 5px;
311
+ cursor: pointer;
312
+ }
313
+ [data-scope='md-table-tools'][data-part='tool']:hover {
314
+ background: var(--md-surface-2);
315
+ }
316
+
317
+ /* ── Math block ───────────────────────────────────────────────────────── */
318
+ [data-scope='md-math'][data-part='root'] {
319
+ display: flex;
320
+ flex-direction: column;
321
+ gap: 0.4rem;
322
+ margin: 0.6rem 0;
323
+ padding: 0.7rem 0.9rem;
324
+ border: 1px solid var(--md-border);
325
+ border-radius: 8px;
326
+ background: var(--md-surface-2);
327
+ }
328
+ [data-scope='md-math'] [data-part='source'] {
329
+ font-family: var(--md-mono);
330
+ font-size: 0.85rem;
331
+ color: var(--md-muted);
332
+ outline: none;
333
+ }
334
+ [data-scope='md-math'] [data-part='source']:focus {
335
+ color: var(--md-text);
336
+ }
337
+ [data-scope='md-math'] [data-part='preview'] {
338
+ text-align: center;
339
+ }
340
+
341
+ /* ── Mermaid block ────────────────────────────────────────────────────── */
342
+ [data-scope='md-mermaid'][data-part='root'] {
343
+ display: flex;
344
+ flex-direction: column;
345
+ gap: 0.4rem;
346
+ margin: 0.6rem 0;
347
+ padding: 0.7rem 0.9rem;
348
+ border: 1px solid var(--md-border);
349
+ border-radius: 8px;
350
+ background: var(--md-surface-2);
351
+ }
352
+ [data-scope='md-mermaid'] [data-part='source'] {
353
+ font-family: var(--md-mono);
354
+ font-size: 0.82rem;
355
+ white-space: pre-wrap;
356
+ color: var(--md-muted);
357
+ outline: none;
358
+ }
359
+ [data-scope='md-mermaid'] [data-part='source']:focus {
360
+ color: var(--md-text);
361
+ }
362
+ [data-md-image='alt'] {
363
+ margin-top: 0.5rem;
364
+ }
365
+ [data-md-image='file'] {
366
+ margin-top: 0.6rem;
367
+ font-size: 0.8rem;
368
+ color: var(--md-muted);
369
+ }
370
+
371
+ /* ── Slash command menu ───────────────────────────────────────────────── */
372
+ [data-scope='md-slash'][data-part='root'] {
373
+ min-width: 12rem;
374
+ max-height: 16rem;
375
+ overflow: auto;
376
+ padding: 0.25rem;
377
+ background: var(--md-surface);
378
+ border: 1px solid var(--md-border);
379
+ border-radius: 8px;
380
+ box-shadow: 0 12px 32px rgba(0, 0, 0, 0.5);
381
+ }
382
+ [data-scope='md-slash'][data-part='option'] {
383
+ padding: 0.4rem 0.6rem;
384
+ border-radius: 5px;
385
+ font-size: 0.88rem;
386
+ color: var(--md-text);
387
+ cursor: pointer;
388
+ }
389
+ [data-scope='md-slash'][data-part='option'][data-active] {
390
+ background: var(--md-primary-soft);
391
+ }
392
+
393
+ /* ── Context menu ─────────────────────────────────────────────────────── */
394
+ [data-scope='md-context'][data-part='backdrop'] {
395
+ position: fixed;
396
+ inset: 0;
397
+ z-index: 60;
398
+ }
399
+ [data-scope='md-context'][data-part='root'] {
400
+ min-width: 11rem;
401
+ max-height: 18rem;
402
+ overflow: auto;
403
+ padding: 0.25rem;
404
+ background: var(--md-surface);
405
+ border: 1px solid var(--md-border);
406
+ border-radius: 8px;
407
+ box-shadow: 0 12px 32px rgba(0, 0, 0, 0.5);
408
+ }
409
+ [data-scope='md-context'][data-part='option'] {
410
+ padding: 0.35rem 0.6rem;
411
+ border-radius: 5px;
412
+ font-size: 0.85rem;
413
+ color: var(--md-text);
414
+ cursor: pointer;
415
+ }
416
+ [data-scope='md-context'][data-part='option']:hover {
417
+ background: var(--md-primary-soft);
418
+ }
419
+
420
+ /* ── Floating selection toolbar ───────────────────────────────────────── */
421
+ [data-scope='md-floating'][data-part='bar'] {
422
+ display: flex;
423
+ gap: 0.1rem;
424
+ padding: 0.2rem;
425
+ background: var(--md-surface);
426
+ border: 1px solid var(--md-border);
427
+ border-radius: 7px;
428
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5);
429
+ }
430
+ [data-scope='md-floating'][data-part='item'] {
431
+ font: inherit;
432
+ font-size: 0.85rem;
433
+ min-width: 1.8rem;
434
+ height: 1.8rem;
435
+ padding: 0 0.35rem;
436
+ color: var(--md-text);
437
+ background: transparent;
438
+ border: 1px solid transparent;
439
+ border-radius: 5px;
440
+ cursor: pointer;
441
+ }
442
+ [data-scope='md-floating'][data-part='item']:hover {
443
+ background: var(--md-surface-2);
444
+ }
445
+ [data-scope='md-floating'][data-part='item'][data-active] {
446
+ background: var(--md-primary-soft);
447
+ color: #fff;
448
+ }
449
+
450
+ /* ── Link dialog ──────────────────────────────────────────────────────── */
451
+ [data-scope='dialog'][data-part='backdrop'] {
452
+ position: fixed;
453
+ inset: 0;
454
+ background: rgba(8, 10, 16, 0.6);
455
+ z-index: 50;
456
+ }
457
+ [data-scope='dialog'][data-part='positioner'] {
458
+ position: fixed;
459
+ inset: 0;
460
+ display: grid;
461
+ place-items: center;
462
+ padding: 1rem;
463
+ z-index: 51;
464
+ }
465
+ [data-md-link='box'] {
466
+ width: min(28rem, 100%);
467
+ background: var(--md-surface);
468
+ border: 1px solid var(--md-border);
469
+ border-radius: 10px;
470
+ padding: 1.1rem 1.2rem;
471
+ box-shadow: 0 16px 48px rgba(0, 0, 0, 0.55);
472
+ color: var(--md-text);
473
+ }
474
+ [data-md-link='title'] {
475
+ font-size: 1rem;
476
+ font-weight: 600;
477
+ margin-bottom: 0.7rem;
478
+ }
479
+ [data-md-link='input'] {
480
+ width: 100%;
481
+ box-sizing: border-box;
482
+ font: inherit;
483
+ font-size: 0.9rem;
484
+ background: var(--md-bg);
485
+ color: var(--md-text);
486
+ border: 1px solid var(--md-border);
487
+ border-radius: 6px;
488
+ padding: 0.5rem 0.6rem;
489
+ outline: none;
490
+ }
491
+ [data-md-link='input']:focus {
492
+ border-color: var(--md-primary);
493
+ }
494
+ [data-md-link='actions'] {
495
+ display: flex;
496
+ justify-content: flex-end;
497
+ gap: 0.5rem;
498
+ margin-top: 1rem;
499
+ }
500
+ [data-md-link='cancel'],
501
+ [data-md-link='apply'] {
502
+ font: inherit;
503
+ font-size: 0.85rem;
504
+ border-radius: 6px;
505
+ padding: 0.4rem 0.85rem;
506
+ cursor: pointer;
507
+ border: 1px solid var(--md-border);
508
+ }
509
+ [data-md-link='cancel'] {
510
+ background: var(--md-surface);
511
+ color: var(--md-text);
512
+ }
513
+ [data-md-link='apply'] {
514
+ background: var(--md-primary);
515
+ color: #fff;
516
+ border-color: var(--md-primary);
517
+ }
@@ -0,0 +1,19 @@
1
+ import { type Mountable, type Signal } from '@llui/dom';
2
+ import { type DialogMsg, type DialogState } from '@llui/components/dialog';
3
+ export interface LinkDialogOptions {
4
+ /** The `{ open }` slice driving the modal. */
5
+ dialog: Signal<DialogState>;
6
+ /** The URL input value. */
7
+ url: Signal<string>;
8
+ /** Called as the user edits the URL. */
9
+ onInput: (url: string) => void;
10
+ /** Called on Apply / Enter. */
11
+ onSubmit: () => void;
12
+ /** Called when the dialog requests open/close (dismiss, close button). */
13
+ onDialog: (msg: DialogMsg) => void;
14
+ /** Dialog instance id for ARIA wiring (default 'md-link-dialog'). */
15
+ id?: string;
16
+ }
17
+ /** Render the link dialog. Hidden (portal, nothing inline) until `dialog.open`. */
18
+ export declare function linkDialog(opts: LinkDialogOptions): Mountable;
19
+ //# sourceMappingURL=link-dialog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"link-dialog.d.ts","sourceRoot":"","sources":["../../src/surfaces/link-dialog.ts"],"names":[],"mappings":"AAKA,OAAO,EAA4B,KAAK,SAAS,EAAE,KAAK,MAAM,EAAE,MAAM,WAAW,CAAA;AACjF,OAAO,EAGL,KAAK,SAAS,EACd,KAAK,WAAW,EACjB,MAAM,yBAAyB,CAAA;AAEhC,MAAM,WAAW,iBAAiB;IAChC,8CAA8C;IAC9C,MAAM,EAAE,MAAM,CAAC,WAAW,CAAC,CAAA;IAC3B,2BAA2B;IAC3B,GAAG,EAAE,MAAM,CAAC,MAAM,CAAC,CAAA;IACnB,wCAAwC;IACxC,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;IAC9B,+BAA+B;IAC/B,QAAQ,EAAE,MAAM,IAAI,CAAA;IACpB,0EAA0E;IAC1E,QAAQ,EAAE,CAAC,GAAG,EAAE,SAAS,KAAK,IAAI,CAAA;IAClC,qEAAqE;IACrE,EAAE,CAAC,EAAE,MAAM,CAAA;CACZ;AAED,mFAAmF;AACnF,wBAAgB,UAAU,CAAC,IAAI,EAAE,iBAAiB,GAAG,SAAS,CAqC7D"}
@@ -0,0 +1,45 @@
1
+ // The link editor — a modal dialog (built on the @llui/components `dialog`) for
2
+ // entering/editing a URL. Pure view: it's driven by `{ open }` + `url` signals
3
+ // and reports changes through callbacks, so any owner (the link plugin) can wire
4
+ // it to its own messages.
5
+ import { button, div, input, text } from '@llui/dom';
6
+ import { connect as connectDialog, overlay as overlayDialog, } from '@llui/components/dialog';
7
+ /** Render the link dialog. Hidden (portal, nothing inline) until `dialog.open`. */
8
+ export function linkDialog(opts) {
9
+ const parts = connectDialog(opts.dialog, opts.onDialog, {
10
+ id: opts.id ?? 'md-link-dialog',
11
+ closeLabel: 'Cancel',
12
+ });
13
+ return overlayDialog({
14
+ state: opts.dialog,
15
+ send: opts.onDialog,
16
+ parts,
17
+ closeOnEscape: true,
18
+ closeOnOutsideClick: true,
19
+ content: () => [
20
+ div({ ...parts.content, 'data-md-link': 'box' }, [
21
+ div({ ...parts.title, 'data-md-link': 'title' }, [text('Insert link')]),
22
+ input({
23
+ 'data-md-link': 'input',
24
+ type: 'url',
25
+ placeholder: 'https://example.com',
26
+ value: opts.url,
27
+ onInput: (e) => opts.onInput(e.target.value),
28
+ onKeyDown: (e) => {
29
+ if (e.key === 'Enter') {
30
+ e.preventDefault();
31
+ opts.onSubmit();
32
+ }
33
+ },
34
+ }),
35
+ div({ 'data-md-link': 'actions' }, [
36
+ button({ ...parts.closeTrigger, 'data-md-link': 'cancel' }, [text('Cancel')]),
37
+ button({ type: 'button', 'data-md-link': 'apply', onClick: () => opts.onSubmit() }, [
38
+ text('Apply'),
39
+ ]),
40
+ ]),
41
+ ]),
42
+ ],
43
+ });
44
+ }
45
+ //# sourceMappingURL=link-dialog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"link-dialog.js","sourceRoot":"","sources":["../../src/surfaces/link-dialog.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,+EAA+E;AAC/E,iFAAiF;AACjF,0BAA0B;AAE1B,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAA+B,MAAM,WAAW,CAAA;AACjF,OAAO,EACL,OAAO,IAAI,aAAa,EACxB,OAAO,IAAI,aAAa,GAGzB,MAAM,yBAAyB,CAAA;AAiBhC,mFAAmF;AACnF,MAAM,UAAU,UAAU,CAAC,IAAuB;IAChD,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,QAAQ,EAAE;QACtD,EAAE,EAAE,IAAI,CAAC,EAAE,IAAI,gBAAgB;QAC/B,UAAU,EAAE,QAAQ;KACrB,CAAC,CAAA;IAEF,OAAO,aAAa,CAAC;QACnB,KAAK,EAAE,IAAI,CAAC,MAAM;QAClB,IAAI,EAAE,IAAI,CAAC,QAAQ;QACnB,KAAK;QACL,aAAa,EAAE,IAAI;QACnB,mBAAmB,EAAE,IAAI;QACzB,OAAO,EAAE,GAAG,EAAE,CAAC;YACb,GAAG,CAAC,EAAE,GAAG,KAAK,CAAC,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,EAAE;gBAC/C,GAAG,CAAC,EAAE,GAAG,KAAK,CAAC,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC;gBACvE,KAAK,CAAC;oBACJ,cAAc,EAAE,OAAO;oBACvB,IAAI,EAAE,KAAK;oBACX,WAAW,EAAE,qBAAqB;oBAClC,KAAK,EAAE,IAAI,CAAC,GAAG;oBACf,OAAO,EAAE,CAAC,CAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAE,CAAC,CAAC,MAA2B,CAAC,KAAK,CAAC;oBACzE,SAAS,EAAE,CAAC,CAAgB,EAAE,EAAE;wBAC9B,IAAI,CAAC,CAAC,GAAG,KAAK,OAAO,EAAE,CAAC;4BACtB,CAAC,CAAC,cAAc,EAAE,CAAA;4BAClB,IAAI,CAAC,QAAQ,EAAE,CAAA;wBACjB,CAAC;oBACH,CAAC;iBACF,CAAC;gBACF,GAAG,CAAC,EAAE,cAAc,EAAE,SAAS,EAAE,EAAE;oBACjC,MAAM,CAAC,EAAE,GAAG,KAAK,CAAC,YAAY,EAAE,cAAc,EAAE,QAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;oBAC7E,MAAM,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,cAAc,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,EAAE;wBAClF,IAAI,CAAC,OAAO,CAAC;qBACd,CAAC;iBACH,CAAC;aACH,CAAC;SACH;KACF,CAAC,CAAA;AACJ,CAAC","sourcesContent":["// The link editor — a modal dialog (built on the @llui/components `dialog`) for\n// entering/editing a URL. Pure view: it's driven by `{ open }` + `url` signals\n// and reports changes through callbacks, so any owner (the link plugin) can wire\n// it to its own messages.\n\nimport { button, div, input, text, type Mountable, type Signal } from '@llui/dom'\nimport {\n connect as connectDialog,\n overlay as overlayDialog,\n type DialogMsg,\n type DialogState,\n} from '@llui/components/dialog'\n\nexport interface LinkDialogOptions {\n /** The `{ open }` slice driving the modal. */\n dialog: Signal<DialogState>\n /** The URL input value. */\n url: Signal<string>\n /** Called as the user edits the URL. */\n onInput: (url: string) => void\n /** Called on Apply / Enter. */\n onSubmit: () => void\n /** Called when the dialog requests open/close (dismiss, close button). */\n onDialog: (msg: DialogMsg) => void\n /** Dialog instance id for ARIA wiring (default 'md-link-dialog'). */\n id?: string\n}\n\n/** Render the link dialog. Hidden (portal, nothing inline) until `dialog.open`. */\nexport function linkDialog(opts: LinkDialogOptions): Mountable {\n const parts = connectDialog(opts.dialog, opts.onDialog, {\n id: opts.id ?? 'md-link-dialog',\n closeLabel: 'Cancel',\n })\n\n return overlayDialog({\n state: opts.dialog,\n send: opts.onDialog,\n parts,\n closeOnEscape: true,\n closeOnOutsideClick: true,\n content: () => [\n div({ ...parts.content, 'data-md-link': 'box' }, [\n div({ ...parts.title, 'data-md-link': 'title' }, [text('Insert link')]),\n input({\n 'data-md-link': 'input',\n type: 'url',\n placeholder: 'https://example.com',\n value: opts.url,\n onInput: (e: Event) => opts.onInput((e.target as HTMLInputElement).value),\n onKeyDown: (e: KeyboardEvent) => {\n if (e.key === 'Enter') {\n e.preventDefault()\n opts.onSubmit()\n }\n },\n }),\n div({ 'data-md-link': 'actions' }, [\n button({ ...parts.closeTrigger, 'data-md-link': 'cancel' }, [text('Cancel')]),\n button({ type: 'button', 'data-md-link': 'apply', onClick: () => opts.onSubmit() }, [\n text('Apply'),\n ]),\n ]),\n ]),\n ],\n })\n}\n"]}
@@ -0,0 +1,48 @@
1
+ import { type Mountable, type Send, type Signal } from '@llui/dom';
2
+ import type { CommandItem } from '../plugins/types.js';
3
+ import type { EditorMsg, FormatState } from '../state.js';
4
+ export interface ToolbarItemParts {
5
+ type: 'button';
6
+ 'data-scope': 'md-toolbar';
7
+ 'data-part': 'item';
8
+ 'data-id': string;
9
+ 'aria-label': string;
10
+ title: string;
11
+ 'aria-pressed': Signal<'true' | 'false'>;
12
+ 'aria-disabled': Signal<'true' | undefined>;
13
+ disabled: Signal<boolean>;
14
+ 'data-active': Signal<'' | undefined>;
15
+ onClick: (e: MouseEvent) => void;
16
+ }
17
+ export interface ToolbarParts {
18
+ root: {
19
+ role: 'toolbar';
20
+ 'aria-label': string;
21
+ 'data-scope': 'md-toolbar';
22
+ 'data-part': 'root';
23
+ };
24
+ item: (id: string) => ToolbarItemParts;
25
+ }
26
+ /** Build reactive toolbar parts from the format signal. Spread `item(id)` onto a
27
+ * `<button>`; `aria-pressed` / `data-active` / `disabled` track the format. */
28
+ export declare function connectToolbar(format: Signal<FormatState>, send: Send<EditorMsg>, items: readonly CommandItem[]): ToolbarParts;
29
+ /** Compact glyphs so the default toolbar reads as a real toolbar without icon
30
+ * assets. SVG strings render as icons; everything else as text. Override via
31
+ * `ToolbarOptions.glyphs`. */
32
+ export declare const DEFAULT_GLYPHS: Readonly<Record<string, string>>;
33
+ export interface ToolbarOptions {
34
+ format: Signal<FormatState>;
35
+ send: Send<EditorMsg>;
36
+ items: readonly CommandItem[];
37
+ /** Explicit grouped layout of ids; defaults to grouping by `item.group`. */
38
+ groups?: readonly (readonly string[])[];
39
+ /** Glyph overrides (id → text/emoji). Merged over {@link DEFAULT_GLYPHS}. */
40
+ glyphs?: Readonly<Record<string, string>>;
41
+ /** Render the `block` group as a `<select>` dropdown instead of buttons
42
+ * (default true). */
43
+ blockSelect?: boolean;
44
+ 'aria-label'?: string;
45
+ }
46
+ /** A ready-made grouped toolbar. Items not surfaced to `'toolbar'` are dropped. */
47
+ export declare function toolbar(opts: ToolbarOptions): Mountable;
48
+ //# sourceMappingURL=toolbar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toolbar.d.ts","sourceRoot":"","sources":["../../src/surfaces/toolbar.ts"],"names":[],"mappings":"AAIA,OAAO,EASL,KAAK,SAAS,EACd,KAAK,IAAI,EACT,KAAK,MAAM,EACZ,MAAM,WAAW,CAAA;AAClB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AACtD,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAEzD,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,QAAQ,CAAA;IACd,YAAY,EAAE,YAAY,CAAA;IAC1B,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,EAAE,MAAM,CAAA;IACjB,YAAY,EAAE,MAAM,CAAA;IACpB,KAAK,EAAE,MAAM,CAAA;IACb,cAAc,EAAE,MAAM,CAAC,MAAM,GAAG,OAAO,CAAC,CAAA;IACxC,eAAe,EAAE,MAAM,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;IAC3C,QAAQ,EAAE,MAAM,CAAC,OAAO,CAAC,CAAA;IACzB,aAAa,EAAE,MAAM,CAAC,EAAE,GAAG,SAAS,CAAC,CAAA;IACrC,OAAO,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,IAAI,CAAA;CACjC;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS,CAAA;QACf,YAAY,EAAE,MAAM,CAAA;QACpB,YAAY,EAAE,YAAY,CAAA;QAC1B,WAAW,EAAE,MAAM,CAAA;KACpB,CAAA;IACD,IAAI,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,gBAAgB,CAAA;CACvC;AAED;+EAC+E;AAC/E,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,CAAC,WAAW,CAAC,EAC3B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EACrB,KAAK,EAAE,SAAS,WAAW,EAAE,GAC5B,YAAY,CA2Bd;AAUD;;8BAE8B;AAC9B,eAAO,MAAM,cAAc,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAoB3D,CAAA;AAuBD,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC,WAAW,CAAC,CAAA;IAC3B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,CAAA;IACrB,KAAK,EAAE,SAAS,WAAW,EAAE,CAAA;IAC7B,4EAA4E;IAC5E,MAAM,CAAC,EAAE,SAAS,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,CAAA;IACvC,6EAA6E;IAC7E,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IACzC;yBACqB;IACrB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AA0BD,mFAAmF;AACnF,wBAAgB,OAAO,CAAC,IAAI,EAAE,cAAc,GAAG,SAAS,CA2CvD"}