@refrakt-md/editor 0.7.2 → 0.8.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 (50) hide show
  1. package/app/dist/assets/{index-4SP4_AaD.js → index-BBinZAiy.js} +1 -1
  2. package/app/dist/assets/index-BD2EBUrQ.css +1 -0
  3. package/app/dist/assets/{index-D77rckeh.js → index-BLuaHLN3.js} +1 -1
  4. package/app/dist/assets/{index-30gAspk8.js → index-BgCNqcSo.js} +1 -1
  5. package/app/dist/assets/index-BlAOhWAQ.js +453 -0
  6. package/app/dist/assets/{index-BZ4adnS0.js → index-BwFn9q4x.js} +1 -1
  7. package/app/dist/assets/{index-DFkteo0w.js → index-C72UC2ga.js} +1 -1
  8. package/app/dist/assets/{index-x67KGOIr.js → index-COIPZ34u.js} +1 -1
  9. package/app/dist/assets/{index-BEFUVB_B.js → index-CW02bulk.js} +1 -1
  10. package/app/dist/assets/{index-CI5PewQM.js → index-CXFMPmtf.js} +1 -1
  11. package/app/dist/assets/{index-ByHhigzw.js → index-CeU_s7BB.js} +1 -1
  12. package/app/dist/assets/{index-DvgOtlru.js → index-CqHjo2YT.js} +1 -1
  13. package/app/dist/assets/{index-DKnhR16N.js → index-D3TQo8gu.js} +1 -1
  14. package/app/dist/assets/{index-Baf7ZSct.js → index-DVM3uoxc.js} +1 -1
  15. package/app/dist/assets/{index-C9w1RpYY.js → index-DW2zI-Ss.js} +1 -1
  16. package/app/dist/assets/{index--rGC9bba.js → index-D_Y6J00B.js} +1 -1
  17. package/app/dist/assets/{index-kPhFxtn-.js → index-DgIg-QAA.js} +2 -2
  18. package/app/dist/assets/{index-DIuFNfTc.js → index-DmY6uqAw.js} +1 -1
  19. package/app/dist/assets/{index-D1WOi3EN.js → index-DzHt8ZRh.js} +1 -1
  20. package/app/dist/assets/{index-BwWzfQVn.js → index-ZLvRNfLb.js} +1 -1
  21. package/app/dist/index.html +2 -2
  22. package/app/src/lib/api/client.ts +49 -0
  23. package/app/src/lib/components/ActionEditPopover.svelte +245 -0
  24. package/app/src/lib/components/BlockCard.svelte +255 -1
  25. package/app/src/lib/components/BlockEditPanel.svelte +697 -138
  26. package/app/src/lib/components/BlockEditor.svelte +467 -389
  27. package/app/src/lib/components/CodeEditPopover.svelte +226 -0
  28. package/app/src/lib/components/ContentModelTree.svelte +562 -0
  29. package/app/src/lib/components/ContentTree.svelte +181 -0
  30. package/app/src/lib/components/EditorLayout.svelte +1 -6
  31. package/app/src/lib/components/FrontmatterEditPanel.svelte +0 -1
  32. package/app/src/lib/components/HeaderBar.svelte +38 -0
  33. package/app/src/lib/components/InlineEditPopover.svelte +593 -0
  34. package/app/src/lib/components/InsertBlockDialog.svelte +429 -0
  35. package/app/src/lib/components/PageCard.svelte +3 -4
  36. package/app/src/lib/components/PreviewPane.svelte +19 -1
  37. package/app/src/lib/components/RuneAttributes.svelte +249 -100
  38. package/app/src/lib/editor/block-parser.ts +463 -0
  39. package/app/src/lib/preview/block-renderer.ts +30 -14
  40. package/dist/community-tags-builder.d.ts.map +1 -1
  41. package/dist/community-tags-builder.js +5 -1
  42. package/dist/community-tags-builder.js.map +1 -1
  43. package/dist/server.d.ts +1 -0
  44. package/dist/server.d.ts.map +1 -1
  45. package/dist/server.js +92 -6
  46. package/dist/server.js.map +1 -1
  47. package/package.json +6 -6
  48. package/preview-runtime/App.svelte +2 -0
  49. package/app/dist/assets/index-DlrXwdpb.css +0 -1
  50. package/app/dist/assets/index-GlUHQ_jL.js +0 -324
@@ -0,0 +1,593 @@
1
+ <script lang="ts">
2
+ import { onMount } from 'svelte';
3
+ import { parseInlineMarkdown, serializeInlineHtml, normalizeEditableDom } from '../editor/inline-markdown.js';
4
+
5
+ interface Props {
6
+ anchorRect: DOMRect;
7
+ dataName: string;
8
+ inlineSource: string;
9
+ onchange: (newInlineSource: string) => void;
10
+ onclose: () => void;
11
+ }
12
+
13
+ let { anchorRect, dataName, inlineSource, onchange, onclose }: Props = $props();
14
+
15
+ let popoverEl: HTMLDivElement;
16
+ let editableEl: HTMLDivElement;
17
+ let left = $state(0);
18
+ let top = $state(0);
19
+ let showAbove = $state(true);
20
+
21
+ // Link editing state
22
+ let linkEdit: {
23
+ anchorEl: HTMLAnchorElement;
24
+ href: string;
25
+ text: string;
26
+ rect: DOMRect;
27
+ } | null = $state(null);
28
+ let linkHrefInput: HTMLInputElement | undefined = $state();
29
+
30
+ let debounceTimer: ReturnType<typeof setTimeout>;
31
+
32
+ onMount(() => {
33
+ // Set initial content from markdown source
34
+ editableEl.innerHTML = parseInlineMarkdown(inlineSource);
35
+
36
+ // Position centered above the anchor by default
37
+ const popoverRect = popoverEl.getBoundingClientRect();
38
+ const popoverWidth = popoverRect.width;
39
+ const popoverHeight = popoverRect.height;
40
+ const gap = 8;
41
+
42
+ // Horizontal: center on anchor
43
+ let x = anchorRect.left + anchorRect.width / 2 - popoverWidth / 2;
44
+ if (x < gap) x = gap;
45
+ if (x + popoverWidth > window.innerWidth - gap) x = window.innerWidth - popoverWidth - gap;
46
+ left = x;
47
+
48
+ // Vertical: above anchor if room, else below
49
+ const aboveY = anchorRect.top - popoverHeight - gap;
50
+ if (aboveY >= gap) {
51
+ top = aboveY;
52
+ showAbove = true;
53
+ } else {
54
+ top = anchorRect.bottom + gap;
55
+ showAbove = false;
56
+ }
57
+
58
+ // Focus and place cursor at end
59
+ editableEl.focus();
60
+ const sel = window.getSelection();
61
+ if (sel && editableEl.childNodes.length > 0) {
62
+ const range = document.createRange();
63
+ range.selectNodeContents(editableEl);
64
+ range.collapse(false);
65
+ sel.removeAllRanges();
66
+ sel.addRange(range);
67
+ }
68
+
69
+ // Close handlers
70
+ function handleClickOutside(e: MouseEvent) {
71
+ if (popoverEl && !popoverEl.contains(e.target as Node)) {
72
+ onclose();
73
+ }
74
+ }
75
+
76
+ function handleKeydown(e: KeyboardEvent) {
77
+ if (e.key === 'Escape') {
78
+ if (linkEdit) {
79
+ linkEdit = null;
80
+ } else {
81
+ onclose();
82
+ }
83
+ }
84
+ }
85
+
86
+ requestAnimationFrame(() => {
87
+ document.addEventListener('mousedown', handleClickOutside);
88
+ });
89
+ document.addEventListener('keydown', handleKeydown);
90
+
91
+ return () => {
92
+ document.removeEventListener('mousedown', handleClickOutside);
93
+ document.removeEventListener('keydown', handleKeydown);
94
+ clearTimeout(debounceTimer);
95
+ };
96
+ });
97
+
98
+ function handleInput() {
99
+ clearTimeout(debounceTimer);
100
+ debounceTimer = setTimeout(() => {
101
+ normalizeEditableDom(editableEl);
102
+ const md = serializeInlineHtml(editableEl);
103
+ onchange(md);
104
+ }, 100);
105
+ }
106
+
107
+ function handleKeydown(e: KeyboardEvent) {
108
+ // Block Enter to prevent block-level elements
109
+ if (e.key === 'Enter') {
110
+ e.preventDefault();
111
+ return;
112
+ }
113
+
114
+ const mod = e.metaKey || e.ctrlKey;
115
+ if (!mod) return;
116
+
117
+ if (e.key === 'b') {
118
+ e.preventDefault();
119
+ toggleFormat('bold');
120
+ } else if (e.key === 'i') {
121
+ e.preventDefault();
122
+ toggleFormat('italic');
123
+ } else if (e.key === 'k') {
124
+ e.preventDefault();
125
+ openLinkEditor();
126
+ }
127
+ }
128
+
129
+ function handlePaste(e: ClipboardEvent) {
130
+ e.preventDefault();
131
+ const text = e.clipboardData?.getData('text/plain') ?? '';
132
+ document.execCommand('insertText', false, text);
133
+ }
134
+
135
+ function handleEditableClick(e: MouseEvent) {
136
+ // Check if an <a> was clicked
137
+ const target = e.target as HTMLElement;
138
+ const anchor = target.closest('a') as HTMLAnchorElement | null;
139
+ if (anchor && editableEl.contains(anchor)) {
140
+ e.preventDefault();
141
+ openLinkEditorForAnchor(anchor);
142
+ }
143
+ }
144
+
145
+ // ── Formatting ──────────────────────────────────────────────
146
+
147
+ function toggleFormat(format: 'bold' | 'italic' | 'code') {
148
+ editableEl.focus();
149
+ const sel = window.getSelection();
150
+ if (!sel || sel.rangeCount === 0) return;
151
+
152
+ if (format === 'code') {
153
+ const range = sel.getRangeAt(0);
154
+ if (range.collapsed) return;
155
+
156
+ // Check if selection is already inside a <code>
157
+ const codeParent = findAncestor(range.commonAncestorContainer, 'CODE', editableEl);
158
+ if (codeParent) {
159
+ // Unwrap: replace <code> with its text content
160
+ const text = document.createTextNode(codeParent.textContent ?? '');
161
+ codeParent.replaceWith(text);
162
+ // Re-select the text
163
+ const newRange = document.createRange();
164
+ newRange.selectNode(text);
165
+ sel.removeAllRanges();
166
+ sel.addRange(newRange);
167
+ } else {
168
+ const code = document.createElement('code');
169
+ code.textContent = range.toString();
170
+ range.deleteContents();
171
+ range.insertNode(code);
172
+ // Select the code element contents
173
+ const newRange = document.createRange();
174
+ newRange.selectNodeContents(code);
175
+ sel.removeAllRanges();
176
+ sel.addRange(newRange);
177
+ }
178
+ } else {
179
+ // Bold and italic use execCommand for simplicity
180
+ const command = format === 'bold' ? 'bold' : 'italic';
181
+ document.execCommand(command, false);
182
+ }
183
+
184
+ normalizeEditableDom(editableEl);
185
+ handleInput();
186
+ }
187
+
188
+ function openLinkEditor() {
189
+ const sel = window.getSelection();
190
+ if (!sel || sel.rangeCount === 0) return;
191
+
192
+ const range = sel.getRangeAt(0);
193
+
194
+ // Check if cursor is inside an existing link
195
+ const existingLink = findAncestor(range.commonAncestorContainer, 'A', editableEl) as HTMLAnchorElement | null;
196
+ if (existingLink) {
197
+ openLinkEditorForAnchor(existingLink);
198
+ return;
199
+ }
200
+
201
+ // Create a new link from selection
202
+ if (range.collapsed) return;
203
+
204
+ const linkText = range.toString();
205
+ const a = document.createElement('a');
206
+ a.href = '';
207
+ a.textContent = linkText;
208
+ range.deleteContents();
209
+ range.insertNode(a);
210
+
211
+ openLinkEditorForAnchor(a);
212
+ }
213
+
214
+ function openLinkEditorForAnchor(anchor: HTMLAnchorElement) {
215
+ linkEdit = {
216
+ anchorEl: anchor,
217
+ href: anchor.getAttribute('href') ?? '',
218
+ text: anchor.textContent ?? '',
219
+ rect: anchor.getBoundingClientRect(),
220
+ };
221
+ // Focus the URL input after render
222
+ requestAnimationFrame(() => {
223
+ linkHrefInput?.focus();
224
+ linkHrefInput?.select();
225
+ });
226
+ }
227
+
228
+ function applyLinkEdit() {
229
+ if (!linkEdit) return;
230
+ linkEdit.anchorEl.href = linkEdit.href;
231
+ linkEdit.anchorEl.textContent = linkEdit.text;
232
+ linkEdit = null;
233
+ editableEl.focus();
234
+ handleInput();
235
+ }
236
+
237
+ function removeLinkEdit() {
238
+ if (!linkEdit) return;
239
+ const text = document.createTextNode(linkEdit.anchorEl.textContent ?? '');
240
+ linkEdit.anchorEl.replaceWith(text);
241
+ linkEdit = null;
242
+ editableEl.focus();
243
+ handleInput();
244
+ }
245
+
246
+ function handleLinkKeydown(e: KeyboardEvent) {
247
+ if (e.key === 'Enter') {
248
+ e.preventDefault();
249
+ applyLinkEdit();
250
+ }
251
+ }
252
+
253
+ // ── Toolbar state ───────────────────────────────────────────
254
+
255
+ let isBold = $state(false);
256
+ let isItalic = $state(false);
257
+ let isCode = $state(false);
258
+
259
+ function updateToolbarState() {
260
+ isBold = document.queryCommandState('bold');
261
+ isItalic = document.queryCommandState('italic');
262
+
263
+ const sel = window.getSelection();
264
+ if (sel && sel.rangeCount > 0) {
265
+ isCode = !!findAncestor(sel.getRangeAt(0).commonAncestorContainer, 'CODE', editableEl);
266
+ } else {
267
+ isCode = false;
268
+ }
269
+ }
270
+
271
+ // ── Helpers ─────────────────────────────────────────────────
272
+
273
+ function findAncestor(node: globalThis.Node, tagName: string, boundary: HTMLElement): HTMLElement | null {
274
+ let current: globalThis.Node | null = node;
275
+ while (current && current !== boundary) {
276
+ if (current.nodeType === globalThis.Node.ELEMENT_NODE && (current as HTMLElement).tagName === tagName) {
277
+ return current as HTMLElement;
278
+ }
279
+ current = current.parentNode;
280
+ }
281
+ return null;
282
+ }
283
+ </script>
284
+
285
+ <div
286
+ class="inline-edit-popover"
287
+ class:above={showAbove}
288
+ class:below={!showAbove}
289
+ bind:this={popoverEl}
290
+ style="left: {left}px; top: {top}px"
291
+ >
292
+ <!-- Toolbar row -->
293
+ <div class="inline-edit-popover__toolbar">
294
+ <span class="inline-edit-popover__label">{dataName}</span>
295
+ <div class="inline-edit-popover__toolbar-buttons">
296
+ <button
297
+ class="inline-edit-popover__tool-btn"
298
+ class:active={isBold}
299
+ onclick={() => toggleFormat('bold')}
300
+ title="Bold (Ctrl+B)"
301
+ ><strong>B</strong></button>
302
+ <button
303
+ class="inline-edit-popover__tool-btn"
304
+ class:active={isItalic}
305
+ onclick={() => toggleFormat('italic')}
306
+ title="Italic (Ctrl+I)"
307
+ ><em>I</em></button>
308
+ <button
309
+ class="inline-edit-popover__tool-btn inline-edit-popover__tool-btn--code"
310
+ class:active={isCode}
311
+ onclick={() => toggleFormat('code')}
312
+ title="Inline code"
313
+ >&lt;/&gt;</button>
314
+ <button
315
+ class="inline-edit-popover__tool-btn"
316
+ onclick={openLinkEditor}
317
+ title="Link (Ctrl+K)"
318
+ >
319
+ <svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
320
+ <path d="M6.5 9.5a3 3 0 0 0 4.2.3l2-2a3 3 0 0 0-4.2-4.3l-1.1 1.1" />
321
+ <path d="M9.5 6.5a3 3 0 0 0-4.2-.3l-2 2a3 3 0 0 0 4.2 4.3l1.1-1.1" />
322
+ </svg>
323
+ </button>
324
+ </div>
325
+ </div>
326
+
327
+ <!-- Editable content area -->
328
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
329
+ <div
330
+ class="inline-edit-popover__editable"
331
+ contenteditable="true"
332
+ bind:this={editableEl}
333
+ oninput={handleInput}
334
+ onkeydown={handleKeydown}
335
+ onkeyup={updateToolbarState}
336
+ onmouseup={updateToolbarState}
337
+ onpaste={handlePaste}
338
+ onclick={handleEditableClick}
339
+ ></div>
340
+
341
+ <!-- Link editor sub-popover -->
342
+ {#if linkEdit}
343
+ <div class="inline-edit-popover__link-editor">
344
+ <div class="inline-edit-popover__link-row">
345
+ <label class="inline-edit-popover__link-label">Text</label>
346
+ <input
347
+ class="inline-edit-popover__link-input"
348
+ type="text"
349
+ bind:value={linkEdit.text}
350
+ onkeydown={handleLinkKeydown}
351
+ />
352
+ </div>
353
+ <div class="inline-edit-popover__link-row">
354
+ <label class="inline-edit-popover__link-label">URL</label>
355
+ <input
356
+ class="inline-edit-popover__link-input"
357
+ type="text"
358
+ bind:value={linkEdit.href}
359
+ bind:this={linkHrefInput}
360
+ onkeydown={handleLinkKeydown}
361
+ placeholder="https://..."
362
+ />
363
+ </div>
364
+ <div class="inline-edit-popover__link-actions">
365
+ <button class="inline-edit-popover__link-btn inline-edit-popover__link-btn--apply" onclick={applyLinkEdit}>Apply</button>
366
+ <button class="inline-edit-popover__link-btn inline-edit-popover__link-btn--remove" onclick={removeLinkEdit}>Remove link</button>
367
+ </div>
368
+ </div>
369
+ {/if}
370
+ </div>
371
+
372
+ <style>
373
+ .inline-edit-popover {
374
+ position: fixed;
375
+ z-index: 1100;
376
+ display: flex;
377
+ flex-direction: column;
378
+ gap: var(--ed-space-1, 0.25rem);
379
+ background: var(--ed-surface-0, #fff);
380
+ border: 1px solid var(--ed-border-default, #e2e8f0);
381
+ border-radius: var(--ed-radius-lg, 8px);
382
+ box-shadow: var(--ed-shadow-xl, 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1));
383
+ padding: var(--ed-space-2, 0.5rem);
384
+ min-width: 280px;
385
+ max-width: 520px;
386
+ animation: inline-edit-enter 120ms ease-out;
387
+ }
388
+
389
+ .inline-edit-popover.above {
390
+ transform-origin: bottom center;
391
+ }
392
+
393
+ .inline-edit-popover.below {
394
+ transform-origin: top center;
395
+ }
396
+
397
+ @keyframes inline-edit-enter {
398
+ from { opacity: 0; transform: scale(0.97) translateY(4px); }
399
+ to { opacity: 1; transform: scale(1) translateY(0); }
400
+ }
401
+
402
+ /* ── Toolbar ──────────────────────────────────────────── */
403
+
404
+ .inline-edit-popover__toolbar {
405
+ display: flex;
406
+ align-items: center;
407
+ gap: var(--ed-space-2, 0.5rem);
408
+ padding: 0 var(--ed-space-1, 0.25rem);
409
+ }
410
+
411
+ .inline-edit-popover__label {
412
+ font-size: 10px;
413
+ font-weight: 700;
414
+ color: var(--ed-text-muted, #94a3b8);
415
+ text-transform: uppercase;
416
+ letter-spacing: 0.04em;
417
+ white-space: nowrap;
418
+ flex-shrink: 0;
419
+ }
420
+
421
+ .inline-edit-popover__toolbar-buttons {
422
+ display: flex;
423
+ align-items: center;
424
+ gap: 2px;
425
+ margin-left: auto;
426
+ }
427
+
428
+ .inline-edit-popover__tool-btn {
429
+ display: flex;
430
+ align-items: center;
431
+ justify-content: center;
432
+ width: 26px;
433
+ height: 26px;
434
+ border: none;
435
+ border-radius: var(--ed-radius-sm, 4px);
436
+ background: transparent;
437
+ color: var(--ed-text-tertiary, #a0aec0);
438
+ cursor: pointer;
439
+ font-size: 13px;
440
+ font-family: inherit;
441
+ transition: background 100ms, color 100ms;
442
+ }
443
+
444
+ .inline-edit-popover__tool-btn:hover {
445
+ background: var(--ed-surface-2, #f1f5f9);
446
+ color: var(--ed-text-secondary, #475569);
447
+ }
448
+
449
+ .inline-edit-popover__tool-btn.active {
450
+ background: var(--ed-accent-muted, rgba(59, 130, 246, 0.1));
451
+ color: var(--ed-accent, #3b82f6);
452
+ }
453
+
454
+ .inline-edit-popover__tool-btn--code {
455
+ font-size: 10px;
456
+ font-family: monospace;
457
+ letter-spacing: -0.5px;
458
+ }
459
+
460
+ /* ── Editable area ────────────────────────────────────── */
461
+
462
+ .inline-edit-popover__editable {
463
+ min-height: 1.6em;
464
+ padding: var(--ed-space-1, 0.25rem) var(--ed-space-2, 0.5rem);
465
+ border: 1px solid var(--ed-border-default, #e2e8f0);
466
+ border-radius: var(--ed-radius-sm, 4px);
467
+ font-size: var(--ed-text-sm, 13px);
468
+ color: var(--ed-text-primary, #1a1a2e);
469
+ background: var(--ed-surface-0, #fff);
470
+ outline: none;
471
+ font-family: inherit;
472
+ line-height: 1.6;
473
+ white-space: nowrap;
474
+ overflow-x: auto;
475
+ transition: border-color 0.15s ease, box-shadow 0.15s ease;
476
+ }
477
+
478
+ .inline-edit-popover__editable:focus {
479
+ border-color: var(--ed-accent, #3b82f6);
480
+ box-shadow: 0 0 0 2px var(--ed-accent-ring, rgba(59, 130, 246, 0.2));
481
+ }
482
+
483
+ /* Inline formatting styles within the editable area */
484
+ .inline-edit-popover__editable :global(a) {
485
+ color: var(--ed-accent, #3b82f6);
486
+ text-decoration: underline;
487
+ text-decoration-style: dashed;
488
+ text-underline-offset: 2px;
489
+ cursor: pointer;
490
+ }
491
+
492
+ .inline-edit-popover__editable :global(a:hover) {
493
+ text-decoration-style: solid;
494
+ }
495
+
496
+ .inline-edit-popover__editable :global(code) {
497
+ background: var(--ed-surface-2, #f1f5f9);
498
+ border-radius: 3px;
499
+ padding: 0.1em 0.3em;
500
+ font-family: monospace;
501
+ font-size: 0.9em;
502
+ }
503
+
504
+ .inline-edit-popover__editable :global(strong) {
505
+ font-weight: 700;
506
+ }
507
+
508
+ .inline-edit-popover__editable :global(em) {
509
+ font-style: italic;
510
+ }
511
+
512
+ /* ── Link editor ──────────────────────────────────────── */
513
+
514
+ .inline-edit-popover__link-editor {
515
+ display: flex;
516
+ flex-direction: column;
517
+ gap: var(--ed-space-1, 0.25rem);
518
+ padding: var(--ed-space-2, 0.5rem);
519
+ border-top: 1px solid var(--ed-border-default, #e2e8f0);
520
+ margin-top: var(--ed-space-1, 0.25rem);
521
+ }
522
+
523
+ .inline-edit-popover__link-row {
524
+ display: flex;
525
+ align-items: center;
526
+ gap: var(--ed-space-2, 0.5rem);
527
+ }
528
+
529
+ .inline-edit-popover__link-label {
530
+ font-size: 10px;
531
+ font-weight: 600;
532
+ color: var(--ed-text-muted, #94a3b8);
533
+ text-transform: uppercase;
534
+ letter-spacing: 0.03em;
535
+ width: 32px;
536
+ flex-shrink: 0;
537
+ }
538
+
539
+ .inline-edit-popover__link-input {
540
+ flex: 1;
541
+ min-width: 0;
542
+ padding: var(--ed-space-1, 0.25rem) var(--ed-space-2, 0.5rem);
543
+ border: 1px solid var(--ed-border-default, #e2e8f0);
544
+ border-radius: var(--ed-radius-sm, 4px);
545
+ font-size: var(--ed-text-sm, 13px);
546
+ color: var(--ed-text-primary, #1a1a2e);
547
+ background: var(--ed-surface-0, #fff);
548
+ outline: none;
549
+ font-family: inherit;
550
+ line-height: 1.4;
551
+ }
552
+
553
+ .inline-edit-popover__link-input:focus {
554
+ border-color: var(--ed-accent, #3b82f6);
555
+ box-shadow: 0 0 0 2px var(--ed-accent-ring, rgba(59, 130, 246, 0.2));
556
+ }
557
+
558
+ .inline-edit-popover__link-actions {
559
+ display: flex;
560
+ gap: var(--ed-space-2, 0.5rem);
561
+ margin-top: var(--ed-space-1, 0.25rem);
562
+ }
563
+
564
+ .inline-edit-popover__link-btn {
565
+ padding: var(--ed-space-1, 0.25rem) var(--ed-space-2, 0.5rem);
566
+ border: 1px solid var(--ed-border-default, #e2e8f0);
567
+ border-radius: var(--ed-radius-sm, 4px);
568
+ font-size: 11px;
569
+ font-weight: 500;
570
+ cursor: pointer;
571
+ transition: background 100ms, color 100ms;
572
+ }
573
+
574
+ .inline-edit-popover__link-btn--apply {
575
+ background: var(--ed-accent, #3b82f6);
576
+ border-color: var(--ed-accent, #3b82f6);
577
+ color: white;
578
+ }
579
+
580
+ .inline-edit-popover__link-btn--apply:hover {
581
+ opacity: 0.9;
582
+ }
583
+
584
+ .inline-edit-popover__link-btn--remove {
585
+ background: transparent;
586
+ color: var(--ed-text-muted, #94a3b8);
587
+ }
588
+
589
+ .inline-edit-popover__link-btn--remove:hover {
590
+ color: var(--ed-text-secondary, #475569);
591
+ background: var(--ed-surface-2, #f1f5f9);
592
+ }
593
+ </style>